蓝牙电话(hfp)与Android audio hal的关联

转自https://blog.csdn.net/bberdong/article/details/82912670

 

通话的时候,需要打开音频通路,音频设备(上下行都要)

我们从这里开始:

packages/apps/Bluetooth/src/com/android/bluetooth/hfpclient

 
  1. // in Connected state

  2. private void processAudioEvent(int state, BluetoothDevice device) {

  3.   ...

  4.   switch (state) {

  5.           ...

  6.           case HeadsetClientHalConstants.AUDIO_STATE_CONNECTED:

  7.           routeHfpAudio(true);

  8.   }

  9. }

  10. private void acceptCall(int flag) {

  11.   ...

  12.    if (flag == BluetoothHeadsetClient.CALL_ACCEPT_HOLD) {

  13.            // When unholding a call over Bluetooth make sure to route audio.

  14.            routeHfpAudio(true);

  15.       }

  16.   ...

  17. }

两种场景,一个是接通电话,一个是电话hold之后,unhold的时候。都需要去调用routeHfpAudio(true).我们简化问题,只分析打开的情况。

 
  1. static synchronized void routeHfpAudio(boolean enable) {

  2.   ...

  3.        if (enable && !sAudioIsRouted) {

  4.            sAudioManager.setParameters("hfp_enable=true");

  5.       } else if (!enable) {

  6.            sAudioManager.setParameters("hfp_enable=false");

  7.       }

  8.   ...

  9.   }

直接跳过中间繁琐的调用分析,欢迎查看我之前的博客。我们直接来到这里(路径都懒得贴了,搞audio的都知道):

audio_hw.c

 
  1. static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)

  2. {

  3.   ...

  4.    struct str_parms *parms;

  5.   ...

  6.    //一猜就是通过等号把上面传下来的参数分割成对:hfp_enable,true

  7.    parms = str_parms_create_str(kvpairs);

  8.   ...

  9.    status = audio_extn_set_parameters(adev, parms);

  10.   ...

  11. }

hardware/qcom/audio/hal/audio_extn/audio_extn.c

 
  1. int audio_extn_set_parameters(struct audio_device *adev,

  2.                               struct str_parms *parms)

  3. {

  4.   ...

  5.    ret = audio_extn_hfp_set_parameters(adev, parms);

  6.   ...

  7. }

hardware/qcom/audio/hal/audio_extn/hfp.c

 
  1. int audio_extn_hfp_set_parameters(struct audio_device *adev, struct str_parms *parms)

  2. {

  3.   ...

  4.    //解析字符串参数

  5.    ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_ENABLE, value,

  6.                            sizeof(value));

  7.    if (ret >= 0) {                                                                                                                                                          

  8.           if ((!strncmp(value,"true",sizeof(value))) && (!hfpmod.is_hfp_running))

  9.               ret = start_hfp(adev,parms);

  10.           else if((!strncmp(value,"false",sizeof(value))) && (hfpmod.is_hfp_running))

  11.               stop_hfp(adev);

  12.           else {

  13.               ...

  14.           }

  15.   }

  16.   ...

  17.    //设置routing

  18.    ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING,

  19.                                value, sizeof(value));

  20.        if (ret >= 0) {

  21.            val = atoi(value);

  22.            if (val > 0)

  23.                select_devices(adev, hfpmod.ucid);

  24.       }

  25.    //设置hfp_volume

  26.    memset(value, 0, sizeof(value));

  27.    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_HFP_VOLUME,

  28.                            value, sizeof(value));

  29.    if (ret >= 0) {

  30.       ...

  31.        hfp_set_volume(adev, vol);

  32.   }

  33. }

也就是说routeHfpAudio的调用,最终对应着start_hfp和stop_hfp.

这里我们就看看start_hfp就好。

 
  1. static int32_t start_hfp(struct audio_device *adev,

  2.                         struct str_parms *parms __unused)

  3. {

  4.   ...

  5.    //直接来个usecase

  6.    struct audio_usecase *uc_uplink_info;

  7.    uc_uplink_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));

  8.    //初始化

  9.    uc_uplink_info->id = hfpmod.ucid;

  10.    uc_uplink_info->type = PCM_HFP_CALL;

  11.    uc_uplink_info->stream.out = adev->primary_output;

  12.    uc_uplink_info->devices = adev->primary_output->devices;

  13.    uc_uplink_info->in_snd_device = SND_DEVICE_NONE;

  14.    uc_uplink_info->out_snd_device = SND_DEVICE_NONE;

  15.    

  16.    list_add_tail(&adev->usecase_list, &uc_uplink_info->list);

  17.    //hfpmod.ucid 的值为

  18.    //USECASE_AUDIO_HFP_SCO_UPLINK(hfp_sco的上行链路的usecase)

  19.    //用这个usecase去选出设备

  20.    select_devices(adev, hfpmod.ucid);

  21.   ...

  22.    //获取pcm设备id

  23.    //上行 rx

  24.    pcm_ul_rx_id = platform_get_pcm_device_id(uc_uplink_info->id, PCM_PLAYBACK);

  25.    //上行 tx

  26.    pcm_ul_tx_id = platform_get_pcm_device_id(uc_uplink_info->id, PCM_CAPTURE);

  27.    pcm_dl_rx_id = platform_get_pcm_device_id(uc_downlink_info.id, PCM_PLAYBACK);

  28.    pcm_dl_tx_id = platform_get_pcm_device_id(uc_downlink_info.id, PCM_CAPTURE);

  29.   ...

  30.    //打开上行tx对应的pcm(一般是mic)

  31.    hfpmod.hfp_ul_tx = pcm_open(adev->snd_card,

  32.                                  pcm_ul_tx_id,

  33.                                  PCM_IN, &pcm_config_hfp);

  34.   ...

  35.   //另外三个打开操作类似

  36. }

audio_hw.c中可以查到:

USECASE_AUDIO_HFP_SCO_UPLINK对应的use_case_table名字:"hfp-sco"

platform.c中可以查到:

USECASE_AUDIO_HFP_SCO_UPLINK对应的hw_interface_table名字:

"QUAT_TDM_TX_0"

这些对应的mixer_paths.xml中都有:

 
  1. <path name="hfp-sco">  

  2.        <ctl name="QUAT_TDM_RX_2 Audio Mixer MultiMedia21" value="1" />

  3.        <ctl name="MultiMedia21 Mixer AUX_PCM_UL_TX" value="1" />

  4.        <ctl name="AUX_PCM_RX Audio Mixer MultiMedia6" value="1" />

  5.        <ctl name="MultiMedia6 Mixer QUAT_TDM_TX_0" value="1" />

  6.    </path>

还有这个pcm_config_hfp的定义:

 
  1. static struct pcm_config pcm_config_hfp = {

  2.   .channels = 1,

  3.   .rate = 8000,

  4.   .period_size = 240,

  5.   .period_count = 2,

  6.   .format = PCM_FORMAT_S16_LE,

  7.   .start_threshold = 0,

  8.   .stop_threshold = INT_MAX,

  9.   .avail_min = 0,

  10. };

估计普通电话也差不多,单声道,8k采样率(窄带,宽带是这个:

USECASE_AUDIO_HFP_SCO_WB_UPLINK),格式:PCM_FORMAT_S16_LE.

到这里为止,pcm设备就准备完毕,可以使用了!

那是什么时候开始使用这个pcm设备,调用pcm_read和pcm_write的呢?全局搜索了一遍也没看到,也没去调用audio_hw里的out_write!!!!.又仔细看了一遍start_hfp,难道是它:

 
  1. static int32_t start_hfp(struct audio_device *adev,

  2.                         struct str_parms *parms __unused)

  3. {

  4.   ...

  5.    hfpmod.hfp_ul_tx = pcm_open(adev->snd_card,

  6.                                  pcm_ul_tx_id,

  7.                                  PCM_IN, &pcm_config_hfp);

  8.   ...

  9.    if (pcm_start(hfpmod.hfp_ul_rx) < 0) {

  10.        ALOGE("%s: pcm start for hfp ul rx failed", __func__);

  11.        ret = -EINVAL;

  12.        goto exit;

  13.   }

  14.   ...

  15. }

这个过程中,总共pcm_open了四个设备:

hfpmod.hfp_ul_rx

hfpmod.hfp_ul_tx

hfpmod.hfp_dl_rx

hfpmod.hfp_dl_tx

然后pcm_start了这四个FE(前端) PCM.

tinymix中可以看到打开的通路有这些:

 
  1. 637 BOOL 1 QUAT_TDM_TX_0 Audio Mixer MultiMedia6   On

  2. 684 BOOL 1 QUAT_TDM_RX_2 Audio Mixer MultiMedia21   On

  3. 879 BOOL 1 MultiMedia6 Mixer QUAT_TDM_TX_0         On

  4. 987 BOOL 1 MultiMedia21 Mixer AUX_PCM_UL_TX         On

  5. 1027 BOOL 1 AUX_PCM_RX Audio Mixer MultiMedia6       On

第一路:"QUAT_TDM_TX_0 Audio Mixer MultiMedia6"

FE(前端)是MultiMedia6,BE(后端)是QUAT_TDM_TX_0,Audio Mixer表示DSP路由功能。

未完待续。。。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值