How to Add Support for a New Audio Device Platform in Meetily's Modular Audio System
To add a new audio platform to Meetily, create a platform-specific module in frontend/src-tauri/src/audio/devices/platform/, implement the configure_*_audio function, expose it conditionally in mod.rs, and wire it into the discovery flow.
Meetily's audio architecture uses a modular design that keeps the core application agnostic of operating system specifics. The cpal-based audio subsystem delegates device enumeration to platform-specific modules located in frontend/src-tauri/src/audio/devices/platform/, allowing developers to add support for new audio device platforms without modifying the high-level recording or transcription logic.
Create a Platform-Specific Module
Start by adding a new Rust file under frontend/src-tauri/src/audio/devices/platform/ (e.g., freebsd.rs or solaris.rs). This file must expose a public function that follows the established naming convention and signature pattern.
Implement a function named configure_<platform>_audio that accepts a &cpal::Host and returns anyhow::Result<Vec<AudioDevice>>. Inside this function:
- Enumerate input devices using
host.input_devices() - Enumerate output devices using
host.output_devices() - Construct
AudioDeviceinstances viaAudioDevice::new(name, device_type)whereDeviceTypeis eitherDeviceType::InputorDeviceType::Output - Return the populated vector wrapped in
Ok()
use anyhow::Result;
use cpal::traits::{DeviceTrait, HostTrait};
use crate::audio::devices::configuration::{AudioDevice, DeviceType};
pub fn configure_freebsd_audio(host: &cpal::Host) -> Result<Vec<AudioDevice>> {
let mut devices = Vec::new();
// Input (microphone) devices
for dev in host.input_devices()? {
if let Ok(name) = dev.name() {
devices.push(AudioDevice::new(name, DeviceType::Input));
}
}
// Output (system audio) devices – filter for monitor sources
for dev in host.output_devices()? {
if let Ok(name) = dev.name() {
if name.contains("monitor") {
devices.push(AudioDevice::new(name, DeviceType::Output));
}
}
}
Ok(devices)
}
Implement Optional Device Resolution Helpers
Some platforms require special handling to resolve an AudioDevice into a usable cpal::Device with a compatible stream configuration. If your platform needs this functionality (similar to how Windows uses get_windows_device), expose a second public function.
Name this helper get_<platform>_device and implement device lookup by name, then return a tuple containing the cpal::Device and its SupportedStreamConfig:
pub fn get_freebsd_device(
audio_device: &AudioDevice,
) -> Result<(cpal::Device, cpal::SupportedStreamConfig)> {
let host = cpal::default_host();
match audio_device.device_type {
DeviceType::Input => {
for dev in host.input_devices()? {
if let Ok(name) = dev.name() {
if name == audio_device.name {
return Ok((dev, dev.default_input_config()?));
}
}
}
}
DeviceType::Output => {
for dev in host.output_devices()? {
if let Ok(name) = dev.name() {
if name == audio_device.name {
return Ok((dev, dev.default_output_config()?));
}
}
}
}
}
Err(anyhow::anyhow!("Device not found: {}", audio_device.name))
}
Expose the Module with Conditional Compilation
Edit frontend/src-tauri/src/audio/devices/platform/mod.rs to register your new platform using #[cfg(target_os = "...")] attributes. Add conditional compilation blocks that declare the module and re-export its public functions:
#[cfg(target_os = "freebsd")]
pub mod freebsd;
#[cfg(target_os = "freebsd")]
pub use freebsd::{configure_freebsd_audio, get_freebsd_device};
This pattern mirrors the existing implementations for Windows, macOS, and Linux, ensuring the compiler only includes your code when building for the target platform.
Wire Into the Discovery Flow
The generic device discovery logic in frontend/src-tauri/src/audio/devices/discovery.rs orchestrates platform detection. Update this file to call your new configure_*_audio function when the target OS matches your platform.
If the discovery code uses a match statement or conditional compilation to select the platform function, add your platform to that selection logic. The discovery module acts as the entry point for the rest of the application to obtain the device list.
Update Dependencies and Test
Modify frontend/src-tauri/Cargo.toml if your platform requires additional system libraries or audio backends. Add dependencies under [dependencies] and guard them with platform-specific conditionals:
[target.'cfg(target_os = "freebsd")'.dependencies]
freebsd-audio-sys = "0.1"
Run the existing test suite to verify your implementation. Add platform-specific unit tests using #[cfg(target_os = "freebsd")] attributes to verify that configure_freebsd_audio returns at least one valid AudioDevice when hardware is present.
Reference Existing Implementations
Study the existing platform modules to understand the full range of implementation patterns:
frontend/src-tauri/src/audio/devices/platform/windows.rs: Demonstrates a fully-featured implementation with both enumeration and device resolution helpersfrontend/src-tauri/src/audio/devices/platform/macos.rs: Shows a minimal implementation requiring only the enumeration functionfrontend/src-tauri/src/audio/devices/platform/linux.rs: Illustrates handling of PulseAudio monitor sources and virtual devices
The AudioDevice struct defined in frontend/src-tauri/src/audio/devices/configuration.rs provides the common interface used across all platforms.
Summary
- Create a new file in
frontend/src-tauri/src/audio/devices/platform/implementingconfigure_<platform>_audiowith signaturefn(&cpal::Host) -> Result<Vec<AudioDevice>> - Optional: Implement
get_<platform>_devicefor platforms requiring special stream configuration resolution - Expose the module conditionally in
mod.rsusing#[cfg(target_os = "...")] - Wire the platform into
discovery.rsto participate in device enumeration - Update
Cargo.tomlwith platform-specific dependencies if needed - Test with
#[cfg(target_os = "...")]guarded unit tests
Frequently Asked Questions
What is the minimum function required to support a new platform?
You must implement a public function named configure_<platform>_audio that accepts &cpal::Host and returns anyhow::Result<Vec<AudioDevice>>. This function enumerates available input and output devices and returns them as a vector of AudioDevice structs. According to the Meetily source code, this is the only mandatory component—platforms like macOS require only this function, while Windows additionally implements get_windows_device for stream configuration resolution.
Do I need to modify the core audio recording logic?
No. Meetily's architecture isolates platform-specific code in the audio/devices/platform/ directory. The discovery layer in discovery.rs and the recording pipeline interact only with the generic AudioDevice type from configuration.rs. By following the existing module pattern, you extend platform support without touching the transcription, recording, or UI layers.
How do I handle platforms without native CPAL host support?
If cpal does not provide a default host for your target platform, implement the device enumeration using raw system calls to ALSA, PulseAudio, or the platform's native audio API. Wrap these calls in your configure_<platform>_audio function and convert the results to AudioDevice instances. Ensure you handle errors gracefully using anyhow::Result to maintain compatibility with the rest of the error handling in the Meetily codebase.
Where should I document platform-specific requirements?
Add documentation to the project README or create a dedicated section in the codebase's architecture documentation. Mention any special permissions required (such as microphone access), virtual device naming conventions (like PulseAudio monitor sources), or additional system dependencies needed for compilation. This helps other developers understand the capabilities and limitations of your platform implementation.
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 →