You can use any signaling implementation with any WebRTC Experiment; whether it is XMPP/SIP or PHP/MySQL or Socket.io/WebSockets or WebSync/SignalR or PeerServer/SignalMaster or other gateway.
=
Your server side code can be as simple as possible like this:
io.sockets.on('connection', function (socket) {
socket.on('message', function (data) {
socket.broadcast.emit('message', data);
});
});
You can even use existing services like (for server side code only!):
- https://github.com/andyet/signalmaster
- https://github.com/peers/peerjs-server
- https://github.com/SignalR/SignalR
- http://millermedeiros.github.io/js-signals/
- https://github.com/sockjs/sockjs-client
=
There are dozens of WebRTC Experiments and Libraries; you can use any existing signaling server with any WebRTC Experiment/Library!
You just need to understand how signaling is implemented in WebRTC Experiments:
- All WebRTC Experiments has
openSocket
method; that can be defined in the HTML page; which allows you override/use any signaling implementation there! - All WebRTC Libraries has a public method i.e.
openSignalingChannel
; which can also be overridden/defined in the HTML page; also you can override it to easily use any signaling implementation exists out there!
Now you understood how default implementations can be overridden; it is time to understand how to override for any signaling implementation exists out there!
=
This array-like object will store onmessage
callbacks.
var onMessageCallbacks = {};
var websocket = new WebSocket('wss://something:port/');
var socket = io.connect('https://domain:port/');
var firebase = new Firebase('https://user.firebaseio.com/' + connection.channel);
For socket.io; you can pass default channel as URL parameter:
var socket = io.connect('https://domain:port/?channel=' + connection.channel);
Capture server messages:
websocket.onmessage = function (event) {
onMessageCallBack(event.data);
};
socket.on('message', function (data) {
onMessageCallBack(data);
});
firebase.on('child_added', function (snap) {
onMessageCallBack(snap.val());
snap.ref().remove(); // for socket.io live behaviour
});
and onMessageCallBack
:
function onMessageCallBack(data) {
data = JSON.parse(e.data);
if (data.sender == connection.userid) return;
if (onMessageCallbacks[data.channel]) {
onMessageCallbacks[data.channel](data.message);
};
}
connection.openSignalingChannel = function (config) {
var channel = config.channel || this.channel;
onMessageCallbacks[channel] = config.onmessage;
if (config.onopen) setTimeout(config.onopen, 1000);
return {
send: function (message) {
websocket.send(JSON.stringify({
sender: connection.userid,
channel: channel,
message: message
}));
},
channel: channel
};
};
Read more here.
=
openSignalingChannel
for RTCMultiConnection.js and DataChanel.js (Client-Side Code)
Putting above 4-steps together! Here is your browser side code that overrides default signaling implementations:
var onMessageCallbacks = {};
var socketio = io.connect('http://localhost:8888/');
socketio.on('message', function(data) {
if(data.sender == connection.userid) return;
if (onMessageCallbacks[data.channel]) {
onMessageCallbacks[data.channel](data.message);
};
});
connection.openSignalingChannel = function (config) {
var channel = config.channel || this.channel;
onMessageCallbacks[channel] = config.onmessage;
if (config.onopen) setTimeout(config.onopen, 1000);
return {
send: function (message) {
socketio.emit('message', {
sender: connection.userid,
channel: channel,
message: message
});
},
channel: channel
};
};
=
var onMessageCallbacks = {};
var currentUserUUID = Math.round(Math.random() * 60535) + 5000;
var socketio = io.connect('http://localhost:8888/');
socketio.on('message', function(data) {
if(data.sender == currentUserUUID) return;
if (onMessageCallbacks[data.channel]) {
onMessageCallbacks[data.channel](data.message);
};
});
var config = {
openSocket = function (config) {
var channel = config.channel || 'main-channel';
onMessageCallbacks[channel] = config.onmessage;
if (config.onopen) setTimeout(config.onopen, 1000);
return {
send: function (message) {
socketio.emit('message', {
sender: currentUserUUID,
channel: channel,
message: message
});
},
channel: channel
};
}
};
=
// global stuff
var onMessageCallbacks = {};
var currentUserUUID = Math.round(Math.random() * 60535) + 5000;
var websocket = new WebSocket('ws://localhost:8888/');
websocket.onmessage = function(e) {
data = JSON.parse(e.data);
if(data.sender == currentUserUUID) return;
if (onMessageCallbacks[data.channel]) {
onMessageCallbacks[data.channel](data.message);
};
};
// overriding "openSignalingChannel" method
connection.openSignalingChannel = function (config) {
var channel = config.channel || this.channel;
onMessageCallbacks[channel] = config.onmessage;
if (config.onopen) setTimeout(config.onopen, 1000);
return {
send: function (message) {
websocket.send(JSON.stringify({
sender: currentUserUUID,
channel: channel,
message: message
}));
},
channel: channel
};
};
=
- The object returned by overridden
openSignalingChannel
oropenSocket
method MUST return an object with two things: i.send
method. Used to send data via signaling gateway. ii.channel
object. Used for video-conferencing. If you skip it; it will make one-to-many instead of many-to-many. onmessage
oron('message', callback)
MUST have same code as you can see a few lines above.
You don't need to do anything else on your signaling server. You'll NEVER be asked to modify your existing signaling implementations! Just use existing stuff and enjoy WebRTC experiments!
=
How to use WebSync for Signaling?
<script src="fm.js"> </script>
<script src="fm.websync.js"> </script>
<script src="fm.websync.subscribers.js"> </script>
<script src="fm.websync.chat.js"> </script>
// www.RTCMultiConnection.org/latest.js
var connection = new RTCMultiConnection();
// ------------------------------------------------------------------
// start-using WebSync for signaling
var onMessageCallbacks = {};
var username = Math.round(Math.random() * 60535) + 5000;
var client = new fm.websync.client('websync.ashx');
client.setAutoDisconnect({
synchronous: true
});
client.connect({
onSuccess: function () {
client.join({
channel: '/chat',
userId: username,
userNickname: username,
onReceive: function (event) {
var message = JSON.parse(event.getData().text);
if (onMessageCallbacks[message.channel]) {
onMessageCallbacks[message.channel](message.message);
}
}
});
}
});
connection.openSignalingChannel = function (config) {
var channel = config.channel || this.channel;
onMessageCallbacks[channel] = config.onmessage;
if (config.onopen) setTimeout(config.onopen, 1000);
return {
send: function (message) {
client.publish({
channel: '/chat',
data: {
username: username,
text: JSON.stringify({
message: message,
channel: channel
})
}
});
}
};
};
// end-using WebSync for signaling
// ------------------------------------------------------------------
// check existing sessions
connection.connect();
// open new session
document.getElementById('open-new-session').onclick = function() {
connection.open();
};
=
First Step: Create Hub class:
public class WebRtcHub3: Hub {
public void Send(string message) {
Clients.All.onMessageReceived(message);
}
}
Second Step: Client side stuff:
var onMessageCallbacks = {};
var connection = new RTCMultiConnection();
var hub = $.connection.webRtcHub3;
$.support.cors = true;
$.connection.hub.url = '/signalr/hubs';
hub.client.onMessageReceived = function (message) {
var message = JSON.parse(message);
if (onMessageCallbacks[message.channel]) {
onMessageCallbacks[message.channel](message.message);
}
};
// start the hub
$.connection.hub.start();
Third Step: Overriding openSignalingChannel
method:
connection.openSignalingChannel = function (config) {
var channel = config.channel || this.channel;
onMessageCallbacks[channel] = config.onmessage;
if (config.onopen) setTimeout(config.onopen, 1000);
return {
send: function (message) {
message = JSON.stringify({
message: message,
channel: channel
});
hub.server.send(message);
}
};
};
=
new window.Firebase('https://chat.firebaseIO.com/' + sessionid).once('value', function (data) {
var isRoomPresent = data.val() != null;
if (!isRoomPresent) connection.open(sessionid);
else connection.connect(sessionid);
console.debug('room is present?', isRoomPresent);
});
or for RTCMultiConnectionjs or DataChaneljs:
new window.Firebase('//' + rtcMultiConnection.firebase + '.firebaseIO.com/' + rtcMultiConnection.channel).once('value', function (data) {
var isRoomPresent = data.val() != null;
if (!isRoomPresent) {
rtcMultiConnection.open();
} else {
rtcMultiConnection.connect();
}
});
function testChannelPresence(channel) {
var socket = io.connect('/');
socket.on('presence', function (isChannelPresent) {
console.log('is channel present', isChannelPresent);
if (!isChannelPresent) playRoleOfSessionInitiator();
});
socket.emit('presence', channel);
}
testChannelPresence('default-channel');
Socket.io over Node.js demos can be found here.
=
You can find many other good examples here:
http://www.RTCMultiConnection.org/docs/openSignalingChannel/
=
- https://www.webrtc-experiment.com/docs/WebRTC-Signaling-Concepts.html
- http://www.RTCMultiConnection.org/FAQ/
- http://www.RTCMultiConnection.org/docs/sessionid/
- http://www.RTCMultiConnection.org/docs/channel-id/
=
WebRTC Experiments are released under MIT licence . Copyright (c) 2013 Muaz Khan.