Files
voice-cat/clients/windows/VoiceCat.Interop/Structs.cs
Talon e806b698ec
Some checks failed
Build Linux Binaries / linux/amd64 (push) Has been cancelled
Build Linux Binaries / linux/arm64 (push) Has been cancelled
feat(windows): per-app screen-audio sharing (include/exclude)
Adds "only selected apps" and "all apps except selected" screen-audio
modes to the Windows client, alongside the existing entire-desktop path.

Per-app capture uses WASAPI process loopback (AUDCLNT_ACTIVATIONTYPE_
PROCESS_LOOPBACK) via ProcessLoopbackCapture, mixed by ProcessAudioMixer
and fed to the core through vc_stream_feed_pcm (external_feed=1 so the
core skips its own loopback device).

Init must pass AUDCLNT_STREAMFLAGS_LOOPBACK | EVENTCALLBACK |
AUTOCONVERTPCM; the LOOPBACK flag is what makes the virtual endpoint
deliver rendered audio (without it every buffer is flagged SILENT) and
AUTOCONVERTPCM resamples the app's native format to 48k s16.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 00:19:38 +02:00

186 lines
4.6 KiB
C#

using System.Runtime.InteropServices;
// Native (blittable) struct layouts mirroring voicecat.h field-for-field. These are the raw
// P/Invoke shapes — NativeMethods.cs uses them directly; Marshaling.cs converts them to the
// managed record types in Models.cs. const char* fields stay IntPtr here (LibraryImport's
// StringMarshalling only auto-converts top-level string parameters/returns, not struct
// fields) and must be hand-marshaled — see Marshaling.cs and VoiceCatClient.cs.
namespace VoiceCat.Interop;
[StructLayout(LayoutKind.Sequential)]
internal struct VcEventNative
{
public VcEventType Type;
public VcConnectionState ConnectionState;
public int Result; // vc_result
public uint UserId;
public uint ChannelId;
public uint StreamId;
public VcTextScope TextScope;
public uint U32a;
public IntPtr Text; // owned by core, valid ONLY for the callback's duration
public ulong TimestampUnixMs;
}
[StructLayout(LayoutKind.Sequential)]
internal struct VcConfigNative
{
public IntPtr ClientName;
public IntPtr ClientVersion;
public VcLogLevel LogLevel;
public IntPtr TofuStorePath;
}
[StructLayout(LayoutKind.Sequential)]
internal struct VcCallbacksNative
{
public IntPtr OnEvent; // delegate* unmanaged<IntPtr, VcEventNative*, void>
public IntPtr OnLevel; // delegate* unmanaged<IntPtr, uint, float, void>
public IntPtr User;
}
[StructLayout(LayoutKind.Sequential)]
internal struct VcStreamDescNative
{
public VcStreamKind Kind;
public IntPtr DeviceId; // unused by vc_stream_start today — device selection is a
// separate vc_set_input_device call; always IntPtr.Zero here.
public IntPtr Label;
// Mirrors vc_stream_desc::external_feed. When 1, the core skips its own WASAPI loopback
// and the caller feeds PCM via StreamFeedPcm (per-app capture path on Windows).
public int ExternalFeed;
}
[StructLayout(LayoutKind.Sequential)]
internal struct VcAudioConfigNative
{
public uint Codec;
public uint Mode;
public uint SampleRate;
public uint BitrateBps;
public uint FrameMs;
public uint Application;
public int Fec;
public uint ExpectedPacketLoss;
public int Dtx;
public uint Complexity;
public int Dred;
}
[StructLayout(LayoutKind.Sequential)]
internal struct VcPermissionsNative
{
public int CanCreateTempChannel;
public int CanKick;
public int CanBan;
public int CanMoveUsers;
public int CanAdminAccounts;
public int IsAdmin;
}
[StructLayout(LayoutKind.Sequential)]
internal struct VcChannelInfoNative
{
public uint Id;
public uint ParentId;
public IntPtr Name;
public IntPtr Topic;
public int PasswordProtected;
public IntPtr Password;
public uint MaxUsers;
public uint SortOrder;
public VcAudioConfigNative Audio;
}
[StructLayout(LayoutKind.Sequential)]
internal struct VcDeviceNative
{
public IntPtr Id;
public IntPtr Name;
public int IsDefault;
}
[StructLayout(LayoutKind.Sequential)]
internal struct VcDeviceListNative
{
public IntPtr Items;
public nuint Count;
}
[StructLayout(LayoutKind.Sequential)]
internal struct VcChannelNative
{
public uint Id;
public uint ParentId;
public IntPtr Name;
public IntPtr Topic;
public int PasswordProtected;
public uint MaxUsers;
}
[StructLayout(LayoutKind.Sequential)]
internal struct VcChannelListNative
{
public IntPtr Items;
public nuint Count;
}
[StructLayout(LayoutKind.Sequential)]
internal struct VcUserNative
{
public uint Id;
public IntPtr Nickname;
public int IsGuest;
public uint ChannelId;
public int SelfMicMuted;
public int SelfDeafened;
public int ServerMuted;
public int ServerDeafened;
}
[StructLayout(LayoutKind.Sequential)]
internal struct VcUserListNative
{
public IntPtr Items;
public nuint Count;
}
[StructLayout(LayoutKind.Sequential)]
internal struct VcStreamSummaryNative
{
public uint StreamId;
public VcStreamKind Kind;
public IntPtr Label;
}
[StructLayout(LayoutKind.Sequential)]
internal struct VcStreamSummaryListNative
{
public IntPtr Items;
public nuint Count;
}
[StructLayout(LayoutKind.Sequential)]
internal struct VcRemoteStreamStateNative
{
public float Gain;
public int Muted;
public int NoiseReduction;
}
[StructLayout(LayoutKind.Sequential)]
internal struct VcAccountNative
{
public IntPtr Username;
public int IsAdmin;
public ulong CreatedAtUnixMs;
public ulong LastLoginUnixMs;
}
[StructLayout(LayoutKind.Sequential)]
internal struct VcAccountListNative
{
public IntPtr Items;
public nuint Count;
}