# How to Add Support for a New Audio Device Platform in Meetily's Modular Audio System

> Learn to add a new audio device platform to Meetily's modular audio system. Implement platform-specific modules and integrate them into the discovery flow for enhanced audio support.

- Repository: [Zackriya Solutions/meetily](https://github.com/Zackriya-Solutions/meetily)
- Tags: how-to-guide
- Published: 2026-07-12

---

**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`](https://github.com/Zackriya-Solutions/meetily/blob/main/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`](https://github.com/Zackriya-Solutions/meetily/blob/main/freebsd.rs) or [`solaris.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/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 `AudioDevice` instances via `AudioDevice::new(name, device_type)` where `DeviceType` is either `DeviceType::Input` or `DeviceType::Output`
- Return the populated vector wrapped in `Ok()`

```rust
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`:

```rust
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`](https://github.com/Zackriya-Solutions/meetily/blob/main/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:

```rust
#[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`](https://github.com/Zackriya-Solutions/meetily/blob/main/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`](https://github.com/Zackriya-Solutions/meetily/blob/main/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:

```toml
[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`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/audio/devices/platform/windows.rs)**: Demonstrates a fully-featured implementation with both enumeration and device resolution helpers
- **[`frontend/src-tauri/src/audio/devices/platform/macos.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/audio/devices/platform/macos.rs)**: Shows a minimal implementation requiring only the enumeration function
- **[`frontend/src-tauri/src/audio/devices/platform/linux.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/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`](https://github.com/Zackriya-Solutions/meetily/blob/main/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/` implementing `configure_<platform>_audio` with signature `fn(&cpal::Host) -> Result<Vec<AudioDevice>>`
- **Optional**: Implement `get_<platform>_device` for platforms requiring special stream configuration resolution
- **Expose** the module conditionally in [`mod.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/mod.rs) using `#[cfg(target_os = "...")]`
- **Wire** the platform into [`discovery.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/discovery.rs) to participate in device enumeration
- **Update** [`Cargo.toml`](https://github.com/Zackriya-Solutions/meetily/blob/main/Cargo.toml) with 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`](https://github.com/Zackriya-Solutions/meetily/blob/main/discovery.rs) and the recording pipeline interact only with the generic `AudioDevice` type from [`configuration.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/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.