8

i am getting wrong playback state in MP music player. while playing a song i am getting pause state. My app is working fine in ios 4.but i am having this issue in ios 5. can anybody Help me ??

My code is here.

[musicPlayer stop];
if (userMediaItemCollection)
{
   userMediaItemCollection=nil; 
}
musicPlayer.nowPlayingItem=nil;

userMediaItemCollection=[MPMediaItemCollection collectionWithItems:[mediaItemCollection    items]];

[musicPlayer setQueueWithItemCollection:userMediaItemCollection];
[musicPlayer setNowPlayingItem:    
[[userMediaItemCollectionitems]objectAtIndex:indexOfCurrentObject]];
[self enablePrevAndNextButtons];

[musicPlayer play];        
}

-(void)playbackStateDidChanged:(NSNotification *)notification
{

 if (musicPlayer.playbackState!=MPMusicPlaybackStatePlaying)
 {
    [playPauseButton setBackgroundImage:[UIImage imageNamed:@"play_iPad.png"] forState:UIControlStateNormal];
 }
 else if(musicPlayer.playbackState==MPMusicPlaybackStatePlaying)
 {
    [playPauseButton setBackgroundImage:[UIImage imageNamed:@"pause_iPad.png"] forState:UIControlStateNormal];
 }
Vivek Parikh
  • 627
  • 8
  • 18
  • 31

5 Answers5

4

I have also reported this bug to Apple. I was able to reproduce it 100% of the time by doing the following:

Launch application that uses MPMusicPlayerController. Launch the "Music" App. Hit Play, Skip, Skip, Pause, Play, Pause Open the original application and the MPMusicPlaybackState of MPMusicPlayerController will be incorrect.

None of the proposed solutions here worked for me. The solution that did work was to keep track of when the bug was occurring and updating the UI specially in these cases.

When the UIApplicationDidBecomeActiveNotification notification is received (see matbur post for more details on this), see if audio is actually not playing when the MPMusicPlaybackState said it was:

-(BOOL) isPlaybackStateBugActive {
    MPMusicPlaybackState playbackState = self.musicPlayer.playbackState;
    if (playbackState == MPMusicPlaybackStatePlaying) {
        AudioSessionInitialize (NULL, NULL, NULL, NULL);
        UInt32 sessionCategory = kAudioSessionCategory_AmbientSound;
        AudioSessionSetProperty (kAudioSessionProperty_AudioCategory, sizeof (sessionCategory), &sessionCategory);
        AudioSessionSetActive (true);

        UInt32 audioIsPlaying;
        UInt32 size = sizeof(audioIsPlaying);
        AudioSessionGetProperty(kAudioSessionProperty_OtherAudioIsPlaying, &size, &audioIsPlaying);

        if (!audioIsPlaying){
            NSLog(@"PlaybackState bug is active");
            return YES;
        }
    }

    return NO;
}

Don't forget to import the AudioToolbox framework.

pgkelley
  • 484
  • 1
  • 6
  • 9
  • And what should I do with this information? How can I get the correct state? Or how can I reset the player? – MetaImi Nov 27 '12 at 23:50
  • I've got it. If audioIsPlaying is true, then you can use the musicplayer pause method to pause the music, even if it has a wrong state. And vice versa. So with this code snippet, you can fix the mpmusicplayercontroller – MetaImi Nov 28 '12 at 00:07
3

None of these workarounds fix the issue for my app. It is a bug in iOS, and my app will never function properly until Apple fixes it.

I have a music player with a play/pause button. When music is playing, the button shows the "pause" icon. When music is paused, the button shows the "play" icon - just like all music apps. I can replicate the bug at any time by doing the following: 1. Play music in my app (the play/pause button shows the "pause" icon correctly) 2. Background my app and lock my phone for ~10 minutes 3. Double tap home and hit the pause button from the iPod controls 4. Unlock my phone and open my app again 5. Music will be stopped, but my app still shows the "pause" icon when it should so "play"

I've done extensive debugging and logging to ensure that the method that updates my play/pause button is always called when my application becomes active. The issue is that when I re-enter my app, the playback state of MPMusicPlayer is still set to MPMusicPlaybackStatePlaying even when music is stopped/paused.

I filed a bug report for this about a year ago and haven't heard anything from Apple. If someone else would file one it would be greatly appreciated.

mms13
  • 31
  • 2
0

I have the same problem but when I play/pause many times when my app is in background, I reported the bug to Apple and hope to get an amswer soon, I want to know if my coding is wrong or there is an API problem. If this was the error you were having, this may be helpful. I came to a workaround which even though isnt the best solution, for my app is acceptable:

In the viewDidLoad, add this:

NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver: self
                       selector: @selector (handle_ApplicationDidBecomeActive:)
                           name: UIApplicationDidBecomeActiveNotification
                         object: nil];

