调试audio遇到的问题总结

平台: QSC60X0
参考文档: 80-V9137-1, 80-VH828-1, CL93-V6321-1, 80-VA552-11
参考代码: msmaud.h,  sndcal.c ,  voccal.c
工具: FIR/IIR滤波器调节工具---QFILT  

      本文主要是针对QSC60X0的音频调试,但是高通音频部分的原理都是大同小异的,所以对于其他平台也有借鉴作用。首先我们要熟悉平台的音频通路:

调试audio遇到的问题总结_第1张图片




一,音频通路说明
1.发送通路(TX)---表示本地到远端,即发送给对方的声音通路
      声音一开始是从MIC 进入,这里有2个MIC ,默认MIC1用于手机(handset),MIC2用于耳机(headset)。之后声音进过2个可选 增益的AP,注意第一个AP只能选择0db或+24db,而第二个AP的增益范围就大了很多,从-6db~+24db,步长1.5db。通过codec的 寄存器,可以选择AP的增益,以及使用哪个AP(全选,全不选,或则只用一个,另一个bypass)。经过ADC之后,有两个滤波器HPF和 SLOPE,HPF滤出120Hz以下信号,SLOPE会增强1kHz以上的高频信号。在进入QDSP前,有一个可编程增益CodecTxGain,范围 -84dB~12dB。这里还有直连到RX后级的侧音增益控制side_tone_gain。进入QDSP后,首先经过EC(回声消除器),然后经过 NS(噪声抑制器)和TX AGC,到这里声音信号已经达到最大信噪比。然后通过Tx PCM Filter,这是个FIR滤波器,根据自身的幅频和相频特性影响SFR(发送频响)。最后还有一级可编程增益TxVolume,也会影响到SLR(发送 响度)。

1.接收通路(RX)---表示远端到本地,即本地听到声音的通路
      与TX部分类似。需要补充一点,除图中所示外,SPEAKER还会在PMIC中进行最后一级放大,声音从MIC进来以后,流到CODEC,然 后从AUXOP,AUXON输出,流到SPKR_IN_M,SPKR_IN_P, 即进入PMIC,这时可以通过PMIC的API pm_set_speaker_gain(PM_SPKR_GAIN_PLUS12DB)定义增益大小(在sndhw_init()中),放大增益范围为 [-16,-12,-8,-4,0,4,8,12]dB ,最后通过SPKR_OUT_P,SPKR_OUT_M输出到喇叭。

二,音频校准
主要修改2个文件 sndcal.c ,voccal.c


1.先要理解两个常量,一个是voccal.c中的常量voc_pcm_on_chip_0_gsm_cal,结构如下:
typedef struct {
  voc_ec_type ec_mode;   /* Echo Cancellation mode    */
  voc_ns_type ns_enable;  /* Noise suppressor enable   */
  uint16 tx_gain;    /* TX Voice Volume           */
  uint16 dtmf_tx_gain;   /* TX DTMF gain              */
  uint16 codec_tx_gain;   /* CODEC TX gain             */
  uint16 codec_rx_gain;   /* CODEC RX gain             */
  uint16 codec_st_gain;   /* CODEC ST gain             */
  qdsp_cmd_pcm_filter_type tx_filter; /* TX PCM filter coefficients*/
  qdsp_cmd_pcm_filter_type rx_filter; /* RX PCM filter coefficients*/
  sint15 rx_dbm_offset;     /* RX offset in dBm          */
  qdsp_cmd_agc_param_type agc_param; /* AGC/AVC parameters        */
……
……
}voc_pcm_path_cal_type;
根据注释,很容易找到Tx Codec Gain, Tx Volume, Rx Codec Gain, ST Codec Gain, Tx PCM Filter, Rx PCM Filter。这里找到的Gain和Volume增益计算公式为:Gain(dB) = 20*LOG(Value/16384)。

2.另一个是Sndcal.c中的snd_cal_handset_voice_vol。平台默认为四级音量,数组的第一竖列就是每级音量对应Rx Volume的大小。
VOL_MEMORY snd_gen_level_voc_type snd_cal_handset_voice_vol[] = {
{ VOC_VOL_SILENCE , VOC_VOL_SILENCE ,  0 },
{    -1100  ,    -3400 ,  0 },
{     -500  ,     -3300 ,  0 },
{      100  ,     -3200 ,  0 },
{      700  ,     -3100 ,  0 }
};
Rx volume计算公式为:Value = 100* Gain(dB)。上例四级音量分别为-11,-5,1,7dB,最大音量7dB。需要说明的是每级音量至少间隔4dB,才能被人耳区分出来。

