feat(android): promote the low-latency pipeline to default
apple / swift (push) Successful in 1m6s
android / android (push) Successful in 4m58s
arch / build-publish (push) Successful in 5m59s
ci / web (push) Successful in 51s
ci / rust (push) Successful in 2m29s
ci / docs-site (push) Successful in 1m0s
windows-host / package (push) Successful in 8m15s
release / apple (push) Successful in 8m19s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 1m24s
windows-msix / package (x64, C:\Users\Public\ffmpeg, x86_64-pc-windows-msvc, C:\t) (push) Successful in 1m17s
windows / build (aarch64-pc-windows-msvc) (push) Successful in 54s
ci / bench (push) Successful in 5m14s
windows / build (x86_64-pc-windows-msvc) (push) Successful in 1m1s
deb / build-publish (push) Successful in 5m0s
decky / build-publish (push) Successful in 15s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 6s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 5s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 4s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 54s
apple / screenshots (push) Successful in 5m49s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 2m23s
flatpak / build-publish (push) Successful in 4m39s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Failing after 8m48s
docker / deploy-docs (push) Successful in 19s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Failing after 8m12s

The async decode loop (burst-feed + present-newest-per-vsync, the Apple client's
discipline) plus the per-SoC tuning was gated behind an experimental,
default-off toggle after the 5dc24a0 overhaul regressed on some phones. That
regression was the receive-side latency ratchet the async loop fed — a standing
queue that only grew — now fixed in the shared core (FrameChannel jumps to live
instead of accumulating it), so the fast pipeline is the default again.

Default the master toggle on via a fresh pref key (low_latency_mode_v2),
mirroring the migration da376b31 used to flip it off: a new key re-defaults every
install — including ones persisted off under the old key — to on, so the
promotion reaches users who had saved settings, not just fresh installs. Both
stale keys are abandoned unread. Toggle-off still restores the original
synchronous decode pipeline byte-for-byte as a per-device escape hatch.

Drop "(experimental)" from the settings labels and fix the now-stale default-off
wording in the native + Kotlin docs. No decode-path routing change — run_async is
reached simply because the toggle now defaults on.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-07 16:18:40 +00:00
parent a1b890ef42
commit 04302075b5
5 changed files with 39 additions and 31 deletions
+9 -9
View File
@@ -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<MediaCodec> {
/// 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.