Android汽车服务篇(四) CarAudioService

这篇具有很好参考价值的文章主要介绍了Android汽车服务篇(四) CarAudioService。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一.简介

        本文将基于CarService中另一个重要的服务CarAudioService以及其对应的CarAudioManager介绍汽车音频的相关内容.

        在车载上,音频设备的数量还是使用场景都和手机有很大的不同,紧靠Android原有的音频服务是无法满足在车内的使用需求的.

        因此AAOS对Android原有的音频机制进行了扩充. 在CarService中加入了CarAudioService.对音频设备进行更加细致的管理,以满足车上的使用场景.

二. 音量控制        

2.1  音量组

        汽车音频中新增了音量组的概念. 所谓音量组,就是将不同用途的声音进行归纳,按组对相关的音量进行控制.

        在进一步解释音量组的概念之前,先了解一下音频上下文(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的默认分组(Android10中首选以car_audio_configuration.xml文件读取音频配置).

2.2 音量组的定义与加载

        音量组通过car_volume_groups.xml文件进行定义,默认的配置文件的源码路径为:

packages/services/Car/service/res/xml/car_volume_groups.xml   

<volumeGroups xmlns:car="http://schemas.android.com/apk/res-auto"
        car:isDeprecated="true">
    <group>
        <context car:context="music"/>
        <context car:context="call_ring"/>
        <context car:context="notification"/>
        <context car:context="system_sound"/>
    </group>
    <group>
        <context car:context="navigation"/>
        <context car:context="voice_command"/>
    </group>
    <group>
        <context car:context="call"/>
    </group>
    <group>
        <context car:context="alarm"/>
    </group>
</volumeGroups>

从XML文件中的内容可以发现CarAudioService默认的音量组分为4组

其中 music, call_ring, notification,system_sound为一组;  navigation, voice_command组成另一组; 而call 和 alarm单独为一组.

在同一组中的音频虽然属于不同的上下文,但是它们的音量变化是联动的.  当然,各制造商可以覆盖以上默认定义,对音频上下文进行不同的组合,或者增加分组的数量.  但是需要满足以下条件:

1.  一个音频上下文只能归属于一个组

2. 除去UNKNOWN, 共有8个有效的音量上下文类型,这8个类型都需要进行分组,不能缺省.

3.  上下文对应的底层的总线设备不应该出现在两个组中

4. 在同一组的音频上下文的单次调节的步长度应该一致.

在Android10之后,为了更好地支持多音区音频的特性,修改了汽车音频配置文件的格式.同时文件也不再以Android资源的形式进行配置,而是通过系统构建时复制到指定的路径下进行读取.

PRODUCT_COPY_FILES += \
    vendor/custom/car_audio_configuration.xml: $(TARGET_COPY_OUT_VENDRO)/etc/car_audio_configuration.xml

2.3 音量控制接口

有了音量组,就要通过音量组对音量大小进行控制, 这点和手机不一样, 手机上面使用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"/>

同样的,该权限只有系统特权应用可以使用.

2.4 制造商实现与相关配置

        前文提到可以通过overlay机制覆盖CarAudioService默认的音量组实现音量组的自定义. 当然制造商可以做的和需要完成的事情不仅于此. 本节内容就基于CarAudioService的相关实现,对制造商的音频实现和相关配置进行一些补充.

        在AAOS中推荐使用硬件放大器来控制音量, 而在Android手机中,支持软件混音器调节音量,这也是Android框架中的默认配置. 因此,如果要改用硬件放大器调节音量, 首先需要覆盖config_useFixedVolume属性.

<bool name="config_useFixedVolume">false</bool>

/frameworks/base/core/res/res/values/config.xml 默认值为false, 该情况下,应用就可以调用AudioManager.setStreamVolume方法调节不同音频属性的音量. 

在车载设备上, 我们一般设置为true, 这样子AudioManager.setStreamVolume就不生效了.

继续看一下 CarAudioService的源码(Android10)

  public void init() {
        synchronized (mImplLock) {
            //注释1
            if (mUseDynamicRouting) {
                // Enumerate all output bus device ports
                AudioDeviceInfo[] deviceInfos = mAudioManager.getDevices(
                        AudioManager.GET_DEVICES_OUTPUTS);
                if (deviceInfos.length == 0) {
                    Log.e(CarLog.TAG_AUDIO, "No output device available, ignore");
                    return;
                }
                SparseArray<CarAudioDeviceInfo> busToCarAudioDeviceInfo = new SparseArray<>();
                for (AudioDeviceInfo info : deviceInfos) {
                    Log.v(CarLog.TAG_AUDIO, String.format("output id=%d address=%s type=%s",
                            info.getId(), info.getAddress(), info.getType()));
                    if (info.getType() == AudioDeviceInfo.TYPE_BUS) {
                        final CarAudioDeviceInfo carInfo = new CarAudioDeviceInfo(info);
                        // See also the audio_policy_configuration.xml,
                        // the bus number should be no less than zero.
                        if (carInfo.getBusNumber() >= 0) {
                            busToCarAudioDeviceInfo.put(carInfo.getBusNumber(), carInfo);
                            Log.i(CarLog.TAG_AUDIO, "Valid bus found " + carInfo);
                        }
                    }
                }
                setupDynamicRouting(busToCarAudioDeviceInfo);
            } else {
                Log.i(CarLog.TAG_AUDIO, "Audio dynamic routing not enabled, run in legacy mode");
                setupLegacyVolumeChangedListener();
            }

            // Restore master mute state if applicable
            if (mPersistMasterMuteState) {
                boolean storedMasterMute = Settings.Global.getInt(mContext.getContentResolver(),
                        VOLUME_SETTINGS_KEY_MASTER_MUTE, 0) != 0;
                setMasterMute(storedMasterMute, 0);
            }
        }
    }

注释1处的 mUseDynamicRouting 这个boolean值非常重要,   实际上无论是硬件放大器调节音量还是音量组的划分, 都有一个先决条件, 那就是mUseDynamicRouting的值为true. 该值是在

/frameworks/base/core/res/res/values/config.xml中配置

因为它的默认值为false,所以需要制造商覆盖设置为true. 这一点非常重要,否则汽车音频相关特性都不会被使能.

三. 音频焦点

        在汽车音频中,音频焦点(Audio Focus)的处理和手机有所不同, 在具体介绍 AAOS中汽车音频焦点的实现之前, 需要了解一下Android的音频焦点机制

        Android 引入音频焦点机制的主要目的是协调多个应用同时播放音频时产生的声音竞争的问题, 从而避免系统中有多个应用同时发声, 而导致声音混杂,影响用户体验.

        每个应用在播放音频时需要申请音频焦点,当获得音频焦点成功或音频焦点被抢占后,应用应当根据相关的规则,暂停/继续播放音频.

          因此在音频焦点的基础上,为了保证车类音频体验,制造商可以通过在HAL层对不同的音频上下文采用强制性的策略.

        在AAOS中, 通过CarAudioFocus,汽车音频定义了属于自己的音频焦点规则.   见下表

       竖列代表获得焦点并正在播放中的音频上下文

       横行代表申请焦点的音频上下文.

       0: 代表焦点获取被拒绝

       1: 代表焦点申请成功, 且原持有者失去焦点

       2: 代表申请焦点成功,且原焦点保持

Context Music Nav Voice Ring Call Alarm Notification System
Music 1 2 1 1 1 1 2 2
Nav 2 2 1 2 1 2 2 2
Voice 2 0 2 1 1 0 0 0
Ring 0 2 2 2 2 0 0 2
Call 0 2 0 2 2 2 2 0
Alarm 2 2 1 1 1 2 2 2
Notification 2 2 1 1 1 2 2 2
System 2 2 1 1 1 2 2 2

举个例子: 

如果一个应用正在使用导航(Nav)上下文播放音频, 并获取了音频焦点,这时有一个应用以音乐(Music)上下文申请焦点, 那么申请结果为2  表示的意思: 焦点申请成功, 且导航应用保持焦点.

也就是说: 虽然音乐音频申请焦点成功了,导航音频却不会收到音频焦点丢失的通知  

这与手机不同, 手机系统中同时只有一个应用维持音频焦点, 有其他用应用获取了焦点,那么意味着之前的应用失去了焦点.

但是CarAudioFocus中却不是这样, 使用导航上下文和音乐上下文的应用可以同时维持着音频焦点. 这样的设计更符合在汽车上的使用场景, 因为汽车上往往不同音频对应不同的扬声器设备, 汽车本身已经有很好的车内音响环境, 有的时候不同的声音可以同时播放并提供给用户出色的体验感.       文章来源地址https://www.toymoban.com/news/detail-494826.html

到了这里,关于Android汽车服务篇(四) CarAudioService的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于SpringBoot+微信小程序汽车服务系统的设计与实现

    早晨四点起来,开发个基于SpringBoot+微信小程序汽车服务系统。 困死我了。 送完孩子,然后去上班。 昨天有个读者朋友问小孟:程序员之间的差距为何如此之大。 有时候甚至在同一所大学,同一个专业,有的学生大四毕业可以拿到四五十w的年薪,有的学生毕业找不到工作。

    2024年02月03日
    浏览(55)
  • 汽车贴膜店展示服务预约小程序的作用是什么

    很多家庭都有车辆,除了车身自带颜色或外观,部分消费者会选择贴车衣、改色膜以及其它装饰类服务;而市场高需求下也促进了商家生意增长。 但随着线上化程度加深,传统线下门店也面临多重困境,品牌需要线上发展获得生意及内容宣传等。 那么通过【 雨科 】平台制作

    2024年02月06日
    浏览(49)
  • python上海汽车服务商家数据可视化系统设计与实现(django框架)

     博主介绍 :黄菊华老师《Vue.js入门与商城开发实战》《微信小程序商城开发》图书作者,CSDN博客专家,在线教育专家,CSDN钻石讲师;专注大学生毕业设计教育和辅导。 所有项目都配有从入门到精通的基础知识视频课程,免费 项目配有对应开发文档、开题报告、任务书、

    2024年02月03日
    浏览(44)
  • 基于“互联网+ 服务供应链”的汽车道路救援系统对策分析

    1。 建立“互联网+服务供应链”背景下汽车道路救援系统 基于互联网的汽车道路救援,两级服务供应链结构是由服务提供商、服务 集成商和客户组成。“互联网+服务供应链”背景下汽车道路救援系统组成, 它是一种 B2B2C 的形式,与前述传统汽车道路救援 B2B2C 模式有所不同

    2024年02月10日
    浏览(42)
  • 某汽车金融企业:搭建SDLC安全体系,打造智慧金融服务样本

    某汽车金融企业是国内头部汽车金融公司,已经为超过数百万名客户提供专业的汽车金融服务。该公司通过近几年的数字化创新,在提升客户体验、提高管理效率、降低经营成本等方面已具备很强的服务能力,让客户获得更方便、更快捷、更灵活的金融服务。 发力线上汽车金

    2024年02月05日
    浏览(45)
  • VR汽车技术服务虚拟仿真实训平台更好地辅助职业上岗培训

    VR汽车虚拟仿真教学软件是一种基于虚拟现实技术的教学辅助工具。它能够模拟真实的汽车环境和操作场景,让学生能够通过虚拟仿真来学习和实践汽车相关知识和技能。 与传统的教学方式相比,VR汽车虚拟仿真教学软件具有更高的视觉沉浸感和互动性,能够更好地激发学生

    2024年02月04日
    浏览(47)
  • 通俗易懂实现功能强大的实战项目 springboot+java+vue+mysql 汽车服务管理系统

    ✍✍计算机编程指导师 ⭐⭐个人介绍:自己非常喜欢研究技术问题!专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目:有源码或者技术上的问题欢迎在评论区一起讨论交流! ⚡⚡ Java实战 | SpringBoot/SSM Python实战项目 | Django 微信小

    2024年01月16日
    浏览(40)
  • 东莞UG逆向建模设计汽车内外饰出stp图抄数3d造型建模代画图服务

    汽车内外饰三维扫描及逆向建模是一项复杂且技术性强的工程。它涉及到使用高精度的三维扫描仪对汽车内外饰进行全面、细致的扫描,获取其精确的三维数据。这个过程中,需要确保扫描的环境、光线、角度等因素对扫描结果的影响最小化,以保证获取的三维数据准确无误

    2024年01月24日
    浏览(50)
  • 如何在本地服务器部署TeslaMate并远程查看特斯拉汽车数据无需公网ip

    TeslaMate是一个开源软件,可以通过连接特斯拉账号,记录行驶历史,统计能耗、里程、充电次数等数据。用户可以通过web界面查看车辆状态、行程报告、充电记录等信息,并生成漂亮的图表和统计报告。 另外,TeslaMate也可以记录车子所有的位置、轨迹、速度、温度、海拔、续

    2024年02月21日
    浏览(47)
  • 开源 | 慧哥充电桩平台V2.5.2(支持 汽车 电动自行车 云快充1.5、云快充1.6 微服务 )

    pc管理后台 39.98.222.58:9251 admin/123456 **开源充电桩云平台(v2.5.2)支持 前端uniapp(H5、小程序)、采集端、运营端、代理商端、充电桩硬件(电动自行车、电动汽车)全业务场景,平台目前服务企业1000+,采用SpringBoot、SpringCloud、MySQL、Netty、MQTT、支付宝支付、微信支付、微信退

    2024年04月09日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包