通話的時候,需要打開音頻通路,音頻裝置(上下行都要)
我們從這裡開始:
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路由功能。
未完待續。。。