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

Airplay streaming issue on ios #6482

Open
5 tasks done
tvinko opened this issue Jun 6, 2024 · 12 comments
Open
5 tasks done

Airplay streaming issue on ios #6482

tvinko opened this issue Jun 6, 2024 · 12 comments
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

Comments

@tvinko
Copy link

tvinko commented Jun 6, 2024

What version of Hls.js are you using?

v1.5.11

What browser (including version) are you using?

Safari 17.5.1

What OS (including version) are you using?

IOS

Test stream

https://hlsjs.video-dev.org/demo/?src=https%3A%2F%2Fvz-b1d0f3b4-139.flufflecdn.net%2Fb13f6bba-728f-4fd3-88b4-ad8eb276976b%2Fplaylist.m3u8&demoConfig=eyJlbmFibGVTdHJlYW1pbmciOnRydWUsImF1dG9SZWNvdmVyRXJyb3IiOnRydWUsInN0b3BPblN0YWxsIjpmYWxzZSwiZHVtcGZNUDQiOmZhbHNlLCJsZXZlbENhcHBpbmciOi0xLCJsaW1pdE1ldHJpY3MiOi0xfQ==

Configuration

{
    debug: true,
    enableWorker: true,
    lowLatencyMode: true,
    backBufferLength: 90,
    preferManagedMediaSource: false,
}

Additional player setup steps

No response

Checklist

Steps to reproduce

  1. Host the following html snippet locally
<!DOCTYPE html>
<html>

<head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/hls.js/1.5.11/hls.min.js"
        integrity="sha512-Z0W3S5swMoBWjkNBP3ACbXA4mh/jdjJOTOOZfF1yIO0OdkIU373s/Tm+eaCbUQq7EEgKl9O1eji1ZgseHCUVgw=="
        crossorigin="anonymous" referrerpolicy="no-referrer"></script>
</head>

<body id="body">
    <video id="video" controls x-webkit-airplay="allow"></video>

    <script>
        var useHls = true;
        var autoplay = false;

        var urlPlaylistUrl =
            "https://vz-b1d0f3b4-139.flufflecdn.net/b13f6bba-728f-4fd3-88b4-ad8eb276976b/playlist.m3u8";

        var video = document.getElementById("video");

        video.controls = true;
        video.loop = true;
        video.muted = true;
        video.autoplay = autoplay;
        video.src = urlPlaylistUrl;

        if (useHls) {
            var hls = new Hls({
                debug: true,
                enableWorker: true,
                lowLatencyMode: true,
                backBufferLength: 90,
                preferManagedMediaSource: false,
            });

            hls.on(Hls.Events.MEDIA_ATTACHED, function () {
                console.log("video and hls.js are now bound together !");
            });

            hls.on(Hls.Events.MANIFEST_PARSED, function (event, data) {
                console.log(
                    "manifest loaded, found " + data.levels.length + " quality level"
                );
            });
            hls.loadSource(urlPlaylistUrl);

            hls.attachMedia(video);

            var airPlaySrc = document.createElement("source");
            airPlaySrc.src = urlPlaylistUrl;
            video.appendChild(airPlaySrc);
            video.disableRemotePlayback = false;
        }
    </script>
</body>

</html>
  1. Connect with iPhone client
  2. Select Airplay option
  3. Select streaming destination

Expected behaviour

Airplay should be streamed to selected destination

What actually happened?

The Airplay is not streamed with a given configuration.

However, I can stream if I enable autoplay:

var useHls = true;
var autoplay = true;

or if I use native hls:

var useHls = false;
var autoplay = false;

Console output

[Log] [log] >"Debug logs enabled for \"Hls instance\" in hls.js version 1.5.11" (hls.min.js, line 1)
[Log] [log] >"stopLoad" (hls.min.js, line 1)
[Log] [log] >"loadSource:https://vz-b1d0f3b4-139.flufflecdn.net/b13f6bba-728f-4fd3-88b4-ad8eb276976b/playlist.m3u8" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Trigger BUFFER_RESET" (hls.min.js, line 1)
[Log] [log] >"attachMedia" (hls.min.js, line 1)
[Log] [log] >"[buffer-controller]""created media source: ManagedMediaSource" (hls.min.js, line 1)
[Log] [log] >"[buffer-controller]""Media source opened" (hls.min.js, line 1)
[Log] video and hls.js are now bound together ! (test2.html, line 38)
[Log] [log] >"[level-controller]:""manifest loaded, 5 level(s) found, first bitrate: 1419909" (hls.min.js, line 1)
[Log] [log] >"setting initial bwe to 1419909" (hls.min.js, line 1)
[Log] [log] >"[buffer-controller]""1 bufferCodec event(s) expected" (hls.min.js, line 1)
[Log] manifest loaded, found 5 quality level (test2.html, line 42)
[Log] [log] >"startLoad(-1)" (hls.min.js, line 1)
[Log] [log] >"[abr] picked start tier {\"codecSet\":\"avc1,mp4a\",\"videoRanges\":[\"SDR\"],\"preferHDR\":false,\"minFramerate\":0,\"minBitrate\":1073607}" (hls.min.js, line 1)
[Info] [info] >"[abr] switch candidate:1->1 adjustedbw(1419909)-bitrate=0 ttfb:0.1 avgDuration:0.0 maxFetchDuration:4.0 fetchDuration:0.…" (hls.min.js, line 1)
"[abr] switch candidate:1->1 adjustedbw(1419909)-bitrate=0 ttfb:0.1 avgDuration:0.0 maxFetchDuration:4.0 fetchDuration:0.1 firstSelection:true codecSet:avc1,mp4a videoRange:SDR hls.loadLevel:-1"
[Log] [log] >"[level-controller]:""Switching to level 1 (360p SDR avc1,mp4a @1419909) from level -1" (hls.min.js, line 1)
[Log] [log] >"[level-controller]:""Loading level index 1 with https://vz-b1d0f3b4-139.flufflecdn.net/b13f6bba-728f-4fd3-88b4-ad8eb276976b/360p/video.m3u8" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""STOPPED->IDLE" (hls.min.js, line 1)
[Log] [log] >"[subtitle-stream-controller]:""STOPPED->IDLE" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Level 1 loaded [0,13][part-13--1], cc [0, 0] duration:52.208333" (hls.min.js, line 1)
[Log] [log] >"[buffer-controller]""Updating Media Source duration to 52.208" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Loading fragment 0 cc: 0 of [0-13] level: 1, target: 0" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""IDLE->FRAG_LOADING" (hls.min.js, line 1)
[Log] [log] >"injecting Web Worker for \"main\"" (hls.min.js, line 1)
[Log] [log] >"[transmuxer-interface, main]: Starting new transmux session for sn: 0 p: -1 level: 1 id: 1↵        discontinuity: true↵        trackSwitch…" (hls.min.js, line 1)
"[transmuxer-interface, main]: Starting new transmux session for sn: 0 p: -1 level: 1 id: 1
        discontinuity: true
        trackSwitch: true
        contiguous: false
        accurateTimeOffset: true
        timeOffset: 0
        initSegmentChange: true"
