diff --git a/ChangeLog b/ChangeLog index be05681a..c65bc664 100644 --- a/ChangeLog +++ b/ChangeLog @@ -43,6 +43,7 @@ Valerio Pilo * Stop using alloca and allocate buffer on the heap for alsa_io. * Rename jdelay to jack_iodelay as per Fons' request. * Call buffer size callback in activate (actually this is done on client side in the RT thread Init method). + * JackEngine::ComputeTotalLatencies in progress. 2011-03-08 Stephane Letz diff --git a/common/JackAPI.cpp b/common/JackAPI.cpp index 60deb5c6..8f3fa232 100644 --- a/common/JackAPI.cpp +++ b/common/JackAPI.cpp @@ -1521,7 +1521,7 @@ EXPORT size_t jack_port_type_get_buffer_size(jack_client_t* ext_client, const ch jack_error("jack_port_type_get_buffer_size called with an unknown port type = %s", port_type); return 0; } else { - return GetPortType(port_id)->fSize; + return GetPortType(port_id)->size(); } } } diff --git a/common/JackAudioPort.cpp b/common/JackAudioPort.cpp index 888660a5..c006b1cf 100644 --- a/common/JackAudioPort.cpp +++ b/common/JackAudioPort.cpp @@ -18,7 +18,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include "JackGlobals.h" +#include "JackEngineControl.h" #include "JackPortType.h" + #include #if defined (__APPLE__) @@ -127,13 +130,18 @@ static void AudioBufferMixdown(void* mixbuffer, void** src_buffers, int src_coun } } +static size_t AudioBufferSize() +{ + return GetEngineControl()->fBufferSize * sizeof(float); +} + const JackPortType gAudioPortType = - { - JACK_DEFAULT_AUDIO_TYPE, - BUFFER_SIZE_MAX * sizeof(jack_default_audio_sample_t), - AudioBufferInit, - AudioBufferMixdown - }; +{ + JACK_DEFAULT_AUDIO_TYPE, + AudioBufferSize, + AudioBufferInit, + AudioBufferMixdown +}; } // namespace Jack diff --git a/common/JackConnectionManager.cpp b/common/JackConnectionManager.cpp index f6a74dca..fcc3a025 100644 --- a/common/JackConnectionManager.cpp +++ b/common/JackConnectionManager.cpp @@ -12,7 +12,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License -along with this program; if not, write to the Free Software +along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ @@ -246,7 +246,7 @@ int JackConnectionManager::SuspendRefNum(JackClientControl* control, JackSynchro int JackConnectionManager::ResumeRefNum(JackClientControl* control, JackSynchro* table, JackClientTiming* timing) { jack_time_t current_date = GetMicroSeconds(); - const jack_int_t* outputRef = fConnectionRef.GetItems(control->fRefNum); + const jack_int_t* output_ref = fConnectionRef.GetItems(control->fRefNum); int res = 0; // Update state and timestamp of current client @@ -256,7 +256,7 @@ int JackConnectionManager::ResumeRefNum(JackClientControl* control, JackSynchro* for (int i = 0; i < CLIENT_NUM; i++) { // Signal connected clients or drivers - if (outputRef[i] > 0) { + if (output_ref[i] > 0) { // Update state and timestamp of destination clients timing[i].fStatus = Triggered; @@ -272,6 +272,33 @@ int JackConnectionManager::ResumeRefNum(JackClientControl* control, JackSynchro* return res; } +void JackConnectionManager::Visit(jack_int_t refnum, bool visited[CLIENT_NUM], std::vector& res) +{ + if (!visited[refnum]) { + visited[refnum] = true; + jack_int_t output_ref[CLIENT_NUM]; + fConnectionRef.GetOutputTable1(refnum, output_ref); + + //const jack_int_t* output_ref = fConnectionRef.GetItems(refnum); + for (int i = 0; i < CLIENT_NUM; i++) { + if (output_ref[i] > 0) + Visit(i, visited, res); + } + res.push_back(refnum); + } +} + +void JackConnectionManager::TopologicalSort(std::vector& sorted) +{ + bool visited[CLIENT_NUM]; + for (int i = 0; i < CLIENT_NUM; i++) { + visited[i] = false; + } + + Visit(AUDIO_DRIVER_REFNUM, visited, sorted); + Visit(FREEWHEEL_DRIVER_REFNUM, visited, sorted); +} + /*! \brief Increment the number of ports between 2 clients, if the 2 clients become connected, then the Activation counter is updated. */ diff --git a/common/JackConnectionManager.h b/common/JackConnectionManager.h index 5d5b8c62..7710d035 100644 --- a/common/JackConnectionManager.h +++ b/common/JackConnectionManager.h @@ -12,7 +12,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License -along with this program; if not, write to the Free Software +along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ @@ -25,6 +25,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "JackError.h" #include "JackCompilerDeps.h" +#include #include namespace Jack @@ -151,7 +152,7 @@ class JackFixedArray1 : public JackFixedArray return true; } } - + } POST_PACKED_STRUCTURE; /*! @@ -218,6 +219,13 @@ class JackFixedMatrix } } + void GetOutputTable1(jack_int_t index, jack_int_t* output) const + { + for (int i = 0; i < SIZE; i++) { + output[i] = fTable[i][index]; + } + } + bool IsInsideTable(jack_int_t index, jack_int_t* output) const { for (int i = 0; i < SIZE && output[i] != EMPTY; i++) { @@ -359,7 +367,7 @@ struct JackClientTiming } ~JackClientTiming() {} - + void Init() { fSignaledAt = 0; @@ -367,7 +375,7 @@ struct JackClientTiming fFinishedAt = 0; fStatus = NotTriggered; } - + } POST_PACKED_STRUCTURE; /*! @@ -398,6 +406,8 @@ class SERVER_EXPORT JackConnectionManager bool IsLoopPathAux(int ref1, int ref2) const; + void Visit(jack_int_t refnum, bool visited[CLIENT_NUM], std::vector& res); + public: JackConnectionManager(); @@ -461,7 +471,8 @@ class SERVER_EXPORT JackConnectionManager void ResetGraph(JackClientTiming* timing); int ResumeRefNum(JackClientControl* control, JackSynchro* table, JackClientTiming* timing); int SuspendRefNum(JackClientControl* control, JackSynchro* table, JackClientTiming* timing, long time_out_usec); - + void TopologicalSort(std::vector& sorted); + } POST_PACKED_STRUCTURE; } // end of namespace diff --git a/common/JackEngine.cpp b/common/JackEngine.cpp index 93f62946..80c96955 100644 --- a/common/JackEngine.cpp +++ b/common/JackEngine.cpp @@ -211,7 +211,27 @@ void JackEngine::CheckXRun(jack_time_t callback_usecs) // REVOIR les conditions int JackEngine::ComputeTotalLatencies() { - // TODO : jack_compute_new_latency + std::vector sorted; + std::vector::iterator it; + std::vector::reverse_iterator rit; + + fGraphManager->TopologicalSort(sorted); + + /* iterate over all clients in graph order, and emit + * capture latency callback. + */ + + for (it = sorted.begin(); it != sorted.end(); it++) { + jack_log("ComputeTotalLatencies %d", *it); + NotifyClient(*it, kLatencyCallback, true, "", 0, 0); + } + + /* now issue playback latency callbacks in reverse graph order + */ + for (rit = sorted.rbegin(); rit != sorted.rend(); rit++) { + NotifyClient(*rit, kLatencyCallback, true, "", 1, 0); + } + return 0; } diff --git a/common/JackGraphManager.cpp b/common/JackGraphManager.cpp index 22166317..9276ad87 100644 --- a/common/JackGraphManager.cpp +++ b/common/JackGraphManager.cpp @@ -127,6 +127,19 @@ int JackGraphManager::SuspendRefNum(JackClientControl* control, JackSynchro* tab return manager->SuspendRefNum(control, table, fClientTiming, usec); } +void JackGraphManager::TopologicalSort(std::vector& sorted) +{ + UInt16 cur_index; + UInt16 next_index; + + do { + cur_index = GetCurrentIndex(); + JackConnectionManager* manager = ReadCurrentState(); + manager->TopologicalSort(sorted); + next_index = GetCurrentIndex(); + } while (cur_index != next_index); // Until a coherent state has been read +} + // Server void JackGraphManager::DirectConnect(int ref1, int ref2) { diff --git a/common/JackGraphManager.h b/common/JackGraphManager.h index da5bf276..4f038ba8 100644 --- a/common/JackGraphManager.h +++ b/common/JackGraphManager.h @@ -124,6 +124,7 @@ class SERVER_EXPORT JackGraphManager : public JackShmMem, public JackAtomicState void InitRefNum(int refnum); int ResumeRefNum(JackClientControl* control, JackSynchro* table); int SuspendRefNum(JackClientControl* control, JackSynchro* table, long usecs); + void TopologicalSort(std::vector& sorted); JackClientTiming* GetClientTiming(int refnum) { diff --git a/common/JackMidiPort.cpp b/common/JackMidiPort.cpp index 1949ca0d..117b7a70 100644 --- a/common/JackMidiPort.cpp +++ b/common/JackMidiPort.cpp @@ -133,12 +133,17 @@ static void MidiBufferMixdown(void* mixbuffer, void** src_buffers, int src_count mix->lost_events += event_count - events_done; } +static size_t MidiBufferSize() +{ + return BUFFER_SIZE_MAX * sizeof(float); +} + const JackPortType gMidiPortType = - { - JACK_DEFAULT_MIDI_TYPE, - BUFFER_SIZE_MAX * sizeof(jack_default_audio_sample_t), - MidiBufferInit, - MidiBufferMixdown - }; +{ + JACK_DEFAULT_MIDI_TYPE, + MidiBufferSize, + MidiBufferInit, + MidiBufferMixdown +}; } // namespace Jack diff --git a/common/JackPortType.h b/common/JackPortType.h index c7507dd5..efb8ca2f 100644 --- a/common/JackPortType.h +++ b/common/JackPortType.h @@ -32,7 +32,7 @@ extern jack_port_type_id_t PORT_TYPES_MAX; struct JackPortType { const char* fName; - size_t fSize; + size_t (*size)(); void (*init)(void* buffer, size_t buffer_size, jack_nframes_t nframes); void (*mixdown)(void *mixbuffer, void** src_buffers, int src_count, jack_nframes_t nframes); }; diff --git a/common/JackServer.cpp b/common/JackServer.cpp index 126e7c4f..50894529 100644 --- a/common/JackServer.cpp +++ b/common/JackServer.cpp @@ -45,7 +45,7 @@ JackServer::JackServer(bool sync, bool temporary, int timeout, bool rt, int prio } else { jack_info("JACK server starting in non-realtime mode"); } - + fGraphManager = JackGraphManager::Allocate(port_max); fEngineControl = new JackEngineControl(sync, temporary, timeout, rt, priority, verbose, clock, server_name); fEngine = new JackLockedEngine(fGraphManager, GetSynchroTable(), fEngineControl); @@ -72,17 +72,17 @@ int JackServer::Open(jack_driver_desc_t* driver_desc, JSList* driver_params) { // TODO: move that in reworked JackServerGlobals::Init() JackMessageBuffer::Create(); - + if ((fAudioDriver = fDriverInfo->Open(driver_desc, fEngine, GetSynchroTable(), driver_params)) == NULL) { jack_error("Cannot initialize driver"); goto fail_close1; } - + if (fChannel.Open(fEngineControl->fServerName, this) < 0) { jack_error("Server channel open error"); goto fail_close2; } - + if (fEngine->Open() < 0) { jack_error("Cannot open engine"); goto fail_close3; @@ -92,12 +92,12 @@ int JackServer::Open(jack_driver_desc_t* driver_desc, JSList* driver_params) jack_error("Cannot open driver"); goto fail_close4; } - + if (fAudioDriver->Attach() < 0) { jack_error("Cannot attach audio driver"); goto fail_close5; } - + fFreewheelDriver->SetMaster(false); fAudioDriver->SetMaster(true); fAudioDriver->AddSlave(fFreewheelDriver); // After ??? @@ -113,11 +113,11 @@ fail_close4: fail_close3: fChannel.Close(); - -fail_close2: + +fail_close2: fAudioDriver->Close(); -fail_close1: +fail_close1: JackMessageBuffer::Destroy(); return -1; } @@ -190,7 +190,7 @@ int JackServer::SetBufferSize(jack_nframes_t buffer_size) jack_log("SetBufferSize: requirement for new buffer size equals current value"); return 0; } - + if (fAudioDriver->IsFixedBufferSize()) { jack_log("SetBufferSize: driver only supports a fixed buffer size"); return -1; @@ -316,37 +316,37 @@ int JackServer::SwitchMaster(jack_driver_desc_t* driver_desc, JSList* driver_par fAudioDriver->Stop(); fAudioDriver->Detach(); fAudioDriver->Close(); - + // Open new master JackDriverInfo* info = new JackDriverInfo(); JackDriverClientInterface* master = info->Open(driver_desc, fEngine, GetSynchroTable(), driver_params); - + if (master == NULL || info == NULL) { delete info; delete master; return -1; } else { - + // Get slaves list std::list slave_list = fAudioDriver->GetSlaves(); std::list::const_iterator it; - + // Move slaves in new master for (it = slave_list.begin(); it != slave_list.end(); it++) { JackDriverInterface* slave = *it; master->AddSlave(slave); } - + // Delete old master delete fAudioDriver; delete fDriverInfo; - + // Activate master fAudioDriver = master; fDriverInfo = info; fAudioDriver->Attach(); fAudioDriver->SetMaster(true); - return fAudioDriver->Start(); + return fAudioDriver->Start(); } } diff --git a/common/JackServerGlobals.h b/common/JackServerGlobals.h index 273912bc..f7d6e439 100644 --- a/common/JackServerGlobals.h +++ b/common/JackServerGlobals.h @@ -39,8 +39,8 @@ struct SERVER_EXPORT JackServerGlobals static JackServer* fInstance; static unsigned int fUserCount; static int fRTNotificationSocket; // For debugging purpose - static bool (* on_device_acquire)(const char * device_name); - static void (* on_device_release)(const char * device_name); + static bool (* on_device_acquire)(const char* device_name); + static void (* on_device_release)(const char* device_name); JackServerGlobals(); ~JackServerGlobals(); diff --git a/posix/JackSocketClientChannel.cpp b/posix/JackSocketClientChannel.cpp index b59f9751..23555c1d 100644 --- a/posix/JackSocketClientChannel.cpp +++ b/posix/JackSocketClientChannel.cpp @@ -108,7 +108,6 @@ int JackSocketClientChannel::Start() } } - void JackSocketClientChannel::Stop() { jack_log("JackSocketClientChannel::Stop");