Skip to content

feat(coreaudio): check macOS system audio permission - #1257

Open
thewh1teagle wants to merge 1 commit into
RustAudio:masterfrom
thewh1teagle:feat/macos-system-audio-permission-check
Open

feat(coreaudio): check macOS system audio permission#1257
thewh1teagle wants to merge 1 commit into
RustAudio:masterfrom
thewh1teagle:feat/macos-system-audio-permission-check

Conversation

@thewh1teagle

Copy link
Copy Markdown
Contributor

Summary

This adds macOS System Audio Recording permission helpers and uses the non-blocking check before constructing a CoreAudio loopback process tap.

The goal is to avoid the current failure mode where CoreAudio tap loopback can build successfully but record silence when the process is missing the kTCCServiceAudioCapture permission. Stream construction now fails early with ErrorKind::PermissionDenied instead of silently producing empty audio.

Design

  • Add cpal::platform::check_system_audio_permission() as a non-blocking permission check.
  • Add explicit app-controlled helpers:
    • cpal::platform::request_system_audio_permission()
    • cpal::platform::open_system_audio_settings()
  • Call only the non-blocking check from LoopbackDevice::from_device().
  • Return ErrorKind::PermissionDenied when permission is missing.
  • Keep the macOS backend module crate-visible rather than making coreaudio::macos public.
  • Add a minimal example showing the check/request/settings flow.

This follows the middle-ground approach discussed in #1124: CPAL does not show blocking permission UI during stream construction, but applications can explicitly request permission at an appropriate time.

Related context

Testing

Ran on macOS/aarch64:

cargo fmt --check
cargo check --target aarch64-apple-darwin
cargo clippy --target aarch64-apple-darwin --lib -- -D warnings
cargo clippy --target aarch64-apple-darwin --example macos_system_audio_permission -- -D warnings
cargo check --target aarch64-apple-darwin --example macos_system_audio_permission

Manual probes:

  • check_system_audio_permission() returned the current permission state.
  • request_system_audio_permission() returned successfully after granting permission.
  • open_system_audio_settings() opened System Settings.
  • Building an input stream from the default output device with missing permission returned:
kind=PermissionDenied
msg=System audio recording permission is required for macOS loopback recording; call cpal::platform::request_system_audio_permission() or grant it in System Settings

megastruktur added a commit to megastruktur/transcripter that referenced this pull request Aug 24, 2026
…macOS

The Core Audio process tap never reports a missing kTCCServiceAudioCapture
permission: the tap, aggregate, IOProc and start all return noErr, the
callback fires on schedule, and every buffer is zeros. On top of that the
system prompt (normally triggered by starting IO on a tap-backed aggregate)
never appears for our unsigned/ad-hoc builds because TCC keys the record
off a stable signing identity — so users silently record a silent system
track while the mic works fine. Confirmed independently by the Thunder
Kitty writeup, cpal PR RustAudio/cpal#1257, and AudioCap.

Request the permission explicitly through the private TCC SPI
(TCCAccessPreflight / TCCAccessRequest, dlopen'ed at runtime — the same
approach AudioCap, screenpipe and the cpal PR use). create_loopback now
prompts once before creating the tap and returns a real error on denial,
which the existing v0.2.5 degrade-to-mic path turns into a visible
warning instead of a silently dead system track.
megastruktur added a commit to megastruktur/transcripter that referenced this pull request Aug 27, 2026
…macOS

The Core Audio process tap never reports a missing kTCCServiceAudioCapture
permission: the tap, aggregate, IOProc and start all return noErr, the
callback fires on schedule, and every buffer is zeros. On top of that the
system prompt (normally triggered by starting IO on a tap-backed aggregate)
never appears for our unsigned/ad-hoc builds because TCC keys the record
off a stable signing identity — so users silently record a silent system
track while the mic works fine. Confirmed independently by the Thunder
Kitty writeup, cpal PR RustAudio/cpal#1257, and AudioCap.

Request the permission explicitly through the private TCC SPI
(TCCAccessPreflight / TCCAccessRequest, dlopen'ed at runtime — the same
approach AudioCap, screenpipe and the cpal PR use). create_loopback now
prompts once before creating the tap and returns a real error on denial,
which the existing v0.2.5 degrade-to-mic path turns into a visible
warning instead of a silently dead system track.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant