一、GroupVolume介绍
汽车音频中新增了音量组的概念. 所谓音量组,就是将不同用途的声音进行归纳,按组对相关的音量进行控制,在进一步解释音量组的概念之前,先了解一下音频上下文(Audio Context)和音频属性(Audio Attribute)两个概念。Android中的每段声音都由相应的应用和声音生成的原因来识别, 然后Android设备会使用这些信息来确认如何呈现声音。音频属性与音频上下文的具体对应关系如表:
音频上下文 | 音频属性对象 |
---|---|
MUSIC | MEDIA |
VOICE_COMMAND | USAGE_ASSISTANT |
NAVIGATION | ASSISTANCE_NAVIGATION_GUIDEANCE |
CALL | VOICE_COMMUNICATION |
RINGTONE | NOTIFICATION_RINGTONE |
NOTIFICATION | NOTIFICATION |
ALARM | ALARM |
SYSTEM_SOUND | ASSISTANCE_SONIFICATION |
UNKNOWN | UNKNOWN |
也就是说, 应用在使用音频设备时, 需要指定相应的音频属性,而音频属性对应着相关的音频上下文. 音量组就是对音频上下文进行了分组,在同一组内的上下文,音量会同步变化,而如何对音量组进行分类,则由制造商自己定义,如果制造商没有定义,则使用AAOS的默认分组。
在同一组中的音频虽然属于不同的上下文,但是它们的音量变化是联动的. 当然,各制造商可以覆盖以上默认定义,对音频上下文进行不同的组合,或者增加分组的数量. 但是需要满足以下条件:
1. 一个音频上下文只能归属于一个组
2. 除去UNKNOWN, 共有8个有效的音量上下文类型,这8个类型都需要进行分组,不能缺省.
3. 上下文对应的底层的总线设备不应该出现在两个组中
4. 在同一组的音频上下文的单次调节的步长度应该一致.
在Android10之后,为了更好地支持多音区音频的特性,修改了汽车音频配置文件的格式.同时文件也不再以Android资源的形式进行配置,而是通过系统构建时复制到指定的路径下进行读取.
有了音量组,就要通过音量组对音量大小进行控制, 这点和手机不一样, 手机上面使用AudiaManager的setStreamVolume方法进行音量调节,但是在AAOS中该方法很可能是无效的(取决于制造商的配置).
AAOS上建议的是使用车上的硬件放大器完成对音量大小的调节,而非软件混音器. 系统音量的调节需要通过CarAudioManager中提供的接口进行控制. 其中相关的接口都是SystemAPI, 即系统级别的接口,所以普通第三方应用是无法使用的. 也就是说在实际驾驶过程中,第三方应用的音量调节主要依赖系统设置或者相关控制按键(如音量旋钮, 方向盘音量按键)实现.
CarAudioManager实例的获取方法和CarPropertyManager的获取类似,也是通过
Car car = Car.createCar(this);
CarAudioManager carAudioManager = (CarAudioManager)car.getCarManager(Car.AUDIO_SERVICE);
获取到CarAudioManager的实例之后,就可以使用它对音量进行调节了. 以增加某一Group的音量为例子:
int volume = carAudioManager.getGroupVolume(groupID);
carAudioManager.setGroupVolume(groupID, ++volume,
AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_PLAY_SOUND);
通过getGroupVolume可以获取当前组的音量值,在通过setGroupVolume设置新的值.
那么这里有个疑问?如何知道想要调节的音频属性所对应的groupID呢? 因为制造商是可以重新定义分组的,不推荐开发者使用"硬编码"的方式, 为了使应用有较好的通用性,应用态获取音频属性所属的分组. 这里分为两个步骤实现:
1. 通过getVolumeGroupIdForUsage获取该Usage对应的groupId
2. 在利用获取的groupId设置音量
int groupID = carAudioManager.getVolumeGroupIdForUsage(AudioAttributes.USAGE_MEDIA);
调节音量需要申请对应的权限,因此不要忘记在清单文件中增加声明:
<uses-permission android:name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME"/>
同样的,该权限只有系统特权应用可以使用.
可以通过overlay机制覆盖CarAudioService默认的音量组实现音量组的自定义. 当然制造商可以做的和需要完成的事情不仅于此. 本节内容就基于CarAudioService的相关实现,对制造商的音频实现和相关配置进行一些补充.
在AAOS中推荐使用硬件放大器来控制音量, 而在Android手机中,支持软件混音器调节音量,这也是Android框架中的默认配置. 因此,如果要改用硬件放大器调节音量, 首先需要覆盖config_useFixedVolume属性.
<bool name="config_useFixedVolume">false</bool>
config文件位置:
android/frameworks/base/core/res/res/values/config.xml
semidrive x9u使用了overlay,会使用如下文件:
android/device/semidrive/x9u/x9u_ref_a/overlay/frameworks/base/core/res/res/values/config.xml
android/device/semidrive/x9u/x9u_ref_b/overlay/frameworks/base/core/res/res/values/config.xml
默认值为false, 该情况下,应用就可以调用AudioManager.setStreamVolume方法调节不同音频属性的音量.
在车载设备上, 我们一般设置为true, 这样子AudioManager.setStreamVolume就不生效了.
二、GroupVolume相关类
CarAudioService 相关类
AudioPolicy&AudioFlinger相关类
AudioFlinger&AudioHal相关类
CarVolumeGroup
A class encapsulates a volume group in car.
CarVolumeGroup代码位于:
packages/services/Car/service/src/com/android/car/CarVolumeGroup.java
CarVolumeGroup的定义:
final class CarVolumeGroup {
static final class Builder {}
}
三、GroupVolume相关方法
1、CarAudioManager方法
-
void setGroupVolume(int groupId, int index, int flags) :设置组音量
-
void setGroupVolume(int zoneId, int groupId, int index, int flags):设置组音量
-
int getGroupMaxVolume(int groupId) :获取组最大音量
-
int getGroupMinVolume(int groupId) :获取组最小音量
-
int getGroupVolume(int groupId) :获取组音量
-
int getVolumeGroupCount():获取Volume组数量
-
int getVolumeGroupIdForUsage(@AudioAttributes.AttributeUsage int usage):获取Volume组ID
-
int[] getUsagesForVolumeGroupId(int groupId):获取声音组ID
-
boolean isVolumeGroupMuted(int zoneId, int groupId):Volume组是否静音
-
void setVolumeGroupMute(int zoneId, int groupId, boolean mute, int flags):设置Volume组静音
-
void registerVolumeCallback(in IBinder binder):注册Volume回调
-
void unregisterVolumeCallback(in IBinder binder):解除注册Volume回调
zoneId的定义路径packages/services/Car/car-lib/src/android/car/media/CarAudioManager.java,定义如下:
PRIMARY_AUDIO_ZONE
usage的定义路径frameworks/base/media/java/android/media/AudioAttributes.java,定义如下:
USAGE_MEDIA
USAGE_VOICE_COMMUNICATION
USAGE_ALARM
USAGE_NOTIFICATION
USAGE_NOTIFICATION_RINGTONE
USAGE_NOTIFICATION_COMMUNICATION_REQUEST
USAGE_NOTIFICATION_COMMUNICATION_INSTANT
USAGE_NOTIFICATION_COMMUNICATION_DELAYED
USAGE_NOTIFICATION_EVENT
USAGE_ASSISTANCE_ACCESSIBILITY
USAGE_ASSISTANCE_NAVIGATION_GUIDANCE
USAGE_ASSISTANCE_SONIFICATION
USAGE_GAME
USAGE_VIRTUAL_SOURCE
USAGE_ASSISTANT
USAGE_CALL_ASSISTANT
groupId的定义如下:
2、CarAudioService方法
-
void setGroupVolume(int zoneId, int groupId, int index, int flags):设置组音量
-
int getGroupMaxVolume(int zoneId, int groupId):获取组最大音量
-
int getGroupMinVolume(int zoneId, int groupId):获取组最小音量
-
int getGroupVolume(int zoneId, int groupId):获取组音量
-
int getVolumeGroupCount(int zoneId):获取Volume组数量
-
int getVolumeGroupIdForUsage(int zoneId, int usage):获取Volume组ID
-
int[] getUsagesForVolumeGroupId(int zoneId, int groupId):获取声音组ID
-
boolean isVolumeGroupMuted(int zoneId, int groupId) :Volume组是否静音
-
void setVolumeGroupMute(int zoneId, int groupId, boolean mute, int flags):设置Volume组静音
-
void registerVolumeCallback(in IBinder binder):注册Volume回调
-
void unregisterVolumeCallback(in IBinder binder):解除注册Volume回调
四、GroupVolume流程分析
1、setGroupVolume流程分析
Android13 CarAudioManager setGroupVolume流程分析-CSDN博客