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 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> 2011-04-04 Stephane Letz <letz@grame.fr>


* Correct driver lifetime management. * Correct driver lifetime management.


+ 6
- 6
common/JackFreewheelDriver.cpp View File

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


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


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


return res; return res;
} }


+ 5
- 12
common/JackMidiAsyncQueue.cpp View File

@@ -54,23 +54,16 @@ JackMidiAsyncQueue::DequeueEvent()
{ {
jack_midi_event_t *event = 0; jack_midi_event_t *event = 0;
if (jack_ringbuffer_read_space(info_ring) >= INFO_SIZE) { if (jack_ringbuffer_read_space(info_ring) >= INFO_SIZE) {
size_t size;
event = &dequeue_event; event = &dequeue_event;
jack_ringbuffer_read(info_ring, (char *) &(event->time), jack_ringbuffer_read(info_ring, (char *) &(event->time),
sizeof(jack_nframes_t)); 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->buffer = data_buffer;
event->size = size; 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; 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 { 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: class SERVER_EXPORT JackMidiAsyncQueue:
@@ -64,7 +63,8 @@ namespace Jack {


JackMidiAsyncQueue(size_t max_bytes=4096, size_t max_messages=1024); 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 * 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); return packet_queue->EnqueueEvent(time, size, buffer);
} }


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

void void
JackMidiRawInputWriteQueue::HandleBufferFailure(size_t unbuffered_bytes, JackMidiRawInputWriteQueue::HandleBufferFailure(size_t unbuffered_bytes,
size_t total_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, EnqueueEvent(jack_nframes_t time, size_t size,
jack_midi_data_t *buffer); 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 * The `Process()` method should be called each time the
* `EnqueueEvent()` method returns `OK`. The `Process()` method will * `EnqueueEvent()` method returns `OK`. The `Process()` method will


+ 36
- 106
common/JackMidiRawOutputWriteQueue.cpp View File

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


bool
void
JackMidiRawOutputWriteQueue::DequeueNonRealtimeEvent() JackMidiRawOutputWriteQueue::DequeueNonRealtimeEvent()
{ {
non_rt_event = non_rt_queue->DequeueEvent(); 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; non_rt_event_time = non_rt_event->time;
running_status = ApplyRunningStatus(non_rt_event, running_status); running_status = ApplyRunningStatus(non_rt_event, running_status);
} }
return result;
} }


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


Jack::JackMidiWriteQueue::EnqueueResult Jack::JackMidiWriteQueue::EnqueueResult
@@ -79,11 +75,7 @@ JackMidiRawOutputWriteQueue::EnqueueEvent(jack_nframes_t time, size_t size,
{ {
JackMidiAsyncQueue *queue = (size == 1) && (*buffer >= 0xf8) ? rt_queue : JackMidiAsyncQueue *queue = (size == 1) && (*buffer >= 0xf8) ? rt_queue :
non_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 void
@@ -99,38 +91,34 @@ JackMidiRawOutputWriteQueue::HandleWriteQueueBug(jack_nframes_t time,
jack_nframes_t jack_nframes_t
JackMidiRawOutputWriteQueue::Process(jack_nframes_t boundary_frame) 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 bool
@@ -151,78 +139,20 @@ JackMidiRawOutputWriteQueue::SendByte(jack_nframes_t time,
} }


bool 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)++) { (non_rt_event->size)--, (non_rt_event->buffer)++) {
jack_nframes_t current_frame = send_queue->GetNextScheduleFrame();
if (! STILL_TIME(current_frame, boundary_frame)) { if (! STILL_TIME(current_frame, boundary_frame)) {
return true; return true;
} }
if (! SendByte(current_frame, *(non_rt_event->buffer))) {
if (! SendByte(non_rt_event_time, *(non_rt_event->buffer))) {
return false; 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 * 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: * event copying:
* *
* -Running status: Status bytes can be omitted when the status byte of the * -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 * non-realtime bytes so that realtime messages can be sent as close as
* possible to the time they're scheduled for sending. * 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 * Use this queue if the MIDI API you're interfacing with allows you to
* send raw MIDI bytes. * send raw MIDI bytes.
*/ */
@@ -52,7 +48,6 @@ namespace Jack {


private: private:


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


bool
void
DequeueNonRealtimeEvent(); DequeueNonRealtimeEvent();


bool
void
DequeueRealtimeEvent(); DequeueRealtimeEvent();


bool bool
SendByte(jack_nframes_t time, jack_midi_data_t byte); SendByte(jack_nframes_t time, jack_midi_data_t byte);


bool bool
WriteNonRealtimeEvents(jack_nframes_t boundary_frame);

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


protected: protected:




+ 2
- 1
common/JackMidiUtil.cpp View File

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


jack_nframes_t 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) 2002-2007 Werner Schweer and others
// Copyright (C) 2009 Grame // Copyright (C) 2009 Grame
@@ -24,6 +20,7 @@
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


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


/* dynamically load libjack and forward all registered calls to libjack /* dynamically load libjack and forward all registered calls to libjack
(similar to what relaytool is trying to do, but more portably..) (similar to what relaytool is trying to do, but more portably..)
@@ -40,24 +37,25 @@
typedef void (*print_function)(const char *); typedef void (*print_function)(const char *);
typedef void *(*thread_routine)(void*); 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 #ifdef WIN32
HMODULE libjack_handle = 0;
static HMODULE libjack_handle = 0;
#else #else
static void *libjack_handle = 0; static void *libjack_handle = 0;
#endif #endif



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


// session // 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(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_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_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)); 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 // Slave drivers
for (it = slaves_list.begin(); it != slaves_list.end(); it++) { for (it = slaves_list.begin(); it != slaves_list.end(); it++) {
jackctl_driver_t * slave_driver_ctl = jackctl_server_get_driver(server_ctl, *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 // Internal clients
for (it = internals_list.begin(); it != internals_list.end(); it++) { for (it = internals_list.begin(); it != internals_list.end(); it++) {
jackctl_internal_t * internal_driver_ctl = jackctl_server_get_internal(server_ctl, *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); jackctl_server_close(server_ctl);
destroy_server: 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> #include <samplerate.h>
#endif #endif


#include "JackError.h"

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




+ 0
- 2
common/netjack_packet.c View File

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


#include "JackError.h"

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


+ 228
- 113
dbus/controller.c View File

@@ -1,6 +1,6 @@
/* -*- Mode: C ; c-basic-offset: 4 -*- */ /* -*- 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 Copyright (C) 2007-2008 Juuso Alasuutari


This program is free software; you can redistribute it and/or modify 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 NULL
}; };


static
jackctl_driver_t * jackctl_driver_t *
jack_controller_find_driver( jack_controller_find_driver(
jackctl_server_t *server, jackctl_server_t *server,
@@ -64,9 +65,7 @@ jack_controller_find_driver(
return NULL; 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 list_head * node_ptr;
struct jack_controller_slave_driver * driver_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) list_for_each(node_ptr, &controller_ptr->slave_drivers)
{ {
driver_ptr = list_entry(node_ptr, struct jack_controller_slave_driver, siblings); 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)) if (!jackctl_server_add_slave(controller_ptr->server, driver_ptr->handle))
{ {
jack_error("Driver \"%s\" cannot be loaded", driver_ptr->name); jack_error("Driver \"%s\" cannot be loaded", driver_ptr->name);
goto fail;
return false;
} }

driver_ptr->loaded = true;
} }


return 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 list_head * node_ptr;
struct jack_controller_slave_driver * driver_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) list_for_each(node_ptr, &controller_ptr->slave_drivers)
{ {
driver_ptr = list_entry(node_ptr, struct jack_controller_slave_driver, siblings); 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); 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 * jackctl_internal_t *
jack_controller_find_internal( jack_controller_find_internal(
jackctl_server_t *server, jackctl_server_t *server,
@@ -136,42 +161,18 @@ jack_controller_find_internal(
return NULL; 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 bool
jack_controller_select_driver( jack_controller_select_driver(
struct jack_controller * controller_ptr, struct jack_controller * controller_ptr,
const char * driver_name) 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; return false;
} }


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


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

return true; return true;
} }


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


assert(!controller_ptr->started); /* should be ensured by caller */ 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; controller_ptr->xruns = 0;


if (!jackctl_server_open( if (!jackctl_server_open(
controller_ptr->server, 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"); jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "Failed to open server");
goto fail; goto fail;
} }


jack_controller_add_slave_drivers(controller_ptr);
jack_controller_load_slave_drivers(controller_ptr);


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


fail_close_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)) if (!jackctl_server_close(controller_ptr->server))
{ {
@@ -317,7 +312,7 @@ jack_controller_stop_server(
return FALSE; return FALSE;
} }


jack_controller_remove_slave_drivers(controller_ptr);
jack_controller_unload_slave_drivers(controller_ptr);


if (!jackctl_server_close(controller_ptr->server)) if (!jackctl_server_close(controller_ptr->server))
{ {
@@ -337,12 +332,13 @@ jack_controller_switch_master(
{ {
if (!jackctl_server_switch_master( if (!jackctl_server_switch_master(
controller_ptr->server, 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"); jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "Failed to switch master");
return FALSE; return FALSE;
} }



return TRUE; return TRUE;
} }


@@ -408,16 +404,108 @@ on_device_release(const char * device_name)
g_device_count--; 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 * void *
jack_controller_create( jack_controller_create(
DBusConnection *connection) DBusConnection *connection)
{ {
struct jack_controller *controller_ptr; 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 = DBusObjectPathVTable vtable =
{ {
jack_dbus_message_handler_unregister, jack_dbus_message_handler_unregister,
@@ -439,54 +527,37 @@ jack_controller_create(
goto fail_free; 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; 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.context = controller_ptr;
controller_ptr->dbus_descriptor.interfaces = g_jackcontroller_interfaces; controller_ptr->dbus_descriptor.interfaces = g_jackcontroller_interfaces;
@@ -498,18 +569,15 @@ jack_controller_create(
&controller_ptr->dbus_descriptor)) &controller_ptr->dbus_descriptor))
{ {
jack_error("Ran out of memory trying to register D-Bus object path"); 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); jack_controller_settings_load(controller_ptr);


return 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: fail_destroy_server:
jackctl_server_destroy(controller_ptr->server); jackctl_server_destroy(controller_ptr->server);
@@ -526,7 +594,31 @@ jack_controller_add_slave_driver(
struct jack_controller * controller_ptr, struct jack_controller * controller_ptr,
const char * driver_name) const char * driver_name)
{ {
jackctl_driver_t * driver;
struct jack_controller_slave_driver * driver_ptr; 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)); driver_ptr = malloc(sizeof(struct jack_controller_slave_driver));
if (driver_ptr == NULL) if (driver_ptr == NULL)
@@ -543,12 +635,21 @@ jack_controller_add_slave_driver(
return false; 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); 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; return true;
} }


@@ -565,10 +666,25 @@ jack_controller_remove_slave_driver(
driver_ptr = list_entry(node_ptr, struct jack_controller_slave_driver, siblings); driver_ptr = list_entry(node_ptr, struct jack_controller_slave_driver, siblings);
if (strcmp(driver_ptr->name, driver_name) == 0) if (strcmp(driver_ptr->name, driver_name) == 0)
{ {
jack_info("slave driver \"%s\" removed", driver_name);
list_del(&driver_ptr->siblings); list_del(&driver_ptr->siblings);
free(driver_ptr->name); free(driver_ptr->name);
free(driver_ptr); 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; return true;
} }
} }
@@ -623,9 +739,8 @@ jack_controller_destroy(
jack_controller_stop_server(controller_ptr, NULL); 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); jackctl_server_destroy(controller_ptr->server);


free(controller_ptr); 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 "jackdbus.h"
#include "controller_internal.h" #include "controller_internal.h"
#include "xml.h"


#define JACK_DBUS_IFACE_NAME "org.jackaudio.JackControl" #define JACK_DBUS_IFACE_NAME "org.jackaudio.JackControl"


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

jack_controller_control_send_signal_server_stopped();
} }
else if (strcmp (call->method_name, "GetLoad") == 0) else if (strcmp (call->method_name, "GetLoad") == 0)
{ {
@@ -246,12 +245,17 @@ jack_control_run_method(
goto exit; 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( jack_dbus_error(
call, call,
JACK_DBUS_ERROR_GENERIC, JACK_DBUS_ERROR_GENERIC,
"jack_controller_add_slave_driver failed for driver (%s)", driver_name); "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) else if (strcmp (call->method_name, "RemoveSlaveDriver") == 0)
{ {
@@ -270,12 +274,17 @@ jack_control_run_method(
goto exit; 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( jack_dbus_error(
call, call,
JACK_DBUS_ERROR_GENERIC, JACK_DBUS_ERROR_GENERIC,
"jack_controller_remove_slave_driver failed for driver (%s)", driver_name); "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) 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 -*- */ /* -*- 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 Copyright (C) 2007-2008 Juuso Alasuutari
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
@@ -27,17 +27,20 @@
#include "jack/jack.h" #include "jack/jack.h"
#include "jackdbus.h" #include "jackdbus.h"
#include "list.h" #include "list.h"
#include "params.h"


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


struct jack_controller struct jack_controller
{ {
jackctl_server_t *server; jackctl_server_t *server;
jack_params_handle params;


void *patchbay_context; void *patchbay_context;


@@ -45,15 +48,10 @@ struct jack_controller
jack_client_t *client; jack_client_t *client;
unsigned int xruns; 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; 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; struct jack_dbus_object_descriptor dbus_descriptor;
}; };
@@ -65,21 +63,6 @@ struct jack_controller
"You probably don't want to edit this because\n" \ "You probably don't want to edit this because\n" \
"it will be overwritten next time jackdbus saves.\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 bool
jack_controller_start_server( jack_controller_start_server(
struct jack_controller *controller_ptr, struct jack_controller *controller_ptr,
@@ -121,47 +104,15 @@ jack_controller_unload_internal(
const char * internal_name); const char * internal_name);


void 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, 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 bool
jack_controller_patchbay_init( 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 = [ obj.source = [
'jackdbus.c', 'jackdbus.c',
'controller.c', 'controller.c',
'params.c',
'controller_iface_configure.c', 'controller_iface_configure.c',
'controller_iface_control.c', 'controller_iface_control.c',
'controller_iface_introspectable.c', 'controller_iface_introspectable.c',
@@ -59,7 +60,6 @@ def build(bld):
'controller_iface_transport.c', 'controller_iface_transport.c',
'xml.c', 'xml.c',
'xml_expat.c', 'xml_expat.c',
#'xml_libxml.c',
#'xml_nop.c', #'xml_nop.c',
'xml_write_raw.c', 'xml_write_raw.c',
'sigsegv.c', 'sigsegv.c',


+ 67
- 309
dbus/xml.c View File

@@ -1,6 +1,6 @@
/* -*- Mode: C ; c-basic-offset: 4 -*- */ /* -*- 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 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 it under the terms of the GNU General Public License as published by
@@ -25,358 +25,116 @@
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <assert.h>
#include <dbus/dbus.h> #include <dbus/dbus.h>


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


void 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; 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: case JackParamInt:
jack_controller_settings_set_sint_option(option_value, &value_int);
value.i = value_int;
value.i = atoi(option_value);
break; break;
case JackParamUInt: case JackParamUInt:
jack_controller_settings_set_uint_option(option_value, &value_uint);
value.ui = value_uint;
value.ui = strtoul(option_value, NULL, 10);
break; break;
case JackParamChar: 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; break;
case JackParamString: 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; break;
case JackParamBool: 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; break;
default: 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; 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 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; 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: 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: 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: case JackParamChar:
jack_controller_settings_set_char_option(option_value, &value.c);
break;
sprintf(value_buffer, "%c", (char)value.c);
return;
case JackParamString: case JackParamString:
jack_controller_settings_set_string_option(option_value, value.str, sizeof(value.str));
break;
strcpy(value_buffer, value.str);
return;
case JackParamBool: 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 -*- */ /* -*- 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 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 it under the terms of the GNU General Public License as published by
@@ -29,6 +29,7 @@
#include <fcntl.h> #include <fcntl.h>
#include <errno.h> #include <errno.h>
#include <string.h> #include <string.h>
#include <assert.h>
#include <expat.h> #include <expat.h>
#include <dbus/dbus.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 parse_context
{ {
struct jack_controller *controller_ptr; struct jack_controller *controller_ptr;
XML_Bool error; 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]; char option[JACK_PARAM_STRING_MAX+1];
int option_used; int option_used;
const char * address[PARAM_ADDRESS_SIZE];
int address_index;
char * container;
char *name; char *name;
}; };


@@ -80,7 +70,7 @@ jack_controller_settings_callback_chrdata(void *data, const XML_Char *s, int len
return; 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) 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 void
jack_controller_settings_callback_elstart(void *data, const char *el, const char **attr) 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) if (context_ptr->error)
{ {
return; 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; context_ptr->error = XML_TRUE;
return; return;
} }


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

if (strcmp(el, "jack") == 0) if (strcmp(el, "jack") == 0)
{ {
//jack_info("<jack>");
context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_JACK;
return; 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; 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; 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; 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) 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; context_ptr->error = XML_TRUE;
return; 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; context_ptr->error = XML_TRUE;
return; 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; return;
} }


if (strcmp(el, "option") == 0) if (strcmp(el, "option") == 0)
{ {
//jack_info("<option>");
if ((attr[0] == NULL || attr[2] != NULL) || strcmp(attr[0], "name") != 0) if ((attr[0] == NULL || attr[2] != NULL) || strcmp(attr[0], "name") != 0)
{ {
jack_error("<option> XML element must contain exactly one attribute, named \"name\""); 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; 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; context_ptr->option_used = 0;
return; return;
} }
@@ -225,49 +178,48 @@ jack_controller_settings_callback_elstart(void *data, const char *el, const char
void void
jack_controller_settings_callback_elend(void *data, const char *el) jack_controller_settings_callback_elend(void *data, const char *el)
{ {
int i;

if (context_ptr->error) if (context_ptr->error)
{ {
return; 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; 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); free(context_ptr->name);
context_ptr->name = NULL; 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.controller_ptr = controller_ptr;
context.error = XML_FALSE; context.error = XML_FALSE;
context.depth = -1;
context.option_value_capture = false;
context.address_index = 0;
context.name = NULL; context.name = NULL;
context.container = NULL;


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


xmls = XML_ParseBuffer(parser, bytes_read, XML_TRUE); xmls = XML_ParseBuffer(parser, bytes_read, XML_TRUE);

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

if (xmls == XML_STATUS_ERROR) if (xmls == XML_STATUS_ERROR)
{ {
jack_error("XML_ParseBuffer() failed."); 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 struct save_context
{ {
void * call;
int fd; 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 fd
#undef ctx_ptr


bool bool
jack_controller_settings_save( jack_controller_settings_save(
@@ -114,9 +117,9 @@ jack_controller_settings_save(
time_t timestamp; time_t timestamp;
char timestamp_str[26]; char timestamp_str[26];
struct save_context context; 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); time(&timestamp);
ctime_r(&timestamp, timestamp_str); ctime_r(&timestamp, timestamp_str);
@@ -147,6 +150,7 @@ jack_controller_settings_save(
} }


context.fd = fd; 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)) 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 = " "; 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; goto exit_close;
} }
@@ -206,100 +212,50 @@ jack_controller_settings_save(
goto exit_close; 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; 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; 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; 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; 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; 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; 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; 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)) 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 <errno.h>
#include <math.h> #include <math.h>
#include <signal.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -65,8 +66,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <semaphore.h> #include <semaphore.h>
#endif #endif


#include <signal.h>

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


#ifdef WIN32 #ifdef WIN32
@@ -75,9 +74,9 @@ typedef HANDLE semaphore_t;
typedef sem_t *semaphore_t; typedef sem_t *semaphore_t;
#endif #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_RESERVE = "could not reserve MIDI event on port buffer";
const char *ERROR_SHUTDOWN = "the JACK server has been shutdown"; 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_EVENT_RESERVE = "jack_midi_event_reserve";
const char *SOURCE_PROCESS = "handle_process"; const char *SOURCE_PROCESS = "handle_process";
@@ -107,7 +106,7 @@ size_t message_size;
jack_latency_range_t out_latency_range; jack_latency_range_t out_latency_range;
jack_port_t *out_port; jack_port_t *out_port;
semaphore_t process_semaphore; semaphore_t process_semaphore;
int process_state;
volatile sig_atomic_t process_state;
char *program_name; char *program_name;
jack_port_t *remote_in_port; jack_port_t *remote_in_port;
jack_port_t *remote_out_port; jack_port_t *remote_out_port;
@@ -118,13 +117,6 @@ jack_time_t total_latency_time;
size_t unexpected_messages; size_t unexpected_messages;
size_t xrun_count; size_t xrun_count;


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

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


static void static void
output_usage();
output_usage(void);


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


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


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


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


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

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

} }
return 0; return 0;
} }
@@ -346,6 +338,16 @@ handle_shutdown(void *arg)
set_process_error(SOURCE_SHUTDOWN, ERROR_SHUTDOWN); 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 static int
handle_xrun(void *arg) handle_xrun(void *arg)
{ {
@@ -360,7 +362,7 @@ output_error(const char *source, const char *message)
} }


static void static void
output_usage()
output_usage(void)
{ {
fprintf(stderr, "Usage: %s [options] out-port-name in-port-name\n\n" fprintf(stderr, "Usage: %s [options] out-port-name in-port-name\n\n"
"\t-h, --help print program usage\n" "\t-h, --help print program usage\n"
@@ -392,6 +394,32 @@ parse_positive_number_arg(char *s, char *name)
return result; 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 static void
set_process_error(const char *source, const char *message) 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; error_message = message;
process_state = -1; process_state = -1;
if (! signal_semaphore(process_semaphore)) { if (! signal_semaphore(process_semaphore)) {
// Sigh
/* Sigh ... */
output_error(source, message); output_error(source, message);
die(SOURCE_SIGNAL_SEMAPHORE, get_semaphore_error()); 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_size - 2) * sizeof(jack_midi_data_t));
message_2[message_size - 1] = 0xf7; 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); client = jack_client_open(program_name, JackNullOption, NULL);
if (client == NULL) { if (client == NULL) {
error_message = "failed to open JACK client"; error_message = "failed to open JACK client";
@@ -657,11 +672,21 @@ main(int argc, char **argv)
error_source = "post_semaphore"; error_source = "post_semaphore";
goto deactivate_client; 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) { if (wait_semaphore(process_semaphore, 1) == -1) {
error_message = get_semaphore_error(); error_message = get_semaphore_error();
error_source = "wait_semaphore"; error_source = "wait_semaphore";
goto deactivate_client; 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) { if (process_state == 2) {
double average_latency = ((double) total_latency) / samples; double average_latency = ((double) total_latency) / samples;
double average_latency_time = total_latency_time / samples; double average_latency_time = total_latency_time / samples;
@@ -739,17 +764,22 @@ main(int argc, char **argv)
latency_plot[100]); 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) { if (unexpected_messages) {
printf("Unexpected messages received: %d\n", unexpected_messages); printf("Unexpected messages received: %d\n", unexpected_messages);
} }
if (xrun_count) { 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_process_semaphore:
destroy_semaphore(process_semaphore, 1); destroy_semaphore(process_semaphore, 1);
destroy_init_semaphore: 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) { if (argc==1) {
return; return;
} }
fprintf(stderr, "usage: %s [bufsize]\n", package);
fprintf(stderr, "usage: %s\n", package);
exit(9); 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); ret = sscanf(buf, "Clocking: %" SCNu64, &mhz);
#elif defined( __s390__ ) #elif defined( __s390__ )
ret = sscanf(buf, "bogomips per cpu: %" SCNu64, &mhz); ret = sscanf(buf, "bogomips per cpu: %" SCNu64, &mhz);
#elif defined( __sh__ )
ret = sscanf(buf, "bogomips : %" SCNu64, &mhz);
#else /* MIPS, ARM, alpha */ #else /* MIPS, ARM, alpha */
ret = sscanf(buf, "BogoMIPS : %" SCNu64, &mhz); ret = sscanf(buf, "BogoMIPS : %" SCNu64, &mhz);
#endif #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 <alsa/asoundlib.h>


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


@@ -72,7 +74,7 @@ JackALSARawMidiDriver::Attach()
if (index == NO_PORT) { if (index == NO_PORT) {
jack_error("JackALSARawMidiDriver::Attach - cannot register input " jack_error("JackALSARawMidiDriver::Attach - cannot register input "
"port with name '%s'.", name); "port with name '%s'.", name);
// X: Do we need to deallocate ports?
// XX: Do we need to deallocate ports?
return -1; return -1;
} }
alias = input_port->GetAlias(); alias = input_port->GetAlias();
@@ -99,7 +101,7 @@ JackALSARawMidiDriver::Attach()
if (index == NO_PORT) { if (index == NO_PORT) {
jack_error("JackALSARawMidiDriver::Attach - cannot register " jack_error("JackALSARawMidiDriver::Attach - cannot register "
"output port with name '%s'.", name); "output port with name '%s'.", name);
// X: Do we need to deallocate ports?
// XX: Do we need to deallocate ports?
return -1; return -1;
} }
alias = output_port->GetAlias(); alias = output_port->GetAlias();
@@ -143,15 +145,51 @@ JackALSARawMidiDriver::Execute()
{ {
jack_nframes_t timeout_frame = 0; jack_nframes_t timeout_frame = 0;
for (;;) { 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) { if (! timeout_frame) {
timeout_frame_ptr = 0;
timeout_ptr = 0;
} else { } 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) { if (errno == EINTR) {
continue; continue;
} }
@@ -159,38 +197,73 @@ JackALSARawMidiDriver::Execute()
strerror(errno)); strerror(errno));
break; 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; 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 " jack_error("JackALSARawMidiDriver::Execute - a fatal error "
"occurred while processing ALSA input events.");
"occurred while processing ALSA output events.");
goto cleanup; 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 " jack_error("JackALSARawMidiDriver::Execute - a fatal error "
"occurred while processing ALSA output events.");
"occurred while processing ALSA input events.");
goto cleanup; goto cleanup;
} }
if (process_frame && ((! timeout_frame) ||
(process_frame < timeout_frame))) {
timeout_frame = process_frame;
}
} }
} }
cleanup: cleanup:
@@ -202,6 +275,21 @@ JackALSARawMidiDriver::Execute()
return false; 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 void
JackALSARawMidiDriver:: JackALSARawMidiDriver::
GetDeviceInfo(snd_ctl_t *control, snd_rawmidi_info_t *info, 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)) { if (! (potential_inputs || potential_outputs)) {
jack_error("JackALSARawMidiDriver::Open - no ALSA raw MIDI input or " jack_error("JackALSARawMidiDriver::Open - no ALSA raw MIDI input or "
"output ports found."); "output ports found.");
FreeDeviceInfo(&in_info_list, &out_info_list);
return -1; 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) { 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) { 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++) { for (size_t i = 0; i < potential_inputs; i++) {
snd_rawmidi_info_t *info = in_info_list.at(i); snd_rawmidi_info_t *info = in_info_list.at(i);
try { try {
input_ports[num_inputs] = new JackALSARawMidiInputPort(info, i); 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++; num_inputs++;
} catch (std::exception e) { } catch (std::exception e) {
jack_error("JackALSARawMidiDriver::Open - while creating new " 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); snd_rawmidi_info_t *info = out_info_list.at(i);
try { try {
output_ports[num_outputs] = new JackALSARawMidiOutputPort(info, i); 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++; num_outputs++;
} catch (std::exception e) { } catch (std::exception e) {
jack_error("JackALSARawMidiDriver::Open - while creating new " 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); 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 " jack_error("JackALSARawMidiDriver::Open - none of the potential "
"inputs or outputs were successfully opened."); "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 { } 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 int
@@ -450,39 +507,27 @@ JackALSARawMidiDriver::Start()
} }
try { try {
poll_fds = new pollfd[poll_fd_count]; poll_fds = new pollfd[poll_fd_count];
} catch (std::bad_alloc e) {
} catch (std::exception e) {
jack_error("JackALSARawMidiDriver::Start - creating poll descriptor " jack_error("JackALSARawMidiDriver::Start - creating poll descriptor "
"structures failed: %s", e.what()); "structures failed: %s", e.what());
return -1; 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; struct pollfd *poll_fd_iter;
if (pipe(fds) == -1) {
try {
CreateNonBlockingPipe(fds);
} catch (std::exception e) {
jack_error("JackALSARawMidiDriver::Start - while creating wake pipe: " 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].events = POLLERR | POLLIN | POLLNVAL;
poll_fds[0].fd = fds[0]; poll_fds[0].fd = fds[0];
@@ -496,6 +541,7 @@ JackALSARawMidiDriver::Start()
JackALSARawMidiOutputPort *output_port = output_ports[i]; JackALSARawMidiOutputPort *output_port = output_ports[i];
output_port->PopulatePollDescriptors(poll_fd_iter); output_port->PopulatePollDescriptors(poll_fd_iter);
poll_fd_iter += output_port->GetPollDescriptorCount(); poll_fd_iter += output_port->GetPollDescriptorCount();
output_port_timeouts[i] = 0;
} }


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


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

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


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

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


int
Poll(const jack_nframes_t *wakeup_frame);

public: public:


JackALSARawMidiDriver(const char *name, const char *alias, 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 <memory>


#include "JackALSARawMidiInputPort.h" #include "JackALSARawMidiInputPort.h"
@@ -28,7 +29,7 @@ JackALSARawMidiInputPort::JackALSARawMidiInputPort(snd_rawmidi_info_t *info,
size_t index, size_t index,
size_t max_bytes, size_t max_bytes,
size_t max_messages): size_t max_messages):
JackALSARawMidiPort(info, index)
JackALSARawMidiPort(info, index, POLLIN)
{ {
alsa_event = 0; alsa_event = 0;
jack_event = 0; jack_event = 0;
@@ -53,91 +54,69 @@ JackALSARawMidiInputPort::~JackALSARawMidiInputPort()
delete write_queue; 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 bool
JackALSARawMidiInputPort::ProcessJack(JackMidiBuffer *port_buffer, JackALSARawMidiInputPort::ProcessJack(JackMidiBuffer *port_buffer,
jack_nframes_t frames) jack_nframes_t frames)
{ {
write_queue->ResetMidiBuffer(port_buffer, frames); write_queue->ResetMidiBuffer(port_buffer, frames);
bool dequeued = false;
if (! jack_event) { 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)) { switch (write_queue->EnqueueEvent(jack_event, frames)) {
case JackMidiWriteQueue::BUFFER_TOO_SMALL: case JackMidiWriteQueue::BUFFER_TOO_SMALL:
jack_error("JackALSARawMidiInputPort::ProcessJack - The write " jack_error("JackALSARawMidiInputPort::ProcessJack - The write "
"queue couldn't enqueue a %d-byte event. Dropping " "queue couldn't enqueue a %d-byte event. Dropping "
"event.", jack_event->size); "event.", jack_event->size);
// Fallthrough on purpose
// Fallthrough on purpose.
case JackMidiWriteQueue::OK: case JackMidiWriteQueue::OK:
continue;
break;
default: 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; return true;
} }

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

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


jack_nframes_t
EnqueueALSAEvent();

public: public:


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

~JackALSARawMidiInputPort(); ~JackALSARawMidiInputPort();


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


bool 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 <memory>


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


JackALSARawMidiOutputPort::JackALSARawMidiOutputPort(snd_rawmidi_info_t *info, JackALSARawMidiOutputPort::JackALSARawMidiOutputPort(snd_rawmidi_info_t *info,
size_t index, size_t index,
size_t max_bytes_per_poll,
size_t max_bytes, size_t max_bytes,
size_t max_messages): size_t max_messages):
JackALSARawMidiPort(info, index)
JackALSARawMidiPort(info, index, POLLOUT)
{ {
alsa_event = 0; alsa_event = 0;
blocked = false;
read_queue = new JackMidiBufferReadQueue(); read_queue = new JackMidiBufferReadQueue();
std::auto_ptr<JackMidiBufferReadQueue> read_ptr(read_queue); 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); std::auto_ptr<JackALSARawMidiSendQueue> send_ptr(send_queue);
thread_queue = new JackMidiAsyncQueue(max_bytes, max_messages); thread_queue = new JackMidiAsyncQueue(max_bytes, max_messages);
std::auto_ptr<JackMidiAsyncQueue> thread_ptr(thread_queue); std::auto_ptr<JackMidiAsyncQueue> thread_ptr(thread_queue);
@@ -52,121 +53,94 @@ JackALSARawMidiOutputPort::~JackALSARawMidiOutputPort()
delete thread_queue; 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 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; 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) { 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)) { 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: 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. " "output queue couldn't enqueue a %d-byte event. "
"Dropping event.", alsa_event->size); "Dropping event.", alsa_event->size);
// Fallthrough on purpose
// Fallthrough on purpose.
case JackMidiWriteQueue::OK: case JackMidiWriteQueue::OK:
continue; continue;
default: 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(); *frame = raw_queue->Process();
blocked = send_queue->IsBlocked();
set_io_events:
bool blocked = send_queue->IsBlocked();
SetIOEventsEnabled(blocked);
if (blocked) { if (blocked) {

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

SetPollEventMask(POLLERR | POLLNVAL | POLLOUT);
*frame = 0; *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; return true;
} }

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

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


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


jack_midi_event_t *
DequeueALSAEvent(int read_fd);

public: public:


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

~JackALSARawMidiOutputPort(); ~JackALSARawMidiOutputPort();


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


bool 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 <stdexcept>
#include <string> #include <string>


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


using Jack::JackALSARawMidiPort; using Jack::JackALSARawMidiPort;


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


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


JackALSARawMidiPort::~JackALSARawMidiPort() JackALSARawMidiPort::~JackALSARawMidiPort()
{ {
DestroyNonBlockingPipe(fds);
if (rawmidi) { if (rawmidi) {
int code = snd_rawmidi_close(rawmidi); int code = snd_rawmidi_close(rawmidi);
if (code) { if (code) {
@@ -135,6 +145,32 @@ JackALSARawMidiPort::GetAlias()
return alias; 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 * const char *
JackALSARawMidiPort::GetName() JackALSARawMidiPort::GetName()
{ {
@@ -144,48 +180,76 @@ JackALSARawMidiPort::GetName()
int int
JackALSARawMidiPort::GetPollDescriptorCount() 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."); "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."); "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 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: private:


char alias[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; 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]; char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
int num_fds;
struct pollfd *poll_fds;
struct pollfd *queue_poll_fd;


protected: protected:


snd_rawmidi_t *rawmidi; snd_rawmidi_t *rawmidi;


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

int
GetQueuePollEvent();

void
SetIOEventsEnabled(bool enabled);


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

bool
TriggerQueueEvent();


public: public:


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


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


bool
void
PopulatePollDescriptors(struct pollfd *poll_fd); 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; 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; this->rawmidi = rawmidi;
blocked = false; blocked = false;
bytes_available = bytes_per_poll;
} }


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


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


public: public:


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


JackMidiWriteQueue::EnqueueResult JackMidiWriteQueue::EnqueueResult
EnqueueEvent(jack_nframes_t time, size_t size, EnqueueEvent(jack_nframes_t time, size_t size,
@@ -44,6 +47,9 @@ namespace Jack {
bool bool
IsBlocked(); 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 ) conf.define('HAVE_PPOLL', 1 )



def create_jack_driver_obj(bld, target, sources, uselib = None): def create_jack_driver_obj(bld, target, sources, uselib = None):
driver = bld.new_task_gen('cxx', 'shlib') driver = bld.new_task_gen('cxx', 'shlib')
driver.features.append('cc') driver.features.append('cc')
driver.env['shlib_PATTERN'] = 'jack_%s.so' 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.includes = ['.', '../linux', '../posix', '../common', '../common/jack', '../dbus']
driver.target = target driver.target = target
driver.source = sources driver.source = sources
@@ -62,7 +64,8 @@ def build(bld):
'alsarawmidi/JackALSARawMidiOutputPort.cpp', 'alsarawmidi/JackALSARawMidiOutputPort.cpp',
'alsarawmidi/JackALSARawMidiPort.cpp', 'alsarawmidi/JackALSARawMidiPort.cpp',
'alsarawmidi/JackALSARawMidiReceiveQueue.cpp', 'alsarawmidi/JackALSARawMidiReceiveQueue.cpp',
'alsarawmidi/JackALSARawMidiSendQueue.cpp'
'alsarawmidi/JackALSARawMidiSendQueue.cpp',
'alsarawmidi/JackALSARawMidiUtil.cpp'
] ]


ffado_driver_src = ['firewire/JackFFADODriver.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 "windows.h"
#include "mmsystem.h" #include "mmsystem.h"
#ifdef _WIN64 #ifdef _WIN64
#define JACK_ROUTER "JackRouter64.dll"
#define JACK_ROUTER "JackRouter.dll"
#include <psapi.h> #include <psapi.h>
#else #else
#define JACK_ROUTER "JackRouter.dll" #define JACK_ROUTER "JackRouter.dll"


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

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


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

@@ -53,7 +53,6 @@
<bgfoot> </> <bgfoot> </>
<bgback> </> <bgback> </>
<files listview > <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.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.lib</><dest>inst</><custom>lib</><ifexist>overnewer</><recurs>0</></>
<_><src>..\Release\bin\libjack.def</><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\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\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>..\..\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\mingwm10.dll</><dest>inst</><custom></><ifexist>overnewer</><recurs>0</></>
<_><src>.\qjackctl\qjackctl.exe</><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</></> <_><src>.\qjackctl\QtCore4.dll</><dest>inst</><custom></><ifexist>overnewer</><recurs>0</></>
@@ -107,7 +108,6 @@
</files> </files>
<runx listview > <runx listview >
<_><type>app</><path>inst</><file>vcredist_2010_x86.exe</><cmdline></><wait>1</><workdir>inst</><custdir></><when>end</></>
</runx> </runx>
<registry listview > <registry listview >
@@ -126,7 +126,7 @@
</copy> </copy>
<activex listview > <activex listview >
<_><path>inst</><name>JackRouter.dll</></>
<_><path>inst</><name>32bits\JackRouter.dll</></>
</activex> </activex>
<font listview > <font listview >


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

@@ -53,8 +53,6 @@
<bgfoot> </> <bgfoot> </>
<bgback> </> <bgback> </>
<files listview > <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.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.lib</><dest>inst</><custom>lib</><ifexist>overnewer</><recurs>0</></>
<_><src>..\Release64\bin\libjack64.def</><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.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.def</><dest>inst</><custom>lib</><ifexist>overnewer</><recurs>0</></>
<_><src>..\Release\bin\libjackserver.dll</><dest>sys</><custom></><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_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_disconnect.exe</><dest>inst</><custom></><ifexist>overnewer</><recurs>0</></>
<_><src>..\Release64\bin\jack_load.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\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\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>..\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_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\jack_netone.dll</><dest>inst</><custom>jack</><ifexist>overnewer</><recurs>0</></>
<_><src>..\Release64\bin\jack_netsource.exe</><dest>inst</><custom></><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\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\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>..\..\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\mingwm10.dll</><dest>inst</><custom></><ifexist>overnewer</><recurs>0</></>
<_><src>.\qjackctl\qjackctl.exe</><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</></> <_><src>.\qjackctl\QtCore4.dll</><dest>inst</><custom></><ifexist>overnewer</><recurs>0</></>
@@ -118,9 +121,7 @@
</files> </files>
<runx listview > <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 listview >
</registry> </registry>
@@ -138,8 +139,8 @@
</copy> </copy>
<activex listview > <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> </activex>
<font listview > <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" ?> <?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_workspace_file> <CodeBlocks_workspace_file>
<Workspace title="jack"> <Workspace title="jack">
<Project filename="libjackserver.cbp" />
<Project filename="libjackserver.cbp" active="1" />
<Project filename="jack_portaudio.cbp" /> <Project filename="jack_portaudio.cbp" />
<Project filename="jack_netdriver.cbp" /> <Project filename="jack_netdriver.cbp" />
<Project filename="jack_netonedriver.cbp" /> <Project filename="jack_netonedriver.cbp" />
<Project filename="jack_dummy.cbp" /> <Project filename="jack_dummy.cbp" />
<Project filename="jack_netmanager.cbp" /> <Project filename="jack_netmanager.cbp" />
<Project filename="jack_audioadapter.cbp" active="1" />
<Project filename="jack_audioadapter.cbp" />
<Project filename="libjack.cbp" /> <Project filename="libjack.cbp" />
<Project filename="jack_load.cbp" /> <Project filename="jack_load.cbp" />
<Project filename="jack_unload.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 <memory>
#include <stdexcept> #include <stdexcept>


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


void void
JackWinMMEInputPort::EnqueueMessage(jack_nframes_t time, size_t length,
JackWinMMEInputPort::EnqueueMessage(DWORD timestamp, size_t length,
jack_midi_data_t *data) 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: case JackMidiWriteQueue::BUFFER_FULL:
jack_error("JackWinMMEInputPort::EnqueueMessage - The thread queue " jack_error("JackWinMMEInputPort::EnqueueMessage - The thread queue "
"cannot currently accept a %d-byte event. Dropping event.", "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 void
JackWinMMEInputPort::ProcessJack(JackMidiBuffer *port_buffer, JackWinMMEInputPort::ProcessJack(JackMidiBuffer *port_buffer,
jack_nframes_t frames) jack_nframes_t frames)
@@ -164,7 +174,7 @@ JackWinMMEInputPort::ProcessJack(JackMidiBuffer *port_buffer,
jack_event = thread_queue->DequeueEvent(); jack_event = thread_queue->DequeueEvent();
} }
for (; jack_event; 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: case JackMidiWriteQueue::BUFFER_TOO_SMALL:
jack_error("JackWinMMEMidiInputPort::Process - The buffer write " jack_error("JackWinMMEMidiInputPort::Process - The buffer write "
"queue couldn't enqueue a %d-byte event. Dropping " "queue couldn't enqueue a %d-byte event. Dropping "
@@ -181,8 +191,6 @@ void
JackWinMMEInputPort::ProcessWinMME(UINT message, DWORD param1, DWORD param2) JackWinMMEInputPort::ProcessWinMME(UINT message, DWORD param1, DWORD param2)
{ {
set_threaded_log_function(); set_threaded_log_function();
jack_nframes_t current_frame = GetCurrentFrame();

switch (message) { switch (message) {
case MIM_CLOSE: case MIM_CLOSE:
jack_info("JackWinMMEInputPort::ProcessWinMME - MIDI device closed."); jack_info("JackWinMMEInputPort::ProcessWinMME - MIDI device closed.");
@@ -218,18 +226,24 @@ JackWinMMEInputPort::ProcessWinMME(UINT message, DWORD param1, DWORD param2)
"status byte."); "status byte.");
return; return;
} }
EnqueueMessage(current_frame, (size_t) length, message_buffer);
break;
EnqueueMessage(param2, (size_t) length, message_buffer);
break;
} }
case MIM_LONGDATA: { case MIM_LONGDATA: {
LPMIDIHDR header = (LPMIDIHDR) param1; 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; 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 " jack_error("JackWinMMEInputPort::ProcessWinMME - Discarding "
"%d-byte sysex chunk.", length1);
"%d-byte sysex chunk.", byte_count);
} else { } else {
EnqueueMessage(current_frame, length1, data);
EnqueueMessage(param2, byte_count, data);
} }
// Is this realtime-safe? This function isn't run in the JACK thread, // 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 // 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, MMRESULT result = midiInAddBuffer(handle, &sysex_header,
sizeof(MIDIHDR)); sizeof(MIDIHDR));
if (result != MMSYSERR_NOERROR) { if (result != MMSYSERR_NOERROR) {
WriteInError("JackWinMMEInputPort::ProcessWinMME", "midiInAddBuffer",
result);
WriteInError("JackWinMMEInputPort::ProcessWinMME",
"midiInAddBuffer", result);
} }
break;
break;
} }
case MIM_LONGERROR: case MIM_LONGERROR:
jack_error("JackWinMMEInputPort::ProcessWinMME - Invalid or " jack_error("JackWinMMEInputPort::ProcessWinMME - Invalid or "
@@ -255,6 +269,7 @@ bool
JackWinMMEInputPort::Start() JackWinMMEInputPort::Start()
{ {
if (! started) { if (! started) {
start_time = GetMicroSeconds();
MMRESULT result = midiInStart(handle); MMRESULT result = midiInStart(handle);
started = result == MMSYSERR_NOERROR; started = result == MMSYSERR_NOERROR;
if (! started) { if (! started) {
@@ -277,15 +292,6 @@ JackWinMMEInputPort::Stop()
return ! started; 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 void
JackWinMMEInputPort::WriteInError(const char *jack_func, const char *mm_func, JackWinMMEInputPort::WriteInError(const char *jack_func, const char *mm_func,
MMRESULT result) MMRESULT result)
@@ -294,5 +300,3 @@ JackWinMMEInputPort::WriteInError(const char *jack_func, const char *mm_func,
GetInErrorString(result, error_message); GetInErrorString(result, error_message);
jack_error("%s - %s: %s", jack_func, mm_func, 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); DWORD param1, DWORD param2);


void 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 void
ProcessWinMME(UINT message, DWORD param1, DWORD param2); ProcessWinMME(UINT message, DWORD param1, DWORD param2);


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

HMIDIIN handle; HMIDIIN handle;
jack_midi_event_t *jack_event; jack_midi_event_t *jack_event;
jack_time_t start_time;
bool started;
jack_midi_data_t *sysex_buffer; jack_midi_data_t *sysex_buffer;
MIDIHDR sysex_header; MIDIHDR sysex_header;
JackMidiAsyncQueue *thread_queue; JackMidiAsyncQueue *thread_queue;
JackMidiBufferWriteQueue *write_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: public:


JackWinMMEInputPort(const char *alias_name, const char *client_name, 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; MIDIHDR header;
header.dwBufferLength = size; header.dwBufferLength = size;
header.dwBytesRecorded = size;
header.dwFlags = 0; header.dwFlags = 0;
header.dwOffset = 0;
header.dwUser = 0;
header.lpData = (LPSTR)data;
header.lpData = (LPSTR) data;
result = midiOutPrepareHeader(handle, &header, sizeof(MIDIHDR)); result = midiOutPrepareHeader(handle, &header, sizeof(MIDIHDR));
if (result != MMSYSERR_NOERROR) { if (result != MMSYSERR_NOERROR) {
WriteOutError("JackWinMMEOutputPort::Execute", WriteOutError("JackWinMMEOutputPort::Execute",
@@ -215,9 +212,7 @@ JackWinMMEOutputPort::Execute()
"midiOutUnprepareHeader", result); "midiOutUnprepareHeader", result);
break; break;
} }

} }
stop_execution:
return false; return false;
} }


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

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


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


Loading…
Cancel
Save