Steps to reproduce:
Log in as user A.
Fast user switch to user B.
Let user B change port / volume / mute.
Fast user switch back to user A.
At this point ALSA and PA volumes are unsynchronised, ALSA is still at
B's volume, whereas PA thinks it has A's volume.
I'm trying to make PA set ALSA to A's volume when A comes back, but the
best I can come up with is an ugly hack: to
1) read the old volume
2) call set_port
3) read the volume again and discard the result (!)
4) set the old volume
It seems difficult just to "invalidate" the remembered ALSA
port/volume/mute and set it again, but I might very well be missing
something (all these volumes are a bit mind-boggling).
Ideas welcome.
--
David Henningsson, Canonical Ltd.
http://launchpad.net/~diwic
>From a0c3724acf66b9385c62b763716a97ca45ce01f3 Mon Sep 17 00:00:00 2001
From: David Henningsson <[email protected]>
Date: Fri, 30 Mar 2012 17:10:11 +0200
Subject: [PATCH] Hack
Signed-off-by: David Henningsson <[email protected]>
---
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
_______________________________________________
pulseaudio-discuss mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss