Browse Source

New latency API implementation (in progress).

git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@4150 0c269be4-1314-0410-8aa9-9f06e86f4224
tags/1.9.7
sletz 14 years ago
parent
commit
ae99359963
12 changed files with 328 additions and 13 deletions
  1. +1
    -0
      ChangeLog
  2. +58
    -0
      common/JackAPI.cpp
  3. +33
    -0
      common/JackAudioDriver.cpp
  4. +4
    -0
      common/JackAudioDriver.h
  5. +119
    -0
      common/JackClient.cpp
  6. +5
    -0
      common/JackClient.h
  7. +5
    -5
      common/JackDriver.cpp
  8. +41
    -1
      common/JackGraphManager.cpp
  9. +4
    -0
      common/JackGraphManager.h
  10. +2
    -1
      common/JackNotification.h
  11. +49
    -5
      common/JackPort.cpp
  12. +7
    -1
      common/JackPort.h

+ 1
- 0
ChangeLog View File

@@ -39,6 +39,7 @@ Valerio Pilo
* Revert r4119 (RT notification in the server). JackAudioDriver::ProcessSync now skip backend write in case of graph process failure.
* Fix incorrect error codes in alsa/usx2y.c and alsa/JackAlsaDriver.cpp.
* Synchronize public headers with JACK1. Update OSX project.
* New latency API implementation (in progress).

2011-02-09 Stephane Letz <letz@grame.fr>



+ 58
- 0
common/JackAPI.cpp View File

@@ -115,6 +115,9 @@ extern "C"
void *);
EXPORT int jack_set_xrun_callback (jack_client_t *,
JackXRunCallback xrun_callback, void *arg);
EXPORT int jack_set_latency_callback (jack_client_t *client,
JackLatencyCallback callback, void *arg);

EXPORT int jack_activate (jack_client_t *client);
EXPORT int jack_deactivate (jack_client_t *client);
EXPORT jack_port_t * jack_port_register (jack_client_t *client,
@@ -138,12 +141,19 @@ extern "C"
const jack_port_t *port);
EXPORT int jack_port_tie (jack_port_t *src, jack_port_t *dst);
EXPORT int jack_port_untie (jack_port_t *port);

// Old latency API
EXPORT jack_nframes_t jack_port_get_latency (jack_port_t *port);
EXPORT jack_nframes_t jack_port_get_total_latency (jack_client_t *,
jack_port_t *port);
EXPORT void jack_port_set_latency (jack_port_t *, jack_nframes_t);
EXPORT int jack_recompute_total_latency (jack_client_t*, jack_port_t* port);

// New latency API
EXPORT void jack_port_get_latency_range (jack_port_t *port, jack_latency_callback_mode_t mode, jack_latency_range_t *range);
EXPORT void jack_port_set_latency_range (jack_port_t *port, jack_latency_callback_mode_t mode, jack_latency_range_t *range);
EXPORT int jack_recompute_total_latencies (jack_client_t*);

EXPORT int jack_port_set_name (jack_port_t *port, const char *port_name);
EXPORT int jack_port_set_alias (jack_port_t *port, const char *alias);
EXPORT int jack_port_unset_alias (jack_port_t *port, const char *alias);
@@ -526,6 +536,40 @@ EXPORT void jack_port_set_latency(jack_port_t* port, jack_nframes_t frames)
}
}

EXPORT void jack_port_get_latency_range(jack_port_t *port, jack_latency_callback_mode_t mode, jack_latency_range_t *range)
{
#ifdef __CLIENTDEBUG__
JackGlobals::CheckContext("jack_port_get_latency_range");
#endif
uintptr_t port_aux = (uintptr_t)port;
jack_port_id_t myport = (jack_port_id_t)port_aux;
if (!CheckPort(myport)) {
jack_error("jack_port_get_latency_range called with an incorrect port %ld", myport);
} else {
WaitGraphChange();
JackGraphManager* manager = GetGraphManager();
if (manager)
manager->GetPort(myport)->GetLatencyRange(mode, range);
}
}

EXPORT void jack_port_set_latency_range(jack_port_t *port, jack_latency_callback_mode_t mode, jack_latency_range_t *range)
{
#ifdef __CLIENTDEBUG__
JackGlobals::CheckContext("jack_port_set_latency_range");
#endif
uintptr_t port_aux = (uintptr_t)port;
jack_port_id_t myport = (jack_port_id_t)port_aux;
if (!CheckPort(myport)) {
jack_error("jack_port_set_latency_range called with an incorrect port %ld", myport);
} else {
WaitGraphChange();
JackGraphManager* manager = GetGraphManager();
if (manager)
manager->GetPort(myport)->SetLatencyRange(mode, range);
}
}

