diff --git a/frontend/src/hooks/useAudioRecorder.ts b/frontend/src/hooks/useAudioRecorder.ts index 6cbb7e1..893c5e3 100644 --- a/frontend/src/hooks/useAudioRecorder.ts +++ b/frontend/src/hooks/useAudioRecorder.ts @@ -9,12 +9,12 @@ import { useState, useCallback, useEffect, useRef } from "react"; export function useAudioRecorder() { const [isLoading, setIsLoading] = useState(false); const [isRecording, setIsRecording] = useState(false); - const [recordings, setRecordings] = useState([]); - const [currentRecording, setCurrentRecording] = useState(null); + const [currentRecording, setCurrentRecording] = useState(null); const mediaRecorderRef = useRef(null); const chunksRef = useRef([]); const streamRef = useRef(null); + const stopResolverRef = useRef<((value: { blob: Blob }) => void) | null>(null); /** Choisit le meilleur mimeType supporté par le navigateur. */ const getMimeType = useCallback(() => { @@ -54,7 +54,6 @@ export function useAudioRecorder() { const mimeType = getMimeType(); const recorder = new MediaRecorder(stream, { mimeType: mimeType || undefined, - audioBitsPerSecond: 128000, }); recorder.ondataavailable = (e) => { @@ -66,10 +65,11 @@ export function useAudioRecorder() { recorder.onstop = () => { const actualMime = recorder.mimeType || mimeType || "audio/webm"; const blob = new Blob(chunksRef.current, { type: actualMime }); - const url = URL.createObjectURL(blob); - - setRecordings((prev) => [...prev, url]); - setCurrentRecording(url); + setCurrentRecording(blob); + stopResolverRef.current?.({ blob }); + stopResolverRef.current = null; + mediaRecorderRef.current = null; + chunksRef.current = []; // Arrête les pistes micro stream.getTracks().forEach((t) => t.stop()); @@ -92,26 +92,15 @@ export function useAudioRecorder() { if (!isRecording || !mediaRecorderRef.current) return; setIsLoading(true); - return new Promise<{ blob: Blob; url: string }>((resolve) => { + return new Promise<{ blob: Blob }>((resolve) => { const recorder = mediaRecorderRef.current!; - const mimeType = recorder.mimeType || getMimeType() || "audio/webm"; - const ext = getExtension(mimeType); - - const originalOnStop = recorder.onstop; - recorder.onstop = (ev) => { - // Appelle le handler de base (qui crée le blob + currentRecording) - if (originalOnStop) originalOnStop.call(recorder, ev); - - const blob = new Blob(chunksRef.current, { type: mimeType }); - const url = URL.createObjectURL(blob); - setIsRecording(false); - setIsLoading(false); - resolve({ blob, url }); - }; - + stopResolverRef.current = resolve; + recorder.requestData(); recorder.stop(); + setIsRecording(false); + setIsLoading(false); }); - }, [isRecording, getMimeType, getExtension]); + }, [isRecording]); const toggleRecording = useCallback(async () => { if (isRecording) { @@ -122,25 +111,21 @@ export function useAudioRecorder() { }, [isRecording, startRecording, stopRecording]); const clearRecordings = useCallback(() => { - recordings.forEach((url) => URL.revokeObjectURL(url)); - setRecordings([]); setCurrentRecording(null); - }, [recordings]); + }, []); // Cleanup au démontage useEffect(() => { return () => { - recordings.forEach((url) => URL.revokeObjectURL(url)); if (streamRef.current) { streamRef.current.getTracks().forEach((t) => t.stop()); } }; - }, [recordings]); + }, []); return { isLoading, isRecording, - recordings, currentRecording, startRecording, stopRecording, diff --git a/frontend/src/pages/Recipes/RecipeForm.tsx b/frontend/src/pages/Recipes/RecipeForm.tsx index ce755ab..d25c6c3 100644 --- a/frontend/src/pages/Recipes/RecipeForm.tsx +++ b/frontend/src/pages/Recipes/RecipeForm.tsx @@ -109,20 +109,16 @@ export default function RecipeForm() { return () => clearInterval(id) }, [pageState]) - // Convertit l'enregistrement en File + // Convertit l'enregistrement en File sans repasser par une blob URL, + // pour éviter toute altération ou perte lors du fetch() local. useEffect(() => { if (!currentRecording) return - fetch(currentRecording) - .then((res) => res.blob()) - .then((blob) => { - // Détecte le format réel du blob (webm, mp4, ogg…) - const mime = blob.type || "audio/webm" - const ext = mime.includes("mp4") ? "m4a" : mime.includes("ogg") ? "ogg" : "webm" - const file = new File([blob], `recording.${ext}`, { type: mime }) - setAudioFile(file) - setPageState("review") - setError("") - }) + const mime = currentRecording.type || "audio/webm" + const ext = mime.includes("mp4") ? "m4a" : mime.includes("ogg") ? "ogg" : "webm" + const file = new File([currentRecording], `recording.${ext}`, { type: mime }) + setAudioFile(file) + setPageState("review") + setError("") }, [currentRecording]) // Timer