Webcam (presque) inutile en streaming depuis un navigateur. Partie 2. WebRTC

D'une manière ou d'une autre dans одной à partir d'articles anciens et déjà abandonnés, j'ai écrit sur la facilité et la nature avec laquelle vous pouvez diffuser une vidéo à partir de Canvas via des websockets. Dans cet article, j'ai brièvement expliqué comment capturer la vidéo d'une caméra et le son d'un microphone à l'aide de API MediaStream, comment encoder le flux reçu et l'envoyer via des websockets au serveur. Cependant, en réalité, ils ne le font pas : pour les diffusions, ils utilisent soit un logiciel spécial qui doit être installé et configuré : cela peut être simple Ouvrez Logiciels Radio, soit ils utilisent WebRTC, qui fonctionne immédiatement, c'est-à-dire qu'il ne nécessite l'installation d'aucun plugin à la Flash Player, qui sera supprimé du navigateur Chromium dès décembre.

Aujourd'hui, nous allons parler de WebRTC.

La communication Web en temps réel (WebRTC) n'est pas un protocole unique, il s'agit d'un ensemble complet de normes, de protocoles et d'API JavaScript qui, ensemble, fournissent une communication vidéo-audio peer-to-peer en temps réel et peuvent également être utilisés pour transférer n'importe quel données binaires. Habituellement, les navigateurs agissent comme des pairs, mais il peut également s'agir d'une application mobile, par exemple. Afin d'organiser la communication p2p entre les clients, la prise en charge du navigateur pour différents types d'encodage vidéo et audio est requise, la prise en charge d'une variété de protocoles réseau, assurant l'interaction du matériel avec le navigateur (via les couches du système d'exploitation) : webcams, cartes son. Tout ce mélange de technologies est caché derrière l'abstraction de l'API JavaScript pour la commodité du développeur.

Tout se résume à trois API :

  • API MediaStream — démonté la dernière fois, aujourd'hui j'écrirai un peu plus sur lui. Sert à recevoir les flux vidéo/audio du matériel

  • Connexion RTCPeer — assure la communication entre deux clients (p2p)

  • Canal de données RTC - sert à transférer des données arbitraires entre deux clients

Préparation des flux audio et vidéo pour la transmission

Tout commence par la « capture » des flux multimédias de la webcam et du microphone. Bien entendu, les flux bruts ne sont pas adaptés à l'organisation d'une téléconférence, chaque flux doit être traité : améliorer la qualité, synchroniser l'audio avec la vidéo, placer des repères de synchronisation dans le flux vidéo, et assurer le débit correspondant à la bande passante en constante évolution du canal . Le navigateur s'occupe de tout cela, le développeur n'a même pas à se soucier de l'encodage des flux multimédias. Dans un navigateur moderne, il existe déjà des couches logicielles pour capturer, améliorer la qualité (supprimer l'écho et le bruit du son, améliorer l'image), l'encodage vidéo et audio. Le schéma des couches est illustré à la fig. 1:

Webcam (presque) inutile en streaming depuis un navigateur. Partie 2. WebRTCRiz. 1. Couches de traitement audio et vidéo dans le navigateur

Tous les traitements ont lieu directement dans le navigateur lui-même, sans aucun ajout. aucun plugin requis. Toutefois, les choses ne sont toujours pas si roses pour 2020. Il existe des navigateurs qui ne prennent pas encore entièrement en charge API MediaStream, vous pouvez suivre le lien et voir le tableau de compatibilité tout en bas. IE en particulier est encore une fois décevant.

Vous pouvez faire des choses très intéressantes avec les flux reçus : vous pouvez cloner, modifier la résolution vidéo, manipuler la qualité audio, vous pouvez prendre et « accrocher » le flux Media Stream à taguez et regardez-vous sur la page html. Ou vous pouvez dessiner un flux sur le canevas, définir WebGL ou CSS3, appliquer divers filtres à la vidéo, capturer la vidéo traitée à partir du canevas, puis l'envoyer sur le réseau au serveur, la transcoder et la publier à tout le monde (bonjour bigo live, Twitch et d'autres). Ici, je n'analyserai pas comment de telles choses se font, je donnerai quelques exemples trouvés sur le Web :

https://jeeliz.com/ - les gars font des CV en temps réel en Javascript. Ils ont un tout arsenal diverses bibliothèques js pour travailler avec un flux vidéo sur canevas : détection de visages, d'objets, application de filtres (masques, comme dans Instagram), etc. Un excellent exemple de la façon dont vous pouvez traiter une vidéo en temps réel directement dans le navigateur sans plugins supplémentaires.

API captureStream du canevas - Documentation API pour capturer un flux vidéo à partir de Canvas. Déjà pris en charge dans Chrome, Opera et Firefox

Connexion RTCPeer

Nous sommes donc arrivés au point, mais comment transférer réellement la vidéo à un autre utilisateur ? Vient au premier plan Connexion RTCPeer. En bref, presque à cette étape, vous devez créer un objet RTCPeerConnection :

const peerConnection = new RTCPeerConnection({
  iceServers: [{
    urls: 'stun:stun.l.google.com:19302'
  }]
});

Nous spécifions iceServers comme l'une des options - il s'agit d'un serveur qui permet de fournir une connexion entre deux navigateurs derrière NAT'om. C'est-à-dire que le problème est ici résolu : comment connaître l'ip de l'interlocuteur s'il se trouve derrière le NAT de son fournisseur ? Le protocole ICE vient à la rescousse, en fait, ICE ne s'applique pas du tout à WebRTC, mais nous y reviendrons plus tard.

Auparavant, nous obtenions les flux Usermedia :

navigator.mediaDevices.getUserMedia({ video: true, audio: true }).then(stream => {
  // Usermedia-потоки, обычно это видео и аудио 
  const tracks = stream.getTracks();

   for (const track of tracks) {
     // каждый трек присоединяем к peerConnection
     peerConnection.addTrack(track);
   }
}).catch(console.error);

Ensuite, l'événement onnegotiationneeded se déclenche sur le peerConnection, dans le gestionnaire duquel nous devons créer une offre (en termes de SDP - Session Description Protocol) et l'attribuer au peerConnection via la méthode setLocalDescription. À propos de SDP - de quoi il s'agit et des formats d'offre et de réponse - nous en parlerons plus loin.

Après avoir attribué une peerConnection LocalDescription, le navigateur « rassemble » les candidats ice, c'est-à-dire qu'il trouve différentes manières de communiquer via NAT. L’événement onicegatheringstatechange se déclenche. Dans le gestionnaire onicegatheringstatechange, nous autorisons une connexion au flux webrtc-signaling-server pour échanger la description de session entre pairs :

peerConnection.oniceconnectionstatechange = (event) => {
      console.log('Connection state: ', peerConnection.iceConnectionState);

      if (peerConnection.iceConnectionState === 'connected') {
        // Можем активировать кнопку Start broadcast
        setBroadcasting(true);
        setBroadcastingBtnActive(true);
      }
    };

// Событие срабатывает сразу, как только добавился медаиапоток в peerConnection
peerConnection.onnegotiationneeded = (event) => {
      // Создаем и назначаем SDP offer
      peerConnection.createOffer().
        then((offer) => peerConnection.setLocalDescription(offer)).
        catch(console.error);
    };

// Событие срабатывает каждый раз, как появляется ICE кандидат
peerConnection.onicegatheringstatechange = (ev) => {
      let connection = ev.target;

      // Now we can activate broadcast button
      if (connection.iceGatheringState === 'complete') {
        let delay = 50;
        let tries = 0;
        let maxTries = 3;

        let timerId = setTimeout(function allowStreaming() {
          if (isOnline) {
            setBroadcastingBtnActive(true);
            return;
          }

          if (tries < maxTries) {
            tries += 1;
            delay *= 2;
            timerId = setTimeout(allowStreaming, delay);
          } else {
            // TODO: show user notification
            console.error("Can't connect to server");

            alert("Can't connect to server");
          }
        }, delay);
      }
    };

Le webrtc-signaling-server est le serveur requis pour échanger la description de session entre deux pairs, il peut s'agir du websocket ou du serveur xhr le plus simple sur n'importe quel PL. Sa tâche est simple : accepter une description de session d'un homologue et la transférer à un autre.

Après l'échange des descriptions de session, les deux côtés sont prêts à diffuser et à recevoir des flux vidéo, du côté qui reçoit le flux vidéo, l'événement ontrack est déclenché sur la peerConnection, dans le gestionnaire duquel les pistes reçues peuvent être attribuées à et regardez votre interlocuteur préféré. Plus de théorie et de détails.

Liens et littérature :

https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection - Documentation Connexion RTCPeer

https://github.com/pion/webrtc - implémentation des protocoles WebRTC en cours

https://webrtcforthecurious.com/ - un livre des créateurs de pion

https://hpbn.co/ - Réservez un réseau de navigateur haute performance. Les problèmes liés à la garantie de hautes performances des applications Web sont discutés en détail. À la fin, WebRTC est décrit. Le livre est certes ancien (2013), mais ne perd pas pour autant de sa pertinence.

Dans la partie suivante, je souhaite donner un peu plus de théorie et analyser en pratique la réception et le traitement d'un flux vidéo sur le serveur à l'aide de pion, transcodage en HLS via ffmpeg pour diffusion ultérieure aux téléspectateurs dans le navigateur.

Pour les impatients : mon prototype très rudimentaire de diffusion de vidéo depuis une webcam pour réagir via un serveur basé sur pion dans Twitch (ce n'est qu'une expérience).

Source: habr.com

Ajouter un commentaire