惊雷无声 发表于 2025-3-16 06:04:21

CarAudioService启动流程分析

CarAudioService启动流程分析

在CarServiceImpl的onCreate方法内里会new一个ICarImpl实例,在ICarImpl构造函数中会创建CarAudioService:
public class ICarImpl extends ICar.Stub {
        ICarImpl(...) {
      mCarAudioService = constructWithTrace(t, CarAudioService.class,
                () -> new CarAudioService(serviceContext), allServices);                   
      }
}
CarAudioService初始化
    @Override
    public void init() {
      synchronized (mImplLock) {
            mOccupantZoneService = CarLocalServices.getService(CarOccupantZoneService.class);
            mCarInputService = CarLocalServices.getService(CarInputService.class);
            //如果使用动态路由,在packages/services/Car/Service/res/values/comfig.xml中将audioUseDynamicRouting的配置改为true
            if (mUseDynamicRouting) {
                //设置动态路由
                setupDynamicRoutingLocked();
                设置Hal层音频焦点监听器,向IAudioControl.aidl注册焦点请求Listener
                setupHalAudioFocusListenerLocked();
                //设置Hal层音频增益回调,向IAudioControl.aidl注册音量变化callback
                setupHalAudioGainCallbackLocked();
                //向IAudioControl.aidl注册设备配置信息变化callback,当底层硬件设置了播放Device的最小增益、最大增益、默认增益、步进这些配置信息时,会调用此callback。
                setupHalAudioModuleChangeCallbackLocked();
                //设置音频配置,向AudioService注册PlaybackCallback
                setupAudioConfigurationCallbackLocked();
                setupPowerPolicyListener();
                mCarInputService.registerKeyEventListener(mCarKeyEventListener,
                        KEYCODES_OF_INTEREST);
            } else {
                Slogf.i(TAG, "Audio dynamic routing not enabled, run in legacy mode");
                setupLegacyVolumeChangedListener();
            }
            //设置当前支持的system级AudioAttributes.usage,注册到AudioPolicyService中
            mAudioManager.setSupportedSystemUsages(CarAudioContext.getSystemUsages());
      }

      restoreMasterMuteState();
    }
setupDynamicRoutingLocked

setupDynamicRouting做的事变比力多,我们分布举行梳理
1.读取CarAudio的配置
2.创建CarAudioZonesHelper,同步当前音量
3.通过usage创建动态路由
private void setupDynamicRoutingLocked() {
    AudioPolicy.Builder builder = new AudioPolicy.Builder(mContext);
    builder.setLooper(Looper.getMainLooper());

    loadCarAudioZonesLocked();//加载CarAudioZones

    mCarVolume = new CarVolume(mCarAudioContext, mClock,
            mAudioVolumeAdjustmentContextsVersion, mKeyEventTimeoutMs);

    for (int i = 0; i < mCarAudioZones.size(); i++) {
      CarAudioZone zone = mCarAudioZones.valueAt(i);
      // Ensure HAL gets our initial value
      //设置每个Device的当前音量增益值到AudioHAL中,最后应该是保存到SettingProvider数据库中。
      zone.init();
      Slogf.v(TAG, "Processed audio zone: %s", zone);
    }

    // Mirror policy has to be set before general audio policy
    setupMirrorDevicePolicyLocked(builder);//为MirrorDevice创建一个USAGE_MEDIA匹配规则的对象AudioMix,并添加到AudioPolicy中。
    //将CarAudioZone数据结构转换成AudioPolicyConfig,并添加到AudioPolicy中。
    CarAudioDynamicRouting.setupAudioDynamicRouting(builder, mCarAudioZones, mCarAudioContext);

    AudioPolicyVolumeCallbackInternal volumeCallbackInternal =
            new AudioPolicyVolumeCallbackInternal() {
      @Override
      public void onMuteChange(boolean mute, int zoneId, int groupId, int flags) {
            if (mUseCarVolumeGroupMuting) {
                setVolumeGroupMute(zoneId, groupId, mute, flags);
                return;
            }
            setMasterMute(mute, flags);
      }

      @Override
      public void onGroupVolumeChange(int zoneId, int groupId, int volumeValue, int flags) {
            setGroupVolume(zoneId, groupId, volumeValue, flags);
      }
    };
       
    mCarAudioPolicyVolumeCallback = new CarAudioPolicyVolumeCallback(volumeCallbackInternal,
            mAudioManager, new CarVolumeInfoWrapper(this), mUseCarVolumeGroupMuting);
    //向AudioPolicy中注册一个音量控制callback
    // Attach the {@link AudioPolicyVolumeCallback}
    CarAudioPolicyVolumeCallback.addVolumeCallbackToPolicy(builder,
            mCarAudioPolicyVolumeCallback);

    AudioControlWrapper audioControlWrapper = getAudioControlWrapperLocked();
    if (mUseHalDuckingSignals) {
      if (audioControlWrapper.supportsFeature(AUDIOCONTROL_FEATURE_AUDIO_DUCKING)) {
            mCarDucking = new CarDucking(mCarAudioZones, audioControlWrapper);
      }
    }

    if (mUseCarVolumeGroupMuting) {
      mCarVolumeGroupMuting = new CarVolumeGroupMuting(mCarAudioZones, audioControlWrapper);
    }

    // Configure our AudioPolicy to handle focus events.
    // This gives us the ability to decide which audio focus requests to accept and bypasses
    // the framework ducking logic.
    mFocusHandler = CarZonesAudioFocus.createCarZonesAudioFocus(mAudioManager,
            mContext.getPackageManager(),
            mCarAudioZones,
            mCarAudioSettings,
            mCarDucking,
            new CarVolumeInfoWrapper(this));
    builder.setAudioPolicyFocusListener(mFocusHandler);
    builder.setIsAudioFocusPolicy(true);

    mAudioPolicy = builder.build();

    // Connect the AudioPolicy and the focus listener
    mFocusHandler.setOwningPolicy(this, mAudioPolicy);

    int r = mAudioManager.registerAudioPolicy(mAudioPolicy);//向AudioService注册此AudioPolicy
    if (r != AudioManager.SUCCESS) {
      throw new RuntimeException("registerAudioPolicy failed " + r);
    }

    setupOccupantZoneInfoLocked();

    if (mUseCoreAudioVolume) {
      mCoreAudioVolumeGroupCallback = new CoreAudioVolumeGroupCallback(
                new CarVolumeInfoWrapper(this), mAudioManager);
      mCoreAudioVolumeGroupCallback.init(mContext.getMainExecutor());
    }
}
loadCarAudioZonesLocked 加载CarAudioZones,解析car_audio_configuration.xml
private void loadCarAudioZonesLocked() {
    List<CarAudioDeviceInfo> carAudioDeviceInfos = generateCarAudioDeviceInfos();生成CarAudioDeviceInfos
    AudioDeviceInfo[] inputDevices = getAllInputDevices();//获取所有输入设备信息

    if (mCarAudioConfigurationPath != null) {
      //通过生成的CarAudioDeviceInfos和获取的所有输入设备信息,加载CarAudioZones配置
      mCarAudioZones = loadCarAudioConfigurationLocked(carAudioDeviceInfos, inputDevices);
    } else {
      mCarAudioZones =
                loadVolumeGroupConfigurationWithAudioControlLocked(carAudioDeviceInfos,
                        inputDevices);
    }
    //验证CarAudioZones,检查配置文件有效性
    CarAudioZonesValidator.validate(mCarAudioZones, mUseCoreAudioRouting);
}

loadCarAudioConfigurationLocked调用CarAudioZonesHelper,CarAudioZonesHelper()的构造函数比力简单,创建完毕之后,调用loadAudioZones()函数,这里主要是对传入的path举行解析
解析过程如下:
1.先找name和isPrimary,在CarAudioZone中isPrimary只能有一个,如果isPrimary为true,则id是CarAudioManager.PRIMARY_AUDIO_ZONE,否则id是mNextSecondaryZoneId,因为mNextSecondaryZoneId初始为1,也就是说primary为true的id=0,其他的从1开始累加
2.根据zone标签,我们知道终极会创建多少个CarAudioZone。每个CarAudioZone包含一个VolumeGroups的集合,而集合的size是由的数目决定,每个下的device以及他们下面的所有context构成了CarVolumeGroup,每个CarVolumeGroup包含了一个contextNumber和busNumber构成的map,以及busNumber和CarAudioDeviceInfo构成的map,每个device下的音量最大,最小,当前音量,默认音量都是一样的,每个group下的所有音量的步长都是一样的。
private SparseArray<CarAudioZone> loadCarAudioConfigurationLocked(
      List<CarAudioDeviceInfo> carAudioDeviceInfos, AudioDeviceInfo[] inputDevices) {

    try (InputStream fileStream = new FileInputStream(mCarAudioConfigurationPath);
             InputStream inputStream = new BufferedInputStream(fileStream)) {
      //CarAudioZonesHelper来解析car_audio_configuration.xml
      CarAudioZonesHelper zonesHelper = new CarAudioZonesHelper(mAudioManager,
                mCarAudioSettings, inputStream, carAudioDeviceInfos, inputDevices,
                mUseCarVolumeGroupMuting, mUseCoreAudioVolume, mUseCoreAudioRouting);
      //一个zoneID和occpantZoneId对应的集合
      mAudioZoneIdToOccupantZoneIdMapping =
                zonesHelper.getCarAudioZoneIdToOccupantZoneIdMapping();
      //加载xml
      SparseArray<CarAudioZone> zones = zonesHelper.loadAudioZones();
      mCarAudioMirrorRequestHandler.setMirrorDeviceInfos(zonesHelper.getMirrorDeviceInfos());
      mCarAudioContext = zonesHelper.getCarAudioContext();
      return zones;
    } catch (IOException | XmlPullParserException e) {
      throw new RuntimeException("Failed to parse audio zone configuration", e);
    }
}
CarAudioZonesValidator.validate()函数,这个函数内里界说了一些car_audio_configuration.xml配置文件须要遵守的规则:


[*] 至少须要配置一个音区。
[*] 每个音区中,都须要配置一个默认的,通过节点的isDefault属性举行配置。并且一个音区中只能配置一个默认。
[*] 在整个配置文件中,每个只能出现一次,不能重复配置,即使是在不同的音区中。
[*] 在每个中,所有已界说的都必须出现。默认的界说是在CarAudioContext.java->getAllContextsInfo()函数中。也就是说每个都必须配置完整的规则。
[*] 在一个中,每种只能出现一次。即:一种不能同时配置到两个不同的中。
[*] 在同一个中的所有Device,它们的步进必须相同。因为CarAudioService在针对每个volumeGroup设置音量时,会同时设置这个下的所有Device。
[*] 主音区中必须配置一个TYPE_BUILTIN_MIC类型的麦克风装备。主音区是通过节点的isPrimary属性配置。固然,如果你没有在配置文件中配置主音区的麦克风装备,CarAudioZonesHelper在解析完配置文件后,也会通过CarAudioZonesHelper.addRemainingMicrophonesToPrimaryZone()函数自动帮你添加上。
https://i-blog.csdnimg.cn/blog_migrate/9e3e4d512c5b210668130e078a26aaef.png
setupAudioDynamicRouting

遍历carAudioZones获取zoneConfigs
static void setupAudioDynamicRouting(AudioPolicy.Builder builder,
      SparseArray<CarAudioZone> carAudioZones, CarAudioContext carAudioContext) {
    for (int i = 0; i < carAudioZones.size(); i++) {
      List<CarAudioZoneConfig> zoneConfigs =
                carAudioZones.valueAt(i).getAllCarAudioZoneConfigs();
      for (int configIndex = 0; configIndex < zoneConfigs.size(); configIndex++) {
            setupAudioDynamicRoutingForZoneConfig(builder, zoneConfigs.get(configIndex),
                  carAudioContext);
      }
    }
}
获取volumeGroups,设置每个group的策略
private static void setupAudioDynamicRoutingForZoneConfig(AudioPolicy.Builder builder,
      CarAudioZoneConfig zoneConfig, CarAudioContext carAudioContext) {
    CarVolumeGroup[] volumeGroups = zoneConfig.getVolumeGroups();
    for (int index = 0; index < volumeGroups.length; index++) {
            //设置每个group的策略
      setupAudioDynamicRoutingForGroup(builder, volumeGroups, carAudioContext);
    }
}
将AudioMix add 到 AudioPolicy中
private static void setupAudioDynamicRoutingForGroup(AudioPolicy.Builder builder,
      CarVolumeGroup group, CarAudioContext carAudioContext) {
    // Note that one can not register audio mix for same bus more than once.
    List<String> addresses = group.getAddresses();
    //设置每个group的策略
    for (int index = 0; index < addresses.size(); index++) {
      String address = addresses.get(index);
      boolean hasContext = false;
      // 根据group下的address 拿到对应的CarAudioDeviceInfo
      CarAudioDeviceInfo info = group.getCarAudioDeviceInfoForAddress(address);
      if (!info.canBeRoutedWithDynamicPolicyMix()) {
            if (Slogf.isLoggable(CarLog.TAG_AUDIO, Log.DEBUG)) {
                Slogf.d(CarLog.TAG_AUDIO, "Address: %s AudioContext: %s cannot be routed with "
                        + "Dynamic Policy Mixing", address, carAudioContext);
            }
            continue;
      }
      // 将CarAudioDeviceInfo的信息赋值给到AudioFormat
      AudioFormat mixFormat = createMixFormatFromDevice(info);
      AudioMixingRule.Builder mixingRuleBuilder = new AudioMixingRule.Builder();
      List<Integer> contextIdsForAddress = group.getContextsForAddress(address);
      // 遍历address下的context
      for (int contextIndex = 0; contextIndex < contextIdsForAddress.size(); contextIndex++) {
            @CarAudioContext.AudioContext int contextId =
                  contextIdsForAddress.get(contextIndex);
            hasContext = true;
            AudioAttributes[] allAudioAttributes =
                  carAudioContext.getAudioAttributesForContext(contextId);
            for (int attrIndex = 0; attrIndex < allAudioAttributes.length; attrIndex++) {
                AudioAttributes attributes = allAudioAttributes;
                mixingRuleBuilder.addRule(attributes,
                        AudioMixingRule.RULE_MATCH_ATTRIBUTE_USAGE);
            }
            if (Slogf.isLoggable(CarLog.TAG_AUDIO, Log.DEBUG)) {
                Slogf.d(CarLog.TAG_AUDIO, "Address: %s AudioContext: %s sampleRate: %d "
                        + "channels: %d attributes: %s", address, carAudioContext,
                        info.getSampleRate(), info.getChannelCount(),
                        Arrays.toString(allAudioAttributes));
            }
      }
      if (hasContext) {
            // It's a valid case that an audio output address is defined in
            // audio_policy_configuration and no context is assigned to it.
            // In such case, do not build a policy mix with zero rules.
            addMix(builder, info, mixFormat, mixingRuleBuilder);// 将AudioMix add 到 AudioPolicy中
      }
    }
}
createCarZonesAudioFocus

CarZonesAudioFocus的createCarZonesAudioFocus方法来创建CarZonesAudioFocus:
mFocusHandler = CarZonesAudioFocus.createCarZonesAudioFocus(mAudioManager,
      mContext.getPackageManager(),
      mCarAudioZones,
      mCarAudioSettings,
      mCarDucking,
      new CarVolumeInfoWrapper(this));
builder.setAudioPolicyFocusListener(mFocusHandler);//向AudioPolicy中注册一个焦点管理Listener
builder.setIsAudioFocusPolicy(true);
public static CarZonesAudioFocus createCarZonesAudioFocus(AudioManager audioManager,
      PackageManager packageManager,
      SparseArray<CarAudioZone> carAudioZones,
      CarAudioSettings carAudioSettings,
      CarFocusCallback carFocusCallback,
      CarVolumeInfoWrapper carVolumeInfoWrapper) {
    Objects.requireNonNull(audioManager, "Audio manager cannot be null");
    Objects.requireNonNull(packageManager, "Package manager cannot be null");
    Objects.requireNonNull(carAudioZones, "Car audio zones cannot be null");
    Preconditions.checkArgument(carAudioZones.size() != 0,
            "There must be a minimum of one audio zone");
    Objects.requireNonNull(carAudioSettings, "Car audio settings cannot be null");
    Objects.requireNonNull(carVolumeInfoWrapper, "Car volume info cannot be null");

    SparseArray<CarAudioFocus> audioFocusPerZone = new SparseArray<>();

    //Create focus for all the zones
    //为所有区域创建焦点
    for (int i = 0; i < carAudioZones.size(); i++) {
      CarAudioZone audioZone = carAudioZones.valueAt(i);
      int audioZoneId = audioZone.getId();
      Slogf.d(TAG, "Adding new zone %d", audioZoneId);
                //使用创建的FocusInteraction作为参数创建CarAudioFocus,FocusInteraction内部定义了焦点交互矩阵
      CarAudioFocus zoneFocusListener = new CarAudioFocus(audioManager,
                packageManager, new FocusInteraction(carAudioSettings,
                new ContentObserverFactory(AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL_URI),
                audioZone.getCarAudioContext()),
                audioZone.getCarAudioContext(), carVolumeInfoWrapper, audioZoneId);
      audioFocusPerZone.put(audioZoneId, zoneFocusListener);
    }
    //返回对象
    return new CarZonesAudioFocus(audioFocusPerZone, carFocusCallback);
}
代码中使用创建的FocusInteraction作为参数创建CarAudioFocus,FocusInteraction类内部有名称为mInteractionMatrix静态数组来界说音频焦点策略
static {
    // Each Row represents CarAudioContext of current focus holder
    // Each Column represents CarAudioContext of incoming request (labels along the right)
    // Cell value is one of INTERACTION_REJECT, INTERACTION_EXCLUSIVE,
    // or INTERACTION_CONCURRENT

    // Focus holder: INVALID
    INTERACTION_MATRIX.append(/* INVALID= */ 0, new SparseArray() {
      {
            append(/* INVALID= */ 0, INTERACTION_REJECT); // INVALID
            append(MUSIC, INTERACTION_REJECT); // MUSIC
            append(NAVIGATION, INTERACTION_REJECT); // NAVIGATION
            append(VOICE_COMMAND, INTERACTION_REJECT); // VOICE_COMMAND
            append(CALL_RING, INTERACTION_REJECT); // CALL_RING
            append(CALL, INTERACTION_REJECT); // CALL
            append(ALARM, INTERACTION_REJECT); // ALARM
            append(NOTIFICATION, INTERACTION_REJECT); // NOTIFICATION
            append(SYSTEM_SOUND, INTERACTION_REJECT); // SYSTEM_SOUND,
            append(EMERGENCY, INTERACTION_EXCLUSIVE); // EMERGENCY
            append(SAFETY, INTERACTION_EXCLUSIVE); // SAFETY
            append(VEHICLE_STATUS, INTERACTION_REJECT); // VEHICLE_STATUS
            append(ANNOUNCEMENT, INTERACTION_REJECT); // ANNOUNCEMENT
      }
    });
    // Focus holder: MUSIC
    INTERACTION_MATRIX.append(MUSIC, new SparseArray() {
      {
            append(/* INVALID= */ 0, INTERACTION_REJECT); // INVALID
            append(MUSIC, INTERACTION_EXCLUSIVE); // MUSIC
            append(NAVIGATION, INTERACTION_CONCURRENT); // NAVIGATION
            append(VOICE_COMMAND, INTERACTION_EXCLUSIVE); // VOICE_COMMAND
            append(CALL_RING, INTERACTION_EXCLUSIVE); // CALL_RING
            append(CALL, INTERACTION_EXCLUSIVE); // CALL
            append(ALARM, INTERACTION_EXCLUSIVE); // ALARM
            append(NOTIFICATION, INTERACTION_CONCURRENT); // NOTIFICATION
            append(SYSTEM_SOUND, INTERACTION_CONCURRENT); // SYSTEM_SOUND,
            append(EMERGENCY, INTERACTION_EXCLUSIVE); // EMERGENCY
            append(SAFETY, INTERACTION_CONCURRENT); // SAFETY
            append(VEHICLE_STATUS, INTERACTION_CONCURRENT); // VEHICLE_STATUS
            append(ANNOUNCEMENT, INTERACTION_EXCLUSIVE); // ANNOUNCEMENT
      }
    });
    // Focus holder: NAVIGATION
    INTERACTION_MATRIX.append(NAVIGATION, new SparseArray() {
      {
            append(/* INVALID= */ 0, INTERACTION_REJECT); // INVALID
            append(MUSIC, INTERACTION_CONCURRENT); // MUSIC
            append(NAVIGATION, INTERACTION_CONCURRENT); // NAVIGATION
            append(VOICE_COMMAND, INTERACTION_EXCLUSIVE); // VOICE_COMMAND
            append(CALL_RING, INTERACTION_CONCURRENT); // CALL_RING
            append(CALL, INTERACTION_EXCLUSIVE); // CALL
            append(ALARM, INTERACTION_CONCURRENT); // ALARM
            append(NOTIFICATION, INTERACTION_CONCURRENT); // NOTIFICATION
            append(SYSTEM_SOUND, INTERACTION_CONCURRENT); // SYSTEM_SOUND,
            append(EMERGENCY, INTERACTION_EXCLUSIVE); // EMERGENCY
            append(SAFETY, INTERACTION_CONCURRENT); // SAFETY
            append(VEHICLE_STATUS, INTERACTION_CONCURRENT); // VEHICLE_STATUS
            append(ANNOUNCEMENT, INTERACTION_CONCURRENT); // ANNOUNCEMENT
      }
    });
    // Focus holder: VOICE_COMMAND
    INTERACTION_MATRIX.append(VOICE_COMMAND, new SparseArray() {
      {
            append(/* INVALID= */ 0, INTERACTION_REJECT); // INVALID
            append(MUSIC, INTERACTION_CONCURRENT); // MUSIC
            append(NAVIGATION, INTERACTION_REJECT); // NAVIGATION
            append(VOICE_COMMAND, INTERACTION_CONCURRENT); // VOICE_COMMAND
            append(CALL_RING, INTERACTION_EXCLUSIVE); // CALL_RING
            append(CALL, INTERACTION_EXCLUSIVE); // CALL
            append(ALARM, INTERACTION_REJECT); // ALARM
            append(NOTIFICATION, INTERACTION_REJECT); // NOTIFICATION
            append(SYSTEM_SOUND, INTERACTION_REJECT); // SYSTEM_SOUND,
            append(EMERGENCY, INTERACTION_EXCLUSIVE); // EMERGENCY
            append(SAFETY, INTERACTION_CONCURRENT); // SAFETY
            append(VEHICLE_STATUS, INTERACTION_CONCURRENT); // VEHICLE_STATUS
            append(ANNOUNCEMENT, INTERACTION_REJECT); // ANNOUNCEMENT
      }
    });
    // Focus holder: CALL_RING
    INTERACTION_MATRIX.append(CALL_RING, new SparseArray() {
      {
            append(/* INVALID= */ 0, INTERACTION_REJECT); // INVALID
            append(MUSIC, INTERACTION_REJECT); // MUSIC
            append(NAVIGATION, INTERACTION_CONCURRENT); // NAVIGATION
            append(VOICE_COMMAND, INTERACTION_CONCURRENT); // VOICE_COMMAND
            append(CALL_RING, INTERACTION_CONCURRENT); // CALL_RING
            append(CALL, INTERACTION_CONCURRENT); // CALL
            append(ALARM, INTERACTION_REJECT); // ALARM
            append(NOTIFICATION, INTERACTION_REJECT); // NOTIFICATION
            append(SYSTEM_SOUND, INTERACTION_CONCURRENT); // SYSTEM_SOUND,
            append(EMERGENCY, INTERACTION_EXCLUSIVE); // EMERGENCY
            append(SAFETY, INTERACTION_CONCURRENT); // SAFETY
            append(VEHICLE_STATUS, INTERACTION_CONCURRENT); // VEHICLE_STATUS
            append(ANNOUNCEMENT, INTERACTION_REJECT); // ANNOUNCEMENT
      }
    });
    // Focus holder: CALL
    INTERACTION_MATRIX.append(CALL, new SparseArray() {
      {
            append(/* INVALID= */ 0, INTERACTION_REJECT); // INVALID
            append(MUSIC, INTERACTION_REJECT); // MUSIC
            append(NAVIGATION, INTERACTION_CONCURRENT); // NAVIGATION
            append(VOICE_COMMAND, INTERACTION_REJECT); // VOICE_COMMAND
            append(CALL_RING, INTERACTION_CONCURRENT); // CALL_RING
            append(CALL, INTERACTION_CONCURRENT); // CALL
            append(ALARM, INTERACTION_CONCURRENT); // ALARM
            append(NOTIFICATION, INTERACTION_CONCURRENT); // NOTIFICATION
            append(SYSTEM_SOUND, INTERACTION_REJECT); // SYSTEM_SOUND,
            append(EMERGENCY, INTERACTION_CONCURRENT); // EMERGENCY
            append(SAFETY, INTERACTION_CONCURRENT); // SAFETY
            append(VEHICLE_STATUS, INTERACTION_CONCURRENT); // VEHICLE_STATUS
            append(ANNOUNCEMENT, INTERACTION_REJECT); // ANNOUNCEMENT
      }
    });
    // Focus holder: ALARM
    INTERACTION_MATRIX.append(ALARM, new SparseArray() {
      {
            append(/* INVALID= */ 0, INTERACTION_REJECT); // INVALID
            append(MUSIC, INTERACTION_CONCURRENT); // MUSIC
            append(NAVIGATION, INTERACTION_CONCURRENT); // NAVIGATION
            append(VOICE_COMMAND, INTERACTION_EXCLUSIVE); // VOICE_COMMAND
            append(CALL_RING, INTERACTION_EXCLUSIVE); // CALL_RING
            append(CALL, INTERACTION_EXCLUSIVE); // CALL
            append(ALARM, INTERACTION_CONCURRENT); // ALARM
            append(NOTIFICATION, INTERACTION_CONCURRENT); // NOTIFICATION
            append(SYSTEM_SOUND, INTERACTION_CONCURRENT); // SYSTEM_SOUND,
            append(EMERGENCY, INTERACTION_EXCLUSIVE); // EMERGENCY
            append(SAFETY, INTERACTION_CONCURRENT); // SAFETY
            append(VEHICLE_STATUS, INTERACTION_CONCURRENT); // VEHICLE_STATUS
            append(ANNOUNCEMENT, INTERACTION_REJECT); // ANNOUNCEMENT
      }
    });
    // Focus holder: NOTIFICATION
    INTERACTION_MATRIX.append(NOTIFICATION, new SparseArray() {
      {
            append(/* INVALID= */ 0, INTERACTION_REJECT); // INVALID
            append(MUSIC, INTERACTION_CONCURRENT); // MUSIC
            append(NAVIGATION, INTERACTION_CONCURRENT); // NAVIGATION
            append(VOICE_COMMAND, INTERACTION_EXCLUSIVE); // VOICE_COMMAND
            append(CALL_RING, INTERACTION_EXCLUSIVE); // CALL_RING
            append(CALL, INTERACTION_EXCLUSIVE); // CALL
            append(ALARM, INTERACTION_CONCURRENT); // ALARM
            append(NOTIFICATION, INTERACTION_CONCURRENT); // NOTIFICATION
            append(SYSTEM_SOUND, INTERACTION_CONCURRENT); // SYSTEM_SOUND,
            append(EMERGENCY, INTERACTION_EXCLUSIVE); // EMERGENCY
            append(SAFETY, INTERACTION_CONCURRENT); // SAFETY
            append(VEHICLE_STATUS, INTERACTION_CONCURRENT); // VEHICLE_STATUS
            append(ANNOUNCEMENT, INTERACTION_CONCURRENT); // ANNOUNCEMENT
      }
    });
    // Focus holder: SYSTEM_SOUND
    INTERACTION_MATRIX.append(SYSTEM_SOUND, new SparseArray() {
      {
            append(/* INVALID= */ 0, INTERACTION_REJECT); // INVALID
            append(MUSIC, INTERACTION_CONCURRENT); // MUSIC
            append(NAVIGATION, INTERACTION_CONCURRENT); // NAVIGATION
            append(VOICE_COMMAND, INTERACTION_EXCLUSIVE); // VOICE_COMMAND
            append(CALL_RING, INTERACTION_EXCLUSIVE); // CALL_RING
            append(CALL, INTERACTION_EXCLUSIVE); // CALL
            append(ALARM, INTERACTION_CONCURRENT); // ALARM
            append(NOTIFICATION, INTERACTION_CONCURRENT); // NOTIFICATION
            append(SYSTEM_SOUND, INTERACTION_CONCURRENT); // SYSTEM_SOUND,
            append(EMERGENCY, INTERACTION_EXCLUSIVE); // EMERGENCY
            append(SAFETY, INTERACTION_CONCURRENT); // SAFETY
            append(VEHICLE_STATUS, INTERACTION_CONCURRENT); // VEHICLE_STATUS
            append(ANNOUNCEMENT, INTERACTION_CONCURRENT); // ANNOUNCEMENT
      }
    });
    // Focus holder: EMERGENCY
    INTERACTION_MATRIX.append(EMERGENCY, new SparseArray() {
      {
            append(/* INVALID= */ 0, INTERACTION_REJECT); // INVALID
            append(MUSIC, INTERACTION_REJECT); // MUSIC
            append(NAVIGATION, INTERACTION_REJECT); // NAVIGATION
            append(VOICE_COMMAND, INTERACTION_REJECT); // VOICE_COMMAND
            append(CALL_RING, INTERACTION_REJECT); // CALL_RING
            append(CALL, INTERACTION_CONCURRENT); // CALL
            append(ALARM, INTERACTION_REJECT); // ALARM
            append(NOTIFICATION, INTERACTION_REJECT); // NOTIFICATION
            append(SYSTEM_SOUND, INTERACTION_REJECT); // SYSTEM_SOUND,
            append(EMERGENCY, INTERACTION_CONCURRENT); // EMERGENCY
            append(SAFETY, INTERACTION_CONCURRENT); // SAFETY
            append(VEHICLE_STATUS, INTERACTION_REJECT); // VEHICLE_STATUS
            append(ANNOUNCEMENT, INTERACTION_REJECT); // ANNOUNCEMENT
      }
    });
    // Focus holder: SAFETY
    INTERACTION_MATRIX.append(SAFETY, new SparseArray() {
      {
            append(/* INVALID= */ 0, INTERACTION_REJECT); // INVALID
            append(MUSIC, INTERACTION_CONCURRENT); // MUSIC
            append(NAVIGATION, INTERACTION_CONCURRENT); // NAVIGATION
            append(VOICE_COMMAND, INTERACTION_CONCURRENT); // VOICE_COMMAND
            append(CALL_RING, INTERACTION_CONCURRENT); // CALL_RING
            append(CALL, INTERACTION_CONCURRENT); // CALL
            append(ALARM, INTERACTION_CONCURRENT); // ALARM
            append(NOTIFICATION, INTERACTION_CONCURRENT); // NOTIFICATION
            append(SYSTEM_SOUND, INTERACTION_CONCURRENT); // SYSTEM_SOUND,
            append(EMERGENCY, INTERACTION_CONCURRENT); // EMERGENCY
            append(SAFETY, INTERACTION_CONCURRENT); // SAFETY
            append(VEHICLE_STATUS, INTERACTION_CONCURRENT); // VEHICLE_STATUS
            append(ANNOUNCEMENT, INTERACTION_CONCURRENT); // ANNOUNCEMENT
      }
    });
    // Focus holder: VEHICLE_STATUS
    INTERACTION_MATRIX.append(VEHICLE_STATUS, new SparseArray() {
      {
            append(/* INVALID= */ 0, INTERACTION_REJECT); // INVALID
            append(MUSIC, INTERACTION_CONCURRENT); // MUSIC
            append(NAVIGATION, INTERACTION_CONCURRENT); // NAVIGATION
            append(VOICE_COMMAND, INTERACTION_CONCURRENT); // VOICE_COMMAND
            append(CALL_RING, INTERACTION_CONCURRENT); // CALL_RING
            append(CALL, INTERACTION_CONCURRENT); // CALL
            append(ALARM, INTERACTION_CONCURRENT); // ALARM
            append(NOTIFICATION, INTERACTION_CONCURRENT); // NOTIFICATION
            append(SYSTEM_SOUND, INTERACTION_CONCURRENT); // SYSTEM_SOUND,
            append(EMERGENCY, INTERACTION_EXCLUSIVE); // EMERGENCY
            append(SAFETY, INTERACTION_CONCURRENT); // SAFETY
            append(VEHICLE_STATUS, INTERACTION_CONCURRENT); // VEHICLE_STATUS
            append(ANNOUNCEMENT, INTERACTION_CONCURRENT); // ANNOUNCEMENT
      }
    });
    // Focus holder: ANNOUNCEMENT
    INTERACTION_MATRIX.append(ANNOUNCEMENT, new SparseArray() {
      {
            append(/* INVALID= */ 0, INTERACTION_REJECT); // INVALID
            append(MUSIC, INTERACTION_EXCLUSIVE); // MUSIC
            append(NAVIGATION, INTERACTION_CONCURRENT); // NAVIGATION
            append(VOICE_COMMAND, INTERACTION_EXCLUSIVE); // VOICE_COMMAND
            append(CALL_RING, INTERACTION_EXCLUSIVE); // CALL_RING
            append(CALL, INTERACTION_EXCLUSIVE); // CALL
            append(ALARM, INTERACTION_EXCLUSIVE); // ALARM
            append(NOTIFICATION, INTERACTION_CONCURRENT); // NOTIFICATION
            append(SYSTEM_SOUND, INTERACTION_CONCURRENT); // SYSTEM_SOUND,
            append(EMERGENCY, INTERACTION_EXCLUSIVE); // EMERGENCY
            append(SAFETY, INTERACTION_CONCURRENT); // SAFETY
            append(VEHICLE_STATUS, INTERACTION_CONCURRENT); // VEHICLE_STATUS
            append(ANNOUNCEMENT, INTERACTION_EXCLUSIVE); // ANNOUNCEMENT
      }
    });
}
CarAudioFocus的构造函数如下
class CarAudioFocus extends AudioPolicy.AudioPolicyFocusListener {
    CarAudioFocus(AudioManager audioManager, PackageManager packageManager,
            FocusInteraction focusInteraction, CarAudioContext carAudioContext,
            CarVolumeInfoWrapper volumeInfoWrapper, int zoneId) {
      mAudioManager = Objects.requireNonNull(audioManager, "Audio manager can not be null");
      mPackageManager = Objects.requireNonNull(packageManager, "Package manager can not null");
      mFocusEventLogger = new LocalLog(FOCUS_EVENT_LOGGER_QUEUE_SIZE);
      mFocusInteraction = Objects.requireNonNull(focusInteraction,
                "Focus interactions can not be null");
      mCarAudioContext = Objects.requireNonNull(carAudioContext,
                "Car audio context can not be null");
      mCarVolumeInfoWrapper = Objects.requireNonNull(volumeInfoWrapper,
                "Car volume info can not be null");
      mAudioZoneId = zoneId;
    }
}
CarAudioFocus继承于AudioPolicy.AudioPolicyFocusListener,当有AudioFocus哀求时,就会调用CarAudioFocus的onAudioFocusRequest或onAudioFocusAbandon方法
setupOccupantZoneInfoLocked

private void setupOccupantZoneInfoLocked() {
    CarOccupantZoneService occupantZoneService;
    SparseIntArray audioZoneIdToOccupantZoneMapping;
    audioZoneIdToOccupantZoneMapping = mAudioZoneIdToOccupantZoneIdMapping;
    occupantZoneService = mOccupantZoneService;
    //设置音频区 ID 到占用区 ID 的映射
    occupantZoneService.setAudioZoneIdsForOccupantZoneIds(audioZoneIdToOccupantZoneMapping);
    occupantZoneService.registerCallback(mOccupantZoneCallback);
}
setupHalAudioFocusListenerLocked

private void setupHalAudioFocusListenerLocked() {
    AudioControlWrapper audioControlWrapper = getAudioControlWrapperLocked();
    if (!audioControlWrapper.supportsFeature(AUDIOCONTROL_FEATURE_AUDIO_FOCUS)) {
      Slogf.d(TAG, "HalAudioFocus is not supported on this device");
      return;
    }
        //创建HalAudioFocus对象
    mHalAudioFocus = new HalAudioFocus(mAudioManager, mAudioControlWrapper, getAudioZoneIds());
    //注册音频焦点监听器
    mHalAudioFocus.registerFocusListener();
}
//调用HalAudioFocus的registerFocusListener方法
//packages/services/Car/service/src/com/android/car/audio/hal/HalAudioFocus.java
public final class HalAudioFocus implements HalFocusListener {
    private final AudioControlWrapper mAudioControlWrapper;
    public void registerFocusListener() {
      mAudioControlWrapper.registerFocusListener(this);
    }
}
调用AudioControlWrapper的registerFocusListener方法,AudioControlWrapper是一个接口,由AudioControlWrapperAidl、AudioControlWrapperV1、AudioControlWrapperV2 实现,我们看AudioControlWrapperAidl的registerFocusListener方法:
//packages/services/Car/service/src/com/android/car/audio/hal/AudioControlWrapperAidl.java
public final class AudioControlWrapperAidl implements AudioControlWrapper {
    private IAudioControl mAudioControl;
    public void registerFocusListener(HalFocusListener focusListener) {
      if (Slogf.isLoggable(TAG, Log.DEBUG)) {
            Slogf.d(TAG, "Registering focus listener on AudioControl HAL");
      }
      IFocusListener listenerWrapper = new FocusListenerWrapper(focusListener); //创建FocusListenerWrapper
      try {
            mAudioControl.registerFocusListener(listenerWrapper); //调用AudioControl的registerFocusListener方法
      } catch (RemoteException e) {
            Slogf.e(TAG, "Failed to register focus listener");
            throw new IllegalStateException("IAudioControl#registerFocusListener failed", e);
      }
      mListenerRegistered = true;
    }
}
调用IAudioControl的registerFocusListener方法,IAudioControl是一个接口,由AudioControl HAL实现,因此会调用AudioControl HAL的registerFocusListener方法:
//hardware/interfaces/automotive/audiocontrol/aidl/default/AudioControl.cpp
ndk::ScopedAStatus AudioControl::registerFocusListener(
      const shared_ptr<IFocusListener>& in_listener) {
    LOG(DEBUG) << "registering focus listener";

    if (in_listener) {
      std::atomic_store(&mFocusListener, in_listener);
    } else {
      LOG(ERROR) << "Unexpected nullptr for listener resulting in no-op.";
    }
    return ndk::ScopedAStatus::ok();
}
在AudioControl的registerFocusListener方法中将传入的IFocusListener存放到本地变量mFocusListener 中,如许AudioControl HAL就可以通过mFocusListener 调用上层注册的回调方法了。
setupHalAudioGainCallbackLocked

//packages/services/Car/service/src/com/android/car/audio/CarAudioService.java
public class CarAudioService extends ICarAudio.Stub implements CarServiceBase {
    private AudioControlWrapper mAudioControlWrapper;
    private void setupHalAudioGainCallbackLocked() {
      AudioControlWrapper audioControlWrapper = getAudioControlWrapperLocked();
      if (!audioControlWrapper.supportsFeature(AUDIOCONTROL_FEATURE_AUDIO_GAIN_CALLBACK)) {
            Slogf.d(CarLog.TAG_AUDIO, "HalAudioGainCallback is not supported on this device");
            return;
      }
      //创建CarAudioGainMonitor对象
      mCarAudioGainMonitor = new CarAudioGainMonitor(mAudioControlWrapper, mCarAudioZones);
      //调用CarAudioGainMonitor的registerAudioGainListener方法
      mCarAudioGainMonitor.registerAudioGainListener(mHalAudioGainCallback);
    }
}
调用CarAudioGainMonitor的registerAudioGainListener方法
//packages/services/Car/service/src/com/android/car/audio/CarAudioGainMonitor.java
final class CarAudioGainMonitor {
    @NonNull private final AudioControlWrapper mAudioControlWrapper;
    public void registerAudioGainListener(HalAudioGainCallback callback) {
      Objects.requireNonNull(callback, "Hal Audio Gain callback can not be null");
      mAudioControlWrapper.registerAudioGainCallback(callback); //调用AudioControlWrapper的registerAudioGainCallback方法
    }
}
调用AudioControlWrapper的registerAudioGainCallback方法:
//packages/services/Car/service/src/com/android/car/audio/hal/AudioControlWrapperAidl.java
//Wrapper for AIDL interface for AudioControl HAL
public final class AudioControlWrapperAidl implements AudioControlWrapper {
    private IAudioControl mAudioControl;
    public void registerAudioGainCallback(HalAudioGainCallback gainCallback) {
      if (Log.isLoggable(TAG, Log.DEBUG)) {
            Slogf.d(TAG, "Registering Audio Gain Callback on AudioControl HAL");
      }
      Objects.requireNonNull(gainCallback);
      IAudioGainCallback agc = new AudioGainCallbackWrapper(gainCallback); //创建AudioGainCallbackWrapper类对象
      try {
            mAudioControl.registerGainCallback(agc); //调用IAudioControl的registerGainCallback方法
      } catch (RemoteException e) {
            Slogf.e(TAG, "Failed to register gain callback");
            throw new IllegalStateException("IAudioControl#registerAudioGainCallback failed", e);
      }
      mGainCallbackRegistered = true;
    }
}
调用IAudioControl的registerGainCallback方法,IAudioControl是一个接口,由AudioControl HAL实现,会调用AudioControl HAL的registerGainCallback方法。
ndk::ScopedAStatus AudioControl::registerGainCallback(
      const std::shared_ptr<IAudioGainCallback>& in_callback) {
    LOG(DEBUG) << ": " << __func__;
    if (in_callback) {
      std::atomic_store(&mAudioGainCallback, in_callback);
    } else {
      LOG(ERROR) << "Unexpected nullptr for audio gain callback resulting in no-op.";
    }
    return ndk::ScopedAStatus::ok();
}
在AudioControl的registerGainCallback方法中将传入的IAudioGainCallback存放到本地变量mAudioGainCallback中,如许AudioControl HAL就可以通过mAudioGainCallback调用上层注册的回调方法了
setupAudioConfigurationCallbackLocked

//packages/services/Car/service/src/com/android/car/audio/audio/CarAudioService.java
public class CarAudioService extends ICarAudio.Stub implements CarServiceBase {
    private void setupAudioConfigurationCallbackLocked() {
      mCarAudioPlaybackCallback =
                new CarAudioPlaybackCallback(getCarAudioZone(PRIMARY_AUDIO_ZONE),
                        mClock, mKeyEventTimeoutMs);//创建CarAudioPlaybackCallback对象
      mAudioManager.registerAudioPlaybackCallback(mCarAudioPlaybackCallback, null); //向AudioManager注册PlaybackCallback
    }
}
setupPowerPolicyListener

