summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Hung <hunga@google.com>2015-09-22 18:26:32 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2015-09-22 18:26:32 +0000
commit282091913b4ee3b26a2f79a630ecdca4e8ca89f6 (patch)
tree6bf4df6c4bfc7b84916633554a0e8a0ecb50a872
parent81d4127c5bd2c0bd2ac50a1a7a9f24ad8148434d (diff)
parente1eb6c4d68b03eb725b7da6d8832a96e8627b78e (diff)
downloadandroid_system_bt-282091913b4ee3b26a2f79a630ecdca4e8ca89f6.tar.gz
android_system_bt-282091913b4ee3b26a2f79a630ecdca4e8ca89f6.tar.bz2
android_system_bt-282091913b4ee3b26a2f79a630ecdca4e8ca89f6.zip
Merge "DO NOT MERGE - A2DP audio HAL: implement out_get_presentation_position()" into mnc-dr-dev
-rw-r--r--audio_a2dp_hw/audio_a2dp_hw.c47
1 files 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);