fix actionHookDelay feature is not working properly if there is no de… (#679)

* fix actionHookDelayAction when no actions is defnied

* terminated by jambonz for giveuptimeout
This commit is contained in:
Hoan Luu Huu
2024-03-12 19:33:03 +07:00
committed by GitHub
parent 878578fe0f
commit c946a5d14d
7 changed files with 76 additions and 42 deletions

View File

@@ -53,16 +53,24 @@ class AdultingCallSession extends CallSession {
} }
_callerHungup() { _callerHungup() {
this._hangup('caller');
}
_jambonzHangup() {
this._hangup();
}
_hangup(terminatedBy = 'jambonz') {
if (this.dlg.connectTime) { if (this.dlg.connectTime) {
const duration = moment().diff(this.dlg.connectTime, 'seconds'); const duration = moment().diff(this.dlg.connectTime, 'seconds');
this.rootSpan.setAttributes({'call.termination': 'hangup by caller'}); this.rootSpan.setAttributes({'call.termination': `hangup by ${terminatedBy}`});
this.callInfo.callTerminationBy = 'caller'; this.callInfo.callTerminationBy = terminatedBy;
this.emit('callStatusChange', { this.emit('callStatusChange', {
callStatus: CallStatus.Completed, callStatus: CallStatus.Completed,
duration duration
}); });
} }
this.logger.info('InboundCallSession: caller hung up'); this.logger.info(`InboundCallSession: ${terminatedBy} hung up`);
this._callReleased(); this._callReleased();
this.req.removeAllListeners('cancel'); this.req.removeAllListeners('cancel');
} }

View File

@@ -1831,6 +1831,14 @@ Duration=${duration} `
assert(false, 'subclass responsibility to override this method'); 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 * get a media server to use for this call
*/ */
@@ -2259,7 +2267,7 @@ Duration=${duration} `
this.logger.debug(`CallSession:_startActionHookNoResponseTimer ${options.noResponseTimeoutMs}`); this.logger.debug(`CallSession:_startActionHookNoResponseTimer ${options.noResponseTimeoutMs}`);
this._actionHookNoResponseTimer = setTimeout(() => { this._actionHookNoResponseTimer = setTimeout(() => {
if (this._actionHookDelayRetryCount >= options.retries) { if (this._actionHookDelayRetryCount >= options.retries) {
this._callerHungup(); this._jambonzHangup();
} }
const verb = options.actions[this._actionHookDelayRetryCount % options.actions.length]; const verb = options.actions[this._actionHookDelayRetryCount % options.actions.length];
// Inject verb to main stack // Inject verb to main stack
@@ -2297,7 +2305,7 @@ Duration=${duration} `
this.logger.debug(`CallSession:_startActionHookNoResponseGiveUpTimer ${options.noResponseGiveUpTimeoutMs}`); this.logger.debug(`CallSession:_startActionHookNoResponseGiveUpTimer ${options.noResponseGiveUpTimeoutMs}`);
this._actionHookNoResponseGiveUpTimer = setTimeout(() => { this._actionHookNoResponseGiveUpTimer = setTimeout(() => {
this.logger.debug('CallSession:_startActionHookNoResponseGiveUpTimer Timeout'); this.logger.debug('CallSession:_startActionHookNoResponseGiveUpTimer Timeout');
this._callerHungup(); this._jambonzHangup();
this._actionHookNoResponseGiveUpTimer = null; this._actionHookNoResponseGiveUpTimer = null;
}, options.noResponseGiveUpTimeoutMs); }, options.noResponseGiveUpTimeoutMs);
} }

View File

@@ -34,6 +34,9 @@ class ConfirmCallSession extends CallSession {
_callerHungup() { _callerHungup() {
} }
_jambonzHangup() {
}
} }

View File

@@ -67,19 +67,27 @@ class InboundCallSession extends CallSession {
* This is invoked when the caller hangs up, in order to calculate the call duration. * This is invoked when the caller hangs up, in order to calculate the call duration.
*/ */
_callerHungup() { _callerHungup() {
this._hangup('caller');
}
_jambonzHangup() {
this._hangup();
}
_hangup(terminatedBy = 'jambonz') {
if (this.dlg === null) { 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; return;
} }
assert(this.dlg.connectTime); assert(this.dlg.connectTime);
const duration = moment().diff(this.dlg.connectTime, 'seconds'); const duration = moment().diff(this.dlg.connectTime, 'seconds');
this.rootSpan.setAttributes({'call.termination': 'hangup by caller'}); this.rootSpan.setAttributes({'call.termination': `hangup by ${terminatedBy}`});
this.callInfo.callTerminationBy = 'caller'; this.callInfo.callTerminationBy = terminatedBy;
this.emit('callStatusChange', { this.emit('callStatusChange', {
callStatus: CallStatus.Completed, callStatus: CallStatus.Completed,
duration duration
}); });
this.logger.info('InboundCallSession: caller hung up'); this.logger.info(`InboundCallSession: ${terminatedBy} hung up`);
this._callReleased(); this._callReleased();
this.req.removeAllListeners('cancel'); this.req.removeAllListeners('cancel');
} }

View File

@@ -49,13 +49,21 @@ class RestCallSession extends CallSession {
* This is invoked when the called party hangs up, in order to calculate the call duration. * This is invoked when the called party hangs up, in order to calculate the call duration.
*/ */
_callerHungup() { _callerHungup() {
this._hangup('caller');
}
_jambonzHangup() {
this._hangup();
}
_hangup(terminatedBy = 'jamboz') {
if (this.restDialTask) { if (this.restDialTask) {
this.restDialTask.turnOffAmd(); this.restDialTask.turnOffAmd();
} }
this.callInfo.callTerminationBy = 'caller'; this.callInfo.callTerminationBy = terminatedBy;
const duration = moment().diff(this.dlg.connectTime, 'seconds'); const duration = moment().diff(this.dlg.connectTime, 'seconds');
this.emit('callStatusChange', {callStatus: CallStatus.Completed, duration}); 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(); this._callReleased();
} }

View File

@@ -139,28 +139,27 @@ class TaskGather extends SttTask {
this.logger.debug('Gather:exec - early hints match enabled'); this.logger.debug('Gather:exec - early hints match enabled');
} }
// actionHook delay // actionHook delay
this._actionHookDelayEnabled = cs.actionHookDelayEnabled || !!this.actionHookDelayAction; this._hookDelayEn = 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._actionHookNoResponseGiveUpTimeout = (this.actionHookDelayAction && this._hookDelayActions = this.actionHookDelayAction?.actions || cs.actionHookDelayActions || [];
this.actionHookDelayAction.noResponseGiveUpTimeout ?
this.actionHookDelayAction.noResponseGiveUpTimeout : cs.actionHookNoResponseGiveUpTimeout || 0) * 1000;
this._actionHookDelayRetries = this.actionHookDelayAction && this.actionHookDelayAction.retries ? // Only enable NoResponseTimeout if there is _hookDelayActions
this.actionHookDelayAction.retries : cs.actionHookDelayRetries || 1; this._hookNoResponseTimeout = (this._hookDelayActions?.length ?
this._actionHookDelayTryCount = 0; (this.actionHookDelayAction?.noResponseTimeout || cs.actionHookNoResponseTimeout || 0)
this.actionHookDelayActionOptions = { : 0) * 1000;
enabled: this._actionHookDelayEnabled,
actions: this._actionHookDelayActions, this._hookNoResponseGiveUpTimeout = (this.actionHookDelayAction?.noResponseGiveUpTimeout ||
noResponseTimeoutMs: this._actionHookNoResponseTimeout, cs.actionHookNoResponseGiveUpTimeout || 0) * 1000;
noResponseGiveUpTimeoutMs: this._actionHookNoResponseGiveUpTimeout,
retries: this._actionHookDelayRetries 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) => { const startListening = async(cs, ep) => {
this._startTimer(); this._startTimer();
@@ -600,24 +599,24 @@ class TaskGather extends SttTask {
} }
_startActionHookNoResponseTimer() { _startActionHookNoResponseTimer() {
assert(this._actionHookNoResponseTimeout > 0); assert(this._hookNoResponseTimeout > 0);
this._clearActionHookNoResponseTimer(); this._clearActionHookNoResponseTimer();
this.logger.debug('startActionHookNoResponseTimer'); this.logger.debug('startActionHookNoResponseTimer');
this._actionHookNoResponseTimer = setTimeout(() => { this._actionHookNoResponseTimer = setTimeout(() => {
if (this._actionHookDelayTryCount >= this._actionHookDelayRetries) { if (this._hookDelayRetryCount >= this._hookDelayRetries) {
this._hangupCall(); this._hangupCall();
return; return;
} }
const verb = this._actionHookDelayActions[this._actionHookDelayTryCount % this._actionHookDelayActions.length]; const verb = this._hookDelayActions[this._hookDelayRetryCount % this._hookDelayActions.length];
if (verb.verb === 'say') { if (verb.verb === 'say') {
this._actionHookDelaySayAction(verb); this._actionHookDelaySayAction(verb);
} else if (verb.verb === 'play') { } else if (verb.verb === 'play') {
this._actionHookDelayPlayAction(verb); this._actionHookDelayPlayAction(verb);
} }
this._actionHookDelayTryCount++; this._hookDelayRetryCount++;
this._startActionHookNoResponseTimer(); this._startActionHookNoResponseTimer();
}, this._actionHookNoResponseTimeout); }, this._hookNoResponseTimeout);
} }
@@ -629,12 +628,12 @@ class TaskGather extends SttTask {
} }
_startActionHookNoResponseGiveUpTimer() { _startActionHookNoResponseGiveUpTimer() {
assert(this._actionHookNoResponseGiveUpTimeout > 0); assert(this._hookNoResponseGiveUpTimeout > 0);
this._clearActionHookNoResponseGiveUpTimer(); this._clearActionHookNoResponseGiveUpTimer();
this.logger.debug('startActionHookNoResponseGiveUpTimer'); this.logger.debug('startActionHookNoResponseGiveUpTimer');
this._actionHookNoResponseGiveUpTimer = setTimeout(() => { this._actionHookNoResponseGiveUpTimer = setTimeout(() => {
this._hangupCall(); this._hangupCall();
}, this._actionHookNoResponseGiveUpTimeout); }, this._hookNoResponseGiveUpTimeout);
} }
_clearActionHookNoResponseGiveUpTimer() { _clearActionHookNoResponseGiveUpTimer() {
@@ -994,11 +993,11 @@ class TaskGather extends SttTask {
} }
// Enabled action Hook delay timer to applied actions // Enabled action Hook delay timer to applied actions
if (this._actionHookNoResponseTimeout > 0) { if (this._hookNoResponseTimeout > 0) {
this._startActionHookNoResponseTimer(); this._startActionHookNoResponseTimer();
} }
if (this._actionHookNoResponseGiveUpTimeout > 0) { if (this._hookNoResponseGiveUpTimeout > 0) {
this._startActionHookNoResponseGiveUpTimer(); this._startActionHookNoResponseGiveUpTimer();
} }

View File

@@ -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 // 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 // We have to transfer the task to call-session to await on next ws command verbs, and also run action Hook
// delay actions // delay actions
if (this.actionHookDelayActionOptions) { if (this.hookDelayActionOpts) {
this.emit('ActionHookDelayActionOptions', this.actionHookDelayActionOptions); this.emit('ActionHookDelayActionOptions', this.hookDelayActionOpts);
} }
} }
if (expectResponse && json && Array.isArray(json)) { if (expectResponse && json && Array.isArray(json)) {