Search code examples
javascripthtmlwebwebrtcvideo-streaming

Is it possible to make a video call over websocket on the web without using WebRTC?


I want to stream video (with audio) over websocket in one direction without using STUN/TURN server. Is it possible to write such a web app?

Data will flow like this:

Peer A -> Websocket Server -> Peer B


Solution

  • Yes it is possible. if you ok 0.5 s latency
    streamer:

    navigator.mediaDevices.getUserMedia({video:true,audio:true}).then(stream=>{
    var ws,mediaRecorder;
    var options = {
            mimeType: "video/webm;codecs=opus, vp8",
            bitsPerSecond:5000 //quality
            };
    
    function handleVideo(){
      
        try{
            mediaRecorder.stop()
        }catch(e){}
        mediaRecorder=null;
        mediaRecorder = new MediaRecorder(stream,options);
        mediaRecorder.ondataavailable =function(e) {
    
            if(e.data&&e.data.size>0) {
                e.data.arrayBuffer().then(buffer=>{
                        ws.send(buffer)
                  })
            }
        }
        mediaRecorder.start(300);
       }
    
       function connect(){
        ws = new WebSocket("wss://yourwebsocket.com")
        ws.binaryType = "arraybuffer"
        ws.onopen=handleVideo
        ws.onmessage=handleVideo
        ws.onclose=connect
       }
    connect()
    
    })
    // so onmessage function neccessary for when someone join the socket stream again, because webm format need embl header
    

    watcher:

    var media,sourceBuffer,ws;
    var video = document.getElementById('yourvideoid')
    
    function handleStream(e){
        const buffer=e.data
        const data= new Uint8Array(buffer)
        
            if(data[0]===26&&data[1]===69&&data[2]===223){
                if(media){
                URL.revokeObjectURL(media)
                sourceBuffer=null;  
                     }
            
            media= new MediaSource();
            video.src = URL.createObjectURL(media);
            video.onloadedmetadata=function(){
                video.muted=false
                video.play()
            }
            
            media.onsourceopen=function(){
            sourceBuffer= media.addSourceBuffer("video/webm;codecs=opus, vp8");
            sourceBuffer.appendBuffer(buffer)
          }
        
            }
            
            else {
            if(!media)return;
            
                sourceBuffer.appendBuffer(buffer)
                
            }
    }
    function connect(){
        ws = new WebSocket("wss://yourwsserver.com")
        ws.binaryType = "arraybuffer"
        ws.onmessage=handleStream
        ws.onclose=connect
    }
    connect()
    // we fetch data from websocket then add data to video buffer
    

    nodejs server:

    const EventEmitter = require('events');
    const https = require('https');
    const {Server} = require('ws'); //npm i ws
    
    const emitter= new EventEmitter();
    const app = https.createServer(options,function (req, res) {})
    const wss = new Server({ server: app });
    
    
    wss.on('connection', (socket,req) => {
        var isStreamer=false
        socket.fn=function(e){socket.send(e)}
        const interval= setInterval(socket.ping, 5000);
        emitter.on('data',socket.fn)
        emitter.emit('refresh','0')    
    
        socket.on('message', (data) => {
            isStreamer||(emitter.on('refresh',socket.fn),emitter.off('data',socket.fn),(isStreamer=true))
            emitter.emit('data',data)
        });
    
        socket.on('close', () => {
            clearInterval(interval)
            emitter.off('data',socket.fn)
            emitter.off('refresh',socket.fn)
            
        })
        socket.on('ping',socket.pong)
        socket.on("error", (err) => {})
    });
    
    app.listen(PORT,'0.0.0.0')
    
    //u need to set option for https or use http instead