前言
VolumeStreamState是AudioService中控制音量调节的内部类
是AudioService中很重要,也很难懂的一个类
很多用户行为,设备的连接都会调用到该类的方法,对volume大小产生影响。
本文的代码引用至 http://androidxref.com/5.1.1_r6/xref/frameworks/base/media/java/android/media/AudioService.java
属性
源码
public class VolumeStreamState {
private final int mStreamType;
private String mVolumeIndexSettingName;
private int mIndexMax;
private final ConcurrentHashMap<Integer, Integer> mIndex =
new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo clients death
分类
根据源码来看,VolumeStreamState的属性并不多。
- stream type 相关:mStreamType , mVolumeIndexSettingName ,既可以用数字表示类型,也可以用名字来表示
- index相关:mIndexMax , mIndex (没有Index Min也可以理解,因为不能有音量为负数,只会是0)
- Clients death:mDeathHandler;
构造函数
源码
function : VolumeStreamState
private VolumeStreamState(String settingName, int streamType) {
mVolumeIndexSettingName = settingName;
mStreamType = streamType;
mIndexMax = MAX_STREAM_VOLUME[streamType];
AudioSystem.initStreamVolume(streamType, 0, mIndexMax);
mIndexMax *= 10;
// mDeathHandlers must be created before calling readSettings()
mDeathHandlers = new ArrayList<VolumeDeathHandler>();
readSettings();
}
该函数多数行很简单,对上面的属性通过复制进行初始化
mIndexMax复制完成后:
- 对native初始化,调用 AudioSystem.initStreamVolume,参数为stream type, index min, index max.
- mIndexMax * 10用于提高运算精度
function : readSetting
该函数的有50多行,观察之后可以发现,每个代码块{} 中,都在执行mIndex.put,可以了解到readSetting是对 mIndex 初始化
逻辑大概如下:
- 使用 fixed volume , master volume 的情况,mIndex只存入 default out device ,max index 作为一对device–> index,然后退出 ,代码中为第一个 if 块
- 如果当前VolumeStreamState的tpye是
AudioSystem.STREAM_SYSTEM
AudioSystem.STREAM_SYSTEM_ENFORCED
那么存入default out device, default index,代码为第二个 if 块,该代码块还包含了一个
if (mCameraSoundForced)的代码块,用于处理相机拍照音
-
remainingDevices 中所有的device的 index从数据库中取值,如果数据库中没有 getSettingNameForDevice 生成的 key,则使用defaultIndex
影响这个代码块的因素是 mVolumeIndexSettingName, mStreamType
-
index*10 提高进度后再通过 getValidIndex 检查,最后存入 mIndex
public void readSettings() {
synchronized (VolumeStreamState.class) {
// force maximum volume on all streams if fixed volume property
// or master volume property is set
if (mUseFixedVolume || mUseMasterVolume) {
mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
return;
}
// do not read system stream volume from settings: this stream is always aliased
// to another stream type and its volume is never persisted. Values in settings can
// only be stale values
if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
(mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
int index = 10 * DEFAULT_STREAM_VOLUME[mStreamType];
synchronized (mCameraSoundForced) {
if (mCameraSoundForced) {
index = mIndexMax;
}
}
mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
return;
}
int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
for (int i = 0; remainingDevices != 0; i++) {
int device = (1 << i);
if ((device & remainingDevices) == 0) {
continue;
}
remainingDevices &= ~device;
// retrieve current volume for device
String name = getSettingNameForDevice(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) ?
DEFAULT_STREAM_VOLUME[mStreamType] : -1;
int index = Settings.System.getIntForUser(
mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
if (index == -1) {
continue;
}
mIndex.put(device, getValidIndex(10 * index));
}
}
}
function : getSettingNameForDevice
代码简单,也是 mVolumeIndexSettingName 被唯一使用的地方
将volume name 同device name 结合生成的key,体现出对应关系。
public String getSettingNameForDevice(int device) {
String name = mVolumeIndexSettingName;
String suffix = AudioSystem.getOutputDeviceName(device);
if (suffix.isEmpty()) {
return name;
}
return name + "_" + suffix;
}
初始化过程
VolumeStreamState的初始化在AudioService的构造过程中完成。通过函数 createStreamStates() 实现
public AudioService(Context context) {
......
......
}
function : createStreamStates
函数 createStreamStates() 根据 AudioSystem.getNumStreamTypes(); 对每种 stream type生成一个VolumeStreamState, 并用
System.VOLUME_SETTINGS[mStreamVolumeAlias[i]] 作为初始化 mVolumeIndexSettingName 的参数。
有些不同的 stream type 的 stream volume alias 是相同的,则不同的 VolumeStreamState 实例,存在相同的 mVolumeIndexSettingName
private void createStreamStates() {
int numStreamTypes = AudioSystem.getNumStreamTypes();
VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
for (int i = 0; i < numStreamTypes; i++) {
streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
}
checkAllFixedVolumeDevices();
checkAllAliasStreamVolumes();
}
function: checkAllFixedVolumeDevices
根据函数名理解是检查全部的固定音量设备,实际代码是调用每个 VolumeStreamState.checkFixedVolumeDevice.
最终会调用AudioSystem.setStreamVolumeIndex(mStreamType, index, device);下派参数
private void checkAllFixedVolumeDevices(int streamType) {
mStreamStates[streamType].checkFixedVolumeDevices();
}
function: checkAllAliasStreamVolumes
1.stream 和 对应的alias stream 不同则,用alias stream的VolumeStreamIndex 来初始化该stream的VolumeStreamIndex.
最终会调用AudioSystem.setStreamVolumeIndex(mStreamType, index, device);下派参数
private void checkAllAliasStreamVolumes() {
synchronized (VolumeStreamState.class) {
int numStreamTypes = AudioSystem.getNumStreamTypes();
for (int streamType = 0; streamType < numStreamTypes; streamType++) {
if (streamType != mStreamVolumeAlias[streamType]) {
mStreamStates[streamType].
setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]]);
}
// apply stream volume
if (!mStreamStates[streamType].isMuted_syncVSS()) {
mStreamStates[streamType].applyAllVolumes();
}
}
}
}
What to do
Android这么定义到底是要做什么?
- 适配多个平台
- 适配多种外设