|
- /*
- Copyright (C) 2009-2013 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 <assert.h>
- #include <stdarg.h>
-
- #include "JackNetInterface.h"
- #include "JackAudioAdapterInterface.h"
-
- #ifdef __cplusplus
- extern "C"
- {
- #endif
-
- // NetJack common API
-
- #define MASTER_NAME_SIZE 256
-
- enum JackNetEncoder {
-
- JackFloatEncoder = 0,
- JackIntEncoder = 1,
- JackCeltEncoder = 2,
- JackOpusEncoder = 3
- };
-
- typedef struct {
-
- int audio_input;
- int audio_output;
- int midi_input;
- int midi_output;
- int mtu;
- int time_out; // in millisecond, -1 means in infinite
- int encoder; // one of JackNetEncoder
- int kbps; // KB per second for CELT encoder
- int latency; // network cycles
-
- } jack_slave_t;
-
- typedef struct {
-
- int audio_input;
- int audio_output;
- int midi_input;
- int midi_output;
- jack_nframes_t buffer_size;
- jack_nframes_t sample_rate;
- char master_name[MASTER_NAME_SIZE];
- int time_out;
- int partial_cycle;
-
- } jack_master_t;
-
- // NetJack slave API
-
- typedef struct _jack_net_slave jack_net_slave_t;
-
- typedef int (* JackNetSlaveProcessCallback) (jack_nframes_t buffer_size,
- int audio_input,
- float** audio_input_buffer,
- int midi_input,
- void** midi_input_buffer,
- int audio_output,
- float** audio_output_buffer,
- int midi_output,
- void** midi_output_buffer,
- void* data);
-
- typedef int (*JackNetSlaveBufferSizeCallback) (jack_nframes_t nframes, void *arg);
- typedef int (*JackNetSlaveSampleRateCallback) (jack_nframes_t nframes, void *arg);
- typedef void (*JackNetSlaveShutdownCallback) (void* arg);
- typedef int (*JackNetSlaveRestartCallback) (void* arg);
- typedef void (*JackNetSlaveErrorCallback) (int error_code, void* arg);
-
- 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);
-
- LIB_EXPORT int jack_net_slave_activate(jack_net_slave_t* net);
- LIB_EXPORT int jack_net_slave_deactivate(jack_net_slave_t* net);
- LIB_EXPORT int jack_net_slave_is_active(jack_net_slave_t* net);
-
- 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);
- LIB_EXPORT int jack_set_net_slave_restart_callback(jack_net_slave_t* net, JackNetSlaveRestartCallback restart_callback, void *arg);
- LIB_EXPORT int jack_set_net_slave_error_callback(jack_net_slave_t* net, JackNetSlaveErrorCallback error_callback, void *arg);
-
- // NetJack master API
-
- typedef struct _jack_net_master jack_net_master_t;
-
- LIB_EXPORT jack_net_master_t* jack_net_master_open(const char* ip, int port, jack_master_t* request, jack_slave_t* result);
- 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);
- 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;
-
- 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);
- 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);
-
- #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
- }
- #endif
-
- namespace Jack
- {
-
- struct JackNetExtMaster : public JackNetMasterInterface {
-
- jack_master_t fRequest;
-
- JackRingBuffer** fRingBuffer;
-
- JackNetExtMaster(const char* ip,
- int port,
- jack_master_t* request)
- {
- fRunning = true;
- assert(strlen(ip) < 32);
- strcpy(fMulticastIP, ip);
- 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;
- 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)
- {
- // Check buffer_size
- if (fRequest.buffer_size == 0) {
- jack_error("Incorrect buffer_size...");
- return -1;
- }
- // Check sample_rate
- if (fRequest.sample_rate == 0) {
- jack_error("Incorrect sample_rate...");
- return -1;
- }
-
- // Init socket API (win32)
- if (SocketAPIInit() < 0) {
- jack_error("Can't init Socket API, exiting...");
- return -1;
- }
-
- // Request socket
- if (fSocket.NewSocket() == SOCKET_ERROR) {
- jack_error("Can't create the network manager input socket : %s", StrError(NET_ERROR_CODE));
- return -1;
- }
-
- // Bind the socket to the local port
- if (fSocket.Bind() == SOCKET_ERROR) {
- jack_error("Can't bind the network manager socket : %s", StrError(NET_ERROR_CODE));
- fSocket.Close();
- return -1;
- }
-
- // Join multicast group
- if (fSocket.JoinMCastGroup(fMulticastIP) == SOCKET_ERROR) {
- jack_error("Can't join multicast group : %s", StrError(NET_ERROR_CODE));
- }
-
- // Local loop
- if (fSocket.SetLocalLoop() == SOCKET_ERROR) {
- jack_error("Can't set local loop : %s", StrError(NET_ERROR_CODE));
- }
-
- // Set a timeout on the multicast receive (the thread can now be cancelled)
- if (fSocket.SetTimeOut(MANAGER_INIT_TIMEOUT) == SOCKET_ERROR) {
- jack_error("Can't set timeout : %s", StrError(NET_ERROR_CODE));
- }
-
- // Main loop, wait for data, deal with it and wait again
- int attempt = 0;
- int rx_bytes = 0;
- int try_count = (fRequest.time_out > 0) ? int((1000000.f * float(fRequest.time_out)) / float(MANAGER_INIT_TIMEOUT)) : INT_MAX;
-
- do
- {
- session_params_t net_params;
- rx_bytes = fSocket.CatchHost(&net_params, sizeof(session_params_t), 0);
- SessionParamsNToH(&net_params, &fParams);
-
- if ((rx_bytes == SOCKET_ERROR) && (fSocket.GetError() != NET_NO_DATA)) {
- jack_error("Error in receive : %s", StrError(NET_ERROR_CODE));
- if (++attempt == 10) {
- jack_error("Can't receive on the socket, exiting net manager" );
- goto error;
- }
- }
-
- if (rx_bytes == sizeof(session_params_t)) {
- switch (GetPacketType(&fParams)) {
-
- case SLAVE_AVAILABLE:
- if (InitMaster(result) == 0) {
- SessionParamsDisplay(&fParams);
- fRunning = false;
- } else {
- jack_error("Can't init new net master...");
- goto error;
- }
- jack_info("Waiting for a slave...");
- break;
-
- case KILL_MASTER:
- break;
-
- default:
- break;
- }
- }
- }
- while (fRunning && (--try_count > 0));
-
- if (try_count == 0) {
- jack_error("Time out error in connect");
- return -1;
- }
-
- // Set result parameters
- result->audio_input = fParams.fSendAudioChannels;
- result->audio_output = fParams.fReturnAudioChannels;
- result->midi_input = fParams.fSendMidiChannels;
- 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:
- fSocket.Close();
- return -1;
- }
-
- int InitMaster(jack_slave_t* result)
- {
- // Check MASTER <==> SLAVE network protocol coherency
- if (fParams.fProtocolVersion != NETWORK_PROTOCOL) {
- jack_error("Error : slave '%s' is running with a different protocol %d != %d", fParams.fName, fParams.fProtocolVersion, NETWORK_PROTOCOL);
- return -1;
- }
-
- // Settings
- fSocket.GetName(fParams.fMasterNetName);
- fParams.fID = 1;
- 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 init
- if (!JackNetMasterInterface::Init()) {
- return -1;
- }
-
- // Set global parameters
- if (!SetParams()) {
- return -1;
- }
-
- return 0;
- }
-
- int Close()
- {
- fSocket.Close();
- return 0;
- }
-
- void UseRingBuffer(int audio_input, float** audio_input_buffer, int write, int read)
- {
- // Possibly use ringbuffer...
- if (fRingBuffer) {
- for (int i = 0; i < audio_input; i++) {
- fRingBuffer[i]->Write(audio_input_buffer[i], write);
- fRingBuffer[i]->Read(audio_input_buffer[i], read);
- }
- }
- }
-
- int Read(int audio_input, float** audio_input_buffer, int midi_input, void** midi_input_buffer, int frames)
- {
- try {
-
- // frames = -1 means : entire buffer
- if (frames < 0) frames = fParams.fPeriodSize;
-
- int read_frames = 0;
- assert(audio_input == fParams.fReturnAudioChannels);
-
- for (int audio_port_index = 0; audio_port_index < audio_input; audio_port_index++) {
- assert(audio_input_buffer[audio_port_index]);
- fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, audio_input_buffer[audio_port_index]);
- }
-
- for (int midi_port_index = 0; midi_port_index < midi_input; midi_port_index++) {
- assert(((JackMidiBuffer**)midi_input_buffer)[midi_port_index]);
- fNetMidiPlaybackBuffer->SetBuffer(midi_port_index, ((JackMidiBuffer**)midi_input_buffer)[midi_port_index]);
- }
-
- 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);
- }
- UseRingBuffer(audio_input, audio_input_buffer, fParams.fPeriodSize, frames);
- return res1;
-
- case SOCKET_ERROR:
- return res1;
-
- case SYNC_PACKET_ERROR:
- // since sync packet is incorrect, don't decode it and continue with data
- break;
-
- default:
- // decode sync
- DecodeSyncPacket(read_frames);
- break;
- }
-
- int res2 = DataRecv();
- UseRingBuffer(audio_input, audio_input_buffer, read_frames, frames);
- return res2;
-
- } catch (JackNetException& e) {
- jack_error(e.what());
- return -1;
- }
- }
-
- int Write(int audio_output, float** audio_output_buffer, int midi_output, void** midi_output_buffer, int frames)
- {
- try {
-
- // frames = -1 means : entire buffer
- if (frames < 0) frames = fParams.fPeriodSize;
-
- assert(audio_output == fParams.fSendAudioChannels);
-
- for (int audio_port_index = 0; audio_port_index < audio_output; audio_port_index++) {
- assert(audio_output_buffer[audio_port_index]);
- fNetAudioCaptureBuffer->SetBuffer(audio_port_index, audio_output_buffer[audio_port_index]);
- }
-
- for (int midi_port_index = 0; midi_port_index < midi_output; midi_port_index++) {
- assert(((JackMidiBuffer**)midi_output_buffer)[midi_port_index]);
- fNetMidiCaptureBuffer->SetBuffer(midi_port_index, ((JackMidiBuffer**)midi_output_buffer)[midi_port_index]);
- }
-
- EncodeSyncPacket(frames);
-
- // send sync
- if (SyncSend() == SOCKET_ERROR) {
- return SOCKET_ERROR;
- }
-
- // send data
- if (DataSend() == SOCKET_ERROR) {
- return SOCKET_ERROR;
- }
- return 0;
-
- } catch (JackNetException& e) {
- jack_error(e.what());
- return -1;
- }
- }
-
- // Transport
- void EncodeTransportData()
- {}
-
- void DecodeTransportData()
- {}
-
- };
-
- struct JackNetExtSlave : public JackNetSlaveInterface, public JackRunnableInterface {
-
- // Data buffers
- float** fAudioCaptureBuffer;
- float** fAudioPlaybackBuffer;
-
- JackMidiBuffer** fMidiCaptureBuffer;
- JackMidiBuffer** fMidiPlaybackBuffer;
-
- JackThread fThread;
-
- JackNetSlaveProcessCallback fProcessCallback;
- void* fProcessArg;
-
- JackNetSlaveShutdownCallback fShutdownCallback;
- void* fShutdownArg;
-
- JackNetSlaveRestartCallback fRestartCallback;
- void* fRestartArg;
-
- JackNetSlaveErrorCallback fErrorCallback;
- void* fErrorArg;
-
- JackNetSlaveBufferSizeCallback fBufferSizeCallback;
- void* fBufferSizeArg;
-
- JackNetSlaveSampleRateCallback fSampleRateCallback;
- void* fSampleRateArg;
-
- int fConnectTimeOut;
- int fFrames;
-
- JackNetExtSlave(const char* ip,
- int port,
- const char* name,
- jack_slave_t* request)
- :fThread(this),
- fProcessCallback(NULL),fProcessArg(NULL),
- fShutdownCallback(NULL), fShutdownArg(NULL),
- fRestartCallback(NULL), fRestartArg(NULL),
- fErrorCallback(NULL), fErrorArg(NULL),
- fBufferSizeCallback(NULL), fBufferSizeArg(NULL),
- fSampleRateCallback(NULL), fSampleRateArg(NULL)
- {
- char host_name[JACK_CLIENT_NAME_SIZE + 1];
-
- // Request parameters
- assert(strlen(ip) < 32);
- strcpy(fMulticastIP, ip);
- fParams.fMtu = request->mtu;
- fParams.fTransportSync = 0;
- fParams.fSendAudioChannels = request->audio_input;
- fParams.fReturnAudioChannels = request->audio_output;
- fParams.fSendMidiChannels = request->midi_input;
- fParams.fReturnMidiChannels = request->midi_output;
- fParams.fNetworkLatency = request->latency;
- fParams.fSampleEncoder = request->encoder;
- fParams.fKBps = request->kbps;
- fParams.fSlaveSyncMode = 1;
- fConnectTimeOut = request->time_out;
-
- // Create name with hostname and client name
- GetHostName(host_name, JACK_CLIENT_NAME_SIZE);
- snprintf(fParams.fName, JACK_CLIENT_NAME_SIZE, "%s_%s", host_name, name);
- fSocket.GetName(fParams.fSlaveNetName);
-
- // Set the socket parameters
- fSocket.SetPort(port);
- fSocket.SetAddress(fMulticastIP, port);
-
- fAudioCaptureBuffer = NULL;
- fAudioPlaybackBuffer = NULL;
- fMidiCaptureBuffer = NULL;
- fMidiPlaybackBuffer = NULL;
- }
-
- virtual ~JackNetExtSlave()
- {}
-
- void AllocPorts()
- {
- // Set buffers
- if (fParams.fSendAudioChannels > 0) {
- fAudioCaptureBuffer = new float*[fParams.fSendAudioChannels];
- for (int audio_port_index = 0; audio_port_index < fParams.fSendAudioChannels; audio_port_index++) {
- fAudioCaptureBuffer[audio_port_index] = new float[fParams.fPeriodSize];
- memset(fAudioCaptureBuffer[audio_port_index], 0, sizeof(float) * fParams.fPeriodSize);
- fNetAudioCaptureBuffer->SetBuffer(audio_port_index, fAudioCaptureBuffer[audio_port_index]);
- }
- }
-
- if (fParams.fSendMidiChannels > 0) {
- fMidiCaptureBuffer = new JackMidiBuffer*[fParams.fSendMidiChannels];
- for (int midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
- fMidiCaptureBuffer[midi_port_index] = (JackMidiBuffer*)new float[fParams.fPeriodSize];
- memset(fMidiCaptureBuffer[midi_port_index], 0, sizeof(float) * fParams.fPeriodSize);
- fNetMidiCaptureBuffer->SetBuffer(midi_port_index, fMidiCaptureBuffer[midi_port_index]);
- }
- }
-
- if (fParams.fReturnAudioChannels > 0) {
- fAudioPlaybackBuffer = new float*[fParams.fReturnAudioChannels];
- for (int audio_port_index = 0; audio_port_index < fParams.fReturnAudioChannels; audio_port_index++) {
- fAudioPlaybackBuffer[audio_port_index] = new float[fParams.fPeriodSize];
- memset(fAudioPlaybackBuffer[audio_port_index], 0, sizeof(float) * fParams.fPeriodSize);
- fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, fAudioPlaybackBuffer[audio_port_index]);
- }
- }
-
- if (fParams.fReturnMidiChannels > 0) {
- fMidiPlaybackBuffer = new JackMidiBuffer*[fParams.fReturnMidiChannels];
- for (int midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
- fMidiPlaybackBuffer[midi_port_index] = (JackMidiBuffer*)new float[fParams.fPeriodSize];
- memset(fMidiPlaybackBuffer[midi_port_index], 0, sizeof(float) * fParams.fPeriodSize);
- fNetMidiPlaybackBuffer->SetBuffer(midi_port_index, fMidiPlaybackBuffer[midi_port_index]);
- }
- }
- }
-
- void FreePorts()
- {
- if (fAudioCaptureBuffer) {
- 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++) {
- 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++) {
- 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++) {
- delete[] (fMidiPlaybackBuffer[midi_port_index]);
- }
- delete[] fMidiPlaybackBuffer;
- fMidiPlaybackBuffer = NULL;
- }
- }
-
- int Open(jack_master_t* result)
- {
- // Check audio/midi parameters
- if (fParams.fSendAudioChannels == 0
- && fParams.fReturnAudioChannels == 0
- && fParams.fSendMidiChannels == 0
- && fParams.fReturnMidiChannels == 0) {
- jack_error("Incorrect audio/midi channels number...");
- return -1;
- }
-
- // Check MTU parameters
- if ((fParams.fMtu < DEFAULT_MTU) && (fParams.fMtu > MAX_MTU)) {
- jack_error("MTU is not in the expected range [%d ... %d]", DEFAULT_MTU, MAX_MTU);
- return -1;
- }
-
- // Check CELT encoder parameters
- if ((fParams.fSampleEncoder == JackCeltEncoder) && (fParams.fKBps == 0)) {
- jack_error("CELT encoder with 0 for kps...");
- return -1;
- }
-
- if ((fParams.fSampleEncoder == JackOpusEncoder) && (fParams.fKBps == 0)) {
- jack_error("Opus encoder with 0 for kps...");
- return -1;
- }
-
- // Check latency
- if (fParams.fNetworkLatency > NETWORK_MAX_LATENCY) {
- jack_error("Network latency is limited to %d", NETWORK_MAX_LATENCY);
- return -1;
- }
-
- // Init network connection
- if (!JackNetSlaveInterface::InitConnection(fConnectTimeOut)) {
- jack_error("Initing network fails...");
- return -1;
- }
-
- // Finish connection...
- if (!JackNetSlaveInterface::InitRendering()) {
- jack_error("Starting network fails...");
- return -1;
- }
-
- // Then set global parameters
- if (!SetParams()) {
- jack_error("SetParams error...");
- return -1;
- }
-
- // Set result
- if (result != NULL) {
- result->buffer_size = fParams.fPeriodSize;
- result->sample_rate = fParams.fSampleRate;
- result->audio_input = fParams.fSendAudioChannels;
- result->audio_output = fParams.fReturnAudioChannels;
- result->midi_input = fParams.fSendMidiChannels;
- result->midi_output = fParams.fReturnMidiChannels;
- strcpy(result->master_name, fParams.fMasterNetName);
- }
-
- // By default fFrames is fPeriodSize
- fFrames = fParams.fPeriodSize;
-
- SessionParamsDisplay(&fParams);
-
- AllocPorts();
- return 0;
- }
-
- int Restart()
- {
- // Do it until client possibly decides to stop trying to connect...
- while (true) {
-
- // If restart cb is set, then call it
- if (fRestartCallback) {
- if (fRestartCallback(fRestartArg) != 0) {
- return -1;
- }
- // Otherwise if shutdown cb is set, then call it
- } else if (fShutdownCallback) {
- fShutdownCallback(fShutdownArg);
- }
-
- // Init network connection
- if (!JackNetSlaveInterface::InitConnection(fConnectTimeOut)) {
- jack_error("Initing network fails after time_out, retry...");
- } else {
- break;
- }
- }
-
- // Finish connection
- if (!JackNetSlaveInterface::InitRendering()) {
- jack_error("Starting network fails...");
- return -1;
- }
-
- // Then set global parameters
- if (!SetParams()) {
- jack_error("SetParams error...");
- return -1;
- }
-
- // We need to notify possibly new buffer size and sample rate (see Execute)
- if (fBufferSizeCallback) {
- if (fBufferSizeCallback(fParams.fPeriodSize, fBufferSizeArg) != 0) {
- jack_error("New buffer size = %d cannot be used...", fParams.fPeriodSize);
- return -1;
- }
- }
-
- if (fSampleRateCallback) {
- if (fSampleRateCallback(fParams.fSampleRate, fSampleRateArg) != 0) {
- jack_error("New sample rate = %d cannot be used...", fParams.fSampleRate);
- return -1;
- }
- }
-
- AllocPorts();
- return 0;
- }
-
- int Close()
- {
- fSocket.Close();
- FreePorts();
- return 0;
- }
-
- // Transport
- void EncodeTransportData()
- {}
-
- void DecodeTransportData()
- {}
-
- bool Init()
- {
- // Will do "something" on OSX only...
- UInt64 period, constraint;
- period = constraint = UInt64(1000000000.f * (float(fParams.fPeriodSize) / float(fParams.fSampleRate)));
- UInt64 computation = JackTools::ComputationMicroSec(fParams.fPeriodSize) * 1000;
- fThread.SetParams(period, computation, constraint);
-
- return (fThread.AcquireSelfRealTime(80) == 0); // TODO: get a value from the server
- }
-
- bool IsRunning()
- {
- return (fThread.GetStatus() == JackThread::kRunning);
- }
-
- bool Execute()
- {
- try {
- /*
- Fist cycle use an INT_MAX time out, so that connection
- is considered established (with PACKET_TIMEOUT later on)
- when the first cycle has been done.
- */
- DummyProcess();
- // keep running even in case of error
- while (fThread.GetStatus() == JackThread::kRunning) {
- if (Process() == SOCKET_ERROR) {
- return false;
- }
- }
- return false;
- } catch (JackNetException& e) {
- // otherwise just restart...
- e.PrintMessage();
- jack_info("NetSlave is restarted");
- fThread.DropRealTime();
- fThread.SetStatus(JackThread::kIniting);
- FreePorts();
- if (Restart() == 0 && Init()) {
- fThread.SetStatus(JackThread::kRunning);
- return true;
- } else {
- return false;
- }
- }
- }
-
- int Read()
- {
- // receive sync (launch the cycle)
- switch (SyncRecv()) {
-
- case SOCKET_ERROR:
- return SOCKET_ERROR;
-
- case SYNC_PACKET_ERROR:
- // since sync packet is incorrect, don't decode it and continue with data
- if (fErrorCallback) {
- fErrorCallback(SYNC_PACKET_ERROR, fErrorArg);
- }
- break;
-
- default:
- // decode sync
- DecodeSyncPacket(fFrames);
- break;
- }
-
- int res = DataRecv();
- if (res == DATA_PACKET_ERROR && fErrorCallback) {
- fErrorCallback(DATA_PACKET_ERROR, fErrorArg);
- }
- return res;
- }
-
- int Write()
- {
- EncodeSyncPacket(fFrames);
-
- if (SyncSend() == SOCKET_ERROR) {
- return SOCKET_ERROR;
- }
-
- return DataSend();
- }
-
- void DummyProcess()
- {
- // First cycle with INT_MAX time out
- SetPacketTimeOut(INT_MAX);
-
- // One cycle
- Process();
-
- // Then use PACKET_TIMEOUT * fParams.fNetworkLatency for next cycles
- SetPacketTimeOut(std::max(int(PACKET_TIMEOUT), int(PACKET_TIMEOUT * fParams.fNetworkLatency)));
- }
-
- int Process()
- {
- // Read data from the network, throw JackNetException in case of network error...
- if (Read() == SOCKET_ERROR) {
- return SOCKET_ERROR;
- }
-
- if (fFrames < 0) fFrames = fParams.fPeriodSize;
-
- fProcessCallback(fFrames,
- fParams.fSendAudioChannels,
- fAudioCaptureBuffer,
- fParams.fSendMidiChannels,
- (void**)fMidiCaptureBuffer,
- fParams.fReturnAudioChannels,
- fAudioPlaybackBuffer,
- fParams.fReturnMidiChannels,
- (void**)fMidiPlaybackBuffer,
- fProcessArg);
-
- // Then write data to network, throw JackNetException in case of network error...
- if (Write() == SOCKET_ERROR) {
- return SOCKET_ERROR;
- }
-
- return 0;
- }
-
- int Start()
- {
- return (fProcessCallback == 0) ? -1 : fThread.StartSync();
- }
-
- int Stop()
- {
- return (fProcessCallback == 0) ? -1 : fThread.Kill();
- }
-
- // Callback
- int SetProcessCallback(JackNetSlaveProcessCallback net_callback, void *arg)
- {
- if (fThread.GetStatus() == JackThread::kRunning) {
- return -1;
- } else {
- fProcessCallback = net_callback;
- fProcessArg = arg;
- return 0;
- }
- }
-
- int SetShutdownCallback(JackNetSlaveShutdownCallback shutdown_callback, void *arg)
- {
- if (fThread.GetStatus() == JackThread::kRunning) {
- return -1;
- } else {
- fShutdownCallback = shutdown_callback;
- fShutdownArg = arg;
- return 0;
- }
- }
-
- int SetRestartCallback(JackNetSlaveRestartCallback restart_callback, void *arg)
- {
- if (fThread.GetStatus() == JackThread::kRunning) {
- return -1;
- } else {
- fRestartCallback = restart_callback;
- fRestartArg = arg;
- return 0;
- }
- }
-
- int SetErrorCallback(JackNetSlaveErrorCallback error_callback, void *arg)
- {
- if (fThread.GetStatus() == JackThread::kRunning) {
- return -1;
- } else {
- fErrorCallback = error_callback;
- fErrorArg = arg;
- return 0;
- }
- }
-
- int SetBufferSizeCallback(JackNetSlaveBufferSizeCallback bufsize_callback, void *arg)
- {
- if (fThread.GetStatus() == JackThread::kRunning) {
- return -1;
- } else {
- fBufferSizeCallback = bufsize_callback;
- fBufferSizeArg = arg;
- return 0;
- }
- }
-
- int SetSampleRateCallback(JackNetSlaveSampleRateCallback samplerate_callback, void *arg)
- {
- if (fThread.GetStatus() == JackThread::kRunning) {
- return -1;
- } else {
- fSampleRateCallback = samplerate_callback;
- fSampleRateArg = arg;
- return 0;
- }
- }
-
- };
-
- struct JackNetAdapter : public JackAudioAdapterInterface {
-
- JackNetAdapter(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)
- :JackAudioAdapterInterface(host_buffer_size, host_sample_rate, adapted_buffer_size, adapted_sample_rate)
- {
- fCaptureChannels = input;
- fPlaybackChannels = output;
- Create();
- }
-
- void Create()
- {
- //ringbuffers
-
- if (fCaptureChannels > 0) {
- fCaptureRingBuffer = new JackResampler*[fCaptureChannels];
- }
- if (fPlaybackChannels > 0) {
- fPlaybackRingBuffer = new JackResampler*[fPlaybackChannels];
- }
-
- if (fAdaptative) {
- AdaptRingBufferSize();
- jack_info("Ringbuffer automatic adaptative mode size = %d frames", fRingbufferCurSize);
- } else {
- if (fRingbufferCurSize > DEFAULT_RB_SIZE) {
- fRingbufferCurSize = DEFAULT_RB_SIZE;
- }
- jack_info("Fixed ringbuffer size = %d frames", fRingbufferCurSize);
- }
-
- for (int i = 0; i < fCaptureChannels; i++ ) {
- fCaptureRingBuffer[i] = new JackResampler();
- fCaptureRingBuffer[i]->Reset(fRingbufferCurSize);
- }
- for (int i = 0; i < fPlaybackChannels; i++ ) {
- fPlaybackRingBuffer[i] = new JackResampler();
- fPlaybackRingBuffer[i]->Reset(fRingbufferCurSize);
- }
-
- if (fCaptureChannels > 0) {
- jack_log("ReadSpace = %ld", fCaptureRingBuffer[0]->ReadSpace());
- }
- if (fPlaybackChannels > 0) {
- jack_log("WriteSpace = %ld", fPlaybackRingBuffer[0]->WriteSpace());
- }
- }
-
- virtual ~JackNetAdapter()
- {
- Destroy();
- }
-
- void Flush()
- {
- for (int i = 0; i < fCaptureChannels; i++ ) {
- fCaptureRingBuffer[i]->Reset(fRingbufferCurSize);
- }
- for (int i = 0; i < fPlaybackChannels; i++ ) {
- fPlaybackRingBuffer[i]->Reset(fRingbufferCurSize);
- }
- }
-
- };
-
-
- } // end of namespace
-
- using namespace Jack;
-
- 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) {
- return (jack_net_slave_t*)slave;
- } else {
- delete slave;
- return NULL;
- }
- }
-
- LIB_EXPORT int jack_net_slave_close(jack_net_slave_t* net)
- {
- JackNetExtSlave* slave = (JackNetExtSlave*)net;
- slave->Close();
- delete slave;
- return 0;
- }
-
- 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);
- }
-
- LIB_EXPORT int jack_net_slave_activate(jack_net_slave_t* net)
- {
- JackNetExtSlave* slave = (JackNetExtSlave*)net;
- return slave->Start();
- }
-
- LIB_EXPORT int jack_net_slave_deactivate(jack_net_slave_t* net)
- {
- JackNetExtSlave* slave = (JackNetExtSlave*)net;
- return slave->Stop();
- }
-
- LIB_EXPORT int jack_net_slave_is_active(jack_net_slave_t* net)
- {
- JackNetExtSlave* slave = (JackNetExtSlave*)net;
- return slave->IsRunning();
- }
-
- 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);
- }
-
- 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);
- }
-
- 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);
- }
-
- LIB_EXPORT int jack_set_net_slave_restart_callback(jack_net_slave_t *net, JackNetSlaveRestartCallback restart_callback, void *arg)
- {
- JackNetExtSlave* slave = (JackNetExtSlave*)net;
- return slave->SetRestartCallback(restart_callback, arg);
- }
-
- LIB_EXPORT int jack_set_net_slave_error_callback(jack_net_slave_t *net, JackNetSlaveErrorCallback error_callback, void *arg)
- {
- JackNetExtSlave* slave = (JackNetExtSlave*)net;
- return slave->SetErrorCallback(error_callback, arg);
- }
-
- // Master API
-
- LIB_EXPORT jack_net_master_t* jack_net_master_open(const char* ip, int port, jack_master_t* request, jack_slave_t* result)
- {
- JackNetExtMaster* master = new JackNetExtMaster(ip, port, request);
- if (master->Open(result) == 0) {
- return (jack_net_master_t*)master;
- } else {
- delete master;
- return NULL;
- }
- }
-
- LIB_EXPORT int jack_net_master_close(jack_net_master_t* net)
- {
- JackNetExtMaster* master = (JackNetExtMaster*)net;
- master->Close();
- delete master;
- return 0;
- }
-
- 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, -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, -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
-
- 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)
- {
- try {
- return (jack_adapter_t*)new JackNetAdapter(input, output, host_buffer_size, host_sample_rate, adapted_buffer_size, adapted_sample_rate);
- } catch (...) {
- return NULL;
- }
- }
-
- LIB_EXPORT int jack_destroy_adapter(jack_adapter_t* adapter)
- {
- delete((JackNetAdapter*)adapter);
- return 0;
- }
-
- LIB_EXPORT void jack_flush_adapter(jack_adapter_t* adapter)
- {
- JackNetAdapter* slave = (JackNetAdapter*)adapter;
- slave->Flush();
- }
-
- 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);
- }
-
- 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);
- }
-
- static void jack_format_and_log(int level, const char *prefix, const char *fmt, va_list ap)
- {
- static const char* netjack_log = getenv("JACK_NETJACK_LOG");
- static bool is_netjack_log = (netjack_log) ? atoi(netjack_log) : 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");
- }
- }
-
- LIB_EXPORT void jack_error(const char *fmt, ...)
- {
- va_list ap;
- va_start(ap, fmt);
- jack_format_and_log(LOG_LEVEL_INFO, "Jack: ", fmt, ap);
- va_end(ap);
- }
-
- LIB_EXPORT void jack_info(const char *fmt, ...)
- {
- va_list ap;
- va_start(ap, fmt);
- jack_format_and_log(LOG_LEVEL_INFO, "Jack: ", fmt, ap);
- va_end(ap);
- }
-
- 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);
- }
|