UNPKG

@virusonic/react-native-sdk

Version:

249 lines (215 loc) 8.35 kB
var EventBus = require('../util/event-bus'); var Constants = require('../util/datatype'); Call = function (callInfo, options, loggedUser, incoming) { EventBus.apply(this, arguments); var me = this; me._callInfo = callInfo; me._options = options; me._worker = null; me._userWorkers = {}; me.id = callInfo.id; me.loggedUser = loggedUser; me.participants = {}; //todo remove owner participant and receive from server me.participants[loggedUser.username] = { username: loggedUser.username, role: 40, joinOrdinal: 1 }; callInfo.participants.forEach(p => { me.participants[p.username] = p; if ((p.joinOrdinal || !incoming) && p.username !== loggedUser.username) { me.createOrGetWorker(p.username); } }); }; Call.prototype = Object.create(EventBus.prototype); Call.prototype.constructor = Call; Call.prototype.addParticipant = function (participant) { const me = this; me.participants[participant.username] = participant; } Call.prototype.removeParticipant = function (participant) { const me = this; let username = participant.username; delete me.participants[username]; if (me._userWorkers && me._userWorkers[username]) { me._userWorkers[username].destroy(); delete me._userWorkers[username]; } } Call.prototype.joinedParticipant = function (participant) { const me = this; me.participants[participant.username] = participant; let myUsername = me.loggedUser.username; let myParticipant = me.participants[myUsername]; //if my joined event received later than another user joine event, we need iterate for all participants which joined early //todo refactor without iterate console.log("My Participant ", myParticipant); for (const [username, p] of Object.entries(me.participants)) { console.log("Participant ", p); if (p.joinOrdinal > 0 && myParticipant.joinOrdinal > 0 && myParticipant.joinOrdinal > p.joinOrdinal && p.username !== myUsername) { me.createOrGetWorker(p.username); } } } //todo create method leftParticipant Call.prototype.startConnectivity = function (stream) { var me = this; var promises = []; if (stream) { //todo store stream in worker me._stream = stream; } const usersSessionInfo = {}; let needSend = false; //todo add stream only one peerconnection or create configuration for (const [username, worker] of Object.entries(me._userWorkers)) { //todo refactor with stream try { console.log("Check need connectivity for worker", username); if (worker.waitConnectivity() && me._stream) { console.log("Start connectivity for worker with username", username, me._stream); promises.push(worker.startConnectivity(me._stream).then(sessionInfo => { if (sessionInfo) { needSend = true; console.log("For " + username + " received sessionInfo: ", sessionInfo); usersSessionInfo[username] = sessionInfo; } })); } } catch (e) { console.log("Error on start connectivity", e); } } return Promise.all(promises).then(() => { console.log("All workers ready needSend:" + needSend + "; usersSessionInfo:", usersSessionInfo); if (needSend) { return {usersSessionInfo: usersSessionInfo}; } else { return null; } }); }; Call.prototype.updateConnectionInfo = function (connectionInfo) { var me = this; var sessionInfo = connectionInfo.sessionInfo; if (sessionInfo) { var worker = me.createOrGetWorker(); if (sessionInfo.sdpInfo) { worker.setRemoteSessionInfo(sessionInfo); } } for (var x in connectionInfo.usersSessionInfo) { var userWorker = me.createOrGetWorker(x); var userSessionInfo = connectionInfo.usersSessionInfo[x]; if (userSessionInfo.sdpInfo) { userWorker.setRemoteSessionInfo(userSessionInfo); } } }; Call.prototype.muteAudio = function (mute) { var me = this; const tracksInfo = []; me._stream?.getAudioTracks().forEach(track => { track.enabled = !mute; const trackInfo = {id: track.id, type: track.kind, enabled: track.enabled}; tracksInfo.push(trackInfo); }); return tracksInfo; } Call.prototype.muteVideo = function (mute) { var me = this; const tracksInfo = []; me._stream?.getVideoTracks().forEach(track => { track.enabled = !mute; const trackInfo = {id: track.id, type: track.kind, enabled: track.enabled}; tracksInfo.push(trackInfo); }); return tracksInfo; } Call.prototype.addExtraSessionDescription = function (extraConnectionInfo) { var me = this; if (extraConnectionInfo.extraSDPInfo && me._worker) { me._worker.addExtraSdpInfo(extraConnectionInfo.extraSDPInfo); } let usersExtraSDPInfo = extraConnectionInfo.usersExtraSDPInfo; if (usersExtraSDPInfo) { for (const username in usersExtraSDPInfo) { // skip loop if the property is from prototype if (!usersExtraSDPInfo.hasOwnProperty(username)) continue; if (me._userWorkers && me._userWorkers[username]) { me._userWorkers[username].addExtraSdpInfo(usersExtraSDPInfo[username]); } } } } Call.prototype.createOrGetWorker = function (username) { var me = this; if (username) { var userWorker = me._userWorkers[username]; if (!userWorker) { console.log("Create worker for ", username); userWorker = me.createWorker(username); me._userWorkers[username] = userWorker; } return userWorker; } else { if (!me._worker) { me._worker = me.createWorker(); } return me._worker; } }; Call.prototype.createWorker = function (username) { var me = this; const WebRTCWorker = require('./webrtc-worker'); var webRTCWorker = new WebRTCWorker(me._options); webRTCWorker.register(Constants.WorkerEvent.iceCandidate, function (candidate) { me.post(Constants.CallEvent.onIceCandidate, [me.id, username, candidate]); }); webRTCWorker.register(Constants.WorkerEvent.onTrack, function (event) { me.post(Constants.CallEvent.onTrack, [username, event]); }); webRTCWorker.register(Constants.WorkerEvent.trackInfo, function (tracksInfo) { me.post(Constants.CallEvent.trackInfo, [me.participants[username], tracksInfo]); }); webRTCWorker.register(Constants.WorkerEvent.connectionState, function (connectionState) { const participant = me.participants[username]; if (connectionState === "connectionState.failed" || connectionState === "connectionState.disconnected") { setTimeout(() => { if (participant && (participant.connectionState === "connectionState.failed" || participant.connectionState === "connectionState.disconnected")) { //todo leave if for all workers connection failed me.post(Constants.CallEvent.dead, [username, connectionState]); } }, 5000); } if (participant) { participant.connectionState = connectionState; } me.post(Constants.CallEvent.connectionState, [username, connectionState]); }); return webRTCWorker; }; Call.prototype.destroy = function () { var me = this; if (me._worker) { me._worker.destroy(); me._worker = null; } for (const username in me._userWorkers) { // skip loop if the property is from prototype if (!me._userWorkers.hasOwnProperty(username)) continue; me._userWorkers[username].destroy(); } me._userWorkers = {}; //todo refactor manipulate with stream (destroy stream by configuration) if (me._stream) { me._stream.getTracks().forEach((track) => { //todo configurable destroy track by configuration call track.stop(); //track.enabled = true; }); } } module.exports = Call;