音量管理

音量管理包含在 CarAudioService 中,后者使用固定音量,并期望音量由硬件放大器在 HAL 下方应用,而不是在软件中应用。CarAudioService 将输出设备组织成音量组,以便对与音量组关联的所有设备应用相同的增益。

固定音量

AAOS 实现使用硬件放大器来控制音量,而不是软件混音器。为避免副作用,请将 config_useFixedVolume 标志设置为 true(根据需要叠加)

<resources>
    <!-- Car uses hardware amplifier for volume. -->
    <bool name="config_useFixedVolume">true</bool>
</resources>

config_useFixedVolume 标志未设置(或设置为 false)时,应用可以调用 AudioManager.setStreamVolume() 以按软件混音器中的流类型更改音量。这可能并不总是理想的,因为它可能会对其他应用产生潜在影响,并且软件混音器中的音量衰减可能会导致硬件放大器接收到的信号中可用的有效位减少。

音量组

音量组管理音频区域内一组设备的音量。对于每个音量组,音量可以独立控制。生成的增益在关联的设备上配置,以便由车辆的放大器应用。音量设置会为用户持久保存,并在用户登录时加载。

定义音量组

CarAudioService 使用在 car_audio_configuration.xml 中定义的音量组

<audioZoneConfiguration version="4">
    </deviceConfigurations>
    <activationVolumeConfigs>
        <activationVolumeConfig name="activation_volume_on_boot_config">
            <activationVolumeConfigEntry minActivationVolumePercentage="10" maxActivationVolumePercentage="90"
            invocationType="onBoot" />
        </activationVolumeConfig>
        ...
    </activationVolumeConfigs>
    <zones>
        <zone name="primary zone" isPrimary="true">
          <zoneConfigs>
              <zoneConfig name="primary zone config 0" isDefault="true">
                <volumeGroups>
                    <group activationConfig="activation_volume_on_boot_config">
                        <device address="bus0_media_out">
                            <context context="music"/>
                        </device>
                    </group>
                    <group>
                        <device address="bus1_navigation_out">
                            <context context="navigation"/>
                        </device>
                        <device address="bus2_voice_command_out">
                            <context context="voice_command"/>
                        </device>
                    </group>
                    ...
                </volumeGroups>
              </zoneConfig>
              ...
            </zoneConfigs>
        </zone>
     </zones>
</audioZoneConfiguration>

每个音量组应包含一个或多个具有关联地址的输出设备。地址应与在 audio_policy_configuration.xml 中定义的输出设备相对应。

配置音量组增益

每个音量组都具有最小、最大和默认增益值以及步长,步长基于在 audio_policy_configuration.xml 中为与音量组关联的设备配置的值。

<devicePort tagName="bus0_media_out" role="sink" type="AUDIO_DEVICE_OUT_BUS" address="bus0_media_out">
  <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
  <gains>
    <gain name="" mode="AUDIO_GAIN_MODE_JOINT"
      minValueMB="-3200" maxValueMB="600" defaultValueMB="0" stepValueMB="100"/>
  </gains>
</devicePort>

在初始化期间,音量组会检查关联设备的增益值,并按如下方式配置组

  • 步长。 对于音量组控制的所有设备,必须相同。
  • 最小增益。 组中设备中最小的最小增益。
  • 最大增益。 组中设备中最大的最大增益。
  • 默认增益。 组中设备中最大的默认增益。

鉴于这些值的配置方式,可以设置音量组的增益,使其超出与音量组关联的设备支持的范围。在这种情况下,对于该设备,增益将设置为设备的最小或最大增益值,具体取决于音量组的值低于还是高于该范围。

音量组标识符

音量组在运行时按照 XML 文件中定义的顺序进行标识。ID 范围从音频区域内的 0N-1,其中 N 是该区域中音量组的数量。这样,音量组 ID 在区域之间不是唯一的。这些标识符用于与音量组关联的 CarAudioManager API。任何接收 groupId 而没有 zoneId 的 API 都默认为主音频区域。

多区域音量管理

每个音频区域都应有一个或多个音量组,并且每个音量组仅与一个音频区域关联。此关系在 car_audio_configuration.xml 中定义。要了解更多信息,请参阅上面定义音量组中的示例。

每个区域的当前音量级别都会为与该区域关联的用户持久保存。这些设置是特定于区域的,这意味着如果用户在与主区域关联的显示屏上登录,然后稍后登录到与辅助音频区域关联的区域,则为第一个区域加载和持久保存的音量级别与辅助区域的音量级别不同。

最小和最大激活音量

Android 15 引入了对音量组索引的控制,以提高车载音频系统的安全性和用户舒适度。这通过使用在车载音频配置中配置的最小和最大激活音量来实现(请参阅定义音量组)。您可以通过在 Car Service RRO 中将 audioUseMinMaxActivationVolume 设置为 true 来启用此功能。

您可以在 activationVolumeConfigs 中定义多个 activationVolumeConfig 条目,每个条目代表不同的最小和最大激活配置。每个 activationVolumeConfig

  • 必须在整个车载音频配置文件中包含唯一的 name,以便稍后可以在音量组 (group) 中引用它。
  • 必须仅包含一个 activationVolumeConfigEntry

每个 activationVolumeConfig 都包含以下属性

  • minActivationVolumePercentage(整数,0-100,可选,默认值:0):指定最小激活音量(以百分比表示)。
  • maxActivationVolumePercentage(整数,0-100,可选,默认值:100):指定最大激活音量(以百分比表示)。
  • invocationType(字符串,可选,默认值:onPlaybackChanged):定义应用最小和最大激活音量的条件

    • onBoot:仅应用于启动后音量组上的第一个新激活的播放。
    • onSourceChanged:仅应用于音量组上具有已更改的应用或 UID 源的新激活的播放。
    • onPlaybackChanged:应用于音量组上的每个新激活的播放。

CarAudioService 通过监控以下当前处于活动状态的音频子组件来管理最小和最大激活

  • 当前活动的播放音轨
  • 当前通话状态
  • 来自音频控制 HAL 的当前音频焦点请求,其中来自音频控制 HAL 的音频焦点请求表示在 Android 外部正在进行活动的音频播放

下图显示了最小和最大激活音量管理的高级概览

image

图 1. 最小和最大激活音量管理活动音频数据路径。

通过指定的 minActivationVolumePercentagemaxActivationVolumePercentage、最小和最大音量增益索引,您可以计算每个音量组的最小和最大激活音量增益索引。CarAudioService 监控每个新激活的播放,并在以下条件下应用最小和最大激活音量

  • 调用类型匹配:播放的激活类型(源自音频管理器、音频控制 HAL 或电话管理器)必须与音量组关联的 activationVolumeConfigEntry 中指定的 invocationType 相匹配。
  • 音量索引超出范围:音量组的当前音量增益索引必须超出定义的激活音量增益索引范围,具体而言,以下条件之一为真

    • 索引低于计算出的最小激活音量增益索引。

    • 索引高于计算出的最大激活音量增益索引。

如果激活匹配,则音量组的音量增益索引将调整为以下值之一

  • 如果低于最小激活音量增益索引,则为最小激活音量增益索引

  • 如果高于最大激活音量增益索引,则为最大激活音量增益索引

此外,事件类型为 EVENT_TYPE_VOLUME_GAIN_INDEX_CHANGED 的车载音量组事件将发送到所有已注册的音量组事件回调。

处理音量键事件

Android 定义了多个用于音量控制的键码,包括

  • KEYCODE_VOLUME_UP
  • KEYCODE_VOLUME_DOWN
  • KEYCODE_VOLUME_MUTE

默认情况下,Android 会将音量键事件路由到应用。汽车实现应强制 CarAudioService 处理这些键事件,然后根据需要调用 setGroupVolumesetMasterMute。要强制执行此行为,请将 config_handleVolumeKeysInWindowManager 标志设置为 true

<resources>
    <bool name="config_handleVolumeKeysInWindowManager">true</bool>
</resources>

音量键事件目前无法区分它们的目标区域,并且假定它们都与主音频区域关联。当收到音量键事件时,CarAudioService 通过获取活动播放器的音频上下文,然后调整包含与最高优先级音频上下文关联的输出设备的音量组来确定要调整哪个音量组。优先级基于在 CarVolume.AUDIO_CONTEXT_VOLUME_PRIORITY 中定义的固定顺序确定。

