[pulseaudio-discuss] RFC: New volume functionality for PulseAudio

Tanu Kaskinen tanu.kaskinen at linux.intel.com
Sun Feb 16 12:03:26 CET 2014

On Sat, 2014-02-15 at 10:08 +0100, David Henningsson wrote:
> On 02/14/2014 01:51 PM, Tanu Kaskinen wrote:
> > On Fri, 2014-02-14 at 11:55 +0100, David Henningsson wrote:
> >> I don't understand this argument. A mute control *is* a volume control
> >> (with two distinct values).
> > 
> > That doesn't change the fact that the volume and mute controls should be
> > separate: I don't want to bundle two volume controls together either.
> > 
> > However, I'd be ok with adding a possibly-NULL reference from a volume
> > control object to a mute control object and vice versa. There are other
> > ways to correlate a volume control with a mute control, but direct
> > reference would definitely make it easier.
> Mute controls and volume controls should be the same type of objects.
> They will share a lot of logic internally and it would lead to a lot of
> copy-pasting if they were two different kind of objects.
> I'd prefer if they also were the same object, because I think that would
> make it simpler for volume control UIs instead of having to follow links
> between objects.

Let's discuss first whether volume and mute should be bundled in the
same object. Bundling them together limits the flexibility: you can't
cleanly represent entities (e.g. devices) that have only volume or mute
control, and you can't represent a situation where a stream's volume and
mute follow different grouping rules. For example, it doesn't sound
insane to me that someone would want to enable volume grouping and
restoring in module-stream-restore, but disable grouping and restoring
the stream mute status.

By the way, I take back the suggestion of adding a pointer from a volume
control to a mute control and vice versa. Routing is another kind of
control that UIs may want to show grouped with the volume and mute, and
I don't want to add mutual pointers between each of volume, mute and
routing controls. There could be even more "groupable" control types in
the future (I'm thinking of any kind of processing, like equalizer), and
this approach of adding mutual references between every control type
makes the number of references grow exponentially.

UIs can easily do the grouping without these extra references, because
the UI probably anyway gets first a list of e.g. streams and then shows
the controls for those streams. The stream object will have references
to the volume control and the mute control (and maybe in the future,
references also to the routing node, equalizer control etc.).

> >> The concept "volume class" does not exist in module-stream-restore, at
> >> least not with that name.
> >>
> >> Could you give a clear definition of what "volume classes" are? If it's
> >> just a way of grouping volume control objects, then volume control
> >> objects could just have some property of what class they belong to.
> > 
> > An attempt at a definition: a volume class is a named set of rules for
> > grouping volumes.
> > 
> > "A way of grouping volume control objects" is not an entirely accurate
> > description. You probably were thinking of a setup where each stream has
> > a volume control object, and those are somehow grouped by a volume
> > class. In my proposal streams whose volume is governed by the volume
> > class do not have their own volume control objects. Instead, the streams
> > reference the volume control object of the volume class.
> > 
> > This is not a very important distinction, however, because your
> > suggestion of using a property works either way. You could set a
> > "volume_class = event" property on a volume control to tell clients that
> > this volume control object controls the volume of event sounds.
> I'm still confused.
>  * Is there a 1:1 relation between volume control objects and volume
> classes? If so we don't need an additional object, they can just be the
> same object.

No, there are volume control objects that aren't part of any class.
Device volumes very rarely are part of any volume class.

>  * Or can several volume control objects belong to the same class? If so
> "the volume control object of the volume class" does not make sense
> because there can be many.

Not simultaneously. Think about this: you write a UI for controlling the
event sound volume class. If there are two volume control objects for
the same class, I suppose you could show two volume sliders for the
user, but the user is going to be very confused.

The volume control object that is associated with a volume class can
change during runtime, however. On the N9, there were two volume classes
(a bit simplified): "call" and "everything else". When audio was routed
to the integrated speakers, the "call" volume class was associated with
the "speakers/call" volume control, and when audio was routed to
headphones, the "call" volume class was associated with the
"headphones/call" volume control. That is, there were volume controls
for each pair of routing and volume class.

If you generalize the N9 volume model for any random hardware, it could
also happen on a machine that doesn't have any integrated audio output
devices that there are volume classes for "call" and "everything else",
but those volume classes are not associated with any volume control,
because there are no output devices. Only once you plug in e.g. a USB
sound card, the volume classes will get associated with volume controls.

>  * Or can a volume control object belong to several classes? If so the
> property on a volume control does not work (unless you do something like
> "volume_classes = foo,bar").

I can imagine that someone would define hierarchical volume classes: if
we standardize some volume class semantics based on e.g. the media role,
a system could expose these per-role volume classes for applications
that want to show per-role volumes, but the system could also expose
more coarse-grained non-standard volume classes (like "call" and
"everything else"). In this case the volume class for the "phone" media
role would point to the same volume control object as the "call" volume
class, and all other media role volume classes would point to the volume
control object of the "everything else" volume class.

After all this talk about volume classes, I've come to the conclusion
that I don't actually want a concept called "volume class". I want a bit
more general concept: "audio group". An audio group like a volume class,
but instead of only being associated with a volume control, the audio
group is also associated with mute and routing controls (by routing
control, I mean a routing node). This idea arose from the fact that I
didn't want to add mutual references between all the different control
types, but it should still be easy for UIs to show the volume, mute and
routing grouped together for abstract things like "music", "event
sounds", etc. It would still be possible to have audio groups that are
equivalent to volume classes, if you want different grouping for volume
than for mute and routing: just set the mute and routing controls of the
audio group to null. This also avoids the need to worry about adding
mute classes and routing classes in the future, since they're all
covered by the same concept.

struct pa_audio_group_info {
    uint32_t index;
    char *name;
    char *description;
    uint32_t volume_control;
    uint32_t mute_control;
    uint32_t routing_node;

> About taking things in iterations, would it work for you to get started
> on the volume control objects and skip the volume classes for the time
> being? And postpone that to a later iteration.

Yes, I can and I will start the implementation from the volume control
objects, but let's not stop the discussion about volume classes / audio
groups, because I will need to implement a client API for working with
volume classes anyway. The sooner I know how to do it, the better.


More information about the pulseaudio-discuss mailing list