audio: hal: Fix CTS test failure with no hardware output
am: dc71a44c07
Change-Id: Icc158ec19944adcec0af005e4348401078377636
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 71aecb3..19b8fbe 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -2203,14 +2203,30 @@
const void *buffer, size_t bytes)
{
struct stream_out *out = (struct stream_out *)stream;
-
- /* No Output device supported other than BT for playback.
- * Sleep for the amount of buffer duration
- */
+ struct timespec t = { .tv_sec = 0, .tv_nsec = 0 };
+ clock_gettime(CLOCK_MONOTONIC, &t);
+ const int64_t now = (t.tv_sec * 1000000000LL + t.tv_nsec) / 1000;
lock_output_stream(out);
- usleep(bytes * 1000000 / audio_stream_out_frame_size(&out->stream.common) /
- out_get_sample_rate(&out->stream.common));
+ const int64_t elapsed_time_since_last_write = now - out->last_write_time_us;
+ int64_t sleep_time = bytes * 1000000LL / audio_stream_out_frame_size(stream) /
+ out_get_sample_rate(&stream->common) - elapsed_time_since_last_write;
+ if (sleep_time > 0) {
+ usleep(sleep_time);
+ } else {
+ // we don't sleep when we exit standby (this is typical for a real alsa buffer).
+ sleep_time = 0;
+ }
+ out->last_write_time_us = now + sleep_time;
pthread_mutex_unlock(&out->lock);
+ // last_write_time_us is an approximation of when the (simulated) alsa
+ // buffer is believed completely full. The usleep above waits for more space
+ // in the buffer, but by the end of the sleep the buffer is considered
+ // topped-off.
+ //
+ // On the subsequent out_write(), we measure the elapsed time spent in
+ // the mixer. This is subtracted from the sleep estimate based on frames,
+ // thereby accounting for drain in the alsa buffer during mixing.
+ // This is a crude approximation; we don't handle underruns precisely.
return bytes;
}
#endif
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 798d954..2cf72e1 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -210,6 +210,8 @@
card_status_t card_status;
struct error_log error_log;
+
+ int64_t last_write_time_us;
};
struct stream_in {