feat: PyroWave Phase 3 — pinned rate, all-intra silencing, opt-in UI, notices, docs
ci / docs-site (push) Successful in 1m0s
ci / web (push) Successful in 2m13s
arch / build-publish (push) Failing after 6m17s
decky / build-publish (push) Successful in 18s
android / android (push) Failing after 6m43s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 9s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 10s
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 8s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 53s
ci / bench (push) Successful in 5m6s
ci / rust (push) Failing after 9m30s
docker / deploy-docs (push) Successful in 27s
flatpak / build-publish (push) Failing after 4m50s
deb / build-publish (push) Failing after 7m17s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Failing after 6m10s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Failing after 6m2s
windows-host / package (push) Failing after 3m4s
apple / swift (push) Failing after 1m25s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (push) Failing after 3m1s
release / apple (push) Failing after 1m28s
windows-msix / package (x64, C:\Users\Public\ffmpeg, , x86_64-pc-windows-msvc, C:\t) (push) Failing after 2m15s
windows / build (aarch64-pc-windows-msvc) (push) Failing after 4m36s
windows / build (x86_64-pc-windows-msvc) (push) Failing after 4m43s
apple / screenshots (push) Has been skipped
ci / docs-site (push) Successful in 1m0s
ci / web (push) Successful in 2m13s
arch / build-publish (push) Failing after 6m17s
decky / build-publish (push) Successful in 18s
android / android (push) Failing after 6m43s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 9s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 10s
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 8s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 53s
ci / bench (push) Successful in 5m6s
ci / rust (push) Failing after 9m30s
docker / deploy-docs (push) Successful in 27s
flatpak / build-publish (push) Failing after 4m50s
deb / build-publish (push) Failing after 7m17s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Failing after 6m10s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Failing after 6m2s
windows-host / package (push) Failing after 3m4s
apple / swift (push) Failing after 1m25s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (push) Failing after 3m1s
release / apple (push) Failing after 1m28s
windows-msix / package (x64, C:\Users\Public\ffmpeg, , x86_64-pc-windows-msvc, C:\t) (push) Failing after 2m15s
windows / build (aarch64-pc-windows-msvc) (push) Failing after 4m36s
windows / build (x86_64-pc-windows-msvc) (push) Failing after 4m43s
apple / screenshots (push) Has been skipped
plan §4.6 + Phase 3 productization: - Pinned bitrate: an Automatic client (bitrate 0) on a PyroWave session resolves to the codec's ~1.6 bpp operating point for the mode (≈200 Mbps at 1080p60) instead of the 20 Mbps H.26x default; explicit rates are honored. Mid-stream SetBitrate retargets are refused with the pinned rate acked (guards old/foreign clients), and the client-side AIMD controller + startup capacity probe stay off for the codec — no rate descent into wavelet mush, no climb probe whose VBV reasoning doesn't apply to hard per-frame CBR. Unit-tested. - All-intra silencing: the data plane drops drained keyframe/RFI requests on PyroWave sessions (the next frame IS the recovery), so the forced-IDR cooldown, RFI attempt, and storm coalescing never run. - Opt-in UI: 'PyroWave (wired LAN)' joins the console's Video-codec cycler; trust::Settings maps it to CODEC_PYROWAVE. Safe everywhere by the negotiation contract — an un-advertised preference falls back through the ladder. - FEC: decision recorded — adaptive FEC (10% start, loss-report driven) stays as-is for the MVP opaque-AU mode; the FEC≈0 policy belongs to the Phase-4 datagram-aligned mode. - THIRD-PARTY-NOTICES: the generator now lists third-party trees vendored inside first-party crates (pyrowave, Granite subset, volk, Vulkan-Headers) with their full license texts; file regenerated. - docs-site: 'PyroWave (wired-LAN codec)' page — what it is, the bandwidth table, how to enable it, current limits. Validated on .21: 309 host + 148 core + 26 client tests green, console-ui clean, both feature configs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -280,6 +280,65 @@ pub fn pair_with_host(
|
||||
)
|
||||
}
|
||||
|
||||
/// User-facing sentence for a failed connect / request-access, keyed on the actual cause —
|
||||
/// shared by every desktop/console surface so "the host declined this device" never renders
|
||||
/// as "connection timed out". Reason-specific text for a typed host rejection
|
||||
/// ([`punktfunk_core::reject::RejectReason`]); the caller keeps its own wording for
|
||||
/// non-rejection errors.
|
||||
pub fn connect_reject_message(reason: punktfunk_core::reject::RejectReason) -> String {
|
||||
use punktfunk_core::reject::RejectReason as R;
|
||||
match reason {
|
||||
R::Denied => "The host declined this device's request.".into(),
|
||||
R::ApprovalTimeout => {
|
||||
"Nobody approved the request on the host in time — approve this device in the \
|
||||
host's console or web UI, then request access again."
|
||||
.into()
|
||||
}
|
||||
R::Superseded => {
|
||||
"A newer request from this device replaced this one — approve the latest request \
|
||||
on the host."
|
||||
.into()
|
||||
}
|
||||
R::IdentityRequired => {
|
||||
"The host requires pairing — pair this device (PIN or request access) first.".into()
|
||||
}
|
||||
R::PairingNotArmed => {
|
||||
"Pairing isn't armed on the host — arm it on the host's Pairing page, then try \
|
||||
again."
|
||||
.into()
|
||||
}
|
||||
R::PairingBoundToOtherDevice => {
|
||||
"The host's pairing window is armed for a different device — arm it for this one."
|
||||
.into()
|
||||
}
|
||||
R::PairingRateLimited => {
|
||||
"Too many pairing attempts — wait a couple of seconds and try again.".into()
|
||||
}
|
||||
R::WireVersionMismatch => {
|
||||
"Client and host versions don't match — update both to the same release.".into()
|
||||
}
|
||||
R::Busy => "The host is busy with another session.".into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// User-facing sentence for a failed PIN pairing ceremony ([`pair_with_host`]) — distinguishes
|
||||
/// a wrong PIN (the SPAKE2 proof failed) from an unreachable host and from the host's typed
|
||||
/// rejections, so a dead network path or a disarmed host is never reported as a bad PIN.
|
||||
pub fn pair_error_message(err: &punktfunk_core::PunktfunkError) -> String {
|
||||
use punktfunk_core::PunktfunkError as E;
|
||||
match err {
|
||||
E::Crypto => "Wrong PIN — check the PIN on the host's Pairing page and try again.".into(),
|
||||
E::Rejected(reason) => connect_reject_message(*reason),
|
||||
E::Timeout => "The host didn't answer. Is it running and reachable?".into(),
|
||||
E::Io(_) => {
|
||||
"Couldn't reach the host — check that this device and the host are on the same \
|
||||
network (no VPN on this device, no guest-Wi-Fi / AP isolation)."
|
||||
.into()
|
||||
}
|
||||
other => format!("Pairing failed: {other:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Probe several hosts for reachability in parallel — one thread each, so the wall-clock cost is
|
||||
/// ~one `timeout`, not the sum. Each element of the returned vec corresponds by index to
|
||||
/// `targets`. Wraps the single-host [`NativeClient::probe`] (a bounded, trust-agnostic,
|
||||
@@ -515,6 +574,10 @@ impl Settings {
|
||||
"h264" | "avc" => punktfunk_core::quic::CODEC_H264,
|
||||
"hevc" | "h265" => punktfunk_core::quic::CODEC_HEVC,
|
||||
"av1" => punktfunk_core::quic::CODEC_AV1,
|
||||
// The wired-LAN wavelet codec: preference-only by design (resolve_codec never
|
||||
// auto-picks it), and harmless on a build/device that doesn't advertise the
|
||||
// bit — the ladder falls back to HEVC.
|
||||
"pyrowave" => punktfunk_core::quic::CODEC_PYROWAVE,
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
@@ -631,6 +694,9 @@ mod tests {
|
||||
assert!(s.mic_enabled);
|
||||
assert_eq!(s.decoder, "hardware");
|
||||
assert_eq!(s.preferred_codec(), punktfunk_core::quic::CODEC_AV1);
|
||||
let mut pw = s.clone();
|
||||
pw.codec = "pyrowave".into();
|
||||
assert_eq!(pw.preferred_codec(), punktfunk_core::quic::CODEC_PYROWAVE);
|
||||
assert_eq!(s.adapter, "NVIDIA GeForce RTX 4080");
|
||||
assert!(s.hdr_enabled);
|
||||
// The old shell's `show_hud` lands on `show_stats` (the user's preference survives).
|
||||
|
||||
Reference in New Issue
Block a user