fix: audio player pause
This commit is contained in:
@@ -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;
|
||||||
|
}
|
||||||
@@ -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}
|
||||||
|
|||||||
@@ -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
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user