CarZonesAudioFocus 继承于AudioPolicy.AudioPolicyFocusListener,当有音频焦点请求时就会调用到CarZonesAudioFocus的onAudioFocusRequest方法:
//packages/services/Car/service/src/com/android/car/audio/CarZonesAudioFocus.java
final class CarZonesAudioFocus extends AudioPolicy.AudioPolicyFocusListener {
private final SparseArray<CarAudioFocus> mFocusZones;
public void onAudioFocusRequest(AudioFocusInfo afi, int requestResult) {
int zoneId = getAudioZoneIdForAudioFocusInfo(afi); //通过AudioFocusInfo获取zoneId
getCarAudioFocusForZoneId(zoneId).onAudioFocusRequest(afi, requestResult); //调用CarAudioFocus的onAudioFocusRequest方法
notifyFocusCallback(new int[]{zoneId}); //通知音频焦点回调
}
}
上面方法进行如下处理:
调用getAudioZoneIdForAudioFocusInfo方法获取zoneId。
调用CarAudioFocus的onAudioFocusRequest方法,进行音频焦点仲裁。
调用notifyFocusCallback方法,进行Ducking处理。
getAudioZoneIdForAudioFocusInfo
调用getAudioZoneIdForAudioFocusInfo方法获取zoneId:
//packages/services/Car/service/src/com/android/car/audio/CarZonesAudioFocus.java
final class CarZonesAudioFocus extends AudioPolicy.AudioPolicyFocusListener {
private int getAudioZoneIdForAudioFocusInfo(AudioFocusInfo afi) {
int zoneId = mCarAudioService.getZoneIdForUid(afi.getClientUid());
// If the bundle attribute for AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID has been assigned
// Use zone id from that instead.
Bundle bundle = afi.getAttributes().getBundle();
if (bundle != null) {
int bundleZoneId =
bundle.getInt(CarAudioManager.AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID,
-1);
// check if the zone id is within current zones bounds
if (mCarAudioService.isAudioZoneIdValid(bundleZoneId)) {
Slogf.d(TAG, "getFocusForAudioFocusInfo valid zoneId %d with bundle request for"
+ " client %s", bundleZoneId, afi.getClientId());
zoneId = bundleZoneId;
} else {
Slogf.w(TAG, "getFocusForAudioFocusInfo invalid zoneId %d with bundle request for "
+ "client %s, dispatching focus request to zoneId %d", bundleZoneId,
afi.getClientId(), zoneId);
}
}
return zoneId;
}
}
onAudioFocusRequest
调用CarAudioFocus的onAudioFocusRequest方法:
//packages/services/Car/service/src/com/android/car/audio/CarAudioFocus.java
class CarAudioFocus extends AudioPolicy.AudioPolicyFocusListener {
public void onAudioFocusRequest(AudioFocusInfo afi, int requestResult) {
int response;
AudioPolicy policy;
synchronized (mLock) {
policy = mAudioPolicy;
response = evaluateFocusRequestLocked(afi); //评估焦点请求
}
// Post our reply for delivery to the original focus requester
mAudioManager.setFocusRequestResult(afi, response, policy); //设置音频焦点请求结果
logFocusEvent("onAudioFocusRequest for client " + afi.getClientId()
+ " with gain type " + focusEventToString(afi.getGainRequest())
+ " resulted in " + focusRequestResponseToString(response));
}
}
CarAudioFocus .evaluateFocusRequestLocked
调用evaluateFocusRequestLocked评估焦点请求:
//packages/services/Car/service/src/com/android/car/audio/CarAudioFocus.java
class CarAudioFocus extends AudioPolicy.AudioPolicyFocusListener {
private int evaluateFocusRequestLocked(AudioFocusInfo afi) {
Slogf.i(TAG, "Evaluating " + focusEventToString(afi.getGainRequest())
+ " request for client " + afi.getClientId()
+ " with usage " + usageToString(afi.getAttributes().getUsage()));
if (mIsFocusRestricted) {
int audioContext = CarAudioContext.getContextForAttributes(afi.getAttributes());
if (!isCriticalAudioContext(audioContext)) {
return AUDIOFOCUS_REQUEST_FAILED;
}
}
// Is this a request for premanant focus?
// AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE -- Means Notifications should be denied
// AUDIOFOCUS_GAIN_TRANSIENT -- Means current focus holders should get transient loss
// AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK -- Means other can duck (no loss message from us)
// NOTE: We expect that in practice it will be permanent for all media requests and
// transient for everything else, but that isn't currently an enforced requirement.
final boolean permanent =
(afi.getGainRequest() == AUDIOFOCUS_GAIN);
final boolean allowDucking =
(afi.getGainRequest() == AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
boolean delayFocusForCurrentRequest = false;
int requestedContext = CarAudioContext.getContextForAttributes(afi.getAttributes());
// If we happen to find entries that this new request should replace, we'll store them here.
// This happens when a client makes a second AF request on the same listener.
// After we've granted audio focus to our current request, we'll abandon these requests.
FocusEntry replacedCurrentEntry = null;
FocusEntry replacedBlockedEntry = null;
boolean allowDelayedFocus = canReceiveDelayedFocus(afi); //可以接收延迟聚焦
// We don't allow sharing listeners (client IDs) between two concurrent requests
// (because the app would have no way to know to which request a later event applied)
if (mDelayedRequest != null && afi.getClientId().equals(mDelayedRequest.getClientId())) {
int delayedRequestedContext = CarAudioContext.getContextForAttributes(
mDelayedRequest.getAttributes());
// If it is for a different context then reject
if (delayedRequestedContext != requestedContext) {
// Trivially reject a request for a different USAGE
Slogf.e(TAG, "Client %s has already delayed requested focus for %s - cannot request"
+ " focus for %s on same listener.", mDelayedRequest.getClientId(),
usageToString(mDelayedRequest.getAttributes().getUsage()),
usageToString(afi.getAttributes().getUsage()));
return AUDIOFOCUS_REQUEST_FAILED;
}
}
// Scan all active and pending focus requests. If any should cause rejection of
// this new request, then we're done. Keep a list of those against whom we're exclusive
// so we can update the relationships if/when we are sure we won't get rejected.
Slogf.i(TAG, "Scanning focus holders...");
final ArrayList<FocusEntry> losers = new ArrayList<FocusEntry>();
for (FocusEntry entry : mFocusHolders.values()) { //扫描拥有焦点者
Slogf.d(TAG, "Evaluating focus holder: " + entry.getClientId());
// If this request is for Notifications and a current focus holder has specified
// AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE, then reject the request.
// This matches the hardwired behavior in the default audio policy engine which apps
// might expect (The interaction matrix doesn't have any provision for dealing with
// override flags like this).
if ((requestedContext == CarAudioContext.NOTIFICATION)
&& (entry.getAudioFocusInfo().getGainRequest()
== AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)) {
return AUDIOFOCUS_REQUEST_FAILED;
}
// We don't allow sharing listeners (client IDs) between two concurrent requests
// (because the app would have no way to know to which request a later event applied)
if (afi.getClientId().equals(entry.getAudioFocusInfo().getClientId())) {
if ((entry.getAudioContext() == requestedContext)
|| canSwapCallOrRingerClientRequest(afi.getClientId(),
entry.getAudioContext(), requestedContext)) {
// This is a request from a current focus holder.
// Abandon the previous request (without sending a LOSS notification to it),
// and don't check the interaction matrix for it.
Slogf.i(TAG, "Replacing accepted request from same client: %s",
afi.getClientId());
replacedCurrentEntry = entry;
continue;
} else {
// Trivially reject a request for a different USAGE
Slogf.e(TAG, "Client %s has already requested focus for %s - cannot request "
+ "focus for %s on same listener.", entry.getClientId(),
usageToString(entry.getAudioFocusInfo().getAttributes().getUsage()),
usageToString(afi.getAttributes().getUsage()));
return AUDIOFOCUS_REQUEST_FAILED;
}
}
int interactionResult = mFocusInteraction.evaluateRequest(requestedContext, entry,
losers, allowDucking, allowDelayedFocus); //基于交互矩阵评估传入焦点与当前焦点请求之间的交互
if (interactionResult == AUDIOFOCUS_REQUEST_FAILED) { //失败
return interactionResult;
}
if (interactionResult == AUDIOFOCUS_REQUEST_DELAYED) { //延迟
delayFocusForCurrentRequest = true;
}
}
Slogf.i(TAG, "Scanning those who've already lost focus...");
final ArrayList<FocusEntry> blocked = new ArrayList<FocusEntry>();
for (FocusEntry entry : mFocusLosers.values()) { //扫描失去焦点者
Slogf.i(TAG, entry.getAudioFocusInfo().getClientId());
// If this request is for Notifications and a pending focus holder has specified
// AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE, then reject the request
if ((requestedContext == CarAudioContext.NOTIFICATION)
&& (entry.getAudioFocusInfo().getGainRequest()
== AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)) {
return AUDIOFOCUS_REQUEST_FAILED;
}
// We don't allow sharing listeners (client IDs) between two concurrent requests
// (because the app would have no way to know to which request a later event applied)
if (afi.getClientId().equals(entry.getAudioFocusInfo().getClientId())) {
if (entry.getAudioContext() == requestedContext) {
// This is a repeat of a request that is currently blocked.
// Evaluate it as if it were a new request, but note that we should remove
// the old pending request, and move it.
// We do not want to evaluate the new request against itself.
Slogf.i(TAG, "Replacing pending request from same client");
replacedBlockedEntry = entry;
continue;
} else {
// Trivially reject a request for a different USAGE
Slogf.e(TAG, "Client %s has already requested focus for %s - cannot request "
+ "focus for %s on same listener.", entry.getClientId(),
usageToString(entry.getAudioFocusInfo().getAttributes().getUsage()),
usageToString(afi.getAttributes().getUsage()));
return AUDIOFOCUS_REQUEST_FAILED;
}
}
int interactionResult = mFocusInteraction
.evaluateRequest(requestedContext, entry, blocked, allowDucking,
allowDelayedFocus); //基于交互矩阵评估传入焦点与当前焦点请求之间的交互
if (interactionResult == AUDIOFOCUS_REQUEST_FAILED) { //失败
return interactionResult;
}
if (interactionResult == AUDIOFOCUS_REQUEST_DELAYED) { //延迟
delayFocusForCurrentRequest = true;
}
}
// Now that we've decided we'll grant focus, construct our new FocusEntry
// 现在我们已经决定授予焦点,构建我们的新焦点条目
FocusEntry newEntry = new FocusEntry(afi, requestedContext, mPackageManager);
// 由于此请求,这些条目已永久失去焦点,因此应从所有阻止程序列表中删除它们。
// These entries have permanently lost focus as a result of this request, so they
// should be removed from all blocker lists.
ArrayList<FocusEntry> permanentlyLost = new ArrayList<>();
if (replacedCurrentEntry != null) {
mFocusHolders.remove(replacedCurrentEntry.getClientId());
permanentlyLost.add(replacedCurrentEntry);
}
if (replacedBlockedEntry != null) {
mFocusLosers.remove(replacedBlockedEntry.getClientId());
permanentlyLost.add(replacedBlockedEntry);
}
// 现在我们确定我们会接受此请求,请更新我们将要更新的任何请求
// Now that we're sure we'll accept this request, update any requests which we would
// block but are already out of focus but waiting to come back
for (FocusEntry entry : blocked) {
// If we're out of focus it must be because somebody is blocking us
assert !entry.isUnblocked();
if (permanent) {
// This entry has now lost focus forever
sendFocusLossLocked(entry.getAudioFocusInfo(), AUDIOFOCUS_LOSS); //发送焦点失去消息
entry.setDucked(false);
final FocusEntry deadEntry = mFocusLosers.remove(
entry.getAudioFocusInfo().getClientId());
assert deadEntry != null;
permanentlyLost.add(entry);
} else {
if (!allowDucking && entry.isDucked()) {
// This entry was previously allowed to duck, but can no longer do so.
Slogf.i(TAG, "Converting duckable loss to non-duckable for "
+ entry.getClientId());
sendFocusLossLocked(entry.getAudioFocusInfo(), AUDIOFOCUS_LOSS_TRANSIENT); //发送焦点短暂失去消息
entry.setDucked(false);
}
// Note that this new request is yet one more reason we can't (yet) have focus
entry.addBlocker(newEntry);
}
}
// Notify and update any requests which are now losing focus as a result of the new request
// 通知并更新由于新请求而失去焦点的任何请求
for (FocusEntry entry : losers) {
// If we have focus (but are about to loose it), nobody should be blocking us yet
assert entry.isUnblocked();
int lossType;
if (permanent) {
lossType = AUDIOFOCUS_LOSS; //失去焦点
} else if (allowDucking && entry.receivesDuckEvents()) {
lossType = AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK; //失去焦点并且进行Duck处理
entry.setDucked(true);
} else {
lossType = AUDIOFOCUS_LOSS_TRANSIENT; //暂时失去
}
sendFocusLossLocked(entry.getAudioFocusInfo(), lossType); //发送焦点失去消息
// The entry no longer holds focus, so take it out of the holders list
mFocusHolders.remove(entry.getAudioFocusInfo().getClientId());
if (permanent) {
permanentlyLost.add(entry);
} else {
// Add ourselves to the list of requests waiting to get focus back and
// note why we lost focus so we can tell when it's time to get it back
mFocusLosers.put(entry.getAudioFocusInfo().getClientId(), entry);
entry.addBlocker(newEntry);
}
}
// Now that all new blockers have been added, clear out any other requests that have been
// permanently lost as a result of this request. Treat them as abandoned - if they're on
// any blocker lists, remove them. If any focus requests become unblocked as a result,
// re-grant them. (This can happen when a GAIN_TRANSIENT_MAY_DUCK request replaces a
// GAIN_TRANSIENT request from the same listener.)
for (FocusEntry entry : permanentlyLost) {
Slogf.d(TAG, "Cleaning up entry " + entry.getClientId());
removeBlockerAndRestoreUnblockedWaitersLocked(entry);
}
if (delayFocusForCurrentRequest) {
swapDelayedAudioFocusRequestLocked(afi);
return AUDIOFOCUS_REQUEST_DELAYED;
}
mFocusHolders.put(afi.getClientId(), newEntry);
Slogf.i(TAG, "AUDIOFOCUS_REQUEST_GRANTED");
return AUDIOFOCUS_REQUEST_GRANTED;
}
}
CarAudioFocus.sendFocusLossLocked
调用sendFocusLossLocked发送焦点失去消息:
//packages/services/Car/service/src/com/android/car/audio/CarAudioFocus.java
class CarAudioFocus extends AudioPolicy.AudioPolicyFocusListener {
private final AudioManager mAudioManager;
private void sendFocusLossLocked(AudioFocusInfo loser, int lossType) {
int result = mAudioManager.dispatchAudioFocusChange(loser, lossType,
mAudioPolicy); //通过AudioManager通知具有焦点侦听器的应用程序音频焦点的变化
if (result != AUDIOFOCUS_REQUEST_GRANTED) {
// TODO: Is this actually an error, or is it okay for an entry in the focus stack
// to NOT have a listener? If that's the case, should we even keep it in the focus
// stack?
Slogf.e(TAG, "Failure to signal loss of audio focus with error: " + result);
}
logFocusEvent("sendFocusLoss for client " + loser.getClientId()
+ " with loss type " + focusEventToString(lossType)
+ " resulted in " + focusRequestResponseToString(result));
}
}
AudioManager dispatchAudioFocusChange
通过AudioManager通知具有焦点侦听器的应用程序音频焦点的变化:
//frameworks/base/media/java/android/media/AudioManager.java
public class AudioManager {
//Notifies an application with a focus listener of gain or loss of audio focus.
//通知具有焦点侦听器的应用程序音频焦点的增益或损失。
public int dispatchAudioFocusChange(@NonNull AudioFocusInfo afi, int focusChange,
@NonNull AudioPolicy ap) {
if (afi == null) {
throw new NullPointerException("Illegal null AudioFocusInfo");
}
if (ap == null) {
throw new NullPointerException("Illegal null AudioPolicy");
}
final IAudioService service = getService(); //获取IAudioService对象
try {
return service.dispatchFocusChange(afi, focusChange, ap.cb()); //调用IAudioService的dispatchFocusChange方法
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
调用IAudioService的dispatchFocusChange方法,IAudioService是一个接口,由AudioService的dispatchFocusChange方法实现:
//frameworks/base/service/java/com/android/server/audio/AudioService.java
public class AudioService extends IAudioService.Stub
private final MediaFocusControl mMediaFocusControl;
public int dispatchFocusChange(AudioFocusInfo afi, int focusChange, IAudioPolicyCallback pcb) {
if (afi == null) {
throw new IllegalArgumentException("Illegal null AudioFocusInfo");
}
if (pcb == null) {
throw new IllegalArgumentException("Illegal null AudioPolicy callback");
}
synchronized (mAudioPolicies) {
if (!mAudioPolicies.containsKey(pcb.asBinder())) {
throw new IllegalStateException("Unregistered AudioPolicy for focus dispatch");
}
return mMediaFocusControl.dispatchFocusChange(afi, focusChange); //调用MediaFocusControl的dispatchFocusChange方法
}
}
}
调用MediaFocusControl的dispatchFocusChange方法:
//frameworks/base/service/java/com/android/server/audio/MediaFocusControl.java
public class MediaFocusControl implements PlayerFocusEnforcer {
int dispatchFocusChange(AudioFocusInfo afi, int focusChange) {
if (DEBUG) {
Log.v(TAG, "dispatchFocusChange " + focusChange + " to afi client="
+ afi.getClientId());
}
synchronized (mAudioFocusLock) {
if (mFocusPolicy == null) {
if (DEBUG) { Log.v(TAG, "> failed: no focus policy" ); }
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
}
final FocusRequester fr;
if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
fr = mFocusOwnersForFocusPolicy.remove(afi.getClientId());
} else {
fr = mFocusOwnersForFocusPolicy.get(afi.getClientId());
}
if (fr == null) {
if (DEBUG) { Log.v(TAG, "> failed: no such focus requester known" ); }
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
}
return fr.dispatchFocusChange(focusChange); //调用FocusRequester的dispatchFocusChange方法
}
}
}
调用FocusRequester的dispatchFocusChange方法:
//frameworks/base/service/java/com/android/server/audio/FocusRequester.java
public class FocusRequester {
int dispatchFocusChange(int focusChange) {
final IAudioFocusDispatcher fd = mFocusDispatcher;
if (fd == null) {
if (MediaFocusControl.DEBUG) { Log.e(TAG, "dispatchFocusChange: no focus dispatcher"); }
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
}
if (focusChange == AudioManager.AUDIOFOCUS_NONE) {
if (MediaFocusControl.DEBUG) { Log.v(TAG, "dispatchFocusChange: AUDIOFOCUS_NONE"); }
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
} else if ((focusChange == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
|| focusChange == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE
|| focusChange == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT
|| focusChange == AudioManager.AUDIOFOCUS_GAIN)
&& (mFocusGainRequest != focusChange)){
Log.w(TAG, "focus gain was requested with " + mFocusGainRequest
+ ", dispatching " + focusChange);
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK
|| focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT
|| focusChange == AudioManager.AUDIOFOCUS_LOSS) {
mFocusLossReceived = focusChange;
}
try {
fd.dispatchAudioFocusChange(focusChange, mClientId); //调用IAudioFocusDispatcher的dispatchAudioFocusChange方法
} catch (android.os.RemoteException e) {
Log.e(TAG, "dispatchFocusChange: error talking to focus listener " + mClientId, e);
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
}
return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
}
}
调用IAudioFocusDispatcher的dispatchAudioFocusChange方法,IAudioFocusDispatcher是一个接口,由AudioManager实现:
//frameworks/base/media/java/android/media/AudioManager.java
public class AudioManager {
private final IAudioFocusDispatcher mAudioFocusDispatcher = new IAudioFocusDispatcher.Stub() {
@Override
public void dispatchAudioFocusChange(int focusChange, String id) {
final FocusRequestInfo fri = findFocusRequestInfo(id);
if (fri != null) {
final OnAudioFocusChangeListener listener =
fri.mRequest.getOnAudioFocusChangeListener();
if (listener != null) {
final Handler h = (fri.mHandler == null) ?
mServiceEventHandlerDelegate.getHandler() : fri.mHandler;
final Message m = h.obtainMessage(
MSSG_FOCUS_CHANGE/*what*/, focusChange/*arg1*/, 0/*arg2 ignored*/, //获取要发送的消息
id/*obj*/);
h.sendMessage(m); //发送消息
}
}
}
};
}
发送MSSG_FOCUS_CHANGE消息,AudioManager的内部类ServiceEventHandlerDelegate的handleMessage方法会处理这个消息:
//frameworks/base/media/java/android/media/AudioManager.java
public class AudioManager {
private class ServiceEventHandlerDelegate {
private final Handler mHandler;
ServiceEventHandlerDelegate(Handler handler) {
Looper looper;
if (handler == null) {
if ((looper = Looper.myLooper()) == null) {
looper = Looper.getMainLooper();
}
} else {
looper = handler.getLooper();
}
if (looper != null) {
// implement the event handler delegate to receive events from audio service
mHandler = new Handler(looper) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSSG_FOCUS_CHANGE: {
final FocusRequestInfo fri = findFocusRequestInfo((String)msg.obj);
if (fri != null) {
final OnAudioFocusChangeListener listener =
fri.mRequest.getOnAudioFocusChangeListener(); //获取OnAudioFocusChange监听器
if (listener != null) {
Log.d(TAG, "dispatching onAudioFocusChange("
+ msg.arg1 + ") to " + msg.obj);
listener.onAudioFocusChange(msg.arg1); //调用监听器的onAudioFocusChange方法,通知监听App
}
}
} break;
default:
Log.e(TAG, "Unknown event " + msg.what);
}
}
};
} else {
mHandler = null;
}
}
Handler getHandler() {
return mHandler;
}
}
}
AudioManager setFocusRequestResult
当App调用AudioManager的requestAudioFocus方法申请音频焦点时,会通过AudioPolicy.AudioPolicyFocusListener的方式调用到CarZonesAudioFocus的onAudioFocusRequest方法,经过CarZonesAudioFocus对音频焦点进行仲裁后后,再通过CarAudioFocus的setFocusRequestResult通知AudioManager,这时AudioManager的requestAudioFocus方法才会返回处理结果,接下来我们分析AudioManager的setFocusRequestResult方法:
//frameworks/base/media/java/android/media/AudioManager.java
public class AudioManager {
public void setFocusRequestResult(@NonNull AudioFocusInfo afi,
@FocusRequestResult int requestResult, @NonNull AudioPolicy ap) {
if (afi == null) {
throw new IllegalArgumentException("Illegal null AudioFocusInfo");
}
if (ap == null) {
throw new IllegalArgumentException("Illegal null AudioPolicy");
}
final IAudioService service = getService(); //取得IAudioService对象
try {
service.setFocusRequestResultFromExtPolicy(afi, requestResult, ap.cb()); //调用IAudioService的setFocusRequestResultFromExtPolicy方法
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
调用IAudioService的setFocusRequestResultFromExtPolicy方法,IAudioService是一个接口,由AudioService实现,因此会调用AudioService的setFocusRequestResultFromExtPolicy方法:
//frameworks/base/service/java/com/android/server/audio/AudioService.java
public class AudioService extends IAudioService.Stub
private final MediaFocusControl mMediaFocusControl;
public void setFocusRequestResultFromExtPolicy(AudioFocusInfo afi, int requestResult,
IAudioPolicyCallback pcb) {
if (afi == null) {
throw new IllegalArgumentException("Illegal null AudioFocusInfo");
}
if (pcb == null) {
throw new IllegalArgumentException("Illegal null AudioPolicy callback");
}
synchronized (mAudioPolicies) {
if (!mAudioPolicies.containsKey(pcb.asBinder())) {
throw new IllegalStateException("Unregistered AudioPolicy for external focus");
}
mMediaFocusControl.setFocusRequestResultFromExtPolicy(afi, requestResult); //调用MediaFocusControl的setFocusRequestResultFromExtPolicy方法
}
}
}
调用MediaFocusControl的setFocusRequestResultFromExtPolicy方法:
//frameworks/base/service/java/com/android/server/audio/MediaFocusControl.java
public class MediaFocusControl implements PlayerFocusEnforcer {
void setFocusRequestResultFromExtPolicy(AudioFocusInfo afi, int requestResult) {
synchronized (mExtFocusChangeLock) {
if (afi.getGen() > mExtFocusChangeCounter) {
return;
}
}
final FocusRequester fr;
if (requestResult == AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
fr = mFocusOwnersForFocusPolicy.remove(afi.getClientId()); //获取FocusRequester对象
} else {
fr = mFocusOwnersForFocusPolicy.get(afi.getClientId()); //获取FocusRequester对象
}
if (fr != null) {
fr.dispatchFocusResultFromExtPolicy(requestResult); //调用FocusRequester的dispatchFocusResultFromExtPolicy方法
}
}
}
调用FocusRequester的dispatchFocusResultFromExtPolicy方法:
//frameworks/base/service/java/com/android/server/audio/FocusRequester.java
public class FocusRequester {
void dispatchFocusResultFromExtPolicy(int requestResult) {
final IAudioFocusDispatcher fd = mFocusDispatcher;
if (fd == null) {
if (MediaFocusControl.DEBUG) {
Log.e(TAG, "dispatchFocusResultFromExtPolicy: no focus dispatcher");
}
return;
}
if (DEBUG) {
Log.v(TAG, "dispatching result" + requestResult + " to " + mClientId);
}
try {
fd.dispatchFocusResultFromExtPolicy(requestResult, mClientId); //调用IAudioFocusDispatcher的dispatchFocusResultFromExtPolicy方法
} catch (android.os.RemoteException e) {
Log.e(TAG, "dispatchFocusResultFromExtPolicy: error talking to focus listener"
+ mClientId, e);
}
}
}
调用IAudioFocusDispatcher的dispatchFocusResultFromExtPolicy方法,IAudioFocusDispatcher是一个接口,由AudioManager实现:
//frameworks/base/media/java/android/media/AudioManager.java
public class AudioManager {
private final IAudioFocusDispatcher mAudioFocusDispatcher = new IAudioFocusDispatcher.Stub() {
@Override
public void dispatchFocusResultFromExtPolicy(int requestResult, String clientId) {
synchronized (mFocusRequestsLock) {
// TODO use generation counter as the key instead
final BlockingFocusResultReceiver focusReceiver =
mFocusRequestsAwaitingResult.remove(clientId);
if (focusReceiver != null) {
focusReceiver.notifyResult(requestResult); //调用BlockingFocusResultReceiver的notifyResult方法
} else {
Log.e(TAG, "dispatchFocusResultFromExtPolicy found no result receiver");
}
}
}
};
}
调用BlockingFocusResultReceiver的notifyResult方法,BlockingFocusResultReceiver是AudioManager的内部类:
//frameworks/base/media/java/android/media/AudioManager.java
public class AudioManager {
private static final class BlockingFocusResultReceiver {
private final SafeWaitObject mLock = new SafeWaitObject();
@GuardedBy("mLock")
private boolean mResultReceived = false;
// request denied by default (e.g. timeout)
private int mFocusRequestResult = AudioManager.AUDIOFOCUS_REQUEST_FAILED;
private final String mFocusClientId;
void notifyResult(int requestResult) {
synchronized (mLock) {
mResultReceived = true;
mFocusRequestResult = requestResult;
mLock.safeNotify(); //调用SafeWaitObject 的safeNotify方法,通知锁
}
}
}
}
在AudioManager的requestAudioFocus方法中调用focusReceiver的waitForResult方法等待上面的Notify:
//frameworks/base/media/java/android/media/AudioManager.java
public class AudioManager {
public int requestAudioFocus(@NonNull AudioFocusRequest afr, @Nullable AudioPolicy ap) {
if (afr == null) {
throw new NullPointerException("Illegal null AudioFocusRequest");
}
// this can only be checked now, not during the creation of the AudioFocusRequest instance
if (afr.locksFocus() && ap == null) {
throw new IllegalArgumentException(
"Illegal null audio policy when locking audio focus");
}
registerAudioFocusRequest(afr);
final IAudioService service = getService();
final int status;
int sdk;
try {
sdk = getContext().getApplicationInfo().targetSdkVersion;
} catch (NullPointerException e) {
// some tests don't have a Context
sdk = Build.VERSION.SDK_INT;
}
final String clientId = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener());
final BlockingFocusResultReceiver focusReceiver;
synchronized (mFocusRequestsLock) {
try {
// TODO status contains result and generation counter for ext policy
status = service.requestAudioFocus(afr.getAudioAttributes(),
afr.getFocusGain(), mICallBack,
mAudioFocusDispatcher,
clientId,
getContext().getOpPackageName() /* package name */,
getContext().getAttributionTag(),
afr.getFlags(),
ap != null ? ap.cb() : null,
sdk);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
if (status != AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY) {
// default path with no external focus policy
return status;
}
if (mFocusRequestsAwaitingResult == null) {
mFocusRequestsAwaitingResult =
new HashMap<String, BlockingFocusResultReceiver>(1);
}
focusReceiver = new BlockingFocusResultReceiver(clientId);
mFocusRequestsAwaitingResult.put(clientId, focusReceiver);
}
focusReceiver.waitForResult(EXT_FOCUS_POLICY_TIMEOUT_MS);
if (DEBUG && !focusReceiver.receivedResult()) {
Log.e(TAG, "requestAudio response from ext policy timed out, denying request");
}
synchronized (mFocusRequestsLock) {
mFocusRequestsAwaitingResult.remove(clientId);
}
return focusReceiver.requestResult(); //返回焦点申请结果
}
}
BlockingFocusResultReceiver的waitForResult方法如下:
public class AudioManager {
private static final class BlockingFocusResultReceiver {
private final SafeWaitObject mLock = new SafeWaitObject();
@GuardedBy("mLock")
private boolean mResultReceived = false;
// request denied by default (e.g. timeout)
private int mFocusRequestResult = AudioManager.AUDIOFOCUS_REQUEST_FAILED;
private final String mFocusClientId;
public void waitForResult(long timeOutMs) {
synchronized (mLock) {
if (mResultReceived) {
// the result was received before waiting
return;
}
try {
mLock.safeWait(timeOutMs); //调用SafeWaitObject的safeWait,等待锁
} catch (InterruptedException e) { }
}
}
}
}
notifyFocusCallback
我们再分析notifyFocusCallback的处理:
//packages/services/Car/service/src/com/android/car/audio/CarZonesAudioFocus.java
final class CarZonesAudioFocus extends AudioPolicy.AudioPolicyFocusListener {
private final CarFocusCallback mCarFocusCallback;
private void notifyFocusCallback(int[] zoneIds) {
if (mCarFocusCallback == null) {
return;
}
SparseArray<List<AudioFocusInfo>> focusHoldersByZoneId = new SparseArray<>(); //创建AudioFocusInfo队列focusHoldersByZoneId
for (int i = 0; i < zoneIds.length; i++) {
int zoneId = zoneIds[i];
List<AudioFocusInfo> focusHolders = mFocusZones.get(zoneId).getAudioFocusHolders(); //获取AudioFocusInfo队列
focusHoldersByZoneId.put(zoneId, focusHolders); //将focusHolders加入到focusHoldersByZoneId
}
mCarFocusCallback.onFocusChange(zoneIds, focusHoldersByZoneId); //调用回调接口的onFocusChange方法
}
}
CarDucking onFocusChange
调用CarFocusCallback的onFocusChange方法,CarFocusCallback是一个接口,由CarDucking实现,因此调用CarDucking的onFocusChange方法:
//packages/services/Car/service/src/com/android/car/audio/CarZonesAudioFocus.java
final class CarZonesAudioFocus extends AudioPolicy.AudioPolicyFocusListener {
private final CarFocusCallback mCarFocusCallback;
private void notifyFocusCallback(int[] zoneIds) {
if (mCarFocusCallback == null) {
return;
}
SparseArray<List<AudioFocusInfo>> focusHoldersByZoneId = new SparseArray<>();
for (int i = 0; i < zoneIds.length; i++) {
int zoneId = zoneIds[i];
List<AudioFocusInfo> focusHolders = mFocusZones.get(zoneId).getAudioFocusHolders();
focusHoldersByZoneId.put(zoneId, focusHolders);
}
mCarFocusCallback.onFocusChange(zoneIds, focusHoldersByZoneId); //调用回调接口的onFocusChange方法
}
}
在notifyFocusCallback方法中会调用CarFocusCallback的onFocusChange方法,CarFocusCallback是一个接口,由CarDucking实现,因此会调用CarDucking的onFocusChange方法:
//packages/services/Car/service/src/com/android/car/audio/CarDucking.java
final class CarDucking implements CarFocusCallback {
private final AudioControlWrapper mAudioControlWrapper;
@Override
public void onFocusChange(int[] audioZoneIds,
@NonNull SparseArray<List<AudioFocusInfo>> focusHoldersByZoneId) {
synchronized (mLock) {
List<CarDuckingInfo> newDuckingInfos = new ArrayList<>(audioZoneIds.length); //创建CarDuckingInfo队列
for (int i = 0; i < audioZoneIds.length; i++) {
int zoneId = audioZoneIds[i];
List<AudioFocusInfo> focusHolders = focusHoldersByZoneId.get(zoneId); //循环获取每个audioZoneIds的AudioFocusInfo
CarDuckingInfo newDuckingInfo = updateDuckingForZoneIdLocked(zoneId, focusHolders); //更新DuckingInfo
newDuckingInfos.add(newDuckingInfo); //将DuckingInfo添加到DuckingInfo队列
}
mAudioControlWrapper.onDevicesToDuckChange(newDuckingInfos); //调用AudioControlWrapper的onDevicesToDuckChange方法,通知audiocontrol HAL
}
}
}
以上方法中主要有两个处理:
调用updateDuckingForZoneIdLocked更新DuckingInfo
调用AudioControlWrapper的onDevicesToDuckChange方法
下面我们分别分析:
updateDuckingForZoneIdLocked
首先是updateDuckingForZoneIdLocked:
//packages/services/Car/service/src/com/android/car/audio/CarDucking.java
final class CarDucking implements CarFocusCallback {
private final SparseArray<CarDuckingInfo> mCurrentDuckingInfo = new SparseArray<>();
private CarDuckingInfo updateDuckingForZoneIdLocked(int zoneId,
List<AudioFocusInfo> focusHolders) {
CarDuckingInfo oldDuckingInfo = mCurrentDuckingInfo.get(zoneId); //获取oldDuckingInfo
CarDuckingInfo newDuckingInfo = generateNewDuckingInfoLocked(oldDuckingInfo,
focusHolders); //通过oldDuckingInfo和focusHolders生成newDuckingInfo
mCurrentDuckingInfo.put(zoneId, newDuckingInfo); //将newDuckingInfo和zoneId放入CurrentDuckingInfo
return newDuckingInfo;
}
}
调用generateNewDuckingInfoLocked方法,通过oldDuckingInfo和focusHolders生成newDuckingInfo:
//packages/services/Car/service/src/com/android/car/audio/CarDucking.java
final class CarDucking implements CarFocusCallback {
private CarDuckingInfo generateNewDuckingInfoLocked(CarDuckingInfo oldDuckingInfo,
List<AudioFocusInfo> focusHolders) {
int zoneId = oldDuckingInfo.mZoneId; //获取zoneId
CarAudioZone zone = mCarAudioZones.get(zoneId); //获取CarAudioZone
int[] usagesHoldingFocus = CarDuckingUtils.getUsagesHoldingFocus(focusHolders); //获取usagesHoldingFocus
List<String> addressesToDuck = CarDuckingUtils.getAddressesToDuck(usagesHoldingFocus, zone); //获取addressesToDuck
List<String> addressesToUnduck = CarDuckingUtils.getAddressesToUnduck(addressesToDuck,
oldDuckingInfo.mAddressesToDuck); //获取addressesToUnduck
return new CarDuckingInfo(zoneId, addressesToDuck, addressesToUnduck, usagesHoldingFocus); //返回CarDuckingInfo对象
}
}
调用CarDuckingUtils的getUsagesHoldingFocus方法获取usagesHoldingFocus对象:
//packages/services/Car/service/src/com/android/car/audio/CarDuckingUtils.java
final class CarDuckingUtils {
static int[] getUsagesHoldingFocus(List<AudioFocusInfo> focusHolders) {
Set<Integer> uniqueUsages = new HashSet<>();
for (AudioFocusInfo focusInfo : focusHolders) {
uniqueUsages.add(focusInfo.getAttributes().getSystemUsage());
}
int index = 0;
int[] usagesHoldingFocus = new int[uniqueUsages.size()];
for (int usage : uniqueUsages) {
usagesHoldingFocus[index] = usage;
index++;
}
return usagesHoldingFocus;
}
}
调用CarDuckingUtils的getAddressesToDuck方法,获取addressesToDuck对象:
//packages/services/Car/service/src/com/android/car/audio/CarDuckingUtils.java
final class CarDuckingUtils {
static List<String> getAddressesToDuck(int[] usages, CarAudioZone zone) {
Set<Integer> uniqueContexts = CarAudioContext.getUniqueContextsForUsages(usages);
uniqueContexts.remove(INVALID);
Set<Integer> contextsToDuck = getContextsToDuck(uniqueContexts);
Set<String> addressesToDuck = getAddressesForContexts(contextsToDuck, zone);
Set<Integer> unduckedContexts = getUnduckedContexts(uniqueContexts, contextsToDuck);
Set<String> unduckedAddresses = getAddressesForContexts(unduckedContexts, zone);
// We should not duck any device that's associated with an unducked context holding focus.
addressesToDuck.removeAll(unduckedAddresses);
return new ArrayList<>(addressesToDuck);
}
}
调用CarDuckingUtils的getAddressesToUnduck,获取addressesToUnduck对象:
//packages/services/Car/service/src/com/android/car/audio/CarDuckingUtils.java
final class CarDuckingUtils {
static List<String> getAddressesToUnduck(List<String> addressesToDuck,
List<String> oldAddressesToDuck) {
List<String> addressesToUnduck = new ArrayList<>(oldAddressesToDuck);
addressesToUnduck.removeAll(addressesToDuck);
return addressesToUnduck;
}
}
创建CarDuckingInfo对象,CarDuckingInfo的构造函数如下:
//packages/services/Car/service/src/com/android/car/audio/CarDuckingInfo.java
public final class CarDuckingInfo {
public CarDuckingInfo(int zoneId, @NonNull List<String> addressesToDuck,
@NonNull List<String> addressesToUnduck, @NonNull int[] usagesHoldingFocus) {
mZoneId = zoneId;
mAddressesToDuck = Objects.requireNonNull(addressesToDuck);
mAddressesToUnduck = Objects.requireNonNull(addressesToUnduck);
mUsagesHoldingFocus = Objects.requireNonNull(usagesHoldingFocus);
}
}
AudioControlWrapper.onDevicesToDuckChange
我们分析onDevicesToDuckChange方法,调用AudioControlWrapper的onDevicesToDuckChange方法,AudioControlWrapper是一个接口,由AudioControlWrapperAidl实现,因此会调用AudioControlWrapperAidl的onDevicesToDuckChange方法:
//packages/services/Car/service/src/com/android/car/audio/hal/AudioControlWrapperAidl.java
public final class AudioControlWrapperAidl implements AudioControlWrapper {
private IAudioControl mAudioControl;
@Override
public void onDevicesToDuckChange(@NonNull List<CarDuckingInfo> carDuckingInfos) {
Objects.requireNonNull(carDuckingInfos);
DuckingInfo[] duckingInfos = new DuckingInfo[carDuckingInfos.size()]; //创建DuckingInfo对象
for (int i = 0; i < carDuckingInfos.size(); i++) {
CarDuckingInfo info = Objects.requireNonNull(carDuckingInfos.get(i)); 调用carDuckingInfos的get方法获取CarDuckingInfo
duckingInfos[i] = info.generateDuckingInfo();
}
try {
mAudioControl.onDevicesToDuckChange(duckingInfos); //调用IAudioControl的onDevicesToDuckChange方法
} catch (RemoteException e) {
Slogf.e(TAG, "onDevicesToDuckChange failed", e);
}
}
}
调用IAudioControl的onDevicesToDuckChange方法,IAudioControl是一个Aidl接口,由AudioControl实现,因此会调用AudioControl的onDevicesToDuckChange方法:
ndk::ScopedAStatus AudioControl::onDevicesToDuckChange(
const std::vector<DuckingInfo>& in_duckingInfos) {
LOG(INFO) << "AudioControl::onDevicesToDuckChange";
for (const DuckingInfo& duckingInfo : in_duckingInfos) {
LOG(INFO) << "zone: " << duckingInfo.zoneId;
LOG(INFO) << "Devices to duck:";
for (const auto& addressToDuck : duckingInfo.deviceAddressesToDuck) {
LOG(INFO) << addressToDuck;
}
LOG(INFO) << "Devices to unduck:";
for (const auto& addressToUnduck : duckingInfo.deviceAddressesToUnduck) {
LOG(INFO) << addressToUnduck;
}
LOG(INFO) << "Usages holding focus:";
for (const auto& usage : duckingInfo.usagesHoldingFocus) {
LOG(INFO) << usage;
}
}
return ndk::ScopedAStatus::ok();
}



被折叠的 条评论
为什么被折叠?



