Skip to content

Messages ​

Cả hai server đều nói chuyện bằng text frame JSON trên một WebSocket bình thường ở /ws. Mỗi message là một object có trường type. Type nào không biết thì bị bỏ qua.

HTTP ​

RequestKết quảDùng cho
GET / trên signaling server{"name":"signaling-server","ok":true}Chấm trạng thái ở lobby, gọi mỗi 5 s
GET / trên SFU server{"name":"sfu-server","ok":true}Như trên, ở chế độ nhóm

Cuộc gọi 1:1 ​

Signaling server là server.js, port mặc định 4000. Nó ghép hai socket trong mỗi phòng và chuyển gần như mọi message, giữ nguyên nội dung, sang socket còn lại.

Client gửiClient bên kia nhậnMục đích
join {roomId}peer joined (peer đã ở trong phòng nhận)Người vào đầu tiên tạo phòng, người thứ hai bắt đầu cuộc gọi
offer {sdp}offer {sdp}SDP offer
answer {sdp}answer {sdp}SDP answer
candidate {candidate: {candidate, sdpMid, sdpMLineIndex}}giống hệtTrickle ICE
encryption key {key}giống hệt32 byte key material cho E2EE, dạng base64. Gửi trước offer.
encryption key receivedgiống hệtXác nhận đã nhận, chỉ để log
media state {state: {audio, video, screen}}giống hệtMicro và camera đang bật hay tắt, và có đang chia sẻ nội dung không
leavekhông có gìGiải phóng chỗ trong phòng. Đóng socket cũng có tác dụng như vậy.
Server gửiKhi nào
error {message, fatal}fatal: true thì kết thúc cuộc gọi: Room is full, Missing room id. You are already in this room thì không fatal.

Cứ 25 s server ping mọi socket một lần và ngắt socket nào không trả lời.

Cuộc gọi nhóm ​

SFU server là sfu-server, port mặc định 4001 cho cả TCP lẫn UDP. Server này không chuyển tiếp message: nó chính là đầu bên kia của cả hai peer connection.

Client → serverTrườngGhi chú
joinroomId, name, e2ee, e2eeKey (base64, khi có e2ee)Message đầu tiên. name là nhãn, ví dụ Web, Android, iOS.
offerpc: "publish", sdpMột lần, sau joined
answerpc: "subscribe", sdpTrả lời cho mọi offer subscribe
candidatepc, candidate: {candidate, sdpMid, sdpMLineIndex}Trickle ICE cho connection nào cũng được
media statestate: {audio, video, screen}Cùng ý nghĩa và cùng quy tắc 300 ms như cuộc gọi 1:1
chattext
leavekhông cóSau đó client đóng socket
Server → clientTrườngGhi chú
joinedparticipantId, participants: [{id, name, state}], e2ee, e2eeKeyparticipants liệt kê những người khác đã ở trong phòng. e2eeKey là key của phòng.
answerpc: "publish", sdp
offerpc: "subscribe", sdpLần đầu và mỗi lần renegotiate. Trả lời từng cái một.
participant joinedparticipant: {id, name, state}
participant leftparticipantIdXóa tile ngay
media stateparticipantId, state
chatparticipantId, name, text
errormessage, fatalLỗi fatal (Room is full, E2EE setting does not match the room) sẽ đóng socket

Server không trickle candidate của chính nó: các candidate đã nằm sẵn trong mọi SDP server gửi đi. Server ping mỗi 20 s. WebSocket đóng thì người tham gia bị xóa khỏi phòng, và không có cơ chế tiếp tục phiên cũ.

Track được chuyển tiếp ​

Giá trị
Stream ID (msid)participantId của người publish
Track ID<participantId>-audio hoặc <participantId>-video
CodecChỉ VP8 và Opus

Địa chỉ server ​

Mỗi client chấp nhận những gì ở lobby, trước khi tự thêm /ws:

Bạn nhậpSignaling server, mọi clientSFU trên Android, iOS, macOS, Windows
192.168.1.10http://192.168.1.10, port 80ws://192.168.1.10:4001
192.168.1.10:4000http://192.168.1.10:4000ws://192.168.1.10:4000
https://example.comhttps://example.comwss://example.com
ws://192.168.1.10:4001/wskhông chấp nhậnws://192.168.1.10:4001
Có path bất kỳBị bỏBị bỏ

Vậy nên với signaling server, và với SFU trên web, hãy ghi kèm port. Mặc định của web client là port 4000 (signaling) và 4001 (SFU) trên host đang phục vụ trang web.