mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
refactor: enhance TTS playback management with abort signal support
- Update TTSManager to accept an optional abort signal, allowing for graceful cancellation of TTS playback. - Implement abort handling in the generateAndWaitForPlayback method to clean up pending playbacks and reject promises when playback is aborted. - Modify Session class to pass the abort signal during TTS generation, improving control over playback interruptions. These changes improve the robustness of the voice assistant's TTS functionality and enhance user experience by allowing for better management of audio playback.
This commit is contained in:
Binary file not shown.
@@ -25,20 +25,49 @@ export class TTSManager {
|
||||
*/
|
||||
public async generateAndWaitForPlayback(
|
||||
text: string,
|
||||
emitMessage: (msg: SessionOutboundMessage) => void
|
||||
emitMessage: (msg: SessionOutboundMessage) => void,
|
||||
abortSignal?: AbortSignal
|
||||
): Promise<void> {
|
||||
// Check if already aborted
|
||||
if (abortSignal?.aborted) {
|
||||
throw new Error("TTS playback aborted");
|
||||
}
|
||||
|
||||
// Generate TTS audio
|
||||
const { audio, format } = await synthesizeSpeech(text);
|
||||
|
||||
// Create unique ID for this audio segment
|
||||
const audioId = uuidv4();
|
||||
|
||||
// Store abort handler reference outside Promise constructor
|
||||
let onAbort: (() => void) | undefined;
|
||||
|
||||
// Create promise that will be resolved when client confirms playback
|
||||
const playbackPromise = new Promise<void>((resolve, reject) => {
|
||||
// Store handlers (no timeout - will resolve when client confirms or connection closes)
|
||||
this.pendingPlaybacks.set(audioId, { resolve, reject });
|
||||
|
||||
// Handle abort signal
|
||||
if (abortSignal) {
|
||||
onAbort = () => {
|
||||
// Clean up pending playback
|
||||
this.pendingPlaybacks.delete(audioId);
|
||||
// Reject with abort error
|
||||
reject(new Error("TTS playback aborted"));
|
||||
};
|
||||
|
||||
// Listen for abort (once: true for auto-cleanup if abort fires)
|
||||
abortSignal.addEventListener("abort", onAbort, { once: true });
|
||||
}
|
||||
});
|
||||
|
||||
// Clean up abort listener when promise settles (in case abort never fires)
|
||||
if (onAbort) {
|
||||
playbackPromise.finally(() => {
|
||||
abortSignal!.removeEventListener("abort", onAbort!);
|
||||
});
|
||||
}
|
||||
|
||||
// Emit audio output message
|
||||
emitMessage({
|
||||
type: "audio_output",
|
||||
|
||||
@@ -332,7 +332,8 @@ export class Session {
|
||||
if (enableTTS) {
|
||||
pendingTTS = this.ttsManager.generateAndWaitForPlayback(
|
||||
textBuffer,
|
||||
(msg) => this.emit(msg)
|
||||
(msg) => this.emit(msg),
|
||||
this.abortController.signal
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user