Code Monkey home page Code Monkey logo

rtcmulticonnection's Introduction

RTCMultiConnection - WebRTC JavaScript Library

npm downloads Build Status: Linux

v3 has its own built-in socket.io server. It has pubnub/firebase demos as well; however reliable-signaler or socketio-over-nodejs or similar codes can NOT be used with v3. Please use Signaling-Server.js instead.

v3 can use XHR/XMPP/etc. signaling implementations as well. Please check PubNubConnection.js to see how to configure it for 3rd party signaling implementations. You simply have to modify top few lines.

Install

Or fetch latest code via github:

git clone https://github.com/muaz-khan/RTCMultiConnection.git ./RTCMultiConnection
cd RTCMultiConnection
sudo npm install --save-dev

Or wget/TAR:

mkdir RTCMultiConnection-v3
cd RTCMultiConnection-v3
wget http://dl.webrtc-experiment.com/rtcmulticonnection-v3.tar.gz
tar -zxvf rtcmulticonnection-v3.tar.gz
ls -a

To TEST:

node server.js

If above command fails:

lsof -n -i4TCP:9001 | grep LISTEN
kill process-ID

Or kill specific port. It may require "sudo" privileges:

fuser -vk 9001/tcp

Now open: https://localhost:9001/

Keep running server in background

nohup nodejs server.js > /dev/null 2>&1 &

Or:

nohup nodejs server.js &

Or use forever:

npm install forever -g
forever start server.js

To auto-start server.js on system-reboot (i.e. when Mac/Linux system shuts down or reboots):

npm install forever-service

cd __path to your npm install__
forever-service install ncustomAppName --script server.js

Commands to interact with service ncustomAppName Start:

- "sudo service ncustomAppName start" Stop
- "sudo service ncustomAppName stop" Status
- "sudo service ncustomAppName status" Restart - "sudo service ncustomAppName restart"

More info about forever-service here.

DemoTitle TestLive ViewSource
Audio+Video+File+TextChat Demo Source
FileSharing Demo Source
Scalable Audio/Video Broadcast Demo Source
Scalable Video Broadcast Demo Source
Scalable File Sharing Demo Source
Video Conferencing Demo Source
Audio Conferencing Demo Source
Video Broadcasting Demo Source
TextChat+FileSharing Demo Source
addStream in a Chat room Demo Source
Part-of-Screen Sharing Demo Source
Share Audio+Screen Demo Source
Screen Sharing Demo Source
Disconnect/Rejoin rooms Demo Source
Password Protected Rooms Demo Source
replaceTrack in Firefox Demo Source
applyConstraints in Firefox Demo Source
Firebase-Demo Demo Source
PubNub Demo Demo Source
Socket.io Custom-Messaging Demo Source
Check Rooms Presence Demo Source
getPublicModerators Demo Source
Change Cameras/Microphonea Demo Source
MultiRTC: Skype-like app Demo Source
Change Video Resolutions in your Live Sessions Demo Source

Link Script Files

All files from /dist directory are available on CDN: https://cdn.webrtc-experiment.com:443/

<script src="/RTCMultiConnection.min.js"></script>

<!-- or -->
<script src="/dist/rmc3.min.js"></script>

<!-- CDN non-minified or minified -->
<script src="https://cdn.webrtc-experiment.com:443/rmc3.min.js"></script>

<!-- or specific version -->
<script src="https://github.com/muaz-khan/RTCMultiConnection/releases/download/3.2.98/rmc3.min.js"></script>

If you're sharing files, you also need to link:

<script src="/dev/FileBufferReader.js"></script>

<!-- or CDN -->
<script src="https://cdn.webrtc-experiment.com:443/rmc3.fbr.min.js"></script>

<!-- or specific version -->
<script src="https://github.com/muaz-khan/RTCMultiConnection/releases/download/3.2.98/rmc3.fbr.min.js"></script>

You can link multiple files from dev directory. Order doesn't matters.

Set different socket URL

By default, RTCMultiConnection uses default port of your domain.

You can use custom ports either via config.json file:

{
  "socketURL": "http:s//yourdomain.com:9001/",
  "socketMessageEvent": "RTCMultiConnection-Message"
}

Or simply override in your HTML code:

connection.socketURL = 'http:s//yourdomain.com:9001/';

// if your server is already having "message" event
// then you can use something else, unique.
connection.socketMessageEvent = 'unique-message';

For testing purpose, you can use this as well:

{
  "socketURL": "https://rtcmulticonnection.herokuapp.com:443/",
  "socketMessageEvent": "RTCMultiConnection-Message"
}

Or:

connection.socketURL = 'https://rtcmulticonnection.herokuapp.com:443/';

Here is a demo explaining how to use above socketURL:

Integrate in your own applications?

// node.js code
require('./Signaling-Server.js')(httpServerHandlerOrPort);

If you're using express.js:

var fs = require('fs');

var options = {
    key: fs.readFileSync('fake-keys/privatekey.pem'),
    cert: fs.readFileSync('fake-keys/certificate.pem')
};

var express = require("express"),
    http = require("https"), // Use HTTPs here -------------
    app = express(),
    server = http.createServer(options, app);

server.listen(3000);

require('./Signaling-Server.js')(server);

Migrating from older versions?

Use streamEvents instead of connection.streams:

var stream = connection.streamEvents['streamid'];

// or use this code:
// backward compatibility
connection.streams = connection.streamEvents;
connection.numberOfConnectedUsers = 0;

if (Object.observe) {
    Object.observe(connection.streamEvents, function() {
        // for backward compatibility
        connection.streams = connection.streamEvents;
    });

    Object.observe(connection.peers, function() {
        // for backward compatibility
        connection.numberOfConnectedUsers = connection.getAllParticipants().length;
    });
}

# you can even use "getStreamById"
var stream = connection.attachStreams.getStreamById('streamid');

# to get remote stream by id
var allRemoteStreams = connection.getRemoteStreams('remote-user-id');
var stream = allRemoteStreams.getStreamByid('streamid');

Wanna check isScreen or isVideo or isAudio?

connection.onstream = function(event) {
	if(event.stream.isScreen) {
		// screen stream
	}

	if(event.stream.isVideo) {
		// audio+video or video-only stream
	}

	if(event.stream.isAudio) {
		// audio-only stream
	}
};

Wanna mute/unmute?

var stream = connection.streamEvents['streamid'].stream;
stream.mute('audio'); // audio or video or both

API

applyConstraints

This method allows you change video resolutions or audio sources without making a new getUserMedia request i.e. it modifies your existing MediaStream:

var width = 1280;
var height = 720;

var supports = navigator.mediaDevices.getSupportedConstraints();

var constraints = {};
if (supports.width && supports.height) {
    constraints = {
        width: width,
        height: height
    };
}

connection.applyConstraints({
    video: constraints
});

applyConstraints access mediaConstraints object, defined here:

replaceTrack

This method allows you replace your front-camera video with back-camera video or replace video with screen or replace older low-quality video with new high quality video.

// here is its simpler usage
connection.replaceTrack({
	screen: true,
	oneway: true
});

You can even pass MediaStreamTrack object:

var videoTrack = yourVideoStream.getVideoTracks()[0];
connection.replaceTrack(videoTrack);

You can even pass MediaStream object:

connection.replaceTrack(yourVideoStream);

You can even force to replace tracks only with a single user:

var remoteUserId = 'single-remote-userid';

var videoTrack = yourVideoStream.getVideoTracks()[0];
connection.replaceTrack(videoTrack, remoteUserId);

resetTrack

If you replaced a video or audio track, RTCMultiConnection keeps record of old track, and allows you move-back-to previous track:

connection.resetTrack(null, true);

It takes following arguments:

  1. [Array of user-ids] or "single-user-id" or null
  2. Is video track (boolean): Either true or false. null means replace all last tracks.
// with single user
connection.resetTrack('specific-userid', true);

// with multiple users
connection.resetTrack(['first-user', 'second-user'], true);

// NULL means all users
connection.resetTrack(null, true);

// reset only audio
connection.resetTrack(null, false);

// to reset all last-tracks (both audio and video)
connection.resetTrack();

Means that you can reset all tracks that are replaced recently.

onUserStatusChanged

This event allows you show online/offline statuses of the user:

connection.onUserStatusChanged = function(status) {
	document.getElementById(event.userid).src = status === 'online' ? 'online.gif' : 'offline.gif';
};

You can even manually call above method from onopen, onstream and similar events to get the most accurate result possible:

connection.onopen = connection.stream = function(event) {
    connection.onUserStatusChanged({
        userid: event.userid,
        extra: event.extra,
        status: 'online'
    });
};

connection.onleave = connection.streamended = connection.onclose = function(event) {
    connection.onUserStatusChanged({
        userid: event.userid,
        extra: event.extra,
        status: 'offline'
    });
};

getSocket

This method allows you get the socket object used for signaling (handshake/presence-detection/etc.):

var socket = connection.getSocket();
socket.emit('custom-event', 'hi there');
socket.on('custom-event', function(message) {
	alert(message);
});

If socket isn't connected yet, then above method will auto-connect it. It is using connectSocket to connect socket. See below section.

connectSocket

It is same like old RTCMultiConnection connect method:

connectSocket method simply initializes socket.io server so that you can send custom-messages before creating/joining rooms:

connection.connectSocket(function(socket) {
	socket.on('custom-message', function(message) {
		alert(message);

		// custom message
		if(message.joinMyRoom) {
			connection.join(message.roomid);
		}
	});

	socket.emit('custom-message', 'hi there');

	connection.open('room-id');
});

getUserMediaHandler

This object allows you capture audio/video stream yourself. RTCMultiConnection will NEVER know about your stream until you add it yourself, manually:

var options = {
	localMediaConstraints: {
		audio: true,
		video: true
	},
	onGettingLocalMedia: function(stream) {},
	onLocalMediaError: function(error) {}
};
connection.getUserMediaHandler(options);

Its defined here:

becomePublicModerator

By default: all moderators are private.

This method returns list of all moderators (room owners) who declared themselves as public via becomePublicModerator method:

# to become a public moderator
connection.open('roomid', true); // 2nd argument is "TRUE"

# or call this method later (any time)
connection.becomePublicModerator();

getPublicModerators

You can access list of all the public rooms using this method. This works similar to old RTCMultiConnection method onNewSession.

Here is how to get public moderators:

connection.getPublicModerators(function(array) {
	array.forEach(function(moderator) {
		// moderator.extra
		connection.join(moderator.userid);
	});
});

You can even search for specific moderators. Moderators whose userid starts with specific string:

var moderatorIdStartsWith = 'public-moderator-';
connection.getPublicModerators(moderatorIdStartsWith, function(array) {
	// only those moderators are returned here
	// that are having userid similar to this:
	// public-moderator-xyz
	// public-moderator-abc
	// public-moderator-muaz
	// public-moderator-conference
	array.forEach(function(moderator) {
		// moderator.extra
		connection.join(moderator.userid);
	});
});

setUserPreferences

You can force dontAttachStream and dontGetRemoteStream for any or each user in any situation:

connection.setUserPreferences = function(userPreferences) {
    if (connection.dontAttachStream) {
    	// current user's streams will NEVER be shared with any other user
        userPreferences.dontAttachLocalStream = true;
    }

    if (connection.dontGetRemoteStream) {
    	// current user will NEVER receive any stream from any other user
        userPreferences.dontGetRemoteStream = true;
    }

    return userPreferences;
};

Scenarios:

  1. All users in the room are having cameras
  2. All users in the room can see only self video
  3. All users in the room can text-chat or share files; but can't share videos
  4. As soon as teacher or moderator or presenter enters in the room; he can ask all the participants or specific participants to share their cameras with single or multiple users.

They can enable cameras as following:

connection.onmessage = function(event) {
	var message = event.data;
	if(message.shareYourCameraWithMe) {
		connection.dontAttachStream = false;
		connection.renegotiate(event.userid); // share only with single user
	}

	if(message.shareYourCameraWithAllUsers) {
		connection.dontAttachStream = false;
		connection.renegotiate(); // share with all users
	}
}

i.e. setUserPreferences allows you enable camera on demand.

checkPresence

This method allows you check presence of the moderators/rooms:

connection.checkPresence('roomid', function(isRoomEists, roomid) {
	if(isRoomEists) {
		connection.join(roomid);
	}
	else {
		connection.open(roomid);
	}
});

onReadyForOffer

This event is fired as soon as callee says "I am ready for offer. I enabled camera. Please create offer and share.".

connection.onReadyForOffer = function(remoteUserId, userPreferences) {
	// if OfferToReceiveAudio/OfferToReceiveVideo should be enabled for specific users
	userPreferences.localPeerSdpConstraints.OfferToReceiveAudio = true;
	userPreferences.localPeerSdpConstraints.OfferToReceiveVideo = true;

	userPreferences.dontAttachStream = false; // according to situation
	userPreferences.dontGetRemoteStream = false;  // according to situation

	// below line must be included. Above all lines are optional.
	connection.multiPeersHandler.createNewPeer(remoteUserId, userPreferences);
};

onNewParticipant

This event is fired as soon as someone tries to join you. You can either reject his request or set preferences.

connection.onNewParticipant = function(participantId, userPreferences) {
    // if OfferToReceiveAudio/OfferToReceiveVideo should be enabled for specific users
	userPreferences.localPeerSdpConstraints.OfferToReceiveAudio = true;
	userPreferences.localPeerSdpConstraints.OfferToReceiveVideo = true;

	userPreferences.dontAttachStream = false; // according to situation
	userPreferences.dontGetRemoteStream = false;  // according to situation

	// below line must be included. Above all lines are optional.
	// if below line is NOT included; "join-request" will be considered rejected.
    connection.acceptParticipationRequest(participantId, userPreferences);
};

Or:

var alreadyAllowed = {};
connection.onNewParticipant = function(participantId, userPreferences) {
	if(alreadyAllowed[participantId]) {
		connection.addParticipationRequest(participantId, userPreferences);
		return;
	}

	var message = participantId + ' is trying to join your room. Confirm to accept his request.';
	if( window.confirm(messsage ) ) {
		connection.addParticipationRequest(participantId, userPreferences);
	}
};

disconnectWith

Disconnect with single or multiple users. This method allows you keep connected to socket however either leave entire room or remove single or multiple users:

connection.disconnectWith('remoteUserId');

// to leave entire room
connection.getAllParticipants().forEach(function(participantId) {
	connection.disconnectWith(participantId);
});

getAllParticipants

Get list of all participants that are connected with current user.

var numberOfUsersInTheRoom = connection.getAllParticipants().length;

var remoteUserId = 'xyz';
var isUserConnectedWithYou = connection.getAllParticipants().indexOf(remoteUserId) !== -1;

connection.getAllParticipants().forEach(function(remoteUserId) {
	var user = connection.peers[remoteUserId];
	console.log(user.extra);

	user.peer.close();
	alert(user.peer === webkitRTCPeerConnection);
});

maxParticipantsAllowed

Set number of users who can join your room.

// to allow another single person to join your room
// it will become one-to-one (i.e. you+anotherUser)
connection.maxParticipantsAllowed = 1;

setCustomSocketHandler

This method allows you skip Socket.io and force Firebase or PubNub or WebSockets or PHP/ASPNET whatever.

connection.setCustomSocketHandler(FirebaseConnection);

Please check FirebaseConnection or PubNubConnection.js to understand how it works.

enableLogs

By default, logs are enabled.

connection.enableLogs = false; // to disable logs

updateExtraData

You can force all the extra-data to be synced among all connected users.

connection.extra.fullName = 'New Full Name';
connection.updateExtraData(); // now above value will be auto synced among all connected users

onExtraDataUpdated

This event is fired as soon as extra-data from any user is updated:

connection.onExtraDataUpdated = function(event) {
	console.log('extra data updated', event.userid, event.extra);

	// make sure that <video> header is having latest fullName
	document.getElementById('video-header').innerHTML = event.extra.fullName;
};

streamEvents

It is similar to this:

socketOptions

Socket.io options:

connection.socketOptions = {
	'force new connection': true, // For SocketIO version < 1.0
	'forceNew': true, // For SocketIO version >= 1.0
	'transport': 'polling' // fixing transport:unknown issues
};

connection.socket

connection.open('roomid', function() {
    connection.socket.emit('whatever', 'hmm');
    connection.socket.disconnect();
});

DetectRTC

Wanna detect current browser?

if(connection.DetectRTC.browser.isChrome) {
	// it is Chrome
}

// you can even set backward compatibility hack
connection.UA = connection.DetectRTC.browser;
if(connection.UA.isChrome) { }

Wanna detect if user is having microphone or webcam?

connection.DetectRTC.detectMediaAvailability(function(media){
	if(media.hasWebcam) { }
	if(media.hasMicrophone) { }
	if(media.hasSpeakers) { }
});

invokeSelectFileDialog

Get files problematically instead of using input[type=file]:

connection.invokeSelectFileDialog(function(file) {
	var file = this.files[0];
	if(file){
		connection.shareFile(file);
	}
});

processSdp

Force bandwidth, bitrates, etc.

var BandwidthHandler = connection.BandwidthHandler;
connection.bandwidth = {
	audio: 128,
	video: 256,
	screen: 300
};
connection.processSdp = function(sdp) {
    sdp = BandwidthHandler.setApplicationSpecificBandwidth(sdp, connection.bandwidth, !!connection.session.screen);
    sdp = BandwidthHandler.setVideoBitrates(sdp, {
        min: connection.bandwidth.video,
        max: connection.bandwidth.video
    });

    sdp = BandwidthHandler.setOpusAttributes(sdp);

    sdp = BandwidthHandler.setOpusAttributes(sdp, {
        'stereo': 1,
        //'sprop-stereo': 1,
        'maxaveragebitrate': connection.bandwidth.audio * 1000 * 8,
        'maxplaybackrate': connection.bandwidth.audio * 1000 * 8,
        //'cbr': 1,
        //'useinbandfec': 1,
        // 'usedtx': 1,
        'maxptime': 3
    });

    return sdp;
};

shiftModerationControl

Moderator can shift moderation control to any other user:

connection.shiftModerationControl('remoteUserId', connection.broadcasters, false);

connection.broadcasters is the array of users that builds mesh-networking model i.e. multi-user conference.

Moderator shares connection.broadcasters with each new participant; so that new participants can connect with other members of the room as well.

onShiftedModerationControl

This event is fired, as soon as moderator of the room shifts moderation control toward you:

connection.onShiftedModerationControl = function(sender, existingBroadcasters) {
	connection.acceptModerationControl(sender, existingBroadcasters);
};

autoCloseEntireSession

filesContainer

A DOM-element to show progress-bars and preview files.

connection.filesContainer = document.getElementById('files-container');

videosContainer

A DOM-element to append videos or audios or screens:

connection.videosContainer = document.getElementById('videos-container');

addNewBroadcaster

In a one-way session, you can make multiple broadcasters using this method:

if(connection.isInitiator) {
	connection.addNewBroadcaster('remoteUserId');
}

Now this user will also share videos/screens.

removeFromBroadcastersList

Remove user from connection.broadcasters list.

connection.removeFromBroadcastersList('remote-userid');

onMediaError

If screen or video capturing fails:

connection.onMediaError = function(error) {
	alert( 'onMediaError:\n' + JSON.stringify(error) );
};

renegotiate

Recreate peers. Capture new video using connection.captureUserMedia and call connection.renegotiate() and that new video will be shared with all connected users.

connection.renegotiate('with-single-userid');

connection.renegotiate(); // with all users

addStream

You can even pass streamCallback:

connection.addStream({
	screen: true,
	oneway: true,
	streamCallback: function(screenStream) {
		// this will be fired as soon as stream is captured
		screenStream.onended = function() {
			document.getElementById('share-screen').disabled = false;

			// or show button
			$('#share-screen').show();
		}
	}
});

mediaConstraints

sdpConstraints

extra

userid

session

enableFileSharing

To enable file sharing. By default, it is false:

connection.enableFileSharing = true;

changeUserId

Change userid and update userid among all connected peers:

connection.changeUserId('new-userid');

// or callback to check if userid is successfully changed
connection.changeUserId('new-userid', function() {
    alert('Your userid is successfully changed to: ' + connection.userid);
});

closeBeforeUnload

It is true by default. If you are handling window.onbeforeunload yourself, then you can set it to false:

connection.closeBeforeUnload = false;
window.onbeforeunlaod = function() {
	connection.close();
};

closeEntireSession

You can skip using autoCloseEntireSession. You can keep session/room opened whenever/wherever required and dynamically close the entire room using this method.

connection.closeEntireSession();

// or callback
connection.closeEntireSession(function() {
    alert('Entire session has been closed.');
});

// or before leaving a page
connection.closeBeforeUnload = false;
window.onbeforeunlaod = function() {
    connection.closeEntireSession();
};

onUserIdAlreadyTaken

This event is fired if two users tries to open same room.

connection.onUserIdAlreadyTaken = function(useridAlreadyTaken, yourNewUserId) {
    if (connection.enableLogs) {
        console.warn('Userid already taken.', useridAlreadyTaken, 'Your new userid:', yourNewUserId);
    }

    connection.join(useridAlreadyTaken);
};

Above event gets fired out of this code:

moderator1.open('same-roomid');
moderator2.open('same-roomid');

onEntireSessionClosed

You can tell users that room-moderator closed entire session:

connection.onEntireSessionClosed = function(event) {
    console.info('Entire session is closed: ', event.sessionid, event.extra);
};

captureUserMedia

open

Open room:

var isPublicRoom = false;
connection.open('roomid', isPublicRoom);

// or
connection.open('roomid', function() {
	// on room created
});

join

Join room:

connection.join('roomid');

// or pass "options"
connection.join('roomid', {
	localPeerSdpConstraints: {
		OfferToReceiveAudio: true,
		OfferToReceiveVideo: true
	},
	remotePeerSdpConstraints: {
		OfferToReceiveAudio: true,
		OfferToReceiveVideo: true
	},
	isOneWay: false,
	isDataOnly: false
});

openOrJoin

connection.openOrJoin('roomid');

// or
connection.openOrJoin('roomid', function(isRoomExists, roomid) {
	if(isRoomExists) alert('opened the room');
	else alert('joined the room');
});

dontCaptureUserMedia

By default, it is false. Which means that RTCMultiConnection will always capture video if connection.session.video===true.

If you are attaching external streams, you can ask RTCMultiConnection to DO NOT capture video:

connection.dontCaptureUserMedia = true;

dontAttachStream

By default, it is false. Which means that RTCMultiConnection will always attach local streams.

connection.dontAttachStream = true;

dontGetRemoteStream

By default, it is false. Which means that RTCMultiConnection will always get remote streams.

connection.dontGetRemoteStream = true;

getScreenConstraints

This method allows you get full control over screen-parameters:

connection.__getScreenConstraints = connection.getScreenConstraints;
connection.getScreenConstraints = function(callback) {
    connection.__getScreenConstraints(function(error, screen_constraints) {
        if (connection.DetectRTC.browser.name === 'Chrome') {
            delete screen_constraints.mandatory.minAspectRatio;
            delete screen_constraints.mandatory.googLeakyBucket;
            delete screen_constraints.mandatory.googTemporalLayeredScreencast;
            delete screen_constraints.mandatory.maxWidth;
            delete screen_constraints.mandatory.maxHeight;
            delete screen_constraints.mandatory.minFrameRate;
            delete screen_constraints.mandatory.maxFrameRate;
        }
        callback(error, screen_constraints);
    });
};

Or to more simplify it:

connection.__getScreenConstraints = connection.getScreenConstraints;
connection.getScreenConstraints = function(callback) {
    connection.__getScreenConstraints(function(error, screen_constraints) {
        if (connection.DetectRTC.browser.name === 'Chrome') {
            screen_constraints.mandatory = {
                chromeMediaSource: screen_constraints.mandatory.chromeMediaSource,
                chromeMediaSourceId: screen_constraints.mandatory.chromeMediaSourceId
            };
        }
        callback(error, screen_constraints);
    });
};

You can even delete width/height for Firefox:

connection.__getScreenConstraints = connection.getScreenConstraints;
connection.getScreenConstraints = function(callback) {
    connection.__getScreenConstraints(function(error, screen_constraints) {
        if (connection.DetectRTC.browser.name === 'Chrome') {
            delete screen_constraints.mandatory.minAspectRatio;
        }
        if (connection.DetectRTC.browser.name === 'Firefox') {
            delete screen_constraints.width;
            delete screen_constraints.height;
        }
        callback(error, screen_constraints);
    });
};

Firebase?

If you are willing to use Firebase instead of Socket.io there, open GruntFile.js and replace SocketConnection.js with FirebaseConnection.js.

Then use grunt to recompile RTCMultiConnection.js.

Otherwise if you don't want to modify RTCMultiConnection:

<script src="/dev/globals.js"></script>
<script src="/dev/FirebaseConnection.js"></script>
<script>
var connection = new RTCMultiConnection();

connection.firebase = 'your-firebase-account';

// below line replaces FirebaseConnection
connection.setCustomSocketHandler(FirebaseConnection);
</script>

Demo: https://rtcmulticonnection.herokuapp.com/demos/Firebase-Demo.html

PubNub?

Follow above all "firebase" steps and use PubNubConnection.js instead.

Please don't forget to use your own PubNub keys.

Demo: https://rtcmulticonnection.herokuapp.com/demos/PubNub-Demo.html

Scalable Broadcasting

v3 now supports WebRTC scalable broadcasting. Two new API are introduced: enableScalableBroadcast and singleBroadcastAttendees.

connection.enableScalableBroadcast = true; // by default, it is false.
connection.singleBroadcastAttendees = 3;   // how many users are handled by each broadcaster

Live Demos:

Fix Echo

connection.onstream = function(event) {
	if(event.mediaElement) {
		event.mediaElement.muted = true;
		delete event.mediaElement;
	}

	var video = document.createElement('video');
	if(event.type === 'local') {
		video.muted = true;
	}
	video.src = URL.createObjectURL(event.stream);
	connection.videosContainer.appendChild(video);
}

How to use getStats?

connection.multiPeersHandler.onPeerStateChanged = function(state) {
    if (state.iceConnectionState.search(/disconnected|closed|failed/gi) === -1 && !connection.isConnected) {
        connection.isConnected = true;

        var peer = connection.peers[state.userid].peer;
        getStats(peer, function(result) {
            if (!result || !result.connectionType) return;

            // "relay" means TURN server
            // "srflx" or "prflx" means STUN server
            // "host" means neither STUN, nor TURN
            console.debug('Incoming stream is using:', result.connectionType.remote.candidateType);
            console.debug('Outgoing stream is using:', result.connectionType.local.candidateType);

            // user external ip-addresses
            console.debug('Remote user ip-address:', result.connectionType.remote.ipAddress);
            console.debug('Local user ip-address:', result.connectionType.local.ipAddress);

            // UDP is a real media port; TCP is a fallback.
            console.debug('Peers are connected on port:', result.connectionType.transport);
        }, 5000);
        return;
    }
};

How to mute/unmute?

You can compare muteType for onmute event; and unmuteType for onunmute event.

connection.onmute = function(e) {
    if (!e.mediaElement) {
        return;
    }

    if (e.muteType === 'both' || e.muteType === 'video') {
        e.mediaElement.src = null;
        e.mediaElement.pause();
        e.mediaElement.poster = e.snapshot || 'https://cdn.webrtc-experiment.com/images/muted.png';
    } else if (e.muteType === 'audio') {
        e.mediaElement.muted = true;
    }
};

connection.onunmute = function(e) {
    if (!e.mediaElement) {
        return;
    }

    if (e.unmuteType === 'both' || e.unmuteType === 'video') {
        e.mediaElement.poster = null;
        e.mediaElement.src = URL.createObjectURL(e.stream);
        e.mediaElement.play();
    } else if (e.unmuteType === 'audio') {
        e.mediaElement.muted = false;
    }
};

