说实话,android的代码是越来越难以阅读。业务函数里面狗皮膏药似的补丁与日俱增。继上篇简要介绍音频焦点的文章,这篇文章的主要内容是分析audiofocus的实现。看了一下午的相关代码都没找到做audiofocus策略的核心逻辑。目前能看懂的大概包含下面两个逻辑。欢迎评论区沟通。
audiofocus实现的核心代码是在project_dir/frameworks/base/services/core/java/com/android/server/audio/MediaFocusControl.java
project_dir/frameworks/base/services/core/java/com/android/server/audio/FocusRequester.java
project_dir在这里指代android源码的根目录。
1.MediaFocusControl会维护所有audiofocus申请信息的堆栈mFocusStack。
2.android当系统进入铃声或者通话状态,会静音住媒体播放器,代码片段如下,mRingOrCallActive变量会在应用申请焦点时进行判断刷新。
if (mRingOrCallActive) {
mFocusEnforcer.mutePlayersForCall(USAGES_TO_MUTE_IN_RING_OR_CALL);
} else {
mFocusEnforcer.unmutePlayersForCall();
}
3.audiofocus的监听器都是在AudioManager的队列里维护。代码如下:
public void registerAudioFocusRequest(@NonNull AudioFocusRequest afr) {
final Handler h = afr.getOnAudioFocusChangeListenerHandler();
final FocusRequestInfo fri = new FocusRequestInfo(afr, (h == null) ? null :
new ServiceEventHandlerDelegate(h).getHandler());
final String key = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener());
mAudioFocusIdListenerMap.put(key, fri);
}
4.audiomanager进行焦点变化通知的核心类IAudioFocusDispatcher会调用listener。IAudioFocusDispatcher
自身会被注册给audioservice。
status = service.requestAudioFocus(afr.getAudioAttributes(),
afr.getFocusGain(), mICallBack,
mAudioFocusDispatcher,
clientId,
getContext().getOpPackageName() /* package name */, afr.getFlags(),
ap != null ? ap.cb() : null,
sdk);
阅读代码期间出现重大错误,阅读函数handleFocusLossFromGain的时候,认为gain是增益的含义,没仔细阅读实现。导致增加阅读理解代码的时间周期。gain在这里应该是对应焦点的第一种类型,永久性焦点。犯了惯性思维的错误。遇到这种与认知相悖的地方应该更加小心。gain在这块代码里面的含义是获得,与之对应的是loss。
androidaudio进行audiofocus控制决策的核心代码是下面这一段
if (mMultiAudioFocusEnabled
&& (focusChangeHint == AudioManager.AUDIOFOCUS_GAIN)) {
if (enteringRingOrCall) {
if (!mMultiAudioFocusList.isEmpty()) {
for (FocusRequester multifr : mMultiAudioFocusList) {
multifr.handleFocusLossFromGain(focusChangeHint, nfr, forceDuck);
}
}
} else {
boolean needAdd = true;
if (!mMultiAudioFocusList.isEmpty()) {
for (FocusRequester multifr : mMultiAudioFocusList) {
if (multifr.getClientUid() == Binder.getCallingUid()) {
needAdd = false;
break;
}
}
}
if (needAdd) {
mMultiAudioFocusList.add(nfr);
}
nfr.handleFocusGainFromRequest(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
notifyExtPolicyFocusGrant_syncAf(nfr.toAudioFocusInfo(),
AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
}
}
思考android Audio focus的设计时,我想到一个问题,如果某APP,先申请media类型的focus,然后再去申请call类型的focus会怎么样?