Events & Hooks
This is the API that scripts use to participate in WirePlumber's event-driven session management logic. Almost all of the policy that ships with WirePlumber is implemented as hooks registered through this API.
For a conceptual introduction to events and hooks, read Events and Hooks first. The underlying C API is documented in Events, Event Dispatcher and Event Hooks.
Overview
An event is something that happened, pushed onto the event stack. Events
carry a type (for example node-added), a priority, a set of
properties, a source and a subject.
A hook is a piece of code that runs when a matching event is dispatched. A hook declares:
a unique
name, which other hooks use to order themselves against itone or more
interests, which decide whether the hook runs for a given eventbefore/afterconstraints, which order it relative to other hooks running on the same eventthe code to run, either as a single
executefunction (SimpleEventHook()) or as a state machine (AsyncEventHook())
Hooks do not run until they are registered with EventHook.register().
A minimal hook therefore looks like this:
SimpleEventHook {
name = "example/log-new-nodes",
interests = {
EventInterest {
Constraint { "event.type", "=", "node-added" },
},
},
execute = function (event)
local node = event:get_subject ()
log:info (node, "node added: " .. tostring (node.properties ["node.name"]))
end
}:register ()
Event
The event object is passed to the hook's execute function.
- Event.get_properties(self)
Binds
wp_event_get_properties()Returns the properties of the event. These always include
event.type, and typically include properties copied from the subject, which is what makes it possible to match on them in anEventInterest().- Returns:
the properties of the event
- Return type:
Properties, see Properties
- Event.get_source(self)
Binds
wp_event_get_source()Returns the object that pushed this event. For events pushed by the standard event source, this is the standard-event-source plugin, which is also the object that provides the
schedule-rescanandget-object-manageractions used by the shipped scripts.- Returns:
the source of the event
- Return type:
GObject
- Event.get_subject(self)
Binds
wp_event_get_subject()Returns the object that this event is about; for a
node-addedevent this is theNodethat was added.- Returns:
the subject of the event
- Return type:
GObject
- Event.stop_processing(self)
Binds
wp_event_stop_processing()Stops the event from being processed any further. No hooks that would run after this one will run for this event.
- Event.set_data(self, key, value)
Binds
wp_event_set_data()Stores an arbitrary value on the event, so that later hooks running on the same event can read it with
Event.get_data(). This is the standard way for a chain of hooks to communicate; theselect-targetchain, for instance, uses it to pass the selected target from thefind-*hooks tolinking/link-target.Passing no value (or nil) removes the data.
- Parameters:
key (string) -- the key to store the value under
value -- the value to store; booleans, numbers, strings, tables (stored as
Properties) and GValue userdata are supported
- Event.get_data(self, key)
Binds
wp_event_get_data()Returns the value previously stored with
Event.set_data(), or nil.- Parameters:
key (string) -- the key to look up
- Returns:
the stored value, or nil
EventInterest
- EventInterest(decl)
Creates an ObjectInterest that matches
Eventobjects. It is a shorthand forInterest { type = "event", ... }.The constraints are matched against the event's properties, so
event.typeis almost always the first constraint. See Object Interest for the full constraint syntax.EventInterest { Constraint { "event.type", "=", "node-added" }, Constraint { "media.class", "#", "Stream/*" }, }
When an event is created, the properties of its subject - both the info properties and the global properties - are merged into the event's own properties, which is why the
media.classconstraint above works without any further qualification. Consequently, the constrainttypeis irrelevant for"pw"and"pw-global"constraints on an event interest; both look up the same merged set of properties. A"gobject"constraint, on the other hand, is still matched against the GObject properties of the event's subject.A hook may declare several interests; the hook runs if any of them matches.
- Returns:
the new event interest
- Return type:
ObjectInterest
EventHook
Both SimpleEventHook() and AsyncEventHook() return an object with
the following methods.
- EventHook.register(self)
Binds
wp_event_dispatcher_register_hook()Registers the hook with the event dispatcher, so that it starts running for matching events. A hook has no effect until this is called.
- EventHook.remove(self)
Binds
wp_event_dispatcher_unregister_hook()Unregisters the hook. This is how scripts enable and disable hooks at runtime in response to a setting change; see the example below.
SimpleEventHook
- SimpleEventHook(decl)
Binds
wp_simple_event_hook_new()Constructs a hook whose action is a single synchronous function.
The constructor takes a single table with the following fields:
Field
Contains
name
(required) a string, the unique name of the hook
execute
(required) the function to run; it takes the
Eventas its only argument and returns nothinginterests
a list of
EventInterest()objects; the hook runs if any of them matchesbefore
a hook name, or a list of hook names, that must run after this hook
after
a hook name, or a list of hook names, that must run before this hook
SimpleEventHook { name = "linking/find-default-target", after = { "linking/find-defined-target", "linking/find-filter-target" }, before = "linking/prepare-link", interests = { EventInterest { Constraint { "event.type", "=", "select-target" }, }, }, execute = function (event) -- ... end }:register ()
- Returns:
the new hook
- Return type:
EventHook
AsyncEventHook
- AsyncEventHook(decl)
Binds
wp_async_event_hook_new()Constructs a hook whose action is a state machine, for actions that cannot complete synchronously — typically because they need to wait for an object to activate or for a PipeWire round trip.
The constructor takes the same
name,interests,beforeandafterfields asSimpleEventHook(), but instead ofexecuteit takes astepstable.Each entry in
stepsis named by a string and contains:Field
Contains
next
(required) the name of the step to run next, or the string
"none"to finishexecute
(required) the function to run for this step; it takes the
Eventand a TransitionExecution always starts at the step named
startand follows thenextlinks until a step whosenextis"none"has run.Each step's
executefunction is responsible for advancing the transition, either immediately withtransition:advance ()or later from an asynchronous callback. Callingtransition:return_error (message)aborts the hook.A step named
erroris optional; if present, it runs when the transition fails.AsyncEventHook { name = "node/create-item", interests = { EventInterest { Constraint { "event.type", "=", "node-added" }, }, }, steps = { start = { next = "register", execute = function (event, transition) local node = event:get_subject () -- ... create and configure the item ... transition:advance () end }, register = { next = "none", execute = function (event, transition) -- ... register the item ... transition:advance () end }, }, }:register ()
- Returns:
the new hook
- Return type:
EventHook
EventDispatcher
- EventDispatcher.push_event(event)
Binds
wp_event_dispatcher_push_event()Pushes an event onto the event stack, where it will be picked up and dispatched to all the hooks that are interested in it.
The argument is either an existing
Event, or a table describing a new event to construct and push:Field
Contains
type
(required) a string, the event type
priority
(required) a number; higher priority events are dispatched before lower priority ones
properties
a table or
Propertieswith additional properties for the eventsource
the object pushing the event
subject
the object the event is about
Properties of the subject are automatically copied into the event's properties, so interests can match on them.
In practice, the shipped scripts rarely build the table themselves. They ask the standard-event-source plugin to create the event instead, which assigns the priority that is configured for that event type, then attach any extra data to it and push it:
source = source or Plugin.find ("standard-event-source") local e = source:call ("create-event", "create-v4l2-device", parent, nil) e:set_data ("device-properties", properties) e:set_data ("factory", factory) EventDispatcher.push_event (e)
The
create-eventaction takes the event type, the subject and an optional properties table.- Returns:
the event that was pushed
- Return type:
Event
Enabling and disabling hooks at runtime
Because EventHook.register() and EventHook.remove() can be called
at any time, a script can react to a setting changing by adding or removing a
hook, rather than by checking the setting on every event. This is the pattern
used by, for example, linking/rescan-trigger-on-target-metadata-changed:
local hook = nil
local function updateEnabled (enable)
if enable and not hook then
hook = SimpleEventHook {
name = "example/my-hook",
interests = { EventInterest { Constraint { "event.type", "=", "node-added" } } },
execute = function (event) --[[ ... ]] end
}
hook:register ()
elseif hook and not enable then
hook:remove ()
hook = nil
end
end
Settings.subscribe ("example.my-setting", function ()
updateEnabled (Settings.get_boolean ("example.my-setting"))
end)
updateEnabled (Settings.get_boolean ("example.my-setting"))
See also Settings and Custom Scripts.