WebRTC - Firefox <> Chrome 上的多轨流问题

问题描述 投票:0回答:1

我创建了一个视频通话+多屏幕共享应用程序,除了一种情况外,它在所有情况下都运行良好。

主要流程是:

  • 用户(P1)加入一个空房间,没有任何反应
  • 第二个用户 (P2) 加入房间。 P1 向 P2 发送报价,P2 向 P1 发送响应。
  • 其他用户(PN)加入房间。房间中的每个用户都会向 PN 用户发送报价。 PN 用户发送每个报价的答案。
  • 在主应用程序流程中,每个用户都可以共享他们的屏幕(多次)。发生这种情况时,用户向每个已连接的对等方发送报价并从他们那里接收答案。

网络摄像头流程始终运行良好,但屏幕共享在特定情况下会中断:

  • P1 是加入房间的 Chrome 用户。什么也没发生。
  • P2 是加入 Room 的 Firefox 用户。 P1 (Chrome) 将其报价发送到 P2 网络摄像头连接工作正常。
  • P2 (Firefox) 共享屏幕。报价抛出错误:
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 用户在第一个屏幕共享期间创建的优惠包含有效负载冲突。

为什么会发生这种情况(仅在这种情况下)以及如何防止此错误?

webrtc video-streaming streaming simplewebrtc
1个回答
0
投票

我也遇到了这个bug,除了自己修改SDP描述之外没有找到解决方案。 虽然这是一个粗略的解决方法,但它修复了编解码器冲突错误。

  1. 您想要从视频轨道中删除重复的编解码器编号(此处为 127):

    m=视频 9 UDP/TLS/RTP/SAVPF 100 101 127 127 ...

  2. 然后删除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('');
}
© www.soinside.com 2019 - 2024. All rights reserved.