AudioService.java
AudioSystem.java

1、Android音量的保存

存放到数据库

AudioHandler.persistVolume

private void persistVolume(VolumeStreamState streamState, int device) {
...
   System.putIntForUser(mContentResolver,
           streamState.getSettingNameForDevice(device),
           (streamState.getIndex(device) + 5)/ 10,
           UserHandle.USER_CURRENT);
...
}

VolumeStreamState .getSettingNameForDevice

public @Nullable String getSettingNameForDevice(int device) {
...
    final String suffix = AudioSystem.getOutputDeviceName(device);
...
    return mVolumeIndexSettingName + "_" + suffix;
}

mVolumeIndexSettingName 为初始化多个stream type的实例时给定,每个stream type的name不一样(根据System.VOLUME_SETTINGS_INT数组中返回)

AudioService.createStreamStates

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_INT[mStreamVolumeAlias[i]], i);
    }
}

System.java
在这里插入图片描述
在这里插入图片描述

        switch(getDeviceForVolume(deviceTypes)) {
        case AUDIO_DEVICE_OUT_EARPIECE:
            return DEVICE_CATEGORY_EARPIECE;
        case AUDIO_DEVICE_OUT_WIRED_HEADSET:
        case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
        case AUDIO_DEVICE_OUT_BLUETOOTH_SCO:
        case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
        case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
        case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
        case AUDIO_DEVICE_OUT_USB_HEADSET:
            return DEVICE_CATEGORY_HEADSET;
        case AUDIO_DEVICE_OUT_HEARING_AID:
            return DEVICE_CATEGORY_HEARING_AID;
        case AUDIO_DEVICE_OUT_LINE:
        case AUDIO_DEVICE_OUT_AUX_DIGITAL:
        case AUDIO_DEVICE_OUT_USB_DEVICE:
            return DEVICE_CATEGORY_EXT_MEDIA;
        case AUDIO_DEVICE_OUT_SPEAKER:
        case AUDIO_DEVICE_OUT_SPEAKER_SAFE:
        case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
        case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
        case AUDIO_DEVICE_OUT_USB_ACCESSORY:
        case AUDIO_DEVICE_OUT_REMOTE_SUBMIX:
        default:
            return DEVICE_CATEGORY_SPEAKER;

每个stream中的每个device的音量都是分开保存,
数据库的字串为: mVolumeIndexSettingName (System.VOLUME_SETTINGS_INT字符数组) + AudioSystem.getOutputDeviceName设备名称 。
例如:
Music 类型的speaker音量存储的string为:volume_music_speaker
Music 类型的hdmi arc音量存储的string为:volume_music_hmdi_arc
音量存储在android数据库的system区,可通过命令获取

settings list system |grep music

在这里插入图片描述

2、特殊音量

固定音量的设备

音量为最大或者0
mFixedVolumeDevices

// Devices for which the volume is fixed (volume is either max or muted)
Set<Integer> mFixedVolumeDevices = new HashSet<>(Arrays.asList(
       AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET,
       AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET,
       AudioSystem.DEVICE_OUT_HDMI_ARC,
       AudioSystem.DEVICE_OUT_AUX_LINE));

音量总是最大的设备

mFullVolumeDevices 

3、音量的加载

每个type拥有一个VolumeStreamState实例
在这里插入图片描述

private void createStreamStates() {
    int numStreamTypes = AudioSystem.getNumStreamTypes();
    // 加载多条type的音量实例
    VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
    for (int i = 0; i < numStreamTypes; i++) {
        streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS_INT[mStreamVolumeAlias[i]], i);
    }
    checkAllFixedVolumeDevices();
    checkAllAliasStreamVolumes();
    checkMuteAffectedStreams();
    updateDefaultVolumes();
}

创建实例时会将每一个type的各个device的音量加载到该实例的map mIndexMap中去

VolumeStreamState.readSettings

	for (int device : AudioSystem.DEVICE_OUT_ALL_SET) {
		// retrieve current volume for 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) ?
		       AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
		int index;
		if (!hasValidSettingsName()) {
		   index = defaultIndex;
		} else {
		   String name = getSettingNameForDevice(device);
		   index = Settings.System.getIntForUser(
		           mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
		}
		if (index == -1) {
		   continue;
		}
		mIndexMap.put(device, getValidIndex(10 * index, true /*hasModifyAudioSettings*/));
	}

4、音量设置

单板目录 /product/build.prop (Android R)
在这里插入图片描述
在这里插入图片描述

4.1、默认音量

开机起来AUDIO_STREAM_MUSIC的默认音量prop设置为,见上图

ro.config.media_vol_default

不配置该prop的逻辑处理如下:

int defaultMusicVolume = SystemProperties.getInt("ro.config.media_vol_default", -1);
if (defaultMusicVolume != -1 &&
        defaultMusicVolume <= MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] &&
        defaultMusicVolume >= MIN_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]) {
    AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = defaultMusicVolume;
} else {
    if (isPlatformTelevision()) {
        AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] =
                MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] / 4;
    } else {
        AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] =
                MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] / 3;
    }
}

4.2、最大音量

AUDIO_STREAM_MUSIC的UI可设置的最大音量prop为,见上图

ro.config.media_vol_steps

例如:UI可设置最大音量为0-100
在这里插入图片描述
不配置该prop的逻辑处理如下:

int maxMusicVolume = SystemProperties.getInt("ro.config.media_vol_steps", -1);
if (maxMusicVolume != -1) {
	MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = maxMusicVolume;
}

4、音量曲线

这里以AUDIO_STREAM_ACCESSIBILITY(10)类型的music在Speaker播放为例
hippoaudio是小编的sample可执行文件,-t后面的数字是type

在这里插入图片描述
则,使用的音量曲线为:通过/vendor/etc/audio_policy_volumes.xml查询可知,使用的为"DEFAULT_NON_MUTABLE_SPEAKER_VOLUME_CURVE"数组,路径为/vendor/etc/default_volume_tables.xml
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

float VolumeCurve::volIndexToDb(int indexInUi, int volIndexMin, int volIndexMax) const
{
    ALOG_ASSERT(!mCurvePoints.isEmpty(), "Invalid volume curve");
    if (volIndexMin < 0 || volIndexMax < 0) {
        // In order to let AudioService initialize the min and max, convention is to use -1
        return NAN;
    }
    ALOGI("[%s:%d]index:%d, min:%d, max:%d, dev:%d", __func__, __LINE__, indexInUi, volIndexMin, volIndexMax, mDeviceCategory);
    if (indexInUi < volIndexMin) {
        // an index of 0 means mute request when volIndexMin > 0
        if (indexInUi == 0) {
            ALOGV("VOLUME forcing mute for index 0 with min index %d", volIndexMin);
            return VOLUME_MIN_DB;
        }
        ALOGV("VOLUME remapping index from %d to min index %d", indexInUi, volIndexMin);
        indexInUi = volIndexMin;
    } else if (indexInUi > volIndexMax) {
        ALOGV("VOLUME remapping index from %d to max index %d", indexInUi, volIndexMax);
        indexInUi = volIndexMax;
    }

    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);
    ALOGI("[%s:%d] point_size:%d, nbSteps:%d,volIdx:%d max:%d, min:%d", __func__, __LINE__, nbCurvePoints, nbSteps, volIdx, mCurvePoints[nbCurvePoints - 1].mIndex,
        mCurvePoints[0].mIndex);

    // Where would this volume index been inserted in the curve point
    size_t indexInUiPosition = mCurvePoints.orderOf(CurvePoint(volIdx, 0));
    ALOGI("[%s:%d]indexInUiPosition:%d", __func__, __LINE__,
        indexInUiPosition);
    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)) );

    ALOGD("VOLUME vol index=[%d %d %d], dB=[%.1f %.1f %.1f]",
            mCurvePoints[indexInUiPosition - 1].mIndex, volIdx,
            mCurvePoints[indexInUiPosition].mIndex,
            ((float)mCurvePoints[indexInUiPosition - 1].mAttenuationInMb / 100.0f), decibels,
            ((float)mCurvePoints[indexInUiPosition].mAttenuationInMb / 100.0f));

    return decibels;
}
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