From 1ca67abc66da1f293771ac8268ca9b60b951d3fa Mon Sep 17 00:00:00 2001 From: George Kiagiadakis Date: Mon, 7 Jun 2021 17:23:15 +0300 Subject: [PATCH] object-manager: support declaring interest on all properties of globals Until now, object manager could only match pw global properties on pw global objects, because this is the only available properties set at the time the registry creates the global. With this change, the object manager will now bind the proxy if the type and the pw global properties have matched and will wait until the proxy is available with all of its properties and tries the check again. --- lib/wp/object-manager.c | 74 +++++++++++++++---------- tests/common/base-test-fixture.h | 9 +-- tests/wp/meson.build | 8 +++ tests/wp/object-manager.c | 95 ++++++++++++++++++++++++++++++++ 4 files changed, 152 insertions(+), 34 deletions(-) create mode 100644 tests/wp/object-manager.c diff --git a/lib/wp/object-manager.c b/lib/wp/object-manager.c index 3ab01e64..35133716 100644 --- a/lib/wp/object-manager.c +++ b/lib/wp/object-manager.c @@ -10,6 +10,7 @@ #include "object-manager.h" #include "log.h" +#include "proxy-interfaces.h" #include "private/registry.h" #include @@ -620,11 +621,27 @@ wp_object_manager_is_interested_in_global (WpObjectManager * self, for (i = 0; i < self->interests->len; i++) { interest = g_ptr_array_index (self->interests, i); - if (wp_object_interest_matches_full (interest, 0, global->type, - global->proxy, NULL, global->properties) == WP_INTEREST_MATCH_ALL) { + + /* check all constraints */ + WpInterestMatch match = wp_object_interest_matches_full (interest, + WP_INTEREST_MATCH_FLAGS_CHECK_ALL, global->type, global->proxy, + NULL, global->properties); + + /* and consider the manager interested if the type and the globals match... + if pw_properties / g_properties fail, that's ok because they are not + known yet (the proxy is likely NULL and properties not yet retrieved) */ + if (match & (WP_INTEREST_MATCH_GTYPE | + WP_INTEREST_MATCH_PW_GLOBAL_PROPERTIES)) { gpointer ft = g_hash_table_lookup (self->features, GSIZE_TO_POINTER (global->type)); *wanted_features = (WpObjectFeatures) GPOINTER_TO_UINT (ft); + + /* force INFO to be present so that we can check PW_PROPERTIES constraints */ + if (!(match & WP_INTEREST_MATCH_PW_PROPERTIES) && + !(*wanted_features & WP_PIPEWIRE_OBJECT_FEATURE_INFO) && + g_type_is_a (global->type, WP_TYPE_PIPEWIRE_OBJECT)) + *wanted_features |= WP_PIPEWIRE_OBJECT_FEATURE_INFO; + return TRUE; } } @@ -698,6 +715,30 @@ wp_object_manager_maybe_objects_changed (WpObjectManager * self) } } +/* caller must also call wp_object_manager_maybe_objects_changed() after */ +static void +wp_object_manager_add_object (WpObjectManager * self, gpointer object) +{ + if (wp_object_manager_is_interested_in_object (self, object)) { + wp_trace_object (self, "added: " WP_OBJECT_FORMAT, WP_OBJECT_ARGS (object)); + g_ptr_array_add (self->objects, object); + g_signal_emit (self, signals[SIGNAL_OBJECT_ADDED], 0, object); + self->changed = TRUE; + } +} + +/* caller must also call wp_object_manager_maybe_objects_changed() after */ +static void +wp_object_manager_rm_object (WpObjectManager * self, gpointer object) +{ + guint index; + if (g_ptr_array_find (self->objects, object, &index)) { + g_ptr_array_remove_index_fast (self->objects, index); + g_signal_emit (self, signals[SIGNAL_OBJECT_REMOVED], 0, object); + self->changed = TRUE; + } +} + static void on_proxy_ready (GObject * proxy, GAsyncResult * res, gpointer data) { @@ -709,10 +750,7 @@ on_proxy_ready (GObject * proxy, GAsyncResult * res, gpointer data) if (!wp_object_activate_finish (WP_OBJECT (proxy), res, &error)) { wp_message_object (self, "proxy activation failed: %s", error->message); } else { - wp_trace_object (self, "added: " WP_OBJECT_FORMAT, WP_OBJECT_ARGS (proxy)); - g_ptr_array_add (self->objects, proxy); - g_signal_emit (self, signals[SIGNAL_OBJECT_ADDED], 0, proxy); - self->changed = TRUE; + wp_object_manager_add_object (self, proxy); } wp_object_manager_maybe_objects_changed (self); @@ -748,30 +786,6 @@ wp_object_manager_add_global (WpObjectManager * self, WpGlobal * global) } } -/* caller must also call wp_object_manager_maybe_objects_changed() after */ -static void -wp_object_manager_add_object (WpObjectManager * self, gpointer object) -{ - if (wp_object_manager_is_interested_in_object (self, object)) { - wp_trace_object (self, "added: " WP_OBJECT_FORMAT, WP_OBJECT_ARGS (object)); - g_ptr_array_add (self->objects, object); - g_signal_emit (self, signals[SIGNAL_OBJECT_ADDED], 0, object); - self->changed = TRUE; - } -} - -/* caller must also call wp_object_manager_maybe_objects_changed() after */ -static void -wp_object_manager_rm_object (WpObjectManager * self, gpointer object) -{ - guint index; - if (g_ptr_array_find (self->objects, object, &index)) { - g_ptr_array_remove_index_fast (self->objects, index); - g_signal_emit (self, signals[SIGNAL_OBJECT_REMOVED], 0, object); - self->changed = TRUE; - } -} - /* * WpRegistry: * diff --git a/tests/common/base-test-fixture.h b/tests/common/base-test-fixture.h index e0a907dc..3eb26d96 100644 --- a/tests/common/base-test-fixture.h +++ b/tests/common/base-test-fixture.h @@ -93,7 +93,7 @@ wp_base_test_fixture_setup (WpBaseTestFixture * self, WpBaseTestFlags flags) } static void -done_callback (WpCore *core, GAsyncResult *res, WpBaseTestFixture *self) +test_core_done_cb (WpCore *core, GAsyncResult *res, WpBaseTestFixture *self) { g_autoptr (GError) error = NULL; g_assert_true (wp_core_sync_finish (core, res, &error)); @@ -106,14 +106,15 @@ wp_base_test_fixture_teardown (WpBaseTestFixture * self) { /* wait for all client core pending tasks to be done */ if (self->client_core && wp_core_is_connected (self->client_core)) { - wp_core_sync (self->client_core, NULL, (GAsyncReadyCallback) done_callback, - self); + wp_core_sync (self->client_core, NULL, + (GAsyncReadyCallback) test_core_done_cb, self); g_main_loop_run (self->loop); } /* wait for all core pending tasks to be done */ if (self->core && wp_core_is_connected (self->core)) { - wp_core_sync (self->core, NULL, (GAsyncReadyCallback) done_callback, self); + wp_core_sync (self->core, NULL, (GAsyncReadyCallback) test_core_done_cb, + self); g_main_loop_run (self->loop); } diff --git a/tests/wp/meson.build b/tests/wp/meson.build index 6946ddd9..59326e01 100644 --- a/tests/wp/meson.build +++ b/tests/wp/meson.build @@ -30,6 +30,7 @@ test( dependencies: common_deps, c_args: common_args), env: common_env, ) + test( 'test-object-interest', executable('test-object-interest', 'object-interest.c', @@ -37,6 +38,13 @@ test( env: common_env, ) +test( + 'test-object-manager', + executable('test-object-manager', 'object-manager.c', + dependencies: common_deps, c_args: common_args), + env: common_env, +) + test( 'test-properties', executable('test-properties', 'properties.c', diff --git a/tests/wp/object-manager.c b/tests/wp/object-manager.c new file mode 100644 index 00000000..99a8edef --- /dev/null +++ b/tests/wp/object-manager.c @@ -0,0 +1,95 @@ +/* WirePlumber + * + * Copyright © 2021 Collabora Ltd. + * @author George Kiagiadakis + * + * SPDX-License-Identifier: MIT + */ + +#include "../common/base-test-fixture.h" + +typedef struct { + WpBaseTestFixture base; + WpObjectManager *om; +} TestFixture; + +static void +test_om_setup (TestFixture *self, gconstpointer user_data) +{ + wp_base_test_fixture_setup (&self->base, WP_BASE_TEST_FLAG_CLIENT_CORE); +} + +static void +test_om_teardown (TestFixture *self, gconstpointer user_data) +{ + wp_base_test_fixture_teardown (&self->base); +} + +static void +test_om_interest_on_pw_props (TestFixture *f, gconstpointer user_data) +{ + g_autoptr (WpNode) node = NULL; + g_autoptr (WpObjectManager) om = NULL; + + /* load audiotestsrc on the server side */ + { + g_autoptr (WpTestServerLocker) lock = + wp_test_server_locker_new (&f->base.server); + + g_assert_cmpint (pw_context_add_spa_lib (f->base.server.context, + "fake*", "test/libspa-test"), ==, 0); + g_assert_nonnull (pw_context_load_module (f->base.server.context, + "libpipewire-module-spa-node-factory", NULL, NULL)); + } + + /* export node on the client core */ + node = wp_node_new_from_factory (f->base.client_core, + "spa-node-factory", + wp_properties_new ( + "factory.name", "fakesink", + "node.name", "Fakesink", + "test.answer", "42", + NULL)); + g_assert_nonnull (node); + + wp_object_activate (WP_OBJECT (node), WP_OBJECT_FEATURES_ALL, + NULL, (GAsyncReadyCallback) test_object_activate_finish_cb, f); + g_main_loop_run (f->base.loop); + + /* ensure the base core is in sync */ + wp_core_sync (f->base.core, NULL, (GAsyncReadyCallback) test_core_done_cb, f); + g_main_loop_run (f->base.loop); + + /* request that node from the base core */ + om = wp_object_manager_new (); + wp_object_manager_add_interest (om, WP_TYPE_NODE, + WP_CONSTRAINT_TYPE_PW_GLOBAL_PROPERTY, "node.name", "=s", "Fakesink", + WP_CONSTRAINT_TYPE_PW_PROPERTY, "test.answer", "=s", "42", + NULL); + test_ensure_object_manager_is_installed (om, f->base.core, f->base.loop); + + g_assert_cmpuint (wp_object_manager_get_n_objects (om), ==, 1); + g_clear_object (&om); + + /* request "test.answer" to be absent... this will not match */ + om = wp_object_manager_new (); + wp_object_manager_add_interest (om, WP_TYPE_NODE, + WP_CONSTRAINT_TYPE_PW_GLOBAL_PROPERTY, "node.name", "=s", "Fakesink", + WP_CONSTRAINT_TYPE_PW_PROPERTY, "test.answer", "-", + NULL); + test_ensure_object_manager_is_installed (om, f->base.core, f->base.loop); + + g_assert_cmpuint (wp_object_manager_get_n_objects (om), ==, 0); +} + +gint +main (gint argc, gchar *argv[]) +{ + g_test_init (&argc, &argv, NULL); + wp_init (WP_INIT_ALL); + + g_test_add ("/wp/om/interest-on-pw-props", TestFixture, NULL, + test_om_setup, test_om_interest_on_pw_props, test_om_teardown); + + return g_test_run (); +}