[pulseaudio-discuss] RFC: Routing and Priority lists
gmane at colin.guthr.ie
Thu Nov 24 02:13:07 PST 2011
'Twas brillig, and Janos Kovacs at 22/11/11 20:22 did gyre and gimble:
>> Yes, this should generally be OK. The entries in each priority list are
>> what I've coined as "device+ports". This is basically a specific port of
>> a given device.
> Yep, and I think a route in the priority list should be considered unavailable
> if the device (ie. sink/source) is available but the active port does not
Yes, this is the intention.
Unless this "autoswitch" mode is enabled in which case it may try to
switch ports to a higher, available, but not current port should it find
it list before a current port.
> In such case the subsequent, lower priority routes should be
> considered as long as a valid route target is not found. If we run out
> of the routes, the stream should be moved to the null sink (if loaded :).
> Alternatively the null sink can be part of the priority list I guess.
> (Or do I miss something here?)
Yeah the "module-always-sink" module ensures there is always a sink
loaded, even if it's a null sink. Any sink that exists should be in a
priority list (even if it's only in-memory and they are subsequently
removed again before any list is written to disk)
So ultimately we'll get down to a "default" priority list (one that does
not use roles as keys) and we can be pretty certain that it will contain
a sink we can use. If for some bizarre reason it does not, we simply
don't assign a sink as part of the routing system and PA will ultimately
assign the stream to the default/fallback sink as it does now so nothing
>> e.g. on some HW I have, I have a single sink, but that sink consists of
>> two ports: Speaker and Headphones.
>> In a given priority list I may favour the built in Headphones first,
>> then some external USB headset, then the Speakers.
>> So as you can see the single sink actually fits into the priority list
>> in two different places (or as many different places as there are ports).
>> Some separate logic (ultimately coming from David's work on jack
>> detection) would ensure a given port is activated when it becomes
>> "available". This means that I have some stream playing and it's on the
>> speakers, I plugin my USB headset and the stream moves over
>> automatically (due to a "reroute" event triggered when the new sink
>> becomes available). Then I plug in my headphones into the 3.5mm jack
>> socket, and it's detected as now being "available". The "separate logic"
>> mentioned, switches port from "speakers" to "headphones" and a "reroute"
>> event is triggered (just like a new sink appearing/disappearing,
>> "reroute" events are triggered on port changes too) and the stream is
>> automatically moved to the Headphones.
> Just to make sure we are on the same page:
> Basically I propose a routing scheme where the routing decisions would
> be made in a nested loop. In the outer loop we would walk through the streams
> in decreasing priority order (marked by the media role of the stream).
> In the inner loop we would walk through of the media role based routes of the
> stream (also in decreasing priority order). The first available route will
> be selected and configured, ie. the needed profiles and ports would be set.
> Next the stream could be moved to the actual device. Lower priority streams
> should never undo the settings caused by higher priority streams.
Yup, this seems sensible. I hadn't actually thought about how it would
be implemented but yes this seems like a good way of approaching it. It
will necessitate a bit of a design change on my side (to what I had in
my head anyway!) but not substantially so.
> So, IMO the 'separate logic' should not make unconditional port changes,
> rather it should consider the actual routing priority lists and make the port
> change accordingly.
Yup, this sounds good. It would essentially track which device+ports had
been allocated from a previous routing choice earlier in the stream loop
and then (when in "auto switch" mode) only make changes that would not
invalidate those previous decisions.
I specifically want to avoid tracking which *changes* have been made
(i.e. which ports have been switched to) as "reroute" events can be
triggered at any time and any "what I've changed" list would have to be
somehow persistent across separate reroute events which is a bit nasty.
So I think just keeping a list of "devices routed to" (we don't need to
save specifically which port was selected at this stage as the device
will be enough) will cover the requirement here for not making
The key to this is getting the order of the streams right in the stream
> However, because in your preferences 'headphones' has the highest priority,
> the above routing scheme will select the route to 'headphones' and actually
> switch the port and move the stream from the USB sink to the sink of the
> headphones. The port switching will block lower priority streams from using
> the 'speaker'.
Yeah that would work. I think this is the correct behaviour?
> So my point is that
> - the 'separate logic' should not unconditionally change the profiles/ports
Yes, there does have to be an "order" to it. I was originally thinking
first come first served, but your additional requirement of routing the
streams in a pre-defined order (based currently on roles, but I'd rather
be more generic) makes this much more deterministic which is nice.
> - we need some mechanism to mark cards/sinks to be configured to prevent
> lower priority streams to undo the possible port changes caused by higher
> priority streams
Yup, the "devices routed to" list I mentioned above would serve this
> - since the 'separate logic' completely driven by the priority lists,
> it can actually be part of the basic routing infrastructure.
Yeah. I suck at choosing names for things. "separate logic" in this case
I think will indeed be internal to the "priority list routing"
>> NB I've used the term "separate logic" here quite loosely. David has
>> some code to do this already, but this may eventually be superceded by
>> logic inside the routing daemon that will automatically switch to higher
>> priority ports on sinks if they are available.
> I guess the above described algorithm (if you like it) could be part of the
> of the basic infrastructure inside PA. Might not harm to provide some
> mechanism to disable it and allow an external 'separate logic' to do the
> profile/port settings if someone wishes to do so.
Yeah, this would be part of the priority list routing logic. It would be
100% up to modules to actually register priority lists (see my example
wiki page) and thus the whole system is completely optional. If some
other routing system is needed, the same basic hooks used by the
priority list routing stuff could be used to provide the necessary
custom functionality and the priority list code is basically unused.
Hopefully this wont be required if the priority list approach is itself
sufficiently useful, but the infrastructure is there if needed.
>>> 3.) the routing module would also track the streams and maintain a
>>> list of the active media roles.
>> OK, I won't specifically do that in the proposed implementation, but
>> (and feel free to correct me if I'm wrong) this is just a simple matter
>> of iterating over the sink inputs and check the media.role property on
>> each of them.
> Right. The routing module meant to see how the 'separate logic' would
> look like as PA module. The whole routing was split into two phases
> and the media role tracking was just an optimization. Let's forget
> about it for the time being :)
I kinda see the point now.. this tracking would allow for the ordering
of the sink inputs to be cached and thus we'd know the correct sequence
to iterate over them when routing.
OK, I've got the gist, I'll try and update the wiki page when I get the
time to think about it again (likely over the weekend).
Tribalogic Limited http://www.tribalogic.net/
Mageia Contributor http://www.mageia.org/
PulseAudio Hacker http://www.pulseaudio.org/
Trac Hacker http://trac.edgewall.org/
More information about the pulseaudio-discuss