昨天分析了一把snd_kcontrol,可以認爲上層應用的確是通過名稱標識name來遍歷底層的snd_kcontrol鏈表,從而找到相匹配的kcontrol。見snd_ctl_find_id函數
view plaincopy to clipboardprint?
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
/**
* 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;
}
/**
* 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;
}
今天繼續跟蹤Android音頻系統時,發現無論如何都找不到Android與snd_kcontrol的聯結點,無論是name還是numid(alsa_amixer controls打印出來的那個numid,即是內核層snd_kcontrol鏈表元素的numid)都找不到相關關鍵字。但是它確實可以進行調節音量等控制。後來我修改內核的Codec驅動,將音量控制的kcontrol.name換成其他字符串,重新編譯,Android還是可以進行音量控制。
看起來有點像是通過numid來控制的,《Android音頻HAL移植》一文有提到:“設備的切換就需要和驅動聯調。例如,目前earpiece的id爲10,那麼就可以通過ALSA的amixer設置earpiece的開和關,以及大小。而id的值就需要做驅動的同事提供。”但是還不能就此肯定。目前也沒有找到保存這些值的腳本文件。
--------------------------------------------------------------------------------
繼續以上問題,我在調節音量時,打印Codec寄存器的值,發現volume寄存器的值根本不會發生變化,但是音量確確實實是變化的。那時就在懷疑我們Android的音量調節不是通過硬件來實現的,而是有自身的sw mixer機制。晚上和Vic一起吃飯時,聊起這個,肯定了我的猜測。
view plaincopy to clipboardprint?
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
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;
}
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允許開發者在HAL層實現hw mixer,當AudioFlinger探測到存在hw mixer時,則調用mAudioHardware->setMasterVolume()對volume寄存器進行設置,也不會對volume值進行scale。至於sw mixer如何使用scale值的,我沒有深入探究。
以後實現hw mixer看看(反正到時也要實現EQ)效果,現在這個音量設置不是線性的,用硬件控制應該更好一點。
PS:標題就不用管它了,默認下Android根本不去找底層的kcontrol接口,而是使用自身的sw mixer。
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/sepnic/archive/2011/01/19/6152792.aspx