video-dev / hls.js

HLS.js is a JavaScript library that plays HLS in browsers with support for MSE.
https://hlsjs.video-dev.org/demo
Other
14.69k stars 2.56k forks source link

Multiple audio tracks and track selection #3996

Closed radiantmediaplayer closed 3 years ago

radiantmediaplayer commented 3 years ago

What do you want to do with Hls.js? I am trying to properly implement a quality selection UI for hls.js but I am running into an atypical HLS stream: https://visionplus-stream.visionplus.id/live/eds/JTV/sa_hls/JTV.m3u8. I am using hls.js 1.0.5 and testing in latest Chrome for Windows 10.

What have you tried so far? I read hls.audioTracks, I got 1 track:

attrs: AttrList {TYPE: "AUDIO", URI: "JTV-mp4a_66000_eng=2.m3u8", GROUP-ID: "audio-AACL-66", LANGUAGE: "en", NAME: "English", …}
audioCodec: "mp4a.40.2"
autoselect: true
bitrate: 0
default: true
details: LevelDetails {PTSKnown: false, alignedSliding: false, averagetargetduration: 9.998860769230768, endCC: 0, endSN: 20264926, …}
forced: false
groupId: "audio-AACL-66"
id: 0
instreamId: undefined
lang: "en"
name: "English"
type: "AUDIO"
url: "https://visionplus-stream.visionplus.id/live/eds/JTV/sa_hls/JTV-mp4a_66000_eng=2.m3u8"
__proto__: Object
length: 1

I read hls.levels, I have 8 tracks

0: Level {attrs: AttrList, audioCodec: "mp4a.40.2", bitrate: 225609, codecSet: "avc1,mp4a", height: 144, …}
1: Level {attrs: AttrList, audioCodec: "mp4a.40.2", bitrate: 258737, codecSet: "avc1,mp4a", height: 144, …}
2: Level {attrs: AttrList, audioCodec: "mp4a.40.2", bitrate: 384626, codecSet: "avc1,mp4a", height: 240, …}
3: Level {attrs: AttrList, audioCodec: "mp4a.40.2", bitrate: 417754, codecSet: "avc1,mp4a", height: 240, …}
4: Level {attrs: AttrList, audioCodec: "mp4a.40.2", bitrate: 596626, codecSet: "avc1,mp4a", height: 360, …}
5: Level {attrs: AttrList, audioCodec: "mp4a.40.2", bitrate: 629754, codecSet: "avc1,mp4a", height: 360, …}
6: Level {attrs: AttrList, audioCodec: "mp4a.40.2", bitrate: 1126660, codecSet: "avc1,mp4a", height: 480, …}
7: Level {attrs: AttrList, audioCodec: "mp4a.40.2", bitrate: 1159788, codecSet: "avc1,mp4a", height: 480, …}
length: 8
__proto__: Array(0)

To make it more confusing when I read data.audioTracks from Hls.Events.MANIFEST_PARSED I have 2 audio tracks:

0: {attrs: AttrList, bitrate: 0, id: 0, groupId: "audio-AACL-66", instreamId: undefined, …}
1: {attrs: AttrList, bitrate: 0, id: 0, groupId: "audio-AACL-99", instreamId: undefined, …}

There seems to be a discrepancy in audio tracks being reported in that case. I am actually expecting to have 2 audio tracks and only 4 levels. My question is how to deal with this kind of streams when building a track selection UI? I understand I could create a table to properly match audioGroupIds and make a reference to each track but I was under the impression that hls.js should do this for me, especially since v1 release, and report this assembly of tracks "correctly". I am also afraid that doing so could break redundancy support or multi-language audio tracks when they appear. So question is how to properly handle that stream?

radiantmediaplayer commented 3 years ago

Sorry I misposted the stream to test - the correct stream to test is https://visionplus-stream.visionplus.id/live/eds/JTV/sa_hls/JTV.m3u8. I have corrected this above already.

robwalch commented 3 years ago

Use the audio tracks updated event. The audio tracks listed are the one in the current level's audio group ID. When the level changes to one with a different group ID, audio tracks are updated to reflect the tracks in that group.

radiantmediaplayer commented 3 years ago

@robwalch thanks for answering. I however believe I wrongly phrased my question. My question is not about how to read the data from the manifest (reading data from AUDIO_TRACKS_UPDATED gives me 1 audio track), it is about how to select the correct track without having duplicates in my UI: 1 (see screenshot - this is the same at https://hls-js.netlify.app/demo/?src=https%3A%2F%2Fvisionplus-stream.visionplus.id%2Flive%2Feds%2FJTV%2Fsa_hls%2FJTV.m3u8&demoConfig=eyJlbmFibGVTdHJlYW1pbmciOnRydWUsImF1dG9SZWNvdmVyRXJyb3IiOnRydWUsInN0b3BPblN0YWxsIjpmYWxzZSwiZHVtcGZNUDQiOmZhbHNlLCJsZXZlbENhcHBpbmciOi0xLCJsaW1pdE1ldHJpY3MiOi0xfQ==). hls.js reports 8 levels (hls.levels) and that this not what I expect. I expect either 1 audio track and 4 levels or 2 audio tracks and 4 levels. But I do not expect 8 levels otherwise I have to remove or filter some levels and keep a map of what is what in each audio group ID - which is complicated and is normally handle by hls.js with alternate language audio track like in that example https://5b44cf20b0388.streamlock.net:8443/vod/smil:hls-maudios-prod.smil/playlist.m3u8. I actually am starting to think this could be a bug in hls.js.

robwalch commented 3 years ago

hls.js reports a level for each unique variant. You have 8 unique variants. Audio groups do not group variants into fewer levels.

Only redundant variants are reduced to fewer levels. For the levels to be redundant, they have the share the same BANDWIDTH, RESOLUTION and CODECS attribute values.

radiantmediaplayer commented 3 years ago

For the levels to be redundant, they have the share the same BANDWIDTH, RESOLUTION and CODECS attribute values.

That answers my question. Thanks.

robwalch commented 3 years ago

Redundant levels are not there for providing two different audio qualities. They are supposed to be for when you have each level hosted on two different origins or CDNs so that if one fails, the client switches over to the backup.

If you want to separate resolution selection from audio quality selection using this stream as-is, then you need to split the levels into two arrays, and present that list in your UI based on the active audio group. There is no way however to have ABR run while sticking to an audio group. ABR will select one of the 8 levels based on bitrate and audio group switching will just happen automatically.

If what you want is 4 levels and 2 tracks then you need to change your stream to only have one audio group containing both audio tracks and assign that group to the 4 variants. BANDWIDTH will just have to be set to the higher of the two combinations (variant + AACL-99 track bitrate).