Commit 416928c2 authored by sletz's avatar sletz
Browse files

rebase from trunk 3455:3482

git-svn-id: http://subversion.jackaudio.org/jack/jack2/branches/libjacknet@3483 0c269be4-1314-0410-8aa9-9f06e86f4224
parent 31bb3bc2
......@@ -18,12 +18,34 @@ Fernando Lopez-Lezcano
Romain Moret
Florian Faber
Michael Voigt
Torben Hohn
Torben Hohn
Paul Davis
---------------------------
Jackdmp changes log
---------------------------
2009-04-03 Stephane Letz <letz@grame.fr>
* Simplify JackClient RT code, jack_thread_wait API marked deprecated."
2009-03-29 Stephane Letz <letz@grame.fr>
* Cleanup JackInternalClient code.
2009-03-27 Stephane Letz <letz@grame.fr>
* Add a buffer size callback for netmaster that just remove the client (it will be recreated with the new parameters).
2009-03-26 Stephane Letz <letz@grame.fr>
* First working JackBoomerDriver two threads version.
2009-03-24 Stephane Letz <letz@grame.fr>
* New JackBoomerDriver class for Boomer driver on Solaris.
* Add mixed 32/64 bits mode (off by default).
2009-03-23 Stephane Letz <letz@grame.fr>
* Version 1.9.3 started.
......
--------------------------------------
jackdmp for Linux, MacOSX and Windows
--------------------------------------
-----------------------------------------------
jackdmp for Linux, MacOSX, Windows and Solaris
-----------------------------------------------
jackdmp is a C++ version of the JACK low-latency audio server for multi-processor machines. It is a new implementation of the JACK server core features that aims in removing some limitations of the current design. The activation system has been changed for a data flow model and lock-free programming techniques for graph access have been used to have a more dynamic and robust system.
......@@ -36,12 +36,40 @@ Important compilation options :
- the --dbus flag must be defined at configure time to compile the jackdbus executable. If the "automatic start server option" is used by clients, jackd server will be started using the dbus service.
----------------------------
Known problems, limitations
----------------------------
- use of POSIX named semaphore is currently unstable and not recommended yet.
----------------
Solaris version
----------------
The published version uses fifos for server/client synchronization. Sockets are used for server/client communications. An OSS backend is used. To build jackdmp, a "waf" (http://code.google.com/p/waf/) based compilation system is available. The code has to be compiled on a machine where OSS 4.0 headers and libraries are corrected installed.
In the top folder do :
./waf configure
./waf build
sudo ./waf install
(Note : you may have to use "pfexec" instead of "sudo" on systems where sudo is not there.)
Various compilation options can be seen using ./waf --help.
Important compilation options :
- if the "automatic start server option" is used by clients, jackd server will be started using the old fork + exe system.
- the --dbus flag must be defined at configure time to compile the jackdbus executable. If the "automatic start server option" is used by clients, jackd server will be started using the dbus service.
Starting the server :
- for best performances, the server has to be started with privileges that allows to use "real-time" threads, for example using the "pfexec" command (or configurating the system with "priocntl" first), for instance : pfexec jackd -R -S -P59 -d oss
- audio cards info can be retrieved using "ossinfo" tool (for instance ossinfo -v3). Some card needs to be configurated first using "ossxmix" then the correct buffer size has to be used, for instance : pfexec jackd -R -S -P59 -d oss -p 512
------------
OSX version
......@@ -95,7 +123,7 @@ The binary elements are :
- jack_portaudio.dll : the PortAudio based backend. The backend components (currently "jack_portaudio.dll" only) are searched for in a "jackmp" folder located with the "jackdmp.exe" server.
- jack_dummy.dll : the "dummy" driver.
- jack_dummy.dll : the "dummy" driver.
- jack_net.dll : the NetJack driver.
......
......@@ -842,7 +842,8 @@ EXPORT jack_nframes_t jack_thread_wait(jack_client_t* ext_client, int status)
jack_error("jack_thread_wait called with a NULL client");
return 0;
} else {
return client->Wait(status);
jack_error("jack_thread_wait: deprecated, use jack_cycle_wait/jack_cycle_signal");
return -1;
}
}
......
......@@ -355,6 +355,7 @@ int JackClient::StartThread()
/*!
\brief RT thread.
*/
bool JackClient::Execute()
{
if (!jack_tls_set(JackGlobals::fRealTime, this))
......@@ -362,73 +363,59 @@ bool JackClient::Execute()
if (GetEngineControl()->fRealTime)
set_threaded_log_function();
// Execute a dummy cycle to be sure thread has the correct properties
DummyCycle();
if (fThreadFun) {
// Execute a dummy cycle to be sure thread has the correct properties (ensure thread creation is finished)
WaitSync();
SignalSync();
fThreadFun(fThreadFunArg);
} else {
if (WaitFirstSync())
ExecuteThread();
ExecuteThread();
}
return false;
}
inline bool JackClient::WaitFirstSync()
void JackClient::DummyCycle()
{
while (true) {
// Start first cycle
WaitSync();
if (IsActive()) {
CallSyncCallback();
// Finish first cycle
if (Wait(CallProcessCallback()) != GetEngineControl()->fBufferSize)
return false;
return true;
} else {
jack_log("Process called for an inactive client");
}
SignalSync();
}
return false;
WaitSync();
SignalSync();
}
inline void JackClient::ExecuteThread()
{
while (Wait(CallProcessCallback()) == GetEngineControl()->fBufferSize);
while (true) {
CycleWaitAux();
CycleSignalAux(CallProcessCallback());
}
}
jack_nframes_t JackClient::Wait(int status)
{
if (status == 0)
CallTimebaseCallback();
SignalSync();
if (status != 0)
End(); // Terminates the thread
if (!WaitSync())
Error(); // Terminates the thread
CallSyncCallback();
return GetEngineControl()->fBufferSize;
}
jack_nframes_t JackClient::CycleWait()
inline jack_nframes_t JackClient::CycleWaitAux()
{
if (!WaitSync())
Error(); // Terminates the thread
CallSyncCallback();
CallSyncCallbackAux();
return GetEngineControl()->fBufferSize;
}
void JackClient::CycleSignal(int status)
inline void JackClient::CycleSignalAux(int status)
{
if (status == 0)
CallTimebaseCallback();
CallTimebaseCallbackAux();
SignalSync();
if (status != 0)
End(); // Terminates the thread
}
jack_nframes_t JackClient::CycleWait()
{
return CycleWaitAux();
}
void JackClient::CycleSignal(int status)
{
CycleSignalAux(status);
}
inline int JackClient::CallProcessCallback()
{
return (fProcess != NULL) ? fProcess(GetEngineControl()->fBufferSize, fProcessArg) : 0;
......@@ -696,7 +683,13 @@ void JackClient::TransportStop()
// Never called concurently with the server
// TODO check concurrency with SetSyncCallback
void JackClient::CallSyncCallback()
{
CallSyncCallbackAux();
}
inline void JackClient::CallSyncCallbackAux()
{
if (GetClientControl()->fTransportSync) {
......@@ -717,6 +710,11 @@ void JackClient::CallSyncCallback()
}
void JackClient::CallTimebaseCallback()
{
CallTimebaseCallbackAux();
}
inline void JackClient::CallTimebaseCallbackAux()
{
JackTransportEngine& transport = GetEngineControl()->fTransport;
int master;
......
......@@ -97,14 +97,18 @@ class JackClient : public JackClientInterface, public JackRunnableInterface
virtual int ClientNotifyImp(int refnum, const char* name, int notify, int sync, int value1, int value);
inline bool WaitFirstSync();
inline void DummyCycle();
inline void ExecuteThread();
inline bool WaitSync();
inline void SignalSync();
inline int CallProcessCallback();
inline void End();
inline void Error();
inline jack_nframes_t CycleWaitAux();
inline void CycleSignalAux(int status);
inline void CallSyncCallbackAux();
inline void CallTimebaseCallbackAux();
public:
JackClient();
......@@ -172,10 +176,7 @@ class JackClient : public JackClientInterface, public JackRunnableInterface
virtual int InternalClientLoad(const char* client_name, jack_options_t options, jack_status_t* status, jack_varargs_t* va);
virtual void InternalClientUnload(int ref, jack_status_t* status);
// Fons Adriaensen thread model
virtual jack_nframes_t Wait(int status);
virtual jack_nframes_t CycleWait();
jack_nframes_t CycleWait();
void CycleSignal(int status);
int SetProcessThread(JackThreadCallback fun, void *arg);
......@@ -184,11 +185,6 @@ class JackClient : public JackClientInterface, public JackRunnableInterface
bool Execute();
};
// Each "side" server and client will implement this to get the shared graph manager, engine control and inter-process synchro table.
extern JackGraphManager* GetGraphManager();
extern JackEngineControl* GetEngineControl();
extern JackSynchro* GetSynchroTable();
} // end of namespace
#endif
......@@ -79,7 +79,7 @@ struct JackClientControl : public JackShmMemAble
fActive = false;
}
};
} POST_PACKED_STRUCTURE;
} // end of namespace
......
......@@ -356,7 +356,7 @@ struct JackClientTiming
{}
~JackClientTiming()
{}
};
} POST_PACKED_STRUCTURE;
/*!
\brief Connection manager.
......@@ -445,12 +445,11 @@ class SERVER_EXPORT JackConnectionManager
return fInputCounter[refnum].GetValue();
}
// Graph
void ResetGraph(JackClientTiming* timing);
int ResumeRefNum(JackClientControl* control, JackSynchro* table, JackClientTiming* timing);
int SuspendRefNum(JackClientControl* control, JackSynchro* table, JackClientTiming* timing, long time_out_usec);
};
} // end of namespace
......
......@@ -83,11 +83,7 @@
#define ALL_CLIENTS -1 // for notification
#if defined(__ppc64__) || defined(__x86_64__)
#define JACK_PROTOCOL_VERSION 6
#else
#define JACK_PROTOCOL_VERSION 5
#endif
#define JACK_PROTOCOL_VERSION 7
#define SOCKET_TIME_OUT 5 // in sec
#define DRIVER_OPEN_TIMEOUT 5 // in sec
......
......@@ -521,11 +521,5 @@ void JackDebugClient::InternalClientUnload(int ref, jack_status_t* status)
fClient->InternalClientUnload(ref, status);
}
jack_nframes_t JackDebugClient::Wait(int status)
{
CheckClient();
return fClient->Wait(status);
}
} // end of namespace
......@@ -127,9 +127,6 @@ class JackDebugClient : public JackClient
int InternalClientLoad(const char* client_name, jack_options_t options, jack_status_t* status, jack_varargs_t* va);
void InternalClientUnload(int ref, jack_status_t* status);
// Fons Adriaensen thread model
jack_nframes_t Wait(int status);
JackClientControl* GetClientControl() const;
void CheckClient() const;
......
......@@ -432,8 +432,7 @@ jack_get_descriptor (JSList * drivers, const char * sofile, const char * symbol)
return NULL;
}
so_get_descriptor = (JackDriverDescFunction)
GetProc(dlhandle, symbol);
so_get_descriptor = (JackDriverDescFunction)GetDriverProc(dlhandle, symbol);
#ifdef WIN32
if ((so_get_descriptor == NULL) && (dlerr = GetLastError()) != 0) {
......@@ -513,7 +512,7 @@ static bool check_symbol(const char* sofile, const char* symbol)
jack_error ("could not open component .so '%s': %s", filename, dlerror());
#endif
} else {
res = (GetProc(dlhandle, symbol)) ? true : false;
res = (GetDriverProc(dlhandle, symbol)) ? true : false;
UnloadDriverModule(dlhandle);
}
......@@ -791,7 +790,7 @@ Jack::JackDriverClientInterface* JackDriverInfo::Open(jack_driver_desc_t* driver
return NULL;
}
fInitialize = (driverInitialize)GetProc(fHandle, "driver_initialize");
fInitialize = (driverInitialize)GetDriverProc(fHandle, "driver_initialize");
#ifdef WIN32
if ((fInitialize == NULL) && (errstr = GetLastError ()) != 0) {
......
......@@ -69,7 +69,7 @@ int JackEngine::Close()
{
jack_log("JackEngine::Close");
fChannel.Close();
// Close remaining clients (RT is stopped)
for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) {
if (JackLoadableInternalClient* loadable_client = dynamic_cast<JackLoadableInternalClient*>(fClientTable[i])) {
......@@ -85,10 +85,10 @@ int JackEngine::Close()
fClientTable[i] = NULL;
}
}
return 0;
}
//-----------------------------
// Client ressource management
//-----------------------------
......@@ -147,7 +147,7 @@ void JackEngine::ProcessCurrent(jack_time_t cur_cycle_begin)
bool JackEngine::Process(jack_time_t cur_cycle_begin, jack_time_t prev_cycle_end)
{
bool res = true;
// Cycle begin
fEngineControl->CycleBegin(fClientTable, fGraphManager, cur_cycle_begin, prev_cycle_end);
......@@ -213,7 +213,7 @@ void JackEngine::NotifyClient(int refnum, int event, int sync, int value1, int v
jack_log("JackEngine::NotifyClient: client not available anymore");
} else if (client->GetClientControl()->fCallback[event]) {
if (client->ClientNotify(refnum, client->GetClientControl()->fName, event, sync, value1, value2) < 0)
jack_error("NotifyClient fails name = %s event = %ld = val1 = %ld val2 = %ld", client->GetClientControl()->fName, event, value1, value2);
jack_error("NotifyClient fails name = %s event = %ld val1 = %ld val2 = %ld", client->GetClientControl()->fName, event, value1, value2);
} else {
jack_log("JackEngine::NotifyClient: no callback for event = %ld", event);
}
......@@ -226,7 +226,7 @@ void JackEngine::NotifyClients(int event, int sync, int value1, int value2)
if (client) {
if (client->GetClientControl()->fCallback[event]) {
if (client->ClientNotify(i, client->GetClientControl()->fName, event, sync, value1, value2) < 0)
jack_error("NotifyClient fails name = %s event = %ld = val1 = %ld val2 = %ld", client->GetClientControl()->fName, event, value1, value2);
jack_error("NotifyClient fails name = %s event = %ld val1 = %ld val2 = %ld", client->GetClientControl()->fName, event, value1, value2);
} else {
jack_log("JackEngine::NotifyClients: no callback for event = %ld", event);
}
......@@ -461,7 +461,7 @@ int JackEngine::GetClientPID(const char* name)
if (client && (strcmp(client->GetClientControl()->fName, name) == 0))
return client->GetClientControl()->fPID;
}
return 0;
}
......@@ -472,7 +472,7 @@ int JackEngine::GetClientRefNum(const char* name)
if (client && (strcmp(client->GetClientControl()->fName, name) == 0))
return client->GetClientControl()->fRefNum;
}
return -1;
}
......@@ -511,7 +511,7 @@ int JackEngine::ClientExternalOpen(const char* name, int pid, int* ref, int* sha
jack_error("Cannot notify add client");
goto error;
}
fGraphManager->InitRefNum(refnum);
fEngineControl->ResetRollingUsecs();
*shared_engine = fEngineControl->GetShmIndex();
......@@ -576,7 +576,7 @@ int JackEngine::ClientExternalClose(int refnum)
{
AssertRefnum(refnum);
JackClientInterface* client = fClientTable[refnum];
if (client) {
fEngineControl->fTransport.ResetTimebase(refnum);
int res = ClientCloseAux(refnum, client, true);
......@@ -613,7 +613,7 @@ int JackEngine::ClientCloseAux(int refnum, JackClientInterface* client, bool wai
for (i = 0; (i < PORT_NUM_FOR_CLIENT) && (ports[i] != EMPTY) ; i++) {
PortUnRegister(refnum, ports[i]);
}
// Remove the client from the table
ReleaseRefnum(refnum);
......@@ -641,11 +641,11 @@ int JackEngine::ClientActivate(int refnum, bool state)
AssertRefnum(refnum);
JackClientInterface* client = fClientTable[refnum];
assert(fClientTable[refnum]);
jack_log("JackEngine::ClientActivate ref = %ld name = %s", refnum, client->GetClientControl()->fName);
if (state)
if (state)
fGraphManager->Activate(refnum);
// Wait for graph state change to be effective
if (!fSignal.LockedTimedWait(fEngineControl->fTimeOutUsecs * 10)) {
jack_error("JackEngine::ClientActivate wait error ref = %ld name = %s", refnum, client->GetClientControl()->fName);
......@@ -665,11 +665,11 @@ int JackEngine::ClientDeactivate(int refnum)
return -1;
jack_log("JackEngine::ClientDeactivate ref = %ld name = %s", refnum, client->GetClientControl()->fName);
// Disconnect all ports ==> notifications are sent
jack_int_t ports[PORT_NUM_FOR_CLIENT];
int i;
fGraphManager->GetInputPorts(refnum, ports);
for (i = 0; (i < PORT_NUM_FOR_CLIENT) && (ports[i] != EMPTY) ; i++) {
PortDisconnect(refnum, ports[i], ALL_PORTS);
......@@ -679,7 +679,7 @@ int JackEngine::ClientDeactivate(int refnum)
for (i = 0; (i < PORT_NUM_FOR_CLIENT) && (ports[i] != EMPTY) ; i++) {
PortDisconnect(refnum, ports[i], ALL_PORTS);
}
fGraphManager->Deactivate(refnum);
fLastSwitchUsecs = 0; // Force switch to occur next cycle, even when called with "dead" clients
......@@ -701,11 +701,11 @@ int JackEngine::PortRegister(int refnum, const char* name, const char *type, uns
jack_log("JackEngine::PortRegister ref = %ld name = %s type = %s flags = %d buffer_size = %d", refnum, name, type, flags, buffer_size);
AssertRefnum(refnum);
assert(fClientTable[refnum]);
// Check if port name already exists
if (fGraphManager->GetPort(name) != NO_PORT) {
jack_error("port_name \"%s\" already exists", name);
return -1;
return -1;
}
*port_index = fGraphManager->AllocatePort(refnum, name, type, (JackPortFlags)flags, fEngineControl->fBufferSize);
......@@ -722,7 +722,7 @@ int JackEngine::PortUnRegister(int refnum, jack_port_id_t port_index)
jack_log("JackEngine::PortUnRegister ref = %ld port_index = %ld", refnum, port_index);
AssertRefnum(refnum);
assert(fClientTable[refnum]);
// Disconnect port ==> notification is sent
PortDisconnect(refnum, port_index, ALL_PORTS);
......@@ -775,7 +775,7 @@ int JackEngine::PortConnect(int refnum, jack_port_id_t src, jack_port_id_t dst)
}
int res = fGraphManager->Connect(src, dst);
if (res == 0)
if (res == 0)
NotifyPortConnect(src, dst, true);
return res;
}
......
......@@ -166,7 +166,7 @@ struct SERVER_EXPORT JackEngineControl : public JackShmMem
void CalcCPULoad(JackClientInterface** table, JackGraphManager* manager, jack_time_t cur_cycle_begin, jack_time_t prev_cycle_end);
void ResetRollingUsecs();
};
} POST_PACKED_STRUCTURE;
} // end of namespace
......
......@@ -52,7 +52,8 @@ struct JackTimingMeasureClient
fFinishedAt(0),
fStatus((jack_client_state_t)0)
{}
};
} POST_PACKED_STRUCTURE;
/*!
\brief Timing interval in the global table for a given client
......@@ -70,7 +71,8 @@ struct JackTimingClientInterval
fBeginInterval(-1),
fEndInterval(-1)
{}
};
} POST_PACKED_STRUCTURE;
/*!
\brief Timing stucture for a table of clients.
......@@ -90,7 +92,8 @@ struct JackTimingMeasure
fCurCycleBegin(0),
fPrevCycleEnd(0)
{}
};
} POST_PACKED_STRUCTURE;
/*!
\brief Client timing monitoring.
......@@ -125,7 +128,7 @@ class SERVER_EXPORT JackEngineProfiling
JackTimingMeasure* GetCurMeasure();
};
} POST_PACKED_STRUCTURE;
} // end of namespace
......
......@@ -93,7 +93,8 @@ class SERVER_EXPORT JackFrameTimer : public JackAtomicState<JackTimer>
void ResetFrameTime(jack_nframes_t frames_rate, jack_time_t callback_usecs, jack_time_t period_usecs);
void IncFrameTime(jack_nframes_t buffer_size, jack_time_t callback_usecs, jack_time_t period_usecs);
void ReadFrameTime(JackTimer* timer);
};
} POST_PACKED_STRUCTURE;
} // end of namespace
......
......@@ -22,13 +22,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "JackPlatformPlug.h"
#include "JackConstants.h"
#include "JackClient.h"
namespace Jack
{
// Globals used for client management on server or libray side.
struct JackGlobals {
static jack_tls_key fRealTime;
......@@ -42,6 +40,11 @@ struct JackGlobals {
};
// Each "side" server and client will implement this to get the shared graph manager, engine control and inter-process synchro table.
extern EXPORT JackGraphManager* GetGraphManager();
extern EXPORT JackEngineControl* GetEngineControl();
extern EXPORT JackSynchro* GetSynchroTable();
} // end of namespace
#endif
......@@ -125,11 +125,10 @@ class SERVER_EXPORT JackGraphManager : public JackShmMem, public JackAtomicState
return &fClientTiming[refnum];
}
void Save(JackConnectionManager* dst);
void Restore(JackConnectionManager* src);
};