Merge branch 'master' into next
This commit is contained in:
commit
c2d125b0da
75
NEWS.rst
75
NEWS.rst
|
@ -1,6 +1,76 @@
|
|||
WirePlumber 0.4.15
|
||||
WirePlumber 0.4.17
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Fixes:
|
||||
|
||||
- Fixed a reference counting issue in the object managers that could cause
|
||||
crashes due to memory corruption (#534)
|
||||
|
||||
- Fixed an issue with filters linking to wrong targets, often with two sets
|
||||
of links (#536)
|
||||
|
||||
- Fixed a crash in the endpoints policy that would show up when log messages
|
||||
were enabled at level 3 or higher
|
||||
|
||||
Past releases
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
WirePlumber 0.4.16
|
||||
..................
|
||||
|
||||
Additions:
|
||||
|
||||
- Added a new "sm-objects" script that allows loading objects on demand
|
||||
via metadata entries that describe the object to load; this can be used to
|
||||
load pipewire modules, such as filters or network sources/sinks, on demand
|
||||
|
||||
- Added a mechanism to override device profile priorities in the configuration,
|
||||
mainly as a way to re-prioritize Bluetooth codecs, but this also can be used
|
||||
for other devices
|
||||
|
||||
- Added a mechanism in the endpoints policy to allow connecting filters
|
||||
between a certain endpoint's virtual sink and the device sink; this is
|
||||
specifically intended to allow plugging a filter-chain to act as equalizer
|
||||
on the Multimedia endpoint
|
||||
|
||||
- Added wp_core_get_own_bound_id() method in WpCore
|
||||
|
||||
Changes:
|
||||
|
||||
- PipeWire 0.3.68 is now required
|
||||
|
||||
- policy-dsp now has the ability to hide hardware nodes behind the DSP sink
|
||||
to prevent hardware misuse or damage
|
||||
|
||||
- JSON parsing in Lua now allows keys inside objects to be without quotes
|
||||
|
||||
- Added optional argument in the Lua JSON parse() method to limit recursions,
|
||||
making it possible to partially parse a JSON object
|
||||
|
||||
- It is now possible to pass ``nil`` in Lua object constructors that expect an
|
||||
optional properties object; previously, omitting the argument was the only
|
||||
way to skip the properties
|
||||
|
||||
- The endpoints policy now marks the endpoint nodes as "passive" instead of
|
||||
marking their links, adjusting for the behavior change in PipeWire 0.3.68
|
||||
|
||||
- Removed the "passive" property from si-standard-link, since only nodes are
|
||||
marked as passive now
|
||||
|
||||
Fixes:
|
||||
|
||||
- Fixed the ``wpctl clear-default`` command to completely clear all the
|
||||
default nodes state instead of only the last set default
|
||||
|
||||
- Reduced the amount of globals that initially match the interest in the
|
||||
object manager
|
||||
|
||||
- Used an idle callback instead of pw_core_sync() in the object manager to
|
||||
expose tmp globals
|
||||
|
||||
WirePlumber 0.4.15
|
||||
..................
|
||||
|
||||
Additions:
|
||||
|
||||
- A new "DSP policy" module has been added; its purpose is to automatically
|
||||
|
@ -51,9 +121,6 @@ Changes/Fixes:
|
|||
- Added some missing `\since` annotations and made them show up in the
|
||||
generated gobject-introspection file, to help bindings generators
|
||||
|
||||
Past releases
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
WirePlumber 0.4.14
|
||||
..................
|
||||
|
||||
|
|
|
@ -141,7 +141,7 @@ if build_gir
|
|||
dependencies: [wp_dep, dummy_dep],
|
||||
namespace: 'Wp',
|
||||
nsversion: wireplumber_api_version,
|
||||
export_packages: 'wireplumber-0.4',
|
||||
export_packages: 'wireplumber-' + wireplumber_api_version,
|
||||
header: 'wp/wp.h',
|
||||
sources: [wpenums_h, wp_gtkdoc_h, wp_lib_headers],
|
||||
include_directories: [wpenums_include_dir],
|
||||
|
|
|
@ -441,7 +441,7 @@ This can be done in 3 different ways:
|
|||
|
||||
1. Use pavucontrol and toggle the codecs in the output advanced section.
|
||||
|
||||
2. Modify the ``["iec958.codecs"]`` node property to contain suported codecs.
|
||||
2. Modify the ``["iec958.codecs"]`` node property to contain supported codecs.
|
||||
|
||||
Example ``~/.config/wireplumber/main.lua.d/51-alsa-spdif.lua``:
|
||||
|
||||
|
|
|
@ -806,6 +806,26 @@ wp_core_is_connected (WpCore * self)
|
|||
return self->pw_core && self->info;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the bound id of the client object that is created as a result
|
||||
* of this core being connected to the PipeWire daemon
|
||||
*
|
||||
* \ingroup wpcore
|
||||
* \since 0.4.16
|
||||
* \param self the core
|
||||
* \returns the bound id of this client
|
||||
*/
|
||||
guint32
|
||||
wp_core_get_own_bound_id (WpCore * self)
|
||||
{
|
||||
struct pw_client *client;
|
||||
|
||||
g_return_val_if_fail (wp_core_is_connected (self), SPA_ID_INVALID);
|
||||
|
||||
client = pw_core_get_client (self->pw_core);
|
||||
return pw_proxy_get_bound_id ((struct pw_proxy *) client);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the cookie of the core's connected PipeWire instance
|
||||
*
|
||||
|
|
|
@ -74,6 +74,9 @@ gboolean wp_core_is_connected (WpCore * self);
|
|||
|
||||
/* Properties */
|
||||
|
||||
WP_API
|
||||
guint32 wp_core_get_own_bound_id (WpCore * self);
|
||||
|
||||
WP_API
|
||||
guint32 wp_core_get_remote_cookie (WpCore * self);
|
||||
|
||||
|
|
|
@ -651,8 +651,7 @@ wp_impl_metadata_activate_execute_step (WpObject * object,
|
|||
case STEP_BIND: {
|
||||
g_autoptr (WpCore) core = wp_object_get_core (object);
|
||||
struct pw_core *pw_core = wp_core_get_pw_core (core);
|
||||
struct spa_dict_item items[1];
|
||||
struct spa_dict *props = NULL, prop_impl;
|
||||
const struct pw_properties *props = NULL;
|
||||
|
||||
/* no pw_core -> we are not connected */
|
||||
if (!pw_core) {
|
||||
|
@ -663,16 +662,9 @@ wp_impl_metadata_activate_execute_step (WpObject * object,
|
|||
return;
|
||||
}
|
||||
|
||||
/* TODO: Ideally, we should use the properties from pw_impl_metadata here,
|
||||
* but the pw_impl_metadata_get_properties is not implemented in pipewire
|
||||
* yet, so we add the name property manually for now */
|
||||
if (self->name) {
|
||||
items[0] = SPA_DICT_ITEM_INIT(PW_KEY_METADATA_NAME, self->name);
|
||||
prop_impl = SPA_DICT_INIT_ARRAY(items);
|
||||
props = &prop_impl;
|
||||
}
|
||||
props = pw_impl_metadata_get_properties (self->impl);
|
||||
wp_proxy_set_pw_proxy (WP_PROXY (self), pw_core_export (pw_core,
|
||||
PW_TYPE_INTERFACE_Metadata, props, priv->iface, 0)
|
||||
PW_TYPE_INTERFACE_Metadata, &props->dict, priv->iface, 0)
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1054,6 +1054,7 @@ expose_tmp_globals (WpCore *core)
|
|||
{
|
||||
WpRegistry *self = wp_core_get_registry (core);
|
||||
g_autoptr (GPtrArray) tmp_globals = NULL;
|
||||
g_autoptr (GPtrArray) object_managers = NULL;
|
||||
|
||||
/* in case the registry was cleared in the meantime... */
|
||||
if (G_UNLIKELY (!self->tmp_globals))
|
||||
|
@ -1093,9 +1094,13 @@ expose_tmp_globals (WpCore *core)
|
|||
g_ptr_array_index (self->globals, g->id) = wp_global_ref (g);
|
||||
}
|
||||
|
||||
object_managers = g_ptr_array_copy (self->object_managers,
|
||||
(GCopyFunc) g_object_ref, NULL);
|
||||
g_ptr_array_set_free_func (object_managers, g_object_unref);
|
||||
|
||||
/* notify object managers */
|
||||
for (guint i = 0; i < self->object_managers->len; i++) {
|
||||
WpObjectManager *om = g_ptr_array_index (self->object_managers, i);
|
||||
for (guint i = 0; i < object_managers->len; i++) {
|
||||
WpObjectManager *om = g_ptr_array_index (object_managers, i);
|
||||
|
||||
for (guint i = 0; i < tmp_globals->len; i++) {
|
||||
WpGlobal *g = g_ptr_array_index (tmp_globals, i);
|
||||
|
|
|
@ -128,8 +128,8 @@ wp_properties_new_valist (const gchar * key, va_list args)
|
|||
* be parsed from the given string
|
||||
*
|
||||
* \ingroup wpproperties
|
||||
* \param str a string containing a whitespace separated list of key=value pairs
|
||||
* (ex. "key1=value1 key2=value2")
|
||||
* \param str a string containing either a whitespace separated list of key=value
|
||||
* pairs (ex. "key1=value1 key2=value2") or a JSON object (ex. '{"key1":"value1"}')
|
||||
* \returns (transfer full): the newly constructed properties set
|
||||
*/
|
||||
WpProperties *
|
||||
|
|
|
@ -19,7 +19,6 @@ WP_LOG_TOPIC_EXTERN (log_topic_lua_scripting)
|
|||
|
||||
void wp_lua_scripting_pod_init (lua_State *L);
|
||||
void wp_lua_scripting_json_init (lua_State *L);
|
||||
void push_luajson (lua_State *L, WpSpaJson *json);
|
||||
|
||||
/* helpers */
|
||||
|
||||
|
@ -182,6 +181,15 @@ core_get_vm_type (lua_State *L)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
core_get_own_bound_id (lua_State *L)
|
||||
{
|
||||
WpCore * core = get_wp_core (L);
|
||||
guint32 id = wp_core_get_own_bound_id (core);
|
||||
lua_pushinteger (L, id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
core_idle_add (lua_State *L)
|
||||
{
|
||||
|
@ -288,6 +296,7 @@ static const luaL_Reg core_funcs[] = {
|
|||
{ "get_properties", core_get_properties },
|
||||
{ "get_info", core_get_info },
|
||||
{ "get_vm_type", core_get_vm_type },
|
||||
{ "get_own_bound_id", core_get_own_bound_id },
|
||||
{ "idle_add", core_idle_add },
|
||||
{ "timeout_add", core_timeout_add },
|
||||
{ "sync", core_sync },
|
||||
|
@ -940,7 +949,7 @@ impl_metadata_new (lua_State *L)
|
|||
const char *name = luaL_checkstring (L, 1);
|
||||
WpProperties *properties = NULL;
|
||||
|
||||
if (lua_type (L, 2) != LUA_TNONE) {
|
||||
if (lua_type (L, 2) != LUA_TNONE && lua_type (L, 2) != LUA_TNIL) {
|
||||
luaL_checktype (L, 2, LUA_TTABLE);
|
||||
properties = wplua_table_to_properties (L, 2);
|
||||
}
|
||||
|
@ -960,7 +969,7 @@ device_new (lua_State *L)
|
|||
const char *factory = luaL_checkstring (L, 1);
|
||||
WpProperties *properties = NULL;
|
||||
|
||||
if (lua_type (L, 2) != LUA_TNONE) {
|
||||
if (lua_type (L, 2) != LUA_TNONE && lua_type (L, 2) != LUA_TNIL) {
|
||||
luaL_checktype (L, 2, LUA_TTABLE);
|
||||
properties = wplua_table_to_properties (L, 2);
|
||||
}
|
||||
|
@ -980,7 +989,7 @@ spa_device_new (lua_State *L)
|
|||
const char *factory = luaL_checkstring (L, 1);
|
||||
WpProperties *properties = NULL;
|
||||
|
||||
if (lua_type (L, 2) != LUA_TNONE) {
|
||||
if (lua_type (L, 2) != LUA_TNONE && lua_type (L, 2) != LUA_TNIL) {
|
||||
luaL_checktype (L, 2, LUA_TTABLE);
|
||||
properties = wplua_table_to_properties (L, 2);
|
||||
}
|
||||
|
@ -1038,7 +1047,7 @@ node_new (lua_State *L)
|
|||
const char *factory = luaL_checkstring (L, 1);
|
||||
WpProperties *properties = NULL;
|
||||
|
||||
if (lua_type (L, 2) != LUA_TNONE) {
|
||||
if (lua_type (L, 2) != LUA_TNONE && lua_type (L, 2) != LUA_TNIL) {
|
||||
luaL_checktype (L, 2, LUA_TTABLE);
|
||||
properties = wplua_table_to_properties (L, 2);
|
||||
}
|
||||
|
@ -1147,7 +1156,7 @@ impl_node_new (lua_State *L)
|
|||
const char *factory = luaL_checkstring (L, 1);
|
||||
WpProperties *properties = NULL;
|
||||
|
||||
if (lua_type (L, 2) != LUA_TNONE) {
|
||||
if (lua_type (L, 2) != LUA_TNONE && lua_type (L, 2) != LUA_TNIL) {
|
||||
luaL_checktype (L, 2, LUA_TTABLE);
|
||||
properties = wplua_table_to_properties (L, 2);
|
||||
}
|
||||
|
@ -1183,7 +1192,7 @@ link_new (lua_State *L)
|
|||
const char *factory = luaL_checkstring (L, 1);
|
||||
WpProperties *properties = NULL;
|
||||
|
||||
if (lua_type (L, 2) != LUA_TNONE) {
|
||||
if (lua_type (L, 2) != LUA_TNONE && lua_type (L, 2) != LUA_TNIL) {
|
||||
luaL_checktype (L, 2, LUA_TTABLE);
|
||||
properties = wplua_table_to_properties (L, 2);
|
||||
}
|
||||
|
|
|
@ -97,8 +97,8 @@ spa_json_is_object (lua_State *L)
|
|||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
push_luajson (lua_State *L, WpSpaJson *json)
|
||||
static void
|
||||
push_luajson (lua_State *L, WpSpaJson *json, gint n_recursions)
|
||||
{
|
||||
/* Null */
|
||||
if (wp_spa_json_is_null (json)) {
|
||||
|
@ -127,20 +127,20 @@ push_luajson (lua_State *L, WpSpaJson *json)
|
|||
}
|
||||
|
||||
/* Array */
|
||||
else if (wp_spa_json_is_array (json)) {
|
||||
else if (wp_spa_json_is_array (json) && n_recursions > 0) {
|
||||
g_auto (GValue) item = G_VALUE_INIT;
|
||||
g_autoptr (WpIterator) it = wp_spa_json_new_iterator (json);
|
||||
guint i = 1;
|
||||
lua_newtable (L);
|
||||
for (; wp_iterator_next (it, &item); g_value_unset (&item)) {
|
||||
WpSpaJson *j = g_value_get_boxed (&item);
|
||||
push_luajson (L, j);
|
||||
push_luajson (L, j, n_recursions - 1);
|
||||
lua_rawseti (L, -2, i++);
|
||||
}
|
||||
}
|
||||
|
||||
/* Object */
|
||||
else if (wp_spa_json_is_object (json)) {
|
||||
else if (wp_spa_json_is_object (json) && n_recursions > 0) {
|
||||
g_auto (GValue) item = G_VALUE_INIT;
|
||||
g_autoptr (WpIterator) it = wp_spa_json_new_iterator (json);
|
||||
lua_newtable (L);
|
||||
|
@ -154,7 +154,7 @@ push_luajson (lua_State *L, WpSpaJson *json)
|
|||
if (!wp_iterator_next (it, &item))
|
||||
break;
|
||||
value = g_value_get_boxed (&item);
|
||||
push_luajson (L, value);
|
||||
push_luajson (L, value, n_recursions - 1);
|
||||
lua_setfield (L, -2, key_str);
|
||||
}
|
||||
}
|
||||
|
@ -171,7 +171,8 @@ static int
|
|||
spa_json_parse (lua_State *L)
|
||||
{
|
||||
WpSpaJson *json = wplua_checkboxed (L, 1, WP_TYPE_SPA_JSON);
|
||||
push_luajson (L, json);
|
||||
gint n_recursions = luaL_opt (L, luaL_checkinteger, 2, INT_MAX);
|
||||
push_luajson (L, json, n_recursions);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -250,6 +250,8 @@ si_audio_virtual_enable_active (WpSessionItem *si, WpTransition *transition)
|
|||
(self->direction == WP_DIRECTION_OUTPUT) ? "Capture" : "Playback");
|
||||
g_autofree gchar *media = g_strdup_printf ("Audio/%s",
|
||||
(self->direction == WP_DIRECTION_OUTPUT) ? "Source" : "Sink");
|
||||
const gchar *passive =
|
||||
(self->direction == WP_DIRECTION_OUTPUT) ? "in" : "out";
|
||||
|
||||
if (!wp_session_item_is_configured (si)) {
|
||||
wp_transition_return_error (transition,
|
||||
|
@ -266,6 +268,7 @@ si_audio_virtual_enable_active (WpSessionItem *si, WpTransition *transition)
|
|||
PW_KEY_FACTORY_NAME, "support.null-audio-sink",
|
||||
PW_KEY_NODE_DESCRIPTION, desc,
|
||||
PW_KEY_NODE_AUTOCONNECT, "true",
|
||||
PW_KEY_NODE_PASSIVE, passive,
|
||||
"monitor.channel-volumes", "true",
|
||||
"wireplumber.is-virtual", "true",
|
||||
NULL));
|
||||
|
|
|
@ -24,7 +24,6 @@ struct _WpSiStandardLink
|
|||
GWeakRef in_item;
|
||||
const gchar *out_item_port_context;
|
||||
const gchar *in_item_port_context;
|
||||
gboolean passive;
|
||||
gboolean passthrough;
|
||||
|
||||
/* activate */
|
||||
|
@ -70,7 +69,6 @@ si_standard_link_reset (WpSessionItem * item)
|
|||
g_weak_ref_set (&self->in_item, NULL);
|
||||
self->out_item_port_context = NULL;
|
||||
self->in_item_port_context = NULL;
|
||||
self->passive = FALSE;
|
||||
self->passthrough = FALSE;
|
||||
|
||||
WP_SESSION_ITEM_CLASS (si_standard_link_parent_class)->reset (item);
|
||||
|
@ -120,9 +118,6 @@ si_standard_link_configure (WpSessionItem * item, WpProperties * p)
|
|||
self->in_item_port_context = wp_properties_get (si_props,
|
||||
"in.item.port.context");
|
||||
|
||||
str = wp_properties_get (si_props, "passive");
|
||||
self->passive = str && pw_properties_parse_bool (str);
|
||||
|
||||
str = wp_properties_get (si_props, "passthrough");
|
||||
self->passthrough = str && pw_properties_parse_bool (str);
|
||||
|
||||
|
@ -354,8 +349,6 @@ create_links (WpSiStandardLink * self, WpTransition * transition,
|
|||
wp_properties_setf (props, PW_KEY_LINK_OUTPUT_PORT, "%u", out_port.port_id);
|
||||
wp_properties_setf (props, PW_KEY_LINK_INPUT_NODE, "%u", best_port->node_id);
|
||||
wp_properties_setf (props, PW_KEY_LINK_INPUT_PORT, "%u", best_port->port_id);
|
||||
if (self->passive)
|
||||
wp_properties_set (props, PW_KEY_LINK_PASSIVE, "true");
|
||||
|
||||
wp_debug_object (self, "create pw link: %u:%u (%s) -> %u:%u (%s)",
|
||||
out_port.node_id, out_port.port_id,
|
||||
|
|
16
po/fa.po
16
po/fa.po
|
@ -1,22 +1,22 @@
|
|||
# Persian translation for WirePlumber.
|
||||
# Copyright (C) 2022 WirePlumber's COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the WirePlumber package.
|
||||
# Danial Behzadi <dani.behzi@ubuntu.com>, 2022.
|
||||
# Danial Behzadi <dani.behzi@ubuntu.com>, 2022-2023.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: WirePlumber master\n"
|
||||
"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/wireplumber/-/"
|
||||
"issues\n"
|
||||
"POT-Creation-Date: 2022-07-08 03:32+0000\n"
|
||||
"PO-Revision-Date: 2022-08-07 04:59+0430\n"
|
||||
"POT-Creation-Date: 2023-10-06 03:31+0000\n"
|
||||
"PO-Revision-Date: 2023-10-06 16:22+0330\n"
|
||||
"Last-Translator: Danial Behzadi <dani.behzi@ubuntu.com>\n"
|
||||
"Language-Team: Persian <fa@li.org>\n"
|
||||
"Language: fa\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: Poedit 3.1.1\n"
|
||||
"X-Generator: Poedit 3.3.2\n"
|
||||
|
||||
#. WirePlumber
|
||||
#.
|
||||
|
@ -48,11 +48,15 @@ msgstr ""
|
|||
#. ensure the device has an appropriate name
|
||||
#. deduplicate devices with the same name
|
||||
#. ensure the device has a description
|
||||
#: src/scripts/monitors/alsa.lua:228
|
||||
#: src/scripts/monitors/alsa.lua:236
|
||||
msgid "Loopback"
|
||||
msgstr "حلقهٔ معکوس"
|
||||
|
||||
#: src/scripts/monitors/alsa.lua:238
|
||||
msgid "Built-in Audio"
|
||||
msgstr "صدای توکار"
|
||||
|
||||
#: src/scripts/monitors/alsa.lua:230
|
||||
#: src/scripts/monitors/alsa.lua:240
|
||||
msgid "Modem"
|
||||
msgstr "مودم"
|
||||
|
||||
|
|
74
po/he.po
74
po/he.po
|
@ -4,10 +4,10 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: pipewire\n"
|
||||
"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/wireplumber/"
|
||||
"issues/new\n"
|
||||
"POT-Creation-Date: 2022-04-09 15:19+0300\n"
|
||||
"PO-Revision-Date: 2021-03-02 14:40+0000\n"
|
||||
"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/wireplumber/-/"
|
||||
"issues\n"
|
||||
"POT-Creation-Date: 2023-03-04 13:34+0000\n"
|
||||
"PO-Revision-Date: 2023-12-06 10:07+0200\n"
|
||||
"Last-Translator: Yaron Shahrabani <sh.yaron@gmail.com>\n"
|
||||
"Language-Team: Hebrew <https://translate.fedoraproject.org/projects/pipewire/"
|
||||
"pipewire/he/>\n"
|
||||
|
@ -16,9 +16,7 @@ msgstr ""
|
|||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: Weblate 4.4.2\n"
|
||||
"X-Poedit-Language: Hebrew\n"
|
||||
"X-Poedit-Country: Israel\n"
|
||||
"X-Generator: Poedit 3.4.1\n"
|
||||
|
||||
#. WirePlumber
|
||||
#.
|
||||
|
@ -28,6 +26,7 @@ msgstr ""
|
|||
#. SPDX-License-Identifier: MIT
|
||||
#. Receive script arguments from config.lua
|
||||
#. ensure config.properties is not nil
|
||||
#. unique device/node name tables
|
||||
#. preprocess rules and create Interest objects
|
||||
#. applies properties from config.rules when asked to
|
||||
#. set the device id and spa factory name; REQUIRED, do not change
|
||||
|
@ -43,15 +42,68 @@ msgstr ""
|
|||
#. ensure the node has a description
|
||||
#. also sanitize description, replace ':' with ' '
|
||||
#. add api.alsa.card.* properties for rule matching purposes
|
||||
#. apply VM overrides
|
||||
#. apply properties from config.rules
|
||||
#. create the node
|
||||
#. ensure the device has an appropriate name
|
||||
#. deduplicate devices with the same name
|
||||
#. ensure the device has a description
|
||||
#: src/scripts/monitors/alsa.lua:222
|
||||
msgid "Built-in Audio"
|
||||
msgstr "צליל פנימי"
|
||||
#: src/scripts/monitors/alsa.lua:236
|
||||
msgid "Loopback"
|
||||
msgstr "לולאה חוזרת"
|
||||
|
||||
#: src/scripts/monitors/alsa.lua:224
|
||||
#: src/scripts/monitors/alsa.lua:238
|
||||
msgid "Built-in Audio"
|
||||
msgstr "צליל מובנה"
|
||||
|
||||
#: src/scripts/monitors/alsa.lua:240
|
||||
msgid "Modem"
|
||||
msgstr "מודם"
|
||||
|
||||
#. ensure the device has a nick
|
||||
#. set the icon name
|
||||
#. form factor -> icon
|
||||
#. apply properties from config.rules
|
||||
#. override the device factory to use ACP
|
||||
#. use device reservation, if available
|
||||
#. unlike pipewire-media-session, this logic here keeps the device
|
||||
#. acquired at all times and destroys it if someone else acquires
|
||||
#. create the device
|
||||
#. attempt to acquire again
|
||||
#. destroy the device
|
||||
#. TODO enable the jack device
|
||||
#. TODO disable the jack device
|
||||
#. create the device
|
||||
#. handle create-object to prepare device
|
||||
#. handle object-removed to destroy device reservations and recycle device name
|
||||
#. reset the name tables to make sure names are recycled
|
||||
#. activate monitor
|
||||
#. create the JACK device (for PipeWire to act as client to a JACK server)
|
||||
#. enable device reservation if requested
|
||||
#. if the reserve-device plugin is enabled, at the point of script execution
|
||||
#. it is expected to be connected. if it is not, assume the d-bus connection
|
||||
#. has failed and continue without it
|
||||
#. handle rd_plugin state changes to destroy and re-create the ALSA monitor in
|
||||
#. case D-Bus service is restarted
|
||||
#. create the monitor
|
||||
#. WirePlumber
|
||||
#.
|
||||
#. Copyright © 2021 Collabora Ltd.
|
||||
#. @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
||||
#.
|
||||
#. SPDX-License-Identifier: MIT
|
||||
#. preprocess rules and create Interest objects
|
||||
#. applies properties from config.rules when asked to
|
||||
#. set the device id and spa factory name; REQUIRED, do not change
|
||||
#. set the default pause-on-idle setting
|
||||
#. set the node name
|
||||
#. sanitize name
|
||||
#. deduplicate nodes with the same name
|
||||
#. set the node description
|
||||
#: src/scripts/monitors/libcamera.lua:88
|
||||
msgid "Built-in Front Camera"
|
||||
msgstr "מצלמה פנימית מובנית"
|
||||
|
||||
#: src/scripts/monitors/libcamera.lua:90
|
||||
msgid "Built-in Back Camera"
|
||||
msgstr "מצלמה אחורית מובנית"
|
||||
|
|
|
@ -38,7 +38,8 @@ context.modules = [
|
|||
## [ flags = [ ifexists | nofail ] ]
|
||||
## }
|
||||
|
||||
## Uses RTKit to boost the data thread priority.
|
||||
# Uses RTKit to boost the data thread priority. Also allows clamping
|
||||
# of utilisation when using the Completely Fair Scheduler on Linux.
|
||||
{
|
||||
name = libpipewire-module-rt
|
||||
args = {
|
||||
|
@ -46,6 +47,8 @@ context.modules = [
|
|||
# rt.prio = 88
|
||||
# rt.time.soft = -1
|
||||
# rt.time.hard = -1
|
||||
# uclamp.min = 0
|
||||
# uclamp.max = 1024
|
||||
}
|
||||
flags = [ ifexists, nofail ]
|
||||
}
|
||||
|
@ -68,6 +71,7 @@ wireplumber.profiles = {
|
|||
main = {
|
||||
check.no-media-session = required
|
||||
support.settings = required
|
||||
metadata.sm-objects = required
|
||||
hardware.audio = required
|
||||
hardware.bluetooth = required
|
||||
hardware.video-capture = required
|
||||
|
@ -239,6 +243,12 @@ wireplumber.components = [
|
|||
provides = metadata.filters
|
||||
}
|
||||
|
||||
## Provide the "sm-objects" pw_metadata, supporting dynamic loadable objects
|
||||
{
|
||||
name = sm-objects.lua, type = script/lua
|
||||
provides = metadata.sm-objects
|
||||
}
|
||||
|
||||
## Device monitors' optional features
|
||||
{
|
||||
type = virtual, provides = monitor.alsa.reserve-device,
|
||||
|
|
|
@ -42,8 +42,6 @@ AsyncEventHook {
|
|||
tostring (si_props ["node.name"]), tostring (si_props ["node.id"])))
|
||||
|
||||
local exclusive = cutils.parseBool (si_props ["node.exclusive"])
|
||||
local passive = cutils.parseBool (si_props ["node.passive"]) or
|
||||
cutils.parseBool (target_props ["node.passive"])
|
||||
|
||||
-- break rescan if tried more than 5 times with same target
|
||||
if si_flags.failed_peer_id ~= nil and
|
||||
|
@ -79,10 +77,9 @@ AsyncEventHook {
|
|||
local is_virtual_client_link = target_props ["item.factory.name"] == "si-audio-virtual"
|
||||
|
||||
log:info (si,
|
||||
string.format ("link %s <-> %s passive:%s, passthrough:%s, exclusive:%s, virtual-client:%s",
|
||||
string.format ("link %s <-> %s passthrough:%s, exclusive:%s, virtual-client:%s",
|
||||
tostring (si_props ["node.name"]),
|
||||
tostring (target_props ["node.name"]),
|
||||
tostring (passive),
|
||||
tostring (passthrough),
|
||||
tostring (exclusive),
|
||||
tostring (is_virtual_client_link)))
|
||||
|
@ -92,7 +89,6 @@ AsyncEventHook {
|
|||
if not si_link:configure {
|
||||
["out.item"] = out_item,
|
||||
["in.item"] = in_item,
|
||||
["passive"] = passive,
|
||||
["passthrough"] = passthrough,
|
||||
["exclusive"] = exclusive,
|
||||
["out.item.port.context"] = "output",
|
||||
|
|
|
@ -28,7 +28,12 @@ nodes_om = ObjectManager {
|
|||
Interest { type = "node" },
|
||||
}
|
||||
|
||||
clients_om = ObjectManager {
|
||||
Interest { type = "client" }
|
||||
}
|
||||
|
||||
filter_chains = {}
|
||||
hidden_nodes = {}
|
||||
|
||||
nodes_om:connect("object-added", function (om, node)
|
||||
for _, r in ipairs(config.rules or {}) do
|
||||
|
@ -43,6 +48,17 @@ nodes_om:connect("object-added", function (om, node)
|
|||
filter_chains[id] = LocalModule("libpipewire-module-filter-chain", r.filter_chain, {}, true)
|
||||
end
|
||||
end
|
||||
|
||||
if r.hide_parent then
|
||||
Log.debug("Hiding node " .. node["bound-id"] .. " from clients")
|
||||
for client in clients_om:iterate { type = "client" } do
|
||||
if not client["properties"]["wireplumber.daemon"] then
|
||||
client:update_permissions { [node["bound-id"]] = "-" }
|
||||
end
|
||||
end
|
||||
hidden_nodes[node["bound-id"]] = id
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -58,4 +74,13 @@ nodes_om:connect("object-removed", function (om, node)
|
|||
end
|
||||
end)
|
||||
|
||||
clients_om:connect("object-added", function (om, client)
|
||||
for id, _ in pairs(hidden_nodes) do
|
||||
if not client["properties"]["wireplumber.daemon"] then
|
||||
client:update_permissions { [id] = "-" }
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
nodes_om:activate()
|
||||
clients_om:activate()
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
-- WirePlumber
|
||||
--
|
||||
-- Copyright © 2023 Collabora Ltd.
|
||||
-- @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
||||
--
|
||||
-- SPDX-License-Identifier: MIT
|
||||
--
|
||||
-- The script exposes a metadata object named "sm-objects" that clients can
|
||||
-- use to load objects into the WirePlumber daemon process. The objects are
|
||||
-- loaded as soon as the metadata is set and are destroyed when the metadata
|
||||
-- is cleared.
|
||||
--
|
||||
-- To load an object, a client needs to set a metadata entry with:
|
||||
--
|
||||
-- * subject:
|
||||
-- The ID of the owner of the object; you can use 0 here, but the
|
||||
-- idea is to be able to restrict which clients can change and/or
|
||||
-- delete these objects by using IDs of other objects appropriately
|
||||
--
|
||||
-- * key: "<UNIQUE-OBJECT-NAME>"
|
||||
-- This is the name that will be used to identify the object.
|
||||
-- If an object with the same name already exists, it will be destroyed.
|
||||
-- Note that the keys are unique per subject, so you can have multiple
|
||||
-- objects with the same name as long as they are owned by different subjects.
|
||||
--
|
||||
-- * type: "Spa:String:JSON"
|
||||
--
|
||||
-- * value: "{ type = <object-type>,
|
||||
-- name = <object-name>,
|
||||
-- args = { ...object arguments... } }"
|
||||
-- The object type can be one of the following:
|
||||
-- - "pw-module": loads a pipewire module: `name` and `args` are interpreted
|
||||
-- just like a module entry in pipewire.conf
|
||||
-- - "metadata": loads a metadata object with `metadata.name` = `name`
|
||||
-- and any additional properties provided in `args`
|
||||
--
|
||||
|
||||
on_demand_objects = {}
|
||||
|
||||
object_constructors = {
|
||||
["pw-module"] = LocalModule,
|
||||
["metadata"] = function (name, args)
|
||||
local m = ImplMetadata (name, args)
|
||||
m:activate (Features.ALL, function (m, e)
|
||||
if e then
|
||||
Log.warning ("failed to activate on-demand metadata `" .. name .. "`: " .. tostring (e))
|
||||
end
|
||||
end)
|
||||
return m
|
||||
end
|
||||
}
|
||||
|
||||
function handle_metadata_changed (m, subject, key, type, value)
|
||||
-- destroy all objects when metadata is cleared
|
||||
if not key then
|
||||
on_demand_objects = {}
|
||||
return
|
||||
end
|
||||
|
||||
local object_id = key .. "@" .. tostring(subject)
|
||||
|
||||
-- destroy existing object instance, if needed
|
||||
if on_demand_objects[object_id] then
|
||||
Log.debug("destroy on-demand object: " .. object_id)
|
||||
on_demand_objects[object_id] = nil
|
||||
end
|
||||
|
||||
if value then
|
||||
local json = Json.Raw(value)
|
||||
if not json:is_object() then
|
||||
Log.warning("loading '".. object_id .. "' failed: expected JSON object, got: '" .. value .. "'")
|
||||
return
|
||||
end
|
||||
|
||||
local obj = json:parse(1)
|
||||
if not obj.type then
|
||||
Log.warning("loading '".. object_id .. "' failed: no object type specified")
|
||||
return
|
||||
end
|
||||
if not obj.name then
|
||||
Log.warning("loading '".. object_id .. "' failed: no object name specified")
|
||||
return
|
||||
end
|
||||
|
||||
local constructor = object_constructors[obj.type]
|
||||
if not constructor then
|
||||
Log.warning("loading '".. object_id .. "' failed: unknown object type: " .. obj.type)
|
||||
return
|
||||
end
|
||||
|
||||
Log.info("load on-demand object: " .. object_id .. " -> " .. obj.name)
|
||||
on_demand_objects[object_id] = constructor(obj.name, obj.args)
|
||||
end
|
||||
end
|
||||
|
||||
objects_metadata = ImplMetadata ("sm-objects")
|
||||
objects_metadata:activate (Features.ALL, function (m, e)
|
||||
if e then
|
||||
Log.warning ("failed to activate the sm-objects metadata: " .. tostring (e))
|
||||
else
|
||||
m:connect("changed", handle_metadata_changed)
|
||||
end
|
||||
end)
|
|
@ -203,3 +203,40 @@ assert (val.name == "wireplumber")
|
|||
assert (val.version[1] == 0)
|
||||
assert (val.version[2] == 4)
|
||||
assert (val.version[3] == 7)
|
||||
|
||||
-- recursion limit
|
||||
json = Json.Raw ("{ name = wireplumber, version = [0, 4, 15], args = { test = [0, 1] } }")
|
||||
|
||||
val = json:parse (0)
|
||||
assert (type (val) == "string")
|
||||
assert (val == "{ name = wireplumber, version = [0, 4, 15], args = { test = [0, 1] } }")
|
||||
|
||||
val = json:parse (1)
|
||||
assert (type (val) == "table")
|
||||
assert (val.name == "wireplumber")
|
||||
assert (type (val.version) == "string")
|
||||
assert (val.version == "[0, 4, 15]")
|
||||
assert (type (val.args) == "string")
|
||||
assert (val.args == "{ test = [0, 1] }")
|
||||
|
||||
val = json:parse(2)
|
||||
assert (type (val) == "table")
|
||||
assert (val.name == "wireplumber")
|
||||
assert (type (val.version) == "table")
|
||||
assert (val.version[1] == 0)
|
||||
assert (val.version[2] == 4)
|
||||
assert (val.version[3] == 15)
|
||||
assert (type (val.args) == "table")
|
||||
assert (val.args.test == "[0, 1]")
|
||||
|
||||
val = json:parse(3)
|
||||
assert (type (val) == "table")
|
||||
assert (val.name == "wireplumber")
|
||||
assert (type (val.version) == "table")
|
||||
assert (val.version[1] == 0)
|
||||
assert (val.version[2] == 4)
|
||||
assert (val.version[3] == 15)
|
||||
assert (type (val.args) == "table")
|
||||
assert (type (val.args.test) == "table")
|
||||
assert (val.args.test[1] == 0)
|
||||
assert (val.args.test[2] == 1)
|
||||
|
|
Loading…
Reference in New Issue