Feature/siprec server (#143)

* fixes from testing

* modify Task#exec to take resources as an object rather than argument list

* pass 2 endpoints to Transcribe when invoked in a SipRec call session

* logging

* change siprec invite to sendrecv just so freeswitch does not try to reinvite (TODO: block outgoing media at rtpengine)

* Config: when enabling recording, block until siprec dialog is established

* missed play verb in commit 031c79d

* linting

* bugfix: get final transcript in siprec call
This commit is contained in:
Dave Horton
2022-08-09 15:23:55 +02:00
committed by GitHub
parent f068aa5390
commit 3298918322
24 changed files with 87 additions and 65 deletions

View File

@@ -72,7 +72,7 @@ class Conference extends Task {
get shouldRecord() { return this.record.path; }
get isRecording() { return this.recordingInProgress; }
async exec(cs, ep) {
async exec(cs, {ep}) {
await super.exec(cs);
this.ep = ep;
const dlg = cs.dlg;

View File

@@ -4,8 +4,6 @@ const {TaskName, TaskPreconditions} = require('../utils/constants');
class TaskConfig extends Task {
constructor(logger, opts) {
super(logger, opts);
this.preconditions = TaskPreconditions.Endpoint;
[
'synthesizer',
'recognizer',
@@ -28,7 +26,9 @@ class TaskConfig extends Task {
});
}
if (this.bargeIn.sticky) this.autoEnable = true;
this.preconditions = this.bargeIn.enable ? TaskPreconditions.Endpoint : TaskPreconditions.None;
this.preconditions = (this.bargeIn.enable || this.record?.action) ?
TaskPreconditions.Endpoint :
TaskPreconditions.None;
}
get name() { return TaskName.Config; }
@@ -108,7 +108,13 @@ class TaskConfig extends Task {
cs.disableBotMode();
}
}
if (this.record.action) cs.notifyRecordOptions(this.record);
if (this.record.action) {
try {
await cs.notifyRecordOptions(this.record);
} catch (err) {
this.logger.info({err}, 'Config: error starting recording');
}
}
}
async kill(cs) {

View File

@@ -23,7 +23,7 @@ class TaskDequeue extends Task {
get name() { return TaskName.Dequeue; }
async exec(cs, ep) {
async exec(cs, {ep}) {
await super.exec(cs);
this.ep = ep;
this.queueName = `queue:${cs.accountSid}:${this.queueName}`;

View File

@@ -248,7 +248,7 @@ class TaskDial extends Task {
const {span, ctx} = this.startChildSpan(`whisper:${task.summary}`);
task.span = span;
task.ctx = ctx;
await task.exec(cs, callSid === this.callSid ? this.ep : this.epOther);
await task.exec(cs, callSid === this.callSid ? {ep: this.ep} : {ep: this.epOther});
span.end();
}
this.logger.debug('Dial:whisper tasks complete');
@@ -631,8 +631,8 @@ class TaskDial extends Task {
if (this.parentDtmfCollector) this._installDtmfDetection(cs, cs.dlg);
if (this.childDtmfCollector) this._installDtmfDetection(cs, this.dlg);
if (this.transcribeTask) this.transcribeTask.exec(cs, this.epOther, this.ep);
if (this.listenTask) this.listenTask.exec(cs, this.epOther);
if (this.transcribeTask) this.transcribeTask.exec(cs, {ep2: this.epOther, ep:this.ep});
if (this.listenTask) this.listenTask.exec(cs, {ep: this.epOther});
if (this.startAmd) {
try {
this.startAmd(cs, this.ep, this, this.data.amd);

View File

@@ -64,7 +64,7 @@ class Dialogflow extends Task {
get name() { return TaskName.Dialogflow; }
async exec(cs, ep) {
async exec(cs, {ep}) {
await super.exec(cs);
try {

View File

@@ -12,7 +12,7 @@ class TaskDtmf extends Task {
get name() { return TaskName.Dtmf; }
async exec(cs, ep) {
async exec(cs, {ep}) {
await super.exec(cs);
this.ep = ep;
try {

View File

@@ -37,7 +37,7 @@ class TaskEnqueue extends Task {
get name() { return TaskName.Enqueue; }
async exec(cs, ep) {
async exec(cs, {ep}) {
await super.exec(cs);
const dlg = cs.dlg;
this.queueName = `queue:${cs.accountSid}:${this.queueName}`;

View File

@@ -116,7 +116,7 @@ class TaskGather extends Task {
return s;
}
async exec(cs, ep) {
async exec(cs, {ep}) {
this.logger.debug('Gather:exec');
await super.exec(cs);
const {updateSpeechCredentialLastUsed} = require('../utils/db-utils')(this.logger, cs.srf);
@@ -164,7 +164,7 @@ class TaskGather extends Task {
const {span, ctx} = this.startChildSpan(`nested:${this.sayTask.summary}`);
this.sayTask.span = span;
this.sayTask.ctx = ctx;
this.sayTask.exec(cs, ep); // kicked off, _not_ waiting for it to complete
this.sayTask.exec(cs, {ep}); // kicked off, _not_ waiting for it to complete
this.sayTask.on('playDone', (err) => {
span.end();
if (err) this.logger.error({err}, 'Gather:exec Error playing tts');
@@ -176,7 +176,7 @@ class TaskGather extends Task {
const {span, ctx} = this.startChildSpan(`nested:${this.playTask.summary}`);
this.playTask.span = span;
this.playTask.ctx = ctx;
this.playTask.exec(cs, ep); // kicked off, _not_ waiting for it to complete
this.playTask.exec(cs, {ep}); // kicked off, _not_ waiting for it to complete
this.playTask.on('playDone', (err) => {
span.end();
if (err) this.logger.error({err}, 'Gather:exec Error playing url');

View File

@@ -14,7 +14,7 @@ class TaskHangup extends Task {
/**
* Hangup the call
*/
async exec(cs, dlg) {
async exec(cs, {dlg}) {
await super.exec(cs);
try {
await dlg.destroy({headers: this.headers});

View File

@@ -8,7 +8,7 @@ class TaskLeave extends Task {
get name() { return TaskName.Leave; }
async exec(cs, ep) {
async exec(cs, {ep}) {
await super.exec(cs);
await this.awaitTaskDone();
}

View File

@@ -44,7 +44,7 @@ class Lex extends Task {
get name() { return TaskName.Lex; }
async exec(cs, ep) {
async exec(cs, {ep}) {
await super.exec(cs);
try {

View File

@@ -26,7 +26,7 @@ class TaskListen extends Task {
get name() { return TaskName.Listen; }
async exec(cs, ep) {
async exec(cs, {ep}) {
await super.exec(cs);
this.ep = ep;
this._dtmfHandler = this._onDtmf.bind(this, ep);
@@ -40,7 +40,7 @@ class TaskListen extends Task {
const {span, ctx} = this.startChildSpan(`nested:${this.transcribeTask.summary}`);
this.transcribeTask.span = span;
this.transcribeTask.ctx = ctx;
this.transcribeTask.exec(cs, ep)
this.transcribeTask.exec(cs, {ep})
.then((result) => span.end())
.catch((err) => span.end());
}
@@ -219,7 +219,7 @@ class TaskListen extends Task {
this.logger.debug('Listen:whisper tasks starting');
while (tasks.length && !cs.callGone) {
const task = tasks.shift();
await task.exec(cs, this.ep);
await task.exec(cs, {ep: this.ep});
}
this.logger.debug('Listen:whisper tasks complete');
} catch (err) {

View File

@@ -10,7 +10,7 @@ class TaskPause extends Task {
get name() { return TaskName.Pause; }
async exec(cs, ep) {
async exec(cs) {
await super.exec(cs);
this.timer = setTimeout(this.notifyTaskDone.bind(this), this.length * 1000);
await this.awaitTaskDone();

View File

@@ -17,7 +17,7 @@ class TaskPlay extends Task {
return `${this.name}:{url=${this.url}}`;
}
async exec(cs, ep) {
async exec(cs, {ep}) {
await super.exec(cs);
this.ep = ep;
try {

View File

@@ -20,7 +20,7 @@ class Rasa extends Task {
return this.reportedFinalAction || this.isReplacingApplication;
}
async exec(cs, ep) {
async exec(cs, {ep}) {
await super.exec(cs);
this.ep = ep;
@@ -34,7 +34,7 @@ class Rasa extends Task {
const {span, ctx} = this.startChildSpan(`nested:${this.gatherTask.summary}`);
this.gatherTask.span = span;
this.gatherTask.ctx = ctx;
this.gatherTask.exec(cs, ep, this)
this.gatherTask.exec(cs, {ep})
.then(() => span.end())
.catch((err) => {
span.end();
@@ -128,7 +128,7 @@ class Rasa extends Task {
const {span, ctx} = this.startChildSpan(`nested:${this.gatherTask.summary}`);
this.gatherTask.span = span;
this.gatherTask.ctx = ctx;
this.gatherTask.exec(cs, ep, this)
this.gatherTask.exec(cs, {ep})
.then(() => span.end())
.catch((err) => {
span.end();

View File

@@ -23,7 +23,7 @@ class TaskSayLegacy extends Task {
get name() { return TaskName.SayLegacy; }
async exec(cs, ep) {
async exec(cs, {ep}) {
super.exec(cs);
this.ep = ep;
try {

View File

@@ -22,7 +22,7 @@ class TaskSay extends Task {
return `${this.name}{${this.text[0]}}`;
}
async exec(cs, ep) {
async exec(cs, {ep}) {
await super.exec(cs);
const {srf} = cs;

View File

@@ -17,7 +17,7 @@ class TaskSipRequest extends Task {
get name() { return TaskName.SipRequest; }
async exec(cs, dlg) {
async exec(cs, {dlg}) {
super.exec(cs);
try {
this.logger.info({dlg}, `TaskSipRequest: sending a SIP ${this.method}`);

View File

@@ -58,7 +58,7 @@ class TaskTranscribe extends Task {
get name() { return TaskName.Transcribe; }
async exec(cs, ep, ep2) {
async exec(cs, {ep, ep2}) {
super.exec(cs);
const {updateSpeechCredentialLastUsed} = require('../utils/db-utils')(this.logger, cs.srf);
@@ -80,7 +80,9 @@ class TaskTranscribe extends Task {
throw new Error('no provisioned speech credentials for TTS');
}
await this._startTranscribing(cs, ep, 1);
if (this.separateRecognitionPerChannel && ep2) await this._startTranscribing(cs, ep2, 2);
if (this.separateRecognitionPerChannel && ep2) {
await this._startTranscribing(cs, ep2, 2);
}
updateSpeechCredentialLastUsed(this.sttCredentials.speech_credential_sid)
.catch(() => {/*already logged error */});
@@ -102,18 +104,21 @@ class TaskTranscribe extends Task {
async kill(cs) {
super.kill(cs);
let stopTranscription = false;
if (this.ep?.connected) {
stopTranscription = true;
this.ep.stopTranscription({vendor: this.vendor})
.catch((err) => this.logger.info(err, 'Error TaskTranscribe:kill'));
// hangup after 1 sec if we don't get a final transcription
this._timer = setTimeout(() => this.notifyTaskDone(), 1000);
}
if (this.separateRecognitionPerChannel && this.ep2 && this.ep2.connected) {
stopTranscription = true;
this.ep2.stopTranscription({vendor: this.vendor})
.catch((err) => this.logger.info(err, 'Error TaskTranscribe:kill'));
}
// hangup after 1 sec if we don't get a final transcription
if (stopTranscription) this._timer = setTimeout(() => this.notifyTaskDone(), 1500);
else this.notifyTaskDone();
await this.awaitTaskDone();
}