3. 对照音频的款图可以发现,以下参数可以调节:
Tx Volume     ---------voccal.c
Tx Codec Gain  ---------voccal.c
Rx Codec Gain  ---------voccal.c
ST Codec Gain  ---------voccal.c
Tx PCM Filter  ---------voccal.c
Rx PCM Filter ---------voccal.c
Rx Volume(max)  ---------snddcal.c

做过高通平台的msm7X27,msm7x27a,qrd8x25的audio驱动工作,关于android的audio流程网上可以查到很多内容,就总结下调试audio遇到的问题吧

这是整个audio tx,rx的流程。包括voice的,很清晰

一。关于耳机检测及耳机按键检测的问题

耳机插拔检测是靠一个GPIO管脚检测,有上拉电阻到vbat,没有插耳机为高电平,插入之后变低电平,报中断

对应的gpio配置code在hs_gpio_cfg_s.c, 详见数组hsi_gpio_info

关于OTHC,在qcom网站找到的解释是这样的

 The one-touch headset detection feature is supported through the HSET_BIAS pin. The internal hardware in this device performs actions
 based on the amount of current being drawn by the headset microphone. The HSET_BIAS output functions like a traditional microphone
 bias except that it has some additional features to support one-touch headset detection.

而事实上,这几个平台都不是OTHC的。

msm7X27,msm7x27a平台的耳机按键检测是adc读取值进行判断的,qrd8625我们是利用micbias的电流进行判断的

相关耳机插拔代码及键值上报code见hs_othc.c

二。关于audio部分

1。多媒体音量的调节

如果是提高声音,可以调整index值,降低音量的话,对计算出来的volume进行衰减就可以了

例如:衰减

if((stream == AudioSystem::MUSIC)  && (mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET))
    {
          volume = volume *0.30903;
    }

android2.3跟android4.0volume的计算方式有差别,android2.3不管是哪种模式哪种媒体流用的是同一种计算方法,而android4.0有分开处理,默认的情况下,音量的曲线都不是很好,音量低部分变化不明显,可以调整db/step

如在android4.0上

#if 0
const AudioPolicyManagerBase::VolumeCurvePoint
    AudioPolicyManagerBase::sDefaultMediaVolumeCurve[AudioPolicyManagerBase::VOLCNT] = {
    {1, -58.0f}, {20, -40.0f}, {60, -17.0f}, {100, 0.0f}
};
#else
const AudioPolicyManagerBase::VolumeCurvePoint
    AudioPolicyManagerBase::sDefaultMediaVolumeCurve[AudioPolicyManagerBase::VOLCNT] = {
    {1, -30.0f}, {20, -24.0f}, {60, -12.0f}, {100, 0.0f}
};
#endif

这是对media音量进行的调整,基本上是均匀变化的。基本思想就是,例如0.0f-(-12.0f)/100-60=(-12.0f)-(-24.0f)/60-20约等于-24.0f-(-30.f)/20-1

关于android音量控制,audioservice.java里定义了每种媒体流的音量等级

For example:
 /** @hide Maximum volume index values for audio streams */
/* private int[] MAX_STREAM_VOLUME = new int[] {
      7,  // STREAM_SYSTEM
      7,  // STREAM_RING
      15, // STREAM_MUSIC
      7,  // STREAM_ALARM
      7,  // STREAM_NOTIFICATION
      15, // STREAM_BLUETOOTH_SCO
      7,  // STREAM_SYSTEM_ENFORCED
      15, // STREAM_DTMF
      15  // STREAM_TTS
};*/

在audiomanager.java里设定每种媒体流默认音量级别

For example

/** @hide Default volume index values for audio streams*/
/* private int[]DEFAULT_STREAM_VALUE = new int[] {
      7,  // STREAM_SYSTEM
      7,  // STREAM_RING
      15, // STREAM_MUSIC
      7,  // STREAM_ALARM
      7,  // STREAM_NOTIFICATION
      15, // STREAM_BLUETOOTH_SCO
      7,  // STREAM_SYSTEM_ENFORCED
      15, // STREAM_DTMF
      15  // STREAM_TTS
};*/

2. adjust peaker ---ringtone or media

可以调节MBADRC 的band改变频响,这个调节的过程由硬件完成,硬件会给audiofilter.csv文件

