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!!!