m-default-nodes: lift restrictions on media.class for audio nodes

Previously a default source had to be Audio/Source and a default sink
had to be Audio/Sink. This did not account for:
 - monitor sources (Audio/Sink)
 - duplex nodes (Audio/Duplex)
 - virtual sources (Audio/Source/Virtual)

With this change the restriction is now on the number of input/output
ports, so any Audio/* node with output ports is a valid target to select
as a default source, while any Audio/* node with input ports is a valid
target for a default sink.

Fixes #60
This commit is contained in:
George Kiagiadakis
2021-10-05 17:21:06 +03:00
parent 4f97def376
commit 5e14c69108
3 changed files with 68 additions and 19 deletions

View File

@@ -156,7 +156,7 @@ wp_default_nodes_api_get_default_node (WpDefaultNodesApi * self,
{
gint node_t = -1;
for (gint i = 0; i < N_DEFAULT_NODES; i++) {
if (!g_strcmp0 (media_class, MEDIA_CLASS[i])) {
if (!g_strcmp0 (media_class, NODE_TYPE_STR[i])) {
node_t = i;
break;
}
@@ -166,8 +166,6 @@ wp_default_nodes_api_get_default_node (WpDefaultNodesApi * self,
WP_TYPE_NODE,
WP_CONSTRAINT_TYPE_PW_PROPERTY,
PW_KEY_NODE_NAME, "=s", self->defaults[node_t],
WP_CONSTRAINT_TYPE_PW_PROPERTY,
PW_KEY_MEDIA_CLASS, "=s", MEDIA_CLASS[node_t],
NULL);
if (node)
return wp_proxy_get_bound_id (WP_PROXY (node));

View File

@@ -10,7 +10,7 @@
#include <errno.h>
#include <pipewire/keys.h>
#define DEFAULT_CONFIG_KEYS 1
#define COMPILING_MODULE_DEFAULT_NODES 1
#include "module-default-nodes/common.h"
#define NAME "default-nodes"
@@ -39,6 +39,7 @@ struct _WpDefaultNodes
WpObjectManager *metadata_om;
WpObjectManager *nodes_om;
GSource *timeout_source;
GSource *idle_source;
/* properties */
guint save_interval_ms;
@@ -107,7 +108,8 @@ find_highest_priority_node (WpDefaultNodes * self, gint node_t)
WpNode *res = NULL;
it = wp_object_manager_new_filtered_iterator (self->nodes_om, WP_TYPE_NODE,
WP_CONSTRAINT_TYPE_PW_PROPERTY, PW_KEY_MEDIA_CLASS, "=s", MEDIA_CLASS[node_t],
WP_CONSTRAINT_TYPE_PW_PROPERTY, PW_KEY_MEDIA_CLASS, "#s", MEDIA_CLASS_MATCH[node_t],
WP_CONSTRAINT_TYPE_G_PROPERTY, N_PORTS_KEY[node_t], "!u", 0,
NULL);
for (; wp_iterator_next (it, &val); g_value_unset (&val)) {
@@ -136,7 +138,8 @@ reevaluate_default_node (WpDefaultNodes * self, WpMetadata *m, gint node_t)
if (node_name) {
node = wp_object_manager_lookup (self->nodes_om, WP_TYPE_NODE,
WP_CONSTRAINT_TYPE_PW_PROPERTY, PW_KEY_NODE_NAME, "=s", node_name,
WP_CONSTRAINT_TYPE_PW_PROPERTY, PW_KEY_MEDIA_CLASS, "=s", MEDIA_CLASS[node_t],
WP_CONSTRAINT_TYPE_PW_PROPERTY, PW_KEY_MEDIA_CLASS, "#s", MEDIA_CLASS_MATCH[node_t],
WP_CONSTRAINT_TYPE_G_PROPERTY, N_PORTS_KEY[node_t], "!u", 0,
NULL);
}
@@ -156,7 +159,7 @@ reevaluate_default_node (WpDefaultNodes * self, WpMetadata *m, gint node_t)
self->defaults[node_t].value = g_strdup (node_name);
wp_info_object (self, "set default node for %s: %s",
MEDIA_CLASS[node_t], node_name);
NODE_TYPE_STR[node_t], node_name);
g_snprintf (buf, sizeof(buf), "{ \"name\": \"%s\" }", node_name);
wp_metadata_set (m, 0, DEFAULT_KEY[node_t], "Spa:String:JSON", buf);
@@ -203,21 +206,46 @@ on_metadata_changed (WpMetadata *m, guint32 subject,
}
}
static void
on_nodes_changed (WpObjectManager * om, WpDefaultNodes * self)
static gboolean
rescan (WpDefaultNodes * self)
{
g_autoptr (WpMetadata) metadata = NULL;
g_clear_pointer (&self->idle_source, g_source_unref);
/* Get the metadata */
metadata = wp_object_manager_lookup (self->metadata_om, WP_TYPE_METADATA,
NULL);
if (!metadata)
return;
return G_SOURCE_REMOVE;
wp_trace_object (om, "nodes changed, re-evaluating defaults");
wp_trace_object (self, "nodes changed, re-evaluating defaults");
reevaluate_default_node (self, metadata, AUDIO_SINK);
reevaluate_default_node (self, metadata, AUDIO_SOURCE);
reevaluate_default_node (self, metadata, VIDEO_SOURCE);
return G_SOURCE_REMOVE;
}
static void
schedule_rescan (WpDefaultNodes * self)
{
if (!self->idle_source) {
g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (self));
g_return_if_fail (core);
wp_core_idle_add_closure (core, &self->idle_source,
g_cclosure_new_object (G_CALLBACK (rescan), G_OBJECT (self)));
}
}
static void
on_node_added (WpObjectManager * om, WpNode * node, WpDefaultNodes * self)
{
g_signal_connect_object (node, "notify::n-input-ports",
G_CALLBACK (schedule_rescan), self, G_CONNECT_SWAPPED);
g_signal_connect_object (node, "notify::n-output-ports",
G_CALLBACK (schedule_rescan), self, G_CONNECT_SWAPPED);
}
static void
@@ -246,8 +274,12 @@ on_metadata_added (WpObjectManager *om, WpMetadata *metadata, gpointer d)
wp_object_manager_add_interest (self->nodes_om, WP_TYPE_NODE, NULL);
wp_object_manager_request_object_features (self->nodes_om, WP_TYPE_NODE,
WP_PIPEWIRE_OBJECT_FEATURES_MINIMAL);
g_signal_connect_object (self->nodes_om, "objects-changed",
G_CALLBACK (on_nodes_changed), self, 0);
g_signal_connect_object (self->nodes_om, "object-added",
G_CALLBACK (on_node_added), self, 0);
g_signal_connect_object (self->nodes_om, "object-added",
G_CALLBACK (schedule_rescan), self, G_CONNECT_SWAPPED);
g_signal_connect_object (self->nodes_om, "object-removed",
G_CALLBACK (schedule_rescan), self, G_CONNECT_SWAPPED);
wp_core_install_object_manager (core, self->nodes_om);
}
@@ -282,6 +314,11 @@ wp_default_nodes_disable (WpPlugin * plugin)
{
WpDefaultNodes * self = WP_DEFAULT_NODES (plugin);
/* Clear the current rescan callback */
if (self->idle_source)
g_source_destroy (self->idle_source);
g_clear_pointer (&self->idle_source, g_source_unref);
/* Clear the current timeout callback */
if (self->timeout_source)
g_source_destroy (self->timeout_source);

View File

@@ -23,20 +23,34 @@ static const gchar * DEFAULT_KEY[N_DEFAULT_NODES] = {
[VIDEO_SOURCE] = "default.video.source",
};
#if DEFAULT_CONFIG_KEYS
static const gchar * NODE_TYPE_STR[N_DEFAULT_NODES] = {
[AUDIO_SINK] = "Audio/Sink",
[AUDIO_SOURCE] = "Audio/Source",
[VIDEO_SOURCE] = "Video/Source",
};
#if COMPILING_MODULE_DEFAULT_NODES
static const gchar * DEFAULT_CONFIG_KEY[N_DEFAULT_NODES] = {
[AUDIO_SINK] = "default.configured.audio.sink",
[AUDIO_SOURCE] = "default.configured.audio.source",
[VIDEO_SOURCE] = "default.configured.video.source",
};
#endif
static const gchar * MEDIA_CLASS[N_DEFAULT_NODES] = {
[AUDIO_SINK] = "Audio/Sink",
[AUDIO_SOURCE] = "Audio/Source",
[VIDEO_SOURCE] = "Video/Source",
static const gchar * MEDIA_CLASS_MATCH[N_DEFAULT_NODES] = {
[AUDIO_SINK] = "Audio/*",
[AUDIO_SOURCE] = "Audio/*",
[VIDEO_SOURCE] = "Video/*",
};
static const gchar * N_PORTS_KEY[N_DEFAULT_NODES] = {
[AUDIO_SINK] = "n-input-ports",
[AUDIO_SOURCE] = "n-output-ports",
[VIDEO_SOURCE] = "n-output-ports",
};
#endif
static int
json_object_find (const char *obj, const char *key, char *value, size_t len)
{