Browse Source

Merge branch 'js-dbus'

git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@4525 0c269be4-1314-0410-8aa9-9f06e86f4224
tags/1.9.8
nedko 14 years ago
parent
commit
ad47e933a3
17 changed files with 794 additions and 102 deletions
  1. +14
    -10
      common/JackClient.cpp
  2. +1
    -1
      common/JackClient.h
  3. +28
    -16
      common/JackEngine.cpp
  4. +4
    -4
      common/JackEngine.h
  5. +36
    -1
      common/JackInternalClientChannel.h
  6. +4
    -4
      common/JackLockedEngine.h
  7. +69
    -15
      common/JackRequest.h
  8. +31
    -3
      dbus/controller.c
  9. +573
    -0
      dbus/controller_iface_session_manager.c
  10. +15
    -0
      dbus/controller_internal.h
  11. +6
    -0
      dbus/jackdbus.c
  12. +1
    -0
      dbus/wscript
  13. +7
    -7
      example-clients/session_notify.c
  14. +1
    -18
      posix/JackSocketClientChannel.cpp
  15. +2
    -3
      posix/JackSocketServerChannel.cpp
  16. +1
    -18
      windows/JackWinNamedPipeClientChannel.cpp
  17. +1
    -2
      windows/JackWinNamedPipeServerChannel.cpp

+ 14
- 10
common/JackClient.cpp View File

@@ -81,6 +81,8 @@ JackClient::JackClient(JackSynchro* table):fThread(this)
fThreadFunArg = NULL;
fSessionArg = NULL;
fLatencyArg = NULL;

fSessionReply = kPendingSessionReply;
}

JackClient::~JackClient()
@@ -286,17 +288,18 @@ int JackClient::ClientNotify(int refnum, const char* name, int notify, int sync,
case kSessionCallback:
jack_log("JackClient::kSessionCallback");
if (fSession) {
jack_session_event_t *event = (jack_session_event_t *) malloc( sizeof(jack_session_event_t) );
jack_session_event_t* event = (jack_session_event_t*)malloc( sizeof(jack_session_event_t));
char uuid_buf[JACK_UUID_SIZE];
event->type = (jack_session_event_type_t) value1;
event->session_dir = strdup( message );
event->type = (jack_session_event_type_t)value1;
event->session_dir = strdup(message);
event->command_line = NULL;
event->flags = (jack_session_flags_t) 0;
snprintf( uuid_buf, sizeof(uuid_buf), "%d", GetClientControl()->fSessionID );
event->client_uuid = strdup( uuid_buf );
fImmediateSessionReply = false;
event->flags = (jack_session_flags_t)0;
snprintf(uuid_buf, sizeof(uuid_buf), "%d", GetClientControl()->fSessionID);
event->client_uuid = strdup(uuid_buf);
fSessionReply = kPendingSessionReply;
// Session callback may change fSessionReply by directly using jack_session_reply
fSession(event, fSessionArg);
res = (fImmediateSessionReply) ? 1 : 2;
res = fSessionReply;
}
break;

@@ -1234,8 +1237,9 @@ int JackClient::SessionReply(jack_session_event_t* ev)

jack_log("JackClient::SessionReply... we are here");
if (fChannel->IsChannelThread()) {
jack_log( "JackClient::SessionReply... in callback reply");
fImmediateSessionReply = true;
jack_log("JackClient::SessionReply... in callback reply");
// OK, immediate reply...
fSessionReply = kImmediateSessionReply;
return 0;
}



+ 1
- 1
common/JackClient.h View File

@@ -93,7 +93,7 @@ class SERVER_EXPORT JackClient : public JackClientInterface, public JackRunnable
JackSynchro* fSynchroTable;
std::list<jack_port_id_t> fPortList;

bool fImmediateSessionReply;
JackSessionReply fSessionReply;

int StartThread();
void SetupDriverSync(bool freewheel);


+ 28
- 16
common/JackEngine.cpp View File

@@ -932,12 +932,15 @@ int JackEngine::PortRename(int refnum, jack_port_id_t port, const char* name)
// Session management
//--------------------

void JackEngine::SessionNotify(int refnum, const char *target, jack_session_event_type_t type, const char *path, JackChannelTransaction *socket)
void JackEngine::SessionNotify(int refnum, const char *target, jack_session_event_type_t type, const char *path, JackChannelTransaction *socket, JackSessionNotifyResult** result)
{
if (fSessionPendingReplies != 0) {
JackSessionNotifyResult res(-1);
res.Write(socket);
jack_log("JackEngine::SessionNotify ... busy");
if (result != NULL) {
*result = NULL;
}
return;
}

@@ -961,30 +964,36 @@ void JackEngine::SessionNotify(int refnum, const char *target, jack_session_even
}

char path_buf[JACK_PORT_NAME_SIZE];
snprintf( path_buf, sizeof(path_buf), "%s%s%c", path, client->GetClientControl()->fName, DIR_SEPARATOR );
snprintf(path_buf, sizeof(path_buf), "%s%s%c", path, client->GetClientControl()->fName, DIR_SEPARATOR);

int res = JackTools::MkDir(path_buf);
if (res)
jack_error( "JackEngine::SessionNotify: can not create session directory '%s'", path_buf );
jack_error("JackEngine::SessionNotify: can not create session directory '%s'", path_buf);

int result = client->ClientNotify(i, client->GetClientControl()->fName, kSessionCallback, true, path_buf, (int) type, 0);
int result = client->ClientNotify(i, client->GetClientControl()->fName, kSessionCallback, true, path_buf, (int)type, 0);

if (result == 2) {
if (result == kPendingSessionReply) {
fSessionPendingReplies += 1;
} else if (result == 1) {
} else if (result == kImmediateSessionReply) {
char uuid_buf[JACK_UUID_SIZE];
snprintf( uuid_buf, sizeof(uuid_buf), "%d", client->GetClientControl()->fSessionID );
fSessionResult->fCommandList.push_back( JackSessionCommand( uuid_buf,
client->GetClientControl()->fName,
client->GetClientControl()->fSessionCommand,
client->GetClientControl()->fSessionFlags ));
snprintf(uuid_buf, sizeof(uuid_buf), "%d", client->GetClientControl()->fSessionID);
fSessionResult->fCommandList.push_back(JackSessionCommand(uuid_buf,
client->GetClientControl()->fName,
client->GetClientControl()->fSessionCommand,
client->GetClientControl()->fSessionFlags));
}
}
}

if (result != NULL) {
*result = fSessionResult;
}

if (fSessionPendingReplies == 0) {
fSessionResult->Write(socket);
delete fSessionResult;
if (result == NULL) {
delete fSessionResult;
}
fSessionResult = NULL;
} else {
fSessionTransaction = socket;
@@ -995,7 +1004,7 @@ void JackEngine::SessionReply(int refnum)
{
JackClientInterface* client = fClientTable[refnum];
char uuid_buf[JACK_UUID_SIZE];
snprintf( uuid_buf, sizeof(uuid_buf), "%d", client->GetClientControl()->fSessionID);
snprintf(uuid_buf, sizeof(uuid_buf), "%d", client->GetClientControl()->fSessionID);
fSessionResult->fCommandList.push_back(JackSessionCommand(uuid_buf,
client->GetClientControl()->fName,
client->GetClientControl()->fSessionCommand,
@@ -1004,7 +1013,10 @@ void JackEngine::SessionReply(int refnum)

if (fSessionPendingReplies == 0) {
fSessionResult->Write(fSessionTransaction);
delete fSessionResult;
if (fSessionTransaction != NULL)
{
delete fSessionResult;
}
fSessionResult = NULL;
}
}
@@ -1060,11 +1072,11 @@ void JackEngine::ReserveClientName(const char *name, const char *uuid, int *resu
*result = 0;
}

void JackEngine::ClientHasSessionCallbackRequest(const char *name, int *result)
void JackEngine::ClientHasSessionCallback(const char *name, int *result)
{
JackClientInterface* client = NULL;
for (int i = 0; i < CLIENT_NUM; i++) {
JackClientInterface* client = fClientTable[i];
client = fClientTable[i];
if (client && (strcmp(client->GetClientControl()->fName, name) == 0))
break;
}


+ 4
- 4
common/JackEngine.h View File

@@ -54,8 +54,8 @@ class SERVER_EXPORT JackEngine : public JackLockAble
jack_time_t fLastSwitchUsecs;

int fSessionPendingReplies;
JackChannelTransaction *fSessionTransaction;
JackSessionNotifyResult *fSessionResult;
JackChannelTransaction* fSessionTransaction;
JackSessionNotifyResult* fSessionResult;
std::map<int,std::string> fReservationMap;
int fMaxUUID;

@@ -145,13 +145,13 @@ class SERVER_EXPORT JackEngine : public JackLockAble
void NotifyQuit();

// Session management
void SessionNotify(int refnum, const char *target, jack_session_event_type_t type, const char *path, JackChannelTransaction *socket);
void SessionNotify(int refnum, const char *target, jack_session_event_type_t type, const char *path, JackChannelTransaction *socket, JackSessionNotifyResult** result);
void SessionReply(int refnum);

void GetUUIDForClientName(const char *client_name, char *uuid_res, int *result);
void GetClientNameForUUID(const char *uuid, char *name_res, int *result);
void ReserveClientName(const char *name, const char *uuid, int *result);
void ClientHasSessionCallbackRequest(const char *name, int *result);
void ClientHasSessionCallback(const char *name, int *result);
};




+ 36
- 1
common/JackInternalClientChannel.h View File

@@ -146,7 +146,42 @@ class JackInternalClientChannel : public detail::JackClientChannelInterface

void SessionNotify(int refnum, const char *target, jack_session_event_type_t type, const char *path, jack_session_command_t** result)
{
*result = NULL;
JackSessionNotifyResult* res;
fEngine->SessionNotify(refnum, target, type, path, NULL, &res);
if (res == NULL)
{
*result = NULL;
return;
}

*result = res->GetCommands();
delete(res);
}

void SessionReply(int refnum, int* result)
{
fEngine->SessionReply(refnum);
*result = 0;
}

void GetUUIDForClientName(int refnum, const char* client_name, char* uuid_res, int* result)
{
fEngine->GetUUIDForClientName(client_name, uuid_res, result);
}

void GetClientNameForUUID(int refnum, const char* uuid, char* name_res, int* result)
{
fEngine->GetClientNameForUUID(uuid, name_res, result);
}

void ReserveClientName(int refnum, const char* client_name, const char *uuid, int* result)
{
fEngine->ReserveClientName(client_name, uuid, result);
}

void ClientHasSessionCallback(const char* client_name, int* result)
{
fEngine->ClientHasSessionCallback(client_name, result);
}




+ 4
- 4
common/JackLockedEngine.h View File

@@ -325,11 +325,11 @@ class SERVER_EXPORT JackLockedEngine
CATCH_EXCEPTION
}

void SessionNotify(int refnum, const char* target, jack_session_event_type_t type, const char *path, JackChannelTransaction *socket)
void SessionNotify(int refnum, const char* target, jack_session_event_type_t type, const char *path, JackChannelTransaction *socket, JackSessionNotifyResult** result)
{
TRY_CALL
JackLock lock(&fEngine);
fEngine.SessionNotify(refnum, target, type, path, socket);
fEngine.SessionNotify(refnum, target, type, path, socket, result);
CATCH_EXCEPTION
}

@@ -363,11 +363,11 @@ class SERVER_EXPORT JackLockedEngine
CATCH_EXCEPTION
}

void ClientHasSessionCallbackRequest(const char *name, int *result)
void ClientHasSessionCallback(const char *name, int *result)
{
TRY_CALL
JackLock lock(&fEngine);
fEngine.ClientHasSessionCallbackRequest(name, result);
fEngine.ClientHasSessionCallback(name, result);
CATCH_EXCEPTION
}
};


+ 69
- 15
common/JackRequest.h View File

@@ -23,15 +23,28 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

#include "JackConstants.h"
#include "JackPlatformPlug.h"
#include "JackTime.h"
#include "types.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <list>

namespace Jack
{

#define CheckRes(exp) { if ((exp) < 0) return -1;}
#define CheckRes(exp) { if ((exp) < 0) return -1; }

/*!
\brief Session API constants.
*/

enum JackSessionReply {

kImmediateSessionReply = 1,
kPendingSessionReply = 2

};

/*!
\brief Request from client to server.
@@ -1122,11 +1135,11 @@ struct JackSessionCommand
JackSessionCommand()
{}

JackSessionCommand( const char *uuid, const char *clientname, const char *command, jack_session_flags_t flags )
JackSessionCommand(const char *uuid, const char *clientname, const char *command, jack_session_flags_t flags)
{
strncpy( fUUID, uuid, sizeof(fUUID));
strncpy( fClientName, clientname, sizeof(fClientName));
strncpy( fCommand, command, sizeof(fCommand));
strncpy(fUUID, uuid, sizeof(fUUID));
strncpy(fClientName, clientname, sizeof(fClientName));
strncpy(fCommand, command, sizeof(fCommand));
fFlags = flags;
}
};
@@ -1135,17 +1148,23 @@ struct JackSessionNotifyResult : public JackResult
{

std::list<JackSessionCommand> fCommandList;
bool fDone;

JackSessionNotifyResult(): JackResult()
JackSessionNotifyResult(): JackResult(), fDone(false)
{}
JackSessionNotifyResult(int32_t result)
: JackResult(result)
: JackResult(result), fDone(false)
{}

int Read(JackChannelTransaction* trans)
{
if (trans == NULL)
{
return 0;
}

CheckRes(JackResult::Read(trans));
while(1) {
while (true) {
JackSessionCommand buffer;

CheckRes(trans->Read(buffer.fUUID, sizeof(buffer.fUUID)));
@@ -1158,16 +1177,25 @@ struct JackSessionNotifyResult : public JackResult

fCommandList.push_back(buffer);
}

fDone = true;

return 0;
}

int Write(JackChannelTransaction* trans)
{
if (trans == NULL)
{
fDone = true;
return 0;
}

char terminator[JACK_UUID_SIZE];
terminator[0] = '\0';

CheckRes(JackResult::Write(trans));
for (std::list<JackSessionCommand>::iterator i=fCommandList.begin(); i!=fCommandList.end(); i++) {
for (std::list<JackSessionCommand>::iterator i = fCommandList.begin(); i != fCommandList.end(); i++) {
CheckRes(trans->Write(i->fUUID, sizeof(i->fUUID)));
CheckRes(trans->Write(i->fClientName, sizeof(i->fClientName)));
CheckRes(trans->Write(i->fCommand, sizeof(i->fCommand)));
@@ -1177,6 +1205,32 @@ struct JackSessionNotifyResult : public JackResult
return 0;
}

jack_session_command_t* GetCommands()
{
/* TODO: some kind of signal should be used instead */
while (!fDone)
{
JackSleep(50000); /* 50 ms */
}

jack_session_command_t* session_command = (jack_session_command_t *)malloc(sizeof(jack_session_command_t) * (fCommandList.size() + 1));
int i = 0;

for (std::list<JackSessionCommand>::iterator ci = fCommandList.begin(); ci != fCommandList.end(); ci++) {
session_command[i].uuid = strdup(ci->fUUID);
session_command[i].client_name = strdup(ci->fClientName);
session_command[i].command = strdup(ci->fCommand);
session_command[i].flags = ci->fFlags;
i += 1;
}

session_command[i].uuid = NULL;
session_command[i].client_name = NULL;
session_command[i].command = NULL;
session_command[i].flags = (jack_session_flags_t)0;

return session_command;
}
};

