Android调节音量分析

本文详细解析了Android系统的音量调节机制,从AudioManager的setStreamVolume方法开始,深入介绍了硬调音的实现方式,以及如何通过AudioFlinger进行PCM数据增益调整,并探讨了车机环境下使用CarAudioManager进行音量控制的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

音量调节接口

我们知道Android Audio的音量调节接口是通过AudioManager的setStreamVolume实现的,这个函数的实现在AudioService的setStreamVolume函数中,然后会调用到setStreamVolumeInt,这个函数首先通过streamState.setIndex发送音量调节的广播通知app更新UI。然后通过消息机制走到setDeviceVolume函数。注:如果要实现硬调音,也就是调节dsp音量不调节安卓音量,可以把config_useFixedVolume这个参数置为true。
我们简单分析一下setDeviceVolume函数

    /*package*/ void setDeviceVolume(VolumeStreamState streamState, int device) {

        final boolean isAvrcpAbsVolSupported = mDeviceBroker.isAvrcpAbsoluteVolumeSupported();

        synchronized (VolumeStreamState.class) {
            // Apply volume
            streamState.applyDeviceVolume_syncVSS(device, isAvrcpAbsVolSupported);

            // Apply change to all streams using this one as alias
            int numStreamTypes = AudioSystem.getNumStreamTypes();
            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
                if (streamType != streamState.mStreamType &&
                        mStreamVolumeAlias[streamType] == streamState.mStreamType) {
                    // Make sure volume is also maxed out on A2DP device for aliased stream
                    // that may have a different device selected
                    int streamDevice = getDeviceForStream(streamType);
                    if ((device != streamDevice) && isAvrcpAbsVolSupported
                            && ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
                        mStreamStates[streamType].applyDeviceVolume_syncVSS(device,
                                isAvrcpAbsVolSupported);
                    }
                    mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice,
                            isAvrcpAbsVolSupported);
                }
            }
        }
        // Post a persist volume msg
        sendMsg(mAudioHandler,
                MSG_PERSIST_VOLUME,
                SENDMSG_QUEUE,
                device,
                0,
                streamState,
                PERSIST_DELAY);

    }

首先是经过applyDeviceVolume_syncVSS函数走到AudioSystem.cpp的setStreamVolumeInt函数(这个后面再继续分析)。然后发送了一个MSG_PERSIST_VOLUME的消息,通过persistVolume函数把音量值存储到setting数据库中。

native层音量调节的实现

我们上面分析到会走到AudioSystem::setStreamVolumeIndex函数,这个函数通过binder最终走到AudioPolicyManager::setStreamVolumeIndex函数中,然后调用AudioPolicyManager::setVolumeIndexForAttributes函数,在这个函数中Android10.0的代码中已经有了组的概念,我们按照正常的流程往下走,会走到AudioPolicyManagerCustom::checkAndSetVolume函数中,然后这个函数会根据audiopolicy中的audio_policy_volumes.xml文件中配置的声音曲线调用computeVolume计算出一个volumeDb值,然后通过AudioOutputDescriptor::setVolume函数去set音量。这个函数通过setCurVolume函数调用mVolumeActivities[vs].setVolume(volumeDb),这个mVolumeActivities就是当前在这个output中活动的track,所以我们跟到了AudioTrack::setVolume函数,这个函数会调用mProxy->setVolumeLR函数

    void        setVolumeLR(gain_minifloat_packed_t volumeLR) {
        mCblk->mVolumeLR = volumeLR;
    }

通过上面的代码我们知道就是把现在的增益保存在mCblk->mVolumeLR中,看到mCblk我们就应该能联想到这是与audioflinger通信的环形buffer,所以使用这个音量的地方肯定在AudioFlinger中,我们去AudioFlinger中去找发现是prepareTracks_l函数通过proxy->getVolumeLR拿到的这个增益。我们知道AudioFlinger的threadLoop函数会不断的循环的调用prepareTracks_l函数去准备音频流和混音流的数据,在这里把audiopolicy设置的音量以及track的音量和master音量做一个计算(一般是相乘),所以现在AudioFlinger拿到的pcm数据就已经包含了修改的增益,然后通过threadLoop_wrtie函数把修改了增益的pcm数据写到hal层,到这里整个setStreamVolume的流程就分析完成了。
例:app1:混音数据1 = 音频数据1 * master_volume * stream1_volume * AudioTrack1_volume
app2:混音数据2 = 音频数据2 * master_volume * stream2_volume * AudioTrack2_volume

然而在车机上会有主副屏后排屏的概念,这时候我们可以使用CarAudioManager的setGroupVolume去set音量。

setGroupVolume的实现

setGroupVolume会走到setCurrentGainIndex函数然后把音量值存储到setting数据库中,然后会走到AudioManager的setAudioPortGain函数中

    public static int setAudioPortGain(AudioPort port, AudioGainConfig gain) {
        if (port == null || gain == null) {
            return ERROR_BAD_VALUE;
        }
        AudioPortConfig activeConfig = port.activeConfig();
        AudioPortConfig config = new AudioPortConfig(port, activeConfig.samplingRate(),
                                        activeConfig.channelMask(), activeConfig.format(), gain);
        config.mConfigMask = AudioPortConfig.GAIN;
        return AudioSystem.setAudioPortConfig(config);
    }

这个函数会把增益等一些参数封装到AudioPortConfig中然后调用AudioSystem.setAudioPortConfig函数,经过一系列的调用会走到AudioPolicyManager::setAudioPortConfig函数,然后通过binder等一系列封装调用会走到AudioFlinger::setAudioPortConfig函数中,最终会走到hal层audio_hw的adev_set_audio_port_config函数中去,最后的实现在auto_hal.c的auto_hal_set_audio_port_config函数中,最终会调用到kernel的set_volume函数中去。这样看来这条通路设置的应该就是dsp的音量,因为并没有修改到AudioFlinger中pcm数据的增益,这个函数留到后面仔细分析。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值