From 67d4dd86563ba4957bee3ecd59be98b5091f06ba Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 18 Sep 2017 09:35:00 +0200 Subject: [PATCH] factory: add introspection --- .../module-protocol-native/protocol-native.c | 81 ++++++++++++++++++- src/modules/spa/module-node-factory.c | 2 +- src/pipewire/core.c | 6 +- src/pipewire/factory.c | 19 +++-- src/pipewire/factory.h | 3 + src/pipewire/interfaces.h | 2 +- src/pipewire/introspect.c | 36 +++++++++ src/pipewire/private.h | 3 - src/tools/pipewire-cli.c | 35 ++++++++ src/tools/pipewire-monitor.c | 55 +++++++++++-- 10 files changed, 220 insertions(+), 22 deletions(-) diff --git a/src/modules/module-protocol-native/protocol-native.c b/src/modules/module-protocol-native/protocol-native.c index 754d396be..9fcb77f4c 100644 --- a/src/modules/module-protocol-native/protocol-native.c +++ b/src/modules/module-protocol-native/protocol-native.c @@ -92,7 +92,7 @@ core_marshal_create_object(void *object, struct spa_pod_frame f; uint32_t i, n_items; - b = pw_protocol_native_begin_proxy(proxy, PW_CORE_PROXY_METHOD_CREATE_NODE); + b = pw_protocol_native_begin_proxy(proxy, PW_CORE_PROXY_METHOD_CREATE_OBJECT); n_items = props ? props->n_items : 0; @@ -630,6 +630,66 @@ static bool module_demarshal_info(void *object, void *data, size_t size) return true; } +static void factory_marshal_info(void *object, struct pw_factory_info *info) +{ + struct pw_resource *resource = object; + struct spa_pod_builder *b; + struct spa_pod_frame f; + uint32_t i, n_items; + + b = pw_protocol_native_begin_resource(resource, PW_FACTORY_PROXY_EVENT_INFO); + + n_items = info->props ? info->props->n_items : 0; + + spa_pod_builder_add(b, + SPA_POD_TYPE_STRUCT, &f, + SPA_POD_TYPE_INT, info->id, + SPA_POD_TYPE_LONG, info->change_mask, + SPA_POD_TYPE_STRING, info->name, + SPA_POD_TYPE_ID, info->type, + SPA_POD_TYPE_INT, info->version, + SPA_POD_TYPE_INT, n_items, 0); + + for (i = 0; i < n_items; i++) { + spa_pod_builder_add(b, + SPA_POD_TYPE_STRING, info->props->items[i].key, + SPA_POD_TYPE_STRING, info->props->items[i].value, 0); + } + spa_pod_builder_add(b, -SPA_POD_TYPE_STRUCT, &f, 0); + + pw_protocol_native_end_resource(resource, b); +} + +static bool factory_demarshal_info(void *object, void *data, size_t size) +{ + struct pw_proxy *proxy = object; + struct spa_pod_iter it; + struct spa_dict props; + struct pw_factory_info info; + int i; + + if (!spa_pod_iter_struct(&it, data, size) || + !spa_pod_iter_get(&it, + SPA_POD_TYPE_INT, &info.id, + SPA_POD_TYPE_LONG, &info.change_mask, + SPA_POD_TYPE_STRING, &info.name, + SPA_POD_TYPE_ID, &info.type, + SPA_POD_TYPE_INT, &info.version, + SPA_POD_TYPE_INT, &props.n_items, 0)) + return false; + + info.props = &props; + props.items = alloca(props.n_items * sizeof(struct spa_dict_item)); + for (i = 0; i < props.n_items; i++) { + if (!spa_pod_iter_get(&it, + SPA_POD_TYPE_STRING, &props.items[i].key, + SPA_POD_TYPE_STRING, &props.items[i].value, 0)) + return false; + } + pw_proxy_notify(proxy, struct pw_factory_proxy_events, info, &info); + return true; +} + static void node_marshal_info(void *object, struct pw_node_info *info) { struct pw_resource *resource = object; @@ -992,6 +1052,24 @@ const struct pw_protocol_marshal pw_protocol_native_module_marshal = { pw_protocol_native_module_event_demarshal, }; +static const struct pw_factory_proxy_events pw_protocol_native_factory_event_marshal = { + PW_VERSION_FACTORY_PROXY_EVENTS, + &factory_marshal_info, +}; + +static const struct pw_protocol_native_demarshal pw_protocol_native_factory_event_demarshal[] = { + { &factory_demarshal_info, PW_PROTOCOL_NATIVE_REMAP, }, +}; + +const struct pw_protocol_marshal pw_protocol_native_factory_marshal = { + PW_TYPE_INTERFACE__Factory, + PW_VERSION_FACTORY, + 0, NULL, NULL, + PW_FACTORY_PROXY_EVENT_NUM, + &pw_protocol_native_factory_event_marshal, + pw_protocol_native_factory_event_demarshal, +}; + static const struct pw_node_proxy_events pw_protocol_native_node_event_marshal = { PW_VERSION_NODE_PROXY_EVENTS, &node_marshal_info, @@ -1052,6 +1130,7 @@ void pw_protocol_native_init(struct pw_protocol *protocol) pw_protocol_add_marshal(protocol, &pw_protocol_native_registry_marshal); pw_protocol_add_marshal(protocol, &pw_protocol_native_module_marshal); pw_protocol_add_marshal(protocol, &pw_protocol_native_node_marshal); + pw_protocol_add_marshal(protocol, &pw_protocol_native_factory_marshal); pw_protocol_add_marshal(protocol, &pw_protocol_native_client_marshal); pw_protocol_add_marshal(protocol, &pw_protocol_native_link_marshal); } diff --git a/src/modules/spa/module-node-factory.c b/src/modules/spa/module-node-factory.c index c4aa8cc45..a4865327f 100644 --- a/src/modules/spa/module-node-factory.c +++ b/src/modules/spa/module-node-factory.c @@ -63,7 +63,7 @@ static void *create_object(void *_data, node = pw_spa_node_load(data->core, NULL, - NULL, + pw_factory_get_global(data->this), lib, factory_name, name, diff --git a/src/pipewire/core.c b/src/pipewire/core.c index 701ded83b..160098d9d 100644 --- a/src/pipewire/core.c +++ b/src/pipewire/core.c @@ -181,10 +181,10 @@ core_create_object(void *object, if (factory == NULL) goto no_factory; - if (factory->type != type) + if (factory->info.type != type) goto wrong_type; - if (factory->version < version) + if (factory->info.version < version) goto wrong_version; if (props) { @@ -795,7 +795,7 @@ struct pw_factory *pw_core_find_factory(struct pw_core *core, const char *name) struct pw_factory *factory; spa_list_for_each(factory, &core->factory_list, link) { - if (strcmp(factory->name, name) == 0) + if (strcmp(factory->info.name, name) == 0) return factory; } return NULL; diff --git a/src/pipewire/factory.c b/src/pipewire/factory.c index 1b556e0a2..a836c7fe8 100644 --- a/src/pipewire/factory.c +++ b/src/pipewire/factory.c @@ -36,12 +36,14 @@ struct pw_factory *pw_factory_new(struct pw_core *core, this = calloc(1, sizeof(*this) + user_data_size); this->core = core; - this->name = strdup(name); - this->type = type; - this->version = version; this->properties = properties; spa_list_init(&this->resource_list); + this->info.name = strdup(name); + this->info.type = type; + this->info.version = version; + this->info.props = properties ? &properties->dict : NULL; + if (user_data_size > 0) this->user_data = SPA_MEMBER(this, sizeof(*this), void); @@ -58,8 +60,10 @@ void pw_factory_destroy(struct pw_factory *factory) spa_list_remove(&factory->link); pw_global_destroy(factory->global); } - if (factory->name) - free((char *)factory->name); + if (factory->info.name) + free((char *)factory->info.name); + if (factory->properties) + pw_properties_free(factory->properties); free(factory); } @@ -123,6 +127,11 @@ void *pw_factory_get_user_data(struct pw_factory *factory) return factory->user_data; } +struct pw_global *pw_factory_get_global(struct pw_factory *factory) +{ + return factory->global; +} + void pw_factory_set_implementation(struct pw_factory *factory, const struct pw_factory_implementation *implementation, void *data) diff --git a/src/pipewire/factory.h b/src/pipewire/factory.h index def1e66c2..5324d8715 100644 --- a/src/pipewire/factory.h +++ b/src/pipewire/factory.h @@ -69,6 +69,9 @@ void pw_factory_destroy(struct pw_factory *factory); void *pw_factory_get_user_data(struct pw_factory *factory); +/** Get the global of this factory */ +struct pw_global *pw_factory_get_global(struct pw_factory *factory); + void pw_factory_set_implementation(struct pw_factory *factory, const struct pw_factory_implementation *implementation, void *data); diff --git a/src/pipewire/interfaces.h b/src/pipewire/interfaces.h index de26f89d7..b20319bc1 100644 --- a/src/pipewire/interfaces.h +++ b/src/pipewire/interfaces.h @@ -72,7 +72,7 @@ struct pw_link_proxy; #define PW_CORE_PROXY_METHOD_SYNC 1 #define PW_CORE_PROXY_METHOD_GET_REGISTRY 2 #define PW_CORE_PROXY_METHOD_CLIENT_UPDATE 3 -#define PW_CORE_PROXY_METHOD_CREATE_NODE 4 +#define PW_CORE_PROXY_METHOD_CREATE_OBJECT 4 #define PW_CORE_PROXY_METHOD_CREATE_LINK 5 #define PW_CORE_PROXY_METHOD_NUM 6 diff --git a/src/pipewire/introspect.c b/src/pipewire/introspect.c index 7eb5e99d5..3877af897 100644 --- a/src/pipewire/introspect.c +++ b/src/pipewire/introspect.c @@ -273,6 +273,42 @@ void pw_node_info_free(struct pw_node_info *info) free(info); } +struct pw_factory_info *pw_factory_info_update(struct pw_factory_info *info, + const struct pw_factory_info *update) +{ + if (update == NULL) + return info; + + if (info == NULL) { + info = calloc(1, sizeof(struct pw_factory_info)); + if (info == NULL) + return NULL; + } + info->id = update->id; + if (info->name) + free((void *) info->name); + info->name = update->name ? strdup(update->name) : NULL; + info->type = update->type; + info->version = update->version; + info->change_mask = update->change_mask; + + if (update->change_mask & PW_FACTORY_CHANGE_MASK_PROPS) { + if (info->props) + pw_spa_dict_destroy(info->props); + info->props = pw_spa_dict_copy(update->props); + } + return info; +} + +void pw_factory_info_free(struct pw_factory_info *info) +{ + if (info->name) + free((void *) info->name); + if (info->props) + pw_spa_dict_destroy(info->props); + free(info); +} + struct pw_module_info *pw_module_info_update(struct pw_module_info *info, const struct pw_module_info *update) { diff --git a/src/pipewire/private.h b/src/pipewire/private.h index 8c5d22f8c..670b33552 100644 --- a/src/pipewire/private.h +++ b/src/pipewire/private.h @@ -374,9 +374,6 @@ struct pw_factory { struct pw_global *global; /**< global for this factory */ struct pw_factory_info info; /**< introspectable factory info */ - const char *name; /**< the factory name */ - uint32_t type; /**< the type produced by the factory*/ - uint32_t version; /**< the version of the produced object */ struct pw_properties *properties; /**< properties of the factory */ const struct pw_factory_implementation *implementation; diff --git a/src/tools/pipewire-cli.c b/src/tools/pipewire-cli.c index 91e11d56d..e9a9d349a 100644 --- a/src/tools/pipewire-cli.c +++ b/src/tools/pipewire-cli.c @@ -543,6 +543,17 @@ static void info_node(struct proxy_data *pd) print_properties(info->props, MARK_CHANGE(6)); } +static void info_factory(struct proxy_data *pd) +{ + struct pw_factory_info *info = pd->info; + struct pw_type *t = pd->rd->data->t; + + info_global(pd); + fprintf(stdout, "\tname: \"%s\"\n", info->name); + fprintf(stdout, "\tobject-type: %s/%d\n", spa_type_map_get_type(t->map, info->type), info->version); + print_properties(info->props, MARK_CHANGE(0)); +} + static void info_client(struct proxy_data *pd) { struct pw_client_info *info = pd->info; @@ -624,6 +635,24 @@ static const struct pw_node_proxy_events node_events = { .info = node_event_info }; +static void factory_event_info(void *object, struct pw_factory_info *info) +{ + struct proxy_data *pd = object; + struct remote_data *rd = pd->rd; + pd->info = pw_factory_info_update(pd->info, info); + if (pd->global == NULL) + pd->global = pw_map_lookup(&rd->globals, info->id); + if (pd->global && pd->global->info_pending) { + info_factory(pd); + pd->global->info_pending = false; + } +} + +static const struct pw_factory_proxy_events factory_events = { + PW_VERSION_FACTORY_PROXY_EVENTS, + .info = factory_event_info +}; + static void client_event_info(void *object, struct pw_client_info *info) { struct proxy_data *pd = object; @@ -716,6 +745,12 @@ static bool bind_global(struct remote_data *rd, struct global *global, char **er destroy = (pw_destroy_t) pw_node_info_free; info_func = info_node; } + else if (global->type == t->factory) { + events = &factory_events; + client_version = PW_VERSION_FACTORY; + destroy = (pw_destroy_t) pw_factory_info_free; + info_func = info_factory; + } else if (global->type == t->client) { events = &client_events; client_version = PW_VERSION_CLIENT; diff --git a/src/tools/pipewire-monitor.c b/src/tools/pipewire-monitor.c index f3bd4e0a8..08f3a6019 100644 --- a/src/tools/pipewire-monitor.c +++ b/src/tools/pipewire-monitor.c @@ -40,6 +40,7 @@ struct data { }; struct proxy_data { + struct data *data; struct pw_proxy *proxy; uint32_t id; uint32_t parent_id; @@ -86,8 +87,7 @@ static void on_info_changed(void *data, const struct pw_core_info *info) static void module_event_info(void *object, struct pw_module_info *info) { - struct pw_proxy *proxy = object; - struct proxy_data *data = pw_proxy_get_user_data(proxy); + struct proxy_data *data = object; bool print_all, print_mark; print_all = true; @@ -123,8 +123,7 @@ static const struct pw_module_proxy_events module_events = { static void node_event_info(void *object, struct pw_node_info *info) { - struct pw_proxy *proxy = object; - struct proxy_data *data = pw_proxy_get_user_data(proxy); + struct proxy_data *data = object; bool print_all, print_mark; print_all = true; @@ -173,10 +172,45 @@ static const struct pw_node_proxy_events node_events = { .info = node_event_info }; +static void factory_event_info(void *object, struct pw_factory_info *info) +{ + struct proxy_data *data = object; + struct pw_type *t = pw_core_get_type(data->data->core); + bool print_all, print_mark; + + print_all = true; + if (data->info == NULL) { + printf("added:\n"); + print_mark = false; + } + else { + printf("changed:\n"); + print_mark = true; + } + + info = data->info = pw_factory_info_update(data->info, info); + + printf("\tid: %d\n", data->id); + printf("\tparent_id: %d\n", data->parent_id); + printf("\tpermissions: %c%c%c\n", data->permissions & PW_PERM_R ? 'r' : '-', + data->permissions & PW_PERM_W ? 'w' : '-', + data->permissions & PW_PERM_X ? 'x' : '-'); + printf("\ttype: %s (version %d)\n", PW_TYPE_INTERFACE__Factory, data->version); + printf("\tname: \"%s\"\n", info->name); + printf("\tobject-type: %s/%d\n", spa_type_map_get_type(t->map, info->type), info->version); + if (print_all) { + print_properties(info->props, MARK_CHANGE(0)); + } +} + +static const struct pw_factory_proxy_events factory_events = { + PW_VERSION_FACTORY_PROXY_EVENTS, + .info = factory_event_info +}; + static void client_event_info(void *object, struct pw_client_info *info) { - struct pw_proxy *proxy = object; - struct proxy_data *data = pw_proxy_get_user_data(proxy); + struct proxy_data *data = object; bool print_all, print_mark; print_all = true; @@ -209,8 +243,7 @@ static const struct pw_client_proxy_events client_events = { static void link_event_info(void *object, struct pw_link_info *info) { - struct pw_proxy *proxy = object; - struct proxy_data *data = pw_proxy_get_user_data(proxy); + struct proxy_data *data = object; bool print_all, print_mark; print_all = true; @@ -290,6 +323,11 @@ static void registry_event_global(void *data, uint32_t id, uint32_t parent_id, client_version = PW_VERSION_MODULE; destroy = (pw_destroy_t) pw_module_info_free; } + else if (type == t->factory) { + events = &factory_events; + client_version = PW_VERSION_FACTORY; + destroy = (pw_destroy_t) pw_factory_info_free; + } else if (type == t->client) { events = &client_events; client_version = PW_VERSION_CLIENT; @@ -318,6 +356,7 @@ static void registry_event_global(void *data, uint32_t id, uint32_t parent_id, goto no_mem; pd = pw_proxy_get_user_data(proxy); + pd->data = d; pd->proxy = proxy; pd->id = id; pd->parent_id = parent_id;