Merge remote-tracking branch 'origin/master' into proxy-refactoring
This commit is contained in:
@@ -93,6 +93,7 @@ struct _WpEndpointPrivate
|
|||||||
{
|
{
|
||||||
gchar *name;
|
gchar *name;
|
||||||
gchar media_class[40];
|
gchar media_class[40];
|
||||||
|
guint direction;
|
||||||
GPtrArray *streams;
|
GPtrArray *streams;
|
||||||
GPtrArray *controls;
|
GPtrArray *controls;
|
||||||
GPtrArray *links;
|
GPtrArray *links;
|
||||||
@@ -104,6 +105,7 @@ enum {
|
|||||||
PROP_CORE,
|
PROP_CORE,
|
||||||
PROP_NAME,
|
PROP_NAME,
|
||||||
PROP_MEDIA_CLASS,
|
PROP_MEDIA_CLASS,
|
||||||
|
PROP_DIRECTION,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@@ -211,6 +213,9 @@ wp_endpoint_set_property (GObject * object, guint property_id,
|
|||||||
strncpy (priv->media_class, g_value_get_string (value),
|
strncpy (priv->media_class, g_value_get_string (value),
|
||||||
sizeof (priv->media_class) - 1);
|
sizeof (priv->media_class) - 1);
|
||||||
break;
|
break;
|
||||||
|
case PROP_DIRECTION:
|
||||||
|
priv->direction = g_value_get_uint(value);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
break;
|
break;
|
||||||
@@ -234,6 +239,9 @@ wp_endpoint_get_property (GObject * object, guint property_id, GValue * value,
|
|||||||
case PROP_MEDIA_CLASS:
|
case PROP_MEDIA_CLASS:
|
||||||
g_value_set_string (value, priv->media_class);
|
g_value_set_string (value, priv->media_class);
|
||||||
break;
|
break;
|
||||||
|
case PROP_DIRECTION:
|
||||||
|
g_value_set_uint (value, priv->direction);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
break;
|
break;
|
||||||
@@ -281,6 +289,15 @@ wp_endpoint_class_init (WpEndpointClass * klass)
|
|||||||
signals[SIGNAL_NOTIFY_CONTROL_VALUE] = g_signal_new ("notify-control-value",
|
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_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
|
||||||
G_TYPE_NONE, 1, G_TYPE_UINT);
|
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;
|
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:
|
* wp_endpoint_register_stream:
|
||||||
* @self: the endpoint
|
* @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);
|
WpCore *wp_endpoint_get_core (WpEndpoint * self);
|
||||||
const gchar * wp_endpoint_get_name (WpEndpoint * self);
|
const gchar * wp_endpoint_get_name (WpEndpoint * self);
|
||||||
const gchar * wp_endpoint_get_media_class (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);
|
void wp_endpoint_register_stream (WpEndpoint * self, GVariant * stream);
|
||||||
GVariant * wp_endpoint_get_stream (WpEndpoint * self, guint32 stream_id);
|
GVariant * wp_endpoint_get_stream (WpEndpoint * self, guint32 stream_id);
|
||||||
|
@@ -42,9 +42,6 @@ struct _WpPipewireSimpleEndpoint
|
|||||||
/* Handler */
|
/* Handler */
|
||||||
gulong proxy_node_done_handler_id;
|
gulong proxy_node_done_handler_id;
|
||||||
|
|
||||||
/* Direction */
|
|
||||||
enum pw_direction direction;
|
|
||||||
|
|
||||||
/* Proxies */
|
/* Proxies */
|
||||||
WpProxyNode *proxy_node;
|
WpProxyNode *proxy_node;
|
||||||
struct spa_hook node_proxy_listener;
|
struct spa_hook node_proxy_listener;
|
||||||
@@ -230,6 +227,7 @@ on_port_added(WpRemotePipewire *rp, guint id, gconstpointer p, gpointer d)
|
|||||||
static void
|
static void
|
||||||
emit_endpoint_ports(WpPipewireSimpleEndpoint *self)
|
emit_endpoint_ports(WpPipewireSimpleEndpoint *self)
|
||||||
{
|
{
|
||||||
|
enum pw_direction direction = wp_endpoint_get_direction (WP_ENDPOINT (self));
|
||||||
struct pw_node_proxy* node_proxy = NULL;
|
struct pw_node_proxy* node_proxy = NULL;
|
||||||
struct spa_audio_info_raw format = { 0, };
|
struct spa_audio_info_raw format = { 0, };
|
||||||
struct spa_pod *param;
|
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_format_audio_raw_build(&pod_builder, SPA_PARAM_Format, &format);
|
||||||
param = spa_pod_builder_add_object(&pod_builder,
|
param = spa_pod_builder_add_object(&pod_builder,
|
||||||
SPA_TYPE_OBJECT_ParamPortConfig, SPA_PARAM_PortConfig,
|
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_mode, SPA_POD_Id(SPA_PARAM_PORT_CONFIG_MODE_dsp),
|
||||||
SPA_PARAM_PORT_CONFIG_format, SPA_POD_Pod(param));
|
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);
|
WpPipewireSimpleEndpoint *self = WP_PIPEWIRE_SIMPLE_ENDPOINT (initable);
|
||||||
g_autoptr (WpCore) core = wp_endpoint_get_core(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));
|
|
||||||
struct pw_node_proxy *node_proxy = NULL;
|
struct pw_node_proxy *node_proxy = NULL;
|
||||||
|
|
||||||
/* Create the async task */
|
/* Create the async task */
|
||||||
@@ -332,14 +329,6 @@ wp_simple_endpoint_init_async (GAsyncInitable *initable, int io_priority,
|
|||||||
/* Init the proxies_port array */
|
/* Init the proxies_port array */
|
||||||
self->proxies_port = g_ptr_array_new_full(2, (GDestroyNotify)g_object_unref);
|
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 */
|
/* Register a port_added callback */
|
||||||
self->remote_pipewire = wp_core_get_global (core, WP_GLOBAL_REMOTE_PIPEWIRE);
|
self->remote_pipewire = wp_core_get_global (core, WP_GLOBAL_REMOTE_PIPEWIRE);
|
||||||
g_return_if_fail(self->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;
|
g_autoptr (WpCore) core = NULL;
|
||||||
const gchar *name, *media_class;
|
const gchar *name, *media_class;
|
||||||
|
guint direction;
|
||||||
guint global_id;
|
guint global_id;
|
||||||
|
|
||||||
/* Make sure the type is correct */
|
/* Make sure the type is correct */
|
||||||
@@ -593,6 +583,8 @@ simple_endpoint_factory (WpFactory * factory, GType type,
|
|||||||
return;
|
return;
|
||||||
if (!g_variant_lookup (properties, "media-class", "&s", &media_class))
|
if (!g_variant_lookup (properties, "media-class", "&s", &media_class))
|
||||||
return;
|
return;
|
||||||
|
if (!g_variant_lookup (properties, "direction", "u", &direction))
|
||||||
|
return;
|
||||||
if (!g_variant_lookup (properties, "global-id", "u", &global_id))
|
if (!g_variant_lookup (properties, "global-id", "u", &global_id))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -601,6 +593,7 @@ simple_endpoint_factory (WpFactory * factory, GType type,
|
|||||||
"core", core,
|
"core", core,
|
||||||
"name", name,
|
"name", name,
|
||||||
"media-class", media_class,
|
"media-class", media_class,
|
||||||
|
"direction", direction,
|
||||||
"global-id", global_id,
|
"global-id", global_id,
|
||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
@@ -96,6 +96,7 @@ on_node_added(WpRemotePipewire *rp, guint id, gconstpointer p, gpointer d)
|
|||||||
const struct spa_dict *props = p;
|
const struct spa_dict *props = p;
|
||||||
g_autoptr (WpCore) core = wp_module_get_core (impl->module);
|
g_autoptr (WpCore) core = wp_module_get_core (impl->module);
|
||||||
const gchar *media_class, *name;
|
const gchar *media_class, *name;
|
||||||
|
enum pw_direction direction;
|
||||||
GVariantBuilder b;
|
GVariantBuilder b;
|
||||||
g_autoptr (GVariant) endpoint_props = NULL;
|
g_autoptr (GVariant) endpoint_props = NULL;
|
||||||
|
|
||||||
@@ -116,12 +117,28 @@ on_node_added(WpRemotePipewire *rp, guint id, gconstpointer p, gpointer d)
|
|||||||
if (!name)
|
if (!name)
|
||||||
name = spa_dict_lookup (props, "node.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 */
|
/* Set the properties */
|
||||||
g_variant_builder_init (&b, G_VARIANT_TYPE_VARDICT);
|
g_variant_builder_init (&b, G_VARIANT_TYPE_VARDICT);
|
||||||
g_variant_builder_add (&b, "{sv}",
|
g_variant_builder_add (&b, "{sv}",
|
||||||
"name", g_variant_new_string (name));
|
"name", g_variant_new_string (name));
|
||||||
g_variant_builder_add (&b, "{sv}",
|
g_variant_builder_add (&b, "{sv}",
|
||||||
"media-class", g_variant_new_string (media_class));
|
"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}",
|
g_variant_builder_add (&b, "{sv}",
|
||||||
"global-id", g_variant_new_uint32 (id));
|
"global-id", g_variant_new_uint32 (id));
|
||||||
g_variant_builder_add (&b, "{sv}",
|
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;
|
const struct spa_dict *props = p;
|
||||||
g_autoptr (WpCore) core = wp_module_get_core (data->module);
|
g_autoptr (WpCore) core = wp_module_get_core (data->module);
|
||||||
const gchar *name, *media_class;
|
const gchar *name, *media_class;
|
||||||
|
enum pw_direction direction;
|
||||||
GVariantBuilder b;
|
GVariantBuilder b;
|
||||||
g_autoptr (GVariant) endpoint_props = NULL;
|
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/"))
|
if (!g_str_has_prefix (media_class, "Stream/"))
|
||||||
return;
|
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 */
|
/* Get the name */
|
||||||
name = spa_dict_lookup (props, "media.name");
|
name = spa_dict_lookup (props, "media.name");
|
||||||
if (!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_new_take_string (g_strdup_printf ("Stream %u", id)));
|
||||||
g_variant_builder_add (&b, "{sv}",
|
g_variant_builder_add (&b, "{sv}",
|
||||||
"media-class", g_variant_new_string (media_class));
|
"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}",
|
g_variant_builder_add (&b, "{sv}",
|
||||||
"global-id", g_variant_new_uint32 (id));
|
"global-id", g_variant_new_uint32 (id));
|
||||||
endpoint_props = g_variant_builder_end (&b);
|
endpoint_props = g_variant_builder_end (&b);
|
||||||
|
@@ -42,9 +42,6 @@ struct _WpPwAudioSoftdspEndpoint
|
|||||||
GTask *init_task;
|
GTask *init_task;
|
||||||
gboolean init_abort;
|
gboolean init_abort;
|
||||||
|
|
||||||
/* Direction */
|
|
||||||
enum pw_direction direction;
|
|
||||||
|
|
||||||
/* Audio Streams */
|
/* Audio Streams */
|
||||||
WpAudioStream *adapter;
|
WpAudioStream *adapter;
|
||||||
GPtrArray *converters;
|
GPtrArray *converters;
|
||||||
@@ -162,6 +159,7 @@ on_audio_adapter_created(GObject *initable, GAsyncResult *res,
|
|||||||
gpointer data)
|
gpointer data)
|
||||||
{
|
{
|
||||||
WpPwAudioSoftdspEndpoint *self = 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_autoptr (WpCore) core = wp_endpoint_get_core(WP_ENDPOINT(self));
|
||||||
g_autofree gchar *name = NULL;
|
g_autofree gchar *name = NULL;
|
||||||
const struct pw_node_info *adapter_info = 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 */
|
/* Create the audio converters */
|
||||||
g_variant_iter_init (&iter, self->streams);
|
g_variant_iter_init (&iter, self->streams);
|
||||||
for (i = 0; g_variant_iter_next (&iter, "&s", &stream); i++) {
|
for (i = 0; g_variant_iter_next (&iter, "&s", &stream); i++) {
|
||||||
wp_audio_convert_new (WP_ENDPOINT(self), i, stream, self->direction,
|
wp_audio_convert_new (WP_ENDPOINT(self), i, stream, direction, adapter_info,
|
||||||
adapter_info, on_audio_convert_created, self);
|
on_audio_convert_created, self);
|
||||||
|
|
||||||
/* Register the stream */
|
/* Register the stream */
|
||||||
g_variant_dict_init (&d, NULL);
|
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)
|
GCancellable *cancellable, GAsyncReadyCallback callback, gpointer data)
|
||||||
{
|
{
|
||||||
WpPwAudioSoftdspEndpoint *self = WP_PW_AUDIO_SOFTDSP_ENDPOINT (initable);
|
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));
|
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;
|
GVariantDict d;
|
||||||
|
|
||||||
/* Create the async task */
|
/* Create the async task */
|
||||||
self->init_task = g_task_new (initable, cancellable, callback, data);
|
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 */
|
/* Create the adapter proxy */
|
||||||
wp_audio_adapter_new (WP_ENDPOINT(self), WP_STREAM_ID_NONE, "master",
|
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 */
|
/* Register the selected control */
|
||||||
self->selected = FALSE;
|
self->selected = FALSE;
|
||||||
@@ -401,6 +391,7 @@ endpoint_factory (WpFactory * factory, GType type, GVariant * properties,
|
|||||||
{
|
{
|
||||||
g_autoptr (WpCore) core = NULL;
|
g_autoptr (WpCore) core = NULL;
|
||||||
const gchar *name, *media_class;
|
const gchar *name, *media_class;
|
||||||
|
guint direction;
|
||||||
guint global_id;
|
guint global_id;
|
||||||
g_autoptr (GVariant) streams = NULL;
|
g_autoptr (GVariant) streams = NULL;
|
||||||
|
|
||||||
@@ -416,6 +407,8 @@ endpoint_factory (WpFactory * factory, GType type, GVariant * properties,
|
|||||||
return;
|
return;
|
||||||
if (!g_variant_lookup (properties, "media-class", "&s", &media_class))
|
if (!g_variant_lookup (properties, "media-class", "&s", &media_class))
|
||||||
return;
|
return;
|
||||||
|
if (!g_variant_lookup (properties, "direction", "u", &direction))
|
||||||
|
return;
|
||||||
if (!g_variant_lookup (properties, "global-id", "u", &global_id))
|
if (!g_variant_lookup (properties, "global-id", "u", &global_id))
|
||||||
return;
|
return;
|
||||||
if (!(streams = g_variant_lookup_value (properties, "streams",
|
if (!(streams = g_variant_lookup_value (properties, "streams",
|
||||||
@@ -428,6 +421,7 @@ endpoint_factory (WpFactory * factory, GType type, GVariant * properties,
|
|||||||
"core", core,
|
"core", core,
|
||||||
"name", name,
|
"name", name,
|
||||||
"media-class", media_class,
|
"media-class", media_class,
|
||||||
|
"direction", direction,
|
||||||
"global-id", global_id,
|
"global-id", global_id,
|
||||||
"streams", streams,
|
"streams", streams,
|
||||||
NULL);
|
NULL);
|
||||||
|
@@ -26,6 +26,7 @@ struct _WpAudioAdapter
|
|||||||
/* The task to signal the proxy is initialized */
|
/* The task to signal the proxy is initialized */
|
||||||
GTask *init_task;
|
GTask *init_task;
|
||||||
gboolean init_abort;
|
gboolean init_abort;
|
||||||
|
gboolean ports_done;
|
||||||
|
|
||||||
/* Props */
|
/* Props */
|
||||||
guint adapter_id;
|
guint adapter_id;
|
||||||
@@ -79,6 +80,42 @@ on_audio_adapter_done(WpProxy *proxy, gpointer data)
|
|||||||
{
|
{
|
||||||
WpAudioAdapter *self = 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 */
|
/* Don't do anything if the audio adapter has already been initialized */
|
||||||
if (!self->init_task)
|
if (!self->init_task)
|
||||||
return;
|
return;
|
||||||
@@ -93,12 +130,6 @@ on_audio_adapter_proxy_created(GObject *initable, GAsyncResult *res,
|
|||||||
gpointer data)
|
gpointer data)
|
||||||
{
|
{
|
||||||
WpAudioAdapter *self = 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 */
|
/* Get the adapter proxy */
|
||||||
self->proxy = WP_PROXY_NODE (object_safe_new_finish (self, initable,
|
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)
|
if (!self->proxy)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Get the pipewire proxy */
|
/* Emit the EnumFormat param */
|
||||||
pw_proxy = wp_proxy_get_pw_proxy(WP_PROXY(self->proxy));
|
wp_proxy_node_enum_params (self->proxy, 0, SPA_PARAM_EnumFormat, 0, -1, NULL);
|
||||||
g_return_if_fail (pw_proxy);
|
|
||||||
|
|
||||||
/* Emit the props param */
|
/* Register the done callback */
|
||||||
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 */
|
|
||||||
g_signal_connect_object(self->proxy, "done", (GCallback)on_audio_adapter_done,
|
g_signal_connect_object(self->proxy, "done", (GCallback)on_audio_adapter_done,
|
||||||
self, 0);
|
self, 0);
|
||||||
wp_proxy_sync (WP_PROXY(self->proxy));
|
wp_proxy_sync (WP_PROXY(self->proxy));
|
||||||
@@ -248,6 +250,7 @@ static void
|
|||||||
wp_audio_adapter_init (WpAudioAdapter * self)
|
wp_audio_adapter_init (WpAudioAdapter * self)
|
||||||
{
|
{
|
||||||
self->init_abort = FALSE;
|
self->init_abort = FALSE;
|
||||||
|
self->ports_done = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@@ -25,6 +25,7 @@ struct monitor {
|
|||||||
struct impl {
|
struct impl {
|
||||||
WpModule *module;
|
WpModule *module;
|
||||||
WpRemotePipewire *remote_pipewire;
|
WpRemotePipewire *remote_pipewire;
|
||||||
|
GHashTable *registered_endpoints;
|
||||||
|
|
||||||
/* The bluez monitor */
|
/* The bluez monitor */
|
||||||
struct monitor monitor;
|
struct monitor monitor;
|
||||||
@@ -57,6 +58,107 @@ struct node {
|
|||||||
struct pw_proxy *proxy;
|
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 *
|
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)
|
||||||
@@ -343,6 +445,10 @@ module_destroy (gpointer data)
|
|||||||
impl->module = NULL;
|
impl->module = NULL;
|
||||||
impl->remote_pipewire = NULL;
|
impl->remote_pipewire = NULL;
|
||||||
|
|
||||||
|
/* Destroy the registered endpoints table */
|
||||||
|
g_hash_table_unref(impl->registered_endpoints);
|
||||||
|
impl->registered_endpoints = NULL;
|
||||||
|
|
||||||
/* Clean up */
|
/* Clean up */
|
||||||
g_slice_free (struct impl, impl);
|
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 = g_slice_new0(struct impl);
|
||||||
impl->module = module;
|
impl->module = module;
|
||||||
impl->remote_pipewire = rp;
|
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 */
|
/* Set destroy callback for impl */
|
||||||
wp_module_set_destroy_callback (module, module_destroy, 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 */
|
/* Start the monitor when the connected callback is triggered */
|
||||||
g_signal_connect(rp, "state-changed::connected", (GCallback)start_monitor, impl);
|
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