How Meetily Handles Audio Permissions on macOS, Windows, and Linux
Meetily automatically triggers platform-specific permission requests before any audio capture begins, using a centralized Rust module that orchestrates microphone and screen-recording consent across all supported operating systems.
Meetily is an open-source AI meeting assistant built with Tauri. Before it can record meetings, it must obtain system-level audio permissions—requirements vary significantly by platform. This article examines how Meetily's permission architecture works, tracing the flow from JavaScript invocation through Rust platform abstractions to native OS APIs.
Permission Architecture Overview
Meetily's permission system follows a layered design that keeps platform complexity isolated while ensuring consistent behavior:
- Entry point:
frontend/src-tauri/src/audio/permissions.rs— central orchestrator - Platform modules:
audio/devices/platform/{macos,windows,linux}.rs— OS-specific implementations - Native helpers: Swift scripts for macOS screen-recording prompts
- Frontend integration:
usePermissionCheck.tshook for UI coordination
The permission flow executes automatically when any recording command is invoked, preventing audio capture until all required consents are granted.
macOS: Microphone and Screen Recording Permissions
macOS requires two distinct permissions for full meeting capture: microphone access and screen recording (for system audio). Meetily handles these sequentially in permissions.rs, calling native Swift code for the screen-recording check.
Microphone Permission
The macOS platform module uses AVAudioSession to request microphone access. This triggers the standard macOS permission dialog with the application's NSMicrophoneUsageDescription string.
Screen Recording Permission
System audio capture requires ScreenCaptureKit entitlement, which needs explicit user approval. Meetily delegates this to a Swift helper:
// frontend/src-tauri/check_screen_permission.swift
import Cocoa
let options = [kAXTrustedCheckOptionPrompt.takeRetainedValue() as String: true] as CFDictionary
let trusted = AXIsProcessTrustedWithOptions(options)
exit(trusted ? 0 : 1)
The Rust caller runs this script and parses the exit code to determine whether recording can proceed.
macOS Implementation Files
| File | Purpose |
|---|---|
frontend/src-tauri/src/audio/devices/platform/macos.rs |
Device enumeration and native API calls |
frontend/src-tauri/check_screen_permission.swift |
Screen-recording permission prompt |
Windows: WASAPI Access and Device Permissions
Windows handles audio permissions through the WASAPI (Windows Audio Session API) framework. Unlike macOS, Windows typically does not show a permission dialog for microphone access—access is granted implicitly when the application first opens an audio stream.
Meetily's Windows implementation in audio/devices/platform/windows.rs uses IMMDeviceEnumerator to discover and activate capture devices. If the OS denies access (for example, due to privacy settings or corporate policy), the error propagates back to the frontend:
// Conceptual flow in windows.rs
let device = device_enumerator
.GetDefaultAudioEndpoint(eCapture, eConsole, &device)
.map_err(|e| format!("WASAPI access denied: {}", e))?;
The frontend receives this error through the Tauri command layer and displays an actionable message to the user.
Linux: ALSA/PulseAudio Group Membership
Linux audio permissions are implicit rather than interactive. Meetily attempts to open the default ALSA or PulseAudio device; success depends on the user belonging to the audio group and having appropriate udev rules.
The audio/devices/platform/linux.rs module tries PulseAudio first, falling back to ALSA if unavailable. Permission failures surface as device-open errors:
// Simplified from linux.rs
pub async fn ensure_alsa_or_pulse_access() -> Result<(), String> {
match pulse::connect() {
Ok(_) => Ok(()),
Err(_) => alsa::open_default()
.map_err(|e| format!("Audio access failed: {}. Ensure user is in 'audio' group.", e)),
}
}
No OS dialog appears—administrators must configure access through system groups and permissions.
Frontend Integration: The Permission Hook
Meetily's React frontend uses a custom hook to coordinate permission state with the Rust backend. The usePermissionCheck.ts hook provides:
hasPermission: Boolean indicating current consent statusrequestPermission(): Triggers the platform-specific flow- Error state propagation for UI feedback
// Frontend usage example
import { invoke } from '@tauri-apps/api/tauri';
import { usePermissionCheck } from '@/hooks/usePermissionCheck';
const MeetingRecorder = () => {
const { hasPermission, requestPermission } = usePermissionCheck();
const startRecording = async () => {
if (!hasPermission) {
const granted = await requestPermission();
if (!granted) return; // User denied
}
try {
await invoke('start_recording', {
mic_device_name: 'Built-in Microphone',
system_device_name: 'BlackHole 2ch',
meeting_name: 'Team Sync',
});
} catch (e) {
console.error('Recording failed:', e);
}
};
return <button onClick={startRecording}>Start Recording</button>;
};
The hook internally calls Tauri commands that delegate to permissions.rs, ensuring consistent behavior across all entry points.
Complete Permission Flow
When a user clicks "Start Recording," this sequence executes:
- JavaScript invokes
start_recordingcommand via Tauri API recording_commands.rsreceives the call and invokespermissions::ensure_permissions()permissions.rsselects platform module based oncfg!macros- Platform module executes native permission requests:
- macOS:
request_microphone_permission()→ Swift screen-recording check - Windows:
ensure_wasapi_access()→ Verify device activation succeeds - Linux:
ensure_alsa_or_pulse_access()→ Test device open
- macOS:
- Result propagation: Success allows pipeline initialization; failure returns descriptive error
- Frontend displays error or proceeds to recording UI
This flow guarantees fail-fast behavior—permissions are verified before any audio pipeline resources are allocated.
Key Implementation Files
Design Patterns and Best Practices
Meetily's permission handling demonstrates several robust patterns:
- Platform abstraction trait: Common interface across macOS, Windows, and Linux implementations
- Early validation: Permissions checked before resource allocation prevents partial initialization states
- User-transparent flow: Permission requests emerge from normal app interaction, not preemptive prompts
- Clear error messages: Platform-specific failures include actionable guidance (e.g., "Ensure user is in 'audio' group")
The architecture also simplifies testing: platform modules can be mocked, and the permission layer supports conditional compilation for different target environments.
Summary
- Centralized control:
permissions.rsgates all audio capture throughensure_permissions() - macOS complexity: Requires both microphone and screen-recording permissions, with Swift helper for the latter
- Windows simplicity: Implicit WASAPI access, with graceful handling of enterprise policy restrictions
- Linux system dependency: Relies on group membership and udev configuration rather than interactive prompts
- Frontend coordination:
usePermissionCheck.tshook bridges Rust permission state with React UI state - Fail-fast safety: No audio pipeline initializes until all platform requirements are satisfied
Frequently Asked Questions
How does Meetily request microphone permission on macOS?
Meetily's macOS platform module uses AVAudioSession to trigger the standard system permission dialog. This occurs in audio/devices/platform/macos.rs when request_microphone_permission() is called from the central permissions.rs orchestrator. The user sees the application-specific usage description defined in Info.plist.
Why does macOS require screen recording permission for meeting audio?
macOS routes system audio (application sounds, not microphone input) through ScreenCaptureKit. Meetily therefore needs kTCCServiceScreenCapture approval to capture remote participants' voices in video calls. The check_screen_permission.swift script uses AXIsProcessTrustedWithOptions to prompt the user if this permission is not yet granted.
What happens if Windows WASAPI access is blocked by group policy?
If Windows enterprise policies block audio capture, the windows.rs platform module receives an E_ACCESSDENIED or similar HRESULT from IMMDeviceEnumerator. This error propagates through recording_commands.rs to the frontend, where usePermissionCheck displays: "WASAPI access denied. Contact your system administrator." The recording does not start.
Can Meetily work on Linux without root access?
Yes, provided the user belongs to the audio group and has read/write access to ALSA devices or PulseAudio socket. The linux.rs module attempts PulseAudio first (which often works for standard desktop sessions), falling back to direct ALSA access. No elevation is required if permissions are properly configured.
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 →