summaryrefslogtreecommitdiff
path: root/src/modules/alsa/alsa-source.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/modules/alsa/alsa-source.c')
-rw-r--r--src/modules/alsa/alsa-source.c69
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");