How to Add Support for a New Audio Device Platform in Meetily
To add support for a new audio device platform in Meetily, implement two standard Rust functions—configure_<platform>_audio and get_<platform>_device—in a platform-specific module, register them behind #[cfg(target_os)] guards in the platform gate, and the existing discovery logic will automatically enumerate devices for your target OS.
Meetily's audio subsystem is built around a portable, platform-agnostic core that delegates OS-specific device enumeration to modular backend implementations. Whether you are targeting a new Linux distribution, a BSD variant, or an embedded audio stack, you can add support for a new audio device platform in Meetily by placing your implementation in frontend/src-tauri/src/audio/devices/platform/ and exposing two public symbols that the generic discovery layer consumes.
Architecture Overview
Meetily isolates platform-specific code in frontend/src-tauri/src/audio/devices/platform/, where each operating system lives in its own source file. Every platform module exposes two public symbols:
configure_<platform>_audio(&cpal::Host) -> Result<Vec<AudioDevice>>– Enumerates available input and output devices that Meetily can present to the user.get_<platform>_device(&AudioDevice) -> Result<(cpal::Device, cpal::SupportedStreamConfig)>]– Returns a concrete CPAL device and a usable stream configuration for recording.
These functions are re-exported from frontend/src-tauri/src/audio/devices/platform/mod.rs via #[cfg(target_os = "...")] guards. The generic discovery logic in frontend/src-tauri/src/audio/devices/discovery.rs calls the appropriate implementation based on the compile-time target triple, ensuring only relevant code is linked into the final binary.
Step 1: Create the Platform Implementation File
Create a new Rust source file at frontend/src-tauri/src/audio/devices/platform/<your_os>.rs. You must implement at least the device enumeration function, and optionally the device retrieval function if your platform requires special handling (e.g., loop-back modes or specific audio APIs).
Implement Device Enumeration
Define configure_<your_os>_audio to return a vector of AudioDevice structs using CPAL's HostTrait and DeviceTrait. The following skeleton mirrors the pattern used in the Windows (windows.rs) and macOS (macos.rs) implementations:
use anyhow::Result;
use cpal::traits::{DeviceTrait, HostTrait};
use crate::audio::devices::configuration::{AudioDevice, DeviceType};
/// Configure MyOS audio devices using the native API (e.g., PipeWire, ALSA)
pub fn configure_myos_audio(host: &cpal::Host) -> Result<Vec<AudioDevice>> {
let mut devices = Vec::new();
// Enumerate input devices (microphones)
for device in host.input_devices()? {
if let Ok(name) = device.name() {
devices.push(AudioDevice::new(name, DeviceType::Input));
}
}
// Enumerate output devices (system audio)
for device in host.output_devices()? {
if let Ok(name) = device.name() {
devices.push(AudioDevice::new(name, DeviceType::Output));
}
}
Ok(devices)
}
Implement Device Retrieval
Implement get_<your_os>_device to resolve an AudioDevice back to a concrete CPAL device and its default configuration:
/// Retrieve a specific MyOS device and a compatible stream config.
pub fn get_myos_device(
audio_device: &AudioDevice
) -> Result<(cpal::Device, cpal::SupportedStreamConfig)> {
let host = cpal::default_host();
let target_name = &audio_device.name;
match audio_device.device_type {
DeviceType::Input => {
for dev in host.input_devices()? {
if let Ok(name) = dev.name() {
if name == *target_name {
return Ok((dev, dev.default_input_config()?));
}
}
}
}
DeviceType::Output => {
for dev in host.output_devices()? {
if let Ok(name) = dev.name() {
if name == *target_name {
return Ok((dev, dev.default_output_config()?));
}
}
}
}
}
Err(anyhow::anyhow!("Device not found: {}", target_name))
}
Step 2: Register the Platform Module
Edit frontend/src-tauri/src/audio/devices/platform/mod.rs to conditionally expose your new symbols. Use #[cfg(target_os = "...")] attributes to ensure the code is only compiled for the relevant target, following the existing pattern for Windows, macOS, and Linux:
#[cfg(target_os = "myos")]
pub mod myos;
#[cfg(target_os = "myos")]
pub use myos::configure_myos_audio;
#[cfg(target_os = "myos")]
pub use myos::get_myos_device;
This registration step is critical: it allows the rest of the codebase to call platform::configure_myos_audio without knowing the specific target OS at the call site.
Step 3: Verify Integration with the Discovery Flow
The list_audio_devices function in frontend/src-tauri/src/audio/devices/discovery.rs automatically invokes your platform's configuration function based on compile-time target detection. No further code changes are required; once your module is compiled, list_audio_devices will include the devices returned by your implementation in the results returned to the frontend.
From the TypeScript UI layer, you consume the new platform support exactly like existing platforms:
// Automatically uses the platform-specific configure_* function
const devices: AudioDevice[] = await invoke('list_audio_devices');
// Start recording with discovered devices
await invoke('start_recording', {
mic_device_name: devices.find(d => d.type === 'input')?.name,
system_device_name: devices.find(d => d.type === 'output')?.name,
meeting_name: 'Demo Meeting',
});
Optional: Handle Platform-Specific Permissions
If your platform requires runtime permissions (e.g., microphone access or screen recording), extend trigger_audio_permission in discovery.rs or add a platform-specific helper. Invoke this from the UI layer before calling list_audio_devices to ensure the user has granted necessary access, mirroring the macOS permission flow pattern found in the source code.
Summary
- Create a new Rust file in
frontend/src-tauri/src/audio/devices/platform/implementingconfigure_<platform>_audiofor device enumeration andget_<platform>_devicefor stream configuration. - Register the module in
platform/mod.rsusing#[cfg(target_os = "...")]guards to enable conditional compilation. - Verify that
list_audio_devicesindiscovery.rsautomatically includes your platform's devices without additional changes to the discovery logic. - Leverage CPAL's
HostTraitandDeviceTraitabstractions to maintain portability across audio backends. - Handle platform-specific permissions separately from device enumeration to keep the modular architecture clean.
Frequently Asked Questions
What functions must I implement to add a new audio platform in Meetily?
You must implement configure_<platform>_audio to return a Vec<AudioDevice> containing available input and output devices, and get_<platform>_device to return a tuple of (cpal::Device, cpal::SupportedStreamConfig) for a given AudioDevice. These signatures integrate directly with the existing discovery pipeline in discovery.rs.
Where does Meetily store platform-specific audio device code?
Platform-specific implementations reside in frontend/src-tauri/src/audio/devices/platform/, with reference implementations for Windows (windows.rs), macOS (macos.rs), and Linux (linux.rs). The module gate at platform/mod.rs re-exports these implementations using #[cfg(target_os)] conditional compilation.
How does Meetily automatically detect my new platform implementation?
The list_audio_devices function in frontend/src-tauri/src/audio/devices/discovery.rs uses compile-time target detection to call the appropriate configure_<platform>_audio function. When you register your module in platform/mod.rs with the correct #[cfg(target_os = "...")] attribute, the Rust compiler includes your code only for that target, and the discovery logic automatically invokes it.
Do I need to modify the UI code when adding a new audio platform?
No. The TypeScript frontend calls generic commands like list_audio_devices and start_recording through Tauri's invoke API. Because the Rust backend abstracts platform differences behind the AudioDevice and DeviceType structures, the UI remains agnostic to the underlying operating system or audio API.
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 →