fix: play Opus TTS audio directly instead of WAV-converting it

The backend sends Opus-encoded audio from OpenAI TTS (tts-1 with
response_format=opus). The frontend was treating it as raw PCM16
and wrapping it in a WAV container, which corrupted the audio into
static. Now plays the Opus data directly as audio/ogg.
This commit is contained in:
2026-06-04 13:59:04 -04:00
parent a370f1ebff
commit 537ddcd841
+2 -16
View File
@@ -151,28 +151,14 @@ export function useConversation() {
break; break;
case 'audio': { case 'audio': {
// Incoming PCM16 audio from Kira // Incoming Opus audio from TTS (full response, not streamed)
if (msg.data && audioRef.current) { if (msg.data && audioRef.current) {
// Accumulate audio chunks and create a blob
const binary = atob(msg.data); const binary = atob(msg.data);
const bytes = new Uint8Array(binary.length); const bytes = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i++) { for (let i = 0; i < binary.length; i++) {
bytes[i] = binary.charCodeAt(i); bytes[i] = binary.charCodeAt(i);
} }
audioBufferRef.current.push(bytes); const blob = new Blob([bytes], { type: 'audio/ogg' });
// Convert accumulated PCM16 to WAV blob for playback
const allChunks = audioBufferRef.current;
const totalLen = allChunks.reduce((s, c) => s + c.length, 0);
const combined = new Uint8Array(totalLen);
let offset = 0;
for (const chunk of allChunks) {
combined.set(chunk, offset);
offset += chunk.length;
}
const wav = pcm16ToWav(combined);
const blob = new Blob([wav], { type: 'audio/wav' });
const url = URL.createObjectURL(blob); const url = URL.createObjectURL(blob);
audioRef.current.src = url; audioRef.current.src = url;
audioRef.current.play().catch(() => {}); audioRef.current.play().catch(() => {});