diff --git a/ChangeLog b/ChangeLog index 94b97df0..2d11462c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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 + + * Simplify JackClient RT code, jack_thread_wait API marked deprecated." + +2009-03-29 Stephane Letz + + * Cleanup JackInternalClient code. + +2009-03-27 Stephane Letz + + * 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 + + * First working JackBoomerDriver two threads version. + +2009-03-24 Stephane Letz + + * New JackBoomerDriver class for Boomer driver on Solaris. + * Add mixed 32/64 bits mode (off by default). + 2009-03-23 Stephane Letz * Version 1.9.3 started. diff --git a/README b/README index 33e7285d..f11e26f9 100644 --- a/README +++ b/README @@ -1,6 +1,6 @@ --------------------------------------- -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. diff --git a/common/JackAPI.cpp b/common/JackAPI.cpp index fa7b4f22..519cb4c5 100644 --- a/common/JackAPI.cpp +++ b/common/JackAPI.cpp @@ -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; } } diff --git a/common/JackClient.cpp b/common/JackClient.cpp index 3599547e..310b3c78 100644 --- a/common/JackClient.cpp +++ b/common/JackClient.cpp @@ -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; diff --git a/common/JackClient.h b/common/JackClient.h index f9addd6e..f41d734f 100644 --- a/common/JackClient.h +++ b/common/JackClient.h @@ -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 diff --git a/common/JackClientControl.h b/common/JackClientControl.h index 4aa31b0c..a82313c7 100644 --- a/common/JackClientControl.h +++ b/common/JackClientControl.h @@ -79,7 +79,7 @@ struct JackClientControl : public JackShmMemAble fActive = false; } -}; +} POST_PACKED_STRUCTURE; } // end of namespace diff --git a/common/JackConnectionManager.h b/common/JackConnectionManager.h index b95261d6..bb972e31 100644 --- a/common/JackConnectionManager.h +++ b/common/JackConnectionManager.h @@ -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 diff --git a/common/JackConstants.h b/common/JackConstants.h index 71288d11..5d4a136e 100644 --- a/common/JackConstants.h +++ b/common/JackConstants.h @@ -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 diff --git a/common/JackDebugClient.cpp b/common/JackDebugClient.cpp index 3ff29b7d..74566c5e 100644 --- a/common/JackDebugClient.cpp +++ b/common/JackDebugClient.cpp @@ -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 diff --git a/common/JackDebugClient.h b/common/JackDebugClient.h index d8625998..430c9610 100644 --- a/common/JackDebugClient.h +++ b/common/JackDebugClient.h @@ -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; diff --git a/common/JackDriverLoader.cpp b/common/JackDriverLoader.cpp index 79069642..37ac7479 100644 --- a/common/JackDriverLoader.cpp +++ b/common/JackDriverLoader.cpp @@ -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) { diff --git a/common/JackEngine.cpp b/common/JackEngine.cpp index 03d7f91b..16c75589 100644 --- a/common/JackEngine.cpp +++ b/common/JackEngine.cpp @@ -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(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; } diff --git a/common/JackEngineControl.h b/common/JackEngineControl.h index a4e2adcd..5f8b604b 100644 --- a/common/JackEngineControl.h +++ b/common/JackEngineControl.h @@ -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 diff --git a/common/JackEngineProfiling.h b/common/JackEngineProfiling.h index 62c4b86e..c06487a0 100644 --- a/common/JackEngineProfiling.h +++ b/common/JackEngineProfiling.h @@ -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 diff --git a/common/JackFrameTimer.h b/common/JackFrameTimer.h index 703a90be..1468f1b5 100644 --- a/common/JackFrameTimer.h +++ b/common/JackFrameTimer.h @@ -93,7 +93,8 @@ class SERVER_EXPORT JackFrameTimer : public JackAtomicState 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 diff --git a/common/JackGlobals.h b/common/JackGlobals.h index 8495c062..f5516f73 100644 --- a/common/JackGlobals.h +++ b/common/JackGlobals.h @@ -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 diff --git a/common/JackGraphManager.h b/common/JackGraphManager.h index 67d482e7..575e3752 100644 --- a/common/JackGraphManager.h +++ b/common/JackGraphManager.h @@ -125,11 +125,10 @@ class SERVER_EXPORT JackGraphManager : public JackShmMem, public JackAtomicState return &fClientTiming[refnum]; } - void Save(JackConnectionManager* dst); void Restore(JackConnectionManager* src); -}; +} POST_PACKED_STRUCTURE; } // end of namespace diff --git a/common/JackInternalClient.cpp b/common/JackInternalClient.cpp index 45350802..1150a5e9 100644 --- a/common/JackInternalClient.cpp +++ b/common/JackInternalClient.cpp @@ -34,73 +34,21 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. namespace Jack { -#ifdef WIN32 - -static void BuildClientPath(char* path_to_so, int path_len, const char* so_name) -{ - snprintf(path_to_so, path_len, ADDON_DIR "/%s.dll", so_name); -} - -static void PrintLoadError(const char* so_name) -{ - // Retrieve the system error message for the last-error code - LPVOID lpMsgBuf; - LPVOID lpDisplayBuf; - DWORD dw = GetLastError(); - - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - dw, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR) &lpMsgBuf, - 0, NULL ); - - // Display the error message and exit the process - lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, - (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)so_name) + 40) * sizeof(TCHAR)); - _snprintf((LPTSTR)lpDisplayBuf, LocalSize(lpDisplayBuf) / sizeof(TCHAR), - TEXT("error loading %s err = %s"), so_name, lpMsgBuf); - - jack_error((LPCTSTR)lpDisplayBuf); - - LocalFree(lpMsgBuf); - LocalFree(lpDisplayBuf); -} - -#else - -static void BuildClientPath(char* path_to_so, int path_len, const char* so_name) -{ - const char* internal_dir; - if ((internal_dir = getenv("JACK_INTERNAL_DIR")) == 0) { - if ((internal_dir = getenv("JACK_DRIVER_DIR")) == 0) { - internal_dir = ADDON_DIR; - } - } - - snprintf(path_to_so, path_len, "%s/%s.so", internal_dir, so_name); -} - -#endif - JackGraphManager* JackInternalClient::fGraphManager = NULL; JackEngineControl* JackInternalClient::fEngineControl = NULL; // Used for external C API (JackAPI.cpp) -JackGraphManager* GetGraphManager() +EXPORT JackGraphManager* GetGraphManager() { return JackServerGlobals::fInstance->GetGraphManager(); } -JackEngineControl* GetEngineControl() +EXPORT JackEngineControl* GetEngineControl() { return JackServerGlobals::fInstance->GetEngineControl(); } -JackSynchro* GetSynchroTable() +EXPORT JackSynchro* GetSynchroTable() { return JackServerGlobals::fInstance->GetSynchroTable(); } diff --git a/common/JackInternalClient.h b/common/JackInternalClient.h index 1e0d5559..fe398139 100644 --- a/common/JackInternalClient.h +++ b/common/JackInternalClient.h @@ -60,25 +60,6 @@ class JackInternalClient : public JackClient \brief Loadable internal clients in the server. */ -#ifdef WIN32 - -#include -#define HANDLE HINSTANCE -#define LoadJackModule(name) LoadLibrary((name)); -#define UnloadJackModule(handle) FreeLibrary((handle)); -#define GetJackProc(handle, name) GetProcAddress((handle), (name)); - -#else - -#include -#define HANDLE void* -#define LoadJackModule(name) dlopen((name), RTLD_NOW | RTLD_LOCAL); -#define UnloadJackModule(handle) dlclose((handle)); -#define GetJackProc(handle, name) dlsym((handle), (name)); -#define PrintLoadError(so_name) jack_log("error loading %s err = %s", so_name, dlerror()); - -#endif - typedef int (*InitializeCallback)(jack_client_t*, const char*); typedef int (*InternalInitializeCallback)(jack_client_t*, const JSList* params); typedef void (*FinishCallback)(void *); @@ -89,7 +70,7 @@ class JackLoadableInternalClient : public JackInternalClient protected: - HANDLE fHandle; + JACK_HANDLE fHandle; FinishCallback fFinish; JackDriverDescFunction fDescriptor; diff --git a/common/JackLibClient.cpp b/common/JackLibClient.cpp index ed6a0ba1..f65148e9 100644 --- a/common/JackLibClient.cpp +++ b/common/JackLibClient.cpp @@ -106,7 +106,7 @@ int JackLibClient::Open(const char* server_name, const char* name, jack_options_ } SetupDriverSync(false); - + // Connect shared synchro : the synchro must be usable in I/O mode when several clients live in the same process if (!fSynchroTable[GetClientControl()->fRefNum].Connect(name_res, fServerName)) { jack_error("Cannot ConnectSemaphore %s client", name_res); diff --git a/common/JackNetAdapter.cpp b/common/JackNetAdapter.cpp index 7164e637..c1817848 100644 --- a/common/JackNetAdapter.cpp +++ b/common/JackNetAdapter.cpp @@ -226,11 +226,9 @@ namespace Jack SetAdaptedSampleRate ( fParams.fSampleRate ); // Will do "something" on OSX only... - fThread.SetParams(JackServerGlobals::fInstance->GetEngineControl()->fPeriod, - JackServerGlobals::fInstance->GetEngineControl()->fComputation, - JackServerGlobals::fInstance->GetEngineControl()->fConstraint); + fThread.SetParams(GetEngineControl()->fPeriod, GetEngineControl()->fComputation, GetEngineControl()->fConstraint); - if (fThread.AcquireRealTime ( JackServerGlobals::fInstance->GetEngineControl()->fClientPriority ) < 0) { + if (fThread.AcquireRealTime(GetEngineControl()->fClientPriority) < 0) { jack_error("AcquireRealTime error"); } else { set_threaded_log_function(); diff --git a/common/JackNetInterface.cpp b/common/JackNetInterface.cpp index 27495c18..78e9dbb9 100644 --- a/common/JackNetInterface.cpp +++ b/common/JackNetInterface.cpp @@ -329,9 +329,6 @@ namespace Jack jack_error ( "Can't send suicide request : %s", StrError ( NET_ERROR_CODE ) ); mcast_socket.Close(); - - // UGLY temporary way to be sure the thread does not call code possibly causing a deadlock in JackEngine. - ThreadExit(); } int JackNetMasterInterface::Recv ( size_t size, int flags ) @@ -349,6 +346,9 @@ namespace Jack jack_error ( "'%s' : %s, exiting.", fParams.fName, StrError ( NET_ERROR_CODE ) ); //ask to the manager to properly remove the master Exit(); + + // UGLY temporary way to be sure the thread does not call code possibly causing a deadlock in JackEngine. + ThreadExit(); } else jack_error ( "Error in master receive : %s", StrError ( NET_ERROR_CODE ) ); @@ -373,6 +373,9 @@ namespace Jack //fatal connection issue, exit jack_error ( "'%s' : %s, exiting.", fParams.fName, StrError ( NET_ERROR_CODE ) ); Exit(); + + // UGLY temporary way to be sure the thread does not call code possibly causing a deadlock in JackEngine. + ThreadExit(); } else jack_error ( "Error in master send : %s", StrError ( NET_ERROR_CODE ) ); diff --git a/common/JackNetManager.cpp b/common/JackNetManager.cpp index 1b8b9c72..86d23522 100644 --- a/common/JackNetManager.cpp +++ b/common/JackNetManager.cpp @@ -127,7 +127,11 @@ namespace Jack return false; } - jack_set_process_callback ( fJackClient, SetProcess, this ); + if (jack_set_process_callback(fJackClient, SetProcess, this ) < 0) + goto fail; + + if (jack_set_buffer_size_callback(fJackClient, SetBufferSize, this) < 0) + goto fail; if ( AllocPorts() != 0 ) { @@ -334,7 +338,7 @@ namespace Jack if ( jack_transport_reposition ( fJackClient, &fReturnTransportData.fPosition ) == EINVAL ) jack_error ( "Can't set new position." ); jack_transport_start ( fJackClient ); - jack_info ( "'%s' starts transport frame = %d", fParams.fName, fReturnTransportData.fPosition.frame); + jack_info ( "'%s' starts transport frame = %d frame = %d", fParams.fName, fReturnTransportData.fPosition.frame); break; case JackTransportNetStarting : jack_info ( "'%s' is ready to roll..", fParams.fName ); @@ -369,6 +373,13 @@ namespace Jack { return ( fReturnTransportData.fState == JackTransportNetStarting ); } + + int JackNetMaster::SetBufferSize (jack_nframes_t nframes, void* arg) + { + jack_error("Cannot handle bufer size change, so proxy will be removed..."); + static_cast ( arg )->Exit(); + return 0; + } //process----------------------------------------------------------------------------- int JackNetMaster::SetProcess ( jack_nframes_t nframes, void* arg ) diff --git a/common/JackNetManager.h b/common/JackNetManager.h index 6e05759f..b6ad7857 100644 --- a/common/JackNetManager.h +++ b/common/JackNetManager.h @@ -39,6 +39,7 @@ namespace Jack friend class JackNetMasterManager; private: static int SetProcess ( jack_nframes_t nframes, void* arg ); + static int SetBufferSize (jack_nframes_t nframes, void* arg); static void SetTimebaseCallback ( jack_transport_state_t state, jack_nframes_t nframes, jack_position_t* pos, int new_pos, void* arg ); //jack client @@ -63,8 +64,7 @@ namespace Jack bool Init(bool auto_connect); int AllocPorts(); void FreePorts(); - void Exit(); - + //transport void EncodeTransportData(); void DecodeTransportData(); diff --git a/common/JackPort.cpp b/common/JackPort.cpp index 2afec24b..42b5fb2e 100644 --- a/common/JackPort.cpp +++ b/common/JackPort.cpp @@ -109,12 +109,12 @@ int JackPort::RequestMonitor(bool onoff) { /** jackd.h - * If @ref JackPortCanMonitor is set for this @a port, turn input - * monitoring on or off. Otherwise, do nothing. + * If @ref JackPortCanMonitor is set for this @a port, turn input + * monitoring on or off. Otherwise, do nothing. - if (!(fFlags & JackPortCanMonitor)) + if (!(fFlags & JackPortCanMonitor)) return -1; - */ + */ if (onoff) { fMonitorRequests++; @@ -129,12 +129,12 @@ int JackPort::EnsureMonitor(bool onoff) { /** jackd.h - * If @ref JackPortCanMonitor is set for this @a port, turn input - * monitoring on or off. Otherwise, do nothing. + * If @ref JackPortCanMonitor is set for this @a port, turn input + * monitoring on or off. Otherwise, do nothing. - if (!(fFlags & JackPortCanMonitor)) + if (!(fFlags & JackPortCanMonitor)) return -1; - */ + */ if (onoff) { if (fMonitorRequests == 0) { @@ -247,13 +247,13 @@ int JackPort::UnsetAlias(const char* alias) void JackPort::ClearBuffer(jack_nframes_t frames) { const JackPortType* type = GetPortType(fTypeId); - (type->init)(fBuffer, frames * sizeof(float), frames); + (type->init)(GetBuffer(), frames * sizeof(float), frames); } void JackPort::MixBuffers(void** src_buffers, int src_count, jack_nframes_t buffer_size) { const JackPortType* type = GetPortType(fTypeId); - (type->mixdown)(fBuffer, src_buffers, src_count, buffer_size); + (type->mixdown)(GetBuffer(), src_buffers, src_count, buffer_size); } } // end of namespace diff --git a/common/JackPort.h b/common/JackPort.h index 4951ffa9..45f90733 100644 --- a/common/JackPort.h +++ b/common/JackPort.h @@ -55,9 +55,8 @@ class SERVER_EXPORT JackPort bool fInUse; jack_port_id_t fTied; // Locally tied source port - - MEM_ALIGN(float fBuffer[BUFFER_SIZE_MAX], 64); // 16 bytes alignment for vector code, 64 bytes better for cache loads/stores - + float fBuffer[BUFFER_SIZE_MAX + 4]; + bool IsUsed() const { return fInUse; @@ -99,14 +98,15 @@ class SERVER_EXPORT JackPort return (fMonitorRequests > 0); } + // Since we are in shared memory, the resulting pointer cannot be cached, so align it here... float* GetBuffer() { - return fBuffer; + return (float*)((long)fBuffer & ~15L) + 4; } int GetRefNum() const; -}; - + +} POST_PACKED_STRUCTURE; } // end of namespace diff --git a/common/JackRequest.h b/common/JackRequest.h index 03cfea4f..e6243b7b 100644 --- a/common/JackRequest.h +++ b/common/JackRequest.h @@ -116,6 +116,7 @@ struct JackResult { return trans->Write(&fResult, sizeof(int)); } + }; /*! @@ -151,7 +152,8 @@ struct JackClientCheckRequest : public JackRequest CheckRes(trans->Write(&fProtocol, sizeof(int))); return trans->Write(&fOptions, sizeof(int)); } -}; + +} POST_PACKED_STRUCTURE; /*! \brief CheckClient result. @@ -186,7 +188,8 @@ struct JackClientCheckResult : public JackResult CheckRes(trans->Write(&fStatus, sizeof(int))); return 0; } -}; + +} POST_PACKED_STRUCTURE; /*! \brief NewClient request. @@ -218,7 +221,8 @@ struct JackClientOpenRequest : public JackRequest CheckRes(trans->Write(&fPID, sizeof(int))); return trans->Write(&fName, JACK_CLIENT_NAME_SIZE + 1); } -}; + +} POST_PACKED_STRUCTURE; /*! \brief NewClient result. @@ -255,7 +259,8 @@ struct JackClientOpenResult : public JackResult CheckRes(trans->Write(&fSharedGraph, sizeof(int))); return 0; } -}; + +} POST_PACKED_STRUCTURE; /*! \brief CloseClient request. @@ -281,7 +286,8 @@ struct JackClientCloseRequest : public JackRequest CheckRes(JackRequest::Write(trans)); return trans->Write(&fRefNum, sizeof(int)); } -}; + +} POST_PACKED_STRUCTURE; /*! \brief Activate request. @@ -312,7 +318,7 @@ struct JackActivateRequest : public JackRequest return trans->Write(&fState, sizeof(int)); } -}; +} POST_PACKED_STRUCTURE; /*! \brief Deactivate request. @@ -339,7 +345,7 @@ struct JackDeactivateRequest : public JackRequest return trans->Write(&fRefNum, sizeof(int)); } -}; +} POST_PACKED_STRUCTURE; /*! \brief PortRegister request. @@ -383,7 +389,8 @@ struct JackPortRegisterRequest : public JackRequest CheckRes(trans->Write(&fBufferSize, sizeof(unsigned int))); return 0; } -}; + +} POST_PACKED_STRUCTURE; /*! \brief PortRegister result. @@ -408,7 +415,8 @@ struct JackPortRegisterResult : public JackResult CheckRes(JackResult::Write(trans)); return trans->Write(&fPortIndex, sizeof(jack_port_id_t)); } -}; + +} POST_PACKED_STRUCTURE; /*! \brief PortUnregister request. @@ -440,7 +448,8 @@ struct JackPortUnRegisterRequest : public JackRequest CheckRes(trans->Write(&fPortIndex, sizeof(jack_port_id_t))); return 0; } -}; + +} POST_PACKED_STRUCTURE; /*! \brief PortConnectName request. @@ -479,7 +488,8 @@ struct JackPortConnectNameRequest : public JackRequest CheckRes(trans->Write(&fDst, JACK_PORT_NAME_SIZE + 1)); return 0; } -}; + +} POST_PACKED_STRUCTURE; /*! \brief PortDisconnectName request. @@ -517,7 +527,8 @@ struct JackPortDisconnectNameRequest : public JackRequest CheckRes(trans->Write(&fDst, JACK_PORT_NAME_SIZE + 1)); return 0; } -}; + +} POST_PACKED_STRUCTURE; /*! \brief PortConnect request. @@ -552,8 +563,8 @@ struct JackPortConnectRequest : public JackRequest CheckRes(trans->Write(&fDst, sizeof(jack_port_id_t))); return 0; } -}; - + +} POST_PACKED_STRUCTURE; /*! \brief PortDisconnect request. @@ -589,7 +600,8 @@ struct JackPortDisconnectRequest : public JackRequest return 0; } -}; + +} POST_PACKED_STRUCTURE; /*! \brief PortRename request. @@ -627,7 +639,8 @@ struct JackPortRenameRequest : public JackRequest return 0; } -}; + +} POST_PACKED_STRUCTURE; /*! \brief SetBufferSize request. @@ -654,7 +667,8 @@ struct JackSetBufferSizeRequest : public JackRequest CheckRes(JackRequest::Write(trans)); return trans->Write(&fBufferSize, sizeof(jack_nframes_t)); } -}; + +} POST_PACKED_STRUCTURE; /*! \brief SetFreeWheel request. @@ -681,7 +695,8 @@ struct JackSetFreeWheelRequest : public JackRequest CheckRes(JackRequest::Write(trans)); return trans->Write(&fOnOff, sizeof(int)); } -}; + +} POST_PACKED_STRUCTURE; /*! \brief ReleaseTimebase request. @@ -708,7 +723,8 @@ struct JackReleaseTimebaseRequest : public JackRequest CheckRes(JackRequest::Write(trans)); return trans->Write(&fRefNum, sizeof(int)); } -}; + +} POST_PACKED_STRUCTURE; /*! \brief SetTimebaseCallback request. @@ -738,7 +754,8 @@ struct JackSetTimebaseCallbackRequest : public JackRequest CheckRes(trans->Write(&fRefNum, sizeof(int))); return trans->Write(&fConditionnal, sizeof(int)); } -}; + +} POST_PACKED_STRUCTURE; /*! \brief GetInternalClientName request. @@ -768,7 +785,8 @@ struct JackGetInternalClientNameRequest : public JackRequest CheckRes(trans->Write(&fRefNum, sizeof(int))); return trans->Write(&fIntRefNum, sizeof(int)); } -}; + +} POST_PACKED_STRUCTURE; /*! \brief GetInternalClient result. @@ -800,7 +818,8 @@ struct JackGetInternalClientNameResult : public JackResult CheckRes(trans->Write(&fName, JACK_CLIENT_NAME_SIZE + 1)); return 0; } -}; + +} POST_PACKED_STRUCTURE; /*! \brief InternalClientHandle request. @@ -832,7 +851,8 @@ struct JackInternalClientHandleRequest : public JackRequest CheckRes(trans->Write(&fRefNum, sizeof(int))); return trans->Write(&fName, JACK_CLIENT_NAME_SIZE + 1); } -}; + +} POST_PACKED_STRUCTURE; /*! \brief InternalClientHandle result. @@ -865,7 +885,8 @@ struct JackInternalClientHandleResult : public JackResult CheckRes(trans->Write(&fIntRefNum, sizeof(int))); return 0; } -}; + +} POST_PACKED_STRUCTURE; /*! \brief InternalClientLoad request. @@ -912,7 +933,8 @@ struct JackInternalClientLoadRequest : public JackRequest CheckRes(trans->Write(&fLoadInitName, JACK_LOAD_INIT_LIMIT + 1)); return trans->Write(&fOptions, sizeof(int)); } -}; + +} POST_PACKED_STRUCTURE; /*! \brief InternalClientLoad result. @@ -945,7 +967,8 @@ struct JackInternalClientLoadResult : public JackResult CheckRes(trans->Write(&fIntRefNum, sizeof(int))); return 0; } -}; + +} POST_PACKED_STRUCTURE; /*! \brief InternalClientUnload request. @@ -975,8 +998,7 @@ struct JackInternalClientUnloadRequest : public JackRequest CheckRes(trans->Write(&fRefNum, sizeof(int))); return trans->Write(&fIntRefNum, sizeof(int)); } -}; - +} POST_PACKED_STRUCTURE; /*! \brief InternalClientLoad result. @@ -1006,7 +1028,8 @@ struct JackInternalClientUnloadResult : public JackResult CheckRes(trans->Write(&fStatus, sizeof(int))); return 0; } -}; + +} POST_PACKED_STRUCTURE; /*! \brief ClientNotification request. @@ -1042,7 +1065,7 @@ struct JackClientNotificationRequest : public JackRequest return 0; } -}; +} POST_PACKED_STRUCTURE; /*! \brief ClientNotification. @@ -1087,7 +1110,7 @@ struct JackClientNotification return 0; } -}; +} POST_PACKED_STRUCTURE; } // end of namespace diff --git a/common/JackShmMem.cpp b/common/JackShmMem.cpp index a6ec3159..5d68b86e 100644 --- a/common/JackShmMem.cpp +++ b/common/JackShmMem.cpp @@ -37,7 +37,7 @@ JackShmMem::JackShmMem() void JackShmMemAble::Init() { fInfo.index = gInfo.index; - fInfo.attached_at = gInfo.attached_at; + fInfo.ptr.attached_at = gInfo.ptr.attached_at; fInfo.size = gInfo.size; } @@ -71,9 +71,9 @@ void* JackShmMem::operator new(size_t size) // so use an intermediate global data gInfo.index = info.index; gInfo.size = size; - gInfo.attached_at = info.attached_at; + gInfo.ptr.attached_at = info.ptr.attached_at; - jack_log("JackShmMem::new index = %ld attached = %x size = %ld ", info.index, info.attached_at, size); + jack_log("JackShmMem::new index = %ld attached = %x size = %ld ", info.index, info.ptr.attached_at, size); return obj; error: @@ -86,7 +86,7 @@ void JackShmMem::operator delete(void* p, size_t size) jack_shm_info_t info; JackShmMem* obj = (JackShmMem*)p; info.index = obj->fInfo.index; - info.attached_at = obj->fInfo.attached_at; + info.ptr.attached_at = obj->fInfo.ptr.attached_at; jack_log("JackShmMem::delete size = %ld index = %ld", size, info.index); diff --git a/common/JackShmMem.h b/common/JackShmMem.h index 6a6261a2..5976c96d 100644 --- a/common/JackShmMem.h +++ b/common/JackShmMem.h @@ -102,7 +102,7 @@ class JackShmMemAble char* GetShmAddress() { - return (char*)fInfo.attached_at; + return (char*)fInfo.ptr.attached_at; } void LockMemory() @@ -173,7 +173,7 @@ class JackShmReadWritePtr JackShmReadWritePtr() { fInfo.index = -1; - fInfo.attached_at = NULL; + fInfo.ptr.attached_at = (char*)NULL; } JackShmReadWritePtr(int index, const char* server_name) @@ -192,12 +192,12 @@ class JackShmReadWritePtr T* operator->() const { - return (T*)fInfo.attached_at; + return (T*)fInfo.ptr.attached_at; } operator T*() const { - return (T*)fInfo.attached_at; + return (T*)fInfo.ptr.attached_at; } JackShmReadWritePtr& operator=(int index) @@ -218,7 +218,7 @@ class JackShmReadWritePtr T* GetShmAddress() { - return (T*)fInfo.attached_at; + return (T*)fInfo.ptr.attached_at; } }; @@ -259,7 +259,7 @@ class JackShmReadWritePtr1 JackShmReadWritePtr1() { fInfo.index = -1; - fInfo.attached_at = NULL; + fInfo.ptr.attached_at = NULL; } JackShmReadWritePtr1(int index, const char* server_name) @@ -278,12 +278,12 @@ class JackShmReadWritePtr1 T* operator->() const { - return (T*)fInfo.attached_at; + return (T*)fInfo.ptr.attached_at; } operator T*() const { - return (T*)fInfo.attached_at; + return (T*)fInfo.ptr.attached_at; } JackShmReadWritePtr1& operator=(int index) @@ -304,7 +304,7 @@ class JackShmReadWritePtr1 T* GetShmAddress() { - return (T*)fInfo.attached_at; + return (T*)fInfo.ptr.attached_at; } }; @@ -339,7 +339,7 @@ class JackShmReadPtr JackShmReadPtr() { fInfo.index = -1; - fInfo.attached_at = NULL; + fInfo.ptr.attached_at = NULL; } JackShmReadPtr(int index, const char* server_name) @@ -358,12 +358,12 @@ class JackShmReadPtr T* operator->() const { - return (T*)fInfo.attached_at; + return (T*)fInfo.ptr.attached_at; } operator T*() const { - return (T*)fInfo.attached_at; + return (T*)fInfo.ptr.attached_at; } JackShmReadPtr& operator=(int index) @@ -384,7 +384,7 @@ class JackShmReadPtr T* GetShmAddress() { - return (T*)fInfo.attached_at; + return (T*)fInfo.ptr.attached_at; } }; diff --git a/common/JackThreadedDriver.cpp b/common/JackThreadedDriver.cpp index 590d9575..45fb1dc9 100644 --- a/common/JackThreadedDriver.cpp +++ b/common/JackThreadedDriver.cpp @@ -22,7 +22,6 @@ #include "JackThreadedDriver.h" #include "JackError.h" #include "JackGlobals.h" -#include "JackClient.h" #include "JackEngineControl.h" namespace Jack diff --git a/common/JackTools.cpp b/common/JackTools.cpp index 75209ede..cc8c67c3 100644 --- a/common/JackTools.cpp +++ b/common/JackTools.cpp @@ -212,6 +212,63 @@ namespace Jack { } new_name[i] = '\0'; } + +#ifdef WIN32 + +void BuildClientPath(char* path_to_so, int path_len, const char* so_name) +{ + snprintf(path_to_so, path_len, ADDON_DIR "/%s.dll", so_name); +} + +void PrintLoadError(const char* so_name) +{ + // Retrieve the system error message for the last-error code + LPVOID lpMsgBuf; + LPVOID lpDisplayBuf; + DWORD dw = GetLastError(); + + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + dw, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf, + 0, NULL ); + + // Display the error message and exit the process + lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, + (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)so_name) + 40) * sizeof(TCHAR)); + _snprintf((LPTSTR)lpDisplayBuf, LocalSize(lpDisplayBuf) / sizeof(TCHAR), + TEXT("error loading %s err = %s"), so_name, lpMsgBuf); + + jack_error((LPCTSTR)lpDisplayBuf); + + LocalFree(lpMsgBuf); + LocalFree(lpDisplayBuf); +} + +#else +void PrintLoadError(const char* so_name) +{ + jack_log("error loading %s err = %s", so_name, dlerror()); } +void BuildClientPath(char* path_to_so, int path_len, const char* so_name) +{ + const char* internal_dir; + if ((internal_dir = getenv("JACK_INTERNAL_DIR")) == 0) { + if ((internal_dir = getenv("JACK_DRIVER_DIR")) == 0) { + internal_dir = ADDON_DIR; + } + } + + snprintf(path_to_so, path_len, "%s/%s.so", internal_dir, so_name); +} + +#endif + +} // end of namespace + diff --git a/common/JackTools.h b/common/JackTools.h index 9f3cb5fa..820f91ba 100644 --- a/common/JackTools.h +++ b/common/JackTools.h @@ -201,6 +201,10 @@ namespace Jack return 0; } }; + + void BuildClientPath(char* path_to_so, int path_len, const char* so_name); + void PrintLoadError(const char* so_name); + } #endif diff --git a/common/JackTransportEngine.cpp b/common/JackTransportEngine.cpp index 66f96cf2..b0d100dc 100644 --- a/common/JackTransportEngine.cpp +++ b/common/JackTransportEngine.cpp @@ -174,29 +174,29 @@ void JackTransportEngine::CycleEnd(JackClientInterface** table, jack_nframes_t f case JackTransportStopped: // Set a JackTransportStarting for the current cycle, if all clients are ready (no slow_sync) ==> JackTransportRolling next state if (cmd == TransportCommandStart) { - jack_log("transport stopped ==> starting"); + jack_log("transport stopped ==> starting frame = %d", ReadCurrentState()->frame); fTransportState = JackTransportStarting; MakeAllStartingLocating(table); SyncTimeout(frame_rate, buffer_size); } else if (fPendingPos) { - jack_log("transport stopped ==> stopped (locating)"); + jack_log("transport stopped ==> stopped (locating) frame = %d", ReadCurrentState()->frame); MakeAllLocating(table); } break; case JackTransportStarting: if (cmd == TransportCommandStop) { - jack_log("transport starting ==> stopped"); + jack_log("transport starting ==> stopped frame = %d", ReadCurrentState()->frame); fTransportState = JackTransportStopped; MakeAllStopping(table); } else if (fPendingPos) { - jack_log("transport starting ==> starting"); + jack_log("transport starting ==> starting frame = %d"), ReadCurrentState()->frame; fTransportState = JackTransportStarting; MakeAllStartingLocating(table); SyncTimeout(frame_rate, buffer_size); } else if (--fSyncTimeLeft == 0 || CheckAllRolling(table)) { // Slow clients may still catch up if (fNetworkSync) { - jack_log("transport starting ==> netstarting"); + jack_log("transport starting ==> netstarting frame = %d"); fTransportState = JackTransportNetStarting; } else { jack_log("transport starting ==> rolling fSyncTimeLeft = %ld", fSyncTimeLeft); diff --git a/common/JackTransportEngine.h b/common/JackTransportEngine.h index 9602516d..2adac8b1 100644 --- a/common/JackTransportEngine.h +++ b/common/JackTransportEngine.h @@ -193,7 +193,7 @@ class SERVER_EXPORT JackTransportEngine : public JackAtomicArrayState +#include +#include #else #include @@ -57,7 +58,7 @@ #include "shm.h" #include "JackError.h" -static int GetUID() +static int GetUID() { #ifdef WIN32 return _getpid(); @@ -67,7 +68,7 @@ static int GetUID() #endif } -static int GetPID() +static int GetPID() { #ifdef WIN32 return _getpid(); @@ -105,13 +106,13 @@ static jack_shm_id_t registry_id; /* SHM id for the registry */ #ifdef WIN32 static jack_shm_info_t registry_info = {/* SHM info for the registry */ - JACK_SHM_NULL_INDEX, + JACK_SHM_NULL_INDEX, NULL -}; +}; #else static jack_shm_info_t registry_info = { /* SHM info for the registry */ .index = JACK_SHM_NULL_INDEX, - .attached_at = MAP_FAILED + .ptr.attached_at = MAP_FAILED }; #endif @@ -142,7 +143,7 @@ static char jack_shm_server_prefix[JACK_SERVER_NAME_SIZE] = ""; static int semid = -1; -#ifdef WIN32 +#ifdef WIN32 static void semaphore_init () {} @@ -167,7 +168,7 @@ semaphore_init () struct sembuf sbuf; int create_flags = IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; - + /* Get semaphore ID associated with this key. */ if ((semid = semget(semkey, 0, 0)) == -1) { @@ -188,7 +189,7 @@ semaphore_init () } } else { - semaphore_error ("semget creation"); + semaphore_error ("semget creation"); } } } @@ -208,7 +209,7 @@ semaphore_add (int value) #endif -static void +static void jack_shm_lock_registry (void) { if (semid == -1) @@ -217,7 +218,7 @@ jack_shm_lock_registry (void) semaphore_add (-1); } -static void +static void jack_shm_unlock_registry (void) { semaphore_add (1); @@ -232,7 +233,7 @@ jack_shm_init_registry () memset (jack_shm_header, 0, JACK_SHM_REGISTRY_SIZE); jack_shm_header->magic = JACK_SHM_MAGIC; - //jack_shm_header->protocol = JACK_PROTOCOL_VERSION; + //jack_shm_header->protocol = JACK_PROTOCOL_VERSION; jack_shm_header->type = jack_shmtype; jack_shm_header->size = JACK_SHM_REGISTRY_SIZE; jack_shm_header->hdr_len = sizeof (jack_shm_header_t); @@ -249,7 +250,7 @@ jack_shm_validate_registry () /* registry must be locked */ if ((jack_shm_header->magic == JACK_SHM_MAGIC) - //&& (jack_shm_header->protocol == JACK_PROTOCOL_VERSION) + //&& (jack_shm_header->protocol == JACK_PROTOCOL_VERSION) && (jack_shm_header->type == jack_shmtype) && (jack_shm_header->size == JACK_SHM_REGISTRY_SIZE) && (jack_shm_header->hdr_len == sizeof (jack_shm_header_t)) @@ -281,7 +282,7 @@ static void jack_set_server_prefix (const char *server_name) { snprintf (jack_shm_server_prefix, sizeof (jack_shm_server_prefix), - "jack-%d:%s:", GetUID(), server_name); + "jack-%d:%s:", GetUID(), server_name); } /* gain server addressability to shared memory registration segment @@ -299,7 +300,7 @@ jack_server_initialize_shm (int new_registry) jack_shm_lock_registry (); rc = jack_access_registry (®istry_info); - + if (new_registry) { jack_remove_shm (®istry_id); rc = ENOENT; @@ -365,9 +366,9 @@ jack_initialize_shm (const char *server_name) } -char* jack_shm_addr (jack_shm_info_t* si) +char* jack_shm_addr (jack_shm_info_t* si) { - return (char*)si->attached_at; + return (char*)si->ptr.attached_at; } void @@ -393,7 +394,7 @@ jack_get_free_shm_info () break; } } - + if (i < MAX_SHM_ID) { si = &jack_shm_registry[i]; } @@ -422,7 +423,7 @@ jack_release_shm_info (jack_shm_registry_index_t index) } } -/* Claim server_name for this process. +/* Claim server_name for this process. * * returns 0 if successful * EEXIST if server_name was already active for this user @@ -485,7 +486,7 @@ jack_register_server (const char *server_name, int new_registry) strncpy (jack_shm_header->server[i].name, jack_shm_server_prefix, JACK_SERVER_NAME_SIZE); - + unlock: jack_shm_unlock_registry (); return 0; @@ -517,10 +518,10 @@ jack_cleanup_shm () jack_shm_info_t copy; jack_shm_lock_registry (); - + for (i = 0; i < MAX_SHM_ID; i++) { jack_shm_registry_t* r; - + r = &jack_shm_registry[i]; memcpy (©, r, sizeof (jack_shm_info_t)); destroy = FALSE; @@ -532,7 +533,7 @@ jack_cleanup_shm () /* is this my shm segment? */ if (r->allocator == GetPID()) { - /* allocated by this process, so unattach + /* allocated by this process, so unattach and destroy. */ jack_release_shm (©); destroy = TRUE; @@ -638,7 +639,7 @@ jack_access_registry (jack_shm_info_t *ri) return rc; } - if ((ri->attached_at = mmap (0, JACK_SHM_REGISTRY_SIZE, + if ((ri->ptr.attached_at = mmap (0, JACK_SHM_REGISTRY_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, shm_fd, 0)) == MAP_FAILED) { jack_error ("Cannot mmap shm registry segment (%s)", @@ -649,9 +650,9 @@ jack_access_registry (jack_shm_info_t *ri) /* set up global pointers */ ri->index = JACK_SHM_REGISTRY_INDEX; - jack_shm_header = ri->attached_at; + jack_shm_header = ri->ptr.attached_at; jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1); - + close (shm_fd); // steph return 0; } @@ -668,7 +669,7 @@ jack_create_registry (jack_shm_info_t *ri) { /* registry must be locked */ int shm_fd; - + strncpy (registry_id, "/jack-shm-registry", sizeof (registry_id)); if ((shm_fd = shm_open (registry_id, O_RDWR|O_CREAT, 0666)) < 0) { @@ -677,10 +678,10 @@ jack_create_registry (jack_shm_info_t *ri) strerror (errno)); return rc; } - + /* Previous shm_open result depends of the actual value of umask, force correct file permisssion here */ if (fchmod(shm_fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) < 0) { - jack_log("Cannot chmod jack-shm-registry (%s) %d %d", strerror (errno)); + jack_log("Cannot chmod jack-shm-registry (%s) %d %d", strerror (errno)); } /* Set the desired segment size. NOTE: the non-conformant Mac @@ -694,7 +695,7 @@ jack_create_registry (jack_shm_info_t *ri) return rc; } - if ((ri->attached_at = mmap (0, JACK_SHM_REGISTRY_SIZE, + if ((ri->ptr.attached_at = mmap (0, JACK_SHM_REGISTRY_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, shm_fd, 0)) == MAP_FAILED) { jack_error ("Cannot mmap shm registry segment (%s)", @@ -706,7 +707,7 @@ jack_create_registry (jack_shm_info_t *ri) /* set up global pointers */ ri->index = JACK_SHM_REGISTRY_INDEX; - jack_shm_header = ri->attached_at; + jack_shm_header = ri->ptr.attached_at; jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1); /* initialize registry contents */ @@ -726,8 +727,8 @@ void jack_release_shm (jack_shm_info_t* si) { /* registry may or may not be locked */ - if (si->attached_at != MAP_FAILED) { - munmap (si->attached_at, jack_shm_registry[si->index].size); + if (si->ptr.attached_at != MAP_FAILED) { + munmap (si->ptr.attached_at, jack_shm_registry[si->index].size); } } @@ -781,7 +782,7 @@ jack_shmalloc (const char *shm_name, jack_shmsize_t size, jack_shm_info_t* si) strncpy (registry->id, name, sizeof (registry->id)); registry->allocator = getpid(); si->index = registry->index; - si->attached_at = MAP_FAILED; /* not attached */ + si->ptr.attached_at = MAP_FAILED; /* not attached */ rc = 0; /* success */ unlock: @@ -802,9 +803,9 @@ jack_attach_shm (jack_shm_info_t* si) return -1; } - if ((si->attached_at = mmap (0, registry->size, PROT_READ|PROT_WRITE, + if ((si->ptr.attached_at = mmap (0, registry->size, PROT_READ|PROT_WRITE, MAP_SHARED, shm_fd, 0)) == MAP_FAILED) { - jack_error ("Cannot mmap shm segment %s (%s)", + jack_error ("Cannot mmap shm segment %s (%s)", registry->id, strerror (errno)); close (shm_fd); @@ -828,9 +829,9 @@ jack_attach_shm_read (jack_shm_info_t* si) return -1; } - if ((si->attached_at = mmap (0, registry->size, PROT_READ, + if ((si->ptr.attached_at = mmap (0, registry->size, PROT_READ, MAP_SHARED, shm_fd, 0)) == MAP_FAILED) { - jack_error ("Cannot mmap shm segment %s (%s)", + jack_error ("Cannot mmap shm segment %s (%s)", registry->id, strerror (errno)); close (shm_fd); @@ -848,12 +849,10 @@ jack_access_registry (jack_shm_info_t *ri) { /* registry must be locked */ HANDLE shm_fd; - LPSECURITY_ATTRIBUTES sec = 0; - strncpy (registry_id, "jack-shm-registry", sizeof (registry_id)); /* try to open an existing segment */ - + if ((shm_fd = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, registry_id)) == NULL) { int rc = GetLastError(); if (rc != ERROR_FILE_NOT_FOUND) { @@ -862,7 +861,7 @@ jack_access_registry (jack_shm_info_t *ri) return rc; } - if ((ri->attached_at = MapViewOfFile (shm_fd, FILE_MAP_ALL_ACCESS, 0, 0, JACK_SHM_REGISTRY_SIZE)) == NULL) { + if ((ri->ptr.attached_at = MapViewOfFile (shm_fd, FILE_MAP_ALL_ACCESS, 0, 0, JACK_SHM_REGISTRY_SIZE)) == NULL) { jack_error ("Cannot mmap shm registry segment (%ld)", GetLastError()); jack_remove_shm (®istry_id); CloseHandle (shm_fd); @@ -871,7 +870,7 @@ jack_access_registry (jack_shm_info_t *ri) /* set up global pointers */ ri->index = JACK_SHM_REGISTRY_INDEX; - jack_shm_header = ri->attached_at; + jack_shm_header = ri->ptr.attached_at; jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1); //CloseHandle(shm_fd); // TO CHECK @@ -886,16 +885,16 @@ jack_create_registry (jack_shm_info_t *ri) strncpy (registry_id, "jack-shm-registry", sizeof (registry_id)); - if ((shm_fd = CreateFileMapping(INVALID_HANDLE_VALUE, - 0, PAGE_READWRITE, - 0, JACK_SHM_REGISTRY_SIZE, + if ((shm_fd = CreateFileMapping(INVALID_HANDLE_VALUE, + 0, PAGE_READWRITE, + 0, JACK_SHM_REGISTRY_SIZE, registry_id)) == NULL || (shm_fd == INVALID_HANDLE_VALUE)) { int rc = GetLastError(); jack_error ("Cannot create shm registry segment (%ld)", rc); return rc; } - if ((ri->attached_at = MapViewOfFile (shm_fd, FILE_MAP_ALL_ACCESS, 0, 0, JACK_SHM_REGISTRY_SIZE)) == NULL) { + if ((ri->ptr.attached_at = MapViewOfFile (shm_fd, FILE_MAP_ALL_ACCESS, 0, 0, JACK_SHM_REGISTRY_SIZE)) == NULL) { jack_error ("Cannot mmap shm registry segment (%ld)", GetLastError()); jack_remove_shm (®istry_id); CloseHandle (shm_fd); @@ -904,7 +903,7 @@ jack_create_registry (jack_shm_info_t *ri) /* set up global pointers */ ri->index = JACK_SHM_REGISTRY_INDEX; - jack_shm_header = ri->attached_at; + jack_shm_header = ri->ptr.attached_at; jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1); /* initialize registry contents */ @@ -924,8 +923,8 @@ void jack_release_shm (jack_shm_info_t* si) { /* registry may or may not be locked */ - if (si->attached_at != NULL) { - UnmapViewOfFile (si->attached_at); + if (si->ptr.attached_at != NULL) { + UnmapViewOfFile (si->ptr.attached_at); } } @@ -951,9 +950,9 @@ jack_shmalloc (const char *shm_name, jack_shmsize_t size, jack_shm_info_t* si) goto unlock; } - if ((shm_fd = CreateFileMapping(INVALID_HANDLE_VALUE, - 0, PAGE_READWRITE, - 0, size, + if ((shm_fd = CreateFileMapping(INVALID_HANDLE_VALUE, + 0, PAGE_READWRITE, + 0, size, name)) == NULL || (shm_fd == INVALID_HANDLE_VALUE)) { int rc = GetLastError(); jack_error ("Cannot create shm segment (%ld)",rc); @@ -966,7 +965,7 @@ jack_shmalloc (const char *shm_name, jack_shmsize_t size, jack_shm_info_t* si) strncpy (registry->id, name, sizeof (registry->id)); registry->allocator = _getpid(); si->index = registry->index; - si->attached_at = NULL; /* not attached */ + si->ptr.attached_at = NULL; /* not attached */ rc = 0; /* success */ unlock: @@ -986,7 +985,7 @@ jack_attach_shm (jack_shm_info_t* si) return -1; } - if ((si->attached_at = MapViewOfFile (shm_fd, FILE_MAP_ALL_ACCESS, 0, 0, registry->size)) == NULL) { + if ((si->ptr.attached_at = MapViewOfFile (shm_fd, FILE_MAP_ALL_ACCESS, 0, 0, registry->size)) == NULL) { jack_error ("Cannot mmap shm segment (%ld)", GetLastError()); jack_remove_shm (®istry_id); CloseHandle (shm_fd); @@ -1009,10 +1008,10 @@ jack_attach_shm_read (jack_shm_info_t* si) return -1; } - if ((si->attached_at = MapViewOfFile (shm_fd, FILE_MAP_READ, 0, 0, registry->size)) == NULL) { - jack_error ("Cannot mmap shm segment (%ld)", GetLastError()); - jack_remove_shm (®istry_id); - CloseHandle (shm_fd); + if ((si->ptr.attached_at = MapViewOfFile (shm_fd, FILE_MAP_READ, 0, 0, registry->size)) == NULL) { + jack_error("Cannot mmap shm segment (%ld)", GetLastError()); + jack_remove_shm(®istry_id); + CloseHandle(shm_fd); return -1; } @@ -1127,7 +1126,7 @@ jack_release_shm (jack_shm_info_t* si) int jack_shmalloc (const char* name_not_used, jack_shmsize_t size, - jack_shm_info_t* si) + jack_shm_info_t* si) { int shmflags; int shmid; diff --git a/common/shm.h b/common/shm.h index a3d9f34f..4a7d15c6 100644 --- a/common/shm.h +++ b/common/shm.h @@ -35,15 +35,15 @@ extern "C" #ifndef SHM_NAME_MAX #define SHM_NAME_MAX NAME_MAX #endif - typedef char shm_name_t[SHM_NAME_MAX]; + typedef char shm_name_t[SHM_NAME_MAX]; typedef shm_name_t jack_shm_id_t; -#elif WIN32 // steph TO CHECK +#elif WIN32 // TO CHECK #define NAME_MAX 255 #ifndef SHM_NAME_MAX #define SHM_NAME_MAX NAME_MAX #endif - typedef char shm_name_t[SHM_NAME_MAX]; + typedef char shm_name_t[SHM_NAME_MAX]; typedef shm_name_t jack_shm_id_t; #else @@ -73,7 +73,6 @@ extern "C" #ifdef WIN32 int pid; /* process ID */ #else - pid_t pid; /* process ID */ #endif @@ -96,10 +95,8 @@ extern "C" jack_shm_registry_index_t index; /* offset into the registry */ #ifdef WIN32 - int allocator; /* PID that created shm segment */ #else - pid_t allocator; /* PID that created shm segment */ #endif @@ -118,12 +115,16 @@ extern "C" * indicating where the shared memory has been * attached to the address space. */ + typedef struct _jack_shm_info { jack_shm_registry_index_t index; /* offset into the registry */ - size_t size; - void *attached_at; /* address where attached */ + uint32_t size; + union { + void *attached_at; /* address where attached */ + char ptr_size[8]; + } ptr; /* a "pointer" that has the same 8 bytes size when compling in 32 or 64 bits */ } - jack_shm_info_t; + POST_PACKED_STRUCTURE jack_shm_info_t; /* utility functions used only within JACK */ @@ -132,15 +133,15 @@ extern "C" void jack_shm_copy_to_registry (jack_shm_info_t*, jack_shm_registry_index_t*); void jack_release_shm_info (jack_shm_registry_index_t); - char* jack_shm_addr (jack_shm_info_t* si); // steph + char* jack_shm_addr (jack_shm_info_t* si); // here begin the API int jack_register_server (const char *server_name, int new_registry); void jack_unregister_server (const char *server_name); int jack_initialize_shm (const char *server_name); - int jack_initialize_shm_server (void); // steph - int jack_initialize_shm_client (void); // steph + int jack_initialize_shm_server (void); + int jack_initialize_shm_client (void); int jack_cleanup_shm (void); int jack_shmalloc (const char *shm_name, jack_shmsize_t size, @@ -148,7 +149,7 @@ extern "C" void jack_release_shm (jack_shm_info_t*); void jack_destroy_shm (jack_shm_info_t*); int jack_attach_shm (jack_shm_info_t*); - int jack_attach_shm_read (jack_shm_info_t*); // steph + int jack_attach_shm_read (jack_shm_info_t*); int jack_resize_shm (jack_shm_info_t*, jack_shmsize_t size); #ifdef __cplusplus diff --git a/example-clients/impulse_grabber.c b/example-clients/impulse_grabber.c index cb36da85..0a1fd706 100644 --- a/example-clients/impulse_grabber.c +++ b/example-clients/impulse_grabber.c @@ -95,7 +95,7 @@ main (int argc, char *argv[]) int c; extern int optind, opterr; int show_usage = 0; - char *optstring = "d:f"; + char *optstring = "d:f:h"; struct option long_options[] = { { "help", 1, 0, 'h' }, { "duration", 1, 0, 'd' }, diff --git a/example-clients/wscript b/example-clients/wscript index 1a5dcd69..c8310d41 100644 --- a/example-clients/wscript +++ b/example-clients/wscript @@ -107,6 +107,8 @@ def build(bld): prog.uselib = 'SNDFILE' if bld.env['IS_LINUX']: prog.uselib = 'RT SNDFILE' + if bld.env['IS_SUN']: + prog.uselib = 'RT SNDFILE' prog.uselib_local = 'clientlib' prog.target = 'jack_rec' diff --git a/posix/JackCompilerDeps_os.h b/posix/JackCompilerDeps_os.h index d7d10992..767674e1 100644 --- a/posix/JackCompilerDeps_os.h +++ b/posix/JackCompilerDeps_os.h @@ -20,23 +20,42 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #ifndef __JackCompilerDeps_POSIX__ #define __JackCompilerDeps_POSIX__ +#include "JackConstants.h" + #if __GNUC__ + #ifndef POST_PACKED_STRUCTURE + /* POST_PACKED_STRUCTURE needs to be a macro which + expands into a compiler directive. The directive must + tell the compiler to arrange the preceding structure + declaration so that it is packed on byte-boundaries rather + than use the natural alignment of the processor and/or + compiler. + */ + #if (__GNUC__< 4) /* Does not seem to work with GCC 3.XX serie */ + #define POST_PACKED_STRUCTURE + #elif defined(JACK_32_64) + #define POST_PACKED_STRUCTURE __attribute__((__packed__)) + #else + #define POST_PACKED_STRUCTURE + #endif + #endif #define MEM_ALIGN(x,y) x __attribute__((aligned(y))) #define EXPORT __attribute__((visibility("default"))) #ifdef SERVER_SIDE #if (__GNUC__< 4) - #define SERVER_EXPORT + #define SERVER_EXPORT #else #define SERVER_EXPORT __attribute__((visibility("default"))) - #endif + #endif #else #define SERVER_EXPORT #endif -#else +#else #define MEM_ALIGN(x,y) x #define EXPORT #define SERVER_EXPORT + /* Add other things here for non-gcc platforms for POST_PACKED_STRUCTURE */ #endif - + #endif diff --git a/posix/JackSocket.h b/posix/JackSocket.h index 0382bd84..01e49539 100644 --- a/posix/JackSocket.h +++ b/posix/JackSocket.h @@ -20,8 +20,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifndef __JackSocket__ #define __JackSocket__ -#include #include +#include #include #include #include diff --git a/posix/JackSystemDeps_os.h b/posix/JackSystemDeps_os.h index dae9f6fd..cbddb0b1 100644 --- a/posix/JackSystemDeps_os.h +++ b/posix/JackSystemDeps_os.h @@ -28,7 +28,12 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #define DRIVER_HANDLE void* #define LoadDriverModule(name) dlopen((name), RTLD_NOW | RTLD_GLOBAL) #define UnloadDriverModule(handle) dlclose((handle)) -#define GetProc(handle, name) dlsym((handle), (name)) +#define GetDriverProc(handle, name) dlsym((handle), (name)) + +#define JACK_HANDLE void* +#define LoadJackModule(name) dlopen((name), RTLD_NOW | RTLD_LOCAL); +#define UnloadJackModule(handle) dlclose((handle)); +#define GetJackProc(handle, name) dlsym((handle), (name)); #define JACK_DEBUG (getenv("JACK_CLIENT_DEBUG") && strcmp(getenv("JACK_CLIENT_DEBUG"), "on") == 0) diff --git a/solaris/oss/JackBoomerDriver.cpp b/solaris/oss/JackBoomerDriver.cpp new file mode 100644 index 00000000..3080dcde --- /dev/null +++ b/solaris/oss/JackBoomerDriver.cpp @@ -0,0 +1,1001 @@ +/* +Copyright (C) 2009 Grame + +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. + +*/ + +#include "driver_interface.h" +#include "JackThreadedDriver.h" +#include "JackDriverLoader.h" +#include "JackBoomerDriver.h" +#include "JackEngineControl.h" +#include "JackGraphManager.h" +#include "JackError.h" +#include "JackTime.h" +#include "JackShmMem.h" +#include "JackGlobals.h" +#include "memops.h" + +#include +#include +#include +#include +#include +#include + +using namespace std; + +namespace Jack +{ + +#ifdef JACK_MONITOR + +#define CYCLE_POINTS 500000 + +struct OSSCycle { + jack_time_t fBeforeRead; + jack_time_t fAfterRead; + jack_time_t fAfterReadConvert; + jack_time_t fBeforeWrite; + jack_time_t fAfterWrite; + jack_time_t fBeforeWriteConvert; +}; + +struct OSSCycleTable { + jack_time_t fBeforeFirstWrite; + jack_time_t fAfterFirstWrite; + OSSCycle fTable[CYCLE_POINTS]; +}; + +OSSCycleTable gCycleTable; +int gCycleCount = 0; + +#endif + +inline int int2pow2(int x) { int r = 0; while ((1 << r) < x) r++; return r; } + +static inline void CopyAndConvertIn(jack_sample_t *dst, void *src, size_t nframes, int channel, int chcount, int bits) +{ + switch (bits) { + + case 16: { + signed short *s16src = (signed short*)src; + s16src += channel; + sample_move_dS_s16(dst, (char*)s16src, nframes, chcount<<1); + break; + } + case 24: { + signed short *s32src = (signed short*)src; + s32src += channel; + sample_move_dS_s24(dst, (char*)s32src, nframes, chcount<<2); + break; + } + case 32: { + signed short *s32src = (signed short*)src; + s32src += channel; + sample_move_dS_s32u24(dst, (char*)s32src, nframes, chcount<<2); + break; + } + } +} + +static inline void CopyAndConvertOut(void *dst, jack_sample_t *src, size_t nframes, int channel, int chcount, int bits) +{ + switch (bits) { + + case 16: { + signed short *s16dst = (signed short*)dst; + s16dst += channel; + sample_move_d16_sS((char*)s16dst, src, nframes, chcount<<1, NULL); // No dithering for now... + break; + } + case 24: { + signed int *s32dst = (signed int*)dst; + s32dst += channel; + sample_move_d24_sS((char*)s32dst, src, nframes, chcount<<2, NULL); // No dithering for now... + break; + } + case 32: { + signed int *s32dst = (signed int*)dst; + s32dst += channel; + sample_move_d32u24_sS((char*)s32dst, src, nframes, chcount<<2, NULL); + break; + } + } +} + +void JackBoomerDriver::SetSampleFormat() +{ + switch (fBits) { + + case 24: /* native-endian LSB aligned 24-bits in 32-bits integer */ + fSampleFormat = AFMT_S24_NE; + fSampleSize = sizeof(int); + break; + case 32: /* native-endian 32-bit integer */ + fSampleFormat = AFMT_S32_NE; + fSampleSize = sizeof(int); + break; + case 16: /* native-endian 16-bit integer */ + default: + fSampleFormat = AFMT_S16_NE; + fSampleSize = sizeof(short); + break; + } +} + +void JackBoomerDriver::DisplayDeviceInfo() +{ + audio_buf_info info; + oss_audioinfo ai_in, ai_out; + memset(&info, 0, sizeof(audio_buf_info)); + int cap = 0; + + // Duplex cards : http://manuals.opensound.com/developer/full_duplex.html + jack_info("Audio Interface Description :"); + jack_info("Sampling Frequency : %d, Sample Format : %d, Mode : %d", fEngineControl->fSampleRate, fSampleFormat, fRWMode); + + if (fRWMode & kWrite) { + + oss_sysinfo si; + if (ioctl(fOutFD, OSS_SYSINFO, &si) == -1) { + jack_error("JackBoomerDriver::DisplayDeviceInfo OSS_SYSINFO failed : %s@%i, errno = %d", __FILE__, __LINE__, errno); + } else { + jack_info("OSS product %s", si.product); + jack_info("OSS version %s", si.version); + jack_info("OSS version num %d", si.versionnum); + jack_info("OSS numaudios %d", si.numaudios); + jack_info("OSS numaudioengines %d", si.numaudioengines); + jack_info("OSS numcards %d", si.numcards); + } + + jack_info("Output capabilities - %d channels : ", fPlaybackChannels); + jack_info("Output block size = %d", fOutputBufferSize); + + if (ioctl(fOutFD, SNDCTL_DSP_GETOSPACE, &info) == -1) { + jack_error("JackBoomerDriver::DisplayDeviceInfo SNDCTL_DSP_GETOSPACE failed : %s@%i, errno = %d", __FILE__, __LINE__, errno); + } else { + jack_info("output space info: fragments = %d, fragstotal = %d, fragsize = %d, bytes = %d", + info.fragments, info.fragstotal, info.fragsize, info.bytes); + } + + if (ioctl(fOutFD, SNDCTL_DSP_GETCAPS, &cap) == -1) { + jack_error("JackBoomerDriver::DisplayDeviceInfo SNDCTL_DSP_GETCAPS failed : %s@%i, errno = %d", __FILE__, __LINE__, errno); + } else { + if (cap & DSP_CAP_DUPLEX) jack_info(" DSP_CAP_DUPLEX"); + if (cap & DSP_CAP_REALTIME) jack_info(" DSP_CAP_REALTIME"); + if (cap & DSP_CAP_BATCH) jack_info(" DSP_CAP_BATCH"); + if (cap & DSP_CAP_COPROC) jack_info(" DSP_CAP_COPROC"); + if (cap & DSP_CAP_TRIGGER) jack_info(" DSP_CAP_TRIGGER"); + if (cap & DSP_CAP_MMAP) jack_info(" DSP_CAP_MMAP"); + if (cap & DSP_CAP_MULTI) jack_info(" DSP_CAP_MULTI"); + if (cap & DSP_CAP_BIND) jack_info(" DSP_CAP_BIND"); + } + } + + if (fRWMode & kRead) { + + oss_sysinfo si; + if (ioctl(fInFD, OSS_SYSINFO, &si) == -1) { + jack_error("JackBoomerDriver::DisplayDeviceInfo OSS_SYSINFO failed : %s@%i, errno = %d", __FILE__, __LINE__, errno); + } else { + jack_info("OSS product %s", si.product); + jack_info("OSS version %s", si.version); + jack_info("OSS version num %d", si.versionnum); + jack_info("OSS numaudios %d", si.numaudios); + jack_info("OSS numaudioengines %d", si.numaudioengines); + jack_info("OSS numcards %d", si.numcards); + } + + jack_info("Input capabilities - %d channels : ", fCaptureChannels); + jack_info("Input block size = %d", fInputBufferSize); + + if (ioctl(fInFD, SNDCTL_DSP_GETISPACE, &info) == -1) { + jack_error("JackBoomerDriver::DisplayDeviceInfo SNDCTL_DSP_GETOSPACE failed : %s@%i, errno = %d", __FILE__, __LINE__, errno); + } else { + jack_info("input space info: fragments = %d, fragstotal = %d, fragsize = %d, bytes = %d", + info.fragments, info.fragstotal, info.fragsize, info.bytes); + } + + if (ioctl(fInFD, SNDCTL_DSP_GETCAPS, &cap) == -1) { + jack_error("JackBoomerDriver::DisplayDeviceInfo SNDCTL_DSP_GETCAPS failed : %s@%i, errno = %d", __FILE__, __LINE__, errno); + } else { + if (cap & DSP_CAP_DUPLEX) jack_info(" DSP_CAP_DUPLEX"); + if (cap & DSP_CAP_REALTIME) jack_info(" DSP_CAP_REALTIME"); + if (cap & DSP_CAP_BATCH) jack_info(" DSP_CAP_BATCH"); + if (cap & DSP_CAP_COPROC) jack_info(" DSP_CAP_COPROC"); + if (cap & DSP_CAP_TRIGGER) jack_info(" DSP_CAP_TRIGGER"); + if (cap & DSP_CAP_MMAP) jack_info(" DSP_CAP_MMAP"); + if (cap & DSP_CAP_MULTI) jack_info(" DSP_CAP_MULTI"); + if (cap & DSP_CAP_BIND) jack_info(" DSP_CAP_BIND"); + } + } + + if (ai_in.rate_source != ai_out.rate_source) { + jack_info("Warning : input and output are not necessarily driven by the same clock!"); + } +} + +int JackBoomerDriver::OpenInput() +{ + int flags = 0; + int gFragFormat; + int cur_capture_channels; + int cur_sample_format; + jack_nframes_t cur_sample_rate; + + if (fCaptureChannels == 0) fCaptureChannels = 2; + + if ((fInFD = open(fCaptureDriverName, O_RDONLY | ((fExcl) ? O_EXCL : 0))) < 0) { + jack_error("JackBoomerDriver::OpenInput failed to open device : %s@%i, errno = %d", __FILE__, __LINE__, errno); + return -1; + } + + jack_log("JackBoomerDriver::OpenInput input fInFD = %d", fInFD); + + if (fExcl) { + if (ioctl(fInFD, SNDCTL_DSP_COOKEDMODE, &flags) == -1) { + jack_error("JackBoomerDriver::OpenInput failed to set cooked mode : %s@%i, errno = %d", __FILE__, __LINE__, errno); + goto error; + } + } + + gFragFormat = (2 << 16) + int2pow2(fEngineControl->fBufferSize * fSampleSize * fCaptureChannels); + if (ioctl(fInFD, SNDCTL_DSP_SETFRAGMENT, &gFragFormat) == -1) { + jack_error("JackBoomerDriver::OpenInput failed to set fragments : %s@%i, errno = %d", __FILE__, __LINE__, errno); + goto error; + } + + cur_sample_format = fSampleFormat; + if (ioctl(fInFD, SNDCTL_DSP_SETFMT, &fSampleFormat) == -1) { + jack_error("JackBoomerDriver::OpenInput failed to set format : %s@%i, errno = %d", __FILE__, __LINE__, errno); + goto error; + } + if (cur_sample_format != fSampleFormat) { + jack_info("JackBoomerDriver::OpenInput driver forced the sample format %ld", fSampleFormat); + } + + cur_capture_channels = fCaptureChannels; + if (ioctl(fInFD, SNDCTL_DSP_CHANNELS, &fCaptureChannels) == -1) { + jack_error("JackBoomerDriver::OpenInput failed to set channels : %s@%i, errno = %d", __FILE__, __LINE__, errno); + goto error; + } + if (cur_capture_channels != fCaptureChannels) { + jack_info("JackBoomerDriver::OpenInput driver forced the number of capture channels %ld", fCaptureChannels); + } + + cur_sample_rate = fEngineControl->fSampleRate; + if (ioctl(fInFD, SNDCTL_DSP_SPEED, &fEngineControl->fSampleRate) == -1) { + jack_error("JackBoomerDriver::OpenInput failed to set sample rate : %s@%i, errno = %d", __FILE__, __LINE__, errno); + goto error; + } + if (cur_sample_rate != fEngineControl->fSampleRate) { + jack_info("JackBoomerDriver::OpenInput driver forced the sample rate %ld", fEngineControl->fSampleRate); + } + + // Just set the read size to the value we want... + fInputBufferSize = fEngineControl->fBufferSize * fSampleSize * fCaptureChannels; + + fInputBuffer = (void*)calloc(fInputBufferSize, 1); + assert(fInputBuffer); + return 0; + +error: + ::close(fInFD); + return -1; +} + +int JackBoomerDriver::OpenOutput() +{ + int flags = 0; + int gFragFormat; + int cur_sample_format; + int cur_playback_channels; + jack_nframes_t cur_sample_rate; + + if (fPlaybackChannels == 0) fPlaybackChannels = 2; + + if ((fOutFD = open(fPlaybackDriverName, O_WRONLY | ((fExcl) ? O_EXCL : 0))) < 0) { + jack_error("JackBoomerDriver::OpenOutput failed to open device : %s@%i, errno = %d", __FILE__, __LINE__, errno); + return -1; + } + + jack_log("JackBoomerDriver::OpenOutput output fOutFD = %d", fOutFD); + + if (fExcl) { + if (ioctl(fOutFD, SNDCTL_DSP_COOKEDMODE, &flags) == -1) { + jack_error("JackBoomerDriver::OpenOutput failed to set cooked mode : %s@%i, errno = %d", __FILE__, __LINE__, errno); + goto error; + } + } + + gFragFormat = (2 << 16) + int2pow2(fEngineControl->fBufferSize * fSampleSize * fPlaybackChannels); + if (ioctl(fOutFD, SNDCTL_DSP_SETFRAGMENT, &gFragFormat) == -1) { + jack_error("JackBoomerDriver::OpenOutput failed to set fragments : %s@%i, errno = %d", __FILE__, __LINE__, errno); + goto error; + } + + cur_sample_format = fSampleFormat; + if (ioctl(fOutFD, SNDCTL_DSP_SETFMT, &fSampleFormat) == -1) { + jack_error("JackBoomerDriver::OpenOutput failed to set format : %s@%i, errno = %d", __FILE__, __LINE__, errno); + goto error; + } + if (cur_sample_format != fSampleFormat) { + jack_info("JackBoomerDriver::OpenOutput driver forced the sample format %ld", fSampleFormat); + } + + cur_playback_channels = fPlaybackChannels; + if (ioctl(fOutFD, SNDCTL_DSP_CHANNELS, &fPlaybackChannels) == -1) { + jack_error("JackBoomerDriver::OpenOutput failed to set channels : %s@%i, errno = %d", __FILE__, __LINE__, errno); + goto error; + } + if (cur_playback_channels != fPlaybackChannels) { + jack_info("JackBoomerDriver::OpenOutput driver forced the number of playback channels %ld", fPlaybackChannels); + } + + cur_sample_rate = fEngineControl->fSampleRate; + if (ioctl(fOutFD, SNDCTL_DSP_SPEED, &fEngineControl->fSampleRate) == -1) { + jack_error("JackBoomerDriver::OpenOutput failed to set sample rate : %s@%i, errno = %d", __FILE__, __LINE__, errno); + goto error; + } + if (cur_sample_rate != fEngineControl->fSampleRate) { + jack_info("JackBoomerDriver::OpenInput driver forced the sample rate %ld", fEngineControl->fSampleRate); + } + + // Just set the write size to the value we want... + fOutputBufferSize = fEngineControl->fBufferSize * fSampleSize * fPlaybackChannels; + + fOutputBuffer = (void*)calloc(fOutputBufferSize, 1); + assert(fOutputBuffer); + return 0; + +error: + ::close(fOutFD); + return -1; +} + +int JackBoomerDriver::Open(jack_nframes_t nframes, + int user_nperiods, + jack_nframes_t samplerate, + bool capturing, + bool playing, + int inchannels, + int outchannels, + bool excl, + bool monitor, + const char* capture_driver_uid, + const char* playback_driver_uid, + jack_nframes_t capture_latency, + jack_nframes_t playback_latency, + int bits, + bool ignorehwbuf) +{ + + if (playing && !capturing) { + jack_error("Playback only mode is not yet supported, use duplex instead"); + return -1; + } + + // Generic JackAudioDriver Open + if (JackAudioDriver::Open(nframes, samplerate, capturing, playing, inchannels, outchannels, monitor, + capture_driver_uid, playback_driver_uid, capture_latency, playback_latency) != 0) { + return -1; + } else { + + if (fEngineControl->fSyncMode) { + jack_error("Cannot run in synchronous mode, remove the -S parameter for jackd"); + return -1; + } + + fRWMode |= ((capturing) ? kRead : 0); + fRWMode |= ((playing) ? kWrite : 0); + fBits = bits; + fIgnoreHW = ignorehwbuf; + fNperiods = user_nperiods; + fExcl = excl; + + #ifdef JACK_MONITOR + // Force memory page in + memset(&gCycleTable, 0, sizeof(gCycleTable)); + #endif + + if (OpenAux() < 0) { + Close(); + return -1; + } else { + return 0; + } + } +} + +int JackBoomerDriver::Close() +{ + #ifdef JACK_MONITOR + FILE* file = fopen("OSSProfiling.log", "w"); + + if (file) { + jack_info("Writing OSS driver timing data...."); + for (int i = 1; i < gCycleCount; i++) { + int d1 = gCycleTable.fTable[i].fAfterRead - gCycleTable.fTable[i].fBeforeRead; + int d2 = gCycleTable.fTable[i].fAfterReadConvert - gCycleTable.fTable[i].fAfterRead; + int d3 = gCycleTable.fTable[i].fAfterWrite - gCycleTable.fTable[i].fBeforeWrite; + int d4 = gCycleTable.fTable[i].fBeforeWrite - gCycleTable.fTable[i].fBeforeWriteConvert; + fprintf(file, "%d \t %d \t %d \t %d \t \n", d1, d2, d3, d4); + } + fclose(file); + } else { + jack_error("JackBoomerDriver::Close : cannot open OSSProfiling.log file"); + } + + file = fopen("TimingOSS.plot", "w"); + + if (file == NULL) { + jack_error("JackBoomerDriver::Close cannot open TimingOSS.plot file"); + } else { + + fprintf(file, "set grid\n"); + fprintf(file, "set title \"OSS audio driver timing\"\n"); + fprintf(file, "set xlabel \"audio cycles\"\n"); + fprintf(file, "set ylabel \"usec\"\n"); + fprintf(file, "plot \"OSSProfiling.log\" using 1 title \"Driver read wait\" with lines, \ + \"OSSProfiling.log\" using 2 title \"Driver read convert duration\" with lines, \ + \"OSSProfiling.log\" using 3 title \"Driver write wait\" with lines, \ + \"OSSProfiling.log\" using 4 title \"Driver write convert duration\" with lines\n"); + + fprintf(file, "set output 'TimingOSS.pdf\n"); + fprintf(file, "set terminal pdf\n"); + + fprintf(file, "set grid\n"); + fprintf(file, "set title \"OSS audio driver timing\"\n"); + fprintf(file, "set xlabel \"audio cycles\"\n"); + fprintf(file, "set ylabel \"usec\"\n"); + fprintf(file, "plot \"OSSProfiling.log\" using 1 title \"Driver read wait\" with lines, \ + \"OSSProfiling.log\" using 2 title \"Driver read convert duration\" with lines, \ + \"OSSProfiling.log\" using 3 title \"Driver write wait\" with lines, \ + \"OSSProfiling.log\" using 4 title \"Driver write convert duration\" with lines\n"); + + fclose(file); + } + #endif + int res = JackAudioDriver::Close(); + CloseAux(); + return res; +} + +int JackBoomerDriver::OpenAux() +{ + SetSampleFormat(); + + if ((fRWMode & kRead) && (OpenInput() < 0)) { + return -1; + } + + if ((fRWMode & kWrite) && (OpenOutput() < 0)) { + return -1; + } + + // Prepare ringbuffers used for output + if (fPlaybackChannels > 0) { + fRingBuffer = new jack_ringbuffer_t*[fPlaybackChannels]; + for (int i = 0; i < fPlaybackChannels; i++) { + fRingBuffer[i] = jack_ringbuffer_create(fOutputBufferSize * 2); + jack_ringbuffer_read_advance(fRingBuffer[i], fOutputBufferSize); + } + } + + DisplayDeviceInfo(); + return 0; +} + +void JackBoomerDriver::CloseAux() +{ + if (fRWMode & kRead && fInFD > 0) { + close(fInFD); + fInFD = -1; + } + + if (fRWMode & kWrite && fOutFD > 0) { + close(fOutFD); + fOutFD = -1; + } + + if (fInputBuffer) + free(fInputBuffer); + fInputBuffer = NULL; + + if (fOutputBuffer) + free(fOutputBuffer); + fOutputBuffer = NULL; + + for (int i = 0; i < fPlaybackChannels; i++) { + if (fRingBuffer[i]) + jack_ringbuffer_free(fRingBuffer[i]); + fRingBuffer[i] = NULL; + } + + delete [] fRingBuffer; + fRingBuffer = NULL; +} + +int JackBoomerDriver::Start() +{ + jack_log("JackBoomerDriver::Start"); + + // Start output thread only when needed + if (fOutFD > 0) { + if (fThread.StartSync() < 0) { + jack_error("Cannot start thread"); + return -1; + } + } + + return 0; +} + +int JackBoomerDriver::Stop() +{ + // Stop output thread only when needed + if (fOutFD > 0) { + return fThread.Kill(); + } else { + return 0; + } +} + +int JackBoomerDriver::Read() +{ + if (fInFD < 0) { + // Keep begin cycle time + JackDriver::CycleTakeBeginTime(); + return 0; + } + +#ifdef JACK_MONITOR + gCycleTable.fTable[gCycleCount].fBeforeRead = GetMicroSeconds(); +#endif + + audio_errinfo ei_in; + ssize_t count = ::read(fInFD, fInputBuffer, fInputBufferSize); + +#ifdef JACK_MONITOR + if (count > 0 && count != (int)fInputBufferSize) + jack_log("JackBoomerDriver::Read count = %ld", count / (fSampleSize * fCaptureChannels)); + gCycleTable.fTable[gCycleCount].fAfterRead = GetMicroSeconds(); +#endif + + // XRun detection + if (ioctl(fInFD, SNDCTL_DSP_GETERROR, &ei_in) == 0) { + + if (ei_in.rec_overruns > 0 ) { + jack_error("JackBoomerDriver::Read overruns"); + jack_time_t cur_time = GetMicroSeconds(); + NotifyXRun(cur_time, float(cur_time - fBeginDateUst)); // Better this value than nothing... + } + + if (ei_in.rec_errorcount > 0 && ei_in.rec_lasterror != 0) { + jack_error("%d OSS rec event(s), last=%05d:%d", ei_in.rec_errorcount, ei_in.rec_lasterror, ei_in.rec_errorparm); + } + } + + if (count < 0) { + jack_log("JackBoomerDriver::Read error = %s", strerror(errno)); + return -1; + } else if (count < (int)fInputBufferSize) { + jack_error("JackBoomerDriver::Read error bytes read = %ld", count); + return -1; + } else { + + // Keep begin cycle time + JackDriver::CycleTakeBeginTime(); + for (int i = 0; i < fCaptureChannels; i++) { + if (fGraphManager->GetConnectionsNum(fCapturePortList[i]) > 0) { + CopyAndConvertIn(GetInputBuffer(i), fInputBuffer, fEngineControl->fBufferSize, i, fCaptureChannels, fBits); + } + } + + #ifdef JACK_MONITOR + gCycleTable.fTable[gCycleCount].fAfterReadConvert = GetMicroSeconds(); + #endif + + return 0; + } +} + +int JackBoomerDriver::Write() +{ + for (int i = 0; i < fPlaybackChannels; i++) { + if (fGraphManager->GetConnectionsNum(fPlaybackPortList[i]) > 0) { + if (jack_ringbuffer_write(fRingBuffer[i], (char*)GetOutputBuffer(i), fOutputBufferSize) < fOutputBufferSize) { + jack_log("JackBoomerDriver::Write ringbuffer full"); + } + } + } + + return 0; +} + +bool JackBoomerDriver::Init() +{ + if (IsRealTime()) { + jack_log("JackBoomerDriver::Init IsRealTime"); + if (fThread.AcquireRealTime(GetEngineControl()->fServerPriority) < 0) { + jack_error("AcquireRealTime error"); + } else { + set_threaded_log_function(); + } + } + + // Maybe necessary to write an empty output buffer first time : see http://manuals.opensound.com/developer/fulldup.c.html + memset(fOutputBuffer, 0, fOutputBufferSize); + + // Prefill ouput buffer + if (fOutFD > 0) { + for (int i = 0; i < fNperiods; i++) { + ssize_t count = ::write(fOutFD, fOutputBuffer, fOutputBufferSize); + if (count < (int)fOutputBufferSize) { + jack_error("JackBoomerDriver::Write error bytes written = %ld", count); + } + } + + int delay; + if (ioctl(fOutFD, SNDCTL_DSP_GETODELAY, &delay) == -1) { + jack_error("JackBoomerDriver::Write error get out delay : %s@%i, errno = %d", __FILE__, __LINE__, errno); + } + + delay /= fSampleSize * fPlaybackChannels; + jack_info("JackBoomerDriver::Write output latency frames = %ld", delay); + } + + return true; +} + +bool JackBoomerDriver::Execute() +{ + memset(fOutputBuffer, 0, fOutputBufferSize); + + for (int i = 0; i < fPlaybackChannels; i++) { + if (fGraphManager->GetConnectionsNum(fPlaybackPortList[i]) > 0) { + + jack_ringbuffer_data_t ring_buffer_data[2]; + jack_ringbuffer_get_read_vector(fRingBuffer[i], ring_buffer_data); + + unsigned int available_frames = (ring_buffer_data[0].len + ring_buffer_data[1].len) / sizeof(float); + jack_log("Output available = %ld", available_frames); + + unsigned int needed_bytes = fOutputBufferSize; + float* output = (float*)fOutputBuffer; + + for (int j = 0; j < 2; j++) { + unsigned int consumed_bytes = std::min(needed_bytes, ring_buffer_data[j].len); + CopyAndConvertOut(output, (float*)ring_buffer_data[j].buf, consumed_bytes / sizeof(float), i, fPlaybackChannels, fBits); + output += consumed_bytes / sizeof(float); + needed_bytes -= consumed_bytes; + } + + if (needed_bytes > 0) { + jack_error("JackBoomerDriver::Execute missing frames = %ld", needed_bytes / sizeof(float)); + } + + jack_ringbuffer_read_advance(fRingBuffer[i], fOutputBufferSize - needed_bytes); + } + } + +#ifdef JACK_MONITOR + gCycleTable.fTable[gCycleCount].fBeforeWrite = GetMicroSeconds(); +#endif + + // Keep end cycle time + JackDriver::CycleTakeEndTime(); + ssize_t count = ::write(fOutFD, fOutputBuffer, fOutputBufferSize); + +#ifdef JACK_MONITOR + if (count > 0 && count != (int)fOutputBufferSize) + jack_log("JackBoomerDriver::Execute count = %ld", count / (fSampleSize * fPlaybackChannels)); + gCycleTable.fTable[gCycleCount].fAfterWrite = GetMicroSeconds(); + gCycleCount = (gCycleCount == CYCLE_POINTS - 1) ? gCycleCount: gCycleCount + 1; +#endif + + // XRun detection + audio_errinfo ei_out; + if (ioctl(fOutFD, SNDCTL_DSP_GETERROR, &ei_out) == 0) { + + if (ei_out.play_underruns > 0) { + jack_error("JackBoomerDriver::Execute underruns"); + jack_time_t cur_time = GetMicroSeconds(); + NotifyXRun(cur_time, float(cur_time - fBeginDateUst)); // Better this value than nothing... + } + + if (ei_out.play_errorcount > 0 && ei_out.play_lasterror != 0) { + jack_error("%d OSS play event(s), last=%05d:%d",ei_out.play_errorcount, ei_out.play_lasterror, ei_out.play_errorparm); + } + } + + if (count < 0) { + jack_log("JackBoomerDriver::Execute error = %s", strerror(errno)); + } else if (count < (int)fOutputBufferSize) { + jack_error("JackBoomerDriver::Execute error bytes written = %ld", count); + } + + return true; +} + +int JackBoomerDriver::SetBufferSize(jack_nframes_t buffer_size) +{ + CloseAux(); + JackAudioDriver::SetBufferSize(buffer_size); // never fails + return OpenAux(); +} + +int JackBoomerDriver::ProcessAsync() +{ + // Read input buffers for the current cycle + if (Read() < 0) { + jack_error("JackBoomerDriver::ProcessAsync: read error, skip cycle"); + return 0; // Skip cycle, but continue processing... + } + + // Write output buffers from the previous cycle + if (Write() < 0) { + jack_error("JackBoomerDriver::ProcessAsync: write error, skip cycle"); + return 0; // Skip cycle, but continue processing... + } + + if (fIsMaster) { + ProcessGraphAsync(); + } else { + fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable); + } + + // Keep end cycle time + JackDriver::CycleTakeEndTime(); + return 0; +} + +} // end of namespace + +#ifdef __cplusplus +extern "C" +{ +#endif + +SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor() +{ + jack_driver_desc_t *desc; + unsigned int i; + desc = (jack_driver_desc_t*)calloc(1, sizeof(jack_driver_desc_t)); + + strcpy(desc->name, "boomer"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1 + strcpy(desc->desc, "Boomer/OSS API based audio backend"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1 + + desc->nparams = OSS_DRIVER_N_PARAMS; + desc->params = (jack_driver_param_desc_t*)calloc(desc->nparams, sizeof(jack_driver_param_desc_t)); + + i = 0; + strcpy(desc->params[i].name, "rate"); + desc->params[i].character = 'r'; + desc->params[i].type = JackDriverParamUInt; + desc->params[i].value.ui = OSS_DRIVER_DEF_FS; + strcpy(desc->params[i].short_desc, "Sample rate"); + strcpy(desc->params[i].long_desc, desc->params[i].short_desc); + + i++; + strcpy(desc->params[i].name, "period"); + desc->params[i].character = 'p'; + desc->params[i].type = JackDriverParamUInt; + desc->params[i].value.ui = OSS_DRIVER_DEF_BLKSIZE; + strcpy(desc->params[i].short_desc, "Frames per period"); + strcpy(desc->params[i].long_desc, desc->params[i].short_desc); + + i++; + strcpy(desc->params[i].name, "nperiods"); + desc->params[i].character = 'n'; + desc->params[i].type = JackDriverParamUInt; + desc->params[i].value.ui = OSS_DRIVER_DEF_NPERIODS; + strcpy(desc->params[i].short_desc, "Number of periods to prefill output buffer"); + strcpy(desc->params[i].long_desc, desc->params[i].short_desc); + + i++; + strcpy(desc->params[i].name, "wordlength"); + desc->params[i].character = 'w'; + desc->params[i].type = JackDriverParamInt; + desc->params[i].value.i = OSS_DRIVER_DEF_BITS; + strcpy(desc->params[i].short_desc, "Word length"); + strcpy(desc->params[i].long_desc, desc->params[i].short_desc); + + i++; + strcpy(desc->params[i].name, "inchannels"); + desc->params[i].character = 'i'; + desc->params[i].type = JackDriverParamUInt; + desc->params[i].value.ui = OSS_DRIVER_DEF_INS; + strcpy(desc->params[i].short_desc, "Capture channels"); + strcpy(desc->params[i].long_desc, desc->params[i].short_desc); + + i++; + strcpy(desc->params[i].name, "outchannels"); + desc->params[i].character = 'o'; + desc->params[i].type = JackDriverParamUInt; + desc->params[i].value.ui = OSS_DRIVER_DEF_OUTS; + strcpy(desc->params[i].short_desc, "Playback channels"); + strcpy(desc->params[i].long_desc, desc->params[i].short_desc); + + i++; + strcpy(desc->params[i].name, "excl"); + desc->params[i].character = 'e'; + desc->params[i].type = JackDriverParamBool; + desc->params[i].value.i = false; + strcpy(desc->params[i].short_desc, "Exclusif (O_EXCL) access mode"); + strcpy(desc->params[i].long_desc, desc->params[i].short_desc); + + i++; + strcpy(desc->params[i].name, "capture"); + desc->params[i].character = 'C'; + desc->params[i].type = JackDriverParamString; + strcpy(desc->params[i].value.str, OSS_DRIVER_DEF_DEV); + strcpy(desc->params[i].short_desc, "Input device"); + strcpy(desc->params[i].long_desc, desc->params[i].short_desc); + + i++; + strcpy(desc->params[i].name, "playback"); + desc->params[i].character = 'P'; + desc->params[i].type = JackDriverParamString; + strcpy(desc->params[i].value.str, OSS_DRIVER_DEF_DEV); + strcpy(desc->params[i].short_desc, "Output device"); + strcpy(desc->params[i].long_desc, desc->params[i].short_desc); + + i++; + strcpy (desc->params[i].name, "device"); + desc->params[i].character = 'd'; + desc->params[i].type = JackDriverParamString; + strcpy(desc->params[i].value.str, OSS_DRIVER_DEF_DEV); + strcpy(desc->params[i].short_desc, "OSS device name"); + strcpy(desc->params[i].long_desc, desc->params[i].short_desc); + + i++; + strcpy(desc->params[i].name, "ignorehwbuf"); + desc->params[i].character = 'b'; + desc->params[i].type = JackDriverParamBool; + desc->params[i].value.i = false; + strcpy(desc->params[i].short_desc, "Ignore hardware period size"); + strcpy(desc->params[i].long_desc, desc->params[i].short_desc); + + i++; + strcpy(desc->params[i].name, "input-latency"); + desc->params[i].character = 'I'; + desc->params[i].type = JackDriverParamUInt; + desc->params[i].value.i = 0; + strcpy(desc->params[i].short_desc, "Extra input latency"); + strcpy(desc->params[i].long_desc, desc->params[i].short_desc); + + i++; + strcpy(desc->params[i].name, "output-latency"); + desc->params[i].character = 'O'; + desc->params[i].type = JackDriverParamUInt; + desc->params[i].value.i = 0; + strcpy(desc->params[i].short_desc, "Extra output latency"); + strcpy(desc->params[i].long_desc, desc->params[i].short_desc); + + return desc; +} + +EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params) +{ + int bits = OSS_DRIVER_DEF_BITS; + jack_nframes_t srate = OSS_DRIVER_DEF_FS; + jack_nframes_t frames_per_interrupt = OSS_DRIVER_DEF_BLKSIZE; + const char* capture_pcm_name = OSS_DRIVER_DEF_DEV; + const char* playback_pcm_name = OSS_DRIVER_DEF_DEV; + bool capture = false; + bool playback = false; + int chan_in = 0; + int chan_out = 0; + bool monitor = false; + bool excl = false; + unsigned int nperiods = OSS_DRIVER_DEF_NPERIODS; + const JSList *node; + const jack_driver_param_t *param; + bool ignorehwbuf = false; + jack_nframes_t systemic_input_latency = 0; + jack_nframes_t systemic_output_latency = 0; + + for (node = params; node; node = jack_slist_next(node)) { + + param = (const jack_driver_param_t *)node->data; + + switch (param->character) { + + case 'r': + srate = param->value.ui; + break; + + case 'p': + frames_per_interrupt = (unsigned int)param->value.ui; + break; + + case 'n': + nperiods = (unsigned int)param->value.ui; + break; + + case 'w': + bits = param->value.i; + break; + + case 'i': + chan_in = (int)param->value.ui; + break; + + case 'o': + chan_out = (int)param->value.ui; + break; + + case 'C': + capture = true; + if (strcmp(param->value.str, "none") != 0) { + capture_pcm_name = strdup(param->value.str); + } + break; + + case 'P': + playback = true; + if (strcmp(param->value.str, "none") != 0) { + playback_pcm_name = strdup(param->value.str); + } + break; + + case 'd': + playback_pcm_name = strdup (param->value.str); + capture_pcm_name = strdup (param->value.str); + break; + + case 'b': + ignorehwbuf = true; + break; + + case 'e': + excl = true; + break; + + case 'I': + systemic_input_latency = param->value.ui; + break; + + case 'O': + systemic_output_latency = param->value.ui; + break; + } + } + + // duplex is the default + if (!capture && !playback) { + capture = true; + playback = true; + } + + Jack::JackBoomerDriver* boomer_driver = new Jack::JackBoomerDriver("system", "boomer", engine, table); + Jack::JackDriverClientInterface* threaded_driver = new Jack::JackThreadedDriver(boomer_driver); + + // Special open for OSS driver... + if (boomer_driver->Open(frames_per_interrupt, nperiods, srate, capture, playback, chan_in, chan_out, + excl, monitor, capture_pcm_name, playback_pcm_name, systemic_input_latency, systemic_output_latency, bits, ignorehwbuf) == 0) { + return threaded_driver; + } else { + delete threaded_driver; // Delete the decorated driver + return NULL; + } +} + +#ifdef __cplusplus +} +#endif diff --git a/solaris/oss/JackBoomerDriver.h b/solaris/oss/JackBoomerDriver.h new file mode 100644 index 00000000..1861e8d8 --- /dev/null +++ b/solaris/oss/JackBoomerDriver.h @@ -0,0 +1,135 @@ +/* +Copyright (C) 2009 Grame + +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 __JackBoomerDriver__ +#define __JackBoomerDriver__ + +#include "JackAudioDriver.h" +#include "JackPlatformPlug.h" +#include "ringbuffer.h" +//#include "JackThread.h" + +namespace Jack +{ + +typedef jack_default_audio_sample_t jack_sample_t; + +#define OSS_DRIVER_N_PARAMS 13 +#define OSS_DRIVER_DEF_DEV "/dev/dsp" +#define OSS_DRIVER_DEF_FS 48000 +#define OSS_DRIVER_DEF_BLKSIZE 1024 +#define OSS_DRIVER_DEF_NPERIODS 1 +#define OSS_DRIVER_DEF_BITS 16 +#define OSS_DRIVER_DEF_INS 2 +#define OSS_DRIVER_DEF_OUTS 2 + +/*! +\brief The Boomer driver. +*/ + +class JackBoomerDriver : public JackAudioDriver, public JackRunnableInterface +{ + + enum { kRead = 1, kWrite = 2, kReadWrite = 3 }; + + private: + + int fInFD; + int fOutFD; + + int fBits; + int fSampleFormat; + int fNperiods; + unsigned int fSampleSize; + int fRWMode; + bool fExcl; + bool fIgnoreHW; + + unsigned int fInputBufferSize; + unsigned int fOutputBufferSize; + + void* fInputBuffer; + void* fOutputBuffer; + jack_ringbuffer_t** fRingBuffer; + JackThread fThread; + + int OpenInput(); + int OpenOutput(); + int OpenAux(); + void CloseAux(); + void SetSampleFormat(); + void DisplayDeviceInfo(); + + // Redefining since timing for CPU load is specific + int ProcessAsync(); + + public: + + JackBoomerDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table) + : JackAudioDriver(name, alias, engine, table), + fInFD(-1), fOutFD(-1), fBits(0), + fSampleFormat(0), fNperiods(0), fRWMode(0), fExcl(false), fIgnoreHW(true), + fInputBufferSize(0), fOutputBufferSize(0), + fInputBuffer(NULL), fOutputBuffer(NULL), + fRingBuffer(NULL), fThread(this) + {} + + virtual ~JackBoomerDriver() + {} + + int Open(jack_nframes_t frames_per_cycle, + int user_nperiods, + jack_nframes_t rate, + bool capturing, + bool playing, + int chan_in, + int chan_out, + bool vmix, + bool monitor, + const char* capture_driver_name, + const char* playback_driver_name, + jack_nframes_t capture_latency, + jack_nframes_t playback_latency, + int bits, + bool ignorehwbuf); + + int Close(); + + int Start(); + int Stop(); + + int Read(); + int Write(); + + // BufferSize can be changed + bool IsFixedBufferSize() + { + return false; + } + + int SetBufferSize(jack_nframes_t buffer_size); + + bool Init(); + bool Execute(); + +}; + +} // end of namespace + +#endif diff --git a/solaris/oss/JackOSSDriver.cpp b/solaris/oss/JackOSSDriver.cpp index 46a2871a..ad44a43c 100644 --- a/solaris/oss/JackOSSDriver.cpp +++ b/solaris/oss/JackOSSDriver.cpp @@ -828,7 +828,7 @@ SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor() strcpy(desc->params[i].name, "ignorehwbuf"); desc->params[i].character = 'b'; desc->params[i].type = JackDriverParamBool; - desc->params[i].value.i = TRUE; + desc->params[i].value.i = false; strcpy(desc->params[i].short_desc, "Ignore hardware period size"); strcpy(desc->params[i].long_desc, desc->params[i].short_desc); diff --git a/solaris/wscript b/solaris/wscript index 06bbe5b9..9e7ce920 100644 --- a/solaris/wscript +++ b/solaris/wscript @@ -28,6 +28,8 @@ def build(bld): create_jack_driver_obj(bld, 'oss', ['oss/JackOSSDriver.cpp', '../common/memops.c']) + create_jack_driver_obj(bld, 'boomer', ['oss/JackBoomerDriver.cpp', '../common/memops.c']) + create_jack_driver_obj(bld, 'dummy', '../common/JackDummyDriver.cpp') create_jack_driver_obj(bld, 'net', '../common/JackNetDriver.cpp') diff --git a/tests/test.cpp b/tests/test.cpp index 9ae3963f..2358a891 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2005 Samuel TRACOL for GRAME - + 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 @@ -20,7 +20,7 @@ /** @file jack_test.c * * @brief This client test the jack API. - * + * */ #include @@ -38,7 +38,7 @@ #include -#ifdef WIN32 +#if defined(WIN32) && !defined(M_PI) #define M_PI 3.151592653 #endif @@ -122,9 +122,9 @@ int client_register = 0; /** *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* - + Callbacks & basics functions - + *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* */ @@ -266,9 +266,9 @@ int Jack_Sync_Callback(jack_transport_state_t state, jack_position_t *pos, void /** *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* - + processing functions - + *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* * Proccess1 is for client1 @@ -370,7 +370,7 @@ int process2(jack_nframes_t nframes, void *arg) } } } - + if (process2_activated == 2) { // envoie de signal1 pour test tie mode et le r�cup�re direct + latence de la boucle jack... out2 = (jack_default_audio_sample_t *) jack_port_get_buffer (output_port2, nframes); in2 = (jack_default_audio_sample_t *) jack_port_get_buffer (input_port2, nframes); @@ -389,7 +389,7 @@ int process2(jack_nframes_t nframes, void *arg) } } } - + if (process2_activated == 3) { // envoie de -signal1 pour sommation en oppo de phase par jack in2 = (jack_default_audio_sample_t *) jack_port_get_buffer (input_port2, nframes); @@ -416,14 +416,14 @@ static int _process (jack_nframes_t nframes) out = (jack_default_audio_sample_t *)jack_port_get_buffer (output_port1, nframes); memcpy (out, in, sizeof (jack_default_audio_sample_t) * nframes); - return 0; + return 0; } -static void* jack_thread(void *arg) +static void* jack_thread(void *arg) { jack_client_t* client = (jack_client_t*) arg; jack_nframes_t last_thread_time = jack_frame_time(client); - + while (1) { jack_nframes_t frames = jack_cycle_wait (client); jack_nframes_t current_thread_time = jack_frame_time(client); @@ -433,7 +433,7 @@ static void* jack_thread(void *arg) last_thread_time = current_thread_time; jack_cycle_signal (client, status); } - + return 0; } @@ -441,7 +441,7 @@ static void* jack_thread(void *arg) int process3(jack_nframes_t nframes, void *arg) { static int process3_call = 0; - + if (process3_call++ > 10) { Log("process3 callback : exiting...\n"); return -1; @@ -457,15 +457,15 @@ int process4(jack_nframes_t nframes, void *arg) static jack_nframes_t last_time = jack_frame_time(client); static jack_nframes_t tolerance = (jack_nframes_t)(cur_buffer_size * 0.1f); - + jack_nframes_t cur_time = jack_frame_time(client); jack_nframes_t delta_time = cur_time - last_time; - + Log("calling process4 callback : jack_frame_time = %ld delta_time = %ld\n", cur_time, delta_time); if (delta_time > 0 && (unsigned int)abs(delta_time - cur_buffer_size) > tolerance) { printf("!!! ERROR !!! jack_frame_time seems to return incorrect values cur_buffer_size = %d, delta_time = %d\n", cur_buffer_size, delta_time); } - + last_time = cur_time; return 0; } @@ -525,7 +525,7 @@ int main (int argc, char *argv[]) int is_mine = 0; // to test jack_port_is_mine function... const char *options = "kRnqvt:"; float ratio; // for speed calculation in freewheel mode - jack_options_t jack_options = JackNullOption; + jack_options_t jack_options = JackNullOption; struct option long_options[] = { {"realtime", 0, 0, 'R'}, {"non-realtime", 0, 0, 'n'}, @@ -602,8 +602,8 @@ int main (int argc, char *argv[]) printf("*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\n"); /** - * Register a client... - * + * Register a client... + * */ Log("Register a client using jack_client_open()...\n"); client1 = jack_client_open(client_name1, jack_options, &status, server_name); @@ -618,7 +618,7 @@ int main (int argc, char *argv[]) if (status & JackServerStarted) { fprintf(stderr, "JACK server started\n"); } - + /** * try to register another one with the same name... * @@ -631,7 +631,7 @@ int main (int argc, char *argv[]) printf("!!! ERROR !!! Jackd server has accepted multiples client with the same name !\n"); jack_client_close(client2); } - + /** * try to register another one with the same name using jack_client_open ==> since JackUseExactName is not used, an new client should be opened... * @@ -644,7 +644,7 @@ int main (int argc, char *argv[]) } else { printf("!!! ERROR !!! Jackd server automatic renaming feature does not work!\n"); } - + /** * testing client name... * Verify that the name sended at registration and the one returned by jack server is the same... @@ -683,31 +683,31 @@ int main (int argc, char *argv[]) if (jack_set_buffer_size_callback(client1, Jack_Update_Buffer_Size, 0) != 0) { printf("Error when calling buffer_size_callback !\n"); } - + if (jack_set_graph_order_callback(client1, Jack_Graph_Order_Callback, 0) != 0) { printf("Error when calling Jack_Graph_Order_Callback() !\n"); } - + if (jack_set_xrun_callback(client1, Jack_XRun_Callback, 0 ) != 0) { printf("Error when calling jack_set_xrun_callback() !\n"); } - + if (jack_set_sample_rate_callback(client1, Jack_Sample_Rate_Callback, 0 ) != 0) { printf("Error when calling Jack_Sample_Rate_Callback() !\n"); } - + if (jack_set_port_registration_callback(client1, Jack_Port_Register, 0) != 0) { printf("Error when calling jack_set_port_registration_callback() !\n"); } - + if (jack_set_port_connect_callback(client1, Jack_Port_Connect, 0) != 0) { printf("Error when calling jack_set_port_connect_callback() !\n"); } - + if (jack_set_client_registration_callback(client1, Jack_Client_Registration_Callback, 0) != 0) { printf("Error when calling jack_set_client_registration_callback() !\n"); } - + jack_set_error_function(Jack_Error_Callback); /** @@ -747,7 +747,7 @@ int main (int argc, char *argv[]) printf("!!! ERROR !!! Can't register any port for the client !\n"); exit(1); } - + /** * Test port type of the just registered port. * @@ -811,7 +811,7 @@ int main (int argc, char *argv[]) printf ("Fatal error : cannot activate client1\n"); exit(1); } - + /** * Test if init callback initThread have been called. * @@ -925,7 +925,7 @@ int main (int argc, char *argv[]) /** * remove the output port previously created * no more ports should subsist here for our client. - * + * */ if (jack_port_unregister(client1, output_port1) != 0) { printf("!!! ERROR !!! while unregistering port %s.\n", jack_port_name(output_port1)); @@ -933,7 +933,7 @@ int main (int argc, char *argv[]) /** * list all in ports - * + * */ inports = jack_get_ports(client1, NULL, NULL, 0); @@ -1133,7 +1133,7 @@ int main (int argc, char *argv[]) } free(inports); // free array of ports (as mentionned in the doc of jack_get_ports) - + /** *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* @@ -1157,7 +1157,7 @@ int main (int argc, char *argv[]) } exit(1); } - + // Check client registration callback jack_sleep(1000); if (client_register == 0) @@ -1368,7 +1368,7 @@ int main (int argc, char *argv[]) } /** - * Test TIE MODE + * Test TIE MODE * (This mode seems to be problematic in standard jack version 0.100. It seems that nobody * is used to apply this mode because the tie mode doesn't work at all. A patch seems difficult to produce * in this version of jack. Tie mode work well in MP version.) @@ -1468,7 +1468,7 @@ int main (int argc, char *argv[]) * So, the result must be zero... * See process1 for details about steps of this test * - */ + */ // fprintf(file, "Sum test\n"); Log("Checking summation capabilities of patching...\n"); output_port1b = jack_port_register(client1, "out1b", @@ -1565,7 +1565,7 @@ int main (int argc, char *argv[]) outports = jack_get_ports(client1, NULL, NULL, JackPortIsPhysical | JackPortIsOutput); if (inports[0] != NULL) { output_ext_latency = jack_port_get_latency (jack_port_by_name(client1, inports[0])); // from client to out driver (which has "inputs" ports..) - input_ext_latency = jack_port_get_latency (jack_port_by_name(client1, outports[0])); // from in driver (which has "output" ports..) to client + input_ext_latency = jack_port_get_latency (jack_port_by_name(client1, outports[0])); // from in driver (which has "output" ports..) to client if (output_ext_latency != jack_port_get_total_latency(client1, jack_port_by_name(client1, inports[0]))) { t_error = 1; printf("!!! ERROR !!! get_latency & get_all_latency for a PHY device (unconnected) didn't return the same value !\n"); @@ -1641,7 +1641,7 @@ int main (int argc, char *argv[]) jack_port_disconnect(client1, input_port2); jack_port_disconnect(client1, output_port1); jack_port_disconnect(client1, output_port2); - + jack_sleep(1000); free(inports); @@ -1836,23 +1836,23 @@ int main (int argc, char *argv[]) jack_sleep (1 * 1000); time_before_exit--; } - + if (jack_deactivate(client2) != 0) { printf("!!! ERROR !!! jack_deactivate does not return 0 for client2 !\n"); } if (jack_deactivate(client1) != 0) { printf("!!! ERROR !!! jack_deactivate does not return 0 for client1 !\n"); } - + /** * Checking jack_frame_time. */ Log("Testing jack_frame_time...\n"); jack_set_process_callback(client1, process4, client1); jack_activate(client1); - jack_sleep(2 * 1000); - - + jack_sleep(2 * 1000); + + /** * Checking alternate thread model */ @@ -1862,7 +1862,7 @@ int main (int argc, char *argv[]) jack_set_process_thread(client1, jack_thread, client1); jack_activate(client1); jack_sleep(2 * 1000); - + /** * Checking callback exiting : when the return code is != 0, the client is desactivated. */ @@ -1871,8 +1871,8 @@ int main (int argc, char *argv[]) jack_set_process_thread(client1, NULL, NULL); // remove thread callback jack_set_process_callback(client1, process3, 0); jack_activate(client1); - jack_sleep(3 * 1000); - + jack_sleep(3 * 1000); + /** *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* diff --git a/windows/JackCompilerDeps_os.h b/windows/JackCompilerDeps_os.h index f98dba9c..82fae18e 100644 --- a/windows/JackCompilerDeps_os.h +++ b/windows/JackCompilerDeps_os.h @@ -18,9 +18,25 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __JackCompilerDeps_WIN32__ -#define __JackCompilerDeps_WIN32__ +#define __JackCompilerDeps_WIN32__ -#if __GNUC__ +#if __GNUC__ + #ifndef POST_PACKED_STRUCTURE + /* POST_PACKED_STRUCTURE needs to be a macro which + expands into a compiler directive. The directive must + tell the compiler to arrange the preceding structure + declaration so that it is packed on byte-boundaries rather + than use the natural alignment of the processor and/or + compiler. + */ + #if (__GNUC__< 4) /* Does not seem to work with GCC 3.XX serie */ + #define POST_PACKED_STRUCTURE + #elif defined(JACK_32_64) + #define POST_PACKED_STRUCTURE __attribute__((__packed__)) + #else + #define POST_PACKED_STRUCTURE + #endif + #endif #define MEM_ALIGN(x,y) x __attribute__((aligned(y))) #define EXPORT __declspec(dllexport) #ifdef SERVER_SIDE @@ -29,7 +45,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #define SERVER_EXPORT #endif #else - //#define MEM_ALIGN(x,y) __declspec(align(y)) x #define MEM_ALIGN(x,y) x #define EXPORT __declspec(dllexport) #ifdef SERVER_SIDE diff --git a/windows/JackSystemDeps_os.h b/windows/JackSystemDeps_os.h index 78cccdc7..69b842b3 100644 --- a/windows/JackSystemDeps_os.h +++ b/windows/JackSystemDeps_os.h @@ -25,10 +25,14 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #define DRIVER_HANDLE HINSTANCE #define LoadDriverModule(name) LoadLibrary((name)) #define UnloadDriverModule(handle) (FreeLibrary(((HMODULE)handle))) -#define GetProc(handle, name) GetProcAddress(((HMODULE)handle),(name)) +#define GetDriverProc(handle, name) GetProcAddress(((HMODULE)handle), (name)) -#define ENOBUFS 55 +#define JACK_HANDLE HINSTANCE +#define LoadJackModule(name) LoadLibrary((name)); +#define UnloadJackModule(handle) FreeLibrary((handle)); +#define GetJackProc(handle, name) GetProcAddress((handle), (name)); +#define ENOBUFS 55 #define JACK_DEBUG false #endif diff --git a/windows/Setup/jack.ci b/windows/Setup/jack.ci index ee1c96ca..213bcc82 100644 --- a/windows/Setup/jack.ci +++ b/windows/Setup/jack.ci @@ -1,9 +1,9 @@ <*project version = 4 civer = "Free v4.14.3" winver = "2.6/5.1.2600" > . - Jack_v1.9.2_setup.exe + Jack_v1.9.3_setup.exe - Jack v1.9.2 + Jack v1.9.3 Default - 2 diff --git a/windows/Setup/src/README b/windows/Setup/src/README index eafc21ae..5ba3bc3a 100644 --- a/windows/Setup/src/README +++ b/windows/Setup/src/README @@ -8,7 +8,7 @@ This installer will install everything to use Jack Audio Connection Kit (JACK) ( Microsoft Runtime Libraries ============================================= -In order to use this software, you will need the Microsoft Vusual C++ 2008 redistributable package. This package is freely available on the Microsoft download center. Please be sure you install the correct version (2008). This package is required by portaudio to run windows specific audio drivers (MME, DSound and ASIO). +In order to use this software, you will need the Microsoft Visual C++ 2008 redistributable package. This package is freely available on the Microsoft download center. Please be sure you install the correct version (2008). This package is required by portaudio to run windows specific audio drivers (MME, DSound and ASIO). ============================================= QJACKCTL on Windows diff --git a/wscript b/wscript index 4fef3251..659a1a26 100644 --- a/wscript +++ b/wscript @@ -64,6 +64,7 @@ def set_options(opt): opt.add_option('--dbus', action='store_true', default=False, help='Enable D-Bus JACK (jackdbus)') opt.add_option('--doxygen', action='store_true', default=False, help='Enable build of doxygen documentation') opt.add_option('--profile', action='store_true', default=False, help='Build with engine profiling') + opt.add_option('--mixed', action='store_true', default=False, help='Build with 32/64 bits mixed mode') opt.add_option('--clients', default=64, type="int", dest="clients", help='Maximum number of JACK clients') opt.add_option('--ports', default=1024, type="int", dest="ports", help='Maximum number of ports') opt.add_option('--clients', default=64, type="int", dest="clients", help='Maximum number of JACK clients') @@ -120,6 +121,7 @@ def configure(conf): conf.env['BUILD_DOXYGEN_DOCS'] = Options.options.doxygen conf.env['BUILD_WITH_PROFILE'] = Options.options.profile + conf.env['BUILD_WITH_32_64'] = Options.options.mixed if Options.options.libdir: conf.env['LIBDIR'] = Options.options.libdir @@ -137,6 +139,8 @@ def configure(conf): conf.define('JACK_DBUS', 1) if conf.env['BUILD_WITH_PROFILE'] == True: conf.define('JACK_MONITOR', 1) + if conf.env['BUILD_WITH_32_64'] == True: + conf.define('JACK_32_64', 1) conf.write_config_header('config.h') svnrev = None @@ -163,6 +167,7 @@ def configure(conf): display_msg("Drivers directory", conf.env['ADDON_DIR'], 'CYAN') display_feature('Build doxygen documentation', conf.env['BUILD_DOXYGEN_DOCS']) display_feature('Build with engine profiling', conf.env['BUILD_WITH_PROFILE']) + display_feature('Build with 32/64 bits mixed mode', conf.env['BUILD_WITH_32_64']) if conf.env['IS_LINUX']: