feat(M4): Windows WinForms client, TOFU identity pinning, VAD threshold + always-on mode
Core ABI extensions (voicecat.h):
- vc_list_channels / vc_list_users / vc_list_user_streams — pull-based snapshot getters
for the channel-tree and user-list UI; session_model_mu_ guards cross-thread reads
- VC_EVENT_JOIN_RESULT / vc_join_channel — channel join with optional password
- VC_EVENT_SERVER_IDENTITY + vc_confirm_server_identity — TOFU gate that blocks io_thread_
until the UI approves or rejects; pins TLS leaf-cert SHA-256 (not declared Ed25519)
- vc_get_server_identity_display — Ed25519 fingerprint for human-readable display only
- VC_INPUT_ALWAYS_ON = 2 in vc_input_mode — transmit unconditionally, no VAD gate
- vc_set_vad_threshold — live RMS threshold update (0.0–1.0); EnergyVadProcessor stores
it atomically so the audio RT path reads without a lock
C++ implementation:
- SessionModel::apply_snapshot / apply_channel_event fixed to populate parent_id,
password_protected, and max_users (were permanently zeroed)
- TlsContext::peer_cert_fingerprint — SHA-256 of peer leaf cert DER via mbedTLS
- TofuStore split into peek (read-only) + pin (write) so first-connect only persists
after user approval; tofu_store_path in vc_config for per-user pin file location
- TcpAcceptor uses dual-stack IPv6+IPv4 fallback (fixes localhost → ::1 on Windows)
- windows-client CMake preset: Release shared DLL, static MinGW runtime, no tools/tests
- New C++ tests: test_channel_user_list_abi, test_tofu_flow (14/14 green)
Windows client (clients/windows/ — .NET 10 WinForms):
- VoiceCat.Interop: LibraryImport P/Invoke surface, UnmanagedCallersOnly callbacks,
Channel<VoiceCatEvent> event delivery drained by 30ms WinForms Timer
- VoiceCat.App: ConnectDialog (saved servers, DPAPI password storage), ServerIdentity-
Dialog (TOFU first-connect / mismatch warning), MainForm (channel TreeView, user
ListBox, RichTextBox chat, voice controls, device pickers, VAD/PTT/always-on mode,
per-user gain/mute/NR tuning, VAD sensitivity TrackBar, level meter ProgressBar)
- PttKeyCaptureDialog — focus-scoped PTT key capture (documented limitation)
- PerUserTuningDialog — real-time gain/mute/NR applied to all of a user's streams
- Accessibility: explicit AccessibleName/Description on every control, & mnemonics,
Activity log ListBox as durable screen-reader record, AutomationNotification for
curated live announcements
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 00:35:16 +02:00
|
|
|
// Mirrors of voicecat.h's enums. Keep these in lockstep with core/include/voicecat.h —
|
|
|
|
|
// values are append-only per the C ABI's house rule, so it's safe to add new members at the
|
|
|
|
|
// end here too, but never renumber/remove existing ones.
|
|
|
|
|
namespace VoiceCat.Interop;
|
|
|
|
|
|
|
|
|
|
public enum VcResult
|
|
|
|
|
{
|
|
|
|
|
Ok = 0,
|
|
|
|
|
NotImplemented = 1,
|
|
|
|
|
InvalidArg = 2,
|
|
|
|
|
NotConnected = 3,
|
|
|
|
|
Already = 4,
|
|
|
|
|
AuthFailed = 5,
|
|
|
|
|
PermissionDenied = 6,
|
|
|
|
|
Timeout = 7,
|
|
|
|
|
Io = 8,
|
|
|
|
|
Protocol = 9,
|
|
|
|
|
Crypto = 10,
|
|
|
|
|
Audio = 11,
|
|
|
|
|
Internal = 12,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public enum VcLogLevel
|
|
|
|
|
{
|
|
|
|
|
Trace = 0,
|
|
|
|
|
Debug = 1,
|
|
|
|
|
Info = 2,
|
|
|
|
|
Warn = 3,
|
|
|
|
|
Error = 4,
|
|
|
|
|
Off = 5,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public enum VcConnectionState
|
|
|
|
|
{
|
|
|
|
|
Disconnected = 0,
|
|
|
|
|
Connecting = 1,
|
|
|
|
|
TlsHandshake = 2,
|
|
|
|
|
Authenticating = 3,
|
|
|
|
|
Connected = 4,
|
|
|
|
|
/// <summary>M4: handshake succeeded, waiting on vc_confirm_server_identity().</summary>
|
|
|
|
|
VerifyingIdentity = 5,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public enum VcTextScope
|
|
|
|
|
{
|
|
|
|
|
Channel = 0,
|
|
|
|
|
Private = 1,
|
|
|
|
|
Server = 2,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public enum VcDeviceKind
|
|
|
|
|
{
|
|
|
|
|
Input = 0,
|
|
|
|
|
Output = 1,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public enum VcStreamKind
|
|
|
|
|
{
|
|
|
|
|
Mic = 0,
|
|
|
|
|
/// <summary>System/desktop audio (WASAPI loopback on Windows).</summary>
|
|
|
|
|
ScreenAudio = 1,
|
|
|
|
|
AuxDevice = 2,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>Send-side input gate (docs/voice.md §11).</summary>
|
|
|
|
|
public enum VcInputMode
|
|
|
|
|
{
|
|
|
|
|
VoiceActivation = 0,
|
|
|
|
|
PushToTalk = 1,
|
|
|
|
|
AlwaysOn = 2, // transmit unconditionally, no VAD gate
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public enum VcEventType
|
|
|
|
|
{
|
|
|
|
|
ConnectionState = 0,
|
|
|
|
|
AuthResult = 1,
|
|
|
|
|
ChannelList = 2,
|
|
|
|
|
UserJoined = 3,
|
|
|
|
|
UserLeft = 4,
|
|
|
|
|
UserUpdated = 5,
|
|
|
|
|
TextMessage = 6,
|
|
|
|
|
StreamStarted = 7,
|
|
|
|
|
StreamStopped = 8,
|
|
|
|
|
TalkState = 9,
|
|
|
|
|
Error = 10,
|
|
|
|
|
Disconnected = 11,
|
|
|
|
|
/// <summary>M4: reply to VoiceCatClient.JoinChannelAsync's underlying vc_join_channel.</summary>
|
|
|
|
|
JoinResult = 12,
|
|
|
|
|
/// <summary>M4: the TOFU server-identity gate — see VcTofuStatus.</summary>
|
|
|
|
|
ServerIdentity = 13,
|
2026-06-17 16:31:29 +02:00
|
|
|
/// <summary>M5: async result for moderation/admin/channel operations.</summary>
|
|
|
|
|
GenericResult = 14,
|
|
|
|
|
/// <summary>M5: reply to VoiceCatClient.RequestAccountList — call ListAccounts() to read.</summary>
|
|
|
|
|
AccountList = 15,
|
feat(M4): Windows WinForms client, TOFU identity pinning, VAD threshold + always-on mode
Core ABI extensions (voicecat.h):
- vc_list_channels / vc_list_users / vc_list_user_streams — pull-based snapshot getters
for the channel-tree and user-list UI; session_model_mu_ guards cross-thread reads
- VC_EVENT_JOIN_RESULT / vc_join_channel — channel join with optional password
- VC_EVENT_SERVER_IDENTITY + vc_confirm_server_identity — TOFU gate that blocks io_thread_
until the UI approves or rejects; pins TLS leaf-cert SHA-256 (not declared Ed25519)
- vc_get_server_identity_display — Ed25519 fingerprint for human-readable display only
- VC_INPUT_ALWAYS_ON = 2 in vc_input_mode — transmit unconditionally, no VAD gate
- vc_set_vad_threshold — live RMS threshold update (0.0–1.0); EnergyVadProcessor stores
it atomically so the audio RT path reads without a lock
C++ implementation:
- SessionModel::apply_snapshot / apply_channel_event fixed to populate parent_id,
password_protected, and max_users (were permanently zeroed)
- TlsContext::peer_cert_fingerprint — SHA-256 of peer leaf cert DER via mbedTLS
- TofuStore split into peek (read-only) + pin (write) so first-connect only persists
after user approval; tofu_store_path in vc_config for per-user pin file location
- TcpAcceptor uses dual-stack IPv6+IPv4 fallback (fixes localhost → ::1 on Windows)
- windows-client CMake preset: Release shared DLL, static MinGW runtime, no tools/tests
- New C++ tests: test_channel_user_list_abi, test_tofu_flow (14/14 green)
Windows client (clients/windows/ — .NET 10 WinForms):
- VoiceCat.Interop: LibraryImport P/Invoke surface, UnmanagedCallersOnly callbacks,
Channel<VoiceCatEvent> event delivery drained by 30ms WinForms Timer
- VoiceCat.App: ConnectDialog (saved servers, DPAPI password storage), ServerIdentity-
Dialog (TOFU first-connect / mismatch warning), MainForm (channel TreeView, user
ListBox, RichTextBox chat, voice controls, device pickers, VAD/PTT/always-on mode,
per-user gain/mute/NR tuning, VAD sensitivity TrackBar, level meter ProgressBar)
- PttKeyCaptureDialog — focus-scoped PTT key capture (documented limitation)
- PerUserTuningDialog — real-time gain/mute/NR applied to all of a user's streams
- Accessibility: explicit AccessibleName/Description on every control, & mnemonics,
Activity log ListBox as durable screen-reader record, AutomationNotification for
curated live announcements
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 00:35:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// TOFU server-identity classification. Pins the TLS leaf certificate's own SHA-256
|
|
|
|
|
/// fingerprint (real, verifiable from the handshake) — NOT the declared Ed25519 identity
|
|
|
|
|
/// fingerprint from ServerHello, which is informational/display-only (see
|
|
|
|
|
/// VoiceCatClient.GetServerIdentityDisplay and docs/security.md §1.1).
|
|
|
|
|
/// </summary>
|
|
|
|
|
public enum VcTofuStatus
|
|
|
|
|
{
|
|
|
|
|
FirstConnect = 0,
|
|
|
|
|
Matched = 1,
|
|
|
|
|
Mismatch = 2,
|
|
|
|
|
}
|