页面重新加载后连接多个对等连接

Reconnecting serveral peerConnections after page reload

我正在创建一个 Web 应用程序,用于使用 WebRTC 的智能手机进行监控,以及我正在使用的信令服务器 socket.io。

当我发送一个流时,我在 "watch" 页面上创建了一个 RTCPeerConnection 对象来接收这个流。我在不同的页面上发送流。用户最多可以从智能手机附加四个流,因此在 "watch" 页面上最多有四个 RTCPeerConnection 对象。

一旦来自 "transmit" 页面的报价出现,就会自动接收流,然后 RTCPeerConnection 对象在 "watch" 页面上创建并连接到标准的 WebRTC 模式。

"transmit" 页数:

  function onCreateOfferSuccess(sdp){
  //console.log(sdp);
  pc.setLocalDescription(new RTCSessionDescription(sdp));
  console.log('ask');
  socket.emit('ask', {"sdp":JSON.stringify(pc.localDescription),
                      "user": loggedUserID,
                      "fromSocket": ownSocket});
}

"watch" 页数:

socket.on('ask', function(offer){
   if (offer.user === loggedUserID){
      TempDescriptions = JSON.parse(offer.sdp);
      console.log(TempDescriptions)
      currTransmiterSocket = offer.fromSocket;
      console.log(currTransmiterSocket);
      getStream();
}

function getStream(){
   try {
       setTimeout(function(){
           console.log(time, 'getStream()');
           connection = getPeerConnection();

           connection.setRemoteDescription(
           new RTCSessionDescription(TempDescriptions),
           function() {
               connection.createAnswer(gotDescription, function(error){
           console.log(error)
           });
           }, function(error){
               console.log(error)
           });
       }, getStreamDelay*3000)
       getStreamDelay++
   }

   catch(err){
       console.log(err);
   }
};

我的 Web 应用程序需要这样的功能,当我们退出 "watch" 页面并再次 return 时,必须显示所有先前包含的流。

为了实现这个功能,我使用了 oniceconnectionstatechange 方法。如果流断开连接,将执行 iceRestart 函数,该函数创建带有选项 {iceRestart: true}

的报价

"transmit" 页数:

var options_with_restart = {offerToReceiveAudio: false,
                            offerToReceiveVideo: true,
                            iceRestart: true};

function iceRestart(event){  
  try{
      setTimeout(function(){
       pc.createOffer(options_with_restart).then(onCreateOfferSuccess, onCreateOfferError);
      },1000);
  } catch(error) {
      console.log(error);

问题是当我重新启动 "watch" 页面时,所有页面 "transmit" 立即发送询问。尽管一次创建了四个 RTCPeerConnection 对象(假设用户发送了四个流),但只有一个对象已连接。

几天来我一直在为这个问题苦苦挣扎。我试图在后续调用 getStream() 函数时设置增加的时间延迟,如上面的代码所示,我试图在执行 [= 之前​​检查 signallingState 连接55=]getStream() 函数,我尝试了其他几种方法,但其中 none 有效。

如果您需要我的部分代码来帮助您,请写信。

编辑:

"watch" 页中的 gotDescription() 方法。

function gotDescription(sdp) {
   try{
       connection.setLocalDescription(sdp,
       function() {
       registerIceCandidate();
       socket.emit('response', {"sdp": sdp,
                                "user": loggedUserID,
                                "fromSocket": ownSocket,
                                "toSocket": currTransmiterSocket});
        }, function(error){
               console.log(error)
           });
   } catch(err){
       console.log(err);
   }
}

我用RTCPeerConnection object

加上console.log

控制台输出: https://i.stack.imgur.com/dQXkE.png1

log显示connection的signalingState是"stable"但是我开发对象的时候signalingState等于"have-remote-offer"

like here

去掉TempDescriptions全局变量,直接将sdp传给getStream(offer.sdp)

否则,您已经 socket.on('ask', function(offer){ 调用了 4 次,覆盖了 TempDescriptions。然后 3 秒后,您的 4 setTimeout 滚动,所有访问的最终值仅 TempDescriptions

这可能就是为什么只有一个 RTCPeerConnection 重新连接的原因。

一般来说,使用时间延迟来分离连接似乎是个坏主意,因为它会减慢重新连接的速度。相反,为什么不发送 id?例如

socket.emit('ask', {id: connectionNumber++,
                    sdp: JSON.stringify(pc.localDescription),
                    user: loggedUserID,
                    fromSocket: ownSocket});

更新:停止向 window

添加全局变量

每当您像这样分配给未声明的变量时:

connection = getPeerConnection();

...它在 window 上创建一个全局,例如window.connection,和你有同样的问题。您有 4 个连接,但您将它们存储在一个变量中。

在源文件的开头键入 "use strict"; 以捕获此内容:

ReferenceError: assignment to undeclared variable connection

范围界定:一般问题

您在这里处理 4 个连接,但您缺少确定每个实例范围的方法。

大多数其他语言会告诉您创建一个 class 并创建对象实例,然后将包括 connection 在内的所有内容放在 this 上。这是一个好方法。在 JS 中,您可以改用闭包。但至少你仍然需要 4 个变量来保存 4 个连接,或者一个 connections 的数组。然后你抬头——例如来自 id 我提到的——要处理的连接。

此外,您的 try/catches 不会捕获异步错误。在处理高度异步的 WebRTC API 时,我强烈建议 using promises, or even async/await 而不是定义所有这些回调。这使得范围界定变得微不足道。例如

const connections = [];

socket.on('ask', async ({user, id, sdp, fromSocket}) => {
  try {
    if (user != loggedUserID) return;
    if (!connections[id]) {
      connections[id] = getPeerConnection();
      registerIceCandidate(connections[id]);
    }
    const connection = connections[id];
    await connection.setRemoteDescription(JSON.parse(sdp));
    await connection.setLocalDescription(await connection.createAnswer());
    socket.emit('response', {sdp,
                             user: loggedUserID,
                             fromSocket: ownSocket,
                             toSocket: fromSocket});
  } catch (err) {
    console.log(err);
  }
};

这种错误处理方式很可靠。