Skip to content

Commit 457969d

Browse files
hiroshihoriecloudwebrtc
authored andcommitted
Remove blocking mic permission request from AudioEngine pre-enable check (#265)
Forward-port of #204 (originally targeting `m137_release`) to `m144_release`, which is the line currently shipped by the LiveKit Swift SDK (`main` pins `144.7559.10`). The blocking call was never ported forward, so it still lives on `m144_release`. ## Problem `EnsureMicrophonePermissionSync()` blocks the WebRTC worker thread on a semaphore (`dispatch_semaphore_wait(…, DISPATCH_TIME_FOREVER)`) until the user answers the mic permission dialog. When the app is woken in the background (e.g. an incoming CallKit call), no dialog can appear, so `setEngineAvailability` hangs indefinitely. Ref: livekit/client-sdk-swift#815 ## Change Replace the blocking request with a passive `IsMicrophonePermissionAuthorized()` check in the AudioEngine pre-enable path. When the mic is not authorized it returns `kAudioEngineErrorInsufficientDevicePermission` instead of blocking. The (dead) `IsMicrophonePermissionGranted()` is renamed into that check; it had no other callers. Only the `.notDetermined` case changes behavior: previously it prompted and blocked the worker thread; now it returns an error immediately. `authorized` and `denied`/`restricted` are unchanged.
1 parent eaf1cd8 commit 457969d

2 files changed

Lines changed: 6 additions & 33 deletions

File tree

modules/audio_device/audio_engine_device.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -512,8 +512,7 @@ class AudioEngineDevice : public AudioDeviceModule, public AudioSessionObserver
512512
std::vector<std::string> input_device_labels_;
513513
#endif
514514

515-
bool IsMicrophonePermissionGranted();
516-
bool EnsureMicrophonePermissionSync();
515+
bool IsMicrophonePermissionAuthorized();
517516

518517
#if !TARGET_OS_OSX
519518
bool IsAudioSessionCategoryValid(NSString* category, bool is_input_enabled,

modules/audio_device/audio_engine_device.mm

Lines changed: 5 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2284,9 +2284,10 @@ AVAudioVoiceProcessingOtherAudioDuckingLevel ToAVDuckingLevel(
22842284
// At this point mic permissions / session should be configured for recording.
22852285
if (state.DidEnableInput()) {
22862286
LOGI() << "Checking microphone permission...";
2287-
// Attempt to acquire mic permissions at this point to return an erorr early.
2288-
bool isAuthorized = EnsureMicrophonePermissionSync();
2289-
LOGI() << "AudioEngine pre-enable check, device permission: "
2287+
// Passively check the current authorization status to fail early without blocking.
2288+
// Requesting permission is the SDK's responsibility (gated to the foreground).
2289+
bool isAuthorized = IsMicrophonePermissionAuthorized();
2290+
LOGI() << "AudioEngine pre-enable check, mic permission authorized: "
22902291
<< (isAuthorized ? "true" : "false");
22912292
if (!isAuthorized) {
22922293
return rollback(kAudioEngineErrorInsufficientDevicePermission);
@@ -3185,38 +3186,11 @@ AVAudioVoiceProcessingOtherAudioDuckingLevel ToAVDuckingLevel(
31853186
// ----------------------------------------------------------------------------------------------------
31863187
// Private - Microphone permission
31873188

3188-
bool AudioEngineDevice::IsMicrophonePermissionGranted() {
3189+
bool AudioEngineDevice::IsMicrophonePermissionAuthorized() {
31893190
AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
31903191
return status == AVAuthorizationStatusAuthorized;
31913192
}
31923193

3193-
bool AudioEngineDevice::EnsureMicrophonePermissionSync() {
3194-
AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
3195-
3196-
if (status == AVAuthorizationStatusAuthorized) {
3197-
return true;
3198-
}
3199-
3200-
if (status == AVAuthorizationStatusNotDetermined) {
3201-
// Request permission synchronously - this will block WebRTC's worker thread
3202-
// but this is acceptable since instantiating AVAudioInputNode would block anyway
3203-
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
3204-
__block BOOL granted = NO;
3205-
3206-
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeAudio
3207-
completionHandler:^(BOOL granted_inner) {
3208-
granted = granted_inner;
3209-
dispatch_semaphore_signal(semaphore);
3210-
}];
3211-
3212-
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
3213-
return granted;
3214-
}
3215-
3216-
// Status is denied or restricted
3217-
return false;
3218-
}
3219-
32203194
// ----------------------------------------------------------------------------------------------------
32213195
// Private - Audio session
32223196

0 commit comments

Comments
 (0)