Android Audio音量设置

Android 音量设置流程解析

常用API方法

setStreamVolume

java 复制代码
public void setStreamVolume(int streamType, int index, int flags)
功能:直接设置指定音频流的音量
参数:
streamType:音频流类型(如AudioManager.STREAM_MUSIC)
index:音量级别(0到最大音量之间)
flags:标志位(如AudioManager.FLAG_SHOW_UI)
示例:

adjustStreamVolume

java 复制代码
-public void adjustStreamVolume(int streamType, int direction, int flags)
功能:按照direction,音量+1-1这种
参数:
streamType:音频流类型
direction:调整方向(如AudioManager.ADJUST_RAISE、AudioManager.ADJUST_LOWER等)
flags:标志位
参数值 常量名 描述
1 ADJUST_RAISE 提高音量
-1 ADJUST_LOWER 降低音量
0 ADJUST_SAME 保持当前音量
16 ADJUST_MUTE 静音
32 ADJUST_UNMUTE 取消静音
64 ADJUST_TOGGLE_MUTE 切换静音状态

adjustStreamVolume解析

AudioManager.java中adjustStreamVolume做了哪些操作

  • direction、streamtype的类型检查然后判断当前direction和stream_tpye是否是静音 如果是return
  • 如果direction是静音,stream_type是STREAM_VOICE_CALL or STREAM_BLUETOOTH_SCO 检查app是否有MODIFY_PHONE_STATE权限、如果 stream is STREAM_ASSISTANT,那么检查app是否有MODIFY_AUDIO_ROUTING权限
  • 通过stream_type获取当前合适的device,并且获取VolumeStreamState对象,这个对象是根据stream_type创建的,并且对象里面包含了各种device的默认音量大小
    静音调整处理:
  • 如果是静音调整(ADJUST_MUTE或ADJUST_TOGGLE_MUTE),会设置系统音频静音状态
  • 遍历所有音频流,对匹配的音频流进行静音/取消静音操作
  • 特殊处理了STREAM_SYSTEM_ENFORCED流(如相机快门声)
    音量增大处理:
  • 检查安全音量限制,如果超出安全音量会显示警告
  • 对于非全音量设备,调整音量索引
  • 如果当前是静音状态,会根据方向立即取消静音或延迟取消静音
  • 如果是蓝牙设备就要把消息发给蓝牙的service postSetAvrcpAbsoluteVolumeIndex
  • 如果是HDMI设备就调用 HdmiTvClient.java setSystemAudioVolume

是 否 App调用adjustStreamVolume AudioManager.java adjustStreamVolume AudioService.java adjustStreamVolume 静音调整? mute setAllVolumes applyAllVolumes setStreamVolumeIndex adjustIndex setDeviceVolume applyDeviceVolume_syncVSS

目前java层的代码已经分析完了,接下来要看native层的代码了

直接来看AudioPolicyManager.cppsetStreamVolumeIndex主要功能如下:

  • 根据stream_type获取attibutes

ProductStrategyMap ProductStrategy 1 ProductStrategy ... AudioAttributesVector AudioAttributesVector AudioAttributes 1 AudioAttributes ... AudioAttributes 1 AudioAttributes ...

ProductStrategyMap中的数据是通过解析audio_policy_engine_configuration.xml获取的如果没有配置则使用默认配置。

xml 复制代码
<ProductStrategy name="STRATEGY_PHONE">
    <AttributesGroup streamType="AUDIO_STREAM_VOICE_CALL" volumeGroup="voice_call">
        <Attributes> <Usage value="AUDIO_USAGE_VOICE_COMMUNICATION"/> </Attributes>
    </AttributesGroup>
    <AttributesGroup streamType="AUDIO_STREAM_BLUETOOTH_SCO" volumeGroup="bluetooth_sco">
        <Attributes> <Flags value="AUDIO_FLAG_SCO"/> </Attributes>
    </AttributesGroup>
</ProductStrategy>

比如上述xml配置中,可以看出这个ProductStrategy包含了两种stream_type分别是AUDIO_STREAM_VOICE_CALL和AUDIO_STREAM_BLUETOOTH_SCO。然后这个ProductStrategy包含了两个AudioAttributes。

audio_policy_engine_stream_volumes.xml

xml 复制代码
    <volumeGroup>
        <name>voice_call</name>
        <indexMin>1</indexMin>
        <indexMax>7</indexMax>
        <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
            <point>0,-4200</point>
            <point>33,-2800</point>
            <point>66,-1400</point>
            <point>100,0</point>
        </volume>
        <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
            <point>0,-2400</point>
            <point>33,-1600</point>
            <point>66,-800</point>
            <point>100,0</point>
        </volume>
        <volume deviceCategory="DEVICE_CATEGORY_EARPIECE">
            <point>0,-2700</point>
            <point>33,-1800</point>
            <point>66,-900</point>
            <point>100,0</point>
        </volume>
        <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
        <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
    </volumeGroup>

