Browse Source

rebase from trunk 4306:4323

git-svn-id: http://subversion.jackaudio.org/jack/jack2/branches/libjacknet@4324 0c269be4-1314-0410-8aa9-9f06e86f4224
tags/1.9.8
sletz 14 years ago
parent
commit
ad34703368
54 changed files with 2285 additions and 3504 deletions
  1. +4
    -0
      ChangeLog
  2. +6
    -6
      common/JackFreewheelDriver.cpp
  3. +5
    -12
      common/JackMidiAsyncQueue.cpp
  4. +9
    -9
      common/JackMidiAsyncQueue.h
  5. +6
    -0
      common/JackMidiRawInputWriteQueue.cpp
  6. +7
    -0
      common/JackMidiRawInputWriteQueue.h
  7. +36
    -106
      common/JackMidiRawOutputWriteQueue.cpp
  8. +4
    -12
      common/JackMidiRawOutputWriteQueue.h
  9. +2
    -1
      common/JackMidiUtil.cpp
  10. +12
    -14
      common/JackWeakAPI.c
  11. +5
    -2
      common/Jackdmp.cpp
  12. +0
    -2
      common/netjack.c
  13. +0
    -2
      common/netjack_packet.c
  14. +228
    -113
      dbus/controller.c
  15. +209
    -1366
      dbus/controller_iface_configure.c
  16. +13
    -4
      dbus/controller_iface_control.c
  17. +14
    -63
      dbus/controller_internal.h
  18. +726
    -0
      dbus/params.c
  19. +111
    -0
      dbus/params.h
  20. +1
    -1
      dbus/wscript
  21. +67
    -309
      dbus/xml.c
  22. +62
    -104
      dbus/xml_expat.c
  23. +0
    -797
      dbus/xml_libxml.c
  24. +59
    -103
      dbus/xml_write_raw.c
  25. +70
    -40
      example-clients/midi_latency_test.c
  26. +1
    -1
      example-clients/samplerate.c
  27. +2
    -0
      linux/JackLinuxTime.c
  28. +184
    -134
      linux/alsarawmidi/JackALSARawMidiDriver.cpp
  29. +5
    -3
      linux/alsarawmidi/JackALSARawMidiDriver.h
  30. +50
    -71
      linux/alsarawmidi/JackALSARawMidiInputPort.cpp
  31. +3
    -5
      linux/alsarawmidi/JackALSARawMidiInputPort.h
  32. +67
    -93
      linux/alsarawmidi/JackALSARawMidiOutputPort.cpp
  33. +5
    -7
      linux/alsarawmidi/JackALSARawMidiOutputPort.h
  34. +101
    -37
      linux/alsarawmidi/JackALSARawMidiPort.cpp
  35. +20
    -7
      linux/alsarawmidi/JackALSARawMidiPort.h
  36. +0
    -0
      linux/alsarawmidi/JackALSARawMidiReceiveQueue.cpp
  37. +0
    -0
      linux/alsarawmidi/JackALSARawMidiReceiveQueue.h
  38. +15
    -1
      linux/alsarawmidi/JackALSARawMidiSendQueue.cpp
  39. +7
    -1
      linux/alsarawmidi/JackALSARawMidiSendQueue.h
  40. +43
    -0
      linux/alsarawmidi/JackALSARawMidiUtil.cpp
  41. +36
    -0
      linux/alsarawmidi/JackALSARawMidiUtil.h
  42. +6
    -3
      linux/wscript
  43. +1
    -1
      windows/JackRouter/JackRouter.cpp
  44. +1
    -1
      windows/JackRouter/JackRouter.vcxproj
  45. +5
    -5
      windows/Setup/jack.ci
  46. +12
    -11
      windows/Setup/jack64.ci
  47. BIN
      windows/Setup/src/32bits/JackRouter.dll
  48. +7
    -0
      windows/Setup/src/32bits/JackRouter.ini
  49. BIN
      windows/Setup/src/64bits/JackRouter.dll
  50. +7
    -0
      windows/Setup/src/64bits/JackRouter.ini
  51. +2
    -2
      windows/jackd.workspace
  52. +38
    -34
      windows/winmme/JackWinMMEInputPort.cpp
  53. +9
    -12
      windows/winmme/JackWinMMEInputPort.h
  54. +2
    -9
      windows/winmme/JackWinMMEOutputPort.cpp

+ 4
- 0
ChangeLog View File

@@ -34,6 +34,10 @@ Valerio Pilo
Jackdmp changes log
---------------------------

2011-04-18 Stephane Letz <letz@grame.fr>

* JackWeakAPI.cpp renamed in JackWeakAPI.c.

2011-04-04 Stephane Letz <letz@grame.fr>

* Correct driver lifetime management.


+ 6
- 6
common/JackFreewheelDriver.cpp View File

@@ -28,12 +28,12 @@ namespace Jack

int JackFreewheelDriver::Process()
{
int res = 0;
int res = 0;

jack_log("JackFreewheelDriver::Process master %lld", fEngineControl->fTimeOutUsecs);
JackDriver::CycleTakeBeginTime();
jack_log("JackFreewheelDriver::Process master %lld", fEngineControl->fTimeOutUsecs);
JackDriver::CycleTakeBeginTime();

if (fEngine->Process(fBeginDateUst, fEndDateUst)) {
if (fEngine->Process(fBeginDateUst, fEndDateUst)) {

if (fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable)) { // Signal all clients
jack_error("JackFreewheelDriver::Process: ResumeRefNum error");
@@ -46,10 +46,10 @@ int JackFreewheelDriver::Process()
return 0;
}

} else { // Graph not finished: do not activate it
} else { // Graph not finished: do not activate it
jack_error("JackFreewheelDriver::Process: Process error");
res = -1;
}
}

return res;
}


+ 5
- 12
common/JackMidiAsyncQueue.cpp View File

@@ -54,23 +54,16 @@ JackMidiAsyncQueue::DequeueEvent()
{
jack_midi_event_t *event = 0;
if (jack_ringbuffer_read_space(info_ring) >= INFO_SIZE) {
size_t size;
event = &dequeue_event;
jack_ringbuffer_read(info_ring, (char *) &(event->time),
sizeof(jack_nframes_t));
size_t size;
jack_ringbuffer_read(info_ring, (char *) &size, sizeof(size_t));
jack_ringbuffer_read(info_ring, (char *) &size,
sizeof(size_t));
jack_ringbuffer_read(byte_ring, (char *) data_buffer,
size * sizeof(jack_midi_data_t));
event->buffer = data_buffer;
event->size = size;
jack_ringbuffer_data_t vector[2];
jack_ringbuffer_get_read_vector(byte_ring, vector);
size_t size1 = vector[0].len;
memcpy(data_buffer, vector[0].buf, size1 * sizeof(jack_midi_data_t));
if (size1 < size) {
memcpy(data_buffer + size1, vector[1].buf,
(size - size1) * sizeof(jack_midi_data_t));
}
jack_ringbuffer_read_advance(byte_ring,
size * sizeof(jack_midi_data_t));
}
return event;
}


+ 9
- 9
common/JackMidiAsyncQueue.h View File

@@ -28,14 +28,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
namespace Jack {

/**
* This is a MIDI message queue designed to allow two threads to pass MIDI
* messages between two threads (though it can also be used to buffer
* events internally). This is especially useful if the MIDI API
* you're attempting to interface with doesn't provide the ability to
* schedule MIDI events ahead of time and/or has blocking send/receive
* calls, as it allows a separate thread to handle input/output while the
* JACK process thread copies events from a `JackMidiBufferReadQueue` to
* this queue, or from this queue to a `JackMidiBufferWriteQueue`.
* This is a MIDI message queue designed to allow one thread to pass MIDI
* messages to another thread (though it can also be used to buffer events
* internally). This is especially useful if the MIDI API you're
* attempting to interface with doesn't provide the ability to schedule
* MIDI events ahead of time and/or has blocking send/receive calls, as it
* allows a separate thread to handle input/output while the JACK process
* thread copies events from a MIDI buffer to this queue, or vice versa.
*/

class SERVER_EXPORT JackMidiAsyncQueue:
@@ -64,7 +63,8 @@ namespace Jack {

JackMidiAsyncQueue(size_t max_bytes=4096, size_t max_messages=1024);

virtual ~JackMidiAsyncQueue();
virtual
~JackMidiAsyncQueue();

/**
* Dequeues and returns a MIDI event. Returns '0' if there are no MIDI


+ 6
- 0
common/JackMidiRawInputWriteQueue.cpp View File

@@ -66,6 +66,12 @@ JackMidiRawInputWriteQueue::EnqueueEvent(jack_nframes_t time, size_t size,
return packet_queue->EnqueueEvent(time, size, buffer);
}

size_t
JackMidiRawInputWriteQueue::GetAvailableSpace()
{
return packet_queue->GetAvailableSpace();
}

void
JackMidiRawInputWriteQueue::HandleBufferFailure(size_t unbuffered_bytes,
size_t total_bytes)


+ 7
- 0
common/JackMidiRawInputWriteQueue.h View File

@@ -142,6 +142,13 @@ namespace Jack {
EnqueueEvent(jack_nframes_t time, size_t size,
jack_midi_data_t *buffer);

/**
* Returns the maximum size event that can be enqueued right *now*.
*/

size_t
GetAvailableSpace();

/**
* The `Process()` method should be called each time the
* `EnqueueEvent()` method returns `OK`. The `Process()` method will


+ 36
- 106
common/JackMidiRawOutputWriteQueue.cpp View File

@@ -50,27 +50,23 @@ JackMidiRawOutputWriteQueue::~JackMidiRawOutputWriteQueue()
delete rt_queue;
}

bool
void
JackMidiRawOutputWriteQueue::DequeueNonRealtimeEvent()
{
non_rt_event = non_rt_queue->DequeueEvent();
bool result = non_rt_event != 0;
if (result) {
if (non_rt_event) {
non_rt_event_time = non_rt_event->time;
running_status = ApplyRunningStatus(non_rt_event, running_status);
}
return result;
}

bool
void
JackMidiRawOutputWriteQueue::DequeueRealtimeEvent()
{
rt_event = rt_queue->DequeueEvent();
bool result = rt_event != 0;
if (result) {
if (rt_event) {
rt_event_time = rt_event->time;
}
return result;
}

Jack::JackMidiWriteQueue::EnqueueResult
@@ -79,11 +75,7 @@ JackMidiRawOutputWriteQueue::EnqueueEvent(jack_nframes_t time, size_t size,
{
JackMidiAsyncQueue *queue = (size == 1) && (*buffer >= 0xf8) ? rt_queue :
non_rt_queue;
EnqueueResult result = queue->EnqueueEvent(time, size, buffer);
if (result == OK) {
last_enqueued_message_time = time;
}
return result;
return queue->EnqueueEvent(time, size, buffer);
}

void
@@ -99,38 +91,34 @@ JackMidiRawOutputWriteQueue::HandleWriteQueueBug(jack_nframes_t time,
jack_nframes_t
JackMidiRawOutputWriteQueue::Process(jack_nframes_t boundary_frame)
{
jack_nframes_t current_frame = send_queue->GetNextScheduleFrame();
while (STILL_TIME(current_frame, boundary_frame)) {
if (! non_rt_event) {
DequeueNonRealtimeEvent();
}
if (! rt_event) {
DequeueRealtimeEvent();
}
if (! (non_rt_event || rt_event)) {
return 0;
if (! non_rt_event) {
DequeueNonRealtimeEvent();
}
if (! rt_event) {
DequeueRealtimeEvent();
}
while (rt_event) {
jack_nframes_t current_frame = send_queue->GetNextScheduleFrame();
if ((rt_event_time > current_frame) && non_rt_event &&
(non_rt_event_time < rt_event_time)) {
if (! SendNonRTBytes(rt_event_time < boundary_frame ?
rt_event_time : boundary_frame)) {
return non_rt_event_time;
}
current_frame = send_queue->GetNextScheduleFrame();
}
if (! WriteRealtimeEvents(boundary_frame)) {
break;
if (! STILL_TIME(current_frame, boundary_frame)) {
return (! non_rt_event) ? rt_event_time :
non_rt_event_time < rt_event_time ? non_rt_event_time :
rt_event_time;
}
jack_nframes_t non_rt_boundary =
rt_event && STILL_TIME(rt_event_time, boundary_frame) ?
rt_event_time : boundary_frame;
if (! WriteNonRealtimeEvents(non_rt_boundary)) {
break;
if (! SendByte(rt_event_time, *(rt_event->buffer))) {
return rt_event_time;
}
current_frame = send_queue->GetNextScheduleFrame();
DequeueRealtimeEvent();
}

// If we get here, that means there is some sort of message available, and
// that either we can't currently write to the write queue or we have
// reached the boundary frame. Return the earliest time that a message is
// scheduled to be sent.

return ! non_rt_event ? rt_event_time :
non_rt_event->size > 1 ? current_frame :
! rt_event ? non_rt_event_time :
non_rt_event_time < rt_event_time ? non_rt_event_time : rt_event_time;
SendNonRTBytes(boundary_frame);
return non_rt_event ? non_rt_event_time : 0;
}

bool
@@ -151,78 +139,20 @@ JackMidiRawOutputWriteQueue::SendByte(jack_nframes_t time,
}

bool
JackMidiRawOutputWriteQueue::
WriteNonRealtimeEvents(jack_nframes_t boundary_frame)
JackMidiRawOutputWriteQueue::SendNonRTBytes(jack_nframes_t boundary_frame)
{
if (! non_rt_event) {
if (! DequeueNonRealtimeEvent()) {
return true;
}
}
jack_nframes_t current_frame = send_queue->GetNextScheduleFrame();
do {

// Send out as much of the non-realtime buffer as we can, save for one
// byte which we will send out when the message is supposed to arrive.

for (; non_rt_event->size > 1;
while (non_rt_event) {
for (; non_rt_event->size;
(non_rt_event->size)--, (non_rt_event->buffer)++) {
jack_nframes_t current_frame = send_queue->GetNextScheduleFrame();
if (! STILL_TIME(current_frame, boundary_frame)) {
return true;
}
if (! SendByte(current_frame, *(non_rt_event->buffer))) {
if (! SendByte(non_rt_event_time, *(non_rt_event->buffer))) {
return false;
}
current_frame = send_queue->GetNextScheduleFrame();
}
if (! (STILL_TIME(current_frame, boundary_frame) &&
STILL_TIME(non_rt_event_time, boundary_frame))) {
return true;
}

// There's still time. Try to send the byte.

if (! SendByte(non_rt_event_time, *(non_rt_event->buffer))) {
return false;
}
current_frame = send_queue->GetNextScheduleFrame();
if (! DequeueNonRealtimeEvent()) {
break;
}
} while (STILL_TIME(current_frame, boundary_frame));
return true;
}

bool
JackMidiRawOutputWriteQueue::WriteRealtimeEvents(jack_nframes_t boundary_frame)
{
jack_nframes_t current_frame = send_queue->GetNextScheduleFrame();
if (! rt_event) {
if (! DequeueRealtimeEvent()) {
return true;
}
}
for (;;) {
if (! STILL_TIME(current_frame, boundary_frame)) {
return false;
}

// If:
// -there's still time before we need to send the realtime event
// -there's a non-realtime event available for sending
// -non-realtime data can be scheduled before this event

if ((rt_event_time > current_frame) && non_rt_event &&
((non_rt_event->size > 1) ||
(non_rt_event_time < rt_event_time))) {
return true;
}
if (! SendByte(rt_event_time, *(rt_event->buffer))) {
return false;
}
current_frame = send_queue->GetNextScheduleFrame();
if (! DequeueRealtimeEvent()) {
return true;
}
DequeueNonRealtimeEvent();
}
return true;
}

+ 4
- 12
common/JackMidiRawOutputWriteQueue.h View File

@@ -27,7 +27,7 @@ namespace Jack {

/**
* This queue enqueues valid MIDI events and modifies them for raw output
* to a write queue. It has a number of advantages over straight MIDI
* to a write queue. It has a couple of advantages over straight MIDI
* event copying:
*
* -Running status: Status bytes can be omitted when the status byte of the
@@ -39,10 +39,6 @@ namespace Jack {
* non-realtime bytes so that realtime messages can be sent as close as
* possible to the time they're scheduled for sending.
*
* -Time optimization: Bytes in non-realtime messages are sent out early
* when possible, with the last byte of the message being sent out as close
* to the specified event time as possible.
*
* Use this queue if the MIDI API you're interfacing with allows you to
* send raw MIDI bytes.
*/
@@ -52,7 +48,6 @@ namespace Jack {

private:

jack_nframes_t last_enqueued_message_time;
jack_midi_event_t *non_rt_event;
jack_nframes_t non_rt_event_time;
JackMidiAsyncQueue *non_rt_queue;
@@ -62,20 +57,17 @@ namespace Jack {
jack_midi_data_t running_status;
JackMidiSendQueue *send_queue;

bool
void
DequeueNonRealtimeEvent();

bool
void
DequeueRealtimeEvent();

bool
SendByte(jack_nframes_t time, jack_midi_data_t byte);

bool
WriteNonRealtimeEvents(jack_nframes_t boundary_frame);

bool
WriteRealtimeEvents(jack_nframes_t boundary_frame);
SendNonRTBytes(jack_nframes_t boundary_frame);

protected:



+ 2
- 1
common/JackMidiUtil.cpp View File

@@ -55,10 +55,11 @@ Jack::ApplyRunningStatus(jack_midi_event_t *event,
jack_nframes_t
Jack::GetCurrentFrame()
{
jack_time_t time = GetMicroSeconds();
JackEngineControl *control = GetEngineControl();
JackTimer timer;
control->ReadFrameTime(&timer);
return timer.Time2Frames(GetMicroSeconds(), control->fBufferSize);
return timer.Time2Frames(time, control->fBufferSize);
}

jack_nframes_t


common/JackWeakAPI.cpp → common/JackWeakAPI.c View File

@@ -1,10 +1,6 @@
//=============================================================================
// MuseScore
// Linux Music Score Editor
// $Id:
//
// jackWeakAPI based on code from Stéphane Letz (Grame)
// partly based on Julien Pommier (PianoTeq : http://www.pianoteq.com/) code.
// jackWeakAPI partly based on Julien Pommier (PianoTeq : http://www.pianoteq.com/) code.
//
// Copyright (C) 2002-2007 Werner Schweer and others
// Copyright (C) 2009 Grame
@@ -24,6 +20,7 @@
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

#include <jack/jack.h>
#include <jack/session.h>
#include <jack/thread.h>
#include <jack/midiport.h>
#include <math.h>
@@ -31,7 +28,7 @@
#include <dlfcn.h>
#endif
#include <stdlib.h>
#include <iostream>
#include <stdio.h>

/* dynamically load libjack and forward all registered calls to libjack
(similar to what relaytool is trying to do, but more portably..)
@@ -40,24 +37,25 @@
typedef void (*print_function)(const char *);
typedef void *(*thread_routine)(void*);

using std::cerr;

int libjack_is_present = 0; // public symbol, similar to what relaytool does.
static int libjack_is_present = 0; // public symbol, similar to what relaytool does.

#ifdef WIN32
HMODULE libjack_handle = 0;
static HMODULE libjack_handle = 0;
#else
static void *libjack_handle = 0;
#endif


static void __attribute__((constructor)) tryload_libjack()
{
if (getenv("SKIP_LIBJACK") == 0) { // just in case libjack is causing troubles..
#ifdef __APPLE__
libjack_handle = dlopen("libjack.0.dylib", RTLD_LAZY);
#elif defined(WIN32)
libjack_handle = LoadLibrary("libjack.dll");
#ifdef _WIN64
libjack_handle = LoadLibrary("libjack64.dll");
#else
libjack_handle = LoadLibrary("libjack.dll");
#endif
#else
libjack_handle = dlopen("libjack.so.0", RTLD_LAZY);
#endif
@@ -289,8 +287,8 @@ DECL_VOID_FUNCTION(jack_free, (void* ptr), (ptr));

// session
DECL_FUNCTION(int, jack_set_session_callback, (jack_client_t* ext_client, JackSessionCallback session_callback, void* arg), (ext_client, session_callback, arg));
DECL_FUNCTION(jack_session_command_t*, jack_session_notify, (jack_client_t* ext_client, const char* target, jack_session_event_type_t ev_type, const char* path), (ext_client, target, ev_type, path)Ă );
DECL_FUNCTION(int jack_session_reply, (jack_client_t* ext_client, jack_session_event_t *event), (ext_client, event));
DECL_FUNCTION(jack_session_command_t*, jack_session_notify, (jack_client_t* ext_client, const char* target, jack_session_event_type_t ev_type, const char* path), (ext_client, target, ev_type, path));
DECL_FUNCTION(int, jack_session_reply, (jack_client_t* ext_client, jack_session_event_t *event), (ext_client, event));
DECL_VOID_FUNCTION(jack_session_event_free, (jack_session_event_t* ev), (ev));
DECL_FUNCTION(char*, jack_get_uuid_for_client_name, (jack_client_t* ext_client, const char* client_name),(ext_client, client_name));
DECL_FUNCTION(char*, jack_get_client_name_by_uuid, (jack_client_t* ext_client, const char* client_uuid),(ext_client, client_uuid));

+ 5
- 2
common/Jackdmp.cpp View File

@@ -540,12 +540,15 @@ int main(int argc, char* argv[])
// Slave drivers
for (it = slaves_list.begin(); it != slaves_list.end(); it++) {
jackctl_driver_t * slave_driver_ctl = jackctl_server_get_driver(server_ctl, *it);
jackctl_server_remove_slave(server_ctl, slave_driver_ctl);
if (slave_driver_ctl)
jackctl_server_remove_slave(server_ctl, slave_driver_ctl);
}

// Internal clients
for (it = internals_list.begin(); it != internals_list.end(); it++) {
jackctl_internal_t * internal_driver_ctl = jackctl_server_get_internal(server_ctl, *it);
jackctl_server_unload_internal(server_ctl, internal_driver_ctl);
if (internal_driver_ctl)
jackctl_server_unload_internal(server_ctl, internal_driver_ctl);
}
jackctl_server_close(server_ctl);
destroy_server:


+ 0
- 2
common/netjack.c View File

@@ -55,8 +55,6 @@ $Id: net_driver.c,v 1.17 2006/04/16 20:16:10 torbenh Exp $
#include <samplerate.h>
#endif

#include "JackError.h"

#include "netjack.h"
#include "netjack_packet.h"



+ 0
- 2
common/netjack_packet.c View File

@@ -68,8 +68,6 @@
#include <samplerate.h>
#endif

#include "JackError.h"

#if HAVE_CELT
#include <celt/celt.h>
#endif


+ 228
- 113
dbus/controller.c View File

@@ -1,6 +1,6 @@
/* -*- Mode: C ; c-basic-offset: 4 -*- */
/*
Copyright (C) 2007,2008,2010 Nedko Arnaudov
Copyright (C) 2007,2008,2010,2011 Nedko Arnaudov
Copyright (C) 2007-2008 Juuso Alasuutari

This program is free software; you can redistribute it and/or modify
@@ -42,6 +42,7 @@ struct jack_dbus_interface_descriptor * g_jackcontroller_interfaces[] =
NULL
};

static
jackctl_driver_t *
jack_controller_find_driver(
jackctl_server_t *server,
@@ -64,9 +65,7 @@ jack_controller_find_driver(
return NULL;
}

bool
jack_controller_add_slave_drivers(
struct jack_controller * controller_ptr)
static bool jack_controller_check_slave_driver(struct jack_controller * controller_ptr, const char * name)
{
struct list_head * node_ptr;
struct jack_controller_slave_driver * driver_ptr;
@@ -74,31 +73,40 @@ jack_controller_add_slave_drivers(
list_for_each(node_ptr, &controller_ptr->slave_drivers)
{
driver_ptr = list_entry(node_ptr, struct jack_controller_slave_driver, siblings);
driver_ptr->handle = jack_controller_find_driver(controller_ptr->server, driver_ptr->name);

if (driver_ptr->handle == NULL)
if (strcmp(name, driver_ptr->name) == 0)
{
jack_error("Unknown driver \"%s\"", driver_ptr->name);
goto fail;
return true;
}
}

return false;
}

static bool jack_controller_load_slave_drivers(struct jack_controller * controller_ptr)
{
struct list_head * node_ptr;
struct jack_controller_slave_driver * driver_ptr;

list_for_each(node_ptr, &controller_ptr->slave_drivers)
{
driver_ptr = list_entry(node_ptr, struct jack_controller_slave_driver, siblings);

assert(driver_ptr->handle != NULL);
assert(!driver_ptr->loaded);

if (!jackctl_server_add_slave(controller_ptr->server, driver_ptr->handle))
{
jack_error("Driver \"%s\" cannot be loaded", driver_ptr->name);
goto fail;
return false;
}

driver_ptr->loaded = true;
}

return true;

fail:
driver_ptr->handle = NULL;
return false;
}

void
jack_controller_remove_slave_drivers(
struct jack_controller * controller_ptr)
static void jack_controller_unload_slave_drivers(struct jack_controller * controller_ptr)
{
struct list_head * node_ptr;
struct jack_controller_slave_driver * driver_ptr;
@@ -106,14 +114,31 @@ jack_controller_remove_slave_drivers(
list_for_each(node_ptr, &controller_ptr->slave_drivers)
{
driver_ptr = list_entry(node_ptr, struct jack_controller_slave_driver, siblings);
if (driver_ptr->handle != NULL)
if (driver_ptr->loaded)
{
jackctl_server_remove_slave(controller_ptr->server, driver_ptr->handle);
driver_ptr->handle = NULL;
driver_ptr->loaded = false;
}
}
}

static void jack_controller_remove_slave_drivers(struct jack_controller * controller_ptr)
{
struct jack_controller_slave_driver * driver_ptr;

while (!list_empty(&controller_ptr->slave_drivers))
{
driver_ptr = list_entry(controller_ptr->slave_drivers.next, struct jack_controller_slave_driver, siblings);
assert(!driver_ptr->loaded);
list_del(&driver_ptr->siblings);
free(driver_ptr->name);
free(driver_ptr);
}

controller_ptr->slave_drivers_vparam_value.str[0] = 0;
}

static
jackctl_internal_t *
jack_controller_find_internal(
jackctl_server_t *server,
@@ -136,42 +161,18 @@ jack_controller_find_internal(
return NULL;
}

jackctl_parameter_t *
jack_controller_find_parameter(
const JSList * parameters_list,
const char * parameter_name)
{
while (parameters_list)
{
if (strcmp(jackctl_parameter_get_name((jackctl_parameter_t *)parameters_list->data), parameter_name) == 0)
{
return parameters_list->data;
}

parameters_list = jack_slist_next(parameters_list);
}

return NULL;
}

bool
jack_controller_select_driver(
struct jack_controller * controller_ptr,
const char * driver_name)
{
jackctl_driver_t *driver;

driver = jack_controller_find_driver(controller_ptr->server, driver_name);
if (driver == NULL)
if (!jack_params_set_driver(controller_ptr->params, driver_name))
{
return false;
}

jack_info("driver \"%s\" selected", driver_name);

controller_ptr->driver = driver;
controller_ptr->driver_set = true;

return true;
}

@@ -195,23 +196,17 @@ jack_controller_start_server(

assert(!controller_ptr->started); /* should be ensured by caller */

if (controller_ptr->driver == NULL)
{
jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "Select driver first!");
goto fail;
}

controller_ptr->xruns = 0;

if (!jackctl_server_open(
controller_ptr->server,
controller_ptr->driver))
jack_params_get_driver(controller_ptr->params)))
{
jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "Failed to open server");
goto fail;
}

jack_controller_add_slave_drivers(controller_ptr);
jack_controller_load_slave_drivers(controller_ptr);

if (!jackctl_server_start(
controller_ptr->server))
@@ -273,7 +268,7 @@ fail_stop_server:
}

fail_close_server:
jack_controller_remove_slave_drivers(controller_ptr);
jack_controller_unload_slave_drivers(controller_ptr);

if (!jackctl_server_close(controller_ptr->server))
{
@@ -317,7 +312,7 @@ jack_controller_stop_server(
return FALSE;
}

jack_controller_remove_slave_drivers(controller_ptr);
jack_controller_unload_slave_drivers(controller_ptr);

if (!jackctl_server_close(controller_ptr->server))
{
@@ -337,12 +332,13 @@ jack_controller_switch_master(
{
if (!jackctl_server_switch_master(
controller_ptr->server,
controller_ptr->driver))
jack_params_get_driver(controller_ptr->params)))
{
jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "Failed to switch master");
return FALSE;
}


return TRUE;
}

@@ -408,16 +404,108 @@ on_device_release(const char * device_name)
g_device_count--;
}

#define controller_ptr ((struct jack_controller *)obj)

static bool slave_drivers_parameter_is_set(void * obj)
{
return controller_ptr->slave_drivers_set;
}

static bool slave_drivers_parameter_reset(void * obj)
{
if (controller_ptr->started)
{
jack_error("Cannot modify slave-drivers when server is started");
return false;
}

jack_controller_remove_slave_drivers(controller_ptr);
controller_ptr->slave_drivers_set = false;
return true;
}

static union jackctl_parameter_value slave_drivers_parameter_get_value(void * obj)
{
return controller_ptr->slave_drivers_vparam_value;
}

static bool slave_drivers_parameter_set_value(void * obj, const union jackctl_parameter_value * value_ptr)
{
char * buffer;
char * save;
const char * token;
struct list_head old_list;
struct list_head new_list;
union jackctl_parameter_value old_value;
union jackctl_parameter_value new_value;
bool old_set;

if (controller_ptr->started)
{
jack_error("Cannot modify slave-drivers when server is started");
return false;
}

old_set = controller_ptr->slave_drivers_set;
old_value = controller_ptr->slave_drivers_vparam_value;
controller_ptr->slave_drivers_vparam_value.str[0] = 0;
old_list = controller_ptr->slave_drivers;
INIT_LIST_HEAD(&controller_ptr->slave_drivers);

buffer = strdup(value_ptr->str);
if (buffer == NULL)
{
jack_error("strdup() failed.");
return false;
}

token = strtok_r(buffer, ",", &save);
while (token)
{
//jack_info("slave driver '%s'", token);
if (!jack_controller_add_slave_driver(controller_ptr, token))
{
jack_controller_remove_slave_drivers(controller_ptr);
controller_ptr->slave_drivers = old_list;
controller_ptr->slave_drivers_vparam_value = old_value;
controller_ptr->slave_drivers_set = old_set;

free(buffer);

return false;
}

token = strtok_r(NULL, ",", &save);
}

new_value = controller_ptr->slave_drivers_vparam_value;
new_list = controller_ptr->slave_drivers;
controller_ptr->slave_drivers = old_list;
jack_controller_remove_slave_drivers(controller_ptr);
controller_ptr->slave_drivers_vparam_value = new_value;
controller_ptr->slave_drivers = new_list;
controller_ptr->slave_drivers_set = true;

free(buffer);

return true;
}

static union jackctl_parameter_value slave_drivers_parameter_get_default_value(void * obj)
{
union jackctl_parameter_value value;
value.str[0] = 0;
return value;
}

#undef controller_ptr

void *
jack_controller_create(
DBusConnection *connection)
{
struct jack_controller *controller_ptr;
const JSList * node_ptr;
const char ** driver_name_target;
const char ** internal_name_target;
JSList * drivers;
JSList * internals;
const char * address[PARAM_ADDRESS_SIZE];
DBusObjectPathVTable vtable =
{
jack_dbus_message_handler_unregister,
@@ -439,54 +527,37 @@ jack_controller_create(
goto fail_free;
}

controller_ptr->client = NULL;
controller_ptr->started = false;
controller_ptr->driver = NULL;
controller_ptr->driver_set = false;
INIT_LIST_HEAD(&controller_ptr->slave_drivers);

drivers = (JSList *)jackctl_server_get_drivers_list(controller_ptr->server);
controller_ptr->drivers_count = jack_slist_length(drivers);
controller_ptr->driver_names = malloc(controller_ptr->drivers_count * sizeof(const char *));
if (controller_ptr->driver_names == NULL)
controller_ptr->params = jack_params_create(controller_ptr->server);
if (controller_ptr->params == NULL)
{
jack_error("Ran out of memory trying to allocate driver names array");
jack_error("Failed to initialize parameter tree");
goto fail_destroy_server;
}

driver_name_target = controller_ptr->driver_names;
node_ptr = jackctl_server_get_drivers_list(controller_ptr->server);
while (node_ptr != NULL)
{
*driver_name_target = jackctl_driver_get_name((jackctl_driver_t *)node_ptr->data);
controller_ptr->client = NULL;
controller_ptr->started = false;

/* select default driver */
if (controller_ptr->driver == NULL && strcmp(*driver_name_target, DEFAULT_DRIVER) == 0)
{
controller_ptr->driver = (jackctl_driver_t *)node_ptr->data;
}
INIT_LIST_HEAD(&controller_ptr->slave_drivers);
controller_ptr->slave_drivers_set = false;
controller_ptr->slave_drivers_vparam_value.str[0] = 0;

node_ptr = jack_slist_next(node_ptr);
driver_name_target++;
}
internals = (JSList *)jackctl_server_get_internals_list(controller_ptr->server);
controller_ptr->internals_count = jack_slist_length(internals);
controller_ptr->internal_names = malloc(controller_ptr->internals_count * sizeof(const char *));
if (controller_ptr->internal_names == NULL)
{
jack_error("Ran out of memory trying to allocate internals names array");
goto fail_free_driver_names_array;
}
controller_ptr->slave_drivers_vparam.obj = controller_ptr;

internal_name_target = controller_ptr->internal_names;
node_ptr = jackctl_server_get_internals_list(controller_ptr->server);
while (node_ptr != NULL)
{
*internal_name_target = jackctl_internal_get_name((jackctl_internal_t *)node_ptr->data);
node_ptr = jack_slist_next(node_ptr);
internal_name_target++;
}
controller_ptr->slave_drivers_vparam.vtable.is_set = slave_drivers_parameter_is_set;
controller_ptr->slave_drivers_vparam.vtable.reset = slave_drivers_parameter_reset;
controller_ptr->slave_drivers_vparam.vtable.get_value = slave_drivers_parameter_get_value;
controller_ptr->slave_drivers_vparam.vtable.set_value = slave_drivers_parameter_set_value;
controller_ptr->slave_drivers_vparam.vtable.get_default_value = slave_drivers_parameter_get_default_value;

controller_ptr->slave_drivers_vparam.type = JackParamString;
controller_ptr->slave_drivers_vparam.name = "slave-drivers";
controller_ptr->slave_drivers_vparam.short_decr = "Slave drivers to use";
controller_ptr->slave_drivers_vparam.long_descr = "A comma separated list of slave drivers";
controller_ptr->slave_drivers_vparam.constraint_flags = 0;

address[0] = PTNODE_ENGINE;
address[1] = NULL;
jack_params_add_parameter(controller_ptr->params, address, true, &controller_ptr->slave_drivers_vparam);

controller_ptr->dbus_descriptor.context = controller_ptr;
controller_ptr->dbus_descriptor.interfaces = g_jackcontroller_interfaces;
@@ -498,18 +569,15 @@ jack_controller_create(
&controller_ptr->dbus_descriptor))
{
jack_error("Ran out of memory trying to register D-Bus object path");
goto fail_free_internal_names_array;
goto fail_destroy_params;
}

jack_controller_settings_load(controller_ptr);

return controller_ptr;

fail_free_internal_names_array:
free(controller_ptr->internal_names);

fail_free_driver_names_array:
free(controller_ptr->driver_names);
fail_destroy_params:
jack_params_destroy(controller_ptr->params);

fail_destroy_server:
jackctl_server_destroy(controller_ptr->server);
@@ -526,7 +594,31 @@ jack_controller_add_slave_driver(
struct jack_controller * controller_ptr,
const char * driver_name)
{
jackctl_driver_t * driver;
struct jack_controller_slave_driver * driver_ptr;
size_t len_old;
size_t len_new;

len_old = strlen(controller_ptr->slave_drivers_vparam_value.str);
len_new = strlen(driver_name);
if (len_old + len_new + 2 > sizeof(controller_ptr->slave_drivers_vparam_value.str))
{
jack_error("No more space for slave drivers.");
return false;
}

driver = jack_controller_find_driver(controller_ptr->server, driver_name);
if (driver == NULL)
{
jack_error("Unknown driver \"%s\"", driver_name);
return false;
}

if (jack_controller_check_slave_driver(controller_ptr, driver_name))
{
jack_info("Driver \"%s\" is already slave", driver_name);
return true;
}

driver_ptr = malloc(sizeof(struct jack_controller_slave_driver));
if (driver_ptr == NULL)
@@ -543,12 +635,21 @@ jack_controller_add_slave_driver(
return false;
}

driver_ptr->handle = NULL;
driver_ptr->handle = driver;
driver_ptr->loaded = false;

jack_info("slave driver \"%s\" added", driver_name);
jack_info("driver \"%s\" set as slave", driver_name);

list_add_tail(&driver_ptr->siblings, &controller_ptr->slave_drivers);

if (len_old != 0)
{
controller_ptr->slave_drivers_vparam_value.str[len_old++] = ',';
}

memcpy(controller_ptr->slave_drivers_vparam_value.str + len_old, driver_name, len_new + 1);
controller_ptr->slave_drivers_set = true;

return true;
}

@@ -565,10 +666,25 @@ jack_controller_remove_slave_driver(
driver_ptr = list_entry(node_ptr, struct jack_controller_slave_driver, siblings);
if (strcmp(driver_ptr->name, driver_name) == 0)
{
jack_info("slave driver \"%s\" removed", driver_name);
list_del(&driver_ptr->siblings);
free(driver_ptr->name);
free(driver_ptr);

/* update the slave-drivers param value */
controller_ptr->slave_drivers_vparam_value.str[0] = 0;
list_for_each(node_ptr, &controller_ptr->slave_drivers)
{
driver_ptr = list_entry(node_ptr, struct jack_controller_slave_driver, siblings);
if (controller_ptr->slave_drivers_vparam_value.str[0] != 0)
{
strcat(controller_ptr->slave_drivers_vparam_value.str, ",");
}

strcat(controller_ptr->slave_drivers_vparam_value.str, driver_ptr->name);
}

jack_info("driver \"%s\" is not slave anymore", driver_name);

return true;
}
}
@@ -623,9 +739,8 @@ jack_controller_destroy(
jack_controller_stop_server(controller_ptr, NULL);
}

free(controller_ptr->driver_names);
free(controller_ptr->internal_names);

jack_controller_remove_slave_drivers(controller_ptr);
jack_params_destroy(controller_ptr->params);
jackctl_server_destroy(controller_ptr->server);

free(controller_ptr);


+ 209
- 1366
dbus/controller_iface_configure.c
File diff suppressed because it is too large
View File


+ 13
- 4
dbus/controller_iface_control.c View File

@@ -30,6 +30,7 @@

#include "jackdbus.h"
#include "controller_internal.h"
#include "xml.h"

#define JACK_DBUS_IFACE_NAME "org.jackaudio.JackControl"

@@ -127,8 +128,6 @@ jack_control_run_method(
assert(call->reply != NULL);
return true;
}

jack_controller_control_send_signal_server_stopped();
}
else if (strcmp (call->method_name, "GetLoad") == 0)
{
@@ -246,12 +245,17 @@ jack_control_run_method(
goto exit;
}
if (!jack_controller_add_slave_driver(controller_ptr, driver_name)) {
if (!jack_controller_add_slave_driver(controller_ptr, driver_name))
{
jack_dbus_error(
call,
JACK_DBUS_ERROR_GENERIC,
"jack_controller_add_slave_driver failed for driver (%s)", driver_name);
}
else
{
jack_controller_settings_save_auto(controller_ptr);
}
}
else if (strcmp (call->method_name, "RemoveSlaveDriver") == 0)
{
@@ -270,12 +274,17 @@ jack_control_run_method(
goto exit;
}
if (!jack_controller_remove_slave_driver(controller_ptr, driver_name)) {
if (!jack_controller_remove_slave_driver(controller_ptr, driver_name))
{
jack_dbus_error(
call,
JACK_DBUS_ERROR_GENERIC,
"jack_controller_remove_slave_driver failed for driver (%s)", driver_name);
}
else
{
jack_controller_settings_save_auto(controller_ptr);
}
}
else if (strcmp (call->method_name, "UnloadInternal") == 0)
{


+ 14
- 63
dbus/controller_internal.h View File

@@ -1,6 +1,6 @@
/* -*- Mode: C ; c-basic-offset: 4 -*- */
/*
Copyright (C) 2007,2008 Nedko Arnaudov
Copyright (C) 2007,2008,2011 Nedko Arnaudov
Copyright (C) 2007-2008 Juuso Alasuutari
This program is free software; you can redistribute it and/or modify
@@ -27,17 +27,20 @@
#include "jack/jack.h"
#include "jackdbus.h"
#include "list.h"
#include "params.h"

struct jack_controller_slave_driver
{
struct list_head siblings;
char * name;
jackctl_driver_t * handle;
bool loaded;
};

struct jack_controller
{
jackctl_server_t *server;
jack_params_handle params;

void *patchbay_context;

@@ -45,15 +48,10 @@ struct jack_controller
jack_client_t *client;
unsigned int xruns;

const char **driver_names;
unsigned int drivers_count;
const char **internal_names;
unsigned int internals_count;

jackctl_driver_t *driver;
bool driver_set; /* whether driver is manually set, if false - DEFAULT_DRIVER is auto set */
struct list_head slave_drivers;
bool slave_drivers_set;
struct jack_parameter slave_drivers_vparam;
union jackctl_parameter_value slave_drivers_vparam_value;

struct jack_dbus_object_descriptor dbus_descriptor;
};
@@ -65,21 +63,6 @@ struct jack_controller
"You probably don't want to edit this because\n" \
"it will be overwritten next time jackdbus saves.\n"

jackctl_driver_t *
jack_controller_find_driver(
jackctl_server_t *server,
const char *driver_name);
jackctl_internal_t *
jack_controller_find_internal(
jackctl_server_t *server,
const char *internal_name);

jackctl_parameter_t *
jack_controller_find_parameter(
const JSList *parameters_list,
const char *parameter_name);

bool
jack_controller_start_server(
struct jack_controller *controller_ptr,
@@ -121,47 +104,15 @@ jack_controller_unload_internal(
const char * internal_name);

void
jack_controller_settings_set_driver_option(
jackctl_driver_t *driver,
const char *option_name,
const char *option_value);

void
jack_controller_settings_set_internal_option(
jackctl_internal_t *internal,
const char *option_name,
const char *option_value);

void
jack_controller_settings_set_engine_option(
struct jack_controller *controller_ptr,
const char *option_name,
const char *option_value);

bool
jack_controller_settings_save_engine_options(
void *context,
jack_controller_deserialize_parameter_value(
struct jack_controller *controller_ptr,
void *dbus_call_context_ptr);

bool
jack_controller_settings_write_option(
void *context,
const char *name,
const char *content,
void *dbus_call_context_ptr);
const char * const * address,
const char * value);

bool
jack_controller_settings_save_driver_options(
void *context,
jackctl_driver_t *driver,
void *dbus_call_context_ptr);

bool
jack_controller_settings_save_internal_options(
void *context,
jackctl_internal_t *internal,
void *dbus_call_context_ptr);
void
jack_controller_serialize_parameter_value(
const struct jack_parameter * param_ptr,
char * value_buffer);

bool
jack_controller_patchbay_init(


+ 726
- 0
dbus/params.c View File

@@ -0,0 +1,726 @@
/* -*- 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.

*/

/*
* Parameter addresses:
*
* "engine"
* "engine", "driver"
* "engine", "realtime"
* "engine", ...more engine parameters
*
* "driver", "device"
* "driver", ...more driver parameters
*
* "drivers", "alsa", "device"
* "drivers", "alsa", ...more alsa driver parameters
*
* "drivers", ...more drivers
*
* "internals", "netmanager", "multicast_ip"
* "internals", "netmanager", ...more netmanager parameters
*
* "internals", ...more internals
*
*/

#include <stdbool.h>
#include <string.h>
#include <assert.h>
#include <dbus/dbus.h>

#include "params.h"
#include "controller_internal.h"

#define PTNODE_ENGINE "engine"
#define PTNODE_DRIVER "driver"
#define PTNODE_DRIVERS "drivers"
#define PTNODE_INTERNALS "internals"

struct jack_parameter_container
{
struct list_head siblings;
char * name;
struct jack_parameter_container * symlink;
bool leaf;
struct list_head children;
void * obj;
};

struct jack_params
{
jackctl_server_t * server;
struct jack_parameter_container root;
struct list_head * drivers_ptr;
uint32_t drivers_count;
struct jack_parameter_container * driver_ptr;
bool driver_set; /* whether driver is manually set, if false - DEFAULT_DRIVER is auto set */
};

static bool controlapi_parameter_is_set(void * obj)
{
return jackctl_parameter_is_set((jackctl_parameter_t *)obj);
}

static bool controlapi_parameter_reset(void * obj)
{
return jackctl_parameter_reset((jackctl_parameter_t *)obj);
}

union jackctl_parameter_value controlapi_parameter_get_value(void * obj)
{
return jackctl_parameter_get_value((jackctl_parameter_t *)obj);
}

bool controlapi_parameter_set_value(void * obj, const union jackctl_parameter_value * value_ptr)
{
return jackctl_parameter_set_value((jackctl_parameter_t *)obj, value_ptr);
}

union jackctl_parameter_value controlapi_parameter_get_default_value(void * obj)
{
return jackctl_parameter_get_default_value((jackctl_parameter_t *)obj);
}

static struct jack_parameter_container * create_container(struct list_head * parent_list_ptr, const char * name)
{
struct jack_parameter_container * container_ptr;

container_ptr = malloc(sizeof(struct jack_parameter_container));
if (container_ptr == NULL)
{
jack_error("Ran out of memory trying to allocate struct jack_parameter_container");
goto fail;
}

container_ptr->name = strdup(name);
if (container_ptr->name == NULL)
{
jack_error("Ran out of memory trying to strdup parameter container name");
goto free;
}

container_ptr->leaf = false;
container_ptr->symlink = NULL;
container_ptr->obj = NULL;
INIT_LIST_HEAD(&container_ptr->children);
list_add_tail(&container_ptr->siblings, parent_list_ptr);

return container_ptr;

free:
free(container_ptr);
fail:
return NULL;
}

static bool add_controlapi_param(struct list_head * parent_list_ptr, jackctl_parameter_t * param)
{
struct jack_parameter * param_ptr;
uint32_t i;

param_ptr = malloc(sizeof(struct jack_parameter));
if (param_ptr == NULL)
{
jack_error("Ran out of memory trying to allocate struct jack_parameter");
goto fail;
}

param_ptr->ext = false;
param_ptr->obj = param;
param_ptr->vtable.is_set = controlapi_parameter_is_set;
param_ptr->vtable.reset = controlapi_parameter_reset;
param_ptr->vtable.get_value = controlapi_parameter_get_value;
param_ptr->vtable.set_value = controlapi_parameter_set_value;
param_ptr->vtable.get_default_value = controlapi_parameter_get_default_value;

param_ptr->type = jackctl_parameter_get_type(param);
param_ptr->name = jackctl_parameter_get_name(param);
param_ptr->short_decr = jackctl_parameter_get_short_description(param);
param_ptr->long_descr = jackctl_parameter_get_long_description(param);

if (jackctl_parameter_has_range_constraint(param))
{
param_ptr->constraint_flags = JACK_CONSTRAINT_FLAG_VALID;
param_ptr->constraint_range = true;
jackctl_parameter_get_range_constraint(param, &param_ptr->constraint.range.min, &param_ptr->constraint.range.max);
}
else if (jackctl_parameter_has_enum_constraint(param))
{
param_ptr->constraint_flags = JACK_CONSTRAINT_FLAG_VALID;
param_ptr->constraint_range = false;
param_ptr->constraint.enumeration.count = jackctl_parameter_get_enum_constraints_count(param);
param_ptr->constraint.enumeration.possible_values_array = malloc(sizeof(struct jack_parameter_enum) * param_ptr->constraint.enumeration.count);
if (param_ptr->constraint.enumeration.possible_values_array == NULL)
{
goto free;
}

for (i = 0; i < param_ptr->constraint.enumeration.count; i++)
{
param_ptr->constraint.enumeration.possible_values_array[i].value = jackctl_parameter_get_enum_constraint_value(param, i);
param_ptr->constraint.enumeration.possible_values_array[i].short_desc = jackctl_parameter_get_enum_constraint_description(param, i);
}
}
else
{
param_ptr->constraint_flags = 0;
goto add;
}

if (jackctl_parameter_constraint_is_strict(param))
{
param_ptr->constraint_flags |= JACK_CONSTRAINT_FLAG_STRICT;
}

if (jackctl_parameter_constraint_is_fake_value(param))
{
param_ptr->constraint_flags |= JACK_CONSTRAINT_FLAG_FAKE_VALUE;
}

add:
list_add_tail(&param_ptr->siblings, parent_list_ptr);
return true;

free:
free(param_ptr);
fail:
return false;
}

static void free_params(struct list_head * parent_list_ptr)
{
struct jack_parameter * param_ptr;

while (!list_empty(parent_list_ptr))
{
param_ptr = list_entry(parent_list_ptr->next, struct jack_parameter, siblings);
list_del(&param_ptr->siblings);

if (param_ptr->ext)
{
continue;
}

if ((param_ptr->constraint_flags & JACK_CONSTRAINT_FLAG_VALID) != 0 &&
!param_ptr->constraint_range &&
param_ptr->constraint.enumeration.possible_values_array != NULL)
{
free(param_ptr->constraint.enumeration.possible_values_array);
}

free(param_ptr);
}
}

static void free_containers(struct list_head * parent_list_ptr)
{
struct jack_parameter_container * container_ptr;

while (!list_empty(parent_list_ptr))
{
container_ptr = list_entry(parent_list_ptr->next, struct jack_parameter_container, siblings);
list_del(&container_ptr->siblings);

if (container_ptr->leaf)
{
free_params(&container_ptr->children);
}
else
{
free_containers(&container_ptr->children);
}

free(container_ptr->name);
free(container_ptr);
}
}

static struct jack_parameter_container * find_container(struct jack_parameter_container * parent_ptr, const char * const * address, int max_depth)
{
struct list_head * node_ptr;
struct jack_parameter_container * container_ptr;

if (max_depth == 0 || *address == NULL)
{
return parent_ptr;
}

if (parent_ptr->leaf)
{
return NULL;
}

if (max_depth > 0)
{
max_depth--;
}

list_for_each(node_ptr, &parent_ptr->children)
{
container_ptr = list_entry(node_ptr, struct jack_parameter_container, siblings);
if (strcmp(container_ptr->name, *address) == 0)
{
if (container_ptr->symlink != NULL)
{
container_ptr = container_ptr->symlink;
}

return find_container(container_ptr, address + 1, max_depth);
}
}

return NULL;
}

static bool init_leaf(struct list_head * parent_list_ptr, const char * name, const JSList * params_list, void * obj)
{
struct jack_parameter_container * container_ptr;

container_ptr = create_container(parent_list_ptr, name);
if (container_ptr == NULL)
{
return false;
}

container_ptr->leaf = true;
container_ptr->obj = obj;

while (params_list)
{
if (!add_controlapi_param(&container_ptr->children, params_list->data))
{
return false;
}

params_list = jack_slist_next(params_list);
}

return true;
}

static bool init_engine(struct jack_params * params_ptr)
{
return init_leaf(&params_ptr->root.children, PTNODE_ENGINE, jackctl_server_get_parameters(params_ptr->server), NULL);
}

static bool init_drivers(struct jack_params * params_ptr)
{
const JSList * list;
struct jack_parameter_container * container_ptr;

container_ptr = create_container(&params_ptr->root.children, PTNODE_DRIVERS);
if (container_ptr == NULL)
{
return false;
}

params_ptr->drivers_ptr = &container_ptr->children;
params_ptr->drivers_count = 0;

list = jackctl_server_get_drivers_list(params_ptr->server);
while (list)
{
if (!init_leaf(&container_ptr->children, jackctl_driver_get_name(list->data), jackctl_driver_get_parameters(list->data), list->data))
{
return false;
}

params_ptr->drivers_count++;

list = jack_slist_next(list);
}

return true;
}

static bool init_internals(struct jack_params * params_ptr)
{
const JSList * list;
struct jack_parameter_container * container_ptr;

container_ptr = create_container(&params_ptr->root.children, PTNODE_INTERNALS);
if (container_ptr == NULL)
{
return false;
}

list = jackctl_server_get_internals_list(params_ptr->server);
while (list)
{
if (!init_leaf(&container_ptr->children, jackctl_internal_get_name(list->data), jackctl_internal_get_parameters(list->data), NULL))
{
return false;
}

list = jack_slist_next(list);
}

return true;
}

static bool init_driver(struct jack_params * params_ptr)
{
struct jack_parameter_container * container_ptr;

container_ptr = create_container(&params_ptr->root.children, PTNODE_DRIVER);
if (container_ptr == NULL)
{
return false;
}

params_ptr->driver_ptr = container_ptr;

return true;
}

#define params_ptr ((struct jack_params *)obj)

static bool engine_driver_parameter_is_set(void * obj)
{
return params_ptr->driver_set;
}

static bool engine_driver_parameter_reset(void * obj)
{
if (!jack_params_set_driver(obj, DEFAULT_DRIVER))
{
return false;
}

params_ptr->driver_set = false;

return true;
}

union jackctl_parameter_value engine_driver_parameter_get_value(void * obj)
{
union jackctl_parameter_value value;

strcpy(value.str, params_ptr->driver_ptr->symlink->name);

return value;
}

bool engine_driver_parameter_set_value(void * obj, const union jackctl_parameter_value * value_ptr)
{
return jack_params_set_driver(obj, value_ptr->str);
}

union jackctl_parameter_value engine_driver_parameter_get_default_value(void * obj)
{
union jackctl_parameter_value value;

strcpy(value.str, DEFAULT_DRIVER);

return value;
}

#undef params_ptr

static bool add_engine_driver_enum_constraint(void * context, const char * name)
{
strcpy((*((struct jack_parameter_enum **)context))->value.str, name);
(*((struct jack_parameter_enum **)context))->short_desc = name;
(*((struct jack_parameter_enum **)context))++;
return true;
}

static bool init_engine_driver_parameter(struct jack_params * params_ptr)
{
struct jack_parameter * param_ptr;
const char * address[PARAM_ADDRESS_SIZE] = {PTNODE_ENGINE, NULL};
struct jack_parameter_container * engine_ptr;
struct jack_parameter_enum * possible_value;

engine_ptr = find_container(&params_ptr->root, address, PARAM_ADDRESS_SIZE);
if (engine_ptr == NULL)
{
return false;
}

param_ptr = malloc(sizeof(struct jack_parameter));
if (param_ptr == NULL)
{
jack_error("Ran out of memory trying to allocate struct jack_parameter");
goto fail;
}

param_ptr->ext = false;
param_ptr->obj = params_ptr;
param_ptr->vtable.is_set = engine_driver_parameter_is_set;
param_ptr->vtable.reset = engine_driver_parameter_reset;
param_ptr->vtable.get_value = engine_driver_parameter_get_value;
param_ptr->vtable.set_value = engine_driver_parameter_set_value;
param_ptr->vtable.get_default_value = engine_driver_parameter_get_default_value;

param_ptr->type = JackParamString;
param_ptr->name = "driver";
param_ptr->short_decr = "Driver to use";
param_ptr->long_descr = "";

param_ptr->constraint_flags = JACK_CONSTRAINT_FLAG_VALID | JACK_CONSTRAINT_FLAG_STRICT | JACK_CONSTRAINT_FLAG_FAKE_VALUE;
param_ptr->constraint_range = false;
param_ptr->constraint.enumeration.count = params_ptr->drivers_count;
param_ptr->constraint.enumeration.possible_values_array = malloc(sizeof(struct jack_parameter_enum) * params_ptr->drivers_count);
if (param_ptr->constraint.enumeration.possible_values_array == NULL)
{
goto free;
}

address[0] = PTNODE_DRIVERS;
possible_value = param_ptr->constraint.enumeration.possible_values_array;
jack_params_iterate_container((jack_params_handle)params_ptr, address, add_engine_driver_enum_constraint, &possible_value);

list_add(&param_ptr->siblings, &engine_ptr->children);
return true;

free:
free(param_ptr);
fail:
return false;
}

jack_params_handle jack_params_create(jackctl_server_t * server)
{
struct jack_params * params_ptr;

params_ptr = malloc(sizeof(struct jack_params));
if (params_ptr == NULL)
{
jack_error("Ran out of memory trying to allocate struct jack_params");
return NULL;
}

params_ptr->server = server;
INIT_LIST_HEAD(&params_ptr->root.children);
params_ptr->root.leaf = false;
params_ptr->root.name = NULL;

if (!init_engine(params_ptr) ||
!init_drivers(params_ptr) ||
!init_driver(params_ptr) ||
!init_engine_driver_parameter(params_ptr) ||
!jack_params_set_driver((jack_params_handle)params_ptr, DEFAULT_DRIVER) ||
!init_internals(params_ptr))
{
jack_params_destroy((jack_params_handle)params_ptr);
return NULL;
}

params_ptr->driver_set = false;

assert(strcmp(params_ptr->driver_ptr->symlink->name, DEFAULT_DRIVER) == 0);

return (jack_params_handle)params_ptr;
}

#define params_ptr ((struct jack_params *)params)

void jack_params_destroy(jack_params_handle params)
{
free_containers(&params_ptr->root.children);
free(params);
}

bool jack_params_set_driver(jack_params_handle params, const char * name)
{
struct list_head * node_ptr;
struct jack_parameter_container * container_ptr;

list_for_each(node_ptr, params_ptr->drivers_ptr)
{
container_ptr = list_entry(node_ptr, struct jack_parameter_container, siblings);
if (strcmp(container_ptr->name, name) == 0)
{
params_ptr->driver_ptr->symlink = container_ptr;
params_ptr->driver_set = true;
return true;
}
}

return false;
}

jackctl_driver_t * jack_params_get_driver(jack_params_handle params)
{
return params_ptr->driver_ptr->symlink->obj;
}

bool jack_params_check_address(jack_params_handle params, const char * const * address, bool want_leaf)
{
struct jack_parameter_container * container_ptr;

container_ptr = find_container(&params_ptr->root, address, PARAM_ADDRESS_SIZE);
if (container_ptr == NULL)
{
return false;
}

if (want_leaf && !container_ptr->leaf)
{
return false;
}

return true;
}

bool jack_params_is_leaf_container(jack_params_handle params, const char * const * address)
{
struct jack_parameter_container * container_ptr;

container_ptr = find_container(&params_ptr->root, address, PARAM_ADDRESS_SIZE);
if (container_ptr == NULL)
{
assert(false);
return false;
}

return container_ptr->leaf;
}

bool
jack_params_iterate_container(
jack_params_handle params,
const char * const * address,
bool (* callback)(void * context, const char * name),
void * context)
{
struct jack_parameter_container * container_ptr;
struct list_head * node_ptr;
const char * name;

container_ptr = find_container(&params_ptr->root, address, PARAM_ADDRESS_SIZE);
if (container_ptr == NULL)
{
assert(false);
return true;
}

list_for_each(node_ptr, &container_ptr->children)
{
if (container_ptr->leaf)
{
name = list_entry(node_ptr, struct jack_parameter, siblings)->name;
}
else
{
name = list_entry(node_ptr, struct jack_parameter_container, siblings)->name;
}

if (!callback(context, name))
{
return false;
}
}

return true;
}

bool
jack_params_iterate_params(
jack_params_handle params,
const char * const * address,
bool (* callback)(void * context, const struct jack_parameter * param_ptr),
void * context)
{
struct jack_parameter_container * container_ptr;
struct list_head * node_ptr;
struct jack_parameter * param_ptr;

container_ptr = find_container(&params_ptr->root, address, PARAM_ADDRESS_SIZE);
if (container_ptr == NULL || !container_ptr->leaf)
{
assert(false);
return true;
}

list_for_each(node_ptr, &container_ptr->children)
{
param_ptr = list_entry(node_ptr, struct jack_parameter, siblings);
if (!callback(context, param_ptr))
{
return false;
}
}

return true;
}

const struct jack_parameter * jack_params_get_parameter(jack_params_handle params, const char * const * address)
{
int depth;
struct jack_parameter_container * container_ptr;
struct list_head * node_ptr;
struct jack_parameter * param_ptr;

for (depth = 0; depth < PARAM_ADDRESS_SIZE; depth++)
{
if (address[depth] == NULL)
{
break;
}
}

depth--;

container_ptr = find_container(&params_ptr->root, address, depth);
if (container_ptr == NULL || !container_ptr->leaf)
{
return NULL;
}

list_for_each(node_ptr, &container_ptr->children)
{
param_ptr = list_entry(node_ptr, struct jack_parameter, siblings);
if (strcmp(param_ptr->name, address[depth]) == 0)
{
return param_ptr;
}
}

return NULL;
}

void jack_params_add_parameter(jack_params_handle params, const char * const * address, bool end, struct jack_parameter * param_ptr)
{
struct jack_parameter_container * container_ptr;

container_ptr = find_container(&params_ptr->root, address, PARAM_ADDRESS_SIZE);
if (container_ptr == NULL || !container_ptr->leaf)
{
assert(false);
return;
}

param_ptr->ext = true;

if (end)
{
list_add_tail(&param_ptr->siblings, &container_ptr->children);
}
else
{
list_add(&param_ptr->siblings, &container_ptr->children);
}

return;
}

#undef params_ptr

+ 111
- 0
dbus/params.h View File

@@ -0,0 +1,111 @@
/* -*- 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.

*/

#ifndef PARAMS_H__A23EDE06_C1C9_4489_B253_FD1B26B66929__INCLUDED
#define PARAMS_H__A23EDE06_C1C9_4489_B253_FD1B26B66929__INCLUDED

#include "jack/control.h"
#include "list.h"

#define PARAM_ADDRESS_SIZE 3

#define PTNODE_ENGINE "engine"
#define PTNODE_DRIVER "driver"
#define PTNODE_DRIVERS "drivers"
#define PTNODE_INTERNALS "internals"

struct jack_parameter_vtable
{
bool (* is_set)(void * obj);
bool (* reset)(void * obj);
union jackctl_parameter_value (* get_value)(void * obj);
bool (* set_value)(void * obj, const union jackctl_parameter_value * value_ptr);
union jackctl_parameter_value (* get_default_value)(void * obj);
};

#define JACK_CONSTRAINT_FLAG_VALID ((uint32_t)1) /**< if not set, there is no constraint */
#define JACK_CONSTRAINT_FLAG_STRICT ((uint32_t)2) /**< if set, constraint is strict, i.e. supplying non-matching value will not work */
#define JACK_CONSTRAINT_FLAG_FAKE_VALUE ((uint32_t)4) /**< if set, values have no user meaningful meaning */

struct jack_parameter_enum
{
union jackctl_parameter_value value;
const char * short_desc;
};

struct jack_parameter
{
void * obj;
struct jack_parameter_vtable vtable;
struct list_head siblings;
bool ext;
jackctl_param_type_t type;
const char * name;
const char * short_decr;
const char * long_descr;

uint32_t constraint_flags; /**< JACK_CONSTRAINT_FLAG_XXX */
bool constraint_range; /**< if true, constraint is a range (min-max), otherwise it is an enumeration */

union
{
struct
{
union jackctl_parameter_value min;
union jackctl_parameter_value max;
} range; /**< valid when JACK_CONSTRAINT_FLAG_RANGE flag is set */

struct
{
uint32_t count;
struct jack_parameter_enum * possible_values_array;
} enumeration; /**< valid when JACK_CONSTRAINT_FLAG_RANGE flag is not set */
} constraint;
};

typedef struct _jack_params { int unused; } * jack_params_handle;

jack_params_handle jack_params_create(jackctl_server_t * server);
void jack_params_destroy(jack_params_handle params);

bool jack_params_set_driver(jack_params_handle params, const char * name);
jackctl_driver_t * jack_params_get_driver(jack_params_handle params);

bool jack_params_check_address(jack_params_handle params, const char * const * address, bool want_leaf);
bool jack_params_is_leaf_container(jack_params_handle params, const char * const * address);

bool
jack_params_iterate_container(
jack_params_handle params,
const char * const * address,
bool (* callback)(void * context, const char * name),
void * context);

bool
jack_params_iterate_params(
jack_params_handle params,
const char * const * address,
bool (* callback)(void * context, const struct jack_parameter * param_ptr),
void * context);

const struct jack_parameter * jack_params_get_parameter(jack_params_handle params, const char * const * address);

void jack_params_add_parameter(jack_params_handle params, const char * const * address, bool end, struct jack_parameter * param_ptr);

#endif /* #ifndef PARAMS_H__A23EDE06_C1C9_4489_B253_FD1B26B66929__INCLUDED */

+ 1
- 1
dbus/wscript View File

@@ -52,6 +52,7 @@ def build(bld):
obj.source = [
'jackdbus.c',
'controller.c',
'params.c',
'controller_iface_configure.c',
'controller_iface_control.c',
'controller_iface_introspectable.c',
@@ -59,7 +60,6 @@ def build(bld):
'controller_iface_transport.c',
'xml.c',
'xml_expat.c',
#'xml_libxml.c',
#'xml_nop.c',
'xml_write_raw.c',
'sigsegv.c',


+ 67
- 309
dbus/xml.c View File

@@ -1,6 +1,6 @@
/* -*- Mode: C ; c-basic-offset: 4 -*- */
/*
Copyright (C) 2007,2008 Nedko Arnaudov
Copyright (C) 2007,2008,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
@@ -25,358 +25,116 @@
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <dbus/dbus.h>

#include "controller_internal.h"

void
jack_controller_settings_set_bool_option(
const char *value_str,
int *value_ptr)
{
if (strcmp(value_str, "true") == 0)
{
*value_ptr = true;
}
else if (strcmp(value_str, "false") == 0)
{
*value_ptr = false;
}
else
{
jack_error("ignoring unknown bool value \"%s\"", value_str);
}
}

void
jack_controller_settings_set_sint_option(
const char *value_str,
int *value_ptr)
{
*value_ptr = atoi(value_str);
}

void
jack_controller_settings_set_uint_option(
const char *value_str,
unsigned int *value_ptr)
{
*value_ptr = strtoul(value_str, NULL, 10);
}

void
jack_controller_settings_set_char_option(
const char *value_str,
char *value_ptr)
{
if (value_str[0] == 0 || value_str[1] != 0)
{
jack_error("invalid char option value \"%s\"", value_str);
return;
}

*value_ptr = *value_str;
}

void
jack_controller_settings_set_string_option(
const char *value_str,
char *value_ptr,
size_t max_size)
{
size_t size;

size = strlen(value_str);

if (size >= max_size)
{
jack_error("string option value \"%s\" is too long, max is %u chars (including terminating zero)", value_str, (unsigned int)max_size);
return;
}

strcpy(value_ptr, value_str);
}

void
jack_controller_settings_set_driver_option(
jackctl_driver_t *driver,
const char *option_name,
const char *option_value)
jack_controller_deserialize_parameter_value(
struct jack_controller *controller_ptr,
const char * const * address,
const char * option_value)
{
jackctl_parameter_t *parameter;
jackctl_param_type_t type;
int value_int = 0;
unsigned int value_uint = 0;
const struct jack_parameter * param_ptr;
union jackctl_parameter_value value;
size_t size;

jack_info("setting driver option \"%s\" to value \"%s\"", option_name, option_value);

parameter = jack_controller_find_parameter(jackctl_driver_get_parameters(driver), option_name);
if (parameter == NULL)
param_ptr = jack_params_get_parameter(controller_ptr->params, address);
if (param_ptr == NULL)
{
jack_error(
"Unknown parameter \"%s\" of driver \"%s\"",
option_name,
jackctl_driver_get_name(driver));
return;
jack_error("Unknown parameter");
goto ignore;
}

type = jackctl_parameter_get_type(parameter);
jack_info("setting parameter '%s':'%s':'%s' to value \"%s\"", address[0], address[1], address[2], option_value);

switch (type)
switch (param_ptr->type)
{
case JackParamInt:
jack_controller_settings_set_sint_option(option_value, &value_int);
value.i = value_int;
value.i = atoi(option_value);
break;
case JackParamUInt:
jack_controller_settings_set_uint_option(option_value, &value_uint);
value.ui = value_uint;
value.ui = strtoul(option_value, NULL, 10);
break;
case JackParamChar:
jack_controller_settings_set_char_option(option_value, &value.c);
if (option_value[0] == 0 || option_value[1] != 0)
{
jack_error("invalid char option value \"%s\"", option_value);
goto ignore;
}
value.c = *option_value;
break;
case JackParamString:
jack_controller_settings_set_string_option(option_value, value.str, sizeof(value.str));
size = strlen(option_value);
if (size >= sizeof(value.str))
{
jack_error("string option value \"%s\" is too long, max is %zu chars (including terminating zero)", option_value, sizeof(value.str));
goto ignore;
}

strcpy(value.str, option_value);
break;
case JackParamBool:
jack_controller_settings_set_bool_option(option_value, &value_int);
value.i = value_int;
if (strcmp(option_value, "true") == 0)
{
value.b = true;
}
else if (strcmp(option_value, "false") == 0)
{
value.b = false;
}
else
{
jack_error("ignoring unknown bool value \"%s\"", option_value);
goto ignore;
}
break;
default:
jack_error("Parameter \"%s\" of driver \"%s\" is of unknown type %d",
jackctl_parameter_get_name(parameter),
jackctl_driver_get_name(driver),
type);
jack_error("Unknown type %d", (int)param_ptr->type);
goto ignore;
}

jackctl_parameter_set_value(parameter, &value);
}

void
jack_controller_settings_set_internal_option(
jackctl_internal_t *internal,
const char *option_name,
const char *option_value)
{
jackctl_parameter_t *parameter;
jackctl_param_type_t type;
int value_int = 0;
unsigned int value_uint = 0;
union jackctl_parameter_value value;

jack_info("setting internal option \"%s\" to value \"%s\"", option_name, option_value);

parameter = jack_controller_find_parameter(jackctl_internal_get_parameters(internal), option_name);
if (parameter == NULL)
if (param_ptr->vtable.set_value(param_ptr->obj, &value))
{
jack_error(
"Unknown parameter \"%s\" of internal \"%s\"",
option_name,
jackctl_internal_get_name(internal));
return;
}

type = jackctl_parameter_get_type(parameter);

switch (type)
{
case JackParamInt:
jack_controller_settings_set_sint_option(option_value, &value_int);
value.i = value_int;
break;
case JackParamUInt:
jack_controller_settings_set_uint_option(option_value, &value_uint);
value.ui = value_uint;
break;
case JackParamChar:
jack_controller_settings_set_char_option(option_value, &value.c);
break;
case JackParamString:
jack_controller_settings_set_string_option(option_value, value.str, sizeof(value.str));
break;
case JackParamBool:
jack_controller_settings_set_bool_option(option_value, &value_int);
value.i = value_int;
break;
default:
jack_error("Parameter \"%s\" of internal \"%s\" is of unknown type %d",
jackctl_parameter_get_name(parameter),
jackctl_internal_get_name(internal),
type);
}
jack_error("Parameter set failed");

jackctl_parameter_set_value(parameter, &value);
ignore:
jack_error("Ignoring restore attempt of parameter '%s':'%s':'%s'", address[0], address[1], address[2]);
}

void
jack_controller_settings_set_engine_option(
struct jack_controller *controller_ptr,
const char *option_name,
const char *option_value)
jack_controller_serialize_parameter_value(
const struct jack_parameter * param_ptr,
char * value_buffer)
{
jackctl_parameter_t *parameter;
jackctl_param_type_t type;
int value_int = 0;
unsigned int value_uint = 0;
union jackctl_parameter_value value;

jack_info("setting engine option \"%s\" to value \"%s\"", option_name, option_value);
value = param_ptr->vtable.get_value(param_ptr->obj);

if (strcmp(option_name, "driver") == 0)
{
if (!jack_controller_select_driver(controller_ptr, option_value))
{
jack_error("unknown driver '%s'", option_value);
}

return;
}

parameter = jack_controller_find_parameter(jackctl_server_get_parameters(controller_ptr->server), option_name);
if (parameter == NULL)
{
jack_error(
"Unknown engine parameter \"%s\"",
option_name);
return;
}

type = jackctl_parameter_get_type(parameter);

switch (type)
switch (param_ptr->type)
{
case JackParamInt:
jack_controller_settings_set_sint_option(option_value, &value_int);
value.i = value_int;
break;
sprintf(value_buffer, "%d", (int)value.i);
return;
case JackParamUInt:
jack_controller_settings_set_uint_option(option_value, &value_uint);
value.ui = value_uint;
break;
sprintf(value_buffer, "%u", (unsigned int)value.ui);
return;
case JackParamChar:
jack_controller_settings_set_char_option(option_value, &value.c);
break;
sprintf(value_buffer, "%c", (char)value.c);
return;
case JackParamString:
jack_controller_settings_set_string_option(option_value, value.str, sizeof(value.str));
break;
strcpy(value_buffer, value.str);
return;
case JackParamBool:
jack_controller_settings_set_bool_option(option_value, &value_int);
value.i = value_int;
break;
default:
jack_error("Engine parameter \"%s\" is of unknown type %d",
jackctl_parameter_get_name(parameter),
type);
}

jackctl_parameter_set_value(parameter, &value);
}

static
bool
jack_controller_settings_save_options(
void *context,
const JSList * parameters_list,
void *dbus_call_context_ptr)
{
jackctl_parameter_t *parameter;
jackctl_param_type_t type;
union jackctl_parameter_value value;
const char * name;
char value_str[50];

while (parameters_list != NULL)
{
parameter = (jackctl_parameter_t *)parameters_list->data;

if (jackctl_parameter_is_set(parameter))
{
type = jackctl_parameter_get_type(parameter);
value = jackctl_parameter_get_value(parameter);
name = jackctl_parameter_get_name(parameter);
switch (type)
{
case JackParamInt:
sprintf(value_str, "%d", (int)value.i);
if (!jack_controller_settings_write_option(context, name, value_str, dbus_call_context_ptr))
{
return false;
}
break;
case JackParamUInt:
sprintf(value_str, "%u", (unsigned int)value.ui);
if (!jack_controller_settings_write_option(context, name, value_str, dbus_call_context_ptr))
{
return false;
}
break;
case JackParamChar:
sprintf(value_str, "%c", (char)value.c);
if (!jack_controller_settings_write_option(context, name, value_str, dbus_call_context_ptr))
{
return false;
}
break;
case JackParamString:
if (!jack_controller_settings_write_option(context, name, value.str, dbus_call_context_ptr))
{
return false;
}
break;
case JackParamBool:
if (!jack_controller_settings_write_option(context, name, value.b ? "true" : "false", dbus_call_context_ptr))
{
return false;
}
break;
default:
jack_error("parameter of unknown type %d", type);
}
}

parameters_list = jack_slist_next(parameters_list);
}

return true;
}

bool
jack_controller_settings_save_engine_options(
void *context,
struct jack_controller *controller_ptr,
void *dbus_call_context_ptr)
{
if (controller_ptr->driver != NULL)
{
if (!jack_controller_settings_write_option(
context,
"driver",
jackctl_driver_get_name(controller_ptr->driver),
dbus_call_context_ptr))
{
return false;
}
strcpy(value_buffer, value.b ? "true" : "false");
return;
}

return jack_controller_settings_save_options(context, jackctl_server_get_parameters(controller_ptr->server), dbus_call_context_ptr);
}

bool
jack_controller_settings_save_driver_options(
void *context,
jackctl_driver_t *driver,
void *dbus_call_context_ptr)
{
return jack_controller_settings_save_options(context, jackctl_driver_get_parameters(driver), dbus_call_context_ptr);
}

bool
jack_controller_settings_save_internal_options(
void *context,
jackctl_internal_t *internal,
void *dbus_call_context_ptr)
{
return jack_controller_settings_save_options(context, jackctl_internal_get_parameters(internal), dbus_call_context_ptr);
jack_error("parameter of unknown type %d", (int)param_ptr->type);
assert(false);
*value_buffer = 0;
}

+ 62
- 104
dbus/xml_expat.c View File

@@ -1,6 +1,6 @@
/* -*- Mode: C ; c-basic-offset: 4 -*- */
/*
Copyright (C) 2007,2008 Nedko Arnaudov
Copyright (C) 2007,2008,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
@@ -29,6 +29,7 @@
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <assert.h>
#include <expat.h>
#include <dbus/dbus.h>

@@ -46,27 +47,16 @@ jack_controller_settings_uninit()
{
}

#define PARSE_CONTEXT_ROOT 0
#define PARSE_CONTEXT_JACK 1
#define PARSE_CONTEXT_ENGINE 1
#define PARSE_CONTEXT_DRIVERS 2
#define PARSE_CONTEXT_DRIVER 3
#define PARSE_CONTEXT_OPTION 4
#define PARSE_CONTEXT_INTERNALS 5
#define PARSE_CONTEXT_INTERNAL 6

#define MAX_STACK_DEPTH 10

struct parse_context
{
struct jack_controller *controller_ptr;
XML_Bool error;
unsigned int element[MAX_STACK_DEPTH];
signed int depth;
jackctl_driver_t *driver;
jackctl_internal_t *internal;
bool option_value_capture;
char option[JACK_PARAM_STRING_MAX+1];
int option_used;
const char * address[PARAM_ADDRESS_SIZE];
int address_index;
char * container;
char *name;
};

@@ -80,7 +70,7 @@ jack_controller_settings_callback_chrdata(void *data, const XML_Char *s, int len
return;
}

if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_OPTION)
if (context_ptr->option_value_capture)
{
if (context_ptr->option_used + len >= JACK_PARAM_STRING_MAX)
{
@@ -97,107 +87,69 @@ jack_controller_settings_callback_chrdata(void *data, const XML_Char *s, int len
void
jack_controller_settings_callback_elstart(void *data, const char *el, const char **attr)
{
jackctl_driver_t *driver;
jackctl_internal_t *internal;

if (context_ptr->error)
{
return;
}

if (context_ptr->depth + 1 >= MAX_STACK_DEPTH)
if (context_ptr->address_index >= PARAM_ADDRESS_SIZE)
{
jack_error("xml parse max stack depth reached");
assert(context_ptr->address_index == PARAM_ADDRESS_SIZE);
jack_error("xml param address max depth reached");
context_ptr->error = XML_TRUE;
return;
}

//jack_info("<%s>", el);

if (strcmp(el, "jack") == 0)
{
//jack_info("<jack>");
context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_JACK;
return;
}

if (strcmp(el, "engine") == 0)
if (strcmp(el, PTNODE_ENGINE) == 0)
{
//jack_info("<engine>");
context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_ENGINE;
context_ptr->address[context_ptr->address_index++] = PTNODE_ENGINE;
return;
}

if (strcmp(el, "drivers") == 0)
if (strcmp(el, PTNODE_DRIVERS) == 0)
{
//jack_info("<drivers>");
context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_DRIVERS;
context_ptr->address[context_ptr->address_index++] = PTNODE_DRIVERS;
return;
}
if (strcmp(el, "internals") == 0)
if (strcmp(el, PTNODE_INTERNALS) == 0)
{
//jack_info("<internals>");
context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_INTERNALS;
context_ptr->address[context_ptr->address_index++] = PTNODE_INTERNALS;
return;
}

if (strcmp(el, "driver") == 0)
if (strcmp(el, "driver") == 0 ||
strcmp(el, "internal") == 0)
{
if ((attr[0] == NULL || attr[2] != NULL) || strcmp(attr[0], "name") != 0)
{
jack_error("<driver> XML element must contain exactly one attribute, named \"name\"");
jack_error("<%s> XML element must contain exactly one attribute, named \"name\"", el);
context_ptr->error = XML_TRUE;
return;
}

//jack_info("<driver>");
context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_DRIVER;

driver = jack_controller_find_driver(context_ptr->controller_ptr->server, attr[1]);
if (driver == NULL)
{
jack_error("ignoring settings for unknown driver \"%s\"", attr[1]);
}
else
{
jack_info("setting for driver \"%s\" found", attr[1]);
}

context_ptr->driver = driver;

return;
}
if (strcmp(el, "internal") == 0)
{
if ((attr[0] == NULL || attr[2] != NULL) || strcmp(attr[0], "name") != 0)
context_ptr->container = strdup(attr[1]);
if (context_ptr->container == NULL)
{
jack_error("<internal> XML element must contain exactly one attribute, named \"name\"");
jack_error("strdup() failed");
context_ptr->error = XML_TRUE;
return;
}

//jack_info("<internal>");
context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_INTERNAL;

internal = jack_controller_find_internal(context_ptr->controller_ptr->server, attr[1]);
if (internal == NULL)
{
jack_error("ignoring settings for unknown internal \"%s\"", attr[1]);
}
else
{
jack_info("setting for internal \"%s\" found", attr[1]);
}

context_ptr->internal = internal;
context_ptr->address[context_ptr->address_index++] = context_ptr->container;

return;
}


if (strcmp(el, "option") == 0)
{
//jack_info("<option>");
if ((attr[0] == NULL || attr[2] != NULL) || strcmp(attr[0], "name") != 0)
{
jack_error("<option> XML element must contain exactly one attribute, named \"name\"");
@@ -213,7 +165,8 @@ jack_controller_settings_callback_elstart(void *data, const char *el, const char
return;
}

context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_OPTION;
context_ptr->address[context_ptr->address_index++] = context_ptr->name;
context_ptr->option_value_capture = true;
context_ptr->option_used = 0;
return;
}
@@ -225,49 +178,48 @@ jack_controller_settings_callback_elstart(void *data, const char *el, const char
void
jack_controller_settings_callback_elend(void *data, const char *el)
{
int i;

if (context_ptr->error)
{
return;
}

//jack_info("element end (depth = %d, element = %u)", context_ptr->depth, context_ptr->element[context_ptr->depth]);
//jack_info("</%s> (depth = %d)", el, context_ptr->address_index);

if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_OPTION)
if (strcmp(el, "option") == 0)
{
assert(context_ptr->option_value_capture);
context_ptr->option[context_ptr->option_used] = 0;

if (context_ptr->depth == 2 &&
context_ptr->element[0] == PARSE_CONTEXT_JACK &&
context_ptr->element[1] == PARSE_CONTEXT_ENGINE)
for (i = context_ptr->address_index; i < PARAM_ADDRESS_SIZE; i++)
{
jack_controller_settings_set_engine_option(context_ptr->controller_ptr, context_ptr->name, context_ptr->option);
context_ptr->address[context_ptr->address_index] = NULL;
}

if (context_ptr->depth == 3 &&
context_ptr->element[0] == PARSE_CONTEXT_JACK &&
context_ptr->element[1] == PARSE_CONTEXT_DRIVERS &&
context_ptr->element[2] == PARSE_CONTEXT_DRIVER &&
context_ptr->driver != NULL)
{
jack_controller_settings_set_driver_option(context_ptr->driver, context_ptr->name, context_ptr->option);
}
if (context_ptr->depth == 3 &&
context_ptr->element[0] == PARSE_CONTEXT_JACK &&
context_ptr->element[1] == PARSE_CONTEXT_INTERNALS &&
context_ptr->element[2] == PARSE_CONTEXT_INTERNAL &&
context_ptr->internal != NULL)
{
jack_controller_settings_set_internal_option(context_ptr->internal, context_ptr->name, context_ptr->option);
}
}
jack_controller_deserialize_parameter_value(context_ptr->controller_ptr, context_ptr->address, context_ptr->option);

context_ptr->depth--;

if (context_ptr->name != NULL)
{
free(context_ptr->name);
context_ptr->name = NULL;
context_ptr->option_value_capture = false;
context_ptr->address_index--;
}
else if (context_ptr->container != NULL)
{
//jack_info("'%s'", context_ptr->container);
free(context_ptr->container);
context_ptr->container = NULL;
context_ptr->address_index--;
}
else if (strcmp(el, PTNODE_ENGINE) == 0 ||
strcmp(el, PTNODE_DRIVERS) == 0 ||
strcmp(el, PTNODE_INTERNALS) == 0)
{
context_ptr->address_index--;
}
else
{
//jack_info("no depth decrement");
}
}

@@ -341,14 +293,20 @@ jack_controller_settings_load(

context.controller_ptr = controller_ptr;
context.error = XML_FALSE;
context.depth = -1;
context.option_value_capture = false;
context.address_index = 0;
context.name = NULL;
context.container = NULL;

XML_SetElementHandler(parser, jack_controller_settings_callback_elstart, jack_controller_settings_callback_elend);
XML_SetCharacterDataHandler(parser, jack_controller_settings_callback_chrdata);
XML_SetUserData(parser, &context);

xmls = XML_ParseBuffer(parser, bytes_read, XML_TRUE);

free(context.name);
free(context.container);

if (xmls == XML_STATUS_ERROR)
{
jack_error("XML_ParseBuffer() failed.");


+ 0
- 797
dbus/xml_libxml.c View File

@@ -1,797 +0,0 @@
/* -*- Mode: C ; c-basic-offset: 4 -*- */
/*
Copyright (C) 2007,2008 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 <stdbool.h>
#include <string.h>
#include <dbus/dbus.h>

#include <libxml/xmlwriter.h>
#include <libxml/parser.h>
#include <libxml/xpath.h>

#include <jack/driver.h>
#include <jack/engine.h>
#include "controller_internal.h"
#include "dbus.h"

/* XPath expression used for engine options selection */
#define XPATH_ENGINE_OPTIONS_EXPRESSION "/jack/engine/option"

/* XPath expression used for drivers selection */
#define XPATH_DRIVERS_EXPRESSION "/jack/drivers/driver"

/* XPath expression used for driver options selection */
#define XPATH_DRIVER_OPTIONS_EXPRESSION "/jack/drivers/driver[@name = '%s']/option"

bool
jack_controller_settings_init()
{
/*
* this initialize the library and check potential ABI mismatches
* between the version it was compiled for and the actual shared
* library used.
*/
LIBXML_TEST_VERSION;

return true;
}

void
jack_controller_settings_uninit()
{
}

#define writer ((xmlTextWriterPtr)context)

bool
jack_controller_settings_write_option(
void *context,
const char *name,
const char *content,
void *dbus_call_context_ptr)
{
if (xmlTextWriterStartElement(writer, BAD_CAST "option") == -1)
{
jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
return false;
}

if (xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST name) == -1)
{
jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteAttribute() failed.");
return false;
}

if (xmlTextWriterWriteString(writer, BAD_CAST content) == -1)
{
jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteString() failed.");
return false;
}

if (xmlTextWriterEndElement(writer) == -1)
{
jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed.");
return false;
}

return true;
}

#undef writer

bool
jack_controller_settings_write_engine(
struct jack_controller * controller_ptr,
xmlTextWriterPtr writer,
void *dbus_call_context_ptr)
{
/* jack_info("engine settings begin"); */

/* if (xmlTextWriterWriteComment(writer, BAD_CAST "engine parameters") == -1) */
/* { */
/* jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed."); */
/* return false; */
/* } */

if (xmlTextWriterStartElement(writer, BAD_CAST "engine") == -1)
{
jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
return false;
}

if (!jack_controller_settings_save_engine_options(writer, controller_ptr, dbus_call_context_ptr))
{
return false;
}

if (xmlTextWriterEndElement(writer) == -1)
{
jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed.");
return false;
}

/* jack_info("engine settings end"); */
return true;
}

bool
jack_controller_settings_write_driver(
struct jack_controller * controller_ptr,
xmlTextWriterPtr writer,
jackctl_driver driver,
void *dbus_call_context_ptr)
{
/* if (xmlTextWriterWriteComment(writer, BAD_CAST "driver parameters") == -1) */
/* { */
/* jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed."); */
/* return false; */
/* } */

if (xmlTextWriterStartElement(writer, BAD_CAST "driver") == -1)
{
jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
return false;
}

if (xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST jackctl_driver_get_name(driver)) == -1)
{
jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteAttribute() failed.");
return false;
}

if (!jack_controller_settings_save_driver_options(writer, driver, dbus_call_context_ptr))
{
return false;
}

if (xmlTextWriterEndElement(writer) == -1)
{
jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed.");
return false;
}

return true;
}

bool
jack_controller_settings_write_drivers(
struct jack_controller * controller_ptr,
xmlTextWriterPtr writer,
void *dbus_call_context_ptr)
{
const JSList * node_ptr;
jackctl_driver driver;

if (xmlTextWriterStartElement(writer, BAD_CAST "drivers") == -1)
{
jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
return false;
}

node_ptr = jackctl_server_get_drivers_list(controller_ptr->server);

while (node_ptr != NULL)
{
driver = (jackctl_driver)node_ptr->data;

if (!jack_controller_settings_write_driver(
controller_ptr,
writer,
driver,
dbus_call_context_ptr))
{
return false;
}

node_ptr = jack_slist_next(node_ptr);
}

if (xmlTextWriterEndElement(writer) == -1)
{
jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed.");
return false;
}

return true;
}

bool
jack_controller_settings_write_internal(
struct jack_controller * controller_ptr,
xmlTextWriterPtr writer,
jackctl_internal internal,
void *dbus_call_context_ptr)
{
/* if (xmlTextWriterWriteComment(writer, BAD_CAST "driver parameters") == -1) */
/* { */
/* jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed."); */
/* return false; */
/* } */

if (xmlTextWriterStartElement(writer, BAD_CAST "internal") == -1)
{
jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
return false;
}

if (xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST jackctl_internal_get_name(driver)) == -1)
{
jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteAttribute() failed.");
return false;
}

if (!jack_controller_settings_save_internal_options(writer, internal, dbus_call_context_ptr))
{
return false;
}

if (xmlTextWriterEndElement(writer) == -1)
{
jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed.");
return false;
}

return true;
}

bool
jack_controller_settings_write_internals(
struct jack_controller * controller_ptr,
xmlTextWriterPtr writer,
void *dbus_call_context_ptr)
{
const JSList * node_ptr;
jackctl_driver internal;

if (xmlTextWriterStartElement(writer, BAD_CAST "internals") == -1)
{
jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
return false;
}

node_ptr = jackctl_server_get_internals_list(controller_ptr->server);

while (node_ptr != NULL)
{
internal = (jackctl_internal)node_ptr->data;

if (!jack_controller_settings_write_internal(
controller_ptr,
writer,
internal,
dbus_call_context_ptr))
{
return false;
}

node_ptr = jack_slist_next(node_ptr);
}

if (xmlTextWriterEndElement(writer) == -1)
{
jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed.");
return false;
}

return true;
}

bool
jack_controller_settings_save(
struct jack_controller * controller_ptr,
void *dbus_call_context_ptr)
{
xmlTextWriterPtr writer;
char *filename;
size_t conf_len;
bool ret;
time_t timestamp;
char timestamp_str[28];

time(&timestamp);
timestamp_str[0] = ' ';
ctime_r(&timestamp, timestamp_str + 1);
timestamp_str[25] = ' ';

ret = false;

conf_len = strlen(JACKDBUS_CONF);

filename = malloc(g_jackdbus_dir_len + conf_len + 1);
if (filename == NULL)
{
jack_error("Out of memory.");
goto fail;
}

memcpy(filename, g_jackdbus_dir, g_jackdbus_dir_len);
memcpy(filename + g_jackdbus_dir_len, JACKDBUS_CONF, conf_len);
filename[g_jackdbus_dir_len + conf_len] = 0;

jack_info("saving settings to \"%s\"", filename);

writer = xmlNewTextWriterFilename(filename, 0);
if (writer == NULL)
{
jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "Error creating the xml writer.");
goto fail_free_filename;
}

if (xmlTextWriterSetIndent(writer, 1) == -1)
{
jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterSetIndent() failed.");
goto fail_free_writter;
}

if (xmlTextWriterStartDocument(writer, NULL, NULL, NULL) == -1)
{
jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartDocument() failed.");
goto fail_free_writter;
}

if (xmlTextWriterWriteComment(writer, BAD_CAST "\n" JACK_CONF_HEADER_TEXT) == -1)
{
jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed.");
goto fail_free_writter;
}

if (xmlTextWriterWriteComment(writer, BAD_CAST timestamp_str) == -1)
{
jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed.");
goto fail_free_writter;
}

if (xmlTextWriterStartElement(writer, BAD_CAST "jack") == -1)
{
jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
goto fail_free_writter;
}

if (!jack_controller_settings_write_engine(controller_ptr, writer, dbus_call_context_ptr))
{
goto fail_free_writter;
}

if (!jack_controller_settings_write_drivers(controller_ptr, writer, dbus_call_context_ptr))
{
goto fail_free_writter;
}
if (!jack_controller_settings_write_internals(controller_ptr, writer, dbus_call_context_ptr))
{
goto fail_free_writter;
}

if (xmlTextWriterEndElement(writer) == -1)
{
jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
goto fail_free_writter;
}

if (xmlTextWriterEndDocument(writer) == -1)
{
jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndDocument() failed.");
goto fail_free_writter;
}

ret = true;

fail_free_writter:
xmlFreeTextWriter(writer);

fail_free_filename:
free(filename);

fail:
return ret;
}

void
jack_controller_settings_read_engine(
struct jack_controller * controller_ptr,
xmlXPathContextPtr xpath_ctx_ptr)
{
xmlXPathObjectPtr xpath_obj_ptr;
xmlBufferPtr content_buffer_ptr;
int i;
const char *option_name;
const char *option_value;

/* Evaluate xpath expression */
xpath_obj_ptr = xmlXPathEvalExpression((const xmlChar *)XPATH_ENGINE_OPTIONS_EXPRESSION, xpath_ctx_ptr);
if (xpath_obj_ptr == NULL)
{
jack_error("Unable to evaluate XPath expression \"%s\"", XPATH_ENGINE_OPTIONS_EXPRESSION);
goto exit;
}

if (xpath_obj_ptr->nodesetval == NULL || xpath_obj_ptr->nodesetval->nodeNr == 0)
{
jack_error("XPath \"%s\" evaluation returned no data", XPATH_ENGINE_OPTIONS_EXPRESSION);
goto free_xpath_obj;
}

content_buffer_ptr = xmlBufferCreate();
if (content_buffer_ptr == NULL)
{
jack_error("xmlBufferCreate() failed.");
goto free_xpath_obj;
}

for (i = 0 ; i < xpath_obj_ptr->nodesetval->nodeNr ; i++)
{
//jack_info("engine option \"%s\" at index %d", xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name"), i);

if (xmlNodeBufGetContent(content_buffer_ptr, xpath_obj_ptr->nodesetval->nodeTab[i]) == -1)
{
jack_error("xmlNodeBufGetContent() failed.");
goto next_option;
}

option_name = (const char *)xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name");
option_value = (const char *)xmlBufferContent(content_buffer_ptr);

jack_controller_settings_set_engine_option(controller_ptr, option_name, option_value);

next_option:
xmlBufferEmpty(content_buffer_ptr);
}

//free_buffer:
xmlBufferFree(content_buffer_ptr);

free_xpath_obj:
xmlXPathFreeObject(xpath_obj_ptr);

exit:
return;
}

void
jack_controller_settings_read_driver(
struct jack_controller * controller_ptr,
xmlXPathContextPtr xpath_ctx_ptr,
jackctl_driver driver)
{
char *xpath;
size_t xpath_len;
xmlXPathObjectPtr xpath_obj_ptr;
xmlBufferPtr content_buffer_ptr;
int i;
const char *option_name;
const char *option_value;
const char *driver_name;

driver_name = jackctl_driver_get_name(driver);

jack_info("reading options for driver \"%s\"", driver_name);

xpath_len = snprintf(NULL, 0, XPATH_DRIVER_OPTIONS_EXPRESSION, driver_name);

xpath = malloc(xpath_len);
if (xpath == NULL)
{
jack_error("Out of memory.");
goto exit;
}

snprintf(xpath, xpath_len, XPATH_DRIVER_OPTIONS_EXPRESSION, driver_name);

//jack_info("xpath = \"%s\"", xpath);

/* Evaluate xpath expression */
xpath_obj_ptr = xmlXPathEvalExpression((const xmlChar *)xpath, xpath_ctx_ptr);
if (xpath_obj_ptr == NULL)
{
jack_error("Unable to evaluate XPath expression \"%s\"", xpath);
goto free_xpath;
}

if (xpath_obj_ptr->nodesetval == NULL || xpath_obj_ptr->nodesetval->nodeNr == 0)
{
//jack_info("XPath \"%s\" evaluation returned no data", xpath);
goto free_xpath_obj;
}

content_buffer_ptr = xmlBufferCreate();
if (content_buffer_ptr == NULL)
{
jack_error("xmlBufferCreate() failed.");
goto free_xpath_obj;
}

for (i = 0 ; i < xpath_obj_ptr->nodesetval->nodeNr ; i++)
{
//jack_info("driver option \"%s\" at index %d", xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name"), i);

if (xmlNodeBufGetContent(content_buffer_ptr, xpath_obj_ptr->nodesetval->nodeTab[i]) == -1)
{
jack_error("xmlNodeBufGetContent() failed.");
goto next_option;
}

option_name = (const char *)xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name");
option_value = (const char *)xmlBufferContent(content_buffer_ptr);

jack_controller_settings_set_driver_option(driver, option_name, option_value);

next_option:
xmlBufferEmpty(content_buffer_ptr);
}

//free_buffer:
xmlBufferFree(content_buffer_ptr);

free_xpath_obj:
xmlXPathFreeObject(xpath_obj_ptr);

free_xpath:
free(xpath);

exit:
return;
}

void
jack_controller_settings_read_internal(
struct jack_controller * controller_ptr,
xmlXPathContextPtr xpath_ctx_ptr,
jackctl_internal internal)
{
char *xpath;
size_t xpath_len;
xmlXPathObjectPtr xpath_obj_ptr;
xmlBufferPtr content_buffer_ptr;
int i;
const char *option_name;
const char *option_value;
const char *internal_name;

internal_name = jackctl_internal_get_name(internal);

jack_info("reading options for internal \"%s\"", internal_name);

xpath_len = snprintf(NULL, 0, XPATH_DRIVER_OPTIONS_EXPRESSION, internal_name);

xpath = malloc(xpath_len);
if (xpath == NULL)
{
jack_error("Out of memory.");
goto exit;
}

snprintf(xpath, xpath_len, XPATH_DRIVER_OPTIONS_EXPRESSION, internal_name);

//jack_info("xpath = \"%s\"", xpath);

/* Evaluate xpath expression */
xpath_obj_ptr = xmlXPathEvalExpression((const xmlChar *)xpath, xpath_ctx_ptr);
if (xpath_obj_ptr == NULL)
{
jack_error("Unable to evaluate XPath expression \"%s\"", xpath);
goto free_xpath;
}

if (xpath_obj_ptr->nodesetval == NULL || xpath_obj_ptr->nodesetval->nodeNr == 0)
{
//jack_info("XPath \"%s\" evaluation returned no data", xpath);
goto free_xpath_obj;
}

content_buffer_ptr = xmlBufferCreate();
if (content_buffer_ptr == NULL)
{
jack_error("xmlBufferCreate() failed.");
goto free_xpath_obj;
}

for (i = 0 ; i < xpath_obj_ptr->nodesetval->nodeNr ; i++)
{
//jack_info("driver option \"%s\" at index %d", xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name"), i);

if (xmlNodeBufGetContent(content_buffer_ptr, xpath_obj_ptr->nodesetval->nodeTab[i]) == -1)
{
jack_error("xmlNodeBufGetContent() failed.");
goto next_option;
}

option_name = (const char *)xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name");
option_value = (const char *)xmlBufferContent(content_buffer_ptr);

jack_controller_settings_set_internal_option(internal, option_name, option_value);

next_option:
xmlBufferEmpty(content_buffer_ptr);
}

//free_buffer:
xmlBufferFree(content_buffer_ptr);

free_xpath_obj:
xmlXPathFreeObject(xpath_obj_ptr);

free_xpath:
free(xpath);

exit:
return;
}

void
jack_controller_settings_read_drivers(
struct jack_controller * controller_ptr,
xmlXPathContextPtr xpath_ctx_ptr)
{
xmlXPathObjectPtr xpath_obj_ptr;
int i;
const char *driver_name;
jackctl_driver driver;

/* Evaluate xpath expression */
xpath_obj_ptr = xmlXPathEvalExpression((const xmlChar *)XPATH_DRIVERS_EXPRESSION, xpath_ctx_ptr);
if (xpath_obj_ptr == NULL)
{
jack_error("Unable to evaluate XPath expression \"%s\"", XPATH_DRIVERS_EXPRESSION);
goto exit;
}

if (xpath_obj_ptr->nodesetval == NULL || xpath_obj_ptr->nodesetval->nodeNr == 0)
{
jack_error("XPath \"%s\" evaluation returned no data", XPATH_DRIVERS_EXPRESSION);
goto free_xpath_obj;
}

for (i = 0 ; i < xpath_obj_ptr->nodesetval->nodeNr ; i++)
{
driver_name = (const char *)xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name");

driver = jack_controller_find_driver(controller_ptr->server, driver_name);
if (driver == NULL)
{
jack_error("ignoring settings for unknown driver \"%s\"", driver_name);
}
else
{
jack_info("setting for driver \"%s\" found", driver_name);

jack_controller_settings_read_driver(controller_ptr, xpath_ctx_ptr, driver);
}
}

free_xpath_obj:
xmlXPathFreeObject(xpath_obj_ptr);

exit:
return;
}

void
jack_controller_settings_read_internals(
struct jack_controller * controller_ptr,
xmlXPathContextPtr xpath_ctx_ptr)
{
xmlXPathObjectPtr xpath_obj_ptr;
int i;
const char *internal_name;
jackctl_internal internal;

/* Evaluate xpath expression */
xpath_obj_ptr = xmlXPathEvalExpression((const xmlChar *)XPATH_DRIVERS_EXPRESSION, xpath_ctx_ptr);
if (xpath_obj_ptr == NULL)
{
jack_error("Unable to evaluate XPath expression \"%s\"", XPATH_DRIVERS_EXPRESSION);
goto exit;
}

if (xpath_obj_ptr->nodesetval == NULL || xpath_obj_ptr->nodesetval->nodeNr == 0)
{
jack_error("XPath \"%s\" evaluation returned no data", XPATH_DRIVERS_EXPRESSION);
goto free_xpath_obj;
}

for (i = 0 ; i < xpath_obj_ptr->nodesetval->nodeNr ; i++)
{
internal_name = (const char *)xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name");

driver = jack_controller_find_internal(controller_ptr->server, driver_name);
if (driver == NULL)
{
jack_error("ignoring settings for unknown internal \"%s\"", internal_name);
}
else
{
jack_info("setting for internal \"%s\" found", internal_name);

jack_controller_settings_read_internal(controller_ptr, xpath_ctx_ptr, driver);
}
}

free_xpath_obj:
xmlXPathFreeObject(xpath_obj_ptr);

exit:
return;
}


void
jack_controller_settings_load(
struct jack_controller * controller_ptr)
{
char *filename;
size_t conf_len;
xmlDocPtr doc_ptr;
xmlXPathContextPtr xpath_ctx_ptr;

conf_len = strlen(JACKDBUS_CONF);

filename = malloc(g_jackdbus_dir_len + conf_len + 1);
if (filename == NULL)
{
jack_error("Out of memory.");
goto exit;
}

memcpy(filename, g_jackdbus_dir, g_jackdbus_dir_len);
memcpy(filename + g_jackdbus_dir_len, JACKDBUS_CONF, conf_len);
filename[g_jackdbus_dir_len + conf_len] = 0;

jack_info("loading settings from \"%s\"", filename);

doc_ptr = xmlParseFile(filename);
if (doc_ptr == NULL)
{
jack_error("Failed to parse \"%s\"", filename);
goto free_filename;
}

/* Create xpath evaluation context */
xpath_ctx_ptr = xmlXPathNewContext(doc_ptr);
if (xpath_ctx_ptr == NULL)
{
jack_error("Unable to create new XPath context");
goto free_doc;
}

jack_controller_settings_read_engine(controller_ptr, xpath_ctx_ptr);
jack_controller_settings_read_drivers(controller_ptr, xpath_ctx_ptr);
jack_controller_settings_read_internals(controller_ptr, xpath_ctx_ptr);

xmlXPathFreeContext(xpath_ctx_ptr);

free_doc:
xmlFreeDoc(doc_ptr);

free_filename:
free(filename);

exit:
return;
}

void
jack_controller_settings_save_auto(
struct jack_controller * controller_ptr)
{
jack_controller_settings_save(controller_ptr, NULL);
}

+ 59
- 103
dbus/xml_write_raw.c View File

@@ -53,54 +53,57 @@ jack_controller_settings_write_string(int fd, const char * string, void *dbus_ca

struct save_context
{
void * call;
int fd;
const char *indent;
const char * indent;
jack_params_handle params;
const char * address[PARAM_ADDRESS_SIZE];
const char * str;
};

#define save_context_ptr ((struct save_context *)context)
#define fd (save_context_ptr->fd)
#define ctx_ptr ((struct save_context *)context)
#define fd (ctx_ptr->fd)

bool
jack_controller_settings_write_option(
void *context,
const char *name,
const char *content,
void *dbus_call_context_ptr)
static bool jack_controller_serialize_parameter(void * context, const struct jack_parameter * param_ptr)
{
if (!jack_controller_settings_write_string(fd, save_context_ptr->indent, dbus_call_context_ptr))
{
return false;
}

if (!jack_controller_settings_write_string(fd, "<option name=\"", dbus_call_context_ptr))
{
return false;
}
char value[JACK_PARAM_STRING_MAX + 1];

if (!jack_controller_settings_write_string(fd, name, dbus_call_context_ptr))
if (!param_ptr->vtable.is_set(param_ptr->obj))
{
return false;
return true;
}

if (!jack_controller_settings_write_string(fd, "\">", dbus_call_context_ptr))
{
return false;
}
jack_controller_serialize_parameter_value(param_ptr, value);

if (!jack_controller_settings_write_string(fd, content, dbus_call_context_ptr))
{
return false;
}

if (!jack_controller_settings_write_string(fd, "</option>\n", dbus_call_context_ptr))
{
return false;
}
return
jack_controller_settings_write_string(fd, ctx_ptr->indent, ctx_ptr->call) &&
jack_controller_settings_write_string(fd, "<option name=\"", ctx_ptr->call) &&
jack_controller_settings_write_string(fd, param_ptr->name, ctx_ptr->call) &&
jack_controller_settings_write_string(fd, "\">", ctx_ptr->call) &&
jack_controller_settings_write_string(fd, value, ctx_ptr->call) &&
jack_controller_settings_write_string(fd, "</option>\n", ctx_ptr->call);
}

return true;
bool serialize_modules(void * context, const char * name)
{
ctx_ptr->indent = " ";
ctx_ptr->address[1] = name;
ctx_ptr->address[2] = NULL;

return
jack_controller_settings_write_string(fd, " <", ctx_ptr->call) &&
jack_controller_settings_write_string(fd, ctx_ptr->str, ctx_ptr->call) &&
jack_controller_settings_write_string(fd, " name=\"", ctx_ptr->call) &&
jack_controller_settings_write_string(fd, name, ctx_ptr->call) &&
jack_controller_settings_write_string(fd, "\">\n", ctx_ptr->call) &&
jack_params_iterate_params(ctx_ptr->params, ctx_ptr->address, jack_controller_serialize_parameter, ctx_ptr) &&
jack_controller_settings_write_string(fd, " </", ctx_ptr->call) &&
jack_controller_settings_write_string(fd, ctx_ptr->str, ctx_ptr->call) &&
jack_controller_settings_write_string(fd, ">\n", ctx_ptr->call);
}

#undef fd
#undef ctx_ptr

bool
jack_controller_settings_save(
@@ -114,9 +117,9 @@ jack_controller_settings_save(
time_t timestamp;
char timestamp_str[26];
struct save_context context;
const JSList * node_ptr;
jackctl_driver_t *driver;
jackctl_internal_t *internal;
const char * modules[] = {"driver", "internal", NULL};
char buffer[100];
unsigned int i;

time(&timestamp);
ctime_r(&timestamp, timestamp_str);
@@ -147,6 +150,7 @@ jack_controller_settings_save(
}

context.fd = fd;
context.call = dbus_call_context_ptr;

if (!jack_controller_settings_write_string(fd, "<?xml version=\"1.0\"?>\n", dbus_call_context_ptr))
{
@@ -196,7 +200,9 @@ jack_controller_settings_save(
}

context.indent = " ";
if (!jack_controller_settings_save_engine_options(&context, controller_ptr, dbus_call_context_ptr))
context.address[0] = PTNODE_ENGINE;
context.address[1] = NULL;
if (!jack_params_iterate_params(controller_ptr->params, context.address, jack_controller_serialize_parameter, &context))
{
goto exit_close;
}
@@ -206,100 +212,50 @@ jack_controller_settings_save(
goto exit_close;
}

/* drivers */
if (!jack_controller_settings_write_string(fd, " <drivers>\n", dbus_call_context_ptr))
for (i = 0; modules[i] != NULL; i++)
{
goto exit_close;
}

node_ptr = jackctl_server_get_drivers_list(controller_ptr->server);

while (node_ptr != NULL)
{
driver = (jackctl_driver_t *)node_ptr->data;

if (!jack_controller_settings_write_string(fd, " <driver name=\"", dbus_call_context_ptr))
{
goto exit_close;
}

if (!jack_controller_settings_write_string(fd, jackctl_driver_get_name(driver), dbus_call_context_ptr))
{
goto exit_close;
}

if (!jack_controller_settings_write_string(fd, "\">\n", dbus_call_context_ptr))
if (!jack_controller_settings_write_string(fd, " <", dbus_call_context_ptr))
{
goto exit_close;
}

context.indent = " ";

if (!jack_controller_settings_save_driver_options(&context, driver, dbus_call_context_ptr))
if (!jack_controller_settings_write_string(fd, modules[i], dbus_call_context_ptr))
{
goto exit_close;
}

if (!jack_controller_settings_write_string(fd, " </driver>\n", dbus_call_context_ptr))
if (!jack_controller_settings_write_string(fd, "s>\n", dbus_call_context_ptr))
{
goto exit_close;
}

node_ptr = jack_slist_next(node_ptr);
}
context.indent = " ";
context.params = controller_ptr->params;
context.str = modules[i];
strcpy(buffer, modules[i]);
strcat(buffer, "s");
context.address[0] = buffer;
context.address[1] = NULL;

if (!jack_controller_settings_write_string(fd, " </drivers>\n", dbus_call_context_ptr))
{
goto exit_close;
}
/* internals */
if (!jack_controller_settings_write_string(fd, " <internals>\n", dbus_call_context_ptr))
{
goto exit_close;
}

node_ptr = jackctl_server_get_internals_list(controller_ptr->server);

while (node_ptr != NULL)
{
internal = (jackctl_internal_t *)node_ptr->data;

if (!jack_controller_settings_write_string(fd, " <internal name=\"", dbus_call_context_ptr))
if (!jack_params_iterate_container(controller_ptr->params, context.address, serialize_modules, &context))
{
goto exit_close;
}

if (!jack_controller_settings_write_string(fd, jackctl_internal_get_name(internal), dbus_call_context_ptr))
if (!jack_controller_settings_write_string(fd, " </", dbus_call_context_ptr))
{
goto exit_close;
}

if (!jack_controller_settings_write_string(fd, "\">\n", dbus_call_context_ptr))
if (!jack_controller_settings_write_string(fd, modules[i], dbus_call_context_ptr))
{
goto exit_close;
}

context.indent = " ";

if (!jack_controller_settings_save_internal_options(&context, internal, dbus_call_context_ptr))
if (!jack_controller_settings_write_string(fd, "s>\n", dbus_call_context_ptr))
{
goto exit_close;
}

if (!jack_controller_settings_write_string(fd, " </internal>\n", dbus_call_context_ptr))
{
goto exit_close;
}

node_ptr = jack_slist_next(node_ptr);
}

if (!jack_controller_settings_write_string(fd, " </internals>\n", dbus_call_context_ptr))
{
goto exit_close;
}

if (!jack_controller_settings_write_string(fd, "</jack>\n", dbus_call_context_ptr))


+ 70
- 40
example-clients/midi_latency_test.c View File

@@ -49,6 +49,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

#include <errno.h>
#include <math.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -65,8 +66,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <semaphore.h>
#endif

#include <signal.h>

#define ABS(x) (((x) >= 0) ? (x) : (-(x)))

#ifdef WIN32
@@ -75,9 +74,9 @@ typedef HANDLE semaphore_t;
typedef sem_t *semaphore_t;
#endif

const char *ERROR_MSG_TIMEOUT = "timed out while waiting for MIDI message";
const char *ERROR_RESERVE = "could not reserve MIDI event on port buffer";
const char *ERROR_SHUTDOWN = "the JACK server has been shutdown";
const char *ERROR_TIMEOUT1 = "timed out while waiting for MIDI message";

const char *SOURCE_EVENT_RESERVE = "jack_midi_event_reserve";
const char *SOURCE_PROCESS = "handle_process";
@@ -107,7 +106,7 @@ size_t message_size;
jack_latency_range_t out_latency_range;
jack_port_t *out_port;
semaphore_t process_semaphore;
int process_state;
volatile sig_atomic_t process_state;
char *program_name;
jack_port_t *remote_in_port;
jack_port_t *remote_out_port;
@@ -118,13 +117,6 @@ jack_time_t total_latency_time;
size_t unexpected_messages;
size_t xrun_count;

static void signal_handler(int sig)
{
jack_client_close(client);
fprintf(stderr, "signal received, exiting ...\n");
exit(0);
}

#ifdef WIN32
char semaphore_error_msg[1024];
#endif
@@ -133,7 +125,7 @@ static void
output_error(const char *source, const char *message);

static void
output_usage();
output_usage(void);

static void
set_process_error(const char *source, const char *message);
@@ -150,7 +142,7 @@ create_semaphore(int id)
semaphore_t semaphore;

#ifdef WIN32
semaphore = CreateSemaphore(NULL, 0, 1, NULL);
semaphore = CreateSemaphore(NULL, 0, 2, NULL);
#elif defined (__APPLE__)
char name[128];
sprintf(name, "midi_sem_%d", id);
@@ -201,7 +193,7 @@ die(const char *source, const char *error_message)
}

static const char *
get_semaphore_error()
get_semaphore_error(void)
{

#ifdef WIN32
@@ -247,7 +239,7 @@ handle_process(jack_nframes_t frames, void *arg)
switch (wait_semaphore(init_semaphore, 0)) {
case -1:
set_process_error(SOURCE_WAIT_SEMAPHORE, get_semaphore_error());
// Fallthrough on purpose
/* Fallthrough on purpose */
case 0:
return 0;
}
@@ -284,7 +276,7 @@ handle_process(jack_nframes_t frames, void *arg)
microseconds = jack_frames_to_time(client, last_frame_time) -
last_activity_time;
if ((microseconds / 1000000) >= timeout) {
set_process_error(SOURCE_PROCESS, ERROR_TIMEOUT1);
set_process_error(SOURCE_PROCESS, ERROR_MSG_TIMEOUT);
}
break;
found_message:
@@ -307,7 +299,7 @@ handle_process(jack_nframes_t frames, void *arg)
if (messages_received == samples) {
process_state = 2;
if (! signal_semaphore(process_semaphore)) {
// Sigh ...
/* Sigh ... */
die(SOURCE_SIGNAL_SEMAPHORE, get_semaphore_error());
}
break;
@@ -331,11 +323,11 @@ handle_process(jack_nframes_t frames, void *arg)

case 2:
/* State: finished - do nothing */

case -1:
/* State: error - do nothing */
case -2:
/* State: signalled - do nothing */
;

}
return 0;
}
@@ -346,6 +338,16 @@ handle_shutdown(void *arg)
set_process_error(SOURCE_SHUTDOWN, ERROR_SHUTDOWN);
}

static void
handle_signal(int sig)
{
process_state = -2;
if (! signal_semaphore(process_semaphore)) {
/* Sigh ... */
die(SOURCE_SIGNAL_SEMAPHORE, get_semaphore_error());
}
}

static int
handle_xrun(void *arg)
{
@@ -360,7 +362,7 @@ output_error(const char *source, const char *message)
}

static void
output_usage()
output_usage(void)
{
fprintf(stderr, "Usage: %s [options] out-port-name in-port-name\n\n"
"\t-h, --help print program usage\n"
@@ -392,6 +394,32 @@ parse_positive_number_arg(char *s, char *name)
return result;
}

static int
register_signal_handler(void (*func)(int))
{

#ifdef WIN32
if (signal(SIGABRT, func) == SIG_ERR) {
return 0;
}
#else
if (signal(SIGQUIT, func) == SIG_ERR) {
return 0;
}
if (signal(SIGHUP, func) == SIG_ERR) {
return 0;
}
#endif

if (signal(SIGINT, func) == SIG_ERR) {
return 0;
}
if (signal(SIGTERM, func) == SIG_ERR) {
return 0;
}
return 1;
}

static void
set_process_error(const char *source, const char *message)
{
@@ -399,7 +427,7 @@ set_process_error(const char *source, const char *message)
error_message = message;
process_state = -1;
if (! signal_semaphore(process_semaphore)) {
// Sigh
/* Sigh ... */
output_error(source, message);
die(SOURCE_SIGNAL_SEMAPHORE, get_semaphore_error());
}
@@ -565,19 +593,6 @@ main(int argc, char **argv)
(message_size - 2) * sizeof(jack_midi_data_t));
message_2[message_size - 1] = 0xf7;
}

/* install a signal handler to properly quits jack client */
#ifdef WIN32
signal(SIGINT, signal_handler);
signal(SIGABRT, signal_handler);
signal(SIGTERM, signal_handler);
#else
signal(SIGQUIT, signal_handler);
signal(SIGTERM, signal_handler);
signal(SIGHUP, signal_handler);
signal(SIGINT, signal_handler);
#endif

client = jack_client_open(program_name, JackNullOption, NULL);
if (client == NULL) {
error_message = "failed to open JACK client";
@@ -657,11 +672,21 @@ main(int argc, char **argv)
error_source = "post_semaphore";
goto deactivate_client;
}
if (! register_signal_handler(handle_signal)) {
error_message = strerror(errno);
error_source = "register_signal_handler";
goto deactivate_client;
}
if (wait_semaphore(process_semaphore, 1) == -1) {
error_message = get_semaphore_error();
error_source = "wait_semaphore";
goto deactivate_client;
}
if (! register_signal_handler(SIG_DFL)) {
error_message = strerror(errno);
error_source = "register_signal_handler";
goto deactivate_client;
}
if (process_state == 2) {
double average_latency = ((double) total_latency) / samples;
double average_latency_time = total_latency_time / samples;
@@ -739,17 +764,22 @@ main(int argc, char **argv)
latency_plot[100]);
}
}
printf("\nMessages sent: %d\n"
"Messages received: %d\n",
messages_sent, messages_received);
deactivate_client:
jack_deactivate(client);

/* Output this information after deactivation to prevent two threads
from accessing data at the same time. */
if (process_state != 2) {
printf("\nMessages sent: %d\nMessages received: %d\n", messages_sent,
messages_received);
}
if (unexpected_messages) {
printf("Unexpected messages received: %d\n", unexpected_messages);
}
if (xrun_count) {
printf("Xruns: %d (messages may have been lost)\n", xrun_count);
printf("Xruns: %d\n", xrun_count);
}
deactivate_client:
jack_deactivate(client);

destroy_process_semaphore:
destroy_semaphore(process_semaphore, 1);
destroy_init_semaphore:


+ 1
- 1
example-clients/samplerate.c View File

@@ -56,7 +56,7 @@ void parse_arguments(int argc, char *argv[])
if (argc==1) {
return;
}
fprintf(stderr, "usage: %s [bufsize]\n", package);
fprintf(stderr, "usage: %s\n", package);
exit(9);
}



+ 2
- 0
linux/JackLinuxTime.c View File

@@ -166,6 +166,8 @@ static jack_time_t jack_get_mhz (void)
ret = sscanf(buf, "Clocking: %" SCNu64, &mhz);
#elif defined( __s390__ )
ret = sscanf(buf, "bogomips per cpu: %" SCNu64, &mhz);
#elif defined( __sh__ )
ret = sscanf(buf, "bogomips : %" SCNu64, &mhz);
#else /* MIPS, ARM, alpha */
ret = sscanf(buf, "BogoMIPS : %" SCNu64, &mhz);
#endif


+ 184
- 134
linux/alsarawmidi/JackALSARawMidiDriver.cpp View File

@@ -24,6 +24,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include <alsa/asoundlib.h>

#include "JackALSARawMidiDriver.h"
#include "JackALSARawMidiUtil.h"
#include "JackEngineControl.h"
#include "JackError.h"
#include "JackMidiUtil.h"
@@ -43,6 +44,7 @@ JackALSARawMidiDriver::JackALSARawMidiDriver(const char *name,
fPlaybackChannels = 0;
input_ports = 0;
output_ports = 0;
output_port_timeouts = 0;
poll_fds = 0;
}

@@ -72,7 +74,7 @@ JackALSARawMidiDriver::Attach()
if (index == NO_PORT) {
jack_error("JackALSARawMidiDriver::Attach - cannot register input "
"port with name '%s'.", name);
// X: Do we need to deallocate ports?
// XX: Do we need to deallocate ports?
return -1;
}
alias = input_port->GetAlias();
@@ -99,7 +101,7 @@ JackALSARawMidiDriver::Attach()
if (index == NO_PORT) {
jack_error("JackALSARawMidiDriver::Attach - cannot register "
"output port with name '%s'.", name);
// X: Do we need to deallocate ports?
// XX: Do we need to deallocate ports?
return -1;
}
alias = output_port->GetAlias();
@@ -143,15 +145,51 @@ JackALSARawMidiDriver::Execute()
{
jack_nframes_t timeout_frame = 0;
for (;;) {
jack_nframes_t process_frame;
unsigned short revents;
jack_nframes_t *timeout_frame_ptr;
struct timespec timeout;
struct timespec *timeout_ptr;
if (! timeout_frame) {
timeout_frame_ptr = 0;
timeout_ptr = 0;
} else {
timeout_frame_ptr = &timeout_frame;

// The timeout value is relative to the time that
// 'GetMicroSeconds()' is called, not the time that 'poll()' is
// called. This means that the amount of time that passes between
// 'GetMicroSeconds()' and 'ppoll()' is time that will be lost
// while waiting for 'poll() to timeout.
//
// I tried to replace the timeout with a 'timerfd' with absolute
// times, but, strangely, it actually slowed things down, and made
// the code a lot more complicated.
//
// I wonder about using the 'epoll' interface instead of 'ppoll()'.
// The problem with the 'epoll' interface is that the timeout
// resolution of 'epoll_wait()' is set in milliseconds. We need
// microsecond resolution. Without microsecond resolution, we
// impose the same jitter as USB MIDI.
//
// Another problem is that 'ppoll()' returns later than the wait
// time. The problem can be minimized with high precision timers.

timeout_ptr = &timeout;
jack_time_t next_time = GetTimeFromFrames(timeout_frame);
jack_time_t now = GetMicroSeconds();
if (next_time <= now) {
timeout.tv_sec = 0;
timeout.tv_nsec = 0;
} else {
jack_time_t wait_time = next_time - now;
timeout.tv_sec = wait_time / 1000000;
timeout.tv_nsec = (wait_time % 1000000) * 1000;
}
}
if (Poll(timeout_frame_ptr) == -1) {
int poll_result = ppoll(poll_fds, poll_fd_count, timeout_ptr, 0);

// Getting the current frame value here allows us to use it for
// incoming MIDI bytes. This makes sense, as the data has already
// arrived at this point.
jack_nframes_t current_frame = GetCurrentFrame();

if (poll_result == -1) {
if (errno == EINTR) {
continue;
}
@@ -159,38 +197,73 @@ JackALSARawMidiDriver::Execute()
strerror(errno));
break;
}
revents = poll_fds[0].revents;
if (revents & POLLHUP) {
// Driver is being stopped.
break;
jack_nframes_t port_timeout;
timeout_frame = 0;
if (! poll_result) {

// No I/O events occurred. So, only handle timeout events on
// output ports.

for (int i = 0; i < fPlaybackChannels; i++) {
port_timeout = output_port_timeouts[i];
if (port_timeout && (port_timeout <= current_frame)) {
if (! output_ports[i]->ProcessPollEvents(false, true,
&port_timeout)) {
jack_error("JackALSARawMidiDriver::Execute - a fatal "
"error occurred while processing ALSA "
"output events.");
goto cleanup;
}
output_port_timeouts[i] = port_timeout;
}
if (port_timeout && ((! timeout_frame) ||
(port_timeout < timeout_frame))) {
timeout_frame = port_timeout;
}
}
continue;
}
if (revents & (~ POLLIN)) {
jack_error("JackALSARawMidiDriver::Execute - unexpected poll "
"event on pipe file descriptor.");

// See if it's time to shutdown.

unsigned short revents = poll_fds[0].revents;
if (revents) {
if (revents & (~ POLLHUP)) {
jack_error("JackALSARawMidiDriver::Execute - unexpected poll "
"event on pipe file descriptor.");
}
break;
}
timeout_frame = 0;
for (int i = 0; i < fCaptureChannels; i++) {
if (! input_ports[i]->ProcessALSA(&process_frame)) {

// Handle I/O events *and* timeout events on output ports.

for (int i = 0; i < fPlaybackChannels; i++) {
port_timeout = output_port_timeouts[i];
bool timeout = port_timeout && (port_timeout <= current_frame);
if (! output_ports[i]->ProcessPollEvents(true, timeout,
&port_timeout)) {
jack_error("JackALSARawMidiDriver::Execute - a fatal error "
"occurred while processing ALSA input events.");
"occurred while processing ALSA output events.");
goto cleanup;
}
if (process_frame && ((! timeout_frame) ||
(process_frame < timeout_frame))) {
timeout_frame = process_frame;
output_port_timeouts[i] = port_timeout;
if (port_timeout && ((! timeout_frame) ||
(port_timeout < timeout_frame))) {
timeout_frame = port_timeout;
}
}
for (int i = 0; i < fPlaybackChannels; i++) {
if (! output_ports[i]->ProcessALSA(fds[0], &process_frame)) {

// Handle I/O events on input ports. We handle these last because we
// already computed the arrival time above, and will impose a delay on
// the events by 'period-size' frames anyway, which gives us a bit of
// borrowed time.

for (int i = 0; i < fCaptureChannels; i++) {
if (! input_ports[i]->ProcessPollEvents(current_frame)) {
jack_error("JackALSARawMidiDriver::Execute - a fatal error "
"occurred while processing ALSA output events.");
"occurred while processing ALSA input events.");
goto cleanup;
}
if (process_frame && ((! timeout_frame) ||
(process_frame < timeout_frame))) {
timeout_frame = process_frame;
}
}
}
cleanup:
@@ -202,6 +275,21 @@ JackALSARawMidiDriver::Execute()
return false;
}

void
JackALSARawMidiDriver::
FreeDeviceInfo(std::vector<snd_rawmidi_info_t *> *in_info_list,
std::vector<snd_rawmidi_info_t *> *out_info_list)
{
size_t length = in_info_list->size();
for (size_t i = 0; i < length; i++) {
snd_rawmidi_info_free(in_info_list->at(i));
}
length = out_info_list->size();
for (size_t i = 0; i < length; i++) {
snd_rawmidi_info_free(out_info_list->at(i));
}
}

void
JackALSARawMidiDriver::
GetDeviceInfo(snd_ctl_t *control, snd_rawmidi_info_t *info,
@@ -315,39 +403,35 @@ JackALSARawMidiDriver::Open(bool capturing, bool playing, int in_channels,
if (! (potential_inputs || potential_outputs)) {
jack_error("JackALSARawMidiDriver::Open - no ALSA raw MIDI input or "
"output ports found.");
FreeDeviceInfo(&in_info_list, &out_info_list);
return -1;
}

// XXX: Can't use auto_ptr here. These are arrays, and require the
// delete[] operator.
std::auto_ptr<JackALSARawMidiInputPort *> input_ptr;
size_t num_inputs = 0;
size_t num_outputs = 0;
if (potential_inputs) {
input_ports = new JackALSARawMidiInputPort *[potential_inputs];
input_ptr.reset(input_ports);
try {
input_ports = new JackALSARawMidiInputPort *[potential_inputs];
} catch (std::exception e) {
jack_error("JackALSARawMidiDriver::Open - while creating input "
"port array: %s", e.what());
FreeDeviceInfo(&in_info_list, &out_info_list);
return -1;
}
}
std::auto_ptr<JackALSARawMidiOutputPort *> output_ptr;
if (potential_outputs) {
output_ports = new JackALSARawMidiOutputPort *[potential_outputs];
output_ptr.reset(output_ports);
try {
output_ports = new JackALSARawMidiOutputPort *[potential_outputs];
} catch (std::exception e) {
jack_error("JackALSARawMidiDriver::Open - while creating output "
"port array: %s", e.what());
FreeDeviceInfo(&in_info_list, &out_info_list);
goto delete_input_ports;
}
}

size_t num_inputs = 0;
size_t num_outputs = 0;
for (size_t i = 0; i < potential_inputs; i++) {
snd_rawmidi_info_t *info = in_info_list.at(i);
try {
input_ports[num_inputs] = new JackALSARawMidiInputPort(info, i);

jack_info("JackALSARawMidiDriver::Open - Input port: card=%d, "
"device=%d, subdevice=%d, id=%s, name=%s, subdevice "
"name=%s",
snd_rawmidi_info_get_card(info),
snd_rawmidi_info_get_device(info),
snd_rawmidi_info_get_subdevice(info),
snd_rawmidi_info_get_id(info),
snd_rawmidi_info_get_name(info),
snd_rawmidi_info_get_subdevice_name(info));

num_inputs++;
} catch (std::exception e) {
jack_error("JackALSARawMidiDriver::Open - while creating new "
@@ -359,17 +443,6 @@ JackALSARawMidiDriver::Open(bool capturing, bool playing, int in_channels,
snd_rawmidi_info_t *info = out_info_list.at(i);
try {
output_ports[num_outputs] = new JackALSARawMidiOutputPort(info, i);

jack_info("JackALSARawMidiDriver::Open - Output port: card=%d, "
"device=%d, subdevice=%d, id=%s, name=%s, subdevice "
"name=%s",
snd_rawmidi_info_get_card(info),
snd_rawmidi_info_get_device(info),
snd_rawmidi_info_get_subdevice(info),
snd_rawmidi_info_get_id(info),
snd_rawmidi_info_get_name(info),
snd_rawmidi_info_get_subdevice_name(info));

num_outputs++;
} catch (std::exception e) {
jack_error("JackALSARawMidiDriver::Open - while creating new "
@@ -377,49 +450,33 @@ JackALSARawMidiDriver::Open(bool capturing, bool playing, int in_channels,
}
snd_rawmidi_info_free(info);
}
if (num_inputs || num_outputs) {
if (! JackMidiDriver::Open(capturing, playing, num_inputs, num_outputs,
monitor, capture_driver_name,
playback_driver_name, capture_latency,
playback_latency)) {
if (potential_inputs) {
input_ptr.release();
}
if (potential_outputs) {
output_ptr.release();
}
return 0;
}
jack_error("JackALSARawMidiDriver::Open - JackMidiDriver::Open error");
} else {
if (! (num_inputs || num_outputs)) {
jack_error("JackALSARawMidiDriver::Open - none of the potential "
"inputs or outputs were successfully opened.");
}
Close();
return -1;
}

int
JackALSARawMidiDriver::Poll(const jack_nframes_t *wakeup_frame)
{
struct timespec timeout;
struct timespec *timeout_ptr;
if (! wakeup_frame) {
timeout_ptr = 0;
} else if (JackMidiDriver::Open(capturing, playing, num_inputs,
num_outputs, monitor, capture_driver_name,
playback_driver_name, capture_latency,
playback_latency)) {
jack_error("JackALSARawMidiDriver::Open - JackMidiDriver::Open error");
} else {
timeout_ptr = &timeout;
jack_time_t next_time = GetTimeFromFrames(*wakeup_frame);
jack_time_t now = GetMicroSeconds();
if (next_time <= now) {
timeout.tv_sec = 0;
timeout.tv_nsec = 0;
} else {
jack_time_t wait_time = next_time - now;
timeout.tv_sec = wait_time / 1000000;
timeout.tv_nsec = (wait_time % 1000000) * 1000;
return 0;
}
if (output_ports) {
for (size_t i = 0; i < num_outputs; i++) {
delete output_ports[i];
}
delete[] output_ports;
output_ports = 0;
}
delete_input_ports:
if (input_ports) {
for (size_t i = 0; i < num_inputs; i++) {
delete input_ports[i];
}
delete[] input_ports;
input_ports = 0;
}
return ppoll(poll_fds, poll_fd_count, timeout_ptr, 0);
return -1;
}

int
@@ -450,39 +507,27 @@ JackALSARawMidiDriver::Start()
}
try {
poll_fds = new pollfd[poll_fd_count];
} catch (std::bad_alloc e) {
} catch (std::exception e) {
jack_error("JackALSARawMidiDriver::Start - creating poll descriptor "
"structures failed: %s", e.what());
return -1;
}
int flags;
if (fPlaybackChannels) {
try {
output_port_timeouts = new jack_nframes_t[fPlaybackChannels];
} catch (std::exception e) {
jack_error("JackALSARawMidiDriver::Start - creating array for "
"output port timeout values failed: %s", e.what());
goto free_poll_descriptors;
}
}
struct pollfd *poll_fd_iter;
if (pipe(fds) == -1) {
try {
CreateNonBlockingPipe(fds);
} catch (std::exception e) {
jack_error("JackALSARawMidiDriver::Start - while creating wake pipe: "
"%s", strerror(errno));
goto free_poll_descriptors;
}
flags = fcntl(fds[0], F_GETFL);
if (flags == -1) {
jack_error("JackALSARawMidiDriver::Start = while getting flags for "
"read file descriptor: %s", strerror(errno));
goto close_fds;
}
if (fcntl(fds[0], F_SETFL, flags | O_NONBLOCK) == -1) {
jack_error("JackALSARawMidiDriver::Start - while setting non-blocking "
"mode for read file descriptor: %s", strerror(errno));
goto close_fds;
}
flags = fcntl(fds[1], F_GETFL);
if (flags == -1) {
jack_error("JackALSARawMidiDriver::Start = while getting flags for "
"write file descriptor: %s", strerror(errno));
goto close_fds;
}
if (fcntl(fds[1], F_SETFL, flags | O_NONBLOCK) == -1) {
jack_error("JackALSARawMidiDriver::Start - while setting non-blocking "
"mode for write file descriptor: %s", strerror(errno));
goto close_fds;
"%s", e.what());
goto free_output_port_timeouts;
}
poll_fds[0].events = POLLERR | POLLIN | POLLNVAL;
poll_fds[0].fd = fds[0];
@@ -496,6 +541,7 @@ JackALSARawMidiDriver::Start()
JackALSARawMidiOutputPort *output_port = output_ports[i];
output_port->PopulatePollDescriptors(poll_fd_iter);
poll_fd_iter += output_port->GetPollDescriptorCount();
output_port_timeouts[i] = 0;
}

jack_info("JackALSARawMidiDriver::Start - starting ALSA thread ...");
@@ -508,11 +554,13 @@ JackALSARawMidiDriver::Start()
}
jack_error("JackALSARawMidiDriver::Start - failed to start MIDI "
"processing thread.");
close_fds:
close(fds[1]);
DestroyNonBlockingPipe(fds);
fds[1] = -1;
close(fds[0]);
fds[0] = -1;
free_output_port_timeouts:
delete[] output_port_timeouts;
output_port_timeouts = 0;
free_poll_descriptors:
delete[] poll_fds;
poll_fds = 0;
@@ -548,6 +596,10 @@ JackALSARawMidiDriver::Stop()
close(fds[0]);
fds[0] = -1;
}
if (output_port_timeouts) {
delete[] output_port_timeouts;
output_port_timeouts = 0;
}
if (poll_fds) {
delete[] poll_fds;
poll_fds = 0;
@@ -563,10 +615,8 @@ int
JackALSARawMidiDriver::Write()
{
jack_nframes_t buffer_size = fEngineControl->fBufferSize;
int write_fd = fds[1];
for (int i = 0; i < fPlaybackChannels; i++) {
if (! output_ports[i]->ProcessJack(GetOutputBuffer(i), buffer_size,
write_fd)) {
if (! output_ports[i]->ProcessJack(GetOutputBuffer(i), buffer_size)) {
return -1;
}
}


+ 5
- 3
linux/alsarawmidi/JackALSARawMidiDriver.h View File

@@ -40,10 +40,15 @@ namespace Jack {
int fds[2];
JackALSARawMidiInputPort **input_ports;
JackALSARawMidiOutputPort **output_ports;
jack_nframes_t *output_port_timeouts;
nfds_t poll_fd_count;
struct pollfd *poll_fds;
JackThread *thread;

void
FreeDeviceInfo(std::vector<snd_rawmidi_info_t *> *in_info_list,
std::vector<snd_rawmidi_info_t *> *out_info_list);

void
GetDeviceInfo(snd_ctl_t *control, snd_rawmidi_info_t *info,
std::vector<snd_rawmidi_info_t *> *info_list);
@@ -52,9 +57,6 @@ namespace Jack {
HandleALSAError(const char *driver_func, const char *alsa_func,
int code);

int
Poll(const jack_nframes_t *wakeup_frame);

public:

JackALSARawMidiDriver(const char *name, const char *alias,


+ 50
- 71
linux/alsarawmidi/JackALSARawMidiInputPort.cpp View File

@@ -17,6 +17,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

#include <cassert>
#include <memory>

#include "JackALSARawMidiInputPort.h"
@@ -28,7 +29,7 @@ JackALSARawMidiInputPort::JackALSARawMidiInputPort(snd_rawmidi_info_t *info,
size_t index,
size_t max_bytes,
size_t max_messages):
JackALSARawMidiPort(info, index)
JackALSARawMidiPort(info, index, POLLIN)
{
alsa_event = 0;
jack_event = 0;
@@ -53,91 +54,69 @@ JackALSARawMidiInputPort::~JackALSARawMidiInputPort()
delete write_queue;
}

jack_nframes_t
JackALSARawMidiInputPort::EnqueueALSAEvent()
{
switch (raw_queue->EnqueueEvent(alsa_event)) {
case JackMidiWriteQueue::BUFFER_FULL:
// Processing events early might free up some space in the raw queue.
raw_queue->Process();
switch (raw_queue->EnqueueEvent(alsa_event)) {
case JackMidiWriteQueue::BUFFER_TOO_SMALL:
jack_error("JackALSARawMidiInputPort::Process - **BUG** "
"JackMidiRawInputWriteQueue::EnqueueEvent returned "
"`BUFFER_FULL` and then returned `BUFFER_TOO_SMALL` "
"after a `Process()` call.");
// Fallthrough on purpose
case JackMidiWriteQueue::OK:
return 0;
default:
;
}
break;
case JackMidiWriteQueue::BUFFER_TOO_SMALL:
jack_error("JackALSARawMidiInputPort::Execute - The thread queue "
"couldn't enqueue a %d-byte packet. Dropping event.",
alsa_event->size);
// Fallthrough on purpose
case JackMidiWriteQueue::OK:
return 0;
default:
;
}
jack_nframes_t alsa_time = alsa_event->time;
jack_nframes_t next_time = raw_queue->Process();
return (next_time < alsa_time) ? next_time : alsa_time;
}

bool
JackALSARawMidiInputPort::ProcessALSA(jack_nframes_t *frame)
{
unsigned short revents;
if (! ProcessPollEvents(&revents)) {
return false;
}
if (alsa_event) {
*frame = EnqueueALSAEvent();
if (*frame) {
return true;
}
}
if (revents & POLLIN) {
for (alsa_event = receive_queue->DequeueEvent(); alsa_event;
alsa_event = receive_queue->DequeueEvent()) {
*frame = EnqueueALSAEvent();
if (*frame) {
return true;
}
}
}
*frame = raw_queue->Process();
return true;
}

bool
JackALSARawMidiInputPort::ProcessJack(JackMidiBuffer *port_buffer,
jack_nframes_t frames)
{
write_queue->ResetMidiBuffer(port_buffer, frames);
bool dequeued = false;
if (! jack_event) {
jack_event = thread_queue->DequeueEvent();
goto dequeue_event;
}
for (; jack_event; jack_event = thread_queue->DequeueEvent()) {

// We add `frames` so that MIDI events align with audio as closely as
// possible.
for (;;) {
switch (write_queue->EnqueueEvent(jack_event, frames)) {
case JackMidiWriteQueue::BUFFER_TOO_SMALL:
jack_error("JackALSARawMidiInputPort::ProcessJack - The write "
"queue couldn't enqueue a %d-byte event. Dropping "
"event.", jack_event->size);
// Fallthrough on purpose
// Fallthrough on purpose.
case JackMidiWriteQueue::OK:
continue;
break;
default:
;
goto trigger_queue_event;
}
dequeue_event:
jack_event = thread_queue->DequeueEvent();
if (! jack_event) {
break;
}
dequeued = true;
}
trigger_queue_event:
return dequeued ? TriggerQueueEvent() : true;
}

bool
JackALSARawMidiInputPort::ProcessPollEvents(jack_nframes_t current_frame)
{
if (GetQueuePollEvent() == -1) {
return false;
}
int io_event = GetIOPollEvent();
switch (io_event) {
case -1:
return false;
case 1:
alsa_event = receive_queue->DequeueEvent();
}
if (alsa_event) {
size_t size = alsa_event->size;
size_t space = raw_queue->GetAvailableSpace();
bool enough_room = space >= size;
if (enough_room) {
assert(raw_queue->EnqueueEvent(current_frame, size,
alsa_event->buffer) ==
JackMidiWriteQueue::OK);
alsa_event = 0;
} else if (space) {
assert(raw_queue->EnqueueEvent(current_frame, space,
alsa_event->buffer) ==
JackMidiWriteQueue::OK);
alsa_event->buffer += space;
alsa_event->size -= space;
}
break;
SetIOEventsEnabled(enough_room);
}
raw_queue->Process();
return true;
}

+ 3
- 5
linux/alsarawmidi/JackALSARawMidiInputPort.h View File

@@ -39,21 +39,19 @@ namespace Jack {
JackMidiAsyncQueue *thread_queue;
JackMidiBufferWriteQueue *write_queue;

jack_nframes_t
EnqueueALSAEvent();

public:

JackALSARawMidiInputPort(snd_rawmidi_info_t *info, size_t index,
size_t max_bytes=4096,
size_t max_messages=1024);

~JackALSARawMidiInputPort();

bool
ProcessALSA(jack_nframes_t *frame);
ProcessJack(JackMidiBuffer *port_buffer, jack_nframes_t frames);

bool
ProcessJack(JackMidiBuffer *port_buffer, jack_nframes_t frames);
ProcessPollEvents(jack_nframes_t current_frame);

};



+ 67
- 93
linux/alsarawmidi/JackALSARawMidiOutputPort.cpp View File

@@ -17,6 +17,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

#include <cassert>
#include <memory>

#include "JackALSARawMidiOutputPort.h"
@@ -25,15 +26,15 @@ using Jack::JackALSARawMidiOutputPort;

JackALSARawMidiOutputPort::JackALSARawMidiOutputPort(snd_rawmidi_info_t *info,
size_t index,
size_t max_bytes_per_poll,
size_t max_bytes,
size_t max_messages):
JackALSARawMidiPort(info, index)
JackALSARawMidiPort(info, index, POLLOUT)
{
alsa_event = 0;
blocked = false;
read_queue = new JackMidiBufferReadQueue();
std::auto_ptr<JackMidiBufferReadQueue> read_ptr(read_queue);
send_queue = new JackALSARawMidiSendQueue(rawmidi);
send_queue = new JackALSARawMidiSendQueue(rawmidi, max_bytes_per_poll);
std::auto_ptr<JackALSARawMidiSendQueue> send_ptr(send_queue);
thread_queue = new JackMidiAsyncQueue(max_bytes, max_messages);
std::auto_ptr<JackMidiAsyncQueue> thread_ptr(thread_queue);
@@ -52,121 +53,94 @@ JackALSARawMidiOutputPort::~JackALSARawMidiOutputPort()
delete thread_queue;
}

jack_midi_event_t *
JackALSARawMidiOutputPort::DequeueALSAEvent(int read_fd)
bool
JackALSARawMidiOutputPort::ProcessJack(JackMidiBuffer *port_buffer,
jack_nframes_t frames)
{
jack_midi_event_t *event = thread_queue->DequeueEvent();
if (event) {
char c;
ssize_t result = read(read_fd, &c, 1);
if (! result) {
jack_error("JackALSARawMidiOutputPort::DequeueALSAEvent - **BUG** "
"An event was dequeued from the thread queue, but no "
"byte was available for reading from the pipe file "
"descriptor.");
} else if (result < 0) {
jack_error("JackALSARawMidiOutputPort::DequeueALSAEvent - error "
"reading a byte from the pipe file descriptor: %s",
strerror(errno));
read_queue->ResetMidiBuffer(port_buffer);
bool enqueued = false;
for (jack_midi_event_t *event = read_queue->DequeueEvent(); event;
event = read_queue->DequeueEvent()) {
switch (thread_queue->EnqueueEvent(event, frames)) {
case JackMidiWriteQueue::BUFFER_FULL:
jack_error("JackALSARawMidiOutputPort::ProcessJack - The thread "
"queue doesn't have enough room to enqueue a %d-byte "
"event. Dropping event.", event->size);
continue;
case JackMidiWriteQueue::BUFFER_TOO_SMALL:
jack_error("JackALSARawMidiOutputPort::ProcessJack - The thread "
"queue is too small to enqueue a %d-byte event. "
"Dropping event.", event->size);
continue;
default:
enqueued = true;
}
}
return event;
return enqueued ? TriggerQueueEvent() : true;
}

bool
JackALSARawMidiOutputPort::ProcessALSA(int read_fd, jack_nframes_t *frame)
JackALSARawMidiOutputPort::ProcessPollEvents(bool handle_output, bool timeout,
jack_nframes_t *frame)
{
unsigned short revents;
if (! ProcessPollEvents(&revents)) {
int io_event;
int queue_event;
send_queue->ResetPollByteCount();
if (! handle_output) {
assert(timeout);
goto process_raw_queue;
}
io_event = GetIOPollEvent();
if (io_event == -1) {
return false;
}
if (blocked) {
if (! (revents & POLLOUT)) {
*frame = 0;
return true;
}
blocked = false;
queue_event = GetQueuePollEvent();
if (queue_event == -1) {
return false;
}
if (io_event || timeout) {
process_raw_queue:
// We call the 'Process' event early because there are events waiting
// to be processed that either need to be sent now, or before now.
raw_queue->Process();
} else if (! queue_event) {
return true;
}
if (! alsa_event) {
alsa_event = DequeueALSAEvent(read_fd);
alsa_event = thread_queue->DequeueEvent();
}
for (; alsa_event; alsa_event = DequeueALSAEvent(read_fd)) {
for (; alsa_event; alsa_event = thread_queue->DequeueEvent()) {
switch (raw_queue->EnqueueEvent(alsa_event)) {
case JackMidiWriteQueue::BUFFER_FULL:
// Try to free up some space by processing events early.
raw_queue->Process();
switch (raw_queue->EnqueueEvent(alsa_event)) {
case JackMidiWriteQueue::BUFFER_TOO_SMALL:
jack_error("JackALSARawMidiOutputPort::ProcessALSA - **BUG** "
"JackMidiRawOutputWriteQueue::EnqueueEvent "
"returned `BUFFER_FULL`, and then returned "
"`BUFFER_TOO_SMALL` after a Process() call.");
// Fallthrough on purpose
case JackMidiWriteQueue::OK:
continue;
default:
;
}
goto process_events;
case JackMidiWriteQueue::BUFFER_TOO_SMALL:
jack_error("JackALSARawMidiOutputPort::ProcessALSA - The raw "
jack_error("JackALSARawMidiOutputPort::ProcessQueues - The raw "
"output queue couldn't enqueue a %d-byte event. "
"Dropping event.", alsa_event->size);
// Fallthrough on purpose
// Fallthrough on purpose.
case JackMidiWriteQueue::OK:
continue;
default:
;
}
break;

// Try to free up some space by processing events early.
*frame = raw_queue->Process();

switch (raw_queue->EnqueueEvent(alsa_event)) {
case JackMidiWriteQueue::BUFFER_FULL:
goto set_io_events;
case JackMidiWriteQueue::BUFFER_TOO_SMALL:
// This shouldn't happen.
assert(false);
default:
;
}
}
process_events:
*frame = raw_queue->Process();
blocked = send_queue->IsBlocked();
set_io_events:
bool blocked = send_queue->IsBlocked();
SetIOEventsEnabled(blocked);
if (blocked) {

jack_info("JackALSARawMidiOutputPort::ProcessALSA - MIDI port is "
"blocked");

SetPollEventMask(POLLERR | POLLNVAL | POLLOUT);
*frame = 0;
} else {
SetPollEventMask(POLLERR | POLLNVAL);
}
return true;
}

bool
JackALSARawMidiOutputPort::ProcessJack(JackMidiBuffer *port_buffer,
jack_nframes_t frames, int write_fd)
{
read_queue->ResetMidiBuffer(port_buffer);
for (jack_midi_event_t *event = read_queue->DequeueEvent(); event;
event = read_queue->DequeueEvent()) {
if (event->size > thread_queue->GetAvailableSpace()) {
jack_error("JackALSARawMidiOutputPort::ProcessJack - The thread "
"queue doesn't have enough room to enqueue a %d-byte "
"event. Dropping event.", event->size);
continue;
}
char c = 1;
ssize_t result = write(write_fd, &c, 1);
assert(result <= 1);
if (result < 0) {
jack_error("JackALSARawMidiOutputPort::ProcessJack - error "
"writing a byte to the pipe file descriptor: %s",
strerror(errno));
return false;
}
if (! result) {
// Recoverable.
jack_error("JackALSARawMidiOutputPort::ProcessJack - Couldn't "
"write a byte to the pipe file descriptor. Dropping "
"event.");
} else {
assert(thread_queue->EnqueueEvent(event, frames) ==
JackMidiWriteQueue::OK);
}
}
return true;
}

+ 5
- 7
linux/alsarawmidi/JackALSARawMidiOutputPort.h View File

@@ -33,28 +33,26 @@ namespace Jack {
private:

jack_midi_event_t *alsa_event;
bool blocked;
JackMidiRawOutputWriteQueue *raw_queue;
JackMidiBufferReadQueue *read_queue;
JackALSARawMidiSendQueue *send_queue;
JackMidiAsyncQueue *thread_queue;

jack_midi_event_t *
DequeueALSAEvent(int read_fd);

public:

JackALSARawMidiOutputPort(snd_rawmidi_info_t *info, size_t index,
size_t max_bytes_per_poll=3,
size_t max_bytes=4096,
size_t max_messages=1024);

~JackALSARawMidiOutputPort();

bool
ProcessALSA(int read_fd, jack_nframes_t *frame);
ProcessJack(JackMidiBuffer *port_buffer, jack_nframes_t frames);

bool
ProcessJack(JackMidiBuffer *port_buffer, jack_nframes_t frames,
int write_fd);
ProcessPollEvents(bool handle_output, bool timeout,
jack_nframes_t *frame);

};



+ 101
- 37
linux/alsarawmidi/JackALSARawMidiPort.cpp View File

@@ -17,16 +17,18 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

#include <cassert>
#include <stdexcept>
#include <string>

#include "JackALSARawMidiPort.h"
#include "JackALSARawMidiUtil.h"
#include "JackError.h"

using Jack::JackALSARawMidiPort;

JackALSARawMidiPort::JackALSARawMidiPort(snd_rawmidi_info_t *info,
size_t index)
size_t index, unsigned short io_mask)
{
int card = snd_rawmidi_info_get_card(info);
unsigned int device = snd_rawmidi_info_get_device(info);
@@ -50,7 +52,6 @@ JackALSARawMidiPort::JackALSARawMidiPort(snd_rawmidi_info_t *info,
name_suffix = "in";
out = 0;
}
const char *device_name;
const char *func;
int code = snd_rawmidi_open(in, out, device_id, SND_RAWMIDI_NONBLOCK);
if (code) {
@@ -78,7 +79,7 @@ JackALSARawMidiPort::JackALSARawMidiPort(snd_rawmidi_info_t *info,
goto free_params;
}

// Smallest valid buffer size.
// Minimum buffer size allowed by ALSA
code = snd_rawmidi_params_set_buffer_size(rawmidi, params, 32);
if (code) {
error_message = snd_strerror(code);
@@ -99,15 +100,23 @@ JackALSARawMidiPort::JackALSARawMidiPort(snd_rawmidi_info_t *info,
goto free_params;
}
snd_rawmidi_params_free(params);
num_fds = snd_rawmidi_poll_descriptors_count(rawmidi);
if (! num_fds) {
alsa_poll_fd_count = snd_rawmidi_poll_descriptors_count(rawmidi);
if (! alsa_poll_fd_count) {
error_message = "returned '0' count for poll descriptors";
func = "snd_rawmidi_poll_descriptors_count";
goto close;
}
try {
CreateNonBlockingPipe(fds);
} catch (std::exception e) {
error_message = e.what();
func = "CreateNonBlockingPipe";
goto close;
}
snprintf(alias, sizeof(alias), "%s%d", alias_prefix, index + 1);
snprintf(name, sizeof(name), "system:%d-%d %s %d %s", card + 1, device + 1,
snd_rawmidi_info_get_name(info), subdevice + 1, name_suffix);
this->io_mask = io_mask;
return;
free_params:
snd_rawmidi_params_free(params);
@@ -119,6 +128,7 @@ JackALSARawMidiPort::JackALSARawMidiPort(snd_rawmidi_info_t *info,

JackALSARawMidiPort::~JackALSARawMidiPort()
{
DestroyNonBlockingPipe(fds);
if (rawmidi) {
int code = snd_rawmidi_close(rawmidi);
if (code) {
@@ -135,6 +145,32 @@ JackALSARawMidiPort::GetAlias()
return alias;
}

int
JackALSARawMidiPort::GetIOPollEvent()
{
unsigned short events;
int code = snd_rawmidi_poll_descriptors_revents(rawmidi, alsa_poll_fds,
alsa_poll_fd_count,
&events);
if (code) {
jack_error("JackALSARawMidiPort::GetIOPollEvents - "
"snd_rawmidi_poll_descriptors_revents: %s",
snd_strerror(code));
return -1;
}
if (events & POLLNVAL) {
jack_error("JackALSARawMidiPort::GetIOPollEvents - the file "
"descriptor is invalid.");
return -1;
}
if (events & POLLERR) {
jack_error("JackALSARawMidiPort::GetIOPollEvents - an error has "
"occurred on the device or stream.");
return -1;
}
return (events & io_mask) ? 1 : 0;
}

const char *
JackALSARawMidiPort::GetName()
{
@@ -144,48 +180,76 @@ JackALSARawMidiPort::GetName()
int
JackALSARawMidiPort::GetPollDescriptorCount()
{
return num_fds;
}

bool
JackALSARawMidiPort::PopulatePollDescriptors(struct pollfd *poll_fd)
{
bool result = snd_rawmidi_poll_descriptors(rawmidi, poll_fd, num_fds) ==
num_fds;
if (result) {
poll_fds = poll_fd;
}
return result;
return alsa_poll_fd_count + 1;
}

bool
JackALSARawMidiPort::ProcessPollEvents(unsigned short *revents)
int
JackALSARawMidiPort::GetQueuePollEvent()
{
int code = snd_rawmidi_poll_descriptors_revents(rawmidi, poll_fds, num_fds,
revents);
if (code) {
jack_error("JackALSARawMidiPort::ProcessPollEvents - "
"snd_rawmidi_poll_descriptors_revents: %s",
snd_strerror(code));
return false;
}
if ((*revents) & POLLNVAL) {
jack_error("JackALSARawMidiPort::ProcessPollEvents - the file "
unsigned short events = queue_poll_fd->revents;
if (events & POLLNVAL) {
jack_error("JackALSARawMidiPort::GetQueuePollEvents - the file "
"descriptor is invalid.");
return false;
return -1;
}
if ((*revents) & POLLERR) {
jack_error("JackALSARawMidiPort::ProcessPollEvents - an error has "
if (events & POLLERR) {
jack_error("JackALSARawMidiPort::GetQueuePollEvents - an error has "
"occurred on the device or stream.");
return false;
return -1;
}
return true;
int event = events & POLLIN ? 1 : 0;
if (event) {
char c;
ssize_t result = read(fds[0], &c, 1);
assert(result);
if (result < 0) {
jack_error("JackALSARawMidiPort::GetQueuePollEvents - error "
"reading a byte from the pipe file descriptor: %s",
strerror(errno));
return -1;
}
}
return event;
}

void
JackALSARawMidiPort::SetPollEventMask(unsigned short events)
JackALSARawMidiPort::PopulatePollDescriptors(struct pollfd *poll_fd)
{
alsa_poll_fds = poll_fd + 1;
assert(snd_rawmidi_poll_descriptors(rawmidi, alsa_poll_fds,
alsa_poll_fd_count) ==
alsa_poll_fd_count);
queue_poll_fd = poll_fd;
queue_poll_fd->events = POLLERR | POLLIN | POLLNVAL;
queue_poll_fd->fd = fds[0];
SetIOEventsEnabled(true);
}

void
JackALSARawMidiPort::SetIOEventsEnabled(bool enabled)
{
unsigned short mask = POLLNVAL | POLLERR | (enabled ? io_mask : 0);
for (int i = 0; i < alsa_poll_fd_count; i++) {
(alsa_poll_fds + i)->events = mask;
}
}

bool
JackALSARawMidiPort::TriggerQueueEvent()
{
for (int i = 0; i < num_fds; i++) {
(poll_fds + i)->events = events;
char c;
ssize_t result = write(fds[1], &c, 1);
assert(result <= 1);
switch (result) {
case 1:
return true;
case 0:
jack_error("JackALSARawMidiPort::TriggerQueueEvent - error writing a "
"byte to the pipe file descriptor: %s", strerror(errno));
break;
default:
jack_error("JackALSARawMidiPort::TriggerQueueEvent - couldn't write a "
"byte to the pipe file descriptor.");
}
return false;
}

+ 20
- 7
linux/alsarawmidi/JackALSARawMidiPort.h View File

@@ -32,23 +32,36 @@ namespace Jack {
private:

char alias[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
struct pollfd *alsa_poll_fds;
int alsa_poll_fd_count;
int fds[2];
unsigned short io_mask;
char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
int num_fds;
struct pollfd *poll_fds;
struct pollfd *queue_poll_fd;

protected:

snd_rawmidi_t *rawmidi;

bool
ProcessPollEvents(unsigned short *revents);
int
GetIOPollEvent();

int
GetQueuePollEvent();

void
SetIOEventsEnabled(bool enabled);

void
SetPollEventMask(unsigned short events);
SetQueueEventsEnabled(bool enabled);

bool
TriggerQueueEvent();

public:

JackALSARawMidiPort(snd_rawmidi_info_t *info, size_t index);
JackALSARawMidiPort(snd_rawmidi_info_t *info, size_t index,
unsigned short io_mask);

virtual
~JackALSARawMidiPort();
@@ -62,7 +75,7 @@ namespace Jack {
int
GetPollDescriptorCount();

bool
void
PopulatePollDescriptors(struct pollfd *poll_fd);

};


+ 0
- 0
linux/alsarawmidi/JackALSARawMidiReceiveQueue.cpp View File


+ 0
- 0
linux/alsarawmidi/JackALSARawMidiReceiveQueue.h View File


+ 15
- 1
linux/alsarawmidi/JackALSARawMidiSendQueue.cpp View File

@@ -24,10 +24,14 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

using Jack::JackALSARawMidiSendQueue;

JackALSARawMidiSendQueue::JackALSARawMidiSendQueue(snd_rawmidi_t *rawmidi)
JackALSARawMidiSendQueue::JackALSARawMidiSendQueue(snd_rawmidi_t *rawmidi,
size_t bytes_per_poll)
{
assert(bytes_per_poll > 0);
this->bytes_per_poll = bytes_per_poll;
this->rawmidi = rawmidi;
blocked = false;
bytes_available = bytes_per_poll;
}

Jack::JackMidiWriteQueue::EnqueueResult
@@ -38,10 +42,14 @@ JackALSARawMidiSendQueue::EnqueueEvent(jack_nframes_t time, size_t size,
if (time > GetCurrentFrame()) {
return EVENT_EARLY;
}
if (! bytes_available) {
return BUFFER_FULL;
}
ssize_t result = snd_rawmidi_write(rawmidi, buffer, 1);
switch (result) {
case 1:
blocked = false;
bytes_available--;
return OK;
case -EWOULDBLOCK:
blocked = true;
@@ -57,3 +65,9 @@ JackALSARawMidiSendQueue::IsBlocked()
{
return blocked;
}

void
JackALSARawMidiSendQueue::ResetPollByteCount()
{
bytes_available = bytes_per_poll;
}

+ 7
- 1
linux/alsarawmidi/JackALSARawMidiSendQueue.h View File

@@ -31,11 +31,14 @@ namespace Jack {
private:

bool blocked;
size_t bytes_available;
size_t bytes_per_poll;
snd_rawmidi_t *rawmidi;

public:

JackALSARawMidiSendQueue(snd_rawmidi_t *rawmidi);
JackALSARawMidiSendQueue(snd_rawmidi_t *rawmidi,
size_t bytes_per_poll=0);

JackMidiWriteQueue::EnqueueResult
EnqueueEvent(jack_nframes_t time, size_t size,
@@ -44,6 +47,9 @@ namespace Jack {
bool
IsBlocked();

void
ResetPollByteCount();

};

}


+ 43
- 0
linux/alsarawmidi/JackALSARawMidiUtil.cpp View File

@@ -0,0 +1,43 @@
#include <cerrno>
#include <cstring>
#include <stdexcept>

#include <fcntl.h>
#include <unistd.h>

#include "JackALSARawMidiUtil.h"

void
Jack::CreateNonBlockingPipe(int *fds)
{
if (pipe(fds) == -1) {
throw std::runtime_error(strerror(errno));
}
try {
SetNonBlocking(fds[0]);
SetNonBlocking(fds[1]);
} catch (...) {
close(fds[1]);
close(fds[0]);
throw;
}
}

void
Jack::DestroyNonBlockingPipe(int *fds)
{
close(fds[1]);
close(fds[0]);
}

void
Jack::SetNonBlocking(int fd)
{
int flags = fcntl(fd, F_GETFL);
if (flags == -1) {
throw std::runtime_error(strerror(errno));
}
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
throw std::runtime_error(strerror(errno));
}
}

+ 36
- 0
linux/alsarawmidi/JackALSARawMidiUtil.h View File

@@ -0,0 +1,36 @@
/*
Copyright (C) 2011 Devin Anderson

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
(at your option) any later version.

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.

*/

#ifndef __JackALSARawMidiUtil__
#define __JackALSARawMidiUtil__

namespace Jack {

void
CreateNonBlockingPipe(int *fds);

void
DestroyNonBlockingPipe(int *fds);

void
SetNonBlocking(int fd);

}

#endif

+ 6
- 3
linux/wscript View File

@@ -13,12 +13,14 @@ def configure(conf):

conf.define('HAVE_PPOLL', 1 )


def create_jack_driver_obj(bld, target, sources, uselib = None):
driver = bld.new_task_gen('cxx', 'shlib')
driver.features.append('cc')
driver.env['shlib_PATTERN'] = 'jack_%s.so'
driver.defines = ['HAVE_CONFIG_H','SERVER_SIDE', 'HAVE_PPOLL']

#driver.defines = ['HAVE_CONFIG_H','SERVER_SIDE', 'HAVE_PPOLL']
driver.defines = ['HAVE_CONFIG_H','SERVER_SIDE', 'HAVE_PPOLL', 'HAVE_TIMERFD']

driver.includes = ['.', '../linux', '../posix', '../common', '../common/jack', '../dbus']
driver.target = target
driver.source = sources
@@ -62,7 +64,8 @@ def build(bld):
'alsarawmidi/JackALSARawMidiOutputPort.cpp',
'alsarawmidi/JackALSARawMidiPort.cpp',
'alsarawmidi/JackALSARawMidiReceiveQueue.cpp',
'alsarawmidi/JackALSARawMidiSendQueue.cpp'
'alsarawmidi/JackALSARawMidiSendQueue.cpp',
'alsarawmidi/JackALSARawMidiUtil.cpp'
]

ffado_driver_src = ['firewire/JackFFADODriver.cpp',


+ 1
- 1
windows/JackRouter/JackRouter.cpp View File

@@ -54,7 +54,7 @@ static const double twoRaisedTo32Reciprocal = 1. / twoRaisedTo32;
#include "windows.h"
#include "mmsystem.h"
#ifdef _WIN64
#define JACK_ROUTER "JackRouter64.dll"
#define JACK_ROUTER "JackRouter.dll"
#include <psapi.h>
#else
#define JACK_ROUTER "JackRouter.dll"


+ 1
- 1
windows/JackRouter/JackRouter.vcxproj View File

@@ -242,7 +242,7 @@
<SuppressStartupBanner>true</SuppressStartupBanner>
<LinkDLL>true</LinkDLL>
<SubSystem>Windows</SubSystem>
<OutputFile>.\Release\JackRouter64.dll</OutputFile>
<OutputFile>.\x64\Release\JackRouter.dll</OutputFile>
<ImportLibrary>.\Release\JackRouter64.lib</ImportLibrary>
<AdditionalDependencies>odbc32.lib;odbccp32.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>.\JackRouter.def</ModuleDefinitionFile>


+ 5
- 5
windows/Setup/jack.ci View File

@@ -53,7 +53,6 @@
<bgfoot> </>
<bgback> </>
<files listview >
<_><src>.\src\vcredist_2010_x86.exe</><dest>inst</><custom></><ifexist>overnewer</><recurs>0</></>
<_><src>..\Release\bin\libjack.a</><dest>inst</><custom>lib</><ifexist>overnewer</><recurs>0</></>
<_><src>..\Release\bin\libjack.lib</><dest>inst</><custom>lib</><ifexist>overnewer</><recurs>0</></>
<_><src>..\Release\bin\libjack.def</><dest>inst</><custom>lib</><ifexist>overnewer</><recurs>0</></>
@@ -95,8 +94,10 @@
<_><src>..\..\common\jack\systemdeps.h</><dest>inst</><custom>includes\jack</><ifexist>overnewer</><recurs>1</></>
<_><src>..\..\common\jack\weakjack.h</><dest>inst</><custom>includes\jack</><ifexist>overnewer</><recurs>1</></>
<_><src>..\..\common\jack\weakmacros.h</><dest>inst</><custom>includes\jack</><ifexist>overnewer</><recurs>1</></>
<_><src>.\JackRouter.dll</><dest>inst</><custom></><ifexist>overnewer</><recurs>0</></>
<_><src>.\JackRouter.ini</><dest>inst</><custom></><ifexist>overnewer</><recurs>0</></>
<_><src>.\src\32bits\JackRouter.dll</><dest>inst</><custom>32bits</><ifexist>overnewer</><recurs>0</></>
<_><src>.\src\32bits\JackRouter.ini</><dest>inst</><custom>32bits</><ifexist>overnewer</><recurs>0</></>
<_><src>.\src\32bits\msvcr100.dll</><dest>inst</><custom>32bits</><ifexist>overnewer</><recurs>0</></>
<_><src>.\src\32bits\msvcp100.dll</><dest>inst</><custom>32bits</><ifexist>overnewer</><recurs>0</></>
<_><src>.\qjackctl\mingwm10.dll</><dest>inst</><custom></><ifexist>overnewer</><recurs>0</></>
<_><src>.\qjackctl\qjackctl.exe</><dest>inst</><custom></><ifexist>overnewer</><recurs>0</></>
<_><src>.\qjackctl\QtCore4.dll</><dest>inst</><custom></><ifexist>overnewer</><recurs>0</></>
@@ -107,7 +108,6 @@
</files>
<runx listview >
<_><type>app</><path>inst</><file>vcredist_2010_x86.exe</><cmdline></><wait>1</><workdir>inst</><custdir></><when>end</></>
</runx>
<registry listview >
@@ -126,7 +126,7 @@
</copy>
<activex listview >
<_><path>inst</><name>JackRouter.dll</></>
<_><path>inst</><name>32bits\JackRouter.dll</></>
</activex>
<font listview >


+ 12
- 11
windows/Setup/jack64.ci View File

@@ -53,8 +53,6 @@
<bgfoot> </>
<bgback> </>
<files listview >
<_><src>.\src\vcredist_2010_x86.exe</><dest>inst</><custom></><ifexist>overnewer</><recurs>0</></>
<_><src>.\src\vcredist_2010_x64.exe</><dest>inst</><custom></><ifexist>overnewer</><recurs>0</></>
<_><src>..\Release64\bin\libjack64.a</><dest>inst</><custom>lib</><ifexist>overnewer</><recurs>0</></>
<_><src>..\Release64\bin\libjack64.lib</><dest>inst</><custom>lib</><ifexist>overnewer</><recurs>0</></>
<_><src>..\Release64\bin\libjack64.def</><dest>inst</><custom>lib</><ifexist>overnewer</><recurs>0</></>
@@ -71,6 +69,7 @@
<_><src>..\Release\bin\libjackserver.lib</><dest>inst</><custom>lib</><ifexist>overnewer</><recurs>0</></>
<_><src>..\Release\bin\libjackserver.def</><dest>inst</><custom>lib</><ifexist>overnewer</><recurs>0</></>
<_><src>..\Release\bin\libjackserver.dll</><dest>sys</><custom></><ifexist>overnewer</><recurs>0</></>
<_><src>..\Release\bin\portaudio_x86.dll</><dest>inst</><custom></><ifexist>overnewer</><recurs>0</></>
<_><src>..\Release64\bin\jack_connect.exe</><dest>inst</><custom></><ifexist>overnewer</><recurs>0</></>
<_><src>..\Release64\bin\jack_disconnect.exe</><dest>inst</><custom></><ifexist>overnewer</><recurs>0</></>
<_><src>..\Release64\bin\jack_load.exe</><dest>inst</><custom></><ifexist>overnewer</><recurs>0</></>
@@ -81,7 +80,6 @@
<_><src>..\Release64\bin\jackd.exe</><dest>inst</><custom></><ifexist>overnewer</><recurs>0</></>
<_><src>..\Release64\bin\libsamplerate_x86_64.dll</><dest>inst</><custom></><ifexist>overnewer</><recurs>0</></>
<_><src>..\Release64\bin\portaudio_x86_64.dll</><dest>inst</><custom></><ifexist>overnewer</><recurs>0</></>
<_><src>..\Release\bin\portaudio_x86.dll</><dest>inst</><custom></><ifexist>overnewer</><recurs>0</></>
<_><src>..\Release64\bin\jack\jack_net.dll</><dest>inst</><custom>jack</><ifexist>overnewer</><recurs>0</></>
<_><src>..\Release64\bin\jack\jack_netone.dll</><dest>inst</><custom>jack</><ifexist>overnewer</><recurs>0</></>
<_><src>..\Release64\bin\jack_netsource.exe</><dest>inst</><custom></><ifexist>overnewer</><recurs>0</></>
@@ -105,9 +103,14 @@
<_><src>..\..\common\jack\systemdeps.h</><dest>inst</><custom>includes\jack</><ifexist>overnewer</><recurs>1</></>
<_><src>..\..\common\jack\weakjack.h</><dest>inst</><custom>includes\jack</><ifexist>overnewer</><recurs>1</></>
<_><src>..\..\common\jack\weakmacros.h</><dest>inst</><custom>includes\jack</><ifexist>overnewer</><recurs>1</></>
<_><src>.\JackRouter.dll</><dest>inst</><custom></><ifexist>overnewer</><recurs>0</></>
<_><src>.\JackRouter64.dll</><dest>inst</><custom></><ifexist>overnewer</><recurs>0</></>
<_><src>.\JackRouter.ini</><dest>inst</><custom></><ifexist>overnewer</><recurs>0</></>
<_><src>.\src\32bits\JackRouter.dll</><dest>inst</><custom>32bits</><ifexist>overnewer</><recurs>0</></>
<_><src>.\src\32bits\JackRouter.ini</><dest>inst</><custom>32bits</><ifexist>overnewer</><recurs>0</></>
<_><src>.\src\32bits\msvcr100.dll</><dest>inst</><custom>32bits</><ifexist>overnewer</><recurs>0</></>
<_><src>.\src\32bits\msvcp100.dll</><dest>inst</><custom>32bits</><ifexist>overnewer</><recurs>0</></>
<_><src>.\src\64bits\JackRouter.dll</><dest>inst</><custom>64bits</><ifexist>overnewer</><recurs>0</></>
<_><src>.\src\64bits\JackRouter.ini</><dest>inst</><custom>64bits</><ifexist>overnewer</><recurs>0</></>
<_><src>.\src\64bits\msvcr100.dll</><dest>inst</><custom>64bits</><ifexist>overnewer</><recurs>0</></>
<_><src>.\src\64bits\msvcp100.dll</><dest>inst</><custom>64bits</><ifexist>overnewer</><recurs>0</></>
<_><src>.\qjackctl\mingwm10.dll</><dest>inst</><custom></><ifexist>overnewer</><recurs>0</></>
<_><src>.\qjackctl\qjackctl.exe</><dest>inst</><custom></><ifexist>overnewer</><recurs>0</></>
<_><src>.\qjackctl\QtCore4.dll</><dest>inst</><custom></><ifexist>overnewer</><recurs>0</></>
@@ -118,9 +121,7 @@
</files>
<runx listview >
<_><type>app</><path>inst</><file>vcredist_2010_x86.exe</><cmdline></><wait>1</><workdir>inst</><custdir></><when>end</></>
<_><type>app</><path>inst</><file>vcredist_2010_x64.exe</><cmdline></><wait>1</><workdir>inst</><custdir></><when>end</></>
</runx>
</runx>
<registry listview >
</registry>
@@ -138,8 +139,8 @@
</copy>
<activex listview >
<_><path>inst</><name>JackRouter.dll</></>
<_><path>inst</><name>JackRouter64.dll</></>
<_><path>inst</><name>32bits\JackRouter.dll</></>
<_><path>inst</><name>64bits\JackRouter.dll</></>
</activex>
<font listview >


BIN
windows/Setup/JackRouter.dll → windows/Setup/src/32bits/JackRouter.dll View File


+ 7
- 0
windows/Setup/src/32bits/JackRouter.ini View File

@@ -0,0 +1,7 @@
[IO]
input=4
output=4
[AUTO_CONNECT]
input=1
output=1

BIN
windows/Setup/JackRouter64.dll → windows/Setup/src/64bits/JackRouter.dll View File


+ 7
- 0
windows/Setup/src/64bits/JackRouter.ini View File

@@ -0,0 +1,7 @@
[IO]
input=4
output=4
[AUTO_CONNECT]
input=1
output=1

+ 2
- 2
windows/jackd.workspace View File

@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_workspace_file>
<Workspace title="jack">
<Project filename="libjackserver.cbp" />
<Project filename="libjackserver.cbp" active="1" />
<Project filename="jack_portaudio.cbp" />
<Project filename="jack_netdriver.cbp" />
<Project filename="jack_netonedriver.cbp" />
<Project filename="jack_dummy.cbp" />
<Project filename="jack_netmanager.cbp" />
<Project filename="jack_audioadapter.cbp" active="1" />
<Project filename="jack_audioadapter.cbp" />
<Project filename="libjack.cbp" />
<Project filename="jack_load.cbp" />
<Project filename="jack_unload.cbp" />


+ 38
- 34
windows/winmme/JackWinMMEInputPort.cpp View File

@@ -21,7 +21,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include <memory>
#include <stdexcept>

#include "JackError.h"
#include "JackError.h"
#include "JackTime.h"
#include "JackMidiUtil.h"
#include "JackWinMMEInputPort.h"
#include "JackMidiWriteQueue.h"
@@ -55,7 +56,8 @@ JackWinMMEInputPort::JackWinMMEInputPort(const char *alias_name,
std::auto_ptr<JackMidiBufferWriteQueue> write_queue_ptr(write_queue);
sysex_buffer = new jack_midi_data_t[max_bytes];
char error_message[MAXERRORLENGTH];
MMRESULT result = midiInOpen(&handle, index, (DWORD_PTR)HandleMidiInputEvent,
MMRESULT result = midiInOpen(&handle, index,
(DWORD_PTR) HandleMidiInputEvent,
(DWORD_PTR)this,
CALLBACK_FUNCTION | MIDI_IO_STATUS);
if (result != MMSYSERR_NOERROR) {
@@ -63,11 +65,8 @@ JackWinMMEInputPort::JackWinMMEInputPort(const char *alias_name,
goto delete_sysex_buffer;
}
sysex_header.dwBufferLength = max_bytes;
sysex_header.dwBytesRecorded = 0;
sysex_header.dwFlags = 0;
sysex_header.dwUser = 0;
sysex_header.lpData = (LPSTR)(((LPBYTE) &sysex_header) + sizeof(MIDIHDR));
sysex_header.lpNext = 0;
result = midiInPrepareHeader(handle, &sysex_header, sizeof(MIDIHDR));
if (result != MMSYSERR_NOERROR) {
GetInErrorString(result, error_message);
@@ -103,12 +102,13 @@ JackWinMMEInputPort::JackWinMMEInputPort(const char *alias_name,
result = midiInUnprepareHeader(handle, &sysex_header, sizeof(MIDIHDR));
if (result != MMSYSERR_NOERROR) {
WriteInError("JackWinMMEInputPort [constructor]",
"midiInUnprepareHeader", result);
"midiInUnprepareHeader", result);
}
close_handle:
result = midiInClose(handle);
if (result != MMSYSERR_NOERROR) {
WriteInError("JackWinMMEInputPort [constructor]", "midiInClose", result);
WriteInError("JackWinMMEInputPort [constructor]", "midiInClose",
result);
}
delete_sysex_buffer:
delete[] sysex_buffer;
@@ -123,8 +123,8 @@ JackWinMMEInputPort::~JackWinMMEInputPort()
}
result = midiInUnprepareHeader(handle, &sysex_header, sizeof(MIDIHDR));
if (result != MMSYSERR_NOERROR) {
WriteInError("JackWinMMEInputPort [destructor]", "midiInUnprepareHeader",
result);
WriteInError("JackWinMMEInputPort [destructor]",
"midiInUnprepareHeader", result);
}
result = midiInClose(handle);
if (result != MMSYSERR_NOERROR) {
@@ -136,10 +136,11 @@ JackWinMMEInputPort::~JackWinMMEInputPort()
}

void
JackWinMMEInputPort::EnqueueMessage(jack_nframes_t time, size_t length,
JackWinMMEInputPort::EnqueueMessage(DWORD timestamp, size_t length,
jack_midi_data_t *data)
{
switch (thread_queue->EnqueueEvent(time, length, data)) {
jack_nframes_t frame = GetFramesFromTime(start_time + (timestamp * 1000));
switch (thread_queue->EnqueueEvent(frame, length, data)) {
case JackMidiWriteQueue::BUFFER_FULL:
jack_error("JackWinMMEInputPort::EnqueueMessage - The thread queue "
"cannot currently accept a %d-byte event. Dropping event.",
@@ -155,6 +156,15 @@ JackWinMMEInputPort::EnqueueMessage(jack_nframes_t time, size_t length,
}
}

void
JackWinMMEInputPort::GetInErrorString(MMRESULT error, LPTSTR text)
{
MMRESULT result = midiInGetErrorText(error, text, MAXERRORLENGTH);
if (result != MMSYSERR_NOERROR) {
snprintf(text, MAXERRORLENGTH, "Unknown error code '%d'", error);
}
}

void
JackWinMMEInputPort::ProcessJack(JackMidiBuffer *port_buffer,
jack_nframes_t frames)
@@ -164,7 +174,7 @@ JackWinMMEInputPort::ProcessJack(JackMidiBuffer *port_buffer,
jack_event = thread_queue->DequeueEvent();
}
for (; jack_event; jack_event = thread_queue->DequeueEvent()) {
switch (write_queue->EnqueueEvent(jack_event)) {
switch (write_queue->EnqueueEvent(jack_event, frames)) {
case JackMidiWriteQueue::BUFFER_TOO_SMALL:
jack_error("JackWinMMEMidiInputPort::Process - The buffer write "
"queue couldn't enqueue a %d-byte event. Dropping "
@@ -181,8 +191,6 @@ void
JackWinMMEInputPort::ProcessWinMME(UINT message, DWORD param1, DWORD param2)
{
set_threaded_log_function();
jack_nframes_t current_frame = GetCurrentFrame();

switch (message) {
case MIM_CLOSE:
jack_info("JackWinMMEInputPort::ProcessWinMME - MIDI device closed.");
@@ -218,18 +226,24 @@ JackWinMMEInputPort::ProcessWinMME(UINT message, DWORD param1, DWORD param2)
"status byte.");
return;
}
EnqueueMessage(current_frame, (size_t) length, message_buffer);
break;
EnqueueMessage(param2, (size_t) length, message_buffer);
break;
}
case MIM_LONGDATA: {
LPMIDIHDR header = (LPMIDIHDR) param1;
size_t byte_count = header->dwBytesRecorded;
if (! byte_count) {
jack_info("JackWinMMEInputPort::ProcessWinMME - WinMME driver has "
"returned sysex header to us with no bytes. The JACK "
"driver is probably being stopped.");
break;
}
jack_midi_data_t *data = (jack_midi_data_t *) header->lpData;
size_t length1 = header->dwBytesRecorded;
if ((data[0] != 0xf0) || (data[length1 - 1] != 0xf7)) {
if ((data[0] != 0xf0) || (data[byte_count - 1] != 0xf7)) {
jack_error("JackWinMMEInputPort::ProcessWinMME - Discarding "
"%d-byte sysex chunk.", length1);
"%d-byte sysex chunk.", byte_count);
} else {
EnqueueMessage(current_frame, length1, data);
EnqueueMessage(param2, byte_count, data);
}
// Is this realtime-safe? This function isn't run in the JACK thread,
// but we still want it to perform as quickly as possible. Even if
@@ -237,10 +251,10 @@ JackWinMMEInputPort::ProcessWinMME(UINT message, DWORD param1, DWORD param2)
MMRESULT result = midiInAddBuffer(handle, &sysex_header,
sizeof(MIDIHDR));
if (result != MMSYSERR_NOERROR) {
WriteInError("JackWinMMEInputPort::ProcessWinMME", "midiInAddBuffer",
result);
WriteInError("JackWinMMEInputPort::ProcessWinMME",
"midiInAddBuffer", result);
}
break;
break;
}
case MIM_LONGERROR:
jack_error("JackWinMMEInputPort::ProcessWinMME - Invalid or "
@@ -255,6 +269,7 @@ bool
JackWinMMEInputPort::Start()
{
if (! started) {
start_time = GetMicroSeconds();
MMRESULT result = midiInStart(handle);
started = result == MMSYSERR_NOERROR;
if (! started) {
@@ -277,15 +292,6 @@ JackWinMMEInputPort::Stop()
return ! started;
}

void
JackWinMMEInputPort::GetInErrorString(MMRESULT error, LPTSTR text)
{
MMRESULT result = midiInGetErrorText(error, text, MAXERRORLENGTH);
if (result != MMSYSERR_NOERROR) {
snprintf(text, MAXERRORLENGTH, "Unknown error code '%d'", error);
}
}

void
JackWinMMEInputPort::WriteInError(const char *jack_func, const char *mm_func,
MMRESULT result)
@@ -294,5 +300,3 @@ JackWinMMEInputPort::WriteInError(const char *jack_func, const char *mm_func,
GetInErrorString(result, error_message);
jack_error("%s - %s: %s", jack_func, mm_func, error_message);
}



+ 9
- 12
windows/winmme/JackWinMMEInputPort.h View File

@@ -37,30 +37,27 @@ namespace Jack {
DWORD param1, DWORD param2);

void
EnqueueMessage(jack_nframes_t time, size_t length,
jack_midi_data_t *data);
EnqueueMessage(DWORD timestamp, size_t length, jack_midi_data_t *data);

void
GetInErrorString(MMRESULT error, LPTSTR text);

void
ProcessWinMME(UINT message, DWORD param1, DWORD param2);

void
WriteInError(const char *jack_func, const char *mm_func,
MMRESULT result);

HMIDIIN handle;
jack_midi_event_t *jack_event;
jack_time_t start_time;
bool started;
jack_midi_data_t *sysex_buffer;
MIDIHDR sysex_header;
JackMidiAsyncQueue *thread_queue;
JackMidiBufferWriteQueue *write_queue;

bool started;


void
WriteInError(const char *jack_func, const char *mm_func,
MMRESULT result);

void
GetInErrorString(MMRESULT error, LPTSTR text);

public:

JackWinMMEInputPort(const char *alias_name, const char *client_name,


+ 2
- 9
windows/winmme/JackWinMMEOutputPort.cpp View File

@@ -184,11 +184,8 @@ JackWinMMEOutputPort::Execute()
}
MIDIHDR header;
header.dwBufferLength = size;
header.dwBytesRecorded = size;
header.dwFlags = 0;
header.dwOffset = 0;
header.dwUser = 0;
header.lpData = (LPSTR)data;
header.lpData = (LPSTR) data;
result = midiOutPrepareHeader(handle, &header, sizeof(MIDIHDR));
if (result != MMSYSERR_NOERROR) {
WriteOutError("JackWinMMEOutputPort::Execute",
@@ -215,9 +212,7 @@ JackWinMMEOutputPort::Execute()
"midiOutUnprepareHeader", result);
break;
}

}
stop_execution:
return false;
}

@@ -237,7 +232,7 @@ JackWinMMEOutputPort::HandleMessage(UINT message, DWORD_PTR param1,
jack_info("JackWinMMEOutputPort::HandleMessage - MIDI device opened.");
break;
case MOM_POSITIONCB:
LPMIDIHDR header = (LPMIDIHDR) param2;
LPMIDIHDR header = (LPMIDIHDR) param1;
jack_info("JackWinMMEOutputPort::HandleMessage - %d bytes out of %d "
"bytes of the current sysex message have been sent.",
header->dwOffset, header->dwBytesRecorded);
@@ -262,7 +257,6 @@ JackWinMMEOutputPort::ProcessJack(JackMidiBuffer *port_buffer,
jack_nframes_t frames)
{
read_queue->ResetMidiBuffer(port_buffer);

for (jack_midi_event_t *event = read_queue->DequeueEvent(); event;
event = read_queue->DequeueEvent()) {

@@ -369,4 +363,3 @@ JackWinMMEOutputPort::WriteOutError(const char *jack_func, const char *mm_func,
GetOutErrorString(result, error_message);
jack_error("%s - %s: %s", jack_func, mm_func, error_message);
}


Loading…
Cancel
Save