Переподключение нескольких peerConnections после перезагрузки страницы - PullRequest
0 голосов
/ 10 февраля 2019

Я создаю веб-приложение для мониторинга с помощью смартфонов с помощью WebRTC, а для сервера сигнализации я использую socket.io.

Когда я отправляю поток, я создаю RTCPeerConnection объект на странице наблюдения, которая получает этот поток.Потоки отправляю на отдельных страницах.Пользователь может присоединить до четырех потоков со смартфона, поэтому на странице «Просмотр» имеется до четырех RTCPeerConnection объектов.

Потоки принимаются автоматически, как только предложение отПоявляется страница «Передача», затем на странице «Наблюдение» создается объект RTCPeerConnection , который подключается к стандартной схеме WebRTC.

Страница «Передача»:

  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});
}

страница "просмотра":

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);
   }
};

Моему веб-приложению требуется функциональность, при которой при выходе из страницы "наблюдения" и возвращении к ней должны отображаться все ранее включенные потоки.

Для реализации этой функции я использую метод oniceconnectionstatechange .Если поток отключен, выполняется функция iceRestart , которая создает предложение с опцией {iceRestart: true}

страница "передачи":

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);

Проблема в том, что когда я перезагружаю страницу просмотра, все страницы сразу передают запрос.Подключен только один объект, хотя четыре объекта RTCPeerConnection создаются одновременно (предположим, что пользователь отправляет четыре потока).

Я боролся с этой проблемой в течение нескольких дней.Я пытался установить увеличивающуюся задержку при последующих вызовах функции getStream () , как видно из приведенного выше кода, я пытался проверить соединения signallingState перед выполнением getStream () функция, я пробовал несколько других методов, но ни один из них не работал.

Если вам нужна какая-то часть моего кода, пожалуйста, напишите.

edit:

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);
   }
}

Я добавляю console.log с RTCPeerConnection object

консольным выводом: https://i.stack.imgur.com/dQXkE.png 1

показывает, что signalingState соединения" стабильно ", но когда я разрабатываю объект, signalingState равно" have-remote-offer "

как здесь

1 Ответ

0 голосов
/ 10 февраля 2019

Удалите глобальную переменную 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

Scoping: общая проблема

Здесь вы имеете дело с 4-мя соединениями, но у вас нет подхода к определению области действия каждого экземпляра.

Большинство других языков говорят, что вы должны создать класс и создать экземпляры объекта и поместить все, включаяconnection на this.Это один хороший подход.В JS вместо этого вы можете использовать замыкания.Но как минимум вам все еще нужно 4 переменные, содержащие 4 соединения, или массив connections.Затем вы ищите, например, из id, о котором я говорил, с каким соединением иметь дело.

Кроме того, ваши try / catch не собираются отлавливать асинхронные ошибки.Вместо определения всех этих обратных вызовов я настоятельно рекомендую использовать обещания или даже async / await при работе с сильно асинхронным API WebRTC.Это делает область видимости тривиальной.Например,

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);
  }
};

. Таким образом, обработка ошибок является надежной.

...