Permalink
584585e Jan 23, 2017
executable file 384 lines (267 sloc) 11.3 KB

Tips & Tricks

RTCMultiConnection v3 tips and tricks for advance users!

How to secure your socket.io usage?

Modify Signaling-Server.js and add this line:

io.on('connection', onConnection);

// add this line,
// quickly after above line
io.set('origins', 'https://domain.com:9001');

Now you've restricted the usage of socket.io only on domain https://domain.com:9001.

How to arrange videos?

It happens all insidde the onstream event.

connection.onstream = function(event) {
    if (event.type == 'local') {
        showLocalVideo(event);
        return;
    }

    if (event.type == 'remote') {
        var numberOfUsers = connection.getAllParticipants().length;
        if (numberOfUsers == 1) {
            showFirstUserVideoOnFullScreen(event);
        } else {
            showSecondAndUpcomingVideosInSmallDiv(event);
        }
    }
};

function showLocalVideo(event) {}

function showFirstUserVideoOnFullScreen(event) {}

function showSecondAndUpcomingVideosInSmallDiv(event) {}

Points to be noted:

  1. We are comparing even.type == local or remote to detect video's type.
  2. We can differentiate between audio, video and screen using event.stream.isScreen or event.stream.isAudio or event.stream.isVideo.
  3. Unique event.streamid to set unique IDs for each video element.

E.g.

connection.onstream = function(event) {
    var videoElement = event.mediaElement;

    // "streamid" uniquely identifies each video
    videoElement.id = event.streamid;

    // single user can share multiple videos (+multiple screens)
    videoElement.setAttribute('data-userid', event.userid);

    videoElement.onclick = function() {
        // get the unique stream-id
        var streamid = this.id;

        // get user-id
        var userid = this.getAttribute('data-userid');

        // you can access native RTCPeerConnection object
        var allVideosComingFromThisUser = connection.peers[userid].peer.getRemoteStreams();

        // you can access the MediaStream data
        var streamEvent = connection.streamEvents[streamid];

        console.log(streamEvent.type, streamEvent.stream.isScreen, streamEvent.stream, streamEvent.mediaElement);
    };
};

As you can see in the above snippet, we are setting two HTML attributes:

  1. id which is event.streamid
  2. data-userid which is event.userid

id helps us access MediaStream object. We can detect type of stream, active tracks, etc.

data-userid helps us detect who is sending the video stream.

You can always reset the video.src:

videoElement.onclick = function() {
    // get the unique stream-id
    var streamid = this.id;

    // you can access the MediaStream data
    var streamEvent = connection.streamEvents[streamid];

    // access native MediaStreamObject
    var mediaStream = streamEvent.stream;

    // reset the URL
    videoElement.src = URL.createObjectURL(mediaStream);
    videoElement.play();
};

You can merge or stop tracks:

videoElement.onclick = function() {
    // get the unique stream-id
    var streamid = this.id;

    // you can access the MediaStream data
    var streamEvent = connection.streamEvents[streamid];

    // access native MediaStreamObject
    var mediaStream = streamEvent.stream;

    // add new track
    mediaStream.addTrack(newTrack);

    // remove existing track
    var videoTrack = mediaStream.getVideoTracks()[0];
    mediaStream.removeTrack(videoTrack);
};

You can renegotiate peers to share new tracks:

videoElement.onclick = function() {
    // get user-id
    var userid = this.getAttribute('data-userid');

    // renegotiate to update RTCPeerConnection
    // it will reset ports; access all fresh tracks; etc.
    connection.renegotiate(userid);
};

If WebRTC fails

<script>
// add this script before loading "RTCMultiConnection.min.js"
window.getExternalIceServers = true;
</script>
<script src="https://rtcmulticonnection.herokuapp.com/dist/RTCMultiConnection.min.js"></script>

Now you will get maximum WebRTC success across all devices.

window.getExternalIceServers boolean variable tries to load STUN+TURN servers from xirsys.com. It is disabled by default.

Object.observe

Object.observe has been removed since v3.2.95. So you've to manually update-extra-data or set stream-end-handlers:

connection.extra.something = 'something';
connection.updateExtraData();

Attach External Stream

When attaching external streams:

connection.attachStreams.push(yourExternalStrea);
connection.setStreamEndHandler(yourExternalStrea);

Change User ID

Change userid using this method:

connection.changeUserId('your-new-userid');

ReUse Socket.io

Record Videos

<script src="https://cdn.WebRTC-Experiment.com/RecordRTC.js"></script>
<script>
var listOfRecorders = {};
connection.onstream = function(event) {
    var recorder = RecordRTC(event.stream, {
        type: 'video',
        recorderType: MediaStreamRecorder
    });

    recorder.startRecording();

    listOfRecorders[event.streamid] = recorder;
};

