question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Properly handle the Promise returned by <audio>.play()

See original GitHub issue

Background

In modern browsers, the HTMLMediaElement.play() method is not always synchronous. According to MDN:

The HTMLMediaElement.play() method attempts to begin playback of the media and returns a Promise which is fulfilled when the playback has been successfully started, and which is rejected if playback fails to begin for any reason (such as permission issues or other problems).

It seems that “permission issues” cover mobile/recent desktop browser decisions to ignore autoplay. Google has published an article about this here which points to this example page. Running that example on an iPhone indeed reports a permissions issue in the output.

In fact, the “permissions” issue for autoplay is no longer limited to mobile contexts. Safari now disables autoplay functionality on the Desktop by default as well. Opening Google’s example page in Safari shows this error:

Attempting to play automatically… The play() Promise rejected! Use the Play button instead. {“code”:35,“name”:“NotAllowedError”,“message”:“The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission.”,“line”:124,“column”:47,“sourceURL”:“https://googlechrome.github.io/samples/play-return-promise/”}

Google has also published a document that goes into greater detail about the causes of this. Of particular interest is this note:

Note: Calling video.pause() isn’t the only way to interrupt a video. You can entirely reset the video playback state, including the buffer, with video.load() and video.src = ''.

(Note that the same applies for audio.)

In APlayer

Currently, APlayer does not attempt to capture the returned Promise. This is the latest from time of writing: https://github.com/MoePlayer/APlayer/blob/81002c0bf93425884bd565147ad3c2b85762ca44/src/APlayer.js#L738-L745

Proper handling of the <audio> element requires handling the Promise. It is exceptionally simple to cause exceptions with the <audio> API (see: #155).

In fact, the basic Demo Page shows this in the console directly after the APlayer version report:

[Error] Unhandled Promise Rejection: NotAllowedError (DOM Exception 35): The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission.

I have created a JSFiddle that shows a range of ways to deal with the HTMLMediaElement API. Try each of the four buttons and check the JavaScript console and output block. Please also take a look at the implementation of the best() function. It shows a unified way to handle the API in environments that return Promises and undefined.

I would highly recommend that the APlayer codebase be updated to properly handle Promises. This may also require holding a reference to the most recent Promise returned by the HTMLMediaElement.play() function (as well as a “playPending” boolean?) so that you can chain other calls (pause(), load(), etc.) off of it.

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:2
  • Comments:32 (28 by maintainers)

github_iconTop GitHub Comments

4reactions
DIYgodcommented, Mar 8, 2018

@ericdrobinson You are right, I fix playedPromise overwritten in your first way(https://github.com/MoePlayer/APlayer/commit/cf5972879a27459445aaf730f7777c9400667881#r27989819) in fb4211a0b050a065f1ecc3e5eb37b97f0bd96ffc.

Does this make sense?

2reactions
SevenOutmancommented, Mar 9, 2018

@ericdrobinson Glad to see it’s finally resolved. Gonna keep up with it.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Properly handle the Promise returned by <audio>.play() #179
The HTMLMediaElement.play() method attempts to begin playback of the media and returns a Promise which is fulfilled when the playback has ...
Read more >
How to correctly handle media.play() promise across browsers
As autoplay is unreliable across browsers, there is a blog post on the video js website where they advice to do this: let...
Read more >
HTMLMediaElement.play() Returns a Promise Sample
Sample illustrating the use of HTMLMediaElement.play() Returns a Promise.
Read more >
DOMException - The play() request was interrupted
If playback succeeds, the Promise is fulfilled and the playing event is fired at the same time. If playback fails, the Promise is...
Read more >
audio play promise | The AI Search Engine You Control
The audio is an HTMLMediaElement , and calling play() returns a Promise, so needs to be handled. Depending on the size of the...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found