Fix build under mixed mode
[jack2.git] / common / JackNetManager.cpp
blob250c123728816fb492b1491381f1ddaf27ffdea0
1 /*
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"
23 #include "thread.h"
25 using namespace std;
27 namespace Jack
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");
36 //settings
37 fName = const_cast<char*>(fParams.fName);
38 fClient = NULL;
39 fSendTransportData.fState = -1;
40 fReturnTransportData.fState = -1;
41 fLastTransportState = -1;
42 int port_index;
44 //jack audio ports
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;
55 //jack midi ports
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;
66 //monitor
67 #ifdef JACK_MONITOR
68 fPeriodUsecs = (int)(1000000.f * ((float) fParams.fPeriodSize / (float) fParams.fSampleRate));
69 string plot_name;
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[] =
77 string("sync send"),
78 string("end of send"),
79 string("sync recv"),
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);
88 #endif
91 JackNetMaster::~JackNetMaster()
93 jack_log("JackNetMaster::~JackNetMaster ID = %u", fParams.fID);
95 if (fClient) {
96 jack_deactivate(fClient);
97 FreePorts();
98 jack_client_close(fClient);
100 delete[] fAudioCapturePorts;
101 delete[] fAudioPlaybackPorts;
102 delete[] fMidiCapturePorts;
103 delete[] fMidiPlaybackPorts;
104 #ifdef JACK_MONITOR
105 fNetTimeMon->Save();
106 delete fNetTimeMon;
107 #endif
109 //init--------------------------------------------------------------------------------
110 bool JackNetMaster::Init(bool auto_connect)
112 //network init
113 if (!JackNetMasterInterface::Init()) {
114 jack_error("JackNetMasterInterface::Init() error...");
115 return false;
118 //set global parameters
119 if (!SetParams()) {
120 jack_error("SetParams error...");
121 return false;
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");
128 return false;
131 if (jack_set_process_callback(fClient, SetProcess, this) < 0) {
132 goto fail;
135 if (jack_set_buffer_size_callback(fClient, SetBufferSize, this) < 0) {
136 goto fail;
139 if (jack_set_sample_rate_callback(fClient, SetSampleRate, this) < 0) {
140 goto fail;
143 if (jack_set_latency_callback(fClient, LatencyCallback, this) < 0) {
144 goto fail;
148 if (jack_set_port_connect_callback(fClient, SetConnectCallback, this) < 0) {
149 goto fail;
153 if (AllocPorts() != 0) {
154 jack_error("Can't allocate JACK ports");
155 goto fail;
158 //process can now run
159 fRunning = true;
161 //finally activate jack client
162 if (jack_activate(fClient) != 0) {
163 jack_error("Can't activate JACK client");
164 goto fail;
167 if (auto_connect) {
168 ConnectPorts();
170 jack_info("New NetMaster started");
171 return true;
173 fail:
174 FreePorts();
175 jack_client_close(fClient);
176 fClient = NULL;
177 return false;
180 //jack ports--------------------------------------------------------------------------
181 int JackNetMaster::AllocPorts()
183 int i;
184 char name[32];
185 jack_log("JackNetMaster::AllocPorts");
187 //audio
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) {
191 return -1;
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) {
198 return -1;
202 //midi
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) {
206 return -1;
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) {
213 return -1;
216 return 0;
219 void JackNetMaster::ConnectPorts()
221 const char** ports = jack_get_ports(fClient, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortIsPhysical | JackPortIsOutput);
222 if (ports != NULL) {
223 for (int i = 0; i < fParams.fSendAudioChannels && ports[i]; i++) {
224 jack_connect(fClient, ports[i], jack_port_name(fAudioCapturePorts[i]));
226 jack_free(ports);
229 ports = jack_get_ports(fClient, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortIsPhysical | JackPortIsInput);
230 if (ports != NULL) {
231 for (int i = 0; i < fParams.fReturnAudioChannels && ports[i]; i++) {
232 jack_connect(fClient, jack_port_name(fAudioPlaybackPorts[i]), ports[i]);
234 jack_free(ports);
238 void JackNetMaster::FreePorts()
240 jack_log("JackNetMaster::FreePorts ID = %u", fParams.fID);
242 int port_index;
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) {
288 int timebase = 0;
289 switch (fReturnTransportData.fTimebaseMaster)
291 case RELEASE_TIMEBASEMASTER :
292 timebase = jack_release_timebase(fClient);
293 if (timebase < 0) {
294 jack_error("Can't release timebase master");
295 } else {
296 jack_info("'%s' isn't the timebase master anymore", fParams.fName);
298 break;
300 case TIMEBASEMASTER :
301 timebase = jack_set_timebase_callback(fClient, 0, SetTimebaseCallback, this);
302 if (timebase < 0) {
303 jack_error("Can't set a new timebase master");
304 } else {
305 jack_info("'%s' is the new timebase master", fParams.fName);
307 break;
309 case CONDITIONAL_TIMEBASEMASTER :
310 timebase = jack_set_timebase_callback(fClient, 1, SetTimebaseCallback, this);
311 if (timebase != EBUSY) {
312 if (timebase < 0)
313 jack_error("Can't set a new timebase master");
314 else
315 jack_info("'%s' is the new timebase master", fParams.fName);
317 break;
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);
329 break;
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);
336 break;
338 case JackTransportNetStarting :
339 jack_info("'%s' is ready to roll...", fParams.fName);
340 break;
342 case JackTransportRolling :
343 jack_info("'%s' is rolling", fParams.fName);
344 break;
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...");
378 obj->Exit();
380 return 0;
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...");
388 obj->Exit();
390 return 0;
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;
399 //audio
400 for (int i = 0; i < obj->fParams.fSendAudioChannels; i++) {
401 //port latency
402 range.min = range.max = float(obj->fParams.fNetworkLatency * port_latency) / 2.f;
403 jack_port_set_latency_range(obj->fAudioCapturePorts[i], JackPlaybackLatency, &range);
406 //audio
407 for (int i = 0; i < obj->fParams.fReturnAudioChannels; i++) {
408 //port latency
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);
413 //midi
414 for (int i = 0; i < obj->fParams.fSendMidiChannels; i++) {
415 //port latency
416 range.min = range.max = float(obj->fParams.fNetworkLatency * port_latency) / 2.f;
417 jack_port_set_latency_range(obj->fMidiCapturePorts[i], JackPlaybackLatency, &range);
420 //midi
421 for (int i = 0; i < obj->fParams.fReturnMidiChannels; i++) {
422 //port latency
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)
431 try {
432 return static_cast<JackNetMaster*>(arg)->Process();
433 } catch (JackNetException& e) {
434 return 0;
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);
446 if (connect) {
447 jack_connect(fClient, jack_port_name(jack_port_by_id(fClient, a)), "system:playback_1");
451 int JackNetMaster::Process()
453 if (!fRunning) {
454 return 0;
457 #ifdef JACK_MONITOR
458 jack_time_t begin_time = GetMicroSeconds();
459 fNetTimeMon->New();
460 #endif
462 //buffers
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))
476 : NULL));
477 } else {
478 fNetAudioCaptureBuffer->SetBuffer(audio_port_index, NULL);
480 #else
481 fNetAudioCaptureBuffer->SetBuffer(audio_port_index,
482 static_cast<sample_t*>(jack_port_get_buffer(fAudioCapturePorts[audio_port_index],
483 fParams.fPeriodSize)));
484 #endif
485 // TODO
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))
498 : NULL;
499 if (out) {
500 memset(out, 0, sizeof(float) * fParams.fPeriodSize);
502 fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, out);
503 #else
504 sample_t* out = static_cast<sample_t*>(jack_port_get_buffer(fAudioPlaybackPorts[audio_port_index], fParams.fPeriodSize));
505 if (out) {
506 memset(out, 0, sizeof(float) * fParams.fPeriodSize);
508 fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, out)));
509 #endif
512 // encode the first packet
513 EncodeSyncPacket();
515 if (SyncSend() == SOCKET_ERROR) {
516 return SOCKET_ERROR;
519 #ifdef JACK_MONITOR
520 fNetTimeMon->Add((((float)(GetMicroSeconds() - begin_time)) / (float) fPeriodUsecs) * 100.f);
521 #endif
523 // send data
524 if (DataSend() == SOCKET_ERROR) {
525 return SOCKET_ERROR;
528 #ifdef JACK_MONITOR
529 fNetTimeMon->Add((((float)(GetMicroSeconds() - begin_time)) / (float) fPeriodUsecs) * 100.f);
530 #endif
532 // receive sync
533 int res = SyncRecv();
534 switch (res) {
536 case NET_SYNCHING:
537 case SOCKET_ERROR:
538 return res;
540 case SYNC_PACKET_ERROR:
541 // Since sync packet is incorrect, don't decode it and continue with data
542 break;
544 default:
545 // Decode sync
546 int unused_frames;
547 DecodeSyncPacket(unused_frames);
548 break;
551 #ifdef JACK_MONITOR
552 fNetTimeMon->Add((((float)(GetMicroSeconds() - begin_time)) / (float) fPeriodUsecs) * 100.f);
553 #endif
555 // receive data
556 res = DataRecv();
557 switch (res) {
559 case 0:
560 case SOCKET_ERROR:
561 return res;
563 case DATA_PACKET_ERROR:
564 // Well not a real XRun...
565 JackServerGlobals::fInstance->GetEngine()->NotifyClientXRun(ALL_CLIENTS);
566 break;
569 #ifdef JACK_MONITOR
570 fNetTimeMon->AddLast((((float)(GetMicroSeconds() - begin_time)) / (float) fPeriodUsecs) * 100.f);
571 #endif
572 return 0;
575 void JackNetMaster::SaveConnections(connections_list_t& connections)
577 // Audio
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);
600 // MIDI
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");
640 fClient = client;
641 fName = jack_get_client_name(fClient);
642 fGlobalID = 0;
643 fRunning = true;
644 fAutoConnect = false;
645 fAutoSave = false;
647 const JSList* node;
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);
659 } else {
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) {
667 case 'a' :
668 if (strlen(param->value.str) < 32) {
669 strcpy(fMulticastIP, param->value.str);
670 } else {
671 jack_error("Can't use multicast address %s, using default %s", param->value.ui, DEFAULT_MULTICAST_IP);
673 break;
675 case 'p':
676 fSocket.SetPort(param->value.ui);
677 break;
679 case 'c':
680 fAutoConnect = true;
681 break;
683 case 's':
684 fAutoSave = true;
685 break;
689 //set sync callback
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");
706 ShutDown();
709 int JackNetMasterManager::CountIO(const char* type, int flags)
711 int count = 0;
712 const char** ports = jack_get_ports(fClient, NULL, type, flags);
713 if (ports != NULL) {
714 while (ports[count]) { count++; }
715 jack_free(ports);
717 return count;
720 void JackNetMasterManager::SetShutDown(void* arg)
722 static_cast<JackNetMasterManager*>(arg)->ShutDown();
725 void JackNetMasterManager::ShutDown()
727 jack_log("JackNetMasterManager::ShutDown");
728 if (fRunning) {
729 jack_client_kill_thread(fClient, fThread);
730 fRunning = false;
732 master_list_t::iterator it;
733 for (it = fMasterList.begin(); it != fMasterList.end(); it++) {
734 delete (*it);
736 fMasterList.clear();
737 fSocket.Close();
738 SocketAPIEnd();
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
749 int res = 1;
750 master_list_it_t it;
751 for (it = fMasterList.begin(); it != fMasterList.end(); it++) {
752 if (!(*it)->IsSlaveReadyToRoll()) {
753 res = 0;
756 jack_log("JackNetMasterManager::SyncCallback returns '%s'", (res) ? "true" : "false");
757 return res;
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();
766 return NULL;
769 void JackNetMasterManager::Run()
771 jack_log("JackNetMasterManager::Run");
772 //utility variables
773 int attempt = 0;
775 //data
776 session_params_t host_params;
777 int rx_bytes = 0;
778 JackNetMaster* net_master;
780 //init socket API (win32)
781 if (SocketAPIInit() < 0) {
782 jack_error("Can't init Socket API, exiting...");
783 return;
786 //socket
787 if (fSocket.NewSocket() == SOCKET_ERROR) {
788 jack_error("Can't create NetManager input socket : %s", StrError(NET_ERROR_CODE));
789 return;
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));
795 fSocket.Close();
796 return;
799 //join multicast group
800 if (fSocket.JoinMCastGroup(fMulticastIP) == SOCKET_ERROR) {
801 jack_error("Can't join multicast group : %s", StrError(NET_ERROR_CODE));
804 //local loop
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");
825 return;
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);
835 } else {
836 jack_error("Can't init new NetMaster...");
838 jack_info("Waiting for a slave...");
839 break;
840 case KILL_MASTER:
841 if (KillMaster(&host_params)) {
842 jack_info("Waiting for a slave...");
844 break;
845 default:
846 break;
850 while (fRunning);
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);
860 return NULL;
863 //settings
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]);
896 return master;
897 } else {
898 delete master;
899 return NULL;
903 master_list_it_t JackNetMasterManager::FindMaster(uint32_t id)
905 jack_log("JackNetMasterManager::FindMaster ID = %u", id);
907 master_list_it_t it;
908 for (it = fMasterList.begin(); it != fMasterList.end(); it++) {
909 if ((*it)->fParams.fID == id) {
910 return it;
913 return it;
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()) {
922 if (fAutoSave) {
923 fMasterConnectionList[params->fName].clear();
924 (*master_it)->SaveConnections(fMasterConnectionList[params->fName]);
926 fMasterList.erase(master_it);
927 delete (*master_it);
928 return 1;
930 return 0;
932 }//namespace
934 static Jack::JackNetMasterManager* master_manager = NULL;
936 #ifdef __cplusplus
937 extern "C"
939 #endif
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);
955 value.i = false;
956 jack_driver_descriptor_add_parameter(desc, &filler, "auto-connect", 'c', JackDriverParamBool, &value, NULL, "Auto connect netmaster to system ports", NULL);
958 value.i = false;
959 jack_driver_descriptor_add_parameter(desc, &filler, "auto-save", 's', JackDriverParamBool, &value, NULL, "Save/restore netmaster connection state when restarted", NULL);
961 return desc;
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");
968 return 1;
969 } else {
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;
980 int res = 1;
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, &params);
988 if (parse_params) {
989 res = jack_internal_initialize(jack_client, params);
990 parser.FreeParams(params);
992 return res;
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;
1004 #ifdef __cplusplus
1006 #endif