hw mixer還是sw mixer實現setMasterVolume?

昨天分析了一把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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章