AAOS系列之音量设置

news2024/12/22 16:23:19

文章目录

      • 前言
      • UI 处理流程
      • 音量键的响应流程
      • AudioService设置音量流程
      • AAOS音量条选项
      • 总结

前言

AAOS音量设置内容可以分为几个部分

  • 音量的ui响应流程
  • legacy模式
  • dynamic模式
  • 通过按键进行设置

AAOS 音量设置比通用的Android系统复杂,表现在两个方面。首先是UI响应上面的区别,AAOS 虽然有复用部分AOSP的UI逻辑,但有关音量设置的界面和音量变化的回调响应都是独立实现。这一部分还不是很完善,部分的功能实现不全。 其次 AAOS动态路由模式下的音量设置,这一模式下的音量设置跟正常的流程完全不一样,极大的依赖于hal层的实现。

本文的目标

  1. 理解CarService中UI的响应流程
  2. 理解AudioService中音量设置流程
  3. CarAudioService 中legacy和dynamic音量的处理
  4. 按键调整音量的流程
  5. 相关问题的处理

UI 处理流程

  • system volume ui的处理流程

要理解car volume ui的处理首先要理解system volume ui的处理。

system volume ui代码位置:

frameworks\base\packages\SystemUI\src\com\android\systemui\volume\VolumeDialogImpl.java
frameworks\base\packages\SystemUI\src\com\android\systemui\volume\VolumeDialogControllerImpl.java
frameworks\base\packages\SystemUI\src\com\android\systemui\volume\VolumeDialogComponent.java

volume UI通过将 volumeUI的IVolumeController设置到audioService中,audioService音量设置完成后调用volumeControl的volumeChanged将音量变化通知到volumeUI。volumeUI根据传递的参数来确认是不是要弹出UI,播放提示音等等操作。

具体来说

  1. VolumeController首先设置audioManager 中,audioManager 在设置到audioService中。
  2. 上层的处理逻辑主要在VolumeDialogControllerImpl 和 VolumeDialogImpl这里面。
  3. 在VolumeDialogImpl通过addCallback将ui这边的callback和handler传递给VolumeDialogControllerImpl。
  4. VolumeDialogControllerImpl这里面同样有一个handler,所有audioService的调用都会转换为消息通过handler进行发送。
  5. 在对应的消息处理函数中进行flags和streamType的判断处理,需要显示的ui就调用之前通过addCallback设置下来的回调函数和handler进行处理。
  6. 在VolumeDialogImpl就是ui的各种处理比如音量设置的时候的弹出UI等等。

关键的代码:

注册到audioSerivice

VolumeDialogControllerImpl.java
    public void register() {
        setVolumeController();
    }
    protected void setVolumeController() 
        mAudio.setVolumeController(mVolumeController);
    }

audioService回调

AudioService.java
  protected void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags, int device) {
      mVolumeController.postVolumeChanged(streamType, flags);
   }

VolumeDialogControllerImpl.java 
public void volumeChanged(int streamType, int flags) throws RemoteException {
      mWorker.obtainMessage(W.VOLUME_CHANGED, streamType, flags).sendToTarget();
}

VolumeDialogController的回调和处理

public void init(int windowType, Callback callback) {
    mController.addCallback(mControllerCallbackH, mHandler);
}

boolean onVolumeChangedW(int stream, int flags) {
    final boolean showUI = shouldShowUI(flags);
    final boolean fromKey = (flags & AudioManager.FLAG_FROM_KEY) != 0;
    final boolean showVibrateHint = (flags & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0;
    final boolean showSilentHint = (flags & AudioManager.FLAG_SHOW_SILENT_HINT) != 0;
    boolean changed = true;
    if (showUI) {
        mCallbacks.onShowRequested(Events.SHOW_REASON_VOLUME_CHANGED);
    }
    return changed;
}
  • car volume ui的处理流程
    car volume ui跟system volume ui的区别是
  1. 复用了VolumeDialogControllerImpl 这一部分,但是VolumeDialogImpl这一部分独立实现 为CarVolumeDialogImpl。
  2. volume UI的实现也跟system volume ui也不一样。在上层CarVolumeDialogImpl没有设置callback的回调 ,但是有设置control到audioService。
  3. audioSeriver调用volumeControl部分的作用就不是很大。没有回调函数,VolumeDialogControllerImpl对于callback的调用是空的。
  • legacy模式

    1. car volume ui 中如果是legacy的模式. CarVolumeDialogImpl会注册CarVolumeCallback到CarAudioService。
    2. CarAudioService会监听VolumeChange的Intent。
    3. audioService这边如果有volumechange的intent广播出来之后。会回调到 CarVolumeDialogImpl进行ui相关的处理。
    4. intent中只包含了stramType 而对于之前的flag参数(是showUI play sound等等标志的或)是没有的。所以这边有个问题在需要显示ui或者播放声音的时候,处理不了。
  • dynamic 模式
    dynamic模式跟legacy模式又完全不一样,分为carAudioService 和 audioService

    1. carAudioService利用audioService 的setAudioPolicyVolumeCallback 将自己的调节音量的回调注册到audioSerivice。

    2. audioService 中实际是判断mIsVolumeController来处理的。有回调的时候,外部注册AudioPolicyProxy是将mIsVolumeController置为1.

    3. audioService:在进行调节之前 会判断外部的control 是不是存在的,存在的话 会notifyExternalVolumeController 发送 MSG_NOTIFY_VOL_EVENT

    4. 这个会调用到CarAudioService 的mVolCb.onVolumeAdjustment(msg.arg1);利用carAudioService 的 CarAudioPolicyVolumeCallback 然后调用setGroupVolume。

    5. setGroupVolume会调用AudioManger的AudioManager.setAudioPortGain。其实现就直接调用到hal层了。

    6. 同时在设置外部的controller的时候,会判断下面这个值,需要在overlay进行默认值覆盖。否则设置的无效。

      mContext.getResources().getBoolean(com.android.internal.R.bool.config_handleVolumeKeysInWindowManager)
      
    7. 对于ui的处理在CarAudioPolicyVolumeCallback中调用setGroupVolume时将flag设置为了showUI 和from key这样在callbackGroupVolumeChange中就会根据这个flag来显示音量变化时进行ui的显示了。

音量键的响应流程

简单的一个流程:

  1. phonwinowsManager 是第一个截获按键的地方,这边会派发给MediaSessionService。
  2. MediaSessionService调用mAudioManager.adjustSuggestedStreamVolumeForUid。
  3. 这里面调用了AudioPolicy的音量设置函数。 是通过音量曲线,将index 转换为增益,最后增益是设置到audioPloicy 设置到hal起作用的。 音频曲线有一个xml来定义,在xml 中是定义了一些坐标表示从1到100 对应的音频增益是多少。
  4. 设置完成之后会发送brodcast来通知外部 同时通过回调通知外部。外部的ui接收到信息后 会做出弹出ui,播放声音等响应。

AudioService设置音量流程

不管是通过按键还是进度条进行音量的调节,最后都会调用到AudioService。 但两种方式所调用的函数不一样。

需要注意的地方

  • streamalias

    audioService中定义的流类型在不同的平台映射是不一样的,有些平台如tv上music类型的音量是和ring alarm一样的,也就是说改变这些类型的音量会同时改变streamAlias对应的音量。同时base下面的的config.xml 中的config_single_volume 也会影响映射矩阵。

    假如config_single_volume 这个在overlay被重载为true,那么isSingleVolume就为true,所以对应映射矩阵是 PLATFORM_TELEVISION。而对于TVLEVISION 而言所有的streamType基本都是music。

      private final int[] STREAM_VOLUME_ALIAS_TELEVISION = new int[] {
                AudioSystem.STREAM_MUSIC, // STREAM_VOICE_CALL
                AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM
                AudioSystem.STREAM_MUSIC, // STREAM_RING
                AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
                AudioSystem.STREAM_MUSIC, // STREAM_ALARM
                AudioSystem.STREAM_MUSIC, // STREAM_NOTIFICATION
    
  • suppressAdjustment 处理

    这个只有在按键进行调节的时候 会进行这样的处理, 目的是在第一次设置不会真正的去设置音量 会先回调到UI这边 让UI显示出来,UI显示出来之后会通知到AudioService 这边 设置mVisible为true。

    之后在设置音量的话就可以显示了。(这样处理的目的是什么? 可能是为了在第一次调试的时候 让用户可以知道当前正在调节的音量是哪一个)。

AAOS音量条选项

  • 动态路由情况

    进度条选项跟car_audio_configuration 中定义的volumegroup对应。xml定义的group 每个group有多个usage的时候, 用的是第一个的。这边会有一个context转usage的过程。例子: 目前定义了4个 这边就会有4个选项。
    在这里插入图片描述

  • legacy 模式
    carAudioservice 中如果不是动态路由的话定义的是下面的这三种。AudioManager.STREAM_MUSIC, AudioManager.STREAM_ALARM, AudioManager.STREAM_RING。这个是固定在代码中。AAOS音频这边主要还是实现动态路由的场景。

总结

AAOS 音频音量的设置从ui上面看不太完善,与原生的Android有较大的差距,主要是为了支持传统的音频路由和动态路由,两者对于音量响应不一样,一个是依赖audioService intent的广播,一个是依赖于carAudioSerivice这边的回调。 从设置流程上看传统模式跟原生Android类似,而动态路由是可以之间操作到hal进行处理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/633009.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

chatgpt赋能python:如何取出带有4的整数

如何取出带有4的整数 Python是一门功能强大的编程语言,可以轻松解决复杂的编程问题。在本文中,我们将介绍如何使用Python编程语言从一个整数列表中取出所有带有4的整数。我们将从介绍如何创建一个整数列表开始,然后编写Python代码以实现我们…

Unreal 5 实现丢弃武器功能

之前实现了物品的拾取功能,但是没有实现丢弃功能,这一篇讲一下我是如何实现丢弃功能的。 丢弃功能的逻辑是:拾取物品时,需要使用拾取的物品进行类的实现,所以,我们需要把数据存储到拾取的物品上&#xff0c…

4.DIY可视化-拖拽设计1天搞定主流小程序-后台设计幻灯

后台设计幻灯:本教程均在第一节中项目启动下操作 1.首页幻灯片php安装:phpthink安装: 2.数据库创建:幻灯片表:项目根目录下cmd :执行 : php think diygw:tableandapi oneHdp查看结果目录:访问url: http://one.com/one/api.hdp/list 3.界面增删…

【6.10 代随_53day】 最长公共子序列、不相交的线、最大子数组和

最长公共子序列、不相交的线、最大子数组和 最长公共子序列动态规划方法图解步骤代码 不相交的线动态规划方法 最大子数组和图解步骤代码 最长公共子序列 力扣连接:1143. 最长公共子序列(中等) 动态规划方法 确定递推公式 主要就是两大情况…

《横向联邦学习中 PCA差分隐私数据发布算法》论文算法原理笔记

论文地址:https://www.arocmag.com/article/01-2022-01-041.html 论文摘要 为了让不同组织在保护本地敏感数据和降维后发布数据隐私的前提下,联合使用 PCA进行降维和数据发布,提出横向联邦 PCA差分隐私数据发布算法。引入随机种子联合协商方…

九、进程程序替换

文章目录 一、进程程序替换(一)概念(二)为什么程序替换(三)程序替换的原理(四)如何进行程序替换1. execl2. 引入进程创建——子进程执行程序替换,会不会影响父进程呢? &…

016、元组(行)结构与dml操作

元组结构与dml操作 元组(行)结构行头信息Pageinspect工具DML操作InsertionDeletionUpdate块空间清理元组(行)结构 t_xmin保存插入此元组的事务的txid。这一行被哪个事务ID所修改t_xmax保存删除或更新此元组的事务的txid。如果此元组未被删除或更新,则t_xmax设置为0,这意味…

数据结构——堆(C语言实现)

文章目录 什么是堆堆的实现堆的结构定义堆的初始化接口堆的销毁接口堆的插入数据接口向上调整建堆接口判断堆是否为空堆的删除数据接口向下调整建堆接口获取堆顶数据获取堆的有效数据个数完整实现代码小结 堆排序堆排序的实现 关于建堆和堆排序时间复杂度的分析向下调整建堆向上…

STL之string

目录 string的基本实现一. string的基本架构二. 常用方法及实现1.初始化和清理a. 构造函数b. 析构函数c. swapd. 拷贝构造e. operator 2.成员访问a. operator[]b. sizec. c_str 3.迭代器iteratora. beginb. end 4.增删查改a. reserveb. resizec. insertd. push_backe. appendf.…

【连续介质力学】连续体运动学

简介 一个质点从t0出发,随着时间有不同的构形,运动的描述是运动学。 所以需要建立运动方程来表征连续体是如何演化及其性质(例如位移、速度、加速度、质量密度、温度等)如何随时间变化 初始构形 或者 参考构形: B …

Java反射与注解

文章目录 一、 注解1.简介2. 元注解3. 自定义注解 二、 反射1. 简介2. 理解Class类并获取Class实例3. 类的加载与初始化4. 类加载器ClassLoader5. 获取运行时类的完整结构6. 动态创建对象执行方法7. 反射操作泛型8. 反射操作注解 一、 注解 1.简介 Annotation是JDK5.0开始引入…

day52|动态规划13-子序列问题

子序列系列问题 300.最长递增子序列 什么是递增子序列: 元素之间可以不连续,但是需要保证他们所在位置是元素在数组中的原始位置。 dp数组dp[i]表示以nums[i]为结尾的最长递增子序列的长度。递归函数:dp[i] max(dp[j]1,dp[j])初始化条件&…

Linux常用命令——gpm命令

在线Linux命令查询工具 gpm 提供文字模式下的滑鼠事件处理 补充说明 gpm命令是Linux的虚拟控制台下的鼠标服务器,用于在虚拟控制台下实现鼠标复制和粘贴文本的功能。 语法 gpm(选项)选项 -a:设置加速值; -b:设置波特率&…

chatgpt赋能python:Python中如何取出字符串中的数字并赋予新的变量

Python 中如何取出字符串中的数字并赋予新的变量 在 Python 中,我们经常需要处理字符串,其中可能包含多种类型的数据。当我们需要获取字符串中的数字时,该怎样做呢?本文将介绍取出字符串中的数字的方法,并赋予新的变量…

chatgpt赋能python:Python利器之数字提取

Python 利器之数字提取 Python 是一门强大的编程语言,被广泛应用在数据分析、人工智能等领域。在很多数据分析的场景下,需要从文本中提取数字,本文将介绍如何使用 Python 快速提取文本中的所有数字。 使用正则表达式提取数字 正则表达式&a…

YOLOv7 模型融合

将两种训练模型的检测结果融合 首先需要两种模型,一个是yolov7原有的模型,另一个是你训练出来的模型 其中yolov7.pt是官方提供的模型,有80个类别 其中yolov7_3.7HRW.pt是我们自己训练的模型,有三个分类,举手、看书、写…

WPF开发txt阅读器6:用树形图管理书籍

txt阅读器系列: 需求分析和文件读写目录提取类💎列表控件与目录字体控件绑定书籍管理系统 TreeView控件 TreeView可以通过可折叠的节点来显示层次结构中的信息,是表达文件系统从属关系的不二选择,其最终效果如下 为了构建这个树…

UnityVR--组件6--Animation动画

目录 新建动画Animation Animation组件解释 应用举例1:制作动画片段 应用举例2:添加动画事件 Animator动画控制器 应用举例3:在Animator中设置动画片段间的跳转 本篇使用的API:Animation、Animator以及Animator类中的SetFlo…

【Python可视化大屏】「淄博烧烤」热评舆情分析大屏

文章目录 一、开发背景二、爬虫代码2.1 展示爬取结果2.3 导入MySQL数据库 三、可视化代码3.1 大标题3.2 词云图(含:加载停用词)3.3 玫瑰图(含:snownlp情感分析)3.4 柱形图-TOP10关键词3.5 折线图-讨论热度趋…

ViewOverlay-使用简单实践

ViewOverlay-使用简单实践 一、ViewOverlay能实现什么?二、基础用法2.1 一个简单案例2.2 overlay.add(drawable)/groupOverlay.add(view)之后,不显示问题解决2.2.1 add(Drawable)方法2.2.1 add(View)方法 一、ViewOverlay能实现什么? 在Andro…