(toetoe lava) leai se aoga webcam tafe mai se su'ega. Ala o Faasalalauga ma Websockets

I lenei tusiga ou te manaʻo e faʻasoa aʻu taumafaiga e faʻasalalau vitio e ala i websockets e aunoa ma le faʻaogaina o masini suʻesuʻe lona tolu e pei ole Adobe Flash Player. Faitau pea e iloa ai po o le a le mea na maua mai ai.

Adobe Flash, muamua Macromedia Flash, o se faʻavae mo le fatuina o talosaga e taʻavale i luga o le upega tafaʻilagi. Aʻo leʻi faʻaofiina le Media Stream API, e na o le pau lea o le faʻavae mo le faʻafefeina o vitio ma leo mai se webcam, faʻapea foʻi ma le fatuina o ituaiga eseese o konafesi ma talatalanoaga i totonu o le masini. O le faʻasalalauga mo le faʻasalalauina o faʻamatalaga faʻasalalau RTMP (Real Time Messaging Protocol) na tapunia moni mo se taimi umi, o lona uiga: afai e te manaʻo e faʻaleleia lau auaunaga faʻafefe, ia lava le agalelei e faʻaoga le polokalama mai le Adobe lava ia - Adobe Media Server (AMS).

Ina ua mavae sina taimi i le 2012, Adobe "na fiu ma feanu" i tagata lautele. fa'amatalaga RTMP protocol, lea sa i ai mea sese ma e matua le atoatoa. I lena taimi, na amata ona faia e le au atinaʻe a latou lava faʻatinoga o lenei faʻasalalauga, ma faʻaalia le server Wowza. I le 2011, na faila ai e Adobe se tagi faasaga ia Wowza mo le faʻaaogaina faasolitulafono o pateni e fesoʻotaʻi ma le RTMP; ina ua maeʻa le 4 tausaga, na foia lelei le feeseeseaiga.

O le Adobe Flash platform e sili atu i le 20 tausaga le matua, o le taimi lea na maua ai le tele o faʻafitauli matuia, lagolago. folafola e fa'ai'u i le 2020, ae tu'u ai nai isi avanoa mo le auaunaga fa'asalalau.

Mo laʻu galuega faatino, na vave ona ou filifili e lafoai atoa le faʻaogaina o le Flash i le masini. Na ou faʻaalia le mafuaʻaga autu i luga; E leʻo lagolagoina foʻi le Flash i luga o masini feaveaʻi, ma ou te leʻi manaʻo e faʻapipiʻi le Adobe Flash mo le atinaʻe i luga o Windows (wine emulator). O lea na ou alu ai e tusi se tagata faʻatau ile JavaScript. O le a na o se faʻataʻitaʻiga, talu ai na ou iloa mulimuli ane o le tafega e mafai ona sili atu le lelei e faʻavae i luga o le p2p, naʻo aʻu o le a avea ma peer - server - peers, ae sili atu i lena isi taimi, aua e leʻi sauni.

Ina ia amata, matou te manaʻomia le server websockets moni. Na ou faia le mea sili ona faigofie e faʻatatau i le melody go package:

Code server

package main

import (
	"errors"
	"github.com/go-chi/chi"
	"gopkg.in/olahol/melody.v1"
	"log"
	"net/http"
	"time"
)

func main() {
	r := chi.NewRouter()
	m := melody.New()

	m.Config.MaxMessageSize = 204800

	r.Get("/", func(w http.ResponseWriter, r *http.Request) {
		http.ServeFile(w, r, "public/index.html")
	})
	r.Get("/ws", func(w http.ResponseWriter, r *http.Request) {
		m.HandleRequest(w, r)
	})

         // Бродкастим видео поток 
	m.HandleMessageBinary(func(s *melody.Session, msg []byte) {
		m.BroadcastBinary(msg)
	})

	log.Println("Starting server...")

	http.ListenAndServe(":3000", r)
}

I luga o le tagata o tausia (faitaaga itu), e tatau ona e mauaina muamua le meapueata. E faia lenei mea e ala i MediaStream API.

Matou te maua le avanoa (fa'atagaga) i le meapueata/microphone e ala i Mea Fa'asalalau API. O lenei API e maua ai se metotia MediaDevices.getUserMedia(), lea e fa'aalia ai popup. se fa'amalama e fesili ai le tagata fa'aoga mo se fa'atagaga e maua ai le meapueata ma/po'o le masini faaleotele leo. Ou te fia maitauina na ou faia uma faʻataʻitaʻiga i Google Chrome, ae ou te manatu o le a tutusa mea uma i Firefox.

Sosoo ai, getUserMedia() toe faafoi se Folafolaga, lea na te pasia ai se mea MediaStream - o se tafega o faamatalaga vitio-leo. Matou te tuʻuina atu lenei mea i le meatotino src o le elemene vitio. Code:

Itu faasalalau

<style>
  #videoObjectHtml5ApiServer { width: 320px; height: 240px; background: #666; }
</style>
</head>
<body>
<!-- Здесь в этом "окошечке" клиент будет видеть себя -->
<video autoplay id="videoObjectHtml5ApiServer"></video>

<script type="application/javascript">
  var
        video = document.getElementById('videoObjectHtml5ApiServer');

// если доступен MediaDevices API, пытаемся получить доступ к камере (можно еще и к микрофону)
// getUserMedia вернет обещание, на которое подписываемся и полученный видеопоток в колбеке направляем в video объект на странице

if (navigator.mediaDevices.getUserMedia) {
        navigator.mediaDevices.getUserMedia({video: true}).then(function (stream) {
          // видео поток привязываем к video тегу, чтобы клиент мог видеть себя и контролировать 
          video.srcObject = stream;
        });
}
</script>

Ina ia faʻasalalau se ata vitio i luga o sockets, e tatau ona e faʻapipiʻiina i se mea, puipui, ma faʻasalalau i vaega. E le mafai ona fa'asalalauina le ata vitio mata'utia e ala i sockets. O le mea lea e sau ai le matou fesoasoani MediaRecorder API. O lenei API e mafai ai e oe ona faʻapipiʻi ma talepe le vaitafe i ni vaega. Ou te faia le faʻailoga e faʻapipiʻi ai le ata vitio ina ia mafai ona lafo ni nai paita i luga o le upega tafailagi. A uma ona talepeina i ni vaega, e mafai ona e auina atu fasipepa taitasi i se websocket. Code:

Matou te faʻapipiʻiina le ata vitio, vaevae i ni vaega

<style>
  #videoObjectHtml5ApiServer { width: 320px; height: 240px; background: #666; }
</style>
</head>
<body>
<!-- Здесь в этом "окошечке" клиент будет видеть себя -->
<video autoplay id="videoObjectHtml5ApiServer"></video>

<script type="application/javascript">
  var
        video = document.getElementById('videoObjectHtml5ApiServer');

// если доступен MediaDevices API, пытаемся получить доступ к камере (можно еще и к микрофону)
// getUserMedia вернет обещание, на которое подписываемся и полученный видеопоток в колбеке направляем в video объект на странице

if (navigator.mediaDevices.getUserMedia) {
        navigator.mediaDevices.getUserMedia({video: true}).then(function (stream) {
          // видео поток привязываем к video тегу, чтобы клиент мог видеть себя и контролировать 
          video.srcObject = s;
          var
            recorderOptions = {
                mimeType: 'video/webm; codecs=vp8' // будем кодировать видеопоток в формат webm кодеком vp8
              },
              mediaRecorder = new MediaRecorder(s, recorderOptions ); // объект MediaRecorder

               mediaRecorder.ondataavailable = function(e) {
                if (e.data && e.data.size > 0) {
                  // получаем кусочек видеопотока в e.data
                }
            }

            mediaRecorder.start(100); // делит поток на кусочки по 100 мс каждый

        });
}
</script>

Se'i o tatou fa'aopoopo le fa'asalalauga e ala i sockets. O le mea e ofo ai, pau lava le mea e te manaʻomia mo lenei mea o se mea Upega Tafaʻilagi. E na'o le lua auala e lafo ma tapunia. O igoa e tautala mo i latou lava. Fa'ailoga fa'aopoopo:

Matou te lafoina le ata vitio i le server

<style>
  #videoObjectHtml5ApiServer { width: 320px; height: 240px; background: #666; }
</style>
</head>
<body>
<!-- Здесь в этом "окошечке" клиент будет видеть себя -->
<video autoplay id="videoObjectHtml5ApiServer"></video>

<script type="application/javascript">
  var
        video = document.getElementById('videoObjectHtml5ApiServer');

// если доступен MediaDevices API, пытаемся получить доступ к камере (можно еще и к микрофону)
// getUserMedia вернет обещание, на которое подписываемся и полученный видеопоток в колбеке направляем в video объект на странице

if (navigator.mediaDevices.getUserMedia) {
        navigator.mediaDevices.getUserMedia({video: true}).then(function (stream) {
          // видео поток привязываем к video тегу, чтобы клиент мог видеть себя и контролировать 
          video.srcObject = s;
          var
            recorderOptions = {
                mimeType: 'video/webm; codecs=vp8' // будем кодировать видеопоток в формат webm кодеком vp8
              },
              mediaRecorder = new MediaRecorder(s, recorderOptions ), // объект MediaRecorder
              socket = new WebSocket('ws://127.0.0.1:3000/ws');

               mediaRecorder.ondataavailable = function(e) {
                if (e.data && e.data.size > 0) {
                  // получаем кусочек видеопотока в e.data
                 socket.send(e.data);
                }
            }

            mediaRecorder.start(100); // делит поток на кусочки по 100 мс каждый

        }).catch(function (err) { console.log(err); });
}
</script>

Ua saunia le itu faasalalau! Se'i o tatou taumafai e maua se ata vitio ma fa'aali i luga ole kalani. O le a le mea tatou te manaʻomia mo lenei mea? Muamua, ioe, le socket socket. Matou te faʻapipiʻi se "faʻalogo" i le mea WebSocket ma faʻapipiʻi i le 'feʻau' mea na tupu. O le mauaina o se vaega o faʻamaumauga binary, e faʻasalalau e le matou 'auʻaunaga i le au fai saofaga, o lona uiga, tagata faʻatau. I lenei tulaga, o le galuega toe foʻi e fesoʻotaʻi ma le "faʻalogo" o le 'feʻau' mea na tupu e faʻaosoina i luga o le kalani; o le mea lava ia e pasi atu i le finauga o galuega - o se vaega o le ata vitio ua faʻapipiʻiina e vp8.

Matou te talia ata vitio

<style>
  #videoObjectHtml5ApiServer { width: 320px; height: 240px; background: #666; }
</style>
</head>
<body>
<!-- Здесь в этом "окошечке" клиент будет видеть тебя -->
<video autoplay id="videoObjectHtml5ApiServer"></video>

<script type="application/javascript">
  var
        video = document.getElementById('videoObjectHtml5ApiServer'),
         socket = new WebSocket('ws://127.0.0.1:3000/ws'), 
         arrayOfBlobs = [];

         socket.addEventListener('message', function (event) {
                // "кладем" полученный кусочек в массив 
                arrayOfBlobs.push(event.data);
                // здесь будем читать кусочки
                readChunk();
            });
</script>

Mo se taimi umi sa ou taumafai e malamalama pe aisea e le mafai ai ona vave auina atu fasipepa na maua i le elemene vitio mo le toe taʻalo, ae na foliga mai e le mafai ona faia lenei mea, ioe, e tatau ona e tuʻu muamua le fasi pepa i totonu o se pa puipui faʻapitoa e fusifusia i. le elemene vitio, ona faatoa amata ai lea ona taina le ata vitio. Mo lenei mea e te manaʻomia MediaSource API и FileReader API.

MediaSource e galue o se ituaiga tagata faufautua i le va o le mea e toe faʻafoʻi ai le aufaasālalau ma le puna o lenei ala faʻasalalau. O le MediaSource meafaitino o loʻo i ai se paʻu faʻapipiʻi mo le puna o le ata vitio/leo. O se tasi o vaega o le paʻu e mafai ona naʻo le Uint8 faʻamaumauga, o lea e te manaʻomia ai se FileReader e fatu ai sea paʻu. Vaʻai i le code ma o le a sili atu ona manino:

Ta'alo le ata vitio

<style>
  #videoObjectHtml5ApiServer { width: 320px; height: 240px; background: #666; }
</style>
</head>
<body>
<!-- Здесь в этом "окошечке" клиент будет видеть тебя -->
<video autoplay id="videoObjectHtml5ApiServer"></video>

<script type="application/javascript">
  var
        video = document.getElementById('videoObjectHtml5ApiServer'),
         socket = new WebSocket('ws://127.0.0.1:3000/ws'),
        mediaSource = new MediaSource(), // объект MediaSource
        vid2url = URL.createObjectURL(mediaSource), // создаем объект URL для связывания видеопотока с проигрывателем
        arrayOfBlobs = [],
        sourceBuffer = null; // буфер, пока нуль-объект

         socket.addEventListener('message', function (event) {
                // "кладем" полученный кусочек в массив 
                arrayOfBlobs.push(event.data);
                // здесь будем читать кусочки
                readChunk();
            });

         // как только MediaSource будет оповещен , что источник готов отдавать кусочки 
        // видео/аудио потока
        // создаем буфер , следует обратить внимание, что буфер должен знать в каком формате 
        // каким кодеком был закодирован поток, чтобы тем же способом прочитать видеопоток
         mediaSource.addEventListener('sourceopen', function() {
            var mediaSource = this;
            sourceBuffer = mediaSource.addSourceBuffer("video/webm; codecs="vp8"");
        });

      function readChunk() {
        var reader = new FileReader();
        reader.onload = function(e) { 
          // как только FileReader будет готов, и загрузит себе кусочек видеопотока
          // мы "прицепляем" перекодированный в Uint8Array (был Blob) кусочек в буфер, связанный
          // с проигрывателем, и проигрыватель начинает воспроизводить полученный кусочек видео/аудио
          sourceBuffer.appendBuffer(new Uint8Array(e.target.result));

          reader.onload = null;
        }
        reader.readAsArrayBuffer(arrayOfBlobs.shift());
      }
</script>

Ua saunia le fa'ata'ita'iga o le auaunaga fa'a'aola. O le faʻaletonu autu o le toe faʻafoʻiina o ata vitio o le a tuʻu i tua o le itu faʻasalalau e 100 ms; matou te setiina i matou lava pe a vaeluaina le ata vitio ae leʻi tuʻuina atu i le server. E le gata i lea, ina ua ou siaki i luga o laʻu komepiuta, o le lag i le va o le felauaiga ma le mauaina o itu na faasolosolo malie lava ona faʻaputuina, o lenei mea na manino le iloa. Na amata ona ou sailia ni auala e foia ai lenei tulaga le lelei, ma ... na oo mai RTCPeerConnection API, lea e mafai ai ona e faʻasalalauina se ata vitio e aunoa ma ni togafiti e pei o le vaevaeina o le vaitafe i ni vaega. O le faʻaputuina o le lag, ou te manatu, e mafua ona o le mea moni e toe faʻapipiʻi e le browser vaega taʻitasi i le webm format aʻo leʻi faʻasalalau. Ou te leʻi toe eliina, ae na amata ona ou suʻesuʻeina WebRTC. Ou te manatu o le a ou tusia se isi tala e uiga i taunuuga o laʻu suʻesuʻega pe afai ou te fiafia i le alalafaga.

puna: www.habr.com

Faaopoopo i ai se faamatalaga