feat: stop command (stopAllAudio), sequential audio queue with stop support
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
a483aa6def
commit
730214d30b
2 changed files with 40 additions and 1 deletions
|
|
@ -22,6 +22,7 @@ export class AudioProcedure {
|
||||||
private _initScriptInjected: boolean = false;
|
private _initScriptInjected: boolean = false;
|
||||||
private _audioQueue: Array<{ audioData: string; format: 'mp3' | 'wav' | 'pcm' }> = [];
|
private _audioQueue: Array<{ audioData: string; format: 'mp3' | 'wav' | 'pcm' }> = [];
|
||||||
private _isPlaying: boolean = false;
|
private _isPlaying: boolean = false;
|
||||||
|
private _stopRequested: boolean = false;
|
||||||
|
|
||||||
constructor(page: Page, logger: Logger) {
|
constructor(page: Page, logger: Logger) {
|
||||||
this._page = page;
|
this._page = page;
|
||||||
|
|
@ -138,8 +139,9 @@ export class AudioProcedure {
|
||||||
private async _processAudioQueue(): Promise<void> {
|
private async _processAudioQueue(): Promise<void> {
|
||||||
if (this._isPlaying) return;
|
if (this._isPlaying) return;
|
||||||
this._isPlaying = true;
|
this._isPlaying = true;
|
||||||
|
this._stopRequested = false;
|
||||||
|
|
||||||
while (this._audioQueue.length > 0) {
|
while (this._audioQueue.length > 0 && !this._stopRequested) {
|
||||||
const item = this._audioQueue.shift()!;
|
const item = this._audioQueue.shift()!;
|
||||||
try {
|
try {
|
||||||
await this._playAudioInternal(item.audioData, item.format);
|
await this._playAudioInternal(item.audioData, item.format);
|
||||||
|
|
@ -148,7 +150,37 @@ export class AudioProcedure {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this._stopRequested) {
|
||||||
|
this._audioQueue = [];
|
||||||
|
this._logger.info('Audio queue cleared due to stop request');
|
||||||
|
}
|
||||||
|
|
||||||
this._isPlaying = false;
|
this._isPlaying = false;
|
||||||
|
this._stopRequested = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop all audio immediately: stop current playback and clear the queue.
|
||||||
|
* Called when a user says "<botname> STOP" or similar.
|
||||||
|
*/
|
||||||
|
async stopAllAudio(): Promise<void> {
|
||||||
|
this._logger.info('Stop all audio requested');
|
||||||
|
this._stopRequested = true;
|
||||||
|
this._audioQueue = [];
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this._page.evaluate(() => {
|
||||||
|
const ctx = (window as any).__ttsAudioContext as AudioContext;
|
||||||
|
if (ctx) {
|
||||||
|
// Suspend immediately stops all audio output
|
||||||
|
ctx.suspend();
|
||||||
|
// Resume after a short delay so future audio can play
|
||||||
|
setTimeout(() => ctx.resume(), 100);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
// Page might not be ready
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -334,6 +334,13 @@ export class BotOrchestrator {
|
||||||
this.sendChatMessageToMeeting(chatMsg.text);
|
this.sendChatMessageToMeeting(chatMsg.text);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'stopAudio':
|
||||||
|
this._logger.info('Stop audio command received from Gateway');
|
||||||
|
if (this._audioProcedure) {
|
||||||
|
this._audioProcedure.stopAllAudio();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case 'pong':
|
case 'pong':
|
||||||
// Heartbeat response
|
// Heartbeat response
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue