JackNetAPI.cpp 42.2 KB
Newer Older
1
/*
Stephane Letz's avatar
Stephane Letz committed
2
Copyright (C) 2009-2013 Grame
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

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>
sletz's avatar
sletz committed
21
#include <stdarg.h>
sletz's avatar
sletz committed
22

23
24
25
26
27
28
29
#include "JackNetInterface.h"
#include "JackAudioAdapterInterface.h"

#ifdef __cplusplus
extern "C"
{
#endif
sletz's avatar
sletz committed
30

31
    // NetJack common API
sletz's avatar
sletz committed
32

33
34
    #define MASTER_NAME_SIZE 256

35
36
37
38
39
    enum JackNetEncoder {

        JackFloatEncoder = 0,
        JackIntEncoder = 1,
        JackCeltEncoder = 2,
Robin Gareus's avatar
Robin Gareus committed
40
        JackOpusEncoder = 3
41
    };
42

43
    typedef struct {
sletz's avatar
sletz committed
44

45
46
47
        int audio_input;
        int audio_output;
        int midi_input;
sletz's avatar
sletz committed
48
        int midi_output;
49
50
        int mtu;
        int time_out;   // in millisecond, -1 means in infinite
sletz's avatar
sletz committed
51
        int encoder;    // one of JackNetEncoder
52
        int kbps;       // KB per second for CELT encoder
sletz's avatar
sletz committed
53
        int latency;    // network cycles
54
55
56
57

    } jack_slave_t;

    typedef struct {
sletz's avatar
sletz committed
58

59
60
61
62
        int audio_input;
        int audio_output;
        int midi_input;
        int midi_output;
63
64
65
        jack_nframes_t buffer_size;
        jack_nframes_t sample_rate;
        char master_name[MASTER_NAME_SIZE];
66
67
        int time_out;
        int partial_cycle;                   
68
69

    } jack_master_t;
sletz's avatar
sletz committed
70

71
    // NetJack slave API
sletz's avatar
sletz committed
72

73
    typedef struct _jack_net_slave jack_net_slave_t;
sletz's avatar
sletz committed
74

75
    typedef int (* JackNetSlaveProcessCallback) (jack_nframes_t buffer_size,
sletz's avatar
sletz committed
76
77
                                            int audio_input,
                                            float** audio_input_buffer,
78
79
80
                                            int midi_input,
                                            void** midi_input_buffer,
                                            int audio_output,
sletz's avatar
sletz committed
81
82
83
                                            float** audio_output_buffer,
                                            int midi_output,
                                            void** midi_output_buffer,
84
                                            void* data);
sletz's avatar
sletz committed
85

86
87
    typedef int (*JackNetSlaveBufferSizeCallback) (jack_nframes_t nframes, void *arg);
    typedef int (*JackNetSlaveSampleRateCallback) (jack_nframes_t nframes, void *arg);
Stephane Letz's avatar
Stephane Letz committed
88
89
90
    typedef void (*JackNetSlaveShutdownCallback) (void* arg);
    typedef int (*JackNetSlaveRestartCallback) (void* arg);
    typedef void (*JackNetSlaveErrorCallback) (int error_code, void* arg);
91

sletz's avatar
sletz committed
92
93
    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);
sletz's avatar
sletz committed
94

sletz's avatar
sletz committed
95
96
    LIB_EXPORT int jack_net_slave_activate(jack_net_slave_t* net);
    LIB_EXPORT int jack_net_slave_deactivate(jack_net_slave_t* net);
97
    LIB_EXPORT int jack_net_slave_is_active(jack_net_slave_t* net);
sletz's avatar
sletz committed
98

sletz's avatar
sletz committed
99
100
101
102
    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);
103
    LIB_EXPORT int jack_set_net_slave_restart_callback(jack_net_slave_t* net, JackNetSlaveRestartCallback restart_callback, void *arg);
104
    LIB_EXPORT int jack_set_net_slave_error_callback(jack_net_slave_t* net, JackNetSlaveErrorCallback error_callback, void *arg);
sletz's avatar
sletz committed
105

106
    // NetJack master API
sletz's avatar
sletz committed
107

108
    typedef struct _jack_net_master jack_net_master_t;
sletz's avatar
sletz committed
109

sletz's avatar
sletz committed
110
111
    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);
sletz's avatar
sletz committed
112

sletz's avatar
sletz committed
113
114
    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);
sletz's avatar
sletz committed
115

116
117
118
    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);

119
    // NetJack adapter API
sletz's avatar
sletz committed
120

121
    typedef struct _jack_adapter jack_adapter_t;
sletz's avatar
sletz committed
122

sletz's avatar
sletz committed
123
    LIB_EXPORT jack_adapter_t* jack_create_adapter(int input, int output,
sletz's avatar
sletz committed
124
                                                    jack_nframes_t host_buffer_size,
sletz's avatar
sletz committed
125
126
127
                                                    jack_nframes_t host_sample_rate,
                                                    jack_nframes_t adapted_buffer_size,
                                                    jack_nframes_t adapted_sample_rate);
sletz's avatar
sletz committed
128
129
    LIB_EXPORT int jack_destroy_adapter(jack_adapter_t* adapter);
    LIB_EXPORT void jack_flush_adapter(jack_adapter_t* adapter);
130

sletz's avatar
sletz committed
131
132
    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);
sletz's avatar
sletz committed
133

sletz's avatar
sletz committed
134
135
136
137
138
139
140
    #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, ...);

141
142
143
144
145
146
147
#ifdef __cplusplus
}
#endif

namespace Jack
{

Stephane Letz's avatar
Stephane Letz committed
148
struct JackNetExtMaster : public JackNetMasterInterface {
sletz's avatar
sletz committed
149

150
    jack_master_t fRequest;
151
    
152
    JackRingBuffer** fRingBuffer;
sletz's avatar
sletz committed
153
154
155
156

    JackNetExtMaster(const char* ip,
                    int port,
                    const char* name,
157
158
159
160
161
162
                    jack_master_t* request)
    {
        fRunning = true;
        assert(strlen(ip) < 32);
        strcpy(fMulticastIP, ip);
        fSocket.SetPort(port);
sletz's avatar
sletz committed
163
164
        fRequest.buffer_size = request->buffer_size;
        fRequest.sample_rate = request->sample_rate;
sletz's avatar
sletz committed
165
166
        fRequest.audio_input = request->audio_input;
        fRequest.audio_output = request->audio_output;
167
        fRequest.time_out = request->time_out;
168
169
        fRequest.partial_cycle = request->partial_cycle;
        fRingBuffer = NULL;
170
    }
sletz's avatar
sletz committed
171

172
    virtual ~JackNetExtMaster()
173
174
175
176
177
178
179
180
    {
        if (fRingBuffer) {
            for (int i = 0; i < fParams.fReturnAudioChannels; i++) {
                delete fRingBuffer[i];
            }
            delete [] fRingBuffer;
        }
    }
sletz's avatar
sletz committed
181

182
183
    int Open(jack_slave_t* result)
    {
184
        // Check buffer_size
Stephane Letz's avatar
Typos.    
Stephane Letz committed
185
        if (fRequest.buffer_size == 0) {
186
187
188
189
            jack_error("Incorrect buffer_size...");
            return -1;
        }
        // Check sample_rate
Stephane Letz's avatar
Typos.    
Stephane Letz committed
190
        if (fRequest.sample_rate == 0) {
191
192
193
194
            jack_error("Incorrect sample_rate...");
            return -1;
        }
                   
195
196
        // Init socket API (win32)
        if (SocketAPIInit() < 0) {
Stephane Letz's avatar
Stephane Letz committed
197
            jack_error("Can't init Socket API, exiting...");
198
199
200
201
202
            return -1;
        }

        // Request socket
        if (fSocket.NewSocket() == SOCKET_ERROR) {
Stephane Letz's avatar
Stephane Letz committed
203
            jack_error("Can't create the network management input socket : %s", StrError(NET_ERROR_CODE));
204
205
206
207
208
            return -1;
        }

        // Bind the socket to the local port
        if (fSocket.Bind() == SOCKET_ERROR) {
Stephane Letz's avatar
Stephane Letz committed
209
            jack_error("Can't bind the network manager socket : %s", StrError(NET_ERROR_CODE));
210
211
212
213
214
            fSocket.Close();
            return -1;
        }

        // Join multicast group
sletz's avatar
sletz committed
215
        if (fSocket.JoinMCastGroup(fMulticastIP) == SOCKET_ERROR) {
Stephane Letz's avatar
Stephane Letz committed
216
            jack_error("Can't join multicast group : %s", StrError(NET_ERROR_CODE));
sletz's avatar
sletz committed
217
        }
218
219

        // Local loop
sletz's avatar
sletz committed
220
        if (fSocket.SetLocalLoop() == SOCKET_ERROR) {
Stephane Letz's avatar
Stephane Letz committed
221
            jack_error("Can't set local loop : %s", StrError(NET_ERROR_CODE));
sletz's avatar
sletz committed
222
        }
223
224

        // Set a timeout on the multicast receive (the thread can now be cancelled)
sletz's avatar
sletz committed
225
        if (fSocket.SetTimeOut(MANAGER_INIT_TIMEOUT) == SOCKET_ERROR) {
Stephane Letz's avatar
Stephane Letz committed
226
            jack_error("Can't set timeout : %s", StrError(NET_ERROR_CODE));
sletz's avatar
sletz committed
227
        }
sletz's avatar
sletz committed
228

229
         // Main loop, wait for data, deal with it and wait again
230
231
        int attempt = 0;
        int rx_bytes = 0;
232
233
        int try_count = (fRequest.time_out > 0) ? int((1000000.f * float(fRequest.time_out)) / float(MANAGER_INIT_TIMEOUT)) : INT_MAX;
       
234
235
236
237
238
        do
        {
            session_params_t net_params;
            rx_bytes = fSocket.CatchHost(&net_params, sizeof(session_params_t), 0);
            SessionParamsNToH(&net_params, &fParams);
sletz's avatar
sletz committed
239

240
            if ((rx_bytes == SOCKET_ERROR) && (fSocket.GetError() != NET_NO_DATA)) {
Stephane Letz's avatar
Stephane Letz committed
241
                jack_error("Error in receive : %s", StrError(NET_ERROR_CODE));
242
                if (++attempt == 10) {
Stephane Letz's avatar
Stephane Letz committed
243
                    jack_error("Can't receive on the socket, exiting net manager" );
244
245
246
                    goto error;
                }
            }
sletz's avatar
sletz committed
247

248
249
            if (rx_bytes == sizeof(session_params_t ))  {
                switch (GetPacketType(&fParams)) {
sletz's avatar
sletz committed
250

251
                    case SLAVE_AVAILABLE:
sletz's avatar
sletz committed
252
                        if (InitMaster(result) == 0) {
253
254
255
                            SessionParamsDisplay(&fParams);
                            fRunning = false;
                        } else {
Stephane Letz's avatar
Stephane Letz committed
256
                            jack_error("Can't init new net master...");
257
258
                            goto error;
                        }
Stephane Letz's avatar
Stephane Letz committed
259
                        jack_info("Waiting for a slave...");
260
                        break;
sletz's avatar
sletz committed
261

262
263
                    case KILL_MASTER:
                         break;
sletz's avatar
sletz committed
264

265
266
267
268
269
                    default:
                        break;
                }
            }
        }
270
271
272
273
274
275
        while (fRunning && (--try_count > 0));
        
        if (try_count == 0) {
            jack_error("Time out error in connect");
            return -1;
        }
sletz's avatar
sletz committed
276
 
277
        // Set result parameters
278
279
280
        result->audio_input = fParams.fSendAudioChannels;
        result->audio_output = fParams.fReturnAudioChannels;
        result->midi_input = fParams.fSendMidiChannels;
sletz's avatar
sletz committed
281
282
        result->midi_output = fParams.fReturnMidiChannels;
        result->mtu = fParams.fMtu;
283
        result->latency = fParams.fNetworkLatency;
284
285
286
287
288
289
290
291
        
        // 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);
            }
        }
292
        return 0;
sletz's avatar
sletz committed
293

294
295
296
297
    error:
        fSocket.Close();
        return -1;
    }
sletz's avatar
sletz committed
298

sletz's avatar
sletz committed
299
    int InitMaster(jack_slave_t* result)
300
    {
sletz's avatar
sletz committed
301
        // Check MASTER <==> SLAVE network protocol coherency
Stephane Letz's avatar
Stephane Letz committed
302
        if (fParams.fProtocolVersion != NETWORK_PROTOCOL) {
Stephane Letz's avatar
Stephane Letz committed
303
            jack_error("Error : slave '%s' is running with a different protocol %d != %d", fParams.fName, fParams.fProtocolVersion, NETWORK_PROTOCOL);
304
305
306
307
308
309
310
311
            return -1;
        }

        // Settings
        fSocket.GetName(fParams.fMasterNetName);
        fParams.fID = 1;
        fParams.fPeriodSize = fRequest.buffer_size;
        fParams.fSampleRate = fRequest.sample_rate;
sletz's avatar
sletz committed
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
        
        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;
        }
        
345
346
        // Close request socket
        fSocket.Close();
sletz's avatar
sletz committed
347

sletz's avatar
sletz committed
348
        /// Network init
sletz's avatar
sletz committed
349
        if (!JackNetMasterInterface::Init()) {
350
            return -1;
sletz's avatar
sletz committed
351
        }
352
353

        // Set global parameters
sletz's avatar
sletz committed
354
        if (!SetParams()) {
sletz's avatar
sletz committed
355
            return -1;
sletz's avatar
sletz committed
356
        }
sletz's avatar
sletz committed
357

358
359
        return 0;
    }
sletz's avatar
sletz committed
360

361
362
363
364
365
    int Close()
    {
        fSocket.Close();
        return 0;
    }
Stephane Letz's avatar
Stephane Letz committed
366
367
368
369
370
371
372
373
374
375
376
    
    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);
            }
        }
    }
377
  
378
    int Read(int audio_input, float** audio_input_buffer, int midi_input, void** midi_input_buffer, int frames)
sletz's avatar
sletz committed
379
    {
sletz's avatar
sletz committed
380
        try {
Stephane Letz's avatar
Stephane Letz committed
381
382
            
            // frames = -1 means : entire buffer
383
            if (frames < 0) frames = fParams.fPeriodSize;
sletz's avatar
sletz committed
384
           
385
            int read_frames = 0;
sletz's avatar
sletz committed
386
            assert(audio_input == fParams.fReturnAudioChannels);
sletz's avatar
sletz committed
387

sletz's avatar
sletz committed
388
389
            for (int audio_port_index = 0; audio_port_index < audio_input; audio_port_index++) {
                fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, audio_input_buffer[audio_port_index]);
sletz's avatar
sletz committed
390
            }
sletz's avatar
sletz committed
391

sletz's avatar
sletz committed
392
393
            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]);
sletz's avatar
sletz committed
394
            }
sletz's avatar
sletz committed
395
         
396
397
            int res1 = SyncRecv();
            switch (res1) {
398
            
Stephane Letz's avatar
Stephane Letz committed
399
                case NET_SYNCHING:
400
401
                    // Data will not be received, so cleanup buffers...
                    for (int audio_port_index = 0; audio_port_index < audio_input; audio_port_index++) {
402
403
                        memset(audio_input_buffer[audio_port_index], 0, sizeof(float) * fParams.fPeriodSize);
                    }
Stephane Letz's avatar
Stephane Letz committed
404
                    UseRingBuffer(audio_input, audio_input_buffer, fParams.fPeriodSize, frames);
405
                    return res1;
406
                    
407
                case SOCKET_ERROR:
408
                    return res1;
409
                    
410
                case SYNC_PACKET_ERROR:
411
                    // since sync packet is incorrect, don't decode it and continue with data
412
413
414
                    break;
                    
                default:
415
                    // decode sync
Stephane Letz's avatar
Stephane Letz committed
416
                    DecodeSyncPacket(read_frames);
417
418
419
                    break;
            }
          
420
            int res2 = DataRecv();
Stephane Letz's avatar
Stephane Letz committed
421
            UseRingBuffer(audio_input, audio_input_buffer, read_frames, frames);
422
            return res2;
sletz's avatar
sletz committed
423

sletz's avatar
sletz committed
424
        } catch (JackNetException& e) {
425
            jack_error(e.what());
sletz's avatar
sletz committed
426
            return -1;
sletz's avatar
sletz committed
427
        }
428
    }
429

430
    int Write(int audio_output, float** audio_output_buffer, int midi_output, void** midi_output_buffer, int frames)
431
    {
sletz's avatar
sletz committed
432
        try {
433
        
Stephane Letz's avatar
Stephane Letz committed
434
            // frames = -1 means : entire buffer
435
            if (frames < 0) frames = fParams.fPeriodSize;
sletz's avatar
sletz committed
436
            
sletz's avatar
sletz committed
437
            assert(audio_output == fParams.fSendAudioChannels);
sletz's avatar
sletz committed
438

sletz's avatar
sletz committed
439
440
441
            for (int audio_port_index = 0; audio_port_index < audio_output; audio_port_index++) {
                fNetAudioCaptureBuffer->SetBuffer(audio_port_index, audio_output_buffer[audio_port_index]);
            }
sletz's avatar
sletz committed
442

sletz's avatar
sletz committed
443
444
445
            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]);
            }
sletz's avatar
sletz committed
446
            
447
448
            EncodeSyncPacket(frames);
    
449
450
451
452
            // send sync
            if (SyncSend() == SOCKET_ERROR) {
                return SOCKET_ERROR;
            }
sletz's avatar
sletz committed
453

454
            // send data
455
456
            if (DataSend() == SOCKET_ERROR) {
                return SOCKET_ERROR;
sletz's avatar
sletz committed
457
            }
sletz's avatar
sletz committed
458
            return 0;
sletz's avatar
sletz committed
459

sletz's avatar
sletz committed
460
        } catch (JackNetException& e) {
461
            jack_error(e.what());
sletz's avatar
sletz committed
462
            return -1;
sletz's avatar
sletz committed
463
        }
sletz's avatar
sletz committed
464
    }
sletz's avatar
sletz committed
465

466
    // Transport
sletz's avatar
sletz committed
467
468
    void EncodeTransportData()
    {}
sletz's avatar
sletz committed
469

sletz's avatar
sletz committed
470
471
    void DecodeTransportData()
    {}
sletz's avatar
sletz committed
472

473
474
};

Stephane Letz's avatar
Stephane Letz committed
475
struct JackNetExtSlave : public JackNetSlaveInterface, public JackRunnableInterface {
sletz's avatar
sletz committed
476

Stephane Letz's avatar
Stephane Letz committed
477
478
479
480
481
482
483
    // Data buffers
    float** fAudioCaptureBuffer;
    float** fAudioPlaybackBuffer;

    JackMidiBuffer** fMidiCaptureBuffer;
    JackMidiBuffer** fMidiPlaybackBuffer;
   
484
    JackThread fThread;
sletz's avatar
sletz committed
485

486
487
    JackNetSlaveProcessCallback fProcessCallback;
    void* fProcessArg;
sletz's avatar
sletz committed
488

489
490
    JackNetSlaveShutdownCallback fShutdownCallback;
    void* fShutdownArg;
491
492
    
    JackNetSlaveRestartCallback fRestartCallback;
493
494
495
496
    void* fRestartArg;
    
    JackNetSlaveErrorCallback fErrorCallback;
    void* fErrorArg;
sletz's avatar
sletz committed
497

498
499
    JackNetSlaveBufferSizeCallback fBufferSizeCallback;
    void* fBufferSizeArg;
sletz's avatar
sletz committed
500

501
502
    JackNetSlaveSampleRateCallback fSampleRateCallback;
    void* fSampleRateArg;
sletz's avatar
sletz committed
503

sletz's avatar
sletz committed
504
    int fConnectTimeOut;
Stephane Letz's avatar
Stephane Letz committed
505
    int fFrames;
506
   
sletz's avatar
sletz committed
507
508
509
    JackNetExtSlave(const char* ip,
                    int port,
                    const char* name,
sletz's avatar
sletz committed
510
                    jack_slave_t* request)
Stephane Letz's avatar
Stephane Letz committed
511
        :fThread(this),
sletz's avatar
sletz committed
512
        fProcessCallback(NULL),fProcessArg(NULL),
513
        fShutdownCallback(NULL), fShutdownArg(NULL),
514
        fRestartCallback(NULL), fRestartArg(NULL),
515
        fErrorCallback(NULL), fErrorArg(NULL),
516
        fBufferSizeCallback(NULL), fBufferSizeArg(NULL),
517
518
        fSampleRateCallback(NULL), fSampleRateArg(NULL)
   {
519
        char host_name[JACK_CLIENT_NAME_SIZE];
sletz's avatar
sletz committed
520

521
522
523
524
525
526
527
528
        // 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;
sletz's avatar
sletz committed
529
        fParams.fReturnMidiChannels = request->midi_output;
530
        fParams.fNetworkLatency = request->latency;
531
532
        fParams.fSampleEncoder = request->encoder;
        fParams.fKBps = request->kbps;
sletz's avatar
sletz committed
533
        fParams.fSlaveSyncMode = 1;
sletz's avatar
sletz committed
534
        fConnectTimeOut = request->time_out;
sletz's avatar
sletz committed
535

536
537
538
539
        // 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);
sletz's avatar
sletz committed
540

541
542
543
        // Set the socket parameters
        fSocket.SetPort(port);
        fSocket.SetAddress(fMulticastIP, port);
Stephane Letz's avatar
Stephane Letz committed
544
545
546
547
548
        
        fAudioCaptureBuffer = NULL;
        fAudioPlaybackBuffer = NULL;
        fMidiCaptureBuffer = NULL;
        fMidiPlaybackBuffer = NULL;
549
    }
sletz's avatar
sletz committed
550

551
552
    virtual ~JackNetExtSlave()
    {}
Stephane Letz's avatar
Stephane Letz committed
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
     
    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;
        }
    }
sletz's avatar
sletz committed
628

629
630
    int Open(jack_master_t* result)
    {
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
        // 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;
        }
            
sletz's avatar
sletz committed
646
        // Check CELT encoder parameters
sletz's avatar
sletz committed
647
648
649
650
651
        if ((fParams.fSampleEncoder == JackCeltEncoder) && (fParams.fKBps == 0)) {
            jack_error("CELT encoder with 0 for kps...");
            return -1;
        }
        
Robin Gareus's avatar
Robin Gareus committed
652
653
654
655
656
        if ((fParams.fSampleEncoder == JackOpusEncoder) && (fParams.fKBps == 0)) {
            jack_error("Opus encoder with 0 for kps...");
            return -1;
        }

sletz's avatar
sletz committed
657
        // Check latency
sletz's avatar
sletz committed
658
        if (fParams.fNetworkLatency > NETWORK_MAX_LATENCY) {
659
            jack_error("Network latency is limited to %d", NETWORK_MAX_LATENCY);
sletz's avatar
sletz committed
660
661
662
            return -1;
        }

663
        // Init network connection
sletz's avatar
sletz committed
664
        if (!JackNetSlaveInterface::InitConnection(fConnectTimeOut)) {
Stephane Letz's avatar
Stephane Letz committed
665
666
667
668
669
670
671
            jack_error("Initing network fails...");
            return -1;
        }

        // Finish connection...
        if (!JackNetSlaveInterface::InitRendering()) {
            jack_error("Starting network fails...");
672
            return -1;
sletz's avatar
sletz committed
673
        }
sletz's avatar
sletz committed
674

675
        // Then set global parameters
sletz's avatar
sletz committed
676
        if (!SetParams()) {
Stephane Letz's avatar
Stephane Letz committed
677
            jack_error("SetParams error...");
sletz's avatar
sletz committed
678
            return -1;
sletz's avatar
sletz committed
679
        }
sletz's avatar
sletz committed
680

681
682
        // Set result
        if (result != NULL) {
683
684
            result->buffer_size = fParams.fPeriodSize;
            result->sample_rate = fParams.fSampleRate;
685
686
687
688
            result->audio_input = fParams.fSendAudioChannels;
            result->audio_output = fParams.fReturnAudioChannels;
            result->midi_input = fParams.fSendMidiChannels;
            result->midi_output = fParams.fReturnMidiChannels;
689
690
            strcpy(result->master_name, fParams.fMasterNetName);
        }
691
        
Stephane Letz's avatar
Stephane Letz committed
692
693
        // By default fFrames is fPeriodSize
        fFrames = fParams.fPeriodSize;
694
695
        
        SessionParamsDisplay(&fParams);
696
     
Stephane Letz's avatar
Stephane Letz committed
697
        AllocPorts();
698
699
        return 0;
    }
sletz's avatar
sletz committed
700

701
    int Restart() 
702
    {
703
704
705
706
707
708
709
710
711
712
713
714
       // 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);
            }
sletz's avatar
sletz committed
715

716
717
718
719
720
721
            // Init network connection
            if (!JackNetSlaveInterface::InitConnection(fConnectTimeOut)) {
                jack_error("Initing network fails after time_out, retry...");
            } else {
                break;
            }
Stephane Letz's avatar
Stephane Letz committed
722
723
        }

sletz's avatar
sletz committed
724
         // Finish connection
Stephane Letz's avatar
Stephane Letz committed
725
726
        if (!JackNetSlaveInterface::InitRendering()) {
            jack_error("Starting network fails...");
727
            return -1;
sletz's avatar
sletz committed
728
        }
sletz's avatar
sletz committed
729

730
        // Then set global parameters
sletz's avatar
sletz committed
731
        if (!SetParams()) {
Stephane Letz's avatar
Stephane Letz committed
732
            jack_error("SetParams error...");
sletz's avatar
sletz committed
733
            return -1;
sletz's avatar
sletz committed
734
        }
sletz's avatar
sletz committed
735

736
        // We need to notify possibly new buffer size and sample rate (see Execute)
sletz's avatar
sletz committed
737
        if (fBufferSizeCallback) {
738
739
740
741
            if (fBufferSizeCallback(fParams.fPeriodSize, fBufferSizeArg) != 0) {
                jack_error("New buffer size = %d cannot be used...", fParams.fPeriodSize);
                return -1;
            }
sletz's avatar
sletz committed
742
        }
sletz's avatar
sletz committed
743

sletz's avatar
sletz committed
744
        if (fSampleRateCallback) {
745
746
747
748
            if (fSampleRateCallback(fParams.fSampleRate, fSampleRateArg) != 0) {
                jack_error("New sample rate = %d cannot be used...", fParams.fSampleRate);
                return -1;
            }
sletz's avatar
sletz committed
749
        }
sletz's avatar
sletz committed
750

Stephane Letz's avatar
Stephane Letz committed
751
        AllocPorts();
752
753
        return 0;
    }
sletz's avatar
sletz committed
754

755
756
757
    int Close()
    {
        fSocket.Close();
Stephane Letz's avatar
Stephane Letz committed
758
        FreePorts();
759
760
761
762
        return 0;
    }

    // Transport
sletz's avatar
sletz committed
763
764
    void EncodeTransportData()
    {}
sletz's avatar
sletz committed
765

sletz's avatar
sletz committed
766
767
    void DecodeTransportData()
    {}
sletz's avatar
sletz committed
768
769

    bool Init()
770
771
    {
        // Will do "something" on OSX only...
sletz's avatar
sletz committed
772
        UInt64 period, constraint;
Stephane Letz's avatar
Stephane Letz committed
773
774
        period = constraint = UInt64(1000000000.f * (float(fParams.fPeriodSize) / float(fParams.fSampleRate)));
        UInt64 computation = JackTools::ComputationMicroSec(fParams.fPeriodSize) * 1000;
sletz's avatar
sletz committed
775
776
        fThread.SetParams(period, computation, constraint);

sletz's avatar
sletz committed
777
        return (fThread.AcquireSelfRealTime(80) == 0);      // TODO: get a value from the server
778
    }
779
780
781
782
783
    
    bool IsRunning()
    {
        return (fThread.GetStatus() == JackThread::kRunning);
    }
sletz's avatar
sletz committed
784

785
786
    bool Execute()
    {
787
        try {
788
789
790
791
792
793
            /*
                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();
794
            // keep running even in case of error
795
            while (fThread.GetStatus() == JackThread::kRunning) {
sletz's avatar
sletz committed
796
                if (Process() == SOCKET_ERROR) {
797
                    return false;
sletz's avatar
sletz committed
798
                }
799
800
801
            }
            return false;
        } catch (JackNetException& e) {
802
            // otherwise just restart...
803
            e.PrintMessage();
Stephane Letz's avatar
Stephane Letz committed
804
            jack_info("NetSlave is restarted");
805
806
            fThread.DropRealTime();
            fThread.SetStatus(JackThread::kIniting);
Stephane Letz's avatar
Stephane Letz committed
807
            FreePorts();
sletz's avatar
sletz committed
808
            if (Restart() == 0 && Init()) {
809
810
811
812
813
814
815
                fThread.SetStatus(JackThread::kRunning);
                return true;
            } else {
                return false;
            }
        }
    }
sletz's avatar
sletz committed
816

817
818
    int Read()
    {
819
        // receive sync (launch the cycle)
Stephane Letz's avatar
Stephane Letz committed
820
        switch (SyncRecv()) {
821
822
823
824
        
            case SOCKET_ERROR:
                return SOCKET_ERROR;
                
825
            case SYNC_PACKET_ERROR:
826
                // since sync packet is incorrect, don't decode it and continue with data
827
828
829
                if (fErrorCallback) {
                    fErrorCallback(SYNC_PACKET_ERROR, fErrorArg);
                }
830
831
832
                break;
                
            default:
833
                // decode sync
Stephane Letz's avatar
Stephane Letz committed
834
                DecodeSyncPacket(fFrames);
835
836
837
                break;
        }

838
839
840
841
842
        int res = DataRecv();
        if (res == DATA_PACKET_ERROR && fErrorCallback) {
            fErrorCallback(DATA_PACKET_ERROR, fErrorArg);
        }
        return res;
843
    }
844
    
845
846
    int Write()
    {
Stephane Letz's avatar
Stephane Letz committed
847
        EncodeSyncPacket(fFrames);
848
      
sletz's avatar
sletz committed
849
        if (SyncSend() == SOCKET_ERROR) {
850
            return SOCKET_ERROR;
sletz's avatar
sletz committed
851
        }
852
853
854

        return DataSend();
    }
855
856
857
858
    
    void DummyProcess()
    {
        // First cycle with INT_MAX time out
Stephane Letz's avatar
Typos.    
Stephane Letz committed
859
        SetPacketTimeOut(INT_MAX);
860
861
862
863
864
        
        // One cycle
        Process();
        
        // Then use PACKET_TIMEOUT for next cycles
Stephane Letz's avatar
Typos.    
Stephane Letz committed
865
        SetPacketTimeOut(PACKET_TIMEOUT);
866
    }
sletz's avatar
sletz committed
867
868

    int Process()
869
    {
sletz's avatar
sletz committed
870
        // Read data from the network, throw JackNetException in case of network error...
sletz's avatar
sletz committed
871
        if (Read() == SOCKET_ERROR) {
872
            return SOCKET_ERROR;
sletz's avatar
sletz committed
873
        }
874
        
Stephane Letz's avatar
Stephane Letz committed
875
876
        if (fFrames < 0) fFrames = fParams.fPeriodSize;
        
Stephane Letz's avatar
Stephane Letz committed
877
        fProcessCallback(fFrames,
sletz's avatar
sletz committed
878
879
                        fParams.fSendAudioChannels,
                        fAudioCaptureBuffer,
880
                        fParams.fSendMidiChannels,
sletz's avatar
sletz committed
881
                        (void**)fMidiCaptureBuffer,
882
                        fParams.fReturnAudioChannels,
sletz's avatar
sletz committed
883
                        fAudioPlaybackBuffer,
884
                        fParams.fReturnMidiChannels,
sletz's avatar
sletz committed
885
886
                        (void**)fMidiPlaybackBuffer,
                        fProcessArg);
887
       
sletz's avatar
sletz committed
888
        // Then write data to network, throw JackNetException in case of network error...
sletz's avatar
sletz committed
889
        if (Write() == SOCKET_ERROR) {
890
            return SOCKET_ERROR;
sletz's avatar
sletz committed
891
        }
892
893
894

        return 0;
    }
sletz's avatar
sletz committed
895

896
897
898
899
900
901
902
903
904
    int Start()
    {
        return (fProcessCallback == 0) ? -1 : fThread.StartSync();
    }

    int Stop()
    {
        return (fProcessCallback == 0) ? -1 : fThread.Kill();
    }
sletz's avatar
sletz committed
905

906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
    // 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;
        }
    }
928
929
930
931
932
933
934
935
936
937
938
    
    int SetRestartCallback(JackNetSlaveRestartCallback restart_callback, void *arg)
    {
        if (fThread.GetStatus() == JackThread::kRunning) {
            return -1;
        } else {
            fRestartCallback = restart_callback;
            fRestartArg = arg;
            return 0;
        }
    }
939
940
941
942
943
944
945
946
947
948
949
    
    int SetErrorCallback(JackNetSlaveErrorCallback error_callback, void *arg)
    {
        if (fThread.GetStatus() == JackThread::kRunning) {
            return -1;
        } else {
            fErrorCallback = error_callback;
            fErrorArg = arg;
            return 0;
        }
    }
sletz's avatar
sletz committed
950

951
952
953
954
955
956
957
958
959
960
    int SetBufferSizeCallback(JackNetSlaveBufferSizeCallback bufsize_callback, void *arg)
    {
        if (fThread.GetStatus() == JackThread::kRunning) {
            return -1;
        } else {
            fBufferSizeCallback = bufsize_callback;
            fBufferSizeArg = arg;
            return 0;
        }
    }
sletz's avatar
sletz committed
961

962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
    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 {

sletz's avatar
sletz committed
977
    JackNetAdapter(int input, int output,
sletz's avatar
sletz committed
978
                    jack_nframes_t host_buffer_size,
sletz's avatar
sletz committed
979
980
981
982
                    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)
983
    {
sletz's avatar
sletz committed
984
985
986
        fCaptureChannels = input;
        fPlaybackChannels = output;
        Create();
987
    }
sletz's avatar
sletz committed
988

sletz's avatar
sletz committed
989
    void Create()
990
    {
sletz's avatar
sletz committed
991
        //ringbuffers
sletz's avatar
sletz committed
992