import React , { useEffect , useRef } from "react" ; const isSafari = ( ( /iPad|iPhone|iPod/ . test ( navigator . platform ) || ( navigator . platform === "MacIntel" && navigator . maxTouchPoints > 1 ) ) && ! window . MSStream ) || /^((?!chrome|android).)*safari/i . test ( navigator . userAgent ) ; let audioBank = [ ] ; if ( isSafari ) { audioBank = Array . from ( { length : 100 } , ( el ) => ( document . createElement ( "audio" ) as unknown ) as HTMLAudioElement ) ; } let prepared = false ; export function prepareAudioBank ( ) { if ( prepared || ! isSafari ) { return ; } audioBank . forEach ( ( audioElement ) => { try { audioElement . play ( ) . catch ( ( ) => { } ) ; audioElement . pause ( ) ; } catch ( e ) { console . error ( "uh oh" ) ; } } ) ; prepared = true ; } interface IAutoPlayAudioProps { srcObject ? : MediaStream ; volume ? : number ; } const AutoPlayAudio = ( { srcObject , volume = 1.0 , } ) => { const audioElement = useRef < HTMLAudioElement > ( audioBank . pop ( ) || document . createElement ( "audio" ) ) ; useEffect ( ( ) => { if ( ! prepared && isSafari ) { throw new Error ( "Audios are not prepared" ) ; } if ( ! srcObject ) { return ; } const element = audioElement . current ; function canplay ( ) { element . play ( ) . catch ( ( e ) => { console . error ( e ) ; } ) ; } element . addEventListener ( "canplay" , canplay ) ; element . srcObject = srcObject ; return ( ) => { element . pause ( ) ; element . removeEventListener ( "canplay" , canplay ) ; element . srcObject = null ; if ( isSafari ) { audioBank . push ( element ) ; } } ; } , [ srcObject ] ) ; useEffect ( ( ) => { const element = audioElement . current ; element . volume = volume ; return ( ) => { element . volume = 1.0 ; } ; } , [ volume ] ) ; return < div ref = { ( el ) => el && el . appendChild ( audioElement . current ) } />; } ; export default AutoPlayAudio ;