Merge "hal : non-ms12 fmt support in qaf"
diff --git a/configs/msm8998/audio_output_policy.conf b/configs/msm8998/audio_output_policy.conf
index f1694b5..3a610c1 100644
--- a/configs/msm8998/audio_output_policy.conf
+++ b/configs/msm8998/audio_output_policy.conf
@@ -18,6 +18,13 @@
bit_width 16
app_type 69937
}
+ proaudio {
+ flags AUDIO_OUTPUT_FLAG_FAST|AUDIO_OUTPUT_FLAG_RAW
+ formats AUDIO_FORMAT_PCM_16_BIT
+ sampling_rates 48000
+ bit_width 16
+ app_type 69943
+ }
deep_buffer {
flags AUDIO_OUTPUT_FLAG_DEEP_BUFFER
formats AUDIO_FORMAT_PCM_16_BIT
diff --git a/configs/sdm660/audio_platform_info.xml b/configs/sdm660/audio_platform_info.xml
index a68d8c2..8b31fb1 100644
--- a/configs/sdm660/audio_platform_info.xml
+++ b/configs/sdm660/audio_platform_info.xml
@@ -76,11 +76,11 @@
</config_params>
<acdb_ids>
<device name="SND_DEVICE_OUT_SPEAKER" acdb_id="15"/>
- <device name="SND_DEVICE_OUT_SPEAKER_PROTECTED" acdb_id="136"/>
- <device name="SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED" acdb_id="136"/>
- <device name="SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT" acdb_id="136"/>
- <device name="SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED_VBAT" acdb_id="136"/>
- <device name="SND_DEVICE_IN_CAPTURE_VI_FEEDBACK" acdb_id="137"/>
+ <device name="SND_DEVICE_OUT_SPEAKER_PROTECTED" acdb_id="124"/>
+ <device name="SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED" acdb_id="101"/>
+ <device name="SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT" acdb_id="124"/>
+ <device name="SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED_VBAT" acdb_id="101"/>
+ <device name="SND_DEVICE_IN_CAPTURE_VI_FEEDBACK" acdb_id="102"/>
<device name="SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED" acdb_id="150"/>
<device name="SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED_VBAT" acdb_id="150"/>
<device name="SND_DEVICE_IN_CAPTURE_VI_FEEDBACK_MONO_1" acdb_id="151"/>
diff --git a/hal/audio_extn/audio_defs.h b/hal/audio_extn/audio_defs.h
index ae90cb3..cbc9014 100644
--- a/hal/audio_extn/audio_defs.h
+++ b/hal/audio_extn/audio_defs.h
@@ -106,6 +106,8 @@
/* Set or Query stream profile type */
#define AUDIO_PARAMETER_STREAM_PROFILE "audio_stream_profile"
+#define AUDIO_PARAMETER_KEY_VR_AUDIO_MODE "vr_audio_mode_on"
+
/* audio input flags for compress and timestamp mode.
* check other input flags defined in audio.h for conflicts
*/
@@ -138,16 +140,42 @@
struct aptx_dec_bt_addr bt_addr;
};
+struct audio_avt_device_drift_param {
+ /* Flag to indicate if resync is required on the client side for
+ * drift correction. Flag is set to TRUE for the first get_param response
+ * after device interface starts. This flag value can be used by client
+ * to identify if device interface restart has happened and if any
+ * re-sync is required at their end for drift correction.
+ */
+ uint32_t resync_flag;
+ /* Accumulated drift value in microseconds. This value is updated
+ * every 100th ms.
+ * Positive drift value indicates AV timer is running faster than device.
+ * Negative drift value indicates AV timer is running slower than device.
+ */
+ int32_t avt_device_drift_value;
+ /* Lower 32 bits of the 64-bit absolute timestamp of reference
+ * timer in microseconds.
+ */
+ uint32_t ref_timer_abs_ts_lsw;
+ /* Upper 32 bits of the 64-bit absolute timestamp of reference
+ * timer in microseconds.
+ */
+ uint32_t ref_timer_abs_ts_msw;
+};
+
typedef union {
struct source_tracking_param st_params;
struct sound_focus_param sf_params;
struct aptx_dec_param aptx_params;
+ struct audio_avt_device_drift_param drift_params;
} audio_extn_param_payload;
typedef enum {
AUDIO_EXTN_PARAM_SOURCE_TRACK,
AUDIO_EXTN_PARAM_SOUND_FOCUS,
- AUDIO_EXTN_PARAM_APTX_DEC
+ AUDIO_EXTN_PARAM_APTX_DEC,
+ AUDIO_EXTN_PARAM_AVT_DEVICE_DRIFT
} audio_extn_param_id;
#endif /* AUDIO_DEFS_H */
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index c9d3cf8..bc722f8 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -180,6 +180,41 @@
return ret;
}
+static int update_audio_ack_state(const struct audio_device *adev, int node_value)
+{
+ const char *mixer_ctl_name = "External Display Audio Ack";
+ struct mixer_ctl *ctl;
+ int ret = 0;
+
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ /* If no mixer command support, fall back to sysfs node approach */
+ if (!ctl) {
+ ALOGI("%s: could not get ctl for mixer cmd(%s), use sysfs node instead\n",
+ __func__, mixer_ctl_name);
+ ret = update_ext_disp_sysfs_node(adev, node_value);
+ } else {
+ char *ack_str = NULL;
+
+ if (node_value == EXT_DISPLAY_PLUG_STATUS_NOTIFY_ENABLE)
+ ack_str = "Ack_Enable";
+ else if (node_value == 1)
+ ack_str = "Connect";
+ else if (node_value == 0)
+ ack_str = "Disconnect";
+ else {
+ ALOGE("%s: Invalid input parameter - 0x%x\n",
+ __func__, node_value);
+ return -EINVAL;
+ }
+
+ ret = mixer_ctl_set_enum_by_string(ctl, ack_str);
+ if (ret)
+ ALOGE("%s: Could not set ctl for mixer cmd - %s ret %d\n",
+ __func__, mixer_ctl_name, ret);
+ }
+ return ret;
+}
+
static void audio_extn_ext_disp_set_parameters(const struct audio_device *adev,
struct str_parms *parms)
{
@@ -192,13 +227,13 @@
if (is_hdmi_sysfs_node_init == false) {
//check if this is different for dp and hdmi
is_hdmi_sysfs_node_init = true;
- update_ext_disp_sysfs_node(adev, EXT_DISPLAY_PLUG_STATUS_NOTIFY_ENABLE);
+ update_audio_ack_state(adev, EXT_DISPLAY_PLUG_STATUS_NOTIFY_ENABLE);
}
- update_ext_disp_sysfs_node(adev, 1);
+ update_audio_ack_state(adev, 1);
} else if(str_parms_get_str(parms, "disconnect", value, sizeof(value)) >= 0
&& (atoi(value) & AUDIO_DEVICE_OUT_AUX_DIGITAL)){
//params = "disconnect=1024" for external display disconnection.
- update_ext_disp_sysfs_node(adev, 0);
+ update_audio_ack_state(adev, 0);
ALOGV("invalidate cached edid");
platform_invalidate_hdmi_config(adev->platform);
} else {
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 93036af..b83ef4d 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -820,4 +820,7 @@
int audio_extn_set_aptx_dec_params(struct aptx_dec_param *payload);
#endif
+int audio_extn_utils_get_avt_device_drift(
+ struct audio_usecase *usecase,
+ struct audio_avt_device_drift_param *drift_param);
#endif /* AUDIO_EXTN_H */
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index b12ab8e..217f110 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -92,6 +92,7 @@
STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DIRECT_PCM),
STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_PRIMARY),
STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_FAST),
+ STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_RAW),
STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DEEP_BUFFER),
STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD),
STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_NON_BLOCKING),
@@ -155,6 +156,17 @@
#endif
};
+/* payload structure avt_device drift query */
+struct audio_avt_device_drift_stats {
+ uint32_t minor_version;
+ /* Indicates the device interface direction as either
+ * source (Tx) or sink (Rx).
+ */
+ uint16_t device_direction;
+ /*params exposed to client */
+ struct audio_avt_device_drift_param drift_param;
+};
+
static char bTable[BASE_TABLE_SIZE] = {
'A','B','C','D','E','F','G','H','I','J','K','L',
'M','N','O','P','Q','R','S','T','U','V','W','X',
@@ -192,7 +204,7 @@
flag_name = strtok_r(NULL, "|", &last_r);
}
- ALOGV("parse_flag_names: flag - %d", flag);
+ ALOGV("parse_flag_names: flag - %x", flag);
io_flags.in_flags = (audio_input_flags_t)flag;
io_flags.out_flags = (audio_output_flags_t)flag;
return io_flags;
@@ -676,8 +688,8 @@
__func__, sample_rate, bit_width);
}
- ALOGV("%s: flags: %x, format: %x sample_rate %d, profile %s",
- __func__, flags, format, sample_rate, profile);
+ ALOGV("%s: flags: %x, format: %x sample_rate %d, profile %s, app_type %d",
+ __func__, flags, format, sample_rate, profile, app_type_cfg->app_type);
list_for_each(node_i, streams_output_cfg_list) {
s_info = node_to_item(node_i, struct streams_io_cfg, list);
/* Along with flags do profile matching if set at either end.*/
@@ -725,6 +737,12 @@
return native_usecase;
}
+
+static inline bool audio_is_vr_mode_on(struct audio_device *(__attribute__((unused)) adev))
+{
+ return adev->vr_audio_mode_enabled;
+}
+
void audio_extn_utils_update_stream_app_type_cfg_for_usecase(
struct audio_device *adev,
struct audio_usecase *usecase)
@@ -789,12 +807,21 @@
if ((usecase->id != USECASE_AUDIO_PLAYBACK_DEEP_BUFFER) &&
(usecase->id != USECASE_AUDIO_PLAYBACK_LOW_LATENCY) &&
(usecase->id != USECASE_AUDIO_PLAYBACK_MULTI_CH) &&
+ (usecase->id != USECASE_AUDIO_PLAYBACK_ULL) &&
(!is_offload_usecase(usecase->id)) &&
(usecase->type != PCM_CAPTURE)) {
ALOGV("%s: a rx/tx/loopback path where app type cfg is not required %d", __func__, usecase->id);
rc = 0;
goto exit_send_app_type_cfg;
}
+
+ //if VR is active then only send the mixer control
+ if (usecase->id == USECASE_AUDIO_PLAYBACK_ULL && !audio_is_vr_mode_on(adev)) {
+ ALOGI("ULL doesnt need sending app type cfg, returning");
+ rc = 0;
+ goto exit_send_app_type_cfg;
+ }
+
if (usecase->type == PCM_PLAYBACK) {
pcm_device_id = platform_get_pcm_device_id(usecase->id, PCM_PLAYBACK);
snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
@@ -1548,3 +1575,75 @@
}
#endif
+
+int audio_extn_utils_get_avt_device_drift(
+ struct audio_usecase *usecase,
+ struct audio_avt_device_drift_param *drift_param)
+{
+ int ret = 0, count = 0;
+ char avt_device_drift_mixer_ctl_name[MIXER_PATH_MAX_LENGTH] = {0};
+ struct mixer_ctl *ctl = NULL;
+ struct audio_avt_device_drift_stats drift_stats;
+ struct audio_device *adev = NULL;
+
+ if (usecase != NULL && usecase->type == PCM_PLAYBACK) {
+ adev = usecase->stream.out->dev;
+ switch(usecase->out_snd_device) {
+ case SND_DEVICE_OUT_HDMI:
+ strlcpy(avt_device_drift_mixer_ctl_name,
+ "HDMI RX Drift",
+ MIXER_PATH_MAX_LENGTH);
+ break;
+ case SND_DEVICE_OUT_DISPLAY_PORT:
+ strlcpy(avt_device_drift_mixer_ctl_name,
+ "DISPLAY Port RX Drift",
+ MIXER_PATH_MAX_LENGTH);
+ break;
+ default :
+ ALOGE("%s: Unsupported device %d",__func__,
+ usecase->stream.out->devices);
+ ret = -EINVAL;
+ }
+ } else {
+ ALOGE("%s: Invalid usecase %d ",__func__, usecase->type);
+ ret = -EINVAL;
+ }
+
+ if(ret)
+ goto done;
+
+ ctl = mixer_get_ctl_by_name(adev->mixer, avt_device_drift_mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, avt_device_drift_mixer_ctl_name);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ALOGV("%s: Getting AV Timer vs Device Drift mixer ctrl name %s", __func__,
+ avt_device_drift_mixer_ctl_name);
+
+ mixer_ctl_update(ctl);
+ count = mixer_ctl_get_num_values(ctl);
+ if (count != sizeof(struct audio_avt_device_drift_stats)) {
+ ALOGE("%s: mixer_ctl_get_num_values() invalid drift_stats data size",
+ __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = mixer_ctl_get_array(ctl, (void *)&drift_stats, count);
+ if (ret != 0) {
+ ALOGE("%s: mixer_ctl_get_array() failed to get drift_stats Params",
+ __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+ memcpy(drift_param, &drift_stats.drift_param,
+ sizeof(struct audio_avt_device_drift_param));
+done:
+ return ret;
+}
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 9da81e6..6644b48 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -2169,6 +2169,9 @@
struct audio_usecase *uc_info;
struct audio_device *adev = out->dev;
int snd_card_status = get_snd_card_state(adev);
+ char mixer_ctl_name[128];
+ struct mixer_ctl *ctl = NULL;
+ char* perf_mode[] = {"ULL", "ULL_PP", "LL"};
if ((out->usecase < 0) || (out->usecase >= AUDIO_USECASE_MAX)) {
ret = -EINVAL;
@@ -2249,6 +2252,28 @@
} else
flags |= PCM_MONOTONIC;
+ if ((adev->vr_audio_mode_enabled) &&
+ (out->flags & AUDIO_OUTPUT_FLAG_RAW)) {
+ snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
+ "PCM_Dev %d Topology", out->pcm_device_id);
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGI("%s: Could not get ctl for mixer cmd might be ULL - %s",
+ __func__, mixer_ctl_name);
+ } else {
+ //if success use ULLPP
+ ALOGI("%s: mixer ctrl %s succeeded setting up ULL for %d",
+ __func__, mixer_ctl_name, out->pcm_device_id);
+ //There is a still a possibility that some sessions
+ // that request for FAST|RAW when 3D audio is active
+ //can go through ULLPP. Ideally we expects apps to
+ //listen to audio focus and stop concurrent playback
+ //Also, we will look for mode flag (voice_in_communication)
+ //before enabling the realtime flag.
+ mixer_ctl_set_enum_by_string(ctl, perf_mode[1]);
+ }
+ }
+
while (1) {
out->pcm = pcm_open(adev->snd_card, out->pcm_device_id,
flags, &out->config);
@@ -4245,8 +4270,8 @@
}
}
- ALOGV("%s devices:%d, format:%x, out->sample_rate:%d,out->bit_width:%d out->format:%d out->flags:%x, flags:%x",
- __func__, devices, format, out->sample_rate, out->bit_width, out->format, out->flags, flags);
+ ALOGV("%s devices:%d, format:%x, out->sample_rate:%d,out->bit_width:%d out->format:%d out->flags:%x, flags: %x usecase %d",
+ __func__, devices, format, out->sample_rate, out->bit_width, out->format, out->flags, flags, out->usecase);
/* TODO remove this hardcoding and check why width is zero*/
if (out->bit_width == 0)
@@ -4277,6 +4302,7 @@
ret = -EEXIST;
goto error_open;
}
+
pthread_mutex_unlock(&adev->lock);
out->stream.common.get_sample_rate = out_get_sample_rate;
@@ -4564,6 +4590,23 @@
}
}
}
+
+ //handle vr audio setparam
+ ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VR_AUDIO_MODE,
+ value, sizeof(value));
+ if (ret >= 0) {
+ ALOGI("Setting vr mode to be %s", value);
+ if (!strncmp(value, "true", 4)) {
+ adev->vr_audio_mode_enabled = true;
+ ALOGI("Setting vr mode to true");
+ } else if (!strncmp(value, "false", 5)) {
+ adev->vr_audio_mode_enabled = false;
+ ALOGI("Setting vr mode to false");
+ } else {
+ ALOGI("wrong vr mode set");
+ }
+ }
+
audio_extn_set_parameters(adev, parms);
done:
str_parms_destroy(parms);
@@ -4605,6 +4648,30 @@
str_parms_add_int(reply, "SND_CARD_STATUS", val);
goto exit;
}
+ //handle vr audio getparam
+
+ ret = str_parms_get_str(query,
+ AUDIO_PARAMETER_KEY_VR_AUDIO_MODE,
+ value, sizeof(value));
+
+ if (ret >= 0) {
+ bool vr_audio_enabled = false;
+ pthread_mutex_lock(&adev->lock);
+ vr_audio_enabled = adev->vr_audio_mode_enabled;
+ pthread_mutex_unlock(&adev->lock);
+
+ ALOGI("getting vr mode to %d", vr_audio_enabled);
+
+ if (vr_audio_enabled) {
+ str_parms_add_str(reply, AUDIO_PARAMETER_KEY_VR_AUDIO_MODE,
+ "true");
+ goto exit;
+ } else {
+ str_parms_add_str(reply, AUDIO_PARAMETER_KEY_VR_AUDIO_MODE,
+ "false");
+ goto exit;
+ }
+ }
pthread_mutex_lock(&adev->lock);
audio_extn_get_parameters(adev, query, reply);
@@ -5193,6 +5260,9 @@
}
adev->bt_wb_speech_enabled = false;
+ //initialize this to false for now,
+ //this will be set to true through set param
+ adev->vr_audio_mode_enabled = false;
audio_extn_ds2_enable(adev);
*device = &adev->device.common;
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index e99d546..abfba45 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -428,6 +428,7 @@
bool native_playback_enabled;
bool asrc_mode_enabled;
qahwi_device_t qahwi_dev;
+ bool vr_audio_mode_enabled;
};
int select_devices(struct audio_device *adev,
diff --git a/hal/audio_hw_extn_api.c b/hal/audio_hw_extn_api.c
index f36d85d..25c4503 100644
--- a/hal/audio_hw_extn_api.c
+++ b/hal/audio_hw_extn_api.c
@@ -48,6 +48,61 @@
};
#endif
+static void lock_output_stream(struct stream_out *out)
+{
+ pthread_mutex_lock(&out->pre_lock);
+ pthread_mutex_lock(&out->lock);
+ pthread_mutex_unlock(&out->pre_lock);
+}
+
+/* API to send playback stream specific config parameters */
+int qahwi_out_set_param_data(struct audio_stream_out *stream __unused,
+ audio_extn_param_id param_id __unused,
+ audio_extn_param_payload *payload __unused) {
+ return -ENOSYS;
+}
+
+/* API to get playback stream specific config parameters */
+int qahwi_out_get_param_data(struct audio_stream_out *stream,
+ audio_extn_param_id param_id,
+ audio_extn_param_payload *payload)
+{
+ int ret = -EINVAL;
+ struct stream_out *out = (struct stream_out *)stream;
+ struct audio_usecase *uc_info;
+
+ if (!stream || !payload) {
+ ALOGE("%s:: Invalid Param",__func__);
+ return ret;
+ }
+
+ lock_output_stream(out);
+ ALOGD("%s: enter: stream (%p) usecase(%d: %s) param_id %d", __func__,
+ stream, out->usecase, use_case_table[out->usecase], param_id);
+
+ switch (param_id) {
+ case AUDIO_EXTN_PARAM_AVT_DEVICE_DRIFT:
+ uc_info = get_usecase_from_list(out->dev, out->usecase);
+ if (uc_info == NULL) {
+ ALOGE("%s: Could not find the usecase (%d) in the list",
+ __func__, out->usecase);
+ ret = -EINVAL;
+ } else {
+ ret = audio_extn_utils_get_avt_device_drift(uc_info,
+ (struct audio_avt_device_drift_param *)payload);
+ if(ret)
+ ALOGE("%s:: avdrift query failed error %d", __func__, ret);
+ }
+ break;
+ default:
+ ALOGE("%s:: unsupported param_id %d", __func__, param_id);
+ break;
+ }
+
+ pthread_mutex_unlock(&out->lock);
+ return ret;
+}
+
int qahwi_get_param_data(const struct audio_hw_device *adev,
audio_extn_param_id param_id,
audio_extn_param_payload *payload)
diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp
index 147c03c..cb22dc7 100644
--- a/policy_hal/AudioPolicyManager.cpp
+++ b/policy_hal/AudioPolicyManager.cpp
@@ -1593,6 +1593,7 @@
// requested sample rate matches with that of voip input stream (if opened already)
int value = 0;
uint32_t mode = 0, voipOutCount = 1, voipSampleRate = 1;
+ bool is_vr_mode_on = false;
String8 valueStr = mpClientInterface->getParameters((audio_io_handle_t)0,
String8("audio_mode"));
AudioParameter result = AudioParameter(valueStr);
@@ -1627,6 +1628,25 @@
}
}
}
+ //IF VOIP is going to be started at the same time as when
+ //vr is enabled, get VOIP to fallback to low latency
+ String8 vr_value;
+ valueStr = mpClientInterface->getParameters((audio_io_handle_t)0,
+ String8("vr_audio_mode_on"));
+ result = AudioParameter(valueStr);
+ if (result.get(String8("vr_audio_mode_on"), vr_value) == NO_ERROR) {
+ is_vr_mode_on = vr_value.contains("true");
+ ALOGI("VR mode is %d, switch to primary output if request is for fast|raw",
+ is_vr_mode_on);
+ }
+
+ if (is_vr_mode_on) {
+ //check the flags being requested for, and clear FAST|RAW
+ flags = (audio_output_flags_t)(flags &
+ (~(AUDIO_OUTPUT_FLAG_FAST|AUDIO_OUTPUT_FLAG_RAW)));
+
+ }
+
}
#ifdef VOICE_CONCURRENCY
diff --git a/qahw_api/inc/qahw_api.h b/qahw_api/inc/qahw_api.h
index 8a65686..0f3fc50 100644
--- a/qahw_api/inc/qahw_api.h
+++ b/qahw_api/inc/qahw_api.h
@@ -141,6 +141,16 @@
char* qahw_out_get_parameters(const qahw_stream_handle_t *stream,
const char *keys);
+/* API to set playback stream specific config parameters */
+int qahw_out_set_param_data(qahw_stream_handle_t *out_handle,
+ qahw_param_id param_id,
+ qahw_param_payload *payload);
+
+/* API to get playback stream specific config parameters */
+int qahw_out_get_param_data(qahw_stream_handle_t *out_handle,
+ qahw_param_id param_id,
+ qahw_param_payload *payload);
+
/*
* Return the audio hardware driver estimated latency in milliseconds.
*/
@@ -270,7 +280,6 @@
int qahw_close_input_stream(qahw_stream_handle_t *in_handle);
-
/*
* Return the sampling rate in Hz - eg. 44100.
*/
diff --git a/qahw_api/inc/qahw_defs.h b/qahw_api/inc/qahw_defs.h
index eb500a2..63dc4da 100644
--- a/qahw_api/inc/qahw_defs.h
+++ b/qahw_api/inc/qahw_defs.h
@@ -243,19 +243,37 @@
struct aptx_dec_bt_addr bt_addr;
};
+struct qahw_avt_device_drift_param {
+ /* Flag to indicate if resync is required on the client side for
+ * drift correction. Flag is set to TRUE for the first get_param response
+ * after device interface starts. This flag value can be used by client
+ * to identify if device interface restart has happened and if any
+ * re-sync is required at their end for drift correction.
+ */
+ uint32_t resync_flag;
+ /* Accumulated drift value in microseconds.
+ * Positive drift value indicates AV timer is running faster than device.
+ * Negative drift value indicates AV timer is running slower than device.
+ */
+ int32_t avt_device_drift_value;
+ /* 64-bit absolute timestamp of reference */
+ uint64_t ref_timer_abs_ts;
+};
+
typedef union {
struct qahw_source_tracking_param st_params;
struct qahw_sound_focus_param sf_params;
struct qahw_aptx_dec_param aptx_params;
+ struct qahw_avt_device_drift_param drift_params;
} qahw_param_payload;
typedef enum {
QAHW_PARAM_SOURCE_TRACK,
QAHW_PARAM_SOUND_FOCUS,
- QAHW_PARAM_APTX_DEC
+ QAHW_PARAM_APTX_DEC,
+ QAHW_PARAM_AVT_DEVICE_DRIFT /* PARAM to query AV timer vs device drift */
} qahw_param_id;
-
__END_DECLS
#endif // QTI_AUDIO_HAL_DEFS_H
diff --git a/qahw_api/src/qahw.c b/qahw_api/src/qahw.c
index 393dba9..c5cd636 100644
--- a/qahw_api/src/qahw.c
+++ b/qahw_api/src/qahw.c
@@ -47,15 +47,23 @@
*/
#define QAHW_MODULE_API_VERSION_CURRENT QAHW_MODULE_API_VERSION_0_0
-typedef uint64_t (*qahwi_in_read_v2_t)(audio_stream_in_t *in, void* buffer,
- size_t bytes, int64_t *timestamp);
-
typedef int (*qahwi_get_param_data_t) (const audio_hw_device_t *,
qahw_param_id, qahw_param_payload *);
typedef int (*qahwi_set_param_data_t) (audio_hw_device_t *,
qahw_param_id, qahw_param_payload *);
+typedef uint64_t (*qahwi_in_read_v2_t)(audio_stream_in_t *in, void* buffer,
+ size_t bytes, int64_t *timestamp);
+
+typedef int (*qahwi_out_set_param_data_t)(struct audio_stream_out *out,
+ qahw_param_id param_id,
+ qahw_param_payload *payload);
+
+typedef int (*qahwi_out_get_param_data_t)(struct audio_stream_out *out,
+ qahw_param_id param_id,
+ qahw_param_payload *payload);
+
typedef struct {
audio_hw_device_t *audio_device;
char module_name[MAX_MODULE_NAME_LENGTH];
@@ -80,6 +88,8 @@
qahw_module_t *module;
struct listnode list;
pthread_mutex_t lock;
+ qahwi_out_set_param_data_t qahwi_out_get_param_data;
+ qahwi_out_get_param_data_t qahwi_out_set_param_data;
} qahw_stream_out_t;
typedef struct {
@@ -397,6 +407,67 @@
return str_param;
}
+/* API to get playback stream specific config parameters */
+int qahw_out_set_param_data(qahw_stream_handle_t *out_handle,
+ qahw_param_id param_id,
+ qahw_param_payload *payload)
+{
+ int rc = -EINVAL;
+ qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+ audio_stream_out_t *out = NULL;
+
+ if (!payload) {
+ ALOGE("%s::Invalid param", __func__);
+ goto exit;
+ }
+
+ if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+ ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+ goto exit;
+ }
+
+ pthread_mutex_lock(&qahw_stream_out->lock);
+ out = qahw_stream_out->stream;
+ if (qahw_stream_out->qahwi_out_set_param_data) {
+ rc = qahw_stream_out->qahwi_out_set_param_data(out, param_id, payload);
+ } else {
+ rc = -ENOSYS;
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_stream_out->lock);
+
+exit:
+ return rc;
+}
+
+/* API to get playback stream specific config parameters */
+int qahw_out_get_param_data(qahw_stream_handle_t *out_handle,
+ qahw_param_id param_id,
+ qahw_param_payload *payload)
+{
+ int rc = -EINVAL;
+ qahw_stream_out_t *qahw_stream_out = (qahw_stream_out_t *)out_handle;
+ audio_stream_out_t *out = NULL;
+
+ if (!is_valid_qahw_stream((void *)qahw_stream_out, STREAM_DIR_OUT)) {
+ ALOGE("%s::Invalid out handle %p", __func__, out_handle);
+ goto exit;
+ }
+
+ pthread_mutex_lock(&qahw_stream_out->lock);
+ out = qahw_stream_out->stream;
+ if (qahw_stream_out->qahwi_out_get_param_data) {
+ rc = qahw_stream_out->qahwi_out_get_param_data(out, param_id, payload);
+ } else {
+ rc = -ENOSYS;
+ ALOGW("%s not supported", __func__);
+ }
+ pthread_mutex_unlock(&qahw_stream_out->lock);
+
+exit:
+ return rc;
+}
+
uint32_t qahw_out_get_latency(const qahw_stream_handle_t *out_handle)
{
uint32_t latency = 0;
@@ -1373,7 +1444,29 @@
*out_handle = (void *)qahw_stream_out;
pthread_mutex_init(&qahw_stream_out->lock, (const pthread_mutexattr_t *)NULL);
list_add_tail(&qahw_module->out_list, &qahw_stream_out->list);
- }
+
+ /* clear any existing errors */
+ const char *error;
+ dlerror();
+ qahw_stream_out->qahwi_out_get_param_data = (qahwi_out_get_param_data_t)
+ dlsym(qahw_module->module->dso,
+ "qahwi_out_get_param_data");
+ if ((error = dlerror()) != NULL) {
+ ALOGI("%s: dlsym error %s for qahwi_out_get_param_data",
+ __func__, error);
+ qahw_stream_out->qahwi_out_get_param_data = NULL;
+ }
+
+ dlerror();
+ qahw_stream_out->qahwi_out_set_param_data = (qahwi_out_set_param_data_t)
+ dlsym(qahw_module->module->dso,
+ "qahwi_out_set_param_data");
+ if ((error = dlerror()) != NULL) {
+ ALOGI("%s: dlsym error %s for qahwi_out_set_param_data",
+ __func__, error);
+ qahw_stream_out->qahwi_out_set_param_data = NULL;
+ }
+}
exit:
pthread_mutex_unlock(&qahw_module->lock);
diff --git a/qahw_api/test/qahw_playback_test.c b/qahw_api/test/qahw_playback_test.c
index b3e5291..71229c1 100644
--- a/qahw_api/test/qahw_playback_test.c
+++ b/qahw_api/test/qahw_playback_test.c
@@ -120,6 +120,11 @@
struct wav_header hdr;
};
+struct drift_data {
+ qahw_module_handle_t *out_handle;
+ volatile bool thread_exit;
+};
+
typedef struct {
qahw_module_handle_t *qahw_mod_handle;
audio_io_handle_t handle;
@@ -137,6 +142,7 @@
char *kvpair_values;
bool flags_set;
int effect_index;
+ bool drift_query;
thread_func_t ethread_func;
thread_data_t *ethread_data;
cmd_data_t cmd_data;
@@ -152,8 +158,6 @@
const char *log_filename = NULL;
float vol_level = 0.01;
struct proxy_data proxy_params;
-bool proxy_thread_active;
-pthread_t proxy_thread;
pthread_t playback_thread[MAX_PLAYBACK_STREAMS];
bool thread_active[MAX_PLAYBACK_STREAMS] = { false };
@@ -384,6 +388,30 @@
return 0;
}
+void *drift_read(void* data)
+{
+ struct drift_data* params = (struct drift_data*) data;
+ qahw_stream_handle_t* out_handle = params->out_handle;
+ struct qahw_avt_device_drift_param drift_param;
+ int rc = -EINVAL;
+
+ printf("drift quried at 100ms interval \n");
+ while (!(params->thread_exit)) {
+ memset(&drift_param, 0, sizeof(struct qahw_avt_device_drift_param));
+ rc = qahw_out_get_param_data(out_handle, QAHW_PARAM_AVT_DEVICE_DRIFT,
+ (qahw_param_payload *)&drift_param);
+ if (!rc) {
+ printf("resync flag = %d, drift %d, av timer %lld\n",
+ drift_param.resync_flag,
+ drift_param.avt_device_drift_value,
+ drift_param.ref_timer_abs_ts);
+ } else {
+ printf("drift query failed rc = %d retry after 100ms\n", rc);
+ }
+
+ usleep(100000);
+ }
+}
/* Entry point function for stream playback
* Opens the stream
@@ -397,6 +425,12 @@
int rc = 0;
stream_config *params = (stream_config*) stream_data;
const char* stream_name = "output_stream";
+ bool proxy_thread_active = false;
+ pthread_t proxy_thread;
+
+ bool drift_thread_active = false;
+ pthread_t drift_query_thread;
+ struct drift_data drift_params;
if (params->output_device & AUDIO_DEVICE_OUT_ALL_A2DP)
params->output_device = AUDIO_DEVICE_OUT_PROXY;
@@ -522,6 +556,17 @@
rc = pthread_create(&proxy_thread, NULL, proxy_read, (void *)&proxy_params);
if (!rc)
proxy_thread_active = true;
+ } else if (params->drift_query &&
+ (params->output_device & AUDIO_DEVICE_OUT_HDMI) &&
+ !drift_thread_active) {
+ drift_params.out_handle = params->out_handle;
+ drift_params.thread_exit = false;
+ fprintf(log_file, "create thread to read avtime vs hdmi drift\n");
+ rc = pthread_create(&drift_query_thread, NULL, drift_read, (void *)&drift_params);
+ if (!rc)
+ drift_thread_active = true;
+ else
+ fprintf(log_file, "drift query thread creation failure %d\n", rc);
}
rc = qahw_out_set_volume(params->out_handle, vol_level, vol_level);
@@ -616,6 +661,11 @@
pthread_join(proxy_thread, NULL);
}
+ if (drift_thread_active) {
+ usleep(500000);
+ drift_params.thread_exit = true;
+ pthread_join(drift_query_thread, NULL);
+ }
rc = qahw_out_standby(params->out_handle);
if (rc) {
fprintf(log_file, "stream %d: out standby failed %d \n", params->stream_index, rc);
@@ -974,6 +1024,7 @@
printf(" -e --effect-type <effect type> - Effect used for test\n");
printf(" 0:bassboost 1:virtualizer 2:equalizer 3:visualizer(NA) 4:reverb 5:audiosphere others:null\n\n");
printf(" -A --bt-addr <bt device addr> - Required to set bt device adress for aptx decoder\n\n");
+ printf(" -q --query drift - Required for querying avtime vs hdmi drift\n");
printf(" -P - Argument to do multi-stream playback, currently 2 streams are supported to run concurrently\n");
printf(" Put -P and mention required attributes for the next stream\n");
printf(" \n Examples \n");
@@ -1072,7 +1123,6 @@
int i = 0;
int j = 0;
kpi_mode = false;
- proxy_thread_active = false;
log_file = stdout;
proxy_params.acp.file_name = "/data/pcm_dump.wav";
@@ -1099,6 +1149,7 @@
{"plus", no_argument, 0, 'P'},
{"effect-path", required_argument, 0, 'e'},
{"bt-addr", required_argument, 0, 'A'},
+ {"query drift", no_argument, 0, 'q'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}
};
@@ -1122,7 +1173,7 @@
while ((opt = getopt_long(argc,
argv,
- "-f:r:c:b:d:v:l:t:a:w:k:PD:KF:e:A:h",
+ "-f:r:c:b:d:v:l:t:a:w:k:PD:KF:e:A:qh",
long_options,
&option_index)) != -1) {
@@ -1198,6 +1249,9 @@
case 'A':
ba = optarg;
break;
+ case 'q':
+ stream_param[i].drift_query = true;
+ break;
case 'P':
if(i >= MAX_PLAYBACK_STREAMS - 1) {
fprintf(log_file, "cannot have more than %d streams\n", MAX_PLAYBACK_STREAMS);