(L1) 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复制完成后:

  1. 对native初始化,调用 AudioSystem.initStreamVolume,参数为stream type, index min, index max.
  2. mIndexMax * 10用于提高运算精度

function : readSetting

该函数的有50多行,观察之后可以发现,每个代码块{} 中,都在执行mIndex.put,可以了解到readSetting是对 mIndex 初始化

逻辑大概如下:

  1. 使用 fixed volume , master volume 的情况,mIndex只存入 default out device ,max index 作为一对device–> index,然后退出 ,代码中为第一个 if 块
  2. 如果当前VolumeStreamState的tpye是 
    AudioSystem.STREAM_SYSTEM
    AudioSystem.STREAM_SYSTEM_ENFORCED

    那么存入default out device, default index,代码为第二个 if 块,该代码块还包含了一个

    if (mCameraSoundForced)的代码块,用于处理相机拍照音
     
  3. remainingDevices 中所有的device的 index从数据库中取值,如果数据库中没有 getSettingNameForDevice 生成的 key,则使用defaultIndex

    影响这个代码块的因素是 mVolumeIndexSettingName, mStreamType

  4. 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(mStreamTypeindexdevice);下派参数

    private void checkAllFixedVolumeDevices(int streamType) {
        mStreamStates[streamType].checkFixedVolumeDevices();
    }

function: checkAllAliasStreamVolumes

1.stream  和 对应的alias stream 不同则,用alias stream的VolumeStreamIndex 来初始化该stream的VolumeStreamIndex.

最终会调用AudioSystem.setStreamVolumeIndex(mStreamTypeindexdevice);下派参数

    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这么定义到底是要做什么?

  1. 适配多个平台
  2. 适配多种外设
发布了27 篇原创文章 · 获赞 2 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/wlia/article/details/46897819