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/]