From e1eb6c4d68b03eb725b7da6d8832a96e8627b78e Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Tue, 26 May 2015 15:50:29 -0700 Subject: [PATCH] DO NOT MERGE - A2DP audio HAL: implement out_get_presentation_position() And complete implementation of out_get_render_position() Bug: 21199150 Bug: 24042067 Change-Id: I95038ad68433e401b096a0159282a2ae372570e1 --- audio_a2dp_hw/audio_a2dp_hw.c | 47 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/audio_a2dp_hw/audio_a2dp_hw.c b/audio_a2dp_hw/audio_a2dp_hw.c index d0b36a0a9..29803366e 100644 --- a/audio_a2dp_hw/audio_a2dp_hw.c +++ b/audio_a2dp_hw/audio_a2dp_hw.c @@ -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); -- 2.11.0