Audio wasapi
Manipulate Windows audio via WASAPI (learn.microsoft.com/coreaudio): SoundVolumeView + svcl.exe (NirSoft — set default device, per-app volumes, save/load profiles), AudioDeviceCmdlets PowerShell module (Get-AudioDevice, Set-AudioDevice, Get-AudioDevicePlaybackMute), nircmd setdefaultsounddevice. Shared mode (Windows engine resamples all streams to endpoint fixed format) vs Exclusive mode (bit-perfect, audiophile, ~sub-3ms latency with IAudioClient3 + event-driven callbacks). WASAPI then MMDevice then Audio Engine (audiodg.exe) then WDM/KS. ASIO is Steinberg's parallel stack bypassing Windows audio. Virtual audio devices: VB-Audio Virtual Cable, VoiceMeeter/Banana/Potato. Use when the user asks to change Windows default audio device, route app audio, use VoiceMeeter, install VB-Cable, set a specific device from PowerShell, or enable exclusive-mode low-latency output.From its SKILL.md
npx -y skills add damionrashford/media-os --skill audio-wasapiAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 17 stars17 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
14.2 KB, as published. Nobody here has run it
Audio WASAPI
Context: $ARGUMENTS
Quick start
- List all audio endpoints: → Step 1 (
winaudio.py list-devices) - Check current default: → Step 2 (
winaudio.py get-default) - Change default output/input/communications: → Step 3 (
winaudio.py set-default) - Mute / unmute / change volume: → Step 4 (
winaudio.py mute/unmute/volume) - Check if exclusive mode is allowed on a device: → Step 5 (
winaudio.py exclusive-test) - Install VB-Cable virtual cable: → Step 6 (
winaudio.py vbcable-install) - Set up VoiceMeeter virtual mixer: → Step 7 (
winaudio.py voicemeeter-config)
When to use
- User is on Windows and needs terminal / PowerShell-driven audio control.
- User wants to change the default playback/recording/communications device without clicking through Sound settings.
- User wants bit-perfect exclusive-mode output for audiophile playback, or to diagnose why an app can't grab the device in exclusive mode.
- User wants to install a virtual audio cable (VB-Cable, VoiceMeeter) to route system audio into OBS / streaming tools.
- User is debugging a shared-mode vs exclusive-mode mismatch (pops, silence, format negotiation errors).
Not for: macOS (use audio-coreaudio), Linux (use audio-pipewire).
The script exits 2 with a helpful message if run on non-Windows.
Read references/exclusive-vs-shared.md
when the user asks about latency, bit-perfect playback, or
IAudioClient::Initialize errors.
Read references/virtual-cable.md when the user
asks about OBS system-audio capture or VoiceMeeter routing.
Step 1 — List devices
uv run ${CLAUDE_SKILL_DIR}/scripts/winaudio.py list-devices
uv run ${CLAUDE_SKILL_DIR}/scripts/winaudio.py list-devices --kind playback
uv run ${CLAUDE_SKILL_DIR}/scripts/winaudio.py list-devices --kind recording
Calls Get-AudioDevice -List (from the AudioDeviceCmdlets PowerShell module).
If the module isn't installed the PowerShell errors out — install with:
Install-Module -Name AudioDeviceCmdlets -Scope CurrentUser
Output columns: Index, Default, Type, Name, ID.
Step 2 — Get current default
uv run ${CLAUDE_SKILL_DIR}/scripts/winaudio.py get-default
uv run ${CLAUDE_SKILL_DIR}/scripts/winaudio.py get-default --kind recording
uv run ${CLAUDE_SKILL_DIR}/scripts/winaudio.py get-default --kind communications
Windows has three separate default roles:
| Role | Used by |
|---|---|
playback (eMultimedia) | Music/movie apps that request "default" device |
recording (eMultimedia for capture) | Your default mic |
communications (eCommunications) | Zoom / Teams / Discord for voice |
Step 3 — Change the default
Pass the device name exactly as list-devices printed it (quote for spaces):
uv run ${CLAUDE_SKILL_DIR}/scripts/winaudio.py set-default "Speakers (Realtek High Definition Audio)"
uv run ${CLAUDE_SKILL_DIR}/scripts/winaudio.py set-default "Focusrite USB Audio" --kind recording
uv run ${CLAUDE_SKILL_DIR}/scripts/winaudio.py set-default "Shure MV7+" --kind communications
Alternatives not wrapped here (also valid):
nircmd setdefaultsounddevice "<Name>"— older NirCmd, smaller.svcl.exe /SetDefault "<Name>" Playback— NirSoft command-line version of SoundVolumeView. Seereferences/virtual-cable.mdfor fullsvclflags.
Step 4 — Mute / unmute / volume
uv run ${CLAUDE_SKILL_DIR}/scripts/winaudio.py mute "Speakers (Realtek High Definition Audio)"
uv run ${CLAUDE_SKILL_DIR}/scripts/winaudio.py unmute "Speakers (Realtek High Definition Audio)"
uv run ${CLAUDE_SKILL_DIR}/scripts/winaudio.py volume "Speakers (Realtek High Definition Audio)" --level 50
For per-app (not per-device) volume, use NirSoft's SoundVolumeView GUI or
svcl.exe /SetAppDefault <process>.exe Playback. Per-app volume is not
wrapped here because the app-vs-device distinction deserves explicit CLI args.
Step 5 — Probe exclusive-mode permission
Exclusive mode gives an app sole ownership of the device at a negotiated format. Bit-perfect, lowest latency, but blocks every other app.
Each endpoint has a registry flag "Allow applications to take exclusive control of this device". The wrapper reads it:
uv run ${CLAUDE_SKILL_DIR}/scripts/winaudio.py exclusive-test "Speakers (Realtek High Definition Audio)"
Output:
Speakers (Realtek High Definition Audio) -> exclusive mode: allowed|blocked|unknown
allowed = apps can request exclusive mode. blocked = Windows will always
return AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED. The toggle lives in Sound
Control Panel → Properties → Advanced.
To set that flag from script you need elevation + registry write — not
wrapped here deliberately. See
references/exclusive-vs-shared.md for
the manual path and the audio-engine implications.
Step 6 — VB-Audio Virtual Cable
The go-to free virtual audio cable on Windows. Creates two endpoints (CABLE Input = a virtual speaker, CABLE Output = a virtual mic) that are internally wired. Anything played to CABLE Input is captured from CABLE Output.
uv run ${CLAUDE_SKILL_DIR}/scripts/winaudio.py vbcable-install
Prints the download URL and install steps (does not auto-download). The script refuses to fetch the installer itself — VB-Audio is donationware + has paid tiers; auto-install risks violating their T&Cs.
Typical OBS system-audio pattern:
- Install VB-Cable.
- Set Windows default playback = VB-Cable Input. Now all system audio is routed into the cable instead of your speakers.
- Configure OBS Audio Input Capture = VB-Cable Output.
- To still hear system audio, also route VB-Cable Input out to your speakers via VoiceMeeter, or use "Listen to this device" on the CABLE Output properties.
Step 7 — VoiceMeeter
VoiceMeeter is a virtual mixer that ships its own set of virtual WDM devices (VAIO1/2/3) and acts as an ASIO host. Free for the 2-bus version, donationware for Banana (3 physical + 2 virtual) and Potato (5+3).
uv run ${CLAUDE_SKILL_DIR}/scripts/winaudio.py voicemeeter-config
Prints the install URL and basic setup. Configuration is primarily GUI; the
config XML lives under %APPDATA%\VB\Voicemeeter. Scriptable via the
C API (VoicemeeterRemote.dll) or the unofficial Python binding
pip install voicemeeter-api. See
references/virtual-cable.md for a worked
routing example.
Gotchas
- Windows has no first-party CLI to change audio devices. Everything here is third-party (AudioDeviceCmdlets, NirSoft SoundVolumeView/svcl, VB-Audio). Expect install steps.
- AudioDeviceCmdlets isn't signed by Microsoft —
Install-Modulefrom PSGallery is trust-by-repository. Users with strict execution policy may needSet-ExecutionPolicy -Scope CurrentUser RemoteSigned. - Device names are not stable across Windows updates. A Windows update
that reinstalls a Realtek driver renames endpoints from "Speakers (2-
Realtek Audio)" to "Speakers (Realtek Audio)". Script around Name at your
peril — prefer the immutable endpoint
IdGUID fromGet-AudioDevice -List. set-defaultvia AudioDeviceCmdlets changes the Multimedia default; communications is a separate flag. Zoom/Discord pull from the communications endpoint by default, not the multimedia one. To change both, callset-default --kind playbackthenset-default --kind communications.- Exclusive mode is gated per-endpoint, not per-app. The endpoint toggle
blanket-allows or blanket-blocks. An app still has to successfully
negotiate a format (bit depth + rate + channel layout) that the hardware
supports in exclusive mode, or
IAudioClient::InitializereturnsAUDCLNT_E_UNSUPPORTED_FORMAT. - The Windows audio engine (
audiodg.exe) always resamples shared-mode streams to the endpoint's fixed "mix format". If the mix format is 48 kHz 24-bit, a 44.1 kHz 16-bit track gets resampled before it even hits the device. This is why bit-perfect listeners use exclusive mode. - WASAPI's
IAudioClient3::InitializeSharedAudioStreamgives sub-3 ms latency without exclusive mode, but requires Windows 10+ and an endpoint whose audio engine period is small enough (GetSharedModeEnginePeriod). Not every driver / hardware combo supports it. - VB-Cable is donationware + has paid A+B / C+D variants. Installing multiple variants gives you multiple cables — they don't conflict, but keep track of which one you're pointing apps at.
- VoiceMeeter + physical ASIO app conflict. Only one process can hold the ASIO driver. If your DAW has claimed the interface's ASIO driver, VoiceMeeter can't bridge to it simultaneously.
- ASIO4ALL and FlexASIO are different. ASIO4ALL wraps WDM/KS; FlexASIO wraps WASAPI. Both offer an ASIO layer to apps that only speak ASIO, but FlexASIO plays better with modern WASAPI-aware hardware.
- SoundVolumeView and svcl.exe are the same tool — svcl is the pure-CLI version. Both are NirSoft freeware closed-source. No PSGallery equivalent.
- The registry flag for "exclusive mode allowed" lives under
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Render\ <GUID>\Properties\{b3f8fa53-0004-438e-9003-51a46e139bfc},2— that's whatexclusive-testreads. Writing requires SYSTEM / admin + a reboot to take effect for some driver stacks. - After installing / removing a virtual audio driver (VB-Cable, VoiceMeeter), existing apps do NOT see the new device until they reopen their endpoint enumeration. Most restart-to-pickup.
Examples
Example 1 — "Swap default output to my headphones for Spotify"
uv run ${CLAUDE_SKILL_DIR}/scripts/winaudio.py list-devices --kind playback
uv run ${CLAUDE_SKILL_DIR}/scripts/winaudio.py set-default "Headphones (Sony WH-1000XM5 Stereo)"
Example 2 — "Make Zoom use my USB mic without affecting music apps"
uv run ${CLAUDE_SKILL_DIR}/scripts/winaudio.py set-default "Microphone (USB PnP Sound Device)" --kind communications
# Multimedia default stays on your studio interface for music/games.
Example 3 — "Capture system audio into OBS"
uv run ${CLAUDE_SKILL_DIR}/scripts/winaudio.py vbcable-install
# (run the printed installer; reboot)
uv run ${CLAUDE_SKILL_DIR}/scripts/winaudio.py set-default "CABLE Input (VB-Audio Virtual Cable)"
# Point OBS Audio Input Capture at "CABLE Output (VB-Audio Virtual Cable)"
Example 4 — "Why does Foobar2000 say exclusive mode failed?"
uv run ${CLAUDE_SKILL_DIR}/scripts/winaudio.py exclusive-test "Speakers (Realtek High Definition Audio)"
# If output says "blocked", open Sound Control Panel -> the device -> Properties
# -> Advanced tab -> check "Allow applications to take exclusive control".
# If "allowed", the app's requested format is not supported at the hardware
# level — try 44100 Hz 16-bit to match CD, or inspect the endpoint's supported
# formats in that same Advanced tab.
Example 5 — "Script this across many machines"
# Skip the Python wrapper; call AudioDeviceCmdlets directly:
Import-Module AudioDeviceCmdlets
$d = Get-AudioDevice -List | Where-Object { $_.Name -like '*Focusrite*' -and $_.Type -eq 'Playback' }
Set-AudioDevice -Index $d.Index
The wrapper is a convenience layer; any PowerShell script targeting the same cmdlet works fine.
Troubleshooting
Import-Module: The specified module 'AudioDeviceCmdlets' was not loaded
Cause: Module not installed. Fix:
Install-Module -Name AudioDeviceCmdlets -Scope CurrentUser -Force
Get-AudioDevice : Running scripts is disabled on this system
Cause: Execution policy Restricted (default on Windows Server).
Fix:
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
set-default succeeded but the app still plays through old device
Cause: Many apps cache the endpoint at startup and don't listen for
MMDevice default-change notifications. Restart the app.
Fix: Restart the app, or for Chromium-based apps use their internal
"Audio output" setting in site permissions.
Exclusive-mode app gets AUDCLNT_E_UNSUPPORTED_FORMAT
Cause: Requested format isn't natively supported by the driver in exclusive mode. No resampler runs in exclusive mode. Fix: Match exactly what the Properties → Advanced tab lists as a supported format, or switch to shared mode (accepts the engine mix format via resampling).
VB-Cable installed but doesn't appear
Cause: Installer ran but driver signing was blocked; reboot skipped. Fix: Reboot. If still missing, reinstall as Administrator and approve the UAC / driver-signing prompt when it appears.
VoiceMeeter shows "Audio Engine" stopped
Cause: Sample-rate mismatch between physical A1 output and VoiceMeeter's internal engine rate. Fix: Menu → System Settings/Options → set engine rate to match the physical interface's configured sample rate.
Reference docs
- Shared-mode vs exclusive-mode deep dive, latency tradeoffs, IAudioClient3 →
references/exclusive-vs-shared.md. - VB-Cable tiers,
svcl.exeflag reference, VoiceMeeter routing examples →references/virtual-cable.md.