Raz niekedy v jednej zo starých a už opustených článkov som písal o tom, ako jednoducho a bez námahy sa dá prenášať video z canvasu cez websockets. V tom článku som povrchne popísal, ako zachytiť video z kamery a zvuk z mikrofónu pomocou , ako na získaný tok aplikovať kódovanie a posielať ho cez websockets na server. Avšak v skutočnosti sa to tak nerobí, na prenosy sa zvyčajne používajú buď špeciálny softvér, ktorý je potrebné nainštalovať a nastaviť: ako prvé ma napadá , alebo sa využíva WebRTC, ktorý funguje priamo bez akýchkoľvek pluginov, ako napríklad flash player, ktorý v decembri definitívne odstránia z prehliadača Chromium.
Dnes sa porozprávame o WebRTC.
Web Real-Time Communication (WebRTC) nie je len jeden protokol, je to celá zbierka štandardov, protokolov a JavaScript API, ktoré spoločne zabezpečujú peer-to-peer video a audio komunikáciu v reálnom čase a môžu byť použité na prenos akýchkoľvek binárnych údajov. Obvykle sú peerami prehliadače, avšak môže to byť aj mobilná aplikácia, napríklad. Na to, aby bolo možné zorganizovať p2p komunikáciu medzi klientmi, je potrebná podpora pre rôzne typy kódovania videa a audia od prehliadača, podpora mnohých sieťových protokolov a zabezpečenie spolupráce hardvéru s prehliadačom (cez vrstvy OS): webkamier, zvukových kariet. Celá táto zmes technológií je skrytá za abstrakciou JavaScript API pre pohodlie vývojára.
Nakoniec všetko spočíva v troch API:
— ako sme preberali minule, dnes o ňom ešte niečo napíšem. Slúži na získavanie video/audío tokov z 'hardvéru'
— zabezpečuje komunikáciu medzi dvoma klientmi (p2p)
— slúži na prenos ľubovoľných údajov medzi dvoma klientmi
Príprava audio a video tokov na prenos
Všetko začína „zachytávaním“ mediálnych tokov z webkamery a mikrofónu. Raw toky samozrejme nie sú vhodné na organizáciu telekonferencie, preto je potrebné každý tok spracovať: zlepšiť kvalitu, synchronizovať audio s videom, pridať synchronizačné značky do video toku a zabezpečiť, aby sa bitrate prispôsobil neustále sa meniacim šírkam prenosového kanála. To všetko zabezpečuje prehliadač, vývojár sa nemusí obávať o kódovanie mediálnych tokov. Vnútri moderného prehliadača sú už prítomné softvérové vrstvy na zachytávanie, zlepšovanie kvality (odstránenie ozveny a šumu zo zvuku, zlepšenie obrazu), kódovanie videa a audia. Schéma vrstiev je znázornená na obr. 1:
Obr. 1. Vrstvy spracovania audia a videa v prehliadači
Celé spracovanie prebieha priamo v prehliadači, žiadne ďalšie pluginy nie sú potrebné. Avšak na rok 2020 to stále nie je ideálne. Existujú prehliadače, ktoré zatiaľ úplne nepodporujú , môžete prejsť na odkaz a na spodnej časti nájsť tabuľku kompatibility. Predovšetkým IE znovu sklamáva.
S prijatými tokmi môžete robiť veľmi zaujímavé veci: môžete klonovať, meniť rozlíšenie videa, manipulovať s kvalitou audia, môžete vziať a „pripojiť“ Media Stream tok k <video> značke a pozerať sa na seba na html stránke. Tok môžete tiež zobraziť na canvas, nasmerovať WebGL alebo CSS3, aplikovať rôzne filtre na video, zachytiť spracované video z canvas a následne ho poslať cez sieť na server, transcodiť a publikovať všetkým záujemcom (pozdravujem bigo live, twitch a ďalších). Tu nebudem podrobne rozoberať, ako sa tieto veci robia, uvediem pár príkladov, ktoré som našiel na internete:
— chlapci sa zaoberajú realtime CV na Javascript. Majú celý rôznych js knižníc na prácu s videom na canvas: detekcia tvárí, objektov, aplikácia filtrov (masiek, ako v instagrame) a pod. Skvelý príklad toho, ako bez ďalších pluginov môžeme priamo v prehliadači spracovávať video v reálnom čase.
— dokumentácia API na zachytávanie video toku z canvas. Už je podporovaná v Chrome, Opera a Firefox.
RTCPeerConnection
A sme pri otázke, ako vlastne preniesť video inému používateľovi? Na prvý plán vystupuje Ak hovoríme stručne, prakticky v tomto kroku musíte vytvoriť objekt RTCPeerConnection:
const peerConnection = new RTCPeerConnection({
iceServers: [{
urls: 'stun:stun.l.google.com:19302'
}]
});Jednou z možností je určiť iceServers — to je server, ktorý pomáha zabezpečiť spojenie medzi dvoma prehliadačmi, ktoré sú za NAT. Týmto sa rieši problém: ako zistiť IP adresu partnera, ak sa nachádza za NAT jeho poskytovateľa? Na pomoc prichádza protokol ICE, v skutočnosti, ICE sa vôbec netýka WebRTC, ale o tom viac neskôr.
Predtým sme získali Usermedia toky:
navigator.mediaDevices.getUserMedia({ video: true, audio: true }).then(stream => {
// Usermedia toky, zvyčajne video a audio
const tracks = stream.getTracks();
for (const track of tracks) {
// každý track pridáme k peerConnection
peerConnection.addTrack(track);
}
}).catch(console.error);Potom sa na peerConnection aktivuje udalosť onnegotiationneeded, v spracovateľovi ktorej musíme vytvoriť ponuku (v termínoch SDP — Session Description Protocol) a nastaviť ju v peerConnection pomocou metódy setLocalDescription. O SDP — čo to je a o formátoch ponuky a odpovede — si povieme neskôr.
Po nastavení LocalDescription peerConnection, prehliadač "zhromažďuje" ice kandidátov, to znamená, že hľadá rôzne cesty na komunikáciu cez NAT. Aktivuje sa udalosť onicegatheringstatechange. V spracovateľovi onicegatheringstatechange povolíme spojenie s webrtc-signaling serverom stream na výmenu Session Description medzi partnermi:
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 — to je server potrebný na zabezpečenie výmeny session description medzi dvoma partnermi, môže to byť jednoduchý websocket alebo xhr server v akomkoľvek programovacom jazyku. Jeho úlohou je jednoduchá: prijať session description od jedného partnera a poslať ho druhému.
Po výmene Session descriptions sú obe strany pripravené vysielať a prijímať video toky, na strane, ktorá prijíma video tok sa aktivuje udalosť ontrack na peerConnection, v spracovateľovi ktorej môžeme prijaté tracky priradiť k
Odkazy a literatúra:
— dokumentácia
— implementácia protokolov WebRTC v go
— knižka od tvorcov pion
— kniha High Performance Browser Networking. V podrobnostiach sa zaoberá otázkami zabezpečenia vysokej výkonnosti webových aplikácií. Na konci sa popisuje WebRTC. Kniha je samozrejme staršia (2013), ale nestráca svoju aktuálnosť.
V nasledujúcej časti chcem poskytnúť ešte trochu teórie a prakticky si rozobrať prijímanie a spracovanie videostreamu na serveri pomocou pion, transcoding do HLS cez ffmpeg pre následnú distribúciu divákom v prehliadači.
Pre netrpezlivých: (to je len experiment).
Zdroj: habr.com
