From d85e302143a3b2797815716866a135c0944ec783 Mon Sep 17 00:00:00 2001 From: Dave Horton Date: Sun, 17 Nov 2024 11:06:14 -0500 Subject: [PATCH] initial changes to change media routing during call --- lib/session/call-session.js | 22 +++++++++++++++++++ lib/tasks/dial.js | 43 +++++++++++++++++++++++++++++++------ lib/utils/constants.json | 5 +++++ 3 files changed, 64 insertions(+), 6 deletions(-) diff --git a/lib/session/call-session.js b/lib/session/call-session.js index 1785eaa4..503f28dd 100644 --- a/lib/session/call-session.js +++ b/lib/session/call-session.js @@ -1589,6 +1589,18 @@ Duration=${duration} ` this.logger.info({response}, '_lccBoostAudioSignal: response from freeswitch'); } + async _lccMediaPath(opts, callSid) { + const {type} = opts; + + // only valid in a Dial verb + const task = this.currentTask; + if (!task || task.name !== TaskName.Dial) { + return this.logger.info('CallSession:_lccMediaPath - invalid command since we are not in a dial verb'); + } + task.updateMediaPath(type) + .catch((err) => this.logger.error(err, 'CallSession:_lccMediaPath')); + } + _lccToolOutput(tool_call_id, opts, callSid) { // only valid if we are in an LLM verb const task = this.currentTask; @@ -1672,6 +1684,9 @@ Duration=${duration} ` else if (opts.boostAudioSignal) { return this._lccBoostAudioSignal(opts, callSid); } + else if (opts.media_path) { + return this._lccMediaPath(opts.media_path, callSid); + } else if (opts.llm_tool_output) { return this._lccToolOutput(opts.tool_call_id, opts.llm_tool_output, callSid); } @@ -1975,6 +1990,13 @@ Duration=${duration} ` }); break; + case 'media-path': + this._lccMediaPath(data, call_sid) + .catch((err) => { + this.logger.info({err, data}, 'CallSession:_onCommand - error setting media path'); + }); + break; + case 'llm:tool-output': this._lccToolOutput(tool_call_id, data, call_sid); break; diff --git a/lib/tasks/dial.js b/lib/tasks/dial.js index 9356e5ca..c9e93c18 100644 --- a/lib/tasks/dial.js +++ b/lib/tasks/dial.js @@ -6,6 +6,7 @@ const { TaskName, TaskPreconditions, MAX_SIMRINGS, + MediaPath, KillReason } = require('../utils/constants'); const assert = require('assert'); @@ -108,6 +109,7 @@ class TaskDial extends Task { this.proxy = this.data.proxy; this.tag = this.data.tag; this.boostAudioSignal = this.data.boostAudioSignal; + this._mediaPath = MediaPath.FullMedia; if (this.dtmfHook) { const {parentDtmfCollector, childDtmfCollector} = parseDtmfOptions(logger, this.data.dtmfCapture || {}); @@ -167,7 +169,7 @@ class TaskDial extends Task { } get shouldExitMediaPathEntirely() { - return this.canReleaseMedia && this.data.exitMediaPath; + return this.data.exitMediaPath; } get summary() { @@ -307,7 +309,7 @@ class TaskDial extends Task { if (!cs.callGone && this.epOther) { /* if we can release the media back to the SBC, do so now */ - if (this.canReleaseMedia) this._releaseMedia(cs, this.sd); + if (this.canReleaseMedia) this._releaseMedia(cs, this.sd, this.shouldExitMediaPathEntirely); else this.epOther.bridge(this.ep); } } catch (err) { @@ -756,7 +758,7 @@ class TaskDial extends Task { // 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); + await this._releaseMedia(this.cs, this.sd, this.shouldExitMediaPathEntirely); this.isOutgoingLegHold = false; } else { this.logger.debug('Dial: _onReinvite receive unhold Request, update media server'); @@ -865,7 +867,7 @@ class TaskDial extends Task { } /* if we can release the media back to the SBC, do so now */ - if (this.canReleaseMedia) setTimeout(this._releaseMedia.bind(this, cs, sd), 200); + if (this.canReleaseMedia) setTimeout(this._releaseMedia.bind(this, cs, sd, this.shouldExitMediaPathEntirely), 200); } _bridgeEarlyMedia(sd) { @@ -877,12 +879,40 @@ class TaskDial extends Task { } } + /* public api */ + async updateMediaPath(type) { + switch (type) { + case 'no-media': + assert(this._mediaPath !== MediaPath.NoMedia, 'updateMediaPath: already no-media'); + await this._releaseMedia(this.cs, this.sd, true); + this._mediaPath = MediaPath.NoMedia; + break; + case 'partial-media': + assert(this._mediaPath !== MediaPath.PartialMedia, 'updateMediaPath: already partial-media'); + if (this._mediaPath === MediaPath.FullMedia) { + await this._releaseMedia(this.cs, this.sd, false); + } + else { + await this.reAnchorMedia(this.cs, this.sd); + } + this._mediaPath = MediaPath.PartialMedia; + break; + case 'full-media': + assert(this._mediaPath !== MediaPath.FullMedia, 'updateMediaPath: already full-media'); + await this.reAnchorMedia(this.cs, this.sd); + this._mediaPath = MediaPath.FullMedia; + break; + default: + assert(false, `updateMediaPath: invalid type ${type}`); + } + } + /** * Release the media from freeswitch * @param {*} cs * @param {*} sd */ - async _releaseMedia(cs, sd) { + async _releaseMedia(cs, sd, releaseEntirely = false) { assert(cs.ep && sd.ep); try { @@ -893,6 +923,7 @@ class TaskDial extends Task { await cs.releaseMediaToSBC(bLegSdp, this.shouldExitMediaPathEntirely); this.epOther = null; this.logger.info('Dial:_releaseMedia - successfully released media from freewitch'); + this._mediaPath = this.shouldExitMediaPathEntirely ? MediaPath.NoMedia : MediaPath.PartialMedia; } catch (err) { this.logger.info({err}, 'Dial:_releaseMedia error'); } @@ -926,7 +957,7 @@ class TaskDial extends Task { // 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); + await this._releaseMedia(this.cs, this.sd, this.shouldExitMediaPathEntirely); isHandled = true; } this.isIncomingLegHold = false; diff --git a/lib/utils/constants.json b/lib/utils/constants.json index 996e6819..090a7285 100644 --- a/lib/utils/constants.json +++ b/lib/utils/constants.json @@ -221,6 +221,11 @@ "ToneTimeout": "amd_tone_timeout", "Stopped": "amd_stopped" }, + "MediaPath": { + "NoMedia": "no-media", + "PartialMedia": "partial-media", + "FullMedia": "full-media" + }, "MAX_SIMRINGS": 10, "BONG_TONE": "tone_stream://v=-7;%(100,0,941.0,1477.0);v=-7;>=2;+=.1;%(1400,0,350,440)", "FS_UUID_SET_NAME": "fsUUIDs"