EXPORT int jack_recompute_total_latency(jack_client_t* ext_client, jack_port_t* port)
{
#ifdef __CLIENTDEBUG__
@@ -988,6 +1032,20 @@ EXPORT int jack_set_xrun_callback(jack_client_t* ext_client, JackXRunCallback xr
}
}

EXPORT int jack_set_latency_callback(jack_client_t *ext_client, JackLatencyCallback latency_callback, void *arg)
{
#ifdef __CLIENTDEBUG__
JackGlobals::CheckContext("jack_set_latency_callback");
#endif
JackClient* client = (JackClient*)ext_client;
if (client == NULL) {
jack_error("jack_set_latency_callback called with a NULL client");
return -1;
} else {
return client->SetLatencyCallback(latency_callback, arg);
}
}

EXPORT int jack_set_thread_init_callback(jack_client_t* ext_client, JackThreadInitCallback init_callback, void *arg)
{
#ifdef __CLIENTDEBUG__


+ 33
- 0
common/JackAudioDriver.cpp View File

@@ -335,4 +335,37 @@ jack_default_audio_sample_t* JackAudioDriver::GetMonitorBuffer(int port_index)
return (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fMonitorPortList[port_index], fEngineControl->fBufferSize);
}

int JackAudioDriver::ClientNotify(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2)
{
switch (notify) {

case kLatencyCallback:
HandleLatencyCallback(value1);
break;

default:
JackDriver::ClientNotify(refnum, name, notify, sync, message, value1, value2);
break;
}

return 0;
}

void JackAudioDriver::HandleLatencyCallback(int status)
{
jack_latency_callback_mode_t mode = (status == 0) ? JackCaptureLatency : JackPlaybackLatency;

for (int i = 0; i < fCaptureChannels; i++) {
if (mode == JackPlaybackLatency) {
fGraphManager->RecalculateLatency(fCapturePortList[i], mode);
}
}

for (int i = 0; i < fPlaybackChannels; i++) {
if (mode == JackCaptureLatency) {
fGraphManager->RecalculateLatency(fPlaybackPortList[i], mode);
}
}
}

} // end of namespace

+ 4
- 0
common/JackAudioDriver.h View File

@@ -57,6 +57,8 @@ class SERVER_EXPORT JackAudioDriver : public JackDriver
jack_default_audio_sample_t* GetOutputBuffer(int port_index);
jack_default_audio_sample_t* GetMonitorBuffer(int port_index);

void HandleLatencyCallback(int status);

public:

JackAudioDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table);
@@ -95,6 +97,8 @@ class SERVER_EXPORT JackAudioDriver : public JackDriver
virtual int SetBufferSize(jack_nframes_t buffer_size);
virtual int SetSampleRate(jack_nframes_t sample_rate);

virtual int ClientNotify(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2);

};

} // end of namespace


+ 119
- 0
common/JackClient.cpp View File

@@ -60,6 +60,9 @@ JackClient::JackClient(JackSynchro* table):fThread(this)
fTimebase = NULL;
fSync = NULL;
fThreadFun = NULL;
fSession = NULL;
fLatency = NULL;

fProcessArg = NULL;
fGraphOrderArg = NULL;
fXrunArg = NULL;
@@ -75,6 +78,8 @@ JackClient::JackClient(JackSynchro* table):fThread(this)
fSyncArg = NULL;
fTimebaseArg = NULL;
fThreadFunArg = NULL;
fSessionArg = NULL;
fLatencyArg = NULL;
}

JackClient::~JackClient()
@@ -289,12 +294,113 @@ int JackClient::ClientNotify(int refnum, const char* name, int notify, int sync,
res = (fImmediateSessionReply) ? 1 : 2;
}
break;

case kLatencyCallback:
res = HandleLatencyCallback(value1);
break;
}
}

return res;
}

int JackClient::HandleLatencyCallback(int status)
{
jack_latency_callback_mode_t mode = (status == 0) ? JackCaptureLatency : JackPlaybackLatency;
jack_latency_range_t latency = { UINT32_MAX, 0 };

/* first setup all latency values of the ports.
* this is based on the connections of the ports.
*/
list<jack_port_id_t>::iterator it;

for (it = fPortList.begin(); it != fPortList.end(); it++) {
JackPort* port = GetGraphManager()->GetPort(*it);

if ((port->GetFlags() & JackPortIsOutput) && (mode == JackPlaybackLatency)) {
GetGraphManager()->RecalculateLatency(*it, mode);
}
if ((port->GetFlags() & JackPortIsInput) && (mode == JackCaptureLatency)) {
GetGraphManager()->RecalculateLatency(*it, mode);
}
}

if (!fLatency) {
/*
* default action is to assume all ports depend on each other.
* then always take the maximum latency.
*/

if (mode == JackPlaybackLatency) {
/* iterate over all OutputPorts, to find maximum playback latency
*/
for (it = fPortList.begin(); it != fPortList.end(); it++) {
JackPort* port = GetGraphManager()->GetPort(*it);

if (port->GetFlags() & JackPortIsOutput) {
jack_latency_range_t other_latency;

port->GetLatencyRange(mode, &other_latency);
if (other_latency.max > latency.max)
latency.max = other_latency.max;
if (other_latency.min < latency.min)
latency.min = other_latency.min;
}
}

if (latency.min == UINT32_MAX)
latency.min = 0;

/* now set the found latency on all input ports
*/
for (it = fPortList.begin(); it != fPortList.end(); it++) {
JackPort* port = GetGraphManager()->GetPort(*it);

if (port->GetFlags() & JackPortIsInput) {
port->SetLatencyRange(mode, &latency);
}
}
}
if (mode == JackCaptureLatency) {
/* iterate over all InputPorts, to find maximum playback latency
*/
for (it = fPortList.begin(); it != fPortList.end(); it++) {
JackPort* port = GetGraphManager()->GetPort(*it);

if (port->GetFlags() & JackPortIsInput) {
jack_latency_range_t other_latency;

port->GetLatencyRange(mode, &other_latency);
if (other_latency.max > latency.max)
latency.max = other_latency.max;
if (other_latency.min < latency.min)
latency.min = other_latency.min;
}
}

if (latency.min == UINT32_MAX)
latency.min = 0;

/* now set the found latency on all output ports
*/
for (it = fPortList.begin(); it != fPortList.end(); it++) {
JackPort* port = GetGraphManager()->GetPort(*it);

if (port->GetFlags() & JackPortIsOutput) {
port->SetLatencyRange(mode, &latency);
}
}
}
return 0;
}

/* we have a latency callback setup by the client,
* lets use it...
*/
fLatency(mode, fLatencyArg);
return 0;
}

/*!
\brief We need to start thread before activating in the server, otherwise the FW driver
connected to the client may not be activated.
@@ -1011,6 +1117,19 @@ int JackClient::SetSessionCallback(JackSessionCallback callback, void *arg)
}
}

int JackClient::SetLatencyCallback(JackLatencyCallback callback, void *arg)
{
if (IsActive()) {
jack_error("You cannot set callbacks on an active client");
return -1;
} else {
GetClientControl()->fCallback[kLatencyCallback] = (callback != NULL);
fLatencyArg = arg;
fLatency = callback;
return 0;
}
}

//------------------
// Internal clients
//------------------


+ 5
- 0
common/JackClient.h View File

@@ -67,6 +67,7 @@ class JackClient : public JackClientInterface, public JackRunnableInterface
JackSyncCallback fSync;
JackThreadCallback fThreadFun;
JackSessionCallback fSession;
JackLatencyCallback fLatency;

void* fProcessArg;
void* fGraphOrderArg;
@@ -85,6 +86,7 @@ class JackClient : public JackClientInterface, public JackRunnableInterface
void* fSyncArg;
void* fThreadFunArg;
void* fSessionArg;
void* fLatencyArg;
char fServerName[64];

JackThread fThread; /*! Thread to execute the Process function */
@@ -116,6 +118,8 @@ class JackClient : public JackClientInterface, public JackRunnableInterface
inline void CallTimebaseCallbackAux();
inline int ActivateAux();

int HandleLatencyCallback(int status);

public:

JackClient();
@@ -178,6 +182,7 @@ class JackClient : public JackClientInterface, public JackRunnableInterface
virtual int SetPortConnectCallback(JackPortConnectCallback callback, void *arg);
virtual int SetPortRenameCallback(JackPortRenameCallback callback, void *arg);
virtual int SetSessionCallback(JackSessionCallback callback, void *arg);
virtual int SetLatencyCallback(JackLatencyCallback callback, void *arg);

// Internal clients
virtual char* GetInternalClientName(int ref);


