using System.Runtime.InteropServices; // Raw P/Invoke surface over core/include/voicecat.h, via LibraryImport (source-generated — // no runtime reflection marshaling stub; see docs/tech-stack.md §2). One entry per voicecat.h // function. `vc_client*` is represented as a raw `nint` here — VoiceCatClientHandle (a // SafeHandle) owns the create/destroy lifetime one level up; these declarations never see a // SafeHandle directly, per .NET's own SafeHandle convention. // // "voicecat" resolves to voicecat.dll via the OS's standard DLL search order (same directory // as the .exe first) — see clients/windows/README.md for how it gets there at build time. namespace VoiceCat.Interop; internal static partial class NativeMethods { private const string LibName = "voicecat"; // ── Lifecycle ──────────────────────────────────────────────────────────────────────── // NOTE: these two return `const char*` pointing at STATIC string literals the core never // expects the caller to free. Declaring them as `string` with StringMarshalling.Utf8 // would be wrong: the built-in Utf8StringMarshaller's return-value convention assumes the // native callee allocated the string FOR this call and that the marshaller should free it // afterward — calling that on a static literal corrupts the heap (confirmed: it crashes // with STATUS_HEAP_CORRUPTION / 0xC0000374). Return the raw pointer instead and convert // with Marshal.PtrToStringUTF8 ourselves, without ever freeing it — see VoiceCatClient.cs. [LibraryImport(LibName)] internal static partial nint vc_version_string(); [LibraryImport(LibName)] internal static partial nint vc_result_string(VcResult code); [LibraryImport(LibName)] internal static partial nint vc_client_create(in VcConfigNative cfg, VcCallbacksNative cb); [LibraryImport(LibName)] internal static partial void vc_client_destroy(nint c); // ── Connection & auth (async; results via on_event) ──────────────────────────────────── [LibraryImport(LibName, StringMarshalling = StringMarshalling.Utf8)] internal static partial VcResult vc_connect(nint c, string host, ushort port); [LibraryImport(LibName)] internal static partial VcResult vc_disconnect(nint c); [LibraryImport(LibName, StringMarshalling = StringMarshalling.Utf8)] internal static partial VcResult vc_authenticate_guest(nint c, string nickname); [LibraryImport(LibName, StringMarshalling = StringMarshalling.Utf8)] internal static partial VcResult vc_authenticate_user(nint c, string username, string password); // ── Channels ───────────────────────────────────────────────────────────────────────── [LibraryImport(LibName, StringMarshalling = StringMarshalling.Utf8)] internal static partial VcResult vc_join_channel(nint c, uint channelId, string? password); [LibraryImport(LibName)] internal static partial VcResult vc_leave_channel(nint c); // ── Local media streams ───────────────────────────────────────────────────────────────── [LibraryImport(LibName)] internal static partial VcResult vc_stream_start(nint c, in VcStreamDescNative desc, out uint outStreamId); [LibraryImport(LibName)] internal static partial VcResult vc_stream_stop(nint c, uint streamId); [LibraryImport(LibName, StringMarshalling = StringMarshalling.Utf8)] internal static partial VcResult vc_set_input_device(nint c, uint streamId, string? deviceId); [LibraryImport(LibName)] internal static partial VcResult vc_set_input_mode(nint c, VcInputMode mode); [LibraryImport(LibName)] internal static partial VcResult vc_set_vad_threshold(nint c, float threshold); [LibraryImport(LibName)] internal static partial VcResult vc_set_push_to_talk(nint c, int active); [LibraryImport(LibName)] internal static partial VcResult vc_set_self_mute(nint c, int micMuted, int deafened); [LibraryImport(LibName)] internal static partial VcResult vc_set_output_volume(nint c, float gain); [LibraryImport(LibName)] internal static partial VcResult vc_set_input_gain(nint c, float gain); [LibraryImport(LibName)] internal static partial VcResult vc_set_input_noise_reduction(nint c, int enable); [LibraryImport(LibName)] internal static partial VcResult vc_set_remote_stream(nint c, uint userId, uint streamId, float gain, int muted, int noiseReduction); [LibraryImport(LibName)] internal static partial VcResult vc_get_remote_stream(nint c, uint userId, uint streamId, out VcRemoteStreamStateNative outState); [LibraryImport(LibName)] internal static partial VcResult vc_get_stream_audio_config(nint c, uint userId, uint streamId, out VcAudioConfigNative outCfg); // TEST-ONLY in the core (see voicecat.h) — declared for ABI parity; the real app never // calls this (no microphone-bypass path in production UI). [LibraryImport(LibName)] internal static unsafe partial VcResult vc_test_inject_capture(nint c, uint streamId, short* pcm, nuint samples); // ── External PCM feed / tap ────────────────────────────────────────────────────────── [LibraryImport(LibName)] internal static unsafe partial VcResult vc_stream_feed_pcm(nint c, uint streamId, short* pcm, nuint samplesPerChannel, uint channels); // Delegate type for the PCM sink callback — callers convert to a native function // pointer via Marshal.GetFunctionPointerForDelegate (for instance members) or by casting // a static lambda to delegate* unmanaged<> (for [UnmanagedCallersOnly] statics). // Keep the delegate alive for the lifetime of the sink registration. [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void VcPcmSinkCallback(IntPtr user, uint userId, uint streamId, IntPtr pcm, nuint samplesPerChannel, uint channels, uint sampleRate); // cb is a raw function pointer (IntPtr.Zero = disable). Use // Marshal.GetFunctionPointerForDelegate(sinkDelegate) to convert from VcPcmSinkCallback. [LibraryImport(LibName)] internal static partial VcResult vc_set_pcm_sink(nint c, nint cb, IntPtr user); // ── Text ───────────────────────────────────────────────────────────────────────────── [LibraryImport(LibName, StringMarshalling = StringMarshalling.Utf8)] internal static partial VcResult vc_send_text(nint c, VcTextScope scope, uint targetId, string utf8); // ── Device enumeration ─────────────────────────────────────────────────────────────── [LibraryImport(LibName)] internal static partial VcResult vc_list_devices(nint c, VcDeviceKind kind, out VcDeviceListNative outList); [LibraryImport(LibName)] internal static partial void vc_free_device_list(ref VcDeviceListNative list); // ── M4: channel / user / stream snapshot getters ──────────────────────────────────────── [LibraryImport(LibName)] internal static partial VcResult vc_list_channels(nint c, out VcChannelListNative outList); [LibraryImport(LibName)] internal static partial void vc_free_channel_list(ref VcChannelListNative list); [LibraryImport(LibName)] internal static partial VcResult vc_list_users(nint c, out VcUserListNative outList); [LibraryImport(LibName)] internal static partial void vc_free_user_list(ref VcUserListNative list); [LibraryImport(LibName)] internal static partial VcResult vc_list_user_streams(nint c, uint userId, out VcStreamSummaryListNative outList); [LibraryImport(LibName)] internal static partial void vc_free_stream_summary_list(ref VcStreamSummaryListNative list); // ── M4: TOFU server-identity gate ─────────────────────────────────────────────────────── [LibraryImport(LibName)] internal static partial VcResult vc_confirm_server_identity(nint c, int accept); [LibraryImport(LibName)] internal static partial VcResult vc_get_server_identity_display(nint c, nint outBuf, nuint bufCap, out nuint outLen); // ── M5: Moderation & admin ───────────────────────────────────────────────────────────── [LibraryImport(LibName, StringMarshalling = StringMarshalling.Utf8)] internal static partial VcResult vc_kick_user(nint c, uint userId, string? reason); [LibraryImport(LibName, StringMarshalling = StringMarshalling.Utf8)] internal static partial VcResult vc_ban_user(nint c, uint userId, string? reason, ulong expiresUnixMs); [LibraryImport(LibName)] internal static partial VcResult vc_set_permission(nint c, uint userId, in VcPermissionsNative perms); [LibraryImport(LibName)] internal static partial VcResult vc_set_server_mute(nint c, uint userId, int muted, int deafened); [LibraryImport(LibName)] internal static partial VcResult vc_move_user(nint c, uint userId, uint channelId); [LibraryImport(LibName)] internal static partial VcResult vc_create_channel(nint c, in VcChannelInfoNative info); [LibraryImport(LibName)] internal static partial VcResult vc_edit_channel(nint c, in VcChannelInfoNative info); [LibraryImport(LibName)] internal static partial VcResult vc_delete_channel(nint c, uint channelId); [LibraryImport(LibName, StringMarshalling = StringMarshalling.Utf8)] internal static partial VcResult vc_create_account(nint c, string username, string password); [LibraryImport(LibName, StringMarshalling = StringMarshalling.Utf8)] internal static partial VcResult vc_reset_password(nint c, string username, string newPassword); [LibraryImport(LibName, StringMarshalling = StringMarshalling.Utf8)] internal static partial VcResult vc_delete_account(nint c, string username); [LibraryImport(LibName)] internal static partial VcResult vc_list_accounts(nint c); [LibraryImport(LibName)] internal static partial VcResult vc_get_account_list(nint c, out VcAccountListNative outList); [LibraryImport(LibName)] internal static partial void vc_free_account_list(ref VcAccountListNative list); [LibraryImport(LibName)] internal static partial VcResult vc_get_permissions(nint c, out VcPermissionsNative outPerms); }