MPMusicPlayerController::playbackStateがおかしくなる問題
具体的に説明すると、実際には音楽が再生されてないのにplaybackStateがMPMusicPlaybackStatePlayingになる現象。普通に『MPMusicPlayerController iPodMusicPlayer』を使うアプリならどれでも再現するかと。
Appleのサンプルプログラムの『AddMusic』はもちろん、『Groove』でも再現して逆にびっくり。
問題を確認した環境
環境 | 情報 |
---|---|
iOS | 7.1.2 |
Hardware | iPhone 5s |
Date | 2014/07/07 |
再現手順
サンプルプログラムの『AddMusic』の場合。ちなみに、Xcode 5.1でコンパイルして実機で確認。
- AddMusicを立ち上げて何曲か曲を追加・再生
- AddMusicを閉じて標準のミュージックを立ち上げ
- 次の手順を実行
- 再生してる曲を一時停止
- 次の曲にスキップ
- 再生
- 一時停止
- 再生
- 一時停止
- ミュージックを閉じてAddMusicを立ち上げ
この時点で左上のボタンは再生になるはずだけど、一時停止のままになってる問題。
この手順でかなり高い確率で再現できる。
この他に、アプリで曲を再生したままiPhoneをロックして10分ぐらい放置。ロック画面で再生を停止してロックを解除した場合にも再現する場合あり(こっちは再現率40%ぐらい)。
対応策
Stack OverflowにはAudioSessionGetPropertyを使う方法が紹介されてるけど、これは使ってるAPIがすでにdeprecated。なので、AVAudioSessionを使ってもっと簡単に調べることに。
具体的にはこんな感じ。
#import <AVFoundation/AVFoundation.h> BOOL isPlaybackStateWrong( MPMusicPlayerController* player ) { // MPMusicPlaybackStatePlaying以外は信用できる MPMusicPlaybackState st = player.playbackState; if( st != MPMusicPlaybackStatePlaying ) return NO; // オーディオが再生中で無い場合、playbackStateがおかしい BOOL play = [[AVAudioSession sharedInstance] isOtherAudioPlaying]; if( play == NO ) { NSLog( @"PlaybackState wrong" ); return YES; } return NO; }
NOが帰ってきた場合は特に問題なし。YESが帰ってきた場合はplaybackStateがおかしくなってる。対応策としては、MPMusicPlayerController::pauseで明示的に停止させるのが無難かと。
備考
1つのアプリの中で再生/一時停止を繰り返してる範囲では、playbackStateがおかしくなることはない。たぶん。アプリ起動時にいきなりおかしくなることもなさそう。
つまり、アプリがバックグラウンドからフォアグラウンドに移行したタイミングで確認すればいい。そう思って、UIApplicationWillEnterForegroundNotificationで単純にチェックすると、MPMusicPlayerControllerPlaybackStateDidChangeNotificationとの絡みでさらにハマる結果に。
最終的に、どのタイミングで状態を確認するかは、アプリの作り方次第かと。
音楽再生系のアプリだと一定の間隔でタイマーを仕掛けて画面を更新する作りが多いだろうから、そのループで、フォアグラウンドに移行した後の最初のタイミングでチェックするのが一番無難かな?
Appleが修正してくれるのが一番いいんだけど・・・ iOS8で治ってるといいなぁ。
参考資料
AddMusic
https://developer.apple.com/library/ios/samplecode/AddMusic/Introduction/Intro.html
iphone - Getting wrong playback state in MP Music Player Controller in ios 5 - Stack Overflow
http://stackoverflow.com/questions/10118726/getting-wrong-playback-state-in-mp-music-player-controller-in-ios-5
(2014/07/07)