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

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中实现。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容