feat(coreaudio): check macOS system audio permission - #1257
Open
thewh1teagle wants to merge 1 commit into
Open
Conversation
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
kTCCServiceAudioCapturepermission. Stream construction now fails early withErrorKind::PermissionDeniedinstead of silently producing empty audio.Design
cpal::platform::check_system_audio_permission()as a non-blocking permission check.cpal::platform::request_system_audio_permission()cpal::platform::open_system_audio_settings()LoopbackDevice::from_device().ErrorKind::PermissionDeniedwhen permission is missing.coreaudio::macospublic.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:
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.