Compare commits

..

2 Commits

Author SHA1 Message Date
Quan HL
673ab8a730 reanchor media for A leg 2024-02-20 15:25:00 +07:00
Quan HL
ec1408fa0c allow lcc child call via ws 2024-02-20 15:04:30 +07:00
12 changed files with 65 additions and 354 deletions

View File

@@ -130,7 +130,7 @@ const JAMBONZ_RECORD_WS_PASSWORD = process.env.JAMBONZ_RECORD_WS_PASSWORD || pro
const JAMBONZ_DISABLE_DIAL_PAI_HEADER = process.env.JAMBONZ_DISABLE_DIAL_PAI_HEADER || false;
const JAMBONES_DISABLE_DIRECT_P2P_CALL = process.env.JAMBONES_DISABLE_DIRECT_P2P_CALL || false;
const JAMBONES_EAGERLY_PRE_CACHE_AUDIO = parseInt(process.env.JAMBONES_EAGERLY_PRE_CACHE_AUDIO, 10) || 0;
const JAMBONES_EAGERLY_PRE_CACHE_AUDIO = process.env.JAMBONES_EAGERLY_PRE_CACHE_AUDIO;
const JAMBONES_USE_FREESWITCH_TIMER_FD = process.env.JAMBONES_USE_FREESWITCH_TIMER_FD;

View File

@@ -7,8 +7,7 @@ const {
TaskName,
KillReason,
RecordState,
AllowedSipRecVerbs,
AllowedConfirmSessionVerbs
AllowedSipRecVerbs
} = require('../utils/constants');
const moment = require('moment');
const assert = require('assert');
@@ -450,47 +449,6 @@ class CallSession extends Emitter {
this._sipRequestWithinDialogHook = url;
}
// Bot Delay (actionHook delayed)
get actionHookDelayEnabled() {
return this._actionHookDelayEnabled;
}
set actionHookDelayEnabled(e) {
this._actionHookDelayEnabled = e;
}
get actionHookNoResponseTimeout() {
return this._actionHookNoResponseTimeout;
}
set actionHookNoResponseTimeout(e) {
this._actionHookNoResponseTimeout = e;
}
get actionHookNoResponseGiveUpTimeout() {
return this._actionHookNoResponseGiveUpTimeout;
}
set actionHookNoResponseGiveUpTimeout(e) {
this._actionHookNoResponseGiveUpTimeout = e;
}
get actionHookDelayRetries() {
return this._actionHookDelayRetries;
}
set actionHookDelayRetries(e) {
this._actionHookDelayRetries = e;
}
get actionHookDelayActions() {
return this._actionHookDelayActions;
}
set actionHookDelayActions(e) {
this._actionHookDelayActions = e;
}
hasGlobalSttPunctuation() {
return this._globalSttPunctuation !== undefined;
}
@@ -878,7 +836,6 @@ class CallSession extends Emitter {
task.on('VerbHookSpanWaitForEnd', ({span}) => {
this.verbHookSpan = span;
});
task.on('ActionHookDelayActionOptions', this._onActionHookDelayActions.bind(this));
try {
const resources = await this._evaluatePreconditions(task);
let skip = false;
@@ -1086,30 +1043,22 @@ class CallSession extends Emitter {
* @param {object} [opts.call_hook] - new call_status_hook
*/
async _lccCallHook(opts) {
const webhooks = [];
let sd, tasks, childTasks;
const b3 = this.b3;
const httpHeaders = b3 && {b3};
if (opts.call_hook || opts.child_call_hook) {
if (opts.call_hook) {
webhooks.push(this.requestor.request('session:redirect', opts.call_hook, this.callInfo.toJSON(), httpHeaders));
tasks = await this.requestor.request('session:redirect', opts.call_hook, this.callInfo.toJSON(), httpHeaders);
}
if (opts.child_call_hook) {
/* child call hook only allowed from a connected Dial state */
const task = this.currentTask;
sd = task.sd;
if (task && TaskName.Dial === task.name && sd) {
webhooks.push(this.requestor.request(
'session:redirect', opts.child_call_hook, sd.callInfo.toJSON(), httpHeaders));
childTasks = [];
}
}
const [tasks1, tasks2] = await Promise.all(webhooks);
if (opts.call_hook) {
tasks = tasks1;
if (opts.child_call_hook) childTasks = tasks2;
}
else childTasks = tasks1;
}
else if (opts.parent_call || opts.child_call) {
const {parent_call, child_call} = opts;
@@ -1129,13 +1078,17 @@ class CallSession extends Emitter {
const cs = await sd.doAdulting({
logger: childLogger,
application: this.application,
tasks: t
tasks: t,
call_hook_url: opts.child_call_hook
});
/* need to update the callSid of the child with its own (new) AdultingCallSession */
sessionTracker.add(cs.callSid, cs);
}
if (tasks) {
if (!this.ep) {
await this.reAnchorMedia();
}
const t = normalizeJambones(this.logger, tasks).map((tdata) => makeTask(this.logger, tdata));
this.logger.info({tasks: listTaskNames(t)}, 'CallSession:_lccCallHook new task list');
this.replaceApplication(t);
@@ -1150,9 +1103,6 @@ class CallSession extends Emitter {
this.currentTask.kill(this);
}
this._endVerbHookSpan();
// clear all delay action hook timeout if there is
this._clearActionHookNoResponseGiveUpTimer();
this._clearActionHookNoResponseTimer();
}
/**
@@ -1340,14 +1290,6 @@ Duration=${duration} `
task.whisper(tasks, callSid).catch((err) => this.logger.error(err, 'CallSession:_lccWhisper'));
}
/**
* perform call hangup by jambonz
*/
async hangup() {
return this._callerHungup();
}
/**
* perform live call control
@@ -1421,19 +1363,6 @@ Duration=${duration} `
tasks = pruned;
}
}
else if (this.isConfirmCallSession) {
const pruned = tasks.filter((t) => AllowedConfirmSessionVerbs.includes(t.name));
if (0 === pruned.length) {
this.logger.info({tasks},
'CallSession:replaceApplication - filtering verbs allowed on an confirmSession call');
return;
}
if (pruned.length < tasks.length) {
this.logger.info(
'CallSession:replaceApplication - removing verbs that are not allowed for confirmSession call');
tasks = pruned;
}
}
this.tasks = tasks;
this.taskIdx = 0;
this.stackIdx++;
@@ -1572,9 +1501,6 @@ Duration=${duration} `
}
resolution = {reason: 'received command, new tasks', queue: queueCommand, command};
resolution.command = listTaskNames(t);
// clear all delay action hook timeout if there is
this._clearActionHookNoResponseGiveUpTimer();
this._clearActionHookNoResponseTimer();
}
else this._lccCallHook(data);
break;
@@ -1815,8 +1741,6 @@ Duration=${duration} `
this.rootSpan && this.rootSpan.end();
// close all background tasks
this.backgroundTaskManager.stopAll();
this._clearActionHookNoResponseGiveUpTimer();
this._clearActionHookNoResponseTimer();
}
/**
@@ -2242,69 +2166,6 @@ Duration=${duration} `
this.verbHookSpan = null;
}
}
// actionHook delay actions
_onActionHookDelayActions(options) {
this._actionHookDelayRetryCount = 0;
this._startActionHookNoResponseTimer(options);
this._startActionHookNoResponseGiveUpTimer(options);
}
_startActionHookNoResponseTimer(options) {
this._clearActionHookNoResponseTimer();
if (options.noResponseTimeoutMs) {
this.logger.debug(`CallSession:_startActionHookNoResponseTimer ${options.noResponseTimeoutMs}`);
this._actionHookNoResponseTimer = setTimeout(() => {
if (this._actionHookDelayRetryCount >= options.retries) {
this._callerHungup();
}
const verb = options.actions[this._actionHookDelayRetryCount % options.actions.length];
// Inject verb to main stack
const t = normalizeJambones(this.logger, [verb])
.map((tdata) => makeTask(this.logger, tdata));
if (t.length) {
t[0].on('playDone', (err) => {
if (err) this.logger.error({err}, `Call-Session:exec Error delay action, play ${verb}`);
this._startActionHookNoResponseTimer(options);
});
}
this.tasks.push(...t);
if (this.wakeupResolver) {
this.wakeupResolver({reason: 'actionHook no response, applied delay actions', verb});
this.wakeupResolver = null;
}
this.logger.debug(`CallSession:_startActionHookNoResponseTimer, executing verb ${JSON.stringify(verb)}`);
this._actionHookDelayRetryCount++;
}, options.noResponseTimeoutMs);
}
}
_clearActionHookNoResponseTimer() {
if (this._actionHookNoResponseTimer) {
clearTimeout(this._actionHookNoResponseTimer);
}
this._actionHookNoResponseTimer = null;
}
_startActionHookNoResponseGiveUpTimer(options) {
this._clearActionHookNoResponseGiveUpTimer();
if (options.noResponseGiveUpTimeoutMs) {
this.logger.debug(`CallSession:_startActionHookNoResponseGiveUpTimer ${options.noResponseGiveUpTimeoutMs}`);
this._actionHookNoResponseGiveUpTimer = setTimeout(() => {
this.logger.debug('CallSession:_startActionHookNoResponseGiveUpTimer Timeout');
this._callerHungup();
this._actionHookNoResponseGiveUpTimer = null;
}, options.noResponseGiveUpTimeoutMs);
}
}
_clearActionHookNoResponseGiveUpTimer() {
if (this._actionHookNoResponseGiveUpTimer) {
clearTimeout(this._actionHookNoResponseGiveUpTimer);
}
this._actionHookNoResponseGiveUpTimer = null;
}
}
module.exports = CallSession;

View File

@@ -67,10 +67,6 @@ class InboundCallSession extends CallSession {
* This is invoked when the caller hangs up, in order to calculate the call duration.
*/
_callerHungup() {
if (this.dlg === null) {
this.logger.info('InboundCallSession:_callerHungup - 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'});

View File

@@ -10,8 +10,7 @@ class TaskConfig extends Task {
'bargeIn',
'record',
'listen',
'transcribe',
'actionHookDelayAction'
'transcribe'
].forEach((k) => this[k] = this.data[k] || {});
if ('notifyEvents' in this.data) {
@@ -250,14 +249,6 @@ class TaskConfig extends Task {
cs.stopBackgroundTask('transcribe');
}
}
if (this.actionHookDelayAction) {
cs.actionHookDelayEnabled = this.actionHookDelayAction.enabled || false;
cs.actionHookNoResponseTimeout = this.actionHookDelayAction.noResponseTimeout || 0;
cs.actionHookNoResponseGiveUpTimeout = this.actionHookDelayAction.noResponseGiveUpTimeout || 0;
cs.actionHookDelayRetries = this.actionHookDelayAction.retries || 1;
cs.actionHookDelayActions = this.actionHookDelayAction.actions || [];
}
if (this.data.sipRequestWithinDialogHook) {
cs.sipRequestWithinDialogHook = this.data.sipRequestWithinDialogHook;
}

View File

@@ -27,7 +27,7 @@ class TaskGather extends SttTask {
[
'finishOnKey', 'input', 'numDigits', 'minDigits', 'maxDigits',
'interDigitTimeout', 'partialResultHook', 'bargein', 'dtmfBargein',
'speechTimeout', 'timeout', 'say', 'play', 'actionHookDelayAction'
'speechTimeout', 'timeout', 'say', 'play'
].forEach((k) => this[k] = this.data[k]);
// gather default input is digits
@@ -138,30 +138,6 @@ class TaskGather extends SttTask {
this.interim = true;
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._actionHookNoResponseGiveUpTimeout = (this.actionHookDelayAction &&
this.actionHookDelayAction.noResponseGiveUpTimeout ?
this.actionHookDelayAction.noResponseGiveUpTimeout : cs.actionHookNoResponseGiveUpTimeout || 0) * 1000;
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
};
}
const startListening = async(cs, ep) => {
this._startTimer();
if (this.isContinuousAsr && 0 === this.timeout) this._startAsrTimer();
@@ -255,7 +231,6 @@ class TaskGather extends SttTask {
kill(cs) {
super.kill(cs);
this._killAudio(cs);
this._killActionHookDelayAction();
this.ep.removeAllListeners('dtmf');
clearTimeout(this.interDigitTimer);
this._clearAsrTimer();
@@ -546,104 +521,6 @@ class TaskGather extends SttTask {
this._asrTimer = null;
}
_hangupCall() {
this.logger.debug('_hangupCall');
this.cs.hangup();
}
_actionHookDelaySayAction(verb) {
delete verb.verb;
this.logger.debug(`_actionHookDelaySayAction ${verb}`);
this._actionHookDelaySayTask = makeTask(this.logger, {say: verb}, this);
const {span, ctx} = this.startChildSpan(`actionHookDelayAction:${this._actionHookDelaySayTask.summary}`);
this._actionHookDelaySayTask.span = span;
this._actionHookDelaySayTask.ctx = ctx;
this._actionHookDelaySayTask.exec(this.cs, {ep: this.ep});
this._actionHookDelaySayTask.on('playDone', (err) => {
this._actionHookDelaySayTask = null;
span.end();
if (err) this.logger.error({err}, 'Gather:actionHookDelay Error playing tts');
});
}
_killActionHookDelayAction() {
this.logger.debug('_killActionHookDelayAction');
if (this._actionHookDelaySayTask && !this._actionHookDelaySayTask.killed) {
this._actionHookDelaySayTask.removeAllListeners('playDone');
this._actionHookDelaySayTask.kill(this.cs);
this._actionHookDelaySayTask.span.end();
this._actionHookDelaySayTask = null;
}
if (this._actionHookDelayPlayTask && !this._actionHookDelayPlayTask.killed) {
this._actionHookDelayPlayTask.removeAllListeners('playDone');
this._actionHookDelayPlayTask.kill(this.cs);
this._actionHookDelayPlayTask.span.end();
this._actionHookDelayPlayTask = null;
}
}
_actionHookDelayPlayAction(verb) {
delete verb.verb;
this.logger.debug(`_actionHookDelayPlayAction ${verb}`);
this._actionHookDelayPlayTask = makeTask(this.logger, {play: verb}, this);
const {span, ctx} = this.startChildSpan(`actionHookDelayAction:${this._actionHookDelayPlayTask.summary}`);
this._actionHookDelayPlayTask.span = span;
this._actionHookDelayPlayTask.ctx = ctx;
this._actionHookDelayPlayTask.exec(this.cs, {ep: this.ep});
this._actionHookDelayPlayTask.on('playDone', (err) => {
this._actionHookDelayPlayTask = null;
span.end();
if (err) this.logger.error({err}, 'Gather:actionHookDelay Error playing tts');
});
}
_startActionHookNoResponseTimer() {
assert(this._actionHookNoResponseTimeout > 0);
this._clearActionHookNoResponseTimer();
this.logger.debug('startActionHookNoResponseTimer');
this._actionHookNoResponseTimer = setTimeout(() => {
if (this._actionHookDelayTryCount >= this._actionHookDelayRetries) {
this._hangupCall();
return;
}
const verb = this._actionHookDelayActions[this._actionHookDelayTryCount % this._actionHookDelayActions.length];
if (verb.verb === 'say') {
this._actionHookDelaySayAction(verb);
} else if (verb.verb === 'play') {
this._actionHookDelayPlayAction(verb);
}
this._actionHookDelayTryCount++;
this._startActionHookNoResponseTimer();
}, this._actionHookNoResponseTimeout);
}
_clearActionHookNoResponseTimer() {
if (this._actionHookNoResponseTimer) {
clearTimeout(this._actionHookNoResponseTimer);
}
this._actionHookNoResponseTimer = null;
}
_startActionHookNoResponseGiveUpTimer() {
assert(this._actionHookNoResponseGiveUpTimeout > 0);
this._clearActionHookNoResponseGiveUpTimer();
this.logger.debug('startActionHookNoResponseGiveUpTimer');
this._actionHookNoResponseGiveUpTimer = setTimeout(() => {
this._hangupCall();
}, this._actionHookNoResponseGiveUpTimeout);
}
_clearActionHookNoResponseGiveUpTimer() {
if (this._actionHookNoResponseGiveUpTimer) {
clearTimeout(this._actionHookNoResponseGiveUpTimer);
}
this._actionHookNoResponseGiveUpTimer = null;
}
_startFastRecognitionTimer(evt) {
assert(this.fastRecognitionTimeout > 0);
this._clearFastRecognitionTimer();
@@ -822,26 +699,13 @@ class TaskGather extends SttTask {
}
}
else {
/* deepgram can send a non-final transcript but with words that are final, so we need to buffer */
let emptyTranscript = false;
if (this.vendor === 'deepgram') {
const originalEvent = evt.vendor.evt;
if (originalEvent.is_final && evt.alternatives[0].transcript !== '') {
this.logger.debug({evt}, 'Gather:_onTranscription - buffering a completed (partial) deepgram transcript');
this._bufferedTranscripts.push(evt);
}
if (evt.alternatives[0].transcript === '') emptyTranscript = true;
}
if (!emptyTranscript) {
if (this._clearTimer()) this._startTimer();
if (this.bargein && (words + bufferedWords) >= this.minBargeinWordCount) {
if (!this.playComplete) {
this.logger.debug({transcript: evt.alternatives[0].transcript}, 'killing audio due to speech');
this.emit('vad');
}
this._killAudio(cs);
if (this._clearTimer()) this._startTimer();
if (this.bargein && (words + bufferedWords) >= this.minBargeinWordCount) {
if (!this.playComplete) {
this.logger.debug({transcript: evt.alternatives[0].transcript}, 'killing audio due to speech');
this.emit('vad');
}
this._killAudio(cs);
}
if (this.fastRecognitionTimeout) {
this._startFastRecognitionTimer(evt);
@@ -859,6 +723,14 @@ class TaskGather extends SttTask {
this._sonioxTranscripts.push(evt.vendor.finalWords);
}
}
/* deepgram can send a non-final transcript but with words that are final, so we need to buffer */
if (this.vendor === 'deepgram') {
const originalEvent = evt.vendor.evt;
if (originalEvent.is_final && evt.alternatives[0].transcript !== '') {
this.logger.debug({evt}, 'Gather:_onTranscription - buffering a completed (partial) deepgram transcript');
this._bufferedTranscripts.push(evt);
}
}
}
}
_onEndOfUtterance(cs, ep) {
@@ -993,15 +865,6 @@ class TaskGather extends SttTask {
return;
}
// Enabled action Hook delay timer to applied actions
if (this._actionHookNoResponseTimeout > 0) {
this._startActionHookNoResponseTimer();
}
if (this._actionHookNoResponseGiveUpTimeout > 0) {
this._startActionHookNoResponseGiveUpTimer();
}
try {
if (reason.startsWith('dtmf')) {
if (this.parentTask) this.parentTask.emit('dtmf', evt);
@@ -1032,11 +895,6 @@ class TaskGather extends SttTask {
}
}
} catch (err) { /*already logged error*/ }
// Gather got response from hook, cancel all delay timers if there is any
this._clearActionHookNoResponseTimer();
this._clearActionHookNoResponseGiveUpTimer();
this.notifyTaskDone();
}
}

View File

@@ -103,7 +103,7 @@ class TaskSay extends Task {
voice = this.options.voice_id || voice;
}
ep.set({
this.ep.set({
tts_engine: vendor,
tts_voice: voice,
cache_speech_handles: 1,
@@ -179,7 +179,7 @@ class TaskSay extends Task {
}
else {
this.logger.debug('a streaming tts api will be used');
const modifiedPath = filePath.replace('say:{', `say:{session-uuid=${ep.uuid},`);
const modifiedPath = filePath.replace('say:{', `say:{session-uuid=${this.ep.uuid},`);
return modifiedPath;
}
return filePath;
@@ -261,12 +261,12 @@ class TaskSay extends Task {
}
this.notifyStatus({event: 'start-playback'});
while (!this.killed && (this.loop === 'forever' || this.loop--) && ep?.connected) {
while (!this.killed && (this.loop === 'forever' || this.loop--) && this.ep?.connected) {
let segment = 0;
while (!this.killed && segment < filepath.length) {
if (cs.isInConference) {
const {memberId, confName, confUuid} = cs;
await this.playToConfMember(ep, memberId, confName, confUuid, filepath[segment]);
await this.playToConfMember(this.ep, memberId, confName, confUuid, filepath[segment]);
}
else {
if (filepath[segment].startsWith('say:{')) {
@@ -274,7 +274,7 @@ class TaskSay extends Task {
if (arr) this.logger.debug(`Say:exec sending streaming tts request: ${arr[1].substring(0, 64)}..`);
}
else this.logger.debug(`Say:exec sending ${filepath[segment].substring(0, 64)}`);
ep.once('playback-start', (evt) => {
this.ep.once('playback-start', (evt) => {
this.logger.debug({evt}, 'got playback-start');
if (this.otelSpan) {
this.logger.debug({evt}, 'got playback-start');
@@ -284,7 +284,7 @@ class TaskSay extends Task {
if (evt.variable_tts_cache_filename) cs.trackTmpFile(evt.variable_tts_cache_filename);
}
});
ep.once('playback-stop', (evt) => {
this.ep.once('playback-stop', (evt) => {
this.logger.debug({evt}, 'got playback-stop');
if (evt.variable_tts_error) {
writeAlerts({
@@ -321,7 +321,7 @@ class TaskSay extends Task {
async kill(cs) {
super.kill(cs);
if (this.ep?.connected) {
if (this.ep.connected) {
this.logger.debug('TaskSay:kill - killing audio');
if (cs.isInConference) {
const {memberId, confName} = cs;

View File

@@ -173,13 +173,6 @@ class Task extends Emitter {
* first new set of verbs arrive after sending a transcript
* */
this.emit('VerbHookSpanWaitForEnd', {span});
// 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 (expectResponse && json && Array.isArray(json)) {
const makeTask = require('./make_task');

View File

@@ -30,7 +30,6 @@
"Transcribe": "transcribe"
},
"AllowedSipRecVerbs": ["config", "gather", "transcribe", "listen", "tag"],
"AllowedConfirmSessionVerbs": ["config", "gather", "plays", "say", "tag"],
"CallStatus": {
"Trying": "trying",
"Ringing": "ringing",

View File

@@ -16,6 +16,7 @@ const uuidv4 = require('uuid-random');
const HttpRequestor = require('./http-requestor');
const WsRequestor = require('./ws-requestor');
const {makeOpusFirst} = require('./sdp-utils');
const listTaskNames = require('./summarize-tasks');
const {
JAMBONES_USE_FREESWITCH_TIMER_FD
} = require('../config');
@@ -353,7 +354,6 @@ class SingleDialer extends Emitter {
const json = await this.requestor.request('dial:confirm', confirmHook, this.callInfo.toJSON());
if (!json || (Array.isArray(json) && json.length === 0)) {
this.logger.info('SingleDialer:_executeApp: no tasks returned from confirm hook');
this.emit('accept');
return;
}
const tasks = normalizeJambones(this.logger, json).map((tdata) => makeTask(this.logger, tdata));
@@ -392,7 +392,7 @@ class SingleDialer extends Emitter {
}
}
async doAdulting({logger, tasks, application}) {
async doAdulting({logger, tasks, application, call_hook_url}) {
this.adulting = true;
this.emit('adulting');
if (this.ep) {
@@ -411,6 +411,9 @@ class SingleDialer extends Emitter {
//clone application from parent call with new requestor
//parrent application will be closed in case the parent hangup
const app = {...application};
if (call_hook_url) {
app.call_hook.url = call_hook_url;
}
if ('WS' === app.call_hook?.method ||
app.call_hook?.url.startsWith('ws://') || app.call_hook?.url.startsWith('wss://')) {
const requestor = new WsRequestor(logger, this.accountInfo.account.account_sid,
@@ -427,6 +430,16 @@ class SingleDialer extends Emitter {
this.accountInfo.account.webhook_secret);
else app.notifier = {request: () => {}, close: () => {}};
}
// Time to open session:new for adulting call
// If ws is used, open session:new to control the call later.
if (!tasks || tasks.length === 0 || app.requestor instanceof WsRequestor) {
const b3 = rootSpan?.getTracingPropagation();
const httpHeaders = b3 && {b3};
const newTask = await app.requestor.request(
'session:new', call_hook_url, this.callInfo.toJSON(), httpHeaders);
tasks = normalizeJambones(newLogger, newTask).map((tdata) => makeTask(newLogger, tdata));
newLogger.info({tasks: listTaskNames(tasks)}, 'SingleDialer:doAdulting new task list for adulting call');
}
// Replace old application with new application.
this.application = app;
const cs = new AdultingCallSession({

28
package-lock.json generated
View File

@@ -35,7 +35,7 @@
"drachtio-srf": "^4.5.31",
"express": "^4.18.2",
"express-validator": "^7.0.1",
"ip": "^1.1.9",
"ip": "^1.1.8",
"moment": "^2.29.4",
"parse-url": "^8.1.0",
"pino": "^8.8.0",
@@ -45,7 +45,7 @@
"short-uuid": "^4.2.2",
"sinon": "^15.0.1",
"to-snake-case": "^1.0.0",
"undici": "^5.28.3",
"undici": "^5.26.2",
"uuid-random": "^1.3.2",
"verify-aws-sns-signature": "^0.1.0",
"ws": "^8.9.0",
@@ -7764,9 +7764,9 @@
}
},
"node_modules/ip": {
"version": "1.1.9",
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.9.tgz",
"integrity": "sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ=="
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz",
"integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg=="
},
"node_modules/ip6addr": {
"version": "0.2.5",
@@ -10841,9 +10841,9 @@
}
},
"node_modules/undici": {
"version": "5.28.3",
"resolved": "https://registry.npmjs.org/undici/-/undici-5.28.3.tgz",
"integrity": "sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==",
"version": "5.26.2",
"resolved": "https://registry.npmjs.org/undici/-/undici-5.26.2.tgz",
"integrity": "sha512-a4PDLQgLTPHVzOK+x3F79/M4GtyYPl+aX9AAK7aQxpwxDwCqkeZCScy7Gk5kWT3JtdFq1uhO3uZJdLtHI4dK9A==",
"dependencies": {
"@fastify/busboy": "^2.0.0"
},
@@ -17485,9 +17485,9 @@
}
},
"ip": {
"version": "1.1.9",
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.9.tgz",
"integrity": "sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ=="
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz",
"integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg=="
},
"ip6addr": {
"version": "0.2.5",
@@ -19822,9 +19822,9 @@
}
},
"undici": {
"version": "5.28.3",
"resolved": "https://registry.npmjs.org/undici/-/undici-5.28.3.tgz",
"integrity": "sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==",
"version": "5.26.2",
"resolved": "https://registry.npmjs.org/undici/-/undici-5.26.2.tgz",
"integrity": "sha512-a4PDLQgLTPHVzOK+x3F79/M4GtyYPl+aX9AAK7aQxpwxDwCqkeZCScy7Gk5kWT3JtdFq1uhO3uZJdLtHI4dK9A==",
"requires": {
"@fastify/busboy": "^2.0.0"
}

View File

@@ -51,7 +51,7 @@
"drachtio-srf": "^4.5.31",
"express": "^4.18.2",
"express-validator": "^7.0.1",
"ip": "^1.1.9",
"ip": "^1.1.8",
"moment": "^2.29.4",
"parse-url": "^8.1.0",
"pino": "^8.8.0",
@@ -61,7 +61,7 @@
"short-uuid": "^4.2.2",
"sinon": "^15.0.1",
"to-snake-case": "^1.0.0",
"undici": "^5.28.3",
"undici": "^5.26.2",
"uuid-random": "^1.3.2",
"verify-aws-sns-signature": "^0.1.0",
"ws": "^8.9.0",

View File

@@ -42,7 +42,7 @@ services:
ipv4_address: 172.38.0.7
drachtio:
image: drachtio/drachtio-server:0.8.25-rc8
image: drachtio/drachtio-server:0.8.24
restart: always
command: drachtio --contact "sip:*;transport=udp" --mtu 4096 --address 0.0.0.0 --port 9022
ports:
@@ -57,7 +57,7 @@ services:
condition: service_healthy
freeswitch:
image: drachtio/drachtio-freeswitch-mrf:0.6.2
image: drachtio/drachtio-freeswitch-mrf:0.6.1
restart: always
command: freeswitch --rtp-range-start 20000 --rtp-range-end 20100
environment: