2 votes

Reconnexion de plusieurs peerConnections après le rechargement de la page

Je suis en train de créer une application web pour la surveillance par des smartphones en utilisant WebRTC, et pour le serveur de signalisation j'utilise socket.io.

Lorsque j'envoie un flux, je crée un fichier RTCPeerConnection sur la page "watch" qui reçoit ce flux. Les flux sont envoyés sur des pages séparées. L'utilisateur peut joindre jusqu'à quatre flux à partir d'un smartphone, de sorte que la page "watch" peut contenir jusqu'à quatre flux. RTCPeerConnection objets.

Les flux sont reçus automatiquement dès que l'offre de la page "transmettre" apparaît. RTCPeerConnection est créé sur la page "watch" et connecté au schéma WebRTC standard.

page "transmettre" :

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

page "veille" :

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

Mon application web nécessite une fonctionnalité qui permette d'afficher tous les flux précédemment inclus lorsque l'on quitte la page "watch" et que l'on y revient.

Pour mettre en œuvre cette fonctionnalité, j'utilise la fonction oniceconnexionchangement d'état méthode. Si le flux est déconnecté, la méthode redémarrage de la glace est exécutée et crée l'offre avec l'option {iceRestart : true}

page "transmettre" :

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

Le problème est que lorsque je redémarre la page "watch", toutes les pages "transmit" envoient des demandes en même temps. Un seul objet est connecté, bien que quatre RTCPeerConnection sont créés en une seule fois (supposons que l'utilisateur envoie quatre flux).

Je suis confronté à ce problème depuis plusieurs jours. J'ai essayé de fixer un délai croissant pour les appels ultérieurs au getStream() comme indiqué dans le code ci-dessus, j'ai essayé de vérifier la fonction signallingState avant d'exécuter la commande getStream() J'ai essayé plusieurs autres méthodes, mais aucune n'a fonctionné.

Si vous avez besoin d'une partie de mon code pour vous aider, écrivez-nous.

éditer :

Méthode gotDescription() dans la page "watch".

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

J'ajoute console.log avec RTCPeerConnection object

sortie de la console : https://i.stack.imgur.com/dQXkE.png 1

montre que le signalingState de connexion est "stable" mais lorsque je développe l'objet, signalingState est égal à "have-remote-offer"

comme ici

1voto

jib Points 18592

Retirer le TempDescriptions et transmet le sdp à la variable globale getStream(offer.sdp) directement.

Sinon, vous avez socket.on('ask', function(offer){ appelé 4 fois, en écrasant TempDescriptions . Puis, 3+ secondes plus tard, votre 4 setTimeout se succèdent, tous accédant à la valeur finale de TempDescriptions seulement.

C'est probablement la raison pour laquelle une seule connexion RTCPeerConnection se reconnecte.

En général, l'utilisation d'un délai pour séparer les connexions semble être une mauvaise idée, car elle ralentit la reconnexion. Au lieu de cela, pourquoi ne pas envoyer un id ? Par exemple

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

Mise à jour : Ne plus ajouter de variables globales aux window

Chaque fois que vous affectez une variable non déclarée comme ceci :

connection = getPeerConnection();

...il crée un global sur window , par exemple window.connection et vous avez le même problème. Vous avez 4 connexions, mais vous les stockez dans une seule variable.

Tipo "use strict"; dans l'en-tête de votre fichier source :

ReferenceError: assignment to undeclared variable connection

Scoping (délimitation du champ d'application) : Le problème général

Vous avez affaire à 4 connexions ici, mais vous n'avez pas d'approche pour déterminer la portée de chaque instance.

La plupart des autres langages vous demanderaient de créer une classe et de créer des instances d'objets, et de mettre tout ce qui comprend des connection sur this . C'est une bonne approche. En JS, vous pouvez utiliser les fermetures à la place. Mais au minimum, vous avez toujours besoin de 4 variables contenant les 4 connexions, ou d'un tableau de connections . Ensuite, vous regardez vers le haut - par exemple depuis le id J'ai mentionné la connexion à traiter.

En outre, votre try / catch es ne vont pas attraper les erreurs asynchrones. Au lieu de définir tous ces rappels, je recommande fortement utiliser des promesses ou même async/await lorsqu'il s'agit de l'API WebRTC hautement asynchrone. Cela rend le cadrage trivial. Par exemple

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

De cette manière, la gestion des erreurs est solide.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X