mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-10-29 05:40:23 -04:00
alsa: make the unsuspend more robust
We met a weird situation on a couple of Lenovo machines and at least on one Dell machine. First we open the gnome-sound-setting, then suspend and resume the system, after the system resume back, the audio devices change to dummy, the audio doesn't work anymore. And pacmd list-cards shows no available sound card. Through debugging I found after resume, the alsa receives POLLERR events and it will call unsuspend to recover the pcm, but at that moment, the device nodes in /dev/snd/ is not accessible, so the snd_pcm_open() fails and the pulseaudio unload the module-alsa-card. Here I add retry and pa_msleep if snd_pcm_open fails, I tested it on all machines which have this problem, pa_msleep(25) is ok for most of them, there is only one machine which needs to call pa_msleep(25) twice, so for safety reason, I set the max retry times to 4. Signed-off-by: Hui Wang <hui.wang@canonical.com>
This commit is contained in:
parent
f12795330b
commit
ede8cbb131
2 changed files with 41 additions and 15 deletions
|
|
@ -1152,7 +1152,7 @@ static void update_size(struct userdata *u, pa_sample_spec *ss) {
|
|||
/* Called from IO context */
|
||||
static int unsuspend(struct userdata *u, bool recovering) {
|
||||
pa_sample_spec ss;
|
||||
int err;
|
||||
int err, i;
|
||||
bool b, d;
|
||||
snd_pcm_uframes_t period_frames, buffer_frames;
|
||||
snd_pcm_uframes_t tsched_frames = 0;
|
||||
|
|
@ -1172,13 +1172,26 @@ static int unsuspend(struct userdata *u, bool recovering) {
|
|||
pa_snprintf(device_name, len, "%s,AES0=6", u->device_name);
|
||||
}
|
||||
|
||||
if ((err = snd_pcm_open(&u->pcm_handle, device_name ? device_name : u->device_name, SND_PCM_STREAM_PLAYBACK,
|
||||
SND_PCM_NONBLOCK|
|
||||
SND_PCM_NO_AUTO_RESAMPLE|
|
||||
SND_PCM_NO_AUTO_CHANNELS|
|
||||
SND_PCM_NO_AUTO_FORMAT)) < 0) {
|
||||
pa_log("Error opening PCM device %s: %s", u->device_name, pa_alsa_strerror(err));
|
||||
goto fail;
|
||||
/*
|
||||
* On some machines, during the system suspend and resume, the thread_func could receive
|
||||
* POLLERR events before the dev nodes in /dev/snd/ are accessible, and thread_func calls
|
||||
* the unsuspend() to try to recover the PCM, this will make the snd_pcm_open() fail, here
|
||||
* we add msleep and retry to make sure those nodes are accessible.
|
||||
*/
|
||||
for (i = 0; i < 4; i++) {
|
||||
if ((err = snd_pcm_open(&u->pcm_handle, device_name ? device_name : u->device_name, SND_PCM_STREAM_PLAYBACK,
|
||||
SND_PCM_NONBLOCK|
|
||||
SND_PCM_NO_AUTO_RESAMPLE|
|
||||
SND_PCM_NO_AUTO_CHANNELS|
|
||||
SND_PCM_NO_AUTO_FORMAT)) < 0 && recovering)
|
||||
pa_msleep(25);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (err < 0) {
|
||||
pa_log("Error opening PCM device %s: %s", u->device_name, pa_alsa_strerror(err));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (pa_frame_size(&u->sink->sample_spec) != u->frame_size) {
|
||||
|
|
|
|||
|
|
@ -1033,7 +1033,7 @@ static void update_size(struct userdata *u, pa_sample_spec *ss) {
|
|||
/* Called from IO context */
|
||||
static int unsuspend(struct userdata *u, bool recovering) {
|
||||
pa_sample_spec ss;
|
||||
int err;
|
||||
int err, i;
|
||||
bool b, d;
|
||||
snd_pcm_uframes_t period_frames, buffer_frames;
|
||||
snd_pcm_uframes_t tsched_frames = 0;
|
||||
|
|
@ -1044,12 +1044,25 @@ static int unsuspend(struct userdata *u, bool recovering) {
|
|||
|
||||
pa_log_info("Trying resume...");
|
||||
|
||||
if ((err = snd_pcm_open(&u->pcm_handle, u->device_name, SND_PCM_STREAM_CAPTURE,
|
||||
SND_PCM_NONBLOCK|
|
||||
SND_PCM_NO_AUTO_RESAMPLE|
|
||||
SND_PCM_NO_AUTO_CHANNELS|
|
||||
SND_PCM_NO_AUTO_FORMAT)) < 0) {
|
||||
pa_log("Error opening PCM device %s: %s", u->device_name, pa_alsa_strerror(err));
|
||||
/*
|
||||
* On some machines, during the system suspend and resume, the thread_func could receive
|
||||
* POLLERR events before the dev nodes in /dev/snd/ are accessible, and thread_func calls
|
||||
* the unsuspend() to try to recover the PCM, this will make the snd_pcm_open() fail, here
|
||||
* we add msleep and retry to make sure those nodes are accessible.
|
||||
*/
|
||||
for (i = 0; i < 4; i++) {
|
||||
if ((err = snd_pcm_open(&u->pcm_handle, u->device_name, SND_PCM_STREAM_CAPTURE,
|
||||
SND_PCM_NONBLOCK|
|
||||
SND_PCM_NO_AUTO_RESAMPLE|
|
||||
SND_PCM_NO_AUTO_CHANNELS|
|
||||
SND_PCM_NO_AUTO_FORMAT)) < 0 && recovering)
|
||||
pa_msleep(25);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (err < 0) {
|
||||
pa_log("Error opening PCM device %s: %s", u->device_name, pa_alsa_strerror(err));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue