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

David Henningsson david.henningsson at canonical.com
Wed Jul 17 03:26:22 PDT 2013


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:
>>> Yes, automatic use of the combine module is planned (the combining
>>> functionality would move to the core, because what's the point of having
>>> code in a module if the core directly depends on that code).
>>
>> Okay, so combine stuff would then not have its own node or set of nodes,
>> but essentially be as integrated as mixing is today?
>
> Yes. Or well, I wouldn't say that it's as integrated as mixing, since it
> would still create a separate combine sink, which is a bit ugly, but as
> you said, the sink and the intermediate sink inputs wouldn't show up as
> nodes. I think it would make sense to make combining really as
> integrated as mixing, but that's not a high priority.

Ok.

>>>>       - Can there be more than one edge between the same nodes? E g, one
>>>> default connection and one explicit connection? Or how does this work?
>>>
>>> Yes, there can be both an explicit and a default connection between two
>>> nodes, or it can be also thought as being one connection that is both
>>> explicit and default. I don't know what is a better way to think about
>>> it, but perhaps it doesn't matter anyway.
>>
>> I would prefer the latter way. I would then see "default" and "explicit"
>> as a property of the edge.
>
> I agree about that, at a conceptual level. Would you perhaps like to
> have it this way also at the code level, i.e. have connection objects
> with "default" and "explicit" fields instead of storing the information
> in the nodes?

Good question. Actually one option could be to store the connections as 
global list-like matrix instead of lists on the individual node objects. 
After all, you'll need the connection on both sides, and unless you want 
to duplicate information, you'll have to do a global search on one of 
the sides anyway. Since the number of nodes < 100, I don't think this 
would matter from a performance standpoint.

You would end up with a global list with entries looking something like:

struct pa_node_connection_t {
   pa_node *from_node;
   pa_node *to_node;
   bool default;
   bool explicit;
   bool explicitly_disabled;
};

Where there is only one entry for every from_node/to_node combination, 
explicit and explicitly_disabled cannot both be true, and there is a 
connection if and only if (!explictitly_disabled) && (explicit || default).
And no list entry for a node combination, is the same as all three bools 
being false.

>>>>       - Can edges have properties, e g, a volume?
>>>
>>> I don't know. Currently I'm not aware of a requirement to have
>>> properties on the connections. My current thinking regarding volume
>>> specifically is that we shouldn't attach volume to nodes: let's keep the
>>> nodes for routing only.
>>
>> Ok, that makes sense.
>>
>>>>     * As for possible node operations, a move operation would be the same
>>>> as a "batched remove + add" operation. Maybe therefore the batch
>>>> solution would be better, i e, the client API inputs an array of node
>>>> operations?
>>>
>>> I don't like the idea that if a client wants to move a stream, it has to
>>> break the operation down to "remove + add", and then the server tries to
>>> guess what the client really meant. Having a "move" operations keeps the
>>> client intention obvious.
>>
>> Fair point, although the move can be on both sides, whereas one type of
>> move would be "I want node A to take data from C instead of B" and the
>> other type would be "I want node A to output data to node C instead of B".
>
> These both are served by the move operation.

In the RFC you only have pa_context_move_node_connection, which serves 
the latter case only. The former case is from "C -> A" to "B -> A", the 
typical example would be a client wanting to move a recording stream 
from one source to another.

>> Or perhaps you want to swap, so that if you're currently on "A -> B and
>> C -> D" and you want "A -> D and B -> C" and you want to do all of this
>> atomically. The number of operations you want to do might grow out of
>> hand unless you have a "batch mode".
>
> The core doesn't currently have a concept of atomic swapping, so I don't
> see the need for a separate swap command, but the core has a concept of
> atomic moving.

Well, IIRC, we have move_start and move_finish commands? A swap command 
would just be two move_starts and then two move_finish.

> If you think applications need to be able to swap connections in one go
> (even though the server will execute the commands sequentially), I'm not
> opposed at all to having a batch mode.
>
>>>
>>>>     * The operations on changing the default connections does not make
>>>> sense to me. If the definition for default connections are those made
>>>> automatically by the routing system, if you change them then you broke
>>>> the definition...?
>>>
>>> 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.


-- 
David Henningsson, Canonical Ltd.
https://launchpad.net/~diwic


More information about the pulseaudio-discuss mailing list