feat(core,apple,session): report decode latency from the Apple + Windows/Linux clients too
ci / web (push) Successful in 51s
ci / docs-site (push) Successful in 1m4s
ci / rust (push) Failing after 6m46s
decky / build-publish (push) Successful in 20s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 10s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 9s
ci / bench (push) Successful in 5m19s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 9s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 9s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 8s
arch / build-publish (push) Successful in 11m12s
windows-host / package (push) Successful in 14m52s
flatpak / build-publish (push) Successful in 7m10s
android / android (push) Successful in 16m0s
docker / deploy-docs (push) Failing after 17s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 4m8s
deb / build-publish (push) Successful in 14m3s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 13m41s
windows-msix / package (x64, C:\Users\Public\ffmpeg, , x86_64-pc-windows-msvc, C:\t) (push) Successful in 4m8s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 13m18s
windows / build (aarch64-pc-windows-msvc) (push) Successful in 4m54s
windows / build (x86_64-pc-windows-msvc) (push) Successful in 5m31s
apple / swift (push) Successful in 5m19s
release / apple (push) Successful in 27m46s
apple / screenshots (push) Successful in 19m39s

Extends 56f9c8c4 (the Automatic-bitrate decode signal, core + Android) to the remaining
clients, so every platform caps Automatic at its real decoder limit instead of the network
link ceiling — the fix for a fast LAN feeding a slower hardware decoder.

- core/abi: punktfunk_connection_report_decode_us + _wants_decode_latency expose the
  NativeClient methods to the C-ABI embedders (regenerated punktfunk_core.h, additive only).
- apple: PunktfunkConnection wrappers + Stage2Pipeline reports received→decoded from the
  VideoToolbox decode-completion callback — every decoded frame, before the newest-wins ring
  can drop the backlog. Stage-1 (AVSampleBufferDisplayLayer, no per-frame decode callback)
  stays network-only; stage-2 is the metered path.
- windows/linux: the shared punktfunk-session client (pf-client-core) links core directly, so
  it calls the NativeClient methods — report received→decoded from the pump, gated on
  wants_decode_latency. Exact for the synchronous D3D11VA/software decode; received→submit
  (still the decoder-input backpressure signal) for the async Vulkan-Video path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-15 17:43:54 +02:00
parent 56f9c8c4b4
commit ff38933312
5 changed files with 155 additions and 0 deletions
+12
View File
@@ -352,6 +352,9 @@ fn pump(
// corrected), `decode` = received→decoded (client-local). p50 per 1 s window.
let mut hostnet_us: Vec<u64> = Vec::with_capacity(256);
let mut decode_us: Vec<u64> = Vec::with_capacity(256);
// Adaptive bitrate: report the decode stage back to the core controller only when it's armed
// (Automatic, non-PyroWave). Constant for the session — resolve once, gate the per-frame call.
let wants_decode = connector.wants_decode_latency();
// Host/network split (Phase 2): frames awaiting their per-AU 0xCF host timing,
// correlated by pts_ns. Bounded — an old host never sends any, so entries just age out.
let mut pending_split: std::collections::VecDeque<(u64, u64)> =
@@ -574,6 +577,15 @@ fn pump(
decode_us.push(decoded_ns.saturating_sub(received_ns) / 1000);
}
}
// Adaptive bitrate: feed the decoder-backlog signal every frame (the network
// signals can't see the client's decoder). Uses the CPU-side decoded stamp:
// exact for the synchronous D3D11VA/software path; received→submit for the
// async Vulkan-Video path — still the decoder-input backpressure the rate
// controller needs, without the per-frame fence wait the HUD stat avoids.
if wants_decode {
let us = decoded_ns.saturating_sub(received_ns) / 1000;
connector.report_decode_us(us.min(u32::MAX as u64) as u32);
}
}
// The decoder produced nothing — under zero-reorder LOW_DELAY (one-in/one-out) that
// means it's wedged on missing references with no reassembler drop to trigger