JackNetManager.cpp 37.1 KB
Newer Older
1
/*
sletz's avatar
sletz committed
2
Copyright(C) 2008-2011 Romain Moret at Grame
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "JackNetManager.h"
20
#include "JackArgParser.h"
sletz's avatar
sletz committed
21
22
#include "JackServerGlobals.h"
#include "JackLockedEngine.h"
23
#include "thread.h"
24
25
26
27
28
29
30

using namespace std;

namespace Jack
{
//JackNetMaster******************************************************************************************************

sletz's avatar
sletz committed
31
32
    JackNetMaster::JackNetMaster(JackNetSocket& socket, session_params_t& params, const char* multicast_ip)
            : JackNetMasterInterface(params, socket, multicast_ip)
33
    {
sletz's avatar
sletz committed
34
        jack_log("JackNetMaster::JackNetMaster");
moret's avatar
moret committed
35

36
        //settings
37
38
        fName = const_cast<char*>(fParams.fName);
        fClient = NULL;
39
40
41
        fSendTransportData.fState = -1;
        fReturnTransportData.fState = -1;
        fLastTransportState = -1;
sletz's avatar
sletz committed
42
        int port_index;
43
44
45

        //jack audio ports
        fAudioCapturePorts = new jack_port_t* [fParams.fSendAudioChannels];
sletz's avatar
sletz committed
46
        for (port_index = 0; port_index < fParams.fSendAudioChannels; port_index++) {
47
            fAudioCapturePorts[port_index] = NULL;
sletz's avatar
sletz committed
48
49
        }

50
        fAudioPlaybackPorts = new jack_port_t* [fParams.fReturnAudioChannels];
sletz's avatar
sletz committed
51
        for (port_index = 0; port_index < fParams.fReturnAudioChannels; port_index++) {
52
            fAudioPlaybackPorts[port_index] = NULL;
sletz's avatar
sletz committed
53
54
        }

55
56
        //jack midi ports
        fMidiCapturePorts = new jack_port_t* [fParams.fSendMidiChannels];
sletz's avatar
sletz committed
57
        for (port_index = 0; port_index < fParams.fSendMidiChannels; port_index++) {
58
            fMidiCapturePorts[port_index] = NULL;
sletz's avatar
sletz committed
59
60
        }

61
        fMidiPlaybackPorts = new jack_port_t* [fParams.fReturnMidiChannels];
sletz's avatar
sletz committed
62
        for (port_index = 0; port_index < fParams.fReturnMidiChannels; port_index++) {
63
            fMidiPlaybackPorts[port_index] = NULL;
sletz's avatar
sletz committed
64
        }
65
    
moret's avatar
moret committed
66
        //monitor
67
#ifdef JACK_MONITOR
sletz's avatar
sletz committed
68
        fPeriodUsecs = (int)(1000000.f * ((float) fParams.fPeriodSize / (float) fParams.fSampleRate));
moret's avatar
moret committed
69
        string plot_name;
sletz's avatar
sletz committed
70
71
72
73
74
        plot_name = string(fParams.fName);
        plot_name += string("_master");
        plot_name += string((fParams.fSlaveSyncMode) ? "_sync" : "_async");
        plot_name += string("_latency");
        fNetTimeMon = new JackGnuPlotMonitor<float>(128, 4, plot_name);
moret's avatar
moret committed
75
76
        string net_time_mon_fields[] =
        {
sletz's avatar
sletz committed
77
78
79
80
            string("sync send"),
            string("end of send"),
            string("sync recv"),
            string("end of cycle")
moret's avatar
moret committed
81
82
83
        };
        string net_time_mon_options[] =
        {
sletz's avatar
sletz committed
84
85
            string("set xlabel \"audio cycles\""),
            string("set ylabel \"% of audio cycle\"")
moret's avatar
moret committed
86
        };
sletz's avatar
sletz committed
87
        fNetTimeMon->SetPlotFile(net_time_mon_options, 2, net_time_mon_fields, 4);
moret's avatar
moret committed
88
#endif
89
90
91
92
    }

    JackNetMaster::~JackNetMaster()
    {
sletz's avatar
sletz committed
93
        jack_log("JackNetMaster::~JackNetMaster ID = %u", fParams.fID);
moret's avatar
moret committed
94

95
96
        if (fClient) {
            jack_deactivate(fClient);
97
            FreePorts();
98
            jack_client_close(fClient);
99
100
101
102
103
        }
        delete[] fAudioCapturePorts;
        delete[] fAudioPlaybackPorts;
        delete[] fMidiCapturePorts;
        delete[] fMidiPlaybackPorts;
104
#ifdef JACK_MONITOR
moret's avatar
moret committed
105
106
        fNetTimeMon->Save();
        delete fNetTimeMon;
moret's avatar
moret committed
107
#endif
108
    }
109
//init--------------------------------------------------------------------------------
110
    bool JackNetMaster::Init(bool auto_connect)
111
    {
112
        //network init
sletz's avatar
sletz committed
113
        if (!JackNetMasterInterface::Init()) {
sletz's avatar
sletz committed
114
            jack_error("JackNetMasterInterface::Init() error...");
115
            return false;
sletz's avatar
sletz committed
116
        }
117

moret's avatar
moret committed
118
        //set global parameters
sletz's avatar
sletz committed
119
        if (!SetParams()) {
sletz's avatar
sletz committed
120
            jack_error("SetParams error...");
sletz's avatar
sletz committed
121
            return false;
sletz's avatar
sletz committed
122
        }
moret's avatar
moret committed
123

124
125
        //jack client and process
        jack_status_t status;
126
        if ((fClient = jack_client_open(fName, JackNullOption, &status, NULL)) == NULL) {
sletz's avatar
sletz committed
127
            jack_error("Can't open a new JACK client");
128
129
            return false;
        }
130
131
        
        if (jack_set_process_callback(fClient, SetProcess, this) < 0) {
132
133
            goto fail;
        }
sletz's avatar
sletz committed
134

135
        if (jack_set_buffer_size_callback(fClient, SetBufferSize, this) < 0) {
136
137
            goto fail;
        }
138
        
139
140
141
142
        if (jack_set_sample_rate_callback(fClient, SetSampleRate, this) < 0) {
            goto fail;
        }
        
143
144
145
146
        if (jack_set_latency_callback(fClient, LatencyCallback, this) < 0) {
            goto fail;
        }
        
147
148
149
150
151
        /*
        if (jack_set_port_connect_callback(fClient, SetConnectCallback, this) < 0) {
            goto fail;
        }
        */
152
     
153
        if (AllocPorts() != 0) {
sletz's avatar
sletz committed
154
            jack_error("Can't allocate JACK ports");
155
            goto fail;
156
157
        }

moret's avatar
moret committed
158
        //process can now run
159
        fRunning = true;
160

161
        //finally activate jack client
162
        if (jack_activate(fClient) != 0) {
sletz's avatar
sletz committed
163
            jack_error("Can't activate JACK client");
164
            goto fail;
165
        }
sletz's avatar
sletz committed
166

167
        if (auto_connect) {
168
            ConnectPorts();
169
170
        }
        jack_info("New NetMaster started");
171
        return true;
172

moret's avatar
moret committed
173
    fail:
174
        FreePorts();
175
176
        jack_client_close(fClient);
        fClient = NULL;
177
178
179
        return false;
    }

180
//jack ports--------------------------------------------------------------------------
181
182
    int JackNetMaster::AllocPorts()
    {
sletz's avatar
sletz committed
183
        int i;
184
        char name[32];
sletz's avatar
sletz committed
185
        jack_log("JackNetMaster::AllocPorts");
186

187
        //audio
sletz's avatar
sletz committed
188
        for (i = 0; i < fParams.fSendAudioChannels; i++) {
sletz's avatar
sletz committed
189
            snprintf(name, sizeof(name), "to_slave_%d", i+1);
190
            if ((fAudioCapturePorts[i] = jack_port_register(fClient, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0)) == NULL) {
191
                return -1;
192
            }
193
        }
sletz's avatar
sletz committed
194

sletz's avatar
sletz committed
195
        for (i = 0; i < fParams.fReturnAudioChannels; i++) {
sletz's avatar
sletz committed
196
            snprintf(name, sizeof(name), "from_slave_%d", i+1);
197
            if ((fAudioPlaybackPorts[i] = jack_port_register(fClient, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput | JackPortIsTerminal, 0)) == NULL) {
198
                return -1;
199
            }
200
        }
sletz's avatar
sletz committed
201

202
        //midi
sletz's avatar
sletz committed
203
        for (i = 0; i < fParams.fSendMidiChannels; i++) {
sletz's avatar
sletz committed
204
            snprintf(name, sizeof(name), "midi_to_slave_%d", i+1);
205
            if ((fMidiCapturePorts[i] = jack_port_register(fClient, name, JACK_DEFAULT_MIDI_TYPE, JackPortIsInput | JackPortIsTerminal, 0)) == NULL) {
206
                return -1;
207
            }
208
        }
sletz's avatar
sletz committed
209
210

        for (i = 0; i < fParams.fReturnMidiChannels; i++) {
sletz's avatar
sletz committed
211
            snprintf(name, sizeof(name), "midi_from_slave_%d", i+1);
212
            if ((fMidiPlaybackPorts[i] = jack_port_register(fClient, name, JACK_DEFAULT_MIDI_TYPE,  JackPortIsOutput | JackPortIsTerminal, 0)) == NULL) {
213
                return -1;
214
            }
215
        }
216
        return 0;
217
    }
sletz's avatar
sletz committed
218

