feat: Handle route change notifications

This commit is contained in:
ronaldheft
2022-08-30 22:59:59 -04:00
parent 11f22888d5
commit 82159ee537
+39 -5
View File
@@ -71,7 +71,7 @@ class AudioPlayer: NSObject {
} }
// Listen to player events // Listen to player events
self.setupInteruptionNotification() self.setupAudioSessionNotifications()
self.audioPlayer.addObserver(self, forKeyPath: #keyPath(AVPlayer.rate), options: .new, context: &playerContext) self.audioPlayer.addObserver(self, forKeyPath: #keyPath(AVPlayer.rate), options: .new, context: &playerContext)
self.audioPlayer.addObserver(self, forKeyPath: #keyPath(AVPlayer.currentItem), options: .new, context: &playerContext) self.audioPlayer.addObserver(self, forKeyPath: #keyPath(AVPlayer.currentItem), options: .new, context: &playerContext)
@@ -120,7 +120,7 @@ class AudioPlayer: NSObject {
print(error) print(error)
} }
self.removeInteruptionNotification() self.removeAudioSessionNotifications()
DispatchQueue.runOnMainQueue { DispatchQueue.runOnMainQueue {
UIApplication.shared.endReceivingRemoteControlEvents() UIApplication.shared.endReceivingRemoteControlEvents()
} }
@@ -148,12 +148,14 @@ class AudioPlayer: NSObject {
return 0 return 0
} }
private func setupInteruptionNotification() { private func setupAudioSessionNotifications() {
NotificationCenter.default.addObserver(self, selector: #selector(handleInteruption), name: AVAudioSession.interruptionNotification, object: AVAudioSession.sharedInstance()) NotificationCenter.default.addObserver(self, selector: #selector(handleInteruption), name: AVAudioSession.interruptionNotification, object: AVAudioSession.sharedInstance())
NotificationCenter.default.addObserver(self, selector: #selector(handleRouteChange), name: AVAudioSession.routeChangeNotification, object: AVAudioSession.sharedInstance())
} }
private func removeInteruptionNotification() { private func removeAudioSessionNotifications() {
NotificationCenter.default.removeObserver(self, name: AVAudioSession.interruptionNotification, object: AVAudioSession.sharedInstance()) NotificationCenter.default.removeObserver(self, name: AVAudioSession.interruptionNotification, object: AVAudioSession.sharedInstance())
NotificationCenter.default.removeObserver(self, name: AVAudioSession.routeChangeNotification, object: AVAudioSession.sharedInstance())
} }
private func setupTimeObserver() { private func setupTimeObserver() {
@@ -598,7 +600,7 @@ class AudioPlayer: NSObject {
} }
} }
// MARK: - iOS audio interupt notifications // MARK: - iOS audio session notifications
@objc private func handleInteruption(notification: Notification) { @objc private func handleInteruption(notification: Notification) {
guard let userInfo = notification.userInfo, guard let userInfo = notification.userInfo,
let typeValue = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt, let typeValue = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt,
@@ -617,6 +619,38 @@ class AudioPlayer: NSObject {
} }
} }
@objc private func handleRouteChange(notification: Notification) {
guard let userInfo = notification.userInfo,
let reasonValue = userInfo[AVAudioSessionRouteChangeReasonKey] as? UInt,
let reason = AVAudioSession.RouteChangeReason(rawValue: reasonValue) else {
return
}
switch reason {
case .newDeviceAvailable: // New device found.
let session = AVAudioSession.sharedInstance()
let headphonesConnected = hasHeadphones(in: session.currentRoute)
if headphonesConnected {
// We should just let things be, as it's okay to go from speaker to headphones
}
case .oldDeviceUnavailable: // Old device removed.
if let previousRoute = userInfo[AVAudioSessionRouteChangePreviousRouteKey] as? AVAudioSessionRouteDescription {
let headphonesWereConnected = hasHeadphones(in: previousRoute)
if headphonesWereConnected {
// Removing headphones we should pause instead of keeping on playing
self.pause()
}
}
default: ()
}
}
private func hasHeadphones(in routeDescription: AVAudioSessionRouteDescription) -> Bool {
// Filter the outputs to only those with a port type of headphones.
return !routeDescription.outputs.filter({$0.portType == .headphones}).isEmpty
}
// MARK: - Now playing // MARK: - Now playing
private func setupRemoteTransportControls() { private func setupRemoteTransportControls() {
DispatchQueue.runOnMainQueue { DispatchQueue.runOnMainQueue {