/* WirePlumber * * Copyright © 2024 Collabora Ltd. * @author George Kiagiadakis * * SPDX-License-Identifier: MIT * * This is an example that shows how to correctly set additional node properties * that reside in a special "Props" field that is called "params". These show up * in pw-dump as an array, like this: * * "Props": [ * { * ... * "params": [ * "key1", * value1, * "key2", * value2, * ... * ] * }, * { * "params": [ * "additional_key", * additional_value, * ] * } * ], * * The correct way to set them is to construct a Props object that has a "params" * property and inside that property add a POD structure with the key/value * pairs listed in order. * * This example also parses the key/value pairs from a JSON array that is provided * on the command line, so you can call this like this: * * $ ./filter-chain-params NODE_ID '["key1", value1, "key2", value2]' * */ #include #include typedef struct { GMainLoop *loop; WpCore *core; WpObjectManager *om; gint arg_id; WpSpaJson *arg_params; } Data; static void async_quit (WpCore * core, GAsyncResult * res, Data * data) { g_main_loop_quit (data->loop); } static WpSpaPod * construct_params_pod (WpSpaJson * params_j) { // the inner POD is a struct g_autoptr (WpSpaPodBuilder) b_struct = wp_spa_pod_builder_new_struct (); // iterate the JSON array and fill the inner POD int state = 0; g_autoptr (WpIterator) it = wp_spa_json_new_iterator (params_j); g_auto (GValue) val = G_VALUE_INIT; for (; wp_iterator_next (it, &val); g_value_unset (&val)) { WpSpaJson *val_json = g_value_get_boxed (&val); switch (state) { case 0: { //parsing key g_autofree gchar * key = wp_spa_json_parse_string (val_json); wp_spa_pod_builder_add_string (b_struct, key); break; } case 1: //parsing value if (wp_spa_json_is_int (val_json)) { gint value = 0; wp_spa_json_parse_int (val_json, &value); wp_spa_pod_builder_add_int (b_struct, value); } else if (wp_spa_json_is_float (val_json)) { gfloat value = 0.0; wp_spa_json_parse_float (val_json, &value); wp_spa_pod_builder_add_float (b_struct, value); } else if (wp_spa_json_is_boolean (val_json)) { gboolean value = FALSE; wp_spa_json_parse_boolean (val_json, &value); wp_spa_pod_builder_add_boolean (b_struct, value); } else { g_autofree gchar * value = wp_spa_json_parse_string (val_json); wp_spa_pod_builder_add_string (b_struct, value); } break; default: break; } state = (state + 1) % 2; } if (state == 1) printf ("WARNING: last key didn't have a value!\n"); g_autoptr (WpSpaPod) pod_struct = wp_spa_pod_builder_end (b_struct); // now fill the outer POD, which is an object of type Props g_autoptr (WpSpaPodBuilder) b_obj = wp_spa_pod_builder_new_object ("Spa:Pod:Object:Param:Props", "Props"); wp_spa_pod_builder_add (b_obj, "params", "P", pod_struct, NULL); return wp_spa_pod_builder_end (b_obj); } static void on_om_installed (WpObjectManager * om, Data * data) { g_autoptr (WpPipewireObject) pwobj = wp_object_manager_lookup (om, WP_TYPE_NODE, WP_CONSTRAINT_TYPE_G_PROPERTY, "bound-id", "=u", data->arg_id, NULL); wp_pipewire_object_set_param (pwobj, "Props", 0, construct_params_pod (data->arg_params)); wp_core_sync (data->core, NULL, (GAsyncReadyCallback) async_quit, data); } static void on_core_activated (WpObject * core, GAsyncResult * res, Data * data) { g_autoptr (GError) error = NULL; if (!wp_object_activate_finish (core, res, &error)) { fprintf (stderr, "%s\n", error->message); g_main_loop_quit (data->loop); return; } data->om = wp_object_manager_new (); wp_object_manager_add_interest (data->om, WP_TYPE_NODE, WP_CONSTRAINT_TYPE_G_PROPERTY, "bound-id", "=u", data->arg_id, NULL); wp_object_manager_request_object_features (data->om, WP_TYPE_NODE, WP_PIPEWIRE_OBJECT_FEATURES_ALL); g_signal_connect (data->om, "installed", G_CALLBACK (on_om_installed), data); wp_core_install_object_manager (data->core, data->om); } int main (int argc, char **argv) { Data data = {0}; wp_init (WP_INIT_ALL); if (argc < 2) { printf ("Usage: %s ID '[param1, value1, param2, value2, ...]'\n", argv[0]); return 1; } data.loop = g_main_loop_new (NULL, FALSE); data.core = wp_core_new (NULL, NULL, NULL); data.arg_id = atoi (argv[1]); data.arg_params = wp_spa_json_new_wrap_string (argv[2]); wp_object_activate (WP_OBJECT (data.core), WP_CORE_FEATURE_CONNECTED, NULL, (GAsyncReadyCallback) on_core_activated, &data); g_main_loop_run (data.loop); wp_spa_json_unref (data.arg_params); g_object_unref (data.core); g_main_loop_unref (data.loop); return 0; }