Webcam (aproape) inutil streaming dintr-un browser. Partea 2. WebRTC

Cumva în одной din articole vechi și deja abandonate, am scris despre cât de ușor și natural poți difuza videoclipuri din pânză prin intermediul websocket-urilor. În acel articol, am vorbit pe scurt despre cum să capturi video de la o cameră și sunet de la un microfon folosind MediaStream API, cum să codificați fluxul primit și să îl trimiteți prin websocket-uri către server. Cu toate acestea, în realitate, ei nu fac acest lucru, pentru emisiuni folosesc fie software special care trebuie instalat și configurat: de la îndemână, acest lucru poate fi Software de difuzare deschisă, sau folosesc WebRTC, care funcționează imediat, adică nu necesită instalarea niciunui plugin la flash player, care va fi scos din browserul Chromium deja în decembrie.

Astăzi vom vorbi despre WebRTC.

Comunicarea web în timp real (WebRTC) nu este un singur protocol, este o întreagă colecție de standarde, protocoale și API-uri JavaScript care oferă împreună comunicații video-audio în timp real peer-to-peer și pot fi, de asemenea, utilizate pentru a transfera orice date binare. De obicei, browserele acționează ca peers, dar poate fi și o aplicație mobilă, de exemplu. Pentru a organiza comunicarea p2p între clienți, este necesar suport de browser pentru diverse tipuri de codare video și audio, suport pentru o varietate de protocoale de rețea, asigurând interacțiunea hardware-ului cu browserul (prin straturi OS): camere web, plăci de sunet. Tot acest amestec de tehnologii este ascuns în spatele abstracției API-ului JavaScript pentru confortul dezvoltatorului.

Totul se rezumă la trei API-uri:

  • MediaStream API — demontat data trecută, azi voi mai scrie puțin despre el. Servește pentru a primi fluxuri video / audio de la hardware

  • RTCPeerConnection — asigură comunicarea între doi clienți (p2p)

  • RTCDataChannel - servește la transferul de date arbitrare între doi clienți

Pregătirea fluxurilor audio și video pentru transmisie

Totul începe cu „capturarea” fluxurilor media webcam și microfon. Desigur, fluxurile brute nu sunt potrivite pentru organizarea unei teleconferințe, fiecare flux trebuie procesat: îmbunătățiți calitatea, sincronizați audio cu video, plasați marcaje de sincronizare în fluxul video și asigurați rata de biți corespunzătoare lățimii de bandă în continuă schimbare a canalului. . Browserul are grijă de toate acestea, dezvoltatorul nici nu trebuie să-și facă griji cu privire la furnizarea de codificare pentru fluxurile media. În interiorul unui browser modern, există deja straturi software pentru captură, îmbunătățirea calității (eliminarea ecoului și zgomotul din sunet, îmbunătățirea imaginii), codificare video și audio. Schema straturilor este prezentată în fig. 1:

Webcam (aproape) inutil streaming dintr-un browser. Partea 2. WebRTCOrez. 1. Straturi de procesare audio și video în browser

Toată prelucrarea are loc direct în browser în sine, fără suplimentar. nu sunt necesare pluginuri. Cu toate acestea, lucrurile nu sunt încă atât de roz pentru 2020. Există browsere care nu acceptă încă pe deplin MediaStream API, puteți urma linkul și puteți vedea tabelul de compatibilitate din partea de jos. IE în special este din nou dezamăgitor.

Puteți face lucruri foarte interesante cu fluxurile primite: puteți clona, ​​schimba rezoluția video, manipula calitatea audio, puteți lua și „conecta” fluxul Media Stream la etichetați și priviți-vă pe pagina html. Sau poți să desenezi un flux pe pânză și să setezi WebGL sau CSS3 și să aplici diverse filtre pentru videoclipuri, să captezi videoclipul procesat din pânză și apoi să-l trimiți prin rețea către server, să transcodezi și să îl publici pentru toată lumea (bună ziua, bigo live, twitch si altii). Aici nu voi analiza cum se fac astfel de lucruri, voi da câteva exemple găsite pe web:

https://jeeliz.com/ - băieții fac CV în timp real în Javascript. Au un întreg arsenal diverse biblioteci js pentru lucrul cu un flux video pe pânză: detectarea fețelor, obiectelor, aplicarea filtrelor (măști, ca în Instagram), etc. Un exemplu excelent despre cum puteți procesa videoclipuri în timp real direct în browser fără pluginuri suplimentare.

Canvas captureStream API - Documentație API pentru captarea unui flux video din pânză. Deja acceptat în Chrome, Opera și Firefox

RTCPeerConnection

Deci am ajuns la subiect, dar cum să transferăm de fapt videoclipul unui alt utilizator? Vine în prim-plan RTCPeerConnection. Pe scurt, aproape la acest pas trebuie să creați un obiect RTCPeerConnection:

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

Specificăm iceServers ca una dintre opțiuni - acesta este un server care ajută la asigurarea unei conexiuni între două browsere din spatele NAT'om. Adică problema se rezolvă aici: cum să aflu ip-ul interlocutorului dacă se află în spatele NAT-ului furnizorului său? Protocolul ICE vine în ajutor, de fapt, ICE nu se aplică deloc la WebRTC, dar vom vorbi despre asta mai târziu.

Anterior, am primit fluxuri 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);

Apoi, evenimentul onnegotiationneeded se declanșează pe peerConnection, în al cărui handler trebuie să creăm o ofertă (în termeni de SDP - Session Description Protocol) și să o atribuim peerConnection prin metoda setLocalDescription. Despre SDP - ce este și despre formatele de ofertă și răspuns - vom vorbi în continuare.

După atribuirea unui peerConnection LocalDescription, browserul „asamblează” candidați de gheață, adică găsește diferite moduri de a comunica prin NAT. Evenimentul onicegatheringstatechange se declanșează. În handlerul onicegatheringstatechange, permitem o conexiune la fluxul webrtc-signaling-server pentru a schimba Descrierea sesiunii între egali:

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

Webrtc-signaling-server este serverul necesar pentru a schimba descrierea sesiunii între doi colegi, poate fi cel mai simplu websocket sau xhr-server de pe orice PL. Sarcina sa este simplă: să accepte o descriere a sesiunii de la un peer și să o transfere la altul.

După schimbul de descrieri de sesiune, ambele părți sunt gata să difuzeze și să primească fluxuri video, pe partea care primește fluxul video, evenimentul onttrack este declanșat pe peerConnection, în al cărui handler, piesele primite pot fi alocate și uită-te la interlocutorul tău preferat. Mai multe teorii și detalii.

Legături și literatură:

https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection - documentație RTCPeerConnection

https://github.com/pion/webrtc - implementarea protocoalelor WebRTC pe drum

https://webrtcforthecurious.com/ - o carte de la creatorii de pion

https://hpbn.co/ - Rezervați rețele de browser de înaltă performanță. Problemele asigurării performanței înalte a aplicațiilor web sunt discutate în detaliu. La sfârșit, este descris WebRTC. Cartea este cu siguranță veche (2013), dar nu își pierde relevanța.

În partea următoare, vreau să dau puțin mai multă parte de teorie și, în practică, să analizez recepția și procesarea unui flux video pe server folosind pion, transcodând în HLS prin ffmpeg pentru difuzarea ulterioară către telespectatori în browser.

Pentru cei nerăbdători: Prototipul meu foarte grosier de difuzare video de la o cameră web pentru a reacționa printr-un server bazat pe pioni în twitch (acesta este doar un experiment).

Sursa: www.habr.com

Adauga un comentariu