AudioService.VolumeStreamState 代码走读与设计思考
前言
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) {
......
createStreamStates();
......
}
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这么定义到底是要做什么?
适配多个平台
适配多种外设
————————————————
版权声明:本文为CSDN博主「wlia」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wlia/article/details/46897819
相关文章
- verilog流水线设计代码_十进制BCD译码器的verilog
- 开发一个在线代码对比工具
- 用SPSS估计HLM多层(层次)线性模型模型|附代码数据
- 通过HTML和CSS设计一个静态网页(练习实例,附完整代码)
- zblogPHP调用文章总数、置顶数、tag总数等相关代码教程
- 优雅代码的秘密,都藏在这6个设计原则中
- DDD 实战之一:从需求到代码实现生鲜电商系统
- 【C 语言】字符串拷贝 ( 字符串拷贝业务逻辑代码 | 分离 主函数 与 字符串拷贝 业务模型 )
- 【算法】动态规划 ⑤ ( LeetCode 63.不同路径 II | 问题分析 | 动态规划算法设计 | 代码示例 )
- Java实现打字练习的代码详解编程语言
- 博客园自定义页面风格设计 后续篇(页面设计模式及代码高亮 鼠标点击效果升级)详解编程语言
- Java并发编程之并发代码设计详解编程语言
- 编写可靠性高的Redis代码遵循原则(redis设计的原则)
- SaveRemoteFile函数之asp实现保存远程的文件到本地的代码
- 利用404错误页面实现UrlRewrite的实现代码
- asp.net动态引用样式表代码
- php随机排序广告的实现代码
- 简单的PHP缓存设计实现代码
- php网上商城促销设计实例代码
- PHP杂谈《重构-改善既有代码的设计》之五简化函数调用
- ASP.NET设计网络硬盘之下载或在线查看实现代码
- jquery延迟加载外部js实现代码
- 解析:清除SQL被注入恶意病毒代码的语句
- jquery动态增加text元素以及删除文本内容实例代码
- js切换光标示例代码
- js判断IE浏览器版本过低示例代码
- Jquery动态添加及删除页面节点元素示例代码