Compare commits

..

2 Commits

Author SHA1 Message Date
Dave Horton
1fd2e951e3 wip 2024-01-14 10:28:11 -05:00
Dave Horton
4a1af6e584 set default deepgram model by language and task (gather vs transcribe) 2024-01-14 10:21:23 -05:00
8 changed files with 52 additions and 133 deletions

View File

@@ -828,10 +828,6 @@ class CallSession extends Emitter {
const task = this.tasks.shift();
this.logger.info(`CallSession:exec starting task #${stackNum}:${taskNum}: ${task.name}`);
this._notifyTaskStatus(task, {event: 'starting'});
// Register verbhook span wait for end
task.on('VerbHookSpanWaitForEnd', ({span}) => {
this.verbHookSpan = span;
});
try {
const resources = await this._evaluatePreconditions(task);
let skip = false;
@@ -1039,7 +1035,6 @@ class CallSession extends Emitter {
/* we started a new app on the child leg, but nothing given for parent so hang him up */
this.currentTask.kill(this);
}
this._endVerbHookSpan();
}
/**
@@ -1311,7 +1306,6 @@ Duration=${duration} `
kill(onBackgroundGatherBargein = false) {
if (this.isConfirmCallSession) this.logger.debug('CallSession:kill (ConfirmSession)');
else this.logger.info('CallSession:kill');
this._endVerbHookSpan();
if (this.currentTask) {
this.currentTask.kill(this);
this.currentTask = null;
@@ -1416,7 +1410,6 @@ Duration=${duration} `
switch (command) {
case 'redirect':
if (Array.isArray(data)) {
this._endVerbHookSpan();
const t = normalizeJambones(this.logger, data)
.map((tdata) => makeTask(this.logger, tdata));
if (!queueCommand) {
@@ -1751,7 +1744,7 @@ Duration=${duration} `
res.send(200, {body: this.ep.local.sdp});
}
else {
if (this.currentTask.name === TaskName.Dial && this.currentTask.isOnHoldEnabled) {
if (this.currentTask.name === TaskName.Dial && this.currentTask.isOnHold) {
this.logger.info('onholdMusic reINVITE after media has been released');
await this.currentTask.handleReinviteAfterMediaReleased(req, res);
} else {
@@ -2080,13 +2073,6 @@ Duration=${duration} `
stopBackgroundTask(type) {
this.backgroundTaskManager.stop(type);
}
_endVerbHookSpan() {
if (this.verbHookSpan) {
this.verbHookSpan.end();
this.verbHookSpan = null;
}
}
}
module.exports = CallSession;

View File

@@ -138,14 +138,13 @@ class TaskDial extends Task {
get name() { return TaskName.Dial; }
get isOnHoldEnabled() {
return !!this.data.onHoldHook;
get isOnHold() {
return this.isIncomingLegHold || this.isOutgoingLegHold;
}
get canReleaseMedia() {
const keepAnchor = this.data.anchorMedia ||
this.cs.isBackGroundListen ||
this.cs.onHoldMusic ||
ANCHOR_MEDIA_ALWAYS ||
this.listenTask ||
this.transcribeTask ||
@@ -571,8 +570,7 @@ class TaskDial extends Task {
accountInfo: cs.accountInfo,
rootSpan: cs.rootSpan,
startSpan: this.startSpan.bind(this),
dialTask: this,
onHoldMusic: this.cs.onHoldMusic
dialTask: this
});
this.dials.set(sd.callSid, sd);
@@ -681,43 +679,22 @@ class TaskDial extends Task {
async _onReinvite(req, res) {
try {
let isHandled = false;
if (this.isOnHoldEnabled) {
if (isOnhold(req.body)) {
this.logger.debug('Dial: _onReinvite receive hold Request');
if (!this.epOther && !this.ep) {
this.logger.debug(`Dial: _onReinvite receive hold Request,
media already released, reconnect media server`);
// update caller leg for new SDP from callee.
await this.cs.handleReinviteAfterMediaReleased(req, res);
// Freeswitch media is released, reconnect
await this.reAnchorMedia(this.cs, this.sd);
this.isOutgoingLegHold = true;
} else {
this.logger.debug('Dial: _onReinvite receive hold Request, update SDP');
const newSdp = await this.ep.modify(req.body);
res.send(200, {body: newSdp});
}
if (this.cs.onHoldMusic) {
if (isOnhold(req.body) && !this.epOther && !this.ep) {
await this.cs.handleReinviteAfterMediaReleased(req, res);
// Onhold but media is already released
// reconnect A Leg and Response B leg
await this.reAnchorMedia(this.cs, this.sd);
this.isOutgoingLegHold = true;
isHandled = true;
// Media already connected, ask for onHoldHook
this._onHoldHook(req);
} else if (!isOnhold(req.body)) {
this.logger.debug('Dial: _onReinvite receive unhold Request');
if (this.epOther && this.ep && this.isOutgoingLegHold && this.canReleaseMedia) {
this.logger.debug('Dial: _onReinvite receive unhold Request, release media');
// Offhold, time to release media
const newSdp = await this.ep.modify(req.body);
await res.send(200, {body: newSdp});
await this._releaseMedia(this.cs, this.sd);
this.isOutgoingLegHold = false;
} else {
this.logger.debug('Dial: _onReinvite receive unhold Request, update media server');
const newSdp = await this.ep.modify(req.body);
res.send(200, {body: newSdp});
}
if (this._onHoldSession) {
this._onHoldSession.kill();
}
this._onHoldHook();
} else if (!isOnhold(req.body) && this.epOther && this.ep && this.isOutgoingLegHold && this.canReleaseMedia) {
// Offhold, time to release media
const newSdp = await this.ep.modify(req.body);
await res.send(200, {body: newSdp});
await this._releaseMedia(this.cs, this.sd);
isHandled = true;
this.isOutgoingLegHold = false;
}
}
if (!isHandled) {
@@ -834,34 +811,23 @@ class TaskDial extends Task {
this.epOther = cs.ep;
}
// Handle RE-INVITE hold from caller leg.
async handleReinviteAfterMediaReleased(req, res) {
let isHandled = false;
if (this.isOnHoldEnabled) {
if (isOnhold(req.body)) {
if (!this.epOther && !this.ep) {
// update callee leg for new SDP from caller.
const sdp = await this.dlg.modify(req.body);
res.send(200, {body: sdp});
// Onhold but media is already released, reconnect
await this.reAnchorMedia(this.cs, this.sd);
isHandled = true;
this.isIncomingLegHold = true;
}
this._onHoldHook(req);
} else if (!isOnhold(req.body)) {
if (this.epOther && this.ep && this.isIncomingLegHold && this.canReleaseMedia) {
// Offhold, time to release media
const newSdp = await this.epOther.modify(req.body);
await res.send(200, {body: newSdp});
await this._releaseMedia(this.cs, this.sd);
isHandled = true;
}
this.isIncomingLegHold = false;
if (this._onHoldSession) {
this._onHoldSession.kill();
}
}
if (isOnhold(req.body) && !this.epOther && !this.ep) {
const sdp = await this.dlg.modify(req.body);
res.send(200, {body: sdp});
// Onhold but media is already released
await this.reAnchorMedia(this.cs, this.sd);
isHandled = true;
this.isIncomingLegHold = true;
this._onHoldHook();
} else if (!isOnhold(req.body) && this.epOther && this.ep && this.isIncomingLegHold && this.canReleaseMedia) {
// Offhold, time to release media
const newSdp = await this.epOther.modify(req.body);
await res.send(200, {body: newSdp});
await this._releaseMedia(this.cs, this.sd);
isHandled = true;
this.isIncomingLegHold = false;
}
if (!isHandled) {
@@ -880,7 +846,7 @@ class TaskDial extends Task {
});
}
async _onHoldHook(req, allowed = [TaskName.Play, TaskName.Say, TaskName.Pause]) {
async _onHoldHook(allowed = [TaskName.Play, TaskName.Say, TaskName.Pause]) {
if (this.data.onHoldHook) {
// send silence for keep Voice quality
await this.epOther.play('silence_stream://500');
@@ -890,13 +856,7 @@ class TaskDial extends Task {
const b3 = this.getTracingPropagation();
const httpHeaders = b3 && {b3};
const json = await this.cs.application.requestor.
request('verb:hook', this.data.onHoldHook, {
...this.cs.callInfo.toJSON(),
hold_detail: {
from: req.get('From'),
to: req.get('To')
}
}, httpHeaders);
request('verb:hook', this.data.onHoldHook, this.cs.callInfo.toJSON(), httpHeaders);
const tasks = normalizeJambones(this.logger, json).map((tdata) => makeTask(this.logger, tdata));
allowedTasks = tasks.filter((t) => allowed.includes(t.name));
if (tasks.length !== allowedTasks.length) {
@@ -905,7 +865,7 @@ class TaskDial extends Task {
}
this.logger.debug(`DialTask:_onHoldHook: executing ${tasks.length} tasks`);
if (tasks.length) {
this._onHoldSession = new ConfirmCallSession({
this._playSession = new ConfirmCallSession({
logger: this.logger,
application: this.cs.application,
dlg: this.isIncomingLegHold ? this.dlg : this.cs.dlg,
@@ -915,12 +875,12 @@ class TaskDial extends Task {
tasks,
rootSpan: this.cs.rootSpan
});
await this._onHoldSession.exec();
this._onHoldSession = null;
await this._playSession.exec();
this._playSession = null;
}
} catch (error) {
this.logger.info(error, 'DialTask:_onHoldHook: failed retrieving waitHook');
this._onHoldSession = null;
this._playSession = null;
break;
}
} while (allowedTasks && allowedTasks.length > 0 && !this.killed && this.isOnHold);

View File

@@ -686,9 +686,6 @@ class TaskGather extends SttTask {
this.logger.debug('TaskGather:_onTranscription - got speech_final waiting for UtteranceEnd event');
return;
}
/* deepgram can send an empty and final transcript; only if we have any buffered should we resolve */
if (this._bufferedTranscripts.length === 0) return;
this.logger.debug({evt}, 'TaskGather:_onTranscription - compiling deepgram transcripts');
evt = this.consolidateTranscripts(this._bufferedTranscripts, 1, this.language);
this._bufferedTranscripts = [];

View File

@@ -162,17 +162,7 @@ class Task extends Emitter {
try {
const json = await this.cs.requestor.request(type, this.actionHook, params, httpHeaders);
span.setAttributes({'http.statusCode': 200});
const isWsConnection = this.cs.requestor instanceof WsRequestor;
if (!isWsConnection || (expectResponse && json && Array.isArray(json) && json.length)) {
span.end();
} else {
/** we use this span to measure application response latency,
* and with websocket connections we generally get the application's response
* in a subsequent message from the far end, so we terminate the span when the
* first new set of verbs arrive after sending a transcript
* */
this.emit('VerbHookSpanWaitForEnd', {span});
}
span.end();
if (expectResponse && json && Array.isArray(json)) {
const makeTask = require('./make_task');
const tasks = normalizeJambones(this.logger, json).map((tdata) => makeTask(this.logger, tdata));

View File

@@ -18,8 +18,7 @@ const WsRequestor = require('./ws-requestor');
const {makeOpusFirst} = require('./sdp-utils');
class SingleDialer extends Emitter {
constructor({logger, sbcAddress, target, opts, application, callInfo, accountInfo, rootSpan, startSpan, dialTask,
onHoldMusic}) {
constructor({logger, sbcAddress, target, opts, application, callInfo, accountInfo, rootSpan, startSpan, dialTask}) {
super();
assert(target.type);
@@ -42,7 +41,6 @@ class SingleDialer extends Emitter {
this.callSid = uuidv4();
this.dialTask = dialTask;
this.onHoldMusic = onHoldMusic;
this.on('callStatusChange', this._notifyCallStatusChange.bind(this));
}
@@ -133,7 +131,6 @@ class SingleDialer extends Emitter {
this.serviceUrl = srf.locals.serviceUrl;
this.ep = await ms.createEndpoint();
this._configMsEndpoint();
this.logger.debug(`SingleDialer:exec - created endpoint ${this.ep.uuid}`);
/**
@@ -256,7 +253,7 @@ class SingleDialer extends Emitter {
.on('modify', async(req, res) => {
try {
if (this.ep) {
if (this.dialTask && this.dialTask.isOnHoldEnabled) {
if (this.dialTask && this.dialTask.isOnHold) {
this.logger.info('dial is onhold, emit event');
this.emit('reinvite', req, res);
} else {
@@ -323,12 +320,6 @@ class SingleDialer extends Emitter {
}
}
_configMsEndpoint() {
if (this.onHoldMusic) {
this.ep.set({hold_music: `shout://${this.onHoldMusic.replace(/^https?:\/\//, '')}`});
}
}
/**
* Run an application on the call after answer, e.g. call screening.
* Once the application completes in some fashion, emit an 'accepted' event
@@ -445,7 +436,6 @@ class SingleDialer extends Emitter {
async reAnchorMedia() {
assert(this.dlg && this.dlg.connected && !this.ep);
this.ep = await this.ms.createEndpoint({remoteSdp: this.dlg.remote.sdp});
this._configMsEndpoint();
await this.dlg.modify(this.ep.local.sdp, {
headers: {
'X-Reason': 'anchor-media'
@@ -476,12 +466,11 @@ class SingleDialer extends Emitter {
}
function placeOutdial({
logger, srf, ms, sbcAddress, target, opts, application, callInfo, accountInfo, rootSpan, startSpan, dialTask,
onHoldMusic
logger, srf, ms, sbcAddress, target, opts, application, callInfo, accountInfo, rootSpan, startSpan, dialTask
}) {
const myOpts = deepcopy(opts);
const sd = new SingleDialer({
logger, sbcAddress, target, myOpts, application, callInfo, accountInfo, rootSpan, startSpan, dialTask, onHoldMusic
logger, sbcAddress, target, myOpts, application, callInfo, accountInfo, rootSpan, startSpan, dialTask
});
sd.exec(srf, ms, myOpts);
return sd;

View File

@@ -560,9 +560,6 @@ module.exports = (logger) => {
}),
...(sttCredentials.use_custom_stt && sttCredentials.custom_stt_endpoint &&
{AZURE_SERVICE_ENDPOINT_ID: sttCredentials.custom_stt_endpoint}),
//azureSttEndpointId overrides sttCredentials.custom_stt_endpoint
...(rOpts.azureSttEndpointId &&
{AZURE_SERVICE_ENDPOINT_ID: rOpts.azureSttEndpointId}),
};
}
else if ('nuance' === vendor) {

14
package-lock.json generated
View File

@@ -11,7 +11,7 @@
"dependencies": {
"@aws-sdk/client-auto-scaling": "^3.360.0",
"@aws-sdk/client-sns": "^3.360.0",
"@jambonz/db-helpers": "^0.9.3",
"@jambonz/db-helpers": "^0.9.1",
"@jambonz/http-health-check": "^0.0.1",
"@jambonz/mw-registrar": "^0.2.4",
"@jambonz/realtimedb-helpers": "^0.8.7",
@@ -3392,9 +3392,9 @@
}
},
"node_modules/@jambonz/db-helpers": {
"version": "0.9.3",
"resolved": "https://registry.npmjs.org/@jambonz/db-helpers/-/db-helpers-0.9.3.tgz",
"integrity": "sha512-3XFs7NC7J7Q/eb1CwG1YJHa6N4elh8IP/4hMMDgoM9U5Loplx61XI4nZ58FIrY3C/F6gEF4UdjqKvbusEVw7cQ==",
"version": "0.9.1",
"resolved": "https://registry.npmjs.org/@jambonz/db-helpers/-/db-helpers-0.9.1.tgz",
"integrity": "sha512-asQQdeQEl1jCyQAxp2kMljZzExQbcG/mBxVYA2Jf0E1ReZctC206LWMWmY/rvbSHHXNZBzJlNxhD0dQB+FtJYA==",
"dependencies": {
"cidr-matcher": "^2.1.1",
"debug": "^4.3.4",
@@ -14779,9 +14779,9 @@
"dev": true
},
"@jambonz/db-helpers": {
"version": "0.9.3",
"resolved": "https://registry.npmjs.org/@jambonz/db-helpers/-/db-helpers-0.9.3.tgz",
"integrity": "sha512-3XFs7NC7J7Q/eb1CwG1YJHa6N4elh8IP/4hMMDgoM9U5Loplx61XI4nZ58FIrY3C/F6gEF4UdjqKvbusEVw7cQ==",
"version": "0.9.1",
"resolved": "https://registry.npmjs.org/@jambonz/db-helpers/-/db-helpers-0.9.1.tgz",
"integrity": "sha512-asQQdeQEl1jCyQAxp2kMljZzExQbcG/mBxVYA2Jf0E1ReZctC206LWMWmY/rvbSHHXNZBzJlNxhD0dQB+FtJYA==",
"requires": {
"cidr-matcher": "^2.1.1",
"debug": "^4.3.4",

View File

@@ -27,7 +27,7 @@
"dependencies": {
"@aws-sdk/client-auto-scaling": "^3.360.0",
"@aws-sdk/client-sns": "^3.360.0",
"@jambonz/db-helpers": "^0.9.3",
"@jambonz/db-helpers": "^0.9.1",
"@jambonz/http-health-check": "^0.0.1",
"@jambonz/mw-registrar": "^0.2.4",
"@jambonz/realtimedb-helpers": "^0.8.7",