PowerLog: Enable for userdebug and eng builds only am: 9e737dea6d
am: 9f5019369e
Change-Id: I4ea97aec95d6eb8d13a9771b056664b193057408
diff --git a/hal/Android.mk b/hal/Android.mk
index 2b27e64..2de6c16 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -67,7 +67,8 @@
audio_extn/ext_speaker.c \
audio_extn/audio_extn.c \
audio_extn/utils.c \
- $(AUDIO_PLATFORM)/platform.c
+ $(AUDIO_PLATFORM)/platform.c \
+ acdb.c
ifdef MULTIPLE_HW_VARIANTS_ENABLED
LOCAL_CFLAGS += -DHW_VARIANTS_ENABLED
diff --git a/hal/acdb.c b/hal/acdb.c
new file mode 100644
index 0000000..1614cc9
--- /dev/null
+++ b/hal/acdb.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "audio_hw_acdb"
+//#define LOG_NDEBUG 0
+#define LOG_NDDEBUG 0
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <dlfcn.h>
+#include <cutils/log.h>
+#include <cutils/str_parms.h>
+#include <system/audio.h>
+#include <tinyalsa/asoundlib.h>
+#include "acdb.h"
+#include <platform_api.h>
+
+#define PLATFORM_CONFIG_KEY_SOUNDCARD_NAME "snd_card_name"
+#define PLATFORM_INFO_XML_PATH "audio_platform_info.xml"
+
+int acdb_init(int snd_card_num)
+{
+
+ int result = -1;
+ char *cvd_version = NULL;
+
+ char *snd_card_name = NULL;
+ struct mixer *mixer = NULL;
+ struct acdb_platform_data *my_data = NULL;
+
+ if(snd_card_num < 0) {
+ ALOGE("invalid sound card number");
+ return result;
+ }
+
+ mixer = mixer_open(snd_card_num);
+ if (!mixer) {
+ ALOGE("%s: Unable to open the mixer card: %d", __func__,
+ snd_card_num);
+ goto cleanup;
+ }
+
+ my_data = calloc(1, sizeof(struct acdb_platform_data));
+ if (!my_data) {
+ ALOGE("failed to allocate acdb platform data");
+ goto cleanup;
+ }
+
+ list_init(&my_data->acdb_meta_key_list);
+
+ /* Extract META KEY LIST INFO */
+ //platform_info_init(PLATFORM_INFO_XML_PATH, my_data);
+
+ my_data->acdb_handle = dlopen(LIB_ACDB_LOADER, RTLD_NOW);
+ if (my_data->acdb_handle == NULL) {
+ ALOGE("%s: DLOPEN failed for %s", __func__, LIB_ACDB_LOADER);
+ goto cleanup;
+ }
+
+ ALOGV("%s: DLOPEN successful for %s", __func__, LIB_ACDB_LOADER);
+
+ my_data->acdb_init_v3 = (acdb_init_v3_t)dlsym(my_data->acdb_handle,
+ "acdb_loader_init_v3");
+ if (my_data->acdb_init_v3 == NULL)
+ ALOGE("%s: dlsym error %s for acdb_loader_init_v3", __func__, dlerror());
+
+ my_data->acdb_init_v2 = (acdb_init_v2_cvd_t)dlsym(my_data->acdb_handle,
+ "acdb_loader_init_v2");
+ if (my_data->acdb_init_v2 == NULL)
+ ALOGE("%s: dlsym error %s for acdb_loader_init_v2", __func__, dlerror());
+
+ my_data->acdb_init = (acdb_init_t)dlsym(my_data->acdb_handle,
+ "acdb_loader_init_ACDB");
+ if (my_data->acdb_init == NULL && my_data->acdb_init_v2 == NULL
+ && my_data->acdb_init_v3 == NULL) {
+ ALOGE("%s: dlsym error %s for acdb_loader_init_ACDB", __func__, dlerror());
+ goto cleanup;
+ }
+
+ /* Get CVD version */
+ cvd_version = calloc(1, MAX_CVD_VERSION_STRING_SIZE);
+ if (!cvd_version) {
+ ALOGE("%s: Failed to allocate cvd version", __func__);
+ goto cleanup;
+ } else {
+ struct mixer_ctl *ctl = NULL;
+ int count = 0;
+
+ ctl = mixer_get_ctl_by_name(mixer, CVD_VERSION_MIXER_CTL);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s", __func__, CVD_VERSION_MIXER_CTL);
+ goto cleanup;
+ }
+ mixer_ctl_update(ctl);
+
+ count = mixer_ctl_get_num_values(ctl);
+ if (count > MAX_CVD_VERSION_STRING_SIZE)
+ count = MAX_CVD_VERSION_STRING_SIZE;
+
+ result = mixer_ctl_get_array(ctl, cvd_version, count);
+ if (result != 0) {
+ ALOGE("%s: ERROR! mixer_ctl_get_array() failed to get CVD Version", __func__);
+ goto cleanup;
+ }
+ }
+
+ /* Get Sound card name */
+ snd_card_name = strdup(mixer_get_name(mixer));
+ if (!snd_card_name) {
+ ALOGE("failed to allocate memory for snd_card_name");
+ result = -1;
+ goto cleanup;
+ }
+
+ int key = 0;
+ struct listnode *node = NULL;
+ struct meta_key_list *key_info = NULL;
+
+ if (my_data->acdb_init_v3) {
+ result = my_data->acdb_init_v3(snd_card_name, cvd_version,
+ &my_data->acdb_meta_key_list);
+ } else if (my_data->acdb_init_v2) {
+ node = list_head(&my_data->acdb_meta_key_list);
+ key_info = node_to_item(node, struct meta_key_list, list);
+ key = key_info->cal_info.nKey;
+ result = my_data->acdb_init_v2(snd_card_name, cvd_version, key);
+ } else {
+ result = my_data->acdb_init();
+ }
+
+cleanup:
+ if (NULL != my_data) {
+ if (my_data->acdb_handle)
+ dlclose(my_data->acdb_handle);
+
+ struct listnode *node;
+ struct meta_key_list *key_info;
+ list_for_each(node, &my_data->acdb_meta_key_list) {
+ key_info = node_to_item(node, struct meta_key_list, list);
+ free(key_info);
+ }
+ free(my_data);
+ }
+
+ mixer_close(mixer);
+ free(cvd_version);
+ free(snd_card_name);
+
+ return result;
+}
+
+int acdb_set_metainfo_key(void *platform, char *name, int key) {
+
+ struct meta_key_list *key_info = (struct meta_key_list *)
+ calloc(1, sizeof(struct meta_key_list));
+ struct acdb_platform_data *pdata = (struct acdb_platform_data *)platform;
+ if (!key_info) {
+ ALOGE("%s: Could not allocate memory for key %d", __func__, key);
+ return -ENOMEM;
+ }
+
+ key_info->cal_info.nKey = key;
+ strlcpy(key_info->name, name, sizeof(key_info->name));
+ list_add_tail(&pdata->acdb_meta_key_list, &key_info->list);
+
+ ALOGD("%s: successfully added module %s and key %d to the list", __func__,
+ key_info->name, key_info->cal_info.nKey);
+
+ return 0;
+}
+
+int acdb_set_parameters(void *platform, struct str_parms *parms)
+{
+ struct acdb_platform_data *my_data = (struct acdb_platform_data *)platform;
+ char value[128];
+ char *kv_pairs = str_parms_to_str(parms);
+ int ret = 0;
+
+ if (kv_pairs == NULL) {
+ ret = -EINVAL;
+ ALOGE("%s: key-value pair is NULL",__func__);
+ goto done;
+ }
+
+ ret = str_parms_get_str(parms, PLATFORM_CONFIG_KEY_SOUNDCARD_NAME,
+ value, sizeof(value));
+ if (ret >= 0) {
+ str_parms_del(parms, PLATFORM_CONFIG_KEY_SOUNDCARD_NAME);
+ my_data->snd_card_name = strdup(value);
+ ALOGV("%s: sound card name %s", __func__, my_data->snd_card_name);
+ }
+
+done:
+ free(kv_pairs);
+
+ return ret;
+}
diff --git a/hal/acdb.h b/hal/acdb.h
new file mode 100644
index 0000000..08026fb
--- /dev/null
+++ b/hal/acdb.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ACDB_H
+#define ACDB_H
+
+#include <cutils/list.h>
+#include <linux/msm_audio_calibration.h>
+
+#define MAX_CVD_VERSION_STRING_SIZE 100
+#define LIB_ACDB_LOADER "libacdbloader.so"
+#define CVD_VERSION_MIXER_CTL "CVD Version"
+#define ACDB_METAINFO_KEY_MODULE_NAME_LEN 100
+
+/* Audio calibration related functions */
+typedef void (*acdb_deallocate_t)();
+typedef int (*acdb_init_v3_t)(const char *, char *, struct listnode *);
+typedef int (*acdb_init_v2_cvd_t)(char *, char *, int);
+typedef int (*acdb_init_v2_t)(char *);
+typedef int (*acdb_init_t)();
+typedef void (*acdb_send_audio_cal_t)(int, int);
+typedef void (*acdb_send_voice_cal_t)(int, int);
+typedef int (*acdb_reload_vocvoltable_t)(int);
+typedef int (*acdb_send_gain_dep_cal_t)(int, int, int, int, int);
+typedef int (*acdb_send_custom_top_t) (void);
+
+struct meta_key_list {
+ struct listnode list;
+ struct audio_cal_info_metainfo cal_info;
+ char name[ACDB_METAINFO_KEY_MODULE_NAME_LEN];
+};
+
+struct acdb_platform_data {
+ /* Audio calibration related functions */
+ void *acdb_handle;
+ acdb_init_t acdb_init;
+ acdb_init_v2_cvd_t acdb_init_v2;
+ acdb_init_v3_t acdb_init_v3;
+ char *snd_card_name;
+ struct listnode acdb_meta_key_list;
+};
+
+int acdb_init(int);
+
+int acdb_set_metainfo_key(void *platform, char *name, int key);
+int acdb_set_parameters(void *platform, struct str_parms *parms);
+#endif //ACDB_H
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index b734cb6..85a5881 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -79,6 +79,9 @@
#define audio_extn_usb_enable_sidetone(device, enable) (0)
#define audio_extn_usb_set_sidetone_gain(parms, value, len) (0)
#define audio_extn_usb_is_capture_supported() (false)
+#define audio_extn_usb_get_max_channels() (0)
+#define audio_extn_usb_get_max_bit_width() (0)
+#define audio_extn_usb_sup_sample_rates(t, s, l) (0)
#else
void audio_extn_usb_init(void *adev);
void audio_extn_usb_deinit();
@@ -92,6 +95,9 @@
int audio_extn_usb_set_sidetone_gain(struct str_parms *parms,
char *value, int len);
bool audio_extn_usb_is_capture_supported();
+int audio_extn_usb_get_max_channels();
+int audio_extn_usb_get_max_bit_width();
+int audio_extn_usb_sup_sample_rates(int type, uint32_t *sr, uint32_t l);
#endif
@@ -137,6 +143,8 @@
void audio_extn_utils_send_default_app_type_cfg(void *platform, struct mixer *mixer);
int audio_extn_utils_send_app_type_cfg(struct audio_device *adev,
struct audio_usecase *usecase);
+void audio_extn_utils_send_audio_calibration(struct audio_device *adev,
+ struct audio_usecase *usecase);
#ifndef HWDEP_CAL_ENABLED
#define audio_extn_hwdep_cal_send(snd_card, acdb_handle) (0)
#else
@@ -178,4 +186,8 @@
int audio_extn_snd_mon_unregister_listener(void *stream);
#endif
+bool audio_extn_utils_resolve_config_file(char[]);
+void audio_extn_utils_get_platform_info(const char* snd_card_name,
+ char* platform_info_file);
+int audio_extn_utils_get_snd_card_num();
#endif /* AUDIO_EXTN_H */
diff --git a/hal/audio_extn/usb.c b/hal/audio_extn/usb.c
index 3747318..a1af141 100644
--- a/hal/audio_extn/usb.c
+++ b/hal/audio_extn/usb.c
@@ -42,9 +42,12 @@
#define SAMPLE_RATE_11025 11025
/* TODO: dynamically populate supported sample rates */
static uint32_t supported_sample_rates[] =
- {44100, 48000, 64000, 88200, 96000, 176400, 192000, 384000};
+ {192000, 176400, 96000, 88200, 64000, 48000, 44100};
+static uint32_t supported_sample_rates_mask[2];
+static const uint32_t MAX_SAMPLE_RATE_SIZE =
+ (sizeof(supported_sample_rates)/sizeof(supported_sample_rates[0]));
-#define MAX_SAMPLE_RATE_SIZE sizeof(supported_sample_rates)/sizeof(supported_sample_rates[0])
+// assert on sizeof bm v/s size of rates if needed
enum usb_usecase_type{
USB_PLAYBACK = 0,
@@ -211,7 +214,7 @@
return 0;
}
-static int usb_get_sample_rates(char *rates_str,
+static int usb_get_sample_rates(int type, char *rates_str,
struct usb_device_config *config)
{
uint32_t i;
@@ -242,6 +245,7 @@
if (supported_sample_rates[i] >= min_sr &&
supported_sample_rates[i] <= max_sr) {
config->rates[sr_size++] = supported_sample_rates[i];
+ supported_sample_rates_mask[type] |= (1<<i);
ALOGI_IF(usb_audio_debug_enable,
"%s: continuous sample rate supported_sample_rates[%d] %d",
__func__, i, supported_sample_rates[i]);
@@ -256,6 +260,7 @@
"%s: sr %d, supported_sample_rates[%d] %d -> matches!!",
__func__, sr, i, supported_sample_rates[i]);
config->rates[sr_size++] = supported_sample_rates[i];
+ supported_sample_rates_mask[type] |= (1<<i);
}
}
next_sr_string = strtok_r(NULL, " ,.-", &temp_ptr);
@@ -418,7 +423,7 @@
}
memcpy(rates_str, rates_str_start, size);
rates_str[size] = '\0';
- ret = usb_get_sample_rates(rates_str, usb_device_info);
+ ret = usb_get_sample_rates(type, rates_str, usb_device_info);
if (rates_str)
free(rates_str);
if (ret < 0) {
@@ -876,6 +881,68 @@
return true;
}
+#define _MAX(x, y) (((x) >= (y)) ? (x) : (y))
+#define _MIN(x, y) (((x) <= (y)) ? (x) : (y))
+
+int audio_extn_usb_get_max_channels()
+{
+ struct listnode *node_i, *node_j;
+ struct usb_device_config *dev_info;
+ struct usb_card_config *card_info;
+ unsigned int max_ch = 1;
+ list_for_each(node_i, &usbmod->usb_card_conf_list) {
+ card_info = node_to_item(node_i, struct usb_card_config, list);
+ list_for_each(node_j, &card_info->usb_device_conf_list) {
+ dev_info = node_to_item(node_j, struct usb_device_config, list);
+ max_ch = _MAX(max_ch, dev_info->channel_count);
+ }
+ }
+
+ return max_ch;
+}
+
+int audio_extn_usb_get_max_bit_width()
+{
+ struct listnode *node_i, *node_j;
+ struct usb_device_config *dev_info;
+ struct usb_card_config *card_info;
+ unsigned int max_bw = 16;
+ list_for_each(node_i, &usbmod->usb_card_conf_list) {
+ card_info = node_to_item(node_i, struct usb_card_config, list);
+ list_for_each(node_j, &card_info->usb_device_conf_list) {
+ dev_info = node_to_item(node_j, struct usb_device_config, list);
+ max_bw = _MAX(max_bw, dev_info->bit_width);
+ }
+ }
+
+ return max_bw;
+}
+
+int audio_extn_usb_sup_sample_rates(int type,
+ uint32_t *sample_rates,
+ uint32_t sample_rate_size)
+{
+ struct listnode *node_i, *node_j;
+ struct usb_device_config *dev_info;
+ struct usb_card_config *card_info;
+
+ if (type != USB_PLAYBACK && type != USB_CAPTURE)
+ return -1;
+
+ ALOGV("%s supported_sample_rates_mask 0x%x", __func__, supported_sample_rates_mask[type]);
+ uint32_t bm = supported_sample_rates_mask[type];
+ uint32_t tries = _MIN(sample_rate_size, (uint32_t)__builtin_popcount(bm));
+
+ int i = 0;
+ while (tries--) {
+ int idx = __builtin_ffs(bm) - 1;
+ sample_rates[i++] = supported_sample_rates[idx];
+ bm &= ~(1<<idx);
+ }
+
+ return i;
+}
+
bool audio_extn_usb_is_capture_supported()
{
if (usbmod == NULL) {
@@ -997,6 +1064,8 @@
}
}
usbmod->is_capture_supported = false;
+ supported_sample_rates_mask[USB_PLAYBACK] = 0;
+ supported_sample_rates_mask[USB_CAPTURE] = 0;
exit:
if (usb_audio_debug_enable)
usb_print_active_device();
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index d2bb42c..e41af96 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -26,6 +26,7 @@
#include <cutils/log.h>
#include <cutils/misc.h>
+#include "acdb.h"
#include "audio_hw.h"
#include "platform.h"
#include "platform_api.h"
@@ -91,7 +92,7 @@
return;
}
-int audio_extn_utils_send_app_type_cfg(struct audio_device *adev,
+static int audio_extn_utils_send_app_type_cfg_hfp(struct audio_device *adev,
struct audio_usecase *usecase)
{
struct mixer_ctl *ctl;
@@ -177,3 +178,266 @@
exit_send_app_type_cfg:
return rc;
}
+
+int audio_extn_utils_send_app_type_cfg(struct audio_device *adev,
+ struct audio_usecase *usecase)
+{
+ int len = 0;
+ if (usecase->type == PCM_HFP_CALL) {
+ return audio_extn_utils_send_app_type_cfg_hfp(adev, usecase);
+ }
+
+ if (usecase->type != PCM_PLAYBACK || !platform_supports_app_type_cfg())
+ return -1;
+
+ size_t app_type_cfg[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {0};
+ int pcm_device_id = platform_get_pcm_device_id(usecase->id, PCM_PLAYBACK);
+
+ char mixer_ctl_name[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {0};
+ snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
+ "Audio Stream %d App Type Cfg", pcm_device_id);
+ struct mixer_ctl *ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s", __func__,
+ mixer_ctl_name);
+ return -EINVAL;
+ }
+
+ snd_device_t snd_device = usecase->out_snd_device; // add speaker prot changes if needed
+ int acdb_dev_id = platform_get_snd_device_acdb_id(snd_device);
+ if (acdb_dev_id <= 0) {
+ ALOGE("%s: Couldn't get the acdb dev id", __func__);
+ return -1;
+ }
+
+ if (usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER) {
+ usecase->stream.out->app_type_cfg.sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
+ } else if (snd_device == SND_DEVICE_OUT_USB_HEADSET ||
+ snd_device == SND_DEVICE_OUT_USB_HEADPHONES) {
+ platform_check_and_update_copp_sample_rate(adev->platform, snd_device,
+ usecase->stream.out->sample_rate,
+ &usecase->stream.out->app_type_cfg.sample_rate);
+ }
+
+ int32_t sample_rate = usecase->stream.out->app_type_cfg.sample_rate;
+ int app_type;
+ if (!audio_is_linear_pcm(usecase->stream.out->format)) {
+ platform_get_default_app_type_v2(adev->platform,
+ PCM_PLAYBACK,
+ &app_type);
+ } else if (usecase->stream.out->format == AUDIO_FORMAT_PCM_16_BIT) {
+ platform_get_app_type_v2(adev->platform,
+ 16,
+ sample_rate,
+ PCM_PLAYBACK,
+ &app_type);
+ } else if (usecase->stream.out->format == AUDIO_FORMAT_PCM_24_BIT_PACKED ||
+ usecase->stream.out->format == AUDIO_FORMAT_PCM_8_24_BIT) {
+ platform_get_app_type_v2(adev->platform,
+ 24,
+ sample_rate,
+ PCM_PLAYBACK,
+ &app_type);
+ } else if (usecase->stream.out->format == AUDIO_FORMAT_PCM_32_BIT) {
+ platform_get_app_type_v2(adev->platform,
+ 32,
+ sample_rate,
+ PCM_PLAYBACK,
+ &app_type);
+ } else {
+ ALOGE("%s bad format\n", __func__);
+ return -1;
+ }
+
+ //XXX this would be set somewhere else
+ usecase->stream.out->app_type_cfg.app_type = app_type;
+ app_type_cfg[len++] = app_type;
+ app_type_cfg[len++] = acdb_dev_id;
+ app_type_cfg[len++] = sample_rate;
+
+ // add be_idx once available
+ // if (snd_device_be_idx > 0)
+ // app_type_cfg[len++] = snd_device_be_idx;
+
+ ALOGI("%s PLAYBACK app_type %d, acdb_dev_id %d, sample_rate %d",
+ __func__, app_type, acdb_dev_id, sample_rate);
+
+ mixer_ctl_set_array(ctl, app_type_cfg, len);
+ return 0;
+}
+
+void audio_extn_utils_send_audio_calibration(struct audio_device *adev,
+ struct audio_usecase *usecase)
+{
+ int type = usecase->type;
+ int app_type = 0;
+
+ if (type == PCM_PLAYBACK && usecase->stream.out != NULL) {
+ struct stream_out *out = usecase->stream.out;
+ ALOGV("%s send cal for app_type %d, rate %d", __func__, out->app_type_cfg.app_type,
+ usecase->stream.out->app_type_cfg.sample_rate);
+ platform_send_audio_calibration_v2(adev->platform, usecase,
+ out->app_type_cfg.app_type,
+ usecase->stream.out->app_type_cfg.sample_rate);
+ } else if (type == PCM_CAPTURE && usecase->stream.in != NULL) {
+ // TBD
+ // platform_send_audio_calibration_v2(adev->platform, usecase,
+ // usecase->stream.in->app_type_cfg.app_type,
+ // usecase->stream.in->app_type_cfg.sample_rate);
+ // uncomment these once send_app_type_cfg and the config entries for
+ // non-16 bit capture are figured out.
+ platform_get_default_app_type_v2(adev->platform, type, &app_type);
+ platform_send_audio_calibration_v2(adev->platform, usecase, app_type, 48000);
+ } else {
+ /* when app type is default. the sample rate is not used to send cal */
+ platform_get_default_app_type_v2(adev->platform, type, &app_type);
+ platform_send_audio_calibration_v2(adev->platform, usecase, app_type, 48000);
+ }
+}
+
+#define MAX_SND_CARD 8
+#define RETRY_US 500000
+#define RETRY_NUMBER 10
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+static const char *kConfigLocationList[] =
+ {"/odm/etc", "/vendor/etc", "/system/etc"};
+static const int kConfigLocationListSize =
+ (sizeof(kConfigLocationList) / sizeof(kConfigLocationList[0]));
+
+bool audio_extn_utils_resolve_config_file(char file_name[MIXER_PATH_MAX_LENGTH])
+{
+ char full_config_path[MIXER_PATH_MAX_LENGTH];
+ for (int i = 0; i < kConfigLocationListSize; i++) {
+ snprintf(full_config_path,
+ MIXER_PATH_MAX_LENGTH,
+ "%s/%s",
+ kConfigLocationList[i],
+ file_name);
+ if (F_OK == access(full_config_path, 0)) {
+ strcpy(file_name, full_config_path);
+ return true;
+ }
+ }
+ return false;
+}
+
+/* platform_info_file should be size 'MIXER_PATH_MAX_LENGTH' */
+void audio_extn_utils_get_platform_info(const char* snd_card_name, char* platform_info_file)
+{
+ if (NULL == snd_card_name) {
+ return;
+ }
+
+ struct snd_card_split *snd_split_handle = NULL;
+
+ audio_extn_set_snd_card_split(snd_card_name);
+ snd_split_handle = audio_extn_get_snd_card_split();
+
+ snprintf(platform_info_file, MIXER_PATH_MAX_LENGTH, "%s_%s_%s.xml",
+ PLATFORM_INFO_XML_BASE_STRING, snd_split_handle->snd_card,
+ snd_split_handle->form_factor);
+
+ if (!audio_extn_utils_resolve_config_file(platform_info_file)) {
+ memset(platform_info_file, 0, MIXER_PATH_MAX_LENGTH);
+ snprintf(platform_info_file, MIXER_PATH_MAX_LENGTH, "%s_%s.xml",
+ PLATFORM_INFO_XML_BASE_STRING, snd_split_handle->snd_card);
+
+ if (!audio_extn_utils_resolve_config_file(platform_info_file)) {
+ memset(platform_info_file, 0, MIXER_PATH_MAX_LENGTH);
+ strlcpy(platform_info_file, PLATFORM_INFO_XML_PATH, MIXER_PATH_MAX_LENGTH);
+ audio_extn_utils_resolve_config_file(platform_info_file);
+ }
+ }
+}
+
+int audio_extn_utils_get_snd_card_num()
+{
+
+ void *hw_info = NULL;
+ struct mixer *mixer = NULL;
+ int retry_num = 0;
+ int snd_card_num = 0;
+ const char* snd_card_name = NULL;
+ char platform_info_file[MIXER_PATH_MAX_LENGTH]= {0};
+
+ struct acdb_platform_data *my_data = calloc(1, sizeof(struct acdb_platform_data));
+
+ bool card_verifed[MAX_SND_CARD] = {0};
+ const int retry_limit = property_get_int32("audio.snd_card.open.retries", RETRY_NUMBER);
+
+ for (;;) {
+ if (snd_card_num >= MAX_SND_CARD) {
+ if (retry_num++ >= retry_limit) {
+ ALOGE("%s: Unable to find correct sound card, aborting.", __func__);
+ snd_card_num = -1;
+ goto done;
+ }
+
+ snd_card_num = 0;
+ usleep(RETRY_US);
+ continue;
+ }
+
+ if (card_verifed[snd_card_num]) {
+ ++snd_card_num;
+ continue;
+ }
+
+ mixer = mixer_open(snd_card_num);
+
+ if (!mixer) {
+ ALOGE("%s: Unable to open the mixer card: %d", __func__,
+ snd_card_num);
+ ++snd_card_num;
+ continue;
+ }
+
+ card_verifed[snd_card_num] = true;
+
+ snd_card_name = mixer_get_name(mixer);
+ hw_info = hw_info_init(snd_card_name);
+
+ audio_extn_utils_get_platform_info(snd_card_name, platform_info_file);
+
+ /* Initialize snd card name specific ids and/or backends*/
+ snd_card_info_init(platform_info_file, my_data, &acdb_set_parameters);
+
+ /* validate the sound card name
+ * my_data->snd_card_name can contain
+ * <a> complete sound card name, i.e. <device>-<codec>-<form_factor>-snd-card
+ * example: msm8994-tomtom-mtp-snd-card
+ * <b> or sub string of the card name, i.e. <device>-<codec>
+ * example: msm8994-tomtom
+ * snd_card_name is truncated to 32 charaters as per mixer_get_name() implementation
+ * so use min of my_data->snd_card_name and snd_card_name length for comparison
+ */
+
+ if (my_data->snd_card_name != NULL &&
+ strncmp(snd_card_name, my_data->snd_card_name,
+ min(strlen(snd_card_name), strlen(my_data->snd_card_name))) != 0) {
+ ALOGI("%s: found valid sound card %s, but not primary sound card %s",
+ __func__, snd_card_name, my_data->snd_card_name);
+ ++snd_card_num;
+ mixer_close(mixer);
+ mixer = NULL;
+ hw_info_deinit(hw_info);
+ hw_info = NULL;
+ continue;
+ }
+
+ ALOGI("%s: found sound card %s, primary sound card expeted is %s",
+ __func__, snd_card_name, my_data->snd_card_name);
+ break;
+ }
+
+done:
+ mixer_close(mixer);
+ hw_info_deinit(hw_info);
+
+ if (my_data)
+ free(my_data);
+
+ return snd_card_num;
+}
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index e7de4a9..9fad3fd 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -159,6 +159,17 @@
.avail_min = MMAP_PERIOD_SIZE, //1 ms
};
+struct pcm_config pcm_config_hifi = {
+ .channels = DEFAULT_CHANNEL_COUNT, /* changed when the stream is opened */
+ .rate = DEFAULT_OUTPUT_SAMPLING_RATE, /* changed when the stream is opened */
+ .period_size = DEEP_BUFFER_OUTPUT_PERIOD_SIZE, /* change #define */
+ .period_count = DEEP_BUFFER_OUTPUT_PERIOD_COUNT,
+ .format = PCM_FORMAT_S24_3LE,
+ .start_threshold = 0,
+ .stop_threshold = INT_MAX,
+ .avail_min = 0,
+};
+
struct pcm_config pcm_config_audio_capture = {
.channels = DEFAULT_CHANNEL_COUNT,
.period_count = AUDIO_CAPTURE_PERIOD_COUNT,
@@ -227,7 +238,7 @@
const char * const use_case_table[AUDIO_USECASE_MAX] = {
[USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = "deep-buffer-playback",
[USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = "low-latency-playback",
- [USECASE_AUDIO_PLAYBACK_MULTI_CH] = "multi-channel-playback",
+ [USECASE_AUDIO_PLAYBACK_HIFI] = "hifi-playback",
[USECASE_AUDIO_PLAYBACK_OFFLOAD] = "compress-offload-playback",
[USECASE_AUDIO_PLAYBACK_TTS] = "audio-tts-playback",
[USECASE_AUDIO_PLAYBACK_ULL] = "audio-ull-playback",
@@ -253,6 +264,11 @@
[USECASE_AUDIO_PLAYBACK_AFE_PROXY] = "afe-proxy-playback",
[USECASE_AUDIO_RECORD_AFE_PROXY] = "afe-proxy-record",
+
+ [USECASE_INCALL_REC_UPLINK] = "incall-rec-uplink",
+ [USECASE_INCALL_REC_DOWNLINK] = "incall-rec-downlink",
+ [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK] = "incall-rec-uplink-and-downlink",
+
};
@@ -523,6 +539,7 @@
snd_device = usecase->out_snd_device;
audio_extn_utils_send_app_type_cfg(adev, usecase);
+ audio_extn_utils_send_audio_calibration(adev, usecase);
strcpy(mixer_path, use_case_table[usecase->id]);
platform_add_backend_name(adev->platform, mixer_path, snd_device);
ALOGD("%s: usecase(%d) apply and update mixer path: %s", __func__, usecase->id, mixer_path);
@@ -943,6 +960,50 @@
return ret;
}
+static int read_usb_sup_sample_rates(struct stream_out *out)
+{
+ uint32_t *sr = out->supported_sample_rates;
+ size_t count = audio_extn_usb_sup_sample_rates(0 /*playback*/,
+ sr,
+ MAX_SUPPORTED_SAMPLE_RATES);
+#if !LOG_NDEBUG
+
+ for (size_t i=0; i<count; i++) {
+ ALOGV("%s %d", __func__, out->supported_sample_rates[i]);
+ }
+#endif
+ return count > 0 ? 0 : -1;
+}
+
+static int read_usb_sup_channel_masks(struct stream_out *out)
+{
+ int channels = audio_extn_usb_get_max_channels();
+ out->supported_channel_masks[0] =
+ channels < 3 ? audio_channel_out_mask_from_count(channels) :
+ audio_channel_mask_for_index_assignment_from_count(channels);
+ return 0;
+}
+
+static int read_usb_sup_formats(struct stream_out *out)
+{
+ int bitwidth = audio_extn_usb_get_max_bit_width();
+ switch (bitwidth) {
+ case 24:
+ // XXX : usb.c returns 24 for s24 and s24_le?
+ out->supported_formats[0] = AUDIO_FORMAT_PCM_24_BIT_PACKED;
+ break;
+ case 32:
+ out->supported_formats[0] = AUDIO_FORMAT_PCM_32_BIT;
+ break;
+ case 16:
+ default :
+ out->supported_formats[0] = AUDIO_FORMAT_PCM_16_BIT;
+ break;
+ }
+
+ return 0;
+}
+
static audio_usecase_t get_voice_usecase_id_from_list(struct audio_device *adev)
{
struct audio_usecase *usecase;
@@ -1186,6 +1247,9 @@
return -EINVAL;
}
+ /* Close in-call recording streams */
+ voice_check_and_stop_incall_rec_usecase(adev, in);
+
/* 1. Disable stream specific mixer controls */
disable_audio_route(adev, uc_info);
@@ -1218,6 +1282,13 @@
goto error_config;
}
+ /* Check if source matches incall recording usecase criteria */
+ ret = voice_check_and_set_incall_rec_usecase(adev, in);
+ if (ret)
+ goto error_config;
+ else
+ ALOGV("%s: usecase(%d)", __func__, in->usecase);
+
in->pcm_device_id = platform_get_pcm_device_id(in->usecase, PCM_CAPTURE);
if (in->pcm_device_id < 0) {
ALOGE("%s: Could not find PCM device id for the usecase(%d)",
@@ -1500,8 +1571,8 @@
__func__);
ret = false;
break;
- } else if (usecase->id == USECASE_AUDIO_PLAYBACK_MULTI_CH) {
- ALOGV("%s: multi channel playback is active, "
+ } else if (usecase->id == USECASE_AUDIO_PLAYBACK_HIFI) {
+ ALOGV("%s: hifi playback is active, "
"no change in HDMI channels", __func__);
ret = false;
break;
@@ -2070,6 +2141,7 @@
char *str;
char value[256];
struct str_parms *reply = str_parms_create();
+ bool replied = false;
size_t i, j;
int ret;
bool first = true;
@@ -2092,6 +2164,62 @@
i++;
}
str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value);
+ replied = true;
+ }
+
+ ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS, value, sizeof(value));
+ if (ret >= 0) {
+ value[0] = '\0';
+ switch (out->supported_formats[0]) {
+ case AUDIO_FORMAT_PCM_16_BIT:
+ strcat(value, "AUDIO_FORMAT_PCM_16_BIT");
+ break;
+ case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+ strcat(value, "AUDIO_FORMAT_PCM_24_BIT_PACKED");
+ break;
+ case AUDIO_FORMAT_PCM_32_BIT:
+ strcat(value, "AUDIO_FORMAT_PCM_32_BIT");
+ break;
+ default:
+ ALOGE("%s: unsupported format %#x", __func__,
+ out->supported_formats[0]);
+ break;
+ }
+ str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_FORMATS, value);
+ replied = true;
+ }
+
+ ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES,
+ value, sizeof(value));
+ if (ret >= 0) {
+ value[0] = '\0';
+ i=0;
+ int cursor = 0;
+ while (out->supported_sample_rates[i]) {
+ int avail = sizeof(value) - cursor;
+ ret = snprintf(value + cursor, avail, "%s%d",
+ cursor > 0 ? "|" : "",
+ out->supported_sample_rates[i]);
+ if (ret < 0 || ret >= avail) {
+ // if cursor is at the last element of the array
+ // overwrite with \0 is duplicate work as
+ // snprintf already put a \0 in place.
+ // else
+ // we had space to write the '|' at value[cursor]
+ // (which will be overwritten) or no space to fill
+ // the first element (=> cursor == 0)
+ value[cursor] = '\0';
+ break;
+ }
+ cursor += ret;
+ ++i;
+ }
+ str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES,
+ value);
+ replied = true;
+ }
+
+ if (replied) {
str = str_parms_to_str(reply);
} else {
str = strdup("");
@@ -2129,7 +2257,7 @@
struct stream_out *out = (struct stream_out *)stream;
int volume[2];
- if (out->usecase == USECASE_AUDIO_PLAYBACK_MULTI_CH) {
+ if (out->usecase == USECASE_AUDIO_PLAYBACK_HIFI) {
/* only take left channel into account: the API is for stereo anyway */
out->muted = (left == 0.0f);
return 0;
@@ -3202,6 +3330,7 @@
struct audio_device *adev = (struct audio_device *)dev;
struct stream_out *out;
int i, ret;
+ const uint32_t direct_dev = (AUDIO_DEVICE_OUT_HDMI|AUDIO_DEVICE_OUT_USB_DEVICE);
ALOGV("%s: enter: sample_rate(%d) channel_mask(%#x) devices(%#x) flags(%#x)",
__func__, config->sample_rate, config->channel_mask, devices, flags);
@@ -3221,30 +3350,50 @@
out->handle = handle;
/* Init use case and pcm_config */
- if (out->flags & AUDIO_OUTPUT_FLAG_DIRECT &&
- !(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
- out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+ if (audio_is_linear_pcm(out->format) &&
+ (out->flags == AUDIO_OUTPUT_FLAG_NONE ||
+ out->flags == AUDIO_OUTPUT_FLAG_DIRECT) &&
+ (out->devices & direct_dev)) {
+
+ bool hdmi = (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL);
+
pthread_mutex_lock(&adev->lock);
- ret = read_hdmi_channel_masks(out);
+ if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+ ret = read_hdmi_channel_masks(out);
+ } else if (out->devices & AUDIO_DEVICE_OUT_USB_DEVICE) {
+ ret = read_usb_sup_formats(out) ||
+ read_usb_sup_channel_masks(out) ||
+ read_usb_sup_sample_rates(out);
+ ALOGV("plugged dev USB ret %d", ret);
+ } else {
+ ret = -1;
+ }
pthread_mutex_unlock(&adev->lock);
if (ret != 0)
goto error_open;
- if (config->sample_rate == 0)
- config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
- if (config->channel_mask == 0)
- config->channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
- if (config->format == AUDIO_FORMAT_DEFAULT)
- config->format = AUDIO_FORMAT_PCM_16_BIT;
-
- out->channel_mask = config->channel_mask;
- out->sample_rate = config->sample_rate;
- out->format = config->format;
- out->usecase = USECASE_AUDIO_PLAYBACK_MULTI_CH;
- out->config = pcm_config_hdmi_multi;
+ if (config->sample_rate == 0) {
+ out->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
+ } else {
+ out->sample_rate = config->sample_rate;
+ }
+ if (config->channel_mask == 0) {
+ out->channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
+ } else {
+ out->channel_mask = config->channel_mask;
+ }
+ if (config->format == AUDIO_FORMAT_DEFAULT) {
+ out->format = AUDIO_FORMAT_PCM_16_BIT;
+ } else {
+ out->format = config->format;
+ }
+ out->usecase = USECASE_AUDIO_PLAYBACK_HIFI;
+ // does this change?
+ out->config = hdmi ? pcm_config_hdmi_multi : pcm_config_hifi;
out->config.rate = config->sample_rate;
out->config.channels = audio_channel_count_from_out_mask(out->channel_mask);
out->config.period_size = HDMI_MULTI_PERIOD_BYTES / (out->config.channels * 2);
+ out->config.format = pcm_format_from_audio_format(out->format);
} else if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
pthread_mutex_lock(&adev->lock);
bool offline = (adev->card_status == CARD_STATUS_OFFLINE);
@@ -3306,24 +3455,16 @@
__func__, config->offload_info.version,
config->offload_info.bit_rate);
} else if (out->devices == AUDIO_DEVICE_OUT_TELEPHONY_TX) {
- if (config->sample_rate == 0)
- config->sample_rate = AFE_PROXY_SAMPLING_RATE;
- if (config->sample_rate != 48000 && config->sample_rate != 16000 &&
- config->sample_rate != 8000) {
- config->sample_rate = AFE_PROXY_SAMPLING_RATE;
- ret = -EINVAL;
- goto error_open;
+ switch (config->sample_rate) {
+ case 8000:
+ case 16000:
+ case 48000:
+ out->sample_rate = config->sample_rate;
+ break;
+ default:
+ out->sample_rate = AFE_PROXY_SAMPLING_RATE;
}
- out->sample_rate = config->sample_rate;
- out->config.rate = config->sample_rate;
- if (config->format == AUDIO_FORMAT_DEFAULT)
- config->format = AUDIO_FORMAT_PCM_16_BIT;
- if (config->format != AUDIO_FORMAT_PCM_16_BIT) {
- config->format = AUDIO_FORMAT_PCM_16_BIT;
- ret = -EINVAL;
- goto error_open;
- }
- out->format = config->format;
+ out->format = AUDIO_FORMAT_PCM_16_BIT;
out->usecase = USECASE_AUDIO_PLAYBACK_AFE_PROXY;
out->config = pcm_config_afe_proxy_playback;
adev->voice_tx_output = out;
@@ -3366,6 +3507,19 @@
}
out->sample_rate = out->config.rate;
}
+
+ if ((config->sample_rate != 0 && config->sample_rate != out->sample_rate) ||
+ (config->format != AUDIO_FORMAT_DEFAULT && config->format != out->format) ||
+ (config->channel_mask != 0 && config->channel_mask != out->channel_mask)) {
+ ALOGI("%s: Unsupported output config. sample_rate:%u format:%#x channel_mask:%#x",
+ __func__, config->sample_rate, config->format, config->channel_mask);
+ config->sample_rate = out->sample_rate;
+ config->format = out->format;
+ config->channel_mask = out->channel_mask;
+ ret = -EINVAL;
+ goto error_open;
+ }
+
ALOGV("%s: Usecase(%s) config->format %#x out->config.format %#x\n",
__func__, use_case_table[out->usecase], config->format, out->config.format);
@@ -3947,13 +4101,13 @@
*
* [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {0, 0},
* [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {15, 15},
- * [USECASE_AUDIO_PLAYBACK_MULTI_CH] = {1, 1},
+ * [USECASE_AUDIO_PLAYBACK_HIFI] = {1, 1},
* [USECASE_AUDIO_PLAYBACK_OFFLOAD] = {9, 9},
* [USECASE_AUDIO_RECORD] = {0, 0},
* [USECASE_AUDIO_RECORD_LOW_LATENCY] = {15, 15},
* [USECASE_VOICE_CALL] = {2, 2},
*
- * USECASE_AUDIO_PLAYBACK_OFFLOAD, USECASE_AUDIO_PLAYBACK_MULTI_CH omitted.
+ * USECASE_AUDIO_PLAYBACK_OFFLOAD, USECASE_AUDIO_PLAYBACK_HIFI omitted.
* USECASE_VOICE_CALL omitted, but possible for either input or output.
*/
@@ -4290,7 +4444,8 @@
}
}
- audio_extn_utils_send_default_app_type_cfg(adev->platform, adev->mixer);
+ // commented as full set of app type cfg is sent from platform
+ // audio_extn_utils_send_default_app_type_cfg(adev->platform, adev->mixer);
audio_device_ref_count++;
if (property_get("audio_hal.period_multiplier", value, NULL) > 0) {
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index ca068e2..e410d64 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -50,7 +50,7 @@
#define ACDB_DEV_TYPE_OUT 1
#define ACDB_DEV_TYPE_IN 2
-#define MAX_SUPPORTED_CHANNEL_MASKS 2
+#define MAX_SUPPORTED_CHANNEL_MASKS 8
#define MAX_SUPPORTED_FORMATS 15
#define MAX_SUPPORTED_SAMPLE_RATES 7
#define DEFAULT_HDMI_OUT_CHANNELS 2
@@ -82,7 +82,7 @@
/* Playback usecases */
USECASE_AUDIO_PLAYBACK_DEEP_BUFFER = 0,
USECASE_AUDIO_PLAYBACK_LOW_LATENCY,
- USECASE_AUDIO_PLAYBACK_MULTI_CH,
+ USECASE_AUDIO_PLAYBACK_HIFI,
USECASE_AUDIO_PLAYBACK_OFFLOAD,
USECASE_AUDIO_PLAYBACK_TTS,
USECASE_AUDIO_PLAYBACK_ULL,
@@ -167,6 +167,12 @@
int data[];
};
+struct stream_app_type_cfg {
+ int sample_rate;
+ uint32_t bit_width;
+ int app_type;
+};
+
struct stream_out {
struct audio_stream_out stream;
pthread_mutex_t lock; /* see note below on mutex acquisition order */
@@ -186,9 +192,12 @@
audio_usecase_t usecase;
/* Array of supported channel mask configurations. +1 so that the last entry is always 0 */
audio_channel_mask_t supported_channel_masks[MAX_SUPPORTED_CHANNEL_MASKS + 1];
+ audio_format_t supported_formats[MAX_SUPPORTED_FORMATS + 1];
+ uint32_t supported_sample_rates[MAX_SUPPORTED_SAMPLE_RATES + 1];
bool muted;
uint64_t written; /* total frames written, not cleared when entering standby */
audio_io_handle_t handle;
+ struct stream_app_type_cfg app_type_cfg;
int non_blocking;
int playback_started;
@@ -243,7 +252,8 @@
PCM_PLAYBACK,
PCM_CAPTURE,
VOICE_CALL,
- PCM_HFP_CALL
+ PCM_HFP_CALL,
+ USECASE_TYPE_MAX
} usecase_type_t;
union stream_ptr {
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index 2fe6168..aa3419d 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -157,7 +157,7 @@
DEEP_BUFFER_PCM_DEVICE},
[USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE,
LOWLATENCY_PCM_DEVICE},
- [USECASE_AUDIO_PLAYBACK_MULTI_CH] = {MULTIMEDIA2_PCM_DEVICE,
+ [USECASE_AUDIO_PLAYBACK_HIFI] = {MULTIMEDIA2_PCM_DEVICE,
MULTIMEDIA2_PCM_DEVICE},
[USECASE_AUDIO_PLAYBACK_OFFLOAD] =
{PLAYBACK_OFFLOAD_DEVICE, PLAYBACK_OFFLOAD_DEVICE},
@@ -215,6 +215,7 @@
[SND_DEVICE_OUT_VOICE_TX] = "voice-tx",
[SND_DEVICE_OUT_AFE_PROXY] = "afe-proxy",
[SND_DEVICE_OUT_USB_HEADSET] = "usb-headphones",
+ [SND_DEVICE_OUT_USB_HEADPHONES] = "usb-headphones",
[SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = "speaker-and-usb-headphones",
[SND_DEVICE_OUT_SPEAKER_PROTECTED] = "speaker-protected",
[SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED] = "voice-speaker-protected",
@@ -302,6 +303,7 @@
[SND_DEVICE_OUT_VOICE_TX] = 45,
[SND_DEVICE_OUT_AFE_PROXY] = 0,
[SND_DEVICE_OUT_USB_HEADSET] = 45,
+ [SND_DEVICE_OUT_USB_HEADPHONES] = 45,
[SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = 14,
[SND_DEVICE_OUT_SPEAKER_PROTECTED] = 124,
[SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED] = 101,
@@ -396,6 +398,7 @@
{TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_TX)},
{TO_NAME_INDEX(SND_DEVICE_OUT_AFE_PROXY)},
{TO_NAME_INDEX(SND_DEVICE_OUT_USB_HEADSET)},
+ {TO_NAME_INDEX(SND_DEVICE_OUT_USB_HEADPHONES)},
{TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET)},
{TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_PROTECTED)},
{TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED)},
@@ -462,7 +465,7 @@
static struct name_to_index usecase_name_index[AUDIO_USECASE_MAX] = {
{TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_DEEP_BUFFER)},
{TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_LOW_LATENCY)},
- {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_MULTI_CH)},
+ {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_HIFI)},
{TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD)},
{TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_ULL)},
{TO_NAME_INDEX(USECASE_AUDIO_RECORD)},
@@ -663,6 +666,7 @@
backend_table[SND_DEVICE_IN_VOICE_RX] = strdup("afe-proxy");
backend_table[SND_DEVICE_OUT_AFE_PROXY] = strdup("afe-proxy");
backend_table[SND_DEVICE_OUT_USB_HEADSET] = strdup("usb-headphones");
+ backend_table[SND_DEVICE_OUT_USB_HEADPHONES] = strdup("usb-headphones");
backend_table[SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] =
strdup("speaker-and-usb-headphones");
backend_table[SND_DEVICE_IN_USB_HEADSET_MIC] = strdup("usb-headset-mic");
@@ -2294,3 +2298,36 @@
{
return -1;
}
+
+int platform_send_audio_calibration_v2(void *platform __unused,
+ struct audio_usecase *usecase __unused,
+ int app_type __unused,
+ int sample_rate __unused)
+{
+ return -ENOSYS;
+}
+
+void platform_check_and_update_copp_sample_rate(void* platform __unused,
+ snd_device_t snd_device __unused,
+ unsigned int stream_sr __unused,
+ int* sample_rate __unused)
+{
+
+}
+
+int platform_get_snd_device_backend_index(snd_device_t snd_device __unused)
+{
+ return -ENOSYS;
+}
+
+bool platform_supports_app_type_cfg() { return false; }
+
+void platform_add_app_type(int bw __unused, const char *uc_type __unused,
+ int app_type __unused, int max_sr __unused) {}
+
+int platform_get_app_type_v2(void *platform __unused,
+ enum usecase_type_t type __unused,
+ int bw __unused, int sr __unused,
+ int *app_type __unused) {
+ return -ENOSYS;
+}
diff --git a/hal/msm8916/platform.h b/hal/msm8916/platform.h
index da4a027..6e1fb88 100644
--- a/hal/msm8916/platform.h
+++ b/hal/msm8916/platform.h
@@ -76,6 +76,7 @@
SND_DEVICE_OUT_VOICE_TX,
SND_DEVICE_OUT_AFE_PROXY,
SND_DEVICE_OUT_USB_HEADSET,
+ SND_DEVICE_OUT_USB_HEADPHONES,
SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET,
SND_DEVICE_OUT_ANC_HEADSET,
SND_DEVICE_OUT_ANC_FB_HEADSET,
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index 072a1e4..cfae645 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -1133,3 +1133,31 @@
{
return -1;
}
+
+int platform_get_snd_device_backend_index(snd_device_t snd_device)
+{
+ return -ENOSYS;
+}
+
+void platform_check_and_update_copp_sample_rate(void* platform, snd_device_t snd_device,
+ unsigned int stream_sr, int* sample_rate)
+{
+
+}
+
+int platform_send_audio_calibration_v2(void *platform, struct audio_usecase *usecase,
+ int app_type, int sample_rate)
+{
+ return -ENOSYS;
+}
+
+bool platform_supports_app_type_cfg() { return false; }
+
+void platform_add_app_type(int bw, const char *uc_type,
+ int app_type, int max_sr) {}
+
+
+int platform_get_app_type_v2(void *platform, enum usecase_type_t type,
+ int bw, int sr, int *app_type) {
+ return -ENOSYS;
+}
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 0f3bcf0..b9812b1 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -24,6 +24,7 @@
#include <cutils/properties.h>
#include <audio_hw.h>
#include <platform_api.h>
+#include "acdb.h"
#include "platform.h"
#include "audio_extn.h"
#include <linux/msm_audio.h>
@@ -54,14 +55,10 @@
/* EDID format ID for LPCM audio */
#define EDID_FORMAT_LPCM 1
-/* Retry for delay in FW loading*/
-#define RETRY_NUMBER 10
-#define RETRY_US 500000
-#define MAX_SND_CARD 8
-
#define MAX_SND_CARD_NAME_LEN 31
-#define DEFAULT_APP_TYPE_RX_PATH 0x11130
+#define DEFAULT_APP_TYPE_RX_PATH 69936
+#define DEFAULT_APP_TYPE_TX_PATH 69938
#define TOSTRING_(x) #x
#define TOSTRING(x) TOSTRING_(x)
@@ -93,21 +90,18 @@
int acdb_id;
};
+#define BE_DAI_NAME_MAX_LENGTH 24
+struct be_dai_name_struct {
+ unsigned int be_id;
+ char be_name[BE_DAI_NAME_MAX_LENGTH];
+};
+
static struct listnode operator_info_list;
static struct listnode *operator_specific_device_table[SND_DEVICE_MAX];
/* Audio calibration related functions */
-typedef void (*acdb_deallocate_t)();
-typedef int (*acdb_init_v2_cvd_t)(char *, char *, int);
-typedef int (*acdb_init_v2_t)(char *);
-typedef int (*acdb_init_t)();
-typedef void (*acdb_send_audio_cal_t)(int, int);
-typedef void (*acdb_send_voice_cal_t)(int, int);
-typedef int (*acdb_reload_vocvoltable_t)(int);
-typedef int (*acdb_send_gain_dep_cal_t)(int, int, int, int, int);
-typedef int (*acdb_send_custom_top_t) (void);
+typedef void (*acdb_send_audio_cal_v3_t)(int, int, int, int, int);
-/* Audio calibration related functions */
struct platform_data {
struct audio_device *adev;
bool fluence_in_spkr_mode;
@@ -129,6 +123,7 @@
#endif
acdb_deallocate_t acdb_deallocate;
acdb_send_audio_cal_t acdb_send_audio_cal;
+ acdb_send_audio_cal_v3_t acdb_send_audio_cal_v3;
acdb_send_voice_cal_t acdb_send_voice_cal;
acdb_reload_vocvoltable_t acdb_reload_vocvoltable;
acdb_send_gain_dep_cal_t acdb_send_gain_dep_cal;
@@ -151,7 +146,7 @@
DEEP_BUFFER_PCM_DEVICE},
[USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE,
LOWLATENCY_PCM_DEVICE},
- [USECASE_AUDIO_PLAYBACK_MULTI_CH] = {MULTIMEDIA2_PCM_DEVICE,
+ [USECASE_AUDIO_PLAYBACK_HIFI] = {MULTIMEDIA2_PCM_DEVICE,
MULTIMEDIA2_PCM_DEVICE},
[USECASE_AUDIO_PLAYBACK_OFFLOAD] = {PLAYBACK_OFFLOAD_DEVICE,
PLAYBACK_OFFLOAD_DEVICE},
@@ -231,7 +226,9 @@
[SND_DEVICE_OUT_VOICE_TTY_VCO_USB] = "voice-tty-vco-usb",
[SND_DEVICE_OUT_VOICE_TX] = "voice-tx",
[SND_DEVICE_OUT_USB_HEADSET] = "usb-headset",
+ [SND_DEVICE_OUT_VOICE_USB_HEADSET] = "usb-headset",
[SND_DEVICE_OUT_USB_HEADPHONES] = "usb-headphones",
+ [SND_DEVICE_OUT_VOICE_USB_HEADPHONES] = "usb-headphones",
[SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = "speaker-and-usb-headphones",
[SND_DEVICE_OUT_SPEAKER_PROTECTED] = "speaker-protected",
[SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED] = "voice-speaker-protected",
@@ -289,6 +286,10 @@
[SND_DEVICE_IN_VOICE_REC_DMIC_STEREO] = "voice-rec-dmic-ef",
[SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = "voice-rec-dmic-ef-fluence",
[SND_DEVICE_IN_USB_HEADSET_MIC] = "usb-headset-mic",
+ [SND_DEVICE_IN_VOICE_USB_HEADSET_MIC] ="usb-headset-mic",
+ [SND_DEVICE_IN_USB_HEADSET_MIC_AEC] = "usb-headset-mic",
+ [SND_DEVICE_IN_UNPROCESSED_USB_HEADSET_MIC] = "usb-headset-mic",
+ [SND_DEVICE_IN_VOICE_RECOG_USB_HEADSET_MIC] = "usb-headset-mic",
[SND_DEVICE_IN_VOICE_REC_HEADSET_MIC] = "headset-mic",
[SND_DEVICE_IN_UNPROCESSED_MIC] = "unprocessed-mic",
@@ -338,7 +339,9 @@
[SND_DEVICE_OUT_VOICE_TTY_VCO_USB] = 17,
[SND_DEVICE_OUT_VOICE_TX] = 45,
[SND_DEVICE_OUT_USB_HEADSET] = 45,
+ [SND_DEVICE_OUT_VOICE_USB_HEADSET] = 45,
[SND_DEVICE_OUT_USB_HEADPHONES] = 45,
+ [SND_DEVICE_OUT_VOICE_USB_HEADPHONES] = 45,
[SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = 14,
[SND_DEVICE_OUT_SPEAKER_PROTECTED] = 124,
[SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED] = 101,
@@ -402,6 +405,10 @@
[SND_DEVICE_IN_VOICE_RX] = 44,
[SND_DEVICE_IN_USB_HEADSET_MIC] = 44,
+ [SND_DEVICE_IN_VOICE_USB_HEADSET_MIC] = 44,
+ [SND_DEVICE_IN_UNPROCESSED_USB_HEADSET_MIC] = 44,
+ [SND_DEVICE_IN_VOICE_RECOG_USB_HEADSET_MIC] = 44,
+ [SND_DEVICE_IN_USB_HEADSET_MIC_AEC] = 44,
[SND_DEVICE_IN_THREE_MIC] = 46,
[SND_DEVICE_IN_QUAD_MIC] = 46,
[SND_DEVICE_IN_CAPTURE_VI_FEEDBACK] = 102,
@@ -453,7 +460,9 @@
{TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_TTY_FULL_USB)},
{TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_TTY_VCO_USB)},
{TO_NAME_INDEX(SND_DEVICE_OUT_USB_HEADSET)},
+ {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_USB_HEADSET)},
{TO_NAME_INDEX(SND_DEVICE_OUT_USB_HEADPHONES)},
+ {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_USB_HEADPHONES)},
{TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET)},
{TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_PROTECTED)},
{TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED)},
@@ -510,6 +519,10 @@
{TO_NAME_INDEX(SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE)},
{TO_NAME_INDEX(SND_DEVICE_IN_VOICE_REC_HEADSET_MIC)},
{TO_NAME_INDEX(SND_DEVICE_IN_USB_HEADSET_MIC)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_USB_HEADSET_MIC)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_UNPROCESSED_USB_HEADSET_MIC)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_RECOG_USB_HEADSET_MIC)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_USB_HEADSET_MIC_AEC)},
{TO_NAME_INDEX(SND_DEVICE_IN_UNPROCESSED_MIC)},
{TO_NAME_INDEX(SND_DEVICE_IN_UNPROCESSED_HEADSET_MIC)},
@@ -532,7 +545,7 @@
static const struct name_to_index usecase_name_index[AUDIO_USECASE_MAX] = {
{TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_DEEP_BUFFER)},
{TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_LOW_LATENCY)},
- {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_MULTI_CH)},
+ {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_HIFI)},
{TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD)},
{TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_TTS)},
{TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_ULL)},
@@ -558,6 +571,23 @@
{TO_NAME_INDEX(USECASE_AUDIO_DSM_FEEDBACK)},
};
+static const struct name_to_index usecase_type_index[USECASE_TYPE_MAX] = {
+ {TO_NAME_INDEX(PCM_PLAYBACK)},
+ {TO_NAME_INDEX(PCM_CAPTURE)},
+ {TO_NAME_INDEX(VOICE_CALL)},
+ {TO_NAME_INDEX(PCM_HFP_CALL)},
+};
+
+struct app_type_entry {
+ int uc_type;
+ int bit_width;
+ int app_type;
+ int max_rate;
+ struct listnode node; // membership in app_type_entry_list;
+};
+
+static struct listnode app_type_entry_list;
+
#define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL)
#define LOW_LATENCY_PLATFORM_DELAY (13*1000LL)
#define ULL_PLATFORM_DELAY (3*1000LL)
@@ -566,6 +596,8 @@
static pthread_once_t check_op_once_ctl = PTHREAD_ONCE_INIT;
static bool is_tmus = false;
+static int init_be_dai_name_table(struct audio_device *adev);
+
static void check_operator()
{
char value[PROPERTY_VALUE_MAX];
@@ -667,6 +699,15 @@
return ret;
}
+inline bool platform_supports_app_type_cfg()
+{
+#ifdef PLATFORM_MSM8998
+ return true;
+#else
+ return false;
+#endif
+}
+
bool platform_send_gain_dep_cal(void *platform, int level)
{
bool ret_val = false;
@@ -952,10 +993,16 @@
backend_tag_table[SND_DEVICE_IN_VOICE_RX] = strdup("afe-proxy");
backend_tag_table[SND_DEVICE_OUT_USB_HEADSET] = strdup("usb-headset");
+ backend_tag_table[SND_DEVICE_OUT_VOICE_USB_HEADSET] = strdup("usb-headset");
backend_tag_table[SND_DEVICE_OUT_USB_HEADPHONES] = strdup("usb-headphones");
+ backend_tag_table[SND_DEVICE_OUT_VOICE_USB_HEADPHONES] = strdup("usb-headphones");
backend_tag_table[SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] =
strdup("speaker-and-usb-headphones");
backend_tag_table[SND_DEVICE_IN_USB_HEADSET_MIC] = strdup("usb-headset-mic");
+ backend_tag_table[SND_DEVICE_IN_VOICE_USB_HEADSET_MIC] = strdup("usb-headset-mic");
+ backend_tag_table[SND_DEVICE_IN_UNPROCESSED_USB_HEADSET_MIC] = strdup("usb-headset-mic");
+ backend_tag_table[SND_DEVICE_IN_VOICE_RECOG_USB_HEADSET_MIC] = strdup("usb-headset-mic");
+ backend_tag_table[SND_DEVICE_IN_USB_HEADSET_MIC_AEC] = strdup("usb-headset-mic");
hw_interface_table[SND_DEVICE_OUT_HANDSET] = strdup("SLIMBUS_0_RX");
hw_interface_table[SND_DEVICE_OUT_SPEAKER] = strdup("SLIMBUS_0_RX");
hw_interface_table[SND_DEVICE_OUT_SPEAKER_REVERSE] = strdup("SLIMBUS_0_RX");
@@ -980,7 +1027,9 @@
hw_interface_table[SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = strdup("SLIMBUS_0_RX");
hw_interface_table[SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = strdup("SLIMBUS_0_RX");
hw_interface_table[SND_DEVICE_OUT_USB_HEADSET] = strdup("USB_AUDIO_RX");
+ hw_interface_table[SND_DEVICE_OUT_VOICE_USB_HEADSET] = strdup("USB_AUDIO_RX");
hw_interface_table[SND_DEVICE_OUT_USB_HEADPHONES] = strdup("USB_AUDIO_RX");
+ hw_interface_table[SND_DEVICE_OUT_VOICE_USB_HEADPHONES] = strdup("USB_AUDIO_RX");
hw_interface_table[SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = strdup("SLIMBUS_0_RX-and-USB_AUDIO_RX");
hw_interface_table[SND_DEVICE_OUT_VOICE_TX] = strdup("AFE_PCM_RX");
hw_interface_table[SND_DEVICE_OUT_SPEAKER_PROTECTED] = strdup("SLIMBUS_0_RX");
@@ -1100,26 +1149,51 @@
strdup("USB_AUDIO_RX Channels");
}
-// Treblized config files will be located in /odm/etc or /vendor/etc.
-static const char *kConfigLocationList[] =
- {"/odm/etc", "/vendor/etc", "/system/etc"};
-static const int kConfigLocationListSize =
- (sizeof(kConfigLocationList) / sizeof(kConfigLocationList[0]));
+static int
+platform_backend_app_type_cfg_init(struct platform_data *pdata,
+ struct mixer *mixer)
+{
+ size_t app_type_cfg[128] = {0};
+ int length, num_app_types = 0;
+ struct mixer_ctl *ctl = NULL;
-bool resolveConfigFile(char file_name[MIXER_PATH_MAX_LENGTH]) {
- char full_config_path[MIXER_PATH_MAX_LENGTH];
- for (int i = 0; i < kConfigLocationListSize; i++) {
- snprintf(full_config_path,
- MIXER_PATH_MAX_LENGTH,
- "%s/%s",
- kConfigLocationList[i],
- file_name);
- if (F_OK == access(full_config_path, 0)) {
- strcpy(file_name, full_config_path);
- return true;
+ const char *mixer_ctl_name = "App Type Config";
+ ctl = mixer_get_ctl_by_name(mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",__func__, mixer_ctl_name);
+ return -1;
+ }
+
+ length = 1; // reserve index 0 for number of app types
+
+ struct listnode *node;
+ struct app_type_entry *entry;
+ list_for_each(node, &app_type_entry_list) {
+ entry = node_to_item(node, struct app_type_entry, node);
+ app_type_cfg[length++] = entry->app_type;
+ app_type_cfg[length++] = entry->max_rate;
+ app_type_cfg[length++] = entry->bit_width;
+ ALOGI("%s add entry %d %d", __func__, entry->app_type, entry->bit_width);
+ num_app_types += 1;
+ }
+
+ // default for capture
+ int t;
+ platform_get_default_app_type_v2(pdata,
+ PCM_CAPTURE,
+ &t);
+ app_type_cfg[length++] = t;
+ app_type_cfg[length++] = 48000;
+ app_type_cfg[length++] = 16;
+ num_app_types += 1;
+
+ if (num_app_types) {
+ app_type_cfg[0] = num_app_types;
+ if (mixer_ctl_set_array(ctl, app_type_cfg, length) < 0) {
+ ALOGE("Failed to set app type cfg");
}
}
- return false;
+ return 0;
}
void *platform_init(struct audio_device *adev)
@@ -1140,144 +1214,86 @@
my_data->adev = adev;
list_init(&operator_info_list);
+ list_init(&app_type_entry_list);
set_platform_defaults(my_data);
- bool card_verifed[MAX_SND_CARD] = {0};
- const int retry_limit = property_get_int32("audio.snd_card.open.retries", RETRY_NUMBER);
- for (;;) {
- if (snd_card_num >= MAX_SND_CARD) {
- if (retry_num++ >= retry_limit) {
- ALOGE("%s: Unable to find correct sound card, aborting.", __func__);
- goto init_failed;
- }
+ // audio_extn_utils_get_snd_card_num does
+ // - open mixer and get snd card name
+ // - parse platform info xml file and check for valid snd card name
+ // - on failure loop through all the active snd card
- snd_card_num = 0;
- usleep(RETRY_US);
- continue;
- }
-
- if (card_verifed[snd_card_num]) {
- ++snd_card_num;
- continue;
- }
-
- adev->mixer = mixer_open(snd_card_num);
-
- if (!adev->mixer) {
- ALOGE("%s: Unable to open the mixer card: %d", __func__,
- snd_card_num);
- ++snd_card_num;
- continue;
- }
-
- card_verifed[snd_card_num] = true;
-
- snd_card_name = mixer_get_name(adev->mixer);
- my_data->hw_info = hw_info_init(snd_card_name);
-
- audio_extn_set_snd_card_split(snd_card_name);
- snd_split_handle = audio_extn_get_snd_card_split();
-
- /* Get the codec internal name from the sound card and/or form factor
- * name and form the mixer paths and platfor info file name dynamically.
- * This is generic way of picking any codec and forma factor name based
- * mixer and platform info files in future with no code change.
-
- * current code extends and looks for any of the exteneded mixer path and
- * platform info file present based on codec and form factor.
-
- * order of picking appropriate file is
- * <i> mixer_paths_<codec_name>_<form_factor>.xml, if file not present
- * <ii> mixer_paths_<codec_name>.xml, if file not present
- * <iii> mixer_paths.xml
-
- * same order is followed for audio_platform_info.xml as well
- */
-
- // need to carryforward old file name
- if (!strncmp(snd_card_name, TOMTOM_8226_SND_CARD_NAME,
- min(strlen(TOMTOM_8226_SND_CARD_NAME), strlen(snd_card_name)))) {
- snprintf(mixer_xml_file, sizeof(mixer_xml_file), "%s_%s.xml",
- MIXER_XML_BASE_STRING, TOMTOM_MIXER_FILE_SUFFIX );
- } else {
-
- snprintf(mixer_xml_file, sizeof(mixer_xml_file), "%s_%s_%s.xml",
- MIXER_XML_BASE_STRING, snd_split_handle->snd_card,
- snd_split_handle->form_factor);
- if (!resolveConfigFile(mixer_xml_file)) {
- memset(mixer_xml_file, 0, sizeof(mixer_xml_file));
- snprintf(mixer_xml_file, sizeof(mixer_xml_file), "%s_%s.xml",
- MIXER_XML_BASE_STRING, snd_split_handle->snd_card);
-
- if (!resolveConfigFile(mixer_xml_file)) {
- memset(mixer_xml_file, 0, sizeof(mixer_xml_file));
- strlcpy(mixer_xml_file, MIXER_XML_DEFAULT_PATH, MIXER_PATH_MAX_LENGTH);
- resolveConfigFile(mixer_xml_file);
- }
- }
-
- snprintf(platform_info_file, sizeof(platform_info_file), "%s_%s_%s.xml",
- PLATFORM_INFO_XML_BASE_STRING, snd_split_handle->snd_card,
- snd_split_handle->form_factor);
-
- if (!resolveConfigFile(platform_info_file)) {
- memset(platform_info_file, 0, sizeof(platform_info_file));
- snprintf(platform_info_file, sizeof(platform_info_file), "%s_%s.xml",
- PLATFORM_INFO_XML_BASE_STRING, snd_split_handle->snd_card);
-
- if (!resolveConfigFile(platform_info_file)) {
- memset(platform_info_file, 0, sizeof(platform_info_file));
- strlcpy(platform_info_file, PLATFORM_INFO_XML_PATH, MIXER_PATH_MAX_LENGTH);
- resolveConfigFile(platform_info_file);
- }
- }
- }
-
- /* Initialize platform specific ids and/or backends*/
- platform_info_init(platform_info_file, my_data);
-
- /* validate the sound card name
- * my_data->snd_card_name can contain
- * <a> complete sound card name, i.e. <device>-<codec>-<form_factor>-snd-card
- * example: msm8994-tomtom-mtp-snd-card
- * <b> or sub string of the card name, i.e. <device>-<codec>
- * example: msm8994-tomtom
- * snd_card_name is truncated to 32 charaters as per mixer_get_name() implementation
- * so use min of my_data->snd_card_name and snd_card_name length for comparison
- */
-
- if (my_data->snd_card_name != NULL &&
- strncmp(snd_card_name, my_data->snd_card_name,
- min(strlen(snd_card_name), strlen(my_data->snd_card_name))) != 0) {
- ALOGI("%s: found valid sound card %s, but not primary sound card %s",
- __func__, snd_card_name, my_data->snd_card_name);
- ++snd_card_num;
- mixer_close(adev->mixer);
- adev->mixer = NULL;
- hw_info_deinit(my_data->hw_info);
- my_data->hw_info = NULL;
- continue;
- }
- ALOGI("%s: found sound card %s, primary sound card expeted is %s",
- __func__, snd_card_name, my_data->snd_card_name);
-
- ALOGD("%s: Loading mixer file: %s", __func__, mixer_xml_file);
- adev->audio_route = audio_route_init(snd_card_num, mixer_xml_file);
-
- if (!adev->audio_route) {
- ALOGE("%s: Failed to init audio route controls, aborting.", __func__);
- mixer_close(adev->mixer);
- adev->mixer = NULL;
- hw_info_deinit(my_data->hw_info);
- my_data->hw_info = NULL;
- goto init_failed;
- }
- adev->snd_card = snd_card_num;
- ALOGD("%s: Opened sound card:%d", __func__, snd_card_num);
- break;
+ snd_card_num = audio_extn_utils_get_snd_card_num();
+ if (-1 == snd_card_num) {
+ ALOGE("%s: invalid sound card number (-1), bailing out ", __func__);
+ goto init_failed;
}
+ adev->mixer = mixer_open(snd_card_num);
+ snd_card_name = mixer_get_name(adev->mixer);
+ my_data->hw_info = hw_info_init(snd_card_name);
+
+ audio_extn_set_snd_card_split(snd_card_name);
+ snd_split_handle = audio_extn_get_snd_card_split();
+
+ /* Get the codec internal name from the sound card and/or form factor
+ * name and form the mixer paths and platfor info file name dynamically.
+ * This is generic way of picking any codec and forma factor name based
+ * mixer and platform info files in future with no code change.
+
+ * current code extends and looks for any of the exteneded mixer path and
+ * platform info file present based on codec and form factor.
+
+ * order of picking appropriate file is
+ * <i> mixer_paths_<codec_name>_<form_factor>.xml, if file not present
+ * <ii> mixer_paths_<codec_name>.xml, if file not present
+ * <iii> mixer_paths.xml
+
+ * same order is followed for audio_platform_info.xml as well
+ */
+
+ // need to carryforward old file name
+ if (!strncmp(snd_card_name, TOMTOM_8226_SND_CARD_NAME,
+ min(strlen(TOMTOM_8226_SND_CARD_NAME), strlen(snd_card_name)))) {
+ snprintf(mixer_xml_file, sizeof(mixer_xml_file), "%s_%s.xml",
+ MIXER_XML_BASE_STRING, TOMTOM_MIXER_FILE_SUFFIX );
+ } else {
+
+ snprintf(mixer_xml_file, sizeof(mixer_xml_file), "%s_%s_%s.xml",
+ MIXER_XML_BASE_STRING, snd_split_handle->snd_card,
+ snd_split_handle->form_factor);
+ if (!audio_extn_utils_resolve_config_file(mixer_xml_file)) {
+ memset(mixer_xml_file, 0, sizeof(mixer_xml_file));
+ snprintf(mixer_xml_file, sizeof(mixer_xml_file), "%s_%s.xml",
+ MIXER_XML_BASE_STRING, snd_split_handle->snd_card);
+
+ if (!audio_extn_utils_resolve_config_file(mixer_xml_file)) {
+ memset(mixer_xml_file, 0, sizeof(mixer_xml_file));
+ strlcpy(mixer_xml_file, MIXER_XML_DEFAULT_PATH, MIXER_PATH_MAX_LENGTH);
+ audio_extn_utils_resolve_config_file(mixer_xml_file);
+ }
+ }
+ }
+
+ audio_extn_utils_get_platform_info(snd_card_name, platform_info_file);
+
+ /* Initialize platform specific ids and/or backends*/
+ platform_info_init(platform_info_file, my_data);
+
+ ALOGD("%s: Loading mixer file: %s", __func__, mixer_xml_file);
+ adev->audio_route = audio_route_init(snd_card_num, mixer_xml_file);
+
+ if (!adev->audio_route) {
+ ALOGE("%s: Failed to init audio route controls, aborting.", __func__);
+ mixer_close(adev->mixer);
+ adev->mixer = NULL;
+ hw_info_deinit(my_data->hw_info);
+ my_data->hw_info = NULL;
+ goto init_failed;
+ }
+ adev->snd_card = snd_card_num;
+ ALOGD("%s: Opened sound card:%d", __func__, snd_card_num);
+
//set max volume step for voice call
property_get("ro.config.vc_call_vol_steps", value, TOSTRING(MAX_VOL_INDEX));
my_data->max_vol_index = atoi(value);
@@ -1360,6 +1376,12 @@
ALOGE("%s: Could not find the symbol acdb_loader_deallocate_ACDB from %s",
__func__, LIB_ACDB_LOADER);
+ my_data->acdb_send_audio_cal_v3 = (acdb_send_audio_cal_v3_t)dlsym(my_data->acdb_handle,
+ "acdb_loader_send_audio_cal_v3");
+ if (!my_data->acdb_send_audio_cal_v3)
+ ALOGE("%s: Could not find the symbol acdb_send_audio_cal_v3 from %s",
+ __func__, LIB_ACDB_LOADER);
+
my_data->acdb_send_audio_cal = (acdb_send_audio_cal_t)dlsym(my_data->acdb_handle,
"acdb_loader_send_audio_cal");
if (!my_data->acdb_send_audio_cal)
@@ -1385,30 +1407,30 @@
__func__, LIB_ACDB_LOADER);
#if defined (PLATFORM_MSM8994) || (PLATFORM_MSM8996) || (PLATFORM_MSM8998)
- acdb_init_v2_cvd_t acdb_init;
- acdb_init = (acdb_init_v2_cvd_t)dlsym(my_data->acdb_handle,
+ acdb_init_v2_cvd_t acdb_init_local;
+ acdb_init_local = (acdb_init_v2_cvd_t)dlsym(my_data->acdb_handle,
"acdb_loader_init_v2");
- if (acdb_init == NULL)
+ if (acdb_init_local == NULL)
ALOGE("%s: dlsym error %s for acdb_loader_init_v2", __func__,
dlerror());
#elif defined (PLATFORM_MSM8084)
- acdb_init_v2_t acdb_init;
- acdb_init = (acdb_init_v2_t)dlsym(my_data->acdb_handle,
+ acdb_init_v2_t acdb_init_local;
+ acdb_init_local = (acdb_init_v2_t)dlsym(my_data->acdb_handle,
"acdb_loader_init_v2");
- if (acdb_init == NULL)
+ if (acdb_init_local == NULL)
ALOGE("%s: dlsym error %s for acdb_loader_init_v2", __func__,
dlerror());
#else
- acdb_init_t acdb_init;
- acdb_init = (acdb_init_t)dlsym(my_data->acdb_handle,
+ acdb_init_t acdb_init_local;
+ acdb_init_local = (acdb_init_t)dlsym(my_data->acdb_handle,
"acdb_loader_init_ACDB");
- if (acdb_init == NULL)
+ if (acdb_init_local == NULL)
ALOGE("%s: dlsym error %s for acdb_loader_init_ACDB", __func__,
dlerror());
#endif
- my_data->acdb_init = acdb_init;
+ my_data->acdb_init = acdb_init_local;
my_data->acdb_send_custom_top = (acdb_send_custom_top_t)
dlsym(my_data->acdb_handle,
@@ -1418,7 +1440,14 @@
ALOGE("%s: Could not find the symbol acdb_get_default_app_type from %s",
__func__, LIB_ACDB_LOADER);
- platform_acdb_init(my_data);
+ int result = acdb_init(adev->snd_card);
+ if (!result) {
+ my_data->acdb_initialized = true;
+ ALOGD("ACDB initialized");
+ } else {
+ my_data->acdb_initialized = false;
+ ALOGD("ACDB initialization failed");
+ }
}
/* init usb */
@@ -1433,6 +1462,11 @@
platform_backend_config_init(my_data);
+ init_be_dai_name_table(adev);
+
+ if (platform_supports_app_type_cfg())
+ platform_backend_app_type_cfg_init(my_data, adev->mixer);
+
return my_data;
init_failed:
@@ -1446,6 +1480,7 @@
int32_t dev;
struct operator_info *info_item;
struct operator_specific_device *device_item;
+ struct app_type_entry *ap;
struct listnode *node;
struct platform_data *my_data = (struct platform_data *)platform;
@@ -1483,6 +1518,13 @@
free(info_item);
}
+ while (!list_empty(&app_type_entry_list)) {
+ node = list_head(&app_type_entry_list);
+ list_remove(node);
+ ap = node_to_item(node, struct app_type_entry, node);
+ free(ap);
+ }
+
mixer_close(my_data->adev->mixer);
free(platform);
@@ -1668,13 +1710,6 @@
return ret;
}
-int platform_get_default_app_type_v2(void *platform __unused, usecase_type_t type __unused,
- int *app_type __unused)
-{
- ALOGE("%s: Not implemented", __func__);
- return -ENOSYS;
-}
-
int platform_get_snd_device_acdb_id(snd_device_t snd_device)
{
if ((snd_device < SND_DEVICE_MIN) || (snd_device >= SND_DEVICE_MAX)) {
@@ -1725,6 +1760,9 @@
struct platform_data *my_data = (struct platform_data *)platform;
int acdb_dev_id, acdb_dev_type;
+ if (platform_supports_app_type_cfg()) // use v2 instead
+ return -ENOSYS;
+
acdb_dev_id = acdb_device_table[audio_extn_get_spkr_prot_snd_device(snd_device)];
if (acdb_dev_id < 0) {
ALOGE("%s: Could not find acdb id for device(%d)",
@@ -1744,6 +1782,63 @@
return 0;
}
+int platform_send_audio_calibration_v2(void *platform, struct audio_usecase *usecase,
+ int app_type, int sample_rate)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ int acdb_dev_id, acdb_dev_type;
+ int snd_device = SND_DEVICE_OUT_SPEAKER;
+ int new_snd_device[SND_DEVICE_OUT_END] = {0};
+ int i, num_devices = 1;
+
+ if (!platform_supports_app_type_cfg()) // use v1 instead
+ return -ENOSYS;
+
+ if (usecase->type == PCM_PLAYBACK)
+ snd_device = usecase->out_snd_device;
+ else if (usecase->type == PCM_CAPTURE)
+ snd_device = usecase->in_snd_device;
+
+ // skipped over get_spkr_prot_device
+ acdb_dev_id = acdb_device_table[snd_device];
+ if (acdb_dev_id < 0) {
+ ALOGE("%s: Could not find acdb id for device(%d)",
+ __func__, snd_device);
+ return -EINVAL;
+ }
+
+ if (platform_can_split_snd_device(snd_device,
+ &num_devices, new_snd_device) < 0) {
+ new_snd_device[0] = snd_device;
+ }
+
+ for (i = 0; i < num_devices; i++) {
+ acdb_dev_id = acdb_device_table[new_snd_device[i]];
+ if (acdb_dev_id < 0) {
+ ALOGE("%s: Could not find acdb id for device(%d)",
+ __func__, new_snd_device[i]);
+ return -EINVAL;
+ }
+ ALOGV("%s: sending audio calibration for snd_device(%d) acdb_id(%d)",
+ __func__, new_snd_device[i], acdb_dev_id);
+ if (new_snd_device[i] >= SND_DEVICE_OUT_BEGIN &&
+ new_snd_device[i] < SND_DEVICE_OUT_END)
+ acdb_dev_type = ACDB_DEV_TYPE_OUT;
+ else
+ acdb_dev_type = ACDB_DEV_TYPE_IN;
+
+ if (my_data->acdb_send_audio_cal_v3) {
+ my_data->acdb_send_audio_cal_v3(acdb_dev_id, acdb_dev_type,
+ app_type, sample_rate, i);
+ } else if (my_data->acdb_send_audio_cal) {
+ my_data->acdb_send_audio_cal(acdb_dev_id, acdb_dev_type); // this version differs from internal
+ }
+ }
+
+ return 0;
+}
+
+
int platform_switch_voice_call_device_pre(void *platform)
{
struct platform_data *my_data = (struct platform_data *)platform;
@@ -2195,11 +2290,18 @@
// since Hearing will be on handset\speaker, use existing device
snd_device = SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET;
break;
+ case TTY_MODE_OFF:
+ break;
default:
ALOGE("%s: Invalid TTY mode (%#x)",
__func__, adev->voice.tty_mode);
}
}
+ if (snd_device == SND_DEVICE_NONE) {
+ snd_device = audio_extn_usb_is_capture_supported() ?
+ SND_DEVICE_OUT_VOICE_USB_HEADSET :
+ SND_DEVICE_OUT_VOICE_USB_HEADPHONES;
+ }
} else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) {
if (adev->bt_wb_speech_enabled) {
snd_device = SND_DEVICE_OUT_BT_SCO_WB;
@@ -2368,6 +2470,10 @@
}
} else if (out_device & AUDIO_DEVICE_OUT_TELEPHONY_TX) {
snd_device = SND_DEVICE_IN_VOICE_RX;
+ } else if (out_device & AUDIO_DEVICE_OUT_USB_DEVICE) {
+ if (audio_extn_usb_is_capture_supported()) {
+ snd_device = SND_DEVICE_IN_VOICE_USB_HEADSET_MIC;
+ }
}
} else if (source == AUDIO_SOURCE_CAMCORDER) {
if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC ||
@@ -2424,6 +2530,8 @@
}
} else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
snd_device = SND_DEVICE_IN_VOICE_REC_HEADSET_MIC;
+ } else if (in_device & AUDIO_DEVICE_IN_USB_DEVICE) {
+ snd_device = SND_DEVICE_IN_VOICE_RECOG_USB_HEADSET_MIC;
}
} else if (source == AUDIO_SOURCE_UNPROCESSED) {
if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
@@ -2442,6 +2550,8 @@
}
} else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
snd_device = SND_DEVICE_IN_UNPROCESSED_HEADSET_MIC;
+ } else if (in_device & AUDIO_DEVICE_IN_USB_DEVICE) {
+ snd_device = SND_DEVICE_IN_UNPROCESSED_USB_HEADSET_MIC;
}
} else if (source == AUDIO_SOURCE_VOICE_COMMUNICATION ||
mode == AUDIO_MODE_IN_COMMUNICATION) {
@@ -2467,6 +2577,8 @@
}
} else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
snd_device = SND_DEVICE_IN_HEADSET_MIC_AEC;
+ } else if (in_device & AUDIO_DEVICE_IN_USB_DEVICE) {
+ snd_device = SND_DEVICE_IN_USB_HEADSET_MIC_AEC;
}
platform_set_echo_reference(adev, true, out_device);
} else if (adev->active_input->enable_aec) {
@@ -2487,6 +2599,8 @@
}
} else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
snd_device = SND_DEVICE_IN_HEADSET_MIC_AEC;
+ } else if (in_device & AUDIO_DEVICE_IN_USB_DEVICE) {
+ snd_device = SND_DEVICE_IN_USB_HEADSET_MIC_AEC;
}
platform_set_echo_reference(adev, true, out_device);
} else if (adev->active_input->enable_ns) {
@@ -3361,12 +3475,12 @@
return backend_change;
}
-static void platform_pick_playback_cfg_for_uc(struct audio_device *adev,
- struct audio_usecase *usecase,
- snd_device_t snd_device,
- unsigned int *bit_width,
- unsigned int *sample_rate,
- unsigned int *channels)
+static void pick_playback_cfg_for_uc(struct audio_device *adev,
+ struct audio_usecase *usecase,
+ snd_device_t snd_device,
+ unsigned int *bit_width,
+ unsigned int *sample_rate,
+ unsigned int *channels)
{
int i =0;
struct listnode *node;
@@ -3397,6 +3511,27 @@
return;
}
+static void headset_is_config_supported(unsigned int *bit_width,
+ unsigned int *sample_rate,
+ unsigned int *channels) {
+ switch (*bit_width) {
+ case 16:
+ case 24:
+ break;
+ default:
+ *bit_width = 16;
+ break;
+ }
+
+ if (*sample_rate > 192000) {
+ *sample_rate = 192000;
+ }
+
+ if (*channels > 2) {
+ *channels = 2;
+ }
+}
+
static bool platform_check_playback_backend_cfg(struct audio_device* adev,
struct audio_usecase* usecase,
snd_device_t snd_device,
@@ -3406,10 +3541,8 @@
unsigned int bit_width;
unsigned int sample_rate;
unsigned int channels;
- bool passthrough_enabled = false;
int backend_idx = DEFAULT_CODEC_BACKEND;
struct platform_data *my_data = (struct platform_data *)adev->platform;
- bool channels_updated = false;
if (snd_device == SND_DEVICE_OUT_BT_SCO ||
snd_device == SND_DEVICE_OUT_BT_SCO_WB) {
@@ -3443,10 +3576,10 @@
*
* Exception: 16 bit playbacks is allowed through 16 bit/48/44.1 khz backend only
*/
- platform_pick_playback_cfg_for_uc(adev, usecase, snd_device,
- &bit_width,
- &sample_rate,
- &channels);
+ pick_playback_cfg_for_uc(adev, usecase, snd_device,
+ &bit_width,
+ &sample_rate,
+ &channels);
}
switch (backend_idx) {
@@ -3456,8 +3589,10 @@
ALOGV("%s: USB BE configured as bit_width(%d)sample_rate(%d)channels(%d)",
__func__, bit_width, sample_rate, channels);
break;
- case DEFAULT_CODEC_BACKEND:
case HEADPHONE_BACKEND:
+ headset_is_config_supported(&bit_width, &sample_rate, &channels);
+ break;
+ case DEFAULT_CODEC_BACKEND:
default:
bit_width = platform_get_snd_device_bit_width(snd_device);
sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
@@ -3465,23 +3600,19 @@
break;
}
- if (channels != my_data->current_backend_cfg[backend_idx].channels) {
- channels_updated = true;
- }
-
ALOGV("%s:becf: afe: Codec selected backend: %d updated bit width: %d and"
"sample rate: %d",
__func__, backend_idx , bit_width, sample_rate);
// Force routing if the expected bitwdith or samplerate
// is not same as current backend comfiguration
- if ((bit_width != my_data->current_backend_cfg[backend_idx].bit_width) ||
- (sample_rate != my_data->current_backend_cfg[backend_idx].sample_rate) ||
- passthrough_enabled || channels_updated) {
+ if (bit_width != my_data->current_backend_cfg[backend_idx].bit_width ||
+ sample_rate != my_data->current_backend_cfg[backend_idx].sample_rate ||
+ channels != my_data->current_backend_cfg[backend_idx].channels) {
backend_cfg->bit_width = bit_width;
backend_cfg->sample_rate = sample_rate;
backend_cfg->channels = channels;
- backend_cfg->passthrough_enabled = passthrough_enabled;
+ backend_cfg->passthrough_enabled = false;
backend_change = true;
ALOGV("%s:becf: afe: Codec backend needs to be updated. new bit width: %d"
"new sample rate: %d new channels: %d",
@@ -3566,3 +3697,237 @@
return false;
}
+static int max_be_dai_names = 0;
+static const struct be_dai_name_struct *be_dai_name_table;
+
+/*
+ * Retrieves the be_dai_name_table from kernel to enable a mapping
+ * between sound device hw interfaces and backend IDs. This allows HAL to
+ * specify the backend a specific calibration is needed for.
+ */
+static int init_be_dai_name_table(struct audio_device *adev)
+{
+ const char *mixer_ctl_name = "Backend DAI Name Table";
+ struct mixer_ctl *ctl;
+ int i, j, ret, size;
+ bool valid_hw_interface;
+
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer name %s\n",
+ __func__, mixer_ctl_name);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ mixer_ctl_update(ctl);
+
+ size = mixer_ctl_get_num_values(ctl);
+ if (size <= 0){
+ ALOGE("%s: Failed to get %s size %d\n",
+ __func__, mixer_ctl_name, size);
+ ret = -EFAULT;
+ goto done;
+ }
+
+ posix_memalign((void **)&be_dai_name_table, 32, size);
+ if (be_dai_name_table == NULL) {
+ ALOGE("%s: Failed to allocate memory for %s\n",
+ __func__, mixer_ctl_name);
+ ret = -ENOMEM;
+ goto freeMem;
+ }
+
+ ret = mixer_ctl_get_array(ctl, (void *)be_dai_name_table, size);
+ if (ret) {
+ ALOGE("%s: Failed to get %s, ret %d\n",
+ __func__, mixer_ctl_name, ret);
+ ret = -EFAULT;
+ goto freeMem;
+ }
+
+ if (be_dai_name_table != NULL) {
+ max_be_dai_names = size / sizeof(struct be_dai_name_struct);
+ ALOGV("%s: Successfully got %s, number of be dais is %d\n",
+ __func__, mixer_ctl_name, max_be_dai_names);
+ ret = 0;
+ } else {
+ ALOGE("%s: Failed to get %s\n", __func__, mixer_ctl_name);
+ ret = -EFAULT;
+ goto freeMem;
+ }
+
+ /*
+ * Validate all sound devices have a valid backend set to catch
+ * errors for uncommon sound devices
+ */
+ for (i = 0; i < SND_DEVICE_MAX; i++) {
+ valid_hw_interface = false;
+
+ if (hw_interface_table[i] == NULL) {
+ ALOGW("%s: sound device %s has no hw interface set\n",
+ __func__, platform_get_snd_device_name(i));
+ continue;
+ }
+
+ for (j = 0; j < max_be_dai_names; j++) {
+ if (strcmp(hw_interface_table[i], be_dai_name_table[j].be_name)
+ == 0) {
+ valid_hw_interface = true;
+ break;
+ }
+ }
+ if (!valid_hw_interface)
+ ALOGD("%s: sound device %s does not have a valid hw interface set "
+ "(disregard for combo devices) %s\n",
+ __func__, platform_get_snd_device_name(i),
+ hw_interface_table[i]);
+ }
+
+ goto done;
+
+freeMem:
+ if (be_dai_name_table) {
+ free((void *)be_dai_name_table);
+ be_dai_name_table = NULL;
+ }
+
+done:
+ return ret;
+}
+
+int platform_get_snd_device_backend_index(snd_device_t device)
+{
+ int i, be_dai_id;
+ const char * hw_interface_name = NULL;
+
+ ALOGV("%s: enter with device %d\n", __func__, device);
+
+ if ((device <= SND_DEVICE_MIN) || (device >= SND_DEVICE_MAX)) {
+ ALOGE("%s: Invalid snd_device = %d",
+ __func__, device);
+ be_dai_id = -EINVAL;
+ goto done;
+ }
+
+ /* Get string value of necessary backend for device */
+ hw_interface_name = hw_interface_table[device];
+ if (hw_interface_name == NULL) {
+ ALOGE("%s: no hw_interface set for device %d\n", __func__, device);
+ be_dai_id = -EINVAL;
+ goto done;
+ }
+
+ /* Check if be dai name table was retrieved successfully */
+ if (be_dai_name_table == NULL) {
+ ALOGE("%s: BE DAI Name Table is not present\n", __func__);
+ be_dai_id = -EFAULT;
+ goto done;
+ }
+
+ /* Get backend ID for device specified */
+ for (i = 0; i < max_be_dai_names; i++) {
+ if (strcmp(hw_interface_name, be_dai_name_table[i].be_name) == 0) {
+ be_dai_id = be_dai_name_table[i].be_id;
+ goto done;
+ }
+ }
+ ALOGE("%s: no interface matching name %s\n", __func__, hw_interface_name);
+ be_dai_id = -EINVAL;
+ goto done;
+
+done:
+ return be_dai_id;
+}
+
+void platform_check_and_update_copp_sample_rate(void* platform, snd_device_t snd_device,
+ unsigned int stream_sr, int* sample_rate)
+{
+ struct platform_data* my_data = (struct platform_data *)platform;
+ int backend_idx = platform_get_backend_index(snd_device);
+ int device_sr = my_data->current_backend_cfg[backend_idx].sample_rate;
+ /*
+ *Check if device SR is multiple of 8K or 11.025 Khz
+ *check if the stream SR is multiple of same base, if yes
+ *then have copp SR equal to stream SR, this ensures that
+ *post processing happens at stream SR, else have
+ *copp SR equal to device SR.
+ */
+ if (!(((sample_rate_multiple(device_sr, SAMPLE_RATE_8000)) &&
+ (sample_rate_multiple(stream_sr, SAMPLE_RATE_8000))) ||
+ ((sample_rate_multiple(device_sr, SAMPLE_RATE_11025)) &&
+ (sample_rate_multiple(stream_sr, SAMPLE_RATE_11025))))) {
+ *sample_rate = device_sr;
+ } else
+ *sample_rate = stream_sr;
+
+ ALOGI("sn_device %d device sr %d stream sr %d copp sr %d", snd_device, device_sr, stream_sr
+ , *sample_rate);
+
+}
+
+// called from info parser
+void platform_add_app_type(int bw, const char *uc_type,
+ int app_type, int max_rate) {
+ struct app_type_entry *ap =
+ (struct app_type_entry *)calloc(1, sizeof(struct app_type_entry));
+
+ if (!ap) {
+ ALOGE("%s failed to allocate mem for app type", __func__);
+ return;
+ }
+
+ ap->uc_type = -1;
+ for (int i=0; i<USECASE_TYPE_MAX; i++) {
+ if (!strcmp(uc_type, usecase_type_index[i].name)) {
+ ap->uc_type = usecase_type_index[i].index;
+ break;
+ }
+ }
+
+ if (ap->uc_type == -1) {
+ free(ap);
+ return;
+ }
+
+ ALOGI("%s bw %d uc %s app_type %d max_rate %d",
+ __func__, bw, uc_type, app_type, max_rate);
+ ap->bit_width = bw;
+ ap->app_type = app_type;
+ ap->max_rate = max_rate;
+ list_add_tail(&app_type_entry_list, &ap->node);
+}
+
+
+int platform_get_default_app_type_v2(void *platform __unused,
+ usecase_type_t type,
+ int *app_type )
+{
+ if (type == PCM_PLAYBACK)
+ *app_type = DEFAULT_APP_TYPE_RX_PATH;
+ else
+ *app_type = DEFAULT_APP_TYPE_TX_PATH;
+ return 0;
+}
+
+int platform_get_app_type_v2(void *platform, usecase_type_t uc_type,
+ int bw, int sr __unused,
+ int *app_type)
+{
+ struct listnode *node;
+ struct app_type_entry *entry;
+ *app_type = -1;
+ list_for_each(node, &app_type_entry_list) {
+ entry = node_to_item(node, struct app_type_entry, node);
+ if (entry->bit_width == bw &&
+ entry->uc_type == uc_type) {
+ *app_type = entry->app_type;
+ break;
+ }
+ }
+
+ if (*app_type == -1) {
+ return platform_get_default_app_type_v2(platform, uc_type, app_type);
+ }
+ return 0;
+}
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index b411e9d..61da332 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -94,6 +94,8 @@
SND_DEVICE_OUT_USB_HEADSET,
SND_DEVICE_OUT_USB_HEADPHONES,
SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET,
+ SND_DEVICE_OUT_VOICE_USB_HEADPHONES,
+ SND_DEVICE_OUT_VOICE_USB_HEADSET,
SND_DEVICE_OUT_END,
/*
@@ -161,6 +163,10 @@
SND_DEVICE_IN_VOICE_RX,
SND_DEVICE_IN_USB_HEADSET_MIC,
+ SND_DEVICE_IN_USB_HEADSET_MIC_AEC,
+ SND_DEVICE_IN_VOICE_USB_HEADSET_MIC,
+ SND_DEVICE_IN_UNPROCESSED_USB_HEADSET_MIC,
+ SND_DEVICE_IN_VOICE_RECOG_USB_HEADSET_MIC,
SND_DEVICE_IN_THREE_MIC,
SND_DEVICE_IN_QUAD_MIC,
SND_DEVICE_IN_CAPTURE_VI_FEEDBACK,
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 59ad4b1..c51c492 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -50,6 +50,8 @@
int platform_set_snd_device_acdb_id(snd_device_t snd_device, unsigned int acdb_id);
int platform_get_snd_device_acdb_id(snd_device_t snd_device);
int platform_send_audio_calibration(void *platform, snd_device_t snd_device);
+int platform_send_audio_calibration_v2(void *platform, struct audio_usecase *usecase,
+ int app_type, int sample_rate);
int platform_get_default_app_type_v2(void *platform, enum usecase_type_t type, int *app_type);
int platform_switch_voice_call_device_pre(void *platform);
int platform_switch_voice_call_enable_device_config(void *platform,
@@ -105,6 +107,9 @@
/* From platform_info.c */
int platform_info_init(const char *filename, void *);
+typedef int (*set_parameters_fn)(void *platform, struct str_parms *parms);
+int snd_card_info_init(const char *filename, void *, set_parameters_fn);
+
int platform_get_usecase_index(const char * usecase);
int platform_set_usecase_pcm_id(audio_usecase_t usecase, int32_t type, int32_t pcm_id);
void platform_set_echo_reference(struct audio_device *adev, bool enable, audio_devices_t out_device);
@@ -125,4 +130,11 @@
struct audio_usecase *usecase, snd_device_t snd_device);
int platform_snd_card_update(void *platform, enum card_status_t status);
+void platform_check_and_update_copp_sample_rate(void *platform, snd_device_t snd_device,
+ unsigned int stream_sr,int *sample_rate);
+int platform_get_snd_device_backend_index(snd_device_t snd_device);
+bool platform_supports_app_type_cfg();
+int platform_get_app_type_v2(void *platform, enum usecase_type_t type,
+ int bw, int sr, int *app_type);
+void platform_add_app_type(int bw, const char *uc_type, int app_type, int max_sr);
#endif // AUDIO_PLATFORM_API_H
diff --git a/hal/platform_info.c b/hal/platform_info.c
index f6b57e3..c63f244 100644
--- a/hal/platform_info.c
+++ b/hal/platform_info.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2014-2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -34,6 +34,7 @@
CONFIG_PARAMS,
OPERATOR_SPECIFIC,
GAIN_LEVEL_MAPPING,
+ APP_TYPE,
} section_t;
typedef void (* section_process_fn)(const XML_Char **attr);
@@ -45,6 +46,7 @@
static void process_root(const XML_Char **attr);
static void process_operator_specific(const XML_Char **attr);
static void process_gain_db_to_level_map(const XML_Char **attr);
+static void process_app_type(const XML_Char **attr);
static section_process_fn section_table[] = {
[ROOT] = process_root,
@@ -54,16 +56,20 @@
[CONFIG_PARAMS] = process_config_params,
[OPERATOR_SPECIFIC] = process_operator_specific,
[GAIN_LEVEL_MAPPING] = process_gain_db_to_level_map,
+ [APP_TYPE] = process_app_type,
};
+static set_parameters_fn set_parameters = &platform_set_parameters;
+
static section_t section;
struct platform_info {
+ bool do_full_parse;
void *platform;
struct str_parms *kvpairs;
};
-static struct platform_info my_data;
+static struct platform_info my_data = {true, NULL, NULL};
/*
* <audio_platform_info>
@@ -302,7 +308,34 @@
}
str_parms_add_str(my_data.kvpairs, (char*)attr[1], (char*)attr[3]);
- platform_set_parameters(my_data.platform, my_data.kvpairs);
+ set_parameters(my_data.platform, my_data.kvpairs);
+done:
+ return;
+}
+
+static void process_app_type(const XML_Char **attr)
+{
+ if (strcmp(attr[0], "uc_type")) {
+ ALOGE("%s: uc_type not found", __func__);
+ goto done;
+ }
+
+ if (strcmp(attr[2], "bit_width")) {
+ ALOGE("%s: bit_width not found", __func__);
+ goto done;
+ }
+
+ if (strcmp(attr[4], "id")) {
+ ALOGE("%s: id not found", __func__);
+ goto done;
+ }
+
+ if (strcmp(attr[6], "max_rate")) {
+ ALOGE("%s: max rate not found", __func__);
+ goto done;
+ }
+
+ platform_add_app_type(atoi(attr[3]), attr[1], atoi(attr[5]), atoi(attr[7]));
done:
return;
}
@@ -314,51 +347,76 @@
const XML_Char *attr_value = NULL;
unsigned int i;
- if (strcmp(tag_name, "acdb_ids") == 0) {
- section = ACDB;
- } else if (strcmp(tag_name, "pcm_ids") == 0) {
- section = PCM_ID;
- } else if (strcmp(tag_name, "backend_names") == 0) {
- section = BACKEND_NAME;
- } else if (strcmp(tag_name, "config_params") == 0) {
- section = CONFIG_PARAMS;
- } else if (strcmp(tag_name, "operator_specific") == 0) {
- section = OPERATOR_SPECIFIC;
- } else if (strcmp(tag_name, "gain_db_to_level_mapping") == 0) {
- section = GAIN_LEVEL_MAPPING;
- } else if (strcmp(tag_name, "device") == 0) {
- if ((section != ACDB) && (section != BACKEND_NAME) && (section != OPERATOR_SPECIFIC)) {
- ALOGE("device tag only supported for acdb/backend names");
- return;
- }
- /* call into process function for the current section */
- section_process_fn fn = section_table[section];
- fn(attr);
- } else if (strcmp(tag_name, "usecase") == 0) {
- if (section != PCM_ID) {
- ALOGE("usecase tag only supported with PCM_ID section");
- return;
- }
+ if (my_data.do_full_parse) {
+ if (strcmp(tag_name, "acdb_ids") == 0) {
+ section = ACDB;
+ } else if (strcmp(tag_name, "pcm_ids") == 0) {
+ section = PCM_ID;
+ } else if (strcmp(tag_name, "backend_names") == 0) {
+ section = BACKEND_NAME;
+ } else if (strcmp(tag_name, "config_params") == 0) {
+ section = CONFIG_PARAMS;
+ } else if (strcmp(tag_name, "operator_specific") == 0) {
+ section = OPERATOR_SPECIFIC;
+ } else if (strcmp(tag_name, "gain_db_to_level_mapping") == 0) {
+ section = GAIN_LEVEL_MAPPING;
+ } else if (strcmp(tag_name, "app_types") == 0) {
+ section = APP_TYPE;
+ } else if (strcmp(tag_name, "device") == 0) {
+ if ((section != ACDB) && (section != BACKEND_NAME) && (section != OPERATOR_SPECIFIC)) {
+ ALOGE("device tag only supported for acdb/backend names");
+ return;
+ }
- section_process_fn fn = section_table[PCM_ID];
- fn(attr);
- } else if (strcmp(tag_name, "param") == 0) {
- if (section != CONFIG_PARAMS) {
- ALOGE("param tag only supported with CONFIG_PARAMS section");
- return;
- }
+ /* call into process function for the current section */
+ section_process_fn fn = section_table[section];
+ fn(attr);
+ } else if (strcmp(tag_name, "usecase") == 0) {
+ if (section != PCM_ID) {
+ ALOGE("usecase tag only supported with PCM_ID section");
+ return;
+ }
- section_process_fn fn = section_table[section];
- fn(attr);
- } else if (strcmp(tag_name, "gain_level_map") == 0) {
- if (section != GAIN_LEVEL_MAPPING) {
- ALOGE("usecase tag only supported with GAIN_LEVEL_MAPPING section");
- return;
- }
+ section_process_fn fn = section_table[PCM_ID];
+ fn(attr);
+ } else if (strcmp(tag_name, "param") == 0) {
+ if (section != CONFIG_PARAMS) {
+ ALOGE("param tag only supported with CONFIG_PARAMS section");
+ return;
+ }
- section_process_fn fn = section_table[GAIN_LEVEL_MAPPING];
- fn(attr);
+ section_process_fn fn = section_table[section];
+ fn(attr);
+ } else if (strcmp(tag_name, "gain_level_map") == 0) {
+ if (section != GAIN_LEVEL_MAPPING) {
+ ALOGE("usecase tag only supported with GAIN_LEVEL_MAPPING section");
+ return;
+ }
+
+ section_process_fn fn = section_table[GAIN_LEVEL_MAPPING];
+ fn(attr);
+ } else if (!strcmp(tag_name, "app")) {
+ if (section != APP_TYPE) {
+ ALOGE("app tag only valid in section APP_TYPE");
+ return;
+ }
+
+ section_process_fn fn = section_table[APP_TYPE];
+ fn(attr);
+ }
+ } else {
+ if(strcmp(tag_name, "config_params") == 0) {
+ section = CONFIG_PARAMS;
+ } else if (strcmp(tag_name, "param") == 0) {
+ if (section != CONFIG_PARAMS) {
+ ALOGE("param tag only supported with CONFIG_PARAMS section");
+ return;
+ }
+
+ section_process_fn fn = section_table[section];
+ fn(attr);
+ }
}
return;
@@ -378,9 +436,18 @@
section = ROOT;
} else if (strcmp(tag_name, "gain_db_to_level_mapping") == 0) {
section = ROOT;
+ } else if (strcmp(tag_name, "app_types") == 0) {
+ section = ROOT;
}
}
+int snd_card_info_init(const char *filename, void *platform, set_parameters_fn fn)
+{
+ set_parameters = fn;
+ my_data.do_full_parse = false;
+ return platform_info_init(filename, platform);
+}
+
int platform_info_init(const char *filename, void *platform)
{
XML_Parser parser;
@@ -448,6 +515,9 @@
break;
}
+ set_parameters = &platform_set_parameters;
+ my_data.do_full_parse = true;
+
err_free_parser:
XML_ParserFree(parser);
err_close_file:
diff --git a/post_proc/Android.mk b/post_proc/Android.mk
index eb59ddb..493f2cc 100644
--- a/post_proc/Android.mk
+++ b/post_proc/Android.mk
@@ -1,4 +1,4 @@
-ifneq ($(filter msm8974 msm8226 msm8084 msm8992 msm8994 msm8996 msm8909,$(TARGET_BOARD_PLATFORM)),)
+ifneq ($(filter msm8974 msm8226 msm8084 msm8992 msm8994 msm8996 msm8909 msm8998,$(TARGET_BOARD_PLATFORM)),)
LOCAL_PATH:= $(call my-dir)
@@ -35,7 +35,7 @@
################################################################################
-ifneq ($(filter msm8992 msm8994 msm8996 msm8909,$(TARGET_BOARD_PLATFORM)),)
+ifneq ($(filter msm8992 msm8994 msm8996 msm8909 msm8998,$(TARGET_BOARD_PLATFORM)),)
include $(CLEAR_VARS)