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

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.
*/

sletz's avatar
sletz committed
19
20
#include "JackCompilerDeps.h"
#include "driver_interface.h"
sletz's avatar
sletz committed
21
22
#include "JackNetDriver.h"
#include "JackEngineControl.h"
23
#include "JackLockedEngine.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
33
                                char* net_name, uint transport_sync, int network_latency, 
                                int celt_encoding, int opus_encoding, bool auto_save)
Stephane Letz's avatar
Stephane Letz committed
34
            : JackWaiterDriver(name, alias, engine, table), JackNetSlaveInterface(ip, udp_port)
35
    {
36
        jack_log("JackNetDriver::JackNetDriver ip %s, port %d", ip, udp_port);
37

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

43
        fParams.fMtu = mtu;
44
45
46
47
        
        fWantedMIDICaptureChannels = midi_input_ports;
        fWantedMIDIPlaybackChannels = midi_output_ports;
        
48
49
50
        if (celt_encoding > 0) {
            fParams.fSampleEncoder = JackCeltEncoder;
            fParams.fKBps = celt_encoding;
Robin Gareus's avatar
Robin Gareus committed
51
52
53
        } else if (opus_encoding > 0) {
            fParams.fSampleEncoder = JackOpusEncoder;
            fParams.fKBps = opus_encoding;
54
55
        } else {
            fParams.fSampleEncoder = JackFloatEncoder;
Stephane Letz's avatar
Stephane Letz committed
56
            //fParams.fSampleEncoder = JackIntEncoder;
57
58
59
        }
        strcpy(fParams.fName, net_name);
        fSocket.GetName(fParams.fSlaveNetName);
60
        fParams.fTransportSync = transport_sync;
61
        fParams.fNetworkLatency = network_latency;
62
63
64
        fSendTransportData.fState = -1;
        fReturnTransportData.fState = -1;
        fLastTransportState = -1;
65
        fLastTimebaseMaster = -1;
66
67
        fMidiCapturePortList = NULL;
        fMidiPlaybackPortList = NULL;
68
69
        fWantedAudioCaptureChannels = -1;
        fWantedAudioPlaybackChannels = -1;
70
        fAutoSave = auto_save;
moret's avatar
moret committed
71
#ifdef JACK_MONITOR
moret's avatar
moret committed
72
        fNetTimeMon = NULL;
73
        fRcvSyncUst = 0;
moret's avatar
Cleanup    
moret committed
74
#endif
75
76
77
78
79
80
    }

    JackNetDriver::~JackNetDriver()
    {
        delete[] fMidiCapturePortList;
        delete[] fMidiPlaybackPortList;
moret's avatar
moret committed
81
#ifdef JACK_MONITOR
moret's avatar
moret committed
82
        delete fNetTimeMon;
moret's avatar
moret committed
83
#endif
84
    }
sletz's avatar
sletz committed
85

86
//open, close, attach and detach------------------------------------------------------
87

88
89
90
91
92
93
94
95
96
97
98
99
100
    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)
    {
        // Keep initial wanted values
101
102
        fWantedAudioCaptureChannels = inchannels;
        fWantedAudioPlaybackChannels = outchannels;
103
104
105
106
107
108
109
110
        return JackWaiterDriver::Open(buffer_size, samplerate, 
                                    capturing, playing, 
                                    inchannels, outchannels, 
                                    monitor, 
                                    capture_driver_name, playback_driver_name, 
                                    capture_latency, playback_latency);
    }
                         
moret's avatar
Cleanup    
moret committed
111
112
    int JackNetDriver::Close()
    {
sletz's avatar
sletz committed
113
#ifdef JACK_MONITOR
sletz's avatar
sletz committed
114
        if (fNetTimeMon) {
moret's avatar
moret committed
115
            fNetTimeMon->Save();
sletz's avatar
sletz committed
116
        }
sletz's avatar
sletz committed
117
118
#endif
        FreeAll();
Stephane Letz's avatar
Stephane Letz committed
119
        return JackWaiterDriver::Close();
moret's avatar
Cleanup    
moret committed
120
121
    }

sletz's avatar
sletz committed
122
    // Attach and Detach are defined as empty methods: port allocation is done when driver actually start (that is in Init)
123
124
125
126
127
128
129
130
131
132
    int JackNetDriver::Attach()
    {
        return 0;
    }

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

133
//init and restart--------------------------------------------------------------------
134
    /*
135
        JackNetDriver is wrapped in a JackWaitThreadedDriver decorator that behaves
136
137
        as a "dummy driver, until Init method returns.
    */
