• Register

The Story So Far Three galaxy spanning civilizations struggle for domination of a galaxy. What is it? Humans vs Aliens vs Robots is a series of three intertwined strategy multi player games. The outcomes and events in each game can affect the other games, and it's up to you what games you play and how you play them. War: Take command of your civilization and capture a cluster of stars for side. Battle: Command a fleet of ships in battle and eradicate all enemy forces while using as few resources as possible. Chase: Take over an asteroid mining drone and collect the rare elements used in the war effort.

Post tutorial Report RSS Setting up HTML Video Chat

First in a two part series of tutorials demonstrating how I added peer to peer Video Chat to Humans vs Aliens vs Robots:War WebRTC client to client video and audio chat in your own game! Keen!

Posted by on - Intermediate Client Side Coding

I recently added peer to peer video chat to Humans vs Aliens vs Robots: War, and thought it would be nice to share the start-to finish implementation. Almost all the code in this is still rough and could be done more succinctly and in better form. But it is what it is until I get around to cleaning it up.

What my implementation ended up looking like:
Robot-Alien collusion - Video Communication

This works between firefox and chrome browsers on all platforms, and if a STUN/TURN server is implemented it seems to work through most common router and firewall setups.

Technology used

nodejs
socketio
peerjs
rfc5766-turn-server

Getting Started - Setting up the display and retrieving configuration information from the server


On the client side I added a video chat dialog that contains two video tags. The local is muted so we don't get echo/feedback (we don't need to hear ourselves):


On displaying the video chat dialog the following is executed:

if (window.localStream == null || (window.localStream != null && window.localStream.ended)){
            navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
            navigator.getUserMedia({audio: true, video: true},
                function(stream){
                    window.localStream = stream;
                    $("#localVideo").attr("src", URL.createObjectURL(stream));
                },
                function(error) {
                    console.log("navigator.getUserMedia error: ", error);
                }
            );
        }
        else {
            window.localStream.start();
        };
socket.emit("peerConfig");

This code starts the local video capture and sends a request to the server to get configuration details for the peer to peer connection. The reason this information is provided from the server is that it includes time-sensitive credentials which are supplied from the turn server. (The turn server credentials only last a few seconds/minutes.)

On the server side in response to the peerConfig request:

socket.on('peerConfig', function(){
   var configDetails = {"iceServers": [{"url": "stun:stun.l.google.com:19302"},
                    {"url":"turn:username@yourdomain.com", "credential":"yourCrdentials", password:"password set in turn server user database"}]};

        socket.emit('peerConfigResponse', JSON.stringify(configDetails));
    });

This code grabs the next set of credentials from the turn server user database. (In this case a text file that is being fed usernames and passwords from a different node process.) This section will be a little mysterious, but there's some great information out there already that covers Turn server setup. And for now, it's outside the scope of this tutorial. (One of the first posts I gleaned a lot from was: Dialogic.com ).

At any rate, configuration details are created and sent back to the client. Back on the client side:

socket.on("peerConfig", function(data){
        if (peer == null){
            data = JSON.parse(data);
            window.remoteStream = null;

            peer = new Peer(peerID, {host: 'yourdomain.com', port: 9000, path: '/', debug: 1, config: data});

            peer.on('open', function(id) {

            });

            peer.on('call', function(call){
                call.answer(window.localStream);
                console.log("peer called");
                makeVideoChatCall(call);
            });

            peer.on('close', function(call){
                window.existingCall.close();
                window.existingCall = null;
                peer = null;
                this.settingUpVideoConnection = false;
            });

            peer.on('disconnected', function(call){
                window.existingCall.close();
                window.existingCall = null;
                peer = null;
            });

            peer.on('error', function(err){
                window.existingCall = null;
                console.log("peer error: ", err.message);
                peer = null;
            });
        }
    });


makeVideoChatCall = function makeVideoChatCall(call){
        if (window.existingCall) {
            window.existingCall.close();
        }

        window.existingCall = call;

        // Wait for stream on the call, then set peer video display
        call.on('stream', function(stream){
            var element = $('#remoteVideo')[0];
            if (typeof element.srcObject !== 'undefined') {
                element.srcObject = stream;
            } else if (typeof element.mozSrcObject !== 'undefined') {
                element.mozSrcObject = stream;
            } else if (typeof element.src !== 'undefined') {
                element.src = URL.createObjectURL(stream);
            } else {
                console.log('Error attaching stream to element.');
            }

        });

        call.on('open', function(event){

        })

        call.on('close', function(event){
            window.existingCall = null;

        })

        call.on('error', function(err){
            window.existingCall = null;
            window.localStream = null;
            window.remoteStream = null;
            console.log('CALL ON error', err);
        })

        // UI stuff - Show end call button etc.
    }


Summary


At this point the client is capturing a local audio and video stream and displaying it in the localVideo video element.
The client has created a peer object ready to connect to another peer, and if need be use a stun or turn server to facilitate crossing common firewall and router configurations.

In the next part of this tutorial I'll cover making and answering calls

Post a comment

Your comment will be anonymous unless you join the community. Or sign in with your social account: