How to Add Support for a New Audio Input Device Platform in Meetily

To add support for a new audio input device platform in Meetily, create a platform-specific Rust module implementing configure_<platform>_audio to enumerate devices, register it in platform/mod.rs using #[cfg(target_os = "...")], and wire it into discovery.rs to expose devices to the UI.

Meetily's audio subsystem uses a modular architecture that isolates OS-specific device enumeration logic from the core audio pipeline. This design allows developers to extend support to new operating systems or embedded hardware platforms without modifying the cross-platform audio processing code.

Understanding the Audio Device Architecture

The audio system splits platform detection into compile-time conditional blocks that route device discovery to the appropriate OS-specific implementation.

The Discovery Flow

In frontend/src-taura/src/audio/devices/discovery.rs, the entry point calls a platform-specific configuration function based on the target OS:

#[cfg(target_os = "windows")] { platform::configure_windows_audio(&host)? }
#[cfg(target_os = "macos")]   { platform::configure_macos_audio(&host)? }
#[cfg(target_os = "linux")]   { platform::configure_linux_audio(&host)? }

Each function returns a Vec<AudioDevice> that populates the device selection dropdown in the frontend UI.

Platform Module Contract

Each platform module under frontend/src-taura/src/audio/devices/platform/ must expose specific public symbols:

  • configure_<platform>_audio(host: &cpal::Host) -> Result<Vec<AudioDevice>> – Enumerates available input devices (microphones) and output devices (system audio monitors).
  • get_<platform>_device(audio_device: &AudioDevice) -> Result<(cpal::Device, cpal::SupportedStreamConfig)> – (Optional, Windows only) Returns a CPAL device with a manually selected stream configuration. Most platforms omit this and use the generic helper in configuration.rs.

These modules are re-exported through frontend/src-taura/src/audio/devices/platform/mod.rs using conditional compilation gates.

Step-by-Step Implementation Guide

Follow these steps to add support for a new platform (example: myos):

Step 1: Create the Platform Module File

Create frontend/src-taura/src/audio/devices/platform/myos.rs. This file will contain all OS-specific device enumeration logic and platform API integrations.

Step 2: Implement Device Enumeration

Implement configure_myos_audio to return a vector of AudioDevice structs. Use the appropriate audio API for your platform (ALSA, CoreAudio, WASAPI, or a custom library):

use anyhow::Result;
use cpal::traits::{DeviceTrait, HostTrait};
use crate::audio::devices::configuration::{AudioDevice, DeviceType};

pub fn configure_myos_audio(host: &cpal::Host) -> Result<Vec<AudioDevice>> {
    let mut devices = Vec::new();

    // Input devices (microphones)
    for device in host.input_devices()? {
        if let Ok(name) = device.name() {
            devices.push(AudioDevice::new(name, DeviceType::Input));
        }
    }

    // Output devices (system audio monitors)
    for device in host.output_devices()? {
        if let Ok(name) = device.name() {
            if name.contains("monitor") {
                devices.push(AudioDevice::new(
                    format!("{} (System Audio)", name),
                    DeviceType::Output,
                ));
            }
        }
    }

    Ok(devices)
}

Step 3: Handle Special Configuration Cases (Optional)

If your platform requires special handling to obtain a SupportedStreamConfig (as Windows does), implement get_myos_device. Most platforms can omit this and rely on the generic lookup in configuration.rs:

pub fn get_myos_device(audio_device: &AudioDevice) -> Result<(cpal::Device, cpal::SupportedStreamConfig)> {
    super::super::configuration::get_device_and_config(audio_device)
}

Step 4: Register the Module

Add conditional compilation entries to frontend/src-taura/src/audio/devices/platform/mod.rs:

#[cfg(target_os = "myos")]
pub mod myos;

#[cfg(target_os = "myos")]
pub use myos::{configure_myos_audio, get_myos_device};

Step 5: Wire Into the Discovery Layer

Add a new conditional block in frontend/src-taura/src/audio/devices/discovery.rs to invoke your platform function:

#[cfg(target_os = "myos")]
{
    platform::configure_myos_audio(&host)?
}

Step 6: Configure Cargo and Build Targets

If the new OS requires a specific Rust target triple or additional system libraries, update frontend/src-taura/Cargo.toml with the necessary dependencies and features. Ensure your CI pipeline includes build steps for the new target architecture.

Step 7: Test the Integration

Run the Tauri application on the target platform and verify that list_audio_devices() returns the expected microphones and system audio sources, and that recording and transcription function correctly end-to-end.

Key Implementation Files

Summary

  • Platform isolation – Meetily separates OS-specific code into dedicated modules under frontend/src-taura/src/audio/devices/platform/.
  • Standardized interface – Implement configure_<platform>_audio to return Vec<AudioDevice> structs that the UI consumes without platform-specific logic.
  • Compile-time selection – Use #[cfg(target_os = "...")] in platform/mod.rs and discovery.rs to include only the relevant platform implementation.
  • Optional configuration helper – Only implement get_<platform>_device if your OS requires special stream configuration negotiation; otherwise rely on configuration.rs.
  • Shared data model – All platforms use the AudioDevice and DeviceType definitions from configuration.rs, ensuring the frontend receives consistent data structures.

Frequently Asked Questions

Do I need to modify the frontend TypeScript code when adding a new platform?

No. The frontend invokes the Tauri command list_audio_devices, which returns a platform-agnostic Vec<AudioDevice> from the Rust backend. As long as your platform module returns properly formatted AudioDevice structs with name and device_type fields, the React frontend will display them without modification.

What is the difference between Input and Output device types?

Input devices (DeviceType::Input) represent physical microphones or audio capture endpoints. Output devices (DeviceType::Output) represent system audio monitor sources (such as "Monitor of Built-in Audio" on Linux) that allow capturing the computer's internal audio output. The Linux implementation in linux.rs demonstrates detecting monitor sources by filtering device names for the substring "monitor".

Can I use platform-specific audio APIs instead of CPAL?

Yes. While existing implementations use CPAL (Cross-Platform Audio Library) for consistency, you can replace CPAL-based enumeration with direct OS API calls (such as raw ALSA on Linux or AudioObject on macOS) as long as you construct AudioDevice structs compatible with the shared model defined in configuration.rs.

Why does Windows require a separate get_windows_device function?

Windows audio drivers often expose multiple stream configurations with varying sample rates and buffer sizes that CPAL cannot automatically negotiate for the transcription pipeline. The get_windows_device function in windows.rs manually selects a compatible SupportedStreamConfig before passing the device to the audio pipeline. Most other platforms work correctly with CPAL's default device selection, allowing them to use the generic fallback.

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 →