diff --git a/lib/session/call-session.js b/lib/session/call-session.js index 58e7d2f9..c389124a 100644 --- a/lib/session/call-session.js +++ b/lib/session/call-session.js @@ -950,6 +950,12 @@ class CallSession extends Emitter { this.ttsStreamingBuffer?.start(); } + stopTtsStream() { + this.requestor?.request('tts:streaming-event', '/streaming-event', {event_type: 'stream_closed'}) + .catch((err) => this.logger.info({err}, 'CallSession:clearTtsStream - Error sending user_interruption')); + this.ttsStreamingBuffer?.stop(); + } + async enableBotMode(gather, autoEnable) { try { let task; @@ -1272,6 +1278,7 @@ class CallSession extends Emitter { this.ttsStreamingBuffer.on(TtsStreamingEvents.Pause, this._onTtsStreamingPause.bind(this)); this.ttsStreamingBuffer.on(TtsStreamingEvents.Resume, this._onTtsStreamingResume.bind(this)); this.ttsStreamingBuffer.on(TtsStreamingEvents.ConnectFailure, this._onTtsStreamingConnectFailure.bind(this)); + this.ttsStreamingBuffer.on(TtsStreamingEvents.Connected, this._onTtsStreamingConnected.bind(this)); } else { this.logger.info(`CallSession:exec - not a normal call session: ${this.constructor.name}`); @@ -2556,7 +2563,7 @@ Duration=${duration} ` this.backgroundTaskManager.stopAll(); this.clearOrRestoreActionHookDelayProcessor().catch((err) => {}); - this.ttsStreamingBuffer?.stop(); + this.stopTtsStream(); this.sttLatencyCalculator?.stop(); } @@ -3103,6 +3110,11 @@ Duration=${duration} ` } } + _onTtsStreamingConnected() { + this.requestor?.request('tts:streaming-event', '/streaming-event', {event_type: 'stream_open'}) + .catch((err) => this.logger.info({err}, 'CallSession:_onTtsStreamingConnected - Error sending')); + } + _onTtsStreamingEmpty() { const task = this.currentTask; if (task && TaskName.Say === task.name) { diff --git a/lib/tasks/say.js b/lib/tasks/say.js index 2281e1e5..44709172 100644 --- a/lib/tasks/say.js +++ b/lib/tasks/say.js @@ -145,9 +145,6 @@ class TaskSay extends TtsTask { await cs.startTtsStream(); - cs.requestor?.request('tts:streaming-event', '/streaming-event', {event_type: 'stream_open'}) - .catch((err) => this.logger.info({err}, 'TaskSay:handlingStreaming - Error sending')); - if (this.text.length !== 0) { this.logger.info('TaskSay:handlingStreaming - sending text to TTS stream'); for (const t of this.text) { @@ -447,8 +444,8 @@ class TaskSay extends TtsTask { const {memberId, confName} = cs; this.killPlayToConfMember(this.ep, memberId, confName); } else if (this.isStreamingTts) { - this.logger.debug('TaskSay:kill - clearing TTS stream for streaming audio'); - cs.clearTtsStream(); + this.logger.debug('TaskSay:kill - stopping TTS stream for streaming audio'); + cs.stopTtsStream(); } else { if (!this.notifiedPlayBackStop) { this.notifyStatus({event: 'stop-playback'}); diff --git a/lib/utils/constants.json b/lib/utils/constants.json index 79d3c8ba..e6e3176d 100644 --- a/lib/utils/constants.json +++ b/lib/utils/constants.json @@ -335,7 +335,8 @@ "Empty": "tts_streaming::empty", "Pause": "tts_streaming::pause", "Resume": "tts_streaming::resume", - "ConnectFailure": "tts_streaming::connect_failed" + "ConnectFailure": "tts_streaming::connect_failed", + "Connected": "tts_streaming::connected" }, "TtsStreamingConnectionStatus": { "NotConnected": "not_connected", diff --git a/lib/utils/tts-streaming-buffer.js b/lib/utils/tts-streaming-buffer.js index b2f39563..b397aeeb 100644 --- a/lib/utils/tts-streaming-buffer.js +++ b/lib/utils/tts-streaming-buffer.js @@ -80,7 +80,7 @@ class TtsStreamingBuffer extends Emitter { clearTimeout(this.timer); this.removeCustomEventListeners(); if (this.ep) { - this._api(this.ep, [this.ep.uuid, 'close']) + this._api(this.ep, [this.ep.uuid, 'stop']) .catch((err) => this.logger.info({ err }, 'TtsStreamingBuffer:stop Error closing TTS streaming') ); @@ -193,10 +193,7 @@ class TtsStreamingBuffer extends Emitter { this.logger.debug('TtsStreamingBuffer:_feedQueue TTS stream is not open or no endpoint available'); return; } - if ( - this._connectionStatus === TtsStreamingConnectionStatus.NotConnected || - this._connectionStatus === TtsStreamingConnectionStatus.Failed - ) { + if (this._connectionStatus !== TtsStreamingConnectionStatus.Connected) { this.logger.debug('TtsStreamingBuffer:_feedQueue TTS stream is not connected'); return; } @@ -365,6 +362,7 @@ class TtsStreamingBuffer extends Emitter { if (this.queue.length > 0) { await this._feedQueue(); } + this.emit(TtsStreamingEvents.Connected, { vendor }); } _onConnectFailure(vendor) { @@ -415,6 +413,7 @@ class TtsStreamingBuffer extends Emitter { removeCustomEventListeners() { this.eventHandlers.forEach((h) => h.ep.removeCustomEventListener(h.event, h.handler)); + this.eventHandlers.length = 0; } _initHandlers(ep) { diff --git a/test/webhooks-tests.js b/test/webhooks-tests.js index a3f3bbe2..7fb75219 100644 --- a/test/webhooks-tests.js +++ b/test/webhooks-tests.js @@ -83,7 +83,8 @@ test('invalid jambonz json create alert tests', async(t) => { {account_sid: 'bb845d4b-83a9-4cde-a6e9-50f3743bab3f', page: 1, page_size: 25, days: 7}); let checked = false; for (let i = 0; i < data.total; i++) { - checked = data.data[i].message === 'malformed jambonz payload: must be array' + checked = data.data[i].message === 'malformed jambonz payload: must be array'; + if (checked) break; } t.ok(checked, 'alert is raised as expected'); disconnect();