138

139
    bool JackNetDriver::Initialize()
140
    {
Stephane Letz's avatar
Stephane Letz committed
141
        jack_log("JackNetDriver::Initialize");
142
143
144
        if (fAutoSave) {
            SaveConnections(0);
        }
sletz's avatar
sletz committed
145
        FreePorts();
146

147
        // New loading, but existing socket, restart the driver
sletz's avatar
sletz committed
148
        if (fSocket.IsSocket()) {
149
            jack_info("Restarting driver...");
sletz's avatar
sletz committed
150
151
            FreeAll();
        }
152

153
        // Set the parameters to send
154
155
156
157
158
159
        fParams.fSendAudioChannels = fWantedAudioCaptureChannels;
        fParams.fReturnAudioChannels = fWantedAudioPlaybackChannels;
        
        fParams.fSendMidiChannels = fWantedMIDICaptureChannels;
        fParams.fReturnMidiChannels = fWantedMIDIPlaybackChannels;
        
moret's avatar
moret committed
160
        fParams.fSlaveSyncMode = fEngineControl->fSyncMode;
161

162
        // Display some additional infos
163
164
        jack_info("NetDriver started in %s mode %s Master's transport sync.",
                    (fParams.fSlaveSyncMode) ? "sync" : "async", (fParams.fTransportSync) ? "with" : "without");
165

166
        // Init network
167
168
        if (!JackNetSlaveInterface::Init()) {
            jack_error("Starting network fails...");
moret's avatar
moret committed
169
            return false;
170
        }
171

172
        // Set global parameters
sletz's avatar
sletz committed
173
        if (!SetParams()) {
174
            jack_error("SetParams error...");
sletz's avatar
sletz committed
175
            return false;
sletz's avatar
sletz committed
176
        }
177

178
        // If -1 at connection time for audio, in/out audio channels count is sent by the master
179
180
        fCaptureChannels = fParams.fSendAudioChannels;
        fPlaybackChannels = fParams.fReturnAudioChannels;
181
182
183
        
        // If -1 at connection time for MIDI, in/out MIDI channels count is sent by the master (in fParams struct)
   
184
        // Allocate midi ports lists
185
186
187
        delete[] fMidiCapturePortList;
        delete[] fMidiPlaybackPortList;
        
188
189
190
191
192
193
        if (fParams.fSendMidiChannels > 0) {
            fMidiCapturePortList = new jack_port_id_t [fParams.fSendMidiChannels];
            assert(fMidiCapturePortList);
            for (int midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
                fMidiCapturePortList[midi_port_index] = 0;
            }
194
        }
195
196
197
198
199
200
201
        
        if (fParams.fReturnMidiChannels > 0) {
            fMidiPlaybackPortList = new jack_port_id_t [fParams.fReturnMidiChannels];
            assert(fMidiPlaybackPortList);
            for (int midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
                fMidiPlaybackPortList[midi_port_index] = 0;
            }
202
        }
moret's avatar
moret committed
203

204
        // Register jack ports
205
206
        if (AllocPorts() != 0) {
            jack_error("Can't allocate ports.");
207
208
209
            return false;
        }

210
        // Init done, display parameters
211
        SessionParamsDisplay(&fParams);
212

213
        // Monitor
214
#ifdef JACK_MONITOR
moret's avatar
moret committed
215
        string plot_name;
216
        // NetTimeMon
217
218
219
        plot_name = string(fParams.fName);
        plot_name += string("_slave");
        plot_name += (fEngineControl->fSyncMode) ? string("_sync") : string("_async");
Stephane Letz's avatar
Stephane Letz committed
220
        plot_name += string("_latency");
221
        fNetTimeMon = new JackGnuPlotMonitor<float>(128, 5, plot_name);
moret's avatar
moret committed
222
223
        string net_time_mon_fields[] =
        {
224
225
226
227
228
            string("sync decoded"),
            string("end of read"),
            string("start of write"),
            string("sync send"),
            string("end of write")
moret's avatar
moret committed
229
230
231
        };
        string net_time_mon_options[] =
        {
232
233
            string("set xlabel \"audio cycles\""),
            string("set ylabel \"% of audio cycle\"")
moret's avatar
moret committed
234
        };
235
        fNetTimeMon->SetPlotFile(net_time_mon_options, 2, net_time_mon_fields, 5);
236
#endif
237
        // Driver parametering
238
239
        JackTimedDriver::SetBufferSize(fParams.fPeriodSize);
        JackTimedDriver::SetSampleRate(fParams.fSampleRate);
240

241
242
        JackDriver::NotifyBufferSize(fParams.fPeriodSize);
        JackDriver::NotifySampleRate(fParams.fSampleRate);
243

244
        // Transport engine parametering
245
        fEngineControl->fTransport.SetNetworkSync(fParams.fTransportSync);
246

247
248
249
        if (fAutoSave) {
            LoadConnections(0);
        }
250
251
252
        return true;
    }

sletz's avatar
sletz committed
253
    void JackNetDriver::FreeAll()
254
    {
sletz's avatar
sletz committed
255
        FreePorts();
256

257
258
259
260
261
262
263
264
        delete[] fTxBuffer;
        delete[] fRxBuffer;
        delete fNetAudioCaptureBuffer;
        delete fNetAudioPlaybackBuffer;
        delete fNetMidiCaptureBuffer;
        delete fNetMidiPlaybackBuffer;
        delete[] fMidiCapturePortList;
        delete[] fMidiPlaybackPortList;
265

sletz's avatar
sletz committed
266
267
268
269
270
271
272
        fTxBuffer = NULL;
        fRxBuffer = NULL;
        fNetAudioCaptureBuffer = NULL;
        fNetAudioPlaybackBuffer = NULL;
        fNetMidiCaptureBuffer = NULL;
        fNetMidiPlaybackBuffer = NULL;
        fMidiCapturePortList = NULL;
273
        fMidiPlaybackPortList = NULL;
274

275
276
277
278
#ifdef JACK_MONITOR
        delete fNetTimeMon;
        fNetTimeMon = NULL;
#endif
279
    }
280
281
282
283
284
285
    
    void JackNetDriver::UpdateLatencies()
    {
        jack_latency_range_t input_range;
        jack_latency_range_t output_range;
        jack_latency_range_t monitor_range;
Stephane Letz's avatar
Stephane Letz committed
286
     
287
        for (int i = 0; i < fCaptureChannels; i++) {
Stephane Letz's avatar
Stephane Letz committed
288
            input_range.max = input_range.min = float(fParams.fNetworkLatency * fEngineControl->fBufferSize) / 2.f;
289
290
291
292
            fGraphManager->GetPort(fCapturePortList[i])->SetLatencyRange(JackCaptureLatency, &input_range);
        }

        for (int i = 0; i < fPlaybackChannels; i++) {
Stephane Letz's avatar
Stephane Letz committed
293
294
295
296
            output_range.max = output_range.min = float(fParams.fNetworkLatency * fEngineControl->fBufferSize) / 2.f;
            if (!fEngineControl->fSyncMode) {
                output_range.max = output_range.min += fEngineControl->fBufferSize;
            }
297
298
299
300
301
302
303
            fGraphManager->GetPort(fPlaybackPortList[i])->SetLatencyRange(JackPlaybackLatency, &output_range);
            if (fWithMonitorPorts) {
                monitor_range.min = monitor_range.max = 0;
                fGraphManager->GetPort(fMonitorPortList[i])->SetLatencyRange(JackCaptureLatency, &monitor_range);
            }
        }
    }
304

305
//jack ports and buffers--------------------------------------------------------------
306
307
    int JackNetDriver::AllocPorts()
    {
308
        jack_log("JackNetDriver::AllocPorts fBufferSize = %ld fSampleRate = %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate);
moret's avatar
moret committed
309

Stephane Letz's avatar
Stephane Letz committed
310
311
312
313
314
315
316
317
318
        /*
            fNetAudioCaptureBuffer                fNetAudioPlaybackBuffer
            fSendAudioChannels                    fReturnAudioChannels

            fCapturePortList                      fPlaybackPortList
            fCaptureChannels    ==> SLAVE ==>     fPlaybackChannels
            "capture_"                            "playback_"
        */

319
        JackPort* port;
320
        jack_port_id_t port_index;
sletz's avatar
sletz committed
321
322
        char name[REAL_JACK_PORT_NAME_SIZE];
        char alias[REAL_JACK_PORT_NAME_SIZE];
323
        int audio_port_index;
324
        int midi_port_index;
325
     
326
        //audio
sletz's avatar
sletz committed
327
        for (audio_port_index = 0; audio_port_index < fCaptureChannels; audio_port_index++) {
sletz's avatar
sletz committed
328
329
            snprintf(alias, sizeof(alias), "%s:%s:out%d", fAliasName, fCaptureDriverName, audio_port_index + 1);
            snprintf(name, sizeof(name), "%s:capture_%d", fClientControl.fName, audio_port_index + 1);
330
            if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE,
Stephane Letz's avatar
Stephane Letz committed
331
                             CaptureDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) {
332
                jack_error("driver: cannot register port for %s", name);
333
334
                return -1;
            }
sletz's avatar
sletz committed
335

336
            port = fGraphManager->GetPort(port_index);
337
            port->SetAlias(alias);
338
339
            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());
340
        }
sletz's avatar
sletz committed
341
342

        for (audio_port_index = 0; audio_port_index < fPlaybackChannels; audio_port_index++) {
sletz's avatar
sletz committed
343
344
            snprintf(alias, sizeof(alias), "%s:%s:in%d", fAliasName, fPlaybackDriverName, audio_port_index + 1);
            snprintf(name, sizeof(name), "%s:playback_%d",fClientControl.fName, audio_port_index + 1);
345
            if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE,
Stephane Letz's avatar
Stephane Letz committed
346
                             PlaybackDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) {
347
                jack_error("driver: cannot register port for %s", name);
348
349
                return -1;
            }
sletz's avatar
sletz committed
350

351
            port = fGraphManager->GetPort(port_index);
352
            port->SetAlias(alias);
353
354
            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());
355
        }
sletz's avatar
sletz committed
356

357
        //midi
sletz's avatar
sletz committed
358
        for (midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
sletz's avatar
sletz committed
359
360
            snprintf(alias, sizeof(alias), "%s:%s:out%d", fAliasName, fCaptureDriverName, midi_port_index + 1);
            snprintf(name, sizeof (name), "%s:midi_capture_%d", fClientControl.fName, midi_port_index + 1);
361
            if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_MIDI_TYPE,
Stephane Letz's avatar
Stephane Letz committed
362
                             CaptureDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) {
363
                jack_error("driver: cannot register port for %s", name);
364
365
                return -1;
            }
sletz's avatar
sletz committed
366
367

            port = fGraphManager->GetPort(port_index);
368
369
            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());
370
371
        }

sletz's avatar
sletz committed
372
        for (midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
sletz's avatar
sletz committed
373
374
            snprintf(alias, sizeof(alias), "%s:%s:in%d", fAliasName, fPlaybackDriverName, midi_port_index + 1);
            snprintf(name, sizeof(name), "%s:midi_playback_%d", fClientControl.fName, midi_port_index + 1);
375
            if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_MIDI_TYPE,
Stephane Letz's avatar
Stephane Letz committed
376
                             PlaybackDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) {
377
                jack_error("driver: cannot register port for %s", name);
378
379
                return -1;
            }
sletz's avatar
sletz committed
380
381

            port = fGraphManager->GetPort(port_index);
382
383
            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());
384
385
        }

Stephane Letz's avatar
Stephane Letz committed
386
        UpdateLatencies();
387
388
389
390
391
        return 0;
    }

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

394
395
        for (int audio_port_index = 0; audio_port_index < fCaptureChannels; audio_port_index++) {
            if (fCapturePortList[audio_port_index] > 0) {
396
                fEngine->PortUnRegister(fClientControl.fRefNum, fCapturePortList[audio_port_index]);
sletz's avatar
sletz committed
397
                fCapturePortList[audio_port_index] = 0;
398
399
400
401
402
            }
        }

        for (int audio_port_index = 0; audio_port_index < fPlaybackChannels; audio_port_index++) {
            if (fPlaybackPortList[audio_port_index] > 0) {
403
                fEngine->PortUnRegister(fClientControl.fRefNum, fPlaybackPortList[audio_port_index]);
sletz's avatar
sletz committed
404
                fPlaybackPortList[audio_port_index] = 0;
405
406
407
            }
        }

408
        for (int midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
409
            if (fMidiCapturePortList && fMidiCapturePortList[midi_port_index] > 0) {
sletz's avatar
sletz committed
410
411
                fGraphManager->ReleasePort(fClientControl.fRefNum, fMidiCapturePortList[midi_port_index]);
                fMidiCapturePortList[midi_port_index] = 0;
412
413
414
            }
        }

415
        for (int midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
416
            if (fMidiPlaybackPortList && fMidiPlaybackPortList[midi_port_index] > 0) {
417
                fEngine->PortUnRegister(fClientControl.fRefNum, fMidiPlaybackPortList[midi_port_index]);
sletz's avatar
sletz committed
418
                fMidiPlaybackPortList[midi_port_index] = 0;
419
420
            }
        }
