Skip to content

Commit

Permalink
Merge pull request #7404 from capilkey/better-transfer-detect
Browse files Browse the repository at this point in the history
Improved audio connect and transfer
  • Loading branch information
ffdixon committed May 9, 2019
2 parents 056ef6e + 2bee179 commit 799354b
Showing 1 changed file with 52 additions and 47 deletions.
99 changes: 52 additions & 47 deletions bigbluebutton-html5/imports/api/audio/client/bridge/sip.js
@@ -1,5 +1,3 @@
import VoiceUsers from '/imports/api/voice-users';
import { Tracker } from 'meteor/tracker';
import browser from 'browser-detect';
import BaseAudioBridge from './base';
import logger from '/imports/startup/client/logger';
Expand All @@ -12,7 +10,6 @@ const CALL_HANGUP_TIMEOUT = MEDIA.callHangupTimeout;
const CALL_HANGUP_MAX_RETRIES = MEDIA.callHangupMaximumRetries;
const ICE_NEGOTIATION_FAILED = ['iceConnectionFailed'];
const CALL_CONNECT_TIMEOUT = 15000;
const CALL_CONNECT_NOTIFICATION_TIMEOUT = 1000;
const ICE_NEGOTIATION_TIMEOUT = 20000;

export default class SIPBridge extends BaseAudioBridge {
Expand All @@ -39,6 +36,14 @@ export default class SIPBridge extends BaseAudioBridge {
this.hostname = window.document.location.hostname;
}

static parseDTMF(message) {
const parse = message.match(/Signal=(.)/);
if (parse && parse.length === 2) {
return parse[1];
}
return '';
}

joinAudio({ isListenOnly, extension, inputStream }, managerCallback) {
return new Promise((resolve, reject) => {
const callExtension = extension ? `${extension}${this.userData.voiceBridge}` : this.userData.voiceBridge;
Expand Down Expand Up @@ -84,47 +89,29 @@ export default class SIPBridge extends BaseAudioBridge {

transferCall(onTransferSuccess) {
return new Promise((resolve, reject) => {
let trackerControl = null;
let transferAttemptCount = 0;

const timeout = setInterval(() => {
// There's a bug with FS and FF where the connection can take awhile to negotiate. I'm
// adding retries if they're on that to mitigate the issue. Refer to the following bug
// for more info, https://freeswitch.org/jira/browse/FS-11661.
if (browser().name === 'firefox' && transferAttemptCount < 3) {
transferAttemptCount++;
this.currentSession.dtmf(1);
} else {
clearInterval(timeout);
trackerControl.stop();
logger.error({ logCode: 'sip_js_transfer_timed_out' }, 'Timeout on transfering from echo test to conference');
this.callback({
status: this.baseCallStates.failed,
error: 1008,
bridgeError: 'Timeout on call transfer',
});
reject(this.baseErrorCodes.REQUEST_TIMEOUT);
}
clearInterval(timeout);
logger.error({ logCode: 'sip_js_transfer_timed_out' }, 'Timeout on transfering from echo test to conference');
this.callback({
status: this.baseCallStates.failed,
error: 1008,
bridgeError: 'Timeout on call transfer',
});
reject(this.baseErrorCodes.REQUEST_TIMEOUT);
}, CALL_TRANSFER_TIMEOUT);

// This is is the call transfer code ask @chadpilkey
this.currentSession.dtmf(1);

Tracker.autorun((c) => {
trackerControl = c;
const selector = { meetingId: this.userData.meetingId, intId: this.userData.userId };
const query = VoiceUsers.find(selector);

query.observeChanges({
changed: (id, fields) => {
if (fields.joined) {
clearInterval(timeout);
onTransferSuccess();
c.stop();
resolve();
}
},
});
this.currentSession.on('dtmf', (event) => {
if (event.body && (typeof event.body === 'string')) {
const key = SIPBridge.parseDTMF(event.body);
if (key === '7') {
clearInterval(timeout);
onTransferSuccess();
resolve();
}
}
});
});
}
Expand Down Expand Up @@ -271,6 +258,7 @@ export default class SIPBridge extends BaseAudioBridge {
const { mediaHandler } = currentSession;

this.connectionCompleted = false;
this.inEcho = false;

let connectionCompletedEvents = ['iceConnectionCompleted', 'iceConnectionConnected'];
// Edge sends a connected first and then a completed, but the call isn't ready until
Expand All @@ -280,6 +268,13 @@ export default class SIPBridge extends BaseAudioBridge {
connectionCompletedEvents = ['iceConnectionCompleted'];
}

const checkIfCallReady = () => {
if (this.connectionCompleted && this.inEcho) {
this.callback({ status: this.baseCallStates.started });
resolve();
}
};

// Sometimes FreeSWITCH just won't respond with anything and hangs. This timeout is to
// avoid that issue
const callTimeout = setTimeout(() => {
Expand Down Expand Up @@ -322,15 +317,8 @@ export default class SIPBridge extends BaseAudioBridge {
clearTimeout(iceNegotiationTimeout);
connectionCompletedEvents.forEach(e => mediaHandler.off(e, handleConnectionCompleted));
this.connectionCompleted = true;
// We have to delay notifying that the call is connected because it is sometimes not
// actually ready and if the user says "Yes they can hear themselves" too quickly the
// B-leg transfer will fail
const that = this;
const notificationTimeout = (browser().name === 'firefox' ? CALL_CONNECT_NOTIFICATION_TIMEOUT : 0);
setTimeout(() => {
that.callback({ status: that.baseCallStates.started });
resolve();
}, notificationTimeout);

checkIfCallReady();
};
connectionCompletedEvents.forEach(e => mediaHandler.on(e, handleConnectionCompleted));

Expand Down Expand Up @@ -361,6 +349,11 @@ export default class SIPBridge extends BaseAudioBridge {
currentSession.on('terminated', handleSessionTerminated);

const handleIceNegotiationFailed = (peer) => {
if (this.connectionCompleted) {
logger.error({ logCode: 'sipjs_ice_failed_after' }, 'ICE connection failed after success');
} else {
logger.error({ logCode: 'sipjs_ice_failed_before' }, 'ICE connection failed before success');
}
clearTimeout(callTimeout);
clearTimeout(iceNegotiationTimeout);
ICE_NEGOTIATION_FAILED.forEach(e => mediaHandler.off(e, handleIceNegotiationFailed));
Expand All @@ -387,6 +380,18 @@ export default class SIPBridge extends BaseAudioBridge {
};
['iceConnectionClosed'].forEach(e => mediaHandler.on(e, handleIceConnectionTerminated));

const inEchoDTMF = (event) => {
if (event.body && typeof event.body === 'string') {
const dtmf = SIPBridge.parseDTMF(event.body);
if (dtmf === '0') {
this.inEcho = true;
checkIfCallReady();
}
}
currentSession.off('dtmf', inEchoDTMF);
};
currentSession.on('dtmf', inEchoDTMF);

this.currentSession = currentSession;
});
}
Expand Down

0 comments on commit 799354b

Please sign in to comment.