←HOME

How to write video-conferencing application using WebRTC?

Copyright © 2013 Muaz Khan<@muazkh>.

If you're newcomer, newbie or beginner; you're suggested to try RTCMultiConnection.js or DataChannel.js libraries.


How to video conferencing?

  1. Open multiple peer connections to support multi-users connectivity
It is called peer-to-peer model; where all peers are interconnected.

This document is considered obsolete. (Notification added at June 22, 2013).


You should

  1. create two reusable functions: one for creating offer and other for creating answer. These will be called/invoked many times on each new room participation request.
  2. create a function like "openSignalingChannel" that should open new socket on each invocation.
  3. uniquely identify the current user

It is preferred to use socket.io because it supports multiplexing. WebSockets is useless in conferencing.

Those functions

On invocation; those functions should:

  1. create a new peer connection
  2. create offer or answer session-descriptions accordingly

Then, on page load

On page load: call "openSignalingChannel" method. This time your "openSignalingChannel" must open "default-channel" that must be active all the time. That default channel will be used to:

  1. show list of all active rooms
  2. allow new users to send "participation requests"

For room creator

If someone creates new room; you should continuously transmit his room details over the "default-channel".

You can use transmission-interval i.e. 3 or 5 seconds. It should be your own preference.

For room participant

Send "participation request" over same "default-channel".

You should also send participant's unique id in the "participation request" message.

Call "openSignalingChannel" method to create new socket where you should use his unique id as channel name/label.

That newly created socket will be used to get offer-sdp from room owner. It will also be used to get ICE gathered by room owner.

As soon as room owner will receive participation-request

You should create new socket using "openSignalingChannel" method where you should use participant's unique id for channel name/label. Otherwise, use random number that must be passed along with "participation request" message.

That new socket will be used to exchange SDP/ICE between room owner and that participant.

On the room owner's side

You should quickly create a new peer connection.

You should also quickly create "offer" because room-owner is expected to play the role of "offerer" for each new participant.

As soon as offer is created; you should pass that "offer sdp" over same socket that is being used to exchange SDP/ICE between room owner and participant.

On the participant's side

Set remote descriptions using offer sdp sent by room owner.

Create answer. Participant will always play role of "answerer" on joining new room.

As soon as answer is created; you should pass that "answer sdp" over same socket that is being used to exchange SDP/ICE between room owner and participant.

Again, on the room owner's side

Set remote descriptions using answer sdp sent by participant.

And handshake is completed! Are you sure? Wait....there is something else!

ICE candidates gathered on room owner's side

You should use same socket to exchange/post/transfer these ICE candidates on participant's side.

ICE candidates gathered on participant's side

You should use same socket to exchange/post/transfer these ICE candidates on room owner's side.

Finally...

And finally handshake is completed. You're done! Good job Sir!

For upcoming participants

For each new participant; repeat above process and that's it!

For video-conferencing

After successful handshake between room owner and the participant; transmit participant's details over all other connected sockets i.e. toward all other room participants.

As soon as other participants will receive transmitted details; make "auto" participation request toward that "last participant".

And then follow above process again.



Explaining above theory using (a little bit real however) pseudo codes.

Reusable functions...

function openSignalingChannel(channel)
{
   var socket = io.connect('http://your-site:8888/' + channel);
}

function createOffer()
{
   var peer = new RTCPeerConnection(...);
   peer.createOffer(onSuccess);
}

function createAnswer(offer_sdp)
{
   var peer = new RTCPeerConnection(...);
   peer.setRemoteDescription(offer_sdp);
   peer.createAnswer(onSuccess);
}

Opening default signaling channel

var channel = openSignalingChannel('default-channel');
channel.onmessage = function(message)
{
   if(message.participationRequest) {}
   if(message.sharingRoomDetails) {}
};

Assuming a new participant

channel.send({
   isNewParticipant: true,
   participant_id: participant_id
});

// this private socket will be used to exchange sdp/ice
var privateChannel = openSignalingChannel(participant_id);
privateChannel.onmessage = function(message)
{
   if(message.type === 'offer')
   {
       createAnswer(message.sdp);

       // on creating answer-sdp; transmit it over "privateChannel"
       privateChannel.send(answer_sdp);
   }
};

On participation request

if(message.isNewParticipant)
{
   var privateChannel = openSignalingChannel(message.participant_id);

   createOffer();

   // on creating offer-sdp; transmit it over "privateChannel"
   privateChannel.send(offer_sdp);
   privateChannel.onmessage = function(message)
   {
      if(message.type === 'answer') peer.setRemoteDescription(message.sdp);
   };
}

Exchanging ICE

privateChannel.onmessage = function(message)
{
   if(message.ice) peer.addIceCandidate(new RTCIceCandidate(message.ice));
};

peer.onicecandidate = function(event)
{
   privateChannel.send(event.candidate);
};

For video-conferencing

After successful handshake:

for(var i = 0; i < otherParticipants.length; i++)
{
    var participant = otherParticipants[i];

    // send/emit/push/etc.
    participant.send({
        isNewParticipant: true,
        participant_id: '0123456789'
    });
}

Use "participant_id" you can make additional participation requests to him.

Feedback