Summary
HlsOutputFormat can generate a master playlist with BANDWIDTH=0 and a plain opus codec string in CODECS.
This appears to cause Safari/iOS to reject the master playlist before requesting the child media playlist.
Example output
Generated master.m3u8:
#EXTM3U
#EXT-X-STREAM-INF:BANDWIDTH=0,CODECS="avc1.640015,opus",RESOLUTION=480x270
playlist-1.m3u8
Problems
There seem to be two compatibility issues here:
-
BANDWIDTH=0
HLS clients expect BANDWIDTH to be a positive integer. Safari/iOS appears to reject this master playlist and does not proceed to request playlist-1.m3u8.
-
CODECS="...,opus"
For Opus in MP4/CMAF/fMP4 HLS, the codec string should be RFC 6381-compatible. I believe plain opus is not accepted by Safari's HLS parser here, and the expected string is likely mp4a.ad.
Expected behavior
The generated master playlist should use Safari/iOS-compatible attributes, for example:
#EXT-X-STREAM-INF:BANDWIDTH=396000,CODECS="avc1.640015,mp4a.ad",RESOLUTION=480x270
playlist-1.m3u8
More generally:
BANDWIDTH should never be 0; it should be a positive estimated peak bitrate.
CODECS should contain RFC 6381-compatible codec strings.
- AVC should remain in full form, such as
avc1.640015.
- Opus in MP4/CMAF HLS should not be emitted as plain
opus; it should likely be mp4a.ad.
Environment
- Mediabunny version:
1.46.0
- Output format:
HlsOutputFormat
- Segment format: CMAF/fMP4
- Playback issue observed in Safari/iOS native HLS playback
Additional context
In the consuming app, macOS Safari can play some outputs, but iPhone Safari reports native media failure:
MediaError code 4 / MEDIA_ERR_SRC_NOT_SUPPORTED
The iPhone/Safari player does not appear to request the child media playlist, which suggests the master playlist itself is being rejected.
I worked around this downstream by patching the generated master playlist to:
- replace
BANDWIDTH=0 with a positive estimated aggregate bitrate
- replace plain
opus in CODECS with mp4a.ad
After that patch, the generated master playlist looks like:
#EXT-X-STREAM-INF:BANDWIDTH=473600,CODECS="avc1.64000c,mp4a.ad",RESOLUTION=320x180,AUDIO="audio-3"
playlist-2.m3u8
Possible source locations
From the distributed package, the master playlist writer appears to generate these values around:
dist/modules/src/hls/hls-muxer.js
- writes
BANDWIDTH=${Math.ceil(totalPeakBitrate)}
- writes
CODECS="${codecs.join(',')}"
Also, buildAudioCodecString appears to return plain "opus" for Opus, which may be correct in some contexts but seems incompatible with HLS master playlist CODECS for fMP4/CMAF playback in Safari.
Summary
HlsOutputFormatcan generate a master playlist withBANDWIDTH=0and a plainopuscodec string inCODECS.This appears to cause Safari/iOS to reject the master playlist before requesting the child media playlist.
Example output
Generated
master.m3u8:Problems
There seem to be two compatibility issues here:
BANDWIDTH=0HLS clients expect
BANDWIDTHto be a positive integer. Safari/iOS appears to reject this master playlist and does not proceed to requestplaylist-1.m3u8.CODECS="...,opus"For Opus in MP4/CMAF/fMP4 HLS, the codec string should be RFC 6381-compatible. I believe plain
opusis not accepted by Safari's HLS parser here, and the expected string is likelymp4a.ad.Expected behavior
The generated master playlist should use Safari/iOS-compatible attributes, for example:
More generally:
BANDWIDTHshould never be0; it should be a positive estimated peak bitrate.CODECSshould contain RFC 6381-compatible codec strings.avc1.640015.opus; it should likely bemp4a.ad.Environment
1.46.0HlsOutputFormatAdditional context
In the consuming app, macOS Safari can play some outputs, but iPhone Safari reports native media failure:
The iPhone/Safari player does not appear to request the child media playlist, which suggests the master playlist itself is being rejected.
I worked around this downstream by patching the generated master playlist to:
BANDWIDTH=0with a positive estimated aggregate bitrateopusinCODECSwithmp4a.adAfter that patch, the generated master playlist looks like:
Possible source locations
From the distributed package, the master playlist writer appears to generate these values around:
dist/modules/src/hls/hls-muxer.jsBANDWIDTH=${Math.ceil(totalPeakBitrate)}CODECS="${codecs.join(',')}"Also,
buildAudioCodecStringappears to return plain"opus"for Opus, which may be correct in some contexts but seems incompatible with HLS master playlistCODECSfor fMP4/CMAF playback in Safari.