//
Title: 音量调节流程
Code Version: http://aospxref.com/android-14.0.0_r2/
Author: zzmeow
Date📆 : 2024/7, 2024/8
README:Edit with notepad++ & Typora
//
1. 音量按键 调节音量
1.1 音量按键调节音量整体流程图

PhoneWindow::onKeyDown
-> MediaSessionManager::dispatchVolumeKeyEventAsSystemService
->-> dispatchVolumeKeyEventInternal
// 前台app没有处理音量按键事件,交由系统来处理,这里加mediasessionservice锁
-> MediaSessionService::dispatchVolumeKeyEvent
-> handleVolumeKeyEventLocked
-> handleKeyEventLocked
-> dispatchVolumeKeyEventLocked // 判断按键方向,长按短按
-> dispatchAdjustVolumeLocked //在MediaSessionService的handler上执行AudioService::adjustSuggestedStreamVolume
-> AudioManager.adjustSuggestedStreamVolumeForUid
->AudioService::adjustSuggestedStreamVolumeForUid
-> AudioService::adjustSuggestedStreamVolume // 1. 确认实际需要调整的stream type, 2. 屏蔽某些情况下的FLAG_PLAY_SOUND, 3. 调用adjustStreamVolume()
-> notifyExternalVolumeController //确认是否有外部音量控制,比如音箱这种
-> ensureValidStreamType // mVolumeControlStream确认实际需要调整的stream type
-> final int resolvedStream = mStreamVolumeAlias[streamType]; // 获取映射后的流类型
-> adjustStreamVolume
-> 获取流类型别名,volumestreamstate,以及流类型对应的设备 // volumestreamstate中保存的音量值是原来的十倍
-> rescaleStep // 调整步长
-> 对于 flag 的一些处理
-> Handler -> setDeviceVolume
-> applyDeviceVolume_syncVSS
-> setStreamVolumeIndex(index, device) // 总算到了这一步了哇, 后续就是进行 音量等级index 到 分贝 的处理
-> mEngine->getAttributesForStreamType
-> setVolumeIndexForAttributes(attributes, index, device)
-> mEngine->getVolumeGroupForAttributes(attributes) // 从attributes中获取关联的volumeGroup
-> getVolumeCurves(attributes) // 先从attributes获取关联的volumegroup,再从volumegroup获取对应的curves
-> mEngine->getProductStrategyForAttributes(attributes) // 根据attributes获取ProductStrategy
// std::map<audio_devices_t, int> mIndexCur;/**< current volume index per device. */
-> setVolumeCurveIndex(index, device, curves) // 将当前的音量等级设置到volumeCurves的mIndexCur<device,index>成员中去,
-> ...
-> checkAndSetVolume
-> computeVolume
-> volIndexToDb
-> outputDesc->setVolume / setVoiceVolume // 将分贝值写入到输出设备outputDesc中去,如果是通话音量的话voice话,则调用setVoiceVolume直通hal层去调整音量
-> setAudioPortConfig // 如果这个device支持gain硬件方式设置音量,就使用硬件音量调整setAudioPortConfig
-> DbToAmpl // 否则就是软件音量调整设置setStreamVolume
-> mClientInterface->setStreamVolume(stream, volumeAmpl, mIoHandle, delayMs)
-> AudioFlinger::setStreamVolume
-> getVolumeInterface_l(output) // 从mPlaybackThreads集合中拿到一个回播线程实例
-> volumeInterface->setStreamVolume(stream, value) // 设置音量对应功率值到playbackthread中的stream对应的音量值去
-> AudioFlinger::PlaybackThread::setStreamVolume
-> 回播线程按照streamType类型集合保存了音量值,准确说应该是音量值对应的功率值,在播放音频或混音时,回播线程会将音频数据与音量数据相乘,最后将结果传送到Hal去播放
1.2 关键概念
1.2.1 STREAM_VOLUME_ALIAS_XXX
STREAM_VOLUME_ALIAS 是每种流类型音量的别名,用于统一管理某场景下某一类流的音量,比如打开手机的 声音与震动 界面,调整手机的铃声音量 将同步调整 铃声, 系统音, 通知音 的音量:
08-13 19:42:36.075 2182 2677 I vol.Events: writeEvent level_changed STREAM_NOTIFICATION 9 08-13 19:42:36.081 2182 2677 I vol.Events: writeEvent level_changed STREAM_SYSTEM 9 08-13 19:42:36.088 2182 2677 I vol.Events: writeEvent level_changed STREAM_RING 9
08-13 19:42:36.109 2182 2677 I vol.Events: writeEvent level_changed STREAM_NOTIFICATION 10 08-13 19:42:36.114 2182 2677 I vol.Events: writeEvent level_changed STREAM_SYSTEM 10 08-13 19:42:36.116 2182 2677 I vol.Events: writeEvent level_changed STREAM_RING 10
不同场景会有不同的映射关系,
比如TV设备场景,映射完成后STREAM_VOLUME_ALIAS_TELEVISION就只剩下MUSIC流和BT_SCO流这两种:
499 private final int[] STREAM_VOLUME_ALIAS_TELEVISION = new int[] {
500 AudioSystem.STREAM_MUSIC, // STREAM_VOICE_CALL
501 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM
502 AudioSystem.STREAM_MUSIC, // STREAM_RING
503 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
504 AudioSystem.STREAM_MUSIC, // STREAM_ALARM
505 AudioSystem.STREAM_MUSIC, // STREAM_NOTIFICATION
506 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
507 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED
508 AudioSystem.STREAM_MUSIC, // STREAM_DTMF
509 AudioSystem.STREAM_MUSIC, // STREAM_TTS
510 AudioSystem.STREAM_MUSIC, // STREAM_ACCESSIBILITY
511 AudioSystem.STREAM_MUSIC // STREAM_ASSISTANT
512 };
比如通话场景,映射完成后STREAM_VOLUME_ALIAS_VOICE如下:
485 private final int[] STREAM_VOLUME_ALIAS_VOICE = new int[] {
486 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
487 AudioSystem.STREAM_RING, // STREAM_SYSTEM
488 AudioSystem.STREAM_RING, // STREAM_RING
489 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
490 AudioSystem.STREAM_ALARM, // STREAM_ALARM
491 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
492 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
493 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
494 AudioSystem.STREAM_RING, // STREAM_DTMF
495 AudioSystem.STREAM_MUSIC, // STREAM_TTS
496 AudioSystem.STREAM_MUSIC, // STREAM_ACCESSIBILITY
497 AudioSystem.STREAM_MUSIC // STREAM_ASSISTANT
映射关系统一使用mStreamVolumeAlias[ ] 数组来保存。需要使用的时候,可以如下:
mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
1.2.2 VolumeStreamState
1.2.2.1 volumeStreamState概念
AudioService的内部类,用来管理音量状态。以streamtype为单位,每一个streamtype对应一个volumeStreamState.
当需要设置某一种stream的音量时,就会用到对应流的VolumeStreamState中的方法来处理音量。
1.2.2.2 AudioService内部对象关系图(转载于csdn)

1.2.2.3 volumeStreamState初始化
2146 private void createStreamStates() {
// 获取streamtype个数,可以对比一下Android 6 8 11版本这个值的差异
2147 int numStreamTypes = AudioSystem.getNumStreamTypes();
// 连续赋值,streams和mStreamStates都指向数组
// mStreamStates是一个存储VolumeStreamState类型的数组,保存着每个音频流的状态
2148 VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
2149
2150 for (int i = 0; i < numStreamTypes; i++) {
// System.VOLUME_SETTINGS_INT[mStreamVolumeAlias[i]]是为了将StreamType 转换成string类型
2151 streams[i] =
2152 new VolumeStreamState(System.VOLUME_SETTINGS_INT[mStreamVolumeAlias[i]], i);
2153 }
2154
// 对音量进行一些基本check
2155 checkAllFixedVolumeDevices();
2156 checkAllAliasStreamVolumes();
2157 checkMuteAffectedStreams();
// 顾名思义,就是这里会对默认音量进行更新。
2158 updateDefaultVolumes();
2159 }
1.2.2.4 volumeStreamState的内部带参构造
8263 private VolumeStreamState(String settingName, int streamType) {
8264 mVolumeIndexSettingName = settingName;
8265
8266 mStreamType = streamType;
// 在 Audioservice的构造方法中,我们已经获取了每一种流的最大最小值,这里 *10 是为了方便运算
8267 mIndexMin = MIN_STREAM_VOLUME[streamType] * 10;
8268 mIndexMinNoPerm = mIndexMin; // may be overwritten later in updateNoPermMinIndex()
8269 mIndexMax = MAX_STREAM_VOLUME[streamType] * 10;
// 这里的initStreamVolume主要还是调用到APM::initStreamVolume的逻辑, 这一步是为了设置 volumecurve对象的mIndexMin和mIndexMax。
// 这一步基于之前的解析strategy配置文件,得到strategy与volumeGroup数据的连接关系;从streamType获取到attribute,在从attribute获取到volumeGroup,然后就拿到volumeGroup的indexMin和indexMax
// 实质是设置VolumeCurves对象的mIndexMin和mIndexMax成员
8270 final int status = AudioSystem.initStreamVolume(
8271 streamType, mIndexMin / 10, mIndexMax / 10);
..........
8280 readSettings();
..........
1.2.2.5 readSettings()
1.2.2.6 流程小结
大致流程图如下:
VolumeStreamState
-> AudioSystem::initStreamVolume
-> AudioPolicyManager::initStreamVolume
->getVolumeCurves(stream).initVolume
-> EngingBase::getVolumeCurvesForStreamType
-> mProductStrategies.getVolumeGroupForStreamType
…
-> readSettings
1.3 代码分析
1.3.0 前言
Android系统按键的映射过程会经过 ScanCode -> KeyCodeLabel -> KeyCode -> KeyEvent
他们之间的关系是:
ScanCode是由Linux的Input驱动框架定义的整数类型。
ScanCode经过一次转化后,形成按键的标签KeycodeLabel,是一个字符串的表示形式。
KeycodeLabel经过转换后,再次形成整数型的按键码keycode。在Android应用程序层,主要使用按键码keycode来区分。
查看上层映射表kl, 如frameworks/base/data/keyboards/Generic.kl,对应手机目录**/system/usr/keylayout/Generic.kl**
klein:/system/usr/keylayout $ cat Generic.kl | grep -iE "volume"
key 113 VOLUME_MUTE
key 114 VOLUME_DOWN
key 115 VOLUME_UP
klein:/system/usr/keylayout $
以音量 + 为例,代码中的 key 115 与 scanCode 115 一致:
08-14 14:00:32.286 973 1084 D MediaSessionService: dispatchVolumeKeyEvent, pkg=android, opPkg=android, pid=973, uid=1000, asSystem=false, event=KeyEvent { action=ACTION_DOWN, keyCode=KEYCODE_VOLUME_UP, scanCode=115, metaState=0, flags=0x8, repeatCount=0, eventTime=17444709312000, downTime=17444709312000, deviceId=2, source=0x101, displayId=-1 }, stream=-2147483648, musicOnly=true
当底层kernel驱动加载完成后,可以使用adb shell getevent命令查看上报事件:
按下音量 + :
/dev/input/event0: 0001 0073 00000001 /dev/input/event0: 0000 0000 00000000 松开音量 + : /dev/input/event0: 0001 0073 00000000 /dev/input/event0: 0000 0000 00000000
按下音量 - :
/dev/input/event0: 0001 0072 00000001
/dev/input/event0: 0000 0000 00000000
松开音量 - :
/dev/input/event0: 0001 0072 00000000
/dev/input/event0: 0000 0000 00000000
可以看到event0上报事件0x0073 ,对应音量 + 按键, 0x73(h) = 115(d)
在frameworks/base/core/java/android/view/KeyEvent.java中定义的keycode:
151 /** Key code constant: Volume Up key.
152 * Adjusts the speaker volume up. */
153 public static final int KEYCODE_VOLUME_UP = 24;
154 /** Key code constant: Volume Down key.
155 * Adjusts the speaker volume down. */
156 public static final int KEYCODE_VOLUME_DOWN = 25;
也就是说,音量+ 按键最终转换成keycode 24上报。
参考文档:https://blog.csdn.net/weixin_44008788/article/details/118755916
1.3.1 PhoneWindow::onKeyDown
1923 protected boolean onKeyDown(int featureId, int keyCode, KeyEvent event) {
...
1944 switch (keyCode) {
// 处理音量 上 下 mute
1945 case KeyEvent.KEYCODE_VOLUME_UP:
1946 case KeyEvent.KEYCODE_VOLUME_DOWN:
1947 case KeyEvent.KEYCODE_VOLUME_MUTE: {
1948 // If we have a session and no active phone call send it the volume command,
1949 // otherwise use the suggested stream.
1950 if (mMediaController != null && !isActivePhoneCallOngoing()) {
1951 getMediaSessionManager().dispatchVolumeKeyEventToSessionAsSystemService(event,
1952 mMediaController.getSessionToken());
1953 } else {
// 没有mediaController,调用MediaSessionManager::dispatchVolumeKeyEventAsSystemService
1954 getMediaSessionManager().dispatchVolumeKeyEventAsSystemService(event,
1955 mVolumeControlStreamType);
1956 }
1957 return true;
1958 }
1959 // These are all the recognized media key codes in
1960 // KeyEvent.isMediaSessionKey()
//处理其他按键,常用的有PLAY, PAUSE,HEADSETHOOK等, 逻辑同上。
1961 case KeyEvent.KEYCODE_MEDIA_PLAY:
1962 case KeyEvent.KEYCODE_MEDIA_PAUSE:
1963 case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
1964 case KeyEvent.KEYCODE_MUTE:
1965 case KeyEvent.KEYCODE_HEADSETHOOK:
1966 case KeyEvent.KEYCODE_MEDIA_STOP:
1967 case KeyEvent.KEYCODE_MEDIA_NEXT:
1968 case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
1969 case KeyEvent.KEYCODE_MEDIA_REWIND:
1970 case KeyEvent.KEYCODE_MEDIA_RECORD:
1971 case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
1972 if (mMediaController != null) {
1973 if (getMediaSessionManager().dispatchMediaKeyEventToSessionAsSystemService(
1974 event, mMediaController.getSessionToken())) {
1975 return true;
1976 }
1977 }
1978 return false;
1979 }
...
1997
1998 return false;
1999 }
1.3.2 MediaSessionService::dispatchVolumeKeyEvent
dispatchVolumeKeyEventAsSystemService 经过调用到了dispatchVolumeKeyEvent。
1790 public void dispatchVolumeKeyEvent(String packageName, String opPackageName,
1791 boolean asSystemService, KeyEvent keyEvent, int stream, boolean musicOnly) {
...
1811 try {
1812 synchronized (mLock) {
1813 if (isGlobalPriorityActiveLocked()) {
1814 dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
1815 asSystemService, keyEvent, stream, musicOnly);
1816 } else {
1817 // TODO: Consider the case when both volume up and down keys are pressed
1818 // at the same time.
1819 mVolumeKeyEventHandler.handleVolumeKeyEventLocked(packageName, pid, uid,
1820 asSystemService, keyEvent, opPackageName, stream, musicOnly);
1821 }
1822 }
1823 } finally {
1824 Binder.restoreCallingIdentity(token);
1825 }
1826 }
1.3.3 handleKeyEventLocked
handleVolumeKeyEventLocked 经过调用到了 handleKeyEventLocked
2551 void handleKeyEventLocked(String packageName, int pid, int uid,
2552 boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock,
2553 String opPackageName, int stream, boolean musicOnly) {
2554 if (keyEvent.isCanceled()) {
2555 return;
2556 }
2557
2558 int overriddenKeyEvents = 0;
2559 if (mCustomMediaKeyDispatcher != null
2560 && mCustomMediaKeyDispatcher.getOverriddenKeyEvents() != null) {
2561 overriddenKeyEvents = mCustomMediaKeyDispatcher.getOverriddenKeyEvents()
2562 .get(keyEvent.getKeyCode());
2563 }
2564 cancelTrackingIfNeeded(packageName, pid, uid, asSystemService, keyEvent,
2565 needWakeLock, opPackageName, stream, musicOnly, overriddenKeyEvents);
2566 if (!needTracking(keyEvent, overriddenKeyEvents)) {
2567 if (mKeyType == KEY_TYPE_VOLUME) {
2568 dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
2569 asSystemService, keyEvent, stream, musicOnly);
2570 } else {
2571 dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
2572 keyEvent, needWakeLock);
2573 }
2574 return;
2575 }
2576
2577 if (isFirstDownKeyEvent(keyEvent)) {
2578 mTrackingFirstDownKeyEvent = keyEvent;
2579 mIsLongPressing = false;
2580 return;
2581 }
2582
2583 // Long press is always overridden here, otherwise the key event would have been
2584 // already handled
2585 if (isFirstLongPressKeyEvent(keyEvent)) {
2586 mIsLongPressing = true;
2587 }
2588 if (mIsLongPressing) {
2589 handleLongPressLocked(keyEvent, needWakeLock, overriddenKeyEvents);
2590 return;
2591 }
2592
2593 if (keyEvent.getAction() == KeyEvent.ACTION_UP) {
2594 mTrackingFirstDownKeyEvent = null;
2595 if (shouldTrackForMultipleTapsLocked(overriddenKeyEvents)) {
2596 if (mMultiTapCount == 0) {
2597 mMultiTapTimeoutRunnable = createSingleTapRunnable(packageName, pid,
2598 uid, asSystemService, keyEvent, needWakeLock,
2599 opPackageName, stream, musicOnly,
2600 isSingleTapOverridden(overriddenKeyEvents));
2601 if (isSingleTapOverridden(overriddenKeyEvents)
2602 && !isDoubleTapOverridden(overriddenKeyEvents)
2603 && !isTripleTapOverridden(overriddenKeyEvents)) {
2604 mMultiTapTimeoutRunnable.run();
2605 } else {
2606 mHandler.postDelayed(mMultiTapTimeoutRunnable,
2607 MULTI_TAP_TIMEOUT);
2608 mMultiTapCount = 1;
2609 mMultiTapKeyCode = keyEvent.getKeyCode();
2610 }
2611 } else if (mMultiTapCount == 1) {
2612 mHandler.removeCallbacks(mMultiTapTimeoutRunnable);
2613 mMultiTapTimeoutRunnable = createDoubleTapRunnable(packageName, pid,
2614 uid, asSystemService, keyEvent, needWakeLock, opPackageName,
2615 stream, musicOnly, isSingleTapOverridden(overriddenKeyEvents),
2616 isDoubleTapOverridden(overriddenKeyEvents));
2617 if (isTripleTapOverridden(overriddenKeyEvents)) {
2618 mHandler.postDelayed(mMultiTapTimeoutRunnable, MULTI_TAP_TIMEOUT);
2619 mMultiTapCount = 2;
2620 } else {
2621 mMultiTapTimeoutRunnable.run();
2622 }
2623 } else if (mMultiTapCount == 2) {
2624 mHandler.removeCallbacks(mMultiTapTimeoutRunnable);
2625 onTripleTap(keyEvent);
2626 }
2627 } else {
2628 dispatchDownAndUpKeyEventsLocked(packageName, pid, uid, asSystemService,
2629 keyEvent, needWakeLock, opPackageName, stream, musicOnly);
2630 }
2631 }
2632 }
1.3.4 dispatchAdjustVolumeLocked
dispatchDownAndUpKeyEventsLocked 经过调用到了 dispatchAdjustVolumeLocked
2185 private void dispatchAdjustVolumeLocked(String packageName, String opPackageName, int pid,
2186 int uid, boolean asSystemService, int suggestedStream, int direction, int flags,
2187 boolean musicOnly) {
// 获取mediasession, 优先选择全局优先的mediasession对象, 否则在当前用户记录的mediasession栈中获取默认的与音量调节相关的session
2188 MediaSessionRecordImpl session = isGlobalPriorityActiveLocked() ? mGlobalPrioritySession
2189 : mCurrentFullUserRecord.mPriorityStack.getDefaultVolumeSession();
2190
2191 boolean preferSuggestedStream = false;
2192 if (isValidLocalStreamType(suggestedStream)
2193 && AudioSystem.isStreamActive(suggestedStream, 0)) {
2194 preferSuggestedStream = true;
2195 }
2196 if (session == null || preferSuggestedStream) {
2197 if (DEBUG_KEY_EVENT) {
2198 Log.d(TAG, "Adjusting suggestedStream=" + suggestedStream + " by " + direction
2199 + ". flags=" + flags + ", preferSuggestedStream="
2200 + preferSuggestedStream + ", session=" + session);
2201 }
2202 if (musicOnly && !AudioSystem.isStreamActive(AudioManager.STREAM_MUSIC, 0)) {
2203 if (DEBUG_KEY_EVENT) {
2204 Log.d(TAG, "Nothing is playing on the music stream. Skipping volume event,"
2205 + " flags=" + flags);
2206 }
2207 return;
2208 }
2209
2210 // Execute mAudioService.adjustSuggestedStreamVolume() on
2211 // handler thread of MediaSessionService.
2212 // This will release the MediaSessionService.mLock sooner and avoid
2213 // a potential deadlock between MediaSessionService.mLock and
2214 // ActivityManagerService lock.
// 在MediaSessionService的Handler线程上执行AudioService::adjustSuggestedStreamVolume
2215 mHandler.post(new Runnable() {
2216 @Override
2217 public void run() {
2218 final String callingOpPackageName;
2219 final int callingUid;
2220 final int callingPid;
2221 if (asSystemService) {
2222 callingOpPackageName = mContext.getOpPackageName();
2223 callingUid = Process.myUid();
2224 callingPid = Process.myPid();
2225 } else {
2226 callingOpPackageName = opPackageName;
2227 callingUid = uid;
2228 callingPid = pid;
2229 }
2230 try {
2231 mAudioManager.adjustSuggestedStreamVolumeForUid(suggestedStream,
2232 direction, flags, callingOpPackageName, callingUid, callingPid,
2233 getContext().getApplicationInfo().targetSdkVersion);
2234 } catch (SecurityException | IllegalArgumentException e) {
2235 Log.e(TAG, "Cannot adjust volume: direction=" + direction
2236 + ", suggestedStream=" + suggestedStream + ", flags=" + flags
2237 + ", packageName=" + packageName + ", uid=" + uid
2238 + ", asSystemService=" + asSystemService, e);
2239 }
2240 }
2241 });
2242 } else {
// session不为空,将按键事件转发给mediasession::adjustVolume
2243 if (DEBUG_KEY_EVENT) {
2244 Log.d(TAG, "Adjusting " + session + " by " + direction + ". flags="
2245 + flags + ", suggestedStream=" + suggestedStream
2246 + ", preferSuggestedStream=" + preferSuggestedStream);
2247 }
2248 session.adjustVolume(packageName, opPackageName, pid, uid, asSystemService,
2249 direction, flags, true);
2250 }
2251 }
1.3.5 adjustStreamVolume(重点)
3366 protected void adjustStreamVolume(int streamType, int direction, int flags,
3367 String callingPackage, String caller, int uid, int pid, String attributionTag,
3368 boolean hasModifyAudioSettings, int keyEventMode) {
// 使用指定音量,return
3369 if (mUseFixedVolume) {
3370 return;
3371 }
3372 if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream=" + streamType + ", dir=" + direction
3373 + ", flags=" + flags + ", caller=" + caller);
3374
// 保证 Direction 和 StreamType 没有问题
3375 ensureValidDirection(direction);
3376 ensureValidStreamType(streamType);
3377
// 判断按键是不是mute相关
3378 boolean isMuteAdjust = isMuteAdjust(direction);
3379
3380 if (isMuteAdjust && !isStreamAffectedByMute(streamType)) {
3381 return;
3382 }
3383
3384 // If adjust is mute and the stream is STREAM_VOICE_CALL or STREAM_BLUETOOTH_SCO, make sure
3385 // that the calling app have the MODIFY_PHONE_STATE permission.
// 打电话时如果要Mute,需要判断app是否有MODIFY_PHONE_STATE权限
3386 if (isMuteAdjust &&
3387 (streamType == AudioSystem.STREAM_VOICE_CALL ||
3388 streamType == AudioSystem.STREAM_BLUETOOTH_SCO) &&
3389 mContext.checkPermission(android.Manifest.permission.MODIFY_PHONE_STATE, pid, uid)
3390 != PackageManager.PERMISSION_GRANTED) {
3391 Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: adjustStreamVolume from pid="
3392 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
3393 return;
3394 }
3395
3396 // If the stream is STREAM_ASSISTANT,
3397 // make sure that the calling app have the MODIFY_AUDIO_ROUTING permission.
3398 if (streamType == AudioSystem.STREAM_ASSISTANT &&
3399 mContext.checkPermission(
3400 android.Manifest.permission.MODIFY_AUDIO_ROUTING, pid, uid)
3401 != PackageManager.PERMISSION_GRANTED) {
3402 Log.w(TAG, "MODIFY_AUDIO_ROUTING Permission Denial: adjustStreamVolume from pid="
3403 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
3404 return;
3405 }
3406
3407 // use stream type alias here so that streams with same alias have the same behavior,
3408 // including with regard to silent mode control (e.g the use of STREAM_RING below and in
3409 // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
// 使用流类型别名,从而让具有相同别名的流具有相同的行为
3410 int streamTypeAlias = mStreamVolumeAlias[streamType];
3411
// 获取当前streamType对应的 VolumeStreamState 对象
// mStreamStates 指向 VolumeStreamState类型的数组,
3412 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
3413
// 获取当前streamType对应的output device
3414 final int device = getDeviceForStream(streamTypeAlias);
3415
// 获取当前streamType 对应的 output device 对应的 音量等级 aliasIndex
3416 int aliasIndex = streamState.getIndex(device);
3417 boolean adjustVolume = true;
3418 int step;
3419
3420 // skip a2dp absolute volume control request when the device
3421 // is neither an a2dp device nor BLE device
// 当此次音量控制是a2dp绝对音量控制,但是又没有a2dp / ble 设备连接时,return
3422 if ((!AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
3423 && !AudioSystem.DEVICE_OUT_ALL_BLE_SET.contains(device))
3424 && (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
3425 return;
3426 }
3427
3428 // If we are being called by the system (e.g. hardware keys) check for current user
3429 // so we handle user restrictions correctly.
3430 if (uid == android.os.Process.SYSTEM_UID) {
3431 uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid));
3432 }
3433 // validate calling package and app op
3434 if (!checkNoteAppOp(
3435 STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage, attributionTag)) {
3436 return;
3437 }
3438
3439 mSoundDoseHelper.invalidatPendingVolumeCommand();
3440
// 去掉 固定音量 的flag
3441 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
// 开始计算调节音量的step步长
3442 if (streamTypeAlias == AudioSystem.STREAM_MUSIC && isFixedVolumeDevice(device)) {
3443 flags |= AudioManager.FLAG_FIXED_VOLUME;
3444
3445 // Always toggle between max safe volume and 0 for fixed volume devices where safe
3446 // volume is enforced, and max and 0 for the others.
3447 // This is simulated by stepping by the full allowed volume range
// 对于强制执行安全音量的固定音量设备,音量始终在最大安全音量和0之间切换,
// 否则,就在最大音量和0之间切换
3448 step = mSoundDoseHelper.getSafeMediaVolumeIndex(device);
3449 if (step < 0) {
3450 step = streamState.getMaxIndex();
3451 }
3452 if (aliasIndex != 0) {
3453 aliasIndex = step;
3454 }
3455 } else {
3456 // convert one UI step (+/-1) into a number of internal units on the stream alias
// 将音量值的变化从 原来的流类型 变换到 别名流类型,理由是因为每种流的取值范围不一样,所以需要调整rescale。
3457 step = rescaleStep(10, streamType, streamTypeAlias);
3458 }
3459
3460 // If either the client forces allowing ringer modes for this adjustment,
3461 // or stream is used for UI sonification
// 这边就是对flag的一些处理
3462 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
3463 (isUiSoundsStreamType(streamTypeAlias))) {
3464 int ringerMode = getRingerModeInternal();
3465 // do not vibrate if already in vibrate mode
3466 if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
3467 flags &= ~AudioManager.FLAG_VIBRATE;
3468 }
3469 // Check if the ringer mode handles this adjustment. If it does we don't
3470 // need to adjust the volume further.
3471 final int result = checkForRingerModeChange(aliasIndex, direction, step,
3472 streamState.mIsMuted, callingPackage, flags);
3473 adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
3474 // If suppressing a volume adjustment in silent mode, display the UI hint
3475 if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
3476 flags |= AudioManager.FLAG_SHOW_SILENT_HINT;
3477 }
3478 // If suppressing a volume down adjustment in vibrate mode, display the UI hint
3479 if ((result & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0) {
3480 flags |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
3481 }
3482 } else if (isStreamMutedByRingerOrZenMode(streamTypeAlias) && streamState.mIsMuted) {
3483 // if the stream is currently muted streams by ringer/zen mode
3484 // then it cannot be unmuted (without FLAG_ALLOW_RINGER_MODES) with an unmute or raise
3485 if (direction == AudioManager.ADJUST_TOGGLE_MUTE
3486 || direction == AudioManager.ADJUST_UNMUTE
3487 || direction == AudioManager.ADJUST_RAISE) {
3488 adjustVolume = false;
3489 }
3490 }
3491
3492 // If the ringer mode or zen is muting the stream, do not change stream unless
3493 // it'll cause us to exit dnd
3494 if (!volumeAdjustmentAllowedByDnd(streamTypeAlias, flags)) {
3495 adjustVolume = false;
3496 }
3497 int oldIndex = mStreamStates[streamType].getIndex(device);
3498
3499 // Check if the volume adjustment should be handled by an absolute volume controller instead
// absolute volume controller暂时还没接触过,先不看
3500 if (isAbsoluteVolumeDevice(device)
3501 && (flags & AudioManager.FLAG_ABSOLUTE_VOLUME) == 0) {
3502 AbsoluteVolumeDeviceInfo info = mAbsoluteVolumeDeviceInfoMap.get(device);
3503 if (info.mHandlesVolumeAdjustment) {
3504 dispatchAbsoluteVolumeAdjusted(streamType, info, oldIndex, direction,
3505 keyEventMode);
3506 return;
3507 }
3508 }
3509
// direction != AudioManager.ADJUST_SAME 意思就是音量要发生变化,具体怎么变化看方向
// ADJUST_RAISE = 1 ADJUST_SAME = 0 ADJUST_LOWER = -1
3510 if (adjustVolume && (direction != AudioManager.ADJUST_SAME)
3511 && (keyEventMode != AudioDeviceVolumeManager.ADJUST_MODE_END)) {
3512 mAudioHandler.removeMessages(MSG_UNMUTE_STREAM);
3513
3514 if (isMuteAdjust && !mFullVolumeDevices.contains(device)) {
3515 boolean state;
3516 if (direction == AudioManager.ADJUST_TOGGLE_MUTE) {
3517 state = !streamState.mIsMuted;
3518 } else {
3519 state = direction == AudioManager.ADJUST_MUTE;
3520 }
3521 muteAliasStreams(streamTypeAlias, state);
// 如果不是mute操作,先判断下是不是和safevolume,fullvolume相关
3522 } else if ((direction == AudioManager.ADJUST_RAISE)
3523 && mSoundDoseHelper.raiseVolumeDisplaySafeMediaVolume(streamTypeAlias,
3524 aliasIndex + step, device, flags)) {
3525 Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex);
3526 } else if (!isFullVolumeDevice(device)
3527 && (streamState.adjustIndex(direction * step, device, caller,
3528 hasModifyAudioSettings)
3529 || streamState.mIsMuted)) {
3530 // Post message to set system volume (it in turn will post a
3531 // message to persist).
3532 if (streamState.mIsMuted) {
3533 // Unmute the stream if it was previously muted
3534 if (direction == AudioManager.ADJUST_RAISE) {
3535 // unmute immediately for volume up
3536 muteAliasStreams(streamTypeAlias, false);
3537 } else if (direction == AudioManager.ADJUST_LOWER) {
3538 if (mIsSingleVolume) {
3539 sendMsg(mAudioHandler, MSG_UNMUTE_STREAM, SENDMSG_QUEUE,
3540 streamTypeAlias, flags, null, UNMUTE_STREAM_DELAY);
3541 }
3542 }
3543 }
// 这边最终调用到方法是 setStreamVolumeIndex(index, device)
3544 sendMsg(mAudioHandler,
3545 MSG_SET_DEVICE_VOLUME,
3546 SENDMSG_QUEUE,
3547 device,
3548 0,
3549 streamState,
3550 0);
3551 }
3552
3553 int newIndex = mStreamStates[streamType].getIndex(device);
3554
3555 // Check if volume update should be send to AVRCP
3556 if (streamTypeAlias == AudioSystem.STREAM_MUSIC
3557 && AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
3558 && (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
3559 if (DEBUG_VOL) {
3560 Log.d(TAG, "adjustSreamVolume: postSetAvrcpAbsoluteVolumeIndex index="
3561 + newIndex + "stream=" + streamType);
3562 }
3563 mDeviceBroker.postSetAvrcpAbsoluteVolumeIndex(newIndex / 10);
3564 } else if (isAbsoluteVolumeDevice(device)
3565 && (flags & AudioManager.FLAG_ABSOLUTE_VOLUME) == 0) {
3566 AbsoluteVolumeDeviceInfo info = mAbsoluteVolumeDeviceInfoMap.get(device);
3567 dispatchAbsoluteVolumeChanged(streamType, info, newIndex);
3568 }
3569
3570 if (AudioSystem.isLeAudioDeviceType(device)
3571 && streamType == getBluetoothContextualVolumeStream()
3572 && (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
3573 if (DEBUG_VOL) {
3574 Log.d(TAG, "adjustSreamVolume postSetLeAudioVolumeIndex index="
3575 + newIndex + " stream=" + streamType);
3576 }
3577 mDeviceBroker.postSetLeAudioVolumeIndex(newIndex,
3578 mStreamStates[streamType].getMaxIndex(), streamType);
3579 }
3580
3581 // Check if volume update should be send to Hearing Aid
3582 if (device == AudioSystem.DEVICE_OUT_HEARING_AID) {
3583 // only modify the hearing aid attenuation when the stream to modify matches
3584 // the one expected by the hearing aid
3585 if (streamType == getBluetoothContextualVolumeStream()) {
3586 if (DEBUG_VOL) {
3587 Log.d(TAG, "adjustSreamVolume postSetHearingAidVolumeIndex index="
3588 + newIndex + " stream=" + streamType);
3589 }
3590 mDeviceBroker.postSetHearingAidVolumeIndex(newIndex, streamType);
3591 }
3592 }
3593 }
3594
3595 final int newIndex = mStreamStates[streamType].getIndex(device);
3596
3597 if (adjustVolume) {
3598 synchronized (mHdmiClientLock) {
3599 if (mHdmiManager != null) {
3600 // At most one of mHdmiPlaybackClient and mHdmiTvClient should be non-null
3601 HdmiClient fullVolumeHdmiClient = mHdmiPlaybackClient;
3602 if (mHdmiTvClient != null) {
3603 fullVolumeHdmiClient = mHdmiTvClient;
3604 }
3605
3606 if (fullVolumeHdmiClient != null
3607 && mHdmiCecVolumeControlEnabled
3608 && streamTypeAlias == AudioSystem.STREAM_MUSIC
3609 // vol change on a full volume device
3610 && isFullVolumeDevice(device)) {
3611 int keyCode = KeyEvent.KEYCODE_UNKNOWN;
3612 switch (direction) {
3613 case AudioManager.ADJUST_RAISE:
3614 keyCode = KeyEvent.KEYCODE_VOLUME_UP;
3615 break;
3616 case AudioManager.ADJUST_LOWER:
3617 keyCode = KeyEvent.KEYCODE_VOLUME_DOWN;
3618 break;
3619 case AudioManager.ADJUST_TOGGLE_MUTE:
3620 case AudioManager.ADJUST_MUTE:
3621 case AudioManager.ADJUST_UNMUTE:
3622 // Many CEC devices only support toggle mute. Therefore, we send the
3623 // same keycode for all three mute options.
3624 keyCode = KeyEvent.KEYCODE_VOLUME_MUTE;
3625 break;
3626 default:
3627 break;
3628 }
3629 if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
3630 final long ident = Binder.clearCallingIdentity();
3631 try {
3632 switch (keyEventMode) {
3633 case AudioDeviceVolumeManager.ADJUST_MODE_NORMAL:
3634 fullVolumeHdmiClient.sendVolumeKeyEvent(keyCode, true);
3635 fullVolumeHdmiClient.sendVolumeKeyEvent(keyCode, false);
3636 break;
3637 case AudioDeviceVolumeManager.ADJUST_MODE_START:
3638 fullVolumeHdmiClient.sendVolumeKeyEvent(keyCode, true);
3639 break;
3640 case AudioDeviceVolumeManager.ADJUST_MODE_END:
3641 fullVolumeHdmiClient.sendVolumeKeyEvent(keyCode, false);
3642 break;
3643 default:
3644 Log.e(TAG, "Invalid keyEventMode " + keyEventMode);
3645 }
3646 } finally {
3647 Binder.restoreCallingIdentity(ident);
3648 }
3649 }
3650 }
3651
3652 if (streamTypeAlias == AudioSystem.STREAM_MUSIC
3653 && (oldIndex != newIndex || isMuteAdjust)) {
3654 maybeSendSystemAudioStatusCommand(isMuteAdjust);
3655 }
3656 }
3657 }
3658 }
// 更新ui,发送音量改变的广播
3659 sendVolumeUpdate(streamType, oldIndex, newIndex, flags, device);
3660 }
1.3.6 setStreamVolumeIndex(index, device)
经过一套java - jni - nawtive调用:
AudioSystem.java -> AudioSystem.cpp -> AudioPolicyManager.cpp -> AudioPOlicyService -> AudioPolicyManager.cpp
现在走到了
APM::setStreamVolumeIndex(stream, inde, device):
2675 status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream,
2676 int index,
2677 audio_devices_t device)
2678 {
// 将stream转换到对应的属性attributes, 具体的流程需要熟悉 解析strategy配置文件 。 这个暂时还没看。
2679 auto attributes = mEngine->getAttributesForStreamType(stream);
2680 if (attributes == AUDIO_ATTRIBUTES_INITIALIZER) {
2681 ALOGW("%s: no group for stream %s, bailing out", __func__, toString(stream).c_str());
2682 return NO_ERROR;
2683 }
2684 ALOGV("%s: stream %s attributes=%s", __func__,
2685 toString(stream).c_str(), toString(attributes).c_str());
2686 return setVolumeIndexForAttributes(attributes, index, device);
2687 }
- ps:截取一段 音量调节 走到这个节点,apm这边的log:
07-31 10:15:54.313 940 32611 V APM_AudioPolicyManager: setStreamVolumeIndex: stream AUDIO_STREAM_MUSIC attributes={ Content type: AUDIO_CONTENT_TYPE_UNKNOWN Usage: AUDIO_USAGE_MEDIA Source: AUDIO_SOURCE_DEFAULT Flags: 0x0 Tags: }
07-31 10:15:54.313 940 32611 V APM_AudioPolicyManager: setVolumeIndexForAttributes: group 6 matching with { Content type: AUDIO_CONTENT_TYPE_UNKNOWN Usage: AUDIO_USAGE_MEDIA Source: AUDIO_SOURCE_DEFAULT Flags: 0x0 Tags: }
07-31 10:15:54.313 940 32611 V APM_AudioPolicyManager: setVolumeCurveIndex device 00000002, index 6
07-31 10:15:54.314 940 32611 D APM::AudioPolicyEngine: getDevices ForStrategy() strategy 0, device 0x2 avadevice 0x1, 0x2, 0x10000 sfu [0]:0, [1]:0, [4]:11
07-31 10:15:54.316 940 940 V APM_AudioPolicyManager: setStreamVolumeIndex: stream AUDIO_STREAM_ACCESSIBILITY attributes={ Content type: AUDIO_CONTENT_TYPE_UNKNOWN Usage: AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY Source: AUDIO_SOURCE_DEFAULT Flags: 0x0 Tags: }
07-31 10:15:54.316 940 940 V APM_AudioPolicyManager: setVolumeIndexForAttributes: group 1 matching with { Content type: AUDIO_CONTENT_TYPE_UNKNOWN Usage: AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY Source: AUDIO_SOURCE_DEFAULT Flags: 0x0 Tags: }
07-31 10:15:54.316 940 940 V APM_AudioPolicyManager: setVolumeCurveIndex device 00000002, index 7
07-31 10:15:54.320 940 32611 V APM_AudioPolicyManager: setStreamVolumeIndex: stream AUDIO_STREAM_TTS attributes={ Content type: AUDIO_CONTENT_TYPE_UNKNOWN Usage: AUDIO_USAGE_UNKNOWN Source: AUDIO_SOURCE_DEFAULT Flags: 0x8 Tags: }
07-31 10:15:54.320 940 32611 V APM_AudioPolicyManager: setVolumeIndexForAttributes: group 12 matching with { Content type: AUDIO_CONTENT_TYPE_UNKNOWN Usage: AUDIO_USAGE_UNKNOWN Source: AUDIO_SOURCE_DEFAULT Flags: 0x8 Tags: }
07-31 10:15:54.320 940 32611 V APM_AudioPolicyManager: setVolumeCurveIndex device 00000002, index 6
1.3.7 setVolumeIndexForAttributes(attributes, index, device)
2703 status_t AudioPolicyManager::setVolumeIndexForAttributes(const audio_attributes_t &attributes,
2704 int index,
2705 audio_devices_t device)
2706 {
2707 // Get Volume group matching the Audio Attributes
// 根据attributes获取volumeGroup
2708 auto group = mEngine->getVolumeGroupForAttributes(attributes);
2709 if (group == VOLUME_GROUP_NONE) {
2710 ALOGD("%s: no group matching with %s", __FUNCTION__, toString(attributes).c_str());
2711 return BAD_VALUE;
2712 }
2713 ALOGV("%s: group %d matching with %s", __FUNCTION__, group, toString(attributes).c_str());
2714 status_t status = NO_ERROR;
2715 IVolumeCurves &curves = getVolumeCurves(attributes);
2716 VolumeSource vs = toVolumeSource(group);
// 根据attributes获取productStrategy
2717 product_strategy_t strategy = mEngine->getProductStrategyForAttributes(attributes);
2718
// 将当前的音量等级设置到volumeCurves的mIndexCur<device,index>成员中去,
2719 status = setVolumeCurveIndex(index, device, curves);
2720 if (status != NO_ERROR) {
2721 ALOGE("%s failed to set curve index for group %d device 0x%X", __func__, group, device);
2722 return status;
2723 }
2724
2725 DeviceTypeSet curSrcDevices;
// 绕一圈又去拿到attributes,
2726 auto curCurvAttrs = curves.getAttributes();
2727 if (!curCurvAttrs.empty() && curCurvAttrs.front() != defaultAttr) {
2728 auto attr = curCurvAttrs.front();
// 经典函数,获取attr适合的devices
2729 curSrcDevices = mEngine->getOutputDevicesForAttributes(attr, nullptr, false).types();
2730 } else if (!curves.getStreamTypes().empty()) {
2731 auto stream = curves.getStreamTypes().front();
2732 curSrcDevices = mEngine->getOutputDevicesForStream(stream, false).types();
2733 } else {
2734 ALOGE("%s: Invalid src %d: no valid attributes nor stream",__func__, vs);
2735 return BAD_VALUE;
2736 }
// curSrcDevices 多个设备的情况下,选择一个设备 curSrcDevice
2737 audio_devices_t curSrcDevice = Volume::getDeviceForVolume(curSrcDevices);
2738 resetDeviceTypes(curSrcDevices, curSrcDevice);
2739
2740 // update volume on all outputs and streams matching the following:
2741 // - The requested stream (or a stream matching for volume control) is active on the output
2742 // - The device (or devices) selected by the engine for this stream includes
2743 // the requested device
2744 // - For non default requested device, currently selected device on the output is either the
2745 // requested device or one of the devices selected by the engine for this stream
2746 // - For default requested device (AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME), apply volume only if
2747 // no specific device volume value exists for currently selected device.
// 遍历每一个output
2748 for (size_t i = 0; i < mOutputs.size(); i++) {
2749 sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
2750 DeviceTypeSet curDevices = desc->devices().types();
2751
2752 if (curDevices.erase(AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
2753 curDevices.insert(AUDIO_DEVICE_OUT_SPEAKER);
2754 }
2755 if (!(desc->isActive(vs) || isInCall())) {
2756 continue;
2757 }
2758 if (device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME &&
2759 curDevices.find(device) == curDevices.end()) {
2760 continue;
2761 }
2762 bool applyVolume = false;
2763 if (device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) {
2764 curSrcDevices.insert(device);
2765 applyVolume = (curSrcDevices.find(
2766 Volume::getDeviceForVolume(curDevices)) != curSrcDevices.end());
2767 } else {
2768 applyVolume = !curves.hasVolumeIndexForDevice(curSrcDevice);
2769 }
2770 if (!applyVolume) {
2771 continue; // next output
2772 }
2773 // Inter / intra volume group priority management: Loop on strategies arranged by priority
2774 // If a higher priority strategy is active, and the output is routed to a device with a
2775 // HW Gain management, do not change the volume
2776 if (desc->useHwGain()) {
2777 applyVolume = false;
2778 for (const auto &productStrategy : mEngine->getOrderedProductStrategies()) {
2779 auto activeClients = desc->clientsList(true /*activeOnly*/, productStrategy,
2780 false /*preferredDevice*/);
2781 if (activeClients.empty()) {
2782 continue;
2783 }
2784 bool isPreempted = false;
2785 bool isHigherPriority = productStrategy < strategy;
2786 for (const auto &client : activeClients) {
2787 if (isHigherPriority && (client->volumeSource() != vs)) {
2788 ALOGV("%s: Strategy=%d (\nrequester:\n"
2789 " group %d, volumeGroup=%d attributes=%s)\n"
2790 " higher priority source active:\n"
2791 " volumeGroup=%d attributes=%s) \n"
2792 " on output %zu, bailing out", __func__, productStrategy,
2793 group, group, toString(attributes).c_str(),
2794 client->volumeSource(), toString(client->attributes()).c_str(), i);
2795 applyVolume = false;
2796 isPreempted = true;
2797 break;
2798 }
2799 // However, continue for loop to ensure no higher prio clients running on output
2800 if (client->volumeSource() == vs) {
2801 applyVolume = true;
2802 }
2803 }
2804 if (isPreempted || applyVolume) {
2805 break;
2806 }
2807 }
2808 if (!applyVolume) {
2809 continue; // next output
2810 }
2811 }
2812 //FIXME: workaround for truncated touch sounds
2813 // delayed volume change for system stream to be removed when the problem is
2814 // handled by system UI
2815 status_t volStatus = checkAndSetVolume(
2816 curves, vs, index, desc, curDevices,
2817 ((vs == toVolumeSource(AUDIO_STREAM_SYSTEM))?
2818 TOUCH_SOUND_FIXED_DELAY_MS : 0));
2819 if (volStatus != NO_ERROR) {
2820 status = volStatus;
2821 }
2822 }
2823 mpClientInterface->onAudioVolumeGroupChanged(group, 0 /*flags*/);
2824 return status;
2825 }
1.4 过程总结
- 音量键处理流程的发起者是PhoneWindow。
- AudioManager仅仅起到代理的作用。
- AudioService接收AudioManager的调用请求,操作VolumeStreamState的实例进行音量的设置。
- VolumeStreamState负责保存音量设置,并且提供了将音量设置到底层的方法。
- AudioService负责将设置结果以广播的形式通知外界。
2. 滑动音量条 调节音量
2.1 主界面滑动调整音量 代码分析
2.2 设置界面滑动调整音量 代码分析
2.2.1 VolumeSeekBarPreference
每一个 VolumeSeekBarPreference 要跟 一个 SeekBar 绑定,
每一个 SeekBar 对应一个 stream,
滑动SeekBar时会设置该stream 以及对应的 alias stream的音量。
/packages/apps/Settings/res/xml/sound_settings.xml:
75 <!-- Notification volume -->
76 <com.android.settings.notification.VolumeSeekBarPreference
77 android:key="notification_volume"
78 android:icon="@drawable/ic_notifications"
79 android:title="@string/notification_volume_option_title"
80 android:order="-150"
81 settings:controller="com.android.settings.notification.NotificationVolumePreferenceController"
82 settings:unavailableSliceSubtitle="@string/notification_volume_disabled_summary"/>
123 public void onBindViewHolder(PreferenceViewHolder view) {
124 super.onBindViewHolder(view);
125 mSeekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar);
126 mIconView = (ImageView) view.findViewById(com.android.internal.R.id.icon);
127 mSuppressionTextView = (TextView) view.findViewById(R.id.suppression_text);
128 mTitle = (TextView) view.findViewById(com.android.internal.R.id.title);
129 init();
130 }
2.2.2 init
132 protected void init() {
133 if (mSeekBar == null) return;
134 final SeekBarVolumizer.Callback sbvc = new SeekBarVolumizer.Callback() {
135 @Override
136 public void onSampleStarting(SeekBarVolumizer sbv) {
137 if (mCallback != null) {
138 mCallback.onSampleStarting(sbv);
139 }
140 }
// 重写回调方法,进度条改变时被调用
141 @Override
142 public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
143 if (mCallback != null) {
144 mCallback.onStreamValueChanged(mStream, progress);
145 }
146 }
147 @Override
148 public void onMuted(boolean muted, boolean zenMuted) {
149 if (mMuted == muted && mZenMuted == zenMuted) return;
150 mMuted = muted;
151 mZenMuted = zenMuted;
152 updateIconView();
153 if (mListener != null) {
154 mListener.onUpdateMuteState();
155 }
156 }
// 重写回调方法,用户开始触摸时调用
157 @Override
158 public void onStartTrackingTouch(SeekBarVolumizer sbv) {
159 if (mCallback != null) {
160 mCallback.onStartTrackingTouch(sbv);
161 }
162 mJankMonitor.begin(InteractionJankMonitor.Configuration.Builder
163 .withView(CUJ_SETTINGS_SLIDER, mSeekBar)
164 .setTag(getKey()));
165 }
// 重写回调方法,用户停止触摸时调用
166 @Override
167 public void onStopTrackingTouch(SeekBarVolumizer sbv) {
168 mJankMonitor.end(CUJ_SETTINGS_SLIDER);
169 }
170 };
171 final Uri sampleUri = mStream == AudioManager.STREAM_MUSIC ? getMediaVolumeUri() : null;
172 if (mVolumizer == null) {
173 mVolumizer = new SeekBarVolumizer(getContext(), mStream, sampleUri, sbvc);
174 }
175 mVolumizer.start();
176 mVolumizer.setSeekBar(mSeekBar);
177 updateIconView();
178 updateSuppressionText();
179 if (mListener != null) {
180 mListener.onUpdateMuteState();
181 }
182 if (!isEnabled()) {
183 mSeekBar.setEnabled(false);
184 mVolumizer.stop();
185 }
186 }
当音量条被滑动时,经过一系列的监听回调逻辑,后面会调用到SeekBarVolumizer类的onProgressChanged( ) 方法,
2.2.3 onProgressChanged
472 public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
473 if (fromTouch) {
// 最根本的方法还是postSetVolume
474 postSetVolume(progress);
475 }
476 if (mCallback != null) {
477 mCallback.onProgressChanged(seekBar, progress, fromTouch);
478 }
479 }
2.2.4 postSetVolume
481 private void postSetVolume(int progress) {
482 if (mHandler == null) return;
483 // Do the volume changing separately to give responsive UI
484 mLastProgress = progress;
// 移除 Handler 中可能存在的旧的与音量设置相关的消息。这可以防止多次触发相同的操作,确保只处理最新的请求
485 mHandler.removeMessages(MSG_SET_STREAM_VOLUME);
486 mHandler.removeMessages(MSG_START_SAMPLE);
487 mHandler.removeMessages(MSG_UPDATE_SLIDER_MAYBE_LATER);
488 mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SET_STREAM_VOLUME),
489 isDelay() ? SET_STREAM_VOLUME_DELAY_MS : 0);
490 }
2.2.5 MSG_SET_STREAM_VOLUME
309 public boolean handleMessage(Message msg) {
310 switch (msg.what) {
311 case MSG_SET_STREAM_VOLUME:
312 if (mMuted && mLastProgress > 0) {
313 mAudioManager.adjustStreamVolume(mStreamType, AudioManager.ADJUST_UNMUTE, 0);
314 } else if (!mMuted && mLastProgress == 0) {
315 mAudioManager.adjustStreamVolume(mStreamType, AudioManager.ADJUST_MUTE, 0);
316 }
// 非Mute或者解mute操作,就正常调用AudioManager::setStreamVolume,
// 后续就是AudioService::setStreamVolume. 流程同前文分析
317 mAudioManager.setStreamVolume(mStreamType, mLastProgress,
318 AudioManager.FLAG_SHOW_UI_WARNINGS);
319 break;
......
3. 蓝牙耳机 调节音量(待补充)
4. 音量问题常见Log
4.1 按键音量相关
mediasessionservice, dispatchVolumeKeyEvent, MiuiInputKeyEventLog, KeyCode, KeyEvent, scanCode, adjustSuggestedStreamVolume, adjustStreamVolume, setstreamvolumeIndex,setVolumeCurveIndex, checkAndSetVolume
4.2 滑动音量相关
setstreamvolume,setstreamvolumeIndex,setVolumeCurveIndex, checkAndSetVolume
4.3 音量条相关
volumeDialog, volumePanel
4.4 音量事件
vol.event
4.5 shell命令
getevent, dumpsys media.audio_flinger, dumpsys media.audio_policy
4.6 绝对音量
abloluteVolume, avrcpSupportsAbsoluteVolume, setAvrcpAbsoluteVolumeSupported
1118

被折叠的 条评论
为什么被折叠?



