From ede98d2c46c5049e5afdac791fbf1bfa18222375 Mon Sep 17 00:00:00 2001 From: jialin Date: Tue, 3 Dec 2024 20:19:30 +0800 Subject: [PATCH] fix: audio player pause --- src/components/audio-animation/index.tsx | 4 +- src/components/audio-player/config/type.ts | 39 +++++ src/components/audio-player/index.tsx | 1 + .../audio-player/raw-audio-player.tsx | 164 ++++++++++++++++++ src/components/speech-content/speech-item.tsx | 17 +- src/hooks/use-chunk-fetch.ts | 2 +- .../playground/components/ground-images.tsx | 8 +- src/pages/playground/config/params-config.ts | 8 +- 8 files changed, 223 insertions(+), 20 deletions(-) create mode 100644 src/components/audio-player/config/type.ts create mode 100644 src/components/audio-player/raw-audio-player.tsx diff --git a/src/components/audio-animation/index.tsx b/src/components/audio-animation/index.tsx index 2b2cb780..f24c3f3a 100644 --- a/src/components/audio-animation/index.tsx +++ b/src/components/audio-animation/index.tsx @@ -8,6 +8,7 @@ interface AudioAnimationProps { maxWidth?: number; scaleFactor?: number; maxBarCount?: number; + amplitude?: number; fixedHeight?: boolean; analyserData: { data: Uint8Array; @@ -19,6 +20,7 @@ const AudioAnimation: React.FC = (props) => { const { scaleFactor = 1.2, maxBarCount = 128, + amplitude = 40, maxWidth, fixedHeight = true, analyserData, @@ -71,7 +73,7 @@ const AudioAnimation: React.FC = (props) => { const barSpacing = 6; const centerLine = Math.floor(HEIGHT / 2); - const jitterAmplitude = 40; + const jitterAmplitude = amplitude; const minJitter = 10; let lastFrameTime = 0; diff --git a/src/components/audio-player/config/type.ts b/src/components/audio-player/config/type.ts new file mode 100644 index 00000000..210fb88c --- /dev/null +++ b/src/components/audio-player/config/type.ts @@ -0,0 +1,39 @@ +export type AudioEvent = + | 'play' + | 'playing' + | 'pause' + | 'timeupdate' + | 'ended' + | 'loadedmetadata' + | 'audioprocess' + | 'canplay' + | 'ended' + | 'loadeddata' + | 'seeked' + | 'seeking' + | 'volumechange'; + +export interface AudioPlayerProps { + controls?: boolean; + autoplay?: boolean; + url: string; + speed?: number; + ref?: any; + height?: number; + width?: number; + duration?: number; + onPlay?: () => void; + onPlaying?: () => void; + onPause?: () => void; + onTimeUpdate?: () => void; + onEnded?: () => void; + onLoadedMetadata?: (duration: number) => void; + onAudioProcess?: (current: number) => void; + onCanPlay?: () => void; + onLoadedData?: () => void; + onSeeked?: () => void; + onSeeking?: () => void; + onVolumeChange?: () => void; + onReady?: (duration: number) => void; + onAnalyse?: (analyseData: any, frequencyBinCount: any) => void; +} diff --git a/src/components/audio-player/index.tsx b/src/components/audio-player/index.tsx index 459a3952..40d49ed5 100644 --- a/src/components/audio-player/index.tsx +++ b/src/components/audio-player/index.tsx @@ -75,6 +75,7 @@ const AudioPlayer: React.FC = forwardRef((props, ref) => { }, []); const handleAudioOnPlay = useCallback(() => { + console.log('audio play'); timer.current = setInterval(() => { setAudioState((prestate) => { return { diff --git a/src/components/audio-player/raw-audio-player.tsx b/src/components/audio-player/raw-audio-player.tsx new file mode 100644 index 00000000..b27e3a36 --- /dev/null +++ b/src/components/audio-player/raw-audio-player.tsx @@ -0,0 +1,164 @@ +import React, { + forwardRef, + useCallback, + useEffect, + useImperativeHandle, + useRef +} from 'react'; +import { AudioPlayerProps } from './config/type'; + +const RawAudioPlayer: React.FC = forwardRef((props, ref) => { + const { autoplay = false } = props; + const audioRef = React.useRef(null); + + // =================== audio context ====================== + const audioContext = useRef(null); + const analyser = useRef(null); + const dataArray = useRef(null); + // ======================================================== + + const initAudioContext = useCallback(() => { + audioContext.current = new (window.AudioContext || + window.webkitAudioContext)(); + + analyser.current = audioContext.current.createAnalyser(); + analyser.current.fftSize = 512; + dataArray.current = new Uint8Array(analyser.current.frequencyBinCount); + }, []); + + const generateVisualData = useCallback(() => { + const source = audioContext.current.createMediaElementSource( + audioRef.current + ); + source.connect(analyser.current); + analyser.current.connect(audioContext.current.destination); + }, []); + + const initEnvents = () => { + if (!audioRef.current) { + return; + } + + audioRef.current.addEventListener('complete', () => {}); + + audioRef.current.addEventListener('play', () => { + props.onAnalyse?.(dataArray.current, analyser); + props.onPlay?.(); + }); + + audioRef.current.addEventListener('pause', () => { + props.onAnalyse?.(dataArray.current, analyser); + props.onPause?.(); + }); + + audioRef.current.addEventListener('timeupdate', () => { + props.onTimeUpdate?.(); + }); + + audioRef.current.addEventListener('ended', () => { + props.onEnded?.(); + }); + // add all other events + + audioRef.current.addEventListener('canplay', () => { + props.onCanPlay?.(); + }); + + audioRef.current.addEventListener('loadeddata', () => { + initEnvents(); + initAudioContext(); + generateVisualData(); + props.onLoadedData?.(); + }); + + audioRef.current.addEventListener('seeked', () => { + props.onSeeked?.(); + }); + + audioRef.current.addEventListener('seeking', () => { + props.onSeeking?.(); + }); + + audioRef.current.addEventListener('volumechange', () => { + props.onVolumeChange?.(); + }); + + audioRef.current.addEventListener('audioprocess', () => { + const current = audioRef.current?.currentTime || 0; + props.onAudioProcess?.(current); + }); + + audioRef.current.addEventListener('playing', () => { + props.onPlaying?.(); + }); + + audioRef.current.addEventListener('loadedmetadata', () => { + const duration = audioRef.current?.duration || 0; + props.onLoadedMetadata?.(duration); + props.onReady?.(duration); + }); + + audioRef.current.addEventListener('ended', () => { + props.onEnded?.(); + }); + + audioRef.current.addEventListener('loadeddata', () => { + props.onLoadedData?.(); + }); + }; + + const handleAudioOnPlay = () => { + audioRef.current?.play(); + }; + + const handleLoadedMetadata = () => {}; + + useImperativeHandle(ref, () => ({ + play: () => { + audioRef.current?.play(); + }, + pause: () => { + audioRef.current?.pause(); + } + })); + + useEffect(() => { + if (audioRef.current) { + } + return () => { + if (audioContext.current) { + audioContext.current.close(); + } + // remove all events + + audioRef.current?.removeEventListener('play', () => {}); + audioRef.current?.removeEventListener('pause', () => {}); + audioRef.current?.removeEventListener('timeupdate', () => {}); + audioRef.current?.removeEventListener('ended', () => {}); + audioRef.current?.removeEventListener('canplay', () => {}); + audioRef.current?.removeEventListener('loadeddata', () => {}); + 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', () => {}); + audioRef.current?.removeEventListener('loadeddata', () => {}); + }; + }, [audioRef.current]); + + return ( + + ); +}); + +export default RawAudioPlayer; diff --git a/src/components/speech-content/speech-item.tsx b/src/components/speech-content/speech-item.tsx index cd923bc8..84251ba3 100644 --- a/src/components/speech-content/speech-item.tsx +++ b/src/components/speech-content/speech-item.tsx @@ -50,12 +50,6 @@ const SpeechItem: React.FC = (props) => { const handlePlay = useCallback(async () => { try { - console.log( - 'isPlay:', - isPlay, - ref.current?.wavesurfer.current?.isPlaying() - ); - ref.current?.pause(); if (ref.current?.wavesurfer.current?.isPlaying()) { ref.current?.pause(); setIsPlay(false); @@ -124,6 +118,11 @@ const SpeechItem: React.FC = (props) => { debounceSeek(value); }; + const handleReady = useCallback((duration: number) => { + console.log('duration:', duration); + setDuration(duration); + }, []); + const handlOnChangeComplete = useCallback((value: number) => { ref.current?.seekTo(value / duration); setCurrentTime(value); @@ -152,8 +151,7 @@ const SpeechItem: React.FC = (props) => { = (props) => { > {isPlay && ( { } const chunk = decoder.decode(value, { stream: true }); - + console.log('chunk===', chunk); callback(chunk); // console.log('chunkDataRef.current===2', chunkDataRef.current); diff --git a/src/pages/playground/components/ground-images.tsx b/src/pages/playground/components/ground-images.tsx index 79001e2d..1ddd8e85 100644 --- a/src/pages/playground/components/ground-images.tsx +++ b/src/pages/playground/components/ground-images.tsx @@ -419,14 +419,14 @@ const GroundImages: React.FC = forwardRef((props, ref) => { useEffect(() => { if (size === 'custom') { form.current?.form?.setFieldsValue({ - width: 256, - height: 256 + width: 512, + height: 512 }); setParams((pre: object) => { return { ...pre, - width: 256, - height: 256 + width: 512, + height: 512 }; }); } diff --git a/src/pages/playground/config/params-config.ts b/src/pages/playground/config/params-config.ts index f8df6a5a..08319c0a 100644 --- a/src/pages/playground/config/params-config.ts +++ b/src/pages/playground/config/params-config.ts @@ -115,9 +115,7 @@ export const ImageParamsConfig: ParamsSchema[] = [ { label: 'playground.params.custom', value: 'custom', locale: true }, { label: '256x256', value: '256x256' }, { label: '512x512', value: '512x512' }, - { label: '1024x1024', value: '1024x1024' }, - { label: '1792x1024', value: '1792x1024' }, - { label: '1024x1792', value: '1024x1792' } + { label: '1024x1024', value: '1024x1024' } ], label: { text: 'playground.params.size', @@ -367,7 +365,7 @@ export const ImageCustomSizeConfig: ParamsSchema[] = [ }, attrs: { min: 256, - max: 1792, + max: 1024, step: 64, inputnumber: false }, @@ -387,7 +385,7 @@ export const ImageCustomSizeConfig: ParamsSchema[] = [ }, attrs: { min: 256, - max: 1792, + max: 1024, step: 64, inputnumber: false },