diff --git a/spa/include/spa/monitor/device.h b/spa/include/spa/monitor/device.h index ebbc21644..3ebf0f795 100644 --- a/spa/include/spa/monitor/device.h +++ b/spa/include/spa/monitor/device.h @@ -34,6 +34,7 @@ struct spa_device; #include #include #include +#include /** * spa_device_callbacks: @@ -79,9 +80,64 @@ struct spa_device { int (*set_callbacks) (struct spa_device *device, const struct spa_device_callbacks *callbacks, void *data); + /** + * Enumerate the parameters of a device. + * + * Parameters are identified with an \a id. Some parameters can have + * multiple values, see the documentation of the parameter id. + * + * Parameters can be filtered by passing a non-NULL \a filter. + * + * This function must be called from the main thread. + * + * \param device a \ref spa_device + * \param id the param id to enumerate + * \param index the index of enumeration, pass 0 for the first item and the + * index is updated to retrieve the next item. + * \param filter and optional filter to use + * \param param result param or NULL + * \param builder builder for the param object. + * \return 1 on success and \a param contains the result + * 0 when there are no more parameters to enumerate + * -EINVAL when invalid arguments are given + * -ENOENT the parameter \a id is unknown + * -ENOTSUP when there are no parameters + * implemented on \a device + */ + int (*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); + /** + * Set the configurable parameter in \a device. + * + * Usually, \a param will be obtained from enum_params and then + * modified but it is also possible to set another spa_pod + * as long as its keys and types match a supported object. + * + * Objects with property keys that are not known are ignored. + * + * This function must be called from the main thread. + * + * \param device a \ref spa_device + * \param id the parameter id to configure + * \param flags additional flags + * \param param the parameter to configure + * + * \return 0 on success + * -EINVAL when invalid arguments are given + * -ENOTSUP when there are no parameters implemented on \a device + * -ENOENT the parameter is unknown + */ + int (*set_param) (struct spa_device *device, + uint32_t id, uint32_t flags, + const struct spa_pod *param); }; -#define spa_device_set_callbacks(m,...) (m)->set_callbacks((m),__VA_ARGS__) +#define spa_device_set_callbacks(d,...) (d)->set_callbacks((d),__VA_ARGS__) +#define spa_device_enum_params(d,...) (d)->enum_params((d),__VA_ARGS__) +#define spa_device_set_param(d,...) (d)->set_param((d),__VA_ARGS__) #ifdef __cplusplus } /* extern "C" */ diff --git a/spa/plugins/alsa/alsa-device.c b/spa/plugins/alsa/alsa-device.c new file mode 100644 index 000000000..f210ead85 --- /dev/null +++ b/spa/plugins/alsa/alsa-device.c @@ -0,0 +1,334 @@ +/* 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 +#include + +#define NAME "alsa-device" + +#define MAX_DEVICES 64 + +extern const struct spa_handle_factory spa_alsa_sink_factory; +extern const struct spa_handle_factory spa_alsa_source_factory; + +static const char default_device[] = "hw:0"; + +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; + + snd_ctl_t *ctl_hndl; + + struct props props; +}; + +static const char *get_class(snd_pcm_info_t *pcminfo) +{ + switch (snd_pcm_info_get_class(pcminfo)) { + case SND_PCM_CLASS_GENERIC: + return "generic"; + case SND_PCM_CLASS_MULTI: + return "multichannel"; + case SND_PCM_CLASS_MODEM: + return "modem"; + case SND_PCM_CLASS_DIGITIZER: + return "digitizer"; + default: + return "unknown"; + } +} + +static const char *get_subclass(snd_pcm_info_t *pcminfo) +{ + switch (snd_pcm_info_get_subclass(pcminfo)) { + case SND_PCM_SUBCLASS_GENERIC_MIX: + return "generic-mix"; + case SND_PCM_SUBCLASS_MULTI_MIX: + return "multichannel-mix"; + default: + return "unknown"; + } +} + +static int emit_device(struct impl *this, snd_ctl_card_info_t *info, snd_pcm_info_t *pcminfo) +{ + struct spa_dict_item items[13]; + const struct spa_handle_factory *factory; + char device_name[128]; + + snprintf(device_name, 128, "%s,%d", this->props.device, snd_pcm_info_get_device(pcminfo)); + + items[0] = SPA_DICT_ITEM_INIT("alsa.card.id", snd_ctl_card_info_get_id(info)); + items[1] = SPA_DICT_ITEM_INIT("alsa.device", device_name); + items[2] = SPA_DICT_ITEM_INIT("alsa.card.components", snd_ctl_card_info_get_components(info)); + items[3] = SPA_DICT_ITEM_INIT("alsa.card.driver", snd_ctl_card_info_get_driver(info)); + items[4] = SPA_DICT_ITEM_INIT("alsa.card.name", snd_ctl_card_info_get_name(info)); + items[5] = SPA_DICT_ITEM_INIT("alsa.card.longname", snd_ctl_card_info_get_longname(info)); + items[6] = SPA_DICT_ITEM_INIT("alsa.card.mixername", snd_ctl_card_info_get_mixername(info)); + items[7] = SPA_DICT_ITEM_INIT("device.name", snd_ctl_card_info_get_id(info)); + items[8] = SPA_DICT_ITEM_INIT("alsa.pcm.id", snd_pcm_info_get_id(pcminfo)); + items[9] = SPA_DICT_ITEM_INIT("alsa.pcm.name", snd_pcm_info_get_name(pcminfo)); + items[10] = SPA_DICT_ITEM_INIT("alsa.pcm.subname", snd_pcm_info_get_subdevice_name(pcminfo)); + items[11] = SPA_DICT_ITEM_INIT("alsa.pcm.class", get_class(pcminfo)); + items[12] = SPA_DICT_ITEM_INIT("alsa.pcm.subclass", get_subclass(pcminfo)); + + if (snd_pcm_info_get_stream(pcminfo) == SND_PCM_STREAM_PLAYBACK) + factory = &spa_alsa_sink_factory; + else + factory = &spa_alsa_source_factory; + + if (this->callbacks->add) + this->callbacks->add(this->callbacks_data, 0, + factory, + SPA_TYPE_INTERFACE_Node, + &SPA_DICT_INIT(items, 13)); + + return 0; +} + +static int emit_devices(struct impl *this) +{ + int err = 0, dev; + snd_ctl_card_info_t *info; + snd_pcm_info_t *pcminfo; + + spa_log_info(this->log, "open card %s", this->props.device); + + if ((err = snd_ctl_open(&this->ctl_hndl, this->props.device, 0)) < 0) { + spa_log_error(this->log, "can't open control for card %s: %s", + this->props.device, snd_strerror(err)); + return err; + } + + snd_ctl_card_info_alloca(&info); + if ((err = snd_ctl_card_info(this->ctl_hndl, info)) < 0) { + spa_log_error(this->log, "error hardware info: %s", snd_strerror(err)); + goto exit; + } + + snd_pcm_info_alloca(&pcminfo); + dev = -1; + while (1) { + if ((err = snd_ctl_pcm_next_device(this->ctl_hndl, &dev)) < 0) { + spa_log_error(this->log, "error iterating devices: %s", snd_strerror(err)); + goto exit; + } + if (dev < 0) + break; + + snd_pcm_info_set_device(pcminfo, dev); + snd_pcm_info_set_subdevice(pcminfo, 0); + + snd_pcm_info_set_stream(pcminfo, SND_PCM_STREAM_PLAYBACK); + if ((err = snd_ctl_pcm_info(this->ctl_hndl, pcminfo)) < 0) { + if (err != -ENOENT) + spa_log_error(this->log, "error pcm info: %s", snd_strerror(err)); + } + if (err >= 0) + emit_device(this, info, pcminfo); + + snd_pcm_info_set_stream(pcminfo, SND_PCM_STREAM_CAPTURE); + if ((err = snd_ctl_pcm_info(this->ctl_hndl, pcminfo)) < 0) { + if (err != -ENOENT) + spa_log_error(this->log, "error pcm info: %s", snd_strerror(err)); + } + if (err >= 0) + emit_device(this, info, pcminfo); + } + + exit: + snd_ctl_close(this->ctl_hndl); + + return err; +} + +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) + 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, + NULL, + 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; + const char *str; + 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; + } + + this->device = impl_device; + + reset_props(&this->props); + + if (info && (str = spa_dict_lookup(info, "alsa.card"))) + snprintf(this->props.device, 64, "hw:%d", atoi(str)); + + 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_alsa_device_factory = { + SPA_VERSION_HANDLE_FACTORY, + NAME, + NULL, + impl_get_size, + impl_init, + impl_enum_interface_info, +}; diff --git a/spa/plugins/alsa/alsa-monitor.c b/spa/plugins/alsa/alsa-monitor.c index 5a0691469..9bef481bd 100644 --- a/spa/plugins/alsa/alsa-monitor.c +++ b/spa/plugins/alsa/alsa-monitor.c @@ -40,30 +40,12 @@ #define NAME "alsa-monitor" -#define MAX_CARDS 32 -#define MAX_DEVICES 64 +#define MAX_CARDS 64 -extern const struct spa_handle_factory spa_alsa_sink_factory; -extern const struct spa_handle_factory spa_alsa_source_factory; +extern const struct spa_handle_factory spa_alsa_device_factory; -struct device { - int id; -#define DEVICE_FLAG_VALID (1<<0) -#define DEVICE_FLAG_PLAYBACK (1<<1) -#define DEVICE_FLAG_RECORD (1<<2) - uint32_t flags; -}; - -struct card { - int id; - struct udev_device *dev; - snd_ctl_t *ctl_hndl; - char name[16]; - struct device devices[MAX_DEVICES]; - int n_devices; - - int device_idx; - int stream_idx; +struct item { + struct udev_device *udevice; }; struct impl { @@ -82,12 +64,10 @@ struct impl { uint32_t index; struct udev_list_entry *devices; - struct card cards[MAX_CARDS]; + struct item uitem; + uint32_t cards[MAX_CARDS]; int n_cards; - int card_idx; - - int fd; struct spa_source source; }; @@ -97,10 +77,25 @@ static int impl_udev_open(struct impl *this) return 0; this->udev = udev_new(); + if (this->udev == NULL) + return -ENOMEM; return 0; } +static inline void add_dict(struct spa_pod_builder *builder, const char *key, ...) +{ + va_list args; + + va_start(args, key); + while (key) { + spa_pod_builder_string(builder, key); + spa_pod_builder_string(builder, va_arg(args, const char*)); + key = va_arg(args, const char *); + } + va_end(args); +} + static const char *path_get_card_id(const char *path) { const char *e; @@ -117,56 +112,16 @@ static const char *path_get_card_id(const char *path) return e + 5; } -static inline void add_dict(struct spa_pod_builder *builder, const char *key, ...) +static int fill_item(struct impl *this, struct item *item, struct udev_device *dev, + struct spa_pod **result, struct spa_pod_builder *builder) { - va_list args; + const char *str, *name; - va_start(args, key); - while (key) { - spa_pod_builder_string(builder, key); - spa_pod_builder_string(builder, va_arg(args, const char*)); - key = va_arg(args, const char *); - } - va_end(args); -} - -static int -fill_item(struct impl *this, snd_ctl_card_info_t *card_info, - snd_pcm_info_t *dev_info, struct card *card, - struct spa_pod **item, struct spa_pod_builder *builder) -{ - const char *str, *name, *klass = NULL; - const struct spa_handle_factory *factory = NULL; - char device_name[64], id[66]; - struct udev_device *dev = card->dev; - struct device *device; - int device_idx = snd_pcm_info_get_device(dev_info); - int stream = snd_pcm_info_get_stream(dev_info); - - if (device_idx < 0 || device_idx >= MAX_DEVICES) - return -1; - - device = &card->devices[device_idx]; - device->id = device_idx; - - snprintf(device_name, 64, "%s,%d", card->name, device_idx); - - switch (stream) { - case SND_PCM_STREAM_PLAYBACK: - factory = &spa_alsa_sink_factory; - klass = "Audio/Sink"; - SPA_FLAG_SET(device->flags, DEVICE_FLAG_PLAYBACK); - snprintf(id, 66, "%s/P", device_name); - break; - case SND_PCM_STREAM_CAPTURE: - factory = &spa_alsa_source_factory; - klass = "Audio/Source"; - SPA_FLAG_SET(device->flags, DEVICE_FLAG_RECORD); - snprintf(id, 66, "%s/C", device_name); - break; - default: - return -1; - } + 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)) { @@ -180,32 +135,25 @@ fill_item(struct impl *this, snd_ctl_card_info_t *card_info, spa_pod_builder_push_object(builder, SPA_TYPE_OBJECT_MonitorItem, 0); spa_pod_builder_props(builder, - SPA_MONITOR_ITEM_id, &SPA_POD_String(id, sizeof(id)), + SPA_MONITOR_ITEM_id, &SPA_POD_Stringv(udev_device_get_syspath(dev)), SPA_MONITOR_ITEM_flags, &SPA_POD_Id(SPA_MONITOR_ITEM_FLAG_NONE), SPA_MONITOR_ITEM_state, &SPA_POD_Id(SPA_MONITOR_ITEM_STATE_Available), SPA_MONITOR_ITEM_name, &SPA_POD_Stringv(name), - SPA_MONITOR_ITEM_class, &SPA_POD_Stringv(klass), - SPA_MONITOR_ITEM_factory, &SPA_POD_Pointer(SPA_TYPE_INTERFACE_HandleFactory, factory), - SPA_MONITOR_ITEM_type, &SPA_POD_Id(SPA_TYPE_INTERFACE_Node), + SPA_MONITOR_ITEM_class, &SPA_POD_Stringv("Audio/Device"), + SPA_MONITOR_ITEM_factory, &SPA_POD_Pointer(SPA_TYPE_INTERFACE_HandleFactory, &spa_alsa_device_factory), + SPA_MONITOR_ITEM_type, &SPA_POD_Id(SPA_TYPE_INTERFACE_Device), 0); + if ((str = path_get_card_id(udev_device_get_property_value(dev, "DEVPATH"))) == NULL) + return 0; + spa_pod_builder_prop(builder, SPA_MONITOR_ITEM_info, 0); spa_pod_builder_push_struct(builder), add_dict(builder, - "alsa.card", card->name, - "alsa.device", device_name, - "alsa.card.id", snd_ctl_card_info_get_id(card_info), - "alsa.card.components", snd_ctl_card_info_get_components(card_info), - "alsa.card.driver", snd_ctl_card_info_get_driver(card_info), - "alsa.card.name", snd_ctl_card_info_get_name(card_info), - "alsa.card.longname", snd_ctl_card_info_get_longname(card_info), - "alsa.card.mixername", snd_ctl_card_info_get_mixername(card_info), "udev-probed", "1", "device.api", "alsa", - "device.name", snd_ctl_card_info_get_id(card_info), - "alsa.pcm.id", snd_pcm_info_get_id(dev_info), - "alsa.pcm.name", snd_pcm_info_get_name(dev_info), - "alsa.pcm.subname", snd_pcm_info_get_subdevice_name(dev_info), + "device.path", udev_device_get_devnode(dev), + "alsa.card", str, NULL); if ((str = udev_device_get_property_value(dev, "SOUND_CLASS")) && *str) { @@ -255,115 +203,49 @@ fill_item(struct impl *this, snd_ctl_card_info_t *card_info, add_dict(builder, "device.form_factor", str, 0); } spa_pod_builder_pop(builder); - *item = spa_pod_builder_pop(builder); + *result = spa_pod_builder_pop(builder); - return 0; + return 1; } -static struct card *find_card(struct impl *this, struct udev_device *dev) +static int need_notify(struct impl *this, struct udev_device *dev, uint32_t id) { - int id; const char *str; - struct card *card; + int idx, i; if (udev_device_get_property_value(dev, "PULSE_IGNORE")) - return NULL; - - if ((str = udev_device_get_property_value(dev, "SOUND_CLASS")) && strcmp(str, "modem") == 0) - return NULL; - - if ((str = path_get_card_id(udev_device_get_property_value(dev, "DEVPATH"))) == NULL) - return NULL; - - id = atoi(str); - if (id < 0 || id >= MAX_CARDS) - return NULL; - - card = &this->cards[id]; - card->id = id; - card->dev = dev; - - return card; -} - -static int open_card(struct impl *this, struct card *card) -{ - int err; - - if (card->ctl_hndl) return 0; - snprintf(card->name, 16, "hw:%d", card->id); - spa_log_info(this->log, "open card %s", card->name); + if ((str = udev_device_get_property_value(dev, "SOUND_CLASS")) && strcmp(str, "modem") == 0) + return 0; - if ((err = snd_ctl_open(&card->ctl_hndl, card->name, 0)) < 0) { - spa_log_error(this->log, "can't open control for card %s: %s", - card->name, snd_strerror(err)); - return err; - } - card->device_idx = -1; - card->stream_idx = -1; + if ((str = path_get_card_id(udev_device_get_property_value(dev, "DEVPATH"))) == NULL) + return 0; - return 0; -} + idx = atoi(str); -static void close_card(struct impl *this, struct card *card) -{ - if (card->ctl_hndl == NULL) - return; - - spa_log_info(this->log, "close card %s", card->name); - udev_device_unref(card->dev); - snd_ctl_close(card->ctl_hndl); - card->ctl_hndl = NULL; -} - -static int get_next_device(struct impl *this, struct card *card, - struct spa_pod **item, struct spa_pod_builder *builder) -{ - int err; - snd_pcm_info_t *dev_info; - snd_ctl_card_info_t *card_info; - - if (card->stream_idx == -1) { - next_device: - if ((err = snd_ctl_pcm_next_device(card->ctl_hndl, &card->device_idx)) < 0) { - spa_log_error(this->log, "error iterating devices: %s", snd_strerror(err)); - return err; + if (id == SPA_MONITOR_EVENT_Added) { + for (i = 0; i < this->n_cards; i++) { + if (this->cards[i] == idx) + return 0; } - if (card->device_idx < 0) - return -1; - - card->stream_idx = 0; + if (this->n_cards >= MAX_CARDS) + return 0; + this->cards[this->n_cards++] = idx; } - - snd_pcm_info_alloca(&dev_info); - snd_pcm_info_set_device(dev_info, card->device_idx); - snd_pcm_info_set_subdevice(dev_info, 0); - - again: - switch (card->stream_idx++) { - case 0: - snd_pcm_info_set_stream(dev_info, SND_PCM_STREAM_PLAYBACK); - break; - case 1: - snd_pcm_info_set_stream(dev_info, SND_PCM_STREAM_CAPTURE); - break; - default: - goto next_device; + if (id == SPA_MONITOR_EVENT_Removed) { + int found = -1; + for (i = 0; i < this->n_cards; i++) { + if (this->cards[i] == idx) { + found = i; + break; + } + } + if (found == -1) + return 0; + this->cards[found] = this->cards[--this->n_cards]; } - - snd_ctl_card_info_alloca(&card_info); - - if ((err = snd_ctl_card_info(card->ctl_hndl, card_info)) < 0) { - spa_log_error(this->log, "can't get card info for device: %s", snd_strerror(err)); - return err; - } - - if ((err = snd_ctl_pcm_info(card->ctl_hndl, dev_info)) < 0) - goto again; - - return fill_item(this, card_info, dev_info, card, item, builder); + return 1; } static void impl_on_fd_events(struct spa_source *source) @@ -371,76 +253,35 @@ static void impl_on_fd_events(struct spa_source *source) struct impl *this = source->data; struct udev_device *dev; const char *action; - uint32_t type; - struct card *card; + 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) + return; if ((action = udev_device_get_action(dev)) == NULL) action = "change"; if (strcmp(action, "add") == 0) { - type = SPA_MONITOR_EVENT_Added; + id = SPA_MONITOR_EVENT_Added; } else if (strcmp(action, "change") == 0) { - type = SPA_MONITOR_EVENT_Changed; + id = SPA_MONITOR_EVENT_Changed; } else if (strcmp(action, "remove") == 0) { - type = SPA_MONITOR_EVENT_Removed; + id = SPA_MONITOR_EVENT_Removed; } else return; - if ((card = find_card(this, dev)) == NULL) + if (!need_notify(this, dev, id)) return; - if (type == SPA_MONITOR_EVENT_Removed) { - int i; - - for (i = 0; i < MAX_DEVICES; i++) { - struct device *device = &card->devices[i]; - uint8_t buffer[4096]; - char id[64]; - struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); - - if (SPA_FLAG_CHECK(device->flags, DEVICE_FLAG_PLAYBACK)) { - snprintf(id, 64, "%s,%d/P", card->name, device->id); - event = spa_pod_builder_object(&b, SPA_TYPE_EVENT_Monitor, type, 0); - spa_pod_builder_object(&b, - SPA_TYPE_OBJECT_MonitorItem, 0, - SPA_MONITOR_ITEM_id, &SPA_POD_Stringv(id), - SPA_MONITOR_ITEM_name, &SPA_POD_Stringv(id), - 0); - this->callbacks->event(this->callbacks_data, event); - } - if (SPA_FLAG_CHECK(device->flags, DEVICE_FLAG_RECORD)) { - snprintf(id, 64, "%s,%d/C", card->name, device->id); - event = spa_pod_builder_object(&b, SPA_TYPE_EVENT_Monitor, type, 0); - spa_pod_builder_object(&b, - SPA_TYPE_OBJECT_MonitorItem, 0, - SPA_MONITOR_ITEM_id, &SPA_POD_Stringv(id), - SPA_MONITOR_ITEM_name, &SPA_POD_Stringv(id), - 0); - this->callbacks->event(this->callbacks_data, event); - } - device->flags = 0; - } - } - else { - if (open_card(this, card) < 0) - return; - - while (true) { - uint8_t buffer[4096]; - struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); - struct spa_pod *item; - - event = spa_pod_builder_object(&b, SPA_TYPE_EVENT_Monitor, type, 0); - if (get_next_device(this, card, &item, &b) < 0) - break; - - this->callbacks->event(this->callbacks_data, event); - } - } - close_card(this, card); + 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); } static int @@ -492,7 +333,6 @@ static int impl_monitor_enum_items(struct spa_monitor *monitor, int res; struct impl *this; struct udev_device *dev; - struct card *card; spa_return_val_if_fail(monitor != NULL, -EINVAL); spa_return_val_if_fail(item != NULL, -EINVAL); @@ -511,42 +351,31 @@ static int impl_monitor_enum_items(struct spa_monitor *monitor, udev_enumerate_scan_devices(this->enumerate); this->devices = udev_enumerate_get_list_entry(this->enumerate); - this->card_idx = -1; this->index = 0; } while (*index > this->index && this->devices) { + next: this->devices = udev_list_entry_get_next(this->devices); this->index++; } - again: - if (this->devices == NULL) + if (this->devices == NULL) { + fill_item(this, &this->uitem, NULL, item, builder); return 0; + } - if (this->card_idx == -1) { - dev = udev_device_new_from_syspath(this->udev, + dev = udev_device_new_from_syspath(this->udev, udev_list_entry_get_name(this->devices)); - if ((card = find_card(this, dev)) == NULL) { - udev_device_unref(dev); - goto next; - } - - if (open_card(this, card) < 0) { - next: - this->card_idx = -1; - this->devices = udev_list_entry_get_next(this->devices); - goto again; - } - this->card_idx = card->id; - } - else - card = &this->cards[this->card_idx]; - - if (get_next_device(this, card, item, builder) < 0) { - close_card(this, card); + if (dev == NULL) goto next; - } + if (!need_notify(this, dev, SPA_MONITOR_EVENT_Added)) + 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)++; @@ -580,11 +409,9 @@ 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; - int i; - - for (i = 0; i < MAX_CARDS; i++) - close_card(this, &this->cards[i]); + if (this->uitem.udevice) + udev_device_unref(this->uitem.udevice); if (this->enumerate) udev_enumerate_unref(this->enumerate); if (this->umonitor) diff --git a/spa/plugins/alsa/alsa-sink.c b/spa/plugins/alsa/alsa-sink.c index 30294b74b..6ccdcc7b1 100644 --- a/spa/plugins/alsa/alsa-sink.c +++ b/spa/plugins/alsa/alsa-sink.c @@ -780,7 +780,7 @@ impl_init(const struct spa_handle_factory *factory, spa_list_init(&this->ready); for (i = 0; info && i < info->n_items; i++) { - if (!strcmp(info->items[i].key, "alsa.card")) { + if (!strcmp(info->items[i].key, "alsa.device")) { snprintf(this->props.device, 63, "%s", info->items[i].value); } } diff --git a/spa/plugins/alsa/alsa-source.c b/spa/plugins/alsa/alsa-source.c index 9ea56061b..d1ceba0a3 100644 --- a/spa/plugins/alsa/alsa-source.c +++ b/spa/plugins/alsa/alsa-source.c @@ -796,7 +796,7 @@ impl_init(const struct spa_handle_factory *factory, spa_list_init(&this->ready); for (i = 0; info && i < info->n_items; i++) { - if (!strcmp(info->items[i].key, "alsa.card")) { + if (!strcmp(info->items[i].key, "alsa.device")) { snprintf(this->props.device, 63, "%s", info->items[i].value); } } diff --git a/spa/plugins/v4l2/v4l2-device.c b/spa/plugins/v4l2/v4l2-device.c index 0867f8067..3b5b86cc0 100644 --- a/spa/plugins/v4l2/v4l2-device.c +++ b/spa/plugins/v4l2/v4l2-device.c @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -68,7 +69,7 @@ struct impl { struct spa_v4l2_device dev; }; -static int impl_device_set_callbacks(struct spa_device *device, +static int impl_set_callbacks(struct spa_device *device, const struct spa_device_callbacks *callbacks, void *data) { @@ -99,6 +100,22 @@ static int impl_device_set_callbacks(struct spa_device *device, 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_dict_item info_items[] = { { "media.class", "Video/Device" }, }; @@ -111,7 +128,9 @@ static const struct spa_dict info = { static const struct spa_device impl_device = { SPA_VERSION_DEVICE, &info, - impl_device_set_callbacks, + impl_set_callbacks, + impl_enum_params, + impl_set_param, }; static int impl_get_interface(struct spa_handle *handle, uint32_t type, void **interface) diff --git a/src/modules/module-audio-dsp/audio-dsp.c b/src/modules/module-audio-dsp/audio-dsp.c index 6c7f37084..600115b42 100644 --- a/src/modules/module-audio-dsp/audio-dsp.c +++ b/src/modules/module-audio-dsp/audio-dsp.c @@ -253,10 +253,14 @@ struct pw_node *pw_audio_dsp_new(struct pw_core *core, struct pw_properties *pr; int i; - if ((api = pw_properties_get(props, "device.api")) == NULL) + if ((api = pw_properties_get(props, "device.api")) == NULL) { + pw_log_error("missing device.api property"); goto error; - if ((alias = pw_properties_get(props, "device.name")) == NULL) + } + if ((alias = pw_properties_get(props, "device.name")) == NULL) { + pw_log_error("missing device.name property"); goto error; + } snprintf(node_name, sizeof(node_name), "system_%s", alias); for (i = 0; node_name[i]; i++) { @@ -287,8 +291,10 @@ struct pw_node *pw_audio_dsp_new(struct pw_core *core, PW_SPA_NODE_FLAG_ACTIVATE | PW_SPA_NODE_FLAG_NO_REGISTER, pr, sizeof(struct node) + user_data_size); - if (node == NULL) + if (node == NULL) { + pw_log_error("can't load spa node"); goto error; + } n = pw_spa_node_get_user_data(node); n->core = core; diff --git a/src/modules/spa/spa-monitor.c b/src/modules/spa/spa-monitor.c index f6288399b..bade49958 100644 --- a/src/modules/spa/spa-monitor.c +++ b/src/modules/spa/spa-monitor.c @@ -44,7 +44,6 @@ #include #include "spa-monitor.h" -#include "spa-node.h" #include "spa-device.h" struct monitor_item { @@ -81,7 +80,6 @@ static struct monitor_item *add_item(struct pw_spa_monitor *this, enum spa_monitor_item_state state; struct spa_pod *info = NULL; const struct spa_support *support; - enum pw_spa_node_flags flags; uint32_t n_support, type; if (spa_pod_object_parse(item, @@ -147,13 +145,6 @@ static struct monitor_item *add_item(struct pw_spa_monitor *this, mitem->type = type; switch (type) { - case SPA_TYPE_INTERFACE_Node: - flags = PW_SPA_NODE_FLAG_ACTIVATE; - flags |= (state == SPA_MONITOR_ITEM_STATE_Available) ? 0 : PW_SPA_NODE_FLAG_DISABLE; - mitem->object = pw_spa_node_new(impl->core, NULL, impl->parent, name, - flags, - iface, handle, props, 0); - break; case SPA_TYPE_INTERFACE_Device: mitem->object = pw_spa_device_new(impl->core, NULL, impl->parent, name, 0, iface, handle, props, 0); diff --git a/src/pipewire/device.c b/src/pipewire/device.c index 9f0024a18..2edab30c0 100644 --- a/src/pipewire/device.c +++ b/src/pipewire/device.c @@ -202,7 +202,8 @@ static void device_add(void *data, uint32_t id, uint32_t n_support; struct pw_node *node; struct node_data *nd; - int res; + struct pw_properties *props; + int i, res; void *iface; if (type != SPA_TYPE_INTERFACE_Node) { @@ -213,9 +214,13 @@ static void device_add(void *data, uint32_t id, pw_log_debug("device %p: add node %d", device, id); support = pw_core_get_support(device->core, &n_support); + props = pw_properties_copy(device->properties); + for (i = 0; info && i < info->n_items; i++) + pw_properties_set(props, info->items[i].key, info->items[i].value); + node = pw_node_new(device->core, device->info.name, - pw_properties_copy(device->properties), + props, sizeof(struct node_data) + spa_handle_factory_get_size(factory, info)); diff --git a/src/pipewire/properties.c b/src/pipewire/properties.c index 4740748d2..19a24a377 100644 --- a/src/pipewire/properties.c +++ b/src/pipewire/properties.c @@ -208,7 +208,7 @@ struct pw_properties *pw_properties_copy(const struct pw_properties *properties) * \memberof pw_properties */ struct pw_properties *pw_properties_merge(const struct pw_properties *oldprops, - struct pw_properties *newprops) + const struct pw_properties *newprops) { struct pw_properties *res = NULL; diff --git a/src/pipewire/properties.h b/src/pipewire/properties.h index 301c58f7a..45728cbad 100644 --- a/src/pipewire/properties.h +++ b/src/pipewire/properties.h @@ -58,7 +58,7 @@ pw_properties_copy(const struct pw_properties *properties); struct pw_properties * pw_properties_merge(const struct pw_properties *oldprops, - struct pw_properties *newprops); + const struct pw_properties *newprops); void pw_properties_free(struct pw_properties *properties);