v3.0 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.0. Please use
Signaling-Server.js
instead.v3.0 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.
Fetch latest code:
git clone https://github.com/muaz-khan/RTCMultiConnection.git ./RTCMultiConnection
cd RTCMultiConnection
sudo npm install --save-dev
Or:
Download via Github (as ZIP
or .js
): https://github.com/muaz-khan/RTCMultiConnection/releases
Or:
sudo npm install rtcmulticonnection-v3
cd node_modules
cd rtcmulticonnection-v3 # you MUST go to this directory
node server.js
# 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:
npm start
# or
node server.js
# if 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/
nohup nodejs server.js > /dev/null 2>&1 &
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.94/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.94/rmc3.fbr.min.js"></script>
You can link multiple files from
dev
directory. Order doesn't matters.
Either via config.json
file:
{
"socketURL": "/",
"socketMessageEvent": "RTCMultiConnection-Message"
}
or 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
:
// node.js code
require('./Signaling-Server.js')(httpServerHandlerOrPort);
If you're using expressjs:
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);
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
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:
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);
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:
[Array of user-ids]
or"single-user-id"
ornull
- Is video track (boolean): Either
true
orfalse
.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.
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'
});
};
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.
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');
});
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:
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();
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);
});
});
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:
- All users in the room are having cameras
- All users in the room can see only self video
- All users in the room can text-chat or share files; but can't share videos
- 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.
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);
}
});
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);
};
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);
}
};
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);
});
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);
});
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;
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.
By default, logs are enabled.
connection.enableLogs = false; // to disable logs
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
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;
};
It is similar to this:
If socket.io is listening on a separate port or external URL:
connection.socketURL = 'https://domain:port/';
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
};
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) { }
});
Get files problematically instead of using input[type=file]
:
connection.invokeSelectFileDialog(function(file) {
var file = this.files[0];
if(file){
connection.shareFile(file);
}
});
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;
};
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.
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);
};
A DOM-element to show progress-bars and preview files.
connection.filesContainer = document.getElementById('files-container');
A DOM-element to append videos or audios or screens:
connection.videosContainer = document.getElementById('videos-container');
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.
Remove user from connection.broadcasters
list.
connection.removeFromBroadcastersList('remote-userid');
If screen or video capturing fails:
connection.onMediaError = function(error) {
alert( 'onMediaError:\n' + JSON.stringify(error) );
};
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
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();
}
}
});
To enable file sharing. By default, it is false
:
connection.enableFileSharing = true;
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);
});
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();
};
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();
};
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');
You can tell users that room-moderator closed entire session:
connection.onEntireSessionClosed = function(event) {
console.info('Entire session is closed: ', event.sessionid, event.extra);
};
Open room:
var isPublicRoom = false;
connection.open('roomid', isPublicRoom);
// or
connection.open('roomid', function() {
// on room created
});
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
});
connection.openOrJoin('roomid');
// or
connection.openOrJoin('roomid', function(isRoomExists, roomid) {
if(isRoomExists) alert('opened the room');
else alert('joined the room');
});
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;
By default, it is false
. Which means that RTCMultiConnection will always attach local streams.
connection.dontAttachStream = true;
By default, it is false
. Which means that RTCMultiConnection will always get remote streams.
connection.dontGetRemoteStream = true;
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);
});
};
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
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
v3.0 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:
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);
}
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;
}
};
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;
}
};
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:
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
});
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
});
connection.codecs.video = 'H264';
<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>
connection.codecs.video = 'VP8';
connection.codecs.audio = 'G722';
<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>
RTCMultiConnection-v3.0 supports cordova
based iOS/android apps.
Copy/paste entire rmc3.min.js
file inside deviceready
callback:
// please read below comments:
// normally you can place below code in your www/js/index.js file
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:
- xcode
7.2.1
(required) - cordova android plugin
5.1.0
(suggested) - 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>
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:
- https://twitter.com/WebRTCWeb i.e. @WebRTCWeb
RTCMultiConnection is released under MIT licence . Copyright (c) Muaz Khan.