70 lines
2.8 KiB
Swift
70 lines
2.8 KiB
Swift
#if canImport(AVFoundation)
|
|
import AVFoundation
|
|
import Foundation
|
|
|
|
enum AudioSession {
|
|
typealias Token = any NSObjectProtocol
|
|
|
|
#if os(iOS) || os(watchOS)
|
|
static var outputLatency: TimeInterval {
|
|
AVAudioSession.sharedInstance().outputLatency
|
|
}
|
|
|
|
static func activate() async throws {
|
|
let session = AVAudioSession.sharedInstance()
|
|
#if os(watchOS)
|
|
try session.setCategory(.playback, mode: .default, policy: .longFormAudio)
|
|
_ = try await session.activate()
|
|
#else
|
|
try session.setCategory(.playback, mode: .default)
|
|
try session.setActive(true)
|
|
#endif
|
|
}
|
|
|
|
static func observe(
|
|
interrupted: @escaping @Sendable (Bool) -> Void,
|
|
routeLost: @escaping @Sendable () -> Void
|
|
) -> [Token] {
|
|
let center = NotificationCenter.default
|
|
let session = AVAudioSession.sharedInstance()
|
|
let interruption = center.addObserver(forName: AVAudioSession.interruptionNotification, object: session, queue: nil) {
|
|
guard let raw = $0.userInfo?[AVAudioSessionInterruptionTypeKey] as? UInt,
|
|
let type = AVAudioSession.InterruptionType(rawValue: raw)
|
|
else { return }
|
|
switch type {
|
|
case .began:
|
|
interrupted(true)
|
|
case .ended:
|
|
let options = $0.userInfo?[AVAudioSessionInterruptionOptionKey] as? UInt ?? 0
|
|
if AVAudioSession.InterruptionOptions(rawValue: options).contains(.shouldResume) {
|
|
interrupted(false)
|
|
}
|
|
@unknown default:
|
|
break
|
|
}
|
|
}
|
|
let route = center.addObserver(forName: AVAudioSession.routeChangeNotification, object: session, queue: nil) {
|
|
let raw = $0.userInfo?[AVAudioSessionRouteChangeReasonKey] as? UInt
|
|
if raw.flatMap(AVAudioSession.RouteChangeReason.init) == .oldDeviceUnavailable {
|
|
routeLost()
|
|
}
|
|
}
|
|
return [interruption, route]
|
|
}
|
|
#else
|
|
static var outputLatency: TimeInterval {
|
|
0
|
|
}
|
|
|
|
static func activate() async throws {}
|
|
|
|
static func observe(
|
|
interrupted _: @escaping @Sendable (Bool) -> Void,
|
|
routeLost _: @escaping @Sendable () -> Void
|
|
) -> [Token] {
|
|
[]
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|