Channels and Sessions

Muaz Khan edited this page Sep 5, 2015 · 3 revisions

Summary: This wiki-page explains differences between "channels" and "sessions"; and how to manage sessions; how to disconnect and re-initiate sessions.

This wiki is updated at Sep 05, 2015. Please scroll bottom to see new detailed explanation.

RTCMultiConnection is based on "channels"; a term used for a big-room that can have many sub-rooms.

  1. Big-room is named as "channels"
  2. Sub-rooms are named as "sessions"

Here is how to set channels:

// first method: pass an argument
var connection = new RTCMultiConnection('channel-uuid');

// second method: set "channe" property
var connection = new RTCMultiConnection();
connection.channel = 'channel-uuid';

// third method: let RTCMultiConnection generate random channels
var connection = new RTCMultiConnection();

Channels allow you setup multiple unique big-rooms on the same page; as you can test in this demo. Multiple channels can be opened on the same page, as described in this snippet:

var connection1 = new RTCMultiConnection('channel-uuid-1');
var connection2 = new RTCMultiConnection('channel-uuid-2');
var connection3 = new RTCMultiConnection('channel-uuid-3');

// set media type
connection1.session = {
   audio: true
};

// set media type
connection2.session = {
   screen: true,
   oneway: true
};

// set media type
connection3.session = {
   data: true
};

As you can see connection1 is audio-only conferencing room, connection2 is screen sharing, and connection3 is data sharing. All these works in the same page without interrupting each other.

Don't forget that a "channel" is merely a top-level big-room; main thing in RTCMultiConnection is a "session" i.e. sub-room or sub-channel or a small-room.

Here is how to set session-ids i.e. how to open a session (small room) in a channel (big room):

initiator.sessionid = 'unique-session-id';
initiator.open();

// or
initiator.open('sessionid');

// or
participant.connect('sessionid');

// or 
participant.join('sessionid');

// or
participant.join({
    userid: 'initiator-id',
    sessionid: 'initiator-sessionid',
    extra: 'initiator-extra',
    session: 'initiator-session' // i.e. { audio: true, video: true }
});

leave method allows a user to leave that "small-room" i.e. leave-session. User is still part of the channel i.e. user is still connected to main-big-room.

// a user can leave small-room using "leave" method
connection.leave();

// small-room moderator i.e. session-initiator can close
// entire session using "close" method
connection.close();

// session-initiator can throw any user out of the session
// i.e. eject any user from his small-room
// using "eject" method
connection.eject('participant-userid');

You can easily detect if a user is ejected:

connection.onSessionClosed = function (session) {
    if (session.isEjected) {
        warn(session.userid, 'ejected you.');
        // roomsList.innerHTML = '';
    } else warn('Session has been closed.', session);
};

RTCMultiConnection is highly customizable, which means that you can override many things by setting a few Boolean properties. E.g.

// by default, this boolean is true
// it means that if any user leaves
// "connection.leave" method will be invoked for him
// which means that he will leave the session
// his video, his screen, his data, his sockets, everything
// will be removed from all other relevant users' sides
connection.leaveOnPageUnload = true;

// by default, this boolean is false
// which means that if session-initiator leaves
// moderation or initiation control will be shifted to 
// first available participant
// so room will be kept active until everyone leaves
connection.autoCloseEntireSession = true;

You can easily detect if a user left the session using onleave event. This event is fired for all kinds of users.

connection.onleave = function(event) {
   event.userid == 'target-userid'
   event.extra  == 'target-user-extra-data'
};

You can also detect if entire session is closed by room moderator. Don't forget that term "session" is used for a small-room. So, even if entire session is closed; all users are still connected to main-channel i.e. big-room.

connection.onSessionClosed = function(event) {
   event.userid == 'target-userid'
   event.extra  == 'target-user-extra-data'
};

If you want to leave channel as well, you can use disconnect method. Disconnect method disconnects everything. You can easily detect if room-moderator asked you to disconnect from big-room i.e. leave the channel:

connection.disconnect();

connection.ondisconnected = function(event) {
    if (event.isSocketsDisconnected) {
        // you're disconnected not only from the session (sub-channel)
        // but, also from main-channel
    }
};

First step RTCMultiConnection do is connects to main-channel; then sessions can be created or joined in the same channel.

Users from channel-XYZ are isolated from all other channels. Sessions that are created in channel-XYZ are visible in that channel only.

Channels provides reliable, also easy session-management scenarios.

Remember, disconnect method merely do following tasks:

  1. Closes all sockets
  2. Stops all stream if keepStreamsOpened boolean isn't used
  3. Clears all stored sctp-datachannels, all user-ids and everything
  4. Most importantly, disconnects from main-channel

However channel-id isn't removed. It means that if you invoke connect method quickly after you're disconnected from main-channel, you'll be connected again to same channel:

connection.ondisconnected = function(event) {
    if (event.isSocketsDisconnected) {
        console.log('your channel-id:', connection.channel); // channel-id isn't modified or removed

        // usually not required, however you can reset channel-id
        connection.channel = 'something-new';
        connection.connect(); // reconnect to same or new channel
    }
};

Here is how to implement session re-initiation scenarios:

// leave "main-channel"
btnLeaveChannel.onclick = function() {
    connection.disconnect();
};

// leave "session"
btnLeaveSession.onclick = function() {
    connection.leave();
};

connection.ondisconnected = function(event) {
    if (event.isSocketsDisconnected) {
        connection.connect(); // reconnect to same channel

        // or not only connect to same channel, 
        // but also open a "session" in that channel
        connection.open('session-id');

        // or not only connect to same channel, 
        // but also join a "session" in that channel
        connection.join('session-id');
    }
};

Differences between connect, join and open methods is that:

  1. connect method connects to main-channel. Then it waits for onNewSession event to be fired.
  2. join method connects to main-channel but it NEVER waits for onNewSession event. It quickly makes participation-request.
  3. open method connects to main-channel, then it quickly opens a session in that channel.

As you can see, all three are connecting to main-channel.

When users are connected to main-channel; you can easily pass custom messages using sendCustomMessage method.

btnSendCustomMessage.onclick = function() {
    connection.sendCustomMessage({
        messageFor: 'all',
        disconnectFromChannel: true
    });
};

connection.onCustomMessage = function(message) {
    if (message.messageFor == 'all' && message.disconnectFromChannel == true) {
        connection.disconnect();
    }
};

You can even ask users to leave old channel, and connect to a new channel:

btnSendCustomMessage.onclick = function() {
    connection.sendCustomMessage({
        messageFor: 'all',
        disconnectFromChannel: true,
        connectToNewChannel: 'new-channel-id'
    });
};

connection.onCustomMessage = function(message) {
    if (message.messageFor == 'all' && message.disconnectFromChannel == true) {
        connection.disconnect();

        // connect to new channel
        if (message.connectToNewChannel) {
            connection.channel = message.connectToNewChannel;
            connection.connect();
        }
    }
};

As you can see, channels can be set either using RTCMultiConnection-constructor, or otherwise channel property.

Sessions can be set in four ways:

  1. By using open method
  2. By using connect method
  3. By using join method
  4. By using sessionid property

E.g.

connection.open('session-id');

// or
connection.connect('session-id');

// or
connection.join('session-id');

// or
connection.sessionid = 'session-id';

RTCMultiConnection has a session property; a correct name for this property should be media-type. It means that this property merely sets type of media to be fetched and used in the session:

connection.session = {
     audio:     true,  // by default, it is true
     video:     true,  // by default, it is true
     screen:    false, // screen sharing
     
     data:      false, // SCTP/RTP data channels
     
     oneway:    false,
     broadcast: false,
     
     inactive: true    // added since v2.0.*
};

So please don't be confused about session and sessionid.

Whilst caring about session management, you should focus on sessionid or channel properties:

connection.channel   = 'big-room';
connection.sessionid = 'sub-small-room';

Updated at Sep 05, 2015

Each participant MUST know big-room-id which is named as "channel-id".

The real object that stores channel-id i.e. big-room-id is connection.channel. E.g.

connection.channel = 'big-room-id';

All other methods (e.g. constructor) simply sets above object.

If a participant knows above "channel-id"; he can easily watch "onNewSession" event and he can easily join sessions that are created inside above big-room.

"onNewSession", by default, auto tries to join the session. However you can easily override it.

RTCMultiConnection uses a term named as "start-transmitting-room-descriptions" which is used as a default option; however one can easily override it by passing "dontTransmit" Boolean over "open" method.

Start-transmitting room description simply means that, as soon as connection.open is called, RTCMultiConnection will make "websocket.send" request after every 3-seconds. "onNewSession" event for remote users will be fired accordingly.

Here is the default behavior:

var connection = new RTCMultiConnection();
connection.channel = 'big-room';
connection.session = { video: true };
connection.onNewSession = function(session) {
    connection.join(session);
    // "onNewSession" will not fire after calling "join" method
};
btnOpenRoom.onclick = function() {
    connection.open('Session-ID');
};
connection.connect(); // needed for participants so that we can fire "onNewSession" event.

Here is overridden behavior that skips room-transmission:

var connection = new RTCMultiConnection();
connection.channel = 'big-room';
connection.session = { video: true };
btnOpenRoom.onclick = function() {
    connection.userid = 'session-owner-id';
    connection.sessionid = 'session-id';
    connection.open({
        dontTransmit: true  // "onNewSession" will NEVER fire
    });
};
btnJoinRoom.onclick = function() {
    var sessionOwnerId = database.sessionOwnerId;
    var sessionId = database.sessionId;
    connection.join({
        userid: sessionOwnerId,
        sessionid: sessionId,
        session: { video: true }, // or connection.session
        extra: {} // you can even fetch "owner.extra" object from database
    });
};

You can see that the person who creates room, need to provide NOT-only his userid, but also "session-id".

But the person who joins his room, MUST provide following things:

  1. "userid" ====== OWNER-UserID
  2. "sessionid" ======== OWNER-SessionID
  3. "extra" ======= OWNER extra data (optional)
  4. "session" ===== Usually it is equivalent to connection.session object

Here is RAW-diagram:

Big-room i.e. channel (whilst using dontTransmit:true) >>
         >> Session ID === 007
                >> OWNER should provide both userid and sessionid
                >> All participants should provide OWNER_UserID, Owner_SessionID, extra, session obj
         >> Session ID === 123
                >> OWNER should provide both userid and sessionid
                >> All participants should provide OWNER_UserID, Owner_SessionID, extra, session obj
         >> Session ID === 754
                >> OWNER should provide both userid and sessionid
                >> All participants should provide OWNER_UserID, Owner_SessionID, extra, session obj

The default behavior looks like this:

Big-room i.e. channel (whilst using dontTransmit:true) >>
         >> Session ID === 007
                >> OWNER should provide both userid and sessionid
                >> "onNewSession" will be fired for all participants
                >> You can show all sessions in a <list>
                >> All such sessions are stored in "connection.sessionDescriptions"
         >> Session ID === 123
                >> OWNER should provide both userid and sessionid
                >> "onNewSession" will be fired for all participants
                >> You can show all sessions in a <list>
                >> All such sessions are stored in "connection.sessionDescriptions"
         >> Session ID === 754
                >> OWNER should provide both userid and sessionid
                >> "onNewSession" will be fired for all participants
                >> You can show all sessions in a <list>
                >> All such sessions are stored in "connection.sessionDescriptions"

You can even use something like this:

var connection = new RTCMultiConnection();
connection.channel = 'big-room';
connection.session = { video: true };
connection.onNewSession = function(session) { }; // EMPTY

btnOpenRoom.onclick = function() {
    connection.open('Session-ID');
};

btnJoinRoom.onclick = function() {
    var session = connection.sessionDescriptions['Session-ID'];
    if(!session) return;

    connection.join( session );
};

Conclusion:

  • connection.channel provides big-room-id and it is always used.
  • Owner MUST set connection.sessionid. Otherwise, RTCMultiConnection will set connection.sessionid = connection.channel i.e it is assumed that this channel merely have single session.
  • Participant should be having same channel-id, and he can pass both owner's userid and owner's sessionid to join his session.

In simple words:

All users who are having same-channel-id can join with each other. Anyone can open the room. Anyone can join that room.

If two different domains are using:

  • same signaling medium i.e. firebase or websockets
  • same channel-id

then both domain can share sessions with each other. Users from both domains can connect with each other.