Jack2  1.9.8
JackNetDriver.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 "JackNetDriver.h"
20 #include "JackEngineControl.h"
21 #include "JackLockedEngine.h"
22 #include "JackWaitThreadedDriver.h"
23 
24 using namespace std;
25 
26 namespace Jack
27 {
28  JackNetDriver::JackNetDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table,
29  const char* ip, int udp_port, int mtu, int midi_input_ports, int midi_output_ports,
30  char* net_name, uint transport_sync, int network_latency, int celt_encoding)
31  : JackWaiterDriver(name, alias, engine, table), JackNetSlaveInterface(ip, udp_port)
32  {
33  jack_log("JackNetDriver::JackNetDriver ip %s, port %d", ip, udp_port);
34 
35  // Use the hostname if no name parameter was given
36  if (strcmp(net_name, "") == 0) {
37  GetHostName(net_name, JACK_CLIENT_NAME_SIZE);
38  }
39 
40  fParams.fMtu = mtu;
41  fParams.fSendMidiChannels = midi_input_ports;
42  fParams.fReturnMidiChannels = midi_output_ports;
43  if (celt_encoding > 0) {
44  fParams.fSampleEncoder = JackCeltEncoder;
45  fParams.fKBps = celt_encoding;
46  } else {
47  fParams.fSampleEncoder = JackFloatEncoder;
48  //fParams.fSampleEncoder = JackIntEncoder;
49  }
50  strcpy(fParams.fName, net_name);
51  fSocket.GetName(fParams.fSlaveNetName);
52  fParams.fTransportSync = transport_sync;
53  fParams.fNetworkLatency = network_latency;
54  fSendTransportData.fState = -1;
55  fReturnTransportData.fState = -1;
56  fLastTransportState = -1;
57  fLastTimebaseMaster = -1;
58  fMidiCapturePortList = NULL;
59  fMidiPlaybackPortList = NULL;
60 #ifdef JACK_MONITOR
61  fNetTimeMon = NULL;
62  fRcvSyncUst = 0;
63 #endif
64  }
65 
66  JackNetDriver::~JackNetDriver()
67  {
68  delete[] fMidiCapturePortList;
69  delete[] fMidiPlaybackPortList;
70 #ifdef JACK_MONITOR
71  delete fNetTimeMon;
72 #endif
73  }
74 
75 //open, close, attach and detach------------------------------------------------------
76 
77  int JackNetDriver::Close()
78  {
79 #ifdef JACK_MONITOR
80  if (fNetTimeMon) {
81  fNetTimeMon->Save();
82  }
83 #endif
84  FreeAll();
85  return JackWaiterDriver::Close();
86  }
87 
88  // Attach and Detach are defined as empty methods: port allocation is done when driver actually start (that is in Init)
89  int JackNetDriver::Attach()
90  {
91  return 0;
92  }
93 
94  int JackNetDriver::Detach()
95  {
96  return 0;
97  }
98 
99 //init and restart--------------------------------------------------------------------
100  /*
101  JackNetDriver is wrapped in a JackWaitThreadedDriver decorator that behaves
102  as a "dummy driver, until Init method returns.
103  */
104 
105  bool JackNetDriver::Initialize()
106  {
107  jack_log("JackNetDriver::Initialize");
108  SaveConnections();
109  FreePorts();
110 
111  // New loading, but existing socket, restart the driver
112  if (fSocket.IsSocket()) {
113  jack_info("Restarting driver...");
114  FreeAll();
115  }
116 
117  // Set the parameters to send
118  fParams.fSendAudioChannels = fCaptureChannels;
119  fParams.fReturnAudioChannels = fPlaybackChannels;
120  fParams.fSlaveSyncMode = fEngineControl->fSyncMode;
121 
122  // Display some additional infos
123  jack_info("NetDriver started in %s mode %s Master's transport sync.",
124  (fParams.fSlaveSyncMode) ? "sync" : "async", (fParams.fTransportSync) ? "with" : "without");
125 
126  // Init network
127  if (!JackNetSlaveInterface::Init()) {
128  jack_error("Starting network fails...");
129  return false;
130  }
131 
132  // Set global parameters
133  if (!SetParams()) {
134  jack_error("SetParams error...");
135  return false;
136  }
137 
138  // If -1 at connection time, in/out channels count is sent by the master
139  fCaptureChannels = fParams.fSendAudioChannels;
140  fPlaybackChannels = fParams.fReturnAudioChannels;
141 
142  // Allocate midi ports lists
143  fMidiCapturePortList = new jack_port_id_t [fParams.fSendMidiChannels];
144  fMidiPlaybackPortList = new jack_port_id_t [fParams.fReturnMidiChannels];
145 
146  assert(fMidiCapturePortList);
147  assert(fMidiPlaybackPortList);
148 
149  for (int midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
150  fMidiCapturePortList[midi_port_index] = 0;
151  }
152  for (int midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
153  fMidiPlaybackPortList[midi_port_index] = 0;
154  }
155 
156  // Register jack ports
157  if (AllocPorts() != 0) {
158  jack_error("Can't allocate ports.");
159  return false;
160  }
161 
162  // Init done, display parameters
163  SessionParamsDisplay(&fParams);
164 
165  // Monitor
166 #ifdef JACK_MONITOR
167  string plot_name;
168  // NetTimeMon
169  plot_name = string(fParams.fName);
170  plot_name += string("_slave");
171  plot_name += (fEngineControl->fSyncMode) ? string("_sync") : string("_async");
172  plot_name += string("_latency");
173  fNetTimeMon = new JackGnuPlotMonitor<float>(128, 5, plot_name);
174  string net_time_mon_fields[] =
175  {
176  string("sync decoded"),
177  string("end of read"),
178  string("start of write"),
179  string("sync send"),
180  string("end of write")
181  };
182  string net_time_mon_options[] =
183  {
184  string("set xlabel \"audio cycles\""),
185  string("set ylabel \"% of audio cycle\"")
186  };
187  fNetTimeMon->SetPlotFile(net_time_mon_options, 2, net_time_mon_fields, 5);
188 #endif
189  // Driver parametering
190  JackTimedDriver::SetBufferSize(fParams.fPeriodSize);
191  JackTimedDriver::SetSampleRate(fParams.fSampleRate);
192 
193  JackDriver::NotifyBufferSize(fParams.fPeriodSize);
194  JackDriver::NotifySampleRate(fParams.fSampleRate);
195 
196  // Transport engine parametering
197  fEngineControl->fTransport.SetNetworkSync(fParams.fTransportSync);
198 
199  RestoreConnections();
200  return true;
201  }
202 
203  void JackNetDriver::FreeAll()
204  {
205  FreePorts();
206 
207  delete[] fTxBuffer;
208  delete[] fRxBuffer;
209  delete fNetAudioCaptureBuffer;
210  delete fNetAudioPlaybackBuffer;
211  delete fNetMidiCaptureBuffer;
212  delete fNetMidiPlaybackBuffer;
213  delete[] fMidiCapturePortList;
214  delete[] fMidiPlaybackPortList;
215 
216  fTxBuffer = NULL;
217  fRxBuffer = NULL;
218  fNetAudioCaptureBuffer = NULL;
219  fNetAudioPlaybackBuffer = NULL;
220  fNetMidiCaptureBuffer = NULL;
221  fNetMidiPlaybackBuffer = NULL;
222  fMidiCapturePortList = NULL;
223  fMidiPlaybackPortList = NULL;
224 
225 #ifdef JACK_MONITOR
226  delete fNetTimeMon;
227  fNetTimeMon = NULL;
228 #endif
229  }
230 
231 //jack ports and buffers--------------------------------------------------------------
232  int JackNetDriver::AllocPorts()
233  {
234  jack_log("JackNetDriver::AllocPorts fBufferSize = %ld fSampleRate = %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate);
235 
236  /*
237  fNetAudioCaptureBuffer fNetAudioPlaybackBuffer
238  fSendAudioChannels fReturnAudioChannels
239 
240  fCapturePortList fPlaybackPortList
241  fCaptureChannels ==> SLAVE ==> fPlaybackChannels
242  "capture_" "playback_"
243  */
244 
245  JackPort* port;
246  jack_port_id_t port_index;
247  char name[REAL_JACK_PORT_NAME_SIZE];
248  char alias[REAL_JACK_PORT_NAME_SIZE];
249  int audio_port_index;
250  int midi_port_index;
251  jack_latency_range_t range;
252 
253  //audio
254  for (audio_port_index = 0; audio_port_index < fCaptureChannels; audio_port_index++) {
255  snprintf(alias, sizeof(alias), "%s:%s:out%d", fAliasName, fCaptureDriverName, audio_port_index + 1);
256  snprintf(name, sizeof(name), "%s:capture_%d", fClientControl.fName, audio_port_index + 1);
257  if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE,
258  CaptureDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) {
259  jack_error("driver: cannot register port for %s", name);
260  return -1;
261  }
262 
263  //port latency
264  port = fGraphManager->GetPort(port_index);
265  port->SetAlias(alias);
266  range.min = range.max = fEngineControl->fBufferSize;
267  port->SetLatencyRange(JackCaptureLatency, &range);
268  fCapturePortList[audio_port_index] = port_index;
269  jack_log("JackNetDriver::AllocPorts() fCapturePortList[%d] audio_port_index = %ld fPortLatency = %ld", audio_port_index, port_index, port->GetLatency());
270  }
271 
272  for (audio_port_index = 0; audio_port_index < fPlaybackChannels; audio_port_index++) {
273  snprintf(alias, sizeof(alias), "%s:%s:in%d", fAliasName, fPlaybackDriverName, audio_port_index + 1);
274  snprintf(name, sizeof(name), "%s:playback_%d",fClientControl.fName, audio_port_index + 1);
275  if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE,
276  PlaybackDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) {
277  jack_error("driver: cannot register port for %s", name);
278  return -1;
279  }
280 
281  //port latency
282  port = fGraphManager->GetPort(port_index);
283  port->SetAlias(alias);
284  range.min = range.max = (fParams.fNetworkLatency * fEngineControl->fBufferSize + (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize);
285  port->SetLatencyRange(JackPlaybackLatency, &range);
286  fPlaybackPortList[audio_port_index] = port_index;
287  jack_log("JackNetDriver::AllocPorts() fPlaybackPortList[%d] audio_port_index = %ld fPortLatency = %ld", audio_port_index, port_index, port->GetLatency());
288  }
289 
290  //midi
291  for (midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
292  snprintf(alias, sizeof(alias), "%s:%s:out%d", fAliasName, fCaptureDriverName, midi_port_index + 1);
293  snprintf(name, sizeof (name), "%s:midi_capture_%d", fClientControl.fName, midi_port_index + 1);
294  if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_MIDI_TYPE,
295  CaptureDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) {
296  jack_error("driver: cannot register port for %s", name);
297  return -1;
298  }
299 
300  //port latency
301  port = fGraphManager->GetPort(port_index);
302  range.min = range.max = fEngineControl->fBufferSize;
303  port->SetLatencyRange(JackCaptureLatency, &range);
304  fMidiCapturePortList[midi_port_index] = port_index;
305  jack_log("JackNetDriver::AllocPorts() fMidiCapturePortList[%d] midi_port_index = %ld fPortLatency = %ld", midi_port_index, port_index, port->GetLatency());
306  }
307 
308  for (midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
309  snprintf(alias, sizeof(alias), "%s:%s:in%d", fAliasName, fPlaybackDriverName, midi_port_index + 1);
310  snprintf(name, sizeof(name), "%s:midi_playback_%d", fClientControl.fName, midi_port_index + 1);
311  if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_MIDI_TYPE,
312  PlaybackDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) {
313  jack_error("driver: cannot register port for %s", name);
314  return -1;
315  }
316 
317  //port latency
318  port = fGraphManager->GetPort(port_index);
319  range.min = range.max = (fParams.fNetworkLatency * fEngineControl->fBufferSize + (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize);
320  port->SetLatencyRange(JackPlaybackLatency, &range);
321  fMidiPlaybackPortList[midi_port_index] = port_index;
322  jack_log("JackNetDriver::AllocPorts() fMidiPlaybackPortList[%d] midi_port_index = %ld fPortLatency = %ld", midi_port_index, port_index, port->GetLatency());
323  }
324 
325  return 0;
326  }
327 
328  int JackNetDriver::FreePorts()
329  {
330  jack_log("JackNetDriver::FreePorts");
331 
332  for (int audio_port_index = 0; audio_port_index < fCaptureChannels; audio_port_index++) {
333  if (fCapturePortList[audio_port_index] > 0) {
334  fEngine->PortUnRegister(fClientControl.fRefNum, fCapturePortList[audio_port_index]);
335  fCapturePortList[audio_port_index] = 0;
336  }
337  }
338 
339  for (int audio_port_index = 0; audio_port_index < fPlaybackChannels; audio_port_index++) {
340  if (fPlaybackPortList[audio_port_index] > 0) {
341  fEngine->PortUnRegister(fClientControl.fRefNum, fPlaybackPortList[audio_port_index]);
342  fPlaybackPortList[audio_port_index] = 0;
343  }
344  }
345 
346  for (int midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
347  if (fMidiCapturePortList && fMidiCapturePortList[midi_port_index] > 0) {
348  fGraphManager->ReleasePort(fClientControl.fRefNum, fMidiCapturePortList[midi_port_index]);
349  fMidiCapturePortList[midi_port_index] = 0;
350  }
351  }
352 
353  for (int midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
354  if (fMidiPlaybackPortList && fMidiPlaybackPortList[midi_port_index] > 0) {
355  fEngine->PortUnRegister(fClientControl.fRefNum, fMidiPlaybackPortList[midi_port_index]);
356  fMidiPlaybackPortList[midi_port_index] = 0;
357  }
358  }
359  return 0;
360  }
361 
362  void JackNetDriver::SaveConnections()
363  {
364  JackDriver::SaveConnections();
365  const char** connections;
366 
367  for (int i = 0; i < fParams.fSendMidiChannels; ++i) {
368  if (fCapturePortList[i] && (connections = fGraphManager->GetConnections(fMidiCapturePortList[i])) != 0) {
369  for (int j = 0; connections[j]; j++) {
370  fConnections.push_back(make_pair(fGraphManager->GetPort(fMidiCapturePortList[i])->GetName(), connections[j]));
371  }
372  free(connections);
373  }
374  }
375 
376  for (int i = 0; i < fParams.fReturnMidiChannels; ++i) {
377  if (fPlaybackPortList[i] && (connections = fGraphManager->GetConnections(fMidiPlaybackPortList[i])) != 0) {
378  for (int j = 0; connections[j]; j++) {
379  fConnections.push_back(make_pair(connections[j], fGraphManager->GetPort(fMidiPlaybackPortList[i])->GetName()));
380  }
381  free(connections);
382  }
383  }
384  }
385 
386  JackMidiBuffer* JackNetDriver::GetMidiInputBuffer(int port_index)
387  {
388  return static_cast<JackMidiBuffer*>(fGraphManager->GetBuffer(fMidiCapturePortList[port_index], fEngineControl->fBufferSize));
389  }
390 
391  JackMidiBuffer* JackNetDriver::GetMidiOutputBuffer(int port_index)
392  {
393  return static_cast<JackMidiBuffer*>(fGraphManager->GetBuffer(fMidiPlaybackPortList[port_index], fEngineControl->fBufferSize));
394  }
395 
396 //transport---------------------------------------------------------------------------
397  void JackNetDriver::DecodeTransportData()
398  {
399  //is there a new timebase master on the net master ?
400  // - release timebase master only if it's a non-conditional request
401  // - no change or no request : don't do anything
402  // - conditional request : don't change anything too, the master will know if this slave is actually the timebase master
403  int refnum;
404  bool conditional;
405  if (fSendTransportData.fTimebaseMaster == TIMEBASEMASTER) {
406  fEngineControl->fTransport.GetTimebaseMaster(refnum, conditional);
407  if (refnum != -1) {
408  fEngineControl->fTransport.ResetTimebase(refnum);
409  }
410  jack_info("The NetMaster is now the new timebase master.");
411  }
412 
413  //is there a transport state change to handle ?
414  if (fSendTransportData.fNewState &&(fSendTransportData.fState != fEngineControl->fTransport.GetState())) {
415 
416  switch (fSendTransportData.fState)
417  {
418  case JackTransportStopped :
419  fEngineControl->fTransport.SetCommand(TransportCommandStop);
420  jack_info("Master stops transport.");
421  break;
422 
423  case JackTransportStarting :
424  fEngineControl->fTransport.RequestNewPos(&fSendTransportData.fPosition);
425  fEngineControl->fTransport.SetCommand(TransportCommandStart);
426  jack_info("Master starts transport frame = %d", fSendTransportData.fPosition.frame);
427  break;
428 
429  case JackTransportRolling :
430  //fEngineControl->fTransport.SetCommand(TransportCommandStart);
431  fEngineControl->fTransport.SetState(JackTransportRolling);
432  jack_info("Master is rolling.");
433  break;
434  }
435  }
436  }
437 
438  void JackNetDriver::EncodeTransportData()
439  {
440  //is there a timebase master change ?
441  int refnum;
442  bool conditional;
443  fEngineControl->fTransport.GetTimebaseMaster(refnum, conditional);
444  if (refnum != fLastTimebaseMaster) {
445  //timebase master has released its function
446  if (refnum == -1) {
447  fReturnTransportData.fTimebaseMaster = RELEASE_TIMEBASEMASTER;
448  jack_info("Sending a timebase master release request.");
449  } else {
450  //there is a new timebase master
451  fReturnTransportData.fTimebaseMaster = (conditional) ? CONDITIONAL_TIMEBASEMASTER : TIMEBASEMASTER;
452  jack_info("Sending a %s timebase master request.", (conditional) ? "conditional" : "non-conditional");
453  }
454  fLastTimebaseMaster = refnum;
455  } else {
456  fReturnTransportData.fTimebaseMaster = NO_CHANGE;
457  }
458 
459  //update transport state and position
460  fReturnTransportData.fState = fEngineControl->fTransport.Query(&fReturnTransportData.fPosition);
461 
462  //is it a new state (that the master need to know...) ?
463  fReturnTransportData.fNewState = ((fReturnTransportData.fState == JackTransportNetStarting) &&
464  (fReturnTransportData.fState != fLastTransportState) &&
465  (fReturnTransportData.fState != fSendTransportData.fState));
466  if (fReturnTransportData.fNewState) {
467  jack_info("Sending '%s'.", GetTransportState(fReturnTransportData.fState));
468  }
469  fLastTransportState = fReturnTransportData.fState;
470  }
471 
472 //driver processes--------------------------------------------------------------------
473 
474  int JackNetDriver::Read()
475  {
476  //buffers
477  for (int midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
478  fNetMidiCaptureBuffer->SetBuffer(midi_port_index, GetMidiInputBuffer(midi_port_index));
479  }
480 
481  for (int audio_port_index = 0; audio_port_index < fParams.fSendAudioChannels; audio_port_index++) {
482  #ifdef OPTIMIZED_PROTOCOL
483  if (fGraphManager->GetConnectionsNum(fCapturePortList[audio_port_index]) > 0) {
484  fNetAudioCaptureBuffer->SetBuffer(audio_port_index, GetInputBuffer(audio_port_index));
485  } else {
486  fNetAudioCaptureBuffer->SetBuffer(audio_port_index, NULL);
487  }
488  #else
489  fNetAudioCaptureBuffer->SetBuffer(audio_port_index, GetInputBuffer(audio_port_index));
490  #endif
491  }
492 
493 #ifdef JACK_MONITOR
494  fNetTimeMon->New();
495 #endif
496 
497  //receive sync (launch the cycle)
498  if (SyncRecv() == SOCKET_ERROR) {
499  return SOCKET_ERROR;
500  }
501 
502 #ifdef JACK_MONITOR
503  // For timing
504  fRcvSyncUst = GetMicroSeconds();
505 #endif
506 
507  //decode sync
508  //if there is an error, don't return -1, it will skip Write() and the network error probably won't be identified
509  DecodeSyncPacket();
510 
511 #ifdef JACK_MONITOR
512  fNetTimeMon->Add((float(GetMicroSeconds() - fRcvSyncUst) / float(fEngineControl->fPeriodUsecs) * 100.f);
513 #endif
514  //audio, midi or sync if driver is late
515  int res = DataRecv();
516  if (res == SOCKET_ERROR) {
517  return SOCKET_ERROR;
518  } else if (res == NET_PACKET_ERROR) {
519  jack_time_t cur_time = GetMicroSeconds();
520  NotifyXRun(cur_time, float(cur_time - fBeginDateUst)); // Better this value than nothing...
521  }
522 
523  //take the time at the beginning of the cycle
524  JackDriver::CycleTakeBeginTime();
525 
526 #ifdef JACK_MONITOR
527  fNetTimeMon->Add((float(GetMicroSeconds() - fRcvSyncUst) / float(fEngineControl->fPeriodUsecs) * 100.f);
528 #endif
529 
530  return 0;
531  }
532 
533  int JackNetDriver::Write()
534  {
535  //buffers
536  for (int midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
537  fNetMidiPlaybackBuffer->SetBuffer(midi_port_index, GetMidiOutputBuffer(midi_port_index));
538  }
539 
540  for (int audio_port_index = 0; audio_port_index < fPlaybackChannels; audio_port_index++) {
541  #ifdef OPTIMIZED_PROTOCOL
542  // Port is connected on other side...
543  if (fNetAudioPlaybackBuffer->GetConnected(audio_port_index)) {
544  if (fGraphManager->GetConnectionsNum(fPlaybackPortList[audio_port_index]) > 0) {
545  fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, GetOutputBuffer(audio_port_index));
546  } else {
547  fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, NULL);
548  }
549  } else {
550  fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, NULL);
551  }
552  #else
553  fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, GetOutputBuffer(audio_port_index));
554  #endif
555  }
556 
557 #ifdef JACK_MONITOR
558  fNetTimeMon->AddLast((float(GetMicroSeconds() - fRcvSyncUst) / float(fEngineControl->fPeriodUsecs) * 100.f);
559 #endif
560 
561  //sync
562  EncodeSyncPacket();
563 
564  //send sync
565  if (SyncSend() == SOCKET_ERROR) {
566  return SOCKET_ERROR;
567  }
568 
569 #ifdef JACK_MONITOR
570  fNetTimeMon->Add(((float)(GetMicroSeconds() - fRcvSyncUst) / (float)fEngineControl->fPeriodUsecs) * 100.f);
571 #endif
572 
573  //send data
574  if (DataSend() == SOCKET_ERROR) {
575  return SOCKET_ERROR;
576  }
577 
578 #ifdef JACK_MONITOR
579  fNetTimeMon->AddLast(((float)(GetMicroSeconds() - fRcvSyncUst) / (float)fEngineControl->fPeriodUsecs) * 100.f);
580 #endif
581 
582  return 0;
583  }
584 
585 //driver loader-----------------------------------------------------------------------
586 
587 #ifdef __cplusplus
588  extern "C"
589  {
590 #endif
591  SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor()
592  {
593  jack_driver_desc_t * desc;
596 
597  desc = jack_driver_descriptor_construct("net", JackDriverMaster, "netjack slave backend component", &filler);
598 
599  strcpy(value.str, DEFAULT_MULTICAST_IP);
600  jack_driver_descriptor_add_parameter(desc, &filler, "multicast-ip", 'a', JackDriverParamString, &value, NULL, "Multicast Address", NULL);
601 
602  value.i = DEFAULT_PORT;
603  jack_driver_descriptor_add_parameter(desc, &filler, "udp-net-port", 'p', JackDriverParamInt, &value, NULL, "UDP port", NULL);
604 
605  value.i = DEFAULT_MTU;
606  jack_driver_descriptor_add_parameter(desc, &filler, "mtu", 'M', JackDriverParamInt, &value, NULL, "MTU to the master", NULL);
607 
608  value.i = -1;
609  jack_driver_descriptor_add_parameter(desc, &filler, "input-ports", 'C', JackDriverParamInt, &value, NULL, "Number of audio input ports", "Number of audio input ports. If -1, audio physical input from the master");
610  jack_driver_descriptor_add_parameter(desc, &filler, "output-ports", 'P', JackDriverParamInt, &value, NULL, "Number of audio output ports", "Number of audio output ports. If -1, audio physical output from the master");
611 
612  value.i = 0;
613  jack_driver_descriptor_add_parameter(desc, &filler, "midi-in-ports", 'i', JackDriverParamInt, &value, NULL, "Number of midi input ports", NULL);
614  jack_driver_descriptor_add_parameter(desc, &filler, "midi-out-ports", 'o', JackDriverParamInt, &value, NULL, "Number of midi output ports", NULL);
615 
616 #if HAVE_CELT
617  value.i = -1;
618  jack_driver_descriptor_add_parameter(desc, &filler, "celt", 'c', JackDriverParamInt, &value, NULL, "Set CELT encoding and number of kBits per channel", NULL);
619 #endif
620  strcpy(value.str, "'hostname'");
621  jack_driver_descriptor_add_parameter(desc, &filler, "client-name", 'n', JackDriverParamString, &value, NULL, "Name of the jack client", NULL);
622 
623  value.ui = 0U;
624  jack_driver_descriptor_add_parameter(desc, &filler, "transport-sync", 't', JackDriverParamUInt, &value, NULL, "Sync transport with master's", NULL);
625 
626  value.ui = 5U;
627  jack_driver_descriptor_add_parameter(desc, &filler, "latency", 'l', JackDriverParamUInt, &value, NULL, "Network latency", NULL);
628 
629  return desc;
630  }
631 
632  SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
633  {
634  char multicast_ip[32];
635  char net_name[JACK_CLIENT_NAME_SIZE + 1];
636  int udp_port;
637  int mtu = DEFAULT_MTU;
638  // Desactivated for now...
639  uint transport_sync = 0;
640  jack_nframes_t period_size = 1024;
641  jack_nframes_t sample_rate = 48000;
642  int audio_capture_ports = -1;
643  int audio_playback_ports = -1;
644  int midi_input_ports = 0;
645  int midi_output_ports = 0;
646  int celt_encoding = -1;
647  bool monitor = false;
648  int network_latency = 5;
649  const JSList* node;
650  const jack_driver_param_t* param;
651 
652  net_name[0] = 0;
653 
654  // Possibly use env variable
655  const char* default_udp_port = getenv("JACK_NETJACK_PORT");
656  udp_port = (default_udp_port) ? atoi(default_udp_port) : DEFAULT_PORT;
657 
658  const char* default_multicast_ip = getenv("JACK_NETJACK_MULTICAST");
659  if (default_multicast_ip) {
660  strcpy(multicast_ip, default_multicast_ip);
661  } else {
662  strcpy(multicast_ip, DEFAULT_MULTICAST_IP);
663  }
664 
665  for (node = params; node; node = jack_slist_next(node)) {
666  param = (const jack_driver_param_t*) node->data;
667  switch (param->character)
668  {
669  case 'a' :
670  assert(strlen(param->value.str) < 32);
671  strcpy(multicast_ip, param->value.str);
672  break;
673  case 'p':
674  udp_port = param->value.ui;
675  break;
676  case 'M':
677  mtu = param->value.i;
678  break;
679  case 'C':
680  audio_capture_ports = param->value.i;
681  break;
682  case 'P':
683  audio_playback_ports = param->value.i;
684  break;
685  case 'i':
686  midi_input_ports = param->value.i;
687  break;
688  case 'o':
689  midi_output_ports = param->value.i;
690  break;
691  #if HAVE_CELT
692  case 'c':
693  celt_encoding = param->value.i;
694  break;
695  #endif
696  case 'n' :
697  strncpy(net_name, param->value.str, JACK_CLIENT_NAME_SIZE);
698  break;
699  case 't' :
700  transport_sync = param->value.ui;
701  break;
702  case 'l' :
703  network_latency = param->value.ui;
704  if (network_latency > NETWORK_MAX_LATENCY) {
705  printf("Error : network latency is limited to %d\n", NETWORK_MAX_LATENCY);
706  return NULL;
707  }
708  break;
709  }
710  }
711 
712  try {
713 
715  new Jack::JackNetDriver("system", "net_pcm", engine, table, multicast_ip, udp_port, mtu,
716  midi_input_ports, midi_output_ports,
717  net_name, transport_sync,
718  network_latency, celt_encoding));
719  if (driver->Open(period_size, sample_rate, 1, 1, audio_capture_ports, audio_playback_ports, monitor, "from_master_", "to_master_", 0, 0) == 0) {
720  return driver;
721  } else {
722  delete driver;
723  return NULL;
724  }
725 
726  } catch (...) {
727  return NULL;
728  }
729  }
730 
731 #ifdef __cplusplus
732  }
733 #endif
734 }