The AudioFilter.csv file can be parsed in AudioHardware.cpp. The tuning parameters are pushed down to the ADSP when there is a device change.

       1: Speaker,

       2: Handset,

       3: Headset

3。连接蓝牙耳机,notification会断续,播ringtone的时候,speaker声音会断续,not smoothly

将a2dpUsedForSonification()改为false,声音就不会从蓝牙耳机里播放。产生这种断续现象的原因,在播放 notification or ringtone的时候,蓝牙跟speaker设备会同时打开,即使对于来电铃音来说蓝牙耳机会播放自己的提示音,但code里还是会把这个设备打开,蓝 牙工作的时候需要唤醒,当声音开始播放的时候,蓝牙跟蓝牙耳机的通信不是立刻建立。当播来电铃声的时候,来电铃声的数据会送到蓝牙协议栈,但是这部分数据 却没有送到蓝牙耳机播放,是怎么处理的不清楚,但是会影响到speaker播放ringtone

 

4.   C网来电,拒接,铃声突然变大

The audio is played at 48KHz sample-rate so ringtone is also played 48KHz.

On CDMA call, vocder is acquired during the ringtone playback so ringtone is played at 8KHz sample-rate.

This issue is presented on only CDMA call.

To avoid this issue, need to undifne "FEATURE_RX_VOICE_OVER_HOST_PCM" in custXXXXX.h file(=AMSS side).

5.点击开始录像,开始提示音响后会有兹兹声

playback跟capture动作切换造成

status_t AudioHardware::AudioStreamInMSM72xx::standby()

{

       //mHardware->clearCurDevice();
        //mHardware->doRouting(this);
       mHardware->doRouting(NULL);

}

 

二。voice部分

1。关于蓝牙打电话

由于qrd8625这个项目外挂了一个modem,着实被蓝牙打电话折腾够呛,初期评估了解的情况不足也是导致调试时间花费比较多的原因

首先高通的默认code是主芯片做pcm的master,提供时钟,而外挂的modem pcm口只能做slave,不能做master,那么就需要将BT PCM做master,这样才行进行通信,简直为难死人。提case给高通,确认BT可以做master后,开始着手调试。看到BT相关文件的那些tag 啊,都要崩溃了。还好经过有一个周吧,把pcm的主时钟给搞出来了,高通主芯片配成slave模式是有文档的,这个可以参照 80_VH558_1_D_AUX_PCM_MSM72xxA_MSM75xxA_MSM76xx_MSM7x27.pdf文档去配。

其实BT做master也很容易配。改的很简单,只是当时tag跟代码里对不上,用的蓝牙芯片是WCN2243

文件vender\qcom\proprietary\bt\hci_qcomm_init\btqsoncnvmtags.c

static bt_qsoc_cfg_cst_element_type bt_qsoc_cfg_tag_44_bha_b0[] = \
{
  0x2C, 0x01, 0x2C, 0x29,
  0x2F, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
  0xFF0x10, 0x02, 0x02, 0x01, 0x00, 0x14, 0x01,
  0x06, 0x28, 0xA0, 0x62, 0x03, 0x64, 0x01, 0x01,
  0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0,
  0xFF0x10, 0x02, 0x01, 0x00, 0x14, 0x01, 0x02,
  0x03
};

要是改成master,需要将0x10改成0x00,这个是配置BT PCM是做master还是slave的寄存器,0x50这个寄存器,0x01代表的时钟是25.6khz,这个详见spec了,然后0x50就是2048khz,这个就是pcm工作的时钟,帧同步信号是0xFF这个寄存器,FF代表了256分频,正好是8k,帧同步信号跟pcm数据的采样率一致。

接着就开始建立通话部分调试,上行有声音,下行没有声音,需要将主芯片的PCM口四根线PCM_CLK,PCM_ASYNC,PCM_IN,PCM_OUT配成高阻态,高阻态的配置只需要配成gpio无拉输入状态即可。

2。蓝牙打电话后手机完全没有声音

EVDO蓝牙打电话后,挂断电话手机完全没有声音,这个问题产生的原因就是BT PCMmaster,主芯片PCM slave造成的,再挂断电话时有个提示音没有播出来。从log看是申请不到内存,其实是能看到obtainBuffer timed out (is the CPU pegged?)这句log,后来高通给了patch,是在audio_out.c文件做的修改

将audio_write()函数中的进程睡眠唤醒方式做了修改

rc = wait_event_interruptible(audio->wait,
           (frame->used == 0) || (audio->stopped));

改成

rc = wait_event_interruptible_timeout(audio->wait,
           (frame->used == 0) || (audio->stopped),
           msecs_to_jiffies(2000));

3.主micbias,hp micbias都是可以在AP侧发rpc到cp请求使能or dis功能

主micbias enable/disable

adie_codec_write (ADIE_CODEC_EN3_R,       

                                       ADIE_CODEC_EN3_EN_MICBIAS_M,

                                       ADIE_CODEC_EN3_MICBIAS_ENA_V/ADIE_CODEC_EN3_MICBIAS_DIS_V);

hp micbias,有这样几种状态可以选择

typedef enum
{
    /**
     * Headset module off
     */
    PM_HSED_ENABLE_OFF,
    /**
     * enabled if TCXO signal is high
     */
    PM_HSED_ENABLE_TCXO,
    /**
     * enabled if PWM or TCXO signal is high
     */
    PM_HSED_ENABLE_PWM_TCXO,
    /**
     * enabled always
     */
    PM_HSED_ENABLE_ALWAYS,
    /**
     * Invalid selection, used for range checking in PMIC APIs
     */
    PM_HSED_ENABLE_TYPE__INVALID
}pm_hsed_enable_type;

4。录音声音小的问题

一是提高录的声音,二是提高播的声音,但是调整播放相关的增益会影响其他音频的输出,最好能提高录的声音

在android4.0+qrd8625上可以这样修改

可以增大codectxgain,tx volume

增大codectxgain

1 在vocdata.c

voc_data_codec_gain_ctrl_type* voc_data_get_codec_gain()
{
....

 if (voc_check_in_call())
    {
      voc_data_codec_gain.codec_st_gain = voc_data_pcm_cal_ptr->codec_st_gain;
    }
    else
    {
+  voc_data_codec_gain.codec_tx_gain =设置新的gain
   #if defined(T_MSM7x27A) || defined(T_MSM7x25A)
      if (voc_data_codec_inuse == VOC_CODEC_STEREO_HEADSET) {
        // Hack for power measurement 
        voc_data_codec_gain.codec_rx_gain = VOC_DATA_UNITY_GAIN;
      }
      
      .....


}

增大tx volume

1 在vocproc.c

vocproc_state_return_type vocproc_state_active (void)
{
....
+if(!voc_check_in_call())
+ vocproc_set_volume_normal();

return (VOCPROC_STATE_SUCCESS);
}

2

extern vocproc_status_type vocproc_set_volume()
{
...

if( voc_check_in_call() == FALSE ) {
      vocproc_vol.tx_comfort_noise_ena = QDSP_COMFORT_NOISE_DIS_V ;
+     vocproc_vol.tx_vol=设置新的gain
    }

}

 5。打开PGA通路

早期的FM通路是这样走的,qrd8625平台外挂modem电话免提模式是这样做的

ADIE register configurations are located in ...\services\adsp\msmaud.h

To enable AUX_PGA loopback, you should logical OR the existing register values with the following for the specific audio path that you are working with.

ADIE_CODEC_EN5_R/*0x39*/, MSMAUD_ADIE_CODEC_EN5_ENABLE_BANDGAP_AUXPGA_LR/*0x0C*/, \
ADIE_CODEC_C7B_R/*0x43*/, MSMAUD_ADIE_CODEC_C7B_AUX_PGA_RXP_L_R/*0x2F*/, \ 

#define MSMAUD_ADIE_CODEC_C7B_AUX_PGA_RXP_L_R \ 
( MSMAUD_ADIE_CODEC_C7B_INIT | \ 
ADIE_CODEC_C7B_AUX_PGA_RXP_L_SEL_V | \ 
ADIE_CODEC_C7B_AUX_PGA_RXP_R_SEL_V | \ 
ADIE_CODEC_C7B_AUX_PGA_RXM_L_SEL_V | \ 
ADIE_CODEC_C7B_AUX_PGA_RXM_R_SEL_V | \ 
ADIE_CODEC_C7B_AUX_PGA_VOCM_LOCAL_V ) 

ADIE_CODEC_C10_R/*0x46*/, /*must be configured for whatever output you're going through.  See the description for CODEC_C10 in the Software Interface Manual for your target*/

ADIE_CODEC_C10_R, (ADIE_CODEC_C10_HPH_L_ADD_LINEI_L_ENA_V        \
                             | ADIE_CODEC_C10_HPH_R_ADD_LINEI_R_ENA_V)

可以参考芯片sepc关于codec寄存器的配置说明

你可能感兴趣的:(audio)