UNPKG

podchat-browser

Version:

Javascript SDK to use POD's Chat Service - Browser Only

1,122 lines (994 loc) 43.2 kB
import {WebrtcPeerConnection} from "./webrtcPeer"; import Utility from "../../../utility/utility"; import {errorList} from "../../errorHandler"; import MidManager from "./midManager"; class PeerConnectionManager { constructor({ app, callId, direction, rtcPeerConfig, brokerAddress, onPeerFailed, onSendTrackFailed }) { this._app = app; this._callId = callId; this._brokerAddress = brokerAddress; this._nextTrackMid = 0; this._trackList = []; this._addTrackQueue = []; this._sendTrackQueue = []; this._addIceQueue = []; this._direction = direction; this._firstSub = true; this._canProcessNextTrack = true; this._isDestroyed = false; this._requestTimeouts = {}; this._negotiationOfferUpdate = []; this._isReconnecting = false; this._subscribeOrUpdateFailedCount = 0; this._peerStates = { DISCONNECTED: 0, CONNECTING: 1, FAILED: 3, CONNECTED: 4 }; this._state = 0; //0: disconnected, 1: connecting, 2: failed, 3: connected, 4: disconnected this._defaultConfig = { callId, direction, rtcPeerConfig, connectionStateChange: this._onConnectionStateChange.bind(this), iceConnectionStateChange: this._onIceConnectionStateChange.bind(this) }; this._onPeerFailed = onPeerFailed; this._onSendTrackFailed = onSendTrackFailed; this._peer = new WebrtcPeerConnection(this._defaultConfig); this._onTrackCalls = 0; this._sendOpenDone = false; this._sendOpenDoneTimeout = null; this.watchConnectionStateChange(); this._addTrackLock = false; this._addTrackQueueTriggerTimeout = null; this._midManager = new MidManager({app}); let that = this; window.trackList = function () { return that._trackList; } } _nextTrack(retries = 0) { if(this.isDestroyed()) return; if (this._canProcessNextTrack) { if (this._direction == 'send' && this._canProcessNextTrack && this._addTrackQueue.length) { if(this._firstSub || this._peer && this._peer.peerConnection && this._peer.peerConnection.connectionState == 'connected') { this._canProcessNextTrack = false; let item = this._addTrackQueue[0]; this._requestAddSendTrack(item); } else if(retries <= 3) { setTimeout(()=> { this._nextTrack(retries++); }, 3000) } } else if (this._direction == 'receive' && this._canProcessNextTrack) { if(this._negotiationOfferUpdate.length) { this._canProcessNextTrack = false; this._sendTrackQueue = []; this.handleProcessSDPOfferForRenegotiate(); } else if(this._addTrackQueue.length && !this._isReconnecting){ this._canProcessNextTrack = false; this._sendTrackQueue = []; while (this._addTrackQueue.length > 0) { // if (this._addTrackQueue[0].mediaType != 2) { let track = this._addTrackQueue.shift(); this._sendTrackQueue.push(track); // } else { // if (this._sendTrackQueue.length) { // break; // } // this._sendTrackQueue.push(this._addTrackQueue.shift()); // break; // } } this._requestReceiveTrack(); } } } } _requestAddSendTrack(item) { let that = this, localTrackIndex, uuid = Utility.generateUUID(); item.uniqueId = uuid; let sender = this._peer.peerConnection.getSenders().find(function (s, index) { if (s.track == item.stream.getTracks()[0]) { localTrackIndex = index; return true; } }); if (sender) { console.warn('Track already exists in connection, direction: send'); // item.onTrackCallback(item, item.stream.getTracks()[localTrackIndex]) } let localStream; if (item.topic.indexOf('Vi-') > -1 || item.topic.indexOf('screen') > -1) { if (item.isScreenShare) { localStream = this._app.call.deviceManager.mediaStreams.getScreenShareInput(); } else { localStream = this._app.call.deviceManager.mediaStreams.getVideoInput(); } if (localStream && !sender) { this._peer.addTrack(localStream.getTracks()[0], localStream); } } else { localStream = this._app.call.deviceManager.mediaStreams.getAudioInput(); if (localStream && !sender) { this._peer.addTrack(localStream.getTracks()[0], localStream); } } this._peer.peerConnection.onicecandidate = ({candidate}) => { if(!candidate) return; this._app.call.currentCall().sendCallMessage({ id: "SEND_ADD_ICE_CANDIDATE", token: this._app.sdkParams.token, chatId: this._callId, brokerAddress: this._brokerAddress, iceCandidate: JSON.stringify(candidate), }, null, {}); }; item.onTrackCallback(item, localStream.getTracks()[0]) if (this._firstSub) { this._firstSub = false; item.isFirstSub = true; if(!item.offer) { that._peer.peerConnection .createOffer() .then(offer => { if(this._addTrackQueue[0]) this._addTrackQueue[0].offer = offer; else return; return that._peer.peerConnection.setLocalDescription(offer) }) .then(() => { // console.log('[debug][_requestAddSendTrack] SEND_SDP_OFFER', this._peer.peerConnection.localDescription.sdp, [{ // mline: item.mline, // topic: item.topic, // mediaType: item.mediaType // }]); that._sendSdpOfferMessage(item, uuid); }) .catch(error => console.error({error})); } else { that._sendSdpOfferMessage(item, uuid); } } else { if(!item.offer) { that._peer.peerConnection .createOffer() .then(offer => { this._addTrackQueue[0].offer = offer; return that._peer.peerConnection.setLocalDescription(offer) }) .then(() => { this._app.logger.log( this._app.logger.tags.CALL_PROCESS, "[_requestAddSendTrack][SEND_NEGOTIATION] ", item ); // console.log('[debug][_requestAddSendTrack] SEND_NEGOTIATION', this._peer.peerConnection.localDescription.sdp, [{ // mline: item.mline, // topic: item.topic, // mediaType: item.mediaType // }]); that._sendNegotioateMessage(item, uuid) }); } else { that._sendNegotioateMessage(item, uuid) } } this.setSendRequestTimeout(uuid, item); } _requestRemoveSendTrackNoMessage(item){ if (this._isDestroyed) return; let localTrackIndex; let sender = this._peer.peerConnection.getSenders().find(function (s, index) { if (s.track == item.stream.getTracks()[0]) { localTrackIndex = index; return true; } }); if (sender) { this._peer.peerConnection.removeTrack(sender); } } _sendSdpOfferMessage(item, uuid) { this._app.call.currentCall().sendCallMessage({ id: "SEND_SDP_OFFER", sdpOffer: this._peer.peerConnection.localDescription.sdp, token: this._app.sdkParams.token, chatId: this._callId, brokerAddress: this._brokerAddress, addition: [{ mline: item.mline, topic: item.topic, mediaType: item.mediaType }], uniqueId: uuid, }, null, {}); } _sendNegotioateMessage(item, uuid) { this._app.call.currentCall().sendCallMessage({ id: "SEND_NEGOTIATION", sdpOffer: this._peer.peerConnection.localDescription.sdp, token: this._app.sdkParams.token, chatId: this._callId, brokerAddress: this._brokerAddress, addition: [{ mline: item.mline, topic: item.topic, mediaType: item.mediaType }], uniqueId: uuid, }, null, {}); } _requestRemoveSendTrack(item) { if (this._isDestroyed) return; let localTrackIndex; let sender = this._peer.peerConnection.getSenders().find(function (s, index) { if (s.track == item.stream.getTracks()[0]) { localTrackIndex = index; return true; } }); if (sender) { this._peer.peerConnection.removeTrack(sender); // this._trackList.forEach((it, index) => { // if (item.topic == it.topic) { // delete this._trackList[index] // } // }) this._peer.peerConnection .createOffer() .then(offer => this._peer.peerConnection.setLocalDescription(offer)) .then(() => { this._app.call.currentCall().sendCallMessage({ id: "SEND_NEGOTIATION", sdpOffer: this._peer.peerConnection.localDescription.sdp, token: this._app.sdkParams.token, chatId: this._callId, brokerAddress: this._brokerAddress, deletion: [{ mline: item.mline, topic: item.topic, mediaType: item.mediaType }] }, null, {}); }); } } _requestReceiveTrack() { let list = []; let includedItem = []; this._sendTrackQueue.forEach(item => { if(!includedItem.includes(item.topic)) { list.push({ clientId: item.clientId, mline: item.mline, topic: item.topic, mediaType: item.mediaType }); includedItem.push(item.topic); } }); let uuid = Utility.generateUUID(); this._sendRequestReceiveTrack(uuid, list); // this._sendTrackQueue = this._sendTrackQueue.filter(it => { // return !items.find(ite => ite.topic == it.topic); // }); } _sendRequestReceiveTrack(uuid, list) { console.log('[media][SUBSCRIBE/UPDATE] Sending.. , clientIds: ', list.map(it => it.clientId).join(','), ' ||| topics: ', list.map(it => it.topic).join(','), '||| _trackList: ', JSON.stringify(this._trackList), '||| _sendTrackQueue: ', JSON.stringify(this._sendTrackQueue), '||| _addTrackQueue: ', JSON.stringify(this._addTrackQueue), ); if (this._firstSub) { this._app.call.currentCall().sendCallMessage({ id: 'SUBSCRIBE', uniqueId: uuid, token: this._app.sdkParams.token, chatId: this._callId, brokerAddress: this._brokerAddress, addition: list }, null, {}); } else { this._app.call.currentCall().sendCallMessage({ id: 'UPDATE', uniqueId: uuid, token: this._app.sdkParams.token, chatId: this._callId, brokerAddress: this._brokerAddress, addition: list }, null, {}); } this.setRequestTimeout(uuid, list); } setSendRequestTimeout(uuid, item) { this._requestTimeouts[uuid] = { timeout: setTimeout(() => { // this.removeFailedTrack(item); // item.onOpenFailure && item.onOpenFailure(item); delete this._requestTimeouts[uuid]; this._onSendTrackFailed(); return; if(item.isFirstSub) { this._firstSub = true; } // this._requestRemoveSendTrackNoMessage(item); // this.processingCurrentTrackCompleted(); this._unlockProcessingNextTrack(); this._nextTrack(); delete this._requestTimeouts[uuid]; }, 10000) }; } resetSubscribeOrUpdateFailedCount(){ this._subscribeOrUpdateFailedCount = 0; } setRequestTimeout(uuid, list) { this._requestTimeouts[uuid] = { timeout: setTimeout(() => { if (!this._app.call.currentCall() || this._isDestroyed) return; if(this._subscribeOrUpdateFailedCount < 3) { this._subscribeOrUpdateFailedCount += 1; /** * This will resend the request and waits for the response */ delete this._requestTimeouts[uuid]; this._sendRequestReceiveTrack(uuid, list); // this._app.call.currentCall().sendCallMessage({ // id: 'REQUEST_RECEIVING_MEDIA', // token: this._app.sdkParams.token, // chatId: this._callId, // brokerAddress: this._brokerAddress, // }, null, {}); // this.processingCurrentTrackCompleted(); // delete this._requestTimeouts[uuid]; } else { // items.forEach(it => { // this.removeFailedTrack(it); // it.onOpenFailure && it.onOpenFailure(it); // }); this.resetSubscribeOrUpdateFailedCount(); if(this._app.call.currentCall()) { // this._app.chatEvents.fireEvent('callEvents', { // type: 'CALL_ENDED', // callId: this._app.call.currentCall().getCallId() // }); this._app.call.currentCall().raiseCallError(errorList.UPDATE_TRACK_REQUEST_TIMEOUT, null, true); this._app.chatEvents.fireEvent('callEvents', { type: 'YOU_DROPPED_FROM_CALL', callId: this._app.call.currentCall().getCallId(), result: { callId: this._app.call.currentCall().getCallId(), userId: this._app.store.user.get().id, } }); this._app.call.endCall({callId: this._app.call.currentCall().getCallId()}) } } }, 2000) }; } removeFailedTrack(item) { this._addTrackQueue = this._addTrackQueue.filter(it => it.topic != item.topic); this._sendTrackQueue = []; this._trackList = this._trackList.filter(it => it.topic != item.topic); // console.log('debug removed failed track', {item}, JSON.stringify(this._trackList), JSON.stringify(this._addTrackQueue)); } requestReceiveError(uuid) { if (this._requestTimeouts[uuid]) { let item = this._trackList.find(item => { return item && item.topic === this._requestTimeouts[uuid].topic; }); this.removeRequestTimeout(uuid); this.removeFailedTrack(item); this.processingCurrentTrackCompleted(); item.onOpenFailure(item); } } removeRequestTimeout(uuid) { let record = this._requestTimeouts[uuid]; if (record) { if (record.timeout) clearTimeout(record.timeout); delete this._requestTimeouts[uuid]; } } removeRequestTimeoutByTopic(topic){ this._trackList.forEach(item => { if(item.topic == topic) { if(this._requestTimeouts[item.uniqueId]) { if (this._requestTimeouts[item.uniqueId].timeout) { clearTimeout(this._requestTimeouts[item.uniqueId].timeout); } if (this._requestTimeouts[item.uniqueId]) delete this._requestTimeouts[item.uniqueId] } } }) } _unlockProcessingNextTrack() { this._canProcessNextTrack = true; } _setPeerState(state) { this._state = state; } addTrack(data) { let existingTrack = this._trackList.some(item => item.topic == data.topic); if (existingTrack) return 2; if (this._direction == 'send') { data.mline = this._nextTrackMid; this._nextTrackMid++; } this._trackList.push(data); this._addTrackQueue.push(data); if (this._direction == 'send') { this._nextTrack(); } else { /** * Gives some time so other users have enough time to add their tracks. * Otherwise, if receiving_media gives 5 tracks together they will open one by one */ this._addTrackQueueTriggerTimeout && clearTimeout(this._addTrackQueueTriggerTimeout); this._addTrackQueueTriggerTimeout = setTimeout(()=> { this._nextTrack(); }, 20); } return 1; } removeTrack(topic) { let item = this._trackList.find(it => { return it && it.topic === topic; }); if (this._direction == 'send') { if (item) { this._requestRemoveSendTrack(item); } } if (item) { this._midManager.removeTopic(topic); this._trackList = this._trackList.filter(it => it.topic != item.topic); } } processingCurrentTrackCompleted() { if(this._direction == 'send') this._addTrackQueue.shift(); this._unlockProcessingNextTrack(); this._nextTrack(); } maybeNextTrack() { this._nextTrack(); } isPeerConnecting() { return this._state === this._peerStates.CONNECTING; } isPeerFailed() { return this._state === this._peerStates.FAILED; } isPeerConnected() { return this._state === this._peerStates.CONNECTED; } isPeerDisconnected() { return this._state === this._peerStates.DISCONNECTED; } _onConnectionStateChange() { if (!this._peer || this.isDestroyed()) { return; } this._app.chatEvents.fireEvent("callStreamEvents", { type: 'WEBRTC_CONNECTION_STATE_CHANGE', callId: this._callId, direction: this._direction, connectionState: this._peer.peerConnection.connectionState, }); this._app.logger.log( this._app.logger.tags.CALL_PROCESS.id, "[peerConnection.onconnectionstatechange]", "peer: " + this._direction + " peerConnection.connectionState: " + this._peer.peerConnection.connectionState ); // this._app.sdkParams.consoleLogging && console.log("[SDK][peerConnection.onconnectionstatechange] ", "peer: ", this._direction, " peerConnection.connectionState: ", this._peer.peerConnection.connectionState); switch (this._peer.peerConnection.connectionState) { case 'disconnected': if (this.isPeerDisconnected()) return; this._state = this._peerStates.DISCONNECTED; this._app.call.currentCall().sendCallStatusEvent(); break; case 'failed': if (this.isPeerFailed()) return; this._app.chatEvents.fireEvent('callEvents', { type: 'PEER_FAILED', callId: this._callId, direction: this._direction }); this._handlePeerFailed(); break case 'connected': if (this.isPeerConnected()) return; this._nextTrack(); this._state = this._peerStates.CONNECTED; this._app.call.currentCall().sendCallStatusEvent(); this._app.chatEvents.fireEvent('callEvents', { type: 'PEER_CONNECTED', callId: this._callId, direction: this._direction }); break; } } _onIceConnectionStateChange() { if (!this._peer || this.isDestroyed()) { return; //avoid log errors } this._app.logger.log( this._app.logger.tags.CALL_PROCESS.id, "[peerConnection.oniceconnectionstatechange]", "peer: " + this._direction + " peerConnection.connectionState: " + this._peer.peerConnection.connectionState ); // this._app.sdkParams.consoleLogging && console.log("[SDK][oniceconnectionstatechange] ", "peer: ", this._direction, " peerConnection.connectionState: ", this._peer.peerConnection.iceConnectionState); switch (this._peer.peerConnection.iceConnectionState) { case 'disconnected': if (this.isPeerDisconnected()) return; this._state = this._peerStates.DISCONNECTED; this._app.call.currentCall().sendCallStatusEvent(); // this._app.chatEvents.fireEvent('callEvents', { // type: 'CALL_STATUS', // callId: this._callId, // errorCode: 7000, // errorMessage: `Call Peer (${this._direction}) is disconnected!`, // errorInfo: this._peer // }); // this._app.sdkParams.consoleLogging && console.log('[SDK][oniceconnectionstatechange]:[disconnected] Internet connection failed, Reconnect your call, peer:', this._direction); break; case 'failed': if (this.isPeerFailed()) return; this._app.chatEvents.fireEvent('callEvents', { type: 'PEER_FAILED', callId: this._callId, direction: this._direction }); this._handlePeerFailed(); break case 'connected': if (this.isPeerConnected()) return; this._state = this._peerStates.CONNECTED; this._app.call.currentCall().sendCallStatusEvent(); this._app.chatEvents.fireEvent('callEvents', { type: 'PEER_CONNECTED', callId: this._callId, direction: this._direction }); // this._app.chatEvents.fireEvent('callEvents', { // type: 'CALL_STATUS', // callId: this._callId, // errorCode: 7000, // errorMessage: `Call Peer (${this._direction}) has connected!`, // errorInfo: this._peer.peerConnection // }); break; } } _handlePeerFailed() { this._state = this._peerStates.FAILED; this._app.call.currentCall().sendCallStatusEvent(); // this._app.chatEvents.fireEvent('callEvents', { // type: 'CALL_STATUS', // callId: this._callId, // errorCode: 7000, // errorMessage: `Call Peer (${this._direction}) has failed!`, // errorInfo: this._peer // }); this._onPeerFailed(this._direction); } addIceCandidateToQueue(candidate) { if (this._peer.peerConnection.signalingState === 'stable' && !!this._peer.peerConnection.currentRemoteDescription) { this.addIceCandidate(candidate) .catch(error => { this._addIceQueue.push(candidate); }); } else { this._addIceQueue.push(candidate); } } addIceOnPeer(event) { let that = this; that._addIceQueue.forEach(item => { that.addIceCandidate(item); }); } watchConnectionStateChange() { let that = this; this._peer.peerConnection.onsignalingstatechange = (event) => { if (that._peer.peerConnection.signalingState === 'stable' && !!that._peer.peerConnection.currentRemoteDescription) { that.addIceOnPeer(event); } } } async addIceCandidate(data) { return new Promise((resolve, reject) => { this._peer.peerConnection .addIceCandidate(data) .catch(err => { if (err) { console.warn("[peerConnectionManager addIceCandidate" + this._direction + "] " + err); reject(err); } }); }); } reconnectPeer() { this._destroyPeer(); this._peer = new WebrtcPeerConnection(this._defaultConfig); } async handleProcessSDPOfferForReceiveTrack(jsonMessage, callback) { this._firstSub = false; let topics = JSON.parse(jsonMessage.topic); await this._midManager.reOpenExistingDuplicateMids(topics); console.log('[media][PROCESS_SDP_OFFER/UPDATE] Received.. , clientIds: ', topics.map(it => it.clientId).join(','),' ||| topics: ', topics.map(it => it.topic).join(','), ', sendTrackQueue: ', this._sendTrackQueue); this._sendTrackQueue.forEach(item => { topics.forEach(it => { if (item.topic == it.topic) { item.onUpdateSuccess(item) } }) }) this._bindReceiveIceCandidateCallback(); let timeoutsList = {}; this._sendTrackQueue.forEach(item => { topics.forEach(it => { if (item.topic == it.topic) { timeoutsList[it.topic] = setTimeout(() => { let uId = this._app.call.currentCall().users().findUserIdByTopic(it.topic); if(!uId) return; // this._app.call.currentCall().users().get(uId).trackOpenQueue.add(); if(it.mediaType == 0 || it.mediaType == 2) { this._app.call.currentCall().users().get(uId).stopVideo(); setTimeout(()=>{ this._app.call.currentCall().users().get(uId).startVideo(it.topic.replace('Vi-', ''), it); setTimeout(()=>{ this.maybeNextTrack(); }, 200) }, 200) } else if(it.mediaType == 0) { this._app.call.currentCall().users().get(uId).stopAudio(); setTimeout(()=>{ this._app.call.currentCall().users().get(uId).startAudio(it.topic.replace('Vo-', ''), it); setTimeout(()=>{ this.maybeNextTrack(); }, 200) }, 200) } }, 5000) } }) }); this._peer.peerConnection.ontrack = (event) => { const transceiver = event.transceiver; console.log('[media][ontrack] ', {topics, transceiver}); if (transceiver.receiver.track) { transceiver.receiver.track.onunmute = () => { console.log('[media][track.onunmute] ', {topics, transceiver}); // if (topics.length == 1 && topics[0].mediaType == 2) // screenShareTopicHandler(transceiver); // else normalTopicHandler(topics, transceiver); transceiver.receiver.track.onunmute = null; } transceiver.receiver.track.onmute = () => { console.log('[media][track.onmute] debug transceiver.receiver.track.onmute', {transceiver}); transceiver.receiver.track.onmute = null; // this.repairMutedTracks(); } } /** * Disable on track when we are done adding requested tracks */ this._onTrackCalls++; if (this._onTrackCalls == topics.length) { this._peer.peerConnection.ontrack = null; this._onTrackCalls = 0; } } let that = this; function normalTopicHandler(topics2, transceiver) { let cTrackData; topics2.forEach(item => { if (item.mids.includes(transceiver.mid)) { that._trackList.forEach(it => { if (it.topic === item.topic) { clearTimeout(timeoutsList[it.topic]); console.log('[media][onTrack][match] , clientId: ', it.clientId,' , topic: ', it.topic, ', mid: ', transceiver.mid, {transceiver}); it.mid = transceiver.mid; it.transceiver = transceiver; cTrackData = it; } }); } }); if (cTrackData) { cTrackData.track = transceiver.receiver.track; cTrackData.onTrackCallback(cTrackData, transceiver.receiver.track); } else { console.error('[media][onTrack][mismatch] normalTopicHandler cTrackData not found.', {transceiver}, {topics}); } } function screenShareTopicHandler(transceiver) { let cTrackData; cTrackData = that._trackList.find(item => item.mediaType == 2); if (cTrackData) { clearTimeout(timeoutsList[cTrackData.topic]); cTrackData.track = transceiver.receiver.track; cTrackData.onTrackCallback(cTrackData, transceiver.receiver.track); } else { console.error('[SDK][ontrack] screenShareTopicHandler cTrackData not found.', {transceiver}, {topics}); } } this._peer.processOffer(jsonMessage.sdpOffer, (error, sdpAnswer) => { if (error) { console.error('[SDK][processOffer] Error: ', {error}); return; } console.log('[media][RECIVE_SDP_ANSWER] Sending.. , clientIds: ', topics.map(it => it.clientId).join(','),' ||| topics: ', topics.map(it => it.topic).join(',')); this._app.call.currentCall().sendCallMessage({ id: "RECIVE_SDP_ANSWER", sdpAnswer, token: this._app.sdkParams.token, brokerAddress: this._brokerAddress, addition: topics }, null, {}); setTimeout(() => { callback && callback(); }); }); } handleProcessSDPOfferForReceiveTrackUseExsistingTracks(jsonMessage, callback) { let that = this; this._firstSub = false; let topics = JSON.parse(jsonMessage.topic); console.log('[media][PROCESS_SDP_OFFER/UPDATE using exist tracks] Received.. , clientIds: ', topics.map(it => it.clientId).join(','),' ||| topics: ', topics.map(it => it.topic).join(','), ', sendTrackQueue: ', this._sendTrackQueue); this._sendTrackQueue.forEach(item => { topics.forEach(it => { if (item.topic == it.topic) { it.onTrackCallback(it); } }) }); // this._bindReceiveIceCandidateCallback(); // this._peer.peerConnection.ontrack = (event) => { // const transceiver = event.transceiver; // console.log('[media][ontrack] ', {topics, transceiver}); // if (transceiver.receiver.track) { // transceiver.receiver.track.onunmute = () => { // console.log('[media][track.onunmute] ', {topics, transceiver}); // // if (topics.length == 1 && topics[0].mediaType == 2) // screenShareTopicHandler(transceiver); // else // normalTopicHandler(topics, transceiver); // // transceiver.receiver.track.onunmute = null; // } // transceiver.receiver.track.onmute = () => { // console.log('[media][track.onmute] debug transceiver.receiver.track.onmute', {transceiver}); // transceiver.receiver.track.onmute = null; // this.repairMutedTracks(); // } // // } // // /** // * Disable on track when we are done adding requested tracks // */ // this._onTrackCalls++; // if (this._onTrackCalls == topics.length) { // this._peer.peerConnection.ontrack = null; // this._onTrackCalls = 0; // } // } // function normalTopicHandler(topics2, transceiver) { // let cTrackData; // topics2.forEach(item => { // if (item.mids.includes(transceiver.mid)) { // that._trackList.forEach(it => { // if (it.topic === item.topic) { // console.log('[media][onTrack][match] , clientId: ', it.clientId,' , topic: ', it.topic, ', mid: ', transceiver.mid, {transceiver}); // // console.log('debug matched mid: ', transceiver.mid, ' for topic: ', item.topic, transceiver); // it.mid = transceiver.mid; // cTrackData = it; // } // }); // } // }); // if (cTrackData) { // cTrackData.track = transceiver.receiver.track; // cTrackData.onTrackCallback(cTrackData, transceiver.receiver.track); // } else { // console.error('[media][onTrack][mismatch] normalTopicHandler cTrackData not found.', {transceiver}, {topics}); // // console.error('[SDK][ontrack] normalTopicHandler cTrackData not found.', {transceiver}, {topics}); // } // } // function screenShareTopicHandler(transceiver) { // let cTrackData; // cTrackData = that._trackList.find(item => item.mediaType == 2); // if (cTrackData) { // cTrackData.track = transceiver.receiver.track; // cTrackData.onTrackCallback(cTrackData, transceiver.receiver.track); // } else { // console.error('[SDK][ontrack] screenShareTopicHandler cTrackData not found.', {transceiver}, {topics}); // } // } this._peer.processOffer(jsonMessage.sdpOffer, (error, sdpAnswer) => { if (error) { console.error('[SDK][processOffer] Error: ', {error}); return; } console.log('[media][RECIVE_SDP_ANSWER] Sending.. , clientIds: ', topics.map(it => it.clientId).join(','),' ||| topics: ', topics.map(it => it.topic).join(',')); this._app.call.currentCall().sendCallMessage({ id: "RECIVE_SDP_ANSWER", sdpAnswer, token: this._app.sdkParams.token, brokerAddress: this._brokerAddress, addition: topics }, null, {}); setTimeout(() => { callback && callback(); }); }); } addNegotiationOfferToQueue(offer, topics) { this._negotiationOfferUpdate.push({offer, topics}) // this._negotiationOfferUpdate.sdpOffer = offer; // this._negotiationOfferUpdate.topics = topics; } _bindReceiveIceCandidateCallback(){ this._peer.peerConnection.onicecandidate = ({candidate}) => { if(!candidate) return; this._app.call.currentCall().sendCallMessage({ id: "RECIVE_ADD_ICE_CANDIDATE", brokerAddress: this._brokerAddress, token: this._app.sdkParams.token, chatId: this._callId, iceCandidate: JSON.stringify(candidate), }, null, {}); }; } handleProcessSDPOfferForRenegotiate() { this._bindReceiveIceCandidateCallback(); let localSdpObject = this._negotiationOfferUpdate.shift(); this._peer.processOffer(localSdpObject.offer, (error, sdpAnswer) => { if (error) { console.error('[SDK][processOffer] Error: ', {error}); this._onPeerFailed(this._direction); return; } this._app.call.currentCall().sendCallMessage({ id: "RECIVE_SDP_ANSWER", sdpAnswer, token: this._app.sdkParams.token, brokerAddress: this._brokerAddress, deletion: (!Array.isArray(localSdpObject.topics)? JSON.parse(localSdpObject.topics) : localSdpObject.topics) }, null, {}); // setTimeout(() => { // callback && callback(); // }); }); } handleProcessLatestSDPOffer(jsonMessage, callback) { this._bindReceiveIceCandidateCallback(); this._peer.processOffer(jsonMessage.sdpOffer, (error, sdpAnswer) => { if (error) { return; } this._app.call.currentCall().sendCallMessage({ id: "RECIVE_SDP_ANSWER", sdpAnswer, token: this._app.sdkParams.token, brokerAddress: this._brokerAddress, }, null, {}); setTimeout(() => { callback && callback(); }, 100); }); } repairMutedTracks(){ this._trackList.forEach(item => { if(item.track && item.track.mute) { console.log('[media] repairMutedTracks()', item.topic, {item}); this.removeFailedTrack(item); this.processingCurrentTrackCompleted(); item.onOpenFailure(item); } }) } getPeer() { return this._peer; } _destroyPeer() { if(this._peer) { this._peer.dispose(); this._peer = null; } } async destroy() { this._isDestroyed = true; this._destroyPeer(); } isDestroyed() { return this._isDestroyed; } changeVideoSendStream(stream) { const currentTrack = this._trackList.find(it => it.mediaType === 0) if (!currentTrack) { console.error("webcam src not found") } const newTrackId = this._app.call.currentCall().sendPeerManager().getPeer().switchVideoStream(currentTrack.currentTrackId, stream) if (newTrackId) { currentTrack.currentTrackId = newTrackId } } getTracksList() { return this._trackList; } getIsReConnecting() { return this._isReconnecting; } setIsReconnecting(val){ this._isReconnecting = val; } sendOpenDone() { this._sendOpenDone = true; } isSendOpenDone(){ return this._sendOpenDone; } getPeerStatus() { if(this.isPeerConnected()) return 'connected'; else if(this.isPeerFailed()) return 'failed'; else if(this.isPeerConnecting()) return 'connecting'; else if(this.isPeerDisconnected()) return 'disconnected'; } resetSendQueue(){ this._addTrackQueue = []; this._sendTrackQueue = []; this._canProcessNextTrack = true; this._negotiationOfferUpdate = []; } } export default PeerConnectionManager