当前位置: 首页 > news >正文

Android Audio分区——音频分区相关API(四)

        前面文章我们介绍了车载多区音频的相关基础内容以及相关配置文件,在 Android 车载系统中,多区音频支持允许车辆的不同区域(如前排、后排)同时播放不同的音频内容。这种功能在现代汽车中变得越来越普遍,尤其是在高端车型和家庭用车中,它可以提升乘客的乘坐体验。这里我们看进一步看一下音频分区的相关代码,想要快速了解音频分区相关功能,首先从其相关接口开始。

一、音频分区API

        对于车载系统音频分区的相关接口位于 CarAudioManager 中,这里我们就来看一下 CarAudioManager 中关于音频分区的相关设置。

1、CarAudioManager

源码位置:/packages/services/Car/car-lib/src/android/car/media/CarAudioManager.java

/*** 用于处理汽车音频的api** 在汽车环境中,我们引入了通过在config.xml中设置“audioUseDynamicRouting”属性来打开/关闭音频动态路由的支持** 启用音频动态路由时:* - 音频设备分组到区域* - 至少有一个主要区域,以及额外的次要区域,如RSE(娱乐座椅)* - 在每个区域内,音频设备被分组为音量控制的卷组* - 音频根据其AudioAttributes使用情况分配给音频设备** 禁用音频动态路由时:* - 只有一个音频区域,这是主要区域* - 每个卷组代表一个可控的STREAM_TYPE,与AudioManager相同*/
public final class CarAudioManager extends CarManagerBase {/*** Zone主音频区域id* @hide*/@SystemApipublic static final int PRIMARY_AUDIO_ZONE = 0x0;/*** 无效音频区域id。* @hide*/@SystemApipublic static final int INVALID_AUDIO_ZONE = 0xffffffff;……/*** 用于作为键值存储在Bundle中,以便在创建AudioFocusRequest时指定请求音频焦点的目标音频区域。* @hide*/public static final String AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID = "android.car.media.AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID";
}

        这里仅展示了 CarAudioManager 的相关备注及几个属性,对于属性已经备注比较好理解,这里先来看一下音频动态路由的属性开关设置。

        动态音频路由允许系统根据用户的设置或应用的需求动态调整音频输出的路径。这意味着可以根据不同的场景和需求,将音频流路由到不同的扬声器区域。

config.xml

源码位置:/packages/services/Car/service/res/values/config.xml

<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"><!--  配置以启用动态音频路由--><bool name="audioUseDynamicRouting">false</bool>……
</resources>

        在 Android 源码中,这里的默认值为 false,即固定音频路由。这时音频输出将遵循固定的路由规则,这意味着应用程序无法动态地改变音频输出的区域。例如,所有音频流可能默认路由到主音频区域,而不是根据应用程序的请求动态改变。CarAudioManager 可能不支持通过 API 动态设置音频输出区域。方法如 setZoneIdForUid 可能不可用或者不起作用。

2、Zone相关接口

        涉及到分区相关的音频设置,最主要的数据便是 zoneId,所以我们首先看一下该参数的获取接口。

获取zoneId

private final ICarAudio mService;/*** 获取当前可用的音频区域* @return 音频区id* @hide*/
@SystemApi
@RequiresPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS)
public @NonNull List<Integer> getAudioZoneIds() {try {int[] zoneIdArray = mService.getAudioZoneIds();List<Integer> zoneIdList = new ArrayList<Integer>(zoneIdArray.length);for (int zoneIdValue : zoneIdArray) {zoneIdList.add(zoneIdValue);}return zoneIdList;} catch (RemoteException e) {return handleRemoteExceptionFromCarService(e, Collections.emptyList());}
}

        这里主要调用 CarAudioService 中的对应函数 getAudioZoneIds() 来获取 zoneId。

关联用户

        关联用户是指用户 ID (uid) 与音频区域 (zone id) 的关联,在汽车音频管理系统,将应用程序的用户 ID 与特定的音频区域进行绑定。这种绑定有助于实现更精细的音频控制策略,例如根据不同的应用或用户来路由音频流到不同的扬声器或输出设备。

/*** 获取当前映射到uId的音频区域id,如果不存在映射,则默认为PRIMARY_AUDIO_ZONE** @param uid 要映射的uid* @return zone Id映射到uid*/
public int getZoneIdForUid(int uid) {try {return mService.getZoneIdForUid(uid);} catch (RemoteException e) {return handleRemoteExceptionFromCarService(e, 0);}
}/*** 将音频区id映射为uid*/
public boolean setZoneIdForUid(int zoneId, int uid) {try {return mService.setZoneIdForUid(zoneId, uid);} catch (RemoteException e) {return handleRemoteExceptionFromCarService(e, false);}
}/*** 清除uid的当前zone映射*/
public boolean clearZoneIdForUid(int uid) {try {return mService.clearZoneIdForUid(uid);} catch (RemoteException e) {return handleRemoteExceptionFromCarService(e, false);}
}

        这里提供了用户 ID (uid) 与音频区域 (zone id) 设置关联、获取关联信息以及解除关联的相关函数。

