git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@2526 0c269be4-1314-0410-8aa9-9f06e86f4224tags/1.90
@@ -185,12 +185,12 @@ int JackAudioDriver::Process() | |||
int JackAudioDriver::ProcessNull() | |||
{ | |||
JackDriver::CycleTakeTime(); | |||
JackDriver::CycleTakeBeginTime(); | |||
int wait_time_usec = (int((float(fEngineControl->fBufferSize) / (float(fEngineControl->fSampleRate))) * 1000000.0f)); | |||
JackSleep(wait_time_usec); | |||
if (!fEngine->Process(fLastWaitUst)) // fLastWaitUst is set in the "low level" layer | |||
if (!fEngine->Process(fBeginDateUst, fEndDateUst)) // fBeginDateUst is set in the "low level" layer, fEndDateUst is from previous cycle | |||
jack_error("JackAudioDriver::ProcessNull Process error"); | |||
fGraphManager->ResumeRefNum(fClientControl, fSynchroTable); | |||
if (ProcessSlaves() < 0) | |||
@@ -219,7 +219,8 @@ int JackAudioDriver::ProcessAsync() | |||
} | |||
if (fIsMaster) { | |||
if (!fEngine->Process(fLastWaitUst)) // fLastWaitUst is set in the "low level" layer | |||
// fBeginDateUst is set in the "low level" layer, fEndDateUst is from previous cycle | |||
if (!fEngine->Process(fBeginDateUst, fEndDateUst)) | |||
jack_error("JackAudioDriver::ProcessAsync Process error"); | |||
fGraphManager->ResumeRefNum(fClientControl, fSynchroTable); | |||
if (ProcessSlaves() < 0) | |||
@@ -227,6 +228,9 @@ int JackAudioDriver::ProcessAsync() | |||
} else { | |||
fGraphManager->ResumeRefNum(fClientControl, fSynchroTable); | |||
} | |||
// Keep end cycle time | |||
CycleTakeEndTime(); | |||
return 0; | |||
} | |||
@@ -245,7 +249,8 @@ int JackAudioDriver::ProcessSync() | |||
if (fIsMaster) { | |||
if (fEngine->Process(fLastWaitUst)) { // fLastWaitUst is set in the "low level" layer | |||
// fBeginDateUst is set in the "low level" layer, fEndDateUst is from previous cycle | |||
if (fEngine->Process(fBeginDateUst, fEndDateUst)) { | |||
fGraphManager->ResumeRefNum(fClientControl, fSynchroTable); | |||
if (ProcessSlaves() < 0) | |||
jack_error("JackAudioDriver::ProcessSync ProcessSlaves error, engine may now behave abnormally!!"); | |||
@@ -264,6 +269,9 @@ int JackAudioDriver::ProcessSync() | |||
} else { | |||
fGraphManager->ResumeRefNum(fClientControl, fSynchroTable); | |||
} | |||
// Keep end cycle time | |||
CycleTakeEndTime(); | |||
return 0; | |||
} | |||
@@ -51,7 +51,7 @@ JackDriver::JackDriver(const char* name, const char* alias, JackLockedEngine* en | |||
strcpy(fAliasName, alias); | |||
fEngine = engine; | |||
fGraphManager = NULL; | |||
fLastWaitUst = 0; | |||
fBeginDateUst = 0; | |||
fDelayedUsecs = 0.f; | |||
fIsMaster = true; | |||
} | |||
@@ -62,7 +62,7 @@ JackDriver::JackDriver() | |||
fClientControl = NULL; | |||
fEngine = NULL; | |||
fGraphManager = NULL; | |||
fLastWaitUst = 0; | |||
fBeginDateUst = 0; | |||
fIsMaster = true; | |||
} | |||
@@ -181,12 +181,18 @@ bool JackDriver::IsRealTime() const | |||
void JackDriver::CycleIncTime() | |||
{ | |||
fEngineControl->CycleIncTime(fLastWaitUst); | |||
fEngineControl->CycleIncTime(fBeginDateUst); | |||
} | |||
void JackDriver::CycleTakeTime() | |||
void JackDriver::CycleTakeBeginTime() | |||
{ | |||
fBeginDateUst = GetMicroSeconds(); // Take callback date here | |||
fEngineControl->CycleIncTime(fBeginDateUst); | |||
} | |||
void JackDriver::CycleTakeEndTime() | |||
{ | |||
fLastWaitUst = GetMicroSeconds(); // Take callback date here | |||
fEngineControl->CycleIncTime(fLastWaitUst); | |||
fEndDateUst = GetMicroSeconds(); // Take end date here | |||
} | |||
JackClientControl* JackDriver::GetClientControl() const | |||
@@ -194,9 +200,9 @@ JackClientControl* JackDriver::GetClientControl() const | |||
return fClientControl; | |||
} | |||
void JackDriver::NotifyXRun(jack_time_t callback_usecs, float delayed_usecs) | |||
void JackDriver::NotifyXRun(jack_time_t cur_cycle_begin, float delayed_usecs) | |||
{ | |||
fEngine->NotifyXRun(callback_usecs, delayed_usecs); | |||
fEngine->NotifyXRun(cur_cycle_begin, delayed_usecs); | |||
} | |||
void JackDriverClient::SetMaster(bool onoff) | |||
@@ -130,7 +130,8 @@ class EXPORT JackDriver : public JackDriverClient | |||
char fAliasName[JACK_CLIENT_NAME_SIZE + 1]; | |||
jack_nframes_t fCaptureLatency; | |||
jack_nframes_t fPlaybackLatency; | |||
jack_time_t fLastWaitUst; | |||
jack_time_t fBeginDateUst; | |||
jack_time_t fEndDateUst; | |||
float fDelayedUsecs; | |||
JackLockedEngine* fEngine; | |||
JackGraphManager* fGraphManager; | |||
@@ -141,7 +142,8 @@ class EXPORT JackDriver : public JackDriverClient | |||
JackClientControl* GetClientControl() const; | |||
void CycleIncTime(); | |||
void CycleTakeTime(); | |||
void CycleTakeBeginTime(); | |||
void CycleTakeEndTime(); | |||
public: | |||
@@ -65,9 +65,9 @@ int JackDummyDriver::Open(jack_nframes_t nframes, | |||
int JackDummyDriver::Process() | |||
{ | |||
JackDriver::CycleTakeTime(); | |||
JackDriver::CycleTakeBeginTime(); | |||
JackAudioDriver::Process(); | |||
JackSleep(std::max(0L, long(fWaitTime - (GetMicroSeconds() - fLastWaitUst)))); | |||
JackSleep(std::max(0L, long(fWaitTime - (GetMicroSeconds() - fBeginDateUst)))); | |||
return 0; | |||
} | |||
@@ -133,41 +133,41 @@ void JackEngine::ReleaseRefnum(int ref) | |||
// Graph management | |||
//------------------ | |||
void JackEngine::ProcessNext(jack_time_t callback_usecs) | |||
void JackEngine::ProcessNext(jack_time_t cur_cycle_begin) | |||
{ | |||
fLastSwitchUsecs = callback_usecs; | |||
fLastSwitchUsecs = cur_cycle_begin; | |||
if (fGraphManager->RunNextGraph()) // True if the graph actually switched to a new state | |||
fChannel.Notify(ALL_CLIENTS, kGraphOrderCallback, 0); | |||
fSignal.SignalAll(); // Signal for threads waiting for next cycle | |||
fSignal.SignalAll(); // Signal for threads waiting for next cycle | |||
} | |||
void JackEngine::ProcessCurrent(jack_time_t callback_usecs) | |||
void JackEngine::ProcessCurrent(jack_time_t cur_cycle_begin) | |||
{ | |||
if (callback_usecs < fLastSwitchUsecs + 2 * fEngineControl->fPeriodUsecs) // Signal XRun only for the first failing cycle | |||
CheckXRun(callback_usecs); | |||
if (cur_cycle_begin < fLastSwitchUsecs + 2 * fEngineControl->fPeriodUsecs) // Signal XRun only for the first failing cycle | |||
CheckXRun(cur_cycle_begin); | |||
fGraphManager->RunCurrentGraph(); | |||
} | |||
bool JackEngine::Process(jack_time_t callback_usecs) | |||
bool JackEngine::Process(jack_time_t cur_cycle_begin, jack_time_t prev_cycle_end) | |||
{ | |||
bool res = true; | |||
// Cycle begin | |||
fEngineControl->CycleBegin(fClientTable, fGraphManager, callback_usecs); | |||
fEngineControl->CycleBegin(fClientTable, fGraphManager, cur_cycle_begin, prev_cycle_end); | |||
// Graph | |||
if (fGraphManager->IsFinishedGraph()) { | |||
ProcessNext(callback_usecs); | |||
ProcessNext(cur_cycle_begin); | |||
res = true; | |||
} else { | |||
jack_log("Process: graph not finished!"); | |||
if (callback_usecs > fLastSwitchUsecs + fEngineControl->fTimeOutUsecs) { | |||
jack_log("Process: switch to next state delta = %ld", long(callback_usecs - fLastSwitchUsecs)); | |||
ProcessNext(callback_usecs); | |||
if (cur_cycle_begin > fLastSwitchUsecs + fEngineControl->fTimeOutUsecs) { | |||
jack_log("Process: switch to next state delta = %ld", long(cur_cycle_begin - fLastSwitchUsecs)); | |||
ProcessNext(cur_cycle_begin); | |||
res = true; | |||
} else { | |||
jack_log("Process: waiting to switch delta = %ld", long(callback_usecs - fLastSwitchUsecs)); | |||
ProcessCurrent(callback_usecs); | |||
jack_log("Process: waiting to switch delta = %ld", long(cur_cycle_begin - fLastSwitchUsecs)); | |||
ProcessCurrent(cur_cycle_begin); | |||
res = false; | |||
} | |||
} | |||
@@ -108,7 +108,7 @@ class EXPORT JackEngine | |||
int PortDisconnect(int refnum, jack_port_id_t src, jack_port_id_t dst); | |||
// Graph | |||
bool Process(jack_time_t callback_usecs); | |||
bool Process(jack_time_t cur_cycle_begin, jack_time_t prev_cycle_end); | |||
// Notifications | |||
void NotifyXRun(jack_time_t callback_usecs, float delayed_usecs); | |||
@@ -37,14 +37,17 @@ void JackEngineControl::CycleIncTime(jack_time_t callback_usecs) | |||
fFrameTimer.IncFrameTime(fBufferSize, callback_usecs, fPeriodUsecs); | |||
} | |||
void JackEngineControl::CycleBegin(JackClientInterface** table, JackGraphManager* manager, jack_time_t callback_usecs) | |||
void JackEngineControl::CycleBegin(JackClientInterface** table, | |||
JackGraphManager* manager, | |||
jack_time_t cur_cycle_begin, | |||
jack_time_t prev_cycle_end) | |||
{ | |||
// Transport | |||
fTransport.CycleBegin(fSampleRate, callback_usecs); | |||
fTransport.CycleBegin(fSampleRate, cur_cycle_begin); | |||
// Timing | |||
GetTimeMeasure(table, manager, callback_usecs); | |||
CalcCPULoad(table, manager); | |||
//GetTimeMeasure(table, manager, callback_usecs); | |||
CalcCPULoad(table, manager, cur_cycle_begin, prev_cycle_end); | |||
} | |||
void JackEngineControl::CycleEnd(JackClientInterface** table) | |||
@@ -57,9 +60,9 @@ void JackEngineControl::InitFrameTime() | |||
fFrameTimer.InitFrameTime(); | |||
} | |||
void JackEngineControl::ResetFrameTime(jack_time_t callback_usecs) | |||
void JackEngineControl::ResetFrameTime(jack_time_t cur_cycle_begin) | |||
{ | |||
fFrameTimer.ResetFrameTime(fSampleRate, callback_usecs, fPeriodUsecs); | |||
fFrameTimer.ResetFrameTime(fSampleRate, cur_cycle_begin, fPeriodUsecs); | |||
} | |||
void JackEngineControl::ReadFrameTime(JackTimer* timer) | |||
@@ -77,38 +80,41 @@ inline jack_time_t MAX(jack_time_t a, jack_time_t b) | |||
#define MAX(a,b) std::max((a),(b)) | |||
#endif | |||
void JackEngineControl::CalcCPULoad(JackClientInterface** table, JackGraphManager* manager) | |||
void JackEngineControl::CalcCPULoad(JackClientInterface** table, | |||
JackGraphManager* manager, | |||
jack_time_t cur_cycle_begin, | |||
jack_time_t prev_cycle_end) | |||
{ | |||
jack_time_t lastCycleEnd = fLastProcessTime; | |||
for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) { | |||
JackClientInterface* client = table[i]; | |||
JackClientTiming* timing = manager->GetClientTiming(i); | |||
if (client && client->GetClientControl()->fActive && timing->fStatus == Finished) { | |||
lastCycleEnd = MAX(lastCycleEnd, timing->fFinishedAt); | |||
fPrevCycleTime = fCurCycleTime; | |||
fCurCycleTime = cur_cycle_begin; | |||
jack_time_t last_cycle_end = prev_cycle_end; | |||
// In Asynchronous mode, last cycle end is the max of client end dates | |||
if (!fSyncMode) { | |||
for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) { | |||
JackClientInterface* client = table[i]; | |||
JackClientTiming* timing = manager->GetClientTiming(i); | |||
if (client && client->GetClientControl()->fActive && timing->fStatus == Finished) | |||
last_cycle_end = MAX(last_cycle_end, timing->fFinishedAt); | |||
} | |||
} | |||
/* store the execution time for later averaging */ | |||
fRollingClientUsecs[fRollingClientUsecsIndex++] = lastCycleEnd - fLastTime; | |||
if (fRollingClientUsecsIndex >= JACK_ENGINE_ROLLING_COUNT) { | |||
// Store the execution time for later averaging | |||
fRollingClientUsecs[fRollingClientUsecsIndex++] = last_cycle_end - fPrevCycleTime; | |||
if (fRollingClientUsecsIndex >= JACK_ENGINE_ROLLING_COUNT) | |||
fRollingClientUsecsIndex = 0; | |||
} | |||
/* every so often, recompute the current maximum use over the | |||
last JACK_ENGINE_ROLLING_COUNT client iterations. | |||
*/ | |||
// Every so often, recompute the current maximum use over the | |||
// last JACK_ENGINE_ROLLING_COUNT client iterations. | |||
if (++fRollingClientUsecsCnt % fRollingInterval == 0) { | |||
jack_time_t maxUsecs = 0; | |||
for (int i = 0; i < JACK_ENGINE_ROLLING_COUNT; i++) { | |||
maxUsecs = MAX(fRollingClientUsecs[i], maxUsecs); | |||
} | |||
fMaxUsecs = MAX(fMaxUsecs, maxUsecs); | |||
fSpareUsecs = jack_time_t((maxUsecs < fPeriodUsecs) ? fPeriodUsecs - maxUsecs : 0); | |||
jack_time_t max_usecs = 0; | |||
for (int i = 0; i < JACK_ENGINE_ROLLING_COUNT; i++) | |||
max_usecs = MAX(fRollingClientUsecs[i], max_usecs); | |||
fMaxUsecs = MAX(fMaxUsecs, max_usecs); | |||
fSpareUsecs = jack_time_t((max_usecs < fPeriodUsecs) ? fPeriodUsecs - max_usecs : 0); | |||
fCPULoad = ((1.f - (float(fSpareUsecs) / float(fPeriodUsecs))) * 50.f + (fCPULoad * 0.5f)); | |||
} | |||
} | |||
@@ -119,48 +125,7 @@ void JackEngineControl::ResetRollingUsecs() | |||
fRollingClientUsecsIndex = 0; | |||
fRollingClientUsecsCnt = 0; | |||
fSpareUsecs = 0; | |||
fRollingInterval = (int)floor((JACK_ENGINE_ROLLING_INTERVAL * 1000.f) / fPeriodUsecs); | |||
} | |||
void JackEngineControl::GetTimeMeasure(JackClientInterface** table, JackGraphManager* manager, jack_time_t callback_usecs) | |||
{ | |||
int pos = (++fAudioCycle) % TIME_POINTS; | |||
fLastTime = fCurTime; | |||
fCurTime = callback_usecs; | |||
fLastProcessTime = fProcessTime; | |||
fProcessTime = GetMicroSeconds(); | |||
if (fLastTime > 0) { | |||
fMeasure[pos].fEngineTime = fLastTime; | |||
fMeasure[pos].fAudioCycle = fAudioCycle; | |||
for (int i = 0; i < CLIENT_NUM; i++) { | |||
JackClientInterface* client = table[i]; | |||
JackClientTiming* timing = manager->GetClientTiming(i); | |||
if (client && client->GetClientControl()->fActive) { | |||
fMeasure[pos].fClientTable[i].fRefNum = i; | |||
fMeasure[pos].fClientTable[i].fSignaledAt = timing->fSignaledAt; | |||
fMeasure[pos].fClientTable[i].fAwakeAt = timing->fAwakeAt; | |||
fMeasure[pos].fClientTable[i].fFinishedAt = timing->fFinishedAt; | |||
fMeasure[pos].fClientTable[i].fStatus = timing->fStatus; | |||
} | |||
} | |||
} | |||
} | |||
void JackEngineControl::ClearTimeMeasures() | |||
{ | |||
for (int i = 0; i < TIME_POINTS; i++) { | |||
for (int j = 0; j < CLIENT_NUM; j++) { | |||
fMeasure[i].fClientTable[j].fRefNum = 0; | |||
fMeasure[i].fClientTable[j].fSignaledAt = 0; | |||
fMeasure[i].fClientTable[j].fAwakeAt = 0; | |||
fMeasure[i].fClientTable[j].fFinishedAt = 0; | |||
} | |||
} | |||
fLastTime = fCurTime = 0; | |||
fRollingInterval = int(floor((JACK_ENGINE_ROLLING_INTERVAL * 1000.f) / fPeriodUsecs)); | |||
} | |||
void JackEngineControl::NotifyXRun(float delayed_usecs) | |||
@@ -33,34 +33,9 @@ namespace Jack | |||
class JackClientInterface; | |||
class JackGraphManager; | |||
#define TIME_POINTS 1000 | |||
#define JACK_ENGINE_ROLLING_COUNT 32 | |||
#define JACK_ENGINE_ROLLING_INTERVAL 1024 | |||
/*! | |||
\brief Timing stucture for a client. | |||
*/ | |||
struct JackTimingMeasureClient | |||
{ | |||
int fRefNum; | |||
jack_time_t fSignaledAt; | |||
jack_time_t fAwakeAt; | |||
jack_time_t fFinishedAt; | |||
jack_client_state_t fStatus; | |||
}; | |||
/*! | |||
\brief Timing stucture for a table of clients. | |||
*/ | |||
struct JackTimingMeasure | |||
{ | |||
unsigned int fAudioCycle; | |||
jack_time_t fEngineTime; | |||
JackTimingMeasureClient fClientTable[CLIENT_NUM]; | |||
}; | |||
/*! | |||
\brief Engine control in shared memory. | |||
*/ | |||
@@ -83,15 +58,11 @@ struct EXPORT JackEngineControl : public JackShmMem | |||
JackTransportEngine fTransport; | |||
bool fVerbose; | |||
// Timing | |||
JackTimingMeasure fMeasure[TIME_POINTS]; | |||
jack_time_t fLastTime; | |||
jack_time_t fCurTime; | |||
jack_time_t fProcessTime; | |||
jack_time_t fLastProcessTime; | |||
// CPU Load | |||
jack_time_t fPrevCycleTime; | |||
jack_time_t fCurCycleTime; | |||
jack_time_t fSpareUsecs; | |||
jack_time_t fMaxUsecs; | |||
unsigned int fAudioCycle; | |||
jack_time_t fRollingClientUsecs[JACK_ENGINE_ROLLING_COUNT]; | |||
int fRollingClientUsecsCnt; | |||
int fRollingClientUsecsIndex; | |||
@@ -118,14 +89,10 @@ struct EXPORT JackEngineControl : public JackShmMem | |||
fRealTime = rt; | |||
fPriority = priority; | |||
fVerbose = verbose; | |||
fLastTime = 0; | |||
fCurTime = 0; | |||
fProcessTime = 0; | |||
fLastProcessTime = 0; | |||
fPrevCycleTime = 0; | |||
fCurCycleTime = 0; | |||
fSpareUsecs = 0; | |||
fMaxUsecs = 0; | |||
fAudioCycle = 0; | |||
ClearTimeMeasures(); | |||
ResetRollingUsecs(); | |||
snprintf(fServerName, sizeof(fServerName), server_name); | |||
fPeriod = 0; | |||
@@ -139,7 +106,7 @@ struct EXPORT JackEngineControl : public JackShmMem | |||
// Cycle | |||
void CycleIncTime(jack_time_t callback_usecs); | |||
void CycleBegin(JackClientInterface** table, JackGraphManager* manager, jack_time_t callback_usecs); | |||
void CycleBegin(JackClientInterface** table, JackGraphManager* manager, jack_time_t cur_cycle_begin, jack_time_t prev_cycle_end); | |||
void CycleEnd(JackClientInterface** table); | |||
// Timer | |||
@@ -152,9 +119,7 @@ struct EXPORT JackEngineControl : public JackShmMem | |||
void ResetXRun(); | |||
// Private | |||
void CalcCPULoad(JackClientInterface** table, JackGraphManager* manager); | |||
void GetTimeMeasure(JackClientInterface** table, JackGraphManager* manager, jack_time_t callback_usecs); | |||
void ClearTimeMeasures(); | |||
void CalcCPULoad(JackClientInterface** table, JackGraphManager* manager, jack_time_t cur_cycle_begin, jack_time_t prev_cycle_end); | |||
void ResetRollingUsecs(); | |||
}; | |||
@@ -0,0 +1,75 @@ | |||
/* | |||
Copyright (C) 2003 Paul Davis | |||
Copyright (C) 2004-2008 Grame | |||
This program is free software; you can redistribute it and/or modify | |||
it under the terms of the GNU Lesser General Public License as published by | |||
the Free Software Foundation; either version 2.1 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 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 | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
#if defined(HAVE_CONFIG_H) | |||
#include "config.h" | |||
#endif | |||
#include "JackEngineTiming.h" | |||
#include "JackGraphManager.h" | |||
#include "JackClientControl.h" | |||
#include "JackClientInterface.h" | |||
#include "JackTime.h" | |||
namespace Jack | |||
{ | |||
void JackEngineTiming::GetTimeMeasure(JackClientInterface** table, | |||
JackGraphManager* manager, | |||
jack_time_t cur_cycle_begin, | |||
jack_time_t prev_cycle_end) | |||
{ | |||
int pos = (++fAudioCycle) % TIME_POINTS; | |||
fPrevCycleTime = fCurCycleTime; | |||
fCurCycleTime = cur_cycle_begin; | |||
if (fPrevCycleTime > 0) { | |||
fMeasure[pos].fEngineTime = fPrevCycleTime; | |||
fMeasure[pos].fAudioCycle = fAudioCycle; | |||
for (int i = 0; i < CLIENT_NUM; i++) { | |||
JackClientInterface* client = table[i]; | |||
JackClientTiming* timing = manager->GetClientTiming(i); | |||
if (client && client->GetClientControl()->fActive) { | |||
fMeasure[pos].fClientTable[i].fRefNum = i; | |||
fMeasure[pos].fClientTable[i].fSignaledAt = timing->fSignaledAt; | |||
fMeasure[pos].fClientTable[i].fAwakeAt = timing->fAwakeAt; | |||
fMeasure[pos].fClientTable[i].fFinishedAt = timing->fFinishedAt; | |||
fMeasure[pos].fClientTable[i].fStatus = timing->fStatus; | |||
} | |||
} | |||
} | |||
} | |||
void JackEngineTiming::ClearTimeMeasures() | |||
{ | |||
for (int i = 0; i < TIME_POINTS; i++) { | |||
for (int j = 0; j < CLIENT_NUM; j++) { | |||
fMeasure[i].fClientTable[j].fRefNum = 0; | |||
fMeasure[i].fClientTable[j].fSignaledAt = 0; | |||
fMeasure[i].fClientTable[j].fAwakeAt = 0; | |||
fMeasure[i].fClientTable[j].fFinishedAt = 0; | |||
} | |||
} | |||
fPrevCycleTime = fCurCycleTime = 0; | |||
} | |||
} // end of namespace |
@@ -0,0 +1,87 @@ | |||
/* | |||
Copyright (C) 2003 Paul Davis | |||
Copyright (C) 2004-2008 Grame | |||
This program is free software; you can redistribute it and/or modify | |||
it under the terms of the GNU Lesser General Public License as published by | |||
the Free Software Foundation; either version 2.1 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 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 | |||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
#ifndef __JackEngineTiming__ | |||
#define __JackEngineTiming__ | |||
#include "types.h" | |||
#include "JackTypes.h" | |||
#include "JackConstants.h" | |||
namespace Jack | |||
{ | |||
#define TIME_POINTS 1000 | |||
/*! | |||
\brief Timing stucture for a client. | |||
*/ | |||
struct JackTimingMeasureClient | |||
{ | |||
int fRefNum; | |||
jack_time_t fSignaledAt; | |||
jack_time_t fAwakeAt; | |||
jack_time_t fFinishedAt; | |||
jack_client_state_t fStatus; | |||
}; | |||
/*! | |||
\brief Timing stucture for a table of clients. | |||
*/ | |||
struct JackTimingMeasure | |||
{ | |||
unsigned int fAudioCycle; | |||
jack_time_t fEngineTime; | |||
JackTimingMeasureClient fClientTable[CLIENT_NUM]; | |||
}; | |||
/*! | |||
\brief Client timing. | |||
*/ | |||
class JackClientInterface; | |||
class JackGraphManager; | |||
class JackEngineTiming | |||
{ | |||
private: | |||
JackTimingMeasure fMeasure[TIME_POINTS]; | |||
unsigned int fAudioCycle; | |||
jack_time_t fPrevCycleTime; | |||
jack_time_t fCurCycleTime; | |||
public: | |||
JackEngineTiming():fAudioCycle(0),fPrevCycleTime(0),fCurCycleTime(0) | |||
{} | |||
~JackEngineTiming() | |||
{} | |||
void GetTimeMeasure(JackClientInterface** table, JackGraphManager* manager, jack_time_t cur_cycle_begin, jack_time_t prev_cycle_end); | |||
void ClearTimeMeasures(); | |||
}; | |||
} // end of namespace | |||
#endif |
@@ -37,8 +37,8 @@ int JackFreewheelDriver::Process() | |||
{ | |||
if (fIsMaster) { | |||
jack_log("JackFreewheelDriver::Process master %lld", fEngineControl->fTimeOutUsecs); | |||
JackDriver::CycleTakeTime(); | |||
fEngine->Process(fLastWaitUst); | |||
JackDriver::CycleTakeBeginTime(); | |||
fEngine->Process(fBeginDateUst, fEndDateUst); | |||
fGraphManager->ResumeRefNum(fClientControl, fSynchroTable); // Signal all clients | |||
if (fGraphManager->SuspendRefNum(fClientControl, fSynchroTable, FREEWHEEL_DRIVER_TIMEOUT * 1000000) < 0) { // Wait for all clients to finish for 10 sec | |||
jack_error("JackFreewheelDriver::ProcessSync SuspendRefNum error"); | |||
@@ -146,17 +146,17 @@ class EXPORT JackLockedEngine : public JackLockAble | |||
} | |||
// Graph | |||
bool Process(jack_time_t callback_usecs) | |||
bool Process(jack_time_t cur_cycle_begin, jack_time_t prev_cycle_end) | |||
{ | |||
// RT : no lock | |||
return fEngine.Process(callback_usecs); | |||
return fEngine.Process(cur_cycle_begin, prev_cycle_end); | |||
} | |||
// Notifications | |||
void NotifyXRun(jack_time_t callback_usecs, float delayed_usecs) | |||
void NotifyXRun(jack_time_t cur_cycle_begin, float delayed_usecs) | |||
{ | |||
// RT : no lock | |||
fEngine.NotifyXRun(callback_usecs, delayed_usecs); | |||
fEngine.NotifyXRun(cur_cycle_begin, delayed_usecs); | |||
} | |||
void NotifyXRun(int refnum) | |||
@@ -475,7 +475,7 @@ namespace Jack | |||
} | |||
while ( !rx_bytes && ( rx_head->fDataType != 's' ) ); | |||
JackDriver::CycleTakeTime(); | |||
JackDriver::CycleTakeBeginTime(); | |||
//audio, midi or sync if driver is late | |||
if ( fParams.fSendMidiChannels || fParams.fSendAudioChannels ) | |||
@@ -1343,7 +1343,7 @@ JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *stat | |||
poll_ret = jack_get_microseconds (); | |||
// steph | |||
fLastWaitUst = poll_ret; | |||
fBeginDateUst = poll_ret; | |||
if (extra_fd < 0) { | |||
if (driver->poll_next && poll_ret > driver->poll_next) { | |||
@@ -2291,7 +2291,7 @@ int JackAlsaDriver::Read() | |||
* clients about the delay. | |||
*/ | |||
jack_log("ALSA XRun"); | |||
NotifyXRun(fLastWaitUst, fDelayedUsecs); | |||
NotifyXRun(fBeginDateUst, fDelayedUsecs); | |||
return -1; | |||
} | |||
@@ -301,7 +301,7 @@ JackFFADODriver::ffado_driver_wait (ffado_driver_t *driver, int extra_fd, int *s | |||
return 0; | |||
} | |||
fLastWaitUst = wait_ret; | |||
fBeginDateUst = wait_ret; | |||
printExit(); | |||
return driver->period_size; | |||
@@ -398,7 +398,7 @@ JackFFADODriver::ffado_driver_new (const char *name, | |||
/* prepare all parameters */ | |||
driver->sample_rate = params->sample_rate; | |||
driver->period_size = params->period_size; | |||
fLastWaitUst = 0; | |||
fBeginDateUst = 0; | |||
driver->period_usecs = | |||
(jack_time_t) floor ((((float) driver->period_size) * 1000000.0f) / driver->sample_rate); | |||
@@ -743,7 +743,7 @@ int JackFFADODriver::Read() | |||
* clients about the delay. | |||
*/ | |||
jack_log("FFADO XRun"); | |||
NotifyXRun(fLastWaitUst, fDelayedUsecs); | |||
NotifyXRun(fBeginDateUst, fDelayedUsecs); | |||
return -1; | |||
} | |||
@@ -195,7 +195,7 @@ JackFreebobDriver::freebob_driver_wait (freebob_driver_t *driver, int extra_fd, | |||
} | |||
*status = 0; | |||
fLastWaitUst = wait_ret; | |||
fBeginDateUst = wait_ret; | |||
// FIXME: this should do something more usefull | |||
*delayed_usecs = 0; | |||
@@ -316,7 +316,7 @@ JackFreebobDriver::freebob_driver_new (char *name, | |||
/* prepare all parameters */ | |||
driver->sample_rate = params->sample_rate; | |||
driver->period_size = params->period_size; | |||
fLastWaitUst = 0; | |||
fBeginDateUst = 0; | |||
driver->period_usecs = | |||
(jack_time_t) floor ((((float) driver->period_size) * 1000000.0f) / driver->sample_rate); | |||
@@ -875,7 +875,7 @@ int JackFreebobDriver::Read() | |||
* clients about the delay. | |||
*/ | |||
jack_log("FreeBoB XRun"); | |||
NotifyXRun(fLastWaitUst, fDelayedUsecs); | |||
NotifyXRun(fBeginDateUst, fDelayedUsecs); | |||
return -1; | |||
} | |||
@@ -177,7 +177,7 @@ OSStatus JackCoreAudioDriver::Render(void *inRefCon, | |||
driver->fActionFags = ioActionFlags; | |||
driver->fCurrentTime = (AudioTimeStamp *)inTimeStamp; | |||
driver->fDriverOutputData = ioData; | |||
driver->CycleTakeTime(); | |||
driver->CycleTakeBeginTime(); | |||
return driver->Process(); | |||
} | |||
@@ -258,7 +258,7 @@ OSStatus JackCoreAudioDriver::DeviceNotificationCallback(AudioDeviceID inDevice, | |||
case kAudioDeviceProcessorOverload: | |||
jack_log("JackCoreAudioDriver::DeviceNotificationCallback kAudioDeviceProcessorOverload"); | |||
jack_time_t cur_time = GetMicroSeconds(); | |||
driver->NotifyXRun(cur_time, float(cur_time - driver->fLastWaitUst)); // Better this value than nothing... | |||
driver->NotifyXRun(cur_time, float(cur_time - driver->fBeginDateUst)); // Better this value than nothing... | |||
break; | |||
case kAudioDevicePropertyStreamConfiguration: | |||
@@ -482,6 +482,8 @@ | |||
4B80D7EB0BA0D17400F035BB /* JackMidiPort.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B80D7E50BA0D17400F035BB /* JackMidiPort.h */; }; | |||
4B80D7EC0BA0D17400F035BB /* JackMidiPort.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B80D7E60BA0D17400F035BB /* JackMidiPort.cpp */; }; | |||
4B80D7ED0BA0D17400F035BB /* JackMidiAPI.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B80D7E70BA0D17400F035BB /* JackMidiAPI.cpp */; }; | |||
4B8F3D4B0E06C4A10096D19C /* JackEngineTiming.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B8F3D490E06C4A10096D19C /* JackEngineTiming.cpp */; }; | |||
4B8F3D4C0E06C4A10096D19C /* JackEngineTiming.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B8F3D4A0E06C4A10096D19C /* JackEngineTiming.h */; }; | |||
4B95BCAC0D913064000F7695 /* JackControl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B95BCAB0D913064000F7695 /* JackControl.cpp */; }; | |||
4B95BCAE0D913073000F7695 /* control.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B95BCAD0D913073000F7695 /* control.h */; settings = {ATTRIBUTES = (Public, ); }; }; | |||
4B978DED0A31D099009E2DD1 /* JackPortAudioDriver.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B978DEB0A31D099009E2DD1 /* JackPortAudioDriver.h */; }; | |||
@@ -1241,6 +1243,8 @@ | |||
4B869D7F08C9CB00001CF041 /* JackDriverLoader.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = JackDriverLoader.cpp; path = ../common/JackDriverLoader.cpp; sourceTree = SOURCE_ROOT; }; | |||
4B89B759076B731100D170DE /* JackRPCClientUser.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = JackRPCClientUser.c; path = RPC/JackRPCClientUser.c; sourceTree = SOURCE_ROOT; }; | |||
4B89B769076B74D200D170DE /* JackRPCEngineUser.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = JackRPCEngineUser.c; path = RPC/JackRPCEngineUser.c; sourceTree = SOURCE_ROOT; }; | |||
4B8F3D490E06C4A10096D19C /* JackEngineTiming.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackEngineTiming.cpp; path = ../common/JackEngineTiming.cpp; sourceTree = SOURCE_ROOT; }; | |||
4B8F3D4A0E06C4A10096D19C /* JackEngineTiming.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackEngineTiming.h; path = ../common/JackEngineTiming.h; sourceTree = SOURCE_ROOT; }; | |||
4B940B9B06DDDE5B00D77F60 /* AudioHardware.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = AudioHardware.h; path = /System/Library/Frameworks/CoreAudio.framework/Versions/A/Headers/AudioHardware.h; sourceTree = "<absolute>"; }; | |||
4B95BCAB0D913064000F7695 /* JackControl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackControl.cpp; path = ../common/JackControl.cpp; sourceTree = SOURCE_ROOT; }; | |||
4B95BCAD0D913073000F7695 /* control.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = control.h; path = ../common/jack/control.h; sourceTree = SOURCE_ROOT; }; | |||
@@ -2288,6 +2292,8 @@ | |||
4B2C28F908DAD01E00249230 /* JackGlobals.cpp */, | |||
4BF8D2190834F03D00C94B91 /* JackEngineControl.h */, | |||
4B6F7AEC0CD0CDBD00F48A9D /* JackEngineControl.cpp */, | |||
4B8F3D4A0E06C4A10096D19C /* JackEngineTiming.h */, | |||
4B8F3D490E06C4A10096D19C /* JackEngineTiming.cpp */, | |||
4BD4B4D409BACD9600750C0F /* JackTransportEngine.h */, | |||
4BD4B4D509BACD9600750C0F /* JackTransportEngine.cpp */, | |||
4BF8D2220834F05C00C94B91 /* JackServer.h */, | |||
@@ -3034,6 +3040,7 @@ | |||
4B5F253E0DEE9B8F0041E486 /* JackLockedEngine.h in Headers */, | |||
4BBC93BB0DF9736C002DF220 /* JackWaitThreadedDriver.h in Headers */, | |||
4B4CA9750E02CF9600F4BFDA /* JackRestartThreadedDriver.h in Headers */, | |||
4B8F3D4C0E06C4A10096D19C /* JackEngineTiming.h in Headers */, | |||
); | |||
runOnlyForDeploymentPostprocessing = 0; | |||
}; | |||
@@ -5631,6 +5638,7 @@ | |||
4B4F9C8C0DC20C0400706CB0 /* JackMessageBuffer.cpp in Sources */, | |||
4BBC93BA0DF9736C002DF220 /* JackWaitThreadedDriver.cpp in Sources */, | |||
4B4CA9760E02CF9600F4BFDA /* JackRestartThreadedDriver.cpp in Sources */, | |||
4B8F3D4B0E06C4A10096D19C /* JackEngineTiming.cpp in Sources */, | |||
); | |||
runOnlyForDeploymentPostprocessing = 0; | |||
}; | |||
@@ -227,7 +227,7 @@ int JackPortAudioDriver::Render(const void* inputBuffer, void* outputBuffer, | |||
driver->fOutputBuffer = (float**)outputBuffer; | |||
// Setup threadded based log function | |||
set_threaded_log_function(); | |||
driver->CycleTakeTime(); | |||
driver->CycleTakeBeginTime(); | |||
return (driver->Process() == 0) ? paContinue : paAbort; | |||
} | |||