|
|
|
@ -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; |
|
|
|
|
} |
|
|
|
|