diff --git a/modules/module-config-endpoint/context.c b/modules/module-config-endpoint/context.c index d11e8212dcda0d070902c9cf12f05f6bb5891fcc..809b42e70b5a5aa4cb2f07101796a9d0e38b0865 100644 --- a/modules/module-config-endpoint/context.c +++ b/modules/module-config-endpoint/context.c @@ -14,6 +14,8 @@ #include "parser-streams.h" #include "context.h" +G_DEFINE_QUARK (wp-module-config-endpoint-context-session, session); + struct _WpConfigEndpointContext { GObject parent; @@ -21,8 +23,9 @@ struct _WpConfigEndpointContext /* Props */ GWeakRef core; - WpObjectManager *om; - GHashTable *registered_endpoints; + WpObjectManager *sessions_om; + WpObjectManager *nodes_om; + GHashTable *endpoints; }; enum { @@ -40,63 +43,52 @@ static guint signals[N_SIGNALS]; G_DEFINE_TYPE (WpConfigEndpointContext, wp_config_endpoint_context, G_TYPE_OBJECT) -static void -on_endpoint_created (GObject *initable, GAsyncResult *res, gpointer d) -{ - WpConfigEndpointContext *self = d; - g_autoptr (WpBaseEndpoint) endpoint = NULL; - g_autoptr (WpProxy) proxy = NULL; - guint global_id = 0; - GError *error = NULL; - - /* Get the endpoint */ - endpoint = wp_base_endpoint_new_finish (initable, res, &error); - if (error) { - g_warning ("Failed to create endpoint: %s", error->message); - return; - } - - /* Get the endpoint global id */ - g_object_get (endpoint, "node", &proxy, NULL); - global_id = wp_proxy_get_bound_id (proxy); - - /* Register the endpoint and add it to the table */ - wp_base_endpoint_register (endpoint); - g_hash_table_insert (self->registered_endpoints, GUINT_TO_POINTER (global_id), - g_object_ref (endpoint)); - - /* Emit the endpoint-created signal */ - g_signal_emit (self, signals[SIGNAL_ENDPOINT_CREATED], 0, endpoint); -} - -static GVariant * -create_streams_variant (WpConfiguration *config, const char *streams) +static const struct WpParserStreamsData * +get_streams_data (WpConfiguration *config, const char *file_name) { g_autoptr (WpConfigParser) parser = NULL; - const struct WpParserStreamsData *streams_data = NULL; - g_autoptr (GVariantBuilder) ba = NULL; - if (!streams || !config) - return NULL; + g_return_val_if_fail (config, 0); + g_return_val_if_fail (file_name, 0); /* Get the streams parser */ parser = wp_configuration_get_parser (config, WP_PARSER_STREAMS_EXTENSION); if (!parser) - return NULL; + return 0; /* Get the streams data */ - streams_data = wp_config_parser_get_matched_data (parser, (gpointer)streams); - if (!streams_data || streams_data->n_streams <= 0) - return NULL; - - /* Build the variant array with the stream name and priority */ - ba = g_variant_builder_new (G_VARIANT_TYPE ("a(su)")); - g_variant_builder_init (ba, G_VARIANT_TYPE_ARRAY); - for (guint i = 0; i < streams_data->n_streams; i++) - g_variant_builder_add (ba, "(su)", streams_data->streams[i].name, - streams_data->streams[i].priority); - - return g_variant_new ("a(su)", ba); + return wp_config_parser_get_matched_data (parser, (gpointer)file_name); +} + +static void +endpoint_export_finish_cb (WpSessionItem * ep, GAsyncResult * res, + WpConfigEndpointContext * self) +{ + g_autoptr (GError) error = NULL; + gboolean export_ret = wp_session_item_export_finish (ep, res, &error); + g_return_if_fail (error == NULL); + g_return_if_fail (export_ret); + + /* Emit the signal */ + g_signal_emit (self, signals[SIGNAL_ENDPOINT_CREATED], 0, ep); +} + +static void +endpoint_activate_finish_cb (WpSessionItem * ep, GAsyncResult * res, + WpConfigEndpointContext * self) +{ + WpSession * session = NULL; + g_autoptr (GError) error = NULL; + gboolean activate_ret = wp_session_item_activate_finish (ep, res, &error); + g_return_if_fail (error == NULL); + g_return_if_fail (activate_ret); + + /* Get the session */ + session = g_object_get_qdata (G_OBJECT (ep), session_quark ()); + g_return_if_fail (session); + + wp_session_item_export (ep, WP_SESSION (session), + (GAsyncReadyCallback) endpoint_export_finish_cb, self); } static void @@ -106,74 +98,141 @@ on_node_added (WpObjectManager *om, WpProxy *proxy, gpointer d) g_autoptr (WpCore) core = g_weak_ref_get (&self->core); g_autoptr (WpConfiguration) config = wp_configuration_get_instance (core); g_autoptr (WpProperties) props = wp_proxy_get_properties (proxy); + g_autoptr (WpSessionItem) ep = NULL; + g_autoptr (WpSessionItem) streams_ep = NULL; + g_autoptr (WpSession) session = NULL; g_autoptr (WpConfigParser) parser = NULL; const struct WpParserEndpointData *endpoint_data = NULL; - GVariantBuilder b; - g_autoptr (GVariant) endpoint_props = NULL; - const char *media_class = NULL, *name = NULL; - g_autoptr (GVariant) streams_variant = NULL; + const struct WpParserStreamsData *streams_data = NULL; /* Skip nodes with no media class (JACK Clients) */ - media_class = wp_properties_get (props, PW_KEY_MEDIA_CLASS); - if (!media_class) + if (!wp_properties_get (props, PW_KEY_MEDIA_CLASS)) return; - /* Get the linked and ep streams data */ + /* Get the endpoint configuration data */ parser = wp_configuration_get_parser (config, WP_PARSER_ENDPOINT_EXTENSION); endpoint_data = wp_config_parser_get_matched_data (parser, proxy); if (!endpoint_data) return; - /* Set the name if it is null */ - name = endpoint_data->e.name; - if (!name) - name = wp_properties_get (props, PW_KEY_NODE_NAME); - - /* Set the media class if it is null */ - if (endpoint_data->e.media_class) - media_class = endpoint_data->e.media_class; - - /* Create the streams variant */ - streams_variant = create_streams_variant (config, endpoint_data->e.streams); - - /* Set the properties */ - g_variant_builder_init (&b, G_VARIANT_TYPE_VARDICT); - g_variant_builder_add (&b, "{sv}", - "name", g_variant_new_take_string (g_strdup_printf ("%s", 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 (endpoint_data->e.direction)); - g_variant_builder_add (&b, "{sv}", - "priority", g_variant_new_uint32 (endpoint_data->e.priority)); - g_variant_builder_add (&b, "{sv}", - "node", g_variant_new_uint64 ((guint64) proxy)); - if (streams_variant) - g_variant_builder_add (&b, "{sv}", "streams", - g_steal_pointer (&streams_variant)); - endpoint_props = g_variant_builder_end (&b); - - /* Create the endpoint async */ - wp_factory_make (core, endpoint_data->e.type, WP_TYPE_BASE_ENDPOINT, - endpoint_props, on_endpoint_created, self); + /* Get the session */ + session = wp_object_manager_lookup (self->sessions_om, WP_TYPE_SESSION, + WP_CONSTRAINT_TYPE_PW_PROPERTY, "session.name", "=s", + endpoint_data->e.session, NULL); + if (!session) { + wp_warning_object (self, "could not find session for endpoint"); + return; + } + + /* Get the streams data */ + streams_data = endpoint_data->e.streams ? + get_streams_data (config, endpoint_data->e.streams) : NULL; + + /* Create the endpoint */ + ep = wp_session_item_make (core, endpoint_data->e.type); + if (!ep) { + wp_warning_object (self, "could not create endpoint of type %s", + endpoint_data->e.type); + return; + } + + /* Configure the endpoint */ + { + g_auto (GVariantBuilder) b = + G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_VARDICT); + g_variant_builder_add (&b, "{sv}", "node", + g_variant_new_uint64 ((guint64) proxy)); + + if (endpoint_data->e.c.name) + g_variant_builder_add (&b, "{sv}", "name", + g_variant_new_string (endpoint_data->e.c.name)); + + if (endpoint_data->e.c.media_class) + g_variant_builder_add (&b, "{sv}", "media-class", + g_variant_new_string (endpoint_data->e.c.media_class)); + + if (endpoint_data->e.c.role) + g_variant_builder_add (&b, "{sv}", "role", + g_variant_new_string (endpoint_data->e.c.role)); + + g_variant_builder_add (&b, "{sv}", "priority", + g_variant_new_uint32 (endpoint_data->e.c.priority)); + + g_variant_builder_add (&b, "{sv}", "enable-control-port", + g_variant_new_boolean (endpoint_data->e.c.enable_control_port)); + + g_variant_builder_add (&b, "{sv}", "enable-monitor", + g_variant_new_boolean (endpoint_data->e.c.enable_monitor)); + + wp_session_item_configure (ep, g_variant_builder_end (&b)); + } + + /* TODO: for now we always create softdsp audio endpoints if streams data is + * valid. However, this will need to change once we have video endpoints. */ + if (streams_data) { + /* Create the steams endpoint */ + streams_ep = wp_session_item_make (core, "si-audio-softdsp-endpoint"); + + /* Configure the streams endpoint */ + { + g_auto (GVariantBuilder) b = + G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_VARDICT); + g_variant_builder_add (&b, "{sv}", "adapter", + g_variant_new_uint64 ((guint64) ep)); + wp_session_item_configure (streams_ep, g_variant_builder_end (&b)); + } + + /* Add the streams */ + for (guint i = 0; i < streams_data->n_streams; i++) { + const struct WpParserStreamsStreamData *sd = streams_data->streams + i; + g_autoptr (WpSessionItem) stream = + wp_session_item_make (core, "si-convert"); + { + g_auto (GVariantBuilder) b = + G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_VARDICT); + g_variant_builder_add (&b, "{sv}", "target", + g_variant_new_uint64 ((guint64) ep)); + g_variant_builder_add (&b, "{sv}", "name", + g_variant_new_string (sd->name)); + g_variant_builder_add (&b, "{sv}", "enable-control-port", + g_variant_new_boolean (sd->enable_control_port)); + wp_session_item_configure (stream, g_variant_builder_end (&b)); + } + + wp_session_bin_add (WP_SESSION_BIN (streams_ep), g_steal_pointer (&stream)); + } + } + + /* Activate endpoint */ + g_object_set_qdata_full ( + G_OBJECT (streams_data ? streams_ep : ep), session_quark (), + g_steal_pointer (&session), g_object_unref); + wp_session_item_activate (streams_data ? streams_ep : ep, + (GAsyncReadyCallback) endpoint_activate_finish_cb, self); + + /* Insert the endpoint */ + g_hash_table_insert (self->endpoints, proxy, + streams_data ? g_steal_pointer (&streams_ep) : g_steal_pointer (&ep)); } static void -on_node_removed (WpObjectManager *om, WpProxy *proxy, gpointer d) +on_sessions_changed (WpObjectManager *om, gpointer d) { WpConfigEndpointContext *self = d; - WpBaseEndpoint *endpoint = NULL; - guint32 id = wp_proxy_get_bound_id (proxy); + g_autoptr (WpCore) core = g_weak_ref_get (&self->core); + g_return_if_fail (core); - /* Get the endpoint */ - endpoint = g_hash_table_lookup (self->registered_endpoints, - GUINT_TO_POINTER(id)); - if (!endpoint) - return; + /* Handle node-added signal and install the nodes object manager */ + wp_object_manager_add_interest_1 (self->nodes_om, WP_TYPE_NODE, NULL); + wp_object_manager_request_proxy_features (self->nodes_om, WP_TYPE_NODE, + WP_PROXY_FEATURES_STANDARD); + g_signal_connect_object (self->nodes_om, "object-added", + G_CALLBACK (on_node_added), self, 0); + wp_core_install_object_manager (core, self->nodes_om); - /* Unregister the endpoint and remove it from the table */ - wp_base_endpoint_unregister (endpoint); - g_hash_table_remove (self->registered_endpoints, GUINT_TO_POINTER(id)); + /* Remove handler */ + g_signal_handlers_disconnect_by_func (self->sessions_om, + on_sessions_changed, d); } static void @@ -195,8 +254,13 @@ wp_config_endpoint_context_constructed (GObject * object) wp_configuration_reload (config, WP_PARSER_ENDPOINT_EXTENSION); wp_configuration_reload (config, WP_PARSER_STREAMS_EXTENSION); - /* Install the object manager */ - wp_core_install_object_manager (core, self->om); + /* Handle sessions-changed signal and install the session object manager */ + wp_object_manager_add_interest_1 (self->sessions_om, WP_TYPE_SESSION, NULL); + wp_object_manager_request_proxy_features (self->sessions_om, WP_TYPE_SESSION, + WP_PROXY_FEATURES_STANDARD); + g_signal_connect_object (self->sessions_om, "objects-changed", + G_CALLBACK (on_sessions_changed), self, 0); + wp_core_install_object_manager (core, self->sessions_om); G_OBJECT_CLASS (wp_config_endpoint_context_parent_class)->constructed (object); } @@ -246,8 +310,9 @@ wp_config_endpoint_context_finalize (GObject *object) } g_weak_ref_clear (&self->core); - g_clear_object (&self->om); - g_clear_pointer (&self->registered_endpoints, g_hash_table_unref); + g_clear_pointer (&self->endpoints, g_hash_table_unref); + g_clear_object (&self->sessions_om); + g_clear_object (&self->nodes_om); G_OBJECT_CLASS (wp_config_endpoint_context_parent_class)->finalize (object); } @@ -255,20 +320,10 @@ wp_config_endpoint_context_finalize (GObject *object) static void wp_config_endpoint_context_init (WpConfigEndpointContext *self) { - self->om = wp_object_manager_new (); - self->registered_endpoints = g_hash_table_new_full (g_direct_hash, - g_direct_equal, NULL, (GDestroyNotify) g_object_unref); - - /* Only handle augmented nodes with info set */ - wp_object_manager_add_interest_1 (self->om, WP_TYPE_NODE, NULL); - wp_object_manager_request_proxy_features (self->om, WP_TYPE_NODE, - WP_PROXY_FEATURES_STANDARD); - - /* Register the global added/removed callbacks */ - g_signal_connect(self->om, "object-added", - (GCallback) on_node_added, self); - g_signal_connect(self->om, "object-removed", - (GCallback) on_node_removed, self); + self->nodes_om = wp_object_manager_new (); + self->sessions_om = wp_object_manager_new (); + self->endpoints = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, + (GDestroyNotify) g_object_unref); } static void @@ -290,7 +345,7 @@ wp_config_endpoint_context_class_init (WpConfigEndpointContextClass *klass) /* Signals */ signals[SIGNAL_ENDPOINT_CREATED] = g_signal_new ("endpoint-created", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, - G_TYPE_NONE, 1, WP_TYPE_ENDPOINT); + G_TYPE_NONE, 1, WP_TYPE_SESSION_ITEM); } WpConfigEndpointContext * @@ -300,10 +355,3 @@ wp_config_endpoint_context_new (WpCore *core) "core", core, NULL); } - -guint -wp_config_endpoint_context_get_length (WpConfigEndpointContext *self) -{ - g_return_val_if_fail (WP_IS_CONFIG_ENDPOINT_CONTEXT (self), 0); - return g_hash_table_size (self->registered_endpoints); -} diff --git a/modules/module-config-endpoint/context.h b/modules/module-config-endpoint/context.h index 1336546c29dfac1cd877603a1ab0d714def83b84..b09e98ab4660d9343894673ef94fe9060dc2be4c 100644 --- a/modules/module-config-endpoint/context.h +++ b/modules/module-config-endpoint/context.h @@ -19,8 +19,6 @@ G_DECLARE_FINAL_TYPE (WpConfigEndpointContext, wp_config_endpoint_context, WpConfigEndpointContext * wp_config_endpoint_context_new (WpCore *core); -guint wp_config_endpoint_context_get_length (WpConfigEndpointContext *self); - G_END_DECLS #endif diff --git a/modules/module-config-endpoint/parser-endpoint.c b/modules/module-config-endpoint/parser-endpoint.c index c9c5d5d85ebd9f6f61d5e4ec00f82ab7eb2c394b..32b3afea9de03b4cdeda1691f427ca3a58eec81e 100644 --- a/modules/module-config-endpoint/parser-endpoint.c +++ b/modules/module-config-endpoint/parser-endpoint.c @@ -32,14 +32,14 @@ wp_parser_endpoint_data_destroy (gpointer p) { struct WpParserEndpointData *data = p; - /* Free the strings */ g_clear_pointer (&data->filename, g_free); g_clear_pointer (&data->mn.props, wp_properties_unref); - g_clear_pointer (&data->e.name, g_free); - g_clear_pointer (&data->e.media_class, g_free); - g_clear_pointer (&data->e.props, wp_properties_unref); + g_clear_pointer (&data->e.session, g_free); g_clear_pointer (&data->e.type, g_free); g_clear_pointer (&data->e.streams, g_free); + g_clear_pointer (&data->e.c.name, g_free); + g_clear_pointer (&data->e.c.media_class, g_free); + g_clear_pointer (&data->e.c.role, g_free); g_slice_free (struct WpParserEndpointData, data); } @@ -76,25 +76,12 @@ parse_properties (WpTomlTable *table, const char *name) return props; } -static guint -parse_endpoint_direction (const char *direction) -{ - if (g_strcmp0 (direction, "sink") == 0) - return PW_DIRECTION_INPUT; - else if (g_strcmp0 (direction, "source") == 0) - return PW_DIRECTION_OUTPUT; - - g_return_val_if_reached (PW_DIRECTION_INPUT); -} - static struct WpParserEndpointData * wp_parser_endpoint_data_new (const gchar *location) { g_autoptr (WpTomlFile) file = NULL; - g_autoptr (WpTomlTable) table = NULL, mn = NULL, e = NULL; - g_autoptr (WpTomlArray) streams = NULL; + g_autoptr (WpTomlTable) table = NULL, mn = NULL, e = NULL, c = NULL; struct WpParserEndpointData *res = NULL; - g_autofree char *direction = NULL; /* File format: * ------------ @@ -102,13 +89,17 @@ wp_parser_endpoint_data_new (const gchar *location) * properties (WpProperties) * * [endpoint] + * session (string) + * type (string) + * streams (string) + * + * [endpoint.config] * name (string) * media_class (string) - * direction (string) + * role (string) * priority (uint32) - * properties (WpProperties) - * type (string) - * streams (string) + * enable_control_port (bool) + * enable_monitor (bool) */ /* Get the TOML file */ @@ -140,33 +131,33 @@ wp_parser_endpoint_data_new (const gchar *location) if (!e) goto error; - /* Get the name from the endpoint table */ - res->e.name = wp_toml_table_get_string (e, "name"); - - /* Get the media class from the endpoint table */ - res->e.media_class = wp_toml_table_get_string (e, "media_class"); - - /* Get the direction from the endpoint table */ - direction = wp_toml_table_get_string (e, "direction"); - if (!direction) + /* Get the endpoint session */ + res->e.session = wp_toml_table_get_string (e, "session"); + if (!res->e.session) goto error; - res->e.direction = parse_endpoint_direction (direction); - - /* Get the priority from the endpoint table */ - res->e.priority = 0; - wp_toml_table_get_uint32 (e, "priority", &res->e.priority); - - /* Get the endpoint properties */ - res->e.props = parse_properties (e, "properties"); /* Get the endpoint type */ res->e.type = wp_toml_table_get_string (e, "type"); if (!res->e.type) goto error; - /* Get the endpoint streams */ + /* Get the optional streams */ res->e.streams = wp_toml_table_get_string (e, "streams"); + /* Get the optional endpoint config table */ + c = wp_toml_table_get_table (e, "config"); + if (c) { + res->e.c.name = wp_toml_table_get_string (c, "name"); + res->e.c.media_class = wp_toml_table_get_string (c, "media_class"); + res->e.c.role = wp_toml_table_get_string (c, "role"); + res->e.c.priority = 0; + wp_toml_table_get_uint32 (c, "priority", &res->e.c.priority); + res->e.c.enable_control_port = FALSE; + wp_toml_table_get_boolean (c, "enable-control-port", &res->e.c.enable_control_port); + res->e.c.enable_monitor = FALSE; + wp_toml_table_get_boolean (c, "enable-monitor", &res->e.c.enable_monitor); + } + return res; error: @@ -193,7 +184,7 @@ wp_parser_endpoint_add_file (WpConfigParser *parser, /* Parse the file */ data = wp_parser_endpoint_data_new (name); if (!data) { - g_warning ("Failed to parse configuration file '%s'", name); + wp_warning_object (parser, "Failed to parse configuration file '%s'", name); return FALSE; } diff --git a/modules/module-config-endpoint/parser-endpoint.h b/modules/module-config-endpoint/parser-endpoint.h index a24a41d7fdc0fc983b83e1560424adbdc2f5345f..bdc93805098858f4ef642fd7f7b357408752df66 100644 --- a/modules/module-config-endpoint/parser-endpoint.h +++ b/modules/module-config-endpoint/parser-endpoint.h @@ -21,13 +21,18 @@ struct WpParserEndpointData { WpProperties *props; } mn; struct Endpoint { - char *name; - char *media_class; - guint direction; - guint priority; - WpProperties *props; + char *session; char *type; char *streams; + struct Config { + char *name; + char *media_class; + char *role; + guint priority; + gboolean enable_control_port; + gboolean enable_monitor; + guint direction; + } c; } e; }; diff --git a/modules/module-config-endpoint/parser-streams.c b/modules/module-config-endpoint/parser-streams.c index b1c718aa53484e1c8a66e9301e90b2b4ef20de74..a611a73be17e94c2d517d5ac208d59c29275469e 100644 --- a/modules/module-config-endpoint/parser-streams.c +++ b/modules/module-config-endpoint/parser-streams.c @@ -97,6 +97,11 @@ streams_for_each (const WpTomlTable *table, gpointer user_data) stream->priority = 0; wp_toml_table_get_uint32 (table, "priority", &stream->priority); + /* Parse the optional enable_control_port */ + stream->enable_control_port = FALSE; + wp_toml_table_get_boolean (table, "enable_control_port", + &stream->enable_control_port); + /* Increment the number of streams */ data->n_streams++; } @@ -115,6 +120,7 @@ wp_parser_streams_data_new (const gchar *location) * [[streams]] * name (string) * priority (uint32) + * enable_control_port (bool) */ /* Get the TOML file */ @@ -152,7 +158,7 @@ wp_parser_streams_add_file (WpConfigParser *parser, /* Parse the file */ data = wp_parser_streams_data_new (name); if (!data) { - g_warning ("Failed to parse configuration file '%s'", name); + wp_warning_object (parser, "Failed to parse configuration file '%s'", name); return FALSE; } diff --git a/modules/module-config-endpoint/parser-streams.h b/modules/module-config-endpoint/parser-streams.h index 75c6209bf63844f0ea29ea347fb432e0823fa3ef..821e1db1b88ba420885afa8bd84d29bbecb48237 100644 --- a/modules/module-config-endpoint/parser-streams.h +++ b/modules/module-config-endpoint/parser-streams.h @@ -21,6 +21,7 @@ G_BEGIN_DECLS struct WpParserStreamsStreamData { char *name; guint priority; + gboolean enable_control_port; }; struct WpParserStreamsData { diff --git a/tests/modules/config-endpoint.c b/tests/modules/config-endpoint.c index 94ad755d65e14dd0ac8e231989d1a3d30e8b0513..bd3411bad193cc0c396e155e53ad9bc631a0c861 100644 --- a/tests/modules/config-endpoint.c +++ b/tests/modules/config-endpoint.c @@ -7,7 +7,6 @@ */ #include "../common/base-test-fixture.h" -#include "config-endpoint/endpoint-audiotestsrc.h" #include "../../modules/module-config-endpoint/context.h" typedef struct { @@ -15,64 +14,183 @@ typedef struct { } TestConfigEndpointFixture; static void -config_endpoint_setup (TestConfigEndpointFixture *self, gconstpointer data) +config_endpoint_setup (TestConfigEndpointFixture *f, gconstpointer data) { - wp_base_test_fixture_setup (&self->base, 0); - - /* load audiotestsrc */ - pw_thread_loop_lock (self->base.server.thread_loop); - pw_context_add_spa_lib (self->base.server.context, "audiotestsrc", - "audiotestsrc/libspa-audiotestsrc"); - if (!pw_context_load_module (self->base.server.context, - "libpipewire-module-spa-node", "audiotestsrc", NULL)) { - pw_thread_loop_unlock (self->base.server.thread_loop); - g_test_skip ("audiotestsrc SPA plugin is not installed"); - return; - } - pw_thread_loop_unlock (self->base.server.thread_loop); + wp_base_test_fixture_setup (&f->base, 0); + + /* load modules */ + { + g_autoptr (WpTestServerLocker) lock = + wp_test_server_locker_new (&f->base.server); - /* Register the wp-endpoint-audiotestsrc */ - wp_factory_new (self->base.core, "wp-endpoint-audiotestsrc", - wp_endpoint_audiotestsrc_factory); + g_assert_cmpint (pw_context_add_spa_lib (f->base.server.context, + "audiotestsrc", "audiotestsrc/libspa-audiotestsrc"), ==, 0); + g_assert_nonnull (pw_context_load_module (f->base.server.context, + "libpipewire-module-spa-node-factory", NULL, NULL)); + g_assert_nonnull (pw_context_load_module (f->base.server.context, + "libpipewire-module-adapter", NULL, NULL)); + } + { + g_autoptr (GError) error = NULL; + WpModule *module = wp_module_load (f->base.core, "C", + "libwireplumber-module-si-simple-node-endpoint", NULL, &error); + g_assert_no_error (error); + g_assert_nonnull (module); + } + { + g_autoptr (GError) error = NULL; + WpModule *module = wp_module_load (f->base.core, "C", + "libwireplumber-module-si-adapter", NULL, &error); + g_assert_no_error (error); + g_assert_nonnull (module); + } + { + g_autoptr (GError) error = NULL; + WpModule *module = wp_module_load (f->base.core, "C", + "libwireplumber-module-si-convert", NULL, &error); + g_assert_no_error (error); + g_assert_nonnull (module); + } + { + g_autoptr (GError) error = NULL; + WpModule *module = wp_module_load (f->base.core, "C", + "libwireplumber-module-si-audio-softdsp-endpoint", NULL, &error); + g_assert_no_error (error); + g_assert_nonnull (module); + } } static void -config_endpoint_teardown (TestConfigEndpointFixture *self, gconstpointer data) +config_endpoint_teardown (TestConfigEndpointFixture *f, gconstpointer data) { - wp_base_test_fixture_teardown (&self->base); + wp_base_test_fixture_teardown (&f->base); } static void -on_audiotestsrc_created (WpConfigEndpointContext *ctx, WpEndpoint *ep, +on_default_session_exported (WpProxy * session, GAsyncResult * res, TestConfigEndpointFixture *f) { + g_autoptr (GError) error = NULL; + g_assert_true (wp_proxy_augment_finish (session, res, &error)); + g_assert_no_error (error); + g_assert_true (WP_IS_IMPL_SESSION (session)); + g_main_loop_quit (f->base.loop); +} + +static void +on_audiotestsrc_simple_endpoint_created (WpConfigEndpointContext *ctx, + WpSessionItem *ep, TestConfigEndpointFixture *f) +{ + g_autoptr (WpNode) node = NULL; + g_autoptr (WpProperties) props = NULL; g_assert_nonnull (ep); + + g_autoptr (GVariant) v = wp_session_item_get_configuration (ep); + const gchar *str; + guint32 prio; + g_assert_true (g_variant_lookup (v, "name", "&s", &str)); + g_assert_cmpstr (str, ==, "audiotestsrc-endpoint"); + g_assert_true (g_variant_lookup (v, "media-class", "&s", &str)); + g_assert_cmpstr (str, ==, "Audio/Source"); + g_assert_true (g_variant_lookup (v, "role", "&s", &str)); + g_assert_cmpstr (str, ==, "Multimedia"); + g_assert_true (g_variant_lookup (v, "priority", "u", &prio)); + g_assert_cmpuint (prio, ==, 0); + g_main_loop_quit (f->base.loop); } static void -basic (TestConfigEndpointFixture *f, gconstpointer data) +on_audiotestsrc_streams_endpoint_created (WpConfigEndpointContext *ctx, + WpSessionItem *ep, TestConfigEndpointFixture *f) +{ + g_assert_nonnull (ep); + g_assert_cmpuint (5, ==, wp_session_bin_get_n_children (WP_SESSION_BIN (ep))); + + g_autoptr (GVariant) v = wp_session_item_get_configuration (ep); + guint64 p_i; + g_assert_true (g_variant_lookup (v, "adapter", "t", &p_i)); + g_assert_nonnull ((gpointer)p_i); + + g_autoptr (GVariant) v2 = wp_session_item_get_configuration ((gpointer)p_i); + const gchar *str; + guint32 prio; + g_assert_true (g_variant_lookup (v2, "name", "&s", &str)); + g_assert_cmpstr (str, ==, "audiotestsrc-endpoint"); + g_assert_true (g_variant_lookup (v2, "media-class", "&s", &str)); + g_assert_cmpstr (str, ==, "Audio/Source"); + g_assert_true (g_variant_lookup (v2, "role", "&s", &str)); + g_assert_cmpstr (str, ==, "Multimedia"); + g_assert_true (g_variant_lookup (v2, "priority", "u", &prio)); + g_assert_cmpuint (prio, ==, 0); + + g_main_loop_quit (f->base.loop); +} + +static void +simple (TestConfigEndpointFixture *f, gconstpointer data) { /* Set the configuration path */ g_autoptr (WpConfiguration) config = wp_configuration_get_instance (f->base.core); g_assert_nonnull (config); - wp_configuration_add_path (config, "config-endpoint/basic"); + wp_configuration_add_path (config, "config-endpoint/simple"); - /* Create the context and handle the endpoint-created callback */ + /* Create the endpoint context and handle the endpoint-created callback */ g_autoptr (WpConfigEndpointContext) ctx = wp_config_endpoint_context_new (f->base.core); g_assert_nonnull (ctx); - g_assert_cmpint (wp_config_endpoint_context_get_length (ctx), ==, 0); + g_signal_connect (ctx, "endpoint-created", + (GCallback) on_audiotestsrc_simple_endpoint_created, f); + + /* Create and export the default session */ + g_autoptr (WpImplSession) session = wp_impl_session_new (f->base.core); + wp_impl_session_set_property (session, "session.name", "default"); + wp_proxy_augment (WP_PROXY (session), WP_PROXY_FEATURE_BOUND, NULL, + (GAsyncReadyCallback) on_default_session_exported, f); + g_main_loop_run (f->base.loop); - /* Add a handler to stop the main loop when the endpoint is created */ + /* Create the audiotestsrc node and run until the endpoint is created */ + g_autoptr (WpNode) node = wp_node_new_from_factory (f->base.core, + "spa-node-factory", + wp_properties_new ( + "factory.name", "audiotestsrc", + "node.name", "audiotestsrc0", + NULL)); + g_assert_nonnull (node); + g_main_loop_run (f->base.loop); +} + +static void +streams (TestConfigEndpointFixture *f, gconstpointer data) +{ + /* Set the configuration path */ + g_autoptr (WpConfiguration) config = wp_configuration_get_instance (f->base.core); + g_assert_nonnull (config); + wp_configuration_add_path (config, "config-endpoint/streams"); + + /* Create the endpoint context and handle the endpoint-created callback */ + g_autoptr (WpConfigEndpointContext) ctx = + wp_config_endpoint_context_new (f->base.core); + g_assert_nonnull (ctx); g_signal_connect (ctx, "endpoint-created", - (GCallback) on_audiotestsrc_created, f); + (GCallback) on_audiotestsrc_streams_endpoint_created, f); - /* Run the main loop */ + /* Create and export the default session */ + g_autoptr (WpImplSession) session = wp_impl_session_new (f->base.core); + wp_impl_session_set_property (session, "session.name", "default"); + wp_proxy_augment (WP_PROXY (session), WP_PROXY_FEATURE_BOUND, NULL, + (GAsyncReadyCallback) on_default_session_exported, f); g_main_loop_run (f->base.loop); - /* Check if the endpoint was created */ - g_assert_cmpint (wp_config_endpoint_context_get_length (ctx), ==, 1); + /* create audiotestsrc adapter node and run until the endpoint is created */ + g_autoptr (WpNode) node = wp_node_new_from_factory (f->base.core, + "adapter", + wp_properties_new ( + "factory.name", "audiotestsrc", + "node.name", "adapter-audiotestsrc0", + NULL)); + g_assert_nonnull (node); + g_main_loop_run (f->base.loop); } int @@ -82,8 +200,10 @@ main (int argc, char *argv[]) pw_init (NULL, NULL); g_log_set_writer_func (wp_log_writer_default, NULL, NULL); - g_test_add ("/modules/config-endpoint/basic", TestConfigEndpointFixture, - NULL, config_endpoint_setup, basic, config_endpoint_teardown); + g_test_add ("/modules/config-endpoint/simple", TestConfigEndpointFixture, + NULL, config_endpoint_setup, simple, config_endpoint_teardown); + g_test_add ("/modules/config-endpoint/streams", TestConfigEndpointFixture, + NULL, config_endpoint_setup, streams, config_endpoint_teardown); return g_test_run (); } diff --git a/tests/modules/config-endpoint/basic/audio-source.endpoint b/tests/modules/config-endpoint/basic/audio-source.endpoint deleted file mode 100644 index bf9fb7d11171840ed90291665065c790a09a0289..0000000000000000000000000000000000000000 --- a/tests/modules/config-endpoint/basic/audio-source.endpoint +++ /dev/null @@ -1,9 +0,0 @@ -[match-node] -properties = [ - { name = "media.class", value = "Audio/Source" }, -] - -[endpoint] -direction = "source" -type = "wp-endpoint-audiotestsrc" -streams = "default.streams" diff --git a/tests/modules/config-endpoint/endpoint-audiotestsrc.c b/tests/modules/config-endpoint/endpoint-audiotestsrc.c deleted file mode 100644 index 034c086907e504adf6344196571fd81fd7336594..0000000000000000000000000000000000000000 --- a/tests/modules/config-endpoint/endpoint-audiotestsrc.c +++ /dev/null @@ -1,254 +0,0 @@ -/* WirePlumber - * - * Copyright © 2019 Collabora Ltd. - * @author Julian Bouzas <julian.bouzas@collabora.com> - * - * SPDX-License-Identifier: MIT - */ - -#include <wp/wp.h> - -#include "endpoint-audiotestsrc.h" - -struct _WpEndpointAudiotestsrc -{ - WpBaseEndpoint parent; - GTask *init_task; - guint id; - - /* Props */ - WpNode *node; - GVariant *streams; -}; - -enum { - PROP_0, - PROP_PROXY_NODE, - PROP_STREAMS, -}; - -static GAsyncInitableIface *wp_endpoint_audiotestsrc_parent_interface = NULL; -static void wp_endpoint_audiotestsrc_async_initable_init (gpointer iface, - gpointer iface_data); - -G_DEFINE_TYPE_WITH_CODE (WpEndpointAudiotestsrc, wp_endpoint_audiotestsrc, - WP_TYPE_BASE_ENDPOINT, - G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, - wp_endpoint_audiotestsrc_async_initable_init)) - -static WpProperties * -wp_endpoint_audiotestsrc_get_properties (WpBaseEndpoint * ep) -{ - WpEndpointAudiotestsrc *self = WP_ENDPOINT_AUDIOTESTSRC (ep); - return wp_proxy_get_properties (WP_PROXY (self->node)); -} - -static const char * -wp_endpoint_audiotestsrc_get_role (WpBaseEndpoint * ep) -{ - return NULL; -} - -static guint32 -wp_endpoint_audiotestsrc_get_global_id (WpBaseEndpoint * ep) -{ - WpEndpointAudiotestsrc *self = WP_ENDPOINT_AUDIOTESTSRC (ep); - return self->id; -} - -static gboolean -wp_endpoint_audiotestsrc_prepare_link (WpBaseEndpoint * ep, guint32 stream_id, - WpBaseEndpointLink * link, GVariant ** properties, GError ** error) -{ - return TRUE; -} - -static const char * -wp_endpoint_audiotestsrc_get_endpoint_link_factory (WpBaseEndpoint * ep) -{ - return NULL; -} - -static void -wp_endpoint_audiotestsrc_constructed (GObject * object) -{ - WpEndpointAudiotestsrc *self = WP_ENDPOINT_AUDIOTESTSRC (object); - GVariantDict d; - GVariantIter iter; - const gchar *stream; - guint priority; - int i; - - if (self->streams) { - g_variant_iter_init (&iter, self->streams); - for (i = 0; g_variant_iter_next (&iter, "(&su)", &stream, &priority); i++) { - g_variant_dict_init (&d, NULL); - g_variant_dict_insert (&d, "id", "u", i); - g_variant_dict_insert (&d, "name", "s", stream); - g_variant_dict_insert (&d, "priority", "u", priority); - wp_base_endpoint_register_stream (WP_BASE_ENDPOINT (self), g_variant_dict_end (&d)); - } - } - - G_OBJECT_CLASS (wp_endpoint_audiotestsrc_parent_class)->constructed (object); -} - -static void -wp_endpoint_audiotestsrc_set_property (GObject * object, guint property_id, - const GValue * value, GParamSpec * pspec) -{ - WpEndpointAudiotestsrc *self = WP_ENDPOINT_AUDIOTESTSRC (object); - - switch (property_id) { - case PROP_PROXY_NODE: - self->node = g_value_dup_object (value); - break; - case PROP_STREAMS: - self->streams = g_value_dup_variant(value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -wp_endpoint_audiotestsrc_get_property (GObject * object, guint property_id, - GValue * value, GParamSpec * pspec) -{ - WpEndpointAudiotestsrc *self = WP_ENDPOINT_AUDIOTESTSRC (object); - - switch (property_id) { - case PROP_PROXY_NODE: - g_value_set_object (value, self->node); - break; - case PROP_STREAMS: - g_value_set_variant (value, self->streams); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -wp_endpoint_audiotestsrc_finalize (GObject * object) -{ - WpEndpointAudiotestsrc *self = WP_ENDPOINT_AUDIOTESTSRC (object); - - g_clear_object(&self->node); - g_clear_pointer(&self->streams, g_variant_unref); - - G_OBJECT_CLASS (wp_endpoint_audiotestsrc_parent_class)->finalize (object); -} - -static void -wp_endpoint_audiotestsrc_finish_creation (WpCore *core, GAsyncResult *res, - WpEndpointAudiotestsrc *self) -{ - g_task_return_boolean (self->init_task, TRUE); - g_clear_object (&self->init_task); -} - -static void -wp_endpoint_audiotestsrc_init_async (GAsyncInitable *initable, int io_priority, - GCancellable *cancellable, GAsyncReadyCallback callback, gpointer data) -{ - WpEndpointAudiotestsrc *self = WP_ENDPOINT_AUDIOTESTSRC (initable); - - self->init_task = g_task_new (initable, cancellable, callback, data); - - wp_endpoint_audiotestsrc_parent_interface->init_async (initable, io_priority, - cancellable, callback, data); - - g_autoptr (WpCore) core = wp_base_endpoint_get_core (WP_BASE_ENDPOINT(self)); - g_return_if_fail (core); - - wp_core_sync (core, NULL, - (GAsyncReadyCallback) wp_endpoint_audiotestsrc_finish_creation, self); -} - -static void -wp_endpoint_audiotestsrc_async_initable_init (gpointer iface, - gpointer iface_data) -{ - GAsyncInitableIface *ai_iface = iface; - wp_endpoint_audiotestsrc_parent_interface = - g_type_interface_peek_parent (iface); - ai_iface->init_async = wp_endpoint_audiotestsrc_init_async; -} - -static void -wp_endpoint_audiotestsrc_init (WpEndpointAudiotestsrc * self) -{ - static guint id = 0; - self->id = id++; -} - -static void -wp_endpoint_audiotestsrc_class_init (WpEndpointAudiotestsrcClass * klass) -{ - GObjectClass *object_class = (GObjectClass *) klass; - WpBaseEndpointClass *endpoint_class = (WpBaseEndpointClass *) klass; - - object_class->constructed = wp_endpoint_audiotestsrc_constructed; - object_class->finalize = wp_endpoint_audiotestsrc_finalize; - object_class->set_property = wp_endpoint_audiotestsrc_set_property; - object_class->get_property = wp_endpoint_audiotestsrc_get_property; - - endpoint_class->get_properties = wp_endpoint_audiotestsrc_get_properties; - endpoint_class->get_role = wp_endpoint_audiotestsrc_get_role; - endpoint_class->get_global_id = wp_endpoint_audiotestsrc_get_global_id; - endpoint_class->prepare_link = wp_endpoint_audiotestsrc_prepare_link; - endpoint_class->get_endpoint_link_factory = - wp_endpoint_audiotestsrc_get_endpoint_link_factory; - - g_object_class_install_property (object_class, PROP_PROXY_NODE, - g_param_spec_object ("node", "node", - "The node this endpoint refers to", WP_TYPE_NODE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (object_class, PROP_STREAMS, - g_param_spec_variant ("streams", "streams", - "The stream names for the streams to register", - G_VARIANT_TYPE ("a(su)"), NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); -} - -void -wp_endpoint_audiotestsrc_factory (WpFactory * factory, GType type, - GVariant * properties, GAsyncReadyCallback ready, gpointer data) -{ - g_autoptr (WpCore) core = NULL; - const gchar *name, *media_class; - guint direction, priority; - guint64 node; - g_autoptr (GVariant) streams = NULL; - - core = wp_factory_get_core(factory); - g_return_if_fail (core); - - if (!g_variant_lookup (properties, "name", "&s", &name)) - 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, "priority", "u", &priority)) - return; - if (!g_variant_lookup (properties, "node", "t", &node)) - return; - streams = g_variant_lookup_value (properties, "streams", - G_VARIANT_TYPE ("a(su)")); - - g_async_initable_new_async (wp_endpoint_audiotestsrc_get_type (), - G_PRIORITY_DEFAULT, NULL, ready, data, - "core", core, - "name", name, - "media-class", media_class, - "direction", direction, - "priority", priority, - "node", (gpointer) node, - "streams", streams, - NULL); -} diff --git a/tests/modules/config-endpoint/endpoint-audiotestsrc.h b/tests/modules/config-endpoint/endpoint-audiotestsrc.h deleted file mode 100644 index 5fa96dd7f6d7ba018e2fa64014005b201929457a..0000000000000000000000000000000000000000 --- a/tests/modules/config-endpoint/endpoint-audiotestsrc.h +++ /dev/null @@ -1,24 +0,0 @@ -/* WirePlumber - * - * Copyright © 2019 Collabora Ltd. - * @author Julian Bouzas <julian.bouzas@collabora.com> - * - * SPDX-License-Identifier: MIT - */ - -#ifndef __WIREPLUMBER_ENDPOINT_AUDIOTESTSRC_H__ -#define __WIREPLUMBER_ENDPOINT_AUDIOTESTSRC_H__ - -#include <wp/wp.h> - -G_BEGIN_DECLS - -G_DECLARE_FINAL_TYPE (WpEndpointAudiotestsrc, wp_endpoint_audiotestsrc, WP, - ENDPOINT_AUDIOTESTSRC, WpBaseEndpoint) - -void wp_endpoint_audiotestsrc_factory (WpFactory * factory, GType type, - GVariant * properties, GAsyncReadyCallback ready, gpointer data); - -G_END_DECLS - -#endif diff --git a/tests/modules/config-endpoint/simple/audio-source.endpoint b/tests/modules/config-endpoint/simple/audio-source.endpoint new file mode 100644 index 0000000000000000000000000000000000000000..3421e343587ef3ee25267ac171b3cd3bde90d984 --- /dev/null +++ b/tests/modules/config-endpoint/simple/audio-source.endpoint @@ -0,0 +1,14 @@ +[match-node] +properties = [ + { name = "media.class", value = "Audio/Source" }, +] + +[endpoint] +session = "default" +type = "si-simple-node-endpoint" + +[endpoint.config] +name = "audiotestsrc-endpoint" +media_class = "Audio/Source" +role = "Multimedia" +priority = 0 diff --git a/tests/modules/config-endpoint/streams/audio-source.endpoint b/tests/modules/config-endpoint/streams/audio-source.endpoint new file mode 100644 index 0000000000000000000000000000000000000000..938cad58988a5f6e0409c26fca44a91abccb0bc7 --- /dev/null +++ b/tests/modules/config-endpoint/streams/audio-source.endpoint @@ -0,0 +1,15 @@ +[match-node] +properties = [ + { name = "media.class", value = "Audio/Source" }, +] + +[endpoint] +session = "default" +type = "si-adapter" +streams = "default.streams" + +[endpoint.config] +name = "audiotestsrc-endpoint" +media_class = "Audio/Source" +role = "Multimedia" +priority = 0 diff --git a/tests/modules/config-endpoint/basic/default.streams b/tests/modules/config-endpoint/streams/default.streams similarity index 56% rename from tests/modules/config-endpoint/basic/default.streams rename to tests/modules/config-endpoint/streams/default.streams index 50cd23c79cda3678cbd094d4db3edcd756006c86..d4264c09cc1ccf747e847e4bc1e401618c97319e 100644 --- a/tests/modules/config-endpoint/basic/default.streams +++ b/tests/modules/config-endpoint/streams/default.streams @@ -1,15 +1,19 @@ [[streams]] name = "0" priority = 0 +enable_control_port = false [[streams]] name = "2" priority = 2 +enable_control_port = false [[streams]] name = "3" priority = 3 +enable_control_port = false [[streams]] name = "4" priority = 4 +enable_control_port = false diff --git a/tests/modules/meson.build b/tests/modules/meson.build index 79f8679497345c32af4108af1bef30b4166ea40e..452e6bf543e4b5c847b67eac4f83084404db0463 100644 --- a/tests/modules/meson.build +++ b/tests/modules/meson.build @@ -38,7 +38,6 @@ test( executable('test-config-endpoint', [ 'config-endpoint.c', - 'config-endpoint/endpoint-audiotestsrc.c', '../../modules/module-config-endpoint/parser-endpoint.c', '../../modules/module-config-endpoint/parser-streams.c', '../../modules/module-config-endpoint/context.c',