上面两篇简单的分析了,android系统中FrameWork中对于音量的调节的部分代码,可能有些更深入的东西并没有涉及,因为初次尝试分析,并不是所有东西都能完全明白和透彻的理解,所以暂时只能将我所了解到并用到的部分做了解析。
这篇主要想解析下在AudioManager中对于音频竞争机制的部分内容和使用方式。
首先来说下这中竞争机制的产生原因,根据我的理解因为Android系统中存在众多音频类型,并且他们相互之间都保持独立的存在,并不会相互影响。如音乐的声音,按键的触摸声音,响铃的声音,通话的声音,蓝牙通话的声音,错误报警的声音等等。都会有一个响应的声音类型。因此他们之间也会有独立的音频流来控制播放。为了防止这些声音会相互产生影响,竞争机制就产生了,这个机制有效的控制了这部分声音的播放的优先级已经是否存在互斥,共存等独立的关系,每个音频流在播放时都会通过这中机制获取播放的许可,使其可以被监控状态,便于管理。
对于这种机制,其中核心内容就是音频焦点的管理。
下面会贴出部分代码
[java] view
plaincopy
-
-
-
-
-
-
public static final int AUDIOFOCUS_GAIN = 1;
-
-
-
-
-
-
-
-
public static final int AUDIOFOCUS_GAIN_TRANSIENT = 2;
-
-
-
-
-
-
-
-
-
-
public static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3;
-
-
-
-
-
public static final int AUDIOFOCUS_LOSS = -1 * AUDIOFOCUS_GAIN;
-
-
-
-
-
public static final int AUDIOFOCUS_LOSS_TRANSIENT = -1 * AUDIOFOCUS_GAIN_TRANSIENT;
-
-
-
-
-
-
-
public static final int AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK =
-
-1 * AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK;
上述代码也是存在于androidframeworksasemediajavaandroidmediaAudioManager.java中的,先给出部分定义。
AUDIOFOCUS_GAIN -- 持久焦点,详情见注释部分,用来播放较长一段时间的音频,之前的音频焦点使用者需停止声音。
AUDIOFOCUS_GAIN_TRANSIENT --瞬态焦点,用来播放很短时间的音频,之前的焦点使用者需暂停声音。
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK --瞬态焦点,用来播放时间较短的音频,之前的音频焦点使用者需降低本身音量。
AUDIOFOCUS_LOSS -- 失去焦点,表明持续焦点使用者失去音频焦点。
AUDIOFOCUS_LOSS_TRANSIENT -- 失去焦点,表明瞬态焦点使用者失去音频焦点。
AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -- 失去焦点,表明瞬态焦点使用者即降低本身音量的焦点使用者失去音频焦点。
上述定义都是需要在请求音频焦点时指定的参数,接下来继续解析音频焦点的请求。
[java] view
plaincopy
-
-
-
-
public static final int AUDIOFOCUS_REQUEST_FAILED = 0;
-
-
-
-
public static final int AUDIOFOCUS_REQUEST_GRANTED = 1;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
public int requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint) {
-
int status = AUDIOFOCUS_REQUEST_FAILED;
-
if ((durationHint < AUDIOFOCUS_GAIN) || (durationHint > AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK))
-
{
-
Log.e(TAG, "Invalid duration hint, audio focus request denied");
-
return status;
-
}
-
registerAudioFocusListener(l);
-
-
IAudioService service = getService();
-
try {
-
status = service.requestAudioFocus(streamType, durationHint, mICallBack,
-
mAudioFocusDispatcher, getIdForAudioFocusListener(l),
-
mContext.getPackageName() );
-
}catch (RemoteException e) {
-
Log.e(TAG, "Can't call requestAudioFocus() on AudioService due to "+e);
-
}
-
return status;
-
}
-
-
-
-
-
-
-
-
-
-
-
-
public void requestAudioFocusForCall(int streamType, int durationHint) {
-
IAudioService service = getService();
-
try {
-
service.requestAudioFocus(streamType, durationHint, mICallBack, null,
-
AudioService.IN_VOICE_COMM_FOCUS_ID,
-
"system" );
-
}catch (RemoteException e) {
-
Log.e(TAG, "Can't call requestAudioFocusForCall() on AudioService due to "+e);
-
}
-
}
-
-
-
-
-
-
-
-
public void abandonAudioFocusForCall() {
-
IAudioService service = getService();
-
try {
-
service.abandonAudioFocus(null, AudioService.IN_VOICE_COMM_FOCUS_ID);
-
} catch (RemoteException e) {
-
Log.e(TAG, "Can't call abandonAudioFocusForCall() on AudioService due to "+e);
-
}
-
}
-
-
-
-
-
-
-
public int abandonAudioFocus(OnAudioFocusChangeListener l) {
-
int status = AUDIOFOCUS_REQUEST_FAILED;
-
unregisterAudioFocusListener(l);
-
IAudioService service = getService();
-
try {
-
status = service.abandonAudioFocus(mAudioFocusDispatcher,
-
getIdForAudioFocusListener(l));
-
} catch (RemoteException e) {
-
Log.e(TAG, "Can't call abandonAudioFocus() on AudioService due to "+e);
-
}
-
return status;
-
}
上面的代码主要贴出了请求和释放音频焦点的两个操作的函数,对于请求操作
requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint)有三个参数
第一个参数:需要写一个音频焦点的监听,可以如下
[java] view
plaincopy
-
OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() {
-
public void onAudioFocusChange(int focusChange) {
-
if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT
-
-
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
-
-
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
-
am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
-
am.abandonAudioFocus(afChangeListener);
-
-
}
-
}
-
};
第二个参数:需要制定音频流的类型,如第一篇所描述的STREAM_MUSIC,STREAM_RING,STREAM_SYSTEM等等。
第三个参数:这个参数就是这篇开始的时候所列举的前三个音频焦点类型了。
请求函数如果成功的话会返回AUDIOFOCUS_REQUEST_GRANTED 失败则返回 AUDIOFOCUS_REQUEST_FAILED
请求的方法可参考如下:
[java] view
plaincopy
-
AudioManager am = mContext.getSystemService(Context.AUDIO_SERVICE);
-
...
-
-
-