Valaha 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 , 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 , 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:
— legutóbb átbeszéltem, ma még egy kicsit írok róla. A „hardverből” érkező videó/audio folyamok megszerzésére szolgál
— biztosítja a kommunikációt két kliens között (p2p)
— 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ó:
1. á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 , 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
— a srácok valós idejű CV-vel foglalkoznak Javascriptben. Van egy egész 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.
— 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 . 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:
— dokumentáció
— a WebRTC protokollok megvalósítása Go nyelven
— könyv a pion alkotóitól
— 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: (ez csak egy kísérlet).
Forrás: habr.com
