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>
This commit is contained in:
@@ -186,6 +186,26 @@ public sealed class VoiceCatClient : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Like <see cref="StartStream"/> but sets <c>external_feed = 1</c> so the core skips its
|
||||
/// own WASAPI loopback. The caller is responsible for feeding PCM via
|
||||
/// <see cref="StreamFeedPcm"/>. Used by the Windows per-app capture path.
|
||||
/// </summary>
|
||||
public (VcResult Result, uint StreamId) StartStreamExternalFeed(VcStreamKind kind, string label)
|
||||
{
|
||||
nint labelPtr = Marshal.StringToCoTaskMemUTF8(label);
|
||||
try
|
||||
{
|
||||
var desc = new VcStreamDescNative { Kind = kind, DeviceId = 0, Label = labelPtr, ExternalFeed = 1 };
|
||||
var r = NativeMethods.vc_stream_start(_handle.DangerousGetHandle(), in desc, out uint streamId);
|
||||
return (r, streamId);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeCoTaskMem(labelPtr);
|
||||
}
|
||||
}
|
||||
|
||||
public VcResult StopStream(uint streamId) =>
|
||||
NativeMethods.vc_stream_stop(_handle.DangerousGetHandle(), streamId);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user