From 89bc1bf88bcad977c9dda1769826bc2c42869957 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 19 May 2026 13:31:15 +0000 Subject: [PATCH] Decode Gemini TTS raw PCM with correct format flags Gemini returns raw PCM (audio/L16;codec=pcm;rate=24000), not a real WAV file with a header, so FFmpeg fails to auto-detect the format. Pass -f s16le, -ar (from mime type), and -ac 1 explicitly so FFmpeg can decode the byte stream. Also surface FFmpeg stderr on failure instead of swallowing it. https://claude.ai/code/session_01QBvwHAMZzVYfWvy1U5paat --- ffmpeg-service/main.py | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/ffmpeg-service/main.py b/ffmpeg-service/main.py index 0f23260..2e3f204 100644 --- a/ffmpeg-service/main.py +++ b/ffmpeg-service/main.py @@ -247,20 +247,32 @@ async def generate_tts_gemini( print(f"\U0001f50a Gemini audio received: {len(audio_bytes)} bytes, mime={mime_type}") - # Gemini returns WAV/PCM — convert to MP3 via FFmpeg - wav_path = audio_path.with_suffix(".wav") - with open(wav_path, "wb") as f: + # Gemini returns raw PCM (e.g. "audio/L16;codec=pcm;rate=24000") — parse rate from mime + sample_rate = 24000 + rate_match = re.search(r"rate=(\d+)", mime_type) + if rate_match: + sample_rate = int(rate_match.group(1)) + + pcm_path = audio_path.with_suffix(".pcm") + with open(pcm_path, "wb") as f: f.write(audio_bytes) convert_cmd = [ "ffmpeg", "-y", - "-i", str(wav_path), + "-f", "s16le", + "-ar", str(sample_rate), + "-ac", "1", + "-i", str(pcm_path), "-codec:a", "libmp3lame", "-qscale:a", "2", str(audio_path), ] - subprocess.run(convert_cmd, check=True, capture_output=True) - wav_path.unlink(missing_ok=True) + result = subprocess.run(convert_cmd, capture_output=True, text=True) + if result.returncode != 0: + print(f"❌ ffmpeg PCM->MP3 conversion failed (rc={result.returncode}):") + print(result.stderr[-1000:]) + raise RuntimeError(f"ffmpeg conversion failed: {result.stderr[-500:]}") + pcm_path.unlink(missing_ok=True) print(f"\u2705 Gemini TTS audio saved: {audio_path.stat().st_size} bytes")