↑ www.RTCMultiConnection.org

RTCMultiConnection Changes Log ----/ Docs | FAQ | Demos!

Please visit this page for latest changes-log:


v3 - Its latest Beta release.

// Open-Sourced here:

// To install it:
sudo npm install rtcmulticonnection-v3

// or MOST preferred one
mkdir RTCMultiConnection-v3.0 && cd RTCMultiConnection-v3.0
wget http://dl.webrtc-experiment.com/rtcmulticonnection-v3.tar.gz
tar -zxvf rtcmulticonnection-v3.tar.gz
ls -a

// To test it:
node server.js

// if fails,
lsof -n -i4TCP:9001 | grep LISTEN
kill process-ID

// Now open: 


// install latest package
npm install rtcmulticonnection

// use latest file (v2.*.*)
<script src="./node_modules/rtcmulticonnection/RTCMultiConnection.js"></script>

// or instead of installing NPM package,
// directly link the file:
<script src="//cdn.webrtc-experiment.com/RTCMultiConnection.js"></script>
  1. NEW/Breaking changes:
    1. RTCMultiSession is renamed to "SignalingHandler"
    2. "PeerConnection" is renamed to "RTCPeerConnectionHandler"
    3. MultiSockets concept has been removed. Now there is always single socket.
  2. Now, "onSessionClosed" is fired as soon as initiator leaves, for all users---even for NON-connected users.
  3. Fixed: onstatechange isn't firing "request-accepted".
  4. Fixed: If stream is having no audio or video tracks but session=audio:true,video:true
  5. Renegotiation is fixed for Firefox. Removing old stream and using new one.
  6. takeSnapshot now returns "blob" as second argument.
  7. Added: connection.rtcConfiguration:
    connection.rtcConfiguration = {
        iceServers: [],
        iceTransports: 'all'
  8. hark.js updated. onspeaking is disabled for remote streams. Check Coding Tricks wiki page for further details.

    Now, stream object is having "pause" and "resume" methods to pause/resume hark.js instances.
  9. connection.numberOfConnectedUsers is fixed.
  10. connection.candidates={relay:true} fixed. (a=candidate is removed).
  11. Added: connection.attachExternalStream(MediaStream, isScreen);
        video: {
            chromeMediaSource: 'screen'
    }, function(stream) {
        connection.attachExternalStream(stream, true);
    }, function(error) {
  12. Fixed: audio-only stream & crash.
  13. connection.stopMediaStream improved.
  14. Screen capturing improved & some bugs fixed.

v2.0 / released in Sep 01, 2014

<script src="//cdn.webrtc-experiment.com/RTCMultiConnection-v2.0.js"></script>
  1. Latest updates: https://github.com/muaz-khan/RTCMultiConnection/commits/master
  2. v2.2.1 breaking updates:
    --. connection.stats.sessions is removed; use connection.sessionDescriptions instead.
    --. connection.stats.numberOfSessions is removed; use connection.numberOfSessions instead.
    --. connection.stats.numberOfConnectedUsers is removed; use connection.numberOfConnectedUsers instead.
    --. connection.getStats and connection.stats are removed.
  3. Duplicate "enumerateDevices" listing fixed.
  4. "connection.DetectRTC.screen.getChromeExtensionStatus" fixed.
    document.getElementById('add-screen').onclick = function() {
        connection.DetectRTC.screen.extensionid = 'your-own-extension-id';
        connection.DetectRTC.screen.getChromeExtensionStatus(function(status) {
            if(status == 'installed-enabled') {
                connection.addStream({ screen: true, oneway: true });
  5. Bug-Fixed: Now, MediaStream is removed from "attachStreams" array when stopped.
  6. Bug-Fixed: Now, OfferToReceiveAudio/OfferToReceiveVideo are "NOT" forced to be false even for data-only connections. Because it affects renegotiation scenarios.
  7. onStreamEndedHandler updated. "connection.onstreamended" is fired only when both "mediaElement" and "mediaElement.parentNode" are not NULL.
  8. connection.onopen is now having "event.channel" object.
  9. 2nd invocation of "createDataChannel" is disabled.
  10. Fixed: issue#11
  11. "connection.enableFileSharing" added.
    // to disable file sharing
    connection.enableFileSharing = false;
  12. Added: connection.peers['target-userid'].takeSnapshot(callback);
  13. Added: connection.streams['streamid'].takeSnapshot(callback);
  14. Fixed: "session={data:true}" must not having audio/video media lines.
  15. "onleave" is "merely" fired once for each user.
  16. "sync:false" added for "connection.streams['streamid'].mute" method.
    connection.streams.selectFirst({ local:true }).mute({
        video: true,
        sync: false // mute video locally--only
    // or
        audio: true,
        sync: false // mute audio locally--only
  17. "connection.mediaConstraints" updated.
    connection.mediaConstraints = {
        video: {
            mandatory: {},
            optional: []
        audio: {
            mandatory: {},
            optional: []
  18. "onstreamended" fixed. Ref
  19. Renegotiation fixed. It was a bug in 2.*.* < 2.1.7
  20. "connection.rtcConfiguration" added:
    connection.rtcConfiguration = {
        iceTransports: 'relay',
        iceServers: [iceServersArray]
  21. stopRecording "callback" fixed.
    connection.streams['streamid'].stopRecording(function(blobs) {
        // blobs.video
    }, { video: true });
  22. Now "onstreamended" is fired merely "once" for each stream.
  23. {audio:true,video:true} are forced for Android. All media-constraints skipped.
  24. Firefox screen capturing is HTTPs-only.
  25. Screen negotiations fixed. Screen can be renegotiated many times.
        screen: true,
        oneway: true
  26. "preferJSON" is removed. Now data is "always" sent as ArrayBuffer.
  27. "connection.candidates" has been fixed.
  28. Now, FileBufferReader is used for file sharing.
  29. FileSender/FileReceiver/FileConveter has been removed.
  30. onFileStart/onFileProgress/onFileEnd: now having "userid" and "extra" objects.
  31. When "muted" stream is negotiated; it fires "onmute" event as soon as as remote stream is received.
    var firstLocalStream = connection.streams.selectFirst({
        local: true
    // you can mute a stream before joining a session
        video: true
  32. Now, "autoReDialOnFailure" is "true" by default.
  33. connection.selectDevices is fixed.
    connection.selectDevices('audioinput-deviceid', 'videooutput-deviceid');
  34. "connection.enumerateDevices" and "connection.getMediaDevices" added.
    // to iterate over all available media devices
    connection.enumerateDevices(function(devices) {
        devices.forEach(function(device) {
            // device.deviceId
            // device.kind == 'audioinput' || 'audiooutput' || 'audio'
  35. "connection.changeBandwidth" added.
        audio: 30,
        video: 64
  36. "connection.streams.remove" added.
    // fire "onstreamended" for all screen streams
        isScreen: true
    // fire "onstreamended" for all local streams
        local: true
    // fire "onstreamended" for all remote audio-only streams
        isAudio: true,
        remote: true
  37. "connection.streams.selectFirst" and "connection.streams.selectAll" added.
    // first  local stream
    var firstLocalStream = connection.streams.selectFirst({
        local: true
    // all audio-only streams
    var allAudioOnlyStreams = connection.streams.selectAll({
        isAudio: true
    // a user's all streams
    var firstLocalScreenStream = connection.streams.selectAll({
        userid: 'remote-userid'
  38. "connection.streams.stop" improved.
    // stop a user's all screen streams
        userid: 'remote-userid',
        screen: true
  39. "connection.privileges.canStopRemoteStream" and "connection.privileges.canMuteRemoteStream" added:
    // set it "true" if you want to allow user to stop/mute remote stream
    connection.privileges = {
        canStopRemoteStream: true, // user can stop remote streams
        canMuteRemoteStream: true  // user can mute remote streams
    // otherwise, for "false" values, if user will try to programmatically invoke "stop" or "mute" method,
    // you'll be informed in the "onstatechange" event.
    connection.onstatechange = function(state) {
        if(state.name == 'stop-request-denied') {
        if(state.name == 'mute-request-denied') {
  40. Breaking changes for "connection.onstatechange". Now an "object" is passed over "onstatechange"
    connection.onstatechange = function(state) {
        // state.userid == 'target-userid' || 'browser'
        // state.extra  == 'target-user-extra-data' || {}
        // state.name  == 'short name'
        // state.reason == 'longer description'
        if(state.name == 'stop-request-denied') {
  41. "connection.streams.mute" updated:
    // mute all remote audio-only streams.
        isAudio: true,
        remote: true
    // unmute all local screen streams.
        isScreen: true,
        local: true
  42. Fixed #266 i.e. IE11 support added through PluginRTC (webrtc-everywhere).
  43. connection.UA updated for "is***":
  44. connection.preferJSON=true added. You can set "false" to send non-Blob types i.e. ArrayBuffer/ArrayBufferView/DataView etc.
    // Remember: it doesn't applies to file sharing.
    // it applies to all other kinds of data.
    connection.preferJSON = false;
    // send array buffer
    connection.send( new ArrayBuffer(10) );
    // get array buffer
    connection.onmessage =  function(event) {
        var buffer = event.data;
    // convert string to array-buffer
    connection.send( str2ab('a string test') );
    // parsing array-buffer back into string
    connection.onmessage =  function(event) {
        var string = ab2str(event.data);
    // this method converts array-buffer into string
    function ab2str(buf) {
        return String.fromCharCode.apply(null, new Uint16Array(buf));
    // this method converts string into array-buffer
    function str2ab(str) {
        var buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char
        var bufView = new Uint16Array(buf);
        for (var i = 0, strLen = str.length; i < strLen; i++) {
            bufView[i] = str.charCodeAt(i);
        return buf;
  45. connection.sharePartOfScreen fixed for sharing screen over multi-users:
        element: 'body', // element to share
        interval: 500    // how after take screenshots
  46. connection.getExternalIceServers is now "false" by default. If you want to use XirSys based ICE-Servers in your application, you MUST set it "true":
    // if you want to use XirSys-based STUN/TURN servers
    connection.getExternalIceServers = true;
  47. Now, "sendCustomMessage", "addStream", "switchStream", "renegotiate" and "removeStream" can be called even if there is no user connected.
    var connection = new RTCMultiConnection();
    // quickly after initializing constructor
    // call addStream to add screen
    // it will wait until a user is connected
    // and it will auto share/renegotiate your screen with first user
        screen: true,
        oneway: true
    // send a custom message
    // it will be sent as soon as first user connects with you
    connection.sendCustomMessage('hi, there');
  48. Added support for initial "inactive" sessions. You can setup audio/video connection however streams will be "inactive":
    // streams are on-hold:
    connection.session = {
        inactive: true,
        audio:    true,
        video:    true
    // to unhold streams later
    connection.unhold('both'); // both audio and video
  49. Added connection.waitUntilRemoteStreamStartsFlowing. It allows you override default Wait-Until-Remote-Stream-starts-flowing behaviour.
    connection.waitUntilRemoteStreamStartsFlowing = false;
  50. Added: connection.switchStream. It will remove all old local streams and add new stream.
    // remove all old streams and add screen in oneway.
        screen: true,
        oneway: true
  51. Fixed: TextSender is unable to send array.
    connection.send([1, 2, 3, 4, 5]);
  52. Added connection.disconnect:
    // it means that:
    // 1) close all sockets
    // 2) close all peers
    // 3) clear all data
    // 4) refresh everything
    // Note: local streams will be kept in "localStreams" object if "keepStreamsOpened" boolean is used.
    // it fires: 
    connection.ondisconnected = function(event) {
        if(event.isSocketsDisconnected == true) { }
  53. Updated: connection.removeStream:
    // remove all screen streams.
    // you can use "remove all video streams" by passing "video"
    // or "remove all audio streams" by passing "audio"
    // remove-all but multiple streams
    // i.e. remove all audio and video streams
    // or remove all audio and screen streams
        screen: true,
        audio: true
  54. Updated: connection.streams.stop:
    // stop any single stream: audio or video or screen
    // stop multiple streams
        remote: true,
        video: true,
        screen: true
  55. Data-channels "send" method improved.
    connection.send('longest-test' || big_array || blob || file);
  56. Fixed: onStreamEvent.isAudio/onStreamEvent.isVideo seems NULL in mute/unmute cases with only {audio:true} or {video:true}
    connection.onmute = function(event) {
  57. googTemporalLayeredScreencast and googLeakyBucket added for screen capturing.
  58. Updated connection.candidates:
    connection.candidates = {
        stun: true, // NEW property since v2.0
        turn: true, // NEW property since v2.0
        host: true
  59. Added connection.localStreams. All local streams are always kept in this object even if session is closed. Look at above section i.e. keepStreamsOpened.
    var stream = connection.localStreams['streamid'];
    // or
    connection.onSessionClosed = function() {
        var stream = connection.localStreams['streamid'];
    // or
    for(var streamid in connection.localStreams) {
        var stream = connection.localStreams[streamid];
  60. Added connection.log and connection.onlog. It allows you display logs in UI instead of in the console.
    // if you want to disable logs
    connection.log = false;
    connection.onlog = function(log) {
        var div = document.createElement('div');
        div.innerHTML = JSON.stringify(log, null, '<br>');
  61. Added connection.keepStreamsOpened. It allows you keep MediaStream active even if entire session is closed. It is useful in session-reinitiation scenarios.
    connection.keepStreamsOpened = true;
  62. Removed: connection.caniuse.checkIfScreenSharingFlagEnabled. It was redundant.
  63. webrtc-everywhere/temasys support added for Safari & IE11. PluginRTC

v1.9 / released in August 10, 2014

<script src="//cdn.webrtc-experiment.com/RTCMultiConnection.js"></script>

// or
<script src="//cdn.webrtc-experiment.com/RTCMultiConnection-v1.9.js"></script>

// or
<script src="//www.rtcmulticonnection.org/latest.js"></script>
  1. Workaround-added: Firefox don't yet support onended for any stream (remote/local)
  2. RTCMultiConnection is updated for audio+screen from single getUserMedia request for Firefox Nightly. Below snippet is sharing single video stream containing both audio/video tracks; and target browser is joining with only audio. Screen can be viewed on both chrome and Firefox. If you'll share from chrome, then it will be making multiple getUserMedia requests.
    // audio+video+screen will become audio+screen for Firefox
    // because Firefox isn't supporting multi-streams feature
    // initiator from Firefox
    initiator.session = {
        screen: true,
        audio: true
    // participant in chrome or Firefox
    participant.onNewSession = function(session) {
        session.join({ audio: true });
  3. Screen capturing support for Firefox nightly added. You simply need to open "about:config" on Firefox nightly and set "media.getusermedia.screensharing.enabled" to "true".
    // same for Firefox
    connection.session = {
        screen: true,
        oneway: true
  4. connection.dontCaptureUserMedia added:
    connection.dontCaptureUserMedia = true;
  5. connection.dontAttachStream updated:
    connection.dontAttachStream = true;
  6. connection.onstreamid added:
    // on getting remote stream's clue
    connection.onstreamid = function (e) {
        var mediaElement = document.createElement(e.isAudio ? 'audio' : 'video');
        mediaElement.controls = true;
        mediaElement.poster = connection.resources.muted;
        mediaElement.id = e.streamid;
  7. connection.peers['target-userid'].getStats added.
    connection.peers['target-userid'].peer.getStats(function (result) {
        // many useful statistics here
  8. connection.onconnected added.
    connection.onconnected = function (event) {
        log('Peer connection has been established between you and', event.userid);
        // event.peer.addStream || event.peer.removeStream || event.peer.changeBandwidth
        // event.peer == connection.peers[event.userid]
        event.peer.getStats(function (result) {
            // many useful statistics here
  9. connection.onfailed added.
    connection.onfailed = function (event) {
        // or event.peer.redial();
        // event.targetuser.browser == 'firefox' || 'chrome'
  10. connection.eject is fixed.
    // check if user is ejected
    // clear rooms-list if user is ejected
    connection.onSessionClosed = function (session) {
        if (session.isEjected) {
            warn(session.userid, 'ejected you.');
        } else warn('Session has been closed.', session);
        if (session.isEjected) {
            roomsList.innerHTML = '';
            roomsList.style.display = 'block';
  11. Fixed: remoteEvent.streamid and remoteEvent.isScreen:
    connection.onstream = function(event) {
        if(event.isScreen) {
            // it is screen
  12. Screen capturing is improved, and single google chrome extension is used to support capturing from all domains!
  13. connection.processSdp added.
    connection.processSdp = function(sdp) {
        sdp = remove_vp8_codecs(sdp);
        sdp = prefer_opus (sdp);
        sdp = use_maxaveragebitrate(sdp);
        return sdp;
  14. connection.session={} fixed. It allows moderator/initiator to become a listener/viewer i.e. it supports many-to-one scenarios:
    // for initiator
    connection.session = {};
    // for participants
    connection.onNewSession = function(session) {
            audio: true,
            video: true
  15. connection.mediaConstraints and connection.media are updated:
    connection.mediaConstraints = {
        mandatory: {
            maxWidth: 1920,
            maxHeight: 1080,
            minAspectRatio: 1.77,
            minFrameRate: 3,
            maxFrameRate: 64
        optional: [
            bandwidth: 256
  16. connection.onstream is updated for event.isScreen:
    connection.onstream = function (event) {
        if(event.isScreen) {
            // it is screen stream
        if(event.isAudio) {
            // it is audio-only stream
        if(event.isVideo) {
            // it is audio+video stream
  17. connection.refresh is updated and session re-initiation is improved.
    // you simply need to invoke "connection.leave" to 
    // leave a session so that you can rejoin same session
    connection.onstatechange = function (state) {
        if(state == 'connected-with-initiator') {
            document.getElementById('leave-session').disabled = false;
    document.getElementById('leave-session').onclick = function() {
  18. connection.iceProtocols added.
    connection.iceProtocols = {
        tcp: true, // prefer using TCP-candidates
        udp: true  // prefer using UDP-candidates
  19. Use custom chrome extension for screen capturing:
    connection.DetectRTC.screen.extensionid = 'your-app-store-extensionid';
  20. STUN/TURN servers are updated; as well as ICE-servers from XirSys are used:
    // to disable XirSys ICE-Servers
    connection.getExternalIceServers = false;
  21. connection.preventSSLAutoAllowed is disabled.
    // to enable it
    connection.preventSSLAutoAllowed = true;

v1.8 / released in June 28, 2014

<script src="//cdn.webrtc-experiment.com/RTCMultiConnection-v1.8.js"></script>
  1. (to fix canary ipv6 candidates issues): disabled "googIPv6", "googDscp" and "googImprovedWifiBwe"
  2. "connection.leaveOnPageUnload" added.
    // if you want to prevent/override/bypass default behaviour
    connection.leaveOnPageUnload = false;
    // display a notification box
    window.addEventListener('beforeunload', function () {
        return 'Are you want to leave?';
    }, false);
    // leave here
    window.addEventListener('unload', function () {
    }, false);
  3. -. renegotiation scenarios that fails:
    -. 1) if chrome starts video-only session and firefox joins with only audio
    -. 2) if chrome starts with audio-only session and firefox joins with only video
    -. 3) if chrome starts only audio and firefox joins with audio+video
    -. renegotiation scenarios that works:
    -. 1) if chrome starts audio+video and firefox joins with only audio or audio+video
    -. 2) if both browsers has similar streams
  4. "connection.onstatechange" added:
    connection.onstatechange = function (state, reason) {
        // fetching-usermedia
        // usermedia-fetched
        // detecting-room-presence
        // room-not-available
        // room-available
        // connecting-with-initiator
        // connected-with-initiator
        // failed---has reason
        // request-accepted
        // request-rejected
        if(state == 'room-not-available') {
            // room no longer exist
    Remember, older "onstats" event has been removed in v1.8.
  5. Now if you'll invoke "connection.sharePartOfScreen(...)" and a new user will join you; existing part of screen will be auto shared with him.

    It means that "sharePartOfScreen" will work with all new/old users.
  6. "connection.donotJoin" added:
    connection.onstatechange = function (state) {
        if(state == 'room-not-available') {
  7. You can set connection.DetectRTC.screen.extensionid="your-chrome-extensionid" to make sure inline (newly) installed chrome extension is quickly used for screen capturing instead of prompting user to reload page once to use it.

    It means that install the chrome extension and RTCMultiConnection will auto use it. Don't ask your users to reload the page:
    connection.DetectRTC.screen.extensionid = 'ajhifddimkapgcifgcodmmfdlknahffk';
  8. Fixed: If Chrome starts video-only session; and Firefox joins with only audio. Then both fails to connect; though sendrecv/recvonly/sendonly everything is correctly implemented.
  9. Fixed: "the videos are not square and they look grainy not has sharp as before". Now video is captured & streamed with better quality.
  10. "connection.DetectRTC.hasSpeakers" added.
  11. "connection.resumePartOfScreenSharing()" added.
  12. "event.blobURL" in the onstream event is fixed for Firefox.
    connection.onstream = function(e) {
        // e.blobURL -- now it is always blob:URI
  13. startRecording/stopRecording updated & fixed.
    // record both audio and video
        audio: true,
        video: true
    // stop both audio and video
    connection.streams['stream-id'].stopRecording(function (blob) {
        // blob.audio  --- audio blob
        // blob.video  --- video blob
    }, {audio:true, video:true} );
  14. "PreRecordedMediaStreamer" is moved to a separate javascript file.
  15. function "stopTracks" updated.
  16. Fixed connection.streams.stop() via issue #255.
  17. Now, you can easily manage external resources/URLs using "connection.resources":
    connection.resources = {
        RecordRTC: 'https://www.webrtc-experiment.com/RecordRTC.js',
        PreRecordedMediaStreamer: 'https://www.rtcmulticonnection.org/PreRecordedMediaStreamer.js',
        customGetUserMediaBar: 'https://www.webrtc-experiment.com/navigator.customGetUserMediaBar.js',
        html2canvas: 'https://www.webrtc-experiment.com/screenshot.js',
        hark: 'https://www.rtcmulticonnection.org/hark.js',
        firebase: 'https://www.rtcmulticonnection.org/firebase.js',
        firebaseio: 'https://chat.firebaseIO.com/',
        muted: 'https://www.webrtc-experiment.com/images/muted.png'
  18. connection.DetectRTC.MediaDevices added:
    // to iterate over all available media devices
    connection.getDevices(function() {
        connection.DetectRTC.MediaDevices.forEach(function(device) {
            // device.deviceId
            // device.kind == 'audioinput' || 'audiooutput' || 'audio'
  19. Now, hark.js is used instead of SoundMeter.js:
    connection.onspeaking = function() {};
    connection.onsilence = function() {};
  20. captureUserMediaOnDemand added for connection.open method:
    // it is "disabled" by default
    // captureUserMediaOnDemand means that "getUserMedia" API for initiator will 
    // be invoked only when required.
    // i.e. when first participant is detected.
    // you can enable it by setting it to "true"
        captureUserMediaOnDemand: true
  21. connection.DetectRTC.screen.getChromeExtensionStatus added.
    var extensionid = 'ajhifddimkapgcifgcodmmfdlknahffk';
    connection.DetectRTC.screen.getChromeExtensionStatus(extensionid, function(status) {
        if(status == 'installed-enabled') {
            // chrome extension is installed & enabled.
        if(status == 'installed-disabled') {
            // chrome extension is installed but disabled.
        if(status == 'not-installed') {
            // chrome extension is not installed
        if(status == 'not-chrome') {
            // using non-chrome browser
  22. onMediaCaptured added for connection.open method:
        onMediaCaptured: function() {
            // initiator enable camera/microphone
            // you can share "sessionDescription" with other users
            // and they can quickly join initiator!
  23. openSignalingChannel is moved to "setDefaults" private function.
  24. connection.preventSSLAutoAllowed added. Now RTCMultiConnection focuses more on end-users privacy! You can ask RTCMultiConnection to "always" display "getUserMedia-permission-bar" even if chrome is running on HTTPs i.e. SSL domain:
    // by default "preventSSLAutoAllowed" is true only for "HTTPs" domains
    // you can force it for HTTP domains as well by setting this Boolean in your HTML page.
    connection.preventSSLAutoAllowed = true;
  25. onScreenCapturingExtensionAvailable is fired when RTCMultiConnection detects that chrome extension for screen capturing is installed and available:
    connection.onScreenCapturingExtensionAvailable = function() {
        btnInlineInstallButton.disabled = true;
  26. Now, connection.join method allows you force how to join (i.e. with or without streams etc.):
    // it doesn't matter if incoming stream is audio+video
    // you can join it with only audio or with only video
    // or anonymously i.e. { oneway: true }
    var joinWith = {
        audio: true
    connection.join('sessionid', joinWith); // 2nd parameter
  27. Now, onNewSession is fired once for each room. It will NEVER fire multiple times.
  28. chrome.desktopCapture.chooseDesktopMedia is now preferred for screen capturing; and if extension is not installed or disabled, then RTCMultiConnection will auto fallback to command-line flag oriented screen-capturing API; and if both are not available then it will throw a clear "human readable" exception.

    Chrome extension is available here.
  29. You can use connection.DetectRTC like this:
    connection.DetectRTC.load(function() {
        if(connection.DetectRTC.hasMicrophone) { }
        if(connection.DetectRTC.hasWebcam) { }
    connection.DetectRTC.screen.isChromeExtensionAvailable(function(available) {
        if(available) alert('Chrome screen capturing extension is installed and available.');
  30. navigator.getUserMedia errors handling in onMediaError event:
    connection.onMediaError = function(error) {
        if(error.name == 'PermissionDeniedError') {

v1.7 / released in May 14, 2014

v1.7 focused on reliable API invocation, reliable concurrent users connectivity, and more. A few other features were added in this build like part of screen streaming, pre-recorded media streaming, ice-trickling booleans, and obviously DetectRTC!
<script src="//cdn.webrtc-experiment.com/RTCMultiConnection-v1.7.js"></script>
  1. connection.trickleIce added. Useful if you're using XHR/SIP/XMPP for signaling. XHR Demo
    // to ask RTCMultiConnection to wait until all ICE candidates
    // are gathered; and all ice are merged in the SDP
    // you JUST need to share that SDP "only"!
    connection.trickleIce = false;
  2. You can use "connection.DetectRTC" to detect WebRTC features!
    if(connection.DetectRTC.isWebRTCSupported) {}
    if(connection.DetectRTC.hasMicrophone) {}
    if(connection.DetectRTC.hasWebcam) {}
  3. Following scenarios implemented:
    1. if system doesn't have any microphone attached; RTCMultiConnection will skip "{audio:true}" and prompt only "{video: true}"
    2. if system doesn't have any webcam attached; RTCMultiConnection will skip "{video:true}" and prompt only "{audio: true}"
  4. Previously "connection.renegotiatedSessions" was an array; now it is object.
    // sometimes you try to manually fetch media streams
    // sometimes you allow a user to enable webcam ... but don't renegotiate quickly..
    // you may want to ask other user to invoke "renegotiate" function
    // you may want to override default behaviours
    // below code snippet is used in MultiRTC demo in "ui-peer-connection.js" file
    var session = {
        audio: true // you're manually capturing audio
    connection.captureUserMedia(function (stream) {
        // you can see that "renegotiatedSessions" is an object
        // because we wanted to prevent duplicate entries
        connection.renegotiatedSessions[ JSON.stringify(session) ] = {
            session: session,
            stream: stream
    }, session);
  5. Now, using default camera resolutions instead of using minWidth/minHeight and maxWidth/maxHeight. You can easily override those values:
    connection.mediaConstraints.mandatory = {
        minWidth: 1280,
        maxWidth: 1280,
        minHeight: 720,
        maxHeight: 720,
        minAspectRatio: 1.77
  6. Now, auto redials while you're renegotiating and any single browser is firefox!
  7. Previously-renegotiated streams and new users renegotiation has been improved.
  8. Now, auto injecting VoiceActivityDetection:true for chrome to make sure c=IN is always present; otherwise b=AS will fail.
  9. connection.dontOverrideSession added:
    // dont-override-session allows you force RTCMultiConnection
    // to not override default session of participants;
    // by default, session is always overridden and set to the session coming from initiator!
    connection.dontOverrideSession = true;
  10. connection.askToShareParticipants and connection.shareParticipants added. Useful in multi-broadcasters and many viewers scenarios!
    connection.onstream = function (e) {
        if (e.type == 'remote' && role == 'Anonymous Viewer') {
            // because "viewer" joined room as "oneway:true"
            // initiator will NEVER share participants
            // to manually ask for participants;
            // call "askToShareParticipants" method.
        // if you're moderator
        // if stream-type is 'remote'
        // if target user is broadcaster!
        if (connection.isInitiator && e.type == 'remote' && !e.session.oneway) {
            // call "shareParticipants" to manually share participants with all connected users!
                dontShareWith: e.userid
  11. connection.join('sessionid') has been improved.
  12. Now you can pass "sessionid" over "join" method!
    // make sure that room is created!
    // otherwise this "join" method will fail to join the room!
    // "join" method NEVER waits for onNewSession!!
    // it directly "joins" the room!
  13. Session re-initiation has been fixed. You can leave/rejoin many times.
  14. Admin/Guest features has been removed. You should use v1.6 or earlier to use admin/guest features.
  15. screen:300kbps added in connection.bandwidth:
    // by default
    connection.bandwidth = {
        screen: 300
    // if you're using node-webkit; then you MUST set it to NULL
    // make sure that it is set both for browser-client and node-webkit!
    connection.bandwidth.screen = null;
  16. Now, you can check connection.stats.numberOfSessions in a specific channel:
    alert( connection.stats.numberOfSessions );
    // You can even access all sessions using this object-like array:
    alert( connection.stats.sessions['sessionid'] );
    // or
    for(var session in connection.stats.sessions) {
    // You can get above values usnig "getStats" method as well:
    connection.getStats(function(stat) {
        for(var session in stat.sessions) {
  17. Now, multiple users can join a room at the same time and all will be interconnected!
  18. Now, "streamid" is synced among all users! You can mute/unmute or stop single stream-id and it will affect among all connected users!
  19. autoReDialOnFailure added. You can force RTCMultiConnection to auto redial if peer connection is dropped unexpectedly or failed out of any exception!
    // by default, it is "false"
    // it is false because workaround that is used to capture connections' failures
    // affects renegotiation scenarios!
    connection.autoReDialOnFailure = true;
  20. You can override setDefaultEventsForMediaElement to prevent default mute/unmute handlers on media elements.
    // by default it captures "onplay", "onpause" and "onvolumechange" events for all media elements
    connection.setDefaultEventsForMediaElement = false;
  21. onpartofscreenstopped and onpartofscreenpaused added:
    // invoked when you "manually" stopped part-of-screen sharing!
    connection.onpartofscreenstopped = function() {};
    // invoked when you "manually" paused part-of-screen sharing!
    connection.onpartofscreenpaused = function() {};
  22. Now, you can call sharePartOfScreen, pausePartOfScreenSharing and stopPartOfScreenSharing for all users:
        element: '#div-id', // querySelector or HTMLElement
        interval: 1000      // milliseconds
  23. hold/unhold of individual media lines implemented:
    // hold only your audio
    connection.onhold = function(track) {
        if(track.kind == 'audio') {}
    // hold only your video
    connection.onunhold = function(track) {
        if(track.kind == 'video') {}
    // unhold all your 'video' m-lines
    // hold all your 'audio' m-lines
  24. When you mute/unmute; video-controls are synced among all users! Volume is also synced!
  25. window.skipRTCMultiConnectionLogs is replaced with connection.skipLogs method:
  26. Part of screen sharing has been implemented:
    // to share a DIV or region of screen with a specific user
        element: 'body', // querySelector or HTMLElement
        interval: 1000   // milliseconds
    // to capture shared parts of screen
    // var image = document.querySelector('img');
    connection.onpartofscreen = function (e) {
        // image.src = e.screenshot;
    // to pause part-of-screen sharing
    connection.peers['target-userid'].pausePartOfScreenSharing = true;
    // to stop part-of-screen sharing
    connection.peers['target-userid'].stopPartOfScreenSharing = true;
  27. Now, open method returns "sessionDescription" object. "open" method also accepts an object as well!
    1. join method can be used to join that "sessionDescription" anytime without connecting to signaling channel!
    2. For initiator:

      var initiator = new RTCMultiConnection();
      // you can pass object instead of string!
      var sessionDescription = initiator.open({
          dontTransmit: true
    3. For participant:

      var participant = new RTCMultiConnection();
      websocket.onmessage = function(event) {
          var sessionDescription = event.data.sessionDescription;
          participant.join( sessionDescription );
  28. Now, removeStream method quickly removes streams and auto renegotiates. You can also call removeStream over peers object:
    connection.peers['target-userid'].removeStream( 'stream-id' );
  29. Now, onRequest is fired only for session-initiator.
  30. "shareMediaFile" and "onMediaFile" added. (i.e. pre-recorded media support added):
    // select WebM file to share as pre-recorded media!
    document.querySelector('input[type=file]').onchange = function() {
        connection.shareMediaFile( this.files[0] );
    // receive WebM files
    connection.onMediaFile = function(e) {
        // e.mediaElement (it is video-element)
        // e.userid
        // e.extra
        yourExistingVideoElement.src = e.mediaElement.src;
        // or
  31. Mute/UnMute and "onstreamended" among multiple users, issues fixed.
  32. Now, "getDevices" method skips duplicate devices and returns array of unique audio/video devices.
  33. Now, "onFileStart", "onFileProgress" and "onFileEnd" has remote user's ID, "sending" object and "extra" object:
    // file sending or receiving instance is started.
    connection.onFileStart = function(file) {
        // file.userid  ---- userid of the file sender
        // file.extra   ---- extra data from file sender
        // file.sending ---- true or false
    // file sending or receiving instance is ended.
    connection.onFileEnd = function(file) {
        // file.userid  ---- userid of the file sender
        // file.extra    ---- extra data from file sender
        // file.sending ---- true or false
    // file sending or receiving instance is working.
    connection.onFileProgress = function(chunk) {
        // chunk.userid  ---- userid of the file sender
        // chunk.extra    ---- extra data from file sender
        // chunk.sending ---- true or false
  34. "onstream" has two new objects:
    connection.onstream = function(e) {
        // e.isVideo ---- if it is a  Video stream
        // e.isAudio ---- if it is an Audio stream
  35. File chunk-size and chunk-interval are fixed for Firefox.
  36. Now, when renegotiating media streams, v1.7 checks to verify if remote stream is delivered to end-user; if delivery fails, v1.7 auto tries renegotiation again.
  37. Now, "isAcceptNewSession" is shifted to root-level. Using this feature, you can allow single user to join multiple rooms from the same channel:
    connection.onstream = function(event) {
        if(event.type == 'remote') {
            // set "isAcceptNewSession=true" so this user can get and join new session i.e. room
            // it means that "onNewSession" will be fired for this user as soon as other room is available!
            connection.isAcceptNewSession = true;
  38. Now, "session" object is always passed over "onstreamended" event; so, you can check which stream is stopped: screen or audio/video:
    connection.onstreamended = function(event) {
        if(event.session.screen) { }                        // if screen stream is stopped.
        if(event.session.audio && !event.session.video) { } // if audio stream is stopped.
        if(event.session.audio && event.session.video) { }  // if audio+video stream is stopped.
        // event.type == 'local' || 'remote'
  39. v1.6 and earlier releases has a bug for renegotiated streams. When you try to stop renegotiated stream; it is removed only from 1st participant; not from all participants. This issue has been fixed in v1.7.
  40. "forceToStopRemoteStream" added.
    var forceToStopRemoteStream = true;
    connection.streams['remote-stream-id'].stop( forceToStopRemoteStream );
    This feature was disabled since v1.4 however now enabled by passing a single boolean over "stop" method.
  41. Default session is always kept there; it was a bug in v1.6 and earlier releases. Each new renegotiated session was overriding old sessions.
  42. Renegotiated sessions are always stored; and always renegotiated to newcomers.
  43. Renegotiation of external streams along with external session added.
  44. Remote stream stop & removal issues fixed. Now, "onstreamended" is always fired for all users according to the stream stopped.
  45. "setDefaultEventsForMediaElement" added. i.e. mute/unmute are implemented by default! When you'll click mute button from native video control; v1.7 will auto invoke "mute" among all relevant peers.

v1.6 / released in Jan 29, 2014

<script src="//cdn.webrtc-experiment.com/RTCMultiConnection-v1.6.js"></script>
  1. Now v1.6 is capable to auto-redial if connection is dropped by any mean. (This feature is disabled because it was affecting renegotiation process).
  2. Now you can join as audio-only, video-only or screen-only stream both on chrome and firefox:
    1. // original session is "audio-only" stream
      connection.session = { audio: true };
      connection.onNewSession = function(session) {
          // join with both audio and video!
          session.join({audio: true, video: true});
    2. // original session is "audio+video" stream
      connection.session = { audio: true, video: true };
      connection.onNewSession = function(session) {
          // join with audio-only stream!
          session.join({audio: true});
  3. "fakeDataChannels" added. Using "fakeDataChannels" object you can setup fake data connection while you're sharing audio/video/screen. You can do text-chat; share files; etc. without using WebRTC data channels.
    // audio+video and fake data connection
    connection.fakeDataChannels = true;
    connection.session = { audio: true, video: true };
    // only fake data connection; no audio; no video; no WebRTC data channel!
    connection.fakeDataChannels = true;
    connection.session = { };
  4. "UA" object added. It returns whether browser is chrome; firefox or mobile device:
    var isFirefox = connection.UA.Firefox;
    var isChrome = connection.UA.Chrome;
    var isMobileDevice = connection.UA.Mobile;
  5. Now you can renegotiate data-connection in your existing audio/video/screen session!
        data: true
  6. Pull #152 merged for "token" method:
    var randomString = connection.token();
    connection.userid = connection.token();
  7. "autoTranslateText" method added:
    // all incoming text messages will be converted in this language
    // by default, it is "en-US"
    connection.language = 'ja'; // prefer Japanese
    // it is "false" by default.
    connection.autoTranslateText = true;
    // you can use "e.data" and "e.original"
    connection.onmessage = function(e) {
       // e.data     ---- translated text
       // e.original ---- original text
    connection.Translator.TranslateText(textToConvert, function(convertedText) {
  8. "session.join" method added. Remember, it is "session.join"; it isn't "connection.join"!
    connection.onNewSession = function(session) {
        session.join();                           // join session as it is!
        session.join({audio: true});              // join session while allowing only audio
        session.join({video: true});              // join session while allowing only video
        session.join({screen: true});             // join session while allowing only screen
        session.join({audio: true, video: true}); // join session while allowing both audio and video
  9. Bug #152 fixed.
  10. Now, MRecordRTC is used for audio/video recording!
  11. "saveToDisk" method added. You can invoke save-as dialog like this:
    // "fileName" is optional
    connection.saveToDisk(fileURL, fileName);
    // you can save recorded blob to disk like this:
    connection.streams['stream-id'].stopRecording(function (audioBlob, videoBlob) {
    }, {audio:true, video:true} );
  12. If you're recording both audio and video; then "stopRecording" will return both blobs in the single callback; where 1st parameter value will be audio-blob; and 2nd parameter value will be video-blob:
    // stop both audio/video streams
    connection.streams['stream-id'].stopRecording(function (audioBlob, videoBlob) {
        // POST both audio/video "Blobs" to PHP/other server using single FormData/XHR2
    }, {audio:true, video:true} );
  13. "onhold" and "onunhold" events added:
    // to hold call; same like skype!
    connection.onhold = function(e) {
    	// e.mediaElement || e.stream || e.userid || e.streamid
    // to unhold call; same like skype!
    connection.onunhold = function(e) {
    	// e.mediaElement || e.stream || e.userid || e.streamid
  14. Many method has been added in "peers" object.
    // renegotiate while adding external media streams
    // renegotiate while no media stream is added
    // change bandwidth at runtime
        audio: 20,
        video: 30,
        data: 50
    // send private message to target user; privacy is guaranteed!
    connection.peers['user-id'].onCustomMessage = function(privateMessage) {
        console.log('private custom message', privateMessage);
    // to drop call; same like skype!
    // to hold call; same like skype!
    // to unhold call; same like skype!
    1. "changeBandwidth" method is useful to modify bandwidth usage at runtime!
    2. "drop" method is useful to drop call between two users same like skype!
    3. "sendCustomMessage" and "onCustomMessage" are useful to exchange private data between two users where your preferred signaling solution is used to send data i.e. it works all the time! Remember, there is a public version of "sendCustomMessage" as well!
    4. "hold" and "unhold" works same like skype!
  15. "renegotiate" method added.
    // renegotiate with/without media streams!

    "renegotiate" method works same like "addStream" however it gives you a little bit more control over renegotiation process!

    If connection is suddently dropped; or connection has not been established for 5 seconds; then you can use "renegotiate" method to retry/redial.

    In multi-user connectivity scenarios; it is suggested to try "peers" object to renegotiate/retry/redial connections. See next section for more details.

  16. "refresh" method added.

    Using "refresh" method; you can refresh/reload the RTCMultiConnection object!

  17. "remove" method added.

    Using "remove" method; you can clear all sockets, peers and streams coming from that user; so that he can reconnect to the same session!

  18. File sharing is improved! Chrome/Firefox interoperability support added.
  19. "preferSCTP" is now enabled by default.
  20. "chunkSize" added. You can set 64k chunk-size for chrome-to-chrome SCTP-data streaming!
    // for chrome-to-chrome data streaming only!
    connection.chunkSize = 64 * 1000;
    // default value is 15k because Firefox's receiving limit is 16k!
    connection.chunkSize = 15 * 1000;
  21. All possible "complex" renegotiation scenarios are supported!
    1. You can select any participant to broadcast his screen or media stream in oneway direction over all connected users!
    2. There can be 5 broadcasters; and many viewers/listeners!
    3. Each and every skype-like feature is possible using v1.6! You can add/remove streams many times using existing peer connections!

v1.5 / released in Dec 31, 2013

<script src="//cdn.webrtc-experiment.com/RTCMultiConnection-v1.5.js"></script>
  1. You can get list of devices using "getDevices" method and prefer any single or two audio/video devices using "selectDevices" method.
    // get list of devices
        for (var device in devices) {
            device = devices[device];
            // device.kind == 'audio' || 'video'
            console.log(device.id, device.label);
    // select any audio and/or video device
    connection.selectDevices(firstDeviceID, secondDeviceID);
  2. "onspeaking" and "onsilence" added.
    connection.onspeaking = function (e) {
        // e.streamid, e.userid, e.stream, etc.
        e.mediaElement.style.border = '1px solid red';
    connection.onsilence = function (e) {
        // e.streamid, e.userid, e.stream, etc.
        e.mediaElement.style.border = '';
  3. "connection.streams.stop" added to stop all local/remote streams.
    // stop all local media streams
    // stop all remote media streams
    // stop all media streams
  4. mute/unmute and "stop" fixed both for chrome and firefox.
  5. onmute/onunmute auto displays "poster" if not overridden! (both on chrome and firefox)
    connection.onmute = function(e) {
    connection.onunmute = function (e) {
  6. If screen-sharing is stopped using blue button, "onstreamended" will be auto fired for both users!
  7. "onstream" auto appends video to "document.body" element; if not overridden!
  8. Default file progress-bar implemented.
  9. You can manage videos and "progress-bar" container element by setting "connection.body".

    <div class="container"></div>
    connection.body = document.querySelector('.container');
  10. Throws a clear error if users try to interop RTP-datachannels with SCTP.
  11. onmute/onunmute are fixed for both local and remote media streams. Both streams will be auto-synced!
  12. Now, only session-initiator can eject a user.
  13. takeSnapshot/snapshots added:
    // iterate over all snapshots/
    for(var snapshot in connection.snapshots) {
        snapshot = connection.snapshots[snapshot];
    // or, to access individual snapshot later
    image.src = connection.snapshots['userid'];
    // to take a snapshot
    connection.takeSnapshot('userid', function(snapshot) {
        image.src = snapshot;
  14. Session initiator can now stop remote media streams. It works same like eject method:
  15. reject method added. Now, you can reject any request in onRequest event.:
    connection.onRequest = function (request) {
    // "onstats" event can be used to know whether request is rejected or accepted
    connection.onstats = function (stats, callee) {
        // callee rejected the request
        if (stats == 'rejected') {}
        // callee accepted caller's request
        if (stats == 'accepted') {}
        // callee.userid || callee.extra
  16. getStats and stats added.
    connection.getStats(function(stat) {
        // stat.numberOfConnectedUsers
    for(var stat in connection.stats) {
        console.log(stat, connection.stats[stat]);
    // you can directly access "numberOfConnectedUsers" later like this:
  17. caniuse added.
    console.log( connection.caniuse.RTCPeerConnection );
    console.log( connection.caniuse.getUserMedia );
    console.log( connection.caniuse.AudioContext );
    console.log( connection.caniuse.ScreenSharing );
    console.log( connection.caniuse.RtpDataChannels );
    console.log( connection.caniuse.SctpDataChannels );
    connection.caniuse.checkIfScreenSharingFlagEnabled(function (isFlagEnabled, warning) {
        if (isFlagEnabled) {
            console.error('Multi-capturing of screen is not allowed. Capturing process is denied. Try chrome >= M31.');
        if (warning) console.error(warning);
        else if (!isFlagEnabled) {
            console.error('It seems that "Enable screen capture support in getUserMedia" flag is not enabled.');
  18. "drop" added. Using drop method; you can drop the call, same like skype! This method will detach all "local" media streams from both sides.
  19. "ondrop" event added. It is fired if other user drops the call.
    // "ondrop" is fired; if media-connection is droppped by other user
    connection.ondrop = function() { };
  20. "sendCustomMessage" added. Using sendCustomMessage method; you can share public messages over the default socket. E.g.
    1. State of the session-participant or session-initiator; whether he is going to leave; or going to share a media stream.
    2. Ask a session-participant to broadcast screen or video in one-way direction.
    3. Ask session-participants to attach audio stream; even if it is oneway stream coming from session-initiator.
    4. There are unlimited scenarios; that can be accomplished using sendCustomMessage method; just imagine and go ahead and use it!
  21. connection.sendCustomMessage(any_kind_of_data |or| string_message);
  22. "onCustomMessage" event added. Custom messages can be received using onCustomMessage event.
    connection.onCustomMessage = function(message) { };
  23. Echo issue; i.e. self-sound playback fixed.
  24. "stopRecording" now returns both audio/video blobs in the single "callback"!
    // stop single audio stream
    connection.streams['stream-id'].stopRecording(function (blob) {
        // POST "Blob" to PHP/other server using FormData/XHR2
    }, {audio:true});
    // stop single video stream
    connection.streams['stream-id'].stopRecording(function (blob) {
        // POST "Blob" to PHP/other server using FormData/XHR2
    }, {video:true});
    // stop both audio/video streams
    connection.streams['stream-id'].stopRecording(function (audioBlob, videoBlob) {
        // POST both audio/video "Blobs" to PHP/other server using single FormData/XHR2
    }, {audio:true, video:true} );

v1.4 / released in July 06, 2013

<script src="//cdn.webrtc-experiment.com/RTCMultiConnection-v1.4.js"></script>
  1. Multiple concurrent files transmission / see commit
  2. Advance renegotiation
  3. Admin/Guest features; useful in realtime chatting rooms where direct invitation is mandatory / see commit
  4. Multi-streams attachment i.e. audio+video+data+screen / see commit
  5. Mute/UnMute/Stop of individual, all at once; all remote or all local streams
  6. onstreamended added; a better method comparing "onleave"
  7. maxParticipantsAllowed added
  8. media/sdp constraints / see commit
  9. Session re-initiation / see commit
  10. removeStream added to allow removal of existing media streams
  11. disableDtlsSrtp added to fix renegotiation process which fails on chrome when DTLS/SRTP enabled
  12. autoSaveToDisk added to allow customization of file-sharing
  13. file-sharing extended and fixed; no crash for large files anymore!
  14. renegotiation for chrome M29 and upper
  15. sctp/reliable data channels support for chrome (unreliable is still default)
  16. enable/disable ice candidates (host/relfexive/relay)
  17. enable/disable bandwidth sdp parameters (by default, enabled)
  18. noise/echo stepped down; a simple/lazy workaround
  19. audio/video recording added / using RecordRTC
  20. directions simplified
  21. SCTP data channels are preferred / preferSCTP
  22. onmute/onunmute added. Demo
  23. File queue support added. Previously shared files will be auto transmitted to each new peer.

v1.3 / released in May 19, 2013

<script src="//cdn.webrtc-experiment.com/RTCMultiConnection-v1.3.js"></script>
  1. Syntax changed; a few breaking changes comparing v1.2 / see commit
  2. Simple renegotiation
  3. Mute/UnMute of individual streams
  4. Auto-session establishment feature removed
  5. Application specific bandwidth (b=AS) / see commit and commit
  6. Direct Messages
  7. New TURN format added / see commit / IETF Draft
  8. Compatible to socket.io over node.js / see commit

v1.2 / released in April 20, 2013

<script src="//cdn.webrtc-experiment.com/RTCMultiConnection-v1.2.js"></script>
  1. Multi-session establishment
  2. Auto-session establishment
  3. Manual-session establishment
  4. A little bit clear session/direction values e.g.
    connection.session='audio + video and data'
  5. Users ejection, rejection and presence detection / see commit
  6. Keep session active all the time; event if initiator leaves / see commit
  7. Custom data i.e. extra data transmission
  8. Audio-only streaming fixed / see commit
  9. Custom Handlers for server i.e. transmitRoomOnce

v1.1 / released in March 25, 2013

<script src="//cdn.webrtc-experiment.com/RTCMultiConnection-v1.1.js"></script>
  1. Multiple sessions & directions / see commit
  2. File, data and text sharing (of any size & length)
  3. Chrome/Firefox interoperability
  4. Firefox's new DataChannel syntax implemented / see commit

Latest Issues

Want to ask a Question?

You can include your email for private conversation!

Latest Updates