8

I have an iOS7 application with music player. I'm using the following code to check playback state changes from the MPMusicPlayerController to update the UI. More precisely I toggle the look of the play button between play and pause.

[[NSNotificationCenter defaultCenter] addObserver: self
                   selector: @selector (handle_NowPlayingItemChanged:)
                       name: MPMusicPlayerControllerNowPlayingItemDidChangeNotification
                     object: self.musicPlayer];

[[NSNotificationCenter defaultCenter] addObserver: self
                   selector: @selector (handle_PlaybackStateChanged:)
                       name: MPMusicPlayerControllerPlaybackStateDidChangeNotification
                     object: self.musicPlayer];

[self.musicPlayer beginGeneratingPlaybackNotifications];

if I run the app on iOS7 on an iPad or iPhone, I get the following sequence instead of just one single callback:

-[MyMediaPlayer handle_PlaybackStateChanged:] :: playbackState: 1
-[MyMediaPlayer handle_PlaybackStateChanged:] :: playbackState: 2
-[MyMediaPlayer handle_PlaybackStateChanged:] :: playbackState: 1
-[MyMediaPlayer handle_PlaybackStateChanged:] :: playbackState: 2

playbackState 2 means MPMusicPlaybackStatePaused and causes my application to display the wrong state in the UI, while the song is actually being played back. It doesn't make sense that the callback gets called 4 times, with alternating values.

This happens when changing the queue only. It looks like the system is not clearing the queue properly.

Any ideas on how to solve this ?

swifferina
  • 293
  • 4
  • 16

4 Answers4

4

I've been experiencing the same problem since the release of iOS 7. It's defeinitely a problem with iOS; not only is it reporting an incorrect playback state but also on occasions fails to receive playback state change notifications (MPMusicPlayerControllerPlaybackStateDidChangeNotification)

I've reported the bug to Apple and I suggest you do the same thing (Apple Bug Reporter)

sooper
  • 5,991
  • 6
  • 40
  • 65
  • 1
    @user1763004 There's no work-around for this. If you're sometimes being given the wrong playback state, there's no way to determine whether it is right or wrong for any given time. I guess the only other option would be to have both a play and pause button, but I'm guessing that's not something you want. – sooper Sep 20 '13 at 20:03
  • I have this issue as well on a music player. No way to get rid of that so far. This is a serious issue on iOS7. – loretoparisi Oct 02 '13 at 14:31
  • I filed a radar as well. Hope this help to fix this issue. Currently the same happens for iOS 7.0.3 – loretoparisi Oct 02 '13 at 14:57
  • I've had the same problem. My kludge to fix this is to set a timer for 1 second after receiving an indication that MPMusicPlaybackStatePlaying. I then test to determine if the music is playing or not with AudioSessionGetProperty(kAudioSessionProperty_OtherAudioIsPlaying, &size, &audioIsPlaying) . If it is not playing, I reset the audio system and then put the music player back into the playback state. – JeffB6688 Dec 15 '13 at 18:19
4

I had the same problem. I found this workaround, instead of use playbackState to check if the audio is playing, I used this condition:

if([[AVAudioSession sharedInstance] isOtherAudioPlaying])

Hugo Vanderlei
  • 101
  • 1
  • 4
3

Another workaround is check:

    if([[MPMusicPlayerController iPodMusicPlayer] currentPlaybackRate] == 0)
Hugo Vanderlei
  • 101
  • 1
  • 4
  • 1
    I find checking the `currentPlaybackRate` solves the issue I was having. However, you should never compare a float using equality! – matt May 21 '14 at 02:06
2

The workaround depends upon your implementation of the callbacks. What I did is as follows:

(1) Suppress the callbacks during queue change. Thus, I have a BOOL ivar doNotNoteNowPlayingItem. An example callback starts like this:

    if (self.doNotNoteNowPlayingItem) // flag to prevent
        return;

Thus, when I am about to change the queue, I raise the flag, setting this ivar to YES, and lower it again when I'm about to set the nowPlayingItem and am ready for callbacks again. Other callbacks would work similarly.

(2) Do not use playbackState as a test of whether we are playing vs. paused. The answer will be right if we are stopped, but if we are playing, the answer may be reported as paused. To distinguish playing from paused, check the currentPlaybackRate; if it is close to 1 we are playing, but it if it is close to 0 we are paused.

matt
  • 515,959
  • 87
  • 875
  • 1,141