我创建了一个视频通话+多屏幕共享应用程序,除了一种情况外,它在所有情况下都运行良好。
主要流程是:
网络摄像头流程始终运行良好,但屏幕共享在特定情况下会中断:
Failed to execute 'setLocalDescription' on 'RTCPeerConnection': Failed to parse SessionDescription. a=rtpmap:127 H264/90000 Duplicate payload type with conflicting codec name or clock rate
查看报价的 SDP,我发现
a=rtpmap:127
行的有效负载是重复的:
a=rtpmap:127 H264/90000
...
a=rtpmap:127 rtx/90000
此错误仅发生在指定的流程中(Chrome 首先发送报价,Firefox 回答(并且相机运行良好),Firefox 共享屏幕,我收到 SDP 错误)。如果第一个报价是由 Firefox 用户发送的,那么一切都会顺利进行。如果第一个报价是由 Chrome 发送的,并且由 Chrome 用户启动第一个屏幕共享,一切都会正常进行。
如果第一个报价是由 Chrome 用户发送的,然后 Firefox 用户共享屏幕,则会中断。仅在这种情况下。
因此,问题在于 Firefox 用户在第一个屏幕共享期间创建的优惠包含有效负载冲突。
为什么会发生这种情况(仅在这种情况下)以及如何防止此错误?
我也遇到了这个bug,除了自己修改SDP描述之外没有找到解决方案。 虽然这是一个粗略的解决方法,但它修复了编解码器冲突错误。
您想要从视频轨道中删除重复的编解码器编号(此处为 127):
m=视频 9 UDP/TLS/RTP/SAVPF 100 101 127 127 ...
然后删除RTX编解码器的有效负载。
a=rtpmap:127 RTX/90000
...
请记住RTX 用于重新发送损坏的包
RTX代表重传。 RTX
RTP重传是一种有效的丢包恢复技术 具有宽松延迟范围的实时应用程序rfc4588
因此,将其从有效负载中删除可能会导致此功能失效。
这是我的 JS(打字稿)函数
removeDuplicateCodecs(sdp: string): string {
// split sdp for each video track
const lines = sdp.split(/^(?=m=video)/gm);
for (let i = 0, videosLength = lines.length; i < videosLength; i++) {
if (lines[i].startsWith("m=video")) {
// split each line
let rows = lines[i].split(/\r\n/gm);
const codecDuplicated: string[]= [];
if (rows.length) {
// take first row and get all codecs
const duplicates = rows[0].match(/(\b\d+\b)(?=.*\b\1\b)/g);
if (duplicates?.length) {
duplicates.forEach(duplicate => {
// remove duplicates from row
rows[0] = rows[0].replace(` ${duplicate}`, '')
codecDuplicated.push(duplicate);
});
}
}
// join back all rows
lines[i] = rows.join('\r\n');
// split by rtpmap
rows = lines[i].split(/^(?=a=rtpmap:)/gm);
if (rows) {
codecDuplicated.forEach(duplicate => {
// remove duplicate codec definitions rows
rows = rows.filter(row => !row.startsWith(`a=rtpmap:${duplicate} rtx`));
});
lines[i] = rows.join('');
}
}
}
return lines.join('');
}