(Beveik) nenaudingas internetinės kameros srautinis perdavimas iš naršyklės. 2 dalis. WebRTC

Kažkaip viduje одной iš senų ir jau apleistų straipsnių rašiau apie tai, kaip lengvai ir natūraliai galima transliuoti video iš drobės per internetinius lizdus. Tame straipsnyje trumpai kalbėjau apie tai, kaip naudojant kamerą užfiksuoti vaizdo įrašą ir mikrofono garsą „MediaStream“ API, kaip užkoduoti gautą srautą ir per websockets nusiųsti į serverį. Tačiau iš tikrųjų jie to nedaro, transliuodami naudoja specialią programinę įrangą, kurią reikia įdiegti ir sukonfigūruoti: tai gali būti Open Broadcast Software, arba jie naudoja WebRTC, kuris veikia iš karto, tai yra, nereikia diegti jokių įskiepių a la flash player, kurie iš Chromium naršyklės bus iškirpti jau gruodžio mėnesį.

Šiandien kalbėsime apie WebRTC.

Žiniatinklio realiojo laiko komunikacija (WebRTC) nėra vienas protokolas, tai yra visas standartų, protokolų ir „JavaScript“ API rinkinys, kuris kartu užtikrina lygiavertį realaus laiko vaizdo ir garso ryšį, taip pat gali būti naudojamas bet kokiam perdavimui. dvejetainiai duomenys. Paprastai naršyklės veikia kaip lygiavertės, bet tai taip pat gali būti, pavyzdžiui, mobilioji programa. Norint organizuoti p2p ryšį tarp klientų, reikalingas įvairių tipų vaizdo ir garso kodavimo naršyklės palaikymas, įvairių tinklo protokolų palaikymas, užtikrinantis aparatinės įrangos sąveiką su naršykle (per OS sluoksnius): internetinės kameros, garso plokštės. Kūrėjo patogumui visas šis technologijų maišas yra paslėptas už JavaScript API abstrakcijos.

Viskas susiveda į tris API:

  • „MediaStream“ API — išmontuotas praeitą kartą, šiandien apie jį parašysiu šiek tiek plačiau. Naudojamas vaizdo / garso srautams iš aparatinės įrangos priimti

  • RTCPeerConnection - užtikrina ryšį tarp dviejų klientų (p2p)

  • RTCDataChannel - skirtas savavališkų duomenų perdavimui tarp dviejų klientų

Garso ir vaizdo srautų paruošimas perdavimui

Viskas prasideda nuo internetinės kameros ir mikrofono medijos srautų „užfiksavimo“. Žinoma, neapdoroti srautai netinka organizuoti telekonferenciją, kiekvieną srautą reikia apdoroti: pagerinti kokybę, sinchronizuoti garsą su vaizdo įrašu, vaizdo sraute dėti sinchronizacijos žymes, užtikrinti nuolat kintantį kanalo pralaidumą atitinkantį bitų srautą. . Naršyklė visu tuo rūpinasi, kūrėjui net nereikia rūpintis, kad medijos srautams būtų suteikta koduotė. Šiuolaikinės naršyklės viduje jau yra programinės įrangos sluoksniai, skirti fiksuoti, pagerinti kokybę (pašalinti garso aidą ir triukšmą, pagerinti vaizdą), vaizdo ir garso kodavimui. Sluoksnio schema parodyta fig. 1:

(Beveik) nenaudingas internetinės kameros srautinis perdavimas iš naršyklės. 2 dalis. WebRTCRyžiai. 1. Garso ir vaizdo apdorojimo naršyklėje sluoksniai

Visas apdorojimas vyksta tiesiai pačioje naršyklėje, jokių papildomų. nereikia jokių įskiepių. Tačiau 2020 m. reikalai vis dar nėra tokie rožiniai. Yra naršyklių, kurios dar nevisiškai palaiko „MediaStream“ API, galite sekti nuorodą ir pamatyti suderinamumo lentelę pačiame apačioje. Ypač IE vėl nuvilia.

Su gautais srautais galite nuveikti labai įdomių dalykų: galite klonuoti, keisti vaizdo skiriamąją gebą, manipuliuoti garso kokybe, galite paimti ir „prikabinti“ Media Stream srautą. pažymėkite ir pažiūrėkite į save html puslapyje. Arba galite nupiešti srautą ant drobės ir nustatyti WebGL arba CSS3, vaizdo įrašams taikyti įvairius filtrus, užfiksuoti apdorotą vaizdo įrašą iš drobės ir nusiųsti jį per tinklą į serverį, perkoduoti ir paskelbti visiems (hello bigo live, twitch ir kiti). Čia neanalizuosiu kaip tokie dalykai daromi, pateiksiu porą internete rastų pavyzdžių:

https://jeeliz.com/ - Vaikinai kuria CV realiuoju laiku Javascript. Jie turi visumą arsenalas įvairios js bibliotekos, skirtos darbui su vaizdo srautu ant drobės: aptikti veidus, objektus, pritaikyti filtrus (kaukes, kaip Instagrame) ir tt Puikus pavyzdys, kaip galite apdoroti vaizdo įrašą realiuoju laiku tiesiogiai naršyklėje be papildomų įskiepių.

Canvas captureStream API - API dokumentacija, skirta vaizdo įrašų srautui užfiksuoti iš drobės. Jau palaikoma „Chrome“, „Opera“ ir „Firefox“.

RTCPeerConnection

Taigi mes priėjome prie reikalo, bet kaip iš tikrųjų perkelti vaizdo įrašą kitam vartotojui? Išeina į pirmą planą RTCPeerConnection. Trumpai tariant, beveik šiame žingsnyje turite sukurti RTCPeerConnection objektą:

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

Kaip vieną iš variantų nurodome iceServers – tai serveris, padedantis užtikrinti ryšį tarp dviejų naršyklių už NAT'om. Tai yra, čia išspręsta problema: kaip sužinoti pašnekovo IP, jei jis yra už savo teikėjo NAT? ICE protokolas ateina į pagalbą, iš tikrųjų ICE visiškai netaikomas WebRTC, bet apie tai vėliau.

Anksčiau turėjome „Usermedia“ srautus:

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

Tada onnegotiationneeded įvykis suaktyvinamas peerConnection, kurio tvarkyklėje turime sukurti pasiūlymą (pagal SDP - Session Description Protocol) ir priskirti jį peerConnection per setLocalDescription metodą. Apie SDP – kas tai yra ir apie pasiūlymą bei atsakymų formatus – kalbėsime toliau.

Priskyrus LocalDescription peerConnection, naršyklė „surenka“ ledo kandidatus, tai yra randa įvairių būdų bendrauti per NAT. Įvykis „onicegatheringstatechange“ užsidega. Onicegatheringstatechange tvarkyklėje leidžiame prisijungti prie webrtc-signaling-server srauto, kad būtų galima keistis seanso aprašymu tarp lygiaverčių programų:

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 yra serveris, reikalingas keistis sesijos aprašymu tarp dviejų lygiaverčių programų. Tai gali būti paprasčiausias žiniatinklio lizdas arba xhr-serveris bet kuriame PL. Jo užduotis paprasta: priimti seanso aprašymą iš vieno kolegos ir perkelti jį kitam.

Pasikeitus seanso aprašymams, abi pusės yra pasirengusios transliuoti ir priimti vaizdo srautus, toje pusėje, kuri priima vaizdo srautą, „ontrack“ įvykis suveikia „peerConnection“, kurio tvarkyklėje galima priskirti gautus takelius. ir pažiūrėkite į savo mėgstamą pašnekovą. Tolesnė teorija ir detalės.

Nuorodos ir literatūra:

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

https://github.com/pion/webrtc - WebRTC protokolų diegimas kelyje

https://webrtcforthecurious.com/ - knyga iš piono kūrėjų

https://hpbn.co/ - Užsisakykite didelio našumo naršyklės tinklą. Išsamiai aptariami didelio interneto programų našumo užtikrinimo klausimai. Pabaigoje aprašomas WebRTC. Knyga tikrai sena (2013 m.), bet nepraranda savo aktualumo.

Kitoje dalyje noriu pateikti šiek tiek daugiau teorijos ir praktiškai išanalizuoti vaizdo srauto priėmimą ir apdorojimą serveryje naudojant pion, perkoduojant į HLS per ffmpeg, kad vėliau būtų galima transliuoti žiūrovams naršyklėje.

Nekantriesiems: mano labai grubus prototipas, transliuojantis vaizdo įrašą iš internetinės kameros, kad būtų galima reaguoti per pioninį serverį (tai tik eksperimentas).

Šaltinis: www.habr.com

Добавить комментарий