FacebookTwitter

WebRTC or a Video Conference of Your Own

By on Jan 16, 2017 in Interesting, Intermediate, JavaScript

Share On GoogleShare On FacebookShare On Twitter

webrtc

Firstly, lets cover general questions concerning WebRTC. This technology allows the building of video or audio communication through the usage of web browsers. Besides, it is an open source project and currently this technology is in use among such browsers as Opera, Google Chrome, Firefox and some more. For instance, Chrome allows you the possibility to reach the webcam and microphone of a device but only for those websites having specialized a SSL certificate.
In order to connect users, they need to identify each other. It can be achieved by using WebSocket technology.

 

How does it work?
For a better understanding, let’s consider an example of a real project in web development. As a basis for the server development, we have NodeJS supplemented by the socket.io while AndularJS has become a basis for frontend development.

 

Chapter 1: Where can I start?
The first thing you need to do during development is to check the browsers ability to be connected to a device’s media.

 

setupRTC will help you check the availability of this technology support on a separate OS or browser as well as the possibility to access the media.

 

startCall is intended to start checking the support of this technology. After that, the initialization will be launched on the client’s side. The socket.io helps generate thecallRequeston the server.

 

targetId identifies which user from the database is going to get the connection request.
enableSelfVideo is responsible for everything related to the broadcast. Including the camera condition (on/off), streaming, displaying with the help of different players etc.

?View Code JAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
 function setupRTC(targetId) {
 
	var isSupported = false;
 
	navigator.getUserMedia = navigator.getUserMedia ||
    	navigator.webkitGetUserMedia ||
    	navigator.mozGetUserMedia;
 
	window.PeerConnection = window.RTCPeerConnection ||
    	window.mozRTCPeerConnection ||
    	window.webkitRTCPeerConnection;
 
	window.IceCandidate = window.RTCIceCandidate ||
    	window.mozRTCIceCandidate ||
    	window.webkitRTCIceCandidate;
 
	window.SessionDescription = window.RTCSessionDescription ||
    	window.mozRTCSessionDescription ||
    	window.webkitRTCSessionDescription;
 
	isSupported = navigator.getUserMedia && window.PeerConnection && window.SessionDescription;
 
	if (isSupported) {
    	var configuration = {
        	"iceServers": [
            	{url: 'stun server url'},
            	{
                	url: 'turn server url',
                	username: 'turn server username',
                	credential: 'turn server key'
            	}
        	]
    	};
    	//save Peer connection object to angular $rootScope to global access.
    	$rootScope.pc = new PeerConnection(configuration);
 
 
    	//add events handlers
    	$rootScope.pc.onicecandidate = function (e) {
        	if (e.candidate) {
            	$rootScope.io.emit('rtc', {
                	targetId: targetId,
                	type: 'candidate',
                	label: e.candidate.sdpMLineIndex,
                	id: e.candidate.sdpMid,
                	candidate: e.candidate.candidate
            	});
        	}
    	};
 
    	$rootScope.pc.onaddstream = function (e) {
        	// here should be code for processing successful connection
        	// for example save stream url to variable and insert it to HTML5 video player
 
        	$rootScope.stream = e.stream
    	};
 
    	$rootScope.pc.oniceconnectionstatechange = function () {
        	//if interrupted connection
        	if ($rootScope.pc && $rootScope.pc.iceConnectionState == 'disconnected') {
            	console.log('peer connection interrupted');
            	// here should be code for handler of interrupted connection
            	// for example hide video player
        	}
    	};
	}
 
	return isSupported;
}
 
 
 
startCall = function (targetId) {
 
	var isSupported = setupRTC(targetId);
 
	if (isSupported) {
    	enableSelfVideo(function () {
        	$rootScope.io.emit('callRequest', {
            	type: 'video',
            	targetId: targetId
        	});
    	});
	} else {
    	alert('UserMedia or WebRTC is not supported');
	}
};
 
function enableSelfVideo(callback) {
 
    	navigator.getUserMedia({audio: true, video: true}, function (stream) {
 
        	$rootScope.pc.addStream(stream);
        	callback();
 
    	}, function (err) {
        	alert(err)
    	});
	}

 

Chapter 2: Answer me!

 

After having successfully delivered the connection requestanother aim appears. You need to notify the user about accepting the call. The server uses web sockets in order to get a signal to inform user B about user A’s attempt to call.

 

At this stage, we should implement some important checks. For instance, checking banned users.

 

onRequestdeals with the callRequest on the server.

 

This stage is responsible for carrying out checks which are needed for the connection. One single mistake here can lead to an invalid solution.

 

Checking whether or not the user is online is one more important thing during this stage. On condition, if the user is offlinethe request simply will not be obtained.

 

