diff options
Diffstat (limited to 'src/modules/alsa/alsa-sink.c')
-rw-r--r-- | src/modules/alsa/alsa-sink.c | 61 |
1 files changed, 45 insertions, 16 deletions
diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index 042d4df..3fe429c 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -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) { @@ -1654,7 +1667,7 @@ static int sink_set_port_ucm_cb(pa_sink *s, pa_device_port *p) { pa_assert(u->ucm_context); data = PA_DEVICE_PORT_DATA(p); - pa_assert_se(u->mixer_path = data->path); + u->mixer_path = data->path; mixer_volume_init(u); if (s->flags & PA_SINK_DEFERRED_VOLUME) @@ -2138,6 +2151,15 @@ static int setup_mixer(struct userdata *u, bool ignore_dB) { pa_assert(u); + /* This code is before the u->mixer_handle check, because if the UCM + * configuration doesn't specify volume or mute controls, u->mixer_handle + * will be NULL, but the UCM device enable sequence will still need to be + * executed. */ + if (u->sink->active_port && u->ucm_context) { + if (pa_alsa_ucm_set_port(u->ucm_context, u->sink->active_port, true) < 0) + return -1; + } + if (!u->mixer_handle) return 0; @@ -2155,10 +2177,6 @@ static int setup_mixer(struct userdata *u, bool ignore_dB) { } else { pa_alsa_ucm_port_data *data; - /* First activate the port on the UCM side */ - if (pa_alsa_ucm_set_port(u->ucm_context, u->sink->active_port, true) < 0) - return -1; - data = PA_DEVICE_PORT_DATA(u->sink->active_port); /* Now activate volume controls, if any */ @@ -2506,8 +2524,6 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca /* ALSA might tweak the sample spec, so recalculate the frame size */ frame_size = pa_frame_size(&ss); - find_mixer(u, mapping, pa_modargs_get_value(ma, "control", NULL), ignore_dB); - pa_sink_new_data_init(&data); data.driver = driver; data.module = m; @@ -2531,7 +2547,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca pa_sink_new_data_done(&data); goto fail; } - data.avoid_resampling = avoid_resampling; + pa_sink_new_data_set_avoid_resampling(&data, avoid_resampling); pa_sink_new_data_set_sample_spec(&data, &ss); pa_sink_new_data_set_channel_map(&data, &map); @@ -2582,6 +2598,19 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca goto fail; } + if (u->ucm_context) { + pa_device_port *port; + void *state; + unsigned h_prio = 0; + PA_HASHMAP_FOREACH(port, u->sink->ports, state) { + if (!h_prio || port->priority > h_prio) + h_prio = port->priority; + } + /* ucm ports prioriy is 100, 200, ..., 900, change it to units digit */ + h_prio = h_prio / 100; + u->sink->priority += h_prio; + } + if (pa_modargs_get_value_u32(ma, "deferred_volume_safety_margin", &u->sink->thread_info.volume_change_safety_margin) < 0) { pa_log("Failed to parse deferred_volume_safety_margin parameter"); |