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