今回は、iPhoneアプリでのバックグラウンド動作について。
1. 概要
元々(iOS3の頃)のiOSは、サードパーティ製のアプリ(一般アプリ)のバックグラウンド動作は出来ない仕様でした。しかし、iOS4でバックグラウンド動作が出来るように仕様変更されました。
ただし、バックグラウンド動作は、特定の種類のアプリにしか許可されていません。
バックグラウンド動作をしても良いアプリは、次のもののみです。
- 音楽プレーヤーのように、バックグラウンドで音声を再生するアプリケーション
- ナビゲーションのように、常に位置情報を知らせるアプリケーション
- VoIP(Voice over Internet Protocol)対応アプリケーション
- 最新号をダウンロードして処理する必要があるNewsstandアプリケーション
- 外付けアクセサリから定期的に更新情報を受け取るアプリケーション
詳しくは、Appleが発行している「iOSアプリケーションプログラミングガイド」の「バックグラウンド実行とマルチタスク」というセクション(65ページあたり)に書かれています。上記以外の種類のバックグラウンド動作をするアプリだと、Appleの審査でリジェクトされると思います。
2. 基本的な実装方法
plistに「Required Background Mode」を追加して、オーディオアプリならitem0に「App plays audio」を設定します。あとは、デリゲートで起動完了時に、オーディオセッションのカテゴリをプレイバックに設定する必要があります。
以下の記事あたりが分かり易いと思います。
http://d.hatena.ne.jp/KZR/20100920/p1
一般的なアプリなら、この実装をするだけでOKです。ですが、OpenALを用いているプログラムの場合、その他にも色々な改造が必要です。本項の情報なら、割と沢山出回っていたのですが、その点について解説したTIPSが見当たらなかったので、若干苦労しました。以下、OpenALを用いているプログラムをバックグラウンド対応する為に必要なTIPSについて記します。
3. バッファリング間隔の変更
バックグラウンド動作時のバッファリング間隔を修正する必要があるかもしれません。iOSでは、バッファリング間隔の目安として、CD品質(44100Hz、ステレオ、16bit)の音声であれば500ms程度※としています。
※Appleが発行している「オーディオセッションプログラミングガイド」の「最適なオーディオハードウェア設定の指定」(40ページあたり)を参照
SUZUKI PLAN - Video Game System(VGS)の音声品質は、22050Hz、モノラル、16bitなので、125ms辺りが目安値になります。しかし、バッファリング間隔をそんなに長くしてしまうと、効果音の再生処理の遅延が酷くなってしまいます。そのため、VGSでは通常(フォアグラウンド動作時)は、バッファリング間隔を50msにしています。フォアグラウンド動作であれば50msでも問題無く動いてくれていましたが、スリープボタンを押すと、音飛びが発生してしまいます。どうやらiOSは、スリープ時に(電池消費を抑える為に)プロセスに対して割り当てるプライオリティを、意図的に低く設定しているようです。
そこで、バッファリング間隔を
・フォアグラウンド時は50ms
・バックグラウンド移行後は500ms
という具合に、状態に応じて切り替える制御を実装する必要があります。
4. メインルーチンの別スレッド化
私のアプリの場合、メインルーチンは、CADisplayLink(垂直同期)の仕組みを使って1秒間に60回呼び出される形になっています。しかし、バックグラウンド移行後は(アプリに対して垂直同期時に割り込み通知をする必要が無いため)それが呼び出されなくなってしまいます。そこで、バックグラウンド移行後は、メインルーチンの呼び出しを別スレッドで行うようにする必要があります。
5. デバイスロスト(割り込み)の対処
従来の私のiPhoneアプリは、ホーム画面に戻った場合、プロセスを停止するようにしていました。しかし、バックグラウンドでの動作(※サスペンドを含む)を想定する場合、OpenALのデバイスロストを検知した時の処理を実装しなければなりません。OpenALのデバイスロストが発生すると、割り込みにより、予め定義したコールバック処理が実行される仕組みになっています。そのコールバック処理で、適切な復旧処理を行う必要があります。
ちなみに、コールバックが未登録の場合、デバイスロストが発生しても、特にエラーが発生せずに処理を続行します。しかし、その状態(適切な復旧処理を行っていない状態)では、音が鳴らなくなってしまうので、注意する必要があります。
なお、割り込みは、競合するオーディオデバイスを使用するアプリを起動した時に発生します。分かり易い例としては、アプリが動作中に電話が掛ってきた時とか。
こんな感じです。
東方VGSをバックグラウンド再生に対応させるため、これだけのことをやりました。割と大変でした・・・大変だったけど、結構沢山の方から要望を頂いたので、速めに対応した方が良さそうだということで、予定外のバージョンアップで対応することにしました。(本当は、妖々夢の全曲が揃ってからアップするつもりでしたが、それでは遅すぎるだろうと思ったので)
今回の敗因は、「iPhoneではバックグラウンド動作はできない」と私が勝手に思い込んでいたことかな。いわゆる「だろう設計」ってヤツです。Appleの設計思想は、そんなにコロコロ変わらないだろうと勝手にイメージしていましたが、どうやら、そうでもなかったようです。