diff options
author | Jean-Michel Trivi <jmtrivi@google.com> | 2012-09-11 19:19:08 -0700 |
---|---|---|
committer | Jean-Michel Trivi <jmtrivi@google.com> | 2012-09-13 12:23:43 -0700 |
commit | 6acd966320c7f124f103044f3a152d90d6e38749 (patch) | |
tree | a385aa45a7a1dd674f57b48158f6c3f355ba2392 /modules/audio_remote_submix | |
parent | 5d85c537fcae931428ba8b7a47fdd393cc3cbd88 (diff) | |
download | hardware_libhardware-6acd966320c7f124f103044f3a152d90d6e38749.zip hardware_libhardware-6acd966320c7f124f103044f3a152d90d6e38749.tar.gz hardware_libhardware-6acd966320c7f124f103044f3a152d90d6e38749.tar.bz2 |
Remote submix audio module: sleep less, log errors
Neither write nor read are blocking, but write simulates
timing by checking the clock between two writes and
computing how long the next sleep should last.
Change-Id: I495ae6d44b0cf75a24fe4b70662cfac679049c67
Diffstat (limited to 'modules/audio_remote_submix')
-rw-r--r-- | modules/audio_remote_submix/audio_hw.cpp | 47 |
1 files changed, 34 insertions, 13 deletions
diff --git a/modules/audio_remote_submix/audio_hw.cpp b/modules/audio_remote_submix/audio_hw.cpp index e97a96e..0e5589b 100644 --- a/modules/audio_remote_submix/audio_hw.cpp +++ b/modules/audio_remote_submix/audio_hw.cpp @@ -40,7 +40,7 @@ extern "C" { namespace android { #define MAX_PIPE_DEPTH_IN_FRAMES (1024*4) -#define MAX_READ_ATTEMPTS 10 +#define MAX_READ_ATTEMPTS 3 #define READ_ATTEMPT_SLEEP_MS 10 // 10ms between two read attempts when pipe is empty #define DEFAULT_RATE_HZ 48000 // default sample rate @@ -79,6 +79,8 @@ struct submix_stream_in { struct submix_audio_device *dev; }; +static struct timespec currentTs; + /* audio HAL functions */ @@ -202,8 +204,10 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, if (written == (ssize_t)NEGOTIATE) { ALOGE("out_write() write to pipe returned NEGOTIATE"); written = 0; + return 0; } else { // write() returned UNDERRUN or WOULD_BLOCK, retry + ALOGE("out_write() write to pipe returned unexpected %16lx", written); written = sink->write(buffer, frames); } } @@ -214,17 +218,25 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, pthread_mutex_unlock(&out->dev->lock); - if (written > 0) { - // fake timing for audio output, we can't return right after pushing the data in the pipe - // TODO who's doing the flow control here? the wifi display link, or the audio HAL? - usleep(written * 1000000 / out_get_sample_rate(&stream->common)); - return written * audio_stream_frame_size(&stream->common);; - } else { - // error occurred, fake timing - usleep(frames * 1000000 / out_get_sample_rate(&stream->common)); - ALOGE("out_write error=%16lx", written); - return 0; + struct timespec newTs; + int toSleepUs = 0; + int rc = clock_gettime(CLOCK_MONOTONIC, &newTs); + if (rc == 0) { + time_t sec = newTs.tv_sec - currentTs.tv_sec; + long nsec = newTs.tv_nsec - currentTs.tv_nsec; + if (nsec < 0) { + --sec; + nsec += 1000000000; + } + if ((nsec / 1000) < (frames * 1000000 / out_get_sample_rate(&stream->common))) { + toSleepUs = (frames * 1000000 / out_get_sample_rate(&stream->common)) - (nsec/1000); + ALOGI("sleeping %dus", toSleepUs); + usleep(toSleepUs); + } } + clock_gettime(CLOCK_MONOTONIC, ¤tTs); + //ALOGV("out_write(bytes=%d) written=%d", bytes, written); + return written * audio_stream_frame_size(&stream->common); } static int out_get_render_position(const struct audio_stream_out *stream, @@ -319,6 +331,7 @@ static int in_set_gain(struct audio_stream_in *stream, float gain) static ssize_t in_read(struct audio_stream_in *stream, void* buffer, size_t bytes) { + //ALOGV("in_read bytes=%u", bytes); ssize_t frames_read = -1977; const struct submix_stream_in *in = reinterpret_cast<const struct submix_stream_in *>(stream); const size_t frame_size = audio_stream_frame_size(&stream->common); @@ -337,13 +350,14 @@ static ssize_t in_read(struct audio_stream_in *stream, void* buffer, pthread_mutex_unlock(&in->dev->lock); + int attempts = MAX_READ_ATTEMPTS; size_t remaining_frames = bytes / frame_size; char* buff = (char*)buffer; while (attempts > 0) { frames_read = source->read(buff, remaining_frames, AudioBufferProvider::kInvalidPTS); if (frames_read > 0) { - //ALOGV("in_read frames=%ld size=%u", remaining_frames, frame_size); + //ALOGV(" in_read got frames=%u size=%u attempts=%d", remaining_frames, frame_size, attempts); remaining_frames -= frames_read; buff += frames_read * frame_size; if (remaining_frames == 0) { @@ -359,6 +373,7 @@ static ssize_t in_read(struct audio_stream_in *stream, void* buffer, } } else if (frames_read == 0) { // TODO sleep should be tied to how much data is expected + //ALOGW("sleeping %dms", READ_ATTEMPT_SLEEP_MS); usleep(READ_ATTEMPT_SLEEP_MS*1000); attempts--; } else { // frames_read is an error code @@ -375,11 +390,17 @@ static ssize_t in_read(struct audio_stream_in *stream, void* buffer, pthread_mutex_unlock(&in->dev->lock); - // TODO how to handle partial reads? + if (remaining_frames > 0) { + ALOGW("remaining_frames = %d", remaining_frames); + memset(((char*)buffer)+ bytes - (remaining_frames * frame_size), 0, + remaining_frames * frame_size); + return bytes; + } if (frames_read < 0) { ALOGE("in_read error=%16lx", frames_read); } + ALOGE_IF(attempts == 0, "attempts == 0 "); return 0; } |