2 Copyright(C) 2008-2011 Romain Moret at Grame
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 #include "JackNetManager.h"
20 #include "JackArgParser.h"
21 #include "JackServerGlobals.h"
22 #include "JackLockedEngine.h"
29 //JackNetMaster******************************************************************************************************
31 JackNetMaster::JackNetMaster(JackNetSocket
& socket
, session_params_t
& params
, const char* multicast_ip
)
32 : JackNetMasterInterface(params
, socket
, multicast_ip
)
34 jack_log("JackNetMaster::JackNetMaster");
37 fName
= const_cast<char*>(fParams
.fName
);
39 fSendTransportData
.fState
= -1;
40 fReturnTransportData
.fState
= -1;
41 fLastTransportState
= -1;
45 fAudioCapturePorts
= new jack_port_t
* [fParams
.fSendAudioChannels
];
46 for (port_index
= 0; port_index
< fParams
.fSendAudioChannels
; port_index
++) {
47 fAudioCapturePorts
[port_index
] = NULL
;
50 fAudioPlaybackPorts
= new jack_port_t
* [fParams
.fReturnAudioChannels
];
51 for (port_index
= 0; port_index
< fParams
.fReturnAudioChannels
; port_index
++) {
52 fAudioPlaybackPorts
[port_index
] = NULL
;
56 fMidiCapturePorts
= new jack_port_t
* [fParams
.fSendMidiChannels
];
57 for (port_index
= 0; port_index
< fParams
.fSendMidiChannels
; port_index
++) {
58 fMidiCapturePorts
[port_index
] = NULL
;
61 fMidiPlaybackPorts
= new jack_port_t
* [fParams
.fReturnMidiChannels
];
62 for (port_index
= 0; port_index
< fParams
.fReturnMidiChannels
; port_index
++) {
63 fMidiPlaybackPorts
[port_index
] = NULL
;
68 fPeriodUsecs
= (int)(1000000.f
* ((float) fParams
.fPeriodSize
/ (float) fParams
.fSampleRate
));
70 plot_name
= string(fParams
.fName
);
71 plot_name
+= string("_master");
72 plot_name
+= string((fParams
.fSlaveSyncMode
) ? "_sync" : "_async");
73 plot_name
+= string("_latency");
74 fNetTimeMon
= new JackGnuPlotMonitor
<float>(128, 4, plot_name
);
75 string net_time_mon_fields
[] =
78 string("end of send"),
80 string("end of cycle")
82 string net_time_mon_options
[] =
84 string("set xlabel \"audio cycles\""),
85 string("set ylabel \"% of audio cycle\"")
87 fNetTimeMon
->SetPlotFile(net_time_mon_options
, 2, net_time_mon_fields
, 4);
91 JackNetMaster::~JackNetMaster()
93 jack_log("JackNetMaster::~JackNetMaster ID = %u", fParams
.fID
);
96 jack_deactivate(fClient
);
98 jack_client_close(fClient
);
100 delete[] fAudioCapturePorts
;
101 delete[] fAudioPlaybackPorts
;
102 delete[] fMidiCapturePorts
;
103 delete[] fMidiPlaybackPorts
;
109 //init--------------------------------------------------------------------------------
110 bool JackNetMaster::Init(bool auto_connect
)
113 if (!JackNetMasterInterface::Init()) {
114 jack_error("JackNetMasterInterface::Init() error...");
118 //set global parameters
120 jack_error("SetParams error...");
124 //jack client and process
125 jack_status_t status
;
126 if ((fClient
= jack_client_open(fName
, JackNullOption
, &status
, NULL
)) == NULL
) {
127 jack_error("Can't open a new JACK client");
131 if (jack_set_process_callback(fClient
, SetProcess
, this) < 0) {
135 if (jack_set_buffer_size_callback(fClient
, SetBufferSize
, this) < 0) {
139 if (jack_set_sample_rate_callback(fClient
, SetSampleRate
, this) < 0) {
143 if (jack_set_latency_callback(fClient
, LatencyCallback
, this) < 0) {
148 if (jack_set_port_connect_callback(fClient, SetConnectCallback, this) < 0) {
153 if (AllocPorts() != 0) {
154 jack_error("Can't allocate JACK ports");
158 //process can now run
161 //finally activate jack client
162 if (jack_activate(fClient
) != 0) {
163 jack_error("Can't activate JACK client");
170 jack_info("New NetMaster started");
175 jack_client_close(fClient
);
180 //jack ports--------------------------------------------------------------------------
181 int JackNetMaster::AllocPorts()
185 jack_log("JackNetMaster::AllocPorts");
188 for (i
= 0; i
< fParams
.fSendAudioChannels
; i
++) {
189 snprintf(name
, sizeof(name
), "to_slave_%d", i
+1);
190 if ((fAudioCapturePorts
[i
] = jack_port_register(fClient
, name
, JACK_DEFAULT_AUDIO_TYPE
, JackPortIsInput
| JackPortIsTerminal
, 0)) == NULL
) {
195 for (i
= 0; i
< fParams
.fReturnAudioChannels
; i
++) {
196 snprintf(name
, sizeof(name
), "from_slave_%d", i
+1);
197 if ((fAudioPlaybackPorts
[i
] = jack_port_register(fClient
, name
, JACK_DEFAULT_AUDIO_TYPE
, JackPortIsOutput
| JackPortIsTerminal
, 0)) == NULL
) {
203 for (i
= 0; i
< fParams
.fSendMidiChannels
; i
++) {
204 snprintf(name
, sizeof(name
), "midi_to_slave_%d", i
+1);
205 if ((fMidiCapturePorts
[i
] = jack_port_register(fClient
, name
, JACK_DEFAULT_MIDI_TYPE
, JackPortIsInput
| JackPortIsTerminal
, 0)) == NULL
) {
210 for (i
= 0; i
< fParams
.fReturnMidiChannels
; i
++) {
211 snprintf(name
, sizeof(name
), "midi_from_slave_%d", i
+1);
212 if ((fMidiPlaybackPorts
[i
] = jack_port_register(fClient
, name
, JACK_DEFAULT_MIDI_TYPE
, JackPortIsOutput
| JackPortIsTerminal
, 0)) == NULL
) {
219 void JackNetMaster::ConnectPorts()
221 const char** ports
= jack_get_ports(fClient
, NULL
, JACK_DEFAULT_AUDIO_TYPE
, JackPortIsPhysical
| JackPortIsOutput
);
223 for (int i
= 0; i
< fParams
.fSendAudioChannels
&& ports
[i
]; i
++) {
224 jack_connect(fClient
, ports
[i
], jack_port_name(fAudioCapturePorts
[i
]));
229 ports
= jack_get_ports(fClient
, NULL
, JACK_DEFAULT_AUDIO_TYPE
, JackPortIsPhysical
| JackPortIsInput
);
231 for (int i
= 0; i
< fParams
.fReturnAudioChannels
&& ports
[i
]; i
++) {
232 jack_connect(fClient
, jack_port_name(fAudioPlaybackPorts
[i
]), ports
[i
]);
238 void JackNetMaster::FreePorts()
240 jack_log("JackNetMaster::FreePorts ID = %u", fParams
.fID
);
243 for (port_index
= 0; port_index
< fParams
.fSendAudioChannels
; port_index
++) {
244 if (fAudioCapturePorts
[port_index
]) {
245 jack_port_unregister(fClient
, fAudioCapturePorts
[port_index
]);
248 for (port_index
= 0; port_index
< fParams
.fReturnAudioChannels
; port_index
++) {
249 if (fAudioPlaybackPorts
[port_index
]) {
250 jack_port_unregister(fClient
, fAudioPlaybackPorts
[port_index
]);
253 for (port_index
= 0; port_index
< fParams
.fSendMidiChannels
; port_index
++) {
254 if (fMidiCapturePorts
[port_index
]) {
255 jack_port_unregister(fClient
, fMidiCapturePorts
[port_index
]);
258 for (port_index
= 0; port_index
< fParams
.fReturnMidiChannels
; port_index
++) {
259 if (fMidiPlaybackPorts
[port_index
]) {
260 jack_port_unregister(fClient
, fMidiPlaybackPorts
[port_index
]);
265 //transport---------------------------------------------------------------------------
266 void JackNetMaster::EncodeTransportData()
268 //is there a new timebase master ?
269 //TODO : check if any timebase callback has been called (and if it's conditional or not) and set correct value...
270 fSendTransportData
.fTimebaseMaster
= NO_CHANGE
;
272 //update state and position
273 fSendTransportData
.fState
= static_cast<uint
>(jack_transport_query(fClient
, &fSendTransportData
.fPosition
));
275 //is it a new state ?
276 fSendTransportData
.fNewState
= ((fSendTransportData
.fState
!= fLastTransportState
) && (fSendTransportData
.fState
!= fReturnTransportData
.fState
));
277 if (fSendTransportData
.fNewState
) {
278 jack_info("Sending '%s' to '%s' frame = %ld", GetTransportState(fSendTransportData
.fState
), fParams
.fName
, fSendTransportData
.fPosition
.frame
);
280 fLastTransportState
= fSendTransportData
.fState
;
283 void JackNetMaster::DecodeTransportData()
285 //is there timebase master change ?
286 if (fReturnTransportData
.fTimebaseMaster
!= NO_CHANGE
) {
289 switch (fReturnTransportData
.fTimebaseMaster
)
291 case RELEASE_TIMEBASEMASTER
:
292 timebase
= jack_release_timebase(fClient
);
294 jack_error("Can't release timebase master");
296 jack_info("'%s' isn't the timebase master anymore", fParams
.fName
);
300 case TIMEBASEMASTER
:
301 timebase
= jack_set_timebase_callback(fClient
, 0, SetTimebaseCallback
, this);
303 jack_error("Can't set a new timebase master");
305 jack_info("'%s' is the new timebase master", fParams
.fName
);
309 case CONDITIONAL_TIMEBASEMASTER
:
310 timebase
= jack_set_timebase_callback(fClient
, 1, SetTimebaseCallback
, this);
311 if (timebase
!= EBUSY
) {
313 jack_error("Can't set a new timebase master");
315 jack_info("'%s' is the new timebase master", fParams
.fName
);
321 //is the slave in a new transport state and is this state different from master's ?
322 if (fReturnTransportData
.fNewState
&& (fReturnTransportData
.fState
!= jack_transport_query(fClient
, NULL
))) {
324 switch (fReturnTransportData
.fState
)
326 case JackTransportStopped
:
327 jack_transport_stop(fClient
);
328 jack_info("'%s' stops transport", fParams
.fName
);
331 case JackTransportStarting
:
332 if (jack_transport_reposition(fClient
, &fReturnTransportData
.fPosition
) == EINVAL
)
333 jack_error("Can't set new position");
334 jack_transport_start(fClient
);
335 jack_info("'%s' starts transport frame = %d", fParams
.fName
, fReturnTransportData
.fPosition
.frame
);
338 case JackTransportNetStarting
:
339 jack_info("'%s' is ready to roll...", fParams
.fName
);
342 case JackTransportRolling
:
343 jack_info("'%s' is rolling", fParams
.fName
);
349 void JackNetMaster::SetTimebaseCallback(jack_transport_state_t state
, jack_nframes_t nframes
, jack_position_t
* pos
, int new_pos
, void* arg
)
351 static_cast<JackNetMaster
*>(arg
)->TimebaseCallback(pos
);
354 void JackNetMaster::TimebaseCallback(jack_position_t
* pos
)
356 pos
->bar
= fReturnTransportData
.fPosition
.bar
;
357 pos
->beat
= fReturnTransportData
.fPosition
.beat
;
358 pos
->tick
= fReturnTransportData
.fPosition
.tick
;
359 pos
->bar_start_tick
= fReturnTransportData
.fPosition
.bar_start_tick
;
360 pos
->beats_per_bar
= fReturnTransportData
.fPosition
.beats_per_bar
;
361 pos
->beat_type
= fReturnTransportData
.fPosition
.beat_type
;
362 pos
->ticks_per_beat
= fReturnTransportData
.fPosition
.ticks_per_beat
;
363 pos
->beats_per_minute
= fReturnTransportData
.fPosition
.beats_per_minute
;
366 //sync--------------------------------------------------------------------------------
368 bool JackNetMaster::IsSlaveReadyToRoll()
370 return (fReturnTransportData
.fState
== JackTransportNetStarting
);
373 int JackNetMaster::SetBufferSize(jack_nframes_t nframes
, void* arg
)
375 JackNetMaster
* obj
= static_cast<JackNetMaster
*>(arg
);
376 if (nframes
!= obj
->fParams
.fPeriodSize
) {
377 jack_error("Cannot currently handle buffer size change, so JackNetMaster proxy will be removed...");
383 int JackNetMaster::SetSampleRate(jack_nframes_t nframes
, void* arg
)
385 JackNetMaster
* obj
= static_cast<JackNetMaster
*>(arg
);
386 if (nframes
!= obj
->fParams
.fSampleRate
) {
387 jack_error("Cannot currently handle sample rate change, so JackNetMaster proxy will be removed...");
393 void JackNetMaster::LatencyCallback(jack_latency_callback_mode_t mode
, void* arg
)
395 JackNetMaster
* obj
= static_cast<JackNetMaster
*>(arg
);
396 jack_nframes_t port_latency
= jack_get_buffer_size(obj
->fClient
);
397 jack_latency_range_t range
;
400 for (int i
= 0; i
< obj
->fParams
.fSendAudioChannels
; i
++) {
402 range
.min
= range
.max
= float(obj
->fParams
.fNetworkLatency
* port_latency
) / 2.f
;
403 jack_port_set_latency_range(obj
->fAudioCapturePorts
[i
], JackPlaybackLatency
, &range
);
407 for (int i
= 0; i
< obj
->fParams
.fReturnAudioChannels
; i
++) {
409 range
.min
= range
.max
= float(obj
->fParams
.fNetworkLatency
* port_latency
) / 2.f
+ ((obj
->fParams
.fSlaveSyncMode
) ? 0 : port_latency
);
410 jack_port_set_latency_range(obj
->fAudioPlaybackPorts
[i
], JackCaptureLatency
, &range
);
414 for (int i
= 0; i
< obj
->fParams
.fSendMidiChannels
; i
++) {
416 range
.min
= range
.max
= float(obj
->fParams
.fNetworkLatency
* port_latency
) / 2.f
;
417 jack_port_set_latency_range(obj
->fMidiCapturePorts
[i
], JackPlaybackLatency
, &range
);
421 for (int i
= 0; i
< obj
->fParams
.fReturnMidiChannels
; i
++) {
423 range
.min
= range
.max
= obj
->fParams
.fNetworkLatency
* port_latency
+ ((obj
->fParams
.fSlaveSyncMode
) ? 0 : port_latency
);
424 jack_port_set_latency_range(obj
->fMidiPlaybackPorts
[i
], JackCaptureLatency
, &range
);
428 //process-----------------------------------------------------------------------------
429 int JackNetMaster::SetProcess(jack_nframes_t nframes
, void* arg
)
432 return static_cast<JackNetMaster
*>(arg
)->Process();
433 } catch (JackNetException
& e
) {
438 void JackNetMaster::SetConnectCallback(jack_port_id_t a
, jack_port_id_t b
, int connect
, void* arg
)
440 static_cast<JackNetMaster
*>(arg
)->ConnectCallback(a
, b
, connect
);
443 void JackNetMaster::ConnectCallback(jack_port_id_t a
, jack_port_id_t b
, int connect
)
445 jack_info("JackNetMaster::ConnectCallback a = %d b = %d connect = %d", a
, b
, connect
);
447 jack_connect(fClient
, jack_port_name(jack_port_by_id(fClient
, a
)), "system:playback_1");
451 int JackNetMaster::Process()
458 jack_time_t begin_time
= GetMicroSeconds();
463 for (int midi_port_index
= 0; midi_port_index
< fParams
.fSendMidiChannels
; midi_port_index
++) {
464 fNetMidiCaptureBuffer
->SetBuffer(midi_port_index
,
465 static_cast<JackMidiBuffer
*>(jack_port_get_buffer(fMidiCapturePorts
[midi_port_index
],
466 fParams
.fPeriodSize
)));
468 for (int audio_port_index
= 0; audio_port_index
< fParams
.fSendAudioChannels
; audio_port_index
++) {
470 #ifdef OPTIMIZED_PROTOCOL
471 if (fNetAudioCaptureBuffer
->GetConnected(audio_port_index
)) {
472 // Port is connected on other side...
473 fNetAudioCaptureBuffer
->SetBuffer(audio_port_index
,
474 ((jack_port_connected(fAudioCapturePorts
[audio_port_index
]) > 0)
475 ? static_cast<sample_t
*>(jack_port_get_buffer(fAudioCapturePorts
[audio_port_index
], fParams
.fPeriodSize
))
478 fNetAudioCaptureBuffer
->SetBuffer(audio_port_index
, NULL
);
481 fNetAudioCaptureBuffer
->SetBuffer(audio_port_index
,
482 static_cast<sample_t
*>(jack_port_get_buffer(fAudioCapturePorts
[audio_port_index
],
483 fParams
.fPeriodSize
)));
488 for (int midi_port_index
= 0; midi_port_index
< fParams
.fReturnMidiChannels
; midi_port_index
++) {
489 fNetMidiPlaybackBuffer
->SetBuffer(midi_port_index
,
490 static_cast<JackMidiBuffer
*>(jack_port_get_buffer(fMidiPlaybackPorts
[midi_port_index
],
491 fParams
.fPeriodSize
)));
493 for (int audio_port_index
= 0; audio_port_index
< fParams
.fReturnAudioChannels
; audio_port_index
++) {
495 #ifdef OPTIMIZED_PROTOCOL
496 sample_t
* out
= (jack_port_connected(fAudioPlaybackPorts
[audio_port_index
]) > 0)
497 ? static_cast<sample_t
*>(jack_port_get_buffer(fAudioPlaybackPorts
[audio_port_index
], fParams
.fPeriodSize
))
500 memset(out
, 0, sizeof(float) * fParams
.fPeriodSize
);
502 fNetAudioPlaybackBuffer
->SetBuffer(audio_port_index
, out
);
504 sample_t
* out
= static_cast<sample_t
*>(jack_port_get_buffer(fAudioPlaybackPorts
[audio_port_index
], fParams
.fPeriodSize
));
506 memset(out
, 0, sizeof(float) * fParams
.fPeriodSize
);
508 fNetAudioPlaybackBuffer
->SetBuffer(audio_port_index
, out
)));
512 // encode the first packet
515 if (SyncSend() == SOCKET_ERROR
) {
520 fNetTimeMon
->Add((((float)(GetMicroSeconds() - begin_time
)) / (float) fPeriodUsecs
) * 100.f
);
524 if (DataSend() == SOCKET_ERROR
) {
529 fNetTimeMon
->Add((((float)(GetMicroSeconds() - begin_time
)) / (float) fPeriodUsecs
) * 100.f
);
533 int res
= SyncRecv();
540 case SYNC_PACKET_ERROR
:
541 // Since sync packet is incorrect, don't decode it and continue with data
547 DecodeSyncPacket(unused_frames
);
552 fNetTimeMon
->Add((((float)(GetMicroSeconds() - begin_time
)) / (float) fPeriodUsecs
) * 100.f
);
563 case DATA_PACKET_ERROR
:
564 // Well not a real XRun...
565 JackServerGlobals::fInstance
->GetEngine()->NotifyClientXRun(ALL_CLIENTS
);
570 fNetTimeMon
->AddLast((((float)(GetMicroSeconds() - begin_time
)) / (float) fPeriodUsecs
) * 100.f
);
575 void JackNetMaster::SaveConnections(connections_list_t
& connections
)
578 for (int i
= 0; i
< fParams
.fSendAudioChannels
; i
++) {
579 const char** connected_port
= jack_port_get_all_connections(fClient
, fAudioCapturePorts
[i
]);
580 if (connected_port
!= NULL
) {
581 for (int port
= 0; connected_port
[port
]; port
++) {
582 connections
.push_back(make_pair(connected_port
[port
], jack_port_name(fAudioCapturePorts
[i
])));
583 jack_log("INPUT %s ==> %s", connected_port
[port
], jack_port_name(fAudioCapturePorts
[i
]));
585 jack_free(connected_port
);
589 for (int i
= 0; i
< fParams
.fReturnAudioChannels
; i
++) {
590 const char** connected_port
= jack_port_get_all_connections(fClient
, fAudioPlaybackPorts
[i
]);
591 if (connected_port
!= NULL
) {
592 for (int port
= 0; connected_port
[port
]; port
++) {
593 connections
.push_back(make_pair(jack_port_name(fAudioPlaybackPorts
[i
]), connected_port
[port
]));
594 jack_log("OUTPUT %s ==> %s", jack_port_name(fAudioPlaybackPorts
[i
]), connected_port
[port
]);
596 jack_free(connected_port
);
601 for (int i
= 0; i
< fParams
.fSendMidiChannels
; i
++) {
602 const char** connected_port
= jack_port_get_all_connections(fClient
, fMidiCapturePorts
[i
]);
603 if (connected_port
!= NULL
) {
604 for (int port
= 0; connected_port
[port
]; port
++) {
605 connections
.push_back(make_pair(connected_port
[port
], jack_port_name(fMidiCapturePorts
[i
])));
606 jack_log("INPUT %s ==> %s", connected_port
[port
], jack_port_name(fMidiCapturePorts
[i
]));
608 jack_free(connected_port
);
612 for (int i
= 0; i
< fParams
.fReturnMidiChannels
; i
++) {
613 const char** connected_port
= jack_port_get_all_connections(fClient
, fMidiPlaybackPorts
[i
]);
614 if (connected_port
!= NULL
) {
615 for (int port
= 0; connected_port
[port
]; port
++) {
616 connections
.push_back(make_pair(jack_port_name(fMidiPlaybackPorts
[i
]), connected_port
[port
]));
617 jack_log("OUTPUT %s ==> %s", jack_port_name(fMidiPlaybackPorts
[i
]), connected_port
[port
]);
619 jack_free(connected_port
);
624 void JackNetMaster::LoadConnections(const connections_list_t
& connections
)
626 list
<pair
<string
, string
> >::const_iterator it
;
627 for (it
= connections
.begin(); it
!= connections
.end(); it
++) {
628 pair
<string
, string
> connection
= *it
;
629 jack_connect(fClient
, connection
.first
.c_str(), connection
.second
.c_str());
634 //JackNetMasterManager***********************************************************************************************
636 JackNetMasterManager::JackNetMasterManager(jack_client_t
* client
, const JSList
* params
) : fSocket()
638 jack_log("JackNetMasterManager::JackNetMasterManager");
641 fName
= jack_get_client_name(fClient
);
644 fAutoConnect
= false;
648 const jack_driver_param_t
* param
;
650 jack_on_shutdown(fClient
, SetShutDown
, this);
652 // Possibly use env variable
653 const char* default_udp_port
= getenv("JACK_NETJACK_PORT");
654 fSocket
.SetPort((default_udp_port
) ? atoi(default_udp_port
) : DEFAULT_PORT
);
656 const char* default_multicast_ip
= getenv("JACK_NETJACK_MULTICAST");
657 if (default_multicast_ip
) {
658 strcpy(fMulticastIP
, default_multicast_ip
);
660 strcpy(fMulticastIP
, DEFAULT_MULTICAST_IP
);
663 for (node
= params
; node
; node
= jack_slist_next(node
)) {
665 param
= (const jack_driver_param_t
*) node
->data
;
666 switch (param
->character
) {
668 if (strlen(param
->value
.str
) < 32) {
669 strcpy(fMulticastIP
, param
->value
.str
);
671 jack_error("Can't use multicast address %s, using default %s", param
->value
.ui
, DEFAULT_MULTICAST_IP
);
676 fSocket
.SetPort(param
->value
.ui
);
690 jack_set_sync_callback(fClient
, SetSyncCallback
, this);
692 //activate the client (for sync callback)
693 if (jack_activate(fClient
) != 0) {
694 jack_error("Can't activate the NetManager client, transport disabled");
697 //launch the manager thread
698 if (jack_client_create_thread(fClient
, &fThread
, 0, 0, NetManagerThread
, this)) {
699 jack_error("Can't create the NetManager control thread");
703 JackNetMasterManager::~JackNetMasterManager()
705 jack_log("JackNetMasterManager::~JackNetMasterManager");
709 int JackNetMasterManager::CountIO(const char* type
, int flags
)
712 const char** ports
= jack_get_ports(fClient
, NULL
, type
, flags
);
714 while (ports
[count
]) { count
++; }
720 void JackNetMasterManager::SetShutDown(void* arg
)
722 static_cast<JackNetMasterManager
*>(arg
)->ShutDown();
725 void JackNetMasterManager::ShutDown()
727 jack_log("JackNetMasterManager::ShutDown");
729 jack_client_kill_thread(fClient
, fThread
);
732 master_list_t::iterator it
;
733 for (it
= fMasterList
.begin(); it
!= fMasterList
.end(); it
++) {
741 int JackNetMasterManager::SetSyncCallback(jack_transport_state_t state
, jack_position_t
* pos
, void* arg
)
743 return static_cast<JackNetMasterManager
*>(arg
)->SyncCallback(state
, pos
);
746 int JackNetMasterManager::SyncCallback(jack_transport_state_t state
, jack_position_t
* pos
)
748 //check if each slave is ready to roll
751 for (it
= fMasterList
.begin(); it
!= fMasterList
.end(); it
++) {
752 if (!(*it
)->IsSlaveReadyToRoll()) {
756 jack_log("JackNetMasterManager::SyncCallback returns '%s'", (res
) ? "true" : "false");
760 void* JackNetMasterManager::NetManagerThread(void* arg
)
762 JackNetMasterManager
* master_manager
= static_cast<JackNetMasterManager
*>(arg
);
763 jack_info("Starting Jack NetManager");
764 jack_info("Listening on '%s:%d'", master_manager
->fMulticastIP
, master_manager
->fSocket
.GetPort());
765 master_manager
->Run();
769 void JackNetMasterManager::Run()
771 jack_log("JackNetMasterManager::Run");
776 session_params_t host_params
;
778 JackNetMaster
* net_master
;
780 //init socket API (win32)
781 if (SocketAPIInit() < 0) {
782 jack_error("Can't init Socket API, exiting...");
787 if (fSocket
.NewSocket() == SOCKET_ERROR
) {
788 jack_error("Can't create NetManager input socket : %s", StrError(NET_ERROR_CODE
));
792 //bind the socket to the local port
793 if (fSocket
.Bind() == SOCKET_ERROR
) {
794 jack_error("Can't bind NetManager socket : %s", StrError(NET_ERROR_CODE
));
799 //join multicast group
800 if (fSocket
.JoinMCastGroup(fMulticastIP
) == SOCKET_ERROR
) {
801 jack_error("Can't join multicast group : %s", StrError(NET_ERROR_CODE
));
805 if (fSocket
.SetLocalLoop() == SOCKET_ERROR
) {
806 jack_error("Can't set local loop : %s", StrError(NET_ERROR_CODE
));
809 //set a timeout on the multicast receive (the thread can now be cancelled)
810 if (fSocket
.SetTimeOut(MANAGER_INIT_TIMEOUT
) == SOCKET_ERROR
) {
811 jack_error("Can't set timeout : %s", StrError(NET_ERROR_CODE
));
814 //main loop, wait for data, deal with it and wait again
817 session_params_t net_params
;
818 rx_bytes
= fSocket
.CatchHost(&net_params
, sizeof(session_params_t
), 0);
819 SessionParamsNToH(&net_params
, &host_params
);
821 if ((rx_bytes
== SOCKET_ERROR
) && (fSocket
.GetError() != NET_NO_DATA
)) {
822 jack_error("Error in receive : %s", StrError(NET_ERROR_CODE
));
823 if (++attempt
== 10) {
824 jack_error("Can't receive on the socket, exiting net manager");
829 if (rx_bytes
== sizeof(session_params_t
)) {
830 switch (GetPacketType(&host_params
))
832 case SLAVE_AVAILABLE
:
833 if ((net_master
= InitMaster(host_params
))) {
834 SessionParamsDisplay(&net_master
->fParams
);
836 jack_error("Can't init new NetMaster...");
838 jack_info("Waiting for a slave...");
841 if (KillMaster(&host_params
)) {
842 jack_info("Waiting for a slave...");
853 JackNetMaster
* JackNetMasterManager::InitMaster(session_params_t
& params
)
855 jack_log("JackNetMasterManager::InitMaster slave : %s", params
.fName
);
857 //check MASTER <<==> SLAVE network protocol coherency
858 if (params
.fProtocolVersion
!= NETWORK_PROTOCOL
) {
859 jack_error("Error : slave '%s' is running with a different protocol %d != %d", params
.fName
, params
.fProtocolVersion
, NETWORK_PROTOCOL
);
864 fSocket
.GetName(params
.fMasterNetName
);
865 params
.fID
= ++fGlobalID
;
866 params
.fSampleRate
= jack_get_sample_rate(fClient
);
867 params
.fPeriodSize
= jack_get_buffer_size(fClient
);
869 if (params
.fSendAudioChannels
== -1) {
870 params
.fSendAudioChannels
= CountIO(JACK_DEFAULT_AUDIO_TYPE
, JackPortIsPhysical
| JackPortIsOutput
);
871 jack_info("Takes physical %d audio input(s) for slave", params
.fSendAudioChannels
);
874 if (params
.fReturnAudioChannels
== -1) {
875 params
.fReturnAudioChannels
= CountIO(JACK_DEFAULT_AUDIO_TYPE
, JackPortIsPhysical
| JackPortIsInput
);
876 jack_info("Takes physical %d audio output(s) for slave", params
.fReturnAudioChannels
);
879 if (params
.fSendMidiChannels
== -1) {
880 params
.fSendMidiChannels
= CountIO(JACK_DEFAULT_MIDI_TYPE
, JackPortIsPhysical
| JackPortIsOutput
);
881 jack_info("Takes physical %d MIDI input(s) for slave", params
.fSendMidiChannels
);
884 if (params
.fReturnMidiChannels
== -1) {
885 params
.fReturnMidiChannels
= CountIO(JACK_DEFAULT_MIDI_TYPE
, JackPortIsPhysical
| JackPortIsInput
);
886 jack_info("Takes physical %d MIDI output(s) for slave", params
.fReturnMidiChannels
);
889 //create a new master and add it to the list
890 JackNetMaster
* master
= new JackNetMaster(fSocket
, params
, fMulticastIP
);
891 if (master
->Init(fAutoConnect
)) {
892 fMasterList
.push_back(master
);
893 if (fAutoSave
&& fMasterConnectionList
.find(params
.fName
) != fMasterConnectionList
.end()) {
894 master
->LoadConnections(fMasterConnectionList
[params
.fName
]);
903 master_list_it_t
JackNetMasterManager::FindMaster(uint32_t id
)
905 jack_log("JackNetMasterManager::FindMaster ID = %u", id
);
908 for (it
= fMasterList
.begin(); it
!= fMasterList
.end(); it
++) {
909 if ((*it
)->fParams
.fID
== id
) {
916 int JackNetMasterManager::KillMaster(session_params_t
* params
)
918 jack_log("JackNetMasterManager::KillMaster ID = %u", params
->fID
);
920 master_list_it_t master_it
= FindMaster(params
->fID
);
921 if (master_it
!= fMasterList
.end()) {
923 fMasterConnectionList
[params
->fName
].clear();
924 (*master_it
)->SaveConnections(fMasterConnectionList
[params
->fName
]);
926 fMasterList
.erase(master_it
);
934 static Jack::JackNetMasterManager
* master_manager
= NULL
;
941 SERVER_EXPORT jack_driver_desc_t
* jack_get_descriptor()
943 jack_driver_desc_t
* desc
;
944 jack_driver_desc_filler_t filler
;
945 jack_driver_param_value_t value
;
947 desc
= jack_driver_descriptor_construct("netmanager", JackDriverNone
, "netjack multi-cast master component", &filler
);
949 strcpy(value
.str
, DEFAULT_MULTICAST_IP
);
950 jack_driver_descriptor_add_parameter(desc
, &filler
, "multicast-ip", 'a', JackDriverParamString
, &value
, NULL
, "Multicast address", NULL
);
952 value
.i
= DEFAULT_PORT
;
953 jack_driver_descriptor_add_parameter(desc
, &filler
, "udp-net-port", 'p', JackDriverParamInt
, &value
, NULL
, "UDP port", NULL
);
956 jack_driver_descriptor_add_parameter(desc
, &filler
, "auto-connect", 'c', JackDriverParamBool
, &value
, NULL
, "Auto connect netmaster to system ports", NULL
);
959 jack_driver_descriptor_add_parameter(desc
, &filler
, "auto-save", 's', JackDriverParamBool
, &value
, NULL
, "Save/restore netmaster connection state when restarted", NULL
);
964 SERVER_EXPORT
int jack_internal_initialize(jack_client_t
* jack_client
, const JSList
* params
)
966 if (master_manager
) {
967 jack_error("Master Manager already loaded");
970 jack_log("Loading Master Manager");
971 master_manager
= new Jack::JackNetMasterManager(jack_client
, params
);
972 return (master_manager
) ? 0 : 1;
976 SERVER_EXPORT
int jack_initialize(jack_client_t
* jack_client
, const char* load_init
)
978 JSList
* params
= NULL
;
979 bool parse_params
= true;
981 jack_driver_desc_t
* desc
= jack_get_descriptor();
983 Jack::JackArgParser
parser(load_init
);
984 if (parser
.GetArgc() > 0) {
985 parse_params
= parser
.ParseParams(desc
, ¶ms
);
989 res
= jack_internal_initialize(jack_client
, params
);
990 parser
.FreeParams(params
);
995 SERVER_EXPORT
void jack_finish(void* arg
)
997 if (master_manager
) {
998 jack_log("Unloading Master Manager");
999 delete master_manager
;
1000 master_manager
= NULL
;