diff --git a/lib/session/adulting-call-session.js b/lib/session/adulting-call-session.js index 0b9396f4..652272e0 100644 --- a/lib/session/adulting-call-session.js +++ b/lib/session/adulting-call-session.js @@ -53,16 +53,24 @@ class AdultingCallSession extends CallSession { } _callerHungup() { + this._hangup('caller'); + } + + _jambonzHangup() { + this._hangup(); + } + + _hangup(terminatedBy = 'jambonz') { if (this.dlg.connectTime) { const duration = moment().diff(this.dlg.connectTime, 'seconds'); - this.rootSpan.setAttributes({'call.termination': 'hangup by caller'}); - this.callInfo.callTerminationBy = 'caller'; + this.rootSpan.setAttributes({'call.termination': `hangup by ${terminatedBy}`}); + this.callInfo.callTerminationBy = terminatedBy; this.emit('callStatusChange', { callStatus: CallStatus.Completed, duration }); } - this.logger.info('InboundCallSession: caller hung up'); + this.logger.info(`InboundCallSession: ${terminatedBy} hung up`); this._callReleased(); this.req.removeAllListeners('cancel'); } diff --git a/lib/session/call-session.js b/lib/session/call-session.js index 468d0181..a780f26e 100644 --- a/lib/session/call-session.js +++ b/lib/session/call-session.js @@ -1831,6 +1831,14 @@ Duration=${duration} ` assert(false, 'subclass responsibility to override this method'); } + /** + * called when the jambonz has hung up. Provided for subclasses to override + * in order to apply logic at this point if needed. + */ + _jambonzHangup() { + assert(false, 'subclass responsibility to override this method'); + } + /** * get a media server to use for this call */ @@ -2259,7 +2267,7 @@ Duration=${duration} ` this.logger.debug(`CallSession:_startActionHookNoResponseTimer ${options.noResponseTimeoutMs}`); this._actionHookNoResponseTimer = setTimeout(() => { if (this._actionHookDelayRetryCount >= options.retries) { - this._callerHungup(); + this._jambonzHangup(); } const verb = options.actions[this._actionHookDelayRetryCount % options.actions.length]; // Inject verb to main stack @@ -2297,7 +2305,7 @@ Duration=${duration} ` this.logger.debug(`CallSession:_startActionHookNoResponseGiveUpTimer ${options.noResponseGiveUpTimeoutMs}`); this._actionHookNoResponseGiveUpTimer = setTimeout(() => { this.logger.debug('CallSession:_startActionHookNoResponseGiveUpTimer Timeout'); - this._callerHungup(); + this._jambonzHangup(); this._actionHookNoResponseGiveUpTimer = null; }, options.noResponseGiveUpTimeoutMs); } diff --git a/lib/session/confirm-call-session.js b/lib/session/confirm-call-session.js index 462716e3..2630982d 100644 --- a/lib/session/confirm-call-session.js +++ b/lib/session/confirm-call-session.js @@ -34,6 +34,9 @@ class ConfirmCallSession extends CallSession { _callerHungup() { } + _jambonzHangup() { + } + } diff --git a/lib/session/inbound-call-session.js b/lib/session/inbound-call-session.js index 8b2ae2f7..5deb3882 100644 --- a/lib/session/inbound-call-session.js +++ b/lib/session/inbound-call-session.js @@ -67,19 +67,27 @@ class InboundCallSession extends CallSession { * This is invoked when the caller hangs up, in order to calculate the call duration. */ _callerHungup() { + this._hangup('caller'); + } + + _jambonzHangup() { + this._hangup(); + } + + _hangup(terminatedBy = 'jambonz') { if (this.dlg === null) { - this.logger.info('InboundCallSession:_callerHungup - race condition, dlg cleared by app hangup'); + this.logger.info('InboundCallSession:_hangup - race condition, dlg cleared by app hangup'); return; } assert(this.dlg.connectTime); const duration = moment().diff(this.dlg.connectTime, 'seconds'); - this.rootSpan.setAttributes({'call.termination': 'hangup by caller'}); - this.callInfo.callTerminationBy = 'caller'; + this.rootSpan.setAttributes({'call.termination': `hangup by ${terminatedBy}`}); + this.callInfo.callTerminationBy = terminatedBy; this.emit('callStatusChange', { callStatus: CallStatus.Completed, duration }); - this.logger.info('InboundCallSession: caller hung up'); + this.logger.info(`InboundCallSession: ${terminatedBy} hung up`); this._callReleased(); this.req.removeAllListeners('cancel'); } diff --git a/lib/session/rest-call-session.js b/lib/session/rest-call-session.js index 73384c2b..afd5fbf2 100644 --- a/lib/session/rest-call-session.js +++ b/lib/session/rest-call-session.js @@ -49,13 +49,21 @@ class RestCallSession extends CallSession { * This is invoked when the called party hangs up, in order to calculate the call duration. */ _callerHungup() { + this._hangup('caller'); + } + + _jambonzHangup() { + this._hangup(); + } + + _hangup(terminatedBy = 'jamboz') { if (this.restDialTask) { this.restDialTask.turnOffAmd(); } - this.callInfo.callTerminationBy = 'caller'; + this.callInfo.callTerminationBy = terminatedBy; const duration = moment().diff(this.dlg.connectTime, 'seconds'); this.emit('callStatusChange', {callStatus: CallStatus.Completed, duration}); - this.logger.debug('RestCallSession: called party hung up'); + this.logger.debug(`RestCallSession: called party hung up by ${terminatedBy}`); this._callReleased(); } diff --git a/lib/tasks/gather.js b/lib/tasks/gather.js index 7d69b068..65e882eb 100644 --- a/lib/tasks/gather.js +++ b/lib/tasks/gather.js @@ -139,28 +139,27 @@ class TaskGather extends SttTask { this.logger.debug('Gather:exec - early hints match enabled'); } // actionHook delay - this._actionHookDelayEnabled = cs.actionHookDelayEnabled || !!this.actionHookDelayAction; - this._actionHookDelayActions = this.actionHookDelayAction && this.actionHookDelayAction.actions ? - this.actionHookDelayAction.actions : cs.actionHookDelayActions || []; - if (this._actionHookDelayEnabled && this._actionHookDelayActions.length > 0) { - this._actionHookNoResponseTimeout = (this.actionHookDelayAction && this.actionHookDelayAction.noResponseTimeout ? - this.actionHookDelayAction.noResponseTimeout : cs.actionHookNoResponseTimeout || 0) * 1000; + this._hookDelayEn = cs.actionHookDelayEnabled || !!this.actionHookDelayAction; - this._actionHookNoResponseGiveUpTimeout = (this.actionHookDelayAction && - this.actionHookDelayAction.noResponseGiveUpTimeout ? - this.actionHookDelayAction.noResponseGiveUpTimeout : cs.actionHookNoResponseGiveUpTimeout || 0) * 1000; + this._hookDelayActions = this.actionHookDelayAction?.actions || cs.actionHookDelayActions || []; - this._actionHookDelayRetries = this.actionHookDelayAction && this.actionHookDelayAction.retries ? - this.actionHookDelayAction.retries : cs.actionHookDelayRetries || 1; - this._actionHookDelayTryCount = 0; - this.actionHookDelayActionOptions = { - enabled: this._actionHookDelayEnabled, - actions: this._actionHookDelayActions, - noResponseTimeoutMs: this._actionHookNoResponseTimeout, - noResponseGiveUpTimeoutMs: this._actionHookNoResponseGiveUpTimeout, - retries: this._actionHookDelayRetries - }; - } + // Only enable NoResponseTimeout if there is _hookDelayActions + this._hookNoResponseTimeout = (this._hookDelayActions?.length ? + (this.actionHookDelayAction?.noResponseTimeout || cs.actionHookNoResponseTimeout || 0) + : 0) * 1000; + + this._hookNoResponseGiveUpTimeout = (this.actionHookDelayAction?.noResponseGiveUpTimeout || + cs.actionHookNoResponseGiveUpTimeout || 0) * 1000; + + this._hookDelayRetries = this.actionHookDelayAction?.retries || cs.actionHookDelayRetries || 1; + this._hookDelayRetryCount = 0; + this.hookDelayActionOpts = { + enabled: this._hookDelayEn, + actions: this._hookDelayActions, + noResponseTimeoutMs: this._hookNoResponseTimeout, + noResponseGiveUpTimeoutMs: this._hookNoResponseGiveUpTimeout, + retries: this._hookDelayRetries + }; const startListening = async(cs, ep) => { this._startTimer(); @@ -600,24 +599,24 @@ class TaskGather extends SttTask { } _startActionHookNoResponseTimer() { - assert(this._actionHookNoResponseTimeout > 0); + assert(this._hookNoResponseTimeout > 0); this._clearActionHookNoResponseTimer(); this.logger.debug('startActionHookNoResponseTimer'); this._actionHookNoResponseTimer = setTimeout(() => { - if (this._actionHookDelayTryCount >= this._actionHookDelayRetries) { + if (this._hookDelayRetryCount >= this._hookDelayRetries) { this._hangupCall(); return; } - const verb = this._actionHookDelayActions[this._actionHookDelayTryCount % this._actionHookDelayActions.length]; + const verb = this._hookDelayActions[this._hookDelayRetryCount % this._hookDelayActions.length]; if (verb.verb === 'say') { this._actionHookDelaySayAction(verb); } else if (verb.verb === 'play') { this._actionHookDelayPlayAction(verb); } - this._actionHookDelayTryCount++; + this._hookDelayRetryCount++; this._startActionHookNoResponseTimer(); - }, this._actionHookNoResponseTimeout); + }, this._hookNoResponseTimeout); } @@ -629,12 +628,12 @@ class TaskGather extends SttTask { } _startActionHookNoResponseGiveUpTimer() { - assert(this._actionHookNoResponseGiveUpTimeout > 0); + assert(this._hookNoResponseGiveUpTimeout > 0); this._clearActionHookNoResponseGiveUpTimer(); this.logger.debug('startActionHookNoResponseGiveUpTimer'); this._actionHookNoResponseGiveUpTimer = setTimeout(() => { this._hangupCall(); - }, this._actionHookNoResponseGiveUpTimeout); + }, this._hookNoResponseGiveUpTimeout); } _clearActionHookNoResponseGiveUpTimer() { @@ -994,11 +993,11 @@ class TaskGather extends SttTask { } // Enabled action Hook delay timer to applied actions - if (this._actionHookNoResponseTimeout > 0) { + if (this._hookNoResponseTimeout > 0) { this._startActionHookNoResponseTimer(); } - if (this._actionHookNoResponseGiveUpTimeout > 0) { + if (this._hookNoResponseGiveUpTimeout > 0) { this._startActionHookNoResponseGiveUpTimer(); } diff --git a/lib/tasks/task.js b/lib/tasks/task.js index 1cede8fa..556da88c 100644 --- a/lib/tasks/task.js +++ b/lib/tasks/task.js @@ -177,8 +177,8 @@ class Task extends Emitter { // If actionHook delay action is configured, and ws application have not responded yet any verb for actionHook // We have to transfer the task to call-session to await on next ws command verbs, and also run action Hook // delay actions - if (this.actionHookDelayActionOptions) { - this.emit('ActionHookDelayActionOptions', this.actionHookDelayActionOptions); + if (this.hookDelayActionOpts) { + this.emit('ActionHookDelayActionOptions', this.hookDelayActionOpts); } } if (expectResponse && json && Array.isArray(json)) {