hal: Add support for adaptive bitrate
Add support for adaptive bitrate with A2DP Offload.
Changes include separate sample rate for Slimbus Rx and
Tx backend, Tx feedback path setup on SLIMBUS_7_TX from
BTSoC to LPASS, AFE port configuration for A2DP encoder
and decoder.
Change-Id: I3b339e5525c9b6dab2e83f50bb4d63cd5d73850e
diff --git a/hal/audio_extn/a2dp.c b/hal/audio_extn/a2dp.c
index 3b4acd8..21495df 100644
--- a/hal/audio_extn/a2dp.c
+++ b/hal/audio_extn/a2dp.c
@@ -71,10 +71,14 @@
#define MEDIA_FMT_SBC_ALLOCATION_METHOD_LOUDNESS 0
#define MEDIA_FMT_SBC_ALLOCATION_METHOD_SNR 1
#define MIXER_ENC_CONFIG_BLOCK "SLIM_7_RX Encoder Config"
+#define MIXER_DEC_CONFIG_BLOCK "SLIM_7_TX Decoder Config"
#define MIXER_ENC_BIT_FORMAT "AFE Input Bit Format"
#define MIXER_SCRAMBLER_MODE "AFE Scrambler Mode"
-#define MIXER_SAMPLE_RATE "BT SampleRate"
+#define MIXER_SAMPLE_RATE_RX "BT SampleRate RX"
+#define MIXER_SAMPLE_RATE_TX "BT SampleRate TX"
#define MIXER_AFE_IN_CHANNELS "AFE Input Channels"
+#define MIXER_ABR_TX_FEEDBACK_PATH "A2DP_SLIM7_UL_HL Switch"
+#define MIXER_SET_FEEDBACK_CHANNEL "BT set feedback channel"
#define MIXER_ENC_FMT_SBC "SBC"
#define MIXER_ENC_FMT_AAC "AAC"
#define MIXER_ENC_FMT_APTX "APTX"
@@ -95,6 +99,18 @@
#define DEFAULT_SINK_LATENCY_CELT 180
#define DEFAULT_SINK_LATENCY_LDAC 180
+// Slimbus Tx sample rate for ABR feedback channel
+#define ABR_TX_SAMPLE_RATE "KHZ_8"
+
+// Purpose ID for Inter Module Communication (IMC) in AFE
+#define IMC_PURPOSE_ID_BT_INFO 0x000132E2
+
+// Maximum quality levels for ABR
+#define MAX_ABR_QUALITY_LEVELS 5
+
+// Instance identifier for A2DP
+#define MAX_INSTANCE_ID (UINT32_MAX / 2)
+
/*
* Below enum values are extended from audio_base.h to
* to keep encoder codec type local to bthost_ipc
@@ -134,6 +150,42 @@
A2DP_STATE_DISCONNECTED,
};
+typedef enum {
+ IMC_TRANSMIT,
+ IMC_RECEIVE,
+} imc_direction_t;
+
+typedef enum {
+ IMC_DISABLE,
+ IMC_ENABLE,
+} imc_status_t;
+
+/* PCM config for ABR Feedback hostless front end */
+static struct pcm_config pcm_config_abr = {
+ .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,
+};
+
+/* Adaptive bitrate config for A2DP codecs */
+struct a2dp_abr_config {
+ /* Flag to denote whether Adaptive bitrate is enabled for codec */
+ bool is_abr_enabled;
+ /* Flag to denote whether front end has been opened for ABR */
+ bool abr_started;
+ /* ABR Tx path pcm handle */
+ struct pcm *abr_tx_handle;
+ /* ABR Inter Module Communication (IMC) instance ID */
+ uint32_t imc_instance;
+};
+
+static uint32_t instance_id = MAX_INSTANCE_ID;
+
/* structure used to update a2dp state machine
* to communicate IPC library
* to store DSP encoder configuration information
@@ -162,10 +214,76 @@
bool is_a2dp_offload_supported;
bool is_handoff_in_progress;
bool is_aptx_dual_mono_supported;
+ /* Adaptive bitrate config for A2DP codecs */
+ struct a2dp_abr_config abr_config;
};
struct a2dp_data a2dp;
+/* Adaptive bitrate (ABR) is supported by certain Bluetooth codecs.
+ * Structures sent to configure DSP for ABR are defined below.
+ * This data helps DSP configure feedback path (BTSoC to LPASS)
+ * for link quality levels and mapping quality levels to codec
+ * specific bitrate.
+ */
+
+/* Key value pair for link quality level to bitrate mapping. */
+struct bit_rate_level_map_t {
+ uint32_t link_quality_level;
+ uint32_t bitrate;
+};
+
+/* Link quality level to bitrate mapping info sent to DSP. */
+struct quality_level_to_bitrate_info {
+ /* Number of quality levels being mapped.
+ * This will be equal to the size of mapping table.
+ */
+ uint32_t num_levels;
+ /* Quality level to bitrate mapping table */
+ struct bit_rate_level_map_t bit_rate_level_map[MAX_ABR_QUALITY_LEVELS];
+};
+
+/* Structure to set up Inter Module Communication (IMC) between
+ * AFE Decoder and Encoder.
+ */
+struct imc_dec_enc_info {
+ /* Decoder to encoder communication direction.
+ * Transmit = 0 / Receive = 1
+ */
+ uint32_t direction;
+ /* Enable / disable IMC between decoder and encoder */
+ uint32_t enable;
+ /* Purpose of IMC being set up between decoder and encoder.
+ * IMC_PURPOSE_ID_BT_INFO defined for link quality feedback
+ * is the default value to be sent as purpose.
+ */
+ uint32_t purpose;
+ /* Unique communication instance ID.
+ * purpose and comm_instance together form the actual key
+ * used in IMC registration, which must be the same for
+ * encoder and decoder for which IMC is being set up.
+ */
+ uint32_t comm_instance;
+};
+
+/* Structure used for ABR config of AFE encoder and decoder. */
+struct abr_enc_cfg_t {
+ /* Link quality level to bitrate mapping info sent to DSP. */
+ struct quality_level_to_bitrate_info mapping_info;
+ /* Information to set up IMC between decoder and encoder */
+ struct imc_dec_enc_info imc_info;
+} __attribute__ ((packed));
+
+/* Structure to send configuration for decoder introduced
+ * on AFE Tx path for ABR link quality feedback to BT encoder.
+ */
+struct abr_dec_cfg_t {
+ /* Decoder media format */
+ uint32_t dec_format;
+ /* Information to set up IMC between decoder and encoder */
+ struct imc_dec_enc_info imc_info;
+} __attribute__ ((packed));
+
/* START of DSP configurable structures
* These values should match with DSP interface defintion
*/
@@ -265,6 +383,7 @@
{
struct custom_enc_cfg_t custom_cfg;
struct ldac_specific_enc_cfg_t ldac_cfg;
+ struct abr_enc_cfg_t abr_cfg;
} __attribute__ ((packed));
/* In LE BT source code uses system/audio.h for below
@@ -348,6 +467,8 @@
uint32_t bit_rate; /*303000,606000,909000(in bits per second)*/
uint16_t channel_mode; /* 0, 4, 2, 1*/
uint16_t mtu; /*679*/
+ bool is_abr_enabled;
+ struct quality_level_to_bitrate_info level_to_bitrate_map;
} audio_ldac_encoder_config;
/*********** END of DSP configurable structures ********************/
@@ -405,6 +526,117 @@
ALOGD("%s: codec cap = %s",__func__,value);
}
+static int stop_abr()
+{
+ struct mixer_ctl *ctl_abr_tx_path = NULL;
+ struct mixer_ctl *ctl_set_bt_feedback_channel = NULL;
+
+ /* This function can be used if !abr_started for clean up */
+ ALOGV("%s: enter", __func__);
+
+ // Close hostless front end
+ if (a2dp.abr_config.abr_tx_handle != NULL) {
+ pcm_close(a2dp.abr_config.abr_tx_handle);
+ a2dp.abr_config.abr_tx_handle = NULL;
+ }
+ a2dp.abr_config.abr_started = false;
+ a2dp.abr_config.imc_instance = 0;
+
+ // Reset BT driver mixer control for ABR usecase
+ ctl_set_bt_feedback_channel = mixer_get_ctl_by_name(a2dp.adev->mixer,
+ MIXER_SET_FEEDBACK_CHANNEL);
+ if (!ctl_set_bt_feedback_channel) {
+ ALOGE("%s: ERROR Set usecase mixer control not identifed", __func__);
+ return -ENOSYS;
+ }
+ if (mixer_ctl_set_value(ctl_set_bt_feedback_channel, 0, 0) != 0) {
+ ALOGE("%s: Failed to set BT usecase", __func__);
+ return -ENOSYS;
+ }
+
+ // Reset ABR Tx feedback path
+ ALOGV("%s: Disable ABR Tx feedback path", __func__);
+ ctl_abr_tx_path = mixer_get_ctl_by_name(a2dp.adev->mixer,
+ MIXER_ABR_TX_FEEDBACK_PATH);
+ if (!ctl_abr_tx_path) {
+ ALOGE("%s: ERROR ABR Tx feedback path mixer control not identifed", __func__);
+ return -ENOSYS;
+ }
+ if (mixer_ctl_set_value(ctl_abr_tx_path, 0, 0) != 0) {
+ ALOGE("%s: Failed to set ABR Tx feedback path", __func__);
+ return -ENOSYS;
+ }
+
+ return 0;
+}
+
+static int start_abr()
+{
+ struct mixer_ctl *ctl_abr_tx_path = NULL;
+ struct mixer_ctl *ctl_set_bt_feedback_channel = NULL;
+ int abr_device_id;
+ int ret = 0;
+
+ if (!a2dp.abr_config.is_abr_enabled) {
+ ALOGE("%s: Cannot start if ABR is not enabled", __func__);
+ return -ENOSYS;
+ }
+
+ if (a2dp.abr_config.abr_started) {
+ ALOGI("%s: ABR has already started", __func__);
+ return ret;
+ }
+
+ // Enable Slimbus 7 Tx feedback path
+ ALOGV("%s: Enable ABR Tx feedback path", __func__);
+ ctl_abr_tx_path = mixer_get_ctl_by_name(a2dp.adev->mixer,
+ MIXER_ABR_TX_FEEDBACK_PATH);
+ if (!ctl_abr_tx_path) {
+ ALOGE("%s: ERROR ABR Tx feedback path mixer control not identifed", __func__);
+ return -ENOSYS;
+ }
+ if (mixer_ctl_set_value(ctl_abr_tx_path, 0, 1) != 0) {
+ ALOGE("%s: Failed to set ABR Tx feedback path", __func__);
+ return -ENOSYS;
+ }
+
+ // Notify ABR usecase information to BT driver to distinguish
+ // between SCO and feedback usecase
+ ctl_set_bt_feedback_channel = mixer_get_ctl_by_name(a2dp.adev->mixer,
+ MIXER_SET_FEEDBACK_CHANNEL);
+ if (!ctl_set_bt_feedback_channel) {
+ ALOGE("%s: ERROR Set usecase mixer control not identifed", __func__);
+ return -ENOSYS;
+ }
+ if (mixer_ctl_set_value(ctl_set_bt_feedback_channel, 0, 1) != 0) {
+ ALOGE("%s: Failed to set BT usecase", __func__);
+ return -ENOSYS;
+ }
+
+ // Open hostless front end and prepare ABR Tx path
+ abr_device_id = platform_get_pcm_device_id(USECASE_AUDIO_A2DP_ABR_FEEDBACK,
+ PCM_CAPTURE);
+ if (!a2dp.abr_config.abr_tx_handle) {
+ a2dp.abr_config.abr_tx_handle = pcm_open(a2dp.adev->snd_card,
+ abr_device_id, PCM_IN,
+ &pcm_config_abr);
+ if (a2dp.abr_config.abr_tx_handle == NULL ||
+ !pcm_is_ready(a2dp.abr_config.abr_tx_handle))
+ goto fail;
+ }
+ ret = pcm_start(a2dp.abr_config.abr_tx_handle);
+ if (ret < 0)
+ goto fail;
+ a2dp.abr_config.abr_started = true;
+
+ return ret;
+
+fail:
+ ALOGE("%s: %s", __func__, pcm_get_error(a2dp.abr_config.abr_tx_handle));
+ stop_abr();
+ return -ENOSYS;
+}
+
/* API to open BT IPC library to start IPC communication */
static void open_a2dp_output()
{
@@ -489,6 +721,12 @@
a2dp.enc_sampling_rate = 48000;
a2dp.enc_channels = 2;
a2dp.bt_state = A2DP_STATE_DISCONNECTED;
+ if (a2dp.abr_config.is_abr_enabled && a2dp.abr_config.abr_started)
+ stop_abr();
+ a2dp.abr_config.is_abr_enabled = false;
+ a2dp.abr_config.abr_started = false;
+ a2dp.abr_config.imc_instance = 0;
+ a2dp.abr_config.abr_tx_handle = NULL;
return 0;
}
@@ -516,48 +754,63 @@
}
}
-static void a2dp_set_backend_cfg()
+static int a2dp_set_backend_cfg()
{
char *rate_str = NULL, *in_channels = NULL;
- uint32_t sampling_rate = a2dp.enc_sampling_rate;
+ uint32_t sampling_rate_rx = 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;
+ (sampling_rate_rx == 48000 || sampling_rate_rx == 44100 )) {
+ sampling_rate_rx *= 2;
}
- //Configure backend sampling rate
- switch (sampling_rate) {
+
+ // Set Rx backend sample rate
+ switch (sampling_rate_rx) {
case 44100:
rate_str = "KHZ_44P1";
break;
- case 48000:
- rate_str = "KHZ_48";
- break;
case 88200:
rate_str = "KHZ_88P2";
break;
case 96000:
rate_str = "KHZ_96";
break;
+ case 48000:
default:
rate_str = "KHZ_48";
break;
}
- ALOGD("%s: set backend sample rate =%s", __func__, rate_str);
+ ALOGD("%s: set backend rx sample rate = %s", __func__, rate_str);
ctl_sample_rate = mixer_get_ctl_by_name(a2dp.adev->mixer,
- MIXER_SAMPLE_RATE);
+ MIXER_SAMPLE_RATE_RX);
if (!ctl_sample_rate) {
- ALOGE(" ERROR backend sample rate mixer control not identifed");
- return;
- } else {
- if (mixer_ctl_set_enum_by_string(ctl_sample_rate, rate_str) != 0) {
- ALOGE("%s: Failed to set backend sample rate =%s", __func__, rate_str);
- return;
- }
+ ALOGE("%s: ERROR backend sample rate mixer control not identifed", __func__);
+ return -ENOSYS;
+ }
+ if (mixer_ctl_set_enum_by_string(ctl_sample_rate, rate_str) != 0) {
+ ALOGE("%s: Failed to set backend sample rate = %s", __func__, rate_str);
+ return -ENOSYS;
+ }
+
+ // Set Tx backend sample rate
+ if (a2dp.abr_config.is_abr_enabled)
+ rate_str = ABR_TX_SAMPLE_RATE;
+
+ ALOGD("%s: set backend tx sample rate = %s", __func__, rate_str);
+ ctl_sample_rate = mixer_get_ctl_by_name(a2dp.adev->mixer,
+ MIXER_SAMPLE_RATE_TX);
+ if (!ctl_sample_rate) {
+ ALOGE("%s: ERROR backend sample rate mixer control not identifed", __func__);
+ return -ENOSYS;
+ }
+ if (mixer_ctl_set_enum_by_string(ctl_sample_rate, rate_str) != 0) {
+ ALOGE("%s: Failed to set backend sample rate = %s",
+ __func__, rate_str);
+ return -ENOSYS;
}
//Configure AFE input channels
@@ -571,52 +824,96 @@
break;
}
- ALOGD("%s: set afe input channels =%d", __func__, a2dp.enc_channels);
+ ALOGD("%s: set AFE input channels = %d", __func__, a2dp.enc_channels);
ctrl_in_channels = mixer_get_ctl_by_name(a2dp.adev->mixer,
MIXER_AFE_IN_CHANNELS);
if (!ctrl_in_channels) {
- ALOGE(" ERROR AFE input channels mixer control not identifed");
- return;
- } else {
- if (mixer_ctl_set_enum_by_string(ctrl_in_channels, in_channels) != 0) {
- ALOGE("%s: Failed to set AFE in channels =%d", __func__, a2dp.enc_channels);
- return;
- }
+ ALOGE("%s: ERROR AFE input channels mixer control not identifed", __func__);
+ return -ENOSYS;
}
+ if (mixer_ctl_set_enum_by_string(ctrl_in_channels, in_channels) != 0) {
+ ALOGE("%s: Failed to set AFE in channels = %d", __func__, a2dp.enc_channels);
+ return -ENOSYS;
+ }
+
+ return 0;
}
-static void a2dp_reset_backend_cfg()
+static int a2dp_reset_backend_cfg()
{
- char *rate_str = "KHZ_8", *in_channels = "Zero";
- struct mixer_ctl *ctl_sample_rate = NULL, *ctrl_in_channels = NULL;
+ const char *rate_str = "KHZ_8", *in_channels = "Zero";
+ struct mixer_ctl *ctl_sample_rate_rx = NULL, *ctl_sample_rate_tx = NULL;
+ struct mixer_ctl *ctrl_in_channels = NULL;
- //reset backend sampling rate
- ALOGD("%s: reset backend sample rate =%s", __func__, rate_str);
- ctl_sample_rate = mixer_get_ctl_by_name(a2dp.adev->mixer,
- MIXER_SAMPLE_RATE);
- if (!ctl_sample_rate) {
- ALOGE(" ERROR backend sample rate mixer control not identifed");
- return;
- } else {
- if (mixer_ctl_set_enum_by_string(ctl_sample_rate, rate_str) != 0) {
- ALOGE("%s: Failed to reset backend sample rate =%s", __func__, rate_str);
- return;
- }
+ // Reset backend sampling rate
+ ALOGD("%s: reset backend sample rate = %s", __func__, rate_str);
+ ctl_sample_rate_rx = mixer_get_ctl_by_name(a2dp.adev->mixer,
+ MIXER_SAMPLE_RATE_RX);
+ if (!ctl_sample_rate_rx) {
+ ALOGE("%s: ERROR Rx backend sample rate mixer control not identifed", __func__);
+ return -ENOSYS;
+ }
+ if (mixer_ctl_set_enum_by_string(ctl_sample_rate_rx, rate_str) != 0) {
+ ALOGE("%s: Failed to reset Rx backend sample rate = %s", __func__, rate_str);
+ return -ENOSYS;
}
- //reset AFE input channels
- ALOGD("%s: reset afe input channels =%s", __func__, in_channels);
+ ctl_sample_rate_tx = mixer_get_ctl_by_name(a2dp.adev->mixer,
+ MIXER_SAMPLE_RATE_TX);
+ if (!ctl_sample_rate_tx) {
+ ALOGE("%s: ERROR Tx backend sample rate mixer control not identifed", __func__);
+ return -ENOSYS;
+ }
+ if (mixer_ctl_set_enum_by_string(ctl_sample_rate_tx, rate_str) != 0) {
+ ALOGE("%s: Failed to reset Tx backend sample rate = %s", __func__, rate_str);
+ return -ENOSYS;
+ }
+
+ // Reset AFE input channels
+ ALOGD("%s: reset AFE input channels = %s", __func__, in_channels);
ctrl_in_channels = mixer_get_ctl_by_name(a2dp.adev->mixer,
MIXER_AFE_IN_CHANNELS);
if (!ctrl_in_channels) {
- ALOGE(" ERROR AFE input channels mixer control not identifed");
- return;
- } else {
- if (mixer_ctl_set_enum_by_string(ctrl_in_channels, in_channels) != 0) {
- ALOGE("%s: Failed to reset AFE in channels =%d", __func__, a2dp.enc_channels);
- return;
+ ALOGE("%s: ERROR AFE input channels mixer control not identifed", __func__);
+ return -ENOSYS;
+ }
+ if (mixer_ctl_set_enum_by_string(ctrl_in_channels, in_channels) != 0) {
+ ALOGE("%s: Failed to reset AFE in channels = %d", __func__, a2dp.enc_channels);
+ return -ENOSYS;
+ }
+
+ return 0;
+}
+
+/* API to configure AFE decoder in DSP */
+static bool configure_a2dp_decoder_format(int dec_format)
+{
+ struct mixer_ctl *ctl_dec_data = NULL;
+ struct abr_dec_cfg_t dec_cfg;
+ int ret = 0;
+
+ if (a2dp.abr_config.is_abr_enabled) {
+ ctl_dec_data = mixer_get_ctl_by_name(a2dp.adev->mixer, MIXER_DEC_CONFIG_BLOCK);
+ if (!ctl_dec_data) {
+ ALOGE("%s: ERROR A2DP codec config data mixer control not identifed", __func__);
+ return false;
+ }
+ memset(&dec_cfg, 0x0, sizeof(dec_cfg));
+ dec_cfg.dec_format = dec_format;
+ dec_cfg.imc_info.direction = IMC_TRANSMIT;
+ dec_cfg.imc_info.enable = IMC_ENABLE;
+ dec_cfg.imc_info.purpose = IMC_PURPOSE_ID_BT_INFO;
+ dec_cfg.imc_info.comm_instance = a2dp.abr_config.imc_instance;
+
+ ret = mixer_ctl_set_array(ctl_dec_data, &dec_cfg,
+ sizeof(dec_cfg));
+ if (ret != 0) {
+ ALOGE("%s: Failed to set decoder config", __func__);
+ return false;
}
}
+
+ return true;
}
/* API to configure SBC DSP encoder */
@@ -973,7 +1270,7 @@
is_configured = true;
a2dp.bt_encoder_format = ENC_CODEC_TYPE_AAC;
a2dp.enc_sampling_rate = aac_bt_cfg->sampling_rate;
- a2dp.enc_channels = aac_bt_cfg->channels;;
+ a2dp.enc_channels = aac_bt_cfg->channels;
ALOGV("Successfully updated AAC enc format with samplingrate: %d channels:%d",
aac_dsp_cfg.sample_rate, aac_dsp_cfg.channel_cfg);
fail:
@@ -1085,6 +1382,14 @@
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;
+ if (ldac_bt_cfg->is_abr_enabled) {
+ ldac_dsp_cfg.abr_cfg.mapping_info = ldac_bt_cfg->level_to_bitrate_map;
+ ldac_dsp_cfg.abr_cfg.imc_info.direction = IMC_RECEIVE;
+ ldac_dsp_cfg.abr_cfg.imc_info.enable = IMC_ENABLE;
+ ldac_dsp_cfg.abr_cfg.imc_info.purpose = IMC_PURPOSE_ID_BT_INFO;
+ ldac_dsp_cfg.abr_cfg.imc_info.comm_instance = a2dp.abr_config.imc_instance;
+ }
+
ret = mixer_ctl_set_array(ldac_enc_data, (void *)&ldac_dsp_cfg,
sizeof(struct ldac_enc_cfg_t));
if (ret != 0) {
@@ -1108,6 +1413,7 @@
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;
+ a2dp.abr_config.is_abr_enabled = ldac_bt_cfg->is_abr_enabled;
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:
@@ -1130,6 +1436,9 @@
codec_info = a2dp.audio_get_codec_config(&multi_cast, &num_dev,
&codec_type);
+ // ABR disabled by default for all codecs
+ a2dp.abr_config.is_abr_enabled = false;
+
switch(codec_type) {
case ENC_CODEC_TYPE_SBC:
ALOGD(" Received SBC encoder supported BT device");
@@ -1176,8 +1485,12 @@
break;
case ENC_CODEC_TYPE_LDAC:
ALOGD(" Received LDAC encoder supported BT device");
+ if (!instance_id || instance_id > MAX_INSTANCE_ID)
+ instance_id = MAX_INSTANCE_ID;
+ a2dp.abr_config.imc_instance = instance_id--;
is_configured =
- configure_ldac_enc_format((audio_ldac_encoder_config *)codec_info);
+ (configure_ldac_enc_format((audio_ldac_encoder_config *)codec_info) &&
+ configure_a2dp_decoder_format(ENC_CODEC_TYPE_LDAC));
break;
default:
ALOGD(" Received Unsupported encoder formar");
@@ -1230,6 +1543,8 @@
a2dp.a2dp_total_active_session_request++;
a2dp_check_and_set_scrambler();
a2dp_set_backend_cfg();
+ if (a2dp.abr_config.is_abr_enabled)
+ start_abr();
}
ALOGD("start A2DP playback total active sessions :%d",
@@ -1288,6 +1603,10 @@
ALOGV("stop steam to BT IPC lib successful");
reset_a2dp_enc_config_params();
a2dp_reset_backend_cfg();
+ if (a2dp.abr_config.is_abr_enabled && a2dp.abr_config.abr_started)
+ stop_abr();
+ a2dp.abr_config.is_abr_enabled = false;
+ a2dp.a2dp_started = false;
}
if(!a2dp.a2dp_total_active_session_request)
a2dp.a2dp_started = false;
@@ -1446,6 +1765,10 @@
a2dp.is_a2dp_offload_supported = false;
a2dp.is_handoff_in_progress = false;
a2dp.is_aptx_dual_mono_supported = false;
+ a2dp.abr_config.is_abr_enabled = false;
+ a2dp.abr_config.abr_started = false;
+ a2dp.abr_config.imc_instance = 0;
+ a2dp.abr_config.abr_tx_handle = NULL;
reset_a2dp_enc_config_params();
update_offload_codec_capabilities();
}
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index ccac3a1..fa83205 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -351,7 +351,9 @@
[USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM7] = "audio-interactive-stream7",
[USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM8] = "audio-interactive-stream8",
- [USECASE_AUDIO_EC_REF_LOOPBACK] = "ec-ref-audio-capture"
+ [USECASE_AUDIO_EC_REF_LOOPBACK] = "ec-ref-audio-capture",
+
+ [USECASE_AUDIO_A2DP_ABR_FEEDBACK] = "a2dp-abr-feedback"
};
static const audio_usecase_t offload_usecases[] = {
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 0dc9115..497b5c8 100755
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -201,6 +201,9 @@
USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM8,
USECASE_AUDIO_EC_REF_LOOPBACK,
+
+ USECASE_AUDIO_A2DP_ABR_FEEDBACK,
+
AUDIO_USECASE_MAX
};
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index c4708a1..6e76bdc 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -906,6 +906,7 @@
{TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_AFE_PROXY)},
{TO_NAME_INDEX(USECASE_AUDIO_RECORD_AFE_PROXY)},
{TO_NAME_INDEX(USECASE_AUDIO_EC_REF_LOOPBACK)},
+ {TO_NAME_INDEX(USECASE_AUDIO_A2DP_ABR_FEEDBACK)},
};
#define NO_COLS 2
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 80f664b..237fddb 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -884,6 +884,7 @@
{TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_AFE_PROXY)},
{TO_NAME_INDEX(USECASE_AUDIO_RECORD_AFE_PROXY)},
{TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_SILENCE)},
+ {TO_NAME_INDEX(USECASE_AUDIO_A2DP_ABR_FEEDBACK)},
};
#define NO_COLS 2