docs: shuffle files to have the same logical hierarchy as on the generated doc
Also: - rename some files to remove redundant information from the filenames - rename many labels to match the filename and its place in the hierarchy - move lua_api under the scripting section
This commit is contained in:
144
docs/rst/scripting/lua_api/lua_core_api.rst
Normal file
144
docs/rst/scripting/lua_api/lua_core_api.rst
Normal file
@@ -0,0 +1,144 @@
|
||||
.. _lua_core_api:
|
||||
|
||||
Core
|
||||
====
|
||||
|
||||
The :ref:`WpCore <core_api>` API is mostly transparent to lua, as the core
|
||||
object is not exposed to the scripts.
|
||||
|
||||
For some functionality, though, the following static functions are exposed.
|
||||
|
||||
.. function:: Core.get_properties()
|
||||
|
||||
Binds :c:func:`wp_core_get_properties`
|
||||
|
||||
Returns a table with the properties of the core. These are the same
|
||||
properties that appear on WirePlumber's *client* object in the PipeWire
|
||||
global registry.
|
||||
|
||||
:returns: the properties of the core
|
||||
:rtype: table
|
||||
|
||||
.. function:: Core.get_info()
|
||||
|
||||
Returns a table with information about the core. The table contains
|
||||
the following fields:
|
||||
|
||||
=========== ===========
|
||||
Field Contains
|
||||
=========== ===========
|
||||
cookie The value of :c:func:`wp_core_get_remote_cookie`
|
||||
name The value of :c:func:`wp_core_get_remote_name`
|
||||
user_name The value of :c:func:`wp_core_get_remote_user_name`
|
||||
host_name The value of :c:func:`wp_core_get_remote_host_name`
|
||||
version The value of :c:func:`wp_core_get_remote_version`
|
||||
properties The value of :c:func:`wp_core_get_remote_properties`
|
||||
=========== ===========
|
||||
|
||||
:returns: information about the core
|
||||
:rtype: table
|
||||
|
||||
.. function:: Core.idle_add(callback)
|
||||
|
||||
Binds :c:func:`wp_core_idle_add_closure`
|
||||
|
||||
Schedules to call *callback* the next time that the event loop will be idle
|
||||
|
||||
:param function callback: the function to call; the function takes no
|
||||
arguments and must return true/false, as it is a GSourceFunc:
|
||||
return true to have the event loop call it again the next time it is idle,
|
||||
false to stop calling it and remove the associated GSource
|
||||
:returns: the GSource associated with this idle callback
|
||||
:rtype: GSource, see :func:`GSource.destroy`
|
||||
|
||||
.. function:: Core.timeout_add(timeout_ms, callback)
|
||||
|
||||
Binds :c:func:`wp_core_timeout_add_closure`
|
||||
|
||||
Schedules to call *callback* after *timeout_ms* milliseconds
|
||||
|
||||
:param function callback: the function to call; the function takes no
|
||||
arguments and must return true/false, as it is a GSourceFunc:
|
||||
return true to have the event loop call it again periodically every
|
||||
*timeout_ms* milliseconds, false to stop calling it and remove the
|
||||
associated GSource
|
||||
:returns: the GSource associated with this idle callback
|
||||
:rtype: GSource, see :func:`GSource.destroy`
|
||||
|
||||
.. function:: GSource.destroy(self)
|
||||
|
||||
For the purpose of working with :func:`Core.idle_add` and
|
||||
:func:`Core.timeout_add`, the GSource object that is returned by those
|
||||
functions contains this method.
|
||||
|
||||
Call this method to destroy the source, so that the associated callback
|
||||
is not called again. This can be used to stop a repeating timer callback
|
||||
or just to abort some idle operation
|
||||
|
||||
This method binds *g_source_destroy*
|
||||
|
||||
.. function:: Core.sync(callback)
|
||||
|
||||
Binds :c:func:`wp_core_sync`
|
||||
|
||||
Calls *callback* after synchronizing the transaction state with PipeWire
|
||||
|
||||
:param function callback: a function to be called after syncing with PipeWire;
|
||||
the function takes one argument that will be an error string, if something
|
||||
went wrong and nil otherwise and returns nothing
|
||||
|
||||
.. function:: Core.quit()
|
||||
|
||||
Quits the current *wpexec* process
|
||||
|
||||
.. note::
|
||||
|
||||
This can only be called when the script is running in *wpexec*;
|
||||
if it is running in the main WirePlumber daemon, it will print
|
||||
a warning and do nothing
|
||||
|
||||
.. function:: Core.require_api(..., callback)
|
||||
|
||||
Ensures that the specified API plugins are loaded.
|
||||
|
||||
API plugins are plugins that provide some API extensions for use in scripts.
|
||||
These plugins must always have their name end in "-api" and the names
|
||||
specified here must not have the "-api" extension.
|
||||
|
||||
For instance, the "mixer-api" module provides an API to change volume/mute
|
||||
controls from scripts, via action signals. It can be used like this:
|
||||
|
||||
.. code-block:: lua
|
||||
|
||||
Core.require_api("mixer", function(mixer)
|
||||
-- get the volume of node 35
|
||||
local volume = mixer:call("get-volume", 35)
|
||||
|
||||
-- the return value of "get-volume" is a GVariant(a{sv}),
|
||||
-- which gets translated to a Lua table
|
||||
Debug.dump_table(volume)
|
||||
end)
|
||||
|
||||
See also the example in :func:`GObject.call`
|
||||
|
||||
.. note::
|
||||
|
||||
This can only be called when the script is running in *wpexec*;
|
||||
if it is running in the main WirePlumber daemon, it will print
|
||||
a warning and do nothing
|
||||
|
||||
:param strings ...: a list of string arguments, which specify the names of
|
||||
the api plugins to load, if they are not already loaded
|
||||
:param callback: the function to call after the plugins have been loaded;
|
||||
this function takes references to the plugins as parameters
|
||||
|
||||
.. function:: Core.test_feature()
|
||||
|
||||
Binds :c:func:`wp_core_test_feature`
|
||||
|
||||
Tests if the specified feature is provided in the current WirePlumber
|
||||
configuration.
|
||||
|
||||
:param string feature: the name of the feature to test
|
||||
:returns: true if the feature is provided, false otherwise
|
||||
:rtype: boolean
|
300
docs/rst/scripting/lua_api/lua_gobject.rst
Normal file
300
docs/rst/scripting/lua_api/lua_gobject.rst
Normal file
@@ -0,0 +1,300 @@
|
||||
.. _lua_gobject:
|
||||
|
||||
GObject Integration
|
||||
===================
|
||||
|
||||
The Lua engine that powers WirePlumber's scripts provides direct integration
|
||||
with `GObject`_. Most of the objects that you will deal with in the lua scripts
|
||||
are wrapping GObjects. In order to work with the scripts, you will first need
|
||||
to have a basic understanding of GObject's basic concepts, such as signals and
|
||||
properties.
|
||||
|
||||
Properties
|
||||
----------
|
||||
|
||||
All GObjects have the ability to have `properties`_.
|
||||
In C we normally use `g_object_get`_ to retrieve them and `g_object_set`_
|
||||
to set them.
|
||||
|
||||
In WirePlumber's lua engine, these properties are exposed as object members
|
||||
of the Lua object.
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: lua
|
||||
|
||||
-- read the "bound-id" GObject property from the proxy
|
||||
local proxy = function_that_returns_a_wp_proxy()
|
||||
local proxy_id = proxy["bound-id"]
|
||||
print("Bound ID: " .. proxy_id)
|
||||
|
||||
Writable properties can also be set in a similar fashion:
|
||||
|
||||
.. code-block:: lua
|
||||
|
||||
-- set the "scale" GObject property to the enum value "cubic"
|
||||
local mixer = ...
|
||||
mixer["scale"] = "cubic"
|
||||
|
||||
Signals
|
||||
-------
|
||||
|
||||
GObjects also have a generic mechanism to deliver events to external callbacks.
|
||||
These events are called `signals`_.
|
||||
To connect to a signal and handle it, you may use the *connect* method:
|
||||
|
||||
.. function:: GObject.connect(self, detailed_signal, callback)
|
||||
|
||||
Connects the signal to a callback. When the signal is emitted by the
|
||||
underlying object, the callback will be executed.
|
||||
|
||||
The signature of the callback is expected to match the signature of the
|
||||
signal, with the first parameter being the object itself.
|
||||
|
||||
**Example:**
|
||||
|
||||
.. code-block:: lua
|
||||
|
||||
-- connects the "bound" signal from WpProxy to a callback
|
||||
local proxy = function_that_returns_a_wp_proxy()
|
||||
proxy:connect("bound", function(p, id)
|
||||
print("Proxy " .. tostring(p) .. " bound to " .. tostring(id))
|
||||
end)
|
||||
|
||||
In this example, the ``p`` variable in the callback is the ``proxy`` object,
|
||||
while ``id`` is the first parameter of the *"bound"* signal, as documented
|
||||
in :c:struct:`WpProxy`
|
||||
|
||||
:param detailed_signal: the signal name to listen to
|
||||
(of the form "signal-name::detail")
|
||||
:param callback: a lua function that will be called when the signal is emitted
|
||||
|
||||
Signals may also be used as a way to have dynamic methods on objects. These
|
||||
signals are meant to be called by external code and not handled. These signals
|
||||
are called **action signals**.
|
||||
You may call an action signal using the *call* method:
|
||||
|
||||
.. function:: GObject.call(self, action_signal, ...)
|
||||
|
||||
Calls an action signal on this object.
|
||||
|
||||
**Example:**
|
||||
|
||||
.. code-block:: lua
|
||||
|
||||
Core.require_api("default-nodes", "mixer", function(...)
|
||||
local default_nodes, mixer = ...
|
||||
|
||||
-- "get-default-node" and "get-volume" are action signals of the
|
||||
-- "default-nodes-api" and "mixer-api" plugins respectively
|
||||
local id = default_nodes:call("get-default-node", "Audio/Sink")
|
||||
local volume = mixer:call("get-volume", id)
|
||||
|
||||
-- the return value of "get-volume" is a GVariant(a{sv}),
|
||||
-- which gets translated to a Lua table
|
||||
Debug.dump_table(volume)
|
||||
end)
|
||||
|
||||
:param action_signal: the signal name to call
|
||||
:param ...: a list of arguments that will be passed to the signal
|
||||
:returns: the return value of the action signal, if any
|
||||
|
||||
Type conversions
|
||||
----------------
|
||||
|
||||
When working with GObject properties and signals, variables need to be
|
||||
converted from C types to Lua types and vice versa. The following tables
|
||||
list the type conversions that happen automatically:
|
||||
|
||||
C to Lua
|
||||
^^^^^^^^
|
||||
|
||||
Conversion from C to lua is based on the C type.
|
||||
|
||||
================================ ===============================================
|
||||
C Lua
|
||||
================================ ===============================================
|
||||
gchar, guchar, gint, guint integer
|
||||
glong, gulong, gint64, guint64 integer
|
||||
gfloat, gdouble number
|
||||
gboolean boolean
|
||||
gchar * string
|
||||
gpointer lightuserdata
|
||||
WpProperties * table (keys: string, values: string)
|
||||
enum string containing the nickname (short name) of
|
||||
the enum, or integer if the enum is not
|
||||
registered with GType
|
||||
flags integer (as in C)
|
||||
GVariant * a native type, see below
|
||||
other GObject, GInterface userdata holding reference to the object
|
||||
other GBoxed userdata holding reference to the object
|
||||
================================ ===============================================
|
||||
|
||||
.. _lua_gobject_lua_to_c:
|
||||
|
||||
Lua to C
|
||||
^^^^^^^^
|
||||
|
||||
Conversion from Lua to C is based on the expected type in C.
|
||||
|
||||
============================== ==================================================
|
||||
Expecting Lua
|
||||
============================== ==================================================
|
||||
gchar, guchar, gint, guint, convertible to integer
|
||||
glong, gulong, gint64, guint64 convertible to integer
|
||||
gfloat, gdouble convertible to number
|
||||
gboolean convertible to boolean
|
||||
gchar * convertible to string
|
||||
gpointer must be lightuserdata
|
||||
WpProperties * must be table (keys: string, values: convertible
|
||||
to string)
|
||||
enum must be string holding the nickname of the enum,
|
||||
or convertible to integer
|
||||
flags convertible to integer
|
||||
GVariant * see below
|
||||
other GObject, GInterface must be userdata holding a compatible GObject type
|
||||
other GBoxed must be userdata holding the same GBoxed type
|
||||
============================== ==================================================
|
||||
|
||||
GVariant to Lua
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
============================= =============================================
|
||||
GVariant Lua
|
||||
============================= =============================================
|
||||
NULL or G_VARIANT_TYPE_UNIT nil
|
||||
G_VARIANT_TYPE_INT16 integer
|
||||
G_VARIANT_TYPE_INT32 integer
|
||||
G_VARIANT_TYPE_INT64 integer
|
||||
G_VARIANT_TYPE_UINT16 integer
|
||||
G_VARIANT_TYPE_UINT32 integer
|
||||
G_VARIANT_TYPE_UINT64 integer
|
||||
G_VARIANT_TYPE_DOUBLE number
|
||||
G_VARIANT_TYPE_BOOLEAN boolean
|
||||
G_VARIANT_TYPE_STRING string
|
||||
G_VARIANT_TYPE_VARIANT converted recursively
|
||||
G_VARIANT_TYPE_DICTIONARY table (keys & values converted recursively)
|
||||
G_VARIANT_TYPE_ARRAY table (children converted recursively)
|
||||
============================= =============================================
|
||||
|
||||
Lua to GVariant
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
Conversion from Lua to GVariant is based on the lua type and is quite limited.
|
||||
|
||||
There is no way to recover an array, for instance, because there is no way
|
||||
in Lua to tell if a table contains an array or a dictionary. All Lua tables
|
||||
are converted to dictionaries and integer keys are converted to strings.
|
||||
|
||||
========= ================================
|
||||
Lua GVariant
|
||||
========= ================================
|
||||
nil G_VARIANT_TYPE_UNIT
|
||||
boolean G_VARIANT_TYPE_BOOLEAN
|
||||
integer G_VARIANT_TYPE_INT64
|
||||
number G_VARIANT_TYPE_DOUBLE
|
||||
string G_VARIANT_TYPE_STRING
|
||||
table G_VARIANT_TYPE_VARDICT (a{sv})
|
||||
========= ================================
|
||||
|
||||
Closures
|
||||
--------
|
||||
|
||||
When a C function is expecting a GClosure, in Lua it is possible to pass
|
||||
a Lua function directly. The function is then wrapped into a custom GClosure.
|
||||
|
||||
When this GClosure is invalidated, the reference to the Lua function is dropped.
|
||||
Similarly, when the lua engine is stopped, all the GClosures that were
|
||||
created by this engine are invalidated.
|
||||
|
||||
Reference counting
|
||||
------------------
|
||||
|
||||
GObject references in Lua always hold a reference to the underlying GObject.
|
||||
When moving this reference around to other variables in Lua, the underlying
|
||||
GObject reference is shared, but Lua reference counts the wrapper "userdata"
|
||||
object.
|
||||
|
||||
.. code-block:: lua
|
||||
|
||||
-- creating a new FooObject instance; obj holds the GObject reference
|
||||
local obj = FooObject()
|
||||
|
||||
-- GObject reference is dropped and FooObject is finalized
|
||||
obj = nil
|
||||
|
||||
.. code-block:: lua
|
||||
|
||||
-- creating a new FooObject instance; obj holds the GObject reference
|
||||
local obj = FooObject()
|
||||
|
||||
function store_global(o)
|
||||
-- o is now stored in the global 'obj_global' variable
|
||||
-- the GObject ref count is still 1
|
||||
obj_global = o
|
||||
end
|
||||
|
||||
-- obj userdata reference is passed to o, the GObject ref count is still 1
|
||||
store_global(obj)
|
||||
|
||||
-- userdata reference dropped from obj, the GObject is still alive
|
||||
obj = nil
|
||||
|
||||
-- userdata reference dropped from obj_global,
|
||||
-- the GObject ref is dropped and FooObject is finalized
|
||||
obj_global = nil
|
||||
|
||||
.. note::
|
||||
|
||||
When assigning a variable to nil, Lua may not immediately drop
|
||||
the reference of the underlying object. This is because Lua uses a garbage
|
||||
collector and goes through all the unreferenced objects to cleanup when
|
||||
the garbage collector runs.
|
||||
|
||||
When a GObject that is already referenced in Lua re-appears somewhere else
|
||||
through calling some API or because of a callback from C, a new reference is
|
||||
added on the GObject.
|
||||
|
||||
.. code-block:: lua
|
||||
|
||||
-- ObjectManager is created in Lua, om holds 1 ref
|
||||
local om = ObjectManager(...)
|
||||
om:connect("objects-changed", function (om)
|
||||
-- om in this scope is a local function argument that was created
|
||||
-- by the signal's closure marshaller and holds a second reference
|
||||
-- to the ObjectManager
|
||||
|
||||
do_some_stuff()
|
||||
|
||||
-- this second reference is dropped when the function goes out of scope
|
||||
end)
|
||||
|
||||
.. danger::
|
||||
|
||||
Because Lua variables hold strong references to GObjects, it is dangerous
|
||||
to create closures that reference such variables, because these closures
|
||||
may create reference loops and **leak** objects
|
||||
|
||||
.. code-block:: lua
|
||||
|
||||
local om = ObjectManager(...)
|
||||
|
||||
om:connect("objects-changed", function (obj_mgr)
|
||||
-- using 'om' here instead of the local 'obj_mgr'
|
||||
-- creates a dangerous reference from the closure to 'om'
|
||||
for obj in om:iterate() do
|
||||
do_stuff(obj)
|
||||
end
|
||||
end)
|
||||
|
||||
-- local userdata reference dropped, but the GClosure that was generated
|
||||
-- from the above function is still holding a reference and keeps
|
||||
-- the ObjectManager alive; the GClosure is referenced by the ObjectManager
|
||||
-- because of the signal connection, so the ObjectManager is leaked
|
||||
om = nil
|
||||
|
||||
.. _GObject: https://developer.gnome.org/gobject/stable/
|
||||
.. _properties: https://developer.gnome.org/gobject/stable/gobject-properties.html
|
||||
.. _g_object_get: https://developer.gnome.org/gobject/stable/gobject-The-Base-Object-Type.html#g-object-get
|
||||
.. _g_object_set: https://developer.gnome.org/gobject/stable/gobject-The-Base-Object-Type.html#g-object-set
|
||||
.. _signals: https://developer.gnome.org/gobject/stable/signal.html
|
63
docs/rst/scripting/lua_api/lua_introduction.rst
Normal file
63
docs/rst/scripting/lua_api/lua_introduction.rst
Normal file
@@ -0,0 +1,63 @@
|
||||
.. _lua_introduction:
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
`Lua <https://www.lua.org/>`_ is a powerful, efficient, lightweight,
|
||||
embeddable scripting language.
|
||||
|
||||
WirePlumber uses `Lua version 5.4 <https://www.lua.org/versions.html>`_ to
|
||||
implement its engine. For older systems, Lua 5.3 is also supported.
|
||||
|
||||
Scripts can be ran with the ``wpexec`` tool.
|
||||
|
||||
Example scripts can be found in the `tests/examples` directory of the wireplumber source tree.
|
||||
|
||||
Lua Reference
|
||||
-------------
|
||||
|
||||
If you are not familiar with the Lua language and its API, please refer to
|
||||
the `Lua 5.4 Reference Manual <https://www.lua.org/manual/5.4/manual.html>`_
|
||||
|
||||
Sandbox
|
||||
-------
|
||||
|
||||
WirePlumber's scripting engine sandboxes the lua scripts to a safe environment.
|
||||
In this environment, the following rules apply:
|
||||
|
||||
- Scripts are isolated from one another; global variables in one script
|
||||
are not visible from another, even though they are actually executed in
|
||||
the same ``lua_State``
|
||||
|
||||
- Tables that hold API methods are not writable. While this may sound strange,
|
||||
standard Lua allows you to change standard API, for instance
|
||||
``string.format = rogue_format`` is valid outside the sandbox.
|
||||
WirePlumber does not allow that.
|
||||
|
||||
- The standard Lua API is limited to a subset of safe functions. For instance,
|
||||
functions that interact with the file system (io.*) and the process's state
|
||||
(ex.: os.exit) are **not** allowed.
|
||||
|
||||
Here is a full list of Lua functions (and API tables) that are exposed:
|
||||
|
||||
.. literalinclude:: ../../../../modules/module-lua-scripting/wplua/sandbox.lua
|
||||
:language: lua
|
||||
:lines: 27-30
|
||||
|
||||
- Object methods are not exposed in public tables. To call an object method
|
||||
you must use the method call syntax of Lua, i.e. ``object:method(params)``
|
||||
|
||||
The following, for instance, is **not** valid:
|
||||
|
||||
.. code-block:: lua
|
||||
|
||||
-- this will cause an exception
|
||||
local node = ...
|
||||
Node.send_command(node, "Suspend")
|
||||
|
||||
The correct form is this:
|
||||
|
||||
.. code-block:: lua
|
||||
|
||||
local node = ...
|
||||
node:send_command("Suspend")
|
26
docs/rst/scripting/lua_api/lua_local_module_api.rst
Normal file
26
docs/rst/scripting/lua_api/lua_local_module_api.rst
Normal file
@@ -0,0 +1,26 @@
|
||||
.. _lua_local_module_api:
|
||||
|
||||
Local Modules
|
||||
=============
|
||||
|
||||
The `LocalModule` object (which binds the :c:struct:`WpImplModule` C API) provides a way
|
||||
to load PipeWire modules in the WirePlumber process. Instantiating the object
|
||||
loads the module, and when the last reference to the returned module object is
|
||||
dropped, the module is unloaded.
|
||||
|
||||
Constructors
|
||||
~~~~~~~~~~~~
|
||||
|
||||
.. function:: LocalModule(name, arguments, properties)
|
||||
|
||||
Loads the named module with the provided arguments and properties (either of
|
||||
which can be ``nil``).
|
||||
|
||||
:param string name: the module name, such as ``"libpipewire-module-loopback"``
|
||||
:param string arguments: should be either ``nil`` or a string with the desired
|
||||
module arguments
|
||||
:param table properties: can be ``nil`` or a table that can be
|
||||
:ref:`converted <lua_gobject_lua_to_c>` to :c:struct:`WpProperties`
|
||||
:returns: a new LocalModule
|
||||
:rtype: LocalModule (:c:struct:`WpImplModule`)
|
||||
:since: 0.4.2
|
56
docs/rst/scripting/lua_api/lua_log_api.rst
Normal file
56
docs/rst/scripting/lua_api/lua_log_api.rst
Normal file
@@ -0,0 +1,56 @@
|
||||
.. _lua_log_api:
|
||||
|
||||
Debug Logging
|
||||
=============
|
||||
|
||||
.. function:: Log.warning(object, message)
|
||||
|
||||
Logs a warning message, like :c:macro:`wp_warning_object`
|
||||
|
||||
:param object: optional object to associate the message with; you
|
||||
may skip this and just start with the *message* as the first parameter
|
||||
:type object: GObject or GBoxed
|
||||
:param string message: the warning message to log
|
||||
|
||||
.. function:: Log.notice(object, message)
|
||||
|
||||
Logs a notice message, like :c:macro:`wp_notice_object`
|
||||
|
||||
:param object: optional object to associate the message with; you
|
||||
may skip this and just start with the *message* as the first parameter
|
||||
:type object: GObject or GBoxed
|
||||
:param string message: the normal message to log
|
||||
|
||||
.. function:: Log.info(object, message)
|
||||
|
||||
Logs a info message, like :c:macro:`wp_info_object`
|
||||
|
||||
:param object: optional object to associate the message with; you
|
||||
may skip this and just start with the *message* as the first parameter
|
||||
:type object: GObject or GBoxed
|
||||
:param string message: the info message to log
|
||||
|
||||
.. function:: Log.debug(object, message)
|
||||
|
||||
Logs a debug message, like :c:macro:`wp_debug_object`
|
||||
|
||||
:param object: optional object to associate the message with; you
|
||||
may skip this and just start with the *message* as the first parameter
|
||||
:type object: GObject or GBoxed
|
||||
:param string message: the debug message to log
|
||||
|
||||
.. function:: Log.trace(object, message)
|
||||
|
||||
Logs a trace message, like :c:macro:`wp_trace_object`
|
||||
|
||||
:param object: optional object to associate the message with; you
|
||||
may skip this and just start with the *message* as the first parameter
|
||||
:type object: GObject or GBoxed
|
||||
:param string message: the trace message to log
|
||||
|
||||
.. function:: Debug.dump_table(t)
|
||||
|
||||
Prints a table with all its contents, recursively, to stdout
|
||||
for debugging purposes
|
||||
|
||||
:param table t: any table
|
4
docs/rst/scripting/lua_api/lua_object_api.rst
Normal file
4
docs/rst/scripting/lua_api/lua_object_api.rst
Normal file
@@ -0,0 +1,4 @@
|
||||
.. _lua_object_api:
|
||||
|
||||
WpObject
|
||||
========
|
189
docs/rst/scripting/lua_api/lua_object_interest_api.rst
Normal file
189
docs/rst/scripting/lua_api/lua_object_interest_api.rst
Normal file
@@ -0,0 +1,189 @@
|
||||
.. _lua_object_interest_api:
|
||||
|
||||
Object Interest
|
||||
===============
|
||||
|
||||
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 <lua_object_manager_api>` 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 <lua_object_manager_api>`, 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: 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 <lua_gobject>` 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
|
||||
:returns: whether the object matches the interest
|
||||
:rtype: boolean
|
104
docs/rst/scripting/lua_api/lua_object_manager_api.rst
Normal file
104
docs/rst/scripting/lua_api/lua_object_manager_api.rst
Normal file
@@ -0,0 +1,104 @@
|
||||
.. _lua_object_manager_api:
|
||||
|
||||
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 <lua_object_interest_api>`
|
||||
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
|
||||
~~~~~~~~~~~~
|
||||
|
||||
.. function:: ObjectManager(interest_list)
|
||||
|
||||
Constructs a new object manager.
|
||||
|
||||
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 <lua_object_interest_api>` 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 <lua_object_interest_api>`
|
||||
to objects
|
||||
:returns: a new object manager
|
||||
:rtype: ObjectManager (:c:struct:`WpObjectManager`)
|
||||
|
||||
Methods
|
||||
~~~~~~~
|
||||
|
||||
.. function:: ObjectManager.activate(self)
|
||||
|
||||
Activates the object manager.
|
||||
Binds :c:func:`wp_core_install_object_manager`.
|
||||
|
||||
:param self: the object manager
|
||||
|
||||
.. function:: ObjectManager.get_n_objects(self)
|
||||
|
||||
Binds :c:func:`wp_object_manager_get_n_objects`
|
||||
|
||||
:param self: the object manager
|
||||
:returns: the number of objects managed by the object manager
|
||||
:rtype: integer
|
||||
|
||||
.. function:: ObjectManager.iterate(self, interest)
|
||||
|
||||
Binds :c:func:`wp_object_manager_new_filtered_iterator_full`
|
||||
|
||||
:param self: the object manager
|
||||
:param interest: an interest to filter objects
|
||||
:type interest: :ref:`Interest <lua_object_interest_api>` or nil or none
|
||||
:returns: all the managed objects that match the interest
|
||||
:rtype: Iterator; the iteration items are of type :ref:`GObject <lua_gobject>`
|
||||
|
||||
.. function:: ObjectManager.lookup(self, interest)
|
||||
|
||||
Binds :c:func:`wp_object_manager_lookup`
|
||||
|
||||
:param self: the object manager
|
||||
:param interest: the interest to use for the lookup
|
||||
:type interest: :ref:`Interest <lua_object_interest_api>` or nil or none
|
||||
:returns: the first managed object that matches the interest
|
||||
:rtype: :ref:`GObject <lua_gobject>`
|
200
docs/rst/scripting/lua_api/lua_proxies_api.rst
Normal file
200
docs/rst/scripting/lua_api/lua_proxies_api.rst
Normal file
@@ -0,0 +1,200 @@
|
||||
.. _lua_proxies_api:
|
||||
|
||||
PipeWire Proxies
|
||||
================
|
||||
|
||||
Proxy
|
||||
.....
|
||||
|
||||
Lua objects that bind a :ref:`WpProxy <proxy_api>` contain the following methods:
|
||||
|
||||
.. function:: Proxy.get_interface_type(self)
|
||||
|
||||
Binds :c:func:`wp_proxy_get_interface_type`
|
||||
|
||||
:param self: the proxy
|
||||
:returns: the proxy type, the proxy type version
|
||||
:rtype: string, integer
|
||||
|
||||
PipeWire Object
|
||||
...............
|
||||
|
||||
Lua objects that bind a :ref:`WpPipewireObject <pipewire_object_api>`
|
||||
contain the following methods:
|
||||
|
||||
.. function:: PipewireObject.iterate_params(self, param_name)
|
||||
|
||||
Binds :c:func:`wp_pipewire_object_enum_params_sync`
|
||||
|
||||
:param self: the proxy
|
||||
:param string param_name: the PipeWire param name to enumerate,
|
||||
ex "Props", "Route"
|
||||
:returns: the available parameters
|
||||
:rtype: Iterator; the iteration items are Spa Pod objects
|
||||
|
||||
.. function:: PipewireObject.set_param(self, param_name, pod)
|
||||
|
||||
Binds :c:func:`wp_pipewire_object_set_param`
|
||||
|
||||
:param self: the proxy
|
||||
:param string param_name: The PipeWire param name to set, ex "Props", "Route"
|
||||
:param Pod pod: A Spa Pod object containing the new params
|
||||
|
||||
Global Proxy
|
||||
............
|
||||
|
||||
Lua objects that bind a :ref:`WpGlobalProxy <global_proxy_api>`
|
||||
contain the following methods:
|
||||
|
||||
.. function:: GlobalProxy.request_destroy(self)
|
||||
|
||||
Binds :c:func:`wp_global_proxy_request_destroy`
|
||||
|
||||
:param self: the proxy
|
||||
|
||||
PipeWire Node
|
||||
.............
|
||||
|
||||
Lua objects that bind a :ref:`WpNode <node_api>` contain the following methods:
|
||||
|
||||
.. function:: Node.get_state(self)
|
||||
|
||||
Binds :c:func:`wp_node_get_state`
|
||||
|
||||
:param self: the proxy
|
||||
:returns: the current state of the node and an error message, if any
|
||||
:rtype: string (:c:enum:`WpNodeState`), string (error message)
|
||||
:since: 0.4.2
|
||||
|
||||
.. function:: Node.get_n_input_ports(self)
|
||||
|
||||
Binds :c:func:`wp_node_get_n_input_ports`
|
||||
|
||||
:param self: the proxy
|
||||
:returns: the current and max numbers of input ports on the node
|
||||
:rtype: integer (current), integer (max)
|
||||
:since: 0.4.2
|
||||
|
||||
.. function:: Node.get_n_output_ports(self)
|
||||
|
||||
Binds :c:func:`wp_node_get_n_output_ports`
|
||||
|
||||
:param self: the proxy
|
||||
:returns: the current and max numbers of output ports on the node
|
||||
:rtype: integer (current), integer (max)
|
||||
:since: 0.4.2
|
||||
|
||||
.. function:: Node.get_n_ports(self)
|
||||
|
||||
Binds :c:func:`wp_node_get_n_ports`
|
||||
|
||||
:param self: the proxy
|
||||
:returns: the number of ports on the node
|
||||
:since: 0.4.2
|
||||
|
||||
.. function:: Node.iterate_ports(self, interest)
|
||||
|
||||
Binds :c:func:`wp_node_iterate_ports`
|
||||
|
||||
:param self: the proxy
|
||||
:param interest: an interest to filter objects
|
||||
:type interest: :ref:`Interest <lua_object_interest_api>` or nil or none
|
||||
:returns: all the ports of this node that that match the interest
|
||||
:rtype: Iterator; the iteration items are of type :ref:`WpPort <port_api>`
|
||||
:since: 0.4.2
|
||||
|
||||
.. function:: Node.lookup_port(self, interest)
|
||||
|
||||
Binds :c:func:`wp_node_lookup_port`
|
||||
|
||||
:param self: the proxy
|
||||
:param interest: the interest to use for the lookup
|
||||
:type interest: :ref:`Interest <lua_object_interest_api>` or nil or none
|
||||
:returns: the first port of this node that matches the interest
|
||||
:rtype: :ref:`WpPort <port_api>`
|
||||
:since: 0.4.2
|
||||
|
||||
.. function:: Node.send_command(self, command)
|
||||
|
||||
Binds :c:func:`wp_node_send_command`
|
||||
|
||||
:param self: the proxy
|
||||
:param string command: the command to send to the node (ex "Suspend")
|
||||
|
||||
PipeWire Port
|
||||
.............
|
||||
|
||||
Lua objects that bind a :ref:`WpPort <port_api>` contain the following methods:
|
||||
|
||||
.. function:: Port.get_direction(self)
|
||||
|
||||
Binds :c:func:`wp_port_get_direction`
|
||||
|
||||
:param self: the port
|
||||
:returns: the direction of the Port
|
||||
:rtype: string (:c:enum:`WpDirection`)
|
||||
:since: 0.4.2
|
||||
|
||||
PipeWire Client
|
||||
...............
|
||||
|
||||
Lua objects that bind a :ref:`WpClient <client_api>`
|
||||
contain the following methods:
|
||||
|
||||
.. function:: Client.update_permissions(self, perms)
|
||||
|
||||
Binds :c:func:`wp_client_update_permissions`
|
||||
|
||||
Takes a table where the keys are object identifiers and the values are
|
||||
permission strings.
|
||||
|
||||
Valid object identifiers are:
|
||||
|
||||
- A number, meaning the bound ID of a proxy
|
||||
- The string "any" or the string "all", which sets the default permissions
|
||||
for this client
|
||||
|
||||
The permission strings have a chmod-like syntax (ex. "rwx" or "r-xm"), where:
|
||||
|
||||
- "r" means permission to read the object
|
||||
- "w" means permission to write data to the object
|
||||
- "x" means permission to call methods on the object
|
||||
- "m" means permission to set metadata for the object
|
||||
- "-" is ignored and can be used to make the string more readable when
|
||||
a permission flag is omitted
|
||||
|
||||
**Example:**
|
||||
|
||||
.. code-block:: lua
|
||||
|
||||
client:update_permissions {
|
||||
["all"] = "r-x",
|
||||
[35] = "rwxm",
|
||||
}
|
||||
|
||||
:param self: the proxy
|
||||
:param table perms: the permissions to update for this client
|
||||
|
||||
PipeWire Metadata
|
||||
.................
|
||||
|
||||
Lua objects that bind a :ref:`WpMetadata <metadata_api>`
|
||||
contain the following methods:
|
||||
|
||||
.. function:: Metadata.iterate(self, subject)
|
||||
|
||||
Binds :c:func:`wp_metadata_new_iterator`
|
||||
|
||||
:param self: the proxy
|
||||
:param integer subject: the subject id
|
||||
:returns: an iterator
|
||||
|
||||
.. function:: Metadata.find(self, subject, key)
|
||||
|
||||
Binds :c:func:`wp_metadata_find`
|
||||
|
||||
:param self: the proxy
|
||||
:param string subject: the subject id
|
||||
:param string key: the metadata key to find
|
||||
:returns: the value for this metadata key, the type of the value
|
||||
:rtype: string, string
|
42
docs/rst/scripting/lua_api/lua_session_item_api.rst
Normal file
42
docs/rst/scripting/lua_api/lua_session_item_api.rst
Normal file
@@ -0,0 +1,42 @@
|
||||
.. _lua_session_item_api:
|
||||
|
||||
Session Item
|
||||
============
|
||||
|
||||
Lua objects that bind a :ref:`WpSessionItem <session_item_api>`
|
||||
contain the following methods:
|
||||
|
||||
.. function:: SessionItem.get_associated_proxy(self, type)
|
||||
|
||||
Binds :c:func:`wp_session_item_get_associated_proxy`
|
||||
|
||||
:param self: the session item
|
||||
:param string type: the proxy type name
|
||||
:returns: the proxy object or nil
|
||||
|
||||
.. function:: SessionItem.reset(self)
|
||||
|
||||
Binds :c:func:`wp_session_item_reset`
|
||||
|
||||
:param self: the session item
|
||||
|
||||
.. function:: SessionItem.configure(self, properties)
|
||||
|
||||
Binds :c:func:`wp_session_item_configure`
|
||||
|
||||
:param self: the session item
|
||||
:param table properties: The configuration properties
|
||||
:returns: true on success, false on failure
|
||||
:rtype: boolean
|
||||
|
||||
.. function:: SessionItem.register(self)
|
||||
|
||||
Binds :c:func:`wp_session_item_register`
|
||||
|
||||
:param self: the session item
|
||||
|
||||
.. function:: SessionItem.remove(self)
|
||||
|
||||
Binds :c:func:`wp_session_item_remove`
|
||||
|
||||
:param self: the session item
|
21
docs/rst/scripting/lua_api/lua_spa_device_api.rst
Normal file
21
docs/rst/scripting/lua_api/lua_spa_device_api.rst
Normal file
@@ -0,0 +1,21 @@
|
||||
.. _lua_spa_device_api:
|
||||
|
||||
Spa Device
|
||||
==========
|
||||
|
||||
.. function:: SpaDevice.get_managed_object(self, id)
|
||||
|
||||
Binds :c:func:`wp_spa_device_get_managed_object`
|
||||
|
||||
:param self: the spa device
|
||||
:param integer id: the object id
|
||||
:returns: the managed object or nil
|
||||
|
||||
.. function:: SpaDevice.store_managed_object(self, id, object)
|
||||
|
||||
Binds :c:func:`wp_spa_device_store_managed_object`
|
||||
|
||||
:param self: the spa device
|
||||
:param integer id: the object id
|
||||
:param GObject object: a GObject to store or nil to remove the existing
|
||||
stored object
|
4
docs/rst/scripting/lua_api/lua_spa_pod.rst
Normal file
4
docs/rst/scripting/lua_api/lua_spa_pod.rst
Normal file
@@ -0,0 +1,4 @@
|
||||
.. _lua_spa_pod:
|
||||
|
||||
Spa Pod
|
||||
=======
|
15
docs/rst/scripting/lua_api/meson.build
Normal file
15
docs/rst/scripting/lua_api/meson.build
Normal file
@@ -0,0 +1,15 @@
|
||||
# you need to add here any files you add to the toc directory as well
|
||||
sphinx_files += files(
|
||||
'lua_core_api.rst',
|
||||
'lua_gobject.rst',
|
||||
'lua_local_module_api.rst',
|
||||
'lua_introduction.rst',
|
||||
'lua_log_api.rst',
|
||||
'lua_object_api.rst',
|
||||
'lua_object_interest_api.rst',
|
||||
'lua_object_manager_api.rst',
|
||||
'lua_proxies_api.rst',
|
||||
'lua_session_item_api.rst',
|
||||
'lua_spa_device_api.rst',
|
||||
'lua_spa_pod.rst',
|
||||
)
|
Reference in New Issue
Block a user