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