diff --git a/lib/tasks/rest_dial.js b/lib/tasks/rest_dial.js index 9017328a..b67ca69c 100644 --- a/lib/tasks/rest_dial.js +++ b/lib/tasks/rest_dial.js @@ -3,6 +3,7 @@ const {TaskName} = require('../utils/constants'); const makeTask = require('./make_task'); const { normalizeJambones } = require('@jambonz/verb-specifications'); const DtmfCollector = require('../utils/dtmf-collector'); + /** * Manages an outdial made via REST API */ @@ -33,7 +34,6 @@ function parseDtmfOptions(logger, dtmfCapture) { return {childDtmfCollector, parentDtmfCollector}; } - class TaskRestDial extends Task { constructor(logger, opts) { super(logger, opts); @@ -48,8 +48,6 @@ class TaskRestDial extends Task { this.sipRequestWithinDialogHook = this.data.sipRequestWithinDialogHook; this.referHook = this.data.referHook; - - if (this.dtmfHook) { const {parentDtmfCollector, childDtmfCollector} = parseDtmfOptions(logger, this.data.dtmfCapture || {}); if (parentDtmfCollector) { @@ -72,7 +70,7 @@ class TaskRestDial extends Task { /** * INVITE has just been sent at this point - */ + */ async exec(cs) { await super.exec(cs); this.cs = cs; @@ -99,6 +97,10 @@ class TaskRestDial extends Task { this.canCancel = false; cs?.req?.cancel(); } + + // Remove DTMF detection + this._removeDtmfDetection(cs.dlg); + this.notifyTaskDone(); } @@ -108,6 +110,12 @@ class TaskRestDial extends Task { cs.setDialog(dlg); cs.referHook = this.referHook; this.logger.debug('TaskRestDial:_onConnect - call connected'); + + // Attach DTMF detection + if (this.parentDtmfCollector || this.childDtmfCollector) { + this._installDtmfDetection(cs, dlg); + } + if (this.sipRequestWithinDialogHook) this._initSipRequestWithinDialogHandler(cs, dlg); try { const b3 = this.getTracingPropagation(); @@ -187,6 +195,39 @@ class TaskRestDial extends Task { }); } + _installDtmfDetection(cs, dlg) { + dlg.on('info', this._onInfo.bind(this, cs, dlg)); + } + + _onInfo(cs, dlg, req, res) { + res.send(200); + if (req.get('Content-Type') !== 'application/dtmf-relay') { + return; + } + + const dtmfDetector = dlg === cs.dlg ? this.parentDtmfCollector : this.childDtmfCollector; + if (!dtmfDetector) return; + + const arr = /Signal=([0-9#*])/.exec(req.body); + if (!arr) return; + + const key = arr[1]; + const match = dtmfDetector.keyPress(key); + + if (match) { + const b3 = this.getTracingPropagation(); + const httpHeaders = b3 && {b3}; + this.logger.info({callSid: cs.callSid}, `RestDial:_onInfo triggered dtmf match: ${match}`); + + cs.requestor.request('verb:hook', this.dtmfHook, {dtmf: match, ...cs.callInfo.toJSON()}, httpHeaders) + .catch((err) => this.logger.info(err, 'RestDial:_onDtmf - error')); + } + } + + _removeDtmfDetection(dlg) { + dlg && dlg.removeAllListeners('info'); + } + _initSipRequestWithinDialogHandler(cs, dlg) { cs.sipRequestWithinDialogHook = this.sipRequestWithinDialogHook; dlg.on('info', this._onRequestWithinDialog.bind(this, cs));