rtcmulticonnection
Version:
RTCMultiConnection is a WebRTC JavaScript wrapper library runs top over RTCPeerConnection API to support all possible peer-to-peer features.
316 lines (255 loc) • 12.4 kB
JavaScript
function SocketConnection(connection, connectCallback) {
function isData(session) {
return !session.audio && !session.video && !session.screen && session.data;
}
var parameters = '';
parameters += '?userid=' + connection.userid;
parameters += '&sessionid=' + connection.sessionid;
parameters += '&msgEvent=' + connection.socketMessageEvent;
parameters += '&socketCustomEvent=' + connection.socketCustomEvent;
parameters += '&autoCloseEntireSession=' + !!connection.autoCloseEntireSession;
if (connection.session.broadcast === true) {
parameters += '&oneToMany=true';
}
parameters += '&maxParticipantsAllowed=' + connection.maxParticipantsAllowed;
if (connection.enableScalableBroadcast) {
parameters += '&enableScalableBroadcast=true';
parameters += '&maxRelayLimitPerUser=' + (connection.maxRelayLimitPerUser || 2);
}
parameters += '&extra=' + JSON.stringify(connection.extra || {});
if (connection.socketCustomParameters) {
parameters += connection.socketCustomParameters;
}
try {
io.sockets = {};
} catch (e) {};
if (!connection.socketURL) {
connection.socketURL = '/';
}
if (connection.socketURL.substr(connection.socketURL.length - 1, 1) != '/') {
// connection.socketURL = 'https://domain.com:9001/';
throw '"socketURL" MUST end with a slash.';
}
if (connection.enableLogs) {
if (connection.socketURL == '/') {
console.info('socket.io url is: ', location.origin + '/');
} else {
console.info('socket.io url is: ', connection.socketURL);
}
}
try {
connection.socket = io(connection.socketURL + parameters);
} catch (e) {
connection.socket = io.connect(connection.socketURL + parameters, connection.socketOptions);
}
var mPeer = connection.multiPeersHandler;
connection.socket.on('extra-data-updated', function(remoteUserId, extra) {
if (!connection.peers[remoteUserId]) return;
connection.peers[remoteUserId].extra = extra;
connection.onExtraDataUpdated({
userid: remoteUserId,
extra: extra
});
updateExtraBackup(remoteUserId, extra);
});
function updateExtraBackup(remoteUserId, extra) {
if (!connection.peersBackup[remoteUserId]) {
connection.peersBackup[remoteUserId] = {
userid: remoteUserId,
extra: {}
};
}
connection.peersBackup[remoteUserId].extra = extra;
}
function onMessageEvent(message) {
if (message.remoteUserId != connection.userid) return;
if (connection.peers[message.sender] && connection.peers[message.sender].extra != message.message.extra) {
connection.peers[message.sender].extra = message.extra;
connection.onExtraDataUpdated({
userid: message.sender,
extra: message.extra
});
updateExtraBackup(message.sender, message.extra);
}
if (message.message.streamSyncNeeded && connection.peers[message.sender]) {
var stream = connection.streamEvents[message.message.streamid];
if (!stream || !stream.stream) {
return;
}
var action = message.message.action;
if (action === 'ended' || action === 'inactive' || action === 'stream-removed') {
if (connection.peersBackup[stream.userid]) {
stream.extra = connection.peersBackup[stream.userid].extra;
}
connection.onstreamended(stream);
return;
}
var type = message.message.type != 'both' ? message.message.type : null;
if (typeof stream.stream[action] == 'function') {
stream.stream[action](type);
}
return;
}
if (message.message === 'dropPeerConnection') {
connection.deletePeer(message.sender);
return;
}
if (message.message.allParticipants) {
if (message.message.allParticipants.indexOf(message.sender) === -1) {
message.message.allParticipants.push(message.sender);
}
message.message.allParticipants.forEach(function(participant) {
mPeer[!connection.peers[participant] ? 'createNewPeer' : 'renegotiatePeer'](participant, {
localPeerSdpConstraints: {
OfferToReceiveAudio: connection.sdpConstraints.mandatory.OfferToReceiveAudio,
OfferToReceiveVideo: connection.sdpConstraints.mandatory.OfferToReceiveVideo
},
remotePeerSdpConstraints: {
OfferToReceiveAudio: connection.session.oneway ? !!connection.session.audio : connection.sdpConstraints.mandatory.OfferToReceiveAudio,
OfferToReceiveVideo: connection.session.oneway ? !!connection.session.video || !!connection.session.screen : connection.sdpConstraints.mandatory.OfferToReceiveVideo
},
isOneWay: !!connection.session.oneway || connection.direction === 'one-way',
isDataOnly: isData(connection.session)
});
});
return;
}
if (message.message.newParticipant) {
if (message.message.newParticipant == connection.userid) return;
if (!!connection.peers[message.message.newParticipant]) return;
mPeer.createNewPeer(message.message.newParticipant, message.message.userPreferences || {
localPeerSdpConstraints: {
OfferToReceiveAudio: connection.sdpConstraints.mandatory.OfferToReceiveAudio,
OfferToReceiveVideo: connection.sdpConstraints.mandatory.OfferToReceiveVideo
},
remotePeerSdpConstraints: {
OfferToReceiveAudio: connection.session.oneway ? !!connection.session.audio : connection.sdpConstraints.mandatory.OfferToReceiveAudio,
OfferToReceiveVideo: connection.session.oneway ? !!connection.session.video || !!connection.session.screen : connection.sdpConstraints.mandatory.OfferToReceiveVideo
},
isOneWay: !!connection.session.oneway || connection.direction === 'one-way',
isDataOnly: isData(connection.session)
});
return;
}
if (message.message.readyForOffer) {
if (connection.attachStreams.length) {
connection.waitingForLocalMedia = false;
}
if (connection.waitingForLocalMedia) {
// if someone is waiting to join you
// make sure that we've local media before making a handshake
setTimeout(function() {
onMessageEvent(message);
}, 1);
return;
}
}
if (message.message.newParticipationRequest && message.sender !== connection.userid) {
if (connection.peers[message.sender]) {
connection.deletePeer(message.sender);
}
var userPreferences = {
extra: message.extra || {},
localPeerSdpConstraints: message.message.remotePeerSdpConstraints || {
OfferToReceiveAudio: connection.sdpConstraints.mandatory.OfferToReceiveAudio,
OfferToReceiveVideo: connection.sdpConstraints.mandatory.OfferToReceiveVideo
},
remotePeerSdpConstraints: message.message.localPeerSdpConstraints || {
OfferToReceiveAudio: connection.session.oneway ? !!connection.session.audio : connection.sdpConstraints.mandatory.OfferToReceiveAudio,
OfferToReceiveVideo: connection.session.oneway ? !!connection.session.video || !!connection.session.screen : connection.sdpConstraints.mandatory.OfferToReceiveVideo
},
isOneWay: typeof message.message.isOneWay !== 'undefined' ? message.message.isOneWay : !!connection.session.oneway || connection.direction === 'one-way',
isDataOnly: typeof message.message.isDataOnly !== 'undefined' ? message.message.isDataOnly : isData(connection.session),
dontGetRemoteStream: typeof message.message.isOneWay !== 'undefined' ? message.message.isOneWay : !!connection.session.oneway || connection.direction === 'one-way',
dontAttachLocalStream: !!message.message.dontGetRemoteStream,
connectionDescription: message,
successCallback: function() {}
};
connection.onNewParticipant(message.sender, userPreferences);
return;
}
if (message.message.changedUUID) {
if (connection.peers[message.message.oldUUID]) {
connection.peers[message.message.newUUID] = connection.peers[message.message.oldUUID];
delete connection.peers[message.message.oldUUID];
}
}
if (message.message.userLeft) {
mPeer.onUserLeft(message.sender);
if (!!message.message.autoCloseEntireSession) {
connection.leave();
}
return;
}
mPeer.addNegotiatedMessage(message.message, message.sender);
}
connection.socket.on(connection.socketMessageEvent, onMessageEvent);
var alreadyConnected = false;
connection.socket.resetProps = function() {
alreadyConnected = false;
};
connection.socket.on('connect', function() {
if (alreadyConnected) {
return;
}
alreadyConnected = true;
if (connection.enableLogs) {
console.info('socket.io connection is opened.');
}
setTimeout(function() {
connection.socket.emit('extra-data-updated', connection.extra);
}, 1000);
if (connectCallback) {
connectCallback(connection.socket);
}
});
connection.socket.on('disconnect', function(event) {
connection.onSocketDisconnect(event);
});
connection.socket.on('error', function(event) {
connection.onSocketError(event);
});
connection.socket.on('user-disconnected', function(remoteUserId) {
if (remoteUserId === connection.userid) {
return;
}
connection.onUserStatusChanged({
userid: remoteUserId,
status: 'offline',
extra: connection.peers[remoteUserId] ? connection.peers[remoteUserId].extra || {} : {}
});
connection.deletePeer(remoteUserId);
});
connection.socket.on('user-connected', function(userid) {
if (userid === connection.userid) {
return;
}
connection.onUserStatusChanged({
userid: userid,
status: 'online',
extra: connection.peers[userid] ? connection.peers[userid].extra || {} : {}
});
});
connection.socket.on('closed-entire-session', function(sessionid, extra) {
connection.leave();
connection.onEntireSessionClosed({
sessionid: sessionid,
userid: sessionid,
extra: extra
});
});
connection.socket.on('userid-already-taken', function(useridAlreadyTaken, yourNewUserId) {
connection.onUserIdAlreadyTaken(useridAlreadyTaken, yourNewUserId);
});
connection.socket.on('logs', function(log) {
if (!connection.enableLogs) return;
console.debug('server-logs', log);
});
connection.socket.on('number-of-broadcast-viewers-updated', function(data) {
connection.onNumberOfBroadcastViewersUpdated(data);
});
connection.socket.on('set-isInitiator-true', function(sessionid) {
if (sessionid != connection.sessionid) return;
connection.isInitiator = true;
});
}