useSimpleAudioRecorder.ts
1 import { useState, useRef, useCallback } from 'react' 2 3 export function useSimpleAudioRecorder() { 4 const [isRecording, setIsRecording] = useState(false) 5 const [audioBlob, setAudioBlob] = useState<Blob | null>(null) 6 const mediaRecorderRef = useRef<MediaRecorder | null>(null) 7 const audioChunksRef = useRef<Blob[]>([]) 8 const streamRef = useRef<MediaStream | null>(null) 9 10 const startRecording = useCallback(async () => { 11 try { 12 // Reset previous recording 13 setAudioBlob(null) 14 15 const stream = await navigator.mediaDevices.getUserMedia({ 16 audio: { 17 sampleRate: 16000, 18 channelCount: 1, 19 echoCancellation: true, 20 noiseSuppression: true, 21 } 22 }) 23 24 streamRef.current = stream 25 26 const mediaRecorder = new MediaRecorder(stream, { 27 mimeType: 'audio/webm' 28 }) 29 30 audioChunksRef.current = [] 31 32 mediaRecorder.ondataavailable = (event) => { 33 if (event.data.size > 0) { 34 audioChunksRef.current.push(event.data) 35 } 36 } 37 38 mediaRecorder.onstop = () => { 39 const blob = new Blob(audioChunksRef.current, { type: 'audio/webm' }) 40 setAudioBlob(blob) 41 } 42 43 mediaRecorderRef.current = mediaRecorder 44 mediaRecorder.start() 45 setIsRecording(true) 46 47 } catch (error) { 48 console.error('Failed to start recording:', error) 49 throw error 50 } 51 }, []) 52 53 const stopRecording = useCallback(() => { 54 if (mediaRecorderRef.current && mediaRecorderRef.current.state !== 'inactive') { 55 mediaRecorderRef.current.stop() 56 setIsRecording(false) 57 58 // Stop all tracks 59 if (streamRef.current) { 60 streamRef.current.getTracks().forEach(track => track.stop()) 61 streamRef.current = null 62 } 63 } 64 }, []) 65 66 const reset = useCallback(() => { 67 setAudioBlob(null) 68 }, []) 69 70 return { 71 isRecording, 72 audioBlob, 73 startRecording, 74 stopRecording, 75 reset 76 } 77 }