Then, create a handle_ApplicationDidBecomeActive method, and add this:

- (void) handle_ApplicationDidBecomeActive: (id) notification
{
    if (musicPlayer.playbackState!=MPMusicPlaybackStatePlaying)
    {
       [playPauseButton setBackgroundImage:[UIImage imageNamed:@"play_iPad.png"] forState:UIControlStateNormal];
       [musicPlayer pause];
    }
    else if(musicPlayer.playbackState==MPMusicPlaybackStatePlaying)
    {
       [playPauseButton setBackgroundImage:[UIImage imageNamed:@"pause_iPad.png"] forState:UIControlStateNormal];
       [musicPlayer pause];
    }
}

(dont put this code inside your playbackStateDidChanged method as this may generate an endless loop)

This will sync the state of your buttons and music player to the one reported by the API. in the cases in which there is a coincidence, there will be no impact of any type, in the other cases, the player will pause/play accordingly.

matbur
  • 41
  • 4
0

I experienced the same problem with the release of iOS 5. I found that the playbackState property does get updated, but after a delay, so it's not yet set when your playbackStateDidChanged method runs.

My workaround was to set my own instance variable called musicPlayerRecentlyStartedPlaying whenever I start playback. Then I use a method called from a timer to check both that variable and the playbackState property to find out if the player is really playing:

- (void)playMusic {
    [self.musicPlayer play];
    self.musicPlayerRecentlyStartedPlaying = TRUE;
    self.musicControlsUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(updateMusicControls:) userInfo:nil repeats:TRUE];
}

- (void)stopMusic {
    [self.musicPlayer stop];
    self.musicPlayerRecentlyStartedPlaying = FALSE;
    [self.musicControlsUpdateTimer invalidate];
}

- (void)updateMusicControls:(NSTimer *)timer {
    BOOL playing = (([self.musicPlayer playbackState] == MPMusicPlaybackStatePlaying)&&(self.musicPlayer.nowPlayingItem));
    if (!playing) {
        // check to see if we recently started playing
        if (self.musicPlayerRecentlyStartedPlaying) {
            playing = TRUE;
        }
    } else {
        // once the property is updated, we no longer need this
        self.musicPlayerRecentlyStartedPlaying = FALSE;
    }
}

You might not need to call updateMusicControls from a timer, but I do because I'm also updating the position of a progress bar as the music plays.

arlomedia
  • 8,534
  • 5
  • 60
  • 108
  • Regardless of how long I wait to check the playback state, it'll be incorrect until I pause/restart playback while my app is active. – James Boutcher Jan 27 '13 at 21:33
  • My code assumes you're only playing and pausing music from within the app. I don't think the original question mentioned background operation, although the other answers are referring to that scenario. – arlomedia Jan 28 '13 at 00:15
  • The scenario that's giving me the most headache is someone who leaves the app to change the song. Even though the new song is now playing, the notification and playback state given to the app will say the song is paused. – James Boutcher Jan 28 '13 at 12:51
0

This code using when previous Button click Previous song will be play

- (IBAction)playPreviousSongInList:(id)sender {

        static NSTimeInterval skipToBeginningOfSongIfElapsedTimeLongerThan = 3.5;

        NSTimeInterval playbackTime = self.musicPlayer.currentPlaybackTime;
        if (playbackTime <= skipToBeginningOfSongIfElapsedTimeLongerThan) {

            [self.musicPlayer skipToPreviousItem];

        } else {

            [self.musicPlayer skipToBeginning];
        }
    }