import { useState, useRef, useCallback } from 'react'; export function useAudioRecorder() { const [isRecording, setRecording] = useState(false); const [audioBlob, setAudioBlob] = useState(null); const [error, setError] = useState(null); const mediaRecorderRef = useRef(null); const streamRef = useRef(null); const chunksRef = useRef([]); const start = useCallback(async () => { try { setError(null); setAudioBlob(null); chunksRef.current = []; // Request microphone access const stream = await navigator.mediaDevices.getUserMedia({ audio: { echoCancellation: true, noiseSuppression: true, sampleRate: 16000, } }); streamRef.current = stream; // Determine supported MIME type const mimeType = MediaRecorder.isTypeSupported('audio/webm') ? 'audio/webm' : 'audio/mp4'; // Create media recorder const recorder = new MediaRecorder(stream, { mimeType }); mediaRecorderRef.current = recorder; // Set up event handlers recorder.ondataavailable = (e) => { if (e.data.size > 0) { chunksRef.current.push(e.data); } }; recorder.onstop = () => { // Create blob from chunks const blob = new Blob(chunksRef.current, { type: mimeType }); setAudioBlob(blob); // Clean up stream if (streamRef.current) { streamRef.current.getTracks().forEach(track => track.stop()); streamRef.current = null; } }; recorder.onerror = (event) => { console.error('MediaRecorder error:', event); setError('Recording failed'); setRecording(false); }; // Start recording recorder.start(); setRecording(true); console.log('Recording started'); } catch (err) { console.error('Failed to start recording:', err); setError(err.message || 'Failed to start recording'); setRecording(false); } }, []); const stop = useCallback(() => { console.log('Stop called, recorder state:', mediaRecorderRef.current?.state); try { if (mediaRecorderRef.current && mediaRecorderRef.current.state === 'recording') { mediaRecorderRef.current.stop(); console.log('Recording stopped'); } } catch (err) { console.error('Error stopping recorder:', err); } // Always update state setRecording(false); // Clean up stream if still active if (streamRef.current) { streamRef.current.getTracks().forEach(track => track.stop()); streamRef.current = null; } }, []); const reset = useCallback(() => { setAudioBlob(null); setError(null); chunksRef.current = []; }, []); return { isRecording, audioBlob, error, start, stop, reset }; }