Files
buzz/crates/buzz-audio-client
Will Pfleger 65e864301d feat: send a User-Agent on relay WebSocket upgrades (#9246)
Relay WebSocket clients in this repo now send a `User-Agent` of the form
`<name>/<version>` on the upgrade request. The version comes from the
build.

| Client | User-Agent |
|---|---|
| `buzz-acp` | `buzz-acp/<crate version>` |
| `buzz-cli` | `buzz-cli/<crate version>` |
| `buzz-ws-client` (default) | `buzz-ws-client/<crate version>` |
| `buzz-pairing-cli` | `buzz-pairing-cli/<crate version>` |
| `buzz-audio-client` (default) | `buzz-audio-client/<crate version>` |
| mobile (relay and huddle sockets) | `Buzz-Mobile/<app version>` |

- **`buzz-ws-client`**: every connect path sends the default. A
`User-Agent` in the caller's `connect_with_headers` headers replaces it,
so other consumers can identify themselves without any new API.
`buzz-cli` uses this to send its own name.
- **`buzz-audio-client`**: keeps a `User-Agent` already on the
host-supplied request, and adds its default otherwise.
- **Mobile**: `openRelayWebSocket` sets the HTTP client's `userAgent`,
which also covers the huddle transport. Startup waits up to 500 ms for
the app version from `package_info_plus` before the app runs, so the
first socket carries it; if the lookup fails or times out, the value is
`Buzz-Mobile`.

Each client has a test asserting the header on the upgrade request.

---------

Signed-off-by: Will Pfleger <wpfleger@block.xyz>
Co-authored-by: Hayt <211b96e6a2b7f45fd4047988976c7bbbeeda0c15f3ae7b32eec20834b5a55118@buzz.block.builderlab.xyz>
2026-11-08 20:43:55 -05:00
..

Shared Huddle audio client

buzz-audio-client contains the Huddle v2 audio handshake, wire format, Opus sender, and per-peer NetEQ jitter buffer used by Buzz desktop clients. It does not depend on Tauri, the v0 desktop application, a relay server, identity stores, or speech models. A consumer can select this package from a pinned block/buzz Git revision without building the rest of the workspace.

The host validates the destination and supplies an asynchronous NIP-42 signer to connection::connect. The crate bounds connection and admission, validates the initial roster, and returns a socket owned by the host. Dropping the pending future or socket releases it; the crate creates no detached tasks. Hosts retain room creation, membership checks, mute, device routing, connection supervision, and application teardown. Audio admission alone does not grant chat access.

AudioEncoder accepts up to 960 finite mono samples at 48 kHz and produces a 20 ms v2 packet. PeerJitterBuffer consumes the sequence/timestamp/Opus fields from wire::parse_relay_frame and produces 480 samples per 10 ms playout tick. Hosts maintain one receiver per peer, discard its state on leave or roster reassignment, bound playback queues, and stop idle peers after buffered audio drains. V2 has no occupancy epoch in media, so a delayed packet from a previous occupant cannot be distinguished after index reuse.

The default native-roots feature selects system TLS trust. Hosts that use WebPKI roots select default-features = false, features = ["webpki-roots"]; hosts can also pass their configured TLS connector. Signing and trust policy remain host-owned.

Opus 0.4 uses the maintained opusic-sys backend. NetEQ is pinned to 0.8.3: its published source does not use its declared ringbuf dependency, which has advisory RUSTSEC-2026-0293. The root security policy documents that unreachable path and forbids other consumers of vulnerable ringbuf versions. Re-audit or remove that exception when updating NetEQ; 0.9.1 still declares the old ringbuf.

Run cargo test -p buzz-audio-client and cargo clippy -p buzz-audio-client --all-targets -- -D warnings from the root with Hermit active. Tests use real loopback WebSockets and Opus audio, without a live community or microphone. Client integration still requires a native two-person call, mute, leave, cancellation, and device-switching tryout.

STT/TTS providers, model installation, and speech HTTP endpoints are intentionally outside this transport crate.