Android audio ---- 音量调节流程

//
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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值