[pulseaudio-discuss] Musings on stream device and volume restore rules
Colin Guthrie
gmane at colin.guthr.ie
Tue Mar 24 14:08:11 PDT 2009
Disclaimer... I'm a bit tired and haven't proofed this as much as I'd
like. And I wrote most of it while in an airport and quite bored.
The suggestions are my own thoughts and opinions but are perhaps based
on inaccurate assumptions, so feel free to correct me and change my opinion!
Stream Memory Database and Restoration Rules
============================================
This document outlines the needs and use case for the stream memory
capabilities in pulseaudio and how this information should be used. It
finishes with recommendations for implementation.
Restrictions
============
The system employed needs to be simple and allow for fully server based
management and application of the rules. The logic should be kept simple
with minimal overhead but still be powerful enough to meet all the needs
of current actual and potential use cases.
Current System
==============
Currently module-stream-restore stores various metadata on streams it
sees. This currently consists of:
* volume
* channel map
* mute status
* device (optional)
It stores this metadata under a key that governs how it is matched again
in the future.
The key itself has two parts, a prefix from a predefined list and a
suffix relating to the specific stream in some way.
Prefixes include:
* sink-input-by-media-role
* sink-input-by-application-id
* sink-input-by-application-name
* sink-input-by-media-name
(where "sink-input" could also be "source-output" for input streams)
The specific identifier is suffixed on the end of this, to create a
final key that is stored and queried in the database to give final keys
of e.g.:
* sink-input-by-media-role:event
* sink-input-by application-name:MPlayer
* etc.
When a stream is started, module-stream-restore will pick exactly one
key that it will use to identify a stream. If the stream has a media
role property it will use *-by-media-role. It then falls back to check
the different identifiers, in order, as outlined above.
Problems
========
The current system has a couple limitations.
1. If a stream has a media role, it is impossible to save a volume for
the specific application with that role as the key
sink-input-by-media-role:xxxx will always take precidence over a
sink-input-by-application-name:yyyy keyed rule.
2. If an application is modified to start providing new metadata (e.g.
a role) the entries for that specific application that were used
(sink-input-by-application-name) will no longer be matched and the data
will be stale in the file. This is not really a major problem.
3. The current system only allows for one device to be matched, not an
ordered priority list.
NB 3 is only strictly problemati in the case of Phonon integration which
uses such a scheme.
Use Case
========
To think about what we need to change in the system we need to look at
what the user wants out of the system.
For the most part we want routing rules to be automatic, but still allow
the user the degree of control they need.
For comparison, Phonon has a device priority list system that allows
each role to prioritise the output devices they want to use. When a
stream with that role is played, it will go through the list of devices
until it finds one that is currently avaialble (i.e. it keeps track of
devices that are no longer present - e.g. USB sound cards) and uses
that. It offers this priority list for each role, as well as a "global"
list, which is used when no role is provided by the application.
Generally speaking, users seem happy with this arrangement and this
degree of flexibility (albeit there are not many Phonon applications to
expliot this flexibility fully yet.
Looking at native pulse applications, the "default" sink option in
pavucontrol (or more correctly in the daemon itself) is the most
commonly misunderstood option and amounts to by far and away the most
common support issue: "I've changed my default to my USB but application
X still plays sound via my Interal card". From an internal prespective,
we do not consider this to be a "default" sink at all, but rather a
fallback and arguably calling it "default" was a mistake, but the fact
remains that users want an "active" default capability in the system
somewhere, where changing the default device will actually move any
active streams across to that device if they are currently using a
different default. Probably the second most common support question is:
"I set my USB to default, but then unplugged it and the application
started playing on my internal speakers... Great! But when I plugged my
USB back in it didn't move it back. What's up?".
What to do
==========
With the above use cases in mind, it's clear that the current system
needs to be revised to cope. In summary the problems we want to address are:
1. Allow for an "active" default
2. Allow for a prioritised list of devices to be created (on a
per-role basis - finer grained control would be too much).
3. Allow for applications which have the same role to have independant
volumes saved.
To this end, I think the current volume/map/mute/device database is
incorrect. With the flat volume support, I think per-application volumes
are more appropriate, rather than per-role.
I think that a key->device->priority table is needed to allow for a
given role identifier to have it's own rules written appropriately.
Pulse needs to remember the sinks (and sources) both past and present
(including their "nice" name (description)) and provide a way for a UI
app to purge a currently unavailable sink (e.g. remove it from the cache).
When a stream is encountered, it's role should be checked and the
prioritised list of devices loaded for that role. As in Phonon, if a
stream does not have a role a "default" priority list should be used.
(Optional) A subsequent check should be made to see if any specific
rules state that this individual application has a preferred device to
allow for fine grained control. If such a rule exists the device should
be move to the top of the already loaded priority list or injected there
if it does not exist (unlikely). The stream is then restored to the
first available device. This priority list should be saved with the
stream so it can be easily re-evaluated at any point should new sinks
become available later.
If any priority list is changed (e.g. by a client application) all
streams should have their cached priority list invalidated and rebuilt
(perhaps the rebuilding can be lazy - e.g. it's only loaded when needed?)
With regards to volumes etc., these should be saved against a given
application and not a role. To do so at the role level is unlikely to be
a useful end user feature.
With this system in place, a neat and effective UI can be produced and a
good mapping into KDE can also exist which will be good for cross
desktop accpetance of PulseAudio in the linux world.
Implementation
==============
Currently the routing decision is only processed by
module-stream-restore, but this is not sufficient. We need other modules
to be able to participate in this process. In order to acheive the
above, a new hook (or similar) should be created to allow separate
modules to have a say in building the priority list.
PA_CORE_HOOK_SINK_INPUT_ROUTE should be called when a new stream is
created and whenever the routing logic needs to be be recalculated (e.g.
the rules themselves change (or a module participating in rule
calculation is [un]loaded), *not* when a new device comes or goes) I
would suggest that only the device priority list should be handled in
this hook. The volume restoration should probably be handled within the
existing PA_CORE_HOOK_SINK_INPUT_NEW hook.
--
Colin Guthrie
gmane(at)colin.guthr.ie
http://colin.guthr.ie/
Day Job:
Tribalogic Limited [http://www.tribalogic.net/]
Open Source:
Mandriva Linux Contributor [http://www.mandriva.com/]
PulseAudio Hacker [http://www.pulseaudio.org/]
Trac Hacker [http://trac.edgewall.org/]
More information about the pulseaudio-discuss
mailing list