First version of D-Bus based audio device rerservation.
git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@3342 0c269be4-1314-0410-8aa9-9f06e86f4224
This commit is contained in:
parent
3e1864c4d0
commit
abf1b2bca8
|
@ -22,16 +22,17 @@ Michael Voigt
|
|||
---------------------------
|
||||
Jackdmp changes log
|
||||
---------------------------
|
||||
|
||||
|
||||
2009-02-23 Stephane Letz <letz@grame.fr>
|
||||
|
||||
* Another fix in systemdeps.h and types.h: jack_time_t now uniquely defined in types.h.
|
||||
* Another fix in systemdeps.h and types.h: jack_time_t now uniquely defined in types.h.
|
||||
* Move generic code and data in JackNetInterface and JackNetMasterInterface classes.
|
||||
* First version of D-Bus based audio device rerservation.
|
||||
|
||||
2009-02-20 Stephane Letz <letz@grame.fr>
|
||||
|
||||
* Add InitConnection and InitRendering methods in JackNetSlaveInterface, better packet type checking in JackNetSlaveInterface::SyncRecv.
|
||||
* Change fMulticastIP handling in JackNetInterface.
|
||||
* Change fMulticastIP handling in JackNetInterface.
|
||||
* Cleanup systemdeps.h on Windows.
|
||||
|
||||
2009-02-17 Stephane Letz <letz@grame.fr>
|
||||
|
|
|
@ -576,8 +576,8 @@ jackctl_wait_signals(sigset_t signals)
|
|||
// driver exit
|
||||
waiting = false;
|
||||
break;
|
||||
case SIGTTOU:
|
||||
break;
|
||||
case SIGTTOU:
|
||||
break;
|
||||
default:
|
||||
waiting = false;
|
||||
break;
|
||||
|
|
|
@ -139,6 +139,9 @@ def build(bld):
|
|||
'../posix/JackSocketServerNotifyChannel.cpp',
|
||||
'../posix/JackNetUnixSocket.cpp',
|
||||
]
|
||||
|
||||
if bld.env['IS_LINUX'] and bld.env['BUILD_JACKDBUS']:
|
||||
serverlib.source += ['../dbus/reserve.c', '../dbus/audio_reserve.c']
|
||||
|
||||
if bld.env['IS_SUN']:
|
||||
serverlib.source += [
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
/***
|
||||
Copyright 2009 Grame
|
||||
|
||||
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 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 <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "reserve.h"
|
||||
#include "audio_reserve.h"
|
||||
#include "JackError.h"
|
||||
|
||||
static DBusConnection* connection = NULL;
|
||||
|
||||
SERVER_EXPORT int audio_reservation_init()
|
||||
{
|
||||
DBusError error;
|
||||
|
||||
dbus_error_init(&error);
|
||||
|
||||
if (!(connection = dbus_bus_get(DBUS_BUS_SESSION, &error))) {
|
||||
jack_error("Failed to connect to session bus for device reservation %s\n", error.message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SERVER_EXPORT int audio_reservation_finish()
|
||||
{
|
||||
if (connection)
|
||||
dbus_connection_unref(connection);
|
||||
}
|
||||
|
||||
SERVER_EXPORT void* audio_acquire(int num)
|
||||
{
|
||||
DBusError error;
|
||||
rd_device* device;
|
||||
char audio_name[32];
|
||||
int e;
|
||||
|
||||
snprintf(audio_name, sizeof(audio_name) - 1, "Audio%d", num);
|
||||
if ((e = rd_acquire(
|
||||
&device,
|
||||
connection,
|
||||
audio_name,
|
||||
"Jack audio server",
|
||||
INT32_MAX,
|
||||
NULL,
|
||||
&error)) < 0) {
|
||||
|
||||
jack_error ("Failed to acquire device: %s\n", error.message ? error.message : strerror(-e));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jack_info("Acquire audio card %s", audio_name);
|
||||
return (void*)device;
|
||||
}
|
||||
|
||||
SERVER_EXPORT void audio_reserve_loop()
|
||||
{
|
||||
if (connection) {
|
||||
while (dbus_connection_read_write_dispatch (connection, -1))
|
||||
; // empty loop body
|
||||
}
|
||||
}
|
||||
|
||||
SERVER_EXPORT void audio_release(void* dev)
|
||||
{
|
||||
rd_device* device = (rd_device*)dev;
|
||||
if (device) {
|
||||
jack_info("Release audio card");
|
||||
rd_release(device);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
|
||||
|
||||
/***
|
||||
Copyright 2009 GRAME
|
||||
|
||||
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 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 __audio_reserve__
|
||||
#define __audio_reserve__
|
||||
|
||||
#include "JackCompilerDeps.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
SERVER_EXPORT int audio_reservation_init();
|
||||
SERVER_EXPORT int audio_reservation_finish();
|
||||
|
||||
SERVER_EXPORT void* audio_acquire(int num);
|
||||
SERVER_EXPORT void audio_release(void* dev);
|
||||
SERVER_EXPORT void audio_reserve_loop();
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,635 @@
|
|||
/***
|
||||
Copyright 2009 Lennart Poettering
|
||||
|
||||
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 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 <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "reserve.h"
|
||||
|
||||
struct rd_device {
|
||||
int ref;
|
||||
|
||||
char *device_name;
|
||||
char *application_name;
|
||||
char *application_device_name;
|
||||
char *service_name;
|
||||
char *object_path;
|
||||
int32_t priority;
|
||||
|
||||
DBusConnection *connection;
|
||||
|
||||
int owning:1;
|
||||
int registered:1;
|
||||
int filtering:1;
|
||||
int gave_up:1;
|
||||
|
||||
rd_request_cb_t request_cb;
|
||||
void *userdata;
|
||||
};
|
||||
|
||||
|
||||
#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>";
|
||||
|
||||
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) {
|
||||
|
||||
rd_device *d;
|
||||
DBusError error;
|
||||
DBusMessage *reply = NULL;
|
||||
|
||||
dbus_error_init(&error);
|
||||
|
||||
d = userdata;
|
||||
assert(d->ref >= 1);
|
||||
|
||||
if (dbus_message_is_method_call(
|
||||
m,
|
||||
"org.freedesktop.ReserveDevice1",
|
||||
"RequestRelease")) {
|
||||
|
||||
int32_t priority;
|
||||
dbus_bool_t ret;
|
||||
|
||||
if (!dbus_message_get_args(
|
||||
m,
|
||||
&error,
|
||||
DBUS_TYPE_INT32, &priority,
|
||||
DBUS_TYPE_INVALID))
|
||||
goto invalid;
|
||||
|
||||
ret = FALSE;
|
||||
|
||||
if (priority > d->priority && d->request_cb) {
|
||||
d->ref++;
|
||||
|
||||
if (d->request_cb(d, 0) > 0) {
|
||||
ret = TRUE;
|
||||
d->gave_up = 1;
|
||||
}
|
||||
|
||||
rd_release(d);
|
||||
}
|
||||
|
||||
if (!(reply = dbus_message_new_method_return(m)))
|
||||
goto oom;
|
||||
|
||||
if (!dbus_message_append_args(
|
||||
reply,
|
||||
DBUS_TYPE_BOOLEAN, &ret,
|
||||
DBUS_TYPE_INVALID))
|
||||
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.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 (strcmp(interface, "org.freedesktop.ReserveDevice1") == 0) {
|
||||
const char *empty = "";
|
||||
|
||||
if (strcmp(property, "ApplicationName") == 0 && 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 (strcmp(property, "ApplicationDeviceName") == 0) {
|
||||
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 (strcmp(property, "Priority") == 0) {
|
||||
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_unref(reply);
|
||||
|
||||
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 DBusHandlerResult filter_handler(
|
||||
DBusConnection *c,
|
||||
DBusMessage *m,
|
||||
void *userdata) {
|
||||
|
||||
DBusMessage *reply;
|
||||
rd_device *d;
|
||||
DBusError error;
|
||||
|
||||
dbus_error_init(&error);
|
||||
|
||||
d = userdata;
|
||||
|
||||
if (dbus_message_is_signal(m, "org.freedesktop.DBus", "NameLost")) {
|
||||
const char *name;
|
||||
|
||||
if (!dbus_message_get_args(
|
||||
m,
|
||||
&error,
|
||||
DBUS_TYPE_STRING, &name,
|
||||
DBUS_TYPE_INVALID))
|
||||
goto invalid;
|
||||
|
||||
if (strcmp(name, d->service_name) == 0 && d->owning) {
|
||||
d->owning = 0;
|
||||
|
||||
if (!d->gave_up) {
|
||||
d->ref++;
|
||||
|
||||
if (d->request_cb)
|
||||
d->request_cb(d, 1);
|
||||
d->gave_up = 1;
|
||||
|
||||
rd_release(d);
|
||||
}
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
int rd_acquire(
|
||||
rd_device **_d,
|
||||
DBusConnection *connection,
|
||||
const char *device_name,
|
||||
const char *application_name,
|
||||
int32_t priority,
|
||||
rd_request_cb_t request_cb,
|
||||
DBusError *error) {
|
||||
|
||||
rd_device *d = NULL;
|
||||
int r, k;
|
||||
DBusError _error;
|
||||
DBusMessage *m = NULL, *reply = NULL;
|
||||
dbus_bool_t good;
|
||||
|
||||
if (!error)
|
||||
error = &_error;
|
||||
|
||||
dbus_error_init(error);
|
||||
|
||||
if (!_d)
|
||||
return -EINVAL;
|
||||
|
||||
if (!connection)
|
||||
return -EINVAL;
|
||||
|
||||
if (!device_name)
|
||||
return -EINVAL;
|
||||
|
||||
if (!request_cb && priority != INT32_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (!(d = calloc(sizeof(rd_device), 1)))
|
||||
return -ENOMEM;
|
||||
|
||||
d->ref = 1;
|
||||
|
||||
if (!(d->device_name = strdup(device_name))) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(d->application_name = strdup(application_name))) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
d->priority = priority;
|
||||
d->connection = dbus_connection_ref(connection);
|
||||
d->request_cb = request_cb;
|
||||
|
||||
if (!(d->service_name = malloc(sizeof(SERVICE_PREFIX) + strlen(device_name)))) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
sprintf(d->service_name, SERVICE_PREFIX "%s", d->device_name);
|
||||
|
||||
if (!(d->object_path = malloc(sizeof(OBJECT_PREFIX) + strlen(device_name)))) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
sprintf(d->object_path, OBJECT_PREFIX "%s", d->device_name);
|
||||
|
||||
if ((k = dbus_bus_request_name(
|
||||
d->connection,
|
||||
d->service_name,
|
||||
DBUS_NAME_FLAG_DO_NOT_QUEUE|
|
||||
(priority < INT32_MAX ? DBUS_NAME_FLAG_ALLOW_REPLACEMENT : 0),
|
||||
error)) < 0) {
|
||||
r = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (k == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
|
||||
goto success;
|
||||
|
||||
if (k != DBUS_REQUEST_NAME_REPLY_EXISTS) {
|
||||
r = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (priority <= INT32_MIN) {
|
||||
r = -EBUSY;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(m = dbus_message_new_method_call(
|
||||
d->service_name,
|
||||
d->object_path,
|
||||
"org.freedesktop.ReserveDevice1",
|
||||
"RequestRelease"))) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!dbus_message_append_args(
|
||||
m,
|
||||
DBUS_TYPE_INT32, &d->priority,
|
||||
DBUS_TYPE_INVALID)) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(reply = dbus_connection_send_with_reply_and_block(
|
||||
d->connection,
|
||||
m,
|
||||
5000, /* 5s */
|
||||
error))) {
|
||||
|
||||
if (dbus_error_has_name(error, DBUS_ERROR_TIMED_OUT) ||
|
||||
dbus_error_has_name(error, DBUS_ERROR_UNKNOWN_METHOD) ||
|
||||
dbus_error_has_name(error, DBUS_ERROR_NO_REPLY)) {
|
||||
/* This must be treated as denied. */
|
||||
r = -EBUSY;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!dbus_message_get_args(
|
||||
reply,
|
||||
error,
|
||||
DBUS_TYPE_BOOLEAN, &good,
|
||||
DBUS_TYPE_INVALID)) {
|
||||
r = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!good) {
|
||||
r = -EBUSY;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((k = dbus_bus_request_name(
|
||||
d->connection,
|
||||
d->service_name,
|
||||
DBUS_NAME_FLAG_DO_NOT_QUEUE|
|
||||
(priority < INT32_MAX ? DBUS_NAME_FLAG_ALLOW_REPLACEMENT : 0)|
|
||||
DBUS_NAME_FLAG_REPLACE_EXISTING,
|
||||
error)) < 0) {
|
||||
r = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (k != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
|
||||
r = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
success:
|
||||
d->owning = 1;
|
||||
|
||||
if (!(dbus_connection_register_object_path(
|
||||
d->connection,
|
||||
d->object_path,
|
||||
&vtable,
|
||||
d))) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
d->registered = 1;
|
||||
|
||||
if (!dbus_connection_add_filter(
|
||||
d->connection,
|
||||
filter_handler,
|
||||
d,
|
||||
NULL)) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
d->filtering = 1;
|
||||
|
||||
*_d = d;
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (m)
|
||||
dbus_message_unref(m);
|
||||
|
||||
if (reply)
|
||||
dbus_message_unref(reply);
|
||||
|
||||
if (&_error == error)
|
||||
dbus_error_free(&_error);
|
||||
|
||||
if (d)
|
||||
rd_release(d);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void rd_release(
|
||||
rd_device *d) {
|
||||
|
||||
if (!d)
|
||||
return;
|
||||
|
||||
assert(d->ref > 0);
|
||||
|
||||
if (--d->ref)
|
||||
return;
|
||||
|
||||
|
||||
if (d->filtering)
|
||||
dbus_connection_remove_filter(
|
||||
d->connection,
|
||||
filter_handler,
|
||||
d);
|
||||
|
||||
if (d->registered)
|
||||
dbus_connection_unregister_object_path(
|
||||
d->connection,
|
||||
d->object_path);
|
||||
|
||||
if (d->owning) {
|
||||
DBusError error;
|
||||
dbus_error_init(&error);
|
||||
|
||||
dbus_bus_release_name(
|
||||
d->connection,
|
||||
d->service_name,
|
||||
&error);
|
||||
|
||||
dbus_error_free(&error);
|
||||
}
|
||||
|
||||
free(d->device_name);
|
||||
free(d->application_name);
|
||||
free(d->application_device_name);
|
||||
free(d->service_name);
|
||||
free(d->object_path);
|
||||
|
||||
if (d->connection)
|
||||
dbus_connection_unref(d->connection);
|
||||
|
||||
free(d);
|
||||
}
|
||||
|
||||
int rd_set_application_device_name(rd_device *d, const char *n) {
|
||||
char *t;
|
||||
|
||||
if (!d)
|
||||
return -EINVAL;
|
||||
|
||||
assert(d->ref > 0);
|
||||
|
||||
if (!(t = strdup(n)))
|
||||
return -ENOMEM;
|
||||
|
||||
free(d->application_device_name);
|
||||
d->application_device_name = t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rd_set_userdata(rd_device *d, void *userdata) {
|
||||
|
||||
if (!d)
|
||||
return;
|
||||
|
||||
assert(d->ref > 0);
|
||||
d->userdata = userdata;
|
||||
}
|
||||
|
||||
void* rd_get_userdata(rd_device *d) {
|
||||
|
||||
if (!d)
|
||||
return NULL;
|
||||
|
||||
assert(d->ref > 0);
|
||||
|
||||
return d->userdata;
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
#ifndef fooreservehfoo
|
||||
#define fooreservehfoo
|
||||
|
||||
/***
|
||||
Copyright 2009 Lennart Poettering
|
||||
|
||||
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 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 <dbus/dbus.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
typedef struct rd_device rd_device;
|
||||
|
||||
/* Prototype for a function that is called whenever someone else wants
|
||||
* your application to release the device it has locked. A return
|
||||
* value <= 0 denies the request, a positive return value agrees to
|
||||
* it. Before returning your application should close the device in
|
||||
* question completely to make sure the new application may access
|
||||
* it. */
|
||||
typedef int (*rd_request_cb_t)(
|
||||
rd_device *d,
|
||||
int forced); /* Non-zero if an application forcibly took the lock away without asking. If this is the case then the return value of this call is ignored. */
|
||||
|
||||
/* Try to lock the device. Returns 0 on success, a negative errno
|
||||
* style return value on error. The DBus error might be set as well if
|
||||
* the error was caused D-Bus. */
|
||||
int rd_acquire(
|
||||
rd_device **d, /* On success a pointer to the newly allocated rd_device object will be filled in here */
|
||||
DBusConnection *connection,
|
||||
const char *device_name, /* The device to lock, e.g. "Audio0" */
|
||||
const char *application_name, /* A human readable name of the application, e.g. "PulseAudio Sound Server" */
|
||||
int32_t priority, /* The priority for this application. If unsure use 0 */
|
||||
rd_request_cb_t request_cb, /* Will be called whenever someone requests that this device shall be released. May be NULL if priority is INT32_MAX */
|
||||
DBusError *error); /* If we fail due to a D-Bus related issue the error will be filled in here. May be NULL. */
|
||||
|
||||
/* Unlock (if needed) and destroy an rd_device object again */
|
||||
void rd_release(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_set_application_device_name(rd_device *d, const char *name);
|
||||
|
||||
/* Attach a userdata pointer to an rd_device */
|
||||
void rd_set_userdata(rd_device *d, void *userdata);
|
||||
|
||||
/* Query the userdata pointer from an rd_device. Returns NULL if no
|
||||
* userdata was set. */
|
||||
void* rd_get_userdata(rd_device *d);
|
||||
|
||||
#endif
|
|
@ -49,7 +49,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|||
#include "generic.h"
|
||||
#include "memops.h"
|
||||
|
||||
|
||||
#include "audio_reserve.h"
|
||||
|
||||
namespace Jack
|
||||
{
|
||||
|
@ -2170,6 +2170,29 @@ int JackAlsaDriver::Open(jack_nframes_t nframes,
|
|||
else if (strcmp(midi_driver_name, "raw") == 0)
|
||||
midi = alsa_rawmidi_new((jack_client_t*)this);
|
||||
|
||||
#if defined(JACK_DBUS)
|
||||
if (audio_reservation_init() < 0) {
|
||||
jack_error("Audio reservation sevice not available....");
|
||||
} else if (strcmp(capture_driver_name, playback_driver_name) == 0) { // Same device for input and output
|
||||
fReservedCaptureDevice = audio_acquire(0);
|
||||
if (fReservedCaptureDevice == NULL) {
|
||||
jack_error("Error audio device %s not available...", capture_driver_name);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
fReservedCaptureDevice = audio_acquire(0);
|
||||
if (fReservedCaptureDevice == NULL) {
|
||||
jack_error("Error capture audio device %s not available...", capture_driver_name);
|
||||
return -1;
|
||||
}
|
||||
fReservedPlaybackDevice = audio_acquire(0);
|
||||
if (fReservedPlaybackDevice == NULL) {
|
||||
jack_error("Error playback audio device %s not available...", playback_driver_name);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
fDriver = alsa_driver_new ("alsa_pcm", (char*)playback_driver_name, (char*)capture_driver_name,
|
||||
NULL,
|
||||
nframes,
|
||||
|
@ -2203,6 +2226,11 @@ int JackAlsaDriver::Close()
|
|||
{
|
||||
JackAudioDriver::Close();
|
||||
alsa_driver_delete((alsa_driver_t*)fDriver);
|
||||
#if defined(JACK_DBUS)
|
||||
audio_release(fReservedCaptureDevice);
|
||||
audio_release(fReservedPlaybackDevice);
|
||||
audio_reservation_finish();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,8 @@ class JackAlsaDriver : public JackAudioDriver
|
|||
private:
|
||||
|
||||
jack_driver_t* fDriver;
|
||||
void* fReservedCaptureDevice;
|
||||
void* fReservedPlaybackDevice;
|
||||
|
||||
void alsa_driver_release_channel_dependent_memory(alsa_driver_t *driver);
|
||||
int alsa_driver_check_capabilities(alsa_driver_t *driver);
|
||||
|
@ -116,7 +118,11 @@ class JackAlsaDriver : public JackAudioDriver
|
|||
|
||||
public:
|
||||
|
||||
JackAlsaDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table): JackAudioDriver(name, alias, engine, table)
|
||||
JackAlsaDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table)
|
||||
: JackAudioDriver(name, alias, engine, table)
|
||||
,fDriver(NULL)
|
||||
,fReservedCaptureDevice(NULL)
|
||||
,fReservedPlaybackDevice(NULL)
|
||||
{}
|
||||
virtual ~JackAlsaDriver()
|
||||
{}
|
||||
|
|
|
@ -16,7 +16,7 @@ def create_jack_driver_obj(bld, target, sources, uselib = None):
|
|||
driver.features.append('cc')
|
||||
driver.env['shlib_PATTERN'] = 'jack_%s.so'
|
||||
driver.defines = ['HAVE_CONFIG_H','SERVER_SIDE']
|
||||
driver.includes = ['.', '../linux', '../posix', '../common', '../common/jack']
|
||||
driver.includes = ['.', '../linux', '../posix', '../common', '../common/jack', '../dbus']
|
||||
driver.target = target
|
||||
driver.source = sources
|
||||
driver.install_path = '${ADDON_DIR}/'
|
||||
|
@ -26,7 +26,7 @@ def create_jack_driver_obj(bld, target, sources, uselib = None):
|
|||
|
||||
def build(bld):
|
||||
jackd = bld.new_task_gen('cxx', 'program')
|
||||
jackd.includes = ['../linux', '../posix', '../common/jack', '../common']
|
||||
jackd.includes = ['../linux', '../posix', '../common/jack', '../common', '../dbus']
|
||||
jackd.defines = 'HAVE_CONFIG_H'
|
||||
jackd.source = ['../common/Jackdmp.cpp']
|
||||
jackd.uselib = 'PTHREAD DL RT'
|
||||
|
|
Loading…
Reference in New Issue