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

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 "JackNetDriver.h"
#include "JackEngineControl.h"
22
#include "JackLockedEngine.h"
sletz's avatar
sletz committed
23
#include "JackGraphManager.h"
24
#include "JackWaitThreadedDriver.h"
sletz's avatar
sletz committed
25

26
27
using namespace std;

sletz's avatar
sletz committed
28
29
namespace Jack
{
30
    JackNetDriver::JackNetDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table,
31
                                const char* ip, int udp_port, int mtu, int midi_input_ports, int midi_output_ports,
32
                                char* net_name, uint transport_sync, char network_mode, int celt_encoding)
33
            : JackAudioDriver(name, alias, engine, table), JackNetSlaveInterface(ip, udp_port)
34
    {
35
        jack_log("JackNetDriver::JackNetDriver ip %s, port %d", ip, udp_port);
36

sletz's avatar
sletz committed
37
        // Use the hostname if no name parameter was given
38
39
        if (strcmp(net_name, "") == 0)
            GetHostName(net_name, JACK_CLIENT_NAME_SIZE);
40

41
42
43
        fParams.fMtu = mtu;
        fParams.fSendMidiChannels = midi_input_ports;
        fParams.fReturnMidiChannels = midi_output_ports;
44
45
46
47
48
49
50
51
        if (celt_encoding > 0) {
            fParams.fSampleEncoder = JackCeltEncoder;
            fParams.fKBps = celt_encoding;
        } else {
            fParams.fSampleEncoder = JackFloatEncoder;
        }
        strcpy(fParams.fName, net_name);
        fSocket.GetName(fParams.fSlaveNetName);
52
        fParams.fTransportSync = transport_sync;
53
        fParams.fNetworkMode = network_mode;
54
55
56
        fSendTransportData.fState = -1;
        fReturnTransportData.fState = -1;
        fLastTransportState = -1;
57
        fLastTimebaseMaster = -1;
58
59
        fMidiCapturePortList = NULL;
        fMidiPlaybackPortList = NULL;
moret's avatar
moret committed
60
#ifdef JACK_MONITOR
moret's avatar
moret committed
61
        fNetTimeMon = NULL;
62
        fRcvSyncUst = 0;
moret's avatar
Cleanup    
moret committed
63
#endif
64
65
66
67
68
69
    }

    JackNetDriver::~JackNetDriver()
    {
        delete[] fMidiCapturePortList;
        delete[] fMidiPlaybackPortList;
moret's avatar
moret committed
70
#ifdef JACK_MONITOR
moret's avatar
moret committed
71
        delete fNetTimeMon;
moret's avatar
moret committed
72
#endif
73
    }
sletz's avatar
sletz committed
74

75
//open, close, attach and detach------------------------------------------------------
76
77
78
79
    int JackNetDriver::Open(jack_nframes_t buffer_size, jack_nframes_t samplerate, bool capturing, bool playing,
                            int inchannels, int outchannels, bool monitor,
                            const char* capture_driver_name, const char* playback_driver_name,
                            jack_nframes_t capture_latency, jack_nframes_t playback_latency)
80
    {
sletz's avatar
sletz committed
81
        return JackAudioDriver::Open(buffer_size,
82
83
84
85
86
87
88
89
90
                                 samplerate,
                                 capturing,
                                 playing,
                                 inchannels,
                                 outchannels,
                                 monitor,
                                 capture_driver_name,
                                 playback_driver_name,
                                 capture_latency,
sletz's avatar
sletz committed
91
                                 playback_latency);
92
93
    }

moret's avatar
Cleanup    
moret committed
94
95
    int JackNetDriver::Close()
    {
sletz's avatar
sletz committed
96
#ifdef JACK_MONITOR
97
        if (fNetTimeMon)
moret's avatar
moret committed
98
            fNetTimeMon->Save();
sletz's avatar
sletz committed
99
100
#endif
        FreeAll();
moret's avatar
Cleanup    
moret committed
101
102
103
        return JackDriver::Close();
    }

sletz's avatar
sletz committed
104
    // Attach and Detach are defined as empty methods: port allocation is done when driver actually start (that is in Init)
105
106
107
108
109
110
111
112
113
114
    int JackNetDriver::Attach()
    {
        return 0;
    }

    int JackNetDriver::Detach()
    {
        return 0;
    }

115
//init and restart--------------------------------------------------------------------
116
    /*
117
        JackNetDriver is wrapped in a JackWaitThreadedDriver decorator that behaves
118
119
        as a "dummy driver, until Init method returns.
    */
120

121
    bool JackNetDriver::Initialize()
122
    {
sletz's avatar
sletz committed
123
        jack_log("JackNetDriver::Initialize()");
124
        SaveConnections();
sletz's avatar
sletz committed
125
        FreePorts();
126

127
        // New loading, but existing socket, restart the driver
sletz's avatar
sletz committed
128
        if (fSocket.IsSocket()) {
129
            jack_info("Restarting driver...");
sletz's avatar
sletz committed
130
131
            FreeAll();
        }
132

133
        // Set the parameters to send
134
135
        fParams.fSendAudioChannels = fCaptureChannels;
        fParams.fReturnAudioChannels = fPlaybackChannels;
moret's avatar
moret committed
136
        fParams.fSlaveSyncMode = fEngineControl->fSyncMode;
137

138
        // Display some additional infos
139
140
        jack_info("NetDriver started in %s mode %s Master's transport sync.",
                    (fParams.fSlaveSyncMode) ? "sync" : "async", (fParams.fTransportSync) ? "with" : "without");
141

142
        // Init network
143
144
        if (!JackNetSlaveInterface::Init()) {
            jack_error("Starting network fails...");
moret's avatar
moret committed
145
            return false;
146
        }
147

148
        // Set global parameters
sletz's avatar
sletz committed
149
        if (!SetParams()) {
150
            jack_error("SetParams error...");
sletz's avatar
sletz committed
151
            return false;
sletz's avatar
sletz committed
152
        }
153

sletz's avatar
sletz committed
154
        // If -1 at connection time, in/out channels count is sent by the master
155
156
157
        fCaptureChannels = fParams.fSendAudioChannels;
        fPlaybackChannels = fParams.fReturnAudioChannels;

158
        // Allocate midi ports lists
159
160
        fMidiCapturePortList = new jack_port_id_t [fParams.fSendMidiChannels];
        fMidiPlaybackPortList = new jack_port_id_t [fParams.fReturnMidiChannels];
161
162
163
164

        assert(fMidiCapturePortList);
        assert(fMidiPlaybackPortList);

165
        for (int midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
sletz's avatar
sletz committed
166
            fMidiCapturePortList[midi_port_index] = 0;
167
        }
168
        for (int midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
sletz's avatar
sletz committed
169
            fMidiPlaybackPortList[midi_port_index] = 0;
170
        }
moret's avatar
moret committed
171

172
        // Register jack ports
173
174
        if (AllocPorts() != 0) {
            jack_error("Can't allocate ports.");
175
176
177
            return false;
        }

178
        // Init done, display parameters
179
        SessionParamsDisplay(&fParams);
180

181
        // Monitor
182
#ifdef JACK_MONITOR
moret's avatar
moret committed
183
        string plot_name;
184
        // NetTimeMon
185
186
187
188
        plot_name = string(fParams.fName);
        plot_name += string("_slave");
        plot_name += (fEngineControl->fSyncMode) ? string("_sync") : string("_async");
        switch (fParams.fNetworkMode)
moret's avatar
moret committed
189
        {
moret's avatar
moret committed
190
            case 's' :
191
                plot_name += string("_slow");
moret's avatar
moret committed
192
                break;
193

moret's avatar
moret committed
194
            case 'n' :
195
                plot_name += string("_normal");
moret's avatar
moret committed
196
                break;
197

moret's avatar
moret committed
198
            case 'f' :
199
                plot_name += string("_fast");
moret's avatar
moret committed
200
                break;
moret's avatar
moret committed
201
        }
202
        fNetTimeMon = new JackGnuPlotMonitor<float>(128, 5, plot_name);
moret's avatar
moret committed
203
204
        string net_time_mon_fields[] =
        {
205
206
207
208
209
            string("sync decoded"),
            string("end of read"),
            string("start of write"),
            string("sync send"),
            string("end of write")
moret's avatar
moret committed
210
211
212
        };
        string net_time_mon_options[] =
        {
213
214
            string("set xlabel \"audio cycles\""),
            string("set ylabel \"% of audio cycle\"")
moret's avatar
moret committed
215
        };
216
        fNetTimeMon->SetPlotFile(net_time_mon_options, 2, net_time_mon_fields, 5);
217
#endif
218
        // Driver parametering
219
220
        JackAudioDriver::SetBufferSize(fParams.fPeriodSize);
        JackAudioDriver::SetSampleRate(fParams.fSampleRate);
221

222
223
        JackDriver::NotifyBufferSize(fParams.fPeriodSize);
        JackDriver::NotifySampleRate(fParams.fSampleRate);
224

225
        // Transport engine parametering
226
        fEngineControl->fTransport.SetNetworkSync(fParams.fTransportSync);
227
228

        RestoreConnections();
229
230
231
        return true;
    }

sletz's avatar
sletz committed
232
    void JackNetDriver::FreeAll()
233
    {
sletz's avatar
sletz committed
234
        FreePorts();
235

236
237
238
239
240
241
242
243
        delete[] fTxBuffer;
        delete[] fRxBuffer;
        delete fNetAudioCaptureBuffer;
        delete fNetAudioPlaybackBuffer;
        delete fNetMidiCaptureBuffer;
        delete fNetMidiPlaybackBuffer;
        delete[] fMidiCapturePortList;
        delete[] fMidiPlaybackPortList;
244

sletz's avatar
sletz committed
245
246
247
248
249
250
251
        fTxBuffer = NULL;
        fRxBuffer = NULL;
        fNetAudioCaptureBuffer = NULL;
        fNetAudioPlaybackBuffer = NULL;
        fNetMidiCaptureBuffer = NULL;
        fNetMidiPlaybackBuffer = NULL;
        fMidiCapturePortList = NULL;
252
        fMidiPlaybackPortList = NULL;
253

254
255
256
257
#ifdef JACK_MONITOR
        delete fNetTimeMon;
        fNetTimeMon = NULL;
#endif
258
259
    }

260
//jack ports and buffers--------------------------------------------------------------
261
262
    int JackNetDriver::AllocPorts()
    {
263
        jack_log("JackNetDriver::AllocPorts fBufferSize = %ld fSampleRate = %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate);
moret's avatar
moret committed
264

265
        JackPort* port;
266
        jack_port_id_t port_index;
267
268
269
270
        char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
        char alias[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
        unsigned long port_flags;
        int audio_port_index;
271
        int midi_port_index;
272
        jack_latency_range_t range;
273
274
275

        //audio
        port_flags = JackPortIsOutput | JackPortIsPhysical | JackPortIsTerminal;
276
        for (audio_port_index = 0; audio_port_index < fCaptureChannels; audio_port_index++)
277
        {
278
279
            snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName, fCaptureDriverName, audio_port_index + 1);
            snprintf(name, sizeof(name) - 1, "%s:capture_%d", fClientControl.fName, audio_port_index + 1);
280
281
            if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE,
                             static_cast<JackPortFlags>(port_flags), fEngineControl->fBufferSize, &port_index) < 0)
282
            {
283
                jack_error("driver: cannot register port for %s", name);
284
285
                return -1;
            }
286
            port = fGraphManager->GetPort(port_index);
287
            port->SetAlias(alias);
moret's avatar
moret committed
288
            //port latency
289
290
            range.min = range.max = fEngineControl->fBufferSize;
            port->SetLatencyRange(JackCaptureLatency, &range);
291
292
            fCapturePortList[audio_port_index] = port_index;
            jack_log("JackNetDriver::AllocPorts() fCapturePortList[%d] audio_port_index = %ld fPortLatency = %ld", audio_port_index, port_index, port->GetLatency());
293
294
        }
        port_flags = JackPortIsInput | JackPortIsPhysical | JackPortIsTerminal;
295
        for (audio_port_index = 0; audio_port_index < fPlaybackChannels; audio_port_index++)
296
        {
297
298
            snprintf(alias, sizeof(alias) - 1, "%s:%s:in%d", fAliasName, fPlaybackDriverName, audio_port_index + 1);
            snprintf(name, sizeof(name) - 1, "%s:playback_%d",fClientControl.fName, audio_port_index + 1);
299
300
            if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE,
                             static_cast<JackPortFlags>(port_flags), fEngineControl->fBufferSize, &port_index) < 0)
301
            {
302
                jack_error("driver: cannot register port for %s", name);
303
304
                return -1;
            }
305
            port = fGraphManager->GetPort(port_index);
306
            port->SetAlias(alias);
moret's avatar
moret committed
307
            //port latency
308
            switch (fParams.fNetworkMode)
