summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/modules/alsa/alsa-sink.c8
-rw-r--r--src/modules/alsa/alsa-source.c8
-rw-r--r--src/pulsecore/sink.c28
-rw-r--r--src/pulsecore/sink.h2
-rw-r--r--src/pulsecore/source.c28
-rw-r--r--src/pulsecore/source.h3
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 */