- PROGRESS.md: add 2026-04-13 section with 5-tier quality, QualityDirective handling, debug tap enhancements, dual_path fix, keystore sync - PRD-coordinated-codec.md: Phase 3 marked complete (client directive handling) - PRD-adaptive-quality.md: milestone table updated with Done/Pending status Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -195,11 +195,11 @@ The `CallEncoder` already has `set_profile()`. The `CallDecoder` already auto-sw
|
|||||||
|
|
||||||
## Milestones
|
## Milestones
|
||||||
|
|
||||||
| Phase | Scope | Effort | Dependency |
|
| Phase | Scope | Effort | Status |
|
||||||
|-------|-------|--------|------------|
|
|-------|-------|--------|--------|
|
||||||
| 0 | Verify relay sends QualityReports | 0.5 day | None |
|
| 0 | Verify relay sends QualityReports | 0.5 day | Done |
|
||||||
| 1a | Wire QualityAdapter in Android engine | 1 day | Phase 0 |
|
| 1a | Wire QualityAdapter in Android engine | 1 day | Done |
|
||||||
| 1b | Wire QualityAdapter in desktop engine | 1 day | Phase 0 |
|
| 1b | Wire QualityAdapter in desktop engine | 1 day | Done |
|
||||||
| 1c | UI indicator (current codec) | 0.5 day | Phase 1a/1b |
|
| 1c | UI indicator (current codec) | 0.5 day | Done |
|
||||||
| 2 | Extended 5-tier classification | 0.5 day | Phase 1 |
|
| 2 | Extended 5-tier classification (Studio64k→Catastrophic) | 0.5 day | Done (2026-04-13) |
|
||||||
| 3 | Bandwidth probing | 2 days | Phase 2 |
|
| 3 | Bandwidth probing | 2 days | Pending (task #10) |
|
||||||
|
|||||||
@@ -208,15 +208,14 @@ Phases 1-2 are implemented. Phase 3 has a critical gap.
|
|||||||
- **Weakest-link broadcast**: `observe_quality()` method computes room-wide worst tier, broadcasts `QualityDirective` to all participants when tier changes
|
- **Weakest-link broadcast**: `observe_quality()` method computes room-wide worst tier, broadcasts `QualityDirective` to all participants when tier changes
|
||||||
- **Desktop engine handling** (`desktop/src-tauri/src/engine.rs`): `AdaptiveQualityController` in recv task, `pending_profile` AtomicU8 bridge to send task, auto-mode profile switching based on **inbound quality reports**
|
- **Desktop engine handling** (`desktop/src-tauri/src/engine.rs`): `AdaptiveQualityController` in recv task, `pending_profile` AtomicU8 bridge to send task, auto-mode profile switching based on **inbound quality reports**
|
||||||
|
|
||||||
### Gap: QualityDirective signals silently discarded
|
### Phase 3 completed (2026-04-13)
|
||||||
|
|
||||||
Both engines receive `QualityDirective` from the relay but **do not process it**:
|
Both engines now handle `QualityDirective` signals from the relay:
|
||||||
- **Desktop** (`engine.rs` ~line 1152): signal recv loop matches `RoomUpdate` only; `QualityDirective` falls through the catch-all `Ok(Ok(Some(_))) => {}` arm
|
- **Desktop** (`engine.rs`): both P2P and relay signal tasks match `QualityDirective`, extract `recommended_profile`, store index via `sig_pending_profile.store(idx, Release)`. Send task picks it up at the next frame boundary.
|
||||||
- **Android** (`engine.rs` ~line 1198): same pattern — `QualityDirective` falls through to a generic log `info!("signal received: {:?}", ...)` with no action
|
- **Android** (`engine.rs`): signal task matches `QualityDirective`, stores via `pending_profile_recv.store(idx, Release)`.
|
||||||
|
|
||||||
The relay broadcasts directives correctly, but clients ignore them. Desktop adaptive quality currently works **only** via local `AdaptiveQualityController` observing inbound quality reports — not via relay-coordinated directives.
|
Relay-coordinated codec switching is now end-to-end: relay monitors → broadcasts directive → clients switch.
|
||||||
|
|
||||||
### Phases remaining
|
### Phase remaining
|
||||||
|
|
||||||
- Phase 3: **Client-side handling of `QualityDirective`** — add match arms in both engines' signal recv loops to apply `recommended_profile` via `pending_profile` AtomicU8. ~0.5 day since the plumbing already exists.
|
- Phase 4: Upgrade proposal/negotiation protocol for quality recovery (task #28)
|
||||||
- Phase 4: Upgrade proposal/negotiation protocol for quality recovery
|
|
||||||
|
|||||||
@@ -120,9 +120,7 @@
|
|||||||
|
|
||||||
- **Web audio drift**: The browser AudioWorklet playback buffer caps at 200ms, but clock drift between the WebSocket message arrival rate and the AudioContext output rate can cause occasional underruns or accumulation. The cap prevents unbounded growth but may cause glitches.
|
- **Web audio drift**: The browser AudioWorklet playback buffer caps at 200ms, but clock drift between the WebSocket message arrival rate and the AudioContext output rate can cause occasional underruns or accumulation. The cap prevents unbounded growth but may cause glitches.
|
||||||
|
|
||||||
- **Adaptive loop integration (partial)**: AdaptiveQualityController is wired into both desktop and Android send/recv tasks for **inbound quality report observation**. Relay broadcasts QualityDirective to all participants based on weakest-link policy, but **neither engine processes QualityDirective signals** — they fall through catch-all match arms silently. Local adaptive quality works; relay-coordinated quality does not.
|
- **Adaptive loop integration (resolved)**: AdaptiveQualityController wired into both desktop and Android send/recv tasks. Relay-coordinated codec switching broadcasts QualityDirective — now handled by both engines (fixed 2026-04-13). 5-tier classification (Studio64k through Catastrophic) with asymmetric hysteresis.
|
||||||
|
|
||||||
- **dual_path.rs test regression (Phase 7)**: Phase 7 (IPv6 dual-socket) added `ipv6_endpoint: Option<Endpoint>` parameter to `race()` in `crates/wzp-client/src/dual_path.rs`, but the integration tests in `crates/wzp-client/tests/dual_path.rs` were not updated — 3 call sites pass 6 args instead of 7. `cargo test --workspace` fails to compile.
|
|
||||||
|
|
||||||
- **Relay FEC pass-through**: In room mode, the relay forwards packets opaquely without FEC decode/re-encode. This means FEC protection is end-to-end only, not per-hop. In forward mode, the relay pipeline does perform FEC decode/re-encode.
|
- **Relay FEC pass-through**: In room mode, the relay forwards packets opaquely without FEC decode/re-encode. This means FEC protection is end-to-end only, not per-hop. In forward mode, the relay pipeline does perform FEC decode/re-encode.
|
||||||
|
|
||||||
@@ -194,7 +192,37 @@ Run with `wzp-bench --all`. Representative results (Apple M-series, single core)
|
|||||||
- **CI**: Gitea workflow defined for amd64/arm64/armv7 builds
|
- **CI**: Gitea workflow defined for amd64/arm64/armv7 builds
|
||||||
- **Production**: Not yet deployed to production networks
|
- **Production**: Not yet deployed to production networks
|
||||||
|
|
||||||
## Recent Changes (2026-04-12)
|
## Recent Changes (2026-04-13)
|
||||||
|
|
||||||
|
### 5-Tier Adaptive Quality Classification (#9)
|
||||||
|
- `Tier` enum extended from 3 to 6 levels: Studio64k > Studio48k > Studio32k > Good > Degraded > Catastrophic
|
||||||
|
- WiFi thresholds: loss < 1%/RTT < 30ms (Studio64k) through loss >= 15%/RTT >= 200ms (Catastrophic)
|
||||||
|
- Cellular stays at Good ceiling (no studio tiers on mobile data)
|
||||||
|
- Asymmetric hysteresis: downgrade 3 reports, upgrade 5, studio upgrade 10
|
||||||
|
- `Tier` derives `Ord` — ordering matches quality level (Catastrophic=0, Studio64k=5)
|
||||||
|
- `weakest_tier()` simplified to `.min()` via Ord
|
||||||
|
|
||||||
|
### Client QualityDirective Handling (#27)
|
||||||
|
- Both desktop signal tasks (P2P and relay engines) now match `QualityDirective` signals
|
||||||
|
- Android signal task matches `QualityDirective` and stores profile index via `pending_profile_recv`
|
||||||
|
- Relay-coordinated codec switching now works end-to-end: relay broadcasts → clients react
|
||||||
|
- Closes the gap documented in PRD-coordinated-codec.md
|
||||||
|
|
||||||
|
### Debug Tap Enhancements (#11, #12)
|
||||||
|
- `log_signal()`: logs `RoomUpdate` (count + participant names), `QualityDirective` (codec + reason)
|
||||||
|
- `log_event()`: logs participant join/leave lifecycle events
|
||||||
|
- `log_stats()`: periodic 5-second summary — packets in/out, fan-out avg, seq gaps, codecs seen
|
||||||
|
- `TapStats` struct tracks per-participant metrics across the forwarding loop
|
||||||
|
- All output via `target: "debug_tap"` for RUST_LOG filtering
|
||||||
|
|
||||||
|
### Bug Fix: dual_path.rs Phase 7 regression
|
||||||
|
- Added missing `ipv6_endpoint: None` parameter to 3 `race()` call sites in integration tests
|
||||||
|
- Phase 7 IPv6 dual-socket changed the function signature but tests were not updated
|
||||||
|
|
||||||
|
### Build: Keystore sync (f17420a)
|
||||||
|
- `build.sh` syncs keystores from persistent cache before build
|
||||||
|
|
||||||
|
## Previous Changes (2026-04-12)
|
||||||
|
|
||||||
### Bluetooth Audio Routing
|
### Bluetooth Audio Routing
|
||||||
- 3-way route cycling: Earpiece → Speaker → Bluetooth SCO
|
- 3-way route cycling: Earpiece → Speaker → Bluetooth SCO
|
||||||
|
|||||||
Reference in New Issue
Block a user