diff options
author | Andy Hung <hunga@google.com> | 2016-07-15 05:06:15 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2016-07-15 05:06:15 +0000 |
commit | 4d2023e33a1ad24581ad68f63e1702590ec04bee (patch) | |
tree | 43f41b0c367fb81cb31404978afd897e73850d01 | |
parent | e87229e26761e9adc3966fa52de25df3c2f77d13 (diff) | |
parent | 0caeee8ac429dd8098e97b2cd8ad3751031a5b67 (diff) | |
download | libhardware-4d2023e33a1ad24581ad68f63e1702590ec04bee.tar.gz |
Merge "Improve stub hal read and write timing" into nyc-mr1-dev
-rw-r--r-- | modules/audio/audio_hw.c | 58 |
1 files changed, 53 insertions, 5 deletions
diff --git a/modules/audio/audio_hw.c b/modules/audio/audio_hw.c index a1a322ff..68b0d3a1 100644 --- a/modules/audio/audio_hw.c +++ b/modules/audio/audio_hw.c @@ -35,10 +35,12 @@ struct stub_audio_device { struct stub_stream_out { struct audio_stream_out stream; + int64_t last_write_time_us; }; struct stub_stream_in { struct audio_stream_in stream; + int64_t last_read_time_us; }; static uint32_t out_get_sample_rate(const struct audio_stream *stream) @@ -79,7 +81,7 @@ static int out_set_format(struct audio_stream *stream, audio_format_t format) static int out_standby(struct audio_stream *stream) { ALOGV("out_standby"); - + // out->last_write_time_us = 0; unnecessary as a stale write time has same effect return 0; } @@ -118,9 +120,31 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, size_t bytes) { ALOGV("out_write: bytes: %d", bytes); + /* XXX: fake timing for audio output */ - usleep((int64_t)bytes * 1000000 / audio_stream_out_frame_size(stream) / - out_get_sample_rate(&stream->common)); + struct stub_stream_out *out = (struct stub_stream_out *)stream; + 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; + 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; + // 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; } @@ -189,6 +213,8 @@ static int in_set_format(struct audio_stream *stream, audio_format_t format) static int in_standby(struct audio_stream *stream) { + struct stub_stream_in *in = (struct stub_stream_in *)stream; + in->last_read_time_us = 0; return 0; } @@ -217,9 +243,31 @@ static ssize_t in_read(struct audio_stream_in *stream, void* buffer, size_t bytes) { ALOGV("in_read: bytes %d", bytes); + /* XXX: fake timing for audio input */ - usleep((int64_t)bytes * 1000000 / audio_stream_in_frame_size(stream) / - in_get_sample_rate(&stream->common)); + struct stub_stream_in *in = (struct stub_stream_in *)stream; + 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; + + // we do a full sleep when exiting standby. + const bool standby = in->last_read_time_us == 0; + const int64_t elapsed_time_since_last_read = standby ? + 0 : now - in->last_read_time_us; + int64_t sleep_time = bytes * 1000000LL / audio_stream_in_frame_size(stream) / + in_get_sample_rate(&stream->common) - elapsed_time_since_last_read; + if (sleep_time > 0) { + usleep(sleep_time); + } else { + sleep_time = 0; + } + in->last_read_time_us = now + sleep_time; + // last_read_time_us is an approximation of when the (simulated) alsa + // buffer is drained by the read, and is empty. + // + // On the subsequent in_read(), we measure the elapsed time spent in + // the recording thread. This is subtracted from the sleep estimate based on frames, + // thereby accounting for fill in the alsa buffer during the interim. memset(buffer, 0, bytes); return bytes; } |