
Company News
Socket Joins New OpenJS Program to Fund Node.js Security Work
Socket is joining the OpenJS Security Stewardship Program to fund Node.js vulnerability research, maintainer remediation, and security releases.
@subcueai/tauri-plugin-system-audio
Advanced tools
Tauri 2 JS bindings for dual audio capture — microphone + system audio (WASAPI loopback) with WebRTC AEC3.
Capture what your app hears and what the computer plays — with echo cancellation — in Tauri 2.
Microphone + system audio (WASAPI loopback) dual capture for Windows, with WebRTC AEC3 echo cancellation, anti-aliased resampling to 16 kHz mono PCM, and 10 Hz level metering. Extracted from the production desktop app of SubcueAI, where it feeds live dual-stream speech-to-text during video calls.
┌─────────────┐ ┌─────────────┐ ┌───────────┐
│ mic capture │───▶│ resampler │───▶│ APM │──▶ Pcm { source: "mic" }
└─────────────┘ │ to 16k f32 │ │ near-end │
└─────────────┘ └───────────┘
┌─────────────┐ ┌─────────────┐ ┌───────────┐
│ loopback* │───▶│ resampler │───▶│ APM │──▶ Pcm { source: "loopback" }
└─────────────┘ │ to 16k f32 │ │ reverse │
*Windows only └─────────────┘ └───────────┘
Capturing system audio in a Tauri app is a recurring pain point: browsers can't do it, getDisplayMedia audio is unreliable, and most examples stop at "open a mic stream". This plugin packages the hard parts:
AUDCLNT_STREAMFLAGS_LOOPBACK), so you hear Zoom/Meet/Teams/whatever the machine plays. No virtual audio driver, no Stereo Mix.Mixer is included if you want one combined stream.Platform behavior: Windows = full pipeline. macOS/Linux = mic-only (loopback and APM compile to stubs; on macOS, Apple's VPIO already does AEC at the OS level, and system-audio capture there is ScreenCaptureKit's job — out of scope for this plugin).
Rust side (src-tauri/Cargo.toml):
cargo add tauri-plugin-system-audio
[dependencies]
tauri-plugin-system-audio = "0.1"
Register the plugin:
fn main() {
tauri::Builder::default()
.plugin(tauri_plugin_system_audio::init())
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
Allow the commands in your capability file (src-tauri/capabilities/default.json):
{ "permissions": ["system-audio:default"] }
AEC needs webrtc-apm/webrtc-apm.dll (a C-ABI build of WebRTC's AudioProcessing module, BSD-3 licensed — ABI reference). Copy it into src-tauri/resources/ and bundle it:
// tauri.conf.json
{ "bundle": { "resources": ["resources/webrtc-apm.dll"] } }
The plugin resolves the bundled dll automatically (dev and build). Missing dll degrades gracefully: capture keeps working, just without echo cancellation — a warning is logged.
npm i @subcueai/tauri-plugin-system-audio
import { start, stop, decodePcm } from '@subcueai/tauri-plugin-system-audio';
await start((event) => {
switch (event.kind) {
case 'pcm': {
const samples = decodePcm(event.samples_base64); // Int16Array, 16 kHz mono, 20 ms
if (event.source === 'mic') sttLocal.send(samples);
else sttRemote.send(samples); // system audio: the remote party
break;
}
case 'level': // 10 Hz meter: event.mic_rms / event.loopback_rms (0..1)
break;
case 'failure': // category: 'permission' | 'device' | 'io' | 'lifecycle'
break;
}
});
// later
await stop();
Options (all optional): start(onEvent, { loopback: true, processing: true, levelOnly: false })
loopback: false — mic only.processing: false — skip WebRTC APM entirely.levelOnly: true — no PCM at all, just 10 Hz levels (~0% upload, <1% CPU) for an idle "mic check" meter.Pre-flight the mic permission for your Settings UI:
const status = await permissionStatus(); // 'allowed' | 'denied' | 'unknown'
| Event | Payload | Notes |
|---|---|---|
pcm | seq, source (mic|loopback), sample_rate (16000), channels (1), samples_base64 | 20 ms frames; i16 LE, base64 |
level | mic_rms, loopback_rms (0..1) | ≤10 Hz, deduped below 0.005 delta |
failure | category, message | Worker exited; permission → deep-link OS Settings |
Why 16 kHz mono? It's the native rate of speech models and WebRTC APM's processing band. Capturing at device rate and downsampling once (with a proper anti-alias FIR) beats letting each downstream consumer resample.
Why base64 over a Tauri Channel instead of raw buffers? One ordered channel carries tagged heterogeneous events (pcm/level/failure) with backpressure, ~160 KB/s per stream — trivial for the IPC. Decode cost is one atob per 20 ms.
Can it capture a specific app's audio only? No — WASAPI loopback captures the default render endpoint mix. Per-process capture needs the Windows 10 2004+ AUDIOCLIENT_PROCESS_LOOPBACK path, which cpal doesn't expose yet.
Does AEC work if the user wears headphones? There's simply no echo to cancel — AEC3 idles. Loopback capture still works and is unaffected.
macOS system audio? Use ScreenCaptureKit from native code (that's what SubcueAI's own macOS app does); this plugin intentionally stays cpal-only.
This is the audio pipeline that ships in SubcueAI's Windows desktop app (Tauri 2 + React), extracted with its production comments and tests intact.
MIT © 2026 Subcue AI LLC. webrtc-apm.dll is built from BSD-3-Clause WebRTC — see THIRD-PARTY.md.
FAQs
Tauri 2 JS bindings for dual audio capture — microphone + system audio (WASAPI loopback) with WebRTC AEC3.
The npm package @subcueai/tauri-plugin-system-audio receives a total of 2 weekly downloads. As such, @subcueai/tauri-plugin-system-audio popularity was classified as not popular.
We found that @subcueai/tauri-plugin-system-audio demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Company News
Socket is joining the OpenJS Security Stewardship Program to fund Node.js vulnerability research, maintainer remediation, and security releases.

Security News
Two compromised GitHub Actions were re-enabled with malicious tags intact, exposing thousands of downstream repositories to Mini Shai-Hulud.

Research
/Security News
A malicious Firefox extension fetches its payload after installation to evade detection, steal Google session cookies, and automate account takeover.