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.
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/
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 |
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.
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
:
// 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);
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:
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.open('roomid', function() {
connection.socket.emit('whatever', 'hmm');
connection.socket.disconnect();
});
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 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>
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');
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:
- 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:
- List of Breaking Changes
- Coding Tricks
- Switch Between Cameras
- Bandwidth Management
- Channels and Sessions Management
- How to send Custom/Private messages?
- Custom Private Servers
- How to link RTCMultiConnection.js?
- How to fix echo?
- How to share Part-of-Screen?
- How to detect Presence of the users & sessions?
- How to share screen?
- How to secure your RTCMultiConnection codes?
- Use WebSync Signaling Server in any RTCMultiConnection demo
- How to implement client-side (local) screen-sharing without involving any 3rd-party service or extension or addon
- Detect Who is Speaking
- https://twitter.com/WebRTCWeb i.e. @WebRTCWeb
RTCMultiConnection is released under MIT licence . Copyright (c) Muaz Khan.