421
422
        return 0;
    }
423

424
    void JackNetDriver::SaveConnections(int alias)
425
    {
426
        JackDriver::SaveConnections(alias);
427
428
        const char** connections;

429
430
431
432
433
434
435
436
437
        if (fMidiCapturePortList) {
            for (int i = 0; i < fParams.fSendMidiChannels; ++i) {
                if (fMidiCapturePortList[i] && (connections = fGraphManager->GetConnections(fMidiCapturePortList[i])) != 0) {
                    for (int j = 0; connections[j]; j++) {
                        JackPort* port_id = fGraphManager->GetPort(fGraphManager->GetPort(connections[j]));
                        fConnections.push_back(make_pair(port_id->GetType(), make_pair(fGraphManager->GetPort(fMidiCapturePortList[i])->GetName(), connections[j])));
                        jack_info("Save connection: %s %s", fGraphManager->GetPort(fMidiCapturePortList[i])->GetName(), connections[j]);
                    }
                    free(connections);
438
439
440
441
                }
            }
        }

442
443
444
445
446
447
448
449
450
        if (fMidiPlaybackPortList) {
            for (int i = 0; i < fParams.fReturnMidiChannels; ++i) {
                if (fMidiPlaybackPortList[i] && (connections = fGraphManager->GetConnections(fMidiPlaybackPortList[i])) != 0) {
                    for (int j = 0; connections[j]; j++) {
                        JackPort* port_id = fGraphManager->GetPort(fGraphManager->GetPort(connections[j]));
                        fConnections.push_back(make_pair(port_id->GetType(), make_pair(connections[j], fGraphManager->GetPort(fMidiPlaybackPortList[i])->GetName())));
                        jack_info("Save connection: %s %s", connections[j], fGraphManager->GetPort(fMidiPlaybackPortList[i])->GetName());
                    }
                    free(connections);
451
452
453
454
                }
            }
        }
    }
455

456
    JackMidiBuffer* JackNetDriver::GetMidiInputBuffer(int port_index)
457
    {
458
        return static_cast<JackMidiBuffer*>(fGraphManager->GetBuffer(fMidiCapturePortList[port_index], fEngineControl->fBufferSize));
459
460
    }

461
    JackMidiBuffer* JackNetDriver::GetMidiOutputBuffer(int port_index)
462
    {
463
        return static_cast<JackMidiBuffer*>(fGraphManager->GetBuffer(fMidiPlaybackPortList[port_index], fEngineControl->fBufferSize));
464
465
    }

466
//transport---------------------------------------------------------------------------
467
    void JackNetDriver::DecodeTransportData()
468
    {
469
470
471
472
        //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
473
474
        int refnum;
        bool conditional;
sletz's avatar
sletz committed
475
        if (fSendTransportData.fTimebaseMaster == TIMEBASEMASTER) {
476
            fEngineControl->fTransport.GetTimebaseMaster(refnum, conditional);
sletz's avatar
sletz committed
477
            if (refnum != -1) {
478
                fEngineControl->fTransport.ResetTimebase(refnum);
sletz's avatar
sletz committed
479
            }
480
            jack_info("The NetMaster is now the new timebase master.");
481
482
        }

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

486
            switch (fSendTransportData.fState)
487
488
            {
                case JackTransportStopped :
489
490
                    fEngineControl->fTransport.SetCommand(TransportCommandStop);
                    jack_info("Master stops transport.");
491
                    break;
492

493
                case JackTransportStarting :
494
495
496
                    fEngineControl->fTransport.RequestNewPos(&fSendTransportData.fPosition);
                    fEngineControl->fTransport.SetCommand(TransportCommandStart);
                    jack_info("Master starts transport frame = %d", fSendTransportData.fPosition.frame);
497
                    break;
498

499
                case JackTransportRolling :
500
501
502
                    //fEngineControl->fTransport.SetCommand(TransportCommandStart);
                    fEngineControl->fTransport.SetState(JackTransportRolling);
                    jack_info("Master is rolling.");
503
504
505
506
507
                    break;
            }
        }
    }

508
    void JackNetDriver::EncodeTransportData()
