audio: add support to query presentation position from DSP

Add support to query presentation position from DSP
in system time domain.

Change-Id: I475aeedb7a3691027698ca91747b801dff569d21
Signed-off-by: Surendar Karka <skarka@codeaurora.org>
diff --git a/hal/audio_extn/audio_defs.h b/hal/audio_extn/audio_defs.h
index 3fd4b85..d8d1bbb 100644
--- a/hal/audio_extn/audio_defs.h
+++ b/hal/audio_extn/audio_defs.h
@@ -249,6 +249,12 @@
    struct audio_device_cfg_param dev_cfg_params;
 };
 
+struct audio_out_presentation_position_param {
+    struct timespec timestamp;
+    uint64_t frames;
+    int32_t clock_id;
+};
+
 typedef struct mix_matrix_params {
     uint16_t num_output_channels;
     uint16_t num_input_channels;
@@ -282,6 +288,7 @@
     struct audio_device_cfg_param device_cfg;
     struct mix_matrix_params mm_params;
     struct audio_license_params license_params;
+    struct audio_out_presentation_position_param pos_param;
 } audio_extn_param_payload;
 
 typedef enum {
@@ -305,6 +312,7 @@
     AUDIO_EXTN_PARAM_CH_MIX_MATRIX_PARAMS,
     /* License information */
     AUDIO_EXTN_PARAM_LICENSE_PARAMS,
+    AUDIO_EXTN_PARAM_OUT_PRESENTATION_POSITION,
 } audio_extn_param_id;
 
 typedef union {
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index 11b96e7..f00f74d 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -3132,6 +3132,13 @@
                     ALOGE("%s:: avdrift query failed error %d", __func__, ret);
             }
             break;
+        case AUDIO_EXTN_PARAM_OUT_PRESENTATION_POSITION:
+            ret = audio_ext_get_presentation_position(out,
+                      (struct audio_out_presentation_position_param *)payload);
+                if (ret < 0)
+                    ALOGE("%s:: presentation position query failed error %d",
+                           __func__, ret);
+            break;
         default:
             ALOGE("%s:: unsupported param_id %d", __func__, param_id);
             break;
@@ -5164,3 +5171,29 @@
     ALOGD_IF(kv_pairs != NULL, "%s: returns %s", __func__, kv_pairs);
     free(kv_pairs);
 }
+
+int audio_ext_get_presentation_position(struct stream_out *out,
+                           struct audio_out_presentation_position_param *pos_param)
+{
+    int ret = -ENODATA;
+
+    if (!out) {
+        ALOGE("%s:: Invalid stream",__func__);
+        return ret;
+    }
+
+    if (is_offload_usecase(out->usecase)) {
+        if (out->compr != NULL)
+            ret = audio_extn_utils_compress_get_dsp_presentation_pos(out,
+                                  &pos_param->frames, &pos_param->timestamp, pos_param->clock_id);
+    } else {
+        if (out->pcm)
+            ret = audio_extn_utils_pcm_get_dsp_presentation_pos(out,
+                                  &pos_param->frames, &pos_param->timestamp, pos_param->clock_id);
+    }
+
+    ALOGV("%s frames %lld timestamp %lld", __func__, (long long int)pos_param->frames,
+           pos_param->timestamp.tv_sec*1000000000LL + pos_param->timestamp.tv_nsec);
+
+    return ret;
+}
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index facf590..b3297ed 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -1083,6 +1083,12 @@
 int audio_extn_utils_set_downmix_params(
             struct stream_out *out,
             struct mix_matrix_params *mm_params);
+int audio_ext_get_presentation_position(struct stream_out *out,
+            struct audio_out_presentation_position_param *pos_param);
+int audio_extn_utils_compress_get_dsp_presentation_pos(struct stream_out *out,
+            uint64_t *frames, struct timespec *timestamp, int32_t clock_id);
+int audio_extn_utils_pcm_get_dsp_presentation_pos(struct stream_out *out,
+            uint64_t *frames, struct timespec *timestamp, int32_t clock_id);
 #ifdef AUDIO_HW_LOOPBACK_ENABLED
 /* API to create audio patch */
 int audio_extn_hw_loopback_create_audio_patch(struct audio_hw_device *dev,
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index af89a8a..09921af 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -30,6 +30,7 @@
 #include <log/log.h>
 #include <cutils/misc.h>
 #include <unistd.h>
+#include <sys/ioctl.h>
 
 
 #include "audio_hw.h"
@@ -39,6 +40,7 @@
 #include "voice.h"
 #include <sound/compress_params.h>
 #include <sound/compress_offload.h>
+#include <sound/devdep_params.h>
 #include <tinycompress/tinycompress.h>
 
 #ifdef DYNAMIC_LOG_ENABLED
@@ -2258,6 +2260,80 @@
 }
 #endif
 
+#ifdef SNDRV_COMPRESS_DSP_POSITION
+int audio_extn_utils_compress_get_dsp_presentation_pos(struct stream_out *out,
+            uint64_t *frames, struct timespec *timestamp, int32_t clock_id)
+{
+    int ret = -EINVAL;
+    uint64_t *val = NULL;
+    uint64_t time = 0;
+    struct snd_compr_metadata metadata;
+
+    ALOGV("%s:: Quering DSP position with clock id %d",__func__, clock_id);
+    metadata.key = SNDRV_COMPRESS_DSP_POSITION;
+    metadata.value[0] = clock_id;
+    ret = compress_get_metadata(out->compr, &metadata);
+    if (ret) {
+        ALOGE("%s::error %s", __func__, compress_get_error(out->compr));
+        ret = -errno;
+        goto exit;
+    }
+    val = (uint64_t *)&metadata.value[1];
+    *frames = *val;
+    time = *(val + 1);
+    timestamp->tv_sec = time / 1000000;
+    timestamp->tv_nsec = (time % 1000000)*1000;
+
+exit:
+    return ret;
+}
+#else
+int audio_extn_utils_compress_get_dsp_presentation_pos(struct stream_out *out __unused,
+            uint64_t *frames __unused, struct timespec *timestamp __unused,
+            int32_t clock_id __unused)
+{
+    ALOGD("%s:: dsp presentation position not supported", __func__);
+    return 0;
+
+}
+#endif
+
+#ifdef SNDRV_PCM_IOCTL_DSP_POSITION
+int audio_extn_utils_pcm_get_dsp_presentation_pos(struct stream_out *out,
+            uint64_t *frames, struct timespec *timestamp, int32_t clock_id)
+{
+    int ret = -EINVAL;
+    uint64_t time = 0;
+    struct snd_pcm_prsnt_position prsnt_position;
+
+    ALOGV("%s:: Quering DSP position with clock id %d",__func__, clock_id);
+    prsnt_position.clock_id = clock_id;
+    ret = pcm_ioctl(out->pcm, SNDRV_PCM_IOCTL_DSP_POSITION, &prsnt_position);
+    if (ret) {
+        ALOGE("%s::error  %d", __func__, ret);
+        ret = -EIO;
+        goto exit;
+    }
+
+    *frames = prsnt_position.frames;
+    time = prsnt_position.timestamp;
+    timestamp->tv_sec = time / 1000000;
+    timestamp->tv_nsec = (time % 1000000)*1000;
+
+exit:
+    return ret;
+}
+#else
+int audio_extn_utils_pcm_get_dsp_presentation_pos(struct stream_out *out __unused,
+            uint64_t *frames __unused, struct timespec *timestamp __unused,
+            int32_t clock_id __unused)
+{
+    ALOGD("%s:: dsp presentation position not supported", __func__);
+    return 0;
+
+}
+#endif
+
 #define MAX_SND_CARD 8
 #define RETRY_US 1000000
 #define RETRY_NUMBER 40