Làm quen với WebRTC

WebRTC là mặt trận mới trong cuộc chiến lâu dài vì một web mở và không bị ràng buộc.

Brendan Eich, nhà phát minh ra JavaScript

Giao tiếp theo thời gian thực không cần trình bổ trợ

Hãy tưởng tượng một thế giới nơi điện thoại, TV và máy tính của bạn có thể giao tiếp trên một nền tảng chung. Hãy tưởng tượng là bạn có thể dễ dàng thêm cuộc trò chuyện video và tính năng chia sẻ dữ liệu ngang hàng vào ứng dụng web. Đó là tầm nhìn của WebRTC.

Bạn muốn dùng thử? Dịch vụ WebRTC có trên Google Chrome, Safari, Firefox và Opera trên máy tính và thiết bị di động. Bạn nên bắt đầu bằng ứng dụng trò chuyện video đơn giản tại appr.tc:

  1. Mở appr.tc trong trình duyệt.
  2. Nhấp vào Tham gia để tham gia một phòng trò chuyện và cho phép ứng dụng sử dụng webcam của bạn.
  3. Mở URL hiển thị ở cuối trang trong một thẻ mới hoặc tốt hơn nữa là mở trên một máy tính khác.

Bắt đầu nhanh

Bạn không có thời gian để đọc bài viết này hay chỉ muốn viết mã?

Ngoài ra, bạn có thể chuyển thẳng đến lớp học lập trình WebP, đây là hướng dẫn từng bước giải thích cách xây dựng một ứng dụng trò chuyện video hoàn chỉnh, bao gồm cả một máy chủ báo hiệu đơn giản.

Lịch sử WebRTC rất ngắn

Một trong những thách thức chính cuối cùng đối với web là cho phép con người giao tiếp thông qua thoại và video: giao tiếp theo thời gian thực hay gọi tắt là RTC. RTC phải tự nhiên trong ứng dụng web như nhập văn bản vào mục nhập văn bản. Nếu không, khả năng đổi mới và phát triển các cách mới để mọi người tương tác sẽ bị hạn chế.

Trước đây, RTC là một công ty và phức tạp, đòi hỏi công nghệ âm thanh và video tốn kém để được cấp phép hoặc phát triển nội bộ. Việc tích hợp công nghệ RTC với nội dung, dữ liệu và dịch vụ hiện có thật khó khăn và tốn thời gian, đặc biệt là trên web.

Trò chuyện video trong Gmail đã trở nên phổ biến vào năm 2008 và vào năm 2011, Google đã giới thiệu Hangouts, nền tảng sử dụng Talk (cũng như Gmail). Google đã mua lại GIPS, một công ty đã phát triển nhiều thành phần cần thiết cho RTC, chẳng hạn như bộ mã hoá và giải mã (codec) và kỹ thuật loại bỏ tiếng vọng. Google sử dụng nguồn mở các công nghệ do GIPS phát triển và hợp tác với các cơ quan tiêu chuẩn có liên quan thuộc Lực lượng chuyên trách kỹ thuật Internet (IETF) và World Wide Web Consortium (W3C) nhằm đảm bảo sự đồng thuận của toàn ngành. Vào tháng 5 năm 2011, Evolandeo đã xây dựng bản triển khai đầu tiên của WebRTC.

WebRTC đã triển khai các tiêu chuẩn mở để giao tiếp dữ liệu, âm thanh và video theo thời gian thực mà không cần trình bổ trợ. Nhu cầu thực sự:

  • Nhiều dịch vụ web đã sử dụng RTC, nhưng lại cần tải xuống, ứng dụng gốc hoặc trình bổ trợ. Các dịch vụ này bao gồm Skype, Facebook và Hangouts.
  • Việc tải xuống, cài đặt và cập nhật trình bổ trợ rất phức tạp, dễ xảy ra lỗi và gây khó chịu.
  • Trình bổ trợ rất khó triển khai, gỡ lỗi, khắc phục sự cố, kiểm thử và duy trì, đồng thời có thể yêu cầu cấp phép và tích hợp với công nghệ phức tạp, tốn kém. Thường rất khó để thuyết phục mọi người cài đặt trình bổ trợ ngay từ đầu!

Nguyên tắc hướng dẫn của dự án WebRTC là API của dự án phải là nguồn mở, miễn phí, được chuẩn hoá, được tích hợp vào trình duyệt web và hiệu quả hơn các công nghệ hiện có.

Chúng ta đang ở đâu?

WebRTC được dùng trong nhiều ứng dụng, chẳng hạn như Google Meet. WebRTC cũng đã được tích hợp với các ứng dụng gốc WebKitGTK+ và Qt.

WebRTC triển khai 3 API sau: – MediaStream (còn gọi là getUserMedia) – RTCPeerConnectionRTCDataChannel

Các API được xác định theo hai quy cách sau:

Chrome, Safari, Firefox, Edge và Opera hỗ trợ cả ba API này trên thiết bị di động và máy tính.

getUserMedia: Để xem bản minh hoạ và mã, vui lòng xem mẫu WebRTC hoặc thử các ví dụ thú vị của Chris Wilson sử dụng getUserMedia làm dữ liệu đầu vào cho âm thanh trên web.

