From 650315b8e9ae41cd0de878895ce3155611cc1679 Mon Sep 17 00:00:00 2001 From: Dina Wee Date: Tue, 14 Sep 2021 05:05:03 +0000 Subject: [PATCH 1/8] Merged in Update-ios-regex (pull request #438) * Update regex for Chrome iOS * Fixes for retrieving iOS version depending on device type - iPhone or iPad --- src/adapter.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/adapter.js b/src/adapter.js index f020a2476..951364df2 100644 --- a/src/adapter.js +++ b/src/adapter.js @@ -138,9 +138,10 @@ AdapterJS.parseWebrtcDetectedBrowser = function () { } else if (navigator.userAgent.indexOf('CriOS') > 0) { hasMatch = navigator.userAgent.match(/CriOS\/([0-9]+)\./) || []; - const iOSVersion = navigator.userAgent.match(/CPU OS ([0-9]+)_([0-9]+)/g); + const iOSVersion = navigator.userAgent.match(/CPU( iPhone| iPad)? OS ([0-9]+)_([0-9]+)/g); + const parts = iOSVersion[0].split(' '); // iOS Version 14 and above supports webrtc - const isCompatible = iOSVersion[0].split(' ')[2].split('_')[0] > 13; + const isCompatible = parts[parts.length - 1].split('_')[0] > 13; // last section contains the version number if (isCompatible) { window.webrtcDetectedVersion = parseInt(hasMatch[1] || '0', 10); window.webrtcMinimumVersion = 53; From 7907ecea38acbaa6ba812d3d8447ce5fb51240ea Mon Sep 17 00:00:00 2001 From: Dina Wee Date: Wed, 15 Sep 2021 04:54:40 +0000 Subject: [PATCH 2/8] Merged in ESS-2046-renegotiation-loop-bug-fixes (pull request #439) ESS-2046 renegotiation loop bug fixes * ESS-2046: Fixes for bug in renegotiation loop - Renegotiation loop occured when the below series of events happen 1. Peer A and Peer B join the room with audio and video 2. Peer A stops stream, then starts audio and video stream 3. Peer B stops stream, then starts audio and video stream 4. Observe renegotiation loop - This is due to the original array of pcSenders containing null tracks being referenced and used to retrieve the senders based on the index. It results in a non-match and a return value of isRenegoNeeded=true. - To fix this, a new array of pcSendersWithTracks is declared and all senders with tracks pushed into the array, from which to later ref and retreive the sender based on the index. * Minor refactoring --- src/peer-connection/helpers/renegotiateIfNeeded.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/peer-connection/helpers/renegotiateIfNeeded.js b/src/peer-connection/helpers/renegotiateIfNeeded.js index 66c5fad54..98a7c774e 100644 --- a/src/peer-connection/helpers/renegotiateIfNeeded.js +++ b/src/peer-connection/helpers/renegotiateIfNeeded.js @@ -22,8 +22,11 @@ const renegotiateIfNeeded = (state, peerId) => { return resolve(isRenegoNeeded); } + const pcSendersWithTracks = []; + // Filter for senders with tracks pcSenders.forEach((pcSender) => { if (pcSender.track) { // if track is null, the sender does not transmit anything + pcSendersWithTracks.push(pcSender); senderGetStatsPromises.push(pcSender.getStats()); } }); @@ -34,12 +37,12 @@ const renegotiateIfNeeded = (state, peerId) => { resolvedResults.forEach((reports, senderIndex) => { reports.forEach((report) => { if (report && report.ssrc) { - transmittingSenders[report.ssrc] = pcSenders[senderIndex]; + transmittingSenders[report.ssrc] = pcSendersWithTracks[senderIndex]; } else if (report && report.type === 'ssrc' && report.id.indexOf('send') > 1) { // required for retrieving sender information for react // native ios report.values.forEach((value) => { if (value.ssrc) { - transmittingSenders[value.ssrc] = pcSenders[senderIndex]; + transmittingSenders[value.ssrc] = pcSendersWithTracks[senderIndex]; } }); } From 1430a9cc0215db2ca74ff112c34e716e32f0f9fe Mon Sep 17 00:00:00 2001 From: Dina Wee Date: Thu, 16 Sep 2021 06:28:20 +0000 Subject: [PATCH 3/8] Merged in ESS-2090-refactor-onRemoteAnswer-onRemoteOffer (pull request #440) ESS-2090: Refactoring of negotiation piece * Refactor offerAndAnswer handler * Fix conflicts and merge in development * Merge branch 'development' into ESS-2090-refactor-onRemoteAnswer-onRemoteOffer * Minor refactoring * Refactoring of negotiation --- src/messages.js | 1 + .../handlers/answerAckHandler.js | 4 +- .../message-handler/handlers/answerHandler.js | 4 +- .../handlers/commons/enterAndWelcome.js | 4 +- .../commons/handleSetDescriptionFailure.js | 60 +++ .../commons/handleSetDescriptionSuccess.js | 67 +++ .../handlers/commons/offerAndAnswer.js | 437 +++++++----------- .../handlers/commons/processPeer.js | 1 + .../handlers/commons/setSessionDescription.js | 53 +++ .../message-handler/handlers/enterHandler.js | 4 +- .../message-handler/handlers/offerHandler.js | 4 +- .../handlers/welcomeHandler.js | 4 +- 12 files changed, 368 insertions(+), 275 deletions(-) create mode 100644 src/server-communication/signaling-server/message-handler/handlers/commons/handleSetDescriptionFailure.js create mode 100644 src/server-communication/signaling-server/message-handler/handlers/commons/handleSetDescriptionSuccess.js create mode 100644 src/server-communication/signaling-server/message-handler/handlers/commons/setSessionDescription.js diff --git a/src/messages.js b/src/messages.js index 57f8ede1b..7d65cb114 100644 --- a/src/messages.js +++ b/src/messages.js @@ -185,6 +185,7 @@ const MESSAGES = { FAILED_SET_REMOTE_ANSWER: 'Peer failed to set remote answer.', FAILED_RENEGOTIATION: 'Failed renegotiation after answerAck', NOT_STABLE: 'Dropping of message as signaling state is not stable', + INCORRECT_DESCRIPTION: 'Incorrect session description type', PROCESSING_EXISTING_SDP: 'Dropping message as there is another sessionDescription being processed -->', OFFER_TIEBREAKER: 'Dropping the received offer: self weight is greater than incoming offer weight -->', NO_LOCAL_BUFFERED_OFFER: 'FATAL: No buffered local offer found - Unable to setLocalDescription', diff --git a/src/server-communication/signaling-server/message-handler/handlers/answerAckHandler.js b/src/server-communication/signaling-server/message-handler/handlers/answerAckHandler.js index 41e2df6d5..759490573 100644 --- a/src/server-communication/signaling-server/message-handler/handlers/answerAckHandler.js +++ b/src/server-communication/signaling-server/message-handler/handlers/answerAckHandler.js @@ -7,13 +7,13 @@ import MESSAGES from '../../../../messages'; import { dispatchEvent } from '../../../../utils/skylinkEventManager'; import { handshakeProgress } from '../../../../skylink-events'; import { isEmptyArray } from '../../../../utils/helpers'; -import { parseAndSetRemoteDescription } from './commons/offerAndAnswer'; +import { offerAndAnswerHandler } from './commons/offerAndAnswer'; const hasAppliedBufferedRemoteOffer = (updatedState, targetMid) => { if (updatedState.bufferedRemoteOffers[targetMid] && !isEmptyArray(updatedState.bufferedRemoteOffers[targetMid])) { const offerMessage = updatedState.bufferedRemoteOffers[targetMid].shift(); // the first buffered message logger.log.DEBUG([targetMid, 'RTCSessionDescription', offerMessage.type, MESSAGES.NEGOTIATION_PROGRESS.APPLYING_BUFFERED_REMOTE_OFFER], offerMessage); - parseAndSetRemoteDescription(offerMessage); + offerAndAnswerHandler(offerMessage); Skylink.setSkylinkState(updatedState, updatedState.room.id); return true; } diff --git a/src/server-communication/signaling-server/message-handler/handlers/answerHandler.js b/src/server-communication/signaling-server/message-handler/handlers/answerHandler.js index 3021a6d8a..bc200e904 100644 --- a/src/server-communication/signaling-server/message-handler/handlers/answerHandler.js +++ b/src/server-communication/signaling-server/message-handler/handlers/answerHandler.js @@ -1,7 +1,7 @@ -import { parseAndSetRemoteDescription } from './commons/offerAndAnswer'; +import { offerAndAnswerHandler } from './commons/offerAndAnswer'; const answerHandler = (message) => { - parseAndSetRemoteDescription(message); + offerAndAnswerHandler(message); }; export default answerHandler; diff --git a/src/server-communication/signaling-server/message-handler/handlers/commons/enterAndWelcome.js b/src/server-communication/signaling-server/message-handler/handlers/commons/enterAndWelcome.js index 68c6d0dd0..b44169e40 100644 --- a/src/server-communication/signaling-server/message-handler/handlers/commons/enterAndWelcome.js +++ b/src/server-communication/signaling-server/message-handler/handlers/commons/enterAndWelcome.js @@ -77,12 +77,12 @@ const logStats = (caller, targetMid, state, message) => { }; /** - * Function that parses the enterAndWelcome and welcome message and sends the offer or welcome message. + * Function that parses the enter and welcome message and sends the welcome or offer message. * @param {JSON} message * @param {String} caller * @memberOf SignalingMessageHandler */ -export const parseAndSendWelcome = (message, caller) => { +export const enterAndWelcomeHandler = (message, caller) => { const parsedMsg = parsers.enterAndWelcome(message); const { rid, mid, userInfo, publisherId, diff --git a/src/server-communication/signaling-server/message-handler/handlers/commons/handleSetDescriptionFailure.js b/src/server-communication/signaling-server/message-handler/handlers/commons/handleSetDescriptionFailure.js new file mode 100644 index 000000000..ee222bacc --- /dev/null +++ b/src/server-communication/signaling-server/message-handler/handlers/commons/handleSetDescriptionFailure.js @@ -0,0 +1,60 @@ +import MESSAGES from '../../../../../messages'; +import handleNegotiationStats from '../../../../../skylink-stats/handleNegotiationStats'; +import { dispatchEvent } from '../../../../../utils/skylinkEventManager'; +import { handshakeProgress } from '../../../../../skylink-events'; +import { HANDSHAKE_PROGRESS, TAGS } from '../../../../../constants'; +import Room from '../../../../../room'; +import Skylink from '../../../../../index'; +import logger from '../../../../../logger'; + +// eslint-disable-next-line no-underscore-dangle +const _handleSetOfferAndAnswerFailure = (state, targetMid, description, isRemote, error) => { + const { room, user } = state; + const { STATS_MODULE: { HANDLE_NEGOTIATION_STATS } } = MESSAGES; + + handleNegotiationStats.send(room.id, HANDLE_NEGOTIATION_STATS[description.type.toUpperCase()].set_error, targetMid, description, isRemote, error); + + dispatchEvent(handshakeProgress({ + state: HANDSHAKE_PROGRESS.ERROR, + peerId: isRemote ? targetMid : user.sid, + error, + room: Room.getRoomInfo(room.id), + })); +}; + +const onLocalDescriptionSetFailure = (room, targetMid, localDescription, error) => { + const state = Skylink.getSkylinkState(room.id); + const { peerConnections } = state; + const peerConnection = peerConnections[targetMid]; + const { NEGOTIATION_PROGRESS } = MESSAGES; + + logger.log.ERROR([targetMid, TAGS.SESSION_DESCRIPTION, localDescription.type, NEGOTIATION_PROGRESS.FAILED_SET_LOCAL_DESCRIPTION], error); + + peerConnection.processingLocalSDP = false; + peerConnection.negotiating = false; + + _handleSetOfferAndAnswerFailure(state, targetMid, localDescription, false, error); +}; + +const onRemoteDescriptionSetFailure = (room, targetMid, remoteDescription, error) => { + const state = Skylink.getSkylinkState(room.id); + const { peerConnections } = state; + const peerConnection = peerConnections[targetMid]; + const { type } = remoteDescription; + + logger.log.ERROR([targetMid, TAGS.SESSION_DESCRIPTION, type, `${MESSAGES.NEGOTIATION_PROGRESS.ERRORS.FAILED_SET_REMOTE_DESCRIPTION} ->`], { + error, + state: peerConnection.signalingState, + [type]: remoteDescription, + }); + + peerConnection.processingRemoteSDP = false; + peerConnection.negotiating = false; + + _handleSetOfferAndAnswerFailure(state, targetMid, remoteDescription, true, error); +}; + +export { + onLocalDescriptionSetFailure, + onRemoteDescriptionSetFailure, +}; diff --git a/src/server-communication/signaling-server/message-handler/handlers/commons/handleSetDescriptionSuccess.js b/src/server-communication/signaling-server/message-handler/handlers/commons/handleSetDescriptionSuccess.js new file mode 100644 index 000000000..e3f23a793 --- /dev/null +++ b/src/server-communication/signaling-server/message-handler/handlers/commons/handleSetDescriptionSuccess.js @@ -0,0 +1,67 @@ +import MESSAGES from '../../../../../messages'; +import Skylink from '../../../../../index'; +import logger from '../../../../../logger'; +import { HANDSHAKE_PROGRESS, TAGS } from '../../../../../constants'; +import { dispatchEvent } from '../../../../../utils/skylinkEventManager'; +import { handshakeProgress } from '../../../../../skylink-events'; +import Room from '../../../../../room'; +import IceConnection from '../../../../../ice-connection'; + +// eslint-disable-next-line no-underscore-dangle +const _setPeerConnectionInstate = (RTCPeerConnection, room, targetMid) => { + const updatedState = Skylink.getSkylinkState(room.id); + updatedState.peerConnections[targetMid] = RTCPeerConnection; + Skylink.setSkylinkState(updatedState, room.id); +}; + +const setPeerConnectionInState = (RTCPeerConnection, room, targetMid) => _setPeerConnectionInstate(RTCPeerConnection, room, targetMid); + +const onRemoteDescriptionSetSuccess = (RTCPeerConnection, room, targetMid, remoteDescription) => { + const { type } = remoteDescription; + const { NEGOTIATION_PROGRESS } = MESSAGES; + + const updatedState = Skylink.getSkylinkState(room.id); + updatedState.peerConnections[targetMid].processingRemoteSDP = false; + + if (remoteDescription.type === 'offer') { + updatedState.peerConnections[targetMid].setOffer = 'remote'; + } else if (remoteDescription.type === 'answer') { + updatedState.peerConnections[targetMid].setAnswer = 'remote'; + } + + Skylink.setSkylinkState(updatedState, room.id); + + logger.log.DEBUG([targetMid, TAGS.SESSION_DESCRIPTION, type, NEGOTIATION_PROGRESS.SET_REMOTE_DESCRIPTION], remoteDescription); + + dispatchEvent(handshakeProgress({ + state: HANDSHAKE_PROGRESS[remoteDescription.type.toUpperCase()], + peerId: targetMid, + room: Room.getRoomInfo(room.id), + })); + + IceConnection.addIceCandidateFromQueue(targetMid, room); +}; + +const onLocalDescriptionSetSuccess = (RTCPeerConnection, room, targetMid, localDescription) => { + _setPeerConnectionInstate(RTCPeerConnection, room, targetMid); + + const updatedState = Skylink.getSkylinkState(room.id); + const { NEGOTIATION_PROGRESS } = MESSAGES; + + if (localDescription.type === 'offer') { + updatedState.peerConnections[targetMid].setOffer = 'local'; + } else if (localDescription.type === 'answer') { + updatedState.peerConnections[targetMid].setAnswer = 'local'; + } + + updatedState.bufferedLocalOffer[targetMid] = null; + Skylink.setSkylinkState(updatedState, room.id); + + logger.log.DEBUG([targetMid, TAGS.SESSION_DESCRIPTION, localDescription.type, NEGOTIATION_PROGRESS.SET_LOCAL_DESCRIPTION], localDescription); +}; + +export { + setPeerConnectionInState, + onLocalDescriptionSetSuccess, + onRemoteDescriptionSetSuccess, +}; diff --git a/src/server-communication/signaling-server/message-handler/handlers/commons/offerAndAnswer.js b/src/server-communication/signaling-server/message-handler/handlers/commons/offerAndAnswer.js index 6adb19164..d8a8824fb 100644 --- a/src/server-communication/signaling-server/message-handler/handlers/commons/offerAndAnswer.js +++ b/src/server-communication/signaling-server/message-handler/handlers/commons/offerAndAnswer.js @@ -1,137 +1,32 @@ -/* eslint-disable no-unused-vars,no-multi-assign */ import Skylink from '../../../../../index'; import logger from '../../../../../logger'; import { - TAGS, PEER_CONNECTION_STATE, HANDSHAKE_PROGRESS, DATA_CHANNEL_STATE, + TAGS, PEER_CONNECTION_STATE, DATA_CHANNEL_STATE, } from '../../../../../constants'; -import IceConnection from '../../../../../ice-connection/index'; import SkylinkSignalingServer from '../../../index'; import PeerConnection from '../../../../../peer-connection/index'; -import { handshakeProgress } from '../../../../../skylink-events'; -import { dispatchEvent } from '../../../../../utils/skylinkEventManager'; import handleNegotiationStats from '../../../../../skylink-stats/handleNegotiationStats'; import MESSAGES from '../../../../../messages'; import PeerMedia from '../../../../../peer-media/index'; -import SessionDescription from '../../../../../session-description'; -import Room from '../../../../../room'; +import { onLocalDescriptionSetFailure, onRemoteDescriptionSetFailure } from './handleSetDescriptionFailure'; +import { setPeerConnectionInState, onRemoteDescriptionSetSuccess, onLocalDescriptionSetSuccess } from './handleSetDescriptionSuccess'; +import { setRemoteDescription, setLocalDescription } from './setSessionDescription'; -const handleSetOfferAndAnswerSuccess = (state, targetMid, description, isRemote) => { - const { STATS_MODULE: { HANDLE_NEGOTIATION_STATS } } = MESSAGES; - const { peerConnections, bufferedLocalOffer, room } = state; - const peerConnection = peerConnections[targetMid]; - const msgType = description.type === 'offer' ? 'OFFER' : 'ANSWER'; - - handleNegotiationStats.send(room.id, HANDLE_NEGOTIATION_STATS[msgType].set, targetMid, description, isRemote); - - if (isRemote) { // handshake progress is triggered on the local end after sdp it is created - dispatchEvent(handshakeProgress({ - state: HANDSHAKE_PROGRESS[msgType], - peerId: targetMid, - room: Room.getRoomInfo(room.id), - })); - } - - if (isRemote) { - if (description.type === 'offer') { - peerConnection.setOffer = 'remote'; - } else { - peerConnection.setAnswer = 'remote'; - } - IceConnection.addIceCandidateFromQueue(targetMid, room); - } else { - bufferedLocalOffer[targetMid] = null; - if (description.type === 'offer') { - peerConnection.setOffer = 'local'; - } else { - peerConnection.setAnswer = 'local'; - } - } - - Skylink.setSkylinkState(state, room.id); -}; - -const handleSetOfferAndAnswerFailure = (state, targetMid, description, isRemote, error) => { - const { room, user } = state; - const { STATS_MODULE: { HANDLE_NEGOTIATION_STATS } } = MESSAGES; - const msgType = description.type === 'offer' ? 'OFFER' : 'ANSWER'; - - handleNegotiationStats.send(room.id, HANDLE_NEGOTIATION_STATS[msgType].set_error, targetMid, description, isRemote, error); - - dispatchEvent(handshakeProgress({ - state: HANDSHAKE_PROGRESS.ERROR, - peerId: isRemote ? targetMid : user.sid, - error, - room: Room.getRoomInfo(room.id), - })); -}; - -// modifying the remote description received -const mungeSDP = (targetMid, sessionDescription, roomKey) => { - const mungedSessionDescription = sessionDescription; - // TODO: Below SDP methods needs to be implemented in the SessionDescription Class. - mungedSessionDescription.sdp = SessionDescription.setSDPBitrate(targetMid, mungedSessionDescription, roomKey); - mungedSessionDescription.sdp = SessionDescription.removeSDPFilteredCandidates(targetMid, mungedSessionDescription, roomKey); - - logger.log.DEBUG([targetMid, TAGS.SESSION_DESCRIPTION, mungedSessionDescription.type, `Updated remote ${mungedSessionDescription.type} ->`], mungedSessionDescription); - return mungedSessionDescription; -}; - -const setLocalDescription = (room, targetMid, localDescription) => { - const state = Skylink.getSkylinkState(room.id); - const { peerConnections } = state; - const { type } = localDescription; - const peerConnection = peerConnections[targetMid]; - const { STATS_MODULE } = MESSAGES; - const msgType = type === 'offer' ? 'OFFER' : 'ANSWER'; - - peerConnection.processingLocalSDP = true; - - handleNegotiationStats.send(room.id, STATS_MODULE.HANDLE_NEGOTIATION_STATS[msgType][type], targetMid, localDescription, false); - - return peerConnection.setLocalDescription(localDescription) - .then(() => peerConnection); -}; +const setLocalOffer = (room, targetMid, localDescription) => setLocalDescription(room, targetMid, localDescription); -const onLocalDescriptionSetSuccess = (RTCPeerConnection, room, targetMid, localDescription) => { - const state = Skylink.getSkylinkState(room.id); - const { peerConnections } = state; - const { NEGOTIATION_PROGRESS } = MESSAGES; - const peerConnection = peerConnections[targetMid] = RTCPeerConnection; +const setLocalAnswer = (room, targetMid, localDescription) => setLocalDescription(room, targetMid, localDescription); - logger.log.DEBUG([targetMid, TAGS.SESSION_DESCRIPTION, localDescription.type, NEGOTIATION_PROGRESS.SET_LOCAL_DESCRIPTION], localDescription); +const onLocalOfferSetSuccess = (RTCPeerConnection, room, targetMid, localDescription) => onLocalDescriptionSetSuccess(RTCPeerConnection, room, targetMid, localDescription); - peerConnection.processingLocalSDP = false; - handleSetOfferAndAnswerSuccess(state, targetMid, localDescription, false); -}; +const onLocalAnswerSetSuccess = (RTCPeerConnection, room, targetMid, localDescription) => onLocalDescriptionSetSuccess(RTCPeerConnection, room, targetMid, localDescription); -const onLocalDescriptionSetFailure = (room, targetMid, localDescription, error) => { - const state = Skylink.getSkylinkState(room.id); - const { peerConnections } = state; - const peerConnection = peerConnections[targetMid]; - const { NEGOTIATION_PROGRESS } = MESSAGES; +const onLocalOfferSetFailure = (room, targetMid, localDescription, error) => onLocalDescriptionSetFailure(room, targetMid, localDescription, error); - logger.log.ERROR([targetMid, TAGS.SESSION_DESCRIPTION, localDescription.type, NEGOTIATION_PROGRESS.FAILED_SET_LOCAL_DESCRIPTION], error); +const onLocalAnswerSetFailure = (room, targetMid, localDescription, error) => onLocalDescriptionSetFailure(room, targetMid, localDescription, error); - peerConnection.processingLocalSDP = false; - peerConnection.negotiating = false; +const setRemoteOffer = (room, targetMid, remoteDescription) => setRemoteDescription(room, targetMid, remoteDescription); - handleSetOfferAndAnswerFailure(state, targetMid, localDescription, false, error); -}; - -const setRemoteDescription = (room, targetMid, remoteDescription) => { - const state = Skylink.getSkylinkState(room.id); - const { peerConnections } = state; - const { type } = remoteDescription; - const { STATS_MODULE } = MESSAGES; - const peerConnection = peerConnections[targetMid]; - const msgType = type === 'offer' ? 'OFFER' : 'ANSWER'; - - peerConnection.processingRemoteSDP = true; - const mungedSessionDescription = mungeSDP(targetMid, remoteDescription, room.id); - handleNegotiationStats.send(room.id, STATS_MODULE.HANDLE_NEGOTIATION_STATS[msgType][type], targetMid, mungedSessionDescription, true); - return peerConnection.setRemoteDescription(mungedSessionDescription) - .then(() => peerConnection); -}; +const setRemoteAnswer = (room, targetMid, remoteDescription) => setRemoteDescription(room, targetMid, remoteDescription); const sendAnswerAck = (state, targetMid, success) => { const updatedState = state; @@ -142,27 +37,23 @@ const sendAnswerAck = (state, targetMid, success) => { signaling.answerAck(state, targetMid, success); }; -const onRemoteDescriptionSetSuccess = (RTCPeerConnection, room, targetMid, remoteDescription) => { - const signaling = new SkylinkSignalingServer(); - const { type } = remoteDescription; - const { NEGOTIATION_PROGRESS, DATA_CHANNEL } = MESSAGES; +const onRemoteOfferSetSuccess = (RTCPeerConnection, room, targetMid, remoteDescription) => { + setPeerConnectionInState(RTCPeerConnection, room, targetMid); + onRemoteDescriptionSetSuccess(RTCPeerConnection, room, targetMid, remoteDescription); + // create and return the answer const state = Skylink.getSkylinkState(room.id); - const { peerConnections } = state; - const peerConnection = peerConnections[targetMid] = RTCPeerConnection; - - logger.log.DEBUG([targetMid, TAGS.SESSION_DESCRIPTION, type, NEGOTIATION_PROGRESS.SET_REMOTE_DESCRIPTION], remoteDescription); + const signaling = new SkylinkSignalingServer(); + return signaling.answer(state, targetMid); +}; - peerConnection.processingRemoteSDP = false; +const onRemoteAnswerSetSuccess = (RTCPeerConnection, room, targetMid, remoteDescription) => { + setPeerConnectionInState(RTCPeerConnection, room, targetMid); + onRemoteDescriptionSetSuccess(RTCPeerConnection, room, targetMid, remoteDescription); - if (type === 'offer') { - handleSetOfferAndAnswerSuccess(state, targetMid, remoteDescription, true); - return signaling.answer(state, targetMid); - } - // FIXME: why is this needed? - if (state.peerMessagesStamps[targetMid]) { - state.peerMessagesStamps[targetMid].hasRestart = false; - } + const state = Skylink.getSkylinkState(room.id); + const peerConnection = state.peerConnections[targetMid]; + const { DATA_CHANNEL } = MESSAGES; // if remote peer does not have data channel if (state.peerDataChannels[targetMid] && (peerConnection.remoteDescription.sdp.indexOf('m=application') === -1 || peerConnection.remoteDescription.sdp.indexOf('m=application 0') > 0)) { @@ -170,36 +61,24 @@ const onRemoteDescriptionSetSuccess = (RTCPeerConnection, room, targetMid, remot PeerConnection.closeDataChannel(room.id, targetMid); } - handleSetOfferAndAnswerSuccess(state, targetMid, remoteDescription, true); - sendAnswerAck(state, targetMid, true); - return true; + return sendAnswerAck(state, targetMid, true); }; -const onRemoteDescriptionSetFailure = (room, targetMid, remoteDescription, error) => { - const state = Skylink.getSkylinkState(room.id); - const { peerConnections } = state; - const peerConnection = peerConnections[targetMid]; - const { type } = remoteDescription; - - logger.log.ERROR([targetMid, TAGS.SESSION_DESCRIPTION, type, `${MESSAGES.NEGOTIATION_PROGRESS.ERRORS.FAILED_SET_REMOTE_DESCRIPTION} ->`], { - error, - state: peerConnection.signalingState, - [type]: remoteDescription, - }); +const onRemoteOfferSetFailure = (room, targetMid, remoteDescription, error) => onRemoteDescriptionSetFailure(room, targetMid, remoteDescription, error); - peerConnection.processingRemoteSDP = false; - peerConnection.negotiating = false; +const onRemoteAnswerSetFailure = (room, targetMid, remoteDescription, error) => { + onRemoteDescriptionSetFailure(room, targetMid, remoteDescription, error); - handleSetOfferAndAnswerFailure(state, targetMid, remoteDescription, true, error); - - if (type === 'answer') { - sendAnswerAck(state, targetMid, false); - } + const state = Skylink.getSkylinkState(room.id); + sendAnswerAck(state, targetMid, false); }; -const updateState = (state, message) => { +const updateStateInformation = (state, message) => { const updatedState = state; - const { userInfo, rid, mid } = message; + const { + userInfo, rid, mid, mediaInfoList, + } = message; + const { room } = updatedState; const updatedUserInfo = userInfo; const targetMid = mid; @@ -211,27 +90,27 @@ const updateState = (state, message) => { } updatedState.peerConnections[targetMid].negotiating = true; - Skylink.setSkylinkState(updatedState, rid); + + PeerMedia.setPeerMediaInfo(room, targetMid, mediaInfoList); + PeerMedia.deleteUnavailableMedia(room, targetMid); // mediaState can be unavailable during renegotiation }; -const canProceed = (state, message) => { +const canProceed = (message) => { const { - weight, type, mid, sdp, resend, + weight, type, mid, sdp, resend, rid, } = message; + const state = Skylink.getSkylinkState(rid); const { peerPriorityWeight, bufferedLocalOffer, room, peerConnections, } = state; const { STATS_MODULE, NEGOTIATION_PROGRESS, PEER_CONNECTION } = MESSAGES; const targetMid = mid; const peerConnection = peerConnections[targetMid]; - const msgType = type === 'offer' ? 'OFFER' : 'ANSWER'; - let error = null; if (!peerConnection) { logger.log.ERROR([targetMid, null, type, `${PEER_CONNECTION.NO_PEER_CONNECTION}. Unable to set${type === 'offer' ? 'Remote' : 'Local'}Offer.`]); - error = PEER_CONNECTION.NO_PEER_CONNECTION; - handleNegotiationStats.send(room.id, STATS_MODULE.HANDLE_NEGOTIATION_STATS[msgType].dropped, targetMid, message, true, error); + handleNegotiationStats.send(room.id, STATS_MODULE.HANDLE_NEGOTIATION_STATS[type.toUpperCase()].dropped, targetMid, message, true, PEER_CONNECTION.NO_PEER_CONNECTION); return false; } @@ -239,119 +118,151 @@ const canProceed = (state, message) => { processingRemoteSDP, processingLocalSDP, negotiating, } = peerConnection; - if (type === 'offer' && peerConnections[targetMid].signalingState !== PEER_CONNECTION_STATE.STABLE) { - logger.log.WARN([targetMid, null, type, NEGOTIATION_PROGRESS.ERRORS.NOT_STABLE], { - signalingState: peerConnections[targetMid].signalingState, - isRestart: !!resend, - }); - error = `Peer connection state is ${peerConnections[targetMid].signalingState}.`; - } + switch (type) { + case 'offer': + if (peerConnections[targetMid].signalingState !== PEER_CONNECTION_STATE.STABLE) { + logger.log.WARN([targetMid, null, type, NEGOTIATION_PROGRESS.ERRORS.NOT_STABLE], { + signalingState: peerConnections[targetMid].signalingState, + isRestart: !!resend, + }); + handleNegotiationStats.send(room.id, STATS_MODULE.HANDLE_NEGOTIATION_STATS[type.toUpperCase()].dropped, targetMid, message, true, `Peer connection state is ${peerConnections[targetMid].signalingState}.`); + return false; + } - if (type === 'offer' && bufferedLocalOffer[targetMid] && peerPriorityWeight > weight) { - logger.log.WARN([targetMid, null, type, NEGOTIATION_PROGRESS.ERRORS.OFFER_TIEBREAKER], { - selfWeight: peerPriorityWeight, - messageWeight: weight, - }); - error = NEGOTIATION_PROGRESS.ERRORS.OFFER_TIEBREAKER; - } + if (bufferedLocalOffer[targetMid] && peerPriorityWeight > weight) { + logger.log.WARN([targetMid, null, type, NEGOTIATION_PROGRESS.ERRORS.OFFER_TIEBREAKER], { + selfWeight: peerPriorityWeight, + messageWeight: weight, + }); + handleNegotiationStats.send(room.id, STATS_MODULE.HANDLE_NEGOTIATION_STATS[type.toUpperCase()].dropped, targetMid, message, true, NEGOTIATION_PROGRESS.ERRORS.OFFER_TIEBREAKER); + return false; + } - // if processing remote SDP - if (processingRemoteSDP) { - logger.log.WARN([targetMid, TAGS.SESSION_DESCRIPTION, type, NEGOTIATION_PROGRESS.ERRORS.PROCESSING_EXISTING_SDP], sdp); - error = NEGOTIATION_PROGRESS.ERRORS.PROCESSING_EXISTING_SDP; - - // or completed processing local and remote sdp but answerAck has not been received - } else if ((!processingLocalSDP && !processingRemoteSDP && negotiating) && type === 'offer') { - // add to bufferedRemoteOffer - const updatedState = state; - logger.log.DEBUG([targetMid, TAGS.SESSION_DESCRIPTION, type, NEGOTIATION_PROGRESS.ERRORS.ADDING_REMOTE_OFFER_TO_BUFFER], message); - updatedState.bufferedRemoteOffers[targetMid] = updatedState.bufferedRemoteOffers[targetMid] ? updatedState.bufferedRemoteOffers[targetMid] : []; - updatedState.bufferedRemoteOffers[targetMid].push(message); - Skylink.setSkylinkState(updatedState, room.id); - return false; - } + // if processing remote SDP + if (processingRemoteSDP) { + logger.log.WARN([targetMid, TAGS.SESSION_DESCRIPTION, type, NEGOTIATION_PROGRESS.ERRORS.PROCESSING_EXISTING_SDP], sdp); + handleNegotiationStats.send(room.id, STATS_MODULE.HANDLE_NEGOTIATION_STATS[type.toUpperCase()].dropped, targetMid, message, true, NEGOTIATION_PROGRESS.ERRORS.PROCESSING_EXISTING_SDP); + return false; + } - if (error) { - handleNegotiationStats.send(room.id, STATS_MODULE.HANDLE_NEGOTIATION_STATS[msgType].dropped, targetMid, message, true, error); + // or completed processing local and remote sdp but answerAck has not been received + if (!processingLocalSDP && !processingRemoteSDP && negotiating) { + // add to bufferedRemoteOffer + const updatedState = state; + logger.log.DEBUG([targetMid, TAGS.SESSION_DESCRIPTION, type, NEGOTIATION_PROGRESS.ERRORS.ADDING_REMOTE_OFFER_TO_BUFFER], message); + updatedState.bufferedRemoteOffers[targetMid] = updatedState.bufferedRemoteOffers[targetMid] ? updatedState.bufferedRemoteOffers[targetMid] : []; + updatedState.bufferedRemoteOffers[targetMid].push(message); + Skylink.setSkylinkState(updatedState, room.id); + return false; + } + break; + + case 'answer': + // if processing remote SDP + if (processingRemoteSDP) { + logger.log.WARN([targetMid, TAGS.SESSION_DESCRIPTION, type, NEGOTIATION_PROGRESS.ERRORS.PROCESSING_EXISTING_SDP], sdp); + handleNegotiationStats.send(room.id, STATS_MODULE.HANDLE_NEGOTIATION_STATS[type.toUpperCase()].dropped, targetMid, message, true, NEGOTIATION_PROGRESS.ERRORS.PROCESSING_EXISTING_SDP); + return false; + } + break; + + default: + // should not come here + return false; } - return !error; + return true; }; -/** - * Function that parses and sets the remote description for offer and answer. - * @param {JSON} message - * @return {null} - * @memberOf SignalingMessageHandler - * @fires HANDSHAKE_PROGRESS - */ -// eslint-disable-next-line import/prefer-default-export -export const parseAndSetRemoteDescription = (message) => { +const onRemoteAnswer = (message) => { const { - rid, - mid, - type, - sdp, - mediaInfoList, + rid, mid, type, sdp, } = message; const state = Skylink.getSkylinkState(rid); - const { - hasMCU, - room, - bufferedLocalOffer, - } = state; const targetMid = mid; - const msgType = type === 'offer' ? 'OFFER' : 'ANSWER'; - const { NEGOTIATION_PROGRESS } = MESSAGES; - - logger.log.INFO([targetMid, null, type, `Received ${type} from peer. ${msgType}:`], message); - - if (canProceed(state, message)) { - try { - updateState(state, message); - - PeerMedia.setPeerMediaInfo(room, targetMid, mediaInfoList); - PeerMedia.deleteUnavailableMedia(room, targetMid); // mediaState can be unavailable during renegotiation - - if (type === 'offer') { - let localDescription = null; - const remoteDescription = { - type, - sdp: hasMCU ? sdp.replace(/\r\n/g, '\n').split('\n').join('\r\n') : sdp, - }; + const { hasMCU, bufferedLocalOffer, room } = state; + + logger.log.INFO([mid, null, type, 'Received answer from peer. ANSWER:'], message); + + try { + updateStateInformation(state, message); + + if (bufferedLocalOffer[targetMid]) { + const localDescription = bufferedLocalOffer[targetMid]; + const remoteDescription = { + type, + sdp: hasMCU ? sdp.replace(/\r\n/g, '\n').split('\n').join('\r\n') : sdp, + }; + + setLocalOffer(room, targetMid, localDescription) + .then(peerConnection => onLocalOfferSetSuccess(peerConnection, room, targetMid, localDescription)) + .catch(error => onLocalOfferSetFailure(room, targetMid, localDescription, error)) + .then(() => setRemoteAnswer(room, targetMid, remoteDescription)) + .then(peerConnection => onRemoteAnswerSetSuccess(peerConnection, room, targetMid, remoteDescription)) + .catch(error => onRemoteAnswerSetFailure(room, targetMid, remoteDescription, error)); + } else { + logger.log.ERROR([targetMid, TAGS.PEER_CONNECTION, null, MESSAGES.NEGOTIATION_PROGRESS.ERRORS.NO_LOCAL_BUFFERED_OFFER]); + } + } catch (err) { + logger.log.ERROR([mid, TAGS.SESSION_DESCRIPTION, type, 'Failed processing ANSWER ->'], err); + } +}; - setRemoteDescription(room, targetMid, remoteDescription) - .then(peerConnection => onRemoteDescriptionSetSuccess(peerConnection, room, targetMid, remoteDescription)) - .catch(error => onRemoteDescriptionSetFailure(room, targetMid, remoteDescription, error)) - .then((answer) => { - localDescription = { - type: answer.type, - sdp: answer.sdp, - }; - return setLocalDescription(room, targetMid, localDescription); - }) - .then(peerConnection => onLocalDescriptionSetSuccess(peerConnection, room, targetMid, localDescription)) - .catch(error => onLocalDescriptionSetFailure(room, targetMid, localDescription, error)); - } else if (bufferedLocalOffer[targetMid]) { - const localDescription = bufferedLocalOffer[targetMid]; - const remoteDescription = { - type, - sdp: hasMCU ? sdp.replace(/\r\n/g, '\n').split('\n').join('\r\n') : sdp, +const onRemoteOffer = (message) => { + const { + rid, mid, type, sdp, + } = message; + const state = Skylink.getSkylinkState(rid); + const targetMid = mid; + const { room, hasMCU } = state; + const remoteDescription = { + type, + sdp: hasMCU ? sdp.replace(/\r\n/g, '\n').split('\n').join('\r\n') : sdp, + }; + let localDescription = null; + + logger.log.INFO([mid, null, type, 'Received offer from peer. OFFER:'], message); + + try { + updateStateInformation(state, message); + + setRemoteOffer(room, targetMid, remoteDescription) + .then(peerConnection => onRemoteOfferSetSuccess(peerConnection, room, targetMid, remoteDescription)) + .catch(error => onRemoteOfferSetFailure(room, targetMid, remoteDescription, error)) + .then((answer) => { + localDescription = { + type: answer.type, + sdp: answer.sdp, }; + return setLocalAnswer(room, targetMid, localDescription); + }) + .then(peerConnection => onLocalAnswerSetSuccess(peerConnection, room, targetMid, localDescription)) + .catch(error => onLocalAnswerSetFailure(room, targetMid, localDescription, error)); + } catch (err) { + logger.log.ERROR([mid, TAGS.SESSION_DESCRIPTION, type, 'Failed processing OFFER ->'], err); + } +}; - setLocalDescription(room, targetMid, localDescription) - .then(peerConnection => onLocalDescriptionSetSuccess(peerConnection, room, targetMid, localDescription)) - .catch(error => onLocalDescriptionSetFailure(room, targetMid, localDescription, error)) - .then(() => setRemoteDescription(room, targetMid, remoteDescription)) - .then(peerConnection => onRemoteDescriptionSetSuccess(peerConnection, room, targetMid, remoteDescription)) - .catch(error => onRemoteDescriptionSetFailure(room, targetMid, remoteDescription, error)); - } else { - logger.log.ERROR([targetMid, TAGS.PEER_CONNECTION, null, NEGOTIATION_PROGRESS.ERRORS.NO_LOCAL_BUFFERED_OFFER]); - } - } catch (error) { - logger.log.ERROR([targetMid, TAGS.SESSION_DESCRIPTION, type, `Failed processing ${msgType} ->`], error); +/** + * Function that handles the remote offer and answer + * @param {JSON} message + * @memberOf SignalingMessageHandler + * @fires HANDSHAKE_PROGRESS + */ +// eslint-disable-next-line import/prefer-default-export +export const offerAndAnswerHandler = (message) => { + if (canProceed(message)) { + switch (message.type) { + case 'offer': + onRemoteOffer(message); + break; + + case 'answer': + onRemoteAnswer(message); + break; + + default: + // should not come here } } - - return null; }; diff --git a/src/server-communication/signaling-server/message-handler/handlers/commons/processPeer.js b/src/server-communication/signaling-server/message-handler/handlers/commons/processPeer.js index 2c09eecc9..b503aefd5 100644 --- a/src/server-communication/signaling-server/message-handler/handlers/commons/processPeer.js +++ b/src/server-communication/signaling-server/message-handler/handlers/commons/processPeer.js @@ -40,6 +40,7 @@ const processPeer = (params) => { const state = Skylink.getSkylinkState(currentRoom.id); const { hasMCU } = state; const { peerInformations } = state; + if ((!peerInformations[targetMid] && !hasMCU) || (hasMCU && targetMid === PEER_TYPE.MCU && !peerInformations.MCU)) { const hasScreenshare = !!userInfo.screenshare; isNewPeer = true; diff --git a/src/server-communication/signaling-server/message-handler/handlers/commons/setSessionDescription.js b/src/server-communication/signaling-server/message-handler/handlers/commons/setSessionDescription.js new file mode 100644 index 000000000..730b61d5f --- /dev/null +++ b/src/server-communication/signaling-server/message-handler/handlers/commons/setSessionDescription.js @@ -0,0 +1,53 @@ +import Skylink from '../../../../../index'; +import MESSAGES from '../../../../../messages'; +import handleNegotiationStats from '../../../../../skylink-stats/handleNegotiationStats'; +import SessionDescription from '../../../../../session-description'; +import logger from '../../../../../logger'; +import { TAGS } from '../../../../../constants'; + +// modifying the remote description received +// eslint-disable-next-line no-underscore-dangle +const _mungeSDP = (targetMid, sessionDescription, roomKey) => { + const mungedSessionDescription = sessionDescription; + // TODO: Below SDP methods needs to be implemented in the SessionDescription Class. + mungedSessionDescription.sdp = SessionDescription.setSDPBitrate(targetMid, mungedSessionDescription, roomKey); + mungedSessionDescription.sdp = SessionDescription.removeSDPFilteredCandidates(targetMid, mungedSessionDescription, roomKey); + + logger.log.DEBUG([targetMid, TAGS.SESSION_DESCRIPTION, mungedSessionDescription.type, `Updated remote ${mungedSessionDescription.type} ->`], mungedSessionDescription); + return mungedSessionDescription; +}; + +const setRemoteDescription = (room, targetMid, remoteDescription) => { + const state = Skylink.getSkylinkState(room.id); + const { peerConnections } = state; + const { type } = remoteDescription; + const { STATS_MODULE } = MESSAGES; + const peerConnection = peerConnections[targetMid]; + + + peerConnection.processingRemoteSDP = true; + const mungedSessionDescription = _mungeSDP(targetMid, remoteDescription, room.id); + handleNegotiationStats.send(room.id, STATS_MODULE.HANDLE_NEGOTIATION_STATS[type.toUpperCase()][type], targetMid, mungedSessionDescription, true); + return peerConnection.setRemoteDescription(mungedSessionDescription) + .then(() => peerConnection); +}; + +const setLocalDescription = (room, targetMid, localDescription) => { + const state = Skylink.getSkylinkState(room.id); + const { peerConnections } = state; + const { type } = localDescription; + const peerConnection = peerConnections[targetMid]; + const { STATS_MODULE } = MESSAGES; + + peerConnection.processingLocalSDP = true; + + handleNegotiationStats.send(room.id, STATS_MODULE.HANDLE_NEGOTIATION_STATS[type.toUpperCase()][type], targetMid, localDescription, false); + + return peerConnection.setLocalDescription(localDescription) + .then(() => peerConnection); +}; + +export { + setRemoteDescription, + setLocalDescription, +}; diff --git a/src/server-communication/signaling-server/message-handler/handlers/enterHandler.js b/src/server-communication/signaling-server/message-handler/handlers/enterHandler.js index 2cb296358..ada79d35d 100644 --- a/src/server-communication/signaling-server/message-handler/handlers/enterHandler.js +++ b/src/server-communication/signaling-server/message-handler/handlers/enterHandler.js @@ -1,7 +1,7 @@ -import { parseAndSendWelcome, CALLERS } from './commons/enterAndWelcome'; +import { enterAndWelcomeHandler, CALLERS } from './commons/enterAndWelcome'; const enterHandler = (message) => { - parseAndSendWelcome(message, CALLERS.ENTER); + enterAndWelcomeHandler(message, CALLERS.ENTER); }; export default enterHandler; diff --git a/src/server-communication/signaling-server/message-handler/handlers/offerHandler.js b/src/server-communication/signaling-server/message-handler/handlers/offerHandler.js index be66bd508..8baa2a09b 100644 --- a/src/server-communication/signaling-server/message-handler/handlers/offerHandler.js +++ b/src/server-communication/signaling-server/message-handler/handlers/offerHandler.js @@ -1,7 +1,7 @@ -import { parseAndSetRemoteDescription } from './commons/offerAndAnswer'; +import { offerAndAnswerHandler } from './commons/offerAndAnswer'; const offerHandler = (message) => { - parseAndSetRemoteDescription(message); + offerAndAnswerHandler(message); }; export default offerHandler; diff --git a/src/server-communication/signaling-server/message-handler/handlers/welcomeHandler.js b/src/server-communication/signaling-server/message-handler/handlers/welcomeHandler.js index 6c65261cb..c95b7639d 100644 --- a/src/server-communication/signaling-server/message-handler/handlers/welcomeHandler.js +++ b/src/server-communication/signaling-server/message-handler/handlers/welcomeHandler.js @@ -1,7 +1,7 @@ -import { parseAndSendWelcome, CALLERS } from './commons/enterAndWelcome'; +import { enterAndWelcomeHandler, CALLERS } from './commons/enterAndWelcome'; const welcomeHandler = (message) => { - parseAndSendWelcome(message, CALLERS.WELCOME); + enterAndWelcomeHandler(message, CALLERS.WELCOME); }; export default welcomeHandler; From 34c61d014178635ef3837a6d5c80b049e0c9189d Mon Sep 17 00:00:00 2001 From: Dina Wee Date: Thu, 23 Sep 2021 05:16:12 +0000 Subject: [PATCH 4/8] Merged in ESS-2111-negotiation-state (pull request #441) ESS-2111: Implement negotiation state machine * ESS-2111: Refactored negotation piece to implement negotation state machine * ESS-2046: Fixes for FF not renegotiating when the remote peer has no audio and video * ESS-2111: Fixes for extra welcome from remote peer being forwarded by sig --- src/constants.js | 23 ++ src/messages.js | 22 +- src/models/skylink-state.js | 5 + ...ions.js => buildAndSetPeerInformations.js} | 10 +- src/peer-connection/helpers/createOffer.js | 1 - src/peer-connection/helpers/index.js | 8 +- .../peer-addition/createPeerConnection.js | 3 - .../refresh-connection/refreshConnection.js | 4 +- .../restartMCUConnection.js | 4 +- .../restartPeerConnection.js | 4 +- .../refresh-connection/sendRestartOfferMsg.js | 16 - .../helpers/renegotiateIfNeeded.js | 9 +- src/peer-connection/index.js | 4 +- .../signaling-server/index.js | 31 +- .../builders/commons/offerAndAnswer.js | 5 +- .../handlers/answerAckHandler.js | 50 +--- .../message-handler/handlers/answerHandler.js | 6 +- .../message-handler/handlers/byeHandler.js | 1 + .../handlers/commons/enterAndWelcome.js | 102 +------ .../commons/handleSetDescriptionFailure.js | 8 - .../commons/handleSetDescriptionSuccess.js | 7 +- .../handlers/commons/offerAndAnswer.js | 275 ++++-------------- .../handlers/commons/processPeer.js | 131 --------- .../handlers/commons/setSessionDescription.js | 30 +- .../message-handler/handlers/enterHandler.js | 4 +- .../message-handler/handlers/inRoomHandler.js | 2 +- .../message-handler/handlers/offerHandler.js | 6 +- .../handlers/welcomeHandler.js | 4 +- .../helpers/bufferRemoteOffer.js | 14 + .../helpers/getBufferedRemoteOffer.js | 16 + .../negotiationState/helpers/index.js | 15 + .../helpers/logInfoOrErrorAndSendStats.js | 19 ++ .../helpers/processNewPeer.js | 206 +++++++++++++ .../helpers/updateStateInformation.js | 27 ++ .../negotiationState/negotiationState.js | 255 ++++++++++++++++ .../parsers/enterAndWelcome.js | 1 + 36 files changed, 745 insertions(+), 583 deletions(-) rename src/peer-connection/helpers/{buildPeerInformations.js => buildAndSetPeerInformations.js} (57%) delete mode 100644 src/peer-connection/helpers/refresh-connection/sendRestartOfferMsg.js delete mode 100644 src/server-communication/signaling-server/message-handler/handlers/commons/processPeer.js create mode 100644 src/server-communication/signaling-server/negotiationState/helpers/bufferRemoteOffer.js create mode 100644 src/server-communication/signaling-server/negotiationState/helpers/getBufferedRemoteOffer.js create mode 100644 src/server-communication/signaling-server/negotiationState/helpers/index.js create mode 100644 src/server-communication/signaling-server/negotiationState/helpers/logInfoOrErrorAndSendStats.js create mode 100644 src/server-communication/signaling-server/negotiationState/helpers/processNewPeer.js create mode 100644 src/server-communication/signaling-server/negotiationState/helpers/updateStateInformation.js create mode 100644 src/server-communication/signaling-server/negotiationState/negotiationState.js diff --git a/src/constants.js b/src/constants.js index 8ce7a0b1f..4e19074b7 100644 --- a/src/constants.js +++ b/src/constants.js @@ -1825,6 +1825,7 @@ export const TAGS = { ASYNC_MESSAGING: 'ASYNC MESSAGING', ENCRYPTED_MESSAGING: 'ENCRYPTED MESSAGING', STATS: 'STATS', + NEGOTIATION: 'NEGOTIATION', }; /** @@ -2071,4 +2072,26 @@ export const CONFIG_NAME = { SOCKET: 'SOCKET', }; +/** + * The negotiation states for the negotiation state machine + * @type {{WELCOMING: string, LOCAL_OFFER_SENT: string, REMOTE_OFFER_SET: string, REMOTE_ANSWER_RECEIVED: string, LOCAL_OFFER_SET: string, REMOTE_OFFER_RECEIVED: string, LOCAL_ANSWER_SET: string, ENTERING: string, NEGOTIATED: string, REMOTE_ANSWER_SET: string}} + * @private + * @constant + * @readonly + * @memberOf SkylinkConstants + * @since 2.3.3 + */ +export const NEGOTIATION_STATES = { + ENTERING: 'entering', + WELCOMING: 'welcoming', + LOCAL_OFFER_SENT: 'localOfferSent', + LOCAL_OFFER_SET: ' localOfferSet', + REMOTE_OFFER_RECEIVED: 'remoteOfferReceived', + REMOTE_ANSWER_RECEIVED: 'remoteAnswerReceived', + REMOTE_OFFER_SET: 'remoteOfferSet', + LOCAL_ANSWER_SET: 'localAnswerSet', + REMOTE_ANSWER_SET: 'remoteAnswerSet', + NEGOTIATED: 'negotiated', +}; + export const EVENTS = SkylinkEventsConstants; diff --git a/src/messages.js b/src/messages.js index 7d65cb114..b0d54baca 100644 --- a/src/messages.js +++ b/src/messages.js @@ -181,16 +181,20 @@ const MESSAGES = { APPLYING_BUFFERED_REMOTE_OFFER: 'Applying buffered remote offer', ERRORS: { FAILED_SET_LOCAL_DESCRIPTION: 'Failed setting local description -->', - FAILED_SET_REMOTE_DESCRIPTION: 'Failed setting remote description', - FAILED_SET_REMOTE_ANSWER: 'Peer failed to set remote answer.', + FAILED_SET_REMOTE_DESCRIPTION: 'Failed setting remote description -->', + FAILED_SET_REMOTE_ANSWER: 'Remote Peer failed to set answer.', + FAILED_PROCESSING_OFFER: 'Failed processing OFFER ->', + FAILED_PROCESSING_ANSWER: 'Failed processing ANSWER ->', + FAILED_PROCESSING_ANSWER_ACK: 'Failed processing ANSWER_ACK ->', FAILED_RENEGOTIATION: 'Failed renegotiation after answerAck', - NOT_STABLE: 'Dropping of message as signaling state is not stable', - INCORRECT_DESCRIPTION: 'Incorrect session description type', - PROCESSING_EXISTING_SDP: 'Dropping message as there is another sessionDescription being processed -->', OFFER_TIEBREAKER: 'Dropping the received offer: self weight is greater than incoming offer weight -->', NO_LOCAL_BUFFERED_OFFER: 'FATAL: No buffered local offer found - Unable to setLocalDescription', ADDING_REMOTE_OFFER_TO_BUFFER: 'Adding remote offer received to buffer as current negotiation has not completed', STOP_RENEGOTIATION_FORCE_TURN: 'Stopping renegotiation as TURN is not enabled but forceTURN in init options is enforced', + DROPPING_ANSWER: 'Dropping ANSWER as previous negotiation state is not \'LOCAL_OFFER_SENT\'', + DROPPING_ANSWER_ACK: 'Dropping ANSWER_ACK as previous negotiation state is not \'LOCAL_ANSWER_SET\'', + DROPPING_WELCOME_NEG_STATE: 'Dropping WELCOME as previous negotiation state is not \'undefined\'', + DROPPING_WELCOME_MCU_FORWARDED: 'Dropping extra WELCOME from remote peer in MCU room', }, }, SIGNALING: { @@ -325,6 +329,9 @@ const MESSAGES = { BUFFERED: 'buffered', }, HANDLE_NEGOTIATION_STATS: { + WELCOME: { + dropped: 'dropped_welcome', + }, OFFER: { create: 'create_offer', create_error: 'error_create_offer', @@ -332,6 +339,7 @@ const MESSAGES = { set_error: 'error_set_offer', offer: 'offer', dropped: 'dropped_offer', + error: 'error_offer', }, ANSWER: { create: 'create_answer', @@ -340,6 +348,10 @@ const MESSAGES = { set_error: 'error_set_ANSWER', answer: 'answer', dropped: 'dropped_answer', + error: 'error_answer', + }, + ANSWERACK: { + error: 'error_answer_ack', }, }, HANDLE_DATA_CHANNEL_STATS: { diff --git a/src/models/skylink-state.js b/src/models/skylink-state.js index 6ef531c60..0b27f7b79 100644 --- a/src/models/skylink-state.js +++ b/src/models/skylink-state.js @@ -339,6 +339,11 @@ class SkylinkState { this.streamsSettings = {}; this.enableStatsGathering = initOptions.enableStatsGathering; this.dataTransfers = {}; + /** + * Stores the negotiation state keyed by peerId + * @type {{}} + */ + this.negotiationState = {}; } } export default SkylinkState; diff --git a/src/peer-connection/helpers/buildPeerInformations.js b/src/peer-connection/helpers/buildAndSetPeerInformations.js similarity index 57% rename from src/peer-connection/helpers/buildPeerInformations.js rename to src/peer-connection/helpers/buildAndSetPeerInformations.js index 7008e7256..fdbff9774 100644 --- a/src/peer-connection/helpers/buildPeerInformations.js +++ b/src/peer-connection/helpers/buildAndSetPeerInformations.js @@ -1,13 +1,17 @@ +import Skylink from '../../index'; import { DATA_CHANNEL_STATE } from '../../constants'; -const buildPeerInformations = (userInfo, state) => { +const buildAndSetPeerInformations = (peerId, userInfo, state) => { + const updatedState = state; const peerInfo = userInfo; - const peerId = peerInfo.sid; peerInfo.room = state.room.roomName; peerInfo.settings.data = !!(state.peerDataChannels[peerId] && state.peerDataChannels[peerId].main && state.peerDataChannels[peerId].main.channel && state.peerDataChannels[peerId].main.channel.readyState === DATA_CHANNEL_STATE.OPEN); + updatedState.peerInformations[peerId] = peerInfo; + Skylink.setSkylinkState(updatedState, state.room.id); + return peerInfo; }; -export default buildPeerInformations; +export default buildAndSetPeerInformations; diff --git a/src/peer-connection/helpers/createOffer.js b/src/peer-connection/helpers/createOffer.js index e34a06229..c53f207e8 100644 --- a/src/peer-connection/helpers/createOffer.js +++ b/src/peer-connection/helpers/createOffer.js @@ -86,7 +86,6 @@ const createOffer = (currentRoom, targetMid, iceRestart = false, restartOfferMsg logger.log.DEBUG([targetMid, null, null, 'Creating offer with config:'], offerConstraints); peerConnection.endOfCandidates = false; - peerConnection.negotiating = true; peerConnection.sdpConstraints = offerConstraints; Skylink.setSkylinkState(state, currentRoom.id); diff --git a/src/peer-connection/helpers/index.js b/src/peer-connection/helpers/index.js index 554048c54..93afb09ce 100644 --- a/src/peer-connection/helpers/index.js +++ b/src/peer-connection/helpers/index.js @@ -7,18 +7,19 @@ import signalingEndOfCandidates from './signalingEndOfCandidates'; import refreshConnection from './refresh-connection/refreshConnection'; import refreshPeerConnection from './refresh-connection/refreshPeerConnection'; import restartPeerConnection from './refresh-connection/restartPeerConnection'; -import buildPeerInformations from './buildPeerInformations'; +import buildAndSetPeerInformations from './buildAndSetPeerInformations'; import getConnectionStatus from './getConnectionStatus'; import closePeerConnection from './closePeerConnection'; import updatePeerInformationsMediaStatus from './updatePeerInformationsMediaStatus'; import processNewSender from './processNewSender'; +import renegotiateIfNeeded from './renegotiateIfNeeded'; /** * @namespace PeerConnectionHelpers * @description All helper and utility functions for {@link PeerConnection} class are listed here. * @private * @memberOf PeerConnection - * @type {{createOffer, createAnswer, addPeer, sendP2PMessage, getPeersInRoom, signalingEndOfCandidates, refreshConnection, refreshPeerConnection, restartPeerConnection, buildPeerInformations, getConnectionStatus, closePeerConnection, updatePeerInformationsMediaStatus, processNewSender }} + * @type {{createOffer, createAnswer, addPeer, sendP2PMessage, getPeersInRoom, signalingEndOfCandidates, refreshConnection, refreshPeerConnection, restartPeerConnection, buildAndSetPeerInformations, getConnectionStatus, closePeerConnection, updatePeerInformationsMediaStatus, processNewSender, renegotiateIfNeeded }} */ const helpers = { createOffer, @@ -30,11 +31,12 @@ const helpers = { refreshConnection, refreshPeerConnection, restartPeerConnection, - buildPeerInformations, + buildAndSetPeerInformations, getConnectionStatus, closePeerConnection, updatePeerInformationsMediaStatus, processNewSender, + renegotiateIfNeeded, }; export default helpers; diff --git a/src/peer-connection/helpers/peer-addition/createPeerConnection.js b/src/peer-connection/helpers/peer-addition/createPeerConnection.js index 8e3d15563..a0fc216cc 100644 --- a/src/peer-connection/helpers/peer-addition/createPeerConnection.js +++ b/src/peer-connection/helpers/peer-addition/createPeerConnection.js @@ -24,10 +24,7 @@ const createNativePeerConnection = (targetMid, constraints, hasScreenShare, curr // attributes (added on by Temasys) rtcPeerConnection.setOffer = ''; rtcPeerConnection.setAnswer = ''; - rtcPeerConnection.negotiating = false; rtcPeerConnection.hasMainChannel = false; - rtcPeerConnection.processingLocalSDP = false; - rtcPeerConnection.processingRemoteSDP = false; rtcPeerConnection.gathered = false; rtcPeerConnection.gathering = false; diff --git a/src/peer-connection/helpers/refresh-connection/refreshConnection.js b/src/peer-connection/helpers/refresh-connection/refreshConnection.js index 739642454..30766658e 100644 --- a/src/peer-connection/helpers/refresh-connection/refreshConnection.js +++ b/src/peer-connection/helpers/refresh-connection/refreshConnection.js @@ -71,8 +71,8 @@ const filterParams = (targetPeerId, iceRestart, options, peerConnections) => { * Function that refreshes Peer connections to update with the current streaming. * @param {SkylinkState} roomState * @param {String} targetPeerId - * @param {boolean} iceRestart - * @param {Object} options + * @param {boolean} [iceRestart] + * @param {Object} [options] * @param {Object} options.bandwidth * @return {Promise} * @memberOf PeerConnection diff --git a/src/peer-connection/helpers/refresh-connection/restartMCUConnection.js b/src/peer-connection/helpers/refresh-connection/restartMCUConnection.js index 9f5a791b4..73c538972 100644 --- a/src/peer-connection/helpers/refresh-connection/restartMCUConnection.js +++ b/src/peer-connection/helpers/refresh-connection/restartMCUConnection.js @@ -1,6 +1,6 @@ import Skylink from '../../../index'; -import sendRestartOfferMsg from './sendRestartOfferMsg'; import { PEER_TYPE } from '../../../constants'; +import { sendRestartOffer } from '../../../server-communication/signaling-server/message-handler/handlers/commons/offerAndAnswer'; /** * @param {SkylinkState} roomState @@ -23,7 +23,7 @@ const restartMCUConnection = (roomState, doIceRestart, bwOptions) => new Promise updatedRoomState.peerEndOfCandidatesCounter.MCU.len = 0; Skylink.setSkylinkState(updatedRoomState); - resolve(sendRestartOfferMsg(updatedRoomState, PEER_TYPE.MCU, doIceRestart)); + resolve(sendRestartOffer(updatedRoomState, PEER_TYPE.MCU, doIceRestart)); } } catch (error) { resolve([PEER_TYPE.MCU, error]); diff --git a/src/peer-connection/helpers/refresh-connection/restartPeerConnection.js b/src/peer-connection/helpers/refresh-connection/restartPeerConnection.js index cd466d2ea..f4bcc26a5 100644 --- a/src/peer-connection/helpers/refresh-connection/restartPeerConnection.js +++ b/src/peer-connection/helpers/refresh-connection/restartPeerConnection.js @@ -3,7 +3,7 @@ import logger from '../../../logger'; import { PEER_CONNECTION_STATE, TAGS } from '../../../constants'; import SkylinkSignalingServer from '../../../server-communication/signaling-server'; import MESSAGES from '../../../messages'; -import sendRestartOfferMsg from './sendRestartOfferMsg'; +import { sendRestartOffer } from '../../../server-communication/signaling-server/message-handler/handlers/commons/offerAndAnswer'; /** * Function that sends restart message to the signaling server. @@ -51,7 +51,7 @@ const restartPeerConnection = (peerId, roomState, options) => { updateState.peerEndOfCandidatesCounter[peerId].len = 0; Skylink.setSkylinkState(updateState, updateState.room.id); - return resolve(sendRestartOfferMsg(updateState, peerId, doIceRestart)); + return resolve(sendRestartOffer(updateState, peerId, doIceRestart)); } // Checks if the local description is defined first diff --git a/src/peer-connection/helpers/refresh-connection/sendRestartOfferMsg.js b/src/peer-connection/helpers/refresh-connection/sendRestartOfferMsg.js deleted file mode 100644 index f6d4c679f..000000000 --- a/src/peer-connection/helpers/refresh-connection/sendRestartOfferMsg.js +++ /dev/null @@ -1,16 +0,0 @@ -import SkylinkSignalingServer from '../../../server-communication/signaling-server'; - -const sendRestartOfferMsg = (state, peerId, doIceRestart) => { - const { room } = state; - const signaling = new SkylinkSignalingServer(); - - try { - const restartOfferMsg = signaling.messageBuilder.getRestartOfferMessage(room.id, peerId, doIceRestart); - signaling.offer(room, peerId, doIceRestart, restartOfferMsg); - return peerId; - } catch (ex) { - return [peerId, ex]; - } -}; - -export default sendRestartOfferMsg; diff --git a/src/peer-connection/helpers/renegotiateIfNeeded.js b/src/peer-connection/helpers/renegotiateIfNeeded.js index 98a7c774e..2342bcd8b 100644 --- a/src/peer-connection/helpers/renegotiateIfNeeded.js +++ b/src/peer-connection/helpers/renegotiateIfNeeded.js @@ -1,12 +1,13 @@ import Skylink from '../../index'; import { isEmptyArray } from '../../utils/helpers'; import logger from '../../logger'; -import { TAGS } from '../../constants'; +import { BROWSER_AGENT, TAGS } from '../../constants'; import MESSAGES from '../../messages'; const renegotiateIfNeeded = (state, peerId) => { const { peerConnections, currentRTCRTPSenders, hasMCU } = state; const initOptions = Skylink.getInitOptions(); + const { AdapterJS } = window; // eslint-disable-next-line consistent-return return new Promise((resolve) => { @@ -37,7 +38,11 @@ const renegotiateIfNeeded = (state, peerId) => { resolvedResults.forEach((reports, senderIndex) => { reports.forEach((report) => { if (report && report.ssrc) { - transmittingSenders[report.ssrc] = pcSendersWithTracks[senderIndex]; + if (AdapterJS.webrtcDetectedBrowser === BROWSER_AGENT.FIREFOX && report.bytesSent !== 0) { + transmittingSenders[report.ssrc] = pcSendersWithTracks[senderIndex]; + } else if (AdapterJS.webrtcDetectedBrowser !== BROWSER_AGENT.FIREFOX) { + transmittingSenders[report.ssrc] = pcSendersWithTracks[senderIndex]; + } } else if (report && report.type === 'ssrc' && report.id.indexOf('send') > 1) { // required for retrieving sender information for react // native ios report.values.forEach((value) => { diff --git a/src/peer-connection/index.js b/src/peer-connection/index.js index 9e2e89eef..10f1327a2 100644 --- a/src/peer-connection/index.js +++ b/src/peer-connection/index.js @@ -121,8 +121,8 @@ class PeerConnection { return helpers.refreshPeerConnection(listOfPeers, roomState, doIceRestart, bwOptions); } - static buildPeerInformations(...args) { - return helpers.buildPeerInformations(...args); + static buildAndSetPeerInformations(...args) { + return helpers.buildAndSetPeerInformations(...args); } static closePeerConnection(roomState, peerId) { diff --git a/src/server-communication/signaling-server/index.js b/src/server-communication/signaling-server/index.js index c5db67cbc..30ec2dfcc 100644 --- a/src/server-communication/signaling-server/index.js +++ b/src/server-communication/signaling-server/index.js @@ -15,7 +15,7 @@ import { import { dispatchEvent } from '../../utils/skylinkEventManager'; import Skylink from '../../index'; import MESSAGES from '../../messages'; -import { TAGS, SOCKET_ERROR, HANDSHAKE_PROGRESS } from '../../constants'; +import { SOCKET_ERROR, HANDSHAKE_PROGRESS } from '../../constants'; import Room from '../../room'; import HandleSessionStats from '../../skylink-stats/handleSessionStats'; @@ -161,15 +161,12 @@ class SkylinkSignalingServer { /** * - * @param args + * @param state + * @param answer */ - answer(...args) { - return this.messageBuilder.getAnswerMessage(...args).then((answer) => { - const state = args[0]; - this.sendMessage(answer); - this.dispatchHandshakeProgress(state, 'ANSWER'); - return answer; - }); + answer(state, answer) { + this.sendMessage(answer); + this.dispatchHandshakeProgress(state, 'ANSWER'); } answerAck(...args) { @@ -196,19 +193,9 @@ class SkylinkSignalingServer { this.logClientSessionStats(args[0].room.id, join); } - offer(...args) { - const room = args[0]; - const peerId = args[1]; - const state = Skylink.getSkylinkState(room.id); - if (state.peerConnections[peerId].negotiating) { - logger.log.DEBUG([peerId, TAGS.SIG_SERVER, null, `${MESSAGES.SIGNALING.ABORTING_OFFER}`]); - return; - } - - this.messageBuilder.getOfferMessage(...args).then((offer) => { - this.sendMessage(offer); - this.dispatchHandshakeProgress(state, 'OFFER'); - }); + offer(state, offer) { + this.sendMessage(offer); + this.dispatchHandshakeProgress(state, 'OFFER'); } welcome(...args) { diff --git a/src/server-communication/signaling-server/message-builder/builders/commons/offerAndAnswer.js b/src/server-communication/signaling-server/message-builder/builders/commons/offerAndAnswer.js index fa6514c48..6f2c12731 100644 --- a/src/server-communication/signaling-server/message-builder/builders/commons/offerAndAnswer.js +++ b/src/server-communication/signaling-server/message-builder/builders/commons/offerAndAnswer.js @@ -8,16 +8,13 @@ const getCommonMessage = (resolve, targetMid, roomState, sessionDescription, res // TODO: Full implementation to be done from _setLocalAndSendMessage under peer-handshake.js const state = Skylink.getSkylinkState(roomState.room.id); const { - peerConnections, bufferedLocalOffer, peerPriorityWeight, room, + bufferedLocalOffer, peerPriorityWeight, room, } = state; - const peerConnection = peerConnections[targetMid]; const sd = { type: sessionDescription.type, sdp: sessionDescription.sdp, }; - peerConnection.processingLocalSDP = true; - logger.log.INFO([targetMid, 'RTCSessionDescription', sessionDescription.type, 'Local session description updated ->'], sd.sdp); if (sessionDescription.type === HANDSHAKE_PROGRESS.OFFER) { diff --git a/src/server-communication/signaling-server/message-handler/handlers/answerAckHandler.js b/src/server-communication/signaling-server/message-handler/handlers/answerAckHandler.js index 759490573..f6510554f 100644 --- a/src/server-communication/signaling-server/message-handler/handlers/answerAckHandler.js +++ b/src/server-communication/signaling-server/message-handler/handlers/answerAckHandler.js @@ -1,25 +1,8 @@ import Skylink from '../../../../index'; -import renegotiateIfNeeded from '../../../../peer-connection/helpers/renegotiateIfNeeded'; -import refreshConnection from '../../../../peer-connection/helpers/refresh-connection/refreshConnection'; -import logger from '../../../../logger'; -import { TAGS, HANDSHAKE_PROGRESS } from '../../../../constants'; -import MESSAGES from '../../../../messages'; import { dispatchEvent } from '../../../../utils/skylinkEventManager'; import { handshakeProgress } from '../../../../skylink-events'; -import { isEmptyArray } from '../../../../utils/helpers'; -import { offerAndAnswerHandler } from './commons/offerAndAnswer'; - -const hasAppliedBufferedRemoteOffer = (updatedState, targetMid) => { - if (updatedState.bufferedRemoteOffers[targetMid] && !isEmptyArray(updatedState.bufferedRemoteOffers[targetMid])) { - const offerMessage = updatedState.bufferedRemoteOffers[targetMid].shift(); // the first buffered message - logger.log.DEBUG([targetMid, 'RTCSessionDescription', offerMessage.type, MESSAGES.NEGOTIATION_PROGRESS.APPLYING_BUFFERED_REMOTE_OFFER], offerMessage); - offerAndAnswerHandler(offerMessage); - Skylink.setSkylinkState(updatedState, updatedState.room.id); - return true; - } - - return false; -}; +import NegotiationState from '../../negotiationState/negotiationState'; +import logger from '../../../../logger'; /** * Method that handles the "answerAck" socket message received. @@ -30,34 +13,19 @@ const hasAppliedBufferedRemoteOffer = (updatedState, targetMid) => { * @since 1.0.0 */ const answerAckHandler = (message) => { - const { mid, rid, success } = message; - const updatedState = Skylink.getSkylinkState(rid); + const { mid, rid, type } = message; + const state = Skylink.getSkylinkState(rid); const targetMid = mid; + logger.log.INFO([message.mid, null, message.type, 'Received ANSWER_ACK from peer:'], message); + dispatchEvent(handshakeProgress({ - state: HANDSHAKE_PROGRESS.ANSWER_ACK, + state: type, peerId: targetMid, - room: updatedState.room, + room: state.room, })); - updatedState.peerConnections[targetMid].negotiating = false; - Skylink.setSkylinkState(updatedState, rid); - - if (!success) { - logger.log.ERROR([targetMid, TAGS.SESSION_DESCRIPTION, HANDSHAKE_PROGRESS.ANSWER, MESSAGES.NEGOTIATION_PROGRESS.ERRORS.FAILED_SET_REMOTE_ANSWER]); - return; - } - - if (!hasAppliedBufferedRemoteOffer(updatedState, targetMid)) { - renegotiateIfNeeded(updatedState, targetMid).then((shouldRenegotiate) => { - if (shouldRenegotiate) { - refreshConnection(updatedState, targetMid) - .catch((error) => { - logger.log.ERROR([mid, TAGS.SESSION_DESCRIPTION, HANDSHAKE_PROGRESS.ANSWER_ACK, MESSAGES.NEGOTIATION_PROGRESS.ERRORS.FAILED_RENEGOTIATION], error); - }); - } - }); - } + NegotiationState.onAnswerAckReceived(message); }; export default answerAckHandler; diff --git a/src/server-communication/signaling-server/message-handler/handlers/answerHandler.js b/src/server-communication/signaling-server/message-handler/handlers/answerHandler.js index bc200e904..6d02a5adb 100644 --- a/src/server-communication/signaling-server/message-handler/handlers/answerHandler.js +++ b/src/server-communication/signaling-server/message-handler/handlers/answerHandler.js @@ -1,7 +1,9 @@ -import { offerAndAnswerHandler } from './commons/offerAndAnswer'; +import NegotiationState from '../../negotiationState/negotiationState'; +import logger from '../../../../logger'; const answerHandler = (message) => { - offerAndAnswerHandler(message); + logger.log.INFO([message.mid, null, message.type, 'Received ANSWER from peer:'], message); + NegotiationState.onAnswerReceived(message); }; export default answerHandler; diff --git a/src/server-communication/signaling-server/message-handler/handlers/byeHandler.js b/src/server-communication/signaling-server/message-handler/handlers/byeHandler.js index 9d6b77e78..4ccca5658 100644 --- a/src/server-communication/signaling-server/message-handler/handlers/byeHandler.js +++ b/src/server-communication/signaling-server/message-handler/handlers/byeHandler.js @@ -78,6 +78,7 @@ export const clearPeerInfo = (roomKey, peerId) => { delete updatedState.peerStreams[peerId]; delete updatedState.currentRTCRTPSenders[peerId]; delete updatedState.bufferedLocalOffer[peerId]; + delete updatedState.negotiationState[peerId]; }; /** diff --git a/src/server-communication/signaling-server/message-handler/handlers/commons/enterAndWelcome.js b/src/server-communication/signaling-server/message-handler/handlers/commons/enterAndWelcome.js index b44169e40..b2a454f2d 100644 --- a/src/server-communication/signaling-server/message-handler/handlers/commons/enterAndWelcome.js +++ b/src/server-communication/signaling-server/message-handler/handlers/commons/enterAndWelcome.js @@ -1,110 +1,40 @@ import Skylink from '../../../../../index'; -import { PEER_CONNECTION_STATE, TAGS } from '../../../../../constants'; -import processPeer from './processPeer'; -import SkylinkSignalingServer from '../../../index'; +import { TAGS } from '../../../../../constants'; import handleNegotiationStats from '../../../../../skylink-stats/handleNegotiationStats'; import logger from '../../../../../logger'; import messages from '../../../../../messages'; import parsers from '../../../parsers'; - -export const CALLERS = { - ENTER: 'enterHandler', - WELCOME: 'welcomeHander', -}; - -const getNextNegotiationStep = (params) => { - let method = 'welcome'; - - if (params.caller === CALLERS.WELCOME) { - const state = Skylink.getSkylinkState(params.currentRoom.id); - const { peerMessagesStamps, peerPriorityWeight, hasMCU } = state; - if (hasMCU || peerPriorityWeight > params.message.weight) { - if (peerMessagesStamps[params.targetMid].hasWelcome) { - method = 'noop'; - logger.log.WARN([params.targetMid, TAGS.PEER_CONNECTION, null, 'Discarding extra "welcome" received.']); - } else { - method = 'offer'; - state.peerMessagesStamps[params.targetMid].hasWelcome = true; - Skylink.setSkylinkState(state, params.currentRoom.id); - } - } - } - return method; -}; - -// eslint-disable-next-line consistent-return -const checkStampBeforeSendingWelcome = (params) => { - const { currentRoom, targetMid, message } = params; - const state = Skylink.getSkylinkState(currentRoom.id); - const { peerConnections, hasMCU } = state; - const { STATS_MODULE, NEGOTIATION_PROGRESS, PEER_CONNECTION } = messages; - const signaling = new SkylinkSignalingServer(); - const method = getNextNegotiationStep(params); - - if (method === 'offer') { - // Added checks to ensure that connection object is defined first - if (!peerConnections[targetMid]) { - logger.log.WARN([targetMid, 'RTCSessionDescription', 'offer', PEER_CONNECTION.NO_PEER_CONNECTION]); - handleNegotiationStats.send(currentRoom.id, STATS_MODULE.HANDLE_NEGOTIATION_STATS.OFFER.dropped, targetMid, message, false, PEER_CONNECTION.NO_PEER_CONNECTION); - return null; - } - - const { signalingState } = peerConnections[targetMid]; - - // Added checks to ensure that state is "stable" if setting local "offer" - if (signalingState !== PEER_CONNECTION_STATE.STABLE) { - logger.log.WARN([targetMid, 'RTCSessionDescription', 'offer', NEGOTIATION_PROGRESS.ERRORS.NOT_STABLE], signalingState); - handleNegotiationStats.send(currentRoom.id, STATS_MODULE.HANDLE_NEGOTIATION_STATS.OFFER.dropped, targetMid, message, false, NEGOTIATION_PROGRESS.ERRORS.NOT_STABLE); - return null; - } - - signaling[method](params.currentRoom, params.targetMid); - } else if (!hasMCU) { - signaling[method](params.currentRoom, params.targetMid); - } -}; - -const logStats = (caller, targetMid, state, message) => { - const { room } = state; - - let callerState = 'enter'; - if (caller === CALLERS.WELCOME) { - callerState = 'welcome'; - } - - logger.log.INFO([targetMid, TAGS.PEER_CONNECTION, null, `Peer ${callerState} received ->`], message); - handleNegotiationStats.send(room.id, callerState, targetMid, message, true); -}; +import NegotiationState from '../../../negotiationState/negotiationState'; /** * Function that parses the enter and welcome message and sends the welcome or offer message. * @param {JSON} message - * @param {String} caller * @memberOf SignalingMessageHandler */ -export const enterAndWelcomeHandler = (message, caller) => { +// eslint-disable-next-line consistent-return +const enterAndWelcomeHandler = (message) => { const parsedMsg = parsers.enterAndWelcome(message); const { - rid, mid, userInfo, publisherId, + rid, mid, publisherId, } = parsedMsg; const state = Skylink.getSkylinkState(rid); const { hasMCU, user } = state; const targetMid = hasMCU && publisherId ? publisherId : mid; if (!user.sid) { - logger.log.DEBUG([targetMid, TAGS.PEER_CONNECTION, null, [messages.SIGNALING.DROPPING_ENTER]]); + return logger.log.DEBUG([targetMid, TAGS.PEER_CONNECTION, null, [messages.SIGNALING.DROPPING_ENTER]]); } - logStats(caller, targetMid, state, parsedMsg); + logger.log.INFO([targetMid, TAGS.PEER_CONNECTION, null, `Peer ${parsedMsg.type} received ->`], message); + handleNegotiationStats.send(rid, parsedMsg.type, targetMid, message, true); - const peerParams = { - currentRoom: state.room, - targetMid, - userInfo, - message: parsedMsg, - caller, - }; + if (parsedMsg.type === 'enter') { + return NegotiationState.onEnterReceived(message); + } - processPeer(peerParams); - checkStampBeforeSendingWelcome(peerParams); + if (parsedMsg.type === 'welcome') { + return NegotiationState.onWelcomeReceived(message); + } }; + +export default enterAndWelcomeHandler; diff --git a/src/server-communication/signaling-server/message-handler/handlers/commons/handleSetDescriptionFailure.js b/src/server-communication/signaling-server/message-handler/handlers/commons/handleSetDescriptionFailure.js index ee222bacc..93eb7be56 100644 --- a/src/server-communication/signaling-server/message-handler/handlers/commons/handleSetDescriptionFailure.js +++ b/src/server-communication/signaling-server/message-handler/handlers/commons/handleSetDescriptionFailure.js @@ -24,15 +24,10 @@ const _handleSetOfferAndAnswerFailure = (state, targetMid, description, isRemote const onLocalDescriptionSetFailure = (room, targetMid, localDescription, error) => { const state = Skylink.getSkylinkState(room.id); - const { peerConnections } = state; - const peerConnection = peerConnections[targetMid]; const { NEGOTIATION_PROGRESS } = MESSAGES; logger.log.ERROR([targetMid, TAGS.SESSION_DESCRIPTION, localDescription.type, NEGOTIATION_PROGRESS.FAILED_SET_LOCAL_DESCRIPTION], error); - peerConnection.processingLocalSDP = false; - peerConnection.negotiating = false; - _handleSetOfferAndAnswerFailure(state, targetMid, localDescription, false, error); }; @@ -48,9 +43,6 @@ const onRemoteDescriptionSetFailure = (room, targetMid, remoteDescription, error [type]: remoteDescription, }); - peerConnection.processingRemoteSDP = false; - peerConnection.negotiating = false; - _handleSetOfferAndAnswerFailure(state, targetMid, remoteDescription, true, error); }; diff --git a/src/server-communication/signaling-server/message-handler/handlers/commons/handleSetDescriptionSuccess.js b/src/server-communication/signaling-server/message-handler/handlers/commons/handleSetDescriptionSuccess.js index e3f23a793..c69d05ec7 100644 --- a/src/server-communication/signaling-server/message-handler/handlers/commons/handleSetDescriptionSuccess.js +++ b/src/server-communication/signaling-server/message-handler/handlers/commons/handleSetDescriptionSuccess.js @@ -8,20 +8,19 @@ import Room from '../../../../../room'; import IceConnection from '../../../../../ice-connection'; // eslint-disable-next-line no-underscore-dangle -const _setPeerConnectionInstate = (RTCPeerConnection, room, targetMid) => { +const _setPeerConnectionInState = (RTCPeerConnection, room, targetMid) => { const updatedState = Skylink.getSkylinkState(room.id); updatedState.peerConnections[targetMid] = RTCPeerConnection; Skylink.setSkylinkState(updatedState, room.id); }; -const setPeerConnectionInState = (RTCPeerConnection, room, targetMid) => _setPeerConnectionInstate(RTCPeerConnection, room, targetMid); +const setPeerConnectionInState = (RTCPeerConnection, room, targetMid) => _setPeerConnectionInState(RTCPeerConnection, room, targetMid); const onRemoteDescriptionSetSuccess = (RTCPeerConnection, room, targetMid, remoteDescription) => { const { type } = remoteDescription; const { NEGOTIATION_PROGRESS } = MESSAGES; const updatedState = Skylink.getSkylinkState(room.id); - updatedState.peerConnections[targetMid].processingRemoteSDP = false; if (remoteDescription.type === 'offer') { updatedState.peerConnections[targetMid].setOffer = 'remote'; @@ -43,7 +42,7 @@ const onRemoteDescriptionSetSuccess = (RTCPeerConnection, room, targetMid, remot }; const onLocalDescriptionSetSuccess = (RTCPeerConnection, room, targetMid, localDescription) => { - _setPeerConnectionInstate(RTCPeerConnection, room, targetMid); + _setPeerConnectionInState(RTCPeerConnection, room, targetMid); const updatedState = Skylink.getSkylinkState(room.id); const { NEGOTIATION_PROGRESS } = MESSAGES; diff --git a/src/server-communication/signaling-server/message-handler/handlers/commons/offerAndAnswer.js b/src/server-communication/signaling-server/message-handler/handlers/commons/offerAndAnswer.js index d8a8824fb..5bd540009 100644 --- a/src/server-communication/signaling-server/message-handler/handlers/commons/offerAndAnswer.js +++ b/src/server-communication/signaling-server/message-handler/handlers/commons/offerAndAnswer.js @@ -1,53 +1,73 @@ import Skylink from '../../../../../index'; import logger from '../../../../../logger'; -import { - TAGS, PEER_CONNECTION_STATE, DATA_CHANNEL_STATE, -} from '../../../../../constants'; +import { NEGOTIATION_STATES, TAGS } from '../../../../../constants'; import SkylinkSignalingServer from '../../../index'; import PeerConnection from '../../../../../peer-connection/index'; -import handleNegotiationStats from '../../../../../skylink-stats/handleNegotiationStats'; import MESSAGES from '../../../../../messages'; -import PeerMedia from '../../../../../peer-media/index'; import { onLocalDescriptionSetFailure, onRemoteDescriptionSetFailure } from './handleSetDescriptionFailure'; import { setPeerConnectionInState, onRemoteDescriptionSetSuccess, onLocalDescriptionSetSuccess } from './handleSetDescriptionSuccess'; import { setRemoteDescription, setLocalDescription } from './setSessionDescription'; +import NegotiationState from '../../../negotiationState/negotiationState'; -const setLocalOffer = (room, targetMid, localDescription) => setLocalDescription(room, targetMid, localDescription); +export const createAnswer = (state, targetMid) => PeerConnection.createAnswer(state, targetMid); -const setLocalAnswer = (room, targetMid, localDescription) => setLocalDescription(room, targetMid, localDescription); +export const sendAnswer = (room, answer) => { + const state = Skylink.getSkylinkState(room.id); + new SkylinkSignalingServer().answer(state, answer); +}; -const onLocalOfferSetSuccess = (RTCPeerConnection, room, targetMid, localDescription) => onLocalDescriptionSetSuccess(RTCPeerConnection, room, targetMid, localDescription); +export const createOffer = (room, targetMid, doIceRestart, restartOffer) => PeerConnection.createOffer(room, targetMid, doIceRestart, restartOffer); -const onLocalAnswerSetSuccess = (RTCPeerConnection, room, targetMid, localDescription) => onLocalDescriptionSetSuccess(RTCPeerConnection, room, targetMid, localDescription); +export const sendOffer = (room, offer) => { + const state = Skylink.getSkylinkState(room.id); + new SkylinkSignalingServer().offer(state, offer); +}; -const onLocalOfferSetFailure = (room, targetMid, localDescription, error) => onLocalDescriptionSetFailure(room, targetMid, localDescription, error); +export const sendRestartOffer = (state, peerId, doIceRestart) => { + const { room } = state; + const signaling = new SkylinkSignalingServer(); -const onLocalAnswerSetFailure = (room, targetMid, localDescription, error) => onLocalDescriptionSetFailure(room, targetMid, localDescription, error); + try { + const restartOfferMsg = signaling.messageBuilder.getRestartOfferMessage(room.id, peerId, doIceRestart); + + return createOffer(room, peerId, doIceRestart, restartOfferMsg) + .then((offer) => { + sendOffer(room, offer); + NegotiationState.changeState(room.id, peerId, NEGOTIATION_STATES.LOCAL_OFFER_SENT); + return peerId; + }); + } catch (ex) { + return [peerId, ex]; + } +}; -const setRemoteOffer = (room, targetMid, remoteDescription) => setRemoteDescription(room, targetMid, remoteDescription); +export const setLocalOffer = (room, targetMid, localDescription) => setLocalDescription(room, targetMid, localDescription); -const setRemoteAnswer = (room, targetMid, remoteDescription) => setRemoteDescription(room, targetMid, remoteDescription); +export const setLocalAnswer = (room, targetMid, localDescription) => setLocalDescription(room, targetMid, localDescription); -const sendAnswerAck = (state, targetMid, success) => { - const updatedState = state; - updatedState.peerConnections[targetMid].negotiating = false; - Skylink.setSkylinkState(updatedState, targetMid); +export const onLocalOfferSetSuccess = (RTCPeerConnection, room, targetMid, localDescription) => onLocalDescriptionSetSuccess(RTCPeerConnection, room, targetMid, localDescription); - const signaling = new SkylinkSignalingServer(); - signaling.answerAck(state, targetMid, success); +export const onLocalAnswerSetSuccess = (RTCPeerConnection, room, targetMid, localDescription) => onLocalDescriptionSetSuccess(RTCPeerConnection, room, targetMid, localDescription); + +export const onLocalOfferSetFailure = (room, targetMid, localDescription, error) => onLocalDescriptionSetFailure(room, targetMid, localDescription, error); + +export const onLocalAnswerSetFailure = (room, targetMid, localDescription, error) => onLocalDescriptionSetFailure(room, targetMid, localDescription, error); + +export const setRemoteOffer = (room, targetMid, remoteDescription) => setRemoteDescription(room, targetMid, remoteDescription); + +export const setRemoteAnswer = (room, targetMid, remoteDescription) => setRemoteDescription(room, targetMid, remoteDescription); + +export const sendAnswerAck = (room, targetMid, success) => { + const state = Skylink.getSkylinkState(room.id); + new SkylinkSignalingServer().answerAck(state, targetMid, success); }; -const onRemoteOfferSetSuccess = (RTCPeerConnection, room, targetMid, remoteDescription) => { +export const onRemoteOfferSetSuccess = (RTCPeerConnection, room, targetMid, remoteDescription) => { setPeerConnectionInState(RTCPeerConnection, room, targetMid); onRemoteDescriptionSetSuccess(RTCPeerConnection, room, targetMid, remoteDescription); - - // create and return the answer - const state = Skylink.getSkylinkState(room.id); - const signaling = new SkylinkSignalingServer(); - return signaling.answer(state, targetMid); }; -const onRemoteAnswerSetSuccess = (RTCPeerConnection, room, targetMid, remoteDescription) => { +export const onRemoteAnswerSetSuccess = (RTCPeerConnection, room, targetMid, remoteDescription) => { setPeerConnectionInState(RTCPeerConnection, room, targetMid); onRemoteDescriptionSetSuccess(RTCPeerConnection, room, targetMid, remoteDescription); @@ -60,209 +80,12 @@ const onRemoteAnswerSetSuccess = (RTCPeerConnection, room, targetMid, remoteDesc logger.log.WARN([targetMid, TAGS.PEER_CONNECTION, null, `${DATA_CHANNEL.CLOSING} - ${DATA_CHANNEL.NO_REMOTE_DATA_CHANNEL}`]); PeerConnection.closeDataChannel(room.id, targetMid); } - - return sendAnswerAck(state, targetMid, true); }; -const onRemoteOfferSetFailure = (room, targetMid, remoteDescription, error) => onRemoteDescriptionSetFailure(room, targetMid, remoteDescription, error); +export const onRemoteOfferSetFailure = (room, targetMid, remoteDescription, error) => onRemoteDescriptionSetFailure(room, targetMid, remoteDescription, error); -const onRemoteAnswerSetFailure = (room, targetMid, remoteDescription, error) => { +export const onRemoteAnswerSetFailure = (room, targetMid, remoteDescription, error) => { onRemoteDescriptionSetFailure(room, targetMid, remoteDescription, error); - const state = Skylink.getSkylinkState(room.id); - sendAnswerAck(state, targetMid, false); -}; - -const updateStateInformation = (state, message) => { - const updatedState = state; - const { - userInfo, rid, mid, mediaInfoList, - } = message; - const { room } = updatedState; - const updatedUserInfo = userInfo; - const targetMid = mid; - - if (userInfo && typeof userInfo === 'object') { - updatedUserInfo.settings.data = !!(updatedState.peerDataChannels[targetMid] && updatedState.peerDataChannels[targetMid].main && updatedState.peerDataChannels[targetMid].main.channel && updatedState.peerDataChannels[targetMid].main.channel.readyState === DATA_CHANNEL_STATE.OPEN); - updatedState.peerInformations[targetMid].settings = updatedUserInfo.settings || {}; - updatedState.peerInformations[targetMid].mediaStatus = updatedUserInfo.mediaStatus || {}; - updatedState.peerInformations[targetMid].userData = updatedUserInfo.userData; - } - - updatedState.peerConnections[targetMid].negotiating = true; - Skylink.setSkylinkState(updatedState, rid); - - PeerMedia.setPeerMediaInfo(room, targetMid, mediaInfoList); - PeerMedia.deleteUnavailableMedia(room, targetMid); // mediaState can be unavailable during renegotiation -}; - -const canProceed = (message) => { - const { - weight, type, mid, sdp, resend, rid, - } = message; - const state = Skylink.getSkylinkState(rid); - const { - peerPriorityWeight, bufferedLocalOffer, room, peerConnections, - } = state; - const { STATS_MODULE, NEGOTIATION_PROGRESS, PEER_CONNECTION } = MESSAGES; - const targetMid = mid; - const peerConnection = peerConnections[targetMid]; - - if (!peerConnection) { - logger.log.ERROR([targetMid, null, type, `${PEER_CONNECTION.NO_PEER_CONNECTION}. Unable to set${type === 'offer' ? 'Remote' : 'Local'}Offer.`]); - handleNegotiationStats.send(room.id, STATS_MODULE.HANDLE_NEGOTIATION_STATS[type.toUpperCase()].dropped, targetMid, message, true, PEER_CONNECTION.NO_PEER_CONNECTION); - return false; - } - - const { - processingRemoteSDP, processingLocalSDP, negotiating, - } = peerConnection; - - switch (type) { - case 'offer': - if (peerConnections[targetMid].signalingState !== PEER_CONNECTION_STATE.STABLE) { - logger.log.WARN([targetMid, null, type, NEGOTIATION_PROGRESS.ERRORS.NOT_STABLE], { - signalingState: peerConnections[targetMid].signalingState, - isRestart: !!resend, - }); - handleNegotiationStats.send(room.id, STATS_MODULE.HANDLE_NEGOTIATION_STATS[type.toUpperCase()].dropped, targetMid, message, true, `Peer connection state is ${peerConnections[targetMid].signalingState}.`); - return false; - } - - if (bufferedLocalOffer[targetMid] && peerPriorityWeight > weight) { - logger.log.WARN([targetMid, null, type, NEGOTIATION_PROGRESS.ERRORS.OFFER_TIEBREAKER], { - selfWeight: peerPriorityWeight, - messageWeight: weight, - }); - handleNegotiationStats.send(room.id, STATS_MODULE.HANDLE_NEGOTIATION_STATS[type.toUpperCase()].dropped, targetMid, message, true, NEGOTIATION_PROGRESS.ERRORS.OFFER_TIEBREAKER); - return false; - } - - // if processing remote SDP - if (processingRemoteSDP) { - logger.log.WARN([targetMid, TAGS.SESSION_DESCRIPTION, type, NEGOTIATION_PROGRESS.ERRORS.PROCESSING_EXISTING_SDP], sdp); - handleNegotiationStats.send(room.id, STATS_MODULE.HANDLE_NEGOTIATION_STATS[type.toUpperCase()].dropped, targetMid, message, true, NEGOTIATION_PROGRESS.ERRORS.PROCESSING_EXISTING_SDP); - return false; - } - - // or completed processing local and remote sdp but answerAck has not been received - if (!processingLocalSDP && !processingRemoteSDP && negotiating) { - // add to bufferedRemoteOffer - const updatedState = state; - logger.log.DEBUG([targetMid, TAGS.SESSION_DESCRIPTION, type, NEGOTIATION_PROGRESS.ERRORS.ADDING_REMOTE_OFFER_TO_BUFFER], message); - updatedState.bufferedRemoteOffers[targetMid] = updatedState.bufferedRemoteOffers[targetMid] ? updatedState.bufferedRemoteOffers[targetMid] : []; - updatedState.bufferedRemoteOffers[targetMid].push(message); - Skylink.setSkylinkState(updatedState, room.id); - return false; - } - break; - - case 'answer': - // if processing remote SDP - if (processingRemoteSDP) { - logger.log.WARN([targetMid, TAGS.SESSION_DESCRIPTION, type, NEGOTIATION_PROGRESS.ERRORS.PROCESSING_EXISTING_SDP], sdp); - handleNegotiationStats.send(room.id, STATS_MODULE.HANDLE_NEGOTIATION_STATS[type.toUpperCase()].dropped, targetMid, message, true, NEGOTIATION_PROGRESS.ERRORS.PROCESSING_EXISTING_SDP); - return false; - } - break; - - default: - // should not come here - return false; - } - - return true; -}; - -const onRemoteAnswer = (message) => { - const { - rid, mid, type, sdp, - } = message; - const state = Skylink.getSkylinkState(rid); - const targetMid = mid; - const { hasMCU, bufferedLocalOffer, room } = state; - - logger.log.INFO([mid, null, type, 'Received answer from peer. ANSWER:'], message); - - try { - updateStateInformation(state, message); - - if (bufferedLocalOffer[targetMid]) { - const localDescription = bufferedLocalOffer[targetMid]; - const remoteDescription = { - type, - sdp: hasMCU ? sdp.replace(/\r\n/g, '\n').split('\n').join('\r\n') : sdp, - }; - - setLocalOffer(room, targetMid, localDescription) - .then(peerConnection => onLocalOfferSetSuccess(peerConnection, room, targetMid, localDescription)) - .catch(error => onLocalOfferSetFailure(room, targetMid, localDescription, error)) - .then(() => setRemoteAnswer(room, targetMid, remoteDescription)) - .then(peerConnection => onRemoteAnswerSetSuccess(peerConnection, room, targetMid, remoteDescription)) - .catch(error => onRemoteAnswerSetFailure(room, targetMid, remoteDescription, error)); - } else { - logger.log.ERROR([targetMid, TAGS.PEER_CONNECTION, null, MESSAGES.NEGOTIATION_PROGRESS.ERRORS.NO_LOCAL_BUFFERED_OFFER]); - } - } catch (err) { - logger.log.ERROR([mid, TAGS.SESSION_DESCRIPTION, type, 'Failed processing ANSWER ->'], err); - } -}; - -const onRemoteOffer = (message) => { - const { - rid, mid, type, sdp, - } = message; - const state = Skylink.getSkylinkState(rid); - const targetMid = mid; - const { room, hasMCU } = state; - const remoteDescription = { - type, - sdp: hasMCU ? sdp.replace(/\r\n/g, '\n').split('\n').join('\r\n') : sdp, - }; - let localDescription = null; - - logger.log.INFO([mid, null, type, 'Received offer from peer. OFFER:'], message); - - try { - updateStateInformation(state, message); - - setRemoteOffer(room, targetMid, remoteDescription) - .then(peerConnection => onRemoteOfferSetSuccess(peerConnection, room, targetMid, remoteDescription)) - .catch(error => onRemoteOfferSetFailure(room, targetMid, remoteDescription, error)) - .then((answer) => { - localDescription = { - type: answer.type, - sdp: answer.sdp, - }; - return setLocalAnswer(room, targetMid, localDescription); - }) - .then(peerConnection => onLocalAnswerSetSuccess(peerConnection, room, targetMid, localDescription)) - .catch(error => onLocalAnswerSetFailure(room, targetMid, localDescription, error)); - } catch (err) { - logger.log.ERROR([mid, TAGS.SESSION_DESCRIPTION, type, 'Failed processing OFFER ->'], err); - } -}; - -/** - * Function that handles the remote offer and answer - * @param {JSON} message - * @memberOf SignalingMessageHandler - * @fires HANDSHAKE_PROGRESS - */ -// eslint-disable-next-line import/prefer-default-export -export const offerAndAnswerHandler = (message) => { - if (canProceed(message)) { - switch (message.type) { - case 'offer': - onRemoteOffer(message); - break; - - case 'answer': - onRemoteAnswer(message); - break; - - default: - // should not come here - } - } + sendAnswerAck(room, targetMid, false); }; diff --git a/src/server-communication/signaling-server/message-handler/handlers/commons/processPeer.js b/src/server-communication/signaling-server/message-handler/handlers/commons/processPeer.js deleted file mode 100644 index b503aefd5..000000000 --- a/src/server-communication/signaling-server/message-handler/handlers/commons/processPeer.js +++ /dev/null @@ -1,131 +0,0 @@ -import Skylink from '../../../../../index'; -import logger from '../../../../../logger'; -import PeerConnection from '../../../../../peer-connection'; -import { CALLERS } from './enterAndWelcome'; -import { peerJoined, handshakeProgress, serverPeerJoined } from '../../../../../skylink-events'; -import { dispatchEvent } from '../../../../../utils/skylinkEventManager'; -import PeerData from '../../../../../peer-data'; -import parsers from '../../../parsers/index'; -import { - PEER_TYPE, SERVER_PEER_TYPE, HANDSHAKE_PROGRESS, TAGS, -} from '../../../../../constants'; -import MESSAGES from '../../../../../messages'; -import Room from '../../../../../room'; - -const setPeerInformations = (state, peerId, userInfo) => { - const { room } = state; - // eslint-disable-next-line no-param-reassign - state.peerInformations[peerId] = PeerConnection.buildPeerInformations(userInfo, state); - Skylink.setSkylinkState(state, room.id); -}; - -/** - * Function that adds a Peer Connection and updates the state(Skylink State). - * @param {JSON} params - * @memberOf SignalingMessageHandler - * @fires SERVER_PEER_JOINED - * @fires PEER_JOINED - * @fires HANDSHAKE_PROGRESS - */ -const processPeer = (params) => { - const { - currentRoom, - targetMid, - cert, - userInfo, - message, - caller, - } = params; - let isNewPeer = false; - const state = Skylink.getSkylinkState(currentRoom.id); - const { hasMCU } = state; - const { peerInformations } = state; - - if ((!peerInformations[targetMid] && !hasMCU) || (hasMCU && targetMid === PEER_TYPE.MCU && !peerInformations.MCU)) { - const hasScreenshare = !!userInfo.screenshare; - isNewPeer = true; - state.peerInformations[targetMid] = PeerConnection.buildPeerInformations(message.userInfo, state); - - const peerBrowser = { - agent: userInfo.agent.name, - version: userInfo.agent.version, - os: userInfo.agent.os, - }; - - Skylink.setSkylinkState(state, currentRoom.id); - - PeerConnection.addPeer({ - currentRoom, - targetMid, - peerBrowser, - cert, - hasScreenshare, - }); - - if (targetMid === PEER_TYPE.MCU) { - logger.log.INFO([targetMid, TAGS.PEER_CONNECTION, null, MESSAGES.PEER_CONNECTION.MCU]); - state.hasMCU = true; - dispatchEvent(serverPeerJoined({ - peerId: targetMid, - serverPeerType: SERVER_PEER_TYPE.MCU, - room: Room.getRoomInfo(currentRoom.id), - })); - } else { - dispatchEvent(peerJoined({ - peerId: targetMid, - peerInfo: PeerData.getPeerInfo(targetMid, currentRoom), - isSelf: false, - room: Room.getRoomInfo(currentRoom.id), - })); - } - } - - state.peerMessagesStamps[targetMid] = state.peerMessagesStamps[targetMid] || { - userData: 0, - audioMuted: 0, - videoMuted: 0, - }; - - if (caller === CALLERS.WELCOME) { - state.peerMessagesStamps[targetMid].hasWelcome = false; - } - - if (caller === CALLERS.WELCOME && hasMCU && Array.isArray(message.peersInRoom) && message.peersInRoom.length) { - const userId = state.user.sid; - for (let peersInRoomIndex = 0; peersInRoomIndex < message.peersInRoom.length; peersInRoomIndex += 1) { - const PEER_ID = message.peersInRoom[peersInRoomIndex].mid; - if (PEER_ID !== userId) { - const parsedMsg = parsers.enterAndWelcome(message.peersInRoom[peersInRoomIndex]); - const peerUserInfo = parsedMsg.userInfo; - setPeerInformations(state, PEER_ID, peerUserInfo); - dispatchEvent(peerJoined({ - peerId: PEER_ID, - peerInfo: PeerData.getPeerInfo(PEER_ID, currentRoom), - isSelf: false, - room: Room.getRoomInfo(currentRoom.id), - })); - } - } - } else if (hasMCU && targetMid !== state.user.sid && targetMid !== PEER_TYPE.MCU) { - setPeerInformations(state, targetMid, userInfo); - dispatchEvent(peerJoined({ - peerId: targetMid, - peerInfo: PeerData.getPeerInfo(targetMid, currentRoom), - isSelf: false, - room: Room.getRoomInfo(currentRoom.id), - })); - } - - Skylink.setSkylinkState(state, currentRoom.id); - - if (isNewPeer) { - dispatchEvent(handshakeProgress({ - peerId: targetMid, - state: HANDSHAKE_PROGRESS.WELCOME, - error: null, - room: Room.getRoomInfo(currentRoom.id), - })); - } -}; - -export default processPeer; diff --git a/src/server-communication/signaling-server/message-handler/handlers/commons/setSessionDescription.js b/src/server-communication/signaling-server/message-handler/handlers/commons/setSessionDescription.js index 730b61d5f..c2323fc99 100644 --- a/src/server-communication/signaling-server/message-handler/handlers/commons/setSessionDescription.js +++ b/src/server-communication/signaling-server/message-handler/handlers/commons/setSessionDescription.js @@ -21,15 +21,20 @@ const setRemoteDescription = (room, targetMid, remoteDescription) => { const state = Skylink.getSkylinkState(room.id); const { peerConnections } = state; const { type } = remoteDescription; - const { STATS_MODULE } = MESSAGES; const peerConnection = peerConnections[targetMid]; + if (peerConnection) { + const mungedSessionDescription = _mungeSDP(targetMid, remoteDescription, room.id); - peerConnection.processingRemoteSDP = true; - const mungedSessionDescription = _mungeSDP(targetMid, remoteDescription, room.id); - handleNegotiationStats.send(room.id, STATS_MODULE.HANDLE_NEGOTIATION_STATS[type.toUpperCase()][type], targetMid, mungedSessionDescription, true); - return peerConnection.setRemoteDescription(mungedSessionDescription) - .then(() => peerConnection); + handleNegotiationStats.send(room.id, MESSAGES.STATS_MODULE.HANDLE_NEGOTIATION_STATS[type.toUpperCase()][type], targetMid, mungedSessionDescription, true); + + return peerConnection.setRemoteDescription(mungedSessionDescription) + .then(() => peerConnection); + } + + logger.log.ERROR([targetMid, TAGS.NEGOTIATION, type, `${MESSAGES.PEER_CONNECTION.NO_PEER_CONNECTION} - Unable to set remote ${type}`]); + + return handleNegotiationStats.send(room.id, MESSAGES.STATS_MODULE.HANDLE_NEGOTIATION_STATS[type.toUpperCase()].dropped, targetMid, remoteDescription, true, MESSAGES.PEER_CONNECTION.NO_PEER_CONNECTION); }; const setLocalDescription = (room, targetMid, localDescription) => { @@ -37,14 +42,17 @@ const setLocalDescription = (room, targetMid, localDescription) => { const { peerConnections } = state; const { type } = localDescription; const peerConnection = peerConnections[targetMid]; - const { STATS_MODULE } = MESSAGES; - peerConnection.processingLocalSDP = true; + if (peerConnection) { + handleNegotiationStats.send(room.id, MESSAGES.STATS_MODULE.HANDLE_NEGOTIATION_STATS[type.toUpperCase()][type], targetMid, localDescription, false); + + return peerConnection.setLocalDescription(localDescription) + .then(() => peerConnection); + } - handleNegotiationStats.send(room.id, STATS_MODULE.HANDLE_NEGOTIATION_STATS[type.toUpperCase()][type], targetMid, localDescription, false); + logger.log.ERROR([targetMid, TAGS.NEGOTIATION, type, `${MESSAGES.PEER_CONNECTION.NO_PEER_CONNECTION} - Unable to set local ${type}`]); - return peerConnection.setLocalDescription(localDescription) - .then(() => peerConnection); + return handleNegotiationStats.send(room.id, MESSAGES.STATS_MODULE.HANDLE_NEGOTIATION_STATS[type.toUpperCase()].dropped, targetMid, localDescription, true, MESSAGES.PEER_CONNECTION.NO_PEER_CONNECTION); }; export { diff --git a/src/server-communication/signaling-server/message-handler/handlers/enterHandler.js b/src/server-communication/signaling-server/message-handler/handlers/enterHandler.js index ada79d35d..2d64cacd6 100644 --- a/src/server-communication/signaling-server/message-handler/handlers/enterHandler.js +++ b/src/server-communication/signaling-server/message-handler/handlers/enterHandler.js @@ -1,7 +1,7 @@ -import { enterAndWelcomeHandler, CALLERS } from './commons/enterAndWelcome'; +import enterAndWelcomeHandler from './commons/enterAndWelcome'; const enterHandler = (message) => { - enterAndWelcomeHandler(message, CALLERS.ENTER); + enterAndWelcomeHandler(message); }; export default enterHandler; diff --git a/src/server-communication/signaling-server/message-handler/handlers/inRoomHandler.js b/src/server-communication/signaling-server/message-handler/handlers/inRoomHandler.js index fd4e96453..fd0d23fcd 100644 --- a/src/server-communication/signaling-server/message-handler/handlers/inRoomHandler.js +++ b/src/server-communication/signaling-server/message-handler/handlers/inRoomHandler.js @@ -9,10 +9,10 @@ import Room from '../../../../room'; import PeerStream from '../../../../peer-stream'; import { ON_INCOMING_STREAM } from '../../../../skylink-events/constants'; import logger from '../../../../logger'; -import { TAGS } from '../../../../constants'; import MESSAGES from '../../../../messages'; import HandleUserMediaStats from '../../../../skylink-stats/handleUserMediaStats'; import HandleSessionStats from '../../../../skylink-stats/handleSessionStats'; +import { TAGS } from '../../../../constants'; const dispatchIncomingStream = (room, sid) => { const state = Skylink.getSkylinkState(room.id); diff --git a/src/server-communication/signaling-server/message-handler/handlers/offerHandler.js b/src/server-communication/signaling-server/message-handler/handlers/offerHandler.js index 8baa2a09b..dad2e4b4b 100644 --- a/src/server-communication/signaling-server/message-handler/handlers/offerHandler.js +++ b/src/server-communication/signaling-server/message-handler/handlers/offerHandler.js @@ -1,7 +1,9 @@ -import { offerAndAnswerHandler } from './commons/offerAndAnswer'; +import NegotiationState from '../../negotiationState/negotiationState'; +import logger from '../../../../logger'; const offerHandler = (message) => { - offerAndAnswerHandler(message); + logger.log.INFO([message.mid, null, message.type, 'Received OFFER from peer:'], message); + NegotiationState.onOfferReceived(message); }; export default offerHandler; diff --git a/src/server-communication/signaling-server/message-handler/handlers/welcomeHandler.js b/src/server-communication/signaling-server/message-handler/handlers/welcomeHandler.js index c95b7639d..e4f183f60 100644 --- a/src/server-communication/signaling-server/message-handler/handlers/welcomeHandler.js +++ b/src/server-communication/signaling-server/message-handler/handlers/welcomeHandler.js @@ -1,7 +1,7 @@ -import { enterAndWelcomeHandler, CALLERS } from './commons/enterAndWelcome'; +import enterAndWelcomeHandler from './commons/enterAndWelcome'; const welcomeHandler = (message) => { - enterAndWelcomeHandler(message, CALLERS.WELCOME); + enterAndWelcomeHandler(message); }; export default welcomeHandler; diff --git a/src/server-communication/signaling-server/negotiationState/helpers/bufferRemoteOffer.js b/src/server-communication/signaling-server/negotiationState/helpers/bufferRemoteOffer.js new file mode 100644 index 000000000..be79a3748 --- /dev/null +++ b/src/server-communication/signaling-server/negotiationState/helpers/bufferRemoteOffer.js @@ -0,0 +1,14 @@ +import Skylink from '../../../../index'; +import { TAGS } from '../../../../constants'; +import MESSAGES from '../../../../messages'; +import logger from '../../../../logger'; + +const bufferRemoteOffer = (room, targetMid, offer) => { + const updatedState = Skylink.getSkylinkState(room.id); + logger.log.DEBUG([targetMid, TAGS.SESSION_DESCRIPTION, offer.type, MESSAGES.NEGOTIATION_PROGRESS.ERRORS.ADDING_REMOTE_OFFER_TO_BUFFER], offer); + updatedState.bufferedRemoteOffers[targetMid] = updatedState.bufferedRemoteOffers[targetMid] ? updatedState.bufferedRemoteOffers[targetMid] : []; + updatedState.bufferedRemoteOffers[targetMid].push(offer); + Skylink.setSkylinkState(updatedState, room.id); +}; + +export default bufferRemoteOffer; diff --git a/src/server-communication/signaling-server/negotiationState/helpers/getBufferedRemoteOffer.js b/src/server-communication/signaling-server/negotiationState/helpers/getBufferedRemoteOffer.js new file mode 100644 index 000000000..2a65beea0 --- /dev/null +++ b/src/server-communication/signaling-server/negotiationState/helpers/getBufferedRemoteOffer.js @@ -0,0 +1,16 @@ +import { isEmptyArray } from '../../../../utils/helpers'; +import { TAGS } from '../../../../constants'; +import MESSAGES from '../../../../messages'; +import logger from '../../../../logger'; + +const getBufferedRemoteOffer = (state, targetMid) => { + if (state.bufferedRemoteOffers[targetMid] && !isEmptyArray(state.bufferedRemoteOffers[targetMid])) { + const offerMessage = state.bufferedRemoteOffers[targetMid].shift(); // the first buffered message + logger.log.DEBUG([targetMid, TAGS.SESSION_DESCRIPTION, offerMessage.type, MESSAGES.NEGOTIATION_PROGRESS.APPLYING_BUFFERED_REMOTE_OFFER], offerMessage); + return offerMessage; + } + + return null; +}; + +export default getBufferedRemoteOffer; diff --git a/src/server-communication/signaling-server/negotiationState/helpers/index.js b/src/server-communication/signaling-server/negotiationState/helpers/index.js new file mode 100644 index 000000000..acc42c4cd --- /dev/null +++ b/src/server-communication/signaling-server/negotiationState/helpers/index.js @@ -0,0 +1,15 @@ +import processNewPeer from './processNewPeer'; +import updateStateInformation from './updateStateInformation'; +import getBufferedRemoteOffer from './getBufferedRemoteOffer'; +import logInfoOrErrorAndSendStats from './logInfoOrErrorAndSendStats'; +import bufferRemoteOffer from './bufferRemoteOffer'; + +const negotiationStateHelpers = { + processNewPeer, + updateStateInformation, + getBufferedRemoteOffer, + logInfoOrErrorAndSendStats, + bufferRemoteOffer, +}; + +export default negotiationStateHelpers; diff --git a/src/server-communication/signaling-server/negotiationState/helpers/logInfoOrErrorAndSendStats.js b/src/server-communication/signaling-server/negotiationState/helpers/logInfoOrErrorAndSendStats.js new file mode 100644 index 000000000..3eedf26ba --- /dev/null +++ b/src/server-communication/signaling-server/negotiationState/helpers/logInfoOrErrorAndSendStats.js @@ -0,0 +1,19 @@ +import logger from '../../../../logger'; +import { TAGS } from '../../../../constants'; +import handleNegotiationStats from '../../../../skylink-stats/handleNegotiationStats'; +import MESSAGES from '../../../../messages'; + +const logInfoOrErrorAndSendStats = (targetMid, type, room, negoMsg, isRemote, message, debugObj) => ({ + DEBUG: () => { + logger.log.DEBUG([targetMid, TAGS.NEGOTIATION, type, message], debugObj); + + return handleNegotiationStats.send(room.id, MESSAGES.STATS_MODULE.HANDLE_NEGOTIATION_STATS[type.toUpperCase()].dropped, targetMid, negoMsg, isRemote, message); + }, + ERROR: () => { + logger.log.ERROR([targetMid, TAGS.NEGOTIATION, type, message], debugObj || null); + + return handleNegotiationStats.send(room.id, MESSAGES.STATS_MODULE.HANDLE_NEGOTIATION_STATS[type.toUpperCase()].error, targetMid, negoMsg, isRemote, message); + }, +}); + +export default logInfoOrErrorAndSendStats; diff --git a/src/server-communication/signaling-server/negotiationState/helpers/processNewPeer.js b/src/server-communication/signaling-server/negotiationState/helpers/processNewPeer.js new file mode 100644 index 000000000..576f65ecc --- /dev/null +++ b/src/server-communication/signaling-server/negotiationState/helpers/processNewPeer.js @@ -0,0 +1,206 @@ +/* eslint-disable no-underscore-dangle */ +import Skylink from '../../../../index'; +import { + HANDSHAKE_PROGRESS, PEER_TYPE, SERVER_PEER_TYPE, TAGS, +} from '../../../../constants'; +import PeerConnection from '../../../../peer-connection'; +import logger from '../../../../logger'; +import MESSAGES from '../../../../messages'; +import { dispatchEvent } from '../../../../utils/skylinkEventManager'; +import { handshakeProgress, peerJoined, serverPeerJoined } from '../../../../skylink-events'; +import Room from '../../../../room'; +import PeerData from '../../../../peer-data'; +import parsers from '../../parsers'; + +const _addPeerConnection = (params) => { + const { + currentRoom, + targetMid, + cert, + userInfo, + message, + } = params; + const state = Skylink.getSkylinkState(currentRoom.id); + const hasScreenshare = !!userInfo.screenshare; + + PeerConnection.buildAndSetPeerInformations(targetMid, message.userInfo, state); + + PeerConnection.addPeer({ + currentRoom, + targetMid, + peerBrowser: { + agent: userInfo.agent.name, + version: userInfo.agent.version, + os: userInfo.agent.os, + }, + cert, + hasScreenshare, + }); +}; + +const _processPeerFromWelcome = (params) => { + const { + currentRoom, + targetMid, + message, + } = params; + const state = Skylink.getSkylinkState(currentRoom.id); + const { hasMCU, peerInformations } = state; + + // process based on room type + switch (hasMCU) { + case true: + // MCU will always send welcome + // 1) process the new MCU connection + if (targetMid === PEER_TYPE.MCU && !peerInformations.MCU) { + _addPeerConnection(params); + + logger.log.INFO([targetMid, TAGS.PEER_CONNECTION, null, MESSAGES.PEER_CONNECTION.MCU]); + + state.hasMCU = true; + + dispatchEvent(serverPeerJoined({ + peerId: targetMid, + serverPeerType: SERVER_PEER_TYPE.MCU, + room: Room.getRoomInfo(currentRoom.id), + })); + + dispatchEvent(handshakeProgress({ + peerId: targetMid, + state: HANDSHAKE_PROGRESS.WELCOME, + error: null, + room: Room.getRoomInfo(currentRoom.id), + })); + } + + // process other peers in the room if any + if (Array.isArray(message.peersInRoom) && message.peersInRoom.length) { + const userId = state.user.sid; + for (let peersInRoomIndex = 0; peersInRoomIndex < message.peersInRoom.length; peersInRoomIndex += 1) { + const PEER_ID = message.peersInRoom[peersInRoomIndex].mid; + if (PEER_ID !== userId) { + const parsedMsg = parsers.enterAndWelcome(message.peersInRoom[peersInRoomIndex]); + const peerUserInfo = parsedMsg.userInfo; + + PeerConnection.buildAndSetPeerInformations(PEER_ID, peerUserInfo, state); + + dispatchEvent(peerJoined({ + peerId: PEER_ID, + peerInfo: PeerData.getPeerInfo(PEER_ID, currentRoom), + isSelf: false, + room: Room.getRoomInfo(currentRoom.id), + })); + } + } + } + + + break; + case false: // P2P + if (!peerInformations[targetMid]) { + _addPeerConnection(params); + + dispatchEvent(peerJoined({ + peerId: targetMid, + peerInfo: PeerData.getPeerInfo(targetMid, currentRoom), + isSelf: false, + room: Room.getRoomInfo(currentRoom.id), + })); + + dispatchEvent(handshakeProgress({ + peerId: targetMid, + state: HANDSHAKE_PROGRESS.WELCOME, + error: null, + room: Room.getRoomInfo(currentRoom.id), + })); + } + + break; + default: + // should not come here + break; + } +}; + +const _processPeerFromEnter = (params) => { + const { + currentRoom, + userInfo, + targetMid, + } = params; + const state = Skylink.getSkylinkState(currentRoom.id); + const { hasMCU, peerInformations } = state; + + switch (hasMCU) { + case true: + // enter is forwarded by the MCU from a new peer that enters a room + PeerConnection.buildAndSetPeerInformations(targetMid, userInfo, state); + + dispatchEvent(peerJoined({ + peerId: targetMid, + peerInfo: PeerData.getPeerInfo(targetMid, currentRoom), + isSelf: false, + room: Room.getRoomInfo(currentRoom.id), + })); + + break; + case false: + + if (!peerInformations[targetMid]) { + _addPeerConnection(params); + + dispatchEvent(peerJoined({ + peerId: targetMid, + peerInfo: PeerData.getPeerInfo(targetMid, currentRoom), + isSelf: false, + room: Room.getRoomInfo(currentRoom.id), + })); + } + + break; + default: + // should not come here + break; + } +}; + +/** + * Function that adds a Peer Connection and updates the state(Skylink State). + * @param {JSON} message + * @memberOf SignalingMessageHandler + * @fires SERVER_PEER_JOINED + * @fires PEER_JOINED + * @fires HANDSHAKE_PROGRESS + */ +const processNewPeer = (message) => { + const parsedMsg = parsers.enterAndWelcome(message); + const { + rid, mid, userInfo, publisherId, + } = parsedMsg; + const state = Skylink.getSkylinkState(rid); + const { hasMCU } = state; + const targetMid = hasMCU && publisherId ? publisherId : mid; + const peerParams = { + currentRoom: state.room, + targetMid, + userInfo, + message: parsedMsg, + }; + const updatedState = Skylink.getSkylinkState(rid); + + // TODO: check if this is used + updatedState.peerMessagesStamps[targetMid] = updatedState.peerMessagesStamps[targetMid] || { + userData: 0, + audioMuted: 0, + videoMuted: 0, + }; + Skylink.setSkylinkState(updatedState, rid); + + if (message.type === 'enter') { + _processPeerFromEnter(peerParams); + } else if (message.type === 'welcome') { + _processPeerFromWelcome(peerParams); + } +}; + +export default processNewPeer; diff --git a/src/server-communication/signaling-server/negotiationState/helpers/updateStateInformation.js b/src/server-communication/signaling-server/negotiationState/helpers/updateStateInformation.js new file mode 100644 index 000000000..bcae6bb5f --- /dev/null +++ b/src/server-communication/signaling-server/negotiationState/helpers/updateStateInformation.js @@ -0,0 +1,27 @@ +import { DATA_CHANNEL_STATE } from '../../../../constants'; +import Skylink from '../../../../index'; +import PeerMedia from '../../../../peer-media'; + +const updateStateInformation = (state, message) => { + const updatedState = state; + const { + userInfo, rid, mid, mediaInfoList, + } = message; + const { room } = updatedState; + const updatedUserInfo = userInfo; + const targetMid = mid; + + if (userInfo && typeof userInfo === 'object') { + updatedUserInfo.settings.data = !!(updatedState.peerDataChannels[targetMid] && updatedState.peerDataChannels[targetMid].main && updatedState.peerDataChannels[targetMid].main.channel && updatedState.peerDataChannels[targetMid].main.channel.readyState === DATA_CHANNEL_STATE.OPEN); + updatedState.peerInformations[targetMid].settings = updatedUserInfo.settings || {}; + updatedState.peerInformations[targetMid].mediaStatus = updatedUserInfo.mediaStatus || {}; + updatedState.peerInformations[targetMid].userData = updatedUserInfo.userData; + } + + Skylink.setSkylinkState(updatedState, rid); + + PeerMedia.setPeerMediaInfo(room, targetMid, mediaInfoList); + PeerMedia.deleteUnavailableMedia(room, targetMid); // mediaState can be unavailable during renegotiation +}; + +export default updateStateInformation; diff --git a/src/server-communication/signaling-server/negotiationState/negotiationState.js b/src/server-communication/signaling-server/negotiationState/negotiationState.js new file mode 100644 index 000000000..64de4d002 --- /dev/null +++ b/src/server-communication/signaling-server/negotiationState/negotiationState.js @@ -0,0 +1,255 @@ +/* eslint-disable no-underscore-dangle */ +import Skylink from '../../../index'; +import negotiationStateHelpers from './helpers'; +import { NEGOTIATION_STATES, PEER_TYPE } from '../../../constants'; +import SkylinkSignalingServer from '../index'; +import MESSAGES from '../../../messages'; +import { + createAnswer, + onLocalAnswerSetFailure, + onLocalAnswerSetSuccess, + onRemoteOfferSetFailure, + onRemoteOfferSetSuccess, + sendAnswer, + setLocalAnswer, + setRemoteOffer, + setLocalOffer, + onLocalOfferSetSuccess, + onLocalOfferSetFailure, + setRemoteAnswer, + onRemoteAnswerSetSuccess, + onRemoteAnswerSetFailure, + sendAnswerAck, createOffer, sendOffer, +} from '../message-handler/handlers/commons/offerAndAnswer'; +import refreshConnection from '../../../peer-connection/helpers/refresh-connection/refreshConnection'; +import peerConnectionHelpers from '../../../peer-connection/helpers/index'; +import bufferRemoteOffer from './helpers/bufferRemoteOffer'; + +class NegotiationState { + static _changeState(roomKey, peerId, newState) { + const updatedState = Skylink.getSkylinkState(roomKey); + updatedState.negotiationState[peerId] = newState; + Skylink.setSkylinkState(updatedState, roomKey); + } + + static _getState(roomKey, peerId) { + const state = Skylink.getSkylinkState(roomKey); + return state.negotiationState[peerId]; + } + + static clearState(roomKey, peerId) { + const updatedState = Skylink.getSkylinkState(roomKey); + delete updatedState.negotiationState[peerId]; + Skylink.setSkylinkState(updatedState, roomKey); + } + + static changeState(roomKey, peerId, newState) { + return this._changeState(roomKey, peerId, newState); + } + + static onEnterReceived(enter) { + const { + rid, mid, publisherId, + } = enter; + const state = Skylink.getSkylinkState(rid); + const { hasMCU, room } = state; + const targetMid = hasMCU && publisherId ? publisherId : mid; + + // peer Connection does not exist + if (!state.peerConnections[targetMid]) { + this._changeState(rid, targetMid, NEGOTIATION_STATES.ENTERING); + // process the new peer + negotiationStateHelpers.processNewPeer(enter); + + const signaling = new SkylinkSignalingServer(); + signaling.welcome(room, targetMid); + + this._changeState(rid, targetMid, NEGOTIATION_STATES.WELCOMING); + } + } + + static onWelcomeReceived(welcome) { + const { + rid, mid, publisherId, type, + } = welcome; + const state = Skylink.getSkylinkState(rid); + const { hasMCU, room } = state; + const targetMid = hasMCU && publisherId ? publisherId : mid; + + const negState = this._getState(rid, targetMid); + if (negState) { // it should be undefined as this will be the first message from the remote peer + return negotiationStateHelpers.logInfoOrErrorAndSendStats(targetMid, type, room, welcome, true, MESSAGES.NEGOTIATION_PROGRESS.ERRORS.DROPPING_WELCOME_NEG_STATE, `Current state: ${negState}`).DEBUG(); + } + + if (hasMCU && targetMid !== PEER_TYPE.MCU) { // welcome forwarded by signaling server + return negotiationStateHelpers.logInfoOrErrorAndSendStats(targetMid, type, room, welcome, true, MESSAGES.NEGOTIATION_PROGRESS.ERRORS.DROPPING_WELCOME_MCU_FORWARDED, `Current state: ${negState}`).DEBUG(); + } + + // peer Connection does not exist + if (!state.peerConnections[targetMid]) { + // process the new peer + negotiationStateHelpers.processNewPeer(welcome); + + return createOffer(room, targetMid) + .then((offer) => { + sendOffer(room, offer); + this._changeState(rid, targetMid, NEGOTIATION_STATES.LOCAL_OFFER_SENT); + }); + } + + return false; + } + + static onOfferReceived(offer) { + const { + rid, mid, publisherId, weight, type, sdp, + } = offer; + const state = Skylink.getSkylinkState(rid); + const { hasMCU, room, peerPriorityWeight } = state; + const targetMid = hasMCU && publisherId ? publisherId : mid; + const remoteDescription = { + type, + sdp: hasMCU ? sdp.replace(/\r\n/g, '\n').split('\n').join('\r\n') : sdp, + }; + let localDescription; + let answer; + + const negState = this._getState(rid, targetMid); + if (!(negState === NEGOTIATION_STATES.WELCOMING || negState === NEGOTIATION_STATES.NEGOTIATED || negState === NEGOTIATION_STATES.LOCAL_OFFER_SENT)) { + if (negState === NEGOTIATION_STATES.LOCAL_OFFER_SENT && peerPriorityWeight > weight) { + return negotiationStateHelpers.logInfoOrErrorAndSendStats(targetMid, type, room, offer, true, MESSAGES.NEGOTIATION_PROGRESS.ERRORS.OFFER_TIEBREAKER, { + selfWeight: peerPriorityWeight, + messageWeight: weight, + }).DEBUG(); + } + + return bufferRemoteOffer(room, targetMid, offer); + } + + this._changeState(rid, targetMid, NEGOTIATION_STATES.REMOTE_OFFER_RECEIVED); + + try { + negotiationStateHelpers.updateStateInformation(state, offer); + + return setRemoteOffer(room, targetMid, remoteDescription) + .then((peerConnection) => { + this._changeState(rid, targetMid, NEGOTIATION_STATES.REMOTE_OFFER_SET); + + onRemoteOfferSetSuccess(peerConnection, room, targetMid, remoteDescription); + + return createAnswer(state, targetMid); + }) + .catch(error => onRemoteOfferSetFailure(room, targetMid, remoteDescription, error)) + .then((ans) => { + answer = ans; + localDescription = { + type: answer.type, + sdp: answer.sdp, + }; + + return setLocalAnswer(room, targetMid, localDescription); + }) + .then((peerConnection) => { + this._changeState(rid, targetMid, NEGOTIATION_STATES.LOCAL_ANSWER_SET); + + onLocalAnswerSetSuccess(peerConnection, room, targetMid, localDescription); + + sendAnswer(room, answer); + }) + .catch(error => onLocalAnswerSetFailure(room, targetMid, localDescription, error)); + } catch (error) { + return negotiationStateHelpers.logInfoOrErrorAndSendStats(mid, type, room, answer, true, MESSAGES.NEGOTIATION_PROGRESS.ERRORS.FAILED_PROCESSING_OFFER, error).ERROR(); + } + } + + static onAnswerReceived(answer) { + const { + rid, mid, publisherId, type, sdp, + } = answer; + const state = Skylink.getSkylinkState(rid); + const { hasMCU, room, bufferedLocalOffer } = state; + const targetMid = hasMCU && publisherId ? publisherId : mid; + + const negState = this._getState(rid, targetMid); + if (negState !== NEGOTIATION_STATES.LOCAL_OFFER_SENT) { + return negotiationStateHelpers.logInfoOrErrorAndSendStats(targetMid, type, room, answer, true, MESSAGES.NEGOTIATION_PROGRESS.ERRORS.DROPPING_ANSWER, `Current state: ${negState}`).DEBUG(); + } + + if (!bufferedLocalOffer[targetMid]) { + return negotiationStateHelpers.logInfoOrErrorAndSendStats(targetMid, type, room, answer, true, MESSAGES.NEGOTIATION_PROGRESS.ERRORS.NO_LOCAL_BUFFERED_OFFER).ERROR(); + } + + this._changeState(rid, targetMid, NEGOTIATION_STATES.REMOTE_ANSWER_RECEIVED); + + try { + negotiationStateHelpers.updateStateInformation(state, answer); + + const localDescription = bufferedLocalOffer[targetMid]; + const remoteDescription = { + type, + sdp: hasMCU ? sdp.replace(/\r\n/g, '\n').split('\n').join('\r\n') : sdp, + }; + + return setLocalOffer(room, targetMid, localDescription) + .then((peerConnection) => { + this._changeState(rid, targetMid, NEGOTIATION_STATES.LOCAL_OFFER_SET); + + return onLocalOfferSetSuccess(peerConnection, room, targetMid, localDescription); + }) + .catch(error => onLocalOfferSetFailure(room, targetMid, localDescription, error)) + .then(() => setRemoteAnswer(room, targetMid, remoteDescription)) + .then((peerConnection) => { + this._changeState(rid, targetMid, NEGOTIATION_STATES.REMOTE_ANSWER_SET); + + return onRemoteAnswerSetSuccess(peerConnection, room, targetMid, remoteDescription); + }) + .catch(error => onRemoteAnswerSetFailure(room, targetMid, remoteDescription, error)) + .then(() => { + sendAnswerAck(room, targetMid, true); + + this._changeState(rid, targetMid, NEGOTIATION_STATES.NEGOTIATED); + }); + } catch (error) { + return negotiationStateHelpers.logInfoOrErrorAndSendStats(mid, type, room, answer, true, MESSAGES.NEGOTIATION_PROGRESS.ERRORS.FAILED_PROCESSING_ANSWER, error).ERROR(); + } + } + + static onAnswerAckReceived(answerAck) { + const { + rid, mid, publisherId, type, success, + } = answerAck; + const state = Skylink.getSkylinkState(rid); + const { hasMCU, room } = state; + const targetMid = hasMCU && publisherId ? publisherId : mid; + + const negState = this._getState(rid, targetMid); + if (negState !== NEGOTIATION_STATES.LOCAL_ANSWER_SET) { + return negotiationStateHelpers.logInfoOrErrorAndSendStats(targetMid, type, room, answerAck, true, MESSAGES.NEGOTIATION_PROGRESS.ERRORS.DROPPING_ANSWER_ACK, `Current state: ${negState}`).DEBUG(); + } + + if (!success) { + return negotiationStateHelpers.logInfoOrErrorAndSendStats(mid, type, room, answerAck, true, MESSAGES.NEGOTIATION_PROGRESS.ERRORS.FAILED_SET_REMOTE_ANSWER).ERROR(); + } + + this._changeState(rid, targetMid, NEGOTIATION_STATES.NEGOTIATED); + + try { + const bufferedOffer = negotiationStateHelpers.getBufferedRemoteOffer(state, targetMid); + + if (bufferedOffer) { + return this.onOfferReceived(bufferedOffer); + } + + return peerConnectionHelpers.renegotiateIfNeeded(state, targetMid).then((shouldRenegotiate) => { + if (shouldRenegotiate) { + refreshConnection(state, targetMid) + .catch(error => negotiationStateHelpers.logInfoOrErrorAndSendStats(mid, type, room, answerAck, true, MESSAGES.NEGOTIATION_PROGRESS.ERRORS.FAILED_RENEGOTIATION, error).ERROR()); + } + }); + } catch (error) { + return negotiationStateHelpers.logInfoOrErrorAndSendStats(mid, type, room, answerAck, true, MESSAGES.NEGOTIATION_PROGRESS.ERRORS.FAILED_PROCESSING_ANSWER_ACK, error).ERROR(); + } + } +} + +export default NegotiationState; diff --git a/src/server-communication/signaling-server/parsers/enterAndWelcome.js b/src/server-communication/signaling-server/parsers/enterAndWelcome.js index 14897dc98..501272ce3 100644 --- a/src/server-communication/signaling-server/parsers/enterAndWelcome.js +++ b/src/server-communication/signaling-server/parsers/enterAndWelcome.js @@ -41,6 +41,7 @@ const enterAndWelcome = (msg) => { publisherId, } = msg; + parsedMsg.type = msg.type; parsedMsg.publisherId = publisherId || null; parsedMsg.rid = rid; parsedMsg.mid = mid; From 285ef850355c58f174ad89354b336547240e1bfa Mon Sep 17 00:00:00 2001 From: Dina Wee Date: Thu, 23 Sep 2021 16:21:01 +0800 Subject: [PATCH 5/8] Merged ESS-2111-negotiation-state into development * ESS-2111: Refactored negotation piece to implement negotation state machine * ESS-2046: Fixes for FF not renegotiating when the remote peer has no audio and video * ESS-2111: Fixes for extra welcome from remote peer being forwarded by sig * ESS-2111: Fix crossing of offers and sending of restart offer when negotiates state is not 'negotiated' --- src/messages.js | 2 ++ src/models/skylink-state.js | 8 +++++ .../handlers/commons/offerAndAnswer.js | 9 ++++- .../helpers/checkAndApplyBufferedRestart.js | 20 +++++++++++ .../negotiationState/helpers/index.js | 2 ++ .../negotiationState/negotiationState.js | 35 ++++++++++++------- 6 files changed, 62 insertions(+), 14 deletions(-) create mode 100644 src/server-communication/signaling-server/negotiationState/helpers/checkAndApplyBufferedRestart.js diff --git a/src/messages.js b/src/messages.js index b0d54baca..3ef064d1a 100644 --- a/src/messages.js +++ b/src/messages.js @@ -179,6 +179,8 @@ const MESSAGES = { SET_LOCAL_DESCRIPTION: 'Successfully set local description -->', SET_REMOTE_DESCRIPTION: 'Successfully set remote description -->', APPLYING_BUFFERED_REMOTE_OFFER: 'Applying buffered remote offer', + BUFFERING_RESTART: 'Buffering restart offer until \'negotiated\' state is reached', + APPLY_BUFFERED_RESTART: 'Applying buffered restart offer now that \'negotiated\' state is reached', ERRORS: { FAILED_SET_LOCAL_DESCRIPTION: 'Failed setting local description -->', FAILED_SET_REMOTE_DESCRIPTION: 'Failed setting remote description -->', diff --git a/src/models/skylink-state.js b/src/models/skylink-state.js index 0b27f7b79..78ec01ca7 100644 --- a/src/models/skylink-state.js +++ b/src/models/skylink-state.js @@ -286,6 +286,14 @@ class SkylinkState { * @since 1.0.0 */ this.bufferedLocalOffer = {}; + /** + * Restart buffered in order to apply when negotiation state is 'negotiated' + * @name bufferedRestart + * @type Object + * @private + * @since 2.3.3 + */ + this.bufferedRestart = {}; /** * Offers buffered in order to apply when answerAck has been received * @name bufferedRemoteOffers diff --git a/src/server-communication/signaling-server/message-handler/handlers/commons/offerAndAnswer.js b/src/server-communication/signaling-server/message-handler/handlers/commons/offerAndAnswer.js index 5bd540009..d52c863fe 100644 --- a/src/server-communication/signaling-server/message-handler/handlers/commons/offerAndAnswer.js +++ b/src/server-communication/signaling-server/message-handler/handlers/commons/offerAndAnswer.js @@ -28,12 +28,19 @@ export const sendRestartOffer = (state, peerId, doIceRestart) => { const signaling = new SkylinkSignalingServer(); try { + if (NegotiationState.getState(room.id, peerId) !== NEGOTIATION_STATES.NEGOTIATED) { + const updatedState = state; + updatedState.bufferedRestart[peerId] = { doIceRestart }; + Skylink.setSkylinkState(updatedState, room.id); + return logger.log.DEBUG([peerId, TAGS.NEGOTIATION, null, MESSAGES.NEGOTIATION_PROGRESS.BUFFERING_RESTART]); + } + const restartOfferMsg = signaling.messageBuilder.getRestartOfferMessage(room.id, peerId, doIceRestart); return createOffer(room, peerId, doIceRestart, restartOfferMsg) .then((offer) => { - sendOffer(room, offer); NegotiationState.changeState(room.id, peerId, NEGOTIATION_STATES.LOCAL_OFFER_SENT); + sendOffer(room, offer); return peerId; }); } catch (ex) { diff --git a/src/server-communication/signaling-server/negotiationState/helpers/checkAndApplyBufferedRestart.js b/src/server-communication/signaling-server/negotiationState/helpers/checkAndApplyBufferedRestart.js new file mode 100644 index 000000000..460d27b6a --- /dev/null +++ b/src/server-communication/signaling-server/negotiationState/helpers/checkAndApplyBufferedRestart.js @@ -0,0 +1,20 @@ +import Skylink from '../../../../index'; +import { sendRestartOffer } from '../../message-handler/handlers/commons/offerAndAnswer'; +import logger from '../../../../logger'; +import { TAGS } from '../../../../constants'; +import MESSAGES from '../../../../messages'; + +const checkAndApplyBufferedRestart = (room, peerId) => { + const updatedState = Skylink.getSkylinkState(room.id); + const { bufferedRestart } = updatedState; + + if (bufferedRestart[peerId]) { + delete updatedState.bufferedRestart[peerId]; + Skylink.setSkylinkState(updatedState, room.id); + + logger.log.DEBUG([peerId, TAGS.NEGOTIATION, null, MESSAGES.NEGOTIATION_PROGRESS.APPLY_BUFFERED_RESTART]); + sendRestartOffer(updatedState, peerId, bufferedRestart.doIceRestart); + } +}; + +export default checkAndApplyBufferedRestart; diff --git a/src/server-communication/signaling-server/negotiationState/helpers/index.js b/src/server-communication/signaling-server/negotiationState/helpers/index.js index acc42c4cd..dfd72e870 100644 --- a/src/server-communication/signaling-server/negotiationState/helpers/index.js +++ b/src/server-communication/signaling-server/negotiationState/helpers/index.js @@ -3,6 +3,7 @@ import updateStateInformation from './updateStateInformation'; import getBufferedRemoteOffer from './getBufferedRemoteOffer'; import logInfoOrErrorAndSendStats from './logInfoOrErrorAndSendStats'; import bufferRemoteOffer from './bufferRemoteOffer'; +import checkAndApplyBufferedRestart from './checkAndApplyBufferedRestart'; const negotiationStateHelpers = { processNewPeer, @@ -10,6 +11,7 @@ const negotiationStateHelpers = { getBufferedRemoteOffer, logInfoOrErrorAndSendStats, bufferRemoteOffer, + checkAndApplyBufferedRestart, }; export default negotiationStateHelpers; diff --git a/src/server-communication/signaling-server/negotiationState/negotiationState.js b/src/server-communication/signaling-server/negotiationState/negotiationState.js index 64de4d002..23d199fc8 100644 --- a/src/server-communication/signaling-server/negotiationState/negotiationState.js +++ b/src/server-communication/signaling-server/negotiationState/negotiationState.js @@ -47,6 +47,10 @@ class NegotiationState { return this._changeState(roomKey, peerId, newState); } + static getState(roomKey, peerId) { + return this._getState(roomKey, peerId); + } + static onEnterReceived(enter) { const { rid, mid, publisherId, @@ -61,10 +65,10 @@ class NegotiationState { // process the new peer negotiationStateHelpers.processNewPeer(enter); + this._changeState(rid, targetMid, NEGOTIATION_STATES.WELCOMING); + const signaling = new SkylinkSignalingServer(); signaling.welcome(room, targetMid); - - this._changeState(rid, targetMid, NEGOTIATION_STATES.WELCOMING); } } @@ -92,8 +96,8 @@ class NegotiationState { return createOffer(room, targetMid) .then((offer) => { - sendOffer(room, offer); this._changeState(rid, targetMid, NEGOTIATION_STATES.LOCAL_OFFER_SENT); + sendOffer(room, offer); }); } @@ -115,14 +119,15 @@ class NegotiationState { let answer; const negState = this._getState(rid, targetMid); - if (!(negState === NEGOTIATION_STATES.WELCOMING || negState === NEGOTIATION_STATES.NEGOTIATED || negState === NEGOTIATION_STATES.LOCAL_OFFER_SENT)) { - if (negState === NEGOTIATION_STATES.LOCAL_OFFER_SENT && peerPriorityWeight > weight) { - return negotiationStateHelpers.logInfoOrErrorAndSendStats(targetMid, type, room, offer, true, MESSAGES.NEGOTIATION_PROGRESS.ERRORS.OFFER_TIEBREAKER, { - selfWeight: peerPriorityWeight, - messageWeight: weight, - }).DEBUG(); - } + if (negState === NEGOTIATION_STATES.LOCAL_OFFER_SENT && peerPriorityWeight > weight) { + return negotiationStateHelpers.logInfoOrErrorAndSendStats(targetMid, type, room, offer, true, MESSAGES.NEGOTIATION_PROGRESS.ERRORS.OFFER_TIEBREAKER, { + selfWeight: peerPriorityWeight, + messageWeight: weight, + }).DEBUG(); + } + + if (!(negState === NEGOTIATION_STATES.WELCOMING || negState === NEGOTIATION_STATES.NEGOTIATED || negState === NEGOTIATION_STATES.LOCAL_OFFER_SENT)) { return bufferRemoteOffer(room, targetMid, offer); } @@ -167,7 +172,9 @@ class NegotiationState { rid, mid, publisherId, type, sdp, } = answer; const state = Skylink.getSkylinkState(rid); - const { hasMCU, room, bufferedLocalOffer } = state; + const { + hasMCU, room, bufferedLocalOffer, + } = state; const targetMid = hasMCU && publisherId ? publisherId : mid; const negState = this._getState(rid, targetMid); @@ -205,9 +212,9 @@ class NegotiationState { }) .catch(error => onRemoteAnswerSetFailure(room, targetMid, remoteDescription, error)) .then(() => { - sendAnswerAck(room, targetMid, true); - this._changeState(rid, targetMid, NEGOTIATION_STATES.NEGOTIATED); + sendAnswerAck(room, targetMid, true); + return negotiationStateHelpers.checkAndApplyBufferedRestart(room, targetMid); }); } catch (error) { return negotiationStateHelpers.logInfoOrErrorAndSendStats(mid, type, room, answer, true, MESSAGES.NEGOTIATION_PROGRESS.ERRORS.FAILED_PROCESSING_ANSWER, error).ERROR(); @@ -244,6 +251,8 @@ class NegotiationState { if (shouldRenegotiate) { refreshConnection(state, targetMid) .catch(error => negotiationStateHelpers.logInfoOrErrorAndSendStats(mid, type, room, answerAck, true, MESSAGES.NEGOTIATION_PROGRESS.ERRORS.FAILED_RENEGOTIATION, error).ERROR()); + } else { + negotiationStateHelpers.checkAndApplyBufferedRestart(room, targetMid); } }); } catch (error) { From ac0d80122996ad8d27e1ed7e92b02ad3d5c602db Mon Sep 17 00:00:00 2001 From: dinawee Date: Thu, 23 Sep 2021 16:23:11 +0800 Subject: [PATCH 6/8] Bump version to 2.3.3 --- README.md | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f19d0f822..fa470f8c1 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# SKYLINK WEB SDK 2.3.2 +# SKYLINK WEB SDK 2.3.3 > Temasys SkylinkJS Web SDK is an open-source client-side library for your web-browser that enables any website to easily leverage the capabilities of WebRTC and its direct data streaming powers between peers for audio/video conferencing. You'll need a Temasys Account, and an App key to use this. [Register here to get your App key](https://console.temasys.io). @@ -34,7 +34,7 @@ You'll need a Temasys Account, and an App key to use this. [Register here to get - We recommend that you always use the latest versions of the Temasys SkylinkJS Web SDK as WebRTC is still evolving and we adapt to changes very frequently. - It is advised to not attach any event handlers to the WebRTC APIs as doing so may override the handlers set in SkylinkJS and result in unexpected behaviour. -[Latest version: 2.3.2](https://github.com/Temasys/SkylinkJS/releases/tag/2.3.2) +[Latest version: 2.3.3](https://github.com/Temasys/SkylinkJS/releases/tag/2.3.3) ## How to build your own Temasys SkylinkJS Web SDK diff --git a/package.json b/package.json index eed836705..0ce8ee86c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "skylinkjs", "description": "Temasys Web SDK is an open-source client-side library for your web-browser that enables any website to easily leverage the capabilities of WebRTC and its direct data streaming powers between peers for audio/video conferencing or file transfer.", - "version": "2.3.2", + "version": "2.3.3", "homepage": "https://temasys.io/", "author": { "name": "Temasys Communications Pte. Ltd.", From daf3abf5076ad4a1527e74fa17ae09950a872acd Mon Sep 17 00:00:00 2001 From: dinawee Date: Thu, 23 Sep 2021 18:55:13 +0800 Subject: [PATCH 7/8] Update version to 2.4.0 --- README.md | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index fa470f8c1..2d6632d3a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# SKYLINK WEB SDK 2.3.3 +# SKYLINK WEB SDK 2.4.0 > Temasys SkylinkJS Web SDK is an open-source client-side library for your web-browser that enables any website to easily leverage the capabilities of WebRTC and its direct data streaming powers between peers for audio/video conferencing. You'll need a Temasys Account, and an App key to use this. [Register here to get your App key](https://console.temasys.io). @@ -34,7 +34,7 @@ You'll need a Temasys Account, and an App key to use this. [Register here to get - We recommend that you always use the latest versions of the Temasys SkylinkJS Web SDK as WebRTC is still evolving and we adapt to changes very frequently. - It is advised to not attach any event handlers to the WebRTC APIs as doing so may override the handlers set in SkylinkJS and result in unexpected behaviour. -[Latest version: 2.3.3](https://github.com/Temasys/SkylinkJS/releases/tag/2.3.3) +[Latest version: 2.4.0](https://github.com/Temasys/SkylinkJS/releases/tag/2.4.0) ## How to build your own Temasys SkylinkJS Web SDK diff --git a/package.json b/package.json index 0ce8ee86c..8ade671e4 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "skylinkjs", "description": "Temasys Web SDK is an open-source client-side library for your web-browser that enables any website to easily leverage the capabilities of WebRTC and its direct data streaming powers between peers for audio/video conferencing or file transfer.", - "version": "2.3.3", + "version": "2.4.0", "homepage": "https://temasys.io/", "author": { "name": "Temasys Communications Pte. Ltd.", From 873c8eafc15f2f20935f8ffbe9d152b83158c47f Mon Sep 17 00:00:00 2001 From: bitbucket-pipelines Date: Thu, 23 Sep 2021 11:01:20 +0000 Subject: [PATCH 8/8] [skip ci] Add publish files --- docs/SkylinkConstants.html | 4 +- docs/constants.js.html | 23 + docs/index.html | 4 +- docs/models_skylink-state.js.html | 369 +-- ...eer-connection_helpers_createOffer.js.html | 1 - ...peer-addition_createPeerConnection.js.html | 3 - ...fresh-connection_refreshConnection.js.html | 4 +- ...sh-connection_restartMCUConnection.js.html | 4 +- ...h-connection_restartPeerConnection.js.html | 4 +- docs/peer-connection_index.js.html | 4 +- ...mmunication_signaling-server_index.js.html | 31 +- ...r_handlers_commons_enterAndWelcome.js.html | 104 +- ...age-handler_handlers_inRoomHandler.js.html | 2 +- ...iationState_helpers_processNewPeer.js.html | 323 ++ publish/2.3.2/gzip/skylink.complete.js | Bin 212400 -> 0 bytes publish/2.3.2/gzip/skylink.complete.min.js | Bin 101749 -> 0 bytes .../2.3.2/gzip/skylink.complete.min.umd.js | Bin 102006 -> 0 bytes publish/2.3.2/gzip/skylink.complete.umd.js | Bin 217692 -> 0 bytes publish/2.3.2/skylink.complete.min.js | 21 - publish/2.3.2/skylink.complete.min.umd.js | 25 - .../demos/collection/README.md | 0 .../demos/collection/assets/imgs/black.png | Bin .../demos/collection/assets/imgs/favicon.ico | Bin .../collection/assets/imgs/no_profile.jpg | Bin .../collection/assets/imgs/skylinkjs.svg | 0 .../demos/collection/assets/imgs/stripes.png | Bin .../demos/collection/assets/imgs/user.png | Bin .../assets/videos/sampleVideo_10.mp4 | Bin .../assets/videos/sampleVideo_30.mp4 | Bin .../demos/collection/audio-call/index.html | 0 .../demos/collection/audio-call/main.js | 0 .../demos/collection/chat/chat.css | 0 .../demos/collection/chat/index.html | 0 .../demos/collection/chat/main.js | 0 .../demos/collection/config.example.js | 0 .../demos/collection/css/main.css | 0 .../demos/collection/index.html | 0 .../collection/kitchensink/eventManager.js | 0 .../demos/collection/kitchensink/index.html | 0 .../collection/kitchensink/kitchensink.css | 0 .../demos/collection/kitchensink/main.js | 0 .../demos/collection/socket.io.js | 0 .../demos/collection/video-call/index.html | 0 .../demos/collection/video-call/main.js | 0 .../{2.3.2 => 2.4.0}/docs/Reconnection.html | 0 publish/{2.3.2 => 2.4.0}/docs/Skylink.html | 0 .../docs/SkylinkConstants.html | 4 +- .../{2.3.2 => 2.4.0}/docs/SkylinkEvents.html | 0 .../{2.3.2 => 2.4.0}/docs/SkylinkLogger.html | 0 .../docs/compatibility_ice-connection.js.html | 0 .../compatibility_peer-connection.js.html | 0 .../{2.3.2 => 2.4.0}/docs/constants.js.html | 23 + .../docs/documentation_reconnection.js.html | 0 .../docs/documentation_typedefs.js.html | 0 ...essaging_encrypted-messaging_index.js.html | 0 .../docs/features_rtmp_index.js.html | 0 .../features_screen-sharing_index.js.html | 0 .../docs/fonts/OpenSans-Bold-webfont.eot | Bin .../docs/fonts/OpenSans-Bold-webfont.svg | 0 .../docs/fonts/OpenSans-Bold-webfont.woff | Bin .../fonts/OpenSans-BoldItalic-webfont.eot | Bin .../fonts/OpenSans-BoldItalic-webfont.svg | 0 .../fonts/OpenSans-BoldItalic-webfont.woff | Bin .../docs/fonts/OpenSans-Italic-webfont.eot | Bin .../docs/fonts/OpenSans-Italic-webfont.svg | 0 .../docs/fonts/OpenSans-Italic-webfont.woff | Bin .../docs/fonts/OpenSans-Light-webfont.eot | Bin .../docs/fonts/OpenSans-Light-webfont.svg | 0 .../docs/fonts/OpenSans-Light-webfont.woff | Bin .../fonts/OpenSans-LightItalic-webfont.eot | Bin .../fonts/OpenSans-LightItalic-webfont.svg | 0 .../fonts/OpenSans-LightItalic-webfont.woff | Bin .../docs/fonts/OpenSans-Regular-webfont.eot | Bin .../docs/fonts/OpenSans-Regular-webfont.svg | 0 .../docs/fonts/OpenSans-Regular-webfont.woff | Bin .../docs/fonts/OpenSans-Semibold-webfont.eot | Bin .../docs/fonts/OpenSans-Semibold-webfont.svg | 0 .../docs/fonts/OpenSans-Semibold-webfont.ttf | Bin .../docs/fonts/OpenSans-Semibold-webfont.woff | Bin .../fonts/OpenSans-SemiboldItalic-webfont.eot | Bin .../fonts/OpenSans-SemiboldItalic-webfont.svg | 0 .../fonts/OpenSans-SemiboldItalic-webfont.ttf | Bin .../OpenSans-SemiboldItalic-webfont.woff | Bin publish/{2.3.2 => 2.4.0}/docs/global.html | 0 .../docs/ice-connection_index.js.html | 0 publish/{2.3.2 => 2.4.0}/docs/icons/home.svg | 0 .../{2.3.2 => 2.4.0}/docs/icons/search.svg | 0 publish/{2.3.2 => 2.4.0}/docs/index.html | 4 +- publish/{2.3.2 => 2.4.0}/docs/index.js.html | 0 .../docs/logger_index.js.html | 0 ...ia-stream_helpers_getStreamSources.js.html | 0 .../media-stream_helpers_getStreams.js.html | 0 .../media-stream_helpers_muteStreams.js.html | 0 ...stream_helpers_onStreamAccessError.js.html | 0 ...eam_helpers_prepMediaAccessRequest.js.html | 0 .../media-stream_helpers_sendStream.js.html | 0 ..._helpers_stopStream_dispatchEvents.js.html | 0 ...pStream_dispatchOnLocalStreamEnded.js.html | 0 ...am_helpers_stopStream_removeTracks.js.html | 0 .../docs/media-stream_index.js.html | 0 .../docs/models_api-response.js.html | 0 .../docs/models_skylink-room.js.html | 0 .../docs/models_skylink-state.js.html | 369 +-- .../docs/models_skylink-user.js.html | 0 ...er-connection_helpers_createAnswer.js.html | 0 ...eer-connection_helpers_createOffer.js.html | 1 - ...nnel_callbacks_onbufferedamountlow.js.html | 0 ...ers_data-channel_callbacks_onclose.js.html | 0 ...ers_data-channel_callbacks_onerror.js.html | 0 ...s_data-channel_callbacks_onmessage.js.html | 0 ...pers_data-channel_callbacks_onopen.js.html | 0 ...pers_data-channel_closeDataChannel.js.html | 0 ...ers_data-channel_createDataChannel.js.html | 0 ..._data-channel_getDataChannelBuffer.js.html | 0 ...rs_data-channel_refreshDataChannel.js.html | 0 ...elpers_data-channel_sendP2PMessage.js.html | 0 ...tion_helpers_peer-addition_addPeer.js.html | 0 ...r-addition_callbacks_ondatachannel.js.html | 0 ...-addition_callbacks_onicecandidate.js.html | 0 ...llbacks_oniceconnectionstatechange.js.html | 0 ...allbacks_onicegatheringstatechange.js.html | 0 ...r-addition_callbacks_onremovetrack.js.html | 0 ...r-addition_callbacks_onsenderadded.js.html | 0 ...n_callbacks_onsignalingstatechange.js.html | 0 ...rs_peer-addition_callbacks_ontrack.js.html | 0 ...peer-addition_createPeerConnection.js.html | 3 - ...fresh-connection_refreshConnection.js.html | 4 +- ...h-connection_refreshPeerConnection.js.html | 0 ...sh-connection_restartMCUConnection.js.html | 4 +- ...h-connection_restartPeerConnection.js.html | 4 +- ...-connection_helpers_sendP2PMessage.js.html | 0 ...n_helpers_signalingEndOfCandidates.js.html | 0 ...onnection_helpers_statistics_index.js.html | 0 ...pers_statistics_parsers_parseAudio.js.html | 0 ...atistics_parsers_parseCertificates.js.html | 0 ...parsers_parseSelectedCandidatePair.js.html | 0 ...pers_statistics_parsers_parseVideo.js.html | 0 ...s_statistics_parsers_tabulateStats.js.html | 0 .../docs/peer-connection_index.js.html | 4 +- ...ata_helpers_getPeersCustomSettings.js.html | 0 .../peer-data_helpers_getPeersStreams.js.html | 0 .../docs/peer-data_index.js.html | 0 .../docs/peer-media_index.js.html | 0 .../docs/peer-privileged_index.js.html | 0 .../docs/public_index.js.html | 0 .../docs/room_getRoomInfo.js.html | 0 .../docs/scripts/linenumber.js | 0 .../docs/scripts/pagelocation.js | 0 ...nication_api-server_defaultOptions.js.html | 0 ...mmunication_signaling-server_index.js.html | 31 +- ...uilder_builders_getPeerListMessage.js.html | 0 ...uilder_builders_setUserDataMessage.js.html | 0 ...age-builder_builders_streamMessage.js.html | 0 ...-handler_handlers_candidateHandler.js.html | 0 ...r_handlers_commons_enterAndWelcome.js.html | 104 +- ...er_handlers_commons_offerAndAnswer.js.html | 0 ...ndler_handlers_commons_processPeer.js.html | 0 ...andler_handlers_getPeerListHandler.js.html | 0 ...age-handler_handlers_inRoomHandler.js.html | 2 +- ...ler_handlers_introduceErrorHandler.js.html | 0 ...ler_handlers_storedMessagesHandler.js.html | 0 ...age-handler_handlers_streamHandler.js.html | 0 ...iationState_helpers_processNewPeer.js.html | 323 ++ .../skylink-events_candidate-events.js.html | 0 ...kylink-events_data-transfer-events.js.html | 0 .../skylink-events_datachannel-events.js.html | 0 .../docs/skylink-events_index.js.html | 0 .../docs/skylink-events_init-events.js.html | 0 .../docs/skylink-events_logger-events.js.html | 0 .../docs/skylink-events_media-events.js.html | 0 .../docs/skylink-events_peer-events.js.html | 0 ...ylink-events_peer-handshake-events.js.html | 0 .../docs/skylink-events_room-events.js.html | 0 .../docs/skylink-events_socket-events.js.html | 0 .../docs/skylink-events_stream-events.js.html | 0 .../docs/skylink-states.js.html | 0 .../{2.3.2 => 2.4.0}/docs/styles/collapse.css | 0 .../docs/styles/jsdoc-default.css | 0 .../docs/styles/prettify-jsdoc.css | 0 .../docs/styles/prettify-tomorrow.css | 0 .../{2.3.2 => 2.4.0}/docs/typedefs.js.html | 0 .../docs/utils_helpers.js.html | 0 publish/2.4.0/gzip/skylink.complete.js | Bin 0 -> 213458 bytes publish/2.4.0/gzip/skylink.complete.min.js | Bin 0 -> 102513 bytes .../2.4.0/gzip/skylink.complete.min.umd.js | Bin 0 -> 102756 bytes publish/2.4.0/gzip/skylink.complete.umd.js | Bin 0 -> 218739 bytes publish/{2.3.2 => 2.4.0}/skylink.complete.js | 2785 +++++++++-------- publish/2.4.0/skylink.complete.min.js | 21 + publish/2.4.0/skylink.complete.min.umd.js | 25 + .../{2.3.2 => 2.4.0}/skylink.complete.umd.js | 2785 +++++++++-------- publish/2.x/docs/SkylinkConstants.html | 4 +- publish/2.x/docs/constants.js.html | 23 + publish/2.x/docs/index.html | 4 +- publish/2.x/docs/models_skylink-state.js.html | 369 +-- ...eer-connection_helpers_createOffer.js.html | 1 - ...peer-addition_createPeerConnection.js.html | 3 - ...fresh-connection_refreshConnection.js.html | 4 +- ...sh-connection_restartMCUConnection.js.html | 4 +- ...h-connection_restartPeerConnection.js.html | 4 +- .../2.x/docs/peer-connection_index.js.html | 4 +- ...mmunication_signaling-server_index.js.html | 31 +- ...r_handlers_commons_enterAndWelcome.js.html | 104 +- ...age-handler_handlers_inRoomHandler.js.html | 2 +- ...iationState_helpers_processNewPeer.js.html | 323 ++ publish/2.x/gzip/skylink.complete.js | Bin 212400 -> 213458 bytes publish/2.x/gzip/skylink.complete.min.js | Bin 101749 -> 102513 bytes publish/2.x/gzip/skylink.complete.min.umd.js | Bin 102006 -> 102756 bytes publish/2.x/gzip/skylink.complete.umd.js | Bin 217692 -> 218739 bytes publish/2.x/skylink.complete.js | 2785 +++++++++-------- publish/2.x/skylink.complete.min.js | 10 +- publish/2.x/skylink.complete.min.umd.js | 6 +- publish/2.x/skylink.complete.umd.js | 2785 +++++++++-------- publish/latest/docs/SkylinkConstants.html | 4 +- publish/latest/docs/constants.js.html | 23 + publish/latest/docs/index.html | 4 +- .../latest/docs/models_skylink-state.js.html | 369 +-- ...eer-connection_helpers_createOffer.js.html | 1 - ...peer-addition_createPeerConnection.js.html | 3 - ...fresh-connection_refreshConnection.js.html | 4 +- ...sh-connection_restartMCUConnection.js.html | 4 +- ...h-connection_restartPeerConnection.js.html | 4 +- .../latest/docs/peer-connection_index.js.html | 4 +- ...mmunication_signaling-server_index.js.html | 31 +- ...r_handlers_commons_enterAndWelcome.js.html | 104 +- ...age-handler_handlers_inRoomHandler.js.html | 2 +- ...iationState_helpers_processNewPeer.js.html | 323 ++ publish/latest/gzip/skylink.complete.js | Bin 212400 -> 213458 bytes publish/latest/gzip/skylink.complete.min.js | Bin 101749 -> 102513 bytes .../latest/gzip/skylink.complete.min.umd.js | Bin 102006 -> 102756 bytes publish/latest/gzip/skylink.complete.umd.js | Bin 217692 -> 218739 bytes publish/latest/skylink.complete.js | 2785 +++++++++-------- publish/latest/skylink.complete.min.js | 10 +- publish/latest/skylink.complete.min.umd.js | 6 +- publish/latest/skylink.complete.umd.js | 2785 +++++++++-------- 234 files changed, 10738 insertions(+), 9616 deletions(-) create mode 100644 docs/server-communication_signaling-server_negotiationState_helpers_processNewPeer.js.html delete mode 100644 publish/2.3.2/gzip/skylink.complete.js delete mode 100644 publish/2.3.2/gzip/skylink.complete.min.js delete mode 100644 publish/2.3.2/gzip/skylink.complete.min.umd.js delete mode 100644 publish/2.3.2/gzip/skylink.complete.umd.js delete mode 100644 publish/2.3.2/skylink.complete.min.js delete mode 100644 publish/2.3.2/skylink.complete.min.umd.js rename publish/{2.3.2 => 2.4.0}/demos/collection/README.md (100%) rename publish/{2.3.2 => 2.4.0}/demos/collection/assets/imgs/black.png (100%) rename publish/{2.3.2 => 2.4.0}/demos/collection/assets/imgs/favicon.ico (100%) rename publish/{2.3.2 => 2.4.0}/demos/collection/assets/imgs/no_profile.jpg (100%) rename publish/{2.3.2 => 2.4.0}/demos/collection/assets/imgs/skylinkjs.svg (100%) rename publish/{2.3.2 => 2.4.0}/demos/collection/assets/imgs/stripes.png (100%) rename publish/{2.3.2 => 2.4.0}/demos/collection/assets/imgs/user.png (100%) rename publish/{2.3.2 => 2.4.0}/demos/collection/assets/videos/sampleVideo_10.mp4 (100%) rename publish/{2.3.2 => 2.4.0}/demos/collection/assets/videos/sampleVideo_30.mp4 (100%) rename publish/{2.3.2 => 2.4.0}/demos/collection/audio-call/index.html (100%) rename publish/{2.3.2 => 2.4.0}/demos/collection/audio-call/main.js (100%) rename publish/{2.3.2 => 2.4.0}/demos/collection/chat/chat.css (100%) rename publish/{2.3.2 => 2.4.0}/demos/collection/chat/index.html (100%) rename publish/{2.3.2 => 2.4.0}/demos/collection/chat/main.js (100%) rename publish/{2.3.2 => 2.4.0}/demos/collection/config.example.js (100%) rename publish/{2.3.2 => 2.4.0}/demos/collection/css/main.css (100%) rename publish/{2.3.2 => 2.4.0}/demos/collection/index.html (100%) rename publish/{2.3.2 => 2.4.0}/demos/collection/kitchensink/eventManager.js (100%) rename publish/{2.3.2 => 2.4.0}/demos/collection/kitchensink/index.html (100%) rename publish/{2.3.2 => 2.4.0}/demos/collection/kitchensink/kitchensink.css (100%) rename publish/{2.3.2 => 2.4.0}/demos/collection/kitchensink/main.js (100%) rename publish/{2.3.2 => 2.4.0}/demos/collection/socket.io.js (100%) rename publish/{2.3.2 => 2.4.0}/demos/collection/video-call/index.html (100%) rename publish/{2.3.2 => 2.4.0}/demos/collection/video-call/main.js (100%) rename publish/{2.3.2 => 2.4.0}/docs/Reconnection.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/Skylink.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/SkylinkConstants.html (99%) rename publish/{2.3.2 => 2.4.0}/docs/SkylinkEvents.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/SkylinkLogger.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/compatibility_ice-connection.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/compatibility_peer-connection.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/constants.js.html (99%) rename publish/{2.3.2 => 2.4.0}/docs/documentation_reconnection.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/documentation_typedefs.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/features_messaging_encrypted-messaging_index.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/features_rtmp_index.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/features_screen-sharing_index.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/fonts/OpenSans-Bold-webfont.eot (100%) rename publish/{2.3.2 => 2.4.0}/docs/fonts/OpenSans-Bold-webfont.svg (100%) rename publish/{2.3.2 => 2.4.0}/docs/fonts/OpenSans-Bold-webfont.woff (100%) rename publish/{2.3.2 => 2.4.0}/docs/fonts/OpenSans-BoldItalic-webfont.eot (100%) rename publish/{2.3.2 => 2.4.0}/docs/fonts/OpenSans-BoldItalic-webfont.svg (100%) rename publish/{2.3.2 => 2.4.0}/docs/fonts/OpenSans-BoldItalic-webfont.woff (100%) rename publish/{2.3.2 => 2.4.0}/docs/fonts/OpenSans-Italic-webfont.eot (100%) rename publish/{2.3.2 => 2.4.0}/docs/fonts/OpenSans-Italic-webfont.svg (100%) rename publish/{2.3.2 => 2.4.0}/docs/fonts/OpenSans-Italic-webfont.woff (100%) rename publish/{2.3.2 => 2.4.0}/docs/fonts/OpenSans-Light-webfont.eot (100%) rename publish/{2.3.2 => 2.4.0}/docs/fonts/OpenSans-Light-webfont.svg (100%) rename publish/{2.3.2 => 2.4.0}/docs/fonts/OpenSans-Light-webfont.woff (100%) rename publish/{2.3.2 => 2.4.0}/docs/fonts/OpenSans-LightItalic-webfont.eot (100%) rename publish/{2.3.2 => 2.4.0}/docs/fonts/OpenSans-LightItalic-webfont.svg (100%) rename publish/{2.3.2 => 2.4.0}/docs/fonts/OpenSans-LightItalic-webfont.woff (100%) rename publish/{2.3.2 => 2.4.0}/docs/fonts/OpenSans-Regular-webfont.eot (100%) rename publish/{2.3.2 => 2.4.0}/docs/fonts/OpenSans-Regular-webfont.svg (100%) rename publish/{2.3.2 => 2.4.0}/docs/fonts/OpenSans-Regular-webfont.woff (100%) rename publish/{2.3.2 => 2.4.0}/docs/fonts/OpenSans-Semibold-webfont.eot (100%) rename publish/{2.3.2 => 2.4.0}/docs/fonts/OpenSans-Semibold-webfont.svg (100%) rename publish/{2.3.2 => 2.4.0}/docs/fonts/OpenSans-Semibold-webfont.ttf (100%) rename publish/{2.3.2 => 2.4.0}/docs/fonts/OpenSans-Semibold-webfont.woff (100%) rename publish/{2.3.2 => 2.4.0}/docs/fonts/OpenSans-SemiboldItalic-webfont.eot (100%) rename publish/{2.3.2 => 2.4.0}/docs/fonts/OpenSans-SemiboldItalic-webfont.svg (100%) rename publish/{2.3.2 => 2.4.0}/docs/fonts/OpenSans-SemiboldItalic-webfont.ttf (100%) rename publish/{2.3.2 => 2.4.0}/docs/fonts/OpenSans-SemiboldItalic-webfont.woff (100%) rename publish/{2.3.2 => 2.4.0}/docs/global.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/ice-connection_index.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/icons/home.svg (100%) rename publish/{2.3.2 => 2.4.0}/docs/icons/search.svg (100%) rename publish/{2.3.2 => 2.4.0}/docs/index.html (99%) rename publish/{2.3.2 => 2.4.0}/docs/index.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/logger_index.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/media-stream_helpers_getStreamSources.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/media-stream_helpers_getStreams.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/media-stream_helpers_muteStreams.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/media-stream_helpers_onStreamAccessError.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/media-stream_helpers_prepMediaAccessRequest.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/media-stream_helpers_sendStream.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/media-stream_helpers_stopStream_dispatchEvents.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/media-stream_helpers_stopStream_dispatchOnLocalStreamEnded.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/media-stream_helpers_stopStream_removeTracks.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/media-stream_index.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/models_api-response.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/models_skylink-room.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/models_skylink-state.js.html (57%) rename publish/{2.3.2 => 2.4.0}/docs/models_skylink-user.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/peer-connection_helpers_createAnswer.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/peer-connection_helpers_createOffer.js.html (99%) rename publish/{2.3.2 => 2.4.0}/docs/peer-connection_helpers_data-channel_callbacks_onbufferedamountlow.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/peer-connection_helpers_data-channel_callbacks_onclose.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/peer-connection_helpers_data-channel_callbacks_onerror.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/peer-connection_helpers_data-channel_callbacks_onmessage.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/peer-connection_helpers_data-channel_callbacks_onopen.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/peer-connection_helpers_data-channel_closeDataChannel.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/peer-connection_helpers_data-channel_createDataChannel.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/peer-connection_helpers_data-channel_getDataChannelBuffer.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/peer-connection_helpers_data-channel_refreshDataChannel.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/peer-connection_helpers_data-channel_sendP2PMessage.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/peer-connection_helpers_peer-addition_addPeer.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/peer-connection_helpers_peer-addition_callbacks_ondatachannel.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/peer-connection_helpers_peer-addition_callbacks_onicecandidate.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/peer-connection_helpers_peer-addition_callbacks_oniceconnectionstatechange.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/peer-connection_helpers_peer-addition_callbacks_onicegatheringstatechange.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/peer-connection_helpers_peer-addition_callbacks_onremovetrack.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/peer-connection_helpers_peer-addition_callbacks_onsenderadded.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/peer-connection_helpers_peer-addition_callbacks_onsignalingstatechange.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/peer-connection_helpers_peer-addition_callbacks_ontrack.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/peer-connection_helpers_peer-addition_createPeerConnection.js.html (99%) rename publish/{2.3.2 => 2.4.0}/docs/peer-connection_helpers_refresh-connection_refreshConnection.js.html (99%) rename publish/{2.3.2 => 2.4.0}/docs/peer-connection_helpers_refresh-connection_refreshPeerConnection.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/peer-connection_helpers_refresh-connection_restartMCUConnection.js.html (98%) rename publish/{2.3.2 => 2.4.0}/docs/peer-connection_helpers_refresh-connection_restartPeerConnection.js.html (98%) rename publish/{2.3.2 => 2.4.0}/docs/peer-connection_helpers_sendP2PMessage.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/peer-connection_helpers_signalingEndOfCandidates.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/peer-connection_helpers_statistics_index.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/peer-connection_helpers_statistics_parsers_parseAudio.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/peer-connection_helpers_statistics_parsers_parseCertificates.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/peer-connection_helpers_statistics_parsers_parseSelectedCandidatePair.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/peer-connection_helpers_statistics_parsers_parseVideo.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/peer-connection_helpers_statistics_parsers_tabulateStats.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/peer-connection_index.js.html (99%) rename publish/{2.3.2 => 2.4.0}/docs/peer-data_helpers_getPeersCustomSettings.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/peer-data_helpers_getPeersStreams.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/peer-data_index.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/peer-media_index.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/peer-privileged_index.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/public_index.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/room_getRoomInfo.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/scripts/linenumber.js (100%) rename publish/{2.3.2 => 2.4.0}/docs/scripts/pagelocation.js (100%) rename publish/{2.3.2 => 2.4.0}/docs/server-communication_api-server_defaultOptions.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/server-communication_signaling-server_index.js.html (96%) rename publish/{2.3.2 => 2.4.0}/docs/server-communication_signaling-server_message-builder_builders_getPeerListMessage.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/server-communication_signaling-server_message-builder_builders_setUserDataMessage.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/server-communication_signaling-server_message-builder_builders_streamMessage.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/server-communication_signaling-server_message-handler_handlers_candidateHandler.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/server-communication_signaling-server_message-handler_handlers_commons_enterAndWelcome.js.html (77%) rename publish/{2.3.2 => 2.4.0}/docs/server-communication_signaling-server_message-handler_handlers_commons_offerAndAnswer.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/server-communication_signaling-server_message-handler_handlers_commons_processPeer.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/server-communication_signaling-server_message-handler_handlers_getPeerListHandler.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/server-communication_signaling-server_message-handler_handlers_inRoomHandler.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/server-communication_signaling-server_message-handler_handlers_introduceErrorHandler.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/server-communication_signaling-server_message-handler_handlers_storedMessagesHandler.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/server-communication_signaling-server_message-handler_handlers_streamHandler.js.html (100%) create mode 100644 publish/2.4.0/docs/server-communication_signaling-server_negotiationState_helpers_processNewPeer.js.html rename publish/{2.3.2 => 2.4.0}/docs/skylink-events_candidate-events.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/skylink-events_data-transfer-events.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/skylink-events_datachannel-events.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/skylink-events_index.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/skylink-events_init-events.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/skylink-events_logger-events.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/skylink-events_media-events.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/skylink-events_peer-events.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/skylink-events_peer-handshake-events.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/skylink-events_room-events.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/skylink-events_socket-events.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/skylink-events_stream-events.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/skylink-states.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/styles/collapse.css (100%) rename publish/{2.3.2 => 2.4.0}/docs/styles/jsdoc-default.css (100%) rename publish/{2.3.2 => 2.4.0}/docs/styles/prettify-jsdoc.css (100%) rename publish/{2.3.2 => 2.4.0}/docs/styles/prettify-tomorrow.css (100%) rename publish/{2.3.2 => 2.4.0}/docs/typedefs.js.html (100%) rename publish/{2.3.2 => 2.4.0}/docs/utils_helpers.js.html (100%) create mode 100644 publish/2.4.0/gzip/skylink.complete.js create mode 100644 publish/2.4.0/gzip/skylink.complete.min.js create mode 100644 publish/2.4.0/gzip/skylink.complete.min.umd.js create mode 100644 publish/2.4.0/gzip/skylink.complete.umd.js rename publish/{2.3.2 => 2.4.0}/skylink.complete.js (97%) create mode 100644 publish/2.4.0/skylink.complete.min.js create mode 100644 publish/2.4.0/skylink.complete.min.umd.js rename publish/{2.3.2 => 2.4.0}/skylink.complete.umd.js (97%) create mode 100644 publish/2.x/docs/server-communication_signaling-server_negotiationState_helpers_processNewPeer.js.html create mode 100644 publish/latest/docs/server-communication_signaling-server_negotiationState_helpers_processNewPeer.js.html diff --git a/docs/SkylinkConstants.html b/docs/SkylinkConstants.html index 1a02dacd6..bfd3ae278 100644 --- a/docs/SkylinkConstants.html +++ b/docs/SkylinkConstants.html @@ -4599,7 +4599,7 @@
Properties:
@@ -5073,7 +5073,7 @@
Properties:
diff --git a/docs/constants.js.html b/docs/constants.js.html index 5f963c304..e0ec16a40 100644 --- a/docs/constants.js.html +++ b/docs/constants.js.html @@ -1920,6 +1920,7 @@

ASYNC_MESSAGING: 'ASYNC MESSAGING', ENCRYPTED_MESSAGING: 'ENCRYPTED MESSAGING', STATS: 'STATS', + NEGOTIATION: 'NEGOTIATION', }; /** @@ -2166,6 +2167,28 @@

SOCKET: 'SOCKET', }; +/** + * The negotiation states for the negotiation state machine + * @type {{WELCOMING: string, LOCAL_OFFER_SENT: string, REMOTE_OFFER_SET: string, REMOTE_ANSWER_RECEIVED: string, LOCAL_OFFER_SET: string, REMOTE_OFFER_RECEIVED: string, LOCAL_ANSWER_SET: string, ENTERING: string, NEGOTIATED: string, REMOTE_ANSWER_SET: string}} + * @private + * @constant + * @readonly + * @memberOf SkylinkConstants + * @since 2.3.3 + */ +export const NEGOTIATION_STATES = { + ENTERING: 'entering', + WELCOMING: 'welcoming', + LOCAL_OFFER_SENT: 'localOfferSent', + LOCAL_OFFER_SET: ' localOfferSet', + REMOTE_OFFER_RECEIVED: 'remoteOfferReceived', + REMOTE_ANSWER_RECEIVED: 'remoteAnswerReceived', + REMOTE_OFFER_SET: 'remoteOfferSet', + LOCAL_ANSWER_SET: 'localAnswerSet', + REMOTE_ANSWER_SET: 'remoteAnswerSet', + NEGOTIATED: 'negotiated', +}; + export const EVENTS = SkylinkEventsConstants; diff --git a/docs/index.html b/docs/index.html index 6777bc58e..2e09a6347 100644 --- a/docs/index.html +++ b/docs/index.html @@ -93,7 +93,7 @@

Classes