//packages/services/Car/service/src/com/android/car/audio/CarAudioService.java
public class CarAudioService extends ICarAudio.Stub implements CarServiceBase {
    private CarAudioPowerListener mCarAudioPowerListener;
    private void setupPowerPolicyListener() {
      mCarAudioPowerListener = CarAudioPowerListener.newCarAudioPowerListener(this); //调用CarAudioPowerListener的newCarAudioPowerListener方法,创建CarAudioPowerListener对象
      mCarAudioPowerListener.startListeningForPolicyChanges(); //调用CarAudioPowerListener的startListeningForPolicyChanges方法
    }
}
上面方法调用如下两个方法:
调用CarAudioPowerListener的newCarAudioPowerListener方法,创建CarAudioPowerListener对象。
调用CarAudioPowerListener的startListeningForPolicyChanges方法。
//packages/services/Car/service/src/com/android/car/audio/CarAudioPowerListener.java
class CarAudioPowerListener {
    static CarAudioPowerListener newCarAudioPowerListener(
            @NonNull CarAudioService carAudioService) {
      CarPowerManagementService carPowerService = CarLocalServices.getService(
                CarPowerManagementService.class); //获取carPowerService实例
      return new CarAudioPowerListener(carAudioService, carPowerService); //创建CarAudioPowerListener并返回其对象
    }
}
CarAudioPowerListener的构造函数如下:
//packages/services/Car/service/src/com/android/car/audio/CarAudioPowerListener.java
class CarAudioPowerListener {
    private final CarPowerManagementService mCarPowerManagementService;
    CarAudioPowerListener(@NonNull CarAudioService carAudioService,
            CarPowerManagementService carPowerManagementService) {
      mCarAudioService = Objects.requireNonNull(carAudioService);
      mCarPowerManagementService = carPowerManagementService;
    }
}
我们继承看CarAudioPowerListener的startListeningForPolicyChanges方法:
//packages/services/Car/service/src/com/android/car/audio/CarAudioPowerListener.java
class CarAudioPowerListener {
    private final CarAudioService mCarAudioService;
    private final CarPowerManagementService mCarPowerManagementService;
    void startListeningForPolicyChanges() {
      if (mCarPowerManagementService == null) {
            Slogf.w(TAG, "Cannot find CarPowerManagementService");
            return;
      }


      CarPowerPolicyFilter filter = new CarPowerPolicyFilter.Builder()
                .setComponents(AUDIO).build(); //创建CarPowerPolicyFilter对象
      mCarPowerManagementService.addPowerPolicyListener(filter, mChangeListener); //调用CarPowerManagementService的addPowerPolicyListener方法
      initializePowerState(); //初始化电源状态
    }

}
上面代码主要举行如下处理:
创建CarPowerPolicyFilter对象,然后CarPowerManagementService的addPowerPolicyListener方法,追加PowerPolicy的监听。
调用initializePowerState初始化电源状态。
当PowerPolicy变化时,ICarPowerPolicyListener的onPolicyChanged方法会被调用,代码如下
//packages/services/Car/service/src/com/android/car/audio/CarAudioPowerListener.java
class CarAudioPowerListener {
    private boolean mIsAudioEnabled;
    private final ICarPowerPolicyListener mChangeListener =
            new ICarPowerPolicyListener.Stub() {
                @Override
                public void onPolicyChanged(CarPowerPolicy policy,
                        CarPowerPolicy accumulatedPolicy) {
                  synchronized (mLock) {
                        if (mIsAudioEnabled != accumulatedPolicy.isComponentEnabled(AUDIO)) { //如果AudioEnable状态与CarPowerPolicy的AudioEnable状态不一致
                            updateAudioPowerStateLocked(accumulatedPolicy); //调用updateAudioPowerStateLocked方法
                        }
                  }
                }
            };
}
我们继承看initializePowerState方法
//packages/services/Car/service/src/com/android/car/audio/CarAudioPowerListener.java
class CarAudioPowerListener {
    private final CarAudioService mCarAudioService;
    private void initializePowerState() {
      CarPowerPolicy policy = mCarPowerManagementService.getCurrentPowerPolicy(); //取得当前的CarPowerPolicy
      if (policy == null) {
            Slogf.w(TAG, "Policy is null. Defaulting to enabled");
            return;
      }
      synchronized (mLock) {
            updateAudioPowerStateLocked(policy); //调用updateAudioPowerStateLocked方法,更新AudioPower状态
      }
    }
}
调用updateAudioPowerStateLocked方法
//packages/services/Car/service/src/com/android/car/audio/CarAudioPowerListener.java
class CarAudioPowerListener {
    private void updateAudioPowerStateLocked(CarPowerPolicy policy) {
      mIsAudioEnabled = policy.isComponentEnabled(AUDIO); //取得mIsAudioEnabled状态
      mCarAudioService.setAudioEnabled(mIsAudioEnabled); //调用setAudioEnabled设置AudioEnable状态
    }
}
调用setAudioEnabled设置AudioEnable状态
//packages/services/Car/service/src/com/android/car/audio/audioCarAudioService.java
public class CarAudioService extends ICarAudio.Stub implements CarServiceBase {
    private CarZonesAudioFocus mFocusHandler;
    private CarVolumeGroupMuting mCarVolumeGroupMuting;
    void setAudioEnabled(boolean isAudioEnabled) {
      Slogf.d(TAG, "Setting isAudioEnabled to %b", isAudioEnabled);
      mFocusHandler.setRestrictFocus(/* isFocusRestricted= */ !isAudioEnabled); //调用CarZonesAudioFocus的setRestrictFocus方法
      if (mUseCarVolumeGroupMuting) {
            mCarVolumeGroupMuting.setRestrictMuting(/* isMutingRestricted= */ !isAudioEnabled); //调用CarVolumeGroupMuting的setRestrictMuting方法
      }
      // TODO(b/176258537) if not using group volume, then set master mute accordingly
    }

}
CarZonesAudioFocus.setRestrictFocus
//packages/services/Car/service/src/com/android/car/audio/CarZonesAudioFocus.java
final class CarZonesAudioFocus extends AudioPolicy.AudioPolicyFocusListener {
    void setRestrictFocus(boolean isFocusRestricted) {
      int[] zoneIds = new int;
      for (int i = 0; i < mFocusZones.size(); i++) {
            zoneIds = mFocusZones.keyAt(i);
            mFocusZones.valueAt(i).setRestrictFocus(isFocusRestricted);
      }
      notifyFocusCallback(zoneIds); //通知音频焦点回调,之后会进行进行Ducking处理
    }
}
CarVolumeGroupMuting.setRestrictMuting
//packages/services/Car/service/src/com/android/car/audio/CarVolumeGroupMuting.java
final class CarVolumeGroupMuting {
    public void setRestrictMuting(boolean isMutingRestricted) {
      synchronized (mLock) {
            mIsMutingRestricted = isMutingRestricted;
      }
      carMuteChanged(); //调用carMuteChanged方法
    }
}
调用carMuteChanged方法:
//packages/services/Car/service/src/com/android/car/audio/CarVolumeGroupMuting.java
final class CarVolumeGroupMuting {
    private final AudioControlWrapper mAudioControlWrapper;
    public void carMuteChanged() {
      if (Slogf.isLoggable(TAG, Log.DEBUG)) {
            Slogf.d(TAG, "carMuteChanged");
      }
      List<MutingInfo> mutingInfo = generateMutingInfo(); //生成mutingInfo
      setLastMutingInfo(mutingInfo); //记录LastMutingInfo
      mAudioControlWrapper.onDevicesToMuteChange(mutingInfo); //通过AudioControlWrapper,调用audiocontrol
    }
}
我们先看generateMutingInfo
//packages/services/Car/service/src/com/android/car/audio/CarVolumeGroupMuting.java
final class CarVolumeGroupMuting {
    private List<MutingInfo> generateMutingInfo() {
      List<MutingInfo> mutingInformation = new ArrayList<>(mCarAudioZones.size());
      boolean isMutingRestricted = isMutingRestricted();
      for (int index = 0; index < mCarAudioZones.size(); index++) {
            //调用generateMutingInfoFromZone方法生成generateMutingInfo,然后加入到MutingInfo队列
            mutingInformation.add(generateMutingInfoFromZone(mCarAudioZones.valueAt(index),
                  isMutingRestricted));
      }
      return mutingInformation;
    }
}
调用generateMutingInfoFromZone方法:
//packages/services/Car/service/src/com/android/car/audio/CarVolumeGroupMuting.java
final class CarVolumeGroupMuting {
    static MutingInfo generateMutingInfoFromZone(CarAudioZone audioZone,
            boolean isMutingRestricted) {
      MutingInfo mutingInfo = new MutingInfo();
      mutingInfo.zoneId = audioZone.getId();
      List<String> mutedDevices = new ArrayList<>();
      List<String> unMutedDevices = new ArrayList<>();
      CarVolumeGroup[] groups = audioZone.getVolumeGroups();
      for (int groupIndex = 0; groupIndex < groups.length; groupIndex++) {
            CarVolumeGroup group = groups;
            if (group.isMuted() || (isMutingRestricted && !group.hasCriticalAudioContexts())) {
                mutedDevices.addAll(group.getAddresses());
            } else {
                unMutedDevices.addAll(group.getAddresses());
            }
      }
      mutingInfo.deviceAddressesToMute = mutedDevices.toArray(new String);
      mutingInfo.deviceAddressesToUnmute =
                unMutedDevices.toArray(new String);
      return mutingInfo;
    }
}
继承看AudioControlWrapper的onDevicesToMuteChange方法:
//packages/services/Car/service/src/com/android/car/audio/hal/AudioControlWrapperAidl.java
public final class AudioControlWrapperAidl implements AudioControlWrapper {
    private IAudioControl mAudioControl;
    @Override
    public void onDevicesToMuteChange(@NonNull List<MutingInfo> carZonesMutingInfo) {
      Objects.requireNonNull(carZonesMutingInfo, "Muting info can not be null");
      Preconditions.checkArgument(!carZonesMutingInfo.isEmpty(), "Muting info can not be empty");
      MutingInfo[] mutingInfoToHal = carZonesMutingInfo
                .toArray(new MutingInfo); //取得MutingInfo
      try {
            mAudioControl.onDevicesToMuteChange(mutingInfoToHal); //调用IAudioControl 的onDevicesToMuteChange方法
      } catch (RemoteException e) {
            Slogf.e(TAG, "onDevicesToMuteChange failed", e);
      }
    }
}
调用IAudioControl的onDevicesToMuteChange方法,IAudioControl是一个Aidl接口,由AudioControl实现,因此会调用AudioControl的onDevicesToMuteChange方法
ndk::ScopedAStatus AudioControl::onDevicesToMuteChange(
      const std::vector<MutingInfo>& in_mutingInfos) {
    LOG(INFO) << "AudioControl::onDevicesToMuteChange";
    for (const MutingInfo& mutingInfo : in_mutingInfos) {
      LOG(INFO) << "zone: " << mutingInfo.zoneId;
      LOG(INFO) << "Devices to mute:";
      for (const auto& addressToMute : mutingInfo.deviceAddressesToMute) {
            LOG(INFO) << addressToMute;
      }
      LOG(INFO) << "Devices to unmute:";
      for (const auto& addressToUnmute : mutingInfo.deviceAddressesToUnmute) {
            LOG(INFO) << addressToUnmute;
      }
    }
    return ndk::ScopedAStatus::ok();
}
restoreMasterMuteState

