alsa: get avail, delay, timestamps in a single kernel call

Refactor code to fetch avail, delay and timestamp values
in a single call to snd_pcm_status().
The information reported is exactly the same as before,
however it is extracted in a more atomic manner to
improve timer-based scheduling.

Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
This commit is contained in:
Pierre-Louis Bossart 2012-07-29 19:46:59 -05:00 committed by David Henningsson
parent 700cd890a9
commit 635eef9981
4 changed files with 21 additions and 22 deletions

View file

@ -825,6 +825,7 @@ static void update_smoother(struct userdata *u) {
int err; int err;
pa_usec_t now1 = 0, now2; pa_usec_t now1 = 0, now2;
snd_pcm_status_t *status; snd_pcm_status_t *status;
snd_htimestamp_t htstamp = { 0, 0 };
snd_pcm_status_alloca(&status); snd_pcm_status_alloca(&status);
@ -833,18 +834,13 @@ static void update_smoother(struct userdata *u) {
/* Let's update the time smoother */ /* Let's update the time smoother */
if (PA_UNLIKELY((err = pa_alsa_safe_delay(u->pcm_handle, &delay, u->hwbuf_size, &u->sink->sample_spec, FALSE)) < 0)) { if (PA_UNLIKELY((err = pa_alsa_safe_delay(u->pcm_handle, status, &delay, u->hwbuf_size, &u->sink->sample_spec, FALSE)) < 0)) {
pa_log_warn("Failed to query DSP status data: %s", pa_alsa_strerror(err)); pa_log_warn("Failed to query DSP status data: %s", pa_alsa_strerror(err));
return; return;
} }
if (PA_UNLIKELY((err = snd_pcm_status(u->pcm_handle, status)) < 0)) snd_pcm_status_get_htstamp(status, &htstamp);
pa_log_warn("Failed to get timestamp: %s", pa_alsa_strerror(err)); now1 = pa_timespec_load(&htstamp);
else {
snd_htimestamp_t htstamp = { 0, 0 };
snd_pcm_status_get_htstamp(status, &htstamp);
now1 = pa_timespec_load(&htstamp);
}
/* Hmm, if the timestamp is 0, then it wasn't set and we take the current time */ /* Hmm, if the timestamp is 0, then it wasn't set and we take the current time */
if (now1 <= 0) if (now1 <= 0)

View file

@ -767,6 +767,7 @@ static void update_smoother(struct userdata *u) {
int err; int err;
pa_usec_t now1 = 0, now2; pa_usec_t now1 = 0, now2;
snd_pcm_status_t *status; snd_pcm_status_t *status;
snd_htimestamp_t htstamp = { 0, 0 };
snd_pcm_status_alloca(&status); snd_pcm_status_alloca(&status);
@ -775,18 +776,13 @@ static void update_smoother(struct userdata *u) {
/* Let's update the time smoother */ /* Let's update the time smoother */
if (PA_UNLIKELY((err = pa_alsa_safe_delay(u->pcm_handle, &delay, u->hwbuf_size, &u->source->sample_spec, TRUE)) < 0)) { if (PA_UNLIKELY((err = pa_alsa_safe_delay(u->pcm_handle, status, &delay, u->hwbuf_size, &u->source->sample_spec, TRUE)) < 0)) {
pa_log_warn("Failed to get delay: %s", pa_alsa_strerror(err)); pa_log_warn("Failed to get delay: %s", pa_alsa_strerror(err));
return; return;
} }
if (PA_UNLIKELY((err = snd_pcm_status(u->pcm_handle, status)) < 0)) snd_pcm_status_get_htstamp(status, &htstamp);
pa_log_warn("Failed to get timestamp: %s", pa_alsa_strerror(err)); now1 = pa_timespec_load(&htstamp);
else {
snd_htimestamp_t htstamp = { 0, 0 };
snd_pcm_status_get_htstamp(status, &htstamp);
now1 = pa_timespec_load(&htstamp);
}
/* Hmm, if the timestamp is 0, then it wasn't set and we take the current time */ /* Hmm, if the timestamp is 0, then it wasn't set and we take the current time */
if (now1 <= 0) if (now1 <= 0)

View file

@ -1141,10 +1141,11 @@ snd_pcm_sframes_t pa_alsa_safe_avail(snd_pcm_t *pcm, size_t hwbuf_size, const pa
return n; return n;
} }
int pa_alsa_safe_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delay, size_t hwbuf_size, const pa_sample_spec *ss, pa_bool_t capture) { int pa_alsa_safe_delay(snd_pcm_t *pcm, snd_pcm_status_t *status, snd_pcm_sframes_t *delay, size_t hwbuf_size, const pa_sample_spec *ss,
pa_bool_t capture) {
ssize_t k; ssize_t k;
size_t abs_k; size_t abs_k;
int r; int err;
snd_pcm_sframes_t avail = 0; snd_pcm_sframes_t avail = 0;
pa_assert(pcm); pa_assert(pcm);
@ -1154,10 +1155,16 @@ int pa_alsa_safe_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delay, size_t hwbuf_si
/* Some ALSA driver expose weird bugs, let's inform the user about /* Some ALSA driver expose weird bugs, let's inform the user about
* what is going on. We're going to get both the avail and delay values so * what is going on. We're going to get both the avail and delay values so
* that we can compare and check them for capture */ * that we can compare and check them for capture.
* This is done with snd_pcm_status() which provides
* avail, delay and timestamp values in a single kernel call to improve
* timer-based scheduling */
if ((r = snd_pcm_avail_delay(pcm, &avail, delay)) < 0) if ((err = snd_pcm_status(pcm, status)) < 0)
return r; return err;
avail = snd_pcm_status_get_avail(status);
*delay = snd_pcm_status_get_delay(status);
k = (ssize_t) *delay * (ssize_t) pa_frame_size(ss); k = (ssize_t) *delay * (ssize_t) pa_frame_size(ss);

View file

@ -125,7 +125,7 @@ int pa_alsa_recover_from_poll(snd_pcm_t *pcm, int revents);
pa_rtpoll_item* pa_alsa_build_pollfd(snd_pcm_t *pcm, pa_rtpoll *rtpoll); pa_rtpoll_item* pa_alsa_build_pollfd(snd_pcm_t *pcm, pa_rtpoll *rtpoll);
snd_pcm_sframes_t pa_alsa_safe_avail(snd_pcm_t *pcm, size_t hwbuf_size, const pa_sample_spec *ss); snd_pcm_sframes_t pa_alsa_safe_avail(snd_pcm_t *pcm, size_t hwbuf_size, const pa_sample_spec *ss);
int pa_alsa_safe_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delay, size_t hwbuf_size, const pa_sample_spec *ss, pa_bool_t capture); int pa_alsa_safe_delay(snd_pcm_t *pcm, snd_pcm_status_t *status, snd_pcm_sframes_t *delay, size_t hwbuf_size, const pa_sample_spec *ss, pa_bool_t capture);
int pa_alsa_safe_mmap_begin(snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas, snd_pcm_uframes_t *offset, snd_pcm_uframes_t *frames, size_t hwbuf_size, const pa_sample_spec *ss); int pa_alsa_safe_mmap_begin(snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas, snd_pcm_uframes_t *offset, snd_pcm_uframes_t *frames, size_t hwbuf_size, const pa_sample_spec *ss);
char *pa_alsa_get_driver_name(int card); char *pa_alsa_get_driver_name(int card);