fix: audio player pause

This commit is contained in:
jialin
2024-12-03 20:21:20 +08:00
parent 20f809740c
commit 4c75a5b421
8 changed files with 223 additions and 20 deletions
+3 -1
View File
@@ -8,6 +8,7 @@ interface AudioAnimationProps {
maxWidth?: number; maxWidth?: number;
scaleFactor?: number; scaleFactor?: number;
maxBarCount?: number; maxBarCount?: number;
amplitude?: number;
fixedHeight?: boolean; fixedHeight?: boolean;
analyserData: { analyserData: {
data: Uint8Array; data: Uint8Array;
@@ -19,6 +20,7 @@ const AudioAnimation: React.FC<AudioAnimationProps> = (props) => {
const { const {
scaleFactor = 1.2, scaleFactor = 1.2,
maxBarCount = 128, maxBarCount = 128,
amplitude = 40,
maxWidth, maxWidth,
fixedHeight = true, fixedHeight = true,
analyserData, analyserData,
@@ -71,7 +73,7 @@ const AudioAnimation: React.FC<AudioAnimationProps> = (props) => {
const barSpacing = 6; const barSpacing = 6;
const centerLine = Math.floor(HEIGHT / 2); const centerLine = Math.floor(HEIGHT / 2);
const jitterAmplitude = 40; const jitterAmplitude = amplitude;
const minJitter = 10; const minJitter = 10;
let lastFrameTime = 0; let lastFrameTime = 0;
@@ -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;
}
+1
View File
@@ -75,6 +75,7 @@ const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
}, []); }, []);
const handleAudioOnPlay = useCallback(() => { const handleAudioOnPlay = useCallback(() => {
console.log('audio play');
timer.current = setInterval(() => { timer.current = setInterval(() => {
setAudioState((prestate) => { setAudioState((prestate) => {
return { return {
@@ -0,0 +1,164 @@
import React, {
forwardRef,
useCallback,
useEffect,
useImperativeHandle,
useRef
} from 'react';
import { AudioPlayerProps } from './config/type';
const RawAudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
const { autoplay = false } = props;
const audioRef = React.useRef<HTMLAudioElement>(null);
// =================== audio context ======================
const audioContext = useRef<any>(null);
const analyser = useRef<any>(null);
const dataArray = useRef<any>(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 (
<audio
width={props.width || 300}
height={props.height || 40}
controls
autoPlay={autoplay}
src={props.url}
ref={audioRef}
preload="metadata"
></audio>
);
});
export default RawAudioPlayer;
@@ -50,12 +50,6 @@ const SpeechItem: React.FC<SpeechContentProps> = (props) => {
const handlePlay = useCallback(async () => { const handlePlay = useCallback(async () => {
try { try {
console.log(
'isPlay:',
isPlay,
ref.current?.wavesurfer.current?.isPlaying()
);
ref.current?.pause();
if (ref.current?.wavesurfer.current?.isPlaying()) { if (ref.current?.wavesurfer.current?.isPlaying()) {
ref.current?.pause(); ref.current?.pause();
setIsPlay(false); setIsPlay(false);
@@ -124,6 +118,11 @@ const SpeechItem: React.FC<SpeechContentProps> = (props) => {
debounceSeek(value); debounceSeek(value);
}; };
const handleReady = useCallback((duration: number) => {
console.log('duration:', duration);
setDuration(duration);
}, []);
const handlOnChangeComplete = useCallback((value: number) => { const handlOnChangeComplete = useCallback((value: number) => {
ref.current?.seekTo(value / duration); ref.current?.seekTo(value / duration);
setCurrentTime(value); setCurrentTime(value);
@@ -152,8 +151,7 @@ const SpeechItem: React.FC<SpeechContentProps> = (props) => {
<AudioPlayer <AudioPlayer
{...props} {...props}
audioUrl={props.audioUrl} audioUrl={props.audioUrl}
onReady={handleReay} onReady={handleReady}
onClick={handleOnClick}
onFinish={handleOnFinish} onFinish={handleOnFinish}
onPlay={handleOnPlay} onPlay={handleOnPlay}
onPause={handleOnPause} onPause={handleOnPause}
@@ -163,7 +161,8 @@ const SpeechItem: React.FC<SpeechContentProps> = (props) => {
></AudioPlayer> ></AudioPlayer>
{isPlay && ( {isPlay && (
<AudioAnimation <AudioAnimation
maxBarCount={180} maxBarCount={100}
amplitude={60}
fixedHeight={true} fixedHeight={true}
height={82} height={82}
width={800} width={800}
+1 -1
View File
@@ -29,7 +29,7 @@ const useSetChunkFetch = () => {
} }
const chunk = decoder.decode(value, { stream: true }); const chunk = decoder.decode(value, { stream: true });
console.log('chunk===', chunk);
callback(chunk); callback(chunk);
// console.log('chunkDataRef.current===2', chunkDataRef.current); // console.log('chunkDataRef.current===2', chunkDataRef.current);
@@ -419,14 +419,14 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
useEffect(() => { useEffect(() => {
if (size === 'custom') { if (size === 'custom') {
form.current?.form?.setFieldsValue({ form.current?.form?.setFieldsValue({
width: 256, width: 512,
height: 256 height: 512
}); });
setParams((pre: object) => { setParams((pre: object) => {
return { return {
...pre, ...pre,
width: 256, width: 512,
height: 256 height: 512
}; };
}); });
} }
+3 -5
View File
@@ -115,9 +115,7 @@ export const ImageParamsConfig: ParamsSchema[] = [
{ label: 'playground.params.custom', value: 'custom', locale: true }, { label: 'playground.params.custom', value: 'custom', locale: true },
{ label: '256x256', value: '256x256' }, { label: '256x256', value: '256x256' },
{ label: '512x512', value: '512x512' }, { label: '512x512', value: '512x512' },
{ label: '1024x1024', value: '1024x1024' }, { label: '1024x1024', value: '1024x1024' }
{ label: '1792x1024', value: '1792x1024' },
{ label: '1024x1792', value: '1024x1792' }
], ],
label: { label: {
text: 'playground.params.size', text: 'playground.params.size',
@@ -367,7 +365,7 @@ export const ImageCustomSizeConfig: ParamsSchema[] = [
}, },
attrs: { attrs: {
min: 256, min: 256,
max: 1792, max: 1024,
step: 64, step: 64,
inputnumber: false inputnumber: false
}, },
@@ -387,7 +385,7 @@ export const ImageCustomSizeConfig: ParamsSchema[] = [
}, },
attrs: { attrs: {
min: 256, min: 256,
max: 1792, max: 1024,
step: 64, step: 64,
inputnumber: false inputnumber: false
}, },