muaz-khan / RTCMultiConnection

RTCMultiConnection is a WebRTC JavaScript library for peer-to-peer applications (screen sharing, audio/video conferencing, file sharing, media streaming etc.)
https://muazkhan.com:9001/
MIT License
2.55k stars 1.38k forks source link

Working with Pusher #30

Open gpkamp opened 9 years ago

gpkamp commented 9 years ago

I can't seem to get RTCMultiConnection to work with Pusher. More info here: http://stackoverflow.com/questions/28375411/webrtc-rtcmulticonnection-with-pusher

redsketch commented 7 years ago

Mr. Muaz, I also have trouble using your RTCMultiConnection with Pusher, I have checked the above stackoverflow link but it seems it have been removed, webRTC is new for me, so could you kindly help me..

Here is the code that I tried to understand, this is from your example but I add Pusher for signaling

    <body>
        <pre id="session"></pre>
        <input type="text" id="initiator">
        <hr /><button id="openRoom">Open Room</button>
        <button id="joinRoom">Join Room</button><hr />
        <script src="https://cdn.webrtc-experiment.com/RTCMultiConnection.js"> </script>
        <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
        <script src="https://js.pusher.com/3.2/pusher.min.js"></script>
        <script>

        var MODERATOR_CHANNEL_ID = 'ABCDEF'; // channel-id
        var MODERATOR_SESSION_ID = 'XYZ';    // room-id
        var MODERATOR_ID         = 'JKL';    // user-id
        var MODERATOR_SESSION    = {         // media-type
            audio: true,
            video: true
        };
        var MODERATOR_EXTRA      = {};       // empty extra-data

        // Open a connection to Pusher
        var pusher = new Pusher(PUSHER_SECRET_KEY, {
            encrypted: true
        });

        // Enable pusher logging - don't include this in production
        Pusher.logToConsole = true;

        // Storage of Pusher connection socket ID
        var socketId;

        var onMessageCallbacks = {};

        Pusher.log = function (message) {
            if (window.console && window.console.log) {
                window.console.log(message);
            }
        };

        // Monitor Pusher connection state
        pusher.connection.bind("state_change", function (states) {
            switch (states.current) {
                case "connected":
                    socketId = pusher.connection.socket_id;
                    break;
                case "disconnected":
                case "failed":
                case "unavailable":
                    break;
            }
        });

        var con = new RTCMultiConnection();

        con.openSignalingChannel = function (config) {
            var channel = config.channel = MODERATOR_CHANNEL_ID;
            onMessageCallbacks[channel] = config.onmessage;

            var xhrErrorCount = 0;
            var socket = {
                send: function(message) {
                    $.ajax({
                        type: "POST",
                        url: "message.php",
                        data: {
                            socketId: socketId,
                            sender: con.userid,
                            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");
                                con.transmitRoomOnce = true;
                            }
                        }
                    });
                },
                channel: channel,
                onconnected: function (data) {
                    con.send('test');
                }
            };

            // Subscribe to Pusher signalling channel
            var pusherChannel = pusher.subscribe(config.channel);
            console.log('channel ' + 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(data) {
                if(data.sender == con.userid) return;

                if (onMessageCallbacks[data.channel]) {
                    onMessageCallbacks[data.channel](data.message);

                };

            });

            return socket;
        };

        document.getElementById('openRoom').onclick = function() {
            con.channel = MODERATOR_CHANNEL_ID;

            con.socketURL = '/';
            con.session = MODERATOR_SESSION
            con.userid  = MODERATOR_ID;
            con.extra   = MODERATOR_EXTRA;
            con.open({
                dontTransmit: true,
                sessionid: MODERATOR_SESSION_ID
            });

            document.querySelector('#session').textContent = JSON.stringify(con.sessionDescriptions);
        };

        document.getElementById('joinRoom').onclick = function() {

            con.channel = MODERATOR_CHANNEL_ID;
            con.socketURL = '/';

            con.join({
                sessionid: MODERATOR_SESSION_ID,
                userid: MODERATOR_ID,
                extra: MODERATOR_EXTRA,
                session: MODERATOR_SESSION
            });
        };
        </script>
    </body>
</html>
require_once("Pusher.php");
require_once("config.php");

// TODO: Check for valid POST data

var_dump($_POST);
$pusher = new Pusher(APP_KEY, APP_SECRET, APP_ID);
$pusher->trigger($_POST["channel"], "message", $_POST, $_POST["socketId"], true);

header("Status: 200");

The test is on localhost with firefox as browser.

For the test, I opened two tabs, the first one is for the initiator to 'open' the room, and the other tab is for the participant to 'join' the room. When participant join the room, the participant successfully send 'answer' to the initiator, I check in console, participant is successfully 'connected' but not the initiator.

I suspect the problem is on the open signal, but I don't know what it is.

muaz-khan commented 7 years ago

Please check this pusher demo:

Both DataChannel and RTCMultiConnection uses identical API; so you can easily use above demo with RTCMultiConnection-v2 as well.

Here is the article:

On Github:

redsketch commented 7 years ago

Thank you for your response Mr. Muaz, actually I have tried the link that you provided, when I'm using datachannel.js, the send message is working, even though there're some few warning in the console, but when I change it to use RTCMultiConnection it's not working.

Here are the code

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>WebRTC</title>
    </head>

    <body>
        <nav class="navbar" role="navigation">
            <div class="container">
                <a class="brand" href="http://pusher.com">
                    <!-- <img src="http://pusher.com/prom/images/new_landing_page/pusher-logo.png" alt="Pusher" width="111" height="37"> -->
                </a>

                <span>| Realtime API</span>

                <a href="http://pusher.com/pricing"><button class="btn signup-button">Create a Free Account</button></a>
            </div>
        </nav>

        <div class="container">
            <div class="row">
                <header class="col-md-12">
                    <h1>WebRTC DataChannel Chat</h1>
                </header>
            </div>

            <div class="row">
                <section class="col-md-12">
                    <p>This chat application uses WebRTC to create a peer-to-peer, server-less connection between you and the recipient of your chat messages, a bit like Skype!</p>

                    <p>Want to create this yourself? Read the full tutorial on <a href="http://pusher.com/tutorials/webrtc_chat">creating a WebRTC chat application using Pusher</a>.</p>

                    <hr>

                    <h2>Getting started</h2>

                    <ol>
                        <li>Type a channel name and click <strong>create</strong></li>
                        <li>Open the chat in another tab</li>
                        <li>Type the same channel name and click <strong>join</strong></li>
                        <li>Wait a moment and start chatting!</li>
                    </ol>

                    <!-- WebRTC demo -->
                    <div class="demo">
                        <div class="demo-connect">
                            <input type="text" class="demo-chat-channel-input form-control" placeholder="Channel name"></input>
                            <button class="demo-chat-create btn btn-primary">Create</button>
                            <button class="demo-chat-join btn btn-warning">Join</button>
                        </div>
                        <div class="demo-chat inactive">
                            <div class="demo-chat-input">
                                <input name="message" class="demo-chat-message-input form-control" placeholder="Message"></input>
                                <button class="demo-chat-send btn btn-primary">Send</button>
                            </div>
                            <ul class="demo-chat-messages list-group">
                                <li class="list-group-item" data-remove="true">No chat messages available</li>
                            </ul>
                        </div>
                        <footer>
                            <a href="http://pusher.com">Pusher</a> powered peer-to-peer chat
                        </footer>
                    </div>
                    <!-- /End WebRTC demo -->
                </section>
            </div>
        </div>

        <script
            src="https://code.jquery.com/jquery-3.1.1.min.js"
            integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
        crossorigin="anonymous"></script>
        <!-- Pusher for WebRTC signalling -->
        <script src="https://js.pusher.com/3.2/pusher.min.js"></script>
<!--
        <script src="//cdn.webrtc-experiment.com/DataChannel.js"></script>
-->

        <script src="js/RTCMultiConnection.js"></script>
        <script src="js/main.js"></script>
    </body>
</html>

// Initialise DataChannel.js
//~ var datachannel = new DataChannel();
var datachannel = new RTCMultiConnection();

datachannel.socketURL = '/';

datachannel.session = {video: false, audio: false, data: true};
datachannel.enableLogs = true;
//~ datachannel.sdpConstraints.mandatory = {
    //~ OfferToReceiveAudio: true,
    //~ OfferToReceiveVideo: true
//~ };

// Set the userid based on what has been defined by DataChannel
// https://github.com/muaz-khan/WebRTC-Experiment/tree/master/DataChannel#use-custom-user-ids
datachannel.userid = window.userid;

// Open a connection to Pusher
var pusher = new Pusher(PUSHER_SECRET_KEY, {
    encrypted: true
});

// Enable pusher logging - don't include this in production
Pusher.logToConsole = true;

// Storage of Pusher connection socket ID
var socketId;

Pusher.log = function (message) {
    if (window.console && window.console.log) {
        window.console.log(message);
    }
};

