Spaces:
Sleeping
Sleeping
| import { useState, useRef, useCallback } from "react"; | |
| export function useAudio() { | |
| const [isRecording, setIsRecording] = useState(false); | |
| const [audioBlob, setAudioBlob] = useState(null); | |
| const [audioUrl, setAudioUrl] = useState(null); | |
| const mediaRecorderRef = useRef(null); | |
| const chunksRef = useRef([]); | |
| const streamRef = useRef(null); | |
| const startRecording = useCallback(async () => { | |
| try { | |
| const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); | |
| streamRef.current = stream; | |
| // Web Audio API for gain normalization | |
| const ctx = new AudioContext(); | |
| const source = ctx.createMediaStreamSource(stream); | |
| const gain = ctx.createGain(); | |
| gain.gain.value = 3.5; | |
| const compressor = ctx.createDynamicsCompressor(); | |
| compressor.threshold.value = -50; | |
| compressor.knee.value = 40; | |
| compressor.ratio.value = 20; | |
| compressor.attack.value = 0.003; | |
| compressor.release.value = 0.25; | |
| const dest = ctx.createMediaStreamDestination(); | |
| source.connect(gain); | |
| gain.connect(compressor); | |
| compressor.connect(dest); | |
| const recorder = new MediaRecorder(dest.stream); | |
| chunksRef.current = []; | |
| recorder.ondataavailable = (e) => chunksRef.current.push(e.data); | |
| recorder.onstop = () => { | |
| const blob = new Blob(chunksRef.current, { type: "audio/webm" }); | |
| const url = URL.createObjectURL(blob); | |
| setAudioBlob(blob); | |
| setAudioUrl(url); | |
| stream.getTracks().forEach((t) => t.stop()); | |
| }; | |
| mediaRecorderRef.current = recorder; | |
| recorder.start(); | |
| setIsRecording(true); | |
| } catch (err) { | |
| console.error("Mic error:", err); | |
| } | |
| }, []); | |
| const stopRecording = useCallback(() => { | |
| if (mediaRecorderRef.current && isRecording) { | |
| mediaRecorderRef.current.stop(); | |
| setIsRecording(false); | |
| } | |
| }, [isRecording]); | |
| const reset = useCallback(() => { | |
| setAudioBlob(null); | |
| setAudioUrl(null); | |
| setIsRecording(false); | |
| }, []); | |
| return { isRecording, audioBlob, audioUrl, startRecording, stopRecording, reset }; | |
| } | |