219
220
    void JackNetMaster::ConnectPorts()
    {
221
        const char** ports = jack_get_ports(fClient, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortIsPhysical | JackPortIsOutput);
222
        if (ports != NULL) {
sletz's avatar
sletz committed
223
            for (int i = 0; i < fParams.fSendAudioChannels && ports[i]; i++) {
224
                jack_connect(fClient, ports[i], jack_port_name(fAudioCapturePorts[i]));
225
            }
226
            jack_free(ports);
227
        }
sletz's avatar
sletz committed
228

229
        ports = jack_get_ports(fClient, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortIsPhysical | JackPortIsInput);
230
        if (ports != NULL) {
sletz's avatar
sletz committed
231
            for (int i = 0; i < fParams.fReturnAudioChannels && ports[i]; i++) {
232
                jack_connect(fClient, jack_port_name(fAudioPlaybackPorts[i]), ports[i]);
233
            }
234
            jack_free(ports);
235
236
        }
    }
237
238
239

    void JackNetMaster::FreePorts()
    {
sletz's avatar
sletz committed
240
        jack_log("JackNetMaster::FreePorts ID = %u", fParams.fID);
moret's avatar
moret committed
241

sletz's avatar
sletz committed
242
        int port_index;
sletz's avatar
sletz committed
243
244
        for (port_index = 0; port_index < fParams.fSendAudioChannels; port_index++) {
            if (fAudioCapturePorts[port_index]) {
245
                jack_port_unregister(fClient, fAudioCapturePorts[port_index]);
sletz's avatar
sletz committed
246
247
248
249
            }
        }
        for (port_index = 0; port_index < fParams.fReturnAudioChannels; port_index++) {
            if (fAudioPlaybackPorts[port_index]) {
250
                jack_port_unregister(fClient, fAudioPlaybackPorts[port_index]);
sletz's avatar
sletz committed
251
252
253
254
            }
        }
        for (port_index = 0; port_index < fParams.fSendMidiChannels; port_index++) {
            if (fMidiCapturePorts[port_index]) {
255
                jack_port_unregister(fClient, fMidiCapturePorts[port_index]);
sletz's avatar
sletz committed
256
257
258
259
            }
        }
        for (port_index = 0; port_index < fParams.fReturnMidiChannels; port_index++) {
            if (fMidiPlaybackPorts[port_index]) {
260
                jack_port_unregister(fClient, fMidiPlaybackPorts[port_index]);
sletz's avatar
sletz committed
261
262
            }
        }
263
264
    }

265
//transport---------------------------------------------------------------------------
266
    void JackNetMaster::EncodeTransportData()
267
268
269
    {
        //is there a new timebase master ?
        //TODO : check if any timebase callback has been called (and if it's conditional or not) and set correct value...
270
        fSendTransportData.fTimebaseMaster = NO_CHANGE;
271
272

        //update state and position
273
        fSendTransportData.fState = static_cast<uint>(jack_transport_query(fClient, &fSendTransportData.fPosition));
274
275

        //is it a new state ?
sletz's avatar
sletz committed
276
277
278
279
        fSendTransportData.fNewState = ((fSendTransportData.fState != fLastTransportState) && (fSendTransportData.fState != fReturnTransportData.fState));
        if (fSendTransportData.fNewState) {
            jack_info("Sending '%s' to '%s' frame = %ld", GetTransportState(fSendTransportData.fState), fParams.fName, fSendTransportData.fPosition.frame);
        }
280
        fLastTransportState = fSendTransportData.fState;
281
   }
282

283
    void JackNetMaster::DecodeTransportData()
284
    {
285
        //is there timebase master change ?
sletz's avatar
sletz committed
286
287
        if (fReturnTransportData.fTimebaseMaster != NO_CHANGE) {

288
            int timebase = 0;
sletz's avatar
sletz committed
289
            switch (fReturnTransportData.fTimebaseMaster)
290
291
            {
                case RELEASE_TIMEBASEMASTER :
292
                    timebase = jack_release_timebase(fClient);
sletz's avatar
sletz committed
293
294
295
296
297
                    if (timebase < 0) {
                        jack_error("Can't release timebase master");
                    } else {
                        jack_info("'%s' isn't the timebase master anymore", fParams.fName);
                    }
298
                    break;
sletz's avatar
sletz committed
299

300
                case TIMEBASEMASTER :
301
                    timebase = jack_set_timebase_callback(fClient, 0, SetTimebaseCallback, this);
sletz's avatar
sletz committed
302
303
304
305
306
                    if (timebase < 0) {
                        jack_error("Can't set a new timebase master");
                    } else {
                        jack_info("'%s' is the new timebase master", fParams.fName);
                    }
307
                    break;
sletz's avatar
sletz committed
308

309
                case CONDITIONAL_TIMEBASEMASTER :
310
                    timebase = jack_set_timebase_callback(fClient, 1, SetTimebaseCallback, this);
sletz's avatar
sletz committed
311
312
313
                    if (timebase != EBUSY) {
                        if (timebase < 0)
                            jack_error("Can't set a new timebase master");
314
                        else
sletz's avatar
sletz committed
315
                            jack_info("'%s' is the new timebase master", fParams.fName);
316
317
318
                    }
                    break;
            }
319
320
        }

321
        //is the slave in a new transport state and is this state different from master's ?
322
        if (fReturnTransportData.fNewState && (fReturnTransportData.fState != jack_transport_query(fClient, NULL))) {
sletz's avatar
sletz committed
323
324

            switch (fReturnTransportData.fState)
325
326
            {
                case JackTransportStopped :
327
                    jack_transport_stop(fClient);
sletz's avatar
sletz committed
328
                    jack_info("'%s' stops transport", fParams.fName);
329
                    break;
sletz's avatar
sletz committed
330

331
                case JackTransportStarting :
332
                    if (jack_transport_reposition(fClient, &fReturnTransportData.fPosition) == EINVAL)
sletz's avatar
sletz committed
333
                        jack_error("Can't set new position");
334
                    jack_transport_start(fClient);
sletz's avatar
sletz committed
335
                    jack_info("'%s' starts transport frame = %d", fParams.fName, fReturnTransportData.fPosition.frame);
336
                    break;
sletz's avatar
sletz committed
337

338
                case JackTransportNetStarting :
sletz's avatar
sletz committed
339
                    jack_info("'%s' is ready to roll...", fParams.fName);
moret's avatar
moret committed
340
                    break;
sletz's avatar
sletz committed
341

342
                case JackTransportRolling :
sletz's avatar
sletz committed
343
                    jack_info("'%s' is rolling", fParams.fName);
344
345
346
347
348
                    break;
            }
        }
    }

sletz's avatar
sletz committed
349
    void JackNetMaster::SetTimebaseCallback(jack_transport_state_t state, jack_nframes_t nframes, jack_position_t* pos, int new_pos, void* arg)
350
    {
sletz's avatar
sletz committed
351
        static_cast<JackNetMaster*>(arg)->TimebaseCallback(pos);
352
353
    }

sletz's avatar
sletz committed
354
    void JackNetMaster::TimebaseCallback(jack_position_t* pos)
355
    {
356
357
358
359
360
361
362
363
        pos->bar = fReturnTransportData.fPosition.bar;
        pos->beat = fReturnTransportData.fPosition.beat;
        pos->tick = fReturnTransportData.fPosition.tick;
        pos->bar_start_tick = fReturnTransportData.fPosition.bar_start_tick;
        pos->beats_per_bar = fReturnTransportData.fPosition.beats_per_bar;
        pos->beat_type = fReturnTransportData.fPosition.beat_type;
        pos->ticks_per_beat = fReturnTransportData.fPosition.ticks_per_beat;
        pos->beats_per_minute = fReturnTransportData.fPosition.beats_per_minute;
364
365
366
    }

//sync--------------------------------------------------------------------------------
sletz's avatar
sletz committed
367

368
369
    bool JackNetMaster::IsSlaveReadyToRoll()
    {
sletz's avatar
sletz committed
370
        return (fReturnTransportData.fState == JackTransportNetStarting);
371
    }
sletz's avatar
sletz committed
372

sletz's avatar
sletz committed
373
    int JackNetMaster::SetBufferSize(jack_nframes_t nframes, void* arg)
374
    {
sletz's avatar
sletz committed
375
376
        JackNetMaster* obj = static_cast<JackNetMaster*>(arg);
        if (nframes != obj->fParams.fPeriodSize) {
377
378
379
380
381
382
383
384
385
386
387
            jack_error("Cannot currently handle buffer size change, so JackNetMaster proxy will be removed...");
            obj->Exit();
        }
        return 0;
    }
    
    int JackNetMaster::SetSampleRate(jack_nframes_t nframes, void* arg)
    {
        JackNetMaster* obj = static_cast<JackNetMaster*>(arg);
        if (nframes != obj->fParams.fSampleRate) {
            jack_error("Cannot currently handle sample rate change, so JackNetMaster proxy will be removed...");
sletz's avatar
sletz committed
388
389
            obj->Exit();
        }
390
391
        return 0;
    }
392
393
394
395
396
397
    
    void JackNetMaster::LatencyCallback(jack_latency_callback_mode_t mode, void* arg)
    {
        JackNetMaster* obj = static_cast<JackNetMaster*>(arg);
        jack_nframes_t port_latency = jack_get_buffer_size(obj->fClient);
        jack_latency_range_t range;
Stephane Letz's avatar
Stephane Letz committed
398
        
399
        //audio
Stephane Letz's avatar
Stephane Letz committed
400
        for (int i = 0; i < obj->fParams.fSendAudioChannels; i++) {
401
            //port latency
Stephane Letz's avatar
Stephane Letz committed
402
403
404
405
406
407
408
409
            range.min = range.max = float(obj->fParams.fNetworkLatency * port_latency) / 2.f;
            jack_port_set_latency_range(obj->fAudioCapturePorts[i], JackCaptureLatency, &range);
        }
        
        //audio
        for (int i = 0; i < obj->fParams.fReturnAudioChannels; i++) {
            //port latency
            range.min = range.max = float(obj->fParams.fNetworkLatency * port_latency) / 2.f + ((obj->fParams.fSlaveSyncMode) ? 0 : port_latency);
410
411
            jack_port_set_latency_range(obj->fAudioPlaybackPorts[i], JackPlaybackLatency, &range);
        }
Stephane Letz's avatar
Stephane Letz committed
412
413
414
415
416
417
418
419
        
        //midi
        for (int i = 0; i < obj->fParams.fSendMidiChannels; i++) {
            //port latency
            range.min = range.max = float(obj->fParams.fNetworkLatency * port_latency) / 2.f;
            jack_port_set_latency_range(obj->fMidiCapturePorts[i], JackCaptureLatency, &range);
        }
    
420
        //midi
Stephane Letz's avatar
Stephane Letz committed
421
        for (int i = 0; i < obj->fParams.fReturnMidiChannels; i++) {
422
423
424
425
426
            //port latency
            range.min = range.max = obj->fParams.fNetworkLatency * port_latency + ((obj->fParams.fSlaveSyncMode) ? 0 : port_latency);
            jack_port_set_latency_range(obj->fMidiPlaybackPorts[i], JackPlaybackLatency, &range);
        }
    }
427
428

//process-----------------------------------------------------------------------------
sletz's avatar
sletz committed
429
    int JackNetMaster::SetProcess(jack_nframes_t nframes, void* arg)
430
    {
sletz's avatar
sletz committed
431
432
433
434
435
        try {
            return static_cast<JackNetMaster*>(arg)->Process();
        } catch (JackNetException& e) {
            return 0;
        }
436
    }
437
438
439
440
441
442
443
444
445
446
447
448
449
    
    void JackNetMaster::SetConnectCallback(jack_port_id_t a, jack_port_id_t b, int connect, void* arg)
    {
        static_cast<JackNetMaster*>(arg)->ConnectCallback(a, b, connect);
    }
    
    void JackNetMaster::ConnectCallback(jack_port_id_t a, jack_port_id_t b, int connect)
    {
        jack_info("JackNetMaster::ConnectCallback a = %d b = %d connect = %d", a, b, connect);
        if (connect) {
            jack_connect(fClient, jack_port_name(jack_port_by_id(fClient, a)), "system:playback_1");
        }
    }
450
451
452

    int JackNetMaster::Process()
    {
453
        if (!fRunning) {
454
            return 0;
455
        }
456

457
#ifdef JACK_MONITOR
458
        jack_time_t begin_time = GetMicroSeconds();
moret's avatar
Cleanup    
moret committed
459
        fNetTimeMon->New();
moret's avatar
moret committed
460
461
#endif

462
        //buffers
463
464
465
        for (int midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
            fNetMidiCaptureBuffer->SetBuffer(midi_port_index,
                                            static_cast<JackMidiBuffer*>(jack_port_get_buffer(fMidiCapturePorts[midi_port_index],
sletz's avatar
sletz committed
466
467
                                            fParams.fPeriodSize)));
        }
468
        for (int audio_port_index = 0; audio_port_index < fParams.fSendAudioChannels; audio_port_index++) {
469
470

        #ifdef OPTIMIZED_PROTOCOL
471
            if (fNetAudioCaptureBuffer->GetConnected(audio_port_index)) {
472
                // Port is connected on other side...
473
                fNetAudioCaptureBuffer->SetBuffer(audio_port_index,
sletz's avatar
sletz committed
474
475
476
                                                ((jack_port_connected(fAudioCapturePorts[audio_port_index]) > 0)
                                                ? static_cast<sample_t*>(jack_port_get_buffer(fAudioCapturePorts[audio_port_index], fParams.fPeriodSize))
                                                : NULL));
477
478
479
            } else {
                fNetAudioCaptureBuffer->SetBuffer(audio_port_index, NULL);
            }
480
        #else
481
            fNetAudioCaptureBuffer->SetBuffer(audio_port_index,
sletz's avatar
sletz committed
482
483
                                            static_cast<sample_t*>(jack_port_get_buffer(fAudioCapturePorts[audio_port_index],
                                            fParams.fPeriodSize)));
484
        #endif
485
            // TODO
sletz's avatar
sletz committed
486
        }
487
488
489
490

        for (int midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
            fNetMidiPlaybackBuffer->SetBuffer(midi_port_index,
                                                static_cast<JackMidiBuffer*>(jack_port_get_buffer(fMidiPlaybackPorts[midi_port_index],
sletz's avatar
sletz committed
491
492
                                                fParams.fPeriodSize)));
        }
493
        for (int audio_port_index = 0; audio_port_index < fParams.fReturnAudioChannels; audio_port_index++) {
494
495

        #ifdef OPTIMIZED_PROTOCOL
sletz's avatar
sletz committed
496
497
498
            sample_t* out = (jack_port_connected(fAudioPlaybackPorts[audio_port_index]) > 0)
                ? static_cast<sample_t*>(jack_port_get_buffer(fAudioPlaybackPorts[audio_port_index], fParams.fPeriodSize))
                : NULL;
499
500
501
502
            if (out) {
                memset(out, 0, sizeof(float) * fParams.fPeriodSize);
            }
            fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, out);
503
        #else
504
505
506
507
508
            sample_t* out = static_cast<sample_t*>(jack_port_get_buffer(fAudioPlaybackPorts[audio_port_index], fParams.fPeriodSize));
            if (out) {
                memset(out, 0, sizeof(float) * fParams.fPeriodSize);
            }
            fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, out)));