moret's avatar
moret committed
309
310
            {
                case 'f' :
311
                    range.min = range.max = (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize;
moret's avatar
moret committed
312
313
                    break;
                case 'n' :
314
                    range.min = range.max = (fEngineControl->fBufferSize + (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize);
moret's avatar
moret committed
315
316
                    break;
                case 's' :
317
                    range.min = range.max = (2 * fEngineControl->fBufferSize + (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize);
moret's avatar
moret committed
318
319
                    break;
            }
320
            port->SetLatencyRange(JackPlaybackLatency, &range);
321
322
            fPlaybackPortList[audio_port_index] = port_index;
            jack_log("JackNetDriver::AllocPorts() fPlaybackPortList[%d] audio_port_index = %ld fPortLatency = %ld", audio_port_index, port_index, port->GetLatency());
323
324
325
        }
        //midi
        port_flags = JackPortIsOutput | JackPortIsPhysical | JackPortIsTerminal;
326
        for (midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++)
327
        {
328
329
            snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName, fCaptureDriverName, midi_port_index + 1);
            snprintf(name, sizeof (name) - 1, "%s:midi_capture_%d", fClientControl.fName, midi_port_index + 1);
330
331
            if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_MIDI_TYPE,
                             static_cast<JackPortFlags>(port_flags), fEngineControl->fBufferSize, &port_index) < 0)
332
            {
333
                jack_error("driver: cannot register port for %s", name);
334
335
                return -1;
            }
336
            port = fGraphManager->GetPort(port_index);
moret's avatar
moret committed
337
            //port latency
338
339
            range.min = range.max = fEngineControl->fBufferSize;
            port->SetLatencyRange(JackCaptureLatency, &range);
340
341
            fMidiCapturePortList[midi_port_index] = port_index;
            jack_log("JackNetDriver::AllocPorts() fMidiCapturePortList[%d] midi_port_index = %ld fPortLatency = %ld", midi_port_index, port_index, port->GetLatency());
342
343
344
        }

        port_flags = JackPortIsInput | JackPortIsPhysical | JackPortIsTerminal;
345
        for (midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++)
346
        {
347
348
            snprintf(alias, sizeof(alias) - 1, "%s:%s:in%d", fAliasName, fPlaybackDriverName, midi_port_index + 1);
            snprintf(name, sizeof(name) - 1, "%s:midi_playback_%d", fClientControl.fName, midi_port_index + 1);
349
350
            if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_MIDI_TYPE,
                             static_cast<JackPortFlags>(port_flags), fEngineControl->fBufferSize, &port_index) < 0)
351
            {
352
                jack_error("driver: cannot register port for %s", name);
353
354
                return -1;
            }
355
            port = fGraphManager->GetPort(port_index);
moret's avatar
moret committed
356
            //port latency
357
            switch (fParams.fNetworkMode)
moret's avatar
moret committed
358
359
            {
                case 'f' :
360
                    range.min = range.max = (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize;
moret's avatar
moret committed
361
362
                    break;
                case 'n' :
363
                    range.min = range.max = (fEngineControl->fBufferSize + (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize);
moret's avatar
moret committed
364
365
                    break;
                case 's' :
366
                    range.min = range.max = (2 * fEngineControl->fBufferSize + (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize);
moret's avatar
moret committed
367
368
                    break;
            }
369
            port->SetLatencyRange(JackPlaybackLatency, &range);
370
371
            fMidiPlaybackPortList[midi_port_index] = port_index;
            jack_log("JackNetDriver::AllocPorts() fMidiPlaybackPortList[%d] midi_port_index = %ld fPortLatency = %ld", midi_port_index, port_index, port->GetLatency());
372
373
374
375
376
377
378
        }

        return 0;
    }

    int JackNetDriver::FreePorts()
    {
sletz's avatar
sletz committed
379
        jack_log("JackNetDriver::FreePorts");
moret's avatar
moret committed
380

381
382
        for (int audio_port_index = 0; audio_port_index < fCaptureChannels; audio_port_index++) {
            if (fCapturePortList[audio_port_index] > 0) {
383
                fEngine->PortUnRegister(fClientControl.fRefNum, fCapturePortList[audio_port_index]);
sletz's avatar
sletz committed
384
                fCapturePortList[audio_port_index] = 0;
385
386
387
388
389
            }
        }

        for (int audio_port_index = 0; audio_port_index < fPlaybackChannels; audio_port_index++) {
            if (fPlaybackPortList[audio_port_index] > 0) {
390
                fEngine->PortUnRegister(fClientControl.fRefNum, fPlaybackPortList[audio_port_index]);
sletz's avatar
sletz committed
391
                fPlaybackPortList[audio_port_index] = 0;
392
393
394
            }
        }

395
        for (int midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
396
            if (fMidiCapturePortList && fMidiCapturePortList[midi_port_index] > 0) {
sletz's avatar
sletz committed
397
398
                fGraphManager->ReleasePort(fClientControl.fRefNum, fMidiCapturePortList[midi_port_index]);
                fMidiCapturePortList[midi_port_index] = 0;
399
400
401
            }
        }

402
        for (int midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
403
            if (fMidiPlaybackPortList && fMidiPlaybackPortList[midi_port_index] > 0) {
404
                fEngine->PortUnRegister(fClientControl.fRefNum, fMidiPlaybackPortList[midi_port_index]);
sletz's avatar
sletz committed
405
                fMidiPlaybackPortList[midi_port_index] = 0;
406
407
            }
        }
408
409
        return 0;
    }
410
411
412
413
414
415

    void JackNetDriver::SaveConnections()
    {
        const char** connections;
        fConnections.clear();

416
        JackAudioDriver::SaveConnections();
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435

        for (int i = 0; i < fParams.fSendMidiChannels; ++i) {
            if (fCapturePortList[i] && (connections = fGraphManager->GetConnections(fMidiCapturePortList[i])) != 0) {
                for (int j = 0; connections[j]; j++) {
                    fConnections.push_back(make_pair(fGraphManager->GetPort(fMidiCapturePortList[i])->GetName(), connections[j]));
                }
                free(connections);
            }
        }

        for (int i = 0; i < fParams.fReturnMidiChannels; ++i) {
            if (fPlaybackPortList[i] && (connections = fGraphManager->GetConnections(fMidiPlaybackPortList[i])) != 0) {
                for (int j = 0; connections[j]; j++) {
                    fConnections.push_back(make_pair(connections[j], fGraphManager->GetPort(fMidiPlaybackPortList[i])->GetName()));
                }
                free(connections);
            }
        }
    }
436

437
    JackMidiBuffer* JackNetDriver::GetMidiInputBuffer(int port_index)
438
    {
439
        return static_cast<JackMidiBuffer*>(fGraphManager->GetBuffer(fMidiCapturePortList[port_index], fEngineControl->fBufferSize));
440
441
    }

442
    JackMidiBuffer* JackNetDriver::GetMidiOutputBuffer(int port_index)
443
    {
444
        return static_cast<JackMidiBuffer*>(fGraphManager->GetBuffer(fMidiPlaybackPortList[port_index], fEngineControl->fBufferSize));
445
446
    }

447
//transport---------------------------------------------------------------------------
448
    void JackNetDriver::DecodeTransportData()
449
    {
450
451
452
453
        //is there a new timebase master on the net master ?
        // - release timebase master only if it's a non-conditional request
        // - no change or no request : don't do anything
        // - conditional request : don't change anything too, the master will know if this slave is actually the timebase master
454
455
        int refnum;
        bool conditional;
sletz's avatar
sletz committed
456
        if (fSendTransportData.fTimebaseMaster == TIMEBASEMASTER) {
457
458
459
460
            fEngineControl->fTransport.GetTimebaseMaster(refnum, conditional);
            if (refnum != -1)
                fEngineControl->fTransport.ResetTimebase(refnum);
            jack_info("The NetMaster is now the new timebase master.");
461
462
        }

463
        //is there a transport state change to handle ?
sletz's avatar
sletz committed
464
        if (fSendTransportData.fNewState &&(fSendTransportData.fState != fEngineControl->fTransport.GetState())) {
465

466
            switch (fSendTransportData.fState)
467
468
            {
                case JackTransportStopped :
469
470
                    fEngineControl->fTransport.SetCommand(TransportCommandStop);
                    jack_info("Master stops transport.");
471
                    break;
472

473
                case JackTransportStarting :
474
475
476
                    fEngineControl->fTransport.RequestNewPos(&fSendTransportData.fPosition);
                    fEngineControl->fTransport.SetCommand(TransportCommandStart);
                    jack_info("Master starts transport frame = %d", fSendTransportData.fPosition.frame);
477
                    break;
478

479
                case JackTransportRolling :
480
481
482
                    //fEngineControl->fTransport.SetCommand(TransportCommandStart);
                    fEngineControl->fTransport.SetState(JackTransportRolling);
                    jack_info("Master is rolling.");
483
484
485
486
487
                    break;
            }
        }
    }

488
    void JackNetDriver::EncodeTransportData()
489
    {
490
        //is there a timebase master change ?
491
492
        int refnum;
        bool conditional;
493
        fEngineControl->fTransport.GetTimebaseMaster(refnum, conditional);
sletz's avatar
sletz committed
494
        if (refnum != fLastTimebaseMaster) {
495
            //timebase master has released its function
sletz's avatar
sletz committed
496
            if (refnum == -1) {
497
                fReturnTransportData.fTimebaseMaster = RELEASE_TIMEBASEMASTER;
498
                jack_info("Sending a timebase master release request.");
sletz's avatar
sletz committed
499
500
            } else {
                //there is a new timebase master
501
502
                fReturnTransportData.fTimebaseMaster = (conditional) ? CONDITIONAL_TIMEBASEMASTER : TIMEBASEMASTER;
                jack_info("Sending a %s timebase master request.", (conditional) ? "conditional" : "non-conditional");
503
            }
504
            fLastTimebaseMaster = refnum;
sletz's avatar
sletz committed
505
        } else {
506
            fReturnTransportData.fTimebaseMaster = NO_CHANGE;
sletz's avatar
sletz committed
507
        }
508

509
        //update transport state and position
510
        fReturnTransportData.fState = fEngineControl->fTransport.Query(&fReturnTransportData.fPosition);
511

512
        //is it a new state (that the master need to know...) ?
513
514
515
516
517
        fReturnTransportData.fNewState = ((fReturnTransportData.fState == JackTransportNetStarting) &&
                                           (fReturnTransportData.fState != fLastTransportState) &&
                                           (fReturnTransportData.fState != fSendTransportData.fState));
        if (fReturnTransportData.fNewState)
            jack_info("Sending '%s'.", GetTransportState(fReturnTransportData.fState));
518
        fLastTransportState = fReturnTransportData.fState;
519
520
    }

521
//driver processes--------------------------------------------------------------------
522
523
524
    int JackNetDriver::Read()
    {
        //buffers
525
        for (int midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
526
            fNetMidiCaptureBuffer->SetBuffer(midi_port_index, GetMidiInputBuffer(midi_port_index));
527
528
        }
        for (int audio_port_index = 0; audio_port_index < fParams.fSendAudioChannels; audio_port_index++) {
529
530
531
        #ifdef OPTIMIZED_PROTOCOL
            fNetAudioCaptureBuffer->SetBuffer(audio_port_index, GetInputBuffer(audio_port_index, true));
        #else
532
            fNetAudioCaptureBuffer->SetBuffer(audio_port_index, GetInputBuffer(audio_port_index));
533
        #endif
534
        }
535

moret's avatar
moret committed
536
#ifdef JACK_MONITOR
moret's avatar
Cleanup    
moret committed
537
        fNetTimeMon->New();
moret's avatar
moret committed
538
539
#endif

540
        //receive sync (launch the cycle)
541
        if (SyncRecv() == SOCKET_ERROR)
542
            return 0;
543

544
#ifdef JACK_MONITOR
545
        // For timing
546
547
        fRcvSyncUst = GetMicroSeconds();
#endif
548

549
        //decode sync
moret's avatar
moret committed
550
        //if there is an error, don't return -1, it will skip Write() and the network error probably won't be identified
551
        DecodeSyncPacket();
552

553
#ifdef JACK_MONITOR
554
        fNetTimeMon->Add(((float)(GetMicroSeconds() - fRcvSyncUst) / (float)fEngineControl->fPeriodUsecs) * 100.f);
555
#endif
556
        //audio, midi or sync if driver is late
557
        if (DataRecv() == SOCKET_ERROR)
558
            return SOCKET_ERROR;
moret's avatar
moret committed
559

560
        //take the time at the beginning of the cycle
561
562
        JackDriver::CycleTakeBeginTime();

563
#ifdef JACK_MONITOR
564
        fNetTimeMon->Add(((float)(GetMicroSeconds() - fRcvSyncUst) / (float)fEngineControl->fPeriodUsecs) * 100.f);
moret's avatar
moret committed
565
#endif
moret's avatar
moret committed
566

567
568
569
570
571
572
        return 0;
    }

    int JackNetDriver::Write()
    {
        //buffers
573
        for (int midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
574
            fNetMidiPlaybackBuffer->SetBuffer(midi_port_index, GetMidiOutputBuffer(midi_port_index));
575
576
        }
        for (int audio_port_index = 0; audio_port_index < fPlaybackChannels; audio_port_index++) {
577
        #ifdef OPTIMIZED_PROTOCOL
578
579
580
581
582
583
            // Port is connected on other side..
            if ((long)fNetAudioPlaybackBuffer->GetBuffer(audio_port_index) == -1) {
                fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, GetOutputBuffer(audio_port_index, true));
            } else {
                fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, NULL);
            }
584
585
586
        #else
            fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, GetOutputBuffer(audio_port_index));
        #endif
