(Hast) nuttelose webcam streaming fan in browser. Diel 2. WebRTC

Op ien of oare manier yn ien út âlde en al ferlitten artikels skreau ik oer hoe maklik en natuerlik jo fideo kinne útstjoere fan doek fia websockets. Yn dat artikel haw ik koart praat oer hoe't jo fideo fan in kamera kinne opnimme en lûd fan in mikrofoan brûke MediaStream API, hoe't jo de ûntfongen stream kodearje en fia websockets nei de tsjinner stjoere. Yn 'e realiteit dogge se dit lykwols net, foar útstjoerings brûke se of spesjale software dy't ynstalleare en konfigureare wurde moat: offhand, dit kin wêze Iepen Broadcast Software, of se brûke WebRTC, dy't direkt út 'e doaze wurket, dat is, it fereasket gjin ynstallaasje fan alle plugins a la flash-spiler, dy't al yn desimber út' e Chromium-blêder ôfsnien wurde.

Hjoed sille wy prate oer WebRTC.

Web Real-Time Communication (WebRTC) is net ien protokol, it is in hiele kolleksje fan noarmen, protokollen en JavaScript API's dy't tegearre peer-to-peer real-time fideo-audio-kommunikaasje leverje, en kinne ek brûkt wurde om alle binêre gegevens. Normaal fungearje browsers as peers, mar it kin bygelyks ek in mobile applikaasje wêze. Om p2p-kommunikaasje tusken kliïnten te organisearjen, is browserstipe foar ferskate soarten fideo- en audiokodearring nedich, stipe foar in ferskaat oan netwurkprotokollen, garandearje de ynteraksje fan hardware mei de browser (fia OS-lagen): webcams, lûdkaarten. Al dizze hodgepodge fan technologyen is ferburgen efter de JavaScript API-abstraksje foar it gemak fan 'e ûntwikkelder.

It komt allegear del op trije API's:

  • MediaStream API - de lêste kear ôfbrutsen, hjoed skriuw ik noch wat mear oer him. Tsjinnet om fideo- / audiostreamen te ûntfangen fan 'e hardware

  • RTCPeerConnection - leveret kommunikaasje tusken twa kliïnten (p2p)

  • RTCDataChannel - tsjinnet foar it oerdragen fan willekeurige gegevens tusken twa kliïnten

Audio- en fideostreamen tariede foar oerdracht

It begjint allegear mei it "fangen" fan de mediastreams fan 'e webcam en mikrofoan. Fansels binne rau streamen net geskikt foar it organisearjen fan in telekonferinsje, elke stream moat wurde ferwurke: ferbetterje de kwaliteit, syngronisearje audio mei fideo, pleatse syngronisaasjemarken yn 'e fideostream, en soargje foar de bitrate dy't oerienkomt mei de konstant feroarjende bânbreedte fan it kanaal . De browser soarget foar dit alles, de ûntwikkelder hoecht net iens te soargen oer it leverjen fan kodearring foar mediastreamen. Binnen in moderne browser binne d'r al softwarelagen foar it fêstlizzen, ferbetterjen fan kwaliteit (ferwiderje echo en lûd fan lûd, ferbetterje de ôfbylding), fideo- en audiokodearring. It laachskema wurdt werjûn yn fig. 1:

(Hast) nuttelose webcam streaming fan in browser. Diel 2. WebRTCRys. 1. Lagen fan audio- en fideoferwurking yn 'e browser

Alle ferwurking fynt plak direkt yn 'e browser sels, gjin ekstra. gjin plugins nedich. Dingen binne lykwols noch net sa rooskleurich foar 2020. D'r binne browsers dy't noch net folslein stypje MediaStream API, Jo kinne de keppeling folgje en de kompatibiliteitstabel oan 'e ûnderkant sjen. Benammen IE is wer teloarstellend.

Jo kinne heul ynteressante dingen dwaan mei de ûntfongen streamen: jo kinne klonje, de fideoresolúsje feroarje, de audiokwaliteit manipulearje, jo kinne de Media Stream-stream nimme en "heakje" oan tag en sjoch nei josels op 'e html-side. Of jo kinne in stream op canvas tekenje, en WebGL of CSS3 ynstelle, en ferskate filters tapasse op fideo, de ferwurke fideo fan canvas opnimme en it dan oer it netwurk nei de server stjoere, transkodearje en publisearje oan elkenien (hallo bigo live, twitch en oaren). Hjir sil ik net analysearje hoe't sokke dingen wurde dien, ik sil in pear foarbylden jaan dy't fûn binne op it web:

https://jeeliz.com/ - de jonges dogge realtime CV yn Javascript. Se hawwe in gehiel arsenaal ferskate js-biblioteken foar it wurkjen mei in fideostream op doek: gesichten, objekten opspoaren, filters tapasse (maskers, lykas yn Instagram), ensfh. In poerbêst foarbyld fan hoe't jo realtime fideo direkt yn 'e browser kinne ferwurkje sûnder ekstra plugins.

Canvas captureStream API - API-dokumintaasje foar it fêstlizzen fan in fideostream fan canvas. Al stipe yn Chrome, Opera en Firefox

RTCPeerConnection

Dat wy kamen ta it punt, mar hoe kinne jo de fideo feitlik oerdrage nei in oare brûker? Komt nei foaren RTCPeerConnection. Koartsein, op hast dizze stap moatte jo in RTCPeerConnection-objekt oanmeitsje:

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

Wy spesifisearje iceServers as ien fan 'e opsjes - dit is in tsjinner dy't helpt om in ferbining te meitsjen tusken twa browsers efter NAT'om. Dat is, it probleem is hjir oplost: hoe kinne jo de ip fan 'e petearpartner fine as hy efter de NAT fan syn provider is? It ICE-protokol komt ta de rêding, yn feite is ICE hielendal net fan tapassing op WebRTC, mar dêroer letter mear.

Earder krigen wy Usermedia-streams:

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

Folgjende, de ûnderhanneling nedich evenemint fjoer op 'e peerConnection, yn' e handler wêrfan wy moatte meitsje in oanbod (yn termen fan SDP - Sesje Description Protocol) en tawize it oan de peerConnection fia de setLocalDescription metoade. Oer SDP - wat it is en oer it oanbod en antwurdformaten - sille wy fierder prate.

Nei it tawizen fan in LocalDescription peerConnection, de browser "assemble" iis kandidaten, dat is, fynt ferskate manieren om te kommunisearjen fia NAT. It barren fan ienige-statechange fjoer. Yn 'e onicegatheringstatechange-handler litte wy in ferbining mei de webrtc-signaling-serverstream tastean om de sesjebeskriuwing te wikseljen tusken peers:

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

De webrtc-signaling-server is de tsjinner dy't nedich is om de sesjebeskriuwing te wikseljen tusken twa peers, it kin de ienfâldichste websocket of xhr-tsjinner wêze op elke PL. Syn taak is ienfâldich: in sesjebeskriuwing fan ien peer akseptearje en oerdrage nei in oare.

Nei de útwikseling fan sesjebeskriuwingen binne beide kanten ree om fideostreamen út te stjoeren en te ûntfangen, oan 'e kant dy't de fideostream ûntfangt, wurdt it ontrack-evenemint op' e peerConnection trigger, yn 'e handler wêrfan de ûntfongen spoaren kinne wurde tawiisd oan en sjoch nei jo favorite petearpartner. Fierdere teory en details.

Links en literatuer:

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

https://github.com/pion/webrtc - ymplemintaasje fan WebRTC-protokollen ûnderweis

https://webrtcforthecurious.com/ - in boek fan 'e makkers fan pion

https://hpbn.co/ - Book High Performance Browser Networking. De problemen fan it garandearjen fan hege prestaasjes fan webapplikaasjes wurde yn detail besprutsen. Oan 'e ein wurdt WebRTC beskreaun. It boek is grif âld (2013), mar ferliest syn relevânsje net.

Yn it folgjende diel wol ik in bytsje mear diel fan teory jaan en yn 'e praktyk de ûntfangst en ferwurking fan in fideostream op' e tsjinner analysearje mei pion, transkodearjen nei HLS fia ffmpeg foar folgjende útstjoering nei sjoggers yn 'e browser.

Foar de ûngeduldigen: myn heul rûge prototype fan fideo útstjoeren fan in webcam om te reagearjen fia in pion-basearre server yn twitch (dit is gewoan in eksperimint).

Boarne: www.habr.com

Add a comment