From ac5ec9bbe20a0272a284011dd24660dd72a01817 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 13 Feb 2019 11:13:46 +0100 Subject: [PATCH] device: improve callbacks Pass info structures to device callbacks to make it more extensible. Also notify about the supported params on the device because we can. --- spa/include/spa/monitor/device.h | 42 ++++++++++++--- spa/plugins/alsa/alsa-device.c | 41 +++++++++------ spa/plugins/audioconvert/channelmix-ops.c | 4 +- spa/plugins/bluez5/bluez5-device.c | 27 +++++++--- spa/plugins/v4l2/v4l2-device.c | 27 +++++++--- src/modules/module-client-node/remote-node.c | 3 -- src/pipewire/device.c | 55 ++++++++++++-------- 7 files changed, 135 insertions(+), 64 deletions(-) diff --git a/spa/include/spa/monitor/device.h b/spa/include/spa/monitor/device.h index 01f9cd8d0..025e9cacd 100644 --- a/spa/include/spa/monitor/device.h +++ b/spa/include/spa/monitor/device.h @@ -37,6 +37,34 @@ struct spa_device; #include #include +struct spa_device_info { +#define SPA_VERSION_DEVICE_INFO 0 + uint32_t version; + +#define SPA_DEVICE_CHANGE_MASK_INFO (1<<0) +#define SPA_DEVICE_CHANGE_MASK_PARAMS (1<<1) + uint64_t change_mask; + const struct spa_dict *info; + uint32_t n_params; + uint32_t *params; +}; + +#define SPA_DEVICE_INFO_INIT() (struct spa_device_info){ SPA_VERSION_DEVICE_INFO, } + +struct spa_device_object_info { +#define SPA_VERSION_DEVICE_OBJECT_INFO 0 + uint32_t version; + + uint32_t type; + const struct spa_handle_factory *factory; + +#define SPA_DEVICE_OBJECT_CHANGE_MASK_INFO (1<<0) + uint64_t change_mask; + const struct spa_dict *info; +}; + +#define SPA_DEVICE_OBJECT_INFO_INIT() (struct spa_device_object_info){ SPA_VERSION_DEVICE_OBJECT_INFO, } + /** * spa_device_callbacks: */ @@ -45,18 +73,16 @@ struct spa_device_callbacks { #define SPA_VERSION_DEVICE_CALLBACKS 0 uint32_t version; - /**< notify extra information about the device */ - void (*info) (void *data, const struct spa_dict *info); + /** notify extra information about the device */ + void (*info) (void *data, const struct spa_device_info *info); /** a device event */ void (*event) (void *data, struct spa_event *event); - /**< add a new object managed by the device */ - void (*add) (void *data, uint32_t id, - const struct spa_handle_factory *factory, uint32_t type, - const struct spa_dict *info); - /**< remove an object */ - void (*remove) (void *data, uint32_t id); + /** info changed for an object managed by the device, info is NULL when + * the object is removed */ + void (*object_info) (void *data, uint32_t id, + const struct spa_device_object_info *info); }; /** diff --git a/spa/plugins/alsa/alsa-device.c b/spa/plugins/alsa/alsa-device.c index 36f542634..997cc24ff 100644 --- a/spa/plugins/alsa/alsa-device.c +++ b/spa/plugins/alsa/alsa-device.c @@ -107,27 +107,28 @@ static const char *get_subclass(snd_pcm_info_t *pcminfo) static int emit_node(struct impl *this, snd_pcm_info_t *pcminfo, uint32_t id) { struct spa_dict_item items[6]; - const struct spa_handle_factory *factory; char device_name[128]; + struct spa_device_object_info info; + + info = SPA_DEVICE_OBJECT_INFO_INIT(); + info.type = SPA_TYPE_INTERFACE_Node; + if (snd_pcm_info_get_stream(pcminfo) == SND_PCM_STREAM_PLAYBACK) + info.factory = &spa_alsa_sink_factory; + else + info.factory = &spa_alsa_source_factory; + + info.change_mask = SPA_DEVICE_OBJECT_CHANGE_MASK_INFO; snprintf(device_name, 128, "%s,%d", this->props.device, snd_pcm_info_get_device(pcminfo)); - items[0] = SPA_DICT_ITEM_INIT("alsa.device", device_name); items[1] = SPA_DICT_ITEM_INIT("alsa.pcm.id", snd_pcm_info_get_id(pcminfo)); items[2] = SPA_DICT_ITEM_INIT("alsa.pcm.name", snd_pcm_info_get_name(pcminfo)); items[3] = SPA_DICT_ITEM_INIT("alsa.pcm.subname", snd_pcm_info_get_subdevice_name(pcminfo)); items[4] = SPA_DICT_ITEM_INIT("alsa.pcm.class", get_class(pcminfo)); items[5] = SPA_DICT_ITEM_INIT("alsa.pcm.subclass", get_subclass(pcminfo)); + info.info = &SPA_DICT_INIT_ARRAY(items); - if (snd_pcm_info_get_stream(pcminfo) == SND_PCM_STREAM_PLAYBACK) - factory = &spa_alsa_sink_factory; - else - factory = &spa_alsa_source_factory; - - this->callbacks->add(this->callbacks_data, id, - factory, - SPA_TYPE_INTERFACE_Node, - &SPA_DICT_INIT_ARRAY(items)); + this->callbacks->object_info(this->callbacks_data, id, &info); return 0; } @@ -141,9 +142,9 @@ static int activate_profile(struct impl *this, snd_ctl_t *ctl_hndl, uint32_t id) spa_log_debug(this->log, "profile %d", id); this->profile = id; - if (this->callbacks && this->callbacks->remove) { + if (this->callbacks->object_info) { for (i = 0; i < this->n_nodes; i++) { - this->callbacks->remove(this->callbacks_data, i); + this->callbacks->object_info(this->callbacks_data, i, NULL); } } this->n_nodes = 0; @@ -170,7 +171,7 @@ static int activate_profile(struct impl *this, snd_ctl_t *ctl_hndl, uint32_t id) if (err != -ENOENT) spa_log_error(this->log, "error pcm info: %s", snd_strerror(err)); } - if (err >= 0 && this->callbacks->add) + if (err >= 0 && this->callbacks->object_info) emit_node(this, pcminfo, i++); snd_pcm_info_set_stream(pcminfo, SND_PCM_STREAM_CAPTURE); @@ -178,7 +179,7 @@ static int activate_profile(struct impl *this, snd_ctl_t *ctl_hndl, uint32_t id) if (err != -ENOENT) spa_log_error(this->log, "error pcm info: %s", snd_strerror(err)); } - if (err >= 0 && this->callbacks->add) + if (err >= 0 && this->callbacks->object_info) emit_node(this, pcminfo, i++); } this->n_nodes = i; @@ -212,6 +213,8 @@ static int emit_info(struct impl *this) struct spa_dict_item items[10]; snd_ctl_t *ctl_hndl; snd_ctl_card_info_t *info; + struct spa_device_info dinfo; + uint32_t params[] = { SPA_PARAM_EnumProfile, SPA_PARAM_Profile }; spa_log_info(this->log, "open card %s", this->props.device); if ((err = snd_ctl_open(&ctl_hndl, this->props.device, 0)) < 0) { @@ -226,6 +229,9 @@ static int emit_info(struct impl *this) goto exit; } + dinfo = SPA_DEVICE_INFO_INIT(); + dinfo.change_mask = SPA_DEVICE_CHANGE_MASK_INFO | SPA_DEVICE_CHANGE_MASK_PARAMS; + items[0] = SPA_DICT_ITEM_INIT("device.api", "alsa"); items[1] = SPA_DICT_ITEM_INIT("device.path", (char *)this->props.device); items[2] = SPA_DICT_ITEM_INIT("device.nick", snd_ctl_card_info_get_id(info)); @@ -236,9 +242,12 @@ static int emit_info(struct impl *this) items[7] = SPA_DICT_ITEM_INIT("alsa.card.name", snd_ctl_card_info_get_name(info)); items[8] = SPA_DICT_ITEM_INIT("alsa.card.longname", snd_ctl_card_info_get_longname(info)); items[9] = SPA_DICT_ITEM_INIT("alsa.card.mixername", snd_ctl_card_info_get_mixername(info)); + dinfo.info = &SPA_DICT_INIT(items, 10); + dinfo.n_params = SPA_N_ELEMENTS(params); + dinfo.params = params; if (this->callbacks->info) - this->callbacks->info(this->callbacks_data, &SPA_DICT_INIT(items, 10)); + this->callbacks->info(this->callbacks_data, &dinfo); activate_profile(this, ctl_hndl, 0); diff --git a/spa/plugins/audioconvert/channelmix-ops.c b/spa/plugins/audioconvert/channelmix-ops.c index c326a4814..1b6781635 100644 --- a/spa/plugins/audioconvert/channelmix-ops.c +++ b/spa/plugins/audioconvert/channelmix-ops.c @@ -73,8 +73,8 @@ channelmix_f32_n_m(void *data, int n_dst, void *dst[n_dst], for (i = 0; i < n_dst; i++) { float sum = 0.0f; for (j = 0; j < n_src; j++) - sum += s[j][n] * m[i * n_src + j] * v; - d[i][n] = sum; + sum += s[j][n] * m[i * n_src + j]; + d[i][n] = sum * v; } } } diff --git a/spa/plugins/bluez5/bluez5-device.c b/spa/plugins/bluez5/bluez5-device.c index 2247f690c..98c5d4fd4 100644 --- a/spa/plugins/bluez5/bluez5-device.c +++ b/spa/plugins/bluez5/bluez5-device.c @@ -91,15 +91,19 @@ static int emit_nodes(struct impl *this) spa_list_for_each(t, &device->transport_list, device_link) { if (t->profile == profile) { + struct spa_device_object_info info; char transport[16]; snprintf(transport, 16, "%p", t); items[0] = SPA_DICT_ITEM_INIT("bluez5.transport", transport); - this->callbacks->add(this->callbacks_data, 0, - &spa_a2dp_sink_factory, - SPA_TYPE_INTERFACE_Node, - &SPA_DICT_INIT(items, 1)); + info = SPA_DEVICE_OBJECT_INFO_INIT(); + info.type = SPA_TYPE_INTERFACE_Node; + info.factory = &spa_a2dp_sink_factory; + info.change_mask = SPA_DEVICE_OBJECT_CHANGE_MASK_INFO; + info.info = &SPA_DICT_INIT_ARRAY(items); + + this->callbacks->object_info(this->callbacks_data, 0, &info); break; } } @@ -125,10 +129,19 @@ static int impl_set_callbacks(struct spa_device *device, this->callbacks_data = data; if (callbacks) { - if (callbacks->info) - callbacks->info(data, &SPA_DICT_INIT_ARRAY(info_items)); + if (callbacks->info) { + struct spa_device_info info; - if (this->callbacks->add) + info = SPA_DEVICE_INFO_INIT(); + info.change_mask = SPA_DEVICE_CHANGE_MASK_INFO | SPA_DEVICE_CHANGE_MASK_PARAMS; + info.info = &SPA_DICT_INIT_ARRAY(info_items); + info.n_params = 0; + info.params = NULL; + + callbacks->info(data, &info); + } + + if (this->callbacks->object_info) emit_nodes(this); } diff --git a/spa/plugins/v4l2/v4l2-device.c b/spa/plugins/v4l2/v4l2-device.c index 8b130627f..28d88437e 100644 --- a/spa/plugins/v4l2/v4l2-device.c +++ b/spa/plugins/v4l2/v4l2-device.c @@ -73,27 +73,40 @@ static int emit_info(struct impl *this) { int res; struct spa_dict_item items[6]; - struct spa_dict dict; + struct spa_device_info info; + uint32_t params[] = { SPA_PARAM_EnumProfile, SPA_PARAM_Profile }; if ((res = spa_v4l2_open(&this->dev, this->props.device)) < 0) return res; + info = SPA_DEVICE_INFO_INIT(); + info.change_mask = SPA_DEVICE_CHANGE_MASK_INFO | SPA_DEVICE_CHANGE_MASK_PARAMS; + items[0] = SPA_DICT_ITEM_INIT("device.api", "v4l2"); items[1] = SPA_DICT_ITEM_INIT("device.path", (char *)this->props.device); items[2] = SPA_DICT_ITEM_INIT("media.class", "Video/Device"); items[3] = SPA_DICT_ITEM_INIT("v4l2.driver", (char *)this->dev.cap.driver); items[4] = SPA_DICT_ITEM_INIT("v4l2.card", (char *)this->dev.cap.card); items[5] = SPA_DICT_ITEM_INIT("v4l2.bus", (char *)this->dev.cap.bus_info); - dict = SPA_DICT_INIT(items, 6); + info.info = &SPA_DICT_INIT(items, 6); + info.n_params = SPA_N_ELEMENTS(params); + info.params = params; if (this->callbacks->info) - this->callbacks->info(this->callbacks_data, &dict); + this->callbacks->info(this->callbacks_data, &info); + + if (this->callbacks->object_info) { - if (this->callbacks->add) { if (spa_v4l2_is_capture(&this->dev)) { - this->callbacks->add(this->callbacks_data, 0, - &spa_v4l2_source_factory, - SPA_TYPE_INTERFACE_Node, &dict); + struct spa_device_object_info oinfo; + + oinfo = SPA_DEVICE_OBJECT_INFO_INIT(); + oinfo.type = SPA_TYPE_INTERFACE_Node; + oinfo.factory = &spa_v4l2_source_factory; + oinfo.change_mask = SPA_DEVICE_OBJECT_CHANGE_MASK_INFO; + oinfo.info = &SPA_DICT_INIT(items, 6); + + this->callbacks->object_info(this->callbacks_data, 0, &oinfo); } } diff --git a/src/modules/module-client-node/remote-node.c b/src/modules/module-client-node/remote-node.c index 11b51e289..cdbb485af 100644 --- a/src/modules/module-client-node/remote-node.c +++ b/src/modules/module-client-node/remote-node.c @@ -153,9 +153,6 @@ on_rtsocket_condition(void *user_data, int fd, enum spa_io mask) pw_log_trace("remote %p: process %p", data->remote, proxy); - - - spa_graph_node_process(&data->node->rt.root); } } diff --git a/src/pipewire/device.c b/src/pipewire/device.c index 1f1c17b1d..17e56916b 100644 --- a/src/pipewire/device.c +++ b/src/pipewire/device.c @@ -288,17 +288,16 @@ static const struct pw_node_events node_events = { }; -static void device_info(void *data, const struct spa_dict *info) +static void device_info(void *data, const struct spa_device_info *info) { struct pw_device *device = data; - pw_device_update_properties(device, info); + if (info->change_mask & SPA_DEVICE_CHANGE_MASK_INFO) + pw_device_update_properties(device, info->info); } -static void device_add(void *data, uint32_t id, - const struct spa_handle_factory *factory, uint32_t type, - const struct spa_dict *info) +static void device_add(struct pw_device *device, uint32_t id, + const struct spa_device_object_info *info) { - struct pw_device *device = data; const struct spa_support *support; uint32_t n_support; struct pw_node *node; @@ -307,8 +306,8 @@ static void device_add(void *data, uint32_t id, int res; void *iface; - if (type != SPA_TYPE_INTERFACE_Node) { - pw_log_warn("device %p: unknown type %d", device, type); + if (info->type != SPA_TYPE_INTERFACE_Node) { + pw_log_warn("device %p: unknown type %d", device, info->type); return; } @@ -316,14 +315,14 @@ static void device_add(void *data, uint32_t id, support = pw_core_get_support(device->core, &n_support); props = pw_properties_copy(device->properties); - if (info) - pw_properties_update(props, info); + if (info->info) + pw_properties_update(props, info->info); node = pw_node_new(device->core, device->info.name, props, sizeof(struct node_data) + - spa_handle_factory_get_size(factory, info)); + spa_handle_factory_get_size(info->factory, info->info)); nd = pw_node_get_user_data(node); nd->id = id; @@ -332,16 +331,16 @@ static void device_add(void *data, uint32_t id, pw_node_add_listener(node, &nd->node_listener, &node_events, nd); spa_list_append(&device->node_list, &nd->link); - if ((res = spa_handle_factory_init(factory, + if ((res = spa_handle_factory_init(info->factory, nd->handle, - info, + info->info, support, n_support)) < 0) { pw_log_error("can't make factory instance: %d", res); goto error;; } - if ((res = spa_handle_get_interface(nd->handle, type, &iface)) < 0) { + if ((res = spa_handle_get_interface(nd->handle, info->type, &iface)) < 0) { pw_log_error("can't get NODE interface: %d", res); goto error;; } @@ -367,23 +366,37 @@ static struct node_data *find_node(struct pw_device *device, uint32_t id) return NULL; } -static void device_remove(void *data, uint32_t id) +static void device_object_info(void *data, uint32_t id, + const struct spa_device_object_info *info) { struct pw_device *device = data; struct node_data *nd; - pw_log_debug("device %p: remove node %d", device, id); - if ((nd = find_node(device, id)) == NULL) - return; + nd = find_node(device, id); - pw_node_destroy(nd->node); + if (info == NULL) { + if (nd) { + pw_log_debug("device %p: remove node %d", device, id); + pw_node_destroy(nd->node); + } + else { + pw_log_warn("device %p: unknown node %d", device, id); + } + } + else if (nd != NULL) { + if (info->change_mask & SPA_DEVICE_OBJECT_CHANGE_MASK_INFO) + pw_node_update_properties(nd->node, info->info); + } + else { + device_add(device, id, info); + } } + static const struct spa_device_callbacks device_callbacks = { SPA_VERSION_DEVICE_CALLBACKS, .info = device_info, - .add = device_add, - .remove = device_remove, + .object_info = device_object_info, }; SPA_EXPORT