diff options
-rw-r--r-- | src/modules/alsa/alsa-sink.c | 8 | ||||
-rw-r--r-- | src/modules/alsa/alsa-source.c | 8 | ||||
-rw-r--r-- | src/pulsecore/sink.c | 28 | ||||
-rw-r--r-- | src/pulsecore/sink.h | 2 | ||||
-rw-r--r-- | src/pulsecore/source.c | 28 | ||||
-rw-r--r-- | src/pulsecore/source.h | 3 |
6 files changed, 73 insertions, 4 deletions
diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index 65f12c21..c3d18e39 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -1210,8 +1210,10 @@ static int ctl_mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) { if (!PA_SINK_IS_LINKED(u->sink->state)) return 0; - if (u->sink->suspend_cause & PA_SUSPEND_SESSION) + if (u->sink->suspend_cause & PA_SUSPEND_SESSION) { + pa_sink_set_mixer_dirty(u->sink, TRUE); return 0; + } if (mask & SND_CTL_EVENT_MASK_VALUE) { pa_sink_get_volume(u->sink, TRUE); @@ -1230,8 +1232,10 @@ static int io_mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) { if (mask == SND_CTL_EVENT_MASK_REMOVE) return 0; - if (u->sink->suspend_cause & PA_SUSPEND_SESSION) + if (u->sink->suspend_cause & PA_SUSPEND_SESSION) { + pa_sink_set_mixer_dirty(u->sink, TRUE); return 0; + } if (mask & SND_CTL_EVENT_MASK_VALUE) pa_sink_update_volume_and_mute(u->sink); diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c index ab7335d8..97092bb5 100644 --- a/src/modules/alsa/alsa-source.c +++ b/src/modules/alsa/alsa-source.c @@ -1113,8 +1113,10 @@ static int ctl_mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) { if (!PA_SOURCE_IS_LINKED(u->source->state)) return 0; - if (u->source->suspend_cause & PA_SUSPEND_SESSION) + if (u->source->suspend_cause & PA_SUSPEND_SESSION) { + pa_source_set_mixer_dirty(u->source, TRUE); return 0; + } if (mask & SND_CTL_EVENT_MASK_VALUE) { pa_source_get_volume(u->source, TRUE); @@ -1133,8 +1135,10 @@ static int io_mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) { if (mask == SND_CTL_EVENT_MASK_REMOVE) return 0; - if (u->source->suspend_cause & PA_SUSPEND_SESSION) + if (u->source->suspend_cause & PA_SUSPEND_SESSION) { + pa_source_set_mixer_dirty(u->source, TRUE); return 0; + } if (mask & SND_CTL_EVENT_MASK_VALUE) pa_source_update_volume_and_mute(u->source); diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 2d214cf0..e4c343da 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -248,6 +248,7 @@ pa_sink* pa_sink_new( s->flags = flags; s->priority = 0; s->suspend_cause = 0; + pa_sink_set_mixer_dirty(s, FALSE); s->name = pa_xstrdup(name); s->proplist = pa_proplist_copy(data->proplist); s->driver = pa_xstrdup(pa_path_get_filename(data->driver)); @@ -795,6 +796,12 @@ int pa_sink_update_status(pa_sink*s) { return sink_set_state(s, pa_sink_used_by(s) ? PA_SINK_RUNNING : PA_SINK_IDLE); } +/* Called from any context - must be threadsafe */ +void pa_sink_set_mixer_dirty(pa_sink *s, pa_bool_t is_dirty) +{ + pa_atomic_store(&s->mixer_dirty, is_dirty ? 1 : 0); +} + /* Called from main context */ int pa_sink_suspend(pa_sink *s, pa_bool_t suspend, pa_suspend_cause_t cause) { pa_sink_assert_ref(s); @@ -810,6 +817,27 @@ int pa_sink_suspend(pa_sink *s, pa_bool_t suspend, pa_suspend_cause_t cause) { s->monitor_source->suspend_cause &= ~cause; } + if (!(s->suspend_cause & PA_SUSPEND_SESSION) && (pa_atomic_load(&s->mixer_dirty) != 0)) { + /* This might look racy but isn't: If somebody sets mixer_dirty exactly here, + it'll be handled just fine. */ + pa_sink_set_mixer_dirty(s, FALSE); + pa_log_debug("Mixer is now accessible. Updating alsa mixer settings."); + if (s->active_port && s->set_port) { + if (s->flags & PA_SINK_DEFERRED_VOLUME) { + struct sink_message_set_port msg = { .port = s->active_port, .ret = 0 }; + pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_PORT, &msg, 0, NULL) == 0); + } + else + s->set_port(s, s->active_port); + } + else { + if (s->set_mute) + s->set_mute(s); + if (s->set_volume) + s->set_volume(s); + } + } + if ((pa_sink_get_state(s) == PA_SINK_SUSPENDED) == !!s->suspend_cause) return 0; diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index 56fa735a..9bc80475 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -111,6 +111,7 @@ struct pa_sink { pa_hashmap *ports; pa_device_port *active_port; + pa_atomic_t mixer_dirty; unsigned priority; @@ -438,6 +439,7 @@ pa_bool_t pa_sink_get_mute(pa_sink *sink, pa_bool_t force_refresh); pa_bool_t pa_sink_update_proplist(pa_sink *s, pa_update_mode_t mode, pa_proplist *p); int pa_sink_set_port(pa_sink *s, const char *name, pa_bool_t save); +void pa_sink_set_mixer_dirty(pa_sink *s, pa_bool_t is_dirty); unsigned pa_sink_linked_by(pa_sink *s); /* Number of connected streams */ unsigned pa_sink_used_by(pa_sink *s); /* Number of connected streams which are not corked */ diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index a5d5af0b..6308f54d 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -235,6 +235,7 @@ pa_source* pa_source_new( s->flags = flags; s->priority = 0; s->suspend_cause = 0; + pa_source_set_mixer_dirty(s, FALSE); s->name = pa_xstrdup(name); s->proplist = pa_proplist_copy(data->proplist); s->driver = pa_xstrdup(pa_path_get_filename(data->driver)); @@ -713,6 +714,12 @@ int pa_source_update_status(pa_source*s) { return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE); } +/* Called from any context - must be threadsafe */ +void pa_source_set_mixer_dirty(pa_source *s, pa_bool_t is_dirty) +{ + pa_atomic_store(&s->mixer_dirty, is_dirty ? 1 : 0); +} + /* Called from main context */ int pa_source_suspend(pa_source *s, pa_bool_t suspend, pa_suspend_cause_t cause) { pa_source_assert_ref(s); @@ -728,6 +735,27 @@ int pa_source_suspend(pa_source *s, pa_bool_t suspend, pa_suspend_cause_t cause) else s->suspend_cause &= ~cause; + if (!(s->suspend_cause & PA_SUSPEND_SESSION) && (pa_atomic_load(&s->mixer_dirty) != 0)) { + /* This might look racy but isn't: If somebody sets mixer_dirty exactly here, + it'll be handled just fine. */ + pa_source_set_mixer_dirty(s, FALSE); + pa_log_debug("Mixer is now accessible. Updating alsa mixer settings."); + if (s->active_port && s->set_port) { + if (s->flags & PA_SOURCE_DEFERRED_VOLUME) { + struct source_message_set_port msg = { .port = s->active_port, .ret = 0 }; + pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_PORT, &msg, 0, NULL) == 0); + } + else + s->set_port(s, s->active_port); + } + else { + if (s->set_mute) + s->set_mute(s); + if (s->set_volume) + s->set_volume(s); + } + } + if ((pa_source_get_state(s) == PA_SOURCE_SUSPENDED) == !!s->suspend_cause) return 0; diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h index e6f7028f..d81782aa 100644 --- a/src/pulsecore/source.h +++ b/src/pulsecore/source.h @@ -111,6 +111,7 @@ struct pa_source { pa_hashmap *ports; pa_device_port *active_port; + pa_atomic_t mixer_dirty; unsigned priority; @@ -368,6 +369,8 @@ pa_bool_t pa_source_get_mute(pa_source *source, pa_bool_t force_refresh); pa_bool_t pa_source_update_proplist(pa_source *s, pa_update_mode_t mode, pa_proplist *p); int pa_source_set_port(pa_source *s, const char *name, pa_bool_t save); +void pa_source_set_mixer_dirty(pa_source *s, pa_bool_t is_dirty); + pa_bool_t pa_source_update_rate(pa_source *s, uint32_t rate, pa_bool_t passthrough); unsigned pa_source_linked_by(pa_source *s); /* Number of connected streams */ |