lib/wp: merge both WpRemote & WpRemotePipewire in WpCore
In practice we always create a remote and connect to pipewire. Any other scenario is invalid, therefore, it is not justified to be confused with so many classes for such small functionality. This simplifies a lot the modules code. Also, this commit exposes the pw_core and pw_remote objects out of WpCore. This is in practice useful when dealing with low-level pw and spa factories, which are used in the monitors. Let's not add API wrappers for everything... Bindings will never use this functionality anyway, since it depends on low level pipewire C API.
This commit is contained in:
416
lib/wp/core.c
416
lib/wp/core.c
@@ -7,14 +7,95 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
|
#include "proxy.h"
|
||||||
|
#include "wpenums.h"
|
||||||
|
|
||||||
enum {
|
#include <pipewire/pipewire.h>
|
||||||
SIGNAL_GLOBAL_ADDED,
|
|
||||||
SIGNAL_GLOBAL_REMOVED,
|
/*
|
||||||
NUM_SIGNALS
|
* Integration between the PipeWire main loop and GMainLoop
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define WP_LOOP_SOURCE(x) ((WpLoopSource *) x)
|
||||||
|
|
||||||
|
typedef struct _WpLoopSource WpLoopSource;
|
||||||
|
struct _WpLoopSource
|
||||||
|
{
|
||||||
|
GSource parent;
|
||||||
|
struct pw_loop *loop;
|
||||||
};
|
};
|
||||||
|
|
||||||
static guint32 signals[NUM_SIGNALS];
|
static gboolean
|
||||||
|
wp_loop_source_dispatch (GSource * s, GSourceFunc callback, gpointer user_data)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
pw_loop_enter (WP_LOOP_SOURCE(s)->loop);
|
||||||
|
result = pw_loop_iterate (WP_LOOP_SOURCE(s)->loop, 0);
|
||||||
|
pw_loop_leave (WP_LOOP_SOURCE(s)->loop);
|
||||||
|
|
||||||
|
if (G_UNLIKELY (result < 0))
|
||||||
|
g_warning ("pw_loop_iterate failed: %s", spa_strerror (result));
|
||||||
|
|
||||||
|
return G_SOURCE_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
wp_loop_source_finalize (GSource * s)
|
||||||
|
{
|
||||||
|
pw_loop_destroy (WP_LOOP_SOURCE(s)->loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GSourceFuncs source_funcs = {
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
wp_loop_source_dispatch,
|
||||||
|
wp_loop_source_finalize
|
||||||
|
};
|
||||||
|
|
||||||
|
static GSource *
|
||||||
|
wp_loop_source_new (void)
|
||||||
|
{
|
||||||
|
GSource *s = g_source_new (&source_funcs, sizeof (WpLoopSource));
|
||||||
|
WP_LOOP_SOURCE(s)->loop = pw_loop_new (NULL);
|
||||||
|
|
||||||
|
g_source_add_unix_fd (s,
|
||||||
|
pw_loop_get_fd (WP_LOOP_SOURCE(s)->loop),
|
||||||
|
G_IO_IN | G_IO_ERR | G_IO_HUP);
|
||||||
|
|
||||||
|
return (GSource *) s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WpCore
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct _WpCore
|
||||||
|
{
|
||||||
|
GObject parent;
|
||||||
|
|
||||||
|
/* main loop integration */
|
||||||
|
GMainContext *context;
|
||||||
|
|
||||||
|
/* pipewire main objects */
|
||||||
|
struct pw_core *pw_core;
|
||||||
|
struct pw_remote *pw_remote;
|
||||||
|
struct spa_hook remote_listener;
|
||||||
|
|
||||||
|
/* remote core */
|
||||||
|
struct pw_core_proxy *core_proxy;
|
||||||
|
|
||||||
|
/* remote registry */
|
||||||
|
struct pw_registry_proxy *registry_proxy;
|
||||||
|
struct spa_hook registry_listener;
|
||||||
|
|
||||||
|
/* local proxies */
|
||||||
|
GHashTable *proxies;
|
||||||
|
GHashTable *default_features;
|
||||||
|
|
||||||
|
/* local global objects */
|
||||||
|
GPtrArray *global_objects;
|
||||||
|
};
|
||||||
|
|
||||||
struct global_object
|
struct global_object
|
||||||
{
|
{
|
||||||
@@ -23,14 +104,121 @@ struct global_object
|
|||||||
GDestroyNotify destroy;
|
GDestroyNotify destroy;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _WpCore
|
enum {
|
||||||
{
|
PROP_0,
|
||||||
GObject parent;
|
PROP_CONTEXT,
|
||||||
GPtrArray *global_objects;
|
PROP_PW_CORE,
|
||||||
|
PROP_PW_REMOTE,
|
||||||
|
PROP_REMOTE_STATE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
SIGNAL_REMOTE_STATE_CHANGED,
|
||||||
|
SIGNAL_GLOBAL_ADDED,
|
||||||
|
SIGNAL_GLOBAL_REMOVED,
|
||||||
|
SIGNAL_REMOTE_GLOBAL_ADDED,
|
||||||
|
SIGNAL_REMOTE_GLOBAL_REMOVED,
|
||||||
|
NUM_SIGNALS
|
||||||
|
};
|
||||||
|
|
||||||
|
static guint32 signals[NUM_SIGNALS];
|
||||||
|
|
||||||
G_DEFINE_TYPE (WpCore, wp_core, G_TYPE_OBJECT)
|
G_DEFINE_TYPE (WpCore, wp_core, G_TYPE_OBJECT)
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_proxy_ready (GObject * obj, GAsyncResult * res, gpointer data)
|
||||||
|
{
|
||||||
|
WpCore *self = WP_CORE (data);
|
||||||
|
WpProxy *proxy = WP_PROXY (obj);
|
||||||
|
g_autoptr (GError) error = NULL;
|
||||||
|
|
||||||
|
if (!wp_proxy_augment_finish (proxy, res, &error)) {
|
||||||
|
g_warning ("Failed to augment WpProxy (%p): %s", obj, error->message);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_signal_emit (self, signals[SIGNAL_REMOTE_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)
|
||||||
|
{
|
||||||
|
WpCore *self = WP_CORE (data);
|
||||||
|
WpProxy *proxy;
|
||||||
|
WpProxyFeatures features;
|
||||||
|
g_autoptr (WpProperties) properties = wp_properties_new_copy_dict (props);
|
||||||
|
|
||||||
|
/* construct & store WpProxy */
|
||||||
|
proxy = wp_proxy_new_global (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)
|
||||||
|
{
|
||||||
|
WpCore *self = WP_CORE (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_REMOTE_GLOBAL_REMOVED],
|
||||||
|
wp_proxy_get_interface_quark (proxy), proxy);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct pw_registry_proxy_events registry_proxy_events = {
|
||||||
|
PW_VERSION_REGISTRY_PROXY_EVENTS,
|
||||||
|
.global = registry_global,
|
||||||
|
.global_remove = registry_global_remove,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
registry_init (WpCore *self)
|
||||||
|
{
|
||||||
|
/* Get the core proxy */
|
||||||
|
self->core_proxy = pw_remote_get_core_proxy (self->pw_remote);
|
||||||
|
|
||||||
|
/* Registry */
|
||||||
|
self->registry_proxy = pw_core_proxy_get_registry (self->core_proxy,
|
||||||
|
PW_VERSION_REGISTRY_PROXY, 0);
|
||||||
|
pw_registry_proxy_add_listener(self->registry_proxy, &self->registry_listener,
|
||||||
|
®istry_proxy_events, self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_remote_state_changed (void *d, enum pw_remote_state old_state,
|
||||||
|
enum pw_remote_state new_state, const char *error)
|
||||||
|
{
|
||||||
|
WpCore *self = d;
|
||||||
|
GQuark detail;
|
||||||
|
|
||||||
|
g_debug ("pipewire remote state changed, old:%s new:%s",
|
||||||
|
pw_remote_state_as_string (old_state),
|
||||||
|
pw_remote_state_as_string (new_state));
|
||||||
|
|
||||||
|
/* Init the registry when connected */
|
||||||
|
if (!self->registry_proxy && new_state == PW_REMOTE_STATE_CONNECTED)
|
||||||
|
registry_init (self);
|
||||||
|
|
||||||
|
/* enum pw_remote_state matches values with WpRemoteState */
|
||||||
|
detail = g_quark_from_static_string (pw_remote_state_as_string (new_state));
|
||||||
|
g_signal_emit (self, signals[SIGNAL_REMOTE_STATE_CHANGED], detail, new_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct pw_remote_events remote_events = {
|
||||||
|
PW_VERSION_REMOTE_EVENTS,
|
||||||
|
.state_changed = on_remote_state_changed,
|
||||||
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
free_global_object (gpointer p)
|
free_global_object (gpointer p)
|
||||||
{
|
{
|
||||||
@@ -46,9 +234,29 @@ free_global_object (gpointer p)
|
|||||||
static void
|
static void
|
||||||
wp_core_init (WpCore * self)
|
wp_core_init (WpCore * 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);
|
||||||
self->global_objects = g_ptr_array_new_with_free_func (free_global_object);
|
self->global_objects = g_ptr_array_new_with_free_func (free_global_object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
wp_core_constructed (GObject *object)
|
||||||
|
{
|
||||||
|
WpCore *self = WP_CORE (object);
|
||||||
|
g_autoptr (GSource) source = NULL;
|
||||||
|
|
||||||
|
source = wp_loop_source_new ();
|
||||||
|
g_source_attach (source, self->context);
|
||||||
|
|
||||||
|
self->pw_core = pw_core_new (WP_LOOP_SOURCE (source)->loop, NULL, 0);
|
||||||
|
self->pw_remote = pw_remote_new (self->pw_core, NULL, 0);
|
||||||
|
pw_remote_add_listener (self->pw_remote, &self->remote_listener,
|
||||||
|
&remote_events, self);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (wp_core_parent_class)->constructed (object);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
wp_core_dispose (GObject * obj)
|
wp_core_dispose (GObject * obj)
|
||||||
{
|
{
|
||||||
@@ -73,18 +281,98 @@ wp_core_dispose (GObject * obj)
|
|||||||
static void
|
static void
|
||||||
wp_core_finalize (GObject * obj)
|
wp_core_finalize (GObject * obj)
|
||||||
{
|
{
|
||||||
|
WpCore *self = WP_CORE (obj);
|
||||||
|
|
||||||
|
g_clear_pointer (&self->proxies, g_hash_table_unref);
|
||||||
|
g_clear_pointer (&self->default_features, g_hash_table_unref);
|
||||||
|
g_clear_pointer (&self->pw_remote, pw_remote_destroy);
|
||||||
|
self->core_proxy= NULL;
|
||||||
|
self->registry_proxy = NULL;
|
||||||
|
g_clear_pointer (&self->pw_core, pw_core_destroy);
|
||||||
|
g_clear_pointer (&self->context, g_main_context_unref);
|
||||||
|
|
||||||
g_debug ("WpCore destroyed");
|
g_debug ("WpCore destroyed");
|
||||||
|
|
||||||
G_OBJECT_CLASS (wp_core_parent_class)->finalize (obj);
|
G_OBJECT_CLASS (wp_core_parent_class)->finalize (obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
wp_core_get_property (GObject * object, guint property_id,
|
||||||
|
GValue * value, GParamSpec * pspec)
|
||||||
|
{
|
||||||
|
WpCore *self = WP_CORE (object);
|
||||||
|
|
||||||
|
switch (property_id) {
|
||||||
|
case PROP_CONTEXT:
|
||||||
|
g_value_set_boxed (value, self->context);
|
||||||
|
break;
|
||||||
|
case PROP_PW_CORE:
|
||||||
|
g_value_set_pointer (value, self->pw_core);
|
||||||
|
break;
|
||||||
|
case PROP_PW_REMOTE:
|
||||||
|
g_value_set_pointer (value, self->pw_remote);
|
||||||
|
break;
|
||||||
|
case PROP_REMOTE_STATE:
|
||||||
|
g_value_set_enum (value, wp_core_get_remote_state (self, NULL));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
wp_core_set_property (GObject * object, guint property_id,
|
||||||
|
const GValue * value, GParamSpec * pspec)
|
||||||
|
{
|
||||||
|
WpCore *self = WP_CORE (object);
|
||||||
|
|
||||||
|
switch (property_id) {
|
||||||
|
case PROP_CONTEXT:
|
||||||
|
self->context = g_value_dup_boxed (value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
wp_core_class_init (WpCoreClass * klass)
|
wp_core_class_init (WpCoreClass * klass)
|
||||||
{
|
{
|
||||||
GObjectClass *object_class = (GObjectClass *) klass;
|
GObjectClass *object_class = (GObjectClass *) klass;
|
||||||
|
|
||||||
|
pw_init (NULL, NULL);
|
||||||
|
|
||||||
|
object_class->constructed = wp_core_constructed;
|
||||||
object_class->dispose = wp_core_dispose;
|
object_class->dispose = wp_core_dispose;
|
||||||
object_class->finalize = wp_core_finalize;
|
object_class->finalize = wp_core_finalize;
|
||||||
|
object_class->get_property = wp_core_get_property;
|
||||||
|
object_class->set_property = wp_core_set_property;
|
||||||
|
|
||||||
|
g_object_class_install_property (object_class, PROP_CONTEXT,
|
||||||
|
g_param_spec_boxed ("context", "context", "A GMainContext to attach to",
|
||||||
|
G_TYPE_MAIN_CONTEXT,
|
||||||
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
|
g_object_class_install_property (object_class, PROP_PW_CORE,
|
||||||
|
g_param_spec_pointer ("pw-core", "pw-core", "The pipewire core",
|
||||||
|
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
|
g_object_class_install_property (object_class, PROP_PW_REMOTE,
|
||||||
|
g_param_spec_pointer ("pw-remote", "pw-remote", "The pipewire remote",
|
||||||
|
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
|
g_object_class_install_property (object_class, PROP_REMOTE_STATE,
|
||||||
|
g_param_spec_enum ("remote-state", "remote-state",
|
||||||
|
"The state of the remote",
|
||||||
|
WP_TYPE_REMOTE_STATE, WP_REMOTE_STATE_UNCONNECTED,
|
||||||
|
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
|
/* Signals */
|
||||||
|
signals[SIGNAL_REMOTE_STATE_CHANGED] = g_signal_new ("remote-state-changed",
|
||||||
|
G_TYPE_FROM_CLASS (klass), G_SIGNAL_DETAILED | G_SIGNAL_RUN_LAST,
|
||||||
|
0, NULL, NULL, NULL, G_TYPE_NONE, 1, WP_TYPE_REMOTE_STATE);
|
||||||
|
|
||||||
signals[SIGNAL_GLOBAL_ADDED] = g_signal_new ("global-added",
|
signals[SIGNAL_GLOBAL_ADDED] = g_signal_new ("global-added",
|
||||||
G_TYPE_FROM_CLASS (klass), G_SIGNAL_DETAILED | G_SIGNAL_RUN_LAST, 0, NULL,
|
G_TYPE_FROM_CLASS (klass), G_SIGNAL_DETAILED | G_SIGNAL_RUN_LAST, 0, NULL,
|
||||||
@@ -93,12 +381,117 @@ wp_core_class_init (WpCoreClass * klass)
|
|||||||
signals[SIGNAL_GLOBAL_REMOVED] = g_signal_new ("global-removed",
|
signals[SIGNAL_GLOBAL_REMOVED] = g_signal_new ("global-removed",
|
||||||
G_TYPE_FROM_CLASS (klass), G_SIGNAL_DETAILED | G_SIGNAL_RUN_LAST, 0, NULL,
|
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);
|
NULL, NULL, G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_POINTER);
|
||||||
|
|
||||||
|
signals[SIGNAL_REMOTE_GLOBAL_ADDED] = g_signal_new ("remote-global-added",
|
||||||
|
G_TYPE_FROM_CLASS (klass), G_SIGNAL_DETAILED | G_SIGNAL_RUN_LAST,
|
||||||
|
0, NULL, NULL, NULL, G_TYPE_NONE, 1, WP_TYPE_PROXY);
|
||||||
|
|
||||||
|
signals[SIGNAL_REMOTE_GLOBAL_REMOVED] = g_signal_new ("remote-global-removed",
|
||||||
|
G_TYPE_FROM_CLASS (klass), G_SIGNAL_DETAILED | G_SIGNAL_RUN_LAST,
|
||||||
|
0, NULL, NULL, NULL, G_TYPE_NONE, 1, WP_TYPE_PROXY);
|
||||||
}
|
}
|
||||||
|
|
||||||
WpCore *
|
WpCore *
|
||||||
wp_core_new (void)
|
wp_core_new (GMainContext *context)
|
||||||
{
|
{
|
||||||
return g_object_new (WP_TYPE_CORE, NULL);
|
return g_object_new (WP_TYPE_CORE, "context", context, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
GMainContext *
|
||||||
|
wp_core_get_context (WpCore * self)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (WP_IS_CORE (self), NULL);
|
||||||
|
return self->context;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct pw_core *
|
||||||
|
wp_core_get_pw_core (WpCore * self)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (WP_IS_CORE (self), NULL);
|
||||||
|
return self->pw_core;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct pw_remote *
|
||||||
|
wp_core_get_pw_remote (WpCore * self)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (WP_IS_CORE (self), NULL);
|
||||||
|
return self->pw_remote;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
connect_in_idle (WpCore *self)
|
||||||
|
{
|
||||||
|
pw_remote_connect (self->pw_remote);
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
wp_core_connect (WpCore *self)
|
||||||
|
{
|
||||||
|
g_autoptr (GSource) source = NULL;
|
||||||
|
|
||||||
|
g_return_val_if_fail (WP_IS_CORE (self), FALSE);
|
||||||
|
|
||||||
|
source = g_idle_source_new ();
|
||||||
|
g_source_set_callback (source, (GSourceFunc) connect_in_idle, self, NULL);
|
||||||
|
g_source_attach (source, self->context);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
WpRemoteState
|
||||||
|
wp_core_get_remote_state (WpCore * self, const gchar ** error)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (WP_IS_CORE (self), WP_REMOTE_STATE_UNCONNECTED);
|
||||||
|
|
||||||
|
/* enum pw_remote_state matches values with WpRemoteState */
|
||||||
|
G_STATIC_ASSERT ((gint) WP_REMOTE_STATE_ERROR == (gint) PW_REMOTE_STATE_ERROR);
|
||||||
|
G_STATIC_ASSERT ((gint) WP_REMOTE_STATE_UNCONNECTED == (gint) PW_REMOTE_STATE_UNCONNECTED);
|
||||||
|
G_STATIC_ASSERT ((gint) WP_REMOTE_STATE_CONNECTING == (gint) PW_REMOTE_STATE_CONNECTING);
|
||||||
|
G_STATIC_ASSERT ((gint) WP_REMOTE_STATE_CONNECTED == (gint) PW_REMOTE_STATE_CONNECTED);
|
||||||
|
|
||||||
|
return (WpRemoteState) pw_remote_get_state (self->pw_remote, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
wp_core_set_default_proxy_features (WpCore * self,
|
||||||
|
GType proxy_type, WpProxyFeatures features)
|
||||||
|
{
|
||||||
|
g_return_if_fail (WP_IS_CORE (self));
|
||||||
|
|
||||||
|
g_hash_table_insert (self->default_features, GUINT_TO_POINTER (proxy_type),
|
||||||
|
GUINT_TO_POINTER (features));
|
||||||
|
}
|
||||||
|
|
||||||
|
WpProxy *
|
||||||
|
wp_core_create_remote_object (WpCore *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_CORE (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,
|
||||||
|
properties ? wp_properties_peek_dict (properties) : NULL, 0);
|
||||||
|
return wp_proxy_new_wrap (self, pw_proxy, interface_type,
|
||||||
|
interface_version);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct pw_core_proxy *
|
||||||
|
wp_core_get_pw_core_proxy (WpCore * self)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (WP_IS_CORE (self), NULL);
|
||||||
|
return self->core_proxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct pw_registry_proxy *
|
||||||
|
wp_core_get_pw_registry_proxy (WpCore * self)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (WP_IS_CORE (self), NULL);
|
||||||
|
return self->registry_proxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -229,4 +622,3 @@ G_DEFINE_QUARK (endpoint, wp_global_endpoint)
|
|||||||
G_DEFINE_QUARK (factory, wp_global_factory)
|
G_DEFINE_QUARK (factory, wp_global_factory)
|
||||||
G_DEFINE_QUARK (module, wp_global_module)
|
G_DEFINE_QUARK (module, wp_global_module)
|
||||||
G_DEFINE_QUARK (policy-manager, wp_global_policy_manager)
|
G_DEFINE_QUARK (policy-manager, wp_global_policy_manager)
|
||||||
G_DEFINE_QUARK (remote-pipewire, wp_global_remote_pipewire)
|
|
||||||
|
@@ -10,12 +10,57 @@
|
|||||||
#define __WIREPLUMBER_CORE_H__
|
#define __WIREPLUMBER_CORE_H__
|
||||||
|
|
||||||
#include <glib-object.h>
|
#include <glib-object.h>
|
||||||
|
#include "proxy.h"
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
struct pw_core;
|
||||||
|
struct pw_remote;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WpRemoteState:
|
||||||
|
* @WP_REMOTE_STATE_ERROR: remote is in error
|
||||||
|
* @WP_REMOTE_STATE_UNCONNECTED: not connected
|
||||||
|
* @WP_REMOTE_STATE_CONNECTING: connecting to remote service
|
||||||
|
* @WP_REMOTE_STATE_CONNECTED: remote is connected and ready
|
||||||
|
*
|
||||||
|
* The different states the remote can be
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
WP_REMOTE_STATE_ERROR = -1,
|
||||||
|
WP_REMOTE_STATE_UNCONNECTED = 0,
|
||||||
|
WP_REMOTE_STATE_CONNECTING = 1,
|
||||||
|
WP_REMOTE_STATE_CONNECTED = 2,
|
||||||
|
} WpRemoteState;
|
||||||
|
|
||||||
#define WP_TYPE_CORE (wp_core_get_type ())
|
#define WP_TYPE_CORE (wp_core_get_type ())
|
||||||
G_DECLARE_FINAL_TYPE (WpCore, wp_core, WP, CORE, GObject)
|
G_DECLARE_FINAL_TYPE (WpCore, wp_core, WP, CORE, GObject)
|
||||||
|
|
||||||
|
WpCore * wp_core_new (GMainContext *context);
|
||||||
|
|
||||||
|
GMainContext * wp_core_get_context (WpCore * self);
|
||||||
|
struct pw_core * wp_core_get_pw_core (WpCore * self);
|
||||||
|
struct pw_remote * wp_core_get_pw_remote (WpCore * self);
|
||||||
|
|
||||||
|
gboolean wp_core_connect (WpCore * self);
|
||||||
|
WpRemoteState wp_core_get_remote_state (WpCore * self, const gchar ** error);
|
||||||
|
|
||||||
|
void wp_core_set_default_proxy_features (
|
||||||
|
WpCore * self, GType proxy_type, WpProxyFeatures features);
|
||||||
|
|
||||||
|
WpProxy * wp_core_create_remote_object (WpCore * self,
|
||||||
|
const gchar * factory_name, guint32 interface_type,
|
||||||
|
guint32 interface_version, WpProperties * properties);
|
||||||
|
|
||||||
|
|
||||||
|
/* private */
|
||||||
|
|
||||||
|
struct pw_core_proxy;
|
||||||
|
struct pw_registry_proxy;
|
||||||
|
|
||||||
|
struct pw_core_proxy * wp_core_get_pw_core_proxy (WpCore * self);
|
||||||
|
struct pw_registry_proxy * wp_core_get_pw_registry_proxy (WpCore * self);
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
WP_CORE_FOREACH_GLOBAL_DONE = FALSE,
|
WP_CORE_FOREACH_GLOBAL_DONE = FALSE,
|
||||||
WP_CORE_FOREACH_GLOBAL_CONTINUE = TRUE,
|
WP_CORE_FOREACH_GLOBAL_CONTINUE = TRUE,
|
||||||
@@ -24,8 +69,6 @@ enum {
|
|||||||
typedef gboolean (*WpCoreForeachGlobalFunc) (GQuark key, gpointer global,
|
typedef gboolean (*WpCoreForeachGlobalFunc) (GQuark key, gpointer global,
|
||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
|
|
||||||
WpCore * wp_core_new (void);
|
|
||||||
|
|
||||||
gpointer wp_core_get_global (WpCore * self, GQuark key);
|
gpointer wp_core_get_global (WpCore * self, GQuark key);
|
||||||
void wp_core_foreach_global (WpCore * self, WpCoreForeachGlobalFunc callback,
|
void wp_core_foreach_global (WpCore * self, WpCoreForeachGlobalFunc callback,
|
||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
@@ -46,14 +89,6 @@ GQuark wp_global_module_quark (void);
|
|||||||
#define WP_GLOBAL_POLICY_MANAGER (wp_global_policy_manager_quark ())
|
#define WP_GLOBAL_POLICY_MANAGER (wp_global_policy_manager_quark ())
|
||||||
GQuark wp_global_policy_manager_quark (void);
|
GQuark wp_global_policy_manager_quark (void);
|
||||||
|
|
||||||
/**
|
|
||||||
* WP_GLOBAL_REMOTE_PIPEWIRE:
|
|
||||||
* The key to access the #WpRemote global object that maintains
|
|
||||||
* the connection to pipewire
|
|
||||||
*/
|
|
||||||
#define WP_GLOBAL_REMOTE_PIPEWIRE (wp_global_remote_pipewire_quark ())
|
|
||||||
GQuark wp_global_remote_pipewire_quark (void);
|
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -11,8 +11,6 @@ wp_lib_sources = [
|
|||||||
'proxy-link.c',
|
'proxy-link.c',
|
||||||
'proxy-node.c',
|
'proxy-node.c',
|
||||||
'proxy-port.c',
|
'proxy-port.c',
|
||||||
'remote.c',
|
|
||||||
'remote-pipewire.c',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
wp_lib_headers = [
|
wp_lib_headers = [
|
||||||
@@ -28,8 +26,6 @@ wp_lib_headers = [
|
|||||||
'proxy-node.h',
|
'proxy-node.h',
|
||||||
'proxy-port.h',
|
'proxy-port.h',
|
||||||
'proxy-link.h',
|
'proxy-link.h',
|
||||||
'remote.h',
|
|
||||||
'remote-pipewire.h',
|
|
||||||
'wp.h',
|
'wp.h',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@@ -8,8 +8,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "proxy.h"
|
#include "proxy.h"
|
||||||
|
#include "core.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "remote-pipewire.h"
|
|
||||||
#include "wpenums.h"
|
#include "wpenums.h"
|
||||||
|
|
||||||
#include "proxy-client.h"
|
#include "proxy-client.h"
|
||||||
@@ -24,7 +24,7 @@ typedef struct _WpProxyPrivate WpProxyPrivate;
|
|||||||
struct _WpProxyPrivate
|
struct _WpProxyPrivate
|
||||||
{
|
{
|
||||||
/* properties */
|
/* properties */
|
||||||
GWeakRef remote;
|
GWeakRef core;
|
||||||
|
|
||||||
guint32 global_id;
|
guint32 global_id;
|
||||||
guint32 global_perm;
|
guint32 global_perm;
|
||||||
@@ -48,7 +48,7 @@ struct _WpProxyPrivate
|
|||||||
|
|
||||||
enum {
|
enum {
|
||||||
PROP_0,
|
PROP_0,
|
||||||
PROP_REMOTE,
|
PROP_CORE,
|
||||||
PROP_GLOBAL_ID,
|
PROP_GLOBAL_ID,
|
||||||
PROP_GLOBAL_PERMISSIONS,
|
PROP_GLOBAL_PERMISSIONS,
|
||||||
PROP_GLOBAL_PROPERTIES,
|
PROP_GLOBAL_PROPERTIES,
|
||||||
@@ -194,7 +194,7 @@ wp_proxy_init (WpProxy * self)
|
|||||||
{
|
{
|
||||||
WpProxyPrivate *priv = wp_proxy_get_instance_private (self);
|
WpProxyPrivate *priv = wp_proxy_get_instance_private (self);
|
||||||
|
|
||||||
g_weak_ref_init (&priv->remote, NULL);
|
g_weak_ref_init (&priv->core, NULL);
|
||||||
priv->async_tasks = g_hash_table_new_full (g_direct_hash, g_direct_equal,
|
priv->async_tasks = g_hash_table_new_full (g_direct_hash, g_direct_equal,
|
||||||
NULL, g_object_unref);
|
NULL, g_object_unref);
|
||||||
}
|
}
|
||||||
@@ -221,7 +221,7 @@ wp_proxy_finalize (GObject * object)
|
|||||||
g_clear_object (&priv->task);
|
g_clear_object (&priv->task);
|
||||||
g_clear_pointer (&priv->global_props, wp_properties_unref);
|
g_clear_pointer (&priv->global_props, wp_properties_unref);
|
||||||
g_clear_pointer (&priv->pw_proxy, pw_proxy_destroy);
|
g_clear_pointer (&priv->pw_proxy, pw_proxy_destroy);
|
||||||
g_weak_ref_clear (&priv->remote);
|
g_weak_ref_clear (&priv->core);
|
||||||
g_clear_pointer (&priv->async_tasks, g_hash_table_unref);
|
g_clear_pointer (&priv->async_tasks, g_hash_table_unref);
|
||||||
|
|
||||||
G_OBJECT_CLASS (wp_proxy_parent_class)->finalize (object);
|
G_OBJECT_CLASS (wp_proxy_parent_class)->finalize (object);
|
||||||
@@ -234,8 +234,8 @@ wp_proxy_set_property (GObject * object, guint property_id,
|
|||||||
WpProxyPrivate *priv = wp_proxy_get_instance_private (WP_PROXY(object));
|
WpProxyPrivate *priv = wp_proxy_get_instance_private (WP_PROXY(object));
|
||||||
|
|
||||||
switch (property_id) {
|
switch (property_id) {
|
||||||
case PROP_REMOTE:
|
case PROP_CORE:
|
||||||
g_weak_ref_set (&priv->remote, g_value_get_object (value));
|
g_weak_ref_set (&priv->core, g_value_get_object (value));
|
||||||
break;
|
break;
|
||||||
case PROP_GLOBAL_ID:
|
case PROP_GLOBAL_ID:
|
||||||
priv->global_id = g_value_get_uint (value);
|
priv->global_id = g_value_get_uint (value);
|
||||||
@@ -268,8 +268,8 @@ wp_proxy_get_property (GObject * object, guint property_id, GValue * value,
|
|||||||
WpProxyPrivate *priv = wp_proxy_get_instance_private (WP_PROXY(object));
|
WpProxyPrivate *priv = wp_proxy_get_instance_private (WP_PROXY(object));
|
||||||
|
|
||||||
switch (property_id) {
|
switch (property_id) {
|
||||||
case PROP_REMOTE:
|
case PROP_CORE:
|
||||||
g_value_take_object (value, g_weak_ref_get (&priv->remote));
|
g_value_take_object (value, g_weak_ref_get (&priv->core));
|
||||||
break;
|
break;
|
||||||
case PROP_GLOBAL_ID:
|
case PROP_GLOBAL_ID:
|
||||||
g_value_set_uint (value, priv->global_id);
|
g_value_set_uint (value, priv->global_id);
|
||||||
@@ -309,7 +309,7 @@ static void
|
|||||||
wp_proxy_default_augment (WpProxy * self, WpProxyFeatures features)
|
wp_proxy_default_augment (WpProxy * self, WpProxyFeatures features)
|
||||||
{
|
{
|
||||||
WpProxyPrivate *priv = wp_proxy_get_instance_private (self);
|
WpProxyPrivate *priv = wp_proxy_get_instance_private (self);
|
||||||
g_autoptr (WpRemote) remote = NULL;
|
g_autoptr (WpCore) core = NULL;
|
||||||
|
|
||||||
/* ensure we have a pw_proxy, as we can't have
|
/* ensure we have a pw_proxy, as we can't have
|
||||||
* any other feature without first having that */
|
* any other feature without first having that */
|
||||||
@@ -327,13 +327,13 @@ wp_proxy_default_augment (WpProxy * self, WpProxyFeatures features)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
remote = g_weak_ref_get (&priv->remote);
|
core = g_weak_ref_get (&priv->core);
|
||||||
g_return_if_fail (remote);
|
g_return_if_fail (core);
|
||||||
|
|
||||||
/* bind */
|
/* bind */
|
||||||
priv->pw_proxy = wp_remote_pipewire_proxy_bind (
|
priv->pw_proxy = pw_registry_proxy_bind (
|
||||||
WP_REMOTE_PIPEWIRE (remote),
|
wp_core_get_pw_registry_proxy (core), priv->global_id,
|
||||||
priv->global_id, priv->iface_type);
|
priv->iface_type, priv->iface_version, 0);
|
||||||
wp_proxy_got_pw_proxy (self);
|
wp_proxy_got_pw_proxy (self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -352,9 +352,8 @@ wp_proxy_class_init (WpProxyClass * klass)
|
|||||||
|
|
||||||
/* Install the properties */
|
/* Install the properties */
|
||||||
|
|
||||||
g_object_class_install_property (object_class, PROP_REMOTE,
|
g_object_class_install_property (object_class, PROP_CORE,
|
||||||
g_param_spec_object ("remote", "remote",
|
g_param_spec_object ("core", "core", "The WpCore", WP_TYPE_CORE,
|
||||||
"The pipewire connection WpRemote", WP_TYPE_REMOTE,
|
|
||||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
g_object_class_install_property (object_class, PROP_GLOBAL_ID,
|
g_object_class_install_property (object_class, PROP_GLOBAL_ID,
|
||||||
@@ -414,13 +413,13 @@ wp_proxy_class_init (WpProxyClass * klass)
|
|||||||
}
|
}
|
||||||
|
|
||||||
WpProxy *
|
WpProxy *
|
||||||
wp_proxy_new_global (WpRemote * remote,
|
wp_proxy_new_global (WpCore * core,
|
||||||
guint32 id, guint32 permissions, WpProperties * properties,
|
guint32 id, guint32 permissions, WpProperties * properties,
|
||||||
guint32 type, guint32 version)
|
guint32 type, guint32 version)
|
||||||
{
|
{
|
||||||
GType gtype = wp_proxy_find_instance_type (type, version);
|
GType gtype = wp_proxy_find_instance_type (type, version);
|
||||||
return g_object_new (gtype,
|
return g_object_new (gtype,
|
||||||
"remote", remote,
|
"core", core,
|
||||||
"global-id", id,
|
"global-id", id,
|
||||||
"global-permissions", permissions,
|
"global-permissions", permissions,
|
||||||
"global-properties", properties,
|
"global-properties", properties,
|
||||||
@@ -430,12 +429,12 @@ wp_proxy_new_global (WpRemote * remote,
|
|||||||
}
|
}
|
||||||
|
|
||||||
WpProxy *
|
WpProxy *
|
||||||
wp_proxy_new_wrap (WpRemote * remote,
|
wp_proxy_new_wrap (WpCore * core,
|
||||||
struct pw_proxy * proxy, guint32 type, guint32 version)
|
struct pw_proxy * proxy, guint32 type, guint32 version)
|
||||||
{
|
{
|
||||||
GType gtype = wp_proxy_find_instance_type (type, version);
|
GType gtype = wp_proxy_find_instance_type (type, version);
|
||||||
return g_object_new (gtype,
|
return g_object_new (gtype,
|
||||||
"remote", remote,
|
"core", core,
|
||||||
"pw-proxy", proxy,
|
"pw-proxy", proxy,
|
||||||
"interface-type", type,
|
"interface-type", type,
|
||||||
"interface-version", version,
|
"interface-version", version,
|
||||||
@@ -544,20 +543,20 @@ wp_proxy_get_features (WpProxy * self)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* wp_proxy_get_remote:
|
* wp_proxy_get_core:
|
||||||
* @self: the proxy
|
* @self: the proxy
|
||||||
*
|
*
|
||||||
* Returns: (transfer full): the remote that created this proxy
|
* Returns: (transfer full): the core that created this proxy
|
||||||
*/
|
*/
|
||||||
WpRemote *
|
WpCore *
|
||||||
wp_proxy_get_remote (WpProxy * self)
|
wp_proxy_get_core (WpProxy * self)
|
||||||
{
|
{
|
||||||
WpProxyPrivate *priv;
|
WpProxyPrivate *priv;
|
||||||
|
|
||||||
g_return_val_if_fail (WP_IS_PROXY (self), NULL);
|
g_return_val_if_fail (WP_IS_PROXY (self), NULL);
|
||||||
|
|
||||||
priv = wp_proxy_get_instance_private (self);
|
priv = wp_proxy_get_instance_private (self);
|
||||||
return g_weak_ref_get (&priv->remote);
|
return g_weak_ref_get (&priv->core);
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
|
@@ -12,12 +12,12 @@
|
|||||||
|
|
||||||
#include <gio/gio.h>
|
#include <gio/gio.h>
|
||||||
|
|
||||||
#include "remote.h"
|
|
||||||
#include "properties.h"
|
#include "properties.h"
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
struct pw_proxy;
|
struct pw_proxy;
|
||||||
|
typedef struct _WpCore WpCore;
|
||||||
|
|
||||||
typedef enum { /*< flags >*/
|
typedef enum { /*< flags >*/
|
||||||
WP_PROXY_FEATURE_PW_PROXY = (1 << 0),
|
WP_PROXY_FEATURE_PW_PROXY = (1 << 0),
|
||||||
@@ -40,10 +40,10 @@ struct _WpProxyClass
|
|||||||
void (*pw_proxy_destroyed) (WpProxy * self);
|
void (*pw_proxy_destroyed) (WpProxy * self);
|
||||||
};
|
};
|
||||||
|
|
||||||
WpProxy * wp_proxy_new_global (WpRemote * remote,
|
WpProxy * wp_proxy_new_global (WpCore * core,
|
||||||
guint32 id, guint32 permissions, WpProperties * properties,
|
guint32 id, guint32 permissions, WpProperties * properties,
|
||||||
guint32 type, guint32 version);
|
guint32 type, guint32 version);
|
||||||
WpProxy * wp_proxy_new_wrap (WpRemote * remote,
|
WpProxy * wp_proxy_new_wrap (WpCore * core,
|
||||||
struct pw_proxy * proxy, guint32 type, guint32 version);
|
struct pw_proxy * proxy, guint32 type, guint32 version);
|
||||||
|
|
||||||
void wp_proxy_augment (WpProxy *self,
|
void wp_proxy_augment (WpProxy *self,
|
||||||
@@ -54,7 +54,7 @@ gboolean wp_proxy_augment_finish (WpProxy * self, GAsyncResult * res,
|
|||||||
|
|
||||||
WpProxyFeatures wp_proxy_get_features (WpProxy * self);
|
WpProxyFeatures wp_proxy_get_features (WpProxy * self);
|
||||||
|
|
||||||
WpRemote * wp_proxy_get_remote (WpProxy * self);
|
WpCore * wp_proxy_get_core (WpProxy * self);
|
||||||
|
|
||||||
gboolean wp_proxy_is_global (WpProxy * self);
|
gboolean wp_proxy_is_global (WpProxy * self);
|
||||||
guint32 wp_proxy_get_global_id (WpProxy * self);
|
guint32 wp_proxy_get_global_id (WpProxy * self);
|
||||||
|
@@ -1,453 +0,0 @@
|
|||||||
/* WirePlumber
|
|
||||||
*
|
|
||||||
* Copyright © 2019 Collabora Ltd.
|
|
||||||
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "remote-pipewire.h"
|
|
||||||
|
|
||||||
#include <pipewire/pipewire.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Integration between the PipeWire main loop and GMainLoop
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define WP_LOOP_SOURCE(x) ((WpLoopSource *) x)
|
|
||||||
|
|
||||||
typedef struct _WpLoopSource WpLoopSource;
|
|
||||||
struct _WpLoopSource
|
|
||||||
{
|
|
||||||
GSource parent;
|
|
||||||
struct pw_loop *loop;
|
|
||||||
};
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
wp_loop_source_dispatch (GSource * s, GSourceFunc callback, gpointer user_data)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
|
|
||||||
pw_loop_enter (WP_LOOP_SOURCE(s)->loop);
|
|
||||||
result = pw_loop_iterate (WP_LOOP_SOURCE(s)->loop, 0);
|
|
||||||
pw_loop_leave (WP_LOOP_SOURCE(s)->loop);
|
|
||||||
|
|
||||||
if (G_UNLIKELY (result < 0))
|
|
||||||
g_warning ("pw_loop_iterate failed: %s", spa_strerror (result));
|
|
||||||
|
|
||||||
return G_SOURCE_CONTINUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
wp_loop_source_finalize (GSource * s)
|
|
||||||
{
|
|
||||||
pw_loop_destroy (WP_LOOP_SOURCE(s)->loop);
|
|
||||||
}
|
|
||||||
|
|
||||||
static GSourceFuncs source_funcs = {
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
wp_loop_source_dispatch,
|
|
||||||
wp_loop_source_finalize
|
|
||||||
};
|
|
||||||
|
|
||||||
static GSource *
|
|
||||||
wp_loop_source_new (void)
|
|
||||||
{
|
|
||||||
GSource *s = g_source_new (&source_funcs, sizeof (WpLoopSource));
|
|
||||||
WP_LOOP_SOURCE(s)->loop = pw_loop_new (NULL);
|
|
||||||
|
|
||||||
g_source_add_unix_fd (s,
|
|
||||||
pw_loop_get_fd (WP_LOOP_SOURCE(s)->loop),
|
|
||||||
G_IO_IN | G_IO_ERR | G_IO_HUP);
|
|
||||||
|
|
||||||
return (GSource *) s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* WpRemotePipewire
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct _WpRemotePipewire
|
|
||||||
{
|
|
||||||
WpRemote parent;
|
|
||||||
|
|
||||||
struct pw_core *core;
|
|
||||||
struct pw_remote *remote;
|
|
||||||
struct spa_hook remote_listener;
|
|
||||||
struct pw_core_proxy *core_proxy;
|
|
||||||
|
|
||||||
/* Registry */
|
|
||||||
struct pw_registry_proxy *registry_proxy;
|
|
||||||
struct spa_hook registry_listener;
|
|
||||||
|
|
||||||
GMainContext *context;
|
|
||||||
|
|
||||||
GHashTable *proxies;
|
|
||||||
GHashTable *default_features;
|
|
||||||
GQueue created_obj_proxies;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum {
|
|
||||||
PROP_0,
|
|
||||||
PROP_STATE,
|
|
||||||
PROP_ERROR_MESSAGE,
|
|
||||||
PROP_PW_CORE,
|
|
||||||
PROP_PW_REMOTE,
|
|
||||||
PROP_CONTEXT,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
SIGNAL_GLOBAL_ADDED,
|
|
||||||
SIGNAL_GLOBAL_REMOVED,
|
|
||||||
LAST_SIGNAL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static guint signals[LAST_SIGNAL] = { 0 };
|
|
||||||
|
|
||||||
G_DEFINE_TYPE (WpRemotePipewire, wp_remote_pipewire, WP_TYPE_REMOTE)
|
|
||||||
|
|
||||||
static void
|
|
||||||
on_proxy_ready (GObject * obj, GAsyncResult * res, gpointer data)
|
|
||||||
{
|
|
||||||
WpRemotePipewire *self = WP_REMOTE_PIPEWIRE (data);
|
|
||||||
WpProxy *proxy = WP_PROXY (obj);
|
|
||||||
g_autoptr (GError) error = NULL;
|
|
||||||
|
|
||||||
if (!wp_proxy_augment_finish (proxy, res, &error)) {
|
|
||||||
g_warning ("Failed to augment WpProxy (%p): %s", obj, error->message);
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
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 = {
|
|
||||||
PW_VERSION_REGISTRY_PROXY_EVENTS,
|
|
||||||
.global = registry_global,
|
|
||||||
.global_remove = registry_global_remove,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
|
||||||
registry_init (WpRemotePipewire *self)
|
|
||||||
{
|
|
||||||
/* Get the core proxy */
|
|
||||||
self->core_proxy = pw_remote_get_core_proxy (self->remote);
|
|
||||||
|
|
||||||
/* Registry */
|
|
||||||
self->registry_proxy = pw_core_proxy_get_registry (self->core_proxy,
|
|
||||||
PW_VERSION_REGISTRY_PROXY, 0);
|
|
||||||
pw_registry_proxy_add_listener(self->registry_proxy, &self->registry_listener,
|
|
||||||
®istry_proxy_events, self);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
on_remote_state_changed (void *d, enum pw_remote_state old_state,
|
|
||||||
enum pw_remote_state new_state, const char *error)
|
|
||||||
{
|
|
||||||
WpRemotePipewire *self = d;
|
|
||||||
|
|
||||||
g_debug ("pipewire remote state changed, old:%s new:%s",
|
|
||||||
pw_remote_state_as_string (old_state),
|
|
||||||
pw_remote_state_as_string (new_state));
|
|
||||||
|
|
||||||
/* Init the registry when connected */
|
|
||||||
if (!self->registry_proxy && new_state == PW_REMOTE_STATE_CONNECTED)
|
|
||||||
registry_init (self);
|
|
||||||
|
|
||||||
g_object_notify (G_OBJECT (self), "state");
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct pw_remote_events remote_events = {
|
|
||||||
PW_VERSION_REMOTE_EVENTS,
|
|
||||||
.state_changed = on_remote_state_changed,
|
|
||||||
};
|
|
||||||
|
|
||||||
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
|
|
||||||
wp_remote_pipewire_constructed (GObject *object)
|
|
||||||
{
|
|
||||||
WpRemotePipewire *self = WP_REMOTE_PIPEWIRE (object);
|
|
||||||
GSource *source;
|
|
||||||
|
|
||||||
source = wp_loop_source_new ();
|
|
||||||
g_source_attach (source, self->context);
|
|
||||||
|
|
||||||
self->core = pw_core_new (WP_LOOP_SOURCE (source)->loop, NULL, 0);
|
|
||||||
|
|
||||||
self->remote = pw_remote_new (self->core, NULL, 0);
|
|
||||||
pw_remote_add_listener (self->remote, &self->remote_listener, &remote_events,
|
|
||||||
self);
|
|
||||||
|
|
||||||
G_OBJECT_CLASS (wp_remote_pipewire_parent_class)->constructed (object);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
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);
|
|
||||||
self->core_proxy= NULL;
|
|
||||||
self->registry_proxy = NULL;
|
|
||||||
|
|
||||||
G_OBJECT_CLASS (wp_remote_pipewire_parent_class)->finalize (object);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
wp_remote_pipewire_get_property (GObject * object, guint property_id,
|
|
||||||
GValue * value, GParamSpec * pspec)
|
|
||||||
{
|
|
||||||
WpRemotePipewire *self = WP_REMOTE_PIPEWIRE (object);
|
|
||||||
|
|
||||||
switch (property_id) {
|
|
||||||
case PROP_STATE:
|
|
||||||
/* enum pw_remote_state matches values with WpRemoteState */
|
|
||||||
g_value_set_enum (value, pw_remote_get_state (self->remote, NULL));
|
|
||||||
break;
|
|
||||||
case PROP_ERROR_MESSAGE:
|
|
||||||
{
|
|
||||||
const gchar *msg;
|
|
||||||
(void) pw_remote_get_state (self->remote, &msg);
|
|
||||||
g_value_set_string (value, msg);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PROP_PW_CORE:
|
|
||||||
g_value_set_pointer (value, self->core);
|
|
||||||
break;
|
|
||||||
case PROP_PW_REMOTE:
|
|
||||||
g_value_set_pointer (value, self->remote);
|
|
||||||
break;
|
|
||||||
case PROP_CONTEXT:
|
|
||||||
g_value_set_boxed (value, self->context);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
wp_remote_pipewire_set_property (GObject * object, guint property_id,
|
|
||||||
const GValue * value, GParamSpec * pspec)
|
|
||||||
{
|
|
||||||
WpRemotePipewire *self = WP_REMOTE_PIPEWIRE (object);
|
|
||||||
|
|
||||||
switch (property_id) {
|
|
||||||
case PROP_CONTEXT:
|
|
||||||
self->context = g_value_dup_boxed (value);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
connect_in_idle (WpRemotePipewire *self)
|
|
||||||
{
|
|
||||||
pw_remote_connect (self->remote);
|
|
||||||
return G_SOURCE_REMOVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
wp_remote_pipewire_connect (WpRemote *remote)
|
|
||||||
{
|
|
||||||
WpRemotePipewire *self = WP_REMOTE_PIPEWIRE (remote);
|
|
||||||
g_autoptr (GSource) source;
|
|
||||||
|
|
||||||
source = g_idle_source_new ();
|
|
||||||
g_source_set_callback (source, (GSourceFunc) connect_in_idle, self, NULL);
|
|
||||||
g_source_attach (source, self->context);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
wp_remote_pipewire_class_init (WpRemotePipewireClass *klass)
|
|
||||||
{
|
|
||||||
GObjectClass *object_class = (GObjectClass *) klass;
|
|
||||||
WpRemoteClass *remote_class = (WpRemoteClass *) klass;
|
|
||||||
|
|
||||||
pw_init (NULL, NULL);
|
|
||||||
|
|
||||||
object_class->constructed = wp_remote_pipewire_constructed;
|
|
||||||
object_class->finalize = wp_remote_pipewire_finalize;
|
|
||||||
object_class->get_property = wp_remote_pipewire_get_property;
|
|
||||||
object_class->set_property = wp_remote_pipewire_set_property;
|
|
||||||
|
|
||||||
remote_class->connect = wp_remote_pipewire_connect;
|
|
||||||
|
|
||||||
g_object_class_override_property (object_class, PROP_STATE, "state");
|
|
||||||
g_object_class_override_property (object_class, PROP_ERROR_MESSAGE,
|
|
||||||
"error-message");
|
|
||||||
|
|
||||||
g_object_class_install_property (object_class, PROP_CONTEXT,
|
|
||||||
g_param_spec_boxed ("context", "context", "A GMainContext to attach to",
|
|
||||||
G_TYPE_MAIN_CONTEXT,
|
|
||||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
|
||||||
|
|
||||||
g_object_class_install_property (object_class, PROP_PW_CORE,
|
|
||||||
g_param_spec_pointer ("pw-core", "pw-core", "The pipewire core",
|
|
||||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
|
||||||
|
|
||||||
g_object_class_install_property (object_class, PROP_PW_REMOTE,
|
|
||||||
g_param_spec_pointer ("pw-remote", "pw-remote", "The pipewire remote",
|
|
||||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
|
||||||
|
|
||||||
/* 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, 1, WP_TYPE_PROXY);
|
|
||||||
signals[SIGNAL_GLOBAL_REMOVED] = g_signal_new ("global-removed",
|
|
||||||
G_TYPE_FROM_CLASS (klass), G_SIGNAL_DETAILED | G_SIGNAL_RUN_LAST,
|
|
||||||
0, NULL, NULL, NULL, G_TYPE_NONE, 1, WP_TYPE_PROXY);
|
|
||||||
}
|
|
||||||
|
|
||||||
WpRemote *
|
|
||||||
wp_remote_pipewire_new (WpCore *core, GMainContext *context)
|
|
||||||
{
|
|
||||||
WpRemote *remote;
|
|
||||||
|
|
||||||
g_return_val_if_fail (WP_IS_CORE (core), NULL);
|
|
||||||
|
|
||||||
remote = g_object_new (WP_TYPE_REMOTE_PIPEWIRE,
|
|
||||||
"core", core,
|
|
||||||
"context", context,
|
|
||||||
NULL);
|
|
||||||
wp_core_register_global (core, WP_GLOBAL_REMOTE_PIPEWIRE,
|
|
||||||
g_object_ref (remote), g_object_unref);
|
|
||||||
|
|
||||||
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,
|
|
||||||
properties ? wp_properties_peek_dict (properties) : NULL, 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)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail (WP_IS_REMOTE_PIPEWIRE(self), NULL);
|
|
||||||
g_return_val_if_fail (self->registry_proxy, NULL);
|
|
||||||
|
|
||||||
return pw_registry_proxy_bind (self->registry_proxy, global_id, global_type,
|
|
||||||
0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
gpointer
|
|
||||||
wp_remote_pipewire_find_factory (WpRemotePipewire *self,
|
|
||||||
const char *factory_name)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail (WP_IS_REMOTE_PIPEWIRE(self), NULL);
|
|
||||||
g_return_val_if_fail (self->core, NULL);
|
|
||||||
|
|
||||||
return pw_core_find_factory(self->core, factory_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
wp_remote_pipewire_add_spa_lib (WpRemotePipewire *self,
|
|
||||||
const char *factory_regexp, const char *lib)
|
|
||||||
{
|
|
||||||
g_return_if_fail (WP_IS_REMOTE_PIPEWIRE(self));
|
|
||||||
|
|
||||||
pw_core_add_spa_lib (self->core, factory_regexp, lib);
|
|
||||||
}
|
|
||||||
|
|
||||||
gpointer
|
|
||||||
wp_remote_pipewire_load_spa_handle(WpRemotePipewire *self,
|
|
||||||
const char *factory_name, gconstpointer info)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail (WP_IS_REMOTE_PIPEWIRE(self), NULL);
|
|
||||||
|
|
||||||
return pw_core_load_spa_handle (self->core, factory_name, info);
|
|
||||||
}
|
|
||||||
|
|
||||||
gpointer
|
|
||||||
wp_remote_pipewire_export (WpRemotePipewire *self, guint type,
|
|
||||||
gpointer props, gpointer object, size_t user_data_size)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail (WP_IS_REMOTE_PIPEWIRE(self), NULL);
|
|
||||||
|
|
||||||
return pw_remote_export (self->remote, type, props, object, user_data_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
gpointer
|
|
||||||
wp_remote_pipewire_module_load (WpRemotePipewire *self, const char *name,
|
|
||||||
const char *args, gpointer properties)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail (WP_IS_REMOTE_PIPEWIRE(self), NULL);
|
|
||||||
|
|
||||||
return pw_module_load (self->core, name, args, properties);
|
|
||||||
}
|
|
@@ -1,45 +0,0 @@
|
|||||||
/* WirePlumber
|
|
||||||
*
|
|
||||||
* Copyright © 2019 Collabora Ltd.
|
|
||||||
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __WIREPLUMBER_REMOTE_PIPEWIRE_H__
|
|
||||||
#define __WIREPLUMBER_REMOTE_PIPEWIRE_H__
|
|
||||||
|
|
||||||
#include "remote.h"
|
|
||||||
#include "proxy.h"
|
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
|
||||||
|
|
||||||
#define WP_TYPE_REMOTE_PIPEWIRE (wp_remote_pipewire_get_type ())
|
|
||||||
G_DECLARE_FINAL_TYPE (WpRemotePipewire, wp_remote_pipewire,
|
|
||||||
WP, REMOTE_PIPEWIRE, WpRemote)
|
|
||||||
|
|
||||||
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);
|
|
||||||
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,
|
|
||||||
const char *factory_name, gconstpointer info);
|
|
||||||
gpointer wp_remote_pipewire_export (WpRemotePipewire *self, guint type,
|
|
||||||
gpointer props, gpointer object, size_t user_data_size);
|
|
||||||
gpointer wp_remote_pipewire_module_load (WpRemotePipewire *self,
|
|
||||||
const char *name, const char *args, gpointer properties);
|
|
||||||
|
|
||||||
G_END_DECLS
|
|
||||||
|
|
||||||
#endif
|
|
153
lib/wp/remote.c
153
lib/wp/remote.c
@@ -1,153 +0,0 @@
|
|||||||
/* WirePlumber
|
|
||||||
*
|
|
||||||
* Copyright © 2019 Collabora Ltd.
|
|
||||||
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "remote.h"
|
|
||||||
#include "wpenums.h"
|
|
||||||
|
|
||||||
enum {
|
|
||||||
PROP_0,
|
|
||||||
PROP_CORE,
|
|
||||||
PROP_STATE,
|
|
||||||
PROP_ERROR_MESSAGE,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum {
|
|
||||||
SIGNAL_STATE_CHANGED,
|
|
||||||
N_SIGNALS
|
|
||||||
};
|
|
||||||
|
|
||||||
static guint signals[N_SIGNALS];
|
|
||||||
|
|
||||||
typedef struct _WpRemotePrivate WpRemotePrivate;
|
|
||||||
struct _WpRemotePrivate
|
|
||||||
{
|
|
||||||
GWeakRef core;
|
|
||||||
};
|
|
||||||
|
|
||||||
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (WpRemote, wp_remote, G_TYPE_OBJECT)
|
|
||||||
|
|
||||||
static void
|
|
||||||
wp_remote_init (WpRemote *self)
|
|
||||||
{
|
|
||||||
WpRemotePrivate *priv = wp_remote_get_instance_private (self);
|
|
||||||
g_weak_ref_init (&priv->core, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
wp_remote_finalize (GObject *object)
|
|
||||||
{
|
|
||||||
WpRemotePrivate *priv = wp_remote_get_instance_private (WP_REMOTE (object));
|
|
||||||
|
|
||||||
g_weak_ref_clear (&priv->core);
|
|
||||||
|
|
||||||
g_debug ("%s destroyed", G_OBJECT_TYPE_NAME (object));
|
|
||||||
|
|
||||||
G_OBJECT_CLASS (wp_remote_parent_class)->finalize (object);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
wp_remote_set_property (GObject * object, guint property_id,
|
|
||||||
const GValue * value, GParamSpec * pspec)
|
|
||||||
{
|
|
||||||
WpRemotePrivate *priv = wp_remote_get_instance_private (WP_REMOTE (object));
|
|
||||||
|
|
||||||
switch (property_id) {
|
|
||||||
case PROP_CORE:
|
|
||||||
g_weak_ref_set (&priv->core, g_value_get_object (value));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
wp_remote_get_property (GObject * object, guint property_id,
|
|
||||||
GValue * value, GParamSpec * pspec)
|
|
||||||
{
|
|
||||||
WpRemotePrivate *priv = wp_remote_get_instance_private (WP_REMOTE (object));
|
|
||||||
|
|
||||||
switch (property_id) {
|
|
||||||
case PROP_CORE:
|
|
||||||
g_value_take_object (value, g_weak_ref_get (&priv->core));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
wp_remote_notify (GObject *object, GParamSpec *param)
|
|
||||||
{
|
|
||||||
if (!g_strcmp0 (param->name, "state")) {
|
|
||||||
WpRemoteState state;
|
|
||||||
GParamSpecEnum *param_enum = (GParamSpecEnum *) param;
|
|
||||||
GEnumValue *value;
|
|
||||||
GQuark detail;
|
|
||||||
|
|
||||||
g_object_get (object, "state", &state, NULL);
|
|
||||||
value = g_enum_get_value (param_enum->enum_class, state);
|
|
||||||
detail = g_quark_from_static_string (value->value_nick);
|
|
||||||
g_signal_emit (object, signals[SIGNAL_STATE_CHANGED], detail, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (G_OBJECT_CLASS (wp_remote_parent_class)->notify)
|
|
||||||
G_OBJECT_CLASS (wp_remote_parent_class)->notify (object, param);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
wp_remote_class_init (WpRemoteClass *klass)
|
|
||||||
{
|
|
||||||
GObjectClass *object_class = (GObjectClass *) klass;
|
|
||||||
|
|
||||||
object_class->finalize = wp_remote_finalize;
|
|
||||||
object_class->set_property = wp_remote_set_property;
|
|
||||||
object_class->get_property = wp_remote_get_property;
|
|
||||||
object_class->notify = wp_remote_notify;
|
|
||||||
|
|
||||||
g_object_class_install_property (object_class, PROP_CORE,
|
|
||||||
g_param_spec_object ("core", "core", "The wireplumber core",
|
|
||||||
WP_TYPE_CORE,
|
|
||||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
|
||||||
|
|
||||||
g_object_class_install_property (object_class, PROP_STATE,
|
|
||||||
g_param_spec_enum ("state", "state", "The state of the remote",
|
|
||||||
WP_TYPE_REMOTE_STATE, WP_REMOTE_STATE_UNCONNECTED,
|
|
||||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
|
||||||
|
|
||||||
g_object_class_install_property (object_class, PROP_ERROR_MESSAGE,
|
|
||||||
g_param_spec_string ("error-message", "error-message",
|
|
||||||
"The last error message of the remote", NULL,
|
|
||||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
|
||||||
|
|
||||||
signals[SIGNAL_STATE_CHANGED] = g_signal_new ("state-changed",
|
|
||||||
G_TYPE_FROM_CLASS (klass), G_SIGNAL_DETAILED | G_SIGNAL_RUN_LAST,
|
|
||||||
0, NULL, NULL, NULL, G_TYPE_NONE, 1, WP_TYPE_REMOTE_STATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* wp_remote_get_core:
|
|
||||||
* @self: the remote
|
|
||||||
*
|
|
||||||
* Returns: (transfer full): the core of the remote
|
|
||||||
*/
|
|
||||||
WpCore *
|
|
||||||
wp_remote_get_core (WpRemote *self)
|
|
||||||
{
|
|
||||||
WpRemotePrivate *priv = wp_remote_get_instance_private (self);
|
|
||||||
return g_weak_ref_get (&priv->core);
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
|
||||||
wp_remote_connect (WpRemote *self)
|
|
||||||
{
|
|
||||||
if (WP_REMOTE_GET_CLASS (self)->connect)
|
|
||||||
return WP_REMOTE_GET_CLASS (self)->connect (self);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
@@ -1,47 +0,0 @@
|
|||||||
/* WirePlumber
|
|
||||||
*
|
|
||||||
* Copyright © 2019 Collabora Ltd.
|
|
||||||
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __WIREPLUMBER_REMOTE_H__
|
|
||||||
#define __WIREPLUMBER_REMOTE_H__
|
|
||||||
|
|
||||||
#include "core.h"
|
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
|
||||||
|
|
||||||
/**
|
|
||||||
* WpRemoteState:
|
|
||||||
* @WP_REMOTE_STATE_ERROR: remote is in error
|
|
||||||
* @WP_REMOTE_STATE_UNCONNECTED: not connected
|
|
||||||
* @WP_REMOTE_STATE_CONNECTING: connecting to remote service
|
|
||||||
* @WP_REMOTE_STATE_CONNECTED: remote is connected and ready
|
|
||||||
*
|
|
||||||
* The different states the remote can be
|
|
||||||
*/
|
|
||||||
typedef enum {
|
|
||||||
WP_REMOTE_STATE_ERROR = -1,
|
|
||||||
WP_REMOTE_STATE_UNCONNECTED = 0,
|
|
||||||
WP_REMOTE_STATE_CONNECTING = 1,
|
|
||||||
WP_REMOTE_STATE_CONNECTED = 2,
|
|
||||||
} WpRemoteState;
|
|
||||||
|
|
||||||
#define WP_TYPE_REMOTE (wp_remote_get_type ())
|
|
||||||
G_DECLARE_DERIVABLE_TYPE (WpRemote, wp_remote, WP, REMOTE, GObject)
|
|
||||||
|
|
||||||
struct _WpRemoteClass
|
|
||||||
{
|
|
||||||
GObjectClass parent_class;
|
|
||||||
|
|
||||||
gboolean (*connect) (WpRemote *self);
|
|
||||||
};
|
|
||||||
|
|
||||||
WpCore *wp_remote_get_core (WpRemote *self);
|
|
||||||
gboolean wp_remote_connect (WpRemote *self);
|
|
||||||
|
|
||||||
G_END_DECLS
|
|
||||||
|
|
||||||
#endif
|
|
@@ -18,5 +18,3 @@
|
|||||||
#include "proxy-link.h"
|
#include "proxy-link.h"
|
||||||
#include "proxy-node.h"
|
#include "proxy-node.h"
|
||||||
#include "proxy-port.h"
|
#include "proxy-port.h"
|
||||||
#include "remote.h"
|
|
||||||
#include "remote-pipewire.h"
|
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
#include <pipewire/pipewire.h>
|
#include <pipewire/pipewire.h>
|
||||||
|
|
||||||
static void
|
static void
|
||||||
client_added (WpRemote * remote, WpProxyClient *client, gpointer data)
|
client_added (WpCore * core, WpProxyClient *client, gpointer data)
|
||||||
{
|
{
|
||||||
g_autoptr (WpProperties) properties = NULL;
|
g_autoptr (WpProperties) properties = NULL;
|
||||||
const char *access;
|
const char *access;
|
||||||
@@ -30,12 +30,9 @@ client_added (WpRemote * remote, WpProxyClient *client, gpointer data)
|
|||||||
void
|
void
|
||||||
wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args)
|
wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args)
|
||||||
{
|
{
|
||||||
WpRemote *remote = wp_core_get_global (core, WP_GLOBAL_REMOTE_PIPEWIRE);
|
wp_core_set_default_proxy_features (core, WP_TYPE_PROXY_CLIENT,
|
||||||
g_return_if_fail (remote != NULL);
|
WP_PROXY_FEATURE_PW_PROXY | WP_PROXY_FEATURE_INFO);
|
||||||
|
|
||||||
wp_remote_pipewire_set_default_features (WP_REMOTE_PIPEWIRE (remote),
|
g_signal_connect(core, "remote-global-added::client",
|
||||||
WP_TYPE_PROXY_CLIENT, WP_PROXY_FEATURE_PW_PROXY | WP_PROXY_FEATURE_INFO);
|
(GCallback) client_added, NULL);
|
||||||
|
|
||||||
g_signal_connect(remote, "global-added::client", (GCallback) client_added,
|
|
||||||
NULL);
|
|
||||||
}
|
}
|
||||||
|
@@ -298,9 +298,8 @@ mixer_endpoint_class_init (WpMixerEndpointClass * klass)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
remote_connected (WpRemote *remote, WpRemoteState state, GVariant *streams)
|
remote_connected (WpCore *core, WpRemoteState state, GVariant *streams)
|
||||||
{
|
{
|
||||||
g_autoptr (WpCore) core = wp_remote_get_core (remote);
|
|
||||||
g_autoptr (WpEndpoint) ep = g_object_new (mixer_endpoint_get_type (),
|
g_autoptr (WpEndpoint) ep = g_object_new (mixer_endpoint_get_type (),
|
||||||
"core", core,
|
"core", core,
|
||||||
"name", "Mixer",
|
"name", "Mixer",
|
||||||
@@ -313,15 +312,11 @@ remote_connected (WpRemote *remote, WpRemoteState state, GVariant *streams)
|
|||||||
void
|
void
|
||||||
wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args)
|
wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args)
|
||||||
{
|
{
|
||||||
WpRemote *remote;
|
|
||||||
GVariant *streams;
|
GVariant *streams;
|
||||||
|
|
||||||
remote = wp_core_get_global (core, WP_GLOBAL_REMOTE_PIPEWIRE);
|
|
||||||
g_return_if_fail (remote != NULL);
|
|
||||||
|
|
||||||
streams = g_variant_lookup_value (args, "streams", G_VARIANT_TYPE ("as"));
|
streams = g_variant_lookup_value (args, "streams", G_VARIANT_TYPE ("as"));
|
||||||
|
|
||||||
g_signal_connect_data (remote, "state-changed::connected",
|
g_signal_connect_data (core, "remote-state-changed::connected",
|
||||||
(GCallback) remote_connected, streams, (GClosureNotify) g_variant_unref,
|
(GCallback) remote_connected, streams, (GClosureNotify) g_variant_unref,
|
||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
@@ -23,20 +23,10 @@ void simple_endpoint_link_factory (WpFactory * factory, GType type,
|
|||||||
void
|
void
|
||||||
wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args)
|
wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args)
|
||||||
{
|
{
|
||||||
WpRemotePipewire *rp;
|
struct pw_core *pw_core = wp_core_get_pw_core (core);
|
||||||
|
|
||||||
/* Get the remote pipewire */
|
pw_module_load (pw_core, "libpipewire-module-client-device", NULL, NULL);
|
||||||
rp = wp_core_get_global (core, WP_GLOBAL_REMOTE_PIPEWIRE);
|
pw_module_load (pw_core, "libpipewire-module-adapter", NULL, NULL);
|
||||||
if (!rp) {
|
|
||||||
g_critical ("module-pipewire cannot be loaded without a registered "
|
|
||||||
"WpRemotePipewire object");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Load the client-device and adapter modules */
|
|
||||||
wp_remote_pipewire_module_load(rp, "libpipewire-module-client-device", NULL,
|
|
||||||
NULL);
|
|
||||||
wp_remote_pipewire_module_load(rp, "libpipewire-module-adapter", NULL, NULL);
|
|
||||||
|
|
||||||
/* Register simple-endpoint and simple-endpoint-link */
|
/* Register simple-endpoint and simple-endpoint-link */
|
||||||
wp_factory_new (core, "pipewire-simple-endpoint",
|
wp_factory_new (core, "pipewire-simple-endpoint",
|
||||||
|
@@ -167,7 +167,6 @@ simple_endpoint_link_create (WpEndpointLink * epl, GVariant * src_data,
|
|||||||
{
|
{
|
||||||
WpPipewireSimpleEndpointLink *self = WP_PIPEWIRE_SIMPLE_ENDPOINT_LINK(epl);
|
WpPipewireSimpleEndpointLink *self = WP_PIPEWIRE_SIMPLE_ENDPOINT_LINK(epl);
|
||||||
g_autoptr (WpCore) core = NULL;
|
g_autoptr (WpCore) core = NULL;
|
||||||
WpRemotePipewire *remote_pipewire;
|
|
||||||
guint32 output_node_id, input_node_id;
|
guint32 output_node_id, input_node_id;
|
||||||
GVariant *src_ports, *sink_ports;
|
GVariant *src_ports, *sink_ports;
|
||||||
GVariantIter *out_iter, *in_iter;
|
GVariantIter *out_iter, *in_iter;
|
||||||
@@ -179,10 +178,6 @@ simple_endpoint_link_create (WpEndpointLink * epl, GVariant * src_data,
|
|||||||
core = g_weak_ref_get (&self->core);
|
core = g_weak_ref_get (&self->core);
|
||||||
g_return_val_if_fail (core, FALSE);
|
g_return_val_if_fail (core, FALSE);
|
||||||
|
|
||||||
/* Get the remote pipewire */
|
|
||||||
remote_pipewire = wp_core_get_global (core, WP_GLOBAL_REMOTE_PIPEWIRE);
|
|
||||||
g_return_val_if_fail (remote_pipewire, FALSE);
|
|
||||||
|
|
||||||
/* Get the node ids and port ids */
|
/* Get the node ids and port ids */
|
||||||
if (!g_variant_lookup (src_data, "node-id", "u", &output_node_id))
|
if (!g_variant_lookup (src_data, "node-id", "u", &output_node_id))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@@ -226,7 +221,7 @@ simple_endpoint_link_create (WpEndpointLink * epl, GVariant * src_data,
|
|||||||
wp_properties_setf(props, PW_KEY_LINK_INPUT_PORT, "%d", in_id);
|
wp_properties_setf(props, PW_KEY_LINK_INPUT_PORT, "%d", in_id);
|
||||||
|
|
||||||
/* Create the link */
|
/* Create the link */
|
||||||
proxy = wp_remote_pipewire_create_object(remote_pipewire, "link-factory",
|
proxy = wp_core_create_remote_object(core, "link-factory",
|
||||||
PW_TYPE_INTERFACE_Link, PW_VERSION_LINK_PROXY, props);
|
PW_TYPE_INTERFACE_Link, PW_VERSION_LINK_PROXY, props);
|
||||||
g_return_val_if_fail (proxy, FALSE);
|
g_return_val_if_fail (proxy, FALSE);
|
||||||
g_ptr_array_add(self->link_proxies, proxy);
|
g_ptr_array_add(self->link_proxies, proxy);
|
||||||
|
@@ -32,9 +32,6 @@ struct _WpPipewireSimpleEndpoint
|
|||||||
/* The task to signal the endpoint is initialized */
|
/* The task to signal the endpoint is initialized */
|
||||||
GTask *init_task;
|
GTask *init_task;
|
||||||
|
|
||||||
/* The remote pipewire */
|
|
||||||
WpRemotePipewire *remote_pipewire;
|
|
||||||
|
|
||||||
/* Proxies */
|
/* Proxies */
|
||||||
WpProxyNode *proxy_node;
|
WpProxyNode *proxy_node;
|
||||||
GPtrArray *proxies_port;
|
GPtrArray *proxies_port;
|
||||||
@@ -175,7 +172,7 @@ on_proxy_port_augmented (WpProxy *proxy, GAsyncResult *res,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_port_added(WpRemotePipewire *rp, WpProxy *proxy, gpointer d)
|
on_port_added (WpCore *core, WpProxy *proxy, gpointer d)
|
||||||
{
|
{
|
||||||
WpPipewireSimpleEndpoint *self = d;
|
WpPipewireSimpleEndpoint *self = d;
|
||||||
const char *s;
|
const char *s;
|
||||||
@@ -287,10 +284,8 @@ wp_simple_endpoint_init_async (GAsyncInitable *initable, int io_priority,
|
|||||||
self->init_task = g_task_new (initable, cancellable, callback, data);
|
self->init_task = g_task_new (initable, cancellable, callback, data);
|
||||||
|
|
||||||
/* Register a port_added callback */
|
/* Register a port_added callback */
|
||||||
self->remote_pipewire = wp_core_get_global (core, WP_GLOBAL_REMOTE_PIPEWIRE);
|
g_signal_connect_object (core, "remote-global-added::port",
|
||||||
g_return_if_fail(self->remote_pipewire);
|
(GCallback) on_port_added, self, 0);
|
||||||
g_signal_connect_object(self->remote_pipewire, "global-added::port",
|
|
||||||
(GCallback)on_port_added, self, 0);
|
|
||||||
|
|
||||||
/* Augment to get the info */
|
/* Augment to get the info */
|
||||||
wp_proxy_augment (WP_PROXY (self->proxy_node),
|
wp_proxy_augment (WP_PROXY (self->proxy_node),
|
||||||
|
@@ -26,7 +26,6 @@ struct monitor {
|
|||||||
struct impl
|
struct impl
|
||||||
{
|
{
|
||||||
WpModule *module;
|
WpModule *module;
|
||||||
WpRemotePipewire *remote_pipewire;
|
|
||||||
GHashTable *registered_endpoints;
|
GHashTable *registered_endpoints;
|
||||||
GVariant *streams;
|
GVariant *streams;
|
||||||
|
|
||||||
@@ -171,9 +170,8 @@ is_alsa_node (WpProperties * props)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_node_added(WpRemotePipewire *rp, WpProxy *proxy, struct impl *impl)
|
on_node_added(WpCore *core, WpProxy *proxy, struct impl *impl)
|
||||||
{
|
{
|
||||||
g_autoptr (WpCore) core = wp_module_get_core (impl->module);
|
|
||||||
const gchar *media_class, *name;
|
const gchar *media_class, *name;
|
||||||
enum pw_direction direction;
|
enum pw_direction direction;
|
||||||
GVariantBuilder b;
|
GVariantBuilder b;
|
||||||
@@ -214,7 +212,7 @@ on_node_added(WpRemotePipewire *rp, WpProxy *proxy, struct impl *impl)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_global_removed (WpRemotePipewire *rp, WpProxy *proxy, struct impl *impl)
|
on_node_removed (WpCore *core, WpProxy *proxy, struct impl *impl)
|
||||||
{
|
{
|
||||||
WpEndpoint *endpoint = NULL;
|
WpEndpoint *endpoint = NULL;
|
||||||
guint32 id = wp_proxy_get_global_id (proxy);
|
guint32 id = wp_proxy_get_global_id (proxy);
|
||||||
@@ -237,6 +235,7 @@ create_node(struct impl *impl, struct device *dev, uint32_t id,
|
|||||||
struct node *node;
|
struct node *node;
|
||||||
const char *name;
|
const char *name;
|
||||||
g_autoptr (WpProperties) props = NULL;
|
g_autoptr (WpProperties) props = NULL;
|
||||||
|
g_autoptr (WpCore) core = wp_module_get_core (impl->module);
|
||||||
|
|
||||||
/* Check if the type is a node */
|
/* Check if the type is a node */
|
||||||
if (info->type != SPA_TYPE_INTERFACE_Node)
|
if (info->type != SPA_TYPE_INTERFACE_Node)
|
||||||
@@ -264,8 +263,8 @@ create_node(struct impl *impl, struct device *dev, uint32_t id,
|
|||||||
node->impl = impl;
|
node->impl = impl;
|
||||||
node->device = dev;
|
node->device = dev;
|
||||||
node->id = id;
|
node->id = id;
|
||||||
node->proxy = wp_remote_pipewire_create_object (impl->remote_pipewire,
|
node->proxy = wp_core_create_remote_object (core, "adapter",
|
||||||
"adapter", PW_TYPE_INTERFACE_Node, PW_VERSION_NODE_PROXY, props);
|
PW_TYPE_INTERFACE_Node, PW_VERSION_NODE_PROXY, props);
|
||||||
if (!node->proxy) {
|
if (!node->proxy) {
|
||||||
g_slice_free (struct node, node);
|
g_slice_free (struct node, node);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -348,8 +347,9 @@ static const struct spa_device_events device_events = {
|
|||||||
|
|
||||||
static struct device*
|
static struct device*
|
||||||
create_device(struct impl *impl, uint32_t id,
|
create_device(struct impl *impl, uint32_t id,
|
||||||
const struct spa_monitor_object_info *info) {
|
const struct spa_monitor_object_info *info)
|
||||||
|
{
|
||||||
|
g_autoptr (WpCore) core = wp_module_get_core (impl->module);
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct spa_handle *handle;
|
struct spa_handle *handle;
|
||||||
int res;
|
int res;
|
||||||
@@ -360,8 +360,8 @@ create_device(struct impl *impl, uint32_t id,
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Load the device handle */
|
/* Load the device handle */
|
||||||
handle = (struct spa_handle *)wp_remote_pipewire_load_spa_handle (
|
handle = pw_core_load_spa_handle (wp_core_get_pw_core (core),
|
||||||
impl->remote_pipewire, info->factory_name, info->props);
|
info->factory_name, info->props);
|
||||||
if (!handle)
|
if (!handle)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@@ -379,7 +379,8 @@ create_device(struct impl *impl, uint32_t id,
|
|||||||
dev->handle = handle;
|
dev->handle = handle;
|
||||||
dev->device = iface;
|
dev->device = iface;
|
||||||
dev->props = pw_properties_new_dict(info->props);
|
dev->props = pw_properties_new_dict(info->props);
|
||||||
dev->proxy = wp_remote_pipewire_export (impl->remote_pipewire, info->type, dev->props, dev->device, 0);
|
dev->proxy = pw_remote_export (wp_core_get_pw_remote (core),
|
||||||
|
info->type, dev->props, dev->device, 0);
|
||||||
if (!dev->proxy) {
|
if (!dev->proxy) {
|
||||||
pw_unload_spa_handle(handle);
|
pw_unload_spa_handle(handle);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -482,7 +483,7 @@ static const struct spa_monitor_callbacks monitor_callbacks =
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
start_monitor (WpRemotePipewire *remote, WpRemoteState state, gpointer data)
|
start_monitor (WpCore *core, WpRemoteState state, gpointer data)
|
||||||
{
|
{
|
||||||
struct impl *impl = data;
|
struct impl *impl = data;
|
||||||
struct spa_handle *handle;
|
struct spa_handle *handle;
|
||||||
@@ -490,8 +491,8 @@ start_monitor (WpRemotePipewire *remote, WpRemoteState state, gpointer data)
|
|||||||
void *iface;
|
void *iface;
|
||||||
|
|
||||||
/* Load the monitor handle */
|
/* Load the monitor handle */
|
||||||
handle = (struct spa_handle *)wp_remote_pipewire_load_spa_handle (
|
handle = pw_core_load_spa_handle (wp_core_get_pw_core (core),
|
||||||
impl->remote_pipewire, SPA_NAME_API_ALSA_MONITOR, NULL);
|
SPA_NAME_API_ALSA_MONITOR, NULL);
|
||||||
g_return_if_fail (handle);
|
g_return_if_fail (handle);
|
||||||
|
|
||||||
/* Get the handle interface */
|
/* Get the handle interface */
|
||||||
@@ -516,9 +517,8 @@ module_destroy (gpointer data)
|
|||||||
{
|
{
|
||||||
struct impl *impl = data;
|
struct impl *impl = data;
|
||||||
|
|
||||||
/* Set to NULL module and remote pipewire as we don't own the reference */
|
/* Set to NULL as we don't own the reference */
|
||||||
impl->module = NULL;
|
impl->module = NULL;
|
||||||
impl->remote_pipewire = NULL;
|
|
||||||
|
|
||||||
/* Destroy the registered endpoints table */
|
/* Destroy the registered endpoints table */
|
||||||
g_hash_table_unref(impl->registered_endpoints);
|
g_hash_table_unref(impl->registered_endpoints);
|
||||||
@@ -534,20 +534,10 @@ void
|
|||||||
wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args)
|
wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args)
|
||||||
{
|
{
|
||||||
struct impl *impl;
|
struct impl *impl;
|
||||||
WpRemotePipewire *rp;
|
|
||||||
|
|
||||||
/* Make sure the remote pipewire is valid */
|
|
||||||
rp = wp_core_get_global (core, WP_GLOBAL_REMOTE_PIPEWIRE);
|
|
||||||
if (!rp) {
|
|
||||||
g_critical ("module-pw-alsa-udev cannot be loaded without a registered "
|
|
||||||
"WpRemotePipewire object");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create the module data */
|
/* Create the module data */
|
||||||
impl = g_slice_new0(struct impl);
|
impl = g_slice_new0(struct impl);
|
||||||
impl->module = module;
|
impl->module = module;
|
||||||
impl->remote_pipewire = rp;
|
|
||||||
impl->registered_endpoints = g_hash_table_new_full (g_direct_hash,
|
impl->registered_endpoints = g_hash_table_new_full (g_direct_hash,
|
||||||
g_direct_equal, NULL, (GDestroyNotify)g_object_unref);
|
g_direct_equal, NULL, (GDestroyNotify)g_object_unref);
|
||||||
impl->streams = g_variant_lookup_value (args, "streams",
|
impl->streams = g_variant_lookup_value (args, "streams",
|
||||||
@@ -557,12 +547,16 @@ wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args)
|
|||||||
wp_module_set_destroy_callback (module, module_destroy, impl);
|
wp_module_set_destroy_callback (module, module_destroy, impl);
|
||||||
|
|
||||||
/* Add the spa lib */
|
/* Add the spa lib */
|
||||||
wp_remote_pipewire_add_spa_lib (rp, "api.alsa.*", "alsa/libspa-alsa");
|
pw_core_add_spa_lib (wp_core_get_pw_core (core),
|
||||||
|
"api.alsa.*", "alsa/libspa-alsa");
|
||||||
|
|
||||||
/* Start the monitor when the connected callback is triggered */
|
/* Start the monitor when the connected callback is triggered */
|
||||||
g_signal_connect(rp, "state-changed::connected", (GCallback)start_monitor, impl);
|
g_signal_connect(core, "remote-state-changed::connected",
|
||||||
|
(GCallback) start_monitor, impl);
|
||||||
|
|
||||||
/* Register the global addded/removed callbacks */
|
/* Register the global addded/removed callbacks */
|
||||||
g_signal_connect(rp, "global-added::node", (GCallback)on_node_added, impl);
|
g_signal_connect(core, "remote-global-added::node",
|
||||||
g_signal_connect(rp, "global-removed", (GCallback)on_global_removed, impl);
|
(GCallback) on_node_added, impl);
|
||||||
|
g_signal_connect(core, "remote-global-removed::node",
|
||||||
|
(GCallback) on_node_removed, impl);
|
||||||
}
|
}
|
||||||
|
@@ -16,8 +16,6 @@
|
|||||||
|
|
||||||
struct module_data
|
struct module_data
|
||||||
{
|
{
|
||||||
WpModule *module;
|
|
||||||
WpRemotePipewire *remote_pipewire;
|
|
||||||
GHashTable *registered_endpoints;
|
GHashTable *registered_endpoints;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -50,10 +48,9 @@ on_endpoint_created(GObject *initable, GAsyncResult *res, gpointer d)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_node_added (WpRemotePipewire *rp, WpProxy *proxy, gpointer d)
|
on_node_added (WpCore *core, WpProxy *proxy, gpointer d)
|
||||||
{
|
{
|
||||||
struct module_data *data = d;
|
struct module_data *data = d;
|
||||||
g_autoptr (WpCore) core = wp_module_get_core (data->module);
|
|
||||||
const gchar *name, *media_class;
|
const gchar *name, *media_class;
|
||||||
enum pw_direction direction;
|
enum pw_direction direction;
|
||||||
GVariantBuilder b;
|
GVariantBuilder b;
|
||||||
@@ -103,7 +100,7 @@ on_node_added (WpRemotePipewire *rp, WpProxy *proxy, gpointer d)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_global_removed (WpRemotePipewire *rp, WpProxy *proxy, gpointer d)
|
on_node_removed (WpCore *core, WpProxy *proxy, gpointer d)
|
||||||
{
|
{
|
||||||
struct module_data *data = d;
|
struct module_data *data = d;
|
||||||
WpEndpoint *endpoint = NULL;
|
WpEndpoint *endpoint = NULL;
|
||||||
@@ -125,10 +122,6 @@ module_destroy (gpointer d)
|
|||||||
{
|
{
|
||||||
struct module_data *data = d;
|
struct module_data *data = d;
|
||||||
|
|
||||||
/* Set to NULL module and remote pipewire as we don't own the reference */
|
|
||||||
data->module = NULL;
|
|
||||||
data->remote_pipewire = NULL;
|
|
||||||
|
|
||||||
/* Destroy the registered endpoints table */
|
/* Destroy the registered endpoints table */
|
||||||
g_clear_pointer (&data->registered_endpoints, g_hash_table_unref);
|
g_clear_pointer (&data->registered_endpoints, g_hash_table_unref);
|
||||||
|
|
||||||
@@ -140,20 +133,9 @@ void
|
|||||||
wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args)
|
wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args)
|
||||||
{
|
{
|
||||||
struct module_data *data;
|
struct module_data *data;
|
||||||
WpRemotePipewire *rp;
|
|
||||||
|
|
||||||
/* Make sure the remote pipewire is valid */
|
|
||||||
rp = wp_core_get_global (core, WP_GLOBAL_REMOTE_PIPEWIRE);
|
|
||||||
if (!rp) {
|
|
||||||
g_critical ("module-pipewire cannot be loaded without a registered "
|
|
||||||
"WpRemotePipewire object");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create the module data */
|
/* Create the module data */
|
||||||
data = g_slice_new0 (struct module_data);
|
data = g_slice_new0 (struct module_data);
|
||||||
data->module = module;
|
|
||||||
data->remote_pipewire = rp;
|
|
||||||
data->registered_endpoints = g_hash_table_new_full (g_direct_hash,
|
data->registered_endpoints = g_hash_table_new_full (g_direct_hash,
|
||||||
g_direct_equal, NULL, (GDestroyNotify)g_object_unref);
|
g_direct_equal, NULL, (GDestroyNotify)g_object_unref);
|
||||||
|
|
||||||
@@ -161,6 +143,8 @@ wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args)
|
|||||||
wp_module_set_destroy_callback (module, module_destroy, data);
|
wp_module_set_destroy_callback (module, module_destroy, data);
|
||||||
|
|
||||||
/* Register the global added/removed callbacks */
|
/* Register the global added/removed callbacks */
|
||||||
g_signal_connect(rp, "global-added::node", (GCallback)on_node_added, data);
|
g_signal_connect(core, "remote-global-added::node",
|
||||||
g_signal_connect(rp, "global-removed", (GCallback)on_global_removed, data);
|
(GCallback) on_node_added, data);
|
||||||
|
g_signal_connect(core, "remote-global-removed::node",
|
||||||
|
(GCallback) on_node_removed, data);
|
||||||
}
|
}
|
||||||
|
@@ -41,7 +41,7 @@ G_DEFINE_TYPE_WITH_CODE (WpAudioConvert, wp_audio_convert, WP_TYPE_AUDIO_STREAM,
|
|||||||
static void
|
static void
|
||||||
on_audio_convert_running(WpAudioConvert *self)
|
on_audio_convert_running(WpAudioConvert *self)
|
||||||
{
|
{
|
||||||
WpRemotePipewire *rp = wp_audio_stream_get_remote (WP_AUDIO_STREAM (self));
|
g_autoptr (WpCore) core = wp_audio_stream_get_core (WP_AUDIO_STREAM (self));
|
||||||
enum pw_direction direction =
|
enum pw_direction direction =
|
||||||
wp_audio_stream_get_direction (WP_AUDIO_STREAM (self));
|
wp_audio_stream_get_direction (WP_AUDIO_STREAM (self));
|
||||||
g_autoptr (WpProperties) props = NULL;
|
g_autoptr (WpProperties) props = NULL;
|
||||||
@@ -77,7 +77,7 @@ on_audio_convert_running(WpAudioConvert *self)
|
|||||||
g_debug ("%p linking audio convert to target", self);
|
g_debug ("%p linking audio convert to target", self);
|
||||||
|
|
||||||
/* Create the link */
|
/* Create the link */
|
||||||
self->link_proxy = wp_remote_pipewire_create_object (rp, "link-factory",
|
self->link_proxy = wp_core_create_remote_object (core, "link-factory",
|
||||||
PW_TYPE_INTERFACE_Link, PW_VERSION_LINK_PROXY, props);
|
PW_TYPE_INTERFACE_Link, PW_VERSION_LINK_PROXY, props);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,8 +150,7 @@ wp_audio_convert_init_async (GAsyncInitable *initable, int io_priority,
|
|||||||
WpAudioConvert *self = WP_AUDIO_CONVERT (initable);
|
WpAudioConvert *self = WP_AUDIO_CONVERT (initable);
|
||||||
g_autoptr (WpProxy) proxy = NULL;
|
g_autoptr (WpProxy) proxy = NULL;
|
||||||
g_autoptr (WpProperties) props = NULL;
|
g_autoptr (WpProperties) props = NULL;
|
||||||
WpRemotePipewire *remote =
|
g_autoptr (WpCore) core = wp_audio_stream_get_core (WP_AUDIO_STREAM (self));
|
||||||
wp_audio_stream_get_remote (WP_AUDIO_STREAM (self));
|
|
||||||
|
|
||||||
/* Create the properties */
|
/* Create the properties */
|
||||||
props = wp_properties_copy (wp_proxy_node_get_properties (self->target));
|
props = wp_properties_copy (wp_proxy_node_get_properties (self->target));
|
||||||
@@ -161,7 +160,7 @@ wp_audio_convert_init_async (GAsyncInitable *initable, int io_priority,
|
|||||||
wp_properties_set (props, "factory.name", SPA_NAME_AUDIO_CONVERT);
|
wp_properties_set (props, "factory.name", SPA_NAME_AUDIO_CONVERT);
|
||||||
|
|
||||||
/* Create the proxy */
|
/* Create the proxy */
|
||||||
proxy = wp_remote_pipewire_create_object (remote, "spa-node-factory",
|
proxy = wp_core_create_remote_object (core, "spa-node-factory",
|
||||||
PW_TYPE_INTERFACE_Node, PW_VERSION_NODE_PROXY, props);
|
PW_TYPE_INTERFACE_Node, PW_VERSION_NODE_PROXY, props);
|
||||||
g_return_if_fail (proxy);
|
g_return_if_fail (proxy);
|
||||||
|
|
||||||
|
@@ -151,8 +151,7 @@ on_port_config_done (WpProxy *proxy, GAsyncResult *res, WpAudioStream *self)
|
|||||||
|
|
||||||
/* called multiple times after we set the PortConfig */
|
/* called multiple times after we set the PortConfig */
|
||||||
static void
|
static void
|
||||||
on_audio_stream_port_added(WpRemotePipewire *rp, WpProxy *proxy,
|
on_audio_stream_port_added (WpCore *core, WpProxy *proxy, WpAudioStream *self)
|
||||||
WpAudioStream *self)
|
|
||||||
{
|
{
|
||||||
WpAudioStreamPrivate *priv = wp_audio_stream_get_instance_private (self);
|
WpAudioStreamPrivate *priv = wp_audio_stream_get_instance_private (self);
|
||||||
g_autoptr (WpProperties) props = wp_proxy_get_global_properties (proxy);
|
g_autoptr (WpProperties) props = wp_proxy_get_global_properties (proxy);
|
||||||
@@ -326,6 +325,7 @@ wp_audio_stream_init_async (GAsyncInitable *initable, int io_priority,
|
|||||||
WpAudioStream *self = WP_AUDIO_STREAM(initable);
|
WpAudioStream *self = WP_AUDIO_STREAM(initable);
|
||||||
WpAudioStreamPrivate *priv = wp_audio_stream_get_instance_private (self);
|
WpAudioStreamPrivate *priv = wp_audio_stream_get_instance_private (self);
|
||||||
g_autoptr (WpEndpoint) ep = g_weak_ref_get (&priv->endpoint);
|
g_autoptr (WpEndpoint) ep = g_weak_ref_get (&priv->endpoint);
|
||||||
|
g_autoptr (WpCore) core = wp_audio_stream_get_core (self);
|
||||||
GVariantDict d;
|
GVariantDict d;
|
||||||
|
|
||||||
g_debug ("WpEndpoint:%p init stream %s (%s:%p)", ep, priv->name,
|
g_debug ("WpEndpoint:%p init stream %s (%s:%p)", ep, priv->name,
|
||||||
@@ -362,8 +362,8 @@ wp_audio_stream_init_async (GAsyncInitable *initable, int io_priority,
|
|||||||
(GAsyncReadyCallback) on_node_proxy_augmented, self);
|
(GAsyncReadyCallback) on_node_proxy_augmented, self);
|
||||||
|
|
||||||
/* Register a port_added callback */
|
/* Register a port_added callback */
|
||||||
g_signal_connect_object(wp_audio_stream_get_remote (self),
|
g_signal_connect_object(core, "remote-global-added::port",
|
||||||
"global-added::port", (GCallback)on_audio_stream_port_added, self, 0);
|
(GCallback) on_audio_stream_port_added, self, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@@ -560,8 +560,8 @@ wp_audio_stream_set_control_value (WpAudioStream * self, guint32 control_id,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
WpRemotePipewire *
|
WpCore *
|
||||||
wp_audio_stream_get_remote (WpAudioStream * self)
|
wp_audio_stream_get_core (WpAudioStream * self)
|
||||||
{
|
{
|
||||||
WpAudioStreamPrivate *priv = wp_audio_stream_get_instance_private (self);
|
WpAudioStreamPrivate *priv = wp_audio_stream_get_instance_private (self);
|
||||||
g_autoptr (WpEndpoint) ep = NULL;
|
g_autoptr (WpEndpoint) ep = NULL;
|
||||||
@@ -569,9 +569,7 @@ wp_audio_stream_get_remote (WpAudioStream * self)
|
|||||||
|
|
||||||
ep = g_weak_ref_get (&priv->endpoint);
|
ep = g_weak_ref_get (&priv->endpoint);
|
||||||
core = wp_endpoint_get_core (ep);
|
core = wp_endpoint_get_core (ep);
|
||||||
|
return g_steal_pointer (&core);
|
||||||
/* FIXME this is theoretically not safe */
|
|
||||||
return wp_core_get_global (core, WP_GLOBAL_REMOTE_PIPEWIRE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@@ -41,7 +41,7 @@ gboolean wp_audio_stream_set_control_value (WpAudioStream * self,
|
|||||||
|
|
||||||
/* for subclasses */
|
/* for subclasses */
|
||||||
|
|
||||||
WpRemotePipewire *wp_audio_stream_get_remote (WpAudioStream * self);
|
WpCore *wp_audio_stream_get_core (WpAudioStream * self);
|
||||||
void wp_audio_stream_init_task_finish (WpAudioStream * self, GError * error);
|
void wp_audio_stream_init_task_finish (WpAudioStream * self, GError * error);
|
||||||
void wp_audio_stream_set_port_config (WpAudioStream * self,
|
void wp_audio_stream_set_port_config (WpAudioStream * self,
|
||||||
const struct spa_pod * param);
|
const struct spa_pod * param);
|
||||||
|
@@ -31,7 +31,6 @@ struct monitor {
|
|||||||
|
|
||||||
struct impl {
|
struct impl {
|
||||||
WpModule *module;
|
WpModule *module;
|
||||||
WpRemotePipewire *remote_pipewire;
|
|
||||||
GHashTable *registered_endpoints;
|
GHashTable *registered_endpoints;
|
||||||
|
|
||||||
/* The bluez monitor */
|
/* The bluez monitor */
|
||||||
@@ -204,9 +203,8 @@ is_bluez_node (WpProperties *props)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_node_added (WpRemotePipewire *rp, WpProxy *proxy, struct impl *data)
|
on_node_added (WpCore *core, WpProxy *proxy, struct impl *data)
|
||||||
{
|
{
|
||||||
g_autoptr (WpCore) core = wp_module_get_core (data->module);
|
|
||||||
const gchar *name, *media_class;
|
const gchar *name, *media_class;
|
||||||
enum pw_direction direction;
|
enum pw_direction direction;
|
||||||
GVariantBuilder b;
|
GVariantBuilder b;
|
||||||
@@ -246,7 +244,7 @@ on_node_added (WpRemotePipewire *rp, WpProxy *proxy, struct impl *data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_global_removed (WpRemotePipewire *rp, WpProxy *proxy, struct impl *data)
|
on_node_removed (WpCore *core, WpProxy *proxy, struct impl *data)
|
||||||
{
|
{
|
||||||
WpEndpoint *endpoint = NULL;
|
WpEndpoint *endpoint = NULL;
|
||||||
guint32 id = wp_proxy_get_global_id (proxy);
|
guint32 id = wp_proxy_get_global_id (proxy);
|
||||||
@@ -266,6 +264,7 @@ static struct node *
|
|||||||
create_node(struct impl *impl, struct device *dev, uint32_t id,
|
create_node(struct impl *impl, struct device *dev, uint32_t id,
|
||||||
const struct spa_device_object_info *info)
|
const struct spa_device_object_info *info)
|
||||||
{
|
{
|
||||||
|
g_autoptr (WpCore) core = wp_module_get_core (impl->module);
|
||||||
struct node *node;
|
struct node *node;
|
||||||
const char *name, *profile;
|
const char *name, *profile;
|
||||||
struct pw_properties *props = NULL;
|
struct pw_properties *props = NULL;
|
||||||
@@ -293,7 +292,7 @@ create_node(struct impl *impl, struct device *dev, uint32_t id,
|
|||||||
profile = "null";
|
profile = "null";
|
||||||
|
|
||||||
/* Find the factory */
|
/* Find the factory */
|
||||||
factory = wp_remote_pipewire_find_factory(impl->remote_pipewire, "adapter");
|
factory = pw_core_find_factory (wp_core_get_pw_core (core), "adapter");
|
||||||
g_return_val_if_fail (factory, NULL);
|
g_return_val_if_fail (factory, NULL);
|
||||||
|
|
||||||
/* Create the properties */
|
/* Create the properties */
|
||||||
@@ -317,7 +316,7 @@ create_node(struct impl *impl, struct device *dev, uint32_t id,
|
|||||||
node->id = id;
|
node->id = id;
|
||||||
node->props = props;
|
node->props = props;
|
||||||
node->adapter = adapter;
|
node->adapter = adapter;
|
||||||
node->proxy = wp_remote_pipewire_export(impl->remote_pipewire,
|
node->proxy = pw_remote_export (wp_core_get_pw_remote (core),
|
||||||
PW_TYPE_INTERFACE_Node, props, adapter, 0);
|
PW_TYPE_INTERFACE_Node, props, adapter, 0);
|
||||||
if (!node->proxy) {
|
if (!node->proxy) {
|
||||||
pw_properties_free(props);
|
pw_properties_free(props);
|
||||||
@@ -396,8 +395,9 @@ static const struct spa_device_events device_events = {
|
|||||||
|
|
||||||
static struct device*
|
static struct device*
|
||||||
create_device(struct impl *impl, uint32_t id,
|
create_device(struct impl *impl, uint32_t id,
|
||||||
const struct spa_monitor_object_info *info) {
|
const struct spa_monitor_object_info *info)
|
||||||
|
{
|
||||||
|
g_autoptr (WpCore) core = wp_module_get_core (impl->module);
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct spa_handle *handle;
|
struct spa_handle *handle;
|
||||||
int res;
|
int res;
|
||||||
@@ -408,8 +408,8 @@ create_device(struct impl *impl, uint32_t id,
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Load the device handle */
|
/* Load the device handle */
|
||||||
handle = (struct spa_handle *)wp_remote_pipewire_load_spa_handle (
|
handle = pw_core_load_spa_handle (wp_core_get_pw_core (core),
|
||||||
impl->remote_pipewire, info->factory_name, info->props);
|
info->factory_name, info->props);
|
||||||
if (!handle)
|
if (!handle)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@@ -427,7 +427,8 @@ create_device(struct impl *impl, uint32_t id,
|
|||||||
dev->handle = handle;
|
dev->handle = handle;
|
||||||
dev->device = iface;
|
dev->device = iface;
|
||||||
dev->props = pw_properties_new_dict(info->props);
|
dev->props = pw_properties_new_dict(info->props);
|
||||||
dev->proxy = wp_remote_pipewire_export (impl->remote_pipewire, info->type, dev->props, dev->device, 0);
|
dev->proxy = pw_remote_export (wp_core_get_pw_remote (core),
|
||||||
|
info->type, dev->props, dev->device, 0);
|
||||||
if (!dev->proxy) {
|
if (!dev->proxy) {
|
||||||
pw_unload_spa_handle(handle);
|
pw_unload_spa_handle(handle);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -526,7 +527,7 @@ static const struct spa_monitor_callbacks monitor_callbacks =
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
start_monitor (WpRemotePipewire *remote, WpRemoteState state, gpointer data)
|
start_monitor (WpCore *core, WpRemoteState state, gpointer data)
|
||||||
{
|
{
|
||||||
struct impl *impl = data;
|
struct impl *impl = data;
|
||||||
struct spa_handle *handle;
|
struct spa_handle *handle;
|
||||||
@@ -534,8 +535,8 @@ start_monitor (WpRemotePipewire *remote, WpRemoteState state, gpointer data)
|
|||||||
void *iface;
|
void *iface;
|
||||||
|
|
||||||
/* Load the monitor handle */
|
/* Load the monitor handle */
|
||||||
handle = (struct spa_handle *)wp_remote_pipewire_load_spa_handle (
|
handle = pw_core_load_spa_handle (wp_core_get_pw_core (core),
|
||||||
impl->remote_pipewire, SPA_NAME_API_BLUEZ5_MONITOR, NULL);
|
SPA_NAME_API_BLUEZ5_MONITOR, NULL);
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
g_message ("SPA bluez5 plugin could not be loaded; is it installed?");
|
g_message ("SPA bluez5 plugin could not be loaded; is it installed?");
|
||||||
return;
|
return;
|
||||||
@@ -563,9 +564,8 @@ module_destroy (gpointer data)
|
|||||||
{
|
{
|
||||||
struct impl *impl = data;
|
struct impl *impl = data;
|
||||||
|
|
||||||
/* Set to NULL module and remote pipewire as we don't own the reference */
|
/* Set to NULL as we don't own the reference */
|
||||||
impl->module = NULL;
|
impl->module = NULL;
|
||||||
impl->remote_pipewire = NULL;
|
|
||||||
|
|
||||||
/* Destroy the registered endpoints table */
|
/* Destroy the registered endpoints table */
|
||||||
g_hash_table_unref(impl->registered_endpoints);
|
g_hash_table_unref(impl->registered_endpoints);
|
||||||
@@ -579,20 +579,10 @@ void
|
|||||||
wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args)
|
wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args)
|
||||||
{
|
{
|
||||||
struct impl *impl;
|
struct impl *impl;
|
||||||
WpRemotePipewire *rp;
|
|
||||||
|
|
||||||
/* Make sure the remote pipewire is valid */
|
|
||||||
rp = wp_core_get_global (core, WP_GLOBAL_REMOTE_PIPEWIRE);
|
|
||||||
if (!rp) {
|
|
||||||
g_critical ("module-pw-bluez cannot be loaded without a registered "
|
|
||||||
"WpRemotePipewire object");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create the module data */
|
/* Create the module data */
|
||||||
impl = g_slice_new0(struct impl);
|
impl = g_slice_new0(struct impl);
|
||||||
impl->module = module;
|
impl->module = module;
|
||||||
impl->remote_pipewire = rp;
|
|
||||||
impl->registered_endpoints = g_hash_table_new_full (g_direct_hash,
|
impl->registered_endpoints = g_hash_table_new_full (g_direct_hash,
|
||||||
g_direct_equal, NULL, (GDestroyNotify)g_object_unref);
|
g_direct_equal, NULL, (GDestroyNotify)g_object_unref);
|
||||||
|
|
||||||
@@ -600,12 +590,16 @@ wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args)
|
|||||||
wp_module_set_destroy_callback (module, module_destroy, impl);
|
wp_module_set_destroy_callback (module, module_destroy, impl);
|
||||||
|
|
||||||
/* Add the spa lib */
|
/* Add the spa lib */
|
||||||
wp_remote_pipewire_add_spa_lib (rp, "api.bluez5.*", "bluez5/libspa-bluez5");
|
pw_core_add_spa_lib (wp_core_get_pw_core (core),
|
||||||
|
"api.bluez5.*", "bluez5/libspa-bluez5");
|
||||||
|
|
||||||
/* Start the monitor when the connected callback is triggered */
|
/* Start the monitor when the connected callback is triggered */
|
||||||
g_signal_connect(rp, "state-changed::connected", (GCallback)start_monitor, impl);
|
g_signal_connect(core, "remote-state-changed::connected",
|
||||||
|
(GCallback) start_monitor, impl);
|
||||||
|
|
||||||
/* Register the global added/removed callbacks */
|
/* Register the global addded/removed callbacks */
|
||||||
g_signal_connect(rp, "global-added::node", (GCallback)on_node_added, impl);
|
g_signal_connect(core, "remote-global-added::node",
|
||||||
g_signal_connect(rp, "global-removed", (GCallback)on_global_removed, impl);
|
(GCallback) on_node_added, impl);
|
||||||
|
g_signal_connect(core, "remote-global-removed::node",
|
||||||
|
(GCallback) on_node_removed, impl);
|
||||||
}
|
}
|
||||||
|
15
src/main.c
15
src/main.c
@@ -29,7 +29,6 @@ enum WpExitCode
|
|||||||
struct WpDaemonData
|
struct WpDaemonData
|
||||||
{
|
{
|
||||||
WpCore *core;
|
WpCore *core;
|
||||||
WpRemote *remote;
|
|
||||||
GMainLoop *loop;
|
GMainLoop *loop;
|
||||||
|
|
||||||
gint exit_code;
|
gint exit_code;
|
||||||
@@ -67,7 +66,7 @@ signal_handler (gpointer data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
remote_state_changed (WpRemote *remote, WpRemoteState state,
|
remote_state_changed (WpCore *core, WpRemoteState state,
|
||||||
struct WpDaemonData * d)
|
struct WpDaemonData * d)
|
||||||
{
|
{
|
||||||
/* something else triggered the exit; we will certainly get a state
|
/* something else triggered the exit; we will certainly get a state
|
||||||
@@ -82,7 +81,7 @@ remote_state_changed (WpRemote *remote, WpRemoteState state,
|
|||||||
break;
|
break;
|
||||||
case WP_REMOTE_STATE_ERROR: {
|
case WP_REMOTE_STATE_ERROR: {
|
||||||
g_autofree gchar *error;
|
g_autofree gchar *error;
|
||||||
g_object_get (remote, "error-message", &error, NULL);
|
g_object_get (core, "error-message", &error, NULL);
|
||||||
daemon_exit (d, WP_CODE_OPERATION_FAILED, "pipewire remote error: %s",
|
daemon_exit (d, WP_CODE_OPERATION_FAILED, "pipewire remote error: %s",
|
||||||
error);
|
error);
|
||||||
break;
|
break;
|
||||||
@@ -240,7 +239,7 @@ load_commands_file (struct WpDaemonData *d)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* connect to pipewire */
|
/* connect to pipewire */
|
||||||
wp_remote_connect (d->remote);
|
wp_core_connect (d->core);
|
||||||
|
|
||||||
return G_SOURCE_REMOVE;
|
return G_SOURCE_REMOVE;
|
||||||
}
|
}
|
||||||
@@ -251,7 +250,6 @@ main (gint argc, gchar **argv)
|
|||||||
struct WpDaemonData data = {0};
|
struct WpDaemonData data = {0};
|
||||||
g_autoptr (GOptionContext) context = NULL;
|
g_autoptr (GOptionContext) context = NULL;
|
||||||
g_autoptr (GError) error = NULL;
|
g_autoptr (GError) error = NULL;
|
||||||
g_autoptr (WpRemote) remote = NULL;
|
|
||||||
g_autoptr (WpCore) core = NULL;
|
g_autoptr (WpCore) core = NULL;
|
||||||
g_autoptr (GMainLoop) loop = NULL;
|
g_autoptr (GMainLoop) loop = NULL;
|
||||||
|
|
||||||
@@ -265,10 +263,9 @@ main (gint argc, gchar **argv)
|
|||||||
|
|
||||||
/* init wireplumber */
|
/* init wireplumber */
|
||||||
|
|
||||||
data.core = core = wp_core_new ();
|
data.core = core = wp_core_new (NULL);
|
||||||
data.remote = remote = wp_remote_pipewire_new (core, NULL);
|
g_signal_connect (core, "remote-state-changed",
|
||||||
g_signal_connect (remote, "state-changed", (GCallback) remote_state_changed,
|
(GCallback) remote_state_changed, &data);
|
||||||
&data);
|
|
||||||
|
|
||||||
/* init main loop */
|
/* init main loop */
|
||||||
|
|
||||||
|
@@ -20,9 +20,8 @@ typedef struct {
|
|||||||
GMainLoop *loop;
|
GMainLoop *loop;
|
||||||
GSource *timeout_source;
|
GSource *timeout_source;
|
||||||
|
|
||||||
/* the client wireplumber objects */
|
/* the client wireplumber core */
|
||||||
WpCore *core;
|
WpCore *core;
|
||||||
WpRemote *remote;
|
|
||||||
|
|
||||||
} TestProxyFixture;
|
} TestProxyFixture;
|
||||||
|
|
||||||
@@ -37,14 +36,14 @@ timeout_callback (TestProxyFixture *fixture)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_proxy_state_changed (WpRemote *remote, WpRemoteState state,
|
test_proxy_remote_state_changed (WpCore *core, WpRemoteState state,
|
||||||
TestProxyFixture *fixture)
|
TestProxyFixture *fixture)
|
||||||
{
|
{
|
||||||
g_autofree gchar * msg = NULL;
|
const gchar * msg = NULL;
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case WP_REMOTE_STATE_ERROR:
|
case WP_REMOTE_STATE_ERROR:
|
||||||
g_object_get (remote, "error-message", &msg, NULL);
|
wp_core_get_remote_state (core, &msg);
|
||||||
g_message ("remote error: %s", msg);
|
g_message ("remote error: %s", msg);
|
||||||
g_test_fail ();
|
g_test_fail ();
|
||||||
g_main_loop_quit (fixture->loop);
|
g_main_loop_quit (fixture->loop);
|
||||||
@@ -61,14 +60,13 @@ test_proxy_setup (TestProxyFixture *self, gconstpointer user_data)
|
|||||||
g_setenv ("PIPEWIRE_REMOTE", self->server.name, TRUE);
|
g_setenv ("PIPEWIRE_REMOTE", self->server.name, TRUE);
|
||||||
self->context = g_main_context_new ();
|
self->context = g_main_context_new ();
|
||||||
self->loop = g_main_loop_new (self->context, FALSE);
|
self->loop = g_main_loop_new (self->context, FALSE);
|
||||||
self->core = wp_core_new ();
|
self->core = wp_core_new (self->context);
|
||||||
self->remote = wp_remote_pipewire_new (self->core, self->context);
|
|
||||||
|
|
||||||
g_main_context_push_thread_default (self->context);
|
g_main_context_push_thread_default (self->context);
|
||||||
|
|
||||||
/* watchdogs */
|
/* watchdogs */
|
||||||
g_signal_connect (self->remote, "state-changed",
|
g_signal_connect (self->core, "remote-state-changed",
|
||||||
(GCallback) test_proxy_state_changed, self);
|
(GCallback) test_proxy_remote_state_changed, self);
|
||||||
|
|
||||||
self->timeout_source = g_timeout_source_new_seconds (3);
|
self->timeout_source = g_timeout_source_new_seconds (3);
|
||||||
g_source_set_callback (self->timeout_source, (GSourceFunc) timeout_callback,
|
g_source_set_callback (self->timeout_source, (GSourceFunc) timeout_callback,
|
||||||
@@ -81,7 +79,6 @@ test_proxy_teardown (TestProxyFixture *self, gconstpointer user_data)
|
|||||||
{
|
{
|
||||||
g_main_context_pop_thread_default (self->context);
|
g_main_context_pop_thread_default (self->context);
|
||||||
|
|
||||||
g_clear_object (&self->remote);
|
|
||||||
g_clear_object (&self->core);
|
g_clear_object (&self->core);
|
||||||
g_clear_pointer (&self->timeout_source, g_source_unref);
|
g_clear_pointer (&self->timeout_source, g_source_unref);
|
||||||
g_clear_pointer (&self->loop, g_main_loop_unref);
|
g_clear_pointer (&self->loop, g_main_loop_unref);
|
||||||
@@ -117,13 +114,14 @@ test_proxy_basic_augmented (WpProxy *proxy, GAsyncResult *res,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_proxy_basic_global_added (WpRemote *remote, WpProxy *proxy,
|
test_proxy_basic_remote_global_added (WpCore *core, WpProxy *proxy,
|
||||||
TestProxyFixture *fixture)
|
TestProxyFixture *fixture)
|
||||||
{
|
{
|
||||||
g_assert_nonnull (proxy);
|
g_assert_nonnull (proxy);
|
||||||
{
|
{
|
||||||
g_autoptr (WpRemote) remote = wp_proxy_get_remote (proxy);
|
g_autoptr (WpCore) pcore = wp_proxy_get_core (proxy);
|
||||||
g_assert_nonnull (remote);
|
g_assert_nonnull (pcore);
|
||||||
|
g_assert_true (pcore == core);
|
||||||
}
|
}
|
||||||
g_assert_cmpuint (wp_proxy_get_global_id (proxy), !=, 0);
|
g_assert_cmpuint (wp_proxy_get_global_id (proxy), !=, 0);
|
||||||
g_assert_true (wp_proxy_is_global (proxy));
|
g_assert_true (wp_proxy_is_global (proxy));
|
||||||
@@ -155,10 +153,10 @@ test_proxy_basic (TestProxyFixture *fixture, gconstpointer data)
|
|||||||
{
|
{
|
||||||
/* our test server should advertise exactly one
|
/* our test server should advertise exactly one
|
||||||
* client: our WpRemote; use this to test WpProxy */
|
* client: our WpRemote; use this to test WpProxy */
|
||||||
g_signal_connect (fixture->remote, "global-added::client",
|
g_signal_connect (fixture->core, "remote-global-added::client",
|
||||||
(GCallback) test_proxy_basic_global_added, fixture);
|
(GCallback) test_proxy_basic_remote_global_added, fixture);
|
||||||
|
|
||||||
g_assert_true (wp_remote_connect (fixture->remote));
|
g_assert_true (wp_core_connect (fixture->core));
|
||||||
g_main_loop_run (fixture->loop);
|
g_main_loop_run (fixture->loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,7 +197,7 @@ test_proxy_node_enum_params_done (WpProxyNode *node, GAsyncResult *res,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_proxy_node_global_added (WpRemote *remote, WpProxy *proxy,
|
test_proxy_node_remote_global_added (WpCore *core, WpProxy *proxy,
|
||||||
TestProxyFixture *fixture)
|
TestProxyFixture *fixture)
|
||||||
{
|
{
|
||||||
const struct pw_node_info *info;
|
const struct pw_node_info *info;
|
||||||
@@ -256,14 +254,14 @@ test_proxy_node (TestProxyFixture *fixture, gconstpointer data)
|
|||||||
pw_thread_loop_unlock (fixture->server.thread_loop);
|
pw_thread_loop_unlock (fixture->server.thread_loop);
|
||||||
|
|
||||||
/* we should be able to see this exported audiotestsrc node on the client */
|
/* we should be able to see this exported audiotestsrc node on the client */
|
||||||
g_signal_connect (fixture->remote, "global-added::node",
|
g_signal_connect (fixture->core, "remote-global-added::node",
|
||||||
(GCallback) test_proxy_node_global_added, fixture);
|
(GCallback) test_proxy_node_remote_global_added, fixture);
|
||||||
|
|
||||||
/* tell the remote to call global-added only when these features are ready */
|
/* tell the remote to call global-added only when these features are ready */
|
||||||
wp_remote_pipewire_set_default_features (WP_REMOTE_PIPEWIRE (fixture->remote),
|
wp_core_set_default_proxy_features (fixture->core,
|
||||||
WP_TYPE_PROXY_NODE, WP_PROXY_FEATURE_PW_PROXY | WP_PROXY_FEATURE_INFO);
|
WP_TYPE_PROXY_NODE, WP_PROXY_FEATURE_PW_PROXY | WP_PROXY_FEATURE_INFO);
|
||||||
|
|
||||||
g_assert_true (wp_remote_connect (fixture->remote));
|
g_assert_true (wp_core_connect (fixture->core));
|
||||||
g_main_loop_run (fixture->loop);
|
g_main_loop_run (fixture->loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user