Android オーディオ hal との Bluetooth 電話 (hfp) の関連付け

話すときは、オーディオチャンネル、オーディオ機器(アップリンクとダウンリンクの両方)を開く必要があります

ここから始めます。

パッケージ/アプリ/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);
        }
    ...
}

2 つのシナリオがあります。1 つはコールが接続されている場合、もう 1 つはコールが保留中および保留解除されている場合です。すべて 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_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);
    ...
}

ハードウェア/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);
    ...
}

ハードウェア/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;
    }
    ...
}

このプロセスでは、合計 4 つのデバイスが pcm_open です。

hfpmod.hfp_ul_rx

hfpmod.hfp_ul_tx

hfpmod.hfp_dl_rx

hfpmod.hfp_dl_tx

次に、4 つの FE (フロントエンド) PCM を pcm_started しました。

これらの開いているパスは 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ルーティング機能を意味します。

つづく。. .

おすすめ

転載: blog.csdn.net/bberdong/article/details/82912670