Commit 6b765f01 authored by sletz's avatar sletz
Browse files

rebase from trunk 3684:3813

git-svn-id: http://subversion.jackaudio.org/jack/jack2/branches/libjacknet@3814 0c269be4-1314-0410-8aa9-9f06e86f4224
parent 224c41eb
......@@ -25,6 +25,62 @@ Paul Davis
Jackdmp changes log
---------------------------
2009-11-18 Stephane Letz <letz@grame.fr>
* Sync JackCoreAudioAdapter code with JackCoreAudioDriver.
2009-11-17 Stephane Letz <letz@grame.fr>
* In JackCoreAudio driver, clock drift compensation in aggregated devices working.
* In JackCoreAudio driver, clock drift compensation semantic changed a bit : when on, does not activate if not needed (same clock domain).
2009-11-16 Stephane Letz <letz@grame.fr>
* In JackCoreAudio driver, (possibly) clock drift compensation when needed in aggregated devices.
2009-11-14 Stephane Letz <letz@grame.fr>
* Sync with JACK1 : -r parameter now used for no-realtime, realtime (-R) is now default, usable backend given vie platform.
2009-11-13 Stephane Letz <letz@grame.fr>
* Better memory allocation error checking in ringbuffer.c, weak import improvements.
* Memory allocation error checking for jack_client_new and jack_client_open (server and client side).
* Memory allocation error checking in server for RPC.
* Simplify server temporary mode : now use a JackTemporaryException.
* Lock/Unlock shared memory segments (to test...).
2009-11-12 Stephane Letz <letz@grame.fr>
* Better memory allocation error checking on client (library) side.
2009-11-11 Stephane Letz <letz@grame.fr>
* Correct JackCoreAudio driver when empty strings are given as -C, -P or -d parameter.
2009-11-10 Stephane Letz <letz@grame.fr>
* Correct JackInfoShutdownCallback prototype, two new JackClientProcessFailure and JackClientZombie JackStatus code.
2009-11-09 Stephane Letz <letz@grame.fr>
* Correct JackGraphManager::GetBuffer for the "client loop with one connection" case : buffer must be copied.
2009-11-07 Stephane Letz <letz@grame.fr>
* Fix AcquireRealTime and DropRealTime: now distinguish when called from another thread (AcquireRealTime/DropRealTime) and from the thread itself (AcquireSelfRealTime/DropSelfRealTime).
* Correct JackPosixThread::StartImp : thread priority setting now done in the RT case only.
2009-11-06 Stephane Letz <letz@grame.fr>
* Correctly save and restore RT mode state in freewheel mode.
* Correct freewheel code on client side.
2009-11-05 Stephane Letz <letz@grame.fr>
* No reason to make jack_on_shutdown deprecated, so revert the incorrect change.
* Thread AcquireRealTime and DropRealTime were (incorrectly) using fThread field. Use pthread_self()) (or GetCurrentThread() on Windows) to get the calling thread.
2009-10-30 Stephane Letz <letz@grame.fr>
* In JackCoreAudioDriver, improve management of input/output channels: -1 is now used internally to indicate a wanted max value.
......@@ -32,6 +88,7 @@ Paul Davis
* Correct crash bug in JackAudioAdapterInterface when not input is used in adapter (temporary fix...)
* Sync JackCoreAudioAdapter code on JackCoreAudioDriver one.
* JACK_SCHED_POLICY switched to SCHED_FIFO.
* Now can aggregate device that are themselves AD.
2009-10-29 Stephane Letz <letz@grame.fr>
......@@ -398,12 +455,12 @@ Paul Davis
2009-01-05 Stephane Letz <letz@grame.fr>
* Synchronize jack2 public headers with jack1 ones.
* Synchronize jack2 public headers with JACK1 ones.
* Implement jack_client_real_time_priority and jack_client_max_real_time_priority API.
2008-12-18 Stephane Letz <letz@grame.fr>
* For ALSA driver, synchronize with latest jack1 memops functions.
* For ALSA driver, synchronize with latest JACK1 memops functions.
* Use memops functions in JackOSSDriver.
* Use memops functions in JackOSSAdapter.
......@@ -437,13 +494,13 @@ Paul Davis
2008-11-27 Stephane Letz <letz@grame.fr>
* Add timing profiling code in JackOSSDriver.
* Report ringbuffer.c fixes from jack1.
* Report ringbuffer.c fixes from JACK1.
2008-11-21 Stephane Letz <letz@grame.fr>
* Report ringbuffer.c fixes from jack1.
* Better isolation of server and clients system resources to allow starting the server in several user account at the same time.
* Correct ressource cleanup in case of driver open failure.
* Report ringbuffer.c fixes from JACK1.
* Better isolation of server and clients system resources to allow starting the server in several user account at the same time.
* Correct ressource cleanup in case of driver open failure.
2008-11-19 Stephane Letz <letz@grame.fr>
......
......@@ -213,6 +213,7 @@ Note : To experiment with the -S option, jackdmp must be launched in a console.
1.9.1 : Fix jackctl_server_unload_internal. Filter SIGPIPE to avoid having client get a SIGPIPE when trying to access a died server. Libjack shutdown handler does not "deactivate" (fActive = false) the client anymore, so that jack_deactivate correctly does the job later on. Better isolation of server and clients system resources to allow starting the server in several user account at the same time. Report ringbuffer.c fixes from jack1. Client and library global context cleanup in case of incorrect shutdown handling (that is applications not correctly closing client after server has shutdown). Use JACK_DRIVER_DIR variable in internal clients loader. For ALSA driver, synchronize with latest jack1 memops functions. Synchronize jack2 public headers with jack1 ones. Implement jack_client_real_time_priority and jack_client_max_real_time_priority API. Use up to BUFFER_SIZE_MAX frames in midi ports, fix for ticket #117. Cleanup server starting code for clients directly linked with libjackserver.so. JackMessageBuffer was using thread "Stop" scheme in destructor, now use the safer thread "Kill" way. Synchronize ALSA backend code with JACK1 one. Set default mode to 'slow' in JackNetDriver and JackNetAdapter. Simplify audio packet order verification. Fix JackNetInterface::SetNetBufferSize for socket buffer size computation and JackNetMasterInterface::DataRecv if synch packet is received, various cleanup. Better recovery of network overload situations, now "resynchronize" by skipping cycles.". Support for BIG_ENDIAN machines in NetJack2. Support for BIG_ENDIAN machines in NetJack2 for MIDI ports. Support for "-h" option in internal clients to print the parameters. In NetJack2, fix a bug when capture or playback only channels are used. Add a JACK_INTERNAL_DIR environment variable to be used for internal clients. Add a resample quality parameter in audioadapter. Now correctly return an error if JackServer::SetBufferSize could not change the buffer size (and was just restoring the current one). Use PRIu32 kind of macro in JackAlsaDriver again. Add a resample quality parameter in netadapter.
1.9.2 : Solaris version. New "profiling" tools. Rework the mutex/signal classes. Support for BIG_ENDIAN machines in NetJack2. D-BUS based device reservation to better coexist with PulseAudio on Linux. Add auto_connect parameter in netmanager and netadapter. Use Torben Hohn PI controler code for adapters. Client incorrect re-naming fixed : now done at socket and fifo level. Virtualize and allow overriding of thread creation function, to allow Wine support (from JACK1).
1.9.3 : New JackBoomerDriver class for Boomer driver on Solaris. Add mixed 32/64 bits mode (off by default). Native MIDI backend (JackCoreMidiDriver, JackWinMMEDriver). In ALSA audio card reservation code, tries to open the card even if reservation fails. Clock source setting on Linux. Add jackctl_server_switch_master API. Fix transport callback (timebase master, sync) issue when used after jack_activate (RT thread was not running). D-Bus access for jackctl_server_add_slave/jackctl_server_remove_slave API. Cleanup "loopback" stuff in server. Torben Hohn fix for InitTime and GetMicroSeconds in JackWinTime.c. New jack_free function added in jack.h. Reworked Torben Hohn fix for server restart issue on Windows. Correct jack_set_error_function, jack_set_info_function and jack_set_thread_creator functions. Correct JackFifo::TimedWait for EINTR handling. Move DBus based audio device reservation code in ALSA backend compilation. Correct JackTransportEngine::MakeAllLocating, sync callback has to be called in this case also. NetJack2 code : better error checkout, method renaming. Tim Bechmann patch : hammerfall, only release monitor thread, if it has been created. Tim Bechmann memops.c optimization patches. In combined --dbus and --classic compilation code, use PulseAudio acquire/release code. Big rewrite of Solaris boomer driver, seems to work in duplex mode at least. Loopback backend reborn as a dynamically loadable separated backend.
1.9.4 : Solaris boomer backend now working in capture or playback only mode. Add a -G parameter in CoreAudio backend (the computation value in RT thread expressed as percent of period). Use SNDCTL_DSP_SYNCGROUP/SNDCTL_DSP_SYNCSTART API to synchronize input and output in Solaris boomer backend. Big endian bug fix in memops.c. Fix issues in JackNetDriver::DecodeTransportData and JackNetDriver::Initialize. Correct CPU timing in JackNetDriver, now take cycle begin time after Read. Simplify transport in NetJack2: master only can control transport. Change CoreAudio notification thread setup for OSX Snow Leopard. Correct server temporary mode : now set a global and quit after server/client message handling is finished. Add a string parameter to server ==> client notification, add a new JackInfoShutdownCallback type. CoreAudio backend now issue a JackInfoShutdownCallback when an unrecoverable error is detected (sampling rate change, stream configuration changeÉ). Correct jackdmp.cpp (failures case were not correct..). Improve JackCoreAudioDriver code. Raise default port number to 2048. Correct JackProcessSync::LockedTimedWait. Correct JACK_MESSAGE_SIZE value, particularly in OSX RPC code. Now start server channel thread only when backend has been started (so in JackServer::Start). Should solve race conditions at start time. jack_verbose moved to JackGlobals class. Improve aggregate device management in JackCoreAudioDriver : now a "private" device only and cleanup properly. Aggregate device code added to JackCoreAudioAdapter. Implement "hog mode" (exclusive access of the audio device) in JackCoreAudioDriver. Fix jack_set_sample_rate_callback to have he same behavior as in JACK1. Dynamic system version detection in JackCoreAudioDriver to either create public or private aggregate device. In JackCoreAudioDriver, force the SR value to the wanted one *before* creating aggregate device (otherwise creation will fail). In JackCoreAudioDriver, better cleanup of AD when intermediate open failure. In JackCoreAudioDriver::Start, wait for the audio driver to effectively start (use the MeasureCallback). In JackCoreAudioDriver, improve management of input/output channels: -1 is now used internally to indicate a wanted max value. In JackCoreAudioDriver::OpenAUHAL, correct stream format setup and cleanup. Correct crash bug in JackAudioAdapterInterface when not input is used in adapter (temporary fixÉ). Sync JackCoreAudioAdapter code on JackCoreAudioDriver one. JACK_SCHED_POLICY switched to SCHED_FIFO. Now can aggregate device that are themselves AD. No reason to make jack_on_shutdown deprecated, so revert the incorrect change. Thread AcquireRealTime and DropRealTime were (incorrectly) using fThread field. Use pthread_self()) (or GetCurrentThread() on Windows) to get the calling thread. Correctly save and restore RT mode state in freewheel mode. Correct freewheel code on client side. Fix AcquireRealTime and DropRealTime: now distinguish when called from another thread (AcquireRealTime/DropRealTime) and from the thread itself (AcquireSelfRealTime/DropSelfRealTime). Correct JackPosixThread::StartImp : thread priority setting now done in the RT case only. Correct JackGraphManager::GetBuffer for the "client loop with one connection" case : buffer must be copied. Correct JackInfoShutdownCallback prototype, two new JackClientProcessFailure and JackClientZombie JackStatus code. Correct JackCoreAudio driver when empty strings are given as -C, -P or -d parameter. Better memory allocation error checking on client (library) side. Better memory allocation error checking in ringbuffer.c, weak import improvements. Memory allocation error checking for jack_client_new and jack_client_open (server and client side). Memory allocation error checking in server for RPC. Simplify server temporary mode : now use a JackTemporaryException. Lock/Unlock shared memory segments (to test...). Sync with JACK1 : -r parameter now used for no-realtime, realtime (-R) is now default, usable backend given vie platform. In JackCoreAudio driver, (possibly) clock drift compensation when needed in aggregated devices. In JackCoreAudio driver, clock drift compensation in aggregated devices working. In JackCoreAudio driver, clock drift compensation semantic changed a bit : when on, does not activate if not needed (same clock domain). Sync JackCoreAudioAdapter code with JackCoreAudioDriver.
This is a work in progress but the implementation is now stable enough to be tested. jackdmp has been used successfully with the following applications : Ardour, Hydrogen, Jamin, Qjackctl, Jack-Rack, SooperLooper, AlsaPlayer...
......
......@@ -290,15 +290,23 @@ EXPORT void jack_set_info_function (print_function func)
EXPORT jack_client_t* jack_client_new(const char* client_name)
{
assert(JackGlobals::fOpenMutex);
JackGlobals::fOpenMutex->Lock();
jack_error("jack_client_new: deprecated");
int options = JackUseExactName;
if (getenv("JACK_START_SERVER") == NULL)
options |= JackNoStartServer;
jack_client_t* res = jack_client_open_aux(client_name, (jack_options_t)options, NULL, NULL);
JackGlobals::fOpenMutex->Unlock();
return res;
try {
assert(JackGlobals::fOpenMutex);
JackGlobals::fOpenMutex->Lock();
jack_error("jack_client_new: deprecated");
int options = JackUseExactName;
if (getenv("JACK_START_SERVER") == NULL)
options |= JackNoStartServer;
jack_client_t* res = jack_client_open_aux(client_name, (jack_options_t)options, NULL, NULL);
JackGlobals::fOpenMutex->Unlock();
return res;
} catch (std::bad_alloc& e) {
jack_error("Memory allocation error...");
return NULL;
} catch (...) {
jack_error("Unknown error...");
return NULL;
}
}
EXPORT void* jack_port_get_buffer(jack_port_t* port, jack_nframes_t frames)
......@@ -814,7 +822,6 @@ EXPORT void jack_on_shutdown(jack_client_t* ext_client, JackShutdownCallback cal
JackLibGlobals::CheckContext();
#endif
JackClient* client = (JackClient*)ext_client;
jack_error("jack_on_shutdown: deprecated, use jack_on_info_shutdown");
if (client == NULL) {
jack_error("jack_on_shutdown called with a NULL client");
} else {
......@@ -1944,5 +1951,7 @@ jack_get_version_string()
EXPORT void jack_free(void* ptr)
{
free(ptr);
if (ptr) {
free(ptr);
}
}
......@@ -128,6 +128,10 @@ namespace Jack {
return -1;
//else allocate and fill it
argv = (char**)calloc (fArgv.size(), sizeof(char*));
if (argv == NULL)
{
return -1;
}
for ( unsigned int i = 0; i < fArgv.size(); i++ )
{
argv[i] = (char*)calloc(fArgv[i].length(), sizeof(char));
......
......@@ -170,90 +170,105 @@ int JackClient::ClientNotify(int refnum, const char* name, int notify, int sync,
case kAddClient:
jack_log("JackClient::kAddClient fName = %s name = %s", GetClientControl()->fName, name);
if (fClientRegistration && strcmp(GetClientControl()->fName, name) != 0) // Don't call the callback for the registering client itself
if (fClientRegistration && strcmp(GetClientControl()->fName, name) != 0) { // Don't call the callback for the registering client itself
fClientRegistration(name, 1, fClientRegistrationArg);
}
break;
case kRemoveClient:
jack_log("JackClient::kRemoveClient fName = %s name = %s", GetClientControl()->fName, name);
if (fClientRegistration && strcmp(GetClientControl()->fName, name) != 0) // Don't call the callback for the registering client itself
if (fClientRegistration && strcmp(GetClientControl()->fName, name) != 0) { // Don't call the callback for the registering client itself
fClientRegistration(name, 0, fClientRegistrationArg);
}
break;
case kBufferSizeCallback:
jack_log("JackClient::kBufferSizeCallback buffer_size = %ld", value1);
if (fBufferSize)
if (fBufferSize) {
res = fBufferSize(value1, fBufferSizeArg);
}
break;
case kSampleRateCallback:
jack_log("JackClient::kSampleRateCallback sample_rate = %ld", value1);
if (fSampleRate)
if (fSampleRate) {
res = fSampleRate(value1, fSampleRateArg);
}
break;
case kGraphOrderCallback:
jack_log("JackClient::kGraphOrderCallback");
if (fGraphOrder)
if (fGraphOrder) {
res = fGraphOrder(fGraphOrderArg);
}
break;
case kStartFreewheelCallback:
jack_log("JackClient::kStartFreewheel");
SetupDriverSync(true);
fThread.DropRealTime();
if (fFreewheel)
fThread.DropRealTime(); // Always done (JACK server in RT mode or not...)
if (fFreewheel) {
fFreewheel(1, fFreewheelArg);
}
break;
case kStopFreewheelCallback:
jack_log("JackClient::kStopFreewheel");
SetupDriverSync(false);
if (fFreewheel)
if (fFreewheel) {
fFreewheel(0, fFreewheelArg);
fThread.AcquireRealTime();
}
if (GetEngineControl()->fRealTime) {
fThread.AcquireRealTime();
}
break;
case kPortRegistrationOnCallback:
jack_log("JackClient::kPortRegistrationOn port_index = %ld", value1);
if (fPortRegistration)
if (fPortRegistration) {
fPortRegistration(value1, 1, fPortRegistrationArg);
}
break;
case kPortRegistrationOffCallback:
jack_log("JackClient::kPortRegistrationOff port_index = %ld ", value1);
if (fPortRegistration)
if (fPortRegistration) {
fPortRegistration(value1, 0, fPortRegistrationArg);
}
break;
case kPortConnectCallback:
jack_log("JackClient::kPortConnectCallback src = %ld dst = %ld", value1, value2);
if (fPortConnect)
if (fPortConnect) {
fPortConnect(value1, value2, 1, fPortConnectArg);
}
break;
case kPortDisconnectCallback:
jack_log("JackClient::kPortDisconnectCallback src = %ld dst = %ld", value1, value2);
if (fPortConnect)
if (fPortConnect) {
fPortConnect(value1, value2, 0, fPortConnectArg);
}
break;
case kPortRenameCallback:
jack_log("JackClient::kPortRenameCallback port = %ld");
if (fPortRename)
if (fPortRename) {
fPortRename(value1, GetGraphManager()->GetPort(value1)->GetName(), fPortRenameArg);
}
break;
case kXRunCallback:
jack_log("JackClient::kXRunCallback");
if (fXrun)
if (fXrun) {
res = fXrun(fXrunArg);
}
break;
case kShutDownCallback:
jack_log("JackClient::kShutDownCallback");
if (fInfoShutdown) {
fInfoShutdown(value1, message, fInfoShutdownArg);
fInfoShutdown((jack_status_t)value1, message, fInfoShutdownArg);
fInfoShutdown = NULL;
}
break;
......@@ -454,7 +469,7 @@ inline void JackClient::End()
jack_log("JackClient::Execute end name = %s", GetClientControl()->fName);
// Hum... not sure about this, the following "close" code is called in the RT thread...
int result;
fThread.DropRealTime();
fThread.DropSelfRealTime();
GetClientControl()->fActive = false;
fChannel->ClientDeactivate(GetClientControl()->fRefNum, &result);
fThread.Terminate();
......@@ -465,7 +480,7 @@ inline void JackClient::Error()
jack_error("JackClient::Execute error name = %s", GetClientControl()->fName);
// Hum... not sure about this, the following "close" code is called in the RT thread...
int result;
fThread.DropRealTime();
fThread.DropSelfRealTime();
GetClientControl()->fActive = false;
fChannel->ClientDeactivate(GetClientControl()->fRefNum, &result);
ShutDown();
......@@ -973,14 +988,7 @@ char* JackClient::GetInternalClientName(int ref)
char name_res[JACK_CLIENT_NAME_SIZE + 1];
int result = -1;
fChannel->GetInternalClientName(GetClientControl()->fRefNum, ref, name_res, &result);
if (result < 0) {
return NULL;
} else {
char* name = (char*)malloc(strlen(name_res));
strcpy(name, name_res);
return name;
}
return (result < 0) ? NULL : strdup(name_res);
}
int JackClient::InternalClientHandle(const char* client_name, jack_status_t* status)
......
......@@ -41,7 +41,7 @@
#define DRIVER_PORT_NUM 256
#ifndef PORT_NUM_FOR_CLIENT
#define PORT_NUM_FOR_CLIENT 512
#define PORT_NUM_FOR_CLIENT 768
#endif
#define FIRST_AVAILABLE_PORT 1
......
......@@ -611,6 +611,11 @@ get_realtime_priority_constraint()
//jack_info("realtime priority range is (%d,%d)", min, max);
constraint_ptr = (jack_driver_param_constraint_desc_t *)calloc(1, sizeof(jack_driver_param_value_enum_t));
if (constraint_ptr == NULL)
{
jack_error("Cannot allocate memory for jack_driver_param_constraint_desc_t structure.");
return NULL;
}
constraint_ptr->flags = JACK_CONSTRAINT_FLAG_RANGE;
constraint_ptr->constraint.range.min.i = min;
......
......@@ -119,7 +119,7 @@ void JackEngine::ReleaseRefnum(int ref)
// last client and temporay case: quit the server
jack_log("JackEngine::ReleaseRefnum server quit");
fEngineControl->fTemporary = false;
JackServerGlobals::fKilled = true;
throw JackTemporaryException();
}
}
}
......@@ -305,7 +305,15 @@ void JackEngine::NotifyFailure(int code, const char* reason)
void JackEngine::NotifyFreewheel(bool onoff)
{
fEngineControl->fRealTime = !onoff;
if (onoff) {
// Save RT state
fEngineControl->fSavedRealTime = fEngineControl->fRealTime;
fEngineControl->fRealTime = false;
} else {
// Restore RT state
fEngineControl->fRealTime = fEngineControl->fSavedRealTime;
fEngineControl->fSavedRealTime = false;
}
NotifyClients((onoff ? kStartFreewheelCallback : kStopFreewheelCallback), true, "", 0, 0);
}
......
......@@ -58,6 +58,7 @@ struct SERVER_EXPORT JackEngineControl : public JackShmMem
float fXrunDelayedUsecs;
bool fTimeOut;
bool fRealTime;
bool fSavedRealTime; // RT state saved and restored during Freewheel mode
int fServerPriority;
int fClientPriority;
int fMaxClientPriority;
......@@ -100,6 +101,7 @@ struct SERVER_EXPORT JackEngineControl : public JackShmMem
fTimeOut = (timeout > 0);
fTimeOutUsecs = timeout * 1000;
fRealTime = rt;
fSavedRealTime = false;
fServerPriority = priority;
fClientPriority = (rt) ? priority - 5 : 0;
fMaxClientPriority = (rt) ? priority - 1 : 0;
......
......@@ -58,7 +58,25 @@ class SERVER_EXPORT JackException : public std::runtime_error {
};
/*!
\brief Exception possibly thrown by Net Slaves.
\brief Exception thrown by JackEngine in temporary mode.
*/
class SERVER_EXPORT JackTemporaryException : public JackException {
public:
JackTemporaryException(const std::string& msg) : JackException(msg)
{}
JackTemporaryException(char* msg) : JackException(msg)
{}
JackTemporaryException(const char* msg) : JackException(msg)
{}
JackTemporaryException() : JackException("")
{}
};
/*!
\brief Exception possibly thrown by Net slaves.
*/
class SERVER_EXPORT JackNetException : public JackException {
......
......@@ -135,8 +135,8 @@ void* JackGraphManager::GetBuffer(jack_port_id_t port_index, jack_nframes_t buff
JackConnectionManager* manager = ReadCurrentState();
JackPort* port = GetPort(port_index);
// This happens when a port has just been unregistered and is still used by the RT code
if (!port->IsUsed()) {
// This happens when a port has just been unregistered and is still used by the RT code.
jack_log("JackGraphManager::GetBuffer : port = %ld is released state", port_index);
return GetBuffer(0); // port_index 0 is not used
}
......@@ -149,14 +149,29 @@ void* JackGraphManager::GetBuffer(jack_port_id_t port_index, jack_nframes_t buff
// Input port
jack_int_t len = manager->Connections(port_index);
if (len == 0) { // No connections: return a zero-filled buffer
// No connections : return a zero-filled buffer
if (len == 0) {
port->ClearBuffer(buffer_size);
return port->GetBuffer();
} else if (len == 1) { // One connection: use zero-copy mode - just pass the buffer of the connected (output) port.
assert(manager->GetPort(port_index, 0) != port_index); // Check recursion
return GetBuffer(manager->GetPort(port_index, 0), buffer_size);
} else { // Multiple connections
// One connection
} else if (len == 1) {
jack_port_id_t src_index = manager->GetPort(port_index, 0);
// Ports in same client : copy the buffer
if (GetPort(src_index)->GetRefNum() == port->GetRefNum()) {
void* buffers[1];
buffers[0] = GetBuffer(src_index, buffer_size);
port->MixBuffers(buffers, 1, buffer_size);
return port->GetBuffer();
// Otherwise, use zero-copy mode, just pass the buffer of the connected (output) port.
} else {
return GetBuffer(src_index, buffer_size);
}
// Multiple connections : mix all buffers
} else {
const jack_int_t* connections = manager->GetConnections(port_index);
void* buffers[CONNECTION_NUM_FOR_PORT];
jack_port_id_t src_index;
......@@ -167,7 +182,6 @@ void* JackGraphManager::GetBuffer(jack_port_id_t port_index, jack_nframes_t buff
buffers[i] = GetBuffer(src_index, buffer_size);
}
JackPort* port = GetPort(port_index);
port->MixBuffers(buffers, i, buffer_size);
return port->GetBuffer();
}
......@@ -688,6 +702,9 @@ const char** JackGraphManager::GetConnections(jack_port_id_t port_index)
{
const char** res = (const char**)malloc(sizeof(char*) * CONNECTION_NUM_FOR_PORT);
UInt16 cur_index, next_index;
if (!res)
return NULL;
do {
cur_index = GetCurrentIndex();
......@@ -768,6 +785,9 @@ const char** JackGraphManager::GetPorts(const char* port_name_pattern, const cha
{
const char** res = (const char**)malloc(sizeof(char*) * PORT_NUM);
UInt16 cur_index, next_index;
if (!res)
return NULL;
do {
cur_index = GetCurrentIndex();
......
......@@ -111,14 +111,22 @@ EXPORT jack_client_t* jack_client_open_aux(const char* client_name, jack_options
EXPORT jack_client_t* jack_client_open(const char* ext_client_name, jack_options_t options, jack_status_t* status, ...)
{
assert(JackGlobals::fOpenMutex);
JackGlobals::fOpenMutex->Lock();
va_list ap;
va_start(ap, status);
jack_client_t* res = jack_client_open_aux(ext_client_name, options, status, ap);
va_end(ap);
JackGlobals::fOpenMutex->Unlock();
return res;
try {
assert(JackGlobals::fOpenMutex);
JackGlobals::fOpenMutex->Lock();
va_list ap;
va_start(ap, status);
jack_client_t* res = jack_client_open_aux(ext_client_name, options, status, ap);
va_end(ap);
JackGlobals::fOpenMutex->Unlock();
return res;
} catch(std::bad_alloc& e) {
jack_error("Memory allocation error...");
return NULL;
} catch (...) {
jack_error("Unknown error...");
return NULL;
}
}
EXPORT int jack_client_close(jack_client_t* ext_client)
......
......@@ -22,10 +22,35 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include "JackEngine.h"
#include "JackMutex.h"
#include "JackTools.h"
#include "JackException.h"
namespace Jack
{
#define TRY_CALL \
try { \
#define CATCH_EXCEPTION_RETURN \
} catch(std::bad_alloc& e) { \
jack_error("Memory allocation error..."); \
return -1; \
} catch(JackTemporaryException& e) { \
jack_error("JackTemporaryException : now quits..."); \
JackTools::KillServer(); \
return -1; \
} catch (...) { \
jack_error("Unknown error..."); \
return -1; \
} \
#define CATCH_ENGINE_EXCEPTION \
} catch(std::bad_alloc& e) { \
jack_error("Memory allocation error..."); \
} catch (...) { \
jack_error("Unknown error..."); \
} \
/*!
\brief Locked Engine, access to methods is serialized using a mutex.
*/
......@@ -47,108 +72,146 @@ class SERVER_EXPORT JackLockedEngine : public JackLockAble
int Open()
{
// No lock needed
TRY_CALL
return fEngine.Open();
CATCH_EXCEPTION_RETURN
}
int Close()
{
// No lock needed
TRY_CALL
return fEngine.Close();
CATCH_EXCEPTION_RETURN
}
// Client management
int ClientCheck(const char* name, char* name_res, int protocol, int options, int* status)
{
TRY_CALL
JackLock lock(this);
return fEngine.ClientCheck(name, name_res, protocol, options, status);
CATCH_EXCEPTION_RETURN
}
int ClientExternalOpen(const char* name, int pid, int* ref, int* shared_engine, int* shared_client, int* shared_graph_manager)
{
TRY_CALL
JackLock lock(this);
return fEngine.ClientExternalOpen(name, pid, ref, shared_engine, shared_client, shared_graph_manager);
CATCH_EXCEPTION_RETURN
}
int ClientInternalOpen(const char* name, int* ref, JackEngineControl** shared_engine, JackGraphManager** shared_manager, JackClientInterface* client, bool wait)
{
TRY_CALL
JackLock lock(this);
return fEngine.ClientInternalOpen(name, ref, shared_engine, shared_manager, client, wait);
CATCH_EXCEPTION_RETURN
}
int ClientExternalClose(int refnum)
{
TRY_CALL
JackLock lock(this);
return fEngine.ClientExternalClose(refnum);
CATCH_EXCEPTION_RETURN
}
int ClientInternalClose(int refnum, bool wait)
{
TRY_CALL
JackLock lock(this);
return fEngine.ClientInternalClose(refnum, wait);
CATCH_EXCEPTION_RETURN
}
int ClientActivate(int refnum, bool is_real_time)
{
TRY_CALL