Stream Video Downloader logo
← Back to Blog

How Multi-Track Audio Works in HLS: EXT-X-MEDIA Groups, GROUP-ID, and Language Selection

July 11, 2026 · 6 min read

As covered in how HLS streaming works, a master playlist can point video and audio at entirely separate files, tied together by an #EXT-X-MEDIA tag. What that overview leaves out is how a player picks the right audio rendition when a stream offers more than one — different languages, stereo versus surround, or a lower-bitrate audio track to pair with a lower-bitrate video variant. That selection runs through two attributes that have to agree with each other, GROUP-ID and AUDIO, and a parser that only reads one side of that handshake can pair a video variant with audio it was never actually meant to use.

Two tags, one handshake

A variant line in the master playlist looks like this:

  • #EXT-X-STREAM-INF:BANDWIDTH=2600000,RESOLUTION=1920x1080,AUDIO="aac-128k"

That AUDIOattribute doesn't point at a URL — it names a group. Somewhere else in the same playlist, one or more #EXT-X-MEDIA lines advertise that group:

  • #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac-128k",NAME="English",LANGUAGE="en",DEFAULT=YES,AUTOSELECT=YES,URI="audio/en.m3u8"
  • #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac-128k",NAME="Spanish",LANGUAGE="es",DEFAULT=NO,AUTOSELECT=YES,URI="audio/es.m3u8"

The variant's AUDIO="aac-128k" is only a valid match against #EXT-X-MEDIA entries whose GROUP-ID is the exact same string. A playlist is free to define a second group — GROUP-ID="aac-64k", say, with its own English and Spanish entries — and point a lower-bitrate video variant at that group instead, so the audio bitrate scales down alongside the video the same way resolution does. Picking the correct audio rendition for a given video variant means reading both sides of that handshake, not just scanning the playlist for any line with TYPE=AUDIO.

DEFAULT and AUTOSELECT aren't the same flag

Within a single group, DEFAULT and AUTOSELECT answer two different questions. DEFAULT=YES marks the rendition a player should choose with no other information to go on — there should be exactly one per group. AUTOSELECT=YES marks a rendition the player maychoose automatically based on the user's own settings, like a system language that matches the track's LANGUAGEattribute, even though it isn't the group's default. The spec requires that anything marked DEFAULT=YES also be AUTOSELECT=YES, but the reverse isn't true — a group can carry several AUTOSELECT=YES language options alongside a single default, and a player that only checks for DEFAULT=YES will never surface the others as anything but a manual pick.

CHANNELS: how a group tells stereo and surround apart

The same GROUP-ID mechanism is also how a playlist offers stereo and multichannel mixes of the same language side by side, using the CHANNELS attribute — a value like CHANNELS="2" for stereo or CHANNELS="6" for 5.1 surround. Two #EXT-X-MEDIA entries can share a GROUP-ID, the same LANGUAGE, and even the same NAME, and differ only in channel count — which is exactly the kind of distinction a player has to preserve rather than collapse into "the first audio track it finds," since picking the wrong one doesn't just change language, it can silently downmix a 5.1 source to stereo or vice versa.

Where this site's parser doesn't check GROUP-ID

parseMaster() in lib/m3u8-parser.ts picks the highest-resolution #EXT-X-STREAM-INF variant, then walks the playlist a second time for any #EXT-X-MEDIA line with TYPE=AUDIO, keeping the first one it sees and replacing it if a later one has DEFAULT=YES. It never reads the winning variant's AUDIOattribute, and it never checks a candidate rendition's GROUP-IDagainst it. On a playlist with a single audio group that's harmless — there's only one group to find. On a playlist that splits audio into multiple groups (per-bitrate audio, or separate stereo/surround groups), it can just as easily land on an #EXT-X-MEDIA entry from a group the chosen video variant never referenced at all, because nothing about the current logic rules that entry out. This is the same category of gap covered in how subtitles work in HLS and HLS byte-range segments — a real playlist feature the parser doesn't follow, not a hypothetical edge case, and it applies equally to the player and the converter, since both call the same parseMaster() function to choose an audio track before any fetching starts.

FAQ

If a stream only has one audio track, does any of this matter? No — with a single #EXT-X-MEDIA:TYPE=AUDIOentry in the whole playlist, there's nothing to mismatch. The GROUP-ID/AUDIO handshake only matters once a playlist defines more than one audio group for a player to choose between.

Is a multi-language audio playlist the same thing as multi-language subtitles? They use the identical #EXT-X-MEDIA mechanism — GROUP-ID, LANGUAGE, DEFAULT, AUTOSELECT — just with TYPE=AUDIO instead of TYPE=SUBTITLES. A stream can offer either, both, or neither independently, and each one is matched to a video variant (or to nothing, for subtitles) the same way.

Does hls.js handle GROUP-ID matching correctly on its own? Yes — hls.js reads a variant's AUDIO attribute, finds the matching #EXT-X-MEDIAgroup, and exposes the renditions in that group as selectable audio tracks, switching playlists when the user picks one. The gap described above is specific to this site's own lightweight parseMaster(), which exists to pick sensible defaults quickly rather than reimplement a full HLS client.