基于Android O平台Audio Focus分析(主要结合Car)(下)

Car相关

经过一番查找,只有这个地方设置了mFocusListener,我们就拿Car来做研究吧

packages/services/Car/service/src/com/android/car/CarAudioService.java

public void init() {
   
   
    AudioPolicy.Builder builder = new AudioPolicy.Builder(mContext);
    ...
        builder.setAudioPolicyFocusListener(mSystemFocusListener);
    ...
}

mSystemFocusListener

//SystemFocusListener是CarAudioService的内部类
private class SystemFocusListener extends AudioPolicyFocusListener {
   
   
  @Override
  public void onAudioFocusGrant(AudioFocusInfo afi, int requestResult) {
   
   
    ...
      if (requestResult == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
   
   
                synchronized (mLock) {
   
   
                    mPendingFocusChanges.addFirst(afi);
                }
                mFocusHandler.handleAndroidFocusChange();
            }
    ...
  }
  
  @Override
        public void onAudioFocusLoss(AudioFocusInfo afi, boolean wasNotified) {
   
   
            //理由没看懂,总之就是这个地方不管不顾不处理回调这种做法安全
            // ignore loss as tracking gain is enough. At least bottom listener will be
            // always there and getting focus grant. So it is safe to ignore this here.
        }
}

mFocusHandler定义:

mFocusHandlerThread = new HandlerThread(CarLog.TAG_AUDIO);
mFocusHandler = new CarAudioFocusChangeHandler(mFocusHandlerThread.getLooper());

mFocusHandler.handleAndroidFocusChange

private void handleAndroidFocusChange() {
   
   
            cancelFocusReleaseRequest();
            Message msg = obtainMessage(MSG_ANDROID_FOCUS_CHANGE);
            sendMessage(msg);
        }
case MSG_ANDROID_FOCUS_CHANGE:
                    doHandleAndroidFocusChange(false /* triggeredByStreamChange */);
                    break;

又碰到一个比较复杂的函数doHandleAndroidFocusChange@CarAudioService

private void doHandleAndroidFocusChange(boolean triggeredByStreamChange) {
   
   
    ...
        //前面onAudioFocusGrant@SystemFocusListener的时候进行的
        //mPendingFocusChanges.addFirst(afi);
        newTopInfo = mPendingFocusChanges.getFirst();
            //这是一个LinkedList。不知道为什么getFirst之后就要马上清掉
            mPendingFocusChanges.clear();
        ...
        if (newTopInfo != null) {
   
      
               if (newTopInfo.getGainRequest() ==
                    AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK) {
   
   
                    //新的request是获得暂时的可以duck的
                    //让之前的老大降级成副手
                    mSecondaryFocusInfo = mPrimaryFocusInfo;
                } else {
   
   
                    //否则就不设置副手
                    mSecondaryFocusInfo = null;
                }
                //新来的成为老大
                mPrimaryFocusInfo = newTopInfo;
          }
        //请看后边的分析
         focusRequested = handleCarFocusRequestAndResponseLocked();
    ...
        //如果有响应,或者超时强制处理
        if (focusRequested) {
   
   
            doHandleCarFocusChange();
        }
}

newTopInfo往前追溯就是MediaFocusControl的mFocusStack.peek().toAudioFocusInfo(),其实就是mFocusStack这个栈顶的当前音频焦点拥有者信息!

这里我们先做个handleCarFocusRequestAndResponseLocked的分析

private boolean handleCarFocusRequestAndResponseLocked() {
   
   
  boolean focusRequested = reevaluateCarAudioFocusAndSendFocusLocked();
  if (focusRequested) {
   
   
    ...
      // send context change after getting focus response.
      //处理context的改变!关键的新概念,CarAudioContext
      if (mCarAudioContextChangeHandler != null) {
   
   
                mCarAudioContextChangeHandler.requestContextChangeNotification(
                        mAudioContextChangeListener, mCurrentPrimaryAudioContext,
                        mCurrentPrimaryPhysicalStream);
      }
    //检查can总线的工作状态?
      checkCanStatus();
  }
  return focusRequested;
}

这个函数最终返回了focusRequested,从reevaluateCarAudioFocusAndSendFocusLocked返回

让我们看看这个庞大的函数。

reevaluateCarAudioFocusAndSendFocusLocked@CarAudioService

if (mPrimaryFocusInfo == null) {
   
   
   if (mSystemSoundPhysicalStreamActive) {
   
   
        //最终调用了mVehicleHal.set(AUDIO_FOCUS).to(payload);
        //payload = { request, streams, extFocus, audioContexts };
     return requestFocusForSystemSoundOnlyCaseLocked();
   } 
    ...
}
...
    //一段段绕来绕去的判断计算赋值之后,给
    //focusToRequest, streamsToRequest, extFocus,
    //audioContexts, routingHintChanged这几个参数赋值
...
 return sendFocusRequestToCarIfNecessaryLocked(focusToRequest, streamsToRequest, extFocus,audioContexts, routingHintChanged);
}

而sendFocusRequestToCarIfNecessaryLocked也是通过调用

mAudioHal.requestAudioFocusChange(
                    focusToRequest,
                    streamsToRequest,
                    extFocus,
                    audioContexts);

然后

int[] payload = { request, streams, extFocus, audioContexts };
mVehicleHal.set(AUDIO_FOCUS).to(payload);

由于之前已经分析过类似的调用了,再往下就需要Vendor去实现了.

hardware/interfaces/automotive/vehicle/2.0/types.hal

首先是它的注释(原文不贴了,太多了)

AUDIO_FOCUS = (
        0x0900
        | VehiclePropertyGroup:SYSTEM
        | VehiclePropertyType:INT32_VEC
        | VehicleArea:GLOBAL),

代表Android侧的音频焦点状态.注意car的audio module必须拥有audio focus,and grant(准许,发放?) audio focus给Android side(requested by Android side的时候.)焦点既有stream特性,也有全局特性.

请求:

Focus request (get of this property)必须按照以下的格式(VehicleAudioFocusIndex中定义的索引)(就如上面的调用一样)

int32Values[0]: VehicleAudioFocusRequest type

int32Values[1]: bit flags of streams requested by this focus request.

There can be up to 32 streams.

int32Values[2]:External focus state flags....

int32Values[3]:Audio contexts wishing to be active....

响应:

Focus response (set and subscription callback for this property)

int32Values[0]: VehicleAudioFocusState type

int32Values[1]: bit flags of streams allowed.

int32Values[2]: External focus state...(GAIN,GAIN_TRANSIENT,LOSS,LOSS_TRANSIENT)

int32Values[3]:Audio context(s) allowed to be active.When responding positively to a

focus request from Android, the request's original context must be

repeated here. When taking focus away, or denying a request, the

rejected or stopped context would have its corresponding bit cleared.

Audio context:批准的时候就重复请求时候的,如果被拒绝或被stopped的context应该清除相应的bit.

每次focus request必须有focus response,就算focus state没有变化.This can happen in case like focus request

only involving context change where android side still needs matching focus response to confirm that audio module has made necessary changes(context有变化的时候).

If car does not support AUDIO_FOCUS, focus is assumed to be granted always.

//A property to allow external component to control audio focus.
//不知道具体是要干啥的
//Data format is the same as AUDIO_FOCUS property.(数据格式和AUDIO_FOCUS一样)
AUDIO_FOCUS_EXT_SYNC = (
        0x0910
        | VehiclePropertyGroup:SYSTEM
        | VehiclePropertyType:INT32_VEC
        | VehicleArea:GLOBAL),

注释提到的VehicleAudioFocusIndex

/**
 * Index in int32Values for VehicleProperty#AUDIO_FOCUS property.
 */
enum VehicleAudioFocusIndex : int32_t {
   
   
    FOCUS = 0,
    STREAMS = 1,
    EXTERNAL_FOCUS_STATE = 2,
    AUDIO_CONTEXTS = 3,
};

