Webrtc数据交互详情及Web端WebRTC示例

基本概念

https://www.psvmc.cn/article/2022-06-16-webrtc-start.html

交互详情

1
2
3
4
5
6
7
8
9
10
11
12
13
14
sequenceDiagram
participant A as 用户A
participant WS as WS
participant B as 用户B

A->>WS: 1. 创建offer并发送 sdp type:offer
WS->>B: 2. sdp type:offer
B->>WS: 3. sdp type:answer
WS->>A: 4. sdp type:answer
A->>WS: 1. 发送candidate
WS->>B: 2. 发送candidate
B->>WS: 3. 发送candidate
WS->>A: 4. 发送candidate
B->>A: 连接

交互的数据

1 创建offer并发送

1
{"type":"offer","sdp":"v=0\r\no=- 72532 0 IN IP4 127.0.0.1\r\ns=sipsorcery\r\nt=0 0\r\na=group:BUNDLE 0\r\nm=video 9 UDP/TLS/RTP/SAVP 96 100\r\nc=IN IP4 0.0.0.0\r\na=ice-ufrag:SEFW\r\na=ice-pwd:ZWIYQSXNKGKSEUCBULXIQQCQ\r\na=fingerprint:sha-256 7B:8E:55:E3:27:F2:B3:30:E9:2C:A0:87:E2:C9:1F:70:F6:A7:52:97:F6:F6:04:4B:F0:2A:04:87:FD:CA:9E:B7\r\na=setup:actpass\r\na=candidate:950637637 1 udp 2113937663 192.168.3.56 62710 typ host generation 0\r\na=ice-options:ice2,trickle\r\na=mid:0\r\na=rtpmap:96 VP8/90000\r\na=rtpmap:100 H264/90000\r\na=fmtp:100 packetization-mode=1\r\na=rtcp-mux\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=end-of-candidates\r\na=sendrecv\r\na=ssrc:1819341444 cname:6fef90ad-0e6b-4af4-9220-377c2faf01d8\r\n"}

2 响应

1
{"type":"answer","sdp":"v=0\r\no=- 8100819546663100148 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 0\r\na=msid-semantic: WMS 0eb90fdc-f221-409a-8cc2-10015551f1d1\r\nm=video 9 UDP/TLS/RTP/SAVP 96 100\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:Kz3X\r\na=ice-pwd:ci0C3HqUXi/oTbiOqzjxdNKF\r\na=ice-options:trickle\r\na=fingerprint:sha-256 4D:2B:B6:60:B9:F2:C5:9C:D9:7C:DC:7C:DA:E4:1A:A0:B6:79:D7:9D:66:9A:99:05:09:56:A4:43:FF:B3:48:E3\r\na=setup:active\r\na=mid:0\r\na=sendrecv\r\na=msid:0eb90fdc-f221-409a-8cc2-10015551f1d1 c32f714c-b627-4313-be6d-15fbbc7d8656\r\na=rtcp-mux\r\na=rtpmap:96 VP8/90000\r\na=rtpmap:100 H264/90000\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=ssrc:2948904417 cname:ufqrpgnhfhKdMI5c\r\na=ssrc:2948904417 msid:0eb90fdc-f221-409a-8cc2-10015551f1d1 c32f714c-b627-4313-be6d-15fbbc7d8656\r\n"}

3 并发送candidate

