WebRTC videochat through Websockets - javascript

I'm trying to develop a video-chat application using webRTC and WebSockets for signaling.
My problem is that I don't know exactly what is the process of creating RTCPeerConnection and connect both peers(2 browsers) through webSocket(Locally at least).
I know how to communicate clients though WebSockets, but not with the RTCPeerConnection API, you know any tutorial step-by-step explaining the process?(Offer SDP, answers, ICE, ...) and, on the other hand, how looks the server code to managing these clients through RTCPeerConnection?
Here is my Node.js code for the server
"use strict";
// Optional. You will see this name in eg. 'ps' or 'top' command
process.title = 'node-webrtc';
// Port where we'll run the websocket server
var webSocketsServerPort = 1337;
// websocket and http servers
var webSocketServer = require('websocket').server;
var http = require('http');
/* ---------------------------------
GLOBAL VARIABLES
----------------------------------*/
// latest 100 messages
//var history = [ ];
// list of currently connected clients (users)
var clients = [ ];
/* ---------------------------------
HTTP SERVER
----------------------------------*/
var server = http.createServer(function(request, response) {
// Not important for us. We're writing WebSocket server, not HTTP server
});
server.listen(webSocketsServerPort, function() {
console.log((new Date()) + " Server is listening on port " + webSocketsServerPort);
});
/* ---------------------------------
WEBSOCKET SERVER
----------------------------------*/
var wsServer = new webSocketServer({
// WebSocket server is tied to a HTTP server. WebSocket request is just
// an enhanced HTTP request. For more info http://tools.ietf.org/html/rfc6455#page-6
httpServer: server
});
// This callback function is called every time someone
// tries to connect to the WebSocket server
wsServer.on('request', function(request) {
console.log((new Date()) + ' Connection from origin ' + request.origin + '.');
// accept connection - you should check 'request.origin' to make sure that
// client is connecting from your website
// (http://en.wikipedia.org/wiki/Same_origin_policy)
var connection = request.accept(null, request.origin);
// we need to know client index to remove them on 'close' event
var index = clients.push(connection) - 1;
console.log((new Date()) + ' Connection accepted.');
// user sent some message
connection.on('message', function(message) {
for (var i=0; i < clients.length; i++) {
clients[i].sendUTF(message);
}
});
// user disconnected
connection.on('close', function(conn) {
console.log((new Date()) + " Peer " + conn.remoteAddress + " disconnected.");
// remove user from the list of connected clients
clients.splice(index, 1);
});
});

You might want to have a look at the codelab I did for Google I/O: bitbucket.org/webrtc/codelab.
Step 5 shows how to set up a signaling server using socket.io, and Step 6 puts this together with RTCPeerConnection to make a simple video chat app.
You might also want to have a look at easyRTC (full stack) and Signalmaster (signaling server created for SimpleWebRTC).
The 'canonical' WebRTC video chat example at apprtc.appspot.com uses XHR and the Google App Engine Channel API for signaling.

Have you looked at or come across WebRTC.io? It is an opensource GitHub project that utilizes Node.js and websockets to do the exact thing you are talking about. I, not being much of a javascript person, was able to figure out what it was doing within a week. It isn't a step by step instruction, but anyone with javascript experience would be able to figure out the function call order.
There are two bits to the code: the server side and the client side. The server side is run with Node.js, and serves up the client side code to the browser. If I remember correctly, since the two projects are separate, if you want to combine them you will have to copy the webrtcio.js file from the client side and paste it into the server side folder. Although, I think if you clone the github repository right, you might not have to worry about that.

Related

How can I send data to a specific socket?

My problem is that the current solution I have for sending a specific socket using the library "ws" with node.js is not good enough.
The reason is because if I connect with multiple tabs to the websocket server with the same userid which is defined on the client-side, it will only refer to the latest connection with the userid specified.
This is my code:
// Server libraries and configuration
var server = require("ws").Server;
var s = new server({ port: 5001});
// An array which I keep all websockets clients
var search = {};
s.on("connection", function(ws, req) {
ws.on("message", function(message){
// Here the server process the user information given from the client
message = JSON.parse(message);
if(message.type == "userinfo"){
ws.personName = message.data;
ws.id = message.id;
// Defining variable pointing to the unique socket
search[ws.id] = ws;
return;
}
})
})
As you can see, each time a socket with same id connects, it will refer to the latest one.
Example If you did not understand:
Client connect to server with ID: 1337
search[1337] defined as --> websocket 1
A new connection with same ID: 1337
search[1337] becomes instead a variable refering to websocket 2 instead
Websockets provide a means to create a low-latency network "socket" between a browser and a server.
Note that the client here is the browser, not a tab on a browser.
If you need to manage multiple user sessions between the browser and server, you'll need to write code to do it yourself.

Node.js HTTP and TCP Clients Connection

I am trying to create a system where I have a desktop client created in VB, and a browser based client, that can send messages to each other. I am using a Node.js server to handle the connections and messages.
This is the code of my Node.js server:
net = require('net')
// Supports multiple client chat application
// Keep a pool of sockets ready for everyone
// Avoid dead sockets by responding to the 'end' event
var sockets = [];
// Create a TCP socket listener
var s = net.Server(function (socket) {
// Add the new client socket connection to the array of
// sockets
sockets.push(socket);
// 'data' is an event that means that a message was just sent by the
// client application
socket.on('data', function (msg_sent) {
// Loop through all of our sockets and send the data
for (var i = 0; i < sockets.length; i++) {
// Don't send the data back to the original sender
if (sockets[i] == socket) // don't send the message to yourself
continue;
// Write the msg sent by chat client
sockets[i].write(msg_sent);
}
});
// Use splice to get rid of the socket that is ending.
// The 'end' event means tcp client has disconnected.
socket.on('end', function () {
var i = sockets.indexOf(socket);
sockets.splice(i, 1);
});
});
s.listen(8000);
console.log('System waiting at http://localhost:8000');
With this sever, I am able to send messages between two desktop clients successfully.
However, because I am using net and not HTTP I cannot get the browser based client to connect.
How can I get both the clients to connect? I would really appreciate any help/suggestions/directions. I have been searching everywhere for about 4 days now! TIA!
You could use http or express for browser based client. could check socket.io also which works on http port.
I would try to help more if know type of the desktop client you are using.

Reassemble udp messages with node.js

I'm just getting started with node.js and UDP. I'm trying to capture UDP packets and then format the output.
The UDP packet's I'm receiving are being split up in to multiple messages. I can't figure out how to reassemble the message. I can concatenate each message, but how do I know that the message is complete? I need to process that data but I need to complete message.
FYI... This is for a scoreboard type application. The statistics are being broadcast via UDP and I'm trying to create an application that will monitor the stats.
Here is some basic code
var dgram = require("dgram");
var server = dgram.createSocket("udp4");
var fs = require('fs');
var STATS;
server.on("message", function (msg, rinfo) {
STATS = STATS + msg;
msg = msg + '<!>';
console.log(msg);
});
// *****************************
// When the message is complete
// Process STATS
// *****************************
server.on("listening", function () {
var address = server.address();
console.log("server listening " +
address.address + ":" + address.port);
});
server.bind(10101);
// server listening 0.0.0.0:41234
Do you have control over the client? If so, you can simply have some sort of symbol that identifies the end of a message, and your program can detect if msg ends with that.
But UDP sockets are volatile - there is no guarantee that any message will actually arrive. There is also no guarantee that your datagrams will arrive in the order that you send them. Correcting for these issues is more complex - if you don't need the real-time requirement, then switching to TCP is much easier.
TCP will automatically split your data into chunks when you send it from the client, so you will need to use that same end-of-message system, or detect when the socket is closed.

Sending message to a specific connected users using webSocket?

I wrote a code for broadcasting a message to all users:
// websocket and http servers
var webSocketServer = require('websocket').server;
...
...
var clients = [ ];
var server = http.createServer(function(request, response) {
// Not important for us. We're writing WebSocket server, not HTTP server
});
server.listen(webSocketsServerPort, function() {
...
});
var wsServer = new webSocketServer({
// WebSocket server is tied to a HTTP server.
httpServer: server
});
// This callback function is called every time someone
// tries to connect to the WebSocket server
wsServer.on('request', function(request) {
...
var connection = request.accept(null, request.origin);
var index = clients.push(connection) - 1;
...
Please notice:
I don't have any user reference but only a connection .
All users connection are stored in an array.
Goal: Let's say that the Node.js server wants to send a message to a specific client (John). How would the NodeJs server know which connection John has? The Node.js server doesn't even know John. all it sees is the connections.
So, I believe that now, I shouldn't store users only by their connection, instead, I need to store an object, which will contain the userId and the connection object.
Idea:
When the page finishes loading (DOM ready) - establish a connection to the Node.js server.
When the Node.js server accept a connection - generate a unique string and send it to the client browser. Store the user connection and the unique string in an object. e.g. {UserID:"6", value: {connectionObject}}
At client side, when this message arrives - store it in a hidden field or cookie. (for future requests to the NodeJs server )
When the server wants to send a message to John:
Find john's UserID in the dictionary and send a message by the corresponding connection.
please notice there is no asp.net server code invloced here (in the message mechanism). only NodeJs .*
Question:
Is this the right way to go?
This is not only the right way to go, but the only way. Basically each connection needs a unique ID. Otherwise you won't be able to identify them, it's as simple as that.
Now how you will represent it it's a different thing. Making an object with id and connection properties is a good way to do that ( I would definitely go for it ). You could also attach the id directly to connection object.
Also remember that if you want communication between users, then you have to send target user's ID as well, i.e. when user A wants to send a message to user B, then obviously A has to know the ID of B.
Here's a simple chat server private/direct messaging.
package.json
{
"name": "chat-server",
"version": "0.0.1",
"description": "WebSocket chat server",
"dependencies": {
"ws": "0.4.x"
}
}
server.js
var webSocketServer = new (require('ws')).Server({port: (process.env.PORT || 5000)}),
webSockets = {} // userID: webSocket
// CONNECT /:userID
// wscat -c ws://localhost:5000/1
webSocketServer.on('connection', function (webSocket) {
var userID = parseInt(webSocket.upgradeReq.url.substr(1), 10)
webSockets[userID] = webSocket
console.log('connected: ' + userID + ' in ' + Object.getOwnPropertyNames(webSockets))
// Forward Message
//
// Receive Example
// [toUserID, text] [2, "Hello, World!"]
//
// Send Example
// [fromUserID, text] [1, "Hello, World!"]
webSocket.on('message', function(message) {
console.log('received from ' + userID + ': ' + message)
var messageArray = JSON.parse(message)
var toUserWebSocket = webSockets[messageArray[0]]
if (toUserWebSocket) {
console.log('sent to ' + messageArray[0] + ': ' + JSON.stringify(messageArray))
messageArray[0] = userID
toUserWebSocket.send(JSON.stringify(messageArray))
}
})
webSocket.on('close', function () {
delete webSockets[userID]
console.log('deleted: ' + userID)
})
})
Instructions
To test it out, run npm install to install ws. Then, to start the chat server, run node server.js (or npm start) in one Terminal tab. Then, in another Terminal tab, run wscat -c ws://localhost:5000/1, where 1 is the connecting user's user ID. Then, in a third Terminal tab, run wscat -c ws://localhost:5000/2, and then, to send a message from user 2 to 1, enter ["1", "Hello, World!"].
Shortcomings
This chat server is very simple.
Persistence
It doesn't store messages to a database, such as PostgreSQL. So, the user you're sending a message to must be connected to the server to receive it. Otherwise, the message is lost.
Security
It is insecure.
If I know the server's URL and Alice's user ID, then I can impersonate Alice, ie, connect to the server as her, allowing me to receive her new incoming messages and send messages from her to any user whose user ID I also know. To make it more secure, modify the server to accept your access token (instead of your user ID) when connecting. Then, the server can get your user ID from your access token and authenticate you.
I'm not sure if it supports a WebSocket Secure (wss://) connection since I've only tested it on localhost, and I'm not sure how to connect securely from localhost.
For people using ws version 3 or above. If you want to use the answer provided by #ma11hew28, simply change this block as following.
webSocketServer.on('connection', function (webSocket) {
var userID = parseInt(webSocket.upgradeReq.url.substr(1), 10)
webSocketServer.on('connection', function (webSocket, req) {
var userID = parseInt(req.url.substr(1), 10)
ws package has moved upgradeReq to request object and you can check the following link for further detail.
Reference: https://github.com/websockets/ws/issues/1114
I would like to share what I have done. Hope it doesn't waste your time.
I created database table holding field ID, IP, username, logintime and logouttime. When a user logs in logintime will be currect unixtimestamp unix. And when connection is started in websocket database checks for largest logintime. It will be come user logged in.
And for when user logs out it will store currect logouttime. The user will become who left the app.
Whenever there is new message, Websocket ID and IP are compared and related username will be displayed. Following are sample code...
// when a client connects
function wsOnOpen($clientID) {
global $Server;
$ip = long2ip( $Server->wsClients[$clientID][6] );
require_once('config.php');
require_once CLASSES . 'class.db.php';
require_once CLASSES . 'class.log.php';
$db = new database();
$loga = new log($db);
//Getting the last login person time and username
$conditions = "WHERE which = 'login' ORDER BY id DESC LIMIT 0, 1";
$logs = $loga->get_logs($conditions);
foreach($logs as $rows) {
$destination = $rows["user"];
$idh = md5("$rows[user]".md5($rows["time"]));
if ( $clientID > $rows["what"]) {
$conditions = "ip = '$ip', clientID = '$clientID'
WHERE logintime = '$rows[time]'";
$loga->update_log($conditions);
}
}
...//rest of the things
}
interesting post (similar to what I am doing).
We are making an API (in C#) to connect dispensers with WebSockets, for each dispenser we create a ConcurrentDictionary that stores the WebSocket and the DispenserId making it easy for each Dispenser to create a WebSocket and use it afterwards without thread problems (invoking specific functions on the WebSocket like GetSettings or RequestTicket).
The difference for you example is the use of ConcurrentDictionary instead of an array to isolate each element (never attempted to do such in javascript).
Best regards,

Node.js WebSocket Broadcast

I'm using the ws library for WebSockets in Node.js and
I'm trying this example from the library examples:
var sys = require("sys"),
ws = require("./ws");
ws.createServer(function (websocket) {
websocket.addListener("connect", function (resource) {
// emitted after handshake
sys.debug("connect: " + resource);
// server closes connection after 10s, will also get "close" event
setTimeout(websocket.end, 10 * 1000);
}).addListener("data", function (data) {
// handle incoming data
sys.debug(data);
// send data to client
websocket.write("Thanks!");
}).addListener("close", function () {
// emitted when server or client closes connection
sys.debug("close");
});
}).listen(8080);
All OK. It works, but running 3 clients, for instance, and sending "Hello!" from one will make the server only reply "Thanks!" to the client which sent the message, not to all.
How can I broadcast "Thanks!" to all connected clients when someone sends "Hello!"?
Thanks!
If you want to send out to all clients, you have to keep track of them. Here is a sample:
var sys = require("sys"),
ws = require("./ws");
// # Keep track of all our clients
var clients = [];
ws.createServer(function (websocket) {
websocket.addListener("connect", function (resource) {
// emitted after handshake
sys.debug("connect: " + resource);
// # Add to our list of clients
clients.push(websocket);
// server closes connection after 10s, will also get "close" event
// setTimeout(websocket.end, 10 * 1000);
}).addListener("data", function (data) {
// handle incoming data
sys.debug(data);
// send data to client
// # Write out to all our clients
for(var i = 0; i < clients.length; i++) {
clients[i].write("Thanks!");
}
}).addListener("close", function () {
// emitted when server or client closes connection
sys.debug("close");
for(var i = 0; i < clients.length; i++) {
// # Remove from our connections list so we don't send
// # to a dead socket
if(clients[i] == websocket) {
clients.splice(i);
break;
}
}
});
}).listen(8080);
I was able to get it to broadcast to all clients, but it's not heavily tested for all cases. The general concept should get you started though.
EDIT: By the way I'm not sure what the 10 second close is for so I've commented it out. It's rather useless if you're trying to broadcast to all clients since they'll just keep getting disconnected.
I would recommend you to use socket.io. It has example web-chat functionality out of the box and also provides abstraction layer from the socket technology on client (WebSockets are supported by Safari, Chrome, Opera and Firefox, but disabled in Firefox and Opera now due to security vulnerabilities in ws-protocol).

Categories

Resources