Signed-off-by: David Henningsson <david.henningsson at canonical.com> --- src/modules/alsa/alsa-sink.c | 65 ++++++++++++++++++++++++++++++++++++++++-- src/pulsecore/sink.c | 10 ++++++ src/pulsecore/sink.h | 4 ++ 5 files changed, 80 insertions(+), 7 deletions(-) diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index ea5188c..43a8cde 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -106,6 +106,7 @@ struct userdata { snd_mixer_t *mixer_handle; pa_alsa_path_set *mixer_path_set; pa_alsa_path *mixer_path; + pa_atomic_t mixer_dirty; pa_cvolume hardware_volume; @@ -1210,8 +1211,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_atomic_store(&u->mixer_dirty, 1); return 0; + } if (mask & SND_CTL_EVENT_MASK_VALUE) { pa_sink_get_volume(u->sink, TRUE); @@ -1230,8 +1233,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_atomic_store(&u->mixer_dirty, 1); return 0; + } if (mask & SND_CTL_EVENT_MASK_VALUE) pa_sink_update_volume_and_mute(u->sink); @@ -1454,8 +1459,8 @@ static int sink_set_port_cb(pa_sink *s, pa_device_port *p) { pa_assert(u->mixer_handle); data = PA_DEVICE_PORT_DATA(p); - pa_assert_se(u->mixer_path = data->path); + pa_alsa_path_select(u->mixer_path, u->mixer_handle); mixer_volume_init(u); @@ -1471,6 +1476,59 @@ static int sink_set_port_cb(pa_sink *s, pa_device_port *p) { return 0; } +struct sink_message_set_port { + pa_device_port *port; + int ret; +}; + +static void sink_update_suspend_cause_cb(pa_sink *s) { + struct userdata *u = s->userdata; + pa_assert(u); + + pa_log_debug("mixer_dirty = %d", pa_atomic_load(&u->mixer_dirty)); + + if (s->suspend_cause & PA_SUSPEND_SESSION) + return; + if (pa_atomic_load(&u->mixer_dirty) == 0) + return; + /* This might look racy but isn't: If somebody sets mixer_dirty exactly here, + it'll be handled just fine */ + pa_atomic_store(&u->mixer_dirty, 0); + +/* if (s->get_mute) + s->get_mute(s); + if (s->get_volume) + s->get_volume(s);*/ + pa_log_debug("=== DIWIC === %d", s->flags & PA_SINK_DEFERRED_VOLUME); + + if (s->active_port && s->set_port) { + pa_cvolume old_volume; + pa_bool_t old_mute; + old_volume = *pa_sink_get_volume(s, FALSE); + old_mute = pa_sink_get_mute(s, FALSE); + + 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); + + pa_sink_get_volume(s, TRUE); + pa_sink_get_mute(s, TRUE); + pa_sink_set_volume(s, &old_volume, TRUE, FALSE); + pa_sink_set_mute(s, old_mute, FALSE); + + + } + else { + if (s->set_mute) + s->set_mute(s); + if (s->set_volume) + s->set_volume(s); + } +} + static void sink_update_requested_latency_cb(pa_sink *s) { struct userdata *u = s->userdata; size_t before; @@ -2244,6 +2302,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca u->sink->update_requested_latency = sink_update_requested_latency_cb; u->sink->set_state = sink_set_state_cb; u->sink->set_port = sink_set_port_cb; + u->sink->update_suspend_cause = sink_update_suspend_cause_cb; if (u->sink->alternate_sample_rate) u->sink->update_rate = sink_update_rate_cb; u->sink->userdata = u; diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 2d214cf..f8cac69 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -159,6 +159,7 @@ static void reset_callbacks(pa_sink *s) { s->set_mute = NULL; s->request_rewind = NULL; s->update_requested_latency = NULL; + s->update_suspend_cause = NULL; s->set_port = NULL; s->get_formats = NULL; s->set_formats = NULL; @@ -797,11 +798,14 @@ int pa_sink_update_status(pa_sink*s) { /* Called from main context */ int pa_sink_suspend(pa_sink *s, pa_bool_t suspend, pa_suspend_cause_t cause) { + pa_suspend_cause_t old_cause; pa_sink_assert_ref(s); pa_assert_ctl_context(); pa_assert(PA_SINK_IS_LINKED(s->state)); pa_assert(cause != 0); + old_cause = s->suspend_cause; + if (suspend) { s->suspend_cause |= cause; s->monitor_source->suspend_cause |= cause; @@ -810,6 +814,12 @@ int pa_sink_suspend(pa_sink *s, pa_bool_t suspend, pa_suspend_cause_t cause) { s->monitor_source->suspend_cause &= ~cause; } + if (old_cause == s->suspend_cause) + return 0; + + if (s->update_suspend_cause) + s->update_suspend_cause(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 56fa735..8966854 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -202,6 +202,10 @@ struct pa_sink { * set this callback. */ pa_sink_cb_t set_mute; /* may be NULL */ + /* Called when suspend cause has been updated. Called from main + * context. */ + pa_sink_cb_t update_suspend_cause; /* may be NULL */ + /* Called when a rewind request is issued. Called from IO thread * context. */ pa_sink_cb_t request_rewind; /* may be NULL */ -- 1.7.9.1 --------------070608030201060803040200--