import { useMachine } from "@xstate/react" ; import { UseAudio } from "./useAudio.types" ; import PlayerMachine from "src/machines/Player/PlayerMachine" ; import { MachineContext , MachineEvent , Episode , } from "src/machines/Player/PlayerMachine.types" ; const useAudio = ( ) => { const [ state , send , service ] = useMachine < MachineContext , MachineEvent > ( PlayerMachine , { devTools : process . env . NODE_ENV === "development" , } ) ; param { string } src param { string } preload param { boolean } autoplay param { number } volume param { number } rate param { boolean } mute param { boolean } loop returns const onCreateAudio = ( src , episode ) : HTMLAudioElement => { const audioElement = new Audio ( src ) ; audioElement . autoplay = true ; audioElement . volume = 1.0 ; audioElement . muted = false ; audioElement . loop = false ; audioElement . playbackRate = 1.0 ; audioElement . preload = "auto" ; audioElement . addEventListener ( "loadstart" , ( ) => { send ( "LOAD" , { episode } ) ; } ) ; audioElement . addEventListener ( "loadeddata" , ( ) => { send ( "READY" , { duration : audioElement . duration } ) ; } ) ; audioElement . addEventListener ( "error" , ( ) => { send ( "ERROR" , { error : `Error while loading: ${ src }` , } ) ; } ) ; audioElement . addEventListener ( "play" , ( ) => { send ( "PLAY" ) ; } ) ; audioElement . addEventListener ( "pause" , ( ) => { send ( "PAUSE" ) ; } ) ; audioElement . addEventListener ( "volumechange" , ( ) => { send ( "VOLUME" , { volume : audioElement . volume , } ) ; } ) ; audioElement . addEventListener ( "ratechange" , ( ) => { send ( "RATE" , { rate : audioElement . playbackRate , } ) ; } ) ; audioElement . addEventListener ( "ended" , ( ) => { send ( "END" ) ; } ) ; return audioElement ; } ; param { HTMLAudioElement | undefined } audio param { CreateAudioArgs } args returns const onLoadAudio = ( audio , src , episode ) : HTMLAudioElement => { if ( audio instanceof HTMLAudioElement ) { const currentSrc = audio . currentSrc ; if ( currentSrc === src ) { return audio ; } send ( "LOAD" , { episode } ) ; audio . setAttribute ( "src" , src ) ; audio . load ( ) ; return audio ; } else { const newAudio = onCreateAudio ( src , episode ) ; return newAudio ; } } ; param audio returns const onDestroyAudio = ( audio ) : void => { if ( ! audio ) { return undefined ; } else { audio . currentTime = 0 ; audio . removeAttribute ( "src" ) ; audio = undefined ; } } ; return { state , send , service , onCreateAudio , onLoadAudio , onDestroyAudio , } ; } ; export default useAudio ;