Implement HAL API get_presentation_position

Change-Id: I9b917cc565786d5ca95cc0adbb2949bf60fd5910
diff --git a/audio/audio_hw.c b/audio/audio_hw.c
index 81f1bf2..8a0ca37 100644
--- a/audio/audio_hw.c
+++ b/audio/audio_hw.c
@@ -161,6 +161,7 @@
     /* Array of supported channel mask configurations. +1 so that the last entry is always 0 */
     audio_channel_mask_t supported_channel_masks[MAX_SUPPORTED_CHANNEL_MASKS + 1];
     bool muted;
+    uint64_t written; /* total frames written, not cleared when entering standby */
 
     struct audio_device *dev;
 };
@@ -623,13 +624,13 @@
     if (adev->sco_on_count++ > 0)
         return;
 
-    adev->pcm_voice_out = pcm_open(PCM_CARD, PCM_DEVICE_VOICE, PCM_OUT,
+    adev->pcm_voice_out = pcm_open(PCM_CARD, PCM_DEVICE_VOICE, PCM_OUT | PCM_MONOTONIC,
                               &pcm_config_sco);
     if (adev->pcm_voice_out && !pcm_is_ready(adev->pcm_voice_out)) {
         ALOGE("pcm_open(VOICE_OUT) failed: %s", pcm_get_error(adev->pcm_voice_out));
         goto err_voice_out;
     }
-    adev->pcm_sco_out = pcm_open(PCM_CARD, PCM_DEVICE_SCO, PCM_OUT,
+    adev->pcm_sco_out = pcm_open(PCM_CARD, PCM_DEVICE_SCO, PCM_OUT | PCM_MONOTONIC,
                             &pcm_config_sco);
     if (adev->pcm_sco_out && !pcm_is_ready(adev->pcm_sco_out)) {
         ALOGE("pcm_open(SCO_OUT) failed: %s", pcm_get_error(adev->pcm_sco_out));
@@ -703,7 +704,7 @@
                        AUDIO_DEVICE_OUT_ALL_SCO)) {
 
         out->pcm[PCM_CARD] = pcm_open(PCM_CARD, out->pcm_device,
-                                      PCM_OUT, &out->config);
+                                      PCM_OUT | PCM_MONOTONIC, &out->config);
 
         if (out->pcm[PCM_CARD] && !pcm_is_ready(out->pcm[PCM_CARD])) {
             ALOGE("pcm_open(PCM_CARD) failed: %s",
@@ -715,7 +716,7 @@
 
     if (out->device & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) {
         out->pcm[PCM_CARD_SPDIF] = pcm_open(PCM_CARD_SPDIF, out->pcm_device,
-                                            PCM_OUT, &out->config);
+                                            PCM_OUT | PCM_MONOTONIC, &out->config);
 
         if (out->pcm[PCM_CARD_SPDIF] &&
                 !pcm_is_ready(out->pcm[PCM_CARD_SPDIF])) {
@@ -1163,9 +1164,13 @@
 
     /* Write to all active PCMs */
     for (i = 0; i < PCM_TOTAL; i++)
-        if (out->pcm[i])
-           pcm_write(out->pcm[i], (void *)buffer, bytes);
-
+        if (out->pcm[i]) {
+            ret = pcm_write(out->pcm[i], (void *)buffer, bytes);
+            if (ret != 0)
+                break;
+        }
+    if (ret == 0)
+        out->written += bytes / (out->config.channels * sizeof(short));
 
 exit:
     pthread_mutex_unlock(&out->lock);
@@ -1200,6 +1205,40 @@
     return -EINVAL;
 }
 
+static int out_get_presentation_position(const struct audio_stream_out *stream,
+                                   uint64_t *frames, struct timespec *timestamp)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    int ret = -1;
+
+    pthread_mutex_lock(&out->lock);
+
+    int i;
+    // There is a question how to implement this correctly when there is more than one PCM stream.
+    // We are just interested in the frames pending for playback in the kernel buffer here,
+    // not the total played since start.  The current behavior should be safe because the
+    // cases where both cards are active are marginal.
+    for (i = 0; i < PCM_TOTAL; i++)
+        if (out->pcm[i]) {
+            size_t avail;
+            if (pcm_get_htimestamp(out->pcm[i], &avail, timestamp) == 0) {
+                size_t kernel_buffer_size = out->config.period_size * out->config.period_count;
+                // FIXME This calculation is incorrect if there is buffering after app processor
+                int64_t signed_frames = out->written - kernel_buffer_size + avail;
+                // It would be unusual for this value to be negative, but check just in case ...
+                if (signed_frames >= 0) {
+                    *frames = signed_frames;
+                    ret = 0;
+                }
+                break;
+            }
+        }
+
+    pthread_mutex_unlock(&out->lock);
+
+    return ret;
+}
+
 /** audio_stream_in implementation **/
 static uint32_t in_get_sample_rate(const struct audio_stream *stream)
 {
@@ -1541,6 +1580,7 @@
     out->stream.write = out_write;
     out->stream.get_render_position = out_get_render_position;
     out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
+    out->stream.get_presentation_position = out_get_presentation_position;
 
     out->dev = adev;
 
@@ -1550,6 +1590,7 @@
 
     out->standby = true;
     /* out->muted = false; by calloc() */
+    /* out->written = 0; by calloc() */
 
     pthread_mutex_lock(&adev->lock);
     if (adev->outputs[type]) {