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.
This commit is contained in:
George Kiagiadakis 2021-06-07 17:23:15 +03:00
parent 997bdb65cd
commit 1ca67abc66
4 changed files with 152 additions and 34 deletions

View file

@ -10,6 +10,7 @@
#include "object-manager.h"
#include "log.h"
#include "proxy-interfaces.h"
#include "private/registry.h"
#include <pipewire/pipewire.h>
@ -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:
*

View file

@ -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);
}

View file

@ -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',

95
tests/wp/object-manager.c Normal file
View file

@ -0,0 +1,95 @@
/* WirePlumber
*
* Copyright © 2021 Collabora Ltd.
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
*
* 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 ();
}