Detecting if Headphones are Plugged-in to an iOS Device in Swift

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.

11 thoughts on “Detecting if Headphones are Plugged-in to an iOS Device in Swift

  1. 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
    }
    }

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

  3. 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!

    1. Thanks for your comment 🙂
      As far as I understood the question, though not related to iOS, you should be able to detect video playback on a browser with HTML 5 video events. Please see:

      http://stackoverflow.com/questions/8599076/detect-if-html5-video-element-is-playing
      http://www.w3.org/2010/05/video/mediaevents.html

      On the other hand if you are trying to detect inside your iOS app, if some other app (in your case a browser) is playing audio/video, please try:

      http://stackoverflow.com/questions/20371388/detecting-active-avaudiosessions-on-ios-device

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 )

Connecting to %s