proxy: refactor the proxy class to hide pipewire API and make things easier
This commit is contained in:
@@ -6,46 +6,29 @@
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "error.h"
|
||||
#include "proxy-link.h"
|
||||
|
||||
#include <pipewire/pipewire.h>
|
||||
|
||||
struct _WpProxyLink
|
||||
{
|
||||
WpProxy parent;
|
||||
|
||||
/* The task to signal the proxy is initialized */
|
||||
GTask *init_task;
|
||||
|
||||
/* The link proxy listener */
|
||||
struct spa_hook listener;
|
||||
|
||||
/* The link info */
|
||||
struct pw_link_info *info;
|
||||
};
|
||||
|
||||
static void wp_proxy_link_async_initable_init (gpointer iface,
|
||||
gpointer iface_data);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (WpProxyLink, wp_proxy_link, WP_TYPE_PROXY,
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE,
|
||||
wp_proxy_link_async_initable_init))
|
||||
G_DEFINE_TYPE (WpProxyLink, wp_proxy_link, WP_TYPE_PROXY)
|
||||
|
||||
static void
|
||||
link_event_info(void *data, const struct pw_link_info *info)
|
||||
{
|
||||
WpProxyLink *self = data;
|
||||
WpProxy *proxy = WP_PROXY (data);
|
||||
|
||||
/* Make sure the task is valid */
|
||||
if (!self->init_task)
|
||||
return;
|
||||
|
||||
/* Update the link info */
|
||||
self->info = pw_link_info_update(self->info, info);
|
||||
|
||||
/* Finish the creation of the proxy */
|
||||
g_task_return_boolean (self->init_task, TRUE);
|
||||
g_clear_object (&self->init_task);
|
||||
wp_proxy_update_native_info (proxy, info,
|
||||
(WpProxyNativeInfoUpdate) pw_link_info_update,
|
||||
(GDestroyNotify) pw_link_info_free);
|
||||
wp_proxy_set_feature_ready (proxy, WP_PROXY_FEATURE_INFO);
|
||||
}
|
||||
|
||||
static const struct pw_link_proxy_events link_events = {
|
||||
@@ -53,102 +36,23 @@ static const struct pw_link_proxy_events link_events = {
|
||||
.info = link_event_info,
|
||||
};
|
||||
|
||||
static void
|
||||
wp_proxy_link_finalize (GObject * object)
|
||||
{
|
||||
WpProxyLink *self = WP_PROXY_LINK(object);
|
||||
|
||||
/* Destroy the init task */
|
||||
g_clear_object (&self->init_task);
|
||||
|
||||
/* Clear the info */
|
||||
if (self->info) {
|
||||
pw_link_info_free(self->info);
|
||||
self->info = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (wp_proxy_link_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_proxy_link_destroy (WpProxy * proxy)
|
||||
{
|
||||
WpProxyLink *self = WP_PROXY_LINK(proxy);
|
||||
GError *error = NULL;
|
||||
|
||||
/* Return error if the pipewire destruction happened while the async creation
|
||||
* of this proxy link object has not finished */
|
||||
if (self->init_task) {
|
||||
g_set_error (&error, WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_OPERATION_FAILED,
|
||||
"pipewire link proxy destroyed before finishing");
|
||||
g_task_return_error (self->init_task, error);
|
||||
g_clear_object (&self->init_task);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wp_proxy_link_init_async (GAsyncInitable *initable, int io_priority,
|
||||
GCancellable *cancellable, GAsyncReadyCallback callback, gpointer data)
|
||||
{
|
||||
WpProxyLink *self = WP_PROXY_LINK(initable);
|
||||
WpProxy *wp_proxy = WP_PROXY(initable);
|
||||
struct pw_link_proxy *proxy = NULL;
|
||||
|
||||
/* Create the async task */
|
||||
self->init_task = g_task_new (initable, cancellable, callback, data);
|
||||
|
||||
/* Get the proxy from the base class */
|
||||
proxy = wp_proxy_get_pw_proxy(wp_proxy);
|
||||
|
||||
/* Add the link proxy listener */
|
||||
pw_link_proxy_add_listener(proxy, &self->listener, &link_events, self);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_proxy_link_async_initable_init (gpointer iface, gpointer iface_data)
|
||||
{
|
||||
GAsyncInitableIface *ai_iface = iface;
|
||||
|
||||
/* Only set the init_async */
|
||||
ai_iface->init_async = wp_proxy_link_init_async;
|
||||
}
|
||||
|
||||
static void
|
||||
wp_proxy_link_init (WpProxyLink * self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
wp_proxy_link_pw_proxy_created (WpProxy * proxy, struct pw_proxy * pw_proxy)
|
||||
{
|
||||
WpProxyLink *self = WP_PROXY_LINK (proxy);
|
||||
pw_link_proxy_add_listener ((struct pw_link_proxy *) pw_proxy,
|
||||
&self->listener, &link_events, self);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_proxy_link_class_init (WpProxyLinkClass * klass)
|
||||
{
|
||||
GObjectClass *object_class = (GObjectClass *) klass;
|
||||
WpProxyClass *proxy_class = (WpProxyClass *) klass;
|
||||
|
||||
object_class->finalize = wp_proxy_link_finalize;
|
||||
|
||||
proxy_class->destroy = wp_proxy_link_destroy;
|
||||
}
|
||||
|
||||
void
|
||||
wp_proxy_link_new (guint global_id, gpointer proxy,
|
||||
GAsyncReadyCallback callback, gpointer user_data)
|
||||
{
|
||||
g_async_initable_new_async (
|
||||
WP_TYPE_PROXY_LINK, G_PRIORITY_DEFAULT, NULL, callback, user_data,
|
||||
"global-id", global_id,
|
||||
"pw-proxy", proxy,
|
||||
NULL);
|
||||
}
|
||||
|
||||
WpProxyLink *
|
||||
wp_proxy_link_new_finish(GObject *initable, GAsyncResult *res, GError **error)
|
||||
{
|
||||
GAsyncInitable *ai = G_ASYNC_INITABLE(initable);
|
||||
return WP_PROXY_LINK(g_async_initable_new_finish(ai, res, error));
|
||||
}
|
||||
|
||||
const struct pw_link_info *
|
||||
wp_proxy_link_get_info (WpProxyLink * self)
|
||||
{
|
||||
return self->info;
|
||||
proxy_class->pw_proxy_created = wp_proxy_link_pw_proxy_created;
|
||||
}
|
||||
|
@@ -9,7 +9,6 @@
|
||||
#ifndef __WIREPLUMBER_PROXY_LINK_H__
|
||||
#define __WIREPLUMBER_PROXY_LINK_H__
|
||||
|
||||
#include "core.h"
|
||||
#include "proxy.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
@@ -17,12 +16,12 @@ G_BEGIN_DECLS
|
||||
#define WP_TYPE_PROXY_LINK (wp_proxy_link_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (WpProxyLink, wp_proxy_link, WP, PROXY_LINK, WpProxy)
|
||||
|
||||
void wp_proxy_link_new (guint global_id, gpointer proxy,
|
||||
GAsyncReadyCallback callback, gpointer user_data);
|
||||
WpProxyLink *wp_proxy_link_new_finish(GObject *initable, GAsyncResult *res,
|
||||
GError **error);
|
||||
|
||||
const struct pw_link_info *wp_proxy_link_get_info (WpProxyLink * self);
|
||||
static inline const struct pw_link_info *
|
||||
wp_proxy_link_get_info (WpProxyLink * self)
|
||||
{
|
||||
return (const struct pw_link_info *)
|
||||
wp_proxy_get_native_info (WP_PROXY (self));
|
||||
}
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@@ -6,46 +6,29 @@
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "error.h"
|
||||
#include "proxy-node.h"
|
||||
|
||||
#include <pipewire/pipewire.h>
|
||||
|
||||
struct _WpProxyNode
|
||||
{
|
||||
WpProxy parent;
|
||||
|
||||
/* The task to signal the proxy is initialized */
|
||||
GTask *init_task;
|
||||
|
||||
/* The node proxy listener */
|
||||
struct spa_hook listener;
|
||||
|
||||
/* The node info */
|
||||
struct pw_node_info *info;
|
||||
};
|
||||
|
||||
static void wp_proxy_node_async_initable_init (gpointer iface,
|
||||
gpointer iface_data);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (WpProxyNode, wp_proxy_node, WP_TYPE_PROXY,
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE,
|
||||
wp_proxy_node_async_initable_init))
|
||||
G_DEFINE_TYPE (WpProxyNode, wp_proxy_node, WP_TYPE_PROXY)
|
||||
|
||||
static void
|
||||
node_event_info(void *data, const struct pw_node_info *info)
|
||||
{
|
||||
WpProxyNode *self = data;
|
||||
WpProxy *proxy = WP_PROXY (data);
|
||||
|
||||
/* Make sure the task is valid */
|
||||
if (!self->init_task)
|
||||
return;
|
||||
|
||||
/* Update the node info */
|
||||
self->info = pw_node_info_update(self->info, info);
|
||||
|
||||
/* Finish the creation of the proxy */
|
||||
g_task_return_boolean (self->init_task, TRUE);
|
||||
g_clear_object (&self->init_task);
|
||||
wp_proxy_update_native_info (proxy, info,
|
||||
(WpProxyNativeInfoUpdate) pw_node_info_update,
|
||||
(GDestroyNotify) pw_node_info_free);
|
||||
wp_proxy_set_feature_ready (proxy, WP_PROXY_FEATURE_INFO);
|
||||
}
|
||||
|
||||
static const struct pw_node_proxy_events node_events = {
|
||||
@@ -53,102 +36,23 @@ static const struct pw_node_proxy_events node_events = {
|
||||
.info = node_event_info,
|
||||
};
|
||||
|
||||
static void
|
||||
wp_proxy_node_finalize (GObject * object)
|
||||
{
|
||||
WpProxyNode *self = WP_PROXY_NODE(object);
|
||||
|
||||
/* Destroy the init task */
|
||||
g_clear_object (&self->init_task);
|
||||
|
||||
/* Clear the info */
|
||||
if (self->info) {
|
||||
pw_node_info_free(self->info);
|
||||
self->info = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (wp_proxy_node_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_proxy_node_destroy (WpProxy * proxy)
|
||||
{
|
||||
WpProxyNode *self = WP_PROXY_NODE(proxy);
|
||||
GError *error = NULL;
|
||||
|
||||
/* Return error if the pipewire destruction happened while the async creation
|
||||
* of this proxy node object has not finished */
|
||||
if (self->init_task) {
|
||||
g_set_error (&error, WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_OPERATION_FAILED,
|
||||
"pipewire node proxy destroyed before finishing");
|
||||
g_task_return_error (self->init_task, error);
|
||||
g_clear_object (&self->init_task);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wp_proxy_node_init_async (GAsyncInitable *initable, int io_priority,
|
||||
GCancellable *cancellable, GAsyncReadyCallback callback, gpointer data)
|
||||
{
|
||||
WpProxyNode *self = WP_PROXY_NODE(initable);
|
||||
WpProxy *wp_proxy = WP_PROXY(initable);
|
||||
struct pw_node_proxy *proxy = NULL;
|
||||
|
||||
/* Create the async task */
|
||||
self->init_task = g_task_new (initable, cancellable, callback, data);
|
||||
|
||||
/* Get the proxy from the base class */
|
||||
proxy = wp_proxy_get_pw_proxy(wp_proxy);
|
||||
|
||||
/* Add the node proxy listener */
|
||||
pw_node_proxy_add_listener(proxy, &self->listener, &node_events, self);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_proxy_node_async_initable_init (gpointer iface, gpointer iface_data)
|
||||
{
|
||||
GAsyncInitableIface *ai_iface = iface;
|
||||
|
||||
/* Only set the init_async */
|
||||
ai_iface->init_async = wp_proxy_node_init_async;
|
||||
}
|
||||
|
||||
static void
|
||||
wp_proxy_node_init (WpProxyNode * self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
wp_proxy_node_pw_proxy_created (WpProxy * proxy, struct pw_proxy * pw_proxy)
|
||||
{
|
||||
WpProxyNode *self = WP_PROXY_NODE (proxy);
|
||||
pw_node_proxy_add_listener ((struct pw_node_proxy *) pw_proxy,
|
||||
&self->listener, &node_events, self);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_proxy_node_class_init (WpProxyNodeClass * klass)
|
||||
{
|
||||
GObjectClass *object_class = (GObjectClass *) klass;
|
||||
WpProxyClass *proxy_class = (WpProxyClass *) klass;
|
||||
|
||||
object_class->finalize = wp_proxy_node_finalize;
|
||||
|
||||
proxy_class->destroy = wp_proxy_node_destroy;
|
||||
}
|
||||
|
||||
void
|
||||
wp_proxy_node_new (guint global_id, gpointer proxy,
|
||||
GAsyncReadyCallback callback, gpointer user_data)
|
||||
{
|
||||
g_async_initable_new_async (
|
||||
WP_TYPE_PROXY_NODE, G_PRIORITY_DEFAULT, NULL, callback, user_data,
|
||||
"global-id", global_id,
|
||||
"pw-proxy", proxy,
|
||||
NULL);
|
||||
}
|
||||
|
||||
WpProxyNode *
|
||||
wp_proxy_node_new_finish(GObject *initable, GAsyncResult *res, GError **error)
|
||||
{
|
||||
GAsyncInitable *ai = G_ASYNC_INITABLE(initable);
|
||||
return WP_PROXY_NODE(g_async_initable_new_finish(ai, res, error));
|
||||
}
|
||||
|
||||
const struct pw_node_info *
|
||||
wp_proxy_node_get_info (WpProxyNode * self)
|
||||
{
|
||||
return self->info;
|
||||
proxy_class->pw_proxy_created = wp_proxy_node_pw_proxy_created;
|
||||
}
|
||||
|
@@ -9,7 +9,6 @@
|
||||
#ifndef __WIREPLUMBER_PROXY_NODE_H__
|
||||
#define __WIREPLUMBER_PROXY_NODE_H__
|
||||
|
||||
#include "core.h"
|
||||
#include "proxy.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
@@ -17,12 +16,12 @@ G_BEGIN_DECLS
|
||||
#define WP_TYPE_PROXY_NODE (wp_proxy_node_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (WpProxyNode, wp_proxy_node, WP, PROXY_NODE, WpProxy)
|
||||
|
||||
void wp_proxy_node_new (guint global_id, gpointer proxy,
|
||||
GAsyncReadyCallback callback, gpointer user_data);
|
||||
WpProxyNode *wp_proxy_node_new_finish(GObject *initable, GAsyncResult *res,
|
||||
GError **error);
|
||||
|
||||
const struct pw_node_info *wp_proxy_node_get_info (WpProxyNode * self);
|
||||
static inline const struct pw_node_info *
|
||||
wp_proxy_node_get_info (WpProxyNode * self)
|
||||
{
|
||||
return (const struct pw_node_info *)
|
||||
wp_proxy_get_native_info (WP_PROXY (self));
|
||||
}
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@@ -6,8 +6,8 @@
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "error.h"
|
||||
#include "proxy-port.h"
|
||||
|
||||
#include <pipewire/pipewire.h>
|
||||
#include <spa/param/audio/format-utils.h>
|
||||
|
||||
@@ -15,46 +15,33 @@ struct _WpProxyPort
|
||||
{
|
||||
WpProxy parent;
|
||||
|
||||
/* The task to signal the proxy is initialized */
|
||||
GTask *init_task;
|
||||
|
||||
/* The port proxy listener */
|
||||
struct spa_hook listener;
|
||||
|
||||
/* The port info */
|
||||
struct pw_port_info *info;
|
||||
|
||||
/* The port format */
|
||||
uint32_t media_type;
|
||||
uint32_t media_subtype;
|
||||
struct spa_audio_info_raw format;
|
||||
};
|
||||
|
||||
static void wp_proxy_port_async_initable_init (gpointer iface,
|
||||
gpointer iface_data);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (WpProxyPort, wp_proxy_port, WP_TYPE_PROXY,
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE,
|
||||
wp_proxy_port_async_initable_init))
|
||||
G_DEFINE_TYPE (WpProxyPort, wp_proxy_port, WP_TYPE_PROXY)
|
||||
|
||||
static void
|
||||
port_event_info(void *data, const struct pw_port_info *info)
|
||||
{
|
||||
WpProxyPort *self = data;
|
||||
WpProxy *proxy = WP_PROXY (data);
|
||||
|
||||
/* Update the port info */
|
||||
self->info = pw_port_info_update(self->info, info);
|
||||
wp_proxy_update_native_info (proxy, info,
|
||||
(WpProxyNativeInfoUpdate) pw_port_info_update,
|
||||
(GDestroyNotify) pw_port_info_free);
|
||||
wp_proxy_set_feature_ready (proxy, WP_PROXY_FEATURE_INFO);
|
||||
}
|
||||
|
||||
static void
|
||||
port_event_param(void *data, int seq, uint32_t id, uint32_t index,
|
||||
uint32_t next, const struct spa_pod *param)
|
||||
{
|
||||
WpProxyPort *self = data;
|
||||
|
||||
/* Make sure the task is valid */
|
||||
if (!self->init_task)
|
||||
return;
|
||||
WpProxyPort *self = WP_PROXY_PORT (data);
|
||||
|
||||
/* Only handle EnumFormat */
|
||||
if (id != SPA_PARAM_EnumFormat)
|
||||
@@ -64,17 +51,14 @@ port_event_param(void *data, int seq, uint32_t id, uint32_t index,
|
||||
spa_format_parse(param, &self->media_type, &self->media_subtype);
|
||||
|
||||
/* Only handle raw audio formats for now */
|
||||
if (self->media_type != SPA_MEDIA_TYPE_audio ||
|
||||
self->media_subtype != SPA_MEDIA_SUBTYPE_raw)
|
||||
return;
|
||||
|
||||
if (self->media_type == SPA_MEDIA_TYPE_audio &&
|
||||
self->media_subtype == SPA_MEDIA_SUBTYPE_raw) {
|
||||
/* Parse the raw audio format */
|
||||
spa_pod_fixate ((struct spa_pod *) param);
|
||||
spa_format_audio_raw_parse (param, &self->format);
|
||||
}
|
||||
|
||||
/* Finish the creation of the proxy */
|
||||
g_task_return_boolean (self->init_task, TRUE);
|
||||
g_clear_object (&self->init_task);
|
||||
wp_proxy_set_feature_ready (WP_PROXY (self), WP_PROXY_PORT_FEATURE_FORMAT);
|
||||
}
|
||||
|
||||
static const struct pw_port_proxy_events port_events = {
|
||||
@@ -83,108 +67,41 @@ static const struct pw_port_proxy_events port_events = {
|
||||
.param = port_event_param,
|
||||
};
|
||||
|
||||
static void
|
||||
wp_proxy_port_finalize (GObject * object)
|
||||
{
|
||||
WpProxyPort *self = WP_PROXY_PORT(object);
|
||||
|
||||
/* Destroy the init task */
|
||||
g_clear_object (&self->init_task);
|
||||
|
||||
/* Clear the indo */
|
||||
if (self->info) {
|
||||
pw_port_info_free(self->info);
|
||||
self->info = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (wp_proxy_port_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_proxy_port_destroy (WpProxy * proxy)
|
||||
{
|
||||
WpProxyPort *self = WP_PROXY_PORT(proxy);
|
||||
GError *error = NULL;
|
||||
|
||||
/* Return error if the pipewire destruction happened while the async creation
|
||||
* of this proxy port object has not finished */
|
||||
if (self->init_task) {
|
||||
g_set_error (&error, WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_OPERATION_FAILED,
|
||||
"pipewire port proxy destroyed before finishing");
|
||||
g_task_return_error (self->init_task, error);
|
||||
g_clear_object (&self->init_task);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wp_proxy_port_init_async (GAsyncInitable *initable, int io_priority,
|
||||
GCancellable *cancellable, GAsyncReadyCallback callback, gpointer data)
|
||||
{
|
||||
WpProxyPort *self = WP_PROXY_PORT(initable);
|
||||
WpProxy *wp_proxy = WP_PROXY(initable);
|
||||
struct pw_port_proxy *proxy = NULL;
|
||||
|
||||
/* Create the async task */
|
||||
self->init_task = g_task_new (initable, cancellable, callback, data);
|
||||
|
||||
/* Get the proxy from the base class */
|
||||
proxy = wp_proxy_get_pw_proxy(wp_proxy);
|
||||
|
||||
/* Add the port proxy listener */
|
||||
pw_port_proxy_add_listener(proxy, &self->listener, &port_events, self);
|
||||
|
||||
/* Emit the EnumFormat param */
|
||||
pw_port_proxy_enum_params((struct pw_port_proxy*)proxy, 0,
|
||||
SPA_PARAM_EnumFormat, 0, -1, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_proxy_port_async_initable_init (gpointer iface, gpointer iface_data)
|
||||
{
|
||||
GAsyncInitableIface *ai_iface = iface;
|
||||
|
||||
/* Only set the init_async */
|
||||
ai_iface->init_async = wp_proxy_port_init_async;
|
||||
}
|
||||
|
||||
static void
|
||||
wp_proxy_port_init (WpProxyPort * self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
wp_proxy_port_augment (WpProxy * proxy, WpProxyFeatures features)
|
||||
{
|
||||
/* call the default implementation to ensure we have a proxy, if necessary */
|
||||
WP_PROXY_CLASS (wp_proxy_port_parent_class)->augment (proxy, features);
|
||||
|
||||
if (features & WP_PROXY_PORT_FEATURE_FORMAT) {
|
||||
struct pw_proxy *pwp = wp_proxy_get_pw_proxy (proxy);
|
||||
g_return_if_fail (pwp != NULL);
|
||||
|
||||
pw_port_proxy_enum_params ((struct pw_port_proxy *) pwp, 0,
|
||||
SPA_PARAM_EnumFormat, 0, -1, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wp_proxy_port_pw_proxy_created (WpProxy * proxy, struct pw_proxy * pw_proxy)
|
||||
{
|
||||
WpProxyPort *self = WP_PROXY_PORT (proxy);
|
||||
pw_port_proxy_add_listener ((struct pw_port_proxy *) pw_proxy,
|
||||
&self->listener, &port_events, self);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_proxy_port_class_init (WpProxyPortClass * klass)
|
||||
{
|
||||
GObjectClass *object_class = (GObjectClass *) klass;
|
||||
WpProxyClass *proxy_class = (WpProxyClass *) klass;
|
||||
|
||||
object_class->finalize = wp_proxy_port_finalize;
|
||||
|
||||
proxy_class->destroy = wp_proxy_port_destroy;
|
||||
}
|
||||
|
||||
void
|
||||
wp_proxy_port_new (guint global_id, gpointer proxy,
|
||||
GAsyncReadyCallback callback, gpointer user_data)
|
||||
{
|
||||
g_async_initable_new_async (
|
||||
WP_TYPE_PROXY_PORT, G_PRIORITY_DEFAULT, NULL, callback, user_data,
|
||||
"global-id", global_id,
|
||||
"pw-proxy", proxy,
|
||||
NULL);
|
||||
}
|
||||
|
||||
WpProxyPort *
|
||||
wp_proxy_port_new_finish(GObject *initable, GAsyncResult *res, GError **error)
|
||||
{
|
||||
GAsyncInitable *ai = G_ASYNC_INITABLE(initable);
|
||||
return WP_PROXY_PORT(g_async_initable_new_finish(ai, res, error));
|
||||
}
|
||||
|
||||
const struct pw_port_info *
|
||||
wp_proxy_port_get_info (WpProxyPort * self)
|
||||
{
|
||||
return self->info;
|
||||
proxy_class->augment = wp_proxy_port_augment;
|
||||
proxy_class->pw_proxy_created = wp_proxy_port_pw_proxy_created;
|
||||
}
|
||||
|
||||
const struct spa_audio_info_raw *
|
||||
|
@@ -9,20 +9,24 @@
|
||||
#ifndef __WIREPLUMBER_PROXY_PORT_H__
|
||||
#define __WIREPLUMBER_PROXY_PORT_H__
|
||||
|
||||
#include "core.h"
|
||||
#include "proxy.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef enum { /*< flags >*/
|
||||
WP_PROXY_PORT_FEATURE_FORMAT = (WP_PROXY_FEATURE_LAST << 0),
|
||||
} WpProxyPortFeatures;
|
||||
|
||||
#define WP_TYPE_PROXY_PORT (wp_proxy_port_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (WpProxyPort, wp_proxy_port, WP, PROXY_PORT, WpProxy)
|
||||
|
||||
void wp_proxy_port_new (guint global_id, gpointer proxy,
|
||||
GAsyncReadyCallback callback, gpointer user_data);
|
||||
WpProxyPort *wp_proxy_port_new_finish(GObject *initable, GAsyncResult *res,
|
||||
GError **error);
|
||||
static inline const struct pw_port_info *
|
||||
wp_proxy_port_get_info (WpProxyPort * self)
|
||||
{
|
||||
return (const struct pw_port_info *)
|
||||
wp_proxy_get_native_info (WP_PROXY (self));
|
||||
}
|
||||
|
||||
const struct pw_port_info *wp_proxy_port_get_info (WpProxyPort * self);
|
||||
const struct spa_audio_info_raw *wp_proxy_port_get_format (WpProxyPort * self);
|
||||
|
||||
G_END_DECLS
|
||||
|
612
lib/wp/proxy.c
612
lib/wp/proxy.c
@@ -2,46 +2,130 @@
|
||||
*
|
||||
* Copyright © 2019 Collabora Ltd.
|
||||
* @author Julian Bouzas <julian.bouzas@collabora.com>
|
||||
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <pipewire/pipewire.h>
|
||||
|
||||
#include "proxy.h"
|
||||
#include "error.h"
|
||||
#include "remote-pipewire.h"
|
||||
#include "wpenums.h"
|
||||
|
||||
#include "proxy-link.h"
|
||||
#include "proxy-node.h"
|
||||
#include "proxy-port.h"
|
||||
|
||||
#include <pipewire/pipewire.h>
|
||||
#include <spa/debug/types.h>
|
||||
|
||||
typedef struct _WpProxyPrivate WpProxyPrivate;
|
||||
struct _WpProxyPrivate
|
||||
{
|
||||
/* The global id */
|
||||
guint global_id;
|
||||
/* properties */
|
||||
GWeakRef remote;
|
||||
|
||||
/* The proxy */
|
||||
struct pw_proxy *proxy;
|
||||
guint32 global_id;
|
||||
guint32 global_perm;
|
||||
WpProperties *global_props;
|
||||
|
||||
guint32 iface_type;
|
||||
guint32 iface_version;
|
||||
|
||||
struct pw_proxy *pw_proxy;
|
||||
gpointer native_info;
|
||||
GDestroyNotify native_info_destroy;
|
||||
|
||||
/* The proxy listener */
|
||||
struct spa_hook listener;
|
||||
|
||||
/* augment state */
|
||||
WpProxyFeatures ft_ready;
|
||||
WpProxyFeatures ft_wanted;
|
||||
GTask *task;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_REMOTE,
|
||||
PROP_GLOBAL_ID,
|
||||
PROP_PROXY,
|
||||
PROP_GLOBAL_PERMISSIONS,
|
||||
PROP_GLOBAL_PROPERTIES,
|
||||
PROP_INTERFACE_TYPE,
|
||||
PROP_INTERFACE_NAME,
|
||||
PROP_INTERFACE_QUARK,
|
||||
PROP_INTERFACE_VERSION,
|
||||
PROP_PW_PROXY,
|
||||
PROP_NATIVE_INFO,
|
||||
PROP_FEATURES,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SIGNAL_DONE,
|
||||
SIGNAL_PW_PROXY_CREATED,
|
||||
SIGNAL_PW_PROXY_DESTROYED,
|
||||
LAST_SIGNAL,
|
||||
};
|
||||
|
||||
static guint wp_proxy_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
static void wp_proxy_async_initable_init (gpointer iface, gpointer iface_data);
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (WpProxy, wp_proxy, G_TYPE_OBJECT)
|
||||
|
||||
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))
|
||||
G_DEFINE_QUARK (core, wp_proxy_core)
|
||||
G_DEFINE_QUARK (registry, wp_proxy_registry)
|
||||
G_DEFINE_QUARK (node, wp_proxy_node)
|
||||
G_DEFINE_QUARK (port, wp_proxy_port)
|
||||
G_DEFINE_QUARK (factory, wp_proxy_factory)
|
||||
G_DEFINE_QUARK (link, wp_proxy_link)
|
||||
G_DEFINE_QUARK (client, wp_proxy_client)
|
||||
G_DEFINE_QUARK (module, wp_proxy_module)
|
||||
G_DEFINE_QUARK (device, wp_proxy_device)
|
||||
G_DEFINE_QUARK (client-node, wp_proxy_client_node)
|
||||
|
||||
static struct {
|
||||
/* the pipewire interface type */
|
||||
guint32 pw_type;
|
||||
/* the minimum interface version that the remote object must support */
|
||||
guint32 req_version;
|
||||
/* the _get_type() function of the subclass */
|
||||
GType (*get_type) (void);
|
||||
/* a function returning a quark that identifies the interface */
|
||||
GQuark (*get_quark) (void);
|
||||
} types_assoc[] = {
|
||||
{ PW_TYPE_INTERFACE_Core, 0, wp_proxy_get_type, wp_proxy_core_quark },
|
||||
{ PW_TYPE_INTERFACE_Registry, 0, wp_proxy_get_type, wp_proxy_registry_quark },
|
||||
{ PW_TYPE_INTERFACE_Node, 0, wp_proxy_node_get_type, wp_proxy_node_quark },
|
||||
{ PW_TYPE_INTERFACE_Port, 0, wp_proxy_port_get_type, wp_proxy_port_quark },
|
||||
{ PW_TYPE_INTERFACE_Factory, 0, wp_proxy_get_type, wp_proxy_factory_quark },
|
||||
{ PW_TYPE_INTERFACE_Link, 0, wp_proxy_link_get_type, wp_proxy_link_quark },
|
||||
{ PW_TYPE_INTERFACE_Client, 0, wp_proxy_get_type, wp_proxy_client_quark },
|
||||
{ PW_TYPE_INTERFACE_Module, 0, wp_proxy_get_type, wp_proxy_module_quark },
|
||||
{ PW_TYPE_INTERFACE_Device, 0, wp_proxy_get_type, wp_proxy_device_quark },
|
||||
{ PW_TYPE_INTERFACE_ClientNode, 0, wp_proxy_get_type, wp_proxy_client_node_quark },
|
||||
};
|
||||
|
||||
static inline GType
|
||||
wp_proxy_find_instance_type (guint32 type, guint32 version)
|
||||
{
|
||||
for (gint i = 0; i < SPA_N_ELEMENTS (types_assoc); i++) {
|
||||
if (types_assoc[i].pw_type == type &&
|
||||
types_assoc[i].req_version <= version)
|
||||
return types_assoc[i].get_type ();
|
||||
}
|
||||
|
||||
return WP_TYPE_PROXY;
|
||||
}
|
||||
|
||||
static inline GQuark
|
||||
wp_proxy_find_quark_for_type (guint32 type)
|
||||
{
|
||||
for (gint i = 0; i < SPA_N_ELEMENTS (types_assoc); i++) {
|
||||
if (types_assoc[i].pw_type == type)
|
||||
return types_assoc[i].get_quark ();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
proxy_event_destroy (void *data)
|
||||
@@ -49,34 +133,46 @@ proxy_event_destroy (void *data)
|
||||
WpProxy *self = WP_PROXY (data);
|
||||
WpProxyPrivate *priv = wp_proxy_get_instance_private (self);
|
||||
|
||||
/* Set the proxy to NULL */
|
||||
priv->proxy = NULL;
|
||||
priv->pw_proxy = NULL;
|
||||
|
||||
/* Call the destroy method */
|
||||
if (WP_PROXY_GET_CLASS (self)->destroy)
|
||||
WP_PROXY_GET_CLASS (self)->destroy (self);
|
||||
g_signal_emit (self, wp_proxy_signals[SIGNAL_PW_PROXY_DESTROYED], 0);
|
||||
|
||||
/* Return error if the pw_proxy destruction happened while the async
|
||||
* init or augment of this proxy object was in progress */
|
||||
if (priv->task) {
|
||||
g_task_return_new_error (priv->task, WP_DOMAIN_LIBRARY,
|
||||
WP_LIBRARY_ERROR_OPERATION_FAILED,
|
||||
"pipewire node proxy destroyed before finishing");
|
||||
g_clear_object (&priv->task);
|
||||
}
|
||||
|
||||
static void
|
||||
proxy_event_done (void *data, int seq)
|
||||
{
|
||||
/* Emit the done signal */
|
||||
g_signal_emit (data, wp_proxy_signals[SIGNAL_DONE], 0);
|
||||
}
|
||||
|
||||
static const struct pw_proxy_events proxy_events = {
|
||||
PW_VERSION_PROXY_EVENTS,
|
||||
.destroy = proxy_event_destroy,
|
||||
.done = proxy_event_done,
|
||||
};
|
||||
|
||||
static void
|
||||
wp_proxy_init (WpProxy * self)
|
||||
{
|
||||
WpProxyPrivate *priv = wp_proxy_get_instance_private (self);
|
||||
g_weak_ref_init (&priv->remote, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_proxy_constructed (GObject * object)
|
||||
{
|
||||
WpProxyPrivate *priv = wp_proxy_get_instance_private (WP_PROXY(object));
|
||||
WpProxy *self = WP_PROXY (object);
|
||||
WpProxyPrivate *priv = wp_proxy_get_instance_private (self);
|
||||
|
||||
/* Add the event listener */
|
||||
pw_proxy_add_listener (priv->proxy, &priv->listener, &proxy_events, object);
|
||||
/* native proxy was passed in the constructor, declare it as ready */
|
||||
if (priv->pw_proxy) {
|
||||
priv->ft_ready |= WP_PROXY_FEATURE_PW_PROXY;
|
||||
|
||||
/* and inform the subclasses */
|
||||
g_signal_emit (self, wp_proxy_signals[SIGNAL_PW_PROXY_CREATED], 0,
|
||||
priv->pw_proxy);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -84,14 +180,14 @@ wp_proxy_finalize (GObject * object)
|
||||
{
|
||||
WpProxyPrivate *priv = wp_proxy_get_instance_private (WP_PROXY(object));
|
||||
|
||||
g_debug ("%s:%p destroyed (pw proxy %p)", G_OBJECT_TYPE_NAME (object),
|
||||
object, priv->proxy);
|
||||
g_debug ("%s:%p destroyed (global %u; pw_proxy %p)", G_OBJECT_TYPE_NAME (object),
|
||||
object, priv->global_id, priv->pw_proxy);
|
||||
|
||||
/* Destroy the proxy */
|
||||
if (priv->proxy) {
|
||||
pw_proxy_destroy (priv->proxy);
|
||||
priv->proxy = NULL;
|
||||
}
|
||||
g_clear_object (&priv->task);
|
||||
g_clear_pointer (&priv->global_props, wp_properties_unref);
|
||||
g_clear_pointer (&priv->native_info, priv->native_info_destroy);
|
||||
g_clear_pointer (&priv->pw_proxy, pw_proxy_destroy);
|
||||
g_weak_ref_clear (&priv->remote);
|
||||
|
||||
G_OBJECT_CLASS (wp_proxy_parent_class)->finalize (object);
|
||||
}
|
||||
@@ -103,11 +199,29 @@ wp_proxy_set_property (GObject * object, guint property_id,
|
||||
WpProxyPrivate *priv = wp_proxy_get_instance_private (WP_PROXY(object));
|
||||
|
||||
switch (property_id) {
|
||||
case PROP_REMOTE:
|
||||
g_weak_ref_set (&priv->remote, g_value_get_object (value));
|
||||
break;
|
||||
case PROP_GLOBAL_ID:
|
||||
priv->global_id = g_value_get_uint (value);
|
||||
break;
|
||||
case PROP_PROXY:
|
||||
priv->proxy = g_value_get_pointer (value);
|
||||
case PROP_GLOBAL_PERMISSIONS:
|
||||
priv->global_perm = g_value_get_uint (value);
|
||||
break;
|
||||
case PROP_GLOBAL_PROPERTIES:
|
||||
priv->global_props = g_value_dup_boxed (value);
|
||||
break;
|
||||
case PROP_INTERFACE_TYPE:
|
||||
priv->iface_type = g_value_get_uint (value);
|
||||
break;
|
||||
case PROP_INTERFACE_VERSION:
|
||||
priv->iface_version = g_value_get_uint (value);
|
||||
break;
|
||||
case PROP_PW_PROXY:
|
||||
priv->pw_proxy = g_value_get_pointer (value);
|
||||
break;
|
||||
case PROP_NATIVE_INFO:
|
||||
priv->native_info = g_value_get_pointer (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
@@ -122,11 +236,39 @@ wp_proxy_get_property (GObject * object, guint property_id, GValue * value,
|
||||
WpProxyPrivate *priv = wp_proxy_get_instance_private (WP_PROXY(object));
|
||||
|
||||
switch (property_id) {
|
||||
case PROP_REMOTE:
|
||||
g_value_take_object (value, g_weak_ref_get (&priv->remote));
|
||||
break;
|
||||
case PROP_GLOBAL_ID:
|
||||
g_value_set_uint (value, priv->global_id);
|
||||
break;
|
||||
case PROP_PROXY:
|
||||
g_value_set_pointer (value, priv->proxy);
|
||||
case PROP_GLOBAL_PERMISSIONS:
|
||||
g_value_set_uint (value, priv->global_perm);
|
||||
break;
|
||||
case PROP_GLOBAL_PROPERTIES:
|
||||
g_value_set_boxed (value, priv->global_props);
|
||||
break;
|
||||
case PROP_INTERFACE_TYPE:
|
||||
g_value_set_uint (value, priv->iface_type);
|
||||
break;
|
||||
case PROP_INTERFACE_NAME:
|
||||
g_value_set_static_string (value,
|
||||
spa_debug_type_find_name (pw_type_info(), priv->iface_type));
|
||||
break;
|
||||
case PROP_INTERFACE_QUARK:
|
||||
g_value_set_uint (value, wp_proxy_find_quark_for_type (priv->iface_type));
|
||||
break;
|
||||
case PROP_INTERFACE_VERSION:
|
||||
g_value_set_uint (value, priv->iface_version);
|
||||
break;
|
||||
case PROP_PW_PROXY:
|
||||
g_value_set_pointer (value, priv->pw_proxy);
|
||||
break;
|
||||
case PROP_NATIVE_INFO:
|
||||
g_value_set_pointer (value, priv->native_info);
|
||||
break;
|
||||
case PROP_FEATURES:
|
||||
g_value_set_flags (value, priv->ft_ready);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
@@ -134,27 +276,29 @@ wp_proxy_get_property (GObject * object, guint property_id, GValue * value,
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
wp_proxy_init_finish (GAsyncInitable *initable, GAsyncResult *result,
|
||||
GError **error)
|
||||
static void
|
||||
wp_proxy_default_augment (WpProxy * self, WpProxyFeatures features)
|
||||
{
|
||||
g_return_val_if_fail (g_task_is_valid (result, initable), FALSE);
|
||||
WpProxyPrivate *priv = wp_proxy_get_instance_private (self);
|
||||
|
||||
return g_task_propagate_boolean (G_TASK (result), error);
|
||||
/* ensure we have a pw_proxy, as we can't have
|
||||
* any other feature without first having that */
|
||||
if (!priv->pw_proxy && features != 0)
|
||||
features |= WP_PROXY_FEATURE_PW_PROXY;
|
||||
|
||||
/* if we don't have a pw_proxy, we have to assume that this WpProxy
|
||||
* represents a global object from the registry; we have no other way
|
||||
* to get a pw_proxy */
|
||||
if (features & WP_PROXY_FEATURE_PW_PROXY) {
|
||||
if (!wp_proxy_is_global (self)) {
|
||||
wp_proxy_augment_error (self, g_error_new (WP_DOMAIN_LIBRARY,
|
||||
WP_LIBRARY_ERROR_INVALID_ARGUMENT,
|
||||
"No global id specified; cannot bind pw_proxy"));
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
wp_proxy_async_initable_init (gpointer iface, gpointer iface_data)
|
||||
{
|
||||
GAsyncInitableIface *ai_iface = iface;
|
||||
|
||||
/* The init_async must be implemented in the derived classes */
|
||||
ai_iface->init_finish = wp_proxy_init_finish;
|
||||
wp_proxy_bind_global (self);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_proxy_init (WpProxy * self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -167,22 +311,263 @@ wp_proxy_class_init (WpProxyClass * klass)
|
||||
object_class->get_property = wp_proxy_get_property;
|
||||
object_class->set_property = wp_proxy_set_property;
|
||||
|
||||
klass->augment = wp_proxy_default_augment;
|
||||
|
||||
/* Install the properties */
|
||||
|
||||
g_object_class_install_property (object_class, PROP_REMOTE,
|
||||
g_param_spec_object ("remote", "remote",
|
||||
"The pipewire connection WpRemote", WP_TYPE_REMOTE,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_GLOBAL_ID,
|
||||
g_param_spec_uint ("global-id", "global-id", "The pipewire global id",
|
||||
0, G_MAXUINT, 0,
|
||||
g_param_spec_uint ("global-id", "global-id",
|
||||
"The pipewire global id", 0, G_MAXUINT, 0,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_GLOBAL_PERMISSIONS,
|
||||
g_param_spec_uint ("global-permissions", "global-permissions",
|
||||
"The pipewire global permissions", 0, G_MAXUINT, 0,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_GLOBAL_PROPERTIES,
|
||||
g_param_spec_boxed ("global-properties", "global-properties",
|
||||
"The pipewire global properties", WP_TYPE_PROPERTIES,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_INTERFACE_TYPE,
|
||||
g_param_spec_uint ("interface-type", "interface-type",
|
||||
"The pipewire interface type", 0, G_MAXUINT, 0,
|
||||
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_object_class_install_property (object_class, PROP_INTERFACE_NAME,
|
||||
g_param_spec_string ("interface-name", "interface-name",
|
||||
"The name of the pipewire interface", NULL,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_INTERFACE_QUARK,
|
||||
g_param_spec_uint ("interface-quark", "interface-quark",
|
||||
"A quark identifying the pipewire interface", 0, G_MAXUINT, 0,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_INTERFACE_VERSION,
|
||||
g_param_spec_uint ("interface-version", "interface-version",
|
||||
"The pipewire interface version", 0, G_MAXUINT, 0,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_PW_PROXY,
|
||||
g_param_spec_pointer ("pw-proxy", "pw-proxy", "The struct pw_proxy *",
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_NATIVE_INFO,
|
||||
g_param_spec_pointer ("native-info", "native-info",
|
||||
"The struct pw_XXXX_info *",
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_FEATURES,
|
||||
g_param_spec_flags ("features", "features",
|
||||
"The ready WpProxyFeatures on this proxy", WP_TYPE_PROXY_FEATURES, 0,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/* Signals */
|
||||
wp_proxy_signals[SIGNAL_DONE] =
|
||||
g_signal_new ("done", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (WpProxyClass, done), NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
wp_proxy_signals[SIGNAL_PW_PROXY_CREATED] = g_signal_new (
|
||||
"pw-proxy-created", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (WpProxyClass, pw_proxy_created), NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 1, G_TYPE_POINTER);
|
||||
|
||||
wp_proxy_signals[SIGNAL_PW_PROXY_DESTROYED] = g_signal_new (
|
||||
"pw-proxy-destroyed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (WpProxyClass, pw_proxy_destroyed), NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
guint
|
||||
WpProxy *
|
||||
wp_proxy_new_global (WpRemote * remote,
|
||||
guint32 id, guint32 permissions, WpProperties * properties,
|
||||
guint32 type, guint32 version)
|
||||
{
|
||||
GType gtype = wp_proxy_find_instance_type (type, version);
|
||||
return g_object_new (gtype,
|
||||
"remote", remote,
|
||||
"global-id", id,
|
||||
"global-permissions", permissions,
|
||||
"global-properties", properties,
|
||||
"interface-type", type,
|
||||
"interface-version", version,
|
||||
NULL);
|
||||
}
|
||||
|
||||
WpProxy *
|
||||
wp_proxy_new_wrap (WpRemote * remote,
|
||||
struct pw_proxy * proxy, guint32 type, guint32 version)
|
||||
{
|
||||
GType gtype = wp_proxy_find_instance_type (type, version);
|
||||
return g_object_new (gtype,
|
||||
"remote", remote,
|
||||
"pw-proxy", proxy,
|
||||
"interface-type", type,
|
||||
"interface-version", version,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
wp_proxy_augment (WpProxy * self,
|
||||
WpProxyFeatures ft_wanted, GCancellable * cancellable,
|
||||
GAsyncReadyCallback callback, gpointer user_data)
|
||||
{
|
||||
WpProxyPrivate *priv;
|
||||
WpProxyFeatures missing = 0;
|
||||
|
||||
g_return_if_fail (WP_IS_PROXY (self));
|
||||
g_return_if_fail (WP_PROXY_GET_CLASS (self)->augment);
|
||||
|
||||
priv = wp_proxy_get_instance_private (self);
|
||||
priv->task = g_task_new (self, cancellable, callback, user_data);
|
||||
|
||||
/* we don't simply assign here, we keep all the previous wanted features;
|
||||
* it is not allowed to remove features */
|
||||
priv->ft_wanted |= ft_wanted;
|
||||
|
||||
/* find which features are wanted but missing from the "ready" set */
|
||||
missing = (priv->ft_ready ^ priv->ft_wanted) & priv->ft_wanted;
|
||||
|
||||
/* if the features are not ready, call augment(),
|
||||
* otherwise signal the callback directly */
|
||||
if (missing != 0) {
|
||||
WP_PROXY_GET_CLASS (self)->augment (self, missing);
|
||||
} else {
|
||||
g_task_return_boolean (priv->task, TRUE);
|
||||
g_clear_object (&priv->task);
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
wp_proxy_augment_finish (WpProxy * self, GAsyncResult * res,
|
||||
GError ** error)
|
||||
{
|
||||
g_return_val_if_fail (WP_IS_PROXY (self), FALSE);
|
||||
g_return_val_if_fail (g_task_is_valid (res, self), FALSE);
|
||||
|
||||
return g_task_propagate_boolean (G_TASK (res), error);
|
||||
}
|
||||
|
||||
void
|
||||
wp_proxy_set_feature_ready (WpProxy * self, WpProxyFeatures feature)
|
||||
{
|
||||
WpProxyPrivate *priv;
|
||||
|
||||
g_return_if_fail (WP_IS_PROXY (self));
|
||||
|
||||
priv = wp_proxy_get_instance_private (self);
|
||||
|
||||
/* feature already marked as ready */
|
||||
if (priv->ft_ready & feature)
|
||||
return;
|
||||
|
||||
priv->ft_ready |= feature;
|
||||
|
||||
g_object_notify (G_OBJECT (self), "features");
|
||||
|
||||
/* return from the task if all the wanted features are now ready */
|
||||
if (priv->task &&
|
||||
(priv->ft_ready & priv->ft_wanted) == priv->ft_wanted) {
|
||||
g_task_return_boolean (priv->task, TRUE);
|
||||
g_clear_object (&priv->task);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wp_proxy_augment_error:
|
||||
* @self: the proxy
|
||||
* @error: (transfer full): the error
|
||||
*
|
||||
* Reports an error that occured during the augment process
|
||||
*/
|
||||
void
|
||||
wp_proxy_augment_error (WpProxy * self, GError * error)
|
||||
{
|
||||
WpProxyPrivate *priv;
|
||||
|
||||
g_return_if_fail (WP_IS_PROXY (self));
|
||||
|
||||
priv = wp_proxy_get_instance_private (self);
|
||||
|
||||
if (priv->task)
|
||||
g_task_return_error (priv->task, error);
|
||||
else
|
||||
g_error_free (error);
|
||||
|
||||
g_clear_object (&priv->task);
|
||||
}
|
||||
|
||||
gboolean
|
||||
wp_proxy_bind_global (WpProxy * self)
|
||||
{
|
||||
WpProxyPrivate *priv;
|
||||
g_autoptr (WpRemote) remote = NULL;
|
||||
|
||||
g_return_val_if_fail (wp_proxy_is_global (self), FALSE);
|
||||
|
||||
priv = wp_proxy_get_instance_private (self);
|
||||
|
||||
if (priv->pw_proxy)
|
||||
return FALSE;
|
||||
|
||||
remote = g_weak_ref_get (&priv->remote);
|
||||
g_return_val_if_fail (remote != NULL, FALSE);
|
||||
|
||||
/* bind */
|
||||
priv->pw_proxy = wp_remote_pipewire_proxy_bind (
|
||||
WP_REMOTE_PIPEWIRE (remote),
|
||||
priv->global_id, priv->iface_type);
|
||||
pw_proxy_add_listener (priv->pw_proxy, &priv->listener, &proxy_events,
|
||||
self);
|
||||
|
||||
/* inform subclasses and listeners */
|
||||
g_signal_emit (self, wp_proxy_signals[SIGNAL_PW_PROXY_CREATED], 0,
|
||||
priv->pw_proxy);
|
||||
|
||||
/* declare the feature as ready */
|
||||
wp_proxy_set_feature_ready (self, WP_PROXY_FEATURE_PW_PROXY);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WpProxyFeatures
|
||||
wp_proxy_get_features (WpProxy * self)
|
||||
{
|
||||
WpProxyPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (WP_IS_PROXY (self), 0);
|
||||
|
||||
priv = wp_proxy_get_instance_private (self);
|
||||
return priv->ft_ready;
|
||||
}
|
||||
|
||||
/**
|
||||
* wp_proxy_get_remote:
|
||||
* @self: the proxy
|
||||
*
|
||||
* Returns: (transfer full): the remote that created this proxy
|
||||
*/
|
||||
WpRemote *
|
||||
wp_proxy_get_remote (WpProxy * self)
|
||||
{
|
||||
WpProxyPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (WP_IS_PROXY (self), NULL);
|
||||
|
||||
priv = wp_proxy_get_instance_private (self);
|
||||
return g_weak_ref_get (&priv->remote);
|
||||
}
|
||||
|
||||
gboolean
|
||||
wp_proxy_is_global (WpProxy * self)
|
||||
{
|
||||
return wp_proxy_get_global_id (self) != 0;
|
||||
}
|
||||
|
||||
guint32
|
||||
wp_proxy_get_global_id (WpProxy * self)
|
||||
{
|
||||
WpProxyPrivate *priv;
|
||||
@@ -193,7 +578,78 @@ wp_proxy_get_global_id (WpProxy * self)
|
||||
return priv->global_id;
|
||||
}
|
||||
|
||||
gpointer
|
||||
guint32
|
||||
wp_proxy_get_global_permissions (WpProxy * self)
|
||||
{
|
||||
WpProxyPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (WP_IS_PROXY (self), 0);
|
||||
|
||||
priv = wp_proxy_get_instance_private (self);
|
||||
return priv->global_perm;
|
||||
}
|
||||
|
||||
/**
|
||||
* wp_proxy_get_global_properties:
|
||||
*
|
||||
* Returns: (transfer full): the global properties of the proxy
|
||||
*/
|
||||
WpProperties *
|
||||
wp_proxy_get_global_properties (WpProxy * self)
|
||||
{
|
||||
WpProxyPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (WP_IS_PROXY (self), NULL);
|
||||
|
||||
priv = wp_proxy_get_instance_private (self);
|
||||
return priv->global_props ? wp_properties_ref (priv->global_props) : NULL;
|
||||
}
|
||||
|
||||
guint32
|
||||
wp_proxy_get_interface_type (WpProxy * self)
|
||||
{
|
||||
WpProxyPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (WP_IS_PROXY (self), 0);
|
||||
|
||||
priv = wp_proxy_get_instance_private (self);
|
||||
return priv->iface_type;
|
||||
}
|
||||
|
||||
const gchar *
|
||||
wp_proxy_get_interface_name (WpProxy * self)
|
||||
{
|
||||
const gchar *name = NULL;
|
||||
|
||||
g_return_val_if_fail (WP_IS_PROXY (self), NULL);
|
||||
|
||||
g_object_get (self, "interface-name", &name, NULL);
|
||||
return name;
|
||||
}
|
||||
|
||||
GQuark
|
||||
wp_proxy_get_interface_quark (WpProxy * self)
|
||||
{
|
||||
GQuark q = 0;
|
||||
|
||||
g_return_val_if_fail (WP_IS_PROXY (self), 0);
|
||||
|
||||
g_object_get (self, "interface-quark", &q, NULL);
|
||||
return q;
|
||||
}
|
||||
|
||||
guint32
|
||||
wp_proxy_get_interface_version (WpProxy * self)
|
||||
{
|
||||
WpProxyPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (WP_IS_PROXY (self), 0);
|
||||
|
||||
priv = wp_proxy_get_instance_private (self);
|
||||
return priv->iface_version;
|
||||
}
|
||||
|
||||
struct pw_proxy *
|
||||
wp_proxy_get_pw_proxy (WpProxy * self)
|
||||
{
|
||||
WpProxyPrivate *priv;
|
||||
@@ -201,17 +657,39 @@ wp_proxy_get_pw_proxy (WpProxy * self)
|
||||
g_return_val_if_fail (WP_IS_PROXY (self), NULL);
|
||||
|
||||
priv = wp_proxy_get_instance_private (self);
|
||||
return priv->proxy;
|
||||
return priv->pw_proxy;
|
||||
}
|
||||
|
||||
void wp_proxy_sync (WpProxy * self)
|
||||
gconstpointer
|
||||
wp_proxy_get_native_info (WpProxy * self)
|
||||
{
|
||||
WpProxyPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (WP_IS_PROXY (self), NULL);
|
||||
|
||||
priv = wp_proxy_get_instance_private (self);
|
||||
return priv->native_info;
|
||||
}
|
||||
|
||||
void
|
||||
wp_proxy_update_native_info (WpProxy * self, gconstpointer info,
|
||||
WpProxyNativeInfoUpdate update, GDestroyNotify destroy)
|
||||
{
|
||||
WpProxyPrivate *priv;
|
||||
|
||||
g_return_if_fail (WP_IS_PROXY (self));
|
||||
g_return_if_fail (destroy != NULL);
|
||||
|
||||
priv = wp_proxy_get_instance_private (self);
|
||||
|
||||
/* Trigger the done callback */
|
||||
pw_proxy_sync(priv->proxy, 0);
|
||||
if (update) {
|
||||
priv->native_info = update (priv->native_info, info);
|
||||
} else {
|
||||
g_clear_pointer (&priv->native_info, priv->native_info_destroy);
|
||||
priv->native_info = (gpointer) info;
|
||||
}
|
||||
|
||||
priv->native_info_destroy = destroy;
|
||||
|
||||
g_object_notify (G_OBJECT (self), "native-info");
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@
|
||||
*
|
||||
* Copyright © 2019 Collabora Ltd.
|
||||
* @author Julian Bouzas <julian.bouzas@collabora.com>
|
||||
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
@@ -11,10 +12,20 @@
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "remote.h"
|
||||
#include "properties.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
struct pw_proxy;
|
||||
|
||||
typedef enum { /*< flags >*/
|
||||
WP_PROXY_FEATURE_PW_PROXY = (1 << 0),
|
||||
WP_PROXY_FEATURE_INFO = (1 << 1),
|
||||
|
||||
WP_PROXY_FEATURE_LAST = (1 << 5), /*< skip >*/
|
||||
} WpProxyFeatures;
|
||||
|
||||
#define WP_TYPE_PROXY (wp_proxy_get_type ())
|
||||
G_DECLARE_DERIVABLE_TYPE (WpProxy, wp_proxy, WP, PROXY, GObject)
|
||||
|
||||
@@ -23,16 +34,53 @@ struct _WpProxyClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
/* Methods */
|
||||
void (*destroy) (WpProxy * self);
|
||||
void (*augment) (WpProxy *self, WpProxyFeatures features);
|
||||
|
||||
/* Signals */
|
||||
void (*done)(WpProxy *wp_proxy, gpointer data);
|
||||
void (*pw_proxy_created) (WpProxy * self, struct pw_proxy * proxy);
|
||||
void (*pw_proxy_destroyed) (WpProxy * self);
|
||||
};
|
||||
|
||||
guint wp_proxy_get_global_id (WpProxy * self);
|
||||
gpointer wp_proxy_get_pw_proxy (WpProxy * self);
|
||||
void wp_proxy_sync (WpProxy * self);
|
||||
WpProxy * wp_proxy_new_global (WpRemote * remote,
|
||||
guint32 id, guint32 permissions, WpProperties * properties,
|
||||
guint32 type, guint32 version);
|
||||
WpProxy * wp_proxy_new_wrap (WpRemote * remote,
|
||||
struct pw_proxy * proxy, guint32 type, guint32 version);
|
||||
|
||||
void wp_proxy_augment (WpProxy *self,
|
||||
WpProxyFeatures wanted_features, GCancellable * cancellable,
|
||||
GAsyncReadyCallback callback, gpointer user_data);
|
||||
gboolean wp_proxy_augment_finish (WpProxy * self, GAsyncResult * res,
|
||||
GError ** error);
|
||||
|
||||
WpProxyFeatures wp_proxy_get_features (WpProxy * self);
|
||||
|
||||
WpRemote * wp_proxy_get_remote (WpProxy * self);
|
||||
|
||||
gboolean wp_proxy_is_global (WpProxy * self);
|
||||
guint32 wp_proxy_get_global_id (WpProxy * self);
|
||||
guint32 wp_proxy_get_global_permissions (WpProxy * self);
|
||||
WpProperties * wp_proxy_get_global_properties (WpProxy * self);
|
||||
|
||||
guint32 wp_proxy_get_interface_type (WpProxy * self);
|
||||
const gchar * wp_proxy_get_interface_name (WpProxy * self);
|
||||
GQuark wp_proxy_get_interface_quark (WpProxy * self);
|
||||
guint32 wp_proxy_get_interface_version (WpProxy * self);
|
||||
|
||||
struct pw_proxy * wp_proxy_get_pw_proxy (WpProxy * self);
|
||||
gconstpointer wp_proxy_get_native_info (WpProxy * self);
|
||||
|
||||
/* for subclasses only */
|
||||
|
||||
typedef gpointer (*WpProxyNativeInfoUpdate) (gpointer old_info,
|
||||
gconstpointer new_info);
|
||||
|
||||
void wp_proxy_update_native_info (WpProxy * self, gconstpointer info,
|
||||
WpProxyNativeInfoUpdate update, GDestroyNotify destroy);
|
||||
|
||||
void wp_proxy_set_feature_ready (WpProxy * self, WpProxyFeatures feature);
|
||||
void wp_proxy_augment_error (WpProxy * self, GError * error);
|
||||
|
||||
gboolean wp_proxy_bind_global (WpProxy * self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
#include "remote-pipewire.h"
|
||||
|
||||
#include <pipewire/pipewire.h>
|
||||
|
||||
/*
|
||||
@@ -15,15 +16,6 @@
|
||||
|
||||
#define WP_LOOP_SOURCE(x) ((WpLoopSource *) x)
|
||||
|
||||
G_DEFINE_QUARK (node, signal_detail_node)
|
||||
G_DEFINE_QUARK (port, signal_detail_port)
|
||||
G_DEFINE_QUARK (factory, signal_detail_factory)
|
||||
G_DEFINE_QUARK (link, signal_detail_link)
|
||||
G_DEFINE_QUARK (client, signal_detail_client)
|
||||
G_DEFINE_QUARK (module, signal_detail_module)
|
||||
G_DEFINE_QUARK (device, signal_detail_device)
|
||||
G_DEFINE_QUARK (endpoint, signal_detail_endpoint)
|
||||
|
||||
typedef struct _WpLoopSource WpLoopSource;
|
||||
struct _WpLoopSource
|
||||
{
|
||||
@@ -90,6 +82,10 @@ struct _WpRemotePipewire
|
||||
struct spa_hook registry_listener;
|
||||
|
||||
GMainContext *context;
|
||||
|
||||
GHashTable *proxies;
|
||||
GHashTable *default_features;
|
||||
GQueue created_obj_proxies;
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -113,45 +109,53 @@ static guint signals[LAST_SIGNAL] = { 0 };
|
||||
G_DEFINE_TYPE (WpRemotePipewire, wp_remote_pipewire, WP_TYPE_REMOTE)
|
||||
|
||||
static void
|
||||
registry_global(void *data, uint32_t id,
|
||||
uint32_t permissions, uint32_t type, uint32_t version,
|
||||
const struct spa_dict *props)
|
||||
on_proxy_ready (GObject * obj, GAsyncResult * res, gpointer data)
|
||||
{
|
||||
GQuark detail = 0;
|
||||
WpRemotePipewire *self = WP_REMOTE_PIPEWIRE (data);
|
||||
WpProxy *proxy = WP_PROXY (obj);
|
||||
g_autoptr (GError) error = NULL;
|
||||
|
||||
switch (type) {
|
||||
case PW_TYPE_INTERFACE_Node:
|
||||
detail = signal_detail_node_quark ();
|
||||
break;
|
||||
case PW_TYPE_INTERFACE_Port:
|
||||
detail = signal_detail_port_quark ();
|
||||
break;
|
||||
case PW_TYPE_INTERFACE_Factory:
|
||||
detail = signal_detail_factory_quark ();
|
||||
break;
|
||||
case PW_TYPE_INTERFACE_Link:
|
||||
detail = signal_detail_link_quark ();
|
||||
break;
|
||||
case PW_TYPE_INTERFACE_Client:
|
||||
detail = signal_detail_client_quark ();
|
||||
break;
|
||||
case PW_TYPE_INTERFACE_Module:
|
||||
detail = signal_detail_module_quark ();
|
||||
break;
|
||||
case PW_TYPE_INTERFACE_Device:
|
||||
detail = signal_detail_device_quark ();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if (!wp_proxy_augment_finish (proxy, res, &error)) {
|
||||
g_warning ("Failed to augment WpProxy (%p): %s", obj, error->message);
|
||||
}
|
||||
|
||||
g_signal_emit (data, signals[SIGNAL_GLOBAL_ADDED], detail, id, props);
|
||||
g_signal_emit (self, signals[SIGNAL_GLOBAL_ADDED],
|
||||
wp_proxy_get_interface_quark (proxy), proxy);
|
||||
}
|
||||
|
||||
static void
|
||||
registry_global(void *data, uint32_t id, uint32_t permissions,
|
||||
uint32_t type, uint32_t version, const struct spa_dict *props)
|
||||
{
|
||||
WpRemotePipewire *self = WP_REMOTE_PIPEWIRE (data);
|
||||
WpProxy *proxy;
|
||||
WpProxyFeatures features;
|
||||
g_autoptr (WpProperties) properties = wp_properties_new_copy_dict (props);
|
||||
|
||||
/* construct & store WpProxy */
|
||||
proxy = wp_proxy_new_global (WP_REMOTE (self), id, permissions, properties,
|
||||
type, version);
|
||||
g_hash_table_insert (self->proxies, GUINT_TO_POINTER (id), proxy);
|
||||
|
||||
g_debug ("registry global:%u perm:0x%x type:%u/%u -> WpProxy:%p",
|
||||
id, permissions, type, version, proxy);
|
||||
|
||||
/* augment */
|
||||
features = GPOINTER_TO_UINT (g_hash_table_lookup (self->default_features,
|
||||
GUINT_TO_POINTER (G_TYPE_FROM_INSTANCE (proxy))));
|
||||
wp_proxy_augment (proxy, features, NULL, on_proxy_ready, self);
|
||||
}
|
||||
|
||||
static void
|
||||
registry_global_remove (void *data, uint32_t id)
|
||||
{
|
||||
g_signal_emit (data, signals[SIGNAL_GLOBAL_REMOVED], 0, id);
|
||||
WpRemotePipewire *self = WP_REMOTE_PIPEWIRE (data);
|
||||
g_autoptr (WpProxy) proxy = NULL;
|
||||
|
||||
if (g_hash_table_steal_extended (self->proxies, GUINT_TO_POINTER (id), NULL,
|
||||
(gpointer *) &proxy))
|
||||
g_signal_emit (data, signals[SIGNAL_GLOBAL_REMOVED],
|
||||
wp_proxy_get_interface_quark (proxy), proxy);
|
||||
}
|
||||
|
||||
static const struct pw_registry_proxy_events registry_proxy_events = {
|
||||
@@ -198,6 +202,9 @@ static const struct pw_remote_events remote_events = {
|
||||
static void
|
||||
wp_remote_pipewire_init (WpRemotePipewire *self)
|
||||
{
|
||||
self->proxies = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
|
||||
g_object_unref);
|
||||
self->default_features = g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -223,6 +230,8 @@ wp_remote_pipewire_finalize (GObject *object)
|
||||
{
|
||||
WpRemotePipewire *self = WP_REMOTE_PIPEWIRE (object);
|
||||
|
||||
g_clear_pointer (&self->proxies, g_hash_table_unref);
|
||||
g_clear_pointer (&self->default_features, g_hash_table_unref);
|
||||
pw_remote_destroy (self->remote);
|
||||
pw_core_destroy (self->core);
|
||||
g_clear_pointer (&self->context, g_main_context_unref);
|
||||
@@ -336,10 +345,10 @@ wp_remote_pipewire_class_init (WpRemotePipewireClass *klass)
|
||||
/* Signals */
|
||||
signals[SIGNAL_GLOBAL_ADDED] = g_signal_new ("global-added",
|
||||
G_TYPE_FROM_CLASS (klass), G_SIGNAL_DETAILED | G_SIGNAL_RUN_LAST,
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_POINTER);
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 1, WP_TYPE_PROXY);
|
||||
signals[SIGNAL_GLOBAL_REMOVED] = g_signal_new ("global-removed",
|
||||
G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_UINT);
|
||||
G_TYPE_FROM_CLASS (klass), G_SIGNAL_DETAILED | G_SIGNAL_RUN_LAST,
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 1, WP_TYPE_PROXY);
|
||||
}
|
||||
|
||||
WpRemote *
|
||||
@@ -359,6 +368,33 @@ wp_remote_pipewire_new (WpCore *core, GMainContext *context)
|
||||
return remote;
|
||||
}
|
||||
|
||||
void
|
||||
wp_remote_pipewire_set_default_features (WpRemotePipewire * self,
|
||||
GType proxy_type, WpProxyFeatures features)
|
||||
{
|
||||
g_return_if_fail (WP_IS_REMOTE_PIPEWIRE (self));
|
||||
|
||||
g_hash_table_insert (self->default_features, GUINT_TO_POINTER (proxy_type),
|
||||
GUINT_TO_POINTER (features));
|
||||
}
|
||||
|
||||
WpProxy *
|
||||
wp_remote_pipewire_create_object (WpRemotePipewire *self,
|
||||
const gchar *factory_name, guint32 interface_type,
|
||||
guint32 interface_version, WpProperties * properties)
|
||||
{
|
||||
struct pw_proxy *pw_proxy;
|
||||
|
||||
g_return_val_if_fail (WP_IS_REMOTE_PIPEWIRE (self), NULL);
|
||||
g_return_val_if_fail (self->core_proxy, NULL);
|
||||
|
||||
pw_proxy = pw_core_proxy_create_object (self->core_proxy, factory_name,
|
||||
interface_type, interface_version, wp_properties_peek_dict (properties),
|
||||
0);
|
||||
return wp_proxy_new_wrap (WP_REMOTE (self), pw_proxy, interface_type,
|
||||
interface_version);
|
||||
}
|
||||
|
||||
gpointer
|
||||
wp_remote_pipewire_proxy_bind (WpRemotePipewire *self, guint global_id,
|
||||
guint global_type)
|
||||
@@ -380,17 +416,6 @@ wp_remote_pipewire_find_factory (WpRemotePipewire *self,
|
||||
return pw_core_find_factory(self->core, factory_name);
|
||||
}
|
||||
|
||||
gpointer
|
||||
wp_remote_pipewire_create_object (WpRemotePipewire *self,
|
||||
const char *factory_name, guint global_type, gconstpointer props)
|
||||
{
|
||||
g_return_val_if_fail (WP_IS_REMOTE_PIPEWIRE(self), NULL);
|
||||
g_return_val_if_fail (self->core_proxy, NULL);
|
||||
|
||||
return pw_core_proxy_create_object (self->core_proxy, factory_name,
|
||||
global_type, 0, props, 0);
|
||||
}
|
||||
|
||||
void
|
||||
wp_remote_pipewire_add_spa_lib (WpRemotePipewire *self,
|
||||
const char *factory_regexp, const char *lib)
|
||||
|
@@ -10,6 +10,7 @@
|
||||
#define __WIREPLUMBER_REMOTE_PIPEWIRE_H__
|
||||
|
||||
#include "remote.h"
|
||||
#include "proxy.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@@ -19,12 +20,17 @@ G_DECLARE_FINAL_TYPE (WpRemotePipewire, wp_remote_pipewire,
|
||||
|
||||
WpRemote *wp_remote_pipewire_new (WpCore *core, GMainContext *context);
|
||||
|
||||
void wp_remote_pipewire_set_default_features (
|
||||
WpRemotePipewire * self, GType proxy_type, WpProxyFeatures features);
|
||||
|
||||
WpProxy * wp_remote_pipewire_create_object (WpRemotePipewire *self,
|
||||
const gchar *factory_name, guint32 interface_type,
|
||||
guint32 interface_version, WpProperties * properties);
|
||||
|
||||
gpointer wp_remote_pipewire_proxy_bind (WpRemotePipewire *self, guint global_id,
|
||||
guint global_type);
|
||||
gpointer wp_remote_pipewire_find_factory (WpRemotePipewire *self,
|
||||
const char *factory_name);
|
||||
gpointer wp_remote_pipewire_create_object (WpRemotePipewire *self,
|
||||
const char *factory_name, guint global_type, gconstpointer props);
|
||||
void wp_remote_pipewire_add_spa_lib (WpRemotePipewire *self,
|
||||
const char *factory_regexp, const char *lib);
|
||||
gpointer wp_remote_pipewire_load_spa_handle(WpRemotePipewire *self,
|
||||
|
Reference in New Issue
Block a user