[pulseaudio-discuss] [PATCH 1/2] protocol-native: Add commands for communication with modules

Tanu Kaskinen tanuk at iki.fi
Mon Jul 10 15:15:11 UTC 2017


On Sat, 2017-07-08 at 22:40 +0200, Georg Chini wrote:
> On 07.07.2017 16:12, Tanu Kaskinen wrote:
> > On Thu, 2017-07-06 at 21:35 +0200, Georg Chini wrote:
> > > Looks good but does not really answer my intended question. Let me
> > > ask differently: How should the recipients be named?
> > 
> > If the recipient is an object as I originally intended, then the object
> > name could be used (e.g. sink name). If the object doesn't currently
> > have a name (e.g. sink inputs), then I think a name should be added. I
> > think it would be good to have names on all objects, as long as they
> > are more informative than just the object index.
> > 
> > If the recipient identifies just the implementor of a collection of
> > functions like you suggest, then the name should be something suitable
> > for that. For example, the loopback API could be named "loopback". I
> > don't want to use "module-loopback" as the name, because the API may
> > not be forever provided by a module called that. Loopbacks could very
> > well end up being included in the core, or loopbacks could be provided
> > by a library that is used by other modules to create loopbacks without
> > needing to load any module-loopback instances. Loading and unloading
> > modules and then controlling those modules from policy modules is more
> > cumbersome than using a direct C API like pa_loopback_new() and
> > pa_loopback_free() and pa_loopback_set_foo().
> 
> I do not really see the difference in that case. The "implementor
> of a collection of functions" is an object. If we allow any object
> to register a message handler, a module is as valid as an object
> as any other entity. I was just saying that I do not see the need
> to chain message handlers if each object registers its handler
> under a unique name. A handler for object A may contain functions
> that operate on object B if these functions are specific for object
> A. If they are not specific for object A, they belong to the handler
> of object B in the first place and should not be implemented together
> with object A.

I'll comment on this topic later in this mail.

> Regarding your naming - I don't see why we should not use module-xyz
> as a name. As said above, a module is a valid entity and as such entitled
> to register its own handler. When the functionality of a module is moved
> to the core or somewhere else, there will be a new valid object which on
> the long run replaces the old.

This is public API, and things generally can't be removed from the
public API. If you use "module-loopback" in the API, and then the
implementation gets moved to a library or the core, we'll have two
choices: either duplicate the same functionality under a new name, or
keep using only the "module-loopback" name. Both cases are undesirable,
when there is no underlying module-loopback instance involved.

> > > > I now noticed that in your patch the message name and parameters are
> > > > not separate. I think it's good to be able to register separate
> > > > handlers for separate messages. Multiple modules might want to register
> > > > different message handlers for a single recipient object. For example,
> > > > the alsa modules could register alsa specific sink messages and an
> > > > equalizer module could register equalizer messages for the same sink.
> 
> This is a good example for what I mean. You are saying "alsa specific
> sink messages" and "equalizer messages for the same sink".
> This shows for me, that the messages do not belong to the sink
> object itself, but to the underlying alsa backend or the equalizer. They
> just operate on the same sink.

When an alsa sink is created, the system will have only one sink, not
one "core sink" and one "alsa sink". However, if the alsa sink is not
able to add a new interface to the sink object that the core creates,
then the API will look like there are two separate objects that are
both called "sinks":

/core/sinks/alsa_sink_1
/alsa/sinks/alsa_sink_1

I would find the interface cleaner if there was only one sink object,
but there are also benefits to having only one interface per object, so
I don't have a strong opinion.

> > > You lost me here. For me there is one handler per recipient. In your
> > > example above, the recipients would be the modules, even though
> > > they work on the same sink. And if a module uses some kind of plug-in,
> > > the plug-in could also register its own handler. A module could
> > > even register multiple handlers with different recipient (object) names.
> > > 
> > > I do not see the necessity to chain handlers for the same object. In
> > > my opinion this would also raise the complexity level and my intention
> > > was to keep it as simple as possible.
> > 
> > Well, do we want an object oriented interface, where operations are
> > performed on devices, streams, loopback instances, etc. or do we want a
> > function oriented interface, where there are just plain functions
> > grouped by API providers (where there is often, but not always, a 1:1
> > relationship between modules and API providers)? Object oriented
> > programming is the "mainstream" approach, and D-Bus has that design
> > too, but functional programming is popular too, so I don't think
> > there's any clear "right answer".
> 
> See above.
> 
> > 
> > When access control is added, the access control policy will be
> > interested in the function/method name, and often it has to check the
> > operand object's attributes too. I imagine it would be easier for the
> > access policy if the messages contained the object name without needing
> > to parse it from the function parameters, but probably the difference
> > isn't huge if the operand objects are always the first function
> > parameters, so I don't have very strong opinion.
> > 
> > For example, let's say that there's a "set_latency" function that
> > operates on a loopback instance. The access control policy will get
> > either the following information:
> > 
> > object_name: "foo_loopback"
> > method_name: "set_latency"
> > parameters: "1234"
> > 
> > or
> > 
> > api: "loopback"
> > function_name: "set_latency"
> > parameters: "foo_loopback 1234"
> > 
> > The first case doesn't involve any parsing work to get the object name,
> > the second case does.
> > 
> 
> As said above, my assumption is, that each handler is registered under
> a unique (object) name that fully specifies the recipient of the message,
> so a call would look like your first example.
> The only problem I see here is to find an appropriate naming convention
> that is easy to use and accounts for multiple instances of the same
> object (multiple equalizers or loopbacks for example). Maybe some path-like
> approach would work:
> /core/object_name
> /sinks/{name|index}
> /modules/{name|index}[/object_within_module]
> ...

Ok, it seems that your thinking is more similar to mine than what I
first thought. I thought you'd prefer to create only one message
endpoint for module-loopback, no matter how many instances there are.
The only question is whether there can be multiple interfaces per
object or not.

Path-style object identifiers are fine for me. I would drop the
"/modules" prefix from non-core object paths. For loopback I suggest
the following object naming:

/loopback (for stuff that is not specific to a particular instance)
/loopback/instances/{instance_name} (for per-instance stuff)

-- 
Tanu

https://www.patreon.com/tanuk


More information about the pulseaudio-discuss mailing list