An snd_kcontrol was analyzed yesterday. It can be considered that the upper-layer application uses the name to identify the name to traverse the underlying snd_kcontrol linked list and find the matched kcontrol. See snd_ctl_find_id Function
/** * snd_ctl_find_id - find the control instance with the given id * @card: the card instance * @id: the id to search * * Finds the control instance with the given id from the card. * * Returns the pointer of the instance if found, or NULL if not. * * The caller must down card->controls_rwsem before calling this function * (if the race condition can happen). */struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card, struct snd_ctl_elem_id *id){struct snd_kcontrol *kctl;if (snd_BUG_ON(!card || !id))return NULL;if (id->numid != 0)return snd_ctl_find_numid(card, id->numid);list_for_each_entry(kctl, &card->controls, list) {if (kctl->id.iface != id->iface)continue;if (kctl->id.device != id->device)continue;if (kctl->id.subdevice != id->subdevice)continue;if (strncmp(kctl->id.name, id->name, sizeof(kctl->id.name)))continue;if (kctl->id.index > id->index)continue;if (kctl->id.index + kctl->count <= id->index)continue;return kctl;}return NULL;}
When we continue to track the android audio system today, we find that no matter what the connection between Android and snd_kcontrol is found, whether it is the name or numid (numid printed by alsa_amixer controls, that is, the numid of the snd_kcontrol linked list element in the kernel layer. However, it can be used to adjust the volume. Later, I modified the codec driver of the kernel, changed the kcontrol. Name of the volume control to another string, and re-compiled it. Android can still control the volume.
It seems like it is controlled by numid. The article "android audio Hal porting" mentions: "device switching requires joint debugging with the driver. For example, if the current earpiece ID is 10, you can use amixer of ALSA to set the Enable and disable of earpiece and the size. The value of ID must be provided by the driving colleagues ." However, it cannot be confirmed. No script file is found to save these values.
When I adjusted the volume, I printed the codec register value and found that the volume register value did not change at all, but the volume actually changed. At that time, we suspected that our android volume adjustment was not implemented by hardware, but by its own SW mixer mechanism. When I had dinner with vic in the evening, I had a chat about it.
status_t AudioFlinger::setMasterVolume(float value){ // check calling permissions if (!settingsAllowed()) { return PERMISSION_DENIED; } // when hw supports master volume, don't scale in sw mixer AutoMutex lock(mHardwareLock); mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME; if (mAudioHardware->setMasterVolume(value) == NO_ERROR) { value = 1.0f; } mHardwareStatus = AUDIO_HW_IDLE; mMasterVolume = value; for (uint32_t i = 0; i < mPlaybackThreads.size(); i++) mPlaybackThreads.valueAt(i)->setMasterVolume(value); return NO_ERROR;}
Android allows developers to implement HW mixer at the Hal layer. When audioflinger detects the existence of HW mixer, it calls maudiohardware-> setmastervolume () to set the volume register, it does not scale the volume value. I have not explored how SW mixer uses the scale value in depth.
In the future, we will implement HW mixer to see the effect (EQ will also be implemented at that time). Now the volume setting is not linear and should be better controlled by hardware.
PS: You don't need to worry about the title. By default, Android does not look for the underlying kcontrol interface, but uses its own SW mixer.