mirror of
https://github.com/jambonz/jambonz-feature-server.git
synced 2025-12-20 16:50:39 +00:00
add support for live call control
This commit is contained in:
@@ -56,10 +56,10 @@ class TaskDial extends Task {
|
||||
this.confirmMethod = this.data.confirmMethod;
|
||||
|
||||
if (this.data.listen) {
|
||||
this.listenTask = makeTask(logger, {'listen': this.data.listen});
|
||||
this.listenTask = makeTask(logger, {'listen': this.data.listen}, this);
|
||||
}
|
||||
if (this.data.transcribe) {
|
||||
this.transcribeTask = makeTask(logger, {'transcribe' : this.data.transcribe});
|
||||
this.transcribeTask = makeTask(logger, {'transcribe' : this.data.transcribe}, this);
|
||||
}
|
||||
|
||||
this.results = {};
|
||||
@@ -131,7 +131,7 @@ class TaskDial extends Task {
|
||||
|
||||
const sbcAddress = cs.direction === CallDirection.Inbound ?
|
||||
`${req.source_address}:${req.source_port}` :
|
||||
config.get('sbcAddress');
|
||||
config.get('outdials.sbc');
|
||||
const opts = {
|
||||
headers: req && req.has('X-CID') ? Object.assign(this.headers, {'X-CID': req.get('X-CID')}) : this.headers,
|
||||
proxy: `sip:${sbcAddress}`,
|
||||
@@ -268,8 +268,8 @@ class TaskDial extends Task {
|
||||
dialCallSid: sd.callSid,
|
||||
});
|
||||
|
||||
if (this.transcribeTask) this.transcribeTask.exec(cs, this.ep, this);
|
||||
if (this.listenTask) this.listenTask.exec(cs, this.ep, this);
|
||||
if (this.transcribeTask) this.transcribeTask.exec(cs, this.ep);
|
||||
if (this.listenTask) this.listenTask.exec(cs, this.ep);
|
||||
}
|
||||
|
||||
_bridgeEarlyMedia(sd) {
|
||||
|
||||
@@ -16,10 +16,11 @@ class TaskListen extends Task {
|
||||
this.mixType = this.mixType || 'mono';
|
||||
this.sampleRate = this.sampleRate || 8000;
|
||||
this.earlyMedia = this.data.earlyMedia === true;
|
||||
this.hook = this.normalizeUrl(this.url, 'GET', this.wsAuth);
|
||||
this.nested = typeof parentTask !== 'undefined';
|
||||
this.parentTask = parentTask;
|
||||
this.nested = parentTask instanceof Task;
|
||||
|
||||
this.results = {};
|
||||
this.ranToCompletion = false;
|
||||
|
||||
if (this.transcribe) this.transcribeTask = makeTask(logger, {'transcribe': opts.transcribe}, this);
|
||||
|
||||
@@ -31,15 +32,18 @@ class TaskListen extends Task {
|
||||
async exec(cs, ep) {
|
||||
super.exec(cs);
|
||||
this.ep = ep;
|
||||
|
||||
try {
|
||||
this.hook = this.normalizeUrl(this.url, 'GET', this.wsAuth);
|
||||
if (this.playBeep) await this._playBeep(ep);
|
||||
if (this.transcribeTask) {
|
||||
this.logger.debug('TaskListen:exec - starting nested transcribe task');
|
||||
this.transcribeTask.exec(cs, ep, this);
|
||||
this.transcribeTask.exec(cs, ep);
|
||||
}
|
||||
await this._startListening(cs, ep);
|
||||
await this.awaitTaskDone();
|
||||
if (this.action) await this.performAction(this.method, this.auth, this.results, !this.nested);
|
||||
const acceptNewApp = !this.nested && this.ranToCompletion;
|
||||
if (this.action) await this.performAction(this.method, this.auth, this.results, acceptNewApp);
|
||||
} catch (err) {
|
||||
this.logger.info(err, `TaskListen:exec - error ${this.url}`);
|
||||
}
|
||||
@@ -73,9 +77,8 @@ class TaskListen extends Task {
|
||||
this._initListeners(ep);
|
||||
const metadata = Object.assign(
|
||||
{sampleRate: this.sampleRate, mixType: this.mixType},
|
||||
cs.callInfo.toJSON(),
|
||||
this.nested ? this.parentTask.sd.callInfo : cs.callInfo.toJSON(),
|
||||
this.metadata);
|
||||
this.logger.debug({metadata, hook: this.hook}, 'TaskListen:_startListening');
|
||||
if (this.hook.username && this.hook.password) {
|
||||
this.logger.debug({username: this.hook.username, password: this.hook.password},
|
||||
'TaskListen:_startListening basic auth');
|
||||
@@ -94,6 +97,7 @@ class TaskListen extends Task {
|
||||
if (this.maxLength) {
|
||||
this._timer = setTimeout(() => {
|
||||
this.logger.debug(`TaskListen terminating task due to timeout of ${this.timeout}s reached`);
|
||||
this.ranToCompletion = true;
|
||||
this.kill();
|
||||
}, this.maxLength * 1000);
|
||||
}
|
||||
@@ -121,6 +125,7 @@ class TaskListen extends Task {
|
||||
if (evt.dtmf === this.finishOnKey) {
|
||||
this.logger.info(`TaskListen:_onDtmf terminating task due to dtmf ${evt.dtmf}`);
|
||||
this.results.digits = evt.dtmf;
|
||||
this.ranToCompletion = true;
|
||||
this.kill();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ const Task = require('./task');
|
||||
const {TaskName} = require('../utils/constants');
|
||||
const errBadInstruction = new Error('malformed jambonz application payload');
|
||||
|
||||
function makeTask(logger, obj) {
|
||||
function makeTask(logger, obj, parent) {
|
||||
const keys = Object.keys(obj);
|
||||
if (!keys || keys.length !== 1) {
|
||||
throw errBadInstruction;
|
||||
@@ -17,40 +17,40 @@ function makeTask(logger, obj) {
|
||||
switch (name) {
|
||||
case TaskName.SipDecline:
|
||||
const TaskSipDecline = require('./sip_decline');
|
||||
return new TaskSipDecline(logger, data);
|
||||
return new TaskSipDecline(logger, data, parent);
|
||||
case TaskName.Dial:
|
||||
const TaskDial = require('./dial');
|
||||
return new TaskDial(logger, data);
|
||||
return new TaskDial(logger, data, parent);
|
||||
case TaskName.Hangup:
|
||||
const TaskHangup = require('./hangup');
|
||||
return new TaskHangup(logger, data);
|
||||
return new TaskHangup(logger, data, parent);
|
||||
case TaskName.Say:
|
||||
const TaskSay = require('./say');
|
||||
return new TaskSay(logger, data);
|
||||
return new TaskSay(logger, data, parent);
|
||||
case TaskName.Play:
|
||||
const TaskPlay = require('./play');
|
||||
return new TaskPlay(logger, data);
|
||||
return new TaskPlay(logger, data, parent);
|
||||
case TaskName.Pause:
|
||||
const TaskPause = require('./pause');
|
||||
return new TaskPause(logger, data);
|
||||
return new TaskPause(logger, data, parent);
|
||||
case TaskName.Gather:
|
||||
const TaskGather = require('./gather');
|
||||
return new TaskGather(logger, data);
|
||||
return new TaskGather(logger, data, parent);
|
||||
case TaskName.Transcribe:
|
||||
const TaskTranscribe = require('./transcribe');
|
||||
return new TaskTranscribe(logger, data);
|
||||
return new TaskTranscribe(logger, data, parent);
|
||||
case TaskName.Listen:
|
||||
const TaskListen = require('./listen');
|
||||
return new TaskListen(logger, data);
|
||||
return new TaskListen(logger, data, parent);
|
||||
case TaskName.Redirect:
|
||||
const TaskRedirect = require('./redirect');
|
||||
return new TaskRedirect(logger, data);
|
||||
return new TaskRedirect(logger, data, parent);
|
||||
case TaskName.RestDial:
|
||||
const TaskRestDial = require('./rest_dial');
|
||||
return new TaskRestDial(logger, data);
|
||||
return new TaskRestDial(logger, data, parent);
|
||||
case TaskName.Tag:
|
||||
const TaskTag = require('./tag');
|
||||
return new TaskTag(logger, data);
|
||||
return new TaskTag(logger, data, parent);
|
||||
}
|
||||
|
||||
// should never reach
|
||||
|
||||
@@ -57,26 +57,14 @@ class Task extends Emitter {
|
||||
}
|
||||
|
||||
normalizeUrl(url, method, auth) {
|
||||
const hook = {url, method};
|
||||
if (auth && auth.username && auth.password) Object.assign(hook, auth);
|
||||
|
||||
if (url.startsWith('/')) {
|
||||
const or = this.callSession.originalRequest;
|
||||
if (or) {
|
||||
hook.url = `${or.baseUrl}${url}`;
|
||||
hook.method = hook.method || or.method || 'POST';
|
||||
if (!hook.auth && or.auth) Object.assign(hook, or.auth);
|
||||
}
|
||||
}
|
||||
this.logger.debug({hook}, 'Task:normalizeUrl');
|
||||
return hook;
|
||||
return this.callSession.normalizeUrl(url, method, auth);
|
||||
}
|
||||
|
||||
async performAction(method, auth, results, expectResponse = true) {
|
||||
if (this.action) {
|
||||
const hook = this.normalizeUrl(this.action, method, auth);
|
||||
const tasks = await this.actionHook(hook, results, expectResponse);
|
||||
if (tasks && Array.isArray(tasks)) {
|
||||
if (expectResponse && tasks && Array.isArray(tasks)) {
|
||||
this.logger.debug({tasks: tasks}, `${this.name} replacing application with ${tasks.length} tasks`);
|
||||
this.callSession.replaceApplication(tasks);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user