import { useCallback , useContext , useEffect , useMemo , useRef } from "react" ; import { playerContext , positionContext } from "./context" ; import { Howl } from "howler" ; import useIsomorphicLayoutEffect from "./useIsomorphicLayout" ; interface UseAudioPositionConfig { highRefreshRate ? : boolean ; } interface AudioPosition { position : number ; duration : number ; percentComplete : number ; seek : ( position : number ) => number ; } export const useAudioPosition = ( config = { } ) : AudioPosition => { const { highRefreshRate = false } = config ; const { player , playing , stopped , duration } = useContext ( playerContext ) ! ; const { position , setPosition } = useContext ( positionContext ) ; const animationFrameRef = useRef < number > ( ) ; useEffect ( ( ) => { if ( player ) { setPosition ( player . seek ( ) as number ) ; } } , [ player , setPosition , stopped ] ) ; useEffect ( ( ) => { let timeout ; if ( ! highRefreshRate && player && playing ) timeout = window . setInterval ( ( ) => setPosition ( player . seek ( ) as number ) , 1000 ) ; return ( ) => clearTimeout ( timeout ) ; } , [ highRefreshRate , player , playing , setPosition ] ) ; useIsomorphicLayoutEffect ( ( ) => { const animate = ( ) => { setPosition ( player ?. seek ( ) as number ) ; animationFrameRef . current = requestAnimationFrame ( animate ) ; } ; if ( highRefreshRate && player && playing ) { animationFrameRef . current = requestAnimationFrame ( animate ) ; } return ( ) => { if ( animationFrameRef . current ) { cancelAnimationFrame ( animationFrameRef . current ) ; } } ; } , [ highRefreshRate , player , playing , setPosition ] ) ; const seek = useCallback ( position => { if ( ! player ) return 0 ; const result = player . seek ( position ) as Howl ; const updatedPos = result . seek ( ) as number ; setPosition ( updatedPos ) ; return updatedPos ; } , [ player , setPosition ] ) ; const percentComplete = useMemo ( ( ) => { return ( position / duration ) * 100 || 0 ; } , [ duration , position ] ) ; return { position , duration , seek , percentComplete } ; } ;