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]) {