diff --git a/lib/config.js b/lib/config.js index 78b101ed..bdfbce04 100644 --- a/lib/config.js +++ b/lib/config.js @@ -139,6 +139,9 @@ const JAMBONES_USE_FREESWITCH_TIMER_FD = process.env.JAMBONES_USE_FREESWITCH_TIM const JAMBONES_DIAL_SBC_FOR_REGISTERED_USER = process.env.JAMBONES_DIAL_SBC_FOR_REGISTERED_USER || false; const JAMBONES_MEDIA_TIMEOUT_MS = process.env.JAMBONES_MEDIA_TIMEOUT_MS || 0; const JAMBONES_MEDIA_HOLD_TIMEOUT_MS = process.env.JAMBONES_MEDIA_HOLD_TIMEOUT_MS || 0; +// jambonz +const JAMBONES_TRANSCRIBE_EP_DESTROY_DELAY_MS = + process.env.JAMBONES_TRANSCRIBE_EP_DESTROY_DELAY_MS; module.exports = { JAMBONES_MYSQL_HOST, @@ -227,5 +230,6 @@ module.exports = { JAMBONES_USE_FREESWITCH_TIMER_FD, JAMBONES_DIAL_SBC_FOR_REGISTERED_USER, JAMBONES_MEDIA_TIMEOUT_MS, - JAMBONES_MEDIA_HOLD_TIMEOUT_MS + JAMBONES_MEDIA_HOLD_TIMEOUT_MS, + JAMBONES_TRANSCRIBE_EP_DESTROY_DELAY_MS }; diff --git a/lib/session/call-session.js b/lib/session/call-session.js index d3b6a48d..642767e1 100644 --- a/lib/session/call-session.js +++ b/lib/session/call-session.js @@ -30,7 +30,8 @@ const { AWS_REGION, JAMBONES_USE_FREESWITCH_TIMER_FD, JAMBONES_MEDIA_TIMEOUT_MS, - JAMBONES_MEDIA_HOLD_TIMEOUT_MS + JAMBONES_MEDIA_HOLD_TIMEOUT_MS, + JAMBONES_TRANSCRIBE_EP_DESTROY_DELAY_MS } = require('../config'); const bent = require('bent'); const BackgroundTaskManager = require('../utils/background-task-manager'); @@ -38,6 +39,7 @@ const dbUtils = require('../utils/db-utils'); const BADPRECONDITIONS = 'preconditions not met'; const CALLER_CANCELLED_ERR_MSG = 'Response not sent due to unknown transaction'; const { NonFatalTaskError} = require('../utils/error'); +const { sleepFor } = require('../utils/helpers'); const sqlRetrieveQueueEventHook = `SELECT * FROM webhooks WHERE webhook_sid = ( @@ -2840,6 +2842,24 @@ Duration=${duration} ` if (Object.keys(opts).length > 0) { this.ep.set(opts); } + + const origDestroy = this.ep.destroy.bind(this.ep); + this.ep.destroy = async() => { + try { + if (this.currentTask?.name === TaskName.Transcribe && JAMBONES_TRANSCRIBE_EP_DESTROY_DELAY_MS) { + // transcribe task is being used, wait for some time before destroy + // if final transcription is received but endpoint is already closed, + // freeswitch module will not be able to send the transcription + + this.logger.info('callSession:_configMsEndpoint -' + + ' transcribe task, wait for some time before destroy'); + await sleepFor(JAMBONES_TRANSCRIBE_EP_DESTROY_DELAY_MS); + } + await origDestroy(); + } catch (err) { + this.logger.error(err, 'callSession:_configMsEndpoint - error destroying endpoint'); + } + }; } async _handleMediaTimeout(evt) { diff --git a/lib/tasks/dequeue.js b/lib/tasks/dequeue.js index a1fcd2f8..d7cff6d8 100644 --- a/lib/tasks/dequeue.js +++ b/lib/tasks/dequeue.js @@ -3,8 +3,7 @@ const {TaskName, TaskPreconditions, DequeueResults, BONG_TONE} = require('../uti const Emitter = require('events'); const bent = require('bent'); const assert = require('assert'); - -const sleepFor = (ms) => new Promise((resolve) => setTimeout(() => resolve(), ms)); +const { sleepFor } = require('../utils/helpers'); const getUrl = (cs) => `${cs.srf.locals.serviceUrl}/v1/dequeue/${cs.callSid}`; diff --git a/lib/tasks/dial.js b/lib/tasks/dial.js index 3c2ba30b..624eb8db 100644 --- a/lib/tasks/dial.js +++ b/lib/tasks/dial.js @@ -24,6 +24,7 @@ const {ANCHOR_MEDIA_ALWAYS, const { isOnhold, isOpusFirst } = require('../utils/sdp-utils'); const { normalizeJambones } = require('@jambonz/verb-specifications'); const { selectHostPort } = require('../utils/network'); +const { sleepFor } = require('../utils/helpers'); function parseDtmfOptions(logger, dtmfCapture) { let parentDtmfCollector, childDtmfCollector; @@ -86,8 +87,6 @@ function filterAndLimit(logger, tasks) { return unique; } -const sleepFor = (ms) => new Promise((resolve) => setTimeout(() => resolve(), ms)); - class TaskDial extends Task { constructor(logger, opts) { super(logger, opts); diff --git a/lib/utils/helpers.js b/lib/utils/helpers.js new file mode 100644 index 00000000..43c58f31 --- /dev/null +++ b/lib/utils/helpers.js @@ -0,0 +1,5 @@ + +const sleepFor = (ms) => new Promise((resolve) => setTimeout(() => resolve(), ms)); +module.exports = { + sleepFor +}; diff --git a/lib/utils/place-outdial.js b/lib/utils/place-outdial.js index 1a496805..d7f19a0f 100644 --- a/lib/utils/place-outdial.js +++ b/lib/utils/place-outdial.js @@ -19,8 +19,10 @@ const {makeOpusFirst} = require('./sdp-utils'); const { JAMBONES_USE_FREESWITCH_TIMER_FD, JAMBONES_MEDIA_TIMEOUT_MS, - JAMBONES_MEDIA_HOLD_TIMEOUT_MS + JAMBONES_MEDIA_HOLD_TIMEOUT_MS, + JAMBONES_TRANSCRIBE_EP_DESTROY_DELAY_MS } = require('../config'); +const { sleepFor } = require('./helpers'); class SingleDialer extends Emitter { constructor({logger, sbcAddress, target, opts, application, callInfo, accountInfo, rootSpan, startSpan, dialTask, @@ -358,6 +360,24 @@ class SingleDialer extends Emitter { this.logger.info(err, 'place-outdial:_configMsEndpoint - error enable inband DTMF'); } } + + const origDestroy = this.ep.destroy.bind(this.ep); + this.ep.destroy = async() => { + try { + if (this.dialTask.transcribeTask && JAMBONES_TRANSCRIBE_EP_DESTROY_DELAY_MS) { + // transcribe task is being used, wait for some time before destroy + // if final transcription is received but endpoint is already closed, + // freeswitch module will not be able to send the transcription + + this.logger.info('SingleDialer:_configMsEndpoint -' + + ' Dial with transcribe task, wait for some time before destroy'); + await sleepFor(JAMBONES_TRANSCRIBE_EP_DESTROY_DELAY_MS); + } + await origDestroy(); + } catch (err) { + this.logger.error(err, 'SingleDialer:_configMsEndpoint - error destroying endpoint'); + } + }; } /** diff --git a/test/dial-tests.js b/test/dial-tests.js index 90d7e793..80d5f5ce 100644 --- a/test/dial-tests.js +++ b/test/dial-tests.js @@ -3,9 +3,8 @@ const { sippUac } = require('./sipp')('test_fs'); const bent = require('bent'); const getJSON = bent('json') const clearModule = require('clear-module'); -const {provisionCallHook} = require('./utils') - -const sleepFor = (ms) => new Promise((r) => setTimeout(r, ms)); +const {provisionCallHook} = require('./utils'); +const { sleepFor } = require('../lib/utils/helpers'); process.on('unhandledRejection', (reason, p) => { console.log('Unhandled Rejection at: Promise', p, 'reason:', reason); diff --git a/test/queue-test.js b/test/queue-test.js index 82fe6dbf..f8eafb7c 100644 --- a/test/queue-test.js +++ b/test/queue-test.js @@ -3,6 +3,7 @@ const { sippUac } = require('./sipp')('test_fs'); const clearModule = require('clear-module'); const {provisionCallHook, provisionActionHook, provisionAnyHook} = require('./utils'); const bent = require('bent'); +const { sleepFor } = require('../lib/utils/helpers'); const getJSON = bent('json'); process.on('unhandledRejection', (reason, p) => { @@ -17,8 +18,6 @@ function connect(connectable) { }); } -const sleepFor = (ms) => new Promise((resolve) => setTimeout(() => resolve(), ms)); - test('\'enqueue-dequeue\' tests', async(t) => { clearModule.all(); diff --git a/test/sip-refer-tests.js b/test/sip-refer-tests.js index fdee9847..39015d58 100644 --- a/test/sip-refer-tests.js +++ b/test/sip-refer-tests.js @@ -3,10 +3,9 @@ const { sippUac } = require('./sipp')('test_fs'); const clearModule = require('clear-module'); const {provisionCallHook, provisionCustomHook, provisionActionHook} = require('./utils') const bent = require('bent'); +const { sleepFor } = require('../lib/utils/helpers'); const getJSON = bent('json') -const sleepFor = async(ms) => new Promise(resolve => setTimeout(resolve, ms)); - process.on('unhandledRejection', (reason, p) => { console.log('Unhandled Rejection at: Promise', p, 'reason:', reason); });