移除SDP中a=ssrc行后,Chrome WebRTC单流音视频能否正常工作?
核心结论
目前Chrome的WebRTC实现已经不支持移除或修改SDP中的a=ssrc及关联属性(如a=msid、a=mid)来完成单流音视频传输。这些属性现在是WebRTC协商中关联媒体轨道、标识RTP流的核心依赖,移除或篡改后,浏览器无法正确映射媒体源,导致传输失败。
为什么早期版本可行现在不行?
你提到M29版本左右可以实现,这是因为早期WebRTC的SDP协商逻辑相对简单,对SSRC的依赖没有那么强。但随着WebRTC支持多流传输、轨道动态增减、带宽精细化管理等功能,a=ssrc、a=msid、a=mid这些属性成为了SDP中必不可少的部分——它们负责把本地媒体轨道和远端的RTP流做唯一绑定,没有这些信息,浏览器无法识别接收到的媒体数据属于哪个流/轨道。
针对你的SIP PBX场景的可行方案
既然你的SIP PBX会过滤a=ssrc行,直接移除/修改这些属性的思路走不通,建议换一种方式:在WebRTC端接收经过PBX过滤的SDP后,手动补全必要的a=ssrc及关联属性,而不是在Offer/Answer阶段主动修改这些行。
结合你提供的仓库代码,修改public/client.js中的modifySdp函数,不要把这些属性重命名为x开头的无效字段,而是检查并补全缺失的SSRC相关信息:
function modifySdp(sdp) { const lines = sdp.split('\n'); let hasSsrc = false; let midValue = ''; let mediaSection = ''; // 遍历SDP行,检查是否已有SSRC行,同时获取mid值和媒体段信息 for (const line of lines) { if (line.startsWith('a=ssrc:')) { hasSsrc = true; } else if (line.startsWith('a=mid:')) { midValue = line.split(':')[1]; } else if (line.startsWith('m=audio') || line.startsWith('m=video')) { mediaSection = line; } } // 如果没有SSRC行,且是单流音频场景,补全必要的SSRC属性 if (!hasSsrc && midValue && mediaSection.startsWith('m=audio')) { // 建议使用本地音频轨道的真实SSRC,示例用随机值演示 const ssrc = Math.floor(Math.random() * 0xFFFFFF); // 本地轨道的msid,可通过getUserMedia获取的stream.tracks[0].id来生成 const trackId = 'audio_track_0'; const msid = `audio_stream ${trackId}`; // 补全SSRC关联的msid和cname(cname用于同步音频视频) sdp += `\na=ssrc:${ssrc} msid:${msid}`; sdp += `\na=ssrc:${ssrc} cname:${trackId}`; } return sdp; }
注意:实际应用中,你应该获取getUserMedia返回的音频轨道的真实SSRC(可以通过RTCRtpSender.getParameters()获取),而不是随机生成,这样才能确保远端和本地的媒体流正确映射。
官方规范与限制说明
在最新的WebRTC 1.0官方规范中,明确指出SSRC是标识RTP媒体流的唯一标识符,msid用于关联SSRC和浏览器中的媒体轨道。Chromium的Issue 1941中的评论属于早期实现阶段的讨论,随着WebRTC功能的演进,现在的实现已经强制依赖这些属性,移除后会导致协商失败。
额外提示
如果你的场景只需要单流音频,还可以尝试在创建Offer时,明确只添加音频轨道,避免视频轨道的干扰,这样SDP中只会包含音频相关的媒体段,减少PBX过滤带来的问题。比如:
const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); const pc = new RTCPeerConnection(); stream.getTracks().forEach(track => pc.addTrack(track, stream));
内容的提问来源于stack exchange,提问作者Tev

