[pulseaudio-discuss] Unsynchronised ALSA and PA volumes with fast user switching

David Henningsson david.henningsson at canonical.com
Fri Mar 30 19:27:33 PDT 2012

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 

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.

More information about the pulseaudio-discuss mailing list