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

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
#include "JackTime.h"
22
23
24
25
26
27
28

using namespace std;

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

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

34
35
36
        //settings
        fClientName = const_cast<char*> ( fParams.fName );
        fJackClient = NULL;
37
38
39
        fSendTransportData.fState = -1;
        fReturnTransportData.fState = -1;
        fLastTransportState = -1;
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
        uint port_index;

        //jack audio ports
        fAudioCapturePorts = new jack_port_t* [fParams.fSendAudioChannels];
        for ( port_index = 0; port_index < fParams.fSendAudioChannels; port_index++ )
            fAudioCapturePorts[port_index] = NULL;
        fAudioPlaybackPorts = new jack_port_t* [fParams.fReturnAudioChannels];
        for ( port_index = 0; port_index < fParams.fReturnAudioChannels; port_index++ )
            fAudioPlaybackPorts[port_index] = NULL;
        //jack midi ports
        fMidiCapturePorts = new jack_port_t* [fParams.fSendMidiChannels];
        for ( port_index = 0; port_index < fParams.fSendMidiChannels; port_index++ )
            fMidiCapturePorts[port_index] = NULL;
        fMidiPlaybackPorts = new jack_port_t* [fParams.fReturnMidiChannels];
        for ( port_index = 0; port_index < fParams.fReturnMidiChannels; port_index++ )
            fMidiPlaybackPorts[port_index] = NULL;

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

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

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

moret's avatar
moret committed
119
        //set global parameters
moret's avatar
moret committed
120
121
        SetParams();

122
123
124
        //jack client and process
        jack_status_t status;
        if ( ( fJackClient = jack_client_open ( fClientName, JackNullOption, &status, NULL ) ) == NULL )
125
        {
126
            jack_error ( "Can't open a new jack client." );
127
128
129
            return false;
        }

130
131
132
133
134
        if (jack_set_process_callback(fJackClient, SetProcess, this ) < 0)
             goto fail;
             
        if (jack_set_buffer_size_callback(fJackClient, SetBufferSize, this) < 0)
             goto fail;
135

136
        if ( AllocPorts() != 0 )
137
        {
138
139
            jack_error ( "Can't allocate jack ports." );
            goto fail;
140
141
        }

moret's avatar
moret committed
142
        //process can now run
143
        fRunning = true;
144

145
146
        //finally activate jack client
        if ( jack_activate ( fJackClient ) != 0 )
147
        {
148
149
            jack_error ( "Can't activate jack client." );
            goto fail;
150
        }
151
152
153
        
        if (auto_connect)
            ConnectPorts();
moret's avatar
moret committed
154
        jack_info ( "New NetMaster started." );
155
        return true;
156

moret's avatar
moret committed
157
    fail:
158
159
160
161
162
163
        FreePorts();
        jack_client_close ( fJackClient );
        fJackClient = NULL;
        return false;
    }

164
//jack ports--------------------------------------------------------------------------
165
166
    int JackNetMaster::AllocPorts()
    {
167
168
        uint i;
        char name[24];
169
        jack_nframes_t port_latency = jack_get_buffer_size ( fJackClient );
170
171
172
        
        jack_log ( "JackNetMaster::AllocPorts" );

173
174
175
176
        //audio
        for ( i = 0; i < fParams.fSendAudioChannels; i++ )
        {
            sprintf ( name, "to_slave_%d", i+1 );
177
            if ( ( fAudioCapturePorts[i] = jack_port_register ( fJackClient, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0 ) ) == NULL )
178
                return -1;
moret's avatar
moret committed
179
            //port latency
moret's avatar
moret committed
180
            jack_port_set_latency ( fAudioCapturePorts[i], 0 );
181
        }
182
        
183
184
185
        for ( i = 0; i < fParams.fReturnAudioChannels; i++ )
        {
            sprintf ( name, "from_slave_%d", i+1 );
186
            if ( ( fAudioPlaybackPorts[i] = jack_port_register ( fJackClient, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput | JackPortIsTerminal, 0 ) ) == NULL )
187
                return -1;
moret's avatar
moret committed
188
189
190
191
192
193
194
195
196
197
198
199
200
            //port latency
            switch ( fParams.fNetworkMode )
            {
                case 'f' :
                    jack_port_set_latency ( fAudioPlaybackPorts[i], ( fParams.fSlaveSyncMode ) ? 0 : port_latency );
                    break;
                case 'n' :
                    jack_port_set_latency ( fAudioPlaybackPorts[i], port_latency + ( fParams.fSlaveSyncMode ) ? 0 : port_latency );
                    break;
                case 's' :
                    jack_port_set_latency ( fAudioPlaybackPorts[i], 2 * port_latency + ( fParams.fSlaveSyncMode ) ? 0 : port_latency );
                    break;
            }
201
        }
202
203
        
        
204
205
206
207
        //midi
        for ( i = 0; i < fParams.fSendMidiChannels; i++ )
        {
            sprintf ( name, "midi_to_slave_%d", i+1 );
208
            if ( ( fMidiCapturePorts[i] = jack_port_register ( fJackClient, name, JACK_DEFAULT_MIDI_TYPE, JackPortIsInput | JackPortIsTerminal, 0 ) ) == NULL )
209
                return -1;
moret's avatar
moret committed
210
            //port latency
moret's avatar
moret committed
211
            jack_port_set_latency ( fMidiCapturePorts[i], 0 );
212
213
214
215
        }
        for ( i = 0; i < fParams.fReturnMidiChannels; i++ )
        {
            sprintf ( name, "midi_from_slave_%d", i+1 );
216
            if ( ( fMidiPlaybackPorts[i] = jack_port_register ( fJackClient, name, JACK_DEFAULT_MIDI_TYPE,  JackPortIsOutput | JackPortIsTerminal, 0 ) ) == NULL )
217
                return -1;
moret's avatar
moret committed
218
219
220
221
222
223
224
225
226
227
228
229
230
            //port latency
            switch ( fParams.fNetworkMode )
            {
                case 'f' :
                    jack_port_set_latency ( fMidiPlaybackPorts[i], ( fParams.fSlaveSyncMode ) ? 0 : port_latency );
                    break;
                case 'n' :
                    jack_port_set_latency ( fMidiPlaybackPorts[i], port_latency + ( fParams.fSlaveSyncMode ) ? 0 : port_latency );
                    break;
                case 's' :
                    jack_port_set_latency ( fMidiPlaybackPorts[i], 2 * port_latency + ( fParams.fSlaveSyncMode ) ? 0 : port_latency );
                    break;
            }
231
        }
232
        return 0;
233
    }
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
    
    void JackNetMaster::ConnectPorts()
    {
        const char **ports;
         
        ports = jack_get_ports(fJackClient, NULL, NULL, JackPortIsPhysical | JackPortIsOutput);
        if (ports != NULL) {
            for (unsigned int i = 0; i < fParams.fSendAudioChannels && ports[i]; i++) {
                jack_connect(fJackClient, ports[i], jack_port_name(fAudioCapturePorts[i]));
            }
            free(ports);
        }
        
        ports = jack_get_ports(fJackClient, NULL, NULL, JackPortIsPhysical | JackPortIsInput);
        if (ports != NULL) {
            for (unsigned int i = 0; i < fParams.fReturnAudioChannels && ports[i]; i++) {
                jack_connect(fJackClient, jack_port_name(fAudioPlaybackPorts[i]), ports[i]);
            }
            free(ports);
        }
    }
255
256
257
258

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

260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
        uint port_index;
        for ( port_index = 0; port_index < fParams.fSendAudioChannels; port_index++ )
            if ( fAudioCapturePorts[port_index] )
                jack_port_unregister ( fJackClient, fAudioCapturePorts[port_index] );
        for ( port_index = 0; port_index < fParams.fReturnAudioChannels; port_index++ )
            if ( fAudioPlaybackPorts[port_index] )
                jack_port_unregister ( fJackClient, fAudioPlaybackPorts[port_index] );
        for ( port_index = 0; port_index < fParams.fSendMidiChannels; port_index++ )
            if ( fMidiCapturePorts[port_index] )
                jack_port_unregister ( fJackClient, fMidiCapturePorts[port_index] );
        for ( port_index = 0; port_index < fParams.fReturnMidiChannels; port_index++ )
            if ( fMidiPlaybackPorts[port_index] )
                jack_port_unregister ( fJackClient, fMidiPlaybackPorts[port_index] );
    }

275
//transport---------------------------------------------------------------------------
276
    void JackNetMaster::EncodeTransportData()
277
278
279
    {
        //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...
280
        fSendTransportData.fTimebaseMaster = NO_CHANGE;
281
282

        //update state and position
283
        fSendTransportData.fState = static_cast<uint> ( jack_transport_query ( fJackClient, &fSendTransportData.fPosition ) );
284
285

        //is it a new state ?
286
        fSendTransportData.fNewState = ( ( fSendTransportData.fState != fLastTransportState ) &&
moret's avatar
moret committed
287
                                         ( fSendTransportData.fState != fReturnTransportData.fState ) );
288
        if ( fSendTransportData.fNewState )
sletz's avatar
sletz committed
289
            jack_info ( "Sending '%s' to '%s' frame = %ld", GetTransportState ( fSendTransportData.fState ), fParams.fName, fSendTransportData.fPosition.frame );
290
        fLastTransportState = fSendTransportData.fState;
291
   }
292

293
    void JackNetMaster::DecodeTransportData()
294
    {
295
        //is there timebase master change ?
296
        if ( fReturnTransportData.fTimebaseMaster != NO_CHANGE )
297
        {
298
            int timebase = 0;
299
            switch ( fReturnTransportData.fTimebaseMaster )
300
301
302
303
304
            {
                case RELEASE_TIMEBASEMASTER :
                    timebase = jack_release_timebase ( fJackClient );
                    if ( timebase < 0 )
                        jack_error ( "Can't release timebase master." );
305
                    else
306
307
308
309
310
                        jack_info ( "'%s' isn't the timebase master anymore.", fParams.fName );
                    break;
                case TIMEBASEMASTER :
                    timebase = jack_set_timebase_callback ( fJackClient, 0, SetTimebaseCallback, this );
                    if ( timebase < 0 )
311
                        jack_error ( "Can't set a new timebase master." );
312
313
314
315
316
317
318
319
320
321
322
323
324
325
                    else
                        jack_info ( "'%s' is the new timebase master.", fParams.fName );
                    break;
                case CONDITIONAL_TIMEBASEMASTER :
                    timebase = jack_set_timebase_callback ( fJackClient, 1, SetTimebaseCallback, this );
                    if ( timebase != EBUSY )
                    {
                        if ( timebase < 0 )
                            jack_error ( "Can't set a new timebase master." );
                        else
                            jack_info ( "'%s' is the new timebase master.", fParams.fName );
                    }
                    break;
            }
326
327
        }

328
        //is the slave in a new transport state and is this state different from master's ?
moret's avatar
moret committed
329
        if ( fReturnTransportData.fNewState && ( fReturnTransportData.fState != jack_transport_query ( fJackClient, NULL ) ) )
330
        {
331
            switch ( fReturnTransportData.fState )
332
333
334
            {
                case JackTransportStopped :
                    jack_transport_stop ( fJackClient );
moret's avatar
moret committed
335
                    jack_info ( "'%s' stops transport.", fParams.fName );
336
337
                    break;
                case JackTransportStarting :
338
                    if ( jack_transport_reposition ( fJackClient, &fReturnTransportData.fPosition ) == EINVAL )
339
                        jack_error ( "Can't set new position." );
340
                    jack_transport_start ( fJackClient );
sletz's avatar
sletz committed
341
                    jack_info ( "'%s' starts transport frame = %d  frame = %d", fParams.fName, fReturnTransportData.fPosition.frame);
342
343
                    break;
                case JackTransportNetStarting :
moret's avatar
moret committed
344
                    jack_info ( "'%s' is ready to roll..", fParams.fName );
moret's avatar
moret committed
345
                    break;
346
                case JackTransportRolling :
moret's avatar
moret committed
347
                    jack_info ( "'%s' is rolling.", fParams.fName );
348
349
350
351
352
353
354
355
356
357
358
359
                    break;
            }
        }
    }

    void JackNetMaster::SetTimebaseCallback ( jack_transport_state_t state, jack_nframes_t nframes, jack_position_t* pos, int new_pos, void* arg )
    {
        static_cast<JackNetMaster*> ( arg )->TimebaseCallback ( pos );
    }

    void JackNetMaster::TimebaseCallback ( jack_position_t* pos )
    {
360
361
362
363
364
365
366
367
        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;
368
369
370
    }

//sync--------------------------------------------------------------------------------
371
 
372
373
    bool JackNetMaster::IsSlaveReadyToRoll()
    {
374
        return ( fReturnTransportData.fState == JackTransportNetStarting );
375
    }
376
377
378
379
380
381
382
    
    int JackNetMaster::SetBufferSize (jack_nframes_t nframes, void* arg)
    {
        jack_error("Cannot handle bufer size change, so proxy will be removed...");
        static_cast<JackNetMaster*> ( arg )->Exit();
        return 0;
    }
383
384

//process-----------------------------------------------------------------------------
385
386
    int JackNetMaster::SetProcess ( jack_nframes_t nframes, void* arg )
    {
387
        return static_cast<JackNetMaster*> ( arg )->Process();
388
389
390
391
392
393
394
    }

    int JackNetMaster::Process()
    {
        if ( !fRunning )
            return 0;

395
396
        uint port_index;
        int res = 0;
397

398
#ifdef JACK_MONITOR
399
        jack_time_t begin_time = GetMicroSeconds();
moret's avatar
Cleanup    
moret committed
400
        fNetTimeMon->New();
moret's avatar
moret committed
401
402
#endif

403
404
        //buffers
        for ( port_index = 0; port_index < fParams.fSendMidiChannels; port_index++ )
moret's avatar
moret committed
405
406
            fNetMidiCaptureBuffer->SetBuffer ( port_index, static_cast<JackMidiBuffer*> ( jack_port_get_buffer ( fMidiCapturePorts[port_index],
                                               fParams.fPeriodSize ) ) );
407
        for ( port_index = 0; port_index < fParams.fSendAudioChannels; port_index++ )
moret's avatar
moret committed
408
409
            fNetAudioCaptureBuffer->SetBuffer ( port_index, static_cast<sample_t*> ( jack_port_get_buffer ( fAudioCapturePorts[port_index],
                                                fParams.fPeriodSize ) ) );
410
        for ( port_index = 0; port_index < fParams.fReturnMidiChannels; port_index++ )
moret's avatar
moret committed
411
412
            fNetMidiPlaybackBuffer->SetBuffer ( port_index, static_cast<JackMidiBuffer*> ( jack_port_get_buffer ( fMidiPlaybackPorts[port_index],
                                                fParams.fPeriodSize ) ) );
413
        for ( port_index = 0; port_index < fParams.fReturnAudioChannels; port_index++ )
moret's avatar
moret committed
414
415
            fNetAudioPlaybackBuffer->SetBuffer ( port_index, static_cast<sample_t*> ( jack_port_get_buffer ( fAudioPlaybackPorts[port_index],
                                                 fParams.fPeriodSize ) ) );
416

417
418
419
        if (IsSynched()) {  // only send if connection is "synched"
        
            //encode the first packet
420
421
            EncodeSyncPacket();
   
422
423
424
425
426
            //send sync
            if ( SyncSend() == SOCKET_ERROR )
                return SOCKET_ERROR;

    #ifdef JACK_MONITOR
427
            fNetTimeMon->Add ( ( ( ( float ) (GetMicroSeconds() - begin_time ) ) / ( float ) fPeriodUsecs ) * 100.f );
428
429
430
431
432
433
434
    #endif

            //send data
            if ( DataSend() == SOCKET_ERROR )
                return SOCKET_ERROR;

    #ifdef JACK_MONITOR
435
            fNetTimeMon->Add ( ( ( ( float ) (GetMicroSeconds() - begin_time ) ) / ( float ) fPeriodUsecs ) * 100.f );
436
437
438
    #endif
    
        } else {
sletz's avatar
sletz committed
439
            jack_error("Connection is not synched, skip cycle...");
440
        }
moret's avatar
moret committed
441

442
443
444
445
        //receive sync
        res = SyncRecv();
        if ( ( res == 0 ) || ( res == SOCKET_ERROR ) )
            return res;
moret's avatar
moret committed
446

447
#ifdef JACK_MONITOR
448
        fNetTimeMon->Add ( ( ( ( float ) (GetMicroSeconds() - begin_time ) ) / ( float ) fPeriodUsecs ) * 100.f );
moret's avatar
moret committed
449
#endif
450

451
        //decode sync
452
453
        DecodeSyncPacket();
  
454
455
456
457
        //receive data
        res = DataRecv();
        if ( ( res == 0 ) || ( res == SOCKET_ERROR ) )
            return res;
moret's avatar
moret committed
458

459
#ifdef JACK_MONITOR
460
        fNetTimeMon->AddLast ( ( ( ( float ) (GetMicroSeconds() - begin_time ) ) / ( float ) fPeriodUsecs ) * 100.f );
moret's avatar
moret committed
461
#endif
462
463
464
465
466
467
468
469
        return 0;
    }

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

    JackNetMasterManager::JackNetMasterManager ( jack_client_t* client, const JSList* params ) : fSocket()
    {
        jack_log ( "JackNetMasterManager::JackNetMasterManager" );
moret's avatar
moret committed
470

471
472
        fManagerClient = client;
        fManagerName = jack_get_client_name ( fManagerClient );
473
        strcpy(fMulticastIP, DEFAULT_MULTICAST_IP);
474
475
476
        fSocket.SetPort ( DEFAULT_PORT );
        fGlobalID = 0;
        fRunning = true;
477
        fAutoConnect = false;
478
479
480
481
482
483
484
485

        const JSList* node;
        const jack_driver_param_t* param;
        for ( node = params; node; node = jack_slist_next ( node ) )
        {
            param = ( const jack_driver_param_t* ) node->data;
            switch ( param->character )
            {
moret's avatar
moret committed
486
                case 'a' :
487
488
489
490
                    if (strlen (param->value.str) < 32)
                        strcpy(fMulticastIP, param->value.str);
                    else
                        jack_error("Can't use multicast address %s, using default %s", param->value.ui, DEFAULT_MULTICAST_IP);
moret's avatar
moret committed
491
                    break;
492
                    
moret's avatar
moret committed
493
494
                case 'p':
                    fSocket.SetPort ( param->value.ui );
495
496
497
498
499
                    break;
                    
                case 'c':
                    fAutoConnect = param->value.i;
                    break;
500
501
502
            }
        }

503
504
        //set sync callback
        jack_set_sync_callback ( fManagerClient, SetSyncCallback, this );
505

506
        //activate the client (for sync callback)
507
        if ( jack_activate ( fManagerClient ) != 0 )
508
            jack_error ( "Can't activate the network manager client, transport disabled." );
509

510
511
512
513
514
515
516
517
        //launch the manager thread
        if ( jack_client_create_thread ( fManagerClient, &fManagerThread, 0, 0, NetManagerThread, this ) )
            jack_error ( "Can't create the network manager control thread." );
    }

    JackNetMasterManager::~JackNetMasterManager()
    {
        jack_log ( "JackNetMasterManager::~JackNetMasterManager" );
518
519
        jack_info ( "Exiting net manager..." );
        fRunning = false;
sletz's avatar
sletz committed
520
        jack_client_kill_thread ( fManagerClient, fManagerThread );
521
522
523
524
525
526
527
        master_list_t::iterator it;
        for ( it = fMasterList.begin(); it != fMasterList.end(); it++ )
            delete ( *it );
        fSocket.Close();
        SocketAPIEnd();
    }

528
529
    int JackNetMasterManager::SetSyncCallback ( jack_transport_state_t state, jack_position_t* pos, void* arg )
    {
530
        return static_cast<JackNetMasterManager*> ( arg )->SyncCallback ( state, pos );
531
532
533
534
    }

    int JackNetMasterManager::SyncCallback ( jack_transport_state_t state, jack_position_t* pos )
    {
535
        //check if each slave is ready to roll
536
537
538
        int ret = 1;
        master_list_it_t it;
        for ( it = fMasterList.begin(); it != fMasterList.end(); it++ )
539
            if ( ! ( *it )->IsSlaveReadyToRoll() )
540
541
                ret = 0;
        jack_log ( "JackNetMasterManager::SyncCallback returns '%s'", ( ret ) ? "true" : "false" );
moret's avatar
moret committed
542
        return ret;
543
544
    }

545
546
547
    void* JackNetMasterManager::NetManagerThread ( void* arg )
    {
        JackNetMasterManager* master_manager = static_cast<JackNetMasterManager*> ( arg );
548
549
        jack_info ( "Starting Jack Network Manager." );
        jack_info ( "Listening on '%s:%d'", master_manager->fMulticastIP, master_manager->fSocket.GetPort() );
550
551
552
553
554
555
556
557
558
559
560
        master_manager->Run();
        return NULL;
    }

    void JackNetMasterManager::Run()
    {
        jack_log ( "JackNetMasterManager::Run" );
        //utility variables
        int attempt = 0;

        //data
561
        session_params_t host_params;
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
        int rx_bytes = 0;
        JackNetMaster* net_master;

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

        //socket
        if ( fSocket.NewSocket() == SOCKET_ERROR )
        {
            jack_error ( "Can't create the network management input socket : %s", StrError ( NET_ERROR_CODE ) );
            return;
        }

        //bind the socket to the local port
moret's avatar
moret committed
580
        if ( fSocket.Bind() == SOCKET_ERROR )
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
        {
            jack_error ( "Can't bind the network manager socket : %s", StrError ( NET_ERROR_CODE ) );
            fSocket.Close();
            return;
        }

        //join multicast group
        if ( fSocket.JoinMCastGroup ( fMulticastIP ) == SOCKET_ERROR )
            jack_error ( "Can't join multicast group : %s", StrError ( NET_ERROR_CODE ) );

        //local loop
        if ( fSocket.SetLocalLoop() == SOCKET_ERROR )
            jack_error ( "Can't set local loop : %s", StrError ( NET_ERROR_CODE ) );

        //set a timeout on the multicast receive (the thread can now be cancelled)
596
        if ( fSocket.SetTimeOut ( 2000000 ) == SOCKET_ERROR )
597
598
599
600
601
602
603
            jack_error ( "Can't set timeout : %s", StrError ( NET_ERROR_CODE ) );

        jack_info ( "Waiting for a slave..." );

        //main loop, wait for data, deal with it and wait again
        do
        {
604
605
606
            session_params_t net_params;
            rx_bytes = fSocket.CatchHost ( &net_params, sizeof ( session_params_t ), 0 );
            SessionParamsNToH(&net_params, &host_params);
607
608
609
610
611
612
613
614
615
616
617
            if ( ( rx_bytes == SOCKET_ERROR ) && ( fSocket.GetError() != NET_NO_DATA ) )
            {
                jack_error ( "Error in receive : %s", StrError ( NET_ERROR_CODE ) );
                if ( ++attempt == 10 )
                {
                    jack_error ( "Can't receive on the socket, exiting net manager." );
                    return;
                }
            }
            if ( rx_bytes == sizeof ( session_params_t ) )
            {
618
                switch ( GetPacketType ( &host_params ) )
619
                {
moret's avatar
moret committed
620
                    case SLAVE_AVAILABLE:
621
                        if ( ( net_master = InitMaster ( host_params ) ) )
moret's avatar
moret committed
622
623
624
                            SessionParamsDisplay ( &net_master->fParams );
                        else
                            jack_error ( "Can't init new net master..." );
moret's avatar
moret committed
625
                        jack_info ( "Waiting for a slave..." );
moret's avatar
moret committed
626
627
                        break;
                    case KILL_MASTER:
628
                        if ( KillMaster ( &host_params ) )
moret's avatar
moret committed
629
630
631
632
                            jack_info ( "Waiting for a slave..." );
                        break;
                    default:
                        break;
633
634
635
636
637
638
                }
            }
        }
        while ( fRunning );
    }

639
    JackNetMaster* JackNetMasterManager::InitMaster ( session_params_t& params )
640
    {
641
        jack_log ( "JackNetMasterManager::InitMaster, Slave : %s", params.fName );
642
643
644
645
646
647
        
        //check MASTER <<==> SLAVE network protocol coherency
        if (params.fProtocolVersion != MASTER_PROTOCOL) {
            jack_error ( "Error : slave is running with a different protocol %s", params.fName );
            return NULL;
        }
moret's avatar
moret committed
648

649
650
651
652
653
654
655
656
657
        //settings
        fSocket.GetName ( params.fMasterNetName );
        params.fID = ++fGlobalID;
        params.fSampleRate = jack_get_sample_rate ( fManagerClient );
        params.fPeriodSize = jack_get_buffer_size ( fManagerClient );
        params.fBitdepth = 0;
        SetSlaveName ( params );

        //create a new master and add it to the list
658
659
        JackNetMaster* master = new JackNetMaster(fSocket, params, fMulticastIP);
        if ( master->Init(fAutoConnect) )
660
661
662
663
664
665
666
667
668
669
670
        {
            fMasterList.push_back ( master );
            return master;
        }
        delete master;
        return NULL;
    }

    void JackNetMasterManager::SetSlaveName ( session_params_t& params )
    {
        jack_log ( "JackNetMasterManager::SetSlaveName" );
moret's avatar
moret committed
671

672
673
674
675
676
677
678
679
680
        master_list_it_t it;
        for ( it = fMasterList.begin(); it != fMasterList.end(); it++ )
            if ( strcmp ( ( *it )->fParams.fName, params.fName ) == 0 )
                sprintf ( params.fName, "%s-%u", params.fName, params.fID );
    }

    master_list_it_t JackNetMasterManager::FindMaster ( uint32_t id )
    {
        jack_log ( "JackNetMasterManager::FindMaster, ID %u.", id );
moret's avatar
moret committed
681

682
683
684
685
686
687
688
        master_list_it_t it;
        for ( it = fMasterList.begin(); it != fMasterList.end(); it++ )
            if ( ( *it )->fParams.fID == id )
                return it;
        return it;
    }

689
    int JackNetMasterManager::KillMaster ( session_params_t* params )
690
691
    {
        jack_log ( "JackNetMasterManager::KillMaster, ID %u.", params->fID );
moret's avatar
moret committed
692

693
694
695
696
697
        master_list_it_t master = FindMaster ( params->fID );
        if ( master != fMasterList.end() )
        {
            fMasterList.erase ( master );
            delete *master;
698
            return 1;
699
        }
700
        return 0;
701
702
703
704
705
706
707
708
709
710
    }
}//namespace

static Jack::JackNetMasterManager* master_manager = NULL;

#ifdef __cplusplus
extern "C"
{
#endif

711
    SERVER_EXPORT jack_driver_desc_t* jack_get_descriptor()
712
713
    {
        jack_driver_desc_t *desc;
moret's avatar
moret committed
714
        desc = ( jack_driver_desc_t* ) calloc ( 1, sizeof ( jack_driver_desc_t ) );
715

716
717
718
        strcpy ( desc->name, "netmanager" );                        // size MUST be less then JACK_DRIVER_NAME_MAX + 1
        strcpy ( desc->desc, "netjack multi-cast master component" );  // size MUST be less then JACK_DRIVER_PARAM_DESC + 1

719
        desc->nparams = 3;
moret's avatar
moret committed
720
        desc->params = ( jack_driver_param_desc_t* ) calloc ( desc->nparams, sizeof ( jack_driver_param_desc_t ) );
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736

        int i = 0;
        strcpy ( desc->params[i].name, "multicast_ip" );
        desc->params[i].character = 'a';
        desc->params[i].type = JackDriverParamString;
        strcpy ( desc->params[i].value.str, DEFAULT_MULTICAST_IP );
        strcpy ( desc->params[i].short_desc, "Multicast Address" );
        strcpy ( desc->params[i].long_desc, desc->params[i].short_desc );

        i++;
        strcpy ( desc->params[i].name, "udp_net_port" );
        desc->params[i].character = 'p';
        desc->params[i].type = JackDriverParamInt;
        desc->params[i].value.i = DEFAULT_PORT;
        strcpy ( desc->params[i].short_desc, "UDP port" );
        strcpy ( desc->params[i].long_desc, desc->params[i].short_desc );
737
738
739
740
741
742
743
744
        
        i++;
        strcpy ( desc->params[i].name, "auto_connect" );
        desc->params[i].character = 'c';
        desc->params[i].type = JackDriverParamBool;
        desc->params[i].value.i = false;
        strcpy ( desc->params[i].short_desc, "Auto connect netmaster to system ports" );
        strcpy ( desc->params[i].long_desc, desc->params[i].short_desc );
745
746
747
748

        return desc;
    }

749
    SERVER_EXPORT int jack_internal_initialize ( jack_client_t* jack_client, const JSList* params )
750
751
752
753
754
755
756
757
758
759
760
761
762
763
    {
        if ( master_manager )
        {
            jack_error ( "Master Manager already loaded" );
            return 1;
        }
        else
        {
            jack_log ( "Loading Master Manager" );
            master_manager = new Jack::JackNetMasterManager ( jack_client, params );
            return ( master_manager ) ? 0 : 1;
        }
    }

764
    SERVER_EXPORT int jack_initialize ( jack_client_t* jack_client, const char* load_init )
765
766
    {
        JSList* params = NULL;
767
768
        bool parse_params = true;
        int res = 1;
769
        jack_driver_desc_t* desc = jack_get_descriptor();
770
771
772

        Jack::JackArgParser parser ( load_init );
        if ( parser.GetArgc() > 0 )
773
            parse_params = parser.ParseParams ( desc, &params );
774

775
776
777
778
        if (parse_params) {
            res = jack_internal_initialize ( jack_client, params );
            parser.FreeParams ( params );
        }
sletz's avatar
sletz committed
779
        return res;
780
781
    }

782
    SERVER_EXPORT void jack_finish ( void* arg )
783
    {
784
785
        if ( master_manager )
        {
786
787
788
789
790
791
792
793
            jack_log ( "Unloading Master Manager" );
            delete master_manager;
            master_manager = NULL;
        }
    }
#ifdef __cplusplus
}
#endif