WebRTC:Track.onOpen()触发但轨道未开启,libdatachannel视频轨道问题求助
问题分析与解决
核心问题总结
你遇到的轨道无法正常开启的问题,主要源于三个关键遗漏:
1. 媒体轨道方向设置错误
发送端创建的媒体描述使用了RecvOnly方向,这意味着该轨道被标记为仅接收视频,但你的需求是发送视频。方向不匹配会导致轨道协商逻辑完全错误。
2. 未完成SDP的带外交换
libdatachannel不会自动协商媒体轨道的SDP——哪怕DataChannel可以在部分场景下简化流程,但媒体轨道必须通过带外信令完成本地SDP发送给对端、对端设置远程SDP的完整流程。你仅在发送端调用了setLocalDescription(),但没有把生成的SDP传递给接收端,接收端也未设置远程SDP,轨道自然无法完成协商。
3. 缺失ICE候选交换
除了SDP,ICE候选也需要通过带外信令在两端交换,否则PeerConnection无法完成网络连通性检查,轨道无法进入可用状态。
具体修正步骤
发送端代码修正
- 修正轨道方向:将媒体描述方向改为
SendOnly(仅发送)或SendRecv(双向收发):
rtc::Description::Video media("myvideo", rtc::Description::Direction::SendOnly); media.addH264Codec(96); media.setBitrate(3000); auto track = peer_connection->addTrack(media);
- 发送本地SDP给接收端:调用
setLocalDescription()后,通过带外信令发送生成的SDP:
peer_connection->onLocalDescription([this](const rtc::Description& desc) { // 这里实现带外信令逻辑,将desc.sdp()和desc.type()发送给接收端 }); peer_connection->setLocalDescription();
- 发送ICE候选给接收端:监听本地候选生成事件,通过带外信令传递:
peer_connection->onLocalCandidate([this](const rtc::Candidate& cand) { // 这里实现带外信令逻辑,将cand.candidate()和cand.mid()发送给接收端 });
接收端代码修正
- 接收并设置远程SDP:通过带外信令收到发送端的SDP后,设置为远程描述:
// 假设通过带外信令获取到sdp字符串和描述类型(如Offer/Answer) rtc::Description remoteDesc(sdp, type); peer_connection->setRemoteDescription(remoteDesc);
- 接收并添加远程ICE候选:通过带外信令收到发送端的ICE候选后,添加到PeerConnection:
// 假设通过带外信令获取到候选字符串和mid rtc::Candidate remoteCand(candidate, mid); peer_connection->addRemoteCandidate(remoteCand);
- 补充本地SDP发送:接收端设置远程SDP后,会生成本地SDP,同样需要通过带外信令发送给发送端:
peer_connection->onLocalDescription([this](const rtc::Description& desc) { // 发送该SDP给发送端,发送端需要调用setRemoteDescription()接收 });
关于onTrack触发但轨道未开启的说明
onTrack回调触发仅表示PeerConnection收到了轨道的元数据(比如mid、编码信息),但这并不代表轨道已经完成了DTLS握手和ICE连通性检查。只有当SDP交换完成、ICE连通性确认后,轨道才会真正进入开启状态,此时isOpen()才会返回true,send()调用也不会报错。
内容的提问来源于stack exchange,提问作者JonasVautherin
相关产品推荐
相关产品推荐

