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 inconfiguration.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
frontend/src-taura/src/audio/devices/discovery.rs– Central dispatcher that calls platform-specific enumeration functions based on compile-time OS detection.frontend/src-taura/src/audio/devices/platform/mod.rs– Re-exports platform modules using#[cfg(target_os = "...")]gates to ensure only relevant code is compiled.frontend/src-taura/src/audio/devices/platform/windows.rs– Reference implementation showing complex device enumeration and manual stream configuration selection.frontend/src-taura/src/audio/devices/configuration.rs– Defines the sharedAudioDevicestruct andDeviceTypeenum used across all platforms, plus the genericget_device_and_configfallback.
Summary
- Platform isolation – Meetily separates OS-specific code into dedicated modules under
frontend/src-taura/src/audio/devices/platform/. - Standardized interface – Implement
configure_<platform>_audioto returnVec<AudioDevice>structs that the UI consumes without platform-specific logic. - Compile-time selection – Use
#[cfg(target_os = "...")]inplatform/mod.rsanddiscovery.rsto include only the relevant platform implementation. - Optional configuration helper – Only implement
get_<platform>_deviceif your OS requires special stream configuration negotiation; otherwise rely onconfiguration.rs. - Shared data model – All platforms use the
AudioDeviceandDeviceTypedefinitions fromconfiguration.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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →