AudioManager中setStreamVolume与adjustStreamVolume

来源:互联网 发布:相机数据恢复 编辑:程序博客网 时间:2024/06/03 08:00

今日遇到一个bug, 酷狗音乐扬声器播放歌曲,此时假定音量值为10。
插入耳机,按手机音量键将音量值调为0,拔出耳机,播放音乐,发现扬声器音量也被置为0。

一、亲自验证?

  • 只有当音量值调为0时,耳机与扬声器音量会将另一方置0,其他音量时互不影响
  • 目前QQ音乐、网易云均无此现象

二、查看系统volume日志,惊奇发现:

AudioService: setStreamVolume 3, index = 0, flags = 8 from pid = 23805 callingPackage = com.kugou.androidAudioService: update volume cache, stream:3, device:headphone, index:0, caller:com.kugou.androidAudioService: update volume cache, stream:9, device:headphone, index:0, caller:com.kugou.androidActivityManager: Broadcast: Intent { act=android.media.VOLUME_CHANGED_ACTION flg=0x14000010 (has extras) } ordered=false userid=-1 callerApp=ProcessRecord{3f82fa1 994:system/1000}AudioService: update volume cache, stream:9, device:speaker, index:0, caller:com.kugou.androidActivityManager: Broadcast: Intent { act=android.media.VOLUME_CHANGED_ACTION flg=0x14000010 (has extras) } ordered=false userid=-1 callerApp=ProcessRecord{3f82fa1 994:system/1000}ActivityManager: Broadcast: Intent { act=android.media.VOLUME_CHANGED_ACTION flg=0x14000010 (has extras) } ordered=false userid=-1 callerApp=ProcessRecord{3f82fa1 994:system/1000}AudioService: applyDeviceVolume_syncVSS stream: 3, device: 8, index: 0AudioService: applyDeviceVolume_syncVSS stream: 9, device: 2, index: 0AudioService: sendVolumeUpdate: StreamType = 3, oldIndex = 1, newIndex = 0com.kugou.android D/setVolume: set:0AudioService: applyAllVolumes stream: 3, device: 2, index: 0AudioService: applyAllVolumes stream: 3, device: 4, index: 0AudioService: applyAllVolumes stream: 3, device: 8, index: 0AudioService: applyAllVolumes stream: 3, device: 128, index: 0AudioService: applyAllVolumes stream: 9, device: 2, index: 0AudioService: applyAllVolumes stream: 9, device: 4, index: 7AudioService: applyAllVolumes stream: 9, device: 8, index: 0AudioService: applyAllVolumes stream: 9, device: 128, index: 8AudioService: adjustSuggestedStreamVolume() stream=3, flags=4116, caller=MediaSessionServiceAudioService: adjustStreamVolume() stream =3, dir =0, flags =4112, callingPackage =android, Pid = 994AudioService: sendVolumeUpdate: StreamType = 3, oldIndex = 0, newIndex = 0om.kugou.android D/MediaSessionHelper: dispatched volume adjustment
  • stream: 3 表示音频流音量
  • stream: 9 表示文本识别音(暂无使用)
  • device: 2 表示 DEVICE_OUT_SPEAKER 扬声器
  • device: 4 表示 DEVICE_OUT_WIRED_HEADSET 线控耳机
  • device: 8 表示 DEVICE_OUT_WIRED_HEADPHONE 普通耳机
  • device: 128 表示 DEVICE_OUT_BLUETOOTH_A2DP 蓝牙A2DP输出
    当音量设置为0时,竟然将这几个设备音量均设置为0。

三、对比网易云音乐

1. 日志区别
AudioService: adjustSuggestedStreamVolume() stream=3, flags=4113, caller=MediaSessionServiceAudioService: adjustStreamVolume() stream =3, dir =-1, flags =4113, callingPackage =android, Pid = 980AudioService: update volume cache, stream:3, device:headphone, index:70, caller:MediaSessionService
2. 初步结论

网易云使用的是adjustStreamVolume,酷狗使用的是setStreamVolume.
将代码改为adjustStreamVolume发现解决了问题。
setStreamVolume:直接设置音量大小
adjustStreamVolume :设置direction,以步长调节音量大小

四、根本原因:源码

1. 日志区别
AudioManager的setStreamVolume进入AudioService之后,有这么一段if (!checkSafeMediaVolume(streamTypeAlias, index, device)) { //音量安全检测   mVolumeController.postDisplaySafeVolumeWarning(flags);    mPendingVolumeCommand = new StreamVolumeCommand(                                        streamType, index, flags, device);} else {    onSetStreamVolume(streamType, index, flags, device); //重点    index = mStreamStates[streamType].getIndex(device);}private void onSetStreamVolume(int streamType, int index, int flags, int device) {    setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false);    // setting volume on master stream type also controls silent mode    if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||            (mStreamVolumeAlias[streamType] == getMasterStreamType())) {        int newRingerMode;        if (index == 0) { //如果设置音量为0,设置新的铃声模式:震动、静音、有声            newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE                    : VOLUME_SETS_RINGER_MODE_SILENT ? AudioManager.RINGER_MODE_SILENT                    : AudioManager.RINGER_MODE_NORMAL;        } else {            newRingerMode = AudioManager.RINGER_MODE_NORMAL;        }        setRingerMode(newRingerMode, TAG + ".onSetStreamVolume", false /*external*/);    }}setRingerMode这个里面会调用setRingerModeInt,这个里面会将0-9的StreamType中符合静音的type设置mStreamStates[streamType].mute(null, false),接着handler.mute_syncVSS(state);然后发送消息if (updateVolume) {  sendMsg(mAudioHandler,    MSG_SET_ALL_VOLUMES,    SENDMSG_QUEUE,    0,    0,    VolumeStreamState.this, 0);}接着将一些applyAllVolumes执行jni方法音量置0

还请以后注意这个问题,使用合理的设置音量方式。

正确使用方式为:
如果想把音量设置为0,先用setStreamVolume设置1,再用adjustStreamVolume设置0。

原创粉丝点击