#10578·shaka-player

HLS: getVideoTracks() returns only the active resolution when each variant uses its own AUDIO group (quality menu shows a single quality)

Author: AndekasCreated Sep 11, 2026Updated Sep 11, 2026
Labelscomponent: HLS

FAQ

  • I have read the FAQ and checked for duplicate open issues

If the problem is related to FairPlay, have you read the tutorial?

Not applicable

What version of Shaka Player are you using?

5.2.4 (also reproduced with 5.2.9)

Can you reproduce the issue with our latest release version?

Yes

Can you reproduce the issue with the latest code from main?

Yes

Are you using the demo app or your own custom app?

Shaka Player demo app

What browser and OS are you using?

Chromium 151, Linux (also reproduced headless). Not browser-specific — the filtering happens in Player.getVideoTracks().

For embedded devices (smart TVs, etc.), what model and firmware version are you using?

No response

What are the manifest and license server URIs?

No DRM. Self-contained repro manifest (synthetic, generated with ffmpeg, hosted without geo-blocking):

https://ande.kruvikeeraja.ee/sahtel/TMP/shaka/synth-test/master-pergroup.m3u8

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="g360",LANGUAGE="est",NAME="Estonian",DEFAULT=YES,URI="a64.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="g360",LANGUAGE="rus",NAME="Russian",DEFAULT=NO,URI="a64.m3u8"
#EXT-X-STREAM-INF:BANDWIDTH=400000,RESOLUTION=640x360,AUDIO="g360"
v360.m3u8
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="g720",LANGUAGE="est",NAME="Estonian",DEFAULT=YES,URI="a128.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="g720",LANGUAGE="rus",NAME="Russian",DEFAULT=NO,URI="a128.m3u8"
#EXT-X-STREAM-INF:BANDWIDTH=1200000,RESOLUTION=1280x720,AUDIO="g720"
v720.m3u8

For a control, master-shared.m3u8 is identical except all #EXT-X-STREAM-INF lines reference a single shared audio group — with that manifest the problem disappears.

This manifest shape (a separate audio group per video rendition, with the audio bitrate scaled to the video bitrate) is what Wowza Streaming Engine produces for multi-audio VOD SMILs, and it is valid per the HLS spec; Apple's HLS authoring guidelines also describe providing multiple audio groups at different bitrates. The real production stream this was found on has 4 resolutions x 4 audio languages in 4 audio groups (64/128/192/256 kbps).

What configuration are you using? What is the output of player.getNonDefaultConfiguration()?

Default, happens on demo app also.

What did you do?

  1. Load the manifest above:
javascript
const player = new shaka.Player();
await player.attach(document.querySelector('video'));
await player.load('https://ande.kruvikeeraja.ee/sahtel/TMP/shaka/synth-test/master-pergroup.m3u8');
console.log('variants:', player.getVariantTracks().length);
console.log('video tracks:', player.getVideoTracks());
  1. Compare getVariantTracks() with getVideoTracks().

What did you expect to happen?

getVideoTracks() returns one entry per distinct video rendition that can be paired with the active audio selection (same language/label/channel count), i.e. both 360p and 720p in the repro — matching what getVariantTracks() exposes (all 4 variants: 2 resolutions x 2 languages) and what the UI quality menu showed in 4.x (which built the menu from variant tracks).

What actually happened?

getVariantTracks() correctly returns all 4 variants, but getVideoTracks() returns only one video track — the resolution currently playing. Consequently the built-in UI's quality menu shows a single quality, and after an ABR switch it shows a different single quality.

On the real production stream (4 resolutions x 4 languages): getVariantTracks() = 16 (correct), getAudioTracks() = 4 (correct), getVideoTracks() = 1.

Root cause: in Player.getVideoTracks() (lib/player.js), variants are filtered with

javascript
filteredTracks = variants.filter((t) => {
  ...
  if (!t.videoCodec || t.audioGroupId !== active.audioGroupId ||
      t.originalAudioId !== active.originalAudioId) {
    return false;
  }
  ...

When every rendition references its own AUDIO group, t.audioGroupId !== active.audioGroupId rejects every variant except those of the currently active rendition, so only one video track survives. The language/label/channels fallback below that check is never reached because the group-id check runs first.

The audio streams across the groups represent the same audio selection (same language, label, channel count, codec — only the bitrate differs), so a variant from another group is a perfectly valid switch target; selectVariantTrack() on any of the 16 variants works fine.

Are you planning to send a PR to add it?

No

Source: shaka-project/shaka-player