RTCPeerConnection: Để xem bản minh hoạ đơn giản và ứng dụng trò chuyện video có đầy đủ chức năng, hãy lần lượt xem các mẫu WebRTC Kết nối ngang hàngappr.tc. Ứng dụng này sử dụng adapter.js (một phần đệm JavaScript do Google duy trì với sự trợ giúp của cộng đồng WebRTC) để tóm tắt những điểm khác biệt về trình duyệt và các thay đổi về thông số kỹ thuật.

RTCDataChannel: Để xem ví dụ thực tế, hãy xem mẫu WebRTC để xem một trong các bản minh hoạ kênh dữ liệu.

Lớp học lập trình về WebRTC cho biết cách sử dụng cả 3 API để xây dựng một ứng dụng đơn giản cho tính năng trò chuyện video và chia sẻ tệp.

WebRTC đầu tiên của bạn

Ứng dụng WebRTC cần thực hiện một số việc sau đây:

  • Nhận âm thanh, video hoặc dữ liệu khác truyền trực tuyến.
  • Lấy thông tin mạng, chẳng hạn như địa chỉ IP và cổng, đồng thời trao đổi thông tin đó với các ứng dụng WebRTC khác (còn gọi là ngang hàng) để kích hoạt kết nối, ngay cả thông qua NAT và tường lửa.
  • Điều phối hoạt động giao tiếp báo hiệu để báo cáo lỗi và bắt đầu hoặc đóng phiên.
  • Trao đổi thông tin về chức năng của ứng dụng và nội dung nghe nhìn, chẳng hạn như độ phân giải và bộ mã hoá và giải mã.
  • Giao tiếp âm thanh, video hoặc dữ liệu phát trực tuyến.

Để thu thập và truyền dữ liệu truyền trực tuyến, WebRTC triển khai các API sau:

  • MediaStream có quyền truy cập vào các luồng dữ liệu, chẳng hạn như từ máy ảnh và micrô của người dùng.
  • RTCPeerConnection cho phép gọi thoại hoặc gọi video, trong đó có các phương tiện mã hoá và quản lý băng thông.
  • RTCDataChannel cho phép giao tiếp ngang hàng về dữ liệu chung.

(Có thảo luận chi tiết về mạng và các khía cạnh báo hiệu của WebRTC sau.)

API MediaStream (còn được gọi là API getUserMedia)

MediaStream API thể hiện các luồng nội dung nghe nhìn được đồng bộ hoá. Ví dụ: luồng được lấy từ đầu vào micrô và máy ảnh có các bản video và âm thanh được đồng bộ hóa. (Đừng nhầm lẫn MediaStreamTrack với phần tử <track>, vì phần tử này hoàn toàn khác.)

Có lẽ cách dễ nhất để hiểu API MediaStream là xem xét API dưới dạng tự nhiên:

  1. Trong trình duyệt, hãy chuyển đến phần mẫu WebRTC getUserMedia.
  2. Mở bảng điều khiển.
  3. Kiểm tra biến stream thuộc phạm vi toàn cục.

Mỗi MediaStream có một dữ liệu đầu vào (có thể là MediaStream do getUserMedia() tạo) và một dữ liệu đầu ra có thể được truyền đến phần tử video hoặc RTCPeerConnection.

Phương thức getUserMedia() lấy tham số đối tượng MediaStreamConstraints và trả về Promise giúp phân giải thành đối tượng MediaStream.

Mỗi MediaStream đều có một label, chẳng hạn như 'Xk7EuLhsuHKbnjLWkW4yYGNJJ8ONsgwHBvLQ'. Một mảng MediaStreamTrack được phương thức getAudioTracks()getVideoTracks() trả về.

Đối với ví dụ getUserMedia, stream.getAudioTracks() trả về một mảng trống (vì không có âm thanh) và giả sử một webcam đang hoạt động được kết nối, stream.getVideoTracks() sẽ trả về một mảng MediaStreamTrack biểu thị cho luồng từ webcam. Mỗi MediaStreamTrack có một loại ('video' hoặc 'audio'), một label (chẳng hạn như 'FaceTime HD Camera (Built-in)') và đại diện cho một hoặc nhiều kênh âm thanh hoặc video. Trong trường hợp này, chỉ có một bản video và không có âm thanh, nhưng rất dễ hình dung các trường hợp sử dụng có nhiều bản âm thanh, chẳng hạn như một ứng dụng trò chuyện nhận luồng nội dung từ máy ảnh trước, máy ảnh sau, micrô và một ứng dụng chia sẻ màn hình.

Bạn có thể đính kèm MediaStream vào một phần tử video bằng cách đặt thuộc tính srcObject. Trước đây, bạn có thể thực hiện việc này bằng cách đặt thuộc tính src thành một URL đối tượng được tạo bằng URL.createObjectURL(), nhưng tính năng này đã ngừng hoạt động.

Bạn cũng có thể dùng getUserMedia làm nút đầu vào cho API Web Audio:

// Cope with browser differences.
let audioContext;
if (typeof AudioContext === 'function') {
  audioContext = new AudioContext();
} else if (typeof webkitAudioContext === 'function') {
  audioContext = new webkitAudioContext(); // eslint-disable-line new-cap
} else {
  console.log('Sorry! Web Audio not supported.');
}

// Create a filter node.
var filterNode = audioContext.createBiquadFilter();
// See https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#BiquadFilterNode-section
filterNode.type = 'highpass';
// Cutoff frequency. For highpass, audio is attenuated below this frequency.
filterNode.frequency.value = 10000;

