Android app 例子 : 获取流音量的dB值 及 android源码走读

要求api level 28 (android 9)

        AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        int minIndex = audioManager.getStreamMinVolume (STREAM_MUSIC);
        int maxIndex = audioManager.getStreamMaxVolume (STREAM_MUSIC);
        for(int i=minIndex; i<maxIndex; i++){
            float db = audioManager.getStreamVolumeDb(STREAM_MUSIC, i, AudioDeviceInfo.TYPE_BLUETOOTH_A2DP);
            Log.d(TAG, "volume db = " + db + "  at index= " + i);
        }

以下是枯燥的android源码走读, 用作记录, 有兴趣的话可以看看.

getStreamVolumeDb简单调用如下:

// frameworks/base/media/java/android/media/AudioManager.java
public float getStreamVolumeDb(@PublicStreamTypes int streamType, int index,
		@AudioDeviceInfo.AudioDeviceTypeOut int deviceType) {

    // ...
	final float gain = AudioSystem.getStreamVolumeDB(streamType, index,
			AudioDeviceInfo.convertDeviceTypeToInternalDevice(deviceType));
	// ...
}

进JNI:

// frameworks/base/media/java/android/media/AudioSystem.java
/** @hide */
public static native float getStreamVolumeDB(int stream, int index, int device);

frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
float AudioPolicyManager::getStreamVolumeDB(
        audio_stream_type_t stream, int index, audio_devices_t device)
{
    return computeVolume(getVolumeCurves(stream), toVolumeSource(stream), index, {device});
}

1.computeVolume负责数值转换,


// frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
float AudioPolicyManager::computeVolume(IVolumeCurves &curves,
                                        VolumeSource volumeSource,
                                        int index,
                                        const DeviceTypeSet& deviceTypes)
{
    float volumeDb = curves.volIndexToDb(Volume::getDeviceCategory(deviceTypes), index);

    // 删除了部分策略处理

    return volumeDb;
}

其中的volIndexToDb细节如下

// frameworks/av/services/audiopolicy/engine/common/src/VolumeCurve.cpp

float VolumeCurve::volIndexToDb(int indexInUi, int volIndexMin, int volIndexMax) const
{
    size_t nbCurvePoints = mCurvePoints.size();
    // the volume index in the UI is relative to the min and max volume indices for this stream
    int nbSteps = 1 + mCurvePoints[nbCurvePoints - 1].mIndex - mCurvePoints[0].mIndex;
    int volIdx = (nbSteps * (indexInUi - volIndexMin)) / (volIndexMax - volIndexMin);

    // Where would this volume index been inserted in the curve point
    size_t indexInUiPosition = mCurvePoints.orderOf(CurvePoint(volIdx, 0));
    if (indexInUiPosition >= nbCurvePoints) {
        //use last point of table
        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;
    }
    // linear interpolation in the attenuation table in dB
    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)) );

    return decibels;
}

2.getVolumeCurves获取音量曲线

// frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.h
IVolumeCurves &getVolumeCurves(audio_stream_type_t stream)
{
	auto *curves = mEngine->getVolumeCurvesForStreamType(stream);
	return *curves;
}


// frameworks/av/services/audiopolicy/engine/common/src/EngineBase.cpp
VolumeCurves *EngineBase::getVolumeCurvesForStreamType(audio_stream_type_t stream) const
{
    volume_group_t volGr = mProductStrategies.getVolumeGroupForStreamType(stream);
    if (volGr == VOLUME_GROUP_NONE) {
        volGr = mProductStrategies.getDefaultVolumeGroup();
    }
    const auto &iter = mVolumeGroups.find(volGr);
    return mVolumeGroups.at(volGr)->getVolumeCurves();
}

// frameworks/av/services/audiopolicy/engine/common/include/VolumeGroup.h
VolumeCurves *getVolumeCurves() { return &mGroupVolumeCurves; }
VolumeCurves mGroupVolumeCurves;

可以注意到其中是从VolumeGroup(s)中获取的, 而VolumeGroup中的VolumeCurves是在loadAudioPolicyEngineConfig时从audio policy的相关xml中作引擎参数载入的

