rtcmulticonnection
Version:
RTCMultiConnection is a WebRTC JavaScript wrapper library runs top over RTCPeerConnection API to support all possible peer-to-peer features.
1,573 lines (1,154 loc) • 44 kB
Markdown
# API Reference
> RTCMultiConnection API References
You can search docs/APIs here:
* http://www.rtcmulticonnection.org/
* http://www.rtcmulticonnection.org/docs/
### `socketURL`
1. You can run nodejs on a separate domain or separate port or on a separate server
2. You can set `socketURL="ip-address"` to link nodejs server
3. Now you can run RTCMultiConnection demos on any webpage; whether it is PHP page, ASP.net page, python or ruby page or whatever framework running top over HTML.
```javascript
connection.socketURL = 'https://onlyChangingPort.com:8888/';
connection.socketURL = 'https://separateDomain.com:443/';
connection.socketURL = '/'; // same domain
// or a free signaling server:
// v3.4.7 or newer
connection.socketURL = 'https://rtcmulticonnection.herokuapp.com:443/';
// v3.4.6 or older
connection.socketURL = 'https://webrtcweb.com:9001/';
```
### `socketCustomParameters`
You can pass your custom socket.io parameters as well:
```javascript
// starts with "&"
// &fullName=Muaz
// &meetingId=xyz
connection.socketCustomParameters = '&fullName=Muaz&country=PK&meetingId=xyz';
```
Now you can open `server.js` and access above parameters here:
```javascript
// you can find below line on "server.js" file
require('./Signaling-Server.js')(app, function(socket) {
var params = socket.handshake.query;
var meetingId = params.meetingId;
var fullName = params.fullName;
var country = params.country;
var userid = params.userid;
// etc.
});
```
### Update Extra-Data before Socket connects
This feature allows you reliably update-extra data on nodejs before socket.io connection opens.
```javascript
connection.extra = {
fullName: 'Muaz Khan',
joinedAt: (new Date).toISOString()
};s
connection.socketCustomParameters = '&extra=' + JSON.stringify(connection.extra);
connection.openOrJoin('room-id');
```
### `applyConstraints`
This method allows you change video resolutions or audio sources without making a new getUserMedia request i.e. it modifies your existing MediaStream:
```javascript
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:
* [http://www.rtcmulticonnection.org/docs/mediaConstraints/](http://www.rtcmulticonnection.org/docs/mediaConstraints/)
### `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.
```javascript
// here is its simpler usage
connection.replaceTrack({
screen: true,
oneway: true
});
```
You can even pass `MediaStreamTrack` object:
```javascript
var videoTrack = yourVideoStream.getVideoTracks()[0];
connection.replaceTrack(videoTrack);
```
You can even pass `MediaStream` object:
```javascript
connection.replaceTrack(yourVideoStream);
```
You can even force to replace tracks only with a single user:
```javascript
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:
```javascript
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.
```javascript
// 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:
```javascript
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:
```javascript
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'
});
};
```
### `onRoomFull`
```javascript
connection.maxParticipantsAllowed = 1; // one-to-one
connection.onRoomFull = function(roomid) {
alert('Room is full.');
};
```
### `getSocket`
This method allows you get the `socket` object used for signaling (handshake/presence-detection/etc.):
```javascript
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:
* [http://www.rtcmulticonnection.org/docs/connect/](http://www.rtcmulticonnection.org/docs/connect/)
`connectSocket` method simply initializes socket.io server so that you can send custom-messages before creating/joining rooms:
```javascript
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');
});
```
### `socketCustomEvent`
A `string` property, allows you set custom socket.io event listener:
```javascript
connection.socketCustomEvent = 'abcdef';
connection.openOrJoin('roomid', function() {
connection.socket.on(connection.socketCustomEvent, function(message) {
alert(message);
});
connection.socket.emit(connection.socketCustomEvent, 'My userid is: ' + connection.userid);
});
```
### `setCustomSocketEvent`
This method allows you set custom socket listeners anytime, during a live session:
```javascript
connection.setCustomSocketEvent('abcdef');
connection.socket.on('abcdef', function(message) {
alert(message);
});
connection.socket.emit('abcdef', 'My userid is: ' + connection.userid);
```
### `getUserMediaHandler`
This object allows you capture audio/video stream yourself. RTCMultiConnection will NEVER know about your stream until you add it yourself, manually:
```javascript
var options = {
localMediaConstraints: {
audio: true,
video: true
},
onGettingLocalMedia: function(stream) {},
onLocalMediaError: function(error) {}
};
connection.getUserMediaHandler(options);
```
Its defined here:
* [getUserMedia.js#L20](https://github.com/muaz-khan/RTCMultiConnection/tree/master/dev/getUserMedia.js#L20)
## `becomePublicModerator`
By default: all moderators are private.
This method returns list of all moderators (room owners) who declared themselves as `public` via `becomePublicModerator` method:
```javascript
# 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:
```javascript
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:
```javascript
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:
```javascript
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:
```javascritp
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:
```javascript
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.".
```javascript
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.
```javascript
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:
```javascript
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:
```javascript
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.
```javascript
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.
```javascript
// 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 custom signaling implementations e.g. SIP-signaling, XHR-signaling, SignalR/WebSync signaling, Firebase/PubNub signaling etc.
Here is Firebase example:
```html
<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>
```
Here is PubNub example:
```html
<script src="/dev/globals.js"></script>
<script src="/dev/PubNubConnection.js"></script>
<script>
var connection = new RTCMultiConnection();
// below line replaces PubNubConnection
connection.setCustomSocketHandler(PubNubConnection);
</script>
```
SIP/SignalR/WebSync/XHR signaling:
```javascript
// please don't forget linking /dev/globals.js
var connection = new RTCMultiConnection();
// SignalR (requires /dev/SignalRConnection.js)
connection.setCustomSocketHandler(SignalRConnection);
// WebSync (requires /dev/WebSyncConnection.js)
connection.setCustomSocketHandler(WebSyncConnection);
// XHR (requires /dev/XHRConnection.js)
connection.setCustomSocketHandler(XHRConnection);
// Sip (requires /dev/SipConnection.js)
connection.setCustomSocketHandler(SipConnection);
```
Please check [`FirebaseConnection`](https://github.com/muaz-khan/RTCMultiConnection/tree/master/dev/FirebaseConnection.js) or [`PubNubConnection.js`](https://github.com/muaz-khan/RTCMultiConnection/tree/master/dev/PubNubConnection.js) to understand how it works.
For more information:
* https://rtcmulticonnection.herokuapp.com/demos/Audio+Video+TextChat+FileSharing.html#comment-2670178473
* https://rtcmulticonnection.herokuapp.com/demos/Audio+Video+TextChat+FileSharing.html#comment-2670182313
## `enableLogs`
By default, logs are enabled.
```javascript
connection.enableLogs = false; // to disable logs
```
## Get Remote User Extra Data
```javascript
connection.extra = {
joinTime: new Date()
};
connection.updateExtraData();
```
Here is how to get extra-data:
```javascript
var extra = connection.peers['remote-userid'].extra;
alert( extra.joinTime);
```
Recent commit supports this as well:
```javascript
connection.onstream = function(event) {
if(event.type === 'remote') {
connection.socket.emit('get-remote-user-extra-data', event.userid, function(extra) {
alert( extra.joinTime );
});
}
}:
```
## `updateExtraData`
You can force all the extra-data to be synced among all connected users.
```javascript
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:
```javascript
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:
* http://www.rtcmulticonnection.org/docs/streams/
## `socketOptions`
Socket.io options:
```javascript
connection.socketOptions = {
'force new connection': true, // For SocketIO version < 1.0
'forceNew': true, // For SocketIO version >= 1.0
'transport': 'polling' // fixing transport:unknown issues
};
```
Or:
```javascript
connection.socketOptions.resource = 'custom';
connection.socketOptions.transport = 'polling';
connection.socketOptions['try multiple transports'] = false;
connection.socketOptions.secure = true;
connection.socketOptions.port = '9001';
connection.socketOptions['max reconnection attempts'] = 100;
// etc.
```
## `connection.socket`
```javascript
connection.open('roomid', function() {
connection.socket.emit('whatever', 'hmm');
connection.socket.disconnect();
});
```
## `DetectRTC`
Wanna detect current browser?
```javascript
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?
```javascript
connection.DetectRTC.detectMediaAvailability(function(media){
if(media.hasWebcam) { }
if(media.hasMicrophone) { }
if(media.hasSpeakers) { }
});
```
## `invokeSelectFileDialog`
Get files problematically instead of using `input[type=file]`:
```javascript
connection.invokeSelectFileDialog(function(file) {
var file = this.files[0];
if(file){
connection.shareFile(file);
}
});
```
## `processSdp`
Force bandwidth, bitrates, etc.
```javascript
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;
};
```
* http://www.rtcmulticonnection.org/docs/processSdp/
## `autoCloseEntireSession`
* http://www.rtcmulticonnection.org/docs/autoCloseEntireSession/
## `filesContainer`
A DOM-element to show progress-bars and preview files.
```javascript
connection.filesContainer = document.getElementById('files-container');
```
## `videosContainer`
A DOM-element to append videos or audios or screens:
```javascript
connection.videosContainer = document.getElementById('videos-container');
```
## `onMediaError`
If screen or video capturing fails:
```javascript
connection.onMediaError = function(error) {
alert( 'onMediaError:\n' + JSON.stringify(error) );
};
```
## `renegotiate`
> Note on 10-02-2018: `replaceTrack` is preferred over `renegotiate`.
Recreate peers. Capture new video using `connection.captureUserMedia` and call `connection.renegotiate()` and that new video will be shared with all connected users.
```javascript
connection.renegotiate('with-single-userid');
connection.renegotiate(); // with all users
```
## `addStream`
* http://www.rtcmulticonnection.org/docs/addStream/
You can even pass `streamCallback` and check if user declined prompt to share
screen:
```javascript
connection.addStream({
screen: true,
oneway: true,
streamCallback: function(screenStream) {
// this will be fired as soon as stream is captured
if (!screenStream) {
alert('User did NOT select to share any stream. He clicked "Cancel" button instead.');
return;
}
screenStream.onended = function() {
document.getElementById('share-screen').disabled = false;
// or show button
$('#share-screen').show();
};
};
});
```
## `removeStream`
* http://www.rtcmulticonnection.org/docs/removeStream/
You can even pass `streamCallback`:
```javascript
connection.removeStream('streamid');
connection.renegotiate();
```
## `mediaConstraints`
* http://www.rtcmulticonnection.org/docs/mediaConstraints/
## `sdpConstraints`
* http://www.rtcmulticonnection.org/docs/sdpConstraints/
## `extra`
* http://www.rtcmulticonnection.org/docs/extra/
## `userid`
* http://www.rtcmulticonnection.org/docs/userid/
`conection.open` method sets this:
```javascript
connection.open = function(roomid) {
connection.userid = roomid; // --------- please check this line
// rest of the codes
};
```
It means that `roomid` is always organizer/moderator's `userid`.
RTCMultiConnection requires unique `userid` for each peer.
Following code is WRONG/INVALID:
```javascript
// both organizer and participants are using same 'userid'
connection.userid = roomid;
connection.open(roomid);
connection.join(roomid);
```
Following code is VALID:
```javascript
connection.userid = connection.token(); // random userid
connection.open(roomid);
connection.join(roomid);
```
Following code is also VALID:
```javascript
var roomid = 'xyz';
connection.open(roomid); // organizer will use "roomid" as his "userid" here
connection.join(roomid); // participant will use random userid here
```
## `session`
* http://www.rtcmulticonnection.org/docs/session/
To enable two-way audio however one-way screen or video:
```javascript
// video is oneway, however audio is two-way
connection.session = {
audio: 'two-way',
video: true,
oneway: true
};
// screen is oneway, however audio is two-way
connection.session = {
audio: 'two-way',
screen: true,
oneway: true
};
```
## `enableFileSharing`
To enable file sharing. By default, it is `false`:
```javascript
connection.enableFileSharing = true;
```
## `changeUserId`
Change userid and update userid among all connected peers:
```javascript
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`:
```javascript
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.
```javascript
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();
};
```
## `closeSocket`
```javascript
connection.closeSocket(); // close socket.io connections
```
## `close`
* http://www.rtcmulticonnection.org/docs/close/
## `onUserIdAlreadyTaken`
This event is fired if two users tries to open same room.
```javascript
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:
```javascript
moderator1.open('same-roomid');
moderator2.open('same-roomid');
```
## `onEntireSessionClosed`
You can tell users that room-moderator closed entire session:
```javascript
connection.onEntireSessionClosed = function(event) {
console.info('Entire session is closed: ', event.sessionid, event.extra);
};
```
## `captureUserMedia`
* http://www.rtcmulticonnection.org/docs/captureUserMedia/
## `open`
Open room:
```javascript
var isPublicRoom = false;
connection.open('roomid', isPublicRoom);
// or
connection.open('roomid', function() {
// on room created
});
```
## `join`
Join room:
```javascript
connection.join('roomid');
// or pass "options"
connection.join('roomid', {
localPeerSdpConstraints: {
OfferToReceiveAudio: true,
OfferToReceiveVideo: true
},
remotePeerSdpConstraints: {
OfferToReceiveAudio: true,
OfferToReceiveVideo: true
},
isOneWay: false,
isDataOnly: false
});
```
## `openOrJoin`
```javascript
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:
```javascript
connection.dontCaptureUserMedia = true;
```
## `dontAttachStream`
By default, it is `false`. Which means that RTCMultiConnection will always attach local streams.
```javascript
connection.dontAttachStream = true;
```
## `dontGetRemoteStream`
By default, it is `false`. Which means that RTCMultiConnection will always get remote streams.
```javascript
connection.dontGetRemoteStream = true;
```
## `onSettingLocalDescription`
This event is fired as soon as RTCMultiConnection calls the `nativePeer.setLocalDescription` method.
This event helps you say: "incoming call" or debug peers if connection didn't establish till next 3 seconds.
This method is helpful if you switch between cameras or you add screen or add other camera or change anything:
```javascript
connection.onSettingLocalDescription = fucntion(event) {
console.log('Trying to connect with', event.userid);
var nativePeer = event.peer;
var localStreams = nativePeer.getLocalStreams();
var remoteStreams = nativePeer.getRemoteStreams();
// make sure that you are correctly displaying all remote videos
var tries = 0;
(function looper() {
if(tries > 10) return; // throw error here
tries++;
// make sure that each user's video.id == hisUserID
var video = document.getElementById(event.userid);
// skip: if user left or if user video is playing
if(!video || video.currentTIme > 0) return;
video.src = URL.createObjectURL ( nativePeer.getRemoteStreams()[0] );
video.play();
setTimeout(looper, 1000); // repeat till 10-seconds
})();
};
```
## `beforeAddingStream`
You can skip any stream or allow RTCMultiConnection to share a stream with remote users.
`nativePeer.addStream` method will be called only if below event permits the `MediaStream` object:
```javascript
connection.beforeAddingStream = function(stream, peer) {
if(stream.id == 'any-streamid') return; // skip
if(stream.isScreen) return; // skip
if(stream.inactive) return; // skip
// var remoteUserId = peer.userid;
// var remoteUserExtra = connection.peers[remoteUserId].extra;
return stream; // otherwise allow RTCMultiConnection to share this stream with remote users
};
```
## `getScreenConstraints`
This method allows you get full control over screen-parameters:
```javascript
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:
```javascript
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:
```javascript
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);
});
};
```
## Cross-Domain Screen Capturing
First step, install this chrome extension:
* https://chrome.google.com/webstore/detail/screen-capturing/ajhifddimkapgcifgcodmmfdlknahffk
Now use below code in any RTCMultiConnection (screen) demo:
```html
<script src="/dev/globals.js"></script>
<!-- capture screen from any HTTPs domain! -->
<script src="https://cdn.webrtc-experiment.com:443/getScreenId.js"></script>
<script>
// Using getScreenId.js to capture screen from any domain
// You do NOT need to deploy Chrome Extension YOUR-Self!!
connection.getScreenConstraints = function(callback, audioPlusTab) {
if (isAudioPlusTab(connection, audioPlusTab)) {
audioPlusTab = true;
}
getScreenConstraints(function(error, screen_constraints) {
if (!error) {
screen_constraints = connection.modifyScreenConstraints(screen_constraints);
callback(error, screen_constraints);
}
}, audioPlusTab);
};
</script>
```
Don't want to link `/dev/globals.js` or want to simplify codes???
```html
<!-- capture screen from any HTTPs domain! -->
<script src="https://cdn.webrtc-experiment.com:443/getScreenId.js"></script>
<script>
// Using getScreenId.js to capture screen from any domain
// You do NOT need to deploy Chrome Extension YOUR-Self!!
connection.getScreenConstraints = function(callback) {
getScreenConstraints(function(error, screen_constraints) {
if (!error) {
screen_constraints = connection.modifyScreenConstraints(screen_constraints);
callback(error, screen_constraints);
}
});
};
</script>
```
## Scalable Broadcasting
RTCMultiConnection now supports WebRTC scalable broadcasting. Two new API are introduced: `enableScalableBroadcast` and `singleBroadcastAttendees`.
```javascript
connection.enableScalableBroadcast = true; // by default, it is false.
connection.singleBroadcastAttendees = 3; // how many users are handled by each broadcaster
```
Live Demos:
| DemoTitle | TestLive | ViewSource |
| ------------- |-------------|-------------|
| Scalable Audio/Video Broadcast | [Demo](https://rtcmulticonnection.herokuapp.com/demos/Scalable-Broadcast.html) | [Source](https://github.com/muaz-khan/RTCMultiConnection/tree/master/demos/Scalable-Broadcast.html) |
| Scalable Screen Broadcast | [Demo](https://rtcmulticonnection.herokuapp.com/demos/Scalable-Screen-Broadcast.html) | [Source](https://github.com/muaz-khan/RTCMultiConnection/tree/master/demos/Scalable-Screen-Broadcast.html) |
| Scalable Video Broadcast | [Demo](https://rtcmulticonnection.herokuapp.com/demos/Video-Scalable-Broadcast.html) | [Source](https://github.com/muaz-khan/RTCMultiConnection/tree/master/demos/Video-Scalable-Broadcast.html) |
| Scalable File Sharing | [Demo](https://rtcmulticonnection.herokuapp.com/demos/Files-Scalable-Broadcast.html) | [Source](https://github.com/muaz-khan/RTCMultiConnection/tree/master/demos/Files-Scalable-Broadcast.html) |
## `onNumberOfBroadcastViewersUpdated`
This event is fired for scalable-broadcast-initiator.
```javascript
connection.onNumberOfBroadcastViewersUpdated = function(event) {
// event.broadcastId
// event.numberOfBroadcastViewers
console.info('Number of broadcast (', event.broadcastId, ') viewers', event.numberOfBroadcastViewers);
};
```
## `getNumberOfBroadcastViewers`
You can manually get number-of-broadcast viewers as well:
```javascript
connection.getNumberOfBroadcastViewers('broadcast-unique-id', function(numberOfBroadcastViewers) {
alert(numberOfBroadcastViewers);
});
```
## Fix Echo
```javascript
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?
* https://github.com/muaz-khan/getStats
```javascript
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.
```javascript
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
```javascript
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:
* https://twitter.com/WebRTCWeb/status/499102787733450753
## 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:
```javascript
// 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.
```javascript
// pass second parameter to force options
var connection = new RTCMultiConnection(roomId, {
autoOpenOrJoin: true
});
```
## Wanna use H264 for video?
```javascript
connection.codecs.video = 'H264';
```
## Disable Video NACK
```html
<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?
```javascript
connection.codecs.video = 'VP8';
```
## Wanna use G722 for audio?
```javascript
connection.codecs.audio = 'G722';
```
## Prioritize Codecs
```html
<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>
```
## `StreamHasData`
[`StreamHasData.js`](https://github.com/muaz-khan/RTCMultiConnection/tree/master/dev/StreamHasData.js) allows you check if remote stream started flowing or if remote stream is successfully received or if remote stream has data or not.
```html
<script src="/dev/StreamHasData.js"></script>
<script>
connection.videosContainer = document.getElementById('videos-container');
connection.onstream = function(event) {
StreamHasData.check(event.mediaElement, function(hasData) {
if (!hasData) {
alert('Seems stream does NOT has any data.');
}
// append video here
connection.videosContainer.appendChild(event.mediaElement);
event.mediaElement.play();
setTimeout(function() {
event.mediaElement.play();
}, 5000);
});
};
</script>
```
Demo: https://rtcmulticonnection.herokuapp.com/demos/StreamHasData.html
## File Sharing
You can share files using `connection.send(file)`. E.g.
```javascript
fileInput.onchange = function() {
var file = this.files[0];
if(!file) return;
connection.send(file);
};
```
If you mistakenly shared wrong file, you can stop further sharing:
```javascript
var file;
fileInput.onchange = function() {
file = this.files[0];
if(!file) return;
// First step: Set UUID for your file object
file.uuid = connection.token();
connection.send(file);
};
if(connection.fbr) {
// Second Last step: remove/delete file chunks based on file UUID
delete connection.fbr.chunks[file.uuid];
}
```
You can even set `connection.fbr=null`. **It is VERY EASY & reliable**:
```javascript
connection.fbr = null;
```
You can even try any of these (you don't need to care about file UUID):
```javascript
if(connection.fbr) {
// clearing all file chunks
// removing all file receivers
connection.fbr.chunks = {};
connection.fbr.users = {};
}
```
## `config.json`
You can set ports, logs, socket-URLs and other configuration using [`config.json`](https://github.com/muaz-khan/RTCMultiConnection/blob/master/config.json).
```json
{
"socketURL": "/",
"socketMessageEvent": "RTCMultiConnection-Message",
"socketCustomEvent": "RTCMultiConnection-Custom-Message",
"port": "9001",
"enableLogs": "true"
}
```
Note: `config.json` is completely optional. You can set each property directly in your HTML files using `connection.property` e.g.
```javascript
connection.socketURL = '/';
connection.socketMessageEvent = 'RTCMultiConnection-Message';
// etc.
```
## Server Logs
[`config.json`](https://github.com/muaz-khan/RTCMultiConnection/blob/master/config.json) provides `enableLogs` attribute.
If `enableLogs:true` then all unexpected-server-errors are logged into [`logs.json`](https://github.com/muaz-khan/RTCMultiConnection/blob/master/logs.json) file.
So, if you're facing unexpected-server-disconnection, or if your application is NOT working properly; for example, if `userid` is NOT getting updated or if `extra-data` is NOT getting-synced; then you can look into `logs.json` to see unexpected errors.
You can either remove `enableLogs` from the `config.json` to **disable logs**; or you can use `false`:
```json
{
"enableLogs": "false"
}
```
# Tips & Tricks
* https://github.com/muaz-khan/RTCMultiConnection/blob/master/docs/tips-tricks.md
# Other Documents
1. [Getting Started guide for RTCMultiConnection](https://github.com/muaz-khan/RTCMultiConnection/tree/master/docs/getting-started.md)
2. [Installation Guide](https://github.com/muaz-khan/RTCMultiConnection/tree/master/docs/installation-guide.md)
3. [How to Use?](https://github.com/muaz-khan/RTCMultiConnection/tree/master/docs/how-to-use.md)
4. [API Reference](https://github.com/muaz-khan/RTCMultiConnection/tree/master/docs/api.md)
5. [Upgrade from v2 to v3](https://github.com/muaz-khan/RTCMultiConnection/tree/master/docs/upgrade.md)
6. [How to write iOS/Android applications?](https://github.com/muaz-khan/RTCMultiConnection/tree/master/docs/ios-android.md)
7. [Tips & Tricks](https://github.com/muaz-khan/RTCMultiConnection/blob/master/docs/tips-tricks.md)
## Twitter
* https://twitter.com/WebRTCWeb i.e. @WebRTCWeb
## License
[RTCMultiConnection](https://github.com/muaz-khan/RTCMultiConnection) is released under [MIT licence](https://github.com/muaz-khan/RTCMultiConnection/blob/master/LICENSE.md) . Copyright (c) [Muaz Khan](http://www.MuazKhan.com/).