Skip to content
Snippets Groups Projects
object-manager.c 32.9 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, 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_get_objects() and the
 * #WpObjectManager::object-added signal will be emitted for all of them.
 */

#include "object-manager.h"
#include "private.h"
  GType g_type;
  WpProxyFeatures wanted_features;
  GVariant *constraints; // aa{sv}
};
struct _WpObjectManager
  GObject parent;

  GWeakRef core;

  /* array of struct interest;
    pw_array has a better API for our use case than GArray */
  struct pw_array interests;

  /* objects that we are interested in, without a ref */
  GPtrArray *objects;

  gboolean pending_objchanged;
};

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);
  pw_array_init (&self->interests, sizeof (struct interest));
  self->objects = g_ptr_array_new ();
  self->pending_objchanged = FALSE;
static void
wp_object_manager_finalize (GObject * object)
  WpObjectManager *self = WP_OBJECT_MANAGER (object);
  struct interest *i;
  g_clear_pointer (&self->objects, g_ptr_array_unref);
  pw_array_for_each (i, &self->interests) {
    g_clear_pointer (&i->constraints, g_variant_unref);
  pw_array_clear (&self->interests);
  g_weak_ref_clear (&self->core);

  G_OBJECT_CLASS (wp_object_manager_parent_class)->finalize (object);
wp_object_manager_set_property (GObject * object, guint property_id,
    const GValue * value, GParamSpec * pspec)
  WpObjectManager *self = WP_OBJECT_MANAGER (object);
  switch (property_id) {
  case PROP_CORE:
    g_weak_ref_set (&self->core, g_value_get_object (value));
    break;
  default:
    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
    break;
  }
}
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;
  object_class->set_property = wp_object_manager_set_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_READWRITE | 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_get_objects()
   */
  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);
}
/**
 * wp_object_manager_new:
Loading
Loading full blame...