# LG Webos - wrong audio track

**URL:** https://forums.plex.tv/t/lg-webos-wrong-audio-track/939218
**Category:** Plex Players
**Tags:** lg-webos
**Created:** [May 28, 2026, 6:51am UTC](https://forums.plex.tv/t/lg-webos-wrong-audio-track/939218 "2026-05-28T06:51:57Z")
**Posts on this page:** 1
**Showing post:** 18

<div class="post-metadata">

### Author: ![0xBEB](https://avatars.discourse-cdn.com/v4/letter/0/b38774/32.png) [@0xBEB](https://forums.plex.tv/u/0xBEB)
#### Post date: [June 26, 2026, 3:48pm UTC](https://forums.plex.tv/t/lg-webos-wrong-audio-track/939218/18 "2026-06-26T15:48:28Z")

</div>

# Follow-up: a _second_, distinct webOS audio-selection bug — merged multi-version items

This is a **different bug** with a **different trigger** that lives in the _same_ function area (`HTMLPlayer._selectAudioTrack`). I instrumented it end-to-end the same way — Chrome DevTools on the live `app.plex.tv/tv-v5-webos` build plus the Plex DB — and traced it to the exact call. The prior bug was about _language tags_; this one is about _merged Versions_, and it can short-circuit the language logic entirely.

**Setup:** LG 49SM9000PLA, webOS 4.10.0; PMS 1.43.2.10687; LG Plex app cdp-30 5.2.1. Repro content: _Spider-Noir_ S01 as a **merged multi-version** item — each episode has two release files combined into one entry: a **FLUX** version (1 audio track, English) and a **B&W** version (2 audio tracks, Italian + English).

## In plain English (for anyone hitting this)

If you have **two copies of the same movie or episode** in Plex and Plex has merged them into a single entry with multiple “Versions,” the audio picker can stop working on one of those copies. You open the audio menu, choose Italian, the menu _shows_ Italian selected — but the sound stays English. It never actually changes.

Why it happens: when you play a merged item, the app needs a list of “which audio tracks this file has.” Because of a bug, it reads that list from the **wrong copy** — the first/default Version — instead of the copy you’re actually watching. The two copies have a different number of audio tracks (here 1 vs 2), the lists don’t line up, and the app gives up and just plays the default (English) track no matter what you pick.

It’s not your TV’s fault, and it’s not a sound-file problem. Single-copy items switch audio fine in both directions. It only happens on merged items.

## Workaround

1. **Remove the extra version** from the library so the item has only one Version.
2. **Disable “Allow Direct Play”** (or lower max quality) so the server transcodes to a single audio track — the app can’t pick the wrong index. Same universal workaround as before.

> **For Plex devs — full technical detail**
>
> **Trigger:** a **merged multi-version** `metadata_item` whose _played_ version has a different audio-stream count than version index 0. Test item: FLUX = 1 audio (`en/eac3`); B&W = 2 audio (`it`+`en`, native element order `[en, it]`).
> 
> **Symptom:** Direct-Playing the B&W (2-track) version, the picker is ignored — audio stays pinned to English:
> 
> ```auto
> Unexpected number of audio tracks available on media element. Found: 2, expected: 1
> 
> ```
> 
> **Proof the native API is fine:** in DevTools, `audioTracks[1].enabled = true` on the `<video>` element switched the decoder to Italian instantly — no reload, no transcode. The native list `[en, it]` is correct; only the index the app computes is wrong.
> 
> **Root cause.** `_selectAudioTrack` (`HTMLPlayer.tsx`, module **29074** ) builds its server-stream list from the default version, not the playing one:
> 
> ```js
> _selectAudioTrack() {
> const tracks = this.mediaElement?.audioTracks; // native AudioTrackList — correct: [en, it]
> const playable = this._playable;
> if (!tracks?.length || !playable?.isDirectPlay
> || playable.playableType !== PlayableType.Video) return;
> 
> // BUG: no media-version index passed → reads version 0's streams (the FLUX copy)
> const serverStreams = getStreamsOfType(playable.metadataItem, StreamType.Audio); // = (0,f.bp)(...)
> if (!serverStreams.length) return;
> 
> const elementTracks = [...tracks];
> if (elementTracks.length === 1) { elementTracks[0].enabled = true; return; }
> 
> const idx = this._getSelectedAudioStreamIndex
> ? this._getSelectedAudioStreamIndex(serverStreams, elementTracks)
> : serverStreams.findIndex(s => s.selected);
> elementTracks.forEach((t, i) => { t.enabled = (i === idx); });
> }
> 
> ```
> 
> > grep: `var i=(0,f.bp)(n.metadataItem,m.jx.Audio);`
> 
> `f.bp` (`f = n(90606)`) is the shared helper `D`:
> 
> ```js
> // f.bp — "get streams of a type from an item"
> function getStreamsOfType(item, streamType, mediaIndex = 0) { // ← 3rd arg, defaults to 0
> if (!item.mediaItems) return [];
> const version = item.mediaItems[mediaIndex]; // version 0 unless told otherwise
> if (!version?.parts) return [];
> return (version.parts[0].streams || []).filter(s => s.streamType === streamType);
> }
> 
> ```
> 
> > verbatim: `function D(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0;if(!e.mediaItems)return[];var i=e.mediaItems[n];return null!=i&&i.parts?(i.parts[0].streams||[]).filter(function(e){return e.streamType===t}):[]}`
> 
> With no index it returns `mediaItems[0]` = FLUX (1 audio) while the element plays `mediaItems[1]` = B&W (2 audio) — hence `expected: 1` against a 2-track file. (`metadataItem` is the full multi-version array, the same one `appInitializer` indexes via `mediaItems[t.mediaIndex]`.)
> 
> **Downstream (stock code).** Lengths differ → `getSelectedAudioStreamIndex` (`getAppConfig.ts`, the #939218 function) short-circuits:
> 
> ```js
> function getSelectedAudioStreamIndex(serverStreams, elementTracks) {
> const r = serverStreams.findIndex(s => s.selected);
> 
> if (serverStreams.length !== elementTracks.length) {
> log.warn(`Unexpected number of audio tracks... Found: ${elementTracks.length}, expected: ${serverStreams.length}`);
> return r; // ← BUG PATH (1 !== 2): skips the language match + mirror below
> }
> 
> const aligned = serverStreams.every((s, i) => { // normal path — only when lists line up
> const elemLang = elementTracks[i].language;
> if (!(s.languageCode || (elemLang && elemLang !== "und"))) return true;
> return s.languageCode === elemLang
> || (!!s.languageCode && (s.languageTag || isoMap[s.languageCode]) === elemLang);
> });
> return aligned ? r : elementTracks.length - r - 1; // ← the #939218 mirror lives here
> }
> 
> ```
> 
> So `audioTracks[r].enabled` → ~track 0 = English, regardless of the pick. The language/mirror code never runs — the defect is the **wrong input** handed upstream.
> 
> **Proposed fix — source from the _playing_ version** (`playable.decision.choice.{mediaIndex,part}`, already read in `PlaybackSessionController`/`appInitializer`):
> 
> ```js
> const part = playable.decision?.choice?.part;
> const serverStreams = part?.streams
> ? part.streams.filter(s => s.id != null && s.streamType === StreamType.Audio) // same predicate as PSC._getStreamsOfType
> : getStreamsOfType(playable.metadataItem, StreamType.Audio); // fallback
> 
> ```
> 
> Minified drop-in:
> 
> ```js
> var p=n.decision&&n.decision.choice&&n.decision.choice.part;
> var i=p&&p.streams?p.streams.filter(function(e){return null!=e.id&&e.streamType===m.jx.Audio}):(0,f.bp)(n.metadataItem,m.jx.Audio);
> 
> ```
> 
> (Or minimal — pass the index: `(0,f.bp)(n.metadataItem,m.jx.Audio,(n.decision&&n.decision.choice?n.decision.choice.mediaIndex:0)||0)`.) After it, lists match and the existing language path runs — also re-enabling the `en-US`/#939218 handling the mismatch was short-circuiting.
> 
> **TL;DR:** `_selectAudioTrack` reads the audio list from version 0 instead of the playing version; source it from `playable.decision.choice.part.streams`.

---

_[View the full topic](https://forums.plex.tv/t/lg-webos-wrong-audio-track/939218)._
