WebRTC là một mặt trận mới trong cuộc chiến lâu dài nhằm xây dựng 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 mà không cần trình bổ trợ
Hãy tưởng tượng một thế giới mà đ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 bạn có thể dễ dàng thêm tính năng trò chuyện video và chia sẻ dữ liệu ngang hàng vào ứng dụng web của mình. Đó là tầm nhìn của WebRTC.
Bạn muốn dùng thử không? WebRTC có trên máy tính và thiết bị di động trong Google Chrome, Safari, Firefox và Opera. Bạn có thể bắt đầu bằng ứng dụng trò chuyện video đơn giản tại appr.tc:
- Mở appr.tc trong trình duyệt.
- Nhấp vào Tham gia để tham gia phòng trò chuyện và cho phép ứng dụng sử dụng webcam của bạn.
- Mở URL xuất hiện ở cuối trang trong một thẻ mới hoặc tốt hơn là 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 hoặc chỉ muốn xem mã?
- Để nắm được thông tin tổng quan về WebRTC, hãy xem video sau đây tại Google I/O hoặc xem các trang trình bày này:
- Nếu bạn chưa sử dụng API
getUserMedia
, hãy xem phần Ghi âm và quay video trong HTML5 và simpl.info getUserMedia. - Để tìm hiểu về API
RTCPeerConnection
, hãy xem ví dụ sau và "simpl.info RTCPeerConnection". - Để tìm hiểu cách WebRTC sử dụng máy chủ để báo hiệu, cũng như tường lửa và NAT, hãy xem mã và nhật ký bảng điều khiển từ appr.tc.
- Bạn không thể chờ đợi và muốn thử WebRTC ngay bây giờ? Hãy thử một số trên 20 bản minh hoạ sử dụng các API JavaScript WebRTC.
- Bạn gặp sự cố với máy và WebRTC? Truy cập vào Trình khắc phục sự cố WebRTC.
Ngoài ra, bạn có thể chuyển thẳng đến lớp học lập trình WebRTC. Đâ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ử rất ngắn về WebRTC
Một trong những thách thức lớn nhất gần đây đối với web là hỗ trợ giao tiếp của con người thông qua giọng nói và video: giao tiếp theo thời gian thực (RTC). RTC phải tự nhiên trong ứng dụng web như khi nhập văn bản vào một trường nhập văn bản. Nếu không có dữ liệu này, bạn sẽ bị hạn chế trong khả năng đổi mới và phát triển những cách mới để mọi người tương tác.
Trước đây, RTC là một công nghệ phức tạp và dành cho doanh nghiệp, đòi hỏi phải mua giấy phép hoặc tự phát triển các công nghệ âm thanh và video đắt tiền. 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ó rất khó khăn và tốn thời gian, đặc biệt là trên web.
Tính năng trò chuyện video trên Gmail trở nên phổ biến vào năm 2008 và vào năm 2011, Google đã ra mắt Hangouts. Ứng dụng này sử dụng Talk (giống như Gmail). Google đã mua 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ã và kỹ thuật loại bỏ tiếng vọng. Google đã phát hành mã nguồn các công nghệ do GIPS phát triển và hợp tác với các tổ chức tiêu chuẩn có liên quan tại Nhóm công tác kỹ thuật Internet (IETF) và Tổ chức World Wide Web (W3C) để đảm bảo sự đồng thuận của ngành. Vào tháng 5 năm 2011, Ericsson đã xây dựng bản triển khai WebRTC đầu tiên.
WebRTC đã triển khai các tiêu chuẩn mở cho giao tiếp dữ liệu, âm thanh và video theo thời gian thực, không cần trình bổ trợ. Có nhu cầu thực sự:
- Nhiều dịch vụ web sử dụng RTC, nhưng cần tải xuống, ứng dụng gốc hoặc trình bổ trợ. Các ứng dụng 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 phiền toái.
- Trình bổ trợ khó triển khai, gỡ lỗi, khắc phục sự cố, kiểm thử và duy trì. Ngoài ra, bạn có thể phải mua giấy phép và tích hợp với công nghệ phức tạp, đắt đỏ. Trước tiên, thường rất khó để thuyết phục mọi người cài đặt trình bổ trợ!
Nguyên tắc chỉ đạo của dự án WebRTC là các API của dự án phải là nguồn mở, miễn phí, được chuẩn hoá, 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 WebKitGTK+ và các ứng dụng gốc Qt.
WebRTC triển khai 3 API sau:
- MediaStream
(còn gọi là getUserMedia
)
- RTCPeerConnection
- RTCDataChannel
Các API được xác định trong hai quy cách sau:
Cả ba API đều được Chrome, Safari, Firefox, Edge và Opera hỗ trợ trên thiết bị di động và máy tính.
getUserMedia
: Để xem các bản minh hoạ và mã, hãy xem mẫu WebRTC hoặc thử các ví dụ tuyệt vời 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 xem mẫu WebRTC Kết nối ngang hàng và appr.tc tương ứng. Ứng dụng này sử dụng adapter.js, một trình bổ trợ JavaScript do Google duy trì với sự trợ giúp của cộng đồng WebRTC, để tóm tắt các điểm khác biệt về trình duyệt và thay đổi về thông số kỹ thuật.
RTCDataChannel
: Để xem cách thực hiện, 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ả ba API để tạo một ứng dụng đơn giản dùng để trò chuyện video và chia sẻ tệp.
WebRTC đầu tiên của bạn
Ứng dụng WebRTC cần làm một số việc:
- Phát trực tuyến âm thanh, video hoặc dữ liệu khác.
- 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 gọi là đồng cấp) để cho phép kết nối, ngay cả thông qua NAT và tường lửa.
- Điều phối thông tin liên lạc 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ề nội dung nghe nhìn và chức năng của ứng dụng, chẳng hạn như độ phân giải và bộ mã hoá và giải mã.
- Truyền tải âm thanh, video hoặc dữ liệu trực tuyến.
Để thu thập và giao tiếp 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 điện hoặc gọi video bằng các cơ sở để mã hoá và quản lý băng thông.RTCDataChannel
cho phép giao tiếp ngang hàng của dữ liệu chung.
(Chúng ta sẽ thảo luận chi tiết về các khía cạnh mạng và tín hiệu của WebRTC sau.)
API MediaStream
(còn gọi là API getUserMedia
)
API MediaStream
đại diện cho các luồng nội dung nghe nhìn được đồng bộ hoá. Ví dụ: một luồng được lấy từ đầu vào máy ảnh và micrô có các kênh video và âm thanh được đồng bộ hoá. (Đừng nhầm lẫn MediaStreamTrack
với phần tử <track>
, đây là hai phần tử hoàn toàn khác nhau.)
Có lẽ cách dễ nhất để hiểu API MediaStream
là xem API này trong thực tế:
- Trong trình duyệt, hãy chuyển đến Mẫu WebRTC
getUserMedia
. - Mở bảng điều khiển.
- Kiểm tra biến
stream
nằm trong phạm vi toàn cục.
Mỗi MediaStream
có một đầu vào, có thể là MediaStream
do getUserMedia()
tạo ra và một đầu ra, có thể được truyền đến phần tử video hoặc RTCPeerConnection
.
Phương thức getUserMedia()
nhận tham số đối tượng MediaStreamConstraints
và trả về Promise
phân giải thành đối tượng MediaStream
.
Mỗi MediaStream
có một label
, chẳng hạn như 'Xk7EuLhsuHKbnjLWkW4yYGNJJ8ONsgwHBvLQ'
. Phương thức getAudioTracks()
và getVideoTracks()
trả về một mảng MediaStreamTrack
.
Đối với ví dụ về 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 gồm một MediaStreamTrack
đại diện cho luồng từ webcam. Mỗi MediaStreamTrack
có một loại ('video'
hoặc 'audio'
), một label
(tương tự 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 kênh video và không có âm thanh, nhưng bạn có thể dễ dàng tưởng tượng các trường hợp sử dụng có nhiều kênh hơn, chẳng hạn như ứng dụng trò chuyện nhận luồng từ máy ảnh trước, máy ảnh sau, micrô và ứ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, việc này được thực hiện bằng cách đặt thuộc tính src
thành URL đối tượng được tạo bằng URL.createObjectURL()
, nhưng việc này đã ngừng hoạt động.
Bạn cũng có thể sử dụng getUserMedia
dưới dạng nút đầu vào cho API Web âm thanh:
// 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 cho phép yêu cầu và cấp quyền chỉ một lần 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ỉ cần cấp quyền một lần cho getUserMedia()
. Lần đầu tiên, nút Cho phép sẽ xuất hiện trong infobar 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ẽ.
Mục đích là để bật MediaStream
cho mọi nguồn dữ liệu phát trực tuyến, không chỉ máy ảnh hoặc micrô. Điều này sẽ 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 đầu vào khác.
getUserMedia()
thực sự trở nên sống độ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 chụp ảnh sử dụng WebGL để thêm các hiệu ứng kỳ lạ và thú vị vào ảnh. Bạn có thể chia sẻ hoặc lưu ảnh trên máy.
- FaceKat là một trò chơi theo dõi khuôn mặt được tạo bằng headtrackr.js.
- ASCII Camera sử dụng Canvas API để tạo hình ảnh ASCII.
Giới hạn
Bạn có thể sử dụng Điều kiện ràng buộc để đặt giá trị cho độ phân giải video cho getUserMedia()
. Điều 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ế độ mặt trước (máy ảnh trước hoặc sau); tốc độ khung hình, chiều cao và chiều rộng; cũng như 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ị quy tắc ràng buộc không được phép sẽ trả về DOMException
hoặc OverconstrainedError
nếu không có độ phân giải được yêu cầu. Để xem cách thực hiện, hãy xem Mẫu WebRTC getUserMedia
: chọn độ phân giải để xem bản minh hoạ.
Chụp màn hình và thẻ
Các ứng dụng Chrome cũng cho phép chia sẻ video phát trực tiếp của một thẻ trình duyệt hoặc toàn bộ màn hình máy tính thông qua API chrome.tabCapture
và chrome.desktopCapture
. (Để xem bản minh hoạ và thêm thông tin, hãy xem bài viết Chia sẻ màn hình bằng WebRTC. Bài viết này đã có từ vài năm trước nhưng vẫn rất thú vị.)
Bạn cũng có thể sử dụng ảnh chụp 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 chromeMediaSource
thử nghiệm. Xin lưu ý rằng tính năng chụp màn hình yêu cầu HTTPS và chỉ nên dùng cho mục đích phát triển do tính năng này được bật thông qua cờ dòng lệnh như giải thích trong bài đăng này.
Tín hiệu: Thông tin về mạng, nội dung nghe nhìn và chế độ kiểm soát phiê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à trình duyệt ngang hàng), nhưng cũng cần có một 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 quá trình được gọi là truyền tín hiệu. Các phương thức và giao thức báo hiệu không được WebRTC chỉ định. Tín hiệu không phải là một phần của API RTCPeerConnection
.
Thay vào đó, 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 XMPP và bất kỳ kênh giao tiếp song công (hai chiều) nào phù hợp. Ví dụ về appr.tc sử dụng XHR và Channel API làm cơ chế báo hiệu. Lớp học lập trình này sử dụng Socket.io chạy trên máy chủ Node.
Tín hiệu được dùng để trao đổi 3 loại thông tin:
- Thông báo kiểm soát phiên: để khởi chạy hoặc đóng hoạt độ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 của máy tính là gì?
- Khả năng đa phương tiện: trình duyệt của bạn và trình duyệt mà trình duyệt đó muốn giao tiếp có thể xử lý những bộ mã hoá và giải mã và độ phân giải nào?
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 thì mới có thể bắt đầu truyền trực tuyến ngang hàng.
Ví dụ: hãy tưởng tượng Alice muốn giao tiếp với Bob. Dưới đây là đoạn mã mẫu từ thông số kỹ thuật WebRTC của W3C, cho thấy quy trình báo hiệu đang hoạt động. Mã này giả định rằng có một số cơ chế báo hiệu đượ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);
}
};
Trước tiên, Alice và Bob trao đổi thông tin mạng. (Biểu thức tìm ứng viên đề cập đến quá trình tìm giao diện mạng và cổng bằng khung ICE.)
- Alice tạo một đối tượng
RTCPeerConnection
có trình xử lýonicecandidate
. Trình xử lý này sẽ chạy khi có đề xuất mạng. - Alice gửi dữ liệu đề xuất đã chuyển đổi tuần tự đến 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.
- Khi nhận được thông báo đề xuất từ Alice, Bob sẽ gọi
addIceCandidate
để thêm đề xuất vào nội dung mô tả máy ngang hàng từ xa.
Ứng dụng WebRTC (còn gọi là peer hoặc Alice và Bob trong ví dụ này) cũng cần xác định và trao đổi thông tin nội dung nghe nhìn cục bộ và từ xa, chẳng hạn như độ phân giải và khả năng mã hoá và giải mã. Việc báo hiệu để trao đổi thông tin cấu hình nội dung nghe nhìn sẽ diễn ra bằng cách trao đổi lời đề nghị và câu trả lời bằng Giao thức mô tả phiên (SDP):
- Alice chạy phương thức
RTCPeerConnection
createOffer()
. Kết quả trả về từ lệnh này được truyền vàoRTCSessionDescription
– nội dung mô tả phiên cục bộ của Alice. - Trong lệnh gọi lại, Alice đặt nội dung mô tả cục bộ bằng
setLocalDescription()
, sau đó gửi nội dung mô tả phiên này cho Bob thông qua kênh báo hiệu. Xin lưu ý rằngRTCPeerConnection
sẽ không bắt đầu thu thập các đề xuất cho đến khisetLocalDescription()
được gọi. Điều này được mã hoá trong bản dự thảo JSEP IETF. - Bob đặt nội dung mô tả mà Alice gửi cho anh làm nội dung mô tả từ xa bằng
setRemoteDescription()
. - Bob chạy phương thức
RTCPeerConnection
createAnswer()
, truyền cho phương thức này nội dung 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ạicreateAnswer()
được truyền mộtRTCSessionDescription
. Bob đặt thông tin đó làm nội dung mô tả cục bộ và gửi cho Alice. - Khi nhận được nội dung mô tả phiên của Bob, Alice sẽ đặt nội dung đó làm nội dung mô tả từ xa bằng
setRemoteDescription
. - Ping!
Các đối tượng RTCSessionDescription
là các blob tuân thủ Giao thức mô tả phiên (SDP). Sau khi chuyển đổi tuần 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
Bạn có thể thu thập và trao đổi thông tin mạng và nội dung nghe nhìn đồng thời, nhưng cả hai quy trình này phải hoàn tất thì mới có thể bắt đầu truyền trực tuyến âm thanh và video giữa các máy ngang hàng.
Cấu trúc ưu đãi/câu trả lời được mô tả trước đó được gọi là Giao thức thiết lập phiên JavaScript (JavaScript Session Establishment Protocol) hoặc JSEP. (Có một ảnh động tuyệt vời giải thích quá trình báo hiệu và truyền trực tuyến trong video minh hoạ của Ericsson cho lần triển khai WebRTC đầu tiên.)
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 tuyến trực tiếp ngang hàng, giữa phương thức gọi và phương thức được gọi – hoặc nếu không thành công, thông qua một máy chủ chuyển tiếp trung gian (sẽ nói thêm về điều này sau). Truyền trực tuyến là công việc của RTCPeerConnection
.
RTCPeerConnection
RTCPeerConnection
là thành phần WebRTC xử lý việc truyền dữ liệu trực tuyến giữa các máy ngang hàng một cách ổn định và hiệu quả.
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!
Từ góc độ JavaScript, điều chính cần hiểu từ sơ đồ này là RTCPeerConnection
bảo vệ các nhà phát triển web khỏi vô số sự phức tạp ẩn giấu bên dưới. Các bộ mã hoá và giải mã cũng như giao thức mà WebRTC sử dụng thực hiện rất nhiều công việc để có thể giao tiếp theo thời gian thực, ngay cả trên các mạng không đáng tin cậy:
- Che giấu tình trạng mất gói
- Khử tiếng vọng
- Khả năng thích ứng với băng thông
- Lưu vào bộ đệm độ trễ động
- Điều chỉnh khuếch đại tự động
- Giảm và loại bỏ tiếng ồn
- Làm sạch hình ảnh
Mã W3C trước đó cho thấy một ví dụ đơn giản về WebRTC từ góc độ tín hiệu. Sau đây là hướng dẫn từng bước về hai ứ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 hoạt động đầy đủ.
RTCPeerConnection không có máy chủ
Mã sau đây được lấy từ mẫu WebRTC Kết nối ngang hàng, có RTCPeerConnection
cục bộ và từ xa (cùng với video cục bộ và từ xa) trên một trang web. Điều này không tạo ra bất kỳ điều gì hữu ích – phương thức gọi và phương thức được gọi nằm trên cùng một trang – nhưng giúp làm rõ hơn cách hoạt động của API RTCPeerConnection
vì các đối tượng RTCPeerConnection
trên trang có thể trao đổi dữ liệu và thông báo trực tiếp mà không cần sử dụng cơ chế báo hiệu trung gian.
Trong ví dụ này, pc1
đại diện cho máy ngang hàng cục bộ (phương thức gọi) và pc2
đại diện cho máy ngang hàng từ xa (phương thức được gọi).
Người gọi
- Tạo một
RTCPeerConnection
mới và thêm luồng từgetUserMedia()
: ```js // Máy chủ là một tệp cấu hình không bắt buộc. (Xem phần thảo luận về TURN và STUN sau.) pc1 = new RTCPeerConnection(servers); // ... localStream.getTracks().forEach((track) => { pc1.addTrack(track, localStream); });
- 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 chopc2
. Bạn có thể thực hiện việc này ngay trong mã mà không cần sử dụng tín hiệu vì cả phương thức gọi và phương thức được gọi đều nằm 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 );
Hàm được gọi
- Tạo
pc2
và khi thêm luồng từpc1
, hãy 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
cùng với các máy chủ
Trong thực tế, WebRTC cần có máy chủ, dù đơn giản đến đâu, vì vậy, những điều sau có thể xảy ra:
- Người dùng khám phá lẫn nhau và trao đổi thông tin chi tiết về thế giới thực, chẳng hạn như tên.
- Các ứng dụng khách WebRTC (đồng cấp) trao đổi thông tin mạng.
- Các máy 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 khách WebRTC đi qua cổng NAT và tường lửa.
Nói cách khác, WebRTC cần 4 loại chức năng phía máy chủ:
- Khám phá và giao tiếp với người dùng
- Báo hiệu
- Truyền tải qua NAT/tường lửa
- Máy chủ chuyển tiếp trong trường hợp giao tiếp ngang hàng không thành công
Bài viết này không đề cập đến việc vượt qua NAT, kết nối ngang hàng và các yêu cầu để tạo ứng dụng máy chủ nhằm phát hiện và báo hiệu người dùng. Chỉ cần nói rằng giao thức STUN và tiện ích của giao thức này, TURN, được khung ICE sử dụng để cho phép RTCPeerConnection
đối phó với việc truyền qua NAT và các vấn đề khác về mạng.
ICE là một khung kết nối các máy ngang hàng, chẳng hạn như hai ứng dụng trò chuyện qua video. Ban đầu, ICE cố gắng kết nối các máy ngang hàng trực tiếp với độ trễ thấp nhất có thể thông qua UDP. Trong quy trình này, máy chủ STUN chỉ có một nhiệm vụ duy nhất: cho phép một máy ngang hàng phía sau NAT tìm ra địa chỉ và cổng công khai của máy đó. (Để biết thêm thông tin về STUN và TURN, hãy xem phần Tạo các dịch vụ phụ trợ cần thiết cho ứng dụng WebRTC.)
Nếu không thành công với UDP, ICE sẽ thử TCP. Nếu không kết nối được trực tiếp (đặc biệt là do tường lửa và tính năng truyền tải NAT của doanh nghiệp), ICE sẽ sử dụng 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 với các máy ngang hàng và nếu không thành công, sẽ quay lại 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 giao diện mạng và cổng.
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 về WebRTC tại Google I/O 2013. (Các trang trình bày của bản trình bày này đưa ra ví dụ về cách triển khai máy chủ TURN và STUN.)
Ứng dụng trò chuyện video đơn giản
Bạn có thể thử WebRTC, hoàn chỉnh với tính năng báo hiệu và truyền tải NAT/tường lửa bằng máy chủ STUN, tại bản minh hoạ cuộc trò chuyện video tại appr.tc. Ứng dụng này sử dụng adapter.js, một trình bổ trợ để cách ly ứng dụng khỏi các thay đổi về thông số kỹ thuật và sự khác biệt về tiền tố.
Mã này được ghi lại một cách chi tiết. Hãy kiểm tra bảng điều khiển để nắm được thứ tự của các sự kiện. Sau đây là hướng dẫn chi tiết về mã.
Cấu trúc mạng
WebRTC, như hiện được triển khai, chỉ hỗ trợ giao tiếp một với một, nhưng có thể được sử dụng trong các tình huống mạng phức tạp hơn, chẳng hạn như với nhiều máy ngang hàng, mỗi máy 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à chuyển tiếp luồng có chọn lọc, cũng như kết hợp hoặc ghi âm âm thanh và video.
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 các thiết bị, chẳng hạn như điện thoại (còn gọi là PSTN) và với các hệ thống VOIP. Vào tháng 5 năm 2012, Doubango Telecom đã phát hành mã nguồn ứng dụng SIP sipml5 được xây dựng bằng WebRTC và WebSocket. Ứng dụng này (cùng với các ứng dụng tiềm năng khác) cho phép thực hiện cuộc 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 đã trình bày một khung giao tiếp trong trường hợp thiên tai trong một chiếc cặp bằng cách sử dụng thiết bị 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. Giao tiếp qua điện thoại mà không cần nhà mạng!
API RTCDataChannel
<
Ngoài âm thanh và video, WebRTC còn 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ỳ ý giữa các máy ngang hàng với độ trễ thấp và thông lượng cao. Để xem các bản minh hoạ một trang và tìm hiểu cách tạo một ứng dụng chuyển tệp đơn giản, hãy xem mẫu WebRTC và lớp học lập trình WebRTC tương ứng.
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 văn bản theo thời gian thực
- Chuyển tệp
- Mạng phân quyền
API này có một số tính năng để khai thác tối đa RTCPeerConnection
và cho phép giao tiếp ngang hàng mạnh mẽ và linh hoạt:
- Tận dụng chế độ thiết lập phiên
RTCPeerConnection
- Nhiều kênh đồng thời với tính năng ưu tiên
- Ngữ nghĩa phân phối đáng tin cậy và không đáng tin cậy
- Tính năng bảo mật tích hợp (DTLS) và kiểm soát tình trạng tắc nghẽn
- Có thể sử dụng có hoặc không có âm thanh hoặc video
Cú pháp này được cố tình thiết kế 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);
};
Quá trình 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 không thể tạo lỗ hổng để đối phó với tường lửa và NAT.
RTCDataChannel
có trong 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 đóng vai một người bạn hoặc một chú gấu! Nền tảng sáng tạo Sharefest cho phép chia sẻ tệp thông qua RTCDataChannel
và peerCDN đã cung cấp một cái nhìn tổng quan về cách WebRTC có thể hỗ trợ 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 giao thức nháp của IETF.
Bảo mật
Có một số cách mà ứng dụng hoặc trình bổ trợ giao tiếp theo thời gian thực có thể làm ảnh hưởng đến tính bảo mật. Ví dụ:
- Nội dung nghe nhìn hoặc dữ liệu chưa 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 vi-rút có thể được cài đặt cùng với một trình bổ trợ hoặc ứng dụng có vẻ vô hại.
WebRTC có một số tính năng để tránh những vấn đề này:
- Các hoạt động triển khai WebRTC sử dụng các giao thức bảo mật, chẳng hạn như DTLS và SRTP.
- Tất cả thành phần WebRTC đều bắt buộc phải mã hoá, bao gồm 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 phải 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 biệt và được cập nhật mỗi khi trình duyệt được cập nhật.
- Quyền truy cập vào máy ảnh và micrô phải được cấp một cách rõ ràng và khi máy ảnh hoặc micrô đang chạy, giao diện người dùng phải hiển thị rõ điều này.
Bài viết này không thảo luận đầy đủ về vấn đề bảo mật cho nội dung nghe nhìn trực tuyến. Để biết thêm thông tin, hãy xem Cấu trúc bảo mật WebRTC được đề xuất do IETF đề xuất.
Kết luận
Các API và tiêu chuẩn của WebRTC có thể phổ biến và phân cấp các công cụ tạo nội dung và giao tiếp, bao gồm cả điện thoại, trò chơi, sản xuất video, sáng tác nhạc và thu thập tin tức.
Công nghệ không còn bất ngờ hơn thế nữa.
Như blogger Phil Edholm nói, "WebRTC và HTML5 có thể hỗ trợ cùng một quá trình chuyển đổi cho hoạt động giao tiếp theo thời gian thực mà trình duyệt gốc đã thực hiện cho 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 cho một phiên đang diễn ra tại:
- about://webrtc-internals trong Chrome
- opera://webrtc-internals trong Opera
- about:webrtc trong Firefox
- Ghi chú về khả năng tương tác trên nhiều trình duyệt
- adapter.js là một trình bổ trợ JavaScript cho WebRTC do Google duy trì với sự trợ giúp của cộng đồng WebRTC. Trình bổ trợ này tóm tắt các tiền tố của nhà cung cấp, sự khác biệt về 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 vào bảng điều khiển.
- Nếu tất cả đều quá nhiều, bạn nên sử dụng khung WebRTC hoặc thậm chí là một dịch vụ WebRTC hoàn chỉnh.
- Chúng tôi luôn hoan nghênh báo cáo lỗi và yêu cầu về tính năng:
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 duy trì một cuốn sách về WebRTC hiện đã xuất bản phiên bản thứ ba ở định dạng sách in và sách điện tử tại webrtcbook.com.
- webrtc.org là trang chủ của tất cả nội dung liên quan đến WebRTC, bao gồm cả bản minh hoạ, tài liệu và nội dung thảo luận.
- discuss-webrtc là một Google Group dành cho thảo luận về kỹ thuật WebRTC.
- @webrtc
- Tài liệu về Talk của Google Developers cung cấp thêm thông tin về việc vượt qua NAT, STUN, máy chủ chuyển tiếp và thu thập đề xuất.
- 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
- Bản thảo của Trình chỉnh sửa WebRTC W3C
- Bản nháp của biên tập viên W3C: Quay video và truyền trực tuyến (còn gọi là
getUserMedia
) - Hiến chương của Nhóm làm việc IETF
- Bản thảo Giao thức kênh dữ liệu WebRTC của IETF
- Bản thảo JSEP của IETF
- Tiêu chuẩn do IETF đề xuất cho ICE
- Bản thảo Internet của Nhóm làm việc RTCWEB của IETF: Các trường hợp sử dụng và yêu cầu về giao tiếp theo thời gian thực trên web
Tóm tắt về dịch vụ hỗ trợ WebRTC
API MediaStream
và getUserMedia
- Chrome phiên bản dành cho máy tính 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 phiên bản dành cho máy tính 20 trở lên; Chrome dành cho Android 29 trở lên (không có cờ)
- Opera 18 trở lên (bật theo mặc định); Opera 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 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ề khả năng hỗ trợ nhiều nền tảng cho API, chẳng hạn như getUserMedia
và RTCPeerConnection
, hãy xem caniuse.com và Trạng thái của nền tảng Chrome.
Bạn cũng có thể xem các API gốc cho RTCPeerConnection
tại tài liệu trên webrtc.org.