Jack2  1.9.8
JackNetManager.cpp
1 /*
2 Copyright(C) 2008-2011 Romain Moret at Grame
3 
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.
8 
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.
13 
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.
17 */
18 
19 #include "JackNetManager.h"
20 #include "JackArgParser.h"
21 #include "JackServerGlobals.h"
22 #include "JackLockedEngine.h"
23 
24 using namespace std;
25 
26 namespace Jack
27 {
28 //JackNetMaster******************************************************************************************************
29 
30  JackNetMaster::JackNetMaster(JackNetSocket& socket, session_params_t& params, const char* multicast_ip)
31  : JackNetMasterInterface(params, socket, multicast_ip)
32  {
33  jack_log("JackNetMaster::JackNetMaster");
34 
35  //settings
36  fClientName = const_cast<char*>(fParams.fName);
37  fJackClient = NULL;
38  fSendTransportData.fState = -1;
39  fReturnTransportData.fState = -1;
40  fLastTransportState = -1;
41  int port_index;
42 
43  //jack audio ports
44  fAudioCapturePorts = new jack_port_t* [fParams.fSendAudioChannels];
45  for (port_index = 0; port_index < fParams.fSendAudioChannels; port_index++) {
46  fAudioCapturePorts[port_index] = NULL;
47  }
48 
49  fAudioPlaybackPorts = new jack_port_t* [fParams.fReturnAudioChannels];
50  for (port_index = 0; port_index < fParams.fReturnAudioChannels; port_index++) {
51  fAudioPlaybackPorts[port_index] = NULL;
52  }
53 
54  //jack midi ports
55  fMidiCapturePorts = new jack_port_t* [fParams.fSendMidiChannels];
56  for (port_index = 0; port_index < fParams.fSendMidiChannels; port_index++) {
57  fMidiCapturePorts[port_index] = NULL;
58  }
59 
60  fMidiPlaybackPorts = new jack_port_t* [fParams.fReturnMidiChannels];
61  for (port_index = 0; port_index < fParams.fReturnMidiChannels; port_index++) {
62  fMidiPlaybackPorts[port_index] = NULL;
63  }
64 
65  //monitor
66 #ifdef JACK_MONITOR
67  fPeriodUsecs = (int)(1000000.f * ((float) fParams.fPeriodSize / (float) fParams.fSampleRate));
68  string plot_name;
69  plot_name = string(fParams.fName);
70  plot_name += string("_master");
71  plot_name += string((fParams.fSlaveSyncMode) ? "_sync" : "_async");
72  plot_name += string("_latency");
73  fNetTimeMon = new JackGnuPlotMonitor<float>(128, 4, plot_name);
74  string net_time_mon_fields[] =
75  {
76  string("sync send"),
77  string("end of send"),
78  string("sync recv"),
79  string("end of cycle")
80  };
81  string net_time_mon_options[] =
82  {
83  string("set xlabel \"audio cycles\""),
84  string("set ylabel \"% of audio cycle\"")
85  };
86  fNetTimeMon->SetPlotFile(net_time_mon_options, 2, net_time_mon_fields, 4);
87 #endif
88  }
89 
90  JackNetMaster::~JackNetMaster()
91  {
92  jack_log("JackNetMaster::~JackNetMaster ID = %u", fParams.fID);
93 
94  if (fJackClient) {
95  jack_deactivate(fJackClient);
96  FreePorts();
97  jack_client_close(fJackClient);
98  }
99  delete[] fAudioCapturePorts;
100  delete[] fAudioPlaybackPorts;
101  delete[] fMidiCapturePorts;
102  delete[] fMidiPlaybackPorts;
103 #ifdef JACK_MONITOR
104  fNetTimeMon->Save();
105  delete fNetTimeMon;
106 #endif
107  }
108 //init--------------------------------------------------------------------------------
109  bool JackNetMaster::Init(bool auto_connect)
110  {
111  //network init
112  if (!JackNetMasterInterface::Init()) {
113  jack_error("JackNetMasterInterface::Init() error...");
114  return false;
115  }
116 
117  //set global parameters
118  if (!SetParams()) {
119  jack_error("SetParams error...");
120  return false;
121  }
122 
123  //jack client and process
124  jack_status_t status;
125  if ((fJackClient = jack_client_open(fClientName, JackNullOption, &status, NULL)) == NULL) {
126  jack_error("Can't open a new JACK client");
127  return false;
128  }
129 
130  if (jack_set_process_callback(fJackClient, SetProcess, this) < 0) {
131  goto fail;
132  }
133 
134  if (jack_set_buffer_size_callback(fJackClient, SetBufferSize, this) < 0) {
135  goto fail;
136  }
137 
138  if (AllocPorts() != 0) {
139  jack_error("Can't allocate JACK ports");
140  goto fail;
141  }
142 
143  //process can now run
144  fRunning = true;
145 
146  //finally activate jack client
147  if (jack_activate(fJackClient) != 0) {
148  jack_error("Can't activate JACK client");
149  goto fail;
150  }
151 
152  if (auto_connect) {
153  ConnectPorts();
154  }
155  jack_info("New NetMaster started");
156  return true;
157 
158  fail:
159  FreePorts();
160  jack_client_close(fJackClient);
161  fJackClient = NULL;
162  return false;
163  }
164 
165 //jack ports--------------------------------------------------------------------------
166  int JackNetMaster::AllocPorts()
167  {
168  int i;
169  char name[24];
170  jack_nframes_t port_latency = jack_get_buffer_size(fJackClient);
171  jack_latency_range_t range;
172 
173  jack_log("JackNetMaster::AllocPorts");
174 
175  //audio
176  for (i = 0; i < fParams.fSendAudioChannels; i++) {
177  snprintf(name, sizeof(name), "to_slave_%d", i+1);
178  if ((fAudioCapturePorts[i] = jack_port_register(fJackClient, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0)) == NULL)
179  return -1;
180  //port latency
181  range.min = range.max = 0;
182  jack_port_set_latency_range(fAudioCapturePorts[i], JackCaptureLatency, &range);
183  }
184 
185  for (i = 0; i < fParams.fReturnAudioChannels; i++) {
186  snprintf(name, sizeof(name), "from_slave_%d", i+1);
187  if ((fAudioPlaybackPorts[i] = jack_port_register(fJackClient, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput | JackPortIsTerminal, 0)) == NULL)
188  return -1;
189  //port latency
190  range.min = range.max = fParams.fNetworkLatency * port_latency + (fParams.fSlaveSyncMode) ? 0 : port_latency;
191  jack_port_set_latency_range(fAudioPlaybackPorts[i], JackPlaybackLatency, &range);
192  }
193 
194  //midi
195  for (i = 0; i < fParams.fSendMidiChannels; i++) {
196  snprintf(name, sizeof(name), "midi_to_slave_%d", i+1);
197  if ((fMidiCapturePorts[i] = jack_port_register(fJackClient, name, JACK_DEFAULT_MIDI_TYPE, JackPortIsInput | JackPortIsTerminal, 0)) == NULL)
198  return -1;
199  //port latency
200  range.min = range.max = 0;
201  jack_port_set_latency_range(fMidiCapturePorts[i], JackCaptureLatency, &range);
202  }
203 
204  for (i = 0; i < fParams.fReturnMidiChannels; i++) {
205  snprintf(name, sizeof(name), "midi_from_slave_%d", i+1);
206  if ((fMidiPlaybackPorts[i] = jack_port_register(fJackClient, name, JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput | JackPortIsTerminal, 0)) == NULL)
207  return -1;
208  //port latency
209  range.min = range.max = fParams.fNetworkLatency * port_latency + (fParams.fSlaveSyncMode) ? 0 : port_latency;
210  jack_port_set_latency_range(fMidiPlaybackPorts[i], JackPlaybackLatency, &range);
211  }
212  return 0;
213  }
214 
215  void JackNetMaster::ConnectPorts()
216  {
217  const char **ports;
218 
219  ports = jack_get_ports(fJackClient, NULL, NULL, JackPortIsPhysical | JackPortIsOutput);
220  if (ports != NULL) {
221  for (int i = 0; i < fParams.fSendAudioChannels && ports[i]; i++) {
222  jack_connect(fJackClient, ports[i], jack_port_name(fAudioCapturePorts[i]));
223  }
224  free(ports);
225  }
226 
227  ports = jack_get_ports(fJackClient, NULL, NULL, JackPortIsPhysical | JackPortIsInput);
228  if (ports != NULL) {
229  for (int i = 0; i < fParams.fReturnAudioChannels && ports[i]; i++) {
230  jack_connect(fJackClient, jack_port_name(fAudioPlaybackPorts[i]), ports[i]);
231  }
232  free(ports);
233  }
234  }
235 
236  void JackNetMaster::FreePorts()
237  {
238  jack_log("JackNetMaster::FreePorts ID = %u", fParams.fID);
239 
240  int port_index;
241  for (port_index = 0; port_index < fParams.fSendAudioChannels; port_index++) {
242  if (fAudioCapturePorts[port_index]) {
243  jack_port_unregister(fJackClient, fAudioCapturePorts[port_index]);
244  }
245  }
246  for (port_index = 0; port_index < fParams.fReturnAudioChannels; port_index++) {
247  if (fAudioPlaybackPorts[port_index]) {
248  jack_port_unregister(fJackClient, fAudioPlaybackPorts[port_index]);
249  }
250  }
251  for (port_index = 0; port_index < fParams.fSendMidiChannels; port_index++) {
252  if (fMidiCapturePorts[port_index]) {
253  jack_port_unregister(fJackClient, fMidiCapturePorts[port_index]);
254  }
255  }
256  for (port_index = 0; port_index < fParams.fReturnMidiChannels; port_index++) {
257  if (fMidiPlaybackPorts[port_index]) {
258  jack_port_unregister(fJackClient, fMidiPlaybackPorts[port_index]);
259  }
260  }
261  }
262 
263 //transport---------------------------------------------------------------------------
264  void JackNetMaster::EncodeTransportData()
265  {
266  //is there a new timebase master ?
267  //TODO : check if any timebase callback has been called (and if it's conditional or not) and set correct value...
268  fSendTransportData.fTimebaseMaster = NO_CHANGE;
269 
270  //update state and position
271  fSendTransportData.fState = static_cast<uint>(jack_transport_query(fJackClient, &fSendTransportData.fPosition));
272 
273  //is it a new state ?
274  fSendTransportData.fNewState = ((fSendTransportData.fState != fLastTransportState) && (fSendTransportData.fState != fReturnTransportData.fState));
275  if (fSendTransportData.fNewState) {
276  jack_info("Sending '%s' to '%s' frame = %ld", GetTransportState(fSendTransportData.fState), fParams.fName, fSendTransportData.fPosition.frame);
277  }
278  fLastTransportState = fSendTransportData.fState;
279  }
280 
281  void JackNetMaster::DecodeTransportData()
282  {
283  //is there timebase master change ?
284  if (fReturnTransportData.fTimebaseMaster != NO_CHANGE) {
285 
286  int timebase = 0;
287  switch (fReturnTransportData.fTimebaseMaster)
288  {
289  case RELEASE_TIMEBASEMASTER :
290  timebase = jack_release_timebase(fJackClient);
291  if (timebase < 0) {
292  jack_error("Can't release timebase master");
293  } else {
294  jack_info("'%s' isn't the timebase master anymore", fParams.fName);
295  }
296  break;
297 
298  case TIMEBASEMASTER :
299  timebase = jack_set_timebase_callback(fJackClient, 0, SetTimebaseCallback, this);
300  if (timebase < 0) {
301  jack_error("Can't set a new timebase master");
302  } else {
303  jack_info("'%s' is the new timebase master", fParams.fName);
304  }
305  break;
306 
307  case CONDITIONAL_TIMEBASEMASTER :
308  timebase = jack_set_timebase_callback(fJackClient, 1, SetTimebaseCallback, this);
309  if (timebase != EBUSY) {
310  if (timebase < 0)
311  jack_error("Can't set a new timebase master");
312  else
313  jack_info("'%s' is the new timebase master", fParams.fName);
314  }
315  break;
316  }
317  }
318 
319  //is the slave in a new transport state and is this state different from master's ?
320  if (fReturnTransportData.fNewState && (fReturnTransportData.fState != jack_transport_query(fJackClient, NULL))) {
321 
322  switch (fReturnTransportData.fState)
323  {
324  case JackTransportStopped :
325  jack_transport_stop(fJackClient);
326  jack_info("'%s' stops transport", fParams.fName);
327  break;
328 
329  case JackTransportStarting :
330  if (jack_transport_reposition(fJackClient, &fReturnTransportData.fPosition) == EINVAL)
331  jack_error("Can't set new position");
332  jack_transport_start(fJackClient);
333  jack_info("'%s' starts transport frame = %d", fParams.fName, fReturnTransportData.fPosition.frame);
334  break;
335 
336  case JackTransportNetStarting :
337  jack_info("'%s' is ready to roll...", fParams.fName);
338  break;
339 
340  case JackTransportRolling :
341  jack_info("'%s' is rolling", fParams.fName);
342  break;
343  }
344  }
345  }
346 
347  void JackNetMaster::SetTimebaseCallback(jack_transport_state_t state, jack_nframes_t nframes, jack_position_t* pos, int new_pos, void* arg)
348  {
349  static_cast<JackNetMaster*>(arg)->TimebaseCallback(pos);
350  }
351 
352  void JackNetMaster::TimebaseCallback(jack_position_t* pos)
353  {
354  pos->bar = fReturnTransportData.fPosition.bar;
355  pos->beat = fReturnTransportData.fPosition.beat;
356  pos->tick = fReturnTransportData.fPosition.tick;
357  pos->bar_start_tick = fReturnTransportData.fPosition.bar_start_tick;
358  pos->beats_per_bar = fReturnTransportData.fPosition.beats_per_bar;
359  pos->beat_type = fReturnTransportData.fPosition.beat_type;
360  pos->ticks_per_beat = fReturnTransportData.fPosition.ticks_per_beat;
361  pos->beats_per_minute = fReturnTransportData.fPosition.beats_per_minute;
362  }
363 
364 //sync--------------------------------------------------------------------------------
365 
366  bool JackNetMaster::IsSlaveReadyToRoll()
367  {
368  return (fReturnTransportData.fState == JackTransportNetStarting);
369  }
370 
371  int JackNetMaster::SetBufferSize(jack_nframes_t nframes, void* arg)
372  {
373  JackNetMaster* obj = static_cast<JackNetMaster*>(arg);
374  if (nframes != obj->fParams.fPeriodSize) {
375  jack_error("Cannot handle buffer size change, so JackNetMaster proxy will be removed...");
376  obj->Exit();
377  }
378  return 0;
379  }
380 
381 //process-----------------------------------------------------------------------------
382  int JackNetMaster::SetProcess(jack_nframes_t nframes, void* arg)
383  {
384  try {
385  return static_cast<JackNetMaster*>(arg)->Process();
386  } catch (JackNetException& e) {
387  return 0;
388  }
389  }
390 
391  int JackNetMaster::Process()
392  {
393  int res;
394 
395  if (!fRunning) {
396  return 0;
397  }
398 
399 #ifdef JACK_MONITOR
400  jack_time_t begin_time = GetMicroSeconds();
401  fNetTimeMon->New();
402 #endif
403 
404  //buffers
405  for (int midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
406  fNetMidiCaptureBuffer->SetBuffer(midi_port_index,
407  static_cast<JackMidiBuffer*>(jack_port_get_buffer(fMidiCapturePorts[midi_port_index],
408  fParams.fPeriodSize)));
409  }
410  for (int audio_port_index = 0; audio_port_index < fParams.fSendAudioChannels; audio_port_index++) {
411 
412  #ifdef OPTIMIZED_PROTOCOL
413  if (fNetAudioCaptureBuffer->GetConnected(audio_port_index)) {
414  // Port is connected on other side...
415  fNetAudioCaptureBuffer->SetBuffer(audio_port_index,
416  ((jack_port_connected(fAudioCapturePorts[audio_port_index]) > 0)
417  ? static_cast<sample_t*>(jack_port_get_buffer(fAudioCapturePorts[audio_port_index], fParams.fPeriodSize))
418  : NULL));
419  } else {
420  fNetAudioCaptureBuffer->SetBuffer(audio_port_index, NULL);
421  }
422  #else
423  fNetAudioCaptureBuffer->SetBuffer(audio_port_index,
424  static_cast<sample_t*>(jack_port_get_buffer(fAudioCapturePorts[audio_port_index],
425  fParams.fPeriodSize)));
426  #endif
427  // TODO
428  }
429 
430  for (int midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
431  fNetMidiPlaybackBuffer->SetBuffer(midi_port_index,
432  static_cast<JackMidiBuffer*>(jack_port_get_buffer(fMidiPlaybackPorts[midi_port_index],
433  fParams.fPeriodSize)));
434  }
435  for (int audio_port_index = 0; audio_port_index < fParams.fReturnAudioChannels; audio_port_index++) {
436 
437  #ifdef OPTIMIZED_PROTOCOL
438  sample_t* out = (jack_port_connected(fAudioPlaybackPorts[audio_port_index]) > 0)
439  ? static_cast<sample_t*>(jack_port_get_buffer(fAudioPlaybackPorts[audio_port_index], fParams.fPeriodSize))
440  : NULL;
441  if (out) {
442  memset(out, 0, sizeof(float) * fParams.fPeriodSize);
443  }
444  fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, out);
445  #else
446  sample_t* out = static_cast<sample_t*>(jack_port_get_buffer(fAudioPlaybackPorts[audio_port_index], fParams.fPeriodSize));
447  if (out) {
448  memset(out, 0, sizeof(float) * fParams.fPeriodSize);
449  }
450  fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, out)));
451  #endif
452  }
453 
454  if (IsSynched()) { // only send if connection is "synched"
455 
456  //encode the first packet
457  EncodeSyncPacket();
458 
459  if (SyncSend() == SOCKET_ERROR) {
460  return SOCKET_ERROR;
461  }
462 
463  #ifdef JACK_MONITOR
464  fNetTimeMon->Add((((float)(GetMicroSeconds() - begin_time)) / (float) fPeriodUsecs) * 100.f);
465  #endif
466 
467  //send data
468  if (DataSend() == SOCKET_ERROR) {
469  return SOCKET_ERROR;
470  }
471 
472  #ifdef JACK_MONITOR
473  fNetTimeMon->Add((((float)(GetMicroSeconds() - begin_time)) / (float) fPeriodUsecs) * 100.f);
474  #endif
475 
476  } else {
477  jack_error("Connection is not synched, skip cycle...");
478  }
479 
480  //receive sync
481  res = SyncRecv();
482  if ((res == 0) || (res == SOCKET_ERROR)) {
483  return res;
484  }
485 
486  /*
487  switch (SyncRecv()) {
488 
489  case 0:
490  jack_error("Connection is not yet synched, skip cycle...");
491  return 0;
492 
493  case SOCKET_ERROR:
494  jack_error("Connection is lost, quit master...");
495  //ask to the manager to properly remove the master
496  Exit();
497  //UGLY temporary way to be sure the thread does not call code possibly causing a deadlock in JackEngine.
498  ThreadExit();
499  break;
500 
501  default:
502  break;
503  }
504  */
505 
506 #ifdef JACK_MONITOR
507  fNetTimeMon->Add((((float)(GetMicroSeconds() - begin_time)) / (float) fPeriodUsecs) * 100.f);
508 #endif
509 
510  //decode sync
511  DecodeSyncPacket();
512 
513  //receive data
514  res = DataRecv();
515  if ((res == 0) || (res == SOCKET_ERROR)) {
516  return res;
517  } else if (res == NET_PACKET_ERROR) {
518  // Well not a real XRun...
519  JackServerGlobals::fInstance->GetEngine()->NotifyXRun(GetMicroSeconds(), 0);
520  }
521 
522  /*
523  switch (DataRecv()) {
524 
525  case 0:
526  jack_error("Connection is not yet synched, skip cycle...");
527  return 0;
528 
529  case SOCKET_ERROR:
530  jack_error("Connection is lost, quit master...");
531  //ask to the manager to properly remove the master
532  Exit();
533  //UGLY temporary way to be sure the thread does not call code possibly causing a deadlock in JackEngine.
534  ThreadExit();
535  break;
536 
537  default:
538  break;
539  }
540  */
541 
542 #ifdef JACK_MONITOR
543  fNetTimeMon->AddLast((((float)(GetMicroSeconds() - begin_time)) / (float) fPeriodUsecs) * 100.f);
544 #endif
545  return 0;
546  }
547 
548 //JackNetMasterManager***********************************************************************************************
549 
550  JackNetMasterManager::JackNetMasterManager(jack_client_t* client, const JSList* params) : fSocket()
551  {
552  jack_log("JackNetMasterManager::JackNetMasterManager");
553 
554  fManagerClient = client;
555  fManagerName = jack_get_client_name(fManagerClient);
556  fGlobalID = 0;
557  fRunning = true;
558  fAutoConnect = false;
559 
560  const JSList* node;
561  const jack_driver_param_t* param;
562 
563  // Possibly use env variable
564  const char* default_udp_port = getenv("JACK_NETJACK_PORT");
565  fSocket.SetPort((default_udp_port) ? atoi(default_udp_port) : DEFAULT_PORT);
566 
567  const char* default_multicast_ip = getenv("JACK_NETJACK_MULTICAST");
568  if (default_multicast_ip) {
569  strcpy(fMulticastIP, default_multicast_ip);
570  } else {
571  strcpy(fMulticastIP, DEFAULT_MULTICAST_IP);
572  }
573 
574  for (node = params; node; node = jack_slist_next(node)) {
575 
576  param = (const jack_driver_param_t*) node->data;
577  switch (param->character)
578  {
579  case 'a' :
580  if (strlen(param->value.str) < 32) {
581  strcpy(fMulticastIP, param->value.str);
582  } else {
583  jack_error("Can't use multicast address %s, using default %s", param->value.ui, DEFAULT_MULTICAST_IP);
584  }
585  break;
586 
587  case 'p':
588  fSocket.SetPort(param->value.ui);
589  break;
590 
591  case 'c':
592  fAutoConnect = param->value.i;
593  break;
594  }
595  }
596 
597  //set sync callback
598  jack_set_sync_callback(fManagerClient, SetSyncCallback, this);
599 
600  //activate the client (for sync callback)
601  if (jack_activate(fManagerClient) != 0) {
602  jack_error("Can't activate the NetManager client, transport disabled");
603  }
604 
605  //launch the manager thread
606  if (jack_client_create_thread(fManagerClient, &fManagerThread, 0, 0, NetManagerThread, this)) {
607  jack_error("Can't create the NetManager control thread");
608  }
609  }
610 
611  JackNetMasterManager::~JackNetMasterManager()
612  {
613  jack_log("JackNetMasterManager::~JackNetMasterManager");
614  jack_info("Exiting NetManager...");
615  fRunning = false;
616  jack_client_kill_thread(fManagerClient, fManagerThread);
617  master_list_t::iterator it;
618  for (it = fMasterList.begin(); it != fMasterList.end(); it++) {
619  delete(*it);
620  }
621  fSocket.Close();
622  SocketAPIEnd();
623  }
624 
625  int JackNetMasterManager::CountIO(int flags)
626  {
627  const char **ports;
628  int count = 0;
629  jack_port_t* port;
630 
631  ports = jack_get_ports(fManagerClient, NULL, NULL, flags);
632  if (ports != NULL) {
633  while (ports[count]
634  && (port = jack_port_by_name(fManagerClient, ports[count]))
635  && (strcmp(jack_port_type(port), JACK_DEFAULT_AUDIO_TYPE) == 0)) {
636  count++;
637  }
638  free(ports);
639  }
640  return count;
641  }
642 
643  int JackNetMasterManager::SetSyncCallback(jack_transport_state_t state, jack_position_t* pos, void* arg)
644  {
645  return static_cast<JackNetMasterManager*>(arg)->SyncCallback(state, pos);
646  }
647 
648  int JackNetMasterManager::SyncCallback(jack_transport_state_t state, jack_position_t* pos)
649  {
650  //check if each slave is ready to roll
651  int ret = 1;
652  master_list_it_t it;
653  for (it = fMasterList.begin(); it != fMasterList.end(); it++) {
654  if (!(*it)->IsSlaveReadyToRoll()) {
655  ret = 0;
656  }
657  }
658  jack_log("JackNetMasterManager::SyncCallback returns '%s'", (ret) ? "true" : "false");
659  return ret;
660  }
661 
662  void* JackNetMasterManager::NetManagerThread(void* arg)
663  {
664  JackNetMasterManager* master_manager = static_cast<JackNetMasterManager*>(arg);
665  jack_info("Starting Jack NetManager");
666  jack_info("Listening on '%s:%d'", master_manager->fMulticastIP, master_manager->fSocket.GetPort());
667  master_manager->Run();
668  return NULL;
669  }
670 
671  void JackNetMasterManager::Run()
672  {
673  jack_log("JackNetMasterManager::Run");
674  //utility variables
675  int attempt = 0;
676 
677  //data
678  session_params_t host_params;
679  int rx_bytes = 0;
680  JackNetMaster* net_master;
681 
682  //init socket API (win32)
683  if (SocketAPIInit() < 0) {
684  jack_error("Can't init Socket API, exiting...");
685  return;
686  }
687 
688  //socket
689  if (fSocket.NewSocket() == SOCKET_ERROR) {
690  jack_error("Can't create NetManager input socket : %s", StrError(NET_ERROR_CODE));
691  return;
692  }
693 
694  //bind the socket to the local port
695  if (fSocket.Bind() == SOCKET_ERROR) {
696  jack_error("Can't bind NetManager socket : %s", StrError(NET_ERROR_CODE));
697  fSocket.Close();
698  return;
699  }
700 
701  //join multicast group
702  if (fSocket.JoinMCastGroup(fMulticastIP) == SOCKET_ERROR) {
703  jack_error("Can't join multicast group : %s", StrError(NET_ERROR_CODE));
704  }
705 
706  //local loop
707  if (fSocket.SetLocalLoop() == SOCKET_ERROR) {
708  jack_error("Can't set local loop : %s", StrError(NET_ERROR_CODE));
709  }
710 
711  //set a timeout on the multicast receive (the thread can now be cancelled)
712  if (fSocket.SetTimeOut(MANAGER_INIT_TIMEOUT) == SOCKET_ERROR) {
713  jack_error("Can't set timeout : %s", StrError(NET_ERROR_CODE));
714  }
715 
716  //main loop, wait for data, deal with it and wait again
717  do
718  {
719  session_params_t net_params;
720  rx_bytes = fSocket.CatchHost(&net_params, sizeof(session_params_t), 0);
721  SessionParamsNToH(&net_params, &host_params);
722  if ((rx_bytes == SOCKET_ERROR) && (fSocket.GetError() != NET_NO_DATA)) {
723  jack_error("Error in receive : %s", StrError(NET_ERROR_CODE));
724  if (++attempt == 10) {
725  jack_error("Can't receive on the socket, exiting net manager");
726  return;
727  }
728  }
729 
730  if (rx_bytes == sizeof(session_params_t)) {
731  switch (GetPacketType (&host_params))
732  {
733  case SLAVE_AVAILABLE:
734  if ((net_master = InitMaster(host_params))) {
735  SessionParamsDisplay(&net_master->fParams);
736  } else {
737  jack_error("Can't init new NetMaster...");
738  }
739  jack_info("Waiting for a slave...");
740  break;
741  case KILL_MASTER:
742  if (KillMaster(&host_params)) {
743  jack_info("Waiting for a slave...");
744  }
745  break;
746  default:
747  break;
748  }
749  }
750  }
751  while (fRunning);
752  }
753 
754  JackNetMaster* JackNetMasterManager::InitMaster(session_params_t& params)
755  {
756  jack_log("JackNetMasterManager::InitMaster, Slave : %s", params.fName);
757 
758  //check MASTER <<==> SLAVE network protocol coherency
759  if (params.fProtocolVersion != MASTER_PROTOCOL) {
760  jack_error("Error : slave %s is running with a different protocol %d != %d", params.fName, params.fProtocolVersion, MASTER_PROTOCOL);
761  return NULL;
762  }
763 
764  //settings
765  fSocket.GetName(params.fMasterNetName);
766  params.fID = ++fGlobalID;
767  params.fSampleRate = jack_get_sample_rate(fManagerClient);
768  params.fPeriodSize = jack_get_buffer_size(fManagerClient);
769 
770  if (params.fSendAudioChannels == -1) {
771  params.fSendAudioChannels = CountIO(JackPortIsPhysical | JackPortIsOutput);
772  jack_info("Takes physical %d inputs for client", params.fSendAudioChannels);
773  }
774 
775  if (params.fReturnAudioChannels == -1) {
776  params.fReturnAudioChannels = CountIO(JackPortIsPhysical | JackPortIsInput);
777  jack_info("Takes physical %d outputs for client", params.fReturnAudioChannels);
778  }
779 
780  //create a new master and add it to the list
781  JackNetMaster* master = new JackNetMaster(fSocket, params, fMulticastIP);
782  if (master->Init(fAutoConnect)) {
783  fMasterList.push_back(master);
784  return master;
785  }
786  delete master;
787  return NULL;
788  }
789 
790  master_list_it_t JackNetMasterManager::FindMaster(uint32_t id)
791  {
792  jack_log("JackNetMasterManager::FindMaster ID = %u", id);
793 
794  master_list_it_t it;
795  for (it = fMasterList.begin(); it != fMasterList.end(); it++) {
796  if ((*it)->fParams.fID == id) {
797  return it;
798  }
799  }
800  return it;
801  }
802 
803  int JackNetMasterManager::KillMaster(session_params_t* params)
804  {
805  jack_log("JackNetMasterManager::KillMaster ID = %u", params->fID);
806 
807  master_list_it_t master = FindMaster(params->fID);
808  if (master != fMasterList.end()) {
809  fMasterList.erase(master);
810  delete *master;
811  return 1;
812  }
813  return 0;
814  }
815 }//namespace
816 
817 static Jack::JackNetMasterManager* master_manager = NULL;
818 
819 #ifdef __cplusplus
820 extern "C"
821 {
822 #endif
823 
824  SERVER_EXPORT jack_driver_desc_t* jack_get_descriptor()
825  {
826  jack_driver_desc_t * desc;
829 
830  desc = jack_driver_descriptor_construct("netmanager", JackDriverNone, "netjack multi-cast master component", &filler);
831 
832  strcpy(value.str, DEFAULT_MULTICAST_IP);
833  jack_driver_descriptor_add_parameter(desc, &filler, "multicast-ip", 'a', JackDriverParamString, &value, NULL, "Multicast Address", NULL);
834 
835  value.i = DEFAULT_PORT;
836  jack_driver_descriptor_add_parameter(desc, &filler, "udp-net-port", 'p', JackDriverParamInt, &value, NULL, "UDP port", NULL);
837 
838  value.i = false;
839  jack_driver_descriptor_add_parameter(desc, &filler, "auto-connect", 'c', JackDriverParamBool, &value, NULL, "Auto connect netmaster to system ports", NULL);
840 
841  return desc;
842  }
843 
844  SERVER_EXPORT int jack_internal_initialize(jack_client_t* jack_client, const JSList* params)
845  {
846  if (master_manager) {
847  jack_error("Master Manager already loaded");
848  return 1;
849  } else {
850  jack_log("Loading Master Manager");
851  master_manager = new Jack::JackNetMasterManager(jack_client, params);
852  return (master_manager) ? 0 : 1;
853  }
854  }
855 
856  SERVER_EXPORT int jack_initialize(jack_client_t* jack_client, const char* load_init)
857  {
858  JSList* params = NULL;
859  bool parse_params = true;
860  int res = 1;
861  jack_driver_desc_t* desc = jack_get_descriptor();
862 
863  Jack::JackArgParser parser(load_init);
864  if (parser.GetArgc() > 0) {
865  parse_params = parser.ParseParams(desc, &params);
866  }
867 
868  if (parse_params) {
869  res = jack_internal_initialize(jack_client, params);
870  parser.FreeParams(params);
871  }
872  return res;
873  }
874 
875  SERVER_EXPORT void jack_finish(void* arg)
876  {
877  if (master_manager) {
878  jack_log ("Unloading Master Manager");
879  delete master_manager;
880  master_manager = NULL;
881  }
882  }
883 
884 #ifdef __cplusplus
885 }
886 #endif