Skip to content
Snippets Groups Projects
proxy.c 5.12 KiB
Newer Older
Julian Bouzas's avatar
Julian Bouzas committed
/* WirePlumber
 *
 * Copyright © 2019 Collabora Ltd.
 *    @author Julian Bouzas <julian.bouzas@collabora.com>
 *
 * SPDX-License-Identifier: MIT
 */

#include <pipewire/pipewire.h>

#include "proxy.h"

typedef struct _WpProxyPrivate WpProxyPrivate;
struct _WpProxyPrivate
{
  /* The core */
  WpCore *core;

  /* The proxy  */
  struct pw_proxy *proxy;

  /* The proxy listener */
  struct spa_hook listener;

  /* The done info */
  GTask *done_task;
};

enum {
  PROP_0,
  PROP_CORE,
  PROP_PROXY,
};

static void wp_proxy_async_initable_init (gpointer iface, gpointer iface_data);

G_DEFINE_ABSTRACT_TYPE_WITH_CODE (WpProxy, wp_proxy, G_TYPE_OBJECT,
    G_ADD_PRIVATE (WpProxy)
    G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, wp_proxy_async_initable_init))

static void
proxy_event_destroy (void *data)
{
  WpProxyPrivate *self = wp_proxy_get_instance_private (WP_PROXY(data));

  /* Set the proxy to NULL */
  self->proxy = NULL;

  /* Remove the proxy from core */
  wp_core_remove_global (self->core, WP_GLOBAL_PROXY, data);
}

static void
proxy_event_done (void *data, int seq)
{
  WpProxyPrivate *self = wp_proxy_get_instance_private (WP_PROXY(data));

  /* Make sure the task is valid */
  if (!self->done_task)
    return;

  /* Execute the task */
  g_task_return_boolean (self->done_task, TRUE);

  /* Clean up */
  g_object_unref (self->done_task);
  self->done_task = NULL;
}

static const struct pw_proxy_events proxy_events = {
  PW_VERSION_PROXY_EVENTS,
  .destroy = proxy_event_destroy,
  .done = proxy_event_done,
};

static void
wp_proxy_finalize (GObject * object)
{
  WpProxyPrivate *self = wp_proxy_get_instance_private (WP_PROXY(object));
  
  /* Remove the listener */
  spa_hook_remove (&self->listener);
  
  /* Destroy the proxy */
  if (self->proxy) {
    pw_proxy_destroy (self->proxy);
    self->proxy = NULL;
  }

  G_OBJECT_CLASS (wp_proxy_parent_class)->finalize (object);
}

static void
wp_proxy_set_property (GObject * object, guint property_id,
    const GValue * value, GParamSpec * pspec)
{
  WpProxyPrivate *self = wp_proxy_get_instance_private (WP_PROXY(object));

  switch (property_id) {
  case PROP_CORE:
    self->core = g_value_get_pointer (value);
    break;
  case PROP_PROXY:
    self->proxy = g_value_get_pointer (value);
    break;
  default:
    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
    break;
  }
}

static void
wp_proxy_get_property (GObject * object, guint property_id, GValue * value,
    GParamSpec * pspec)
{
  WpProxyPrivate *self = wp_proxy_get_instance_private (WP_PROXY(object));

  switch (property_id) {
  case PROP_CORE:
    g_value_set_pointer (value, self->core);
    break;
  case PROP_PROXY:
    g_value_set_pointer (value, self->proxy);
    break;
  default:
    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
    break;
  }
}

static void
wp_proxy_init_async (GAsyncInitable *initable, int io_priority,
    GCancellable *cancellable, GAsyncReadyCallback callback, gpointer data)
{
  WpProxyPrivate *self = wp_proxy_get_instance_private (WP_PROXY(initable));

  /* Create the async task */
  self->done_task = g_task_new (initable, cancellable, callback, data);

  /* Add the event listener */
  pw_proxy_add_listener (self->proxy, &self->listener, &proxy_events, initable);

  /* Trigger the done callback */
  pw_proxy_sync(self->proxy, 0);
}

static gboolean
wp_proxy_init_finish (GAsyncInitable *initable, GAsyncResult *result,
    GError **error)
{
  g_return_val_if_fail (g_task_is_valid (result, initable), FALSE);

  return g_task_propagate_boolean (G_TASK (result), error);
}

static void
wp_proxy_async_initable_init (gpointer iface, gpointer iface_data)
{
  GAsyncInitableIface *ai_iface = iface;

  ai_iface->init_async = wp_proxy_init_async;
  ai_iface->init_finish = wp_proxy_init_finish;
}

static void
wp_proxy_init (WpProxy * self)
{
}

static void
wp_proxy_class_init (WpProxyClass * klass)
{
  GObjectClass *object_class = (GObjectClass *) klass;

  object_class->finalize = wp_proxy_finalize;
  object_class->get_property = wp_proxy_get_property;
  object_class->set_property = wp_proxy_set_property;

  /* Install the properties */
  g_object_class_install_property (object_class, PROP_CORE,
      g_param_spec_pointer ("core", "core", "The wireplumber core",
      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
  g_object_class_install_property (object_class, PROP_PROXY,
      g_param_spec_pointer ("pw-proxy", "pw-proxy", "The pipewire proxy",
      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
}

void
wp_proxy_register(WpProxy * self)
{
  WpProxyPrivate *priv;
  
  g_return_if_fail (WP_IS_PROXY (self));
  
  priv = wp_proxy_get_instance_private (self);
  wp_core_register_global (priv->core, WP_GLOBAL_PROXY, g_object_ref (self),
      g_object_unref);
}

WpCore *
wp_proxy_get_core (WpProxy * self)
{
  WpProxyPrivate *priv;

  g_return_val_if_fail (WP_IS_PROXY (self), NULL);

  priv = wp_proxy_get_instance_private (self);
  return priv->core;
}

gpointer
wp_proxy_get_pw_proxy (WpProxy * self)
{
  WpProxyPrivate *priv;

  g_return_val_if_fail (WP_IS_PROXY (self), NULL);

  priv = wp_proxy_get_instance_private (self);
  return priv->proxy;
}