Make Better Things



I like to make better things.

Headphone plug-in plug-out event in iOS

To get the headphone plug-in plug-out event we need to employ a property listener callback function. The system invokes the callback when a user plugs in or unplugs a headset, or docks or undoes the device – thereby adding or removing an audio connection. The system also invokes the property listener callback when a Bluetooth device connects or disconnects.

Defining a Property Listener Callback Function

To respond to a route change, a property listener callback function must:

  • Identify the nature of the route change
  • Branch, depending on the specific route change and the current audio context (for example, recording, playback, or stopped)
  • Take or invoke appropriate action

Here is the example of this type of callback function. To see a similar callback function in working project you should see AddMusic sample code by Apple.

void audioRouteChangeListenerCallback (
void                   *inUserData,                                 // 1
AudioSessionPropertyID inPropertyID,                                // 2
UInt32                 inPropertyValueSize,                         // 3
const void             *inPropertyValue                             // 4
)

{

if (inPropertyID != kAudioSessionProperty_AudioRouteChange) return; // 5
MainViewController *controller = (MainViewController *) inUserData; // 6
if (controller.appSoundPlayer.playing == 0 ) {                      // 7
return;
} else {
CFDictionaryRef routeChangeDictionary = inPropertyValue;        // 8
CFNumberRef routeChangeReasonRef = CFDictionaryGetValue (routeChangeDictionary,CFSTR (kAudioSession_AudioRouteChangeKey_Reason));
SInt32 routeChangeReason;
CFNumberGetValue (routeChangeReasonRef, kCFNumberSInt32Type, &routeChangeReason);
if (routeChangeReason ==  kAudioSessionRouteChangeReason_OldDeviceUnavailable) {  // 9

[controller.appSoundPlayer pause];
UIAlertView *routeChangeAlertView =    [[UIAlertView alloc] initWithTitle: @"Playback Route Changed"  message: @"Audio output was changed." delegate:nil cancelButtonTitle: @"Ok" otherButtonTitles:nil];
[routeChangeAlertView show];

}

}

}

Here’s how this code works:

  1. A pointer to data that you provide when initializing your audio session.In an Objective-C class file, such as a view controller class, you place the property listener callback function outside of the class implementation block. Because of this, the callback needs a reference to the controller object to be able to send messages to it. You provide this reference when initializing your audio session.
  2. The identifier for the property that this callback function gets notified about.
  3. The size, in bytes, of the data in the inPropertyValue parameter.
  4. The current value of the property that this callback function is monitoring. Because the property being monitored is the kAudioSessionProperty_AudioRouteChange property, this value is a CFDictionary object.
  5. Ensures that the callback was invoked for the correct audio session property change.
  6. Initializes a MainViewController object instance to the reference passed in by the inUserData parameter. This allows the callback to send messages to your view controller object—typically defined in the same file that implements the callback.
  7. If application sound is not playing, there’s nothing to do, so return.
  8. This line and the next several lines determine the reason for the route change. The one route change of interest in this playback-only example is that an output device, such as a headset, was removed.
  9. If an output device was indeed removed, then pause playback and display an alert that allows the user to stop or resume playback.

Registering Your Property Listener Callback with the Audio Session

Your application can listen for hardware and route change events by way of the property mechanism in Audio Session Services. For example, to listen for route change events, you register a callback function with your audio session object, as shown here.

AudioSessionPropertyID routeChangeID =  kAudioSessionProperty_AudioRouteChange;    // 1

AudioSessionAddPropertyListener (                                  // 2

routeChangeID,                                                 // 3

audioRouteChangeListenerCallback,                                      // 4

userData                                                       // 5

);

Here’s how this code works:

  1. Declares and initializes a variable to the identifier for the property you want to monitor.
  2. Registers your property listener callback function with your initialized audio session.
  3. The identifier for the property you want to monitor.
  4. A reference to your hardware listener callback function.
  5. Data you want the audio session to pass back to your callback function.

Category: iPhone

Tagged: , ,

2 Responses

  1. cyril says:

    Thanks for your post, I’m now facing a problem, maybe you would have any idea to fix it :
    - I plug a headphone -> my audio route change callback is called
    - then I switch sound to speakers (without unplugging my headphone) -> audio route change callback is called
    - then I unplug my headphone (when sound is still outputting to speakers) -> audio route change callback is NOT called, which seems logical.

    But here is my problem ! So my question is : Do you see a way to detect that headphone was unplugged for this last case ?

    Thanks for your help
    Cyril

Leave a Reply