(No final conclusion) Why can't Android lower the call volume to the lowest level?

Take a look at the code flow:

The upper-level process has been analyzed before, you can refer to this:

https://blog.csdn.net/bberdong/article/details/51792319 (Sorry, I wrote too casually at that time)

Let's start with AudioPolicyManager::checkAndSetVolume:

status_t AudioPolicyManager::checkAndSetVolume(
    audio_stream_type_t stream,
    int index,
    const sp<AudioOutputDescriptor>& outputDesc,
    audio_devices_t device,
    int delayMs,
    bool force)
{
    ...
        if (stream == AUDIO_STREAM_VOICE_CALL ||
        stream == AUDIO_STREAM_BLUETOOTH_SCO) {
        float voiceVolume;
        // Force voice volume to max for bluetooth SCO as volume is managed by the headset
        if (stream == AUDIO_STREAM_VOICE_CALL) {
            voiceVolume = (float)index/(float)mVolumeCurves->getVolumeIndexMax(stream);
        } else {
            voiceVolume = 1.0;
        }
​
        if (voiceVolume != mLastVoiceVolume) {
            mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
            mLastVoiceVolume = voiceVolume;
        }
    }
    ...
}

Generally speaking volume is calculated according to index/maximum index, where does getVolumeIndexMax come from?

//AudioService.java
public class VolumeStreamState {
    private VolumeStreamState(String settingName, int streamType) {
        mIndexMin = MIN_STREAM_VOLUME[streamType] * 10;
            mIndexMax = MAX_STREAM_VOLUME[streamType] * 10;
            AudioSystem.initStreamVolume(streamType, mIndexMin / 10, mIndexMax / 10);
    }
}

MAX_STREAM_VOLUME[STREAM_VOICE_CALL] is calculated according to 100.

mIndexMax is equal to 1000. Then this call is equivalent to

AudioSystem.initStreamVolume(0,0,100)

Skip all the way and come to:

void AudioPolicyManager::initStreamVolume(audio_stream_type_t stream,
                                            int indexMin,
                                            int indexMax)
{
    ...
    mVolumeCurves->initStreamVolume(stream, indexMin, indexMax);
    ...
}

back to front

AUDIO_STREAM_VOICE_CALL则voiceVolume = index/100

AUDIO_STREAM_BLUETOOTH_SCO则voiceVolume = 1.0.

It seems that this voiceVolume is a coefficient.

We then traced the call to setVoiceVolume, skipping all the way, and came to

//audio_hw.c
static int adev_set_voice_volume(struct audio_hw_device *dev, float volume)                          
{
    int ret;
    struct audio_device *adev = (struct audio_device *)dev;
    pthread_mutex_lock(&adev->lock);
    /* cache volume */
    ret = voice_set_volume(adev, volume);
    pthread_mutex_unlock(&adev->lock);
    return ret;
}
​

The implementation of voice_set_volume is here (forgive me for searching, the result is the reason)

//voice.c
int voice_set_volume(struct audio_device *adev, float volume)
{
    //我们在探讨音量无法调到最小,所以这里volume姑且算0
    int vol, err = 0;
​
    adev->voice.volume = volume;
    if (adev->mode == AUDIO_MODE_IN_CALL) {
        if (volume < 0.0) {
            volume = 0.0;
        } else if (volume > 1.0) {
            volume = 1.0;
        }
​
        vol = lrint(volume * 100.0);
​
        // Voice volume levels from android are mapped to driver volume levels as follows.
        // 0 -> 5, 20 -> 4, 40 ->3, 60 -> 2, 80 -> 1, 100 -> 0
        // So adjust the volume to get the correct volume index in driver
        vol = 100 - vol;
​
        err = platform_set_voice_volume(adev->platform, vol);
    }
    //这个应该是voip通话?好像微信语音就走这个
    if (adev->mode == AUDIO_MODE_IN_COMMUNICATION)
        err = voice_extn_compress_voip_set_volume(adev, volume);
​
​
    return err;
}

The call here becomes:

platform_set_voice_volume(adev->platform,100);

Then look at the code:

int platform_set_voice_volume(void *platform, int volume)
{
    struct platform_data *my_data = (struct platform_data *)platform;
    struct audio_device *adev = my_data->adev;
    struct mixer_ctl *ctl;
    const char *mixer_ctl_name = "Voice Rx Gain";
    int vol_index = 0, ret = 0;
    uint32_t set_values[ ] = {0,
                              ALL_SESSION_VSID,
                              DEFAULT_VOLUME_RAMP_DURATION_MS};
​
    // Voice volume levels are mapped to adsp volume levels as follows.
    // 100 -> 5, 80 -> 4, 60 -> 3, 40 -> 2, 20 -> 1  0 -> 0
    // But this values don't changed in kernel. So, below change is need.
    //percent_to_index返回结果范围,从0到5
    vol_index = (int)percent_to_index(volume, MIN_VOL_INDEX, MAX_VOL_INDEX);
    set_values[0] = vol_index;
​
    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
    if (!ctl) {
        ALOGE("%s: Could not get ctl for mixer cmd - %s",
              __func__, mixer_ctl_name);
        return -EINVAL;
    }
    ALOGV("Setting voice volume index: %d", set_values[0]);
    mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));                                                                                                            
​
    if (my_data->csd != NULL) {
        ret = my_data->csd->volume(ALL_SESSION_VSID, volume,
                                   DEFAULT_VOLUME_RAMP_DURATION_MS);
        if (ret < 0) {
            ALOGE("%s: csd_volume error %d", __func__, ret);
        }
    }
    return ret;
}

The range of vol_index is from 0-5. (0 is the maximum value...), the next call is the interface of tinymix. Further down, I'm afraid. . .

It can only be said that the kernel layer is determined by adsp, and the call volume cannot be adjusted to the minimum. . . As for why this is done, there is still no answer!!!

Guess you like

Origin blog.csdn.net/bberdong/article/details/83068688