feat(windows-host): mic passthrough — auto-wire audio devices + bundle VB-CABLE
The Windows virtual mic worked only with manual Sound-settings fiddling: on a headless host (no real audio output) BOTH the desktop-audio loopback and the virtual mic must run on virtual cables, and on DIFFERENT ones or the loopback re-captures the injected mic (echo). The Steam pair gives only one usable cable (Steam Streaming Speakers loopback is silent — validated), so the mic + loopback collided and echoed, and when the default playback happened to be the mic device the anti-echo guard reported the mic "unavailable". Host now auto-wires the devices at startup (audio/windows/audio_control.rs, ensure_wired_once, hooked from open_audio_capture/open_virtual_mic): default playback = a loopback-capable render that is NOT a cable and NOT the dead Steam Speakers (real output > Steam Streaming Microphone); default recording = the mic capture (VB-Cable "CABLE Output" preferred). Uses a hand-rolled IPolicyConfig vtable (the only way to set a default endpoint; not in windows/wasapi crates). Opt out with PUNKTFUNK_KEEP_DEFAULT. wasapi_mic candidates now prefer "cable input". Validated live: from a deliberately-wrong start (playback=CABLE Input) the host corrected both default endpoints at the OS level. A Windows audio endpoint can only be created by a kernel-mode driver (no UMDF path — ACX is KMDF-only), so we cannot self-sign our own like the UMDF gamepad/ display drivers. Instead the installer bundles + silently installs the official base VB-CABLE (VB-Audio donationware, vendor-signed → loads with no test-signing, redistributed under VB-Audio's bundling grant): install-vbcable.ps1 (seed the VB-Audio cert into TrustedPublisher, run -i -h) + an installaudiocable task, gated on -VbCableDir/$env:VBCABLE_DIR (the package binary is not in the repo). Attribution in packaging/windows/licenses/VB-CABLE-NOTICE.txt. .iss compiles with the path enabled. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -4,10 +4,12 @@
|
||||
//! **capture** endpoint then surfaces as a microphone that host apps can record from.
|
||||
//!
|
||||
//! Target device, by friendly-name substring (first match wins; override with `PUNKTFUNK_MIC_DEVICE`):
|
||||
//! "Steam Streaming Microphone" (ships with Steam Remote Play — exactly this purpose), VB-Audio
|
||||
//! "CABLE Input", VoiceMeeter, or anything with "virtual" in the name. If none is present we
|
||||
//! auto-install the Steam Streaming audio pair (see [`install_steam_audio_pair`]); failing that we
|
||||
//! return an error with install guidance and the host runs without mic passthrough.
|
||||
//! VB-Audio "CABLE Input" (bundled by the installer — the preferred, dedicated mic target), the
|
||||
//! "Steam Streaming Microphone", VoiceMeeter, or anything with "virtual" in the name.
|
||||
//! [`super::audio_control`] sets the default playback to a DIFFERENT loopback-capable device so the
|
||||
//! chosen mic is never the endpoint the loopback captures. If no candidate is present we auto-install
|
||||
//! the Steam Streaming audio pair (see [`install_steam_audio_pair`]); failing that we return an error
|
||||
//! with install guidance and the host runs without mic passthrough.
|
||||
//!
|
||||
//! **Anti-echo guard (the whole point of this being non-trivial).** The desktop-audio plane
|
||||
//! ([`super::wasapi_cap`]) loopback-captures the **default render endpoint**. WASAPI loopback
|
||||
@@ -45,8 +47,8 @@ const MAX_QUEUE_BYTES: usize = (SAMPLE_RATE as usize * 80 / 1000) * BLOCK_ALIGN;
|
||||
/// Render-endpoint friendly-name substrings (lowercased) we can write into so the device's capture
|
||||
/// endpoint becomes a host mic. Ordered by preference.
|
||||
const CANDIDATES: &[&str] = &[
|
||||
"cable input", // VB-Audio Virtual Cable — bundled by the installer; the preferred dedicated mic target
|
||||
"steam streaming microphone",
|
||||
"cable input",
|
||||
"voicemeeter input",
|
||||
"voicemeeter aux input",
|
||||
"virtual",
|
||||
|
||||
Reference in New Issue
Block a user