audio: hal: Fix CTS test failure with no hardware output

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.

Note that this is copied from the stub hal.

Bug: 33764682
Change-Id: I3f3b825ede8f98b92b09ac76be3835c54bd7188f
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 {