章节2-1中TV设备接收到< System Audio Mode Status> 消息后会调用setSystemAudioMode方法设置音频模式
setSystemAudioMode方法中调用了
mService.setSystemAudioActivated(on)方法这个方法用于激活或停用系统音频模式。当on
参数为true
时,它会将音频输出切换到通过HDMI输出或者其它外部音频设备。当on
为false
时,它会将音频输出切换回设备的内置扬声器
mService.announceSystemAudioModeChange(on)方法,这个方法用于通知系统音频模式发生了变化。当on
参数为true
时,它会通知系统音频模式已经切换到外部设备。当on
为false
时,它会通知系统音频模式已经切换回设备内置扬声器
startArcAction(true)方法,开始激活ARC功能的动作(这个方法在如何判断是否已激活ARC功能,功放设备是否与安卓设备建立连接)中有分析。
mService.setSystemAudioActivated(on)以及mService.announceSystemAudioModeChange(on)方法只要知道他们的作用就行,具体流程是怎么处理的这里就不追下去了,有兴趣的大佬可以继续追下去分析到时候可以一起交流
void setSystemAudioMode(boolean on) {
if (!isSystemAudioControlFeatureEnabled() && on) {
HdmiLogger.debug("Cannot turn on system audio mode "
+ "because the System Audio Control feature is disabled.");
return; }
HdmiLogger.debug("System Audio Mode change[old:%b new:%b]",
mService.isSystemAudioActivated(), on);
updateAudioManagerForSystemAudio(on);
synchronized (mLock) {
if (mService.isSystemAudioActivated() != on) {
mService.setSystemAudioActivated(on);
mService.announceSystemAudioModeChange(on);
}
if (on && !mArcEstablished) {
//调用了startArcAction方法开始激活ARC功能
startArcAction(true);
} else if (!on) {
startArcAction(false);
}
}
}
在章节2-1中startArcAction方法最后调用了enableArc方法激活ARC功能。
这个方法中也调用了notifyArcStatusToAudioService方法将Arc状态通知给音频服务
base/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java
void enableArc(List<byte[]> supportedSads) {
assertRunOnServiceThread();
HdmiLogger.debug("Set Arc Status[old:%b new:true]", mArcEstablished);
enableAudioReturnChannel(true);
notifyArcStatusToAudioService(true, supportedSads);
mArcEstablished = true;
}
//mService.getAudioManager().setWiredDeviceConnectionState(attributes, enabled ? 1 : 0)
private void notifyArcStatusToAudioService(boolean enabled, List<byte[]> supportedSads) {
// Note that we don't set any name to ARC.
AudioDeviceAttributes attributes = new AudioDeviceAttributes(
AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_HDMI_ARC, "", "",
new ArrayList<AudioProfile>(), supportedSads.stream()
.map(sad -> new AudioDescriptor(AudioDescriptor.STANDARD_EDID,
AudioProfile.AUDIO_ENCAPSULATION_TYPE_NONE, sad))
.collect(Collectors.toList()));
mService.getAudioManager().setWiredDeviceConnectionState(attributes, enabled ? 1 : 0);
}
base/services/core/java/com/android/server/audio/AudioService.java
//mDeviceBroker.setWiredDeviceConnectionState(attributes, state, caller)
public void setWiredDeviceConnectionState(AudioDeviceAttributes attributes,
@ConnectionState int state, String caller) {
enforceModifyAudioRoutingPermission();
if (state != CONNECTION_STATE_CONNECTED
&& state != CONNECTION_STATE_DISCONNECTED) {
throw new IllegalArgumentException("Invalid state " + state);
}
new MediaMetrics.Item(mMetricsId + "setWiredDeviceConnectionState")
.set(MediaMetrics.Property.ADDRESS, attributes.getAddress())
.set(MediaMetrics.Property.CLIENT_NAME, caller)
.set(MediaMetrics.Property.DEVICE,
AudioSystem.getDeviceName(attributes.getInternalType()))
.set(MediaMetrics.Property.NAME, attributes.getName())
.set(MediaMetrics.Property.STATE,
state == CONNECTION_STATE_CONNECTED ? "connected" : "disconnected")
.record();
if ((attributes.getInternalType() == AudioSystem.DEVICE_OUT_AUX_DIGITAL) && (state == CONNECTION_STATE_CONNECTED)) {
updataFormatForEdid();
}
mDeviceBroker.setWiredDeviceConnectionState(attributes, state, caller);
}
base/services/core/java/com/android/server/audio/AudioDeviceBroker.java
/*package*/ void setWiredDeviceConnectionState(AudioDeviceAttributes attributes,
@AudioService.ConnectionState int state, String caller) {
//TODO move logging here just like in setBluetooth* methods
synchronized (mDeviceStateLock) {
mDeviceInventory.setWiredDeviceConnectionState(attributes, state, caller);
}
}
base/services/core/java/com/android/server/audio/AudioDeviceInventory.java
/*package*/ int setWiredDeviceConnectionState(AudioDeviceAttributes attributes,
@AudioService.ConnectionState int state, String caller) {
synchronized (mDevicesLock) {
int delay = checkSendBecomingNoisyIntentInt(
attributes.getInternalType(), state, AudioSystem.DEVICE_NONE);
mDeviceBroker.postSetWiredDeviceConnectionState(
new WiredDeviceConnectionState(attributes, state, caller), delay);
return delay;
}
}
base/services/core/java/com/android/server/audio/AudioDeviceBroker.java
/*package*/ void postSetWiredDeviceConnectionState(
AudioDeviceInventory.WiredDeviceConnectionState connectionState, int delay) {
sendLMsg(MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE, SENDMSG_QUEUE, connectionState, delay);
}
case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE:
synchronized (mDeviceStateLock) {
mDeviceInventory.onSetWiredDeviceConnectionState(
(AudioDeviceInventory.WiredDeviceConnectionState) msg.obj);
}
break;
base/services/core/java/com/android/server/audio/AudioDeviceInventory.java
//handleDeviceConnection
/*package*/ void onSetWiredDeviceConnectionState(
AudioDeviceInventory.WiredDeviceConnectionState wdcs) {
int type = wdcs.mAttributes.getInternalType();
AudioService.sDeviceLogger.log(new AudioServiceEvents.WiredDevConnectEvent(wdcs));
MediaMetrics.Item mmi = new MediaMetrics.Item(mMetricsId
+ "onSetWiredDeviceConnectionState")
.set(MediaMetrics.Property.ADDRESS, wdcs.mAttributes.getAddress())
.set(MediaMetrics.Property.DEVICE,
AudioSystem.getDeviceName(type))
.set(MediaMetrics.Property.STATE,
wdcs.mState == AudioService.CONNECTION_STATE_DISCONNECTED
? MediaMetrics.Value.DISCONNECTED : MediaMetrics.Value.CONNECTED);
synchronized (mDevicesLock) {
if ((wdcs.mState == AudioService.CONNECTION_STATE_DISCONNECTED)
&& DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.contains(type)) {
mDeviceBroker.setBluetoothA2dpOnInt(true, false /*fromA2dp*/,
"onSetWiredDeviceConnectionState state DISCONNECTED");
}
if (!handleDeviceConnection(wdcs.mAttributes,
wdcs.mState == AudioService.CONNECTION_STATE_CONNECTED, wdcs.mForTest)) {
// change of connection state failed, bailout
mmi.set(MediaMetrics.Property.EARLY_RETURN, "change of connection state failed")
.record();
return; }
if (wdcs.mState != AudioService.CONNECTION_STATE_DISCONNECTED) {
if (DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.contains(type)) {
mDeviceBroker.setBluetoothA2dpOnInt(false, false /*fromA2dp*/,
"onSetWiredDeviceConnectionState state not DISCONNECTED");
}
mDeviceBroker.checkMusicActive(type, wdcs.mCaller);
}
if (type == AudioSystem.DEVICE_OUT_HDMI) {
mDeviceBroker.checkVolumeCecOnHdmiConnection(wdcs.mState, wdcs.mCaller);
}
sendDeviceConnectionIntent(type, wdcs.mState,
wdcs.mAttributes.getAddress(), wdcs.mAttributes.getName());
updateAudioRoutes(type, wdcs.mState);
}
mmi.record();
}
//mDeviceBroker.postAccessoryPlugMediaUnmute(device);
/*package*/ boolean handleDeviceConnection(AudioDeviceAttributes attributes, boolean connect,
boolean isForTesting) {
int device = attributes.getInternalType();
String address = attributes.getAddress();
String deviceName = attributes.getName();
if (AudioService.DEBUG_DEVICES) {
Slog.i(TAG, "handleDeviceConnection(" + connect + " dev:"
+ Integer.toHexString(device) + " address:" + address
+ " name:" + deviceName + ")");
}
MediaMetrics.Item mmi = new MediaMetrics.Item(mMetricsId + "handleDeviceConnection")
.set(MediaMetrics.Property.ADDRESS, address)
.set(MediaMetrics.Property.DEVICE, AudioSystem.getDeviceName(device))
.set(MediaMetrics.Property.MODE, connect
? MediaMetrics.Value.CONNECT : MediaMetrics.Value.DISCONNECT)
.set(MediaMetrics.Property.NAME, deviceName);
synchronized (mDevicesLock) {
final String deviceKey = DeviceInfo.makeDeviceListKey(device, address);
if (AudioService.DEBUG_DEVICES) {
Slog.i(TAG, "deviceKey:" + deviceKey);
}
DeviceInfo di = mConnectedDevices.get(deviceKey);
boolean isConnected = di != null;
if (AudioService.DEBUG_DEVICES) {
Slog.i(TAG, "deviceInfo:" + di + " is(already)Connected:" + isConnected);
}
if (connect && !isConnected) {
final int res;
if (isForTesting) {
res = AudioSystem.AUDIO_STATUS_OK;
} else {
res = mAudioSystem.setDeviceConnectionState(attributes,
AudioSystem.DEVICE_STATE_AVAILABLE, AudioSystem.AUDIO_FORMAT_DEFAULT);
}
if (res != AudioSystem.AUDIO_STATUS_OK) {
final String reason = "not connecting device 0x" + Integer.toHexString(device)
+ " due to command error " + res;
Slog.e(TAG, reason);
mmi.set(MediaMetrics.Property.EARLY_RETURN, reason)
.set(MediaMetrics.Property.STATE, MediaMetrics.Value.DISCONNECTED)
.record();
return false; }
mConnectedDevices.put(deviceKey, new DeviceInfo(
device, deviceName, address, AudioSystem.AUDIO_FORMAT_DEFAULT));
mDeviceBroker.postAccessoryPlugMediaUnmute(device);
mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.CONNECTED).record();
return true; } else if (!connect && isConnected) {
mAudioSystem.setDeviceConnectionState(attributes,
AudioSystem.DEVICE_STATE_UNAVAILABLE, AudioSystem.AUDIO_FORMAT_DEFAULT);
// always remove even if disconnection failed
mConnectedDevices.remove(deviceKey);
mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.CONNECTED).record();
return true; }
Log.w(TAG, "handleDeviceConnection() failed, deviceKey=" + deviceKey
+ ", deviceSpec=" + di + ", connect=" + connect);
}
mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.DISCONNECTED).record();
return false;}
base/services/core/java/com/android/server/audio/AudioService.java
public void postAccessoryPlugMediaUnmute(int newDevice) {
sendMsg(mAudioHandler, MSG_ACCESSORY_PLUG_MEDIA_UNMUTE, SENDMSG_QUEUE,
newDevice, 0, null, 0);
}
case MSG_ACCESSORY_PLUG_MEDIA_UNMUTE:
onAccessoryPlugMediaUnmute(msg.arg1);
break;
//mStreamStates[AudioSystem.STREAM_MUSIC].mute(false);
private void onAccessoryPlugMediaUnmute(int newDevice) {
if (DEBUG_VOL) {
Log.i(TAG, String.format("onAccessoryPlugMediaUnmute newDevice=%d [%s]",
newDevice, AudioSystem.getOutputDeviceName(newDevice)));
}
if (mNm.getZenMode() != Settings.Global.ZEN_MODE_NO_INTERRUPTIONS
&& !isStreamMutedByRingerOrZenMode(AudioSystem.STREAM_MUSIC)
&& DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.contains(newDevice)
&& mStreamStates[AudioSystem.STREAM_MUSIC].mIsMuted
&& mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(newDevice) != 0
&& getDeviceSetForStreamDirect(AudioSystem.STREAM_MUSIC).contains(newDevice)) {
if (DEBUG_VOL) {
Log.i(TAG, String.format("onAccessoryPlugMediaUnmute unmuting device=%d [%s]",
newDevice, AudioSystem.getOutputDeviceName(newDevice)));
}
mStreamStates[AudioSystem.STREAM_MUSIC].mute(false);
}
}
//MSG_SET_ALL_VOLUMES
public boolean mute(boolean state) {
Log.d(TAG,"zfp#mute");
boolean changed = false;
synchronized (VolumeStreamState.class) {
if (state != mIsMuted) {
changed = true;
mIsMuted = state;
// Set the new mute volume. This propagates the values to
// the audio system, otherwise the volume won't be changed
// at the lower level.
sendMsg(mAudioHandler,
MSG_SET_ALL_VOLUMES,
SENDMSG_QUEUE,
0,
0,
this, 0);
}
}
if (changed) {
// Stream mute changed, fire the intent.
Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);
sendBroadcastToAll(intent);
}
return changed;
}
//setAllVolumes
case MSG_SET_ALL_VOLUMES:
setAllVolumes((VolumeStreamState) msg.obj);
break;
//mStreamStates[streamType].applyAllVolumes()
private void setAllVolumes(VolumeStreamState streamState) {
// Apply volume
streamState.applyAllVolumes();
// Apply change to all streams using this one as alias
int numStreamTypes = AudioSystem.getNumStreamTypes();
for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
if (streamType != streamState.mStreamType &&
mStreamVolumeAlias[streamType] == streamState.mStreamType) {
mStreamStates[streamType].applyAllVolumes();
}
}
}
//setStreamVolumeIndex
public void applyAllVolumes() {
synchronized (VolumeStreamState.class) {
// apply device specific volumes first
Log.d(TAG,"zfp#applyAllVolumes");
int index;
for (int i = 0; i < mIndexMap.size(); i++) {
final int device = mIndexMap.keyAt(i);
if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
if (isFullyMuted()) {
index = 0;
} else if (isAbsoluteVolumeDevice(device)
|| isA2dpAbsoluteVolumeDevice(device)
|| AudioSystem.isLeAudioDeviceType(device)) {
index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
} else if (device == AudioSystem.DEVICE_OUT_HEARING_AID) {
index = (mIndexMax + 5)/10;
} else {
index = (mIndexMap.valueAt(i) + 5)/10;
}
setStreamVolumeIndex(index, device);
}
}
// apply default volume last: by convention , default device volume will be used
// by audio policy manager if no explicit volume is present for a given device type
if (isFullyMuted()) {
index = 0;
} else {
index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
}
setStreamVolumeIndex(index, AudioSystem.DEVICE_OUT_DEFAULT);
}
}
//mAudioSystem.setStreamVolumeIndexAS
private void setStreamVolumeIndex(int index, int device) {
// Only set audio policy BT SCO stream volume to 0 when the stream is actually muted.
// This allows RX path muting by the audio HAL only when explicitly muted but not when
// index is just set to 0 to repect BT requirements
if (mStreamType == AudioSystem.STREAM_BLUETOOTH_SCO && index == 0
&& !isFullyMuted()) {
index = 1;
}
boolean arcStatus = SystemProperties.getBoolean("sys.skg.arc.inserted", false);
if (mStreamType == AudioSystem.STREAM_MUSIC && arcStatus){
if (device == AudioSystem.DEVICE_OUT_SPDIF || device == AudioSystem.DEVICE_OUT_SPDIF_1
|| device == AudioSystem.DEVICE_OUT_HDMI || device == AudioSystem.DEVICE_OUT_HDMI_1){
return;
}
}
Log.d(TAG,"zfp#setStreamVolumeIndex#index = " + index + "device = " + device + "mStreamType = " + mStreamType);
mAudioSystem.setStreamVolumeIndexAS(mStreamType, index, device);
}
base/media/java/android/media/AudioSystem.java
//setStreamVolumeIndex
public static int setStreamVolumeIndexAS(int stream, int index, int device) {
if (DEBUG_VOLUME) {
Log.i(TAG, "setStreamVolumeIndex: " + STREAM_NAMES[stream]
+ " dev=" + Integer.toHexString(device) + " idx=" + index);
}
return setStreamVolumeIndex(stream, index, device);
}
private static native int setStreamVolumeIndex(int stream, int index, int device);
//当ARC设备唤醒时还会调用AudioService.java的 方法更新设备声音状态
base/media/java/android/media/AudioSystem.java
private void updateVolumeStates(int device, int streamType, String caller) {
Log.d(TAG,"sug#updateVolumeStates");
// Handle device volume aliasing of SPEAKER_SAFE.
if (device == AudioSystem.DEVICE_OUT_SPEAKER_SAFE) {
device = AudioSystem.DEVICE_OUT_SPEAKER;
}
if (!mStreamStates[streamType].hasIndexForDevice(device)) {
// set the default value, if device is affected by a full/fix/abs volume rule, it
// will taken into account in checkFixedVolumeDevices()
mStreamStates[streamType].setIndex(
mStreamStates[mStreamVolumeAlias[streamType]]
.getIndex(AudioSystem.DEVICE_OUT_DEFAULT),
device, caller, true /*hasModifyAudioSettings*/);
}
// Check if device to be updated is routed for the given audio stream
// This may include devices such as SPEAKER_SAFE.
List<AudioDeviceAttributes> devicesForAttributes = getDevicesForAttributesInt(
new AudioAttributes.Builder().setInternalLegacyStreamType(streamType).build(),
true /* forVolume */);
for (AudioDeviceAttributes deviceAttributes : devicesForAttributes) {
if (deviceAttributes.getType() == AudioDeviceInfo.convertInternalDeviceToDeviceType(
device)) {
mStreamStates[streamType].checkFixedVolumeDevices();
// Unmute streams if required and device is full volume
Log.d(TAG,"sug#updateVolumeStates#device = " + device);
> [!NOTE]
> 当设备音频流为静音状态并且设备为ARC设备时解除设备静音
> if (isStreamMute(streamType) && (mFullVolumeDevices.contains(device) || isArcDevice(device))) {
> mStreamStates[streamType].mute(false);
> }
}
}
}
2、android设备开机时启动AudioService初始化设备音量
public AudioService(Context context, AudioSystemAdapter audioSystem,
SystemServerAdapter systemServer, SettingsAdapter settings, @Nullable Looper looper,
AppOpsManager appOps) {
---
> [!代码1]
> 创建并启动名为AudioService的循环消息处理线程
> createAudioSystemThread();
---
> [!代码2]
> 根据平台不同,选择Stream别名的定义策略。比如TV电视会STREAM_VOLUME_ALIAS_TELEVISION,手机会使用STREAM_VOLUME_ALIAS_VOICE
> updateStreamVolumeAlias(false /*updateVolumes*/, TAG);
---
> [!代码3]
> 开机初始化流以及设备的音量onInitStreamsAndVolumes()//内部线程在处理MSG_INIT_STREAMS_VOLUMES消息时调用
> queueMsgUnderWakeLock(mAudioHandler, MSG_INIT_STREAMS_VOLUMES,
> 0 /* arg1 */, 0 /* arg2 */, null /* obj */, 0 /* delay */);
}
代码3
//createStreamStates();
private void onInitStreamsAndVolumes() {
createStreamStates();
// must be called after createStreamStates() as it uses MUSIC volume as default if no
// persistent data initVolumeGroupStates();
// mSafeUsbMediaVolumeIndex must be initialized after createStreamStates() because it
// relies on audio policy having correct ranges for volume indexes.
mSafeUsbMediaVolumeIndex = getSafeUsbMediaVolumeIndex();
// Call setRingerModeInt() to apply correct mute
// state on streams affected by ringer mode. mRingerAndZenModeMutedStreams = 0;
setRingerModeInt(getRingerModeInternal(), false);
final float[] preScale = new float[3];
preScale[0] = mContext.getResources().getFraction(
com.android.internal.R.fraction.config_prescaleAbsoluteVolume_index1,
1, 1);
preScale[1] = mContext.getResources().getFraction(
com.android.internal.R.fraction.config_prescaleAbsoluteVolume_index2,
1, 1);
preScale[2] = mContext.getResources().getFraction(
com.android.internal.R.fraction.config_prescaleAbsoluteVolume_index3,
1, 1);
for (int i = 0; i < preScale.length; i++) {
if (0.0f <= preScale[i] && preScale[i] <= 1.0f) {
mPrescaleAbsoluteVolume[i] = preScale[i];
}
}
initExternalEventReceivers();
// check on volume initialization
checkVolumeRangeInitialization("AudioService()");
}
private void createStreamStates() {
int numStreamTypes = AudioSystem.getNumStreamTypes();
> [!代码3-1]
> 传入音频流创建streams对象
> VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
for (int i = 0; i < numStreamTypes; i++) {
streams[i] =
new VolumeStreamState(System.VOLUME_SETTINGS_INT[mStreamVolumeAlias[i]], i);
}
> [!代码3-2]
> 检查所有固定音量设备
> checkAllFixedVolumeDevices();
> [!代码3-3]
> 检查所有音频流的值
> checkAllAliasStreamVolumes();
> [!代码3-4]
> checkMuteAffectedStreams();
> [!代码3-5]
> updateDefaultVolumes();
}
代码3-1
private VolumeStreamState(String settingName, int streamType) {
mVolumeIndexSettingName = settingName;
mStreamType = streamType;
mIndexMin = MIN_STREAM_VOLUME[streamType] * 10;
mIndexMinNoPerm = mIndexMin; // may be overwritten later in updateNoPermMinIndex()
mIndexMax = MAX_STREAM_VOLUME[streamType] * 10;
> [!NOTE]
> 通知AudioPolicyService设置最大和最小音量等级
> final int status = AudioSystem.initStreamVolume(
> streamType, mIndexMin / 10, mIndexMax / 10);
if (status != AudioSystem.AUDIO_STATUS_OK) {
sLifecycleLogger.log(new AudioEventLogger.StringEvent(
"VSS() stream:" + streamType + " initStreamVolume=" + status)
.printLog(ALOGE, TAG));
sendMsg(mAudioHandler, MSG_REINIT_VOLUMES, SENDMSG_NOOP, 0, 0,
"VSS()" /*obj*/, 2 * INDICATE_SYSTEM_READY_RETRY_DELAY_MS);
}
> [!代码3-1-1]
> 从SettingProvider中读取当前StreamType对应的各个device的默认音量等级,如果SettingProvider中没有配置,就使用AudioSystem.DEFAULT_STREAM_VOLUME[]数组中的配置
> readSettings();
mVolumeChanged = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
mStreamDevicesChanged = new Intent(AudioManager.STREAM_DEVICES_CHANGED_ACTION);
mStreamDevicesChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
}
代码3-1-1
public void readSettings() {
......
synchronized (VolumeStreamState.class) {
for (int device : AudioSystem.DEVICE_OUT_ALL_SET) {
// retrieve current volume for device
// if no volume stored for current stream and device, use default volume if default
// device, continue otherwise
int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
int index;
if (!hasValidSettingsName()) {
index = defaultIndex;
} else {
String name = getSettingNameForDevice(device);
> [!NOTE]
> 获取音量值
> index = mSettings.getSystemIntForUser(
> mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
}
if (index == -1) {
continue;
}
> [!NOTE]
> 将音量值put到集合中
> mIndexMap.put(device, getValidIndex(10 * index,
> true /*hasModifyAudioSettings*/));
}
}
}
代码3-2
//mStreamStates[streamType].checkFixedVolumeDevices()
private void checkAllFixedVolumeDevices()
{
int numStreamTypes = AudioSystem.getNumStreamTypes();
for (int streamType = 0; streamType < numStreamTypes; streamType++) {
mStreamStates[streamType].checkFixedVolumeDevices();
}
}
public void checkFixedVolumeDevices() {
synchronized (VolumeStreamState.class) {
// ignore settings for fixed volume devices: volume should always be at max or 0
if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) {
for (int i = 0; i < mIndexMap.size(); i++) {
int device = mIndexMap.keyAt(i);
int index = mIndexMap.valueAt(i);
> [!NOTE]
> 当为满音量设备时传入最大音量值
> if (isFullVolumeDevice(device)
> || (isFixedVolumeDevice(device) && index != 0)) {
> mIndexMap.put(device, mIndexMax);
> }
> [!NOTE]
> 同步更新设备音量值
> applyDeviceVolume_syncVSS(device);
}
}
}
}
代码3-3
private void checkAllAliasStreamVolumes() {
synchronized (mSettingsLock) {
synchronized (VolumeStreamState.class) {
int numStreamTypes = AudioSystem.getNumStreamTypes();
for (int streamType = 0; streamType < numStreamTypes; streamType++) {
> [!NOTE]
> 拷贝当前StreamType对应别名的音量
> mStreamStates[streamType]
> .setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]], TAG);
// apply stream volume
if (!mStreamStates[streamType].mIsMuted) {
> [!NOTE]
> 设置当前streamType所有对应device的音量等级到AudioPolicyService中
> mStreamStates[streamType].applyAllVolumes();
}
}
}
}
}