前言

关于音量调节我们知道有AudioManager的软件调节和CarAudioManager的硬件调节,今天先聊聊AudioManager的软件音量调节。

正文

关于AudioManager中音量调节的API主要有如下两个:

  1. adjustVolume
  2. setStreamVolume

adjustVolume偏向一些按键的音量调节,比如手机上音量+-的硬按键控制的音量调节。
setStreamVolume更像是settings中的音量bar进行的音量调节。
说这俩函数前先看下volume几个相关的数组。

  • Max Volume
    所有streamType对应的最大音量
  /** Maximum volume index values for audio streams */protected static int[] MAX_STREAM_VOLUME = new int[] {5,  // STREAM_VOICE_CALL7,  // STREAM_SYSTEM7,  // STREAM_RING15, // STREAM_MUSIC7,  // STREAM_ALARM7,  // STREAM_NOTIFICATION15, // STREAM_BLUETOOTH_SCO7,  // STREAM_SYSTEM_ENFORCED15, // STREAM_DTMF15, // STREAM_TTS15, // STREAM_ACCESSIBILITY15  // STREAM_ASSISTANT};
  • Min Volume
    所有streamType对应的最小音量
    /** Minimum volume index values for audio streams */protected static int[] MIN_STREAM_VOLUME = new int[] {1,  // STREAM_VOICE_CALL0,  // STREAM_SYSTEM0,  // STREAM_RING0,  // STREAM_MUSIC1,  // STREAM_ALARM0,  // STREAM_NOTIFICATION0,  // STREAM_BLUETOOTH_SCO0,  // STREAM_SYSTEM_ENFORCED0,  // STREAM_DTMF0,  // STREAM_TTS1,  // STREAM_ACCESSIBILITY0   // STREAM_ASSISTANT};
  • Default Volume
    注意默认音量定义在AudioSystem中
    public static int[] DEFAULT_STREAM_VOLUME = new int[] {4,  // STREAM_VOICE_CALL7,  // STREAM_SYSTEM5,  // STREAM_RING5, // STREAM_MUSIC6,  // STREAM_ALARM5,  // STREAM_NOTIFICATION7,  // STREAM_BLUETOOTH_SCO7,  // STREAM_SYSTEM_ENFORCED5, // STREAM_DTMF5, // STREAM_TTS5, // STREAM_ACCESSIBILITY5, // STREAM_ASSISTANT};

我们知道了每个streamType对应的最大、最小以及默认的音量,还有个很重的数组

  • Volume Alias
    private final int[] STREAM_VOLUME_ALIAS_VOICE = new int[] {AudioSystem.STREAM_VOICE_CALL,      // STREAM_VOICE_CALLAudioSystem.STREAM_RING,            // STREAM_SYSTEMAudioSystem.STREAM_RING,            // STREAM_RINGAudioSystem.STREAM_MUSIC,           // STREAM_MUSICAudioSystem.STREAM_ALARM,           // STREAM_ALARMAudioSystem.STREAM_RING,            // STREAM_NOTIFICATIONAudioSystem.STREAM_BLUETOOTH_SCO,   // STREAM_BLUETOOTH_SCOAudioSystem.STREAM_RING,            // STREAM_SYSTEM_ENFORCEDAudioSystem.STREAM_RING,            // STREAM_DTMFAudioSystem.STREAM_MUSIC,           // STREAM_TTSAudioSystem.STREAM_MUSIC,           // STREAM_ACCESSIBILITYAudioSystem.STREAM_MUSIC            // STREAM_ASSISTANT};

ALIAS别名,这个主要是将streamType进行了分组,相同别名的音量一组。如streamType是TTS和Music的就是一组,同一组的音源音量一起调节,我们调节了STREAM_MUSIC的音量,那么STREAM_TTS的音量也会同步变更。
接下来就看下具体音量调节的流程吧。

adjustVolume

调节当前音源的音量,AudioService中实现adjustStreamVolume的逻辑比较复杂,因为随着Android版本的不断迭代,功能的不断增多。因此逻辑也是越来越复杂,比如震动下的铃声调节、勿扰模式下的铃声调节,以及特殊StreamType的特殊处理,这里只说下大体的流程吧。
首先是step的计算,即每次调节音量的步长。

 step = rescaleStep(10, streamType, streamTypeAlias);

看下rescaleStep这个函数:

    private int rescaleStep(int step, int srcStream, int dstStream) {int srcRange = getIndexRange(srcStream);int dstRange = getIndexRange(dstStream);if (srcRange == 0) {Log.e(TAG, "rescaleStep : index range should not be zero");return 0;}return ((step * dstRange + srcRange / 2) / srcRange);}

srcStream表示调节的streamType,dstStream表示当前音量组的streamType,举个例子如果当前调节的srcStream是STREAM_TTS那么通过STREAM_VOLUME_ALIAS_VOICE 我们可以知道dstStream是STREAM_MUSIC。

    private int getIndexRange(int streamType) {return (mStreamStates[streamType].getMaxIndex() - mStreamStates[streamType].getMinIndex());}

如果srcStream音量最大值减去最小值不是0,那么就说明这个streamType的音量是可以调节的,那么它的步长就是((step * dstRange + srcRange / 2) / srcRange)根据上面的数组就很容易算出step来了。
拿到step,在根据direction然后调用VolumeStreamState的adjustIndex,而adjustIndex又会调用setIndex

        public boolean adjustIndex(int deltaIndex, int device, String caller,boolean hasModifyAudioSettings) {return setIndex(getIndex(device) + deltaIndex, device, caller,hasModifyAudioSettings);}

setIndex中主要做音量处理,以及发送音量变化的广播。这里多说一句音量变更后存储在mIndexMap中。

mIndexMap.put(device, index)

可以看到音量的存储并不是根据streamType来的,而是根据device存储的,这就解释了我们在播放音乐的时候外放和插入耳机播放时音量不一致的原因了。
因为一个streamType可能对应多个Device即,一个streamType可能存在多个音量。

音量更新完后便是给子线程发 MSG_SET_DEVICE_VOLUME消息来调节音量。 子线程收到音量调节消息后调用VolumeStreamState的setDeviceVolume

    /*package*/ void setDeviceVolume(VolumeStreamState streamState, int device) {synchronized (VolumeStreamState.class) {// Apply volumestreamState.applyDeviceVolume_syncVSS(device);// Apply change to all streams using this one as aliasint numStreamTypes = AudioSystem.getNumStreamTypes();for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {if (streamType != streamState.mStreamType &&mStreamVolumeAlias[streamType] == streamState.mStreamType) {// Make sure volume is also maxed out on A2DP device for aliased stream// that may have a different device selectedint streamDevice = getDeviceForStream(streamType);if ((device != streamDevice) && mAvrcpAbsVolSupported&& AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)) {mStreamStates[streamType].applyDeviceVolume_syncVSS(device);}mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);}}}// Post a persist volume msgsendMsg(mAudioHandler,MSG_PERSIST_VOLUME,SENDMSG_QUEUE,device,0,streamState,PERSIST_DELAY);}

这里主要做了三步,先看第一步即设置音量applyDeviceVolume_syncVSS将音量通过AudioSystem设置到native的AudioPolicyManager中;第二步是 mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice)即设置相同组别的其他streamType的音量;最后一步发送MSG_PERSIST_VOLUME消息。将音量保存起来。
这样adjustVolume的流程就走完了。

setStreamVolume

设置指定streamType的音量。和adjustVolume的流程类似,但是相对adjustVolume而言setStreamVolume直接在AudioManager中调用到AudioService中的setStreamVolume。然后一些特殊的判断后会调用到onSetStreamVolume

    private void onSetStreamVolume(int streamType, int index, int flags, int device,String caller, boolean hasModifyAudioSettings) {final int stream = mStreamVolumeAlias[streamType];setStreamVolumeInt(stream, index, device, false, caller, hasModifyAudioSettings);// setting volume on ui sounds stream type also controls silent modeif (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||(stream == getUiSoundsStreamType())) {setRingerMode(getNewRingerMode(stream, index, flags),TAG + ".onSetStreamVolume", false /*external*/);}// setting non-zero volume for a muted stream unmutes the stream and vice versa,// except for BT SCO stream where only explicit mute is allowed to comply to BT requirementsif (streamType != AudioSystem.STREAM_BLUETOOTH_SCO) {mStreamStates[stream].mute(index == 0);}}

然后是setStreamVolumeInt,然后streamState.setIndex到这里就和adjustVolume的逻辑相同了。

总结

AudioManager的音量调节无论是adjustVolume还是setStreamVolume其实核心逻辑都是一样的,

  • 更新VolumeStreamState中index,并存入mIndexMap中(主要为了getStreamVolume使用),将index通过AudioSystem设置下去
  • 更新同组别的其他streamType的音量,音量组别可以通过int[] STREAM_VOLUME_ALIAS_VOICE查看
  • 音量存储到数据库中
    以上,欢迎大家一起沟通讨论喜欢就点下关注吧

Android R- AudioManager之音量调节(一)相关推荐

  1. Android安卓仿IOS音量调节-自定义view系列(4)

    Android安卓仿IOS音量调节-自定义view系列 功能简介 主要实现步骤 xml相关属性设置 java代码 Android技术生活交流 更多其他页面-自定义View-实用功能合集:点击查看 Gi ...

  2. 去掉Android中的耳机音量调节到最大时候的音量检查

    问题背景: Android R Automotive版本开发车机过程中,想要实现多通路音频输出,正常选择了一个通路对应speaker这个output device,另外一个通路选择了wired hea ...

  3. android 音量调节 seekbar,Android 使用SeekBar调节系统音量

    以下是一个使用SeekBar来调节系统音量的实例: 1.XML: android:id="@+id/sound" android:layout_width="150px& ...

  4. android 音量调节

    音量调节分3个部分,分别是master volume(硬件音量,控制声卡),stream volume(流音量)和track volume(app音量). app音量大小公式: app_mix = m ...

  5. Android 9 按音量键音量调节流程

    参考:https://blog.csdn.net/kehyuanyu/article/details/49153223 https://blog.csdn.net/qq_34787560/articl ...

  6. Android音量调节的实现(RingtoneManager和RingerVolumePreference)

    Android音量调节的实现,分两种情况说明,一种是在settings的音量设置界面,按下侧键进行调节:另一种是在非settings界面,按下侧键进行音量调节.这两种调节方式的实现不一样,分别操作的是 ...

  7. android 自定义音量调节,Android——自定义音量调节控件

    今天我们要实现一个上图中音量调节的效果.主要有两种实现方式自定义RatingBar和自定义View. 自定义RatingBar volume_rating.xml main.xml android:i ...

  8. Android 音频源码分析——音量调节流程

    源码分析基于android9.0 一.声音类型 对于大多数手机用户来说,操作手机音量按键可以看到,声音类型分为四种:媒体.铃声.闹钟.通话,但是其系统内部则分为十几种类型. 声⾳类型用来区分不同播放用 ...

  9. android 音量 广播,Android平台音量调节(一)音量键调节音量

    Android平台音量调节 本文基于Android 8.0讲述Android平台原生音量控制功能. 流的定义 Android中,音量都是分开控制,各种流定义各种流的音量.在Android8.0中,定义 ...

最新文章

  1. wamp的mysql单独使用_Windows 7+8.1+10 单独安装配置 PHP+Apache+MySQL(不使用 WAMP)
  2. php中的css样式改变无反应,解决ecshop清除缓存css样式没反应问题
  3. php文件手机怎么解压,linux 怎么解压文件
  4. opencv 设置视频帧的分辨率“无效”
  5. 她,既是一个风华绝代的演员,更是WiFi之母...
  6. 智慧交通day02-车流量检测实现05:小车匀加速案例
  7. 浅谈Proxmark3 Easy Gui 4.0 5.0 5.1加强版
  8. Hadoop学习笔记一:单节点安装
  9. html倾斜变形,深入理解CSS变形transform(2d)_html/css_WEB-ITnose
  10. xposed+JustTrustMe抓包SSLping
  11. 2021/3/30前端百度笔试题
  12. php 时间和日期,php 日期和时间
  13. linux中tac命令详解,详解Linux中输出文件内容的rev与tac命令使用
  14. 2021年焊工(初级)考试题及焊工(初级)考试报名
  15. PYTHON对接语音验证码接口案列
  16. 李洪强和你一起学习前端之面试题
  17. layui请求加token_琴海森林 JFinal-layui 文档、资料、学习、API,token验证
  18. ERNIE-ViL-理解
  19. 【学习笔记】Android基础知识回顾
  20. three.js 导入显示模型的时候自动计算模型缩放比例

热门文章

  1. Age Estimation
  2. 手机里舍不得删除的48条搞笑短信
  3. 清华大学出版社计算机绘谱,清华大学出版社-图书详情-《土木与建筑类CAD技能一级(二维计算机绘图)AutoCAD培训教程》...
  4. 如何使用Nacos实现配置热更新
  5. 事后诸葛亮-团队总结
  6. 黑色幽默(Black humor)
  7. MPMoviePlayerController 电影播放器—备用
  8. 真实数据揭秘游戏主播能否月入100万
  9. 【Java基础】类的具体细节
  10. Java NIO Selector , SelectionKey , SocketChannel , ServerSocketChannel