On 2014-06-27 17:59, Tanu Kaskinen wrote: > On Fri, 2014-06-27 at 14:41 +0200, David Henningsson wrote: >> >> On 2014-06-25 11:47, Tanu Kaskinen wrote: >> Well, with that argument we could just as well use pa_cvolume. Because >> we don't know if the hardware maintains balance when main volume is -inf >> either. > > It's enough if we remember in pulseaudio the accurate balance that was > set before the overall volume changed to -inf. The hardware doesn't need > to (and can't) remember it. (Btw, I prefer term "overall volume" when > referring to pa_bvolume.volume, because "main volume" is already used to > mean a different thing.) > > The balance information is potentially lost only if we copy the volume > from the hardware to our own volume representation, but that's rarely > necessary. Usually we copy the volume from our own representation to the > hardware, not the other way around. > >> We decided to have an extra "main" volume not to lose balance >> information, we can have an extra mute not to lose "main" volume when >> the stream/sink/etc is muted. > > Losing the overall volume information is not a problem if volume and > mute are in separate control objects, so I fail to see the point you're > trying to make here. It's more common than not to have volume bundled with a mute: almost all sinks, sources, and streams have that. Therefore, it feels logically more correct to keep them together, rather having every GUI having to link them together themselves. That said, I do acknowledge that there are valid use cases, especially for mutes without volumes. But it the answer to that really to separate *all* mutes from *all* volumes? >> Do you also plan to add stream and sink pointers to two pa_control_info >> structs then, one for volume and one for mute? I e for introspection of >> sinks/streams/etc. > > The second "odd" assumption was that having pointers from controls to > sinks/streams/etc would be somehow relevant for sink/stream/etc > introspection. If you want to introspect a sink, you need a pointer from > the sink to the control, not the other way around. Yes, this is what I meant: sinks and sources would have pointers to the control. Like this: struct pa_sink_info { /..../ uint32_t volume_control_index; uint32_t mute_control_index; } Are you planning to add that? > Now, some kind of mechanism to figure out the "primary" purpose of a > volume control object is needed, if a UI wants to indicate that the main > volume currently controls the call volume, or the headphones device, for > example. I initially thought that it's enough to check what stream, > device, or audio group is using the same volume control as what is > assigned as the main volume control, but this is ambiguous if multiple > entities share the volume control. Hmm, but are you also planning to change the internals of PulseAudio so that if a stream and a sink share the same volume control, only one of them will actually apply the volume? Otherwise the volume will have double effect. >>>>> type is either PA_CONTROL_TYPE_VOLUME or PA_CONTROL_TYPE_MUTE. data >>>>> points to one of these structs depending on the control type: >>>>> >>>>> struct pa_volume_control_data { >>>>> pa_bvolume volume; >>>>> int convertible_to_dB; >>>> >>>> Btw, could you explain what this field (convertible_to_dB) means? >>> >>> Sinks and sources have the DECIBEL_VOLUME flag. That's exposed here, so >>> that clients know when they can convert pa_volume_t to decibels. I think we should call it "int decibel_volume" instead for consistency. >> So in short, expect convertible_to_dB to always be true, if it's false, >> we're dealing with "bad" hardware that does not know what their volume >> steps mean? > > Yes. (By the way, all Bluetooth headsets are "bad" in this sense too.) > >> We could do the full capabilities thing that ALSA does - tell exactly >> what steps and so on that the hw supports. In which case we can merge >> volume and mute - a mute control is just a volume control with two >> steps. But this does not seem to be what you're planning. > > Steps are indeed something that probably should be added to volume > controls at some point, to allow UIs to show the user what steps are > available. Since pa_sink_info already have a n_volume_steps field, I think it would make sense to have that here too - shouldn't be too hard to add? > Another use case for volume steps is to limit the dynamic > range by using artificial volume steps and setting the lowest non-mute > step to relatively high value. This is useful if the device has low > dynamic range and is too quiet on lower volumes. There might be some > better solution for the dynamic range problem than forcing the use of > artificial volume steps, but I've heard that Sailfish is using volume > steps for this purpose (via a custom volume API). > > I'm not sure what design you're thinking here. Earlier you suggested a > design where a device would have one control that has both volume and > mute information. Is this paragraph about a design where a device would > have two volume controls, one of which actually represents mute with a > two-step volume slider? Another possibility is that you're thinking a > design where a device has just one merged volume/mute control without > separate mute field, but that's not workable because then we couldn't > remember the previous volume when the device is muted. This was not a design proposal, rather the opposite, an attempt to step back a little. For me, the common case is bundled volume and mute. Hence one bvolume with both volume and mute is my primary suggestion. Then we have all the specials: mutes without volumes, per-channel mutes, volume in steps only, and so on. The question is which one(s) of all those specials do we want to, and need to, solve. >> I can understand that mute and volume are the most common types of >> (volume) controls. But conceptually, we have everything in between too: >> Per channel mutes (common in hw and ALSA), volume with a limited number >> of steps, and so on. Considering this, and the boundary between volume >> and mute is fluid. >> But maybe that is just to over-generalising things and we should stick >> to volumes and mutes, like you suggest. > > I'll try to summarize: > > Bundling volume and mute into one control is not feasible if we want to > have flexible control sharing (see my example of sharing the device > volume control with Totem's stream, I don't think the Totem example makes sense. If Totem wants to control the device volume instead of the stream volume, then Totem can just do that. > while also having per-stream mute > controls), and it's at least awkward in situations where only mute is > relevant (e.g. passthrough streams). For these reasons I want to > separate volume and mute into separate control objects. > > Another idea was to represent mute with a volume control, so each device > would have two volume controls, one of which would be a two-step volume > that emulates mute. That should work, but I think that would look > strange to application developers, and I don't think it would save much > implementation effort if volume and mute controls are both based on a > common pa_control class anyway. > > Then there's the possibility that we drop the control sharing feature. > This makes some issues go away, with the downside that we lose the > transparency in how different volumes relate to each other, so if we > want to describe in the client API how stream volumes and mutes are > grouped, some other mechanism is needed in place of control object > sharing. > > I briefly mentioned my problem with flat volumes earlier, I'll explain > it a bit more here. In flat volume mode, the idea is that clients see > the absolute volume of the stream, i.e. the full hardware volume range > is available through the stream volume control. If a stream volume is > shared with an audio group, this becomes a problem, because the audio > group's volume control can't represent the absolute volume, because > there can be multiple streams connected to multiple devices - some > devices may use flat volume and some not, but even if all devices use > flat volume, their volume scales are different, so absolute volume means > different things on different devices. Therefore, the only sane choice > is that the audio group volume represents the relative stream volume. > But then, if a stream shares the volume control with an audio group, the > clients see the audio group's volume as the stream volume, so the > requirement of providing the full hw volume range is not met. > > The solution is to create a volume control object for providing access > to the stream absolute volume, and propagate changes to that volume > control internally to the audio group's volume control. But then > transparency is lost, i.e. clients don't see the connection between the > stream volume and the audio group volume, which I wanted to be visible. > Since the volume control sharing doesn't work in a common case like > this, I don't see it as a big loss if we add the constraint that one > volume control can be associated with only one entity. It probably makes > some things simpler. Yeah - where possible/convenient, let's design the API so we can add volume sharing later (if we figure out that's a good idea), but for now it seems simpler and easier to understand if one volume control controls one volume and nothing else. -- David Henningsson, Canonical Ltd. https://launchpad.net/~diwic