# How Meetily Handles Audio Permissions and Device Access Across Platforms

> Learn how Meetily manages audio permissions and device access across macOS Windows and Linux using Rust and Tauri for robust security and seamless integration.

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

---

**Meetily implements a platform-aware Rust abstraction layer that explicitly checks macOS screen-recording permissions while delegating microphone grants to OS-level prompts on Windows and Linux, exposing these controls via Tauri commands for seamless frontend integration.**

Meetily, an open-source meeting assistant built by Zackriya-Solutions, manages cross-platform audio capture through a centralized Rust backend that abstracts permission complexity away from the UI. The implementation in `src-tauri/src/audio/` provides unified device discovery while respecting platform-specific privacy requirements for microphone and system audio access.

## Platform-Specific Permission Workflows

Meetily’s permission strategy varies by operating system, with macOS requiring explicit user consent for system audio capture while Windows and Linux rely on automatic or policy-based grants.

### macOS Screen Recording and Microphone Requirements

On macOS, Meetily must request two distinct permissions:

- **Microphone access** – Handled via standard AVCaptureDevice APIs when the app first attempts to open an input device
- **Screen recording permission** – Required specifically for system audio capture through ScreenCaptureKit, implemented in [`src-tauri/src/audio/permissions.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/src-tauri/src/audio/permissions.rs)

The core permission functions reside in [`permissions.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/permissions.rs):

```rust
// Checking and requesting screen-recording permission (macOS only)
pub fn ensure_screen_recording_permission() -> bool {
    if !check_screen_recording_permission() {
        if let Err(e) = request_screen_recording_permission() {
            log::error!("Failed to request screen-recording permission: {}", e);
            return false;
        }
    }
    true
}

```

The `trigger_system_audio_permission()` function specifically handles the ScreenCaptureKit authorization flow. If the user denies access, the error propagates to `audio::core-old.rs` where it is logged as “Permission denied for audio device …”, allowing the UI to surface appropriate guidance.

### Windows and Linux OS-Level Grants

Windows and Linux implementations require no explicit permission code in the Meetily codebase:

- **Windows** – Microphone access is granted automatically by the OS when the Tauri app requests it, with the system prompt appearing on first use. System audio capture utilizes WASAPI loop-back, which does not require additional user grants.
- **Linux** – Microphone access is governed by PulseAudio or ALSA policies. The `trigger_system_audio_permission()` function logs “System audio permissions not required on this platform” and returns immediately, as the underlying audio subsystem handles authorization.

## Device Discovery Architecture

All audio device enumeration flows through a centralized discovery layer that delegates to platform-specific implementations.

### Platform Abstraction in [`discovery.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/discovery.rs)

The [`src-tauri/src/audio/devices/discovery.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/src-tauri/src/audio/devices/discovery.rs) module serves as the entry point for enumerating input and output devices. It delegates to specialized modules located in `src-tauri/src/audio/devices/platform/`:

- [`macos.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/macos.rs) – Core Audio implementations
- [`windows.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/windows.rs) – WASAPI device enumeration  
- [`linux.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/linux.rs) – PulseAudio/ALSA device listing

### Microphone and System Audio Capture

Device-specific access is split between two primary modules:

**Microphone input** – [`src-tauri/src/audio/devices/microphone.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/src-tauri/src/audio/devices/microphone.rs) exposes `default_input_device()` and `list_input_devices()`. The selected device name travels from the frontend through `invoke('start_recording', { mic_device_name, … })` to the Rust command handler in `audio::recording_commands.rs`.

**System audio** – [`src-tauri/src/audio/devices/speakers.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/src-tauri/src/audio/devices/speakers.rs) manages output device enumeration, while [`src-tauri/src/audio/capture/system.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/src-tauri/src/audio/capture/system.rs) handles the actual capture. On macOS, this delegates to [`capture/core_audio.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/capture/core_audio.rs) using ScreenCaptureKit; on Windows and Linux, it utilizes platform-specific loop-back mechanisms that require no explicit permissions.

All device structs are wrapped in `Arc<RwLock<…>>` and shared through `audio::recording_state.rs`, enabling thread-safe concurrent access from the audio pipeline, VAD (Voice Activity Detection), and Whisper transcription workers.

## Frontend Integration via Tauri Commands

The permission helpers are registered as async Tauri commands in [`src-tauri/src/lib.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/src-tauri/src/lib.rs) (lines 713‑720) and exposed to the TypeScript frontend:

```typescript
// Frontend permission check flow
import { invoke } from '@tauri-apps/api/tauri';

async function enableSystemAudio() {
  const hasPerm = await invoke<boolean>('check_screen_recording_permission_command');
  if (!hasPerm) {
    await invoke('request_screen_recording_permission_command');
  }
  // After permission, start system-audio capture
  await invoke('start_system_audio_capture', { device_name: 'BlackHole 2ch' });
}

```

The onboarding flow in [`src-tauri/src/onboarding.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/src-tauri/src/onboarding.rs) (step 4 for macOS) invokes these commands to guide users through required grants before recording begins.

## Error Handling and Permission Propagation

When the OS denies microphone access, the error surfaces in `audio::pipeline.rs` (lines 590‑601) with the message “Permission denied for audio device …”. The frontend can detect these failures through the `Result` returned by the `start_recording` command:

```rust
#[tauri::command]
async fn start_recording(
    mic_device_name: Option<String>,
    system_device_name: Option<String>,
    meeting_name: Option<String>,
) -> Result<(), String> {
    audio::recording_commands::start_recording(mic_device_name, system_device_name, meeting_name).await
}

```

This architecture ensures that permission handling remains centralized in the Rust layer, keeping the frontend code agnostic of platform-specific APIs while maintaining strict privacy controls.

## Summary

- **macOS requires explicit handling** – Meetily checks screen-recording permission via [`src-tauri/src/audio/permissions.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/src-tauri/src/audio/permissions.rs) before capturing system audio, while microphone access follows standard AVCaptureDevice flows.
- **Windows and Linux use OS-level grants** – No explicit permission code exists for these platforms; microphone access is automatic (Windows) or policy-based (Linux), and system audio capture requires no additional user consent.
- **Unified device discovery** – The [`discovery.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/discovery.rs) module abstracts platform-specific implementations in `audio/devices/platform/`, returning consistent device lists across macOS, Windows, and Linux.
- **Thread-safe state management** – All device handles are wrapped in `Arc<RwLock<…>>` and managed through [`recording_state.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/recording_state.rs) for safe concurrent access.
- **Tauri command bridge** – Frontend TypeScript calls Rust commands registered in [`lib.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/lib.rs) to check and request permissions, with onboarding logic in [`onboarding.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/onboarding.rs) guiding macOS users through the grant flow.

## Frequently Asked Questions

### Why does Meetily require screen recording permission on macOS for audio capture?

macOS routes system audio capture through ScreenCaptureKit, which Apple classifies under the screen-recording permission category. When you invoke `check_screen_recording_permission_command` or `request_screen_recording_permission_command` from the frontend, the backend calls `AVCaptureDevice::requestAccess` APIs in [`src-tauri/src/audio/permissions.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/src-tauri/src/audio/permissions.rs). This permission is separate from microphone access and specifically enables capturing application audio output without looping physical cables.

### How does Meetily handle missing microphone permissions?

If the OS denies microphone access, the Rust backend logs “Permission denied for audio device …” in [`src-tauri/src/audio/core-old.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/src-tauri/src/audio/core-old.rs) and returns an error through the `start_recording` command’s `Result<(), String>` type. The frontend can catch this error and prompt the user to check system privacy settings, as the Tauri commands do not automatically retry denied microphone requests on Windows or Linux.

### Can users select specific audio devices rather than using defaults?

Yes. The `audio::devices::microphone.rs` module provides `list_input_devices()` to enumerate available sources. Users pass a specific `mic_device_name` or `system_device_name` parameter to the `start_recording` Tauri command. The backend validates this device name against the discovery cache in [`recording_state.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/recording_state.rs) before initializing the capture stream, falling back to the default device only if no name is specified.

### Is there a difference in privacy implications between platforms?

Yes. On macOS, Meetily must explicitly request screen-recording permission for system audio, which the user can revoke at any time in System Settings. Windows grants microphone access automatically on first use through WASAPI, though users can later disable it in Privacy settings. Linux relies on PulseAudio/ALSA policies, meaning permissions are typically managed at the system level rather than per-application, resulting in no runtime prompts during the onboarding flow defined in [`src-tauri/src/onboarding.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/src-tauri/src/onboarding.rs).