wip: implemented listen, transcribe, play

This commit is contained in:
Dave Horton
2020-01-17 09:15:23 -05:00
parent 1a656f3f0e
commit 0d4c1d9d8c
24 changed files with 688 additions and 108 deletions

View File

@@ -9,6 +9,7 @@ const makeTask = require('./tasks/make_task');
const resourcesMixin = require('./utils/resources');
const moment = require('moment');
const assert = require('assert');
const Dialog = require('drachtio-srf').Dialog;
const BADPRECONDITIONS = 'preconditions not met';
class CallSession extends Emitter {
@@ -34,27 +35,34 @@ class CallSession extends Emitter {
this.hooks = notifiers(this.logger, this.callAttributes);
req.on('cancel', this._onCallerHangup.bind(this));
this.callGone = false;
req.on('cancel', this._onCallerHangup.bind(this, req));
this.on('callStatusChange', this._onCallStatusChange.bind(this));
}
get callSid() { return this.callAttributes.CallSid; }
get parentCallSid() { return this.callAttributes.CallSid; }
get actionHook() { return this.hooks.actionHook; }
get callingNumber() { return this.req.callingNumber; }
get calledNumber() { return this.req.calledNumber; }
async exec() {
let idx = 0;
while (this._executionStack.length) {
const taskList = this.currentTaskList = this._executionStack.shift();
this.logger.debug(`CallSession:exec starting task list with ${taskList.tasks.length} tasks`);
while (taskList.length) {
while (taskList.length && !this.callGone) {
const {task, callSid} = taskList.shift();
this.logger.debug(`CallSession:exec starting task #${++idx}: ${task.name}`);
try {
const resources = await this._evaluatePreconditions(task, callSid);
this.currentTask = task;
await task.exec(this, resources);
this.currentTask = null;
this.logger.debug(`CallSession:exec completed task #${idx}: ${task.name}`);
} catch (err) {
this.currentTask = null;
if (err.message.includes(BADPRECONDITIONS)) {
this.logger.info(`CallSession:exec task #${idx}: ${task.name}: ${err.message}`);
}
@@ -92,6 +100,7 @@ class CallSession extends Emitter {
}
async _evalEndpointPrecondition(task, callSid) {
if (this.callGone) new Error(`${BADPRECONDITIONS}: call gone`);
const resources = this.calls.get(callSid);
if (!resources) throw new Error(`task ${task.name} attempting to operate on unknown CallSid ${callSid}`);
if (resources.ep) return resources.ep;
@@ -105,6 +114,7 @@ class CallSession extends Emitter {
this.addResource('ms', ms);
}
const ep = await ms.createEndpoint({remoteSdp: this.req.body});
ep.cs = this;
resources.ep = ep;
if (task.earlyMedia && callSid === this.parentCallSid && this.req && !this.req.finalResponseSent) {
this.res.send(183, {body: ep.local.sdp});
@@ -112,7 +122,10 @@ class CallSession extends Emitter {
return ep;
}
const uas = await this.srf.createUAS(this.req, this.res, {localSdp: ep.local.sdp});
uas.on('destroy', this._onCallerHangup.bind(this, uas));
uas.callSid = callSid;
resources.dlg = uas;
this.logger.debug(`CallSession:_evalEndpointPrecondition - call was answered with callSid ${callSid}`);
this.calls.set(callSid, resources);
return ep;
} catch (err) {
@@ -122,13 +135,15 @@ class CallSession extends Emitter {
}
_evalStableCallPrecondition(task, callSid) {
if (this.callGone) throw new Error(`${BADPRECONDITIONS}: call gone`);
const resources = this.calls.get(callSid);
if (!resources) throw new Error(`task ${task.name} attempting to operate on unknown callSid ${callSid}`);
if (resources.dlg) throw new Error(`${BADPRECONDITIONS}: call was not answered - callSid ${callSid}`);
if (!resources.dlg) throw new Error(`${BADPRECONDITIONS}: call was not answered - callSid ${callSid}`);
return resources.dlg;
}
_evalUnansweredCallPrecondition(task, callSid) {
if (this.callGone) new Error(`${BADPRECONDITIONS}: call gone`);
if (callSid !== this.parentCallSid || !this.req) {
throw new Error(`${BADPRECONDITIONS}: no inbound call - callSid ${callSid}`);
}
@@ -152,6 +167,11 @@ class CallSession extends Emitter {
this.calls.clear();
}
/**
* These below methods are needed mainly by the dial verb, which
* deals with a variety of scenarios that can't simply be
* described by the precondition concept as other verbs can
*/
/**
* retrieve the media server and endpoint for this call, allocate them if needed
@@ -208,6 +228,7 @@ class CallSession extends Emitter {
return {ep, ms, res: this.res};
}
const dlg = await this.srf.createUAS(this.req, this.res, {localSdp: ep.local.sdp});
this.logger.debug(`CallSession:connectInboundCallToIvr - answered callSid ${this.parentCallSid}`);
this.calls.set(this.parentCallSid, {ep, dlg});
return {ep, ms, dlg};
} catch (err) {
@@ -265,10 +286,25 @@ class CallSession extends Emitter {
}
/**
* got CANCEL from inbound leg
* got CANCEL or BYE from inbound leg
*/
_onCallerHangup(evt) {
this.logger.debug('CallSession: caller hung before connection');
_onCallerHangup(obj, evt) {
this.callGone = true;
if (obj instanceof Dialog) {
this.logger.debug('CallSession: caller hung up');
/* cant destroy endpoint as current task may need to get final transcription
const resources = this.calls.get(obj.callSid);
if (resources.ep && resources.ep.connected) {
resources.ep.destroy();
resources.ep = null;
this.calls.set(obj.callSid, resources);
}
*/
}
else {
this.logger.debug('CallSession: caller hung before answer');
}
if (this.currentTask) this.currentTask.kill();
}
/**