+ 5
- 5
common/JackDriver.cpp View File

@@ -167,7 +167,7 @@ int JackDriver::Open(jack_nframes_t buffer_size,

int JackDriver::Close()
{
if (fClientControl.fRefNum >= 0) {
if (fClientControl.fRefNum >= 0) {
jack_log("JackDriver::Close");
fGraphManager->DirectDisconnect(fClientControl.fRefNum, fClientControl.fRefNum); // Disconnect driver from itself for sync
fClientControl.fActive = false;
@@ -207,7 +207,7 @@ int JackDriver::ClientNotify(int refnum, const char* name, int notify, int sync,
jack_log("JackDriver::kStopFreewheel");
SetupDriverSync(fClientControl.fRefNum, false);
break;
}
}

return 0;
}
@@ -223,13 +223,13 @@ void JackDriver::CycleIncTime()
}

void JackDriver::CycleTakeBeginTime()
{
{
fBeginDateUst = GetMicroSeconds(); // Take callback date here
fEngineControl->CycleIncTime(fBeginDateUst);
}

void JackDriver::CycleTakeEndTime()
{
{
fEndDateUst = GetMicroSeconds(); // Take end date here
}

@@ -254,7 +254,7 @@ void JackDriver::NotifySampleRate(jack_nframes_t sample_rate)
fEngine->NotifySampleRate(sample_rate);
fEngineControl->InitFrameTime();
}
void JackDriver::NotifyFailure(int code, const char* reason)
{
fEngine->NotifyFailure(code, reason);


+ 41
- 1
common/JackGraphManager.cpp View File

@@ -245,7 +245,7 @@ int JackGraphManager::RequestMonitor(jack_port_id_t port_index, bool onoff) // C
// Client
jack_nframes_t JackGraphManager::ComputeTotalLatencyAux(jack_port_id_t port_index, jack_port_id_t src_port_index, JackConnectionManager* manager, int hop_count)
{
const jack_int_t* connections = manager->GetConnections(port_index);
const jack_int_t* connections = ReadCurrentState()->GetConnections(port_index);
jack_nframes_t max_latency = 0;
jack_port_id_t dst_index;

@@ -296,6 +296,46 @@ int JackGraphManager::ComputeTotalLatencies()
return 0;
}

void JackGraphManager::RecalculateLatencyAux(jack_port_id_t port_index, jack_latency_callback_mode_t mode)
{
const jack_int_t* connections = ReadCurrentState()->GetConnections(port_index);
JackPort* port = GetPort(port_index);
jack_latency_range_t latency = { UINT32_MAX, 0 };
jack_port_id_t dst_index;

for (int i = 0; (i < CONNECTION_NUM_FOR_PORT) && ((dst_index = connections[i]) != EMPTY); i++) {
AssertPort(dst_index);
JackPort* dst_port = GetPort(dst_index);
jack_latency_range_t other_latency;

dst_port->GetLatencyRange(mode, &other_latency);

if (other_latency.max > latency.max)
latency.max = other_latency.max;
if (other_latency.min < latency.min)
latency.min = other_latency.min;
}

if (latency.min == UINT32_MAX)
latency.min = 0;

port->SetLatencyRange(mode, &latency);
}

void JackGraphManager::RecalculateLatency(jack_port_id_t port_index, jack_latency_callback_mode_t mode)
{
UInt16 cur_index;
UInt16 next_index;

do {
cur_index = GetCurrentIndex();
RecalculateLatencyAux(port_index, mode);
next_index = GetCurrentIndex();
} while (cur_index != next_index); // Until a coherent state has been read

jack_log("JackGraphManager::RecalculateLatency port_index = %ld", port_index);
}

// Server
void JackGraphManager::SetBufferSize(jack_nframes_t buffer_size)
{


+ 4
- 0
common/JackGraphManager.h View File

@@ -53,6 +53,7 @@ class SERVER_EXPORT JackGraphManager : public JackShmMem, public JackAtomicState
float* GetBuffer(jack_port_id_t port_index);
void* GetBufferAux(JackConnectionManager* manager, jack_port_id_t port_index, jack_nframes_t frames);
jack_nframes_t ComputeTotalLatencyAux(jack_port_id_t port_index, jack_port_id_t src_port_index, JackConnectionManager* manager, int hop_count);
void RecalculateLatencyAux(jack_port_id_t port_index, jack_latency_callback_mode_t mode);

public:

@@ -72,8 +73,11 @@ class SERVER_EXPORT JackGraphManager : public JackShmMem, public JackAtomicState

JackPort* GetPort(jack_port_id_t index);
jack_port_id_t GetPort(const char* name);

int ComputeTotalLatency(jack_port_id_t port_index);
int ComputeTotalLatencies();
void RecalculateLatency(jack_port_id_t port_index, jack_latency_callback_mode_t mode);

int RequestMonitor(jack_port_id_t port_index, bool onoff);

// Connections management


+ 2
- 1
common/JackNotification.h View File

@@ -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.

*/
@@ -46,6 +46,7 @@ enum NotificationType {
kShutDownCallback = 15,
kQUIT = 16,
kSessionCallback = 17,
kLatencyCallback = 18,
kMaxNotification
};



+ 49
- 5
common/JackPort.cpp View File

@@ -13,7 +13,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.

*/
@@ -44,6 +44,8 @@ bool JackPort::Allocate(int refnum, const char* port_name, const char* port_type
fInUse = true;
fLatency = 0;
fTotalLatency = 0;
fPlaybackLatency.min = fPlaybackLatency.max = 0;
fCaptureLatency.min = fCaptureLatency.max = 0;
fTied = NO_PORT;
// DB: At this point we do not know current buffer size in frames,
// but every time buffer will be returned to any user,
@@ -86,6 +88,48 @@ jack_nframes_t JackPort::GetTotalLatency() const
void JackPort::SetLatency(jack_nframes_t nframes)
{
fLatency = nframes;

/* setup the new latency values here,
* so we dont need to change the backend codes.
*/
if (fFlags & JackPortIsOutput) {
fCaptureLatency.min = nframes;
fCaptureLatency.max = nframes;
}
if (fFlags & JackPortIsInput) {
fPlaybackLatency.min = nframes;
fPlaybackLatency.max = nframes;
}
}

void JackPort::SetLatencyRange(jack_latency_callback_mode_t mode, jack_latency_range_t* range)
{
if (mode == JackCaptureLatency) {
fCaptureLatency = *range;

/* hack to set port->shared->latency up for
* backend ports
*/
if ((fFlags & JackPortIsOutput) && (fFlags & JackPortIsPhysical))
fLatency = (range->min + range->max) / 2;
} else {
fPlaybackLatency = *range;

/* hack to set port->shared->latency up for
* backend ports
*/
if ((fFlags & JackPortIsInput) && (fFlags & JackPortIsPhysical))
fLatency = (range->min + range->max) / 2;
}
}

void JackPort::GetLatencyRange(jack_latency_callback_mode_t mode, jack_latency_range_t* range) const
{
if (mode == JackCaptureLatency) {
*range = fCaptureLatency;
} else {
*range = fPlaybackLatency;
}
}

int JackPort::Tie(jack_port_id_t port_index)
@@ -103,10 +147,10 @@ int JackPort::UnTie()
int JackPort::RequestMonitor(bool onoff)
{
/**
jackd.h
jackd.h
* If @ref JackPortCanMonitor is set for this @a port, turn input
* monitoring on or off. Otherwise, do nothing.
if (!(fFlags & JackPortCanMonitor))
return -1;
*/
@@ -123,10 +167,10 @@ int JackPort::RequestMonitor(bool onoff)
int JackPort::EnsureMonitor(bool onoff)
{
/**
jackd.h
jackd.h
* If @ref JackPortCanMonitor is set for this @a port, turn input
* monitoring on or off. Otherwise, do nothing.
if (!(fFlags & JackPortCanMonitor))
return -1;
*/


+ 7
- 1
common/JackPort.h View File

@@ -51,6 +51,8 @@ class SERVER_EXPORT JackPort

jack_nframes_t fLatency;
jack_nframes_t fTotalLatency;
jack_latency_range_t fPlaybackLatency;
jack_latency_range_t fCaptureLatency;
uint8_t fMonitorRequests;

bool fInUse;
@@ -88,9 +90,13 @@ class SERVER_EXPORT JackPort
int UnTie();

jack_nframes_t GetLatency() const;
jack_nframes_t GetTotalLatency() const;
void SetLatency(jack_nframes_t latency);

void SetLatencyRange(jack_latency_callback_mode_t mode, jack_latency_range_t* range);
void GetLatencyRange(jack_latency_callback_mode_t mode, jack_latency_range_t* range) const;

jack_nframes_t GetTotalLatency() const;

int RequestMonitor(bool onoff);
int EnsureMonitor(bool onoff);
bool MonitoringInput()


Loading…
Cancel
Save