diff options
author | Wim Taymans <wtaymans@redhat.com> | 2019-11-20 16:18:46 +0100 |
---|---|---|
committer | Wim Taymans <wtaymans@redhat.com> | 2019-11-29 13:34:09 +0100 |
commit | 80ac7556705b68789caca35fc17f16eb7ee8a957 (patch) | |
tree | fafbe4aaafb40781dc8686ca6802a3e087fc837c | |
parent | b7aa8f5c8580d00852302e8c13789b0ae2ce013a (diff) |
media-session: make the services more modular
-rw-r--r-- | src/examples/media-session/alsa-endpoint.c | 76 | ||||
-rw-r--r-- | src/examples/media-session/alsa-midi.c | 89 | ||||
-rw-r--r-- | src/examples/media-session/alsa-monitor.c | 168 | ||||
-rw-r--r-- | src/examples/media-session/bluez-monitor.c | 85 | ||||
-rw-r--r-- | src/examples/media-session/media-session.c | 153 | ||||
-rw-r--r-- | src/examples/media-session/media-session.h | 20 | ||||
-rw-r--r-- | src/examples/media-session/metadata.c | 49 | ||||
-rw-r--r-- | src/examples/media-session/monitor.c | 146 | ||||
-rw-r--r-- | src/examples/media-session/policy-ep.c | 10 | ||||
-rw-r--r-- | src/examples/media-session/stream-monitor.c | 5 | ||||
-rw-r--r-- | src/examples/media-session/v4l2-monitor.c | 97 | ||||
-rw-r--r-- | src/examples/meson.build | 6 | ||||
-rw-r--r-- | src/modules/module-session-manager/endpoint.c | 1 |
13 files changed, 559 insertions, 346 deletions
diff --git a/src/examples/media-session/alsa-endpoint.c b/src/examples/media-session/alsa-endpoint.c index 7ab290f3..c37125af 100644 --- a/src/examples/media-session/alsa-endpoint.c +++ b/src/examples/media-session/alsa-endpoint.c @@ -40,9 +40,9 @@ #include <spa/param/audio/format-utils.h> #include <spa/param/props.h> #include <spa/debug/dict.h> +#include <spa/debug/pod.h> #include "pipewire/pipewire.h" -#include "pipewire/private.h" struct endpoint { struct spa_list link; @@ -98,7 +98,7 @@ static int client_endpoint_set_param(void *object, uint32_t id, uint32_t flags, const struct spa_pod *param) { struct endpoint *endpoint = object; - struct impl *impl = endpoint->obj->monitor->impl; + struct impl *impl = endpoint->obj->impl; pw_log_debug(NAME " %p: endpoint %p set param %d", impl, endpoint, id); return pw_node_proxy_set_param((struct pw_node_proxy*)endpoint->obj->proxy, id, flags, param); @@ -114,7 +114,7 @@ static int client_endpoint_stream_set_param(void *object, uint32_t stream_id, static int client_endpoint_create_link(void *object, const struct spa_dict *props) { struct endpoint *endpoint = object; - struct impl *impl = endpoint->obj->monitor->impl; + struct impl *impl = endpoint->obj->impl; struct pw_properties *p; char buf[1024]; struct spa_pod_builder b = { 0, }; @@ -243,7 +243,7 @@ static void node_event_param(void *object, int seq, { struct endpoint *endpoint = object; struct alsa_node *n = endpoint->obj; - struct impl *impl = n->monitor->impl; + struct impl *impl = n->impl; struct spa_audio_info info = { 0, }; pw_log_debug(NAME" %p: param for node %d, %d", impl, n->info->id, id); @@ -304,7 +304,7 @@ static void complete_endpoint(void *data) static struct endpoint *make_endpoint(struct alsa_node *obj, struct endpoint *monitor) { - struct impl *impl = obj->monitor->impl; + struct impl *impl = obj->impl; struct pw_properties *props; struct endpoint *endpoint; struct pw_proxy *proxy; @@ -356,7 +356,7 @@ static struct endpoint *make_endpoint(struct alsa_node *obj, struct endpoint *mo endpoint->info.version = PW_VERSION_ENDPOINT_INFO; endpoint->info.name = (char*)pw_properties_get(endpoint->props, PW_KEY_ENDPOINT_NAME); endpoint->info.media_class = (char*)pw_properties_get(endpoint->props, PW_KEY_MEDIA_CLASS); - endpoint->info.session_id = impl->session->info.id; + endpoint->info.session_id = impl->session->session->obj.id; endpoint->info.direction = monitor != NULL ? PW_DIRECTION_OUTPUT : obj->direction; endpoint->info.flags = 0; endpoint->info.change_mask = @@ -461,3 +461,67 @@ static int setup_alsa_endpoint(struct alsa_object *obj) return res; } + +#if 0 +static int +handle_device(struct impl *impl, struct sm_object *obj) +{ + return 0; +} + +static void session_update(void *data, struct sm_object *object) +{ + struct impl *impl = data; + int res; + + switch (object->type) { + case PW_TYPE_INTERFACE_Device: + res = handle_device(impl, object); + break; + + default: + res = 0; + break; + } + if (res < 0) { + pw_log_warn(NAME" %p: can't handle global %d: %s", impl, + object->id, spa_strerror(res)); + } +} + +static void session_remove(void *data, struct sm_object *object) +{ + switch (object->type) { + case PW_TYPE_INTERFACE_Device: + break; + default: + break; + } +} + + +static const struct sm_media_session_events session_events = { + SM_VERSION_MEDIA_SESSION_EVENTS, + .update = session_update, + .remove = session_remove, +}; + +void *sm_alsa_endpoint_start(struct sm_media_session *session) +{ + struct impl *impl; + + impl = calloc(1, sizeof(struct impl)); + if (impl == NULL) + return NULL; + + impl->session = session; + sm_media_session_add_listener(session, &impl->listener, &session_events, impl); + + return impl; +} + +int sm_alsa_endpoint_stop(void *data) +{ + return 0; +} +#endif diff --git a/src/examples/media-session/alsa-midi.c b/src/examples/media-session/alsa-midi.c new file mode 100644 index 00000000..0a61febb --- /dev/null +++ b/src/examples/media-session/alsa-midi.c @@ -0,0 +1,89 @@ +/* PipeWire + * + * Copyright © 2019 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 <string.h> +#include <stdio.h> +#include <errno.h> +#include <math.h> +#include <time.h> + +#include "config.h" + +#include <spa/utils/names.h> +#include <spa/node/keys.h> + +#include "pipewire/pipewire.h" + +#include "media-session.h" + +struct impl { + struct sm_media_session *session; + + struct pw_properties *props; + struct pw_proxy *proxy; +}; + +void * sm_alsa_midi_start(struct sm_media_session *session) +{ + struct impl *impl; + + impl = calloc(1, sizeof(struct impl)); + if (impl == NULL) + return NULL; + + impl->session = session; + impl->props = pw_properties_new( + SPA_KEY_FACTORY_NAME, SPA_NAME_API_ALSA_SEQ_BRIDGE, + SPA_KEY_NODE_NAME, "Midi-Bridge", + NULL); + if (impl->props == NULL) + goto cleanup; + + impl->proxy = sm_media_session_create_object(session, + "spa-node-factory", + PW_TYPE_INTERFACE_Node, + PW_VERSION_NODE_PROXY, + &impl->props->dict, + 0); + + if (impl->proxy == NULL) + goto cleanup_props; + + return impl; + +cleanup_props: + pw_properties_free(impl->props); +cleanup: + free(impl); + return NULL; +} + +int sm_alsa_midi_stop(void *data) +{ + struct impl *impl = data; + pw_proxy_destroy(impl->proxy); + pw_properties_free(impl->props); + free(impl); + return 0; +} diff --git a/src/examples/media-session/alsa-monitor.c b/src/examples/media-session/alsa-monitor.c index 3362359a..4d94f0f2 100644 --- a/src/examples/media-session/alsa-monitor.c +++ b/src/examples/media-session/alsa-monitor.c @@ -40,18 +40,20 @@ #include <spa/param/audio/format-utils.h> #include <spa/param/props.h> #include <spa/debug/dict.h> +#include <spa/support/dbus.h> -#include "pipewire/pipewire.h" -#include "pipewire/private.h" +#include <pipewire/pipewire.h> +#include <pipewire/main-loop.h> +#include <extensions/session-manager.h> + +#include "media-session.h" #include "reserve.c" #define DEFAULT_JACK_SECONDS 1 -struct alsa_object; - struct alsa_node { - struct monitor *monitor; + struct impl *impl; enum pw_direction direction; struct alsa_object *object; struct spa_list link; @@ -67,7 +69,7 @@ struct alsa_node { }; struct alsa_object { - struct monitor *monitor; + struct impl *impl; struct spa_list link; uint32_t id; uint32_t device_id; @@ -88,6 +90,24 @@ struct alsa_object { struct spa_list node_list; }; +struct impl { + struct sm_media_session *session; + + DBusConnection *conn; + + struct spa_handle *handle; + + struct spa_device *monitor; + struct spa_hook listener; + + struct spa_list object_list; + + struct spa_source *jack_timeout; + struct pw_proxy *jack_device; +}; + +#include "alsa-endpoint.c" + static struct alsa_node *alsa_find_node(struct alsa_object *obj, uint32_t id) { struct alsa_node *node; @@ -125,8 +145,7 @@ static struct alsa_node *alsa_create_node(struct alsa_object *obj, uint32_t id, const struct spa_device_object_info *info) { struct alsa_node *node; - struct monitor *monitor = obj->monitor; - struct impl *impl = monitor->impl; + struct impl *impl = obj->impl; int res; const char *dev, *subdev, *stream; int priority; @@ -216,7 +235,7 @@ static struct alsa_node *alsa_create_node(struct alsa_object *obj, uint32_t id, } } - node->monitor = monitor; + node->impl = impl; node->object = obj; node->id = id; node->proxy = sm_media_session_create_object(impl->session, @@ -292,18 +311,18 @@ static const struct spa_device_events alsa_device_events = { .object_info = alsa_device_object_info }; -static struct alsa_object *alsa_find_object(struct monitor *monitor, uint32_t id) +static struct alsa_object *alsa_find_object(struct impl *impl, uint32_t id) { struct alsa_object *obj; - spa_list_for_each(obj, &monitor->object_list, link) { + spa_list_for_each(obj, &impl->object_list, link) { if (obj->id == id) return obj; } return NULL; } -static void alsa_update_object(struct monitor *monitor, struct alsa_object *obj, +static void alsa_update_object(struct impl *impl, struct alsa_object *obj, const struct spa_device_object_info *info) { pw_log_debug("update object %u", obj->id); @@ -418,7 +437,7 @@ static void set_profile(struct alsa_object *obj, int index) static void remove_jack_timeout(struct impl *impl) { - struct pw_loop *main_loop = impl->session->loop->loop; + struct pw_loop *main_loop = impl->session->loop; if (impl->jack_timeout) { pw_loop_destroy_source(main_loop, impl->jack_timeout); @@ -436,7 +455,7 @@ static void jack_timeout(void *data, uint64_t expirations) static void add_jack_timeout(struct impl *impl) { struct timespec value; - struct pw_loop *main_loop = impl->session->loop->loop; + struct pw_loop *main_loop = impl->session->loop; if (impl->jack_timeout == NULL) impl->jack_timeout = pw_loop_add_timer(main_loop, jack_timeout, impl); @@ -449,8 +468,7 @@ static void add_jack_timeout(struct impl *impl) static void reserve_acquired(void *data, struct rd_device *d) { struct alsa_object *obj = data; - struct monitor *monitor = obj->monitor; - struct impl *impl = monitor->impl; + struct impl *impl = obj->impl; pw_log_debug("%p: reserve acquired", obj); @@ -464,8 +482,7 @@ static void reserve_acquired(void *data, struct rd_device *d) static void sync_complete_done(void *data, int seq) { struct alsa_object *obj = data; - struct monitor *monitor = obj->monitor; - struct impl *impl = monitor->impl; + struct impl *impl = obj->impl; pw_log_debug("%d %d", obj->seq, seq); if (seq != obj->seq) @@ -487,8 +504,7 @@ static const struct pw_proxy_events sync_complete_release = { static void reserve_release(void *data, struct rd_device *d, int forced) { struct alsa_object *obj = data; - struct monitor *monitor = obj->monitor; - struct impl *impl = monitor->impl; + struct impl *impl = obj->impl; pw_log_debug("%p: reserve release", obj); @@ -507,10 +523,9 @@ static const struct rd_device_callbacks reserve_callbacks = { .release = reserve_release, }; -static struct alsa_object *alsa_create_object(struct monitor *monitor, uint32_t id, +static struct alsa_object *alsa_create_object(struct impl *impl, uint32_t id, const struct spa_device_object_info *info) { - struct impl *impl = monitor->impl; struct pw_core *core = impl->session->core; struct alsa_object *obj; struct spa_handle *handle; @@ -545,7 +560,7 @@ static struct alsa_object *alsa_create_object(struct monitor *monitor, uint32_t goto unload_handle; } - obj->monitor = monitor; + obj->impl = impl; obj->id = id; obj->handle = handle; obj->device = iface; @@ -591,7 +606,7 @@ static struct alsa_object *alsa_create_object(struct monitor *monitor, uint32_t spa_device_add_listener(obj->device, &obj->device_listener, &alsa_device_events, obj); - spa_list_append(&monitor->object_list, &obj->link); + spa_list_append(&impl->object_list, &obj->link); return obj; @@ -604,7 +619,7 @@ exit: return NULL; } -static void alsa_remove_object(struct monitor *monitor, struct alsa_object *obj) +static void alsa_remove_object(struct impl *impl, struct alsa_object *obj) { pw_log_debug("remove object %u", obj->id); spa_list_remove(&obj->link); @@ -621,20 +636,20 @@ static void alsa_remove_object(struct monitor *monitor, struct alsa_object *obj) static void alsa_udev_object_info(void *data, uint32_t id, const struct spa_device_object_info *info) { - struct monitor *monitor = data; + struct impl *impl = data; struct alsa_object *obj; - obj = alsa_find_object(monitor, id); + obj = alsa_find_object(impl, id); if (info == NULL) { if (obj == NULL) return; - alsa_remove_object(monitor, obj); + alsa_remove_object(impl, obj); } else if (obj == NULL) { - if ((obj = alsa_create_object(monitor, id, info)) == NULL) + if ((obj = alsa_create_object(impl, id, info)) == NULL) return; } else { - alsa_update_object(monitor, obj, info); + alsa_update_object(impl, obj, info); } } @@ -644,81 +659,80 @@ static const struct spa_device_events alsa_udev_events = .object_info = alsa_udev_object_info, }; -static int alsa_start_midi_bridge(struct impl *impl) +static int alsa_start_jack_device(struct impl *impl) { struct pw_properties *props; int res = 0; props = pw_properties_new( - SPA_KEY_FACTORY_NAME, SPA_NAME_API_ALSA_SEQ_BRIDGE, - SPA_KEY_NODE_NAME, "Midi-Bridge", + SPA_KEY_FACTORY_NAME, SPA_NAME_API_JACK_DEVICE, + SPA_KEY_NODE_NAME, "JACK-Device", NULL); - impl->midi_bridge = sm_media_session_create_object(impl->session, - "spa-node-factory", - PW_TYPE_INTERFACE_Node, - PW_VERSION_NODE_PROXY, + impl->jack_device = sm_media_session_create_object(impl->session, + "spa-device-factory", + PW_TYPE_INTERFACE_Device, + PW_VERSION_DEVICE_PROXY, &props->dict, 0); - if (impl->midi_bridge == NULL) + if (impl->jack_device == NULL) res = -errno; return res; } -static int alsa_start_monitor(struct impl *impl, struct monitor *monitor) +void *sm_alsa_monitor_start(struct sm_media_session *session) { - struct spa_handle *handle; - struct pw_core *core = impl->session->core; - int res; + struct pw_core *core = session->core; + struct impl *impl; void *iface; + int res; - handle = pw_core_load_spa_handle(core, SPA_NAME_API_ALSA_ENUM_UDEV, NULL); - if (handle == NULL) { + impl = calloc(1, sizeof(struct impl)); + if (impl == NULL) + return NULL; + + impl->session = session; + + if (session->dbus_connection) + impl->conn = spa_dbus_connection_get(session->dbus_connection); + if (impl->conn == NULL) + pw_log_warn("no dbus connection, device reservation disabled"); + else + pw_log_debug("got dbus connection %p", impl->conn); + + impl->handle = pw_core_load_spa_handle(core, SPA_NAME_API_ALSA_ENUM_UDEV, NULL); + if (impl->handle == NULL) { res = -errno; - goto out; + goto out_free; } - if ((res = spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_Device, &iface)) < 0) { + if ((res = spa_handle_get_interface(impl->handle, SPA_TYPE_INTERFACE_Device, &iface)) < 0) { pw_log_error("can't get udev Device interface: %d", res); goto out_unload; } + impl->monitor = iface; + spa_list_init(&impl->object_list); + spa_device_add_listener(impl->monitor, &impl->listener, &alsa_udev_events, impl); - monitor->impl = impl; - monitor->handle = handle; - monitor->monitor = iface; - spa_list_init(&monitor->object_list); - - spa_device_add_listener(monitor->monitor, &monitor->listener, &alsa_udev_events, monitor); + if ((res = alsa_start_jack_device(impl)) < 0) + goto out_unload; - return 0; + return impl; - out_unload: - pw_unload_spa_handle(handle); - out: - return res; +out_unload: + pw_unload_spa_handle(impl->handle); +out_free: + free(impl); + errno = -res; + return NULL; } -static int alsa_start_jack_device(struct impl *impl) +int sm_alsa_monitor_stop(void *data) { - struct pw_properties *props; - int res = 0; - - props = pw_properties_new( - SPA_KEY_FACTORY_NAME, SPA_NAME_API_JACK_DEVICE, - SPA_KEY_NODE_NAME, "JACK-Device", - NULL); - - impl->jack_device = sm_media_session_create_object(impl->session, - "spa-device-factory", - PW_TYPE_INTERFACE_Device, - PW_VERSION_DEVICE_PROXY, - &props->dict, - 0); - - if (impl->jack_device == NULL) - res = -errno; - - return res; + struct impl *impl = data; + pw_unload_spa_handle(impl->handle); + free(impl); + return 0; } diff --git a/src/examples/media-session/bluez-monitor.c b/src/examples/media-session/bluez-monitor.c index 50ffbc94..963dbd33 100644 --- a/src/examples/media-session/bluez-monitor.c +++ b/src/examples/media-session/bluez-monitor.c @@ -38,12 +38,12 @@ #include <spa/debug/dict.h> #include "pipewire/pipewire.h" -#include "pipewire/private.h" +#include "media-session.h" struct bluez5_object; struct bluez5_node { - struct monitor *monitor; + struct impl *impl; struct bluez5_object *object; struct spa_list link; uint32_t id; @@ -55,7 +55,7 @@ struct bluez5_node { }; struct bluez5_object { - struct monitor *monitor; + struct impl *impl; struct spa_list link; uint32_t id; @@ -69,6 +69,17 @@ struct bluez5_object { struct spa_list node_list; }; +struct impl { + struct sm_media_session *session; + + struct spa_handle *handle; + + struct spa_device *monitor; + struct spa_hook listener; + + struct spa_list object_list; +}; + static struct bluez5_node *bluez5_find_node(struct bluez5_object *obj, uint32_t id) { struct bluez5_node *node; @@ -93,8 +104,7 @@ static struct bluez5_node *bluez5_create_node(struct bluez5_object *obj, uint32_ const struct spa_device_object_info *info) { struct bluez5_node *node; - struct monitor *monitor = obj->monitor; - struct impl *impl = monitor->impl; + struct impl *impl = obj->impl; struct pw_core *core = impl->session->core; struct pw_factory *factory; int res; @@ -128,7 +138,7 @@ static struct bluez5_node *bluez5_create_node(struct bluez5_object *obj, uint32_ pw_properties_set(node->props, PW_KEY_NODE_DESCRIPTION, str); pw_properties_set(node->props, "factory.name", info->factory_name); - node->monitor = monitor; + node->impl = impl; node->object = obj; node->id = id; @@ -203,18 +213,18 @@ static const struct spa_device_events bluez5_device_events = { .object_info = bluez5_device_object_info }; -static struct bluez5_object *bluez5_find_object(struct monitor *monitor, uint32_t id) +static struct bluez5_object *bluez5_find_object(struct impl *impl, uint32_t id) { struct bluez5_object *obj; - spa_list_for_each(obj, &monitor->object_list, link) { + spa_list_for_each(obj, &impl->object_list, link) { if (obj->id == id) return obj; } return NULL; } -static void bluez5_update_object(struct monitor *monitor, struct bluez5_object *obj, +static void bluez5_update_object(struct impl *impl, struct bluez5_object *obj, const struct spa_device_object_info *info) { pw_log_debug("update object %u", obj->id); @@ -223,10 +233,9 @@ static void bluez5_update_object(struct monitor *monitor, struct bluez5_object * spa_debug_dict(0, info->props); } -static struct bluez5_object *bluez5_create_object(struct monitor *monitor, uint32_t id, +static struct bluez5_object *bluez5_create_object(struct impl *impl, uint32_t id, const struct spa_device_object_info *info) { - struct impl *impl = monitor->impl; struct pw_core *core = impl->session->core; struct bluez5_object *obj; struct spa_handle *handle; @@ -260,7 +269,7 @@ static struct bluez5_object *bluez5_create_object(struct monitor *monitor, uint3 goto unload_handle; } - obj->monitor = monitor; + obj->impl = impl; obj->id = id; obj->handle = handle; obj->device = iface; @@ -277,9 +286,9 @@ static struct bluez5_object *bluez5_create_object(struct monitor *monitor, uint3 spa_device_add_listener(obj->device, &obj->device_listener, &bluez5_device_events, obj); - spa_list_append(&monitor->object_list, &obj->link); + spa_list_append(&impl->object_list, &obj->link); - bluez5_update_object(monitor, obj, info); + bluez5_update_object(impl, obj, info); return obj; @@ -292,7 +301,7 @@ exit: return NULL; } -static void bluez5_remove_object(struct monitor *monitor, struct bluez5_object *obj) +static void bluez5_remove_object(struct impl *impl, struct bluez5_object *obj) { struct bluez5_node *node; @@ -311,20 +320,20 @@ static void bluez5_remove_object(struct monitor *monitor, struct bluez5_object * static void bluez5_enum_object_info(void *data, uint32_t id, const struct spa_device_object_info *info) { - struct monitor *monitor = data; + struct impl *impl = data; struct bluez5_object *obj; - obj = bluez5_find_object(monitor, id); + obj = bluez5_find_object(impl, id); if (info == NULL) { if (obj == NULL) return; - bluez5_remove_object(monitor, obj); + bluez5_remove_object(impl, obj); } else if (obj == NULL) { - if ((obj = bluez5_create_object(monitor, id, info)) == NULL) + if ((obj = bluez5_create_object(impl, id, info)) == NULL) return; } else { - bluez5_update_object(monitor, obj, info); + bluez5_update_object(impl, obj, info); } } @@ -334,12 +343,13 @@ static const struct spa_device_events bluez5_enum_callbacks = .object_info = bluez5_enum_object_info, }; -static int bluez5_start_monitor(struct impl *impl, struct monitor *monitor) +void *sm_bluez5_monitor_start(struct sm_media_session *session) { struct spa_handle *handle; - struct pw_core *core = impl->session->core; + struct pw_core *core = session->core; int res; void *iface; + struct impl *impl; handle = pw_core_load_spa_handle(core, SPA_NAME_API_BLUEZ5_ENUM_DBUS, NULL); if (handle == NULL) { @@ -352,18 +362,33 @@ static int bluez5_start_monitor(struct impl *impl, struct monitor *monitor) goto out_unload; } - monitor->impl = impl; - monitor->handle = handle; - monitor->monitor = iface; - spa_list_init(&monitor->object_list); + impl = calloc(1, sizeof(struct impl)); + if (impl == NULL) { + res = -errno; + goto out_unload; + } + + impl->session = session; + impl->handle = handle; + impl->monitor = iface; + spa_list_init(&impl->object_list); - spa_device_add_listener(monitor->monitor, &monitor->listener, - &bluez5_enum_callbacks, monitor); + spa_device_add_listener(impl->monitor, &impl->listener, + &bluez5_enum_callbacks, impl); - return 0; + return impl; out_unload: pw_unload_spa_handle(handle); out: - return res; + errno = -res; + return NULL; +} + +int sm_bluez5_monitor_stop(void *data) +{ + struct impl *impl = data; + pw_unload_spa_handle(impl->handle); + free(impl); + return 0; } diff --git a/src/examples/media-session/media-session.c b/src/examples/media-session/media-session.c index 1d8054d1..4674e0df 100644 --- a/src/examples/media-session/media-session.c +++ b/src/examples/media-session/media-session.c @@ -53,7 +53,12 @@ #define sm_media_session_emit_remove(s,obj) sm_media_session_emit(s, remove, 0, obj) #define sm_media_session_emit_rescan(s,seq) sm_media_session_emit(s, rescan, 0, seq) -int sm_monitor_start(struct sm_media_session *sess); +void * sm_stream_monitor_start(struct sm_media_session *sess); +void * sm_metadata_start(struct sm_media_session *sess); +void * sm_alsa_midi_start(struct sm_media_session *sess); +void * sm_v4l2_monitor_start(struct sm_media_session *sess); +void * sm_bluez5_monitor_start(struct sm_media_session *sess); +void * sm_alsa_monitor_start(struct sm_media_session *sess); int sm_policy_ep_start(struct sm_media_session *sess); /** user data to add to an object */ @@ -77,6 +82,10 @@ struct sync { struct impl { struct sm_media_session this; + uint32_t session_id; + + struct pw_main_loop *loop; + struct spa_dbus *dbus; struct pw_remote *monitor_remote; struct spa_hook monitor_listener; @@ -384,6 +393,54 @@ static void port_destroy(void *object) } /** + * Session + */ +static void session_event_info(void *object, const struct pw_session_info *info) +{ + struct sm_session *sess = object; + struct impl *impl = SPA_CONTAINER_OF(sess->obj.session, struct impl, this); + struct pw_session_info *i = sess->info; + + pw_log_debug(NAME" %p: session %d info", impl, sess->obj.id); + if (i == NULL && info) { + i = sess->info = calloc(1, sizeof(struct pw_session_info)); + i->version = PW_VERSION_SESSION_INFO; + i->id = info->id; + } + i->change_mask = info->change_mask; + if (info->change_mask & PW_SESSION_CHANGE_MASK_PROPS) { + if (i->props) + pw_properties_free ((struct pw_properties *)i->props); + i->props = (struct spa_dict *) pw_properties_new_dict (info->props); + } + + sess->avail |= SM_SESSION_CHANGE_MASK_INFO; + sess->changed |= SM_SESSION_CHANGE_MASK_INFO; + sm_media_session_emit_update(impl, &sess->obj); + sess->changed = 0; +} + +static const struct pw_session_proxy_events session_events = { + PW_VERSION_SESSION_PROXY_EVENTS, + .info = session_event_info, +}; + +static void session_destroy(void *object) +{ + struct sm_session *sess = object; + struct sm_endpoint *endpoint; + + if (sess->info) { + free(sess->info); + } + + spa_list_consume(endpoint, &sess->endpoint_list, link) { + endpoint->session = NULL; + spa_list_remove(&endpoint->link); + } +} + +/** * Endpoint */ static void endpoint_event_info(void *object, const struct pw_endpoint_info *info) @@ -440,6 +497,10 @@ static void endpoint_destroy(void *object) stream->endpoint = NULL; spa_list_remove(&stream->link); } + if (endpoint->session) { + endpoint->session = NULL; + spa_list_remove(&endpoint->link); + } } /** @@ -564,7 +625,7 @@ registry_global(void *data,uint32_t id, const void *events; uint32_t client_version; pw_destroy_t destroy; - struct sm_object *obj; + struct sm_object *obj = NULL; struct pw_proxy *proxy; size_t user_data_size; const char *str; @@ -593,6 +654,13 @@ registry_global(void *data,uint32_t id, user_data_size = sizeof(struct sm_port); break; + case PW_TYPE_INTERFACE_Session: + events = &session_events; + client_version = PW_VERSION_SESSION_PROXY; + destroy = (pw_destroy_t) session_destroy; + user_data_size = sizeof(struct sm_session); + break; + case PW_TYPE_INTERFACE_Endpoint: events = &endpoint_events; client_version = PW_VERSION_ENDPOINT_PROXY; @@ -625,7 +693,8 @@ registry_global(void *data,uint32_t id, goto error; } - obj = pw_proxy_get_user_data(proxy); + if (obj == NULL) + obj = pw_proxy_get_user_data(proxy); obj->session = &impl->this; obj->id = id; obj->type = type; @@ -667,9 +736,24 @@ registry_global(void *data,uint32_t id, } break; } + case PW_TYPE_INTERFACE_Session: + { + struct sm_session *sess = (struct sm_session*) obj; + if (id == impl->session_id) + impl->this.session = sess; + spa_list_init(&sess->endpoint_list); + break; + } case PW_TYPE_INTERFACE_Endpoint: { struct sm_endpoint *endpoint = (struct sm_endpoint*) obj; + if (props) { + if ((str = spa_dict_lookup(props, PW_KEY_SESSION_ID)) != NULL) + endpoint->session = find_object(impl, atoi(str)); + pw_log_debug(NAME" %p: endpoint %d parent session %s", impl, id, str); + if (endpoint->session) + spa_list_append(&endpoint->session->endpoint_list, &endpoint->link); + } spa_list_init(&endpoint->stream_list); break; } @@ -759,7 +843,7 @@ static void roundtrip_callback(void *data) int sm_media_session_roundtrip(struct sm_media_session *sess) { struct impl *impl = SPA_CONTAINER_OF(sess, struct impl, this); - struct pw_main_loop *loop = sess->loop; + struct pw_loop *loop = impl->this.loop; int done, res; if (impl->core_proxy == NULL) @@ -771,15 +855,15 @@ int sm_media_session_roundtrip(struct sm_media_session *sess) pw_log_debug(NAME" %p: roundtrip %d", impl, res); - pw_loop_enter(loop->loop); + pw_loop_enter(loop); while (!done) { - if ((res = pw_loop_iterate(loop->loop, -1)) < 0) { + if ((res = pw_loop_iterate(loop, -1)) < 0) { pw_log_warn(NAME" %p: iterate error %d (%s)", loop, res, spa_strerror(res)); break; } } - pw_loop_leave(loop->loop); + pw_loop_leave(loop); pw_log_debug(NAME" %p: roundtrip done", impl); @@ -986,7 +1070,7 @@ int sm_media_session_create_links(struct sm_media_session *sess, link->info.version = PW_VERSION_ENDPOINT_LINK_INFO; link->info.id = link->id; - link->info.session_id = impl->this.info.id; + link->info.session_id = impl->this.session->obj.id; link->info.output_endpoint_id = outendpoint->info->id; link->info.output_stream_id = outstream ? outstream->info->id : SPA_ID_INVALID; link->info.input_endpoint_id = inendpoint->info->id; @@ -1021,16 +1105,29 @@ int sm_media_session_create_links(struct sm_media_session *sess, static int client_session_set_id(void *object, uint32_t id) { struct impl *impl = object; + struct pw_session_info info; + + impl->session_id = id; + + spa_zero(info); + info.version = PW_VERSION_SESSION_INFO; + info.id = id; pw_log_debug("got sesssion id:%d", id); - impl->this.info.id = id; pw_client_session_proxy_update(impl->client_session, PW_CLIENT_SESSION_UPDATE_INFO, 0, NULL, - &impl->this.info); - - return sm_monitor_start(&impl->this); + &info); + + /* start monitors */ + sm_metadata_start(&impl->this); + sm_alsa_midi_start(&impl->this); + sm_bluez5_monitor_start(&impl->this); + sm_alsa_monitor_start(&impl->this); + sm_v4l2_monitor_start(&impl->this); + sm_stream_monitor_start(&impl->this); + return 0; } static int client_session_set_param(void *object, uint32_t id, uint32_t flags, @@ -1071,7 +1168,6 @@ static int start_session(struct impl *impl) PW_TYPE_INTERFACE_ClientSession, PW_VERSION_CLIENT_SESSION_PROXY, NULL, 0); - impl->this.info.version = PW_VERSION_SESSION_INFO; pw_client_session_proxy_add_listener(impl->client_session, &impl->client_session_listener, @@ -1114,12 +1210,11 @@ static void on_monitor_state_changed(void *_data, enum pw_remote_state old, enum pw_remote_state state, const char *error) { struct impl *impl = _data; - struct sm_media_session *sess = &impl->this; switch (state) { case PW_REMOTE_STATE_ERROR: pw_log_error(NAME" %p: remote error: %s", impl, error); - pw_main_loop_quit(sess->loop); + pw_main_loop_quit(impl->loop); break; case PW_REMOTE_STATE_CONNECTED: @@ -1138,7 +1233,7 @@ static void on_monitor_state_changed(void *_data, enum pw_remote_state old, case PW_REMOTE_STATE_UNCONNECTED: pw_log_info(NAME" %p: disconnected", impl); - pw_main_loop_quit(sess->loop); + pw_main_loop_quit(impl->loop); break; default: @@ -1156,12 +1251,11 @@ static void on_policy_state_changed(void *_data, enum pw_remote_state old, enum pw_remote_state state, const char *error) { struct impl *impl = _data; - struct sm_media_session *sess = &impl->this; switch (state) { case PW_REMOTE_STATE_ERROR: pw_log_error(NAME" %p: remote error: %s", impl, error); - pw_main_loop_quit(sess->loop); + pw_main_loop_quit(impl->loop); break; case PW_REMOTE_STATE_CONNECTED: @@ -1171,7 +1265,7 @@ static void on_policy_state_changed(void *_data, enum pw_remote_state old, case PW_REMOTE_STATE_UNCONNECTED: pw_log_info(NAME" %p: disconnected", impl); - pw_main_loop_quit(sess->loop); + pw_main_loop_quit(impl->loop); break; default: @@ -1188,12 +1282,15 @@ static const struct pw_remote_events policy_remote_events = { int main(int argc, char *argv[]) { struct impl impl = { 0, }; + const struct spa_support *support; + uint32_t n_support; int res; pw_init(&argc, &argv); - impl.this.loop = pw_main_loop_new(NULL); - impl.this.core = pw_core_new(pw_main_loop_get_loop(impl.this.loop), NULL, 0); + impl.loop = pw_main_loop_new(NULL); + impl.this.loop = pw_main_loop_get_loop(impl.loop); + impl.this.core = pw_core_new(impl.this.loop, NULL, 0); pw_core_add_spa_lib(impl.this.core, "api.bluez5.*", "bluez5/libspa-bluez5"); pw_core_add_spa_lib(impl.this.core, "api.alsa.*", "alsa/libspa-alsa"); @@ -1217,15 +1314,25 @@ int main(int argc, char *argv[]) spa_list_init(&impl.sync_list); spa_hook_list_init(&impl.hooks); + support = pw_core_get_support(impl.this.core, &n_support); + + impl.dbus = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_DBus); + if (impl.dbus) + impl.this.dbus_connection = spa_dbus_get_connection(impl.dbus, DBUS_BUS_SESSION); + if (impl.this.dbus_connection == NULL) + pw_log_warn("no dbus connection"); + else + pw_log_debug("got dbus connection %p", impl.this.dbus_connection); + if ((res = pw_remote_connect(impl.monitor_remote)) < 0) return res; if ((res = pw_remote_connect(impl.policy_remote)) < 0) return res; - pw_main_loop_run(impl.this.loop); + pw_main_loop_run(impl.loop); pw_core_destroy(impl.this.core); - pw_main_loop_destroy(impl.this.loop); + pw_main_loop_destroy(impl.loop); return 0; } diff --git a/src/examples/media-session/media-session.h b/src/examples/media-session/media-session.h index bc21b678..73d5adef 100644 --- a/src/examples/media-session/media-session.h +++ b/src/examples/media-session/media-session.h @@ -104,11 +104,25 @@ struct sm_port { struct pw_port_info *info; }; +struct sm_session { + struct sm_object obj; + +#define SM_SESSION_CHANGE_MASK_INFO (1<<0) + uint32_t mask; /**< monitored info */ + uint32_t avail; /**< available info */ + uint32_t changed; /**< changed since last update */ + struct pw_session_info *info; + struct spa_list endpoint_list; +}; + struct sm_endpoint { struct sm_object obj; int32_t priority; + struct sm_session *session; + struct spa_list link; /**< link in session endpoint_list */ + #define SM_ENDPOINT_CHANGE_MASK_INFO (1<<0) #define SM_ENDPOINT_CHANGE_MASK_STREAMS (1<<1) uint32_t mask; /**< monitored info */ @@ -163,10 +177,12 @@ struct sm_media_session_events { }; struct sm_media_session { - struct pw_main_loop *loop; + struct sm_session *session; /** session object managed by this session */ + + struct pw_loop *loop; /** the main loop */ struct pw_core *core; - struct pw_session_info info; + struct spa_dbus_connection *dbus_connection; }; int sm_media_session_add_listener(struct sm_media_session *sess, struct spa_hook *listener, diff --git a/src/examples/media-session/metadata.c b/src/examples/media-session/metadata.c index 72fce95c..fd5d86bd 100644 --- a/src/examples/media-session/metadata.c +++ b/src/examples/media-session/metadata.c @@ -22,8 +22,15 @@ * DEALINGS IN THE SOFTWARE. */ +#include "pipewire/pipewire.h" +#include "pipewire/array.h" + #include <extensions/metadata.h> +#include "media-session.h" + +#define NAME "metadata" + #define pw_metadata_emit(hooks,method,version,...) \ spa_hook_list_call_simple(hooks, struct pw_metadata_events, \ method, version, ##__VA_ARGS__) @@ -54,17 +61,18 @@ static void set_item(struct item *item, uint32_t subject, const char *key, const item->value = strdup(value); } -struct sm_metadata { +struct metadata { struct pw_metadata impl; + struct sm_media_session *session; struct spa_hook_list hooks; struct pw_properties *properties; - struct pw_array metadata; + struct pw_proxy *proxy; }; -static void emit_properties(struct sm_metadata *this, const struct spa_dict *dict) +static void emit_properties(struct metadata *this, const struct spa_dict *dict) { struct item *item; pw_array_for_each(item, &this->metadata) { @@ -81,7 +89,7 @@ static int impl_add_listener(void *object, const struct pw_metadata_events *events, void *data) { - struct sm_metadata *this = object; + struct metadata *this = object; struct spa_hook_list save; spa_return_val_if_fail(this != NULL, -EINVAL); @@ -96,7 +104,7 @@ static int impl_add_listener(void *object, return 0; } -static struct item *find_item(struct sm_metadata *this, uint32_t subject, const char *key) +static struct item *find_item(struct metadata *this, uint32_t subject, const char *key) { struct item *item; @@ -107,7 +115,7 @@ static struct item *find_item(struct sm_metadata *this, uint32_t subject, const return NULL; } -static void clear_items(struct sm_metadata *this) +static void clear_items(struct metadata *this) { struct item *item; @@ -123,7 +131,7 @@ static int impl_set_property(void *object, const char *type, const char *value) { - struct sm_metadata *this = object; + struct metadata *this = object; struct item *item = NULL; if (key == NULL) @@ -160,7 +168,7 @@ static int impl_set_property(void *object, static int impl_clear(void *object) { - struct sm_metadata *this = object; + struct metadata *this = object; clear_items(this); return 0; } @@ -172,18 +180,13 @@ struct pw_metadata_methods impl_metadata = { .clear = impl_clear, }; -struct sm_metadata * -sm_metadata_new(struct pw_properties *props) +void *sm_metadata_start(struct sm_media_session *sess) { - struct sm_metadata *md; - - if (props == NULL) - props = pw_properties_new(NULL, NULL); - if (props == NULL) - return NULL; + struct metadata *md; md = calloc(1, sizeof(*md)); - md->properties = props; + md->session = sess; + md->properties = pw_properties_new(NULL, NULL); pw_array_init(&md->metadata, 4096); md->impl.iface = SPA_INTERFACE_INIT( @@ -192,13 +195,23 @@ sm_metadata_new(struct pw_properties *props) &impl_metadata, md); spa_hook_list_init(&md->hooks); + md->proxy = sm_media_session_export(sess, + PW_TYPE_INTERFACE_Metadata, + NULL, + &md->impl, + 0); return md; } -void sm_metadata_destroy(struct sm_metadata *this) +int sm_metadata_stop(void *data) { + struct metadata *this = data; + + pw_proxy_destroy(this->proxy); + clear_items(this); pw_array_clear(&this->metadata); pw_properties_free(this->properties); free(this); + return 0; } diff --git a/src/examples/media-session/monitor.c b/src/examples/media-session/monitor.c deleted file mode 100644 index 3e3a4905..00000000 --- a/src/examples/media-session/monitor.c +++ /dev/null @@ -1,146 +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 <string.h> -#include <stdio.h> -#include <errno.h> -#include <math.h> -#include <time.h> - -#include "config.h" - -#include <spa/node/node.h> -#include <spa/utils/hook.h> -#include <spa/param/audio/format-utils.h> -#include <spa/param/props.h> -#include <spa/debug/pod.h> -#include <spa/support/dbus.h> - -#include "pipewire/pipewire.h" -#include "pipewire/private.h" -#include "extensions/session-manager.h" - -#include <dbus/dbus.h> - -#include "media-session.h" - -#define NAME "media-session" - -#define DEFAULT_IDLE_SECONDS 3 - -void * sm_stream_monitor_start(struct sm_media_session *sess); - -struct impl; - -struct monitor { - struct impl *impl; - - struct spa_handle *handle; - - struct spa_device *monitor; - struct spa_hook listener; - - struct spa_list object_list; -}; - -struct impl { - struct timespec now; - - struct sm_media_session *session; - - struct monitor bluez5_monitor; - struct monitor alsa_monitor; - struct monitor v4l2_monitor; - - struct sm_metadata *metadata; - - struct spa_dbus *dbus; - struct spa_dbus_connection *dbus_connection; - DBusConnection *conn; - - struct pw_proxy *midi_bridge; - - struct spa_source *jack_timeout; - struct pw_proxy *jack_device; -}; - -struct alsa_object; - -static int setup_alsa_endpoint(struct alsa_object *obj); - -#include "alsa-monitor.c" -#include "alsa-endpoint.c" -#include "v4l2-monitor.c" -#include "bluez-monitor.c" -#include "metadata.c" - -static void start_services(struct impl *impl) -{ - const struct spa_support *support; - uint32_t n_support; - - support = pw_core_get_support(impl->session->core, &n_support); - - impl->dbus = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_DBus); - if (impl->dbus) - impl->dbus_connection = spa_dbus_get_connection(impl->dbus, DBUS_BUS_SESSION); - if (impl->dbus_connection) - impl->conn = spa_dbus_connection_get(impl->dbus_connection); - if (impl->conn == NULL) - pw_log_warn("no dbus connection, device reservation disabled"); - else - pw_log_debug("got dbus connection %p", impl->conn); - - sm_media_session_export(impl->session, - PW_TYPE_INTERFACE_Metadata, - NULL, - impl->metadata, - 0); - - bluez5_start_monitor(impl, &impl->bluez5_monitor); - alsa_start_monitor(impl, &impl->alsa_monitor); - alsa_start_midi_bridge(impl); - alsa_start_jack_device(impl); - v4l2_start_monitor(impl, &impl->v4l2_monitor); - sm_stream_monitor_start(impl->session); -} - -int sm_monitor_start(struct sm_media_session *sess) -{ - struct impl *impl; - - impl = calloc(1, sizeof(*impl)); - if (impl == NULL) - return -errno; - - impl->session = sess; - - clock_gettime(CLOCK_MONOTONIC, &impl->now); - - impl->metadata = sm_metadata_new(NULL); - - start_services(impl); - - return 0; -} diff --git a/src/examples/media-session/policy-ep.c b/src/examples/media-session/policy-ep.c index f4d98dda..60ffb7da 100644 --- a/src/examples/media-session/policy-ep.c +++ b/src/examples/media-session/policy-ep.c @@ -539,13 +539,13 @@ static const struct sm_media_session_events session_events = { .rescan = session_rescan, }; -int sm_policy_ep_start(struct sm_media_session *session) +void *sm_policy_ep_start(struct sm_media_session *session) { struct impl *impl; impl = calloc(1, sizeof(struct impl)); if (impl == NULL) - return -errno; + return NULL; impl->session = session; impl->core = session->core; @@ -554,10 +554,12 @@ int sm_policy_ep_start(struct sm_media_session *session) sm_media_session_add_listener(impl->session, &impl->listener, &session_events, impl); - return 0; + return impl; } -int sm_policy_ep_stop(struct pw_core *core) +int sm_policy_ep_stop(void *data) { + struct impl *impl = data; + free(impl); return 0; } diff --git a/src/examples/media-session/stream-monitor.c b/src/examples/media-session/stream-monitor.c index 89d72cdd..ff07944b 100644 --- a/src/examples/media-session/stream-monitor.c +++ b/src/examples/media-session/stream-monitor.c @@ -270,7 +270,7 @@ static struct client_endpoint *make_endpoint(struct node *node) endpoint->info.version = PW_VERSION_ENDPOINT_INFO; endpoint->info.name = (char*)pw_properties_get(props, PW_KEY_ENDPOINT_NAME); endpoint->info.media_class = (char*)pw_properties_get(props, PW_KEY_MEDIA_CLASS); - endpoint->info.session_id = impl->session->info.id; + endpoint->info.session_id = impl->session->session->obj.id; endpoint->info.direction = node->direction; endpoint->info.flags = 0; endpoint->info.change_mask = @@ -469,8 +469,9 @@ void * sm_stream_monitor_start(struct sm_media_session *session) return impl; } -int sm_stream_monitor_stop(struct impl *impl) +int sm_stream_monitor_stop(void *data) { + struct impl *impl = data; spa_hook_remove(&impl->listener); return 0; } diff --git a/src/examples/media-session/v4l2-monitor.c b/src/examples/media-session/v4l2-monitor.c index e34c0367..c9958197 100644 --- a/src/examples/media-session/v4l2-monitor.c +++ b/src/examples/media-session/v4l2-monitor.c @@ -37,12 +37,13 @@ #include <spa/debug/dict.h> #include "pipewire/pipewire.h" -#include "pipewire/private.h" + +#include "media-session.h" struct v4l2_object; struct v4l2_node { - struct monitor *monitor; + struct impl *impl; struct v4l2_object *object; struct spa_list link; uint32_t id; @@ -54,7 +55,7 @@ struct v4l2_node { }; struct v4l2_object { - struct monitor *monitor; + struct impl *impl; struct spa_list link; uint32_t id; @@ -68,6 +69,16 @@ struct v4l2_object { struct spa_list node_list; }; +struct impl { + struct sm_media_session *session; + + struct spa_handle *handle; + struct spa_device *monitor; + struct spa_hook listener; + + struct spa_list object_list; +}; + static struct v4l2_node *v4l2_find_node(struct v4l2_object *obj, uint32_t id) { struct v4l2_node *node; @@ -94,8 +105,7 @@ static struct v4l2_node *v4l2_create_node(struct v4l2_object *obj, uint32_t id, const struct spa_device_object_info *info) { struct v4l2_node *node; - struct monitor *monitor = obj->monitor; - struct impl *impl = monitor->impl; + struct impl *impl = obj->impl; int res; const char *str; @@ -129,7 +139,7 @@ static struct v4l2_node *v4l2_create_node(struct v4l2_object *obj, uint32_t id, pw_properties_set(node->props, "factory.name", info->factory_name); - node->monitor = monitor; + node->impl = impl; node->object = obj; node->id = id; node->proxy = sm_media_session_create_object(impl->session, @@ -200,18 +210,18 @@ static const struct spa_device_events v4l2_device_events = { .object_info = v4l2_device_object_info }; -static struct v4l2_object *v4l2_find_object(struct monitor *monitor, uint32_t id) +static struct v4l2_object *v4l2_find_object(struct impl *impl, uint32_t id) { struct v4l2_object *obj; - spa_list_for_each(obj, &monitor->object_list, link) { + spa_list_for_each(obj, &impl->object_list, link) { if (obj->id == id) return obj; } return NULL; } -static void v4l2_update_object(struct monitor *monitor, struct v4l2_object *obj, +static void v4l2_update_object(struct impl *impl, struct v4l2_object *obj, const struct spa_device_object_info *info) { pw_log_debug("update object %u", obj->id); @@ -248,10 +258,9 @@ static int v4l2_update_device_props(struct v4l2_object *obj) return 0; } -static struct v4l2_object *v4l2_create_object(struct monitor *monitor, uint32_t id, +static struct v4l2_object *v4l2_create_object(struct impl *impl, uint32_t id, const struct spa_device_object_info *info) { - struct impl *impl = monitor->impl; struct pw_core *core = impl->session->core; struct v4l2_object *obj; struct spa_handle *handle; @@ -285,7 +294,7 @@ static struct v4l2_object *v4l2_create_object(struct monitor *monitor, uint32_t goto unload_handle; } - obj->monitor = monitor; + obj->impl = impl; obj->id = id; obj->handle = handle; obj->device = iface; @@ -304,7 +313,7 @@ static struct v4l2_object *v4l2_create_object(struct monitor *monitor, uint32_t spa_device_add_listener(obj->device, &obj->device_listener, &v4l2_device_events, obj); - spa_list_append(&monitor->object_list, &obj->link); + spa_list_append(&impl->object_list, &obj->link); return obj; @@ -317,7 +326,7 @@ exit: return NULL; } -static void v4l2_remove_object(struct monitor *monitor, struct v4l2_object *obj) +static void v4l2_remove_object(struct impl *impl, struct v4l2_object *obj) { pw_log_debug("remove object %u", obj->id); spa_list_remove(&obj->link); @@ -330,20 +339,20 @@ static void v4l2_remove_object(struct monitor *monitor, struct v4l2_object *obj) static void v4l2_udev_object_info(void *data, uint32_t id, const struct spa_device_object_info *info) { - struct monitor *monitor = data; + struct impl *impl = data; struct v4l2_object *obj; - obj = v4l2_find_object(monitor, id); + obj = v4l2_find_object(impl, id); if (info == NULL) { if (obj == NULL) return; - v4l2_remove_object(monitor, obj); + v4l2_remove_object(impl, obj); } else if (obj == NULL) { - if ((obj = v4l2_create_object(monitor, id, info)) == NULL) + if ((obj = v4l2_create_object(impl, id, info)) == NULL) return; } else { - v4l2_update_object(monitor, obj, info); + v4l2_update_object(impl, obj, info); } } @@ -353,36 +362,50 @@ static const struct spa_device_events v4l2_udev_callbacks = .object_info = v4l2_udev_object_info, }; -static int v4l2_start_monitor(struct impl *impl, struct monitor *monitor) +void * sm_v4l2_monitor_start(struct sm_media_session *sess) { - struct spa_handle *handle; - struct pw_core *core = impl->session->core; + struct pw_core *core = sess->core; + struct impl *impl; int res; void *iface; - handle = pw_core_load_spa_handle(core, SPA_NAME_API_V4L2_ENUM_UDEV, NULL); - if (handle == NULL) { + impl = calloc(1, sizeof(struct impl)); + if (impl == NULL) + return NULL; + + impl->session = sess; + + impl->handle = pw_core_load_spa_handle(core, SPA_NAME_API_V4L2_ENUM_UDEV, NULL); + if (impl->handle == NULL) { res = -errno; - goto out; + goto out_free; } - if ((res = spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_Device, &iface)) < 0) { + if ((res = spa_handle_get_interface(impl->handle, SPA_TYPE_INTERFACE_Device, &iface)) < 0) { pw_log_error("can't get MONITOR interface: %d", res); goto out_unload; } - monitor->impl = impl; - monitor->handle = handle; - monitor->monitor = iface; - spa_list_init(&monitor->object_list); + impl->monitor = iface; + spa_list_init(&impl->object_list); - spa_device_add_listener(monitor->monitor, &monitor->listener, - &v4l2_udev_callbacks, monitor); + spa_device_add_listener(impl->monitor, &impl->listener, + &v4l2_udev_callbacks, impl); - return 0; + return impl; - out_unload: - pw_unload_spa_handle(handle); - out: - return res; +out_unload: + pw_unload_spa_handle(impl->handle); +out_free: + free(impl); + errno = -res; + return NULL; +} + +int sm_v4l2_monitor_stop(void *data) +{ + struct impl *impl = data; + pw_unload_spa_handle(impl->handle); + free(impl); + return 0; } diff --git a/src/examples/meson.build b/src/examples/meson.build index 8b045c93..f95f3c5f 100644 --- a/src/examples/meson.build +++ b/src/examples/meson.build @@ -45,10 +45,14 @@ executable('export-spa-device', ) executable('media-session', + 'media-session/alsa-midi.c', + 'media-session/alsa-monitor.c', + 'media-session/bluez-monitor.c', 'media-session/media-session.c', - 'media-session/monitor.c', + 'media-session/metadata.c', 'media-session/stream-monitor.c', 'media-session/policy-ep.c', + 'media-session/v4l2-monitor.c', c_args : [ '-D_GNU_SOURCE' ], install: false, dependencies : [dbus_dep, pipewire_dep, alsa_dep, mathlib], diff --git a/src/modules/module-session-manager/endpoint.c b/src/modules/module-session-manager/endpoint.c index 0ec34e87..ac0c0dc1 100644 --- a/src/modules/module-session-manager/endpoint.c +++ b/src/modules/module-session-manager/endpoint.c @@ -304,6 +304,7 @@ int endpoint_init(struct endpoint *this, PW_KEY_DEVICE_ID, PW_KEY_NODE_ID, PW_KEY_MEDIA_CLASS, + PW_KEY_SESSION_ID, PW_KEY_PRIORITY_SESSION, PW_KEY_ENDPOINT_NAME, PW_KEY_ENDPOINT_CLIENT_ID, |