RTCMultiConnection Docs

RTCMultiConnection API Reference / "openSignalingChannel" method

"openSignalingChannel" is a simple "public" method which can be overwritten in any HTML page. This method is used to encapsulate all signaling stuff in single place.

Whatever signaling mechanism exists there, whether it is XMPP or SIP, or 3rd party services as Pusher/Firebase/PubNub etc, each and every service can easily be used for signaling using openSignalingChannel method.

Useful resources: https://github.com/muaz-khan/WebRTC-Experiment/blob/master/Signaling.md

Quick Video Presentation

RTCMultiConnection Videos Channel!

Using Single Socket for Signaling

var onMessageCallbacks = {};
var socket = io.connect('http://localhost:8888/');

socket.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) {
            socket.emit('message', {
                sender: connection.userid,
                channel: channel,
                message: message
            });
        },
        channel: channel
    };
};

Using Multiple Sockets for Signaling

// Note: for a working demo, try next section.

connection.openSignalingChannel = function (config) {
   var channel = config.channel || this.channel;
   
   var socket = io.connect('/?channel=' + channel);
   socket.channel = channel;
   
   socket.on('connect', function () {
      if (config.callback) config.callback(socket);
   });
   
   socket.send = function (message) {
        socket.emit('message', {
            sender: connection.userid,
            data  : message
        });
    };
   
   socket.on('message', config.onmessage);
};

Using Socket.io for Signaling

// http://socketio-over-nodejs.hp.af.cm/
// http://socketio-over-nodejs.jit.su:80/
// http://webrtc-signaling.jit.su:80/

var SIGNALING_SERVER = 'https://webrtc-signaling.nodejitsu.com/';
connection.openSignalingChannel = function (config) {
   var channel = config.channel || this.channel;
   var sender = Math.round(Math.random() * 9999999999) + 9999999999;

   io.connect(SIGNALING_SERVER).emit('new-channel', {
      channel: channel,
      sender : sender
   });

   var socket = io.connect(SIGNALING_SERVER + channel);
   socket.channel = channel;

   socket.on('connect', function () {
      if (config.callback) config.callback(socket);
   });

   socket.send = function (message) {
        socket.emit('message', {
            sender: sender,
            data  : message
        });
    };

   socket.on('message', config.onmessage);
};

Using WebSockets for Signaling

// wss://wsnodejs.nodejitsu.com:443 (Secure port: HTTPs)
// ws://wsnodejs.nodejitsu.com:80 (Ordinary port: HTTP)

var SIGNALING_SERVER = 'wss://wsnodejs.nodejitsu.com:443';
connection.openSignalingChannel = function (config) {
    config.channel = config.channel || this.channel;
    var websocket = new WebSocket(SIGNALING_SERVER);
    websocket.channel = config.channel;
    websocket.onopen = function() {
        websocket.push(JSON.stringify({
            open: true,
            channel: config.channel
        }));
        if (config.callback)
            config.callback(websocket);
    };
    websocket.onmessage = function(event) {
        config.onmessage(JSON.parse(event.data));
    };
    websocket.push = websocket.send;
    websocket.send = function(data) {
        websocket.push(JSON.stringify({
            data: data,
            channel: config.channel
        }));
    };
};

Using Firebase for Signaling

connection.openSignalingChannel = function (config) {
    config.channel = config.channel || this.channel;
    
    var socket = new Firebase('https://chat.firebaseIO.com/' + config.channel);
    socket.channel = config.channel;
    
    socket.on('child_added', function (data) {
        config.onmessage(data.val());
    });
    
    socket.send = function(data) {
        this.push(data);
    };
    
    config.onopen && setTimeout(config.onopen, 1);
    socket.onDisconnect().remove();
    return socket;
};

Using PubNub for Signaling

connection.openSignalingChannel = function (config) {
    config.channel = config.channel || this.channel;
    var socket = io.connect('https://pubsub.pubnub.com/' + config.channel, {
        publish_key: 'demo',
        subscribe_key: 'demo',
        channel: config.channel,
        ssl: true
    });
    socket.channel = config.channel;
    if (config.onopen) socket.on('connect', config.onopen);
    socket.on('message', config.onmessage);
    return socket;
};

Using Java for Signaling

// Java/Tomcat Server code
// via: https://www.webrtc-experiment.com/docs/WebRTC-Signaling-Concepts.html#comment-2341098344
// Thanks @(sunder tattavarada) 

import javax.websocket.OnMessage;

import javax.websocket.OnOpen;

import javax.websocket.Session;

import javax.websocket.server.ServerEndpoint;

import org.json.JSONException;

import org.json.JSONObject;

@ServerEndpoint("/webrtc")

public class WebRTCSocket {

    public static Map < string, hashtable < string, object[] >> sessionMap = new Hashtable < string, hashtable < string, object[] >> ();

    @OnMessage

    public void message(String message, Session session) {

        try {

            JSONObject jsonObject = new JSONObject(message);

            try {

                Object isOpen = jsonObject.get("open");

                if (isOpen != null && (Boolean) isOpen == true) {

                    String channel = (String) jsonObject.get("channel");

                    Object value = sessionMap.get(channel);

                    Hashtable < string, object[] > sourceDestMap = null;

                    if (value == null) {

                        sourceDestMap = new Hashtable < string, object[] > ();

                    } else sourceDestMap = (Hashtable < string, object[] > ) value;

                    sourceDestMap.put(session.getId(), new Object[] {
                        session
                    });

                    sessionMap.put(channel, sourceDestMap);

                }

            } catch (JSONException je) {

                je.printStackTrace();

            }

            try {

                Object dataObj = jsonObject.get("data");

                JSONObject dataMapObj = (JSONObject) dataObj;

                //Object thisUserId = dataMapObj.get("userid");

                String channel = null;

                try {

                    channel = (String) dataMapObj.get("sessionid");

                } catch (JSONException json) {

                    channel = (String) jsonObject.get("channel");

                }

                /*
                JSONObject dataMapObj = (JSONObject) dataObj;

                Object thisUserId = dataMapObj.get("userid");
                
                String channel = (String) dataMapObj.get("sessionid");
                
                Hashtable < string, object > sourceDestMap = sessionMap.get(channel);
                
                if (thisUserId != null && sourceDestMap.get((String) thisUserId) == null) {
                
                    sourceDestMap.put((String) thisUserId, new Object[] {
                        message, session
                    });
                
                }
                
                for (String userId: sourceDestMap.keySet()) {
                
                    if (!userId.equals(thisUserId)) {
                
                        Session otherSession = (Session)((Object[]) sourceDestMap.get(userId))[1];
                
                        otherSession.getBasicRemote().sendText(message);
                
                    }
                
                }
                */

                Hashtable < string, object[] > sourceDestMap = sessionMap.get(channel);

                if (sourceDestMap != null)

                for (String id: sourceDestMap.keySet()) {

                    if (!id.equals(session.getId())) {

                        Session otherSession = (Session)((Object[]) sourceDestMap.get(id))[0];

                        if (otherSession.isOpen())

                        otherSession.getBasicRemote().sendText(dataMapObj.toString());

                    }

                }

            } catch (JSONException je) {

                je.printStackTrace();

            }

        } catch (JSONException | IOException je) {

            je.printStackTrace();

        }

        System.out.println("Message received:" + message);

    }

    @OnOpen

    public void open(Session session) {

        System.out.println("Channel opened");

    }

    // need to implement @OnClose too

}
// HTML/Browser side code (client-code)
var SIGNALING_SERVER = "ws://YOUR_TOMCAT_APPLICATION_PATH/webrtc";

connection.openSignalingChannel = function(config) {

    config.channel = config.channel || this.channel;

    var websocket = new WebSocket(SIGNALING_SERVER);

    websocket.channel = config.channel;

    websocket.onopen = function() {

        websocket.push(JSON.stringify({

            open: true,

            channel: config.channel

        }));

        if (config.callback)

            config.callback(websocket);

    };

    websocket.onmessage = function(event) {

        config.onmessage(JSON.parse(event.data));

    };

    websocket.push = websocket.send;

    websocket.send = function(data) {

        websocket.push(JSON.stringify({

            data: data,

            channel: config.channel

        }));

    };
};

Using Pusher for Signaling

// below snippet is taken from: 
// http://pusher.com/tutorials/webrtc_chat

