From 0a1fd9a749d6fd7184809789a10d61ae23974a46 Mon Sep 17 00:00:00 2001 From: Michael Saxl Date: Mon, 30 Jan 2023 19:21:22 +0100 Subject: [PATCH] plasma 5.26 does not like PA_PROP_DEVICE_CLASS abstract according to doxygen only "sound", "modem", "monitor", "filter" are allowed. Use sound as this is the most appropriate also plasma-pa hides virtual devices by default. flag them as hardware since to the user this virtual card behaves like that. It is not some kind of filter or secondary output --- src/module-xrdp-sink.c | 107 +++++++++++++++++++++++++++++++++++-- src/module-xrdp-source.c | 110 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 208 insertions(+), 9 deletions(-) diff --git a/src/module-xrdp-sink.c b/src/module-xrdp-sink.c index 824c7bb..44c9a0b 100644 --- a/src/module-xrdp-sink.c +++ b/src/module-xrdp-sink.c @@ -82,6 +82,7 @@ PA_MODULE_USAGE( "rate= " "channels= " "channel_map= " + "description= " "xrdp_socket_path= " "xrdp_pulse_sink_socket="); @@ -101,6 +102,8 @@ struct userdata { pa_core *core; pa_module *module; pa_sink *sink; + pa_device_port *port; + pa_card *card; pa_thread *thread; pa_thread_mq thread_mq; @@ -126,11 +129,81 @@ static const char* const valid_modargs[] = { "channel_map", "xrdp_socket_path", "xrdp_pulse_sink_socket", + "description", NULL }; static int close_send(struct userdata *u); +static pa_device_port *xrdp_create_port(struct userdata *u) { + pa_device_port_new_data data; + pa_device_port *port; + + pa_device_port_new_data_init(&data); + + pa_device_port_new_data_set_name(&data, "xrdp-output"); + pa_device_port_new_data_set_description(&data, "xrdp output"); + pa_device_port_new_data_set_direction(&data, PA_DIRECTION_OUTPUT); + pa_device_port_new_data_set_available(&data, PA_AVAILABLE_YES); +#if defined(PA_CHECK_VERSION) && PA_CHECK_VERSION(14, 0, 0) + pa_device_port_new_data_set_type(&data, PA_DEVICE_PORT_TYPE_NETWORK); +#endif + + port = pa_device_port_new(u->core, &data, 0); + + pa_device_port_new_data_done(&data); + + if (port == NULL) + { + return NULL; + } + + pa_device_port_ref(port); + + return port; +} + +static pa_card_profile *xrdp_create_profile() { + pa_card_profile *profile; + + profile = pa_card_profile_new("output:xrdp", "xrdp audio output", 0); + profile->priority = 10; + profile->n_sinks = 1; + profile->n_sources = 0; + profile->max_sink_channels = 2; + profile->max_source_channels = 0; + + return profile; +} + +static pa_card *xrdp_create_card(pa_module *m, pa_device_port *port, pa_card_profile *profile) { + pa_card_new_data data; + pa_card *card; + + pa_card_new_data_init(&data); + data.driver = __FILE__; + + pa_card_new_data_set_name(&data, "xrdp.sink"); + + pa_hashmap_put(data.ports, port->name, port); + pa_hashmap_put(data.profiles, profile->name, profile); + + card = pa_card_new(m->core, &data); + + pa_card_new_data_done(&data); + + if (card == NULL) + { + return NULL; + } + + pa_card_choose_initial_profile(card); + + pa_card_put(card); + + return card; +} + static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { @@ -513,6 +586,8 @@ static void set_sink_socket(pa_modargs *ma, struct userdata *u) { int pa__init(pa_module*m) { struct userdata *u = NULL; + pa_device_port *port; + pa_card_profile *profile; pa_sample_spec ss; pa_channel_map map; pa_modargs *ma = NULL; @@ -558,8 +633,11 @@ int pa__init(pa_module*m) { pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME)); pa_sink_new_data_set_sample_spec(&data, &ss); pa_sink_new_data_set_channel_map(&data, &map); - pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, "xrdp sink"); - pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "abstract"); + pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, pa_modargs_get_value(ma, "description", "remote audio output")); + pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "sound"); + pa_proplist_sets(data.proplist, PA_PROP_DEVICE_FORM_FACTOR, "computer"); + pa_proplist_sets(data.proplist, PA_PROP_DEVICE_PRODUCT_NAME, "xrdp"); + if (pa_modargs_get_proplist(ma, "sink_properties", data.proplist, PA_UPDATE_REPLACE) < 0) { @@ -567,9 +645,27 @@ int pa__init(pa_module*m) { pa_sink_new_data_done(&data); goto fail; } + port = xrdp_create_port(u); + if (port == NULL) { + pa_log("Failed to create port object"); + goto fail; + } + + profile = xrdp_create_profile(); + + pa_hashmap_put(port->profiles, profile->name, profile); + + u->card = xrdp_create_card(m, port, profile); + if (u->card == NULL) { + pa_log("Failed to create card object"); + goto fail; + } + + data.card = u->card; + pa_hashmap_put(data.ports, port->name, port); u->sink = pa_sink_new(m->core, &data, - PA_SINK_LATENCY | PA_SINK_DYNAMIC_LATENCY); + PA_SINK_LATENCY | PA_SINK_DYNAMIC_LATENCY | PA_SINK_NETWORK | PA_SINK_HARDWARE); pa_sink_new_data_done(&data); if (!u->sink) { @@ -666,6 +762,11 @@ void pa__done(pa_module*m) { pa_rtpoll_free(u->rtpoll); } + if (u->card) + { + pa_card_free(u->card); + } + if (u->fd >= 0) { close(u->fd); diff --git a/src/module-xrdp-source.c b/src/module-xrdp-source.c index f0c6aa7..26b6781 100644 --- a/src/module-xrdp-source.c +++ b/src/module-xrdp-source.c @@ -81,6 +81,8 @@ struct userdata { pa_core *core; pa_module *module; pa_source *source; + pa_device_port *port; + pa_card *card; pa_thread *thread; pa_thread_mq thread_mq; @@ -111,6 +113,75 @@ static const char* const valid_modargs[] = { NULL }; +static pa_device_port *xrdp_create_port(struct userdata *u) { + pa_device_port_new_data data; + pa_device_port *port; + + pa_device_port_new_data_init(&data); + + pa_device_port_new_data_set_name(&data, "xrdp-input"); + pa_device_port_new_data_set_description(&data, "xrdp input"); + pa_device_port_new_data_set_direction(&data, PA_DIRECTION_INPUT); + pa_device_port_new_data_set_available(&data, PA_AVAILABLE_YES); +#if defined(PA_CHECK_VERSION) && PA_CHECK_VERSION(14, 0, 0) + pa_device_port_new_data_set_type(&data, PA_DEVICE_PORT_TYPE_NETWORK); +#endif + + port = pa_device_port_new(u->core, &data, 0); + + pa_device_port_new_data_done(&data); + + if (port == NULL) + { + return NULL; + } + + pa_device_port_ref(port); + + return port; +} + +static pa_card_profile *xrdp_create_profile() { + pa_card_profile *profile; + + profile = pa_card_profile_new("input:xrdp", "xrdp audio input", 0); + profile->priority = 10; + profile->n_sinks = 0; + profile->n_sources = 1; + profile->max_sink_channels = 0; + profile->max_source_channels = 2; + + return profile; +} + +static pa_card *xrdp_create_card(pa_module *m, pa_device_port *port, pa_card_profile *profile) { + pa_card_new_data data; + pa_card *card; + + pa_card_new_data_init(&data); + data.driver = __FILE__; + + pa_card_new_data_set_name(&data, "xrdp.source"); + + pa_hashmap_put(data.ports, port->name, port); + pa_hashmap_put(data.profiles, profile->name, profile); + + card = pa_card_new(m->core, &data); + + pa_card_new_data_done(&data); + + if (card == NULL) + { + return NULL; + } + + pa_card_choose_initial_profile(card); + + pa_card_put(card); + + return card; +} + static int get_display_num_from_display(const char *display_text) ; static int source_process_msg(pa_msgobject *o, int code, void *data, @@ -400,6 +471,8 @@ static void set_source_socket(pa_modargs *ma, struct userdata *u) { int pa__init(pa_module *m) { struct userdata *u = NULL; + pa_device_port *port; + pa_card_profile *profile; pa_sample_spec ss; pa_channel_map map; pa_modargs *ma = NULL; @@ -454,10 +527,32 @@ int pa__init(pa_module *m) { pa_source_new_data_set_name(&data, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME)); pa_source_new_data_set_sample_spec(&data, &ss); pa_source_new_data_set_channel_map(&data, &map); - pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, pa_modargs_get_value(ma, "description", "xrdp source")); - pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "abstract"); + pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, pa_modargs_get_value(ma, "description", "remote audio input")); + pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "sound"); + pa_proplist_sets(data.proplist, PA_PROP_DEVICE_FORM_FACTOR, "microphone"); + pa_proplist_sets(data.proplist, PA_PROP_DEVICE_PRODUCT_NAME, "xrdp"); + + port = xrdp_create_port(u); + if (port == NULL) { + pa_log("Failed to create port object"); + goto fail; + } + + profile = xrdp_create_profile(); - u->source = pa_source_new(m->core, &data, PA_SOURCE_LATENCY | PA_SOURCE_DYNAMIC_LATENCY); + pa_hashmap_put(port->profiles, profile->name, profile); + + u->card = xrdp_create_card(m, port, profile); + if (u->card == NULL) { + pa_log("Failed to create card object"); + goto fail; + } + + data.card = u->card; + pa_hashmap_put(data.ports, port->name, port); + + u->source = pa_source_new(m->core, &data, PA_SOURCE_LATENCY | + PA_SOURCE_DYNAMIC_LATENCY | PA_SOURCE_NETWORK | PA_SOURCE_HARDWARE); pa_source_new_data_done(&data); if (!u->source) { @@ -528,6 +623,7 @@ void pa__done(pa_module*m) { if (u->source) pa_source_unlink(u->source); + if (u->thread) { pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL); pa_thread_free(u->thread); @@ -535,9 +631,6 @@ void pa__done(pa_module*m) { pa_thread_mq_done(&u->thread_mq); - if (u->source) - pa_source_unref(u->source); - if (u->rtpoll) pa_rtpoll_free(u->rtpoll); @@ -547,6 +640,11 @@ void pa__done(pa_module*m) { u->fd = -1; } + if (u->card) + { + pa_card_free(u->card); + } + pa_xfree(u->source_socket); pa_xfree(u); }