当前位置:   article > 正文

AudioPolicy--音量的控制_audio_policy_volumes.xml

audio_policy_volumes.xml

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

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

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

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

1. VolumeCurvesCollection

(1) IVolumeCurvesCollection

  1. IVolumeCurvesCollection *mVolumeCurves;
  2. mVolumeCurves = new VolumeCurvesCollection()

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

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

(2) VolumeCurvesCollection

  1. class VolumeCurvesCollection :
  2. public KeyedVector<audio_stream_type_t, VolumeCurvesForStream>,
  3. public IVolumeCurvesCollection

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

  1. class VolumeCurvesForStream : public KeyedVector<device_category, sp<VolumeCurve> >
  2. {
  3. private:
  4. KeyedVector<device_category, sp<VolumeCurve> > mOriginVolumeCurves;
  5. KeyedVector<audio_devices_t, int> mIndexCur; /**< current volume index per device. */
  6. int mIndexMin; /**< min volume index. */
  7. int mIndexMax; /**< max volume index. */
  8. bool mCanBeMuted; /**< true is the stream can be muted. */
  9. };

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

  1. private static int[] MAX_STREAM_VOLUME = new int[] {
  2. 5, // STREAM_VOICE_CALL
  3. 7, // STREAM_SYSTEM
  4. 7, // STREAM_RING
  5. 15, // STREAM_MUSIC
  6. 7, // STREAM_ALARM
  7. 7, // STREAM_NOTIFICATION
  8. 15, // STREAM_BLUETOOTH_SCO
  9. 7, // STREAM_SYSTEM_ENFORCED
  10. 15, // STREAM_DTMF
  11. 15, // STREAM_TTS
  12. 15 // STREAM_ACCESSIBILITY
  13. };
  14. private static int[] MIN_STREAM_VOLUME = new int[] {
  15. 1, // STREAM_VOICE_CALL
  16. 0, // STREAM_SYSTEM
  17. 0, // STREAM_RING
  18. 0, // STREAM_MUSIC
  19. 0, // STREAM_ALARM
  20. 0, // STREAM_NOTIFICATION
  21. 0, // STREAM_BLUETOOTH_SCO
  22. 0, // STREAM_SYSTEM_ENFORCED
  23. 0, // STREAM_DTMF
  24. 0, // STREAM_TTS
  25. 0 // STREAM_ACCESSIBILITY
  26. };
          mCanBeMuted 表示该流是否可以被Mute,现在代码环境下,都是ture。
     mIndexCur也是一个容器,下标是设备号audio_devices_t,元素是音量值(际调节的音量. 在VolumeCurvesCollection中,对于每个流每一个设备都保存着一个音量值。这样做的目的主要是可以存储不同设备的音量值,来满足用户对不同设备不同音量的需求。
      VolumeCurvesForStream继承了KeyedVector<device_category, sp<VolumeCurve> >,另外内部又有一个该容器类型的属性mOriginVolumeCurves。所以可以认为VolumeCurvesForStream内部有两个KeyedVector<device_category, sp<VolumeCurve> >类型的对象。其中mOriginVolumeCurves是原始值,不会被改变。KeyedVector<device_category, sp<VolumeCurve> >下标是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类设备的音量值到分贝值的转换关系。

  1. class VolumeCurve : public RefBase
  2. {
  3. private:
  4. SortedVector<CurvePoint> mCurvePoints;
  5. device_category mDeviceCategory;
  6. audio_stream_type_t mStreamType;
  7. };
  8. struct CurvePoint
  9. {
  10. uint32_t mIndex;
  11. int mAttenuationInMb;
  12. };

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

  1. <reference name="DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE">
  2. <!-- Default is Speaker Media Volume Curve -->
  3. <point>1,-5800</point>
  4. <point>20,-4000</point>
  5. <point>60,-1700</point>
  6. <point>100,0</point>
  7. </reference>

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

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

(1) 配置文件的结构

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

  1. <!-- In the filse default_volume_tables.xml -->
  2. <reference name="DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE">
  3. <!-- Default is Speaker Media Volume Curve -->
  4. <point>1,-5800</point>
  5. <point>20,-4000</point>
  6. <point>60,-1700</point>
  7. <point>100,0</point>
  8. </reference>
  9. <!-- In the filse audio_policy_volumes.xml -->
  10. <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_SPEAKER"
  11. ref="DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE"/>

(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
  1. AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface)
  2. // 1. 创建一个VolumeCurvesCollection对象
  3. mVolumeCurves = new VolumeCurvesCollection();
  4. // 2. 把mVolumeCurves对象传入AudioPolicyConfig的构造函数
  5. AudioPolicyConfig config(mHwModules, mAvailableOutputDevices, mAvailableInputDevices,
  6. mDefaultOutputDevice, speakerDrcEnabled,
  7. static_cast<VolumeCurvesCollection *>(mVolumeCurves));
  8. // 保存传入的mVolumeCurves对象
  9. config.mVolumeCurves = mVolumeCurves;
  10. // 3. 尝试解析Audiolicy的配置文件 audio_policy_configuration.xml
  11. deserializeAudioPolicyXmlConfig(config);
  12. // 依次尝试查找下面目录下的audio_policy_configuration.xml配置文件,
  13. // {"/odm/etc", "/vendor/etc/audio", "/vendor/etc", "/system/etc"};
  14. // audioPolicyXmlConfigFile = “audio_policy_configuration.xml”
  15. PolicySerializer serializer;
  16. serializer.deserialize(audioPolicyXmlConfigFile, config)
  17. // 4. 初始化 mVolumeCurves,在当前代码中initializeVolumeCurves没有做什么操作
  18. mVolumeCurves->initializeVolumeCurves(speakerDrcEnabled);

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

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

  1. status_t PolicySerializer::deserialize(const char *configFile, AudioPolicyConfig &config)
  2. // 解析文件xml文件,找到跟节点xmlNodePtr cur
  3. xml文件,DocPtr doc = xmlParseFile(configFile);
  4. xmlNodePtr cur = xmlDocGetRootElement(doc);
  5. // 调用 deserializeCollection 函数解析Volume类型的节点
  6. // 设置AudioPolicyConfig中的属性mVolumeCurves = volumes;
  7. VolumeTraits::Collection volumes;
  8. deserializeCollection<VolumeTraits>(doc, cur, volumes, &config);
  9. config.setVolumes(volumes);

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

  1. <volume stream="AUDIO_STREAM_VOICE_CALL" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
  2. ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
  3. <volume stream="AUDIO_STREAM_SYSTEM" deviceCategory="DEVICE_CATEGORY_HEADSET">
  4. <point>1,-3000</point>
  5. <point>33,-2600</point>
  6. <point>66,-2200</point>
  7. <point>100,-1800</point>
  8. </volume>
  1. status_t VolumeTraits::deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
  2. PtrSerializingCtx /*serializingContext*/)
  3. {
  4. // 解析 “stream” Tag
  5. string streamTypeLiteral = getXmlAttribute(root, Attributes::stream);
  6. audio_stream_type_t streamType;
  7. StreamTypeConverter::fromString(streamTypeLiteral, streamType);
  8. // 解析 “deviceCategory” Tag
  9. string deviceCategoryLiteral = getXmlAttribute(root, Attributes::deviceCategory);
  10. device_category deviceCategory;
  11. DeviceCategoryConverter::fromString(deviceCategoryLiteral, deviceCategory);
  12. // 解析 “ref” Tag
  13. string referenceName = getXmlAttribute(root, Attributes::reference);
  14. const _xmlNode *ref = NULL;
  15. if (!referenceName.empty()) {
  16. getReference<VolumeTraits>(root->parent, ref, referenceName);
  17. }
  18. element = new Element(deviceCategory, streamType);
  19. const xmlNode *child = referenceName.empty() ? root->xmlChildrenNode : ref->xmlChildrenNode;
  20. while (child != NULL) {
  21. if (!xmlStrcmp(child->name, (const xmlChar *)volumePointTag)) {
  22. xmlChar *pointDefinition = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);;
  23. // 解析 “point”
  24. Vector<int32_t> point;
  25. collectionFromString<DefaultTraits<int32_t> >((const char*)pointDefinition, point, ",");
  26. // 添加解析出来的 Point
  27. element->add(CurvePoint(point[0], point[1]));
  28. xmlFree(pointDefinition);
  29. }
  30. child = child->next;
  31. }
  32. }

3. IVolumeCurvesCollection 的接口

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

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

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

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

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

  1. bool canBeMuted(audio_stream_type_t stream)
  2. return getCurvesFor(stream).canBeMuted()
  3. // 返回 流的音量信息中的 mCanBeMuted
  4. // VolumeCurvesForStream.mCanBeMuted
  5. VolumeCurvesForStream::canBeMuted()
  6. return mCanBeMuted;

getVolumeIndexMin,获取该流的最小音量

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

  1. int getVolumeIndexMin(audio_stream_type_t stream)
  2. return getCurvesFor(stream).getVolumeIndexMin()
  3. // 返回 流的音量信息中的 mIndexMin
  4. // VolumeCurvesForStream.mIndexMin
  5. VolumeCurvesForStream::getVolumeIndexMin()
  6. return mIndexMin

getVolumeIndexMax,获取该流的最大音量

  1. int getVolumeIndexMax(audio_stream_type_t stream)
  2. return getCurvesFor(stream).getVolumeIndexMax()
  3. // 返回 流的音量信息中的 mIndexMax
  4. // VolumeCurvesForStream.mIndexMax
  5. VolumeCurvesForStream::getVolumeIndexMax()
  6. return mIndexMax

initStreamVolume,初始化特定流的VolumeCurvesForStream

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

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

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

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

返回VolumeCurvesForStream.mIndexCur.valueFor(device)

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

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

  1. virtual bool hasVolumeIndexForDevice(audio_stream_type_t stream,
  2. audio_devices_t device) const
  3. // VolumeCurvesForStream::hasVolumeIndexForDevice(device)
  4. return getCurvesFor(stream).hasVolumeIndexForDevice(device);
  5. // mIndexCur.indexOfKey(device) < 0 表示mIndexCur没有该项
  6. device = Volume::getDeviceForVolume(device);
  7. 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的修改

  1. virtual void restoreOriginVolumeCurve(audio_stream_type_t stream)
  2. {
  3. switchVolumeCurve(stream, stream);
  4. }

4. 音量(衰减)的计算

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

1. 找到特定的音量曲线

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

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

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

      
  1. // 传入特定流的音量最大值,最小值
  2. float VolumeCurve::volIndexToDb(int indexInUi, int volIndexMin, int volIndexMax) const
  3. {
  4. // 确定曲线的点的个数
  5. size_t nbCurvePoints = mCurvePoints.size();
  6. // 曲线两个端点横坐标的的差值,一般情况下是100
  7. int nbSteps = 1 + mCurvePoints[nbCurvePoints - 1].mIndex - mCurvePoints[0].mIndex;
  8. // 计算出横坐标
  9. if (indexInUi >= volIndexMin)
  10. 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) )


  1. // 计算出横坐标在哪一条线段,即上面公式中的n
  2. size_t indexInUiPosition = mCurvePoints.orderOf(CurvePoint(volIdx, 0));
  3. // 如果横坐标大于最大值,使用最大的音量
  4. if (indexInUiPosition >= nbCurvePoints) {
  5. return mCurvePoints[nbCurvePoints - 1].mAttenuationInMb / 100.0f;
  6. }
  7. // 如果横坐标小于最小值,使用最小的音量
  8. if (indexInUiPosition == 0) {
  9. if (indexInUiPosition != mCurvePoints[0].mIndex) {
  10. return VOLUME_MIN_DB; // out of bounds
  11. }
  12. return mCurvePoints[0].mAttenuationInMb / 100.0f;
  13. }
  14. // 根据线性关系算出音量(衰减)
  15. // 因为配置文件中存入的值不是以dB为单位,所以计算过程中需要做“/100”的操作
  16. float decibels = (mCurvePoints[indexInUiPosition - 1].mAttenuationInMb / 100.0f) +
  17. ((float)(volIdx - mCurvePoints[indexInUiPosition - 1].mIndex)) *
  18. ( ((mCurvePoints[indexInUiPosition].mAttenuationInMb / 100.0f) -
  19. (mCurvePoints[indexInUiPosition - 1].mAttenuationInMb / 100.0f)) /
  20. ((float)(mCurvePoints[indexInUiPosition].mIndex -
  21. 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没有音量配置

  1. status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream,
  2. int index, audio_devices_t device)
  3. // 1. 判断传入的参数
  4. // 音量不可大于流的最大音量,小于最小音量值
  5. if ((index < mVolumeCurves->getVolumeIndexMin(stream)) ||
  6. (index > mVolumeCurves->getVolumeIndexMax(stream)))
  7. return BAD_VALUE;
  8. // 设备需要是输出设备
  9. if (!audio_is_output_device(device))
  10. return BAD_VALUE;
  11. // 如果传入的流不能被Mute, 强制使用该流的最高音量
  12. // canBeMuted,现在代码中,没有设置canBeMuted的接口,默认被设置为true
  13. if (!mVolumeCurves->canBeMuted的接口,默认被设置为true(stream)) index = mVolumeCurves->getVolumeIndexMax(stream);
  14. // 2. 更新与传入的流,设备的音量值
  15. for (int curStream = 0; curStream < AUDIO_STREAM_FOR_POLICY_CNT; curStream++) {
  16. // return (stream1 == stream2)
  17. if (!streamsMatchForvolume(stream, (audio_stream_type_t)curStream)) {
  18. continue;
  19. }
  20. // 更新特定流,特定设备的音量值
  21. mVolumeCurves->addCurrentVolumeIndex((audio_stream_type_t)curStream, device, index);
  22. }
  23. // 3. 遍历已经打开的所有的output,对所有的符合条件的output和流设置音量
  24. status_t status = NO_ERROR;
  25. for (size_t i = 0; i < mOutputs.size(); i++) {
  26. // 获得该output的配置信息
  27. sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
  28. // curDevice 是根据当前output使用的设备得出的
  29. // 其中主要对双设备做了处理,一般双设备只选取了speaker
  30. audio_devices_t curDevice = Volume::getDeviceForVolume(desc->device());
  31. for (int curStream = 0; curStream < AUDIO_STREAM_FOR_POLICY_CNT; curStream++) {
  32. // (1) 请求的流必须在当前output中Active(可以理解为正在播放)
  33. // 遍历所有的流,仅对跟请求的流符合的流(当前的代码下可以认为自有请求的流)
  34. if (!streamsMatchForvolume(stream, (audio_stream_type_t)curStream)) {
  35. continue;
  36. }
  37. // 判断流是不是Active
  38. if (!(desc->isStreamActive((audio_stream_type_t)curStream) ||
  39. (isInCall() && (curStream == AUDIO_STREAM_VOICE_CALL)))) {
  40. continue;
  41. }
  42. // (2) 判断请求的设备是否跟当前获得的设备匹配
  43. // 获得请求的流在当前场景下应该使用的设备
  44. routing_strategy curStrategy = getStrategy((audio_stream_type_t)curStream);
  45. audio_devices_t curStreamDevice = Volume::getDeviceForVolume(getDeviceForStrategy(
  46. curStrategy, false /*fromCache*/));
  47. // 请求的设备跟curStreamDevice是否有相同的设备, 是否是默认设备
  48. // 如果两个条件都不符合,不会调整当前流的音量
  49. if ((device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) &&
  50. ((curStreamDevice & device) == 0)) {
  51. continue;
  52. }
  53. bool applyVolume;
  54. // (3) OutPut的当前设备是否与请求的设备或者请求的设备的子设备相同
  55. if (device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) {
  56. curStreamDevice |= device;
  57. applyVolume = (curDevice & curStreamDevice) != 0;
  58. } else {
  59. // (4) 如果请求的设备是默认设备,需要curStreamDevice没有音量配置
  60. applyVolume = !mVolumeCurves->hasVolumeIndexForDevice(
  61. stream, curStreamDevice);
  62. }
  63. if (applyVolume) {
  64. // 调用checkAndSetVolume应用该音量值
  65. status_t volStatus =
  66. checkAndSetVolume((audio_stream_type_t)curStream, index, desc, curDevice,
  67. (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的音量
  1. status_t AudioPolicyManager::checkAndSetVolume(audio_stream_type_t stream,
  2. int index,
  3. const sp<AudioOutputDescriptor>& outputDesc,
  4. audio_devices_t device,
  5. int delayMs,
  6. bool force)
  7. {
  8. // 1. 如果请求的流已经被Mute, 则不能调节该流的音量
  9. if (outputDesc->mMuteCount[stream] != 0) {
  10. return NO_ERROR;
  11. }
  12. // 2. 如果设置Forceuse SCO,不能设置AUDIO_STREAM_VOICE_CALL的音量、
  13. // 如果没有设置Forceuse SCO,不能设置AUDIO_STREAM_BLUETOOTH_SCO的音量
  14. // AUDIO_STREAM_BLUETOOTH_SCO可以看作是是特殊的VOICE流,用于SCO通话
  15. audio_policy_forced_cfg_t forceUseForComm =
  16. mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION);
  17. if ((stream == AUDIO_STREAM_VOICE_CALL && forceUseForComm == AUDIO_POLICY_FORCE_BT_SCO) ||
  18. (stream == AUDIO_STREAM_BLUETOOTH_SCO && forceUseForComm != AUDIO_POLICY_FORCE_BT_SCO)) {
  19. return INVALID_OPERATION;
  20. }
  21. // 3. 如果传入的设备是空,使用output当前使用的音量
  22. // 有待分析 ???
  23. if (device == AUDIO_DEVICE_NONE) {
  24. device = outputDesc->device();
  25. }
  26. // 4. 获得需要调节音量的分贝值
  27. // 这里主要是调用volIndexToDb完成,另外还会这里还会针对一些特殊情况,调整获得音量
  28. // 代码中有很详尽的注释,不再具体分析
  29. float volumeDb = computeVolume(stream, index, device);
  30. // 5. 把音量传到AudioFlinger
  31. // AudioFlinger是音量调节的执行者,AudioPolicy是决策者
  32. outputDesc->setVolume(volumeDb, stream, device, delayMs, force);
  33. // 6. 计算并设置Voice的音量
  34. // 对于Voice的数据不会经过AP侧,音量的调节一般需要在底层完成(Modem?)
  35. if (stream == AUDIO_STREAM_VOICE_CALL ||
  36. stream == AUDIO_STREAM_BLUETOOTH_SCO) {
  37. float voiceVolume;
  38. if (stream == AUDIO_STREAM_VOICE_CALL) {
  39. // 计算出Voice流的音量
  40. voiceVolume = (float)index/(float)mVolumeCurves->getVolumeIndexMax(stream);
  41. } else {
  42. // 对于AUDIO_STREAM_BLUETOOTH_SCO流,蓝牙侧会调节音量,所以这里会使用最大音量值
  43. voiceVolume = 1.0;
  44. }
  45. if (voiceVolume != mLastVoiceVolume) {
  46. // 直接调用AudioFinger的setVoiceVolume接口
  47. mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
  48. mLastVoiceVolume = voiceVolume;
SwAudioOutputDescriptor::setVolume把计算出来的音量float volume传到AudioFlinger
  1. bool SwAudioOutputDescriptor::setVolume(float volume,
  2.                                         audio_stream_type_t stream,
  3.                                         audio_devices_t device,
  4.                                         uint32_t delayMs,
  5.                                         bool force)
  6.     // 判断是否需要改变音量
  7.     // 这里需要改变音量的条件是当前Outut的请求的流的音量已经改变
  8.     // 或者force == true
  9.     // 这里的mCurVolume只是区别流的音量,没有区别设备的音量,所以在切换设备的过程中,也会应用音量
  10.     // 这里的原因大概是,一个output中所有的Track可能有不同的流类型,但是设备是相同的
  11.     bool changed = AudioOutputDescriptor::setVolume(volume, stream, device, delayMs, force)
  12. return (volume != mCurVolume[stream] || force)
  13.     if (changed) {
  14.         // 把计算出的音量的衰减传入到AudioFnger
  15.         // 分贝值转换为衰减,分贝值一般小于0, 所以这里计算出来的增益(理解为相对的电压值或压强值)是小于1的
  16.         float volume = Volume::DbToAmpl(mCurVolume[stream]);
  17.         // ???
  18.         if (stream == AUDIO_STREAM_BLUETOOTH_SCO) {
  19.             mClientInterface->setStreamVolume(
  20.                     AUDIO_STREAM_VOICE_CALL, volume, mIoHandle, delayMs);
  21.         }
  22.         // 把音量传递给AudioFinger
  23.         mClientInterface->setStreamVolume(stream, volume, mIoHandle, delayMs);
  24.     }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/499780
推荐阅读
相关标签
  

闽ICP备14008679号