/*!
@@ -1187,19 +1241,20 @@ struct JackSessionNotifyRequest : public JackRequest
{
char fPath[JACK_MESSAGE_SIZE + 1];
char fDst[JACK_CLIENT_NAME_SIZE + 1];
jack_session_event_type_t fEventType;
int fRefNum;
jack_session_event_type_t fEventType;
int fRefNum;

JackSessionNotifyRequest()
{}
JackSessionNotifyRequest(int refnum, const char *path, jack_session_event_type_t type, const char *dst)
JackSessionNotifyRequest(int refnum, const char* path, jack_session_event_type_t type, const char* dst)
: JackRequest(JackRequest::kSessionNotify), fEventType(type), fRefNum(refnum)
{
snprintf(fPath, sizeof(fPath), "%s", path);
if (dst)
if (dst) {
snprintf(fDst, sizeof(fDst), "%s", dst);
else
} else {
fDst[0] = '\0';
}
}

int Read(JackChannelTransaction* trans)
@@ -1279,7 +1334,6 @@ struct JackClientNameResult : public JackResult

struct JackUUIDResult : public JackResult
{

char fUUID[JACK_UUID_SIZE];

JackUUIDResult(): JackResult()


+ 31
- 3
dbus/controller.c View File

@@ -26,6 +26,7 @@
#include <string.h>
#include <dbus/dbus.h>
#include <assert.h>
#include <unistd.h>

#include "controller.h"
#include "controller_internal.h"
@@ -38,6 +39,7 @@ struct jack_dbus_interface_descriptor * g_jackcontroller_interfaces[] =
&g_jack_controller_iface_control,
&g_jack_controller_iface_configure,
&g_jack_controller_iface_patchbay,
&g_jack_controller_iface_session_manager,
&g_jack_controller_iface_transport,
NULL
};
@@ -286,6 +288,15 @@ jack_controller_stop_server(
{
int ret;

pthread_mutex_lock(&controller_ptr->lock);
if (!list_empty(&controller_ptr->session_pending_commands))
{
pthread_mutex_unlock(&controller_ptr->lock);
jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "Refusing to stop JACK server because of pending session commands");
return false;
}
pthread_mutex_unlock(&controller_ptr->lock);

jack_info("Stopping jack server...");

assert(controller_ptr->started); /* should be ensured by caller */
@@ -506,6 +517,7 @@ void *
jack_controller_create(
DBusConnection *connection)
{
int error;
struct jack_controller *controller_ptr;
const char * address[PARAM_ADDRESS_SIZE];
DBusObjectPathVTable vtable =
@@ -522,11 +534,20 @@ jack_controller_create(
goto fail;
}

error = pthread_mutex_init(&controller_ptr->lock, NULL);
if (error != 0)
{
jack_error("Failed to initialize mutex. error %d", error);
goto fail_free;
}

INIT_LIST_HEAD(&controller_ptr->session_pending_commands);

controller_ptr->server = jackctl_server_create(on_device_acquire, on_device_release);
if (controller_ptr->server == NULL)
{
jack_error("Failed to create server object");
goto fail_free;
goto fail_uninit_mutex;
}

controller_ptr->params = jack_params_create(controller_ptr->server);
@@ -584,6 +605,9 @@ fail_destroy_params:
fail_destroy_server:
jackctl_server_destroy(controller_ptr->server);

fail_uninit_mutex:
pthread_mutex_destroy(&controller_ptr->lock);

fail_free:
free(controller_ptr);

@@ -738,13 +762,17 @@ jack_controller_destroy(
{
if (controller_ptr->started)
{
jack_controller_stop_server(controller_ptr, NULL);
while (!jack_controller_stop_server(controller_ptr, NULL))
{
jack_info("jack server failed to stop, retrying in 3 seconds...");
usleep(3000000);
}
}

jack_controller_remove_slave_drivers(controller_ptr);
jack_params_destroy(controller_ptr->params);
jackctl_server_destroy(controller_ptr->server);
pthread_mutex_destroy(&controller_ptr->lock);
free(controller_ptr);
}


+ 573
- 0
dbus/controller_iface_session_manager.c View File

@@ -0,0 +1,573 @@
/* -*- Mode: C ; c-basic-offset: 4 -*- */
/*
Copyright (C) 2011 Nedko Arnaudov

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

#if defined(HAVE_CONFIG_H)
#include "config.h"
#endif

#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <dbus/dbus.h>

#include "jackdbus.h"
#include "controller_internal.h"
#include "jack/session.h"
#include "common/JackError.h"

#define JACK_DBUS_IFACE_NAME "org.jackaudio.SessionManager"

static
void
jack_controller_control_send_signal_session_state_changed(
jack_session_event_type_t type,
const char * target)
{
dbus_uint32_t u32;

u32 = type;
if (target == NULL)
{
target = "";
}

jack_dbus_send_signal(
JACK_CONTROLLER_OBJECT_PATH,
JACK_DBUS_IFACE_NAME,
"StateChanged",
DBUS_TYPE_UINT32,
&u32,
DBUS_TYPE_STRING,
&target,
DBUS_TYPE_INVALID);
}

static bool start_detached_thread(void * (* start_routine)(void *), void * arg)
{
int ret;
static pthread_attr_t attr;
pthread_t tid;

ret = pthread_attr_init(&attr);
if (ret != 0)
{
jack_error("pthread_attr_init() failed with %d", ret);
goto exit;
}

ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if (ret != 0)
{
jack_error("pthread_attr_setdetachstate() failed with %d", ret);
goto destroy_attr;
}

ret = pthread_create(&tid, &attr, start_routine, arg);
if (ret != 0)
{
jack_error("pthread_create() failed with %d", ret);
goto destroy_attr;
}

jack_log("Detached thread %d created", (int)tid);

destroy_attr:
pthread_attr_destroy(&attr);
exit:
return ret == 0;
}

static void send_session_notify_reply(struct jack_session_pending_command * pending_cmd_ptr, jack_session_command_t * commands)
{
struct jack_dbus_method_call call;
const jack_session_command_t * cmd_ptr;
DBusMessageIter top_iter, array_iter, struct_iter;
dbus_uint32_t u32;

/* jack_dbus_error() wants call struct */
call.message = pending_cmd_ptr->message;
call.connection = pending_cmd_ptr->connection;

if (commands == NULL)
{
jack_dbus_error(&call, JACK_DBUS_ERROR_GENERIC, "jack_session_notify() failed");
goto send_reply;
}

jack_info("Session notify complete, commands follow:");

call.reply = dbus_message_new_method_return(pending_cmd_ptr->message);
if (call.reply == NULL)
{
goto oom;
}

dbus_message_iter_init_append(call.reply, &top_iter);

if (!dbus_message_iter_open_container(&top_iter, DBUS_TYPE_ARRAY, "(sssu)", &array_iter))
{
goto unref;
}

for (cmd_ptr = commands; cmd_ptr->uuid != NULL; cmd_ptr++)
{
if (!dbus_message_iter_open_container(&array_iter, DBUS_TYPE_STRUCT, NULL, &struct_iter))
{
goto close_array;
}

if (!dbus_message_iter_append_basic(&struct_iter, DBUS_TYPE_STRING, &cmd_ptr->uuid))
{
goto close_struct;
}

if (!dbus_message_iter_append_basic(&struct_iter, DBUS_TYPE_STRING, &cmd_ptr->client_name))
{
goto close_struct;
}

if (!dbus_message_iter_append_basic(&struct_iter, DBUS_TYPE_STRING, &cmd_ptr->command))
{
goto close_struct;
}

u32 = cmd_ptr->flags;
if (!dbus_message_iter_append_basic(&struct_iter, DBUS_TYPE_UINT32, &u32))
{
goto close_struct;
}

jack_info("uuid='%s', client='%s', command='%s', flags=0x%"PRIX32, cmd_ptr->uuid, cmd_ptr->client_name, cmd_ptr->command, u32);

if (!dbus_message_iter_close_container(&array_iter, &struct_iter))
{
goto close_array;
}
}

jack_info("End of session commands.");

if (!dbus_message_iter_close_container(&top_iter, &array_iter))
{
goto unref;
}

goto send_reply;

close_struct:
dbus_message_iter_close_container(&array_iter, &struct_iter);
close_array:
dbus_message_iter_close_container(&top_iter, &array_iter);
unref:
dbus_message_unref(call.reply);
goto oom;

send_reply:
if (call.reply != NULL)
{
if (!dbus_connection_send(pending_cmd_ptr->connection, call.reply, NULL))
{
jack_error("Ran out of memory trying to queue method return");
}

dbus_connection_flush(pending_cmd_ptr->connection);
dbus_message_unref(call.reply);
}
else
{
oom:
jack_error("Ran out of memory trying to construct method return");
}
}

#define controller_ptr ((struct jack_controller *)context)
void * jack_controller_process_session_command_thread(void * context)
{
struct jack_session_pending_command * pending_cmd_ptr;
jack_session_command_t * commands;

jack_log("jack_controller_process_session_command_thread enter");

pthread_mutex_lock(&controller_ptr->lock);
loop:
/* get next command */
assert(!list_empty(&controller_ptr->session_pending_commands));
pending_cmd_ptr = list_entry(controller_ptr->session_pending_commands.next, struct jack_session_pending_command, siblings);
pthread_mutex_unlock(&controller_ptr->lock);

jack_info("Session notify initiated. target='%s', type=%d, path='%s'", pending_cmd_ptr->target, (int)pending_cmd_ptr->type, pending_cmd_ptr->path);

jack_controller_control_send_signal_session_state_changed(pending_cmd_ptr->type, pending_cmd_ptr->target);

commands = jack_session_notify(controller_ptr->client, pending_cmd_ptr->target, pending_cmd_ptr->type, pending_cmd_ptr->path);
usleep(5000000);
send_session_notify_reply(pending_cmd_ptr, commands);
if (commands != NULL)
{
jack_session_commands_free(commands);
}

pthread_mutex_lock(&controller_ptr->lock);

/* keep state consistent by sending signal after to lock */
/* otherwise the main thread may receive not-to-be-queued request and fail */
jack_controller_control_send_signal_session_state_changed(0, NULL);

/* remove the head of the list (queue) */
assert(!list_empty(&controller_ptr->session_pending_commands));
assert(pending_cmd_ptr == list_entry(controller_ptr->session_pending_commands.next, struct jack_session_pending_command, siblings));
list_del(&pending_cmd_ptr->siblings);

/* command cleanup */
dbus_message_unref(pending_cmd_ptr->message);
dbus_connection_ref(pending_cmd_ptr->connection);
free(pending_cmd_ptr);

/* If there are more commands, process them. Otherwise - exit the thread */
if (!list_empty(&controller_ptr->session_pending_commands))
{
goto loop;
}

pthread_mutex_unlock(&controller_ptr->lock);

jack_log("jack_controller_process_session_command_thread exit");
return NULL;
}

#undef controller_ptr
#define controller_ptr ((struct jack_controller *)call->context)

static
void
jack_controller_dbus_session_notify(
struct jack_dbus_method_call * call)
{
dbus_bool_t queue;
const char * target;
dbus_uint32_t u32;
const char * path;
jack_session_event_type_t type;
struct jack_session_pending_command * cmd_ptr;

if (!controller_ptr->started)
{
jack_dbus_only_error(call, JACK_DBUS_ERROR_SERVER_NOT_RUNNING, "Can't execute method '%s' with stopped JACK server", call->method_name);
return;
}

if (!jack_dbus_get_method_args(
call,
DBUS_TYPE_BOOLEAN,
&queue,
DBUS_TYPE_STRING,
&target,
DBUS_TYPE_UINT32,
&u32,
DBUS_TYPE_STRING,
&path,
DBUS_TYPE_INVALID))
{
/* The method call had invalid arguments meaning that jack_dbus_get_method_args() has constructed an error for us. */
return;
}

if (*target == 0)
{
target = NULL;
}

type = (jack_session_event_type_t)u32;

if (type != JackSessionSave &&
type != JackSessionSaveAndQuit &&
type != JackSessionSaveTemplate)
{
jack_dbus_error(call, JACK_DBUS_ERROR_INVALID_ARGS, "Invalid session event type %" PRIu32, u32);
return;
}

pthread_mutex_lock(&controller_ptr->lock);
if (list_empty(&controller_ptr->session_pending_commands))
{
if (!start_detached_thread(jack_controller_process_session_command_thread, controller_ptr))
{
jack_dbus_error(call, JACK_DBUS_ERROR_GENERIC, "Cannot start thread to process the command");
goto unlock;
}

jack_log("Session notify thread started");
}
else if (!queue)
{
jack_dbus_error(call, JACK_DBUS_ERROR_GENERIC, "Busy");
goto unlock;
}

cmd_ptr = malloc(sizeof(struct jack_session_pending_command));
if (cmd_ptr == NULL)
{
jack_dbus_error(call, JACK_DBUS_ERROR_GENERIC, "malloc() failed for jack_session_pending_command struct");
goto unlock;
}

cmd_ptr->message = dbus_message_ref(call->message);
call->message = NULL; /* mark that reply will be sent asynchronously */
cmd_ptr->connection = dbus_connection_ref(call->connection);

/* it is safe to use the retrived pointers because we already made an additional message reference */
cmd_ptr->type = type;
cmd_ptr->target = target;
cmd_ptr->path = path;

list_add_tail(&cmd_ptr->siblings, &controller_ptr->session_pending_commands);

jack_log("Session notify scheduled. target='%s', type=%"PRIu32", path='%s'", target, u32, path);

unlock:
pthread_mutex_unlock(&controller_ptr->lock);
}

static
void
jack_controller_dbus_get_uuid_for_client_name(
struct jack_dbus_method_call * call)
{
const char * client_name;
char * client_uuid;

if (!jack_dbus_get_method_args(
call,
DBUS_TYPE_STRING,
&client_name,
DBUS_TYPE_INVALID))
{
/* The method call had invalid arguments meaning that jack_dbus_get_method_args() has constructed an error for us. */
return;
}

client_uuid = jack_get_uuid_for_client_name(controller_ptr->client, client_name);
if (client_uuid == NULL)
{
jack_dbus_error(call, JACK_DBUS_ERROR_GENERIC, "jack_get_uuid_for_client_name(\"%s\") failed", client_name);
return;
}

jack_dbus_construct_method_return_single(call, DBUS_TYPE_STRING, (message_arg_t)(const char *)client_uuid);
free(client_uuid);
}

static
void
jack_controller_dbus_get_client_name_by_uuid(
struct jack_dbus_method_call * call)
{
const char * client_uuid;
char * client_name;

if (!jack_dbus_get_method_args(
call,
DBUS_TYPE_STRING,
&client_uuid,
DBUS_TYPE_INVALID))
{
/* The method call had invalid arguments meaning that jack_dbus_get_method_args() has constructed an error for us. */
return;
}

client_name = jack_get_client_name_by_uuid(controller_ptr->client, client_uuid);
if (client_name == NULL)
{
jack_dbus_error(call, JACK_DBUS_ERROR_GENERIC, "jack_get_client_name_by_uuid(\"%s\") failed", client_uuid);
return;
}

jack_dbus_construct_method_return_single(call, DBUS_TYPE_STRING, (message_arg_t)(const char *)client_name);
free(client_name);
}

static
void
jack_controller_dbus_reserve_client_name(
struct jack_dbus_method_call * call)
{
int ret;
const char * client_name;
const char * client_uuid;

if (!jack_dbus_get_method_args(
call,
DBUS_TYPE_STRING,
&client_name,
DBUS_TYPE_STRING,
&client_uuid,
DBUS_TYPE_INVALID))
{
/* The method call had invalid arguments meaning that jack_dbus_get_method_args() has constructed an error for us. */
return;
}

ret = jack_reserve_client_name(controller_ptr->client, client_name, client_uuid);
if (ret < 0)
{
jack_dbus_error(call, JACK_DBUS_ERROR_GENERIC, "jack_reserve_client_name(name=\"%s\", uuid=\"%s\") failed (%d)", client_name, client_uuid, ret);
return;
}

jack_dbus_construct_method_return_empty(call);
}

static
void
jack_controller_dbus_has_session_callback(
struct jack_dbus_method_call * call)
{
int ret;
const char * client_name;
message_arg_t retval;

if (!jack_dbus_get_method_args(
call,
DBUS_TYPE_STRING,
&client_name,
DBUS_TYPE_INVALID))
{
/* The method call had invalid arguments meaning that jack_dbus_get_method_args() has constructed an error for us. */
return;
}

ret = jack_client_has_session_callback(controller_ptr->client, client_name);
if (ret < 0)
{
jack_dbus_error(call, JACK_DBUS_ERROR_GENERIC, "jack_client_has_session_callback(\"%s\") failed (%d)", client_name, ret);
return;
}

retval.boolean = ret;
jack_dbus_construct_method_return_single(call, DBUS_TYPE_BOOLEAN, retval);
}

static
void
jack_controller_dbus_get_session_state(
struct jack_dbus_method_call * call)
{
DBusMessageIter iter;
struct jack_session_pending_command * cmd_ptr;
const char * target;
dbus_uint32_t type;
bool append_failed;

call->reply = dbus_message_new_method_return(call->message);
if (call->reply == NULL)
{
goto oom;
}

dbus_message_iter_init_append(call->reply, &iter);

pthread_mutex_lock(&controller_ptr->lock);

if (list_empty(&controller_ptr->session_pending_commands))
{
type = 0;
target = "";
}
else
{
cmd_ptr = list_entry(controller_ptr->session_pending_commands.next, struct jack_session_pending_command, siblings);
type = (dbus_uint32_t)cmd_ptr->type;
target = cmd_ptr->target;
}

append_failed =
!dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT32, &type) ||
!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &target);

pthread_mutex_unlock(&controller_ptr->lock);

if (!append_failed)
{
return;
}

dbus_message_unref(call->reply);
call->reply = NULL;
oom:
jack_error("Ran out of memory trying to construct method return");
}

#undef controller_ptr

JACK_DBUS_METHOD_ARGUMENTS_BEGIN(Notify)
JACK_DBUS_METHOD_ARGUMENT("queue", DBUS_TYPE_BOOLEAN_AS_STRING, false)
JACK_DBUS_METHOD_ARGUMENT("target", DBUS_TYPE_STRING_AS_STRING, false)
JACK_DBUS_METHOD_ARGUMENT("type", DBUS_TYPE_UINT32_AS_STRING, false)
JACK_DBUS_METHOD_ARGUMENT("path", DBUS_TYPE_STRING_AS_STRING, false)
JACK_DBUS_METHOD_ARGUMENT("result", "a(sssu)", true)
JACK_DBUS_METHOD_ARGUMENTS_END

JACK_DBUS_METHOD_ARGUMENTS_BEGIN(GetUuidForClientName)
JACK_DBUS_METHOD_ARGUMENT("name", DBUS_TYPE_STRING_AS_STRING, false)
JACK_DBUS_METHOD_ARGUMENT("uuid", DBUS_TYPE_STRING_AS_STRING, true)
JACK_DBUS_METHOD_ARGUMENTS_END

JACK_DBUS_METHOD_ARGUMENTS_BEGIN(GetClientNameByUuid)
JACK_DBUS_METHOD_ARGUMENT("uuid", DBUS_TYPE_STRING_AS_STRING, false)
JACK_DBUS_METHOD_ARGUMENT("name", DBUS_TYPE_STRING_AS_STRING, true)
JACK_DBUS_METHOD_ARGUMENTS_END

JACK_DBUS_METHOD_ARGUMENTS_BEGIN(ReserveClientName)
JACK_DBUS_METHOD_ARGUMENT("name", DBUS_TYPE_STRING_AS_STRING, false)
JACK_DBUS_METHOD_ARGUMENT("uuid", DBUS_TYPE_STRING_AS_STRING, false)
JACK_DBUS_METHOD_ARGUMENTS_END

JACK_DBUS_METHOD_ARGUMENTS_BEGIN(HasSessionCallback)
JACK_DBUS_METHOD_ARGUMENT("client_name", DBUS_TYPE_STRING_AS_STRING, false)
JACK_DBUS_METHOD_ARGUMENT("has_session_callback", DBUS_TYPE_BOOLEAN_AS_STRING, true)
JACK_DBUS_METHOD_ARGUMENTS_END

JACK_DBUS_METHOD_ARGUMENTS_BEGIN(GetState)
JACK_DBUS_METHOD_ARGUMENT("type", DBUS_TYPE_UINT32_AS_STRING, true)
JACK_DBUS_METHOD_ARGUMENT("target", DBUS_TYPE_STRING_AS_STRING, true)
JACK_DBUS_METHOD_ARGUMENTS_END