HD Streaming

connection.bandwidth = {
    audio: 128,
    video: 1024,
    screen: 1024
};

var videoConstraints = {
    mandatory: {
        maxWidth: 1920,
        maxHeight: 1080,
        minAspectRatio: 1.77,
        minFrameRate: 3,
        maxFrameRate: 64
    },
    optional: []
};

connection.mediaConstraints.video = videoConstraints;

For low-latency audio:

Default devices?

By default, RTCMultiConnection tries to use last available microphone and camera. However you can disable this behavior and ask to use default devices instead:

// pass second parameter to force options
var connection = new RTCMultiConnection(roomId, {
    useDefaultDevices: true
});

Auto open or join?

By default, you always have to call open or join or openOrJoin methods manually. However you can force RTCMultiConnection to auto open/join room as soon as constructor is initialized.

// pass second parameter to force options
var connection = new RTCMultiConnection(roomId, {
    autoOpenOrJoin: true
});

Wanna use H264 for video?

connection.codecs.video = 'H264';

Disable Video NACK

<script src="/dev/CodecsHandler.js"></script>
<script>
// in your HTML file
connection.processSdp = function(sdp) {
    // Disable NACK to test IDR recovery
    sdp = CodecsHandler.disableNACK(sdp);
    return sdp;
};
</script>

Wanna use VP8 for video?

connection.codecs.video = 'VP8';

Wanna use G722 for audio?

connection.codecs.audio = 'G722';

Prioritize Codecs

<script src="/dev/CodecsHandler.js"></script>
<script>
// in your HTML file
if(connection.DetectRTC.browser.name === 'Firefox') {
    connection.getAllParticipants().forEach(function(p) {
        var peer = connection.peers[p].peer;

        CodecsHandler.prioritize('audio/opus', peer);
    });
}
</script>

Tips & Tricks

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();

When attaching external streams:

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

Change userid using this method:

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

iOS/Android

RTCMultiConnection-v3 supports cordova based iOS/android apps.

Copy/paste entire rmc3.min.js file inside deviceready callback:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>CordovaApp using RTCMultiConnection-v3</title>
    <link rel="stylesheet" href="css/index.css">
</head>
<body>
    <!-- your UI code -->

    <!-- scripts are placed on footer -->
    <script src="cordova.js"></script>

    <!-- NEVER link rmc3.min.js here -->
    <!-- instead copy/paste code from rmc3.min.js into below "index.js" file -->
    <script src="js/index.js"></script>
</body>
</html>

www/js/index.js:

// please read below comments:
document.addEventListener('deviceready', function() {
    // copy/paste entire/all code from "rmc3.min.js" file
    // here --- exact here
    // paste inside this callback
    // if you will NOT do this, RTCMultiConnection will fail on cordova-based apps
    // again, you MUST NOT link rmc3.min.js
    // instead copy/paste all the codes here

    // you can put your custom-ui-codes here
    // e.g.
    // var connection = new RTCMultiConnection();
}, false);

Installations:

sudo npm install cordova -g
sudo npm install xcode -g

cordova create ./mobileApp org.mobileApp mobileApp
cd mobileApp

cordova plugin add cordova-plugin-iosrtc
cd hooks
wget https://raw.githubusercontent.com/eface2face/cordova-plugin-iosrtc/master/extra/hooks/iosrtc-swift-support.js

sudo chmod +x iosrtc-swift-support.js

cd ..

Now modify config.xml for this section:

<platform name="ios">
    <hook type="after_platform_add" src="hooks/iosrtc-swift-support.js" />
</platform>

Further commands:

cordova platform add [email protected]

cordova build ios
cordova build android

