views:

939

answers:

5

I'm currently working on a project that involves playing music from the iphone music library within the app inside. I'm using MPMediaPickerController to allow the user to select their music and play it using the iPod music player within the iPhone.

However, i ran into problem when the user insert his earpiece and removes it. The music will suddenly stop playing for no reason. After some testing, i found out that the iPod player will pause playing when the user unplug his earpiece from the device. So is there any way to programatically detect if the earpiece has been unplug so that i can resume playing the music? Or is there any way to prevent iPod player from pausing when the user unplug his earpiece?

+1  A: 

I see you are using the MPMediaPlayer Framework however the microphone handling is done using the AVAudioPlayer framework, which you will need to add to your project.

Apple's website has code from the AVAudioPlayer framework which I use to handle interruptions from a user plugging in or removing the Apple microphone headphones.

Check out Apple's iPhone Dev Center Audio Session Programming Guide.

- (void) beginInterruption {
    if (playing) {
        playing = NO;
        interruptedWhilePlaying = YES;
        [self updateUserInterface];
    }
}

NSError *activationError = nil;
- (void) endInterruption {
    if (interruptedWhilePlaying) {
        [[AVAudioSession sharedInstance] setActive: YES error: &activationError];
        [player play];
        playing = YES;
        interruptedWhilePlaying = NO;
        [self updateUserInterface];
    }
}

My code is a little different and some of this may help you:

    void interruptionListenerCallback (
              void *inUserData,
              UInt32 interruptionState
) {
    // This callback, being outside the implementation block, needs a reference
    // to the AudioViewController object
    RecordingListViewController *controller = (RecordingListViewController *) inUserData;

    if (interruptionState == kAudioSessionBeginInterruption) {

     //NSLog (@"Interrupted. Stopping playback or recording.");

     if (controller.audioRecorder) {
      // if currently recording, stop
      [controller recordOrStop: (id) controller];
     } else if (controller.audioPlayer) {
      // if currently playing, pause
      [controller pausePlayback];
      controller.interruptedOnPlayback = YES;
     }

    } else if ((interruptionState == kAudioSessionEndInterruption) && controller.interruptedOnPlayback) {
     // if the interruption was removed, and the app had been playing, resume playback
     [controller resumePlayback];
     controller.interruptedOnPlayback = NO;
    }
}

void recordingListViewMicrophoneListener (
                         void                      *inUserData,
                         AudioSessionPropertyID    inPropertyID,
                         UInt32                    inPropertyValueSize,
                         const void                *isMicConnected
                         ) {

    // ensure that this callback was invoked for a change to microphone connection
    if (inPropertyID != kAudioSessionProperty_AudioInputAvailable) {
        return;
    }

    RecordingListViewController *controller = (RecordingListViewController *) inUserData;

    // kAudioSessionProperty_AudioInputAvailable is a UInt32 (see Apple Audio Session Services Reference documentation)
    // to read isMicConnected, convert the const void pointer to a UInt32 pointer
    // then dereference the memory address contained in that pointer
    UInt32 connected = * (UInt32 *) isMicConnected;

    if (connected){
        [controller setMicrophoneConnected : YES];
    }
    else{
        [controller setMicrophoneConnected: NO];    
    }

    // check to see if microphone disconnected while recording
    // cancel the recording if it was
    if(controller.isRecording && !connected){
        [controller cancelDueToMicrophoneError];
    }
}
Brock Woolf
+2  A: 

You should register for AudioRoute changed notification and implement how you want to handle the rout changes

 // Registers the audio route change listener callback function
 AudioSessionAddPropertyListener (kAudioSessionProperty_AudioRouteChange,
                                  audioRouteChangeListenerCallback,
                                     self);

and within the callback, you can get the reason for route change

  CFDictionaryRef routeChangeDictionary = inPropertyValue;

  CFNumberRef routeChangeReasonRef =
  CFDictionaryGetValue (routeChangeDictionary,
   CFSTR (kAudioSession_AudioRouteChangeKey_Reason));

  SInt32 routeChangeReason;

      CFNumberGetValue (routeChangeReasonRef, kCFNumberSInt32Type, &routeChangeReason);

  if (routeChangeReason == kAudioSessionRouteChangeReason_OldDeviceUnavailable) 
  {
       // Headset is unplugged..

  }
  if (routeChangeReason == kAudioSessionRouteChangeReason_NewDeviceAvailable)
  {
       // Headset is plugged in..       
  }
Prakash
erm i'm having 2 error when compiling1) wat's inPropertyValue? It not decleared either in the method parameter2) CFDictionaryGetValue returns a void pointer which is incompitable with CFNumberRef. Do i need do any casting before returning the value?
DrkZeraga
hmm i managed to compile my codes and everything runs fine but when i plug in or unplug my headphone nothing happens. The audioRouteChangeListenerCallback function is not been called. Is there anything else i'm missing beside the functions above?
DrkZeraga
You should register for listener function AFTER your call to initializing AudioSession.. Do you do that way?
Prakash
Hmm will deactivating my audio session before or after i register the listener cause it not to work? Cause i'm currently disabling the audio session when using MPMediaPlayer
DrkZeraga
+1  A: 

If you just want to check whether headphones are plugged in at any given time, without listening to route changes, you can simply do the following:

OSStatus error = AudioSessionInitialize(NULL, NULL, NULL, NULL);
if (error) 
    NSLog("Error %d while initializing session", error);

UInt32 routeSize = sizeof (CFStringRef);
CFStringRef route;

error = AudioSessionGetProperty (kAudioSessionProperty_AudioRoute,
                                 &routeSize,
                                 &route);

if (error) 
    NSLog("Error %d while retrieving audio property", error);
else if (route == NULL) {
    NSLog(@"Silent switch is currently on");
} else  if([route isEqual:@"Headset"]) {
    NSLog(@"Using headphones");
} else {
    NSLog(@"Using %@", route);
}

Cheers, Raffaello Colasante

Raffaello Colasante
A: 

Could someone provide an example project which implements this? I do not really understand how it works... :(

okayasu
A: 

Hey guys just check AddMusic sample app. Will solve all your iPod related issues

First register iPod player for notification with following code

NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];

[notificationCenter
 addObserver: self
 selector:    @selector (handle_PlaybackStateChanged:)
 name:        MPMusicPlayerControllerPlaybackStateDidChangeNotification
 object:      musicPlayer];

[musicPlayer beginGeneratingPlaybackNotifications];

And implement the following code in the notification

  • (void) handle_PlaybackStateChanged: (id) notification {

    MPMusicPlaybackState playbackState = [musicPlayer playbackState];

    if (playbackState == MPMusicPlaybackStatePaused) { [self playiPodMusic]; } else if (playbackState == MPMusicPlaybackStatePlaying) {

    } else if (playbackState == MPMusicPlaybackStateStopped) { [musicPlayer stop]; } }

Priyank