hal: Add LDAC encoder support.
-Add support of LDAC encoder over split-a2dp path.
Change-Id: I128b21b4be4a9e18cc0633f0897f199640a79beb
diff --git a/hal/audio_extn/a2dp.c b/hal/audio_extn/a2dp.c
index 803cf4a..786d637 100644
--- a/hal/audio_extn/a2dp.c
+++ b/hal/audio_extn/a2dp.c
@@ -56,6 +56,7 @@
#define ENC_MEDIA_FMT_APTX_HD 0x00013200
#define ENC_MEDIA_FMT_SBC 0x00010BF2
#define ENC_MEDIA_FMT_CELT 0x00013221
+#define ENC_MEDIA_FMT_LDAC 0x00013224
#define MEDIA_FMT_AAC_AOT_LC 2
#define MEDIA_FMT_AAC_AOT_SBR 5
#define MEDIA_FMT_AAC_AOT_PS 29
@@ -82,14 +83,16 @@
#define ENCODER_LATENCY_APTX 40
#define ENCODER_LATENCY_APTX_HD 20
#define ENCODER_LATENCY_AAC 70
-//To Do: Fine Tune Encoder CELT latency.
+//To Do: Fine Tune Encoder CELT/LDAC latency.
#define ENCODER_LATENCY_CELT 40
+#define ENCODER_LATENCY_LDAC 40
#define DEFAULT_SINK_LATENCY_SBC 140
#define DEFAULT_SINK_LATENCY_APTX 160
#define DEFAULT_SINK_LATENCY_APTX_HD 180
#define DEFAULT_SINK_LATENCY_AAC 180
-//To Do: Fine Tune Default CELT Latency.
+//To Do: Fine Tune Default CELT/LDAC Latency.
#define DEFAULT_SINK_LATENCY_CELT 180
+#define DEFAULT_SINK_LATENCY_LDAC 180
/*
* Below enum values are extended from audio_base.h to
@@ -98,12 +101,13 @@
* between IPC lib and Audio HAL.
*/
typedef enum {
- ENC_CODEC_TYPE_INVALID = 4294967295u, // 0xFFFFFFFFUL
- ENC_CODEC_TYPE_AAC = 67108864u, // 0x04000000UL
- ENC_CODEC_TYPE_SBC = 520093696u, // 0x1F000000UL
- ENC_CODEC_TYPE_APTX = 536870912u, // 0x20000000UL
- ENC_CODEC_TYPE_APTX_HD = 553648128u, // 0x21000000UL
+ ENC_CODEC_TYPE_INVALID = AUDIO_FORMAT_INVALID, // 0xFFFFFFFFUL
+ ENC_CODEC_TYPE_AAC = AUDIO_FORMAT_AAC, // 0x04000000UL
+ ENC_CODEC_TYPE_SBC = AUDIO_FORMAT_SBC, // 0x1F000000UL
+ ENC_CODEC_TYPE_APTX = AUDIO_FORMAT_APTX, // 0x20000000UL
+ ENC_CODEC_TYPE_APTX_HD = AUDIO_FORMAT_APTX_HD, // 0x21000000UL
ENC_CODEC_TYPE_APTX_DUAL_MONO = 570425344u, // 0x22000000UL
+ ENC_CODEC_TYPE_LDAC = AUDIO_FORMAT_LDAC, // 0x23000000UL
ENC_CODEC_TYPE_CELT = 603979776u, // 0x24000000UL
}enc_codec_t;
@@ -247,6 +251,19 @@
struct aptx_v2_enc_cfg_ext_t aptx_v2_cfg;
} __packed;
+struct ldac_specific_enc_cfg_t
+{
+ uint32_t bit_rate;
+ uint16_t channel_mode;
+ uint16_t mtu;
+} __packed;
+
+struct ldac_enc_cfg_t
+{
+ struct custom_enc_cfg_t custom_cfg;
+ struct ldac_specific_enc_cfg_t ldac_cfg;
+} __packed;
+
/* In LE BT source code uses system/audio.h for below
* structure definition. To avoid multiple definition
* compilation error for audiohal in LE , masking structure
@@ -319,6 +336,17 @@
uint32_t bitrate; /*32000 - 1536000, 139500*/
} audio_celt_encoder_config;
+/* Information about BT LDAC encoder configuration
+ * This data is used between audio HAL module and
+ * BT IPC library to configure DSP encoder
+ */
+typedef struct {
+ uint32_t sampling_rate; /*44100,48000,88200,96000*/
+ uint32_t bit_rate; /*303000,606000,909000(in bits per second)*/
+ uint16_t channel_mode; /* 0, 4, 2, 1*/
+ uint16_t mtu; /*679*/
+} audio_ldac_encoder_config;
+
/*********** END of DSP configurable structures ********************/
/* API to identify DSP encoder captabilities */
@@ -352,6 +380,10 @@
ALOGD("%s: celt offload supported\n",__func__);
a2dp.is_a2dp_offload_supported = true;
break;
+ } else if (strcmp(tok, "ldac") == 0) {
+ ALOGD("%s: ldac offload supported\n",__func__);
+ a2dp.is_a2dp_offload_supported = true;
+ break;
}
tok = strtok_r(NULL, "-", &saveptr);
};
@@ -484,9 +516,17 @@
static void a2dp_set_backend_cfg()
{
char *rate_str = NULL, *in_channels = NULL;
+ uint32_t sampling_rate = a2dp.enc_sampling_rate;
struct mixer_ctl *ctl_sample_rate = NULL, *ctrl_in_channels = NULL;
+
+ //For LDAC encoder open slimbus port at 96Khz for 48Khz input
+ //and 88.2Khz for 44.1Khz input.
+ if ((a2dp.bt_encoder_format == ENC_CODEC_TYPE_LDAC) &&
+ (sampling_rate == 48000 || sampling_rate == 44100 )) {
+ sampling_rate = sampling_rate *2;
+ }
//Configure backend sampling rate
- switch (a2dp.enc_sampling_rate) {
+ switch (sampling_rate) {
case 44100:
rate_str = "KHZ_44P1";
break;
@@ -928,6 +968,73 @@
fail:
return is_configured;
}
+
+bool configure_ldac_enc_format(audio_ldac_encoder_config *ldac_bt_cfg)
+{
+ struct mixer_ctl *ldac_enc_data = NULL, *ctrl_bit_format = NULL;
+ struct ldac_enc_cfg_t ldac_dsp_cfg;
+ bool is_configured = false;
+ int ret = 0;
+ if(ldac_bt_cfg == NULL)
+ return false;
+
+ ldac_enc_data = mixer_get_ctl_by_name(a2dp.adev->mixer, MIXER_ENC_CONFIG_BLOCK);
+ if (!ldac_enc_data) {
+ ALOGE(" ERROR a2dp encoder CONFIG data mixer control not identifed");
+ is_configured = false;
+ goto fail;
+ }
+ memset(&ldac_dsp_cfg, 0x0, sizeof(struct ldac_enc_cfg_t));
+
+ ldac_dsp_cfg.custom_cfg.enc_format = ENC_MEDIA_FMT_LDAC;
+ ldac_dsp_cfg.custom_cfg.sample_rate = ldac_bt_cfg->sampling_rate;
+ ldac_dsp_cfg.ldac_cfg.channel_mode = ldac_bt_cfg->channel_mode;
+ switch(ldac_dsp_cfg.ldac_cfg.channel_mode) {
+ case 4:
+ ldac_dsp_cfg.custom_cfg.channel_mapping[0] = PCM_CHANNEL_C;
+ ldac_dsp_cfg.custom_cfg.num_channels = 1;
+ break;
+ case 2:
+ case 1:
+ default:
+ ldac_dsp_cfg.custom_cfg.channel_mapping[0] = PCM_CHANNEL_L;
+ ldac_dsp_cfg.custom_cfg.channel_mapping[1] = PCM_CHANNEL_R;
+ ldac_dsp_cfg.custom_cfg.num_channels = 2;
+ break;
+ }
+
+ ldac_dsp_cfg.custom_cfg.custom_size = sizeof(struct ldac_enc_cfg_t);
+ ldac_dsp_cfg.ldac_cfg.mtu = ldac_bt_cfg->mtu;
+ ldac_dsp_cfg.ldac_cfg.bit_rate = ldac_bt_cfg->bit_rate;
+ ret = mixer_ctl_set_array(ldac_enc_data, (void *)&ldac_dsp_cfg,
+ sizeof(struct ldac_enc_cfg_t));
+ if (ret != 0) {
+ ALOGE("%s: Failed to set LDAC encoder config", __func__);
+ is_configured = false;
+ goto fail;
+ }
+ ctrl_bit_format = mixer_get_ctl_by_name(a2dp.adev->mixer, MIXER_ENC_BIT_FORMAT);
+ if (!ctrl_bit_format) {
+ ALOGE(" ERROR bit format CONFIG data mixer control not identifed");
+ is_configured = false;
+ goto fail;
+ }
+ ret = mixer_ctl_set_enum_by_string(ctrl_bit_format, "S16_LE");
+ if (ret != 0) {
+ ALOGE("%s: Failed to set bit format to encoder", __func__);
+ is_configured = false;
+ goto fail;
+ }
+ is_configured = true;
+ a2dp.bt_encoder_format = ENC_CODEC_TYPE_LDAC;
+ a2dp.enc_sampling_rate = ldac_bt_cfg->sampling_rate;
+ a2dp.enc_channels = ldac_dsp_cfg.custom_cfg.num_channels;
+ ALOGV("Successfully updated LDAC encformat with samplingrate: %d channels:%d",
+ ldac_dsp_cfg.custom_cfg.sample_rate, ldac_dsp_cfg.custom_cfg.num_channels);
+fail:
+ return is_configured;
+}
+
bool configure_a2dp_encoder_format()
{
void *codec_info = NULL;
@@ -979,6 +1086,11 @@
is_configured =
configure_celt_enc_format((audio_celt_encoder_config *)codec_info);
break;
+ case ENC_CODEC_TYPE_LDAC:
+ ALOGD(" Received LDAC encoder supported BT device");
+ is_configured =
+ configure_ldac_enc_format((audio_ldac_encoder_config *)codec_info);
+ break;
default:
ALOGD(" Received Unsupported encoder formar");
is_configured = false;
@@ -1258,14 +1370,15 @@
{
uint32_t latency = 0;
int avsync_runtime_prop = 0;
- int sbc_offset = 0, aptx_offset = 0, aptxhd_offset = 0, aac_offset = 0, celt_offset = 0;
+ int sbc_offset = 0, aptx_offset = 0, aptxhd_offset = 0,
+ aac_offset = 0, celt_offset = 0, ldac_offset = 0;
char value[PROPERTY_VALUE_MAX];
memset(value, '\0', sizeof(char)*PROPERTY_VALUE_MAX);
avsync_runtime_prop = property_get("vendor.audio.a2dp.codec.latency", value, NULL);
if (avsync_runtime_prop > 0) {
- if (sscanf(value, "%d/%d/%d/%d/%d",
- &sbc_offset, &aptx_offset, &aptxhd_offset, &aac_offset, &celt_offset) != 5) {
+ if (sscanf(value, "%d/%d/%d/%d/%d%d",
+ &sbc_offset, &aptx_offset, &aptxhd_offset, &aac_offset, &celt_offset, &ldac_offset) != 6) {
ALOGI("Failed to parse avsync offset params from '%s'.", value);
avsync_runtime_prop = 0;
}
@@ -1297,6 +1410,10 @@
latency = (avsync_runtime_prop > 0) ? celt_offset : ENCODER_LATENCY_CELT;
latency += (slatency <= 0) ? DEFAULT_SINK_LATENCY_CELT : slatency;
break;
+ case ENC_CODEC_TYPE_LDAC:
+ latency = (avsync_runtime_prop > 0) ? ldac_offset : ENCODER_LATENCY_LDAC;
+ latency += (slatency <= 0) ? DEFAULT_SINK_LATENCY_LDAC : slatency;
+ break;
default:
latency = 200;
break;