JACK_DBUS_SIGNAL_ARGUMENTS_BEGIN(StateChanged)
JACK_DBUS_SIGNAL_ARGUMENT("type", DBUS_TYPE_UINT32_AS_STRING)
JACK_DBUS_SIGNAL_ARGUMENT("target", DBUS_TYPE_STRING_AS_STRING)
JACK_DBUS_SIGNAL_ARGUMENTS_END

JACK_DBUS_METHODS_BEGIN
JACK_DBUS_METHOD_DESCRIBE(Notify, jack_controller_dbus_session_notify)
JACK_DBUS_METHOD_DESCRIBE(GetUuidForClientName, jack_controller_dbus_get_uuid_for_client_name)
JACK_DBUS_METHOD_DESCRIBE(GetClientNameByUuid, jack_controller_dbus_get_client_name_by_uuid)
JACK_DBUS_METHOD_DESCRIBE(ReserveClientName, jack_controller_dbus_reserve_client_name)
JACK_DBUS_METHOD_DESCRIBE(HasSessionCallback, jack_controller_dbus_has_session_callback)
JACK_DBUS_METHOD_DESCRIBE(GetState, jack_controller_dbus_get_session_state)
JACK_DBUS_METHODS_END

JACK_DBUS_SIGNALS_BEGIN
JACK_DBUS_SIGNAL_DESCRIBE(StateChanged)
JACK_DBUS_SIGNALS_END

JACK_DBUS_IFACE_BEGIN(g_jack_controller_iface_session_manager, JACK_DBUS_IFACE_NAME)
JACK_DBUS_IFACE_EXPOSE_METHODS
JACK_DBUS_IFACE_EXPOSE_SIGNALS
JACK_DBUS_IFACE_END

+ 15
- 0
dbus/controller_internal.h View File

@@ -25,6 +25,7 @@
#include "jslist.h"
#include "jack/control.h"
#include "jack/jack.h"
#include "jack/session.h"
#include "jackdbus.h"
#include "list.h"
#include "params.h"
@@ -37,6 +38,16 @@ struct jack_controller_slave_driver
bool loaded;
};

struct jack_session_pending_command
{
struct list_head siblings;
DBusConnection * connection;
DBusMessage * message;
jack_session_event_type_t type;
const char * target;
const char * path;
};

struct jack_controller
{
jackctl_server_t *server;
@@ -54,6 +65,9 @@ struct jack_controller
union jackctl_parameter_value slave_drivers_vparam_value;

struct jack_dbus_object_descriptor dbus_descriptor;

pthread_mutex_t lock;
struct list_head session_pending_commands;
};

#define DEFAULT_DRIVER "dummy"
@@ -183,6 +197,7 @@ extern struct jack_dbus_interface_descriptor g_jack_controller_iface_introspecta
extern struct jack_dbus_interface_descriptor g_jack_controller_iface_control;
extern struct jack_dbus_interface_descriptor g_jack_controller_iface_configure;
extern struct jack_dbus_interface_descriptor g_jack_controller_iface_patchbay;
extern struct jack_dbus_interface_descriptor g_jack_controller_iface_session_manager;
extern struct jack_dbus_interface_descriptor g_jack_controller_iface_transport;

#endif /* #ifndef CONTROLLER_INTERNAL_H__04D54D51_3D79_49A2_A1DA_F8587E9E7F42__INCLUDED */

+ 6
- 0
dbus/jackdbus.c View File

