This setting will use the best quality or latency profiles for BT devices if
available. HSP/HFP profiles will always be ignored. The setting is a string that
only accepts 'quality' and 'latency' strings. Any other value will be treated
the same way as the 'quality' value.
The core object (ID 0) is implicit in the PipeWire connection and never
appears in the permission manager's ObjectManager. Add a
core_permissions field to set explicit permissions on it independently
of default_permissions.
This is suspected to be the reason why the CI pipelines fail on some
of the linking tests. Reverting the commit for now, until the issue
is better understood.
See #934
This reverts commit 529aaa66cb.
The refactoring uses a new 'select-access' event to select the access for each
client with a fallback mechanism. The fallback priority is: configuration,
flatpak, snap, portal, and default.
The access JSON configuration has also been improved so that users can create
their custom permission managers and attach them to any client. See the access
configuration example for more information describing how to do this.
The `properties` argument of `wp_impl_module_load()` is marked
"transfer none", thus the caller's reference remains valid and
must be disposed of.
Fixes: ef29018c55 ("m-lua-scripting: Add WpImplModule bindings")
Split rescan-on-linkable triggering into a separate script file
(linking/rescan-on-linkable.lua) that can be disabled via
wireplumber.profiles by setting hooks.linking.rescan-on-linkable =
disabled.
Since 'autoswitch-*' events have lower priority than 'select-*' events,
this guarantees that the autoswitch hooks will always run after the
'device/apply-profile' hook, avoiding possible race conditions.
These local events have lower priority than the 'create-*' and 'select-*' ones,
and are meant to be used when wireplumber wants to automatically switch profiles
or other things.
We cannot only rely on the input routes to check whether a profile is a headset
profile or not because some BT devices can have A2DP source nodes, causing the
autoswitch logic to not work properly.
This patch fixes the problem by also checking if the profile name matches the
'headset-head-unit*' or 'bap-duplex' patterns. If the profile name does not
match those patterns, the profile is not considered headset profile.
See #926
Setting api.bluez5.internal=true changes media.class to
Audio/(Stream|Sink)/Internal which makes HFP HF output get wrong media
class.
Don't set this for headset-audio-gateway. Fixes HFP HF stream media
class.
This allows us to have per-device configuration for device volumes, via
a `device.routes.default-volume` property. This allows a non-global
override for situations where we want to expose a different out-of-box
volume (say for an internal speaker where we know a better comfortable
default setting, or HDMI where we might want to avoid attenuation by
default).
At the moment the libcamera monitor and "Device" objects are loaded in the
wireplumber process, but the "Node" objects are loaded in the pipewire daemon.
Due to that, both processes have their own separate `libcamera::CameraManager`
objects. These operate independently.
As a consequence of the above, there is an inherent race condition: when a
new camera appears and the wireplumber process detects it and instructs the
pipewire process to create a "Node" for it, at that point, the camera might
not exist in the `CameraManager` of the "pipewire" process.
This can happen during the initial enumeration as well as hotplug. So load
the nodes locally in the wireplumber process so that all libcamera objects
use the same `CameraManager`, thus eliminating the race condition.
This is required in order to allow plugins to use GL as mincore
is used in Mesas `_eglPointerIsDereferenceable()`.
One example for a client wanting to do so is the in-development
libcamera GPUISP, see https://patchwork.libcamera.org/cover/24183/
(cherry picked from commit pipewire@4796b3fb9524c20ac0f5006143b6a13ee50c01ec)
See pipewire/pipewire!2530
Allows installation of systemd services without libsystemd installed.
Useful for Alpine Linux where systemd services are allowed to be subpackaged
(e.g. for postmarketOS) but hasn't systemd in it's repos.
It has no change in existing behavior, but installs services if the unit
directories are explicitly set.
In `wp_interest_event_hook_get_matching_event_types()`, the variable
`res` owns the allocated `GPtrArray`, but there is an early return
in the function. Hitting that will leak the allocation, so use
`g_autoptr` to avoid that.
Fixes: b80a0975c7 ("event-dispatcher: Register hooks for defined events in a hash table")
This simplifies a lot the logic as we don't need to destroy and re-create the
internal BT nodes right away if the loopback nodes were create after them.
We also now listen for changes in the BT profile autoswitch setting. If the
setting is disabled, the source loopback is destroyed. If it is enabled, the
source loopack is created. This makes the setting to take effect immediately,
without needing to disconnect and re-connect the BT device for the setting to
take effect.
As properties are no longer Lua tables, we'll need to make a table copy
for the Json constructor.
Fixes assigning Json.Array to a non-table, and ending up with
"audio.position":"0x7b771267d690" instead of ["FL","FR"] in json output,
which caused BAP device set node to always have mono channels.
Use prefix matching instead of exact matching for media.class when
validating nodes in the set-default command. This allows virtual
nodes (e.g. Audio/Source/Virtual) to be set as default devices,
while still excluding internal nodes.
Fixes#896
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Audio/Sink nodes should only be used as default audio source node type if the
user has explicitly selected it. If the user has not explicitly selected it,
we should always ignore it and instead select the highest priority Audio/Source
node.
Fixes#886
Take the loopback nodes into account also in device Routes.
Some Pulseaudio applications (eg GNOME) determine what to do based on
device ports, so make sure they are consistent with what nodes will be
emitted.
If enabled, this setting will use the same volume levels as the previous
profile. This is useful on some bluetooth devices if the bluetooth profile
audioswitch is enabled.
If the BT profile autoswitch setting is enabled, we also want to create a sink
loopback for SCO-A2DP sink nodes. Since BT nodes are removed and created again
when the profile changes, this avoids confusing some apps making them think
that the BT profile has not changed at all, because the loopback nodes are
always present, even when switching profiles.
This patch improves the BT profile autoswitch logic so that it is simpler and
more robust. Instead of just relying on capture clients that are linked to (or
unlinked from) the BT loopback source node to evaluate whether we have to switch
to a headset profile or not, we now also evaluate the autoswitch every time the
BT loopback source node state changes. This avoids problems with some capture
clients that pause the input stream without closing them.
Apart from this, the patch also fixes some issues with saved profiles if the
user manually switched to a headset profile when no capture streams are present.
The autoswitch logic should restore back the non-headset profile (A2DP) every
time a capture client is disconnected or the BT loopback source node stops
running.
Finally, the 'bluetooth.autoswitch-to-headset-profile' setting will now register
or remove the necessary hooks depending on whether the setting is enabled or
disabled, improving WirePlumber performance if autoswitching is disabled.
When getting the "core" property from a `WpObject`, a strong reference is
returned to the `WpCore` object. This has to be unref-d when not needed
anymore. `wp_modem_manager_enable()` fails to do so, so fix it.
Fixes: 2794764d5a ("m-modem-manager: add module for tracking status of voice calls")
Add immediate linking for common cases to reduce latency when new
audio/video streams are added. The full rescan mechanism is preserved
and still triggers for all session-item-added events via the
rescan-trigger hook.
Recompiling with the SPA_AUDIO_MAX_CHANNELS=128u defined, will create
larger audio_info structures that can hold more channels. Because
PipeWire is now using 128 channels, do the same in wireplumber so that
the generated PortConfig param can hold all channel positions.
See pipewire#4995
And include the error message while we're at it.
Fixes: 2794764d5a (m-modem-manager: add module for tracking status of voice calls)
Signed-off-by: Evangelos Ribeiro Tzaras <devrtz@fortysixandtwo.eu>
We segfault otherwise on error:
Thread 1 "wireplumber" received signal SIGSEGV, Segmentation fault.
g_type_check_instance_is_fundamentally_a (type_instance=type_instance@entry=0x7fffec008120,
fundamental_type=fundamental_type@entry=0x50 [GObject]) at ../../../gobject/gtype.c:3917
warning: 3917 ../../../gobject/gtype.c: No such file or directory
(gdb) bt
#0 g_type_check_instance_is_fundamentally_a
(type_instance=type_instance@entry=0x7fffec008120, fundamental_type=fundamental_type@entry=0x50 [GObject])
at ../../../gobject/gtype.c:3917
#1 0x00007ffff7eafe3d in g_object_unref (_object=0x7fffec008120) at ../../../gobject/gobject.c:4743
#2 0x00007ffff4784ec1 in list_calls_done (obj=<optimized out>, res=<optimized out>, data=0x5555556ab1b0)
at ../modules/module-modem-manager.c:209
Fixes: 2794764d5a (m-modem-manager: add module for tracking status of voice calls)
Signed-off-by: Evangelos Ribeiro Tzaras <devrtz@fortysixandtwo.eu>
This avoids sorting them constantly when collecting them. If a hook has a
circular dependency, a warning will be logged and the hook won't be registered.
See #824
Since all the current hooks are defined specifically for a particular event
type, we can register the hooks in a hash table using the event type as key
for faster event hook collection.
Also, hooks that are not specific to a particular event type, like constraints
such as 'event.type=*', will be registered in both the undefined hook list,
and also in all the hash table defined hook lists so they are always evaluated.
Even though 'wp_event_dispatcher_new_hooks_iterator()' can still be used, it is
now marked as deprecated because it is slower. The event hook collection uses
'wp_event_dispatcher_new_hooks_for_event_type_iterator()' now because it is
much faster.
Previously, the more hooks we were registering, the slower WirePlumber would
process events as all hooks needed to be evaluated for all events constantly.
This is not the case anymore with this patch. We can register thousands of
hooks, and if only 1 of those runs for a particular event, only 1 will be
evaluated instead of all of them.
See #824
UCM alsa nodes don't seem to have the 'alsa.*' properties from the device
included, which make it harder to match those nodes with alsa rules. This
patch adds all the 'alsa.*' properties in the UCM node to solve this.
We never use the feature of matching the subject type, so we can make
this simpler by not specifying CHECK_ALL, which also allows the
match_full() function to return early if some constraint doesn't match
instead of checking them all and wasting time.
There are streams that should go to a speaker rather than a headphone
or earpiece by default. Examples are alarms and emergency alerts on
phones. Allow to set a preference via
`policy.role-based.preferred-target` which then looks up the target
via `node.name` and `node.nick`.
Signed-off-by: Guido Günther <agx@sigxcpu.org>
`rescan-for-linking` is the lowest priority linking event but the
`rescan-for-media-role-volume` event is lower overall priority.
Signed-off-by: Guido Günther <agx@sigxcpu.org>
When using role based priorities a volume slider presented to the
user should adjust the volume of the currently playing role.
E.g. when a phone has an incoming call and is ringing the default volume
slider should adjust the ringing volume and once the call has been
picked up it should adjust the call volume and once the call ended it
should adjust the media volume again.
It's currently hard for e.g. desktop shells to find out what a suitable
sink for volume control is so add a script to find a suitable target for
volume control (based on media role priority) by storing it's name in
the metadata.
Signed-off-by: Guido Günther <agx@sigxcpu.org>
Limit the amount of channels we read from and write to the position
array with SPA_N_ELEMENTS(). The number of channels might be larger than
what we have positions for.
We should not ignore the returned iterator as it allows users to get the exact
returned params after enumerating them, which might be useful in some cases.
This allows us to set up the device to use HDMI ELD information for
channels. Not yet documented while we experiment with different ways to
make this work.
Attempts to workaround a race condition between daemon thread and
GDBus worker thread during shutdown.
Ubuntu bug: https://bugs.launchpad.net/bugs/2127049
I've not been able to get a symbolic backtrace yet or reproduce it
myself, but the behaviour points to a threading bug. Hypothesis,
Main thread (1, daemon thread) shuts down, unregistering its plugins.
One of the plugins, module-permissions-portal, is triggered to
shutdown.
It tries to clear its GDBus connection handle without disconnecting
its signal handlers.
GDBus thread (2) is in the middle of writing a message on the same
connection handle.
Once finished, it also tries to clear its handle.
The main thread has already taken the signal lock and the signal
handler table ends up in an invalid state, triggering the assert.
I believe this could happen since
wp_portal_permissionstore_plugin_disable is not disconnecting its
signal handlers before trying to clear its DBus object.
See https://bugzilla.gnome.org/show_bug.cgi?id=730296 for more
discussion about this assert in the Glib signal handling code.
Up until now, all the 'node.features.audio.*' settings did not have any effect
if changed at runtime. This patch fixes this by reconfiguring the audio adapters
every time those settings have changed.
If we re-configure the adapter with different settings than the ones from the
first configuration, we also need to configure the node ports to make sure they
are updated with the new settings.
For example, this is needed for stream audio adapters that have been configured
with monitor ports, and later re-configured without monitor ports. Without this
change, since stream audio adapters never configure the node ports on activation,
the internal node will still have the monitor ports present even after disabling
them in the 2nd re-configuration.
This script mutes available output ALSA routes if an audio node that was
previously running was removed. This is useful for cases where users might
unplug their headset accidentaly, causing undesired loud audio to play on the
Speakers.
Two new settings are added to chose whether the user wants to do this for
ALSA devices, Bluetooth devices or both. The settings are set to false by
default.
Finally, a notification is also sent to notify the user that the devices were
muted.
Add comprehensive wpctl documentation that generates both HTML docs and an installable man page from a single RST source.
Closes: #825🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Log.critical does not actually exist.
When logging error, it will in fact throw an exception:
[string "device-info-cache.lua"]:36: attempt to call a nil value
(field 'critical')
Change Log.critical to Log.warning to fix it.
This dependency must not be added here because it creates a circle.
m-standard-event-source is loaded after the hooks, as specified in the
wireplumber.components.rules section.
Move closure annotations from data parameters to function parameters and
also add destroy annotations where necessary. This fixes the "invalid
closure annotation" warnings during the build.
Remove mpris-pause hooks when the controlling setting is disabled,
and re-add when enabled, to avoid unnecessary processing.
Fix link tracking initialization, which previously never run. It worked
earlier since the event hook was registered early, but now it's needed.
A "Voice Call" profile is supposed to be active during a call, even if
there is a higher priority device profile. Add a hook to select the
Voice Call profile when a call is active, and select a profile when
transitioning in and out of an active call.
Voice calls can require special audio routing to work, such as by
switching the profile or opening an audio stream. Add a module to
monitor for the starting and stopping of a voice call.
Signed-off-by: Richard Acayan <mailingradian@gmail.com>
When applying new routes, we always want the save property to be false because
it is done by WirePlumber (not the user). WirePlumber applies routes when
restoring them from the state file, or when finding the best routes after the
profile has changed. In both cases, it does not make sense to set save=true.
If the user changed the volume on a ACP 'Headphones' route to a value different
than 100%, and then unplugs the jack headset, the ACP 'Headphones' route becomes
unavailable with volume set to 100% and the save flag not cleared.
Since the save flag is not cleared when the ACP 'Headphones' route becomes
unavailable, WirePlumber will save it with 100% volume, overriding the previous
volume value set by the user. This is not ideal because the volume will be
restored to 100% by WirePlumber when plugging back the headset.
This change fixes this by never saving routes that are not available.
The Route params changed event can be emitted before the EnumRoute params with
some devices, causing wrong evaluation of the routes because their cached info
is not updated. This change always enumerates the EnumRoute params before
evaluating them to make sure the cache info is always valid.
Fixes: #762
The only secure and robust way to check that a userdata is of the
expected type is to check its metatable. Userdata metatables are not
changeable by Lua code without the debug library, so if the metatable is
a certain table, only C code could have made it so. GLib type checking
functions are _not_ a robust or secure way to check that a block of
memory is a specific type of GObject, because Lua code could cause a
type confusion bug and potentially use it to forge pointers.
`wp_settings_new_iterator()` takes a reference to the underlying
`WpSettings` object with `g_object_ref()`, however, it fails to
release it during finalization. Fix that.
These builders had many bugs:
1. They would longjmp() across the destructor of a g_autoptr() if a Lua
error was thrown. This will leak the memory in the g_autoptr()
unless Lua is compiled with C++ exceptions.
2. They depended on the iteration order of numerical keys in Lua tables.
Lua explicitly does not specify this order.
3. They would produce nonsensical SPA POD array or choice types with
strings or bytes as values. These would cause undefined behavior if
manipulated by naive C code, or assertion failures if
spa_pod_is_array() and spa_pod_is_choice() are modified to check that
the contents of arrays and choices have sensible types.
4. They silently accepted extra arguments, potentially causing confusion
and making it harder to extend the functions in a
backwards-compatible way.
Solve the first problem by calling functions that can raise a Lua error
in a protected environment (with lua_pcall). If there is a Lua error,
rethrow it after the g_autoptr() destructor has run.
Solve the second problem by first obtaining the number of keys in the
table and then iterating over the keys that are expected to be present.
If any of the keys are not contiguious integers starting at 1, the range
[1..number of keys] will include a number that is not a table key. This
will result in lua_rawgeti pushing a nil onto the Lua stack. An
explicit check throws a useful error in this case.
Solve the third problem by explicitly checking that the type is
reasonable before building an array or choice. If it is wrong,
a Lua error is thrown.
Solve the fourth problem by using luaL_checktype (L, 2, LUA_TNONE) to
check that no unwanted values were passed. The C function called with
lua_pcall is passed every argument passed by Lua, followed by a light
userdata that stores a context pointer. After the light userdata is
popped from the Lua stack, the Lua stack is identical to what Lua
created when it called the outer C function, so the type-checking
functions in the auxillary library can be used to enforce that only the
correct number and type of arguments were passed.
Lua provides "extra data", which is some memory in each Lua state that
the application can use for its own purposes. Use this to store the
reference count.
Add rules to extract translatable strings from wireplumber.conf.
Meson i18n.gettext does not support extracting strings from
autogenerated files. Hence, we must commit conf.pot to repository.
These setting descriptions are meant to be user-facing. Translating them
allows also 3rd party apps to get the translations from 'wireplumber'
domain.
When current output target of a media player application is removed, it
can be useful if playback is paused (to avoid e.g. music playback to
going to speakers when headset is accidentally unplugged). Android etc.
implement a policy like this.
Add a policy script that monitors stream target removals. When it
detects a media player application that is linked to a no longer present
output target, it checks whether the stream is associated with a media
player seen in MPRIS. If yes, it sends MPRIS Pause() command to the
media player.
Enable this policy by default.
Some PCM devices can expose multiple nodes with same session priorities but
different route priorities. This improves the default nodes logic to also check
the route priorities when the session priorities are the same.
When a new Format param is set, the node's state is not checked, so this
attempt can even take place when the node is not suspended. Setting that
param will not work if the node isn't suspended though. Add a check for
the state and suspend the node if needed.
Also, do not set the Format param if the new param POD is the same as that
of the existing format to avoid redundant calls.
(This mirrors already existing checks for the PortConfig param.)
If the managed node needs to emit events before it is bound, Wireplumber
treats it as destroyed and ignores the events. Add the node as pending
before it is bound so the node can run set_param on events that happen
before it gets bound.
Signed-off-by: Richard Acayan <mailingradian@gmail.com>
Some modules (like module-loopback) may destroy themselves with
pw_impl_module_schedule_destroy() when the pipewire connection closes.
In that case, we need to clear our pointer so that we don't try to
destroy them again (and crash)
Fixes: #812
The linking-utils module already implements a way to check for available routes,
this patch uses it in default-nodes/rescan.lua to remove redundant code.
This patch caches the settings info to make sure their values are always
updated, even if using the settings API multiple times before pipewire
finishes synchronizing the metadata objects.
Fixes#749
Systemd journal entries have several common entries:
https://www.freedesktop.org/software/systemd/man/latest/systemd.journal-fields.html
Add "SYSLOG_IDENTIFIER" to make it easier to find wireplumber messages.
Add "SYSLOG_FACILITY" to avoid confusing programs that expect both or neither.
Add "TID" and "SYSLOG_PID" to make debugging a little easier.
The test I wrote for
https://gitlab.freedesktop.org/pipewire/wireplumber/-/issues/778 uses
this, since it needs a target-loudness to make a loudness filter:
```
tu.createDeviceNode (
"default-device-node",
"Audio/Sink",
{ ["device.target-loudness"] = -18 }
)
```
It's possible that managed_node.properties["node.name"] == nil if the
node is gone.
The removeDevice call above has already cleared the node names, so no
need to do it again.
I'm guessing this was a typo? I ran `git grep dont-remix` in both
wireplumber's and pipewire's repos, and all the other references were to
stream.dont-remix, including the definition of PW_KEY_STREAM_DONT_REMIX.
wireplumber.service generates the following when dbus.service
stops before it (e.g. when the user logs out):
m-dbus-connection: <WpDBusConnection:0x556b3c561680> DBus connection closed: Underlying GIOStream returned 0 bytes on an async read
m-dbus-connection: <WpDBusConnection:0x556b3c561680> Trying to reconnect after core sync
Stop the service before dbus.service exits, to avoid these messages.
This allows grouping audio streams that have a pw-audio-namespace ancestor
process name. The grouping is done by creating a loopback filter for each group
or namespace. Those loopback filters are then linked in between the actual
stream and device nodes. A '--target-object' flag is also supported in the
ancestor process name to define a target for the loopback stream node.
I had a hard time figuring out all the steps relevant for this to work.
Hopefully this brief summary and couple of links will help the next
person writing their own script.
See: #601
`wp_object_manager_add_interest()` passes the format string
and the arguments after that to `g_variant_new()`, which
requires a 32-bit integer for "u". Passing a 64-bit integer
will cause problems on certain ABIs.
Furthermore, remove the metadata related interest declaration
from `set_default_prepare()` since the "set-default" command
does not access metadata directly, it uses the "default-nodes-api"
plugin.
Fixes: 7784cfad92 ("wpctl: support @DEFAULT_{AUDIO,VIDEO}_{SINK,SOURCE}@ as ID ")
Fixes#773
It is valid for components not to have a "provides" field, but it
prevents them from being able to have "before" and "after" dependencies.
With this patch, we generate a hidden "provides" field so that the
dependencies sorting algorithm can work without issues.
Fixes: #771
stream-restore should not be touching node properties of the Bluetooth
mic / device set / offload / ALSA UCM split loopback nodes. Those are
controlled by Route settings on the device.
Set device.routes and state.restore-props=false as appropriate to avoid
that.
Instruct ACP to provide information about UCM SplitPCM channel
splitting instead of doing it with alsa-lib plugins.
Use the provided information to load loopbacks that create virtual sinks
that do the channel remapping from UCM.
Fix memory leaks in bad GValue handling. Unset iterator GValue after
use and strdup keys. The keys aren't necessarily static strings (for
id-XXXX properties), so have to be dup'd.
Node name deduplication relying on presence of node objects creates race
conditions, as the name cannot be marked unused if the node object was
not created or was destroyed.
Use separate (device_id, node_id) -> name table to track name ownership
separately from the existence of node objects.
Also clear up the reserved names when device is destroyed, by the
monitor or device reservation. In these cases "object-removed" for
nodes is not called, so this fixes names leaking when e.g. pw-reserve is
used.
In cases where a Node is created asynchronously and associated with the
Device later, set the id pending so that we don't miss ObjectConfig
events.
The "set Route again" workaround is also not needed, moreover it was not
reliable before either since the Device might issue ObjectConfig only
for changed properties.
Allow marking WpSpaDevice object ids "pending", which means Props from
any ObjectConfig events received for the ids are saved, if there is no
associated object set yet.
When wp_spa_device_store_managed_object() is called, any pending Props
are set on the managed object.
This is useful when nodes cannot be immediately created in the
"create-object" signal handler. For example, in cases where the nodes
are created asynchronously, e.g. by "module-loopback". In this case,
although the nodes can be later associated with the WpSpaDevice, any
ObjectConfig events received in the meantime are lost, so for example
restoring saved Routes will race against async node creation. Using
wp_spa_device_set_managed_pending() solves this race condition.
If loopback is emitted after the SCO node, e.g. when A2DP profile
connects late, recreate the SCO node.
This ensures the underlying SCO node is hidden when the loopback is
present.
This seems to be an omission from when we transferred the default device
properties from the config file on to the Lua script. Both auto-profile
and auto-port are meant to be disabled, so that we can apply our own
management logic.
Fixes: #734
When node activation fails, it won't be created and its object-removed
signal can be called with some properties missing. This breaks node
name deduplication, causing error
wplua: [string "alsa.lua"]:182: attempt to concatenate a nil value (local 'node_name')
It occurs e.g. when switching ALSA device profile, while some
application has opened the device with ALSA and is keeping it busy.
Fix by handling the activation failure, and tolerating missing property
in object-removed.
Cancel the async calls that get the name of the application owning the
service, when WpReserveDevice is finalized or we are going to make
another call.
Fixes UAF accessing self when the async callback runs.
This patch adds a 500ms timeout callback to switch to HSP/HFP when a stream
starts capturing BT audio. This avoids quickly switching from A2DP to HSP/HFP
back and forth if an application just wants to probe the BT source for a short
period of time.
See #634
Some jobs do not make sense to be run on certain cases and we can save
CI cycles that way.
Most build rules can be run only on merge requests and custom branches.
On master, it only makes sense to build fedora_with_docs for the
purpose of deploying updated documentation on gitlab pages.
The analysis steps only make sense to run when the relevant files have
changed.
The actual deduplication only checked the first device. Extend it to the
full list, as intended.
Fixes: 848b6326 (monitor-utils: Rework camera deduplication code)
The previous code made some invalid assumptions and was rather
complicated. Rework and simplify it.
The approach work as follows:
1. Once a new device gets registered, store its data in a list of pending
devices.
2. Start a timer. On timeout, we check all pending devices and depulicate
according to our heuristic. The timer gets reset whenever a device is
added in order to avoid race conditions.
3. On timeout, add the pending devices to categories. For now: UVC cameras
from the V4L2 plugin, libcamera cameras and other cameras from the V4L2
plugin.
4. Then process the different categories in order of preference and store
their V4L2 device IDs in a list for each plugin.
5. Before creating a camera, check that the V4L2 device(s) it uses are not
yet used by a already existing camera from the other plugin.
While on it, drop support for Pipewire versions that don't report V4L2
device IDs at all.
Closes https://gitlab.freedesktop.org/pipewire/wireplumber/-/issues/689
Closes https://gitlab.freedesktop.org/pipewire/wireplumber/-/issues/708
`wp_dbus_connection_disable()` creates a new GCancellable
object at the end, which is never freed if the GObject
is then destroyed. To fix this, override `finalize()` and
clear everything there as well.
Direct leak of 64 byte(s) in 1 object(s) allocated from:
0 0x70e688efd1aa in calloc /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_malloc_linux.cpp:77
1 0x70e6874b3e62 in g_malloc0 (/usr/lib/libglib-2.0.so.0+0x63e62) (BuildId: 7b781c8d1a6e2161838c5d8f3bd797797c132753)
2 0x70e6875dea75 in g_type_create_instance (/usr/lib/libgobject-2.0.so.0+0x3ea75) (BuildId: 5af5e0f7d0a900ecb6083fbd71e22e5522d872e2)
3 0x70e6875c3804 (/usr/lib/libgobject-2.0.so.0+0x23804) (BuildId: 5af5e0f7d0a900ecb6083fbd71e22e5522d872e2)
4 0x70e6875c4e7e in g_object_new_with_properties (/usr/lib/libgobject-2.0.so.0+0x24e7e) (BuildId: 5af5e0f7d0a900ecb6083fbd71e22e5522d872e2)
5 0x70e6875c5ed1 in g_object_new (/usr/lib/libgobject-2.0.so.0+0x25ed1) (BuildId: 5af5e0f7d0a900ecb6083fbd71e22e5522d872e2)
6 0x70e684d2a8a6 in wp_dbus_connection_disable ../subprojects/wireplumber/modules/module-dbus-connection.c:173
7 0x70e688a833cc in wp_plugin_deactivate ../subprojects/wireplumber/lib/wp/plugin.c:144
8 0x70e688a7126c in wp_object_deactivate ../subprojects/wireplumber/lib/wp/object.c:542
9 0x70e688a6e74e in wp_object_dispose ../subprojects/wireplumber/lib/wp/object.c:191
10 0x70e6875c0f6c in g_object_unref (/usr/lib/libgobject-2.0.so.0+0x20f6c) (BuildId: 5af5e0f7d0a900ecb6083fbd71e22e5522d872e2)
11 0x70e6841f7d6d in wp_portal_permissionstore_plugin_disable ../subprojects/wireplumber/modules/module-portal-permissionstore.c:207
12 0x70e688a833cc in wp_plugin_deactivate ../subprojects/wireplumber/lib/wp/plugin.c:144
[...]
Handle only devices associated with Bluetooth loopback nodes.
Make sure the node.link-group iteration cannot get stuck if there is a
loop in the link graph.
Revamp the profiles section, making use of the inherits feature
and add commonly used profiles for systemwide & embedded use cases,
as well as profiles for a split-instance configuration where the
policy hooks run in a separate instance from the alsa, bluetooth
and camera monitors (which run in 3 separate instances respectively)
Also add an example on how to configure the loaded profile using
a config file instead of the CLI switch.
Fixes: #608
This allows to inherit all the profile definitions of another profile
before the current profile's definitions are parsed, allowing for
more complex structures to be present in the default wireplumber.conf
without too much copy-paste
In some cases, requires/wants dependencies are not enough. As we saw in
!617, the m-standard-event-source module needs to be loaded after all
the hooks, otherwise there may be missed events that the hook was
supposed to "catch", but they were delivered before the hook was actually
loaded. In a similar fashion, we have in purpose put all the "monitor"
components at the every end of the array because if we load them earlier,
they will create devices and nodes before all the hooks are in place to
react.
While in standard configuration we can work this around, in extended
user configurations with custom components, it is impossible to do this
without overriding the entire components array.
To fix this properly, introduce before/after dependencies. They work in
a similar fashion as they work with event hooks. They do not implicitly
"pull" any components to be loaded, but they affect the ordering if the
mentioned components are indeed present.
Note that for backwards compatibility reasons and unlike systemd units,
the "requires"/"wants" targets imply an "after" dependency on them.
Fixes: #600
This allows changing the metadata name in the configuration file
and get all the Lua scripts looking at this new settings metadata
without requiring any other code changes. It can be useful in
multi-instance setups where we'd like the instances to be isolated
and load their own settings instead of relying on each other for that.
This patch removes the manually created object managers in the BT profile
autoswitch logic, and instead uses the object managers from the event source,
simplifying the logic a bit.
The intention here is to fix a Bluetooth bug where changing between different
profiles momentarily causes streams to be linked to an internal speaker.
Unfortunately, this case is not handled by the event dispatcher because some
signals are emitted using idle callbacks, and therefore we have to rely on
extra logic in rescan.lua to solve the problem.
This reverts commit 8012fbd5cf.
There seems to be some underlying bug that sometimes causes a crash
when the Bluetooth monitor uses a loopback for autoswitching between
profiles. Reverting temporarily until the cause is fully determined.
See #682
The previous assumption that any target with "device.intended-roles"
should be managed by the role-based policy is wrong, as for example
Bluetooth SCO nodes always have "device.intended-roles = Communication"
and some ALSA devices managed by ACP also do. This is meant to be used
as a hint for the desktop policy (it's been there in PulseAudio as well)
and does not necessarily mean that a role-priority-based policy should
be applied on all links to those devices.
Instead, use a new property to explicitly mark all the targets that
are meant to be managed by the role-based policy and respect that in
all places where we check for a potential role-based policy link.
Fixes: #682
This way of definining dependencies ensures that if we remove one
of the find-* hooks from the config, the rest of them will continue
to work in the expected order. Previously, removing one of them
would break the entire chain.
Also, move the example from linking.conf to media-role-nodes.conf,
as it's more relevant there, and make sure the setting is constantly
read back in the Lua script, so that runtime changes can work.
There are 2 cases captured here:
1. The stream has "stream.monitor = true", which is used
by pavucontrol for the vu meters and should probably not be managed
by the role policy, no matter if the target is a Source or a Sink
2. The stream is an Input (capture) stream and is targeting a Sink,
which may be used to target the sink's monitor ports. Even if we
want, we can't manage these links because they have opposite direction
than the one expected. Let's leave them alone...
First, add the find-media-role-target to the standard policy.
It does not affect anything and it doubles as the replacement
for intended-roles.lua, as it merely prioritizes linking nodes
that have "media.role" set to targets that have "device.intended-roles"
set to the corresponding role.
Second, make the rescan-media-role-links.lua also load as part
of the standard policy. The idea is to embrace this functionality
by default and make it available on desktops. It does not break
anything as well, but it will apply its own rules to links that
are created between nodes that have a
"media.role" <-> "device.indended-roles" match.
Regular filters should be treated as regular stream / device nodes. Note that
the filter utils API is meant to be used using the direction of the main smart
filter nodes. This is why we use the target direction instead of the actual
stream direction to check if the stream session item is smart or not.
This should never happen, but there are odd cases with broken
configuration where such a device may appear and the least we can do
is not crash, at least not when the device.name is only used for
debug messages. In state-profile and other places where the name
really matters, we actually have checks in place.
Fixes: #674
We always have to destroy the restore timeout source when we want to switch to
HSP/HFP profile, even if the device is already set to HSP/HFP or has already an
input route. Apart from this, we also want to make sure there is no pending
timeout source when we are creating a new one. This should avoid an infinite
loop about switching BT profiles when capture nodes are created and destroyed
quickly.
Indexing into the subject from a node-removed event is slightly quirky.
As a result, we were not properly freeing filter chains tied to
disconnected nodes.
Change how we store the list of loaded filters and ensure they
are properly freed when their parent node is removed from the graph.
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
If a source filter is used, the BT profile autoswitch does not work because
WirePlumber thinks there is always a client capturing audio from it. This patch
fixes the issue by recursively walking through the source filters that are
linked to the BT loopback source until a stream is found. If a stream is found
at the end of the chain, then it switches to HSP/HFP profile, if the stream is
not found, the profile stays to A2DP.
With this change, it is possible to have a top-level object that does
not start at exactly the beginning of the file, allowing comments and
whitespace to exist.
Also add an empty conf file in the tests to verify that
it does not crash.
- split merge.conf into two files, one being standard JSON,
to ensure we can parse this
- ensure that key-value pairs are correctly overriden when
merging without the override. prefix
- remove context.modules, which is no longer needed there
- fix a typo with a stray ; character
A bit of refactoring was needed in order to avoid breaking as-section
loading, which expects the entire file to be an object or array and doesn't
parse it.
Fixes: #633
In some cases the monitors emit the object_info callback with the same id
and non-NULL info multiple times. For example, when an ACP profile changes from
output:analog-stereo+input:analog-stereo to just output:analog-stereo, it emits
object_info() with NULL info for the input node and object_info() with updated
properties and the same id as before for the output node.
This causes the spa-device here to emit create-object multiple times for the
same object and this breaks the name deduplication logic. To solve this, make
sure we emit object-removed before calling create-object a second time.
Fixes#500
Copy all the node properties into the session item and customize
afterwards, instead of starting with an empty set and cherry-picking
properties... We need to cherry-pick more and more properties
overtime and it's easy to make mistakes
Otherwise it is global and it retains a reference to the `parent`
WpSpaDevice object until this function is called again, which prevents
some camera nodes - in some cases - from being destroyed
Fixes#640
At the moment, the same transition can be completed multiple times
(assuming sufficiently high reference count):
return_error()
finish()
return_error()
The consequence of that is that the transition closure will be
invoked multiple times. This is unexpected.
Add some guards against completing a transition or calling finish()
multiple times.
Fixes#628
Enhance the parsing logic to consider more than one device number. libcamera
devices some times use up multiple V4L2 devices, in this case libcamera should
be given a chance to enumerate the device.
Fixes#623
If the user is reported as active then check that they have at
least one active seat and downgrade the status to online if not.
This ensures that a remote login session won't be interpreted as
the user being active on a local seat.
Make decision on whether to show code location in journal messages based
on whether the WpLogTopic would enable DEBUG level messages.
Add wp_logt_checked API to take WpLogTopic as input to make this
possible, and deprecate wp_log_checked.
Logging messages are usually developed based on the stderr logging,
which shows code location and log topics as context, and especially
higher log level messages can be cryptic or useless without that
context.
This context is not shown in journalctl by default, and so usually is
missing from logs submitted by users. In principle it is available in
journalctl but requires extra work to show it.
Fix by prepending the log topic to the messages, like Pipewire logging
does. Also show code locations if log level is high enough.
This patch makes the check more robust when detecting main filter nodes. This is
because some filters might append '/Internal' to their main node media class.
The direction check has also been improved to work with Video filters.
event:set_data() coerces Lua tables to properties, so that keys and
values become strings. Take into account that profile.index is a string
due to this.
Fixes WP setting the profile, even though it is already the active one.
Currently nothing removes the WpLoopSource from the main context, and we
moreover are creating and attaching unused WpLoopSources when sharing
same pw_context between multiple WpCore.
Fix this by keeping track of the WpLoopSource in the pw_context user
data, only creating them when needed, and finalizing it after the
context is destroyed.
It is intended that the Pipewire loops are "entered" the whole time they
are running, i.e. are going to process further events. Currently we
enter/leave for single iterations, which is not right.
Fix by entering the loop on initial GSource idle callback, and leaving
at finalize.
That the loop has to be left from the same thread it was entered from is
a bit hard to do with GSources, as the finalize callback appears not
guaranteed to be called from any particular thread. I didn't find a
fully general way to do this, so this puts additional constraints on how
WpLoopSource (and WpCore) are to be cleaned up.
If we use the project version as library version,
it is not possible to append something to the
project version to indicate a modified wireplumber version.
Using parseBool is actually more broken if the property is already parsed as a
boolean, and causes the node to remain unhidden even when hide-parent = true.
Revert 2a45842169 to fix this behaviour.
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
Using the new Conf() constructor, we can load and parse a filter graph
from a file on disk. This is useful when, for example, maintaining a
large database of filter graphs. It also keeps wireplumber.conf.d free
from clutter.
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
Given that we are allowing Conf() to instantiate a new WpConf,
the methods on the class need to be callable in reference to Self while
maintaining API compatibility with being indexable from the table as a
static method.
Allow this by checking if the first argument passed in is userdata.
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
This exposes the ability to load a SPA-JSON representation of a WpConf
object from an arbitrary file on disk to the Lua API
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
A "plain" JSON object may be passed to WpConf constructors. Previously, this
would cause an error as open_and_load_sections expects the first parsed token
to be a string. Use WpProperties to denote that the file being parsed is an
object/container, and specify a section name for it.
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
Use WpProperties to indicate that searching for and loading
conf.d fragments can/should be skipped.
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
WpProperties may be used to control the behaviour of a WpConf
object. This allows those properties to be referenced at any time
during the lifetime of a WpConf.
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
The signature of the function is quite misleading. If an absolute
path is passed to it, it will ignore the directory constraint flags
and search outside of the specified directories anyway. Make a note
of this in its caller.
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
Global class identifiers, such as "Node", "SessionItem", "Conf", etc
are so far defined either as methods, which are constructors for
the GObject class, or as tables, which contain "static" methods, i.e.
methods that can be called without an instance.
In some cases, we may want to mix a class being both instantiatable
with a constructor and also have static methods. To support this,
allow the class identifier be declared as a table with the constructor
being defined as the "__new" method. This change allows calling the
table as a method and execute "__new" underneath.
For instance:
```
json = Conf.get_section_as_json("foobar") -- static method
conf = Conf("/foo/bar") -- constructor, equivalent to Conf.__new("/foo/bar")
```
See also !629
The cam_data structure stores a reference to the "parent" WpSpaDevice
and doesn't allow it to be destroyed when the monitor detects that
the device is no longer present. Clear it right after pushing the event
to make sure there's no dangling reference left around
Fixes: #627
We apparently store things in the <media-class>:<key>:<value>
format, while pipewire-pulse expects <media-class>.<key>:<value>
and this detail was missed in the latest refactoring.
It also seems that I forgot to ensure that restoring this metadata
key worked. The hook was there, but not registered.
Remove the hook and directly populate the metadata object when
it is activated, as it seems simpler.
Fixes: #604
The existence of props["hide-parent"] is truthy. Parse the boolean explicitly
to get the correct logic.
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
This component provides the automatic filter graph interface to consumers.
We provide the component by default, however it is not activated unless
explicitly requested in wireplumber.profiles by a consumer.
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
This allows DSP rules to be specified in a wireplumber.conf.d file under
the node.software-dsp.rules section. Properties are specified in the
software-dsp action.
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
As this DSP "policy" is intended to run on the creation/deletion
of a node, move it into the node subdir.
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
Prevously, we were only looking at node["global-properties"] for
properties to match on. Change this to instead run against
node.properties, so that we can use type-specific properties such as alsa.id.
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
The current code was not updated to use `clients_om`, thus never
found a client, ending up never sending client errors.
Just use the shared helper to avoid such issues in the future.
These errors are propagated to the caller, so it's the caller's
responsibility to print them appropriately, if necessary. Printing
a notice also here is only confusing.
A debug mesage is still be useful for developers to understand the flow.
These were documented in src/scripts/lib initially because the settings-manager
scripts used to be also there and it made sense to keep them close together.
Autoswitch should make sure the saved headset profile always has an
input route. Check this on loading/saving it, otherwise reselect it.
Headset mode profile without mic used to make some sense when it wasn't
using the loopback node (ie. easy way to disable it), but now with the
loopback node this doesn't make sense any more and it's confusing if it
occurs, so we shouldn't allow it.
Profile autoswitch should support also A2DP profiles with input route,
so the loopback should not assume the source node is SCO one.
Also fix handling of AG SCO output stream nodes, which should not be
hidden as internal.
The wp_settings_delete_all() API internally uses wp_metadata_clear() to clear
all the keys in the persistent-sm-settings metadata object. This call emits
the metadata changed signal with both 'key' and 'value' set to NULL. When that
happens, we need to clear all settings from the state file.
It is possible that a node is destroyed while the select-target
event is ongoing. In that case, the next hook to run will likely crash.
Fix this by cancelling events automatically when their subject
is a session-item associated with a node, as soon as the node is destroyed.
See !619
A smart filter should be considered "targetless" (i.e. interpose on
streams going to default target) only if filter.smart.target is not set.
Currently any smart filter with specified target not found is considered
such, which is wrong. This causes misbehavior, such as all recording
streams going to the bluetooth dummy source.
Fix this by doing it correctly.
Reset back to the session item's "configured" state instead of clearing
the si properties completely. This allows the "session-item-removed"
event to be dispatched with all the original properties of the node
intact, for constraint matching purposes.
Fixes#588
And name the loopback source node the same as bluez source without 'internal'
prefix. This keeps consistency with input/output node names when switching
bluetooth profiles.
Like WirePlumber 0.4.17, we need to mark the current routes as 'active' if they
were previously not active as soon as we detect it. This avoids a possible
infinite loop that restores the routes and saves them constantly, which happens
when the device's Route param has changed more than once before the event
'select-routes' is triggered.
The boolean values of properties in rules are strings in JSON config files and
they will retain the same type when they are translated to Lua.
Use cutils.parseBool() function when they have to be interpreted as bools.
Fixes: #586
The absence of parenthesis confuses the gobject-introspection parser
for some reason, making it emit WP_BASE_DIRS_FLAG_SUBDIR_WIREPLUMBER
multiple times in the .gir file
Define WP_USE_LOCAL_LOG_TOPIC_IN_G_LOG in project scope, so that we always
use this feature in our codebase without causing problems for other projects.
Fixes#571
This is needed for some devices that expose both Headset and Speaker nodes, so
that the applications are automatically linked to the Headset node or Speakers
node automatically when plugging and unplugging a headset.
Cache the rules in a global variable in each script, as JSON,
and use JsonUtils directly to evaluate them. This will allow us to
close the WpConf in the future after loading the scripts.
Also change the order of the return values of the match_rules_apply_properties
function to be able to easily ignore the number of changed values,
which is useless in most cases.
In some cases we need to get a section as JSON, so that we can pass it
down to the rules parser, while in other cases we neeed to get it as a
table to use it natively, and in that case we even need to differentiate
between it being an object, an array or an object with WpProperties.
Make it also possible to optionally pass tables with default values to
the functions so that we can get rid of cutils.get_config_section()
as well.
Add a new private header file, wpbuildbasedirs.h, that contains the
build-time base directories passed directly from meson, without
the "wireplumber" suffix.
Use this to set the WP_BASE_DIRS_BUILD_* and adjust the code to honor
the SUBDIR_WIREPLUMBER flag.
This removes the previous hardcoding of this suffix and allows the
functions to be useful to other projects that use libwireplumber
and want to use this code to locate their data & config.
We do not use these APIs, so there's no point in keeping them.
Realistically, every component that needs a section just does its
own parsing on it, so the _get_value() functions are not needed.
The fallback in _get_section() is also not needed, as we always
pass NULL and then test for it. In Lua, however, it seems we are
using the fallback to return an empty object, so that getting
a section does not expand to multiple lines of code. For that reason,
I have kept the syntax there and implemented it in the bindings layer.
Changes:
- Configuration files are no longer located by libpipewire,
which allows us to control the paths that are being looked up.
This is a requirement for installations where pipewire and
wireplumber are built using different prefixes, in which case
the configuration files of wireplumber end up being installed in
a place that libpipewire doesn't look into...
- The location of conf files is now again $prefix/share/wireplumber,
/etc/wireplumber and $XDG_CONFIG_HOME/wireplumber, instead of using
the pipewire directories. Also, since the previous commits, we now
also support $XDG_CONFIG_DIRS/wireplumber (typically /etc/xdg/wireplumber)
and $XDG_DATA_DIRS/wireplumber for system-wide configuration.
- Since libpipewire doesn't expose the parser, we now also do the
parsing of sections ourselves. This has the advantage that we can
optimize it a bit for our use case.
- The WpConf API has changed to not be a singleton and it is a
property of WpCore instead. The configuration is now expected
to be opened before the core is created, which allows the caller
to identify configuration errors in advance. By not being a singleton,
we can also reuse the WpConf API to open other SPA-JSON files.
- WpConf also now has a lazy loading mechanism. The configuration
files are mmap'ed and the various sections are located in advance,
but not parsed until they are actually requested. Also, the sections
are not copied in memory, unlike what happens in libpipewire. They
are only copied when merging is needed.
- WpCore now disables loading of a configuration file in pw_context,
if a WpConf is provided. This is to have complete control here.
The 'context.spa-libs' and 'context.modules' sections are still
loaded, but we load them in WpConf and pass them down to pw_context
for parsing. If a WpConf is not provided, pw_context is left to load
the default configuration file (client.conf normally).
This allows the returned WpSpaJson object to be kept around
after the parser has advanced to the next token. The behaviour
of the _new_wrap() function is to wrap the underlying spa_json*
and it breaks as soon as the parser advances.
This allows the files iterator to lookup in a specific directory
when the given path is absolute, similar to how pipewire behaves
for configuration files (e.g. /foo/bar/wireplumber.conf must
include /foo/bar/wireplumber.conf.d/*.conf).
This also allows improving the wp_base_dirs_find_file() structure to
avoid duplicated code and add a debug message easily.
This makes things more consistent and allows us also to add more
search paths in the future if necessary.
Also, stop using g_module_build_path() because it's deprecated and
build the path manually. This obviously is not portable to Windows/Mac
or other exotic platforms, but portability is not important at this
point. PipeWire is also not portable beyond Linux & BSD.
This adds support for the system-wide locations for configuration and
data files, as defined by the XDG Base Directory Specification.
In addition, it adds two flag groups, CONFIGURATION and DATA, to the
base-dirs system, so that we don't have to hard-code the combinations
of flags everywhere.
Instead, make it so that WIREPLUMBER_*_DIR environment variables can
contain a list of directories to look into. This is safer and,
as a bonus, allows for more control over the lookup directories.
Using the G_TEST_SRCDIR variable can cause problems for tests of other
projects that use libwireplumber and may also lead to unexpected
behavior by not being obvious that this causes wireplumber to skip
looking in its standard directories...
This also brings back WIREPLUMBER_CONFIG_DIR, which is going to be
needed again for the upcoming WpConf changes.
Previously files would be sorted across all configuration dirs
so their filename was all that mattered, not the priority of the directory.
Ex. you could get:
- /etc/wireplumber/10-foo.conf
- /usr/share/wireplumber/20-bar.conf
- $XDG_CONFIG_HOME/wireplumber/30-baz.conf
- /usr/share/wireplumber/40-zzz.conf
This commit changes that so that it follows the hirerachy of the directories
first and then the order of the filenames, starting from the lowest priority
directory. So now for the same files you get:
- /usr/share/wireplumber/20-bar.conf
- /usr/share/wireplumber/40-zzz.conf
- /etc/wireplumber/10-foo.conf
- $XDG_CONFIG_HOME/wireplumber/30-baz.conf
In addition, the hash table is avoided, making things a bit more efficient
and the files are checked for G_FILE_TEST_IS_REGULAR
Shadowing of files still works the same, so in the above example
if /etc/wireplumber/30-baz.conf also exists, it is not returned
in the list, because it's shadowed by $XDG_CONFIG_HOME/wireplumber/30-baz.conf
This patch improves module-settings to load the settings schema into a
'schema-sm-settings' metadata for clients to know what values types and range
are accepted for each particular setting. This settings schema is defined in
the wireplumber.conf, under a new section called 'wireplumber.settings.schema'.
This doesn't need to be a singleton, since we have the core registration
API available publicly nowadays. Makes things more clean for the API,
following the pattern of WpPlugin and WpSiFactory and simplifies the
built-in settings component in the internal component loader :)
Similar to 'default.audio.sink', a setting from sm-settings should never be
removed when the associated persistent setting is removed. Only settings from
persistent-sm-settings can be removed, like 'default.configured.audio.sink'.
Do not send an error to the client when the target is not defined
and the 'node.linger' property is set.
It is not absolutely necessary that every node has a defined target.
We can have a 'Stream/Output/*' node which can be linked to
multiple 'Stream/Input/*' nodes and only the 'Stream/Input/*'
nodes have a defined target.
This patch removes the 'settings.persistent' option from the configuration as it
only allowed making settings persistent globally instead of individually. This
issue has been addressed in a simpler way by creating a 'persistent-sm-settings'
metadata. If a user wants to make a setting persistent, he can change the
'persistent-sm-settings' metadata object, if the user does not want to make a
persistent change, he can use the 'sm-settings' metadata object. Any changes in
the 'persistent-sm-settings' metadata will be also reflected in the 'sm-settings'
metadata object.
This is because 'filter-forward-format.lua' only configures nodes, and therefore
does not have anything to do with the linking logic. The setting has also been
renamed to 'node.filter.forward-format'.
This is because the associated node does not exist anymore. This change also
logs the session item Id when handling it, so that it is easy to know if the
unhandled session item was handled or not.
Since the loopback bluetooth source node is meant to be always used by
applications, this change hides the actual bluez sco-source node by marking
them as internal. This avoids showing 2 input devices in pavucontrol per BT
device if HSP/HFP profile is enabled.
When running multi-instance setups or when clients like wpctl want to
access the WpSettings instance, it makes no sense to load the entire
module-settings, which will also create sm-settings metadata instances.
This hides the loopback stream node from applications, making desktop
environments to not show the 'recording from microphone' icon (Eg gnome-panel)
when the bluetooth device is not recording yet.
This patch improves the bluetooth profile autoswitch so that it works with any
application that wants to capture from a bluetooth device. To do so, a loopback
source filter is created per connected bluetooth device. If an application wants
to capture audio from such loopback source filter, the profile in the associated
bluetooth device is changed to HSP/HFP. If there isn't any application connected
to the loopback source filter, the profile switches back to A2DP.
The 'target.dont_move' property is only meant to be used with 'target.object'
metadata property, not smart filters metadata properties. This was probably
left accidentaly unused when designing a solution for #524 involving smart
filters.
Fixes#558
Change design of WpLogTopic so that it allows for changing their log
levels at runtime.
Add wp_log_topic_register/unregister functions to track lifetime of the
topics.
Auto-register statically defined log topics.
Make the topic registration threadsafe, in case it is done from
constructors that run in a different thread than main thread.
This patch adds to wireplumber code to manage the Snap audio
permissions.
SNAP containers have two main "audio" rules:
* audio-playback: the applications inside the container can
send audio samples into a sink
* audio-record: the applications inside the container can
get audio samples from a source
Also, old SNAP containers had the "pulseaudio" rule, which just
exposed the pulseaudio socket directly, without limits. This
is similar to the current Flatpak audio permissions.
In the pulseaudio days, an specific pulseaudio module was used
that checked the permissions given to the application and
allowed or forbide access to the pulseaudio operations.
With the change to pipewire, this functionality must be
implemented in pipewire-pulse and wireplumber to guarantee
the sandbox security.
The current code checks for the presence of the pipewire.snap.id
property in a client, in which case it will read the
pipewire.snap.audio.playback and pipewire.snap.audio.record
properties, and allow or deny access to that client to
the nodes with Audio/Sink or Audio/Source media.class
property.
See !567 and pipewire!1779
This property indicates whether the filter can be directly linked with clients
that have a defined target (Eg: pw-play --target <filter-name>) or not. This can
be useful when a client wants to be linked with a filter that is in the middle
of the chain in order to bypass the filters that are placed before the selected
one. If the property is not set, wireplumber will consider the filter not
targetable by default, meaning filters will never by bypassed by clients, and
clients will always be linked with the first filter in the chain.
Fixes#554
This patch fixes the policy to not link the client to the default filter if the
client's defined target is found, is not a filter, does not have any other
filters linked with it. In this case, the client is therefore linked to the
actual defined target. On the other hand, if the client's defined target is a
filter, the client is linked to the first filter in the chain that has the same
target as the defined filter's target.
This is a copy/paste from the code that now lives in apply-routes.lua,
but there is no point since the route here is a real route param and
not a route_info structure.
When a manual change is applied, the store-or-restore-routes is the only
hook that gets executed for this event. In order to be able to test if a
route was changed, we need to reset all of them to 'active = false',
record the previous value of 'active' and test their difference.
Testing only the 'active' variable (and discarding 'prev_active') sounds
tempting here, but if a route is changed back and forth (from A to B
and back to A), there is nothing to reset the 'active' variable of A
when it gets deactivated and it will appear as previously active on
the second switch.
Related to: #551
Add command for changing log level for Pipewire or Wireplumber daemons
at runtime.
It can be done with pw-metadata, but make it easier so that the user
doesn't need to look up Wireplumber client ids.
Pipewire server uses the global "settings" metadata for adjusting its
own log level.
Make it a convention that clients may watch "log.level" in this metadata
with their client id as subject, for setting their own log level
dynamically.
Watch the global "settings" metadata for "log.level" changes for our id.
On changes, set our log level accordingly.
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
Previously the package version used for the gir file was hardcoded and did not change
when the `wireplumber_api_version` definition was changed, which has now been fixed to
use that definition.
* add a new common-utils method to get configuration sections with
defaults more efficiently and with less boilerplate
* rework the ALSA reserve-device settings so that the priority is
configured per device using rules and the application name comes
from the WpCore instead of the config file
* rename bluetooth to bluez in all options for consistency with other
monitors that use the backend API name
* rename alsa.midi to alsa-midi for consistency with bluez-midi
* rename settings to make more sense
* split out monitor settings into a separate category
* add setting for restoring the default nodes in the node category
It is possible that during this process some object managers emit
their "installed" signal, and it is possible that some object managers
are destroyed within the handler of this signal, ending up with a dangling
object manager pointer (since we do not ref object managers in the registry)
and with a modified object_managers list during iteration...
Related to: #534
Currently, if the adapter node already has its ports configured when wireplumber
starts (For example a virtual node), the async _set_ports_format() call is never
completed because the node ports have not changed, stalling the event stack.
This fixes the issue by checking the Props param after configuring the ports,
and completes the task if there is one pending and the node already has ports
available.
Fixes#527
This allows loading objects on demand by adding entries on the
"sm-objects" metadata object.
It is useful to dynamically load pipewire modules such as loopbacks
or network modules without having to start a new pipewire process with
a hardcoded config file.
It is also useful to load new metadata objects in order to implement
the singleton metatada concept as discussed in pipewire!1742
This may be expanded in the future to be able to load other types of
objects.
The key name, combined with the subject, is considered a unique id for
this instance of the object. The value should be a json object with
a 'type' specifying the type of object, together with a 'name' and 'args'
While handling endpoints, first check to see if there is a filter
intending to connect to it.
Also prevent Endpoints connecting to filters unless otherwise
configured.
Equalizer Node or filter nodes are considered as regular linkable and
its output is connected to endpoint. Prevent this by skipping over
filter nodes in this script.
This is a behavioural change in effect since pipewire 0.3.68, where
pipewire's link-factory ignores the link.passive property and the
node.pasive = in/out/true is used instead.
* prefix all settings with just "linking."
* rename settings to make more sense
* fix the handling of the "follow" setting
* move the "move" handler to the rescan.lua script, as it's just a rescan hook
The "follow" setting was never really meant to disable reacting to
default target changes. It is also not meant to disable moving normal streams
to follow the default target. It is only meant to control whether streams
with a 'target.object' that matches the default target will move or not
to follow the default target changes (PulseAudio compat thing...)
Even if we leave this code here, disabling the "follow" option may disable
reacting to default target changes, but the streams will be moved anyway
when there is some other change in the graph (i.e. in the next rescan)
* prefix all settings with "node."
* move settings-stream.lua to settings-node.lua
* move the "audio-no-dsp" setting to the node settings
* add more settings related to node features
* split the default stream volume into 2 settings, one for playback
streams and one for capture streams
The vm.node.defaults logic which was inherited from p-m-s is not really
good because it seems like different VM hardware requires different
values for the defaults. Also, passthrough USB hardware should not
inerhit these values, they just cause trouble.
Instead, we can use rules to match the vm.type and specific device
properties to set a more informed period & headroom.
For now, I am also decreasing the default headroom down to 2048, which
works for me and perhaps it's a good default. We can always add more
rules here and fine-tune per vm type and virtual hardware.
See !394, #316, #348, #507, #162, pipewire#3452
This is a new rules section that allows defining rules to modify
component definitions. This is useful to add repetitive dependencies,
for example, as in the case of "type = script/lua" that always requires
the "support.lua-scripting" feature. This can also be useful to modify
other component properties, such as the arguments, in overriding
configuration files, without needing to redefine the whole components
section.
The previous naming convention was confusing because it did not make
it explicit that the string is not being copied. We had this wrong already
in the Lua bindings and thanks to some miracle it hasn't backfired so far
(it was using the "wrap" behaviour with a string that doesn't stay alive).
In some places we actually need the "copy" behaviour and in some other
places we need the "wrap" behaviour, so let's have both variants available.
Do not continue iteration over all other profiles when
we found the profile set in the 'device.profile' property.
In other case we would overwrite this profile when
we find a best_profile.
This allows partially parsing a json object, allowing some parts to be
passed on as strings to another component that does its own parsing
(ex. a pipewire module)
Sometimes, it may be necessary to pass arguments in to a
Pipewire module being loaded. Allow this to be done using
the same format as load_module()/load_optional_module().
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
Note: this requires all existing config files to be modified to follow
pipewire's rules syntax, with an "actions" object wrapping the
"update-props" object.
The purpose is to wrap some utilities that pipewire provides that use JSON.
Start by wrapping pw_conf_match_rules(), which despite its name, it has nothing
to do with the configuration object. It operates directly on JSON and can be
useful to work with match rules outside the context of configuration files.
update the module-rt description and commented-out defaults to
reflect the addition of utilisation clamping to the module.
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
This is needed for wireplumber to start up correctly in the meson
devenv when built as a subproject of pipewire. The reason for this
is that the value set for `PIPEWIRE_CONFIG_DIR` in the wireplumber
meson build file will be overriden when the pipewire meson files
set up another devenv with its own `PIPEWIRE_CONFIG_DIR`.
When set to 'true', the node will remain alive without any error produced if
it cannot be linked to its specified target; in all other cases, an error will
be produced and the node will be destroyed.
Two new properties are available to change the behavior of the linking policy:
- target.dont-fallback: when set to true, the node shouldn't be allowed to
fallback to another available target other than the one specified in the
target.object property or metadata.
- target.dont-move: when set to true, wireplumber should ignore the
target.object metadata, so that it isn't possible to dynamically move the node
to another target using metadata.
See #524
Calling functions on test server must lock the thread loop, otherwise
the concurrency causes corruptiont in module-protocol-native and you get
bogus messages etc.
some hardware devices are never supposed to be accessed directly by
clients, and are designed under the assumption that they will be
front-loaded by some sort of DSP. add a hide_parent property
to policy-dsp and revoke all permissions to the bound node of a DSP
graph where this is set to prevent hardware misuse or damage by poorly
behaved/configured clients.
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
Try to connect to the default manager remote, before trying the default
remote.
Check libpipewire version is new enough to support setting arrays.
Bump Pipewire version to have pw_check_library_version.
Previously, the `deps` variable was reused for parsing
the required and wanted dependencies of a component,
which lead to the old value allocated here:
if (wp_spa_json_object_get (json, "requires", "J", &deps, NULL)) {
being leaked when a bit later
if (wp_spa_json_object_get (json, "wants", "J", &deps, NULL)) {
succeeded.
Fix that by using two separate variables.
This will completely clear all the default nodes (current and previous ones)
if the configured metadata value has been set to NULL. This is needed so that
the 'wpctl clear-default' command completely clears all the default nodes state.
This patch improves the smart filters unlinking logic by only unlinking smart
filters that are disabled, instead of any kind of filters. The patch also
removes redundant filter hooks.
This reverts commit 2ae1b3cbd9.
This is not a good API. It was only allowed temporarily in 0.4.15
to get things done. We should approach this properly in 0.5
This reverts commit 9def3f96d2.
This was never a good idea, as it turns out. It was not used in practice because
it was breaking other things (see 370b692933)
and now it appears to be causing more problems in Lua object managers that don't
install because they are waiting for inactive links to become active.
Fixes: #518
A core sync is not really necessary here because whatever objects the remote
pipewire daemon has to announce have already been sent to us on a message
and this message is already being processed at this point. This means, we are
not going to be returning to the main loop until all the new objects have been
announced and therefore placed into the tmp globals array. So, we can also use
an idle callback and achieve the same effect of slightly delaying until all
new globals have been announced.
With an idle callback, we can be more agile and add those new objects immediately
after the message has been processed instead of waiting for a pw_core_sync()
reply, which will come in the next message.
This fixes an odd failure of the si-standard-link test after applying the fix
for #517, which was caused by the fact that the test was previously relying on
a delay caused by some unrelated globals being prepared in the object manager
that tries to verify the graph state. After those globals were removed from the
internal preparation queue, the test would fail to detect the link objects
because they were stuck in the tmp_globals array for too long.
With the previous check, any global matching either the type or the global
properties of the interest would be considered for inclusion in the object
manager and would be prepared only to fail the same check later.
The correct way to check is (variable & (X|Y) == (X|Y)), which is what
SPA_FLAG_IS_SET() expands to.
Fixes#517
This is already done for `WpDaemon` and `WpExec`, so let's do it
here as well. This prevents some memory leaks in error paths,
which makes it easier to find real issues in the ASan output.
This patch updates the deprecated policy-bluetooth.lua script so that it works
with the current version. The script has been moved into the device sub-folder,
and renamed to autoswitch-blueooth-profile.lua. The settings-manager is also
used for the configuration, and the actual configuration has been moved from
linkind.conf to bluetooth.conf.
Handle client-requested and flatpak access on the session manager side.
Pipewire daemon doesn't know about the intended permission hierarchy, so
it is better done on the session manager side, where all the rules are.
The "default" access is used for normal clients, in the use case where
Pipewire server will not assign permissions itself but leaves it to the
session manager. In this use case only session manager has
"unrestricted".
Make "default" equal to "unrestricted" in the default access
configuration.
In conf_apply_rules, check input argument is a table before assuming it
is and potentially crashing.
Add check also in wplua_table_to_properties to avoid similar bugs.
This allows users to enable/disable smart filter policy per filter. The property
is considered false by default, meaning that smart filter policy is disabled for
all filters by default.
I don't fully remember where this originates from, but it looks like
some sort of hack to workaround a race condition where the event handler
would try to iterate over items that were just created and were not yet
fully ready to be used.
Since all scripts run in a sandbox with their own global environment,
it means that they don't interfere with each other's global variables.
Therefore, all file-wide variables can be declared global without
any change in behavior. In my understanding, it is better to do so
because this means that any code accessing those variables is going
to access them directly from the global environment table with a simple
lookup rather than having each variable referenced in the local closure
of each function separately.
The filter's destination target was not being found properly due to iterating
the matching rules table with ipairs instead of pairs... the later is meant to
be used with JSON objects. In addition, the filters were not being re-evaluated
and linked properly when a device node was removed, this is because of a typo in
the find-best-target.lua script.
See #501
This solves the problem of linkables not created for libcamera nodes. It makes
sense to run monitors towards the end when rest of the system is really
waiting for them.
not all functions in glib returns a value for the used log fields
in this case a 'g_return_val_if_fail(..) will only set 4 fields an
set the other field to NULL which leads to a segfault
Jul 22 13:41:37 Cynap-Pro-01121508 systemd-coredump[7247]: Process 496 (wireplumber) of user 4242 dumped core.
Stack trace of thread 496:
#0 0x00007f6b2ce58e99 __strlen_avx2 (libc.so.6 + 0x150e99)
#1 0x00007f6b2cf3ebe5 g_log_writer_journald (libglib-2.0.so.0 + 0x5fbe5)
#2 0x00007f6b2d0a9316 wp_log_fields_write_to_journal (libwireplumber-0.5.so.0 + 0x2b316)
#3 0x00007f6b2d0a96f5 wp_log_writer_default (libwireplumber-0.5.so.0 + 0x2b6f5)
#4 0x00007f6b2cf3cf3e g_log_structured_array (libglib-2.0.so.0 + 0x5df3e)
#5 0x00007f6b2cf3d0ae g_log_structured_array (libglib-2.0.so.0 + 0x5e0ae)
#6 0x00007f6b2cf3d4b7 g_logv (libglib-2.0.so.0 + 0x5e4b7)
#7 0x00007f6b2cf3d7ef g_log (libglib-2.0.so.0 + 0x5e7ef)
#8 0x00007f6b29efafef get_node_by_id (libwireplumber-module-cb-ipc.so + 0x24fef)
#9 0x00007f6b29efb032 wp_cb_ipc_get_app_properties (libwireplumber-module-cb-ipc.so + 0x25032)
A profile is a list of features set to required/optional/disabled
which governs which components are getting loaded, given a static
components list with well-defined dependencies
These tests are meant to catch wireplumber issues, so the libpipewire
logs are not very interesting and just make it hard to go through
the interesting bits
Each component can now list required and optional dependencies,
using the component feature names to match other components.
In addition, each component feature can be declared as required, optional
or disabled, making optional components easier to deal with.
The component flags (ifexists, nofail) have been removed.
Using virtual components, this system also allows easier customization
of which components should be loaded for a specific configuration,
without requiring the user to copy the list of components and edit it.
Also bump the required glib version to 2.68 for g_assert_cmpstrv()
This allows registering arbitrary objects on the core's registry and
finding them later, without having to add API for each and every object.
I think this is useful enough to have it public, even though it's
probably not going to be used that much... The rationale here is to
allow registering custom component loaders without having to make them
subclass WpPlugin or to create custom API for registering component
loaders specifically.
Also, remove the wp_plugin_register() and wp_si_factory_register()
functions, since they are not going to be used much in the future.
The idea is to let the component loader do the registration under the
scenes, as the component is getting loaded.
Each component can optionally "provide" a feature, which is basically
a string that describes the feature (ex. "support.dbus"). If the
component loads successfully, the feature is marked as provided and
can be tested for its presence with wp_core_test_feature()
Now that we have proper module load order, we can have this shared
dbus connection in a module instead of the library. The module has
to be loaded before any other modules that need it, obviously.
There is no reason to return the component object... all components
are supposed to be long-lived objects that are referenced by the
registry and there is API to find them. The caller is only interested
in the success or failure of the operation.
Do this in wp_core_load_component() and let the component loaders worry
only about creating the object.
Also run the main loop in tests while loading components, to ensure
that the async operation finishes before continuing execution. GTask
makes sure to make the operation async always, by emitting the callback
from an idle GSource.
Regarding the core parameter, the case used to be that WpComponentLoader
was a WpPlugin, so it had a reference to the core internally, but since
this is no longer a requirement, we need to pass this explicitly
converting a spa log level to a native log level is not trivial, it seems;
when we want to print a message, we should map 2 (WARN) to W, but when we
want to translate WIREPLUMBER_DEBUG=2 to a log level, we should map 2 to N
Syslog calls this level "notice" and I prefer it because we use it
to display significant messages that are not warnings, but they
are not really "standard", as GLib wants them to be. There is nothing
"standard" about log messages in general.
Also, make these notice messages be enabled at debug level 2, together
with warnings. The default log.level is 2 and it is a good idea to show
notices by default too.
Finally, show them in the log with "N" and also change criticals to be
shown with "E", meaning "error"... Then promote G_LOG_LEVEL_ERROR
messages to be shown with "F", meaning "fatal", because in fact these
messages are always fatal and always call abort(). Still, keep the term
"critical" in the functions to make sure that whoever uses them is aware
that this level is only for critical conditions and not suitable to
display any kind of error.
This topic contains traces to debug the pipewire socket protocol.
Adding this pattern allows WIREPLUMBER_DEBUG=5 to show everything
except this trace by default, which is a more reasonable amount
of trace. To enable it, it must be explicitly specified in the
WIREPLUMBER_DEBUG env variable.
* initialize all log-related features in a new wp_log_init() function
* remove the ability to change the log patterns later, as the log
topics are not referenced by the log system and there is no way to
re-initialize them with different levels (we can still implement this
in the future, if necessary, though)
* introduce the notion of a "global log level", referenced by all topics,
and make the topics know if they have a custom level or not, like in
pipewire; this is necessary to be able to set the level in the config
file, which is read later by pw_context / WpCore.
This allows lua scripts to work with log topics. A topic must be
opened at the top of the file, in global scope, and subsequently
all log commands should be executed on the returned object instead
of the Log global table
The intention is to make checks for enabled log topics faster.
Every topic has its own structure that is statically defined in the file
where the logs are printed from. The structure is initialized transparently
when it is first used and it contains all the log level flags for the levels
that this topic should print messages. It is then checked on the wp_log()
macro before printing the message.
Topics from SPA/PipeWire are also handled natively, so messages are printed
directly without checking if the topic is enabled, since the PipeWire and SPA
macros do the checking themselves.
Messages coming from GLib are checked inside the handler.
An internal WpLogFields object is used to manage the state of each log
message, populating all the fields appropriately from the place they
are coming from (wp_log, spa_log, glib log), formatting the message and
then printing it. For printing to the journald, we still use the glib
message handler, converting all the needed fields to GLogField on demand.
That message handler does not do any checks for the topic or the level, so
we can just call it to send the message.
Previously we were mapping SPA ERROR to GLib WARNING and
SPA WARN to GLib MESSAGE, which has been causing some confusion.
After some careful consideration, it makes sense to change that and
leave the GLib MESSAGE level as something to be avoided. With that
change, WIREPLUMBER_DEBUG=M will still enable the MESSAGE level,
but WIREPLUMBER_DEBUG=2 will only enable the WARN level and it will
take WIREPLUMBER_DEBUG=3 to enable both the INFO and MESSAGE levels.
This keeps the original head pointer intact, so that we can effectively
free the list later. If we use the head pointer to iterate, then at the
end we are not freeing anything because the pointer is NULL
This should be considered a configuration error: the user has
specified some component in the config file that cannot be loaded.
Changing the configuration file should fix it.
Since the wireplumber configuration has been moved to /usr/share/pipewire, it
does not makes sense to have a different path for the WIREPLUMBER_CONFIG_DIR
environment variable. Therefore, the WIREPLUMBER_CONFIG_DIR environment variable
has been changed to just be an alias of PIPEWIRE_CONFIG_DIR. Finally, Lua
scripts are now installed under /usr/share/wireplumber/scripts instead of
/usr/share/pipewire/scripts as they are a wireplumber feature only.
This change completely refactors the way components are loaded in wireplumber:
- The module_init() function must return a GObject now. This object is either
a WpPlugin or a WpSiFactory in the current modules.
- When the component loader initializes a module, it automatically registers
the WpPlugin or WpSiFactory with their respective methods. There is no need
to register the WpPlugin or WpSiFactory in the module now.
- The wp_core_load_component() API has been refactored to be asynchronows. This
allows the component loader to automatically activate WpPlugin objects, and
therefore allows the application to directly get the WpPlugin without having
to find it. This simplifies a lot of things.
- The 'ifexists' and 'nofail' component flags now work even if the respective
WpPlugin could not be activated.
- The code that loads components in main.c has also been simplified a lot,
and the option to load dangling components has also been removed.
This removes both the policy-virtual-client.lua and policy-virtual-device.lua
scripts, and creates a new linking/find-virtual-target.lua script to link
clients with virtual session items if one of them can be found. In addition to
this, this patch also ports the policy-virtual-client-links.lua into a new
scripts/rescan-virtual-links.lua to use the event stack. The idea is for the
scripts/link-target.lua to create all links but only activate non virtual links,
and for the scripts/rescan-virtual-links.lua to activate/deactivate virtual
links based on role priorities.
This patch also moves nested configuration objects that are not considered
settings from the wireplumber.settings section to its own configuration
section (eg the rules array, the spa plugin properties, etc...). This allows
those objects to be merged with other same sections defined in other files.
When in error, attempt to execute a step called "error", if it exists.
This is rarely needed, but it might be useful in some cases to cleanup
some state, rolling back changes, when something fails.
This allows for Lua test scripts to be grouped into a label. So that they can be
treated different in terms of the init infrastructure that the script-tester
lays out for those tests.
Call the event "rescan-for-<context>", where <context> is either
"linking" or "default-nodes" and can be expanded in the future.
Add an additional hook in default-nodes to trigger the
rescan-for-default-nodes event when sources and sinks come and go.
Use the directory name and file name to construct the hook's name,
like a path. This way, when you see a hook name, it is clear where
to find that hook in the source code.
* client: Logic that deals with configuring clients (basically, permissions)
* device: Anyhing that that deals with configuring devices (profiles, routes, ...)
* node: Anything that deals with node objects: configuring nodes, changing
their state, their properties and also creating new nodes (but NOT linking them)
* linking: All the logic for creating links between nodes (and obviously,
deciding which links to create)
* monitors: Scripts that deal with hardware subsystems, mainly monitoring
hardware changes and reflecting them on pipewire
* default-nodes: All the logic for selecting the default sinks and sources
When the core is shutting down, the weak reference to it is cleared before
we have a change to use it, but it's ok because everything is getting destroyed
at this point, including the hook that we want to unregister.
But keep the additional comments and debug statement improvements.
Also, merge the stuff from common.h, which was previously shared
with m-default-nodes.
* Use more hooks and no custom object managers
* Use the settings manager for the config values
* Allow fully disabling the hooks when both restore-props and restore-target
are disabled in the settings
* Change the format AND the name of the state file; use json directly
in the values now that we can
* Remove entirely the hook priority numbers and use before/after dependencies
* Split the WpEvent code out of WpEventDispatcher
* Add methods on WpEvent to interface with it from the WpEventDispatcher.
As a bonus, we can now also implement tooling to inspect which hooks would
in theory run for an event and write tests around that
* Removed some internal debugging facilities and log calls, will redo it later.
* Using spa_list now for the list of hooks, to reduce the number of allocations
happening in the "hook collection" algorithm
* Switched some internal data to use g_new0 instead of g_slice_new0
* Added g_free to free WpEvent structures... surprisingly, we were leaking them
before
It is better to have type-specific event names to minimize the amount
of constraint string matches we do on hooks, as most hooks (if not all)
are interested on specific types of objects only.
Similarly, use a different object manager for each object type to
minimize the performance impact of iterations and lookups, as all
such actions are interested in only 1 object type every time.
Port all existing hooks to the new event names and the get-object-manager API.
This avoids having to determine the subject type prior to pushing
an event from lua code and makes the call more convenient
Also add a debug statement to trace calls to push_event
* Use a common function to unwrap the objects out of the event
* Use the same common function to get the si flags
* Do not store back the si flags - there is no point in doing that,
tables are objects in lua and they are passed around by reference
* Store the target on the event
This can be used anywhere else in the codebase to push a "rescan-session"
event, making sure that there is only one such event pushed on the stack,
no matter how many times this is called.
Hooks need to have a priority relative to the event they are executed on,
so it does not make much sense to have all kinds of different priorities
based also on the event type and/or the module where they are defined.
Also, it wouldn't be acceptable to have such an enumeration on the public API.
After the creation of metadata with config data, m-settings will also need to
trigger the init of WpSettings Object/API. Earlier this was done in main.c as
part of init transition but the logic there is much more generalized now and so
it has been moved here.
- Support `priority` tag in definition of wireplumber components in json
config files.
- Support loading dangling components. These are components which are
NOT present in the json config files but present in the wireplumber
lookup folders.
- Simplify the init transition by removing the unneeded steps.
-Scripts loaded with wpexec will also need 'module-standard-event-source'
to be able to convert the pipewire signals to wireplumber events.
-Simplify the init transition states.
after-events-with-event hooks are rendered based on the priority, this means
when a rescan event happens, all the findDefinedTarget hooks(of different
session items) are run first and then all the findDefinedTarget hooks, so on.
This kind of scheduling of hooks was removing the established link between zoom
voice engine and digial mic. Also It is slightly difficult to follow the flow in
the logs.
Instead of arranging the hooks flately based on priority, better scheme to
prioritize them in two layers. First all the hooks for an event or session items
are grouped and with in that group, priority of the hook is honored.
src/scripts/policy-hooks.lua # modified: src/scripts/policy-node.lua #
Most of the configuration settings have a default value when they are loaded by
the Lua scripts if they are not present, so we leave them commented in the
configuration. This will make the configuration smaller when supporting layered
configuration, as all the commented sections will be part of the override files.
- Sharpen the hooks, so that they are called only when needed.
- Make settings live, apply them when they are changed.
- Remove the state saver after events hook, call it directly.
- Remove the settings bookkeeping as the gobject properties.
- Remove the scheduling of default-nodes-changed signal via core.
We cannot guarantee that the object's bound-id is always valid when an event is
triggered, especially when an object is removed. This patch uses the new object
wireplumber unique ID to index Lua tables, fixing runtime WP_PROXY_FEATURE_BOUND
check warnings.
The callback for the last test was getting called with non-string type and this
fails the test. fix it by sending string in correct format.
This test failure was not failing the "make test" this is known limitation in the test
setup. The limitation here is only with the last assert statement.
- WirePlumber Lua now facilitates Lua libraries/modules, utilize this and create
modules. Add some tests around this functionality.
- Create policy-hooks.lua containing all the hooks to find-target events
- Create policy-utils.lua module and push all the policy utility functions to it.
- Create common-utils.lua module and push the common utility functions to it.
- Remove all the above functionality from policy-node.lua and clean it up.
- remove scheduling rescan via core APIs instead use the event stack for proper
scheduling.
- The rescan & handlelinkable hooks will push new findTargetSiAndLink events one
per session item.
- Register a new "after-events-with-event" hook for findTargetSiAndLink event,
it runs with lower priority than the rescan hook and so rescan hook can cancel
unneeded findTargetSiAndLink events.
- Register hooks for move and follow properties.
after-events hooks are instantiated with rescan event, not with the event which
actually triggered it. after-events-with-event fills this gap.
policy-node clean needed this kind of hooks.
They is really no needed with the new _get() API and the WpSpaJson API. In C,
users can use 'wp_spa_json_parse_{boolean|int|float|string}()' APIs to parse the
WpSpaJson. In Lua, users can just do 'Settings.get(setting, m):parse()'.
We need to use WpSpaJson to parse the values in WpSettings. This is because the
wireplumber configuration is written in JSON, so WpSettings should only hold
JSON values. To fix this, 2 API changes have been done:
- wp_settings_get_int() only accepts gint values, instead of gint64 values. This
is because the WpSpaJson API only parses int values, like spa_json_parse_int().
- wp_settings_get_string() now returns a newly allocated string, this is because
the string needs to be decoded in case it has quotes.
after-events hooks will get the original event triggering it, instead of the
rescan event.
after-events hook can register with any event, but it is called with rescan event
info. This is so because, after-events hook run after all the on-events hooks
are done with and as a part of the rescan event. so it is triggered with rescan
event data, which doesnt carry much info, instead of rescan event, it makes more
sense to call the after-events hook with the original event which triggered it.
This scheme provides for an orderly execution of hooks as the priorities
are controlled from one single place. Enumeration is defined in such a
way that new items can be added easily.
All the event hooks are changed to get the priorities from this
enumeration.
- Add a new variable "name" in WpEventHook and use it to log all the
hooks(by name) picked up in _push_event(). This gives a clear picture
if hook is registered for a given event.
- Form a name for an event and a chain of events for an event run, log
both of them. This gives a clear picture of the events executed and
order in which they are dispatched.
- Similarly build hooks chain and print it in _source_dispatch(), this
gives a clear picture of the hooks picked and the order in which they
are dispatched.
- Log only the dispatchable(with hooks) events, this de-clutters
the log messages.
While calling async execute closure, take a reference to the WpEvent
object before pushing it to the Lua stack. Otherwise Lua garbage
collector frees it, which leads to invalid memory access.
- the source shouldn't become ready if there is nothing to do,
otherwise idle sources do not run (since they have lower priority)
- when the source becomes ready, we need a fd to wake up GLib's event
dispatching mechanism to continue processing, otherwise nothing happens
Add a null check when iterator gets the value to detect the end of the
JSON object, this will ensure the rest of the code that operates on the
value is bypassed.
Still it must be noted that an empty setting screws up the following
settings and behavior is undefined, this is the limiation in the
spa-json parsing.
- Create policy-settings.conf and move all the policy settings to it.
- Change all the policy scripts to fetch the settigs from WpSettings
API.
- Remove all the references to config/lua.
- Move the endpoints defination to wireplumber.conf under a new section
in the form of two JSON objects, namely endpoints and
endpoints-roles.
- Treat the endpoint objects as settings, for the sake of loading,
parsing and querying.
- m-settings loads the objects and WpSettings parses them as any other
settings.
- Make the following changes in endpoint scripts.
- Get the endpoint settings using the _get_string() API.
- Parse and use the data.
- Remove references to the config/lua
- Remove the endpoints defination in config/lua
- Monitor to use the JSON APIs and move away from config/lua
- Enhance logic in wpsettings to parse settings which are JSON arrays,
some of the bluetooth properties are JSON arrays and parsing
logic confused them for a rule.
- Add corresponding tests around this logic as well.
- switch stream based lua script and their configs to wpsettings,
remove all the config/lua references
- move last remaining scripts and modules from 90-enable-all.lua to
wireplumber.conf
- delete all files in main.lua.d
- add integer and string version of the APIs,
- Also Refine the APIs, return value to indicate the setting existance
and a new param to return the value of the setting.
- add their lua bindings as well, in lua binding the return value nil
indicates that the setting is not defnied.
- Add corresponding C and lua tests as well.
- Add a few handy debug msgs.
- support loading modules dependent on wireplumber settings in JSON
config.
- load the settings module before parsing wireplumber.components,
so that dependencies can be fetched during parsing.
- access lua scripts are switched to JSON based config and lua configs
are removed.
- unlike pipewire, rules will be parsed during the bootup time, i.e
during the creation of the wpsettings object.
- The rules are parsed into the wpinterest objects and stored in the
wpsettings object, they will be eventually used to service the
apply_rule() API.
- Support pipewire syntax of rules defination in this version.
- settings.c tests conf file loading & parsing, metadata updates,
wpsetttings object creation and its API.
- settings.lua tests the API from lua scripts.
- Add a sample settings.conf file, this file contains sections copied
over from client.conf along with the settings section. Add a file
each for wp side and lua side of scripts.
- Make changes in base test infrastructure to take a custom conf file.
- Enhance the wp_settings_get_instance_api() to be take metadata_name
parameter. So, Wpsetttings is now a singleton instance for a given
metadata file.
- Enhance the m-settings module also to be take metadata_name parameter.
this is handy for lua side of tests as its cumbersome to do this is
lua.
- WpSettings is a singleton object which attaches itself to the core
and registry, it provides a get_instance () for its clients.
- WpSettings provides API to get/set wireplumber settings and rules.
- main.c loads the new object and makes sure it is available for
for all the modules and scripts. This is achieved by introducing
a new activation step.
- Add the lua bindings for get_setting API.
- parse settings from .conf file.
- create "sm-settings" metadata and copy settings as key value pairs
to it.
- put in place "persistent" behavior, control it with a special
setting.
- when persistent behavior is enabled.
- create a state file and update settings to it.
- monitor changes in the metadata and update the settings to state
file.
2023-04-17 07:44:19 -04:00
486 changed files with 45186 additions and 15708 deletions