On Fri, 2014-02-14 at 06:23 +0100, David Henningsson wrote: > On 02/11/2014 03:03 PM, Tanu Kaskinen wrote: > > Hi all! > > > > I'm working (together with other people at Intel) on adding system > > volume control functionality to Tizen (primarily the IVI profile, > > although there's nothing inherently IVI specific here). Tizen uses web > > APIs for the UI, and since there are no existing web API standards for > > this functionality, we need to design the API from scratch. The current > > design can be seen at [1], in case you're interested (it's good > > background material for this discussion). What I'd like to discuss in > > this thread, however, is not the web API as such, but the use cases > > behind that design and what those use cases ultimately require from > > PulseAudio. (Feedback for the web API proposal is welcome too, but I > > think that should be discussed in a separate thread.) > > > > We want to support: > > * A single main output volume control. Think of things like the Gnome > > volume applet: when you click the applet icon, you get a single volume > > slider for controlling the "current output", whatever that means. The > > Gnome volume applet implements the main volume by using the default sink > > volume, but we'd like to make the main volume contextual, so that the > > main volume can control different things at different times. Ideally the > > contextual logic would be implemented in PulseAudio (by a policy > > module), not in the volume applet. The volume applet should know when > > the main volume controls e.g. the headphones volume or the phone call > > volume. > > * Volume classes. A car manufacturer may want to present only two > > volume controls for the user: "system" and "entertainment". A policy > > module in PulseAudio should classify streams based on whether their > > volume should be controlled by the "system" volume or by the > > "entertainment" volume. The volume classification should be separate > > from the routing classification (module-stream-restore, among other > > problems, doesn't allow separate classification for volume and routing). > > * Fine-grained volume UIs that show all application and device volumes, > > like pavucontrol. PulseAudio already handles this pretty well. > > > > The first question: do you agree that PulseAudio should support those > > use cases in one way or another? > > > > If the answer to the first question is "yes", then we can start > > discussing the details of the implementation. How would you implement > > the support for the listed requirements? > > > > I propose that we introduce a new concept: volume control. It would be a > > separate object that could be referenced from other objects. For > > example, all devices would have their own volume control objects. The > > main volume could point to some of the device volume controls, or any > > other volume control object. Streams could have their own volume control > > objects, or multiple streams could reference the shared volume control > > of their volume class. > > > > introspect.h could have something like this: > > > > typedef struct pa_volume_control_info { > > uint32_t index; > > char *name; > > char *description; > > pa_volume_t volume; > > pa_channel_map channel_map; > > double *balance; /* per-channel balance, values between 0.0 and 1.0 */ > > } pa_volume_control_info; > > > > The alternative for separate volume controls is that we keep embedding > > the volume in various other objects, like sinks, sources, ports (which, > > btw, are currently missing volume control altogether when they are > > inactive), sink inputs and source outputs. This is certainly a possible > > approach, but I very much prefer the separate volume control object idea. > > > > Benefits of separate volume control objects: > > * Solves the problem of figuring out what the main volume controls. For > > example, the Gnome volume applet shows a headphone icon when the main > > volume controls the headphones volume. The volume applet can check if > > the main volume points to the same volume control object as the headset > > port. > > * If two streams share the same volume, a pavucontrol-like application > > can group the two streams under one volume slider. > > * Opportunity to separate the overall volume from the channel balance. > > The pa_cvolume volume representation loses all balance information when > > the user slides the overall volume to zero. > > * Flexibility to easily add new volume control objects for whatever > > purpose in the future. For example, there could be a volume debug mode > > where the individual alsa volume elements would be exposed as read-only > > volume controls, or separate read-only volume control objects for the > > "reference", "real" and "soft" components of sink volumes. pactl could > > show and control all volumes without understanding what the volumes are > > associated with. > > > > Drawbacks of separate volume control objects: > > * Duplication in the API. The old volume functionality in the public > > API can't be removed, so there would be two ways to control most volumes. > > > > The main volume would be added to pa_server_info as a new field (index > > referencing the appropriate volume control object). > > > > The volume classes would be separate objects: > > > > typedef struct pa_volume_class { > > uint32_t index; > > char *name; > > char *description; > > uint32_t volume_control; > > } pa_volume_class; > > > > I would add the volume control objects, the main volume and the volume > > classes to the core API, because this is functionality that is used > > pretty much everywhere (desktop environments, mobile devices, IVI > > systems), but I'm open to implementing this in a module too, with a > > protocol extension. > > > > [1] https://wiki.tizen.org/wiki/User:Tanuk/AudioSystemAPI > > > > Hi Tanu, > > my gut feeling would say: > > The volume objects, I think I understand the usefulness of those. I also > acknowledge the problem of having balance information lost when main > slider is zero. Excellent! > However we currently have the pa_cvolume type as well, which is sort of > the same as the new fields volume+channel_map+balance. I wonder if it > makes sense to group these together and call it pa_cvolume2 or something. Does the grouping have any benefits? If pa_volume_control_info has a field with this pa_cvolume2 type, then it could be argued that for symmetry there should also be function pa_context_set_volume_control_volume() that takes a pa_cvolume2 struct as a parameter. However, when an application sets the attributes of a volume control object, usually it will only modify the overall volume or the balance, not both, and the channel map is immutable, so passing a pa_cvolume2 struct to the setter function is inconvenient. If we forget about the symmetry argument and pass something else than pa_cvolume2 to pa_context_set_volume_control_volume(), then the only purpose of pa_cvolume2 seems to be to reduce the number of fields in the pa_volume_control_info struct. > And as somebody already pointed out, having either a global or > per-channel mute in that struct as well would probably be a good thing too. I'd like to keep mute controls completely separate from volume. They are not inherently linked to each other (even though they very often appear together). Another question is that should mute controls have per-channel granularity. I don't remember anyone ever asking for that feature, and it would add complexity to the mute controls (clients need to deal with partially-muted controls, and we need to attach channel map information to the controls). On the other hand, it doesn't seem entirely pointless as a concept either. > If you want main volume to represent one of these, you might want to add > a property list too, to contain the icon property (the UI could show a > headphone icon when controlling headphone volume). Did this paragraph contain implied approval for adding main input and output volume control references to the pa_server_info struct? What would you think about putting the icon name as a separate field to the pa_volume_control_info struct? I'm not against adding a proplist for undocumented metadata, but let's not abuse the proplist for things that are part of the documented stable API (any more than what we already do). > The volume classes however seem more like routing/policy implementation > internals. They could be kept inside the routing/policy module, exported > through property lists, or something like that. Either that, or I didn't > really understand the concept. Applications should have a unified way to query what volume classes exist and what volume control they are associated with. An example of a volume class is the event volume class. If applications want to access that, they currently need to use a module-stream-restore specific API, even though the concept of an event volume class is not specific to module-stream-restore. -- Tanu