Multiple Alternative Audio Tracks
General
m3u8 manifests with multiple audio streams will have those streams added to video.js in an AudioTrackList. The AudioTrackList can be accessed using player.audioTracks() or tech.audioTracks().
Mapping m3u8 metadata to AudioTracks
The mapping between AudioTrack and the parsed m3u8 file is fairly straight forward. The table below shows the mapping
| m3u8 | AudioTrack |
|---|---|
| label | label |
| lang | language |
| default | enabled |
| ??? | kind |
| ??? | id |
As you can see m3u8's do not have a property for AudioTrack.id, which means that we let video.js randomly generate the id for AudioTracks. This will have no real impact on any part of the system as we do not use the id anywhere.
The other property that does not have a mapping in the m3u8 is AudioTrack.kind. It was decided that we would set the kind to main when default is set to true and in other cases we set it to alternative unless the track has characteristics which include public.accessibility.describes-video, in which case we set it to main-desc (note that this kind indicates that the track is a mix of the main track and description, so it can be played instead of the main track; a track with kind description only has the description, not the main track).
Below is a basic example of a mapping m3u8 layout
{
'media-group-1': [{
'audio-track-1': {
default: true,
lang: 'eng'
},
'audio-track-2': {
default: false,
lang: 'fr'
},
'audio-track-3': {
default: false,
lang: 'eng',
characteristics: 'public.accessibility.describes-video'
}
}]
}
Corresponding AudioTrackList when media-group-1 is used (before any tracks have been changed)
[{
label: 'audio-tracks-1',
enabled: true,
language: 'eng',
kind: 'main',
id: 'random'
}, {
label: 'audio-tracks-2',
enabled: false,
language: 'fr',
kind: 'alternative',
id: 'random'
}, {
label: 'audio-tracks-3',
enabled: false,
language: 'eng',
kind: 'main-desc',
id: 'random'
}]
Startup (how tracks are added and used)
AudioTrack & AudioTrackList live in video.js
-
HLScreates aMasterPlaylistControllerand watches for theloadedmetadataevent -
HLSparses the m3u8 using theMasterPlaylistController -
MasterPlaylistControllercreates aPlaylistLoaderfor the master m3u8 -
MasterPlaylistControllercreatesPlaylistLoaders for every audio playlist -
MasterPlaylistControllercreates aSegmentLoaderfor the main m3u8 -
MasterPlaylistControllercreates aSegmentLoaderfor a potential audio playlist -
HLSsees theloadedmetadataand finds the currently selected MediaGroup and all the metadata -
HLSremoves allAudioTracks from theAudioTrackList -
HLScreatedAudioTracks for the MediaGroup and adds them to theAudioTrackList -
HLScallsMasterPlaylistControllersuseAudiowith no arguments (causes it to use the currently enabled audio) -
MasterPlaylistControllerturns off the current audioPlaylistLoaderif it is on -
MasterPlaylistControllermaps thelabelto thePlaylistLoadercontaining the audio -
MasterPlaylistControllerturns on thatPlaylistLoaderand the CorrespondingSegmentLoader(master or audio only) -
MediaSource/mux.jsdetermine how to mux
How tracks are switched
AudioTrack & AudioTrackList live in video.js
-
HLSis setup to watch for thechangedevent on theAudioTrackList - User selects a new
AudioTrackfrom a menu (where only one track can be enabled) -
AudioTrackListenables the newAudiotrackand disables all others -
AudioTrackListtriggers achangedevent -
HLSsees thechangedevent and finds the newly enabledAudioTrack -
HLSsends thelabelfor the newAudioTracktoMasterPlaylistControllersuseAudiofunction -
MasterPlaylistControllerturns off the current audioPlaylistLoaderif it is on -
MasterPlaylistControllermaps thelabelto thePlaylistLoadercontaining the audio -
MasterPlaylistControllermaps thelabelto thePlaylistLoadercontaining the audio -
MasterPlaylistControllerturns on thatPlaylistLoaderand the CorrespondingSegmentLoader(master or audio only) -
MediaSource/mux.jsdetermine how to mux