Conflicts: common/JackControlAPI.cpptags/1.9.9.5
@@ -0,0 +1,4 @@ | |||
build/ | |||
man/*.1 | |||
.waf* | |||
.lock* |
@@ -36,6 +36,88 @@ John Emmas | |||
Jackdmp changes log | |||
--------------------------- | |||
2012-03-15 Stephane Letz <letz@grame.fr> | |||
* POST_PACKED_STRUCTURE used for jack_latency_range_t type. | |||
2012-03-09 Stephane Letz <letz@grame.fr> | |||
* Remove JACK_32_64 flag, so POST_PACKED_STRUCTURE now always used. | |||
2012-02-10 Stephane Letz <letz@grame.fr> | |||
* Improve libjacknet master mode. | |||
2012-02-09 Stephane Letz <letz@grame.fr> | |||
* In control API, UNIX like sigset_t replaced by more abstract jackctl_sigmask_t * opaque struct. | |||
2012-02-01 Stephane Letz <letz@grame.fr> | |||
* Check server API callback from notification thread. | |||
* Use a time-out in notification channel write function. | |||
* Fix lock management in JackEngine. | |||
2012-01-29 Stephane Letz <letz@grame.fr> | |||
* A bit more robust JackMessageBuffer implementation (in progress). | |||
2012-01-27 Stephane Letz <letz@grame.fr> | |||
* Rename JackProcessSync in JackPosixProcessSync. | |||
2012-01-26 Stephane Letz <letz@grame.fr> | |||
* Add EndTime function (especially for Windows). | |||
2012-01-25 Stephane Letz <letz@grame.fr> | |||
* Fix NetJack2 initialisation bug. | |||
2012-01-24 Stephane Letz <letz@grame.fr> | |||
* Improve ShutDown in NetManager. | |||
* Correct ShutDown in JackInternalClient and JackLibClient. | |||
2012-01-20 Stephane Letz <letz@grame.fr> | |||
* Experimental system port alias use in WIndows JackRouter. | |||
2012-01-19 Stephane Letz <letz@grame.fr> | |||
* Implement shutdown for in server clients. | |||
* Better time-out management in NetJack2. | |||
2012-01-13 Stephane Letz <letz@grame.fr> | |||
* More robust server/client protocol. | |||
2012-01-11 Stephane Letz <letz@grame.fr> | |||
* Factorize code the server/client request in JackRequestDecoder class. | |||
2012-01-06 Stephane Letz <letz@grame.fr> | |||
* Cleanup drivers and internals loading code. | |||
* jackctl_driver_params_parse API moved in public control.h. | |||
* More general drivers/internals loading model on Windows. | |||
2012-01-06 Stephane Letz <letz@grame.fr> | |||
* Fix for compilation on Solaris. | |||
2012-01-04 Stephane Letz <letz@grame.fr> | |||
* Fix library symbols export issue. | |||
2012-01-02 Stephane Letz <letz@grame.fr> | |||
* Adrian Knoth fix in midiseq.c. | |||
2011-12-20 Stephane Letz <letz@grame.fr> | |||
* Version 1.9.9 started. | |||
2011-11-25 Stephane Letz <letz@grame.fr> | |||
* More robust dynamic port management in JACK/CoreMidi bridge. | |||
@@ -0,0 +1,317 @@ | |||
/* | |||
Copyright (C) 2006 Jesse Chappell <jesse@essej.net> (AC3Jack) | |||
Copyright (C) 2012 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 "JackAC3Encoder.h" | |||
#include "JackError.h" | |||
#include <unistd.h> | |||
#include <string.h> | |||
#include <stdio.h> | |||
#define max(x,y) (((x)>(y)) ? (x) : (y)) | |||
#define min(x,y) (((x)<(y)) ? (x) : (y)) | |||
namespace Jack | |||
{ | |||
#ifndef __ppc__ | |||
JackAC3Encoder::JackAC3Encoder(const JackAC3EncoderParams& params) | |||
{ | |||
aften_set_defaults(&fAftenContext); | |||
fAftenContext.channels = params.channels; | |||
fAftenContext.samplerate = params.sample_rate; | |||
fAftenContext.params.bitrate = params.bitrate; | |||
int acmod = A52_ACMOD_MONO; | |||
int lfe = params.lfe; | |||
switch (params.channels) { | |||
case 1: acmod = A52_ACMOD_MONO; break; | |||
case 2: acmod = A52_ACMOD_STEREO; break; | |||
case 3: acmod = A52_ACMOD_3_0; break; | |||
case 4: acmod = A52_ACMOD_2_2; break; | |||
case 5: acmod = A52_ACMOD_3_2; break; | |||
break; | |||
default: | |||
break; | |||
} | |||
if (lfe) { | |||
fAftenContext.channels += 1; | |||
} | |||
fAftenContext.acmod = acmod; | |||
fAftenContext.lfe = lfe; | |||
fAftenContext.sample_format = A52_SAMPLE_FMT_FLT; | |||
fAftenContext.verbose = 1; | |||
fAftenContext.system.n_threads = 1; | |||
// create interleaved framebuffer for MAX_AC3_CHANNELS | |||
fSampleBuffer = new float[MAX_AC3_CHANNELS * A52_SAMPLES_PER_FRAME]; | |||
// create AC3 buffer | |||
fAC3Buffer = new unsigned char[A52_MAX_CODED_FRAME_SIZE]; | |||
memset(fAC3Buffer, 0, A52_MAX_CODED_FRAME_SIZE); | |||
fZeroBuffer = new unsigned char[SPDIF_FRAME_SIZE]; | |||
memset(fZeroBuffer, 0, SPDIF_FRAME_SIZE); | |||
fRingBuffer = jack_ringbuffer_create(32768); | |||
fOutSizeByte = 0; | |||
fFramePos = 0; | |||
fSampleRate = 0; | |||
fByteRate = 0; | |||
} | |||
bool JackAC3Encoder::Init(jack_nframes_t sample_rate) | |||
{ | |||
fSampleRate = sample_rate; | |||
fByteRate = fSampleRate * sizeof(short) * 2; | |||
return (aften_encode_init(&fAftenContext) == 0); | |||
} | |||
JackAC3Encoder::~JackAC3Encoder() | |||
{ | |||
aften_encode_close(&fAftenContext); | |||
delete [] fSampleBuffer; | |||
delete [] fAC3Buffer; | |||
delete [] fZeroBuffer; | |||
if (fRingBuffer) { | |||
jack_ringbuffer_free(fRingBuffer); | |||
} | |||
} | |||
void JackAC3Encoder::Process(float** inputs_buffer, float** outputs_buffer, int nframes) | |||
{ | |||
// fill and process frame buffers as appropriate | |||
jack_nframes_t frames_left = A52_SAMPLES_PER_FRAME - fFramePos; | |||
jack_nframes_t offset = 0; | |||
while (offset < nframes) | |||
{ | |||
if ((nframes - offset) >= frames_left) { | |||
// copy only frames_left more data | |||
jack_nframes_t pos = fFramePos * fAftenContext.channels; | |||
for (jack_nframes_t spos = offset; spos < offset + frames_left; ++spos) { | |||
for (size_t i = 0; i < fAftenContext.channels; ++i) { | |||
fSampleBuffer[pos + i] = inputs_buffer[i][spos]; | |||
} | |||
pos += fAftenContext.channels; | |||
} | |||
// use interleaved version | |||
int res = aften_encode_frame(&fAftenContext, fAC3Buffer + SPDIF_HEADER_SIZE, fSampleBuffer); | |||
if (res < 0) { | |||
jack_error("aften_encode_frame error !!"); | |||
return; | |||
} | |||
fOutSizeByte = res; | |||
FillSpdifHeader(fAC3Buffer, fOutSizeByte + SPDIF_HEADER_SIZE); | |||
// push AC3 output to SPDIF ring buffer | |||
float calc_ac3byterate = (fOutSizeByte * fSampleRate / (float) A52_SAMPLES_PER_FRAME); | |||
jack_nframes_t silencebytes = (jack_nframes_t) (fOutSizeByte * (fByteRate / calc_ac3byterate)) - fOutSizeByte - SPDIF_HEADER_SIZE; | |||
jack_ringbuffer_write(fRingBuffer, (const char *)fAC3Buffer, fOutSizeByte + SPDIF_HEADER_SIZE); | |||
// write the proper remainder of zero padding (inefficient, should be memsetting) | |||
jack_ringbuffer_write(fRingBuffer, (const char *)fZeroBuffer, silencebytes); | |||
offset += frames_left; | |||
frames_left = A52_SAMPLES_PER_FRAME; | |||
fFramePos = 0; | |||
} else { | |||
// copy incoming data into frame buffers without processing | |||
jack_nframes_t pos = fFramePos * fAftenContext.channels; | |||
for (jack_nframes_t spos = offset; spos < nframes; ++spos) { | |||
for (size_t i = 0; i < fAftenContext.channels; ++i) { | |||
fSampleBuffer[pos + i] = inputs_buffer[i][spos]; | |||
} | |||
pos += fAftenContext.channels; | |||
} | |||
fFramePos += (nframes - offset); | |||
offset += (nframes-offset); | |||
} | |||
} | |||
Output2Driver(outputs_buffer, nframes); | |||
} | |||
void JackAC3Encoder::FillSpdifHeader(unsigned char* buf, int outsize) | |||
{ | |||
// todo, use outsize and not assume the fixed frame size? | |||
int ac3outsize = outsize - SPDIF_HEADER_SIZE; | |||
buf[0] = 0x72; buf[1] = 0xf8; /* spdif syncword */ | |||
buf[2] = 0x1f; buf[3] = 0x4e; /* .............. */ | |||
buf[4] = 0x01; /* AC3 data */ | |||
buf[5] = buf[13] & 7; /* bsmod, stream = 0 */ | |||
buf[6] = (ac3outsize << 3) & 0xff; | |||
buf[7] = (ac3outsize >> 5) & 0xff; | |||
#if !IS_BIGENDIAN | |||
swab(buf+SPDIF_HEADER_SIZE, buf + SPDIF_HEADER_SIZE, ac3outsize); | |||
#endif | |||
} | |||
int JackAC3Encoder::Output2Driver(float** outputs, jack_nframes_t nframes) | |||
{ | |||
int wrotebytes = 0; | |||
jack_nframes_t nframes_left = nframes; | |||
if (jack_ringbuffer_read_space(fRingBuffer) == 0) { | |||
// just write silence | |||
memset(outputs[0], 0, nframes * sizeof(jack_default_audio_sample_t)); | |||
memset(outputs[1], 0, nframes * sizeof(jack_default_audio_sample_t)); | |||
} else { | |||
jack_ringbuffer_data_t rb_data[2]; | |||
jack_ringbuffer_get_read_vector(fRingBuffer, rb_data); | |||
while (nframes_left > 0 && rb_data[0].len > 4) { | |||
jack_nframes_t towrite_frames = (rb_data[0].len) / (sizeof(short) * 2); | |||
towrite_frames = min(towrite_frames, nframes_left); | |||
// write and deinterleave into the two channels | |||
#if 1 | |||
sample_move_dS_s16(outputs[0] + (nframes - nframes_left), (char *) rb_data[0].buf, towrite_frames, sizeof(short) * 2); | |||
sample_move_dS_s16(outputs[1] + (nframes - nframes_left), (char *) rb_data[0].buf + sizeof(short), towrite_frames, sizeof(short) * 2); | |||
#else | |||
sample_move_dS_s16_24ph(outputs[0] + (nframes - nframes_left), (char *) rb_data[0].buf, towrite_frames, sizeof(short) * 2); | |||
sample_move_dS_s16_24ph(outputs[1] + (nframes - nframes_left), (char *) rb_data[0].buf + sizeof(short), towrite_frames, sizeof(short) * 2); | |||
#endif | |||
wrotebytes = towrite_frames * sizeof(short) * 2; | |||
nframes_left -= towrite_frames; | |||
jack_ringbuffer_read_advance(fRingBuffer, wrotebytes); | |||
jack_ringbuffer_get_read_vector(fRingBuffer, rb_data); | |||
} | |||
if (nframes_left > 0) { | |||
// write silence | |||
memset(outputs[0] + (nframes - nframes_left), 0, (nframes_left) * sizeof(jack_default_audio_sample_t)); | |||
memset(outputs[1] + (nframes - nframes_left), 0, (nframes_left) * sizeof(jack_default_audio_sample_t)); | |||
} | |||
} | |||
return wrotebytes; | |||
} | |||
void JackAC3Encoder::sample_move_dS_s16(jack_default_audio_sample_t* dst, char *src, jack_nframes_t nsamples, unsigned long src_skip) | |||
{ | |||
/* ALERT: signed sign-extension portability !!! */ | |||
while (nsamples--) { | |||
*dst = (*((short *) src)) / SAMPLE_MAX_16BIT; | |||
dst++; | |||
src += src_skip; | |||
} | |||
} | |||
void JackAC3Encoder::sample_move_dS_s16_24ph(jack_default_audio_sample_t* dst, char *src, jack_nframes_t nsamples, unsigned long src_skip) | |||
{ | |||
/* ALERT: signed sign-extension portability !!! */ | |||
while (nsamples--) { | |||
*dst = (((int)(*((short *) src))) << 8) / SAMPLE_MAX_24BIT; | |||
dst++; | |||
src += src_skip; | |||
} | |||
} | |||
void JackAC3Encoder::GetChannelName(const char* name, const char* alias, char* portname, int channel) | |||
{ | |||
/* | |||
* 2 channels = L, R | |||
* 3 channels = L, C, R | |||
* 4 channels = L, R, LS, RS | |||
* 5 ch = L, C, R, LS, RS | |||
* 6 ch = L, C, R, LS, RS, LFE | |||
*/ | |||
const char* AC3_name = ""; | |||
switch (channel) { | |||
case 0: | |||
AC3_name = "AC3_1_Left"; | |||
break; | |||
case 1: | |||
if (fAftenContext.channels == 2 || fAftenContext.channels == 4) { | |||
AC3_name = "AC3_2_Right"; | |||
} else { | |||
AC3_name = "AC3_2_Center"; | |||
} | |||
break; | |||
case 2: | |||
if (fAftenContext.channels == 4) { | |||
AC3_name = "AC3_3_LeftSurround"; | |||
} else { | |||
AC3_name = "AC3_3_Right"; | |||
} | |||
break; | |||
case 3: | |||
if (fAftenContext.channels == 4) { | |||
AC3_name = "AC3_4_RightSurround"; | |||
} else { | |||
AC3_name = "AC3_4_LeftSurround"; | |||
} | |||
break; | |||
case 4: | |||
if (fAftenContext.channels > 4) { | |||
AC3_name = "AC3_5_RightSurround"; | |||
} | |||
break; | |||
default: | |||
break; | |||
} | |||
// Last channel | |||
if (fAftenContext.lfe && (channel == fAftenContext.channels - 1)) { | |||
sprintf(portname, "%s:%s:AC3_%d_LFE", name, alias, fAftenContext.channels); | |||
} else { | |||
sprintf(portname, "%s:%s:%s", name, alias, AC3_name); | |||
} | |||
} | |||
#endif | |||
} // end of namespace |
@@ -0,0 +1,100 @@ | |||
/* | |||
Copyright (C) 2006 Jesse Chappell <jesse@essej.net> (AC3Jack) | |||
Copyright (C) 2012 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 __JackAC3Encoder__ | |||
#define __JackAC3Encoder__ | |||
#include <aften/aften.h> | |||
#include <aften/aften-types.h> | |||
#include "ringbuffer.h" | |||
#include "types.h" | |||
#define MAX_AC3_CHANNELS 6 | |||
#define SPDIF_HEADER_SIZE 8 | |||
#define SPDIF_FRAME_SIZE 6144 | |||
#define SAMPLE_MAX_16BIT 32768.0f | |||
#define SAMPLE_MAX_24BIT 8388608.0f | |||
namespace Jack | |||
{ | |||
struct JackAC3EncoderParams | |||
{ | |||
int64_t duration; | |||
unsigned int channels; | |||
int bitdepth; | |||
int bitrate; | |||
unsigned int sample_rate; | |||
bool lfe; | |||
}; | |||
class JackAC3Encoder | |||
{ | |||
private: | |||
AftenContext fAftenContext; | |||
jack_ringbuffer_t* fRingBuffer; | |||
float* fSampleBuffer; | |||
unsigned char* fAC3Buffer; | |||
unsigned char* fZeroBuffer; | |||
int fOutSizeByte; | |||
jack_nframes_t fFramePos; | |||
jack_nframes_t fSampleRate; | |||
jack_nframes_t fByteRate; | |||
void FillSpdifHeader(unsigned char* buf, int outsize); | |||
int Output2Driver(float** outputs, jack_nframes_t nframes); | |||
void sample_move_dS_s16(jack_default_audio_sample_t* dst, char *src, jack_nframes_t nsamples, unsigned long src_skip); | |||
void sample_move_dS_s16_24ph(jack_default_audio_sample_t* dst, char *src, jack_nframes_t nsamples, unsigned long src_skip); | |||
public: | |||
#ifdef __ppc__ | |||
JackAC3Encoder(const JackAC3EncoderParams& params) {} | |||
virtual ~JackAC3Encoder() {} | |||
bool Init(jack_nframes_t sample_rate) {return false;} | |||
void Process(float** inputs, float** outputs, int nframes) {} | |||
void GetChannelName(const char* name, const char* alias, char* portname, int channel) {} | |||
#else | |||
JackAC3Encoder(const JackAC3EncoderParams& params); | |||
virtual ~JackAC3Encoder(); | |||
bool Init(jack_nframes_t sample_rate); | |||
void Process(float** inputs, float** outputs, int nframes); | |||
void GetChannelName(const char* name, const char* alias, char* portname, int channel); | |||
#endif | |||
}; | |||
typedef JackAC3Encoder * JackAC3EncoderPtr; | |||
} // end of namespace | |||
#endif |
@@ -35,20 +35,22 @@ namespace Jack | |||
int JackAudioAdapter::Process(jack_nframes_t frames, void* arg) | |||
{ | |||
JackAudioAdapter* adapter = static_cast<JackAudioAdapter*>(arg); | |||
jack_default_audio_sample_t* inputBuffer[adapter->fAudioAdapter->GetInputs()]; | |||
jack_default_audio_sample_t* outputBuffer[adapter->fAudioAdapter->GetOutputs()]; | |||
return adapter->ProcessAux(frames); | |||
} | |||
int JackAudioAdapter::ProcessAux(jack_nframes_t frames) | |||
{ | |||
// Always clear output | |||
for (int i = 0; i < adapter->fAudioAdapter->GetInputs(); i++) { | |||
inputBuffer[i] = (jack_default_audio_sample_t*)jack_port_get_buffer(adapter->fCapturePortList[i], frames); | |||
memset(inputBuffer[i], 0, frames * sizeof(jack_default_audio_sample_t)); | |||
for (int i = 0; i < fAudioAdapter->GetInputs(); i++) { | |||
fInputBufferList[i] = (jack_default_audio_sample_t*)jack_port_get_buffer(fCapturePortList[i], frames); | |||
memset(fInputBufferList[i], 0, frames * sizeof(jack_default_audio_sample_t)); | |||
} | |||
for (int i = 0; i < adapter->fAudioAdapter->GetOutputs(); i++) { | |||
outputBuffer[i] = (jack_default_audio_sample_t*)jack_port_get_buffer(adapter->fPlaybackPortList[i], frames); | |||
for (int i = 0; i < fAudioAdapter->GetOutputs(); i++) { | |||
fOutputBufferList[i] = (jack_default_audio_sample_t*)jack_port_get_buffer(fPlaybackPortList[i], frames); | |||
} | |||
adapter->fAudioAdapter->PullAndPush(inputBuffer, outputBuffer, frames); | |||
fAudioAdapter->PullAndPush(fInputBufferList, fOutputBufferList, frames); | |||
return 0; | |||
} | |||
@@ -126,6 +128,9 @@ void JackAudioAdapter::FreePorts() | |||
delete[] fCapturePortList; | |||
delete[] fPlaybackPortList; | |||
delete[] fInputBufferList; | |||
delete[] fOutputBufferList; | |||
} | |||
void JackAudioAdapter::ConnectPorts() | |||
@@ -164,6 +169,9 @@ int JackAudioAdapter::Open() | |||
fCapturePortList = new jack_port_t*[fAudioAdapter->GetInputs()]; | |||
fPlaybackPortList = new jack_port_t*[fAudioAdapter->GetOutputs()]; | |||
fInputBufferList = new jack_default_audio_sample_t*[fAudioAdapter->GetInputs()]; | |||
fOutputBufferList = new jack_default_audio_sample_t*[fAudioAdapter->GetOutputs()]; | |||
for (int i = 0; i < fAudioAdapter->GetInputs(); i++) { | |||
snprintf(name, sizeof(name), "capture_%d", i + 1); | |||
if ((fCapturePortList[i] = jack_port_register(fClient, name, JACK_DEFAULT_AUDIO_TYPE, CaptureDriverFlags, 0)) == NULL) { | |||
@@ -42,6 +42,9 @@ namespace Jack | |||
jack_port_t** fCapturePortList; | |||
jack_port_t** fPlaybackPortList; | |||
jack_default_audio_sample_t** fInputBufferList; | |||
jack_default_audio_sample_t** fOutputBufferList; | |||
jack_client_t* fClient; | |||
JackAudioAdapterInterface* fAudioAdapter; | |||
bool fAutoConnect; | |||
@@ -49,6 +52,7 @@ namespace Jack | |||
void FreePorts(); | |||
void ConnectPorts(); | |||
void Reset(); | |||
int ProcessAux(jack_nframes_t frames); | |||
public: | |||
@@ -26,6 +26,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
#include "JackLibSampleRateResampler.h" | |||
#endif | |||
#include "JackTime.h" | |||
#include "JackError.h" | |||
#include <stdio.h> | |||
namespace Jack | |||
@@ -317,4 +318,75 @@ namespace Jack | |||
return res; | |||
} | |||
int JackAudioAdapterInterface::SetHostBufferSize(jack_nframes_t buffer_size) | |||
{ | |||
fHostBufferSize = buffer_size; | |||
if (fAdaptative) { | |||
AdaptRingBufferSize(); | |||
} | |||
return 0; | |||
} | |||
int JackAudioAdapterInterface::SetAdaptedBufferSize(jack_nframes_t buffer_size) | |||
{ | |||
fAdaptedBufferSize = buffer_size; | |||
if (fAdaptative) { | |||
AdaptRingBufferSize(); | |||
} | |||
return 0; | |||
} | |||
int JackAudioAdapterInterface::SetBufferSize(jack_nframes_t buffer_size) | |||
{ | |||
SetHostBufferSize(buffer_size); | |||
SetAdaptedBufferSize(buffer_size); | |||
return 0; | |||
} | |||
int JackAudioAdapterInterface::SetHostSampleRate(jack_nframes_t sample_rate) | |||
{ | |||
fHostSampleRate = sample_rate; | |||
fPIControler.Init(double(fHostSampleRate) / double(fAdaptedSampleRate)); | |||
return 0; | |||
} | |||
int JackAudioAdapterInterface::SetAdaptedSampleRate(jack_nframes_t sample_rate) | |||
{ | |||
fAdaptedSampleRate = sample_rate; | |||
fPIControler.Init(double(fHostSampleRate) / double(fAdaptedSampleRate)); | |||
return 0; | |||
} | |||
int JackAudioAdapterInterface::SetSampleRate(jack_nframes_t sample_rate) | |||
{ | |||
SetHostSampleRate(sample_rate); | |||
SetAdaptedSampleRate(sample_rate); | |||
return 0; | |||
} | |||
void JackAudioAdapterInterface::SetInputs(int inputs) | |||
{ | |||
jack_log("JackAudioAdapterInterface::SetInputs %d", inputs); | |||
fCaptureChannels = inputs; | |||
} | |||
void JackAudioAdapterInterface::SetOutputs(int outputs) | |||
{ | |||
jack_log("JackAudioAdapterInterface::SetOutputs %d", outputs); | |||
fPlaybackChannels = outputs; | |||
} | |||
int JackAudioAdapterInterface::GetInputs() | |||
{ | |||
//jack_log("JackAudioAdapterInterface::GetInputs %d", fCaptureChannels); | |||
return fCaptureChannels; | |||
} | |||
int JackAudioAdapterInterface::GetOutputs() | |||
{ | |||
//jack_log ("JackAudioAdapterInterface::GetOutputs %d", fPlaybackChannels); | |||
return fPlaybackChannels; | |||
} | |||
} // namespace |
@@ -154,75 +154,16 @@ namespace Jack | |||
return 0; | |||
} | |||
virtual int SetHostBufferSize(jack_nframes_t buffer_size) | |||
{ | |||
fHostBufferSize = buffer_size; | |||
if (fAdaptative) { | |||
AdaptRingBufferSize(); | |||
} | |||
return 0; | |||
} | |||
virtual int SetAdaptedBufferSize(jack_nframes_t buffer_size) | |||
{ | |||
fAdaptedBufferSize = buffer_size; | |||
if (fAdaptative) { | |||
AdaptRingBufferSize(); | |||
} | |||
return 0; | |||
} | |||
virtual int SetBufferSize(jack_nframes_t buffer_size) | |||
{ | |||
SetHostBufferSize(buffer_size); | |||
SetAdaptedBufferSize(buffer_size); | |||
return 0; | |||
} | |||
virtual int SetHostSampleRate(jack_nframes_t sample_rate) | |||
{ | |||
fHostSampleRate = sample_rate; | |||
fPIControler.Init(double(fHostSampleRate) / double(fAdaptedSampleRate)); | |||
return 0; | |||
} | |||
virtual int SetAdaptedSampleRate(jack_nframes_t sample_rate) | |||
{ | |||
fAdaptedSampleRate = sample_rate; | |||
fPIControler.Init(double(fHostSampleRate) / double(fAdaptedSampleRate)); | |||
return 0; | |||
} | |||
virtual int SetSampleRate(jack_nframes_t sample_rate) | |||
{ | |||
SetHostSampleRate(sample_rate); | |||
SetAdaptedSampleRate(sample_rate); | |||
return 0; | |||
} | |||
void SetInputs(int inputs) | |||
{ | |||
jack_log("JackAudioAdapterInterface::SetInputs %d", inputs); | |||
fCaptureChannels = inputs; | |||
} | |||
void SetOutputs(int outputs) | |||
{ | |||
jack_log("JackAudioAdapterInterface::SetOutputs %d", outputs); | |||
fPlaybackChannels = outputs; | |||
} | |||
int GetInputs() | |||
{ | |||
//jack_log("JackAudioAdapterInterface::GetInputs %d", fCaptureChannels); | |||
return fCaptureChannels; | |||
} | |||
int GetOutputs() | |||
{ | |||
//jack_log ("JackAudioAdapterInterface::GetOutputs %d", fPlaybackChannels); | |||
return fPlaybackChannels; | |||
} | |||
virtual int SetHostBufferSize(jack_nframes_t buffer_size); | |||
virtual int SetAdaptedBufferSize(jack_nframes_t buffer_size); | |||
virtual int SetBufferSize(jack_nframes_t buffer_size); | |||
virtual int SetHostSampleRate(jack_nframes_t sample_rate); | |||
virtual int SetAdaptedSampleRate(jack_nframes_t sample_rate); | |||
virtual int SetSampleRate(jack_nframes_t sample_rate); | |||
void SetInputs(int inputs); | |||
void SetOutputs(int outputs); | |||
int GetInputs(); | |||
int GetOutputs(); | |||
virtual int GetInputLatency(int port_index) { return 0; } | |||
virtual int GetOutputLatency(int port_index) { return 0; } | |||
@@ -46,25 +46,20 @@ int JackAudioDriver::SetBufferSize(jack_nframes_t buffer_size) | |||
// Update engine and graph manager state | |||
fEngineControl->fBufferSize = buffer_size; | |||
fGraphManager->SetBufferSize(buffer_size); | |||
fEngineControl->fPeriodUsecs = jack_time_t(1000000.f / fEngineControl->fSampleRate * fEngineControl->fBufferSize); // in microsec | |||
if (!fEngineControl->fTimeOut) { | |||
fEngineControl->fTimeOutUsecs = jack_time_t(2.f * fEngineControl->fPeriodUsecs); | |||
} | |||
fEngineControl->UpdateTimeOut(); | |||
UpdateLatencies(); | |||
// Redirect on slaves drivers... | |||
// Redirected on slaves drivers... | |||
return JackDriver::SetBufferSize(buffer_size); | |||
} | |||
int JackAudioDriver::SetSampleRate(jack_nframes_t sample_rate) | |||
{ | |||
fEngineControl->fSampleRate = sample_rate; | |||
fEngineControl->fPeriodUsecs = jack_time_t(1000000.f / fEngineControl->fSampleRate * fEngineControl->fBufferSize); // in microsec | |||
if (!fEngineControl->fTimeOut) { | |||
fEngineControl->fTimeOutUsecs = jack_time_t(2.f * fEngineControl->fPeriodUsecs); | |||
} | |||
fEngineControl->UpdateTimeOut(); | |||
// Redirected on slaves drivers... | |||
return JackDriver::SetSampleRate(sample_rate); | |||
} | |||
@@ -35,6 +35,54 @@ class JackGraphManager; | |||
namespace detail | |||
{ | |||
class JackChannelTransactionInterface | |||
{ | |||
public: | |||
JackChannelTransactionInterface() | |||
{} | |||
virtual ~JackChannelTransactionInterface() | |||
{} | |||
virtual int Read(void* data, int len) = 0; | |||
virtual int Write(void* data, int len) = 0; | |||
}; | |||
class JackRequestInterface | |||
{ | |||
public: | |||
JackRequestInterface() | |||
{} | |||
virtual ~JackRequestInterface() | |||
{} | |||
virtual int Connect(const char* dir, const char* name, int which) = 0; | |||
virtual int Close() = 0; | |||
}; | |||
class JackClientRequestInterface : public JackChannelTransactionInterface, public JackRequestInterface | |||
{ | |||
public: | |||
JackClientRequestInterface() | |||
{} | |||
virtual ~JackClientRequestInterface() | |||
{} | |||
virtual int Read(void* data, int len) { return -1; } | |||
virtual int Write(void* data, int len) { return -1; } | |||
virtual int Connect(const char* dir, const char* name, int which) { return -1; } | |||
virtual int Close() { return -1; } | |||
}; | |||
/*! | |||
\brief Inter process channel for server/client bidirectionnal communication : request and (receiving) notifications. | |||
*/ | |||
@@ -88,6 +88,19 @@ JackClient::JackClient(JackSynchro* table):fThread(this) | |||
JackClient::~JackClient() | |||
{} | |||
void JackClient::ShutDown() | |||
{ | |||
jack_log("JackClient::ShutDown"); | |||
if (fInfoShutdown) { | |||
fInfoShutdown(JackFailure, "JACK server has been closed", fInfoShutdownArg); | |||
fInfoShutdown = NULL; | |||
} else if (fShutdown) { | |||
fShutdown(fShutdownArg); | |||
fShutdown = NULL; | |||
} | |||
} | |||
int JackClient::Close() | |||
{ | |||
jack_log("JackClient::Close ref = %ld", GetClientControl()->fRefNum); | |||
@@ -346,15 +359,18 @@ int JackClient::HandleLatencyCallback(int status) | |||
if (port->GetFlags() & JackPortIsOutput) { | |||
jack_latency_range_t other_latency; | |||
port->GetLatencyRange(mode, &other_latency); | |||
if (other_latency.max > latency.max) | |||
if (other_latency.max > latency.max) { | |||
latency.max = other_latency.max; | |||
if (other_latency.min < latency.min) | |||
} | |||
if (other_latency.min < latency.min) { | |||
latency.min = other_latency.min; | |||
} | |||
} | |||
} | |||
if (latency.min == UINT32_MAX) | |||
if (latency.min == UINT32_MAX) { | |||
latency.min = 0; | |||
} | |||
/* now set the found latency on all input ports | |||
*/ | |||
@@ -373,15 +389,18 @@ int JackClient::HandleLatencyCallback(int status) | |||
if (port->GetFlags() & JackPortIsInput) { | |||
jack_latency_range_t other_latency; | |||
port->GetLatencyRange(mode, &other_latency); | |||
if (other_latency.max > latency.max) | |||
if (other_latency.max > latency.max) { | |||
latency.max = other_latency.max; | |||
if (other_latency.min < latency.min) | |||
} | |||
if (other_latency.min < latency.min) { | |||
latency.min = other_latency.min; | |||
} | |||
} | |||
} | |||
if (latency.min == UINT32_MAX) | |||
if (latency.min == UINT32_MAX) { | |||
latency.min = 0; | |||
} | |||
/* now set the found latency on all output ports | |||
*/ | |||
@@ -409,13 +428,15 @@ connected to the client may not be activated. | |||
int JackClient::Activate() | |||
{ | |||
jack_log("JackClient::Activate"); | |||
if (IsActive()) | |||
if (IsActive()) { | |||
return 0; | |||
} | |||
// RT thread is started only when needed... | |||
if (IsRealTime()) { | |||
if (StartThread() < 0) | |||
if (StartThread() < 0) { | |||
return -1; | |||
} | |||
} | |||
/* | |||
@@ -440,8 +461,9 @@ int JackClient::Activate() | |||
int JackClient::Deactivate() | |||
{ | |||
jack_log("JackClient::Deactivate"); | |||
if (!IsActive()) | |||
if (!IsActive()) { | |||
return 0; | |||
} | |||
GetClientControl()->fActive = false; | |||
@@ -455,8 +477,9 @@ int JackClient::Deactivate() | |||
jack_log("JackClient::Deactivate res = %ld", result); | |||
// RT thread is stopped only when needed... | |||
if (IsRealTime()) | |||
if (IsRealTime()) { | |||
fThread.Kill(); | |||
} | |||
return result; | |||
} | |||
@@ -493,11 +516,13 @@ bool JackClient::Init() | |||
InitAux(); | |||
// Setup context | |||
if (!jack_tls_set(JackGlobals::fRealTime, this)) | |||
jack_error("failed to set thread realtime key"); | |||
if (!jack_tls_set(JackGlobals::fRealTimeThread, this)) { | |||
jack_error("Failed to set thread realtime key"); | |||
} | |||
if (GetEngineControl()->fRealTime) | |||
if (GetEngineControl()->fRealTime) { | |||
set_threaded_log_function(); | |||
} | |||
// Setup RT | |||
if (GetEngineControl()->fRealTime) { | |||
@@ -560,19 +585,22 @@ inline void JackClient::ExecuteThread() | |||
inline jack_nframes_t JackClient::CycleWaitAux() | |||
{ | |||
if (!WaitSync()) | |||
if (!WaitSync()) { | |||
Error(); // Terminates the thread | |||
} | |||
CallSyncCallbackAux(); | |||
return GetEngineControl()->fBufferSize; | |||
} | |||
inline void JackClient::CycleSignalAux(int status) | |||
{ | |||
if (status == 0) | |||
if (status == 0) { | |||
CallTimebaseCallbackAux(); | |||
} | |||
SignalSync(); | |||
if (status != 0) | |||
if (status != 0) { | |||
End(); // Terminates the thread | |||
} | |||
} | |||
jack_nframes_t JackClient::CycleWait() | |||
@@ -747,27 +775,6 @@ int JackClient::ComputeTotalLatencies() | |||
return result; | |||
} | |||
/* | |||
ShutDown is called: | |||
- from the RT thread when Execute method fails | |||
- possibly from a "closed" notification channel | |||
(Not needed since the synch object used (Sema of Fifo will fails when server quits... see ShutDown)) | |||
*/ | |||
void JackClient::ShutDown() | |||
{ | |||
jack_log("JackClient::ShutDown"); | |||
JackGlobals::fServerRunning = false; | |||
if (fInfoShutdown) { | |||
fInfoShutdown(JackFailure, "JACK server has been closed", fInfoShutdownArg); | |||
fInfoShutdown = NULL; | |||
} else if (fShutdown) { | |||
fShutdown(fShutdownArg); | |||
fShutdown = NULL; | |||
} | |||
} | |||
//---------------------- | |||
// Transport management | |||
//---------------------- | |||
@@ -780,8 +787,9 @@ inline int JackClient::ActivateAux() | |||
jack_log("JackClient::ActivateAux"); | |||
// RT thread is started | |||
if (StartThread() < 0) | |||
if (StartThread() < 0) { | |||
return -1; | |||
} | |||
int result = -1; | |||
GetClientControl()->fCallback[kRealTimeCallback] = IsRealTime(); | |||
@@ -1001,8 +1009,7 @@ int JackClient::SetInitCallback(JackThreadInitCallback callback, void *arg) | |||
fInitArg = arg; | |||
fInit = callback; | |||
/* make sure that the message buffer thread is initialized too */ | |||
JackMessageBuffer::fInstance->SetInitCallback(callback, arg); | |||
return 0; | |||
return JackMessageBuffer::fInstance->SetInitCallback(callback, arg); | |||
} | |||
} | |||
@@ -1042,8 +1049,9 @@ int JackClient::SetSampleRateCallback(JackSampleRateCallback callback, void *arg | |||
fSampleRateArg = arg; | |||
fSampleRate = callback; | |||
// Now invoke it | |||
if (callback) | |||
if (callback) { | |||
callback(GetEngineControl()->fSampleRate, arg); | |||
} | |||
return 0; | |||
} | |||
} | |||
@@ -1122,7 +1130,7 @@ int JackClient::SetProcessThread(JackThreadCallback fun, void *arg) | |||
jack_error("You cannot set callbacks on an active client"); | |||
return -1; | |||
} else if (fProcess) { | |||
jack_error ("A process callback has already been setup, both models cannot be used at the same time!"); | |||
jack_error("A process callback has already been setup, both models cannot be used at the same time!"); | |||
return -1; | |||
} else { | |||
fThreadFun = fun; | |||
@@ -27,6 +27,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
#include "JackSynchro.h" | |||
#include "JackPlatformPlug.h" | |||
#include "JackChannel.h" | |||
#include "JackRequest.h" | |||
#include "varargs.h" | |||
#include <list> | |||
@@ -86,7 +87,7 @@ class SERVER_EXPORT JackClient : public JackClientInterface, public JackRunnable | |||
void* fThreadFunArg; | |||
void* fSessionArg; | |||
void* fLatencyArg; | |||
char fServerName[64]; | |||
char fServerName[JACK_SERVER_CONTROL_NAME_SIZE]; | |||
JackThread fThread; /*! Thread to execute the Process function */ | |||
detail::JackClientChannelInterface* fChannel; | |||
@@ -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. | |||
*/ | |||
@@ -36,12 +36,12 @@ class SERVER_EXPORT JackClientInterface | |||
{ | |||
public: | |||
JackClientInterface() | |||
{} | |||
virtual ~JackClientInterface() | |||
{} | |||
virtual int Close() = 0; | |||
virtual int ClientNotify(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2) = 0; | |||
@@ -24,7 +24,7 @@ | |||
#include "config.h" | |||
#endif | |||
#define VERSION "1.9.8" | |||
#define VERSION "1.9.9" | |||
#define BUFFER_SIZE_MAX 8192 | |||
@@ -71,7 +71,7 @@ | |||
#define JACK_PROTOCOL_VERSION 8 | |||
#define SOCKET_TIME_OUT 5 // in sec | |||
#define SOCKET_TIME_OUT 2 // in sec | |||
#define DRIVER_OPEN_TIMEOUT 5 // in sec | |||
#define FREEWHEEL_DRIVER_TIMEOUT 10 // in sec | |||
#define DRIVER_TIMEOUT_FACTOR 10 | |||
@@ -237,7 +237,7 @@ jackctl_add_driver_parameters( | |||
jackctl_value.b = descriptor_ptr->value.i; | |||
break; | |||
default: | |||
jack_error("unknown driver parameter type %i", (int)descriptor_ptr->type); | |||
jack_error("Unknown driver parameter type %i", (int)descriptor_ptr->type); | |||
assert(0); | |||
goto fail; | |||
} | |||
@@ -330,7 +330,7 @@ jackctl_create_param_list( | |||
retparam_ptr->value.i = param_ptr->value_ptr->b; | |||
break; | |||
default: | |||
jack_error("unknown parameter type %i", (int)param_ptr->type); | |||
jack_error("Unknown parameter type %i", (int)param_ptr->type); | |||
assert(0); | |||
goto free; | |||
} | |||
@@ -361,7 +361,7 @@ jackctl_drivers_load( | |||
descriptor_node_ptr = jack_drivers_load(NULL); | |||
if (descriptor_node_ptr == NULL) | |||
{ | |||
jack_error("could not find any drivers in driver directory!"); | |||
jack_error("Could not find any drivers in driver directory!"); | |||
return false; | |||
} | |||
@@ -370,7 +370,7 @@ jackctl_drivers_load( | |||
driver_ptr = (struct jackctl_driver *)malloc(sizeof(struct jackctl_driver)); | |||
if (driver_ptr == NULL) | |||
{ | |||
jack_error("memory allocation of jackctl_driver structure failed."); | |||
jack_error("Memory allocation of jackctl_driver structure failed."); | |||
goto next; | |||
} | |||
@@ -430,7 +430,7 @@ jackctl_internals_load( | |||
descriptor_node_ptr = jack_internals_load(NULL); | |||
if (descriptor_node_ptr == NULL) | |||
{ | |||
jack_error("could not find any internals in driver directory!"); | |||
jack_error("Could not find any internals in driver directory!"); | |||
return false; | |||
} | |||
@@ -439,7 +439,7 @@ jackctl_internals_load( | |||
internal_ptr = (struct jackctl_internal *)malloc(sizeof(struct jackctl_internal)); | |||
if (internal_ptr == NULL) | |||
{ | |||
jack_error("memory allocation of jackctl_driver structure failed."); | |||
jack_error("Memory allocation of jackctl_driver structure failed."); | |||
goto next; | |||
} | |||
@@ -506,57 +506,68 @@ jackctl_server_free_parameters( | |||
#ifdef WIN32 | |||
static HANDLE waitEvent; | |||
struct jackctl_sigmask | |||
{ | |||
HANDLE wait_event; | |||
}; | |||
static jackctl_sigmask sigmask; | |||
static void do_nothing_handler(int signum) | |||
static void signal_handler(int signum) | |||
{ | |||
printf("jack main caught signal %d\n", signum); | |||
printf("Jack main caught signal %d\n", signum); | |||
(void) signal(SIGINT, SIG_DFL); | |||
SetEvent(waitEvent); | |||
SetEvent(sigmask.wait_event); | |||
} | |||
sigset_t | |||
jackctl_sigmask_t * | |||
jackctl_setup_signals( | |||
unsigned int flags) | |||
{ | |||
if ((waitEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL) { | |||
if ((sigmask.wait_event = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL) { | |||
jack_error("CreateEvent fails err = %ld", GetLastError()); | |||
return 0; | |||
} | |||
(void) signal(SIGINT, do_nothing_handler); | |||
(void) signal(SIGABRT, do_nothing_handler); | |||
(void) signal(SIGTERM, do_nothing_handler); | |||
(void) signal(SIGINT, signal_handler); | |||
(void) signal(SIGABRT, signal_handler); | |||
(void) signal(SIGTERM, signal_handler); | |||
return (sigset_t)waitEvent; | |||
return &sigmask; | |||
} | |||
void jackctl_wait_signals(sigset_t signals) | |||
void jackctl_wait_signals(jackctl_sigmask_t * signals) | |||
{ | |||
if (WaitForSingleObject(waitEvent, INFINITE) != WAIT_OBJECT_0) { | |||
if (WaitForSingleObject(signals->wait_event, INFINITE) != WAIT_OBJECT_0) { | |||
jack_error("WaitForSingleObject fails err = %ld", GetLastError()); | |||
} | |||
} | |||
#else | |||
struct jackctl_sigmask | |||
{ | |||
sigset_t signals; | |||
}; | |||
static jackctl_sigmask sigmask; | |||
static | |||
void | |||
do_nothing_handler(int sig) | |||
signal_handler(int sig) | |||
{ | |||
/* this is used by the child (active) process, but it never | |||
gets called unless we are already shutting down after | |||
another signal. | |||
*/ | |||
char buf[64]; | |||
snprintf (buf, sizeof(buf), "received signal %d during shutdown (ignored)\n", sig); | |||
snprintf(buf, sizeof(buf), "Received signal %d during shutdown (ignored)\n", sig); | |||
} | |||
SERVER_EXPORT sigset_t | |||
SERVER_EXPORT jackctl_sigmask_t * | |||
jackctl_setup_signals( | |||
unsigned int flags) | |||
{ | |||
sigset_t signals; | |||
sigset_t allsignals; | |||
struct sigaction action; | |||
int i; | |||
@@ -595,54 +606,54 @@ jackctl_setup_signals( | |||
after a return from sigwait(). | |||
*/ | |||
sigemptyset(&signals); | |||
sigaddset(&signals, SIGHUP); | |||
sigaddset(&signals, SIGINT); | |||
sigaddset(&signals, SIGQUIT); | |||
sigaddset(&signals, SIGPIPE); | |||
sigaddset(&signals, SIGTERM); | |||
sigaddset(&signals, SIGUSR1); | |||
sigaddset(&signals, SIGUSR2); | |||
sigemptyset(&sigmask.signals); | |||
sigaddset(&sigmask.signals, SIGHUP); | |||
sigaddset(&sigmask.signals, SIGINT); | |||
sigaddset(&sigmask.signals, SIGQUIT); | |||
sigaddset(&sigmask.signals, SIGPIPE); | |||
sigaddset(&sigmask.signals, SIGTERM); | |||
sigaddset(&sigmask.signals, SIGUSR1); | |||
sigaddset(&sigmask.signals, SIGUSR2); | |||
/* all child threads will inherit this mask unless they | |||
* explicitly reset it | |||
*/ | |||
pthread_sigmask(SIG_BLOCK, &signals, 0); | |||
pthread_sigmask(SIG_BLOCK, &sigmask.signals, 0); | |||
/* install a do-nothing handler because otherwise pthreads | |||
behaviour is undefined when we enter sigwait. | |||
*/ | |||
sigfillset(&allsignals); | |||
action.sa_handler = do_nothing_handler; | |||
action.sa_handler = signal_handler; | |||
action.sa_mask = allsignals; | |||
action.sa_flags = SA_RESTART|SA_RESETHAND; | |||
for (i = 1; i < NSIG; i++) | |||
{ | |||
if (sigismember (&signals, i)) | |||
if (sigismember (&sigmask.signals, i)) | |||
{ | |||
sigaction(i, &action, 0); | |||
} | |||
} | |||
return signals; | |||
return &sigmask; | |||
} | |||
SERVER_EXPORT void | |||
jackctl_wait_signals(sigset_t signals) | |||
jackctl_wait_signals(jackctl_sigmask_t * sigmask) | |||
{ | |||
int sig; | |||
bool waiting = true; | |||
while (waiting) { | |||
#if defined(sun) && !defined(__sun__) // SUN compiler only, to check | |||
sigwait(&signals); | |||
sigwait(&sigmask->signals); | |||
#else | |||
sigwait(&signals, &sig); | |||
sigwait(&sigmask->signals, &sig); | |||
#endif | |||
fprintf(stderr, "jack main caught signal %d\n", sig); | |||
fprintf(stderr, "Jack main caught signal %d\n", sig); | |||
switch (sig) { | |||
case SIGUSR1: | |||
@@ -664,7 +675,7 @@ jackctl_wait_signals(sigset_t signals) | |||
// unblock signals so we can see them during shutdown. | |||
// this will help prod developers not to lose sight of | |||
// bugs that cause segfaults etc. during shutdown. | |||
sigprocmask(SIG_UNBLOCK, &signals, 0); | |||
sigprocmask(SIG_UNBLOCK, &sigmask->signals, 0); | |||
} | |||
} | |||
#endif | |||
@@ -911,15 +922,15 @@ SERVER_EXPORT bool jackctl_server_close(jackctl_server *server_ptr) | |||
delete server_ptr->engine; | |||
/* clean up shared memory and files from this server instance */ | |||
jack_log("cleaning up shared memory"); | |||
jack_log("Cleaning up shared memory"); | |||
jack_cleanup_shm(); | |||
jack_log("cleaning up files"); | |||
jack_log("Cleaning up files"); | |||
JackTools::CleanupFiles(server_ptr->name.str); | |||
jack_log("unregistering server `%s'", server_ptr->name.str); | |||
jack_log("Unregistering server `%s'", server_ptr->name.str); | |||
jack_unregister_server(server_ptr->name.str); | |||
@@ -956,14 +967,14 @@ jackctl_server_open( | |||
jack_error("`%s' server already active", server_ptr->name.str); | |||
goto fail; | |||
case ENOSPC: | |||
jack_error("too many servers already active"); | |||
jack_error("Too many servers already active"); | |||
goto fail; | |||
case ENOMEM: | |||
jack_error("no access to shm registry"); | |||
jack_error("No access to shm registry"); | |||
goto fail; | |||
} | |||
jack_log("server `%s' registered", server_ptr->name.str); | |||
jack_log("Server `%s' registered", server_ptr->name.str); | |||
/* clean up shared memory and files from any previous | |||
* instance of this server name */ | |||
@@ -976,7 +987,7 @@ jackctl_server_open( | |||
/* check port max value before allocating server */ | |||
if (server_ptr->port_max.ui > PORT_NUM_MAX) { | |||
jack_error("JACK server started with too much ports %d (when port max can be %d)", server_ptr->port_max.ui, PORT_NUM_MAX); | |||
jack_error("Jack server started with too much ports %d (when port max can be %d)", server_ptr->port_max.ui, PORT_NUM_MAX); | |||
goto fail; | |||
} | |||
@@ -1003,7 +1014,7 @@ jackctl_server_open( | |||
jackctl_destroy_param_list(paramlist); | |||
if (rc < 0) | |||
{ | |||
jack_error("JackServer::Open() failed with %d", rc); | |||
jack_error("JackServer::Open failed with %d", rc); | |||
goto fail_delete; | |||
} | |||
@@ -1019,15 +1030,15 @@ fail_delete: | |||
server_ptr->engine = NULL; | |||
fail_unregister: | |||
jack_log("cleaning up shared memory"); | |||
jack_log("Cleaning up shared memory"); | |||
jack_cleanup_shm(); | |||
jack_log("cleaning up files"); | |||
jack_log("Cleaning up files"); | |||
JackTools::CleanupFiles(server_ptr->name.str); | |||
jack_log("unregistering server `%s'", server_ptr->name.str); | |||
jack_log("Unregistering server `%s'", server_ptr->name.str); | |||
jack_unregister_server(server_ptr->name.str); | |||
@@ -1138,7 +1149,7 @@ SERVER_EXPORT union jackctl_parameter_value jackctl_parameter_get_enum_constrain | |||
strcpy(jackctl_value.str, value_ptr->str); | |||
break; | |||
default: | |||
jack_error("bad driver parameter type %i (enum constraint)", (int)parameter_ptr->type); | |||
jack_error("Bad driver parameter type %i (enum constraint)", (int)parameter_ptr->type); | |||
assert(0); | |||
} | |||
@@ -1167,7 +1178,7 @@ SERVER_EXPORT void jackctl_parameter_get_range_constraint(jackctl_parameter *par | |||
max_ptr->ui = parameter_ptr->constraint_ptr->constraint.range.max.ui; | |||
return; | |||
default: | |||
jack_error("bad driver parameter type %i (range constraint)", (int)parameter_ptr->type); | |||
jack_error("Bad driver parameter type %i (range constraint)", (int)parameter_ptr->type); | |||
assert(0); | |||
} | |||
} | |||
@@ -1307,7 +1318,7 @@ SERVER_EXPORT bool jackctl_server_add_slave(jackctl_server * server_ptr, jackctl | |||
{ | |||
if (server_ptr && server_ptr->engine) { | |||
if (server_ptr->engine->IsRunning()) { | |||
jack_error("cannot add a slave in a running server"); | |||
jack_error("Cannot add a slave in a running server"); | |||
return false; | |||
} else { | |||
JSList * paramlist = jackctl_create_param_list(driver_ptr->parameters); | |||
@@ -1330,7 +1341,7 @@ SERVER_EXPORT bool jackctl_server_remove_slave(jackctl_server * server_ptr, jack | |||
{ | |||
if (server_ptr && server_ptr->engine) { | |||
if (server_ptr->engine->IsRunning()) { | |||
jack_error("cannot remove a slave from a running server"); | |||
jack_error("Cannot remove a slave from a running server"); | |||
return false; | |||
} else { | |||
if (driver_ptr->infos) { | |||
@@ -25,15 +25,6 @@ | |||
#include "jslist.h" | |||
#include "JackCompilerDeps.h" | |||
#ifdef WIN32 | |||
#ifdef __MINGW32__ | |||
#include <sys/types.h> | |||
typedef _sigset_t sigset_t; | |||
#else | |||
typedef HANDLE sigset_t; | |||
#endif | |||
#endif | |||
/** Parameter types, intentionally similar to jack_driver_param_type_t */ | |||
typedef enum | |||
{ | |||
@@ -80,6 +71,9 @@ typedef struct jackctl_internal jackctl_internal_t; | |||
/** opaque type for parameter object */ | |||
typedef struct jackctl_parameter jackctl_parameter_t; | |||
/** opaque type for sigmask object */ | |||
typedef struct jackctl_sigmask jackctl_sigmask_t; | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
@@ -87,13 +81,13 @@ extern "C" { | |||
} /* Adjust editor indent */ | |||
#endif | |||
SERVER_EXPORT sigset_t | |||
SERVER_EXPORT jackctl_sigmask_t * | |||
jackctl_setup_signals( | |||
unsigned int flags); | |||
SERVER_EXPORT void | |||
jackctl_wait_signals( | |||
sigset_t signals); | |||
jackctl_sigmask_t * signals); | |||
SERVER_EXPORT jackctl_server_t * | |||
jackctl_server_create( | |||
@@ -252,6 +246,9 @@ SERVER_EXPORT bool | |||
jackctl_server_switch_master(jackctl_server_t * server, | |||
jackctl_driver_t * driver); | |||
SERVER_EXPORT int | |||
jackctl_parse_driver_params(jackctl_driver * driver_ptr, int argc, char* argv[]); | |||
#if 0 | |||
{ /* Adjust editor indent */ | |||
#endif | |||
@@ -115,7 +115,11 @@ int JackDebugClient::Close() | |||
void JackDebugClient::CheckClient(const char* function_name) const | |||
{ | |||
#ifdef WIN32 | |||
*fStream << "CheckClient : " << function_name << ", calling thread : " << GetCurrentThread() << endl; | |||
#else | |||
*fStream << "CheckClient : " << function_name << ", calling thread : " << pthread_self() << endl; | |||
#endif | |||
if (fIsClosed > 0) { | |||
*fStream << "!!! ERROR !!! : Accessing a client '" << fClientName << "' already closed " << "from " << function_name << endl; | |||
@@ -290,13 +294,13 @@ int JackDebugClient::PortDisconnect(jack_port_id_t src) | |||
{ | |||
CheckClient("PortDisconnect"); | |||
if (!fIsActivated) | |||
*fStream << "!!! ERROR !!! : Trying to disconnect port " << src << " while that client has not been activated !" << endl; | |||
*fStream << "!!! ERROR !!! : Trying to disconnect port " << src << " while that client has not been activated !" << endl; | |||
int res = fClient->PortDisconnect(src); | |||
int i; | |||
for (i = (fTotalPortNumber - 1); i >= 0; i--) { // We search the record into the history | |||
if (fPortList[i].idport == src) { // We found the record in sources | |||
if (fPortList[i].IsUnregistered != 0) | |||
*fStream << "!!! ERROR !!! : Disconnecting port " << src << " previoulsy unregistered !" << endl; | |||
*fStream << "!!! ERROR !!! : Disconnecting port " << src << " previoulsy unregistered !" << endl; | |||
fPortList[i].IsConnected--; | |||
*fStream << "Disconnecting port " << src << ". " << endl; | |||
break; | |||
@@ -313,9 +317,17 @@ int JackDebugClient::PortDisconnect(jack_port_id_t src) | |||
int JackDebugClient::PortIsMine(jack_port_id_t port_index) | |||
{ | |||
CheckClient("PortIsMine"); | |||
*fStream << "JackClientDebug : PortIsMine port_index " << port_index << endl; | |||
return fClient->PortIsMine(port_index); | |||
} | |||
int JackDebugClient::PortRename(jack_port_id_t port_index, const char* name) | |||
{ | |||
CheckClient("PortRename"); | |||
*fStream << "JackClientDebug : PortRename port_index " << port_index << "name" << name << endl; | |||
return fClient->PortRename(port_index, name); | |||
} | |||
//-------------------- | |||
// Context management | |||
//-------------------- | |||
@@ -323,6 +335,7 @@ int JackDebugClient::PortIsMine(jack_port_id_t port_index) | |||
int JackDebugClient::SetBufferSize(jack_nframes_t buffer_size) | |||
{ | |||
CheckClient("SetBufferSize"); | |||
*fStream << "JackClientDebug : SetBufferSize buffer_size " << buffer_size << endl; | |||
return fClient->SetBufferSize(buffer_size); | |||
} | |||
@@ -330,13 +343,19 @@ int JackDebugClient::SetFreeWheel(int onoff) | |||
{ | |||
CheckClient("SetFreeWheel"); | |||
if (onoff && fFreewheel) | |||
*fStream << "!!! ERROR !!! : Freewheel setup seems incorrect : set = ON while FW is already ON " << endl; | |||
*fStream << "!!! ERROR !!! : Freewheel setup seems incorrect : set = ON while FW is already ON " << endl; | |||
if (!onoff && !fFreewheel) | |||
*fStream << "!!! ERROR !!! : Freewheel setup seems incorrect : set = OFF while FW is already OFF " << endl; | |||
*fStream << "!!! ERROR !!! : Freewheel setup seems incorrect : set = OFF while FW is already OFF " << endl; | |||
fFreewheel = onoff ? true : false; | |||
return fClient->SetFreeWheel(onoff); | |||
} | |||
int JackDebugClient::ComputeTotalLatencies() | |||
{ | |||
CheckClient("ComputeTotalLatencies"); | |||
return fClient->ComputeTotalLatencies(); | |||
} | |||
/* | |||
ShutDown is called: | |||
- from the RT thread when Execute method fails | |||
@@ -346,6 +365,7 @@ ShutDown is called: | |||
void JackDebugClient::ShutDown() | |||
{ | |||
CheckClient("ShutDown"); | |||
fClient->ShutDown(); | |||
} | |||
@@ -368,6 +388,7 @@ int JackDebugClient::SetSyncCallback(JackSyncCallback sync_callback, void* arg) | |||
int JackDebugClient::SetSyncTimeout(jack_time_t timeout) | |||
{ | |||
CheckClient("SetSyncTimeout"); | |||
*fStream << "JackClientDebug : SetSyncTimeout timeout " << timeout << endl; | |||
return fClient->SetSyncTimeout(timeout); | |||
} | |||
@@ -380,6 +401,7 @@ int JackDebugClient::SetTimebaseCallback(int conditional, JackTimebaseCallback t | |||
void JackDebugClient::TransportLocate(jack_nframes_t frame) | |||
{ | |||
CheckClient("TransportLocate"); | |||
*fStream << "JackClientDebug : TransportLocate frame " << frame << endl; | |||
fClient->TransportLocate(frame); | |||
} | |||
@@ -435,10 +457,11 @@ int JackDebugClient::TimeCallback(jack_nframes_t nframes, void *arg) | |||
jack_time_t t1 = GetMicroSeconds(); | |||
int res = client->fProcessTimeCallback(nframes, client->fProcessTimeCallbackArg); | |||
if (res == 0) { | |||
jack_time_t t2 = GetMicroSeconds(); | |||
jack_time_t t2 = GetMicroSeconds(); | |||
long delta = long((t2 - t1) - client->GetEngineControl()->fPeriodUsecs); | |||
if (delta > 0 && !client->fFreewheel) | |||
if (delta > 0 && !client->fFreewheel) { | |||
*client->fStream << "!!! ERROR !!! : Process overload of " << delta << " us" << endl; | |||
} | |||
} | |||
return res; | |||
} | |||
@@ -446,9 +469,17 @@ int JackDebugClient::TimeCallback(jack_nframes_t nframes, void *arg) | |||
int JackDebugClient::SetProcessCallback(JackProcessCallback callback, void *arg) | |||
{ | |||
CheckClient("SetProcessCallback"); | |||
fProcessTimeCallback = callback; | |||
fProcessTimeCallbackArg = arg; | |||
return fClient->SetProcessCallback(TimeCallback, this); | |||
if (callback == NULL) { | |||
// Clear the callback... | |||
return fClient->SetProcessCallback(callback, arg); | |||
} else { | |||
// Setup the measuring version... | |||
return fClient->SetProcessCallback(TimeCallback, this); | |||
} | |||
} | |||
int JackDebugClient::SetXRunCallback(JackXRunCallback callback, void *arg) | |||
@@ -517,9 +548,16 @@ int JackDebugClient::SetLatencyCallback(JackLatencyCallback callback, void *arg) | |||
return fClient->SetLatencyCallback(callback, arg); | |||
} | |||
int JackDebugClient::SetProcessThread(JackThreadCallback fun, void *arg) | |||
{ | |||
CheckClient("SetProcessThread"); | |||
return fClient->SetProcessThread(fun, arg); | |||
} | |||
jack_session_command_t* JackDebugClient::SessionNotify(const char* target, jack_session_event_type_t type, const char* path) | |||
{ | |||
CheckClient("SessionNotify"); | |||
*fStream << "JackClientDebug : SessionNotify target " << target << "type " << type << "path " << path << endl; | |||
return fClient->SessionNotify(target, type, path); | |||
} | |||
@@ -532,24 +570,28 @@ int JackDebugClient::SessionReply(jack_session_event_t* ev) | |||
char* JackDebugClient::GetUUIDForClientName(const char* client_name) | |||
{ | |||
CheckClient("GetUUIDForClientName"); | |||
*fStream << "JackClientDebug : GetUUIDForClientName client_name " << client_name << endl; | |||
return fClient->GetUUIDForClientName(client_name); | |||
} | |||
char* JackDebugClient::GetClientNameByUUID(const char* uuid) | |||
{ | |||
CheckClient("GetClientNameByUUID"); | |||
*fStream << "JackClientDebug : GetClientNameByUUID uuid " << uuid << endl; | |||
return fClient->GetClientNameByUUID(uuid); | |||
} | |||
int JackDebugClient::ReserveClientName(const char* client_name, const char* uuid) | |||
{ | |||
CheckClient("ReserveClientName"); | |||
*fStream << "JackClientDebug : ReserveClientName client_name " << client_name << "uuid " << uuid << endl; | |||
return fClient->ReserveClientName(client_name, uuid); | |||
} | |||
int JackDebugClient::ClientHasSessionCallback(const char* client_name) | |||
{ | |||
CheckClient("ClientHasSessionCallback"); | |||
*fStream << "JackClientDebug : ClientHasSessionCallback client_name " << client_name << endl; | |||
return fClient->ClientHasSessionCallback(client_name); | |||
} | |||
@@ -46,7 +46,7 @@ PortFollower; | |||
\brief A "decorator" debug client to validate API use. | |||
*/ | |||
class LIB_EXPORT JackDebugClient : public JackClient | |||
class JackDebugClient : public JackClient | |||
{ | |||
protected: | |||
@@ -83,6 +83,7 @@ class LIB_EXPORT JackDebugClient : public JackClient | |||
// Context | |||
int SetBufferSize(jack_nframes_t buffer_size); | |||
int SetFreeWheel(int onoff); | |||
int ComputeTotalLatencies(); | |||
void ShutDown(); | |||
jack_native_thread_t GetThreadID(); | |||
@@ -95,6 +96,7 @@ class LIB_EXPORT JackDebugClient : public JackClient | |||
int PortDisconnect(jack_port_id_t src); | |||
int PortIsMine(jack_port_id_t port_index); | |||
int PortRename(jack_port_id_t port_index, const char* name); | |||
// Transport | |||
int ReleaseTimebase(); | |||
@@ -129,6 +131,9 @@ class LIB_EXPORT JackDebugClient : public JackClient | |||
int InternalClientHandle(const char* client_name, jack_status_t* status); | |||
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); | |||
// RT Thread | |||
int SetProcessThread(JackThreadCallback fun, void *arg); | |||
// Session API | |||
jack_session_command_t* SessionNotify(const char* target, jack_session_event_type_t type, const char* path); | |||
@@ -129,10 +129,7 @@ int JackDriver::Open(bool capturing, | |||
strcpy(fCaptureDriverName, capture_driver_name); | |||
strcpy(fPlaybackDriverName, playback_driver_name); | |||
fEngineControl->fPeriodUsecs = jack_time_t(1000000.f / fEngineControl->fSampleRate * fEngineControl->fBufferSize); // in microsec | |||
if (!fEngineControl->fTimeOut) { | |||
fEngineControl->fTimeOutUsecs = jack_time_t(2.f * fEngineControl->fPeriodUsecs); | |||
} | |||
fEngineControl->UpdateTimeOut(); | |||
fGraphManager->DirectConnect(fClientControl.fRefNum, fClientControl.fRefNum); // Connect driver to itself for "sync" mode | |||
SetupDriverSync(fClientControl.fRefNum, false); | |||
@@ -183,10 +180,7 @@ int JackDriver::Open(jack_nframes_t buffer_size, | |||
strcpy(fCaptureDriverName, capture_driver_name); | |||
strcpy(fPlaybackDriverName, playback_driver_name); | |||
fEngineControl->fPeriodUsecs = jack_time_t(1000000.f / fEngineControl->fSampleRate * fEngineControl->fBufferSize); // in microsec | |||
if (!fEngineControl->fTimeOut) { | |||
fEngineControl->fTimeOutUsecs = jack_time_t(2.f * fEngineControl->fPeriodUsecs); | |||
} | |||
fEngineControl->UpdateTimeOut(); | |||
fGraphManager->SetBufferSize(buffer_size); | |||
fGraphManager->DirectConnect(fClientControl.fRefNum, fClientControl.fRefNum); // Connect driver to itself for "sync" mode | |||
@@ -495,7 +489,7 @@ void JackDriver::SaveConnections() | |||
fConnections.push_back(make_pair(aliases[0], connections[j])); | |||
jack_info("Save connection: %s %s", aliases[0], connections[j]); | |||
*/ | |||
fConnections.push_back(make_pair(fGraphManager->GetPort(fCapturePortList[i])->GetName(), connections[j])); | |||
fConnections.push_back(make_pair(string(fGraphManager->GetPort(fCapturePortList[i])->GetName()), string(connections[j]))); | |||
jack_info("Save connection: %s %s", fGraphManager->GetPort(fCapturePortList[i])->GetName(), connections[j]); | |||
} | |||
free(connections); | |||
@@ -510,7 +504,7 @@ void JackDriver::SaveConnections() | |||
fConnections.push_back(make_pair(connections[j], aliases[0])); | |||
jack_info("Save connection: %s %s", connections[j], aliases[0]); | |||
*/ | |||
fConnections.push_back(make_pair(connections[j], fGraphManager->GetPort(fPlaybackPortList[i])->GetName())); | |||
fConnections.push_back(make_pair(string(connections[j]), string(fGraphManager->GetPort(fPlaybackPortList[i])->GetName()))); | |||
jack_info("Save connection: %s %s", connections[j], fGraphManager->GetPort(fPlaybackPortList[i])->GetName()); | |||
} | |||
free(connections); | |||
@@ -176,7 +176,7 @@ class SERVER_EXPORT JackDriver : public JackDriverClientInterface | |||
void CycleTakeEndTime(); | |||
void SetupDriverSync(int ref, bool freewheel); | |||
void NotifyXRun(jack_time_t callback_usecs, float delayed_usecs); // XRun notification sent by the driver | |||
void NotifyBufferSize(jack_nframes_t buffer_size); // BufferSize notification sent by the driver | |||
void NotifySampleRate(jack_nframes_t sample_rate); // SampleRate notification sent by the driver | |||
@@ -0,0 +1,55 @@ | |||
/* | |||
Copyright (C) 2001-2005 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 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 __JackDriverInfo__ | |||
#define __JackDriverInfo__ | |||
#include "driver_interface.h" | |||
#include "JackDriver.h" | |||
#include "JackSystemDeps.h" | |||
typedef Jack::JackDriverClientInterface* (*driverInitialize) (Jack::JackLockedEngine*, Jack::JackSynchro*, const JSList*); | |||
class SERVER_EXPORT JackDriverInfo | |||
{ | |||
private: | |||
driverInitialize fInitialize; | |||
DRIVER_HANDLE fHandle; | |||
Jack::JackDriverClientInterface* fBackend; | |||
public: | |||
JackDriverInfo():fInitialize(NULL),fHandle(NULL),fBackend(NULL) | |||
{} | |||
~JackDriverInfo(); | |||
Jack::JackDriverClientInterface* Open(jack_driver_desc_t* driver_desc, Jack::JackLockedEngine*, Jack::JackSynchro*, const JSList*); | |||
Jack::JackDriverClientInterface* GetBackend() | |||
{ | |||
return fBackend; | |||
} | |||
}; | |||
#endif | |||
@@ -20,6 +20,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
#include "JackSystemDeps.h" | |||
#include "JackDriverLoader.h" | |||
#include "JackDriverInfo.h" | |||
#include "JackConstants.h" | |||
#include "JackError.h" | |||
#include <getopt.h> | |||
@@ -31,9 +32,57 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
#include <dirent.h> | |||
#endif | |||
#ifdef WIN32 | |||
static char* locate_dll_driver_dir() | |||
{ | |||
#ifdef _WIN64 | |||
HMODULE libjack_handle = LoadLibrary("libjackserver64.dll"); | |||
#else | |||
HMODULE libjack_handle = LoadLibrary("libjackserver.dll"); | |||
#endif | |||
// For WIN32 ADDON_DIR is defined in JackConstants.h as relative path | |||
char driver_dir_storage[512]; | |||
if (3 < GetModuleFileName(libjack_handle, driver_dir_storage, 512)) { | |||
char *p = strrchr(driver_dir_storage, '\\'); | |||
if (p && (p != driver_dir_storage)) { | |||
*p = 0; | |||
} | |||
jack_info("Drivers/internals found in : %s", driver_dir_storage); | |||
strcat(driver_dir_storage, "/"); | |||
strcat(driver_dir_storage, ADDON_DIR); | |||
FreeLibrary(libjack_handle); | |||
return strdup(driver_dir_storage); | |||
} else { | |||
jack_error("Cannot get JACK dll directory : %d", GetLastError()); | |||
FreeLibrary(libjack_handle); | |||
return NULL; | |||
} | |||
} | |||
static char* locate_driver_dir(HANDLE& file, WIN32_FIND_DATA& filedata) | |||
{ | |||
// Search drivers/internals iin the same folder of "libjackserver.dll" | |||
char* driver_dir = locate_dll_driver_dir(); | |||
char dll_filename[512]; | |||
snprintf(dll_filename, sizeof(dll_filename), "%s/*.dll", driver_dir); | |||
file = (HANDLE)FindFirstFile(dll_filename, &filedata); | |||
if (file == INVALID_HANDLE_VALUE) { | |||
jack_error("Drivers not found "); | |||
free(driver_dir); | |||
return NULL; | |||
} else { | |||
return driver_dir; | |||
} | |||
} | |||
#endif | |||
jack_driver_desc_t* jackctl_driver_get_desc(jackctl_driver_t * driver); | |||
SERVER_EXPORT void jack_print_driver_options(jack_driver_desc_t* desc, FILE* file) | |||
void jack_print_driver_options(jack_driver_desc_t* desc, FILE* file) | |||
{ | |||
unsigned long i; | |||
char arg_default[JACK_DRIVER_PARAM_STRING_MAX + 1]; | |||
@@ -69,15 +118,14 @@ SERVER_EXPORT void jack_print_driver_options(jack_driver_desc_t* desc, FILE* fil | |||
} | |||
} | |||
static void | |||
jack_print_driver_param_usage (jack_driver_desc_t* desc, unsigned long param, FILE *file) | |||
static void jack_print_driver_param_usage (jack_driver_desc_t* desc, unsigned long param, FILE *file) | |||
{ | |||
fprintf (file, "Usage information for the '%s' parameter for driver '%s':\n", | |||
desc->params[param].name, desc->name); | |||
fprintf (file, "%s\n", desc->params[param].long_desc); | |||
} | |||
SERVER_EXPORT void jack_free_driver_params(JSList * driver_params) | |||
void jack_free_driver_params(JSList * driver_params) | |||
{ | |||
JSList*node_ptr = driver_params; | |||
JSList*next_node_ptr; | |||
@@ -90,8 +138,7 @@ SERVER_EXPORT void jack_free_driver_params(JSList * driver_params) | |||
} | |||
} | |||
SERVER_EXPORT int | |||
jack_parse_driver_params(jack_driver_desc_t* desc, int argc, char* argv[], JSList** param_ptr) | |||
int jack_parse_driver_params(jack_driver_desc_t* desc, int argc, char* argv[], JSList** param_ptr) | |||
{ | |||
struct option * long_options; | |||
char* options, * options_ptr; | |||
@@ -116,7 +163,7 @@ jack_parse_driver_params(jack_driver_desc_t* desc, int argc, char* argv[], JSLis | |||
} | |||
} | |||
fprintf (stderr, "jackd: unknown option '%s' " | |||
fprintf (stderr, "Jackd: unknown option '%s' " | |||
"for driver '%s'\n", argv[2], | |||
desc->name); | |||
} | |||
@@ -218,8 +265,7 @@ jack_parse_driver_params(jack_driver_desc_t* desc, int argc, char* argv[], JSLis | |||
return 0; | |||
} | |||
SERVER_EXPORT int | |||
jackctl_parse_driver_params(jackctl_driver *driver_ptr, int argc, char* argv[]) | |||
SERVER_EXPORT int jackctl_driver_params_parse(jackctl_driver *driver_ptr, int argc, char* argv[]) | |||
{ | |||
struct option* long_options; | |||
char* options, * options_ptr; | |||
@@ -250,7 +296,7 @@ jackctl_parse_driver_params(jackctl_driver *driver_ptr, int argc, char* argv[]) | |||
} | |||
} | |||
fprintf (stderr, "jackd: unknown option '%s' " | |||
fprintf (stderr, "Jackd: unknown option '%s' " | |||
"for driver '%s'\n", argv[2], | |||
desc->name); | |||
} | |||
@@ -352,8 +398,7 @@ jackctl_parse_driver_params(jackctl_driver *driver_ptr, int argc, char* argv[]) | |||
return 0; | |||
} | |||
jack_driver_desc_t* | |||
jack_find_driver_descriptor (JSList * drivers, const char* name) | |||
jack_driver_desc_t* jack_find_driver_descriptor (JSList * drivers, const char* name) | |||
{ | |||
jack_driver_desc_t* desc = 0; | |||
JSList* node; | |||
@@ -371,193 +416,87 @@ jack_find_driver_descriptor (JSList * drivers, const char* name) | |||
return desc; | |||
} | |||
static jack_driver_desc_t* | |||
jack_get_descriptor (JSList * drivers, const char* sofile, const char* symbol) | |||
static void* check_symbol(const char* sofile, const char* symbol, const char* driver_dir, void** res_dllhandle = NULL) | |||
{ | |||
jack_driver_desc_t* descriptor, * other_descriptor; | |||
JackDriverDescFunction so_get_descriptor = NULL; | |||
JSList* node; | |||
void * dlhandle; | |||
char* filename; | |||
void* dlhandle; | |||
void* res = NULL; | |||
char filename[1024]; | |||
sprintf(filename, "%s/%s", driver_dir, sofile); | |||
if ((dlhandle = LoadDriverModule(filename)) == NULL) { | |||
#ifdef WIN32 | |||
int dlerr; | |||
jack_error ("Could not open component .dll '%s': %ld", filename, GetLastError()); | |||
#else | |||
const char* dlerr; | |||
jack_error ("Could not open component .so '%s': %s", filename, dlerror()); | |||
#endif | |||
int err; | |||
const char* driver_dir; | |||
if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) { | |||
// for WIN32 ADDON_DIR is defined in JackConstants.h as relative path | |||
// for posix systems, it is absolute path of default driver dir | |||
#ifdef WIN32 | |||
char temp_driver_dir1[512]; | |||
char temp_driver_dir2[512]; | |||
if (3 < GetModuleFileName(NULL, temp_driver_dir1, 512)) { | |||
char *p = strrchr(temp_driver_dir1, '\\'); | |||
if (p && (p != temp_driver_dir1)) | |||
*p = 0; | |||
else | |||
GetCurrentDirectory(512, temp_driver_dir1); | |||
} else { | |||
res = (void*)GetDriverProc(dlhandle, symbol); | |||
if (res_dllhandle) { | |||
*res_dllhandle = dlhandle; | |||
} else { | |||
GetCurrentDirectory(512, temp_driver_dir1); | |||
UnloadDriverModule(dlhandle); | |||
} | |||
sprintf(temp_driver_dir2, "%s/%s", temp_driver_dir1, ADDON_DIR); | |||
driver_dir = temp_driver_dir2; | |||
#else | |||
driver_dir = ADDON_DIR; | |||
#endif | |||
} | |||
int len = strlen(driver_dir) + 1 + strlen(sofile) + 1; | |||
filename = (char*)malloc(len); | |||
snprintf(filename, len, "%s/%s", driver_dir, sofile); | |||
if ((dlhandle = LoadDriverModule(filename)) == NULL) { | |||
#ifdef WIN32 | |||
jack_error ("could not open driver .dll '%s': %ld", filename, GetLastError()); | |||
#else | |||
jack_error ("could not open driver .so '%s': %s", filename, dlerror()); | |||
#endif | |||
free(filename); | |||
return NULL; | |||
} | |||
return res; | |||
} | |||
so_get_descriptor = (JackDriverDescFunction)GetDriverProc(dlhandle, symbol); | |||
static jack_driver_desc_t* jack_get_descriptor (JSList* drivers, const char* sofile, const char* symbol, const char* driver_dir) | |||
{ | |||
jack_driver_desc_t* descriptor = NULL; | |||
jack_driver_desc_t* other_descriptor; | |||
JackDriverDescFunction so_get_descriptor = NULL; | |||
char filename[1024]; | |||
JSList* node; | |||
void* dlhandle; | |||
#ifdef WIN32 | |||
if ((so_get_descriptor == NULL) && (dlerr = GetLastError()) != 0) { | |||
jack_error("jack_get_descriptor : dll is not a driver, err = %ld", dlerr); | |||
#else | |||
if ((so_get_descriptor == NULL) && (dlerr = dlerror ()) != NULL) { | |||
jack_error("jack_get_descriptor err = %s", dlerr); | |||
#endif | |||
sprintf(filename, "%s/%s", driver_dir, sofile); | |||
so_get_descriptor = (JackDriverDescFunction)check_symbol(sofile, symbol, driver_dir, &dlhandle); | |||
UnloadDriverModule(dlhandle); | |||
free(filename); | |||
return NULL; | |||
if (so_get_descriptor == NULL) { | |||
jack_error("jack_get_descriptor : dll %s is not a driver", sofile); | |||
goto error; | |||
} | |||
if ((descriptor = so_get_descriptor ()) == NULL) { | |||
jack_error("driver from '%s' returned NULL descriptor", filename); | |||
UnloadDriverModule(dlhandle); | |||
free(filename); | |||
return NULL; | |||
jack_error("Driver from '%s' returned NULL descriptor", filename); | |||
goto error; | |||
} | |||
#ifdef WIN32 | |||
if ((err = UnloadDriverModule(dlhandle)) == 0) { | |||
jack_error ("error closing driver .so '%s': %ld", filename, GetLastError ()); | |||
} | |||
#else | |||
if ((err = UnloadDriverModule(dlhandle)) != 0) { | |||
jack_error ("error closing driver .so '%s': %s", filename, dlerror ()); | |||
} | |||
#endif | |||
/* check it doesn't exist already */ | |||
for (node = drivers; node; node = jack_slist_next (node)) { | |||
other_descriptor = (jack_driver_desc_t*) node->data; | |||
if (strcmp(descriptor->name, other_descriptor->name) == 0) { | |||
jack_error("the drivers in '%s' and '%s' both have the name '%s'; using the first", | |||
jack_error("The drivers in '%s' and '%s' both have the name '%s'; using the first", | |||
other_descriptor->file, filename, other_descriptor->name); | |||
/* FIXME: delete the descriptor */ | |||
free(filename); | |||
return NULL; | |||
goto error; | |||
} | |||
} | |||
strncpy(descriptor->file, filename, JACK_PATH_MAX); | |||
free(filename); | |||
return descriptor; | |||
} | |||
static bool check_symbol(const char* sofile, const char* symbol) | |||
{ | |||
void * dlhandle; | |||
bool res = false; | |||
const char* driver_dir; | |||
error: | |||
if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) { | |||
// for WIN32 ADDON_DIR is defined in JackConstants.h as relative path | |||
// for posix systems, it is absolute path of default driver dir | |||
#ifdef WIN32 | |||
char temp_driver_dir1[512]; | |||
char temp_driver_dir2[512]; | |||
if (3 < GetModuleFileName(NULL, temp_driver_dir1, 512)) { | |||
char *p = strrchr(temp_driver_dir1, '\\'); | |||
if (p && (p != temp_driver_dir1)) | |||
*p = 0; | |||
else | |||
GetCurrentDirectory(512, temp_driver_dir1); | |||
} else { | |||
GetCurrentDirectory(512, temp_driver_dir1); | |||
} | |||
snprintf(temp_driver_dir2, sizeof(temp_driver_dir2), "%s/%s", temp_driver_dir1, ADDON_DIR); | |||
driver_dir = temp_driver_dir2; | |||
#else | |||
driver_dir = ADDON_DIR; | |||
#endif | |||
} | |||
int len = strlen(driver_dir) + 1 + strlen(sofile) + 1; | |||
char* filename = (char*)malloc(len); | |||
snprintf(filename, len, "%s/%s", driver_dir, sofile); | |||
if ((dlhandle = LoadDriverModule(filename)) == NULL) { | |||
#ifdef WIN32 | |||
jack_error ("could not open component .dll '%s': %ld", filename, GetLastError()); | |||
#else | |||
jack_error ("could not open component .so '%s': %s", filename, dlerror()); | |||
#endif | |||
} else { | |||
res = (GetDriverProc(dlhandle, symbol)) ? true : false; | |||
UnloadDriverModule(dlhandle); | |||
} | |||
free(filename); | |||
return res; | |||
UnloadDriverModule(dlhandle); | |||
return descriptor; | |||
} | |||
#ifdef WIN32 | |||
JSList * | |||
jack_drivers_load (JSList * drivers) { | |||
char* driver_dir; | |||
char driver_dir_storage[512]; | |||
char dll_filename[512]; | |||
JSList * jack_drivers_load(JSList * drivers) | |||
{ | |||
//char dll_filename[512]; | |||
WIN32_FIND_DATA filedata; | |||
HANDLE file; | |||
const char* ptr = NULL; | |||
JSList* driver_list = NULL; | |||
jack_driver_desc_t* desc = NULL; | |||
if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) { | |||
// for WIN32 ADDON_DIR is defined in JackConstants.h as relative path | |||
if (3 < GetModuleFileName(NULL, driver_dir_storage, 512)) { | |||
char *p = strrchr(driver_dir_storage, '\\'); | |||
if (p && (p != driver_dir_storage)) | |||
*p = 0; | |||
else | |||
GetCurrentDirectory(512, driver_dir_storage); | |||
} else { | |||
GetCurrentDirectory(512, driver_dir_storage); | |||
} | |||
strcat(driver_dir_storage, "/"); | |||
strcat(driver_dir_storage, ADDON_DIR); | |||
driver_dir = driver_dir_storage; | |||
} | |||
snprintf(dll_filename, sizeof(dll_filename), "%s/*.dll", driver_dir); | |||
file = (HANDLE )FindFirstFile(dll_filename, &filedata); | |||
if (file == INVALID_HANDLE_VALUE) { | |||
jack_error("error invalid handle"); | |||
return NULL; | |||
char* driver_dir = locate_driver_dir(file, filedata); | |||
if (!driver_dir) { | |||
jack_error("Driver folder not found"); | |||
goto error; | |||
} | |||
do { | |||
@@ -570,17 +509,18 @@ jack_drivers_load (JSList * drivers) { | |||
if (!ptr) { | |||
continue; | |||
} | |||
ptr++; | |||
if (strncmp ("dll", ptr, 3) != 0) { | |||
continue; | |||
} | |||
/* check if dll is an internal client */ | |||
if (check_symbol(filedata.cFileName, "jack_internal_initialize")) { | |||
continue; | |||
if (check_symbol(filedata.cFileName, "jack_internal_initialize", driver_dir) != NULL) { | |||
continue; | |||
} | |||
desc = jack_get_descriptor (drivers, filedata.cFileName, "driver_get_descriptor"); | |||
desc = jack_get_descriptor (drivers, filedata.cFileName, "driver_get_descriptor", driver_dir); | |||
if (desc) { | |||
driver_list = jack_slist_append (driver_list, desc); | |||
} else { | |||
@@ -590,17 +530,21 @@ jack_drivers_load (JSList * drivers) { | |||
} while (FindNextFile(file, &filedata)); | |||
if (!driver_list) { | |||
jack_error ("could not find any drivers in %s!", driver_dir); | |||
return NULL; | |||
jack_error ("Could not find any drivers in %s!", driver_dir); | |||
} | |||
error: | |||
if (driver_dir) { | |||
free(driver_dir); | |||
} | |||
FindClose(file); | |||
return driver_list; | |||
} | |||
#else | |||
JSList * | |||
jack_drivers_load (JSList * drivers) { | |||
JSList* jack_drivers_load (JSList * drivers) | |||
{ | |||
struct dirent * dir_entry; | |||
DIR * dir_stream; | |||
const char* ptr; | |||
@@ -617,7 +561,7 @@ jack_drivers_load (JSList * drivers) { | |||
from the .so files in it */ | |||
dir_stream = opendir (driver_dir); | |||
if (!dir_stream) { | |||
jack_error ("could not open driver directory %s: %s", | |||
jack_error ("Could not open driver directory %s: %s", | |||
driver_dir, strerror (errno)); | |||
return NULL; | |||
} | |||
@@ -639,11 +583,11 @@ jack_drivers_load (JSList * drivers) { | |||
} | |||
/* check if dll is an internal client */ | |||
if (check_symbol(dir_entry->d_name, "jack_internal_initialize")) { | |||
continue; | |||
if (check_symbol(dir_entry->d_name, "jack_internal_initialize", driver_dir) != NULL) { | |||
continue; | |||
} | |||
desc = jack_get_descriptor (drivers, dir_entry->d_name, "driver_get_descriptor"); | |||
desc = jack_get_descriptor (drivers, dir_entry->d_name, "driver_get_descriptor", driver_dir); | |||
if (desc) { | |||
driver_list = jack_slist_append (driver_list, desc); | |||
} else { | |||
@@ -653,12 +597,12 @@ jack_drivers_load (JSList * drivers) { | |||
err = closedir (dir_stream); | |||
if (err) { | |||
jack_error ("error closing driver directory %s: %s", | |||
jack_error ("Error closing driver directory %s: %s", | |||
driver_dir, strerror (errno)); | |||
} | |||
if (!driver_list) { | |||
jack_error ("could not find any drivers in %s!", driver_dir); | |||
jack_error ("Could not find any drivers in %s!", driver_dir); | |||
return NULL; | |||
} | |||
@@ -669,40 +613,19 @@ jack_drivers_load (JSList * drivers) { | |||
#ifdef WIN32 | |||
JSList * | |||
jack_internals_load (JSList * internals) { | |||
char* driver_dir; | |||
char driver_dir_storage[512]; | |||
char dll_filename[512]; | |||
JSList* jack_internals_load(JSList * internals) | |||
{ | |||
///char dll_filename[512]; | |||
WIN32_FIND_DATA filedata; | |||
HANDLE file; | |||
const char* ptr = NULL; | |||
JSList* driver_list = NULL; | |||
jack_driver_desc_t* desc; | |||
if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) { | |||
// for WIN32 ADDON_DIR is defined in JackConstants.h as relative path | |||
if (3 < GetModuleFileName(NULL, driver_dir_storage, 512)) { | |||
char *p = strrchr(driver_dir_storage, '\\'); | |||
if (p && (p != driver_dir_storage)) | |||
*p = 0; | |||
else | |||
GetCurrentDirectory(512, driver_dir_storage); | |||
} else { | |||
GetCurrentDirectory(512, driver_dir_storage); | |||
} | |||
strcat(driver_dir_storage, "/"); | |||
strcat(driver_dir_storage, ADDON_DIR); | |||
driver_dir = driver_dir_storage; | |||
} | |||
snprintf(dll_filename, sizeof(dll_filename), "%s/*.dll", driver_dir); | |||
file = (HANDLE )FindFirstFile(dll_filename, &filedata); | |||
if (file == INVALID_HANDLE_VALUE) { | |||
jack_error("could not open driver directory %s", driver_dir); | |||
return NULL; | |||
char* driver_dir = locate_driver_dir(file, filedata); | |||
if (!driver_dir) { | |||
jack_error("Driver folder not found"); | |||
goto error; | |||
} | |||
do { | |||
@@ -711,17 +634,18 @@ jack_internals_load (JSList * internals) { | |||
if (!ptr) { | |||
continue; | |||
} | |||
ptr++; | |||
if (strncmp ("dll", ptr, 3) != 0) { | |||
continue; | |||
} | |||
/* check if dll is an internal client */ | |||
if (!check_symbol(filedata.cFileName, "jack_internal_initialize")) { | |||
continue; | |||
if (check_symbol(filedata.cFileName, "jack_internal_initialize", driver_dir) == NULL) { | |||
continue; | |||
} | |||
desc = jack_get_descriptor (internals, filedata.cFileName, "jack_get_descriptor"); | |||
desc = jack_get_descriptor (internals, filedata.cFileName, "jack_get_descriptor", driver_dir); | |||
if (desc) { | |||
driver_list = jack_slist_append (driver_list, desc); | |||
} else { | |||
@@ -731,17 +655,21 @@ jack_internals_load (JSList * internals) { | |||
} while (FindNextFile(file, &filedata)); | |||
if (!driver_list) { | |||
jack_error ("could not find any internals in %s!", driver_dir); | |||
return NULL; | |||
jack_error ("Could not find any internals in %s!", driver_dir); | |||
} | |||
error: | |||
if (driver_dir) { | |||
free(driver_dir); | |||
} | |||
FindClose(file); | |||
return driver_list; | |||
} | |||
#else | |||
JSList * | |||
jack_internals_load (JSList * internals) { | |||
JSList* jack_internals_load(JSList * internals) | |||
{ | |||
struct dirent * dir_entry; | |||
DIR * dir_stream; | |||
const char* ptr; | |||
@@ -758,7 +686,7 @@ jack_internals_load (JSList * internals) { | |||
from the .so files in it */ | |||
dir_stream = opendir (driver_dir); | |||
if (!dir_stream) { | |||
jack_error ("could not open driver directory %s: %s\n", | |||
jack_error ("Could not open driver directory %s: %s\n", | |||
driver_dir, strerror (errno)); | |||
return NULL; | |||
} | |||
@@ -769,17 +697,18 @@ jack_internals_load (JSList * internals) { | |||
if (!ptr) { | |||
continue; | |||
} | |||
ptr++; | |||
if (strncmp ("so", ptr, 2) != 0) { | |||
continue; | |||
} | |||
/* check if dll is an internal client */ | |||
if (!check_symbol(dir_entry->d_name, "jack_internal_initialize")) { | |||
continue; | |||
if (check_symbol(dir_entry->d_name, "jack_internal_initialize", driver_dir) == NULL) { | |||
continue; | |||
} | |||
desc = jack_get_descriptor (internals, dir_entry->d_name, "jack_get_descriptor"); | |||
desc = jack_get_descriptor (internals, dir_entry->d_name, "jack_get_descriptor", driver_dir); | |||
if (desc) { | |||
driver_list = jack_slist_append (driver_list, desc); | |||
} else { | |||
@@ -789,12 +718,12 @@ jack_internals_load (JSList * internals) { | |||
err = closedir (dir_stream); | |||
if (err) { | |||
jack_error ("error closing internal directory %s: %s\n", | |||
jack_error ("Error closing internal directory %s: %s\n", | |||
driver_dir, strerror (errno)); | |||
} | |||
if (!driver_list) { | |||
jack_error ("could not find any internals in %s!", driver_dir); | |||
jack_error ("Could not find any internals in %s!", driver_dir); | |||
return NULL; | |||
} | |||
@@ -819,14 +748,14 @@ Jack::JackDriverClientInterface* JackDriverInfo::Open(jack_driver_desc_t* driver | |||
if (fHandle == NULL) { | |||
#ifdef WIN32 | |||
if ((errstr = GetLastError ()) != 0) { | |||
jack_error ("can't load \"%s\": %ld", driver_desc->file, errstr); | |||
jack_error ("Can't load \"%s\": %ld", driver_desc->file, errstr); | |||
#else | |||
if ((errstr = dlerror ()) != 0) { | |||
jack_error ("can't load \"%s\": %s", driver_desc->file, errstr); | |||
jack_error ("Can't load \"%s\": %s", driver_desc->file, errstr); | |||
#endif | |||
} else { | |||
jack_error ("bizarre error loading driver shared object %s", driver_desc->file); | |||
jack_error ("Error loading driver shared object %s", driver_desc->file); | |||
} | |||
return NULL; | |||
} | |||
@@ -838,7 +767,7 @@ Jack::JackDriverClientInterface* JackDriverInfo::Open(jack_driver_desc_t* driver | |||
#else | |||
if ((fInitialize == NULL) && (errstr = dlerror ()) != 0) { | |||
#endif | |||
jack_error("no initialize function in shared object %s\n", driver_desc->file); | |||
jack_error("No initialize function in shared object %s\n", driver_desc->file); | |||
return NULL; | |||
} | |||
@@ -849,13 +778,12 @@ Jack::JackDriverClientInterface* JackDriverInfo::Open(jack_driver_desc_t* driver | |||
JackDriverInfo::~JackDriverInfo() | |||
{ | |||
delete fBackend; | |||
if (fHandle) | |||
if (fHandle) { | |||
UnloadDriverModule(fHandle); | |||
} | |||
} | |||
SERVER_EXPORT | |||
jack_driver_desc_t* | |||
jack_driver_descriptor_construct( | |||
SERVER_EXPORT jack_driver_desc_t* jack_driver_descriptor_construct( | |||
const char * name, | |||
jack_driver_type_t type, | |||
const char * description, | |||
@@ -876,7 +804,7 @@ jack_driver_descriptor_construct( | |||
desc_ptr = (jack_driver_desc_t*)calloc (1, sizeof (jack_driver_desc_t)); | |||
if (desc_ptr == NULL) { | |||
jack_error("calloc() failed to allocate memory for driver descriptor struct"); | |||
jack_error("Error calloc() failed to allocate memory for driver descriptor struct"); | |||
return 0; | |||
} | |||
@@ -893,9 +821,7 @@ jack_driver_descriptor_construct( | |||
return desc_ptr; | |||
} | |||
SERVER_EXPORT | |||
int | |||
jack_driver_descriptor_add_parameter( | |||
SERVER_EXPORT int jack_driver_descriptor_add_parameter( | |||
jack_driver_desc_t* desc_ptr, | |||
jack_driver_desc_filler_t * filler_ptr, | |||
const char* name, | |||
@@ -933,7 +859,7 @@ jack_driver_descriptor_add_parameter( | |||
newsize = filler_ptr->size + 20; // most drivers have less than 20 parameters | |||
param_ptr = (jack_driver_param_desc_t*)realloc (desc_ptr->params, newsize * sizeof (jack_driver_param_desc_t)); | |||
if (param_ptr == NULL) { | |||
jack_error("realloc() failed for parameter array of %zu elements", newsize); | |||
jack_error("Error realloc() failed for parameter array of %zu elements", newsize); | |||
return false; | |||
} | |||
filler_ptr->size = newsize; | |||
@@ -952,6 +878,5 @@ jack_driver_descriptor_add_parameter( | |||
memcpy(param_ptr->long_desc, long_desc, long_desc_len + 1); | |||
desc_ptr->nparams++; | |||
return true; | |||
} |
@@ -24,53 +24,15 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
#include "driver_interface.h" | |||
#include "JackControlAPI.h" | |||
#include "JackPlatformPlug.h" | |||
#include "JackDriver.h" | |||
#include "JackSystemDeps.h" | |||
typedef jack_driver_desc_t* (*JackDriverDescFunction) (); | |||
typedef Jack::JackDriverClientInterface* (*driverInitialize) (Jack::JackLockedEngine*, Jack::JackSynchro*, const JSList*); | |||
class SERVER_EXPORT JackDriverInfo | |||
{ | |||
private: | |||
driverInitialize fInitialize; | |||
DRIVER_HANDLE fHandle; | |||
Jack::JackDriverClientInterface* fBackend; | |||
public: | |||
JackDriverInfo():fInitialize(NULL),fHandle(NULL),fBackend(NULL) | |||
{} | |||
~JackDriverInfo(); | |||
Jack::JackDriverClientInterface* Open(jack_driver_desc_t* driver_desc, Jack::JackLockedEngine*, Jack::JackSynchro*, const JSList*); | |||
Jack::JackDriverClientInterface* GetBackend() | |||
{ | |||
return fBackend; | |||
} | |||
}; | |||
jack_driver_desc_t* jack_find_driver_descriptor(JSList* drivers, const char* name); | |||
JSList* jack_drivers_load(JSList* drivers); | |||
JSList* jack_internals_load(JSList* internals); | |||
void jack_free_driver_params(JSList * param_ptr); | |||
void jack_print_driver_options(jack_driver_desc_t* desc, FILE* file); | |||
#ifdef __cplusplus | |||
extern "C" | |||
{ | |||
#endif | |||
SERVER_EXPORT int jackctl_parse_driver_params(jackctl_driver * driver_ptr, int argc, char* argv[]); | |||
SERVER_EXPORT void jack_free_driver_params(JSList * param_ptr); | |||
SERVER_EXPORT void jack_print_driver_options(jack_driver_desc_t* desc, FILE* file); | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
// External control.h API | |||
extern "C" SERVER_EXPORT int jackctl_driver_params_parse(jackctl_driver * driver, int argc, char* argv[]); | |||
#endif | |||
@@ -38,13 +38,16 @@ namespace Jack | |||
JackEngine::JackEngine(JackGraphManager* manager, | |||
JackSynchro* table, | |||
JackEngineControl* control) | |||
JackEngineControl* control) | |||
: JackLockAble(control->fServerName), | |||
fSignal(control->fServerName) | |||
{ | |||
fGraphManager = manager; | |||
fSynchroTable = table; | |||
fEngineControl = control; | |||
for (int i = 0; i < CLIENT_NUM; i++) | |||
for (int i = 0; i < CLIENT_NUM; i++) { | |||
fClientTable[i] = NULL; | |||
} | |||
fLastSwitchUsecs = 0; | |||
fMaxUUID = 0; | |||
fSessionPendingReplies = 0; | |||
@@ -78,20 +81,33 @@ int JackEngine::Close() | |||
if (JackLoadableInternalClient* loadable_client = dynamic_cast<JackLoadableInternalClient*>(fClientTable[i])) { | |||
jack_log("JackEngine::Close loadable client = %s", loadable_client->GetClientControl()->fName); | |||
loadable_client->Close(); | |||
// Close does not delete the pointer for internal clients | |||
fClientTable[i] = NULL; | |||
delete loadable_client; | |||
} else if (JackExternalClient* external_client = dynamic_cast<JackExternalClient*>(fClientTable[i])) { | |||
jack_log("JackEngine::Close external client = %s", external_client->GetClientControl()->fName); | |||
external_client->Close(); | |||
// Close deletes the pointer for external clients | |||
fClientTable[i] = NULL; | |||
delete external_client; | |||
} | |||
} | |||
return 0; | |||
} | |||
void JackEngine::ShutDown() | |||
{ | |||
jack_log("JackEngine::ShutDown"); | |||
// Shutdown remaining clients (RT is stopped) | |||
for (int i = fEngineControl->fDriverNum; i < CLIENT_NUM; i++) { | |||
if (JackLoadableInternalClient* loadable_client = dynamic_cast<JackLoadableInternalClient*>(fClientTable[i])) { | |||
jack_log("JackEngine::ShutDown loadable client = %s", loadable_client->GetClientControl()->fName); | |||
loadable_client->ShutDown(); | |||
} | |||
} | |||
} | |||
void JackEngine::NotifyQuit() | |||
{ | |||
fChannel.NotifyQuit(); | |||
@@ -119,8 +135,9 @@ void JackEngine::ReleaseRefnum(int ref) | |||
if (fEngineControl->fTemporary) { | |||
int i; | |||
for (i = fEngineControl->fDriverNum; i < CLIENT_NUM; i++) { | |||
if (fClientTable[i]) | |||
if (fClientTable[i]) { | |||
break; | |||
} | |||
} | |||
if (i == CLIENT_NUM) { | |||
// last client and temporay case: quit the server | |||
@@ -146,8 +163,9 @@ void JackEngine::ProcessNext(jack_time_t cur_cycle_begin) | |||
void JackEngine::ProcessCurrent(jack_time_t cur_cycle_begin) | |||
{ | |||
if (cur_cycle_begin < fLastSwitchUsecs + 2 * fEngineControl->fPeriodUsecs) // Signal XRun only for the first failing cycle | |||
if (cur_cycle_begin < fLastSwitchUsecs + 2 * fEngineControl->fPeriodUsecs) { // Signal XRun only for the first failing cycle | |||
CheckXRun(cur_cycle_begin); | |||
} | |||
fGraphManager->RunCurrentGraph(); | |||
} | |||
@@ -157,7 +175,7 @@ bool JackEngine::Process(jack_time_t cur_cycle_begin, jack_time_t prev_cycle_end | |||
// Cycle begin | |||
fEngineControl->CycleBegin(fClientTable, fGraphManager, cur_cycle_begin, prev_cycle_end); | |||
// Graph | |||
if (fGraphManager->IsFinishedGraph()) { | |||
ProcessNext(cur_cycle_begin); | |||
@@ -236,26 +254,42 @@ int JackEngine::ComputeTotalLatencies() | |||
// Notifications | |||
//--------------- | |||
int JackEngine::ClientNotify(JackClientInterface* client, int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2) | |||
{ | |||
if (!client) { | |||
return 0; | |||
} | |||
if (!client->GetClientControl()->fCallback[notify]) { | |||
jack_log("JackEngine::ClientNotify: no callback for notification = %ld", notify); | |||
return 0; | |||
} | |||
int ret; | |||
// External client | |||
if (dynamic_cast<JackExternalClient*>(client)) { | |||
ret = client->ClientNotify(refnum, name, notify, sync, message, value1, value2); | |||
// Important for internal client : unlock before calling the notification callbacks | |||
} else { | |||
bool res = Unlock(); | |||
ret = client->ClientNotify(refnum, name, notify, sync, message, value1, value2); | |||
if (res) { | |||
Lock(); | |||
} | |||
} | |||
if (ret < 0) { | |||
jack_error("NotifyClient fails name = %s notification = %ld val1 = %ld val2 = %ld", name, notify, value1, value2); | |||
} | |||
return ret; | |||
} | |||
void JackEngine::NotifyClient(int refnum, int event, int sync, const char* message, int value1, int value2) | |||
{ | |||
JackClientInterface* client = fClientTable[refnum]; | |||
// The client may be notified by the RT thread while closing | |||
if (client) { | |||
if (client->GetClientControl()->fCallback[event]) { | |||
/* | |||
Important for internal clients : unlock before calling the notification callbacks. | |||
*/ | |||
bool res = Unlock(); | |||
if (client->ClientNotify(refnum, client->GetClientControl()->fName, event, sync, message, value1, value2) < 0) | |||
jack_error("NotifyClient fails name = %s event = %ld val1 = %ld val2 = %ld", client->GetClientControl()->fName, event, value1, value2); | |||
if (res) | |||
Lock(); | |||
} else { | |||
jack_log("JackEngine::NotifyClient: no callback for event = %ld", event); | |||
} | |||
ClientNotify(client, refnum, client->GetClientControl()->fName, event, sync, message, value1, value2); | |||
} | |||
} | |||
@@ -266,19 +300,21 @@ void JackEngine::NotifyClients(int event, int sync, const char* message, int val | |||
} | |||
} | |||
int JackEngine::NotifyAddClient(JackClientInterface* new_client, const char* name, int refnum) | |||
int JackEngine::NotifyAddClient(JackClientInterface* new_client, const char* new_name, int refnum) | |||
{ | |||
jack_log("JackEngine::NotifyAddClient: name = %s", name); | |||
jack_log("JackEngine::NotifyAddClient: name = %s", new_name); | |||
// Notify existing clients of the new client and new client of existing clients. | |||
for (int i = 0; i < CLIENT_NUM; i++) { | |||
JackClientInterface* old_client = fClientTable[i]; | |||
if (old_client && old_client != new_client) { | |||
if (old_client->ClientNotify(refnum, name, kAddClient, false, "", 0, 0) < 0) { | |||
jack_error("NotifyAddClient old_client fails name = %s", old_client->GetClientControl()->fName); | |||
char* old_name = old_client->GetClientControl()->fName; | |||
if (ClientNotify(old_client, refnum, new_name, kAddClient, false, "", 0, 0) < 0) { | |||
jack_error("NotifyAddClient old_client fails name = %s", old_name); | |||
// Not considered as a failure... | |||
} | |||
if (new_client->ClientNotify(i, old_client->GetClientControl()->fName, kAddClient, true, "", 0, 0) < 0) { | |||
jack_error("NotifyAddClient new_client fails name = %s", name); | |||
if (ClientNotify(new_client, i, old_name, kAddClient, true, "", 0, 0) < 0) { | |||
jack_error("NotifyAddClient new_client fails name = %s", new_name); | |||
return -1; | |||
} | |||
} | |||
@@ -291,10 +327,7 @@ void JackEngine::NotifyRemoveClient(const char* name, int refnum) | |||
{ | |||
// Notify existing clients (including the one beeing suppressed) of the removed client | |||
for (int i = 0; i < CLIENT_NUM; i++) { | |||
JackClientInterface* client = fClientTable[i]; | |||
if (client) { | |||
client->ClientNotify(refnum, name, kRemoveClient, false, "", 0, 0); | |||
} | |||
ClientNotify(fClientTable[i], refnum, name, kRemoveClient, false, "", 0, 0); | |||
} | |||
} | |||
@@ -491,13 +524,15 @@ bool JackEngine::ClientCheckName(const char* name) | |||
{ | |||
for (int i = 0; i < CLIENT_NUM; i++) { | |||
JackClientInterface* client = fClientTable[i]; | |||
if (client && (strcmp(client->GetClientControl()->fName, name) == 0)) | |||
if (client && (strcmp(client->GetClientControl()->fName, name) == 0)) { | |||
return true; | |||
} | |||
} | |||
for (std::map<int,std::string>::iterator i = fReservationMap.begin(); i != fReservationMap.end(); i++) { | |||
if (i->second == name) | |||
if (i->second == name) { | |||
return true; | |||
} | |||
} | |||
return false; | |||
@@ -510,8 +545,9 @@ int JackEngine::GetNewUUID() | |||
void JackEngine::EnsureUUID(int uuid) | |||
{ | |||
if (uuid > fMaxUUID) | |||
fMaxUUID = uuid+1; | |||
if (uuid > fMaxUUID) { | |||
fMaxUUID = uuid + 1; | |||
} | |||
for (int i = 0; i < CLIENT_NUM; i++) { | |||
JackClientInterface* client = fClientTable[i]; | |||
@@ -525,8 +561,9 @@ int JackEngine::GetClientPID(const char* name) | |||
{ | |||
for (int i = 0; i < CLIENT_NUM; i++) { | |||
JackClientInterface* client = fClientTable[i]; | |||
if (client && (strcmp(client->GetClientControl()->fName, name) == 0)) | |||
if (client && (strcmp(client->GetClientControl()->fName, name) == 0)) { | |||
return client->GetClientControl()->fPID; | |||
} | |||
} | |||
return 0; | |||
@@ -536,8 +573,9 @@ int JackEngine::GetClientRefNum(const char* name) | |||
{ | |||
for (int i = 0; i < CLIENT_NUM; i++) { | |||
JackClientInterface* client = fClientTable[i]; | |||
if (client && (strcmp(client->GetClientControl()->fName, name) == 0)) | |||
if (client && (strcmp(client->GetClientControl()->fName, name) == 0)) { | |||
return client->GetClientControl()->fRefNum; | |||
} | |||
} | |||
return -1; | |||
@@ -657,9 +695,9 @@ error: | |||
// Used for external clients | |||
int JackEngine::ClientExternalClose(int refnum) | |||
{ | |||
jack_log("JackEngine::ClientExternalClose ref = %ld", refnum); | |||
JackClientInterface* client = fClientTable[refnum]; | |||
fEngineControl->fTransport.ResetTimebase(refnum); | |||
int res = ClientCloseAux(refnum, client, true); | |||
int res = ClientCloseAux(refnum, true); | |||
client->Close(); | |||
delete client; | |||
return res; | |||
@@ -668,13 +706,16 @@ int JackEngine::ClientExternalClose(int refnum) | |||
// Used for server internal clients or drivers when the RT thread is stopped | |||
int JackEngine::ClientInternalClose(int refnum, bool wait) | |||
{ | |||
JackClientInterface* client = fClientTable[refnum]; | |||
return ClientCloseAux(refnum, client, wait); | |||
jack_log("JackEngine::ClientInternalClose ref = %ld", refnum); | |||
return ClientCloseAux(refnum, wait); | |||
} | |||
int JackEngine::ClientCloseAux(int refnum, JackClientInterface* client, bool wait) | |||
int JackEngine::ClientCloseAux(int refnum, bool wait) | |||
{ | |||
jack_log("JackEngine::ClientCloseAux ref = %ld", refnum); | |||
JackClientInterface* client = fClientTable[refnum]; | |||
fEngineControl->fTransport.ResetTimebase(refnum); | |||
// Unregister all ports ==> notifications are sent | |||
jack_int_t ports[PORT_NUM_FOR_CLIENT]; | |||
@@ -717,8 +758,9 @@ int JackEngine::ClientActivate(int refnum, bool is_real_time) | |||
JackClientInterface* client = fClientTable[refnum]; | |||
jack_log("JackEngine::ClientActivate ref = %ld name = %s", refnum, client->GetClientControl()->fName); | |||
if (is_real_time) | |||
if (is_real_time) { | |||
fGraphManager->Activate(refnum); | |||
} | |||
// Wait for graph state change to be effective | |||
if (!fSignal.LockedTimedWait(fEngineControl->fTimeOutUsecs * 10)) { | |||
@@ -802,8 +844,9 @@ int JackEngine::PortRegister(int refnum, const char* name, const char *type, uns | |||
// buffer_size is actually ignored... | |||
*port_index = fGraphManager->AllocatePort(refnum, name, type, (JackPortFlags)flags, fEngineControl->fBufferSize); | |||
if (*port_index != NO_PORT) { | |||
if (client->GetClientControl()->fActive) | |||
if (client->GetClientControl()->fActive) { | |||
NotifyPortRegistation(*port_index, true); | |||
} | |||
return 0; | |||
} else { | |||
return -1; | |||
@@ -819,8 +862,9 @@ int JackEngine::PortUnRegister(int refnum, jack_port_id_t port_index) | |||
PortDisconnect(refnum, port_index, ALL_PORTS); | |||
if (fGraphManager->ReleasePort(refnum, port_index) == 0) { | |||
if (client->GetClientControl()->fActive) | |||
if (client->GetClientControl()->fActive) { | |||
NotifyPortRegistation(port_index, false); | |||
} | |||
return 0; | |||
} else { | |||
return -1; | |||
@@ -843,8 +887,9 @@ int JackEngine::PortConnect(int refnum, jack_port_id_t src, jack_port_id_t dst) | |||
JackClientInterface* client; | |||
int ref; | |||
if (fGraphManager->CheckPorts(src, dst) < 0) | |||
if (fGraphManager->CheckPorts(src, dst) < 0) { | |||
return -1; | |||
} | |||
ref = fGraphManager->GetOutputRefNum(src); | |||
assert(ref >= 0); | |||
@@ -867,8 +912,9 @@ 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; | |||
} | |||
@@ -932,7 +978,7 @@ int JackEngine::PortRename(int refnum, jack_port_id_t port, const char* name) | |||
// Session management | |||
//-------------------- | |||
void JackEngine::SessionNotify(int refnum, const char *target, jack_session_event_type_t type, const char *path, JackChannelTransaction *socket, JackSessionNotifyResult** result) | |||
void JackEngine::SessionNotify(int refnum, const char *target, jack_session_event_type_t type, const char *path, detail::JackChannelTransactionInterface *socket, JackSessionNotifyResult** result) | |||
{ | |||
if (fSessionPendingReplies != 0) { | |||
JackSessionNotifyResult res(-1); | |||
@@ -967,8 +1013,9 @@ void JackEngine::SessionNotify(int refnum, const char *target, jack_session_even | |||
snprintf(path_buf, sizeof(path_buf), "%s%s%c", path, client->GetClientControl()->fName, DIR_SEPARATOR); | |||
int res = JackTools::MkDir(path_buf); | |||
if (res) | |||
if (res) { | |||
jack_error("JackEngine::SessionNotify: can not create session directory '%s'", path_buf); | |||
} | |||
int result = client->ClientNotify(i, client->GetClientControl()->fName, kSessionCallback, true, path_buf, (int)type, 0); | |||
@@ -1000,7 +1047,7 @@ void JackEngine::SessionNotify(int refnum, const char *target, jack_session_even | |||
} | |||
} | |||
void JackEngine::SessionReply(int refnum) | |||
int JackEngine::SessionReply(int refnum) | |||
{ | |||
JackClientInterface* client = fClientTable[refnum]; | |||
char uuid_buf[JACK_UUID_SIZE]; | |||
@@ -1013,78 +1060,78 @@ void JackEngine::SessionReply(int refnum) | |||
if (fSessionPendingReplies == 0) { | |||
fSessionResult->Write(fSessionTransaction); | |||
if (fSessionTransaction != NULL) | |||
{ | |||
if (fSessionTransaction != NULL) { | |||
delete fSessionResult; | |||
} | |||
fSessionResult = NULL; | |||
} | |||
return 0; | |||
} | |||
void JackEngine::GetUUIDForClientName(const char *client_name, char *uuid_res, int *result) | |||
int JackEngine::GetUUIDForClientName(const char *client_name, char *uuid_res) | |||
{ | |||
for (int i = 0; i < CLIENT_NUM; i++) { | |||
JackClientInterface* client = fClientTable[i]; | |||
if (client && (strcmp(client_name, client->GetClientControl()->fName) == 0)) { | |||
snprintf(uuid_res, JACK_UUID_SIZE, "%d", client->GetClientControl()->fSessionID); | |||
*result = 0; | |||
return; | |||
return 0; | |||
} | |||
} | |||
// Did not find name. | |||
*result = -1; | |||
return -1; | |||
} | |||
void JackEngine::GetClientNameForUUID(const char *uuid, char *name_res, int *result) | |||
int JackEngine::GetClientNameForUUID(const char *uuid, char *name_res) | |||
{ | |||
for (int i = 0; i < CLIENT_NUM; i++) { | |||
JackClientInterface* client = fClientTable[i]; | |||
if (!client) | |||
if (!client) { | |||
continue; | |||
} | |||
char uuid_buf[JACK_UUID_SIZE]; | |||
snprintf(uuid_buf, JACK_UUID_SIZE, "%d", client->GetClientControl()->fSessionID); | |||
if (strcmp(uuid,uuid_buf) == 0) { | |||
strncpy(name_res, client->GetClientControl()->fName, JACK_CLIENT_NAME_SIZE); | |||
*result = 0; | |||
return; | |||
return 0; | |||
} | |||
} | |||
// Did not find uuid. | |||
*result = -1; | |||
return -1; | |||
} | |||
void JackEngine::ReserveClientName(const char *name, const char *uuid, int *result) | |||
int JackEngine::ReserveClientName(const char *name, const char *uuid) | |||
{ | |||
jack_log("JackEngine::ReserveClientName ( name = %s, uuid = %s )", name, uuid); | |||
if (ClientCheckName(name)) { | |||
*result = -1; | |||
jack_log("name already taken"); | |||
return; | |||
return -1; | |||
} | |||
EnsureUUID(atoi(uuid)); | |||
fReservationMap[atoi(uuid)] = name; | |||
*result = 0; | |||
return 0; | |||
} | |||
void JackEngine::ClientHasSessionCallback(const char *name, int *result) | |||
int JackEngine::ClientHasSessionCallback(const char *name) | |||
{ | |||
JackClientInterface* client = NULL; | |||
for (int i = 0; i < CLIENT_NUM; i++) { | |||
client = fClientTable[i]; | |||
if (client && (strcmp(client->GetClientControl()->fName, name) == 0)) | |||
if (client && (strcmp(client->GetClientControl()->fName, name) == 0)) { | |||
break; | |||
} | |||
} | |||
if (client) { | |||
*result = client->GetClientControl()->fCallback[kSessionCallback]; | |||
return client->GetClientControl()->fCallback[kSessionCallback]; | |||
} else { | |||
*result = -1; | |||
return -1; | |||
} | |||
} | |||
@@ -26,6 +26,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
#include "JackMutex.h" | |||
#include "JackTransportEngine.h" | |||
#include "JackPlatformPlug.h" | |||
#include "JackRequest.h" | |||
#include "JackChannel.h" | |||
#include <map> | |||
namespace Jack | |||
@@ -54,15 +56,15 @@ class SERVER_EXPORT JackEngine : public JackLockAble | |||
jack_time_t fLastSwitchUsecs; | |||
int fSessionPendingReplies; | |||
JackChannelTransaction* fSessionTransaction; | |||
detail::JackChannelTransactionInterface* fSessionTransaction; | |||
JackSessionNotifyResult* fSessionResult; | |||
std::map<int,std::string> fReservationMap; | |||
int fMaxUUID; | |||
int ClientCloseAux(int refnum, JackClientInterface* client, bool wait); | |||
int ClientCloseAux(int refnum, bool wait); | |||
void CheckXRun(jack_time_t callback_usecs); | |||
int NotifyAddClient(JackClientInterface* new_client, const char* name, int refnum); | |||
int NotifyAddClient(JackClientInterface* new_client, const char* new_name, int refnum); | |||
void NotifyRemoveClient(const char* name, int refnum); | |||
void ProcessNext(jack_time_t callback_usecs); | |||
@@ -74,6 +76,8 @@ class SERVER_EXPORT JackEngine : public JackLockAble | |||
int AllocateRefnum(); | |||
void ReleaseRefnum(int ref); | |||
int ClientNotify(JackClientInterface* client, int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2); | |||
void NotifyClient(int refnum, int event, int sync, const char* message, int value1, int value2); | |||
void NotifyClients(int event, int sync, const char* message, int value1, int value2); | |||
@@ -97,6 +101,8 @@ class SERVER_EXPORT JackEngine : public JackLockAble | |||
int Open(); | |||
int Close(); | |||
void ShutDown(); | |||
// Client management | |||
int ClientCheck(const char* name, int uuid, char* name_res, int protocol, int options, int* status); | |||
@@ -145,13 +151,13 @@ class SERVER_EXPORT JackEngine : public JackLockAble | |||
void NotifyQuit(); | |||
// Session management | |||
void SessionNotify(int refnum, const char *target, jack_session_event_type_t type, const char *path, JackChannelTransaction *socket, JackSessionNotifyResult** result); | |||
void SessionReply(int refnum); | |||
void SessionNotify(int refnum, const char *target, jack_session_event_type_t type, const char *path, detail::JackChannelTransactionInterface *socket, JackSessionNotifyResult** result); | |||
int SessionReply(int refnum); | |||
void GetUUIDForClientName(const char *client_name, char *uuid_res, int *result); | |||
void GetClientNameForUUID(const char *uuid, char *name_res, int *result); | |||
void ReserveClientName(const char *name, const char *uuid, int *result); | |||
void ClientHasSessionCallback(const char *name, int *result); | |||
int GetUUIDForClientName(const char *client_name, char *uuid_res); | |||
int GetClientNameForUUID(const char *uuid, char *name_res); | |||
int ReserveClientName(const char *name, const char *uuid); | |||
int ClientHasSessionCallback(const char *name); | |||
}; | |||
@@ -97,10 +97,11 @@ void JackEngineControl::ResetRollingUsecs() | |||
void JackEngineControl::NotifyXRun(jack_time_t callback_usecs, float delayed_usecs) | |||
{ | |||
ResetFrameTime(callback_usecs); | |||
ResetFrameTime(callback_usecs); | |||
fXrunDelayedUsecs = delayed_usecs; | |||
if (delayed_usecs > fMaxDelayedUsecs) | |||
if (delayed_usecs > fMaxDelayedUsecs) { | |||
fMaxDelayedUsecs = delayed_usecs; | |||
} | |||
} | |||
} // end of namespace |
@@ -124,6 +124,14 @@ struct SERVER_EXPORT JackEngineControl : public JackShmMem | |||
~JackEngineControl() | |||
{} | |||
void UpdateTimeOut() | |||
{ | |||
fPeriodUsecs = jack_time_t(1000000.f / fSampleRate * fBufferSize); // In microsec | |||
if (!(fTimeOut && fTimeOutUsecs > 2 * fPeriodUsecs)) { | |||
fTimeOutUsecs = 2 * fPeriodUsecs; | |||
} | |||
} | |||
// Cycle | |||
void CycleIncTime(jack_time_t callback_usecs) | |||
@@ -154,7 +162,7 @@ struct SERVER_EXPORT JackEngineControl : public JackShmMem | |||
void ResetFrameTime(jack_time_t callback_usecs) | |||
{ | |||
fFrameTimer.ResetFrameTime(fSampleRate, callback_usecs, fPeriodUsecs); | |||
fFrameTimer.ResetFrameTime(callback_usecs); | |||
} | |||
void ReadFrameTime(JackTimer* timer) | |||
@@ -2,21 +2,21 @@ | |||
Copyright (C) 2001 Paul Davis | |||
Copyright (C) 2004-2008 Grame | |||
Copyright (C) 2008 Nedko Arnaudov | |||
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. | |||
*/ | |||
#include <stdarg.h> | |||
@@ -29,7 +29,7 @@ using namespace Jack; | |||
static bool change_thread_log_function(jack_log_function_t log_function) | |||
{ | |||
return (jack_tls_get(JackGlobals::fKeyLogFunction) == NULL | |||
return (jack_tls_get(JackGlobals::fKeyLogFunction) == NULL | |||
&& jack_tls_set(JackGlobals::fKeyLogFunction, (void*)log_function)); | |||
} | |||
@@ -31,14 +31,8 @@ extern "C" | |||
{ | |||
#endif | |||
#define LOG_LEVEL_INFO 1 | |||
#define LOG_LEVEL_ERROR 2 | |||
SERVER_EXPORT void jack_error(const char *fmt, ...); | |||
SERVER_EXPORT void jack_info(const char *fmt, ...); | |||
// like jack_info() but only if verbose mode is enabled | |||
SERVER_EXPORT void jack_log(const char *fmt, ...); | |||
SERVER_EXPORT extern void (*jack_error_callback)(const char *desc); | |||
@@ -47,14 +41,16 @@ extern "C" | |||
SERVER_EXPORT extern void default_jack_error_callback(const char *desc); | |||
SERVER_EXPORT extern void default_jack_info_callback(const char *desc); | |||
SERVER_EXPORT extern void silent_jack_error_callback(const char *desc); | |||
SERVER_EXPORT extern void silent_jack_info_callback(const char *desc); | |||
SERVER_EXPORT void silent_jack_error_callback(const char *desc); | |||
SERVER_EXPORT void silent_jack_info_callback(const char *desc); | |||
typedef void (* jack_log_function_t)(int level, const char *message); | |||
SERVER_EXPORT int set_threaded_log_function(); | |||
void jack_log_function(int level, const char *message); | |||
#define LOG_LEVEL_INFO 1 | |||
#define LOG_LEVEL_ERROR 2 | |||
SERVER_EXPORT int set_threaded_log_function(); | |||
void jack_log_function(int level, const char *message); | |||
typedef void (* jack_log_function_t)(int level, const char *message); | |||
#ifdef __cplusplus | |||
} | |||
@@ -0,0 +1,34 @@ | |||
/* | |||
Copyright (C) 2008 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 "JackException.h" | |||
#include "JackError.h" | |||
namespace Jack | |||
{ | |||
void JackException::PrintMessage() | |||
{ | |||
std::string str = what(); | |||
if (str != "") { | |||
jack_info(str.c_str()); | |||
} | |||
} | |||
} |
@@ -20,10 +20,11 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
#ifndef __JackException__ | |||
#define __JackException__ | |||
#include "JackCompilerDeps.h" | |||
#include <stdexcept> | |||
#include <iostream> | |||
#include <string> | |||
#include "JackError.h" | |||
namespace Jack | |||
{ | |||
@@ -55,14 +56,9 @@ class SERVER_EXPORT JackException : public std::runtime_error { | |||
return what(); | |||
} | |||
void PrintMessage() | |||
{ | |||
std::string str = what(); | |||
if (str != "") { | |||
jack_info(str.c_str()); | |||
} | |||
} | |||
}; | |||
void PrintMessage(); | |||
}; | |||
/*! | |||
\brief Exception thrown by JackEngine in temporary mode. | |||
@@ -43,14 +43,26 @@ JackTimer::JackTimer() | |||
fCurrentWakeup = 0; | |||
fCurrentCallback = 0; | |||
fNextWakeUp = 0; | |||
fFilterCoefficient = 0.01f; | |||
fSecondOrderIntegrator = 0.0f; | |||
fPeriodUsecs = 0.0f; | |||
fFilterOmega = 0.0f; /* Initialised later */ | |||
} | |||
jack_nframes_t JackTimer::Time2Frames(jack_time_t time, jack_nframes_t buffer_size) | |||
jack_nframes_t JackTimer::Time2Frames(jack_time_t usecs, jack_nframes_t buffer_size) | |||
{ | |||
if (fInitialized) { | |||
return fFrames + (long)rint(((double) ((long long)(time - fCurrentWakeup)) / ((long long)(fNextWakeUp - fCurrentWakeup))) * buffer_size); | |||
/* | |||
Make sure we have signed differences. It would make a lot of sense | |||
to use the standard signed intNN_t types everywhere instead of e.g. | |||
jack_nframes_t and jack_time_t. This would at least ensure that the | |||
types used below are the correct ones. There is no way to get a type | |||
that would be 'a signed version of jack_time_t' for example - the | |||
types below are inherently fragile and there is no automatic way to | |||
check they are the correct ones. The only way is to check manually | |||
against jack/types.h. FA - 16/02/2012 | |||
*/ | |||
int64_t du = usecs - fCurrentWakeup; | |||
int64_t dp = fNextWakeUp - fCurrentWakeup; | |||
return fFrames + (int32_t)rint((double)du / (double)dp * buffer_size); | |||
} else { | |||
return 0; | |||
} | |||
@@ -59,12 +71,37 @@ jack_nframes_t JackTimer::Time2Frames(jack_time_t time, jack_nframes_t buffer_si | |||
jack_time_t JackTimer::Frames2Time(jack_nframes_t frames, jack_nframes_t buffer_size) | |||
{ | |||
if (fInitialized) { | |||
return fCurrentWakeup + (long)rint(((double) ((long long)(frames - fFrames)) * ((long long)(fNextWakeUp - fCurrentWakeup))) / buffer_size); | |||
/* | |||
Make sure we have signed differences. It would make a lot of sense | |||
to use the standard signed intNN_t types everywhere instead of e.g. | |||
jack_nframes_t and jack_time_t. This would at least ensure that the | |||
types used below are the correct ones. There is no way to get a type | |||
that would be 'a signed version of jack_time_t' for example - the | |||
types below are inherently fragile and there is no automatic way to | |||
check they are the correct ones. The only way is to check manually | |||
against jack/types.h. FA - 16/02/2012 | |||
*/ | |||
int32_t df = frames - fFrames; | |||
int64_t dp = fNextWakeUp - fCurrentWakeup; | |||
return fCurrentWakeup + (int64_t)rint((double) df * (double) dp / buffer_size); | |||
} else { | |||
return 0; | |||
} | |||
} | |||
int JackTimer::GetCycleTimes(jack_nframes_t* current_frames, jack_time_t* current_usecs, jack_time_t* next_usecs, float* period_usecs) | |||
{ | |||
if (fInitialized) { | |||
*current_frames = fFrames; | |||
*current_usecs = fCurrentWakeup; | |||
*next_usecs = fNextWakeUp; | |||
*period_usecs = fPeriodUsecs; | |||
return 0; | |||
} else { | |||
return -1; | |||
} | |||
} | |||
jack_nframes_t JackTimer::FramesSinceCycleStart(jack_time_t cur_time, jack_nframes_t frames_rate) | |||
{ | |||
return (jack_nframes_t) floor((((float)frames_rate) / 1000000.0f) * (cur_time - fCurrentCallback)); | |||
@@ -80,20 +117,17 @@ void JackFrameTimer::IncFrameTime(jack_nframes_t buffer_size, jack_time_t callba | |||
if (fFirstWakeUp) { | |||
InitFrameTimeAux(callback_usecs, period_usecs); | |||
fFirstWakeUp = false; | |||
} else { | |||
IncFrameTimeAux(buffer_size, callback_usecs, period_usecs); | |||
} | |||
IncFrameTimeAux(buffer_size, callback_usecs, period_usecs); | |||
} | |||
void JackFrameTimer::ResetFrameTime(jack_nframes_t frames_rate, jack_time_t callback_usecs, jack_time_t period_usecs) | |||
void JackFrameTimer::ResetFrameTime(jack_time_t callback_usecs) | |||
{ | |||
if (!fFirstWakeUp) { // ResetFrameTime may be called by a xrun/delayed wakeup on the first cycle | |||
JackTimer* timer = WriteNextStateStart(); | |||
jack_nframes_t period_size_guess = (jack_nframes_t)(frames_rate * ((timer->fNextWakeUp - timer->fCurrentWakeup) / 1000000.0)); | |||
timer->fFrames += ((callback_usecs - timer->fNextWakeUp) / period_size_guess) * period_size_guess; | |||
timer->fCurrentWakeup = callback_usecs; | |||
timer->fCurrentCallback = callback_usecs; | |||
timer->fNextWakeUp = callback_usecs + period_usecs; | |||
WriteNextStateStop(); | |||
TrySwitchState(); // always succeed since there is only one writer | |||
} | |||
@@ -119,10 +153,44 @@ void JackFrameTimer::ReadFrameTime(JackTimer* timer) | |||
void JackFrameTimer::InitFrameTimeAux(jack_time_t callback_usecs, jack_time_t period_usecs) | |||
{ | |||
/* the first wakeup or post-freewheeling or post-xrun */ | |||
/* There seems to be no significant difference between | |||
the two conditions OR-ed above. Incrementing the | |||
frame_time after an xrun shouldn't harm, as there | |||
will be a discontinuity anyway. So the two are | |||
combined in this version. | |||
FA 16/03/2012 | |||
*/ | |||
/* Since the DLL *will* be run, next_wakeup should be the | |||
current wakeup time *without* adding the period time, as | |||
if it were computed in the previous period. | |||
FA 16/03/2012 | |||
*/ | |||
/* Added initialisation of timer->period_usecs, required | |||
due to the modified implementation of the DLL itself. | |||
OTOH, this should maybe not be repeated after e.g. | |||
freewheeling or an xrun, as the current value would be | |||
more accurate than the nominal one. But it doesn't really | |||
harm either. Implementing this would require a new flag | |||
in the engine structure, to be used after freewheeling | |||
or an xrun instead of first_wakeup. I don't know if this | |||
can be done without breaking compatibility, so I did not | |||
add this | |||
FA 13/02/2012 | |||
*/ | |||
/* Added initialisation of timer->filter_omega. This makes | |||
the DLL bandwidth independent of the actual period time. | |||
The bandwidth is now 1/8 Hz in all cases. The value of | |||
timer->filter_omega is 2 * pi * BW * Tperiod. | |||
FA 13/02/2012 | |||
*/ | |||
JackTimer* timer = WriteNextStateStart(); | |||
timer->fSecondOrderIntegrator = 0.0f; | |||
timer->fPeriodUsecs = (float)period_usecs; | |||
timer->fCurrentCallback = callback_usecs; | |||
timer->fNextWakeUp = callback_usecs + period_usecs; | |||
timer->fNextWakeUp = callback_usecs; | |||
timer->fFilterOmega = period_usecs * 7.854e-7f; | |||
WriteNextStateStop(); | |||
TrySwitchState(); // always succeed since there is only one writer | |||
} | |||
@@ -130,13 +198,38 @@ void JackFrameTimer::InitFrameTimeAux(jack_time_t callback_usecs, jack_time_t pe | |||
void JackFrameTimer::IncFrameTimeAux(jack_nframes_t buffer_size, jack_time_t callback_usecs, jack_time_t period_usecs) | |||
{ | |||
JackTimer* timer = WriteNextStateStart(); | |||
float delta = (int64_t)callback_usecs - (int64_t)timer->fNextWakeUp; | |||
/* Modified implementation (the actual result is the same). | |||
'fSecondOrderIntegrator' is renamed to 'fPeriodUsecs' | |||
and now represents the DLL's best estimate of the | |||
period time in microseconds (before it was a scaled | |||
version of the difference w.r.t. the nominal value). | |||
This allows this value to be made available to clients | |||
that are interested in it (see jack_get_cycle_times). | |||
This change also means that 'fPeriodUsecs' must be | |||
initialised to the nominal period time instead of zero. | |||
This is done in the first cycle in jack_run_cycle(). | |||
'fFilterCoefficient' is renamed to 'fFilterOmega'. It | |||
is now equal to the 'omega' value as defined in the | |||
'Using a DLL to filter time' paper (before it was a | |||
scaled version of this value). It is computed once in | |||
jack_run_cycle() rather than set to a fixed value. This | |||
makes the DLL bandwidth independent of the period time. | |||
FA 13/02/2012 | |||
*/ | |||
float delta = (float)((int64_t)callback_usecs - (int64_t)timer->fNextWakeUp); | |||
delta *= timer->fFilterOmega; | |||
timer->fCurrentWakeup = timer->fNextWakeUp; | |||
timer->fCurrentCallback = callback_usecs; | |||
timer->fFrames += buffer_size; | |||
timer->fSecondOrderIntegrator += 0.5f * timer->fFilterCoefficient * delta; | |||
timer->fNextWakeUp = timer->fCurrentWakeup + period_usecs + (int64_t) floorf((timer->fFilterCoefficient * (delta + timer->fSecondOrderIntegrator))); | |||
timer->fPeriodUsecs += timer->fFilterOmega * delta; | |||
timer->fNextWakeUp += (int64_t)floorf(timer->fPeriodUsecs + 1.41f * delta + 0.5f); | |||
timer->fInitialized = true; | |||
WriteNextStateStop(); | |||
TrySwitchState(); // always succeed since there is only one writer | |||
} | |||
@@ -44,8 +44,8 @@ class SERVER_EXPORT JackTimer | |||
jack_time_t fCurrentWakeup; | |||
jack_time_t fCurrentCallback; | |||
jack_time_t fNextWakeUp; | |||
float fSecondOrderIntegrator; | |||
float fFilterCoefficient; /* set once, never altered */ | |||
float fPeriodUsecs; | |||
float fFilterOmega; /* set once, never altered */ | |||
bool fInitialized; | |||
public: | |||
@@ -57,6 +57,7 @@ class SERVER_EXPORT JackTimer | |||
jack_nframes_t Time2Frames(jack_time_t time, jack_nframes_t buffer_size); | |||
jack_time_t Frames2Time(jack_nframes_t frames, jack_nframes_t buffer_size); | |||
jack_nframes_t FramesSinceCycleStart(jack_time_t cur_time, jack_nframes_t frames_rate); | |||
int GetCycleTimes(jack_nframes_t* current_frames, jack_time_t* current_usecs, jack_time_t* next_usecs, float* period_usecs); | |||
jack_nframes_t CurFrame() | |||
{ | |||
@@ -92,7 +93,7 @@ class SERVER_EXPORT JackFrameTimer : public JackAtomicState<JackTimer> | |||
{} | |||
void InitFrameTime(); | |||
void ResetFrameTime(jack_nframes_t frames_rate, jack_time_t callback_usecs, jack_time_t period_usecs); | |||
void ResetFrameTime(jack_time_t callback_usecs); | |||
void IncFrameTime(jack_nframes_t buffer_size, jack_time_t callback_usecs, jack_time_t period_usecs); | |||
void ReadFrameTime(JackTimer* timer); | |||
@@ -37,7 +37,8 @@ int JackFreewheelDriver::Process() | |||
if (fEngine->Process(fBeginDateUst, fEndDateUst)) { | |||
if (ResumeRefNum()) { // Signal all clients | |||
// Resume connected clients in the graph | |||
if (ResumeRefNum()) { | |||
jack_error("JackFreewheelDriver::Process: ResumeRefNum error"); | |||
res = -1; | |||
} | |||
@@ -61,6 +62,7 @@ int JackFreewheelDriver::Process() | |||
int JackFreewheelDriver::ProcessReadSync() | |||
{ | |||
// Resume connected clients in the graph | |||
if (ResumeRefNum() < 0) { // Signal all clients | |||
jack_error("JackFreewheelDriver::ProcessReadSync: ResumeRefNum error"); | |||
return -1; | |||
@@ -80,6 +82,7 @@ int JackFreewheelDriver::ProcessWriteSync() | |||
int JackFreewheelDriver::ProcessReadAsync() | |||
{ | |||
// Resume connected clients in the graph | |||
if (ResumeRefNum() < 0) { // Signal all clients | |||
jack_error("JackFreewheelDriver::ProcessReadAsync: ResumeRefNum error"); | |||
return -1; | |||
@@ -0,0 +1,298 @@ | |||
/* | |||
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. | |||
*/ | |||
#include "JackGenericClientChannel.h" | |||
#include "JackClient.h" | |||
#include "JackGlobals.h" | |||
#include "JackError.h" | |||
namespace Jack | |||
{ | |||
JackGenericClientChannel::JackGenericClientChannel() | |||
{} | |||
JackGenericClientChannel::~JackGenericClientChannel() | |||
{} | |||
int JackGenericClientChannel::ServerCheck(const char* server_name) | |||
{ | |||
jack_log("JackGenericClientChannel::ServerCheck = %s", server_name); | |||
// Connect to server | |||
if (fRequest->Connect(jack_server_dir, server_name, 0) < 0) { | |||
jack_error("Cannot connect to server request channel"); | |||
return -1; | |||
} else { | |||
return 0; | |||
} | |||
} | |||
void JackGenericClientChannel::ServerSyncCall(JackRequest* req, JackResult* res, int* result) | |||
{ | |||
// Check call context | |||
if (jack_tls_get(JackGlobals::fNotificationThread)) { | |||
jack_error("Cannot callback the server in notification thread!"); | |||
*result = -1; | |||
return; | |||
} | |||
if (req->Write(fRequest) < 0) { | |||
jack_error("Could not write request type = %ld", req->fType); | |||
*result = -1; | |||
return; | |||
} | |||
if (res->Read(fRequest) < 0) { | |||
jack_error("Could not read result type = %ld", req->fType); | |||
*result = -1; | |||
return; | |||
} | |||
*result = res->fResult; | |||
} | |||
void JackGenericClientChannel::ServerAsyncCall(JackRequest* req, JackResult* res, int* result) | |||
{ | |||
// Check call context | |||
if (jack_tls_get(JackGlobals::fNotificationThread)) { | |||
jack_error("Cannot callback the server in notification thread!"); | |||
*result = -1; | |||
return; | |||
} | |||
if (req->Write(fRequest) < 0) { | |||
jack_error("Could not write request type = %ld", req->fType); | |||
*result = -1; | |||
} else { | |||
*result = 0; | |||
} | |||
} | |||
void JackGenericClientChannel::ClientCheck(const char* name, int uuid, char* name_res, int protocol, int options, int* status, int* result, int open) | |||
{ | |||
JackClientCheckRequest req(name, protocol, options, uuid, open); | |||
JackClientCheckResult res; | |||
ServerSyncCall(&req, &res, result); | |||
*status = res.fStatus; | |||
strcpy(name_res, res.fName); | |||
} | |||
void JackGenericClientChannel::ClientOpen(const char* name, int pid, int uuid, int* shared_engine, int* shared_client, int* shared_graph, int* result) | |||
{ | |||
JackClientOpenRequest req(name, pid, uuid); | |||
JackClientOpenResult res; | |||
ServerSyncCall(&req, &res, result); | |||
*shared_engine = res.fSharedEngine; | |||
*shared_client = res.fSharedClient; | |||
*shared_graph = res.fSharedGraph; | |||
} | |||
void JackGenericClientChannel::ClientClose(int refnum, int* result) | |||
{ | |||
JackClientCloseRequest req(refnum); | |||
JackResult res; | |||
ServerSyncCall(&req, &res, result); | |||
} | |||
void JackGenericClientChannel::ClientActivate(int refnum, int is_real_time, int* result) | |||
{ | |||
JackActivateRequest req(refnum, is_real_time); | |||
JackResult res; | |||
ServerSyncCall(&req, &res, result); | |||
} | |||
void JackGenericClientChannel::ClientDeactivate(int refnum, int* result) | |||
{ | |||
JackDeactivateRequest req(refnum); | |||
JackResult res; | |||
ServerSyncCall(&req, &res, result); | |||
} | |||
void JackGenericClientChannel::PortRegister(int refnum, const char* name, const char* type, unsigned int flags, unsigned int buffer_size, jack_port_id_t* port_index, int* result) | |||
{ | |||
JackPortRegisterRequest req(refnum, name, type, flags, buffer_size); | |||
JackPortRegisterResult res; | |||
ServerSyncCall(&req, &res, result); | |||
*port_index = res.fPortIndex; | |||
} | |||
void JackGenericClientChannel::PortUnRegister(int refnum, jack_port_id_t port_index, int* result) | |||
{ | |||
JackPortUnRegisterRequest req(refnum, port_index); | |||
JackResult res; | |||
ServerSyncCall(&req, &res, result); | |||
} | |||
void JackGenericClientChannel::PortConnect(int refnum, const char* src, const char* dst, int* result) | |||
{ | |||
JackPortConnectNameRequest req(refnum, src, dst); | |||
JackResult res; | |||
ServerSyncCall(&req, &res, result); | |||
} | |||
void JackGenericClientChannel::PortDisconnect(int refnum, const char* src, const char* dst, int* result) | |||
{ | |||
JackPortDisconnectNameRequest req(refnum, src, dst); | |||
JackResult res; | |||
ServerSyncCall(&req, &res, result); | |||
} | |||
void JackGenericClientChannel::PortConnect(int refnum, jack_port_id_t src, jack_port_id_t dst, int* result) | |||
{ | |||
JackPortConnectRequest req(refnum, src, dst); | |||
JackResult res; | |||
ServerSyncCall(&req, &res, result); | |||
} | |||
void JackGenericClientChannel::PortDisconnect(int refnum, jack_port_id_t src, jack_port_id_t dst, int* result) | |||
{ | |||
JackPortDisconnectRequest req(refnum, src, dst); | |||
JackResult res; | |||
ServerSyncCall(&req, &res, result); | |||
} | |||
void JackGenericClientChannel::PortRename(int refnum, jack_port_id_t port, const char* name, int* result) | |||
{ | |||
JackPortRenameRequest req(refnum, port, name); | |||
JackResult res; | |||
ServerSyncCall(&req, &res, result); | |||
} | |||
void JackGenericClientChannel::SetBufferSize(jack_nframes_t buffer_size, int* result) | |||
{ | |||
JackSetBufferSizeRequest req(buffer_size); | |||
JackResult res; | |||
ServerSyncCall(&req, &res, result); | |||
} | |||
void JackGenericClientChannel::SetFreewheel(int onoff, int* result) | |||
{ | |||
JackSetFreeWheelRequest req(onoff); | |||
JackResult res; | |||
ServerSyncCall(&req, &res, result); | |||
} | |||
void JackGenericClientChannel::ComputeTotalLatencies(int* result) | |||
{ | |||
JackComputeTotalLatenciesRequest req; | |||
JackResult res; | |||
ServerSyncCall(&req, &res, result); | |||
} | |||
void JackGenericClientChannel::SessionNotify(int refnum, const char* target, jack_session_event_type_t type, const char* path, jack_session_command_t** result) | |||
{ | |||
JackSessionNotifyRequest req(refnum, path, type, target); | |||
JackSessionNotifyResult res; | |||
int intresult; | |||
ServerSyncCall(&req, &res, &intresult); | |||
*result = res.GetCommands(); | |||
} | |||
void JackGenericClientChannel::SessionReply(int refnum, int* result) | |||
{ | |||
JackSessionReplyRequest req(refnum); | |||
JackResult res; | |||
ServerSyncCall(&req, &res, result); | |||
} | |||
void JackGenericClientChannel::GetUUIDForClientName(int refnum, const char* client_name, char* uuid_res, int* result) | |||
{ | |||
JackGetUUIDRequest req(client_name); | |||
JackUUIDResult res; | |||
ServerSyncCall(&req, &res, result); | |||
strncpy(uuid_res, res.fUUID, JACK_UUID_SIZE); | |||
} | |||
void JackGenericClientChannel::GetClientNameForUUID(int refnum, const char* uuid, char* name_res, int* result) | |||
{ | |||
JackGetClientNameRequest req(uuid); | |||
JackClientNameResult res; | |||
ServerSyncCall(&req, &res, result); | |||
strncpy(name_res, res.fName, JACK_CLIENT_NAME_SIZE); | |||
} | |||
void JackGenericClientChannel::ClientHasSessionCallback(const char* client_name, int* result) | |||
{ | |||
JackClientHasSessionCallbackRequest req(client_name); | |||
JackResult res; | |||
ServerSyncCall(&req, &res, result); | |||
} | |||
void JackGenericClientChannel::ReserveClientName(int refnum, const char* client_name, const char* uuid, int* result) | |||
{ | |||
JackReserveNameRequest req(refnum, client_name, uuid); | |||
JackResult res; | |||
ServerSyncCall(&req, &res, result); | |||
} | |||
void JackGenericClientChannel::ReleaseTimebase(int refnum, int* result) | |||
{ | |||
JackReleaseTimebaseRequest req(refnum); | |||
JackResult res; | |||
ServerSyncCall(&req, &res, result); | |||
} | |||
void JackGenericClientChannel::SetTimebaseCallback(int refnum, int conditional, int* result) | |||
{ | |||
JackSetTimebaseCallbackRequest req(refnum, conditional); | |||
JackResult res; | |||
ServerSyncCall(&req, &res, result); | |||
} | |||
void JackGenericClientChannel::GetInternalClientName(int refnum, int int_ref, char* name_res, int* result) | |||
{ | |||
JackGetInternalClientNameRequest req(refnum, int_ref); | |||
JackGetInternalClientNameResult res; | |||
ServerSyncCall(&req, &res, result); | |||
strcpy(name_res, res.fName); | |||
} | |||
void JackGenericClientChannel::InternalClientHandle(int refnum, const char* client_name, int* status, int* int_ref, int* result) | |||
{ | |||
JackInternalClientHandleRequest req(refnum, client_name); | |||
JackInternalClientHandleResult res; | |||
ServerSyncCall(&req, &res, result); | |||
*int_ref = res.fIntRefNum; | |||
*status = res.fStatus; | |||
} | |||
void JackGenericClientChannel::InternalClientLoad(int refnum, const char* client_name, const char* so_name, const char* objet_data, int options, int* status, int* int_ref, int uuid, int* result) | |||
{ | |||
JackInternalClientLoadRequest req(refnum, client_name, so_name, objet_data, options, uuid); | |||
JackInternalClientLoadResult res; | |||
ServerSyncCall(&req, &res, result); | |||
*int_ref = res.fIntRefNum; | |||
*status = res.fStatus; | |||
} | |||
void JackGenericClientChannel::InternalClientUnload(int refnum, int int_ref, int* status, int* result) | |||
{ | |||
JackInternalClientUnloadRequest req(refnum, int_ref); | |||
JackInternalClientUnloadResult res; | |||
ServerSyncCall(&req, &res, result); | |||
*status = res.fStatus; | |||
} | |||
} // end of namespace | |||
@@ -0,0 +1,103 @@ | |||
/* | |||
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 __JackGenericClientChannel__ | |||
#define __JackGenericClientChannel__ | |||
#include "JackChannel.h" | |||
namespace Jack | |||
{ | |||
struct JackRequest; | |||
struct JackResult; | |||
/*! | |||
\brief Generic JackClientChannel class. | |||
*/ | |||
class JackGenericClientChannel : public detail::JackClientChannelInterface | |||
{ | |||
protected: | |||
detail::JackClientRequestInterface* fRequest; | |||
void ServerSyncCall(JackRequest* req, JackResult* res, int* result); | |||
void ServerAsyncCall(JackRequest* req, JackResult* res, int* result); | |||
public: | |||
JackGenericClientChannel(); | |||
virtual ~JackGenericClientChannel(); | |||
virtual int Open(const char* server_name, const char* name, int uuid, char* name_res, JackClient* obj, jack_options_t options, jack_status_t* status) { return -1; } | |||
virtual void Close() {} | |||
virtual int Start() { return -1; } | |||
virtual void Stop() {} | |||
int ServerCheck(const char* server_name); | |||
void ClientCheck(const char* name, int uuid, char* name_res, int protocol, int options, int* status, int* result, int open); | |||
void ClientOpen(const char* name, int pid, int uuid, int* shared_engine, int* shared_client, int* shared_graph, int* result); | |||
void ClientOpen(const char* name, int* ref, int uuid, JackEngineControl** shared_engine, JackGraphManager** shared_manager, JackClientInterface* client, int* result) | |||
{} | |||
void ClientClose(int refnum, int* result); | |||
void ClientActivate(int refnum, int is_real_time, int* result); | |||
void ClientDeactivate(int refnum, int* result); | |||
void PortRegister(int refnum, const char* name, const char* type, unsigned int flags, unsigned int buffer_size, jack_port_id_t* port_index, int* result); | |||
void PortUnRegister(int refnum, jack_port_id_t port_index, int* result); | |||
void PortConnect(int refnum, const char* src, const char* dst, int* result); | |||
void PortDisconnect(int refnum, const char* src, const char* dst, int* result); | |||
void PortConnect(int refnum, jack_port_id_t src, jack_port_id_t dst, int* result); | |||
void PortDisconnect(int refnum, jack_port_id_t src, jack_port_id_t dst, int* result); | |||
void PortRename(int refnum, jack_port_id_t port, const char* name, int* result); | |||
void SetBufferSize(jack_nframes_t buffer_size, int* result); | |||
void SetFreewheel(int onoff, int* result); | |||
void ComputeTotalLatencies(int* result); | |||
void ReleaseTimebase(int refnum, int* result); | |||
void SetTimebaseCallback(int refnum, int conditional, int* result); | |||
void GetInternalClientName(int refnum, int int_ref, char* name_res, int* result); | |||
void InternalClientHandle(int refnum, const char* client_name, int* status, int* int_ref, int* result); | |||
void InternalClientLoad(int refnum, const char* client_name, const char* so_name, const char* objet_data, int options, int* status, int* int_ref, int uuid, int* result); | |||
void InternalClientUnload(int refnum, int int_ref, int* status, int* result); | |||
// Session API | |||
void SessionNotify(int refnum, const char* target, jack_session_event_type_t type, const char* path, jack_session_command_t** result); | |||
void SessionReply(int refnum, int* result); | |||
void GetUUIDForClientName(int refnum, const char* client_name, char* uuid_res, int* result); | |||
void GetClientNameForUUID(int refnum, const char* uuid, char* name_res, int* result); | |||
void ReserveClientName(int refnum, const char* client_name, const char *uuid, int* result); | |||
void ClientHasSessionCallback(const char* client_name, int* result); | |||
}; | |||
} // end of namespace | |||
#endif | |||
@@ -24,8 +24,11 @@ namespace Jack | |||
bool JackGlobals::fVerbose = 0; | |||
jack_tls_key JackGlobals::fRealTime; | |||
static bool gKeyRealtimeInitialized = jack_tls_allocate_key(&JackGlobals::fRealTime); | |||
jack_tls_key JackGlobals::fRealTimeThread; | |||
static bool gKeyRealtimeThreadInitialized = jack_tls_allocate_key(&JackGlobals::fRealTimeThread); | |||
jack_tls_key JackGlobals::fNotificationThread; | |||
static bool gKeyNotificationThreadInitialized = jack_tls_allocate_key(&JackGlobals::fNotificationThread); | |||
jack_tls_key JackGlobals::fKeyLogFunction; | |||
static bool fKeyLogFunctionInitialized = jack_tls_allocate_key(&JackGlobals::fKeyLogFunction); | |||
@@ -39,6 +42,7 @@ jack_thread_creator_t JackGlobals::fJackThreadCreator = pthread_create; | |||
#endif | |||
#ifdef __CLIENTDEBUG__ | |||
std::ofstream* JackGlobals::fStream = NULL; | |||
void JackGlobals::CheckContext(const char* name) | |||
@@ -59,6 +63,12 @@ void JackGlobals::CheckContext(const char* name) | |||
} | |||
(*fStream) << "JACK API call : " << name << ", calling thread : " << pthread_self() << std::endl; | |||
} | |||
#else | |||
void JackGlobals::CheckContext(const char* name) | |||
{} | |||
#endif | |||
} // end of namespace |
@@ -37,7 +37,8 @@ namespace Jack | |||
// Globals used for client management on server or library side. | |||
struct JackGlobals { | |||
static jack_tls_key fRealTime; | |||
static jack_tls_key fRealTimeThread; | |||
static jack_tls_key fNotificationThread; | |||
static jack_tls_key fKeyLogFunction; | |||
static JackMutex* fOpenMutex; | |||
static volatile bool fServerRunning; | |||
@@ -49,8 +50,8 @@ struct JackGlobals { | |||
#ifdef __CLIENTDEBUG__ | |||
static std::ofstream* fStream; | |||
static void CheckContext(const char* name); | |||
#endif | |||
static void CheckContext(const char* name); | |||
}; | |||
// Each "side" server and client will implement this to get the shared graph manager, engine control and inter-process synchro table. | |||
@@ -344,7 +344,7 @@ void JackGraphManager::RecalculateLatency(jack_port_id_t port_index, jack_latenc | |||
next_index = GetCurrentIndex(); | |||
} while (cur_index != next_index); // Until a coherent state has been read | |||
jack_log("JackGraphManager::RecalculateLatency port_index = %ld", port_index); | |||
//jack_log("JackGraphManager::RecalculateLatency port_index = %ld", port_index); | |||
} | |||
// Server | |||
@@ -27,7 +27,10 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
#include "JackServer.h" | |||
#include "JackEngineControl.h" | |||
#include "JackClientControl.h" | |||
#include "JackInternalClientChannel.h" | |||
#include "JackGenericClientChannel.h" | |||
#include "JackTools.h" | |||
#include <assert.h> | |||
@@ -98,11 +101,16 @@ int JackInternalClient::Open(const char* server_name, const char* name, int uuid | |||
return 0; | |||
error: | |||
fChannel->Stop(); | |||
fChannel->Close(); | |||
return -1; | |||
} | |||
void JackInternalClient::ShutDown() | |||
{ | |||
jack_log("JackInternalClient::ShutDown"); | |||
JackClient::ShutDown(); | |||
} | |||
JackGraphManager* JackInternalClient::GetGraphManager() const | |||
{ | |||
assert(fGraphManager); | |||
@@ -193,10 +201,12 @@ JackLoadableInternalClient2::JackLoadableInternalClient2(JackServer* server, Jac | |||
JackLoadableInternalClient::~JackLoadableInternalClient() | |||
{ | |||
if (fFinish != NULL) | |||
if (fFinish != NULL) { | |||
fFinish(fProcessArg); | |||
if (fHandle != NULL) | |||
} | |||
if (fHandle != NULL) { | |||
UnloadJackModule(fHandle); | |||
} | |||
} | |||
int JackLoadableInternalClient1::Open(const char* server_name, const char* name, int uuid, jack_options_t options, jack_status_t* status) | |||
@@ -47,6 +47,7 @@ class JackInternalClient : public JackClient | |||
virtual ~JackInternalClient(); | |||
int Open(const char* server_name, const char* name, int uuid, jack_options_t options, jack_status_t* status); | |||
void ShutDown(); | |||
JackGraphManager* GetGraphManager() const; | |||
JackEngineControl* GetEngineControl() const; | |||
@@ -63,7 +64,6 @@ class JackInternalClient : public JackClient | |||
typedef int (*InitializeCallback)(jack_client_t*, const char*); | |||
typedef int (*InternalInitializeCallback)(jack_client_t*, const JSList* params); | |||
typedef void (*FinishCallback)(void *); | |||
typedef jack_driver_desc_t * (*JackDriverDescFunction) (); | |||
class JackLoadableInternalClient : public JackInternalClient | |||
{ | |||
@@ -92,7 +92,7 @@ class JackLoadableInternalClient1 : public JackLoadableInternalClient | |||
InitializeCallback fInitialize; | |||
char fObjectData[JACK_LOAD_INIT_LIMIT]; | |||
public: | |||
JackLoadableInternalClient1(JackServer* server, JackSynchro* table, const char* object_data); | |||
@@ -111,7 +111,7 @@ class JackLoadableInternalClient2 : public JackLoadableInternalClient | |||
InternalInitializeCallback fInitialize; | |||
const JSList* fParameters; | |||
public: | |||
JackLoadableInternalClient2(JackServer* server, JackSynchro* table, const JSList* parameters); | |||
@@ -44,12 +44,6 @@ class JackInternalClientChannel : public detail::JackClientChannelInterface | |||
virtual ~JackInternalClientChannel() | |||
{} | |||
// Open the Server/Client connection | |||
virtual int Open(const char* name, char* name_res, JackClient* obj, jack_options_t options, jack_status_t* status) | |||
{ | |||
return 0; | |||
} | |||
void ClientCheck(const char* name, int uuid, char* name_res, int protocol, int options, int* status, int* result, int open) | |||
{ | |||
*result = fEngine->ClientCheck(name, uuid, name_res, protocol, options, status); | |||
@@ -148,8 +142,7 @@ class JackInternalClientChannel : public detail::JackClientChannelInterface | |||
{ | |||
JackSessionNotifyResult* res; | |||
fEngine->SessionNotify(refnum, target, type, path, NULL, &res); | |||
if (res == NULL) | |||
{ | |||
if (res == NULL) { | |||
*result = NULL; | |||
return; | |||
} | |||
@@ -160,28 +153,27 @@ class JackInternalClientChannel : public detail::JackClientChannelInterface | |||
void SessionReply(int refnum, int* result) | |||
{ | |||
fEngine->SessionReply(refnum); | |||
*result = 0; | |||
*result = fEngine->SessionReply(refnum); | |||
} | |||
void GetUUIDForClientName(int refnum, const char* client_name, char* uuid_res, int* result) | |||
{ | |||
fEngine->GetUUIDForClientName(client_name, uuid_res, result); | |||
*result = fEngine->GetUUIDForClientName(client_name, uuid_res); | |||
} | |||
void GetClientNameForUUID(int refnum, const char* uuid, char* name_res, int* result) | |||
{ | |||
fEngine->GetClientNameForUUID(uuid, name_res, result); | |||
*result = fEngine->GetClientNameForUUID(uuid, name_res); | |||
} | |||
void ReserveClientName(int refnum, const char* client_name, const char *uuid, int* result) | |||
{ | |||
fEngine->ReserveClientName(client_name, uuid, result); | |||
*result = fEngine->ReserveClientName(client_name, uuid); | |||
} | |||
void ClientHasSessionCallback(const char* client_name, int* result) | |||
{ | |||
fEngine->ClientHasSessionCallback(client_name, result); | |||
*result = fEngine->ClientHasSessionCallback(client_name); | |||
} | |||
@@ -166,9 +166,8 @@ static jack_client_t* jack_client_open_aux(const char* client_name, jack_options | |||
LIB_EXPORT jack_client_t* jack_client_open(const char* ext_client_name, jack_options_t options, jack_status_t* status, ...) | |||
{ | |||
#ifdef __CLIENTDEBUG__ | |||
JackGlobals::CheckContext("jack_client_open"); | |||
#endif | |||
try { | |||
assert(JackGlobals::fOpenMutex); | |||
JackGlobals::fOpenMutex->Lock(); | |||
@@ -189,9 +188,8 @@ LIB_EXPORT jack_client_t* jack_client_open(const char* ext_client_name, jack_opt | |||
LIB_EXPORT int jack_client_close(jack_client_t* ext_client) | |||
{ | |||
#ifdef __CLIENTDEBUG__ | |||
JackGlobals::CheckContext("jack_client_close"); | |||
#endif | |||
assert(JackGlobals::fOpenMutex); | |||
JackGlobals::fOpenMutex->Lock(); | |||
int res = -1; | |||
@@ -55,6 +55,20 @@ JackSynchro* GetSynchroTable() | |||
// Client management | |||
//------------------- | |||
/* | |||
ShutDown is called: | |||
- from the RT thread when Execute method fails | |||
- possibly from a "closed" notification channel | |||
(Not needed since the synch object used (Sema of Fifo will fails when server quits... see ShutDown)) | |||
*/ | |||
void JackLibClient::ShutDown() | |||
{ | |||
jack_log("JackLibClient::ShutDown"); | |||
JackGlobals::fServerRunning = false; | |||
JackClient::ShutDown(); | |||
} | |||
JackLibClient::JackLibClient(JackSynchro* table): JackClient(table) | |||
{ | |||
jack_log("JackLibClient::JackLibClient table = %x", table); | |||
@@ -32,7 +32,7 @@ namespace Jack | |||
\brief Client on the library side. | |||
*/ | |||
class LIB_EXPORT JackLibClient : public JackClient | |||
class JackLibClient : public JackClient | |||
{ | |||
private: | |||
@@ -45,6 +45,7 @@ class LIB_EXPORT JackLibClient : public JackClient | |||
virtual ~JackLibClient(); | |||
int Open(const char* server_name, const char* name, int uuid, jack_options_t options, jack_status_t* status); | |||
void ShutDown(); | |||
int ClientNotifyImp(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2); | |||
@@ -50,7 +50,7 @@ class JackClient; | |||
\brief Global library static structure: singleton kind of pattern. | |||
*/ | |||
struct LIB_EXPORT JackLibGlobals | |||
struct JackLibGlobals | |||
{ | |||
JackShmReadWritePtr<JackGraphManager> fGraphManager; /*! Shared memory Port manager */ | |||
JackShmReadWritePtr<JackEngineControl> fEngineControl; /*! Shared engine control */ // transport engine has to be writable | |||
@@ -63,7 +63,9 @@ struct LIB_EXPORT JackLibGlobals | |||
JackLibGlobals() | |||
{ | |||
jack_log("JackLibGlobals"); | |||
JackMessageBuffer::Create(); | |||
if (!JackMessageBuffer::Create()) { | |||
jack_error("Cannot create message buffer"); | |||
} | |||
fGraphManager = -1; | |||
fEngineControl = -1; | |||
@@ -127,6 +129,7 @@ struct LIB_EXPORT JackLibGlobals | |||
{ | |||
if (--fClientCount == 0 && fGlobals) { | |||
jack_log("JackLibGlobals Destroy %x", fGlobals); | |||
EndTime(); | |||
delete fGlobals; | |||
fGlobals = NULL; | |||
} | |||
@@ -18,6 +18,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
*/ | |||
#include "JackLibSampleRateResampler.h" | |||
#include "JackError.h" | |||
namespace Jack | |||
{ | |||
@@ -103,6 +103,14 @@ class SERVER_EXPORT JackLockedEngine | |||
return fEngine.Close(); | |||
CATCH_EXCEPTION_RETURN | |||
} | |||
void ShutDown() | |||
{ | |||
// No lock needed | |||
TRY_CALL | |||
fEngine.ShutDown(); | |||
CATCH_EXCEPTION | |||
} | |||
// Client management | |||
int ClientCheck(const char* name, int uuid, char* name_res, int protocol, int options, int* status) | |||
@@ -325,7 +333,7 @@ class SERVER_EXPORT JackLockedEngine | |||
CATCH_EXCEPTION | |||
} | |||
void SessionNotify(int refnum, const char* target, jack_session_event_type_t type, const char *path, JackChannelTransaction *socket, JackSessionNotifyResult** result) | |||
void SessionNotify(int refnum, const char* target, jack_session_event_type_t type, const char *path, detail::JackChannelTransactionInterface *socket, JackSessionNotifyResult** result) | |||
{ | |||
TRY_CALL | |||
JackLock lock(&fEngine); | |||
@@ -333,42 +341,42 @@ class SERVER_EXPORT JackLockedEngine | |||
CATCH_EXCEPTION | |||
} | |||
void SessionReply(int refnum) | |||
int SessionReply(int refnum) | |||
{ | |||
TRY_CALL | |||
JackLock lock(&fEngine); | |||
fEngine.SessionReply(refnum); | |||
CATCH_EXCEPTION | |||
return fEngine.SessionReply(refnum); | |||
CATCH_EXCEPTION_RETURN | |||
} | |||
void GetUUIDForClientName(const char *client_name, char *uuid_res, int *result) | |||
int GetUUIDForClientName(const char *client_name, char *uuid_res) | |||
{ | |||
TRY_CALL | |||
JackLock lock(&fEngine); | |||
fEngine.GetUUIDForClientName(client_name, uuid_res, result); | |||
CATCH_EXCEPTION | |||
return fEngine.GetUUIDForClientName(client_name, uuid_res); | |||
CATCH_EXCEPTION_RETURN | |||
} | |||
void GetClientNameForUUID(const char *uuid, char *name_res, int *result) | |||
int GetClientNameForUUID(const char *uuid, char *name_res) | |||
{ | |||
TRY_CALL | |||
JackLock lock(&fEngine); | |||
fEngine.GetClientNameForUUID(uuid, name_res, result); | |||
CATCH_EXCEPTION | |||
return fEngine.GetClientNameForUUID(uuid, name_res); | |||
CATCH_EXCEPTION_RETURN | |||
} | |||
void ReserveClientName(const char *name, const char *uuid, int *result) | |||
int ReserveClientName(const char *name, const char *uuid) | |||
{ | |||
TRY_CALL | |||
JackLock lock(&fEngine); | |||
fEngine.ReserveClientName(name, uuid, result); | |||
CATCH_EXCEPTION | |||
return fEngine.ReserveClientName(name, uuid); | |||
CATCH_EXCEPTION_RETURN | |||
} | |||
void ClientHasSessionCallback(const char *name, int *result) | |||
int ClientHasSessionCallback(const char *name) | |||
{ | |||
TRY_CALL | |||
JackLock lock(&fEngine); | |||
fEngine.ClientHasSessionCallback(name, result); | |||
CATCH_EXCEPTION | |||
return fEngine.ClientHasSessionCallback(name); | |||
CATCH_EXCEPTION_RETURN | |||
} | |||
}; | |||
@@ -41,6 +41,7 @@ int JackLoopbackDriver::ProcessReadSync() | |||
memcpy(GetInputBuffer(i), GetOutputBuffer(i), sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize); | |||
} | |||
// Resume connected clients in the graph | |||
if (ResumeRefNum() < 0) { | |||
jack_error("JackLoopbackDriver::ProcessReadSync - ResumeRefNum error"); | |||
res = -1; | |||
@@ -51,6 +52,7 @@ int JackLoopbackDriver::ProcessReadSync() | |||
int JackLoopbackDriver::ProcessWriteSync() | |||
{ | |||
// Suspend on connected clients in the graph | |||
if (SuspendRefNum() < 0) { | |||
jack_error("JackLoopbackDriver::ProcessWriteSync SuspendRefNum error"); | |||
return -1; | |||
@@ -67,6 +69,7 @@ int JackLoopbackDriver::ProcessReadAsync() | |||
memcpy(GetInputBuffer(i), GetOutputBuffer(i), sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize); | |||
} | |||
// Resume connected clients in the graph | |||
if (ResumeRefNum() < 0) { | |||
jack_error("JackLoopbackDriver::ProcessReadAsync - ResumeRefNum error"); | |||
res = -1; | |||
@@ -22,6 +22,7 @@ | |||
#include "JackMessageBuffer.h" | |||
#include "JackGlobals.h" | |||
#include "JackError.h" | |||
#include "JackTime.h" | |||
namespace Jack | |||
{ | |||
@@ -29,19 +30,32 @@ namespace Jack | |||
JackMessageBuffer* JackMessageBuffer::fInstance = NULL; | |||
JackMessageBuffer::JackMessageBuffer() | |||
:fInit(NULL),fInitArg(NULL),fThread(this),fInBuffer(0),fOutBuffer(0),fOverruns(0),fRunning(false) | |||
:fInit(NULL), | |||
fInitArg(NULL), | |||
fThread(this), | |||
fGuard(), | |||
fInBuffer(0), | |||
fOutBuffer(0), | |||
fOverruns(0), | |||
fRunning(false) | |||
{} | |||
JackMessageBuffer::~JackMessageBuffer() | |||
{} | |||
void JackMessageBuffer::Start() | |||
bool JackMessageBuffer::Start() | |||
{ | |||
// Before StartSync()... | |||
fRunning = true; | |||
fThread.StartSync(); | |||
if (fThread.StartSync() == 0) { | |||
return true; | |||
} else { | |||
fRunning = false; | |||
return false; | |||
} | |||
} | |||
void JackMessageBuffer::Stop() | |||
bool JackMessageBuffer::Stop() | |||
{ | |||
if (fOverruns > 0) { | |||
jack_error("WARNING: %d message buffer overruns!", fOverruns); | |||
@@ -59,6 +73,7 @@ void JackMessageBuffer::Stop() | |||
} | |||
Flush(); | |||
return true; | |||
} | |||
void JackMessageBuffer::Flush() | |||
@@ -96,7 +111,7 @@ bool JackMessageBuffer::Execute() | |||
/* and we're done */ | |||
fGuard.Signal(); | |||
} | |||
/* releasing the mutex reduces contention */ | |||
fGuard.Unlock(); | |||
Flush(); | |||
@@ -110,20 +125,30 @@ bool JackMessageBuffer::Execute() | |||
return false; | |||
} | |||
void JackMessageBuffer::Create() | |||
bool JackMessageBuffer::Create() | |||
{ | |||
if (fInstance == NULL) { | |||
fInstance = new JackMessageBuffer(); | |||
fInstance->Start(); | |||
if (!fInstance->Start()) { | |||
jack_error("JackMessageBuffer::Create cannot start thread"); | |||
delete fInstance; | |||
fInstance = NULL; | |||
return false; | |||
} | |||
} | |||
return true; | |||
} | |||
void JackMessageBuffer::Destroy() | |||
bool JackMessageBuffer::Destroy() | |||
{ | |||
if (fInstance != NULL) { | |||
fInstance->Stop(); | |||
delete fInstance; | |||
fInstance = NULL; | |||
return true; | |||
} else { | |||
return false; | |||
} | |||
} | |||
@@ -137,21 +162,42 @@ void JackMessageBufferAdd(int level, const char *message) | |||
} | |||
} | |||
void JackMessageBuffer::SetInitCallback(JackThreadInitCallback callback, void *arg) | |||
int JackMessageBuffer::SetInitCallback(JackThreadInitCallback callback, void *arg) | |||
{ | |||
if (fGuard.Lock()) { | |||
if (fInstance && callback && fRunning && fGuard.Lock()) { | |||
/* set up the callback */ | |||
fInitArg = arg; | |||
fInit = callback; | |||
/* wake msg buffer thread */ | |||
#ifndef WIN32 | |||
// wake msg buffer thread | |||
fGuard.Signal(); | |||
/* wait for it to be done */ | |||
// wait for it to be done | |||
fGuard.Wait(); | |||
/* and we're done */ | |||
// and we're done | |||
fGuard.Unlock(); | |||
} else { | |||
jack_error("JackMessageBuffer::SetInitCallback lock cannot be taken"); | |||
#else | |||
/* | |||
The condition variable emulation code does not work reliably on Windows (lost signal). | |||
So use a "hackish" way to signal/wait for the result. | |||
Probaly better in the long term : use pthread-win32 (http://sourceware.org/pthreads-win32/` | |||
*/ | |||
fGuard.Unlock(); | |||
int count = 0; | |||
while (fInit && ++count < 1000) { | |||
/* wake msg buffer thread */ | |||
fGuard.Signal(); | |||
JackSleep(1000); | |||
} | |||
if (count == 1000) goto error; | |||
#endif | |||
return 0; | |||
} | |||
error: | |||
jack_error("JackMessageBuffer::SetInitCallback : callback cannot be executed"); | |||
return -1; | |||
} | |||
}; | |||
@@ -57,7 +57,7 @@ class JackMessageBuffer : public JackRunnableInterface | |||
private: | |||
JackThreadInitCallback fInit; | |||
volatile JackThreadInitCallback fInit; | |||
void* fInitArg; | |||
JackMessage fBuffers[MB_BUFFERS]; | |||
JackThread fThread; | |||
@@ -69,8 +69,8 @@ class JackMessageBuffer : public JackRunnableInterface | |||
void Flush(); | |||
void Start(); | |||
void Stop(); | |||
bool Start(); | |||
bool Stop(); | |||
public: | |||
@@ -80,11 +80,11 @@ class JackMessageBuffer : public JackRunnableInterface | |||
// JackRunnableInterface interface | |||
bool Execute(); | |||
void static Create(); | |||
void static Destroy(); | |||
bool static Create(); | |||
bool static Destroy(); | |||
void AddMessage(int level, const char *message); | |||
void SetInitCallback(JackThreadInitCallback callback, void *arg); | |||
int SetInitCallback(JackThreadInitCallback callback, void *arg); | |||
static JackMessageBuffer* fInstance; | |||
}; | |||
@@ -19,6 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
#include "JackMidiBufferReadQueue.h" | |||
#include "JackMidiUtil.h" | |||
#include "JackError.h" | |||
using Jack::JackMidiBufferReadQueue; | |||
@@ -19,6 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
#include "JackMidiBufferWriteQueue.h" | |||
#include "JackMidiUtil.h" | |||
#include "JackError.h" | |||
using Jack::JackMidiBufferWriteQueue; | |||
@@ -136,6 +136,8 @@ int JackMidiDriver::SetBufferSize(jack_nframes_t buffer_size) | |||
int JackMidiDriver::ProcessReadSync() | |||
{ | |||
int res = 0; | |||
jack_log("JackMidiDriver::ProcessReadSync"); | |||
// Read input buffers for the current cycle | |||
if (Read() < 0) { | |||
@@ -154,6 +156,8 @@ int JackMidiDriver::ProcessReadSync() | |||
int JackMidiDriver::ProcessWriteSync() | |||
{ | |||
int res = 0; | |||
jack_log("JackMidiDriver::ProcessWriteSync"); | |||
if (SuspendRefNum() < 0) { | |||
jack_error("JackMidiDriver::ProcessWriteSync: SuspendRefNum error"); | |||
@@ -172,6 +176,8 @@ int JackMidiDriver::ProcessWriteSync() | |||
int JackMidiDriver::ProcessReadAsync() | |||
{ | |||
int res = 0; | |||
jack_log("JackMidiDriver::ProcessReadAsync"); | |||
// Read input buffers for the current cycle | |||
if (Read() < 0) { | |||
@@ -195,6 +201,7 @@ int JackMidiDriver::ProcessReadAsync() | |||
int JackMidiDriver::ProcessWriteAsync() | |||
{ | |||
jack_log("JackMidiDriver::ProcessWriteAsync"); | |||
return 0; | |||
} | |||
@@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
#include <new> | |||
#include "JackMidiRawInputWriteQueue.h" | |||
#include "JackError.h" | |||
using Jack::JackMidiRawInputWriteQueue; | |||
@@ -40,7 +40,8 @@ class JackLockAble | |||
JackMutex fMutex; | |||
JackLockAble() | |||
JackLockAble(const char* name = NULL) | |||
:fMutex(name) | |||
{} | |||
~JackLockAble() | |||
{} | |||
@@ -19,9 +19,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
#include <assert.h> | |||
#include <stdarg.h> | |||
#include "JackNetInterface.h" | |||
#include "JackError.h" | |||
#include "JackException.h" | |||
#include "JackAudioAdapterInterface.h" | |||
#ifdef __cplusplus | |||
@@ -86,41 +85,48 @@ extern "C" | |||
typedef int (*JackNetSlaveSampleRateCallback) (jack_nframes_t nframes, void *arg); | |||
typedef void (*JackNetSlaveShutdownCallback) (void* data); | |||
SERVER_EXPORT jack_net_slave_t* jack_net_slave_open(const char* ip, int port, const char* name, jack_slave_t* request, jack_master_t* result); | |||
SERVER_EXPORT int jack_net_slave_close(jack_net_slave_t* net); | |||
LIB_EXPORT jack_net_slave_t* jack_net_slave_open(const char* ip, int port, const char* name, jack_slave_t* request, jack_master_t* result); | |||
LIB_EXPORT int jack_net_slave_close(jack_net_slave_t* net); | |||
SERVER_EXPORT int jack_net_slave_activate(jack_net_slave_t* net); | |||
SERVER_EXPORT int jack_net_slave_deactivate(jack_net_slave_t* net); | |||
LIB_EXPORT int jack_net_slave_activate(jack_net_slave_t* net); | |||
LIB_EXPORT int jack_net_slave_deactivate(jack_net_slave_t* net); | |||
SERVER_EXPORT int jack_set_net_slave_process_callback(jack_net_slave_t* net, JackNetSlaveProcessCallback net_callback, void *arg); | |||
SERVER_EXPORT int jack_set_net_slave_buffer_size_callback(jack_net_slave_t* net, JackNetSlaveBufferSizeCallback bufsize_callback, void *arg); | |||
SERVER_EXPORT int jack_set_net_slave_sample_rate_callback(jack_net_slave_t* net, JackNetSlaveSampleRateCallback samplerate_callback, void *arg); | |||
SERVER_EXPORT int jack_set_net_slave_shutdown_callback(jack_net_slave_t* net, JackNetSlaveShutdownCallback shutdown_callback, void *arg); | |||
LIB_EXPORT int jack_set_net_slave_process_callback(jack_net_slave_t* net, JackNetSlaveProcessCallback net_callback, void *arg); | |||
LIB_EXPORT int jack_set_net_slave_buffer_size_callback(jack_net_slave_t* net, JackNetSlaveBufferSizeCallback bufsize_callback, void *arg); | |||
LIB_EXPORT int jack_set_net_slave_sample_rate_callback(jack_net_slave_t* net, JackNetSlaveSampleRateCallback samplerate_callback, void *arg); | |||
LIB_EXPORT int jack_set_net_slave_shutdown_callback(jack_net_slave_t* net, JackNetSlaveShutdownCallback shutdown_callback, void *arg); | |||
// NetJack master API | |||
typedef struct _jack_net_master jack_net_master_t; | |||
SERVER_EXPORT jack_net_master_t* jack_net_master_open(const char* ip, int port, const char* name, jack_master_t* request, jack_slave_t* result); | |||
SERVER_EXPORT int jack_net_master_close(jack_net_master_t* net); | |||
LIB_EXPORT jack_net_master_t* jack_net_master_open(const char* ip, int port, const char* name, jack_master_t* request, jack_slave_t* result); | |||
LIB_EXPORT int jack_net_master_close(jack_net_master_t* net); | |||
SERVER_EXPORT int jack_net_master_recv(jack_net_master_t* net, int audio_input, float** audio_input_buffer, int midi_input, void** midi_input_buffer); | |||
SERVER_EXPORT int jack_net_master_send(jack_net_master_t* net, int audio_output, float** audio_output_buffer, int midi_output, void** midi_output_buffer); | |||
LIB_EXPORT int jack_net_master_recv(jack_net_master_t* net, int audio_input, float** audio_input_buffer, int midi_input, void** midi_input_buffer); | |||
LIB_EXPORT int jack_net_master_send(jack_net_master_t* net, int audio_output, float** audio_output_buffer, int midi_output, void** midi_output_buffer); | |||
// NetJack adapter API | |||
typedef struct _jack_adapter jack_adapter_t; | |||
SERVER_EXPORT jack_adapter_t* jack_create_adapter(int input, int output, | |||
LIB_EXPORT jack_adapter_t* jack_create_adapter(int input, int output, | |||
jack_nframes_t host_buffer_size, | |||
jack_nframes_t host_sample_rate, | |||
jack_nframes_t adapted_buffer_size, | |||
jack_nframes_t adapted_sample_rate); | |||
SERVER_EXPORT int jack_destroy_adapter(jack_adapter_t* adapter); | |||
SERVER_EXPORT void jack_flush_adapter(jack_adapter_t* adapter); | |||
LIB_EXPORT int jack_destroy_adapter(jack_adapter_t* adapter); | |||
LIB_EXPORT void jack_flush_adapter(jack_adapter_t* adapter); | |||
LIB_EXPORT int jack_adapter_push_and_pull(jack_adapter_t* adapter, float** input, float** output, unsigned int frames); | |||
LIB_EXPORT int jack_adapter_pull_and_push(jack_adapter_t* adapter, float** input, float** output, unsigned int frames); | |||
SERVER_EXPORT int jack_adapter_push_and_pull(jack_adapter_t* adapter, float** input, float** output, unsigned int frames); | |||
SERVER_EXPORT int jack_adapter_pull_and_push(jack_adapter_t* adapter, float** input, float** output, unsigned int frames); | |||
#define LOG_LEVEL_INFO 1 | |||
#define LOG_LEVEL_ERROR 2 | |||
LIB_EXPORT void jack_error(const char *fmt, ...); | |||
LIB_EXPORT void jack_info(const char *fmt, ...); | |||
LIB_EXPORT void jack_log(const char *fmt, ...); | |||
#ifdef __cplusplus | |||
} | |||
@@ -151,6 +157,8 @@ struct JackNetExtMaster : public JackNetMasterInterface { | |||
fSocket.SetPort(port); | |||
fRequest.buffer_size = request->buffer_size; | |||
fRequest.sample_rate = request->sample_rate; | |||
fRequest.audio_input = request->audio_input; | |||
fRequest.audio_output = request->audio_output; | |||
fAudioCaptureBuffer = NULL; | |||
fAudioPlaybackBuffer = NULL; | |||
fMidiCaptureBuffer = NULL; | |||
@@ -215,11 +223,10 @@ struct JackNetExtMaster : public JackNetMasterInterface { | |||
} | |||
if (rx_bytes == sizeof(session_params_t )) { | |||
switch (GetPacketType(&fParams)) { | |||
case SLAVE_AVAILABLE: | |||
if (MasterInit() == 0) { | |||
if (InitMaster(result) == 0) { | |||
SessionParamsDisplay(&fParams); | |||
fRunning = false; | |||
} else { | |||
@@ -238,8 +245,8 @@ struct JackNetExtMaster : public JackNetMasterInterface { | |||
} | |||
} | |||
while (fRunning); | |||
// Set result paramaters | |||
// Set result parameters | |||
result->audio_input = fParams.fSendAudioChannels; | |||
result->audio_output = fParams.fReturnAudioChannels; | |||
result->midi_input = fParams.fSendMidiChannels; | |||
@@ -253,7 +260,7 @@ struct JackNetExtMaster : public JackNetMasterInterface { | |||
return -1; | |||
} | |||
int MasterInit() | |||
int InitMaster(jack_slave_t* result) | |||
{ | |||
// Check MASTER <==> SLAVE network protocol coherency | |||
if (fParams.fProtocolVersion != MASTER_PROTOCOL) { | |||
@@ -264,14 +271,45 @@ struct JackNetExtMaster : public JackNetMasterInterface { | |||
// Settings | |||
fSocket.GetName(fParams.fMasterNetName); | |||
fParams.fID = 1; | |||
fParams.fSampleEncoder = JackFloatEncoder; | |||
fParams.fPeriodSize = fRequest.buffer_size; | |||
fParams.fSampleRate = fRequest.sample_rate; | |||
if (fRequest.audio_input == -1) { | |||
if (fParams.fSendAudioChannels == -1) { | |||
jack_error("Error : master and slave use -1 for wanted inputs..."); | |||
return -1; | |||
} else { | |||
result->audio_input = fParams.fSendAudioChannels; | |||
jack_info("Takes slave %d inputs", fParams.fSendAudioChannels); | |||
} | |||
} else if (fParams.fSendAudioChannels == -1) { | |||
fParams.fSendAudioChannels = fRequest.audio_input; | |||
jack_info("Takes master %d inputs", fRequest.audio_input); | |||
} else if (fParams.fSendAudioChannels != fRequest.audio_input) { | |||
jack_error("Error : master wants %d inputs and slave wants %d inputs...", fRequest.audio_input, fParams.fSendAudioChannels); | |||
return -1; | |||
} | |||
if (fRequest.audio_output == -1) { | |||
if (fParams.fReturnAudioChannels == -1) { | |||
jack_error("Error : master and slave use -1 for wanted outputs..."); | |||
return -1; | |||
} else { | |||
result->audio_output = fParams.fReturnAudioChannels; | |||
jack_info("Takes slave %d outputs", fParams.fReturnAudioChannels); | |||
} | |||
} else if (fParams.fReturnAudioChannels == -1) { | |||
fParams.fReturnAudioChannels = fRequest.audio_output; | |||
jack_info("Takes master %d outputs", fRequest.audio_output); | |||
} else if (fParams.fReturnAudioChannels != fRequest.audio_output) { | |||
jack_error("Error : master wants %d outputs and slave wants %d outputs...", fRequest.audio_output, fParams.fReturnAudioChannels); | |||
return -1; | |||
} | |||
// Close request socket | |||
fSocket.Close(); | |||
// Network slave init | |||
/// Network init | |||
if (!JackNetMasterInterface::Init()) { | |||
return -1; | |||
} | |||
@@ -361,7 +399,9 @@ struct JackNetExtMaster : public JackNetMasterInterface { | |||
int Read(int audio_input, float** audio_input_buffer, int midi_input, void** midi_input_buffer) | |||
{ | |||
try { | |||
assert(audio_input == fParams.fReturnAudioChannels); | |||
for (int audio_port_index = 0; audio_port_index < audio_input; audio_port_index++) { | |||
@@ -371,11 +411,13 @@ struct JackNetExtMaster : public JackNetMasterInterface { | |||
for (int midi_port_index = 0; midi_port_index < midi_input; midi_port_index++) { | |||
fNetMidiPlaybackBuffer->SetBuffer(midi_port_index, ((JackMidiBuffer**)midi_input_buffer)[midi_port_index]); | |||
} | |||
if (SyncRecv() == SOCKET_ERROR) { | |||
return 0; | |||
//receive sync | |||
int res = SyncRecv(); | |||
if ((res == 0) || (res == SOCKET_ERROR)) { | |||
return res; | |||
} | |||
DecodeSyncPacket(); | |||
return DataRecv(); | |||
@@ -388,6 +430,7 @@ struct JackNetExtMaster : public JackNetMasterInterface { | |||
int Write(int audio_output, float** audio_output_buffer, int midi_output, void** midi_output_buffer) | |||
{ | |||
try { | |||
assert(audio_output == fParams.fSendAudioChannels); | |||
for (int audio_port_index = 0; audio_port_index < audio_output; audio_port_index++) { | |||
@@ -397,20 +440,32 @@ struct JackNetExtMaster : public JackNetMasterInterface { | |||
for (int midi_port_index = 0; midi_port_index < midi_output; midi_port_index++) { | |||
fNetMidiCaptureBuffer->SetBuffer(midi_port_index, ((JackMidiBuffer**)midi_output_buffer)[midi_port_index]); | |||
} | |||
if (IsSynched()) { // only send if connection is "synched" | |||
EncodeSyncPacket(); | |||
if (SyncSend() == SOCKET_ERROR) { | |||
return SOCKET_ERROR; | |||
} | |||
EncodeSyncPacket(); | |||
if (SyncSend() == SOCKET_ERROR) { | |||
return SOCKET_ERROR; | |||
//send data | |||
if (DataSend() == SOCKET_ERROR) { | |||
return SOCKET_ERROR; | |||
} | |||
} else { | |||
jack_info("Connection is not synched, skip cycle..."); | |||
} | |||
return DataSend(); | |||
return 0; | |||
} catch (JackNetException& e) { | |||
jack_error("Connection lost."); | |||
return -1; | |||
} | |||
} | |||
} | |||
// Transport | |||
void EncodeTransportData() | |||
@@ -490,6 +545,13 @@ struct JackNetExtSlave : public JackNetSlaveInterface, public JackRunnableInterf | |||
int Open(jack_master_t* result) | |||
{ | |||
// Check CELT encoder parameters | |||
if ((fParams.fSampleEncoder == JackCeltEncoder) && (fParams.fKBps == 0)) { | |||
jack_error("CELT encoder with 0 for kps..."); | |||
return -1; | |||
} | |||
// Check latency | |||
if (fParams.fNetworkLatency > NETWORK_MAX_LATENCY) { | |||
jack_error("Error : network latency is limited to %d", NETWORK_MAX_LATENCY); | |||
return -1; | |||
@@ -541,7 +603,7 @@ struct JackNetExtSlave : public JackNetSlaveInterface, public JackRunnableInterf | |||
return -1; | |||
} | |||
// Finish connection... | |||
// Finish connection | |||
if (!JackNetSlaveInterface::InitRendering()) { | |||
jack_error("Starting network fails..."); | |||
return -1; | |||
@@ -604,29 +666,33 @@ struct JackNetExtSlave : public JackNetSlaveInterface, public JackRunnableInterf | |||
void FreePorts() | |||
{ | |||
if (fAudioCaptureBuffer) { | |||
for (int audio_port_index = 0; audio_port_index < fParams.fSendAudioChannels; audio_port_index++) | |||
for (int audio_port_index = 0; audio_port_index < fParams.fSendAudioChannels; audio_port_index++) { | |||
delete[] fAudioCaptureBuffer[audio_port_index]; | |||
} | |||
delete[] fAudioCaptureBuffer; | |||
fAudioCaptureBuffer = NULL; | |||
} | |||
if (fMidiCaptureBuffer) { | |||
for (int midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) | |||
for (int midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) { | |||
delete[] (fMidiCaptureBuffer[midi_port_index]); | |||
} | |||
delete[] fMidiCaptureBuffer; | |||
fMidiCaptureBuffer = NULL; | |||
} | |||
if (fAudioPlaybackBuffer) { | |||
for (int audio_port_index = 0; audio_port_index < fParams.fReturnAudioChannels; audio_port_index++) | |||
for (int audio_port_index = 0; audio_port_index < fParams.fReturnAudioChannels; audio_port_index++) { | |||
delete[] fAudioPlaybackBuffer[audio_port_index]; | |||
} | |||
delete[] fAudioPlaybackBuffer; | |||
fAudioPlaybackBuffer = NULL; | |||
} | |||
if (fMidiPlaybackBuffer) { | |||
for (int midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) | |||
for (int midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) { | |||
delete[] fMidiPlaybackBuffer[midi_port_index]; | |||
} | |||
delete[] fMidiPlaybackBuffer; | |||
fMidiPlaybackBuffer = NULL; | |||
} | |||
@@ -661,9 +727,9 @@ struct JackNetExtSlave : public JackNetSlaveInterface, public JackRunnableInterf | |||
} | |||
return false; | |||
} catch (JackNetException& e) { | |||
// Otherwise just restart... | |||
e.PrintMessage(); | |||
jack_info("NetSlave is restarted"); | |||
fThread.DropRealTime(); | |||
fThread.SetStatus(JackThread::kIniting); | |||
FreePorts(); | |||
@@ -855,7 +921,7 @@ struct JackNetAdapter : public JackAudioAdapterInterface { | |||
using namespace Jack; | |||
SERVER_EXPORT jack_net_slave_t* jack_net_slave_open(const char* ip, int port, const char* name, jack_slave_t* request, jack_master_t* result) | |||
LIB_EXPORT jack_net_slave_t* jack_net_slave_open(const char* ip, int port, const char* name, jack_slave_t* request, jack_master_t* result) | |||
{ | |||
JackNetExtSlave* slave = new JackNetExtSlave(ip, port, name, request); | |||
if (slave->Open(result) == 0) { | |||
@@ -866,7 +932,7 @@ SERVER_EXPORT jack_net_slave_t* jack_net_slave_open(const char* ip, int port, co | |||
} | |||
} | |||
SERVER_EXPORT int jack_net_slave_close(jack_net_slave_t* net) | |||
LIB_EXPORT int jack_net_slave_close(jack_net_slave_t* net) | |||
{ | |||
JackNetExtSlave* slave = (JackNetExtSlave*)net; | |||
slave->Close(); | |||
@@ -874,37 +940,37 @@ SERVER_EXPORT int jack_net_slave_close(jack_net_slave_t* net) | |||
return 0; | |||
} | |||
SERVER_EXPORT int jack_set_net_slave_process_callback(jack_net_slave_t* net, JackNetSlaveProcessCallback net_callback, void *arg) | |||
LIB_EXPORT int jack_set_net_slave_process_callback(jack_net_slave_t* net, JackNetSlaveProcessCallback net_callback, void *arg) | |||
{ | |||
JackNetExtSlave* slave = (JackNetExtSlave*)net; | |||
return slave->SetProcessCallback(net_callback, arg); | |||
} | |||
SERVER_EXPORT int jack_net_slave_activate(jack_net_slave_t* net) | |||
LIB_EXPORT int jack_net_slave_activate(jack_net_slave_t* net) | |||
{ | |||
JackNetExtSlave* slave = (JackNetExtSlave*)net; | |||
return slave->Start(); | |||
} | |||
SERVER_EXPORT int jack_net_slave_deactivate(jack_net_slave_t* net) | |||
LIB_EXPORT int jack_net_slave_deactivate(jack_net_slave_t* net) | |||
{ | |||
JackNetExtSlave* slave = (JackNetExtSlave*)net; | |||
return slave->Stop(); | |||
} | |||
SERVER_EXPORT int jack_set_net_slave_buffer_size_callback(jack_net_slave_t *net, JackNetSlaveBufferSizeCallback bufsize_callback, void *arg) | |||
LIB_EXPORT int jack_set_net_slave_buffer_size_callback(jack_net_slave_t *net, JackNetSlaveBufferSizeCallback bufsize_callback, void *arg) | |||
{ | |||
JackNetExtSlave* slave = (JackNetExtSlave*)net; | |||
return slave->SetBufferSizeCallback(bufsize_callback, arg); | |||
} | |||
SERVER_EXPORT int jack_set_net_slave_sample_rate_callback(jack_net_slave_t *net, JackNetSlaveSampleRateCallback samplerate_callback, void *arg) | |||
LIB_EXPORT int jack_set_net_slave_sample_rate_callback(jack_net_slave_t *net, JackNetSlaveSampleRateCallback samplerate_callback, void *arg) | |||
{ | |||
JackNetExtSlave* slave = (JackNetExtSlave*)net; | |||
return slave->SetSampleRateCallback(samplerate_callback, arg); | |||
} | |||
SERVER_EXPORT int jack_set_net_slave_shutdown_callback(jack_net_slave_t *net, JackNetSlaveShutdownCallback shutdown_callback, void *arg) | |||
LIB_EXPORT int jack_set_net_slave_shutdown_callback(jack_net_slave_t *net, JackNetSlaveShutdownCallback shutdown_callback, void *arg) | |||
{ | |||
JackNetExtSlave* slave = (JackNetExtSlave*)net; | |||
return slave->SetShutdownCallback(shutdown_callback, arg); | |||
@@ -912,7 +978,7 @@ SERVER_EXPORT int jack_set_net_slave_shutdown_callback(jack_net_slave_t *net, Ja | |||
// Master API | |||
SERVER_EXPORT jack_net_master_t* jack_net_master_open(const char* ip, int port, const char* name, jack_master_t* request, jack_slave_t* result) | |||
LIB_EXPORT jack_net_master_t* jack_net_master_open(const char* ip, int port, const char* name, jack_master_t* request, jack_slave_t* result) | |||
{ | |||
JackNetExtMaster* master = new JackNetExtMaster(ip, port, name, request); | |||
if (master->Open(result) == 0) { | |||
@@ -923,20 +989,21 @@ SERVER_EXPORT jack_net_master_t* jack_net_master_open(const char* ip, int port, | |||
} | |||
} | |||
SERVER_EXPORT int jack_net_master_close(jack_net_master_t* net) | |||
LIB_EXPORT int jack_net_master_close(jack_net_master_t* net) | |||
{ | |||
JackNetExtMaster* master = (JackNetExtMaster*)net; | |||
master->Close(); | |||
delete master; | |||
return 0; | |||
} | |||
SERVER_EXPORT int jack_net_master_recv(jack_net_master_t* net, int audio_input, float** audio_input_buffer, int midi_input, void** midi_input_buffer) | |||
LIB_EXPORT int jack_net_master_recv(jack_net_master_t* net, int audio_input, float** audio_input_buffer, int midi_input, void** midi_input_buffer) | |||
{ | |||
JackNetExtMaster* master = (JackNetExtMaster*)net; | |||
return master->Read(audio_input, audio_input_buffer, midi_input, midi_input_buffer); | |||
} | |||
SERVER_EXPORT int jack_net_master_send(jack_net_master_t* net, int audio_output, float** audio_output_buffer, int midi_output, void** midi_output_buffer) | |||
LIB_EXPORT int jack_net_master_send(jack_net_master_t* net, int audio_output, float** audio_output_buffer, int midi_output, void** midi_output_buffer) | |||
{ | |||
JackNetExtMaster* master = (JackNetExtMaster*)net; | |||
return master->Write(audio_output, audio_output_buffer, midi_output, midi_output_buffer); | |||
@@ -944,7 +1011,7 @@ SERVER_EXPORT int jack_net_master_send(jack_net_master_t* net, int audio_output, | |||
// Adapter API | |||
SERVER_EXPORT jack_adapter_t* jack_create_adapter(int input, int output, | |||
LIB_EXPORT jack_adapter_t* jack_create_adapter(int input, int output, | |||
jack_nframes_t host_buffer_size, | |||
jack_nframes_t host_sample_rate, | |||
jack_nframes_t adapted_buffer_size, | |||
@@ -957,52 +1024,53 @@ SERVER_EXPORT jack_adapter_t* jack_create_adapter(int input, int output, | |||
} | |||
} | |||
SERVER_EXPORT int jack_destroy_adapter(jack_adapter_t* adapter) | |||
LIB_EXPORT int jack_destroy_adapter(jack_adapter_t* adapter) | |||
{ | |||
delete((JackNetAdapter*)adapter); | |||
return 0; | |||
} | |||
SERVER_EXPORT void jack_flush_adapter(jack_adapter_t* adapter) | |||
LIB_EXPORT void jack_flush_adapter(jack_adapter_t* adapter) | |||
{ | |||
JackNetAdapter* slave = (JackNetAdapter*)adapter; | |||
slave->Flush(); | |||
} | |||
SERVER_EXPORT int jack_adapter_push_and_pull(jack_adapter_t* adapter, float** input, float** output, unsigned int frames) | |||
LIB_EXPORT int jack_adapter_push_and_pull(jack_adapter_t* adapter, float** input, float** output, unsigned int frames) | |||
{ | |||
JackNetAdapter* slave = (JackNetAdapter*)adapter; | |||
return slave->PushAndPull(input, output, frames); | |||
} | |||
SERVER_EXPORT int jack_adapter_pull_and_push(jack_adapter_t* adapter, float** input, float** output, unsigned int frames) | |||
LIB_EXPORT int jack_adapter_pull_and_push(jack_adapter_t* adapter, float** input, float** output, unsigned int frames) | |||
{ | |||
JackNetAdapter* slave = (JackNetAdapter*)adapter; | |||
return slave->PullAndPush(input, output, frames); | |||
} | |||
//#ifdef MY_TARGET_OS_IPHONE | |||
#if 1 | |||
static void jack_format_and_log(int level, const char *prefix, const char *fmt, va_list ap) | |||
{ | |||
char buffer[300]; | |||
size_t len; | |||
static const char* netjack_log = getenv("JACK_NETJACK_LOG"); | |||
static bool is_netjack_log = (netjack_log) ? atoi(netjack_log) : 0; | |||
if (prefix != NULL) { | |||
len = strlen(prefix); | |||
memcpy(buffer, prefix, len); | |||
} else { | |||
len = 0; | |||
} | |||
if (is_netjack_log) { | |||
char buffer[300]; | |||
size_t len; | |||
if (prefix != NULL) { | |||
len = strlen(prefix); | |||
memcpy(buffer, prefix, len); | |||
} else { | |||
len = 0; | |||
} | |||
vsnprintf(buffer + len, sizeof(buffer) - len, fmt, ap); | |||
printf("%s", buffer); | |||
printf("\n"); | |||
vsnprintf(buffer + len, sizeof(buffer) - len, fmt, ap); | |||
printf("%s", buffer); | |||
printf("\n"); | |||
} | |||
} | |||
SERVER_EXPORT void jack_error(const char *fmt, ...) | |||
LIB_EXPORT void jack_error(const char *fmt, ...) | |||
{ | |||
va_list ap; | |||
va_start(ap, fmt); | |||
@@ -1010,7 +1078,7 @@ SERVER_EXPORT void jack_error(const char *fmt, ...) | |||
va_end(ap); | |||
} | |||
SERVER_EXPORT void jack_info(const char *fmt, ...) | |||
LIB_EXPORT void jack_info(const char *fmt, ...) | |||
{ | |||
va_list ap; | |||
va_start(ap, fmt); | |||
@@ -1018,26 +1086,10 @@ SERVER_EXPORT void jack_info(const char *fmt, ...) | |||
va_end(ap); | |||
} | |||
SERVER_EXPORT void jack_log(const char *fmt, ...) | |||
LIB_EXPORT void jack_log(const char *fmt, ...) | |||
{ | |||
va_list ap; | |||
va_start(ap, fmt); | |||
jack_format_and_log(LOG_LEVEL_INFO, "Jack: ", fmt, ap); | |||
va_end(ap); | |||
} | |||
#else | |||
// Empty code for now.. | |||
SERVER_EXPORT void jack_error(const char *fmt, ...) | |||
{} | |||
SERVER_EXPORT void jack_info(const char *fmt, ...) | |||
{} | |||
SERVER_EXPORT void jack_log(const char *fmt, ...) | |||
{} | |||
#endif | |||
@@ -260,6 +260,7 @@ namespace Jack | |||
} | |||
return false; | |||
} catch (JackNetException& e) { | |||
// Otherwise just restart... | |||
e.PrintMessage(); | |||
jack_info("NetAdapter is restarted"); | |||
Reset(); | |||
@@ -413,7 +414,7 @@ extern "C" | |||
value.i = 2; | |||
jack_driver_descriptor_add_parameter(desc, &filler, "input-ports", 'C', JackDriverParamInt, &value, NULL, "Number of audio input ports", NULL); | |||
jack_driver_descriptor_add_parameter(desc, &filler, "output-ports", 'C', JackDriverParamInt, &value, NULL, "Number of audio output ports", NULL); | |||
jack_driver_descriptor_add_parameter(desc, &filler, "output-ports", 'P', JackDriverParamInt, &value, NULL, "Number of audio output ports", NULL); | |||
#if HAVE_CELT | |||
value.i = -1; | |||
@@ -16,6 +16,8 @@ along with this program; if not, write to the Free Software | |||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
*/ | |||
#include "JackCompilerDeps.h" | |||
#include "driver_interface.h" | |||
#include "JackNetDriver.h" | |||
#include "JackEngineControl.h" | |||
#include "JackLockedEngine.h" | |||
@@ -509,7 +511,7 @@ namespace Jack | |||
DecodeSyncPacket(); | |||
#ifdef JACK_MONITOR | |||
fNetTimeMon->Add((float(GetMicroSeconds() - fRcvSyncUst) / float(fEngineControl->fPeriodUsecs) * 100.f); | |||
fNetTimeMon->Add(float(GetMicroSeconds() - fRcvSyncUst) / float(fEngineControl->fPeriodUsecs) * 100.f); | |||
#endif | |||
//audio, midi or sync if driver is late | |||
int res = DataRecv(); | |||
@@ -524,7 +526,7 @@ namespace Jack | |||
JackDriver::CycleTakeBeginTime(); | |||
#ifdef JACK_MONITOR | |||
fNetTimeMon->Add((float(GetMicroSeconds() - fRcvSyncUst) / float(fEngineControl->fPeriodUsecs) * 100.f); | |||
fNetTimeMon->Add(float(GetMicroSeconds() - fRcvSyncUst) / float(fEngineControl->fPeriodUsecs) * 100.f); | |||
#endif | |||
return 0; | |||
@@ -555,7 +557,7 @@ namespace Jack | |||
} | |||
#ifdef JACK_MONITOR | |||
fNetTimeMon->AddLast((float(GetMicroSeconds() - fRcvSyncUst) / float(fEngineControl->fPeriodUsecs) * 100.f); | |||
fNetTimeMon->AddLast(float(GetMicroSeconds() - fRcvSyncUst) / float(fEngineControl->fPeriodUsecs) * 100.f); | |||
#endif | |||
//sync | |||
@@ -588,6 +590,7 @@ namespace Jack | |||
extern "C" | |||
{ | |||
#endif | |||
SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor() | |||
{ | |||
jack_driver_desc_t * desc; | |||
@@ -620,8 +623,11 @@ namespace Jack | |||
strcpy(value.str, "'hostname'"); | |||
jack_driver_descriptor_add_parameter(desc, &filler, "client-name", 'n', JackDriverParamString, &value, NULL, "Name of the jack client", NULL); | |||
/* | |||
Deactivated for now.. | |||
value.ui = 0U; | |||
jack_driver_descriptor_add_parameter(desc, &filler, "transport-sync", 't', JackDriverParamUInt, &value, NULL, "Sync transport with master's", NULL); | |||
*/ | |||
value.ui = 5U; | |||
jack_driver_descriptor_add_parameter(desc, &filler, "latency", 'l', JackDriverParamUInt, &value, NULL, "Network latency", NULL); | |||
@@ -696,9 +702,12 @@ namespace Jack | |||
case 'n' : | |||
strncpy(net_name, param->value.str, JACK_CLIENT_NAME_SIZE); | |||
break; | |||
/* | |||
Deactivated for now.. | |||
case 't' : | |||
transport_sync = param->value.ui; | |||
break; | |||
*/ | |||
case 'l' : | |||
network_latency = param->value.ui; | |||
if (network_latency > NETWORK_MAX_LATENCY) { | |||
@@ -18,6 +18,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
#include "JackNetInterface.h" | |||
#include "JackException.h" | |||
#include "JackError.h" | |||
#include <assert.h> | |||
using namespace std; | |||
@@ -52,6 +54,7 @@ namespace Jack | |||
void JackNetInterface::Initialize() | |||
{ | |||
fSetTimeOut = false; | |||
fTxBuffer = NULL; | |||
fRxBuffer = NULL; | |||
fNetAudioCaptureBuffer = NULL; | |||
@@ -196,6 +199,7 @@ namespace Jack | |||
fRxHeader.fCycle = rx_head->fCycle; | |||
fRxHeader.fIsLastPckt = rx_head->fIsLastPckt; | |||
buffer->RenderFromNetwork(rx_head->fSubCycle, rx_bytes - HEADER_SIZE); | |||
// Last midi packet is received, so finish rendering... | |||
if (++recvd_midi_pckt == rx_head->fNumPacket) { | |||
buffer->RenderToJackPorts(); | |||
@@ -211,6 +215,7 @@ namespace Jack | |||
fRxHeader.fIsLastPckt = rx_head->fIsLastPckt; | |||
fRxHeader.fActivePorts = rx_head->fActivePorts; | |||
rx_bytes = buffer->RenderFromNetwork(rx_head->fCycle, rx_head->fSubCycle, fRxHeader.fActivePorts); | |||
// Last audio packet is received, so finish rendering... | |||
if (fRxHeader.fIsLastPckt) { | |||
buffer->RenderToJackPorts(); | |||
@@ -220,7 +225,6 @@ namespace Jack | |||
int JackNetInterface::FinishRecv(NetAudioBuffer* buffer) | |||
{ | |||
// TODO : finish midi and audio rendering ? | |||
buffer->RenderToJackPorts(); | |||
return NET_PACKET_ERROR; | |||
} | |||
@@ -242,12 +246,23 @@ namespace Jack | |||
} | |||
return NULL; | |||
} | |||
void JackNetInterface::SetRcvTimeOut() | |||
{ | |||
if (!fSetTimeOut) { | |||
if (fSocket.SetTimeOut(PACKET_TIMEOUT) == SOCKET_ERROR) { | |||
jack_error("Can't set rx timeout : %s", StrError(NET_ERROR_CODE)); | |||
return; | |||
} | |||
fSetTimeOut = true; | |||
} | |||
} | |||
// JackNetMasterInterface ************************************************************************************ | |||
bool JackNetMasterInterface::Init() | |||
{ | |||
jack_log("JackNetMasterInterface::Init, ID %u", fParams.fID); | |||
jack_log("JackNetMasterInterface::Init : ID %u", fParams.fID); | |||
session_params_t host_params; | |||
uint attempt = 0; | |||
@@ -260,8 +275,9 @@ namespace Jack | |||
} | |||
// timeout on receive (for init) | |||
if (fSocket.SetTimeOut(MASTER_INIT_TIMEOUT) < 0) | |||
jack_error("Can't set timeout : %s", StrError(NET_ERROR_CODE)); | |||
if (fSocket.SetTimeOut(MASTER_INIT_TIMEOUT) < 0) { | |||
jack_error("Can't set init timeout : %s", StrError(NET_ERROR_CODE)); | |||
} | |||
// connect | |||
if (fSocket.Connect() == SOCKET_ERROR) { | |||
@@ -291,6 +307,7 @@ namespace Jack | |||
SessionParamsNToH(&net_params, &host_params); | |||
} | |||
while ((GetPacketType(&host_params) != START_MASTER) && (++attempt < SLAVE_SETUP_RETRY)); | |||
if (attempt == SLAVE_SETUP_RETRY) { | |||
jack_error("Slave doesn't respond, exiting"); | |||
return false; | |||
@@ -299,13 +316,6 @@ namespace Jack | |||
return true; | |||
} | |||
int JackNetMasterInterface::SetRxTimeout() | |||
{ | |||
jack_log("JackNetMasterInterface::SetRxTimeout"); | |||
float time = 3 * 1000000.f * (static_cast<float>(fParams.fPeriodSize) / static_cast<float>(fParams.fSampleRate)); | |||
return fSocket.SetTimeOut(static_cast<int>(time)); | |||
} | |||
bool JackNetMasterInterface::SetParams() | |||
{ | |||
jack_log("JackNetMasterInterface::SetParams audio in = %d audio out = %d MIDI in = %d MIDI out = %d", | |||
@@ -346,14 +356,6 @@ namespace Jack | |||
return false; | |||
} | |||
// set the new timeout for the socket | |||
/* | |||
if (SetRxTimeout() == SOCKET_ERROR) { | |||
jack_error("Can't set rx timeout : %s", StrError(NET_ERROR_CODE)); | |||
goto error; | |||
} | |||
*/ | |||
// set the new rx buffer size | |||
if (SetNetBufferSize() == SOCKET_ERROR) { | |||
jack_error("Can't set net buffer sizes : %s", StrError(NET_ERROR_CODE)); | |||
@@ -418,19 +420,6 @@ namespace Jack | |||
int rx_bytes; | |||
if (((rx_bytes = fSocket.Recv(fRxBuffer, size, flags)) == SOCKET_ERROR) && fRunning) { | |||
/* | |||
net_error_t error = fSocket.GetError(); | |||
// no data isn't really a network error, so just return 0 available read bytes | |||
if (error == NET_NO_DATA) { | |||
return 0; | |||
} else if (error == NET_CONN_ERROR) { | |||
FatalRecvError(); | |||
} else { | |||
jack_error("Error in master receive : %s", StrError(NET_ERROR_CODE)); | |||
} | |||
*/ | |||
FatalRecvError(); | |||
} | |||
@@ -446,14 +435,6 @@ namespace Jack | |||
PacketHeaderHToN(header, header); | |||
if (((tx_bytes = fSocket.Send(fTxBuffer, size, flags)) == SOCKET_ERROR) && fRunning) { | |||
/* | |||
net_error_t error = fSocket.GetError(); | |||
if (error == NET_CONN_ERROR) { | |||
FatalSendError(); | |||
} else { | |||
jack_error("Error in master send : %s", StrError(NET_ERROR_CODE)); | |||
} | |||
*/ | |||
FatalSendError(); | |||
} | |||
return tx_bytes; | |||
@@ -466,6 +447,8 @@ namespace Jack | |||
int JackNetMasterInterface::SyncSend() | |||
{ | |||
SetRcvTimeOut(); | |||
fTxHeader.fCycle++; | |||
fTxHeader.fSubCycle = 0; | |||
fTxHeader.fDataType = 's'; | |||
@@ -490,17 +473,6 @@ namespace Jack | |||
int rx_bytes = 0; | |||
packet_header_t* rx_head = reinterpret_cast<packet_header_t*>(fRxBuffer); | |||
/* | |||
int rx_bytes = Recv(fParams.fMtu, MSG_PEEK); | |||
if ((rx_bytes == 0) || (rx_bytes == SOCKET_ERROR)) { | |||
// 0 bytes considered an error (lost connection) | |||
return SOCKET_ERROR; | |||
} | |||
fCurrentCycleOffset = fTxHeader.fCycle - rx_head->fCycle; | |||
*/ | |||
// receive sync (launch the cycle) | |||
do { | |||
rx_bytes = Recv(fParams.fMtu, MSG_PEEK); | |||
@@ -532,7 +504,7 @@ namespace Jack | |||
while (!fRxHeader.fIsLastPckt) { | |||
// how much data is queued on the rx buffer ? | |||
rx_bytes = Recv(fParams.fMtu, MSG_PEEK); | |||
// error here, problem with recv, just skip the cycle (return -1) | |||
if (rx_bytes == SOCKET_ERROR) { | |||
return rx_bytes; | |||
@@ -556,7 +528,7 @@ namespace Jack | |||
} | |||
} | |||
} | |||
return rx_bytes; | |||
} | |||
@@ -608,6 +580,17 @@ namespace Jack | |||
uint JackNetSlaveInterface::fSlaveCounter = 0; | |||
void JackNetSlaveInterface::InitAPI() | |||
{ | |||
// open Socket API with the first slave | |||
if (fSlaveCounter++ == 0) { | |||
if (SocketAPIInit() < 0) { | |||
jack_error("Can't init Socket API, exiting..."); | |||
throw std::bad_alloc(); | |||
} | |||
} | |||
} | |||
bool JackNetSlaveInterface::Init() | |||
{ | |||
jack_log("JackNetSlaveInterface::Init()"); | |||
@@ -674,8 +657,9 @@ namespace Jack | |||
// then tell the master we are ready | |||
jack_info("Initializing connection with %s...", fParams.fMasterNetName); | |||
status = SendStartToMaster(); | |||
if (status == NET_ERROR) | |||
if (status == NET_ERROR) { | |||
return false; | |||
} | |||
} | |||
while (status != NET_ROLLING); | |||
@@ -705,13 +689,15 @@ namespace Jack | |||
} | |||
} | |||
// timeout on receive | |||
if (fSocket.SetTimeOut(SLAVE_INIT_TIMEOUT) == SOCKET_ERROR) | |||
jack_error("Can't set timeout : %s", StrError(NET_ERROR_CODE)); | |||
// timeout on receive (for init) | |||
if (fSocket.SetTimeOut(SLAVE_INIT_TIMEOUT) == SOCKET_ERROR) { | |||
jack_error("Can't set init timeout : %s", StrError(NET_ERROR_CODE)); | |||
} | |||
// disable local loop | |||
if (fSocket.SetLocalLoop() == SOCKET_ERROR) | |||
if (fSocket.SetLocalLoop() == SOCKET_ERROR) { | |||
jack_error("Can't disable multicast loop : %s", StrError(NET_ERROR_CODE)); | |||
} | |||
// send 'AVAILABLE' until 'SLAVE_SETUP' received | |||
jack_info("Waiting for a master..."); | |||
@@ -720,8 +706,9 @@ namespace Jack | |||
session_params_t net_params; | |||
memset(&net_params, 0, sizeof(session_params_t)); | |||
SessionParamsHToN(&fParams, &net_params); | |||
if (fSocket.SendTo(&net_params, sizeof(session_params_t), 0, fMulticastIP) == SOCKET_ERROR) | |||
if (fSocket.SendTo(&net_params, sizeof(session_params_t), 0, fMulticastIP) == SOCKET_ERROR) { | |||
jack_error("Error in data send : %s", StrError(NET_ERROR_CODE)); | |||
} | |||
// filter incoming packets : don't exit while no error is detected | |||
memset(&net_params, 0, sizeof(session_params_t)); | |||
@@ -833,20 +820,9 @@ namespace Jack | |||
int JackNetSlaveInterface::Recv(size_t size, int flags) | |||
{ | |||
int rx_bytes = fSocket.Recv(fRxBuffer, size, flags); | |||
// handle errors | |||
if (rx_bytes == SOCKET_ERROR) { | |||
/* | |||
net_error_t error = fSocket.GetError(); | |||
// no data isn't really an error in realtime processing, so just return 0 | |||
if (error == NET_NO_DATA) { | |||
jack_error("No data, is the master still running ?"); | |||
// if a network error occurs, this exception will restart the driver | |||
} else if (error == NET_CONN_ERROR) { | |||
FatalRecvError(); | |||
} else { | |||
jack_error("Fatal error in slave receive : %s", StrError(NET_ERROR_CODE)); | |||
} | |||
*/ | |||
FatalRecvError(); | |||
} | |||
@@ -863,17 +839,9 @@ namespace Jack | |||
// handle errors | |||
if (tx_bytes == SOCKET_ERROR) { | |||
/* | |||
net_error_t error = fSocket.GetError(); | |||
// if a network error occurs, this exception will restart the driver | |||
if (error == NET_CONN_ERROR) { | |||
FatalSendError(); | |||
} else { | |||
jack_error("Fatal error in slave send : %s", StrError(NET_ERROR_CODE)); | |||
} | |||
*/ | |||
FatalSendError(); | |||
} | |||
return tx_bytes; | |||
} | |||
@@ -881,7 +849,7 @@ namespace Jack | |||
{ | |||
int rx_bytes = 0; | |||
packet_header_t* rx_head = reinterpret_cast<packet_header_t*>(fRxBuffer); | |||
// receive sync (launch the cycle) | |||
do { | |||
rx_bytes = Recv(fParams.fMtu, 0); | |||
@@ -893,6 +861,8 @@ namespace Jack | |||
while ((strcmp(rx_head->fPacketType, "header") != 0) && (rx_head->fDataType != 's')); | |||
fRxHeader.fIsLastPckt = rx_head->fIsLastPckt; | |||
SetRcvTimeOut(); | |||
return rx_bytes; | |||
} | |||
@@ -21,6 +21,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
#define __JackNetInterface__ | |||
#include "JackNetTool.h" | |||
#include <limits.h> | |||
namespace Jack | |||
{ | |||
@@ -31,9 +32,10 @@ namespace Jack | |||
#define SLAVE_SETUP_RETRY 5 | |||
#define MANAGER_INIT_TIMEOUT 2000000 // in usec | |||
#define MASTER_INIT_TIMEOUT 1000000 // in usec | |||
#define SLAVE_INIT_TIMEOUT 1000000 // in usec | |||
#define MANAGER_INIT_TIMEOUT 2000000 // in usec | |||
#define MASTER_INIT_TIMEOUT 1000000 * 10 // in usec | |||
#define SLAVE_INIT_TIMEOUT 1000000 * 10 // in usec | |||
#define PACKET_TIMEOUT 500000 // in usec | |||
#define NETWORK_MAX_LATENCY 20 | |||
@@ -45,6 +47,8 @@ namespace Jack | |||
{ | |||
protected: | |||
bool fSetTimeOut; | |||
void Initialize(); | |||
@@ -106,6 +110,8 @@ namespace Jack | |||
int AudioRecv(packet_header_t* rx_head, NetAudioBuffer* buffer); | |||
int FinishRecv(NetAudioBuffer* buffer); | |||
void SetRcvTimeOut(); | |||
NetAudioBuffer* AudioBufferFactory(int nports, char* buffer); | |||
@@ -129,13 +135,10 @@ namespace Jack | |||
protected: | |||
bool fRunning; | |||
int fCurrentCycleOffset; | |||
int fMaxCycleOffset; | |||
int fLastfCycleOffset; | |||
bool Init(); | |||
int SetRxTimeout(); | |||
bool SetParams(); | |||
void Exit(); | |||
@@ -160,10 +163,10 @@ namespace Jack | |||
public: | |||
JackNetMasterInterface() : JackNetInterface(), fRunning(false), fCurrentCycleOffset(0), fMaxCycleOffset(0), fLastfCycleOffset(0) | |||
JackNetMasterInterface() : JackNetInterface(), fRunning(false), fCurrentCycleOffset(0), fMaxCycleOffset(0) | |||
{} | |||
JackNetMasterInterface(session_params_t& params, JackNetSocket& socket, const char* multicast_ip) | |||
: JackNetInterface(params, socket, multicast_ip) | |||
: JackNetInterface(params, socket, multicast_ip), fRunning(false), fCurrentCycleOffset(0), fMaxCycleOffset(0) | |||
{} | |||
virtual~JackNetMasterInterface() | |||
@@ -206,16 +209,7 @@ namespace Jack | |||
void FatalRecvError(); | |||
void FatalSendError(); | |||
void InitAPI() | |||
{ | |||
// open Socket API with the first slave | |||
if (fSlaveCounter++ == 0) { | |||
if (SocketAPIInit() < 0) { | |||
jack_error("Can't init Socket API, exiting..."); | |||
throw std::bad_alloc(); | |||
} | |||
} | |||
} | |||
void InitAPI(); | |||
public: | |||
@@ -33,8 +33,8 @@ namespace Jack | |||
jack_log("JackNetMaster::JackNetMaster"); | |||
//settings | |||
fClientName = const_cast<char*>(fParams.fName); | |||
fJackClient = NULL; | |||
fName = const_cast<char*>(fParams.fName); | |||
fClient = NULL; | |||
fSendTransportData.fState = -1; | |||
fReturnTransportData.fState = -1; | |||
fLastTransportState = -1; | |||
@@ -91,10 +91,10 @@ namespace Jack | |||
{ | |||
jack_log("JackNetMaster::~JackNetMaster ID = %u", fParams.fID); | |||
if (fJackClient) { | |||
jack_deactivate(fJackClient); | |||
if (fClient) { | |||
jack_deactivate(fClient); | |||
FreePorts(); | |||
jack_client_close(fJackClient); | |||
jack_client_close(fClient); | |||
} | |||
delete[] fAudioCapturePorts; | |||
delete[] fAudioPlaybackPorts; | |||
@@ -122,18 +122,24 @@ namespace Jack | |||
//jack client and process | |||
jack_status_t status; | |||
if ((fJackClient = jack_client_open(fClientName, JackNullOption, &status, NULL)) == NULL) { | |||
if ((fClient = jack_client_open(fName, JackNullOption, &status, NULL)) == NULL) { | |||
jack_error("Can't open a new JACK client"); | |||
return false; | |||
} | |||
if (jack_set_process_callback(fJackClient, SetProcess, this) < 0) { | |||
if (jack_set_process_callback(fClient, SetProcess, this) < 0) { | |||
goto fail; | |||
} | |||
if (jack_set_buffer_size_callback(fJackClient, SetBufferSize, this) < 0) { | |||
if (jack_set_buffer_size_callback(fClient, SetBufferSize, this) < 0) { | |||
goto fail; | |||
} | |||
/* | |||
if (jack_set_port_connect_callback(fClient, SetConnectCallback, this) < 0) { | |||
goto fail; | |||
} | |||
*/ | |||
if (AllocPorts() != 0) { | |||
jack_error("Can't allocate JACK ports"); | |||
@@ -144,7 +150,7 @@ namespace Jack | |||
fRunning = true; | |||
//finally activate jack client | |||
if (jack_activate(fJackClient) != 0) { | |||
if (jack_activate(fClient) != 0) { | |||
jack_error("Can't activate JACK client"); | |||
goto fail; | |||
} | |||
@@ -157,8 +163,8 @@ namespace Jack | |||
fail: | |||
FreePorts(); | |||
jack_client_close(fJackClient); | |||
fJackClient = NULL; | |||
jack_client_close(fClient); | |||
fClient = NULL; | |||
return false; | |||
} | |||
@@ -167,7 +173,7 @@ namespace Jack | |||
{ | |||
int i; | |||
char name[24]; | |||
jack_nframes_t port_latency = jack_get_buffer_size(fJackClient); | |||
jack_nframes_t port_latency = jack_get_buffer_size(fClient); | |||
jack_latency_range_t range; | |||
jack_log("JackNetMaster::AllocPorts"); | |||
@@ -175,7 +181,7 @@ namespace Jack | |||
//audio | |||
for (i = 0; i < fParams.fSendAudioChannels; i++) { | |||
snprintf(name, sizeof(name), "to_slave_%d", i+1); | |||
if ((fAudioCapturePorts[i] = jack_port_register(fJackClient, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0)) == NULL) | |||
if ((fAudioCapturePorts[i] = jack_port_register(fClient, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0)) == NULL) | |||
return -1; | |||
//port latency | |||
range.min = range.max = 0; | |||
@@ -184,7 +190,7 @@ namespace Jack | |||
for (i = 0; i < fParams.fReturnAudioChannels; i++) { | |||
snprintf(name, sizeof(name), "from_slave_%d", i+1); | |||
if ((fAudioPlaybackPorts[i] = jack_port_register(fJackClient, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput | JackPortIsTerminal, 0)) == NULL) | |||
if ((fAudioPlaybackPorts[i] = jack_port_register(fClient, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput | JackPortIsTerminal, 0)) == NULL) | |||
return -1; | |||
//port latency | |||
range.min = range.max = fParams.fNetworkLatency * port_latency + (fParams.fSlaveSyncMode) ? 0 : port_latency; | |||
@@ -194,7 +200,7 @@ namespace Jack | |||
//midi | |||
for (i = 0; i < fParams.fSendMidiChannels; i++) { | |||
snprintf(name, sizeof(name), "midi_to_slave_%d", i+1); | |||
if ((fMidiCapturePorts[i] = jack_port_register(fJackClient, name, JACK_DEFAULT_MIDI_TYPE, JackPortIsInput | JackPortIsTerminal, 0)) == NULL) | |||
if ((fMidiCapturePorts[i] = jack_port_register(fClient, name, JACK_DEFAULT_MIDI_TYPE, JackPortIsInput | JackPortIsTerminal, 0)) == NULL) | |||
return -1; | |||
//port latency | |||
range.min = range.max = 0; | |||
@@ -203,7 +209,7 @@ namespace Jack | |||
for (i = 0; i < fParams.fReturnMidiChannels; i++) { | |||
snprintf(name, sizeof(name), "midi_from_slave_%d", i+1); | |||
if ((fMidiPlaybackPorts[i] = jack_port_register(fJackClient, name, JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput | JackPortIsTerminal, 0)) == NULL) | |||
if ((fMidiPlaybackPorts[i] = jack_port_register(fClient, name, JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput | JackPortIsTerminal, 0)) == NULL) | |||
return -1; | |||
//port latency | |||
range.min = range.max = fParams.fNetworkLatency * port_latency + (fParams.fSlaveSyncMode) ? 0 : port_latency; | |||
@@ -216,18 +222,18 @@ namespace Jack | |||
{ | |||
const char **ports; | |||
ports = jack_get_ports(fJackClient, NULL, NULL, JackPortIsPhysical | JackPortIsOutput); | |||
ports = jack_get_ports(fClient, NULL, NULL, JackPortIsPhysical | JackPortIsOutput); | |||
if (ports != NULL) { | |||
for (int i = 0; i < fParams.fSendAudioChannels && ports[i]; i++) { | |||
jack_connect(fJackClient, ports[i], jack_port_name(fAudioCapturePorts[i])); | |||
jack_connect(fClient, ports[i], jack_port_name(fAudioCapturePorts[i])); | |||
} | |||
free(ports); | |||
} | |||
ports = jack_get_ports(fJackClient, NULL, NULL, JackPortIsPhysical | JackPortIsInput); | |||
ports = jack_get_ports(fClient, NULL, NULL, JackPortIsPhysical | JackPortIsInput); | |||
if (ports != NULL) { | |||
for (int i = 0; i < fParams.fReturnAudioChannels && ports[i]; i++) { | |||
jack_connect(fJackClient, jack_port_name(fAudioPlaybackPorts[i]), ports[i]); | |||
jack_connect(fClient, jack_port_name(fAudioPlaybackPorts[i]), ports[i]); | |||
} | |||
free(ports); | |||
} | |||
@@ -240,22 +246,22 @@ namespace Jack | |||
int port_index; | |||
for (port_index = 0; port_index < fParams.fSendAudioChannels; port_index++) { | |||
if (fAudioCapturePorts[port_index]) { | |||
jack_port_unregister(fJackClient, fAudioCapturePorts[port_index]); | |||
jack_port_unregister(fClient, fAudioCapturePorts[port_index]); | |||
} | |||
} | |||
for (port_index = 0; port_index < fParams.fReturnAudioChannels; port_index++) { | |||
if (fAudioPlaybackPorts[port_index]) { | |||
jack_port_unregister(fJackClient, fAudioPlaybackPorts[port_index]); | |||
jack_port_unregister(fClient, fAudioPlaybackPorts[port_index]); | |||
} | |||
} | |||
for (port_index = 0; port_index < fParams.fSendMidiChannels; port_index++) { | |||
if (fMidiCapturePorts[port_index]) { | |||
jack_port_unregister(fJackClient, fMidiCapturePorts[port_index]); | |||
jack_port_unregister(fClient, fMidiCapturePorts[port_index]); | |||
} | |||
} | |||
for (port_index = 0; port_index < fParams.fReturnMidiChannels; port_index++) { | |||
if (fMidiPlaybackPorts[port_index]) { | |||
jack_port_unregister(fJackClient, fMidiPlaybackPorts[port_index]); | |||
jack_port_unregister(fClient, fMidiPlaybackPorts[port_index]); | |||
} | |||
} | |||
} | |||
@@ -268,7 +274,7 @@ namespace Jack | |||
fSendTransportData.fTimebaseMaster = NO_CHANGE; | |||
//update state and position | |||
fSendTransportData.fState = static_cast<uint>(jack_transport_query(fJackClient, &fSendTransportData.fPosition)); | |||
fSendTransportData.fState = static_cast<uint>(jack_transport_query(fClient, &fSendTransportData.fPosition)); | |||
//is it a new state ? | |||
fSendTransportData.fNewState = ((fSendTransportData.fState != fLastTransportState) && (fSendTransportData.fState != fReturnTransportData.fState)); | |||
@@ -287,7 +293,7 @@ namespace Jack | |||
switch (fReturnTransportData.fTimebaseMaster) | |||
{ | |||
case RELEASE_TIMEBASEMASTER : | |||
timebase = jack_release_timebase(fJackClient); | |||
timebase = jack_release_timebase(fClient); | |||
if (timebase < 0) { | |||
jack_error("Can't release timebase master"); | |||
} else { | |||
@@ -296,7 +302,7 @@ namespace Jack | |||
break; | |||
case TIMEBASEMASTER : | |||
timebase = jack_set_timebase_callback(fJackClient, 0, SetTimebaseCallback, this); | |||
timebase = jack_set_timebase_callback(fClient, 0, SetTimebaseCallback, this); | |||
if (timebase < 0) { | |||
jack_error("Can't set a new timebase master"); | |||
} else { | |||
@@ -305,7 +311,7 @@ namespace Jack | |||
break; | |||
case CONDITIONAL_TIMEBASEMASTER : | |||
timebase = jack_set_timebase_callback(fJackClient, 1, SetTimebaseCallback, this); | |||
timebase = jack_set_timebase_callback(fClient, 1, SetTimebaseCallback, this); | |||
if (timebase != EBUSY) { | |||
if (timebase < 0) | |||
jack_error("Can't set a new timebase master"); | |||
@@ -317,19 +323,19 @@ namespace Jack | |||
} | |||
//is the slave in a new transport state and is this state different from master's ? | |||
if (fReturnTransportData.fNewState && (fReturnTransportData.fState != jack_transport_query(fJackClient, NULL))) { | |||
if (fReturnTransportData.fNewState && (fReturnTransportData.fState != jack_transport_query(fClient, NULL))) { | |||
switch (fReturnTransportData.fState) | |||
{ | |||
case JackTransportStopped : | |||
jack_transport_stop(fJackClient); | |||
jack_transport_stop(fClient); | |||
jack_info("'%s' stops transport", fParams.fName); | |||
break; | |||
case JackTransportStarting : | |||
if (jack_transport_reposition(fJackClient, &fReturnTransportData.fPosition) == EINVAL) | |||
if (jack_transport_reposition(fClient, &fReturnTransportData.fPosition) == EINVAL) | |||
jack_error("Can't set new position"); | |||
jack_transport_start(fJackClient); | |||
jack_transport_start(fClient); | |||
jack_info("'%s' starts transport frame = %d", fParams.fName, fReturnTransportData.fPosition.frame); | |||
break; | |||
@@ -387,11 +393,22 @@ namespace Jack | |||
return 0; | |||
} | |||
} | |||
void JackNetMaster::SetConnectCallback(jack_port_id_t a, jack_port_id_t b, int connect, void* arg) | |||
{ | |||
static_cast<JackNetMaster*>(arg)->ConnectCallback(a, b, connect); | |||
} | |||
void JackNetMaster::ConnectCallback(jack_port_id_t a, jack_port_id_t b, int connect) | |||
{ | |||
jack_info("JackNetMaster::ConnectCallback a = %d b = %d connect = %d", a, b, connect); | |||
if (connect) { | |||
jack_connect(fClient, jack_port_name(jack_port_by_id(fClient, a)), "system:playback_1"); | |||
} | |||
} | |||
int JackNetMaster::Process() | |||
{ | |||
int res; | |||
if (!fRunning) { | |||
return 0; | |||
} | |||
@@ -474,35 +491,15 @@ namespace Jack | |||
#endif | |||
} else { | |||
jack_error("Connection is not synched, skip cycle..."); | |||
jack_info("Connection is not synched, skip cycle..."); | |||
} | |||
//receive sync | |||
res = SyncRecv(); | |||
int res = SyncRecv(); | |||
if ((res == 0) || (res == SOCKET_ERROR)) { | |||
return res; | |||
} | |||
/* | |||
switch (SyncRecv()) { | |||
case 0: | |||
jack_error("Connection is not yet synched, skip cycle..."); | |||
return 0; | |||
case SOCKET_ERROR: | |||
jack_error("Connection is lost, quit master..."); | |||
//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(); | |||
break; | |||
default: | |||
break; | |||
} | |||
*/ | |||
#ifdef JACK_MONITOR | |||
fNetTimeMon->Add((((float)(GetMicroSeconds() - begin_time)) / (float) fPeriodUsecs) * 100.f); | |||
#endif | |||
@@ -519,26 +516,6 @@ namespace Jack | |||
JackServerGlobals::fInstance->GetEngine()->NotifyXRun(GetMicroSeconds(), 0); | |||
} | |||
/* | |||
switch (DataRecv()) { | |||
case 0: | |||
jack_error("Connection is not yet synched, skip cycle..."); | |||
return 0; | |||
case SOCKET_ERROR: | |||
jack_error("Connection is lost, quit master..."); | |||
//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(); | |||
break; | |||
default: | |||
break; | |||
} | |||
*/ | |||
#ifdef JACK_MONITOR | |||
fNetTimeMon->AddLast((((float)(GetMicroSeconds() - begin_time)) / (float) fPeriodUsecs) * 100.f); | |||
#endif | |||
@@ -551,15 +528,17 @@ namespace Jack | |||
{ | |||
jack_log("JackNetMasterManager::JackNetMasterManager"); | |||
fManagerClient = client; | |||
fManagerName = jack_get_client_name(fManagerClient); | |||
fClient = client; | |||
fName = jack_get_client_name(fClient); | |||
fGlobalID = 0; | |||
fRunning = true; | |||
fAutoConnect = false; | |||
const JSList* node; | |||
const jack_driver_param_t* param; | |||
jack_on_shutdown(fClient, SetShutDown, this); | |||
// Possibly use env variable | |||
const char* default_udp_port = getenv("JACK_NETJACK_PORT"); | |||
fSocket.SetPort((default_udp_port) ? atoi(default_udp_port) : DEFAULT_PORT); | |||
@@ -595,15 +574,15 @@ namespace Jack | |||
} | |||
//set sync callback | |||
jack_set_sync_callback(fManagerClient, SetSyncCallback, this); | |||
jack_set_sync_callback(fClient, SetSyncCallback, this); | |||
//activate the client (for sync callback) | |||
if (jack_activate(fManagerClient) != 0) { | |||
if (jack_activate(fClient) != 0) { | |||
jack_error("Can't activate the NetManager client, transport disabled"); | |||
} | |||
//launch the manager thread | |||
if (jack_client_create_thread(fManagerClient, &fManagerThread, 0, 0, NetManagerThread, this)) { | |||
if (jack_client_create_thread(fClient, &fThread, 0, 0, NetManagerThread, this)) { | |||
jack_error("Can't create the NetManager control thread"); | |||
} | |||
} | |||
@@ -611,15 +590,7 @@ namespace Jack | |||
JackNetMasterManager::~JackNetMasterManager() | |||
{ | |||
jack_log("JackNetMasterManager::~JackNetMasterManager"); | |||
jack_info("Exiting NetManager..."); | |||
fRunning = false; | |||
jack_client_kill_thread(fManagerClient, fManagerThread); | |||
master_list_t::iterator it; | |||
for (it = fMasterList.begin(); it != fMasterList.end(); it++) { | |||
delete(*it); | |||
} | |||
fSocket.Close(); | |||
SocketAPIEnd(); | |||
ShutDown(); | |||
} | |||
int JackNetMasterManager::CountIO(int flags) | |||
@@ -628,10 +599,10 @@ namespace Jack | |||
int count = 0; | |||
jack_port_t* port; | |||
ports = jack_get_ports(fManagerClient, NULL, NULL, flags); | |||
ports = jack_get_ports(fClient, NULL, NULL, flags); | |||
if (ports != NULL) { | |||
while (ports[count] | |||
&& (port = jack_port_by_name(fManagerClient, ports[count])) | |||
&& (port = jack_port_by_name(fClient, ports[count])) | |||
&& (strcmp(jack_port_type(port), JACK_DEFAULT_AUDIO_TYPE) == 0)) { | |||
count++; | |||
} | |||
@@ -639,6 +610,27 @@ namespace Jack | |||
} | |||
return count; | |||
} | |||
void JackNetMasterManager::SetShutDown(void* arg) | |||
{ | |||
static_cast<JackNetMasterManager*>(arg)->ShutDown(); | |||
} | |||
void JackNetMasterManager::ShutDown() | |||
{ | |||
jack_log("JackNetMasterManager::ShutDown"); | |||
if (fRunning) { | |||
jack_client_kill_thread(fClient, fThread); | |||
fRunning = false; | |||
} | |||
master_list_t::iterator it; | |||
for (it = fMasterList.begin(); it != fMasterList.end(); it++) { | |||
delete(*it); | |||
} | |||
fMasterList.clear(); | |||
fSocket.Close(); | |||
SocketAPIEnd(); | |||
} | |||
int JackNetMasterManager::SetSyncCallback(jack_transport_state_t state, jack_position_t* pos, void* arg) | |||
{ | |||
@@ -719,6 +711,7 @@ namespace Jack | |||
session_params_t net_params; | |||
rx_bytes = fSocket.CatchHost(&net_params, sizeof(session_params_t), 0); | |||
SessionParamsNToH(&net_params, &host_params); | |||
if ((rx_bytes == SOCKET_ERROR) && (fSocket.GetError() != NET_NO_DATA)) { | |||
jack_error("Error in receive : %s", StrError(NET_ERROR_CODE)); | |||
if (++attempt == 10) { | |||
@@ -728,7 +721,7 @@ namespace Jack | |||
} | |||
if (rx_bytes == sizeof(session_params_t)) { | |||
switch (GetPacketType (&host_params)) | |||
switch (GetPacketType(&host_params)) | |||
{ | |||
case SLAVE_AVAILABLE: | |||
if ((net_master = InitMaster(host_params))) { | |||
@@ -764,8 +757,8 @@ namespace Jack | |||
//settings | |||
fSocket.GetName(params.fMasterNetName); | |||
params.fID = ++fGlobalID; | |||
params.fSampleRate = jack_get_sample_rate(fManagerClient); | |||
params.fPeriodSize = jack_get_buffer_size(fManagerClient); | |||
params.fSampleRate = jack_get_sample_rate(fClient); | |||
params.fPeriodSize = jack_get_buffer_size(fClient); | |||
if (params.fSendAudioChannels == -1) { | |||
params.fSendAudioChannels = CountIO(JackPortIsPhysical | JackPortIsOutput); | |||
@@ -875,7 +868,7 @@ extern "C" | |||
SERVER_EXPORT void jack_finish(void* arg) | |||
{ | |||
if (master_manager) { | |||
jack_log ("Unloading Master Manager"); | |||
jack_log("Unloading Master Manager"); | |||
delete master_manager; | |||
master_manager = NULL; | |||
} | |||
@@ -39,14 +39,15 @@ 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); | |||
static void SetConnectCallback(jack_port_id_t a, jack_port_id_t b, int connect, void* arg); | |||
//jack client | |||
jack_client_t* fJackClient; | |||
const char* fClientName; | |||
jack_client_t* fClient; | |||
const char* fName; | |||
//jack ports | |||
jack_port_t** fAudioCapturePorts; | |||
@@ -74,6 +75,7 @@ namespace Jack | |||
int Process(); | |||
void TimebaseCallback(jack_position_t* pos); | |||
void ConnectPorts(); | |||
void ConnectCallback(jack_port_id_t a, jack_port_id_t b, int connect); | |||
public: | |||
@@ -96,14 +98,15 @@ namespace Jack | |||
private: | |||
static void SetShutDown(void* arg); | |||
static int SetSyncCallback(jack_transport_state_t state, jack_position_t* pos, void* arg); | |||
static void* NetManagerThread(void* arg); | |||
jack_client_t* fManagerClient; | |||
const char* fManagerName; | |||
jack_client_t* fClient; | |||
const char* fName; | |||
char fMulticastIP[32]; | |||
JackNetSocket fSocket; | |||
jack_native_thread_t fManagerThread; | |||
jack_native_thread_t fThread; | |||
master_list_t fMasterList; | |||
uint32_t fGlobalID; | |||
bool fRunning; | |||
@@ -115,6 +118,7 @@ namespace Jack | |||
int KillMaster(session_params_t* params); | |||
int SyncCallback(jack_transport_state_t state, jack_position_t* pos); | |||
int CountIO(int flags); | |||
void ShutDown(); | |||
public: | |||
@@ -56,7 +56,7 @@ JackNetOneDriver::JackNetOneDriver(const char* name, const char* alias, JackLock | |||
#ifdef WIN32 | |||
WSADATA wsa; | |||
int rc = WSAStartup(MAKEWORD(2, 0), &wsa); | |||
WSAStartup(MAKEWORD(2, 0), &wsa); | |||
#endif | |||
netjack_init(& (this->netj), | |||
@@ -753,6 +753,7 @@ JackNetOneDriver::render_jack_ports_to_payload (int bitdepth, JSList *playback_p | |||
extern "C" | |||
{ | |||
#endif | |||
SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor () | |||
{ | |||
jack_driver_desc_t * desc; | |||
@@ -20,7 +20,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
#ifndef __JackNetSocket__ | |||
#define __JackNetSocket__ | |||
#include "JackError.h" | |||
#include "JackCompilerDeps.h" | |||
#include <cstdlib> | |||
#include <cstdio> | |||
#include <iostream> | |||
@@ -29,7 +30,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
namespace Jack | |||
{ | |||
//get host name********************************* | |||
SERVER_EXPORT int GetHostName ( char * name, int size ); | |||
SERVER_EXPORT int GetHostName(char * name, int size); | |||
//net errors *********************************** | |||
enum _net_error | |||
@@ -18,6 +18,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
*/ | |||
#include "JackNetTool.h" | |||
#include "JackError.h" | |||
#ifdef __APPLE__ | |||
@@ -274,7 +275,7 @@ namespace Jack | |||
*active_port_address = htonl(port_index); | |||
active_port_address++; | |||
active_ports++; | |||
assert(active_ports < 256); | |||
assert(active_ports < 256); | |||
} | |||
} | |||
@@ -306,7 +307,6 @@ namespace Jack | |||
// Count active ports | |||
int active_ports = 0; | |||
for (int port_index = 0; port_index < fNPorts; port_index++) { | |||
if (fPortBuffer[port_index]) { | |||
active_ports++; | |||
} | |||
@@ -627,7 +627,7 @@ namespace Jack | |||
int NetCeltAudioBuffer::RenderFromJackPorts() | |||
{ | |||
float buffer[fPeriodSize]; | |||
float buffer[BUFFER_SIZE_MAX]; | |||
for (int port_index = 0; port_index < fNPorts; port_index++) { | |||
if (fPortBuffer[port_index]) { | |||
@@ -49,6 +49,8 @@ bool JackPort::Allocate(int refnum, const char* port_name, const char* port_type | |||
fPlaybackLatency.min = fPlaybackLatency.max = 0; | |||
fCaptureLatency.min = fCaptureLatency.max = 0; | |||
fTied = NO_PORT; | |||
fAlias1[0] = '\0'; | |||
fAlias2[0] = '\0'; | |||
// DB: At this point we do not know current buffer size in frames, | |||
// but every time buffer will be returned to any user, | |||
// it will be called with either ClearBuffer or MixBuffers | |||
@@ -58,7 +58,7 @@ class SERVER_EXPORT JackPort | |||
bool fInUse; | |||
jack_port_id_t fTied; // Locally tied source port | |||
jack_default_audio_sample_t fBuffer[BUFFER_SIZE_MAX + 4]; | |||
jack_default_audio_sample_t fBuffer[BUFFER_SIZE_MAX + 8]; | |||
bool IsUsed() const | |||
{ | |||
@@ -108,7 +108,7 @@ class SERVER_EXPORT JackPort | |||
// Since we are in shared memory, the resulting pointer cannot be cached, so align it here... | |||
jack_default_audio_sample_t* GetBuffer() | |||
{ | |||
return (jack_default_audio_sample_t*)((uintptr_t)fBuffer & ~15L) + 4; | |||
return (jack_default_audio_sample_t*)((uintptr_t)fBuffer & ~31L) + 8; | |||
} | |||
int GetRefNum() const; | |||
@@ -0,0 +1,351 @@ | |||
/* | |||
Copyright (C) 2012 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. | |||
*/ | |||
#include "JackRequestDecoder.h" | |||
#include "JackServer.h" | |||
#include "JackLockedEngine.h" | |||
#include "JackChannel.h" | |||
#include <assert.h> | |||
#include <signal.h> | |||
using namespace std; | |||
namespace Jack | |||
{ | |||
#define CheckRead(req, socket) { if (req.Read(socket) < 0) { jack_error("CheckRead error"); return -1; } } | |||
#define CheckWriteName(error, socket) { if (res.Write(socket) < 0) { jack_error("%s write error name = %s", error, req.fName); } } | |||
#define CheckWriteRefNum(error, socket) { if (res.Write(socket) < 0) { jack_error("%s write error ref = %d", error, req.fRefNum); } } | |||
#define CheckWrite(error, socket) { if (res.Write(socket) < 0) { jack_error("%s write error", error); } } | |||
JackRequestDecoder::JackRequestDecoder(JackServer* server, JackClientHandlerInterface* handler) | |||
:fServer(server), fHandler(handler) | |||
{} | |||
JackRequestDecoder::~JackRequestDecoder() | |||
{} | |||
int JackRequestDecoder::HandleRequest(detail::JackChannelTransactionInterface* socket, int type_aux) | |||
{ | |||
JackRequest::RequestType type = (JackRequest::RequestType)type_aux; | |||
// Read data | |||
switch (type) { | |||
case JackRequest::kClientCheck: { | |||
jack_log("JackRequest::ClientCheck"); | |||
JackClientCheckRequest req; | |||
JackClientCheckResult res; | |||
CheckRead(req, socket); | |||
res.fResult = fServer->GetEngine()->ClientCheck(req.fName, req.fUUID, res.fName, req.fProtocol, req.fOptions, &res.fStatus); | |||
CheckWriteName("JackRequest::ClientCheck", socket); | |||
// Atomic ClientCheck followed by ClientOpen on same socket | |||
if (req.fOpen) { | |||
JackRequest header; | |||
header.Read(socket); | |||
return HandleRequest(socket, header.fType); | |||
} | |||
break; | |||
} | |||
case JackRequest::kClientOpen: { | |||
jack_log("JackRequest::ClientOpen"); | |||
JackClientOpenRequest req; | |||
JackClientOpenResult res; | |||
CheckRead(req, socket); | |||
fHandler->ClientAdd(socket, &req, &res); | |||
CheckWriteName("JackRequest::ClientOpen", socket); | |||
break; | |||
} | |||
case JackRequest::kClientClose: { | |||
jack_log("JackRequest::ClientClose"); | |||
JackClientCloseRequest req; | |||
JackResult res; | |||
CheckRead(req, socket); | |||
res.fResult = fServer->GetEngine()->ClientExternalClose(req.fRefNum); | |||
CheckWriteRefNum("JackRequest::ClientClose", socket); | |||
fHandler->ClientRemove(socket, req.fRefNum); | |||
// Will cause the wrapping thread to stop | |||
return -1; | |||
} | |||
case JackRequest::kActivateClient: { | |||
JackActivateRequest req; | |||
JackResult res; | |||
jack_log("JackRequest::ActivateClient"); | |||
CheckRead(req, socket); | |||
res.fResult = fServer->GetEngine()->ClientActivate(req.fRefNum, req.fIsRealTime); | |||
CheckWriteRefNum("JackRequest::ActivateClient", socket); | |||
break; | |||
} | |||
case JackRequest::kDeactivateClient: { | |||
jack_log("JackRequest::DeactivateClient"); | |||
JackDeactivateRequest req; | |||
JackResult res; | |||
CheckRead(req, socket); | |||
res.fResult = fServer->GetEngine()->ClientDeactivate(req.fRefNum); | |||
CheckWriteRefNum("JackRequest::DeactivateClient", socket); | |||
break; | |||
} | |||
case JackRequest::kRegisterPort: { | |||
jack_log("JackRequest::RegisterPort"); | |||
JackPortRegisterRequest req; | |||
JackPortRegisterResult res; | |||
CheckRead(req, socket); | |||
res.fResult = fServer->GetEngine()->PortRegister(req.fRefNum, req.fName, req.fPortType, req.fFlags, req.fBufferSize, &res.fPortIndex); | |||
CheckWriteRefNum("JackRequest::RegisterPort", socket); | |||
break; | |||
} | |||
case JackRequest::kUnRegisterPort: { | |||
jack_log("JackRequest::UnRegisterPort"); | |||
JackPortUnRegisterRequest req; | |||
JackResult res; | |||
CheckRead(req, socket); | |||
res.fResult = fServer->GetEngine()->PortUnRegister(req.fRefNum, req.fPortIndex); | |||
CheckWriteRefNum("JackRequest::UnRegisterPort", socket); | |||
break; | |||
} | |||
case JackRequest::kConnectNamePorts: { | |||
jack_log("JackRequest::ConnectNamePorts"); | |||
JackPortConnectNameRequest req; | |||
JackResult res; | |||
CheckRead(req, socket); | |||
res.fResult = fServer->GetEngine()->PortConnect(req.fRefNum, req.fSrc, req.fDst); | |||
CheckWriteRefNum("JackRequest::ConnectNamePorts", socket); | |||
break; | |||
} | |||
case JackRequest::kDisconnectNamePorts: { | |||
jack_log("JackRequest::DisconnectNamePorts"); | |||
JackPortDisconnectNameRequest req; | |||
JackResult res; | |||
CheckRead(req, socket); | |||
res.fResult = fServer->GetEngine()->PortDisconnect(req.fRefNum, req.fSrc, req.fDst); | |||
CheckWriteRefNum("JackRequest::DisconnectNamePorts", socket); | |||
break; | |||
} | |||
case JackRequest::kConnectPorts: { | |||
jack_log("JackRequest::ConnectPorts"); | |||
JackPortConnectRequest req; | |||
JackResult res; | |||
CheckRead(req, socket); | |||
res.fResult = fServer->GetEngine()->PortConnect(req.fRefNum, req.fSrc, req.fDst); | |||
CheckWriteRefNum("JackRequest::ConnectPorts", socket); | |||
break; | |||
} | |||
case JackRequest::kDisconnectPorts: { | |||
jack_log("JackRequest::DisconnectPorts"); | |||
JackPortDisconnectRequest req; | |||
JackResult res; | |||
CheckRead(req, socket); | |||
res.fResult = fServer->GetEngine()->PortDisconnect(req.fRefNum, req.fSrc, req.fDst); | |||
CheckWriteRefNum("JackRequest::DisconnectPorts", socket); | |||
break; | |||
} | |||
case JackRequest::kPortRename: { | |||
jack_log("JackRequest::PortRename"); | |||
JackPortRenameRequest req; | |||
JackResult res; | |||
CheckRead(req, socket); | |||
res.fResult = fServer->GetEngine()->PortRename(req.fRefNum, req.fPort, req.fName); | |||
CheckWriteRefNum("JackRequest::PortRename", socket); | |||
break; | |||
} | |||
case JackRequest::kSetBufferSize: { | |||
jack_log("JackRequest::SetBufferSize"); | |||
JackSetBufferSizeRequest req; | |||
JackResult res; | |||
CheckRead(req, socket); | |||
res.fResult = fServer->SetBufferSize(req.fBufferSize); | |||
CheckWrite("JackRequest::SetBufferSize", socket); | |||
break; | |||
} | |||
case JackRequest::kSetFreeWheel: { | |||
jack_log("JackRequest::SetFreeWheel"); | |||
JackSetFreeWheelRequest req; | |||
JackResult res; | |||
CheckRead(req, socket); | |||
res.fResult = fServer->SetFreewheel(req.fOnOff); | |||
CheckWrite("JackRequest::SetFreeWheel", socket); | |||
break; | |||
} | |||
case JackRequest::kComputeTotalLatencies: { | |||
jack_log("JackRequest::ComputeTotalLatencies"); | |||
JackComputeTotalLatenciesRequest req; | |||
JackResult res; | |||
CheckRead(req, socket); | |||
res.fResult = fServer->GetEngine()->ComputeTotalLatencies(); | |||
CheckWrite("JackRequest::ComputeTotalLatencies", socket); | |||
break; | |||
} | |||
case JackRequest::kReleaseTimebase: { | |||
jack_log("JackRequest::ReleaseTimebase"); | |||
JackReleaseTimebaseRequest req; | |||
JackResult res; | |||
CheckRead(req, socket); | |||
res.fResult = fServer->ReleaseTimebase(req.fRefNum); | |||
CheckWriteRefNum("JackRequest::ReleaseTimebase", socket); | |||
break; | |||
} | |||
case JackRequest::kSetTimebaseCallback: { | |||
jack_log("JackRequest::SetTimebaseCallback"); | |||
JackSetTimebaseCallbackRequest req; | |||
JackResult res; | |||
CheckRead(req, socket); | |||
res.fResult = fServer->SetTimebaseCallback(req.fRefNum, req.fConditionnal); | |||
CheckWriteRefNum("JackRequest::SetTimebaseCallback", socket); | |||
break; | |||
} | |||
case JackRequest::kGetInternalClientName: { | |||
jack_log("JackRequest::GetInternalClientName"); | |||
JackGetInternalClientNameRequest req; | |||
JackGetInternalClientNameResult res; | |||
CheckRead(req, socket); | |||
res.fResult = fServer->GetEngine()->GetInternalClientName(req.fIntRefNum, res.fName); | |||
CheckWriteRefNum("JackRequest::GetInternalClientName", socket); | |||
break; | |||
} | |||
case JackRequest::kInternalClientHandle: { | |||
jack_log("JackRequest::InternalClientHandle"); | |||
JackInternalClientHandleRequest req; | |||
JackInternalClientHandleResult res; | |||
CheckRead(req, socket); | |||
res.fResult = fServer->GetEngine()->InternalClientHandle(req.fName, &res.fStatus, &res.fIntRefNum); | |||
CheckWriteRefNum("JackRequest::InternalClientHandle", socket); | |||
break; | |||
} | |||
case JackRequest::kInternalClientLoad: { | |||
jack_log("JackRequest::InternalClientLoad"); | |||
JackInternalClientLoadRequest req; | |||
JackInternalClientLoadResult res; | |||
CheckRead(req, socket); | |||
res.fResult = fServer->InternalClientLoad1(req.fName, req.fDllName, req.fLoadInitName, req.fOptions, &res.fIntRefNum, req.fUUID, &res.fStatus); | |||
CheckWriteName("JackRequest::InternalClientLoad", socket); | |||
break; | |||
} | |||
case JackRequest::kInternalClientUnload: { | |||
jack_log("JackRequest::InternalClientUnload"); | |||
JackInternalClientUnloadRequest req; | |||
JackInternalClientUnloadResult res; | |||
CheckRead(req, socket); | |||
res.fResult = fServer->GetEngine()->InternalClientUnload(req.fIntRefNum, &res.fStatus); | |||
CheckWriteRefNum("JackRequest::InternalClientUnload", socket); | |||
break; | |||
} | |||
case JackRequest::kNotification: { | |||
jack_log("JackRequest::Notification"); | |||
JackClientNotificationRequest req; | |||
CheckRead(req, socket); | |||
if (req.fNotify == kQUIT) { | |||
jack_log("JackRequest::Notification kQUIT"); | |||
throw JackQuitException(); | |||
} else { | |||
fServer->Notify(req.fRefNum, req.fNotify, req.fValue); | |||
} | |||
break; | |||
} | |||
case JackRequest::kSessionNotify: { | |||
jack_log("JackRequest::SessionNotify"); | |||
JackSessionNotifyRequest req; | |||
CheckRead(req, socket); | |||
fServer->GetEngine()->SessionNotify(req.fRefNum, req.fDst, req.fEventType, req.fPath, socket, NULL); | |||
break; | |||
} | |||
case JackRequest::kSessionReply: { | |||
jack_log("JackRequest::SessionReply"); | |||
JackSessionReplyRequest req; | |||
JackResult res; | |||
CheckRead(req, socket); | |||
res.fResult = fServer->GetEngine()->SessionReply(req.fRefNum); | |||
CheckWrite("JackRequest::SessionReply", socket); | |||
break; | |||
} | |||
case JackRequest::kGetClientByUUID: { | |||
jack_log("JackRequest::GetClientByUUID"); | |||
JackGetClientNameRequest req; | |||
JackClientNameResult res; | |||
CheckRead(req, socket); | |||
res.fResult = fServer->GetEngine()->GetClientNameForUUID(req.fUUID, res.fName); | |||
CheckWrite("JackRequest::GetClientByUUID", socket); | |||
break; | |||
} | |||
case JackRequest::kGetUUIDByClient: { | |||
jack_log("JackRequest::GetUUIDByClient"); | |||
JackGetUUIDRequest req; | |||
JackUUIDResult res; | |||
CheckRead(req, socket); | |||
res.fResult = fServer->GetEngine()->GetUUIDForClientName(req.fName, res.fUUID); | |||
CheckWrite("JackRequest::GetUUIDByClient", socket); | |||
break; | |||
} | |||
case JackRequest::kReserveClientName: { | |||
jack_log("JackRequest::ReserveClientName"); | |||
JackReserveNameRequest req; | |||
JackResult res; | |||
CheckRead(req, socket); | |||
res.fResult = fServer->GetEngine()->ReserveClientName(req.fName, req.fUUID); | |||
CheckWrite("JackRequest::ReserveClientName", socket); | |||
break; | |||
} | |||
case JackRequest::kClientHasSessionCallback: { | |||
jack_log("JackRequest::ClientHasSessionCallback"); | |||
JackClientHasSessionCallbackRequest req; | |||
JackResult res; | |||
CheckRead(req, socket); | |||
res.fResult = fServer->GetEngine()->ClientHasSessionCallback(req.fName); | |||
CheckWrite("JackRequest::ClientHasSessionCallback", socket); | |||
break; | |||
} | |||
default: | |||
jack_error("Unknown request %ld", type); | |||
return -1; | |||
} | |||
return 0; | |||
} | |||
} // end of namespace | |||
@@ -0,0 +1,63 @@ | |||
/* | |||
Copyright (C) 2012 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 __JackRequestDecoder__ | |||
#define __JackRequestDecoder__ | |||
#include "JackChannel.h" | |||
namespace Jack | |||
{ | |||
class JackServer; | |||
struct JackClientOpenRequest; | |||
struct JackClientOpenResult; | |||
struct JackClientHandlerInterface { | |||
virtual void ClientAdd(detail::JackChannelTransactionInterface* socket, JackClientOpenRequest* req, JackClientOpenResult* res) = 0; | |||
virtual void ClientRemove(detail::JackChannelTransactionInterface* socket, int refnum) = 0; | |||
virtual ~JackClientHandlerInterface() | |||
{} | |||
}; | |||
/*! | |||
\brief Request decoder | |||
*/ | |||
class JackRequestDecoder | |||
{ | |||
private: | |||
JackServer* fServer; | |||
JackClientHandlerInterface* fHandler; | |||
public: | |||
JackRequestDecoder(JackServer* server, JackClientHandlerInterface* handler); | |||
virtual ~JackRequestDecoder(); | |||
int HandleRequest(detail::JackChannelTransactionInterface* socket, int type); | |||
}; | |||
} // end of namespace | |||
#endif |
@@ -18,6 +18,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
*/ | |||
#include "JackResampler.h" | |||
#include "JackError.h" | |||
#include <stdio.h> | |||
namespace Jack | |||
@@ -22,7 +22,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
#include "ringbuffer.h" | |||
#include "types.h" | |||
#include "JackError.h" | |||
namespace Jack | |||
{ | |||
@@ -78,7 +78,9 @@ JackServer::~JackServer() | |||
int JackServer::Open(jack_driver_desc_t* driver_desc, JSList* driver_params) | |||
{ | |||
// TODO: move that in reworked JackServerGlobals::Init() | |||
JackMessageBuffer::Create(); | |||
if (!JackMessageBuffer::Create()) { | |||
jack_error("Cannot create message buffer"); | |||
} | |||
if ((fAudioDriver = fDriverInfo->Open(driver_desc, fEngine, GetSynchroTable(), driver_params)) == NULL) { | |||
jack_error("Cannot initialize driver"); | |||
@@ -140,6 +142,7 @@ int JackServer::Close() | |||
fEngine->Close(); | |||
// TODO: move that in reworked JackServerGlobals::Destroy() | |||
JackMessageBuffer::Destroy(); | |||
EndTime(); | |||
return 0; | |||
} | |||
@@ -188,6 +191,8 @@ int JackServer::Stop() | |||
{ | |||
jack_log("JackServer::Stop"); | |||
fChannel.Stop(); | |||
fEngine->ShutDown(); | |||
if (fFreewheel) { | |||
return fThreadedFreewheelDriver->Stop(); | |||
@@ -24,6 +24,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
#include "JackCompilerDeps.h" | |||
#include "driver_interface.h" | |||
#include "JackDriverLoader.h" | |||
#include "JackDriverInfo.h" | |||
#include "JackConnectionManager.h" | |||
#include "JackGlobals.h" | |||
#include "JackPlatformPlug.h" | |||
@@ -47,10 +47,6 @@ extern "C" | |||
using namespace Jack; | |||
static jack_client_t * jack_client_open_aux (const char *client_name, | |||
jack_options_t options, | |||
jack_status_t *status, va_list ap); | |||
jack_client_t* jack_client_new_aux(const char* client_name, jack_options_t options, jack_status_t* status) | |||
{ | |||
jack_varargs_t va; /* variable arguments */ | |||
@@ -155,9 +151,8 @@ jack_client_t* jack_client_open_aux(const char* client_name, jack_options_t opti | |||
SERVER_EXPORT jack_client_t* jack_client_open(const char* ext_client_name, jack_options_t options, jack_status_t* status, ...) | |||
{ | |||
#ifdef __CLIENTDEBUG__ | |||
JackGlobals::CheckContext("jack_client_open"); | |||
#endif | |||
try { | |||
assert(JackGlobals::fOpenMutex); | |||
JackGlobals::fOpenMutex->Lock(); | |||
@@ -178,9 +173,8 @@ SERVER_EXPORT jack_client_t* jack_client_open(const char* ext_client_name, jack_ | |||
SERVER_EXPORT int jack_client_close(jack_client_t* ext_client) | |||
{ | |||
#ifdef __CLIENTDEBUG__ | |||
JackGlobals::CheckContext("jack_client_close"); | |||
#endif | |||
assert(JackGlobals::fOpenMutex); | |||
JackGlobals::fOpenMutex->Lock(); | |||
int res = -1; | |||
@@ -33,11 +33,11 @@ | |||
namespace Jack | |||
{ | |||
SERVER_EXPORT void LockMemoryImp(void* ptr, size_t size); | |||
SERVER_EXPORT void InitLockMemoryImp(void* ptr, size_t size); | |||
SERVER_EXPORT void UnlockMemoryImp(void* ptr, size_t size); | |||
SERVER_EXPORT void LockAllMemory(); | |||
SERVER_EXPORT void UnlockAllMemory(); | |||
void LockMemoryImp(void* ptr, size_t size); | |||
void InitLockMemoryImp(void* ptr, size_t size); | |||
void UnlockMemoryImp(void* ptr, size_t size); | |||
void LockAllMemory(); | |||
void UnlockAllMemory(); | |||
class JackMem | |||
{ | |||
@@ -30,10 +30,12 @@ extern "C" | |||
#endif | |||
SERVER_EXPORT void InitTime(); | |||
SERVER_EXPORT void EndTime(); | |||
SERVER_EXPORT jack_time_t GetMicroSeconds(void); | |||
SERVER_EXPORT void JackSleep(long usec); | |||
SERVER_EXPORT void SetClockSource(jack_timer_type_t source); | |||
SERVER_EXPORT const char* ClockSourceName(jack_timer_type_t source); | |||
void SetClockSource(jack_timer_type_t source); | |||
const char* ClockSourceName(jack_timer_type_t source); | |||
#ifdef __cplusplus | |||
} | |||
@@ -24,6 +24,7 @@ | |||
#include <stdlib.h> | |||
#include <stdio.h> | |||
#include <assert.h> | |||
#include <signal.h> | |||
#ifdef WIN32 | |||
#include <process.h> | |||
@@ -36,11 +37,7 @@ namespace Jack { | |||
void JackTools::KillServer() | |||
{ | |||
#ifdef WIN32 | |||
exit(1); | |||
#else | |||
kill(GetPID(), SIGINT); | |||
#endif | |||
raise(SIGINT); | |||
} | |||
void JackTools::ThrowJackNetException() | |||
@@ -294,5 +291,6 @@ void BuildClientPath(char* path_to_so, int path_len, const char* so_name) | |||
#endif | |||
} // end of namespace | |||
@@ -36,10 +36,8 @@ | |||
#endif | |||
#include "jslist.h" | |||
#include "driver_interface.h" | |||
#include "JackCompilerDeps.h" | |||
#include "JackError.h" | |||
#include "JackException.h" | |||
#include <string> | |||
#include <algorithm> | |||
@@ -112,114 +110,115 @@ namespace Jack | |||
std::string fName; | |||
public: | |||
JackGnuPlotMonitor ( uint32_t measure_cnt = 512, uint32_t measure_points = 5, std::string name = std::string ( "default" ) ) | |||
{ | |||
jack_log ( "JackGnuPlotMonitor::JackGnuPlotMonitor %u measure points - %u measures", measure_points, measure_cnt ); | |||
fMeasureCnt = measure_cnt; | |||
fMeasurePoints = measure_points; | |||
fTablePos = 0; | |||
fName = name; | |||
fCurrentMeasure = new T[fMeasurePoints]; | |||
fMeasureTable = new T*[fMeasureCnt]; | |||
for ( uint32_t cnt = 0; cnt < fMeasureCnt; cnt++ ) | |||
{ | |||
fMeasureTable[cnt] = new T[fMeasurePoints]; | |||
fill_n ( fMeasureTable[cnt], fMeasurePoints, 0 ); | |||
} | |||
} | |||
~JackGnuPlotMonitor() | |||
{ | |||
jack_log ( "JackGnuPlotMonitor::~JackGnuPlotMonitor" ); | |||
for ( uint32_t cnt = 0; cnt < fMeasureCnt; cnt++ ) | |||
delete[] fMeasureTable[cnt]; | |||
delete[] fMeasureTable; | |||
delete[] fCurrentMeasure; | |||
} | |||
T AddNew ( T measure_point ) | |||
{ | |||
fMeasureId = 0; | |||
return fCurrentMeasure[fMeasureId++] = measure_point; | |||
} | |||
uint32_t New() | |||
{ | |||
return fMeasureId = 0; | |||
} | |||
T Add ( T measure_point ) | |||
{ | |||
return fCurrentMeasure[fMeasureId++] = measure_point; | |||
} | |||
uint32_t AddLast ( T measure_point ) | |||
{ | |||
fCurrentMeasure[fMeasureId] = measure_point; | |||
fMeasureId = 0; | |||
return Write(); | |||
} | |||
uint32_t Write() | |||
{ | |||
for ( uint32_t point = 0; point < fMeasurePoints; point++ ) | |||
fMeasureTable[fTablePos][point] = fCurrentMeasure[point]; | |||
if ( ++fTablePos == fMeasureCnt ) | |||
fTablePos = 0; | |||
return fTablePos; | |||
} | |||
JackGnuPlotMonitor(uint32_t measure_cnt, uint32_t measure_points, std::string name) | |||
{ | |||
jack_log ( "JackGnuPlotMonitor::JackGnuPlotMonitor %u measure points - %u measures", measure_points, measure_cnt ); | |||
fMeasureCnt = measure_cnt; | |||
fMeasurePoints = measure_points; | |||
fTablePos = 0; | |||
fName = name; | |||
fCurrentMeasure = new T[fMeasurePoints]; | |||
fMeasureTable = new T*[fMeasureCnt]; | |||
for ( uint32_t cnt = 0; cnt < fMeasureCnt; cnt++ ) | |||
{ | |||
fMeasureTable[cnt] = new T[fMeasurePoints]; | |||
std::fill_n ( fMeasureTable[cnt], fMeasurePoints, 0 ); | |||
} | |||
} | |||
~JackGnuPlotMonitor() | |||
{ | |||
jack_log ( "JackGnuPlotMonitor::~JackGnuPlotMonitor" ); | |||
for ( uint32_t cnt = 0; cnt < fMeasureCnt; cnt++ ) | |||
delete[] fMeasureTable[cnt]; | |||
delete[] fMeasureTable; | |||
delete[] fCurrentMeasure; | |||
} | |||
T AddNew(T measure_point) | |||
{ | |||
fMeasureId = 0; | |||
return fCurrentMeasure[fMeasureId++] = measure_point; | |||
} | |||
uint32_t New() | |||
{ | |||
return fMeasureId = 0; | |||
} | |||
T Add(T measure_point) | |||
{ | |||
return fCurrentMeasure[fMeasureId++] = measure_point; | |||
} | |||
uint32_t AddLast(T measure_point) | |||
{ | |||
fCurrentMeasure[fMeasureId] = measure_point; | |||
fMeasureId = 0; | |||
return Write(); | |||
} | |||
uint32_t Write() | |||
{ | |||
for ( uint32_t point = 0; point < fMeasurePoints; point++ ) | |||
fMeasureTable[fTablePos][point] = fCurrentMeasure[point]; | |||
if ( ++fTablePos == fMeasureCnt ) | |||
fTablePos = 0; | |||
return fTablePos; | |||
} | |||
int Save(std::string name = std::string ( "" )) | |||
{ | |||
std::string filename = ( name.empty() ) ? fName : name; | |||
filename += ".log"; | |||
jack_log ( "JackGnuPlotMonitor::Save filename %s", filename.c_str() ); | |||
std::ofstream file ( filename.c_str() ); | |||
for ( uint32_t cnt = 0; cnt < fMeasureCnt; cnt++ ) | |||
{ | |||
for ( uint32_t point = 0; point < fMeasurePoints; point++ ) | |||
file << fMeasureTable[cnt][point] << " \t"; | |||
file << std::endl; | |||
} | |||
file.close(); | |||
return 0; | |||
} | |||
int SetPlotFile(std::string* options_list, uint32_t options_number, | |||
std::string* field_names, uint32_t field_number, | |||
std::string name = std::string ( "" )) | |||
{ | |||
std::string title = ( name.empty() ) ? fName : name; | |||
std::string plot_filename = title + ".plt"; | |||
std::string data_filename = title + ".log"; | |||
std::ofstream file ( plot_filename.c_str() ); | |||
file << "set multiplot" << std::endl; | |||
file << "set grid" << std::endl; | |||
file << "set title \"" << title << "\"" << std::endl; | |||
for ( uint32_t i = 0; i < options_number; i++ ) | |||
file << options_list[i] << std::endl; | |||
file << "plot "; | |||
for ( uint32_t row = 1; row <= field_number; row++ ) | |||
{ | |||
file << "\"" << data_filename << "\" using " << row << " title \"" << field_names[row-1] << "\" with lines"; | |||
file << ( ( row < field_number ) ? ", " : "\n" ); | |||
} | |||
jack_log ( "JackGnuPlotMonitor::SetPlotFile - Save GnuPlot file to '%s'", plot_filename.c_str() ); | |||
file.close(); | |||
return 0; | |||
} | |||
int Save ( std::string name = std::string ( "" ) ) | |||
{ | |||
std::string filename = ( name.empty() ) ? fName : name; | |||
filename += ".log"; | |||
jack_log ( "JackGnuPlotMonitor::Save filename %s", filename.c_str() ); | |||
std::ofstream file ( filename.c_str() ); | |||
for ( uint32_t cnt = 0; cnt < fMeasureCnt; cnt++ ) | |||
{ | |||
for ( uint32_t point = 0; point < fMeasurePoints; point++ ) | |||
file << fMeasureTable[cnt][point] << " \t"; | |||
file << std::endl; | |||
} | |||
file.close(); | |||
return 0; | |||
} | |||
int SetPlotFile ( std::string* options_list = NULL, uint32_t options_number = 0, | |||
std::string* field_names = NULL, uint32_t field_number = 0, | |||
std::string name = std::string ( "" ) ) | |||
{ | |||
std::string title = ( name.empty() ) ? fName : name; | |||
std::string plot_filename = title + ".plt"; | |||
std::string data_filename = title + ".log"; | |||
std::ofstream file ( plot_filename.c_str() ); | |||
file << "set multiplot" << std::endl; | |||
file << "set grid" << std::endl; | |||
file << "set title \"" << title << "\"" << std::endl; | |||
for ( uint32_t i = 0; i < options_number; i++ ) | |||
file << options_list[i] << std::endl; | |||
file << "plot "; | |||
for ( uint32_t row = 1; row <= field_number; row++ ) | |||
{ | |||
file << "\"" << data_filename << "\" using " << row << " title \"" << field_names[row-1] << "\" with lines"; | |||
file << ( ( row < field_number ) ? ", " : "\n" ); | |||
} | |||
jack_log ( "JackGnuPlotMonitor::SetPlotFile - Save GnuPlot file to '%s'", plot_filename.c_str() ); | |||
file.close(); | |||
return 0; | |||
} | |||
}; | |||
void BuildClientPath(char* path_to_so, int path_len, const char* so_name); | |||
@@ -44,8 +44,11 @@ static HMODULE libjack_handle = 0; | |||
#else | |||
static void *libjack_handle = 0; | |||
#endif | |||
#ifndef WIN32 | |||
static void __attribute__((constructor)) tryload_libjack() | |||
#else | |||
void tryload_libjack() | |||
#endif | |||
{ | |||
if (getenv("SKIP_LIBJACK") == 0) { // just in case libjack is causing troubles.. | |||
#ifdef __APPLE__ | |||
@@ -30,8 +30,10 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
#include "types.h" | |||
#include "jack.h" | |||
#include "control.h" | |||
#include "JackConstants.h" | |||
#include "JackDriverLoader.h" | |||
#include "JackPlatformPlug.h" | |||
#if defined(JACK_DBUS) && defined(__linux__) | |||
#include <dbus/dbus.h> | |||
@@ -86,7 +88,7 @@ static void copyright(FILE* file) | |||
{ | |||
fprintf(file, "jackdmp " VERSION "\n" | |||
"Copyright 2001-2005 Paul Davis and others.\n" | |||
"Copyright 2004-2011 Grame.\n" | |||
"Copyright 2004-2012 Grame.\n" | |||
"jackdmp comes with ABSOLUTELY NO WARRANTY\n" | |||
"This is free software, and you are welcome to redistribute it\n" | |||
"under certain conditions; see the file COPYING for details\n"); | |||
@@ -130,23 +132,15 @@ static void usage(FILE* file) | |||
" to display options for each master backend\n\n"); | |||
} | |||
// To put in the control.h interface?? | |||
static jackctl_driver_t * | |||
jackctl_server_get_driver( | |||
jackctl_server_t *server, | |||
const char *driver_name) | |||
// To put in the control.h interface ?? | |||
static jackctl_driver_t * jackctl_server_get_driver(jackctl_server_t *server, const char *driver_name) | |||
{ | |||
const JSList * node_ptr; | |||
node_ptr = jackctl_server_get_drivers_list(server); | |||
const JSList * node_ptr = jackctl_server_get_drivers_list(server); | |||
while (node_ptr) | |||
{ | |||
if (strcmp(jackctl_driver_get_name((jackctl_driver_t *)node_ptr->data), driver_name) == 0) | |||
{ | |||
while (node_ptr) { | |||
if (strcmp(jackctl_driver_get_name((jackctl_driver_t *)node_ptr->data), driver_name) == 0) { | |||
return (jackctl_driver_t *)node_ptr->data; | |||
} | |||
node_ptr = jack_slist_next(node_ptr); | |||
} | |||
@@ -167,24 +161,21 @@ static jackctl_internal_t * jackctl_server_get_internal(jackctl_server_t *server | |||
return NULL; | |||
} | |||
static jackctl_parameter_t * | |||
jackctl_get_parameter( | |||
const JSList * parameters_list, | |||
const char * parameter_name) | |||
static jackctl_parameter_t * jackctl_get_parameter(const JSList * parameters_list, const char * parameter_name) | |||
{ | |||
while (parameters_list) | |||
{ | |||
if (strcmp(jackctl_parameter_get_name((jackctl_parameter_t *)parameters_list->data), parameter_name) == 0) | |||
{ | |||
while (parameters_list) { | |||
if (strcmp(jackctl_parameter_get_name((jackctl_parameter_t *)parameters_list->data), parameter_name) == 0) { | |||
return (jackctl_parameter_t *)parameters_list->data; | |||
} | |||
parameters_list = jack_slist_next(parameters_list); | |||
} | |||
return NULL; | |||
} | |||
// Prototype to be found in libjackserver | |||
extern "C" void silent_jack_error_callback(const char *desc); | |||
int main(int argc, char** argv) | |||
{ | |||
jackctl_server_t * server_ctl; | |||
@@ -236,7 +227,7 @@ int main(int argc, char** argv) | |||
int do_unlock = 0; | |||
int loopback = 0; | |||
bool show_version = false; | |||
sigset_t signals; | |||
jackctl_sigmask_t * sigmask; | |||
jackctl_parameter_t* param; | |||
union jackctl_parameter_value value; | |||
@@ -454,12 +445,12 @@ int main(int argc, char** argv) | |||
master_driver_args[i] = argv[optind++]; | |||
} | |||
if (jackctl_parse_driver_params(master_driver_ctl, master_driver_nargs, master_driver_args)) { | |||
if (jackctl_driver_params_parse(master_driver_ctl, master_driver_nargs, master_driver_args)) { | |||
goto destroy_server; | |||
} | |||
// Setup signals | |||
signals = jackctl_setup_signals(0); | |||
sigmask = jackctl_setup_signals(0); | |||
// Open server | |||
if (! jackctl_server_open(server_ctl, master_driver_ctl)) { | |||
@@ -529,7 +520,7 @@ int main(int argc, char** argv) | |||
return_value = 0; | |||
// Waits for signal | |||
jackctl_wait_signals(signals); | |||
jackctl_wait_signals(sigmask); | |||
stop_server: | |||
if (!jackctl_server_stop(server_ctl)) { | |||
@@ -28,6 +28,7 @@ extern "C" | |||
#include <limits.h> | |||
#include "jslist.h" | |||
#include "JackCompilerDeps.h" | |||
#include "JackSystemDeps.h" | |||
@@ -75,7 +76,6 @@ typedef struct { | |||
typedef struct { | |||
uint32_t flags; /**< JACK_CONSTRAINT_FLAG_XXX */ | |||
union { | |||
struct { | |||
jack_driver_param_value_t min; | |||
@@ -124,28 +124,32 @@ typedef struct { | |||
} | |||
jack_driver_desc_filler_t; | |||
SERVER_EXPORT int jack_parse_driver_params(jack_driver_desc_t * desc, int argc, char* argv[], JSList ** param_ptr); | |||
int jack_parse_driver_params(jack_driver_desc_t * desc, int argc, char* argv[], JSList ** param_ptr); | |||
SERVER_EXPORT jack_driver_desc_t * /* newlly allocated driver descriptor, NULL on failure */ | |||
// To be used by drivers | |||
SERVER_EXPORT jack_driver_desc_t * /* Newly allocated driver descriptor, NULL on failure */ | |||
jack_driver_descriptor_construct( | |||
const char * name, /* driver name */ | |||
jack_driver_type_t type, /* driver type */ | |||
const char * description, /* driver description */ | |||
const char * name, /* Driver name */ | |||
jack_driver_type_t type, /* Driver type */ | |||
const char * description, /* Driver description */ | |||
jack_driver_desc_filler_t * filler); /* Pointer to stack var to be supplied to jack_driver_descriptor_add_parameter() as well. | |||
Can be NULL for drivers that have no parameters. */ | |||
SERVER_EXPORT int /* 0 on failure */ | |||
jack_driver_descriptor_add_parameter( | |||
jack_driver_desc_t * driver_descr, /* pointer to driver descriptor as returned by jack_driver_descriptor_construct() */ | |||
jack_driver_desc_t * driver_descr, /* Pointer to driver descriptor as returned by jack_driver_descriptor_construct() */ | |||
jack_driver_desc_filler_t * filler, /* Pointer to the stack var that was supplied to jack_driver_descriptor_add_parameter(). */ | |||
const char * name, /* parameter's name */ | |||
char character, /* parameter's character (for getopt, etc) */ | |||
const char * name, /* Parameter's name */ | |||
char character, /* Parameter's character (for getopt, etc) */ | |||
jack_driver_param_type_t type, /* The parameter's type */ | |||
const jack_driver_param_value_t * value_ptr, /* Pointer to parameter's (default) value */ | |||
jack_driver_param_constraint_desc_t * constraint, /* Pointer to parameter constraint descriptor. NULL if there is no constraint */ | |||
const char * short_desc, /* A short (~30 chars) description for the user */ | |||
const char * long_desc); /* A longer description for the user, if NULL short_desc will be used */ | |||
typedef jack_driver_desc_t * (*JackDriverDescFunction) (); | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
@@ -29,9 +29,10 @@ | |||
#ifndef JACKCTL_H__2EEDAD78_DF4C_4B26_83B7_4FF1A446A47E__INCLUDED | |||
#define JACKCTL_H__2EEDAD78_DF4C_4B26_83B7_4FF1A446A47E__INCLUDED | |||
#include <jack/types.h> | |||
#include <jack/jslist.h> | |||
#include <jack/systemdeps.h> | |||
#if !defined (__sun__) | |||
#if !defined(sun) && !defined(__sun__) | |||
#include <stdbool.h> | |||
#endif | |||
@@ -81,6 +82,9 @@ typedef struct jackctl_internal jackctl_internal_t; | |||
/** opaque type for parameter object */ | |||
typedef struct jackctl_parameter jackctl_parameter_t; | |||
/** opaque type for sigmask object */ | |||
typedef struct jackctl_sigmask jackctl_sigmask_t; | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
@@ -102,7 +106,7 @@ extern "C" { | |||
* | |||
* @return the configurated signal set. | |||
*/ | |||
sigset_t | |||
jackctl_sigmask_t * | |||
jackctl_setup_signals( | |||
unsigned int flags); | |||
@@ -113,7 +117,7 @@ jackctl_setup_signals( | |||
*/ | |||
void | |||
jackctl_wait_signals( | |||
sigset_t signals); | |||
jackctl_sigmask_t * signals); | |||
/** | |||
* Call this function to create server object. | |||
@@ -330,6 +334,21 @@ const JSList * | |||
jackctl_driver_get_parameters( | |||
jackctl_driver_t * driver); | |||
/** | |||
* Call this function to parse parameters for a driver. | |||
* | |||
* @param driver driver object handle | |||
* @param argc parameter list len | |||
* @param argv parameter list, as an array of char* | |||
* | |||
* @return success status: true - success, false - fail | |||
*/ | |||
int | |||
jackctl_driver_params_parse( | |||
jackctl_driver_t * driver, | |||
int argc, | |||
char* argv[]); | |||
/** | |||
* Call this function to get name of internal client. | |||
* | |||
@@ -76,6 +76,11 @@ jack_get_version( | |||
const char * | |||
jack_get_version_string() JACK_OPTIONAL_WEAK_EXPORT; | |||
/** | |||
* @defgroup ClientFunctions Creating & manipulating clients | |||
* @{ | |||
*/ | |||
/** | |||
* Open an external client session with a JACK server. This interface | |||
* is more complex but more powerful than jack_client_new(). With it, | |||
@@ -170,7 +175,7 @@ int jack_internal_client_new (const char *client_name, | |||
/** | |||
* Remove an internal client from a JACK server. | |||
* | |||
* @deprecated Please use jack_internal_client_load(). | |||
* @deprecated Please use jack_internal_client_unload(). | |||
*/ | |||
void jack_internal_client_close (const char *client_name) JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT; | |||
@@ -198,9 +203,9 @@ int jack_get_client_pid (const char *name) JACK_OPTIONAL_WEAK_EXPORT; | |||
/** | |||
* @return the pthread ID of the thread running the JACK client side | |||
* code. | |||
* real-time code. | |||
*/ | |||
jack_native_thread_t jack_client_thread_id (jack_client_t *) JACK_OPTIONAL_WEAK_EXPORT; | |||
jack_native_thread_t jack_client_thread_id (jack_client_t *client) JACK_OPTIONAL_WEAK_EXPORT; | |||
/*@}*/ | |||
@@ -224,7 +229,7 @@ int jack_is_realtime (jack_client_t *client) JACK_OPTIONAL_WEAK_EXPORT; | |||
* | |||
* @deprecated Please use jack_cycle_wait() and jack_cycle_signal() functions. | |||
*/ | |||
jack_nframes_t jack_thread_wait (jack_client_t*, int status) JACK_OPTIONAL_WEAK_EXPORT; | |||
jack_nframes_t jack_thread_wait (jack_client_t *client, int status) JACK_OPTIONAL_WEAK_EXPORT; | |||
/** | |||
* Wait until this JACK client should process data. | |||
@@ -432,9 +437,9 @@ int jack_set_sample_rate_callback (jack_client_t *client, | |||
* | |||
* @return 0 on success, otherwise a non-zero error code | |||
*/ | |||
int jack_set_client_registration_callback (jack_client_t *, | |||
JackClientRegistrationCallback | |||
registration_callback, void *arg) JACK_OPTIONAL_WEAK_EXPORT; | |||
int jack_set_client_registration_callback (jack_client_t *client, | |||
JackClientRegistrationCallback | |||
registration_callback, void *arg) JACK_OPTIONAL_WEAK_EXPORT; | |||
/** | |||
* Tell the JACK server to call @a registration_callback whenever a | |||
@@ -449,7 +454,7 @@ int jack_set_client_registration_callback (jack_client_t *, | |||
* | |||
* @return 0 on success, otherwise a non-zero error code | |||
*/ | |||
int jack_set_port_registration_callback (jack_client_t *, | |||
int jack_set_port_registration_callback (jack_client_t *client, | |||
JackPortRegistrationCallback | |||
registration_callback, void *arg) JACK_OPTIONAL_WEAK_EXPORT; | |||
@@ -466,7 +471,7 @@ int jack_set_client_registration_callback (jack_client_t *, | |||
* | |||
* @return 0 on success, otherwise a non-zero error code | |||
*/ | |||
int jack_set_port_connect_callback (jack_client_t *, | |||
int jack_set_port_connect_callback (jack_client_t *client, | |||
JackPortConnectCallback | |||
connect_callback, void *arg) JACK_OPTIONAL_WEAK_EXPORT; | |||
@@ -483,7 +488,7 @@ int jack_set_port_connect_callback (jack_client_t *, | |||
* | |||
* @return 0 on success, otherwise a non-zero error code | |||
*/ | |||
int jack_set_port_rename_callback (jack_client_t *, | |||
int jack_set_port_rename_callback (jack_client_t *client, | |||
JackPortRenameCallback | |||
rename_callback, void *arg) JACK_OPTIONAL_WEAK_EXPORT; | |||
@@ -500,7 +505,7 @@ int jack_set_port_rename_callback (jack_client_t *, | |||
* | |||
* @return 0 on success, otherwise a non-zero error code | |||
*/ | |||
int jack_set_graph_order_callback (jack_client_t *, | |||
int jack_set_graph_order_callback (jack_client_t *client, | |||
JackGraphOrderCallback graph_callback, | |||
void *) JACK_OPTIONAL_WEAK_EXPORT; | |||
@@ -517,7 +522,7 @@ int jack_set_graph_order_callback (jack_client_t *, | |||
* | |||
* @return 0 on success, otherwise a non-zero error code | |||
*/ | |||
int jack_set_xrun_callback (jack_client_t *, | |||
int jack_set_xrun_callback (jack_client_t *client, | |||
JackXRunCallback xrun_callback, void *arg) JACK_OPTIONAL_WEAK_EXPORT; | |||
/*@}*/ | |||
@@ -575,7 +580,7 @@ int jack_set_xrun_callback (jack_client_t *, | |||
* | |||
* @return 0 on success, otherwise a non-zero error code | |||
*/ | |||
int jack_set_latency_callback (jack_client_t *, | |||
int jack_set_latency_callback (jack_client_t *client, | |||
JackLatencyCallback latency_callback, | |||
void *) JACK_WEAK_EXPORT; | |||
/*@}*/ | |||
@@ -713,7 +718,7 @@ jack_port_t * jack_port_register (jack_client_t *client, | |||
* | |||
* @return 0 on success, otherwise a non-zero error code | |||
*/ | |||
int jack_port_unregister (jack_client_t *, jack_port_t *) JACK_OPTIONAL_WEAK_EXPORT; | |||
int jack_port_unregister (jack_client_t *client, jack_port_t *port) JACK_OPTIONAL_WEAK_EXPORT; | |||
/** | |||
* This returns a pointer to the memory area associated with the | |||
@@ -734,7 +739,7 @@ int jack_port_unregister (jack_client_t *, jack_port_t *) JACK_OPTIONAL_WEAK_EXP | |||
* Caching output ports is DEPRECATED in Jack 2.0, due to some new optimization (like "pipelining"). | |||
* Port buffers have to be retrieved in each callback for proper functionning. | |||
*/ | |||
void * jack_port_get_buffer (jack_port_t *, jack_nframes_t) JACK_OPTIONAL_WEAK_EXPORT; | |||
void * jack_port_get_buffer (jack_port_t *port, jack_nframes_t) JACK_OPTIONAL_WEAK_EXPORT; | |||
/** | |||
* @return the full name of the jack_port_t (including the @a | |||
@@ -771,7 +776,7 @@ jack_port_type_id_t jack_port_type_id (const jack_port_t *port) JACK_OPTIONAL_WE | |||
/** | |||
* @return TRUE if the jack_port_t belongs to the jack_client_t. | |||
*/ | |||
int jack_port_is_mine (const jack_client_t *, const jack_port_t *port) JACK_OPTIONAL_WEAK_EXPORT; | |||
int jack_port_is_mine (const jack_client_t *client, const jack_port_t *port) JACK_OPTIONAL_WEAK_EXPORT; | |||
/** | |||
* @return number of connections to or from @a port. | |||
@@ -931,7 +936,7 @@ int jack_port_monitoring_input (jack_port_t *port) JACK_OPTIONAL_WEAK_EXPORT; | |||
* @return 0 on success, EEXIST if the connection is already made, | |||
* otherwise a non-zero error code | |||
*/ | |||
int jack_connect (jack_client_t *, | |||
int jack_connect (jack_client_t *client, | |||
const char *source_port, | |||
const char *destination_port) JACK_OPTIONAL_WEAK_EXPORT; | |||
@@ -948,7 +953,7 @@ int jack_connect (jack_client_t *, | |||
* | |||
* @return 0 on success, otherwise a non-zero error code | |||
*/ | |||
int jack_disconnect (jack_client_t *, | |||
int jack_disconnect (jack_client_t *client, | |||
const char *source_port, | |||
const char *destination_port) JACK_OPTIONAL_WEAK_EXPORT; | |||
@@ -961,7 +966,7 @@ int jack_disconnect (jack_client_t *, | |||
* while generic connection clients (e.g. patchbays) would use | |||
* jack_disconnect(). | |||
*/ | |||
int jack_port_disconnect (jack_client_t *, jack_port_t *) JACK_OPTIONAL_WEAK_EXPORT; | |||
int jack_port_disconnect (jack_client_t *client, jack_port_t *port) JACK_OPTIONAL_WEAK_EXPORT; | |||
/** | |||
* @return the maximum number of characters in a full JACK port name | |||
@@ -1052,7 +1057,7 @@ size_t jack_port_type_get_buffer_size (jack_client_t *client, const char *port_t | |||
* be replaced by a latency callback that calls @ref | |||
* jack_port_set_latency_range(). | |||
*/ | |||
void jack_port_set_latency (jack_port_t *, jack_nframes_t) JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT; | |||
void jack_port_set_latency (jack_port_t *port, jack_nframes_t) JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT; | |||
/** | |||
* return the latency range defined by @a mode for | |||
@@ -1147,7 +1152,7 @@ void jack_port_set_latency_range (jack_port_t *port, jack_latency_callback_mode_ | |||
* @return zero for successful execution of the request. non-zero | |||
* otherwise. | |||
*/ | |||
int jack_recompute_total_latencies (jack_client_t*) JACK_OPTIONAL_WEAK_EXPORT; | |||
int jack_recompute_total_latencies (jack_client_t *client) JACK_OPTIONAL_WEAK_EXPORT; | |||
/** | |||
* @return the time (in frames) between data being available or | |||
@@ -1176,7 +1181,7 @@ jack_nframes_t jack_port_get_latency (jack_port_t *port) JACK_OPTIONAL_WEAK_DEPR | |||
* be replaced by jack_port_get_latency_range() in any existing | |||
* use cases. | |||
*/ | |||
jack_nframes_t jack_port_get_total_latency (jack_client_t *, | |||
jack_nframes_t jack_port_get_total_latency (jack_client_t *client, | |||
jack_port_t *port) JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT; | |||
/** | |||
@@ -1220,7 +1225,7 @@ int jack_recompute_total_latency (jack_client_t*, jack_port_t* port) JACK_OPTION | |||
* | |||
* @see jack_port_name_size(), jack_port_type_size() | |||
*/ | |||
const char ** jack_get_ports (jack_client_t *, | |||
const char ** jack_get_ports (jack_client_t *client, | |||
const char *port_name_pattern, | |||
const char *type_name_pattern, | |||
unsigned long flags) JACK_OPTIONAL_WEAK_EXPORT; | |||
@@ -1230,7 +1235,7 @@ const char ** jack_get_ports (jack_client_t *, | |||
* | |||
* @see jack_port_name_size() | |||
*/ | |||
jack_port_t * jack_port_by_name (jack_client_t *, const char *port_name) JACK_OPTIONAL_WEAK_EXPORT; | |||
jack_port_t * jack_port_by_name (jack_client_t *client, const char *port_name) JACK_OPTIONAL_WEAK_EXPORT; | |||
/** | |||
* @return address of the jack_port_t of a @a port_id. | |||
@@ -1279,6 +1284,55 @@ jack_nframes_t jack_frame_time (const jack_client_t *) JACK_OPTIONAL_WEAK_EXPORT | |||
*/ | |||
jack_nframes_t jack_last_frame_time (const jack_client_t *client) JACK_OPTIONAL_WEAK_EXPORT; | |||
/** | |||
* This function may only be used from the process callback. | |||
* It provides the internal cycle timing information as used by | |||
* most of the other time related functions. This allows the | |||
* caller to map between frame counts and microseconds with full | |||
* precision (i.e. without rounding frame times to integers), | |||
* and also provides e.g. the microseconds time of the start of | |||
* the current cycle directly (it has to be computed otherwise). | |||
* | |||
* If the return value is zero, the following information is | |||
* provided in the variables pointed to by the arguments: | |||
* | |||
* current_frames: the frame time counter at the start of the | |||
* current cycle, same as jack_last_frame_time(). | |||
* current_usecs: the microseconds time at the start of the | |||
* current cycle. | |||
* next_usecs: the microseconds time of the start of the next | |||
* next cycle as computed by the DLL. | |||
* period_usecs: the current best estimate of the period time in | |||
* microseconds. | |||
* | |||
* NOTES: | |||
* | |||
* Because of the types used, all the returned values except period_usecs | |||
* are unsigned. In computations mapping between frames and microseconds | |||
* *signed* differences are required. The easiest way is to compute those | |||
* separately and assign them to the appropriate signed variables, | |||
* int32_t for frames and int64_t for usecs. See the implementation of | |||
* jack_frames_to_time() and Jack_time_to_frames() for an example. | |||
* | |||
* Unless there was an xrun, skipped cycles, or the current cycle is the | |||
* first after freewheeling or starting Jack, the value of current_usecs | |||
* will always be the value of next_usecs of the previous cycle. | |||
* | |||
* The value of period_usecs will in general NOT be exactly equal to | |||
* the difference of next_usecs and current_usecs. This is because to | |||
* ensure stability of the DLL and continuity of the mapping, a fraction | |||
* of the loop error must be included in next_usecs. For an accurate | |||
* mapping between frames and microseconds, the difference of next_usecs | |||
* and current_usecs should be used, and not period_usecs. | |||
* | |||
* @return zero if OK, non-zero otherwise. | |||
*/ | |||
int jack_get_cycle_times(const jack_client_t *client, | |||
jack_nframes_t *current_frames, | |||
jack_time_t *current_usecs, | |||
jack_time_t *next_usecs, | |||
float *period_usecs) JACK_OPTIONAL_WEAK_EXPORT; | |||
/** | |||
* @return the estimated time in microseconds of the specified frame time | |||
*/ | |||
@@ -44,10 +44,10 @@ enum JackNetEncoder { | |||
typedef struct { | |||
int audio_input; // from master or to slave (-1 for get master audio physical outputs) | |||
int audio_output; // to master or from slave (-1 for get master audio physical inputs) | |||
int midi_input; // from master or to slave (-1 for get master MIDI physical outputs) | |||
int midi_output; // to master or from slave (-1 for get master MIDI physical inputs) | |||
int audio_input; // from master or to slave (-1 to take master audio physical inputs) | |||
int audio_output; // to master or from slave (-1 to take master audio physical outputs) | |||
int midi_input; // from master or to slave (-1 to take master MIDI physical inputs) | |||
int midi_output; // to master or from slave (-1 to take master MIDI physical outputs) | |||
int mtu; // network Maximum Transmission Unit | |||
int time_out; // in second, -1 means in infinite | |||
int encoder; // encoder type (one of JackNetEncoder) | |||
@@ -58,10 +58,10 @@ typedef struct { | |||
typedef struct { | |||
int audio_input; // master audio physical outputs | |||
int audio_output; // master audio physical inputs | |||
int midi_input; // master MIDI physical outputs | |||
int midi_output; // master MIDI physical inputs | |||
int audio_input; // master audio physical outputs (-1 to take slave wanted audio inputs) | |||
int audio_output; // master audio physical inputs (-1 to take slave wanted audio outputs) | |||
int midi_input; // master MIDI physical outputs (-1 to take slave wanted MIDI inputs) | |||
int midi_output; // master MIDI physical inputs (-1 to take slave wanted MIDI outputs) | |||
jack_nframes_t buffer_size; // mater buffer size | |||
jack_nframes_t sample_rate; // mater sample rate | |||
char master_name[MASTER_NAME_SIZE]; // master machine name | |||
@@ -1,5 +1,5 @@ | |||
/* | |||
Copyright (C) 2004-2009 Grame | |||
Copyright (C) 2004-2012 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 | |||
@@ -20,66 +20,104 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
#ifndef __jack_systemdeps_h__ | |||
#define __jack_systemdeps_h__ | |||
#if defined(WIN32) && !defined(__CYGWIN__) && !defined(GNU_WIN32) | |||
#ifndef POST_PACKED_STRUCTURE | |||
#ifdef __GNUC__ | |||
/* 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. | |||
*/ | |||
#define PRE_PACKED_STRUCTURE | |||
#define POST_PACKED_STRUCTURE __attribute__((__packed__)) | |||
#else | |||
#ifdef _MSC_VER | |||
#define PRE_PACKED_STRUCTURE1 __pragma(pack(push,1)) | |||
#define PRE_PACKED_STRUCTURE PRE_PACKED_STRUCTURE1 | |||
/* PRE_PACKED_STRUCTURE needs to be a macro which | |||
expands into a compiler directive. The directive must | |||
tell the compiler to arrange the following structure | |||
declaration so that it is packed on byte-boundaries rather | |||
than use the natural alignment of the processor and/or | |||
compiler. | |||
*/ | |||
#define POST_PACKED_STRUCTURE ;__pragma(pack(pop)) | |||
/* and POST_PACKED_STRUCTURE needs to be a macro which | |||
restores the packing to its previous setting */ | |||
#else | |||
#define PRE_PACKED_STRUCTURE | |||
#define POST_PACKED_STRUCTURE | |||
#endif | |||
#include <windows.h> | |||
#ifdef _MSC_VER /* Microsoft compiler */ | |||
#define __inline__ inline | |||
#if (!defined(int8_t) && !defined(_STDINT_H)) | |||
#define __int8_t_defined | |||
typedef char int8_t; | |||
typedef unsigned char uint8_t; | |||
typedef short int16_t; | |||
typedef unsigned short uint16_t; | |||
typedef long int32_t; | |||
typedef unsigned long uint32_t; | |||
typedef LONGLONG int64_t; | |||
typedef ULONGLONG uint64_t; | |||
#endif | |||
#elif __MINGW32__ /* MINGW */ | |||
#include <stdint.h> | |||
#include <sys/types.h> | |||
#else /* other compilers ...*/ | |||
#include <inttypes.h> | |||
#include <pthread.h> | |||
#include <sys/types.h> | |||
#endif | |||
#if !defined(_PTHREAD_H) && !defined(PTHREAD_WIN32) | |||
/** | |||
* to make jack API independent of different thread implementations, | |||
* we define jack_native_thread_t to HANDLE here. | |||
*/ | |||
typedef HANDLE jack_native_thread_t; | |||
#else | |||
#ifdef PTHREAD_WIN32 // Added by JE - 10-10-2011 | |||
#include <ptw32/pthread.h> // Makes sure we #include the ptw32 version ! | |||
#if defined(WIN32) && !defined(__CYGWIN__) && !defined(GNU_WIN32) | |||
#include <windows.h> | |||
#ifdef _MSC_VER /* Microsoft compiler */ | |||
#define __inline__ inline | |||
#if (!defined(int8_t) && !defined(_STDINT_H)) | |||
#define __int8_t_defined | |||
typedef char int8_t; | |||
typedef unsigned char uint8_t; | |||
typedef short int16_t; | |||
typedef unsigned short uint16_t; | |||
typedef long int32_t; | |||
typedef unsigned long uint32_t; | |||
typedef LONGLONG int64_t; | |||
typedef ULONGLONG uint64_t; | |||
#endif | |||
#elif __MINGW32__ /* MINGW */ | |||
#include <stdint.h> | |||
#include <sys/types.h> | |||
#else /* other compilers ...*/ | |||
#include <inttypes.h> | |||
#include <pthread.h> | |||
#include <sys/types.h> | |||
#endif | |||
#if !defined(_PTHREAD_H) && !defined(PTHREAD_WIN32) | |||
/** | |||
* to make jack API independent of different thread implementations, | |||
* we define jack_native_thread_t to HANDLE here. | |||
*/ | |||
typedef HANDLE jack_native_thread_t; | |||
#else | |||
#ifdef PTHREAD_WIN32 // Added by JE - 10-10-2011 | |||
#include <ptw32/pthread.h> // Makes sure we #include the ptw32 version ! | |||
#endif | |||
/** | |||
* to make jack API independent of different thread implementations, | |||
* we define jack_native_thread_t to pthread_t here. | |||
*/ | |||
typedef pthread_t jack_native_thread_t; | |||
#endif | |||
/** | |||
* to make jack API independent of different thread implementations, | |||
* we define jack_native_thread_t to pthread_t here. | |||
*/ | |||
typedef pthread_t jack_native_thread_t; | |||
#endif | |||
#endif // WIN32 && !__CYGWIN__ && !GNU_WIN32 */ | |||
#if defined(__APPLE__) || defined(__linux__) || defined(__sun__) || defined(sun) || defined(__unix__) || defined(__CYGWIN__) || defined(GNU_WIN32) | |||
#if defined(__CYGWIN__) || defined(GNU_WIN32) | |||
#include <stdint.h> | |||
#endif | |||
#include <inttypes.h> | |||
#include <pthread.h> | |||
#include <sys/types.h> | |||
#if defined(__CYGWIN__) || defined(GNU_WIN32) | |||
#include <stdint.h> | |||
#endif | |||
#include <inttypes.h> | |||
#include <pthread.h> | |||
#include <sys/types.h> | |||
/** | |||
* to make jack API independent of different thread implementations, | |||
* we define jack_native_thread_t to pthread_t here. | |||
*/ | |||
typedef pthread_t jack_native_thread_t; | |||
/** | |||
* to make jack API independent of different thread implementations, | |||
* we define jack_native_thread_t to pthread_t here. | |||
*/ | |||
typedef pthread_t jack_native_thread_t; | |||
#endif /* __APPLE__ || __linux__ || __sun__ || sun */ | |||
#endif /* __APPLE__ || __linux__ || __sun__ || sun */ | |||
#endif |
@@ -259,6 +259,7 @@ typedef void (*JackLatencyCallback)(jack_latency_callback_mode_t mode, void *arg | |||
/** | |||
* the new latency API operates on Ranges. | |||
*/ | |||
PRE_PACKED_STRUCTURE | |||
struct _jack_latency_range | |||
{ | |||
/** | |||
@@ -269,7 +270,7 @@ struct _jack_latency_range | |||
* maximum latency | |||
*/ | |||
jack_nframes_t max; | |||
}; | |||
} POST_PACKED_STRUCTURE; | |||
typedef struct _jack_latency_range jack_latency_range_t; | |||
@@ -548,7 +549,8 @@ typedef enum { | |||
#define JACK_POSITION_MASK (JackPositionBBT|JackPositionTimecode) | |||
#define EXTENDED_TIME_INFO | |||
typedef struct { | |||
PRE_PACKED_STRUCTURE | |||
struct _jack_position { | |||
/* these four cannot be set from clients: the server sets them */ | |||
jack_unique_t unique_1; /**< unique ID */ | |||
@@ -614,7 +616,9 @@ typedef struct { | |||
/* When (unique_1 == unique_2) the contents are consistent. */ | |||
jack_unique_t unique_2; /**< unique ID */ | |||
} jack_position_t; | |||
} POST_PACKED_STRUCTURE; | |||
typedef struct _jack_position jack_position_t; | |||
/** | |||
* Prototype for the @a sync_callback defined by slow-sync clients. | |||
@@ -67,6 +67,10 @@ | |||
#endif | |||
#endif | |||
#ifndef JACK_WEAK_EXPORT | |||
#define JACK_WEAK_EXPORT | |||
#endif | |||
#ifndef JACK_OPTIONAL_WEAK_EXPORT | |||
#define JACK_OPTIONAL_WEAK_EXPORT | |||
#endif | |||
@@ -82,6 +86,11 @@ | |||
#endif | |||
#endif /* __GNUC__ */ | |||
#ifndef JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT | |||
#define JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT | |||
#endif | |||
#endif | |||
#endif /* __weakmacros_h__ */ | |||
@@ -47,7 +47,7 @@ $Id: net_driver.c,v 1.17 2006/04/16 20:16:10 torbenh Exp $ | |||
#include <netinet/in.h> | |||
#endif | |||
#ifdef __linux__ | |||
#if defined(HAVE_CONFIG_H) | |||
#include "config.h" | |||
#endif | |||
@@ -26,7 +26,7 @@ | |||
* | |||
*/ | |||
#ifdef __linux__ | |||
#if defined(HAVE_CONFIG_H) | |||
#include "config.h" | |||
#endif | |||
@@ -75,7 +75,7 @@ | |||
#include "netjack_packet.h" | |||
#include "JackError.h" | |||
#ifdef NO_JACK_ERROR | |||
#ifdef NO_JACK_ERROR | |||
#define jack_error printf | |||
#endif | |||
@@ -505,11 +505,11 @@ packet_cache_drain_socket( packet_cache *pcache, int sockfd ) | |||
cache_packet *cpack; | |||
struct sockaddr_in sender_address; | |||
#ifdef WIN32 | |||
size_t senderlen = sizeof( struct sockaddr_in ); | |||
int senderlen = sizeof( struct sockaddr_in ); | |||
u_long parm = 1; | |||
ioctlsocket( sockfd, FIONBIO, &parm ); | |||
#else | |||
socklen_t senderlen = sizeof( struct sockaddr_in ); | |||
int senderlen = sizeof( struct sockaddr_in ); | |||
#endif | |||
while (1) { | |||
#ifdef WIN32 | |||
@@ -117,20 +117,17 @@ extern "C" | |||
*/ | |||
PRE_PACKED_STRUCTURE | |||
typedef struct _jack_shm_info { | |||
struct _jack_shm_info { | |||
jack_shm_registry_index_t index; /* offset into the registry */ | |||
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 */ | |||
} | |||
#ifdef _MSC_VER | |||
jack_shm_info_t; POST_PACKED_STRUCTURE | |||
#else | |||
POST_PACKED_STRUCTURE jack_shm_info_t; | |||
#endif | |||
} POST_PACKED_STRUCTURE; | |||
typedef struct _jack_shm_info jack_shm_info_t; | |||
/* utility functions used only within JACK */ | |||
void jack_shm_copy_from_registry (jack_shm_info_t*, | |||
@@ -15,13 +15,13 @@ def configure(conf): | |||
conf.env['BUILD_ADAPTER'] = conf.is_defined('HAVE_SAMPLERATE') | |||
def create_jack_process_obj(bld, target, sources, uselib = None): | |||
process = bld.new_task_gen('cxx', 'shlib') | |||
process.env['shlib_PATTERN'] = '%s.so' | |||
process = bld(features = ['cxx', 'cxxshlib']) | |||
process.env['cxxshlib_PATTERN'] = '%s.so' | |||
process.defines = ['HAVE_CONFIG_H','SERVER_SIDE'] | |||
if bld.env['IS_MACOSX']: | |||
env_includes = ['../macosx', '../posix', '../macosx/coreaudio'] | |||
if bld.env['IS_LINUX']: | |||
env_includes = ['../linux', '../posix', '../linux/alsa'] | |||
env_includes = ['../linux', '../posix', '../linux/alsa'] | |||
if bld.env['IS_SUN']: | |||
env_includes = ['../solaris', '../posix', '../solaris/oss'] | |||
process.includes = ['.'] + env_includes + ['jack', '..'] | |||
@@ -35,7 +35,7 @@ def create_jack_process_obj(bld, target, sources, uselib = None): | |||
#process.env.append_value("LINKFLAGS", "-arch i386 -arch ppc -arch x86_64") | |||
process.env.append_value("CPPFLAGS", "-fvisibility=hidden") | |||
process.install_path = '${ADDON_DIR}/' | |||
process.uselib_local = uselib.name | |||
process.use = [uselib.name] | |||
return process | |||
def build(bld): | |||
@@ -46,6 +46,7 @@ def build(bld): | |||
'JackConnectionManager.cpp', | |||
'ringbuffer.c', | |||
'JackError.cpp', | |||
'JackException.cpp', | |||
'JackFrameTimer.cpp', | |||
'JackGraphManager.cpp', | |||
'JackPort.cpp', | |||
@@ -55,6 +56,7 @@ def build(bld): | |||
'JackMidiAPI.cpp', | |||
'JackEngineControl.cpp', | |||
'JackShmMem.cpp', | |||
'JackGenericClientChannel.cpp', | |||
'shm.c', | |||
'JackGlobals.cpp', | |||
'JackDebugClient.cpp', | |||
@@ -72,8 +74,8 @@ def build(bld): | |||
common_libsources += [ | |||
'../posix/JackPosixThread.cpp', | |||
'../posix/JackPosixSemaphore.cpp', | |||
'../posix/JackFifo.cpp', | |||
'../posix/JackProcessSync.cpp', | |||
'../posix/JackPosixProcessSync.cpp', | |||
'../posix/JackPosixMutex.cpp', | |||
'../posix/JackSocket.cpp', | |||
'../linux/JackLinuxTime.c', | |||
] | |||
@@ -85,7 +87,8 @@ def build(bld): | |||
common_libsources += [ | |||
'../posix/JackPosixThread.cpp', | |||
'../posix/JackFifo.cpp', | |||
'../posix/JackProcessSync.cpp', | |||
'../posix/JackPosixProcessSync.cpp', | |||
'../posix/JackPosixMutex.cpp', | |||
'../posix/JackSocket.cpp', | |||
'../solaris/JackSolarisTime.c', | |||
] | |||
@@ -94,7 +97,7 @@ def build(bld): | |||
if bld.env['IS_MACOSX']: | |||
common_libsources += [ | |||
'../posix/JackProcessSync.cpp', | |||
'../posix/JackPosixProcessSync.cpp', | |||
'../posix/JackPosixThread.cpp', | |||
'../macosx/JackMachThread.cpp', | |||
'../macosx/JackMachSemaphore.cpp', | |||
@@ -103,18 +106,17 @@ def build(bld): | |||
] | |||
includes = ['../macosx', '../macosx/RPC', '../posix'] + includes | |||
serverlib = bld.new_task_gen('cxx', 'shlib') | |||
serverlib.features.append('cc') | |||
serverlib = bld(features = ['c', 'cxx', 'cxxshlib', 'cshlib']) | |||
serverlib.defines = ['HAVE_CONFIG_H','SERVER_SIDE'] | |||
serverlib.includes = includes | |||
serverlib.name = 'serverlib' | |||
serverlib.target = 'jackserver' | |||
serverlib.uselib = uselib | |||
serverlib.use = uselib | |||
serverlib.install_path = '${LIBDIR}' | |||
serverlib.source = [] + common_libsources | |||
serverlib.source += [ | |||
'JackAudioDriver.cpp', | |||
'JackTimedDriver.cpp', | |||
'JackTimedDriver.cpp', | |||
'JackMidiDriver.cpp', | |||
'JackDriver.cpp', | |||
'JackEngine.cpp', | |||
@@ -132,6 +134,7 @@ def build(bld): | |||
'JackNetTool.cpp', | |||
'JackNetInterface.cpp', | |||
'JackArgParser.cpp', | |||
'JackRequestDecoder.cpp', | |||
'JackMidiAsyncQueue.cpp', | |||
'JackMidiAsyncWaitQueue.cpp', | |||
'JackMidiBufferReadQueue.cpp', | |||
@@ -185,22 +188,23 @@ def build(bld): | |||
serverlib.env.append_value("LINKFLAGS", "-lnsl -lsocket") | |||
if bld.env['BUILD_NETLIB'] == True: | |||
netlib = bld.new_task_gen('cxx', 'shlib') | |||
netlib.features.append('cc') | |||
netlib = bld(features = ['c', 'cxx', 'cxxshlib', 'cshlib']) | |||
netlib.defines = ['HAVE_CONFIG_H','SERVER_SIDE'] | |||
netlib.includes = includes | |||
netlib.name = 'netlib' | |||
netlib.target = 'jacknet' | |||
netlib.uselib = ['SAMPLERATE', 'CELT', 'PTHREAD' , 'RT'] | |||
netlib.use = ['SAMPLERATE', 'CELT', 'PTHREAD' , 'RT'] | |||
netlib.install_path = '${LIBDIR}' | |||
netlib.source = [ | |||
'JackNetAPI.cpp', | |||
'JackNetInterface.cpp', | |||
'JackNetTool.cpp', | |||
'JackException.cpp', | |||
'JackAudioAdapterInterface.cpp', | |||
'JackLibSampleRateResampler.cpp', | |||
'JackResampler.cpp', | |||
'JackGlobals.cpp', | |||
'../posix/JackPosixMutex.cpp', | |||
'ringbuffer.c'] | |||
if bld.env['IS_LINUX']: | |||
@@ -218,13 +222,12 @@ def build(bld): | |||
netlib.vnum = bld.env['JACK_API_VERSION'] | |||
clientlib = bld.new_task_gen('cxx', 'shlib') | |||
clientlib.features.append('cc') | |||
clientlib = bld(features = ['c', 'cxx', 'cxxshlib', 'cshlib']) | |||
clientlib.defines = 'HAVE_CONFIG_H' | |||
clientlib.uselib = uselib | |||
clientlib.use = uselib | |||
clientlib.install_path = '${LIBDIR}' | |||
if bld.env['BUILD_JACKDBUS'] == True and bld.env['BUILD_JACKD'] == False: | |||
clientlib.uselib.append('DBUS-1') | |||
clientlib.use.append('DBUS-1') | |||
clientlib.includes = includes | |||
clientlib.name = 'clientlib' | |||
clientlib.target = 'jack' | |||
@@ -268,7 +271,7 @@ def build(bld): | |||
clientlib.env.append_value("LINKFLAGS", "-lnsl -lsocket") | |||
if bld.env['BUILD_WITH_32_64']: | |||
print "create 32bit lib..." | |||
print("create 32bit lib...") | |||
clientlib32bit = clientlib.clone('lib32') | |||
create_jack_process_obj(bld, 'netmanager', 'JackNetManager.cpp', serverlib) | |||
@@ -285,7 +288,7 @@ def build(bld): | |||
if bld.env['BUILD_ADAPTER'] == True: | |||
process = create_jack_process_obj(bld, 'netadapter', net_adapter_sources, serverlib) | |||
process.uselib = 'SAMPLERATE' | |||
process.use = 'SAMPLERATE' | |||
audio_adapter_sources = [ | |||
'JackResampler.cpp', | |||
@@ -299,33 +302,29 @@ def build(bld): | |||
audio_adapter_sources += ['../macosx/coreaudio/JackCoreAudioAdapter.cpp'] | |||
process = create_jack_process_obj(bld, 'audioadapter', audio_adapter_sources, serverlib) | |||
process.env.append_value("LINKFLAGS", "-framework CoreAudio -framework AudioUnit -framework AudioToolbox -framework CoreServices") | |||
process.uselib = 'SAMPLERATE' | |||
process.use = 'SAMPLERATE' | |||
if bld.env['BUILD_ADAPTER'] and bld.env['IS_LINUX'] and bld.env['BUILD_DRIVER_ALSA']: | |||
audio_adapter_sources += ['../linux/alsa/JackAlsaAdapter.cpp'] | |||
process = create_jack_process_obj(bld, 'audioadapter', audio_adapter_sources, serverlib) | |||
process.uselib = ['ALSA', 'SAMPLERATE'] | |||
process.use = ['ALSA', 'SAMPLERATE'] | |||
if bld.env['BUILD_ADAPTER'] and bld.env['IS_SUN']: | |||
audio_adapter_sources += ['../solaris/oss/JackOSSAdapter.cpp', 'memops.c'] | |||
process = create_jack_process_obj(bld, 'audioadapter', audio_adapter_sources, serverlib) | |||
process.uselib = 'SAMPLERATE' | |||
process.use = 'SAMPLERATE' | |||
#audio_adapter_sources += ['../windows/JackPortAudioAdapter.cpp'] | |||
#process = create_jack_process_obj(bld, 'audioadapter', audio_adapter_sources, serverlib) | |||
bld.install_files('${PREFIX}/include/jack', 'jack/*.h') | |||
bld.install_files('${PREFIX}/include/jack', bld.path.ant_glob('jack/*.h')) | |||
# process jack.pc.in -> jack.pc | |||
import misc | |||
obj = bld.new_task_gen('subst') | |||
obj.source = '../jack.pc.in' | |||
obj.target = 'jack.pc' | |||
obj.dict = {'PREFIX': bld.env['PREFIX'], | |||
'LIBDIR': bld.env['LIBDIR'], | |||
'INCLUDEDIR': os.path.normpath(bld.env['PREFIX'] + '/include'), | |||
'SERVERLIB': serverlib.target, | |||
'JACK_VERSION': bld.env['JACK_VERSION'], | |||
} | |||
obj.install_path = '${LIBDIR}/pkgconfig/' | |||
obj.fun = misc.subst_func | |||
obj = bld( | |||
features = 'subst_pc', | |||
source = '../jack.pc.in', | |||
target = 'jack.pc', | |||
install_path = '${LIBDIR}/pkgconfig/', | |||
INCLUDEDIR = os.path.normpath(bld.env['PREFIX'] + '/include'), | |||
SERVERLIB = serverlib.target, | |||
) |
@@ -26,7 +26,7 @@ | |||
#include "reserve.h" | |||
#include "audio_reserve.h" | |||
#include "JackError.h" | |||
#include "jack/control.h" | |||
#define DEVICE_MAX 2 | |||
@@ -782,7 +782,7 @@ jack_controller_patchbay_disconnect( | |||
ret = jack_disconnect(controller_ptr->client, port1_name, port2_name); | |||
if (ret != 0) | |||
{ | |||
jack_dbus_error(dbus_call_ptr, JACK_DBUS_ERROR_GENERIC, "jack_connect() failed with %d", ret); | |||
jack_dbus_error(dbus_call_ptr, JACK_DBUS_ERROR_GENERIC, "jack_disconnect() failed with %d", ret); | |||
return false; | |||
} | |||
@@ -30,7 +30,7 @@ | |||
#include "jackdbus.h" | |||
#include "controller_internal.h" | |||
#include "jack/session.h" | |||
#include "common/JackError.h" | |||
#include "jack/control.h" | |||
#define JACK_DBUS_IFACE_NAME "org.jackaudio.SessionManager" | |||
@@ -33,7 +33,7 @@ | |||
char * __cxa_demangle(const char * __mangled_name, char * __output_buffer, size_t * __length, int * __status); | |||
#endif | |||
#include "JackError.h" | |||
#include "jack/control.h" | |||
#if defined(REG_RIP) | |||
# define SIGSEGV_STACK_IA64 | |||
@@ -60,6 +60,7 @@ static void signal_segv(int signum, siginfo_t* info, void*ptr) { | |||
static const char *si_codes[3] = {"", "SEGV_MAPERR", "SEGV_ACCERR"}; | |||
size_t i; | |||
const char *si_code_str; | |||
ucontext_t *ucontext = (ucontext_t*)ptr; | |||
#if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64) | |||
@@ -94,9 +95,14 @@ static void signal_segv(int signum, siginfo_t* info, void*ptr) { | |||
jack_error("Unknown bad signal catched!"); | |||
} | |||
if (info->si_code >= 0 && info->si_code < 3) | |||
si_code_str = si_codes[info->si_code]; | |||
else | |||
si_code_str = "unknown"; | |||
jack_error("info.si_signo = %d", signum); | |||
jack_error("info.si_errno = %d", info->si_errno); | |||
jack_error("info.si_code = %d (%s)", info->si_code, si_codes[info->si_code]); | |||
jack_error("info.si_code = %d (%s)", info->si_code, si_code_str); | |||
jack_error("info.si_addr = %p", info->si_addr); | |||
#if !defined(__alpha__) && !defined(__ia64__) && !defined(__FreeBSD_kernel__) && !defined(__arm__) && !defined(__hppa__) && !defined(__sh__) | |||
for(i = 0; i < NGREG; i++) | |||
@@ -171,7 +177,9 @@ int setup_sigsegv() { | |||
memset(&action, 0, sizeof(action)); | |||
action.sa_sigaction = signal_segv; | |||
#ifdef SA_SIGINFO | |||
action.sa_flags = SA_SIGINFO; | |||
#endif | |||
if(sigaction(SIGSEGV, &action, NULL) < 0) { | |||
jack_error("sigaction failed. errno is %d (%s)", errno, strerror(errno)); | |||
return 0; | |||
@@ -6,19 +6,19 @@ import Options | |||
import re # subst_func | |||
import Logs | |||
def set_options(opt): | |||
def options(opt): | |||
opt.add_option('--enable-pkg-config-dbus-service-dir', action='store_true', default=False, help='force D-Bus service install dir to be one returned by pkg-config') | |||
def configure(conf): | |||
conf.env['BUILD_JACKDBUS'] = False | |||
if not conf.check_cfg(package='dbus-1', atleast_version='1.0.0', args='--cflags --libs') or not conf.is_defined('HAVE_DBUS_1'): | |||
print Logs.colors.RED + 'WARNING !! jackdbus will not be built because libdbus-dev is missing' + Logs.colors.NORMAL | |||
print(Logs.colors.RED + 'WARNING !! jackdbus will not be built because libdbus-dev is missing' + Logs.colors.NORMAL) | |||
return | |||
dbus_dir = conf.check_cfg(package='dbus-1', args='--variable=session_bus_services_dir') | |||
if not dbus_dir: | |||
print Logs.colors.RED + 'WARNING !! jackdbus will not be built because service dir is unknown' + Logs.colors.NORMAL | |||
print(Logs.colors.RED + 'WARNING !! jackdbus will not be built because service dir is unknown' + Logs.colors.NORMAL) | |||
return | |||
dbus_dir = dbus_dir.strip() | |||
@@ -29,20 +29,18 @@ def configure(conf): | |||
else: | |||
conf.env['DBUS_SERVICES_DIR'] = os.path.normpath(conf.env['PREFIX'] + '/share/dbus-1/services') | |||
conf.check_tool('misc') | |||
conf.check(header_name='expat.h', define_name="HAVE_EXPAT") | |||
if conf.is_defined('HAVE_EXPAT'): | |||
conf.env['LIB_EXPAT'] = ['expat'] | |||
else: | |||
print Logs.colors.RED + 'WARNING !! jackdbus will not be built because of expat is missing' + Logs.colors.NORMAL | |||
print(Logs.colors.RED + 'WARNING !! jackdbus will not be built because of expat is missing' + Logs.colors.NORMAL) | |||
return | |||
conf.env['BUILD_JACKDBUS'] = True | |||
def build(bld): | |||
obj = bld.new_task_gen('cc', 'program') | |||
obj = bld(features = ['c', 'cprogram'], idx=17) | |||
if bld.env['IS_LINUX']: | |||
sysdeps_dbus_include = ['../linux', '../posix'] | |||
if bld.env['IS_MACOSX']: | |||
@@ -65,20 +63,19 @@ def build(bld): | |||
#'xml_nop.c', | |||
'xml_write_raw.c', | |||
'sigsegv.c', | |||
'reserve.c', | |||
'reserve.c', | |||
] | |||
obj.use = ['serverlib'] | |||
if bld.env['IS_LINUX']: | |||
obj.uselib = 'PTHREAD DL RT DBUS-1 EXPAT' | |||
obj.use += ['PTHREAD', 'DL', 'RT', 'DBUS-1', 'EXPAT'] | |||
if bld.env['IS_MACOSX']: | |||
obj.uselib = 'PTHREAD DL DBUS-1 EXPAT' | |||
obj.uselib_local = 'serverlib' | |||
obj.target = 'jackdbus' | |||
obj.use += ['PTHREAD', 'DL', 'DBUS-1', 'EXPAT'] | |||
obj.target = 'jackdbus' | |||
# process org.jackaudio.service.in -> org.jackaudio.service | |||
import misc | |||
obj = bld.new_task_gen('subst') | |||
obj.source = 'org.jackaudio.service.in' | |||
obj.target = 'org.jackaudio.service' | |||
obj.dict = {'BINDIR': bld.env['PREFIX'] + '/bin'} | |||
obj.install_path = '${DBUS_SERVICES_DIR}/' | |||
obj.fun = misc.subst_func | |||
obj = bld( | |||
features = 'subst', | |||
source = 'org.jackaudio.service.in', | |||
target = 'org.jackaudio.service', | |||
install_path = '${DBUS_SERVICES_DIR}/', | |||
BINDIR = bld.env['PREFIX'] + '/bin') |
@@ -31,7 +31,7 @@ PROJECT_NAME = "Jack2" | |||
# This could be handy for archiving the generated documentation or | |||
# if some version control system is used. | |||
PROJECT_NUMBER = 1.9.8 | |||
PROJECT_NUMBER = 1.9.9 | |||
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) | |||
# base path where the generated documentation will be put. | |||