mirror of
https://gitlab.freedesktop.org/pipewire/wireplumber.git
synced 2026-03-25 08:30:40 +01:00
wpctl: add list subcommand to show objects in a more script-friendly format
This commit is contained in:
parent
bda1c6db43
commit
88495d5da1
1 changed files with 169 additions and 0 deletions
|
|
@ -35,12 +35,31 @@ struct _WpCtl
|
|||
gint exit_code;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
LIST_MEDIA_ALL = 0,
|
||||
LIST_MEDIA_AUDIO,
|
||||
LIST_MEDIA_VIDEO,
|
||||
} ListMediaType;
|
||||
|
||||
typedef enum {
|
||||
LIST_OBJECT_ALL = 0,
|
||||
LIST_OBJECT_DEVICES,
|
||||
LIST_OBJECT_SINKS,
|
||||
LIST_OBJECT_SOURCES,
|
||||
} ListObjectType;
|
||||
|
||||
static struct {
|
||||
union {
|
||||
struct {
|
||||
gboolean display_nicknames;
|
||||
gboolean display_names;
|
||||
} status;
|
||||
|
||||
struct {
|
||||
ListMediaType media_type;
|
||||
ListObjectType object_type;
|
||||
} list;
|
||||
|
||||
struct {
|
||||
guint64 id;
|
||||
gboolean show_referenced;
|
||||
|
|
@ -543,6 +562,146 @@ status_run (WpCtl * self)
|
|||
g_main_loop_quit (self->loop);
|
||||
}
|
||||
|
||||
/* list */
|
||||
|
||||
static gboolean
|
||||
list_parse_positional (gint argc, gchar ** argv, GError **error)
|
||||
{
|
||||
cmdline.list.media_type = LIST_MEDIA_ALL;
|
||||
cmdline.list.object_type = LIST_OBJECT_ALL;
|
||||
|
||||
if (argc < 3)
|
||||
return TRUE;
|
||||
|
||||
if (g_strcmp0 (argv[2], "audio") == 0) {
|
||||
cmdline.list.media_type = LIST_MEDIA_AUDIO;
|
||||
} else if (g_strcmp0 (argv[2], "video") == 0) {
|
||||
cmdline.list.media_type = LIST_MEDIA_VIDEO;
|
||||
} else {
|
||||
g_set_error (error, wpctl_error_domain_quark(), 0,
|
||||
"'%s' is not a valid list option", argv[2]);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (argc < 4)
|
||||
return TRUE;
|
||||
|
||||
if (g_strcmp0 (argv[3], "devices") == 0) {
|
||||
cmdline.list.object_type = LIST_OBJECT_DEVICES;
|
||||
} else if (g_strcmp0 (argv[3], "sinks") == 0) {
|
||||
cmdline.list.object_type = LIST_OBJECT_SINKS;
|
||||
} else if (g_strcmp0 (argv[3], "sources") == 0) {
|
||||
cmdline.list.object_type = LIST_OBJECT_SOURCES;
|
||||
} else {
|
||||
g_set_error (error, wpctl_error_domain_quark(), 0,
|
||||
"'%s' is not a valid list option", argv[3]);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
list_prepare (WpCtl * self, GError ** error)
|
||||
{
|
||||
wp_object_manager_add_interest (self->om, WP_TYPE_DEVICE, NULL);
|
||||
wp_object_manager_add_interest (self->om, WP_TYPE_NODE, NULL);
|
||||
wp_object_manager_add_interest (self->om, WP_TYPE_METADATA, NULL);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
list_print_device (const GValue *item, gpointer data)
|
||||
{
|
||||
WpPipewireObject *obj = g_value_get_object (item);
|
||||
guint32 id = wp_proxy_get_bound_id (WP_PROXY (obj));
|
||||
const gchar *name = wp_pipewire_object_get_property (obj, PW_KEY_DEVICE_NAME);
|
||||
printf ("%u\t%s\t \n", id, name);
|
||||
}
|
||||
|
||||
static void
|
||||
list_print_dev_node (const GValue *item, gpointer data)
|
||||
{
|
||||
WpPipewireObject *obj = g_value_get_object (item);
|
||||
guint32 *default_node = data;
|
||||
guint32 id = wp_proxy_get_bound_id (WP_PROXY (obj));
|
||||
gboolean is_default = (*default_node == id);
|
||||
const gchar *name = wp_pipewire_object_get_property (obj, PW_KEY_NODE_NAME);
|
||||
printf ("%u\t%s\t%c\n", id, name, is_default ? '*' : ' ');
|
||||
}
|
||||
|
||||
static const struct {
|
||||
const gchar *name;
|
||||
ListMediaType value;
|
||||
} list_media_types[] = {
|
||||
{ "Audio", LIST_MEDIA_AUDIO },
|
||||
{ "Video", LIST_MEDIA_VIDEO },
|
||||
};
|
||||
|
||||
static void
|
||||
list_run (WpCtl * self)
|
||||
{
|
||||
guint32 default_node;
|
||||
g_autoptr (WpPlugin) def_nodes_api = wp_plugin_find (self->core, "default-nodes-api");
|
||||
const ListMediaType media_filter = cmdline.list.media_type;
|
||||
const ListObjectType object_filter = cmdline.list.object_type;
|
||||
|
||||
for (guint i = 0; i < G_N_ELEMENTS (list_media_types); i++) {
|
||||
if (media_filter != LIST_MEDIA_ALL &&
|
||||
media_filter != list_media_types[i].value)
|
||||
continue;
|
||||
|
||||
const gchar *media_type = list_media_types[i].name;
|
||||
gchar media_type_glob[16];
|
||||
gchar media_class[24];
|
||||
|
||||
g_snprintf (media_type_glob, sizeof(media_type_glob), "*%s*", media_type);
|
||||
|
||||
/* Devices */
|
||||
if (object_filter == LIST_OBJECT_ALL || object_filter == LIST_OBJECT_DEVICES) {
|
||||
g_autoptr (WpIterator) it = wp_object_manager_new_filtered_iterator (self->om,
|
||||
WP_TYPE_DEVICE,
|
||||
WP_CONSTRAINT_TYPE_PW_PROPERTY, PW_KEY_MEDIA_CLASS, "#s", media_type_glob,
|
||||
NULL);
|
||||
wp_iterator_foreach (it, list_print_device, self);
|
||||
}
|
||||
|
||||
/* Sinks */
|
||||
if (object_filter == LIST_OBJECT_ALL || object_filter == LIST_OBJECT_SINKS) {
|
||||
g_snprintf (media_class, sizeof(media_class), "%s/Sink", media_type);
|
||||
default_node = -1;
|
||||
if (def_nodes_api)
|
||||
g_signal_emit_by_name (def_nodes_api, "get-default-node", media_class,
|
||||
&default_node);
|
||||
g_autoptr (WpIterator) it = wp_object_manager_new_filtered_iterator (self->om,
|
||||
WP_TYPE_NODE,
|
||||
WP_CONSTRAINT_TYPE_PW_PROPERTY, PW_KEY_MEDIA_CLASS, "#s", "*/Sink*",
|
||||
WP_CONSTRAINT_TYPE_PW_PROPERTY, PW_KEY_MEDIA_CLASS, "#s", media_type_glob,
|
||||
WP_CONSTRAINT_TYPE_PW_PROPERTY, PW_KEY_NODE_LINK_GROUP, "-",
|
||||
NULL);
|
||||
wp_iterator_foreach (it, list_print_dev_node, &default_node);
|
||||
}
|
||||
|
||||
/* Sources */
|
||||
if (object_filter == LIST_OBJECT_ALL || object_filter == LIST_OBJECT_SOURCES) {
|
||||
g_snprintf (media_class, sizeof(media_class), "%s/Source", media_type);
|
||||
default_node = -1;
|
||||
if (def_nodes_api)
|
||||
g_signal_emit_by_name (def_nodes_api, "get-default-node", media_class,
|
||||
&default_node);
|
||||
g_autoptr (WpIterator) it = wp_object_manager_new_filtered_iterator (self->om,
|
||||
WP_TYPE_NODE,
|
||||
WP_CONSTRAINT_TYPE_PW_PROPERTY, PW_KEY_MEDIA_CLASS, "#s", "*/Source*",
|
||||
WP_CONSTRAINT_TYPE_PW_PROPERTY, PW_KEY_MEDIA_CLASS, "#s", media_type_glob,
|
||||
WP_CONSTRAINT_TYPE_PW_PROPERTY, PW_KEY_NODE_LINK_GROUP, "-",
|
||||
NULL);
|
||||
wp_iterator_foreach (it, list_print_dev_node, &default_node);
|
||||
}
|
||||
}
|
||||
|
||||
g_main_loop_quit (self->loop);
|
||||
}
|
||||
|
||||
/* get-volume */
|
||||
|
||||
static gboolean
|
||||
|
|
@ -1714,6 +1873,16 @@ static const struct subcommand {
|
|||
.prepare = status_prepare,
|
||||
.run = status_run,
|
||||
},
|
||||
{
|
||||
.name = "list",
|
||||
.positional_args = "[audio|video] [devices|sinks|sources]",
|
||||
.summary = "Displays PipeWire objects, optionally filtered by media and object type",
|
||||
.description = NULL,
|
||||
.entries = { { NULL } },
|
||||
.parse_positional = list_parse_positional,
|
||||
.prepare = list_prepare,
|
||||
.run = list_run,
|
||||
},
|
||||
{
|
||||
.name = "get-volume",
|
||||
.positional_args = "ID",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue