上街三屏网站建设,网站快速盈利,Wordpress 换ip,网站改备案信息本篇承接 addTrack + CreateOffer 分析,聚焦接收方视角:远端 Offer 到达后,libwebrtc 如何从 SDP 里解析出对端的媒体流信息,以及为接收这些流做了哪些内部准备。 微信公众号: WebRTC 工程技术 一、问题的起点 发送方的 SDP Offer 里携带了这些关键信息: m=video 9 UD…本篇承接 addTrack + CreateOffer 分析,聚焦接收方视角:远端 Offer 到达后,libwebrtc 如何从 SDP 里解析出对端的媒体流信息,以及为接收这些流做了哪些内部准备。微信公众号: WebRTC 工程技术一、问题的起点发送方的 SDP Offer 里携带了这些关键信息:m=video 9 UDP/TLS/RTP/SAVPF 96 97 ... a=mid:video a=sendrecv a=msid:stream-1 track-1 ← 对端的 stream_id + track_id a=ssrc:1234567890 cname:xxxx ← 对端发送流的 SSRC a=ssrc:1234567890 msid:stream-1 track-1 a=ssrc:9876543210 cname:xxxx ← RTX SSRC a=rtpmap:96 VP8/90000 a=rtpmap:97 rtx/90000 a=fmtp:97 apt=96 a=ice-ufrag:xxxx a=fingerprint:sha-256 AA:BB:...接收方调用SetRemoteDescription(offer)后,这些信息需要被解析并落地到内部数据结构,最终让接收 pipeline 就绪。二、整体处理流程SetRemoteDescription(offer) └─► DoSetRemoteDescription() ├─ FillInMissingRemoteMids() // 兼容无 a=mid 的旧端 ├─ ValidateSessionDescription() // 合法性校验 └─► ApplyRemoteDescription() ├─ [1] 更新 description 槽位 ├─ [2] PushdownTransportDescription() // ICE/DTLS 参数下推 ├─ [3] UpdateTransceiversAndDataChannels() │ └─► AssociateTransceiver() // Transceiver 关联 │ └─► UpdateTransceiverChannel() // 创建 VoiceChannel/VideoChannel ├─ [4] UpdateSessionState() ├─ [5] UseCandidatesInSessionDescription() └─ [6] 遍历 Transceiver 处理流信息 ├─ SetAssociatedRemoteStreams() // 解析 msid → MediaStream ├─ SetupMediaChannel(ssrc) // 绑定 SSRC 到接收链路 │ └─► RestartMediaChannel() │ ├─ audio: source_-Start(media_channel_, ssrc_) │ └─ video: media_channel_-SetSink(ssrc_, sink) └─ 触发 OnTrack / OnAddTrack 回调三、SDP 解析:从文本到内部结构SDP 文本进入 libwebrtc 后,由SdpDeserialize解析为JsepSessionDescription,其中每个 m= section 对应一个ContentInfo,包含:structContentInfo{std::string name;// a=mid 的值,如 "video"boolrejected;// m= port=0 时为 trueMediaContentDescription*description;};// description 里包含structMediaContentDescription{std::vectorCodeccodecs_;// a=rtpmap 解析结果std::vectorStreamParamsstreams_;// a=ssrc / a=msid 解析结果RtpHeaderExtensions rtp_header_extensions_;// a=extmapTransportDescription transport_desc;// ICE/DTLS};// StreamParams 对应一条发送流structStreamParams{std::string id;// track_id(来自 a=msid 第二个值)std::vectorstd::stringstream_ids;// stream_id(a=msid 第一个值)std::vectoruint32_tssrcs;// a=ssrc 行的 SSRC 值std::vectorSsrcGroupssrc_groups;// a=ssrc-group:FID 等std::string cname;// a=ssrc ... cname:xxx};关键:a=ssrc+a=msid两行合在一起,完成了 SSRC → stream_id/track_id 的映射关系建立。四、第三步详解:AssociateTransceiver —— Transceiver 与 m= section 绑定// 遍历 Offer 的每个 m= sectionfor(size_t i=0;inew_contents.size();++i){autotransceiver_or_error=AssociateTransceiver(CS_REMOTE,SdpType::kOffer,i,new_content,old_local_content,old_remote_content);UpdateTransceiverChannel(transceiver,new_content,bundle_group);}4.1 Transceiver 匹配三级优先级// CS_REMOTE 时的匹配逻辑// 优先级 1:按 MID 精确匹配(重协商时)transceiver=transceivers()-FindByMid(content.name);// 优先级 2:找空闲同类型 Transceiver(本端预先 addTransceiver 了)if(!transceiverRtpTransceiverDirectionHasRecv(media_desc-direction())!media_desc-HasSimulcast()){transceiver=FindAvailableTransceiverToReceive(media_desc-type());}// 优先级 3:全都找不到 → 新建 recvonly Transceiverif