diff --git a/spa/include/spa/monitor/device.h b/spa/include/spa/monitor/device.h index 3ebf0f795..d4eee3003 100644 --- a/spa/include/spa/monitor/device.h +++ b/spa/include/spa/monitor/device.h @@ -35,6 +35,7 @@ struct spa_device; #include #include #include +#include /** * spa_device_callbacks: @@ -44,6 +45,12 @@ 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); + + /** 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, @@ -63,15 +70,13 @@ struct spa_device { #define SPA_VERSION_DEVICE 0 uint32_t version; - /** - * Extra information about the device - */ - const struct spa_dict *info; - /** * Set callbacks to receive asynchronous notifications from * the device. * + * Setting the callbacks will trigger the info event and an + * add event for each managed node. + * * \param device: a #spa_device * \param callback: a #callbacks * \return 0 on success diff --git a/spa/include/spa/monitor/monitor.h b/spa/include/spa/monitor/monitor.h index 3337c1a92..52aa4500f 100644 --- a/spa/include/spa/monitor/monitor.h +++ b/spa/include/spa/monitor/monitor.h @@ -79,6 +79,9 @@ struct spa_monitor_callbacks { #define SPA_VERSION_MONITOR_CALLBACKS 0 uint32_t version; + /** receive extra information about the monitor */ + void (*info) (void *data, const struct spa_dict *info); + /** an item is added/removed/changed on the monitor */ void (*event) (void *data, struct spa_event *event); }; @@ -94,15 +97,12 @@ struct spa_monitor { #define SPA_VERSION_MONITOR 0 uint32_t version; - /** - * Extra information about the monitor - */ - const struct spa_dict *info; - /** * Set callbacks to receive asynchronous notifications from * the monitor. * + * Setting the callbacks will emit the info + * * \param monitor: a #spa_monitor * \param callback: a #callbacks * \return 0 on success @@ -111,29 +111,9 @@ struct spa_monitor { int (*set_callbacks) (struct spa_monitor *monitor, const struct spa_monitor_callbacks *callbacks, void *data); - - /** - * Get the next item of the monitor. \a index should contain 0 to get the - * first item and is updated with an opaque value that should be passed - * unmodified to get the next items. - * - * \param monitor a spa_monitor - * \param index state, use 0 for the first item - * \param item result item - * \param builder builder for \a item - * \return 1 when an item is available - * 0 when no more items are available - * < 0 errno on error - */ - int (*enum_items) (struct spa_monitor *monitor, - uint32_t *index, - struct spa_pod **item, - struct spa_pod_builder *builder); - }; #define spa_monitor_set_callbacks(m,...) (m)->set_callbacks((m),__VA_ARGS__) -#define spa_monitor_enum_items(m,...) (m)->enum_items((m),__VA_ARGS__) #ifdef __cplusplus } /* extern "C" */ diff --git a/spa/include/spa/node/node.h b/spa/include/spa/node/node.h index f68d17a72..2630cf82c 100644 --- a/spa/include/spa/node/node.h +++ b/spa/include/spa/node/node.h @@ -71,6 +71,9 @@ struct spa_node_callbacks { #define SPA_VERSION_NODE_CALLBACKS 0 uint32_t version; /**< version of this structure */ + /** Emited when info changes */ + void (*info) (void *data, const struct spa_dict *info); + /** Emited when an async operation completed. * * Will be called from the main thread. */ diff --git a/spa/plugins/alsa/alsa-device.c b/spa/plugins/alsa/alsa-device.c index a86dd6298..9902a496a 100644 --- a/spa/plugins/alsa/alsa-device.c +++ b/spa/plugins/alsa/alsa-device.c @@ -126,8 +126,7 @@ static int emit_device(struct impl *this, snd_ctl_card_info_t *info, snd_pcm_inf else factory = &spa_alsa_source_factory; - if (this->callbacks->add) - this->callbacks->add(this->callbacks_data, 0, + this->callbacks->add(this->callbacks_data, 0, factory, SPA_TYPE_INTERFACE_Node, &SPA_DICT_INIT(items, 13)); @@ -191,6 +190,10 @@ static int emit_devices(struct impl *this) return err; } +static const struct spa_dict_item info_items[] = { + { "media.class", "Audio/Device" }, +}; + static int impl_set_callbacks(struct spa_device *device, const struct spa_device_callbacks *callbacks, void *data) @@ -204,8 +207,13 @@ static int impl_set_callbacks(struct spa_device *device, this->callbacks = callbacks; this->callbacks_data = data; - if (callbacks) - emit_devices(this); + if (callbacks) { + if (callbacks->info) + callbacks->info(data, &SPA_DICT_INIT_ARRAY(info_items)); + + if (this->callbacks->add) + emit_devices(this); + } return 0; } @@ -227,18 +235,8 @@ static int impl_set_param(struct spa_device *device, return -ENOTSUP; } -static const struct spa_dict_item info_items[] = { - { "media.class", "Audio/Device" }, -}; - -static const struct spa_dict info = { - info_items, - SPA_N_ELEMENTS(info_items) -}; - static const struct spa_device impl_device = { SPA_VERSION_DEVICE, - &info, impl_set_callbacks, impl_enum_params, impl_set_param, diff --git a/spa/plugins/alsa/alsa-monitor.c b/spa/plugins/alsa/alsa-monitor.c index 830f10812..2dfc92740 100644 --- a/spa/plugins/alsa/alsa-monitor.c +++ b/spa/plugins/alsa/alsa-monitor.c @@ -44,10 +44,6 @@ extern const struct spa_handle_factory spa_alsa_device_factory; -struct item { - struct udev_device *udevice; -}; - struct impl { struct spa_handle handle; struct spa_monitor monitor; @@ -60,11 +56,7 @@ struct impl { struct udev *udev; struct udev_monitor *umonitor; - struct udev_enumerate *enumerate; - uint32_t index; - struct udev_list_entry *devices; - struct item uitem; uint32_t cards[MAX_CARDS]; int n_cards; @@ -72,14 +64,20 @@ struct impl { }; static int impl_udev_open(struct impl *this) +{ + if (this->udev == NULL) { + this->udev = udev_new(); + if (this->udev == NULL) + return -ENOMEM; + } + return 0; +} + +static int impl_udev_close(struct impl *this) { if (this->udev != NULL) - return 0; - - this->udev = udev_new(); - if (this->udev == NULL) - return -ENOMEM; - + udev_unref(this->udev); + this->udev = NULL; return 0; } @@ -112,17 +110,11 @@ static const char *path_get_card_id(const char *path) return e + 5; } -static int fill_item(struct impl *this, struct item *item, struct udev_device *dev, +static int fill_item(struct impl *this, struct udev_device *dev, struct spa_pod **result, struct spa_pod_builder *builder) { const char *str, *name; - if (item->udevice) - udev_device_unref(item->udevice); - item->udevice = dev; - if (dev == NULL) - return 0; - name = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE"); if (!(name && *name)) { name = udev_device_get_property_value(dev, "ID_MODEL_ENC"); @@ -263,16 +255,27 @@ static int need_notify(struct impl *this, struct udev_device *dev, uint32_t id, return 1; } +static int emit_device(struct impl *this, uint32_t id, struct udev_device *dev) +{ + uint8_t buffer[4096]; + struct spa_pod_builder b = { NULL, }; + struct spa_event *event; + struct spa_pod *item; + + spa_pod_builder_init(&b, buffer, sizeof(buffer)); + event = spa_pod_builder_object(&b, SPA_TYPE_EVENT_Monitor, id, 0); + fill_item(this, dev, &item, &b); + + this->callbacks->event(this->callbacks_data, event); + return 0; +} + static void impl_on_fd_events(struct spa_source *source) { struct impl *this = source->data; struct udev_device *dev; const char *action; uint32_t id; - uint8_t buffer[4096]; - struct spa_pod_builder b = { NULL }; - struct spa_event *event; - struct spa_pod *item; dev = udev_monitor_receive_device(this->umonitor); if (dev == NULL) @@ -292,13 +295,75 @@ static void impl_on_fd_events(struct spa_source *source) } else return; - if (!need_notify(this, dev, id, false)) - return; + if (need_notify(this, dev, id, false)) + emit_device(this, id, dev); - spa_pod_builder_init(&b, buffer, sizeof(buffer)); - event = spa_pod_builder_object(&b, SPA_TYPE_EVENT_Monitor, id, 0); - if (fill_item(this, &this->uitem, dev, &item, &b) == 1) - this->callbacks->event(this->callbacks_data, event); + udev_device_unref(dev); +} + +static int start_monitor(struct impl *this) +{ + if (this->umonitor != NULL) + return 0; + + this->umonitor = udev_monitor_new_from_netlink(this->udev, "udev"); + if (this->umonitor == NULL) + return -ENOMEM; + + udev_monitor_filter_add_match_subsystem_devtype(this->umonitor, + "sound", NULL); + udev_monitor_enable_receiving(this->umonitor); + + this->source.func = impl_on_fd_events; + this->source.data = this; + this->source.fd = udev_monitor_get_fd(this->umonitor);; + this->source.mask = SPA_IO_IN | SPA_IO_ERR; + + spa_loop_add_source(this->main_loop, &this->source); + + return 0; +} + +static int stop_monitor(struct impl *this) +{ + if (this->umonitor == NULL) + return 0; + + spa_loop_remove_source(this->main_loop, &this->source); + udev_monitor_unref(this->umonitor); + this->umonitor = NULL; + return 0; +} + +static int enum_devices(struct impl *this) +{ + struct udev_enumerate *enumerate; + struct udev_list_entry *devices; + + enumerate = udev_enumerate_new(this->udev); + if (enumerate == NULL) + return -ENOMEM; + + udev_enumerate_add_match_subsystem(enumerate, "sound"); + udev_enumerate_scan_devices(enumerate); + + devices = udev_enumerate_get_list_entry(enumerate); + + while (devices) { + struct udev_device *dev; + + dev = udev_device_new_from_syspath(this->udev, udev_list_entry_get_name(devices)); + + if (need_notify(this, dev, SPA_MONITOR_EVENT_Added, true)) + emit_device(this, SPA_MONITOR_EVENT_Added, dev); + + udev_device_unref(dev); + + devices = udev_list_entry_get_next(devices); + } + udev_enumerate_unref(enumerate); + + return 0; } static int @@ -320,90 +385,22 @@ impl_monitor_set_callbacks(struct spa_monitor *monitor, if ((res = impl_udev_open(this)) < 0) return res; - if (this->umonitor) - udev_monitor_unref(this->umonitor); - this->umonitor = udev_monitor_new_from_netlink(this->udev, "udev"); - if (this->umonitor == NULL) - return -ENODEV; + if ((res = enum_devices(this)) < 0) + return res; - udev_monitor_filter_add_match_subsystem_devtype(this->umonitor, "sound", NULL); - udev_monitor_enable_receiving(this->umonitor); - - this->source.func = impl_on_fd_events; - this->source.data = this; - this->source.fd = udev_monitor_get_fd(this->umonitor);; - this->source.mask = SPA_IO_IN | SPA_IO_ERR; - - spa_loop_add_source(this->main_loop, &this->source); + if ((res = start_monitor(this)) < 0) + return res; } else { - spa_loop_remove_source(this->main_loop, &this->source); + stop_monitor(this); + impl_udev_close(this); } return 0; } -static int impl_monitor_enum_items(struct spa_monitor *monitor, - uint32_t *index, - struct spa_pod **item, - struct spa_pod_builder *builder) -{ - int res; - struct impl *this; - struct udev_device *dev; - - spa_return_val_if_fail(monitor != NULL, -EINVAL); - spa_return_val_if_fail(item != NULL, -EINVAL); - - this = SPA_CONTAINER_OF(monitor, struct impl, monitor); - - if ((res = impl_udev_open(this)) < 0) - return res; - - if (*index == 0 || this->index > *index) { - if (this->enumerate) - udev_enumerate_unref(this->enumerate); - this->enumerate = udev_enumerate_new(this->udev); - - udev_enumerate_add_match_subsystem(this->enumerate, "sound"); - udev_enumerate_scan_devices(this->enumerate); - - this->devices = udev_enumerate_get_list_entry(this->enumerate); - this->index = 0; - } - while (*index > this->index && this->devices) { - next: - this->devices = udev_list_entry_get_next(this->devices); - this->index++; - } - if (this->devices == NULL) { - fill_item(this, &this->uitem, NULL, item, builder); - return 0; - } - - dev = udev_device_new_from_syspath(this->udev, - udev_list_entry_get_name(this->devices)); - - if (dev == NULL) - goto next; - - if (!need_notify(this, dev, SPA_MONITOR_EVENT_Added, true)) - goto next; - - if (fill_item(this, &this->uitem, dev, item, builder) != 1) - goto next; - - this->devices = udev_list_entry_get_next(this->devices); - this->index++; - (*index)++; - - return 1; -} - static const struct spa_monitor impl_monitor = { SPA_VERSION_MONITOR, - NULL, impl_monitor_set_callbacks, - impl_monitor_enum_items, }; static int impl_get_interface(struct spa_handle *handle, uint32_t type, void **interface) @@ -426,16 +423,7 @@ static int impl_get_interface(struct spa_handle *handle, uint32_t type, void **i static int impl_clear(struct spa_handle *handle) { struct impl *this = (struct impl *) handle; - - if (this->uitem.udevice) - udev_device_unref(this->uitem.udevice); - if (this->enumerate) - udev_enumerate_unref(this->enumerate); - if (this->umonitor) - udev_monitor_unref(this->umonitor); - if (this->udev) - udev_unref(this->udev); - + impl_monitor_set_callbacks(&this->monitor, NULL, NULL); return 0; } diff --git a/spa/plugins/bluez5/bluez5-device.c b/spa/plugins/bluez5/bluez5-device.c new file mode 100644 index 000000000..8259913b3 --- /dev/null +++ b/spa/plugins/bluez5/bluez5-device.c @@ -0,0 +1,238 @@ +/* Spa ALSA Device + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define NAME "bluez5-device" + +#define MAX_DEVICES 64 + +extern const struct spa_handle_factory spa_a2dp_sink_factory; + +static const char default_device[] = ""; + +struct props { + char device[64]; +}; + +static void reset_props(struct props *props) +{ + strncpy(props->device, default_device, 64); +} + +struct impl { + struct spa_handle handle; + struct spa_device device; + + struct spa_log *log; + struct spa_loop *main_loop; + + const struct spa_device_callbacks *callbacks; + void *callbacks_data; + + struct props props; + + struct spa_bt_transport *transport; +}; + +static int emit_devices(struct impl *this) +{ + struct spa_dict_item items[1]; + char transport[16]; + + snprintf(transport, 16, "%p", this->transport); + + 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)); + return 0; +} + +static const struct spa_dict_item info_items[] = { + { "media.class", "Audio/Device" }, +}; + +static int impl_set_callbacks(struct spa_device *device, + const struct spa_device_callbacks *callbacks, + void *data) +{ + struct impl *this; + + spa_return_val_if_fail(device != NULL, -EINVAL); + + this = SPA_CONTAINER_OF(device, struct impl, device); + + this->callbacks = callbacks; + this->callbacks_data = data; + + if (callbacks) { + if (callbacks->info) + callbacks->info(data, &SPA_DICT_INIT_ARRAY(info_items)); + + if (this->callbacks->add) + emit_devices(this); + } + + return 0; +} + + +static int impl_enum_params(struct spa_device *device, + uint32_t id, uint32_t *index, + const struct spa_pod *filter, + struct spa_pod **param, + struct spa_pod_builder *builder) +{ + return -ENOTSUP; +} + +static int impl_set_param(struct spa_device *device, + uint32_t id, uint32_t flags, + const struct spa_pod *param) +{ + return -ENOTSUP; +} + +static const struct spa_device impl_device = { + SPA_VERSION_DEVICE, + impl_set_callbacks, + impl_enum_params, + impl_set_param, +}; + +static int impl_get_interface(struct spa_handle *handle, uint32_t type, void **interface) +{ + struct impl *this; + + spa_return_val_if_fail(handle != NULL, -EINVAL); + spa_return_val_if_fail(interface != NULL, -EINVAL); + + this = (struct impl *) handle; + + if (type == SPA_TYPE_INTERFACE_Device) + *interface = &this->device; + else + return -ENOENT; + + return 0; +} + +static int impl_clear(struct spa_handle *handle) +{ + return 0; +} + +static size_t +impl_get_size(const struct spa_handle_factory *factory, + const struct spa_dict *params) +{ + return sizeof(struct impl); +} + +static int +impl_init(const struct spa_handle_factory *factory, + struct spa_handle *handle, + const struct spa_dict *info, + const struct spa_support *support, + uint32_t n_support) +{ + struct impl *this; + uint32_t i; + + spa_return_val_if_fail(factory != NULL, -EINVAL); + spa_return_val_if_fail(handle != NULL, -EINVAL); + + handle->get_interface = impl_get_interface; + handle->clear = impl_clear; + + this = (struct impl *) handle; + + for (i = 0; i < n_support; i++) { + if (support[i].type == SPA_TYPE_INTERFACE_Log) + this->log = support[i].data; + else if (support[i].type == SPA_TYPE_INTERFACE_MainLoop) + this->main_loop = support[i].data; + } + if (this->main_loop == NULL) { + spa_log_error(this->log, "a main-loop is needed"); + return -EINVAL; + } + + for (i = 0; info && i < info->n_items; i++) { + if (strcmp(info->items[i].key, "bluez5.transport") == 0) + sscanf(info->items[i].value, "%p", &this->transport); + } + if (this->transport == NULL) { + spa_log_error(this->log, "a transport is needed"); + return -EINVAL; + } + this->device = impl_device; + + reset_props(&this->props); + + return 0; +} + +static const struct spa_interface_info impl_interfaces[] = { + {SPA_TYPE_INTERFACE_Device,}, +}; + +static int +impl_enum_interface_info(const struct spa_handle_factory *factory, + const struct spa_interface_info **info, + uint32_t *index) +{ + spa_return_val_if_fail(factory != NULL, -EINVAL); + spa_return_val_if_fail(info != NULL, -EINVAL); + spa_return_val_if_fail(index != NULL, -EINVAL); + + if (*index >= SPA_N_ELEMENTS(impl_interfaces)) + return 0; + + *info = &impl_interfaces[(*index)++]; + return 1; +} + +const struct spa_handle_factory spa_bluez5_device_factory = { + SPA_VERSION_HANDLE_FACTORY, + NAME, + NULL, + impl_get_size, + impl_init, + impl_enum_interface_info, +}; diff --git a/spa/plugins/bluez5/bluez5-monitor.c b/spa/plugins/bluez5/bluez5-monitor.c index 125cd8f46..a66d71fd9 100644 --- a/spa/plugins/bluez5/bluez5-monitor.c +++ b/spa/plugins/bluez5/bluez5-monitor.c @@ -70,7 +70,7 @@ struct spa_bt_monitor { struct spa_list transport_list; }; -struct spa_handle_factory spa_a2dp_sink_factory; +struct spa_handle_factory spa_bluez5_device_factory; static inline void add_dict(struct spa_pod_builder *builder, const char *key, const char *val) { @@ -90,7 +90,9 @@ static void fill_item(struct spa_bt_monitor *this, struct spa_bt_transport *tran SPA_MONITOR_ITEM_state, &SPA_POD_Id(SPA_MONITOR_ITEM_STATE_Available), SPA_MONITOR_ITEM_name, &SPA_POD_Stringv(transport->path), SPA_MONITOR_ITEM_class, &SPA_POD_Stringc("Adapter/Bluetooth"), - SPA_MONITOR_ITEM_factory, &SPA_POD_Pointer(SPA_TYPE_INTERFACE_HandleFactory, &spa_a2dp_sink_factory), + SPA_MONITOR_ITEM_factory, &SPA_POD_Pointer(SPA_TYPE_INTERFACE_HandleFactory, + &spa_bluez5_device_factory), + SPA_MONITOR_ITEM_type, &SPA_POD_Id(SPA_TYPE_INTERFACE_Device), 0); spa_pod_builder_prop(builder, SPA_MONITOR_ITEM_info, 0); @@ -1266,21 +1268,9 @@ impl_monitor_set_callbacks(struct spa_monitor *monitor, return 0; } -static int -impl_monitor_enum_items(struct spa_monitor *monitor, uint32_t *index, - struct spa_pod **item, struct spa_pod_builder *builder) -{ - spa_return_val_if_fail(monitor != NULL, -EINVAL); - spa_return_val_if_fail(item != NULL, -EINVAL); - spa_return_val_if_fail(index != NULL, -EINVAL); - return 0; -} - static const struct spa_monitor impl_monitor = { SPA_VERSION_MONITOR, - NULL, impl_monitor_set_callbacks, - impl_monitor_enum_items, }; static int impl_get_interface(struct spa_handle *handle, uint32_t type, void **interface) diff --git a/spa/plugins/bluez5/meson.build b/spa/plugins/bluez5/meson.build index 158902384..08f4719ab 100644 --- a/spa/plugins/bluez5/meson.build +++ b/spa/plugins/bluez5/meson.build @@ -1,6 +1,7 @@ bluez5_sources = ['plugin.c', 'a2dp-sink.c', + 'bluez5-device.c', 'bluez5-monitor.c'] bluez5lib = shared_library('spa-bluez5', diff --git a/spa/plugins/v4l2/v4l2-device.c b/spa/plugins/v4l2/v4l2-device.c index 3b5b86cc0..84c31fd76 100644 --- a/spa/plugins/v4l2/v4l2-device.c +++ b/spa/plugins/v4l2/v4l2-device.c @@ -69,6 +69,10 @@ struct impl { struct spa_v4l2_device dev; }; +static const struct spa_dict_item info_items[] = { + { "media.class", "Video/Device" }, +}; + static int impl_set_callbacks(struct spa_device *device, const struct spa_device_callbacks *callbacks, void *data) @@ -84,14 +88,17 @@ static int impl_set_callbacks(struct spa_device *device, this->callbacks_data = data; if (callbacks) { - if (spa_v4l2_is_capture(&this->dev)) { - items[0] = SPA_DICT_ITEM_INIT("device.path", this->props.device); + if (callbacks->info) + callbacks->info(data, &SPA_DICT_INIT_ARRAY(info_items)); - if (callbacks->add) + if (callbacks->add) { + if (spa_v4l2_is_capture(&this->dev)) { + items[0] = SPA_DICT_ITEM_INIT("device.path", this->props.device); callbacks->add(data, 0, &spa_v4l2_source_factory, SPA_TYPE_INTERFACE_Node, &SPA_DICT_INIT(items, 1)); + } } @@ -116,18 +123,8 @@ static int impl_set_param(struct spa_device *device, return -ENOTSUP; } -static const struct spa_dict_item info_items[] = { - { "media.class", "Video/Device" }, -}; - -static const struct spa_dict info = { - info_items, - SPA_N_ELEMENTS(info_items) -}; - static const struct spa_device impl_device = { SPA_VERSION_DEVICE, - &info, impl_set_callbacks, impl_enum_params, impl_set_param, diff --git a/spa/plugins/v4l2/v4l2-monitor.c b/spa/plugins/v4l2/v4l2-monitor.c index bbac5eb6b..5e509a129 100644 --- a/spa/plugins/v4l2/v4l2-monitor.c +++ b/spa/plugins/v4l2/v4l2-monitor.c @@ -41,10 +41,6 @@ extern const struct spa_handle_factory spa_v4l2_device_factory; -struct item { - struct udev_device *udevice; -}; - struct impl { struct spa_handle handle; struct spa_monitor monitor; @@ -57,24 +53,24 @@ struct impl { struct udev *udev; struct udev_monitor *umonitor; - struct udev_enumerate *enumerate; - uint32_t index; - struct udev_list_entry *devices; - - struct item uitem; struct spa_source source; }; static int impl_udev_open(struct impl *this) +{ + if (this->udev == NULL) { + this->udev = udev_new(); + if (this->udev == NULL) + return -ENOMEM; + } + return 0; +} +static int impl_udev_close(struct impl *this) { if (this->udev != NULL) - return 0; - - this->udev = udev_new(); - if (this->udev == NULL) - return -ENOMEM; - + udev_unref(this->udev); + this->udev = NULL; return 0; } @@ -84,17 +80,11 @@ static inline void add_dict(struct spa_pod_builder *builder, const char *key, co spa_pod_builder_string(builder, val); } -static void fill_item(struct impl *this, struct item *item, struct udev_device *dev, +static void fill_item(struct impl *this, struct udev_device *dev, struct spa_pod **result, struct spa_pod_builder *builder) { const char *str, *name; - if (item->udevice) - udev_device_unref(item->udevice); - item->udevice = dev; - if (dev == NULL) - return; - name = udev_device_get_property_value(dev, "ID_V4L_PRODUCT"); if (!(name && *name)) { name = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE"); @@ -174,16 +164,27 @@ static void fill_item(struct impl *this, struct item *item, struct udev_device * *result = spa_pod_builder_pop(builder); } +static int emit_device(struct impl *this, uint32_t id, struct udev_device *dev) +{ + uint8_t buffer[4096]; + struct spa_pod_builder b = { NULL, }; + struct spa_event *event; + struct spa_pod *item; + + spa_pod_builder_init(&b, buffer, sizeof(buffer)); + event = spa_pod_builder_object(&b, SPA_TYPE_EVENT_Monitor, id, 0); + fill_item(this, dev, &item, &b); + + this->callbacks->event(this->callbacks_data, event); + return 0; +} + static void impl_on_fd_events(struct spa_source *source) { struct impl *this = source->data; struct udev_device *dev; - struct spa_event *event; const char *action; uint32_t id; - struct spa_pod_builder b = { NULL, }; - uint8_t buffer[4096]; - struct spa_pod *item; dev = udev_monitor_receive_device(this->umonitor); if (dev == NULL) @@ -201,13 +202,76 @@ static void impl_on_fd_events(struct spa_source *source) } else return; - spa_pod_builder_init(&b, buffer, sizeof(buffer)); - event = spa_pod_builder_object(&b, SPA_TYPE_EVENT_Monitor, id, 0); - fill_item(this, &this->uitem, dev, &item, &b); + emit_device(this, id, dev); - this->callbacks->event(this->callbacks_data, event); + udev_device_unref(dev); } +static int start_monitor(struct impl *this) +{ + if (this->umonitor != NULL) + return 0; + + this->umonitor = udev_monitor_new_from_netlink(this->udev, "udev"); + if (this->umonitor == NULL) + return -ENOMEM; + + udev_monitor_filter_add_match_subsystem_devtype(this->umonitor, + "video4linux", NULL); + udev_monitor_enable_receiving(this->umonitor); + + this->source.func = impl_on_fd_events; + this->source.data = this; + this->source.fd = udev_monitor_get_fd(this->umonitor);; + this->source.mask = SPA_IO_IN | SPA_IO_ERR; + + spa_loop_add_source(this->main_loop, &this->source); + + return 0; +} + +static int stop_monitor(struct impl *this) +{ + if (this->umonitor == NULL) + return 0; + + spa_loop_remove_source(this->main_loop, &this->source); + udev_monitor_unref(this->umonitor); + this->umonitor = NULL; + return 0; +} + +static int enum_devices(struct impl *this) +{ + struct udev_enumerate *enumerate; + struct udev_list_entry *devices; + + enumerate = udev_enumerate_new(this->udev); + if (enumerate == NULL) + return -ENOMEM; + + udev_enumerate_add_match_subsystem(enumerate, "video4linux"); + udev_enumerate_scan_devices(enumerate); + + devices = udev_enumerate_get_list_entry(enumerate); + + while (devices) { + struct udev_device *dev; + + dev = udev_device_new_from_syspath(this->udev, udev_list_entry_get_name(devices)); + + emit_device(this, SPA_MONITOR_EVENT_Added, dev); + + udev_device_unref(dev); + + devices = udev_list_entry_get_next(devices); + } + udev_enumerate_unref(enumerate); + + return 0; +} + + static int impl_monitor_set_callbacks(struct spa_monitor *monitor, const struct spa_monitor_callbacks *callbacks, @@ -226,84 +290,21 @@ impl_monitor_set_callbacks(struct spa_monitor *monitor, if ((res = impl_udev_open(this)) < 0) return res; - if (this->umonitor) - udev_monitor_unref(this->umonitor); - this->umonitor = udev_monitor_new_from_netlink(this->udev, "udev"); - if (this->umonitor == NULL) - return -ENOMEM; + if ((res = enum_devices(this)) < 0) + return res; - udev_monitor_filter_add_match_subsystem_devtype(this->umonitor, - "video4linux", NULL); - udev_monitor_enable_receiving(this->umonitor); - - this->source.func = impl_on_fd_events; - this->source.data = this; - this->source.fd = udev_monitor_get_fd(this->umonitor);; - this->source.mask = SPA_IO_IN | SPA_IO_ERR; - - spa_loop_add_source(this->main_loop, &this->source); + if ((res = start_monitor(this)) < 0) + return res; } else { - spa_loop_remove_source(this->main_loop, &this->source); + stop_monitor(this); + impl_udev_close(this); } - return 0; } -static int -impl_monitor_enum_items(struct spa_monitor *monitor, uint32_t *index, - struct spa_pod **item, struct spa_pod_builder *builder) -{ - int res; - struct impl *this; - struct udev_device *dev; - - spa_return_val_if_fail(monitor != NULL, -EINVAL); - spa_return_val_if_fail(item != NULL, -EINVAL); - spa_return_val_if_fail(index != NULL, -EINVAL); - - this = SPA_CONTAINER_OF(monitor, struct impl, monitor); - - if ((res = impl_udev_open(this)) < 0) - return res; - - if (*index == 0) { - if (this->enumerate) - udev_enumerate_unref(this->enumerate); - this->enumerate = udev_enumerate_new(this->udev); - - udev_enumerate_add_match_subsystem(this->enumerate, "video4linux"); - udev_enumerate_scan_devices(this->enumerate); - - this->devices = udev_enumerate_get_list_entry(this->enumerate); - this->index = 0; - } - while (*index > this->index && this->devices) { - this->devices = udev_list_entry_get_next(this->devices); - this->index++; - } - if (this->devices == NULL) { - fill_item(this, &this->uitem, NULL, item, builder); - return 0; - } - - dev = udev_device_new_from_syspath(this->udev, udev_list_entry_get_name(this->devices)); - - fill_item(this, &this->uitem, dev, item, builder); - if (dev == NULL) - return 0; - - this->devices = udev_list_entry_get_next(this->devices); - this->index++; - (*index)++; - - return 1; -} - static const struct spa_monitor impl_monitor = { SPA_VERSION_MONITOR, - NULL, impl_monitor_set_callbacks, - impl_monitor_enum_items, }; static int impl_get_interface(struct spa_handle *handle, uint32_t type, void **interface) @@ -326,16 +327,7 @@ static int impl_get_interface(struct spa_handle *handle, uint32_t type, void **i static int impl_clear(struct spa_handle *handle) { struct impl *this = (struct impl *) handle; - - if (this->uitem.udevice) - udev_device_unref(this->uitem.udevice); - if (this->enumerate) - udev_enumerate_unref(this->enumerate); - if (this->umonitor) - udev_monitor_unref(this->umonitor); - if (this->udev) - udev_unref(this->udev); - + impl_monitor_set_callbacks(&this->monitor, NULL, NULL); return 0; } diff --git a/spa/tests/test-bluez5.c b/spa/tests/test-bluez5.c index c7dca5887..adb80eb92 100644 --- a/spa/tests/test-bluez5.c +++ b/spa/tests/test-bluez5.c @@ -121,7 +121,7 @@ static void monitor_event(void *_data, struct spa_event *event) static struct spa_monitor_callbacks monitor_callbacks = { SPA_VERSION_MONITOR_CALLBACKS, - monitor_event, + .event = monitor_event, }; static int get_handle(struct data *data, diff --git a/spa/tools/spa-monitor.c b/spa/tools/spa-monitor.c index da97bfa19..4fac134cb 100644 --- a/spa/tools/spa-monitor.c +++ b/spa/tools/spa-monitor.c @@ -61,6 +61,11 @@ static void inspect_item(struct data *data, struct spa_pod *item) spa_debug_pod(0, NULL, item); } +static void on_monitor_info(void *_data, const struct spa_dict *info) +{ + spa_debug_dict(0, info); +} + static void on_monitor_event(void *_data, struct spa_event *event) { struct data *data = _data; @@ -103,29 +108,12 @@ static void do_remove_source(struct spa_source *source) static const struct spa_monitor_callbacks impl_callbacks = { SPA_VERSION_MONITOR_CALLBACKS, + .info = on_monitor_info, .event = on_monitor_event, }; static void handle_monitor(struct data *data, struct spa_monitor *monitor) { - int res; - uint32_t index; - - if (monitor->info) - spa_debug_dict(0, monitor->info); - - for (index = 0;;) { - struct spa_pod *item; - uint8_t buffer[4096]; - struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); - - if ((res = spa_monitor_enum_items(monitor, &index, &item, &b)) <= 0) { - if (res != 0) - printf("spa_monitor_enum_items: %s\n", spa_strerror(res)); - break; - } - inspect_item(data, item); - } spa_monitor_set_callbacks(monitor, &impl_callbacks, data); while (true) { diff --git a/src/modules/spa/spa-monitor.c b/src/modules/spa/spa-monitor.c index 05ad57abc..378d01c28 100644 --- a/src/modules/spa/spa-monitor.c +++ b/src/modules/spa/spa-monitor.c @@ -368,19 +368,6 @@ struct pw_spa_monitor *pw_spa_monitor_load(struct pw_core *core, spa_list_init(&impl->item_list); - for (index = 0;;) { - struct spa_pod *item; - uint8_t buffer[4096]; - struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); - int res; - - if ((res = spa_monitor_enum_items(this->monitor, &index, &item, &b)) <= 0) { - if (res != 0) - pw_log_debug("spa_monitor_enum_items: %s\n", spa_strerror(res)); - break; - } - add_item(this, item, 0); - } spa_monitor_set_callbacks(this->monitor, &callbacks, impl); return this; diff --git a/src/pipewire/device.c b/src/pipewire/device.c index 2edab30c0..690dc9712 100644 --- a/src/pipewire/device.c +++ b/src/pipewire/device.c @@ -193,6 +193,12 @@ static const struct pw_node_events node_events = { }; +static void device_info(void *data, const struct spa_dict *info) +{ + struct pw_device *device = data; + pw_device_update_properties(device, info); +} + static void device_add(void *data, uint32_t id, const struct spa_handle_factory *factory, uint32_t type, const struct spa_dict *info) @@ -228,6 +234,7 @@ static void device_add(void *data, uint32_t id, nd->id = id; nd->node = node; nd->handle = SPA_MEMBER(nd, sizeof(struct node_data), void); + 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, @@ -244,8 +251,6 @@ static void device_add(void *data, uint32_t id, goto error;; } - pw_node_add_listener(node, &nd->node_listener, &node_events, nd); - pw_node_set_implementation(node, iface); pw_node_register(node, NULL, device->global, NULL); pw_node_set_active(node, true); @@ -281,6 +286,7 @@ static void device_remove(void *data, uint32_t id) static const struct spa_device_callbacks device_callbacks = { SPA_VERSION_DEVICE_CALLBACKS, + .info = device_info, .add = device_add, .remove = device_remove, }; @@ -288,8 +294,6 @@ static const struct spa_device_callbacks device_callbacks = { void pw_device_set_implementation(struct pw_device *device, struct spa_device *spa_device) { device->implementation = spa_device; - if (spa_device && spa_device->info) - pw_device_update_properties(device, spa_device->info); spa_device_set_callbacks(device->implementation, &device_callbacks, device); } diff --git a/src/pipewire/node.c b/src/pipewire/node.c index 89bc45e44..71195ddf5 100644 --- a/src/pipewire/node.c +++ b/src/pipewire/node.c @@ -521,7 +521,7 @@ do_move_nodes(struct spa_loop *loop, spa_graph_node_remove(&this->rt.root); spa_graph_node_add(&dst->driver_graph, &this->rt.root); - if (spa_node_set_io(this->node, + if (this->node && spa_node_set_io(this->node, SPA_IO_Position, &dst->position, sizeof(struct spa_io_position)) >= 0) { pw_log_debug("node %p: set position %p", this, &dst->position); @@ -770,6 +770,12 @@ int pw_node_update_properties(struct pw_node *node, const struct spa_dict *dict) return changed; } +static void node_info(void *data, const struct spa_dict *info) +{ + struct pw_node *node = data; + pw_node_update_properties(node, info); +} + static void node_done(void *data, int seq, int res) { struct pw_node *node = data; @@ -860,6 +866,7 @@ static void node_reuse_buffer(void *data, uint32_t port_id, uint32_t buffer_id) static const struct spa_node_callbacks node_callbacks = { SPA_VERSION_NODE_CALLBACKS, + .info = node_info, .done = node_done, .event = node_event, .process = node_process,