?View Code JAVASCRIPT
1
2
3
4
5
6
7
8
9
function onRequest(io, socket) {
	return function (data) {
 
    	data.userId = socket.user.id;
 
    	socket.to('User:' + data.targetId).emit('callRequest', data);
 
	};
}

 

Next, the callRequest has to receive a request containing the caller’s information from the opposite user’s server.

?View Code JAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var callAccept = function (targetId) {
        	var isSupported = setupRTC(targetId);
 
        	if (isSupported) {
            	enableSelfVideo(function () {
                	$rootScope.io.emit('callRequest', {
                    	type: 'video',
                    	targetId: targetId
                	});
            	});
        	} else {
            	$rootScope.io.emit('callDecline', {
targetId: targetId,
reason: ‘some reason’
});
        	}
    	}

webrtc-tutorial

 

 

When the call is finished – a CallDecline event informs the server. After that, client A is being notified by the server.

webrtc-tutorial-2

 

 

On the condition the access is delivered without any problems, the server will be notified about itcallAccept. Accordingly, client A will be notified by the server.

?View Code JAVASCRIPT
1
2
3
4
5
6
7
8
9
function onAccept(io, socket) {
	return function (data) {
 
    	data.userId = socket.user.id;
 
    	socket.to('User:' + data.targetId).emit('callAccept', data);
 
	};
}

 

Chapter 3: Final preparations
After user B accepted this calluser A sends a message requiring the connection between them.

?View Code JAVASCRIPT
1
2
3
4
5
6
7
8
function onCallAccept() {
        	$rootScope.pc.createOffer(function (description) {
            	$rootScope.pc.setLocalDescription(description, function () {
                	description.type = 'offer';
                	$rootScope.io.emit('rtc', description);
            	}, onError);
        	}, onError, mediaConstraints);
    	}

 

Business logic is not required here. Moreover, having one message handler, the server just accepts these messages and after that sends them back to the target user.

?View Code JAVASCRIPT
1
2
3
4
5
6
7
8
9
function onRtc(io, socket) {
	return function(data){
 
    	data.fromId = socket.user.id;
    	data.toId = socket.interlocutorId;
 
    	socket.to('User:'+socket.interlocutorId).emit('rtc', data);
	};
}

 

socket.user.id – ID of the user who sends the message

socket.interlocutorId – ID of the user who is to receive the message

 

The users data can be kept anywhere including database a and RAM. However, in this particular case, the data is kept in thesocketobject placed on the server.

 

Both client and server side messages are sent at the RTC event.
The code for the handlers client side:

?View Code JAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
function onRtc(data) {
        	switch (data.type) {
            	case 'offer':
                	onRtcOffer(data);
                	break;
            	case 'answer':
                	onRtcAnswer(data);
                	break;
            	case 'candidate':
                	onRtcCandidate(data);
                	break;
        	}
    	}
 
function onRtcOffer(data) {
        	$rootScope.pc.setRemoteDescription(new SessionDescription(data), function () {
            	$rootScope.pc.createAnswer(function (description) {
                	$rootScope.pc.setLocalDescription(new SessionDescription(description), function () {
                    	description.type = 'answer';
                    	description.toId = data.fromId;
                    	console.log('sending answer');
                    	$rootScope.io.emit('rtc', description);
                	}, onError);
            	}, onError, mediaConstraints);
        	}, onError);
    	}
 
    	function onRtcAnswer(data) {
        	console.log('received answer');
        	$rootScope.pc.setRemoteDescription(new SessionDescription(data), function () {
        	}, onError);
    	}
 
    	function onRtcCandidate(data) {
        	console.log('received candidate');
        	var candidate = new RTCIceCandidate({
            	sdpMLineIndex: data.label,
            	candidate: data.candidate
        	});
        	$rootScope.pc.addIceCandidate(candidate);
    	}

 

It provides the clients with a connection by means of webRTC.

 

This way we can single out the following event sequence:

 

 

Then, $rootScope.pc.onaddstream will be activated (handler which was described before) in case of the successfully established connection. After that, the users can eventually start their conference.

 

We have considered the open source project webRTC as a means for the implementation of a video conference. As the basis for this code was taken from a real project. Though, it is deprived of business logic as well as visualization. The architecture for both the server and user side is also absent. We have represented a minimum set of functions that are needed in order to launch a conference.

 

It is important to remember that many details connected with application logic may appear and you have to take all of them into consideration. It may require much more code.

 

Vlad Dmitriev

Marketing Copywriter at Cleveroad
Vitaly Kuprenko is a Marketing Copywriter at Cleveroad Mobile and Web development company. We are focused on mobile and web development for competitive and winning software.

Latest posts by Vlad Dmitriev (see all)