Merge "configs: add quad mic profile for Lahaina target"
diff --git a/configs/lito/lito.mk b/configs/lito/lito.mk
index 3bc4e47..07615fb 100644
--- a/configs/lito/lito.mk
+++ b/configs/lito/lito.mk
@@ -215,7 +215,7 @@
$(TOPDIR)vendor/qcom/opensource/audio-hal/primary-hal/configs/lito/audio_policy_configuration_odm.xml:$(TARGET_COPY_OUT_VENDOR)/etc/audio_policy_configuration.xml
else
PRODUCT_COPY_FILES += \
- $(TOPDIR)frameworks/av/services/audiopolicy/config/audio_policy_configuration.xml:$(TARGET_COPY_OUT_VENDOR)/etc/audio_policy_configuration.xml
+ $(TOPDIR)vendor/qcom/opensource/audio-hal/primary-hal/configs/common/audio_policy_configuration.xml:$(TARGET_COPY_OUT_VENDOR)/etc/audio_policy_configuration.xml
endif
PRODUCT_COPY_FILES += \
diff --git a/configs/msmnile/msmnile.mk b/configs/msmnile/msmnile.mk
index 5a6796b..fa9c210 100644
--- a/configs/msmnile/msmnile.mk
+++ b/configs/msmnile/msmnile.mk
@@ -193,7 +193,7 @@
$(TOPDIR)vendor/qcom/opensource/audio-hal/primary-hal/configs/msmnile/audio_policy_configuration_odm.xml:$(TARGET_COPY_OUT_VENDOR)/etc/audio_policy_configuration.xml
else
PRODUCT_COPY_FILES += \
- $(TOPDIR)frameworks/av/services/audiopolicy/config/audio_policy_configuration.xml:$(TARGET_COPY_OUT_VENDOR)/etc/audio_policy_configuration.xml
+ $(TOPDIR)vendor/qcom/opensource/audio-hal/primary-hal/configs/common/audio_policy_configuration.xml:$(TARGET_COPY_OUT_VENDOR)/etc/audio_policy_configuration.xml
endif
PRODUCT_COPY_FILES += \
diff --git a/configs/msmsteppe/msmsteppe.mk b/configs/msmsteppe/msmsteppe.mk
index 512f378..5b53343 100644
--- a/configs/msmsteppe/msmsteppe.mk
+++ b/configs/msmsteppe/msmsteppe.mk
@@ -193,7 +193,7 @@
$(TOPDIR)vendor/qcom/opensource/audio-hal/primary-hal/configs/msmsteppe/audio_policy_configuration_odm.xml:$(TARGET_COPY_OUT_VENDOR)/etc/audio_policy_configuration.xml
else
PRODUCT_COPY_FILES += \
- $(TOPDIR)frameworks/av/services/audiopolicy/config/audio_policy_configuration.xml:$(TARGET_COPY_OUT_VENDOR)/etc/audio_policy_configuration.xml
+ $(TOPDIR)vendor/qcom/opensource/audio-hal/primary-hal/configs/common/audio_policy_configuration.xml:$(TARGET_COPY_OUT_VENDOR)/etc/audio_policy_configuration.xml
endif
PRODUCT_COPY_FILES += \
diff --git a/hal/audio_extn/a2dp.c b/hal/audio_extn/a2dp.c
index 00e581f..8422846 100644
--- a/hal/audio_extn/a2dp.c
+++ b/hal/audio_extn/a2dp.c
@@ -2875,8 +2875,10 @@
goto param_handled;
list_for_each(node, &a2dp.adev->usecase_list) {
uc_info = node_to_item(node, struct audio_usecase, list);
- if (uc_info->stream.out && uc_info->type == PCM_PLAYBACK &&
- is_a2dp_out_device_type(&uc_info->stream.out->device_list)) {
+ if (uc_info->type == PCM_PLAYBACK &&
+ (uc_info->out_snd_device == SND_DEVICE_OUT_BT_A2DP ||
+ uc_info->out_snd_device == SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP ||
+ uc_info->out_snd_device == SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP)) {
pthread_mutex_unlock(&a2dp.adev->lock);
fp_check_a2dp_restore(a2dp.adev, uc_info->stream.out, false);
pthread_mutex_lock(&a2dp.adev->lock);
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index 786b7181..24dd068 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -5485,6 +5485,11 @@
struct str_parms *);
static maxxaudio_set_parameters_t maxxaudio_set_parameters;
+typedef void (*maxxaudio_get_parameters_t)(struct audio_device *,
+ struct str_parms *,
+ struct str_parms *);
+static maxxaudio_get_parameters_t maxxaudio_get_parameters;
+
typedef bool (*maxxaudio_supported_usb_t)();
static maxxaudio_supported_usb_t maxxaudio_supported_usb;
@@ -5512,6 +5517,8 @@
(maxxaudio_set_device_t)dlsym(maxxaudio_lib_handle, "ma_set_device")) ||
!(maxxaudio_set_parameters =
(maxxaudio_set_parameters_t)dlsym(maxxaudio_lib_handle, "ma_set_parameters")) ||
+ !(maxxaudio_get_parameters =
+ (maxxaudio_get_parameters_t)dlsym(maxxaudio_lib_handle, "ma_get_parameters")) ||
!(maxxaudio_supported_usb =
(maxxaudio_supported_usb_t)dlsym(
maxxaudio_lib_handle, "ma_supported_usb"))) {
@@ -5533,6 +5540,7 @@
maxxaudio_set_state = NULL;
maxxaudio_set_device = NULL;
maxxaudio_set_parameters = NULL;
+ maxxaudio_get_parameters = NULL;
maxxaudio_supported_usb = NULL;
ALOGW(":: %s: ---- Feature MAXX_AUDIO is disabled ----", __func__);
return -ENOSYS;
@@ -5580,6 +5588,14 @@
maxxaudio_set_parameters(adev, parms);
}
+void audio_extn_ma_get_parameters(struct audio_device *adev,
+ struct str_parms *query,
+ struct str_parms *reply)
+{
+ if (maxxaudio_get_parameters)
+ maxxaudio_get_parameters(adev, query, reply);
+}
+
bool audio_extn_ma_supported_usb()
{
return (maxxaudio_supported_usb ? maxxaudio_supported_usb(): false);
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index c71fbc3..c01954d 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -361,6 +361,9 @@
void audio_extn_ma_set_device(struct audio_usecase *usecase);
void audio_extn_ma_set_parameters(struct audio_device *adev,
struct str_parms *parms);
+void audio_extn_ma_get_parameters(struct audio_device *adev,
+ struct str_parms *query,
+ struct str_parms *reply);
bool audio_extn_ma_supported_usb();
bool audio_extn_is_maxx_audio_enabled();
// --- Function pointers from audio_extn needed by MAXX_AUDIO
diff --git a/hal/audio_extn/maxxaudio.c b/hal/audio_extn/maxxaudio.c
index 88de2f2..f1393f6 100644
--- a/hal/audio_extn/maxxaudio.c
+++ b/hal/audio_extn/maxxaudio.c
@@ -50,10 +50,14 @@
#define MA_QDSP_SET_VOL "maxxaudio_qdsp_set_volume"
#define MA_QDSP_SET_VOLT "maxxaudio_qdsp_set_volume_table"
#define MA_QDSP_SET_PARAM "maxxaudio_qdsp_set_parameter"
+#define MA_QDSP_SET_COMMAND "maxxaudio_qdsp_set_command"
+#define MA_QDSP_GET_COMMAND "maxxaudio_qdsp_get_command"
#define SUPPORT_DEV "18d1:5033" // Blackbird usbid
#define SUPPORTED_USB 0x01
+#define WAVES_COMMAND_SIZE 10240
+
typedef unsigned int effective_scope_flag_t;
const effective_scope_flag_t EFFECTIVE_SCOPE_RTC = 1 << 0; /* RTC */
const effective_scope_flag_t EFFECTIVE_SCOPE_ACDB = 1 << 1; /* ACDB */
@@ -145,6 +149,16 @@
const struct ma_audio_cal_settings *,
unsigned int, double);
+typedef bool (*ma_set_cmd_t)(ma_audio_cal_handle_t handle,
+ const struct ma_audio_cal_settings *,
+ const char*);
+
+typedef bool (*ma_get_cmd_t)(ma_audio_cal_handle_t handle,
+ const struct ma_audio_cal_settings *,
+ const char *,
+ char *,
+ uint32_t);
+
struct ma_platform_data {
void *waves_handle;
void *platform;
@@ -158,6 +172,8 @@
ma_set_volume_t ma_set_volume;
ma_set_volume_table_t ma_set_volume_table;
ma_set_param_t ma_set_param;
+ ma_set_cmd_t ma_set_cmd;
+ ma_get_cmd_t ma_get_cmd;
bool speaker_lr_swap;
bool orientation_used;
int dispaly_orientation;
@@ -167,6 +183,9 @@
static uint16_t g_supported_dev = 0;
static struct ma_state ma_cur_state_table[STREAM_MAX_TYPES];
static struct ma_platform_data *my_data = NULL;
+static char ma_command_data[WAVES_COMMAND_SIZE];
+static char ma_reply_data[WAVES_COMMAND_SIZE];
+
// --- external function dependency ---
fp_platform_set_parameters_t fp_platform_set_parameters;
fp_audio_extn_get_snd_card_split_t fp_audio_extn_get_snd_card_split;
@@ -276,7 +295,6 @@
static bool check_and_send_all_audio_cal(struct audio_device *adev, ma_cmd_t cmd)
{
- int i = 0;
bool ret = false;
struct listnode *node;
struct audio_usecase *usecase;
@@ -476,71 +494,78 @@
my_data->waves_handle = dlopen(lib_path, RTLD_NOW);
if (my_data->waves_handle == NULL) {
- ALOGE("%s: DLOPEN failed for %s, %s", __func__, LIB_MA_PARAM, dlerror());
- goto error;
+ ALOGE("%s: DLOPEN failed for %s, %s", __func__, LIB_MA_PARAM, dlerror());
+ goto error;
} else {
- ALOGV("%s: DLOPEN successful for %s", __func__, LIB_MA_PARAM);
+ ALOGV("%s: DLOPEN successful for %s", __func__, LIB_MA_PARAM);
- my_data->ma_param_init = (ma_param_init_t)dlsym(my_data->waves_handle,
- MA_QDSP_PARAM_INIT);
- if (!my_data->ma_param_init) {
- ALOGE("%s: dlsym error %s for ma_param_init", __func__, dlerror());
- goto error;
- }
+ my_data->ma_param_init = (ma_param_init_t)dlsym(my_data->waves_handle, MA_QDSP_PARAM_INIT);
+ if (!my_data->ma_param_init) {
+ ALOGE("%s: dlsym error %s for ma_param_init", __func__, dlerror());
+ goto error;
+ }
- my_data->ma_param_deinit = (ma_param_deinit_t)dlsym(
- my_data->waves_handle, MA_QDSP_PARAM_DEINIT);
- if (!my_data->ma_param_deinit) {
- ALOGE("%s: dlsym error %s for ma_param_deinit", __func__, dlerror());
- goto error;
- }
+ my_data->ma_param_deinit = (ma_param_deinit_t)dlsym(my_data->waves_handle,
+ MA_QDSP_PARAM_DEINIT);
+ if (!my_data->ma_param_deinit) {
+ ALOGE("%s: dlsym error %s for ma_param_deinit", __func__, dlerror());
+ goto error;
+ }
my_data->ma_is_feature_used = (ma_is_feature_used_t)dlsym(my_data->waves_handle,
- MA_QDSP_IS_FEATURE_USED);
+ MA_QDSP_IS_FEATURE_USED);
if (!my_data->ma_is_feature_used) {
ALOGV("%s: dlsym error %s for ma_is_feature_used", __func__, dlerror());
}
my_data->ma_set_orientation = (ma_set_orientation_t)dlsym(my_data->waves_handle,
- MA_QDSP_SET_ORIENTATION);
+ MA_QDSP_SET_ORIENTATION);
if (!my_data->ma_set_orientation) {
ALOGV("%s: dlsym error %s for ma_set_orientation", __func__, dlerror());
}
- my_data->ma_set_lr_swap = (ma_set_lr_swap_t)dlsym(my_data->waves_handle,
- MA_QDSP_SET_LR_SWAP);
- if (!my_data->ma_set_lr_swap) {
- ALOGE("%s: dlsym error %s for ma_set_lr_swap", __func__, dlerror());
- goto error;
- }
+ my_data->ma_set_lr_swap = (ma_set_lr_swap_t)dlsym(my_data->waves_handle,
+ MA_QDSP_SET_LR_SWAP);
+ if (!my_data->ma_set_lr_swap) {
+ ALOGE("%s: dlsym error %s for ma_set_lr_swap", __func__, dlerror());
+ goto error;
+ }
- my_data->ma_set_sound_mode = (ma_set_sound_mode_t)dlsym(
- my_data->waves_handle, MA_QDSP_SET_MODE);
- if (!my_data->ma_set_sound_mode) {
- ALOGE("%s: dlsym error %s for ma_set_sound_mode", __func__, dlerror());
- goto error;
- }
+ my_data->ma_set_sound_mode = (ma_set_sound_mode_t)dlsym(my_data->waves_handle,
+ MA_QDSP_SET_MODE);
+ if (!my_data->ma_set_sound_mode) {
+ ALOGE("%s: dlsym error %s for ma_set_sound_mode", __func__, dlerror());
+ goto error;
+ }
- my_data->ma_set_volume = (ma_set_volume_t)dlsym(my_data->waves_handle,
- MA_QDSP_SET_VOL);
- if (!my_data->ma_set_volume) {
- ALOGE("%s: dlsym error %s for ma_set_volume", __func__, dlerror());
- goto error;
- }
+ my_data->ma_set_volume = (ma_set_volume_t)dlsym(my_data->waves_handle, MA_QDSP_SET_VOL);
+ if (!my_data->ma_set_volume) {
+ ALOGE("%s: dlsym error %s for ma_set_volume", __func__, dlerror());
+ goto error;
+ }
- my_data->ma_set_volume_table = (ma_set_volume_table_t)dlsym(
- my_data->waves_handle, MA_QDSP_SET_VOLT);
- if (!my_data->ma_set_volume_table) {
- ALOGE("%s: dlsym error %s for ma_set_volume_table", __func__, dlerror());
- goto error;
- }
+ my_data->ma_set_volume_table = (ma_set_volume_table_t)dlsym(my_data->waves_handle,
+ MA_QDSP_SET_VOLT);
+ if (!my_data->ma_set_volume_table) {
+ ALOGE("%s: dlsym error %s for ma_set_volume_table", __func__, dlerror());
+ goto error;
+ }
- my_data->ma_set_param = (ma_set_param_t)dlsym(
- my_data->waves_handle, MA_QDSP_SET_PARAM);
- if (!my_data->ma_set_param) {
- ALOGE("%s: dlsym error %s for ma_set_param", __func__, dlerror());
- goto error;
- }
+ my_data->ma_set_param = (ma_set_param_t)dlsym(my_data->waves_handle, MA_QDSP_SET_PARAM);
+ if (!my_data->ma_set_param) {
+ ALOGE("%s: dlsym error %s for ma_set_param", __func__, dlerror());
+ goto error;
+ }
+
+ my_data->ma_set_cmd = (ma_set_cmd_t)dlsym(my_data->waves_handle, MA_QDSP_SET_COMMAND);
+ if (!my_data->ma_set_cmd) {
+ ALOGE("%s: dlsym error %s for ma_set_cmd", __func__, dlerror());
+ }
+
+ my_data->ma_get_cmd = (ma_get_cmd_t)dlsym(my_data->waves_handle, MA_QDSP_GET_COMMAND);
+ if (!my_data->ma_get_cmd) {
+ ALOGE("%s: dlsym error %s for ma_get_cmd", __func__, dlerror());
+ }
}
/* get preset table */
@@ -679,7 +704,6 @@
void ma_set_device(struct audio_usecase *usecase)
{
- int i = 0;
struct ma_audio_cal_settings ma_cal;
if (!my_data) {
@@ -731,8 +755,101 @@
pthread_mutex_unlock(&my_data->lock);
}
-void ma_set_parameters(struct audio_device *adev,
- struct str_parms *parms)
+static bool ma_set_command(struct ma_audio_cal_settings *audio_cal_settings, char *cmd_data)
+{
+ if (my_data->ma_set_cmd)
+ return my_data->ma_set_cmd(g_ma_audio_cal_handle, audio_cal_settings, cmd_data);
+ return false;
+}
+
+static bool ma_get_command(struct ma_audio_cal_settings *audio_cal_settings, char *cmd_data,
+ char *reply_data, uint32_t reply_size)
+{
+ if (my_data->ma_get_cmd)
+ return my_data->ma_get_cmd(g_ma_audio_cal_handle, audio_cal_settings, cmd_data, reply_data,
+ reply_size);
+ return false;
+}
+
+static bool ma_fill_apptype_and_device_from_params(struct str_parms *parms, uint32_t *app_type,
+ struct listnode *devices)
+{
+ int ret;
+ char value[128];
+
+ ret = str_parms_get_str(parms, "cal_apptype", value, sizeof(value));
+
+ if (ret >= 0) {
+ *app_type = (uint32_t)atoi(value);
+ ret = str_parms_get_str(parms, "cal_devid", value, sizeof(value));
+ if (ret >= 0) {
+ update_device_list(devices, (uint32_t)atoi(value), "", true);
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool ma_add_apptype_and_device_to_params(struct str_parms *parms, uint32_t app_type,
+ struct listnode *devices)
+{
+ if (0 <= str_parms_add_int(parms, "cal_apptype", app_type)) {
+ if (0 <= str_parms_add_int(parms, "cal_devid", get_device_types(devices))) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool ma_get_command_parameters(struct str_parms *query, struct str_parms *reply)
+{
+ struct ma_audio_cal_settings ma_cal;
+ int ret;
+
+ ret = str_parms_get_str(query, "waves_data", ma_command_data, sizeof(ma_command_data));
+ if (ret >= 0) {
+ ma_cal_init(&ma_cal);
+ if (ma_fill_apptype_and_device_from_params(query, &ma_cal.common.app_type,
+ &ma_cal.common.devices)) {
+ ma_add_apptype_and_device_to_params(reply, ma_cal.common.app_type,
+ &ma_cal.common.devices);
+ ALOGV("%s: before - command=%s", __func__, (char *)ma_command_data);
+ if (ma_get_command(&ma_cal, ma_command_data, ma_reply_data, sizeof(ma_reply_data))) {
+ str_parms_add_str(reply, "waves_data", ma_reply_data);
+ ALOGV("%s: after - command=%s", __func__, (char *)ma_reply_data);
+ return true;
+ } else {
+ str_parms_add_str(reply, "waves_data", "");
+ }
+ }
+ }
+ return false;
+}
+
+static bool ma_set_command_parameters(struct str_parms *parms)
+{
+ struct ma_audio_cal_settings ma_cal;
+ int ret;
+
+ ret = str_parms_get_str(parms, "waves_data", ma_command_data, sizeof(ma_command_data));
+ if (ret >= 0) {
+ ma_cal_init(&ma_cal);
+ if (ma_fill_apptype_and_device_from_params(parms, &ma_cal.common.app_type,
+ &ma_cal.common.devices)) {
+ return ma_set_command(&ma_cal, ma_command_data);
+ }
+ }
+ return false;
+}
+
+void ma_get_parameters(struct audio_device *adev, struct str_parms *query,
+ struct str_parms *reply)
+{
+ (void)adev;
+ ma_get_command_parameters(query, reply);
+}
+
+void ma_set_parameters(struct audio_device *adev, struct str_parms *parms)
{
int ret;
int val;
@@ -791,6 +908,8 @@
}
}
}
+
+ ma_set_command_parameters(parms);
}
bool ma_supported_usb()
diff --git a/hal/audio_extn/sndmonitor.c b/hal/audio_extn/sndmonitor.c
index 4f27db9..ff234fc 100644
--- a/hal/audio_extn/sndmonitor.c
+++ b/hal/audio_extn/sndmonitor.c
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
+* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -224,6 +224,7 @@
(strncasecmp(card_id, "apq", 3) != 0) &&
(strncasecmp(card_id, "sa", 2) != 0) &&
(strncasecmp(card_id, "kona", 4) != 0) &&
+ (strncasecmp(card_id, "lahaina", 7) != 0) &&
(strncasecmp(card_id, "atoll", 5) != 0) &&
(strncasecmp(card_id, "bengal", 6) != 0) &&
(strncasecmp(card_id, "lito", 4) != 0)) {
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index fc75fd1..13910f6 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -65,6 +65,7 @@
#include <hardware/audio_alsaops.h>
#include <system/thread_defs.h>
#include <tinyalsa/asoundlib.h>
+#include <utils/Timers.h> // systemTime
#include <audio_effects/effect_aec.h>
#include <audio_effects/effect_ns.h>
#include <audio_utils/format.h>
@@ -1957,9 +1958,10 @@
reset_hdmi_sink_caps(out);
/* Cache ext disp type */
- if (platform_get_ext_disp_type_v2(adev->platform,
+ ret = platform_get_ext_disp_type_v2(adev->platform,
out->extconn.cs.controller,
- out->extconn.cs.stream <= 0)) {
+ out->extconn.cs.stream);
+ if(ret < 0) {
ALOGE("%s: Failed to query disp type, ret:%d", __func__, ret);
return -EINVAL;
}
@@ -2642,7 +2644,11 @@
is_single_device_type_equal(&vc_usecase->device_list,
AUDIO_DEVICE_OUT_HEARING_AID) ||
is_single_device_type_equal(&usecase->device_list,
- AUDIO_DEVICE_IN_VOICE_CALL))) {
+ AUDIO_DEVICE_IN_VOICE_CALL) ||
+ (is_single_device_type_equal(&usecase->device_list,
+ AUDIO_DEVICE_IN_USB_HEADSET) &&
+ is_single_device_type_equal(&vc_usecase->device_list,
+ AUDIO_DEVICE_OUT_USB_HEADSET)))) {
in_snd_device = vc_usecase->in_snd_device;
out_snd_device = vc_usecase->out_snd_device;
}
@@ -4549,6 +4555,17 @@
dprintf(fd, " Standby: %s\n", out->standby ? "yes" : "no");
dprintf(fd, " Frames written: %lld\n", (long long)out->written);
+ char buffer[256]; // for statistics formatting
+ if (!is_offload_usecase(out->usecase)) {
+ simple_stats_to_string(&out->fifo_underruns, buffer, sizeof(buffer));
+ dprintf(fd, " Fifo frame underruns: %s\n", buffer);
+ }
+
+ if (out->start_latency_ms.n > 0) {
+ simple_stats_to_string(&out->start_latency_ms, buffer, sizeof(buffer));
+ dprintf(fd, " Start latency ms: %s\n", buffer);
+ }
+
if (locked) {
pthread_mutex_unlock(&out->lock);
}
@@ -4870,7 +4887,7 @@
err = platform_get_controller_stream_from_params(parms, &ext_controller,
&ext_stream);
- if (err >= 0) {
+ if (err == 0) {
out->extconn.cs.controller = ext_controller;
out->extconn.cs.stream = ext_stream;
ALOGD("%s: usecase(%s) new controller/stream (%d/%d)", __func__,
@@ -5705,6 +5722,8 @@
if (out->standby) {
out->standby = false;
+ const int64_t startNs = systemTime(SYSTEM_TIME_MONOTONIC);
+
pthread_mutex_lock(&adev->lock);
if (out->usecase == USECASE_COMPRESS_VOIP_CALL)
ret = voice_extn_compress_voip_start_output_stream(out);
@@ -5717,6 +5736,7 @@
goto exit;
}
out->started = 1;
+ out->last_fifo_valid = false; // we're coming out of standby, last_fifo isn't valid.
if (last_known_cal_step != -1) {
ALOGD("%s: retry previous failed cal level set", __func__);
audio_hw_send_gain_dep_calibration(last_known_cal_step);
@@ -5731,6 +5751,10 @@
}
if (out->set_dual_mono)
audio_extn_send_dual_mono_mixing_coefficients(out);
+
+ // log startup time in ms.
+ simple_stats_log(
+ &out->start_latency_ms, (systemTime(SYSTEM_TIME_MONOTONIC) - startNs) * 1e-6);
}
if (adev->is_channel_status_set == false &&
@@ -5885,6 +5909,30 @@
bytes_to_write /= 2;
}
}
+
+ // Note: since out_get_presentation_position() is called alternating with out_write()
+ // by AudioFlinger, we can check underruns using the prior timestamp read.
+ // (Alternately we could check if the buffer is empty using pcm_get_htimestamp().
+ if (out->last_fifo_valid) {
+ // compute drain to see if there is an underrun.
+ const int64_t current_ns = systemTime(SYSTEM_TIME_MONOTONIC); // sys call
+ const int64_t frames_by_time =
+ (current_ns - out->last_fifo_time_ns) * out->config.rate / NANOS_PER_SECOND;
+ const int64_t underrun = frames_by_time - out->last_fifo_frames_remaining;
+
+ if (underrun > 0) {
+ simple_stats_log(&out->fifo_underruns, underrun);
+
+ ALOGW("%s: underrun(%lld) "
+ "frames_by_time(%lld) > out->last_fifo_frames_remaining(%lld)",
+ __func__,
+ (long long)out->fifo_underruns.n,
+ (long long)frames_by_time,
+ (long long)out->last_fifo_frames_remaining);
+ }
+ out->last_fifo_valid = false; // we're writing below, mark fifo info as stale.
+ }
+
ALOGVV("%s: writing buffer (%zu bytes) to pcm device", __func__, bytes);
long ns = 0;
@@ -6114,15 +6162,26 @@
if (out->pcm) {
unsigned int avail;
if (pcm_get_htimestamp(out->pcm, &avail, timestamp) == 0) {
- size_t kernel_buffer_size = out->config.period_size * out->config.period_count;
-
uint64_t signed_frames = 0;
uint64_t frames_temp = 0;
- frames_temp = (kernel_buffer_size > avail) ? (kernel_buffer_size - avail) : 0;
+ if (out->kernel_buffer_size > avail) {
+ frames_temp = out->last_fifo_frames_remaining = out->kernel_buffer_size - avail;
+ } else {
+ ALOGW("%s: avail:%u > kernel_buffer_size:%zu clamping!",
+ __func__, avail, out->kernel_buffer_size);
+ avail = out->kernel_buffer_size;
+ frames_temp = out->last_fifo_frames_remaining = 0;
+ }
+ out->last_fifo_valid = true;
+ out->last_fifo_time_ns = audio_utils_ns_from_timespec(timestamp);
+
if (out->written >= frames_temp)
signed_frames = out->written - frames_temp;
+ ALOGVV("%s: frames:%lld avail:%u kernel_buffer_size:%zu",
+ __func__, (long long)signed_frames, avail, out->kernel_buffer_size);
+
// This adjustment accounts for buffering after app processor.
// It is based on estimated DSP latency per use case, rather than exact.
frames_temp = platform_render_latency(out->usecase) * out->sample_rate / 1000000LL;
@@ -6141,7 +6200,9 @@
*frames = signed_frames;
ret = 0;
}
- } else if (out->card_status == CARD_STATUS_OFFLINE) {
+ } else if (out->card_status == CARD_STATUS_OFFLINE ||
+ // audioflinger still needs position updates when A2DP is suspended
+ (is_a2dp_out_device_type(&out->device_list) && audio_extn_a2dp_source_is_suspended())) {
*frames = out->written;
clock_gettime(CLOCK_MONOTONIC, timestamp);
if (is_offload_usecase(out->usecase))
@@ -6609,6 +6670,12 @@
dprintf(fd, " Frames read: %lld\n", (long long)in->frames_read);
dprintf(fd, " Frames muted: %lld\n", (long long)in->frames_muted);
+ char buffer[256]; // for statistics formatting
+ if (in->start_latency_ms.n > 0) {
+ simple_stats_to_string(&in->start_latency_ms, buffer, sizeof(buffer));
+ dprintf(fd, " Start latency ms: %s\n", buffer);
+ }
+
if (locked) {
pthread_mutex_unlock(&in->lock);
}
@@ -6870,6 +6937,8 @@
}
if (in->standby) {
+ const int64_t startNs = systemTime(SYSTEM_TIME_MONOTONIC);
+
pthread_mutex_lock(&adev->lock);
if (in->usecase == USECASE_COMPRESS_VOIP_CALL)
ret = voice_extn_compress_voip_start_input_stream(in);
@@ -6884,6 +6953,10 @@
goto exit;
}
in->standby = 0;
+
+ // log startup time in ms.
+ simple_stats_log(
+ &in->start_latency_ms, (systemTime(SYSTEM_TIME_MONOTONIC) - startNs) * 1e-6);
}
/* Avoid read if capture_stopped is set */
@@ -8256,6 +8329,8 @@
else
out->af_period_multiplier = 1;
+ out->kernel_buffer_size = out->config.period_size * out->config.period_count;
+
out->standby = 1;
/* out->muted = false; by calloc() */
/* out->written = 0; by calloc() */
@@ -8772,6 +8847,7 @@
voice_get_parameters(adev, query, reply);
audio_extn_a2dp_get_parameters(query, reply);
platform_get_parameters(adev->platform, query, reply);
+ audio_extn_ma_get_parameters(adev, query, reply);
pthread_mutex_unlock(&adev->lock);
exit:
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index cc9e602..5e3c1cb 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -48,6 +48,8 @@
#include <audio_route/audio_route.h>
#include <audio_utils/ErrorLog.h>
+#include <audio_utils/Statistics.h>
+#include <audio_utils/clock.h>
#include "audio_defs.h"
#include "voice.h"
#include "audio_hw_extn_api.h"
@@ -454,6 +456,16 @@
int stream;
} cs;
} extconn;
+
+ size_t kernel_buffer_size; // cached value of the alsa buffer size, const after open().
+
+ // last out_get_presentation_position() cached info.
+ bool last_fifo_valid;
+ unsigned int last_fifo_frames_remaining;
+ int64_t last_fifo_time_ns;
+
+ simple_stats_t fifo_underruns; // TODO: keep a list of the last N fifo underrun times.
+ simple_stats_t start_latency_ms;
};
struct stream_in {
@@ -507,6 +519,8 @@
int64_t frames_muted; /* total frames muted, not cleared when entering standby */
error_log_t *error_log;
+
+ simple_stats_t start_latency_ms;
};
typedef enum {
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index 235ae1f..b1ba217 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -5269,13 +5269,13 @@
goto done_key_audcal;
}
- memset(&cal, 0, sizeof(acdb_audio_cal_cfg_t));
- /* parse audio calibration keys */
- ret = parse_audiocal_cfg(parms, &cal);
-
/* handle audio calibration data now */
err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_AUD_CALDATA, value, len);
if (err >= 0) {
+ memset(&cal, 0, sizeof(acdb_audio_cal_cfg_t));
+ /* parse audio calibration keys */
+ ret = parse_audiocal_cfg(parms, &cal);
+
str_parms_del(parms, AUDIO_PARAMETER_KEY_AUD_CALDATA);
dlen = strlen(value);
if(dlen <= 0) {
@@ -5604,15 +5604,16 @@
goto done;
}
- memset(&cal, 0, sizeof(acdb_audio_cal_cfg_t));
- /* parse audiocal configuration keys */
- ret = parse_audiocal_cfg(query, &cal);
- if(ret == 0) {
- /* No calibration keys found */
- goto done;
- }
err = str_parms_get_str(query, AUDIO_PARAMETER_KEY_AUD_CALDATA, value, sizeof(value));
if (err >= 0) {
+ memset(&cal, 0, sizeof(acdb_audio_cal_cfg_t));
+ /* parse audiocal configuration keys */
+ ret = parse_audiocal_cfg(query, &cal);
+ if (ret == 0) {
+ /* No calibration keys found */
+ goto done;
+ }
+
str_parms_del(query, AUDIO_PARAMETER_KEY_AUD_CALDATA);
} else {
goto done;
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index a1fdc39..6764e19 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -1525,9 +1525,6 @@
#define ULL_PLATFORM_DELAY (3*1000LL)
#define MMAP_PLATFORM_DELAY (3*1000LL)
-static pthread_once_t check_op_once_ctl = PTHREAD_ONCE_INIT;
-static bool is_tmus = false;
-
static bool is_usb_snd_dev(snd_device_t snd_device)
{
if (snd_device < SND_DEVICE_IN_BEGIN) {
@@ -1549,7 +1546,7 @@
return false;
}
-static void check_operator()
+bool is_operator_tmus()
{
char value[PROPERTY_VALUE_MAX];
int mccmnc;
@@ -1574,17 +1571,12 @@
case 310210:
case 310200:
case 310160:
- is_tmus = true;
- break;
+ return true;
+ default:
+ return false;
}
}
-bool is_operator_tmus()
-{
- pthread_once(&check_op_once_ctl, check_operator);
- return is_tmus;
-}
-
static char *get_current_operator()
{
struct listnode *node;
@@ -1929,7 +1921,8 @@
else if (compare_device_type(out_devices, AUDIO_DEVICE_OUT_EARPIECE))
strlcat(ec_ref_mixer_path, " handset",
MIXER_PATH_MAX_LENGTH);
- else if (compare_device_type(out_devices, AUDIO_DEVICE_OUT_WIRED_HEADPHONE))
+ else if (compare_device_type(out_devices, AUDIO_DEVICE_OUT_WIRED_HEADPHONE) ||
+ compare_device_type(out_devices, AUDIO_DEVICE_OUT_WIRED_HEADSET))
strlcat(ec_ref_mixer_path, " headphones",
MIXER_PATH_MAX_LENGTH);
else if (compare_device_type(out_devices, AUDIO_DEVICE_OUT_USB_HEADSET))
@@ -6007,7 +6000,7 @@
}
disp_type = mixer_ctl_get_value(ctl, 0);
- if (disp_type == EXT_DISPLAY_TYPE_NONE) {
+ if (disp_type <= EXT_DISPLAY_TYPE_NONE) {
ALOGE("%s: Invalid external display type: %d", __func__, disp_type);
return -EINVAL;
}
@@ -7731,13 +7724,13 @@
goto done_key_audcal;
}
- memset(&cal, 0, sizeof(acdb_audio_cal_cfg_t));
- /* parse audio calibration keys */
- ret = parse_audiocal_cfg(parms, &cal);
-
/* handle audio calibration data now */
err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_AUD_CALDATA, value, len);
if (err >= 0) {
+ memset(&cal, 0, sizeof(acdb_audio_cal_cfg_t));
+ /* parse audio calibration keys */
+ ret = parse_audiocal_cfg(parms, &cal);
+
str_parms_del(parms, AUDIO_PARAMETER_KEY_AUD_CALDATA);
dlen = strlen(value);
if(dlen <= 0) {
@@ -8331,15 +8324,18 @@
goto done;
}
+ // init cal
memset(&cal, 0, sizeof(acdb_audio_cal_cfg_t));
- /* parse audiocal configuration keys */
- ret = parse_audiocal_cfg(query, &cal);
- if(ret == 0) {
- /* No calibration keys found */
- goto done;
- }
+
err = str_parms_get_str(query, AUDIO_PARAMETER_KEY_AUD_CALDATA, value, sizeof(value));
if (err >= 0) {
+ /* parse audiocal configuration keys */
+ ret = parse_audiocal_cfg(query, &cal);
+ if (ret == 0) {
+ /* No calibration keys found */
+ goto done;
+ }
+
str_parms_del(query, AUDIO_PARAMETER_KEY_AUD_CALDATA);
} else {
goto done;
diff --git a/hal/voice_extn/compress_voip.c b/hal/voice_extn/compress_voip.c
index dffe8ed..2ba1617 100644
--- a/hal/voice_extn/compress_voip.c
+++ b/hal/voice_extn/compress_voip.c
@@ -768,7 +768,7 @@
__func__, adev->snd_card, pcm_dev_tx_id);
voip_data.pcm_tx = pcm_open(adev->snd_card,
pcm_dev_tx_id,
- PCM_IN, voip_config);
+ PCM_IN|PCM_MONOTONIC, voip_config);
if (voip_data.pcm_tx && !pcm_is_ready(voip_data.pcm_tx)) {
ALOGE("%s: %s", __func__, pcm_get_error(voip_data.pcm_tx));
pcm_close(voip_data.pcm_tx);