[Log] [log] >"[stream-controller]:""Loaded fragment 0 of level 1" (hls.min.js, line 1)
[Log] [log] >"Debug logs enabled for \"main\" in hls.js version 1.5.11" (5ca39030-38ae-4e1c-b4b7-59ee97a13aad, line 1)
[Log] [log] >"[mp4-remuxer]: ISGenerated flag reset" (hls.min.js, line 1)
[Log] [log] >"[mp4-remuxer]: initPTS & initDTS reset" (hls.min.js, line 1)
[Log] [log] >"[mp4-remuxer]: reset next timestamp" (hls.min.js, line 1)
[Log] [log] >"manifest codec:mp4a.40.2, ADTS type:2, samplingIndex:3" (hls.min.js, line 1)
[Log] [log] >"parsed codec:mp4a.40.5, rate:48000, channels:2" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""FRAG_LOADING->PARSING" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Init audio buffer, container:audio/mp4, codecs[selected/level/parsed]=[mp4a.40.2/mp4a.40.2/mp4a.40.5]" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Init video buffer, container:video/mp4, codecs[level/parsed]=[avc1.64001e/avc1.64001e]" (hls.min.js, line 1)
[Log] [log] >"[buffer-controller]""0 bufferCodec event(s) expected audio,video" (hls.min.js, line 1)
[Log] [log] >"[buffer-controller]""creating sourceBuffer(audio/mp4;codecs=mp4a.40.2)" (hls.min.js, line 1)
[Log] [log] >"[buffer-controller]""creating sourceBuffer(video/mp4;codecs=avc1.64001e)" (hls.min.js, line 1)
[Log] [log] >"[audio-stream-controller]:""InitPTS for cc: 0 found from main: 133500" (hls.min.js, line 1)
[Log] [log] >"[transmuxer.ts]: Flushed fragment 0 of level 1" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""PARSING->PARSED" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Buffered main sn: 0 of level 1 (frag:[0.000-4.000] > buffer:[0.000-3.925])" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""PARSED->IDLE" (hls.min.js, line 1)
[Info] [info] >"[abr] switch candidate:1->4 adjustedbw(23077376)-bitrate=14884866 ttfb:0.0 avgDuration:4.0 maxFetchDuration:3.9 fetchDuration:1.…" (hls.min.js, line 1)
"[abr] switch candidate:1->4 adjustedbw(23077376)-bitrate=14884866 ttfb:0.0 avgDuration:4.0 maxFetchDuration:3.9 fetchDuration:1.5 firstSelection:false codecSet:avc1,mp4a videoRange:SDR hls.loadLevel:1"
[Log] [log] >"[stream-controller]:""Adapting to level 4 from level 1" (hls.min.js, line 1)
[Log] [log] >"[level-controller]:""Switching to level 4 (1080p SDR avc1,mp4a @8192510) from level 1" (hls.min.js, line 1)
[Log] [log] >"[level-controller]:""Loading level index 4 with https://vz-b1d0f3b4-139.flufflecdn.net/b13f6bba-728f-4fd3-88b4-ad8eb276976b/1080p/video.m3u8" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""IDLE->WAITING_LEVEL" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Level 4 loaded [0,13][part-13--1], cc [0, 0] duration:52.208333" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""WAITING_LEVEL->IDLE" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Loading fragment 1 cc: 0 of [0-13] level: 4, target: 4" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""IDLE->FRAG_LOADING" (hls.min.js, line 1)
[Log] [log] >"[transmuxer-interface, main]: Starting new transmux session for sn: 1 p: -1 level: 4 id: 1↵        discontinuity: false↵      …" (hls.min.js, line 1)
"[transmuxer-interface, main]: Starting new transmux session for sn: 1 p: -1 level: 4 id: 1
        discontinuity: false
        trackSwitch: true
        contiguous: false
        accurateTimeOffset: true
        timeOffset: 4
        initSegmentChange: false"
[Log] [log] >"[stream-controller]:""Loaded fragment 1 of level 4" (hls.min.js, line 1)
[Log] [log] >"[mp4-remuxer]: ISGenerated flag reset" (hls.min.js, line 1)
[Log] [log] >"[mp4-remuxer]: initPTS & initDTS reset" (hls.min.js, line 1)
[Log] [log] >"[mp4-remuxer]: reset next timestamp" (hls.min.js, line 1)
[Log] [log] >"manifest codec:mp4a.40.2, ADTS type:2, samplingIndex:3" (hls.min.js, line 1)
[Log] [log] >"parsed codec:mp4a.40.5, rate:48000, channels:2" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""FRAG_LOADING->PARSING" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Init audio buffer, container:audio/mp4, codecs[selected/level/parsed]=[mp4a.40.2/mp4a.40.2/mp4a.40.5]" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Init video buffer, container:video/mp4, codecs[level/parsed]=[avc1.640028/avc1.640028]" (hls.min.js, line 1)
[Log] [log] >"[buffer-controller]""changing audio sourceBuffer type to audio/mp4;codecs=mp4a.40.5" (hls.min.js, line 1)
[Log] [log] >"[buffer-controller]""switching codec mp4a.40.2 to mp4a.40.5" (hls.min.js, line 1)
[Log] [log] >"[transmuxer.ts]: Flushed fragment 1 of level 4" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""PARSING->PARSED" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Buffered main sn: 1 of level 4 (frag:[3.925-8.000] > buffer:[0.000-7.936])" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""PARSED->IDLE" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Loading fragment 2 cc: 0 of [0-13] level: 4, target: 7.936" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""IDLE->FRAG_LOADING" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Loaded fragment 2 of level 4" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""FRAG_LOADING->PARSING" (hls.min.js, line 1)
[Log] [log] >"[transmuxer.ts]: Flushed fragment 2 of level 4" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""PARSING->PARSED" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Buffered main sn: 2 of level 4 (frag:[7.936-12.000] > buffer:[0.000-11.925])" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""PARSED->IDLE" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Loading fragment 3 cc: 0 of [0-13] level: 4, target: 11.925" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""IDLE->FRAG_LOADING" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Loaded fragment 3 of level 4" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""FRAG_LOADING->PARSING" (hls.min.js, line 1)
[Log] [log] >"[transmuxer.ts]: Flushed fragment 3 of level 4" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""PARSING->PARSED" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Buffered main sn: 3 of level 4 (frag:[11.925-16.000] > buffer:[0.000-15.936])" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""PARSED->IDLE" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Loading fragment 4 cc: 0 of [0-13] level: 4, target: 15.936" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""IDLE->FRAG_LOADING" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Loaded fragment 4 of level 4" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""FRAG_LOADING->PARSING" (hls.min.js, line 1)
[Log] [log] >"[transmuxer.ts]: Flushed fragment 4 of level 4" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""PARSING->PARSED" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Buffered main sn: 4 of level 4 (frag:[15.936-20.000] > buffer:[0.000-19.925])" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""PARSED->IDLE" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Loading fragment 5 cc: 0 of [0-13] level: 4, target: 19.925" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""IDLE->FRAG_LOADING" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Loaded fragment 5 of level 4" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""FRAG_LOADING->PARSING" (hls.min.js, line 1)
[Log] [log] >"[transmuxer.ts]: Flushed fragment 5 of level 4" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""PARSING->PARSED" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Buffered main sn: 5 of level 4 (frag:[19.925-24.000] > buffer:[0.000-23.936])" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""PARSED->IDLE" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Loading fragment 6 cc: 0 of [0-13] level: 4, target: 23.936" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""IDLE->FRAG_LOADING" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Loaded fragment 6 of level 4" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""FRAG_LOADING->PARSING" (hls.min.js, line 1)
[Log] [log] >"[transmuxer.ts]: Flushed fragment 6 of level 4" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""PARSING->PARSED" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Buffered main sn: 6 of level 4 (frag:[23.936-28.000] > buffer:[0.000-27.925])" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""PARSED->IDLE" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Loading fragment 7 cc: 0 of [0-13] level: 4, target: 27.925" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""IDLE->FRAG_LOADING" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Loaded fragment 7 of level 4" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""FRAG_LOADING->PARSING" (hls.min.js, line 1)
[Log] [log] >"[transmuxer.ts]: Flushed fragment 7 of level 4" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""PARSING->PARSED" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Buffered main sn: 7 of level 4 (frag:[27.925-32.000] > buffer:[0.000-31.936])" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""PARSED->IDLE" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Loading fragment 8 cc: 0 of [0-13] level: 4, target: 31.936" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""IDLE->FRAG_LOADING" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Loaded fragment 8 of level 4" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""FRAG_LOADING->PARSING" (hls.min.js, line 1)
[Log] [log] >"[transmuxer.ts]: Flushed fragment 8 of level 4" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""PARSING->PARSED" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Buffered main sn: 8 of level 4 (frag:[31.936-36.000] > buffer:[0.000-35.925])" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""PARSED->IDLE" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Loading fragment 9 cc: 0 of [0-13] level: 4, target: 35.925" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""IDLE->FRAG_LOADING" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Loaded fragment 9 of level 4" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""FRAG_LOADING->PARSING" (hls.min.js, line 1)
[Log] [log] >"[transmuxer.ts]: Flushed fragment 9 of level 4" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""PARSING->PARSED" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Buffered main sn: 9 of level 4 (frag:[35.925-40.000] > buffer:[0.000-39.936])" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""PARSED->IDLE" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Loading fragment 10 cc: 0 of [0-13] level: 4, target: 39.936" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""IDLE->FRAG_LOADING" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Loaded fragment 10 of level 4" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""FRAG_LOADING->PARSING" (hls.min.js, line 1)
[Log] [log] >"[transmuxer.ts]: Flushed fragment 10 of level 4" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""PARSING->PARSED" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Buffered main sn: 10 of level 4 (frag:[39.936-44.000] > buffer:[0.000-43.925])" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""PARSED->IDLE" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Loading fragment 11 cc: 0 of [0-13] level: 4, target: 43.925" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""IDLE->FRAG_LOADING" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Loaded fragment 11 of level 4" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""FRAG_LOADING->PARSING" (hls.min.js, line 1)
[Log] [log] >"[transmuxer.ts]: Flushed fragment 11 of level 4" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""PARSING->PARSED" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Buffered main sn: 11 of level 4 (frag:[43.925-48.000] > buffer:[0.000-47.936])" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""PARSED->IDLE" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Loading fragment 12 cc: 0 of [0-13] level: 4, target: 47.936" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""IDLE->FRAG_LOADING" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Loaded fragment 12 of level 4" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""FRAG_LOADING->PARSING" (hls.min.js, line 1)
[Log] [log] >"[transmuxer.ts]: Flushed fragment 12 of level 4" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""PARSING->PARSED" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Buffered main sn: 12 of level 4 (frag:[47.936-52.000] > buffer:[0.000-51.925])" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""PARSED->IDLE" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Loading fragment 13 cc: 0 of [0-13] level: 4, target: 51.925" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""IDLE->FRAG_LOADING" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Loaded fragment 13 of level 4" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""FRAG_LOADING->PARSING" (hls.min.js, line 1)
[Log] [log] >"[transmuxer.ts]: Flushed fragment 13 of level 4" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""PARSING->PARSED" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""Buffered main sn: 13 of level 4 (frag:[51.925-52.245] > buffer:[0.000-52.208])" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""PARSED->IDLE" (hls.min.js, line 1)
[Log] [log] >"[buffer-controller]""audio sourceBuffer now EOS" (hls.min.js, line 1)
[Log] [log] >"[buffer-controller]""video sourceBuffer now EOS" (hls.min.js, line 1)
[Log] [log] >"[buffer-controller]""Queueing mediaSource.endOfStream()" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""IDLE->ENDED" (hls.min.js, line 1)
[Log] [log] >"[buffer-controller]""Calling mediaSource.endOfStream()" (hls.min.js, line 1)
[Log] [log] >"[buffer-controller]""Media source ended" (hls.min.js, line 1)
[Log] [log] >"[buffer-controller]""Media source closed" (hls.min.js, line 1)
[Log] [log] >"[stream-controller]:""ENDED->STOPPED" (hls.min.js, line 1)
[Log] [log] >"[subtitle-stream-controller]:""IDLE->STOPPED" (hls.min.js, line 1)

Chrome media internals output

No response

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

robwalch commented Jun 6, 2024

Adding preferManagedMediaSource: false, instructs HLS.js to not use ManagedMediaMediaSource, and to assign the media source (blob url) to the src attribute rather than a source child element. HLS.js only appends source children which is required by Safari for AirPlay with MSE sources when ManagedMediaMediaSource is in use.

Removing preferManagedMediaSource: false and adding crossorigin="anonymous" to the media element (depending on the source CORS policy) resolves the issue for me.

If you'd like to use AirPlay with ManagedMediaMediaSource disabled, consider contributing a PR that makes the buffer-controller's appendSource flag configurable.

@robwalch robwalch added Works as expected and removed Bug Needs Triage If there is a suspected stream issue, apply this label to triage if it is something we should fix. labels Jun 6, 2024
@tvinko
Copy link
Author

tvinko commented Jun 6, 2024

hi @robwalch , sorry I made a mistake when I was reporting the issue.
I was testing various options with preferManagedMediaSource and left it disabled when copying the code.
Otherwise I was testing it also without.

However, even with adding crossorigin="anonymous" I cannot make it streamable.

I published two code samples without preferManagedMediaSource and with crossorigin="anonymous"

Using native hls:
https://js-tests.b-cdn.net/native_hls.html

And hls.js:
https://js-tests.b-cdn.net/hls.html

but I still get same results. I cannot stream it with hlsjs and can with native hls.

I'm testing streaming from iPhone to Macbook M1 Pro

I appreciate your fast responses

@robwalch robwalch added Bug Needs Triage If there is a suspected stream issue, apply this label to triage if it is something we should fix. and removed Works as expected labels Jun 7, 2024
@robwalch
Copy link
Collaborator

robwalch commented Jun 7, 2024

I was testing Desktop Safari to LG C2. I'll take another look on iPhone.

@robwalch
Copy link
Collaborator

robwalch commented Jun 10, 2024

This looks like an iOS issue. Please file a bug report with Feedback Assistant.

Make sure to update your page so that you are only setting video.src when not using HLS.js. Otherwise, HLS.js has to remove the attribute and there is some potential for loading and unloading of resources that you do not intend to use:

if (useHls) {
  // source children will be used when ManagedMediaSource is used
  // video.src should not be set prior to this, otherwise it must be unloaded
  // <hls.js setup with fallback source>

  if (video.webkitCurrentPlaybackTargetIsWireless) {
    hls.stopLoad();
  }
  video.addEventListener('webkitcurrentplaybacktargetiswirelesschanged', function (event) {
    if (video.webkitCurrentPlaybackTargetIsWireless) {
      hls.stopLoad();
    } else {
      hls.startLoad();
    }
  });
} else {
  video.src = urlPlaylistUrl;
}

Some other points:

  1. Provide a valid asset URL that the receiver can play. To be sure this issue is not related to your HLS asset, try a sample HLS asset from another host (like https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_adv_example_hevc/master.m3u8).
  2. Use the "webkitcurrentplaybacktargetiswirelesschanged" event and video.webkitCurrentPlaybackTargetIsWireless to call stopLoad() and startLoad() on HLS.js when AirPlay starts and stops (shared example above)
  3. Adding playsinline to the video element allows playback in the page without entering fullscreen on play
  4. Source elements should have a type attribute. airPlaySrc.type = 'application/x-mpegURL'; will let Safari know up front that this is an HLS asset.
  5. Include the type of receiver (smartTV, AppleTV, or Macbook as you mentioned above) in your bug report
  6. Describe in detail how AirPlay failed, including what you saw on each device (sender and receiver).

I also experienced difficulty initiating a successful AirPlay session from iOS when compared to the same attempt from desktop Safari which worked every time. At first the receiver did not play anything, after a couple reconnects (to WebOS, then to AppleTV) it began to show the music last played from my phone, and then (back to WebOS) finally I got audio-only playback for the AV asset. Only after enabling autoplay and initiating the session after seeking or starting playback was I able to get audio and video to play on the receiver, but it was only for that one session. Additional attempts to reconnect used the receiver as a speaker (no video), or launched the session with the song "Now Playing" on the device. The one way I am most successful at starting a session from iOS is to start playback first, and while playback is active, begin the session. I think the sample above that also stops HLS.js loading (and MMS appends) may also be a factor, but it's the reason that sessions start with the active control center content or audio-only.

Share the feedback ID here so that I can help route the bug report appropriately. Thanks for working with me to identify and resolve this issue.

@robwalch robwalch added browser: Safari Browser issue If there is an underlying issue with the browser that hls.js is running on, this tag should be used. and removed Bug Needs Triage If there is a suspected stream issue, apply this label to triage if it is something we should fix. labels Jun 10, 2024
@jyavenard
Copy link

stream provided give a 404 error

Cannot load https://vz-b1d0f3b4-139.flufflecdn.net/b13f6bba-728f-4fd3-88b4-ad8eb276976b/playlist.m3u8HTTP response code:404 

@jyavenard
Copy link

Loading other URL, the

If you want airplay to work, you need an alternative source that is AirPlay compatible.

@tvinko
Copy link
Author

tvinko commented Jun 14, 2024

This looks like an iOS issue. Please file a bug report with Feedback Assistant.

Make sure to update your page so that you are only setting video.src when not using HLS.js. Otherwise, HLS.js has to remove the attribute and there is some potential for loading and unloading of resources that you do not intend to use:

