zl程序教程

您现在的位置是:首页 >  其他

当前栏目

AudioService.VolumeStreamState 代码走读与设计思考

代码 设计 思考
2023-09-14 09:13:52 时间

前言
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