如何尽快检测网络断开(在 RTCPeerConnection 上)或由此产生的冻结视频?

How to detect network disconnects (on an RTCPeerConnection) as soon as possible or the resulting frozen video?

我正在使用 RTCPeerconnections 在基于 web-RTC 的视频信使中提交视频和音频。我能够在大约 7 秒后检测到网络断开连接 - 然而,这是用户盯着冻结视频并开始随机单击应用程序中的按钮的 7 秒。我想通过缩短这个时间跨度来改善用户体验 - 例如如果视频冻结超过 1 秒,则通知用户网络问题。

现状:我目前正在通过侦听RTCPeerConnectiononconnectionstatechange事件来检测各自的情况。然而,该事件仅在断开连接后大约 7 秒触发。我通过普通 WiFi 连接两台机器来确定大约 7 秒,使用其中一台笔记本电脑上的硬件开关关闭无线(此类开关存在于某些较旧的联想型号/保证立即断开连接)并等待另一台机器检测事件。

考虑:根本原因是底层网络连接中断,最好尽早检测到变化的网络状态(即使只是传输延迟)。话虽如此,用户面临的困扰最终还是源于网络中断时视频瞬间卡顿。如果没有办法更早地检测到连接问题,则可以选择检测冻结的视频。这两件事中的任何一件都可能吗(理想情况下是事件驱动的,这样我就不需要每秒轮询一次)?

这是一个非常简单的代码片段,描述了我当前的断开连接检测:

myRTCPeerConnection.onconnectionstatechange = (event: Event) => {
   let newCS = myRTCPeerConnection.connectionState;
   if (newCS == "disconnected" || newCS == "failed" || newCS == "closed") {
      //do something on disconnect - e.g. show messages to user and start reconnect
   }
}

(ice)connectionstatechange 通常是正确的事件。

如果您想要更详细的信息,您需要轮询 getStats 并查找 framesReceived 之类的统计信息。但是没有保证从另一端发送的帧速率(例如,在屏幕共享中你低于 1/s)。

虽然像 requestsSent 这样的实际 ICE 统计数据似乎更有用,但它们发生的频率要低得多,每秒仅一次,您可能会丢失数据包或延迟。

总的来说,这是一个网络故障检测可靠性的问题。如果它过于激进,你最终会得到糟糕的用户体验,并经常显示警告。 与以引入需要维护的复杂性为代价相比,您最终可能不会好得多。

感谢 Philipp 的见解 - 这为我指明了正确的方向。

我现在正在考虑使用 getStats 来识别任何冻结。乍一看,轮询 framesPerSecond 值对我来说似乎最有希望。好处:它在断开连接时立即做出反应 - 并且 - 当基础视频流暂停时它仍然有效(我允许用户暂停视频提交/通过将所有视频轨道设置为启用 = false 来实现它)。 IE。即使在发送方禁用了视频轨道,接收方仍会继续每秒接收约定的帧数。

由于 getStats 函数的用法在撰写本文时在文档中显得很薄弱/很少有简单的用法示例,请在下面找到我的代码摘录:

        peerRTCPC
          .getReceivers()
          .forEach(
            (
              receiver: RTCRtpReceiver,
              index: number,
              array: RTCRtpReceiver[]
            ) => {
              if (receiver.track.kind == "video") {
                receiver.getStats().then((myStatsReport: RTCStatsReport) => {
                  myStatsReport.forEach(
                    (statValue: any, key: string, parent: RTCStatsReport) => {
                      if (statValue.type == "inbound-rtp") {
                        console.log(
                          "The PC stats returned the framesPerSecond value " +
                          statValue["framesPerSecond"] +
                          " while the full inbound-rtp stats reflect as " +  
                          JSON.stringify(statValue)
                        );
                      }
                    }
                  );
                });
              }
            }
          );

请注意,断开连接后,framesPerSecond 不一定会变为零,即使 webRTCInternals 屏幕提示相同。当断开连接发生时,我看到 undefined

可能需要更仔细地研究以高频率/跨更多连接进行轮询的运行时影响。然而,这似乎是朝着正确方向迈出的良好一步,除非经常这样做。