[pulseaudio-discuss] RFC: Public API for managing nodes

Tanu Kaskinen tanu.kaskinen at linux.intel.com
Thu Aug 8 08:00:20 PDT 2013


On Thu, 2013-08-08 at 15:05 +0200, David Henningsson wrote:
> On 08/06/2013 03:44 PM, Tanu Kaskinen wrote:
> > On Tue, 2013-08-06 at 15:21 +0200, David Henningsson wrote:
> >> On 08/06/2013 02:54 PM, Tanu Kaskinen wrote:
> >>> On Tue, 2013-08-06 at 14:42 +0200, David Henningsson wrote:
> >>>> On 08/06/2013 02:30 PM, Tanu Kaskinen wrote:
> >>>>> On Tue, 2013-08-06 at 13:26 +0200, David Henningsson wrote:
> >>>>>> On 08/05/2013 01:37 PM, Tanu Kaskinen wrote:
> >>>>>>> On Wed, 2013-07-17 at 12:26 +0200, David Henningsson wrote:
> >>>>>>>> On 07/17/2013 11:22 AM, Tanu Kaskinen wrote:
> >>>>>>>>> On Wed, 2013-07-17 at 09:27 +0200, David Henningsson wrote:
> >>>>>>>>>> On 07/16/2013 03:20 PM, Tanu Kaskinen wrote:
> >>>>>>>>>>> What operations do you mean? Moving or removing a default connection is
> >>>>>>>>>>> not supported as such, but if the client tries that anyway, we can
> >>>>>>>>>>> implicitly convert the connection to an explicit one and disable default
> >>>>>>>>>>> connections, or we can require the client to do these operations
> >>>>>>>>>>> explicitly, but I think the latter would be too inconvenient for the
> >>>>>>>>>>> client.
> >>>>>>>>>>
> >>>>>>>>>> Ok, I think I didn't read the proposal well enough. Having done that, I
> >>>>>>>>>> understand that you're suggesting a global switch "default connections
> >>>>>>>>>> on/off" only. Or is it a per-node switch?
> >>>>>>>>>
> >>>>>>>>> It is a per-node switch.
> >>>>>>>>>
> >>>>>>>>>> I have another idea that might be worth considering: how about that the
> >>>>>>>>>> "explicit" layer can both enable and disable connections? So that there
> >>>>>>>>>> could be a default connection between A and B, but there is also some
> >>>>>>>>>> sort of explicit override that disables it. This would be more flexible
> >>>>>>>>>> than a more global on/off switch.
> >>>>>>>>>
> >>>>>>>>> I'm not sure what you mean. Do you perhaps mean that the default
> >>>>>>>>> connection on/off switch should be per-node (which it already is in my
> >>>>>>>>> proposal), or that it should be per-connection (so that if there are
> >>>>>>>>> multiple default from node A, it's possible to disable only a subset of
> >>>>>>>>> those)?
> >>>>>>>>>
> >>>>>>>>> I didn't make make it possible to disable individual default
> >>>>>>>>> connections, because I had a feeling that it would have very messy
> >>>>>>>>> semantics. If default connection from A to B is disabled, what is the
> >>>>>>>>> routing code supposed to do when conditions change and the default
> >>>>>>>>> routing is re-evaluated? Can it ever reactivate the connection between A
> >>>>>>>>> and B again? Is the per-connection disabling handled as a blacklist of
> >>>>>>>>> connections that must never be automatically activated?
> >>>>>>>>
> >>>>>>>> If the A -> B route is explicitly_disabled, that overrides any default 
> >>>>>>>> connections the routing system tries to make.
> >>>>>>>
> >>>>>>> What is the use case for explicitly disabled connections? I'll assume
> >>>>>>> here that your idea was to allow moving a default connection elsewhere
> >>>>>>> (making the connection explicit in the process) without disabling all
> >>>>>>> default connections for the node.
> >>>>>>>
> >>>>>>> When the user moves a default connection, the routing system obviously
> >>>>>>> shouldn't immediately create another default connection elsewhere to
> >>>>>>> replace the disabled connection.
> >>>>>>>
> >>>>>>> On the other hand, if the routing system doesn't create replacement
> >>>>>>> connections, then that results in weird behaviour. Let's say that
> >>>>>>> there's a default connection A -> B, and the user moves the connection
> >>>>>>> to A -> C. Then B disappears. The routing changes its opinion of the
> >>>>>>> best available routing for A, which might be D. So removing node B
> >>>>>>> resulted in audio suddenly appearing in node D, even though nothing was
> >>>>>>> playing to B.
> >>>>>>>
> >>>>>>
> >>>>>> Assume your example of a default connection A -> B which the user
> >>>>>> changes into A -> C, by adding an explicit A -> C connection. Without
> >>>>>> some sort of explicitly_disabled blacklist that would then include A ->
> >>>>>> B, the routing system would be free to route A to *both* B and C.
> >>>>>
> >>>>> My solution is that the application disables the default routing
> >>>>> altogether for A, if it doesn't want to have the default connection A ->
> >>>>> B. It seems to me that this causes fewer surprises than the blacklisting
> >>>>> approach.
> >>>>>
> >>>>>> Whether this is implemented as a bool flag or as a separate blacklist is
> >>>>>> an implementation detail, but a bool flag just seemed simpler and faster
> >>>>>> to me, than having to look in several lists to figure out whether a
> >>>>>> connection exists or not.
> >>>>>
> >>>>> You don't need to look in several lists to figure out whether a
> >>>>> connection exists or not. If we have connection objects, which I think
> >>>>> we both want to have, it's enough to get the list all connections and
> >>>>> see whether a particular connection is included in that list.
> >>>>>
> >>>>
> >>>> Okay, so let me see if I understand this right. You propose that you can
> >>>> add explicit connections between two specified nodes, but blacklisting
> >>>> default connections have to be done on a node wide level (rather than
> >>>> per connection).
> >>>>
> >>>> That sounds interesting, as it would be more resilient towards nodes
> >>>> appearing and disappearing later on.
> >>>> I think that blacklisting would have to be two booleans per node though,
> >>>> one for outgoing connections and one for incoming. And a connection
> >>>> cannot exist if it is blocked on *either* side, rather than both sides.
> >>>> Does that make sense?
> >>>
> >>> My plan has so far been to only disable outgoing default connections,
> >>> but if there's need for it, I don't see any problem with adding another
> >>> bool for disabling incoming default connections. Do you have a use case?
> >>>
> >>
> >> Well, what's outgoing for playback is incoming for recording, so I think
> >> this would be the corresponding use case: assume a user changes from B
> >> -> A to C -> A, and that later on, a new source D appears. Then you
> >> would want to disable A on the incoming side to avoid a new D -> A
> >> connection?
> > 
> > Ok, I misunderstood what you meant by incoming and outgoing. Since a
> > node can't be both an input and output node, 
> 
> Oh? That's a new constraint to me. Are you saying that e g filter sinks
> won't show up in the graph at all, or that they have one output and
> another input node?

I'd like to make filter sinks unnecessary, but as long as we have to
deal with them, they can have both an output node and an input node, or
just an output node if the filter sink doesn't need to be moved to
different master.

> What about recording from monitors? Loopback and
> null sinks?

If monitor sources need to be exposed as routing endpoints, then they
can appear as separate input nodes. Loopbacks aren't routing endpoints,
so no nodes for them. Null sinks of course can be represented by output
nodes.

> > it can never have both
> > incoming and outgoing connections in the audio flow direction sense. I
> > thought that by "incoming" you meant connections that are initiated by
> > other nodes, and by "outgoing" I thought you meant connections that are
> > initiated by the node itself. That is, "incoming" and "outgoing"
> > wouldn't have anything to do with audio flow direction.
> > 
> > In your example, are B, C and D sources, and is A a capture stream? 
> 
> If you by capture stream mean what PulseAudio calls "source output",
> then, yes.
> 
> > And
> > B -> A was a default connection initiated by A? 
> 
> To me, when a routing system decides that a default connection should be
> added or removed, it must look at all relevant nodes and connections
> before making the best decision. Whether something is initiated by one
> side or the other sounds like a strange way to think about it.

In practice, certain nodes will "want to be connected" (streams), and
others are passive (devices). If you think the routing problem from the
point of view of "where should this node be connected" instead of "what
connections should exist in the system", it's not so strange to think
about connections being initiated by one side or the other.

It's possible to have situations where the endpoints are "equal". For
example, there could be a very specific loopback connection rule saying
that "when source A and sink B exist, they should be connected". I don't
think it's an big issue to decide, either arbitrarily or based on some
rationale, that one of the nodes should be the "more active" side. Or
they could both be marked as the initiator. It doesn't matter much. The
thing to consider, when writing that routing rule, is that if the
default connection is disabled, which of the two nodes should get all of
its self-initiated default connections disabled (by default there won't
be any other default connections, though, because both nodes are
devices).

> > If so, I would do the
> > move from B -> A to C -> A so that default connections are disabled for
> > A, and an explicit connection is added from C to A.
> > 
> > D probably won't initiate any default connections (sources and sinks
> > usually don't do that), but if it does initiate a default connection to
> > A, I think it's more likely that it should be allowed (this would be
> > pretty unusual routing rule, though, and you didn't explain why the D ->
> > A connection would be created, so it's hard to say anything with great
> > confidence).
> 
> Maybe the example was a bit contrived, but say that D is a USB
> microphone you just plugged in, and you have explicitly told the system
> to use your line input (C) instead of your internal mic (B), it would be
> bad if the routing switched. While if you had not told the system that,
> maybe switching to the USB mic would be something good - you usually
> want to use the stuff you plug in.

In this case A is obviously the initiator of any default connections, so
the D -> A connection will be created only if default connections are
enabled for A. If the routing was explicitly changed from A -> B to A ->
C, then default connections won't be enabled for A, and if such explicit
change was not done, then A will switch its default connection from B to
D when D appears. In both cases the routing decision is what you wanted.

-- 
Tanu



More information about the pulseaudio-discuss mailing list