From 8dd1c13f85ad544b8c904805788d47ef763b7678 Mon Sep 17 00:00:00 2001 From: ajaysi Date: Tue, 7 Apr 2026 07:05:45 +0530 Subject: [PATCH] Fix: Improve audio recording playback in voice clone component - Use explicit MIME type for MediaRecorder (audio/webm;codecs=opus) - Add error handling for audio playback - Copy chunks before creating blob to prevent race conditions - Add key prop to audio elements for proper re-rendering --- .../components/VoiceAvatarPlaceholder.tsx | 39 +++++++++++++++++-- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/OnboardingWizard/PersonalizationStep/components/VoiceAvatarPlaceholder.tsx b/frontend/src/components/OnboardingWizard/PersonalizationStep/components/VoiceAvatarPlaceholder.tsx index 0e0a05e2..2836c3eb 100644 --- a/frontend/src/components/OnboardingWizard/PersonalizationStep/components/VoiceAvatarPlaceholder.tsx +++ b/frontend/src/components/OnboardingWizard/PersonalizationStep/components/VoiceAvatarPlaceholder.tsx @@ -305,7 +305,14 @@ export const VoiceAvatarPlaceholder: React.FC<{ domainName?: string; onVoiceSet? const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); streamRef.current = stream; - const recorder = new MediaRecorder(stream); + // Use a widely supported MIME type + const mimeType = MediaRecorder.isTypeSupported('audio/webm;codecs=opus') + ? 'audio/webm;codecs=opus' + : MediaRecorder.isTypeSupported('audio/webm') + ? 'audio/webm' + : 'audio/mp4'; + + const recorder = new MediaRecorder(stream, { mimeType }); recorderRef.current = recorder; chunksRef.current = []; @@ -315,7 +322,8 @@ export const VoiceAvatarPlaceholder: React.FC<{ domainName?: string; onVoiceSet? recorder.onstop = async () => { try { - const blob = new Blob(chunksRef.current, { type: recorder.mimeType || 'audio/webm' }); + const chunks = [...chunksRef.current]; + const blob = new Blob(chunks, { type: mimeType }); const file = new File([blob], `voice_sample_${Date.now()}.webm`, { type: blob.type }); if (file.size > 15 * 1024 * 1024) { setError('Recorded file is too large. Please keep it short (5–20 seconds).'); @@ -323,7 +331,11 @@ export const VoiceAvatarPlaceholder: React.FC<{ domainName?: string; onVoiceSet? } setAudioFile(file); const url = URL.createObjectURL(blob); + console.log('[VoiceClone] Created audio preview URL:', url, 'size:', file.size, 'type:', blob.type); setAudioPreviewUrl(url); + } catch (err) { + console.error('[VoiceClone] Error creating audio blob:', err); + setError('Failed to create audio preview. Please try again.'); } finally { cleanupRecording(); } @@ -745,7 +757,18 @@ export const VoiceAvatarPlaceholder: React.FC<{ domainName?: string; onVoiceSet? Source Sample: -