mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	media-session: make the services more modular
This commit is contained in:
		
							parent
							
								
									b7aa8f5c85
								
							
						
					
					
						commit
						80ac755670
					
				
					 13 changed files with 567 additions and 354 deletions
				
			
		| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										89
									
								
								src/examples/media-session/alsa-midi.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								src/examples/media-session/alsa-midi.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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,62 +659,6 @@ static const struct spa_device_events alsa_udev_events =
 | 
			
		|||
	.object_info = alsa_udev_object_info,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int alsa_start_midi_bridge(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",
 | 
			
		||||
			NULL);
 | 
			
		||||
 | 
			
		||||
	impl->midi_bridge = sm_media_session_create_object(impl->session,
 | 
			
		||||
				"spa-node-factory",
 | 
			
		||||
				PW_TYPE_INTERFACE_Node,
 | 
			
		||||
				PW_VERSION_NODE_PROXY,
 | 
			
		||||
				&props->dict,
 | 
			
		||||
                                0);
 | 
			
		||||
 | 
			
		||||
	if (impl->midi_bridge == NULL)
 | 
			
		||||
		res = -errno;
 | 
			
		||||
 | 
			
		||||
	return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int alsa_start_monitor(struct impl *impl, struct monitor *monitor)
 | 
			
		||||
{
 | 
			
		||||
	struct spa_handle *handle;
 | 
			
		||||
	struct pw_core *core = impl->session->core;
 | 
			
		||||
	int res;
 | 
			
		||||
	void *iface;
 | 
			
		||||
 | 
			
		||||
	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_Device, &iface)) < 0) {
 | 
			
		||||
		pw_log_error("can't get udev Device interface: %d", res);
 | 
			
		||||
		goto out_unload;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
      out_unload:
 | 
			
		||||
	pw_unload_spa_handle(handle);
 | 
			
		||||
      out:
 | 
			
		||||
	return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int alsa_start_jack_device(struct impl *impl)
 | 
			
		||||
{
 | 
			
		||||
	struct pw_properties *props;
 | 
			
		||||
| 
						 | 
				
			
			@ -722,3 +681,58 @@ static int alsa_start_jack_device(struct impl *impl)
 | 
			
		|||
 | 
			
		||||
	return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *sm_alsa_monitor_start(struct sm_media_session *session)
 | 
			
		||||
{
 | 
			
		||||
	struct pw_core *core = session->core;
 | 
			
		||||
	struct impl *impl;
 | 
			
		||||
	void *iface;
 | 
			
		||||
	int res;
 | 
			
		||||
 | 
			
		||||
	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_free;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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);
 | 
			
		||||
 | 
			
		||||
	if ((res = alsa_start_jack_device(impl)) < 0)
 | 
			
		||||
		goto out_unload;
 | 
			
		||||
 | 
			
		||||
	return impl;
 | 
			
		||||
 | 
			
		||||
out_unload:
 | 
			
		||||
	pw_unload_spa_handle(impl->handle);
 | 
			
		||||
out_free:
 | 
			
		||||
	free(impl);
 | 
			
		||||
	errno = -res;
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int sm_alsa_monitor_stop(void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct impl *impl = data;
 | 
			
		||||
	pw_unload_spa_handle(impl->handle);
 | 
			
		||||
	free(impl);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	spa_device_add_listener(monitor->monitor, &monitor->listener,
 | 
			
		||||
			&bluez5_enum_callbacks, monitor);
 | 
			
		||||
	impl->session = session;
 | 
			
		||||
	impl->handle = handle;
 | 
			
		||||
	impl->monitor = iface;
 | 
			
		||||
	spa_list_init(&impl->object_list);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
	spa_device_add_listener(impl->monitor, &impl->listener,
 | 
			
		||||
			&bluez5_enum_callbacks, impl);
 | 
			
		||||
 | 
			
		||||
	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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			@ -383,6 +392,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
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
			&info);
 | 
			
		||||
 | 
			
		||||
	return sm_monitor_start(&impl->this);
 | 
			
		||||
	/* 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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue