Post tutorial 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
Sign in or join with:

Only registered members can share their thoughts. So come on! Join the community today (totally free - or sign in with your social account on the right) and join in the conversation.