7

iOS Safari requires a touch event to play/pause media elements. Without, you get the:

NotAllowedError: The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission. caught promiseReaction error message.

The question is "How to delay the <MediaElement>.play() call without loosing the touch event context??"

I'm trying to play a media element with a delay after the click, but in the two methods I've come up with (Promise & setTimeout), they both loose the connection to the touch event and I get the NotAllowedError error due to the scope change of the <MediaElement>.play() call. Both work on all ES6 devices/browsers other than iOS Safari, as expected.

Feel free to play with it here on codepen.

const delay = ms => new Promise(res => setTimeout(res, ms));

const video = document.querySelector('video'),
      button = document.querySelector('button')

const playVideoSyncDelay = async e => {
  document.body.classList.add('blackground')
  await delay(3000)
  video.play()
    .then( e => video.onended = e => document.body.classList.remove('blackground', 'playing') )
    .then( e => document.body.classList.add('playing') )
    .catch( e => console.error('Oops:', e) )
}

const playVideoTimeoutDelay = e => {
  document.body.classList.add('blackground')
  setTimeout(e => {
    video.play()
      .then( e => video.onended = e => document.body.classList.remove('blackground', 'playing') )
      .then( e => document.body.classList.add('playing') )
      .catch( e => console.error('Oops:', e) )
  }, 3000, e)
}

/**
BOTH BELOW RESULT IN DELAYED NotAllowedError: ...not in the current context...
**/
//button.onclick = playVideoTimeoutDelay;
button.onclick = playVideoSyncDelay;
  • Did you ever come up with a fix for this? – Brian Nov 11 '22 at 11:58
  • I don’t even remember asking this question, but I think this could be done in this order: 1) call .load) – Joe Weitzel Nov 12 '22 at 16:08
  • Oops hit submit too soon. Inside your onclick =e=> { .load(); setTimeout(()=> .play(), 1000); } – Joe Weitzel Nov 12 '22 at 16:15
  • Havt tested but .load() should give the user access to control the Media Element, and then they can call .play() with a delay. I don’t think .load with play the media but in case it does, pause it after load() and before setTimeout(). – Joe Weitzel Nov 12 '22 at 16:18

1 Answers1

2

If the user calls .load() before the delayed .play(), they can delayed play on mobile browsers.

Here is a codepen: https://codepen.io/joeweitzel/pen/RwJVBNL $media.load(); $setTimeout(()=>$media.play, 2000)