509
    {
510
        // is there a timebase master change ?
511
512
        int refnum;
        bool conditional;
513
        fEngineControl->fTransport.GetTimebaseMaster(refnum, conditional);
sletz's avatar
sletz committed
514
        if (refnum != fLastTimebaseMaster) {
515
            // timebase master has released its function
sletz's avatar
sletz committed
516
            if (refnum == -1) {
517
                fReturnTransportData.fTimebaseMaster = RELEASE_TIMEBASEMASTER;
518
                jack_info("Sending a timebase master release request.");
sletz's avatar
sletz committed
519
            } else {
520
                // there is a new timebase master
521
522
                fReturnTransportData.fTimebaseMaster = (conditional) ? CONDITIONAL_TIMEBASEMASTER : TIMEBASEMASTER;
                jack_info("Sending a %s timebase master request.", (conditional) ? "conditional" : "non-conditional");
523
            }
524
            fLastTimebaseMaster = refnum;
sletz's avatar
sletz committed
525
        } else {
526
            fReturnTransportData.fTimebaseMaster = NO_CHANGE;
sletz's avatar
sletz committed
527
        }
528

529
        // update transport state and position
530
        fReturnTransportData.fState = fEngineControl->fTransport.Query(&fReturnTransportData.fPosition);
531

532
        // is it a new state (that the master need to know...) ?
533
534
535
        fReturnTransportData.fNewState = ((fReturnTransportData.fState == JackTransportNetStarting) &&
                                           (fReturnTransportData.fState != fLastTransportState) &&
                                           (fReturnTransportData.fState != fSendTransportData.fState));
sletz's avatar
sletz committed
536
        if (fReturnTransportData.fNewState) {
537
            jack_info("Sending '%s'.", GetTransportState(fReturnTransportData.fState));
sletz's avatar
sletz committed
538
        }
539
        fLastTransportState = fReturnTransportData.fState;
540
541
    }

542
//driver processes--------------------------------------------------------------------
543

544
545
    int JackNetDriver::Read()
    {
546
        // buffers
547
        for (int midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
548
            fNetMidiCaptureBuffer->SetBuffer(midi_port_index, GetMidiInputBuffer(midi_port_index));
549
        }
Stephane Letz's avatar
Stephane Letz committed
550

551
        for (int audio_port_index = 0; audio_port_index < fParams.fSendAudioChannels; audio_port_index++) {
552
        #ifdef OPTIMIZED_PROTOCOL
Stephane Letz's avatar
Stephane Letz committed
553
554
555
556
557
            if (fGraphManager->GetConnectionsNum(fCapturePortList[audio_port_index]) > 0) {
                fNetAudioCaptureBuffer->SetBuffer(audio_port_index, GetInputBuffer(audio_port_index));
            } else {
                fNetAudioCaptureBuffer->SetBuffer(audio_port_index, NULL);
            }
558
        #else
559
            fNetAudioCaptureBuffer->SetBuffer(audio_port_index, GetInputBuffer(audio_port_index));
560
        #endif
561
        }
562

moret's avatar
moret committed
563
#ifdef JACK_MONITOR
moret's avatar
Cleanup    
moret committed
564
        fNetTimeMon->New();
moret's avatar
moret committed
565
566
#endif

567
568
569
570
571
        switch (SyncRecv()) {
        
            case SOCKET_ERROR:
                return SOCKET_ERROR;
                
572
            case SYNC_PACKET_ERROR:
573
                // since sync packet is incorrect, don't decode it and continue with data
574
575
576
                break;
                
            default:
577
                // decode sync
578
579
580
                DecodeSyncPacket();
                break;
        }
Stephane Letz's avatar
Stephane Letz committed
581
  
582
#ifdef JACK_MONITOR
583
        // For timing
584
585
        fRcvSyncUst = GetMicroSeconds();
#endif
586

587
#ifdef JACK_MONITOR
sletz's avatar
sletz committed
588
        fNetTimeMon->Add(float(GetMicroSeconds() - fRcvSyncUst) / float(fEngineControl->fPeriodUsecs) * 100.f);
589
#endif
590
        // audio, midi or sync if driver is late
591
592
593
594
595
        switch (DataRecv()) {
        
            case SOCKET_ERROR:
                return SOCKET_ERROR;
                
596
            case DATA_PACKET_ERROR:
597
598
599
600
                jack_time_t cur_time = GetMicroSeconds();
                NotifyXRun(cur_time, float(cur_time - fBeginDateUst));  // Better this value than nothing...
                break;
        }
Stephane Letz's avatar
Stephane Letz committed
601
 
602
        // take the time at the beginning of the cycle
603
604
        JackDriver::CycleTakeBeginTime();

605
#ifdef JACK_MONITOR
sletz's avatar
sletz committed
606
        fNetTimeMon->Add(float(GetMicroSeconds() - fRcvSyncUst) / float(fEngineControl->fPeriodUsecs) * 100.f);
moret's avatar
moret committed
607
#endif
moret's avatar
moret committed
608

609
610
611
612
613
        return 0;
    }

    int JackNetDriver::Write()
    {
614
        // buffers
615
        for (int midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
616
            fNetMidiPlaybackBuffer->SetBuffer(midi_port_index, GetMidiOutputBuffer(midi_port_index));
617
        }
Stephane Letz's avatar
Stephane Letz committed
618

619
        for (int audio_port_index = 0; audio_port_index < fPlaybackChannels; audio_port_index++) {
620
        #ifdef OPTIMIZED_PROTOCOL
621
            // Port is connected on other side...
622
623
624
            if (fNetAudioPlaybackBuffer->GetConnected(audio_port_index)
                && (fGraphManager->GetConnectionsNum(fPlaybackPortList[audio_port_index]) > 0)) {
                fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, GetOutputBuffer(audio_port_index));
625
626
627
            } else {
                fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, NULL);
            }
628
629
630
        #else
            fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, GetOutputBuffer(audio_port_index));
        #endif
631
        }
632

633
#ifdef JACK_MONITOR
sletz's avatar
sletz committed
634
        fNetTimeMon->AddLast(float(GetMicroSeconds() - fRcvSyncUst) / float(fEngineControl->fPeriodUsecs) * 100.f);
moret's avatar
moret committed
635
636
#endif

637
        EncodeSyncPacket();
638

639
        // send sync
sletz's avatar
sletz committed
640
        if (SyncSend() == SOCKET_ERROR) {
641
            return SOCKET_ERROR;
sletz's avatar
sletz committed
642
        }
643

644
#ifdef JACK_MONITOR
645
        fNetTimeMon->Add(((float)(GetMicroSeconds() - fRcvSyncUst) / (float)fEngineControl->fPeriodUsecs) * 100.f);
moret's avatar
moret committed
646
647
#endif

648
        // send data
sletz's avatar
sletz committed
649
        if (DataSend() == SOCKET_ERROR) {
650
            return SOCKET_ERROR;
sletz's avatar
sletz committed
651
        }
moret's avatar
moret committed
652

653
#ifdef JACK_MONITOR
654
        fNetTimeMon->AddLast(((float)(GetMicroSeconds() - fRcvSyncUst) / (float)fEngineControl->fPeriodUsecs) * 100.f);
moret's avatar
moret committed
655
656
#endif

657
658
        return 0;
    }
sletz's avatar
sletz committed
659

660
//driver loader-----------------------------------------------------------------------
sletz's avatar
sletz committed
661
662

#ifdef __cplusplus
663
664
    extern "C"
    {
sletz's avatar
sletz committed
665
#endif
sletz's avatar
sletz committed
666

667
        SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor()
668
        {
669
670
671
672
            jack_driver_desc_t * desc;
            jack_driver_desc_filler_t filler;
            jack_driver_param_value_t value;

673
            desc = jack_driver_descriptor_construct("net", JackDriverMaster, "netjack slave backend component", &filler);
674
675

            strcpy(value.str, DEFAULT_MULTICAST_IP);
676
            jack_driver_descriptor_add_parameter(desc, &filler, "multicast-ip", 'a', JackDriverParamString, &value, NULL, "Multicast address, or explicit IP of the master", NULL);
677
678

            value.i = DEFAULT_PORT;
Stephane Letz's avatar
Stephane Letz committed
679
            jack_driver_descriptor_add_parameter(desc, &filler, "udp-net-port", 'p', JackDriverParamInt, &value, NULL, "UDP port", NULL);
680
681
682
683
684

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

            value.i = -1;
Stephane Letz's avatar
Stephane Letz committed
685
686
            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");
687

688
689
690
            value.i = -1;
            jack_driver_descriptor_add_parameter(desc, &filler, "midi-in-ports", 'i', JackDriverParamInt, &value, NULL, "Number of midi input ports", "Number of MIDI input ports. If -1, MIDI physical input from the master");
            jack_driver_descriptor_add_parameter(desc, &filler, "midi-out-ports", 'o', JackDriverParamInt, &value, NULL, "Number of midi output ports", "Number of MIDI output ports. If -1, MIDI physical output from the master");
691

sletz's avatar
sletz committed
692
#if HAVE_CELT
693
694
            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);
Robin Gareus's avatar
Robin Gareus committed
695
696
697
698
#endif
#if HAVE_OPUS
            value.i = -1;
            jack_driver_descriptor_add_parameter(desc, &filler, "opus", 'O', JackDriverParamInt, &value, NULL, "Set Opus encoding and number of kBits per channel", NULL);
sletz's avatar
sletz committed
699
#endif
700
            strcpy(value.str, "'hostname'");
Stephane Letz's avatar
Stephane Letz committed
701
            jack_driver_descriptor_add_parameter(desc, &filler, "client-name", 'n', JackDriverParamString, &value, NULL, "Name of the jack client", NULL);
702
703
704
705
            
            value.i = false;
            jack_driver_descriptor_add_parameter(desc, &filler, "auto-save", 's', JackDriverParamBool, &value, NULL, "Save/restore connection state when restarting", NULL);

706

sletz's avatar
sletz committed
707
708
/*  
Deactivated for now..
709
            value.ui = 0U;
Stephane Letz's avatar
Stephane Letz committed
710
            jack_driver_descriptor_add_parameter(desc, &filler, "transport-sync", 't', JackDriverParamUInt, &value, NULL, "Sync transport with master's", NULL);
sletz's avatar
sletz committed
711
*/
712

713
            value.ui = 5U;
714
            jack_driver_descriptor_add_parameter(desc, &filler, "latency", 'l', JackDriverParamUInt, &value, NULL, "Network latency", NULL);
nedko's avatar
nedko committed
715

716
717
718
            return desc;
        }

