(Majdnem) haszontalan webkamera streaming a böngészőből. 2. rész. WebRTC

Valaha egy a régi, már elhagyott cikkek egyikében írtam arról, hogy mennyire könnyedén és zökkenőmentesen lehet videót közvetíteni canvason keresztül websockets segítségével. Abban a cikkben felületesen elmondtam, hogyan lehet rögzíteni a videót a kamerából és a hangot a mikrofonnal a segítségével MediaStream API, hogyan kell a kapott adatfolyamot kódolni és át küldeni websockets-en keresztül a szerverre. Azonban a valóságban nem így működik, a közvetítésekhez vagy speciális szoftvereket használnak, amelyeket telepíteni és konfigurálni kell: hirtelen mondva ez lehet Open Broadcast Software, vagy kihasználják a WebRTC-t, amely közvetlenül dobozból dolgozik, tehát nem igényel semmiféle plugin telepítését, mint például a flash player, amit már decemberben eltávolítanak a Chromium böngészőből.

Ma a WebRTC-ről fogunk beszélni.

Web Real-Time Communication (WebRTC) nem egy protokoll, hanem egy egész standardok, protokollok és JavaScript API gyűjteménye, amelyek együtt lehetővé teszik a peer-to-peer video-audio kommunikációt valós időben, és bármely bináris adat átadására is használhatók. Általában a felek böngészők, de ez lehet mobilalkalmazás is például. A p2p kommunikáció megszervezéséhez a böngészőnek támogatnia kell a különböző videó- és audio-kódolási típusokat, számos hálózati protokollt kell támogatnia, és biztosítania kell a hardver böngészővel való interakcióját (az operációs rendszer rétegein keresztül): webkamerák, hangkártyák. Mindez a technológiák zűrzavara rejtve van a JavaScript API absztrakciója mögött a fejlesztő kényelme érdekében.

Végül mindez három API-ra redukálódik:

  • MediaStream API — legutóbb átbeszéltem, ma még egy kicsit írok róla. A „hardverből” érkező videó/audio folyamok megszerzésére szolgál

  • RTCPeerConnection — biztosítja a kommunikációt két kliens között (p2p)

  • RTCDataChannel — szolgál a tetszőleges adatok átvitelére a két kliens között

Az audio és video folyamok előkészítése az átvitelre

Minden a webkamera és a mikrofon médiasugarainak «megragadásával» kezdődik. A nyers streamek természetesen nem alkalmasak a távoli konferenciák lebonyolítására; minden streamet feldolgozni kell: javítani a minőséget, szinkronizálni a hangot a videóval, szinkronizálási címkéket elhelyezni a videóstreamben, és biztosítani kell a csatorna sávszélességének folyamatosan változó bitsebességéhez való illeszkedést. A böngésző mindezt átveszi, a fejlesztőnek egyáltalán nem kell aggódnia a médiasugarak kódolása miatt. A modern böngészőkben már vannak szoftverrétegek, amelyek a rögzítést, a minőségjavítást (az echo és a zaj eltávolítása, a kép javítása), valamint a videó és a hang kódolását végzik. A rétegek séma a 1. ábrán látható:

(Majdnem) haszontalan webkamera streaming a böngészőből. 2. rész. WebRTC1. ábra. A hang- és videofeldolgozási rétegek a böngészőben

Mindez a böngészőben történik, nincs szükség további pluginek telepítésére. Azonban 2020-ra még mindig nem minden olyan rózsás. Vannak böngészők, amelyek még mindig nem támogatják teljes mértékben MediaStream API, a linkre kattintva a legalján megnézheti a kompatibilitási táblázatot. Különösen az IE ismét csalódást okoz.

A megszerzett streamekkel nagyon érdekes dolgokat csinálhatunk: klónozhatjuk, megváltoztathatjuk a videó felbontását, manipulálhatunk a hang minőségével, „hozzákapcsolhatjuk” a Media Streamet a