// Create a gain node to change audio volume.
var gainNode = audioContext.createGain();
// Default is 1 (no change). Less than 1 means audio is attenuated
// and vice versa.
gainNode.gain.value = 0.5;

navigator.mediaDevices.getUserMedia({audio: true}, (stream) => {
  // Create an AudioNode from the stream.
  const mediaStreamSource =
    audioContext.createMediaStreamSource(stream);
  mediaStreamSource.connect(filterNode);
  filterNode.connect(gainNode);
  // Connect the gain node to the destination. For example, play the sound.
  gainNode.connect(audioContext.destination);
});

Các ứng dụng và tiện ích dựa trên Chromium cũng có thể kết hợp getUserMedia. Việc thêm quyền audioCapture và/hoặc videoCapture vào tệp kê khai sẽ cho phép hệ thống yêu cầu và cấp quyền chỉ một lần sau khi cài đặt. Sau đó, người dùng sẽ không được yêu cầu cấp quyền truy cập vào máy ảnh hoặc micrô.

Bạn chỉ phải cấp quyền một lần cho getUserMedia(). Lần đầu tiên, nút Cho phép sẽ hiển thị trong thanh thông tin của trình duyệt. Chrome đã ngừng sử dụng quyền truy cập HTTP cho getUserMedia() vào cuối năm 2015 do tính năng này được phân loại là Tính năng mạnh mẽ.

Có thể ý định này sẽ bật MediaStream cho bất kỳ nguồn dữ liệu phát trực tuyến nào, không chỉ cho camera hoặc micrô. Chế độ này cho phép truyền trực tuyến từ dữ liệu đã lưu trữ hoặc các nguồn dữ liệu tuỳ ý, chẳng hạn như cảm biến hoặc các dữ liệu đầu vào khác.

getUserMedia() thực sự đi vào hoạt động khi kết hợp với các API và thư viện JavaScript khác:

  • Webcam Toy là một ứng dụng photobooth sử dụng WebGL để thêm hiệu ứng lạ và tuyệt vời vào những bức ảnh có thể được chia sẻ hoặc lưu cục bộ.
  • FaceKat là một trò chơi theo dõi khuôn mặt được xây dựng bằng headtrackr.js.
  • Máy ảnh ASCII sử dụng API Canvas để tạo hình ảnh ASCII.
Hình ảnh ASCII do idevelop.ro/ascii-camera tạo
Nghệ thuật ASCII gUM!

Giới hạn

Bạn có thể dùng quy tắc ràng buộc (Constraints) để đặt giá trị cho độ phân giải video trong getUserMedia(). Việc này cũng cho phép hỗ trợ các quy tắc ràng buộc khác, chẳng hạn như tỷ lệ khung hình; chế độ đối diện (máy ảnh trước hoặc sau); tốc độ khung hình, chiều cao và chiều rộng; và phương thức applyConstraints().

Để biết ví dụ, hãy xem phần Mẫu WebRTC getUserMedia: chọn độ phân giải.

Việc đặt giá trị ràng buộc không được phép sẽ cung cấp DOMException hoặc OverconstrainedError nếu không có sẵn độ phân giải được yêu cầu. Để xem cách hoạt động của chế độ này, hãy xem phần Mẫu WebViewgetUserMedia: chọn độ phân giải để xem bản minh hoạ.

Chụp ảnh màn hình và thẻ

Ứng dụng Chrome cũng giúp bạn chia sẻ video trực tiếp trong một thẻ trình duyệt hoặc toàn bộ màn hình thông qua các API chrome.tabCapturechrome.desktopCapture. (Để xem bản minh hoạ và thông tin khác, hãy xem phần Chia sẻ màn hình với WebRTC. Bài viết này đã xuất hiện vài năm trước nhưng vẫn thú vị.)

Bạn cũng có thể sử dụng tính năng chụp ảnh màn hình làm nguồn MediaStream trong Chrome bằng cách sử dụng quy tắc ràng buộc thử nghiệm chromeMediaSource. Lưu ý rằng tính năng chụp ảnh màn hình yêu cầu giao thức HTTPS và chỉ nên dùng để phát triển vì tính năng này được bật thông qua cờ hiệu dòng lệnh như giải thích trong bài đăng này.

Tín hiệu: Kiểm soát phiên, mạng và thông tin phương tiện

WebRTC sử dụng RTCPeerConnection để giao tiếp dữ liệu truyền trực tuyến giữa các trình duyệt (còn gọi là ứng dụng ngang hàng), nhưng cũng cần có cơ chế điều phối hoạt động giao tiếp và gửi thông báo điều khiển, một quy trình gọi là báo hiệu. Các phương thức và giao thức báo hiệu không do WebRTC chỉ định. Tín hiệu không phải là một phần của API RTCPeerConnection.

Thay vào đó, các nhà phát triển ứng dụng WebRTC có thể chọn bất kỳ giao thức nhắn tin nào họ muốn, chẳng hạn như SIP hoặc AdX và bất kỳ kênh giao tiếp song công (hai chiều) thích hợp nào. Ví dụ appr.tc sử dụng XHR và API Kênh làm cơ chế báo hiệu. Lớp học lập trình sử dụng Socket.io chạy trên Máy chủ nút.

Tín hiệu được dùng để trao đổi ba loại thông tin:

  • Thông báo kiểm soát phiên: để khởi chạy hoặc đóng giao tiếp và báo cáo lỗi.
  • Cấu hình mạng: đối với thế giới bên ngoài, địa chỉ IP và cổng trên máy tính của bạn là gì?
  • Khả năng đa phương tiện: những bộ mã hoá và giải mã (codec) và độ phân giải nào có thể được trình duyệt của bạn xử lý và trình duyệt mà trình duyệt muốn giao tiếp?

Quá trình trao đổi thông tin thông qua tín hiệu phải hoàn tất thành công trước khi quá trình truyền trực tuyến ngang hàng có thể bắt đầu.

Ví dụ: Hãy tưởng tượng Alice muốn trò chuyện với Bob. Dưới đây là mã mẫu từ thông số kỹ thuật của W3C WebRTC. Mã mẫu này cho thấy quá trình truyền tín hiệu trong thực tế. Mã này giả định rằng tồn tại một cơ chế báo hiệu nào đó được tạo trong phương thức createSignalingChannel(). Ngoài ra, xin lưu ý rằng trên Chrome và Opera, RTCPeerConnection hiện có tiền tố.

// handles JSON.stringify/parse
const signaling = new SignalingChannel();
const constraints = {audio: true, video: true};
const configuration = {iceServers: [{urls: 'stun:stun.example.org'}]};
const pc = new RTCPeerConnection(configuration);

// Send any ice candidates to the other peer.
pc.onicecandidate = ({candidate}) => signaling.send({candidate});

// Let the "negotiationneeded" event trigger offer generation.
pc.onnegotiationneeded = async () => {
  try {
    await pc.setLocalDescription(await pc.createOffer());
    // Send the offer to the other peer.
    signaling.send({desc: pc.localDescription});
  } catch (err) {
    console.error(err);
  }
};

// Once remote track media arrives, show it in remote video element.
pc.ontrack = (event) => {
  // Don't set srcObject again if it is already set.
  if (remoteView.srcObject) return;
  remoteView.srcObject = event.streams[0];
};

// Call start() to initiate.
async function start() {
  try {
    // Get local stream, show it in self-view, and add it to be sent.
    const stream =
      await navigator.mediaDevices.getUserMedia(constraints);
    stream.getTracks().forEach((track) =>
      pc.addTrack(track, stream));
    selfView.srcObject = stream;
  } catch (err) {
    console.error(err);
  }
}

signaling.onmessage = async ({desc, candidate}) => {
  try {
    if (desc) {
      // If you get an offer, you need to reply with an answer.
      if (desc.type === 'offer') {
        await pc.setRemoteDescription(desc);
        const stream =
          await navigator.mediaDevices.getUserMedia(constraints);
        stream.getTracks().forEach((track) =>
          pc.addTrack(track, stream));
        await pc.setLocalDescription(await pc.createAnswer());
        signaling.send({desc: pc.localDescription});
      } else if (desc.type === 'answer') {
        await pc.setRemoteDescription(desc);
      } else {
        console.log('Unsupported SDP type.');
      }
    } else if (candidate) {
      await pc.addIceCandidate(candidate);
    }
  } catch (err) {
    console.error(err);
  }
};

Đầu tiên, Alice và Bob trao đổi thông tin mạng. (Cụm từ tìm ứng viên đề cập đến quá trình tìm các giao diện mạng và cổng bằng khung ICE.)

  1. Alice tạo một đối tượng RTCPeerConnection bằng trình xử lý onicecandidate. Trình xử lý này sẽ chạy khi có các đề xuất mạng.
  2. Alice gửi dữ liệu ứng viên được tuần tự hoá cho Bob thông qua bất kỳ kênh báo hiệu nào mà họ đang sử dụng, chẳng hạn như WebSocket hoặc một số cơ chế khác.
  3. Khi Bob nhận được tin nhắn về ứng viên từ Alice, anh ấy gọi addIceCandidate để thêm ứng viên vào phần mô tả từ xa về ứng viên.

Các ứng dụng WebRTC (còn gọi là ngang hàng hoặc Alice và Bob trong ví dụ này) cũng cần xác định và trao đổi thông tin phương tiện âm thanh và video cục bộ và từ xa, chẳng hạn như khả năng về độ phân giải và bộ mã hoá và giải mã. Hoạt động gửi tín hiệu để trao đổi thông tin cấu hình nội dung nghe nhìn sẽ được tiến hành bằng cách trao đổi ưu đãicâu trả lời thông qua Giao thức mô tả phiên (SDP):

  1. Alice chạy phương thức RTCPeerConnection createOffer(). Kết quả trả về từ hoạt động này được truyền RTCSessionDescription – nội dung mô tả phiên cục bộ của Alice.
  2. Trong lệnh gọi lại, Alice đặt nội dung mô tả cục bộ bằng cách sử dụng setLocalDescription() rồi gửi nội dung mô tả phiên này cho Bob thông qua kênh báo hiệu của họ. Lưu ý rằng RTCPeerConnection sẽ không bắt đầu thu thập ứng viên cho đến khi setLocalDescription() được gọi. Điều này được quy định trong bản nháp của JSEP IETF.
  3. Bob đặt nội dung mô tả Alice đã gửi cho anh ấy dưới dạng mô tả từ xa bằng setRemoteDescription().
  4. Bob chạy phương thức RTCPeerConnection createAnswer(), chuyển cho phương thức đó mô tả từ xa mà anh nhận được từ Alice để có thể tạo một phiên cục bộ tương thích với phiên của cô. Lệnh gọi lại createAnswer() được truyền một RTCSessionDescription. Bob đặt đó làm nội dung mô tả cục bộ và gửi cho Alice.
  5. Khi Alice nhận được nội dung mô tả phiên của Bob, cô ấy đặt setRemoteDescription làm nội dung mô tả từ xa.
  6. Ping!

