import { Mic, Pause, Upload } from 'lucide-react'; import { useRef, useState } from 'react'; import { type CreativeAudioAsset, readCreativeAudioFileAsAsset, } from './creativeAudioFileAsset'; type CreativeAudioInputPanelProps = { disabled?: boolean; title: string; defaultLabel: string; limitLabel?: string; asset: TAsset | null; buildRecordedFileName: () => string; onAssetChange: (asset: TAsset | null) => void; onError: (message: string | null) => void; readFileAsAsset?: ( file: File, source: 'uploaded' | 'recorded', ) => Promise; }; export function CreativeAudioInputPanel({ disabled = false, title, defaultLabel, limitLabel, asset, buildRecordedFileName, onAssetChange, onError, readFileAsAsset = readCreativeAudioFileAsAsset, }: CreativeAudioInputPanelProps) { const [isRecording, setIsRecording] = useState(false); const recorderRef = useRef(null); const chunksRef = useRef([]); const startRecording = async () => { if (disabled || isRecording) { return; } try { if ( typeof navigator === 'undefined' || !navigator.mediaDevices?.getUserMedia || typeof MediaRecorder === 'undefined' ) { throw new Error('当前浏览器不支持录音。'); } const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); const recorder = new MediaRecorder(stream); chunksRef.current = []; recorder.ondataavailable = (event) => { if (event.data.size > 0) { chunksRef.current.push(event.data); } }; recorder.onstop = () => { const blob = new Blob(chunksRef.current, { type: recorder.mimeType || 'audio/webm', }); stream.getTracks().forEach((track) => track.stop()); const file = new File([blob], buildRecordedFileName(), { type: blob.type, }); void readFileAsAsset(file, 'recorded') .then(onAssetChange) .catch((caughtError) => { onError( caughtError instanceof Error ? caughtError.message : '录音保存失败。', ); }); }; recorderRef.current = recorder; recorder.start(); setIsRecording(true); onError(null); } catch (caughtError) { onError( caughtError instanceof Error ? caughtError.message : '录音启动失败。', ); } }; const stopRecording = () => { recorderRef.current?.stop(); recorderRef.current = null; setIsRecording(false); }; return (
{title}
{limitLabel ? (
{limitLabel}
) : null}
{asset ? ( ) : null}
{asset?.audioSrc ? (
); } export default CreativeAudioInputPanel;