509
        #endif
sletz's avatar
sletz committed
510
        }
511

512
        // encode the first packet
513
        EncodeSyncPacket();
sletz's avatar
sletz committed
514

515
516
517
        if (SyncSend() == SOCKET_ERROR) {
            return SOCKET_ERROR;
        }
518

519
520
521
#ifdef JACK_MONITOR
        fNetTimeMon->Add((((float)(GetMicroSeconds() - begin_time)) / (float) fPeriodUsecs) * 100.f);
#endif
sletz's avatar
sletz committed
522

523
        // send data
524
525
        if (DataSend() == SOCKET_ERROR) {
            return SOCKET_ERROR;
526
        }
moret's avatar
moret committed
527

528
529
530
531
#ifdef JACK_MONITOR
        fNetTimeMon->Add((((float)(GetMicroSeconds() - begin_time)) / (float) fPeriodUsecs) * 100.f);
#endif

532
        // receive sync
533
534
535
        int res = SyncRecv();
        switch (res) {
        
Stephane Letz's avatar
Stephane Letz committed
536
            case NET_SYNCHING:
537
538
539
            case SOCKET_ERROR:
                return res;
                
540
            case SYNC_PACKET_ERROR:
541
                 // Since sync packet is incorrect, don't decode it and continue with data
Stephane Letz's avatar
Stephane Letz committed
542
                 break;
543
544
                
            default:
545
                // Decode sync
546
547
548
                DecodeSyncPacket();
                break;
        }
549

550
#ifdef JACK_MONITOR
sletz's avatar
sletz committed
551
        fNetTimeMon->Add((((float)(GetMicroSeconds() - begin_time)) / (float) fPeriodUsecs) * 100.f);
moret's avatar
moret committed
552
#endif
Stephane Letz's avatar
Stephane Letz committed
553
      
554
        // receive data
555
556
557
558
559
560
561
        res = DataRecv();
        switch (res) {
        
            case 0:
            case SOCKET_ERROR:
                return res;
                
562
            case DATA_PACKET_ERROR:
563
564
565
566
                // Well not a real XRun...
                JackServerGlobals::fInstance->GetEngine()->NotifyClientXRun(ALL_CLIENTS);
                break;
        }
567

568
#ifdef JACK_MONITOR
sletz's avatar
sletz committed
569
        fNetTimeMon->AddLast((((float)(GetMicroSeconds() - begin_time)) / (float) fPeriodUsecs) * 100.f);
moret's avatar
moret committed
570
#endif
571
572
        return 0;
    }
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
628
629
630
631
    
    void JackNetMaster::SaveConnections(connections_list_t& connections)
    {
        // Audio
        for (int i = 0; i < fParams.fSendAudioChannels; i++) {
            const char** connected_port = jack_port_get_all_connections(fClient, fAudioCapturePorts[i]);
            if (connected_port != NULL) {
                for (int port = 0; connected_port[port]; port++) {
                    connections.push_back(make_pair(connected_port[port], jack_port_name(fAudioCapturePorts[i])));
                    jack_log("INPUT %s ==> %s", connected_port[port], jack_port_name(fAudioCapturePorts[i]));
                }
                jack_free(connected_port);
            }
        }
   
        for (int i = 0; i < fParams.fReturnAudioChannels; i++) {
            const char** connected_port = jack_port_get_all_connections(fClient, fAudioPlaybackPorts[i]);
            if (connected_port != NULL) {
                for (int port = 0; connected_port[port]; port++) {
                    connections.push_back(make_pair(jack_port_name(fAudioPlaybackPorts[i]), connected_port[port]));
                    jack_log("OUTPUT %s ==> %s", jack_port_name(fAudioPlaybackPorts[i]), connected_port[port]);
                }
                jack_free(connected_port);
            }
        }
        
        // MIDI
        for (int i = 0; i < fParams.fSendMidiChannels; i++) {
            const char** connected_port = jack_port_get_all_connections(fClient, fMidiCapturePorts[i]);
            if (connected_port != NULL) {
                for (int port = 0; connected_port[port]; port++) {
                    connections.push_back(make_pair(connected_port[port], jack_port_name(fMidiCapturePorts[i])));
                    jack_log("INPUT %s ==> %s", connected_port[port], jack_port_name(fMidiCapturePorts[i]));
                }
                jack_free(connected_port);
            }
        }
   
        for (int i = 0; i < fParams.fReturnMidiChannels; i++) {
            const char** connected_port = jack_port_get_all_connections(fClient, fMidiPlaybackPorts[i]);
            if (connected_port != NULL) {
                for (int port = 0; connected_port[port]; port++) {
                    connections.push_back(make_pair(jack_port_name(fMidiPlaybackPorts[i]), connected_port[port]));
                    jack_log("OUTPUT %s ==> %s", jack_port_name(fMidiPlaybackPorts[i]), connected_port[port]);
                }
                jack_free(connected_port);
            }
        }
    }
    
    void JackNetMaster::LoadConnections(const connections_list_t& connections)
    {
        list<pair<string, string> >::const_iterator it;
        for (it = connections.begin(); it != connections.end(); it++) {
            pair<string, string> connection = *it;
            jack_connect(fClient, connection.first.c_str(), connection.second.c_str());
        }
    }

