perf(android): low-latency decode overhaul — vendor keys, async loop, system tuning

Close the latency gap on the Android client with per-SoC decoder tuning, an
event-driven decode loop, and full system integration.

- Decoder selection: rank MediaCodecList decoders in Kotlin (hardware/vendor
  preferred, software avoided, FEATURE_LowLatency probed) and create the chosen
  one by name. Per-SoC low-latency keys gated on the codec-name prefix: Qualcomm
  picture-order + low-latency, Exynos (also Google Tensor), Amlogic, HiSilicon;
  MediaTek vdec-lowlatency set unconditionally. operating-rate = MAX (Qualcomm)
  vs priority = 0 (else) are mutually exclusive. NVIDIA/Rockchip/Realtek have no
  vendor key — covered by ranking + the standard low-latency key.

- Async decode loop: AMediaCodec async-notify replaces the poll loop, presenting a
  decoded frame the instant it is ready instead of waiting out a poll interval.
  Behind USE_ASYNC_DECODE with the synchronous loop kept for A/B during bring-up.

- System integration: Wi-Fi FULL_LOW_LATENCY lock and HDMI ALLM
  (setPreferMinimalPostProcessing) for the stream's lifetime; game_mode_config.xml
  opting out of OEM downscaling / FPS overrides.

- Pipeline: boost the data-plane pump + audio thread priorities, AAudio usage=Game,
  DSCP marking on by default on Android, ADPF setPreferPowerEfficiency(false),
  and setFrameRateWithChangeStrategy(ALWAYS) to force the HDMI mode switch on TV.

- lowLatencyMode master toggle (default on) as the escape hatch; the stats HUD now
  shows the resolved decoder name.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-06 07:21:57 +02:00
parent 76791e53e9
commit 5dc24a069f
14 changed files with 1098 additions and 58 deletions
@@ -43,6 +43,14 @@
android:supportsRtl="true"
android:theme="@style/Theme.PunktfunkAndroid">
<!-- Game Mode config (Android 13+): declare we support Performance mode and opt OUT of the
OEM interventions that would fight the negotiated stream — resolution downscaling and
FPS overrides. A game-streaming client renders exactly the host's mode; a platform
downscale/FPS-cap corrupts that. Ignored below API 33. -->
<meta-data
android:name="android.game_mode_config"
android:resource="@xml/game_mode_config" />
<activity
android:name=".MainActivity"
android:exported="true"