(Nesten) ubrukelig webkamerastrømming fra en nettleser. Del 2. WebRTC

På en eller annen måte inn одной fra gamle og allerede forlatte artikler skrev jeg om hvor enkelt og naturlig du kan kringkaste video fra lerret via websockets. I den artikkelen snakket jeg kort om hvordan du kan ta opp video fra et kamera og lyd fra en mikrofon ved hjelp av MediaStream API, hvordan koder den mottatte strømmen og sender den via websockets til serveren. Men i virkeligheten gjør de ikke dette, for sendinger bruker de enten spesiell programvare som må installeres og konfigureres: umiddelbart kan dette være Åpne kringkastingsprogramvare, eller de bruker WebRTC, som fungerer rett ut av esken, det vil si at det ikke krever installasjon av noen plugins a la flash player, som vil bli kuttet ut av Chromium-nettleseren allerede i desember.

I dag skal vi snakke om WebRTC.

Web Real-Time Communication (WebRTC) er ikke en enkelt protokoll, det er en hel samling av standarder, protokoller og JavaScript APIer som sammen gir peer-to-peer sanntids video-lyd kommunikasjon, og kan også brukes til å overføre evt. binære data. Vanligvis fungerer nettlesere som likemenn, men det kan for eksempel også være en mobilapplikasjon. For å organisere p2p-kommunikasjon mellom klienter, kreves nettleserstøtte for ulike typer video- og lydkoding, støtte for en rekke nettverksprotokoller, som sikrer interaksjon av maskinvare med nettleseren (gjennom OS-lag): webkameraer, lydkort. All denne mengden av teknologier er skjult bak JavaScript API-abstraksjonen for utviklerens bekvemmelighet.

Det hele koker ned til tre APIer:

  • MediaStream API — demontert forrige gang, i dag skal jeg skrive litt mer om ham. Tjener til å motta video/lydstrømmer fra maskinvaren

  • RTCPeerConnection — gir kommunikasjon mellom to klienter (p2p)

  • RTCDataChannel - tjener til å overføre vilkårlige data mellom to klienter

Forberede lyd- og videostrømmer for overføring

Det hele starter med å "fange" mediestrømmene fra webkameraet og mikrofonen. Selvfølgelig er råstrømmer ikke egnet for å organisere en telekonferanse, hver strøm må behandles: forbedre kvaliteten, synkroniser lyd med video, plasser synkroniseringsmerker i videostrømmen, og sørg for bithastigheten som tilsvarer den stadig skiftende båndbredden til kanalen . Nettleseren tar seg av alt dette, utvikleren trenger ikke engang å bekymre seg for å gi koding for mediestrømmer. Inne i en moderne nettleser er det allerede programvarelag for fangst, forbedring av kvalitet (fjern ekko og støy fra lyd, forbedre bildet), video- og lydkoding. Lagskjemaet er vist i fig. 1:

(Nesten) ubrukelig webkamerastrømming fra en nettleser. Del 2. WebRTCRis. 1. Lag med lyd- og videobehandling i nettleseren

All behandling skjer direkte i selve nettleseren, uten tillegg. ingen plugins kreves. Ting er imidlertid fortsatt ikke så rosenrødt for 2020. Det er nettlesere som ennå ikke støtter fullt ut MediaStream API, kan du følge lenken og se kompatibilitetstabellen helt nederst. Spesielt IE er igjen skuffende.

Du kan gjøre veldig interessante ting med de mottatte strømmene: du kan klone, endre videooppløsningen, manipulere lydkvaliteten, du kan ta og "feste" Media Stream-strømmen til tagg og se på deg selv på html-siden. Eller du kan tegne en strøm på lerretet, og sette WebGL eller CSS3, og bruke forskjellige filtre på video, fange den behandlede videoen fra lerretet og deretter sende den over nettverket til serveren, transkode og publisere til alle (hei bigo live, twitch og andre). Her skal jeg ikke analysere hvordan slike ting gjøres, jeg vil gi et par eksempler funnet på nettet:

https://jeeliz.com/ - gutta gjør sanntids CV i Javascript. De har en helhet arsenal ulike js-biblioteker for å jobbe med en videostrøm på lerret: oppdage ansikter, objekter, bruke filtre (masker, som i Instagram), etc. Et utmerket eksempel på hvordan du kan behandle sanntidsvideo direkte i nettleseren uten ekstra plugins.

Canvas captureStream API - API-dokumentasjon for å fange en videostrøm fra lerret. Allerede støttet i Chrome, Opera og Firefox

RTCPeerConnection

Så vi kom til poenget, men hvordan overfører jeg videoen til en annen bruker? Kommer i forgrunnen RTCPeerConnection. Kort sagt, på nesten dette trinnet må du opprette et RTCPeerConnection-objekt:

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

Vi spesifiserer iceServers som ett av alternativene – dette er en server som bidrar til å gi en kobling mellom to nettlesere bak NAT'om. Det vil si at problemet er løst her: hvordan finne ut ip-en til samtalepartneren hvis han står bak NAT-en til leverandøren sin? ICE-protokollen kommer til unnsetning, faktisk gjelder ikke ICE for WebRTC i det hele tatt, men mer om det senere.

Tidligere fikk vi Usermedia-strømmer:

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

Deretter utløses den nødvendige forhandlingshendelsen på peerConnection, hvor vi må opprette et tilbud (i form av SDP - Session Description Protocol) og tilordne det til peerConnection via setLocalDescription-metoden. Om SDP - hva det er og om tilbuds- og svarformatene - vil vi snakke videre.

Etter å ha tildelt en LocalDescription peerConnection, "samler" nettleseren iskandidater, det vil si finner forskjellige måter å kommunisere gjennom NAT. onicegatheringstatechange-hendelsen starter. I onicegatheringstatechange-behandleren tillater vi en tilkobling til webrtc-signaling-server-strømmen for å utveksle øktbeskrivelsen mellom jevnaldrende:

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-serveren er serveren som kreves for å utveksle øktbeskrivelsen mellom to likemenn, det kan være den enkleste websocket eller xhr-serveren på en hvilken som helst PL. Oppgaven er enkel: å godta en sesjonsbeskrivelse fra en kollega og overføre den til en annen.

Etter utveksling av sesjonsbeskrivelser er begge sider klare til å kringkaste og motta videostrømmer, på siden som mottar videostrømmen, utløses ontrack-hendelsen på peerConnection, i hvis behandler de mottatte sporene kan tilordnes til og se på favorittsamtalen din. Ytterligere teori og detaljer.

Lenker og litteratur:

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

https://github.com/pion/webrtc - implementering av WebRTC-protokoller på farten

https://webrtcforthecurious.com/ - en bok fra skaperne av pion

https://hpbn.co/ - Bestill nettlesernettverk med høy ytelse. Spørsmålene om å sikre høy ytelse av webapplikasjoner diskuteres i detalj. Til slutt beskrives WebRTC. Boken er sikkert gammel (2013), men mister ikke relevansen.

I neste del ønsker jeg å gi litt mer del av teorien og i praksis å analysere mottak og prosessering av en videostrøm på serveren ved hjelp av pion, transkoding til HLS via ffmpeg for påfølgende kringkasting til seere i nettleseren.

For de utålmodige: min veldig grove prototype på å kringkaste video fra et webkamera for å reagere gjennom en pion-basert server i twitch (dette er bare et eksperiment).

Kilde: www.habr.com

Legg til en kommentar