Skip to content

Commit 428759e

Browse files
author
Your Name
committed
Fix TTS blob URL playback error (ERR_REQUEST_RANGE_NOT_SATISFIABLE)
- Clean up previous audio element before creating new one - Set preload='auto' for better buffering - Set up event listeners before setting src - Add oncanplaythrough handler for better loading - Improved error handling with fallback to browser TTS - Properly clean up audio element and blob URL on error - Add try-catch in cancel() method Issue: ERR_REQUEST_RANGE_NOT_SATISFIABLE when playing TTS audio Cause: Blob URL not properly supporting range requests Fix: Better audio element lifecycle management and error handling
1 parent 8aa1575 commit 428759e

1 file changed

Lines changed: 49 additions & 6 deletions

File tree

src/lib/hybrid-tts.ts

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -102,25 +102,63 @@ class HybridTTS {
102102
private async playAudio(audioData: ArrayBuffer, options: HybridTTSOptions, contentType: string = 'audio/wav'): Promise<void> {
103103
return new Promise((resolve, reject) => {
104104
try {
105+
// Clean up previous audio element if exists
106+
if (this.audioElement) {
107+
this.audioElement.pause();
108+
this.audioElement.src = '';
109+
this.audioElement = null;
110+
}
111+
105112
const blob = new Blob([audioData], { type: contentType });
106113
const url = URL.createObjectURL(blob);
107114

108-
this.audioElement = new Audio(url);
115+
this.audioElement = new Audio();
116+
this.audioElement.preload = 'auto';
109117
this.audioElement.volume = options.volume || 1.0;
110118

119+
// Set up event listeners before setting src
111120
this.audioElement.onended = () => {
112121
URL.revokeObjectURL(url);
122+
if (this.audioElement) {
123+
this.audioElement.src = '';
124+
}
113125
options.onEnd?.();
114126
resolve();
115127
};
116128

117-
this.audioElement.onerror = (error) => {
129+
this.audioElement.onerror = (event) => {
130+
console.error('[Hybrid TTS] Audio playback error:', event);
118131
URL.revokeObjectURL(url);
119-
reject(error);
132+
if (this.audioElement) {
133+
this.audioElement.src = '';
134+
}
135+
// Don't reject, fall back to browser TTS
136+
this.useBrowserTTS(options).then(resolve).catch(reject);
137+
};
138+
139+
this.audioElement.oncanplaythrough = () => {
140+
console.log('[Hybrid TTS] Audio ready to play');
120141
};
121142

122-
this.audioElement.play();
143+
// Set src and load
144+
this.audioElement.src = url;
145+
this.audioElement.load();
146+
147+
// Play with error handling
148+
const playPromise = this.audioElement.play();
149+
if (playPromise !== undefined) {
150+
playPromise.catch((error) => {
151+
console.error('[Hybrid TTS] Play error:', error);
152+
URL.revokeObjectURL(url);
153+
if (this.audioElement) {
154+
this.audioElement.src = '';
155+
}
156+
// Fall back to browser TTS
157+
this.useBrowserTTS(options).then(resolve).catch(reject);
158+
});
159+
}
123160
} catch (error) {
161+
console.error('[Hybrid TTS] Setup error:', error);
124162
reject(error);
125163
}
126164
});
@@ -153,8 +191,13 @@ class HybridTTS {
153191
*/
154192
cancel(): void {
155193
if (this.audioElement) {
156-
this.audioElement.pause();
157-
this.audioElement = null;
194+
try {
195+
this.audioElement.pause();
196+
this.audioElement.src = '';
197+
this.audioElement = null;
198+
} catch (error) {
199+
console.error('[Hybrid TTS] Cancel error:', error);
200+
}
158201
}
159202
edgeTTS.cancel();
160203
browserTTS.cancel();

0 commit comments

Comments
 (0)