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 *)&param);
+            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);