65 lines
2.3 KiB
Swift
65 lines
2.3 KiB
Swift
|
|
import AVFoundation
|
||
|
|
import VoiceCatCore
|
||
|
|
|
||
|
|
@MainActor
|
||
|
|
final class AudioSessionManager {
|
||
|
|
static let shared = AudioSessionManager()
|
||
|
|
|
||
|
|
weak var client: VoiceCatClient?
|
||
|
|
|
||
|
|
func configure() {
|
||
|
|
let session = AVAudioSession.sharedInstance()
|
||
|
|
do {
|
||
|
|
try session.setCategory(.playAndRecord, mode: .voiceChat,
|
||
|
|
options: [.allowBluetooth, .allowBluetoothA2DP,
|
||
|
|
.defaultToSpeaker, .mixWithOthers])
|
||
|
|
} catch {
|
||
|
|
print("[AudioSession] setCategory failed: \(error)")
|
||
|
|
}
|
||
|
|
|
||
|
|
NotificationCenter.default.addObserver(
|
||
|
|
self, selector: #selector(handleInterruption),
|
||
|
|
name: AVAudioSession.interruptionNotification, object: nil)
|
||
|
|
NotificationCenter.default.addObserver(
|
||
|
|
self, selector: #selector(handleRouteChange),
|
||
|
|
name: AVAudioSession.routeChangeNotification, object: nil)
|
||
|
|
}
|
||
|
|
|
||
|
|
func activateForStreaming() throws {
|
||
|
|
try AVAudioSession.sharedInstance().setActive(true, options: [])
|
||
|
|
}
|
||
|
|
|
||
|
|
func deactivateAfterStreaming() {
|
||
|
|
try? AVAudioSession.sharedInstance().setActive(false,
|
||
|
|
options: .notifyOthersOnDeactivation)
|
||
|
|
}
|
||
|
|
|
||
|
|
@objc private func handleInterruption(_ notification: Notification) {
|
||
|
|
guard let info = notification.userInfo,
|
||
|
|
let typeValue = info[AVAudioSessionInterruptionTypeKey] as? UInt,
|
||
|
|
let type = AVAudioSession.InterruptionType(rawValue: typeValue)
|
||
|
|
else { return }
|
||
|
|
|
||
|
|
switch type {
|
||
|
|
case .began:
|
||
|
|
client?.audioSuspend()
|
||
|
|
case .ended:
|
||
|
|
let optionsValue = info[AVAudioSessionInterruptionOptionKey] as? UInt ?? 0
|
||
|
|
let options = AVAudioSession.InterruptionOptions(rawValue: optionsValue)
|
||
|
|
if options.contains(.shouldResume) {
|
||
|
|
try? AVAudioSession.sharedInstance().setActive(true)
|
||
|
|
client?.audioResume()
|
||
|
|
}
|
||
|
|
@unknown default: break
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
@objc private func handleRouteChange(_ notification: Notification) {
|
||
|
|
NotificationCenter.default.post(name: .voiceCatDeviceListChanged, object: nil)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
extension Notification.Name {
|
||
|
|
static let voiceCatDeviceListChanged = Notification.Name("cat.voice.deviceListChanged")
|
||
|
|
}
|