From 6ef84a13099420f8cb7fb37d298656da25a5a133 Mon Sep 17 00:00:00 2001 From: George Kiagiadakis Date: Fri, 2 Jul 2021 20:23:45 +0300 Subject: [PATCH] docs: document the lua ObjectManager / Interest / Constraint APIs --- docs/rst/lua_api/lua_object_interest_api.rst | 169 ++++++++++++++++++- docs/rst/lua_api/lua_object_manager_api.rst | 49 +++++- 2 files changed, 215 insertions(+), 3 deletions(-) diff --git a/docs/rst/lua_api/lua_object_interest_api.rst b/docs/rst/lua_api/lua_object_interest_api.rst index 0bf41fd9..69baf6eb 100644 --- a/docs/rst/lua_api/lua_object_interest_api.rst +++ b/docs/rst/lua_api/lua_object_interest_api.rst @@ -3,20 +3,185 @@ Object Interest =============== -Constructors +The Interest object allows you to declare interest in a specific object, or +a set of objects, and filter them. This is used in the +:ref:`ObjectManager ` but also in other places where +methods allow you to iterate over a set of objects or lookup a specific object. + +*Interest* is a binding of :c:struct:`WpObjectInterest`, but it uses a +Lua-idiomatic way of construction instead of mapping directly the C functions, +for convenience. + +Construction ~~~~~~~~~~~~ +The most common use for *Interest* is in the +:ref:`ObjectManager `, where you have to use the +following construction method to create it. + .. function:: Interest(decl) :param table decl: an interest declaration :returns: the interest - :rtype: ObjectInterest + :rtype: Interest (:c:struct:`WpObjectInterest`) + +The interest consists of a GType and an array of constraints. It is constructed +with a table that contains all the constraints, plus the GType in the ``type`` +field. + +.. code-block:: lua + + local om = ObjectManager { + Interest { + type = "node", + Constraint { "node.name", "matches", "alsa*", type = "pw-global" }, + Constraint { "media.class", "equals", "Audio/Sink", type = "pw-global" }, + } + } + +In the above example, the interest will match all objects of type +:c:struct:`WpNode` that contain the following 2 global properties: + + - "node.name", with a value that begins with the string "alsa" + - "media.class", with a value that equals exactly the string "Audio/Sink" + +When an object method requires an *Interest* as an argument, you may as well +directly pass the declaration table as argument instead of using the +:func:`Interest` constructor function. For instance, + +.. code-block:: lua + + local fl_port = node:lookup_port { + Constraint { "port.name", "equals", "playback_FL" } + } + +In the above example, we lookup a port in a node. The :func:`Node.lookup_port` +method takes an *Interest* as an argument, but we can pass the interest +declaration table directly. Note also that such a method does not require +declaring the ``type`` of the interest, as it has :c:struct:`WpPort` as a +hardcoded default. + +The type +........ + +The type of an interest must be a valid GType, written as a string without the +"Wp" prefix and with the first letter optionally being lowercase. The type may +match any wireplumber object or interface. + +Examples: + +============= ============ + type string parsed as +============= ============ +node WpNode +Node WpNode +device WpDevice +plugin WpPlugin +siLink WpSiLink +SiLink WpSiLink +properties WpProperties +============= ============ + +The Constraint +.............. + +The *Constraint* is constructed also with a table, like *Interest* itself. This +table must have the following items in this very strict order: + + - a subject string: a string that specifies the name of a property to match + - a verb string: a string that specifies the match operation + - an object, if the verb requires it + +The verb may be any verb listed in :c:enum:`WpConstraintVerb`, using either +the nickname of the enum or the character value of it. + +Allowed verbs: + +============ ========= ======================================= +nickname character value +============ ========= ======================================= +"equals" "=" :c:enum:`WP_CONSTRAINT_VERB_EQUALS` +"not-equals" "!" :c:enum:`WP_CONSTRAINT_VERB_NOT_EQUALS` +"in-list" "c" :c:enum:`WP_CONSTRAINT_VERB_IN_LIST` +"in-range" "~" :c:enum:`WP_CONSTRAINT_VERB_IN_RANGE` +"matches" "#" :c:enum:`WP_CONSTRAINT_VERB_MATCHES` +"is-present" "+" :c:enum:`WP_CONSTRAINT_VERB_IS_PRESENT` +"is-absent" "-" :c:enum:`WP_CONSTRAINT_VERB_IS_ABSENT` +============ ========= ======================================= + +The values that are expected for each verb are primarily documented in +:c:func:`wp_object_interest_add_constraint`. In Lua, though, native types are +expected instead of GVariant and then they are converted according to the rules +documented in the :ref:`GObject Integration ` page. + +Examples of constraints: + +.. code-block:: lua + + Constraint { "node.id", "equals", "42" } + Constraint { "node.id", "equals", 42 } + Constraint { "port.physical", "=", true } + + Constraint { "audio.channel", "not-equals", "FL" } + + Constraint { "node.name", "matches", "v4l2_input*" } + Constraint { "format.dsp", "#", "*mono audio*" } + + -- matches either "default" or "settings" as a possible value for "metadata.name" + Constraint { "metadata.name", "in-list", "default", "settings" } + + -- matches any priority.session between 0 and 1000, inclusive + Constraint { "priority.session", "in-range", 0, 1000 } + + -- matches when the object has a "media.role" property + Constraint { "media.role", "is-present" } + + -- matches when "media.role" is not present in the properties list + Constraint { "media.role", "is-absent" } + +Constraint types +................ + +PipeWire objects have multiple properties lists, therefore constraints also need +to have a way to specify on which property list they apply. The constraint type +may be any of the types listed in :c:enum:`WpConstraintType` and can be +specified with an additional field in the *Constraint* construction table, +called ``type``. + +For instance: + +.. code-block:: lua + + Constraint { "node.id", "equals", "42", type = "pw-global" } + Constraint { "api.alsa.card.name", "matches", "*Intel*", type = "pw" } + Constraint { "bound-id", "=", 42, type = "gobject" } + +Valid types are: + +========= =============================================== +type value +========= =============================================== +pw-global :c:enum:`WP_CONSTRAINT_TYPE_PW_GLOBAL_PROPERTY` +pw :c:enum:`WP_CONSTRAINT_TYPE_PW_PROPERTY` +gobject :c:enum:`WP_CONSTRAINT_TYPE_G_PROPERTY` +========= =============================================== Methods ~~~~~~~ .. function:: Interest.matches(self, obj) + Binds :c:func:`wp_object_interest_matches` + + Checks if a specific object matches the interest. The object may be a GObject + or a table convertible to :c:struct:`WpProperties`, if the interest is for + properties. + + This is rarely useful to use directly on objects, but it may be useful to + check if a specific table contains key-value pairs that match specific + constraints, using "properties" as the interest type and passing a table as + the object. + :param self: the interest :param obj: an object to check for a match :type obj: GObject or table diff --git a/docs/rst/lua_api/lua_object_manager_api.rst b/docs/rst/lua_api/lua_object_manager_api.rst index 734c4e1d..0f08bbdd 100644 --- a/docs/rst/lua_api/lua_object_manager_api.rst +++ b/docs/rst/lua_api/lua_object_manager_api.rst @@ -3,6 +3,20 @@ Object Manager ============== +The ObjectManager (binding for :c:struct:`WpObjectManager`) provides a way to +collect a set of objects and be notified when objects that fulfill a certain +set of criteria are created or destroyed. + +To start an object manager, you first need to declare interest in a certain +kind of object specifying a set of :ref:`Interests ` +in the constructor and then you need to activate it by calling +:func:`ObjectManager.activate` + +Upon activating an ObjectManager, any pre-existing objects that match the +specified interests will immediately become available to get through +:func:`ObjectManager.iterate` and the :c:struct:`WpObjectManager` "object-added" +signal will be emitted for all of them. + Constructors ~~~~~~~~~~~~ @@ -13,10 +27,43 @@ Constructors Combines :c:func:`wp_object_manager_new` and :c:func:`wp_object_manager_add_interest_full` + The argument needs to be a table that contains one or more + :ref:`Interest ` objects. The object manager + will then contain all objects that match any one of the supplied interests. + + Example: + + .. code-block:: lua + + streams_om = ObjectManager { + -- match stream nodes + Interest { + type = "node", + Constraint { "media.class", "matches", "Stream/*", type = "pw-global" }, + }, + -- and device nodes that are not associated with any routes + Interest { + type = "node", + Constraint { "media.class", "matches", "Audio/*", type = "pw-global" }, + Constraint { "device.routes", "equals", "0", type = "pw" }, + }, + Interest { + type = "node", + Constraint { "media.class", "matches", "Audio/*", type = "pw-global" }, + Constraint { "device.routes", "is-absent", type = "pw" }, + }, + } + + The above example will create an ObjectManager that matches all nodes with + a "media.class" global property that starts with the string "Stream/" + and additionally all those whose "media.class" starts with "Audio/" and + they have either a "device.routes" property that equals zero or they + don't have a "device.routes" property at all. + :param table interest_list: a list of :ref:`interests ` to objects :returns: a new object manager - :rtype: ObjectManager + :rtype: ObjectManager (:c:struct:`WpObjectManager`) Methods ~~~~~~~