Ngày xuất bản: 4 tháng 11 năm 2013
WebRTC cho phép giao tiếp ngang hàng. Công nghệ này cần có máy chủ để ứng dụng có thể trao đổi siêu dữ liệu và điều phối hoạt động giao tiếp thông qua một quy trình gọi là báo hiệu. Máy chủ cũng giúp máy khách xử lý các trình dịch địa chỉ mạng (NAT) và tường lửa.
Tại đây, bạn sẽ tìm hiểu cách xây dựng dịch vụ báo hiệu và xử lý các vấn đề về khả năng kết nối trong thực tế bằng máy chủ STUN và TURN. Bạn cũng sẽ hiểu cách các ứng dụng WebRTC có thể xử lý cuộc gọi nhiều bên và tương tác với các dịch vụ, chẳng hạn như VoIP và PSTN (còn gọi là điện thoại).
Báo hiệu là gì?
Báo hiệu là quá trình điều phối hoạt động giao tiếp. Để ứng dụng WebRTC thiết lập cuộc gọi, ứng dụng khách cần trao đổi thông tin sau:
- Tin nhắn kiểm soát phiên được dùng để mở hoặc đóng hoạt động giao tiếp
- Thông báo lỗi
- Siêu dữ liệu nội dung nghe nhìn, chẳng hạn như bộ mã hoá và giải mã, chế độ cài đặt bộ mã hoá và giải mã, băng thông và loại nội dung nghe nhìn
- Dữ liệu khoá dùng để thiết lập kết nối bảo mật
- Dữ liệu mạng, chẳng hạn như địa chỉ IP và cổng của máy chủ lưu trữ mà bên ngoài nhìn thấy
Quá trình báo hiệu này cần có một cách để các ứng dụng truyền thông báo qua lại. Cơ chế đó không được triển khai bởi API WebRTC. Thay vào đó, bạn cần tự xây dựng.
Tại sao WebRTC không xác định tín hiệu?
Để tránh dư thừa và tối đa hoá khả năng tương thích với các công nghệ đã có, các phương thức và giao thức báo hiệu không được chỉ định theo tiêu chuẩn WebRTC. Phương pháp này được nêu trong Giao thức thiết lập phiên JavaScript (JSEP):
Kiến trúc của JSEP cũng giúp trình duyệt không phải lưu trạng thái, tức là hoạt động như một máy trạng thái báo hiệu. Điều này sẽ gây ra vấn đề nếu, ví dụ, dữ liệu báo hiệu bị mất mỗi khi tải lại trang. Thay vào đó, trạng thái báo hiệu có thể được lưu trên máy chủ.
JSEP yêu cầu trao đổi giữa các ứng dụng ngang hàng về đề nghị và phản hồi, siêu dữ liệu nội dung nghe nhìn. Đề nghị và câu trả lời được truyền đạt theo định dạng Giao thức mô tả phiên (SDP), có dạng như sau:
v=0
o=- 7614219274584779017 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE audio video
a=msid-semantic: WMS
m=audio 1 RTP/SAVPF 111 103 104 0 8 107 106 105 13 126
c=IN IP4 0.0.0.0
a=rtcp:1 IN IP4 0.0.0.0
a=ice-ufrag:W2TGCZw2NZHuwlnf
a=ice-pwd:xdQEccP40E+P0L5qTyzDgfmW
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=mid:audio
a=rtcp-mux
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:9c1AHz27dZ9xPI91YNfSlI67/EMkjHHIHORiClQe
a=rtpmap:111 opus/48000/2
...
Bạn muốn biết ý nghĩa thực sự của tất cả những thuật ngữ SDP khó hiểu này? Hãy xem các ví dụ của Lực lượng chuyên trách kỹ thuật Internet (IETF).
Xin lưu ý rằng WebRTC được thiết kế để có thể điều chỉnh đề nghị hoặc câu trả lời trước khi được đặt làm nội dung mô tả cục bộ hoặc từ xa bằng cách chỉnh sửa các giá trị trong văn bản SDP. Ví dụ: bạn có thể dùng hàm preferAudioCodec() trong appr.tc để đặt bộ mã hoá và giải mã cũng như tốc độ bit mặc định. SDP
hơi khó thao tác bằng JavaScript và có cuộc thảo luận về
việc liệu các phiên bản WebRTC trong tương lai có nên sử dụng JSON hay không, nhưng có
một số lợi thế
khi sử dụng SDP.
RTCPeerConnection API và tín hiệu: Đề nghị, phản hồi và ứng viên
RTCPeerConnection là API mà các ứng dụng WebRTC dùng để tạo kết nối giữa các ứng dụng ngang hàng, cũng như truyền âm thanh và video.
Để khởi chạy quy trình này, RTCPeerConnection có hai nhiệm vụ:
- Xác định các điều kiện của nội dung nghe nhìn cục bộ, chẳng hạn như độ phân giải và khả năng của bộ mã hoá và giải mã. Đây là siêu dữ liệu được dùng cho cơ chế đề nghị và trả lời.
- Lấy địa chỉ mạng tiềm năng cho máy chủ của ứng dụng, còn gọi là ứng viên.
Sau khi xác định được dữ liệu địa phương này, dữ liệu đó phải được trao đổi thông qua cơ chế báo hiệu với ứng dụng ngang hàng từ xa.
Hãy tưởng tượng Alice đang cố gắng gọi cho Eve. Sau đây là cơ chế trả lời đầy đủ với tất cả thông tin chi tiết:
- Alice tạo một đối tượng
RTCPeerConnection. - Alice tạo một đề nghị (mô tả phiên SDP) bằng phương thức
RTCPeerConnectioncreateOffer(). - Alice gọi cho
setLocalDescription()để đưa ra đề nghị. - Alice chuyển đổi đề nghị thành chuỗi và sử dụng cơ chế báo hiệu để gửi đề nghị đó cho Eve.
- Eve gọi
setRemoteDescription()bằng lời đề nghị của Alice đểRTCPeerConnectioncủa cô biết về chế độ thiết lập của Alice. - Eve gọi
createAnswer()và lệnh gọi lại thành công cho lệnh này được truyền một nội dung mô tả phiên cục bộ – câu trả lời của Eve. - Eve đặt câu trả lời của mình làm nội dung mô tả cục bộ bằng cách gọi
setLocalDescription(). - Sau đó, Eve sử dụng cơ chế báo hiệu để gửi câu trả lời đã chuyển đổi thành chuỗi cho Alice.
- Alice đặt câu trả lời của Eve làm nội dung mô tả phiên từ xa bằng
setRemoteDescription().
Alice và Eve cũng cần trao đổi thông tin mạng. Cụm từ "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
RTCPeerConnectionbằng trình xử lýonicecandidate. - Trình xử lý được gọi khi có các ứng viên mạng.
- Trong trình xử lý, Alice gửi dữ liệu ứng viên được xâu chuỗi cho Eve thông qua kênh báo hiệu của họ.
- Khi nhận được thông báo về ứng viên từ Alice, Eve sẽ gọi
addIceCandidate()để thêm ứng viên vào nội dung mô tả ứng viên ngang hàng từ xa.
JSEP hỗ trợ ICE Candidate Trickling, cho phép người gọi cung cấp dần các ứng viên cho người nhận cuộc gọi sau khi đưa ra đề nghị ban đầu, đồng thời cho phép người nhận cuộc gọi bắt đầu thực hiện cuộc gọi và thiết lập kết nối mà không cần đợi tất cả ứng viên đến.
Mã WebRTC để báo hiệu
Đoạn mã sau đây là một ví dụ về mã W3C tóm tắt toàn bộ quy trình báo hiệu. Mã này giả định sự tồn tại của một số cơ chế báo hiệu, SignalingChannel. Tín hiệu sẽ được thảo luận chi tiết hơn ở phần sau.
// 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);
}
};
// After 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);
}
};
Để xem các quy trình đề nghị-trả lời và trao đổi ứng viên trong thực tế, hãy truy cập vào simpl.info RTCPeerConnection và xem nhật ký bảng điều khiển để biết ví dụ về cuộc trò chuyện video trên một trang. Bạn có thể tải bản kết xuất hoàn chỉnh của tín hiệu và số liệu thống kê WebRTC xuống từ trang about://webrtc-internals trong Google Chrome hoặc trang opera://webrtc-internals trong Opera.
Khám phá thiết bị ngang hàng
Đây là một cách hỏi hoa mỹ cho câu hỏi: "Làm cách nào để tìm người trò chuyện?"
Đối với cuộc gọi điện thoại, bạn có số điện thoại và danh bạ. Để trò chuyện video và nhắn tin trực tuyến, bạn cần có hệ thống quản lý danh tính và trạng thái, cũng như phương tiện để người dùng bắt đầu phiên. Ứng dụng WebRTC cần có cách để ứng dụng báo hiệu cho nhau rằng họ muốn bắt đầu hoặc tham gia cuộc gọi.
Cơ chế khám phá ngang hàng không được WebRTC xác định và bạn không cần tìm hiểu các lựa chọn ở đây. Quá trình này có thể đơn giản như việc gửi URL qua email hoặc tin nhắn. Đối với các ứng dụng trò chuyện video như Talky, tawk.to và Browser Meeting, bạn có thể mời mọi người tham gia cuộc gọi bằng cách chia sẻ một đường liên kết tuỳ chỉnh. Nhà phát triển Chris Ball đã xây dựng một thử nghiệm webrtc không máy chủ thú vị, cho phép người tham gia cuộc gọi WebRTC trao đổi siêu dữ liệu bằng bất kỳ dịch vụ nhắn tin nào họ thích, chẳng hạn như tin nhắn tức thời, email hoặc bồ câu đưa thư.
Làm cách nào để xây dựng dịch vụ báo hiệu?
Xin nhắc lại, các giao thức và cơ chế báo hiệu không được xác định theo tiêu chuẩn WebRTC. Dù chọn cách nào, bạn cũng cần có một máy chủ trung gian để trao đổi thông báo báo hiệu và dữ liệu ứng dụng giữa các ứng dụng. Đáng tiếc là ứng dụng web không thể hét lên với Internet rằng "Hãy kết nối tôi với bạn của tôi!"
Rất may là các thông báo báo hiệu có kích thước nhỏ và hầu hết được trao đổi khi bắt đầu cuộc gọi. Khi thử nghiệm với appr.tc cho một phiên trò chuyện video, dịch vụ báo hiệu đã xử lý tổng cộng khoảng 30-45 thông báo với tổng kích thước cho tất cả thông báo là khoảng 10 KB.
Ngoài việc tương đối ít yêu cầu về băng thông, các dịch vụ báo hiệu WebRTC không tiêu tốn nhiều tài nguyên xử lý hoặc bộ nhớ vì chúng chỉ cần chuyển tiếp thông báo và giữ lại một lượng nhỏ dữ liệu trạng thái phiên, chẳng hạn như ứng dụng nào được kết nối.
Đẩy thông báo từ máy chủ đến ứng dụng
Dịch vụ thông báo cho tín hiệu cần phải có hai chiều: từ máy khách đến máy chủ và từ máy chủ đến máy khách. Giao tiếp hai chiều đi ngược lại mô hình yêu cầu/phản hồi của máy khách/máy chủ HTTP, nhưng nhiều thủ thuật như thăm dò ý kiến dài đã được phát triển trong nhiều năm để đẩy dữ liệu từ một dịch vụ chạy trên máy chủ web đến một ứng dụng web chạy trong trình duyệt.
EventSource API cho phép các sự kiện do máy chủ gửi, dữ liệu được gửi từ máy chủ web đến ứng dụng trình duyệt thông qua HTTP. EventSource được thiết kế để nhắn tin một chiều, nhưng có thể được dùng kết hợp với XHR để xây dựng dịch vụ trao đổi thông báo báo hiệu. Dịch vụ báo hiệu truyền thông báo từ người gọi, được gửi bằng yêu cầu XHR, bằng cách đẩy thông báo đó qua EventSource đến người nhận cuộc gọi.
WebSocket được thiết kế để giao tiếp song công hoàn toàn giữa máy khách và máy chủ, tức là thông báo có thể truyền theo cả hai hướng cùng một lúc. Một lợi thế của dịch vụ báo hiệu được xây dựng bằng WebSocket thuần tuý hoặc
sự kiện do máy chủ gửi (EventSource) là phần phụ trợ cho các API này có thể
được triển khai trên nhiều khung web phổ biến cho hầu hết các gói lưu trữ web
cho các ngôn ngữ như PHP, Python và Ruby.
Tất cả trình duyệt hỗ trợ WebRTC cũng hỗ trợ WebSocket. Bạn nên sử dụng TLS cho tất cả các kết nối để đảm bảo thư không bị chặn khi chưa mã hoá, đồng thời giảm thiểu các vấn đề về truyền tải qua proxy. Để biết thêm thông tin về WebSocket và truyền tải proxy, hãy đọc chương WebRTC trong cuốn sách High Performance Browser Networking (Kết nối mạng trình duyệt hiệu suất cao) của Ilya Grigorik.
Bạn có thể xử lý tín hiệu bằng cách yêu cầu ứng dụng WebRTC thăm dò ý kiến của máy chủ nhắn tin nhiều lần thông qua Ajax, nhưng điều đó dẫn đến nhiều yêu cầu mạng dư thừa, đặc biệt là đối với thiết bị di động. Ngay cả sau khi một phiên đã được thiết lập, các ứng dụng ngang hàng vẫn cần thăm dò ý kiến để nhận thông báo báo hiệu trong trường hợp có thay đổi hoặc chấm dứt phiên bởi các ứng dụng ngang hàng khác. Ví dụ về ứng dụng WebRTC Book sử dụng lựa chọn này cùng với một số tính năng tối ưu hoá cho tần suất thăm dò ý kiến.
Tín hiệu về quy mô
Mặc dù dịch vụ báo hiệu tiêu thụ tương đối ít băng thông và CPU trên mỗi máy khách, nhưng máy chủ báo hiệu cho một ứng dụng phổ biến có thể phải xử lý nhiều thông báo từ nhiều vị trí khác nhau với mức độ đồng thời cao. Các ứng dụng WebRTC có lưu lượng truy cập cao cần có máy chủ báo hiệu có thể xử lý tải đáng kể. Bạn không cần đi sâu vào chi tiết ở đây, nhưng có một số lựa chọn cho tính năng nhắn tin hiệu suất cao, lưu lượng lớn, bao gồm:
Giao thức hiện diện và nhắn tin có thể mở rộng (XMPP) là một giao thức được phát triển cho tính năng nhắn tin nhanh, có thể dùng để báo hiệu. Các cách triển khai máy chủ bao gồm ejabberd và Openfire. Ứng dụng JavaScript, chẳng hạn như Strophe.js, sử dụng BOSH để mô phỏng tính năng truyền trực tuyến hai chiều, nhưng BOSH có thể không hiệu quả và khó mở rộng quy mô so với WebSocket.
Thư viện nguồn mở, chẳng hạn như ZeroMQ (được TokBox sử dụng cho dịch vụ Rumour của họ) và OpenMQ (NullMQ áp dụng các khái niệm ZeroMQ cho nền tảng web bằng giao thức STOMP qua WebSocket.)
Các nền tảng gửi thông báo qua đám mây thương mại sử dụng WebSocket (mặc dù có thể quay lại sử dụng kỹ thuật thăm dò dài), chẳng hạn như Pusher và Kaazing.
Các nền tảng WebRTC thương mại, chẳng hạn như vLine
Xây dựng dịch vụ báo hiệu bằng Socket.io trên Node
Sau đây là mã cho một ứng dụng web sử dụng dịch vụ báo hiệu được xây dựng bằng Socket.io trên Node. Thiết kế của Socket.io giúp bạn dễ dàng xây dựng một dịch vụ để trao đổi thông báo và Socket.io đặc biệt phù hợp với tín hiệu WebRTC nhờ khái niệm tích hợp sẵn về phòng. Ví dụ này được thiết kế cho một số lượng người dùng tương đối nhỏ, thay vì cho mục đích sản xuất.
Socket.io sử dụng WebSocket với các phương án dự phòng: thăm dò ý kiến dài hạn AJAX, phát trực tuyến nhiều phần AJAX, Forever Iframe và thăm dò ý kiến JSONP. Thư viện này đã được chuyển sang nhiều phần phụ trợ, nhưng có lẽ nổi tiếng nhất là phiên bản Node được dùng trong ví dụ này.
Trong ví dụ này, không có WebRTC. Mục đích của ứng dụng này là minh hoạ cách xây dựng tín hiệu vào một ứng dụng web. Hãy xem nhật ký bảng điều khiển để biết điều gì xảy ra khi ứng dụng khách tham gia phòng và trao đổi thông báo. Lớp học lập trình WebRTC này cung cấp hướng dẫn từng bước về cách tích hợp lớp học này vào một ứng dụng trò chuyện video WebRTC hoàn chỉnh.
Sau đây là ứng dụng index.html:
<!DOCTYPE html>
<html>
<head>
<title>WebRTC client</title>
</head>
<body>
<script src='/socket.io/socket.io.js'></script>
<script src='js/main.js'></script>
</body>
</html>
Dưới đây là tệp JavaScript main.js được tham chiếu trong ứng dụng:
const isInitiator;
room = prompt('Enter room name:');
const socket = io.connect();
if (room !== '') {
console.log('Joining room ' + room);
socket.emit('create or join', room);
}
socket.on('full', (room) => {
console.log('Room ' + room + ' is full');
});
socket.on('empty', (room) => {
isInitiator = true;
console.log('Room ' + room + ' is empty');
});
socket.on('join', (room) => {
console.log('Making request to join room ' + room);
console.log('You are the initiator!');
});
socket.on('log', (array) => {
console.log.apply(console, array);
});
Dưới đây là ứng dụng máy chủ hoàn chỉnh:
const static = require('node-static');
const http = require('http');
const file = new(static.Server)();
const app = http.createServer(function (req, res) {
file.serve(req, res);
}).listen(2013);
const io = require('socket.io').listen(app);
io.sockets.on('connection', (socket) => {
// Convenience function to log server messages to the client
function log(){
const array = ['>>> Message from server: '];
for (const i = 0; i < arguments.length; i++) {
array.push(arguments[i]);
}
socket.emit('log', array);
}
socket.on('message', (message) => {
log('Got message:', message);
// For a real app, would be room only (not broadcast)
socket.broadcast.emit('message', message);
});
socket.on('create or join', (room) => {
const numClients = io.sockets.clients(room).length;
log('Room ' + room + ' has ' + numClients + ' client(s)');
log('Request to create or join room ' + room);
if (numClients === 0){
socket.join(room);
socket.emit('created', room);
} else if (numClients === 1) {
io.sockets.in(room).emit('join', room);
socket.join(room);
socket.emit('joined', room);
} else { // max two clients
socket.emit('full', room);
}
socket.emit('emit(): client ' + socket.id +
' joined room ' + room);
socket.broadcast.emit('broadcast(): client ' + socket.id +
' joined room ' + room);
});
});
Để chạy ứng dụng này trên máy chủ cục bộ, bạn cần có Node.js, Socket.IO và node-static. Để cài đặt Socket.IO và node-static, hãy chạy npm từ một dòng lệnh trong thư mục ứng dụng:
npm install socket.io
npm install node-static
Để khởi động máy chủ, hãy chạy lệnh sau từ một dòng lệnh trong thư mục ứng dụng:
node server.js
Trên trình duyệt, hãy mở localhost:2013. Mở một thẻ hoặc cửa sổ mới trong bất kỳ trình duyệt nào rồi mở lại localhost:2013. Để xem điều gì đang xảy ra, hãy kiểm tra bảng điều khiển. Trong Chrome và Opera, bạn có thể truy cập vào bảng điều khiển thông qua Công cụ cho nhà phát triển của Google Chrome bằng tổ hợp phím Ctrl+Shift+J (hoặc Command+Option+J trên máy Mac).
Dù bạn chọn phương pháp nào để báo hiệu, thì ứng dụng khách và phần phụ trợ của bạn cũng cần cung cấp các dịch vụ tương tự như ví dụ này.
Những điều cần lưu ý về tín hiệu
RTCPeerConnectionsẽ không bắt đầu thu thập ứng viên cho đến khisetLocalDescription()được gọi. Điều này được quy định trong bản dự thảo JSEP IETF.- Tận dụng Trickle ICE. Hãy gọi
addIceCandidate()ngay khi ứng viên đến.
Máy chủ tín hiệu có sẵn
Nếu không muốn tự triển khai, bạn có thể sử dụng một số máy chủ báo hiệu WebRTC có sẵn. Các máy chủ này sử dụng Socket.IO như ví dụ trước và được tích hợp với các thư viện JavaScript của ứng dụng WebRTC:
- webRTC.io là một trong những thư viện trừu tượng đầu tiên cho WebRTC.
- Signalmaster là một máy chủ báo hiệu được tạo để sử dụng với thư viện ứng dụng JavaScript SimpleWebRTC.
Nếu bạn không muốn viết bất kỳ mã nào, thì các nền tảng WebRTC thương mại hoàn chỉnh sẽ được cung cấp từ các công ty, chẳng hạn như vLine, OpenTok và Asterisk.
Để ghi lại, Ericsson đã xây dựng một máy chủ báo hiệu bằng PHP trên Apache trong những ngày đầu của WebRTC. Mặc dù hiện tại, cách này đã lỗi thời nhưng bạn vẫn nên xem mã nếu đang cân nhắc một giải pháp tương tự.
Bảo mật tín hiệu
Mã hoá là bắt buộc đối với tất cả các thành phần WebRTC.
Tuy nhiên, cơ chế báo hiệu không được xác định theo tiêu chuẩn WebRTC, vì vậy, bạn phải đảm bảo tín hiệu được bảo mật. Nếu kẻ tấn công chiếm được quyền kiểm soát tín hiệu, chúng có thể dừng phiên, chuyển hướng kết nối và ghi lại, thay đổi hoặc chèn nội dung.
Yếu tố quan trọng nhất trong việc bảo mật tín hiệu là sử dụng các giao thức bảo mật: HTTPS và WSS, chẳng hạn như TLS. Điều này đảm bảo rằng thư không thể bị chặn khi chưa được mã hoá. Ngoài ra, hãy cẩn thận để không truyền tin nhắn báo hiệu theo cách mà những người gọi khác có thể truy cập bằng cùng một máy chủ báo hiệu.
Xử lý NAT và tường lửa
Đối với việc truyền tín hiệu siêu dữ liệu, các ứng dụng WebRTC sử dụng một máy chủ trung gian, nhưng đối với việc truyền trực tuyến nội dung nghe nhìn và dữ liệu thực tế sau khi thiết lập phiên, RTCPeerConnection sẽ cố gắng kết nối trực tiếp các ứng dụng khách hoặc kết nối ngang hàng.
Trong một thế giới đơn giản hơn, mọi điểm cuối WebRTC sẽ có một địa chỉ duy nhất mà điểm cuối đó có thể trao đổi với các ứng dụng ngang hàng khác để giao tiếp trực tiếp.
Trên thực tế, hầu hết các thiết bị đều nằm sau một hoặc nhiều lớp NAT, một số thiết bị có phần mềm diệt virus chặn một số cổng và giao thức nhất định, và nhiều thiết bị nằm sau proxy và tường lửa của công ty. Trên thực tế, tường lửa và NAT có thể được triển khai trên cùng một thiết bị, chẳng hạn như bộ định tuyến Wi-Fi tại nhà.
Ứng dụng WebRTC có thể sử dụng khung ICE để khắc phục những vấn đề phức tạp của mạng thực tế. Để bật tính năng này,
ứng dụng của bạn phải truyền URL của máy chủ ICE đến RTCPeerConnection.
ICE cố gắng tìm ra cách tốt nhất để kết nối các ứng dụng ngang hàng. Hệ thống sẽ thử tất cả các khả năng song song và chọn phương án hiệu quả nhất. Trước tiên, ICE sẽ cố gắng kết nối bằng địa chỉ máy chủ lấy từ hệ điều hành và thẻ mạng của thiết bị. Nếu không thành công (điều này sẽ xảy ra đối với các thiết bị phía sau NAT), ICE sẽ lấy địa chỉ bên ngoài bằng máy chủ STUN và nếu không thành công, lưu lượng truy cập sẽ được định tuyến thông qua máy chủ chuyển tiếp TURN.
Nói cách khác, máy chủ STUN được dùng để lấy địa chỉ mạng bên ngoài và máy chủ TURN được dùng để chuyển tiếp lưu lượng truy cập nếu kết nối trực tiếp (ngang hàng) không thành công.
Mọi máy chủ TURN đều hỗ trợ STUN. Máy chủ TURN là một máy chủ STUN có thêm chức năng chuyển tiếp tích hợp sẵn. ICE cũng xử lý các vấn đề phức tạp của chế độ thiết lập NAT. Trên thực tế, việc đục lỗ NAT có thể yêu cầu nhiều hơn chỉ một địa chỉ IP:cổng công khai.
URL cho máy chủ STUN và TURN được (không bắt buộc) chỉ định bởi một ứng dụng WebRTC trong đối tượng cấu hình iceServers là đối số đầu tiên cho hàm khởi tạo RTCPeerConnection. Đối với appr.tc, giá trị đó có dạng như sau:
{
'iceServers': [
{
'urls': 'stun:stun.l.google.com:19302'
},
{
'urls': 'turn:192.158.29.39:3478?transport=udp',
'credential': 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
'username': '28224511:1379330808'
},
{
'urls': 'turn:192.158.29.39:3478?transport=tcp',
'credential': 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
'username': '28224511:1379330808'
}
]
}
Sau khi RTCPeerConnection có thông tin đó, phép thuật ICE sẽ tự động xảy ra. RTCPeerConnection sử dụng khung ICE để tìm ra đường dẫn tốt nhất giữa các ứng dụng ngang hàng, hoạt động với các máy chủ STUN và TURN nếu cần.
STUN
NAT cung cấp cho thiết bị một địa chỉ IP để sử dụng trong mạng cục bộ riêng tư, nhưng địa chỉ này không thể dùng bên ngoài. Nếu không có địa chỉ công khai, các ứng dụng ngang hàng WebRTC sẽ không thể giao tiếp. Để giải quyết vấn đề này, WebRTC sử dụng STUN.
Máy chủ STUN hoạt động trên Internet công cộng và có một nhiệm vụ: kiểm tra địa chỉ IP:cổng của một yêu cầu đến (từ một ứng dụng chạy phía sau NAT) và gửi lại địa chỉ đó dưới dạng phản hồi. Nói cách khác, ứng dụng sử dụng máy chủ STUN để khám phá IP:port từ góc độ công khai. Quá trình này cho phép một ứng dụng ngang hàng WebRTC lấy địa chỉ có thể truy cập công khai cho chính nó, sau đó chuyển địa chỉ đó đến một ứng dụng ngang hàng khác thông qua cơ chế báo hiệu để thiết lập đường liên kết trực tiếp.
Máy chủ STUN không phải làm nhiều việc hoặc ghi nhớ nhiều, vì vậy, máy chủ STUN có thông số kỹ thuật tương đối thấp có thể xử lý một số lượng lớn yêu cầu.
Hầu hết các cuộc gọi WebRTC đều kết nối thành công bằng STUN, mặc dù có thể ít hơn đối với các cuộc gọi giữa các ứng dụng ngang hàng phía sau tường lửa và cấu hình NAT phức tạp.
LƯỢT
RTCPeerConnection cố gắng thiết lập giao tiếp trực tiếp giữa các ứng dụng ngang hàng qua UDP.
Nếu không thành công, RTCPeerConnection sẽ chuyển sang dùng TCP. Nếu không thành công, bạn có thể sử dụng máy chủ TURN làm phương án dự phòng, chuyển tiếp dữ liệu giữa các điểm cuối.
Xin nhắc lại, TURN được dùng để chuyển tiếp âm thanh, video và truyền dữ liệu giữa các ứng dụng ngang hàng, chứ không phải dữ liệu báo hiệu!
Máy chủ TURN có địa chỉ công khai, vì vậy, các ứng dụng ngang hàng có thể liên hệ với máy chủ TURN ngay cả khi các ứng dụng ngang hàng đó nằm sau tường lửa hoặc proxy. Máy chủ TURN có một nhiệm vụ: chuyển tiếp một luồng. Không giống như máy chủ STUN, máy chủ TURN vốn tiêu tốn rất nhiều băng thông.
Sơ đồ này cho thấy cách thức hoạt động của TURN. STUN thuần tuý không thành công, vì vậy, mỗi ứng dụng ngang hàng phải sử dụng máy chủ TURN.
Triển khai máy chủ STUN và TURN
Để thử nghiệm, Google chạy một máy chủ STUN công khai, stun.l.google.com:19302, như được appr.tc sử dụng. Đối với dịch vụ STUN/TURN chính thức, hãy sử dụng rfc5766-turn-server. Mã nguồn cho máy chủ STUN và TURN có trên GitHub, nơi bạn cũng có thể tìm thấy đường liên kết đến một số nguồn thông tin về việc cài đặt máy chủ. Ngoài ra, bạn cũng có thể sử dụng hình ảnh máy ảo cho Amazon Web Services.
Một máy chủ TURN thay thế là restund, có sẵn dưới dạng mã nguồn và cũng dành cho AWS. Bạn có thể thiết lập restund trên Compute :
- Mở tường lửa nếu cần cho tcp=443, udp/tcp=3478.
- Tạo 4 thực thể, mỗi thực thể cho một IP công khai, hình ảnh Ubuntu 12.06 tiêu chuẩn.
- Thiết lập cấu hình tường lửa cục bộ (cho phép MỌI THỨ từ MỌI NƠI).
- Cài đặt các công cụ:
shell sudo apt-get install make sudo apt-get install gcc - Cài đặt libre từ creytiv.com/re.html.
- Tìm nạp restund từ creytiv.com/restund.html rồi giải nén.
wgethancke.name/restund-auth.patch rồi áp dụng bằngpatch -p1 < restund-auth.patch.- Chạy
make,sudo make installcho libre và restund. - Điều chỉnh
restund.confcho phù hợp với nhu cầu của bạn (thay thế địa chỉ IP và đảm bảo địa chỉ IP đó chứa cùng một khoá bí mật dùng chung) rồi sao chép vào/etc. - Sao chép
restund/etc/restundvào/etc/init.d/. - Định cấu hình restund:
- Đặt
LD_LIBRARY_PATH. - Sao chép
restund.confvào/etc/restund.conf. - Đặt
restund.confđể sử dụng 10 bên phải. Địa chỉ IP.
- Đặt
- Chạy restund
- Kiểm thử bằng ứng dụng stund từ máy từ xa:
./client IP:port
WebRTC nhiều bên
Bạn cũng nên xem tiêu chuẩn IETF do Justin Uberti đề xuất cho API REST để truy cập vào Dịch vụ TURN.
Có nhiều trường hợp sử dụng tính năng truyền trực tuyến nội dung nghe nhìn ngoài cuộc gọi trực tiếp. Ví dụ: hội nghị truyền hình giữa một nhóm đồng nghiệp hoặc một sự kiện công khai có một diễn giả và hàng trăm hoặc hàng triệu người xem.
Ứng dụng WebRTC có thể sử dụng nhiều RTCPeerConnection để mọi điểm cuối đều kết nối với mọi điểm cuối khác trong cấu hình lưới. Đây là phương pháp được các ứng dụng như talky.io áp dụng và hoạt động rất hiệu quả đối với một số ít ứng dụng ngang hàng. Ngoài ra, mức tiêu thụ băng thông và xử lý sẽ trở nên quá mức, đặc biệt là đối với ứng dụng di động.
Ngoài ra, ứng dụng WebRTC có thể chọn một điểm cuối để phân phối luồng đến tất cả các điểm cuối khác trong cấu hình hình sao. Bạn cũng có thể chạy một điểm cuối WebRTC trên máy chủ và xây dựng cơ chế phân phối lại của riêng mình (ứng dụng khách mẫu do webrtc.org cung cấp).
Bạn có thể dùng MediaStream của một RTCPeerConnection làm dữ liệu đầu vào cho một
khác. Điều này có thể cho phép các kiến trúc linh hoạt hơn vì nó cho phép một ứng dụng web xử lý định tuyến cuộc gọi bằng cách chọn kết nối với ứng dụng ngang hàng nào khác. Để xem cách hoạt động của tính năng này, hãy xem Mẫu WebRTC về chuyển tiếp kết nối ngang hàng và Mẫu WebRTC về nhiều kết nối ngang hàng.
Bộ điều khiển đa điểm
Một lựa chọn tốt hơn cho số lượng lớn điểm cuối là sử dụng bộ điều khiển đa điểm (MCU). Đây là một máy chủ hoạt động như một cầu nối để phân phối nội dung nghe nhìn giữa một số lượng lớn người tham gia. MCU có thể xử lý nhiều độ phân giải, bộ mã hoá và giải mã, cũng như tốc độ khung hình trong một hội nghị truyền hình; xử lý việc chuyển mã; chuyển tiếp luồng có chọn lọc; cũng như kết hợp hoặc ghi âm thanh và video. Đối với cuộc gọi nhiều bên, có một số vấn đề cần xem xét, đặc biệt là cách hiển thị nhiều đầu vào video và kết hợp âm thanh từ nhiều nguồn. Các nền tảng đám mây, chẳng hạn như vLine, cũng cố gắng tối ưu hoá việc định tuyến lưu lượng truy cập.
Bạn có thể mua một gói phần cứng MCU hoàn chỉnh hoặc tự xây dựng.
Có một số lựa chọn phần mềm MCU nguồn mở. Ví dụ: Licode (trước đây gọi là Lynckia) tạo ra một MCU nguồn mở cho WebRTC. OpenTok có Mantis.
Ngoài trình duyệt: VoIP, điện thoại và nhắn tin
Bản chất chuẩn hoá của WebRTC giúp bạn có thể thiết lập hoạt động giao tiếp giữa một ứng dụng WebRTC chạy trong trình duyệt và một thiết bị hoặc nền tảng chạy trên một nền tảng giao tiếp khác, chẳng hạn như điện thoại hoặc hệ thống hội nghị truyền hình.
SIP là một giao thức báo hiệu được các hệ thống VoIP và hội nghị truyền hình sử dụng. Để cho phép giao tiếp giữa ứng dụng web WebRTC và ứng dụng SIP (chẳng hạn như hệ thống hội nghị truyền hình), WebRTC cần có một máy chủ proxy để làm trung gian cho việc truyền tín hiệu. Tín hiệu phải truyền qua cổng, nhưng sau khi thiết lập được kết nối, lưu lượng truy cập SRTP (video và âm thanh) có thể truyền trực tiếp giữa các thiết bị.
Mạng điện thoại chuyển mạch công cộng (PSTN) là mạng chuyển mạch kênh của tất cả điện thoại analog "kiểu cũ". Đối với các cuộc gọi giữa ứng dụng web WebRTC và điện thoại, lưu lượng truy cập phải đi qua cổng PSTN. Tương tự, các ứng dụng web WebRTC cần có một máy chủ XMPP trung gian để giao tiếp với các điểm cuối Jingle, chẳng hạn như ứng dụng nhắn tin tức thời. Jingle được Google phát triển dưới dạng một tiện ích cho XMPP để hỗ trợ thoại và video cho các dịch vụ nhắn tin. Các phương thức triển khai WebRTC hiện tại dựa trên thư viện libjingle C++, một phương thức triển khai Jingle ban đầu được phát triển cho Talk.
Một số ứng dụng, thư viện và nền tảng sử dụng khả năng giao tiếp của WebRTC với thế giới bên ngoài. Ví dụ:
- jsSIP: Thư viện SIP JavaScript
- Phono: API điện thoại JavaScript nguồn mở được xây dựng dưới dạng trình bổ trợ
- Twilio: thoại và nhắn tin
Tìm hiểu thêm
- Đọc tài liệu về API WebRTC.
- Lớp học lập trình WebRTC cung cấp hướng dẫn từng bước về cách tạo ứng dụng trò chuyện bằng video và văn bản bằng dịch vụ báo hiệu Socket.io chạy trên Node.
- Bài thuyết trình SFHTML5 của Chris Wilson: Giới thiệu về ứng dụng WebRTC
Cuốn sách 350 trang WebRTC: APIs and RTCWEB Protocols of the HTML5 Real-Time Web (WebRTC: API và giao thức RTCWEB của web theo thời gian thực HTML5) cung cấp nhiều thông tin chi tiết về dữ liệu và đường dẫn tín hiệu, đồng thời bao gồm một số sơ đồ cấu trúc liên kết mạng chi tiết.