Bug 173332

Summary: HTML5 audio .ended event not fired when app in background or phone screen is off
Product: WebKit Reporter: Judah Gabriel Himango <judahgabriel>
Component: MediaAssignee: Jer Noble <jer.noble>
Status: RESOLVED FIXED    
Severity: Major CC: beidson, brad, calvaris, cdumez, cmawebsite, commit-queue, contact, craigwharding, eric.carlson, esprehn+autocc, ews-watchlist, glenn, gyuyoung.kim, jer.noble, jond, jonlee, mathiasrechtzigel, philipj, sergio, tobias.gerhardsson, vikas, webkit-bug-importer
Priority: P2 Keywords: HTML5, InRadar
Version: Safari 10   
Hardware: iPhone / iPad   
OS: iOS 10   
URL: http://bitshuvafiles01.com/iOSAudioBugRepro/audioError.html
Attachments:
Description Flags
Patch
none
Patch for landing none

Judah Gabriel Himango
Reported 2017-06-13 14:48:26 PDT
When HTML5 audio finishes playing, the .ended event doesn't fire if the web app is running in the background or if the screen is off. Here's a simple page that demonstrates the problem: http://bitshuvafiles01.com/iOSAudioBugRepro/audioError.html Steps to reproduce: 1. Create web page with a single <audio> element. 2. In JavaScript, set audio.src = "song1.mp3", and .play(); 3. Add an .ended event handler to the audio element. In the .ended event handler, set audio.src = "song2.mp3", and .play(). 4. While song1.mp3 is playing, turn off the phone screen. 5. Wait for the audio to finish. When it finishes, audio will stop; song2.mp3 will never. Expected results: The audio.ended event fires and the next song starts playing. Actual results: The audio.ended event never fires because the screen is off or because Safari is in the background; JS execution is suspended. Additional info: While suspending JS execution is wise for battery life reasons, it harms the user experience when listening to audio on the web. Either don't suspend JS execution for tabs playing audio, or at least fire the .ended event so we can play the next song.
Attachments
Patch (11.88 KB, patch)
2019-11-13 14:07 PST, Jer Noble
no flags
Patch for landing (11.94 KB, patch)
2019-11-15 15:07 PST, Jer Noble
no flags
Radar WebKit Bug Importer
Comment 1 2017-06-13 20:11:12 PDT
Eric Carlson
Comment 2 2017-06-14 08:26:30 PDT
The web proces, normally suspended when in the background, is kept alive while playing audio (and for a few other reasons). The 'ended' event is fired asynchronously, so while the event is scheduled immediately when playback finishes, the task is suspended before the next runloop so the event doesn't fire until the process resumes. We should probably postpone suspension for a few cycles when playback stops to give scripts an opportunity to restart playback.
Judah Gabriel Himango
Comment 3 2017-06-14 09:53:29 PDT
>> "We should probably postpone suspension for a few cycles when playback stops to give scripts an opportunity to restart playback." Ah, that would wonderful and would fix the problem perfectly.
craigwharding
Comment 4 2017-08-11 04:29:31 PDT
Hi any idea when this could be committed and it starts to hit upstream?
Brady Eidson
Comment 5 2017-08-11 06:50:23 PDT
(In reply to craigwharding from comment #4) > Hi any idea when this could be committed and it starts to hit upstream? There's nothing to be committed because there's no patch yet. (This is an open source project)
Judah Gabriel Himango
Comment 6 2018-01-22 08:25:22 PST
This morning I received more reports of this same bug from my users on iOS. Any chance we get this fixed in 2018?
Mathias Rechtzigel
Comment 7 2019-01-18 10:45:15 PST
Confirmed still an issue.
Jer Noble
Comment 8 2019-11-13 12:53:01 PST
*** Bug 204080 has been marked as a duplicate of this bug. ***
Jer Noble
Comment 9 2019-11-13 14:07:44 PST
Eric Carlson
Comment 10 2019-11-14 05:12:42 PST
Comment on attachment 383493 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=383493&action=review r=me once the bots are happy > LayoutTests/media/audio-background-playback-playlist-expected.txt:2 > +RUN(internals.setMediaElementRestrictions(audio, "RequireUserGestureForAudioRateChange")) Oops, look like you need to regenerate this file. > LayoutTests/media/audio-background-playback-playlist.html:20 > + run('audio.load()'); > + testExpected('internals.bestMediaElementForShowingPlaybackControlsManager("NowPlaying")', audio); It would be better to test for NowPlaying status after a delay, e.g. after an 'emptied' event.
Jer Noble
Comment 11 2019-11-15 15:07:09 PST
Created attachment 383656 [details] Patch for landing
WebKit Commit Bot
Comment 12 2019-11-20 10:32:09 PST
Comment on attachment 383656 [details] Patch for landing Clearing flags on attachment: 383656 Committed r252692: <https://trac.webkit.org/changeset/252692>
WebKit Commit Bot
Comment 13 2019-11-20 10:32:11 PST
All reviewed patches have been landed. Closing bug.
craigwharding
Comment 14 2022-03-29 18:18:07 PDT
I’m getting this bug in iOS 15.3.1. It was fixed for me in iOS 14. Should I add info to this bug or open a new one and reference this bug?
Vikas Singh
Comment 15 2022-04-11 23:32:41 PDT
Hi, I am getting this bug again too in Safari in iOS 15. After screenlock, the JS execution is still continuing after the ended event on the audio element as console.log pumps out text. I set new src and call .play(). The promise for .play() resolves without errors, but audio does not play. The Media Sessions API also sets the correct track name/title. An example is here (not mine as mine is behind a paywall but I can create a minimum reproducible example if required): https://codepen.io/craigstroman/pen/aOyRYx To reproduce using the above example link: 1) Play the first track 2) Lock the screen 3) Wait around 3 minutes for the track to end Expected result: The next track should play automatically after ended event. Actual result: The next track does not play in iOS 15 Safari. Works fine in Android/Windows Chrome. What I have tried: changing the src and calling the play event directly inside the audio element's ended event. But all this only works when Safari is in focus, bot when in another app, or screen is locked. Would appreciate any help on this - I am at my wits end. Thanks!
tobeyg
Comment 16 2022-04-19 01:54:52 PDT
I'm still experiencing this in iOS 15.4.1. Both in browser and when running a site as a "home screen bookmark". Initially I got it working by having a function (initTrack()) that ran each time the user pressed played manually. The "ended" event listener was added within that function and all it did was to run initTrack() again. But all of a sudden it stopped working. The audio widget seems to reset it's currentTime and the Media Session API is changing the metadata, but before the new track starts playing, it seems like the sessions gets suspended.
cmawebsite
Comment 17 2022-05-06 12:01:26 PDT
I just want to add my experience with this too (on 15.4.1). My experience is slightly different than the bug title, because when the track ends, mine does appear to briefly switch to the next track and update the new mediaSession MediaMetaData, though fails to actually start playing that track and the new track goes away in less than a second. So I suspect that the _ended_ event _does_ fire, but it maybe doesn't seem to have permission to play() the next track? Also, when testing, I once found that my track stopped playing after a half-hour. I haven't done more testing to see if that always happens or not.
Eric Carlson
Comment 18 2022-05-06 13:57:34 PDT
The inability to begin playing in the background on iOS 15 should be fixed by the changes for 239812.
Eric Carlson
Comment 19 2022-05-06 13:58:28 PDT
(In reply to Eric Carlson from comment #18) > The inability to begin playing in the background on iOS 15 should be fixed > by the changes for 239812. Rather by r293530, bug https://bugs.webkit.org/show_bug.cgi?id=239812
craigwharding
Comment 20 2022-05-06 16:38:46 PDT
Thanks Eric! Do you know what iOS 15 release this will merged into?
Eric Carlson
Comment 21 2022-05-09 10:37:08 PDT
(In reply to craigwharding from comment #20) > Thanks Eric! Do you know what iOS 15 release this will merged into? Sorry, I don't know. I will try to remember to add a note here when a build with this fix is available.
Judah Gabriel Himango
Comment 22 2024-01-11 18:53:49 PST
It appears this bug has been reintroduced in iOS 17.2.1. Here's a simple repro: https://judahtemp.b-cdn.net/ios-webkit-audio-bug/bug.html
contact
Comment 23 2024-01-16 05:42:43 PST
(In reply to Judah Gabriel Himango from comment #22) > It appears this bug has been reintroduced in iOS 17.2.1. Here's a simple > repro: https://judahtemp.b-cdn.net/ios-webkit-audio-bug/bug.html I'm also facing a very similar issue that player can not play next track after ended in background. But on my side (17.2), it is not cause by 'ended' event not triggered. After playing stucked, I turn back to foreground and saw: player shows up the new track .duration, but old .currentTime In console I could see 'ended' triggered, new track 'canplay' triggerd, 'onplay' triggered, but audio does't play. I think my issue was more likely to https://bugs.webkit.org/show_bug.cgi?id=173332#c15 https://files.catbox.moe/fh3z47.png https://files.catbox.moe/xqlqjz.png
Judah Gabriel Himango
Comment 24 2024-01-18 14:58:24 PST
The above commenter (https://bugs.webkit.org/show_bug.cgi?id=173332#c23) is correct. The .ended event fires - great! And I can even call .play(). But no audio is heard. Bottom line: the issue isn't that ended event is not fired. It's that audio.play() does nothing when the app is in the background or the screen is locked. I've updated my repro to show the events that get fired: https://judahtemp.b-cdn.net/ios-webkit-audio-bug/bug.html
Judah Gabriel Himango
Comment 25 2024-01-18 15:34:00 PST
Since the issue isn't .ended event being fired, I'm closing this. Instead, let's move the discussion over to this bug, which seems to be the real issue: https://bugs.webkit.org/show_bug.cgi?id=261554
Note You need to log in before you can comment on or make changes to this bug.