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 Number | Meaning | Note |
---|---|---|
0x00 | u-Law log | |
0x01 | A-law log | |
0x02 | CVSD | |
0x03 | Transparent | Indicates 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. |
0x04 | Linear PCM | |
0x05 | mSBC | |
0x06 | LC3 | |
0x07 | G.729A | This is a draft allocation associated with draft specifications and is subject to change. |
0x08-0xFE | Reserved | |
0xFF | Vendor Specific | The codec is vendor-specific, as defined by the following 4 octets in the full coding format. |
空中数据示例:
4.2 LMP层定义的air mode格式.
0: µ-law log
1: A-law log
2: CVSD
3: transparent data
4-255: reserved for future use