(Fast) nutzloses Webcam-Streaming über einen Browser. Teil 2. WebRTC

Irgendwie drin одной Aus alten und bereits aufgegebenen Artikeln habe ich darüber geschrieben, wie einfach und natürlich Sie Videos von Canvas über WebSockets übertragen können. In diesem Artikel habe ich kurz darüber gesprochen, wie man mit einer Kamera Videos und Ton von einem Mikrofon aufnimmt MediaStream-API, wie man den empfangenen Stream kodiert und über Websockets an den Server sendet. In Wirklichkeit tun sie dies jedoch nicht, denn für Übertragungen verwenden sie entweder spezielle Software, die installiert und konfiguriert werden muss: Das kann ohne weiteres der Fall sein Offene Broadcast-Software, oder sie verwenden WebRTC, das sofort funktioniert, das heißt, es erfordert keine Installation von Plugins a la Flash Player, der bereits im Dezember aus dem Chromium-Browser entfernt wird.

Heute werden wir über WebRTC sprechen.

Web Real-Time Communication (WebRTC) ist kein einzelnes Protokoll, sondern eine ganze Sammlung von Standards, Protokollen und JavaScript-APIs, die zusammen eine Peer-to-Peer-Echtzeit-Video-Audio-Kommunikation ermöglichen und auch zur Übertragung beliebiger Protokolle verwendet werden können Binärdaten. Normalerweise fungieren Browser als Peers, es kann sich aber beispielsweise auch um eine mobile Anwendung handeln. Um die P2P-Kommunikation zwischen Clients zu organisieren, ist Browserunterstützung für verschiedene Arten der Video- und Audiokodierung erforderlich, Unterstützung für eine Vielzahl von Netzwerkprotokollen, Sicherstellung der Interaktion von Hardware mit dem Browser (über Betriebssystemschichten): Webcams, Soundkarten. Dieses ganze Sammelsurium an Technologien verbirgt sich zur Vereinfachung für den Entwickler hinter der JavaScript-API-Abstraktion.

Alles läuft auf drei APIs hinaus:

  • MediaStream-API — letztes Mal abgebaut, heute schreibe ich etwas mehr über ihn. Dient zum Empfang von Video-/Audiostreams von der Hardware

  • RTCPeerConnection — ermöglicht die Kommunikation zwischen zwei Clients (p2p)

  • RTCDataChannel - dient der Übertragung beliebiger Daten zwischen zwei Clients

Vorbereiten von Audio- und Videostreams für die Übertragung

Alles beginnt mit der „Erfassung“ der Webcam- und Mikrofon-Medienströme. Natürlich sind Rohstreams nicht für die Organisation einer Telefonkonferenz geeignet, jeder Stream muss verarbeitet werden: die Qualität verbessern, Audio mit Video synchronisieren, Synchronisierungsmarkierungen im Videostream platzieren und sicherstellen, dass die Bitrate der sich ständig ändernden Bandbreite des Kanals entspricht . Der Browser kümmert sich um all das, der Entwickler muss sich nicht einmal um die Kodierung der Medienströme kümmern. In einem modernen Browser gibt es bereits Softwareebenen zum Erfassen, Verbessern der Qualität (Echo und Rauschen aus dem Ton entfernen, Bild verbessern), Video- und Audiokodierung. Das Ebenenschema ist in Abb. dargestellt. 1:

(Fast) nutzloses Webcam-Streaming über einen Browser. Teil 2. WebRTCReis. 1. Ebenen der Audio- und Videoverarbeitung im Browser

Die gesamte Verarbeitung findet direkt im Browser selbst statt, es sind keine zusätzlichen Daten erforderlich. keine Plugins erforderlich. Allerdings sieht es für 2020 noch nicht so rosig aus. Es gibt Browser, die dies noch nicht vollständig unterstützen MediaStream-API, können Sie dem Link folgen und die Kompatibilitätstabelle ganz unten sehen. Insbesondere IE ist erneut enttäuschend.

Sie können mit den empfangenen Streams sehr interessante Dinge tun: Sie können sie klonen, die Videoauflösung ändern, die Audioqualität manipulieren, Sie können den Media Stream-Stream übernehmen und daran „anhängen“. Taggen Sie und sehen Sie sich selbst auf der HTML-Seite an. Oder Sie können einen Stream auf der Leinwand zeichnen, WebGL oder CSS3 festlegen und verschiedene Filter auf das Video anwenden, das verarbeitete Video von der Leinwand erfassen und es dann über das Netzwerk an den Server senden, transkodieren und für alle veröffentlichen (Hallo Bigo Live, Twitch). und andere). Hier werde ich nicht analysieren, wie solche Dinge gemacht werden, sondern ein paar Beispiele nennen, die im Internet gefunden wurden:

https://jeeliz.com/ - Die Jungs erstellen Echtzeit-Lebensläufe in Javascript. Sie haben ein Ganzes Arsenal Verschiedene JS-Bibliotheken zum Arbeiten mit einem Videostream auf Leinwand: Erkennen von Gesichtern, Objekten, Anwenden von Filtern (Masken, wie in Instagram) usw. Ein hervorragendes Beispiel dafür, wie Sie Echtzeitvideos ohne zusätzliche Plugins direkt im Browser verarbeiten können.

Canvas CaptureStream-API – API-Dokumentation zum Erfassen eines Videostreams von Canvas. Wird bereits in Chrome, Opera und Firefox unterstützt

RTCPeerConnection

Damit sind wir bei der Sache angelangt: Wie überträgt man das Video eigentlich an einen anderen Benutzer? Kommt in den Vordergrund RTCPeerConnection. Kurz gesagt, bei fast diesem Schritt müssen Sie ein RTCPeerConnection-Objekt erstellen:

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

Als eine der Optionen geben wir „iceServers“ an – dabei handelt es sich um einen Server, der dabei hilft, eine Verbindung zwischen zwei Browsern hinter NAT'om bereitzustellen. Das heißt, das Problem ist hier gelöst: Wie findet man die IP des Gesprächspartners heraus, wenn er sich hinter dem NAT seines Providers befindet? Das ICE-Protokoll kommt zur Rettung, tatsächlich gilt ICE überhaupt nicht für WebRTC, aber dazu später mehr.

Bisher haben wir Usermedia-Streams erhalten:

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

Als nächstes wird das onnegotiationneeded-Ereignis auf der peerConnection ausgelöst, in deren Handler wir ein Angebot (im Sinne von SDP – Session Description Protocol) erstellen und es über die Methode setLocalDescription der peerConnection zuweisen müssen. Über SDP – was es ist und über die Angebots- und Antwortformate – werden wir weiter reden.

Nach der Zuweisung einer LocalDescription peerConnection „assembliert“ der Browser Ice-Kandidaten, das heißt, er findet verschiedene Möglichkeiten, über NAT zu kommunizieren. Das Ereignis „onicegatheringstatechange“ wird ausgelöst. Im onicegatheringstatechange-Handler ermöglichen wir eine Verbindung zum webrtc-signaling-server-Stream, um die Sitzungsbeschreibung zwischen Peers auszutauschen:

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

Der WebRTC-Signaling-Server ist der Server, der zum Austausch der Sitzungsbeschreibung zwischen zwei Peers erforderlich ist. Es kann sich um den einfachsten WebSocket oder XHR-Server auf jedem PL handeln. Seine Aufgabe ist einfach: eine Sitzungsbeschreibung von einem Peer zu akzeptieren und an einen anderen zu übertragen.

Nach dem Austausch der Sitzungsbeschreibungen sind beide Seiten bereit, Videostreams zu senden und zu empfangen. Auf der Seite, die den Videostream empfängt, wird das Ontrack-Ereignis auf der PeerConnection ausgelöst, in dessen Handler die empfangenen Tracks zugeordnet werden können und schauen Sie sich Ihren Lieblingsgesprächspartner an. Weitere Theorie und Details.

Links und Literatur:

https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection - Dokumentation RTCPeerConnection

https://github.com/pion/webrtc - Implementierung von WebRTC-Protokollen unterwegs

https://webrtcforthecurious.com/ - ein Buch von den Machern von Pion

https://hpbn.co/ - Buchen Sie High Performance Browser Networking. Die Fragen der Sicherstellung einer hohen Leistung von Webanwendungen werden ausführlich besprochen. Am Ende wird WebRTC beschrieben. Das Buch ist sicherlich alt (2013), verliert aber nicht an Aktualität.

Im nächsten Teil möchte ich etwas mehr Theorie und Praxis vermitteln, um den Empfang und die Verarbeitung eines Videostreams auf dem Server mithilfe von Pion zu analysieren und ihn über ffmpeg in HLS zu transkodieren, um ihn anschließend im Browser an die Zuschauer zu senden.

Für Ungeduldige: mein sehr grober Prototyp der Übertragung von Videos von einer Webcam, um über einen Pion-basierten Server in Twitch zu reagieren (Dies ist nur ein Experiment).

Source: habr.com

Kommentar hinzufügen