How to Set Up System Audio Capture with Virtual Audio Devices in Meetily

Meetily captures system audio using platform-specific virtual audio devices—BlackHole on macOS via ScreenCaptureKit and WASAPI loopback on Windows—through Tauri commands implemented in frontend/src-tauri/src/audio/.

Setting up system audio capture with virtual audio devices like BlackHole or WASAPI loopback enables Meetily to record both microphone input and system output simultaneously. The open-source repository Zackriya-Solutions/meetily implements this functionality through a Rust-based Tauri backend that abstracts macOS ScreenCaptureKit and Windows WASAPI APIs into unified recording commands.

Architecture Overview

The audio capture system resides in frontend/src-tauri/src/audio/ and consists of three primary components that handle cross-platform system audio detection and streaming.

  • system_detector.rs: Detects the current operating system and selects the appropriate capture implementation for macOS or Windows.
  • system_audio_stream.rs: Opens platform-specific audio streams using ScreenCaptureKit on macOS or WASAPI loopback mode on Windows.
  • system_audio_commands.rs: Exposes Tauri commands that the frontend invokes to start and stop system audio capture.

macOS: Configure BlackHole for System Audio

macOS requires a virtual audio device to capture system output because the platform does not expose internal audio mixing to applications directly.

Install BlackHole

Install the BlackHole virtual audio driver using Homebrew to create a software audio device that routes system output back into Meetily.

brew install blackhole-2ch

This creates the BlackHole 2ch device that appears in audio settings as a valid input source.

Configure Aggregate Devices

Create an aggregate device in Audio MIDI Setup to combine your microphone and the BlackHole virtual device, ensuring synchronized capture of both sources.

  1. Open Audio MIDI Setup and click the + button.
  2. Select Create Aggregate Device.
  3. Check both Built-in Microphone and BlackHole 2ch.
  4. Set this aggregate device as the default input to capture both microphone and system audio simultaneously.

Grant macOS Permissions

ScreenCaptureKit requires explicit user permissions. The application requests Microphone and Screen Recording permissions on first launch, or you can prompt them programmatically:

// src-tauri/src/utils.rs
open_system_settings("Privacy_Microphone".to_string());
open_system_settings("Privacy_ScreenCapture".to_string());

Navigate to System Settings → Privacy & Security → Screen Recording to manually enable Meetily if permissions were previously denied.

Select Devices in Meetily

Open Settings → Audio in the Meetily interface and configure:

  • System Audio: Select BlackHole 2ch
  • Microphone: Select your physical microphone or the aggregate device

Windows: Configure WASAPI Loopback

Windows provides direct access to the audio mix through WASAPI loopback mode without requiring third-party virtual drivers.

Enable Stereo Mix

Ensure the WASAPI loopback device is visible in your recording devices.

  1. Right-click the speaker icon in the system tray and select Sounds.
  2. Navigate to the Recording tab.
  3. Right-click in the device list and select Show Disabled Devices.
  4. Enable Stereo Mix or the equivalent loopback device.

Select Loopback Device in Meetily

In Settings → Audio, choose the loopback entry (labeled as Loopback (Stereo Mix) or WASAPI Loopback) as the System Audio source, and select your physical microphone as the Mic device.

Technical Implementation

The Rust backend handles platform detection and stream initialization through conditional compilation and platform-specific APIs.

Device Detection Logic

The system_detector.rs file determines the operating system at runtime and routes to the appropriate capture implementation.

Stream Initialization

The system_audio_stream.rs file contains the platform-specific logic to open audio streams. On macOS, it interfaces with ScreenCaptureKit to capture the BlackHole device; on Windows, it utilizes WASAPI loopback mode.

Command Interface

The system_audio_commands.rs file defines the Tauri command interface that the frontend invokes. The start_system_capture function receives the device name and initializes the stream:

// frontend/src-tauri/src/audio/system_audio_commands.rs
#[tauri::command]
pub async fn start_system_capture(
    app: AppHandle,
    device_name: Option<String>,
) -> Result<(), String> {
    let name = device_name.ok_or("System device not supplied")?;
    let stream = system_audio_stream::open(&name).await?;
    // Store the stream handle in the recording manager
    Ok(())
}

Frontend Integration

The TypeScript frontend calls the start_recording command with device parameters:

// src/app/page.tsx
import { invoke } from '@tauri-apps/api/tauri';

export async function beginRecording() {
  await invoke('start_recording', {
    mic_device_name: 'Built-in Microphone',
    system_device_name: 'BlackHole 2ch',  // macOS
    // system_device_name: 'Loopback (Stereo Mix)',  // Windows
    meeting_name: 'Team Standup',
  });
}

The React UI implements device selection using standard form controls:

// src/components/AudioSettings.tsx
<select
  value={systemDevice}
  onChange={e => setSystemDevice(e.target.value)}
>
  {systemDevices.map(dev => (
    <option key={dev.id} value={dev.name}>{dev.name}</option>
  ))}
</select>

Troubleshooting Common Issues

No system audio options appear in settings

  • macOS: BlackHole is not installed. Run brew install blackhole-2ch and restart the application.
  • Windows: Stereo Mix is disabled. Open Sound settings and enable the loopback device in the Recording tab.

Permissions error on macOS

  • Missing Screen Recording permission. Open System Settings → Privacy & Security → Screen Recording and enable Meetily, then restart the application.

Audio latency or echo

  • On macOS, using separate mic and system devices without an aggregate device causes sync issues. Create an Aggregate Device in Audio MIDI Setup combining both sources.

Whisper receives silence

  • The system audio stream failed to open. Verify that the selected system device matches the active output (BlackHole on macOS or Stereo Mix on Windows) and that the device is not muted.

Summary

  • Meetily captures system audio on macOS using BlackHole virtual devices with ScreenCaptureKit, and on Windows using WASAPI loopback mode.
  • The Rust backend in frontend/src-tauri/src/audio/ provides cross-platform abstraction through system_detector.rs, system_audio_stream.rs, and system_audio_commands.rs.
  • macOS requires installing BlackHole via Homebrew and optionally creating aggregate devices, while Windows only requires enabling the Stereo Mix device.
  • Frontend TypeScript code invokes start_recording with specific device names to initiate capture through the Tauri command layer.

Frequently Asked Questions

Do I need a virtual audio cable on Windows?

No. Windows exposes the system audio mix through WASAPI loopback mode, which Meetily accesses directly without requiring third-party virtual cables. Simply enable the Stereo Mix device in your sound settings and select it as the system audio source in Meetily.

Why does Meetily require Screen Recording permission on macOS?

macOS ScreenCaptureKit requires Screen Recording permission to capture audio from the system, even when only capturing audio without video. This is a platform security requirement. The permission is requested when you first attempt to record system audio, and can be managed in System Settings → Privacy & Security → Screen Recording.

Can I use a different virtual audio device instead of BlackHole on macOS?

Yes. While the documentation references BlackHole 2ch as the default, any macOS virtual audio device that presents itself as a standard input source will work with Meetily. Ensure the device appears in Audio MIDI Setup and is selected in the application's audio settings. The system_audio_stream.rs implementation uses standard CoreAudio APIs that support any compatible virtual device.

How do I troubleshoot when the system audio stream fails to initialize?

First, verify that your selected device name exactly matches the device name shown in system settings. Check the application logs for errors from system_audio_commands.rs indicating "System device not supplied" or stream open failures. On macOS, confirm BlackHole is installed with brew list blackhole-2ch. On Windows, ensure the Stereo Mix device is enabled and not set to "Listen to this device" in its properties, as this can create conflicts with WASAPI loopback capture.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →