audio: hal: add DSP clock recovery support
-Changes to add DSP clock recovery support
Conflicts:
qahw_api/test/qahw_playback_test.c
hal/audio_extn/utils.c
CRs-Fixed: 2036937
Change-Id: I32e18e415c4a7dfdc7ae13d0e50c1ca76d739cc0
diff --git a/hal/audio_extn/audio_defs.h b/hal/audio_extn/audio_defs.h
index 06b4fb9..5fb5cdf 100644
--- a/hal/audio_extn/audio_defs.h
+++ b/hal/audio_extn/audio_defs.h
@@ -177,10 +177,23 @@
uint64_t start_delay; /* session start delay in microseconds*/
};
+struct audio_out_enable_drift_correction {
+ bool enable; /* enable drift correction*/
+};
+
+struct audio_out_correct_drift {
+ /*
+ * adjust time in microseconds, a positive value
+ * to advance the clock or a negative value to
+ * delay the clock.
+ */
+ int64_t adjust_time;
+};
+
/* type of asynchronous write callback events. Mutually exclusive
* event enums append those defined for stream_callback_event_t in audio.h */
typedef enum {
- AUDIO_EXTN_STREAM_CBK_EVENT_ADSP = 0x100 /* callback event from ADSP PP,
+ AUDIO_EXTN_STREAM_CBK_EVENT_ADSP = 0x100 /* callback event from ADSP PP,
* corresponding payload will be
* sent as is to the client
*/
@@ -203,6 +216,8 @@
struct audio_avt_device_drift_param drift_params;
struct audio_out_render_window_param render_window_param;
struct audio_out_start_delay_param start_delay;
+ struct audio_out_enable_drift_correction drift_enable_param;
+ struct audio_out_correct_drift drift_correction_param;
struct audio_adsp_event adsp_event_params;
} audio_extn_param_payload;
@@ -213,6 +228,10 @@
AUDIO_EXTN_PARAM_AVT_DEVICE_DRIFT,
AUDIO_EXTN_PARAM_OUT_RENDER_WINDOW, /* PARAM to set render window */
AUDIO_EXTN_PARAM_OUT_START_DELAY,
+ /* enable adsp drift correction this must be called before out_write */
+ AUDIO_EXTN_PARAM_OUT_ENABLE_DRIFT_CORRECTION,
+ /* param to set drift value to be adjusted by dsp */
+ AUDIO_EXTN_PARAM_OUT_CORRECT_DRIFT,
AUDIO_EXTN_PARAM_ADSP_STREAM_CMD
} audio_extn_param_id;
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index 3c9330c..05afda0 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -1367,12 +1367,20 @@
ret = audio_extn_utils_compress_set_start_delay(out,
(struct audio_out_start_delay_param *)(payload));
break;
+ case AUDIO_EXTN_PARAM_OUT_ENABLE_DRIFT_CORRECTION:
+ ret = audio_extn_utils_compress_enable_drift_correction(out,
+ (struct audio_out_enable_drift_correction *)(payload));
+ break;
+ case AUDIO_EXTN_PARAM_OUT_CORRECT_DRIFT:
+ ret = audio_extn_utils_compress_correct_drift(out,
+ (struct audio_out_correct_drift *)(payload));
+ break;
case AUDIO_EXTN_PARAM_ADSP_STREAM_CMD:
ret = audio_extn_adsp_hdlr_stream_set_param(out->adsp_hdlr_stream_handle,
ADSP_HDLR_STREAM_CMD_REGISTER_EVENT,
(void *)&payload->adsp_event_params);
break;
- default:
+ default:
ALOGE("%s:: unsupported param_id %d", __func__, param_id);
break;
}
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index e8210ac..c71037e 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -864,4 +864,10 @@
int audio_extn_utils_compress_set_start_delay(
struct stream_out *out,
struct audio_out_start_delay_param *start_delay_param);
+int audio_extn_utils_compress_enable_drift_correction(
+ struct stream_out *out,
+ struct audio_out_enable_drift_correction *drift_enable);
+int audio_extn_utils_compress_correct_drift(
+ struct stream_out *out,
+ struct audio_out_correct_drift *drift_correction_param);
#endif /* AUDIO_EXTN_H */
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index a2dff9f..0331fc4 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -1609,36 +1609,39 @@
{
int ret = 0, count = 0;
char avt_device_drift_mixer_ctl_name[MIXER_PATH_MAX_LENGTH] = {0};
+ const char *backend = NULL;
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;
+ backend = platform_get_snd_device_backend_interface(usecase->out_snd_device);
+ if (!backend) {
+ ALOGE("%s: Unsupported device %d", __func__,
+ usecase->stream.out->devices);
+ ret = -EINVAL;
+ goto done;
+ }
+ strlcpy(avt_device_drift_mixer_ctl_name,
+ backend,
+ MIXER_PATH_MAX_LENGTH);
+
+ count = strlen(backend);
+ if (MIXER_PATH_MAX_LENGTH - count > 0) {
+ strlcat(&avt_device_drift_mixer_ctl_name[count],
+ " DRIFT",
+ MIXER_PATH_MAX_LENGTH - count);
+ } else {
+ ret = -EINVAL;
+ goto done;
}
} else {
ALOGE("%s: Invalid usecase",__func__);
ret = -EINVAL;
+ goto done;
}
- if(ret)
- goto done;
-
+ adev = usecase->stream.out->dev;
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",
@@ -1849,11 +1852,8 @@
goto exit;
}
- if ((out->render_mode == RENDER_MODE_AUDIO_MASTER) ||
- (out->render_mode == RENDER_MODE_AUDIO_STC_MASTER)) {
- memcpy(&out->render_window, render_window,
- sizeof(struct audio_out_render_window_param));
- } else {
+ if ((out->render_mode != RENDER_MODE_AUDIO_MASTER) &&
+ (out->render_mode != RENDER_MODE_AUDIO_STC_MASTER)) {
ALOGD("%s:: only supported in timestamp mode, current "
"render mode mode %d", __func__, out->render_mode);
goto exit;
@@ -1915,11 +1915,8 @@
goto exit;
}
- if ((out->render_mode == RENDER_MODE_AUDIO_MASTER) ||
- (out->render_mode == RENDER_MODE_AUDIO_STC_MASTER)) {
- /* store it to reconfigure in start_output_stream() */
- out->delay_param.start_delay = delay_param->start_delay;
- } else {
+ if ((out->render_mode != RENDER_MODE_AUDIO_MASTER) &&
+ (out->render_mode != RENDER_MODE_AUDIO_STC_MASTER)) {
ALOGD("%s:: only supported in timestamp mode, current "
"render mode mode %d", __func__, out->render_mode);
goto exit;
@@ -2016,3 +2013,104 @@
return snd_card_num;
}
+
+#ifdef SNDRV_COMPRESS_ENABLE_ADJUST_SESSION_CLOCK
+int audio_extn_utils_compress_enable_drift_correction(
+ struct stream_out *out,
+ struct audio_out_enable_drift_correction *drift)
+{
+ struct snd_compr_metadata metadata;
+ int ret = -EINVAL;
+
+ if(drift == NULL) {
+ ALOGE("%s:: Invalid param", __func__);
+ goto exit;
+ }
+
+ ALOGD("%s:: drift enable %d", __func__,drift->enable);
+
+ if (!is_offload_usecase(out->usecase)) {
+ ALOGE("%s:: not supported for non offload session", __func__);
+ goto exit;
+ }
+
+ if (!out->compr) {
+ ALOGW("%s:: offload session not yet opened,"
+ "start delay will be configure later", __func__);
+ goto exit;
+ }
+
+ metadata.key = SNDRV_COMPRESS_ENABLE_ADJUST_SESSION_CLOCK;
+ metadata.value[0] = drift->enable;
+ out->drift_correction_enabled = drift->enable;
+
+ ret = compress_set_metadata(out->compr, &metadata);
+ if(ret) {
+ ALOGE("%s::error %s", __func__, compress_get_error(out->compr));
+ out->drift_correction_enabled = false;
+ }
+
+exit:
+ return ret;
+}
+#else
+int audio_extn_utils_compress_enable_drift_correction(
+ struct stream_out *out __unused,
+ struct audio_out_enable_drift_correction *drift __unused)
+{
+ ALOGD("%s:: configuring drift enablement not supported", __func__);
+ return 0;
+}
+#endif
+
+#ifdef SNDRV_COMPRESS_ADJUST_SESSION_CLOCK
+int audio_extn_utils_compress_correct_drift(
+ struct stream_out *out,
+ struct audio_out_correct_drift *drift_param)
+{
+ struct snd_compr_metadata metadata;
+ int ret = -EINVAL;
+
+ if (drift_param == NULL) {
+ ALOGE("%s:: Invalid drift_param", __func__);
+ goto exit;
+ }
+
+ ALOGD("%s:: adjust time 0x%"PRIx64" ", __func__,
+ drift_param->adjust_time);
+
+ if (!is_offload_usecase(out->usecase)) {
+ ALOGE("%s:: not supported for non offload session", __func__);
+ goto exit;
+ }
+
+ if (!out->compr) {
+ ALOGW("%s:: offload session not yet opened", __func__);
+ goto exit;
+ }
+
+ if (!out->drift_correction_enabled) {
+ ALOGE("%s:: drift correction not enabled", __func__);
+ goto exit;
+ }
+
+ metadata.key = SNDRV_COMPRESS_ADJUST_SESSION_CLOCK;
+ metadata.value[0] = 0xFFFFFFFF & drift_param->adjust_time; /* lsb */
+ metadata.value[1] = \
+ (0xFFFFFFFF00000000 & drift_param->adjust_time) >> 32; /* msb*/
+
+ ret = compress_set_metadata(out->compr, &metadata);
+ if(ret)
+ ALOGE("%s::error %s", __func__, compress_get_error(out->compr));
+exit:
+ return ret;
+}
+#else
+int audio_extn_utils_compress_correct_drift(
+ struct stream_out *out __unused,
+ struct audio_out_correct_drift *drift_param __unused)
+{
+ ALOGD("%s:: setting adjust clock not supported", __func__);
+ return 0;
+}
+#endif
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 1013332..a04cc45 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -2208,9 +2208,6 @@
if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)
audio_extn_keep_alive_start();
- /*reset delay_param to 0*/
- out->delay_param.start_delay = 0;
-
ALOGV("%s: exit: status(%d)", __func__, ret);
return ret;
}
@@ -2390,11 +2387,6 @@
audio_extn_utils_compress_set_render_mode(out);
audio_extn_utils_compress_set_clk_rec_mode(uc_info);
- /* set render window if it was set before compress_open() */
- if (out->render_window.render_ws != 0 && out->render_window.render_we != 0)
- audio_extn_utils_compress_set_render_window(out,
- &out->render_window);
- audio_extn_utils_compress_set_start_delay(out, &out->delay_param);
audio_extn_dts_create_state_notifier_node(out->usecase);
audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
@@ -4197,9 +4189,6 @@
out->render_mode = RENDER_MODE_AUDIO_NO_TIMESTAMP;
}
- memset(&out->render_window, 0,
- sizeof(struct audio_out_render_window_param));
-
out->send_new_metadata = 1;
out->send_next_track_params = false;
out->is_compr_metadata_avail = false;
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 9f10efa..26d5d18 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -266,8 +266,7 @@
struct listnode qaf_offload_cmd_list;
uint32_t platform_latency;
render_mode_t render_mode;
- struct audio_out_render_window_param render_window; /*render winodw*/
- struct audio_out_start_delay_param delay_param; /*start delay*/
+ bool drift_correction_enabled;
audio_offload_info_t info;
qahwi_stream_out_t qahwi_out;
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index 22215e3..a7e0044 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -5928,6 +5928,27 @@
return ret;
}
+const char *platform_get_snd_device_backend_interface(snd_device_t device)
+{
+ const char *hw_interface_name = NULL;
+
+ if ((device < SND_DEVICE_MIN) || (device >= SND_DEVICE_MAX)) {
+ ALOGE("%s: Invalid snd_device = %d",
+ __func__, device);
+ 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);
+ else
+ ALOGD("%s: hw_interface set for device %s\n", __func__, hw_interface_name);
+done:
+ return hw_interface_name;
+}
+
+
int platform_get_snd_device_backend_index(snd_device_t device)
{
int i, be_dai_id;
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 47cae0c..c2b5af0 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -5664,6 +5664,26 @@
return ret;
}
+const char *platform_get_snd_device_backend_interface(snd_device_t device)
+{
+ const char *hw_interface_name = NULL;
+
+ if ((device < SND_DEVICE_MIN) || (device >= SND_DEVICE_MAX)) {
+ ALOGE("%s: Invalid snd_device = %d",
+ __func__, device);
+ 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);
+ else
+ ALOGD("%s: hw_interface set for device %s\n", __func__, hw_interface_name);
+done:
+ return hw_interface_name;
+}
+
int platform_get_snd_device_backend_index(snd_device_t device)
{
int i, be_dai_id;
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 1b6c1f1..b7c4598 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -144,6 +144,7 @@
int platform_set_snd_device_backend(snd_device_t snd_device, const char * backend,
const char * hw_interface);
int platform_get_snd_device_backend_index(snd_device_t device);
+const char * platform_get_snd_device_backend_interface(snd_device_t device);
/* From platform_info.c */
int platform_info_init(const char *filename, void *, caller_t);
diff --git a/qahw_api/inc/qahw_defs.h b/qahw_api/inc/qahw_defs.h
index 7ae9475..7dcad2a 100644
--- a/qahw_api/inc/qahw_defs.h
+++ b/qahw_api/inc/qahw_defs.h
@@ -278,6 +278,19 @@
uint64_t start_delay; /* session start delay in microseconds*/
};
+struct qahw_out_enable_drift_correction {
+ bool enable; /* enable drift correction*/
+};
+
+struct qahw_out_correct_drift {
+ /*
+ * adjust time in microseconds, a positive value
+ * to advance the clock or a negative value to
+ * delay the clock.
+ */
+ int64_t adjust_time;
+};
+
#define QAHW_MAX_ADSP_STREAM_CMD_PAYLOAD_LEN 512
/* payload format for HAL parameter
@@ -295,6 +308,8 @@
struct qahw_avt_device_drift_param drift_params;
struct qahw_out_render_window_param render_window_params;
struct qahw_out_start_delay_param start_delay;
+ struct qahw_out_enable_drift_correction drift_enable_param;
+ struct qahw_out_correct_drift drift_correction_param;
struct qahw_adsp_event adsp_event_params;
} qahw_param_payload;
@@ -305,6 +320,10 @@
QAHW_PARAM_AVT_DEVICE_DRIFT, /* PARAM to query AV timer vs device drift */
QAHW_PARAM_OUT_RENDER_WINDOW, /* PARAM to set render window */
QAHW_PARAM_OUT_START_DELAY, /* PARAM to set session start delay*/
+ /* enable adsp drift correction this must be called before out_write */
+ QAHW_PARAM_OUT_ENABLE_DRIFT_CORRECTION,
+ /* param to set drift value to be adjusted by dsp */
+ QAHW_PARAM_OUT_CORRECT_DRIFT,
QAHW_PARAM_ADSP_STREAM_CMD
} qahw_param_id;
diff --git a/qahw_api/test/qahw_playback_test.c b/qahw_api/test/qahw_playback_test.c
index c9f55a7..3fe6fb6 100644
--- a/qahw_api/test/qahw_playback_test.c
+++ b/qahw_api/test/qahw_playback_test.c
@@ -139,6 +139,7 @@
struct drift_data {
qahw_module_handle_t *out_handle;
+ bool enable_drift_correction;
volatile bool thread_exit;
};
@@ -174,6 +175,7 @@
usb_mode_type_t usb_mode;
int effect_index;
bool drift_query;
+ bool drift_correction;
char *device_url;
thread_func_t ethread_func;
thread_data_t *ethread_data;
@@ -499,7 +501,7 @@
struct qahw_avt_device_drift_param drift_param;
int rc = -EINVAL;
- printf("drift quried at 100ms interval \n");
+ printf("drift queried 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,
@@ -514,9 +516,23 @@
}
usleep(100000);
+ if (params->enable_drift_correction &&
+ drift_param.avt_device_drift_value) {
+ struct qahw_out_correct_drift param;
+ param.adjust_time = drift_param.avt_device_drift_value;
+ printf("sending drift correction value %dus\n",
+ drift_param.avt_device_drift_value);
+ rc = qahw_out_set_param_data(out_handle,
+ QAHW_PARAM_OUT_CORRECT_DRIFT,
+ (qahw_param_payload *)¶m);
+ if (rc < 0)
+ fprintf(log_file, "qahw_out_set_param_data failed with err %d %d\n",
+ rc, __LINE__);
+ }
}
return NULL;
}
+
static int is_eof(stream_config *stream) {
if (stream->filename) {
if (feof(stream->file_stream)) {
@@ -711,12 +727,24 @@
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) {
+ } else if (params->drift_query && !drift_thread_active) {
+ struct qahw_out_enable_drift_correction drift_enable_param;
+
drift_params.out_handle = params->out_handle;
drift_params.thread_exit = false;
- fprintf(log_file, "create thread to read avtime vs hdmi drift\n");
+ fprintf(log_file, "create thread to read avtimer vs device drift\n");
+ if(params->drift_correction) {
+ drift_params.enable_drift_correction = true;
+ drift_enable_param.enable = true;
+ rc = qahw_out_set_param_data(params->out_handle,
+ QAHW_PARAM_OUT_ENABLE_DRIFT_CORRECTION,
+ (qahw_param_payload *)&drift_enable_param);
+ if (rc < 0) {
+ fprintf(log_file, "qahw_out_set_param_data failed with err %d %d\n",
+ rc, __LINE__);
+ drift_enable_param.enable = false;
+ }
+ }
rc = pthread_create(&drift_query_thread, NULL, drift_read, (void *)&drift_params);
if (!rc)
drift_thread_active = true;
@@ -1446,7 +1474,8 @@
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(" -q --drift query - Required for querying avtime vs hdmi drift\n");
+ printf(" -Q --drift query and correction - Enable Drift query and correction\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(" 0:bassboost 1:virtualizer 2:equalizer 3:visualizer(NA) 4:reverb 5:audiosphere others:null");
@@ -1658,6 +1687,7 @@
{"effect-path", required_argument, 0, 'e'},
{"bt-addr", required_argument, 0, 'A'},
{"query drift", no_argument, 0, 'q'},
+ {"drift correction", no_argument, 0, 'Q'},
{"device-nodeurl",required_argument, 0, 'u'},
{"mode", required_argument, 0, 'm'},
{"help", no_argument, 0, 'h'},
@@ -1683,7 +1713,7 @@
while ((opt = getopt_long(argc,
argv,
- "-f:r:c:b:d:s:v:l:t:a:w:k:PD:KF:Ee:A:u:m:qh",
+ "-f:r:c:b:d:s:v:l:t:a:w:k:PD:KF:Ee:A:u:m:qQh",
long_options,
&option_index)) != -1) {
@@ -1770,6 +1800,10 @@
case 'q':
stream_param[i].drift_query = true;
break;
+ case 'Q':
+ stream_param[i].drift_query = true;
+ stream_param[i].drift_correction = true;
+ break;
case 'P':
if(i >= MAX_PLAYBACK_STREAMS - 1) {
fprintf(log_file, "cannot have more than %d streams\n", MAX_PLAYBACK_STREAMS);