diff options
Diffstat (limited to 'src/modules/alsa/alsa-source.c')
-rw-r--r-- | src/modules/alsa/alsa-source.c | 69 |
1 files changed, 51 insertions, 18 deletions
diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c index 104de4e..b1149c6 100644 --- a/src/modules/alsa/alsa-source.c +++ b/src/modules/alsa/alsa-source.c @@ -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; } @@ -1525,7 +1538,7 @@ static int source_set_port_ucm_cb(pa_source *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_SOURCE_DEFERRED_VOLUME) @@ -1844,6 +1857,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->source->active_port && u->ucm_context) { + if (pa_alsa_ucm_set_port(u->ucm_context, u->source->active_port, false) < 0) + return -1; + } + if (!u->mixer_handle) return 0; @@ -1861,10 +1883,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->source->active_port, false) < 0) - return -1; - data = PA_DEVICE_PORT_DATA(u->source->active_port); /* Now activate volume controls, if any */ @@ -2193,8 +2211,6 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p /* 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_source_new_data_init(&data); data.driver = driver; data.module = m; @@ -2218,7 +2234,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p pa_source_new_data_done(&data); goto fail; } - data.avoid_resampling = avoid_resampling; + pa_source_new_data_set_avoid_resampling(&data, avoid_resampling); pa_source_new_data_set_sample_spec(&data, &ss); pa_source_new_data_set_channel_map(&data, &map); @@ -2249,10 +2265,14 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p goto fail; } - if (u->ucm_context) + if (u->ucm_context) { pa_alsa_ucm_add_ports(&data.ports, data.proplist, u->ucm_context, false, card, u->pcm_handle, ignore_dB); - else if (u->mixer_path_set) - pa_alsa_add_ports(&data, u->mixer_path_set, card); + find_mixer(u, mapping, pa_modargs_get_value(ma, "control", NULL), ignore_dB); + } else { + find_mixer(u, mapping, pa_modargs_get_value(ma, "control", NULL), ignore_dB); + if (u->mixer_path_set) + pa_alsa_add_ports(&data, u->mixer_path_set, card); + } u->source = pa_source_new(m->core, &data, PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY|(u->use_tsched ? PA_SOURCE_DYNAMIC_LATENCY : 0)); volume_is_set = data.volume_is_set; @@ -2264,6 +2284,19 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p goto fail; } + if (u->ucm_context) { + pa_device_port *port; + void *state; + unsigned h_prio = 0; + PA_HASHMAP_FOREACH(port, u->source->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->source->priority += h_prio; + } + if (pa_modargs_get_value_u32(ma, "deferred_volume_safety_margin", &u->source->thread_info.volume_change_safety_margin) < 0) { pa_log("Failed to parse deferred_volume_safety_margin parameter"); |