import { useInterpret } from '@xstate/react' ; import RooverMachine from '../../machine/Machine' ; import { UseAudio , CreateAudioArgs , MachineContext , MachineEvent , } from '../../types' ; import { EVENTS , STATUS } from '../../utils/constants' ; const useAudio = ( ) => { const service = useInterpret < MachineContext , MachineEvent > ( RooverMachine , { 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 = '' , preload = 'auto' , autoplay = false , volume = 1.0 , rate = 1.0 , mute = false , loop = false , } ) : HTMLAudioElement => { const audioElement = new Audio ( src ) ; audioElement . autoplay = autoplay ; audioElement . volume = volume ; audioElement . muted = mute ; audioElement . loop = loop ; audioElement . playbackRate = rate ; audioElement . preload = preload ; audioElement . addEventListener ( 'loadstart' , ( ) => { service . send ( STATUS . LOAD , { volume : volume , rate : rate , mute : mute , loop : loop } ) ; } ) ; audioElement . addEventListener ( 'loadeddata' , ( ) => { service . send ( STATUS . READY , { duration : audioElement . duration } ) ; } ) ; audioElement . addEventListener ( 'error' , ( ) => { service . send ( STATUS . ERROR , { error : `Error while loading: ${ src }` } ) ; } ) ; audioElement . addEventListener ( 'play' , ( ) => { service . send ( EVENTS . PLAY ) ; } ) ; audioElement . addEventListener ( 'pause' , ( ) => { service . send ( EVENTS . PAUSE ) ; } ) ; audioElement . addEventListener ( 'volumechange' , ( ) => { service . send ( EVENTS . VOLUME , { volume : audioElement . volume } ) ; } ) ; audioElement . addEventListener ( 'ratechange' , ( ) => { service . send ( EVENTS . RATE , { rate : audioElement . playbackRate } ) ; } ) ; audioElement . addEventListener ( 'ended' , ( ) => { service . send ( EVENTS . END ) ; } ) ; return audioElement ; } ; param { HTMLAudioElement | undefined } audio param { CreateAudioArgs } args returns const onLoadAudio = ( audio , args ) : HTMLAudioElement => { if ( audio instanceof HTMLAudioElement ) { const currentSrc = audio . currentSrc ; if ( currentSrc === args . src ) { return audio ; } service . send ( 'LOAD' , { volume : args . volume , rate : args . rate , mute : args . mute , loop : args . loop } ) ; audio . setAttribute ( 'src' , audio . src ) ; audio . load ( ) ; return audio ; } else { const newAudio = onCreateAudio ( args ) ; return newAudio ; } } ; param audio returns const onDestroyAudio = ( audio ) : undefined => { if ( ! audio ) { return undefined ; } else { audio . currentTime = 0 ; audio . removeAttribute ( 'src' ) ; audio = undefined ; return audio ; } } ; return { service , onCreateAudio , onLoadAudio , onDestroyAudio } ; } ; export default useAudio ;