UNPKG

@lobehub/tts

Version:

A high-quality & reliable TTS React Hooks library

131 lines (129 loc) 4.02 kB
import { useCallback, useEffect, useRef, useState } from "react"; //#region src/react/hooks/useStreamAudioPlayer.ts const useStreamAudioPlayer = () => { const audioRef = useRef(null); const [arrayBuffers, setArrayBuffers] = useState([]); const [currentTime, setCurrentTime] = useState(0); const [duration, setDuration] = useState(0); const [isPlaying, setIsPlaying] = useState(false); const [maxLength, setMaxLength] = useState(0); useEffect(() => { try { audioRef.current = new Audio(); } catch {} if (!audioRef.current) return; const onLoadedMetadata = () => { if (!audioRef.current) return; setDuration(audioRef.current.duration); }; const onTimeUpdate = () => { if (!audioRef.current) return; setCurrentTime(audioRef.current.currentTime); }; audioRef.current.addEventListener("loadedmetadata", onLoadedMetadata); audioRef.current.addEventListener("timeupdate", onTimeUpdate); return () => { if (!audioRef.current) return; audioRef.current.pause(); audioRef.current.load(); audioRef.current.removeEventListener("loadedmetadata", onLoadedMetadata); audioRef.current.removeEventListener("timeupdate", onTimeUpdate); }; }, []); useEffect(() => { if (!audioRef.current) return; const onEnded = async () => { if (!audioRef.current || !audioRef.current.currentSrc) return; audioRef.current.pause(); if (maxLength < arrayBuffers.length) { const cacheTime = audioRef.current.currentTime; const newBlob = new Blob(arrayBuffers, { type: "audio/mp3" }); if (audioRef.current.src) URL.revokeObjectURL(audioRef.current.src); const newUrl = URL.createObjectURL(newBlob); audioRef.current.src = newUrl; audioRef.current.load(); audioRef.current.currentTime = cacheTime; audioRef.current.play(); setMaxLength(arrayBuffers.length); } else { setIsPlaying(false); audioRef.current.currentTime = 0; setCurrentTime(0); } }; audioRef.current.addEventListener("ended", onEnded); return () => { if (!audioRef.current) return; audioRef.current.removeEventListener("ended", onEnded); }; }, [maxLength, arrayBuffers]); const loadArrayBuffer = useCallback(async (arrayBuffer) => { if (!arrayBuffer || !audioRef.current) return; if (maxLength === 0) { const newBlob = new Blob([arrayBuffer], { type: "audio/mp3" }); audioRef.current.src = URL.createObjectURL(newBlob); audioRef.current.load(); audioRef.current.play(); setIsPlaying(true); setMaxLength(1); } setArrayBuffers((prev) => [...prev, arrayBuffer].filter(Boolean)); }, [maxLength]); const handlePlay = useCallback(() => { if (!audioRef.current) return; if (audioRef.current.duration > 0) { setIsPlaying(true); audioRef.current.play(); } }, []); const handlePause = useCallback(() => { if (!audioRef.current) return; setIsPlaying(false); audioRef.current.pause(); }, []); const handleStop = useCallback(() => { if (!audioRef.current) return; setIsPlaying(false); audioRef.current.pause(); audioRef.current.currentTime = 0; }, []); const setTime = useCallback((value) => { if (!audioRef.current) return; setCurrentTime(value); audioRef.current.currentTime = value; }, []); const reset = useCallback(() => { if (!audioRef.current) return; audioRef.current.pause(); audioRef.current.currentTime = 0; if (audioRef.current.src) URL.revokeObjectURL(audioRef.current.src); audioRef.current.src = ""; setMaxLength(0); setArrayBuffers([]); setDuration(0); setCurrentTime(0); }, []); return { arrayBuffers, currentTime, download: useCallback(async () => { if (!audioRef.current) return; const a = document.createElement("a"); a.href = audioRef.current.src; a.download = "audio.mp3"; a.click(); }, []), duration, isPlaying, load: loadArrayBuffer, pause: handlePause, play: handlePlay, ref: audioRef, reset, setTime, stop: handleStop, url: audioRef?.current?.src || "" }; }; //#endregion export { useStreamAudioPlayer };