Meetily Platform-Specific Audio Device Implementations: Windows, macOS, and Linux Code Breakdown

Meetily implements distinct audio device handlers for Windows, macOS, and Linux in frontend/src-tauri/src/audio/devices/platform/, using WASAPI, ScreenCaptureKit + CoreAudio, and ALSA/PulseAudio respectively.

The meetily open-source meeting assistant handles audio device enumeration and configuration through a carefully structured platform abstraction layer. Located at frontend/src-tauri/src/audio/devices/platform/, this module isolates operating-system-specific code behind a unified Rust interface, enabling consistent cross-platform audio capture while leveraging native APIs for optimal performance.

Platform-Specific Implementation Files

Each operating system receives its own dedicated implementation file with targeted responsibilities:

Windows: WASAPI Integration

The windows.rs file implements audio device handling through WASAPI via the cpal crate. Key capabilities include:

  • Enumerating input, output, and loopback devices
  • Falling back to the default host if WASAPI enumeration fails
  • Providing get_windows_device() to resolve device names to cpal::Device instances with compatible stream configurations

The Windows implementation prioritizes F32 stereo formats, then any F32 format, then the first available configuration.

File location: frontend/src-tauri/src/audio/devices/platform/windows.rs

macOS: ScreenCaptureKit and CoreAudio

The macos.rs file combines ScreenCaptureKit with CoreAudio (accessed through cpal):

  • Lists input devices using the default host
  • Filters built-in speakers from output devices while preserving Bluetooth peripherals
  • Uses ScreenCaptureKit directly for system-audio capture, bypassing cpal for output streams

This dual-API approach addresses macOS-specific requirements for system audio access, which requires entitlements and specialized capture APIs unavailable through standard audio frameworks.

File location: frontend/src-tauri/src/audio/devices/platform/macos.rs

Linux: ALSA and PulseAudio Support

The linux.rs file implements ALSA and PulseAudio support via cpal:

  • Enumerates regular input devices through ALSA
  • Detects PulseAudio monitor sources to expose system audio as output devices
  • Names detected system audio devices as "<source> (System Audio)" for clear UI presentation

This implementation ensures compatibility with both legacy ALSA configurations and modern PulseAudio-based distributions.

File location: frontend/src-tauri/src/audio/devices/platform/linux.rs

Module Re-Export Pattern

The mod.rs file provides conditional compilation to expose the correct platform implementation:

// frontend/src-tauri/src/audio/devices/platform/mod.rs
#[cfg(target_os = "windows")]
pub use windows::{configure_windows_audio, get_windows_device};

#[cfg(target_os = "macos")]
pub use macos::configure_macos_audio;

#[cfg(target_os = "linux")]
pub use linux::configure_linux_audio;

This pattern allows higher-level code to import platform functions without knowing the target OS at the call site.

Integration with Device Discovery

Platform functions are invoked by audio/devices/discovery.rs to populate the AudioDevice struct list. The rest of the codebase treats devices uniformly through this struct:

  • AudioDevice { name, device_type } — defined in audio/devices/configuration.rs
  • Platform modules handle all native enumeration and stream configuration details

Practical Code Examples

Enumerating Devices in Rust

use crate::audio::devices::platform::*;

pub async fn list_audio_devices(host: &cpal::Host) -> anyhow::Result<Vec<AudioDevice>> {
    #[cfg(target_os = "windows")]
    let devices = configure_windows_audio(host)?;

    #[cfg(target_os = "macos")]
    let devices = configure_macos_audio(host)?;

    #[cfg(target_os = "linux")]
    let devices = configure_linux_audio(host)?;

    Ok(devices)
}

Resolving a Device to Stream (Windows)

// Assume `selected` is an AudioDevice chosen by the user
let (device, config) = get_windows_device(&selected)?;
// Now `device` and `config` can be passed to cpal's stream builder

Frontend TypeScript Integration

import { invoke } from '@tauri-apps/api/tauri';

async function fetchAudioDevices() {
  const devices = await invoke<AudioDevice[]>('list_audio_devices');
  // Populate UI selector with device.name and device.device_type
}

Key Architectural Files

Purpose Path
Windows implementation frontend/src-tauri/src/audio/devices/platform/windows.rs
macOS implementation frontend/src-tauri/src/audio/devices/platform/macos.rs
Linux implementation frontend/src-tauri/src/audio/devices/platform/linux.rs
Module re-export frontend/src-tauri/src/audio/devices/platform/mod.rs
Device configuration struct frontend/src-tauri/src/audio/devices/configuration.rs
Discovery entry point frontend/src-tauri/src/audio/devices/discovery.rs

Summary

  • Windows uses WASAPI for full device enumeration including loopback capture, with get_windows_device() providing detailed stream configuration
  • macOS combines CoreAudio for input with ScreenCaptureKit for system audio, filtering built-in speakers from outputs
  • Linux detects PulseAudio monitor sources to expose system audio alongside ALSA input devices
  • All three implementations expose consistent functions through conditional compilation in mod.rs, enabling uniform treatment in the discovery layer
  • The abstraction allows the frontend to receive a simple AudioDevice list while native APIs handle platform-specific requirements

Frequently Asked Questions

How does Meetily handle system audio capture differently across platforms?

Windows captures system audio through WASAPI loopback devices, which appear as standard output devices in enumeration. MacOS requires ScreenCaptureKit for system audio, as CoreAudio does not provide native loopback support—this bypasses cpal entirely for output streams. Linux uses PulseAudio monitor sources, exposing them as named output devices through the standard enumeration flow.

Why does the macOS implementation filter built-in speakers?

The macos.rs implementation specifically excludes built-in speakers from output device lists while preserving Bluetooth peripherals. This design choice prioritizes common meeting workflows where users typically want to capture audio from headphones or external speakers rather than internal laptop speakers, reducing accidental misconfiguration.

What fallback behavior exists if WASAPI fails on Windows?

Per the source in windows.rs, the implementation falls back to the default cpal host if WASAPI enumeration fails. This ensures basic functionality even on systems with problematic audio drivers or restricted environments, though advanced features like loopback capture may be unavailable in fallback mode.

How are platform differences hidden from the frontend TypeScript code?

The frontend invokes a single Tauri command (list_audio_devices) with no platform parameters. The Rust backend resolves the appropriate implementation at compile time through #[cfg(target_os = ...)] attributes in mod.rs, then returns a uniform Vec<AudioDevice> regardless of the underlying OS-specific code path executed.

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 →