mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	Remove media-session from this tree
It is now available as a separate project in https://gitlab.freedesktop.org/pipewire/media-session The code required by pw-reservice has moved to src/tools/reserve.{c|h}
This commit is contained in:
		
							parent
							
								
									bd8ec29bb5
								
							
						
					
					
						commit
						1bced6b2ef
					
				
					 52 changed files with 21 additions and 16470 deletions
				
			
		| 
						 | 
				
			
			@ -69,6 +69,7 @@ summary({'Build pw-cat tool': build_pw_cat}, bool_yn: true, section: 'pw-cat/pw-
 | 
			
		|||
 | 
			
		||||
if dbus_dep.found()
 | 
			
		||||
  executable('pw-reserve',
 | 
			
		||||
    'reserve.h',
 | 
			
		||||
    'pw-reserve.c',
 | 
			
		||||
    install: true,
 | 
			
		||||
    dependencies : [dbus_dep, pipewire_dep],
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,7 +33,7 @@
 | 
			
		|||
 | 
			
		||||
#include "pipewire/pipewire.h"
 | 
			
		||||
 | 
			
		||||
#include "../media-session/reserve.c"
 | 
			
		||||
#include "reserve.c"
 | 
			
		||||
 | 
			
		||||
struct impl {
 | 
			
		||||
	struct pw_main_loop *mainloop;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										526
									
								
								src/tools/reserve.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										526
									
								
								src/tools/reserve.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,526 @@
 | 
			
		|||
/* DBus device reservation API
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef NAME
 | 
			
		||||
#define NAME "reserve"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "reserve.h"
 | 
			
		||||
 | 
			
		||||
#include <spa/utils/string.h>
 | 
			
		||||
 | 
			
		||||
#define SERVICE_PREFIX "org.freedesktop.ReserveDevice1."
 | 
			
		||||
#define OBJECT_PREFIX "/org/freedesktop/ReserveDevice1/"
 | 
			
		||||
 | 
			
		||||
static const char introspection[] =
 | 
			
		||||
	DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
 | 
			
		||||
	"<node>"
 | 
			
		||||
	" <!-- If you are looking for documentation make sure to check out\n"
 | 
			
		||||
	"      http://git.0pointer.de/?p=reserve.git;a=blob;f=reserve.txt -->\n"
 | 
			
		||||
	" <interface name=\"org.freedesktop.ReserveDevice1\">"
 | 
			
		||||
	"  <method name=\"RequestRelease\">"
 | 
			
		||||
	"   <arg name=\"priority\" type=\"i\" direction=\"in\"/>"
 | 
			
		||||
	"   <arg name=\"result\" type=\"b\" direction=\"out\"/>"
 | 
			
		||||
	"  </method>"
 | 
			
		||||
	"  <property name=\"Priority\" type=\"i\" access=\"read\"/>"
 | 
			
		||||
	"  <property name=\"ApplicationName\" type=\"s\" access=\"read\"/>"
 | 
			
		||||
	"  <property name=\"ApplicationDeviceName\" type=\"s\" access=\"read\"/>"
 | 
			
		||||
	" </interface>"
 | 
			
		||||
	" <interface name=\"org.freedesktop.DBus.Properties\">"
 | 
			
		||||
	"  <method name=\"Get\">"
 | 
			
		||||
	"   <arg name=\"interface\" direction=\"in\" type=\"s\"/>"
 | 
			
		||||
	"   <arg name=\"property\" direction=\"in\" type=\"s\"/>"
 | 
			
		||||
	"   <arg name=\"value\" direction=\"out\" type=\"v\"/>"
 | 
			
		||||
	"  </method>"
 | 
			
		||||
	" </interface>"
 | 
			
		||||
	" <interface name=\"org.freedesktop.DBus.Introspectable\">"
 | 
			
		||||
	"  <method name=\"Introspect\">"
 | 
			
		||||
	"   <arg name=\"data\" type=\"s\" direction=\"out\"/>"
 | 
			
		||||
	"  </method>"
 | 
			
		||||
	" </interface>"
 | 
			
		||||
	"</node>";
 | 
			
		||||
 | 
			
		||||
struct rd_device {
 | 
			
		||||
	DBusConnection *connection;
 | 
			
		||||
 | 
			
		||||
	int32_t priority;
 | 
			
		||||
	char *service_name;
 | 
			
		||||
	char *object_path;
 | 
			
		||||
	char *application_name;
 | 
			
		||||
	char *application_device_name;
 | 
			
		||||
 | 
			
		||||
	const struct rd_device_callbacks *callbacks;
 | 
			
		||||
	void *data;
 | 
			
		||||
 | 
			
		||||
	DBusMessage *reply;
 | 
			
		||||
 | 
			
		||||
	unsigned int filtering:1;
 | 
			
		||||
	unsigned int registered:1;
 | 
			
		||||
	unsigned int acquiring:1;
 | 
			
		||||
	unsigned int owning:1;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static dbus_bool_t add_variant(DBusMessage *m, int type, const void *data)
 | 
			
		||||
{
 | 
			
		||||
	DBusMessageIter iter, sub;
 | 
			
		||||
	char t[2];
 | 
			
		||||
 | 
			
		||||
	t[0] = (char) type;
 | 
			
		||||
	t[1] = 0;
 | 
			
		||||
 | 
			
		||||
	dbus_message_iter_init_append(m, &iter);
 | 
			
		||||
 | 
			
		||||
	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, t, &sub))
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	if (!dbus_message_iter_append_basic(&sub, type, data))
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	if (!dbus_message_iter_close_container(&iter, &sub))
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static DBusHandlerResult object_handler(DBusConnection *c, DBusMessage *m, void *userdata)
 | 
			
		||||
{
 | 
			
		||||
	struct rd_device *d = userdata;
 | 
			
		||||
	DBusError error;
 | 
			
		||||
	DBusMessage *reply = NULL;
 | 
			
		||||
 | 
			
		||||
	dbus_error_init(&error);
 | 
			
		||||
 | 
			
		||||
	if (dbus_message_is_method_call(m, "org.freedesktop.ReserveDevice1",
 | 
			
		||||
				"RequestRelease")) {
 | 
			
		||||
		int32_t priority;
 | 
			
		||||
 | 
			
		||||
		if (!dbus_message_get_args(m, &error,
 | 
			
		||||
					DBUS_TYPE_INT32, &priority,
 | 
			
		||||
					DBUS_TYPE_INVALID))
 | 
			
		||||
			goto invalid;
 | 
			
		||||
 | 
			
		||||
		pw_log_debug("%p: request release priority:%d", d, priority);
 | 
			
		||||
 | 
			
		||||
		if (!(reply = dbus_message_new_method_return(m)))
 | 
			
		||||
			goto oom;
 | 
			
		||||
 | 
			
		||||
		if (d->reply)
 | 
			
		||||
			rd_device_complete_release(d, false);
 | 
			
		||||
		d->reply = reply;
 | 
			
		||||
 | 
			
		||||
		if (priority > d->priority && d->callbacks->release)
 | 
			
		||||
			d->callbacks->release(d->data, d, 0);
 | 
			
		||||
		else
 | 
			
		||||
			rd_device_complete_release(d, false);
 | 
			
		||||
 | 
			
		||||
		return DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
 | 
			
		||||
	} else if (dbus_message_is_method_call(
 | 
			
		||||
			   m,
 | 
			
		||||
			   "org.freedesktop.DBus.Properties",
 | 
			
		||||
			   "Get")) {
 | 
			
		||||
 | 
			
		||||
		const char *interface, *property;
 | 
			
		||||
 | 
			
		||||
		if (!dbus_message_get_args( m, &error,
 | 
			
		||||
					DBUS_TYPE_STRING, &interface,
 | 
			
		||||
					DBUS_TYPE_STRING, &property,
 | 
			
		||||
					DBUS_TYPE_INVALID))
 | 
			
		||||
			goto invalid;
 | 
			
		||||
 | 
			
		||||
		if (spa_streq(interface, "org.freedesktop.ReserveDevice1")) {
 | 
			
		||||
			const char *empty = "";
 | 
			
		||||
 | 
			
		||||
			if (spa_streq(property, "ApplicationName") && d->application_name) {
 | 
			
		||||
				if (!(reply = dbus_message_new_method_return(m)))
 | 
			
		||||
					goto oom;
 | 
			
		||||
 | 
			
		||||
				if (!add_variant(reply,
 | 
			
		||||
					    DBUS_TYPE_STRING,
 | 
			
		||||
					    d->application_name ? (const char**) &d->application_name : &empty))
 | 
			
		||||
					goto oom;
 | 
			
		||||
 | 
			
		||||
			} else if (spa_streq(property, "ApplicationDeviceName")) {
 | 
			
		||||
				if (!(reply = dbus_message_new_method_return(m)))
 | 
			
		||||
					goto oom;
 | 
			
		||||
 | 
			
		||||
				if (!add_variant(reply,
 | 
			
		||||
					    DBUS_TYPE_STRING,
 | 
			
		||||
					    d->application_device_name ? (const char**) &d->application_device_name : &empty))
 | 
			
		||||
					goto oom;
 | 
			
		||||
 | 
			
		||||
			} else if (spa_streq(property, "Priority")) {
 | 
			
		||||
				if (!(reply = dbus_message_new_method_return(m)))
 | 
			
		||||
					goto oom;
 | 
			
		||||
 | 
			
		||||
				if (!add_variant(reply,
 | 
			
		||||
					    DBUS_TYPE_INT32, &d->priority))
 | 
			
		||||
					goto oom;
 | 
			
		||||
			} else {
 | 
			
		||||
				if (!(reply = dbus_message_new_error_printf(m,
 | 
			
		||||
								DBUS_ERROR_UNKNOWN_METHOD,
 | 
			
		||||
								"Unknown property %s", property)))
 | 
			
		||||
					goto oom;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (!dbus_connection_send(c, reply, NULL))
 | 
			
		||||
				goto oom;
 | 
			
		||||
 | 
			
		||||
			dbus_message_unref(reply);
 | 
			
		||||
 | 
			
		||||
			return DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
		}
 | 
			
		||||
	} else if (dbus_message_is_method_call(
 | 
			
		||||
			   m,
 | 
			
		||||
			   "org.freedesktop.DBus.Introspectable",
 | 
			
		||||
			   "Introspect")) {
 | 
			
		||||
			    const char *i = introspection;
 | 
			
		||||
 | 
			
		||||
		if (!(reply = dbus_message_new_method_return(m)))
 | 
			
		||||
			goto oom;
 | 
			
		||||
 | 
			
		||||
		if (!dbus_message_append_args(reply,
 | 
			
		||||
					DBUS_TYPE_STRING, &i,
 | 
			
		||||
					DBUS_TYPE_INVALID))
 | 
			
		||||
			goto oom;
 | 
			
		||||
 | 
			
		||||
		if (!dbus_connection_send(c, reply, NULL))
 | 
			
		||||
			goto oom;
 | 
			
		||||
 | 
			
		||||
		dbus_message_unref(reply);
 | 
			
		||||
 | 
			
		||||
		return DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
 | 
			
		||||
invalid:
 | 
			
		||||
	if (!(reply = dbus_message_new_error(m,
 | 
			
		||||
					DBUS_ERROR_INVALID_ARGS,
 | 
			
		||||
					"Invalid arguments")))
 | 
			
		||||
		goto oom;
 | 
			
		||||
 | 
			
		||||
	if (!dbus_connection_send(c, reply, NULL))
 | 
			
		||||
		goto oom;
 | 
			
		||||
 | 
			
		||||
	dbus_message_unref(reply);
 | 
			
		||||
 | 
			
		||||
	dbus_error_free(&error);
 | 
			
		||||
 | 
			
		||||
	return DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
 | 
			
		||||
oom:
 | 
			
		||||
	if (reply)
 | 
			
		||||
		dbus_message_unref(reply);
 | 
			
		||||
 | 
			
		||||
	dbus_error_free(&error);
 | 
			
		||||
 | 
			
		||||
	return DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct DBusObjectPathVTable vtable ={
 | 
			
		||||
	.message_function = object_handler
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static DBusHandlerResult filter_handler(DBusConnection *c, DBusMessage *m, void *userdata)
 | 
			
		||||
{
 | 
			
		||||
	struct rd_device *d = userdata;
 | 
			
		||||
	DBusError error;
 | 
			
		||||
	const char *name;
 | 
			
		||||
 | 
			
		||||
	dbus_error_init(&error);
 | 
			
		||||
 | 
			
		||||
	if (dbus_message_is_signal(m, "org.freedesktop.DBus", "NameAcquired")) {
 | 
			
		||||
		if (!dbus_message_get_args( m, &error,
 | 
			
		||||
			    DBUS_TYPE_STRING, &name,
 | 
			
		||||
			    DBUS_TYPE_INVALID))
 | 
			
		||||
			goto invalid;
 | 
			
		||||
 | 
			
		||||
		if (!spa_streq(name, d->service_name))
 | 
			
		||||
			goto invalid;
 | 
			
		||||
 | 
			
		||||
		pw_log_debug("%p: acquired %s, %s", d, name, d->service_name);
 | 
			
		||||
 | 
			
		||||
		d->owning = true;
 | 
			
		||||
 | 
			
		||||
		if (!d->registered) {
 | 
			
		||||
			if (!(dbus_connection_register_object_path(d->connection,
 | 
			
		||||
							d->object_path,
 | 
			
		||||
							&vtable,
 | 
			
		||||
							d)))
 | 
			
		||||
				goto invalid;
 | 
			
		||||
 | 
			
		||||
			if (!spa_streq(name, d->service_name))
 | 
			
		||||
				goto invalid;
 | 
			
		||||
 | 
			
		||||
			d->registered = true;
 | 
			
		||||
 | 
			
		||||
			if (d->callbacks->acquired)
 | 
			
		||||
				d->callbacks->acquired(d->data, d);
 | 
			
		||||
		}
 | 
			
		||||
	} else if (dbus_message_is_signal(m, "org.freedesktop.DBus", "NameLost")) {
 | 
			
		||||
		if (!dbus_message_get_args( m, &error,
 | 
			
		||||
			    DBUS_TYPE_STRING, &name,
 | 
			
		||||
			    DBUS_TYPE_INVALID))
 | 
			
		||||
			goto invalid;
 | 
			
		||||
 | 
			
		||||
		if (!spa_streq(name, d->service_name))
 | 
			
		||||
			goto invalid;
 | 
			
		||||
 | 
			
		||||
		pw_log_debug("%p: lost %s", d, name);
 | 
			
		||||
 | 
			
		||||
		d->owning = false;
 | 
			
		||||
 | 
			
		||||
		if (d->registered) {
 | 
			
		||||
			dbus_connection_unregister_object_path(d->connection,
 | 
			
		||||
					d->object_path);
 | 
			
		||||
			d->registered = false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (dbus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged")) {
 | 
			
		||||
		const char *old, *new;
 | 
			
		||||
		if (!dbus_message_get_args( m, &error,
 | 
			
		||||
			    DBUS_TYPE_STRING, &name,
 | 
			
		||||
			    DBUS_TYPE_STRING, &old,
 | 
			
		||||
			    DBUS_TYPE_STRING, &new,
 | 
			
		||||
			    DBUS_TYPE_INVALID))
 | 
			
		||||
			goto invalid;
 | 
			
		||||
 | 
			
		||||
		if (!spa_streq(name, d->service_name) || d->owning)
 | 
			
		||||
			goto invalid;
 | 
			
		||||
 | 
			
		||||
		pw_log_debug("%p: changed %s: %s -> %s", d, name, old, new);
 | 
			
		||||
 | 
			
		||||
		if (old == NULL || *old == 0) {
 | 
			
		||||
			if (d->callbacks->busy && !d->acquiring)
 | 
			
		||||
				d->callbacks->busy(d->data, d, name, 0);
 | 
			
		||||
		} else {
 | 
			
		||||
			if (d->callbacks->available)
 | 
			
		||||
				d->callbacks->available(d->data, d, name);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
invalid:
 | 
			
		||||
	dbus_error_free(&error);
 | 
			
		||||
	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct rd_device *
 | 
			
		||||
rd_device_new(DBusConnection *connection, const char *device_name, const char *application_name,
 | 
			
		||||
		int32_t priority, const struct rd_device_callbacks *callbacks, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct rd_device *d;
 | 
			
		||||
	int res;
 | 
			
		||||
 | 
			
		||||
	d = calloc(1, sizeof(struct rd_device));
 | 
			
		||||
	if (d == NULL)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	d->connection = connection;
 | 
			
		||||
	d->priority = priority;
 | 
			
		||||
	d->callbacks = callbacks;
 | 
			
		||||
	d->data = data;
 | 
			
		||||
 | 
			
		||||
	d->application_name = strdup(application_name);
 | 
			
		||||
 | 
			
		||||
	d->object_path = spa_aprintf(OBJECT_PREFIX "%s", device_name);
 | 
			
		||||
	if (d->object_path == NULL) {
 | 
			
		||||
		res = -errno;
 | 
			
		||||
		goto error_free;
 | 
			
		||||
	}
 | 
			
		||||
	d->service_name = spa_aprintf(SERVICE_PREFIX "%s", device_name);
 | 
			
		||||
	if (d->service_name == NULL) {
 | 
			
		||||
		res = -errno;
 | 
			
		||||
		goto error_free;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!dbus_connection_add_filter(d->connection,
 | 
			
		||||
				filter_handler,
 | 
			
		||||
				d,
 | 
			
		||||
				NULL)) {
 | 
			
		||||
		res = -ENOMEM;
 | 
			
		||||
		goto error_free;
 | 
			
		||||
	}
 | 
			
		||||
	dbus_bus_add_match(d->connection,
 | 
			
		||||
                        "type='signal',sender='org.freedesktop.DBus',"
 | 
			
		||||
                        "interface='org.freedesktop.DBus',member='NameLost'", NULL);
 | 
			
		||||
	dbus_bus_add_match(d->connection,
 | 
			
		||||
                        "type='signal',sender='org.freedesktop.DBus',"
 | 
			
		||||
                        "interface='org.freedesktop.DBus',member='NameAcquired'", NULL);
 | 
			
		||||
	dbus_bus_add_match(d->connection,
 | 
			
		||||
                        "type='signal',sender='org.freedesktop.DBus',"
 | 
			
		||||
                        "interface='org.freedesktop.DBus',member='NameOwnerChanged'", NULL);
 | 
			
		||||
 | 
			
		||||
	dbus_connection_ref(d->connection);
 | 
			
		||||
 | 
			
		||||
	pw_log_debug("%p: new device %s", d, device_name);
 | 
			
		||||
 | 
			
		||||
	return d;
 | 
			
		||||
 | 
			
		||||
error_free:
 | 
			
		||||
	free(d->service_name);
 | 
			
		||||
	free(d->object_path);
 | 
			
		||||
	free(d);
 | 
			
		||||
	errno = -res;
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rd_device_acquire(struct rd_device *d)
 | 
			
		||||
{
 | 
			
		||||
	int res;
 | 
			
		||||
	DBusError error;
 | 
			
		||||
 | 
			
		||||
	dbus_error_init(&error);
 | 
			
		||||
 | 
			
		||||
	pw_log_debug("%p: reserve %s", d, d->service_name);
 | 
			
		||||
 | 
			
		||||
	d->acquiring = true;
 | 
			
		||||
 | 
			
		||||
	if ((res = dbus_bus_request_name(d->connection,
 | 
			
		||||
					d->service_name,
 | 
			
		||||
					(d->priority < INT32_MAX ? DBUS_NAME_FLAG_ALLOW_REPLACEMENT : 0),
 | 
			
		||||
					&error)) < 0) {
 | 
			
		||||
			pw_log_warn("%p: reserve failed: %s", d, error.message);
 | 
			
		||||
			dbus_error_free(&error);
 | 
			
		||||
			return -EIO;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pw_log_debug("%p: reserve result: %d", d, res);
 | 
			
		||||
 | 
			
		||||
	if (res == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER ||
 | 
			
		||||
	    res == DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (res == DBUS_REQUEST_NAME_REPLY_EXISTS ||
 | 
			
		||||
	    res == DBUS_REQUEST_NAME_REPLY_IN_QUEUE)
 | 
			
		||||
		return -EBUSY;
 | 
			
		||||
 | 
			
		||||
	return -EIO;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rd_device_request_release(struct rd_device *d)
 | 
			
		||||
{
 | 
			
		||||
	DBusMessage *m = NULL;
 | 
			
		||||
 | 
			
		||||
	if (d->priority <= INT32_MIN)
 | 
			
		||||
		return -EBUSY;
 | 
			
		||||
 | 
			
		||||
	if ((m = dbus_message_new_method_call(d->service_name,
 | 
			
		||||
					d->object_path,
 | 
			
		||||
					"org.freedesktop.ReserveDevice1",
 | 
			
		||||
					"RequestRelease")) == NULL) {
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
        if (!dbus_message_append_args(m,
 | 
			
		||||
				DBUS_TYPE_INT32, &d->priority,
 | 
			
		||||
				DBUS_TYPE_INVALID)) {
 | 
			
		||||
		dbus_message_unref(m);
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
        }
 | 
			
		||||
	if (!dbus_connection_send(d->connection, m, NULL)) {
 | 
			
		||||
		return -EIO;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rd_device_complete_release(struct rd_device *d, int res)
 | 
			
		||||
{
 | 
			
		||||
	dbus_bool_t ret = res != 0;
 | 
			
		||||
 | 
			
		||||
	if (d->reply == NULL)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	pw_log_debug("%p: complete release %d", d, res);
 | 
			
		||||
 | 
			
		||||
	if (!dbus_message_append_args(d->reply,
 | 
			
		||||
				DBUS_TYPE_BOOLEAN, &ret,
 | 
			
		||||
				DBUS_TYPE_INVALID)) {
 | 
			
		||||
		res = -ENOMEM;
 | 
			
		||||
		goto exit;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!dbus_connection_send(d->connection, d->reply, NULL)) {
 | 
			
		||||
		res = -EIO;
 | 
			
		||||
		goto exit;
 | 
			
		||||
	}
 | 
			
		||||
	res = 0;
 | 
			
		||||
exit:
 | 
			
		||||
	dbus_message_unref(d->reply);
 | 
			
		||||
	d->reply = NULL;
 | 
			
		||||
	return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rd_device_release(struct rd_device *d)
 | 
			
		||||
{
 | 
			
		||||
	pw_log_debug("%p: release %d", d, d->owning);
 | 
			
		||||
 | 
			
		||||
	if (d->owning) {
 | 
			
		||||
		DBusError error;
 | 
			
		||||
		dbus_error_init(&error);
 | 
			
		||||
 | 
			
		||||
		dbus_bus_release_name(d->connection,
 | 
			
		||||
				d->service_name, &error);
 | 
			
		||||
		dbus_error_free(&error);
 | 
			
		||||
	}
 | 
			
		||||
	d->acquiring = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rd_device_destroy(struct rd_device *d)
 | 
			
		||||
{
 | 
			
		||||
	dbus_connection_remove_filter(d->connection,
 | 
			
		||||
			filter_handler, d);
 | 
			
		||||
 | 
			
		||||
	if (d->registered)
 | 
			
		||||
		dbus_connection_unregister_object_path(d->connection,
 | 
			
		||||
				d->object_path);
 | 
			
		||||
 | 
			
		||||
	rd_device_release(d);
 | 
			
		||||
 | 
			
		||||
	free(d->service_name);
 | 
			
		||||
	free(d->object_path);
 | 
			
		||||
	free(d->application_name);
 | 
			
		||||
	free(d->application_device_name);
 | 
			
		||||
	if (d->reply)
 | 
			
		||||
		dbus_message_unref(d->reply);
 | 
			
		||||
 | 
			
		||||
	dbus_connection_unref(d->connection);
 | 
			
		||||
 | 
			
		||||
	free(d);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rd_device_set_application_device_name(struct rd_device *d, const char *name)
 | 
			
		||||
{
 | 
			
		||||
	char *t;
 | 
			
		||||
 | 
			
		||||
	if (!d)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	if (!(t = strdup(name)))
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	free(d->application_device_name);
 | 
			
		||||
	d->application_device_name = t;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										82
									
								
								src/tools/reserve.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								src/tools/reserve.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,82 @@
 | 
			
		|||
/* DBus device reservation API
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef DEVICE_RESERVE_H
 | 
			
		||||
#define DEVICE_RESERVE_H
 | 
			
		||||
 | 
			
		||||
#include <dbus/dbus.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
struct rd_device;
 | 
			
		||||
 | 
			
		||||
struct rd_device_callbacks {
 | 
			
		||||
	/** the device is acquired by us */
 | 
			
		||||
	void (*acquired) (void *data, struct rd_device *d);
 | 
			
		||||
	/** request a release of the device */
 | 
			
		||||
	void (*release) (void *data, struct rd_device *d, int forced);
 | 
			
		||||
	/** the device is busy by someone else */
 | 
			
		||||
	void (*busy) (void *data, struct rd_device *d, const char *name, int32_t priority);
 | 
			
		||||
	/** the device is made available by someone else */
 | 
			
		||||
	void (*available) (void *data, struct rd_device *d, const char *name);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* create a new device and start watching */
 | 
			
		||||
struct rd_device *
 | 
			
		||||
rd_device_new(DBusConnection *connection,		/**< Bus to watch */
 | 
			
		||||
		const char *device_name,		/**< The device to lock, e.g. "Audio0" */
 | 
			
		||||
		const char *application_name,		/**< A human readable name of the application,
 | 
			
		||||
							  *  e.g. "PipeWire Server" */
 | 
			
		||||
		int32_t priority,			/**< The priority for this application.
 | 
			
		||||
							  *  If unsure use 0 */
 | 
			
		||||
		const struct rd_device_callbacks *callbacks,	/**< Called when device name is acquired/released */
 | 
			
		||||
		void *data);
 | 
			
		||||
 | 
			
		||||
/** try to acquire the device */
 | 
			
		||||
int rd_device_acquire(struct rd_device *d);
 | 
			
		||||
 | 
			
		||||
/** request the owner to release the device */
 | 
			
		||||
int rd_device_request_release(struct rd_device *d);
 | 
			
		||||
 | 
			
		||||
/** complete the release of the device */
 | 
			
		||||
int rd_device_complete_release(struct rd_device *d, int res);
 | 
			
		||||
 | 
			
		||||
/** release a device */
 | 
			
		||||
void rd_device_release(struct rd_device *d);
 | 
			
		||||
 | 
			
		||||
/** destroy a device */
 | 
			
		||||
void rd_device_destroy(struct rd_device *d);
 | 
			
		||||
 | 
			
		||||
/* Set the application device name for an rd_device object. Returns 0
 | 
			
		||||
 * on success, a negative errno style return value on error. */
 | 
			
		||||
int rd_device_set_application_device_name(struct rd_device *d, const char *name);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue