在开发音乐播放器的时候遇到开启均衡器然后切换歌曲会突然出现设备音量异常,然后调节侧边音量键,设备音量大小无变化,但是音量进度条有变化,只有杀掉应用进程后重新开启应用输出音量才恢复正常且音量大小受音量键调控;如下是输出异常日志:
08-31 13:45:27.370 D/EqualizerManager( 521): 6:setEnabled() called on uninitialized AudioEffect.
08-31 13:45:27.372 W/System.err( 521): java.lang.IllegalStateException: setEnabled() called on uninitialized AudioEffect.
08-31 13:45:27.374 W/System.err( 521): at android.media.audiofx.AudioEffect.checkState(AudioEffect.java:1257)
08-31 13:45:27.375 W/System.err( 521): at android.media.audiofx.AudioEffect.setEnabled(AudioEffect.java:516)
查看日志发现是uninitialized AudioEffect异常,我们先来看看在我们的代码中抛出该异常的位置,如图:
由上面代码可知setupVisualizerFxAndUI()方法调用一次则创建一个Equalizer对象,而setupVisualizerFxAndUI()的调用是每切换一首歌曲则调用一次,歌曲播放完了则release掉Equalizer,所以就造成了频繁创建Equalizer均衡器对象!
我们查看Equalizer类中的setEnabled方法中会调用父类AudioEffec的checkState方法检测当前状态,如果当前状态不是STATE_INITIALIZED则抛出uninitialized AudioEffect异常;checkState方法如下:
/**
* @hide
*/
public void checkState(String methodName) throws IllegalStateException {
synchronized (mStateLock) {
if (mState != STATE_INITIALIZED) {
throw (new IllegalStateException(methodName
+ " called on uninitialized AudioEffect."));
}
}
}
我们再来看看AudioEffect类源码发现只有在构造方式中会给mState赋值为STATE_INITIALIZED,而AudioEffect类的构造方法会在Equalizer类的构造方法中通过super调用
public AudioEffect(UUID type, UUID uuid, int priority, int audioSession)
throws IllegalArgumentException, UnsupportedOperationException,
RuntimeException {
int[] id = new int[1];
Descriptor[] desc = new Descriptor[1];
// native initialization
int initResult = native_setup(new WeakReference<AudioEffect>(this),
type.toString(), uuid.toString(), priority, audioSession, id,
desc, ActivityThread.currentOpPackageName());
if (initResult != SUCCESS && initResult != ALREADY_EXISTS) {
Log.e(TAG, "Error code " + initResult
+ " when initializing AudioEffect.");
switch (initResult) {
case ERROR_BAD_VALUE:
throw (new IllegalArgumentException("Effect type: " + type
+ " not supported."));
case ERROR_INVALID_OPERATION:
throw (new UnsupportedOperationException(
"Effect library not loaded"));
default:
throw (new RuntimeException(
"Cannot initialize effect engine for type: " + type
+ " Error: " + initResult));
}
}
mId = id[0];
mDescriptor = desc[0];
synchronized (mStateLock) {
mState = STATE_INITIALIZED;
}
}
所以由上面源码知道是AudioEffect初始化失败或同步锁异常而使mState没有赋值为 STATE_INITIALIZED,经分析发现造成这样的原因是频繁初始化AudioEffect。
解决方案:我们知道每个进程MediaPlayer.getAudioSessionId()返回的sessionId是一致的,所以在一个进程里只要创建一次Equalizer对象传入sessionId与MediaPlayer绑定就可以了,就能解决uninitialized AudioEffect异常的问题,也就解决了播放器音量失控的问题,修改后如下:
对了,在退出应用或者不需要均衡器的时候别忘了调用release()释放本机AudioEffect资源.