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 (); +}