Rockchip安卓11.0 16k wbs msbc HFP PCM语音通话支持

Rockchip安卓11.0 16k wbs/msbc HFP PCM语音通话支持

调试平台: 安卓11.0, rk3328, 博通ap6212芯片, HFP 8K已经调通的情况下.

SDK修改支持16k wbs/msbc HFP PCM语音注意点如下:

1. bluedroid(system/bt)

博通方案中, ESCO_DATA_PATH_PCM 为1代表蓝牙芯片作为pcm master, 6作为pcm slave.

因为Host系统作为pcm master, ap6212作为slave. 默认使用HCI_Enhanced_Setup_Synchronous_Connection, 所以修改如下:

diff --git a/device/include/esco_parameters.h b/device/include/esco_parameters.h
-#define ESCO_DATA_PATH_PCM 1                /* 0x01-0xFE (PCM Chan) */
+#define ESCO_DATA_PATH_PCM 6                /* 0x01-0xFE (PCM Chan) */   

另外,检查以下配置, DISABLE_WBS已经被设置为FALSE, BTA_HF_CLIENT_FEAT_CODEC有被设置.

diff --git a/internal_include/bt_target.h b/internal_include/bt_target.h
+#undef DISABLE_WBS
 #ifndef DISABLE_WBS
 #define DISABLE_WBS FALSE
 #endif
diff --git a/btif/src/btif_hf.cc b/btif/src/btif_hf.cc
index 583421a7a..de0e3dbd5 100755
--- a/btif/src/btif_hf.cc
+++ b/btif/src/btif_hf.cc
@@ -81,7 +81,7 @@ namespace headset {
 #define BTIF_HF_FEATURES                                       \
   (BTA_AG_FEAT_3WAY | BTA_AG_FEAT_ECNR | BTA_AG_FEAT_REJECT |  \
    BTA_AG_FEAT_ECS | BTA_AG_FEAT_EXTERR | BTA_AG_FEAT_VREC |   \
-   /*BTA_AG_FEAT_CODEC |*/ BTA_AG_FEAT_HF_IND | BTA_AG_FEAT_ESCO | \
+   BTA_AG_FEAT_CODEC | BTA_AG_FEAT_HF_IND | BTA_AG_FEAT_ESCO | \
    BTA_AG_FEAT_UNAT)
 #endif

2. kernel

2.1 dts

因16k时, 博通要求BCLK要是512M, 所以做如下修改:

diff --git a/arch/arm64/boot/dts/rockchip/rk3328-evb-android-natrium.dts b/arch/arm64/boot/dts/rockchip/rk3328-evb-android-natrium.dts
&i2s2{
        #sound-dai-cells = <0>;
-       /* rockchip,bclk-fs = <64>; */
+       rockchip,bclk-fs = <32>;
        rockchip,clk-trcm = <1>;
        pinctrl-0 = <&i2s2m0_sclk
                             &i2s2m0_lrcktx
@@ -81,3 +81,40 @@
        };
 };

另外, 上述rockchip,clk-trcm = <1>; 代表TX/RX 逻辑同步,共享 TX 的时钟,IO上只有 TX 的时钟. 默认0表示各自使用各自时钟. 2表示共享RX时钟. 这里是其他芯片没有为自身提供clk的能力,所以使用TX时钟.

2.2 sound

主要是kernel要支持16K采样率.

diff --git a/sound/soc/codecs/bt-sco.c b/sound/soc/codecs/bt-sco.c
index d07d7be7710d..cfeae64b1d66 100644
--- a/sound/soc/codecs/bt-sco.c
+++ b/sound/soc/codecs/bt-sco.c
@@ -32,14 +32,14 @@ static struct snd_soc_dai_driver bt_sco_dai[] = {
                        .stream_name = "Playback",
                        .channels_min = 1,
                        .channels_max = 2,
-                       .rates = SNDRV_PCM_RATE_8000,
+                       .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
                        .formats = SNDRV_PCM_FMTBIT_S16_LE,
                },
                .capture = {
                         .stream_name = "Capture",
                        .channels_min = 1,
                        .channels_max = 2,
-                       .rates = SNDRV_PCM_RATE_8000,
+                       .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
                        .formats = SNDRV_PCM_FMTBIT_S16_LE,
                },
        },

3. hardware/rockchip/audio

支持16-8K动态切换. 打包的代码详见redmine #.

commit  (HEAD)
Author: 
Date:   

    1.add 16k wbs pcm support for btsco. it can dynamic change from 8k<->16k.
    2.change 44100 to 48000, for audio mode to 8k/16k.

diff --git a/tinyalsa_hal/audio_hw.c b/tinyalsa_hal/audio_hw.c
index 605c4b2..441f5f0 100755
--- a/tinyalsa_hal/audio_hw.c
+++ b/tinyalsa_hal/audio_hw.c
@@ -879,7 +879,7 @@ static int start_output_stream(struct stream_out *out)
 
     out_dump(out, 0);
 
-    if (out->device & AUDIO_DEVICE_OUT_AUX_DIGITAL/* && !out->device & AUDIO_DEVICE_OUT_ALL_SCO*/) {
+    if (out->device & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
         audio_devices_t route_device = out->device & AUDIO_DEVICE_OUT_AUX_DIGITAL;
         route_pcm_card_open(adev->dev_out[SND_OUT_SOUND_CARD_HDMI].card, getRouteFromDevice(route_device));
 
@@ -965,12 +965,15 @@ static int start_output_stream(struct stream_out *out)
     if (out->device & AUDIO_DEVICE_OUT_ALL_SCO) {
         card = adev->dev_out[SND_OUT_SOUND_CARD_BT].card;
         device = adev->dev_out[SND_OUT_SOUND_CARD_BT].device;
-        ALOGD("pcm_open bt card number = %d, device=%d",card, device);
+        struct pcm_config *pcm_config = &pcm_config_ap_sco;
+        pcm_config->rate = adev->bt_wb_speech_enabled?16000:8000;
+
+        ALOGD("%s pcm_open bt card number = %d, device=%d, src rate: %d dest rate:%d, wbs:%d", __func__, card, device, out->config.rate, pcm_config->rate, adev->bt_wb_speech_enabled);;
         if(card != (int)SND_OUT_SOUND_CARD_UNKNOWN) {
         out->pcm[SND_OUT_SOUND_CARD_BT] = pcm_open(card, device,
-                                    PCM_OUT | PCM_MONOTONIC, &pcm_config_ap_sco);
+                                    PCM_OUT | PCM_MONOTONIC, pcm_config);
         ret = create_resampler(out->config.rate,
-                               pcm_config_ap_sco.rate,
+                               pcm_config->rate,
                                2,
                                RESAMPLER_QUALITY_DEFAULT,
                                NULL,
@@ -1150,6 +1153,9 @@ static int start_input_stream(struct stream_in *in)
     if ((in->device & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) &&
             (adev->mode == AUDIO_MODE_IN_COMMUNICATION)) {
         in->config = &pcm_config_in_bt;
+
+        in->config->rate = adev->bt_wb_speech_enabled?16000:8000;
+
         card = adev->dev_in[SND_IN_SOUND_CARD_BT].card;
         device =  adev->dev_in[SND_IN_SOUND_CARD_BT].device;
         if(card != SND_IN_SOUND_CARD_UNKNOWN){
@@ -1160,7 +1166,8 @@ static int start_input_stream(struct stream_in *in)
                 in->buf_provider.get_next_buffer = get_next_buffer;
                 in->buf_provider.release_buffer = release_buffer;
 
-                ret = create_resampler(8000,
+                ALOGE("%s: %d,src rate:%d, dest(in->requested_rate) = %d",__FUNCTION__,__LINE__,in->config->rate, in->requested_rate);
+                ret = create_resampler(in->config->rate,//8000,
                                        in->requested_rate,
                                        audio_channel_count_from_in_mask(in->channel_mask),
                                        RESAMPLER_QUALITY_DEFAULT,
@@ -1648,6 +1655,7 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
         val = atoi(value);
         /* Don't switch HDMI audio in box products */
         if ((val != 0) && ((out->device & val) != val) ||
+            (val != 0) && (val & AUDIO_DEVICE_OUT_ALL_SCO) ||
             (val != 0) && !(out->device & AUDIO_DEVICE_OUT_HDMI)) {
             /* Force standby if moving to/from SPDIF or if the output
              * device changes when in SPDIF mode */
@@ -1659,7 +1667,8 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
 
             /* force output standby to start or stop SCO pcm stream if needed */
             if ((val & AUDIO_DEVICE_OUT_ALL_SCO) ^
-                    (out->device & AUDIO_DEVICE_OUT_ALL_SCO)) {
+                    (out->device & AUDIO_DEVICE_OUT_ALL_SCO)||adev->bt_sco_reroute) {
+                adev->bt_sco_reroute = 0;
                 do_out_standby(out);
             }
 
@@ -2165,10 +2174,12 @@ false_alarm:
                 if (i == SND_OUT_SOUND_CARD_BT) {
                     // HARD CODE FIXME 48000 stereo -> 8000 stereo
                     size_t inFrameCount = bytes/2/2;
-                    size_t outFrameCount = inFrameCount/6;
+                    int destRate = out->config.rate;//48000;
+                    int srcRate = adev->bt_wb_speech_enabled? 16000:8000;//16000:8000;
+                    int coefficient = (destRate/srcRate);
+                    size_t outFrameCount = inFrameCount/coefficient;
                     int16_t out_buffer[outFrameCount*2];
                     memset(out_buffer, 0x00, outFrameCount*2);
-
                     out->resampler->resample_from_input(out->resampler,
                                                         (const int16_t *)buffer,
                                                         &inFrameCount,
@@ -3276,6 +3287,21 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
         }
     }
 
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_BT_SCO_WB, value, sizeof(value));
+    if (ret >= 0) {
+        adev->bt_wb_speech_enabled = !strcmp(value, AUDIO_PARAMETER_VALUE_ON);
+        ALOGD("%s: adev:0x%p, bt_wb_speech_enabled = %d", __func__, adev, adev->bt_wb_speech_enabled);
+    }
+
+    ret = str_parms_get_str(parms, "BT_SCO", value, sizeof(value));
+    if (ret >= 0) {
+        adev->bt_sco_reroute ^= !strcmp(value, AUDIO_PARAMETER_VALUE_ON);
+        if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) != 0){
+            adev->bt_wb_speech_enabled = false;
+        }
+    }
+    ALOGD("%s:bt_wb_speech_enabled = %d, sco reroute=%u", __func__, adev->bt_wb_speech_enabled, adev->bt_sco_reroute);
+
 #ifdef AUDIO_BITSTREAM_REOPEN_HDMI
     // hdmi reconnect
     ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_CONNECT, // hdmi reconnect
@@ -3588,6 +3614,7 @@ static int adev_open_input_stream(struct audio_hw_device *dev,
 #ifdef BT_AP_SCO
     if (adev->mode == AUDIO_MODE_IN_COMMUNICATION && in->device & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
         pcm_config = &pcm_config_in_bt;
+        pcm_config->rate = adev->bt_wb_speech_enabled? 16000:8000;
     }
 #endif
 
@@ -3606,11 +3633,13 @@ static int adev_open_input_stream(struct audio_hw_device *dev,
         goto err_malloc;
     }
 
-    if ((in->requested_rate != 0) && (in->requested_rate != pcm_config->rate)) {
+    ALOGD("pcm_config->rate:%d! in->requested_rate:%d", pcm_config->rate, in->requested_rate);
+
+    if ((in->requested_rate != 0) && ((in->requested_rate != pcm_config->rate))) {
         in->buf_provider.get_next_buffer = get_next_buffer;
         in->buf_provider.release_buffer = release_buffer;
 
-        ALOGD("pcm_config->rate:%d,in->requested_rate:%d,in->channel_mask:%d",
+        ALOGD("src(pcm_config->rate):%d, dest(in->requested_rate):%d,in->channel_mask:%d",
               pcm_config->rate,in->requested_rate,audio_channel_count_from_in_mask(in->channel_mask));
         ret = create_resampler(pcm_config->rate,
                                in->requested_rate,
@@ -3838,6 +3867,10 @@ static int adev_open(const hw_module_t* module, const char* name,
     //route_init();
     /* adev->cur_route_id initial value is 0 and such that first device
      * selection is always applied by select_devices() */
+
+    adev->bt_wb_speech_enabled = false;
+    adev->bt_sco_reroute = false;
+
     *device = &adev->hw_device.common;
 
     adev_open_init(adev);
diff --git a/tinyalsa_hal/audio_hw.h b/tinyalsa_hal/audio_hw.h
old mode 100644
new mode 100755
index 1f8c785..f23f529
--- a/tinyalsa_hal/audio_hw.h
+++ b/tinyalsa_hal/audio_hw.h
@@ -112,7 +112,7 @@
 #ifdef BOX_HAL
 struct pcm_config pcm_config = {
     .channels = 2,
-    .rate = 44100,
+    .rate = 48000,
     .period_size = 512,
     .period_count = 3,
     .format = PCM_FORMAT_S16_LE,
@@ -120,7 +120,7 @@ struct pcm_config pcm_config = {
 
 struct pcm_config pcm_config_in = {
     .channels = 2,
-    .rate = 44100,
+    .rate = 48000,
     .period_size = 1024,
     .period_count = 4,
     .format = PCM_FORMAT_S16_LE,
@@ -144,7 +144,7 @@ struct pcm_config pcm_config_in = {
 #else
 struct pcm_config pcm_config = {
     .channels = 2,
-    .rate = 44100,
+    .rate = 48000,
     .period_size = 512,
     .period_count = 6,
     .format = PCM_FORMAT_S16_LE,
@@ -190,7 +190,7 @@ struct pcm_config pcm_config_hfp = {
 struct pcm_config pcm_config_ap_sco = {
     .channels = 2,
     .rate = 8000,
-    .period_size = 80,
+    .period_size = 160,
     .period_count = 4,
 };
 
@@ -201,6 +201,7 @@ struct pcm_config pcm_config_in_bt = {
     .period_count = 4,
     .format = PCM_FORMAT_S16_LE,
 };
+
 #endif
 struct pcm_config pcm_config_deep = {
     .channels = 2,
@@ -304,6 +305,9 @@ struct audio_device {
 
     struct dev_info dev_out[SND_OUT_SOUND_CARD_MAX];
     struct dev_info dev_in[SND_IN_SOUND_CARD_MAX];
+
+    bool bt_wb_speech_enabled;
+    unsigned int bt_sco_reroute;
 };
 
 struct stream_out {
(END)

4. 蓝牙核心协议相关内容

4.1 HCI层定义的pcm音频编码格式

Transmit_Coding_Format和Receive_Coding_Format是定义空中传输的格式. Assigned Numbers.

对应的, Host传输给控制的格式, 理论上也可以是以上任意之一. Android Bluedroid默认支持0x04(Linear PCM).

Host Controller Interface 见Assigned Number https://www.bluetooth.com/specifications/assigned-numbers/

Coding Format (1 Octet):

Assigned NumberMeaningNote
0x00u-Law log
0x01A-law log
0x02CVSD
0x03TransparentIndicates that the controller does not do any transcoding or resampling. See the command description for restrictions on the use of this value. This is also used for test mode.
0x04Linear PCM
0x05mSBC
0x06LC3
0x07G.729AThis is a draft allocation associated with draft specifications and is subject to change.
0x08-0xFEReserved
0xFFVendor SpecificThe codec is vendor-specific, as defined by the following 4 octets in the full coding format.

空中数据示例:

image-20220110210304780

4.2 LMP层定义的air mode格式.

0: µ-law log

1: A-law log

2: CVSD

3: transparent data

4-255: reserved for future use

image-20220110211120322

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值