Skip to content

DTS: PMS's dca spelling direct-plays; Force Direct Play offers DTS only with a DTS table row - #899

Merged
GLinnik21 merged 12 commits into
mainfrom
lane/dts-dca-spelling
Oct 22, 2026
Merged

GLinnik21 merged 12 commits into
mainfrom
lane/dts-dca-spelling

Conversation

@GLinnik21

@GLinnik21 GLinnik21 commented Oct 21, 2026 •

Copy link
Copy Markdown
Owner

PMS names DTS dca (every DTS entry in the profiles shipped with PMS, the PMS API spec, the #584 server log). Our route check and the Load payload only knew dts, so a DTS track from a real server never direct-played, in Auto or in Force Direct Play — even on a set whose own codec table lists DTS. That is the Force Direct Play refusal reported in discussion #695. Nobody saw it because the synthetic fixture declares dts and tests/mock_pms.py echoed it back.

Stacked on #898; this diff is against that branch.

Change

  • One canonicaliser, devcaps::audio_codec_id (lowercase, dca→dts, ec-3→eac3), used wherever codec names are compared: device-table membership and channel bounds (Caps::audio_has/audio_supports), the Load payload (engine::audio_payload_codec), and FFmpeg's stream matcher (ff.rs audio_name_matches, so a multi-track file can't pick TrueHD while the Load says DTS). Inbound data stays raw: track memory compares raw codec strings.
  • The profile we send PMS spells DTS dca everywhere PMS reads a codec name (direct-play list, transcode target, add-limitation scopeName) through one profile_codec_name.
  • Force Direct Play DTS rule (Caps::forced_admits_dts): DTS is offered only when the TV's table has a DTS row with a channel count — the same evidence Auto uses — but without the channel ceiling. Planner and forced profile use the same predicate. Before this, Forced offered DTS to every set; with the spelling fixed, that would send DTS to sets with no DTS decoder (dts_restore_plus measured a C5 whose table lists DTS without one). Consequence: a set patched with base dts_restore (which never edits the table) still gets a refusal in Forced — now one that names DTS (Force Direct Play: the audio refusal names the codec #898).
  • DTS-HD MA 7.1: Auto still refuses it against a 6-channel ceiling (today's documented rule). We feed only the DTS core.
  • The mock server speaks PMS's dca; tests/run.py maps the Load name back for its comparison.
  • Test seam: devcaps::caps_on_this_thread_for_test (thread-local, test-support only, same pattern as i18n::language_on_this_thread_for_test).
  • Docs: agent-reference, playback-settings, pms-api updated.

Verification

  • Red first, then green: devcaps dca membership/channel bounds and the Forced row rule (compile-red); engine audio_payload_codec("dca") (left: None, right: Some(("DTS", 4))); auto_and_forced_agree_on_the_dca_spelling; ff.rs the_payload_codec_matches_ffmpegs_name_across_spellings; end-to-end a_dca_track_direct_plays_on_a_set_with_a_dts_row (Auto, DTS-row table, MDE directplay → /library/parts/ URL and a /decision request carrying dca, red with the dca arm disabled); transcoder profile tests red with profile_codec_name made the identity.
  • Never seen red: forced_direct_play_refuses_dca_without_a_dts_row (Forced refused dca before too; guards the no-Load rule) and a_selected_dca_track_is_picked_when_the_table_has_a_dts_row (written after the fix).
  • On the committed merged tree: make check ok (plx_media 1699 passed; 0 failed; 64 ignored), make test-hostsim C=plx_media 1853 passed; 0 failed; 64 ignored, make check-nodef clean. Firmware-compat review: no FFI, link or DT_NEEDED change (source-level; ARM build left to CI).

TV check (dev set, webOS 4.5, debug build of this branch, guest on tests/mock_pms.py, panel off, muted)

The mock served the synthetic H.264 + DTS 5.1 file with codec="dca" (as PMS does). The event log:

  • devcaps: … audio=aac,ac3,eac3,dts and pms: server 0 version=…-synthetic
  • decision: part=directplay video=copy general=Some(1000) mde=Some(1000) -> DIRECT PLAY
  • load: v=H264 a="DTS" …, pipeline str=audio/x-dts
  • clock advancing at 1x through pos=20s (play≈1000pm, timeline playing t=18s/60s), no playing error.

Not verified:

🤖 Generated with Claude Code

GLinnik21 and others added 9 commits October 21, 2026 16:30
ForcedFailure::Audio and AudioNeedsConversion carry the refused track's codec
(friendly_codec, name only), the read-out says "DTS audio can't play without
conversion" instead of "this audio format", and the event log line
playback_policy names the raw codec. Empty codec keeps the generic sentence.
New keys widgets.verdict.forced_audio_codec and forced_audio_conversion_codec
in all 8 locales.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ow gate, profile and mock speak dca

PMS names DTS dca; the route, the payload and the profile only knew dts, so a DTS track
never direct-played in Auto or Force Direct Play. devcaps::audio_codec_id (dca->dts,
ec-3->eac3, lowercase) is applied at membership (Caps::audio_has/audio_supports, the Forced
arm via Caps::forced_feeds_audio) and at the Load payload (audio_payload_codec). Inbound data
stays raw. Force admits DTS only with a table DTS row (channels>0) and skips the ceiling
(Caps::forced_admits_dts); the forced profile offers DTS under the same predicate. The profile
names DTS dca in the direct-play list, the transcode target and add-limitation scopeName
(transcoder.rs::profile_codec_name). tests/mock_pms.py maps dts->dca.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…orced gate

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…dly name

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…canonicaliser

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… on a set with a DTS row

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Base automatically changed from lane/forced-audio-codec to main October 22, 2026 00:44
@GLinnik21
GLinnik21 merged commit d156a85 into main Oct 22, 2026
19 checks passed
@GLinnik21
GLinnik21 deleted the lane/dts-dca-spelling branch October 22, 2026 00:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant