2019-11-13 16:07:36 +02:00
|
|
|
/* WirePlumber
|
|
|
|
|
*
|
|
|
|
|
* Copyright © 2019 Collabora Ltd.
|
|
|
|
|
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
|
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: MIT
|
|
|
|
|
*/
|
|
|
|
|
|
2021-05-13 17:54:58 +03:00
|
|
|
#include "object-manager.h"
|
2021-05-21 18:40:43 +03:00
|
|
|
#include "log.h"
|
2021-06-07 17:23:15 +03:00
|
|
|
#include "proxy-interfaces.h"
|
2021-05-21 18:40:43 +03:00
|
|
|
#include "private/registry.h"
|
2021-05-13 17:54:58 +03:00
|
|
|
|
2021-05-21 18:40:43 +03:00
|
|
|
#include <pipewire/pipewire.h>
|
|
|
|
|
|
log: implement a log topics system, like pipewire
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.
2023-05-16 11:51:29 +03:00
|
|
|
WP_DEFINE_LOCAL_LOG_TOPIC ("wp-object-manager")
|
|
|
|
|
|
2021-05-21 18:40:43 +03:00
|
|
|
/*! \defgroup wpobjectmanager WpObjectManager */
|
2021-05-13 17:54:58 +03:00
|
|
|
/*!
|
2021-05-21 18:40:43 +03:00
|
|
|
* \struct WpObjectManager
|
2020-02-17 15:39:19 +02:00
|
|
|
*
|
2021-05-21 18:40:43 +03:00
|
|
|
* The WpObjectManager class provides a way to collect a set of objects and
|
|
|
|
|
* be notified when objects that fulfill a certain set of criteria are created
|
|
|
|
|
* or destroyed.
|
2021-05-13 17:54:58 +03:00
|
|
|
*
|
|
|
|
|
* There are 4 kinds of objects that can be managed by a
|
2021-05-21 18:40:43 +03:00
|
|
|
* WpObjectManager:
|
2020-02-17 15:39:19 +02:00
|
|
|
* * remote PipeWire global objects that are advertised on the registry;
|
2021-05-21 18:40:43 +03:00
|
|
|
* these are bound locally to subclasses of WpGlobalProxy
|
2020-02-17 15:39:19 +02:00
|
|
|
* * remote PipeWire global objects that are created by calling a remote
|
|
|
|
|
* factory through the WirePlumber API; these are very similar to other
|
2021-05-21 18:40:43 +03:00
|
|
|
* global objects but it should be noted that the same WpGlobalProxy
|
|
|
|
|
* instance that created them appears in the WpObjectManager (as soon as
|
|
|
|
|
* its WP_PROXY_FEATURE_BOUND is enabled)
|
2020-02-17 15:39:19 +02:00
|
|
|
* * local PipeWire objects that are being exported to PipeWire
|
2022-12-09 13:01:13 -05:00
|
|
|
* (WpImplMetadata, WpImplNode, etc); these appear in the
|
2021-05-21 18:40:43 +03:00
|
|
|
* WpObjectManager as soon as they are exported (so, when their
|
|
|
|
|
* WP_PROXY_FEATURE_BOUND is enabled)
|
2021-06-07 17:28:35 +03:00
|
|
|
* * WirePlumber-specific objects, such as plugins, factories and session items
|
2020-02-17 15:39:19 +02:00
|
|
|
*
|
|
|
|
|
* To start an object manager, you first need to declare interest in a certain
|
|
|
|
|
* kind of object by calling wp_object_manager_add_interest() and then install
|
2021-05-21 18:40:43 +03:00
|
|
|
* it on the WpCore with wp_core_install_object_manager().
|
2020-02-17 15:39:19 +02:00
|
|
|
*
|
2021-05-21 18:40:43 +03:00
|
|
|
* Upon installing a WpObjectManager on a WpCore, any pre-existing objects
|
|
|
|
|
* that match the interests of this WpObjectManager will immediately become
|
2021-02-05 10:20:33 -05:00
|
|
|
* available to get through wp_object_manager_new_iterator() and the
|
2021-05-21 18:40:43 +03:00
|
|
|
* WpObjectManager \c object-added signal will be emitted for all of them.
|
2021-12-21 12:51:10 +02:00
|
|
|
* However, note that if these objects need to be prepared (to activate some
|
|
|
|
|
* features on them), the emission of \c object-added will be delayed. To know
|
|
|
|
|
* when it is safe to access the initial set of objects, wait until the
|
|
|
|
|
* \c installed signal has been emitted. That signal is emitted asynchronously
|
|
|
|
|
* after all the initial objects have been prepared.
|
2021-05-13 17:54:58 +03:00
|
|
|
*
|
2021-05-21 18:40:43 +03:00
|
|
|
* \gproperties
|
2021-05-13 17:54:58 +03:00
|
|
|
*
|
2021-05-21 18:40:43 +03:00
|
|
|
* \gproperty{core, WpCore *, G_PARAM_READABLE, The core}
|
2021-05-13 17:54:58 +03:00
|
|
|
*
|
2021-05-21 18:40:43 +03:00
|
|
|
* \gsignals
|
2021-05-13 17:54:58 +03:00
|
|
|
*
|
2021-05-21 18:40:43 +03:00
|
|
|
* \par installed
|
|
|
|
|
* \parblock
|
|
|
|
|
* \code
|
|
|
|
|
* void
|
2021-05-13 17:54:58 +03:00
|
|
|
* installed_callback (WpObjectManager * self,
|
|
|
|
|
* gpointer user_data)
|
2021-05-21 18:40:43 +03:00
|
|
|
* \endcode
|
2021-05-13 17:54:58 +03:00
|
|
|
*
|
2021-05-21 18:40:43 +03:00
|
|
|
* This is emitted once after the object manager is installed with
|
|
|
|
|
* wp_core_install_object_manager(). If there are objects that need to be
|
|
|
|
|
* prepared asynchronously internally, emission of this signal is delayed
|
|
|
|
|
* until all objects are ready.
|
2021-05-13 17:54:58 +03:00
|
|
|
*
|
2021-05-21 18:40:43 +03:00
|
|
|
* Flags: G_SIGNAL_RUN_FIRST
|
|
|
|
|
* \endparblock
|
2021-05-13 17:54:58 +03:00
|
|
|
*
|
2021-05-21 18:40:43 +03:00
|
|
|
* \par object-added
|
|
|
|
|
* \parblock
|
|
|
|
|
* \code
|
|
|
|
|
* void
|
2021-05-13 17:54:58 +03:00
|
|
|
* object_added_callback (WpObjectManager * self,
|
|
|
|
|
* gpointer object,
|
|
|
|
|
* gpointer user_data)
|
2021-05-21 18:40:43 +03:00
|
|
|
* \endcode
|
2021-05-13 17:54:58 +03:00
|
|
|
*
|
2021-05-21 18:40:43 +03:00
|
|
|
* Emitted when an object that matches the interests of this object manager
|
|
|
|
|
* is made available.
|
2021-05-13 17:54:58 +03:00
|
|
|
*
|
2021-05-21 18:40:43 +03:00
|
|
|
* Parameters:
|
|
|
|
|
* - `object` - the managed object that was just added
|
2021-05-13 17:54:58 +03:00
|
|
|
*
|
2021-05-21 18:40:43 +03:00
|
|
|
* Flags: G_SIGNAL_RUN_FIRST
|
|
|
|
|
* \endparblock
|
2021-05-13 17:54:58 +03:00
|
|
|
*
|
2021-05-21 18:40:43 +03:00
|
|
|
* \par object-removed
|
|
|
|
|
* \parblock
|
|
|
|
|
* \code
|
|
|
|
|
* void
|
2021-05-13 17:54:58 +03:00
|
|
|
* object_removed_callback (WpObjectManager * self,
|
|
|
|
|
* gpointer object,
|
|
|
|
|
* gpointer user_data)
|
2021-05-21 18:40:43 +03:00
|
|
|
* \endcode
|
2021-05-13 17:54:58 +03:00
|
|
|
*
|
2021-05-21 18:40:43 +03:00
|
|
|
* Emitted when an object that was previously added on this object manager is
|
|
|
|
|
* now being removed (and most likely destroyed). At the time that this signal
|
|
|
|
|
* is emitted, the object is still alive.
|
2021-05-13 17:54:58 +03:00
|
|
|
*
|
2021-05-21 18:40:43 +03:00
|
|
|
* Parameters:
|
|
|
|
|
* - `object` - the managed object that is being removed
|
2021-05-13 17:54:58 +03:00
|
|
|
*
|
2021-05-21 18:40:43 +03:00
|
|
|
* Flags: G_SIGNAL_RUN_FIRST
|
|
|
|
|
* \endparblock
|
2021-05-13 17:54:58 +03:00
|
|
|
*
|
2021-11-17 14:09:03 +10:00
|
|
|
* \par objects-changed
|
2021-05-21 18:40:43 +03:00
|
|
|
* \parblock
|
|
|
|
|
* \code
|
|
|
|
|
* void
|
2021-11-17 14:09:03 +10:00
|
|
|
* objects_changed_callback (WpObjectManager * self,
|
2021-05-13 17:54:58 +03:00
|
|
|
* gpointer user_data)
|
2021-05-21 18:40:43 +03:00
|
|
|
* \endcode
|
2021-05-13 17:54:58 +03:00
|
|
|
*
|
2021-05-21 18:40:43 +03:00
|
|
|
* Emitted when one or more objects have been recently added or removed from
|
|
|
|
|
* this object manager. This signal is useful to get notified only once when
|
|
|
|
|
* multiple changes happen in a short timespan. The receiving callback may
|
|
|
|
|
* retrieve the updated list of objects by calling wp_object_manager_new_iterator()
|
2021-05-13 17:54:58 +03:00
|
|
|
*
|
2021-05-21 18:40:43 +03:00
|
|
|
* Flags: G_SIGNAL_RUN_FIRST
|
|
|
|
|
* \endparblock
|
2021-05-13 17:54:58 +03:00
|
|
|
*/
|
2021-05-21 18:40:43 +03:00
|
|
|
|
|
|
|
|
struct _WpObjectManager
|
|
|
|
|
{
|
|
|
|
|
GObject parent;
|
|
|
|
|
GWeakRef core;
|
|
|
|
|
|
|
|
|
|
/* element-type: WpObjectInterest* */
|
|
|
|
|
GPtrArray *interests;
|
|
|
|
|
/* element-type: <GType, WpProxyFeatures> */
|
|
|
|
|
GHashTable *features;
|
|
|
|
|
/* objects that we are interested in, without a ref */
|
|
|
|
|
GPtrArray *objects;
|
|
|
|
|
|
|
|
|
|
gboolean installed;
|
|
|
|
|
gboolean changed;
|
|
|
|
|
guint pending_objects;
|
|
|
|
|
GSource *idle_source;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum {
|
|
|
|
|
PROP_0,
|
|
|
|
|
PROP_CORE,
|
|
|
|
|
};
|
|
|
|
|
|
2020-02-14 17:10:53 +02:00
|
|
|
enum {
|
|
|
|
|
SIGNAL_OBJECT_ADDED,
|
|
|
|
|
SIGNAL_OBJECT_REMOVED,
|
|
|
|
|
SIGNAL_OBJECTS_CHANGED,
|
2020-04-24 20:36:53 +03:00
|
|
|
SIGNAL_INSTALLED,
|
2020-02-14 17:10:53 +02:00
|
|
|
LAST_SIGNAL,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static guint signals[LAST_SIGNAL] = { 0 };
|
|
|
|
|
|
|
|
|
|
G_DEFINE_TYPE (WpObjectManager, wp_object_manager, G_TYPE_OBJECT)
|
2020-02-13 19:56:41 +02:00
|
|
|
|
|
|
|
|
static void
|
2020-02-14 17:10:53 +02:00
|
|
|
wp_object_manager_init (WpObjectManager * self)
|
2020-02-13 19:56:41 +02:00
|
|
|
{
|
2020-02-14 17:10:53 +02:00
|
|
|
g_weak_ref_init (&self->core, NULL);
|
2021-01-19 10:52:50 -05:00
|
|
|
self->interests = g_ptr_array_new_with_free_func (
|
|
|
|
|
(GDestroyNotify) wp_object_interest_unref);
|
2020-05-01 19:23:54 +03:00
|
|
|
self->features = g_hash_table_new (g_direct_hash, g_direct_equal);
|
2020-02-14 17:10:53 +02:00
|
|
|
self->objects = g_ptr_array_new ();
|
2020-04-24 20:36:53 +03:00
|
|
|
self->installed = FALSE;
|
|
|
|
|
self->changed = FALSE;
|
|
|
|
|
self->pending_objects = 0;
|
2020-02-13 19:56:41 +02:00
|
|
|
}
|
|
|
|
|
|
2020-02-14 17:10:53 +02:00
|
|
|
static void
|
|
|
|
|
wp_object_manager_finalize (GObject * object)
|
2020-02-13 19:56:41 +02:00
|
|
|
{
|
2020-02-14 17:10:53 +02:00
|
|
|
WpObjectManager *self = WP_OBJECT_MANAGER (object);
|
2020-02-13 19:56:41 +02:00
|
|
|
|
2020-04-24 20:36:53 +03:00
|
|
|
if (self->idle_source) {
|
|
|
|
|
g_source_destroy (self->idle_source);
|
|
|
|
|
g_clear_pointer (&self->idle_source, g_source_unref);
|
|
|
|
|
}
|
2020-02-14 17:10:53 +02:00
|
|
|
g_clear_pointer (&self->objects, g_ptr_array_unref);
|
2020-05-01 19:23:54 +03:00
|
|
|
g_clear_pointer (&self->features, g_hash_table_unref);
|
|
|
|
|
g_clear_pointer (&self->interests, g_ptr_array_unref);
|
2020-02-14 17:10:53 +02:00
|
|
|
g_weak_ref_clear (&self->core);
|
|
|
|
|
|
|
|
|
|
G_OBJECT_CLASS (wp_object_manager_parent_class)->finalize (object);
|
2020-02-13 19:56:41 +02:00
|
|
|
}
|
|
|
|
|
|
2020-02-14 17:10:53 +02:00
|
|
|
static void
|
|
|
|
|
wp_object_manager_get_property (GObject * object, guint property_id,
|
|
|
|
|
GValue * value, GParamSpec * pspec)
|
|
|
|
|
{
|
|
|
|
|
WpObjectManager *self = WP_OBJECT_MANAGER (object);
|
|
|
|
|
|
|
|
|
|
switch (property_id) {
|
|
|
|
|
case PROP_CORE:
|
|
|
|
|
g_value_take_object (value, g_weak_ref_get (&self->core));
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-02-13 19:56:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2020-02-14 17:10:53 +02:00
|
|
|
wp_object_manager_class_init (WpObjectManagerClass * klass)
|
2020-02-13 19:56:41 +02:00
|
|
|
{
|
2020-02-14 17:10:53 +02:00
|
|
|
GObjectClass *object_class = (GObjectClass *) klass;
|
2020-02-13 19:56:41 +02:00
|
|
|
|
2020-02-14 17:10:53 +02:00
|
|
|
object_class->finalize = wp_object_manager_finalize;
|
|
|
|
|
object_class->get_property = wp_object_manager_get_property;
|
2020-02-13 19:56:41 +02:00
|
|
|
|
2020-02-14 17:10:53 +02:00
|
|
|
/* Install the properties */
|
2020-02-14 16:34:05 +02:00
|
|
|
|
2020-02-14 17:10:53 +02:00
|
|
|
g_object_class_install_property (object_class, PROP_CORE,
|
|
|
|
|
g_param_spec_object ("core", "core", "The WpCore", WP_TYPE_CORE,
|
2020-04-24 20:36:53 +03:00
|
|
|
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
2020-02-13 19:56:41 +02:00
|
|
|
|
2020-02-14 17:10:53 +02:00
|
|
|
signals[SIGNAL_OBJECT_ADDED] = g_signal_new (
|
|
|
|
|
"object-added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST,
|
|
|
|
|
0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_OBJECT);
|
2020-02-13 19:56:41 +02:00
|
|
|
|
2020-02-14 17:10:53 +02:00
|
|
|
signals[SIGNAL_OBJECT_REMOVED] = g_signal_new (
|
|
|
|
|
"object-removed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST,
|
|
|
|
|
0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_OBJECT);
|
2020-02-13 19:56:41 +02:00
|
|
|
|
2020-02-14 17:10:53 +02:00
|
|
|
signals[SIGNAL_OBJECTS_CHANGED] = g_signal_new (
|
|
|
|
|
"objects-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST,
|
|
|
|
|
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
2020-04-24 20:36:53 +03:00
|
|
|
|
|
|
|
|
signals[SIGNAL_INSTALLED] = g_signal_new (
|
|
|
|
|
"installed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST,
|
|
|
|
|
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
2020-02-14 17:10:53 +02:00
|
|
|
}
|
2020-02-13 19:56:41 +02:00
|
|
|
|
2021-05-13 17:54:58 +03:00
|
|
|
/*!
|
2021-05-21 18:40:43 +03:00
|
|
|
* \brief Constructs a new object manager.
|
|
|
|
|
* \ingroup wpobjectmanager
|
|
|
|
|
* \returns (transfer full): the newly constructed object manager
|
2020-02-17 15:39:19 +02:00
|
|
|
*/
|
2020-02-14 17:10:53 +02:00
|
|
|
WpObjectManager *
|
|
|
|
|
wp_object_manager_new (void)
|
2020-02-13 19:56:41 +02:00
|
|
|
{
|
2020-02-14 17:10:53 +02:00
|
|
|
return g_object_new (WP_TYPE_OBJECT_MANAGER, NULL);
|
2020-02-13 19:56:41 +02:00
|
|
|
}
|
|
|
|
|
|
2021-05-13 17:54:58 +03:00
|
|
|
/*!
|
2021-06-01 19:39:13 -04:00
|
|
|
* \brief Checks if an object manager is installed.
|
2021-05-21 18:40:43 +03:00
|
|
|
* \ingroup wpobjectmanager
|
|
|
|
|
* \param self the object manager
|
|
|
|
|
* \returns TRUE if the object manager is installed (i.e. the
|
|
|
|
|
* WpObjectManager \c installed signal has been emitted), FALSE otherwise
|
2020-05-07 15:45:00 +03:00
|
|
|
*/
|
|
|
|
|
gboolean
|
|
|
|
|
wp_object_manager_is_installed (WpObjectManager * self)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (WP_IS_OBJECT_MANAGER (self), FALSE);
|
|
|
|
|
return self->installed;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-13 17:54:58 +03:00
|
|
|
/*!
|
2021-05-21 18:40:43 +03:00
|
|
|
* \brief Equivalent to:
|
|
|
|
|
* \code
|
2020-05-01 19:23:54 +03:00
|
|
|
* WpObjectInterest *i = wp_object_interest_new (gtype, ...);
|
|
|
|
|
* wp_object_manager_add_interest_full (self, i);
|
2021-05-21 18:40:43 +03:00
|
|
|
* \endcode
|
2020-05-01 19:23:54 +03:00
|
|
|
*
|
|
|
|
|
* The constraints specified in the variable arguments must follow the rules
|
|
|
|
|
* documented in wp_object_interest_new().
|
2021-05-21 18:40:43 +03:00
|
|
|
*
|
|
|
|
|
* \ingroup wpobjectmanager
|
|
|
|
|
* \param self the object manager
|
|
|
|
|
* \param gtype the GType of the objects that we are declaring interest in
|
|
|
|
|
* \param ... a list of constraints, terminated by NULL
|
2020-05-01 19:23:54 +03:00
|
|
|
*/
|
|
|
|
|
void
|
2020-05-14 16:24:34 +03:00
|
|
|
wp_object_manager_add_interest (WpObjectManager * self, GType gtype, ...)
|
2020-05-01 19:23:54 +03:00
|
|
|
{
|
|
|
|
|
WpObjectInterest *interest;
|
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
|
|
g_return_if_fail (WP_IS_OBJECT_MANAGER (self));
|
|
|
|
|
|
|
|
|
|
va_start (args, gtype);
|
|
|
|
|
interest = wp_object_interest_new_valist (gtype, &args);
|
|
|
|
|
wp_object_manager_add_interest_full (self, interest);
|
|
|
|
|
va_end (args);
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-13 17:54:58 +03:00
|
|
|
/*!
|
2021-05-21 18:40:43 +03:00
|
|
|
* \brief Declares interest in a certain kind of object.
|
|
|
|
|
*
|
|
|
|
|
* Interest consists of a GType that the object must be an ancestor of
|
|
|
|
|
* (g_type_is_a() must match) and optionally, a set of additional constraints
|
|
|
|
|
* on certain properties of the object. Refer to WpObjectInterest for more details.
|
2020-05-01 19:23:54 +03:00
|
|
|
*
|
2021-05-21 18:40:43 +03:00
|
|
|
* \ingroup wpobjectmanager
|
|
|
|
|
* \param self the object manager
|
|
|
|
|
* \param interest (transfer full): the interest
|
2020-05-01 19:23:54 +03:00
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
wp_object_manager_add_interest_full (WpObjectManager *self,
|
|
|
|
|
WpObjectInterest * interest)
|
|
|
|
|
{
|
|
|
|
|
g_autoptr (GError) error = NULL;
|
|
|
|
|
|
|
|
|
|
g_return_if_fail (WP_IS_OBJECT_MANAGER (self));
|
|
|
|
|
|
|
|
|
|
if (G_UNLIKELY (!wp_object_interest_validate (interest, &error))) {
|
|
|
|
|
wp_critical_object (self, "interest validation failed: %s",
|
|
|
|
|
error->message);
|
2021-01-19 10:52:50 -05:00
|
|
|
wp_object_interest_unref (interest);
|
2020-05-01 19:23:54 +03:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
g_ptr_array_add (self->interests, interest);
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-14 13:18:26 +02:00
|
|
|
static void
|
|
|
|
|
store_children_object_features (GHashTable *store, GType object_type,
|
|
|
|
|
WpObjectFeatures wanted_features)
|
|
|
|
|
{
|
|
|
|
|
g_autofree GType *children = NULL;
|
|
|
|
|
GType *child;
|
|
|
|
|
|
|
|
|
|
child = children = g_type_children (object_type, NULL);
|
|
|
|
|
while (*child) {
|
|
|
|
|
WpObjectFeatures existing_ft = (WpObjectFeatures) GPOINTER_TO_UINT (
|
|
|
|
|
g_hash_table_lookup (store, GSIZE_TO_POINTER (*child)));
|
|
|
|
|
g_hash_table_insert (store, GSIZE_TO_POINTER (*child),
|
|
|
|
|
GUINT_TO_POINTER (existing_ft | wanted_features));
|
|
|
|
|
store_children_object_features (store, *child, wanted_features);
|
|
|
|
|
child++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-13 17:54:58 +03:00
|
|
|
/*!
|
2021-05-21 18:40:43 +03:00
|
|
|
* \brief Requests the object manager to automatically prepare the
|
|
|
|
|
* \a wanted_features on any managed object that is of the specified
|
|
|
|
|
* \a object_type.
|
|
|
|
|
*
|
|
|
|
|
* These features will always be prepared before the object appears on the
|
|
|
|
|
* object manager.
|
2020-05-01 19:23:54 +03:00
|
|
|
*
|
2021-05-21 18:40:43 +03:00
|
|
|
* \ingroup wpobjectmanager
|
|
|
|
|
* \param self the object manager
|
|
|
|
|
* \param object_type the WpProxy descendant type
|
|
|
|
|
* \param wanted_features the features to enable on this kind of object
|
2020-05-01 19:23:54 +03:00
|
|
|
*/
|
|
|
|
|
void
|
lib: refactor WpProxy
This is an attempt to unclutter the API of WpProxy and
split functionality into smaller pieces, making it easier
to work with.
In this new class layout, we have the following classes:
- WpObject: base class for everything; handles activating
| and deactivating "features"
|- WpProxy: base class for anything that wraps a pw_proxy;
| handles events from pw_proxy and nothing more
|- WpGlobalProxy: handles integration with the registry
All the other classes derive from WpGlobalProxy. The reason
for separating WpGlobalProxy from WpProxy, though, is that
classes such as WpImplNode / WpSpaDevice can also derive from
WpProxy now, without interfacing with the registry.
All objects that come with an "info" structure and have properties
and/or params also implement the WpPipewireObject interface. This
provides the API to query properties and get/set params. Essentially,
this is implemented by all classes except WpMetadata (pw_metadata
does not have info)
This interface is implemented on each object separately, using
a private "mixin", which is a set of vfunc implementations and helper
functions (and macros) to facilitate the implementation of this interface.
A notable difference to the old WpProxy is that now features can be
deactivated, so it is possible to enable something and later disable
it again.
This commit disables modules, tests, tools, etc, to avoid growing the
patch more, while ensuring that the project compiles.
2020-11-10 19:17:02 +02:00
|
|
|
wp_object_manager_request_object_features (WpObjectManager *self,
|
2020-11-14 13:18:26 +02:00
|
|
|
GType object_type, WpObjectFeatures wanted_features)
|
2020-05-01 19:23:54 +03:00
|
|
|
{
|
|
|
|
|
g_return_if_fail (WP_IS_OBJECT_MANAGER (self));
|
lib: refactor WpProxy
This is an attempt to unclutter the API of WpProxy and
split functionality into smaller pieces, making it easier
to work with.
In this new class layout, we have the following classes:
- WpObject: base class for everything; handles activating
| and deactivating "features"
|- WpProxy: base class for anything that wraps a pw_proxy;
| handles events from pw_proxy and nothing more
|- WpGlobalProxy: handles integration with the registry
All the other classes derive from WpGlobalProxy. The reason
for separating WpGlobalProxy from WpProxy, though, is that
classes such as WpImplNode / WpSpaDevice can also derive from
WpProxy now, without interfacing with the registry.
All objects that come with an "info" structure and have properties
and/or params also implement the WpPipewireObject interface. This
provides the API to query properties and get/set params. Essentially,
this is implemented by all classes except WpMetadata (pw_metadata
does not have info)
This interface is implemented on each object separately, using
a private "mixin", which is a set of vfunc implementations and helper
functions (and macros) to facilitate the implementation of this interface.
A notable difference to the old WpProxy is that now features can be
deactivated, so it is possible to enable something and later disable
it again.
This commit disables modules, tests, tools, etc, to avoid growing the
patch more, while ensuring that the project compiles.
2020-11-10 19:17:02 +02:00
|
|
|
g_return_if_fail (g_type_is_a (object_type, WP_TYPE_OBJECT));
|
2020-05-01 19:23:54 +03:00
|
|
|
|
lib: refactor WpProxy
This is an attempt to unclutter the API of WpProxy and
split functionality into smaller pieces, making it easier
to work with.
In this new class layout, we have the following classes:
- WpObject: base class for everything; handles activating
| and deactivating "features"
|- WpProxy: base class for anything that wraps a pw_proxy;
| handles events from pw_proxy and nothing more
|- WpGlobalProxy: handles integration with the registry
All the other classes derive from WpGlobalProxy. The reason
for separating WpGlobalProxy from WpProxy, though, is that
classes such as WpImplNode / WpSpaDevice can also derive from
WpProxy now, without interfacing with the registry.
All objects that come with an "info" structure and have properties
and/or params also implement the WpPipewireObject interface. This
provides the API to query properties and get/set params. Essentially,
this is implemented by all classes except WpMetadata (pw_metadata
does not have info)
This interface is implemented on each object separately, using
a private "mixin", which is a set of vfunc implementations and helper
functions (and macros) to facilitate the implementation of this interface.
A notable difference to the old WpProxy is that now features can be
deactivated, so it is possible to enable something and later disable
it again.
This commit disables modules, tests, tools, etc, to avoid growing the
patch more, while ensuring that the project compiles.
2020-11-10 19:17:02 +02:00
|
|
|
g_hash_table_insert (self->features, GSIZE_TO_POINTER (object_type),
|
2020-05-01 19:23:54 +03:00
|
|
|
GUINT_TO_POINTER (wanted_features));
|
2020-11-14 13:18:26 +02:00
|
|
|
store_children_object_features (self->features, object_type, wanted_features);
|
2020-02-14 17:10:53 +02:00
|
|
|
}
|
2020-02-13 19:56:41 +02:00
|
|
|
|
2021-05-13 17:54:58 +03:00
|
|
|
/*!
|
2021-06-01 19:39:13 -04:00
|
|
|
* \brief Gets the number of objects managed by the object manager.
|
2021-05-21 18:40:43 +03:00
|
|
|
* \ingroup wpobjectmanager
|
|
|
|
|
* \param self the object manager
|
|
|
|
|
* \returns the number of objects managed by this WpObjectManager
|
2020-03-31 15:00:41 +03:00
|
|
|
*/
|
|
|
|
|
guint
|
|
|
|
|
wp_object_manager_get_n_objects (WpObjectManager * self)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (WP_IS_OBJECT_MANAGER (self), 0);
|
|
|
|
|
return self->objects->len;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-21 13:21:03 +03:00
|
|
|
struct om_iterator_data
|
|
|
|
|
{
|
|
|
|
|
WpObjectManager *om;
|
2022-12-06 11:31:08 +02:00
|
|
|
GPtrArray *objects;
|
2020-05-01 19:23:54 +03:00
|
|
|
WpObjectInterest *interest;
|
2020-04-21 13:21:03 +03:00
|
|
|
guint index;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
om_iterator_reset (WpIterator *it)
|
|
|
|
|
{
|
|
|
|
|
struct om_iterator_data *it_data = wp_iterator_get_user_data (it);
|
|
|
|
|
it_data->index = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
om_iterator_next (WpIterator *it, GValue *item)
|
|
|
|
|
{
|
|
|
|
|
struct om_iterator_data *it_data = wp_iterator_get_user_data (it);
|
|
|
|
|
|
2022-12-06 11:31:08 +02:00
|
|
|
while (it_data->index < it_data->objects->len) {
|
|
|
|
|
gpointer obj = g_ptr_array_index (it_data->objects, it_data->index++);
|
2020-05-01 19:23:54 +03:00
|
|
|
|
|
|
|
|
/* take the next object that matches the interest, if any */
|
|
|
|
|
if (!it_data->interest ||
|
|
|
|
|
wp_object_interest_matches (it_data->interest, obj)) {
|
|
|
|
|
g_value_init_from_instance (item, obj);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
2020-04-21 13:21:03 +03:00
|
|
|
}
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
om_iterator_fold (WpIterator *it, WpIteratorFoldFunc func, GValue *ret,
|
|
|
|
|
gpointer data)
|
|
|
|
|
{
|
|
|
|
|
struct om_iterator_data *it_data = wp_iterator_get_user_data (it);
|
|
|
|
|
gpointer *obj, *base;
|
|
|
|
|
guint len;
|
|
|
|
|
|
2022-12-06 11:31:08 +02:00
|
|
|
obj = base = it_data->objects->pdata;
|
|
|
|
|
len = it_data->objects->len;
|
2020-04-21 13:21:03 +03:00
|
|
|
|
|
|
|
|
while ((obj - base) < len) {
|
2020-05-01 19:23:54 +03:00
|
|
|
/* only pass matching objects to the fold func if we have an interest */
|
|
|
|
|
if (!it_data->interest ||
|
2020-05-31 12:18:29 +03:00
|
|
|
wp_object_interest_matches (it_data->interest, *obj)) {
|
2020-05-01 19:23:54 +03:00
|
|
|
g_auto (GValue) item = G_VALUE_INIT;
|
|
|
|
|
g_value_init_from_instance (&item, *obj);
|
|
|
|
|
if (!func (&item, ret, data))
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2020-04-21 13:21:03 +03:00
|
|
|
obj++;
|
|
|
|
|
}
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
om_iterator_finalize (WpIterator *it)
|
|
|
|
|
{
|
|
|
|
|
struct om_iterator_data *it_data = wp_iterator_get_user_data (it);
|
2022-12-06 11:31:08 +02:00
|
|
|
g_clear_pointer (&it_data->objects, g_ptr_array_unref);
|
2021-01-19 10:52:50 -05:00
|
|
|
g_clear_pointer (&it_data->interest, wp_object_interest_unref);
|
2020-04-21 13:21:03 +03:00
|
|
|
g_object_unref (it_data->om);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const WpIteratorMethods om_iterator_methods = {
|
2020-11-16 11:16:35 +02:00
|
|
|
.version = WP_ITERATOR_METHODS_VERSION,
|
2020-04-21 13:21:03 +03:00
|
|
|
.reset = om_iterator_reset,
|
|
|
|
|
.next = om_iterator_next,
|
|
|
|
|
.fold = om_iterator_fold,
|
|
|
|
|
.finalize = om_iterator_finalize,
|
|
|
|
|
};
|
|
|
|
|
|
2021-05-13 17:54:58 +03:00
|
|
|
/*!
|
2021-06-01 19:39:13 -04:00
|
|
|
* \brief Iterates through all the objects managed by this object manager.
|
2021-05-21 18:40:43 +03:00
|
|
|
* \ingroup wpobjectmanager
|
|
|
|
|
* \param self the object manager
|
|
|
|
|
* \returns (transfer full): a WpIterator that iterates over all the managed
|
2020-04-21 13:21:03 +03:00
|
|
|
* objects of this object manager
|
2020-02-14 17:10:53 +02:00
|
|
|
*/
|
2020-04-21 13:21:03 +03:00
|
|
|
WpIterator *
|
2021-02-05 10:20:33 -05:00
|
|
|
wp_object_manager_new_iterator (WpObjectManager * self)
|
2020-02-14 17:10:53 +02:00
|
|
|
{
|
2020-04-21 13:21:03 +03:00
|
|
|
WpIterator *it;
|
|
|
|
|
struct om_iterator_data *it_data;
|
2020-02-13 19:56:41 +02:00
|
|
|
|
2020-04-21 13:21:03 +03:00
|
|
|
g_return_val_if_fail (WP_IS_OBJECT_MANAGER (self), NULL);
|
|
|
|
|
|
|
|
|
|
it = wp_iterator_new (&om_iterator_methods, sizeof (struct om_iterator_data));
|
|
|
|
|
it_data = wp_iterator_get_user_data (it);
|
|
|
|
|
it_data->om = g_object_ref (self);
|
2022-12-06 11:31:08 +02:00
|
|
|
it_data->objects = g_ptr_array_copy (self->objects, NULL, NULL);
|
2020-04-21 13:21:03 +03:00
|
|
|
it_data->index = 0;
|
|
|
|
|
return it;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-13 17:54:58 +03:00
|
|
|
/*!
|
2021-05-21 18:40:43 +03:00
|
|
|
* \brief Equivalent to:
|
|
|
|
|
* \code
|
2020-05-01 19:23:54 +03:00
|
|
|
* WpObjectInterest *i = wp_object_interest_new (gtype, ...);
|
2021-02-05 10:20:33 -05:00
|
|
|
* return wp_object_manager_new_filtered_iterator_full (self, i);
|
2021-05-21 18:40:43 +03:00
|
|
|
* \endcode
|
2020-05-01 19:23:54 +03:00
|
|
|
*
|
|
|
|
|
* The constraints specified in the variable arguments must follow the rules
|
|
|
|
|
* documented in wp_object_interest_new().
|
|
|
|
|
*
|
2021-05-21 18:40:43 +03:00
|
|
|
* \ingroup wpobjectmanager
|
|
|
|
|
* \param self the object manager
|
|
|
|
|
* \param gtype the GType of the objects to iterate through
|
|
|
|
|
* \param ... a list of constraints, terminated by NULL
|
|
|
|
|
* \returns (transfer full): a WpIterator that iterates over all the matching
|
2020-05-01 19:23:54 +03:00
|
|
|
* objects of this object manager
|
|
|
|
|
*/
|
|
|
|
|
WpIterator *
|
2021-02-05 10:20:33 -05:00
|
|
|
wp_object_manager_new_filtered_iterator (WpObjectManager * self, GType gtype,
|
|
|
|
|
...)
|
2020-05-01 19:23:54 +03:00
|
|
|
{
|
|
|
|
|
WpObjectInterest *interest;
|
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (WP_IS_OBJECT_MANAGER (self), NULL);
|
|
|
|
|
|
|
|
|
|
va_start (args, gtype);
|
|
|
|
|
interest = wp_object_interest_new_valist (gtype, &args);
|
|
|
|
|
va_end (args);
|
|
|
|
|
|
2021-02-05 10:20:33 -05:00
|
|
|
return wp_object_manager_new_filtered_iterator_full (self, interest);
|
2020-05-01 19:23:54 +03:00
|
|
|
}
|
|
|
|
|
|
2021-05-13 17:54:58 +03:00
|
|
|
/*!
|
2021-05-21 18:40:43 +03:00
|
|
|
* \brief Iterates through all the objects managed by this object manager that
|
|
|
|
|
* match the specified \a interest.
|
2020-05-01 19:23:54 +03:00
|
|
|
*
|
2021-05-21 18:40:43 +03:00
|
|
|
* \ingroup wpobjectmanager
|
|
|
|
|
* \param self the object manager
|
|
|
|
|
* \param interest (transfer full): the interest
|
|
|
|
|
* \returns (transfer full): a WpIterator that iterates over all the matching
|
2020-05-01 19:23:54 +03:00
|
|
|
* objects of this object manager
|
|
|
|
|
*/
|
|
|
|
|
WpIterator *
|
2021-02-05 10:20:33 -05:00
|
|
|
wp_object_manager_new_filtered_iterator_full (WpObjectManager * self,
|
2020-05-01 19:23:54 +03:00
|
|
|
WpObjectInterest * interest)
|
|
|
|
|
{
|
|
|
|
|
WpIterator *it;
|
|
|
|
|
struct om_iterator_data *it_data;
|
|
|
|
|
g_autoptr (GError) error = NULL;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (WP_IS_OBJECT_MANAGER (self), NULL);
|
|
|
|
|
|
|
|
|
|
if (G_UNLIKELY (!wp_object_interest_validate (interest, &error))) {
|
|
|
|
|
wp_critical_object (self, "interest validation failed: %s",
|
|
|
|
|
error->message);
|
2021-01-19 10:52:50 -05:00
|
|
|
wp_object_interest_unref (interest);
|
2020-05-01 19:23:54 +03:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
it = wp_iterator_new (&om_iterator_methods, sizeof (struct om_iterator_data));
|
|
|
|
|
it_data = wp_iterator_get_user_data (it);
|
|
|
|
|
it_data->om = g_object_ref (self);
|
2022-12-06 11:31:08 +02:00
|
|
|
it_data->objects = g_ptr_array_copy (self->objects, NULL, NULL);
|
2020-05-01 19:23:54 +03:00
|
|
|
it_data->interest = interest;
|
|
|
|
|
it_data->index = 0;
|
|
|
|
|
return it;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-13 17:54:58 +03:00
|
|
|
/*!
|
2021-05-21 18:40:43 +03:00
|
|
|
* \brief Equivalent to:
|
|
|
|
|
* \code
|
2020-05-01 19:23:54 +03:00
|
|
|
* WpObjectInterest *i = wp_object_interest_new (gtype, ...);
|
|
|
|
|
* return wp_object_manager_lookup_full (self, i);
|
2021-05-21 18:40:43 +03:00
|
|
|
* \endcode
|
2020-05-01 19:23:54 +03:00
|
|
|
*
|
|
|
|
|
* The constraints specified in the variable arguments must follow the rules
|
|
|
|
|
* documented in wp_object_interest_new().
|
|
|
|
|
*
|
2021-05-21 18:40:43 +03:00
|
|
|
* \ingroup wpobjectmanager
|
|
|
|
|
* \param self the object manager
|
|
|
|
|
* \param gtype the GType of the object to lookup
|
|
|
|
|
* \param ... a list of constraints, terminated by NULL
|
|
|
|
|
* \returns (type GObject)(transfer full)(nullable): the first managed object
|
|
|
|
|
* that matches the lookup interest, or NULL if no object matches
|
2020-05-01 19:23:54 +03:00
|
|
|
*/
|
|
|
|
|
gpointer
|
|
|
|
|
wp_object_manager_lookup (WpObjectManager * self, GType gtype, ...)
|
2020-02-13 19:56:41 +02:00
|
|
|
{
|
2020-05-01 19:23:54 +03:00
|
|
|
WpObjectInterest *interest;
|
|
|
|
|
va_list args;
|
2020-02-14 16:34:05 +02:00
|
|
|
|
2020-05-01 19:23:54 +03:00
|
|
|
g_return_val_if_fail (WP_IS_OBJECT_MANAGER (self), NULL);
|
2020-02-14 16:34:05 +02:00
|
|
|
|
2020-05-01 19:23:54 +03:00
|
|
|
va_start (args, gtype);
|
|
|
|
|
interest = wp_object_interest_new_valist (gtype, &args);
|
|
|
|
|
va_end (args);
|
2020-02-14 16:34:05 +02:00
|
|
|
|
2020-05-01 19:23:54 +03:00
|
|
|
return wp_object_manager_lookup_full (self, interest);
|
|
|
|
|
}
|
2020-02-14 16:34:05 +02:00
|
|
|
|
2021-05-13 17:54:58 +03:00
|
|
|
/*!
|
2021-05-21 18:40:43 +03:00
|
|
|
* \brief Searches for an object that matches the specified \a interest and
|
|
|
|
|
* returns it, if found.
|
2020-05-01 19:23:54 +03:00
|
|
|
*
|
2021-05-21 18:40:43 +03:00
|
|
|
* If more than one objects match, only the first one is returned.
|
2020-05-01 19:23:54 +03:00
|
|
|
* To find multiple objects that match certain criteria,
|
2021-02-05 10:20:33 -05:00
|
|
|
* wp_object_manager_new_filtered_iterator() is more suitable.
|
2020-05-01 19:23:54 +03:00
|
|
|
*
|
2021-05-21 18:40:43 +03:00
|
|
|
* \ingroup wpobjectmanager
|
|
|
|
|
* \param self the object manager
|
|
|
|
|
* \param interest (transfer full): the interst
|
|
|
|
|
* \returns (type GObject)(transfer full)(nullable): the first managed object
|
|
|
|
|
* that matches the lookup interest, or NULL if no object matches
|
2020-05-01 19:23:54 +03:00
|
|
|
*/
|
|
|
|
|
gpointer
|
|
|
|
|
wp_object_manager_lookup_full (WpObjectManager * self,
|
|
|
|
|
WpObjectInterest * interest)
|
|
|
|
|
{
|
|
|
|
|
g_auto (GValue) ret = G_VALUE_INIT;
|
|
|
|
|
g_autoptr (WpIterator) it =
|
2021-02-05 10:20:33 -05:00
|
|
|
wp_object_manager_new_filtered_iterator_full (self, interest);
|
2020-02-14 16:34:05 +02:00
|
|
|
|
2020-05-01 19:23:54 +03:00
|
|
|
if (wp_iterator_next (it, &ret))
|
|
|
|
|
return g_value_dup_object (&ret);
|
2020-02-14 16:34:05 +02:00
|
|
|
|
2020-05-01 19:23:54 +03:00
|
|
|
return NULL;
|
2020-02-13 19:56:41 +02:00
|
|
|
}
|
|
|
|
|
|
2020-02-14 17:10:53 +02:00
|
|
|
static gboolean
|
|
|
|
|
wp_object_manager_is_interested_in_object (WpObjectManager * self,
|
|
|
|
|
GObject * object)
|
2020-02-13 19:56:41 +02:00
|
|
|
{
|
2020-12-20 22:14:00 +02:00
|
|
|
guint i;
|
2020-05-01 19:23:54 +03:00
|
|
|
WpObjectInterest *interest = NULL;
|
2020-02-13 19:56:41 +02:00
|
|
|
|
2020-05-01 19:23:54 +03:00
|
|
|
for (i = 0; i < self->interests->len; i++) {
|
|
|
|
|
interest = g_ptr_array_index (self->interests, i);
|
|
|
|
|
if (wp_object_interest_matches (interest, object))
|
2020-02-14 17:10:53 +02:00
|
|
|
return TRUE;
|
2020-02-13 19:56:41 +02:00
|
|
|
}
|
2020-02-14 17:10:53 +02:00
|
|
|
return FALSE;
|
2020-02-13 19:56:41 +02:00
|
|
|
}
|
|
|
|
|
|
2020-02-14 17:10:53 +02:00
|
|
|
static gboolean
|
|
|
|
|
wp_object_manager_is_interested_in_global (WpObjectManager * self,
|
lib: refactor WpProxy
This is an attempt to unclutter the API of WpProxy and
split functionality into smaller pieces, making it easier
to work with.
In this new class layout, we have the following classes:
- WpObject: base class for everything; handles activating
| and deactivating "features"
|- WpProxy: base class for anything that wraps a pw_proxy;
| handles events from pw_proxy and nothing more
|- WpGlobalProxy: handles integration with the registry
All the other classes derive from WpGlobalProxy. The reason
for separating WpGlobalProxy from WpProxy, though, is that
classes such as WpImplNode / WpSpaDevice can also derive from
WpProxy now, without interfacing with the registry.
All objects that come with an "info" structure and have properties
and/or params also implement the WpPipewireObject interface. This
provides the API to query properties and get/set params. Essentially,
this is implemented by all classes except WpMetadata (pw_metadata
does not have info)
This interface is implemented on each object separately, using
a private "mixin", which is a set of vfunc implementations and helper
functions (and macros) to facilitate the implementation of this interface.
A notable difference to the old WpProxy is that now features can be
deactivated, so it is possible to enable something and later disable
it again.
This commit disables modules, tests, tools, etc, to avoid growing the
patch more, while ensuring that the project compiles.
2020-11-10 19:17:02 +02:00
|
|
|
WpGlobal * global, WpObjectFeatures * wanted_features)
|
2020-02-13 19:56:41 +02:00
|
|
|
{
|
2020-12-20 22:14:00 +02:00
|
|
|
guint i;
|
2020-05-01 19:23:54 +03:00
|
|
|
WpObjectInterest *interest = NULL;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < self->interests->len; i++) {
|
|
|
|
|
interest = g_ptr_array_index (self->interests, i);
|
2021-06-07 17:23:15 +03:00
|
|
|
|
|
|
|
|
/* 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) */
|
2023-10-23 23:04:02 +03:00
|
|
|
if (SPA_FLAG_IS_SET (match, (WP_INTEREST_MATCH_GTYPE |
|
|
|
|
|
WP_INTEREST_MATCH_PW_GLOBAL_PROPERTIES))) {
|
2020-05-01 19:23:54 +03:00
|
|
|
gpointer ft = g_hash_table_lookup (self->features,
|
|
|
|
|
GSIZE_TO_POINTER (global->type));
|
lib: refactor WpProxy
This is an attempt to unclutter the API of WpProxy and
split functionality into smaller pieces, making it easier
to work with.
In this new class layout, we have the following classes:
- WpObject: base class for everything; handles activating
| and deactivating "features"
|- WpProxy: base class for anything that wraps a pw_proxy;
| handles events from pw_proxy and nothing more
|- WpGlobalProxy: handles integration with the registry
All the other classes derive from WpGlobalProxy. The reason
for separating WpGlobalProxy from WpProxy, though, is that
classes such as WpImplNode / WpSpaDevice can also derive from
WpProxy now, without interfacing with the registry.
All objects that come with an "info" structure and have properties
and/or params also implement the WpPipewireObject interface. This
provides the API to query properties and get/set params. Essentially,
this is implemented by all classes except WpMetadata (pw_metadata
does not have info)
This interface is implemented on each object separately, using
a private "mixin", which is a set of vfunc implementations and helper
functions (and macros) to facilitate the implementation of this interface.
A notable difference to the old WpProxy is that now features can be
deactivated, so it is possible to enable something and later disable
it again.
This commit disables modules, tests, tools, etc, to avoid growing the
patch more, while ensuring that the project compiles.
2020-11-10 19:17:02 +02:00
|
|
|
*wanted_features = (WpObjectFeatures) GPOINTER_TO_UINT (ft);
|
2021-06-07 17:23:15 +03:00
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
|
2020-02-14 17:10:53 +02:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
2020-02-13 19:56:41 +02:00
|
|
|
}
|
2020-02-14 17:10:53 +02:00
|
|
|
return FALSE;
|
2020-02-13 19:56:41 +02:00
|
|
|
}
|
|
|
|
|
|
2020-04-24 20:36:53 +03:00
|
|
|
static gboolean
|
|
|
|
|
idle_emit_objects_changed (WpObjectManager * self)
|
2020-02-13 19:56:41 +02:00
|
|
|
{
|
2020-04-24 20:36:53 +03:00
|
|
|
g_clear_pointer (&self->idle_source, g_source_unref);
|
2020-02-13 19:56:41 +02:00
|
|
|
|
2020-04-24 20:36:53 +03:00
|
|
|
if (G_UNLIKELY (!self->installed)) {
|
|
|
|
|
wp_trace_object (self, "installed");
|
|
|
|
|
self->installed = TRUE;
|
2023-04-11 22:06:21 +03:00
|
|
|
g_signal_emit (self, signals[SIGNAL_INSTALLED], 0);
|
2020-04-24 20:36:53 +03:00
|
|
|
}
|
2020-05-03 19:44:42 +03:00
|
|
|
wp_trace_object (self, "emit objects-changed");
|
2020-02-14 17:10:53 +02:00
|
|
|
g_signal_emit (self, signals[SIGNAL_OBJECTS_CHANGED], 0);
|
2020-04-24 20:36:53 +03:00
|
|
|
|
|
|
|
|
return G_SOURCE_REMOVE;
|
2020-02-14 17:10:53 +02:00
|
|
|
}
|
2020-02-13 19:56:41 +02:00
|
|
|
|
2024-03-12 11:52:56 +02:00
|
|
|
void
|
2020-04-24 20:36:53 +03:00
|
|
|
wp_object_manager_maybe_objects_changed (WpObjectManager * self)
|
2020-02-14 17:10:53 +02:00
|
|
|
{
|
2020-05-03 19:44:42 +03:00
|
|
|
wp_trace_object (self, "pending:%u changed:%d idle_source:%p installed:%d",
|
|
|
|
|
self->pending_objects, self->changed, self->idle_source, self->installed);
|
|
|
|
|
|
2020-04-24 20:36:53 +03:00
|
|
|
/* always wait until there are no pending objects */
|
|
|
|
|
if (self->pending_objects > 0)
|
2020-02-13 19:56:41 +02:00
|
|
|
return;
|
|
|
|
|
|
2020-04-24 20:36:53 +03:00
|
|
|
/* Emit 'objects-changed' when:
|
|
|
|
|
* - there are no pending objects
|
|
|
|
|
* - object-added or object-removed has been emitted at least once
|
|
|
|
|
*/
|
|
|
|
|
if (self->changed) {
|
|
|
|
|
self->changed = FALSE;
|
|
|
|
|
|
|
|
|
|
/* schedule emission in idle; if it is already scheduled from earlier,
|
|
|
|
|
there is nothing to do; we will emit objects-changed once for all
|
|
|
|
|
changes... win-win */
|
|
|
|
|
if (!self->idle_source) {
|
|
|
|
|
g_autoptr (WpCore) core = g_weak_ref_get (&self->core);
|
|
|
|
|
if (core) {
|
2021-09-28 11:46:46 +03:00
|
|
|
wp_core_idle_add_closure (core, &self->idle_source,
|
|
|
|
|
g_cclosure_new_object (
|
|
|
|
|
G_CALLBACK (idle_emit_objects_changed), G_OBJECT (self)));
|
2020-04-24 20:36:53 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* Emit 'installed' when:
|
|
|
|
|
* - there are no pending objects
|
|
|
|
|
* - !changed: there was no object added
|
|
|
|
|
* - !installed: not already installed
|
|
|
|
|
* - the registry does not have pending globals; these may be interesting
|
|
|
|
|
* to our object manager, so let's wait a bit until they are released
|
|
|
|
|
* and re-evaluate again later
|
2020-05-13 19:24:29 +03:00
|
|
|
* - the registry has globals; if we are on early startup where we don't
|
|
|
|
|
* have any globals yet, wait...
|
2020-04-24 20:36:53 +03:00
|
|
|
*/
|
|
|
|
|
else if (!self->installed) {
|
|
|
|
|
g_autoptr (WpCore) core = g_weak_ref_get (&self->core);
|
2020-05-13 19:52:25 +03:00
|
|
|
if (core) {
|
|
|
|
|
WpRegistry *reg = wp_core_get_registry (core);
|
|
|
|
|
if (reg->tmp_globals->len == 0 && reg->globals->len != 0) {
|
|
|
|
|
wp_trace_object (self, "installed");
|
|
|
|
|
self->installed = TRUE;
|
2023-04-11 22:06:21 +03:00
|
|
|
g_signal_emit (self, signals[SIGNAL_INSTALLED], 0);
|
2020-05-13 19:52:25 +03:00
|
|
|
}
|
2020-04-24 20:36:53 +03:00
|
|
|
}
|
2020-02-14 17:10:53 +02:00
|
|
|
}
|
2020-02-13 19:56:41 +02:00
|
|
|
}
|
|
|
|
|
|
2021-06-07 17:23:15 +03:00
|
|
|
/* caller must also call wp_object_manager_maybe_objects_changed() after */
|
2024-03-12 11:52:56 +02:00
|
|
|
void
|
2021-06-07 17:23:15 +03:00
|
|
|
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 */
|
2024-03-12 11:52:56 +02:00
|
|
|
void
|
2021-06-07 17:23:15 +03:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-14 17:10:53 +02:00
|
|
|
static void
|
|
|
|
|
on_proxy_ready (GObject * proxy, GAsyncResult * res, gpointer data)
|
2020-02-13 19:56:41 +02:00
|
|
|
{
|
2020-02-14 17:10:53 +02:00
|
|
|
g_autoptr (WpObjectManager) self = WP_OBJECT_MANAGER (data);
|
|
|
|
|
g_autoptr (GError) error = NULL;
|
2020-02-13 19:56:41 +02:00
|
|
|
|
2020-04-24 20:36:53 +03:00
|
|
|
self->pending_objects--;
|
|
|
|
|
|
lib: refactor WpProxy
This is an attempt to unclutter the API of WpProxy and
split functionality into smaller pieces, making it easier
to work with.
In this new class layout, we have the following classes:
- WpObject: base class for everything; handles activating
| and deactivating "features"
|- WpProxy: base class for anything that wraps a pw_proxy;
| handles events from pw_proxy and nothing more
|- WpGlobalProxy: handles integration with the registry
All the other classes derive from WpGlobalProxy. The reason
for separating WpGlobalProxy from WpProxy, though, is that
classes such as WpImplNode / WpSpaDevice can also derive from
WpProxy now, without interfacing with the registry.
All objects that come with an "info" structure and have properties
and/or params also implement the WpPipewireObject interface. This
provides the API to query properties and get/set params. Essentially,
this is implemented by all classes except WpMetadata (pw_metadata
does not have info)
This interface is implemented on each object separately, using
a private "mixin", which is a set of vfunc implementations and helper
functions (and macros) to facilitate the implementation of this interface.
A notable difference to the old WpProxy is that now features can be
deactivated, so it is possible to enable something and later disable
it again.
This commit disables modules, tests, tools, etc, to avoid growing the
patch more, while ensuring that the project compiles.
2020-11-10 19:17:02 +02:00
|
|
|
if (!wp_object_activate_finish (WP_OBJECT (proxy), res, &error)) {
|
2021-10-14 22:49:02 +03:00
|
|
|
wp_debug_object (self, "proxy activation failed: %s", error->message);
|
2020-04-24 20:36:53 +03:00
|
|
|
} else {
|
2021-06-07 17:23:15 +03:00
|
|
|
wp_object_manager_add_object (self, proxy);
|
2020-02-13 19:56:41 +02:00
|
|
|
}
|
2020-04-14 18:31:17 +03:00
|
|
|
|
2020-04-24 20:36:53 +03:00
|
|
|
wp_object_manager_maybe_objects_changed (self);
|
2020-02-13 19:56:41 +02:00
|
|
|
}
|
|
|
|
|
|
2020-04-24 20:36:53 +03:00
|
|
|
/* caller must also call wp_object_manager_maybe_objects_changed() after */
|
2024-03-12 11:52:56 +02:00
|
|
|
void
|
2020-02-14 17:10:53 +02:00
|
|
|
wp_object_manager_add_global (WpObjectManager * self, WpGlobal * global)
|
2020-02-13 19:56:41 +02:00
|
|
|
{
|
2020-02-14 17:10:53 +02:00
|
|
|
WpProxyFeatures features = 0;
|
2020-02-13 19:56:41 +02:00
|
|
|
|
2020-06-01 17:48:27 +03:00
|
|
|
/* do not allow proxies that don't have a defined subclass;
|
|
|
|
|
bind will fail because proxy_class->pw_iface_type is NULL */
|
lib: refactor WpProxy
This is an attempt to unclutter the API of WpProxy and
split functionality into smaller pieces, making it easier
to work with.
In this new class layout, we have the following classes:
- WpObject: base class for everything; handles activating
| and deactivating "features"
|- WpProxy: base class for anything that wraps a pw_proxy;
| handles events from pw_proxy and nothing more
|- WpGlobalProxy: handles integration with the registry
All the other classes derive from WpGlobalProxy. The reason
for separating WpGlobalProxy from WpProxy, though, is that
classes such as WpImplNode / WpSpaDevice can also derive from
WpProxy now, without interfacing with the registry.
All objects that come with an "info" structure and have properties
and/or params also implement the WpPipewireObject interface. This
provides the API to query properties and get/set params. Essentially,
this is implemented by all classes except WpMetadata (pw_metadata
does not have info)
This interface is implemented on each object separately, using
a private "mixin", which is a set of vfunc implementations and helper
functions (and macros) to facilitate the implementation of this interface.
A notable difference to the old WpProxy is that now features can be
deactivated, so it is possible to enable something and later disable
it again.
This commit disables modules, tests, tools, etc, to avoid growing the
patch more, while ensuring that the project compiles.
2020-11-10 19:17:02 +02:00
|
|
|
if (global->type == WP_TYPE_GLOBAL_PROXY)
|
2020-06-01 17:48:27 +03:00
|
|
|
return;
|
|
|
|
|
|
2020-02-14 17:10:53 +02:00
|
|
|
if (wp_object_manager_is_interested_in_global (self, global, &features)) {
|
|
|
|
|
g_autoptr (WpCore) core = g_weak_ref_get (&self->core);
|
2020-02-13 19:56:41 +02:00
|
|
|
|
2020-04-24 20:36:53 +03:00
|
|
|
self->pending_objects++;
|
|
|
|
|
|
2020-02-14 17:10:53 +02:00
|
|
|
if (!global->proxy)
|
|
|
|
|
global->proxy = g_object_new (global->type,
|
|
|
|
|
"core", core,
|
|
|
|
|
"global", global,
|
|
|
|
|
NULL);
|
2020-02-13 19:56:41 +02:00
|
|
|
|
2020-04-24 20:36:53 +03:00
|
|
|
wp_trace_object (self, "adding global:%u -> " WP_OBJECT_FORMAT,
|
|
|
|
|
global->id, WP_OBJECT_ARGS (global->proxy));
|
|
|
|
|
|
lib: refactor WpProxy
This is an attempt to unclutter the API of WpProxy and
split functionality into smaller pieces, making it easier
to work with.
In this new class layout, we have the following classes:
- WpObject: base class for everything; handles activating
| and deactivating "features"
|- WpProxy: base class for anything that wraps a pw_proxy;
| handles events from pw_proxy and nothing more
|- WpGlobalProxy: handles integration with the registry
All the other classes derive from WpGlobalProxy. The reason
for separating WpGlobalProxy from WpProxy, though, is that
classes such as WpImplNode / WpSpaDevice can also derive from
WpProxy now, without interfacing with the registry.
All objects that come with an "info" structure and have properties
and/or params also implement the WpPipewireObject interface. This
provides the API to query properties and get/set params. Essentially,
this is implemented by all classes except WpMetadata (pw_metadata
does not have info)
This interface is implemented on each object separately, using
a private "mixin", which is a set of vfunc implementations and helper
functions (and macros) to facilitate the implementation of this interface.
A notable difference to the old WpProxy is that now features can be
deactivated, so it is possible to enable something and later disable
it again.
This commit disables modules, tests, tools, etc, to avoid growing the
patch more, while ensuring that the project compiles.
2020-11-10 19:17:02 +02:00
|
|
|
wp_object_activate (WP_OBJECT (global->proxy), features, NULL,
|
|
|
|
|
on_proxy_ready, g_object_ref (self));
|
2020-02-13 19:56:41 +02:00
|
|
|
}
|
2020-02-14 17:10:53 +02:00
|
|
|
}
|
2020-02-13 19:56:41 +02:00
|
|
|
|
2021-05-13 17:54:58 +03:00
|
|
|
/*!
|
2021-05-21 18:40:43 +03:00
|
|
|
* \brief Installs the object manager on this core, activating its internal
|
|
|
|
|
* management engine.
|
2020-02-14 17:10:53 +02:00
|
|
|
*
|
2021-05-21 18:40:43 +03:00
|
|
|
* This will immediately emit signals about objects added on \a om
|
|
|
|
|
* if objects that the \a om is interested in were in existence already.
|
|
|
|
|
*
|
|
|
|
|
* \ingroup wpobjectmanager
|
|
|
|
|
* \param self the core
|
|
|
|
|
* \param om (transfer none): a WpObjectManager
|
2020-02-14 17:10:53 +02:00
|
|
|
*/
|
|
|
|
|
void
|
2020-02-17 15:39:19 +02:00
|
|
|
wp_core_install_object_manager (WpCore * self, WpObjectManager * om)
|
2019-11-13 16:07:36 +02:00
|
|
|
{
|
2020-02-14 17:10:53 +02:00
|
|
|
WpRegistry *reg;
|
2019-11-13 16:07:36 +02:00
|
|
|
|
2020-02-17 15:39:19 +02:00
|
|
|
g_return_if_fail (WP_IS_CORE (self));
|
2020-02-14 17:10:53 +02:00
|
|
|
g_return_if_fail (WP_IS_OBJECT_MANAGER (om));
|
|
|
|
|
|
2020-04-24 20:36:53 +03:00
|
|
|
g_weak_ref_set (&om->core, self);
|
2020-02-14 17:10:53 +02:00
|
|
|
|
2024-03-12 11:52:56 +02:00
|
|
|
reg = wp_core_get_registry (self);
|
|
|
|
|
wp_registry_install_object_manager (reg, om);
|
2021-05-21 18:40:43 +03:00
|
|
|
}
|