mirror of
https://gitlab.freedesktop.org/pipewire/wireplumber.git
synced 2026-01-04 15:10:12 +01:00
node: add useful API to access node info, associated ports and state changes
This commit is contained in:
parent
135b1c2cbf
commit
72ff4577c5
2 changed files with 281 additions and 0 deletions
223
lib/wp/node.c
223
lib/wp/node.c
|
|
@ -31,15 +31,24 @@
|
|||
#include "debug.h"
|
||||
#include "error.h"
|
||||
#include "private.h"
|
||||
#include "wpenums.h"
|
||||
|
||||
#include <pipewire/pipewire.h>
|
||||
#include <pipewire/impl.h>
|
||||
|
||||
enum {
|
||||
SIGNAL_STATE_CHANGED,
|
||||
N_SIGNALS,
|
||||
};
|
||||
|
||||
static guint32 signals[N_SIGNALS] = {0};
|
||||
|
||||
typedef struct _WpNodePrivate WpNodePrivate;
|
||||
struct _WpNodePrivate
|
||||
{
|
||||
struct pw_node_info *info;
|
||||
struct spa_hook listener;
|
||||
WpObjectManager *ports_om;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (WpNode, wp_node, WP_TYPE_PROXY)
|
||||
|
|
@ -56,10 +65,58 @@ wp_node_finalize (GObject * object)
|
|||
WpNodePrivate *priv = wp_node_get_instance_private (self);
|
||||
|
||||
g_clear_pointer (&priv->info, pw_node_info_free);
|
||||
g_clear_object (&priv->ports_om);
|
||||
|
||||
G_OBJECT_CLASS (wp_node_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_node_enable_feature_ports (WpNode * self, guint32 bound_id)
|
||||
{
|
||||
WpNodePrivate *priv = wp_node_get_instance_private (self);
|
||||
g_autoptr (WpCore) core = wp_proxy_get_core (WP_PROXY (self));
|
||||
GVariantBuilder b;
|
||||
|
||||
/* proxy node port -> check for node.id in global properties */
|
||||
g_variant_builder_init (&b, G_VARIANT_TYPE ("aa{sv}"));
|
||||
g_variant_builder_open (&b, G_VARIANT_TYPE_VARDICT);
|
||||
g_variant_builder_add (&b, "{sv}", "type",
|
||||
g_variant_new_int32 (WP_OBJECT_MANAGER_CONSTRAINT_PW_GLOBAL_PROPERTY));
|
||||
g_variant_builder_add (&b, "{sv}", "name",
|
||||
g_variant_new_string (PW_KEY_NODE_ID));
|
||||
g_variant_builder_add (&b, "{sv}", "value",
|
||||
g_variant_new_take_string (g_strdup_printf ("%u", bound_id)));
|
||||
g_variant_builder_close (&b);
|
||||
|
||||
wp_object_manager_add_interest (priv->ports_om,
|
||||
WP_TYPE_PORT,
|
||||
g_variant_builder_end (&b),
|
||||
WP_PROXY_FEATURES_STANDARD);
|
||||
|
||||
wp_core_install_object_manager (core, priv->ports_om);
|
||||
wp_proxy_set_feature_ready (WP_PROXY (self), WP_NODE_FEATURE_PORTS);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_node_augment (WpProxy * proxy, WpProxyFeatures features)
|
||||
{
|
||||
/* call the parent impl first to ensure we have a pw proxy if necessary */
|
||||
WP_PROXY_CLASS (wp_node_parent_class)->augment (proxy, features);
|
||||
|
||||
if (features & WP_NODE_FEATURE_PORTS) {
|
||||
WpNodePrivate *priv = wp_node_get_instance_private (WP_NODE (proxy));
|
||||
|
||||
priv->ports_om = wp_object_manager_new ();
|
||||
|
||||
/* if we are already bound, enable right away;
|
||||
else, continue in the bound() event */
|
||||
if (wp_proxy_get_features (proxy) & WP_PROXY_FEATURE_BOUND) {
|
||||
wp_node_enable_feature_ports (WP_NODE (proxy),
|
||||
wp_proxy_get_bound_id (proxy));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gconstpointer
|
||||
wp_node_get_info (WpProxy * self)
|
||||
{
|
||||
|
|
@ -122,6 +179,8 @@ node_event_info(void *data, const struct pw_node_info *info)
|
|||
{
|
||||
WpNode *self = WP_NODE (data);
|
||||
WpNodePrivate *priv = wp_node_get_instance_private (self);
|
||||
enum pw_node_state old_state = priv->info ?
|
||||
priv->info->state : PW_NODE_STATE_CREATING;
|
||||
|
||||
priv->info = pw_node_info_update (priv->info, info);
|
||||
wp_proxy_set_feature_ready (WP_PROXY (self), WP_PROXY_FEATURE_INFO);
|
||||
|
|
@ -130,6 +189,10 @@ node_event_info(void *data, const struct pw_node_info *info)
|
|||
|
||||
if (info->change_mask & PW_NODE_CHANGE_MASK_PROPS)
|
||||
g_object_notify (G_OBJECT (self), "properties");
|
||||
|
||||
if (info->change_mask & PW_NODE_CHANGE_MASK_STATE)
|
||||
g_signal_emit (self, signals[SIGNAL_STATE_CHANGED], 0, old_state,
|
||||
priv->info->state);
|
||||
}
|
||||
|
||||
static const struct pw_node_events node_events = {
|
||||
|
|
@ -147,6 +210,16 @@ wp_node_pw_proxy_created (WpProxy * proxy, struct pw_proxy * pw_proxy)
|
|||
&priv->listener, &node_events, self);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_node_bound (WpProxy * proxy, guint32 id)
|
||||
{
|
||||
WpNode *self = WP_NODE (proxy);
|
||||
WpNodePrivate *priv = wp_node_get_instance_private (self);
|
||||
|
||||
if (priv->ports_om)
|
||||
wp_node_enable_feature_ports (self, id);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_node_class_init (WpNodeClass * klass)
|
||||
{
|
||||
|
|
@ -158,6 +231,7 @@ wp_node_class_init (WpNodeClass * klass)
|
|||
proxy_class->pw_iface_type = PW_TYPE_INTERFACE_Node;
|
||||
proxy_class->pw_iface_version = PW_VERSION_NODE;
|
||||
|
||||
proxy_class->augment = wp_node_augment;
|
||||
proxy_class->get_info = wp_node_get_info;
|
||||
proxy_class->get_properties = wp_node_get_properties;
|
||||
proxy_class->enum_params = wp_node_enum_params;
|
||||
|
|
@ -165,6 +239,20 @@ wp_node_class_init (WpNodeClass * klass)
|
|||
proxy_class->set_param = wp_node_set_param;
|
||||
|
||||
proxy_class->pw_proxy_created = wp_node_pw_proxy_created;
|
||||
proxy_class->bound = wp_node_bound;
|
||||
|
||||
/**
|
||||
* WpNode::state-changed:
|
||||
* @self: the node
|
||||
* @old_state: the old state
|
||||
* @new_state: the new state
|
||||
*
|
||||
* Emitted when the node changes state
|
||||
*/
|
||||
signals[SIGNAL_STATE_CHANGED] = g_signal_new (
|
||||
"state-changed", G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 2,
|
||||
WP_TYPE_NODE_STATE, WP_TYPE_NODE_STATE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -206,6 +294,129 @@ wp_node_new_from_factory (WpCore * core,
|
|||
return self;
|
||||
}
|
||||
|
||||
WpNodeState
|
||||
wp_node_get_state (WpNode * self, const gchar ** error)
|
||||
{
|
||||
g_return_val_if_fail (WP_IS_NODE (self), WP_NODE_STATE_ERROR);
|
||||
g_return_val_if_fail (wp_proxy_get_features (WP_PROXY (self)) &
|
||||
WP_PROXY_FEATURE_INFO, WP_NODE_STATE_ERROR);
|
||||
|
||||
WpNodePrivate *priv = wp_node_get_instance_private (self);
|
||||
if (error)
|
||||
*error = priv->info->error;
|
||||
return (WpNodeState) priv->info->state;
|
||||
}
|
||||
|
||||
/**
|
||||
* wp_node_get_n_input_ports:
|
||||
* @self: the node
|
||||
* @max: (out) (optional): the maximum supported number of input ports
|
||||
*
|
||||
* Requires %WP_PROXY_FEATURE_INFO
|
||||
*
|
||||
* Returns: the number of input ports of this node, as reported by the node info
|
||||
*/
|
||||
guint
|
||||
wp_node_get_n_input_ports (WpNode * self, guint * max)
|
||||
{
|
||||
g_return_val_if_fail (WP_IS_NODE (self), 0);
|
||||
g_return_val_if_fail (wp_proxy_get_features (WP_PROXY (self)) &
|
||||
WP_PROXY_FEATURE_INFO, 0);
|
||||
|
||||
WpNodePrivate *priv = wp_node_get_instance_private (self);
|
||||
if (max)
|
||||
*max = priv->info->max_input_ports;
|
||||
return priv->info->n_input_ports;
|
||||
}
|
||||
|
||||
/**
|
||||
* wp_node_get_n_output_ports:
|
||||
* @self: the node
|
||||
* @max: (out) (optional): the maximum supported number of output ports
|
||||
*
|
||||
* Requires %WP_PROXY_FEATURE_INFO
|
||||
*
|
||||
* Returns: the number of output ports of this node, as reported by the node info
|
||||
*/
|
||||
guint
|
||||
wp_node_get_n_output_ports (WpNode * self, guint * max)
|
||||
{
|
||||
g_return_val_if_fail (WP_IS_NODE (self), 0);
|
||||
g_return_val_if_fail (wp_proxy_get_features (WP_PROXY (self)) &
|
||||
WP_PROXY_FEATURE_INFO, 0);
|
||||
|
||||
WpNodePrivate *priv = wp_node_get_instance_private (self);
|
||||
if (max)
|
||||
*max = priv->info->max_output_ports;
|
||||
return priv->info->n_output_ports;
|
||||
}
|
||||
|
||||
/**
|
||||
* wp_node_get_n_ports:
|
||||
* @self: the node
|
||||
*
|
||||
* Requires %WP_NODE_FEATURE_PORTS
|
||||
*
|
||||
* Returns: the number of ports of this node. Note that this number may not
|
||||
* add up to wp_node_get_n_input_ports() + wp_node_get_n_output_ports()
|
||||
* because it is discovered by looking at the number of available ports
|
||||
* in the registry, however ports may appear there with a delay or may
|
||||
* not appear at all if this client does not have permission to read them
|
||||
*/
|
||||
guint
|
||||
wp_node_get_n_ports (WpNode * self)
|
||||
{
|
||||
g_return_val_if_fail (WP_IS_NODE (self), 0);
|
||||
g_return_val_if_fail (wp_proxy_get_features (WP_PROXY (self)) &
|
||||
WP_NODE_FEATURE_PORTS, 0);
|
||||
|
||||
WpNodePrivate *priv = wp_node_get_instance_private (self);
|
||||
return wp_object_manager_get_n_objects (priv->ports_om);
|
||||
}
|
||||
|
||||
/**
|
||||
* wp_node_find_port:
|
||||
* @self: the node
|
||||
* @bound_id: the bound id of the port object to find
|
||||
*
|
||||
* Requires %WP_NODE_FEATURE_PORTS
|
||||
*
|
||||
* Returns: (transfer full) (nullable): the port that has the given
|
||||
* @bound_id, or %NULL if there is no such port
|
||||
*/
|
||||
WpPort *
|
||||
wp_node_find_port (WpNode * self, guint32 bound_id)
|
||||
{
|
||||
g_return_val_if_fail (WP_IS_NODE (self), NULL);
|
||||
g_return_val_if_fail (wp_proxy_get_features (WP_PROXY (self)) &
|
||||
WP_NODE_FEATURE_PORTS, NULL);
|
||||
|
||||
WpNodePrivate *priv = wp_node_get_instance_private (self);
|
||||
return (WpPort *)
|
||||
wp_object_manager_find_proxy (priv->ports_om, bound_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* wp_node_iterate_ports:
|
||||
* @self: the node
|
||||
*
|
||||
* Requires %WP_NODE_FEATURE_PORTS
|
||||
*
|
||||
* Returns: (transfer full): a #WpIterator that iterates over all
|
||||
* the ports that belong to this node
|
||||
*/
|
||||
WpIterator *
|
||||
wp_node_iterate_ports (WpNode * self)
|
||||
{
|
||||
g_return_val_if_fail (WP_IS_NODE (self), NULL);
|
||||
g_return_val_if_fail (wp_proxy_get_features (WP_PROXY (self)) &
|
||||
WP_NODE_FEATURE_PORTS, NULL);
|
||||
|
||||
WpNodePrivate *priv = wp_node_get_instance_private (self);
|
||||
return wp_object_manager_iterate (priv->ports_om);
|
||||
}
|
||||
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_PW_IMPL_NODE,
|
||||
|
|
@ -296,6 +507,18 @@ wp_impl_node_augment (WpProxy * proxy, WpProxyFeatures features)
|
|||
wp_proxy_set_pw_proxy (proxy, pw_core_export (pw_core,
|
||||
PW_TYPE_INTERFACE_Node, NULL, self->pw_impl_node, 0));
|
||||
}
|
||||
|
||||
if (features & WP_NODE_FEATURE_PORTS) {
|
||||
WpNodePrivate *priv = wp_node_get_instance_private (WP_NODE (self));
|
||||
priv->ports_om = wp_object_manager_new ();
|
||||
|
||||
/* if we are already bound, enable right away;
|
||||
else, continue in the bound() event */
|
||||
if (wp_proxy_get_features (proxy) & WP_PROXY_FEATURE_BOUND) {
|
||||
wp_node_enable_feature_ports (WP_NODE (self),
|
||||
wp_proxy_get_bound_id (proxy));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -10,11 +10,51 @@
|
|||
#define __WIREPLUMBER_NODE_H__
|
||||
|
||||
#include "proxy.h"
|
||||
#include "port.h"
|
||||
#include "iterator.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
struct pw_impl_node;
|
||||
|
||||
/**
|
||||
* WpNodeState:
|
||||
* @WP_NODE_STATE_ERROR: error state
|
||||
* @WP_NODE_STATE_CREATING: the node is being created
|
||||
* @WP_NODE_STATE_SUSPENDED: the node is suspended, the device might be closed
|
||||
* @WP_NODE_STATE_IDLE: the node is running but there is no active port
|
||||
* @WP_NODE_STATE_RUNNING: the node is running
|
||||
*/
|
||||
typedef enum {
|
||||
WP_NODE_STATE_ERROR = -1,
|
||||
WP_NODE_STATE_CREATING = 0,
|
||||
WP_NODE_STATE_SUSPENDED = 1,
|
||||
WP_NODE_STATE_IDLE = 2,
|
||||
WP_NODE_STATE_RUNNING = 3,
|
||||
} WpNodeState;
|
||||
|
||||
/**
|
||||
* WpNodeFeatures:
|
||||
* @WP_NODE_FEATURE_PORTS: caches information about ports, enabling
|
||||
* the use of wp_node_get_n_ports(), wp_node_find_port() and
|
||||
* wp_node_iterate_ports()
|
||||
*
|
||||
* An extension of #WpProxyFeatures
|
||||
*/
|
||||
typedef enum { /*< flags >*/
|
||||
WP_NODE_FEATURE_PORTS = WP_PROXY_FEATURE_LAST,
|
||||
} WpNodeFeatures;
|
||||
|
||||
/**
|
||||
* WP_NODE_FEATURES_STANDARD:
|
||||
*
|
||||
* A constant set of features that contains the standard features that are
|
||||
* available in the #WpNode class.
|
||||
*/
|
||||
#define WP_NODE_FEATURES_STANDARD \
|
||||
(WP_PROXY_FEATURES_STANDARD | \
|
||||
WP_NODE_FEATURE_PORTS)
|
||||
|
||||
/**
|
||||
* WP_TYPE_NODE:
|
||||
*
|
||||
|
|
@ -33,6 +73,24 @@ WP_API
|
|||
WpNode * wp_node_new_from_factory (WpCore * core,
|
||||
const gchar * factory_name, WpProperties * properties);
|
||||
|
||||
WP_API
|
||||
WpNodeState wp_node_get_state (WpNode * self, const gchar ** error);
|
||||
|
||||
WP_API
|
||||
guint wp_node_get_n_input_ports (WpNode * self, guint * max);
|
||||
|
||||
WP_API
|
||||
guint wp_node_get_n_output_ports (WpNode * self, guint * max);
|
||||
|
||||
WP_API
|
||||
guint wp_node_get_n_ports (WpNode * self);
|
||||
|
||||
WP_API
|
||||
WpPort * wp_node_find_port (WpNode * self, guint32 bound_id);
|
||||
|
||||
WP_API
|
||||
WpIterator * wp_node_iterate_ports (WpNode * self);
|
||||
|
||||
/**
|
||||
* WP_TYPE_IMPL_NODE:
|
||||
*
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue