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