if (useHls) {
  // source children will be used when ManagedMediaSource is used
  // video.src should not be set prior to this, otherwise it must be unloaded
  // <hls.js setup with fallback source>

  if (video.webkitCurrentPlaybackTargetIsWireless) {
    hls.stopLoad();
  }
  video.addEventListener('webkitcurrentplaybacktargetiswirelesschanged', function (event) {
    if (video.webkitCurrentPlaybackTargetIsWireless) {
      hls.stopLoad();
    } else {
      hls.startLoad();
    }
  });
} else {
  video.src = urlPlaylistUrl;
}

Some other points:

  1. Provide a valid asset URL that the receiver can play. To be sure this issue is not related to your HLS asset, try a sample HLS asset from another host (like https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_adv_example_hevc/master.m3u8).
  2. Use the "webkitcurrentplaybacktargetiswirelesschanged" event and video.webkitCurrentPlaybackTargetIsWireless to call stopLoad() and startLoad() on HLS.js when AirPlay starts and stops (shared example above)
  3. Adding playsinline to the video element allows playback in the page without entering fullscreen on play
  4. Source elements should have a type attribute. airPlaySrc.type = 'application/x-mpegURL'; will let Safari know up front that this is an HLS asset.
  5. Include the type of receiver (smartTV, AppleTV, or Macbook as you mentioned above) in your bug report
  6. Describe in detail how AirPlay failed, including what you saw on each device (sender and receiver).

I also experienced difficulty initiating a successful AirPlay session from iOS when compared to the same attempt from desktop Safari which worked every time. At first the receiver did not play anything, after a couple reconnects (to WebOS, then to AppleTV) it began to show the music last played from my phone, and then (back to WebOS) finally I got audio-only playback for the AV asset. Only after enabling autoplay and initiating the session after seeking or starting playback was I able to get audio and video to play on the receiver, but it was only for that one session. Additional attempts to reconnect used the receiver as a speaker (no video), or launched the session with the song "Now Playing" on the device. The one way I am most successful at starting a session from iOS is to start playback first, and while playback is active, begin the session. I think the sample above that also stops HLS.js loading (and MMS appends) may also be a factor, but it's the reason that sessions start with the active control center content or audio-only.

Share the feedback ID here so that I can help route the bug report appropriately. Thanks for working with me to identify and resolve this issue.

Hey @robwalch , I'll report the issue and share the feedback ID here

@tvinko
Copy link
Author

tvinko commented Jun 14, 2024

3. playsinline

This looks like an iOS issue. Please file a bug report with Feedback Assistant.

Make sure to update your page so that you are only setting video.src when not using HLS.js. Otherwise, HLS.js has to remove the attribute and there is some potential for loading and unloading of resources that you do not intend to use:

if (useHls) {
  // source children will be used when ManagedMediaSource is used
  // video.src should not be set prior to this, otherwise it must be unloaded
  // <hls.js setup with fallback source>

  if (video.webkitCurrentPlaybackTargetIsWireless) {
    hls.stopLoad();
  }
  video.addEventListener('webkitcurrentplaybacktargetiswirelesschanged', function (event) {
    if (video.webkitCurrentPlaybackTargetIsWireless) {
      hls.stopLoad();
    } else {
      hls.startLoad();
    }
  });
} else {
  video.src = urlPlaylistUrl;
}

Some other points:

  1. Provide a valid asset URL that the receiver can play. To be sure this issue is not related to your HLS asset, try a sample HLS asset from another host (like https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_adv_example_hevc/master.m3u8).
  2. Use the "webkitcurrentplaybacktargetiswirelesschanged" event and video.webkitCurrentPlaybackTargetIsWireless to call stopLoad() and startLoad() on HLS.js when AirPlay starts and stops (shared example above)
  3. Adding playsinline to the video element allows playback in the page without entering fullscreen on play
  4. Source elements should have a type attribute. airPlaySrc.type = 'application/x-mpegURL'; will let Safari know up front that this is an HLS asset.
  5. Include the type of receiver (smartTV, AppleTV, or Macbook as you mentioned above) in your bug report
  6. Describe in detail how AirPlay failed, including what you saw on each device (sender and receiver).

