OSDN Git Service

DO NOT MERGE - A2DP audio HAL: implement out_get_presentation_position()
authorEric Laurent <elaurent@google.com>
Tue, 26 May 2015 22:50:29 +0000 (15:50 -0700)
committerAndy Hung <hunga@google.com>
Tue, 15 Sep 2015 17:41:44 +0000 (17:41 +0000)
And complete implementation of out_get_render_position()

Bug: 21199150
Bug: 24042067
Change-Id: I95038ad68433e401b096a0159282a2ae372570e1

audio_a2dp_hw/audio_a2dp_hw.c

index d0b36a0..2980336 100644 (file)
@@ -107,6 +107,8 @@ struct a2dp_stream_common {
 struct a2dp_stream_out {
     struct audio_stream_out stream;
     struct a2dp_stream_common common;
+    uint64_t frames_presented; // frames written, never reset
+    uint64_t frames_rendered;  // frames written, reset on standby
 };
 
 struct a2dp_stream_in {
@@ -591,14 +593,17 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
     pthread_mutex_unlock(&out->common.lock);
     sent = skt_write(out->common.audio_fd, buffer,  bytes);
 
-    if (sent == -1)
-    {
+    if (sent == -1) {
         skt_disconnect(out->common.audio_fd);
         out->common.audio_fd = AUDIO_SKT_DISCONNECTED;
         if (out->common.state != AUDIO_A2DP_STATE_SUSPENDED)
             out->common.state = AUDIO_A2DP_STATE_STOPPED;
         else
             ERROR("write failed : stream suspended, avoid resetting state");
+    } else {
+        const size_t frames = bytes / audio_stream_out_frame_size(stream);
+        out->frames_rendered += frames;
+        out->frames_presented += frames;
     }
 
     DEBUG("wrote %d bytes out of %zu bytes", sent, bytes);
@@ -676,6 +681,7 @@ static int out_standby(struct audio_stream *stream)
     // Do nothing in SUSPENDED state.
     if (out->common.state != AUDIO_A2DP_STATE_SUSPENDED)
         retVal = suspend_audio_datapath(&out->common, true);
+    out->frames_rendered = 0; // rendered is reset, presented is not
     pthread_mutex_unlock (&out->common.lock);
 
     return retVal;
@@ -786,16 +792,45 @@ static int out_set_volume(struct audio_stream_out *stream, float left,
     return -ENOSYS;
 }
 
+static int out_get_presentation_position(const struct audio_stream_out *stream,
+                                         uint64_t *frames, struct timespec *timestamp)
+{
+    struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
+
+    FNLOG();
+    if (stream == NULL || frames == NULL || timestamp == NULL)
+        return -EINVAL;
 
+    int ret = -EWOULDBLOCK;
+    pthread_mutex_lock(&out->common.lock);
+    uint64_t latency_frames = (uint64_t)out_get_latency(stream) * out->common.cfg.rate / 1000;
+    if (out->frames_presented >= latency_frames) {
+        *frames = out->frames_presented - latency_frames;
+        clock_gettime(CLOCK_MONOTONIC, timestamp); // could also be associated with out_write().
+        ret = 0;
+    }
+    pthread_mutex_unlock(&out->common.lock);
+    return ret;
+}
 
 static int out_get_render_position(const struct audio_stream_out *stream,
                                    uint32_t *dsp_frames)
 {
-    UNUSED(stream);
-    UNUSED(dsp_frames);
+    struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
 
     FNLOG();
-    return -EINVAL;
+    if (stream == NULL || dsp_frames == NULL)
+        return -EINVAL;
+
+    pthread_mutex_lock(&out->common.lock);
+    uint64_t latency_frames = (uint64_t)out_get_latency(stream) * out->common.cfg.rate / 1000;
+    if (out->frames_rendered >= latency_frames) {
+        *dsp_frames = (uint32_t)(out->frames_rendered - latency_frames);
+    } else {
+        *dsp_frames = 0;
+    }
+    pthread_mutex_unlock(&out->common.lock);
+    return 0;
 }
 
 static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
@@ -1048,6 +1083,8 @@ static int adev_open_output_stream(struct audio_hw_device *dev,
     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;
+
 
     /* initialize a2dp specifics */
     a2dp_stream_common_init(&out->common);