livecam.js
function SocketCamWrapper(
  gst_tcp_addr,
  gst_tcp_port,
  broadcast_tcp_addr,
  broadcast_tcp_port) {

  const Net = require('net');
  const Http = require('http');
  const Dicer = require('dicer');
  const Assert = require('assert');
  const SocketIO = require('socket.io');
  const gst_multipart_boundary = '--videoboundary';

  /*!
   * @fn wrap
   * @brief wraps a TCP server previously started by GstLiveCamServer.
   */
  var wrap = function(gst_tcp_addr,
    gst_tcp_port,
    broadcast_tcp_addr,
    broadcast_tcp_port) {
    Assert.ok(typeof(gst_tcp_addr), 'string');
    Assert.ok(typeof(gst_tcp_port), 'number');
    Assert.ok(typeof(broadcast_tcp_addr), 'string');
    Assert.ok(typeof(broadcast_tcp_port), 'number');

    var socket = Net.Socket();

    socket.connect(gst_tcp_port, gst_tcp_addr, function() {
      var io = SocketIO.listen(
        Http.createServer()
        .listen(broadcast_tcp_port, broadcast_tcp_addr));

      var dicer = new Dicer({
        boundary: gst_multipart_boundary
      });

      dicer.on('part', function(part) {
        var frameEncoded = '';
        part.setEncoding('base64');

        part.on('data', function(data) {
          frameEncoded += data;
        });
        part.on('end', function() {
          io.sockets.emit('image', frameEncoded);
        });
      });

      dicer.on('finish', function() {
        console.log('Dicer finished: ' + broadcast_tcp_addr + ':' + broadcast_tcp_port);
      });

      socket.on('close', function() {
        console.log('Socket closed: ' + broadcast_tcp_addr + ':' + broadcast_tcp_port);
      });

      socket.pipe(dicer);
    });
  }

  return {
    'wrap': wrap
  }
}
function SocketCamWrapper(
  gst_tcp_addr,
  gst_tcp_port,
  broadcast_tcp_addr,
  broadcast_tcp_port) {

  const Net = require('net');
  const Http = require('http');
  const Dicer = require('dicer');
  const Assert = require('assert');
  const SocketIO = require('socket.io');
  const gst_multipart_boundary = '--videoboundary';

  /*!
   * @fn wrap
   * @brief wraps a TCP server previously started by GstLiveCamServer.
   */
  var wrap = function(gst_tcp_addr,
    gst_tcp_port,
    broadcast_tcp_addr,
    broadcast_tcp_port) {
    Assert.ok(typeof(gst_tcp_addr), 'string');
    Assert.ok(typeof(gst_tcp_port), 'number');
    Assert.ok(typeof(broadcast_tcp_addr), 'string');
    Assert.ok(typeof(broadcast_tcp_port), 'number');

    var socket = Net.Socket();

    socket.connect(gst_tcp_port, gst_tcp_addr, function() {
      var io = SocketIO.listen(
        Http.createServer()
        .listen(broadcast_tcp_port, broadcast_tcp_addr));

      var dicer = new Dicer({
        boundary: gst_multipart_boundary
      });

      dicer.on('part', function(part) {
        var frameEncoded = '';
        part.setEncoding('base64');

        part.on('data', function(data) {
          frameEncoded += data;
        });
        part.on('end', function() {
          io.sockets.emit('image', frameEncoded);
        });
      });

      dicer.on('finish', function() {
        console.log('Dicer finished: ' + broadcast_tcp_addr + ':' + broadcast_tcp_port);
      });

      socket.on('close', function() {
        console.log('Socket closed: ' + broadcast_tcp_addr + ':' + broadcast_tcp_port);
      });

      socket.pipe(dicer);
    });
  }

  return {
    'wrap': wrap
  }
}
/*!
@class SocketCamWrapper
@brief A wrapper that re-broadcasts GStreamer's webcam TCP packets in
Socket.IO events. This way browsers can fetch and understand webcam
video frames.
@credit http://stackoverflow.com/a/23605892/388751