Swift -How to check if Headphones are Plugged In when the VC First Appears

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

    if didSubviewsLayout { return }
    didSubviewsLayout = true

    do {
        try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .default, options: [ .duckOthers,
        try AVAudioSession.sharedInstance().setActive(true)
    } catch { }

    setHeadphonesNotification() // tried this here first

override func viewDidAppear(_ animated: Bool) {

    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
    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


  • 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() { $0.portType } }
    let areHeadphonesConnected: Bool = outputPorts.contains(.headphones)