@@ -105,6 +105,12 @@ void
jack_dbus_send_method_return(
struct jack_dbus_method_call * call)
{
if (call->message == NULL)
{
/* async call */
return;
}

if (call->reply)
{
retry_send:


+ 1
- 0
dbus/wscript View File

@@ -58,6 +58,7 @@ def build(bld):
'controller_iface_control.c',
'controller_iface_introspectable.c',
'controller_iface_patchbay.c',
'controller_iface_session_manager.c',
'controller_iface_transport.c',
'xml.c',
'xml_expat.c',


+ 7
- 7
example-clients/session_notify.c View File

@@ -2,7 +2,7 @@
* session_notify.c -- ultra minimal session manager
*
* Copyright (C) 2010 Torben Hohn.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -141,15 +141,15 @@ int main(int argc, char *argv[])


retval = jack_session_notify( client, NULL, notify_type, save_path );
for(i=0; retval[i].uuid; i++ ) {
for (i = 0; retval[i].uuid; i++) {
printf( "export SESSION_DIR=\"%s%s/\"\n", save_path, retval[i].client_name );
printf( "%s &\n", retval[i].command );
add_uuid_mapping(retval[i].uuid);
add_uuid_mapping(retval[i].uuid);
}

printf( "sleep 10\n" );

for(k=0; retval[k].uuid; k++ ) {
for (k = 0; retval[k].uuid; k++) {

char* port_regexp = alloca( jack_client_name_size()+3 );
char* client_name = jack_get_client_name_by_uuid( client, retval[k].uuid );
@@ -163,12 +163,12 @@ int main(int argc, char *argv[])
const char **connections;
if ((connections = jack_port_get_all_connections (client, jack_port_by_name(client, ports[i]))) != 0) {
for (j = 0; connections[j]; j++) {
char *src = map_port_name_to_uuid_port( ports[i] );
char *dst = map_port_name_to_uuid_port( connections[j] );
char *src = map_port_name_to_uuid_port( ports[i] );
char *dst = map_port_name_to_uuid_port( connections[j] );
printf( "jack_connect -u \"%s\" \"%s\"\n", src, dst );
}
jack_free (connections);
}
}
}
jack_free(ports);



+ 1
- 18
posix/JackSocketClientChannel.cpp View File

@@ -259,24 +259,7 @@ void JackSocketClientChannel::SessionNotify(int refnum, const char* target, jack
JackSessionNotifyResult res;
int intresult;
ServerSyncCall(&req, &res, &intresult);

jack_session_command_t* session_command = (jack_session_command_t *)malloc(sizeof(jack_session_command_t) * (res.fCommandList.size() + 1));
int i = 0;

for (std::list<JackSessionCommand>::iterator ci=res.fCommandList.begin(); ci!=res.fCommandList.end(); ci++) {
session_command[i].uuid = strdup( ci->fUUID );
session_command[i].client_name = strdup( ci->fClientName );
session_command[i].command = strdup( ci->fCommand );
session_command[i].flags = ci->fFlags;
i += 1;
}

session_command[i].uuid = NULL;
session_command[i].client_name = NULL;
session_command[i].command = NULL;
session_command[i].flags = (jack_session_flags_t)0;

*result = session_command;
*result = res.GetCommands();
}

void JackSocketClientChannel::SessionReply(int refnum, int* result)


+ 2
- 3
posix/JackSocketServerChannel.cpp View File

@@ -429,9 +429,8 @@ bool JackSocketServerChannel::HandleRequest(int fd)
case JackRequest::kSessionNotify: {
jack_log("JackRequest::SessionNotify");
JackSessionNotifyRequest req;
JackSessionNotifyResult res;
if (req.Read(socket) == 0) {
fServer->GetEngine()->SessionNotify(req.fRefNum, req.fDst, req.fEventType, req.fPath, socket);
fServer->GetEngine()->SessionNotify(req.fRefNum, req.fDst, req.fEventType, req.fPath, socket, NULL);
}
break;
}
@@ -490,7 +489,7 @@ bool JackSocketServerChannel::HandleRequest(int fd)
JackClientHasSessionCallbackRequest req;
JackResult res;
if (req.Read(socket) == 0) {
fServer->GetEngine()->ClientHasSessionCallbackRequest(req.fName, &res.fResult);
fServer->GetEngine()->ClientHasSessionCallback(req.fName, &res.fResult);
}
if (res.Write(socket) < 0)
jack_error("JackRequest::ClientHasSessionCallback write error");


+ 1
- 18
windows/JackWinNamedPipeClientChannel.cpp View File

@@ -263,24 +263,7 @@ void JackWinNamedPipeClientChannel::SessionNotify(int refnum, const char* target
JackSessionNotifyResult res;
int intresult;
ServerSyncCall(&req, &res, &intresult);

jack_session_command_t* session_command = (jack_session_command_t *)malloc(sizeof(jack_session_command_t) * (res.fCommandList.size() + 1));
int i = 0;

for (std::list<JackSessionCommand>::iterator ci=res.fCommandList.begin(); ci!=res.fCommandList.end(); ci++) {
session_command[i].uuid = strdup( ci->fUUID );
session_command[i].client_name = strdup( ci->fClientName );
session_command[i].command = strdup( ci->fCommand );
session_command[i].flags = ci->fFlags;
i += 1;
}

session_command[i].uuid = NULL;
session_command[i].client_name = NULL;
session_command[i].command = NULL;
session_command[i].flags = (jack_session_flags_t)0;

*result = session_command;
*result = res.GetCommands();
}

void JackWinNamedPipeClientChannel::SessionReply(int refnum, int* result)


+ 1
- 2
windows/JackWinNamedPipeServerChannel.cpp View File

@@ -342,9 +342,8 @@ bool JackClientPipeThread::HandleRequest()
case JackRequest::kSessionNotify: {
jack_log("JackRequest::SessionNotify");
JackSessionNotifyRequest req;
JackSessionNotifyResult res;
if (req.Read(fPipe) == 0) {
fServer->GetEngine()->SessionNotify(req.fRefNum, req.fDst, req.fEventType, req.fPath, fPipe);
fServer->GetEngine()->SessionNotify(req.fRefNum, req.fDst, req.fEventType, req.fPath, fPipe, NULL);
}
res.Write(fPipe);
break;


Loading…
Cancel
Save