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
struct submix_audio_device *dev;
};
+static struct timespec currentTs;
+
/* audio HAL functions */
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);
}
}
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,
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);
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) {
}
} 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
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;
}