modules: remove unneeded si-audio-convert module

This commit is contained in:
Julian Bouzas 2021-04-06 15:19:22 -04:00
parent 34f5dadad0
commit b2c9084413
6 changed files with 0 additions and 613 deletions

View file

@ -112,17 +112,6 @@ shared_library(
dependencies : [wp_dep, pipewire_dep],
)
shared_library(
'wireplumber-module-si-audio-convert',
[
'module-si-audio-convert.c',
],
c_args : [common_c_args, '-DG_LOG_DOMAIN="m-si-audio-convert"'],
install : true,
install_dir : wireplumber_module_dir,
dependencies : [wp_dep, pipewire_dep],
)
shared_library(
'wireplumber-module-si-audio-endpoint',
[

View file

@ -1,436 +0,0 @@
/* WirePlumber
*
* Copyright © 2020 Collabora Ltd.
* @author Julian Bouzas <julian.bouzas@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#include <wp/wp.h>
#include <pipewire/pipewire.h>
#include <pipewire/extensions/session-manager/keys.h>
#include <spa/utils/names.h>
#include <spa/param/format.h>
#include <spa/param/audio/raw.h>
#include <spa/param/param.h>
#define SI_FACTORY_NAME "si-audio-convert"
struct _WpSiAudioConvert
{
WpSessionItem parent;
/* configuration */
WpSessionItem *target;
gchar name[96];
WpDirection direction;
gboolean control_port;
/* activate */
WpNode *node;
WpObjectManager *links_watch;
WpSessionItem *link_to_target;
};
static void si_audio_convert_port_info_init (WpSiPortInfoInterface * iface);
G_DECLARE_FINAL_TYPE(WpSiAudioConvert, si_audio_convert, WP, SI_AUDIO_CONVERT,
WpSessionItem)
G_DEFINE_TYPE_WITH_CODE (WpSiAudioConvert, si_audio_convert,
WP_TYPE_SESSION_ITEM,
G_IMPLEMENT_INTERFACE (WP_TYPE_SI_PORT_INFO, si_audio_convert_port_info_init))
static void
si_audio_convert_init (WpSiAudioConvert * self)
{
}
static void
si_audio_convert_reset (WpSessionItem * item)
{
WpSiAudioConvert *self = WP_SI_AUDIO_CONVERT (item);
/* deactivate first */
wp_object_deactivate (WP_OBJECT (self),
WP_SESSION_ITEM_FEATURE_ACTIVE | WP_SESSION_ITEM_FEATURE_EXPORTED);
/* reset */
g_clear_object (&self->target);
self->name[0] = '\0';
self->direction = WP_DIRECTION_INPUT;
self->control_port = FALSE;
WP_SESSION_ITEM_CLASS (si_audio_convert_parent_class)->reset (item);
}
static gboolean
si_audio_convert_configure (WpSessionItem * item, WpProperties *p)
{
WpSiAudioConvert *self = WP_SI_AUDIO_CONVERT (item);
g_autoptr (WpProperties) si_props = wp_properties_ensure_unique_owner (p);
WpSessionItem *target;
WpProperties *target_props = NULL;
const gchar *str;
/* reset previous config */
si_audio_convert_reset (item);
str = wp_properties_get (si_props, "name");
if (!str)
return FALSE;
strncpy (self->name, str, sizeof (self->name) - 1);
str = wp_properties_get (si_props, "target");
if (!str || sscanf(str, "%p", &target) != 1 || !WP_IS_SESSION_ITEM (target))
return FALSE;
target_props = wp_session_item_get_properties (target);
str = wp_properties_get (si_props, "direction");
if (!str) {
str = wp_properties_get (target_props, "direction");
wp_properties_set (si_props, "direction", str);
}
if (!str || sscanf(str, "%u", &self->direction) != 1)
return FALSE;
str = wp_properties_get (si_props, "enable.control.port");
if (str && sscanf(str, "%u", &self->control_port) != 1)
return FALSE;
if (!str)
wp_properties_setf (si_props, "enable.control.port", "%u",
self->control_port);
self->target = g_object_ref (target);
wp_properties_set (si_props, "si.factory.name", SI_FACTORY_NAME);
wp_session_item_set_properties (WP_SESSION_ITEM (self),
g_steal_pointer (&si_props));
return TRUE;
}
static gpointer
si_audio_convert_get_associated_proxy (WpSessionItem * item, GType proxy_type)
{
WpSiAudioConvert *self = WP_SI_AUDIO_CONVERT (item);
if (proxy_type == WP_TYPE_NODE)
return self->node ? g_object_ref (self->node) : NULL;
return NULL;
}
static void
si_audio_convert_disable_active (WpSessionItem *si)
{
WpSiAudioConvert *self = WP_SI_AUDIO_CONVERT (si);
g_clear_object (&self->node);
g_clear_object (&self->links_watch);
g_clear_object (&self->link_to_target);
wp_object_update_features (WP_OBJECT (self), 0,
WP_SESSION_ITEM_FEATURE_ACTIVE);
}
static void
on_link_activated (WpSessionItem * item, GAsyncResult * res,
WpSiAudioConvert * self)
{
g_autoptr (GError) error = NULL;
if (!wp_object_activate_finish (WP_OBJECT (item), res, &error))
wp_warning_object (item, "failed to activate link to the target node: %s",
error->message);
}
static void
do_link_to_target (WpSiAudioConvert *self)
{
g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (self->node));
g_autoptr (WpSessionItem) link = wp_session_item_make (core,
"si-standard-link");
WpProperties *props = NULL;
if (G_UNLIKELY (!link)) {
wp_warning_object (self, "could not create link; is the module loaded?");
return;
}
props = wp_properties_new_empty ();
if (self->direction == WP_DIRECTION_INPUT) {
/* Playback */
wp_properties_setf (props, "out.item", "%p", self);
wp_properties_setf (props, "in.item", "%p", self->target);
wp_properties_set (props, "out.item.port.context", "reverse");
} else {
/* Capture */
wp_properties_setf (props, "out.item", "%p", self->target);
wp_properties_setf (props, "in.item", "%p", self);
wp_properties_set (props, "in.item.port.context", "reverse");
}
/* always create passive links; that means that they won't hold the graph
running if they are the only links left around */
wp_properties_setf (props, "passive", "%u", TRUE);
wp_session_item_configure (link, props);
wp_object_activate (WP_OBJECT (link), WP_SESSION_ITEM_FEATURE_ACTIVE, NULL,
(GAsyncReadyCallback) on_link_activated, self);
self->link_to_target = g_steal_pointer (&link);
}
static void
on_links_changed (WpObjectManager * om, WpSiAudioConvert * self)
{
if (wp_object_manager_get_n_objects (om) == 0)
g_clear_object (&self->link_to_target);
else if (!self->link_to_target)
do_link_to_target (self);
}
static void
si_audio_convert_do_links_watch (WpSiAudioConvert *self, WpTransition *transition)
{
g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (self));
g_auto (GVariantBuilder) b = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_TUPLE);
g_autoptr (WpIterator) it = NULL;
g_auto (GValue) val = G_VALUE_INIT;
GVariant *ports_v = NULL;
/* get a list of our ports */
for (it = wp_node_new_ports_iterator (self->node);
wp_iterator_next (it, &val);
g_value_unset (&val)) {
WpPort *port = g_value_get_object (&val);
if (wp_port_get_direction (port) != self->direction)
continue;
g_variant_builder_add (&b, "u", wp_proxy_get_bound_id (WP_PROXY (port)));
}
ports_v = g_variant_builder_end (&b);
/* create the object manager */
self->links_watch = wp_object_manager_new ();
wp_object_manager_request_object_features (self->links_watch,
WP_TYPE_LINK, WP_PROXY_FEATURE_BOUND);
/* interested in links that have one of our ports in their
'link.input.port' or 'link.output.port' global property */
wp_object_manager_add_interest_full (self->links_watch, ({
WpObjectInterest *interest = wp_object_interest_new_type (WP_TYPE_LINK);
wp_object_interest_add_constraint (interest,
WP_CONSTRAINT_TYPE_PW_GLOBAL_PROPERTY,
(self->direction == WP_DIRECTION_INPUT) ?
PW_KEY_LINK_INPUT_PORT : PW_KEY_LINK_OUTPUT_PORT,
WP_CONSTRAINT_VERB_IN_LIST,
ports_v);
interest;
}));
g_signal_connect_object (self->links_watch, "objects-changed",
G_CALLBACK (on_links_changed), self, 0);
wp_core_install_object_manager (core, self->links_watch);
wp_object_update_features (WP_OBJECT (self),
WP_SESSION_ITEM_FEATURE_ACTIVE, 0);
}
static void
on_node_activate_done (WpObject * node, GAsyncResult * res,
WpTransition * transition)
{
WpSiAudioConvert *self = wp_transition_get_source_object (transition);
g_autoptr (GError) error = NULL;
if (!wp_object_activate_finish (node, res, &error)) {
wp_transition_return_error (transition, g_steal_pointer (&error));
return;
}
si_audio_convert_do_links_watch (self, transition);
}
static void
si_audio_convert_enable_active (WpSessionItem *si, WpTransition *transition)
{
WpSiAudioConvert *self = WP_SI_AUDIO_CONVERT (si);
g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (self));
g_autoptr (WpNode) node = NULL;
g_autoptr (WpProperties) node_props = NULL;
g_autoptr (WpProperties) props = NULL;
g_autoptr (WpProperties) target_props = NULL;
g_autoptr (WpSpaPod) format = NULL;
const gchar *str;
guint32 channels;
guint32 rate;
if (!wp_session_item_is_configured (WP_SESSION_ITEM (self))) {
wp_transition_return_error (transition,
g_error_new (WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_INVARIANT,
"si-audio-convert: item is not configured"));
return;
}
/* Get the associated node */
node = wp_session_item_get_associated_proxy (self->target, WP_TYPE_NODE);
/* set channels & rate */
target_props = wp_session_item_get_properties (self->target);
str = wp_properties_get (target_props, "preferred.n.channels");
if (!str || sscanf(str, "%u", &channels) != 1)
channels = 2;
rate = ({
g_autoptr (WpProperties) props = wp_core_get_remote_properties (core);
const gchar *rate_str = wp_properties_get (props, "default.clock.rate");
rate_str ? atoi (rate_str) : 48000;
});
/* Create the convert properties based on the adapter properties */
node_props = wp_pipewire_object_get_properties (WP_PIPEWIRE_OBJECT (node));
props = wp_properties_new (
PW_KEY_MEDIA_CLASS, "Audio/Convert",
PW_KEY_FACTORY_NAME, SPA_NAME_AUDIO_CONVERT,
/* the default mode is 'split', which breaks audio in this case */
"factory.mode", "convert",
NULL);
wp_properties_setf (props, PW_KEY_OBJECT_PATH, "%s:%s",
wp_properties_get (node_props, PW_KEY_OBJECT_PATH),
self->name);
wp_properties_setf (props, PW_KEY_NODE_NAME, "%s.%s.%s",
SPA_NAME_AUDIO_CONVERT,
wp_properties_get (node_props, PW_KEY_NODE_NAME),
self->name);
wp_properties_setf (props, PW_KEY_NODE_DESCRIPTION,
"Converter volume for %s: %s",
wp_properties_get (node_props, PW_KEY_NODE_DESCRIPTION), self->name);
/* Create the node */
self->node = wp_node_new_from_factory (core, "spa-node-factory",
g_steal_pointer (&props));
format = wp_spa_pod_new_object (
"Spa:Pod:Object:Param:Format", "Format",
"mediaType", "K", "audio",
"mediaSubtype", "K", "raw",
"format", "K", "F32P",
"rate", "i", rate,
"channels", "i", channels,
NULL);
/* Configure audioconvert to be both merger and splitter; this means it
will have an equal number of input and output ports and just passthrough
the same format, but with altered volume.
In the future we need to consider writing a simpler volume node for this,
as doing merge + split is heavy for our needs */
wp_pipewire_object_set_param (WP_PIPEWIRE_OBJECT (self->node),
"PortConfig", 0,
wp_spa_pod_new_object (
"Spa:Pod:Object:Param:PortConfig", "PortConfig",
"direction", "I", pw_direction_reverse (self->direction),
"mode", "K", "dsp",
"format", "P", format,
NULL));
wp_pipewire_object_set_param (WP_PIPEWIRE_OBJECT (self->node),
"PortConfig", 0,
wp_spa_pod_new_object (
"Spa:Pod:Object:Param:PortConfig", "PortConfig",
"direction", "I", self->direction,
"mode", "K", "dsp",
"control", "b", self->control_port,
"format", "P", format,
NULL));
wp_object_activate (WP_OBJECT (self->node),
WP_PIPEWIRE_OBJECT_FEATURES_MINIMAL | WP_NODE_FEATURE_PORTS, NULL,
(GAsyncReadyCallback) on_node_activate_done, transition);
}
static GVariant *
si_audio_convert_get_ports (WpSiPortInfo * item, const gchar * context)
{
WpSiAudioConvert *self = WP_SI_AUDIO_CONVERT (item);
g_auto (GVariantBuilder) b = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_ARRAY);
g_autoptr (WpIterator) it = NULL;
g_auto (GValue) val = G_VALUE_INIT;
WpDirection direction = self->direction;
guint32 node_id;
/* context can only be either NULL or "reverse" */
if (!g_strcmp0 (context, "reverse")) {
direction = (self->direction == WP_DIRECTION_INPUT) ?
WP_DIRECTION_OUTPUT : WP_DIRECTION_INPUT;
}
else if (context != NULL) {
/* on any other context, return an empty list of ports */
return g_variant_new_array (G_VARIANT_TYPE ("(uuu)"), NULL, 0);
}
g_variant_builder_init (&b, G_VARIANT_TYPE ("a(uuu)"));
node_id = wp_proxy_get_bound_id (WP_PROXY (self->node));
for (it = wp_node_new_ports_iterator (self->node);
wp_iterator_next (it, &val);
g_value_unset (&val))
{
WpPort *port = g_value_get_object (&val);
g_autoptr (WpProperties) props = NULL;
const gchar *channel;
guint32 port_id, channel_id = 0;
if (wp_port_get_direction (port) != direction)
continue;
port_id = wp_proxy_get_bound_id (WP_PROXY (port));
/* try to find the audio channel; if channel is NULL, this will silently
leave the channel_id to its default value, 0 */
props = wp_pipewire_object_get_properties (WP_PIPEWIRE_OBJECT (port));
channel = wp_properties_get (props, PW_KEY_AUDIO_CHANNEL);
if (channel) {
WpSpaIdValue idval = wp_spa_id_value_from_short_name (
"Spa:Enum:AudioChannel", channel);
if (idval)
channel_id = wp_spa_id_value_number (idval);
}
g_variant_builder_add (&b, "(uuu)", node_id, port_id, channel_id);
}
return g_variant_builder_end (&b);
}
static void
si_audio_convert_port_info_init (WpSiPortInfoInterface * iface)
{
iface->get_ports = si_audio_convert_get_ports;
}
static WpObjectFeatures
si_audio_convert_get_supported_features (WpObject * self)
{
return WP_SESSION_ITEM_FEATURE_ACTIVE;
}
static void
si_audio_convert_class_init (WpSiAudioConvertClass * klass)
{
WpObjectClass * wpobject_class = (WpObjectClass *) klass;
WpSessionItemClass *si_class = (WpSessionItemClass *) klass;
wpobject_class->get_supported_features =
si_audio_convert_get_supported_features;
si_class->reset = si_audio_convert_reset;
si_class->configure = si_audio_convert_configure;
si_class->get_associated_proxy = si_audio_convert_get_associated_proxy;
si_class->disable_active = si_audio_convert_disable_active;
si_class->enable_active = si_audio_convert_enable_active;
}
WP_PLUGIN_EXPORT gboolean
wireplumber__module_init (WpCore * core, GVariant * args, GError ** error)
{
wp_si_factory_register (core, wp_si_factory_new_simple (SI_FACTORY_NAME,
si_audio_convert_get_type ()));
return TRUE;
}