// Monitor Pusher connection state
pusher.connection.bind("state_change", function (states) {
    switch (states.current) {
        case "connected":
            socketId = pusher.connection.socket_id;
            break;
        case "disconnected":
        case "failed":
        case "unavailable":
            break;
    }
});

// Set custom Pusher signalling channel
// https://github.com/muaz-khan/WebRTC-Experiment/blob/master/Signaling.md
datachannel.openSignalingChannel = function (config) {
    var channel = config.channel || this.channel || "default-channel";
    var xhrErrorCount = 0;

    var socket = {
        send: function (message) {
            $.ajax({
                type: "POST",
                url: "message.php",
                data: {
                    socketId: socketId,
                    channel: channel,
                    message: message
                },
                timeout: 1000,
                success: function (data) {
                    console.log(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");
                        datachannel.transmitRoomOnce = true;
                    }
                }
            });
        },
        channel: channel
    }; // EoV.socket

    // Subscribe to Pusher signalling channel
    var pusherChannel = pusher.subscribe(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;
};

datachannel.customsStreams = {};

var onCreateChannel = function () {
    var channelName = cleanChannelName(channelInput.value);

    if (!channelName) {
        console.log("No channel name given");
        return;
    }

    disableConnectInput();

    datachannel.open(channelName);
};

var onJoinChannel = function () {
    var channelName = cleanChannelName(channelInput.value);

    if (!channelName) {
        console.log("No channel name given");
        return;
    }

    disableConnectInput();

    // Search for existing data channels
    datachannel.connect(channelName);
};

var cleanChannelName = function (channel) {
    return channel.replace(/(\W)+/g, "-").toLowerCase();
};

var onSendMessage = function () {
    var message = messageInput.value;

    if (!message) {
        console.log("No message given");
        return;
    }

    datachannel.send(message);
    addMessage(message, window.userid, true);

    messageInput.value = "";
};

var onMessageKeyDown = function (event) {
    if (event.keyCode == 13) {
        onSendMessage();
    }
};

var addMessage = function (message, userId, self) {
    var messages = messageList.getElementsByClassName("list-group-item");

    // Check for any messages that need to be removed
    var messageCount = messages.length;
    for (var i = 0; i < messageCount; i++) {
        var msg = messages[i];

        if (msg.dataset.remove === "true") {
            messageList.removeChild(msg);
        }
    }
    ;

    var newMessage = document.createElement("li");
    newMessage.classList.add("list-group-item");

    if (self) {
        newMessage.classList.add("self");
        newMessage.innerHTML = "<span class='badge'>You</span><p>" + message + "</p>";
    } else {
        newMessage.innerHTML = "<span class='badge'>" + userId + "</span><p>" + message + "</p>"
    }

    messageList.appendChild(newMessage);
};

var disableConnectInput = function () {
    channelInput.disabled = true;
    createChannelBtn.disabled = true;
    joinChannelBtn.disabled = true;
};

// Demo DOM elements
var channelInput = document.querySelector(".demo-chat-channel-input");
var createChannelBtn = document.querySelector(".demo-chat-create");
var joinChannelBtn = document.querySelector(".demo-chat-join");
var messageInput = document.querySelector(".demo-chat-message-input");
var sendBtn = document.querySelector(".demo-chat-send");
var messageList = document.querySelector(".demo-chat-messages");

// Set up DOM listeners
createChannelBtn.addEventListener("click", onCreateChannel);
joinChannelBtn.addEventListener("click", onJoinChannel);
sendBtn.addEventListener("click", onSendMessage);
messageInput.addEventListener("keydown", onMessageKeyDown);

// Set up DataChannel handlers
datachannel.onopen = function (userId) {
    document.querySelector(".demo-connect").classList.add("inactive");
    document.querySelector(".demo-chat").classList.remove("inactive");
    messageInput.focus();
};

datachannel.onmessage = function (message, userId) {
    addMessage(message, userId);
};

There is an error that bugging me:

Firefox can't establish a connection to the server at wss://echo.websocket.org/.
http://localhost:8080/webrtc/datachannel/js/RTCMultiConnection.js
Line 5160

And I though by adding

.socketURL = '/'

will remove the default websocket target.

ps: This test was using RTCMulticonnection v2.2.2

redsketch commented 7 years ago

Mr. Muaz, may I know what response must be received by the signaler.

muaz-khan commented 7 years ago

Please make sure that you're using this (v2):

It requires same openSignalingChannel method as DataChannel.js.

ferrolive commented 6 years ago

@muaz-khan , do you have an example of openSignalingChannel using Pusher? Even trying to create a new method (based on this example: https://github.com/pusher-community/pusher-webrtc-chat-demo) I cannot proceed. Do you have any example?