587
        }
588

589
#ifdef JACK_MONITOR
590
        fNetTimeMon->Add(((float) (GetMicroSeconds() - fRcvSyncUst) / (float)fEngineControl->fPeriodUsecs) * 100.f);
moret's avatar
moret committed
591
592
#endif

593
        //sync
594
        EncodeSyncPacket();
595

moret's avatar
moret committed
596
        //send sync
597
        if (SyncSend() == SOCKET_ERROR)
598
            return SOCKET_ERROR;
599

600
#ifdef JACK_MONITOR
601
        fNetTimeMon->Add(((float)(GetMicroSeconds() - fRcvSyncUst) / (float)fEngineControl->fPeriodUsecs) * 100.f);
moret's avatar
moret committed
602
603
#endif

moret's avatar
moret committed
604
        //send data
605
        if (DataSend() == SOCKET_ERROR)
606
            return SOCKET_ERROR;
moret's avatar
moret committed
607

608
#ifdef JACK_MONITOR
609
        fNetTimeMon->AddLast(((float)(GetMicroSeconds() - fRcvSyncUst) / (float)fEngineControl->fPeriodUsecs) * 100.f);
moret's avatar
moret committed
610
611
#endif

612
613
        return 0;
    }
sletz's avatar
sletz committed
614

615
//driver loader-----------------------------------------------------------------------
sletz's avatar
sletz committed
616
617

#ifdef __cplusplus
618
619
    extern "C"
    {
sletz's avatar
sletz committed
620
#endif
621
        SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor()
622
        {
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
            jack_driver_desc_t * desc;
            jack_driver_desc_filler_t filler;
            jack_driver_param_value_t value;

            desc = jack_driver_descriptor_construct("net", "netjack slave backend component", &filler);

            strcpy(value.str, DEFAULT_MULTICAST_IP);
            jack_driver_descriptor_add_parameter(desc, &filler, "multicast_ip", 'a', JackDriverParamString, &value, NULL, "Multicast Address", NULL);

            value.i = DEFAULT_PORT;
            jack_driver_descriptor_add_parameter(desc, &filler, "udp_net_port", 'p', JackDriverParamInt, &value, NULL, "UDP port", NULL);

            value.i = DEFAULT_MTU;
            jack_driver_descriptor_add_parameter(desc, &filler, "mtu", 'M', JackDriverParamInt, &value, NULL, "MTU to the master", NULL);

            value.i = -1;
            jack_driver_descriptor_add_parameter(desc, &filler, "input_ports", 'C', JackDriverParamInt, &value, NULL, "Number of audio input ports", "Number of audio input ports. If -1, audio physical input from the master");
            jack_driver_descriptor_add_parameter(desc, &filler, "output_ports", 'P', JackDriverParamInt, &value, NULL, "Number of audio output ports", "Number of audio output ports. If -1, audio physical output from the master");

            value.i = 0;
            jack_driver_descriptor_add_parameter(desc, &filler, "midi_in_ports", 'i', JackDriverParamInt, &value, NULL, "Number of midi input ports", NULL);
            jack_driver_descriptor_add_parameter(desc, &filler, "midi_out_ports", 'o', JackDriverParamInt, &value, NULL, "Number of midi output ports", NULL);
645

sletz's avatar
sletz committed
646
#if HAVE_CELT
647
648
            value.i = -1;
            jack_driver_descriptor_add_parameter(desc, &filler, "celt", 'c', JackDriverParamInt, &value, NULL, "Set CELT encoding and number of kBits per channel", NULL);
sletz's avatar
sletz committed
649
#endif
650
651
652
653
654
655
656
657
            strcpy(value.str, "'hostname'");
            jack_driver_descriptor_add_parameter(desc, &filler, "client_name", 'n', JackDriverParamString, &value, NULL, "Name of the jack client", NULL);

            value.ui = 1U;
            jack_driver_descriptor_add_parameter(desc, &filler, "transport_sync", 't', JackDriverParamUInt, &value, NULL, "Sync transport with master's", NULL);

            strcpy(value.str, "slow");
            jack_driver_descriptor_add_parameter(desc, &filler, "mode", 'm', JackDriverParamString, &value, NULL, "Slow, Normal or Fast mode.", NULL);
nedko's avatar
nedko committed
658

659
660
661
            return desc;
        }

662
        SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
663
        {
moret's avatar
moret committed
664
            char multicast_ip[16];
665
            char net_name[JACK_CLIENT_NAME_SIZE + 1];
666
            int udp_port;
667
            int mtu = DEFAULT_MTU;
668
            uint transport_sync = 1;
669
670
            jack_nframes_t period_size = 128;
            jack_nframes_t sample_rate = 48000;
sletz's avatar
sletz committed
671
672
            int audio_capture_ports = -1;
            int audio_playback_ports = -1;
673
674
            int midi_input_ports = 0;
            int midi_output_ports = 0;
675
            int celt_encoding = -1;
676
            bool monitor = false;
677
            char network_mode = 's';
678
679
            const JSList* node;
            const jack_driver_param_t* param;
680

sletz's avatar
sletz committed
681
            net_name[0] = 0;
682

683
684
685
686
687
688
689
690
691
692
693
            // Possibly use env variable
            const char* default_udp_port = getenv("JACK_NETJACK_PORT");
            udp_port = (default_udp_port) ? atoi(default_udp_port) : DEFAULT_PORT;

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

694
695
696
            for (node = params; node; node = jack_slist_next(node)) {
                param = (const jack_driver_param_t*) node->data;
                switch (param->character)
697
                {
moret's avatar
moret committed
698
                    case 'a' :
699
                        strncpy(multicast_ip, param->value.str, 15);
moret's avatar
moret committed
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
                        break;
                    case 'p':
                        udp_port = param->value.ui;
                        break;
                    case 'M':
                        mtu = param->value.i;
                        break;
                    case 'C':
                        audio_capture_ports = param->value.i;
                        break;
                    case 'P':
                        audio_playback_ports = param->value.i;
                        break;
                    case 'i':
                        midi_input_ports = param->value.i;
                        break;
                    case 'o':
                        midi_output_ports = param->value.i;
                        break;
sletz's avatar
sletz committed
719
                    #if HAVE_CELT
720
721
722
                    case 'c':
                        celt_encoding = param->value.i;
                        break;
sletz's avatar
sletz committed
723
                    #endif
moret's avatar
moret committed
724
                    case 'n' :
725
                        strncpy(net_name, param->value.str, JACK_CLIENT_NAME_SIZE);
moret's avatar
moret committed
726
727
728
729
                        break;
                    case 't' :
                        transport_sync = param->value.ui;
                        break;
730
                    case 'm' :
731
                        if (strcmp(param->value.str, "normal") == 0)
moret's avatar
moret committed
732
                            network_mode = 'n';
733
                        else if (strcmp(param->value.str, "slow") == 0)
moret's avatar
moret committed
734
                            network_mode = 's';
735
                        else if (strcmp(param->value.str, "fast") == 0)
moret's avatar
moret committed
736
                            network_mode = 'f';
moret's avatar
moret committed
737
                        else
738
                            jack_error("Unknown network mode, using 'normal' mode.");
moret's avatar
moret committed
739
                        break;
740
741
742
                }
            }

743
            try {
744

745
746
747
748
749
750
                Jack::JackDriverClientInterface* driver = new Jack::JackWaitThreadedDriver(
                        new Jack::JackNetDriver("system", "net_pcm", engine, table, multicast_ip, udp_port, mtu,
                                                midi_input_ports, midi_output_ports,
                                                net_name, transport_sync,
                                                network_mode, celt_encoding));
                if (driver->Open(period_size, sample_rate, 1, 1, audio_capture_ports, audio_playback_ports, monitor, "from_master_", "to_master_", 0, 0) == 0) {
751
                    return driver;
752
                } else {
753
754
755
                    delete driver;
                    return NULL;
                }
756

757
            } catch (...) {
758
                return NULL;
759
            }
760
        }
sletz's avatar
sletz committed
761
762

#ifdef __cplusplus
763
    }
sletz's avatar
sletz committed
764
765
#endif
}