diff --git a/clients/android/app/src/main/kotlin/io/unom/punktfunk/GamepadSettingsScreen.kt b/clients/android/app/src/main/kotlin/io/unom/punktfunk/GamepadSettingsScreen.kt index 85a548fa..755a7992 100644 --- a/clients/android/app/src/main/kotlin/io/unom/punktfunk/GamepadSettingsScreen.kt +++ b/clients/android/app/src/main/kotlin/io/unom/punktfunk/GamepadSettingsScreen.kt @@ -327,7 +327,7 @@ private fun buildSettingsRows(s: Settings, update: (Settings) -> Unit): List Unit, context: an ) { c -> update(s.copy(compositor = c)) } ToggleRow( - title = "Low-latency mode (experimental)", - subtitle = "Aggressive decoder and system tuning (per-device decoder selection, async " + - "decode, HDMI game mode). Can lower latency, but may stutter or glitch on " + - "some devices — turn off if the stream misbehaves.", + title = "Low-latency mode", + subtitle = "The fast pipeline (async decode, per-device decoder selection, HDMI game " + + "mode). On by default — turn off to fall back to the plain decode path if the stream " + + "stutters or glitches on this device.", checked = s.lowLatencyMode, onCheckedChange = { on -> update(s.copy(lowLatencyMode = on)) }, ) diff --git a/clients/android/app/src/main/kotlin/io/unom/punktfunk/StreamScreen.kt b/clients/android/app/src/main/kotlin/io/unom/punktfunk/StreamScreen.kt index fd91c1c8..381f9700 100644 --- a/clients/android/app/src/main/kotlin/io/unom/punktfunk/StreamScreen.kt +++ b/clients/android/app/src/main/kotlin/io/unom/punktfunk/StreamScreen.kt @@ -65,10 +65,10 @@ fun StreamScreen(handle: Long, micEnabled: Boolean, onDisconnect: () -> Unit) { var showStats by remember { mutableStateOf(initialSettings.statsHudEnabled) } // Touch model is fixed per session (re-keys the gesture handler below if it ever changes). val touchMode = initialSettings.touchMode - // "Low-latency mode (experimental)" master toggle, resolved once for the session. Off (the - // default) runs the original decode pipeline; on enables the aggressive stack — decoder - // ranking + vendor keys + async loop (native side), HDMI ALLM below, game-tagged audio, and - // DSCP marking (applied earlier, at connect). + // "Low-latency mode" master toggle, resolved once for the session. On (the default) enables the + // fast pipeline — decoder ranking + vendor keys + async loop (native side), HDMI ALLM below, + // game-tagged audio, and DSCP marking (applied earlier, at connect); off falls back to the + // original synchronous decode pipeline as a per-device escape hatch. val lowLatencyMode = initialSettings.lowLatencyMode // TV form factor (leanback): the decoder actively switches the HDMI output mode to the stream // refresh; a phone/tablet gets the softer seamless frame-rate hint instead. diff --git a/clients/android/native/src/decode.rs b/clients/android/native/src/decode.rs index fa053b85..2dbf3c24 100644 --- a/clients/android/native/src/decode.rs +++ b/clients/android/native/src/decode.rs @@ -39,8 +39,8 @@ const PENDING_SPLIT_CAP: usize = 256; /// Whether low-latency mode uses the event-driven async decode loop (default) or the synchronous /// poll loop. Flip to `false` to A/B the two on the HUD (`design/…`); the async loop presents a /// decoded frame the instant it's ready instead of waiting out a poll interval. Only consulted when -/// the user's "Low-latency mode (experimental)" toggle is ON — off, the sync loop always runs (the -/// original pipeline). +/// the user's "Low-latency mode" toggle is ON (now the default) — off, the sync loop always runs (the +/// original pipeline, kept as the per-device escape hatch). const USE_ASYNC_DECODE: bool = true; /// Per-session decode configuration, resolved by the JNI layer (`nativeStartVideo`) and passed to @@ -52,10 +52,10 @@ pub(crate) struct DecodeOptions { /// Whether Kotlin found the chosen decoder advertises `FEATURE_LowLatency` (queryable only via /// the Java `CodecCapabilities` API) — surfaced on the HUD next to the decoder name. pub ll_feature: bool, - /// The user's "Low-latency mode (experimental)" master toggle. On ⇒ the full overhaul: async + /// The user's "Low-latency mode" master toggle. On (default) ⇒ the full fast pipeline: async /// decode loop, per-SoC vendor keys, pipeline thread boosts, ADPF max-performance, forced TV - /// mode switch. Off (default) ⇒ the original pre-overhaul pipeline, kept as the known-good - /// baseline while the overhaul is experimental. + /// mode switch. Off ⇒ the original synchronous pre-overhaul pipeline, kept as the per-device + /// escape hatch. pub low_latency_mode: bool, /// TV form factor (Kotlin's `UiModeManager`): actively drive the HDMI output into the stream's /// refresh mode, vs. the softer seamless hint on a phone/tablet. @@ -409,10 +409,10 @@ fn create_codec(mime: &str, preferred: Option<&str>) -> Option { /// Apply the low-latency MediaFormat keys for `codec_name`. /// -/// `aggressive` = the "Low-latency mode (experimental)" master toggle. **Off** (default) ⇒ the -/// pre-overhaul key set, byte-for-byte — the standard `low-latency` key, the blind Qualcomm vendor -/// twin, `priority = 0` AND `operating-rate = MAX` set together — kept as the known-good baseline -/// (the profile every device streamed with before the overhaul). **On** ⇒ the Moonlight-parity +/// `aggressive` = the "Low-latency mode" master toggle. **Off** ⇒ the pre-overhaul key set, +/// byte-for-byte — the standard `low-latency` key, the blind Qualcomm vendor twin, `priority = 0` AND +/// `operating-rate = MAX` set together — kept as the per-device escape hatch (the profile every device +/// streamed with before the overhaul). **On** (default) ⇒ the Moonlight-parity /// profile: MediaTek's `vdec-lowlatency` (unconditionally — ignored off MediaTek), the per-SoC /// vendor extension keys (gated on the decoder-name prefix the way Moonlight-Android does, since a /// key one vendor honours is meaningless on another), and one *mutually exclusive* clock hint.