docs: function (config) {
  
      // check parameters
      if ((typeof config.IN_PORT !== 'number' && 
          typeof config.OUT_PORT !== 'number')) {
      
          LOG.warn('config needs to define parameters: IN_PORT or OUT_PORT');
          return; 
      }
  	
  	var server_type = config.type || 'MPEG';
  
      var STREAM_SECRET = config.secret;
  		IN_PORT = config.IN_PORT || 8082,
  		OUT_PORT = config.OUT_PORT || 8084,
  		STREAM_MAGSR_BYTES = 'jsmp'; // Must be 4 bytes
  		
  	// channel info
  	var l_channels = {};
          
      var socketServer = undefined;
      var streamServer = undefined;
  
      this.start = function () {
      
          // Websocket Server
          socketServer = new (require('ws').Server)({port: OUT_PORT});
  		
  		// process incoming connection of subscribers
          socketServer.on('connection', function (socket) {
  
  			// generate unique clientID
  			var clientID = UTIL.createUUID();
  			var clientData = socketServer.clients[socketServer.clients.length - 1];
  			
  			var channel = undefined;
  			LOG.sys( 'New WebSocket Connection (' + socketServer.clients.length + ' total) id: ' + clientID );
  					 
  			// we start to handle after receiving channel name to subscribe
  			// NOTE: the incoming content is not string type
  			socket.on('message', function (name) {
  
                  try {
   
                      /*
  					var obj = JSON.parse(name.data);
  					LOG.warn(obj);
  					*/
                      
  					// extract info
  					if (l_channels.hasOwnProperty(name) === false) {
  						var msg = 'no stream registered for channel [' + name + ']';
  						LOG.warn(msg);
  						socket.send(msg);
  						return;
  					}
  					
  					// record channel name
  					channel = name;
  					
  					// get parameters
  					var params = l_channels[channel].para;
  		        
  					// NOTE: we convert string to numbers with | 0			
  					var width = (params[0] || 320) | 0;
  					var height = (params[1] || 240) | 0;
  					
  					LOG.warn('params:');
  					LOG.warn(params);
  					LOG.warn('client to receive channel: ' + channel + ' w: ' + width + ' h: ' + height);
                  
  					// record this user's reference as part of the channel subscribers
  					// NOTE: we record clientData, not socket
  					l_channels[channel].users[clientID] = clientData;   
  					
  					LOG.warn('channel [' + channel + '] has ' + Object.keys(l_channels[channel].users).length + ' users', 'message');
  					
  					// Send back magic bytes and video size to the newly connected socket
  					// struct { char magic[4]; unsigned short width, height;}
  					var streamHeader = new Buffer(8);
  					streamHeader.write(STREAM_MAGSR_BYTES);
  					streamHeader.writeUInt16BE(width, 4);
  					streamHeader.writeUInt16BE(height, 6);
  					socket.send(streamHeader, {binary:true}); 
                  
                  }
                  catch(e) {
                      LOG.error(e);
                  }    
  			});
  			
  			// handles closing in-coming connection
  			socket.on('close', function (code, message) {
  				LOG.sys( 'Disconnected WebSocket (' + socketServer.clients.length + ' total)' );
  				
  				// remove user record (i.e., socket) from channel
  				if (l_channels.hasOwnProperty(channel)) {		
  					delete l_channels[channel].users[clientID];
  					LOG.warn('client [' + clientID + '] unsubscribe from channel [' + channel + ']');
  				}
  			});
          });
      
          socketServer.broadcast = function (channel, data, opts) {
  		
  			// go over all clients for a given channel
  			if (l_channels.hasOwnProperty(channel) === false) {
  				LOG.warn('channel [' + channel + '] not registered, cannot broadcast');
  				return;
  			}
  			//LOG.warn('channel [' + channel + '] has ' + Object.keys(l_channels[channel].users).length + ' users', 'broadcast');
  			
  			var clients = l_channels[channel].users;
  			
  			for (var id in clients) {
  				
  				try {
  					//this.clients[i].send(data, opts);
  					clients[id].send(data, opts);
  				}
  				catch(e) {
  					LOG.warn('client[' + id + '] fails to send to channel [' + channel + ']');
  				}
  			}
          };
      
          // HTTP Server to accept incoming MPEG Stream
          streamServer = require('http').createServer(function (request, response) {
  			var params = request.url.substr(1).split('/');			
  			var channel = params[0];
          
  			if (channel) {
  				LOG.sys(
  					'Stream Connected: ' + request.socket.remoteAddress + 
  					':' + request.socket.remotePort + ' channel: ' + channel
  				);
  				
  				//' size: ' + width + 'x' + height
  				
  				
  				// remove first element (channel name) and store the rest as parameters
  				params.splice(0, 1);
  				l_channels[channel] = {
  					para: params,		// app-specific parameters in string array format
  					users: {}			// user clients conneted awating message updates
  				}
  				
  				request.on('data', function(data) {
  					if (socketServer)
  						socketServer.broadcast(channel, data, {binary:true});
  				});
  			}
  			else {
  				LOG.sys(
  					'failed connection: '+ request.socket.remoteAddress + 
  					request.socket.remotePort + ' - no channel specified.'
  				);
  				response.end();
  			}
          }).listen(IN_PORT);
      
          LOG.warn('Listening for stream on http://'+ SR.Settings.SERVER_INFO.IP +':'+IN_PORT+'/<channel>/<para1>/<para2>/<para3>/...', 'SR.Stream');
          LOG.warn('Awaiting WebSocket connections on ws://' + SR.Settings.SERVER_INFO.IP + ':'+OUT_PORT+'/', 'SR.Stream');
      }
      
      this.stop = function () {
  
          if (socketServer) {
              socketServer.close();
          }
          
          if (streamServer) {
              streamServer.close();
          }
      }
      
  }