美文网首页
CarAudio(一)构造方法与初始化

CarAudio(一)构造方法与初始化

作者: wenny826 | 来源:发表于2024-09-29 14:29 被阅读0次

    CarAudioService介绍

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

    CarAudioService是CarService服务中的其中一种关于Audio的特定服务。主要是负责与汽车音响系统进行交互。对音频进行分区,分区内的焦点分配,音量调节,音频路由等功能。因为CarAudioService是CarService中的其中一个服务,所以,我们直接make CarService 就可以进行编译。

    CarAudioManager API方法

    返回值 方法 参数 描述
    boolean isDynamicRoutingEnabled 返回是否动态路由是否可用的
    void setGroupVolume int groupId, int index, int flags 设置组音量的音量值到primary zone
    void setGroupVolume int zoneId, int groupId, int index, int flags 设置组音量的音量值
    int getGroupMaxVolume int groupId 获取通用域的传入groupId最大组音量
    int getGroupMaxVolume int zoneId, int groupId 获取传入zoneId域里的groupId最大组音量
    int getGroupMinVolume int groupId 获取通用域的传入groupId最小组音量
    int getGroupMinVolume int zoneId, int groupId 获取zoneId域里的groupId最小组音量
    int getGroupVolume int groupId 获取通用域的传入groupId音量值
    int getGroupVolume int zoneId, int groupId 获取传入zoneId域里的groupId音量值
    void setFadeTowardFront float value 设置前后音量偏移,0.0是平衡,1.0是前面
    void setBalanceTowardRight float value 设置左右音量偏移,0.0是平衡,1.0是右面
    String[] getExternalSources 获取外部音源,除麦克风外的输入设备(警报音、DVD、收音机等)
    CarAudioPatchHandle createAudioPatch String sourceAddress, @AudioAttributes.AttributeUsage int usage, int gainInMillibels 通过getExternalSources给出的input port,创建一个外部音源到output的补丁,返回一个CarAudioPatchHandle
    void releaseAudioPatch CarAudioPatchHandle patch 释放input port和output的关联
    int getVolumeGroupCount 获取通用域的可用音量组数目
    int getVolumeGroupCount int zoneId 获取zoneId指定域的可用音量组数目
    int getVolumeGroupIdForUsage @AudioAttributes.AttributeUsage int usage 获取传入音频用例对应的音量组Id
    int getVolumeGroupIdForUsage int zoneId @AudioAttributes.AttributeUsage int usage 获取zoneId指定域传入音频用例对应的音量组Id
    boolean setZoneIdForUid int zoneId, int uid 设置zoneId和uid的映射
    boolean clearZoneIdForUid int uid 清除uid的映射
    int[] getAudioZoneIds 获取所有音频域的id
    int getZoneIdForUid int uid 获取uid映射的zoneId,没有映射返回primaryId
    int getZoneIdForDisplay Display display 获取指定display的zoneId,没有找到返回primaryId
    int getZoneIdForDisplayPortId byte displayPortId 获取指定display端口ID所对应的zoneId,没有找到返回primaryId
    int[] getUsagesForVolumeGroupId int groupId 获取通用域里指定groupId所有的音频用例
    int[] getUsagesForVolumeGroupId int zoneId, int groupId 获取指定zoneId域里指定groupId所有的音频用例
    void registerCarVolumeCallback CarVolumeCallback callback 注册音量callback,添加到CarAudioManager维护的Callback组里,有onGroupVolumeChanged和onMasterMuteChanged的回调
    void unregisterCarVolumeCallback CarVolumeCallback callback 注销音量callback,从Callback组里删除

    其实看下来CarAudioManager提供的方法主要集中在音量和音频分区两个方面。我们后面再详细讲解。其中大部分都行SystemApi方法,只有系统应用能调用,或者用java反射的方式调用。

    服务的获取

    应用成功连接CarService之后,调用Car的getCarManager(String servicename)方法获取服务

    mCarAudioManager = (CarAudioManager) getCar().getCarManager(Car.AUDIO_SERVICE);
    
    888.png
    • 1.CarService启动后,会在onCreate方法中构造一个ICarImpl类。

      //CarService.java
      public void onCreate() {
              mICarImpl = new ICarImpl(this,
                      mVehicle,
                      SystemInterface.Builder.defaultSystemInterface(this).build(),
                      mVehicleInterfaceName);
              mICarImpl.init();
          }
      
    • 2.ICarImpl类在构造方法中创建CarAudioService服务,并添加到服务列表内

      //ICarImpl.java
      ICarImpl(Context serviceContext, IVehicle vehicle, SystemInterface systemInterface,
                  String vehicleInterfaceName,
                  @Nullable CarUserService carUserService,
                  @Nullable CarWatchdogService carWatchdogService,
                  @Nullable ICarPowerPolicySystemNotification powerPolicyDaemon) {
              LimitedTimingsTraceLog t = new LimitedTimingsTraceLog(
                      CAR_SERVICE_INIT_TIMING_TAG, Trace.TRACE_TAG_SYSTEM_SERVER,
                      CAR_SERVICE_INIT_TIMING_MIN_DURATION_MS);
              t.traceBegin("ICarImpl.constructor");
              //创建CarAudioService
              mCarAudioService = constructWithTrace(t, CarAudioService.class,
                      () -> new CarAudioService(serviceContext));
               ...
              //添加到服务列表
              allServices.add(mCarAudioService);
          }
      
    • 3.应用通过Car的getCarManager(String servicename)方法获取CarAudioManager。

      //Car.java
      public Object getCarManager(String serviceName) {
              CarManagerBase manager;
      
                          IBinder binder = mService.getCarService(serviceName);
                          manager = createCarManagerLocked(serviceName, binder);
      
              return manager;
          }
      
    • 4.Car.java与ICarImpl.java通过aidl通讯,所有会走到ICarImpl的getCarService方法中,通过servicename获取到CarAudoService,返回给Car.java中。

      //ICarImpl.java
      @Override
          public IBinder getCarService(String serviceName) {
              if (!mFeatureController.isFeatureEnabled(serviceName)) {
                  Log.w(CarLog.TAG_SERVICE, "getCarService for disabled service:" + serviceName);
                  return null;
              }
              switch (serviceName) {
                  case Car.AUDIO_SERVICE:
                      return mCarAudioService;
              }
          }
      
    • 5.将servicename和CarAudioService传递到createCarManagerLocked方法,创建一个CarAudioManager,同时将CarAudioService传入CarAudioManager中。

      //Car.java
       private CarManagerBase createCarManagerLocked(String serviceName, IBinder binder) {
              CarManagerBase manager = null;
              switch (serviceName) {
                  case AUDIO_SERVICE:
                      manager = new CarAudioManager(this, binder);
                      break;
              }
              return manager;
          }
      

    构造方法

     public CarAudioService(Context context) {
            mContext = context;
            //1.获取TelephonyManager和AudioManager服务,用于判断通话状态,调用系统Audio方法实现大部分audio功能。
            mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
            mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
            //2.从config.xml的文件中获取mUseDynamicRouting属性。 mUseDynamicRouting是尤为重要的属性,为true时。才能开启汽车的动态路由配置。
            mUseDynamicRouting = mContext.getResources().getBoolean(R.bool.audioUseDynamicRouting);
            mKeyEventTimeoutMs =
                    mContext.getResources().getInteger(R.integer.audioVolumeKeyEventTimeoutMs);
            mUseHalDuckingSignals = mContext.getResources().getBoolean(
                    R.bool.audioUseHalDuckingSignals);
            //3.创建CarAudioSetting用于加载和保存音量设置。创建 mUidToZoneMap用于管理音频分区和uid关联集合。
            mUidToZoneMap = new HashMap<>();
            mCarVolumeCallbackHandler = new CarVolumeCallbackHandler();
            mCarAudioSettings = new CarAudioSettings(mContext.getContentResolver());
    
            mAudioZoneIdToUserIdMapping = new SparseIntArray();
            mAudioVolumeAdjustmentContextsVersion =
                    mContext.getResources().getInteger(R.integer.audioVolumeAdjustmentContextsVersion);
            mCarVolume = new CarVolume(mClock,
                    mAudioVolumeAdjustmentContextsVersion, mKeyEventTimeoutMs);
            boolean useCarVolumeGroupMuting = mUseDynamicRouting && mContext.getResources().getBoolean(
                    R.bool.audioUseCarVolumeGroupMuting);
            if (mAudioVolumeAdjustmentContextsVersion != VERSION_TWO && useCarVolumeGroupMuting) {
                throw new IllegalArgumentException("audioUseCarVolumeGroupMuting is enabled but "
                        + "this requires audioVolumeAdjustmentContextsVersion 2,"
                        + " instead version " + mAudioVolumeAdjustmentContextsVersion + " was found");
            }
            mUseCarVolumeGroupMuting = useCarVolumeGroupMuting;
            mPersistMasterMuteState = !mUseCarVolumeGroupMuting && mContext.getResources().getBoolean(
                    R.bool.audioPersistMasterMuteState);
        }
    

    初始化

    999.png

    CarAudioService初始化方法的调用是在CarAudioService启动,创建ICarImpl对像,调用ICarImpl的init方法,在ICarImpl的init方法初始所有car的 相关服务。

    CarAudioService初始化的时候,根据mUseDynamicRouting这个属性走上的完全不一样的逻辑。

      public void init() {
            synchronized (mImplLock) {
                mOccupantZoneService = CarLocalServices.getService(CarOccupantZoneService.class);
                Car car = new Car(mContext, /* service= */null, /* handler= */ null);
                mOccupantZoneManager = new CarOccupantZoneManager(car, mOccupantZoneService);
                if (mUseDynamicRouting) {
                    setupDynamicRoutingLocked();//2.设置动态路由
                    setupHalAudioFocusListenerLocked();//3.注册来自hal层的焦点监听
                    setupAudioConfigurationCallbackLocked();//4.注册Audio播放和配置修改的监听
                    setupPowerPolicyListener();//5.启动Power电量监听和Policy策略修改监听
                } else {
                    Slog.i(CarLog.TAG_AUDIO, "Audio dynamic routing not enabled, run in legacy mode");
                    setupLegacyVolumeChangedListener();//6.设置音量监听
                }
                mAudioManager.setSupportedSystemUsages(SYSTEM_USAGES);//
            }
            restoreMasterMuteState();//
        }
    

    其中setupDynamicRoutingLocked方法是初始化过程中的核心方法。看下具体的代码流程

     private void setupDynamicRoutingLocked() {
          //1.创建AudioPolicy策略
            final AudioPolicy.Builder builder = new AudioPolicy.Builder(mContext);
            builder.setLooper(Looper.getMainLooper());
          //2.加载音频分区
            loadCarAudioZonesLocked();
            for (int i = 0; i < mCarAudioZones.size(); i++) {
                CarAudioZone zone = mCarAudioZones.valueAt(i);
                // Ensure HAL gets our initial value
               //3.给音频分区设置音量增益及对应的index
                zone.synchronizeCurrentGainIndex();
                Slog.v(CarLog.TAG_AUDIO, "Processed audio zone: " + zone);
            }
           //4.给每个CarAudioZones中的CarVolumeGroup配置混音策略,并添加到AudioPolicy策略中。
            CarAudioDynamicRouting.setupAudioDynamicRouting(builder, mCarAudioZones);
           //5.将音量变化的监听回调注册到AudioPolicy中
            CarAudioPolicyVolumeCallback
                    .addVolumeCallbackToPolicy(builder, this, mAudioManager,
                            mUseCarVolumeGroupMuting);
            ...
           //6.创建车载音频焦点的管理对象,并且设置到AudioPolicy策略中
            mFocusHandler = CarZonesAudioFocus.createCarZonesAudioFocus(mAudioManager,
                    mContext.getPackageManager(),
                    mCarAudioZones,
                    mCarAudioSettings,
                    ENABLE_DELAYED_AUDIO_FOCUS,
                    mCarDucking);
            builder.setAudioPolicyFocusListener(mFocusHandler);
            builder.setIsAudioFocusPolicy(true);
            mAudioPolicy = builder.build();
            mFocusHandler.setOwningPolicy(this, mAudioPolicy);
          //7.将AudioPoliy策略注册到AudioManager中
            int r = mAudioManager.registerAudioPolicy(mAudioPolicy);
           ...
            setupOccupantZoneInfo();
        }
    

    总的来说,就是创建AudioPolicy策略,配置音频分区,混音,音频焦点相关策略,并注册到AudioManager中,AuiodManager再传入navie层的AudioPolicy中实现。

    相关文章

      网友评论

          本文标题:CarAudio(一)构造方法与初始化

          本文链接:https://www.haomeiwen.com/subject/pelnidtx.html