1.3 一通通话的全景与状态机


文档摘要

1.3 一通通话的全景与状态机 本节摘要:别以为「视频通话」是一个动作——它是采集、协商、打洞、加密四段流程的接力,任何一段掉链子都表现为同一句用户抱怨「连不上」。本节把一次 1v1 通话拆成完整的建立流水线,并讲清 connectionState 与 iceConnectionState 两套状态机如何联动。它是第 2 到第 5 章的预告片,也是你日后看日志定位故障阶段的总索引。 目标清单 阅读完本节,你应当能够: 按顺序说出一次通话建立的完整步骤与每步的产物; 解释 offer 与 answer 各自回答了什么问题、为什么必须一先一后; 区分 candidate 交换与 SDP 交换这两条不同的时间线; 根据 connectionState 的取值判断通话建立进行到哪个阶段;

1.3 一通通话的全景与状态机

本节摘要:别以为「视频通话」是一个动作——它是采集、协商、打洞、加密四段流程的接力,任何一段掉链子都表现为同一句用户抱怨「连不上」。本节把一次 1v1 通话拆成完整的建立流水线,并讲清 connectionState 与 iceConnectionState 两套状态机如何联动。它是第 2 到第 5 章的预告片,也是你日后看日志定位故障阶段的总索引。

目标清单

阅读完本节,你应当能够:

  1. 按顺序说出一次通话建立的完整步骤与每步的产物;
  2. 解释 offer 与 answer 各自回答了什么问题、为什么必须一先一后;
  3. 区分 candidate 交换与 SDP 交换这两条不同的时间线;
  4. 根据 connectionState 的取值判断通话建立进行到哪个阶段;
  5. 遇到「黑屏但无报错」时,说出至少三个可能的故障阶段。

一、问题与直觉:一个按钮背后的接力赛

用户眼里,「发起视频通话」是一个按钮;工程师眼里,按钮按下之后是一场四棒接力。少了任何一棒,用户看到的现象都一样——黑屏。这就是为什么入门项目最常出现的排查困境是「没有报错,但画面不出来」:你盯着的那段代码没问题,问题在接力赛的前几棒。

把接力棒列出来。第一棒,采集:本端打开摄像头麦克风,拿到轨道。第二棒,协商:两端通过信令交换 SDP,谈好用什么编码、什么参数、谁发谁收。第三棒,接线:两端各自收集自己的网络地址(候选),互相试探哪条路能通。第四棒,开讲:协商出的加密密钥生效,DTLS 握手完成后,媒体数据开始流动。第二棒属于第 3 章,第三棒属于第 4 章,第四棒属于第 5 章——本节只需要你记住接力顺序和每棒的交接物。

二、核心原理:流水线与两套状态机

完整的建立流程画成时序是这样的:

两个容易误解的点要先掰正。其一,SDP 交换和候选交换是两条时间线。SDP 是「谈判纪要」,候选地址是「名片」,名片不需要等谈判结束才递——现代实现用 Trickle ICE,边收集边发,谁先到就用谁排队试探,不必等对端把所有地址收齐。其二,协商没有中心裁判。offer 与 answer 是对等的两个提议与确认,谁先发起谁掌握初始议程,但每一项参数都要对端点头才算数。

流程在代码里映照为两套状态机。RTCPeerConnection.connectionState 描述整条连接的宏观阶段:

iceConnectionState 是其中「打洞」那一棒自己的仪表盘,取值包括 new、checking、connected、completed、failed、disconnected。两套状态机的联动关系值得单独强调:ice 先走到 connected,connectionState 才可能变成 connected;ice 变 failed,connectionState 随之 failed。监听错误时盯 connectionState,定位细节时看 iceConnectionState——一个给你结论,一个给你线索。

用一段骨架代码把事件接起来:

const pc = new RTCPeerConnection(config); pc.onconnectionstatechange = () => { console.log('连接宏观状态:', pc.connectionState); if (pc.connectionState === 'failed') { // 通话彻底建立失败:提示用户检查网络或重启通话 } }; pc.oniceconnectionstatechange = () => { console.log('打洞子状态:', pc.iceConnectionState); }; pc.ontrack = (event) => { // 对端媒体到达:第四棒交接完成的信号 remoteVideo.srcObject = event.streams[0]; };

三、工程实践要点:按阶段归因故障

有了接力赛地图,「黑屏但无报错」就能按阶段归因。给出一张排查用的对照表:

现象组合 最可能的故障阶段 去哪一章
本端预览就黑屏 采集关:权限、设备占用、非安全上下文 第 2 章
本端正常,对端无事件到达 协商关:信令没通、SDP 没送达 第 3 章
有 offer/answer 但连接停在 checking 接线关:候选太少、防火墙拦 UDP 第 4 章
ice 变 failed 或一直 checking 接线关:缺 TURN 中继、对称 NAT 第 4 章
ice 已 connected 但画面黑 开讲关:解码能力协商错位、密钥问题 第 5 章
通了但几十秒后卡死花屏 质量关:丢包恢复与带宽估计失灵 第 6 章

实践里还有两个高频坑值得预记。坑一:忘设 iceServers。不加 STUN 服务器时只有本机地址可用,跨网段必然连不通,症状正是永远停在 checking。坑二:只在一端 addTrack。协商是双向的,A 端发了视频而 B 端一个轨道都不加,B 收不到画面是正常的——方向性由轨道决定,不是 bug。这两个坑在第 4、7 章还会以更完整的形态出现,先混个脸熟。

⚠️ 常见坑:把 connectionState === 'connected' 当作「可以发送数据」的信号是不精确的——数据通道要等它自己的 open 事件,媒体要等 ontrack。状态机到 connected 只说明「路通了」,不说明「货到了」。

本节要点回顾

  • 四棒接力:采集、协商、接线、开讲,用户看到的「连不上」可能出在任何一棒,排查必须按阶段归因。
  • 两条时间线:SDP 交换(谈判)与候选交换(递名片)并行推进,Trickle ICE 让名片随收随试。
  • 两套状态机:connectionState 给宏观结论,iceConnectionState 给打洞细节,前者监听失败、后者定位原因。
  • 事件即交接单:ontrack 表示对端媒体到达,数据通道的 open 表示通道可用,各信号各管各的。
  • 本章是索引:每一段流程都是后续章节的入口,遇到具体故障回到这张地图找对应的章。

作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U