Live Video Stream on a Node.js Server

joshy.poo picture joshy.poo · Mar 15, 2017 · Viewed 44.5k times · Source

I have been researching this a lot but am frustrated as I feel like the solution should be simple though I know wont be. Ideally i'd just want to use node to host the server, webrtc getusermedia to get the live stream on the local client and use something like socket.io to send the stream to the server and then the server would broadcast the stream to the remote client; as if it was a simple messaging chat app.

Just thinking about this some more it seems as an approach this simple would be impossible because a live video requires continuous large amounts of data to be sent, which does not equate to sending a single message or even file after an event (send button pressed).

Maybe I am wrong however, can a live video stream app follow the same structure of a node/socket.io messenger app? Would you send the media object returned from getUserMedia, the blob, some binary data some how (I've tried all of these but perhaps not correctly).

The ideal goal would be an app that uses as little extra fluff as necessary, as little npm installs, as little extra javascript libraries, or little worrying about encoding/decoding or whatever the hell ICE or STUN are. Is there any way this is possible or am I asking for too much?

Ideal Client

    var socket = io();
    var local = document.getElementById("local_video");
    var remote = document.getElementById("remote_video");

    // display local video
    navigator.mediaDevices.getUserMedia({video: true, audio: true}).then(function(stream) {
      local.src = window.URL.createObjectURL(stream);
      socket.emit("stream", stream);
    }).catch(function(err){console.log(err);});

    // displays remote video
    socket.on("stream", function(stream){
      remote.src = window.URL.createObjectURL(stream);

    });

Ideal Server

var app = require("express")();
var http = require("http").Server(app);
var fs = require("fs");
var io = require("socket.io")(http);

app.get('/', onRequest);
http.listen(process.env.PORT || 3000, function() {
    console.log('server started');
})

//404 response
function send404(response) {
    response.writeHead(404, {"Content-Type" : "text/plain"});
    response.write("Error 404: Page not found");
    response.end();
}

function onRequest(request, response) {
  if(request.method == 'GET' && request.url == '/') {
    response.writeHead(200, {"Content-Type" : "text/html"});
    fs.createReadStream("./index.html").pipe(response);
  } else {
    send404(response);
  }
}

io.on('connection', function(socket) {
  console.log("a user connected");
  socket.on('stream', function(stream) {
    socket.broadcast.emit("stream", stream);
  });
  socket.on('disconnect', function () {
    console.log("user disconnected");
  });
});

This is the broken app in action : https://nodejs-videochat.herokuapp.com/

This is the broken code on github: https://github.com/joshydotpoo/nodejs-videochat

Answer

Gaurav Chaudhary picture Gaurav Chaudhary · Mar 15, 2017

Try to be clear and specific. First, you are not using WebRTC here. getUserMedia() is a part of navigator WebAPI which you are using to get media stream from the camera.

Using WebRTC means you are using ICE and STUN/TURN servers for the purpose of signaling. You will use your host server(Node) for specifying ICE configuration, identify each user and provide a way to call each other.

If you want to stream it through your host, probably you should stream it in chunks and set up your own signaling infrastructure. You can use Stream API with socket io to stream data in chunks(packets). See here Stream API(socket.io)

Also, you can check out the live example of WebRTC + Socket.io here: Socket.io | WebRTC Video Chat

You can find out more information here: sending a media stream to Host server