When a vc is first pushed on/presented, how can I check if headphones are already plugged in?
In the below code, if the headphones aren't plugged in when the vc first appears, if I then plug in headphones and unplug them, everything works fine.
But if the headphones are already plugged when the vc first loads, the Notification to detect them doesn't fire. It does fire once I unplug them though.
var didSubviewsLayout = false
override func viewDidLayoutSubviews() { // I also tried viewDidLoad
super.viewDidLayoutSubviews()
if didSubviewsLayout { return }
didSubviewsLayout = true
do {
try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .default, options: [ .duckOthers,
.allowBluetoothA2DP,
.allowAirPlay,
.mixWithOthers,
.defaultToSpeaker]
)
try AVAudioSession.sharedInstance().setActive(true)
} catch { }
setHeadphonesNotification() // tried this here first
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
setHeadphonesNotification() // tried this here after it didn't work the first time
}
func setHeadphonesNotification() {
NotificationCenter.default.addObserver(self, selector: #selector(audioRouteChangeListener),
name: AVAudioSession.routeChangeNotification,
object: nil)
}
@objc private func audioRouteChangeListener(notification: NSNotification) {
guard let userInfo = notification.userInfo else { return }
guard let audioRouteChangeReason = userInfo[AVAudioSessionRouteChangeReasonKey] as? UInt else { return }
switch audioRouteChangeReason {
case AVAudioSession.RouteChangeReason.newDeviceAvailable.rawValue:
print("headphone plugged in")
view.backgroundColor = .red
let session = AVAudioSession.sharedInstance()
for output in session.currentRoute.outputs where output.portType == AVAudioSession.Port.headphones {
view.backgroundColor = .blue
break
}
case AVAudioSession.RouteChangeReason.oldDeviceUnavailable.rawValue:
print("headphone pulled out")
view.backgroundColor = .orange
if let previousRoute = userInfo[AVAudioSessionRouteChangePreviousRouteKey] as? AVAudioSessionRouteDescription {
for output in previousRoute.outputs where output.portType == AVAudioSession.Port.headphones {
view.backgroundColor = .white
break
}
}
default:
break
}
}
You can use currentRoute.outputs
on the AVAudioSession
to check what outputs initially exist:
/// All current connected output device port types.
var outputPorts: [AVAudioSession.Port] { AVAudioSession.sharedInstance().currentRoute.outputs.map { $0.portType } }
let areHeadphonesConnected: Bool = outputPorts.contains(.headphones)