Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bufferStalledError on iOS 18.0.1 when looping video #6890

Closed
5 tasks done
roouit opened this issue Dec 4, 2024 · 5 comments · Fixed by #6980
Closed
5 tasks done

bufferStalledError on iOS 18.0.1 when looping video #6890

roouit opened this issue Dec 4, 2024 · 5 comments · Fixed by #6980
Labels
Browser issue If there is an underlying issue with the browser that hls.js is running on, this tag should be used. browser: Safari Bug Verify Fixed An unreleased bug fix has been merged and should be verified before closing.
Milestone

Comments

@roouit
Copy link

roouit commented Dec 4, 2024

What version of Hls.js are you using?

1.5.15

What browser (including version) are you using?

Mobile Safari 18.0.1

What OS (including version) are you using?

iOS 18.0.1

Test stream

https://hlsjs.video-dev.org/demo/?src=https%3A%2F%2Fvz-dfb04804-1a1.b-cdn.net%2Fe769e9cc-2c93-4179-911f-64d0b88fc0ba%2Fplaylist.m3u8&demoConfig=eyJlbmFibGVTdHJlYW1pbmciOnRydWUsImF1dG9SZWNvdmVyRXJyb3IiOnRydWUsInN0b3BPblN0YWxsIjpmYWxzZSwiZHVtcGZNUDQiOmZhbHNlLCJsZXZlbENhcHBpbmciOi0xLCJsaW1pdE1ldHJpY3MiOi0xfQ==

Configuration

{
  "debug": true,
  "enableWorker": true,
  "lowLatencyMode": true,
  "backBufferLength": 90
}

Additional player setup steps

Player needs to have loop enabled

Checklist

Steps to reproduce

  1. Open test stream page with iOS 18.0.1 device. I think any 18.* version is affected
  2. Enable loop on the video

In the demo page I managed to get this done by adding the "loop" attribute to the video element manually by connecting my iPhone to a Mac. I didn't see any toggle or option in the page for it.

Alternatively you can reproduce it by playing the video here: https://iframe.mediadelivery.net/embed/183266/e769e9cc-2c93-4179-911f-64d0b88fc0ba?autoplay=false&loop=true&muted=true&preload=false

  1. Play the video and wait until the end of video

Expected behaviour

Video should loop from the start

What actually happened?

Video stops on the last frame and there is bufferStalledError in the console. Code is also stuck on some loop based on console logs.

This happens almost every time on the first loop, but sometimes it might take two or more loops.

In the canary version (https://hlsjs-dev.video-dev.org/demo) this happens much more rarely for some reason, but I observed it happen.

Console output

[Log] Using Hls.js config: – {debug: true, enableWorker: true, lowLatencyMode: true, …} (hls-demo.js, line 24445)
{debug: true, enableWorker: true, lowLatencyMode: true, backBufferLength: 90}Object
[Log] [log] >"Debug logs enabled for \"Hls instance\" in hls.js version 1.5.17" (hls.js, line 555)
[Log] [log] >"stopLoad" (hls.js, line 28714)
[Log] [log] >"loadSource:https://vz-dfb04804-1a1.b-cdn.net/e769e9cc-2c93-4179-911f-64d0b88fc0ba/playlist.m3u8" (hls.js, line 28681)
[Log] [log] >"[stream-controller]:""Trigger BUFFER_RESET" (hls.js, line 27726)
[Log] [log] >"attachMedia" (hls.js, line 28653)
[Log] [log] >"[buffer-controller]""created media source: ManagedMediaSource" (hls.js, line 18439)
[Log] [log] >"[level-controller]:""manifest loaded, 1 level(s) found, first bitrate: 2800000" (hls.js, line 26403)
[Log] [log] >"setting initial bwe to 2800000" (hls.js, line 7373)
[Log] [log] >"[buffer-controller]""1 bufferCodec event(s) expected" (hls.js, line 18431)
[Log] [log] >"startLoad(-1)" (hls.js, line 28703)
[Log] [log] >"[level-controller]:""Switching to level 0 (720p SDR @2800000) from level -1" (hls.js, line 26617)
[Log] [log] >"[level-controller]:""Loading level index 0 with https://vz-dfb04804-1a1.b-cdn.net/e769e9cc-2c93-4179-911f-64d0b88fc0ba/1280x720/video.m3u8" (hls.js, line 26506)
[Log] [log] >"[stream-controller]:""STOPPED->IDLE" (hls.js, line 10764)
[Log] [log] >"[subtitle-stream-controller]:""STOPPED->IDLE" (hls.js, line 10764)
[Log] [log] >"[buffer-controller]""Media source opened" (hls.js, line 18324)
[Log] [log] >"[stream-controller]:""IDLE->STOPPED" (hls.js, line 10764)
[Log] [log] >"[level-controller]:""Switching to level 0 (720p SDR @2800000) from level 0" (hls.js, line 26617)
[Log] [log] >"[level-controller]:""Loading level index 0 with https://vz-dfb04804-1a1.b-cdn.net/e769e9cc-2c93-4179-911f-64d0b88fc0ba/1280x720/video.m3u8" (hls.js, line 26506)
[Log] [log] >"[stream-controller]:""STOPPED->IDLE" (hls.js, line 10764)
[Log] [log] >"[subtitle-stream-controller]:""IDLE->STOPPED" (hls.js, line 10764)
[Log] [log] >"[subtitle-stream-controller]:""STOPPED->IDLE" (hls.js, line 10764)
[Log] [log] >"[stream-controller]:""Level 0 loaded [0,0], cc [0, 0] duration:3.4" (hls.js, line 27772)
[Log] [log] >"[buffer-controller]""Updating Media Source duration to 3.400" (hls.js, line 18978)
[Log] [log] >"[stream-controller]:""Loading fragment 0 cc: 0 of [0-0] level: 0, target: 0" (hls.js, line 10017)
[Log] [log] >"[stream-controller]:""IDLE->FRAG_LOADING" (hls.js, line 10764)
[Log] [log] >"injecting Web Worker for \"main\"" (hls.js, line 16003)
[Log] [log] >"[transmuxer-interface, main]: Starting new transmux session for sn: 0 p: -1 level: 0 id: 1↵    discontinuity: true↵    trackSwitch…" (hls.js, line 16104)
"[transmuxer-interface, main]: Starting new transmux session for sn: 0 p: -1 level: 0 id: 1
    discontinuity: true
    trackSwitch: true
    contiguous: false
    accurateTimeOffset: true
    timeOffset: 0
    initSegmentChange: true"
[Log] [log] >"[stream-controller]:""Loaded fragment 0 of level 0" (hls.js, line 9748)
[Log] [log] >"Debug logs enabled for \"main\" in hls.js version 1.5.17" (4090a1c5-69b0-49fe-8e8b-dd4d315a971e, line 555)
[Log] [log] >"[mp4-remuxer]: ISGenerated flag reset" (hls.js, line 16220)
[Log] [log] >"[mp4-remuxer]: initPTS & initDTS reset" (hls.js, line 16220)
[Log] [log] >"[mp4-remuxer]: reset next timestamp" (hls.js, line 16220)
[Log] [log] >"manifest codec:undefined, ADTS type:2, samplingIndex:3" (hls.js, line 16220)
[Log] [log] >"parsed codec:mp4a.40.5, rate:48000, channels:2" (hls.js, line 16220)
[Log] [log] >"[stream-controller]:""FRAG_LOADING->PARSING" (hls.js, line 10764)
[Log] [log] >"[stream-controller]:""Init audio buffer, container:audio/mp4, codecs[selected/level/parsed]=[//mp4a.40.5]" (hls.js, line 28288)
[Log] [log] >"[stream-controller]:""Init video buffer, container:video/mp4, codecs[level/parsed]=[/avc1.4d401f]" (hls.js, line 28293)
[Log] [log] >"[buffer-controller]""0 bufferCodec event(s) expected audio,video" (hls.js, line 18599)
[Log] [log] >"[buffer-controller]""creating sourceBuffer(audio/mp4;codecs=mp4a.40.5)" (hls.js, line 19050)
[Log] [log] >"[buffer-controller]""creating sourceBuffer(video/mp4;codecs=avc1.4d401f)" (hls.js, line 19050)
[Log] [log] >"[audio-stream-controller]:""InitPTS for cc: 0 found from main: 130080" (hls.js, line 16355)
[Log] [log] >"[transmuxer.ts]: Flushed fragment 0 of level 0" (hls.js, line 16220)
[Log] [log] >"[stream-controller]:""PARSING->PARSED" (hls.js, line 10764)
[Log] [log] >"[stream-controller]:""Buffered main sn: 0 of level 0 (frag:[0.000-3.435] > buffer:[0.021-3.421])" (hls.js, line 9892)
[Log] [log] >"[stream-controller]:""PARSED->IDLE" (hls.js, line 10764)
[Log] [log] >"[buffer-controller]""audio sourceBuffer now EOS" (hls.js, line 18821)
[Log] [log] >"[buffer-controller]""video sourceBuffer now EOS" (hls.js, line 18821)
[Log] [log] >"[buffer-controller]""Queueing mediaSource.endOfStream()" (hls.js, line 18827)
[Log] [log] >"[stream-controller]:""IDLE->ENDED" (hls.js, line 10764)
[Log] [log] >"[buffer-controller]""Calling mediaSource.endOfStream()" (hls.js, line 18842)
[Log] [log] >"[buffer-controller]""Media source ended" (hls.js, line 18343)
[Log] [log] >"[stream-controller]:""ENDED->STOPPED" (hls.js, line 10764)
[Log] [log] >"[subtitle-stream-controller]:""IDLE->STOPPED" (hls.js, line 10764)
[Log] [log] >"[stream-controller]:""STOPPED->IDLE" (hls.js, line 10764)
[Info] [info] >"[abr] buffer is empty, optimal quality level 0" (hls.js, line 7624)
[Log] [log] >"[buffer-controller]""Queueing mediaSource.endOfStream()" (hls.js, line 18827)
[Log] [log] >"[stream-controller]:""IDLE->ENDED" (hls.js, line 10764)
[Log] [log] >"[subtitle-stream-controller]:""STOPPED->IDLE" (hls.js, line 10764)
[Log] [log] >"[buffer-controller]""Could not call mediaSource.endOfStream(). mediaSource.readyState: ended" (hls.js, line 18838)
[Log] [log] >"[stream-controller]:""ENDED->STOPPED" (hls.js, line 10764)
[Log] [log] >"[subtitle-stream-controller]:""IDLE->STOPPED" (hls.js, line 10764)
[Log] [log] >"[stream-controller]:""Override startPosition with lastCurrentTime @3.435" (hls.js, line 27397)
[Log] [log] >"[stream-controller]:""STOPPED->IDLE" (hls.js, line 10764)
[Info] [info] >"[abr] buffer is empty, optimal quality level 0" (hls.js, line 7624)
[Log] [log] >"[buffer-controller]""Queueing mediaSource.endOfStream()" (hls.js, line 18827)
[Log] [log] >"[stream-controller]:""IDLE->ENDED" (hls.js, line 10764)
3:52
[Warning] [warn] >"Playback stalling at @3.4346666666666668 due to low buffer ({\"len\":0,\"start\":3.4346666666666668,\"end\":3.4346666666666668})" (hls.js, line 27184)
[Warning] Error event: – {type: "mediaError", details: "bufferStalledError", fatal: false, …} (hls-demo.js, line 24783)
{type: "mediaError", details: "bufferStalledError", fatal: false, error: Error: Playback stalling at @3.4346666666666668 due to low buffer ({"len":0,"start":3.43466666666666…, buffer: 0, …}Object
[Log] [log] >"[subtitle-stream-controller]:""STOPPED->IDLE" (hls.js, line 10764)
[Log] [log] >"[buffer-controller]""Could not call mediaSource.endOfStream(). mediaSource.readyState: ended" (hls.js, line 18838)
[Log] [log] >"[stream-controller]:""ENDED->STOPPED" (hls.js, line 10764)
[Log] [log] >"[subtitle-stream-controller]:""IDLE->STOPPED" (hls.js, line 10764)
[Log] [log] >"[stream-controller]:""Override startPosition with lastCurrentTime @3.435" (hls.js, line 27397)
[Log] [log] >"[stream-controller]:""STOPPED->IDLE" (hls.js, line 10764)
[Info] [info] >"[abr] buffer is empty, optimal quality level 0" (hls.js, line 7624)
[Log] [log] >"[buffer-controller]""Queueing mediaSource.endOfStream()" (hls.js, line 18827)
[Log] [log] >"[stream-controller]:""IDLE->ENDED" (hls.js, line 10764)
[Log] [log] >"[subtitle-stream-controller]:""STOPPED->IDLE" (hls.js, line 10764)
[Log] [log] >"[buffer-controller]""Could not call mediaSource.endOfStream(). mediaSource.readyState: ended" (hls.js, line 18838)
[Log] [log] >"[stream-controller]:""ENDED->STOPPED" (hls.js, line 10764)
[Log] [log] >"[subtitle-stream-controller]:""IDLE->STOPPED" (hls.js, line 10764)
[Log] [log] >"[stream-controller]:""Override startPosition with lastCurrentTime @3.435" (hls.js, line 27397)
[Log] [log] >"[stream-controller]:""STOPPED->IDLE" (hls.js, line 10764)
[Info] [info] >"[abr] buffer is empty, optimal quality level 0" (hls.js, line 7624)
[Log] [log] >"[buffer-controller]""Queueing mediaSource.endOfStream()" (hls.js, line 18827)
[Log] [log] >"[stream-controller]:""IDLE->ENDED" (hls.js, line 10764)
[Log] [log] >"[subtitle-stream-controller]:""STOPPED->IDLE" (hls.js, line 10764)
... This keeps on going in a loop

Chrome media internals output

No response

@roouit roouit added Bug Needs Triage If there is a suspected stream issue, apply this label to triage if it is something we should fix. labels Dec 4, 2024
@robwalch
Copy link
Collaborator

robwalch commented Dec 4, 2024

Related to requests to enhance looping support:

If playback is not looping, then the issue is that the 'ended' event is not being emitted. This bug resurfaces frequently in Safari. I recommend trying the latest canary build, and also verifying that the end of your audio and video tracks are aligned.

@robwalch robwalch added Browser issue If there is an underlying issue with the browser that hls.js is running on, this tag should be used. browser: Safari labels Dec 4, 2024
@robwalch
Copy link
Collaborator

robwalch commented Dec 4, 2024

hls.js is calling mediaSource.endOfStream() correctly.

[Log] [log] > – "[buffer-controller]" – "audio sourceBuffer now EOS" (hls.js, line 18821)
[Log] [log] > – "[buffer-controller]" – "video sourceBuffer now EOS" (hls.js, line 18821)
[Log] [log] > – "[buffer-controller]" – "Queueing mediaSource.endOfStream()" (hls.js, line 18827)
[Log] [log] > – "[stream-controller]:" – "IDLE->ENDED" (hls.js, line 10764)
[Log] [log] > – "[buffer-controller]" – "Calling mediaSource.endOfStream()" (hls.js, line 18842)
[Log] [log] > – "[buffer-controller]" – "Media source ended" (hls.js, line 18343)

After that, Safari does not emit the "ended" event (or handled correctly by seeking back to 0 when the loop attribute is set). The starting/stopping is coming from calls to hls.startLoad() in your application. Instead of ended and looping with a seek to 0, the media element may be emitting 'play' or other events (I get seeking without any change in position in desktop Safari 18.1.1).

@gkashe
Copy link

gkashe commented Jan 28, 2025

I can confirm that this is still happening in the latest version of hls (1.5.20) and happens in both Safari and Chrome on iOS

@robwalch
Copy link
Collaborator

Hi @gkashe,

Chrome and Safari both use WebKit on iOS so don't expect behavior to be any different there. The comment above describes the bug in part (the "ended" event is not emitted). You can try hls.js@v1.6.0-beta.2 - while it doesn't work around any flaws in the browsers handling of playback or looping at end-of-stream, HLS.js does detect when playback has ended and will emit MEDIA_ENDED which you can use in the place of "ended" on platforms with this bug. You can also try a build of #6972 if you are following along with development as this revamps the code responsible for stall detection.

@robwalch
Copy link
Collaborator

I was able to reproduce in latest and found a workaround where delaying the call to MediaSource.endOfStream() until currentTime is past the start of the buffered region. Let me know if this resolves the issue for you:

@robwalch robwalch removed the Needs Triage If there is a suspected stream issue, apply this label to triage if it is something we should fix. label Jan 28, 2025
@robwalch robwalch added the Verify Fixed An unreleased bug fix has been merged and should be verified before closing. label Jan 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Browser issue If there is an underlying issue with the browser that hls.js is running on, this tag should be used. browser: Safari Bug Verify Fixed An unreleased bug fix has been merged and should be verified before closing.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants