2012年3月8日木曜日

音が鳴らない問題 (更新3※解決)

今日、会社でINVADER BLOCK 2で遊んでいたのデバッグをしていたところ、何故か、音が鳴らない現象が発生し、一瞬「バグかな?」と思い、焦りました。

しかし、INVADER BLOCK 2のプロセスを止めて再起動しても現象が再発します。
なので、どうやら、INVADER BLOCK 2のバグではなさそうです。(推測ですが)

帰宅後にlogcatでログを確認してみたところ、AudioFlingerというプロセスが、「TrackBase::getBuffer buffer out of range:」みたいな感じのエラーを延々と出し続けていました。

AudioFlingerというのは、Androidの音声入出力を担うプログラムのようです。
ググればソースコードも見つかります。
問題のエラーを出している部分の実装は、以下のような感じでした。

■AudioFlinger.cppより抜粋
void* AudioFlinger::ThreadBase::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
    audio_track_cblk_t* cblk = this->cblk();
    int8_t *bufferStart = (int8_t *)mBuffer + (offset-cblk->serverBase)*cblk->frameSize;
    int8_t *bufferEnd = bufferStart + frames * cblk->frameSize;


    // Check validity of returned pointer in case the track control block would have been corrupted.
    if (bufferStart < mBuffer || bufferStart > bufferEnd || bufferEnd > mBufferEnd ||
        ((unsigned long)bufferStart & (unsigned long)(cblk->frameSize - 1))) {
        LOGE("TrackBase::getBuffer buffer out of range:\n    start: %p, end %p , mBuffer %p mBufferEnd %p\n    \
                server %d, serverBase %d, user %d, userBase %d, channels %d",
                bufferStart, bufferEnd, mBuffer, mBufferEnd,
                cblk->server, cblk->serverBase, cblk->user, cblk->userBase, cblk->channels);
        return 0;
    }


    return bufferStart;
}
※このソースのライセンスはApache License 2.0です

たぶん、波形情報のバッファを取り出して再生をおこなうための処理だと思います。
何らかの原因でバッファが不整合な状態になり、それが継続してしまい、音が鳴らなくなった・・・という感じでしょうか。

別のプログラムが不正なバッファを渡し続けていて、それに巻き込まれたのかな?
または、AudioFlingerの不良?

こういう場合の調査は、「非は自分にある」と断定してするのが鉄則なので、愚直にINVADER BLOCK 2の処理に問題がないのかも点検しておきます。

ちなみに、INVADER BLOCK 2は、OpenSLを使って音声出力の処理を行っていますが、OpenSL自体、まだ出て間もないもののようなので、OpenSLのバグという可能性も・・・まぁ、そこは気にせず、「非は自分にある」と断定して。


■追記1 (2012/03/09 00:30頃)
愚直にコードを見直してますが、「コレだ!」と確証の持てるバグは無いです。
あと、現象を再現させるために、色々怪しそうな操作をしていますが、一度も再現してません。
海外に幾らか同件と思しき現象の報告のようなものがありますが、解決はしていなさそう。
ちょっと、OS側のソースを解析してみようか考え中。(今日はもうやりませんが)



■追記2 (2012/03/10 00:30頃)
やはり、アプリケーション(INVADER BLOCK 2)の問題ではなさそうな気がします。
そもそも、アプリのプロセスを止めているのに発生し続けていた時点で、その点は確定ですが。
(この問題が発生すると、Androidを再起動するまで現象が発生し続けます)

仮に、アプリレベルで引き起こせる問題だと、もっと世界中で大問題になっている筈。
それにしては、情報が少な過ぎます。
同件と思しき現象が発生しているっぽい情報は以下。(2009年の情報)
http://code.google.com/p/android/issues/detail?id=3197

ちなみにこの現象ですが、開発中は1回も発生したことが無いです。
開発が終了した3月1日に、ちょっとした勘違いでOSのアップデートをしてしまったのですが、それ以降発生したという点がちょっと怪しい。つまり、OSがアップデートでデグった可能性もゼロではないのではないかと。ちなみに、現象が発生したOSは、現時点(3月10日時点)でLenovoの IdeaPad Tablet A1 に適用できる最新のAndroid 2.3.4。(リリースされてから日が浅いため、情報が少ないとか)

もうひとつ、考えられるのが、常駐プログラムの不具合。
OSの不具合だとすると情報が少な過ぎるので、可能性としてはそっちの方が高い。
ちなみに、私の端末で常駐させているプロセスは、

①設定
②Androidシステム
③Googleサービス
④マップ
⑤GO Keyboard for Lenovo

とりあえず、「④マップ」は要らないので消そうとしたところ、結構中核のもの?っぽいことが書いてあったし、音は出さないだろうから放置で。

「⑤GO Keyboard for Lenovo」は音を出すアプリなのでちょっと関係しそう。
念のため、普通のAndroidキーボード(無音)に変更。
この状態で再発したら、再び更新します。
それまで様子見。



■追記3 (2012/03/18 00:30頃)
再現はしてませんが、OS側の実装を調査した結果、原因が判明しました。
INVADER BLOCK 2のバグということになります。
修正版のINVADER BLOCK 2は先ほどリリースしました。


で、問題の原因ですが、OpenSLのリソース解放関連の処理手続きに問題がありました。
解放(Destroy)を行う前にSetPlayStateでSL_PLAYSTATE_STOPPEDにする必要があるようです。
SL_PLAYSTATE_STOPPEDとDestroyでググれば、色々と情報が出てきました。
↓日本語の情報も有りました。
http://www.ku6.jp/report/5.html 



上記記事で書かれている通り、SL_PLAYSTATE_STOPPEDにしなければなりませんそうしないと、音声バッファが不整合な状態になることで、AudioFlingerにヘンなデータが渡ってしまい、結果として「TrackBase::getBuffer buffer out of range」の洪水が起きる形になり得ます。

0 件のコメント:

コメントを投稿

注: コメントを投稿できるのは、このブログのメンバーだけです。

合理的ではないものを作りたい

ここ最近、実機版の東方VGSの開発が忙しくて、東方VGSの曲追加が滞っています。 東方VGS(実機版)のデザインを作りながら検討中。基本レトロUIベースですがシークバーはモダンに倣おうかな…とか pic.twitter.com/YOYprlDsYD — SUZUKI PLAN (...