Merge remote-tracking branch 'origin/master' into proxy-refactoring

This commit is contained in:
George Kiagiadakis
2019-08-27 18:10:41 +03:00
8 changed files with 228 additions and 67 deletions

View File

@@ -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

View File

@@ -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);

View File

@@ -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);
} }

View File

@@ -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}",

View File

@@ -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);

View File

@@ -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);

View File

@@ -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,9 +80,45 @@ 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;
/* Finish the creation of the audio adapter */ /* Finish the creation of the audio adapter */
g_task_return_boolean (self->init_task, TRUE); g_task_return_boolean (self->init_task, TRUE);
@@ -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

View File

@@ -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);
} }