VehicleAudioFocusIndex示例(VehicleAudioFocusIndex的定义是自动生成的):

services/Car/service/src/com/android/car/hal/AudioHalService.java

...
    int focusState = vec.get(VehicleAudioFocusIndex.FOCUS);
    int streams = vec.get(VehicleAudioFocusIndex.STREAMS);
    int externalFocus = vec.get(VehicleAudioFocusIndex.EXTERNAL_FOCUS_STATE);
...

AudioContext使用示例:

/packages/services/Car/service/src/com/android/car/VolumeUtils.java

public static final int[] CAR_AUDIO_CONTEXT = {
   
   
    VehicleAudioContextFlag.MUSIC_FLAG,
    VehicleAudioContextFlag.NAVIGATION_FLAG,
    VehicleAudioContextFlag.VOICE_COMMAND_FLAG,
    VehicleAudioContextFlag.CALL_FLAG,
    VehicleAudioContextFlag.ALARM_FLAG
    VehicleAudioContextFlag.NOTIFICATION_FLAG,
    VehicleAudioContextFlag.UNKNOWN_FLAG,
    VehicleAudioContextFlag.SAFETY_ALERT_FLAG,
    VehicleAudioContextFlag.CD_ROM_FLAG,
    VehicleAudioContextFlag.AUX_AUDIO_FLAG,
    VehicleAudioContextFlag.SYSTEM_SOUND_FLAG,
    VehicleAudioContextFlag.RADIO_FLAG
};
//android传统的stream到CarContext的转换
public static int androidStreamToCarContext(int logicalAndroidStream) {
   
   
        switch (logicalAndroidStream) {
   
   
            case AudioManager.STREAM_VOICE_CALL:
                return VehicleAudioContextFlag.CALL_FLAG;
            case AudioManager.STREAM_SYSTEM:
                return VehicleAudioContextFlag.SYSTEM_SOUND_FLAG;
            case AudioManager.STREAM_RING:
                return VehicleAudioContextFlag.RINGTONE_FLAG;
            case AudioManager.STREAM_MUSIC:
                return VehicleAudioContextFlag.MUSIC_FLAG;
            case AudioManager.STREAM_ALARM:
                return VehicleAudioContextFlag.ALARM_FLAG;
            case AudioManager.STREAM_NOTIFICATION:
                return VehicleAudioContextFlag.NOTIFICATION_FLAG;
            case AudioManager.STREAM_DTMF:
                return VehicleAudioContextFlag.SYSTEM_SOUND_FLAG;
            default:
                return VehicleAudioContextFlag.UNKNOWN_FLAG;
        }
    }

前面看了mVehicleHal.set(AUDIO_FOCUS).to(payload)的例子.我们再来找找,车机端响应的过程.

onPropertyEvent@VehicleHal

@Override
public void onPropertyEvent(ArrayList<VehiclePropValue> propValues) {
   
   
  for (VehiclePropValue v : propValues) {
   
   
    //mPropertyHandlers已经存有对应关系
    HalServiceBase service = mPropertyHandlers.get(v.prop);
    service.getDispatchList().add(v);
    mServicesToDispatch.add(service);
  }
  ...
  for (HalServiceBase s : mServicesToDispatch) {
   
   
            s.handleHalEvents(s.getDispatchList());
           ...
  }
}

因为VehicleHal在调用init的时候已经把每一个service关心的properties做了绑定,所以这个地方有popValues事件的时候就能找到对应的service.不信你看:

//init@VehicleHal
Collection<VehiclePropConfig> taken = service.takeSupportedProperties(properties);
 for (VehiclePropConfig p: taken) {
   
   
   mPropertyHandlers.append(p.prop, service);
 }

takeSupportedProperties@AudioHalService

@Override
    public synchronized Collection<VehiclePropConfig> takeSupportedProperties(
            Collection<VehiclePropConfig> allProperties) {
   
   
        for (VehiclePropConfig p : allProperties) {
   
   
            switch (p.prop) {
   
   
                //这几个就是我们AudioHalService所关心的全部prop啦
                case VehicleProperty.AUDIO_FOCUS:
                case VehicleProperty.AUDIO_VOLUME:
                case VehicleProperty.AUDIO_VOLUME_LIMIT:
                case VehicleProperty.AUDIO_HW_VARIANT:
                case VehicleProperty.AUDIO_EXT_ROUTING_HINT:
                case VehicleProperty.AUDIO_PARAMETERS:
                case VehicleProperty.AUDIO_STREAM_STATE:
                    mProperties.put(p.prop, p);
                    break;
            }
        }
        return new ArrayList<>(mProperties.values());
    }

上文的s.handleHalEvents即是

handleHalEvents@AudioHalService

@Override
    public void handleHalEvents(List<VehiclePropValue> values) {
   
   
        AudioHalFocusListener focusListener;
        AudioHalVolumeListener volumeListener;
        OnParameterChangeListener parameterListener;
        synchronized (this) {
   
   
            focusListener = mFocusListener;
            volumeListener = mVolumeListener;
            parameterListener = mOnParameterChangeListener;
        }
        dispatchEventToListener(focusListener, volumeListener, parameterListener, values);
    }

即将出现前文提到的VehicleAudioFocusIndex

dispatchEventToListener@AudioHalService

...
  case VehicleProperty.AUDIO_FOCUS: {
   
   
        ArrayList<Integer> vec = v.value.int32Values;
        //即是types.hal中定义的AUDIO_FOCUS的response方式(where is Audio Context?)
        int focusState = vec.get(VehicleAudioFocusIndex.FOCUS);
        int streams = vec.get(VehicleAudioFocusIndex.STREAMS);
        int externalFocus = vec.get(VehicleAudioFocusIndex.EXTERNAL_FOCUS_STATE);
        if (focusListener != null) {
   
   
           focusListener.onFocusChange(focusState, streams, externalFocus);
        }
  }
...

这个Listrner是谁呢,不用想,就是它了

onFocusChange@CarAudioService

@Override
    public void onFocusChange(int focusState, int streams, int externalFocus) {
   
   
        synchronized (mLock) {
   
   
            mFocusReceived = FocusState.create(focusState, streams, externalFocus);
            // wake up thread waiting for focus response.
            mLock.notifyAll();
        }                                                
        mFocusHandler.handleFocusChange();
    }

省略几步之后,到了这里

doHandleCarFocusChange@CarAudioService

private void doHandleCarFocusChange() {
   
   
  ...
    newFocusState = ???
    ...
    switch (newFocusState) {
   
   
            case AudioHalService.VEHICLE_AUDIO_FOCUS_STATE_GAIN:
                doHandleFocusGainFromCar(mCurrentFocusState, topInfo, systemSoundActive);
                break;
            case AudioHalService.VEHICLE_AUDIO_FOCUS_STATE_GAIN_TRANSIENT:
                doHandleFocusGainTransientFromCar(mCurrentFocusState, topInfo, systemSoundActive);
                break;
            case AudioHalService.VEHICLE_AUDIO_FOCUS_STATE_LOSS:
                doHandleFocusLossFromCar(mCurrentFocusState, topInfo);
                break;
            case AudioHalService.VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT:
                doHandleFocusLossTransientFromCar(mCurrentFocusState);
                break;
            case AudioHalService.VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_CAN_DUCK:
                doHandleFocusLossTransientCanDuckFromCar(mCurrentFocusState);
                break;
            case AudioHalService.VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_EXLCUSIVE:
                doHandleFocusLossTransientExclusiveFromCar(mCurrentFocusState);
                break;
        }
}

根据不同的newFocusState调用doHandleFocus(Gain/GainTransient/Loss/LossTransient/LossTransientCanDuck/

LossTransientExclusive)FromCar这一系列函数,基本上就是再调用mAudioManager.abandonAudioFocus等等传统函数.

猜你喜欢

转载自blog.csdn.net/bberdong/article/details/79268379