private void restoreMasterMuteState() {
    //如果使用CarVolumeGroupMuting,直接返回
    if (mUseCarVolumeGroupMuting) {
      return;
    }
    // Restore master mute state if applicable
    if (mPersistMasterMuteState) {
      //调用CarAudioSettings的getMasterMute方法,获取storedMasterMute状态
      boolean storedMasterMute = mCarAudioSettings.isMasterMute();
      setMasterMute(storedMasterMute, 0);
    }
}
CarAudioSettings的getMasterMute方法
//packages/services/Car/car-lib/src/android/car/audio/CarAudioSettings.java
public class CarAudioSettings {
    boolean getMasterMute() {
      return Settings.Global.getInt(mContext.getContentResolver(),
                VOLUME_SETTINGS_KEY_MASTER_MUTE, 0) != 0;
    }
}
setMasterMute
//packages/services/Car/service/src/com/android/car/audio/CarAudioService.java
public class CarAudioService extends ICarAudio.Stub implements CarServiceBase {
    void setMasterMute(boolean mute, int flags) {
      AudioManagerHelper.setMasterMute(mAudioManager, mute, flags); //调用AudioManagerHelper的setMasterMute方法
      // Master Mute only applies to primary zone
      callbackMasterMuteChange(PRIMARY_AUDIO_ZONE, flags); //调用callbackMasterMuteChange方法
    }

}
callbackMasterMuteChange
//packages/services/Car/service/src/com/android/car/audio/CarAudioService.java
public class CarAudioService extends ICarAudio.Stub implements CarServiceBase {
    private final CarVolumeCallbackHandler mCarVolumeCallbackHandler;
    private final CarAudioSettings mCarAudioSettings;
    void callbackMasterMuteChange(int zoneId, int flags) {
      mCarVolumeCallbackHandler.onMasterMuteChanged(zoneId, flags); //调用CarVolumeCallbackHandler的onMasterMuteChanged方法
      // Persists master mute state if applicable
      if (mPersistMasterMuteState) {
            mCarAudioSettings.storeMasterMute(isMasterMute(mAudioManager));//调用CarAudioSettings的storeMasterMute方法
      }
    }
}
CarVolumeCallbackHandler的onMasterMuteChanged方法:
//packages/services/Car/service/src/com/android/car/audio/CarVolumeCallbackHandler.java
class CarVolumeCallbackHandler {
    void onMasterMuteChanged(int zoneId, int flags) {
      for (BinderInterfaceContainer.BinderInterface<ICarVolumeCallback> callback :
                mVolumeCallbackContainer.getInterfaces()) {
            try {
                callback.binderInterface.onMasterMuteChanged(zoneId, flags); //
            } catch (RemoteException e) {
                Slogf.e(CarLog.TAG_AUDIO, "Failed to callback onMasterMuteChanged", e);
            }
      }
    }
}
调用ICarVolumeCallback的onMasterMuteChanged方法,ICarVolumeCallback是一个接口由CarAudioManager实现:
//packages/services/Car/car-lib/src/android/car/media/CarAudioManager.java
public final class CarAudioManager extends CarManagerBase {
    private final CarVolumeCallbackHandler mCarVolumeCallbackHandler;
    private final ICarVolumeCallback mCarVolumeCallbackImpl =
            new android.car.media.ICarVolumeCallback.Stub() {
      @Override
      public void onMasterMuteChanged(int zoneId, int flags) {
            mEventHandler.dispatchOnMasterMuteChanged(zoneId, flags); //调用CarVolumeCallbackHandler的dispatchOnMasterMuteChanged方法
      }
    }
}
调用CarVolumeCallbackHandler的dispatchOnMasterMuteChanged方法
//packages/services/Car/car-lib/src/android/car/media/CarAudioManager.java
public final class CarAudioManager extends CarManagerBase {
    private final class EventHandler extends Handler {
      private void dispatchOnMasterMuteChanged(int zoneId, int flags) {
            sendMessage(obtainMessage(MSG_MASTER_MUTE_CHANGE, zoneId, flags)); //发送MSG_MASTER_MUTE_CHANGE消息
      }
    }
}
发送MSG_MASTER_MUTE_CHANGE消息,发送的消息会在CarAudioManager的内部类EventHandler的handleMessage中处理
//packages/services/Car/car-lib/src/android/car/media/CarAudioManager.java
public final class CarAudioManager extends CarManagerBase {
    private final class EventHandler extends Handler {
      @Override
      public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_MASTER_MUTE_CHANGE:
                  handleOnMasterMuteChanged(msg.arg1, msg.arg2); //调用handleOnMasterMuteChanged方法
                  break;
                default:
                  Log.e(CarLibLog.TAG_CAR, "Unknown nessage not handled:" + msg.what);
                  break;
            }
      }
}
调用handleOnMasterMuteChanged方法
//packages/services/Car/car-lib/src/android/car/media/CarAudioManager.java
public final class CarAudioManager extends CarManagerBase {
    private void handleOnMasterMuteChanged(int zoneId, int flags) {
      for (CarVolumeCallback callback : mCarVolumeCallbacks) {
            callback.onMasterMuteChanged(zoneId, flags); //调用CarVolumeCallback的onMasterMuteChanged方法,通知监听的APP
      }
    }
}
CarAudioSettings.storeMasterMute
//packages/services/Car/car-lib/src/android/car/audio/CarAudioSettings.java
public class CarAudioSettings {
    void storeMasterMute(Boolean masterMuteValue) {
      Settings.Global.putInt(mContext.getContentResolver(),
                VOLUME_SETTINGS_KEY_MASTER_MUTE,
                masterMuteValue ? 1 : 0);
    }
}
car_audio_configuration.xml配置文件

car_audio_configuration.xml配置文件路径
//配置文件路劲
private static final String[] AUDIO_CONFIGURATION_PATHS = new String[] {
      "/vendor/etc/car_audio_configuration.xml",
      "/system/etc/car_audio_configuration.xml"
};
car_audio_configuration.xml配置文件中,包含三部分节点**、和。**以下是car_audio_configuration.xml配置文件的示例。
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2020 The Android Open Source Project

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
-->

<!--
Defines the audio configuration in a car, including
    - Audio zones
    - Zone configurations (in each audio zone)
    - Volume groups (in each zone configuration)
    - Context to audio bus mappings (in each volume group)
in the car environment.
-->
<carAudioConfiguration version="3">
    <zones>
      <zone name="primary zone" isPrimary="true" occupantZoneId="0">
            <zoneConfigs>
                <zoneConfig name="primary zone config 0" isDefault="true">
                  <volumeGroups>
                        <group>
                            <device address="bus0_media_out">
                              <context context="music"/>
                              <context context="announcement"/>
                            </device>
                            <device address="bus6_notification_out">
                              <context context="notification"/>
                            </device>
                        </group>
                        <group>
                            <device address="bus1_navigation_out">
                              <context context="navigation"/>
                            </device>
                            <device address="bus2_voice_command_out">
                              <context context="voice_command"/>
                            </device>
                        </group>
                        <group>
                            <device address="bus4_call_out">
                              <context context="call"/>
                            </device>
                            <device address="bus3_call_ring_out">
                              <context context="call_ring"/>
                            </device>
                        </group>
                        <group>
                            <device address="bus5_alarm_out">
                              <context context="alarm"/>
                            </device>
                            <device address="bus7_system_sound_out">
                              <context context="system_sound"/>
                              <context context="emergency"/>
                              <context context="safety"/>
                              <context context="vehicle_status"/>
                            </device>
                        </group>
                  </volumeGroups>
                </zoneConfig>
            </zoneConfigs>
      </zone>
      <zone name="rear seat zone 1" audioZoneId="1">
            <zoneConfigs>
                <zoneConfig name="rear seat zone 1 config 0" isDefault="true">
                  <volumeGroups>
                        <group>
                            <device address="bus100_audio_zone_1">
                              <context context="music"/>
                            </device>
                        </group>
                        <group>
                            <device address="bus101_audio_zone_1">
                              <context context="navigation"/>
                              <context context="voice_command"/>
                              <context context="call_ring"/>
                              <context context="call"/>
                              <context context="alarm"/>
                              <context context="notification"/>
                              <context context="system_sound"/>
                              <context context="emergency"/>
                              <context context="safety"/>
                              <context context="vehicle_status"/>
                              <context context="announcement"/>
                            </device>
                        </group>
                  </volumeGroups>
                </zoneConfig>
                <zoneConfig name="rear seat zone 1 config 1">
                  <volumeGroups>
                        <group>
                            <device address="bus110_audio_zone_1">
                              <context context="music"/>
                            </device>
                        </group>
                        <group>
                            <device address="bus111_audio_zone_1">
                              <context context="navigation"/>
                              <context context="voice_command"/>
                              <context context="call_ring"/>
                              <context context="call"/>
                              <context context="alarm"/>
                              <context context="notification"/>
                              <context context="system_sound"/>
                              <context context="emergency"/>
                              <context context="safety"/>
                              <context context="vehicle_status"/>
                              <context context="announcement"/>
                            </device>
                        </group>
                  </volumeGroups>
                </zoneConfig>
            </zoneConfigs>
      </zone>
      <zone name="rear seat zone 2"audioZoneId="2">
            <zoneConfigs>
                <zoneConfig name="rear seat zone 2 config 0" isDefault="true">
                  <volumeGroups>
                        <group>
                            <device address="bus200_audio_zone_2">
                              <context context="music"/>
                            </device>
                        </group>
                        <group>
                            <device address="bus201_audio_zone_2">
                              <context context="navigation"/>
                              <context context="voice_command"/>
                              <context context="call_ring"/>
                              <context context="call"/>
                              <context context="alarm"/>
                              <context context="notification"/>
                              <context context="system_sound"/>
                              <context context="emergency"/>
                              <context context="safety"/>
                              <context context="vehicle_status"/>
                              <context context="announcement"/>
                            </device>
                        </group>
                  </volumeGroups>
                </zoneConfig>
                <zoneConfig name="rear seat zone 2 config 1">
                  <volumeGroups>
                        <group>
                            <device address="bus210_audio_zone_2">
                              <context context="music"/>
                            </device>
                        </group>
                        <group>
                            <device address="bus211_audio_zone_2">
                              <context context="navigation"/>
                              <context context="voice_command"/>
                              <context context="call_ring"/>
                              <context context="call"/>
                              <context context="alarm"/>
                              <context context="notification"/>
                              <context context="system_sound"/>
                              <context context="emergency"/>
                              <context context="safety"/>
                              <context context="vehicle_status"/>
                              <context context="announcement"/>
                            </device>
                        </group>
                  </volumeGroups>
                </zoneConfig>
            </zoneConfigs>
      </zone>
    </zones>
</carAudioConfiguration>



[*] 节点: 用于配置各个不同的音区。此中只能有一个音区可以配置成主音区,通过节点的isPrimary属性配置。节点对应的是CarAudioZone类。
每个音区包括多个配置信息节点,节点对应的是CarAudioZoneConfig类。
每个音区配置信息可以配置多个音量组节点,节点对应的是CarVolumeGroup类。CarVolumeGroup有两个子类,CarAudioVolumeGroup类和CoreAudioVolumeGroup类,分别代表是两种设置音量的方法。通过config.xml文件中的节点举行配置,配置为false时(默认配置),使用CarAudioVolumeGroup类。配置为true时,使用CoreAudioVolumeGroup类。默认使用的CarAudioVolumeGroup类,在举行音量设置时,会通过AudioManager.setAudioPortGain()接口直接将音量增益值设置到AudioHAL层。而CoreAudioVolumeGroup类在举行音量设置时,会通过AudioManager.setVolumeIndexForAttributes()接口,走音频子系统原来的streamType关联音量设置那一套逻辑。也就是说,CarAudioVolumeGroup类是硬件音量调治、CoreAudioVolumeGroup类是软件音量调治。如果要使用CarAudioVolumeGroup类举行硬件音量调治,就必须在audio_policy_configuration.xml配置文件的节点中,通过子节点配置该装备的最小增益值、最大增益值、默认增益值和步进。
在每个音量组下面,可以配置多个输出装备节点,这些输出装备必须是在audio_policy_configuration.xml文件中配置过的,在车机系统中,所有输出装备的类型都是AUDIO_DEVICE_OUT_BUS,系统会根据它们的address来举行区分。节点对应的是CarAudioDeviceInfo类。
在每个节点下面,可以配置多个,节点对应的是CarAudioContextInfo类。CarAudioContextInfo会包含多个AudioAttributes,如许音频框架AudioPolicyManager在举行播放路由选择时,就可以根据AudioTrack指定的AudioAttributes,找到符合的Device。
在节点下,除了子节点,还有一个子节点,它用于配置当前这个音区的可用录音装备。这些装备也必须在audio_policy_configuration.xml文件中配置过。
[*] **节点:**用于配置AudioAttributes信息。节点的子节点中,可以配置多个节点和节点。节点表现的是AudioAttributes对象的usage属性。目前多音区的路由策略主要是通过usage属性来举行选择。AudioAttributes的别的属性如ContentType等可以不配置。
在AOSP的示例配置文件car_audio_configuration.xml中,默认没有节点的配置。因为目前CarAudioContext的配置信息,是通过硬编码的方式在CarAudioContext.java->getAllContextsInfo()函数中写死的。我们如果自己在car_audio_configuration.xml中配置了节点,记得将car_audio_configuration.xml的版本(节点的version属性)界说为大于等于3,如许CarAudioService就不会再使用默认的硬编码配置信息了。
[*] 节点:节点用于配置多个镜像播放装备,镜像播放装备的作用是让两个或多个不同音区的播放装备可以同时输出同一个AudioTrack的声音。镜像播放只支持USAGE_MEDIA类型的声音输出,也就是支持音乐、视频、游戏场景下的镜像播放。镜像播放不能将主音区关联到别的音区举行播放。每个镜像播放装备只能被关联使用一次,比如副驾驶音区和后排音区1通过1举行关联播放后,如果还想让后排音区2和后排音区3举行关联播放,就必须再重新界说一个2使用。
我们可以通过CarAudioManager.java->enableMirrorForAudioZones(List audioZoneIds)接口举行设置。
https://i-blog.csdnimg.cn/blog_migrate/0d223b8197e5116084efbcf08694447f.png
以上是car_audio_configuration.xml配置文件被解析后的类图。此中CarAudioZonesHelper.java是解析配置文件的工具类,内里也保存了所有解析后的配置信息。CarAudioDeviceInfo(节点)和CarAudioContextInfo(节点)的关联关系是1对多,它们通过CarVolumeGroup的成员变量mContextToAddress集合举行关联。
参考文档

Android CarService源码分析Android Automative是在原先Android的系统架构上增长了 - 掘金
Android R- CarAudioService之car_audio_configuration.xml解析_getinputdevicesforzoneid-CSDN博客
Android3 CarAudioService初始化流程分析-CSDN博客
Android13音频子系统分析(四)—座舱的多音区框架_carserviceimpl-CSDN博客

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: CarAudioService启动流程分析