import { formatTime } from '@/utils/index'; import { FastBackwardOutlined, FastForwardOutlined, PauseCircleFilled, PlayCircleFilled } from '@ant-design/icons'; import { useIntl } from '@umijs/max'; import { Button, Slider, Tooltip } from 'antd'; import { round } from 'lodash'; import React, { forwardRef, useCallback, useEffect, useImperativeHandle } from 'react'; import './index.less'; interface AudioPlayerProps { autoplay?: boolean; url: string; speed?: number; ref?: any; name: string; height?: number; width?: number; duration?: number; } const speedOptions = [ { label: '1x', value: 1 }, { label: '2x', value: 2 }, { label: '3x', value: 3 }, { label: '4x', value: 4 } ]; const speedConfig = { min: 0.5, max: 2, step: 0.25 }; const AudioPlayer: React.FC = forwardRef((props, ref) => { const intl = useIntl(); const { autoplay = false, speed: defaultSpeed = 1 } = props; const audioRef = React.useRef(null); const [audioState, setAudioState] = React.useState<{ currentTime: number; duration: number; }>({ currentTime: 0, duration: 0 }); const [playOn, setPlayOn] = React.useState(false); const [speakerOn, setSpeakerOn] = React.useState(false); const [volume, setVolume] = React.useState(1); const [speed, setSpeed] = React.useState(defaultSpeed); const timer = React.useRef(null); useImperativeHandle(ref, () => ({ play: () => { audioRef.current?.play(); }, pause: () => { audioRef.current?.pause(); } })); const handleShowVolume = useCallback(() => { setSpeakerOn(!speakerOn); }, [speakerOn]); const handleSeepdChange = useCallback((value: number | string) => { setSpeed(value as number); audioRef.current!.playbackRate = value as number; }, []); const handleAudioOnPlay = useCallback(() => { console.log('audio play'); timer.current = setInterval(() => { setAudioState((prestate) => { return { currentTime: Math.ceil(audioRef.current?.currentTime || 0), duration: prestate.duration || Math.ceil(audioRef.current?.duration || 0) }; }); if (audioRef.current?.paused || audioRef.current?.ended) { clearInterval(timer.current); setPlayOn(false); setAudioState((prestate: any) => { return { currentTime: audioRef.current?.ended ? 0 : prestate.currentTime, duration: prestate.duration }; }); } }, 500); }, []); const handlePlay = useCallback(() => { setPlayOn(!playOn); if (playOn) { audioRef.current?.pause(); } else { audioRef.current?.play(); } }, [playOn]); const handleFormatVolume = (val?: number) => { if (val === undefined) { return `${round(volume * 100)}%`; } return `${round(val * 100)}%`; }; const handleVolumeChange = useCallback((value: number) => { audioRef.current!.volume = round(value, 2); setVolume(round(value, 2)); }, []); const initPlayerConfig = () => { if (audioRef.current) { audioRef.current!.volume = volume; audioRef.current!.playbackRate = speed; } }; const handleLoadedMetadata = useCallback( (data: any) => { const duration = Math.ceil(audioRef.current?.duration || 0); setAudioState({ currentTime: 0, duration: duration && duration !== Infinity ? duration : props.duration || 0 }); setPlayOn(autoplay); }, [autoplay, props.duration] ); const handleCurrentChange = useCallback((val: number) => { audioRef.current!.currentTime = val; setAudioState((prestate) => { return { currentTime: val, duration: prestate.duration }; }); }, []); const handleReduceSpeed = () => { setSpeed((pre) => { if (pre - speedConfig.step < speedConfig.min) { return speedConfig.min; } const next = pre - speedConfig.step; audioRef.current!.playbackRate = next; return next; }); }; const handleAddSpeed = () => { setSpeed((pre) => { if (pre + speedConfig.step > speedConfig.max) { return speedConfig.max; } const next = pre + speedConfig.step; audioRef.current!.playbackRate = next; return next; }); }; const handleOnLoad = (e: any) => { console.log('onload', e); }; useEffect(() => { if (audioRef.current) { initPlayerConfig(); } }, [audioRef.current]); useEffect(() => { return () => { clearInterval(timer.current); }; }, []); return (
{props.name}
{' '} {formatTime(audioState.currentTime)}
{formatTime(audioState.duration)}
); }); export default React.memo(AudioPlayer);