Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .changes/mic-permission-foreground
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
patch type="fixed" "Request microphone permission in foreground before enabling recording (#815)"
17 changes: 17 additions & 0 deletions Sources/LiveKit/LiveKit+DeviceHelpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@

import AVFoundation

#if canImport(UIKit) && (os(iOS) || os(visionOS) || os(tvOS))
import UIKit
#endif

public extension LiveKitSDK {
/// Helper method to ensure authorization for video(camera) / audio(microphone) permissions in a single call.
static func ensureDeviceAccess(for types: Set<AVMediaType>) async -> Bool {
Expand All @@ -41,6 +45,19 @@
return true
}

/// Requests authorization for the given media types, but only while the app is foregrounded so
/// the system permission dialog can actually appear. A no-op returning `false` on non-active or
/// non-UIKit (extension/background) contexts. Suitable for paths that must never block, where
/// prompting only makes sense when the app can present UI.
static func ensureDeviceAccessIfForegrounded(for types: Set<AVMediaType>) async -> Bool {
#if canImport(UIKit) && (os(iOS) || os(visionOS) || os(tvOS))
guard await UIApplication.shared.applicationState == .active else { return false }

Check failure on line 54 in Sources/LiveKit/LiveKit+DeviceHelpers.swift

View workflow job for this annotation

GitHub Actions / Build & Test (macos-26, 26.5, iOS Simulator,name=iPhone 17 Pro,OS=26.5, true)

'shared' is unavailable in application extensions for iOS: Use view controller based solutions where appropriate instead.

Check failure on line 54 in Sources/LiveKit/LiveKit+DeviceHelpers.swift

View workflow job for this annotation

GitHub Actions / Build & Test (macos-26, 26.5, iOS Simulator,name=iPhone 17 Pro,OS=26.5, true)

'shared' is unavailable in application extensions for iOS: Use view controller based solutions where appropriate instead.

Check failure on line 54 in Sources/LiveKit/LiveKit+DeviceHelpers.swift

View workflow job for this annotation

GitHub Actions / Build & Test (macos-26, 26.5, iOS Simulator,name=iPhone 17 Pro,OS=26.5, true)

'shared' is unavailable in application extensions for iOS: Use view controller based solutions where appropriate instead.
return await ensureDeviceAccess(for: types)
#else
return false
#endif
}

/// Blocking version of ensureDeviceAccess that uses DispatchGroup to wait for permissions.
static func ensureDeviceAccessSync(for types: Set<AVMediaType>) -> Bool {
let group = DispatchGroup()
Expand Down
5 changes: 5 additions & 0 deletions Sources/LiveKit/Participant/LocalParticipant.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

// swiftlint:disable file_length

import AVFoundation
import Combine
import Foundation

Expand Down Expand Up @@ -387,6 +388,10 @@ public extension LocalParticipant {
reportStatistics: room._state.roomOptions.reportRemoteTrackStatistics)
return try await self._publish(track: localTrack, options: publishOptions)
} else if source == .microphone {
// Replace the WebRTC ADM's removed implicit prompt: request mic access while foregrounded (#815).
if AVCaptureDevice.authorizationStatus(for: .audio) == .notDetermined {
_ = await LiveKitSDK.ensureDeviceAccessIfForegrounded(for: [.audio])
}
let localTrack = LocalAudioTrack.createTrack(options: (captureOptions as? AudioCaptureOptions) ?? room._state.roomOptions.defaultAudioCaptureOptions,
reportStatistics: room._state.roomOptions.reportRemoteTrackStatistics)
return try await self._publish(track: localTrack, options: publishOptions)
Expand Down
Loading