I also experienced difficulty initiating a successful AirPlay session from iOS when compared to the same attempt from desktop Safari which worked every time. At first the receiver did not play anything, after a couple reconnects (to WebOS, then to AppleTV) it began to show the music last played from my phone, and then (back to WebOS) finally I got audio-only playback for the AV asset. Only after enabling autoplay and initiating the session after seeking or starting playback was I able to get audio and video to play on the receiver, but it was only for that one session. Additional attempts to reconnect used the receiver as a speaker (no video), or launched the session with the song "Now Playing" on the device. The one way I am most successful at starting a session from iOS is to start playback first, and while playback is active, begin the session. I think the sample above that also stops HLS.js loading (and MMS appends) may also be a factor, but it's the reason that sessions start with the active control center content or audio-only.

Share the feedback ID here so that I can help route the bug report appropriately. Thanks for working with me to identify and resolve this issue.

@robwalch can you please confirm if this is proper example of sample code

<!DOCTYPE html>
<html>

<head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/hls.js/1.5.11/hls.min.js"
        integrity="sha512-Z0W3S5swMoBWjkNBP3ACbXA4mh/jdjJOTOOZfF1yIO0OdkIU373s/Tm+eaCbUQq7EEgKl9O1eji1ZgseHCUVgw=="
        crossorigin="anonymous" referrerpolicy="no-referrer"></script>
</head>

<body id="body">
    <video id="video" playsinline crossorigin="anonymous" controls x-webkit-airplay="allow"></video>

    <script>
        var useHls = true;
        var autoplay = false;

        var urlPlaylistUrl =
            "https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_adv_example_hevc/master.m3u8";

        var video = document.getElementById("video");

        video.controls = true;
        video.loop = true;
        video.autoplay = autoplay;

        if (useHls) {
            var hls = new Hls({
                debug: true,
                enableWorker: true,
                lowLatencyMode: true,
                backBufferLength: 90
            });


            hls.loadSource(urlPlaylistUrl);

            hls.attachMedia(video);

            if (video.webkitCurrentPlaybackTargetIsWireless) {
                hls.stopLoad();
            }
            video.addEventListener('webkitcurrentplaybacktargetiswirelesschanged', function (event) {
                if (video.webkitCurrentPlaybackTargetIsWireless) {
                    hls.stopLoad();
                } else {
                    hls.startLoad();
                }
            });

            var airPlaySrc = document.createElement("source");
            airPlaySrc.src = urlPlaylistUrl;
            airPlaySrc.type = 'application/x-mpegURL';
            video.appendChild(airPlaySrc);
            video.disableRemotePlayback = false;

        } else {
            video.src = urlPlaylistUrl;
        }
    </script>
</body>

</html>

@jyavenard
Copy link

  video.addEventListener('webkitcurrentplaybacktargetiswirelesschanged', function (event) {
    if (video.webkitCurrentPlaybackTargetIsWireless) {
      hls.stopLoad();
    } else {
      hls.startLoad();
    }
  });

This seems wrong to me and was needed before there was any support of AirPlay when using MSE prior iOS 17.
If <source> are to be set, the src attribute must be not be set ever.

There is nothing to unload/stop load.
Safari/WebKit will automatically select the AirPlay compatible alternative when the user select an AirPlay target.

You don't want to set the source alternative after the fact once you receive the message.
In particular in recent iOS there won't ever be an AirPlay icon for user to select which would trigger the message. Icon will be displayed if there are multiple sources children.

@robwalch
Copy link
Collaborator

robwalch commented Jun 14, 2024

stopLoad() tells HLS.js to stop loading segments and playlists for the MSE playback asset initialized with loadSource(m3u8). @jyavenard - The start and stop load methods do not relate to or call video.load(), unload(), nor set src. They are similar to the action we take when MMS emits start and stop streaming events, which I did not observe firing when an AP session begins or ends.

We don't want the sender loading files and attempting to append them to a MediaSource while the session is active. It's an optimization missing from prior examples. If it's not required with ManagedMediaSource, then it can be removed.

@tvinko
Copy link
Author

tvinko commented Jun 17, 2024

@robwalch feedback id: FB13939256

@jyavenard
Copy link

I see that you have enableWorker: true, configuration set. Does it still occur if this is set to false?

Thanks

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
Projects
None yet
Development

No branches or pull requests

3 participants