monitor: remove monitor API and use device

Remove the monitor API, we can use the device API for it. Make sure
we support creating devices (like alsa) from another device (udev).

Use new object.id to store the object id in the object properties. Use
the port.id/node.id etc to make relations to other objects.
This commit is contained in:
Wim Taymans 2019-09-20 13:04:14 +02:00
parent 818fb9e904
commit 6756a3c8fc
43 changed files with 474 additions and 1015 deletions

View file

@ -37,8 +37,6 @@ install_headers(spa_graph_headers,
spa_monitor_headers = [
'monitor/device.h',
'monitor/monitor.h',
'monitor/type-info.h',
'monitor/utils.h',
]

View file

@ -236,8 +236,10 @@ struct spa_device_methods {
#define spa_device_enum_params(d,...) spa_device_method(d, enum_params, 0, __VA_ARGS__)
#define spa_device_set_param(d,...) spa_device_method(d, set_param, 0, __VA_ARGS__)
#define SPA_KEY_DEVICE_ENUM_API "device.enum.api" /**< the api used to discover this
* device */
#define SPA_KEY_DEVICE_API "device.api" /**< the api used by the device
* Ex. "alsa", "v4l2". */
* Ex. "udev", "alsa", "v4l2". */
#define SPA_KEY_DEVICE_NAME "device.name" /**< the name of the device */
#define SPA_KEY_DEVICE_ALIAS "device.alias" /**< altenative name of the device */
#define SPA_KEY_DEVICE_NICK "device.nick" /**< the device short name */

View file

@ -1,133 +0,0 @@
/* Simple Plugin API
*
* 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.
*/
#ifndef SPA_MONITOR_H
#define SPA_MONITOR_H
#ifdef __cplusplus
extern "C" {
#endif
#include <spa/utils/defs.h>
#include <spa/utils/dict.h>
#include <spa/pod/event.h>
#include <spa/pod/builder.h>
#define SPA_VERSION_MONITOR 0
struct spa_monitor { struct spa_interface iface; };
struct spa_monitor_info {
#define SPA_VERSION_MONITOR_INFO 0
uint32_t version;
#define SPA_MONITOR_CHANGE_MASK_FLAGS (1u<<0)
#define SPA_MONITOR_CHANGE_MASK_PROPS (1u<<1)
uint64_t change_mask;
uint64_t flags;
const struct spa_dict *props;
};
#define SPA_MONITOR_INFO_INIT() (struct spa_monitor_info){ SPA_VERSION_MONITOR_INFO, }
struct spa_monitor_object_info {
#define SPA_VERSION_MONITOR_OBJECT_INFO 0
uint32_t version;
uint32_t type;
const char *factory_name;
#define SPA_MONITOR_OBJECT_CHANGE_MASK_FLAGS (1u<<0)
#define SPA_MONITOR_OBJECT_CHANGE_MASK_PROPS (1u<<1)
uint64_t change_mask;
uint64_t flags;
const struct spa_dict *props;
};
#define SPA_MONITOR_OBJECT_INFO_INIT() (struct spa_monitor_object_info){ SPA_VERSION_MONITOR_OBJECT_INFO, }
/**
* spa_monitor_callbacks:
*/
struct spa_monitor_callbacks {
/** version of the structure */
#define SPA_VERSION_MONITOR_CALLBACKS 0
uint32_t version;
/** receive extra information about the monitor */
int (*info) (void *data, const struct spa_monitor_info *info);
/** an item is added/removed/changed on the monitor */
int (*event) (void *data, const struct spa_event *event);
/** info changed for an object managed by the monitor, info is NULL when
* the object is removed */
int (*object_info) (void *data, uint32_t id,
const struct spa_monitor_object_info *info);
};
/**
* spa_monitor_methods:
*
* The device monitor methods.
*/
struct spa_monitor_methods {
/* the version of this monitor. This can be used to expand this
* structure in the future */
#define SPA_VERSION_MONITOR_METHODS 0
uint32_t version;
/**
* 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
* < 0 errno on error
*/
int (*set_callbacks) (void *object,
const struct spa_monitor_callbacks *callbacks,
void *data);
};
static inline int spa_monitor_set_callbacks(struct spa_monitor *m,
const struct spa_monitor_callbacks *callbacks, void *data)
{
int res = -ENOTSUP;
spa_interface_call_res(&m->iface,
struct spa_monitor_methods, res, set_callbacks, 0,
callbacks, data);
return res;
}
#define SPA_KEY_MONITOR_API "monitor.api" /**< the api used by the monitor.
* Ex. "udev", "dbus", ... */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* SPA_MONITOR_H */

View file

@ -1,51 +0,0 @@
/* Simple Plugin API
*
* 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.
*/
#ifndef SPA_MONITOR_TYPES_H
#define SPA_MONITOR_TYPES_H
#ifdef __cplusplus
extern "C" {
#endif
#include <spa/utils/type-info.h>
#include <spa/monitor/monitor.h>
#define SPA_TYPE_INFO_MonitorEvent SPA_TYPE_INFO_EVENT_BASE "Monitor"
#define SPA_TYPE_INFO_MONITOR_EVENT_BASE SPA_TYPE_INFO_MonitorEvent ":"
static const struct spa_type_info spa_type_monitor_event_id[] = {
{ 0, 0, NULL, NULL },
};
static const struct spa_type_info spa_type_monitor_event[] = {
{ 0, SPA_TYPE_Id, SPA_TYPE_INFO_MONITOR_EVENT_BASE, spa_type_monitor_event_id },
{ 0, 0, NULL, NULL },
};
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* SPA_MONITOR_TYPES_H */

View file

@ -66,9 +66,9 @@ struct spa_interface {
struct spa_hook {
struct spa_list link;
struct spa_callbacks cb;
void *priv; /**< private data for the hook list */
/** callback and data for the hook list */
void (*removed) (struct spa_hook *hook);
void *priv;
};
/** Initialize a hook list */
@ -77,6 +77,11 @@ static inline void spa_hook_list_init(struct spa_hook_list *list)
spa_list_init(&list->list);
}
static inline bool spa_hook_list_is_empty(struct spa_hook_list *list)
{
return spa_list_is_empty(&list->list);
}
/** Append a hook \memberof spa_hook */
static inline void spa_hook_list_append(struct spa_hook_list *list,
struct spa_hook *hook,

View file

@ -37,6 +37,10 @@ extern "C" {
* Screen, Communication, Game,
* Notification, DSP, Production,
* Accessibility, Test */
/** keys for udev api */
#define SPA_KEY_API_UDEV "api.udev" /**< key for the udev api */
#define SPA_KEY_API_UDEV_MATCH "api.udev.match" /**< udev subsystem match */
/** keys for alsa api */
#define SPA_KEY_API_ALSA "api.alsa" /**< key for the alsa api */
#define SPA_KEY_API_ALSA_PATH "api.alsa.path" /**< alsa device path as can be

View file

@ -77,7 +77,7 @@ extern "C" {
#define SPA_NAME_VIDEO_ADAPT "video.adapt" /**< combination of a node and a
* video.convert. */
/** keys for alsa factory names */
#define SPA_NAME_API_ALSA_MONITOR "api.alsa.monitor" /**< an alsa Monitor interface */
#define SPA_NAME_API_ALSA_ENUM_UDEV "api.alsa.enum.udev" /**< an alsa udev Device interface */
#define SPA_NAME_API_ALSA_DEVICE "api.alsa.device" /**< an alsa Device interface */
#define SPA_NAME_API_ALSA_PCM_SOURCE "api.alsa.pcm.source" /**< an alsa Node interface for
* capturing PCM */
@ -87,7 +87,7 @@ extern "C" {
* capturing midi */
/** keys for bluez5 factory names */
#define SPA_NAME_API_BLUEZ5_MONITOR "api.bluez5.monitor" /**< a Monitor interface */
#define SPA_NAME_API_BLUEZ5_ENUM_DBUS "api.bluez5.enum.dbus" /**< a dbus Device interface */
#define SPA_NAME_API_BLUEZ5_DEVICE "api.bluez5.device" /**< a Device interface */
#define SPA_NAME_API_BLUEZ5_A2DP_SINK "api.bluez5.a2dp.sink" /**< a playback Node interface for A2DP profiles */
#define SPA_NAME_API_BLUEZ5_A2DP_SOURCE "api.bluez5.a2dp.source" /**< a capture Node interface for A2DP profiles */
@ -95,7 +95,7 @@ extern "C" {
#define SPA_NAME_API_BLUEZ5_SCO_SOURCE "api.bluez5.sco.source" /**< a capture Node interface for HSP/HFP profiles */
/** keys for v4l2 factory names */
#define SPA_NAME_API_V4L2_MONITOR "api.v4l2.monitor" /**< a v4l2 Monitor interface */
#define SPA_NAME_API_V4L2_ENUM_UDEV "api.v4l2.enum.udev" /**< a v4l2 udev Device interface */
#define SPA_NAME_API_V4L2_DEVICE "api.v4l2.device" /**< a v4l2 Device interface */
#define SPA_NAME_API_V4L2_SOURCE "api.v4l2.source" /**< a v4l2 Node interface for
* capturing */

View file

@ -52,7 +52,6 @@ static const struct spa_type_info spa_type_direction[] = {
{ 0, 0, NULL, NULL }
};
#include <spa/monitor/type-info.h>
#include <spa/node/type-info.h>
#include <spa/param/type-info.h>
#include <spa/control/type-info.h>
@ -110,16 +109,16 @@ static const struct spa_type_info spa_types[] = {
{ SPA_TYPE_INTERFACE_DataSystem, SPA_TYPE_Pointer, SPA_TYPE_INFO_INTERFACE_BASE "DataSystem", NULL },
{ SPA_TYPE_INTERFACE_DataLoop, SPA_TYPE_Pointer, SPA_TYPE_INFO_INTERFACE_BASE "DataLoop", NULL },
{ SPA_TYPE_INTERFACE_DBus, SPA_TYPE_Pointer, SPA_TYPE_INFO_INTERFACE_BASE "DBus", NULL },
{ SPA_TYPE_INTERFACE_Monitor, SPA_TYPE_Pointer, SPA_TYPE_INFO_INTERFACE_BASE "Monitor", NULL },
{ SPA_TYPE_INTERFACE_Node, SPA_TYPE_Pointer, SPA_TYPE_INFO_INTERFACE_BASE "Node", NULL },
{ SPA_TYPE_INTERFACE_Device, SPA_TYPE_Pointer, SPA_TYPE_INFO_INTERFACE_BASE "Device", NULL },
{ SPA_TYPE_INTERFACE_CPU, SPA_TYPE_Pointer, SPA_TYPE_INFO_INTERFACE_BASE "CPU", NULL },
{ SPA_TYPE_EVENT_START, SPA_TYPE_Object, SPA_TYPE_INFO_Event, NULL },
{ SPA_TYPE_EVENT_Monitor, SPA_TYPE_Object, SPA_TYPE_INFO_EVENT_BASE "Monitor", spa_type_monitor_event },
{ SPA_TYPE_EVENT_Device, SPA_TYPE_Object, SPA_TYPE_INFO_EVENT_BASE "Device", NULL },
{ SPA_TYPE_EVENT_Node, SPA_TYPE_Object, SPA_TYPE_INFO_EVENT_BASE "Node", spa_type_node_event },
{ SPA_TYPE_COMMAND_START, SPA_TYPE_Object, SPA_TYPE_INFO_Command, NULL },
{ SPA_TYPE_COMMAND_Device, SPA_TYPE_Object, SPA_TYPE_INFO_COMMAND_BASE "Device", NULL },
{ SPA_TYPE_COMMAND_Node, SPA_TYPE_Object, SPA_TYPE_INFO_COMMAND_BASE "Node", spa_type_node_command },
{ SPA_TYPE_OBJECT_START, SPA_TYPE_Object, SPA_TYPE_INFO_Object, NULL },

View file

@ -75,7 +75,6 @@ enum {
SPA_TYPE_INTERFACE_DataSystem, /**< System functions for data loop */
SPA_TYPE_INTERFACE_DataLoop, /**< a data loop */
SPA_TYPE_INTERFACE_DBus, /**< dbus connection */
SPA_TYPE_INTERFACE_Monitor, /**< monitor of devices */
SPA_TYPE_INTERFACE_Node, /**< nodes for data processing */
SPA_TYPE_INTERFACE_Device, /**< device managing nodes */
SPA_TYPE_INTERFACE_CPU, /**< CPU functions */
@ -83,12 +82,13 @@ enum {
/* Events */
SPA_TYPE_EVENT_START = 0x30000,
SPA_TYPE_EVENT_Monitor,
SPA_TYPE_EVENT_Device,
SPA_TYPE_EVENT_Node,
SPA_TYPE_EVENT_LAST, /**< not part of ABI */
/* Commands */
SPA_TYPE_COMMAND_START = 0x40000,
SPA_TYPE_COMMAND_Device,
SPA_TYPE_COMMAND_Node,
SPA_TYPE_COMMAND_LAST, /**< not part of ABI */

View file

@ -1,4 +1,4 @@
/* Spa ALSA Monitor
/* Spa ALSA udev
*
* Copyright © 2018 Wim Taymans
*
@ -30,7 +30,6 @@
#include <poll.h>
#include <libudev.h>
#include <alsa/asoundlib.h>
#include <spa/support/log.h>
#include <spa/utils/type.h>
@ -38,10 +37,10 @@
#include <spa/utils/names.h>
#include <spa/support/loop.h>
#include <spa/support/plugin.h>
#include <spa/monitor/monitor.h>
#include <spa/monitor/device.h>
#include <spa/monitor/utils.h>
#define NAME "alsa-monitor"
#define NAME "alsa-udev"
#define MAX_CARDS 64
@ -51,12 +50,15 @@
struct impl {
struct spa_handle handle;
struct spa_monitor monitor;
struct spa_device device;
struct spa_log *log;
struct spa_loop *main_loop;
struct spa_callbacks callbacks;
struct spa_hook_list hooks;
uint64_t info_all;
struct spa_device_info info;
struct udev *udev;
struct udev_monitor *umonitor;
@ -183,21 +185,21 @@ static void unescape(const char *src, char *dst)
static int emit_object_info(struct impl *this, uint32_t id, struct udev_device *dev)
{
struct spa_monitor_object_info info;
struct spa_device_object_info info;
const char *str;
char path[32];
struct spa_dict_item items[20];
uint32_t n_items = 0;
info = SPA_MONITOR_OBJECT_INFO_INIT();
info = SPA_DEVICE_OBJECT_INFO_INIT();
info.type = SPA_TYPE_INTERFACE_Device;
info.factory_name = SPA_NAME_API_ALSA_DEVICE;
info.change_mask = SPA_MONITOR_OBJECT_CHANGE_MASK_FLAGS |
SPA_MONITOR_OBJECT_CHANGE_MASK_PROPS;
info.change_mask = SPA_DEVICE_OBJECT_CHANGE_MASK_FLAGS |
SPA_DEVICE_OBJECT_CHANGE_MASK_PROPS;
info.flags = 0;
items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_MONITOR_API, "udev");
items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_ENUM_API, "udev");
items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_API, "alsa");
if ((str = path_get_card_id(udev_device_get_property_value(dev, "DEVPATH"))) == NULL)
@ -275,7 +277,8 @@ static int emit_object_info(struct impl *this, uint32_t id, struct udev_device *
items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_FORM_FACTOR, str);
}
info.props = &SPA_DICT_INIT(items, n_items);
spa_monitor_call_object_info(&this->callbacks, id, &info);
spa_device_emit_object_info(&this->hooks, id, &info);
return 1;
}
@ -348,7 +351,7 @@ static int emit_device(struct impl *this, uint32_t action, bool enumerated, stru
emit_object_info(this, id, dev);
break;
default:
spa_monitor_call_object_info(&this->callbacks, id, NULL);
spa_device_emit_object_info(&this->hooks, id, NULL);
break;
}
return 0;
@ -448,38 +451,67 @@ static int enum_devices(struct impl *this)
return 0;
}
static const struct spa_dict_item device_info_items[] = {
{ SPA_KEY_DEVICE_API, "udev" },
{ SPA_KEY_DEVICE_NICK, "alsa-udev" },
{ SPA_KEY_API_UDEV_MATCH, "sound" },
};
static void emit_device_info(struct impl *this, bool full)
{
if (full)
this->info.change_mask = this->info_all;
if (this->info.change_mask) {
this->info.props = &SPA_DICT_INIT_ARRAY(device_info_items);
spa_device_emit_info(&this->hooks, &this->info);
this->info.change_mask = 0;
}
}
static void impl_hook_removed(struct spa_hook *hook)
{
struct impl *this = hook->priv;
if (spa_hook_list_is_empty(&this->hooks)) {
stop_monitor(this);
impl_udev_close(this);
}
}
static int
impl_monitor_set_callbacks(void *object,
const struct spa_monitor_callbacks *callbacks,
void *data)
impl_device_add_listener(void *object, struct spa_hook *listener,
const struct spa_device_events *events, void *data)
{
int res;
struct impl *this = object;
struct spa_hook_list save;
spa_return_val_if_fail(this != NULL, -EINVAL);
spa_return_val_if_fail(events != NULL, -EINVAL);
this->callbacks = SPA_CALLBACKS_INIT(callbacks, data);
if (callbacks) {
if ((res = impl_udev_open(this)) < 0)
return res;
spa_hook_list_isolate(&this->hooks, &save, listener, events, data);
emit_device_info(this, true);
if ((res = enum_devices(this)) < 0)
return res;
if ((res = start_monitor(this)) < 0)
return res;
} else {
stop_monitor(this);
impl_udev_close(this);
}
spa_hook_list_join(&this->hooks, &save);
listener->removed = impl_hook_removed;
listener->priv = this;
return 0;
}
static const struct spa_monitor_methods impl_monitor = {
SPA_VERSION_MONITOR_METHODS,
.set_callbacks = impl_monitor_set_callbacks,
static const struct spa_device_methods impl_device = {
SPA_VERSION_DEVICE_METHODS,
.add_listener = impl_device_add_listener,
};
static int impl_get_interface(struct spa_handle *handle, uint32_t type, void **interface)
@ -491,18 +523,21 @@ static int impl_get_interface(struct spa_handle *handle, uint32_t type, void **i
this = (struct impl *) handle;
if (type == SPA_TYPE_INTERFACE_Monitor)
*interface = &this->monitor;
else
switch (type) {
case SPA_TYPE_INTERFACE_Device:
*interface = &this->device;
break;
default:
return -ENOENT;
}
return 0;
}
static int impl_clear(struct spa_handle *handle)
{
struct impl *this = (struct impl *) handle;
impl_monitor_set_callbacks(this, NULL, NULL);
stop_monitor(this);
impl_udev_close(this);
return 0;
}
@ -532,26 +567,38 @@ impl_init(const struct spa_handle_factory *factory,
this = (struct impl *) handle;
for (i = 0; i < n_support; i++) {
if (support[i].type == SPA_TYPE_INTERFACE_Log)
switch (support[i].type) {
case SPA_TYPE_INTERFACE_Log:
this->log = support[i].data;
else if (support[i].type == SPA_TYPE_INTERFACE_Loop)
break;
case SPA_TYPE_INTERFACE_Loop:
this->main_loop = support[i].data;
break;
default:
break;
}
}
if (this->main_loop == NULL) {
spa_log_error(this->log, "a main-loop is needed");
return -EINVAL;
}
spa_hook_list_init(&this->hooks);
this->monitor.iface = SPA_INTERFACE_INIT(
SPA_TYPE_INTERFACE_Monitor,
SPA_VERSION_MONITOR,
&impl_monitor, this);
this->device.iface = SPA_INTERFACE_INIT(
SPA_TYPE_INTERFACE_Device,
SPA_VERSION_DEVICE,
&impl_device, this);
this->info = SPA_DEVICE_INFO_INIT();
this->info_all = SPA_DEVICE_CHANGE_MASK_FLAGS |
SPA_DEVICE_CHANGE_MASK_PROPS;
this->info.flags = 0;
return 0;
}
static const struct spa_interface_info impl_interfaces[] = {
{SPA_TYPE_INTERFACE_Monitor,},
{SPA_TYPE_INTERFACE_Device,},
};
static int
@ -570,9 +617,9 @@ impl_enum_interface_info(const struct spa_handle_factory *factory,
return 1;
}
const struct spa_handle_factory spa_alsa_monitor_factory = {
const struct spa_handle_factory spa_alsa_udev_factory = {
SPA_VERSION_HANDLE_FACTORY,
SPA_NAME_API_ALSA_MONITOR,
SPA_NAME_API_ALSA_ENUM_UDEV,
NULL,
impl_get_size,
impl_init,

View file

@ -28,7 +28,7 @@
extern const struct spa_handle_factory spa_alsa_source_factory;
extern const struct spa_handle_factory spa_alsa_sink_factory;
extern const struct spa_handle_factory spa_alsa_monitor_factory;
extern const struct spa_handle_factory spa_alsa_udev_factory;
extern const struct spa_handle_factory spa_alsa_device_factory;
extern const struct spa_handle_factory spa_alsa_midi_source_factory;
@ -46,7 +46,7 @@ int spa_handle_factory_enum(const struct spa_handle_factory **factory, uint32_t
*factory = &spa_alsa_sink_factory;
break;
case 2:
*factory = &spa_alsa_monitor_factory;
*factory = &spa_alsa_udev_factory;
break;
case 3:
*factory = &spa_alsa_device_factory;

View file

@ -1,5 +1,5 @@
spa_alsa_sources = ['alsa.c',
'alsa-monitor.c',
'alsa-udev.c',
'alsa-device.c',
'alsa-seq-source.c',
'alsa-seq.c',

View file

@ -1,4 +1,4 @@
/* Spa V4l2 Monitor
/* Spa V4l2 dbus
*
* Copyright © 2018 Wim Taymans
*
@ -41,8 +41,9 @@
#include <spa/support/loop.h>
#include <spa/support/dbus.h>
#include <spa/support/plugin.h>
#include <spa/monitor/monitor.h>
#include <spa/monitor/device.h>
#include <spa/monitor/utils.h>
#include <spa/utils/hook.h>
#include <spa/utils/type.h>
#include <spa/utils/keys.h>
#include <spa/utils/names.h>
@ -54,7 +55,7 @@
struct spa_bt_monitor {
struct spa_handle handle;
struct spa_monitor monitor;
struct spa_device device;
struct spa_log *log;
struct spa_loop *main_loop;
@ -62,7 +63,7 @@ struct spa_bt_monitor {
struct spa_dbus_connection *dbus_connection;
DBusConnection *conn;
struct spa_callbacks callbacks;
struct spa_hook_list hooks;
uint32_t count;
uint32_t id;
@ -70,6 +71,8 @@ struct spa_bt_monitor {
struct spa_list adapter_list;
struct spa_list device_list;
struct spa_list transport_list;
unsigned int filters_added:1;
};
struct transport_data {
@ -490,7 +493,7 @@ static int device_free(struct spa_bt_device *device)
static int device_add(struct spa_bt_monitor *monitor, struct spa_bt_device *device)
{
struct spa_monitor_object_info info;
struct spa_device_object_info info;
char dev[32];
struct spa_dict_item items[20];
uint32_t n_items = 0;
@ -498,11 +501,11 @@ static int device_add(struct spa_bt_monitor *monitor, struct spa_bt_device *devi
if (device->added)
return 0;
info = SPA_MONITOR_OBJECT_INFO_INIT();
info = SPA_DEVICE_OBJECT_INFO_INIT();
info.type = SPA_TYPE_INTERFACE_Device;
info.factory_name = SPA_NAME_API_BLUEZ5_DEVICE;
info.change_mask = SPA_MONITOR_OBJECT_CHANGE_MASK_FLAGS |
SPA_MONITOR_OBJECT_CHANGE_MASK_PROPS;
info.change_mask = SPA_DEVICE_OBJECT_CHANGE_MASK_FLAGS |
SPA_DEVICE_OBJECT_CHANGE_MASK_PROPS;
info.flags = 0;
items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_API, "bluez5");
@ -517,7 +520,7 @@ static int device_add(struct spa_bt_monitor *monitor, struct spa_bt_device *devi
info.props = &SPA_DICT_INIT(items, n_items);
device->added = true;
spa_monitor_call_object_info(&monitor->callbacks, device->id, &info);
spa_device_emit_object_info(&monitor->hooks, device->id, &info);
return 0;
}
@ -528,7 +531,7 @@ static int device_remove(struct spa_bt_monitor *monitor, struct spa_bt_device *d
return 0;
device->added = false;
spa_monitor_call_object_info(&monitor->callbacks, device->id, NULL);
spa_device_emit_object_info(&monitor->hooks, device->id, NULL);
return 0;
}
@ -2128,6 +2131,9 @@ static void add_filters(struct spa_bt_monitor *this)
{
DBusError err;
if (this->filters_added)
return;
dbus_error_init(&err);
if (!dbus_connection_add_filter(this->conn, filter_cb, this, NULL)) {
@ -2158,6 +2164,8 @@ static void add_filters(struct spa_bt_monitor *this)
"interface='org.freedesktop.DBus.Properties',member='PropertiesChanged',"
"arg0='" BLUEZ_MEDIA_TRANSPORT_INTERFACE "'", &err);
this->filters_added = true;
return;
fail:
@ -2165,27 +2173,28 @@ fail:
}
static int
impl_monitor_set_callbacks(void *object,
const struct spa_monitor_callbacks *callbacks,
void *data)
impl_device_add_listener(void *object, struct spa_hook *listener,
const struct spa_device_events *events, void *data)
{
struct spa_bt_monitor *this = object;
struct spa_hook_list save;
spa_return_val_if_fail(this != NULL, -EINVAL);
spa_return_val_if_fail(events != NULL, -EINVAL);
this->callbacks = SPA_CALLBACKS_INIT(callbacks, data);
spa_hook_list_isolate(&this->hooks, &save, listener, events, data);
if (callbacks) {
add_filters(this);
get_managed_objects(this);
}
spa_hook_list_join(&this->hooks, &save);
return 0;
}
static const struct spa_monitor_methods impl_monitor = {
SPA_VERSION_MONITOR_METHODS,
.set_callbacks = impl_monitor_set_callbacks,
static const struct spa_device_methods impl_device = {
SPA_VERSION_DEVICE_METHODS,
.add_listener = impl_device_add_listener,
};
static int impl_get_interface(struct spa_handle *handle, uint32_t type, void **interface)
@ -2197,11 +2206,13 @@ static int impl_get_interface(struct spa_handle *handle, uint32_t type, void **i
this = (struct spa_bt_monitor *) handle;
if (type == SPA_TYPE_INTERFACE_Monitor)
*interface = &this->monitor;
else
switch (type) {
case SPA_TYPE_INTERFACE_Device:
*interface = &this->device;
break;
default:
return -ENOENT;
}
return 0;
}
@ -2260,10 +2271,12 @@ impl_init(const struct spa_handle_factory *factory,
}
this->conn = spa_dbus_connection_get(this->dbus_connection);
this->monitor.iface = SPA_INTERFACE_INIT(
SPA_TYPE_INTERFACE_Monitor,
SPA_VERSION_MONITOR,
&impl_monitor, this);
spa_hook_list_init(&this->hooks);
this->device.iface = SPA_INTERFACE_INIT(
SPA_TYPE_INTERFACE_Device,
SPA_VERSION_DEVICE,
&impl_device, this);
spa_list_init(&this->adapter_list);
spa_list_init(&this->device_list);
@ -2273,7 +2286,7 @@ impl_init(const struct spa_handle_factory *factory,
}
static const struct spa_interface_info impl_interfaces[] = {
{SPA_TYPE_INTERFACE_Monitor,},
{SPA_TYPE_INTERFACE_Device,},
};
static int
@ -2293,9 +2306,9 @@ impl_enum_interface_info(const struct spa_handle_factory *factory,
return 1;
}
const struct spa_handle_factory spa_bluez5_monitor_factory = {
const struct spa_handle_factory spa_bluez5_dbus_factory = {
SPA_VERSION_HANDLE_FACTORY,
SPA_NAME_API_BLUEZ5_MONITOR,
SPA_NAME_API_BLUEZ5_ENUM_DBUS,
NULL,
impl_get_size,
impl_init,

View file

@ -6,7 +6,7 @@ bluez5_sources = ['plugin.c',
'sco-sink.c',
'sco-source.c',
'bluez5-device.c',
'bluez5-monitor.c']
'bluez5-dbus.c']
bluez5lib = shared_library('spa-bluez5',
bluez5_sources,

View file

@ -27,7 +27,7 @@
#include <spa/support/plugin.h>
extern const struct spa_handle_factory spa_bluez5_monitor_factory;
extern const struct spa_handle_factory spa_bluez5_dbus_factory;
extern const struct spa_handle_factory spa_bluez5_device_factory;
extern const struct spa_handle_factory spa_a2dp_sink_factory;
extern const struct spa_handle_factory spa_a2dp_source_factory;
@ -42,7 +42,7 @@ int spa_handle_factory_enum(const struct spa_handle_factory **factory, uint32_t
switch (*index) {
case 0:
*factory = &spa_bluez5_monitor_factory;
*factory = &spa_bluez5_dbus_factory;
break;
case 1:
*factory = &spa_bluez5_device_factory;

View file

@ -1,6 +1,6 @@
v4l2_sources = ['v4l2.c',
'v4l2-device.c',
'v4l2-monitor.c',
'v4l2-udev.c',
'v4l2-source.c']
v4l2lib = shared_library('spa-v4l2',

View file

@ -1,4 +1,4 @@
/* Spa V4l2 Monitor
/* Spa V4l2 udev monitor
*
* Copyright © 2018 Wim Taymans
*
@ -37,19 +37,22 @@
#include <spa/utils/type.h>
#include <spa/utils/keys.h>
#include <spa/utils/names.h>
#include <spa/monitor/monitor.h>
#include <spa/monitor/device.h>
#include <spa/monitor/utils.h>
#define NAME "v4l2-monitor"
#define NAME "v4l2-udev"
struct impl {
struct spa_handle handle;
struct spa_monitor monitor;
struct spa_device device;
struct spa_log *log;
struct spa_loop *main_loop;
struct spa_callbacks callbacks;
struct spa_hook_list hooks;
uint64_t info_all;
struct spa_device_info info;
struct udev *udev;
struct udev_monitor *umonitor;
@ -172,20 +175,20 @@ static void unescape(const char *src, char *dst)
static int emit_object_info(struct impl *this, uint32_t id, struct udev_device *dev)
{
struct spa_monitor_object_info info;
struct spa_device_object_info info;
const char *str;
struct spa_dict_item items[20];
uint32_t n_items = 0;
info = SPA_MONITOR_OBJECT_INFO_INIT();
info = SPA_DEVICE_OBJECT_INFO_INIT();
info.type = SPA_TYPE_INTERFACE_Device;
info.factory_name = SPA_NAME_API_V4L2_DEVICE;
info.change_mask = SPA_MONITOR_OBJECT_CHANGE_MASK_FLAGS |
SPA_MONITOR_OBJECT_CHANGE_MASK_PROPS;
info.change_mask = SPA_DEVICE_OBJECT_CHANGE_MASK_FLAGS |
SPA_DEVICE_OBJECT_CHANGE_MASK_PROPS;
info.flags = 0;
items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_MONITOR_API,"udev");
items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_ENUM_API,"udev");
items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_API, "v4l2");
items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_API_V4L2_PATH, udev_device_get_devnode(dev));
@ -256,7 +259,7 @@ static int emit_object_info(struct impl *this, uint32_t id, struct udev_device *
items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_CAPABILITIES, str);
}
info.props = &SPA_DICT_INIT(items, n_items);
spa_monitor_call_object_info(&this->callbacks, id, &info);
spa_device_emit_object_info(&this->hooks, id, &info);
return 1;
}
@ -282,7 +285,7 @@ static void impl_on_fd_events(struct spa_source *source)
strcmp(action, "change") == 0) {
emit_object_info(this, id, dev);
} else {
spa_monitor_call_object_info(&this->callbacks, id, NULL);
spa_device_emit_object_info(&this->hooks, id, NULL);
}
udev_device_unref(dev);
}
@ -358,38 +361,68 @@ static int enum_devices(struct impl *this)
return 0;
}
static const struct spa_dict_item device_info_items[] = {
{ SPA_KEY_DEVICE_API, "udev" },
{ SPA_KEY_DEVICE_NICK, "v4l2-udev" },
{ SPA_KEY_API_UDEV_MATCH, "video4linux" },
};
static void emit_device_info(struct impl *this, bool full)
{
if (full)
this->info.change_mask = this->info_all;
if (this->info.change_mask) {
this->info.props = &SPA_DICT_INIT_ARRAY(device_info_items);
spa_device_emit_info(&this->hooks, &this->info);
this->info.change_mask = 0;
}
}
static void impl_hook_removed(struct spa_hook *hook)
{
struct impl *this = hook->priv;
if (spa_hook_list_is_empty(&this->hooks)) {
stop_monitor(this);
impl_udev_close(this);
}
}
static int
impl_monitor_set_callbacks(void *object,
const struct spa_monitor_callbacks *callbacks,
void *data)
impl_device_add_listener(void *object, struct spa_hook *listener,
const struct spa_device_events *events, void *data)
{
int res;
struct impl *this = object;
struct spa_hook_list save;
spa_return_val_if_fail(this != NULL, -EINVAL);
spa_return_val_if_fail(events != NULL, -EINVAL);
this->callbacks = SPA_CALLBACKS_INIT(callbacks, data);
if (callbacks) {
if ((res = impl_udev_open(this)) < 0)
return res;
spa_hook_list_isolate(&this->hooks, &save, listener, events, data);
emit_device_info(this, true);
if ((res = enum_devices(this)) < 0)
return res;
if ((res = start_monitor(this)) < 0)
return res;
} else {
stop_monitor(this);
impl_udev_close(this);
}
spa_hook_list_join(&this->hooks, &save);
listener->removed = impl_hook_removed;
listener->priv = this;
return 0;
}
static const struct spa_monitor_methods impl_monitor = {
SPA_VERSION_MONITOR_METHODS,
.set_callbacks = impl_monitor_set_callbacks,
static const struct spa_device_methods impl_device = {
SPA_VERSION_DEVICE_METHODS,
.add_listener = impl_device_add_listener,
};
static int impl_get_interface(struct spa_handle *handle, uint32_t type, void **interface)
@ -401,10 +434,13 @@ static int impl_get_interface(struct spa_handle *handle, uint32_t type, void **i
this = (struct impl *) handle;
if (type == SPA_TYPE_INTERFACE_Monitor)
*interface = &this->monitor;
else
switch (type) {
case SPA_TYPE_INTERFACE_Device:
*interface = &this->device;
break;
default:
return -ENOENT;
}
return 0;
}
@ -412,7 +448,8 @@ 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;
impl_monitor_set_callbacks(this, NULL, NULL);
stop_monitor(this);
impl_udev_close(this);
return 0;
}
@ -455,17 +492,23 @@ impl_init(const struct spa_handle_factory *factory,
spa_log_error(this->log, "a main-loop is needed");
return -EINVAL;
}
spa_hook_list_init(&this->hooks);
this->monitor.iface = SPA_INTERFACE_INIT(
SPA_TYPE_INTERFACE_Monitor,
SPA_VERSION_MONITOR,
&impl_monitor, this);
this->device.iface = SPA_INTERFACE_INIT(
SPA_TYPE_INTERFACE_Device,
SPA_VERSION_DEVICE,
&impl_device, this);
this->info = SPA_DEVICE_INFO_INIT();
this->info_all = SPA_DEVICE_CHANGE_MASK_FLAGS |
SPA_DEVICE_CHANGE_MASK_PROPS;
this->info.flags = 0;
return 0;
}
static const struct spa_interface_info impl_interfaces[] = {
{SPA_TYPE_INTERFACE_Monitor,},
{SPA_TYPE_INTERFACE_Device,},
};
static int
@ -485,9 +528,9 @@ impl_enum_interface_info(const struct spa_handle_factory *factory,
return 1;
}
const struct spa_handle_factory spa_v4l2_monitor_factory = {
const struct spa_handle_factory spa_v4l2_udev_factory = {
SPA_VERSION_HANDLE_FACTORY,
SPA_NAME_API_V4L2_MONITOR,
SPA_NAME_API_V4L2_ENUM_UDEV,
NULL,
impl_get_size,
impl_init,

View file

@ -27,7 +27,7 @@
#include <spa/support/plugin.h>
extern const struct spa_handle_factory spa_v4l2_source_factory;
extern const struct spa_handle_factory spa_v4l2_monitor_factory;
extern const struct spa_handle_factory spa_v4l2_udev_factory;
extern const struct spa_handle_factory spa_v4l2_device_factory;
SPA_EXPORT
@ -42,7 +42,7 @@ int spa_handle_factory_enum(const struct spa_handle_factory **factory,
*factory = &spa_v4l2_source_factory;
break;
case 1:
*factory = &spa_v4l2_monitor_factory;
*factory = &spa_v4l2_udev_factory;
break;
case 2:
*factory = &spa_v4l2_device_factory;

View file

@ -34,7 +34,6 @@
#include <spa/debug/types.h>
#include <spa/graph/graph.h>
#include <spa/monitor/device.h>
#include <spa/monitor/monitor.h>
#include <spa/node/command.h>
#include <spa/node/event.h>
#include <spa/node/io.h>

View file

@ -102,13 +102,14 @@ static void test_abi(void)
spa_assert(SPA_TYPE_LAST == 21);
spa_assert(SPA_TYPE_EVENT_START == 0x30000);
spa_assert(SPA_TYPE_EVENT_Monitor == 0x30001);
spa_assert(SPA_TYPE_EVENT_Device == 0x30001);
spa_assert(SPA_TYPE_EVENT_Node == 0x30002);
spa_assert(SPA_TYPE_EVENT_LAST == 0x30003);
spa_assert(SPA_TYPE_COMMAND_START == 0x40000);
spa_assert(SPA_TYPE_COMMAND_Node == 0x40001);
spa_assert(SPA_TYPE_COMMAND_LAST == 0x40002);
spa_assert(SPA_TYPE_COMMAND_Device == 0x40001);
spa_assert(SPA_TYPE_COMMAND_Node == 0x40002);
spa_assert(SPA_TYPE_COMMAND_LAST == 0x40003);
spa_assert(SPA_TYPE_OBJECT_START == 0x50000);
spa_assert(SPA_TYPE_OBJECT_PropInfo == 0x50001);

View file

@ -33,7 +33,7 @@
#include <spa/support/log-impl.h>
#include <spa/support/loop.h>
#include <spa/support/plugin.h>
#include <spa/monitor/monitor.h>
#include <spa/monitor/device.h>
#include <spa/debug/dict.h>
#include <spa/debug/pod.h>
@ -56,18 +56,17 @@ struct data {
};
static void inspect_info(struct data *data, const struct spa_monitor_object_info *info)
static void inspect_info(struct data *data, const struct spa_device_object_info *info)
{
spa_debug_dict(0, info->props);
}
static int on_monitor_info(void *_data, const struct spa_monitor_info *info)
static void on_device_info(void *_data, const struct spa_device_info *info)
{
spa_debug_dict(0, info->props);
return 0;
}
static int on_monitor_object_info(void *_data, uint32_t id, const struct spa_monitor_object_info *info)
static void on_device_object_info(void *_data, uint32_t id, const struct spa_device_object_info *info)
{
struct data *data = _data;
@ -78,7 +77,6 @@ static int on_monitor_object_info(void *_data, uint32_t id, const struct spa_mon
fprintf(stderr, "added/changed: %u\n", id);
inspect_info(data, info);
}
return 0;
}
static int do_add_source(void *object, struct spa_source *source)
@ -97,15 +95,17 @@ static const struct spa_loop_methods impl_loop = {
.add_source = do_add_source,
};
static const struct spa_monitor_callbacks impl_callbacks = {
SPA_VERSION_MONITOR_CALLBACKS,
.info = on_monitor_info,
.object_info = on_monitor_object_info,
static const struct spa_device_events impl_device_events = {
SPA_VERSION_DEVICE_EVENTS,
.info = on_device_info,
.object_info = on_device_object_info,
};
static void handle_monitor(struct data *data, struct spa_monitor *monitor)
static void handle_device(struct data *data, struct spa_device *device)
{
spa_monitor_set_callbacks(monitor, &impl_callbacks, data);
struct spa_hook listener;
spa_device_add_listener(device, &listener, &impl_device_events, data);
while (true) {
int r;
@ -129,7 +129,7 @@ static void handle_monitor(struct data *data, struct spa_monitor *monitor)
break;
}
if (r == 0) {
fprintf(stderr, "monitor %p: select timeout", monitor);
fprintf(stderr, "device %p: select timeout", device);
break;
}
@ -139,6 +139,7 @@ static void handle_monitor(struct data *data, struct spa_monitor *monitor)
p->func(p);
}
}
spa_hook_remove(&listener);
}
int main(int argc, char *argv[])
@ -193,7 +194,7 @@ int main(int argc, char *argv[])
break;
}
if (info->type == SPA_TYPE_INTERFACE_Monitor) {
if (info->type == SPA_TYPE_INTERFACE_Device) {
struct spa_handle *handle;
void *interface;
@ -206,12 +207,12 @@ int main(int argc, char *argv[])
}
if ((res =
spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_Monitor,
spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_Device,
&interface)) < 0) {
printf("can't get interface: %s\n", strerror(res));
continue;
}
handle_monitor(&data, interface);
handle_device(&data, interface);
}
}
}

View file

@ -11,11 +11,12 @@ add-spa-lib api.vulkan.* vulkan/libspa-vulkan
add-spa-lib api.jack.* jack/libspa-jack
#load-module libpipewire-module-spa-device api.jack.device
#load-module libpipewire-module-spa-device api.alsa.enum.udev
load-module libpipewire-module-spa-node api.alsa.midi.source node.name=MIDI-Bridge
load-module libpipewire-module-rtkit
load-module libpipewire-module-protocol-native
load-module libpipewire-module-spa-node-factory
load-module libpipewire-module-spa-node api.vulkan.compute.source node.name=my-compute-source
#load-module libpipewire-module-spa-node api.vulkan.compute.source node.name=my-compute-source
#load-module libpipewire-module-spa-node videotestsrc/libspa-videotestsrc videotestsrc videotestsrc Spa:POD:Object:Props:patternType=Spa:POD:Object:Props:patternType:snow
load-module libpipewire-module-client-node
load-module libpipewire-module-client-device

View file

@ -221,7 +221,7 @@ static struct alsa_object *alsa_find_object(struct monitor *monitor, uint32_t id
}
static void alsa_update_object(struct monitor *monitor, struct alsa_object *obj,
const struct spa_monitor_object_info *info)
const struct spa_device_object_info *info)
{
pw_log_debug("update object %u", obj->id);
spa_debug_dict(0, info->props);
@ -306,7 +306,7 @@ static int update_device_props(struct alsa_object *obj)
static struct alsa_object *alsa_create_object(struct monitor *monitor, uint32_t id,
const struct spa_monitor_object_info *info)
const struct spa_device_object_info *info)
{
struct impl *impl = monitor->impl;
struct pw_core *core = impl->core;
@ -384,8 +384,8 @@ static void alsa_remove_object(struct monitor *monitor, struct alsa_object *obj)
free(obj);
}
static int alsa_monitor_object_info(void *data, uint32_t id,
const struct spa_monitor_object_info *info)
static void alsa_udev_object_info(void *data, uint32_t id,
const struct spa_device_object_info *info)
{
struct monitor *monitor = data;
struct alsa_object *obj;
@ -394,21 +394,20 @@ static int alsa_monitor_object_info(void *data, uint32_t id,
if (info == NULL) {
if (obj == NULL)
return -ENODEV;
return;
alsa_remove_object(monitor, obj);
} else if (obj == NULL) {
if ((obj = alsa_create_object(monitor, id, info)) == NULL)
return -ENOMEM;
return;
} else {
alsa_update_object(monitor, obj, info);
}
return 0;
}
static const struct spa_monitor_callbacks alsa_monitor_callbacks =
static const struct spa_device_events alsa_udev_events =
{
SPA_VERSION_MONITOR_CALLBACKS,
.object_info = alsa_monitor_object_info,
SPA_VERSION_DEVICE_EVENTS,
.object_info = alsa_udev_object_info,
};
static int alsa_start_monitor(struct impl *impl, struct monitor *monitor)
@ -418,14 +417,14 @@ static int alsa_start_monitor(struct impl *impl, struct monitor *monitor)
int res;
void *iface;
handle = pw_core_load_spa_handle(core, SPA_NAME_API_ALSA_MONITOR, NULL);
handle = pw_core_load_spa_handle(core, SPA_NAME_API_ALSA_ENUM_UDEV, NULL);
if (handle == NULL) {
res = -errno;
goto out;
}
if ((res = spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_Monitor, &iface)) < 0) {
pw_log_error("can't get MONITOR interface: %d", res);
if ((res = spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_Device, &iface)) < 0) {
pw_log_error("can't get udev Device interface: %d", res);
goto out_unload;
}
@ -434,7 +433,7 @@ static int alsa_start_monitor(struct impl *impl, struct monitor *monitor)
monitor->monitor = iface;
spa_list_init(&monitor->object_list);
spa_monitor_set_callbacks(monitor->monitor, &alsa_monitor_callbacks, monitor);
spa_device_add_listener(monitor->monitor, &monitor->listener, &alsa_udev_events, monitor);
return 0;

View file

@ -212,14 +212,14 @@ static struct bluez5_object *bluez5_find_object(struct monitor *monitor, uint32_
}
static void bluez5_update_object(struct monitor *monitor, struct bluez5_object *obj,
const struct spa_monitor_object_info *info)
const struct spa_device_object_info *info)
{
pw_log_debug("update object %u", obj->id);
spa_debug_dict(0, info->props);
}
static struct bluez5_object *bluez5_create_object(struct monitor *monitor, uint32_t id,
const struct spa_monitor_object_info *info)
const struct spa_device_object_info *info)
{
struct impl *impl = monitor->impl;
struct pw_core *core = impl->core;
@ -303,8 +303,8 @@ static void bluez5_remove_object(struct monitor *monitor, struct bluez5_object *
free(obj);
}
static int bluez5_monitor_object_info(void *data, uint32_t id,
const struct spa_monitor_object_info *info)
static void bluez5_enum_object_info(void *data, uint32_t id,
const struct spa_device_object_info *info)
{
struct monitor *monitor = data;
struct bluez5_object *obj;
@ -313,21 +313,20 @@ static int bluez5_monitor_object_info(void *data, uint32_t id,
if (info == NULL) {
if (obj == NULL)
return -ENODEV;
return;
bluez5_remove_object(monitor, obj);
} else if (obj == NULL) {
if ((obj = bluez5_create_object(monitor, id, info)) == NULL)
return -ENOMEM;
return;
} else {
bluez5_update_object(monitor, obj, info);
}
return 0;
}
static const struct spa_monitor_callbacks bluez5_monitor_callbacks =
static const struct spa_device_events bluez5_enum_callbacks =
{
SPA_VERSION_MONITOR_CALLBACKS,
.object_info = bluez5_monitor_object_info,
SPA_VERSION_DEVICE_EVENTS,
.object_info = bluez5_enum_object_info,
};
static int bluez5_start_monitor(struct impl *impl, struct monitor *monitor)
@ -337,14 +336,14 @@ static int bluez5_start_monitor(struct impl *impl, struct monitor *monitor)
int res;
void *iface;
handle = pw_core_load_spa_handle(core, SPA_NAME_API_BLUEZ5_MONITOR, NULL);
handle = pw_core_load_spa_handle(core, SPA_NAME_API_BLUEZ5_ENUM_DBUS, NULL);
if (handle == NULL) {
res = -errno;
goto out;
}
if ((res = spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_Monitor, &iface)) < 0) {
pw_log_error("can't get MONITOR interface: %d", res);
if ((res = spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_Device, &iface)) < 0) {
pw_log_error("can't get Device interface: %d", res);
goto out_unload;
}
@ -353,7 +352,8 @@ static int bluez5_start_monitor(struct impl *impl, struct monitor *monitor)
monitor->monitor = iface;
spa_list_init(&monitor->object_list);
spa_monitor_set_callbacks(monitor->monitor, &bluez5_monitor_callbacks, monitor);
spa_device_add_listener(monitor->monitor, &monitor->listener,
&bluez5_enum_callbacks, monitor);
return 0;

View file

@ -64,7 +64,7 @@ struct object {
struct spa_handle *handle;
struct pw_proxy *proxy;
struct spa_device *device;
struct spa_hook device_listener;
struct spa_hook listener;
struct spa_list node_list;
};
@ -78,11 +78,11 @@ struct impl {
struct pw_remote *remote;
struct spa_hook remote_listener;
struct spa_handle *monitor_handle;
struct spa_monitor *monitor;
struct spa_hook monitor_listener;
struct spa_handle *handle;
struct spa_device *device;
struct spa_hook listener;
struct spa_list object_list;
struct spa_list device_list;
};
static struct node *find_node(struct object *obj, uint32_t id)
@ -199,7 +199,7 @@ static struct object *find_object(struct impl *impl, uint32_t id)
{
struct object *obj;
spa_list_for_each(obj, &impl->object_list, link) {
spa_list_for_each(obj, &impl->device_list, link) {
if (obj->id == id)
return obj;
}
@ -207,14 +207,14 @@ static struct object *find_object(struct impl *impl, uint32_t id)
}
static void update_object(struct impl *impl, struct object *obj,
const struct spa_monitor_object_info *info)
const struct spa_device_object_info *info)
{
pw_log_debug("update object %u", obj->id);
spa_debug_dict(0, info->props);
}
static struct object *create_object(struct impl *impl, uint32_t id,
const struct spa_monitor_object_info *info)
const struct spa_device_object_info *info)
{
struct pw_core *core = impl->core;
struct object *obj;
@ -256,9 +256,9 @@ static struct object *create_object(struct impl *impl, uint32_t id,
spa_list_init(&obj->node_list);
spa_device_add_listener(obj->device,
&obj->device_listener, &device_events, obj);
&obj->listener, &device_events, obj);
spa_list_append(&impl->object_list, &obj->link);
spa_list_append(&impl->device_list, &obj->link);
update_object(impl, obj, info);
@ -276,14 +276,14 @@ static void remove_object(struct impl *impl, struct object *obj)
{
pw_log_debug("remove object %u", obj->id);
spa_list_remove(&obj->link);
spa_hook_remove(&obj->device_listener);
spa_hook_remove(&obj->listener);
pw_proxy_destroy(obj->proxy);
free(obj->handle);
free(obj);
}
static int monitor_object_info(void *data, uint32_t id,
const struct spa_monitor_object_info *info)
static void dbus_device_object_info(void *data, uint32_t id,
const struct spa_device_object_info *info)
{
struct impl *impl = data;
struct object *obj;
@ -292,21 +292,20 @@ static int monitor_object_info(void *data, uint32_t id,
if (info == NULL) {
if (obj == NULL)
return -ENODEV;
return;
remove_object(impl, obj);
} else if (obj == NULL) {
if ((obj = create_object(impl, id, info)) == NULL)
return -ENOMEM;
return;
} else {
update_object(impl, obj, info);
}
return 0;
}
static const struct spa_monitor_callbacks monitor_callbacks =
static const struct spa_device_events dbus_device_events =
{
SPA_VERSION_MONITOR_CALLBACKS,
.object_info = monitor_object_info,
SPA_VERSION_DEVICE_EVENTS,
.object_info = dbus_device_object_info,
};
static int start_monitor(struct impl *impl)
@ -315,21 +314,21 @@ static int start_monitor(struct impl *impl)
int res;
void *iface;
handle = pw_core_load_spa_handle(impl->core, SPA_NAME_API_BLUEZ5_MONITOR, NULL);
handle = pw_core_load_spa_handle(impl->core, SPA_NAME_API_BLUEZ5_ENUM_DBUS, NULL);
if (handle == NULL) {
res = -errno;
goto out;
}
if ((res = spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_Monitor, &iface)) < 0) {
if ((res = spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_Device, &iface)) < 0) {
pw_log_error("can't get MONITOR interface: %d", res);
goto out_unload;
}
impl->monitor_handle = handle;
impl->monitor = iface;
impl->handle = handle;
impl->device = iface;
spa_monitor_set_callbacks(impl->monitor, &monitor_callbacks, impl);
spa_device_add_listener(impl->device, &impl->listener, &dbus_device_events, impl);
return 0;
@ -390,7 +389,7 @@ int main(int argc, char *argv[])
clock_gettime(CLOCK_MONOTONIC, &impl.now);
spa_list_init(&impl.object_list);
spa_list_init(&impl.device_list);
pw_remote_add_listener(impl.remote,
&impl.remote_listener,

View file

@ -55,7 +55,9 @@ struct monitor {
struct impl *impl;
struct spa_handle *handle;
struct spa_monitor *monitor;
struct spa_device *monitor;
struct spa_hook listener;
struct spa_list object_list;
};

View file

@ -206,7 +206,7 @@ static struct v4l2_object *v4l2_find_object(struct monitor *monitor, uint32_t id
}
static void v4l2_update_object(struct monitor *monitor, struct v4l2_object *obj,
const struct spa_monitor_object_info *info)
const struct spa_device_object_info *info)
{
pw_log_debug("update object %u", obj->id);
spa_debug_dict(0, info->props);
@ -240,7 +240,7 @@ static int v4l2_update_device_props(struct v4l2_object *obj)
}
static struct v4l2_object *v4l2_create_object(struct monitor *monitor, uint32_t id,
const struct spa_monitor_object_info *info)
const struct spa_device_object_info *info)
{
struct impl *impl = monitor->impl;
struct pw_core *core = impl->core;
@ -318,8 +318,8 @@ static void v4l2_remove_object(struct monitor *monitor, struct v4l2_object *obj)
free(obj);
}
static int v4l2_monitor_object_info(void *data, uint32_t id,
const struct spa_monitor_object_info *info)
static void v4l2_udev_object_info(void *data, uint32_t id,
const struct spa_device_object_info *info)
{
struct monitor *monitor = data;
struct v4l2_object *obj;
@ -328,21 +328,20 @@ static int v4l2_monitor_object_info(void *data, uint32_t id,
if (info == NULL) {
if (obj == NULL)
return -ENODEV;
return;
v4l2_remove_object(monitor, obj);
} else if (obj == NULL) {
if ((obj = v4l2_create_object(monitor, id, info)) == NULL)
return -ENOMEM;
return;
} else {
v4l2_update_object(monitor, obj, info);
}
return 0;
}
static const struct spa_monitor_callbacks v4l2_monitor_callbacks =
static const struct spa_device_events v4l2_udev_callbacks =
{
SPA_VERSION_MONITOR_CALLBACKS,
.object_info = v4l2_monitor_object_info,
SPA_VERSION_DEVICE_EVENTS,
.object_info = v4l2_udev_object_info,
};
static int v4l2_start_monitor(struct impl *impl, struct monitor *monitor)
@ -352,13 +351,13 @@ static int v4l2_start_monitor(struct impl *impl, struct monitor *monitor)
int res;
void *iface;
handle = pw_core_load_spa_handle(core, SPA_NAME_API_V4L2_MONITOR, NULL);
handle = pw_core_load_spa_handle(core, SPA_NAME_API_V4L2_ENUM_UDEV, NULL);
if (handle == NULL) {
res = -errno;
goto out;
}
if ((res = spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_Monitor, &iface)) < 0) {
if ((res = spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_Device, &iface)) < 0) {
pw_log_error("can't get MONITOR interface: %d", res);
goto out_unload;
}
@ -368,7 +367,8 @@ static int v4l2_start_monitor(struct impl *impl, struct monitor *monitor)
monitor->monitor = iface;
spa_list_init(&monitor->object_list);
spa_monitor_set_callbacks(monitor->monitor, &v4l2_monitor_callbacks, monitor);
spa_device_add_listener(monitor->monitor, &monitor->listener,
&v4l2_udev_callbacks, monitor);
return 0;

View file

@ -3,15 +3,6 @@ pipewire_module_spa_c_args = [
'-D_GNU_SOURCE',
]
pipewire_module_spa_monitor = shared_library('pipewire-module-spa-monitor',
[ 'module-monitor.c', 'spa-monitor.c', 'spa-node.c', 'spa-device.c' ],
c_args : pipewire_module_spa_c_args,
include_directories : [configinc, spa_inc],
install : true,
install_dir : modules_install_dir,
dependencies : [mathlib, dl_lib, pipewire_dep],
)
pipewire_module_spa_node = shared_library('pipewire-module-spa-node',
[ 'module-node.c', 'spa-node.c' ],
c_args : pipewire_module_spa_c_args,

View file

@ -35,7 +35,6 @@
#include <pipewire/utils.h>
#include <pipewire/keys.h>
#include "spa-monitor.h"
#include "spa-device.h"
#define MODULE_USAGE "<factory> [key=value ...]"

View file

@ -1,123 +0,0 @@
/* PipeWire
* Copyright © 2016 Axis Communications <dev-gstreamer@axis.com>
* @author Linus Svensson <linus.svensson@axis.com>
* 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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <errno.h>
#include <getopt.h>
#include <limits.h>
#include <pipewire/utils.h>
#include <pipewire/log.h>
#include <pipewire/core.h>
#include <pipewire/module.h>
#include <pipewire/keys.h>
#include "spa-monitor.h"
#define MODULE_USAGE "<factory> <name> [key=value ...]"
static const struct spa_dict_item module_props[] = {
{ PW_KEY_MODULE_AUTHOR, "Wim Taymans <wim.taymans@gmail.com>" },
{ PW_KEY_MODULE_DESCRIPTION, "Manage SPA monitors" },
{ PW_KEY_MODULE_USAGE, MODULE_USAGE },
{ PW_KEY_MODULE_VERSION, PACKAGE_VERSION },
};
struct data {
struct pw_spa_monitor *monitor;
struct spa_hook module_listener;
};
static void module_destroy(void *data)
{
struct data *d = data;
spa_hook_remove(&d->module_listener);
pw_spa_monitor_destroy(d->monitor);
}
const struct pw_module_events module_events = {
PW_VERSION_MODULE_EVENTS,
.destroy = module_destroy,
};
SPA_EXPORT
int pipewire__module_init(struct pw_module *module, const char *args)
{
struct pw_core *core = pw_module_get_core(module);
struct pw_properties *props = NULL;
char **argv = NULL;
int n_tokens, res;
struct pw_spa_monitor *monitor;
struct data *data;
if (args == NULL)
goto error_arguments;
argv = pw_split_strv(args, " \t", INT_MAX, &n_tokens);
if (n_tokens < 2)
goto error_arguments;
if (n_tokens == 3) {
props = pw_properties_new_string(argv[2]);
if (props == NULL) {
res = -errno;
goto error_exit_cleanup;
}
}
monitor = pw_spa_monitor_load(core,
argv[0], argv[1],
props,
sizeof(struct data));
if (monitor == NULL) {
res = -errno;
goto error_exit_cleanup;
}
pw_free_strv(argv);
data = monitor->user_data;
data->monitor = monitor;
pw_module_add_listener(module, &data->module_listener, &module_events, data);
pw_module_update_properties(module, &SPA_DICT_INIT_ARRAY(module_props));
return 0;
error_arguments:
res = -EINVAL;
pw_log_error("usage: module-spa-monitor " MODULE_USAGE);
goto error_exit_cleanup;
error_exit_cleanup:
if (argv)
pw_free_strv(argv);
return res;
}

View file

@ -37,7 +37,6 @@
#include <pipewire/module.h>
#include <pipewire/utils.h>
#include "spa-monitor.h"
#include "spa-node.h"
#define MODULE_USAGE "<factory> [key=value ...]"

View file

@ -1,336 +0,0 @@
/* PipeWire
*
* 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 <stdio.h>
#include <dlfcn.h>
#include <errno.h>
#include <poll.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <time.h>
#include <spa/node/node.h>
#include <spa/monitor/monitor.h>
#include <spa/pod/parser.h>
#include <spa/debug/pod.h>
#include <pipewire/log.h>
#include <pipewire/type.h>
#include <pipewire/node.h>
#include <pipewire/device.h>
#include <pipewire/keys.h>
#include <pipewire/pipewire.h>
#include "spa-monitor.h"
#include "spa-device.h"
struct monitor_object {
uint32_t id;
char *name;
struct spa_list link;
struct spa_handle *handle;
uint32_t type;
void *object;
struct spa_hook object_listener;
};
struct impl {
struct pw_spa_monitor this;
struct pw_core *core;
struct spa_list item_list;
};
static void device_free(void *data)
{
struct monitor_object *obj = data;
spa_hook_remove(&obj->object_listener);
spa_list_remove(&obj->link);
pw_unload_spa_handle(obj->handle);
free(obj);
}
static const struct pw_device_events device_events = {
PW_VERSION_DEVICE_EVENTS,
.free = device_free
};
static struct monitor_object *add_object(struct pw_spa_monitor *this, uint32_t id,
const struct spa_monitor_object_info *info, uint64_t now)
{
struct impl *impl = SPA_CONTAINER_OF(this, struct impl, this);
struct pw_core *core = impl->core;
int res;
struct spa_handle *handle;
struct monitor_object *obj;
const char *name, *str;
void *iface;
struct pw_properties *props = NULL;
if (info->props)
props = pw_properties_new_dict(info->props);
else
props = pw_properties_new(NULL, NULL);
if (props == NULL)
return NULL;
if ((name = pw_properties_get(props, PW_KEY_DEVICE_NAME)) == NULL)
name = "unknown";
pw_log_debug("monitor %p: add: \"%s\" (%u)", this, name, id);
if ((str = pw_properties_get(props, PW_KEY_DEVICE_FORM_FACTOR)) != NULL)
if (strcmp(str, "internal") == 0)
now = 0;
if (now != 0 && pw_properties_get(props, PW_KEY_DEVICE_PLUGGED) == NULL)
pw_properties_setf(props, PW_KEY_DEVICE_PLUGGED, "%"PRIu64, now);
handle = pw_core_load_spa_handle(core, info->factory_name,
&props->dict);
if (handle == NULL) {
res = -errno;
pw_log_error("can't make factory instance: %m");
goto error_exit_free_props;
}
if ((res = spa_handle_get_interface(handle, info->type, &iface)) < 0) {
pw_log_error("can't get %d interface: %s", info->type, spa_strerror(res));
goto error_exit_free_handle;
}
obj = calloc(1, sizeof(struct monitor_object));
if (obj == NULL) {
res = -errno;
goto error_exit_free_handle;
}
obj->id = id;
obj->name = strdup(name);
obj->handle = handle;
obj->type = info->type;
switch (obj->type) {
case SPA_TYPE_INTERFACE_Device:
{
struct pw_device *device;
device = pw_spa_device_new(core,
0, iface, handle, props, 0);
pw_device_add_listener(device, &obj->object_listener,
&device_events, obj);
obj->object = device;
break;
}
default:
res = -ENOTSUP;
pw_log_error("interface %d not implemented", obj->type);
goto error_exit_free_object;
}
spa_list_append(&impl->item_list, &obj->link);
return obj;
error_exit_free_object:
free(obj->name);
free(obj);
error_exit_free_handle:
pw_unload_spa_handle(handle);
error_exit_free_props:
pw_properties_free(props);
errno = -res;
return NULL;
}
static struct monitor_object *find_object(struct pw_spa_monitor *this, uint32_t id)
{
struct impl *impl = SPA_CONTAINER_OF(this, struct impl, this);
struct monitor_object *obj;
spa_list_for_each(obj, &impl->item_list, link) {
if (obj->id == id) {
return obj;
}
}
return NULL;
}
void destroy_object(struct monitor_object *obj)
{
switch (obj->type) {
case SPA_TYPE_INTERFACE_Node:
pw_node_destroy(obj->object);
break;
case SPA_TYPE_INTERFACE_Device:
pw_device_destroy(obj->object);
break;
default:
break;
}
}
static void change_object(struct pw_spa_monitor *this, struct monitor_object *obj,
const struct spa_monitor_object_info *info, uint64_t now)
{
pw_log_debug("monitor %p: change: \"%s\" (%u)", this, obj->name, obj->id);
}
static int on_monitor_object_info(void *data, uint32_t id,
const struct spa_monitor_object_info *info)
{
struct impl *impl = data;
struct pw_spa_monitor *this = &impl->this;
struct timespec now;
uint64_t now_nsec;
struct monitor_object *obj;
clock_gettime(CLOCK_MONOTONIC, &now);
now_nsec = SPA_TIMESPEC_TO_NSEC(&now);
obj = find_object(this, id);
if (info == NULL) {
if (obj == NULL)
return -ENODEV;
pw_log_debug("monitor %p: remove: (%s) %u", this, obj->name, id);
destroy_object(obj);
} else if (obj == NULL) {
obj = add_object(this, id, info, now_nsec);
if (obj == NULL)
return -errno;
} else {
change_object(this, obj, info, now_nsec);
}
return 0;
}
static void update_monitor(struct pw_core *core, const char *name)
{
const char *monitors;
struct spa_dict_item item;
const struct pw_properties *props;
struct spa_dict dict = SPA_DICT_INIT(&item, 1);
props = pw_core_get_properties(core);
if (props)
monitors = pw_properties_get(props, PW_KEY_CORE_MONITORS);
else
monitors = NULL;
item.key = PW_KEY_CORE_MONITORS;
if (monitors == NULL)
item.value = name;
else
asprintf((char **) &item.value, "%s,%s", monitors, name);
pw_core_update_properties(core, &dict);
if (monitors != NULL)
free((void *) item.value);
}
static const struct spa_monitor_callbacks callbacks = {
SPA_VERSION_MONITOR_CALLBACKS,
.object_info = on_monitor_object_info,
};
struct pw_spa_monitor *pw_spa_monitor_load(struct pw_core *core,
const char *factory_name,
const char *system_name,
struct pw_properties *properties,
size_t user_data_size)
{
struct impl *impl;
struct pw_spa_monitor *this;
struct spa_handle *handle;
int res;
void *iface;
handle = pw_core_load_spa_handle(core,
factory_name,
properties ? &properties->dict : NULL);
if (handle == NULL) {
res = -errno;
goto error_exit;
}
if ((res = spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_Monitor, &iface)) < 0) {
pw_log_error("can't get MONITOR interface: %s", spa_strerror(res));
goto error_exit_unload;
}
impl = calloc(1, sizeof(struct impl) + user_data_size);
if (impl == NULL) {
res = -errno;
goto error_exit_unload;
}
impl->core = core;
spa_list_init(&impl->item_list);
this = &impl->this;
this->monitor = iface;
this->factory_name = strdup(factory_name);
this->system_name = strdup(system_name);
this->handle = handle;
this->properties = properties;
if (user_data_size > 0)
this->user_data = SPA_MEMBER(impl, sizeof(struct impl), void);
update_monitor(core, this->system_name);
spa_monitor_set_callbacks(this->monitor, &callbacks, impl);
return this;
error_exit_unload:
pw_unload_spa_handle(handle);
error_exit:
errno = -res;
return NULL;
}
void pw_spa_monitor_destroy(struct pw_spa_monitor *monitor)
{
struct impl *impl = SPA_CONTAINER_OF(monitor, struct impl, this);
struct monitor_object *obj, *tmp;
pw_log_debug("spa-monitor %p: destroy", impl);
spa_list_for_each_safe(obj, tmp, &impl->item_list, link)
destroy_object(obj);
pw_unload_spa_handle(monitor->handle);
free(monitor->factory_name);
free(monitor->system_name);
if (monitor->properties)
pw_properties_free(monitor->properties);
free(impl);
}

View file

@ -1,60 +0,0 @@
/* PipeWire
*
* 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.
*/
#ifndef PIPEWIRE_SPA_MONITOR_H
#define PIPEWIRE_SPA_MONITOR_H
#include <spa/monitor/monitor.h>
#include <pipewire/core.h>
#ifdef __cplusplus
extern "C" {
#endif
struct pw_spa_monitor {
struct spa_monitor *monitor;
char *factory_name;
char *system_name;
struct spa_handle *handle;
struct pw_properties *properties;
void *user_data;
};
struct pw_spa_monitor *
pw_spa_monitor_load(struct pw_core *core,
const char *factory_name,
const char *system_name,
struct pw_properties *properties,
size_t user_data_size);
void
pw_spa_monitor_destroy(struct pw_spa_monitor *monitor);
#ifdef __cplusplus
}
#endif
#endif /* PIPEWIRE_SPA_MONITOR_H */

View file

@ -409,7 +409,7 @@ int pw_client_register(struct pw_client *client,
client->registered = true;
client->info.id = client->global->id;
pw_properties_setf(client->properties, PW_KEY_CLIENT_ID, "%d", client->info.id);
pw_properties_setf(client->properties, PW_KEY_OBJECT_ID, "%d", client->info.id);
client->info.props = &client->properties->dict;
pw_global_add_listener(client->global, &client->global_listener, &global_events, client);

View file

@ -590,7 +590,7 @@ struct pw_core *pw_core_new(struct pw_loop *main_loop,
goto error_free_loop;
}
this->info.id = this->global->id;
pw_properties_setf(this->properties, PW_KEY_CORE_ID, "%d", this->info.id);
pw_properties_setf(this->properties, PW_KEY_OBJECT_ID, "%d", this->info.id);
this->info.props = &this->properties->dict;
pw_global_add_listener(this->global, &this->global_listener, &global_events, this);

View file

@ -65,14 +65,52 @@ struct resource_data {
struct spa_hook listener;
};
struct node_data {
struct object_data {
struct spa_list link;
struct pw_node *node;
struct spa_handle *handle;
uint32_t id;
struct spa_hook node_listener;
uint32_t type;
struct spa_handle *handle;
void *object;
struct spa_hook listener;
};
static void object_destroy(struct object_data *od)
{
switch (od->type) {
case SPA_TYPE_INTERFACE_Node:
pw_node_destroy(od->object);
break;
case SPA_TYPE_INTERFACE_Device:
pw_device_destroy(od->object);
break;
}
}
static void object_update(struct object_data *od, const struct spa_dict *props)
{
switch (od->type) {
case SPA_TYPE_INTERFACE_Node:
pw_node_update_properties(od->object, props);
break;
case SPA_TYPE_INTERFACE_Device:
pw_device_update_properties(od->object, props);
break;
}
}
static void object_register(struct object_data *od)
{
switch (od->type) {
case SPA_TYPE_INTERFACE_Node:
pw_node_register(od->object, NULL);
pw_node_set_active(od->object, true);
break;
case SPA_TYPE_INTERFACE_Device:
pw_device_register(od->object, NULL);
break;
}
}
static void check_properties(struct pw_device *device)
{
const char *str;
@ -116,7 +154,7 @@ struct pw_device *pw_device_new(struct pw_core *core,
this->info.params = this->params;
spa_hook_list_init(&this->listener_list);
spa_list_init(&this->node_list);
spa_list_init(&this->object_list);
if (user_data_size > 0)
this->user_data = SPA_MEMBER(this, sizeof(struct impl), void);
@ -137,13 +175,13 @@ error_cleanup:
SPA_EXPORT
void pw_device_destroy(struct pw_device *device)
{
struct node_data *nd;
struct object_data *od;
pw_log_debug(NAME" %p: destroy", device);
pw_device_emit_destroy(device);
spa_list_consume(nd, &device->node_list, link)
pw_node_destroy(nd->node);
spa_list_consume(od, &device->object_list, link)
object_destroy(od);
if (device->registered)
spa_list_remove(&device->link);
@ -366,7 +404,7 @@ int pw_device_register(struct pw_device *device,
struct pw_properties *properties)
{
struct pw_core *core = device->core;
struct node_data *nd;
struct object_data *od;
const char *keys[] = {
PW_KEY_MODULE_ID,
PW_KEY_CLIENT_ID,
@ -400,16 +438,15 @@ int pw_device_register(struct pw_device *device,
device->registered = true;
device->info.id = device->global->id;
pw_properties_setf(device->properties, PW_KEY_DEVICE_ID, "%d", device->info.id);
pw_properties_setf(device->properties, PW_KEY_OBJECT_ID, "%d", device->info.id);
device->info.props = &device->properties->dict;
pw_global_add_listener(device->global, &device->global_listener, &global_events, device);
pw_global_register(device->global);
spa_list_for_each(nd, &device->node_list, link) {
pw_node_register(nd->node, NULL);
pw_node_set_active(nd->node, true);
}
spa_list_for_each(od, &device->object_list, link)
object_register(od);
return 0;
error_existed:
@ -418,22 +455,28 @@ error_existed:
return -EEXIST;
}
static void node_destroy(void *data)
static void on_object_destroy(void *data)
{
struct node_data *nd = data;
spa_list_remove(&nd->link);
struct object_data *od = data;
spa_list_remove(&od->link);
}
static void node_free(void *data)
static void on_object_free(void *data)
{
struct node_data *nd = data;
pw_unload_spa_handle(nd->handle);
struct object_data *od = data;
pw_unload_spa_handle(od->handle);
}
static const struct pw_node_events node_events = {
static const struct pw_node_events node_object_events = {
PW_VERSION_NODE_EVENTS,
.destroy = node_destroy,
.free = node_free,
.destroy = on_object_destroy,
.free = on_object_free,
};
static const struct pw_device_events device_object_events = {
PW_VERSION_DEVICE_EVENTS,
.destroy = on_object_destroy,
.free = on_object_free,
};
static void emit_info_changed(struct pw_device *device)
@ -481,21 +524,16 @@ static void device_info(void *data, const struct spa_device_info *info)
emit_info_changed(device);
}
static void device_add(struct pw_device *device, uint32_t id,
static void device_add_object(struct pw_device *device, uint32_t id,
const struct spa_device_object_info *info)
{
struct pw_core *core = device->core;
struct spa_handle *handle;
struct pw_node *node;
struct node_data *nd;
struct pw_properties *props;
int res;
void *iface;
struct object_data *od = NULL;
if (info->type != SPA_TYPE_INTERFACE_Node) {
pw_log_warn(NAME" %p: unknown type %d", device, info->type);
return;
}
if (info->factory_name == NULL) {
pw_log_warn(NAME" %p: missing factory name", device);
return;
@ -518,32 +556,52 @@ static void device_add(struct pw_device *device, uint32_t id,
if (info->props && props)
pw_properties_update(props, info->props);
node = pw_node_new(core,
props,
sizeof(struct node_data));
nd = pw_node_get_user_data(node);
nd->id = id;
nd->node = node;
nd->handle = handle;
pw_node_add_listener(node, &nd->node_listener, &node_events, nd);
spa_list_append(&device->node_list, &nd->link);
switch (info->type) {
case SPA_TYPE_INTERFACE_Node:
{
struct pw_node *node;
node = pw_node_new(core, props, sizeof(struct object_data));
od = pw_node_get_user_data(node);
od->object = node;
pw_node_add_listener(node, &od->listener, &node_object_events, od);
pw_node_set_implementation(node, iface);
break;
}
case SPA_TYPE_INTERFACE_Device:
{
struct pw_device *dev;
dev = pw_device_new(core, props, sizeof(struct object_data));
if (device->global) {
pw_node_register(node, NULL);
pw_node_set_active(node, true);
od = pw_device_get_user_data(dev);
od->object = dev;
pw_device_add_listener(dev, &od->listener, &device_object_events, od);
pw_device_set_implementation(dev, iface);
break;
}
default:
pw_log_warn(NAME" %p: unknown type %d", device, info->type);
pw_properties_free(props);
break;
}
if (od) {
od->id = id;
od->type = info->type;
od->handle = handle;
spa_list_append(&device->object_list, &od->link);
if (device->global)
object_register(od);
}
return;
}
static struct node_data *find_node(struct pw_device *device, uint32_t id)
static struct object_data *find_object(struct pw_device *device, uint32_t id)
{
struct node_data *nd;
spa_list_for_each(nd, &device->node_list, link) {
if (nd->id == id)
return nd;
struct object_data *od;
spa_list_for_each(od, &device->object_list, link) {
if (od->id == id)
return od;
}
return NULL;
}
@ -552,25 +610,25 @@ 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;
struct object_data *od;
nd = find_node(device, id);
od = find_object(device, id);
if (info == NULL) {
if (nd) {
if (od) {
pw_log_debug(NAME" %p: remove node %d", device, id);
pw_node_destroy(nd->node);
object_destroy(od);
}
else {
pw_log_warn(NAME" %p: unknown node %d", device, id);
}
}
else if (nd != NULL) {
else if (od != NULL) {
if (info->change_mask & SPA_DEVICE_OBJECT_CHANGE_MASK_PROPS)
pw_node_update_properties(nd->node, info->props);
object_update(od, info->props);
}
else {
device_add(device, id, info);
device_add_object(device, id, info);
}
}

View file

@ -229,7 +229,7 @@ int pw_factory_register(struct pw_factory *factory,
factory->registered = true;
factory->info.id = factory->global->id;
pw_properties_setf(factory->properties, PW_KEY_FACTORY_ID, "%d", factory->info.id);
pw_properties_setf(factory->properties, PW_KEY_OBJECT_ID, "%d", factory->info.id);
factory->info.props = &factory->properties->dict;
pw_global_add_listener(factory->global, &factory->global_listener, &global_events, factory);

View file

@ -66,6 +66,8 @@ extern "C" {
#define PW_KEY_LIBRARY_NAME_LOOP "library.name.loop" /**< name of the loop library to use */
#define PW_KEY_LIBRARY_NAME_DBUS "library.name.dbus" /**< name of the dbus library to use */
#define PW_KEY_OBJECT_ID "object.id" /**< a global object id */
#define PW_KEY_CORE_ID "core.id" /**< the core id */
#define PW_KEY_CORE_MONITORS "core.monitors" /**< the apis monitored by core. */

View file

@ -1451,7 +1451,7 @@ int pw_link_register(struct pw_link *link,
link->registered = true;
link->info.id = link->global->id;
pw_properties_setf(link->properties, PW_KEY_LINK_ID, "%d", link->info.id);
pw_properties_setf(link->properties, PW_KEY_OBJECT_ID, "%d", link->info.id);
link->info.props = &link->properties->dict;
pw_global_add_listener(link->global, &link->global_listener, &global_events, link);

View file

@ -261,7 +261,7 @@ pw_module_load(struct pw_core *core,
spa_list_append(&core->module_list, &this->link);
this->info.id = this->global->id;
pw_properties_setf(this->properties, PW_KEY_MODULE_ID, "%d", this->info.id);
pw_properties_setf(this->properties, PW_KEY_OBJECT_ID, "%d", this->info.id);
this->info.props = &this->properties->dict;
pw_global_add_listener(this->global, &this->global_listener, &global_events, this);

View file

@ -588,7 +588,7 @@ int pw_node_register(struct pw_node *this,
this->info.id = this->global->id;
this->rt.activation->position.clock.id = this->info.id;
pw_properties_setf(this->properties, PW_KEY_NODE_ID, "%d", this->info.id);
pw_properties_setf(this->properties, PW_KEY_OBJECT_ID, "%d", this->info.id);
this->info.props = &this->properties->dict;
pw_node_initialized(this);

View file

@ -714,7 +714,7 @@ int pw_port_register(struct pw_port *port,
port->info.id = port->global->id;
pw_properties_setf(port->properties, PW_KEY_NODE_ID, "%d", node->global->id);
pw_properties_setf(port->properties, PW_KEY_PORT_ID, "%d", port->info.id);
pw_properties_setf(port->properties, PW_KEY_OBJECT_ID, "%d", port->info.id);
port->info.props = &port->properties->dict;
return pw_global_register(port->global);

View file

@ -302,7 +302,7 @@ struct pw_device {
struct spa_hook listener;
struct spa_hook_list listener_list;
struct spa_list node_list;
struct spa_list object_list;
void *user_data; /**< device user_data */