天天看點

Android 架構層錄音音量調節功能引入

    錄音音量安卓系統本身并未提供相關接口,同時錄音音量調節也需要硬體的支援。如果硬體支援,是可以實作的。share一下的我的方案。

先說一下思路,對于驅動來說,僅僅是調節相關ctl值就可以了。如此以來,可以看到和paly back的音量調節會有很大差別,play back調節音量,在policy startoutput時,會getVolume,音量的生效是在audioflinger 做mix時,将音量計算到音頻波形中。是以,對于錄音音量調節,我們需要把上層設定音量數值,直接給kernel就ok了。

1.來看驅動的支援

diff --git a/kernel/sound/soc/codecs/rk616_codec.c b/kernel/sound/soc/codecs/rk616_codec.c
index 831bb24..0d6949f 100755
--- a/kernel/sound/soc/codecs/rk616_codec.c
+++ b/kernel/sound/soc/codecs/rk616_codec.c
@@ -1940,6 +1940,14 @@ static const struct snd_kcontrol_new rk616_snd_path_controls[] = {
        */
        SOC_ENUM_EXT("Modem Input Enable", rk616_modem_input_type,
                rk616_modem_input_get, rk616_modem_input_put),
+        SOC_SINGLE_TLV("PGAL Capture Volume", RK616_PGAL_CTL,
+                RK616_PGA_VOL_SFT, 31, 0, pga_vol_tlv),//0x0a bit 5 is 0
+        {
+                .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PGAL Capture Switch", \
+                .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
+                .put = snd_soc_put_pgal_volsw, \
+                .private_value =  SOC_SINGLE_VALUE(RK616_PGAL_CTL, RK616_PGA_MUTE_SFT, 1, 1)
+        },
 };
           

2.HAL 層 通過setparameter 完成,記錄volume值,在inputstream open時,設定給ctl.

setParameter:  
  if (param.getInt(String8(SET_INPUT_VOLUME),cVolume) == NO_ERROR){
        if (openMixer_l() != NULL){
			ALOGV("WZ :SET_INPUT_VOLUME truth value: %d",cVolume);
            //caculate the truth input volume
            if (cVolume <= 0){
                cVolume = 0;
            }else if(cVolume >= 10){
                cVolume = 10;
            }
            if (cVolume == 0){
				ALOGV("SET_INPUT_VOLUME value: %d,we need mute",cVolume);
				//TODO: if future we can setInputVolume while recording,we need setMicMute here
				//setMicMute(true);
			}else{
			    //setMicMute(false);
                cVolume *= 3;
			}
            ALOGV("SET_INPUT_VOLUME truth value: %d",cVolume);
            struct mixer_ctl * cvCtrl = mixer_get_control(mMixer, "PGAL Capture Volume", 0);
            mixer_ctl_set_int(cvCtrl,(long long) cVolume);
			mInputVolume = cVolume;
        }else{
            ALOGE("WZ :SET_INPUT_VOLUME openMixer fail");
		}
    }
           

AudioInputStream::open_l

struct mixer_ctl * cvCtrl = mixer_get_control(mMixer, "PGAL Capture Volume", 0);
	mixer_ctl_set_int(cvCtrl,(long long) mHardware->mInputVolume);
    //adjust input stream volume, mute mic
    if (mHardware->mInputVolume == 0){
       setGain(0.0);
	}
           

3.關于架構層,兩個方面,一個是需要設定時在系統setting 資料庫中儲存,再一個在audioservice服務利用AudioSystem setparameter實作。

安卓本身音頻架構中,設定播放音量,AudioService :: setStreamVolumeIndex->AudioSystem->AudioPolicyService->AudioPolicy完成。

來看具體實作:

1)擷取音量:

/** @see AudioManager#getInputVolume() */
    public int getInputVolume(){
         readInputVolumeSettings();//從資料庫讀取
		 return mInputVolume;
    }
           

2)設定音量

/** @see AudioManager#setInputVolume(int) */
    public void setInputVolume(int index) {
        sendMsg(mAudioHandler,
	        MSG_PERSIST_SET_INPUT_VOLUME,
	        SENDMSG_QUEUE,
	        index,
	        0,
	        null,
	        0);
		AudioSystem.setParameters("set_input_volume="+index);
		mInputVolume = index;
		Log.d(TAG,"setInputVolume mInputVolume: " + index);
	}
           

再者就是,添加接口到frameworks/base/media/java/android/media/IAudioService.aidl,在audiomanager中為上層app提供接口,ok,架構層部分基本完成了。