git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@4167 0c269be4-1314-0410-8aa9-9f06e86f4224tags/1.9.7
| @@ -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 <letz@grame.fr> | |||
| @@ -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(); | |||
| } | |||
| } | |||
| } | |||
| @@ -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 <string.h> | |||
| #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 | |||
| @@ -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<jack_int_t>& 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<jack_int_t>& 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. | |||
| */ | |||
| @@ -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 <vector> | |||
| #include <assert.h> | |||
| namespace Jack | |||
| @@ -151,7 +152,7 @@ class JackFixedArray1 : public JackFixedArray<SIZE> | |||
| 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<jack_int_t>& 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<jack_int_t>& sorted); | |||
| } POST_PACKED_STRUCTURE; | |||
| } // end of namespace | |||
| @@ -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<jack_int_t> sorted; | |||
| std::vector<jack_int_t>::iterator it; | |||
| std::vector<jack_int_t>::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; | |||
| } | |||
| @@ -127,6 +127,19 @@ int JackGraphManager::SuspendRefNum(JackClientControl* control, JackSynchro* tab | |||
| return manager->SuspendRefNum(control, table, fClientTiming, usec); | |||
| } | |||
| void JackGraphManager::TopologicalSort(std::vector<jack_int_t>& 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) | |||
| { | |||
| @@ -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<jack_int_t>& sorted); | |||
| JackClientTiming* GetClientTiming(int refnum) | |||
| { | |||
| @@ -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 | |||
| @@ -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); | |||
| }; | |||
| @@ -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<JackDriverInterface*> slave_list = fAudioDriver->GetSlaves(); | |||
| std::list<JackDriverInterface*>::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(); | |||
| } | |||
| } | |||
| @@ -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(); | |||
| @@ -108,7 +108,6 @@ int JackSocketClientChannel::Start() | |||
| } | |||
| } | |||
| void JackSocketClientChannel::Stop() | |||
| { | |||
| jack_log("JackSocketClientChannel::Stop"); | |||