From 9aae2c7f50fd3b5015fd76f9a5968c8d11e777e3 Mon Sep 17 00:00:00 2001 From: jialin Date: Thu, 5 Mar 2026 19:25:33 +0800 Subject: [PATCH] fix: use html audio to load stream --- src/components/audio-animation/index.tsx | 2 +- .../audio-player/raw-audio-player.tsx | 52 +- .../speech-content/audio-player.tsx | 7 +- src/components/speech-content/index.tsx | 26 +- src/components/speech-content/speech-item.tsx | 283 ++++++---- src/pages/benchmark/index.tsx | 22 +- src/pages/playground/apis/index.ts | 10 +- .../playground/components/params-fields.tsx | 7 +- .../speech/audio/pcm-player-workerlet.ts | 94 ++++ .../playground/speech/forms/tts-advance.tsx | 11 - .../playground/speech/forms/tts-form.tsx | 28 +- .../speech/hooks/use-non-stream-tts.ts | 51 +- .../speech/hooks/use-pcm-stream-player.ts | 172 ++++++ .../playground/speech/hooks/use-stream-tts.ts | 510 ++++++++++-------- src/pages/playground/speech/params-config.ts | 1 - src/pages/playground/speech/tts.tsx | 55 +- src/utils/pcm-to-wav.ts | 54 ++ 17 files changed, 1000 insertions(+), 385 deletions(-) create mode 100644 src/pages/playground/speech/audio/pcm-player-workerlet.ts create mode 100644 src/pages/playground/speech/hooks/use-pcm-stream-player.ts create mode 100644 src/utils/pcm-to-wav.ts diff --git a/src/components/audio-animation/index.tsx b/src/components/audio-animation/index.tsx index f24c3f3a..2a297c68 100644 --- a/src/components/audio-animation/index.tsx +++ b/src/components/audio-animation/index.tsx @@ -189,4 +189,4 @@ const AudioAnimation: React.FC = (props) => { ); }; -export default React.memo(AudioAnimation); +export default AudioAnimation; diff --git a/src/components/audio-player/raw-audio-player.tsx b/src/components/audio-player/raw-audio-player.tsx index 10fea230..69a1fa76 100644 --- a/src/components/audio-player/raw-audio-player.tsx +++ b/src/components/audio-player/raw-audio-player.tsx @@ -18,8 +18,9 @@ const RawAudioPlayer: React.FC = forwardRef((props, ref) => { // ======================================================== const initAudioContext = useCallback(() => { - audioContext.current = new (window.AudioContext || - window.webkitAudioContext)(); + audioContext.current = new ( + window.AudioContext || (window as any).webkitAudioContext + )(); analyser.current = audioContext.current.createAnalyser(); analyser.current.fftSize = 512; @@ -52,7 +53,9 @@ const RawAudioPlayer: React.FC = forwardRef((props, ref) => { }); audioRef.current.addEventListener('timeupdate', () => { + const current = audioRef.current?.currentTime || 0; props.onTimeUpdate?.(); + props.onAudioProcess?.(current); }); audioRef.current.addEventListener('ended', () => { @@ -85,11 +88,6 @@ const RawAudioPlayer: React.FC = forwardRef((props, ref) => { props.onVolumeChange?.(); }); - audioRef.current.addEventListener('audioprocess', () => { - const current = audioRef.current?.currentTime || 0; - props.onAudioProcess?.(current); - }); - audioRef.current.addEventListener('playing', () => { props.onPlaying?.(); }); @@ -111,16 +109,44 @@ const RawAudioPlayer: React.FC = forwardRef((props, ref) => { useImperativeHandle(ref, () => ({ play: () => { - audioRef.current?.play(); + if (audioRef.current) { + // If playback has ended, reset to beginning + if (audioRef.current.currentTime >= audioRef.current.duration) { + audioRef.current.currentTime = 0; + } + audioRef.current.play(); + } }, pause: () => { audioRef.current?.pause(); + }, + seekTo: (ratio: number) => { + if (audioRef.current && audioRef.current.duration) { + audioRef.current.currentTime = ratio * audioRef.current.duration; + } + }, + // Compatibility layer for wavesurfer interface + wavesurfer: { + current: { + play: () => { + if (audioRef.current) { + // If playback has ended, reset to beginning + if (audioRef.current.currentTime >= audioRef.current.duration) { + audioRef.current.currentTime = 0; + } + return audioRef.current.play(); + } + return Promise.resolve(); + }, + isPlaying: () => { + return audioRef.current ? !audioRef.current?.paused : false; + } + } } })); useEffect(() => { if (audioRef.current) { - console.log('audioRef.current', audioRef.current, props.url); initEnvents(); } return () => { @@ -138,7 +164,6 @@ const RawAudioPlayer: React.FC = forwardRef((props, ref) => { audioRef.current?.removeEventListener('seeked', () => {}); audioRef.current?.removeEventListener('seeking', () => {}); audioRef.current?.removeEventListener('volumechange', () => {}); - audioRef.current?.removeEventListener('audioprocess', () => {}); audioRef.current?.removeEventListener('playing', () => {}); audioRef.current?.removeEventListener('loadedmetadata', () => {}); audioRef.current?.removeEventListener('ended', () => {}); @@ -146,6 +171,13 @@ const RawAudioPlayer: React.FC = forwardRef((props, ref) => { }; }, [audioRef.current]); + // Reload audio when URL changes + useEffect(() => { + if (audioRef.current && props.url) { + audioRef.current.load(); + } + }, [props.url]); + return (