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:
@@ -156,7 +156,7 @@ wp_default_nodes_api_get_default_node (WpDefaultNodesApi * self,
|
|||||||
{
|
{
|
||||||
gint node_t = -1;
|
gint node_t = -1;
|
||||||
for (gint i = 0; i < N_DEFAULT_NODES; i++) {
|
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;
|
node_t = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -166,8 +166,6 @@ wp_default_nodes_api_get_default_node (WpDefaultNodesApi * self,
|
|||||||
WP_TYPE_NODE,
|
WP_TYPE_NODE,
|
||||||
WP_CONSTRAINT_TYPE_PW_PROPERTY,
|
WP_CONSTRAINT_TYPE_PW_PROPERTY,
|
||||||
PW_KEY_NODE_NAME, "=s", self->defaults[node_t],
|
PW_KEY_NODE_NAME, "=s", self->defaults[node_t],
|
||||||
WP_CONSTRAINT_TYPE_PW_PROPERTY,
|
|
||||||
PW_KEY_MEDIA_CLASS, "=s", MEDIA_CLASS[node_t],
|
|
||||||
NULL);
|
NULL);
|
||||||
if (node)
|
if (node)
|
||||||
return wp_proxy_get_bound_id (WP_PROXY (node));
|
return wp_proxy_get_bound_id (WP_PROXY (node));
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <pipewire/keys.h>
|
#include <pipewire/keys.h>
|
||||||
|
|
||||||
#define DEFAULT_CONFIG_KEYS 1
|
#define COMPILING_MODULE_DEFAULT_NODES 1
|
||||||
#include "module-default-nodes/common.h"
|
#include "module-default-nodes/common.h"
|
||||||
|
|
||||||
#define NAME "default-nodes"
|
#define NAME "default-nodes"
|
||||||
@@ -39,6 +39,7 @@ struct _WpDefaultNodes
|
|||||||
WpObjectManager *metadata_om;
|
WpObjectManager *metadata_om;
|
||||||
WpObjectManager *nodes_om;
|
WpObjectManager *nodes_om;
|
||||||
GSource *timeout_source;
|
GSource *timeout_source;
|
||||||
|
GSource *idle_source;
|
||||||
|
|
||||||
/* properties */
|
/* properties */
|
||||||
guint save_interval_ms;
|
guint save_interval_ms;
|
||||||
@@ -107,7 +108,8 @@ find_highest_priority_node (WpDefaultNodes * self, gint node_t)
|
|||||||
WpNode *res = NULL;
|
WpNode *res = NULL;
|
||||||
|
|
||||||
it = wp_object_manager_new_filtered_iterator (self->nodes_om, WP_TYPE_NODE,
|
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);
|
NULL);
|
||||||
|
|
||||||
for (; wp_iterator_next (it, &val); g_value_unset (&val)) {
|
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) {
|
if (node_name) {
|
||||||
node = wp_object_manager_lookup (self->nodes_om, WP_TYPE_NODE,
|
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_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);
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,7 +159,7 @@ reevaluate_default_node (WpDefaultNodes * self, WpMetadata *m, gint node_t)
|
|||||||
self->defaults[node_t].value = g_strdup (node_name);
|
self->defaults[node_t].value = g_strdup (node_name);
|
||||||
|
|
||||||
wp_info_object (self, "set default node for %s: %s",
|
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);
|
g_snprintf (buf, sizeof(buf), "{ \"name\": \"%s\" }", node_name);
|
||||||
wp_metadata_set (m, 0, DEFAULT_KEY[node_t], "Spa:String:JSON", buf);
|
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
|
static gboolean
|
||||||
on_nodes_changed (WpObjectManager * om, WpDefaultNodes * self)
|
rescan (WpDefaultNodes * self)
|
||||||
{
|
{
|
||||||
g_autoptr (WpMetadata) metadata = NULL;
|
g_autoptr (WpMetadata) metadata = NULL;
|
||||||
|
|
||||||
|
g_clear_pointer (&self->idle_source, g_source_unref);
|
||||||
|
|
||||||
/* Get the metadata */
|
/* Get the metadata */
|
||||||
metadata = wp_object_manager_lookup (self->metadata_om, WP_TYPE_METADATA,
|
metadata = wp_object_manager_lookup (self->metadata_om, WP_TYPE_METADATA,
|
||||||
NULL);
|
NULL);
|
||||||
if (!metadata)
|
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_SINK);
|
||||||
reevaluate_default_node (self, metadata, AUDIO_SOURCE);
|
reevaluate_default_node (self, metadata, AUDIO_SOURCE);
|
||||||
reevaluate_default_node (self, metadata, VIDEO_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
|
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_add_interest (self->nodes_om, WP_TYPE_NODE, NULL);
|
||||||
wp_object_manager_request_object_features (self->nodes_om, WP_TYPE_NODE,
|
wp_object_manager_request_object_features (self->nodes_om, WP_TYPE_NODE,
|
||||||
WP_PIPEWIRE_OBJECT_FEATURES_MINIMAL);
|
WP_PIPEWIRE_OBJECT_FEATURES_MINIMAL);
|
||||||
g_signal_connect_object (self->nodes_om, "objects-changed",
|
g_signal_connect_object (self->nodes_om, "object-added",
|
||||||
G_CALLBACK (on_nodes_changed), self, 0);
|
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);
|
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);
|
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 */
|
/* Clear the current timeout callback */
|
||||||
if (self->timeout_source)
|
if (self->timeout_source)
|
||||||
g_source_destroy (self->timeout_source);
|
g_source_destroy (self->timeout_source);
|
||||||
|
@@ -23,20 +23,34 @@ static const gchar * DEFAULT_KEY[N_DEFAULT_NODES] = {
|
|||||||
[VIDEO_SOURCE] = "default.video.source",
|
[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] = {
|
static const gchar * DEFAULT_CONFIG_KEY[N_DEFAULT_NODES] = {
|
||||||
[AUDIO_SINK] = "default.configured.audio.sink",
|
[AUDIO_SINK] = "default.configured.audio.sink",
|
||||||
[AUDIO_SOURCE] = "default.configured.audio.source",
|
[AUDIO_SOURCE] = "default.configured.audio.source",
|
||||||
[VIDEO_SOURCE] = "default.configured.video.source",
|
[VIDEO_SOURCE] = "default.configured.video.source",
|
||||||
};
|
};
|
||||||
#endif
|
|
||||||
|
|
||||||
static const gchar * MEDIA_CLASS[N_DEFAULT_NODES] = {
|
static const gchar * MEDIA_CLASS_MATCH[N_DEFAULT_NODES] = {
|
||||||
[AUDIO_SINK] = "Audio/Sink",
|
[AUDIO_SINK] = "Audio/*",
|
||||||
[AUDIO_SOURCE] = "Audio/Source",
|
[AUDIO_SOURCE] = "Audio/*",
|
||||||
[VIDEO_SOURCE] = "Video/Source",
|
[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
|
static int
|
||||||
json_object_find (const char *obj, const char *key, char *value, size_t len)
|
json_object_find (const char *obj, const char *key, char *value, size_t len)
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user