Commit 66b4bfd8 authored by Stephane Letz's avatar Stephane Letz
Browse files

Support for partial buffers in libjacknet.

parent 7123ef15
......@@ -63,7 +63,8 @@ extern "C"
jack_nframes_t buffer_size;
jack_nframes_t sample_rate;
char master_name[MASTER_NAME_SIZE];
int time_out;
int time_out;
int partial_cycle;
} jack_master_t;
......@@ -112,6 +113,9 @@ extern "C"
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);
LIB_EXPORT int jack_net_master_recv_slice(jack_net_master_t* net, int audio_input, float** audio_input_buffer, int midi_input, void** midi_input_buffer, int frames);
LIB_EXPORT int jack_net_master_send_slice(jack_net_master_t* net, int audio_output, float** audio_output_buffer, int midi_output, void** midi_output_buffer, int frames);
// NetJack adapter API
typedef struct _jack_adapter jack_adapter_t;
......@@ -146,6 +150,8 @@ struct JackNetExtMaster : public JackNetMasterInterface {
jack_master_t fRequest;
int fPacketTimeOut;
JackRingBuffer** fRingBuffer;
JackNetExtMaster(const char* ip,
int port,
......@@ -161,10 +167,19 @@ struct JackNetExtMaster : public JackNetMasterInterface {
fRequest.audio_input = request->audio_input;
fRequest.audio_output = request->audio_output;
fRequest.time_out = request->time_out;
fRequest.partial_cycle = request->partial_cycle;
fRingBuffer = NULL;
}
virtual ~JackNetExtMaster()
{}
{
if (fRingBuffer) {
for (int i = 0; i < fParams.fReturnAudioChannels; i++) {
delete fRingBuffer[i];
}
delete [] fRingBuffer;
}
}
int Open(jack_slave_t* result)
{
......@@ -257,6 +272,14 @@ struct JackNetExtMaster : public JackNetMasterInterface {
result->midi_output = fParams.fReturnMidiChannels;
result->mtu = fParams.fMtu;
result->latency = fParams.fNetworkLatency;
// Use ringbuffer in case of partial cycle and latency > 0
if (fRequest.partial_cycle && result->latency > 0) {
fRingBuffer = new JackRingBuffer*[fParams.fReturnAudioChannels];
for (int i = 0; i < fParams.fReturnAudioChannels; i++) {
fRingBuffer[i] = new JackRingBuffer(fRequest.buffer_size * result->latency * 2);
}
}
return 0;
error:
......@@ -332,10 +355,13 @@ struct JackNetExtMaster : public JackNetMasterInterface {
return 0;
}
int Read(int audio_input, float** audio_input_buffer, int midi_input, void** midi_input_buffer)
int Read(int audio_input, float** audio_input_buffer, int midi_input, void** midi_input_buffer, int frames)
{
try {
if (frames < 0) frames = fParams.fPeriodSize;
int cycle_size;
assert(audio_input == fParams.fReturnAudioChannels);
for (int audio_port_index = 0; audio_port_index < audio_input; audio_port_index++) {
......@@ -346,18 +372,25 @@ struct JackNetExtMaster : public JackNetMasterInterface {
fNetMidiPlaybackBuffer->SetBuffer(midi_port_index, ((JackMidiBuffer**)midi_input_buffer)[midi_port_index]);
}
int res = SyncRecv();
switch (res) {
int res1 = SyncRecv();
switch (res1) {
case NET_SYNCHING:
// Data will not be received, so cleanup buffers...
for (int audio_port_index = 0; audio_port_index < audio_input; audio_port_index++) {
memset(audio_input_buffer[audio_port_index], 0, sizeof(float) * fParams.fPeriodSize);
memset(audio_input_buffer[audio_port_index], 0, sizeof(float) * fParams.fPeriodSize);
}
// Possibly use ringbuffer...
if (fRingBuffer) {
for (int i = 0; i < audio_input; i++) {
fRingBuffer[i]->Write(audio_input_buffer[i], fParams.fPeriodSize);
fRingBuffer[i]->Read(audio_input_buffer[i], frames);
}
}
return res;
return res1;
case SOCKET_ERROR:
return res;
return res1;
case SYNC_PACKET_ERROR:
// since sync packet is incorrect, don't decode it and continue with data
......@@ -365,11 +398,20 @@ struct JackNetExtMaster : public JackNetMasterInterface {
default:
// decode sync
DecodeSyncPacket();
cycle_size;
DecodeSyncPacket(cycle_size);
break;
}
return DataRecv();
int res2 = DataRecv();
// Possibly use ringbuffer...
if (res2 == 0 && fRingBuffer) {
for (int i = 0; i < audio_input; i++) {
fRingBuffer[i]->Write(audio_input_buffer[i], cycle_size);
fRingBuffer[i]->Read(audio_input_buffer[i], frames);
}
}
return res2;
} catch (JackNetException& e) {
jack_error("Lost connection");
......@@ -377,9 +419,11 @@ struct JackNetExtMaster : public JackNetMasterInterface {
}
}
int Write(int audio_output, float** audio_output_buffer, int midi_output, void** midi_output_buffer)
int Write(int audio_output, float** audio_output_buffer, int midi_output, void** midi_output_buffer, int frames)
{
try {
if (frames < 0) frames = fParams.fPeriodSize;
assert(audio_output == fParams.fSendAudioChannels);
......@@ -391,8 +435,8 @@ struct JackNetExtMaster : public JackNetMasterInterface {
fNetMidiCaptureBuffer->SetBuffer(midi_port_index, ((JackMidiBuffer**)midi_output_buffer)[midi_port_index]);
}
EncodeSyncPacket();
EncodeSyncPacket(frames);
// send sync
if (SyncSend() == SOCKET_ERROR) {
return SOCKET_ERROR;
......@@ -402,7 +446,6 @@ struct JackNetExtMaster : public JackNetMasterInterface {
if (DataSend() == SOCKET_ERROR) {
return SOCKET_ERROR;
}
return 0;
} catch (JackNetException& e) {
......@@ -450,6 +493,7 @@ struct JackNetExtSlave : public JackNetSlaveInterface, public JackRunnableInterf
void* fSampleRateArg;
int fConnectTimeOut;
int fCycleSize;
JackNetExtSlave(const char* ip,
int port,
......@@ -610,8 +654,8 @@ struct JackNetExtSlave : public JackNetSlaveInterface, public JackRunnableInterf
return -1;
}
// Set result
if (result != NULL) {
// Set result
if (result != NULL) {
result->buffer_size = fParams.fPeriodSize;
result->sample_rate = fParams.fSampleRate;
result->audio_input = fParams.fSendAudioChannels;
......@@ -620,7 +664,10 @@ struct JackNetExtSlave : public JackNetSlaveInterface, public JackRunnableInterf
result->midi_output = fParams.fReturnMidiChannels;
strcpy(result->master_name, fParams.fMasterNetName);
}
// By default fCycleSize is fPeriodSize
fCycleSize = fParams.fPeriodSize;
AllocPorts();
return 0;
}
......@@ -711,7 +758,7 @@ struct JackNetExtSlave : public JackNetSlaveInterface, public JackRunnableInterf
bool Execute()
{
try {
try {
/*
Fist cycle use an INT_MAX time out, so that connection
is considered established (with PACKET_TIMEOUT later on)
......@@ -758,7 +805,7 @@ struct JackNetExtSlave : public JackNetSlaveInterface, public JackRunnableInterf
default:
// decode sync
DecodeSyncPacket();
DecodeSyncPacket(fCycleSize);
break;
}
......@@ -768,11 +815,11 @@ struct JackNetExtSlave : public JackNetSlaveInterface, public JackRunnableInterf
}
return res;
}
int Write()
{
EncodeSyncPacket();
EncodeSyncPacket(fCycleSize);
if (SyncSend() == SOCKET_ERROR) {
return SOCKET_ERROR;
}
......@@ -798,8 +845,8 @@ struct JackNetExtSlave : public JackNetSlaveInterface, public JackRunnableInterf
if (Read() == SOCKET_ERROR) {
return SOCKET_ERROR;
}
fProcessCallback(fParams.fPeriodSize,
fProcessCallback(fCycleSize,
fParams.fSendAudioChannels,
fAudioCaptureBuffer,
fParams.fSendMidiChannels,
......@@ -809,7 +856,7 @@ struct JackNetExtSlave : public JackNetSlaveInterface, public JackRunnableInterf
fParams.fReturnMidiChannels,
(void**)fMidiPlaybackBuffer,
fProcessArg);
// Then write data to network, throw JackNetException in case of network error...
if (Write() == SOCKET_ERROR) {
return SOCKET_ERROR;
......@@ -1068,13 +1115,25 @@ LIB_EXPORT int jack_net_master_close(jack_net_master_t* net)
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);
return master->Read(audio_input, audio_input_buffer, midi_input, midi_input_buffer, -1);
}
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);
return master->Write(audio_output, audio_output_buffer, midi_output, midi_output_buffer, -1);
}
LIB_EXPORT int jack_net_master_recv_slice(jack_net_master_t* net, int audio_input, float** audio_input_buffer, int midi_input, void** midi_input_buffer, int frames)
{
JackNetExtMaster* master = (JackNetExtMaster*)net;
return master->Read(audio_input, audio_input_buffer, midi_input, midi_input_buffer, frames);
}
LIB_EXPORT int jack_net_master_send_slice(jack_net_master_t* net, int audio_output, float** audio_output_buffer, int midi_output, void** midi_output_buffer, int frames)
{
JackNetExtMaster* master = (JackNetExtMaster*)net;
return master->Write(audio_output, audio_output_buffer, midi_output, midi_output_buffer, frames);
}
// Adapter API
......
......@@ -361,7 +361,8 @@ namespace Jack
default:
//decode sync
DecodeSyncPacket();
int unused_cycle_size;
DecodeSyncPacket(unused_cycle_size);
break;
}
......
......@@ -575,7 +575,8 @@ namespace Jack
default:
// decode sync
DecodeSyncPacket();
int unused_cycle_size;
DecodeSyncPacket(unused_cycle_size);
break;
}
......@@ -724,8 +725,8 @@ Deactivated for now..
int mtu = DEFAULT_MTU;
// Desactivated for now...
uint transport_sync = 0;
jack_nframes_t period_size = 1024;
jack_nframes_t sample_rate = 48000;
jack_nframes_t period_size = 1024; // to be used while waiting for master period_size
jack_nframes_t sample_rate = 48000; // to be used while waiting for master sample_rate
int audio_capture_ports = -1;
int audio_playback_ports = -1;
int midi_input_ports = -1;
......
......@@ -544,7 +544,7 @@ namespace Jack
return rx_bytes;
}
void JackNetMasterInterface::EncodeSyncPacket()
void JackNetMasterInterface::EncodeSyncPacket(int cycle_size)
{
// This method contains every step of sync packet informations coding
// first of all, clear sync packet
......@@ -565,9 +565,10 @@ namespace Jack
// Write active ports list
fTxHeader.fActivePorts = (fNetAudioPlaybackBuffer) ? fNetAudioPlaybackBuffer->ActivePortsToNetwork(fTxData) : 0;
fTxHeader.fCycleSize = cycle_size;
}
void JackNetMasterInterface::DecodeSyncPacket()
void JackNetMasterInterface::DecodeSyncPacket(int& cycle_size)
{
// This method contains every step of sync packet informations decoding process
......@@ -590,6 +591,8 @@ namespace Jack
if (fNetAudioCaptureBuffer) {
fNetAudioCaptureBuffer->ActivePortsFromNetwork(fRxData, rx_head->fActivePorts);
}
cycle_size = rx_head->fCycleSize;
}
// JackNetSlaveInterface ************************************************************************************************
......@@ -946,7 +949,7 @@ namespace Jack
}
// network sync------------------------------------------------------------------------
void JackNetSlaveInterface::EncodeSyncPacket()
void JackNetSlaveInterface::EncodeSyncPacket(int cycle_size)
{
// This method contains every step of sync packet informations coding
// first of all, clear sync packet
......@@ -967,9 +970,10 @@ namespace Jack
// Write active ports list
fTxHeader.fActivePorts = (fNetAudioCaptureBuffer) ? fNetAudioCaptureBuffer->ActivePortsToNetwork(fTxData) : 0;
fTxHeader.fCycleSize = cycle_size;
}
void JackNetSlaveInterface::DecodeSyncPacket()
void JackNetSlaveInterface::DecodeSyncPacket(int& cycle_size)
{
// This method contains every step of sync packet informations decoding process
......@@ -992,6 +996,8 @@ namespace Jack
if (fNetAudioPlaybackBuffer) {
fNetAudioPlaybackBuffer->ActivePortsFromNetwork(fRxData, rx_head->fActivePorts);
}
cycle_size = rx_head->fCycleSize;
}
}
......@@ -92,8 +92,8 @@ namespace Jack
virtual void DecodeTransportData() = 0;
// sync packet
virtual void EncodeSyncPacket() = 0;
virtual void DecodeSyncPacket() = 0;
virtual void EncodeSyncPacket(int cycle_size = -1) = 0;
virtual void DecodeSyncPacket(int& cycle_size) = 0;
virtual int SyncRecv() = 0;
virtual int SyncSend() = 0;
......@@ -160,8 +160,8 @@ namespace Jack
int DataSend();
// sync packet
void EncodeSyncPacket();
void DecodeSyncPacket();
void EncodeSyncPacket(int cycle_size = -1);
void DecodeSyncPacket(int& cycle_size);
int Send(size_t size, int flags);
int Recv(size_t size, int flags);
......@@ -217,8 +217,8 @@ namespace Jack
int DataSend();
// sync packet
void EncodeSyncPacket();
void DecodeSyncPacket();
void EncodeSyncPacket(int cycle_size = -1);
void DecodeSyncPacket(int& cycle_size);
int Recv(size_t size, int flags);
int Send(size_t size, int flags);
......
......@@ -543,7 +543,8 @@ namespace Jack
default:
// Decode sync
DecodeSyncPacket();
int unused_cycle_size;
DecodeSyncPacket(unused_cycle_size);
break;
}
......
......@@ -1216,6 +1216,7 @@ namespace Jack
dst_header->fActivePorts = htonl(src_header->fActivePorts);
dst_header->fCycle = htonl(src_header->fCycle);
dst_header->fSubCycle = htonl(src_header->fSubCycle);
dst_header->fCycleSize = htonl(src_header->fCycleSize);
dst_header->fIsLastPckt = htonl(src_header->fIsLastPckt);
}
......@@ -1230,6 +1231,7 @@ namespace Jack
dst_header->fActivePorts = ntohl(src_header->fActivePorts);
dst_header->fCycle = ntohl(src_header->fCycle);
dst_header->fSubCycle = ntohl(src_header->fSubCycle);
dst_header->fCycleSize = ntohl(src_header->fCycleSize);
dst_header->fIsLastPckt = ntohl(src_header->fIsLastPckt);
}
......
......@@ -38,7 +38,7 @@ using namespace std;
#endif
#endif
#define NETWORK_PROTOCOL 7
#define NETWORK_PROTOCOL 8
#define NET_SYNCHING 0
#define SYNC_PACKET_ERROR -2
......@@ -180,6 +180,7 @@ namespace Jack
uint32_t fActivePorts; //number of active ports
uint32_t fCycle; //process cycle counter
uint32_t fSubCycle; //midi/audio subcycle counter
int32_t fCycleSize; //process cycle size in frames
uint32_t fIsLastPckt; //is it the last packet of a given cycle ('y' or 'n')
} POST_PACKED_STRUCTURE;
......
......@@ -24,45 +24,44 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
namespace Jack
{
JackResampler::JackResampler()
:fRatio(1), fRingBufferSize(DEFAULT_RB_SIZE)
JackRingBuffer::JackRingBuffer(int size):fRingBufferSize(size)
{
fRingBuffer = jack_ringbuffer_create(sizeof(jack_default_audio_sample_t) * fRingBufferSize);
jack_ringbuffer_read_advance(fRingBuffer, (sizeof(jack_default_audio_sample_t) * fRingBufferSize) / 2);
Reset(fRingBufferSize);
}
JackResampler::~JackResampler()
JackRingBuffer::~JackRingBuffer()
{
if (fRingBuffer) {
jack_ringbuffer_free(fRingBuffer);
}
}
void JackResampler::Reset(unsigned int new_size)
void JackRingBuffer::Reset(unsigned int new_size)
{
fRingBufferSize = new_size;
jack_ringbuffer_reset(fRingBuffer);
jack_ringbuffer_reset_size(fRingBuffer, sizeof(jack_default_audio_sample_t) * fRingBufferSize);
jack_ringbuffer_read_advance(fRingBuffer, (sizeof(jack_default_audio_sample_t) * fRingBufferSize / 2));
jack_ringbuffer_read_advance(fRingBuffer, (sizeof(jack_default_audio_sample_t) * new_size/2));
}
unsigned int JackResampler::ReadSpace()
unsigned int JackRingBuffer::ReadSpace()
{
return (jack_ringbuffer_read_space(fRingBuffer) / sizeof(jack_default_audio_sample_t));
}
unsigned int JackResampler::WriteSpace()
unsigned int JackRingBuffer::WriteSpace()
{
return (jack_ringbuffer_write_space(fRingBuffer) / sizeof(jack_default_audio_sample_t));
}
unsigned int JackResampler::Read(jack_default_audio_sample_t* buffer, unsigned int frames)
unsigned int JackRingBuffer::Read(jack_default_audio_sample_t* buffer, unsigned int frames)
{
size_t len = jack_ringbuffer_read_space(fRingBuffer);
jack_log("JackResampler::Read input available = %ld", len / sizeof(jack_default_audio_sample_t));
jack_log("JackRingBuffer::Read input available = %ld", len / sizeof(jack_default_audio_sample_t));
if (len < frames * sizeof(jack_default_audio_sample_t)) {
jack_error("JackResampler::Read : producer too slow, missing frames = %d", frames);
jack_error("JackRingBuffer::Read : producer too slow, missing frames = %d", frames);
return 0;
} else {
jack_ringbuffer_read(fRingBuffer, (char*)buffer, frames * sizeof(jack_default_audio_sample_t));
......@@ -70,13 +69,13 @@ unsigned int JackResampler::Read(jack_default_audio_sample_t* buffer, unsigned i
}
}
unsigned int JackResampler::Write(jack_default_audio_sample_t* buffer, unsigned int frames)
unsigned int JackRingBuffer::Write(jack_default_audio_sample_t* buffer, unsigned int frames)
{
size_t len = jack_ringbuffer_write_space(fRingBuffer);
jack_log("JackResampler::Write output available = %ld", len / sizeof(jack_default_audio_sample_t));
jack_log("JackRingBuffer::Write output available = %ld", len / sizeof(jack_default_audio_sample_t));
if (len < frames * sizeof(jack_default_audio_sample_t)) {
jack_error("JackResampler::Write : consumer too slow, skip frames = %d", frames);
jack_error("JackRingBuffer::Write : consumer too slow, skip frames = %d", frames);
return 0;
} else {
jack_ringbuffer_write(fRingBuffer, (char*)buffer, frames * sizeof(jack_default_audio_sample_t));
......@@ -84,13 +83,13 @@ unsigned int JackResampler::Write(jack_default_audio_sample_t* buffer, unsigned
}
}
unsigned int JackResampler::Read(void* buffer, unsigned int bytes)
unsigned int JackRingBuffer::Read(void* buffer, unsigned int bytes)
{
size_t len = jack_ringbuffer_read_space(fRingBuffer);
jack_log("JackResampler::Read input available = %ld", len);
jack_log("JackRingBuffer::Read input available = %ld", len);
if (len < bytes) {
jack_error("JackResampler::Read : producer too slow, missing bytes = %d", bytes);
jack_error("JackRingBuffer::Read : producer too slow, missing bytes = %d", bytes);
return 0;
} else {
jack_ringbuffer_read(fRingBuffer, (char*)buffer, bytes);
......@@ -98,13 +97,13 @@ unsigned int JackResampler::Read(void* buffer, unsigned int bytes)
}
}
unsigned int JackResampler::Write(void* buffer, unsigned int bytes)
unsigned int JackRingBuffer::Write(void* buffer, unsigned int bytes)
{
size_t len = jack_ringbuffer_write_space(fRingBuffer);
jack_log("JackResampler::Write output available = %ld", len);
jack_log("JackRingBuffer::Write output available = %ld", len);
if (len < bytes) {
jack_error("JackResampler::Write : consumer too slow, skip bytes = %d", bytes);
jack_error("JackRingBuffer::Write : consumer too slow, skip bytes = %d", bytes);
return 0;
} else {
jack_ringbuffer_write(fRingBuffer, (char*)buffer, bytes);
......
......@@ -35,34 +35,33 @@ inline float Range(float min, float max, float val)
}
/*!
\brief Base class for Resampler.
\brief Base class for RingBuffer in frames.
*/
class JackResampler
class JackRingBuffer
{
protected:
jack_ringbuffer_t* fRingBuffer;
double fRatio;
unsigned int fRingBufferSize;
public:
JackResampler();
virtual ~JackResampler();
JackRingBuffer(int size = DEFAULT_RB_SIZE);
virtual ~JackRingBuffer();
virtual void Reset(unsigned int new_size);
virtual unsigned int ReadResample(jack_default_audio_sample_t* buffer, unsigned int frames);
virtual unsigned int WriteResample(jack_default_audio_sample_t* buffer, unsigned int frames);
// in frames
virtual unsigned int Read(jack_default_audio_sample_t* buffer, unsigned int frames);
virtual unsigned int Write(jack_default_audio_sample_t* buffer, unsigned int frames);
// in bytes
virtual unsigned int Read(void* buffer, unsigned int bytes);
virtual unsigned int Write(void* buffer, unsigned int bytes);
// in frames
virtual unsigned int ReadSpace();
virtual unsigned int WriteSpace();
......@@ -71,6 +70,29 @@ class JackResampler
return (jack_ringbuffer_read_space(fRingBuffer) / sizeof(float)) - (fRingBufferSize / 2);
}
};
/*!
\brief Base class for Resampler.
*/
class JackResampler : public JackRingBuffer
{
protected:
double fRatio;
public:
JackResampler():JackRingBuffer(),fRatio(1)
{}
virtual ~JackResampler()
{}
virtual unsigned int ReadResample(jack_default_audio_sample_t* buffer, unsigned int frames);
virtual unsigned int WriteResample(jack_default_audio_sample_t* buffer, unsigned int frames);
void SetRatio(double ratio)
{
fRatio = Range(0.25, 4.0, ratio);
......
......@@ -75,6 +75,7 @@ typedef struct {
jack_nframes_t sample_rate; // master sample rate
char master_name[MASTER_NAME_SIZE]; // master machine name
int time_out; // in second, -1 means infinite
int partial_cycle; // if 'true', partial cycle will be used
} jack_master_t;