Merge remote-tracking branch 'origin/master' into proxy-refactoring
This commit is contained in:
@@ -93,6 +93,7 @@ struct _WpEndpointPrivate
|
||||
{
|
||||
gchar *name;
|
||||
gchar media_class[40];
|
||||
guint direction;
|
||||
GPtrArray *streams;
|
||||
GPtrArray *controls;
|
||||
GPtrArray *links;
|
||||
@@ -104,6 +105,7 @@ enum {
|
||||
PROP_CORE,
|
||||
PROP_NAME,
|
||||
PROP_MEDIA_CLASS,
|
||||
PROP_DIRECTION,
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -211,6 +213,9 @@ wp_endpoint_set_property (GObject * object, guint property_id,
|
||||
strncpy (priv->media_class, g_value_get_string (value),
|
||||
sizeof (priv->media_class) - 1);
|
||||
break;
|
||||
case PROP_DIRECTION:
|
||||
priv->direction = g_value_get_uint(value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
@@ -234,6 +239,9 @@ wp_endpoint_get_property (GObject * object, guint property_id, GValue * value,
|
||||
case PROP_MEDIA_CLASS:
|
||||
g_value_set_string (value, priv->media_class);
|
||||
break;
|
||||
case PROP_DIRECTION:
|
||||
g_value_set_uint (value, priv->direction);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
@@ -281,6 +289,15 @@ wp_endpoint_class_init (WpEndpointClass * klass)
|
||||
signals[SIGNAL_NOTIFY_CONTROL_VALUE] = g_signal_new ("notify-control-value",
|
||||
G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 1, G_TYPE_UINT);
|
||||
|
||||
/**
|
||||
* WpEndpoint::direction:
|
||||
* The direction of the endpoint: input = 0, output = 1.
|
||||
*/
|
||||
g_object_class_install_property (object_class, PROP_DIRECTION,
|
||||
g_param_spec_uint ("direction", "direction",
|
||||
"The direction of the endpoint", 0, 1, 0,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -465,6 +482,17 @@ wp_endpoint_get_media_class (WpEndpoint * self)
|
||||
return priv->media_class;
|
||||
}
|
||||
|
||||
guint
|
||||
wp_endpoint_get_direction (WpEndpoint * self)
|
||||
{
|
||||
WpEndpointPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (WP_IS_ENDPOINT (self), -1);
|
||||
|
||||
priv = wp_endpoint_get_instance_private (self);
|
||||
return priv->direction;
|
||||
}
|
||||
|
||||
/**
|
||||
* wp_endpoint_register_stream:
|
||||
* @self: the endpoint
|
||||
|
@@ -48,6 +48,7 @@ GPtrArray * wp_endpoint_find (WpCore * core, const gchar * media_class_lookup);
|
||||
WpCore *wp_endpoint_get_core (WpEndpoint * self);
|
||||
const gchar * wp_endpoint_get_name (WpEndpoint * self);
|
||||
const gchar * wp_endpoint_get_media_class (WpEndpoint * self);
|
||||
guint wp_endpoint_get_direction (WpEndpoint * self);
|
||||
|
||||
void wp_endpoint_register_stream (WpEndpoint * self, GVariant * stream);
|
||||
GVariant * wp_endpoint_get_stream (WpEndpoint * self, guint32 stream_id);
|
||||
|
@@ -42,9 +42,6 @@ struct _WpPipewireSimpleEndpoint
|
||||
/* Handler */
|
||||
gulong proxy_node_done_handler_id;
|
||||
|
||||
/* Direction */
|
||||
enum pw_direction direction;
|
||||
|
||||
/* Proxies */
|
||||
WpProxyNode *proxy_node;
|
||||
struct spa_hook node_proxy_listener;
|
||||
@@ -230,6 +227,7 @@ on_port_added(WpRemotePipewire *rp, guint id, gconstpointer p, gpointer d)
|
||||
static void
|
||||
emit_endpoint_ports(WpPipewireSimpleEndpoint *self)
|
||||
{
|
||||
enum pw_direction direction = wp_endpoint_get_direction (WP_ENDPOINT (self));
|
||||
struct pw_node_proxy* node_proxy = NULL;
|
||||
struct spa_audio_info_raw format = { 0, };
|
||||
struct spa_pod *param;
|
||||
@@ -252,7 +250,7 @@ emit_endpoint_ports(WpPipewireSimpleEndpoint *self)
|
||||
param = spa_format_audio_raw_build(&pod_builder, SPA_PARAM_Format, &format);
|
||||
param = spa_pod_builder_add_object(&pod_builder,
|
||||
SPA_TYPE_OBJECT_ParamPortConfig, SPA_PARAM_PortConfig,
|
||||
SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(self->direction),
|
||||
SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(direction),
|
||||
SPA_PARAM_PORT_CONFIG_mode, SPA_POD_Id(SPA_PARAM_PORT_CONFIG_MODE_dsp),
|
||||
SPA_PARAM_PORT_CONFIG_format, SPA_POD_Pod(param));
|
||||
|
||||
@@ -323,7 +321,6 @@ wp_simple_endpoint_init_async (GAsyncInitable *initable, int io_priority,
|
||||
{
|
||||
WpPipewireSimpleEndpoint *self = WP_PIPEWIRE_SIMPLE_ENDPOINT (initable);
|
||||
g_autoptr (WpCore) core = wp_endpoint_get_core(WP_ENDPOINT(self));
|
||||
const gchar *media_class = wp_endpoint_get_media_class (WP_ENDPOINT (self));
|
||||
struct pw_node_proxy *node_proxy = NULL;
|
||||
|
||||
/* Create the async task */
|
||||
@@ -332,14 +329,6 @@ wp_simple_endpoint_init_async (GAsyncInitable *initable, int io_priority,
|
||||
/* Init the proxies_port array */
|
||||
self->proxies_port = g_ptr_array_new_full(2, (GDestroyNotify)g_object_unref);
|
||||
|
||||
/* Set the direction */
|
||||
if (g_str_has_prefix (media_class, "Stream/Input"))
|
||||
self->direction = PW_DIRECTION_INPUT;
|
||||
else if (g_str_has_prefix (media_class, "Stream/Output"))
|
||||
self->direction = PW_DIRECTION_OUTPUT;
|
||||
else
|
||||
g_critical ("failed to parse direction");
|
||||
|
||||
/* Register a port_added callback */
|
||||
self->remote_pipewire = wp_core_get_global (core, WP_GLOBAL_REMOTE_PIPEWIRE);
|
||||
g_return_if_fail(self->remote_pipewire);
|
||||
@@ -579,6 +568,7 @@ simple_endpoint_factory (WpFactory * factory, GType type,
|
||||
{
|
||||
g_autoptr (WpCore) core = NULL;
|
||||
const gchar *name, *media_class;
|
||||
guint direction;
|
||||
guint global_id;
|
||||
|
||||
/* Make sure the type is correct */
|
||||
@@ -593,6 +583,8 @@ simple_endpoint_factory (WpFactory * factory, GType type,
|
||||
return;
|
||||
if (!g_variant_lookup (properties, "media-class", "&s", &media_class))
|
||||
return;
|
||||
if (!g_variant_lookup (properties, "direction", "u", &direction))
|
||||
return;
|
||||
if (!g_variant_lookup (properties, "global-id", "u", &global_id))
|
||||
return;
|
||||
|
||||
@@ -601,6 +593,7 @@ simple_endpoint_factory (WpFactory * factory, GType type,
|
||||
"core", core,
|
||||
"name", name,
|
||||
"media-class", media_class,
|
||||
"direction", direction,
|
||||
"global-id", global_id,
|
||||
NULL);
|
||||
}
|
||||
|
@@ -96,6 +96,7 @@ on_node_added(WpRemotePipewire *rp, guint id, gconstpointer p, gpointer d)
|
||||
const struct spa_dict *props = p;
|
||||
g_autoptr (WpCore) core = wp_module_get_core (impl->module);
|
||||
const gchar *media_class, *name;
|
||||
enum pw_direction direction;
|
||||
GVariantBuilder b;
|
||||
g_autoptr (GVariant) endpoint_props = NULL;
|
||||
|
||||
@@ -116,12 +117,28 @@ on_node_added(WpRemotePipewire *rp, guint id, gconstpointer p, gpointer d)
|
||||
if (!name)
|
||||
name = spa_dict_lookup (props, "node.name");
|
||||
|
||||
/* Don't handle bluetooth nodes */
|
||||
if (g_str_has_prefix (name, "api.bluez5"))
|
||||
return;
|
||||
|
||||
/* Get the direction */
|
||||
if (g_str_has_prefix (media_class, "Audio/Sink")) {
|
||||
direction = PW_DIRECTION_INPUT;
|
||||
} else if (g_str_has_prefix (media_class, "Audio/Source")) {
|
||||
direction = PW_DIRECTION_OUTPUT;
|
||||
} else {
|
||||
g_critical ("failed to parse direction");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set the properties */
|
||||
g_variant_builder_init (&b, G_VARIANT_TYPE_VARDICT);
|
||||
g_variant_builder_add (&b, "{sv}",
|
||||
"name", g_variant_new_string (name));
|
||||
g_variant_builder_add (&b, "{sv}",
|
||||
"media-class", g_variant_new_string (media_class));
|
||||
g_variant_builder_add (&b, "{sv}",
|
||||
"direction", g_variant_new_uint32 (direction));
|
||||
g_variant_builder_add (&b, "{sv}",
|
||||
"global-id", g_variant_new_uint32 (id));
|
||||
g_variant_builder_add (&b, "{sv}",
|
||||
|
@@ -57,6 +57,7 @@ on_node_added (WpRemotePipewire *rp, guint id, gconstpointer p, gpointer d)
|
||||
const struct spa_dict *props = p;
|
||||
g_autoptr (WpCore) core = wp_module_get_core (data->module);
|
||||
const gchar *name, *media_class;
|
||||
enum pw_direction direction;
|
||||
GVariantBuilder b;
|
||||
g_autoptr (GVariant) endpoint_props = NULL;
|
||||
|
||||
@@ -70,6 +71,16 @@ on_node_added (WpRemotePipewire *rp, guint id, gconstpointer p, gpointer d)
|
||||
if (!g_str_has_prefix (media_class, "Stream/"))
|
||||
return;
|
||||
|
||||
/* Get the direction */
|
||||
if (g_str_has_prefix (media_class, "Stream/Input")) {
|
||||
direction = PW_DIRECTION_INPUT;
|
||||
} else if (g_str_has_prefix (media_class, "Stream/Output")) {
|
||||
direction = PW_DIRECTION_OUTPUT;
|
||||
} else {
|
||||
g_critical ("failed to parse direction");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the name */
|
||||
name = spa_dict_lookup (props, "media.name");
|
||||
if (!name)
|
||||
@@ -83,6 +94,8 @@ on_node_added (WpRemotePipewire *rp, guint id, gconstpointer p, gpointer d)
|
||||
g_variant_new_take_string (g_strdup_printf ("Stream %u", id)));
|
||||
g_variant_builder_add (&b, "{sv}",
|
||||
"media-class", g_variant_new_string (media_class));
|
||||
g_variant_builder_add (&b, "{sv}",
|
||||
"direction", g_variant_new_uint32 (direction));
|
||||
g_variant_builder_add (&b, "{sv}",
|
||||
"global-id", g_variant_new_uint32 (id));
|
||||
endpoint_props = g_variant_builder_end (&b);
|
||||
|
@@ -42,9 +42,6 @@ struct _WpPwAudioSoftdspEndpoint
|
||||
GTask *init_task;
|
||||
gboolean init_abort;
|
||||
|
||||
/* Direction */
|
||||
enum pw_direction direction;
|
||||
|
||||
/* Audio Streams */
|
||||
WpAudioStream *adapter;
|
||||
GPtrArray *converters;
|
||||
@@ -162,6 +159,7 @@ on_audio_adapter_created(GObject *initable, GAsyncResult *res,
|
||||
gpointer data)
|
||||
{
|
||||
WpPwAudioSoftdspEndpoint *self = data;
|
||||
enum pw_direction direction = wp_endpoint_get_direction(WP_ENDPOINT(self));
|
||||
g_autoptr (WpCore) core = wp_endpoint_get_core(WP_ENDPOINT(self));
|
||||
g_autofree gchar *name = NULL;
|
||||
const struct pw_node_info *adapter_info = NULL;
|
||||
@@ -193,8 +191,8 @@ on_audio_adapter_created(GObject *initable, GAsyncResult *res,
|
||||
/* Create the audio converters */
|
||||
g_variant_iter_init (&iter, self->streams);
|
||||
for (i = 0; g_variant_iter_next (&iter, "&s", &stream); i++) {
|
||||
wp_audio_convert_new (WP_ENDPOINT(self), i, stream, self->direction,
|
||||
adapter_info, on_audio_convert_created, self);
|
||||
wp_audio_convert_new (WP_ENDPOINT(self), i, stream, direction, adapter_info,
|
||||
on_audio_convert_created, self);
|
||||
|
||||
/* Register the stream */
|
||||
g_variant_dict_init (&d, NULL);
|
||||
@@ -316,24 +314,16 @@ wp_endpoint_init_async (GAsyncInitable *initable, int io_priority,
|
||||
GCancellable *cancellable, GAsyncReadyCallback callback, gpointer data)
|
||||
{
|
||||
WpPwAudioSoftdspEndpoint *self = WP_PW_AUDIO_SOFTDSP_ENDPOINT (initable);
|
||||
enum pw_direction direction = wp_endpoint_get_direction(WP_ENDPOINT(self));
|
||||
g_autoptr (WpCore) core = wp_endpoint_get_core(WP_ENDPOINT(self));
|
||||
const gchar *media_class = wp_endpoint_get_media_class (WP_ENDPOINT (self));
|
||||
GVariantDict d;
|
||||
|
||||
/* Create the async task */
|
||||
self->init_task = g_task_new (initable, cancellable, callback, data);
|
||||
|
||||
/* Set the direction */
|
||||
if (g_str_has_suffix (media_class, "Source"))
|
||||
self->direction = PW_DIRECTION_OUTPUT;
|
||||
else if (g_str_has_suffix (media_class, "Sink"))
|
||||
self->direction = PW_DIRECTION_INPUT;
|
||||
else
|
||||
g_critical ("failed to parse direction");
|
||||
|
||||
/* Create the adapter proxy */
|
||||
wp_audio_adapter_new (WP_ENDPOINT(self), WP_STREAM_ID_NONE, "master",
|
||||
self->direction, self->global_id, FALSE, on_audio_adapter_created, self);
|
||||
direction, self->global_id, FALSE, on_audio_adapter_created, self);
|
||||
|
||||
/* Register the selected control */
|
||||
self->selected = FALSE;
|
||||
@@ -401,6 +391,7 @@ endpoint_factory (WpFactory * factory, GType type, GVariant * properties,
|
||||
{
|
||||
g_autoptr (WpCore) core = NULL;
|
||||
const gchar *name, *media_class;
|
||||
guint direction;
|
||||
guint global_id;
|
||||
g_autoptr (GVariant) streams = NULL;
|
||||
|
||||
@@ -416,6 +407,8 @@ endpoint_factory (WpFactory * factory, GType type, GVariant * properties,
|
||||
return;
|
||||
if (!g_variant_lookup (properties, "media-class", "&s", &media_class))
|
||||
return;
|
||||
if (!g_variant_lookup (properties, "direction", "u", &direction))
|
||||
return;
|
||||
if (!g_variant_lookup (properties, "global-id", "u", &global_id))
|
||||
return;
|
||||
if (!(streams = g_variant_lookup_value (properties, "streams",
|
||||
@@ -428,6 +421,7 @@ endpoint_factory (WpFactory * factory, GType type, GVariant * properties,
|
||||
"core", core,
|
||||
"name", name,
|
||||
"media-class", media_class,
|
||||
"direction", direction,
|
||||
"global-id", global_id,
|
||||
"streams", streams,
|
||||
NULL);
|
||||
|
@@ -26,6 +26,7 @@ struct _WpAudioAdapter
|
||||
/* The task to signal the proxy is initialized */
|
||||
GTask *init_task;
|
||||
gboolean init_abort;
|
||||
gboolean ports_done;
|
||||
|
||||
/* Props */
|
||||
guint adapter_id;
|
||||
@@ -79,9 +80,45 @@ on_audio_adapter_done(WpProxy *proxy, gpointer data)
|
||||
{
|
||||
WpAudioAdapter *self = data;
|
||||
|
||||
/* Emit the ports if not done and sync again */
|
||||
if (!self->ports_done) {
|
||||
enum pw_direction direction =
|
||||
wp_audio_stream_get_direction ( WP_AUDIO_STREAM (self));
|
||||
struct pw_node_proxy *pw_proxy = NULL;
|
||||
uint8_t buf[1024];
|
||||
struct spa_pod_builder pod_builder = SPA_POD_BUILDER_INIT(buf, sizeof(buf));
|
||||
struct spa_pod *param;
|
||||
|
||||
/* Emit the props param */
|
||||
pw_proxy = wp_proxy_get_pw_proxy(WP_PROXY(self->proxy));
|
||||
pw_node_proxy_enum_params (pw_proxy, 0, SPA_PARAM_Props, 0, -1, NULL);
|
||||
|
||||
/* Emit the ports */
|
||||
if (self->convert) {
|
||||
param = spa_pod_builder_add_object(&pod_builder,
|
||||
SPA_TYPE_OBJECT_ParamPortConfig, SPA_PARAM_PortConfig,
|
||||
SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(direction),
|
||||
SPA_PARAM_PORT_CONFIG_mode, SPA_POD_Id(SPA_PARAM_PORT_CONFIG_MODE_convert));
|
||||
} else {
|
||||
struct spa_audio_info_raw format = *wp_proxy_node_get_format (self->proxy);
|
||||
param = spa_format_audio_raw_build(&pod_builder, SPA_PARAM_Format, &format);
|
||||
param = spa_pod_builder_add_object(&pod_builder,
|
||||
SPA_TYPE_OBJECT_ParamPortConfig, SPA_PARAM_PortConfig,
|
||||
SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(direction),
|
||||
SPA_PARAM_PORT_CONFIG_mode, SPA_POD_Id(SPA_PARAM_PORT_CONFIG_MODE_dsp),
|
||||
SPA_PARAM_PORT_CONFIG_format, SPA_POD_Pod(param));
|
||||
}
|
||||
pw_node_proxy_set_param(pw_proxy, SPA_PARAM_PortConfig, 0, param);
|
||||
|
||||
/* Sync */
|
||||
self->ports_done = TRUE;
|
||||
wp_proxy_sync (WP_PROXY(self->proxy));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Don't do anything if the audio adapter has already been initialized */
|
||||
if (!self->init_task)
|
||||
return;
|
||||
return;
|
||||
|
||||
/* Finish the creation of the audio adapter */
|
||||
g_task_return_boolean (self->init_task, TRUE);
|
||||
@@ -93,12 +130,6 @@ on_audio_adapter_proxy_created(GObject *initable, GAsyncResult *res,
|
||||
gpointer data)
|
||||
{
|
||||
WpAudioAdapter *self = data;
|
||||
enum pw_direction direction =
|
||||
wp_audio_stream_get_direction ( WP_AUDIO_STREAM (self));
|
||||
struct pw_node_proxy *pw_proxy = NULL;
|
||||
uint8_t buf[1024];
|
||||
struct spa_pod_builder pod_builder = SPA_POD_BUILDER_INIT(buf, sizeof(buf));
|
||||
struct spa_pod *param;
|
||||
|
||||
/* Get the adapter proxy */
|
||||
self->proxy = WP_PROXY_NODE (object_safe_new_finish (self, initable,
|
||||
@@ -106,39 +137,10 @@ on_audio_adapter_proxy_created(GObject *initable, GAsyncResult *res,
|
||||
if (!self->proxy)
|
||||
return;
|
||||
|
||||
/* Get the pipewire proxy */
|
||||
pw_proxy = wp_proxy_get_pw_proxy(WP_PROXY(self->proxy));
|
||||
g_return_if_fail (pw_proxy);
|
||||
/* Emit the EnumFormat param */
|
||||
wp_proxy_node_enum_params (self->proxy, 0, SPA_PARAM_EnumFormat, 0, -1, NULL);
|
||||
|
||||
/* Emit the props param */
|
||||
pw_node_proxy_enum_params (pw_proxy, 0, SPA_PARAM_Props, 0, -1, NULL);
|
||||
|
||||
/* Emit the ports */
|
||||
if (self->convert) {
|
||||
param = spa_pod_builder_add_object(&pod_builder,
|
||||
SPA_TYPE_OBJECT_ParamPortConfig, SPA_PARAM_PortConfig,
|
||||
SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(direction),
|
||||
SPA_PARAM_PORT_CONFIG_mode, SPA_POD_Id(SPA_PARAM_PORT_CONFIG_MODE_convert));
|
||||
pw_node_proxy_set_param(pw_proxy, SPA_PARAM_PortConfig, 0, param);
|
||||
} else {
|
||||
struct spa_audio_info_raw format;
|
||||
spa_zero(format);
|
||||
format.format = SPA_AUDIO_FORMAT_F32P;
|
||||
format.flags = 1;
|
||||
format.rate = 48000;
|
||||
format.channels = 2;
|
||||
format.position[0] = SPA_AUDIO_CHANNEL_FL;
|
||||
format.position[1] = SPA_AUDIO_CHANNEL_FR;
|
||||
param = spa_format_audio_raw_build(&pod_builder, SPA_PARAM_Format, &format);
|
||||
param = spa_pod_builder_add_object(&pod_builder,
|
||||
SPA_TYPE_OBJECT_ParamPortConfig, SPA_PARAM_PortConfig,
|
||||
SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(direction),
|
||||
SPA_PARAM_PORT_CONFIG_mode, SPA_POD_Id(SPA_PARAM_PORT_CONFIG_MODE_dsp),
|
||||
SPA_PARAM_PORT_CONFIG_format, SPA_POD_Pod(param));
|
||||
pw_node_proxy_set_param(pw_proxy, SPA_PARAM_PortConfig, 0, param);
|
||||
}
|
||||
|
||||
/* Register a callback to know when all the adapter ports have been emitted */
|
||||
/* Register the done callback */
|
||||
g_signal_connect_object(self->proxy, "done", (GCallback)on_audio_adapter_done,
|
||||
self, 0);
|
||||
wp_proxy_sync (WP_PROXY(self->proxy));
|
||||
@@ -248,6 +250,7 @@ static void
|
||||
wp_audio_adapter_init (WpAudioAdapter * self)
|
||||
{
|
||||
self->init_abort = FALSE;
|
||||
self->ports_done = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@@ -25,6 +25,7 @@ struct monitor {
|
||||
struct impl {
|
||||
WpModule *module;
|
||||
WpRemotePipewire *remote_pipewire;
|
||||
GHashTable *registered_endpoints;
|
||||
|
||||
/* The bluez monitor */
|
||||
struct monitor monitor;
|
||||
@@ -57,6 +58,107 @@ struct node {
|
||||
struct pw_proxy *proxy;
|
||||
};
|
||||
|
||||
static void
|
||||
on_endpoint_created(GObject *initable, GAsyncResult *res, gpointer d)
|
||||
{
|
||||
struct impl *data = d;
|
||||
WpEndpoint *endpoint = NULL;
|
||||
guint global_id = 0;
|
||||
GError *error = NULL;
|
||||
|
||||
/* Get the endpoint */
|
||||
endpoint = wp_endpoint_new_finish(initable, res, NULL);
|
||||
g_return_if_fail (endpoint);
|
||||
|
||||
/* Check for error */
|
||||
if (error) {
|
||||
g_clear_object (&endpoint);
|
||||
g_warning ("Failed to create client endpoint: %s", error->message);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the endpoint global id */
|
||||
g_object_get (endpoint, "global-id", &global_id, NULL);
|
||||
g_debug ("Created bluetooth endpoint for global id %d", global_id);
|
||||
|
||||
/* Register the endpoint and add it to the table */
|
||||
wp_endpoint_register (endpoint);
|
||||
g_hash_table_insert (data->registered_endpoints, GUINT_TO_POINTER(global_id),
|
||||
endpoint);
|
||||
}
|
||||
|
||||
static void
|
||||
on_node_added (WpRemotePipewire *rp, guint id, gconstpointer p, gpointer d)
|
||||
{
|
||||
struct impl *data = d;
|
||||
const struct spa_dict *props = p;
|
||||
g_autoptr (WpCore) core = wp_module_get_core (data->module);
|
||||
const gchar *name, *media_class;
|
||||
enum pw_direction direction;
|
||||
GVariantBuilder b;
|
||||
g_autoptr (GVariant) endpoint_props = NULL;
|
||||
|
||||
/* Make sure the node has properties */
|
||||
g_return_if_fail(props);
|
||||
|
||||
/* Get the media_class */
|
||||
media_class = spa_dict_lookup(props, "media.class");
|
||||
|
||||
/* Get the name */
|
||||
name = spa_dict_lookup (props, "media.name");
|
||||
if (!name)
|
||||
name = spa_dict_lookup (props, "node.name");
|
||||
|
||||
/* Only handle bluetooth nodes */
|
||||
if (!g_str_has_prefix (name, "api.bluez5"))
|
||||
return;
|
||||
|
||||
/* Get the direction */
|
||||
if (g_str_has_prefix (media_class, "Audio/Sink")) {
|
||||
direction = PW_DIRECTION_INPUT;
|
||||
} else if (g_str_has_prefix (media_class, "Audio/Source")) {
|
||||
direction = PW_DIRECTION_OUTPUT;
|
||||
} else {
|
||||
g_critical ("failed to parse direction");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set the properties */
|
||||
g_variant_builder_init (&b, G_VARIANT_TYPE_VARDICT);
|
||||
g_variant_builder_add (&b, "{sv}",
|
||||
"name", name ?
|
||||
g_variant_new_take_string (g_strdup_printf ("Stream %u (%s)", id, name)) :
|
||||
g_variant_new_take_string (g_strdup_printf ("Stream %u", id)));
|
||||
g_variant_builder_add (&b, "{sv}",
|
||||
"media-class", g_variant_new_string (media_class));
|
||||
g_variant_builder_add (&b, "{sv}",
|
||||
"direction", g_variant_new_uint32 (direction));
|
||||
g_variant_builder_add (&b, "{sv}",
|
||||
"global-id", g_variant_new_uint32 (id));
|
||||
endpoint_props = g_variant_builder_end (&b);
|
||||
|
||||
/* Create the endpoint async */
|
||||
wp_factory_make (core, "pipewire-simple-endpoint", WP_TYPE_ENDPOINT,
|
||||
endpoint_props, on_endpoint_created, data);
|
||||
}
|
||||
|
||||
static void
|
||||
on_global_removed (WpRemotePipewire *rp, guint id, gpointer d)
|
||||
{
|
||||
struct impl *data = d;
|
||||
WpEndpoint *endpoint = NULL;
|
||||
|
||||
/* Get the endpoint */
|
||||
endpoint = g_hash_table_lookup (data->registered_endpoints,
|
||||
GUINT_TO_POINTER(id));
|
||||
if (!endpoint)
|
||||
return;
|
||||
|
||||
/* Unregister the endpoint and remove it from the table */
|
||||
wp_endpoint_unregister (endpoint);
|
||||
g_hash_table_remove (data->registered_endpoints, GUINT_TO_POINTER(id));
|
||||
}
|
||||
|
||||
static struct node *
|
||||
create_node(struct impl *impl, struct device *dev, uint32_t id,
|
||||
const struct spa_device_object_info *info)
|
||||
@@ -343,6 +445,10 @@ module_destroy (gpointer data)
|
||||
impl->module = NULL;
|
||||
impl->remote_pipewire = NULL;
|
||||
|
||||
/* Destroy the registered endpoints table */
|
||||
g_hash_table_unref(impl->registered_endpoints);
|
||||
impl->registered_endpoints = NULL;
|
||||
|
||||
/* Clean up */
|
||||
g_slice_free (struct impl, impl);
|
||||
}
|
||||
@@ -365,6 +471,8 @@ wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args)
|
||||
impl = g_slice_new0(struct impl);
|
||||
impl->module = module;
|
||||
impl->remote_pipewire = rp;
|
||||
impl->registered_endpoints = g_hash_table_new_full (g_direct_hash,
|
||||
g_direct_equal, NULL, (GDestroyNotify)g_object_unref);
|
||||
|
||||
/* Set destroy callback for impl */
|
||||
wp_module_set_destroy_callback (module, module_destroy, impl);
|
||||
@@ -374,4 +482,8 @@ wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args)
|
||||
|
||||
/* Start the monitor when the connected callback is triggered */
|
||||
g_signal_connect(rp, "state-changed::connected", (GCallback)start_monitor, impl);
|
||||
|
||||
/* Register the global added/removed callbacks */
|
||||
g_signal_connect(rp, "global-added::node", (GCallback)on_node_added, impl);
|
||||
g_signal_connect(rp, "global-removed", (GCallback)on_global_removed, impl);
|
||||
}
|
||||
|
Reference in New Issue
Block a user