frameworks/av/services/audiopolicy/engine/common/src/EngineBase.cpp
engineConfig::ParsingResult EngineBase::loadAudioPolicyEngineConfig()
{
    // 部分省略
    auto result = fileExists(engineConfig::DEFAULT_PATH) ?
            engineConfig::parse(engineConfig::DEFAULT_PATH) : engineConfig::ParsingResult{};
    if (result.parsedConfig == nullptr) {
        ALOGW("%s: No configuration found, using default matching phone experience.", __FUNCTION__);
        engineConfig::Config config = gDefaultEngineConfig;
        android::status_t ret = engineConfig::parseLegacyVolumes(config.volumeGroups);
        result = {std::make_unique<engineConfig::Config>(config),
                  static_cast<size_t>(ret == NO_ERROR ? 0 : 1)};
    } else {
        // ...
    }
}

其中的engineConfig::DEFAULT_PATH指向/vendor/etc/audio_policy_engine_configuration.xml

// frameworks/av/services/audiopolicy/engine/config/include/EngineConfig.h
/** Default path of audio policy usages configuration file. */
constexpr char DEFAULT_PATH[] = "/vendor/etc/audio_policy_engine_configuration.xml";

而如果没有这个文件的时候回去读传统的配置数据,

而其中最重要的指向是audio_policy_configuration.xml, 我们知道这个xml通常还会再包含一些相关的xml


//system/media/audio/include/system/audio_config.h
static inline std::string audio_get_audio_policy_config_file() {
    static constexpr const char *apmXmlConfigFileName = "audio_policy_configuration.xml";
    static constexpr const char *apmA2dpOffloadDisabledXmlConfigFileName =
            "audio_policy_configuration_a2dp_offload_disabled.xml";
    static constexpr const char *apmBluetoothLegacyHalXmlConfigFileName =
            "audio_policy_configuration_bluetooth_legacy_hal.xml";

    std::string audioPolicyXmlConfigFile;
    // First try alternative files if needed
    if (property_get_bool("ro.bluetooth.a2dp_offload.supported", false)) {
        if (property_get_bool("persist.bluetooth.bluetooth_audio_hal.disabled", false) &&
            property_get_bool("persist.bluetooth.a2dp_offload.disabled", false)) {
            // Both BluetoothAudio@2.0 and BluetoothA2dp@1.0 (Offload) are disabled, and uses
            // the legacy hardware module for A2DP and hearing aid.
            audioPolicyXmlConfigFile = audio_find_readable_configuration_file(
                    apmBluetoothLegacyHalXmlConfigFileName);
        } else if (property_get_bool("persist.bluetooth.a2dp_offload.disabled", false)) {
            // A2DP offload supported but disabled: try to use special XML file
            audioPolicyXmlConfigFile = audio_find_readable_configuration_file(
                    apmA2dpOffloadDisabledXmlConfigFileName);
        }
    } else if (property_get_bool("persist.bluetooth.bluetooth_audio_hal.disabled", false)) {
        audioPolicyXmlConfigFile = audio_find_readable_configuration_file(
                apmBluetoothLegacyHalXmlConfigFileName);
    }
    return audioPolicyXmlConfigFile.empty() ?
            audio_find_readable_configuration_file(apmXmlConfigFileName) : audioPolicyXmlConfigFile;
}

通常来说, audio_policy_configuration.xml中会这样引用一些附属文件


    <!-- Volume section -->

    <xi:include href="audio_policy_volumes.xml"/>
    <xi:include href="default_volume_tables.xml"/>

而audio_policy_volumes.xml文件中会包含下面这样的音频曲线数据

<volumes>
    <volume stream="AUDIO_STREAM_VOICE_CALL" deviceCategory="DEVICE_CATEGORY_HEADSET">
        <point>0,-4200</point>
        <point>33,-2800</point>
        <point>66,-1400</point>
        <point>100,0</point>
    </volume>

我粗略的理解是这表示, 最高0dB, 最低-42dB, 而中间还有两个节点, 行程一个折线式的volume table表.

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值