mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-11-03 09:01:50 -05:00
alsa: work around slightly broken _delay implementations
Use snd_pcm_avail_delay() in pa_alsa_safe_delay() so that we can check the delay value against the avail value and patch it up when it looks invalid. Only do this for capture.
This commit is contained in:
parent
74c117f49f
commit
1c29f5582d
4 changed files with 46 additions and 6 deletions
|
|
@ -803,7 +803,7 @@ static void update_smoother(struct userdata *u) {
|
|||
|
||||
/* 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)) < 0)) {
|
||||
if (PA_UNLIKELY((err = pa_alsa_safe_delay(u->pcm_handle, &delay, u->hwbuf_size, &u->sink->sample_spec, FALSE)) < 0)) {
|
||||
pa_log_warn("Failed to query DSP status data: %s", pa_alsa_strerror(err));
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -760,7 +760,7 @@ static void update_smoother(struct userdata *u) {
|
|||
|
||||
/* 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)) < 0)) {
|
||||
if (PA_UNLIKELY((err = pa_alsa_safe_delay(u->pcm_handle, &delay, u->hwbuf_size, &u->source->sample_spec, TRUE)) < 0)) {
|
||||
pa_log_warn("Failed to get delay: %s", pa_alsa_strerror(err));
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1125,10 +1125,11 @@ snd_pcm_sframes_t pa_alsa_safe_avail(snd_pcm_t *pcm, size_t hwbuf_size, const pa
|
|||
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) {
|
||||
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) {
|
||||
ssize_t k;
|
||||
size_t abs_k;
|
||||
int r;
|
||||
snd_pcm_sframes_t avail = 0;
|
||||
|
||||
pa_assert(pcm);
|
||||
pa_assert(delay);
|
||||
|
|
@ -1136,9 +1137,10 @@ int pa_alsa_safe_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delay, size_t hwbuf_si
|
|||
pa_assert(ss);
|
||||
|
||||
/* Some ALSA driver expose weird bugs, let's inform the user about
|
||||
* what is going on */
|
||||
* 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 */
|
||||
|
||||
if ((r = snd_pcm_delay(pcm, delay)) < 0)
|
||||
if ((r = snd_pcm_avail_delay(pcm, &avail, delay)) < 0)
|
||||
return r;
|
||||
|
||||
k = (ssize_t) *delay * (ssize_t) pa_frame_size(ss);
|
||||
|
|
@ -1167,6 +1169,44 @@ int pa_alsa_safe_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delay, size_t hwbuf_si
|
|||
*delay = (snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss));
|
||||
}
|
||||
|
||||
if (capture) {
|
||||
abs_k = (size_t) avail * pa_frame_size(ss);
|
||||
|
||||
if (abs_k >= hwbuf_size * 5 ||
|
||||
abs_k >= pa_bytes_per_second(ss)*10) {
|
||||
|
||||
PA_ONCE_BEGIN {
|
||||
char *dn = pa_alsa_get_driver_name_by_pcm(pcm);
|
||||
pa_log(_("snd_pcm_avail() returned a value that is exceptionally large: %lu bytes (%lu ms).\n"
|
||||
"Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
|
||||
(unsigned long) k,
|
||||
(unsigned long) (pa_bytes_to_usec(k, ss) / PA_USEC_PER_MSEC),
|
||||
pa_strnull(dn));
|
||||
pa_xfree(dn);
|
||||
pa_alsa_dump(PA_LOG_ERROR, pcm);
|
||||
} PA_ONCE_END;
|
||||
|
||||
/* Mhmm, let's try not to fail completely */
|
||||
avail = (snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss));
|
||||
}
|
||||
|
||||
if (*delay < avail) {
|
||||
PA_ONCE_BEGIN {
|
||||
char *dn = pa_alsa_get_driver_name_by_pcm(pcm);
|
||||
pa_log(_("snd_pcm_avail_delay() returned strange values: delay %lu is less than avail %lu.\n"
|
||||
"Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."),
|
||||
(unsigned long) *delay,
|
||||
(unsigned long) avail,
|
||||
pa_strnull(dn));
|
||||
pa_xfree(dn);
|
||||
pa_alsa_dump(PA_LOG_ERROR, pcm);
|
||||
} PA_ONCE_END;
|
||||
|
||||
/* try to fixup */
|
||||
*delay = avail;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -129,7 +129,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);
|
||||
|
||||
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);
|
||||
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_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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue