Update docs
This commit is contained in:
@@ -10,7 +10,7 @@ stable **C ABI** (`voicecat.h`).
|
||||
┌───────────────────────────────────────────┐
|
||||
macOS / iOS (Swift) │ │ Windows (C#)
|
||||
┌──────────────────┐ │ libvoicecat (C++) │ ┌──────────────────┐
|
||||
│ SwiftUI views │ │ ┌─────────────────────────────────────┐ │ │ WinUI/Avalonia │
|
||||
│ SwiftUI views │ │ ┌─────────────────────────────────────┐ │ │ WinForms (.NET 10│
|
||||
│ AVAudioSession │──┼─▶│ C ABI (voicecat.h) │◀─┼──│ LibraryImport │
|
||||
│ Swift↔C++ interop│ │ ├─────────────────────────────────────┤ │ │ P/Invoke │
|
||||
└──────────────────┘ │ │ Session / Protocol state machine │ │ └──────────────────┘
|
||||
@@ -150,10 +150,14 @@ Design notes:
|
||||
frames, so audio-only stays well within budget. It links a *minimal* slice of the core
|
||||
(Opus encode + media send), shares the session/credentials with the host app through an
|
||||
**App Group**, and re-derives its own media keys. This is detailed in [voice.md](voice.md) §9.
|
||||
- **C# / Windows.** `LibraryImport` (source-generated P/Invoke, .NET 7+) over the C ABI.
|
||||
Marshal the `on_event` callback as a `[UnmanagedCallersOnly]`/function-pointer to avoid
|
||||
delegate lifetime pitfalls. UI in **WinUI 3** (most native) or **Avalonia** (if we later
|
||||
want a single C# UI across desktop OSes).
|
||||
- **C# / Windows.** `[LibraryImport]` (source-generated P/Invoke, .NET 7+) over the C ABI.
|
||||
`[UnmanagedCallersOnly]` static methods for `on_event`/`on_level` to avoid delegate-lifetime
|
||||
pitfalls. UI in **WinForms (.NET 10)** — chosen over WinUI 3/Avalonia for its mature,
|
||||
predictable screen-reader (NVDA/JAWS/Narrator) UIA support (see roadmap.md §2).
|
||||
Events are delivered via `System.Threading.Channels.Channel<VoiceCatEvent>`, drained by a
|
||||
30ms `System.Windows.Forms.Timer` on the UI thread — simpler than a message-only HWND +
|
||||
`PostMessage` with no meaningful latency cost. `VoiceCatClientHandle : SafeHandle` wraps
|
||||
the `vc_client*` and guarantees `vc_client_destroy` runs on GC/Dispose.
|
||||
|
||||
## 5. Server architecture
|
||||
|
||||
|
||||
@@ -38,13 +38,28 @@ exists from M1 so the protocol can be exercised long before any GUI.
|
||||
- **Exit:** a user shares mic + desktop audio; listeners control each independently.
|
||||
|
||||
### M4 — Native clients
|
||||
- **Windows (C#/WinUI):** connect, saved-server list, channel tree, voice, text, device
|
||||
pickers, meters, VAD/PTT + per-user NR controls.
|
||||
- **macOS (Swift/SwiftUI):** same.
|
||||
- **iOS (Swift):** AVAudioSession integration, mic permission, foreground voice; ReplayKit
|
||||
broadcast extension for `SCREEN_AUDIO`.
|
||||
- In-app **admin interface** (account provisioning, bans) for admin users.
|
||||
- **Exit:** non-technical user installs a client, saves a server, and joins.
|
||||
|
||||
**Windows (C#/WinForms, .NET 10) ✓ complete 2026-06-17:**
|
||||
- Connect, saved-server list (JSON, DPAPI-encrypted passwords), TOFU identity dialog.
|
||||
- Channel tree (`TreeView`), user list, join (incl. password-protected channels).
|
||||
- Voice: mic start/stop, mute/deafen, VAD/PTT/**always-on** mode, **VAD sensitivity slider**
|
||||
(live threshold update via `vc_set_vad_threshold`), device picker, level meter.
|
||||
- Per-user gain/mute/NR tuning (`PerUserTuningDialog`).
|
||||
- Channel + private text chat. Activity log (screen-reader primary path).
|
||||
- Explicit `AccessibleName`/`AccessibleDescription` on every control; `&` mnemonics;
|
||||
`AutomationNotification` curated live announcements.
|
||||
- Focus-scoped PTT (documented limitation — no system-wide hook in v1).
|
||||
- Admin/moderation UI **out of scope** — needs server-side dispatch first (M5).
|
||||
|
||||
**macOS (Swift/SwiftUI) — pending:**
|
||||
- Same feature set as Windows over the same C ABI (now stable and complete).
|
||||
- AVAudioSession, mic permission, interruption/route-change handling.
|
||||
|
||||
**iOS (Swift) — pending:**
|
||||
- AVAudioSession, mic permission, foreground voice.
|
||||
- ReplayKit broadcast extension for `SCREEN_AUDIO`.
|
||||
|
||||
**Exit:** non-technical user installs a client, saves a server, and joins.
|
||||
|
||||
### M5 — Moderation, polish, and beyond
|
||||
- Permissions/roles, kick/ban/server-mute, channel passwords UI.
|
||||
@@ -84,6 +99,25 @@ Settled and reflected throughout the docs:
|
||||
the same `ApmProcessor` interface; there is **no AEC/NS/AGC implementation at all** yet. Real
|
||||
`webrtc-audio-processing` stays a tracked future swap (e.g. if/when a Linux build target
|
||||
exists). (voice.md §8, §11)
|
||||
- **Windows client UI framework (2026-06-17):** **WinForms** (.NET 10), not WinUI 3 or
|
||||
Avalonia. Reason: Win32 HWND controls have the most mature, predictable screen-reader
|
||||
(NVDA/JAWS/Narrator) support of any current .NET UI stack. WinUI 3's accessibility UIA
|
||||
tree has known rough edges on .NET 10; Avalonia's accessibility story is thinner still.
|
||||
This overrides the earlier WinUI/Avalonia mention in `docs/tech-stack.md §2` and
|
||||
`docs/architecture.md §4`. (clients/windows/)
|
||||
- **TOFU pins TLS leaf cert, not Ed25519 (2026-06-17):** the original design said to pin the
|
||||
server's declared Ed25519 identity fingerprint from `ServerHello`. This is circular — the
|
||||
Ed25519 key and the TLS cert are generated independently with no cryptographic binding, so
|
||||
accepting/rejecting based on a value sent *inside* the channel being trust-decided is
|
||||
meaningless. **Decision:** pin the TLS leaf certificate's own SHA-256 fingerprint, which is
|
||||
verifiable directly from the TLS handshake before any application data is trusted. The Ed25519
|
||||
value is still shown in the identity dialog for human-readable display only (informational).
|
||||
See `docs/security.md §1.1`. (core/src/crypto/tofu_store.*, vc_confirm_server_identity)
|
||||
- **PTT is focus-scoped in v1 (2026-06-17):** PTT hotkey capture uses `Form.KeyDown`/`KeyUp`
|
||||
(works only while the VoiceCat window has focus), not a system-wide `WH_KEYBOARD_LL` hook.
|
||||
Reason: a low-level keyboard hook requires escalated permissions, risks AV flagging, and is
|
||||
disproportionate complexity for a v1 client. Documented in the UI as a known limitation.
|
||||
Can be revisited for v2 if users request it. (clients/windows/VoiceCat.App/Forms/MainForm.cs)
|
||||
|
||||
## 3. Open questions
|
||||
|
||||
|
||||
@@ -29,14 +29,26 @@ media channel. Plus server identity, authentication, accounts at rest, and anti-
|
||||
Self-hosting means most servers won't have a CA-signed cert for a hostname. We support
|
||||
both, advertised in `ServerHello`:
|
||||
|
||||
1. **TOFU (Trust On First Use)** — default for hobby servers. The server has a long-lived
|
||||
**Ed25519 identity key**; its fingerprint is shown to the user on first connect (like
|
||||
SSH host keys / TeamSpeak server keys) and pinned locally. Subsequent connects verify
|
||||
the pin; a changed key warns loudly. The TLS cert is self-signed and bound to this
|
||||
identity key.
|
||||
1. **TOFU (Trust On First Use)** — default for hobby servers. On first connect the client
|
||||
shows an identity dialog and, if accepted, pins the value locally. Subsequent connects
|
||||
verify the pin silently; a changed value warns loudly (`MISMATCH`).
|
||||
2. **PKI** — a server with a domain can use a normal CA-signed cert (e.g. Let's Encrypt);
|
||||
clients validate the chain conventionally. TOFU pinning still applies on top.
|
||||
|
||||
**What is actually pinned (M4 implementation):** the **TLS leaf certificate's SHA-256
|
||||
fingerprint** — verifiable directly from the TLS handshake before any application data is
|
||||
trusted. The server also declares an Ed25519 identity fingerprint in `ServerHello`, but this
|
||||
value is **display-only** and is *not* the value that is pinned or verified. Reason: the TLS
|
||||
cert and the Ed25519 identity key are generated independently with no cryptographic binding
|
||||
between them, so pinning the self-declared Ed25519 value (sent *inside* the channel being
|
||||
trust-decided) would be circular — an attacker who impersonates the server at the TLS level
|
||||
would supply whatever Ed25519 value they like. Pinning the TLS cert fingerprint is the only
|
||||
value that is genuinely verifiable at the moment of trust decision.
|
||||
|
||||
This is a known limitation of the current design. Closing it properly requires binding the
|
||||
Ed25519 key into the TLS cert (e.g. as a SubjectAltName or extension), which is a planned
|
||||
future improvement. Until then, clients display both values but gate on the cert fingerprint.
|
||||
|
||||
Client certificates are reserved for a future "key-based identity" option (see roadmap) but
|
||||
are not required in v1.
|
||||
|
||||
|
||||
@@ -33,14 +33,16 @@ explicit resampling (speexdsp/libsamplerate) is only needed when a device can't
|
||||
| Packaging | Swift Package + Xcode project | Core shipped as an XCFramework (device + simulator + macOS slices). |
|
||||
| Future | CallKit / PushKit | For background VoIP + incoming-call UX on iOS. Post-v1. |
|
||||
|
||||
### Windows — C#
|
||||
### Windows — C# (shipped in M4, 2026-06-17)
|
||||
|
||||
| Concern | Choice | Notes |
|
||||
|---------|--------|-------|
|
||||
| Runtime | **.NET 8+** | LTS. |
|
||||
| Interop | **`LibraryImport`** (source-gen P/Invoke) over the C ABI | Marshal the event callback as a function pointer (`[UnmanagedCallersOnly]`) to avoid delegate-lifetime bugs; keep the interface "chunky" not "chatty" to minimize managed↔native transitions. |
|
||||
| UI | **WinUI 3** (most native) or **Avalonia** | WinUI for a first-class Windows look; Avalonia if we later want one C# UI across desktop OSes. |
|
||||
| Audio | handled by the core (miniaudio/WASAPI) | C# only drives device selection + meters. |
|
||||
| Runtime | **.NET 10 LTS** (`net10.0-windows`) | In-service until 2028. |
|
||||
| Interop | **`[LibraryImport]`** (source-gen P/Invoke) over the C ABI | `[UnmanagedCallersOnly]` static methods for `on_event`/`on_level`; `VoiceCatClientHandle : SafeHandle` owns the `vc_client*` lifetime. |
|
||||
| Event delivery | **`System.Threading.Channels.Channel<VoiceCatEvent>`** | Single-writer/reader, unbounded; drained by a 30ms `System.Windows.Forms.Timer` on the UI thread. Simpler than a message-only HWND with no meaningful latency cost. |
|
||||
| UI | **WinForms** | Chosen over WinUI 3 / Avalonia for mature, predictable NVDA/JAWS/Narrator UIA support. Win32 HWND controls have the most complete accessibility story on .NET 10 today. See roadmap.md §2. |
|
||||
| Persistence | **`System.Text.Json`** (`servers.json`), **`ProtectedData`** (DPAPI) | Saved-server list in `%AppData%\VoiceCat\`; passwords DPAPI-encrypted at rest, opt-in, `CurrentUser` scope. |
|
||||
| Audio | Handled by the core (miniaudio/WASAPI) | C# only drives device selection + meters. |
|
||||
|
||||
## 3. Server (`voicecat-server`)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user