一次握手只有六步:offer、setLocal、信令、setRemote、answer、setRemote。 顺序错了必失败,而且报错往往看不出是顺序问题。
7.7.5 讲了 API 组成,这一节讲最重要的那个的调用顺序。 下一章开始实战:用 Live555 搭一个能跑的平台。
一、六步的顺序
① createOffer:发起方生成 SDP 提议。
② setLocalDescription:把它设为本地描述。
③ 信令转发:把 SDP 送到对端。这一步不走 WebRTC。
④ setRemoteDescription:对端接收提议。
⑤ createAnswer:对端生成应答。
⑥ setRemoteDescription:发起方接收应答,开始 ICE。
注意第 ③ 步是唯一的「非 WebRTC」动作: SDP 得靠你自己的服务器传。 这是初学者最容易忽略的一步—— API 都调对了,但两端永远收不到对方的描述。
二、SDP 有多大
实测一份最小 SDP 只有 200 字节、10 行。 真实场景会把 ICE 候选、编解码参数、SSRC 全塞进去, 一份完整的 SDP 常有 3 到 8 KB。
为什么差这么多?因为 ICE 候选一行一条: 本机地址、局域网地址、公网地址、TURN 中继地址各一条, 再乘以音视频两路,很容易就几十行。
SDP 大不是问题,但要注意它的「时机」: ICE 候选是陆续产生的,不是一次给全。 所以要支持「增量交换」——每产生一个候选就发一条。
三、最容易出错的三处
① 顺序颠倒:没 setLocalDescription 就 createAnswer,必失败。
而且报错信息往往只说「状态不对」,看不出是顺序问题。
② 忘了信令:WebRTC 自己不会传 SDP,得靠你的服务器。
③ ICE 候选早到:对端还没 setRemoteDescription 就收到候选,
要缓存起来等,直接加会报错。
第 ③ 条最隐蔽: 因为候选产生得很快,常常比信令服务器转发 SDP 还快。 所以正确做法是「收到的候选先排队,等 setRemoteDescription 之后再逐个加」。
四、动手 Demo:重要 API——六步走完一次握手
先把六步的顺序列清楚,再量一份最小 SDP 有多大。 最后指出三处最容易出错的地方。
steps = [("createOffer", "发起方生成 SDP 提议"),
("setLocalDescription", "把提议设为本地描述"),
("信令转发", "把 SDP 送到对端(不走 WebRTC)"),
("setRemoteDescription", "对端接收提议"),
("createAnswer", "对端生成应答"),
("setRemoteDescription", "发起方接收应答")]
for i, (a, d) in enumerate(steps, 1):
print("%d. %-22s %s" % (i, a, d))
print()
sdp = ("v=0\r\n"
"o=- 1234567890 2 IN IP4 127.0.0.1\r\n"
"s=-\r\n"
"t=0 0\r\n"
"a=group:BUNDLE 0 1\r\n"
"m=audio 9 UDP/TLS/RTP/SAVPF 111\r\n"
"a=rtpmap:111 opus/48000/2\r\n"
"m=video 9 UDP/TLS/RTP/SAVPF 96\r\n"
"a=rtpmap:96 H264/90000\r\n"
"a=sendrecv\r\n")
print("最小 SDP %d 字节、%d 行" % (len(sdp.encode()), sdp.count("\r\n")))
实跑输出:
--------------------------------------------------------------------
重要 API——六步走完一次握手
--------------------------------------------------------------------
**① 六步的顺序**
步 API 做什么
------------------------------------------------------------------
1 createOffer 发起方生成 SDP 提议
2 setLocalDescription 把提议设为本地描述
3 信令转发 把 SDP 送到对端(不走 WebRTC)
4 setRemoteDescription 对端接收提议
5 createAnswer 对端生成应答
6 setRemoteDescription 发起方接收应答,开始 ICE
**② SDP 有多大**
**一份最小 SDP 有 200 字节、10 行。**
**真实场景会把 ICE 候选、编解码参数、SSRC 全塞进去,**
**一份完整的 SDP 常有 3 到 8 KB。**
**③ 最容易出错的三处**
**① 顺序颠倒**:**没 setLocalDescription 就 createAnswer,必失败。**
**② 忘了信令**:**WebRTC 自己不会传 SDP,得靠你的服务器。**
**③ ICE 候选早到**:**对端还没 setRemoteDescription 就收到候选,**
**要缓存起来等,直接加会报错。**
六步里只有第 3 步不走 WebRTC,这一步最容易被漏掉。
200 字节的 SDP 只有音视频各一路,加 ICE 候选就会涨到几 KB。
两个 setRemoteDescription 分别在不同端,这是最容易看混的地方。
30 秒实验
- 把第 3 步删掉,想想会发生什么——两端都生成了 SDP 但永远不交换,连接一直停在 connecting。
- 给 SDP 加 10 条
a=candidate行,看字节数——每条约 60 字节,这就是它涨到几 KB 的原因。 - 把
a=sendrecv改成a=recvonly,想想是什么场景——只收不发,观播模式就用它。
常见误区
- 「WebRTC 自带信令」——没有,信令协议由你自己定。
- 「SDP 一次就发全」——ICE 候选是陆续产生的。
- 「顺序错了会报明确的错」——报错很含糊,得自己推。
自测三问(点开对答案)
1. 一次握手的六步是什么? —— **offer、setLocal、信令、setRemote、answer、setRemote。** 2. 哪一步不走 WebRTC? —— **第 3 步信令转发**,SDP 必须靠你自己的服务器传。 3. ICE 候选早到怎么办? —— **先缓存,等 setRemoteDescription 之后再逐个添加。**- ☐ (本章完,下一节 8.1.1 Live555 实现本地视频推流)