android 音量调节
安卓音频数据的最终音量由三部分组成,分别是master volume(全局音量,对整个系统所有的音频数据生效),stream volume(流音量,只针对特定类型的音频数据生效)和track volume(track音量,只针对某个audiotrack的数据生效)。
音频数据音量大小公式:
final_volume= master_volume * stream_volume * track_volume;playbackthread负责这个具体值的计算并设置到audiomixer中生效。
其中master_volume,stream_volume和track_volume都是百分比,1表示音量调到最大;
音量最大分贝是0db,表示没有衰减,也就是音源音量;
stream volume
VolumeStreamState(audioservice用来管理系统音量引入的概念)
android系统定义了11种Stream(从0到10),每个stream都用VolumeStreamState来封装:
VolumeStreamState[] mStreamStates = new int[] {0,1,2,3,4,5,6,7,8,9,10};//0,1,2...这些数字表示stream类型,分别对应default,voice call,ring等;
VolumeStreamState{//用来管理一个流类型所有的音量信息/*stream类型*/int mStreamType;/*volume最小索引,只有0和1*/int mIndexMin;/*volume最大索引,7,15等*/int mIndexMax;//boolean mIsMuted;/*VolumeStreamState的名字,用来对系统setting进行查询和持久化*/String mVolumeIndexSettingName;int mObservedDevices;/*map中的key为device,value为音量值bvolume*/SparseIntArray mIndexMap = new SparseIntArray(8);/*当音量发生改变时,发送广播AudioManager.VOLUME_CHANGED_ACTION*/Intent mVolumeChanged;Intent mStreamDevicesChanged;
}
alias流别名
android系统定义了11种Stream(从0到10),如果用一个数组来表示,它们与mStreamStates数组中的元素一一对应:
int[] STREAM_VOLUME_DEFAULT = new int[] {0,1,2,3,4,5,6,7,8,9,10};//系统默认
android定义了这么多的streamtype,但目前android设备的并不支持这么多的stream,比如点击手机音量键调节某一个Stream音量时,android系统只会出现5个滑动条,也就是手机设备只有5类stream,又比如机顶盒只支持music stream这1类,所以对于不同的平台,需要将这些stream进行分组,把具有相同属性stream分为一类,在Android源码中称之为"别名", 即alias;
下面就是android源码11种stream的分组结果:
int[] STREAM_VOLUME_ALIAS_VOICE = new int[] {0,2,2,3,4,5,6,2,2,3,3};//手机
int[] STREAM_VOLUME_ALIAS_TELEVISION = new int[] {3,3,3,3,3,3,3,3,3,3,3};//机顶盒
int[] STREAM_VOLUME_ALIAS_DEFAULT = new int[] {0,2,2,3,4,2,6,2,2,3,3};//默认
以手机为例,手机只支持2,3,4,5,6(0暂时忽略)这5种stream,由于手机的3,9,10归类到了3,也就是别名alias为3,所以当手机调节3,9,10这3种stream时,实际上调节的是3(music stream)。
系统提供的调节stream volume的api有2个,分别是adjustVolume()和 setStreamVolume(),我们看adjustVolume():
adjustVolume()
//java层:
//AudioService.java
adjustSuggestedStreamVolume()//确定streamTypefinal int streamType;if (mUserSelectedVolumeControlStream) {streamType = mVolumeControlStream;}else{......}adjustStreamVolume()int streamTypeAlias = mStreamVolumeAlias[streamType];//将streamType转化为对应平台的streamTypeAliasVolumeStreamState streamState = mStreamStates[streamTypeAlias];final int device = getDeviceForStream(streamTypeAlias);//得到当前的deviceint aliasIndex = streamState.getIndex(device);//得到该device在当前stream上的音量int step;step = rescaleIndex(10, streamType, streamTypeAlias);//音量步进转化/*安全音量相关*/......if(streamState.adjustIndex()){//调节音量,设置新的index值并发送音量改变的广播sendMsg(...,MSG_SET_DEVICE_VOLUME,...);//设置index到底层,并且将index保存到系统settingssetDeviceVolume();streamState.applyDeviceVolume_syncVSS(device);//设置index到底层,一直想不明白VSS是个啥缩写,今天突然明白了是VolumeStreamState的首字母缩写!!!!!!!!!!!!!!!!!!!!!!!1int index;index = ......;//确定index的最终值AudioSystem.setStreamVolumeIndex(mStreamType, index, device);//将index设置到底层for(......){//处理mStreamVolumeAlias相关mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);}sendMsg(...,MSG_SET_DEVICE_VOLUME,...);//将index保存到系统settingspersistVolume();System.putIntForUser(......);//将index保存到系统settings}sendVolumeUpdate(streamType, oldIndex, index, flags);//刷新音量条(UI)//看看streamState.adjustIndex()streamState.adjustIndex()setIndex()//设置新的index值并发送音量改变的广播oldIndex = getIndex(device);//volume改变之前的indexmIndexMap.put(device, index);//保存volume改变之后的indexchanged = oldIndex != index;//如果volume改变前后的index不相同for(...){//处理alias相关VolumeStreamState aliasStreamState = mStreamStates[streamType];aliasStreamState.setIndex(scaledIndex, device, caller);}if(changed){//当音量发生改变时,发送广播AudioManager.VOLUME_CHANGED_ACTIONsendBroadcastToAll(mVolumeChanged);}
//native层
//AudioSystem.java
AudioSystem.setStreamVolumeIndex()
//AudioSystem.cpp
AudioSystem::setStreamVolumeIndex()
//AudioPolicyManager.cpp
AudioPolicyManager::setStreamVolumeIndex()
for (size_t i = 0; i < mOutputs.size(); i++) {
checkAndSetVolume();//设置每个输出设备的音量
float volumeDb = computeVolume(stream, index, device);//计算音量
volumeDB = mVolumeCurves->volIndexToDb(stream, Volume::getDeviceCategory(device), index);
//VolumeCurve.cpp
VolumeCurve::volIndexToDb()//根据音量曲线计算出音量
outputDesc->setVolume(volumeDb, stream, device, delayMs, force);
//AudioOutputDescriptor.cpp
SwAudioOutputDescriptor::setVolume()
bool changed = AudioOutputDescriptor::setVolume(volume, stream, device, delayMs, force);
AudioOutputDescriptor::setVolume()
mCurVolume[stream] = volume;
mClientInterface->setStreamVolume(stream, volume, mIoHandle, delayMs);
//AudioPolicyService.cpp
AudioPolicyService::setStreamVolume()
mAudioCommandThread->volumeCommand()//AudioPolicyService::AudioCommandThread::volumeCommand()
sp command = new AudioCommand();
command->mCommand = SET_VOLUME;
sendCommand(command, delayMs);//AudioPolicyService::AudioCommandThread::sendCommand()
insertCommand_l(command, delayMs);//插入命令,执行AudioPolicyService::AudioCommandThread::threadLoop()
AudioSystem::setStreamVolume();//AudioSystem::setStreamVolume()
//AudioSystem.cpp
af->setStreamVolume(stream, value, output);//AudioFlinger::setStreamVolume()
//AudioFlinger.cpp
VolumeInterface *volumeInterface = getVolumeInterface_l(output);
volumeInterface->setStreamVolume(stream, value);//AudioFlinger::PlaybackThread::setStreamVolume()
//Threads.cpp
mStreamTypes[stream].volume = value;//保存volume值
broadcast_l();//唤醒PlaybackThread线程
AudioFlinger::PlaybackThread::threadLoop()
mMixerStatus = prepareTracks_l(&tracksToRemove);//不同类型的Thread对prepareTracks_l有不同的实现
AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTracks_l()//计算每个track数据最终的音量
…
}
音量曲线:我们从上面的代码中可以看到在audioservice中音量都是整形的index。而用于音量算法处理的是DB。音量曲线的作用就是将index转化为对应的DB 。这个音量曲线是可以通过配置文件修改。配置文件会定义一些点,audiopolicymanager会根据配置文件的点进行拟合,获得一条从最小index到最大index隐射到-∞DB到0DB的曲线。
auditorack音量设置:
//AudioTrack.cpp
AudioTrack::setVolume(float left, float right)/*传入的音量值保存在mVolume数组中*/mVolume[AUDIO_INTERLEAVE_LEFT] = left;mVolume[AUDIO_INTERLEAVE_RIGHT] = right;/*setVolumeLR会把做声道与右声道的值,组装成一个数*/mProxy->setVolumeLR(gain_minifloat_pack(gain_from_float(left), gain_from_float(right)));//AudioTrackShared.h/*mCblk表示共享内存的头部,也就是说这个音量值会保存到共享内存的头部*/mCblk->mVolumeLR = volumeLR;播放声音时需要AudioMixer进行混音,继续分析AudioFlinger::MixerThread::prepareTracks_l():
//Threads.cpp
AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTracks_l()/*取出硬件声音*/float masterVolume = mMasterVolume;bool masterMute = mMasterMute;/*把所有活跃的Tracks取出来*/for (size_t i=0 ; i<count ; i++) {......//这就是stream volumefloat typeVolume = mStreamTypes[track->streamType()].volume;float v = masterVolume * typeVolume;/*从proxy中取出取出音量,其就是通过头部保存的音量,其含有左右声道的音量*/gain_minifloat_packed_t vlr = proxy->getVolumeLR();/*提取左右声道的值*/vlf = float_from_gain(gain_minifloat_unpack_left(vlr));vrf = float_from_gain(gain_minifloat_unpack_right(vlr));/*都与之前的V进行相乘*/vlf *= v * vh;vrf *= v * vh;/*把vlf与vrf传入给AudioMixer*/mAudioMixer->setParameter(name, param, AudioMixer::VOLUME0, &vlf);mAudioMixer->setParameter(name, param, AudioMixer::VOLUME1, &vrf);}
相关文章:
android 音量调节
安卓音频数据的最终音量由三部分组成,分别是master volume(全局音量,对整个系统所有的音频数据生效),stream volume(流音量,只针对特定类型的音频数据生效)和track volume(track音量,只针对某个audiotrack的…...
Redis JSON 用id读取content总结(sendCommand())
Redis JSON 读取总结(方法 2 - sendCommand()) 💡 背景 在 Redis 中,我们存储了 JSON 数据,并希望通过 Jedis sendCommand() 方式读取 JSON 里的 "content" 字段。由于 jedis.jsonGet() 可能在旧版本不支持…...
使用Qdrant等其他向量数据库时需要将将numpy 数组转换为列表 确保数据能被正确处理和序列化,避免类型不兼容的问题。
在使用Qdrant等其他向量数据库时需要 转换 numpy 数组为列表主要是为了确保数据能被正确处理和序列化,避免类型不兼容的问题。具体原因如下: 序列化兼容性: 很多数据库接口、API 或者 JSON 序列化工具只能处理 Python 的内置类型(…...
[AI速读]如何构建高效的AMBA协议检查器(Checker IP)
在芯片验证过程中,检查器(Checker)是确保设计符合协议规范的关键工具。本文基于一篇技术论文,分享如何为AMBA协议(如AXI、AHB)构建可重用的检查器IP(Checker IP,简称CIP),并简化其核心思路,帮助工程师快速上手。 一、什么是Checker IP? Checker IP是一组用SystemVe…...
基于3DMax与Vray引擎的轻量级室内场景渲染实践
欢迎踏入3DMAX室内渲染的沉浸式学习之旅!在这个精心设计的实战教程中,我们将携手揭开3DMAX与Vray这对黄金搭档在打造现实室内场景时的核心奥秘。无论您是渴望入门的3D新手,还是追求极致效果的专业设计师,这里都将为您呈现从场景蓝图构建到光影魔法施加的完整技术图谱。我们…...
浅谈Qt事件子系统——以可拖动的通用Widget为例子
浅谈Qt事件子系统——以可拖动的通用Widget为例子 这一篇文章是一个通过实现可拖动的通用Widget为引子简单介绍一下我们的事件对象子系统的事情 代码和所有的文档 1:Qt侧的API介绍和说明 这个是每一个小项目的惯例,我会介绍大部分Qt程序中使用到的…...
QT Quick(C++)跨平台应用程序项目实战教程 2 — 环境搭建和项目创建
目录 引言 1. 安装Qt开发环境 1.1 下载Qt安装包 1.2 安装Qt 1.3 安装MSVC编译器 2. 创建Qt Quick项目 2.1 创建新项目 2.2 项目结构 2.3 运行项目 3. 理解项目代码 3.1 main.cpp文件 3.2 Main.qml文件 引言 在上一篇文章中,我们介绍了本教程的目标和结…...
登山第二十梯:无人机实时自主探索——我是一只小小小鸟
文章目录 一 摘要 二 资源 三 内容 一 摘要 自主探索是无人机 (UAV) 各种应用的基本问题。最近,基于 LiDAR 的探索因其能够生成大规模环境的高精度点云地图而受到广泛关注。虽然点云本身就为导航提供了信息,但许多现有的勘探方…...
Pytorch使用手册—扩展 TorchScript 使用自定义 C++ 操作符(专题五十三)
提示 本教程自 PyTorch 2.4 起已弃用。有关 PyTorch 自定义操作符的最新指南,请参阅 PyTorch 自定义操作符。 PyTorch 1.0 版本引入了一种名为 TorchScript 的新编程模型。TorchScript 是 Python 编程语言的一个子集,可以被 TorchScript 编译器解析、编译和优化。此外,编译后…...
word插入Mathtype公式居中和自动更新
word插入公式自动更新 前提:安装Mathtype 1.word中查看页的宽度 出现如下 2.设置样式 出现这个窗口 给样式随便起个名字 3.修改样式 3.1 设置两个制表位 第二个 3.2 修改公式字体 如下所示 4. 修改公式格式 4.1在word中打开 Mathtype 4.2 修改公式的格式 变成…...
网络层之IP协议
在讨论传输层时, 我们都只讨论了发送方和接收方的问题, 而没有讨论中间的网络形态的问题. 也就是数据包如何从主机传送到主机的? 如图, 主机B发送数据到主机C, 发送报文需要进行路径选择, 主机B-> F-> G-> H-> C-> D -> 主机C 这条路径是如何被选择出来的?…...
基于springboot的旅游网站(013)
摘 要 随着科学技术的飞速发展,各行各业都在努力与现代先进技术接轨,通过科技手段提高自身的优势,旅游网站当然也不能排除在外,随着旅游网站的不断成熟,它彻底改变了过去传统的旅游网站方式,不仅使旅游管理…...
人工智能 - 在 Spring Boot 中调用 AnythingLLM+DeepSeek 的知识库获取消息接口
整体逻辑: 自建系统的web UI界面调用接口: 1.SpringBoot接口:/anything/chatMessageAnything 2.调用anythingLLM - 调用知识库deepseek r1 . 部署 AnythingLLM DeepSeek 本地知识库 的环境要求如下: 一、硬件要求 CPU 最低:4核&#x…...
体育直播模板nba英超直播欧洲杯直播模板手机自适应
源码名称:体育直播模板nba英超直播欧洲杯直播模板手机自适应帝国cms 7.5模板 开发环境:帝国cms7.5 空间支持:phpmysql 带软件采集,可以挂着自动采集发布,无需人工操作! 模板特点: 程序伪静态…...
STM32-ARM
一、体系架构 ARM里有37个寄存器ALU算数逻辑单元PC程序计数器:指向哪里执行哪里SP栈指针寄存器LR链接寄存器:保存函数入口地址CPSR(current program status register)当前程序状态寄存器:SOSR(CPSR的备份)MMU(内存管理单元)Cache高速缓冲(iCa…...
ripro 主题激活 问题写入授权Token失败,可能无文件写入权限
ripro 主题激活 问题 写入授权Token失败,可能无文件写入权限 找到主题下面的functions.php文件,给其他写入权限。就好了。...
Lustre 语言的 Rust 生成相关的工作
目前 Lustre V6 编译器支持编译生成的语言为C语言。但也注意到,以 Rust 语言为生成目标语言,也存在若干相关工作。 rustre(elegaanz) 该项工作为 Lustre v6 语言的解析器,使用 Rust 语言实现。生成 Lustre AST。 项…...
计算机网络——通信基础和传输介质
物理层任务:实现相邻节点之间比特(0或1)的传输 到了数据链路层之后,它会以帧为单位,把若干个比特交给物理层,物理层需要把这些比特信息转化成信号,在物理传输媒体上进行传输 通信基础基本概念 信…...
python-selenium 爬虫 由易到难
本质 python第三方库 selenium 控制 浏览器驱动 浏览器驱动控制浏览器 推荐 edge 浏览器驱动(不容易遇到版本或者兼容性的问题) 驱动下载网址:链接: link 1、实战1 (1)安装 selenium 库 pip install selenium&#…...
Execution failed for task ‘:path_provider_android:compileDebugJavaWithJavac‘.
What went wrong: Execution failed for task ‘:path_provider_android:compileDebugJavaWithJavac’. Could not resolve all files for configuration ‘:path_provider_android:androidJdkImage’. Failed to transform core-for-system-modules.jar to match attributes {…...
【Linux 维测专栏 2 -- Deadlock detection介绍】
文章目录 kernel 编译选项配置deadlock 测试代码deadlock 测试 logkernel 编译选项配置 通过 menuconfig 配置下面编译选项 # lockdep CONFIG_LOCK_STAT=y CONFIG_PROVE_LOCKING=y CONFIG_DEBUG_LOCKDEP=y上面配置完成后会定义下面宏: CONFIG_LOCK_DEBUGGING_SUPPORT=y CONF…...
T113-i开发板的休眠与RTC定时唤醒指南
在嵌入式系统设计中,休眠与唤醒技术是优化电源管理、延长设备续航的关键。飞凌嵌入式基于全志T113-i处理器开发设计的OK113i-S开发板提供了两种休眠模式:freeze和mem,以满足不同应用场景下的功耗与恢复速度需求。本文将详细介绍如何让OK1…...
Node.js系列(4)--微服务架构实践
Node.js微服务架构实践 🔄 引言 微服务架构已成为构建大规模Node.js应用的主流选择。本文将深入探讨Node.js微服务架构的设计与实现,包括服务拆分、服务治理、通信机制等方面,帮助开发者构建可扩展的微服务系统。 微服务架构概述 Node.js…...
基于Spring Boot的公司资产网站的设计与实现(LW+源码+讲解)
专注于大学生项目实战开发,讲解,毕业答疑辅导,欢迎高校老师/同行前辈交流合作✌。 技术范围:SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:…...
CSS 中flex - grow、flex - shrink和flex - basis属性的含义及它们在弹性盒布局中的协同作用。
大白话CSS 中flex - grow、flex - shrink和flex - basis属性的含义及它们在弹性盒布局中的协同作用。 在 CSS 的弹性盒布局(Flexbox)里,flex-grow、flex-shrink 和 flex-basis 这三个属性对弹性元素的尺寸和伸缩性起着关键作用。下面为你详细…...
基于CVX优化器的储能电池调峰调频算法matlab仿真
目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 4.1 原理概述 4.2 CVX工具箱概述 5.完整工程文件 1.课题概述 基于CVX优化器的储能电池调峰调频算法matlab仿真。CVX 是一种用于求解凸优化问题的强大工具。凸优化问题具有良好的数学性质,能…...
SpringBoot3+Vue3开发学生成绩管理系统
系统介绍 此系统功能包含:首页、课程管理、成绩查询、成绩详情、班级管理、专业管理、用户管理等功能。用户管理又细分为账号管理、学生管理、教师管理、管理员管理。 基础功能包含:登录、退出、修改登录人信息、修改登录人密码。 分为4种角色&#x…...
正则魔法:解码 return /^\d+$/.test(text) ? text : ‘0‘ 的秘密
🚀 正则魔法:解码 return /^\d$/.test(text) ? text : 0 的秘密 🌟 嘿,技术探险家们!👋 今天我们要破解一段看似简单的代码:return /^\d$/.test(text) ? text : 0。它藏在一个 Vue 前端组件中…...
基于BClinux8部署Ceph 19.2(squid)集群
#作者:闫乾苓 文章目录 1.版本选择Ceph版本发布历史目前官方在维护的版本 2.部署方法3.服务器规划4.前置配置4.1系统更新4.2配置hosts cat >> /etc/hosts << EOFssh-keygenssh-copy-id ceph01ssh-copy-id ceph02ssh-copy-id ceph034.5 Python34.6 Syst…...
CVPR2025 | 对抗样本智能安全方向论文汇总 | 持续更新中~
汇总结果来源:CVPR 2025 Accepted Papers 若文中出现的 论文链接 和 GitHub链接 点不开,则说明还未公布,在公布后笔者会及时添加. 若笔者未及时添加,欢迎读者告知. 文章根据题目关键词搜索,可能会有遗漏. 若笔者出现…...