https://jeeliz.com/ — a srácok valós idejű CV-vel foglalkoznak Javascriptben. Van egy egész fegyvertáruk különböző JS-könyvtárak a videostreammel való munka érdekében a canvason: arcok, objektumok és szűrők (maszkok, mint az instán) és mások észlelése. Kiváló példa arra, hogyan lehet a böngészőben, további pluginek nélkül, valós időben videót feldolgozni.

Canvas captureStream API — API dokumentáció a canvas videostreamjének rögzítésére. Már támogatja a Chrome, Opera és Firefox.

RTCPeerConnection

Most pedig eljutottunk a kérdéshez, hogy hogyan lehet a videót átadni egy másik felhasználónak? A középpontba kerül RTCPeerConnection. Röviden szólva, ezen a lépésen gyakorlatilag egy RTCPeerConnection objektumot kell létrehoznia:

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

Az egyik opció, amit megadhatunk, az iceServers - ez a szerver segít a NAT mögött lévő két böngésző közötti kapcsolat biztosításában. Vagyis itt azt a problémát oldjuk meg, hogy hogyan tudjuk megismerni a partner IP-címét, ha az a szolgáltató NAT-ja mögött helyezkedik el? Az ICE protokoll segít, valójában az ICE nem közvetlenül a WebRTC-hez kapcsolódik, de erről később.

Korábban megkaptuk a Usermedia folyamokat:

navigator.mediaDevices.getUserMedia({ video: true, audio: true }).then(stream => {
  // Usermedia folyamok, általában ez video és audio 
  const tracks = stream.getTracks();

   for (const track of tracks) {
     // minden track-et hozzáadunk a peerConnection-höz
     peerConnection.addTrack(track);
   }
}).catch(console.error);

Ezután a peerConnection-on bekövetkezik az onnegotiationneeded esemény, melynek kezelőjében fel kellene állítanunk egy ajánlatot (SDP - Session Description Protocol kifejezésekben) és be kell állítanunk a peerConnection-t a setLocalDescription metódussal. Az SDP-ről - mi ez és az ajánlat és a válasz formátumáról - később beszélünk.

A LocalDescription peerConnection beállítása után a böngésző "összegyűjti" az ice-jelölteket, vagyis különböző utakat talál a NAT-on keresztüli kommunikációra. Bekövetkezik az onicegatheringstatechange esemény. Az onicegatheringstatechange kezelőjében engedélyezzük a webrtc-signaling szerverrel való kapcsolatot a Session Description cseréjéhez a peer-ek között:

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

A webrtc-signaling szerver egy olyan szerver, amely szükséges a session description cseréjéhez a két peer között, lehet ez egy egyszerű websocket vagy xhr szerver bármilyen programozási nyelven. A feladata egyszerű: elfogadni a session description-t az egyik peer-től és továbbítani a másiknak.

A Session descriptions cseréje után mindkét fél készen áll a video stream-ek továbbítására és fogadására, a befogadó oldalon az ontrack esemény aktiválódik a peerConnection-on, ahol a kapott track-eket a

Hivatkozások és irodalom:

https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection — dokumentáció RTCPeerConnection

https://github.com/pion/webrtc — a WebRTC protokollok megvalósítása Go nyelven

https://webrtcforthecurious.com/ — könyv a pion alkotóitól

https://hpbn.co/ — könyv az High Performance Browser Networkingről. A webalkalmazások magas teljesítményének biztosításával foglalkozó kérdéseket részletez. A végén bemutatja a WebRTC-t. A könyv természetesen régi (2013), de nem veszít aktualitásából.

A következő részben szeretnék még egy adag elméletet adni, és gyakorlatban bemutatni a videofolyam feldolgozásának módját a pion segítségével, az HLS-be való transcodingot az ffmpeg használatával a nézők böngészőbe való közvetítéséhez.

A türelmetlenek számára: az én nagyon nyers prototípusom a videó webkamerás közvetítésére React-on keresztül a pion alapú szerveren a Twitch-en (ez csak egy kísérlet).

Forrás: habr.com

Megbízható hosting vásárlása weboldalak számára, DDoS védelemmel, VPS VDS szerverek. 🔥 Megbízható webtárhely vásárlása DDoS védelemmel, VPS VDS szerverek | ProHoster