btnStopRecording.onclick = function() {
    var streamid = prompt('Enter stream-id');

    if(!listOfRecorders[streamid]) throw 'Wrong stream-id';

    var recorder = listOfRecorders[streamid];
    recorder.stopRecording(function() {
        var blob = recorder.getBlob();

        window.open( URL.createObjectURL(blob) );

        // or upload to server
        var formData = new FormData();
        formData.append('file', blob);
        $.post('/server-address', formData, serverCallback);
    });
};
</script>

Record All Videos In Single File

Wanna try a hack? You will be able to record entire tab + all audios.

First of all, install this Google Chrome extension:

Now, install last Google Chrome Canary. Remember, chrome version 53+.

Now open options page chrome://extensions/?options=ndcljioonkecdnaaihodjgiliohngojp and enable this check-box:

Enable audio+tab recording?

Now click "R" icon to record any tab. Above chrome-extension will record entire tab activity along with all audios at once!!!

To repeat, audio+tab recording option allows you record entire tab activity; all videos on tab, all audios on the tab, dashboards or any activity!

Again, above chrome extension requires Google Chrome version greater than or equal to 53.

Record Audio along with Screen

connection.session = {
    audio: true,
    screen: true
};

connection.onstream = function(event) {
    if(connection.attachStreams.length <= 1) return;

    var screenStream, audioStream;
    connection.attachStreams.forEach(function(stream) {
        if(stream.isScreen) screenStream = true;
        if(stream.isAudio) audioSTream = true;
    });

    if(!screenStream || !audioStream) return;

    var audioPlusScreenStream = new MediaStream();
    audioPlusScreenStream.addTrack( screenStream.getVideoTracks()[0] );
    audioPlusScreenStream.addTrack( audioStream.getAudioTracks()[0] );

    var recorder = RecordRTC(audioPlusScreenStream, {
        type: 'video',
        recorderType: MediaStreamRecorder
    });

    recorder.startRecording();
};

Share RoomID in the URL

There are two possible methods:

  1. Share room-id as URL-hash
  2. Share room-id as URL-query-parameters
var roomid = 'xyz';
connection.open(roomid, function() {
    var urlToShare = 'https://yourDomain.com/room.html#' + roomid;

    // or second technique
    var urlToShare = 'https://yourDomain.com/room.html?roomid=' + roomid;

    window.open(urlToShare);
});

Now target users can read room-id as following:

if(location.hash.length > 1) {
    var roomid = location.hash.replace('#', '');

    // auto join room
    connection.join(roomid);
}

Or read URL-query-parameters:

(function() {
    var params = {},
        r = /([^&=]+)=?([^&]*)/g;

    function d(s) {
        return decodeURIComponent(s.replace(/\+/g, ' '));
    }
    var match, search = window.location.search;
    while (match = r.exec(search.substring(1)))
        params[d(match[1])] = d(match[2]);
    window.params = params;
})();

if(params.roomid) {
    // auto join room
    connection.join(params.roomid);
}

If you want to hide HTML for non-moderators or for users that are MERELY expected to join a room:

if(params.roomid || location.hash.length > 1) { // whatever condition suits you
    $('.moderators-sections').hide();

    // or simple javascript
    Array.prototype.slice.call(document.querySelectorAll('.moderators-sections')).forEach(function(div) {
        div.style.display = 'none';

        // or
        div.parentNode.removeChild(div);
    });
}

PHP/ASPNET-MVC/Ruby developers can easily omit or remove those "redundant" HTML parts before serving the HTML to the browser.

Remember, both open, join, or openOrJoin all these methods supports second-callback-parameter, which means that either you joined or opened the room. E.g. connection.open('roomid', successCallback);

Detect Presence

RTCMultiConnection v2 users should check this wiki-page: https://github.com/muaz-khan/RTCMultiConnection/wiki/Presence-Detection

v3 users should check this API (connection.checkPresence):

v3 users can get list of existing public-rooms using this API (connection.getPublicModerators):

However v2 users can use connection.onNewSession event: http://www.rtcmulticonnection.org/docs/onNewSession/

Other Documents

  1. Getting Started guide for RTCMultiConnection
  2. Installation Guide
  3. How to Use?
  4. API Reference
  5. Upgrade from v2 to v3
  6. How to write iOS/Android applications?
  7. Tips & Tricks

Twitter

License

RTCMultiConnection is released under MIT licence . Copyright (c) Muaz Khan.