audio: improve read/write timing for streams

Change-Id: Ic4231c4b44369a9438c6c94622b90862047e9a32
Reference: 0caeee8ac4
tirimbino
Christopher N. Hesse 8 years ago
parent b7f32128dc
commit e6b3a3eae4
  1. 55
      audio/audio_hw.c
  2. 4
      audio/audio_hw.h

@ -228,7 +228,6 @@ static const char * const use_case_table[AUDIO_USECASE_MAX] = {
[USECASE_VOICE_CALL] = "voice-call",
};
#define STRING_TO_ENUM(string) { #string, string }
static unsigned int audio_device_ref_count;
@ -2556,6 +2555,9 @@ static int out_standby(struct audio_stream *stream)
}
pthread_mutex_unlock(&out->lock);
ALOGV("%s: exit", __func__);
// out->last_write_time_us = 0; unnecessary as a stale write time has same effect
return 0;
}
@ -2917,8 +2919,28 @@ exit:
ALOGE("%s: error %zd - %s", __func__, ret, pcm_get_error(pcm_device->pcm));
}
out_standby(&out->stream.common);
usleep(bytes * 1000000 / audio_stream_out_frame_size(stream) /
out_get_sample_rate(&out->stream.common));
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.
}
#ifdef PREPROCESSING_ENABLED
@ -3171,6 +3193,9 @@ static int do_in_standby_l(struct stream_in *in)
in->standby = 1;
}
in->last_read_time_us = 0;
return 0;
}
@ -3388,8 +3413,28 @@ exit:
if (read_and_process_successful == false) {
in_standby(&in->stream.common);
ALOGV("%s: read failed - sleeping for buffer duration", __func__);
usleep(bytes * 1000000 / audio_stream_in_frame_size(stream) /
in->requested_rate);
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.
}
return bytes;
}

@ -306,6 +306,8 @@ struct stream_out {
#endif
bool is_fastmixer_affinity_set;
int64_t last_write_time_us;
};
struct stream_in {
@ -359,6 +361,8 @@ struct stream_in {
struct audio_device* dev;
bool is_fastcapture_affinity_set;
int64_t last_read_time_us;
};
struct mixer_card {

Loading…
Cancel
Save