Thursday, August 28, 2014

java.lang.UnsupportedOperationException: Effect library not loaded について

多分旧JUST PLAYERから引き継いでいた不具合だとおもうのですが、今日は少し進展がありました。

具体的には下記のようなエラー

java.lang.RuntimeException: Unable to create service jp.co.kayo.android.localplayer.service.MediaPlayerService: java.lang.UnsupportedOperationException: Effect library not loaded
at android.app.ActivityThread.handleCreateService(ActivityThread.java:2314)
at android.app.ActivityThread.access$1700(ActivityThread.java:129)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1228)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4475)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:792)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:559)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.UnsupportedOperationException: Effect library not loaded
at android.media.audiofx.AudioEffect.(AudioEffect.java:384)
at android.media.audiofx.Equalizer.(Equalizer.java:146)
at jp.co.kayo.android.localplayer.media.AudioEffect.attach(AudioEffect.java:120)
at jp.co.kayo.android.localplayer.media.MediaController$GaplessMediaPlayer.setTrack(MediaController.java:758)
at jp.co.kayo.android.localplayer.media.MediaController.init(MediaController.java:90)
at jp.co.kayo.android.localplayer.service.MediaPlayerService.onCreate(MediaPlayerService.java:57)
at android.app.ActivityThread.handleCreateService(ActivityThread.java:2304)
... 10 more

これは一つ前のポストでも取り扱っていた不具合ですが、単純にエラーの原因をみると、Equalizerの生成ができなくてエラーになっています。
エラーの内容が「 Effect library not loaded」なのでサポートされていない端末だからエラーになったのかな?と思ってしまうのですが、現象をみると動く場合もあるのでそういう問題ではないです。
なので、他の原因によって生成が失敗してしまったということだとおもいます。
この例外をGoogleで検索したところいくつかヒットするのですが、その中でも興味深いの次のリンクです。

http://stackoverflow.com/questions/10536170/equalizer-not-always-supported-even-when-api-9

返答は、Eqauzlierのreleaseをしていないから

多分そうだとおもいます。

だけど、EqualizerのReleaseのタイミングはけっこう難しいです。なぜなら音楽プレイヤーのほとんどはServiceで制御するように実装します。
つまりMediaPlayerのインスタンスはServiceが保持するので、必然的にそれに紐づくEqualizer等のAudioEffectはServiceが保持することになります。
しかし、Serviceの場合、onDestroyが呼ばれないケースが存在します。
だから、EqualizerのReleaseのタイミングを逃すケースが存在するのです。
おそらく、上記の不具合はそのようなケースにおいて発生するのでしょう。

多くの端末では、1度や2度Release漏れがあっても問題なく再生できるし、またほっとけば自動的にReleaseされて正常になりますが、そうでない端末もあるようです。
現に私が常時利用しているNexusではそのようなことが発生したことがないです。

今日、たまたまArrowsの端末を使ってテストをしていたら偶然上記の不具合が発生しました。
そして、その理由を考察するにあたり、「APKのインストールを繰り返す」
からではないかと考えています。
理由は、APKのインストールをすると、Serviceは強制的に終了させられるので、onDestoryが呼ばれません。

だいたい原因がわかったので対策をすることにしました。
ひとまず、2つの対策をしてみます。

1 Serviceが強制終了しreleaseが行われなかったとしてもEqualizerのインスタンスは再利用されるように、staticにして保持しておく。

2 とにかく、生成に失敗してもアプリが終了しないようにtry-cacheをしておく。
もちろん、nullになるので次回リクエストのタイミングで再度生成を行う。


                try {
                    Equalizer equalizer = new Equalizer(mPriority, audioSessionId);
                    if (supportFx(descriptor, equalizer.getDescriptor())) {
                        sEqualizer = equalizer;
                    } else {
                        equalizer.release();
                    }
                }catch (Exception e){
                    Log.e(TAG, "EqualizerのReleaseがうまくいってなくてこれ以上生成できないって言われてる。", e);
                }

これで様子を見てみようとおもいます。
手元の端末では一応動作しているのですが、、

ちなみにリリースですが今日中は無理かな、、、
プレイリストの実装がもう少しかかりそうです。

No comments:

Post a Comment