AudioPolicy--音量的控制

/*****************************************************************************************************/

声明:本文内容是基于Android 8.1的源码分析

https://blog.csdn.net/xuechwtx原创,转载请注明出处,谢谢!

/*****************************************************************************************************/

1. VolumeCurvesCollection

(1) IVolumeCurvesCollection

IVolumeCurvesCollection *mVolumeCurves;
mVolumeCurves = new VolumeCurvesCollection()

    从AudioPolicymanager中可以看到,在操作音量的函数中,大都会调用mVolumeCurves的一些方法。比如在函数getStreamVolumeIndex中就调用了 mVolumeCurves->getVolumeIndex()的方法。所以我们可以猜测, mVolumeCurves可能保存着音量的信息, 并且有一些操作音量的方法. 在头文件中,mVolumeCurves被声明为IVolumeCurvesCollection类型。

    IVolumeCurvesCollection,这个类的定义在文件。在IVolumeCurvesCollection类中的public方法都被声明为虚函数,这些方法都是对AudioPolicy的接口,这些接口的实现应该都是在VolumeCurvesCollection类中。

(2) VolumeCurvesCollection

class VolumeCurvesCollection : 
	public KeyedVector,
	public IVolumeCurvesCollection

          VolumeCurvesCollection首先继承于IVolumeCurvesCollection,并且实现了父类中的虚函数。另外VolumeCurvesCollection继承于一个容器KeyedVector,容器的下标是流类型,容器的元素是VolumeCurvesForStream类型的对象。从VolumeCurvesCollection构造函数可以看出,构造时会每一种流类型创建一个VolumeCurvesForStream。所以我们可以猜测VolumeCurvesForStream中保存着每个流的音量信息。这样做可以对不同的流使用各自的策略。