632
633
634

//JackNetMasterManager***********************************************************************************************

sletz's avatar
sletz committed
635
    JackNetMasterManager::JackNetMasterManager(jack_client_t* client, const JSList* params) : fSocket()
636
    {
sletz's avatar
sletz committed
637
        jack_log("JackNetMasterManager::JackNetMasterManager");
moret's avatar
moret committed
638

639
640
        fClient = client;
        fName = jack_get_client_name(fClient);
641
642
        fGlobalID = 0;
        fRunning = true;
643
        fAutoConnect = false;
644
        fAutoSave = false;
645
646
647

        const JSList* node;
        const jack_driver_param_t* param;
648
     
649
        jack_on_shutdown(fClient, SetShutDown, this);
650
    
651
652
653
654
655
656
657
658
659
660
661
        // Possibly use env variable
        const char* default_udp_port = getenv("JACK_NETJACK_PORT");
        fSocket.SetPort((default_udp_port) ? atoi(default_udp_port) : DEFAULT_PORT);

        const char* default_multicast_ip = getenv("JACK_NETJACK_MULTICAST");
        if (default_multicast_ip) {
            strcpy(fMulticastIP, default_multicast_ip);
        } else {
            strcpy(fMulticastIP, DEFAULT_MULTICAST_IP);
        }

sletz's avatar
sletz committed
662
663
664
        for (node = params; node; node = jack_slist_next(node)) {

            param = (const jack_driver_param_t*) node->data;
665
            switch (param->character) {
moret's avatar
moret committed
666
                case 'a' :
sletz's avatar
sletz committed
667
                    if (strlen(param->value.str) < 32) {
668
                        strcpy(fMulticastIP, param->value.str);
sletz's avatar
sletz committed
669
                    } else {
670
                        jack_error("Can't use multicast address %s, using default %s", param->value.ui, DEFAULT_MULTICAST_IP);
sletz's avatar
sletz committed
671
                    }
moret's avatar
moret committed
672
                    break;
sletz's avatar
sletz committed
673

moret's avatar
moret committed
674
                case 'p':
sletz's avatar
sletz committed
675
                    fSocket.SetPort(param->value.ui);
676
                    break;
sletz's avatar
sletz committed
677

678
                case 'c':
679
                    fAutoConnect = true;
680
                    break;
681
682
                    
                case 's':
683
                    fAutoSave = true;
684
                    break;
685
686
687
            }
        }

688
        //set sync callback
689
        jack_set_sync_callback(fClient, SetSyncCallback, this);
690

691
        //activate the client (for sync callback)
692
        if (jack_activate(fClient) != 0) {
sletz's avatar
sletz committed
693
            jack_error("Can't activate the NetManager client, transport disabled");
694
        }
695

696
        //launch the manager thread
697
        if (jack_client_create_thread(fClient, &fThread, 0, 0, NetManagerThread, this)) {
sletz's avatar
sletz committed
698
            jack_error("Can't create the NetManager control thread");
699
        }
700
701
702
703
    }

    JackNetMasterManager::~JackNetMasterManager()
    {
704
        jack_log("JackNetMasterManager::~JackNetMasterManager");
705
        ShutDown();
706
707
    }

708
    int JackNetMasterManager::CountIO(const char* type, int flags)
709
710
    {
        int count = 0;
711
        const char** ports = jack_get_ports(fClient, NULL, type, flags);
712
        if (ports != NULL) {
713
            while (ports[count]) { count++; }
714
            jack_free(ports);
715
716
717
        }
        return count;
    }
718
    
719
720
721
722
723
724
    void JackNetMasterManager::SetShutDown(void* arg)
    {
        static_cast<JackNetMasterManager*>(arg)->ShutDown();
    }
    
    void JackNetMasterManager::ShutDown()
725
726
    {
        jack_log("JackNetMasterManager::ShutDown");
727
728
729
        if (fRunning) {
            jack_client_kill_thread(fClient, fThread);
            fRunning = false;
730
        }
731
732
        master_list_t::iterator it;
        for (it = fMasterList.begin(); it != fMasterList.end(); it++) {
733
            delete (*it);
734
735
736
737
        }
        fMasterList.clear();
        fSocket.Close();
        SocketAPIEnd();
738
    }
739

sletz's avatar
sletz committed
740
    int JackNetMasterManager::SetSyncCallback(jack_transport_state_t state, jack_position_t* pos, void* arg)
741
    {
sletz's avatar
sletz committed
742
        return static_cast<JackNetMasterManager*>(arg)->SyncCallback(state, pos);
743
744
    }

sletz's avatar
sletz committed
745
    int JackNetMasterManager::SyncCallback(jack_transport_state_t state, jack_position_t* pos)
746
    {
747
        //check if each slave is ready to roll
748
        int res = 1;
749
        master_list_it_t it;
750
        for (it = fMasterList.begin(); it != fMasterList.end(); it++) {
751
            if (!(*it)->IsSlaveReadyToRoll()) {
752
                res = 0;
753
            }
754
        }
755
756
        jack_log("JackNetMasterManager::SyncCallback returns '%s'", (res) ? "true" : "false");
        return res;
757
758
    }

sletz's avatar
sletz committed
759
    void* JackNetMasterManager::NetManagerThread(void* arg)
760
    {
sletz's avatar
sletz committed
761
762
763
        JackNetMasterManager* master_manager = static_cast<JackNetMasterManager*>(arg);
        jack_info("Starting Jack NetManager");
        jack_info("Listening on '%s:%d'", master_manager->fMulticastIP, master_manager->fSocket.GetPort());
764
765
766
767
768
769
        master_manager->Run();
        return NULL;
    }

    void JackNetMasterManager::Run()
    {
sletz's avatar
sletz committed
770
        jack_log("JackNetMasterManager::Run");
771
772
773
774
        //utility variables
        int attempt = 0;

        //data
775
        session_params_t host_params;
776
777
778
779
        int rx_bytes = 0;
        JackNetMaster* net_master;

        //init socket API (win32)
780
781
        if (SocketAPIInit() < 0) {
            jack_error("Can't init Socket API, exiting...");
782
783
784
785
            return;
        }

        //socket
786
        if (fSocket.NewSocket() == SOCKET_ERROR) {
sletz's avatar
sletz committed
787
            jack_error("Can't create NetManager input socket : %s", StrError(NET_ERROR_CODE));
788
789
790
791
            return;
        }

        //bind the socket to the local port
792
        if (fSocket.Bind() == SOCKET_ERROR) {
sletz's avatar
sletz committed
793
            jack_error("Can't bind NetManager socket : %s", StrError(NET_ERROR_CODE));
794
795
796
797
798
            fSocket.Close();
            return;
        }

        //join multicast group
sletz's avatar
sletz committed
799
        if (fSocket.JoinMCastGroup(fMulticastIP) == SOCKET_ERROR) {
800
801
            jack_error("Can't join multicast group : %s", StrError(NET_ERROR_CODE));
        }
802
803

        //local loop
804
805
806
        if (fSocket.SetLocalLoop() == SOCKET_ERROR) {
            jack_error("Can't set local loop : %s", StrError(NET_ERROR_CODE));
        }
807
808

        //set a timeout on the multicast receive (the thread can now be cancelled)
sletz's avatar
sletz committed
809
        if (fSocket.SetTimeOut(MANAGER_INIT_TIMEOUT) == SOCKET_ERROR) {
810
811
            jack_error("Can't set timeout : %s", StrError(NET_ERROR_CODE));
        }
812
813
814
815

        //main loop, wait for data, deal with it and wait again
        do
        {
816
            session_params_t net_params;
sletz's avatar
sletz committed
817
            rx_bytes = fSocket.CatchHost(&net_params, sizeof(session_params_t), 0);
818
            SessionParamsNToH(&net_params, &host_params);
819
            
sletz's avatar
sletz committed
820
821
            if ((rx_bytes == SOCKET_ERROR) && (fSocket.GetError() != NET_NO_DATA)) {
                jack_error("Error in receive : %s", StrError(NET_ERROR_CODE));
822
                if (++attempt == 10) {
sletz's avatar
sletz committed
823
                    jack_error("Can't receive on the socket, exiting net manager");
824
825
826
                    return;
                }
            }
sletz's avatar
sletz committed
827
828

            if (rx_bytes == sizeof(session_params_t)) {