音量设置

public void setGroupVolume(int groupId, int index, int flags) {setGroupVolume(PRIMARY_AUDIO_ZONE, groupId, index, flags);
}public void setGroupVolume(int zoneId, int groupId, int index, int flags) {try {mService.setGroupVolume(zoneId, groupId, index, flags);} catch (RemoteException e) {handleRemoteExceptionFromCarService(e);}
}

        对于音量设置功能前面已经介绍过了,这里还是以音量设置为例介绍音频分区相关功能。可以看到 setGroupVolume() 函数有两个不同参数的的接口,区别就是对应分区的 ID。而我们前面常用的不带分区 ID 的接口,只是使用了前面定义的默认主分区 ID 常量。

其他接口

/*** 获取最大音量*/
public int getGroupMaxVolume(int zoneId, int groupId) {// 这里与获取音量的方式相同,都是调用CarAudioService中的对应方法……
}/*** 获取最小音量*/
public int getGroupMinVolume(int zoneId, int groupId) {……
}/*** 获取当前音量*/
public int getGroupVolume(int zoneId, int groupId) {……
}/*** 获取系统中可用音量分组计数*/
public int getVolumeGroupCount(int zoneId) {……
}/*** 获取给定AudioAttributes使用的音量分组id*/
public int getVolumeGroupIdForUsage(int zoneId, @AudioAttributes.AttributeUsage int usage) {……
}/*** 获取与特定音量组ID (groupId) 相关联的使用情况数组 (int[])*/
public @NonNull int[] getUsagesForVolumeGroupId(int zoneId, int groupId) {……
}/*** 获取与特定区域 (zoneId) 和音频使用情况 (usage) 相关联的输出设备信息*/
public AudioDeviceInfo getOutputDeviceForUsage(int zoneId, @AudioAttributes.AttributeUsage int usage) {try {String deviceAddress = mService.getOutputDeviceAddressForUsage(zoneId, usage);if (deviceAddress == null) {return null;}AudioDeviceInfo[] outputDevices = mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);for (AudioDeviceInfo info : outputDevices) {if (info.getAddress().equals(deviceAddress)) {return info;}}return null;} catch (RemoteException e) {return handleRemoteExceptionFromCarService(e, null);}
}/*** 获取音频区域的输入设备*/
public @NonNull List<AudioDeviceInfo> getInputDevicesForZoneId(int zoneId) {try {return convertInputDevicesToDeviceInfos(mService.getInputDevicesForZoneId(zoneId),AudioManager.GET_DEVICES_INPUTS);} catch (RemoteException e) {return handleRemoteExceptionFromCarService(e, new ArrayList<>());}
}/*** 接收汽车音量变化事件的回调接口*/
public abstract static class CarVolumeCallback {// 每当更改分组音量卷时,就会调用该函数。public void onGroupVolumeChanged(int zoneId, int groupId, int flags) {}// 每当主静音状态发生变化时,就调用该方法。public void onMasterMuteChanged(int zoneId, int flags) {}
}

        可以看到,这里提供了获取最大/最小/当前音量、获取音量分组数、获取GroupId、获取分组信息、获取输入/输出设备信息以及音量/静音变化相关回调接口。这些接口都涉及到了 zoneId,可以通过该参数去管理对应的音频分区。

        CarAudioManager 主要是用来控制音频流的音量、静音等。应用程序可以通过 CarAudioManager API来控制不同区域的音频输出。


http://www.mrgr.cn/news/18510.html

相关文章:

  • java基础知识-JVM知识详解
  • 下载xhsell连接Linux系统
  • 鸿蒙之华为登录页
  • 十七、网络编程
  • 0901作业+思维导图梳理
  • Windows记事本打开某些文件后假死如何处理
  • Halcon基于相关性的模板匹配
  • Linux如何关闭终端不中断任务
  • yolo-world开放词汇检测onnxruntime和tensorrt推理
  • DL/T645-2007_Part2(负荷记录数据标识编码表)
  • 传统CV算法——图像特征算法之角点检测算法
  • Nmap使用教程图文教程(超详细)零基础入门到精通,收藏这一篇就够了
  • GCViT实战:使用GCViT实现图像分类任务(一)
  • 深入理解Python OpenCV图像处理
  • 捷邻系统小程序的设计
  • 华为 HCIP-Datacom H12-821 题库 (4)
  • KingbaseES 在K8s中部署报错:invalid value for parameter “port“
  • 人生不将就:互联网时代的探索者
  • 关于CUDA版本查看的问题
  • 【机器学习】图像处理与深度学习利器:OpenCV实战攻略全面解析