Adding get_presentation_position to gf audio

Cts tests require keeping track of audio presentation position at
various playback rates.

Added playback rates to match required 6.0 CDD document.

Added get_presentation_position which simulates a playback rate.

Test: Run CtsMedia module
Bug: 31648354
Change-Id: I688c9db784a5ebbd9a790df38f5d07ca7ac24572
diff --git a/audio/audio_hw.c b/audio/audio_hw.c
index 8dab816..393494b 100644
--- a/audio/audio_hw.c
+++ b/audio/audio_hw.c
@@ -36,8 +36,8 @@
 #define PCM_DEVICE 0
 
 
-#define OUT_PERIOD_SIZE 512
-#define OUT_LONG_PERIOD_COUNT 2
+#define OUT_PERIOD_SIZE 1024
+#define OUT_LONG_PERIOD_COUNT 4
 
 #define IN_PERIOD_MS 20
 #define IN_PERIOD_COUNT 4
@@ -66,6 +66,9 @@
     struct audio_config req_config;   // Constant after init
     struct pcm *pcm;                  // Protected by this->lock
     struct pcm_config pcm_config;     // Constant after init
+    size_t frames_played;             // Protected by this->lock
+    struct timespec frames_played_time;    // Protected by this->lock
+    size_t frames_written;            // Protected by this->lock
 };
 
 struct generic_stream_in {
@@ -116,7 +119,6 @@
 static size_t out_get_buffer_size(const struct audio_stream *stream)
 {
     struct generic_stream_out *out = (struct generic_stream_out *)stream;
-    int channel_count = popcount(out->req_config.channel_mask);
     int size = out->pcm_config.period_size *
                 audio_stream_out_frame_size(&out->stream);
 
@@ -273,7 +275,8 @@
     }
     // pcm_open always returns a non-null pcm ptr which must be
     // checked with pcm_is_ready
-    out->pcm = pcm_open(PCM_CARD, PCM_DEVICE, PCM_OUT, &out->pcm_config);
+    out->pcm = pcm_open(PCM_CARD, PCM_DEVICE,
+                        PCM_OUT | PCM_MONOTONIC, &out->pcm_config);
     if (!pcm_is_ready(out->pcm)) {
         ALOGE("pcm_open(out) failed: %s: channels %d format %d rate %d",
               pcm_get_error(out->pcm),
@@ -297,7 +300,8 @@
     }
     // pcm_open always returns a non-null pcm ptr which must be
     // checked with pcm_is_ready
-    in->pcm = pcm_open(PCM_CARD, PCM_DEVICE, PCM_IN, &in->pcm_config);
+    in->pcm = pcm_open(PCM_CARD, PCM_DEVICE,
+                       PCM_IN | PCM_MONOTONIC, &in->pcm_config);
     if (!pcm_is_ready(in->pcm)) {
         ALOGE("pcm_open(in) failed: %s: channels %d format %d rate %d",
               pcm_get_error(in->pcm),
@@ -310,25 +314,70 @@
     return 0;
 }
 
-static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
+static double diffTimespec(struct timespec *tend, struct timespec *tstart)
+{
+    return (tend->tv_sec-tstart->tv_sec) +
+           (tend->tv_nsec-tstart->tv_nsec)/1000000000.0;
+}
+
+// Must be called with out->lock held
+static void updateFramesPlayed(struct generic_stream_out *out)
+{
+    struct timespec prev_played_time = out->frames_played_time;
+    clock_gettime(CLOCK_MONOTONIC, &out->frames_played_time);
+    double diffTime = diffTimespec(&out->frames_played_time, &prev_played_time);
+    size_t frames_played = out->pcm_config.rate * diffTime;
+    out->frames_played += frames_played;
+    if (out->frames_played > out->frames_written) {
+        out->frames_played = out->frames_written;
+    }
+}
+
+static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
                          size_t bytes)
 {
     int ret = 0;
     struct generic_stream_out *out = (struct generic_stream_out *)stream;
     pthread_mutex_lock(&out->lock);
+
     if (!out->pcm) {
         ret = start_output_stream(out);
     }
     if (ret == 0) {
         ret = pcm_write(out->pcm, buffer, bytes);
     }
+
+    if (ret == 0) {
+        updateFramesPlayed(out);
+        out->frames_written += bytes/audio_stream_out_frame_size(stream);
+    }
+
     pthread_mutex_unlock(&out->lock);
 
-    if (ret != 0)
-        bytes = 0;
+    if (ret != 0) {
+        bytes = -1;
+    }
     return bytes;
 }
 
+static int out_get_presentation_position(const struct audio_stream_out *stream,
+                                   uint64_t *frames, struct timespec *timestamp)
+
+{
+    struct generic_stream_out *out = (struct generic_stream_out *)stream;
+    int ret = -EINVAL;
+    pthread_mutex_lock(&out->lock);
+    if (out->pcm) {
+        updateFramesPlayed(out);
+        *timestamp = out->frames_played_time;
+        *frames = out->frames_played;
+        ret = 0;
+    }
+    pthread_mutex_unlock(&out->lock);
+
+    return ret;
+}
+
 static int out_get_render_position(const struct audio_stream_out *stream,
                                    uint32_t *dsp_frames)
 {
@@ -366,7 +415,8 @@
 
 static int refine_output_parameters(uint32_t *sample_rate, audio_format_t *format, audio_channel_mask_t *channel_mask)
 {
-    static const uint32_t sample_rates [] = {44100};
+    static const uint32_t sample_rates [] = {8000,11025,16000,22050,24000,32000,
+                                            44100,48000};
     static const int sample_rates_count = sizeof(sample_rates)/sizeof(uint32_t);
     bool inval = false;
     if (*format != AUDIO_FORMAT_PCM_16_BIT) {
@@ -375,7 +425,7 @@
     }
 
     int channel_count = popcount(*channel_mask);
-    if (channel_count != 2) {
+    if (channel_count != 1 && channel_count != 2) {
         *channel_mask = AUDIO_CHANNEL_IN_STEREO;
         inval = true;
     }
@@ -726,6 +776,7 @@
     out->stream.set_volume = out_set_volume;
     out->stream.write = out_write;
     out->stream.get_render_position = out_get_render_position;
+    out->stream.get_presentation_position = out_get_presentation_position;
     out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
 
     out->dev = adev;
@@ -736,6 +787,9 @@
 
     memcpy(&out->pcm_config, &pcm_config_out, sizeof(struct pcm_config));
     out->pcm_config.rate = config->sample_rate;
+    out->frames_played= 0;
+    clock_gettime(CLOCK_MONOTONIC, &out->frames_played_time);
+    out->frames_written = 0;
 
     *stream_out = &out->stream;