On 03/30/2012 08:03 PM, Tanu Kaskinen wrote: > On Fri, 2012-03-30 at 17:22 +0200, David Henningsson wrote: >> 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 > > What does this mean? What code is reading what 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. > > Disclaimer: I'm answering quickly without looking at the code, and I > don't know why you need the juggling with the volume. I'm trying to > think what "should" be happen. > > When switching to B, A should notice that and tear down the current > port. I think that mainly means releasing the device, and I guess this > part is working fine. When A gets active again, the port should be > reactivated. Therefore, the "call set_port" step of your ugly hack is > not a hack, it's what should be done. As part of initializing the port, > volume and mute should be set. What's the problem here? Does the port > setting code assume that if the pa_sink.reference_volume hasn't changed, > the hardware volume doesn't need to be set? If so, then that assumption > needs to be removed. When activating a port, the hardware volume should > always be set (or alternatively the current volume should be read from > the hardware, and then set if needed). Thanks for your thoughts. I think I agree, but there's something fishy here. I think it has to do with that the "get_volume" calls are meant for the situation where something has changed on the ALSA side, and then needs to be propagated in the reverse direction. So there might be some (un)wanted side effects of getting the volume. First, there is a "if (s->active_port == port) return;" in pa_sink_set_port that we need to work around somehow. Or avoid calling pa_sink_set_port but instead call something that pa_sink_set_port calls instead. Second, when deferred volumes are active, and they usually are, writing a volume from the main thread does not actually set the volume, but sends a message to put the volume in a queue to be set later. Maybe something is cancelled out somewhere along that chain? Not sure. And getting the volume while something is in that queue empties the queue without first writing anything, which also seems strange to me. (Maybe pa_sink_volume_change_flush should actually write something and not just empty the queue?) I'm also trying to make sense out of why one would call pa_alsa_path_set_volume and element_set_volume, when write_to_hw is false. Probably it has to do something with calculating the soft volume, but the hardware_volume variable is set in both cases, is that also correct? Also, it looks to me like the same mixer handle is being used by both the main thread and the I/O thread without any locking here? (Or is this just a side track?) I guess I just need to debug this thing even more to figure out what's actually going on here...but it's not trivial, I must admit. This stuff needs some serious refactoring. :-/ -- David Henningsson, Canonical Ltd. http://launchpad.net/~diwic