class VolumeCurvesForStream : public KeyedVector >
{
private:
    KeyedVector > mOriginVolumeCurves;
    KeyedVector mIndexCur; /**< current volume index per device. */
    int mIndexMin; /**< min volume index. */
    int mIndexMax; /**< max volume index. */
    bool mCanBeMuted; /**< true is the stream can be muted. */
};

      mIndexMin,mIndexMax这两个属性代表着该流可以调节音量的最大值和最小值,这里的音量值就是我们实际调节音量键的时候所调节的音量值。最大值,最小值保存在AudioService.java中的MAX_STREAM_VOLUME,MIN_STREAM_VOLUME数组内。在AudioService构造的时候会调用AudioSystem的接口initStreamVolume传入每个流的最大值和最小值。

    private static int[] MAX_STREAM_VOLUME = new int[] {
        5,  // STREAM_VOICE_CALL
        7,  // STREAM_SYSTEM
        7,  // STREAM_RING
        15, // STREAM_MUSIC
        7,  // STREAM_ALARM
        7,  // STREAM_NOTIFICATION
        15, // STREAM_BLUETOOTH_SCO
        7,  // STREAM_SYSTEM_ENFORCED
        15, // STREAM_DTMF
        15, // STREAM_TTS
        15  // STREAM_ACCESSIBILITY
    };

    private static int[] MIN_STREAM_VOLUME = new int[] {
        1,  // STREAM_VOICE_CALL
        0,  // STREAM_SYSTEM
        0,  // STREAM_RING
        0,  // STREAM_MUSIC
        0,  // STREAM_ALARM
        0,  // STREAM_NOTIFICATION
        0,  // STREAM_BLUETOOTH_SCO
        0,  // STREAM_SYSTEM_ENFORCED
        0,  // STREAM_DTMF
        0,  // STREAM_TTS
        0   // STREAM_ACCESSIBILITY
    };
          mCanBeMuted 表示该流是否可以被Mute,现在代码环境下,都是ture。
     mIndexCur也是一个容器,下标是设备号audio_devices_t,元素是音量值(际调节的音量. 在VolumeCurvesCollection中,对于每个流每一个设备都保存着一个音量值。这样做的目的主要是可以存储不同设备的音量值,来满足用户对不同设备不同音量的需求。
      VolumeCurvesForStream继承了KeyedVector >,另外内部又有一个该容器类型的属性mOriginVolumeCurves。所以可以认为VolumeCurvesForStream内部有两个KeyedVector >类型的对象。其中mOriginVolumeCurves是原始值,不会被改变。KeyedVector >下标是device_category(设备的类别),元素是VolumeCurve. VolumeCurve代表一个音量曲线,即音量值与分贝值或者增益的对应关系。device_category是把设备分成了四类DEVICE_CATEGORY_HEADSET, DEVICE_CATEGORY_SPEAKER,DEVICE_CATEGORY_EARPIECE,DEVICE_CATEGORY_EXT_MEDIA. getDeviceCategory(audio_devices_t device)函数可以获得设备的分类。mOriginVolumeCurves提供了针对4类设备的音量值到分贝值的转换关系。

class VolumeCurve : public RefBase
{
private:
    SortedVector mCurvePoints;
    device_category mDeviceCategory;
    audio_stream_type_t mStreamType;
};
struct CurvePoint
{
    uint32_t mIndex;
    int mAttenuationInMb;
};

      VolumeCurve里面保存一个CurvePoint(曲线点)的容器,曲线点的横坐标是Index,纵坐标是mAttenuationInMb(单位是mdB).接下来看一下其中一条音量曲线. 我们可以看到该曲线包含四个点, index是从0~100,Attenuation的大小是-58dB~0dB。具体的音量值, Index和Attenuation之间的转换关系我们稍后会具体分析.



    1,-5800
    20,-4000
    60,-1700
    100,0

接下来总结一下VolumeCurvesCollection的结构:

AudioPolicy--音量的控制_第1张图片

2. 音量策略配置文件的解析

(1) 配置文件的结构

     首先我们看一下音量配置文件的结构。首先default_volume_tables.xml文件中保存着一些默认的音量配置,这些配置可以被audio_policy_volumes.xml中具体的音量配置引用,例如, AUDIO_STREAM_MUSIC流DEVICE_CATEGORY_SPEAKER类的设备使用的音量曲线的配置是DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE。




	1,-5800
	20,-4000
	60,-1700
	100,0



(2) 选择配置文件

  音量相关的配置文件包括audio_policy_volumes.xml和default_volume_tables.xml,默认在frameworks/av/services/audiopolicy/config/目录下, 配置文件的位置在不同平台不同。通常跟AudioPolicy的配置文件audio_policy_configuration.xml在同一个目录下。我们可以看到audio_policy_configuration.xml中引用了音量的配置文件。所以音频配置文件在AudioPolicyManager的构造函数中,跟audio_policy_configuration.xml一起解析。

  1. 创建一个VolumeCurvesCollection对象,构造函数会为每一个流创建VolumeCurvesForStream。
  2. 把mVolumeCurves对象传入AudioPolicyConfig的构造函数。作为AudioPolicyConfig的一个属性mVolumeCurves
  3. 解析AudioPolicy的配置文件audio_policy_configuration.xml
AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface)
	// 1. 创建一个VolumeCurvesCollection对象
	mVolumeCurves = new VolumeCurvesCollection();

	// 2. 把mVolumeCurves对象传入AudioPolicyConfig的构造函数
	AudioPolicyConfig config(mHwModules, mAvailableOutputDevices, mAvailableInputDevices,
	                         mDefaultOutputDevice, speakerDrcEnabled,
                             static_cast(mVolumeCurves));
		// 保存传入的mVolumeCurves对象
		config.mVolumeCurves = mVolumeCurves;

	// 3. 尝试解析Audiolicy的配置文件 audio_policy_configuration.xml
	deserializeAudioPolicyXmlConfig(config);
		// 依次尝试查找下面目录下的audio_policy_configuration.xml配置文件,
		// {"/odm/etc", "/vendor/etc/audio", "/vendor/etc", "/system/etc"}; 
		// audioPolicyXmlConfigFile = “audio_policy_configuration.xml”
		PolicySerializer serializer;
		serializer.deserialize(audioPolicyXmlConfigFile, config)
        // 4. 初始化 mVolumeCurves,在当前代码中initializeVolumeCurves没有做什么操作
	mVolumeCurves->initializeVolumeCurves(speakerDrcEnabled);

(3) 配置文件的解析过程

   AudioPolicyManager通过PolicySerializer::deserialize来解析Audio Policy 的配置文件其中包括audio_policy_configuration.xml

status_t PolicySerializer::deserialize(const char *configFile, AudioPolicyConfig &config)
    // 解析文件xml文件,找到跟节点xmlNodePtr cur
	xml文件,DocPtr doc = xmlParseFile(configFile);
	xmlNodePtr cur = xmlDocGetRootElement(doc);

	// 调用 deserializeCollection 函数解析Volume类型的节点
    // 设置AudioPolicyConfig中的属性mVolumeCurves = volumes;
    VolumeTraits::Collection volumes;
    deserializeCollection(doc, cur, volumes, &config);
    config.setVolumes(volumes);	

    deserializeCollection函数最终会调用VolumeTraits::deserialize函数解析每一个音量曲线。VolumeTraits::deserialize函数根据 “stream” “deviceCategory” “point”解析每条曲线配置。



	1,-3000
	33,-2600
	66,-2200
	100,-1800
status_t VolumeTraits::deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
                                   PtrSerializingCtx /*serializingContext*/)
{
    // 解析 “stream” Tag
    string streamTypeLiteral = getXmlAttribute(root, Attributes::stream);
    audio_stream_type_t streamType;
    StreamTypeConverter::fromString(streamTypeLiteral, streamType);
    // 解析 “deviceCategory” Tag
    string deviceCategoryLiteral = getXmlAttribute(root, Attributes::deviceCategory);
    device_category deviceCategory;
    DeviceCategoryConverter::fromString(deviceCategoryLiteral, deviceCategory);
    // 解析 “ref” Tag
    string referenceName = getXmlAttribute(root, Attributes::reference);
    const _xmlNode *ref = NULL;
    if (!referenceName.empty()) {
        getReference(root->parent, ref, referenceName);
    }

    element = new Element(deviceCategory, streamType);

    const xmlNode *child = referenceName.empty() ? root->xmlChildrenNode : ref->xmlChildrenNode;
    while (child != NULL) {
        if (!xmlStrcmp(child->name, (const xmlChar *)volumePointTag)) {
            xmlChar *pointDefinition = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);;
	    // 解析 “point”
            Vector point;
            collectionFromString >((const char*)pointDefinition, point, ",");
 	    // 添加解析出来的 Point
            element->add(CurvePoint(point[0], point[1]));
            xmlFree(pointDefinition);
        }
        child = child->next;
    }
}

3. IVolumeCurvesCollection 的接口

clearCurrentVolumeIndex,清空某个流的所有音量记录,AudioPolicyManager没有调到该接口
void clearCurrentVolumeIndex(audio_stream_type_t stream)
	editCurvesFor(stream).clearCurrentVolumeIndex();
		// 清空当前音量的容器 KeyedVector mIndexCur
		mIndexCur.clear();
addCurrentVolumeIndex,更新某个流某个设备的音量

AudioPolicyManager在函数setStreamVolumeIndex时会调用该接口

void addCurrentVolumeIndex(audio_stream_type_t stream, audio_devices_t device, int index)
    // VolumeCurvesForStream::addCurrentVolumeIndex
	editCurvesFor(stream).addCurrentVolumeIndex(device, index);
		// 向当前音量的容器添加一项,替换当前保存的音量值
		mIndexCur.add(device, index);

canBeMuted,判断该流是否可以静音

当前代码没有setcanBeMuted的接口。 mCanBeMuted默认为ture, 该接口返回ture

bool canBeMuted(audio_stream_type_t stream)
	return getCurvesFor(stream).canBeMuted()
		// 返回 流的音量信息中的 mCanBeMuted
		// VolumeCurvesForStream.mCanBeMuted
		VolumeCurvesForStream::canBeMuted()
			return mCanBeMuted;

getVolumeIndexMin,获取该流的最小音量

没有set的接口, Min和Max只有被接口initializeVolumeCurves设置

int getVolumeIndexMin(audio_stream_type_t stream)
	return getCurvesFor(stream).getVolumeIndexMin()
		// 返回 流的音量信息中的 mIndexMin
		// VolumeCurvesForStream.mIndexMin
		VolumeCurvesForStream::getVolumeIndexMin()
			return mIndexMin

getVolumeIndexMax,获取该流的最大音量

int getVolumeIndexMax(audio_stream_type_t stream)
	return getCurvesFor(stream).getVolumeIndexMax()
		// 返回 流的音量信息中的 mIndexMax
		// VolumeCurvesForStream.mIndexMax
		VolumeCurvesForStream::getVolumeIndexMax()
			return mIndexMax

initStreamVolume,初始化特定流的VolumeCurvesForStream

这里只是设置 VolumeCurvesForStream 的最大音量和最小音量

这也是唯一可以设置最大最小值的接口

virtual status_t initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax)
	editValueAt(stream).setVolumeIndexMin(indexMin);
	// VolumeCurvesForStream.mIndexMin = indexMin;
	editValueAt(stream).setVolumeIndexMax(indexMax);
	// VolumeCurvesForStream.mIndexMax = indexMax;

getVolumeIndex,获取该特定流特定设备的音量

返回VolumeCurvesForStream.mIndexCur.valueFor(device)

int getVolumeIndex(audio_stream_type_t stream, audio_devices_t device)
	return getCurvesFor(stream).getVolumeIndex(device)
		VolumeCurvesForStream::getVolumeIndex()
			// 从多个设备选择中提取一个的设备
			// getCurvesFor(stream).mIndexCur.valueFor(device)
			device = Volume::getDeviceForVolume(device)
			return mIndexCur.valueFor(device)

hasVolumeIndexForDevice,有没有为特定的流特定的设备设置音量值

virtual bool hasVolumeIndexForDevice(audio_stream_type_t stream,
                                    audio_devices_t device) const
    // VolumeCurvesForStream::hasVolumeIndexForDevice(device)
    return getCurvesFor(stream).hasVolumeIndexForDevice(device);
	// mIndexCur.indexOfKey(device) < 0 表示mIndexCur没有该项
        device = Volume::getDeviceForVolume(device);
        return mIndexCur.indexOfKey(device) >= 0;

initializeVolumeCurves,解析配置文件的时候已经被初始化,不需要再初始化

void initializeVolumeCurves(bool /*isSpeakerDrcEnabled*/) {}

switchVolumeCurve, 用src流的mOriginVolumeCurves音量曲线替换dst的音量曲线

这样dst会暂时使用跟src流相同的音量曲线,dst的mOriginVolumeCurves音量曲线不变

virtual void switchVolumeCurve(audio_stream_type_t src流的, audio_stream_type_t dst)

restoreOriginVolumeCurve,从mOriginVolumeCurves音量曲线恢复该流的音量曲线

与switchVolumeCurve配合使用,用来回复switchVolumeCurve的修改

virtual void restoreOriginVolumeCurve(audio_stream_type_t stream)
{
	switchVolumeCurve(stream, stream);
}

4. 音量(衰减)的计算

         上层设置到AudioPolicy的音量是用户设置的音量值, 而底层把音量值转换成分贝值才能处理该音量。音量曲线的作用就是做这种转换。具体的转换流程在函数volIndexToDb内完成的。

1. 找到特定的音量曲线

传入的参数是:特定的流,特定的设备类型,需要计算的音量值。

因为音量的计算依赖于特定的音量曲线,需要根据stream,category找到该音量曲线,调用音量曲线的函数VolumeCurve::volIndexToDb

virtual float volIndexToDb(audio_stream_type_t stream, device_category cat, int indexInUi) const
	return getCurvesFor(stream).volIndexToDb(cat, indexInUi);
																														
float volIndexToDb(device_category deviceCat, int indexInUi) const
	return getCurvesFor(deviceCat)->volIndexToDb(indexInUi, mIndexMin, mIndexMax);
 2. 计算音量值对应的横坐标
      音量值和横坐标是线性关系, 所以计算的方法是
      (indexInUi - volIndexMin) / (volIndexMax - volIndexMin) * 100

      
// 传入特定流的音量最大值,最小值
float VolumeCurve::volIndexToDb(int indexInUi, int volIndexMin, int volIndexMax) const
{
	// 确定曲线的点的个数
    size_t nbCurvePoints = mCurvePoints.size();
    // 曲线两个端点横坐标的的差值,一般情况下是100
    int nbSteps = 1 + mCurvePoints[nbCurvePoints - 1].mIndex - mCurvePoints[0].mIndex;
    // 计算出横坐标
    if (indexInUi >= volIndexMin)
        volIdx = (nbSteps * (indexInUi - volIndexMin)) / (volIndexMax - volIndexMin);
3. 计算横坐标对应的分贝值(纵坐标)
    一般情况下,音量曲线包括三条线段,只需要先找到对应的线段,很容易根据线性关系算出音量值

    p[n-1].y + (x-p[n-1].x) * ( (p[n].y - p[n-1].y) / (p[n].x - p[n-1].x) )

AudioPolicy--音量的控制_第2张图片

    // 计算出横坐标在哪一条线段,即上面公式中的n
    size_t indexInUiPosition = mCurvePoints.orderOf(CurvePoint(volIdx, 0));
    // 如果横坐标大于最大值,使用最大的音量
    if (indexInUiPosition >= nbCurvePoints) {
        return mCurvePoints[nbCurvePoints - 1].mAttenuationInMb / 100.0f;
    }
    // 如果横坐标小于最小值,使用最小的音量
    if (indexInUiPosition == 0) {
        if (indexInUiPosition != mCurvePoints[0].mIndex) {
            return VOLUME_MIN_DB; // out of bounds
        }
        return mCurvePoints[0].mAttenuationInMb / 100.0f;
    }
    // 根据线性关系算出音量(衰减)
    // 因为配置文件中存入的值不是以dB为单位,所以计算过程中需要做“/100”的操作
    float decibels = (mCurvePoints[indexInUiPosition - 1].mAttenuationInMb / 100.0f) +
            ((float)(volIdx - mCurvePoints[indexInUiPosition - 1].mIndex)) *
                ( ((mCurvePoints[indexInUiPosition].mAttenuationInMb / 100.0f) -
                        (mCurvePoints[indexInUiPosition - 1].mAttenuationInMb / 100.0f)) /
                    ((float)(mCurvePoints[indexInUiPosition].mIndex -
                            mCurvePoints[indexInUiPosition - 1].mIndex)) );

5. 设置音量值的接口

setStreamVolumeIndex,设置特定流特定设备的音量
      其中参数device是AudioServer.java通过AudioSystem,AudioPlicy的接口 getStrategyForStream获得, 即Stream->Strategy->Device的方式, 这也是AudioPolicy获得设备的标准方式。

  1. 判断传入的参数
  2. 更新与传入的流,设备的音量值
  3. 遍历已经打开的所有的output,对所有的符合条件的output和流设置音量
具体的条件包括:
      (1) 该output中,请求的流必须正在播放,音量无法设置,很大情况下,都是该条件不符合
      (2) 判断请求的设备是否跟当前根据流类型获得的设备curStreamDevice相匹配
             因为两个设备获得的方式相同,如果设备不同,表示在设置音量的过程中, 已经切换了设备
      (3) OutPut的当前设备是否与请求的设备或者请求的设备的子设备相同
             子设备的情况考虑到了Duplicating的情况,不相同代表OutPut需要切换设备?

      (4) 如果请求的设备是默认设备,需要curStreamDevice没有音量配置

status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream,
						int index, audio_devices_t device)
    // 1. 判断传入的参数
    // 音量不可大于流的最大音量,小于最小音量值
    if ((index < mVolumeCurves->getVolumeIndexMin(stream)) ||
            (index > mVolumeCurves->getVolumeIndexMax(stream)))
        return BAD_VALUE;

    // 设备需要是输出设备
    if (!audio_is_output_device(device))
        return BAD_VALUE;

    // 如果传入的流不能被Mute, 强制使用该流的最高音量
    // canBeMuted,现在代码中,没有设置canBeMuted的接口,默认被设置为true
    if (!mVolumeCurves->canBeMuted的接口,默认被设置为true(stream)) index = mVolumeCurves->getVolumeIndexMax(stream);

    // 2. 更新与传入的流,设备的音量值
    for (int curStream = 0; curStream < AUDIO_STREAM_FOR_POLICY_CNT; curStream++) {
        // return (stream1 == stream2)
        if (!streamsMatchForvolume(stream, (audio_stream_type_t)curStream)) {
            continue;
        }
        // 更新特定流,特定设备的音量值
        mVolumeCurves->addCurrentVolumeIndex((audio_stream_type_t)curStream, device, index);
    }

    // 3. 遍历已经打开的所有的output,对所有的符合条件的output和流设置音量
    status_t status = NO_ERROR;
    for (size_t i = 0; i < mOutputs.size(); i++) {
        // 获得该output的配置信息
        sp desc = mOutputs.valueAt(i);
        // curDevice 是根据当前output使用的设备得出的
        // 其中主要对双设备做了处理,一般双设备只选取了speaker
        audio_devices_t curDevice = Volume::getDeviceForVolume(desc->device());
        for (int curStream = 0; curStream < AUDIO_STREAM_FOR_POLICY_CNT; curStream++) {
            // (1) 请求的流必须在当前output中Active(可以理解为正在播放)
            // 遍历所有的流,仅对跟请求的流符合的流(当前的代码下可以认为自有请求的流)
            if (!streamsMatchForvolume(stream, (audio_stream_type_t)curStream)) {
                continue;
            }
            // 判断流是不是Active
            if (!(desc->isStreamActive((audio_stream_type_t)curStream) ||
                (isInCall() && (curStream == AUDIO_STREAM_VOICE_CALL)))) {
            continue;
            }
            // (2) 判断请求的设备是否跟当前获得的设备匹配
            // 获得请求的流在当前场景下应该使用的设备
            routing_strategy curStrategy = getStrategy((audio_stream_type_t)curStream);
            audio_devices_t curStreamDevice = Volume::getDeviceForVolume(getDeviceForStrategy(
                 curStrategy, false /*fromCache*/));
            // 请求的设备跟curStreamDevice是否有相同的设备, 是否是默认设备
            // 如果两个条件都不符合,不会调整当前流的音量
            if ((device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) &&
                     ((curStreamDevice & device) == 0)) {
                continue;
            }
			
            bool applyVolume;
            // (3) OutPut的当前设备是否与请求的设备或者请求的设备的子设备相同
            if (device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) {
                curStreamDevice |= device;
                applyVolume = (curDevice & curStreamDevice) != 0;
            } else {
            // (4) 如果请求的设备是默认设备,需要curStreamDevice没有音量配置
                applyVolume = !mVolumeCurves->hasVolumeIndexForDevice(
                        stream, curStreamDevice);
            }

            if (applyVolume) {
                // 调用checkAndSetVolume应用该音量值
                status_t volStatus =
                         checkAndSetVolume((audio_stream_type_t)curStream, index, desc, curDevice,
                            (stream == AUDIO_STREAM_SYSTEM) ? TOUCH_SOUND_FIXED_DELAY_MS : 0);

6. 调节音量

        Audiopoicy真正通知Audofinger调节音量的接口是checkAndSetVolume。需要传入的参数主要包括stream,outputDesc,index,force。对于AudioFlinger来说每一个output对应一个播放线程。因为每个output所用输出设备会不同,所以对于不同output需要有不同的音量, 每一个output内可以同时支持多种流播放,每个output中不同的流需要与不同的音量值. 而一个output在当前只能使用同一个输出设备, 所以AudioFlinger只需要关心每个output中每个流的音量. 在每个output都有mCurVolume[stream]保存着该流音量的分贝值。

    接下来分析哪些因素会引起调节音量。首先是音量值的改变即主动调节音量setStreamVolumeIndex,其次就是设置静音setStreamMute。上面都是属于主动因素,接下来看一下被动因素,这里面主要就是输出设备的改变,可以导致输出设备改变的调用包括startOutput, stopOutput, setPhoneState, setDeviceConnectionState, setForceUse. 这些函数涉及到比较复杂的output和设备的管理。需呀逐个分析。这里暂时只分析checkAndSetVolume函数。

  1. 如果请求的流已经被Mute, 则不能调节该流的音量
  2. 判断AUDIO_STREAM_VOICE_CALL或AUDIO_POLICY_FORCE_BT_SCO的情况
  3. 如果传入的设备是空,使用output当前使用的音量
  4. 获得需要调节音量的分贝值
  5. 把音量传到AudioFlinger
  6. 计算并设置Voice的音量
status_t AudioPolicyManager::checkAndSetVolume(audio_stream_type_t stream,
                                                   int index,
                                                   const sp& outputDesc,
                                                   audio_devices_t device,
                                                   int delayMs,
                                                   bool force)
{
    // 1. 如果请求的流已经被Mute, 则不能调节该流的音量
    if (outputDesc->mMuteCount[stream] != 0) {
        return NO_ERROR;
    }
    // 2. 如果设置Forceuse SCO,不能设置AUDIO_STREAM_VOICE_CALL的音量、
    //    如果没有设置Forceuse SCO,不能设置AUDIO_STREAM_BLUETOOTH_SCO的音量
    //    AUDIO_STREAM_BLUETOOTH_SCO可以看作是是特殊的VOICE流,用于SCO通话
    audio_policy_forced_cfg_t forceUseForComm =
            mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION);
    if ((stream == AUDIO_STREAM_VOICE_CALL && forceUseForComm == AUDIO_POLICY_FORCE_BT_SCO) ||
        (stream == AUDIO_STREAM_BLUETOOTH_SCO && forceUseForComm != AUDIO_POLICY_FORCE_BT_SCO)) {
        return INVALID_OPERATION;
    }
    // 3. 如果传入的设备是空,使用output当前使用的音量
    // 有待分析 ???
    if (device == AUDIO_DEVICE_NONE) {
        device = outputDesc->device();
    }

    // 4. 获得需要调节音量的分贝值
    //  这里主要是调用volIndexToDb完成,另外还会这里还会针对一些特殊情况,调整获得音量
    //  代码中有很详尽的注释,不再具体分析
    float volumeDb = computeVolume(stream, index, device);

    // 5. 把音量传到AudioFlinger
    //  AudioFlinger是音量调节的执行者,AudioPolicy是决策者
    outputDesc->setVolume(volumeDb, stream, device, delayMs, force);

    // 6. 计算并设置Voice的音量
    // 对于Voice的数据不会经过AP侧,音量的调节一般需要在底层完成(Modem?)
    if (stream == AUDIO_STREAM_VOICE_CALL ||
        stream == AUDIO_STREAM_BLUETOOTH_SCO) {
        float voiceVolume;
        if (stream == AUDIO_STREAM_VOICE_CALL) {
            // 计算出Voice流的音量
            voiceVolume = (float)index/(float)mVolumeCurves->getVolumeIndexMax(stream);
        } else {
            // 对于AUDIO_STREAM_BLUETOOTH_SCO流,蓝牙侧会调节音量,所以这里会使用最大音量值
            voiceVolume = 1.0;
        }

        if (voiceVolume != mLastVoiceVolume) {
            // 直接调用AudioFinger的setVoiceVolume接口
            mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
            mLastVoiceVolume = voiceVolume;
SwAudioOutputDescriptor::setVolume把计算出来的音量float volume传到AudioFlinger
bool SwAudioOutputDescriptor::setVolume(float volume,
                                        audio_stream_type_t stream,
                                        audio_devices_t device,
                                        uint32_t delayMs,
                                        bool force)
    // 判断是否需要改变音量
    // 这里需要改变音量的条件是当前Outut的请求的流的音量已经改变
    // 或者force == true
    // 这里的mCurVolume只是区别流的音量,没有区别设备的音量,所以在切换设备的过程中,也会应用音量
    // 这里的原因大概是,一个output中所有的Track可能有不同的流类型,但是设备是相同的
    bool changed = AudioOutputDescriptor::setVolume(volume, stream, device, delayMs, force)
		return (volume != mCurVolume[stream] || force)
    if (changed) {
        // 把计算出的音量的衰减传入到AudioFnger
        // 分贝值转换为衰减,分贝值一般小于0, 所以这里计算出来的增益(理解为相对的电压值或压强值)是小于1的
        float volume = Volume::DbToAmpl(mCurVolume[stream]);
        // ???
        if (stream == AUDIO_STREAM_BLUETOOTH_SCO) {
            mClientInterface->setStreamVolume(
                    AUDIO_STREAM_VOICE_CALL, volume, mIoHandle, delayMs);
        }
        // 把音量传递给AudioFinger
        mClientInterface->setStreamVolume(stream, volume, mIoHandle, delayMs);
    }

你可能感兴趣的:(Android,Audio)