(Gotovo) beskoristan streaming web kamere iz preglednika. Dio 2. WebRTC

Nekako unutra одной iz starih i već napuštenih članaka, napisao sam o tome kako jednostavno i prirodno možete emitirati video s platna putem websocketa. U tom sam članku ukratko govorio o tome kako snimiti video s kamere i zvuk s mikrofona pomoću MediaStream API, kako kodirati primljeni stream i poslati ga putem websocketa na poslužitelj. Međutim, u stvarnosti oni to ne rade, za emitiranje koriste ili poseban softver koji treba instalirati i konfigurirati: na brzinu, to može biti Otvorite emitirani softver, ili koriste WebRTC koji radi odmah iz kutije, odnosno ne zahtijeva instalaciju nikakvih dodataka a la flash player koji će već u prosincu biti izrezan iz preglednika Chromium.

Danas ćemo govoriti o WebRTC-u.

Web komunikacija u stvarnom vremenu (WebRTC) nije jedan protokol, to je cijela zbirka standarda, protokola i JavaScript API-ja koji zajedno pružaju peer-to-peer video-audio komunikaciju u stvarnom vremenu, a također se mogu koristiti za prijenos bilo kojeg binarni podaci . Obično se preglednici ponašaju kao ravnopravni, ali to može biti i mobilna aplikacija, na primjer. Kako bi se organizirala p2p komunikacija između klijenata, potrebna je podrška preglednika za različite vrste video i audio kodiranja, podrška za razne mrežne protokole, osiguravanje interakcije hardvera s preglednikom (preko slojeva OS-a): web-kamere, zvučne kartice. Sva ova hrpa tehnologija skrivena je iza JavaScript API apstrakcije radi praktičnosti programera.

Sve se svodi na tri API-ja:

  • MediaStream API — prošli put demontiran, danas ću napisati nešto više o njemu. Služi za primanje video / audio tokova s ​​hardvera

  • RTCPeer veza — omogućuje komunikaciju između dva klijenta (p2p)

  • RTCDataChannel - služi za prijenos proizvoljnih podataka između dva klijenta

Priprema audio i video tokova za prijenos

Sve počinje "hvatanjem" medijskih tokova putem web kamere i mikrofona. Naravno, neobrađeni streamovi nisu prikladni za organiziranje telekonferencije, svaki stream treba obraditi: poboljšati kvalitetu, sinkronizirati audio s videom, postaviti oznake sinkronizacije u video stream i osigurati bitrate koji odgovara stalnoj promjeni propusnosti kanala. . Preglednik se brine za sve to, programer se ne mora brinuti ni o osiguravanju kodiranja za medijske tokove. Unutar modernog preglednika već postoje softverski slojevi za snimanje, poboljšanje kvalitete (uklanjanje jeke i šuma iz zvuka, poboljšanje slike), video i audio kodiranje. Shema slojeva prikazana je na sl. 1:

(Gotovo) beskoristan streaming web kamere iz preglednika. Dio 2. WebRTCRiža. 1. Slojevi audio i video obrade u pregledniku

Sva se obrada odvija izravno u samom pregledniku, bez dodatnih. nisu potrebni dodaci. No, stvari još uvijek nisu tako ružičaste za 2020. godinu. Postoje preglednici koji još ne podržavaju u potpunosti MediaStream API, možete slijediti poveznicu i vidjeti tablicu kompatibilnosti na samom dnu. Posebno je IE opet razočaravajući.

Možete raditi vrlo zanimljive stvari s primljenim streamovima: možete klonirati, promijeniti razlučivost videa, manipulirati kvalitetom zvuka, možete uzeti i "zakačiti" stream Media Stream na označite i pogledajte se na html stranici. Ili možete nacrtati stream na platnu, postaviti WebGL ili CSS3 i primijeniti razne filtere na video, snimiti obrađeni video s platna i zatim ga poslati preko mreže na server, transkodirati i objaviti svima (hello bigo live, twitch i drugi). Ovdje neću analizirati kako se takve stvari rade, dat ću par primjera koji se nalaze na webu:

https://jeeliz.com/ - dečki rade CV u stvarnom vremenu u Javascriptu. Imaju cjelinu arsenal razne js biblioteke za rad s video streamom na platnu: otkrivanje lica, objekata, primjena filtara (maske, kao u Instagramu) itd. Izvrstan primjer kako možete obraditi video u stvarnom vremenu izravno u pregledniku bez dodatnih dodataka.

Canvas captureStream API - API dokumentacija za snimanje video streama s platna. Već podržano u Chromeu, Operi i Firefoxu

RTCPeer veza

Dakle, došli smo do točke, ali kako zapravo prenijeti video na drugog korisnika? Dolazi do izražaja RTCPeer veza. Ukratko, gotovo u ovom koraku morate stvoriti RTCPeerConnection objekt:

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

Navodimo iceServers kao jednu od opcija - ovo je poslužitelj koji pomaže osigurati vezu između dva preglednika iza NAT'om. Odnosno, problem je ovdje riješen: kako saznati ip sugovornika ako on stoji iza NAT-a svog davatelja? Protokol ICE dolazi u pomoć, zapravo, ICE se uopće ne odnosi na WebRTC, ali o tome kasnije.

Prethodno smo imali Usermedia streamove:

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

Zatim se događaj onnegotiationneeded aktivira na peerConnection, u čijem rukovatelju moramo kreirati ponudu (u smislu SDP - Session Description Protocol) i dodijeliti je peerConnection putem metode setLocalDescription. O SDP-u - što je to te o formatima ponude i odgovora - razgovarat ćemo dalje.

Nakon dodjele LocalDescription peerConnection, preglednik "sklapa" ice kandidate, odnosno pronalazi razne načine za komunikaciju putem NAT-a. Događaj onicegatheringstatechange se aktivira. U rukovatelju onicegatheringstatechange, dopuštamo vezu na webrtc-signaling-server stream za razmjenu Opisa sesije između ravnopravnih korisnika:

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 je poslužitelj potreban za razmjenu opisa sesije između dva ravnopravna uređaja, to može biti najjednostavniji websocket ili xhr-poslužitelj na bilo kojem PL-u. Njegov zadatak je jednostavan: prihvatiti opis sesije od jednog peera i prenijeti ga drugom.

Nakon razmjene opisa sesije, obje strane su spremne za emitiranje i primanje video streamova, na strani koja prima video stream, ontrack događaj se pokreće na peerConnection, u čijem rukovatelju se primljeni tragovi mogu dodijeliti i pogledajte svog omiljenog sugovornika. Daljnja teorija i detalji.

Linkovi i literatura:

https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection - dokumentacija RTCPeer veza

https://github.com/pion/webrtc - implementacija WebRTC protokola u pokretu

https://webrtcforthecurious.com/ - knjiga kreatora pion

https://hpbn.co/ - Rezervirajte Umrežavanje preglednika visokih performansi. Detaljno se raspravlja o pitanjima osiguranja visokih performansi web aplikacija. Na kraju je opisan WebRTC. Knjiga je svakako stara (2013.), ali ne gubi na važnosti.

U sljedećem dijelu želim dati malo više teorije iu praksi analizirati prijem i obradu video streama na poslužitelju pomoću piona, transkodiranje u HLS putem ffmpeg za naknadno emitiranje gledateljima u pregledniku.

Za nestrpljive: moj vrlo grubi prototip emitiranja videa s web kamere za reakciju putem pion-baziranog poslužitelja u twitchu (ovo je samo eksperiment).

Izvor: www.habr.com

Dodajte komentar