1
{"candidate":"candidate:388572998 1 udp 2113937151 bd043a02-be83-461c-84d3-6ab8d12290c5.local 62712 typ host generation 0 ufrag Z/Ju network-cost 999","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"Z/Ju"}

SDP数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
v=0
o=- 72532 0 IN IP4 127.0.0.1
s=sipsorcery
t=0 0
a=group:BUNDLE 0
m=video 9 UDP/TLS/RTP/SAVP 96 100
c=IN IP4 0.0.0.0
a=ice-ufrag:SEFW
a=ice-pwd:ZWIYQSXNKGKSEUCBULXIQQCQ
a=fingerprint:sha-256 7B:8E:55:E3:27:F2:B3:30:E9:2C:A0:87:E2:C9:1F:70:F6:A7:52:97:F6:F6:04:4B:F0:2A:04:87:FD:CA:9E:B7
a=setup:actpass
a=candidate:950637637 1 udp 2113937663 192.168.3.56 62710 typ host generation 0
a=ice-options:ice2,trickle
a=mid:0
a=rtpmap:96 VP8/90000
a=rtpmap:100 H264/90000
a=fmtp:100 packetization-mode=1
a=rtcp-mux
a=rtcp:9 IN IP4 0.0.0.0
a=end-of-candidates
a=sendrecv
a=ssrc:1819341444 cname:6fef90ad-0e6b-4af4-9220-377c2faf01d8

可以看出

在SDP阶段,双方交换了各种支持的编码和IP

回发

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
v=0
o=- 8100819546663100148 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE 0
a=msid-semantic: WMS 0eb90fdc-f221-409a-8cc2-10015551f1d1
m=video 9 UDP/TLS/RTP/SAVP 96 100
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:Kz3X
a=ice-pwd:ci0C3HqUXi/oTbiOqzjxdNKF
a=ice-options:trickle
a=fingerprint:sha-256 4D:2B:B6:60:B9:F2:C5:9C:D9:7C:DC:7C:DA:E4:1A:A0:B6:79:D7:9D:66:9A:99:05:09:56:A4:43:FF:B3:48:E3
a=setup:active
a=mid:0
a=sendrecv
a=msid:0eb90fdc-f221-409a-8cc2-10015551f1d1 c32f714c-b627-4313-be6d-15fbbc7d8656
a=rtcp-mux
a=rtpmap:96 VP8/90000
a=rtpmap:100 H264/90000
a=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
a=ssrc:2948904417 cname:ufqrpgnhfhKdMI5c
a=ssrc:2948904417 msid:0eb90fdc-f221-409a-8cc2-10015551f1d1 c32f714c-b627-4313-be6d-15fbbc7d8656

概念

在WebRTC(Web Real-Time Communication)中,SDP是“Session Description Protocol”的缩写。

SDP是一种描述多媒体会话的协议,主要用于定义和协商音视频会话的参数。

在WebRTC中,SDP用于交换会话的元数据,例如媒体格式、编解码器、传输协议和网络地址等。

具体来说,SDP用于:

  1. 描述会话:SDP包含了会话的所有必要信息,如视频和音频流的编解码器、分辨率、比特率等。
  2. 协商参数:通过SDP交换,WebRTC客户端可以协商使用哪些媒体格式和传输方式,以确保双方都能理解和处理对方发送的媒体流。
  3. 建立连接:SDP还用于建立和维护WebRTC连接,包括处理ICE(Interactive Connectivity Establishment)候选者和网络地址信息。

在实际应用中,SDP通常是在建立WebRTC连接时,通过信令服务器进行交换的。

信令服务器的作用是帮助客户端交换SDP信息,协商会话参数,从而成功建立P2P连接。

WebRTC中的candidate是一个包含网络地址信息的实体,它至少包括地址(IP)、端口(Port)、协议(Protocol)三元组,还可能包括Candidate类型、用户名(ufrag)、网络ID(network_id)、网络成本(network_cost)等其他信息。

Web端WebRTC示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<!DOCTYPE html>
<head>
<title>WebRTC</title>
</head>
<body>
<video controls autoplay="autoplay" id="videoCtl" width="640" height="480"></video>
<div>
<label for="websockurl">WS:</label><input type="text" id="websockurl" size="40" />
<button type="button" class="btn btn-success" onclick="start();">Start</button>
<button type="button" class="btn btn-success" onclick="closePeer();">Close</button>
</div>
</body>

<script type="text/javascript">
const WEBSOCKET_URL = "ws://127.0.0.1:8081/ws"
document.querySelector('#websockurl').value = WEBSOCKET_URL;
let pc, ws;

async function start () {
var ws_url = document.querySelector('#websockurl').value;
pc = new RTCPeerConnection();
let stream = await navigator
.mediaDevices
.getUserMedia({ video: true })
stream.getTracks().forEach(track => pc.addTrack(track, stream))
pc.ontrack = evt => document.querySelector('#videoCtl').srcObject = evt.streams[0];
pc.onicecandidate = evt => evt.candidate && ws.send(JSON.stringify(evt.candidate));
ws = new WebSocket(ws_url, []);
ws.onmessage = async function (evt) {
const obj = JSON.parse(evt.data);
if (obj?.sdp) {
await pc.setRemoteDescription(new RTCSessionDescription(obj));
if (pc.signalingState === 'have-remote-offer') {
let answer = await pc.createAnswer();
await pc.setLocalDescription(answer);
ws.send(JSON.stringify(pc.localDescription))
}
} else if (obj?.candidate) {
await pc.addIceCandidate(obj);
}
};
ws.onopen = async () => {
// 创建并发送 Offer
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
ws.send(JSON.stringify(offer))
};
}

async function closePeer () {
await pc?.close();
await ws?.close();
}

start();
</script>