Skip to content
Snippets Groups Projects
object-manager.c 42.6 KiB
Newer Older
/* WirePlumber
 *
 * Copyright © 2019 Collabora Ltd.
 *    @author George Kiagiadakis <george.kiagiadakis@collabora.com>
 *
 * SPDX-License-Identifier: MIT
 */

/**
 * SECTION: WpObjectManager
 *
 * 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.
 *
 * There are 4 kinds of objects that can be managed by a #WpObjectManager:
 *   * remote PipeWire global objects that are advertised on the registry;
 *     these are bound locally to subclasses of #WpProxy
 *   * remote PipeWire global objects that are created by calling a remote
 *     factory through the WirePlumber API; these are very similar to other
 *     global objects but it should be noted that the same #WpProxy instance
 *     that created them appears in the #WpObjectManager (as soon as its
 *     %WP_PROXY_FEATURE_BOUND is enabled)
 *   * local PipeWire objects that are being exported to PipeWire
 *     (#WpImplNode, WpImplEndpoint [private], etc); these appear in the
 *     #WpObjectManager as soon as they are exported (so, when their
 *     %WP_PROXY_FEATURE_BOUND is enabled)
 *   * WirePlumber-specific objects, such as WirePlumber factories
 *
 * 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
 * it on the #WpCore with wp_core_install_object_manager().
 *
 * Upon installing a #WpObjectManager on a #WpCore, any pre-existing objects
 * that match the interests of this #WpObjectManager will immediately become
 * available to get through wp_object_manager_iterate() and the
 * #WpObjectManager::object-added signal will be emitted for all of them.
 */

#define G_LOG_DOMAIN "wp-object-manager"

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,
};

enum {
  SIGNAL_OBJECT_ADDED,
  SIGNAL_OBJECT_REMOVED,
  SIGNAL_OBJECTS_CHANGED,
  LAST_SIGNAL,
};

static guint signals[LAST_SIGNAL] = { 0 };

G_DEFINE_TYPE (WpObjectManager, wp_object_manager, G_TYPE_OBJECT)
wp_object_manager_init (WpObjectManager * self)
  g_weak_ref_init (&self->core, NULL);
  self->interests =
      g_ptr_array_new_with_free_func ((GDestroyNotify) wp_object_interest_free);
  self->features = g_hash_table_new (g_direct_hash, g_direct_equal);
  self->objects = g_ptr_array_new ();
  self->installed = FALSE;
  self->changed = FALSE;
  self->pending_objects = 0;
static void
wp_object_manager_finalize (GObject * object)
  WpObjectManager *self = WP_OBJECT_MANAGER (object);
  if (self->idle_source) {
    g_source_destroy (self->idle_source);
    g_clear_pointer (&self->idle_source, g_source_unref);
  }
  g_clear_pointer (&self->objects, g_ptr_array_unref);
  g_clear_pointer (&self->features, g_hash_table_unref);
  g_clear_pointer (&self->interests, g_ptr_array_unref);
  g_weak_ref_clear (&self->core);

  G_OBJECT_CLASS (wp_object_manager_parent_class)->finalize (object);
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;
  }
wp_object_manager_class_init (WpObjectManagerClass * klass)
  GObjectClass *object_class = (GObjectClass *) klass;
  object_class->finalize = wp_object_manager_finalize;
  object_class->get_property = wp_object_manager_get_property;
  /* Install the properties */
  g_object_class_install_property (object_class, PROP_CORE,
      g_param_spec_object ("core", "core", "The WpCore", WP_TYPE_CORE,
          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
  /**
   * WpObjectManager::object-added:
   * @self: the object manager
   * @object: (transfer none): the managed object that was just added
   *
   * Emitted when an object that matches the interests of this object manager
   * is made available.
   */
  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);
  /**
   * WpObjectManager::object-removed:
   * @self: the object manager
   * @object: (transfer none): the managed object that is being removed
   *
   * 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.
   */
  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);
  /**
   * WpObjectManager::objects-changed:
   * @self: the object manager
   *
   * 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_iterate()
  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);

  /**
   * WpObjectManager::installed:
   * @self: the object manager
   *
   * 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.
   */
  signals[SIGNAL_INSTALLED] = g_signal_new (
      "installed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST,
      0, NULL, NULL, NULL, G_TYPE_NONE, 0);
/**
 * wp_object_manager_new:
 *
 * Constructs a new object manager.
Loading
Loading full blame...