Info

Programmer by day, artist by night

Platform: iOS 8.x or later
Device: iPhone
Language: Swift
Motivation: when user unplugs their headphones, you wan’t to stop playing audio (iTunes like behavior) in your app

The following code snippet shows how to detect if headphones are plugged in (when the app starts or is woken up). The println() command below shows the state of the headphone connection.

let currentRoute = AVAudioSession.sharedInstance().currentRoute
if currentRoute.outputs != nil {
    for description in currentRoute.outputs {
        if description.portType == AVAudioSessionPortHeadphones {
            println("headphone plugged in")
        } else {
            println("headphone pulled out")
        }
    }
} else {
    println("requires connection to device")
}

In Line 4 above, we are checking if portType equals AVAudioSessionPortHeadphones. The full list of output port types are listed below:

  • AVAudioSessionPortLineOut
  • AVAudioSessionPortHeadphones
  • AVAudioSessionPortBluetoothA2DP
  • AVAudioSessionPortBuiltInReceiver
  • AVAudioSessionPortBuiltInSpeaker
  • AVAudioSessionPortHDMI
  • AVAudioSessionPortAirPlay
  • AVAudioSessionPortBluetoothLE

However while the app is running you can’t use the above code snippet to detect active changes in headphones connection. You will need to setup a notification observer for AVAudioSessionRouteChangeNotification in your app with the code below.

NSNotificationCenter.defaultCenter().addObserver(
    self,
    selector: "audioRouteChangeListener:",
    name: AVAudioSessionRouteChangeNotification,
    object: nil)

In line 3 above, the audioRouteChangeListener: is the method that will get notified once a change in headphones connection occurs. The println() statements below show the change in headphones connection to the device.

dynamic private func audioRouteChangeListener(notification:NSNotification) {
    let audioRouteChangeReason = notification.userInfo![AVAudioSessionRouteChangeReasonKey] as UInt

    switch audioRouteChangeReason {
    case AVAudioSessionRouteChangeReason.NewDeviceAvailable.rawValue:
        println("headphone plugged in")
    case AVAudioSessionRouteChangeReason.OldDeviceUnavailable.rawValue:
        println("headphone pulled out")
    default:
        break
    }
}

In line 4 above, we are checking switch-case values for AVAudioSessionRouteChangeReasonKey (identified by the variable audioRouteChangeReason). We are interested in two cases, NewDeviceAvailable (headphones plugged in) and OldDeviceUnavailable (headphone pulled out). The full list of cases are provided below:

  • Unknown
  • NewDeviceAvailable
  • OldDeviceUnavailable
  • CategoryChange
  • Override
  • WakeFromSleep
  • NoSuitableRouteForCategory
  • RouteConfigurationChange

A demo app utilizing the code above can be found here:
https://github.com/sanjibahmad/Is-Headphone-Plugged-In

Here’s a video showing how the app works:

 

Thanks to Udacity for the motivation to write this.

Comments

11 Comments

Post a comment
  1. July 7, 2015

    Thank you for writing this article, it was exactly what I needed! One item I did find was that the current route needs to be set even if I’m not going to be watching the changes when the app first starts up.

    func viewDidLoad() {
    super.viewDidLoad()

    let currentRoute = AVAudioSession.sharedInstance().currentRoute

    NSNotificationCenter.defaultCenter().addObserver(self, selector: “audioRouteChangeListener:”, name: AVAudioSessionRouteChangeNotification, object: nil)

    }

    dynamic private func audioRouteChangeListener(notification:NSNotification) {
    let audioRouteChangeReason = notification.userInfo![AVAudioSessionRouteChangeReasonKey] as! UInt

    switch audioRouteChangeReason {
    case AVAudioSessionRouteChangeReason.NewDeviceAvailable.rawValue:
    println(“headphone plugged in”)
    case AVAudioSessionRouteChangeReason.OldDeviceUnavailable.rawValue:
    println(“headphone pulled out”)
    default:
    break
    }
    }

    • July 8, 2015

      Thanks Ken for posting your additional findings on current route.

  2. Zeta #
    July 9, 2015

    Is this for the Intro to iOS App Development with Swift course? This is what I was trying to tackle lol

    • July 9, 2015

      Yeah 🙂 It’s from the list of iOS issues to solve and write an article about.

  3. abc #
    October 2, 2015

    currentRoute.outputs != nil throws error binary operator != cannot be used of type avaudiosessionportdescription in swift 2

    • October 2, 2015

      Thanks for pointing it out. Will update the code for Swift 2.0 in the upcoming weeks.

    • October 10, 2015

      Codebase updated to Swift 2.0. Thanks!

  4. Tommy #
    March 18, 2016

    hi ! Great demo!! Can a similar script | detection method be done for the Browser? Mainly if a video is playing back can detection occurr from a Browser (Desktop) and OS (Mobile)

    THanks!

  5. Santosh #
    June 7, 2017

    than you very much…!! you made my day..!!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s

Basic HTML is allowed. Your email address will not be published.

Subscribe to this comment feed via RSS