View file

@ -18,7 +18,6 @@ function default_policy.enable()
-- Do not disable these unless you really know what you are doing
load_module("si-node")
load_module("si-audio-adapter")
load_module("si-audio-convert")
load_module("si-standard-link")
-- Create sessions statically at startup

View file

@ -339,10 +339,6 @@ appdata_init (AppData * d, GError ** error)
"libwireplumber-module-si-audio-adapter", "module", NULL, error)))
return FALSE;
if (!(wp_core_load_component (d->core,
"libwireplumber-module-si-audio-convert", "module", NULL, error)))
return FALSE;
if (!(wp_core_load_component (d->core,
"libwireplumber-module-si-standard-link", "module", NULL, error)))
return FALSE;

View file

@ -41,13 +41,6 @@ test(
env: common_env,
)
test(
'test-si-audio-convert',
executable('test-si-audio-convert', 'si-audio-convert.c',
dependencies: common_deps, c_args: common_args),
env: common_env,
)
test(
'test-si-audio-endpoint',
executable('test-si-audio-endpoint', 'si-audio-endpoint.c',

View file

@ -1,154 +0,0 @@
/* WirePlumber
*
* Copyright © 2020 Collabora Ltd.
* @author Julian Bouzas <julian.bouzas@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#include "../common/base-test-fixture.h"
typedef struct {
WpBaseTestFixture base;
} TestFixture;
static void
test_si_audio_convert_setup (TestFixture * f, gconstpointer user_data)
{
wp_base_test_fixture_setup (&f->base, 0);
/* load modules */
{
g_autoptr (WpTestServerLocker) lock =
wp_test_server_locker_new (&f->base.server);
g_assert_cmpint (pw_context_add_spa_lib (f->base.server.context,
"fake*", "test/libspa-test"), ==, 0);
g_assert_cmpint (pw_context_add_spa_lib (f->base.server.context,
"audiotestsrc", "audiotestsrc/libspa-audiotestsrc"), ==, 0);
g_assert_cmpint (pw_context_add_spa_lib (f->base.server.context,
"audio.convert", "audioconvert/libspa-audioconvert"), ==, 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;
wp_core_load_component (f->base.core,
"libwireplumber-module-si-audio-adapter", "module", NULL, &error);
g_assert_no_error (error);
}
{
g_autoptr (GError) error = NULL;
wp_core_load_component (f->base.core,
"libwireplumber-module-si-audio-convert", "module", NULL, &error);
g_assert_no_error (error);
}
}
static void
test_si_audio_convert_teardown (TestFixture * f, gconstpointer user_data)
{
wp_base_test_fixture_teardown (&f->base);
}
static void
test_si_audio_convert_configure_activate (TestFixture * f,
gconstpointer user_data)
{
g_autoptr (WpNode) target_node = NULL;
g_autoptr (WpSessionItem) target = NULL;
g_autoptr (WpSessionItem) convert = NULL;
/* create target node */
target_node = wp_node_new_from_factory (f->base.core,
"adapter",
wp_properties_new (
"factory.name", "audiotestsrc",
"node.name", "audiotestsrc.adapter",
NULL));
g_assert_nonnull (target_node);
wp_object_activate (WP_OBJECT (target_node),
WP_PIPEWIRE_OBJECT_FEATURES_MINIMAL, NULL,
(GAsyncReadyCallback) test_object_activate_finish_cb, f);
g_main_loop_run (f->base.loop);
/* create target */
target = wp_session_item_make (f->base.core, "si-audio-adapter");
g_assert_nonnull (target);
g_assert_true (WP_IS_SI_PORT_INFO (target));
/* configure target */
{
WpProperties *props = wp_properties_new_empty ();
wp_properties_setf (props, "node", "%p", target_node);
g_assert_true (wp_session_item_configure (target, props));
g_assert_true (wp_session_item_is_configured (target));
}
/* create convert */
convert = wp_session_item_make (f->base.core, "si-audio-convert");
g_assert_nonnull (convert);
g_assert_true (WP_IS_SI_PORT_INFO (convert));
/* configure convert */
{
WpProperties *props = wp_properties_new_empty ();
wp_properties_setf (props, "target", "%p", target);
wp_properties_set (props, "name", "convert");
g_assert_true (wp_session_item_configure (convert, props));
g_assert_true (wp_session_item_is_configured (convert));
}
{
const gchar *str = NULL;
g_autoptr (WpProperties) props = wp_session_item_get_properties (convert);
g_assert_nonnull (props);
str = wp_properties_get (props, "name");
g_assert_nonnull (str);
g_assert_cmpstr ("convert", ==, str);
str = wp_properties_get (props, "direction");
g_assert_nonnull (str);
g_assert_cmpstr ("1", ==, str);
str = wp_properties_get (props, "enable.control.port");
g_assert_nonnull (str);
g_assert_cmpstr ("0", ==, str);
str = wp_properties_get (props, "si.factory.name");
g_assert_nonnull (str);
g_assert_cmpstr ("si-audio-convert", ==, str);
}
/* activate convert */
wp_object_activate (WP_OBJECT (convert), WP_SESSION_ITEM_FEATURE_ACTIVE,
NULL, (GAsyncReadyCallback) test_object_activate_finish_cb, f);
g_main_loop_run (f->base.loop);
g_assert_cmphex (wp_object_get_active_features (WP_OBJECT (convert)), ==,
WP_SESSION_ITEM_FEATURE_ACTIVE);
/* reset */
wp_session_item_reset (convert);
g_assert_false (wp_session_item_is_configured (convert));
}
gint
main (gint argc, gchar *argv[])
{
g_test_init (&argc, &argv, NULL);
wp_init (WP_INIT_ALL);
/* configure-activate */
g_test_add ("/modules/si-audio-convert/configure-activate",
TestFixture, NULL,
test_si_audio_convert_setup,
test_si_audio_convert_configure_activate,
test_si_audio_convert_teardown);
return g_test_run ();
}