衰减和平衡

AudioControl HAL 的两个版本都包含用于设置车辆衰减和平衡的 API。CarAudioManager 的相应系统 API 将值传递给 AudioControl HAL。这些 API 需要 android.car.permission.CAR_CONTROL_AUDIO_VOLUME。AudioControl API 包括

  • setBalanceTowardRight(float value) 将扬声器音量向汽车的右侧 (+) 或左侧 (-) 移动。

    • 0.0 为居中
    • +1.0 为完全靠右
    • -1.0 为完全靠左
    • 超出 -1 到 1 范围的值是错误值
  • setFadeTowardFront(float value) 将扬声器音量向汽车的前部 (+) 或后部 (-) 移动。

    • 0.0 为居中
    • +1.0 为完全向前
    • -1.0 为完全向后
    • 超出 -1 到 1 范围的值是错误值

您决定应如何应用这些值以及如何向用户显示这些值。它们可以严格应用于媒体,也可以全面应用于所有 Android 声音。Android 11 还引入了对输出设备应用音频效果的支持。这样,就可以通过适当输出设备上的音频效果而不是通过这些 API 来替代管理衰减和平衡。

音频闪避

当车辆降低一个音频流的增益时,会发生音频闪避,以便可以更清楚地听到同时播放的另一个音频流。在 AAOS 中,音频闪避由 HAL 实现。Android 无法控制超出操作系统的声音。在 Android 11 中,HAL 可用于做出闪避决定的主要信息是两个输出设备是否都具有活动音频流。

何时闪避

虽然闪避的处理方式由各个 OEM 决定,但我们建议遵循以下准则。

  • 在 Android 中播放多个音频流通常发生在两个应用或服务同时保持音频焦点时。要了解 Android 何时可以授予并发焦点,请参阅限制类型中的交互矩阵。随着车载音频插件的引入,这也取决于您的 AudioFocus 管理。

  • Android 混合在一起的任何音频流都是在应用任何增益之前完成的。因此,当与另一个音频流同时播放时应闪避的任何音频流都应路由到单独的输出设备,以便 HAL 可以在混合它们之前应用闪避。

以下是建议闪避的潜在并发互动。

互动 操作
紧急 闪避或静音除 SAFETY 以外的所有内容
安全 闪避除 EMERGENCY 以外的所有内容
导航 闪避除 SAFETYEMERGENCY 以外的所有内容
通话 闪避除 SAFETYEMERGENCYNAVIGATION 以外的所有内容
语音 闪避 CALL_RING
车辆声音 您确定活动声音的重要性以及它是否闪避其他声音。
MUSICANNOUNCEMENT 被所有内容闪避。例外情况是以 SYSTEM_SOUND 播放的触摸互动音调。

闪避时的注意事项

某些应用和服务(例如导航或助手)可能会使用多个播放器来执行操作。当数据流停止流经输出设备时,请避免过度的取消闪避,以确保媒体在导航或助手应用的下一次播放开始之前不会恢复到全音量,然后再被闪避。

对于具有足够隔离的多个声场的车辆,您可以将音频路由到汽车的不同区域,而不是闪避。例如,可以将导航说明路由到驾驶员头枕扬声器,同时继续以正常音量在整个车厢内播放音乐。

安全关键声音

Android 11 引入了 HAL 音频焦点 API。HAL 确保安全关键声音优先于其他声音。如果 HAL 为 USAGE_EMERGENCY 保持音频焦点,则不能保证 Android 的应用和服务不会播放声音。HAL 确定应混合或静音哪些来自 Android 的音频流以播放安全关键声音。

配置音量设置 UI

AAOS 将音量设置 UI 与音量组配置分离。这些可以叠加,如配置音量组增益中所述。这种分离确保了如果音量组的配置发生更改,则无需进行任何更改。

在车载设置 UI 中,packages/apps/Car/Settings/res/xml/car_volume_items.xml 包含与每个定义的 AudioAttributes.USAGE 关联的 UI 元素(标题和图标资源)。此文件通过使用与每个 VolumeGroup 中包含的第一个已识别用法关联的资源,为定义的 VolumeGroups 提供了合理的呈现。

例如,以下示例将 VolumeGroup 定义为包括 voice_communicationvoice_communication_signalling。车载设置 UI 的默认实现使用与 voice_communication 关联的资源来呈现 VolumeGroup,因为这是文件中的第一个匹配项。

<carVolumeItems xmlns:car="http://schemas.android.com/apk/res-auto">
    <item car:usage="voice_communication"
          car:title="@*android:string/volume_call"
          car:icon="@*android:drawable/ic_audio_ring_notif"/>
    <item car:usage="voice_communication_signalling"
          car:title="@*android:string/volume_call"
          car:icon="@*android:drawable/ic_audio_ring_notif"/>
    <item car:usage="media"
          car:title="@*android:string/volume_music"
          car:icon="@*android:drawable/ic_audio_media"/>
    <item car:usage="game"
          car:title="@*android:string/volume_music"
          car:icon="@*android:drawable/ic_audio_media"/>
    <item car:usage="alarm"
          car:title="@*android:string/volume_alarm"
          car:icon="@*android:drawable/ic_audio_alarm"/>
    <item car:usage="assistance_navigation_guidance"
          car:title="@string/navi_volume_title"
          car:icon="@drawable/ic_audio_navi"/>
    <item car:usage="notification_ringtone"
          car:title="@*android:string/volume_ringtone"
          car:icon="@*android:drawable/ic_audio_ring_notif"/>
    <item car:usage="assistant"
          car:title="@*android:string/volume_unknown"
          car:icon="@*android:drawable/ic_audio_vol"/>
    <item car:usage="notification"
          car:title="@*android:string/volume_notification"
          car:icon="@*android:drawable/ic_audio_ring_notif"/>
    <item car:usage="notification_communication_request"
          car:title="@*android:string/volume_notification"
          car:icon="@*android:drawable/ic_audio_ring_notif"/>
    <item car:usage="notification_communication_instant"
          car:title="@*android:string/volume_notification"
          car:icon="@*android:drawable/ic_audio_ring_notif"/>
    <item car:usage="notification_communication_delayed"
          car:title="@*android:string/volume_notification"
          car:icon="@*android:drawable/ic_audio_ring_notif"/>
    <item car:usage="notification_event"
          car:title="@*android:string/volume_notification"
          car:icon="@*android:drawable/ic_audio_ring_notif"/>
    <item car:usage="assistance_accessibility"
          car:title="@*android:string/volume_notification"
          car:icon="@*android:drawable/ic_audio_ring_notif"/>
    <item car:usage="assistance_sonification"
          car:title="@*android:string/volume_unknown"
          car:icon="@*android:drawable/ic_audio_vol"/>
    <item car:usage="unknown"
          car:title="@*android:string/volume_unknown"
          car:icon="@*android:drawable/ic_audio_vol"/>
</carVolumeItems>

上述配置中使用的属性和值在 packages/apps/Car/Settings/res/values/attrs.xml 中声明。音量设置 UI 使用以下基于 VolumeGroup 的 CarAudioManager API

  • getVolumeGroupCount() 以了解应绘制多少个控件。
  • getGroupMinVolume()getGroupMaxVolume() 以获取下限和上限。
  • getGroupVolume() 以获取当前音量。
  • registerVolumeChangeObserver() 以在音量更改时收到通知。

车载音量组事件

音量更新和静音切换的汽车用例具有上下文基础,这些基础可能会定义某些应用(例如音量设置)的操作。来自车载音频堆栈的当前音量和静音回调提供有限的上下文信息。为了更好地服务于汽车用例和未来的可扩展性,Android 14 中添加了 CarVolumeGroupEvent。每个事件都携带三种关键类型的信息

  • CarVolumeGroupInfo 列表
  • EventTypes(位图)
  • ExtraInfos 列表

CarVolumeGroupInfo

事件回调的接收器可以随时访问受影响的车载音量组信息列表。这意味着应用无需对 Car 音频框架进行任何额外调用即可获取最新状态。它可以简单地使用收到的 CarVolumeGroupInfos 来更新 UI 或内部状态。为了使应用更轻松,车载音量组中更改的方面也作为 EventTypes 的一部分提供,如下所述。

EventTypes

定义 CarVolumeGroupInfo 的哪个方面已更改。应用可以使用此来识别更改并采取所需的操作。例如,EVENT_TYPE_VOLUME_MAX_INDEX_CHANGED 指示相应的 CarVolumeGroups 最大音量增益索引已更改,并且可以通过 CarVolumeGroupInfo.getMaxVolumeGainIndex() 进行查询。

下表显示了 EventTypeCarVolumeGroupInfo 之间的关系。

EventType CarVolumeGroupInfo
EVENT_TYPE_VOLUME_GAIN_INDEX_CHANGED CarVolumeGroupInfo.getVolumeGainIndex()
EVENT_TYPE_VOLUME_MIN_INDEX_CHANGED CarVolumeGroupInfo.getMinVolumeGainIndex()
EVENT_TYPE_VOLUME_MAX_INDEX_CHANGED CarVolumeGroupInfo.getMaxVolumeGainIndex()
EVENT_TYPE_MUTE_CHANGED CarVolumeGroupInfo.isMuted()
EVENT_TYPE_VOLUME_BLOCKED_CHANGED CarVolumeGroupInfo.isBlocked()
EVENT_TYPE_ATTENUATION_CHANGED CarVolumeGroupInfo.isAttenuated()
EVENT_TYPE_ZONE_CONFIGURATION_CHANGED CarVolumeGroupInfo.getAudioAttributes()

ExtraInfos

提供有关 CarVolumeGroup 为何更改的其他信息。应用可以使用此信息来提供其他上下文,以提醒用户采取操作或进行通知。例如,EXTRA_INFO_TRANSIENT_ATTENUATION_THERMAL 指示由于热过载而导致的活动瞬态衰减。如果用户尝试增大音量,应用可以告知用户。

我们不对 ExtraInfos 强制执行任何流程。您可以自行决定基于 ExtraInfos 确定流程。例如,如果由于 EXTRA_INFO_TRANSIENT_ATTENUATION_DUCKED 而导致衰减处于活动状态,您也可以选择最初淡化音量条 UI,以防止用户更改音量。其他人可以选择显示 toast 消息,指示闪避处于活动状态,并允许用户更改音量。

车载音频框架依赖于 AudioControl HAL IAudioGainCallback 来提供建议的 ExtraInfos。要了解更多信息,请参阅音频增益回调

CarVolumeGroupEvent 可扩展以满足车载音频框架的未来需求。我们计划通过 CarVolumeGroupEvent 来支持新功能。我们强烈建议应用开发者使用 CarVolumeGroupEvent 来处理组音量和静音更改。

车载音量组事件回调

Android 14,为特权和平台应用提供了新的回调,用于注册并接收 CarVolumeGroupEvents 的通知。

  • 要注册回调,请使用 CarAudioManager#registerCarVolumeGroupEventCallback()

  • 要取消注册回调,请使用 CarAudioManager#unregisterCarVolumeGroupEventCallback()

如果应用注册了新的 CarVolumeGroupEventCallback 和旧版 CarVolumeCallback,则事件 CarVolumeGroupEventCallbacks 将被优先处理。车载音频堆栈不再触发 CarVolumeCallback。这可以防止对同一事件向同一应用重复触发。

我们强烈建议您使用 CarVolumeGroupEventCallback 来管理组音量和静音更改。

音频增益回调

自 Android 13 起,AudioControl HAL 可以触发异步回调,以管理由于车载音频系统更改而导致的音量级别更新。

HAL API

AudioControl @2.0 AIDL

AudioControl AIDL HAL 的 2.0 版本添加了以下 API

API 目的
IAudioControl#registerGainCallback 使用 AudioControl HAL 注册 IAudioGainCallback 的实例。
IAudioGainCallback#onAudioDeviceGainsChanged 异步回调,用于通知音频增益配置的更改。

AudioControl HAL 回调包括原因列表和相应的 AudioGainConfigInfo,后者包括

  • 区域 ID
  • 设备端口地址
  • 音量索引 > 索引可以是受限索引或更新索引。

原因可以大致分为

  • 限制原因。 对音量和静音行为的瞬态更改。
  • 更新原因。 对音量行为的永久更改。

限制类型

截至 AudioControl HAL AIDL V3,以下是支持的限制类型

  • 静音
  • 阻止
  • 限制
  • 衰减
