- /**
- * Function that handles the Peer connection gathered ICE candidate to be sent.
- * @method _onIceCandidate
- * @private
- * @for Skylink
- * @since 0.1.0
- */
- Skylink.prototype._onIceCandidate = function(targetMid, candidate) {
- var self = this;
- var pc = self._peerConnections[targetMid];
-
- if (!pc) {
- log.warn([targetMid, 'RTCIceCandidate', null, 'Ignoring of ICE candidate event as ' +
- 'Peer connection does not exists ->'], candidate);
- return;
- }
-
- if (candidate.candidate) {
- if (!pc.gathering) {
- log.log([targetMid, 'RTCIceCandidate', null, 'ICE gathering has started.']);
-
- pc.gathering = true;
- pc.gathered = false;
-
- self._handleIceGatheringStats('gathering', targetMid, false);
- self._trigger('candidateGenerationState', self.CANDIDATE_GENERATION_STATE.GATHERING, targetMid);
- }
-
- var candidateType = candidate.candidate.split(' ')[7];
-
- log.debug([targetMid, 'RTCIceCandidate', candidateType, 'Generated ICE candidate ->'], candidate);
-
- if (candidateType === 'endOfCandidates' || !(self._peerConnections[targetMid] &&
- self._peerConnections[targetMid].localDescription && self._peerConnections[targetMid].localDescription.sdp &&
- self._peerConnections[targetMid].localDescription.sdp.indexOf('\r\na=mid:' + candidate.sdpMid + '\r\n') > -1)) {
- log.warn([targetMid, 'RTCIceCandidate', candidateType, 'Dropping of sending ICE candidate ' +
- 'end-of-candidates signal or unused ICE candidates to prevent errors ->'], candidate);
- self._handleIceCandidateStats('dropped', targetMid, null, candidate);
- return;
- }
-
- if (self._initOptions.filterCandidatesType[candidateType]) {
- if (!(self._hasMCU && self._initOptions.forceTURN)) {
- log.warn([targetMid, 'RTCIceCandidate', candidateType, 'Dropping of sending ICE candidate as ' +
- 'it matches ICE candidate filtering flag ->'], candidate);
- self._handleIceCandidateStats('dropped', targetMid, null, candidate);
- return;
- }
-
- log.warn([targetMid, 'RTCIceCandidate', candidateType, 'Not dropping of sending ICE candidate as ' +
- 'TURN connections are enforced as MCU is present (and act as a TURN itself) so filtering of ICE candidate ' +
- 'flags are not honoured ->'], candidate);
- }
-
- if (!self._gatheredCandidates[targetMid]) {
- self._gatheredCandidates[targetMid] = {
- sending: { host: [], srflx: [], relay: [] },
- receiving: { host: [], srflx: [], relay: [] }
- };
- }
-
- self._gatheredCandidates[targetMid].sending[candidateType].push({
- sdpMid: candidate.sdpMid,
- sdpMLineIndex: candidate.sdpMLineIndex,
- candidate: candidate.candidate
- });
-
- if (!self._initOptions.enableIceTrickle) {
- log.warn([targetMid, 'RTCIceCandidate', candidateType, 'Dropping of sending ICE candidate as ' +
- 'trickle ICE is disabled ->'], candidate);
- self._handleIceCandidateStats('non_trickle', targetMid, null, candidate);
- return;
- }
-
- log.debug([targetMid, 'RTCIceCandidate', candidateType, 'Sending ICE candidate ->'], candidate);
-
- self._sendChannelMessage({
- type: self._SIG_MESSAGE_TYPE.CANDIDATE,
- label: candidate.sdpMLineIndex,
- id: candidate.sdpMid,
- candidate: candidate.candidate,
- mid: self._user.sid,
- target: targetMid,
- rid: self._room.id
- });
- self._handleIceCandidateStats('received', targetMid, null, candidate);
-
- } else {
- log.log([targetMid, 'RTCIceCandidate', null, 'ICE gathering has completed.']);
-
- if (pc.gathered) {
- return;
- }
-
- pc.gathering = false;
- pc.gathered = true;
-
- self._handleIceGatheringStats('complete', targetMid, false);
- self._trigger('candidateGenerationState', self.CANDIDATE_GENERATION_STATE.COMPLETED, targetMid);
-
- // Disable Ice trickle option
- if (!self._initOptions.enableIceTrickle) {
- var sessionDescription = self._peerConnections[targetMid].localDescription;
-
- if (!(sessionDescription && sessionDescription.type && sessionDescription.sdp)) {
- log.warn([targetMid, 'RTCSessionDescription', null, 'Not sending any session description after ' +
- 'ICE gathering completed as it is not present.']);
- return;
- }
-
- // a=end-of-candidates should present in non-trickle ICE connections so no need to send endOfCandidates message
- self._sendChannelMessage({
- type: sessionDescription.type,
- sdp: self._renderSDPOutput(targetMid, sessionDescription),
- mid: self._user.sid,
- userInfo: self._getUserInfo(targetMid),
- target: targetMid,
- rid: self._room.id
- });
- } else if (self._gatheredCandidates[targetMid]) {
- var sendEndOfCandidates = function() {
- if (self._gatheredCandidates[targetMid] && self._gatheredCandidates[targetMid].sending) {
- self._sendChannelMessage({
- type: self._SIG_MESSAGE_TYPE.END_OF_CANDIDATES,
- noOfExpectedCandidates: self._gatheredCandidates[targetMid].sending.srflx.length +
- self._gatheredCandidates[targetMid].sending.host.length +
- self._gatheredCandidates[targetMid].sending.relay.length,
- mid: self._user.sid,
- target: targetMid,
- rid: self._room.id
- });
- }
- };
- setTimeout(sendEndOfCandidates, 6000);
- }
- }
- };
-
- /**
- * Function that buffers the Peer connection ICE candidate when received
- * before remote session description is received and set.
- * @method _addIceCandidateToQueue
- * @private
- * @for Skylink
- * @since 0.5.2
- */
- Skylink.prototype._addIceCandidateToQueue = function(targetMid, canId, candidate) {
- var candidateType = candidate.candidate.split(' ')[7];
-
- log.debug([targetMid, 'RTCIceCandidate', canId + ':' + candidateType, 'Buffering ICE candidate.']);
-
- this._handleIceCandidateStats('buffered', targetMid, canId, candidate);
- this._trigger('candidateProcessingState', this.CANDIDATE_PROCESSING_STATE.BUFFERED,
- targetMid, canId, candidateType, {
- candidate: candidate.candidate,
- sdpMid: candidate.sdpMid,
- sdpMLineIndex: candidate.sdpMLineIndex
- }, null);
-
- this._peerCandidatesQueue[targetMid] = this._peerCandidatesQueue[targetMid] || [];
- this._peerCandidatesQueue[targetMid].push([canId, candidate]);
- };
-
- /**
- * Function that adds all the Peer connection buffered ICE candidates received.
- * This should be called only after the remote session description is received and set.
- * @method _addIceCandidateFromQueue
- * @private
- * @for Skylink
- * @since 0.5.2
- */
- Skylink.prototype._addIceCandidateFromQueue = function(targetMid) {
- this._peerCandidatesQueue[targetMid] = this._peerCandidatesQueue[targetMid] || [];
-
- for (var i = 0; i < this._peerCandidatesQueue[targetMid].length; i++) {
- var canArray = this._peerCandidatesQueue[targetMid][i];
-
- if (canArray) {
- var candidateType = canArray[1].candidate.split(' ')[7];
-
- log.debug([targetMid, 'RTCIceCandidate', canArray[0] + ':' + candidateType, 'Adding buffered ICE candidate.']);
-
- this._addIceCandidate(targetMid, canArray[0], canArray[1]);
- } else if (this._peerConnections[targetMid] &&
- this._peerConnections[targetMid].signalingState !== this.PEER_CONNECTION_STATE.CLOSED &&
- AdapterJS && !this._isLowerThanVersion(AdapterJS.VERSION, '0.14.0')) {
- try {
- this._peerConnections[targetMid].addIceCandidate(null);
- log.debug([targetMid, 'RTCPeerConnection', null, 'Signaling of end-of-candidates remote ICE gathering.']);
- } catch (error) {
- log.error([targetMid, 'RTCPeerConnection', null, 'Failed signaling of end-of-candidates remote ICE gathering.']);
- }
- }
- }
-
- delete this._peerCandidatesQueue[targetMid];
-
- this._signalingEndOfCandidates(targetMid);
- };
-
- /**
- * Function that adds the ICE candidate to Peer connection.
- * @method _addIceCandidate
- * @private
- * @for Skylink
- * @since 0.6.16
- */
- Skylink.prototype._addIceCandidate = function (targetMid, canId, candidate) {
- var self = this;
- var candidateType = candidate.candidate.split(' ')[7];
-
- var onSuccessCbFn = function () {
- log.log([targetMid, 'RTCIceCandidate', canId + ':' + candidateType,
- 'Added ICE candidate successfully.']);
- self._handleIceCandidateStats('process_success', targetMid, canId, candidate);
- self._trigger('candidateProcessingState', self.CANDIDATE_PROCESSING_STATE.PROCESS_SUCCESS,
- targetMid, canId, candidateType, {
- candidate: candidate.candidate,
- sdpMid: candidate.sdpMid,
- sdpMLineIndex: candidate.sdpMLineIndex
- }, null);
- };
-
- var onErrorCbFn = function (error) {
- log.error([targetMid, 'RTCIceCandidate', canId + ':' + candidateType,
- 'Failed adding ICE candidate ->'], error);
- self._handleIceCandidateStats('process_failed', targetMid, canId, candidate, error);
- self._trigger('candidateProcessingState', self.CANDIDATE_PROCESSING_STATE.PROCESS_ERROR,
- targetMid, canId, candidateType, {
- candidate: candidate.candidate,
- sdpMid: candidate.sdpMid,
- sdpMLineIndex: candidate.sdpMLineIndex
- }, error);
- };
-
- log.debug([targetMid, 'RTCIceCandidate', canId + ':' + candidateType, 'Adding ICE candidate.']);
-
- self._handleIceCandidateStats('processing', targetMid, canId, candidate);
- self._trigger('candidateProcessingState', self.CANDIDATE_PROCESSING_STATE.PROCESSING,
- targetMid, canId, candidateType, {
- candidate: candidate.candidate,
- sdpMid: candidate.sdpMid,
- sdpMLineIndex: candidate.sdpMLineIndex
- }, null);
-
- if (!(self._peerConnections[targetMid] &&
- self._peerConnections[targetMid].signalingState !== self.PEER_CONNECTION_STATE.CLOSED &&
- self._peerConnections[targetMid].remoteDescription &&
- self._peerConnections[targetMid].remoteDescription.sdp &&
- self._peerConnections[targetMid].remoteDescription.sdp.indexOf('\r\na=mid:' + candidate.sdpMid + '\r\n') > -1)) {
- log.warn([targetMid, 'RTCIceCandidate', canId + ':' + candidateType, 'Dropping ICE candidate ' +
- 'as Peer connection does not exists or is closed']);
- self._handleIceCandidateStats('process_failed', targetMid, canId, candidate, 'Peer connection does not exist');
- self._trigger('candidateProcessingState', self.CANDIDATE_PROCESSING_STATE.DROPPED,
- targetMid, canId, candidateType, {
- candidate: candidate.candidate,
- sdpMid: candidate.sdpMid,
- sdpMLineIndex: candidate.sdpMLineIndex
- }, new Error('Failed processing ICE candidate as Peer connection does not exists or is closed.'));
- return;
- }
-
- try {
- self._peerConnections[targetMid].addIceCandidate(candidate, onSuccessCbFn, onErrorCbFn);
- } catch (error) {
- onErrorCbFn(error);
- }
- };
-