蓝牙电话(hfp)与Android audio hal的关联
转自https://blog.csdn.net/bberdong/article/details/82912670
通话的时候,需要打开音频通路,音频设备(上下行都要)
我们从这里开始:
packages/apps/Bluetooth/src/com/android/bluetooth/hfpclient
-
// in Connected state -
private void processAudioEvent(int state, BluetoothDevice device) { -
... -
switch (state) { -
... -
case HeadsetClientHalConstants.AUDIO_STATE_CONNECTED: -
routeHfpAudio(true); -
} -
} -
-
private void acceptCall(int flag) { -
... -
if (flag == BluetoothHeadsetClient.CALL_ACCEPT_HOLD) { -
// When unholding a call over Bluetooth make sure to route audio. -
routeHfpAudio(true); -
} -
... -
}
两种场景,一个是接通电话,一个是电话hold之后,unhold的时候。都需要去调用routeHfpAudio(true).我们简化问题,只分析打开的情况。
-
static synchronized void routeHfpAudio(boolean enable) { -
... -
if (enable && !sAudioIsRouted) { -
sAudioManager.setParameters("hfp_enable=true"); -
} else if (!enable) { -
sAudioManager.setParameters("hfp_enable=false"); -
} -
... -
}
直接跳过中间繁琐的调用分析,欢迎查看我之前的博客。我们直接来到这里(路径都懒得贴了,搞audio的都知道):
audio_hw.c
-
static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) -
{ -
... -
struct str_parms *parms; -
... -
//一猜就是通过等号把上面传下来的参数分割成对:hfp_enable,true -
parms = str_parms_create_str(kvpairs); -
... -
status = audio_extn_set_parameters(adev, parms); -
... -
}
hardware/qcom/audio/hal/audio_extn/audio_extn.c
-
int audio_extn_set_parameters(struct audio_device *adev, -
struct str_parms *parms) -
{ -
... -
ret = audio_extn_hfp_set_parameters(adev, parms); -
... -
}
hardware/qcom/audio/hal/audio_extn/hfp.c
-
int audio_extn_hfp_set_parameters(struct audio_device *adev, struct str_parms *parms) -
{ -
... -
//解析字符串参数 -
ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_ENABLE, value, -
sizeof(value)); -
if (ret >= 0) { -
if ((!strncmp(value,"true",sizeof(value))) && (!hfpmod.is_hfp_running)) -
ret = start_hfp(adev,parms); -
else if((!strncmp(value,"false",sizeof(value))) && (hfpmod.is_hfp_running)) -
stop_hfp(adev); -
else { -
... -
} -
} -
... -
//设置routing -
ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, -
value, sizeof(value)); -
if (ret >= 0) { -
val = atoi(value); -
if (val > 0) -
select_devices(adev, hfpmod.ucid); -
} -
//设置hfp_volume -
memset(value, 0, sizeof(value)); -
ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_HFP_VOLUME, -
value, sizeof(value)); -
if (ret >= 0) { -
... -
hfp_set_volume(adev, vol); -
} -
}
也就是说routeHfpAudio的调用,最终对应着start_hfp和stop_hfp.
这里我们就看看start_hfp就好。
-
static int32_t start_hfp(struct audio_device *adev, -
struct str_parms *parms __unused) -
{ -
... -
//直接来个usecase -
struct audio_usecase *uc_uplink_info; -
uc_uplink_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase)); -
//初始化 -
uc_uplink_info->id = hfpmod.ucid; -
uc_uplink_info->type = PCM_HFP_CALL; -
uc_uplink_info->stream.out = adev->primary_output; -
uc_uplink_info->devices = adev->primary_output->devices; -
uc_uplink_info->in_snd_device = SND_DEVICE_NONE; -
uc_uplink_info->out_snd_device = SND_DEVICE_NONE; -
-
list_add_tail(&adev->usecase_list, &uc_uplink_info->list); -
//hfpmod.ucid 的值为 -
//USECASE_AUDIO_HFP_SCO_UPLINK(hfp_sco的上行链路的usecase) -
//用这个usecase去选出设备 -
select_devices(adev, hfpmod.ucid); -
... -
//获取pcm设备id -
//上行 rx -
pcm_ul_rx_id = platform_get_pcm_device_id(uc_uplink_info->id, PCM_PLAYBACK); -
//上行 tx -
pcm_ul_tx_id = platform_get_pcm_device_id(uc_uplink_info->id, PCM_CAPTURE); -
pcm_dl_rx_id = platform_get_pcm_device_id(uc_downlink_info.id, PCM_PLAYBACK); -
pcm_dl_tx_id = platform_get_pcm_device_id(uc_downlink_info.id, PCM_CAPTURE); -
... -
//打开上行tx对应的pcm(一般是mic) -
hfpmod.hfp_ul_tx = pcm_open(adev->snd_card, -
pcm_ul_tx_id, -
PCM_IN, &pcm_config_hfp); -
... -
//另外三个打开操作类似 -
}
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中都有:
-
<path name="hfp-sco"> -
<ctl name="QUAT_TDM_RX_2 Audio Mixer MultiMedia21" value="1" /> -
<ctl name="MultiMedia21 Mixer AUX_PCM_UL_TX" value="1" /> -
<ctl name="AUX_PCM_RX Audio Mixer MultiMedia6" value="1" /> -
<ctl name="MultiMedia6 Mixer QUAT_TDM_TX_0" value="1" /> -
</path>
还有这个pcm_config_hfp的定义:
-
static struct pcm_config pcm_config_hfp = { -
.channels = 1, -
.rate = 8000, -
.period_size = 240, -
.period_count = 2, -
.format = PCM_FORMAT_S16_LE, -
.start_threshold = 0, -
.stop_threshold = INT_MAX, -
.avail_min = 0, -
};
估计普通电话也差不多,单声道,8k采样率(窄带,宽带是这个:
USECASE_AUDIO_HFP_SCO_WB_UPLINK),格式:PCM_FORMAT_S16_LE.
到这里为止,pcm设备就准备完毕,可以使用了!
那是什么时候开始使用这个pcm设备,调用pcm_read和pcm_write的呢?全局搜索了一遍也没看到,也没去调用audio_hw里的out_write!!!!.又仔细看了一遍start_hfp,难道是它:
-
static int32_t start_hfp(struct audio_device *adev, -
struct str_parms *parms __unused) -
{ -
... -
hfpmod.hfp_ul_tx = pcm_open(adev->snd_card, -
pcm_ul_tx_id, -
PCM_IN, &pcm_config_hfp); -
... -
if (pcm_start(hfpmod.hfp_ul_rx) < 0) { -
ALOGE("%s: pcm start for hfp ul rx failed", __func__); -
ret = -EINVAL; -
goto exit; -
} -
... -
}
这个过程中,总共pcm_open了四个设备:
hfpmod.hfp_ul_rx
hfpmod.hfp_ul_tx
hfpmod.hfp_dl_rx
hfpmod.hfp_dl_tx
然后pcm_start了这四个FE(前端) PCM.
tinymix中可以看到打开的通路有这些:
-
637 BOOL 1 QUAT_TDM_TX_0 Audio Mixer MultiMedia6 On -
684 BOOL 1 QUAT_TDM_RX_2 Audio Mixer MultiMedia21 On -
879 BOOL 1 MultiMedia6 Mixer QUAT_TDM_TX_0 On -
987 BOOL 1 MultiMedia21 Mixer AUX_PCM_UL_TX On -
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路由功能。
未完待续。。。