活动限制 用户触发的音量更改 用户触发的静音切换
静音 ❌ (取消静音)

✔ (静音)
阻止
限制 ❌ (超出限制)

✔ (低于限制)
衰减

限制之间的优先级为:静音 > 阻止 > 限制 > 衰减。

静音限制

静音限制包括

  • Reasons.TCU_MUTE
  • Reasons.REMOTE_MUTE

车载音频框架内部维护着这两种静音状态

  • 用户静音。 根据用户的请求进行切换,可以通过 CarAudioManager 或按键事件。

  • HAL 静音。 根据通过 AudioGain 回调接收到的静音限制进行切换。

对于像“设置”应用这样的监听器,音量组的总体静音状态 (CarVolumeGroupInfo.isMuted()) 将基于上述两种静音状态中的任何一种是否启用。

当 HAL 静音启用时,所有传入的音量更改和组取消静音请求将在限制持续期间被忽略。

交互案例:HAL 静音处于活动状态,用户请求切换静音

当 HAL 静音启用且用户静音禁用时

  • 音量组总体静音状态更改为 true
  • 来自用户的启用静音请求将被处理。
    • 原因:用户静音请求应始终被遵守,以保护用户隐私。

当 HAL 静音启用且用户静音启用时

  • 音量组总体静音状态更改为 true

  • 来自用户的禁用静音请求将 NOT 被处理。缓存的用户静音状态保持启用。

    • 原因:仅当没有活动的限制时,才会遵守用户取消静音请求。

    • 原因:取消静音缓存的用户静音可能会导致意外的声音爆裂并危及用户安全。如果静音状态跨点火周期启用,这尤其如此,这会降低用户对声音水平感知的意识。

交互案例:HAL 静音启用和禁用,而用户静音没有变化

切换 HAL 静音将更改音量组的总体静音状态。但是,它不会直接更新用户静音状态。当用户静音禁用且收到启用 HAL 静音的回调时

  • 音量组总体静音状态更改为 true
  • 来自用户的更改音量请求在 HAL 静音启用时将 NOT 被处理。

    • 原因:用户在静音启用时无法感知声音。允许音量更改可能会导致声音爆裂并危及用户安全。

    • 原因:音量应用可以注册回调并自动触发取消静音 (CarAudioManager.setVolumeGroupMute(...,/* mute=*/ true,..)),如果这是 OEM 期望的行为。

当 HAL 静音禁用且用户静音禁用时

  • 音量组静音状态更改为 false

    原因:使静音状态保持粘性并请求用户取消静音可能会在静音状态频繁切换时不必要地打断用户。

  • 来自用户的更改音量请求将被正常处理。

阻止

阻止限制包括

  • Reasons.FORCED_MASTER_MUTE
  • Reasons.REMOTE_MUTE
  • Reasons.TCU_MUTE.

当阻止限制处于活动状态时,来自用户的

  • 更改音量请求将 不会 被处理。
  • 切换静音请求将被处理。

限制

限制限制包括

  • Reasons.THERMAL_LIMITATION
  • Reasons.SUSPEND_EXIT_VOL_LIMITATION

当限制限制处于活动状态时,来自用户的

  • 更改音量

    • 在限制范围内将被处理
    • 超出限制范围将 不会 被处理
  • 切换静音请求将被处理。

衰减

衰减限制包括

  • Reasons.ADAS_DUCKING
  • Reasons.NAV_DUCKING
  • Reasons.PROJECTION_DUCKING

当衰减限制处于活动状态时,来自用户的

  • 更改音量请求将被处理。新的当前音量级别将设置为衰减后的音量(而不是之前的音量)。未来的音量更改将从此级别开始。

  • 切换静音请求将被处理。

更新到索引

以下情况被视为异步音量索引更新:Reasons.EXTERNAL_AMP_VOL_FEEDBACK

由于此原因,AudioControl HAL 可以将音量组当前索引更新为指定的索引。这主要用作音频系统对来自车载音频框架的音量更改请求的反馈。索引更新也会作为 CarVolumeGroupEvent 回调与应用通信,以同步索引。

示例

用例:用户将音量索引更新为 30

  • 用户使用音量应用将音量索引更改为 30。

  • 此索引将转换为音量增益并发送到 Audio HAL。

  • 供应商的 Audio HAL 实现接收新的音量增益并更新音频系统(如外部放大器)。

  • 音频系统响应称,音量级别仅更新到索引 15(原因 Android 未知)。

  • 供应商的 AudioControl HAL 实现触发

    IAudioGainCallback.onAudioDeviceGainsChanged(EXTERNAL_AMP_VOL_FEEDBACK, {...,  15 /* New index */})
    
  • 车载音频服务使用来自回调的新索引,该索引用于持久性和回调到音量应用。用户请求的索引为 30。但是,音频系统异步反馈将索引更新为 15。

用例:退出挂起后首次音频播放

  • 挂起之前的音量索引设置为高水平 95(范围:[0-99])。

  • Android 进入挂起状态。

  • 一旦 Android 退出挂起状态(例如,恢复)

    • 供应商 Audio HAL/AudioControl HAL 在本地向音频系统应用安全索引 30。

    • 供应商 AudioControl HAL 还会触发安全索引的回调

    IAudioGainCallback.onAudioDeviceGainsChanged(SUSPEND_EXIT_VOL_LIMITATION, {...,  30 /* safe index */})
    
  • 车载音频服务使用来自回调的新索引,该索引用于持久性及其自身到音量应用的回调,从而同步索引。挂起之前的音量索引为 95。但是,恢复后,AudioControl HAL 实现者会将此索引设置为安全音量级别 30。

动态音量配置

对于此功能,我们考虑以下主要用例

  1. 车辆生产线下线 (EOL) 配置。

    • 汽车制造商更喜欢在 EOL 时根据车辆音频系统设置更新音量配置。通常,这是一个侧载,无需更新 Android SW 映像。

    • 汽车制造商可能需要在维修计划期间更新音量配置。

  2. 运行时配置。 汽车音频系统支持外部放大器配置,这些 ECU 可以托管在启动时查询的音量范围配置。

  3. 按需配置。 提供此功能是为了支持对基于需求的音频功能日益增长的需求,用户可以订阅一段时间的增强信号处理。新的音量范围配置在订阅期间有效。

设计

动态音量配置分三个阶段实现

  • 发现。 供应商 AudioControl HAL 实现通过供应商拥有的自定义 IPC 机制发现新的音量范围更新。

    一旦发现,将通过 AudioControl::IModuleChangeCallback 生成回调。

  • 更新。 车载音频堆栈使用新的音量范围更新音量组状态。

    努力在音量范围更新后保持相同的音量级别。但是,如果索引超出范围,则当前音量索引将设置为安全值。例如,供应商在回调期间提供的默认级别。

  • 回调。

    • 在音量组范围更新后,车载音频堆栈会触发回调到通过 CarVolumeGroupEventCallback 注册的应用。

    • CarVolumeGroupEvent 携带更新后的 CarVolumeGroupInfo、事件类型(更改的内容)和额外信息(更改的原因)。

image

图 2. 动态音量配置。

HAL API

AudioControl @ 3.0 AIDL

AudioControl AIDL HAL 的 3.0 版本引入了以下 API

API
IAudioControl#setModuleChangeCallback 使用 AudioControl HAL 设置 IModuleChangeCallback 的实例。
IAudioControl#clearModuleChangeCallback 清除先前使用 AudioControl HAL 设置的 IModuleChangeCallback 实例。
IModuleChangeCallback#onAudioPortsChanged 通知 AudioPorts 更改的回调

序列

动态音量配置的序列图如下所示。

image

图 3. 动态音量配置的序列图。

关键方面

为了优化此功能,请考虑以下事项。

  • 作为回调一部分提供的 AudioPorts 必须 与汽车 BUS 定义匹配

    • 设备端口。 IN_DEVICE, OUT_DEVICE
    • 连接。 BUS
    • 地址。 在 Audio HAL 定义中定义
    • 增益模式。 JOINT
  • 供应商 必须 在 Audio HAL 策略中定义音量范围定义的超集,并使用回调为车辆变体自定义它。有关更多信息,请参阅 IModuleChangeCallbac AIDL 定义。

  • 当多个音频 BUS 属于同一音量组时,每个 BUS 必须 具有相同的音量范围定义。否则会导致车载音频框架拒绝新的音量范围定义。