JackNetAPI.cpp 40.9 KB
Newer Older
1
/*
sletz's avatar
sletz committed
2
Copyright (C) 2009-2011 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
        int time_out;                   
67
68

    } jack_master_t;
sletz's avatar
sletz committed
69

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

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

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

85
86
87
    typedef int (*JackNetSlaveBufferSizeCallback) (jack_nframes_t nframes, void *arg);
    typedef int (*JackNetSlaveSampleRateCallback) (jack_nframes_t nframes, void *arg);
    typedef void (*JackNetSlaveShutdownCallback) (void* data);
88
    typedef int (*JackNetSlaveRestartCallback) (void* data);
89
    typedef int (*JackNetSlaveErrorCallback) (int error_code, void* data);
90

sletz's avatar
sletz committed
91
92
    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
93

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

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

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

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

sletz's avatar
sletz committed
109
110
    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
111

sletz's avatar
sletz committed
112
113
    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
114

115
    // NetJack adapter API
sletz's avatar
sletz committed
116

117
    typedef struct _jack_adapter jack_adapter_t;
sletz's avatar
sletz committed
118

sletz's avatar
sletz committed
119
    LIB_EXPORT jack_adapter_t* jack_create_adapter(int input, int output,
sletz's avatar
sletz committed
120
                                                    jack_nframes_t host_buffer_size,
sletz's avatar
sletz committed
121
122
123
                                                    jack_nframes_t host_sample_rate,
                                                    jack_nframes_t adapted_buffer_size,
                                                    jack_nframes_t adapted_sample_rate);
sletz's avatar
sletz committed
124
125
    LIB_EXPORT int jack_destroy_adapter(jack_adapter_t* adapter);
    LIB_EXPORT void jack_flush_adapter(jack_adapter_t* adapter);
126

sletz's avatar
sletz committed
127
128
    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
129

sletz's avatar
sletz committed
130
131
132
133
134
135
136
    #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, ...);

137
138
139
140
141
142
143
144
#ifdef __cplusplus
}
#endif

namespace Jack
{

struct JackNetExtMaster : public JackNetMasterInterface {
sletz's avatar
sletz committed
145

sletz's avatar
sletz committed
146
    // Data buffers
147
148
    float** fAudioCaptureBuffer;
    float** fAudioPlaybackBuffer;
sletz's avatar
sletz committed
149

150
151
    JackMidiBuffer** fMidiCaptureBuffer;
    JackMidiBuffer** fMidiPlaybackBuffer;
sletz's avatar
sletz committed
152

153
    jack_master_t fRequest;
154
155
    
    int fPacketTimeOut;
sletz's avatar
sletz committed
156
157
158
159

    JackNetExtMaster(const char* ip,
                    int port,
                    const char* name,
160
161
162
163
164
165
                    jack_master_t* request)
    {
        fRunning = true;
        assert(strlen(ip) < 32);
        strcpy(fMulticastIP, ip);
        fSocket.SetPort(port);
sletz's avatar
sletz committed
166
167
        fRequest.buffer_size = request->buffer_size;
        fRequest.sample_rate = request->sample_rate;
sletz's avatar
sletz committed
168
169
        fRequest.audio_input = request->audio_input;
        fRequest.audio_output = request->audio_output;
170
        fRequest.time_out = request->time_out;
171
172
173
174
        fAudioCaptureBuffer = NULL;
        fAudioPlaybackBuffer = NULL;
        fMidiCaptureBuffer = NULL;
        fMidiPlaybackBuffer = NULL;
175
    }
sletz's avatar
sletz committed
176

177
178
    virtual ~JackNetExtMaster()
    {}
sletz's avatar
sletz committed
179

180
181
182
183
    int Open(jack_slave_t* result)
    {
        // Init socket API (win32)
        if (SocketAPIInit() < 0) {
Stephane Letz's avatar
Stephane Letz committed
184
            jack_error("Can't init Socket API, exiting...");
185
186
187
188
189
            return -1;
        }

        // Request socket
        if (fSocket.NewSocket() == SOCKET_ERROR) {
Stephane Letz's avatar
Stephane Letz committed
190
            jack_error("Can't create the network management input socket : %s", StrError(NET_ERROR_CODE));
191
192
193
194
195
            return -1;
        }

        // Bind the socket to the local port
        if (fSocket.Bind() == SOCKET_ERROR) {
Stephane Letz's avatar
Stephane Letz committed
196
            jack_error("Can't bind the network manager socket : %s", StrError(NET_ERROR_CODE));
197
198
199
200
201
            fSocket.Close();
            return -1;
        }

        // Join multicast group
sletz's avatar
sletz committed
202
        if (fSocket.JoinMCastGroup(fMulticastIP) == SOCKET_ERROR) {
Stephane Letz's avatar
Stephane Letz committed
203
            jack_error("Can't join multicast group : %s", StrError(NET_ERROR_CODE));
sletz's avatar
sletz committed
204
        }
205
206

        // Local loop
sletz's avatar
sletz committed
207
        if (fSocket.SetLocalLoop() == SOCKET_ERROR) {
Stephane Letz's avatar
Stephane Letz committed
208
            jack_error("Can't set local loop : %s", StrError(NET_ERROR_CODE));
sletz's avatar
sletz committed
209
        }
210
211

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

216
         // Main loop, wait for data, deal with it and wait again
217
218
        int attempt = 0;
        int rx_bytes = 0;
219
220
        int try_count = (fRequest.time_out > 0) ? int((1000000.f * float(fRequest.time_out)) / float(MANAGER_INIT_TIMEOUT)) : INT_MAX;
       
221
222
223
224
225
        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
226

227
            if ((rx_bytes == SOCKET_ERROR) && (fSocket.GetError() != NET_NO_DATA)) {
Stephane Letz's avatar
Stephane Letz committed
228
                jack_error("Error in receive : %s", StrError(NET_ERROR_CODE));
229
                if (++attempt == 10) {
Stephane Letz's avatar
Stephane Letz committed
230
                    jack_error("Can't receive on the socket, exiting net manager" );
231
232
233
                    goto error;
                }
            }
sletz's avatar
sletz committed
234

235
236
            if (rx_bytes == sizeof(session_params_t ))  {
                switch (GetPacketType(&fParams)) {
sletz's avatar
sletz committed
237

238
                    case SLAVE_AVAILABLE:
sletz's avatar
sletz committed
239
                        if (InitMaster(result) == 0) {
240
241
242
                            SessionParamsDisplay(&fParams);
                            fRunning = false;
                        } else {
Stephane Letz's avatar
Stephane Letz committed
243
                            jack_error("Can't init new net master...");
244
245
                            goto error;
                        }
Stephane Letz's avatar
Stephane Letz committed
246
                        jack_info("Waiting for a slave...");
247
                        break;
sletz's avatar
sletz committed
248

249
250
                    case KILL_MASTER:
                         break;
sletz's avatar
sletz committed
251

252
253
254
255
256
                    default:
                        break;
                }
            }
        }
257
258
259
260
261
262
        while (fRunning && (--try_count > 0));
        
        if (try_count == 0) {
            jack_error("Time out error in connect");
            return -1;
        }
sletz's avatar
sletz committed
263
 
264
        // Set result parameters
265
266
267
        result->audio_input = fParams.fSendAudioChannels;
        result->audio_output = fParams.fReturnAudioChannels;
        result->midi_input = fParams.fSendMidiChannels;
sletz's avatar
sletz committed
268
269
        result->midi_output = fParams.fReturnMidiChannels;
        result->mtu = fParams.fMtu;
270
        result->latency = fParams.fNetworkLatency;
271
        return 0;
sletz's avatar
sletz committed
272

273
274
275
276
    error:
        fSocket.Close();
        return -1;
    }
sletz's avatar
sletz committed
277

sletz's avatar
sletz committed
278
    int InitMaster(jack_slave_t* result)
279
    {
sletz's avatar
sletz committed
280
        // Check MASTER <==> SLAVE network protocol coherency
Stephane Letz's avatar
Stephane Letz committed
281
        if (fParams.fProtocolVersion != NETWORK_PROTOCOL) {
Stephane Letz's avatar
Stephane Letz committed
282
            jack_error("Error : slave '%s' is running with a different protocol %d != %d", fParams.fName, fParams.fProtocolVersion, NETWORK_PROTOCOL);
283
284
285
286
287
288
289
290
            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
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
        
        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;
        }
        
324
325
        // Close request socket
        fSocket.Close();
sletz's avatar
sletz committed
326

sletz's avatar
sletz committed
327
        /// Network init
sletz's avatar
sletz committed
328
        if (!JackNetMasterInterface::Init()) {
329
            return -1;
sletz's avatar
sletz committed
330
        }
331
332

        // Set global parameters
sletz's avatar
sletz committed
333
        if (!SetParams()) {
sletz's avatar
sletz committed
334
            return -1;
sletz's avatar
sletz committed
335
        }
sletz's avatar
sletz committed
336

337
338
339
        AllocPorts();
        return 0;
    }
sletz's avatar
sletz committed
340

341
342
343
344
345
346
    int Close()
    {
        fSocket.Close();
        FreePorts();
        return 0;
    }
sletz's avatar
sletz committed
347

348
349
    void AllocPorts()
    {
sletz's avatar
sletz committed
350
        // Set buffers
351
352
        if (fParams.fSendAudioChannels > 0) {
            fAudioCaptureBuffer = new float*[fParams.fSendAudioChannels];
sletz's avatar
sletz committed
353
354
355
            for (int audio_port_index = 0; audio_port_index < fParams.fSendAudioChannels; audio_port_index++) {
                fAudioCaptureBuffer[audio_port_index] = new float[fParams.fPeriodSize];
                fNetAudioCaptureBuffer->SetBuffer(audio_port_index, fAudioCaptureBuffer[audio_port_index]);
356
            }
357
        }
sletz's avatar
sletz committed
358

359
360
        if (fParams.fSendMidiChannels > 0) {
            fMidiCaptureBuffer = new JackMidiBuffer*[fParams.fSendMidiChannels];
sletz's avatar
sletz committed
361
362
363
            for (int midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
                fMidiCaptureBuffer[midi_port_index] = (JackMidiBuffer*)new float[fParams.fPeriodSize];
                fNetMidiCaptureBuffer->SetBuffer(midi_port_index, fMidiCaptureBuffer[midi_port_index]);
364
            }
365
        }
sletz's avatar
sletz committed
366

367
368
        if (fParams.fReturnAudioChannels > 0) {
            fAudioPlaybackBuffer = new float*[fParams.fReturnAudioChannels];
sletz's avatar
sletz committed
369
370
371
            for (int audio_port_index = 0; audio_port_index < fParams.fReturnAudioChannels; audio_port_index++) {
                fAudioPlaybackBuffer[audio_port_index] = new float[fParams.fPeriodSize];
                fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, fAudioPlaybackBuffer[audio_port_index]);
sletz's avatar
sletz committed
372
            }
373
        }
sletz's avatar
sletz committed
374

375
376
        if (fParams.fReturnMidiChannels > 0) {
            fMidiPlaybackBuffer = new JackMidiBuffer*[fParams.fReturnMidiChannels];
sletz's avatar
sletz committed
377
378
379
            for (int midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
                fMidiPlaybackBuffer[midi_port_index] = (JackMidiBuffer*)new float[fParams.fPeriodSize];
                fNetMidiPlaybackBuffer->SetBuffer(midi_port_index, fMidiPlaybackBuffer[midi_port_index]);
380
            }
381
382
        }
    }
sletz's avatar
sletz committed
383

384
385
    void FreePorts()
    {
386
        if (fAudioCaptureBuffer) {
387
            for (int audio_port_index = 0; audio_port_index < fParams.fSendAudioChannels; audio_port_index++) {
388
                delete[] fAudioCaptureBuffer[audio_port_index];
389
            }
390
391
            delete[] fAudioCaptureBuffer;
            fAudioCaptureBuffer = NULL;
392
        }
393
394
        
        if (fMidiCaptureBuffer) {
395
            for (int midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
396
                delete[] fMidiCaptureBuffer[midi_port_index];
397
            }
398
399
            delete[] fMidiCaptureBuffer;
            fMidiCaptureBuffer = NULL;
400
        }
401
402
        
        if (fAudioPlaybackBuffer) {
403
            for (int audio_port_index = 0; audio_port_index < fParams.fReturnAudioChannels; audio_port_index++) {
404
                delete[] fAudioPlaybackBuffer[audio_port_index];
405
            }
406
407
            delete[] fAudioPlaybackBuffer;
            fAudioPlaybackBuffer = NULL;
408
        }
sletz's avatar
sletz committed
409

410
        if (fMidiPlaybackBuffer) {
411
            for (int midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
412
                delete[] (fMidiPlaybackBuffer[midi_port_index]);
413
            }
414
415
            delete[] fMidiPlaybackBuffer;
            fMidiPlaybackBuffer = NULL;
416
417
        }
    }
sletz's avatar
sletz committed
418

419
    int Read(int audio_input, float** audio_input_buffer, int midi_input, void** midi_input_buffer)
sletz's avatar
sletz committed
420
    {
sletz's avatar
sletz committed
421
        try {
sletz's avatar
sletz committed
422
           
sletz's avatar
sletz committed
423
            assert(audio_input == fParams.fReturnAudioChannels);
sletz's avatar
sletz committed
424

sletz's avatar
sletz committed
425
426
            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
427
            }
sletz's avatar
sletz committed
428

sletz's avatar
sletz committed
429
430
            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
431
            }
sletz's avatar
sletz committed
432
         
433
434
435
            int res = SyncRecv();
            switch (res) {
            
Stephane Letz's avatar
Stephane Letz committed
436
                case NET_SYNCHING:
437
438
439
                case SOCKET_ERROR:
                    return res;
                    
440
                case SYNC_PACKET_ERROR:
441
                    // since sync packet is incorrect, don't decode it and continue with data
442
443
444
                    break;
                    
                default:
445
                    // decode sync
446
447
448
449
                    DecodeSyncPacket();
                    break;
            }
          
sletz's avatar
sletz committed
450
            return DataRecv();
sletz's avatar
sletz committed
451

sletz's avatar
sletz committed
452
        } catch (JackNetException& e) {
453
            jack_error("Lost connection");
sletz's avatar
sletz committed
454
            return -1;
sletz's avatar
sletz committed
455
        }
456
    }
457

458
459
    int Write(int audio_output, float** audio_output_buffer, int midi_output, void** midi_output_buffer)
    {
sletz's avatar
sletz committed
460
        try {
sletz's avatar
sletz committed
461
            
sletz's avatar
sletz committed
462
            assert(audio_output == fParams.fSendAudioChannels);
sletz's avatar
sletz committed
463

sletz's avatar
sletz committed
464
465
466
            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
467

sletz's avatar
sletz committed
468
469
470
            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
471
            
472
            EncodeSyncPacket();
sletz's avatar
sletz committed
473

474
475
476
477
            // send sync
            if (SyncSend() == SOCKET_ERROR) {
                return SOCKET_ERROR;
            }
sletz's avatar
sletz committed
478

479
            // send data
480
481
            if (DataSend() == SOCKET_ERROR) {
                return SOCKET_ERROR;
sletz's avatar
sletz committed
482
            }
sletz's avatar
sletz committed
483
484
            
            return 0;
sletz's avatar
sletz committed
485

sletz's avatar
sletz committed
486
        } catch (JackNetException& e) {
487
            jack_error("Lost connection");
sletz's avatar
sletz committed
488
            return -1;
sletz's avatar
sletz committed
489
        }
sletz's avatar
sletz committed
490
    }
sletz's avatar
sletz committed
491

492
    // Transport
sletz's avatar
sletz committed
493
494
    void EncodeTransportData()
    {}
sletz's avatar
sletz committed
495

sletz's avatar
sletz committed
496
497
    void DecodeTransportData()
    {}
sletz's avatar
sletz committed
498

499
500
501
};

struct JackNetExtSlave : public JackNetSlaveInterface, public JackRunnableInterface {
sletz's avatar
sletz committed
502

503
    JackThread fThread;
sletz's avatar
sletz committed
504

505
506
    JackNetSlaveProcessCallback fProcessCallback;
    void* fProcessArg;
sletz's avatar
sletz committed
507

508
509
    JackNetSlaveShutdownCallback fShutdownCallback;
    void* fShutdownArg;
510
511
    
    JackNetSlaveRestartCallback fRestartCallback;
512
513
514
515
    void* fRestartArg;
    
    JackNetSlaveErrorCallback fErrorCallback;
    void* fErrorArg;
sletz's avatar
sletz committed
516

517
518
    JackNetSlaveBufferSizeCallback fBufferSizeCallback;
    void* fBufferSizeArg;
sletz's avatar
sletz committed
519

520
521
    JackNetSlaveSampleRateCallback fSampleRateCallback;
    void* fSampleRateArg;
sletz's avatar
sletz committed
522

523
524
525
    //sample buffers
    float** fAudioCaptureBuffer;
    float** fAudioPlaybackBuffer;
sletz's avatar
sletz committed
526

527
528
    JackMidiBuffer** fMidiCaptureBuffer;
    JackMidiBuffer** fMidiPlaybackBuffer;
sletz's avatar
sletz committed
529

sletz's avatar
sletz committed
530
    int fConnectTimeOut;
531
   
sletz's avatar
sletz committed
532
533
534
    JackNetExtSlave(const char* ip,
                    int port,
                    const char* name,
sletz's avatar
sletz committed
535
                    jack_slave_t* request)
536
        :fThread(this),
sletz's avatar
sletz committed
537
        fProcessCallback(NULL),fProcessArg(NULL),
538
        fShutdownCallback(NULL), fShutdownArg(NULL),
539
        fRestartCallback(NULL), fRestartArg(NULL),
540
        fErrorCallback(NULL), fErrorArg(NULL),
541
542
543
544
545
546
        fBufferSizeCallback(NULL), fBufferSizeArg(NULL),
        fSampleRateCallback(NULL), fSampleRateArg(NULL),
        fAudioCaptureBuffer(NULL), fAudioPlaybackBuffer(NULL),
        fMidiCaptureBuffer(NULL), fMidiPlaybackBuffer(NULL)
    {
        char host_name[JACK_CLIENT_NAME_SIZE];
sletz's avatar
sletz committed
547

548
549
550
551
552
553
554
555
        // 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
556
        fParams.fReturnMidiChannels = request->midi_output;
557
        fParams.fNetworkLatency = request->latency;
558
559
        fParams.fSampleEncoder = request->encoder;
        fParams.fKBps = request->kbps;
sletz's avatar
sletz committed
560
        fParams.fSlaveSyncMode = 1;
sletz's avatar
sletz committed
561
        fConnectTimeOut = request->time_out;
sletz's avatar
sletz committed
562

563
564
565
566
        // 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
567

568
569
570
571
        // Set the socket parameters
        fSocket.SetPort(port);
        fSocket.SetAddress(fMulticastIP, port);
    }
sletz's avatar
sletz committed
572

573
574
    virtual ~JackNetExtSlave()
    {}
sletz's avatar
sletz committed
575

576
577
    int Open(jack_master_t* result)
    {
sletz's avatar
sletz committed
578
        // Check CELT encoder parameters
sletz's avatar
sletz committed
579
580
581
582
583
        if ((fParams.fSampleEncoder == JackCeltEncoder) && (fParams.fKBps == 0)) {
            jack_error("CELT encoder with 0 for kps...");
            return -1;
        }
        
Robin Gareus's avatar
Robin Gareus committed
584
585
586
587
588
        if ((fParams.fSampleEncoder == JackOpusEncoder) && (fParams.fKBps == 0)) {
            jack_error("Opus encoder with 0 for kps...");
            return -1;
        }

sletz's avatar
sletz committed
589
        // Check latency
sletz's avatar
sletz committed
590
        if (fParams.fNetworkLatency > NETWORK_MAX_LATENCY) {
Stephane Letz's avatar
Stephane Letz committed
591
            jack_error("Error : network latency is limited to %d", NETWORK_MAX_LATENCY);
sletz's avatar
sletz committed
592
593
594
            return -1;
        }

595
        // Init network connection
sletz's avatar
sletz committed
596
        if (!JackNetSlaveInterface::InitConnection(fConnectTimeOut)) {
Stephane Letz's avatar
Stephane Letz committed
597
598
599
600
601
602
603
            jack_error("Initing network fails...");
            return -1;
        }

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

607
        // Then set global parameters
sletz's avatar
sletz committed
608
        if (!SetParams()) {
Stephane Letz's avatar
Stephane Letz committed
609
            jack_error("SetParams error...");
sletz's avatar
sletz committed
610
            return -1;
sletz's avatar
sletz committed
611
        }
sletz's avatar
sletz committed
612

613
614
615
616
         // Set result
         if (result != NULL) {
            result->buffer_size = fParams.fPeriodSize;
            result->sample_rate = fParams.fSampleRate;
617
618
619
620
            result->audio_input = fParams.fSendAudioChannels;
            result->audio_output = fParams.fReturnAudioChannels;
            result->midi_input = fParams.fSendMidiChannels;
            result->midi_output = fParams.fReturnMidiChannels;
621
622
            strcpy(result->master_name, fParams.fMasterNetName);
        }
sletz's avatar
sletz committed
623

624
625
626
        AllocPorts();
        return 0;
    }
sletz's avatar
sletz committed
627

628
    int Restart() 
629
    {
630
631
632
633
634
635
636
637
638
639
640
641
       // 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
642

643
644
645
646
647
648
            // 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
649
650
        }

sletz's avatar
sletz committed
651
         // Finish connection
Stephane Letz's avatar
Stephane Letz committed
652
653
        if (!JackNetSlaveInterface::InitRendering()) {
            jack_error("Starting network fails...");
654
            return -1;
sletz's avatar
sletz committed
655
        }
sletz's avatar
sletz committed
656

657
        // Then set global parameters
sletz's avatar
sletz committed
658
        if (!SetParams()) {
Stephane Letz's avatar
Stephane Letz committed
659
            jack_error("SetParams error...");
sletz's avatar
sletz committed
660
            return -1;
sletz's avatar
sletz committed
661
        }
sletz's avatar
sletz committed
662

663
        // We need to notify possibly new buffer size and sample rate (see Execute)
sletz's avatar
sletz committed
664
        if (fBufferSizeCallback) {
665
666
667
668
            if (fBufferSizeCallback(fParams.fPeriodSize, fBufferSizeArg) != 0) {
                jack_error("New buffer size = %d cannot be used...", fParams.fPeriodSize);
                return -1;
            }
sletz's avatar
sletz committed
669
        }
sletz's avatar
sletz committed
670

sletz's avatar
sletz committed
671
        if (fSampleRateCallback) {
672
673
674
675
            if (fSampleRateCallback(fParams.fSampleRate, fSampleRateArg) != 0) {
                jack_error("New sample rate = %d cannot be used...", fParams.fSampleRate);
                return -1;
            }
sletz's avatar
sletz committed
676
        }
sletz's avatar
sletz committed
677

678
679
680
        AllocPorts();
        return 0;
    }
sletz's avatar
sletz committed
681

682
683
684
685
686
687
688
689
690
691
692
    int Close()
    {
        fSocket.Close();
        FreePorts();
        return 0;
    }

    void AllocPorts()
    {
        // Set buffers
        fAudioCaptureBuffer = new float*[fParams.fSendAudioChannels];
sletz's avatar
sletz committed
693
694
695
        for (int audio_port_index = 0; audio_port_index < fParams.fSendAudioChannels; audio_port_index++) {
            fAudioCaptureBuffer[audio_port_index] = new float[fParams.fPeriodSize];
            fNetAudioCaptureBuffer->SetBuffer(audio_port_index, fAudioCaptureBuffer[audio_port_index]);
696
        }
sletz's avatar
sletz committed
697

698
        fMidiCaptureBuffer = new JackMidiBuffer*[fParams.fSendMidiChannels];
sletz's avatar
sletz committed
699
700
701
        for (int midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
            fMidiCaptureBuffer[midi_port_index] = (JackMidiBuffer*)new float[fParams.fPeriodSize];
            fNetMidiCaptureBuffer->SetBuffer(midi_port_index, fMidiCaptureBuffer[midi_port_index]);
702
        }
sletz's avatar
sletz committed
703

704
        fAudioPlaybackBuffer = new float*[fParams.fReturnAudioChannels];
sletz's avatar
sletz committed
705
706
707
        for (int audio_port_index = 0; audio_port_index < fParams.fReturnAudioChannels; audio_port_index++) {
            fAudioPlaybackBuffer[audio_port_index] = new float[fParams.fPeriodSize];
            fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, fAudioPlaybackBuffer[audio_port_index]);
sletz's avatar
sletz committed
708
709
        }

710
        fMidiPlaybackBuffer = new JackMidiBuffer*[fParams.fReturnMidiChannels];
sletz's avatar
sletz committed
711
712
713
        for (int midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
            fMidiPlaybackBuffer[midi_port_index] = (JackMidiBuffer*)new float[fParams.fPeriodSize];
            fNetMidiPlaybackBuffer->SetBuffer(midi_port_index, fMidiPlaybackBuffer[midi_port_index]);
714
715
        }
    }
sletz's avatar
sletz committed
716

717
718
719
    void FreePorts()
    {
        if (fAudioCaptureBuffer) {
sletz's avatar
sletz committed
720
            for (int audio_port_index = 0; audio_port_index < fParams.fSendAudioChannels; audio_port_index++) {
sletz's avatar
sletz committed
721
                delete[] fAudioCaptureBuffer[audio_port_index];
sletz's avatar
sletz committed
722
            }
723
724
725
            delete[] fAudioCaptureBuffer;
            fAudioCaptureBuffer = NULL;
        }
sletz's avatar
sletz committed
726

727
        if (fMidiCaptureBuffer) {
sletz's avatar
sletz committed
728
            for (int midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
sletz's avatar
sletz committed
729
                delete[] (fMidiCaptureBuffer[midi_port_index]);
sletz's avatar
sletz committed
730
            }
731
732
733
734
735
            delete[] fMidiCaptureBuffer;
            fMidiCaptureBuffer = NULL;
        }

        if (fAudioPlaybackBuffer) {
sletz's avatar
sletz committed
736
            for (int audio_port_index = 0; audio_port_index < fParams.fReturnAudioChannels; audio_port_index++) {
sletz's avatar
sletz committed
737
                delete[] fAudioPlaybackBuffer[audio_port_index];
sletz's avatar
sletz committed
738
            }
739
740
741
            delete[] fAudioPlaybackBuffer;
            fAudioPlaybackBuffer = NULL;
        }
sletz's avatar
sletz committed
742

743
        if (fMidiPlaybackBuffer) {
sletz's avatar
sletz committed
744
            for (int midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
sletz's avatar
sletz committed
745
                delete[] fMidiPlaybackBuffer[midi_port_index];
sletz's avatar
sletz committed
746
            }
747
748
749
750
            delete[] fMidiPlaybackBuffer;
            fMidiPlaybackBuffer = NULL;
        }
    }
sletz's avatar
sletz committed
751

752
    // Transport
sletz's avatar
sletz committed
753
754
    void EncodeTransportData()
    {}
sletz's avatar
sletz committed
755

sletz's avatar
sletz committed
756
757
    void DecodeTransportData()
    {}
sletz's avatar
sletz committed
758
759

    bool Init()
760
761
    {
        // Will do "something" on OSX only...
sletz's avatar
sletz committed
762
        UInt64 period, constraint;
Stephane Letz's avatar
Stephane Letz committed
763
764
        period = constraint = UInt64(1000000000.f * (float(fParams.fPeriodSize) / float(fParams.fSampleRate)));
        UInt64 computation = JackTools::ComputationMicroSec(fParams.fPeriodSize) * 1000;
sletz's avatar
sletz committed
765
766
        fThread.SetParams(period, computation, constraint);

sletz's avatar
sletz committed
767
        return (fThread.AcquireSelfRealTime(80) == 0);      // TODO: get a value from the server
768
    }
769
770
771
772
773
    
    bool IsRunning()
    {
        return (fThread.GetStatus() == JackThread::kRunning);
    }
sletz's avatar
sletz committed
774

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

807
808
    int Read()
    {
809
        // receive sync (launch the cycle)
Stephane Letz's avatar
Stephane Letz committed
810
        switch (SyncRecv()) {
811
812
813
814
        
            case SOCKET_ERROR:
                return SOCKET_ERROR;
                
815
            case SYNC_PACKET_ERROR:
816
                // since sync packet is incorrect, don't decode it and continue with data
817
818
819
                if (fErrorCallback) {
                    fErrorCallback(SYNC_PACKET_ERROR, fErrorArg);
                }
820
821
822
                break;
                
            default:
823
                // decode sync
824
825
826
827
                DecodeSyncPacket();
                break;
        }

828
829
830
831
832
        int res = DataRecv();
        if (res == DATA_PACKET_ERROR && fErrorCallback) {
            fErrorCallback(DATA_PACKET_ERROR, fErrorArg);
        }
        return res;
833
834
835
836
    }

    int Write()
    {
sletz's avatar
sletz committed
837
        EncodeSyncPacket();
sletz's avatar
sletz committed
838

sletz's avatar
sletz committed
839
        if (SyncSend() == SOCKET_ERROR) {
840
            return SOCKET_ERROR;
sletz's avatar
sletz committed
841
        }
842
843
844

        return DataSend();
    }
845
846
847
848
849
850
851
852
853
854
855
856
    
    void DummyProcess()
    {
        // First cycle with INT_MAX time out
        SetPackedTimeOut(INT_MAX);
        
        // One cycle
        Process();
        
        // Then use PACKET_TIMEOUT for next cycles
        SetPackedTimeOut(PACKET_TIMEOUT);
    }
sletz's avatar
sletz committed
857
858

    int Process()
859
    {
sletz's avatar
sletz committed
860
        // Read data from the network, throw JackNetException in case of network error...
sletz's avatar
sletz committed
861
        if (Read() == SOCKET_ERROR) {
862
            return SOCKET_ERROR;
sletz's avatar
sletz committed
863
        }
sletz's avatar
sletz committed
864
865
866
867

        fProcessCallback(fParams.fPeriodSize,
                        fParams.fSendAudioChannels,
                        fAudioCaptureBuffer,
868
                        fParams.fSendMidiChannels,
sletz's avatar
sletz committed
869
                        (void**)fMidiCaptureBuffer,
870
                        fParams.fReturnAudioChannels,
sletz's avatar
sletz committed
871
                        fAudioPlaybackBuffer,
872
                        fParams.fReturnMidiChannels,
sletz's avatar
sletz committed
873
874
875
                        (void**)fMidiPlaybackBuffer,
                        fProcessArg);

sletz's avatar
sletz committed
876
        // Then write data to network, throw JackNetException in case of network error...
sletz's avatar
sletz committed
877
        if (Write() == SOCKET_ERROR) {
878
            return SOCKET_ERROR;
sletz's avatar
sletz committed
879
        }
880
881
882

        return 0;
    }
sletz's avatar
sletz committed
883

884
885
886
887
888
889
890
891
892
    int Start()
    {
        return (fProcessCallback == 0) ? -1 : fThread.StartSync();
    }

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

894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
    // 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;
        }