Commit e5a05dcc authored by George Kiagiadakis's avatar George Kiagiadakis

proxy-*: improve proxy subclasses

* add proxy sync method
* add wrapers for enum/set/subscribe_params
* move the info structure handling to the subclasses
* expose info->props as WpProperties
parent 2e28c9ae
......@@ -13,22 +13,66 @@
struct _WpProxyLink
{
WpProxy parent;
struct pw_link_info *info;
/* The link proxy listener */
struct spa_hook listener;
};
enum {
PROP_0,
PROP_INFO,
PROP_PROPERTIES,
};
G_DEFINE_TYPE (WpProxyLink, wp_proxy_link, WP_TYPE_PROXY)
static void
wp_proxy_link_init (WpProxyLink * self)
{
}
static void
wp_proxy_link_finalize (GObject * object)
{
WpProxyLink *self = WP_PROXY_LINK (object);
g_clear_pointer (&self->info, pw_link_info_free);
G_OBJECT_CLASS (wp_proxy_link_parent_class)->finalize (object);
}
static void
wp_proxy_link_get_property (GObject * object, guint property_id,
GValue * value, GParamSpec * pspec)
{
WpProxyLink *self = WP_PROXY_LINK (object);
switch (property_id) {
case PROP_INFO:
g_value_set_pointer (value, self->info);
break;
case PROP_PROPERTIES:
g_value_take_boxed (value, wp_proxy_link_get_properties (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
link_event_info(void *data, const struct pw_link_info *info)
{
WpProxy *proxy = WP_PROXY (data);
WpProxyLink *self = WP_PROXY_LINK (data);
self->info = pw_link_info_update (self->info, info);
g_object_notify (G_OBJECT (self), "info");
if (info->change_mask & PW_LINK_CHANGE_MASK_PROPS)
g_object_notify (G_OBJECT (self), "properties");
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);
wp_proxy_set_feature_ready (WP_PROXY (self), WP_PROXY_FEATURE_INFO);
}
static const struct pw_link_proxy_events link_events = {
......@@ -36,11 +80,6 @@ static const struct pw_link_proxy_events link_events = {
.info = link_event_info,
};
static void
wp_proxy_link_init (WpProxyLink * self)
{
}
static void
wp_proxy_link_pw_proxy_created (WpProxy * proxy, struct pw_proxy * pw_proxy)
{
......@@ -52,7 +91,32 @@ wp_proxy_link_pw_proxy_created (WpProxy * proxy, struct pw_proxy * pw_proxy)
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;
object_class->get_property = wp_proxy_link_get_property;
proxy_class->pw_proxy_created = wp_proxy_link_pw_proxy_created;
g_object_class_install_property (object_class, PROP_INFO,
g_param_spec_pointer ("info", "info", "The struct pw_link_info *",
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_PROPERTIES,
g_param_spec_boxed ("properties", "properties",
"The pipewire properties of the proxy", WP_TYPE_PROPERTIES,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
}
const struct pw_link_info *
wp_proxy_link_get_info (WpProxyLink * self)
{
return self->info;
}
WpProperties *
wp_proxy_link_get_properties (WpProxyLink * self)
{
return wp_properties_new_wrap_dict (self->info->props);
}
......@@ -13,15 +13,14 @@
G_BEGIN_DECLS
struct pw_link_info;
#define WP_TYPE_PROXY_LINK (wp_proxy_link_get_type ())
G_DECLARE_FINAL_TYPE (WpProxyLink, wp_proxy_link, WP, PROXY_LINK, WpProxy)
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));
}
const struct pw_link_info * wp_proxy_link_get_info (WpProxyLink * self);
WpProperties * wp_proxy_link_get_properties (WpProxyLink * self);
G_END_DECLS
......
......@@ -7,40 +7,106 @@
*/
#include "proxy-node.h"
#include "error.h"
#include <pipewire/pipewire.h>
struct _WpProxyNode
{
WpProxy parent;
struct pw_node_info *info;
/* The node proxy listener */
struct spa_hook listener;
};
enum {
PROP_0,
PROP_INFO,
PROP_PROPERTIES,
};
enum {
SIGNAL_PARAM,
N_SIGNALS
};
static guint32 signals[N_SIGNALS];
G_DEFINE_TYPE (WpProxyNode, wp_proxy_node, WP_TYPE_PROXY)
static void
wp_proxy_node_init (WpProxyNode * self)
{
}
static void
wp_proxy_node_finalize (GObject * object)
{
WpProxyNode *self = WP_PROXY_NODE (object);
g_clear_pointer (&self->info, pw_node_info_free);
G_OBJECT_CLASS (wp_proxy_node_parent_class)->finalize (object);
}
static void
wp_proxy_node_get_property (GObject * object, guint property_id,
GValue * value, GParamSpec * pspec)
{
WpProxyNode *self = WP_PROXY_NODE (object);
switch (property_id) {
case PROP_INFO:
g_value_set_pointer (value, self->info);
break;
case PROP_PROPERTIES:
g_value_take_boxed (value, wp_proxy_node_get_properties (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
node_event_info(void *data, const struct pw_node_info *info)
{
WpProxy *proxy = WP_PROXY (data);
WpProxyNode *self = WP_PROXY_NODE (data);
self->info = pw_node_info_update (self->info, info);
g_object_notify (G_OBJECT (self), "info");
if (info->change_mask & PW_NODE_CHANGE_MASK_PROPS)
g_object_notify (G_OBJECT (self), "properties");
wp_proxy_set_feature_ready (WP_PROXY (self), WP_PROXY_FEATURE_INFO);
}
static void
node_event_param (void *data, int seq, uint32_t id, uint32_t index,
uint32_t next, const struct spa_pod *param)
{
WpProxyNode *self = WP_PROXY_NODE (data);
GTask *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);
g_signal_emit (self, signals[SIGNAL_PARAM], 0, seq, id, index, next, param);
/* if this param event was emited because of enum_params_collect(),
* copy the param in the result array of that API */
task = wp_proxy_find_async_task (WP_PROXY (self), seq, FALSE);
if (task) {
GPtrArray *array = g_task_get_task_data (task);
g_ptr_array_add (array, spa_pod_copy (param));
}
}
static const struct pw_node_proxy_events node_events = {
PW_VERSION_NODE_PROXY_EVENTS,
.info = node_event_info,
.param = node_event_param,
};
static void
wp_proxy_node_init (WpProxyNode * self)
{
}
static void
wp_proxy_node_pw_proxy_created (WpProxy * proxy, struct pw_proxy * pw_proxy)
{
......@@ -52,7 +118,173 @@ wp_proxy_node_pw_proxy_created (WpProxy * proxy, struct pw_proxy * pw_proxy)
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;
object_class->get_property = wp_proxy_node_get_property;
proxy_class->pw_proxy_created = wp_proxy_node_pw_proxy_created;
g_object_class_install_property (object_class, PROP_INFO,
g_param_spec_pointer ("info", "info", "The struct pw_node_info *",
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_PROPERTIES,
g_param_spec_boxed ("properties", "properties",
"The pipewire properties of the proxy", WP_TYPE_PROPERTIES,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
signals[SIGNAL_PARAM] = g_signal_new ("param", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 5,
G_TYPE_INT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_POINTER);
}
const struct pw_node_info *
wp_proxy_node_get_info (WpProxyNode * self)
{
return self->info;
}
WpProperties *
wp_proxy_node_get_properties (WpProxyNode * self)
{
return wp_properties_new_wrap_dict (self->info->props);
}
static void
enum_params_done (WpProxy * proxy, GAsyncResult * res, gpointer data)
{
int seq = GPOINTER_TO_INT (data);
g_autoptr (GError) error = NULL;
g_autoptr (GTask) task = NULL;
/* finish the sync task */
wp_proxy_sync_finish (proxy, res, &error);
/* find the enum params task and return from it */
task = wp_proxy_find_async_task (proxy, seq, TRUE);
g_return_if_fail (task != NULL);
if (error)
g_task_return_error (task, g_steal_pointer (&error));
else {
GPtrArray *params = g_task_get_task_data (task);
g_task_return_pointer (task, g_ptr_array_ref (params),
(GDestroyNotify) g_ptr_array_unref);
}
}
void
wp_proxy_node_enum_params_collect (WpProxyNode * self,
guint32 id, const struct spa_pod *filter,
GCancellable * cancellable, GAsyncReadyCallback callback,
gpointer user_data)
{
g_autoptr (GTask) task = NULL;
int seq;
GPtrArray *params;
g_return_if_fail (WP_IS_PROXY_NODE (self));
/* create task for enum_params */
task = g_task_new (self, cancellable, callback, user_data);
params = g_ptr_array_new_with_free_func (free);
g_task_set_task_data (task, params, (GDestroyNotify) g_ptr_array_unref);
/* call enum_params */
seq = wp_proxy_node_enum_params (self, id, filter);
if (G_UNLIKELY (seq < 0)) {
g_task_return_new_error (task, WP_DOMAIN_LIBRARY,
WP_LIBRARY_ERROR_OPERATION_FAILED, "enum_params failed: %s",
g_strerror (-seq));
return;
}
wp_proxy_register_async_task (WP_PROXY (self), seq, g_steal_pointer (&task));
/* call sync */
wp_proxy_sync (WP_PROXY (self), cancellable,
(GAsyncReadyCallback) enum_params_done, GINT_TO_POINTER (seq));
}
/**
* wp_proxy_node_enum_params_collect_finish:
*
* Returns: (transfer full) (element-type spa_pod*):
* the collected params
*/
GPtrArray *
wp_proxy_node_enum_params_collect_finish (WpProxyNode * self,
GAsyncResult * res, GError ** error)
{
g_return_val_if_fail (WP_IS_PROXY_NODE (self), NULL);
g_return_val_if_fail (g_task_is_valid (res, self), NULL);
return g_task_propagate_pointer (G_TASK (res), error);
}
gint
wp_proxy_node_enum_params (WpProxyNode * self,
guint32 id, const struct spa_pod *filter)
{
struct pw_node_proxy *pwp;
int enum_params_result;
g_return_val_if_fail (WP_IS_PROXY_NODE (self), -EINVAL);
pwp = (struct pw_node_proxy *) wp_proxy_get_pw_proxy (WP_PROXY (self));
g_return_val_if_fail (pwp != NULL, -EINVAL);
enum_params_result = pw_node_proxy_enum_params (pwp, 0, id, 0, -1, filter);
g_warn_if_fail (enum_params_result >= 0);
return enum_params_result;
}
void
wp_proxy_node_subscribe_params (WpProxyNode * self, guint32 n_ids, ...)
{
va_list args;
guint32 *ids = g_alloca (n_ids * sizeof (guint32));
va_start (args, n_ids);
for (gint i = 0; i < n_ids; i++)
ids[i] = va_arg (args, guint32);
va_end (args);
wp_proxy_node_subscribe_params_array (self, n_ids, ids);
}
void
wp_proxy_node_subscribe_params_array (WpProxyNode * self, guint32 n_ids,
guint32 *ids)
{
struct pw_node_proxy *pwp;
int node_subscribe_params_result;
g_return_if_fail (WP_IS_PROXY_NODE (self));
pwp = (struct pw_node_proxy *) wp_proxy_get_pw_proxy (WP_PROXY (self));
g_return_if_fail (pwp != NULL);
node_subscribe_params_result = pw_node_proxy_subscribe_params (
pwp, ids, n_ids);
g_warn_if_fail (node_subscribe_params_result >= 0);
}
void
wp_proxy_node_set_param (WpProxyNode * self, guint32 id,
guint32 flags, const struct spa_pod *param)
{
struct pw_node_proxy *pwp;
int node_set_param_result;
g_return_if_fail (WP_IS_PROXY_NODE (self));
pwp = (struct pw_node_proxy *) wp_proxy_get_pw_proxy (WP_PROXY (self));
g_return_if_fail (pwp != NULL);
node_set_param_result = pw_node_proxy_set_param (
pwp, id, flags, param);
g_warn_if_fail (node_set_param_result >= 0);
}
......@@ -13,15 +13,31 @@
G_BEGIN_DECLS
struct spa_pod;
struct pw_node_info;
#define WP_TYPE_PROXY_NODE (wp_proxy_node_get_type ())
G_DECLARE_FINAL_TYPE (WpProxyNode, wp_proxy_node, WP, PROXY_NODE, WpProxy)
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));
}
const struct pw_node_info * wp_proxy_node_get_info (WpProxyNode * self);
WpProperties * wp_proxy_node_get_properties (WpProxyNode * self);
void wp_proxy_node_enum_params_collect (WpProxyNode * self,
guint32 id, const struct spa_pod *filter,
GCancellable * cancellable, GAsyncReadyCallback callback,
gpointer user_data);
GPtrArray * wp_proxy_node_enum_params_collect_finish (WpProxyNode * self,
GAsyncResult * res, GError ** error);
gint wp_proxy_node_enum_params (WpProxyNode * self,
guint32 id, const struct spa_pod *filter);
void wp_proxy_node_subscribe_params (WpProxyNode * self, guint32 n_ids, ...);
void wp_proxy_node_subscribe_params_array (WpProxyNode * self, guint32 n_ids,
guint32 *ids);
void wp_proxy_node_set_param (WpProxyNode * self, guint32 id,
guint32 flags, const struct spa_pod *param);
G_END_DECLS
......
......@@ -7,34 +7,80 @@
*/
#include "proxy-port.h"
#include "error.h"
#include <pipewire/pipewire.h>
#include <spa/param/audio/format-utils.h>
struct _WpProxyPort
{
WpProxy parent;
struct pw_port_info *info;
/* The port proxy listener */
struct spa_hook listener;
};
enum {
PROP_0,
PROP_INFO,
PROP_PROPERTIES,
};
/* The port format */
uint32_t media_type;
uint32_t media_subtype;
struct spa_audio_info_raw format;
enum {
SIGNAL_PARAM,
N_SIGNALS
};
static guint32 signals[N_SIGNALS];
G_DEFINE_TYPE (WpProxyPort, wp_proxy_port, WP_TYPE_PROXY)
static void
wp_proxy_port_init (WpProxyPort * self)
{
}
static void
wp_proxy_port_finalize (GObject * object)
{
WpProxyPort *self = WP_PROXY_PORT (object);
g_clear_pointer (&self->info, pw_port_info_free);
G_OBJECT_CLASS (wp_proxy_port_parent_class)->finalize (object);
}
static void
wp_proxy_port_get_property (GObject * object, guint property_id,
GValue * value, GParamSpec * pspec)
{
WpProxyPort *self = WP_PROXY_PORT (object);
switch (property_id) {
case PROP_INFO:
g_value_set_pointer (value, self->info);
break;
case PROP_PROPERTIES:
g_value_take_boxed (value, wp_proxy_port_get_properties (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
port_event_info(void *data, const struct pw_port_info *info)
{
WpProxy *proxy = WP_PROXY (data);
WpProxyPort *self = WP_PROXY_PORT (data);
self->info = pw_port_info_update (self->info, info);
g_object_notify (G_OBJECT (self), "info");
if (info->change_mask & PW_PORT_CHANGE_MASK_PROPS)
g_object_notify (G_OBJECT (self), "properties");
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);
wp_proxy_set_feature_ready (WP_PROXY (self), WP_PROXY_FEATURE_INFO);
}
static void
......@@ -42,23 +88,17 @@ port_event_param(void *data, int seq, uint32_t id, uint32_t index,
uint32_t next, const struct spa_pod *param)
{
WpProxyPort *self = WP_PROXY_PORT (data);
GTask *task;
/* Only handle EnumFormat */
if (id != SPA_PARAM_EnumFormat)
return;
/* Parse the format */
spa_format_parse(param, &self->media_type, &self->media_subtype);
g_signal_emit (self, signals[SIGNAL_PARAM], 0, seq, id, index, next, param);
/* Only handle raw audio formats for now */
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);
/* if this param event was emited because of enum_params_collect(),
* copy the param in the result array of that API */
task = wp_proxy_find_async_task (WP_PROXY (self), seq, FALSE);
if (task) {
GPtrArray *array = g_task_get_task_data (task);
g_ptr_array_add (array, spa_pod_copy (param));
}
wp_proxy_set_feature_ready (WP_PROXY (self), WP_PROXY_PORT_FEATURE_FORMAT);
}
static const struct pw_port_proxy_events port_events = {
......@@ -68,44 +108,166 @@ static const struct pw_port_proxy_events port_events = {
};
static void
wp_proxy_port_init (WpProxyPort * self)
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_augment (WpProxy * proxy, WpProxyFeatures features)
wp_proxy_port_class_init (WpProxyPortClass * klass)
{
/* call the default implementation to ensure we have a proxy, if necessary */
WP_PROXY_CLASS (wp_proxy_port_parent_class)->augment (proxy, features);
GObjectClass *object_class = (GObjectClass *) klass;
WpProxyClass *proxy_class = (WpProxyClass *) klass;
if (features & WP_PROXY_PORT_FEATURE_FORMAT) {
struct pw_proxy *pwp = wp_proxy_get_pw_proxy (proxy);
g_return_if_fail (pwp != NULL);
object_class->finalize = wp_proxy_port_finalize;
object_class->get_property = wp_proxy_port_get_property;
pw_port_proxy_enum_params ((struct pw_port_proxy *) pwp, 0,
SPA_PARAM_EnumFormat, 0, -1, NULL);
}
proxy_class->pw_proxy_created = wp_proxy_port_pw_proxy_created;
g_object_class_install_property (object_class, PROP_INFO,
g_param_spec_pointer ("info", "info", "The struct pw_port_info *",
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_PROPERTIES,
g_param_spec_boxed ("properties", "properties",
"The pipewire properties of the proxy", WP_TYPE_PROPERTIES,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
signals[SIGNAL_PARAM] = g_signal_new ("param", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 5,
G_TYPE_INT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_POINTER);
}
static void
wp_proxy_port_pw_proxy_created (WpProxy * proxy, struct pw_proxy * pw_proxy)
const struct pw_port_info *
wp_proxy_port_get_info (WpProxyPort * self)
{
WpProxyPort *self = WP_PROXY_PORT (proxy);
pw_port_proxy_add_listener ((struct pw_port_proxy *) pw_proxy,
&self->listener, &port_events, self);
return self->info;
}
WpProperties *
wp_proxy_port_get_properties (WpProxyPort * self)
{
return wp_properties_new_wrap_dict (self->info->props);
}
static void
wp_proxy_port_class_init (WpProxyPortClass * klass)
enum_params_done (WpProxy * proxy, GAsyncResult * res, gpointer data)
{
WpProxyClass *proxy_class = (WpProxyClass *) klass;
int seq = GPOINTER_TO_INT (data);
g_autoptr (GError) error = NULL;
g_autoptr (GTask) task = NULL;
proxy_class->augment = wp_proxy_port_augment;
proxy_class->pw_proxy_created = wp_proxy_port_pw_proxy_created;
/* finish the sync task */
wp_proxy_sync_finish (proxy, res, &error);
/* find the enum params task and return from it */
task = wp_proxy_find_async_task (proxy, seq, TRUE);
g_return_if_fail (task != NULL);
if (error)
g_task_return_error (task, g_steal_pointer (&error));
else {
GPtrArray *params = g_task_get_task_data (task);
g_task_return_pointer (task, g_ptr_array_ref (params),
(GDestroyNotify) g_ptr_array_unref);
}
}
const struct spa_audio_info_raw *
wp_proxy_port_get_format (WpProxyPort * self)
void
wp_proxy_port_enum_params_collect (WpProxyPort * self,
guint32 id, const struct spa_pod *filter,
GCancellable * cancellable, GAsyncReadyCallback callback,
gpointer user_data)
{
return &self->format;
g_autoptr (GTask) task = NULL;
int seq;
GPtrArray *params;
g_return_if_fail (WP_IS_PROXY_PORT (self));
/* create task for enum_params */
task = g_task_new (self, cancellable, callback, user_data);
params = g_ptr_array_new_with_free_func (free);
g_task_set_task_data (task, params, (GDestroyNotify) g_ptr_array_unref);
/* call enum_params */
seq = wp_proxy_port_enum_params (self, id, filter);
if (G_UNLIKELY (seq < 0)) {
g_task_return_new_error (task, WP_DOMAIN_LIBRARY,
WP_LIBRARY_ERROR_OPERATION_FAILED, "enum_params failed: %s",
g_strerror (-seq));
return;
}
wp_proxy_register_async_task (WP_PROXY (self), seq, g_steal_pointer (&task));
/* call sync */
wp_proxy_sync (WP_PROXY (self), cancellable,
(GAsyncReadyCallback) enum_params_done, GINT_TO_POINTER (seq));
}
/**
* wp_proxy_port_enum_params_collect_finish:
*
* Returns: (transfer full) (element-type spa_pod*):
* the collected params
*/
GPtrArray *
wp_proxy_port_enum_params_collect_finish (WpProxyPort * self,
GAsyncResult * res, GError ** error)
{
g_return_val_if_fail (WP_IS_PROXY_PORT (self), NULL);
g_return_val_if_fail (g_task_is_valid (res, self), NULL);
return g_task_propagate_pointer (G_TASK (res), error);
}
gint
wp_proxy_port_enum_params (WpProxyPort * self,
guint32 id, const struct spa_pod *filter)
{
struct pw_port_proxy *pwp;
int enum_params_result;
g_return_val_if_fail (WP_IS_PROXY_PORT (self), -EINVAL);
pwp = (struct pw_port_proxy *) wp_proxy_get_pw_proxy (WP_PROXY (self));
g_return_val_if_fail (pwp != NULL, -EINVAL);