上述xml作用是解释音量相关的信息,比如在不同设备的voice_call类型的音量曲线 最大、最小index等。 可以看出来AudioAttributes中的AttributesGroup和volumeGroup是一一对应,根据name可以看出。并且从下图可以看出AudioAttributesVector和VolumeGroup一一对应。通过mId链接。

-调用setVolumeIndexForAttributes

调用setVolumeIndexForAttributes,这个函数主要功能如下:

  • 根据Attributes获取对应的VolumeGroup、音量曲线、VolumeSource、strategy
  • setVolumeCurveIndex (根据index device 设置curves)
  • 获取与音量曲线相关的输出设备。
  • 遍历所有输出描述符(SwAudioOutputDescriptor),检查并应用音量调整。checkAndSetVolume
  • 通知客户端音量组已发生变化。onAudioVolumeGroupChanged

checkAndSetVolume功能如下:

  • 检查音量源是否被静音。静音直接返回NO_ERROR(这里检查的是volumeSources是否是静音状态,这个状态在adjustStreamVolume流程并不会被设置)
  • 检查通话和蓝牙 SCO 音量冲突。
  • 获取设备类型。
  • 计算音量分贝值。(eswin在这一步把计算出来的volumeDb = 0.0f)
  • 设置音量。(SwAudioOutputDescriptor::setVolume)
  • 处理主输出设备的通话音量。(如果是主输出设备,并且在通过状态或者音量源是蓝牙,最终会调用到audio_hw.c中的setVoiceVolume,目的是提高实时性、硬件依赖性强)

接下来看一下setVolume的功能:

  • 调用基类的 setVolume 方法进行基础设置。改变mVolumeActivities[vs].setVolume(volumeDb)
  • 处理空音频流类型,默认使用 AUDIO_STREAM_MUSIC。
  • 遍历设备,检查设备类型和增益控制,设置设备增益,并且把软件层的增益设置为0。(前提是当前设备硬件支持音量增益,最后调用到hal的setAudioPortConfig,配置硬件是否支持增益需要更改audio_policy_configuration.xml添加useForVolume="true"即可)
  • 将分贝值换算成振幅
  • 处理蓝牙 SCO 设备的通话音量。setStreamVolume
  • 设置音频流音量。调用到SF中的setStreamVolume,然后调用Thread.cpp中在指定的playbacktrhead中设置 mStreamTypes[stream].volume = value;

音量设置流程总结

是 否 Java层调用adjustStreamVolume AudioManager.java adjustStreamVolume AudioService.java adjustStreamVolume 静音调整? mute setAllVolumes applyAllVolumes setStreamVolumeIndex adjustIndex setDeviceVolume applyDeviceVolume_syncVSS AudioPolicyManager.cpp setStreamVolumeIndex AudioPolicyManager.cpp setVolumeIndexForAttributes checkAndSetVolume SwAudioOutputDescriptor.cpp setVolume Thread.cpp setVolume

setStreamVolume解析

在AudioService.java中 setStreamVolume 功能如下:

  • 如果device是蓝牙并且是绝对音量那么就调用蓝牙音量设置postSetAvrcpAbsoluteVolumeIndex
  • 如果是助听器调用ostSetHearingAidVolumeIndex
  • 如果是HDMI设备调用setSystemAudioVolume
  • 如果当前音频流类型为 STREAM_MUSIC,并且设备是固定音量设备,设置 FLAG_FIXED_VOLUME 标志位。如果音量值不为 0,则根据设备的安全音量状态,将音量值设置为安全音量值或最大音量值。
  • 调用onSetStreamVolume
    onSetStreamVolume功能如下:
    -调用setStreamVolumeInt

AudioService.java setStreamVolume onSetStreamVolume setStreamVolumeInt 发送消息 MSG_SET_DEVICE_VOLUME Handler.handleMessage setDeviceVolume applyDeviceVolume_syncVSS

相关推荐
恋猫de小郭3 小时前
腾讯 Kuikly 正式开源,了解一下这个基于 Kotlin 的全平台框架
android·前端·ios
贫道绝缘子3 小时前
【Android】四大组件之Activity
android
人生游戏牛马NPC1号4 小时前
学习Android(四)
android·kotlin
_祝你今天愉快4 小时前
安卓触摸事件分发机制分析
android
fyr897574 小时前
Ubuntu 下编译goldfish内核并使用模拟器运行
android·linux
心之所向,自强不息4 小时前
关于Android Studio的Gradle各项配置
android·ide·gradle·android studio
隐-梵4 小时前
Android studio学习之路(八)---Fragment碎片化页面的使用
android·学习·android studio
百锦再4 小时前
Kotlin学习基础知识大全(上)
android·xml·学习·微信·kotlin·studio·mobile
前期后期5 小时前
Android 智能家居开发:串口是什么,为什么android版本都比较低?粘包半包的原因以及处理思路,缓冲区处理,以及超时清空缓冲区....
android·智能家居
Wgllss5 小时前
按需下载!!全动态插件化框架WXDynamicPlugin解析怎么支持的
android·架构·android jetpack