719
        SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
720
        {
Stephane Letz's avatar
Stephane Letz committed
721
            char multicast_ip[32];
722
            char net_name[JACK_CLIENT_NAME_SIZE + 1] = {0};
723
            int udp_port;
724
            int mtu = DEFAULT_MTU;
sletz's avatar
sletz committed
725
726
            // Desactivated for now...
            uint transport_sync = 0;
727
            jack_nframes_t period_size = 1024;
728
            jack_nframes_t sample_rate = 48000;
sletz's avatar
sletz committed
729
730
            int audio_capture_ports = -1;
            int audio_playback_ports = -1;
731
732
            int midi_input_ports = -1;
            int midi_output_ports = -1;
733
            int celt_encoding = -1;
Robin Gareus's avatar
Robin Gareus committed
734
            int opus_encoding = -1;
735
            bool monitor = false;
736
            int network_latency = 5;
737
738
            const JSList* node;
            const jack_driver_param_t* param;
739
            bool auto_save = false;
740

741
            // Possibly use env variable for UDP port
742
743
744
            const char* default_udp_port = getenv("JACK_NETJACK_PORT");
            udp_port = (default_udp_port) ? atoi(default_udp_port) : DEFAULT_PORT;

745
            // Possibly use env variable for multicast IP
746
            const char* default_multicast_ip = getenv("JACK_NETJACK_MULTICAST");
747
748
            strcpy(multicast_ip, (default_multicast_ip) ? default_multicast_ip : DEFAULT_MULTICAST_IP);
         
749
750
751
            for (node = params; node; node = jack_slist_next(node)) {
                param = (const jack_driver_param_t*) node->data;
                switch (param->character)
752
                {
moret's avatar
moret committed
753
                    case 'a' :
Stephane Letz's avatar
Stephane Letz committed
754
755
                        assert(strlen(param->value.str) < 32);
                        strcpy(multicast_ip, param->value.str);
moret's avatar
moret committed
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
                        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
775
                    #if HAVE_CELT
776
777
778
                    case 'c':
                        celt_encoding = param->value.i;
                        break;
sletz's avatar
sletz committed
779
                    #endif
Robin Gareus's avatar
Robin Gareus committed
780
781
782
783
784
                    #if HAVE_OPUS
                    case 'O':
                        opus_encoding = param->value.i;
                        break;
                    #endif
moret's avatar
moret committed
785
                    case 'n' :
786
                        strncpy(net_name, param->value.str, JACK_CLIENT_NAME_SIZE);
moret's avatar
moret committed
787
                        break;
788
                    case 's':
789
                        auto_save = true;
790
                        break;
sletz's avatar
sletz committed
791
792
                    /*
                    Deactivated for now..
moret's avatar
moret committed
793
794
795
                    case 't' :
                        transport_sync = param->value.ui;
                        break;
sletz's avatar
sletz committed
796
                    */
797
798
                    case 'l' :
                        network_latency = param->value.ui;
sletz's avatar
sletz committed
799
800