feat(*): subsonic client with avfoundation playback and apple music ui
This commit is contained in:
commit
e5bb559d7f
93 files changed
+7517
No files matched your search
@@ -0,0 +1,69 @@
|
||||
#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
|
||||
Reference in new issue
Block a user