connection.openSignalingChannel = function (config) {
    config.channel = config.channel || this.channel;
    var xhrErrorCount = 0;

    var socket = {
        send: function(message) {
            $.ajax({
                type: "POST",
                url: "/message",
                data: {
                    socketId: socketId,
                    channel: config.channel,
                    message: message
                },
                timeout: 1000,
                success: function(data) {
                    xhrErrorCount = 0;
                },
                error: function(xhr, type) {
                    // Increase XHR error count
                    xhrErrorCount++;

                    // Stop sending signaller messages if it's down
                    if (xhrErrorCount > 5) {
                        console.log("Disabling signaller due to connection failure");
                        connection.transmitRoomOnce = true;
                    }
                }
            });
        },
        channel: config.channel
    };

    // Subscribe to Pusher signalling channel
    var pusherChannel = pusher.subscribe(config.channel);

    // Call callback on successful connection to Pusher signalling channel
    pusherChannel.bind("pusher:subscription_succeeded", function() {
        if (config.callback) config.callback(socket);
    });

    // Proxy Pusher signaller messages to DataChannel
    pusherChannel.bind("message", function(message) {
        config.onmessage(message);
    });

    return socket;
};

Using WebSync for Signaling

// below snippet is taken from:
// https://github.com/muaz-khan/WebSync-Signaling

var channels = {};
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 (channels[message.channel] && channels[message.channel].onmessage) {
                    channels[message.channel].onmessage(message.message);
                }
            }
        });
    }
});

connection.openSignalingChannel = function (config) {
    var channel = config.channel || this.channel;
    channels[channel] = config;

    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
                    })
                }
            });
        }
    };
};

Using XHR for Signaling

// below snipet is taken from:
// https://github.com/muaz-khan/XHR-Signaling

// database has a single table; which has two columns: 
// 1) Message (required to store JSON data)
// 2) ID (optional: as primary key)

// a simple function to make XMLHttpRequests
function xhr(url, callback, data) {
    if (!window.XMLHttpRequest || !window.JSON) return;

    var request = new XMLHttpRequest();
    request.onreadystatechange = function () {
        if (callback && request.readyState == 4 && request.status == 200) {
            // server MUST return JSON text
            callback(JSON.parse(request.responseText));
        }
    };
    request.open('POST', url);

    var formData = new FormData();

    // you're passing "message" parameter
    formData.append('message', data);

    request.send(formData);
}

// this object is used to store "onmessage" callbacks from "openSignalingChannel handler
var onMessageCallbacks = {};

// this object is used to make sure identical messages are not used multiple times
var messagesReceived = {};

function repeatedlyCheck() {
    xhr('/Home/GetData', function (data) {
        // if server says nothing; wait.
        if (data == false) return setTimeout(repeatedlyCheck, 400);

        // if already receied same message; skip.
        if (messagesReceived[data.ID]) return setTimeout(repeatedlyCheck, 400);
        messagesReceived[data.ID] = data.Message;

        // "Message" property is JSON-ified in "openSignalingChannel handler
        data = JSON.parse(data.Message);

        // don't pass self messages over "onmessage" handlers
        if (data.sender != connection.userid && onMessageCallbacks[data.channel]) {
            onMessageCallbacks[data.channel](data.message);
        }

        // repeatedly check the database
        setTimeout(repeatedlyCheck, 1);
    });
}

repeatedlyCheck();

// overriding "openSignalingChannel handler
connection.openSignalingChannel = function (config) {
    var channel = config.channel || this.channel;
    onMessageCallbacks[channel] = config.onmessage;

    // let RTCMultiConnection know that server connection is opened!
    if (config.onopen) setTimeout(config.onopen, 1);

    // returning an object to RTCMultiConnection
    // so it can send data using "send" method
    return {
        send: function (data) {
            data = {
                channel: channel,
                message: data,
                sender: connection.userid
            };

            // posting data to server
            // data is also JSON-ified.
            xhr('/Home/PostData', null, JSON.stringify(data));
        },
        channel: channel
    };
};

Using SignalR for Signaling

// below snippet is taken from:
// https://github.com/muaz-khan/WebRTC-Experiment/blob/master/Signaling.md#how-to-use-signalr-for-signaling

var onMessageCallbacks = {};

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();

connection.openSignalingChannel = function (config) {
    config.channel = config.channel || this.channel;
    onMessageCallbacks[config.channel] = config.onmessage;

    if (config.onopen) setTimeout(config.onopen, 1000);
    return {
        send: function (message) {
            message = JSON.stringify({
                message: message,
                channel: config.channel
            });

            hub.server.send(message);
        }
    };
};

Latest Issues

Want to ask a Question?

You can include your email for private conversation!

Latest Updates