Prerequisites:

  1. xcode 7.2.1 (required)
  2. cordova android plugin 5.1.0 (suggested)
  3. cordova ios plugin 3.9.2 --- note: MUST be this version (don't use newer ones)

Check xcode-build-version: xcodebuild -version

Make sure that terminal is using latest xcode:

xcode-select --print-path

sudo xcode-select -switch /Applications/Xcode5.1.1/Xcode.app

config.xml hints:

Modify platform/android/AndroidManifest.xml for <uses-permission android:name="android.permission.CAMERA"/>. Now getUserMedia API will work in Android.

An example AndroidManifest.xml file:

<?xml version='1.0' encoding='utf-8'?>
<manifest android:hardwareAccelerated="true" android:versionCode="1" android:versionName="0.0.1" package="com.yourApp" xmlns:android="http://schemas.android.com/apk/res/android">
    <supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:resizeable="true" android:smallScreens="true" android:xlargeScreens="true" />
    <application android:hardwareAccelerated="true" android:icon="@drawable/icon" android:label="@string/app_name" android:supportsRtl="true">
        <activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale" android:label="@string/activity_name" android:launchMode="singleTop" android:name="MainActivity" android:theme="@android:style/Theme.DeviceDefault.NoActionBar" android:windowSoftInputMode="adjustResize">
            <intent-filter android:label="@string/launcher_name">
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
    <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="23" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.CAMERA" />
</manifest>

An example config.xml file (make sure that icon.png has valid path):

<?xml version='1.0' encoding='utf-8'?>
<widget id="com.yourApp" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
    <name>yourApp</name>
    <icon src="www/icon.png" />
    <description>yourApp</description>
    <author email="[email protected]" href="http://www.yourApp.com">You</author>
    <content src="index.html" />
    <plugin name="cordova-plugin-whitelist" spec="1" />
    <access uri="*" subdomains="true" origin="*" />
    <allow-intent href="http://*/*" />
    <allow-intent href="https://*/*" />
    <allow-intent href="tel:*" />
    <allow-intent href="sms:*" />
    <allow-intent href="mailto:*" />
    <allow-intent href="geo:*" />
    <allow-navigation href="https://*/*" />
    <platform name="android">
        <allow-intent href="market:*" />
    </platform>
    <platform name="ios">
        <allow-intent href="itms:*" />
        <allow-intent href="itms-apps:*" />
        <hook type="after_platform_add" src="hooks/iosrtc-swift-support.js" />
        <config-file target="*-Info.plist" parent="CFBundleURLTypes">
            <array>
                <key>NSAppTransportSecurity</key>
                <dict><key>NSAllowsArbitraryLoads</key><true/></dict>
            </array>
        </config-file>
    </platform>
    <preference name="xwalkVersion" value="16+" />
    <preference name="xwalkCommandLine" value="--disable-pull-to-refresh-effect --allow-file-access-from-files --disable-web-security" />
    <preference name="xwalkMode" value="embedded" />
    <preference name="xwalkMultipleApk" value="true" />
    <preference name="BackgroundColor" value="0xFFFF0000" />
    <preference name="xwalkUserAgent" value="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36" />
    <preference name="AndroidPersistentFileLocation" value="Internal" />
</widget>

RTCMultiConnection v2.2.2 Demos

Experiment Name Demo Source Code
AppRTC like RTCMultiConnection demo! Demo Source
MultiRTC! RTCMultiConnection all-in-one demo! Demo Source
Collaborative Canvas Designer Demo Source
Conversation.js - Skype like library Demo Source
All-in-One test Demo Source
Multi-Broadcasters and Many Viewers Demo Source
Select Broadcaster at runtime Demo Source
OneWay Screen & Two-Way Audio Demo Source
Stream Mp3 Live Demo Source
Socket.io auto Open/Join rooms Demo Source
Screen Sharing & Cropping Demo Source
Share Part of Screen without cropping it Demo Source
getMediaDevices/enumerateDevices Demo Source
Renegotiation & Mute/UnMute/Stop Demo Source
Video-Conferencing Demo Source
Video Broadcasting Demo Source
Many-to-One Broadcast Demo Source
Audio Conferencing Demo Source
Multi-streams attachment Demo Source
Admin/Guest audio/video calling Demo Source
Session Re-initiation Test Demo Source
Preview Screenshot of the room Demo Source
RecordRTC & RTCMultiConnection Demo Source
Explains how to customize ice servers; and resolutions Demo Source
Mute/Unmute and onmute/onunmute Demo Source
One-page demo: Explains how to skip external signalling gateways Demo Source
Password Protect Rooms: Explains how to authenticate users Demo Source
Session Management: Explains difference between "leave" and "close" methods Demo Source
Multi-Sessions Management Demo Source
Customizing Bandwidth Demo Source
Users ejection and presence detection Demo Source
Multi-Session Establishment Demo Source
Group File Sharing + Text Chat Demo Source
Audio Conferencing + File Sharing + Text Chat Demo Source
Join with/without camera Demo Source
Screen Sharing Demo Source
One-to-One file sharing Demo Source
Manual session establishment + extra data transmission Demo Source
Manual session establishment + extra data transmission + video conferencing Demo Source
takeSnapshot i.e. Take Snapshot of Local/Remote streams Demo Source
Audio/Video/Screen sharing and recording Demo Source
Broadcast Multiple-Cameras Demo Source
Remote Stream Forwarding Demo Source
WebRTC Scalable Broadcast Socketio/Nodejs Source

v2.2.2 is available here:

Twitter

License

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

rtcmulticonnection's People

Contributors

muaz-khan avatar killmenot avatar brianpursley avatar reptoh avatar yuripetusko avatar chenghaoc avatar

Watchers

James Cloos avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.