Đối tượng RTCSessionDescription là các blob tuân thủ Giao thức mô tả phiên, SDP. Được tuần tự hoá, một đối tượng SDP sẽ có dạng như sau:

v=0
o=- 3883943731 1 IN IP4 127.0.0.1
s=
t=0 0
a=group:BUNDLE audio video
m=audio 1 RTP/SAVPF 103 104 0 8 106 105 13 126

// ...

a=ssrc:2223794119 label:H4fjnMzxy3dPIgQ7HxuCTLb4wLLLeRHnFxh810

Việc thu thập và trao đổi thông tin mạng và nội dung nghe nhìn có thể được thực hiện cùng lúc, nhưng cả hai quá trình phải hoàn tất trước khi việc truyền trực tuyến âm thanh và video giữa các ứng dụng ngang hàng có thể bắt đầu.

Cấu trúc ưu đãi/câu trả lời được mô tả trước đây có tên là Giao thức thiết lập phiên JavaScript hay JSEP. (Có một ảnh động rất hay giải thích quy trình báo hiệu và phát trực tuyến trong video minh hoạ của Ericsson cho lần triển khai WebRTC đầu tiên.)

Sơ đồ cấu trúc JSEP
Cấu trúc JSEP

Sau khi quá trình báo hiệu hoàn tất thành công, dữ liệu có thể được truyền trực tiếp ngang hàng, giữa phương thức gọi và người được gọi – hoặc nếu việc này không thành công, sẽ được truyền qua máy chủ chuyển tiếp trung gian (bạn sẽ tìm hiểu thêm về điều này sau). Phát trực tiếp là công việc của RTCPeerConnection.

RTCPeerConnection

RTCPeerConnection là thành phần WebRTC xử lý hoạt động giao tiếp dữ liệu truyền trực tuyến ổn định và hiệu quả giữa các ứng dụng ngang hàng.

Sau đây là sơ đồ cấu trúc WebRTC cho thấy vai trò của RTCPeerConnection. Như bạn sẽ thấy, các phần màu xanh lục rất phức tạp!

Sơ đồ cấu trúc WebRTC
Cấu trúc WebRTC (từ webrtc.org)

Từ góc độ JavaScript, điều chính cần hiểu được từ sơ đồ này là RTCPeerConnection giúp bảo vệ các nhà phát triển web khỏi vô số những điều phức tạp ẩn náu bên dưới. Các bộ mã hoá và giao thức mà WebRTC sử dụng thực hiện một khối lượng công việc khổng lồ để có thể giao tiếp theo thời gian thực, kể cả qua các mạng không đáng tin cậy:

  • Che giấu gói tin
  • Huỷ tiếng vọng
  • Khả năng thích ứng với băng thông
  • Bộ đệm rung động
  • Điều chỉnh khuếch đại tự động
  • Giảm và khử tiếng ồn
  • Làm sạch hình ảnh

Mã W3C trước đây cho thấy một ví dụ đơn giản về WebRTC từ góc độ báo hiệu. Sau đây là hướng dẫn từng bước về 2 ứng dụng WebRTC đang hoạt động. Ví dụ đầu tiên là một ví dụ đơn giản để minh hoạ RTCPeerConnection, và ví dụ thứ hai là một ứng dụng trò chuyện video đang hoạt động đầy đủ.

RTCPeerConnection không có máy chủ

Mã sau đây được lấy từ Kết nối ngang hàng lấy mẫu WebRTC, có RTCPeerConnection cục bộ từ xa (cũng như video cục bộ và từ xa) trên một trang web. Điều này không tạo thành bất kỳ điều gì rất hữu ích – phương thức gọi và phương thức gọi nằm trên cùng một trang – nhưng giúp hoạt động của API RTCPeerConnection rõ ràng hơn một chút vì các đối tượng RTCPeerConnection trên trang có thể trực tiếp trao đổi dữ liệu và tin nhắn mà không cần phải sử dụng cơ chế báo hiệu trung gian.

Trong ví dụ này, pc1 đại diện cho ứng dụng ngang hàng cục bộ (phương thức gọi) và pc2 đại diện cho ứng dụng ngang hàng từ xa (phương thức gọi).

Người gọi

  1. Tạo RTCPeerConnection mới và thêm luồng từ getUserMedia(): ```js // Máy chủ là tệp cấu hình không bắt buộc. (Xem nội dung thảo luận về TURN và STUN sau.) pc1 = new RTCPeerConnection(servers); // ... localStream.getTracks().forEach((track) => { pc1.addTrack(track, localStream); });
  1. Tạo một ưu đãi và đặt ưu đãi đó làm nội dung mô tả cục bộ cho pc1 và làm nội dung mô tả từ xa cho pc2. Bạn có thể thực hiện việc này ngay trong mã mà không cần dùng tín hiệu vì cả phương thức gọi và phương thức gọi đều ở trên cùng một trang: js pc1.setLocalDescription(desc).then(() => { onSetLocalSuccess(pc1); }, onSetSessionDescriptionError ); trace('pc2 setRemoteDescription start'); pc2.setRemoteDescription(desc).then(() => { onSetRemoteSuccess(pc2); }, onSetSessionDescriptionError );

Người được gọi

  1. Tạo pc2 và khi luồng từ pc1 được thêm vào, hiển thị luồng đó trong một phần tử video: js pc2 = new RTCPeerConnection(servers); pc2.ontrack = gotRemoteStream; //... function gotRemoteStream(e){ vid2.srcObject = e.stream; }

API RTCPeerConnection kèm máy chủ

Trong thế giới thực, WebRTC cần có máy chủ, tuy nhiên đơn giản nhưng những điều sau có thể xảy ra:

  • Người dùng có thể tìm thấy nhau và trao đổi thông tin chi tiết trong thế giới thực, chẳng hạn như tên.
  • Các ứng dụng WebRTC (ngang hàng) sẽ trao đổi thông tin về mạng.
  • Các ứng dụng ngang hàng trao đổi dữ liệu về nội dung nghe nhìn, chẳng hạn như định dạng và độ phân giải video.
  • Ứng dụng WebRTC truyền tải cổng NAT và tường lửa.

Nói cách khác, WebRTC cần có 4 loại chức năng phía máy chủ:

  • Khám phá và giao tiếp của người dùng
  • Báo hiệu
  • Truyền tải NAT/tường lửa
  • Máy chủ chuyển tiếp trong trường hợp không giao tiếp được ngang hàng

Bài viết này không bao gồm nội dung truyền tải NAT, kết nối mạng ngang hàng và các yêu cầu khi xây dựng ứng dụng máy chủ để phát hiện người dùng và truyền tín hiệu. Đủ để nói rằng giao thức STUN và phần mở rộng của nó, TURN, được khung ICE sử dụng để cho phép RTCPeerConnection đối phó với hoạt động truyền tải NAT và các sự thay đổi khác về mạng.

ICE là một khung để kết nối những người dùng ngang hàng, chẳng hạn như hai ứng dụng trò chuyện video. Ban đầu, ICE cố gắng kết nối trực tiếp với các ứng dụng ngang hàng với độ trễ thấp nhất có thể thông qua UDP. Trong quá trình này, máy chủ STUN có một nhiệm vụ duy nhất là cho phép một mạng ngang hàng đứng sau NAT tìm ra địa chỉ và cổng công khai của máy chủ đó. (Để biết thêm thông tin về STUN và TURN, hãy xem phần Xây dựng các dịch vụ phụ trợ cần thiết cho ứng dụng WebRTC.)

Đang tìm ứng viên kết nối
Tìm đề xuất kết nối

Nếu UDP không thành công, ICE sẽ thử TCP. Nếu không kết nối trực tiếp được, cụ thể là do tường lửa và truyền tải NAT doanh nghiệp, ICE sử dụng một máy chủ TURN trung gian (chuyển tiếp). Nói cách khác, trước tiên, ICE sử dụng STUN với UDP để kết nối trực tiếp các thiết bị ngang hàng. Nếu không thành công, ICE sẽ quay lại dùng máy chủ chuyển tiếp TURN. Biểu thức tìm ứng viên đề cập đến quá trình tìm các giao diện và cổng mạng.

Đường dẫn dữ liệu WebRTC
Đường dẫn dữ liệu WebRTC

Kỹ sư WebRTC Justin Uberti cung cấp thêm thông tin về ICE, STUN và TURN trong bản trình bày WebRTC Google I/O năm 2013. (Trang trình bày bản trình bày này đưa ra các ví dụ về cách triển khai máy chủ TURN và STUN.)

Một ứng dụng trò chuyện video đơn giản

Bản minh hoạ tính năng trò chuyện video tại appr.tc là nơi phù hợp để dùng thử WebRTC, với đầy đủ tính năng báo hiệu và truyền tải NAT/tường lửa qua máy chủ STUN. Ứng dụng này sử dụng adapter.js, một phần đệm để bảo vệ các ứng dụng khỏi những thay đổi về thông số kỹ thuật và sự khác biệt về tiền tố.

Mã này có chủ đích chi tiết trong quá trình ghi nhật ký. Hãy kiểm tra bảng điều khiển để hiểu thứ tự của các sự kiện. Sau đây là hướng dẫn từng bước chi tiết về mã này.

Cấu trúc liên kết mạng

Hiện tại, WebRTC chỉ hỗ trợ giao tiếp một với một, nhưng có thể dùng trong các trường hợp mạng phức tạp hơn, chẳng hạn như với nhiều người dùng ngang hàng giao tiếp trực tiếp với nhau hoặc thông qua Bộ điều khiển đa điểm (MCU), một máy chủ có thể xử lý số lượng lớn người tham gia và thực hiện chuyển tiếp luồng có chọn lọc, kết hợp hoặc ghi âm và ghi âm.

Sơ đồ cấu trúc liên kết của Bộ điều khiển đa điểm
Ví dụ về cấu trúc liên kết của Bộ điều khiển đa điểm

Nhiều ứng dụng WebRTC hiện có chỉ minh hoạ hoạt động giao tiếp giữa các trình duyệt web, nhưng máy chủ cổng có thể cho phép ứng dụng WebRTC chạy trên trình duyệt tương tác với thiết bị, chẳng hạn như điện thoại (còn gọi là PSTN) và với hệ thống VOIP. Vào tháng 5 năm 2012, Doubango Telecom đã nguồn mở ứng dụng SIP sipml5 được xây dựng bằng WebRTC và WebSocket (trong số các mục đích sử dụng khác) cho phép gọi video giữa các trình duyệt và ứng dụng chạy trên iOS và Android. Tại Google I/O, Tethr và Tropo đã minh hoạ một khung hỗ trợ truyền thông về thảm hoạ trong một chiếc cặp bằng ô OpenBTS để cho phép giao tiếp giữa điện thoại phổ thông và máy tính thông qua WebRTC. Liên lạc qua điện thoại mà không cần nhà mạng!

Bản minh hoạ Tethr/Tropo tại Google I/O 2012
Tethr/Tropo: Thông tin liên lạc khi gặp thảm hoạ trong một chiếc cặp

API RTCDataChannel<

Cũng như âm thanh và video, WebRTC hỗ trợ giao tiếp theo thời gian thực cho các loại dữ liệu khác.

API RTCDataChannel cho phép trao đổi dữ liệu tuỳ ý ngang hàng với độ trễ thấp và công suất cao. Để xem bản minh hoạ trang đơn và tìm hiểu cách xây dựng một ứng dụng truyền tệp đơn giản, hãy lần lượt xem mẫu WebRTClớp học lập trình về WebP.

Có nhiều trường hợp sử dụng tiềm năng cho API này, bao gồm:

  • Trò chơi
  • Ứng dụng máy tính từ xa
  • Trò chuyện bằng tin nhắn theo thời gian thực
  • Chuyển tệp
  • Mạng phi tập trung

API này có một số tính năng giúp khai thác tối đa RTCPeerConnection cũng như cho phép giao tiếp ngang hàng mạnh mẽ và linh hoạt:

  • Sử dụng chế độ thiết lập phiên RTCPeerConnection
  • Nhiều kênh đồng thời có chế độ ưu tiên
  • Ngữ nghĩa phân phối đáng tin cậy và không đáng tin cậy
  • Tích hợp tính năng bảo mật (DTLS) và kiểm soát tắc nghẽn
  • Khả năng sử dụng kèm theo hoặc không kèm theo âm thanh hoặc video

Cú pháp tương tự có chủ ý tương tự như WebSocket với phương thức send() và sự kiện message:

const localConnection = new RTCPeerConnection(servers);
const remoteConnection = new RTCPeerConnection(servers);
const sendChannel =
  localConnection.createDataChannel('sendDataChannel');

// ...

remoteConnection.ondatachannel = (event) => {
  receiveChannel = event.channel;
  receiveChannel.onmessage = onReceiveMessage;
  receiveChannel.onopen = onReceiveChannelStateChange;
  receiveChannel.onclose = onReceiveChannelStateChange;
};

function onReceiveMessage(event) {
  document.querySelector("textarea#send").value = event.data;
}

document.querySelector("button#send").onclick = () => {
  var data = document.querySelector("textarea#send").value;
  sendChannel.send(data);
};

Hoạt động giao tiếp diễn ra trực tiếp giữa các trình duyệt, vì vậy RTCDataChannel có thể nhanh hơn nhiều so với WebSocket ngay cả khi cần có máy chủ chuyển tiếp (TURN) khi lỗ hổng ( lỗ) để xử lý tường lửa và NAT không thành công.

RTCDataChannel hoạt động trên Chrome, Safari, Firefox, Opera và Samsung Internet. Trò chơi Cube Slam sử dụng API để thông báo trạng thái trò chơi. Hãy chơi với bạn bè hoặc chơi gấu! Nền tảng đổi mới Sharefest đã bật tính năng chia sẻ tệp thông qua RTCDataChannelpeerCDN đã cung cấp cái nhìn sơ lược về cách WebRTC có thể cho phép phân phối nội dung ngang hàng.

Để biết thêm thông tin về RTCDataChannel, hãy xem thông số kỹ thuật của giao thức nháp của IETF.

Bảo mật

Có một số cách mà một ứng dụng hoặc trình bổ trợ giao tiếp theo thời gian thực có thể ảnh hưởng đến tính bảo mật. Ví dụ:

  • Phương tiện hoặc dữ liệu chưa được mã hoá có thể bị chặn giữa các trình duyệt hoặc giữa trình duyệt và máy chủ.
  • Ứng dụng có thể ghi lại và phân phối video hoặc âm thanh mà người dùng không biết.
  • Phần mềm độc hại hoặc virus có thể được cài đặt cùng với một trình bổ trợ hoặc ứng dụng dường như vô hại.

WebRTC có một số tính năng giúp tránh các sự cố này:

  • Quá trình triển khai WebRTC sử dụng các giao thức bảo mật, chẳng hạn như DTLSSRTP.
  • Tất cả thành phần WebRTC đều bắt buộc phải mã hoá, kể cả cơ chế báo hiệu.
  • WebRTC không phải là trình bổ trợ. Các thành phần của ứng dụng này chạy trong hộp cát của trình duyệt chứ không chạy trong một quy trình riêng biệt. Các thành phần không yêu cầu cài đặt riêng và được cập nhật bất cứ khi nào trình duyệt được cập nhật.
  • Bạn phải cấp rõ ràng quyền truy cập vào máy ảnh và micrô. Đồng thời, khi máy ảnh hoặc micrô đang chạy, giao diện người dùng sẽ thể hiện rõ việc này.

Bài viết này không nằm ngoài phạm vi thảo luận đầy đủ về vấn đề bảo mật khi phát trực tuyến nội dung đa phương tiện. Để biết thêm thông tin, hãy xem Cấu trúc bảo mật WebRTC đề xuất do IETF đề xuất.

Kết luận

Các API và tiêu chuẩn của WebRTC có thể dân chủ hoá và phi tập trung vào các công cụ tạo và giao tiếp nội dung, bao gồm điện thoại, trò chơi, sản xuất video, sản xuất nhạc và thu thập tin tức.

Công nghệ không gây ra nhiều ảnh hưởng gây gián đoạn hơn thế.

Như blogger Phil Edholm đưa ra, "có khả năng, WebRTC và HTML5 có thể cho phép cùng một chuyển đổi để giao tiếp theo thời gian thực mà trình duyệt ban đầu đã thực hiện để lấy thông tin".

Công cụ dành cho nhà phát triển

  • Bạn có thể xem số liệu thống kê WebRTC của một phiên đang diễn ra tại:
    • about://webrtc-internals trong Chrome
    • Opera://webrtc-internals trong Opera
    • about:webrtc trong Firefox
      trang chrome://webrtc-internals
      ảnh chụp màn hình chrome://webrtc-internals
  • Ghi chú tương tác trên nhiều trình duyệt
  • adapter.js là một phần cập nhật JavaScript cho WebRTC do Google duy trì với sự trợ giúp của cộng đồng WebRTC, giúp tóm tắt các tiền tố của nhà cung cấp, các điểm khác biệt của trình duyệt và các thay đổi về thông số kỹ thuật.
  • Để tìm hiểu thêm về các quy trình báo hiệu WebRTC, hãy kiểm tra đầu ra nhật ký appr.tc trên bảng điều khiển.
  • Nếu chi phí quá cao, bạn có thể sử dụng khung WebRTC hoặc thậm chí là một dịch vụ WebRTC hoàn chỉnh.
  • Các báo cáo lỗi và yêu cầu về tính năng luôn được đánh giá cao:

Tìm hiểu thêm

  • Phiên WebRTC của Justin Uberti tại Google I/O 2012
  • Alan B. Johnston và Daniel C. Burnett hiện đang duy trì sách WebRTC ở phiên bản thứ ba ở định dạng in và sách điện tử tại webrtcbook.com.
  • webrtc.org là nơi lưu trữ tất cả nội dung của WebRTC, bao gồm cả bản minh họa, tài liệu và nội dung thảo luận.
  • discuss-webrtc là một nhóm trên Google Groups dành cho các cuộc thảo luận về WebRTC về kỹ thuật.
  • @webrtc
  • Tài liệu về trò chuyện dành cho nhà phát triển của Google cung cấp thêm thông tin về hoạt động truyền tải NAT, STUN, máy chủ chuyển tiếp và hoạt động thu thập ứng viên.
  • WebRTC trên GitHub
  • Stack Overflow là một nơi phù hợp để tìm câu trả lời và đặt câu hỏi về WebRTC.

Tiêu chuẩn và giao thức

Tóm tắt về dịch vụ hỗ trợ của WebRTC

API MediaStreamgetUserMedia

  • Chrome dành cho máy tính để bàn 18.0.1008 trở lên; Chrome dành cho Android 29 trở lên
  • Opera 18 trở lên; Opera cho Android 20 trở lên
  • Opera 12, Opera Mobile 12 (dựa trên công cụ Presto)
  • Firefox 17 trở lên
  • Microsoft Edge 16 trở lên
  • Safari 11.2 trở lên trên iOS và 11.1 trở lên trên MacOS
  • UC 11.8 trở lên trên Android
  • Samsung Internet 4 trở lên

API RTCPeerConnection

  • Chrome dành cho máy tính để bàn 20 trở lên; Chrome dành cho Android 29 trở lên (không gắn cờ)
  • Opera 18 trở lên (bật theo mặc định); Opera dành cho Android 20 trở lên (bật theo mặc định)
  • Firefox 22 trở lên (bật theo mặc định)
  • Microsoft Edge 16 trở lên
  • Safari 11.2 trở lên trên iOS và 11.1 trở lên trên MacOS
  • Samsung Internet 4 trở lên

API RTCDataChannel

  • Phiên bản thử nghiệm trong Chrome 25, nhưng ổn định hơn (và có khả năng tương tác với Firefox) trong Chrome 26 trở lên; Chrome dành cho Android 29 trở lên
  • Phiên bản ổn định (và có khả năng tương tác với Firefox) trong Opera 18 trở lên; Opera cho Android 20 trở lên
  • Firefox 22 trở lên (bật theo mặc định)

Để biết thêm thông tin chi tiết về tính năng hỗ trợ API trên nhiều nền tảng, chẳng hạn như getUserMediaRTCPeerConnection, hãy truy cập vào caniuse.comTrạng thái nền tảng Chrome.

API gốc cho RTCPeerConnection cũng có sẵn tại tài liệu trên webrtc.org.