Jack2  1.9.8
JackNetAdapter.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 "JackNetAdapter.h"
20 #include "JackException.h"
21 #include "JackServerGlobals.h"
22 #include "JackEngineControl.h"
23 #include "JackArgParser.h"
24 #include <assert.h>
25 
26 namespace Jack
27 {
28  JackNetAdapter::JackNetAdapter(jack_client_t* jack_client, jack_nframes_t buffer_size, jack_nframes_t sample_rate, const JSList* params)
29  : JackAudioAdapterInterface(buffer_size, sample_rate), JackNetSlaveInterface(), fThread(this)
30  {
31  jack_log("JackNetAdapter::JackNetAdapter");
32 
33  /*
34  Global parameter setting : we can't call JackNetSlaveInterface constructor with some parameters before,
35  because we don't have full parametering right now, parameters will be parsed from the param list,
36  and then JackNetSlaveInterface will be filled with proper values.
37  */
38  char multicast_ip[32];
39  uint udp_port;
40  GetHostName(fParams.fName, JACK_CLIENT_NAME_SIZE);
41  fSocket.GetName(fParams.fSlaveNetName);
42  fParams.fMtu = DEFAULT_MTU;
43  // Desactivated for now...
44  fParams.fTransportSync = 0;
45  int send_audio = -1;
46  int return_audio = -1;
47  fParams.fSendMidiChannels = 0;
48  fParams.fReturnMidiChannels = 0;
49  fParams.fSampleRate = sample_rate;
50  fParams.fPeriodSize = buffer_size;
51  fParams.fSlaveSyncMode = 1;
52  fParams.fNetworkLatency = 2;
53  fParams.fSampleEncoder = JackFloatEncoder;
54  fClient = jack_client;
55 
56  // Possibly use env variable
57  const char* default_udp_port = getenv("JACK_NETJACK_PORT");
58  udp_port = (default_udp_port) ? atoi(default_udp_port) : DEFAULT_PORT;
59 
60  const char* default_multicast_ip = getenv("JACK_NETJACK_MULTICAST");
61  if (default_multicast_ip) {
62  strcpy(multicast_ip, default_multicast_ip);
63  } else {
64  strcpy(multicast_ip, DEFAULT_MULTICAST_IP);
65  }
66 
67  //options parsing
68  const JSList* node;
69  const jack_driver_param_t* param;
70  for (node = params; node; node = jack_slist_next(node))
71  {
72  param = (const jack_driver_param_t*) node->data;
73 
74  switch (param->character) {
75  case 'a' :
76  assert(strlen(param->value.str) < 32);
77  strcpy(multicast_ip, param->value.str);
78  break;
79  case 'p' :
80  udp_port = param->value.ui;
81  break;
82  case 'M' :
83  fParams.fMtu = param->value.i;
84  break;
85  case 'C' :
86  send_audio = param->value.i;
87  break;
88  case 'P' :
89  return_audio = param->value.i;
90  break;
91  case 'n' :
92  strncpy(fParams.fName, param->value.str, JACK_CLIENT_NAME_SIZE);
93  break;
94  case 't' :
95  fParams.fTransportSync = param->value.ui;
96  break;
97  #if HAVE_CELT
98  case 'c':
99  if (param->value.i > 0) {
100  fParams.fSampleEncoder = JackCeltEncoder;
101  fParams.fKBps = param->value.i;
102  }
103  break;
104  #endif
105  case 'l' :
106  fParams.fNetworkLatency = param->value.i;
107  if (fParams.fNetworkLatency > NETWORK_MAX_LATENCY) {
108  jack_error("Error : network latency is limited to %d\n", NETWORK_MAX_LATENCY);
109  throw std::bad_alloc();
110  }
111  break;
112  case 'q':
113  fQuality = param->value.ui;
114  break;
115  case 'g':
116  fRingbufferCurSize = param->value.ui;
117  fAdaptative = false;
118  break;
119  }
120  }
121 
122  strcpy(fMulticastIP, multicast_ip);
123 
124  // Set the socket parameters
125  fSocket.SetPort(udp_port);
126  fSocket.SetAddress(fMulticastIP, udp_port);
127 
128  // If not set, takes default
129  fParams.fSendAudioChannels = (send_audio == -1) ? 2 : send_audio;
130 
131  // If not set, takes default
132  fParams.fReturnAudioChannels = (return_audio == -1) ? 2 : return_audio;
133 
134  // Set the audio adapter interface channel values
135  SetInputs(fParams.fSendAudioChannels);
136  SetOutputs(fParams.fReturnAudioChannels);
137 
138  // Soft buffers will be allocated later (once network initialization done)
139  fSoftCaptureBuffer = NULL;
140  fSoftPlaybackBuffer = NULL;
141  }
142 
143  JackNetAdapter::~JackNetAdapter()
144  {
145  jack_log("JackNetAdapter::~JackNetAdapter");
146 
147  if (fSoftCaptureBuffer) {
148  for (int port_index = 0; port_index < fCaptureChannels; port_index++) {
149  delete[] fSoftCaptureBuffer[port_index];
150  }
151  delete[] fSoftCaptureBuffer;
152  }
153  if (fSoftPlaybackBuffer) {
154  for (int port_index = 0; port_index < fPlaybackChannels; port_index++) {
155  delete[] fSoftPlaybackBuffer[port_index];
156  }
157  delete[] fSoftPlaybackBuffer;
158  }
159  }
160 
161 //open/close--------------------------------------------------------------------------
162  int JackNetAdapter::Open()
163  {
164  jack_info("NetAdapter started in %s mode %s Master's transport sync.",
165  (fParams.fSlaveSyncMode) ? "sync" : "async", (fParams.fTransportSync) ? "with" : "without");
166 
167  if (fThread.StartSync() < 0) {
168  jack_error("Cannot start netadapter thread");
169  return -1;
170  }
171 
172  return 0;
173  }
174 
175  int JackNetAdapter::Close()
176  {
177  int res = 0;
178  jack_log("JackNetAdapter::Close");
179 
180 #ifdef JACK_MONITOR
181  fTable.Save(fHostBufferSize, fHostSampleRate, fAdaptedSampleRate, fAdaptedBufferSize);
182 #endif
183 
184  if (fThread.Kill() < 0) {
185  jack_error("Cannot kill thread");
186  res = -1;
187  }
188 
189  fSocket.Close();
190  return res;
191  }
192 
193  int JackNetAdapter::SetBufferSize(jack_nframes_t buffer_size)
194  {
195  JackAudioAdapterInterface::SetHostBufferSize(buffer_size);
196  return 0;
197  }
198 
199 //thread------------------------------------------------------------------------------
200  // TODO : if failure, thread exist... need to restart ?
201 
203  {
204  jack_log("JackNetAdapter::Init");
205 
206  //init network connection
207  if (!JackNetSlaveInterface::Init()) {
208  jack_error("JackNetSlaveInterface::Init() error...");
209  return false;
210  }
211 
212  //then set global parameters
213  if (!SetParams()) {
214  jack_error("SetParams error...");
215  return false;
216  }
217 
218  //set buffers
219  if (fCaptureChannels > 0) {
220  fSoftCaptureBuffer = new sample_t*[fCaptureChannels];
221  for (int port_index = 0; port_index < fCaptureChannels; port_index++) {
222  fSoftCaptureBuffer[port_index] = new sample_t[fParams.fPeriodSize];
223  fNetAudioCaptureBuffer->SetBuffer(port_index, fSoftCaptureBuffer[port_index]);
224  }
225  }
226 
227  if (fPlaybackChannels > 0) {
228  fSoftPlaybackBuffer = new sample_t*[fPlaybackChannels];
229  for (int port_index = 0; port_index < fPlaybackChannels; port_index++) {
230  fSoftPlaybackBuffer[port_index] = new sample_t[fParams.fPeriodSize];
231  fNetAudioPlaybackBuffer->SetBuffer(port_index, fSoftPlaybackBuffer[port_index]);
232  }
233  }
234 
235  //set audio adapter parameters
236  SetAdaptedBufferSize(fParams.fPeriodSize);
237  SetAdaptedSampleRate(fParams.fSampleRate);
238 
239  // Will do "something" on OSX only...
240  fThread.SetParams(GetEngineControl()->fPeriod, GetEngineControl()->fComputation, GetEngineControl()->fConstraint);
241 
242  if (fThread.AcquireSelfRealTime(GetEngineControl()->fClientPriority) < 0) {
243  jack_error("AcquireSelfRealTime error");
244  } else {
245  set_threaded_log_function();
246  }
247 
248  //init done, display parameters
249  SessionParamsDisplay(&fParams);
250  return true;
251  }
252 
253  bool JackNetAdapter::Execute()
254  {
255  try {
256  // Keep running even in case of error
257  while (fThread.GetStatus() == JackThread::kRunning)
258  if (Process() == SOCKET_ERROR) {
259  return false;
260  }
261  return false;
262  } catch (JackNetException& e) {
263  e.PrintMessage();
264  jack_info("NetAdapter is restarted");
265  Reset();
266  fThread.DropSelfRealTime();
267  fThread.SetStatus(JackThread::kIniting);
268  if (Init()) {
269  fThread.SetStatus(JackThread::kRunning);
270  return true;
271  } else {
272  return false;
273  }
274  }
275  }
276 
277 //transport---------------------------------------------------------------------------
278  void JackNetAdapter::DecodeTransportData()
279  {
280  //TODO : we need here to get the actual timebase master to eventually release it from its duty (see JackNetDriver)
281 
282  //is there a new transport state ?
283  if (fSendTransportData.fNewState &&(fSendTransportData.fState != jack_transport_query(fClient, NULL))) {
284  switch (fSendTransportData.fState)
285  {
286  case JackTransportStopped :
287  jack_transport_stop(fClient);
288  jack_info("NetMaster : transport stops");
289  break;
290 
291  case JackTransportStarting :
292  jack_transport_reposition(fClient, &fSendTransportData.fPosition);
293  jack_transport_start(fClient);
294  jack_info("NetMaster : transport starts");
295  break;
296 
297  case JackTransportRolling :
298  // TODO, we need to :
299  // - find a way to call TransportEngine->SetNetworkSync()
300  // - turn the transport state to JackTransportRolling
301  jack_info("NetMaster : transport rolls");
302  break;
303  }
304  }
305  }
306 
307  void JackNetAdapter::EncodeTransportData()
308  {
309  //is there a timebase master change ?
310  int refnum = -1;
311  bool conditional = 0;
312  //TODO : get the actual timebase master
313  if (refnum != fLastTimebaseMaster) {
314  //timebase master has released its function
315  if (refnum == -1) {
316  fReturnTransportData.fTimebaseMaster = RELEASE_TIMEBASEMASTER;
317  jack_info("Sending a timebase master release request.");
318  } else {
319  //there is a new timebase master
320  fReturnTransportData.fTimebaseMaster = (conditional) ? CONDITIONAL_TIMEBASEMASTER : TIMEBASEMASTER;
321  jack_info("Sending a %s timebase master request.", (conditional) ? "conditional" : "non-conditional");
322  }
323  fLastTimebaseMaster = refnum;
324  } else {
325  fReturnTransportData.fTimebaseMaster = NO_CHANGE;
326  }
327 
328  //update transport state and position
329  fReturnTransportData.fState = jack_transport_query(fClient, &fReturnTransportData.fPosition);
330 
331  //is it a new state (that the master need to know...) ?
332  fReturnTransportData.fNewState = ((fReturnTransportData.fState != fLastTransportState) &&
333  (fReturnTransportData.fState != fSendTransportData.fState));
334  if (fReturnTransportData.fNewState) {
335  jack_info("Sending transport state '%s'.", GetTransportState(fReturnTransportData.fState));
336  }
337  fLastTransportState = fReturnTransportData.fState;
338  }
339 
340 //read/write operations---------------------------------------------------------------
341  int JackNetAdapter::Read()
342  {
343  //don't return -1 in case of sync recv failure
344  //we need the process to continue for network error detection
345  if (SyncRecv() == SOCKET_ERROR) {
346  return 0;
347  }
348 
349  DecodeSyncPacket();
350  return DataRecv();
351  }
352 
353  int JackNetAdapter::Write()
354  {
355  EncodeSyncPacket();
356 
357  if (SyncSend() == SOCKET_ERROR) {
358  return SOCKET_ERROR;
359  }
360 
361  return DataSend();
362  }
363 
364 //process-----------------------------------------------------------------------------
365  int JackNetAdapter::Process()
366  {
367  //read data from the network
368  //in case of fatal network error, stop the process
369  if (Read() == SOCKET_ERROR) {
370  return SOCKET_ERROR;
371  }
372 
373  PushAndPull(fSoftCaptureBuffer, fSoftPlaybackBuffer, fAdaptedBufferSize);
374 
375  //then write data to network
376  //in case of failure, stop process
377  if (Write() == SOCKET_ERROR) {
378  return SOCKET_ERROR;
379  }
380 
381  return 0;
382  }
383 
384 } // namespace Jack
385 
386 //loader------------------------------------------------------------------------------
387 #ifdef __cplusplus
388 extern "C"
389 {
390 #endif
391 
392 #include "driver_interface.h"
393 #include "JackAudioAdapter.h"
394 
395  using namespace Jack;
396 
397  SERVER_EXPORT jack_driver_desc_t* jack_get_descriptor()
398  {
399  jack_driver_desc_t * desc;
402 
403  desc = jack_driver_descriptor_construct("netadapter", JackDriverNone, "netjack net <==> audio backend adapter", &filler);
404 
405  strcpy(value.str, DEFAULT_MULTICAST_IP);
406  jack_driver_descriptor_add_parameter(desc, &filler, "multicast-ip", 'a', JackDriverParamString, &value, NULL, "Multicast Address", NULL);
407 
408  value.i = DEFAULT_PORT;
409  jack_driver_descriptor_add_parameter(desc, &filler, "udp-net-port", 'p', JackDriverParamInt, &value, NULL, "UDP port", NULL);
410 
411  value.i = DEFAULT_MTU;
412  jack_driver_descriptor_add_parameter(desc, &filler, "mtu", 'M', JackDriverParamInt, &value, NULL, "MTU to the master", NULL);
413 
414  value.i = 2;
415  jack_driver_descriptor_add_parameter(desc, &filler, "input-ports", 'C', JackDriverParamInt, &value, NULL, "Number of audio input ports", NULL);
416  jack_driver_descriptor_add_parameter(desc, &filler, "output-ports", 'C', JackDriverParamInt, &value, NULL, "Number of audio output ports", NULL);
417 
418  #if HAVE_CELT
419  value.i = -1;
420  jack_driver_descriptor_add_parameter(desc, &filler, "celt", 'c', JackDriverParamInt, &value, NULL, "Set CELT encoding and number of kBits per channel", NULL);
421  #endif
422 
423  strcpy(value.str, "'hostname'");
424  jack_driver_descriptor_add_parameter(desc, &filler, "client-name", 'n', JackDriverParamString, &value, NULL, "Name of the jack client", NULL);
425 
426  value.ui = 0U;
427  jack_driver_descriptor_add_parameter(desc, &filler, "transport-sync", 't', JackDriverParamUInt, &value, NULL, "Sync transport with master's", NULL);
428 
429  value.ui = 5U;
430  jack_driver_descriptor_add_parameter(desc, &filler, "latency", 'l', JackDriverParamUInt, &value, NULL, "Network latency", NULL);
431 
432  value.i = 0;
433  jack_driver_descriptor_add_parameter(desc, &filler, "quality", 'q', JackDriverParamInt, &value, NULL, "Resample algorithm quality (0 - 4)", NULL);
434 
435  value.i = 32768;
436  jack_driver_descriptor_add_parameter(desc, &filler, "ring-buffer", 'g', JackDriverParamInt, &value, NULL, "Fixed ringbuffer size", "Fixed ringbuffer size (if not set => automatic adaptative)");
437 
438  value.i = false;
439  jack_driver_descriptor_add_parameter(desc, &filler, "auto-connect", 'c', JackDriverParamBool, &value, NULL, "Auto connect netmaster to system ports", "");
440 
441  return desc;
442  }
443 
444  SERVER_EXPORT int jack_internal_initialize(jack_client_t* client, const JSList* params)
445  {
446  jack_log("Loading netadapter");
447 
448  Jack::JackAudioAdapter* adapter;
449  jack_nframes_t buffer_size = jack_get_buffer_size(client);
450  jack_nframes_t sample_rate = jack_get_sample_rate(client);
451 
452  try {
453 
454  adapter = new Jack::JackAudioAdapter(client, new Jack::JackNetAdapter(client, buffer_size, sample_rate, params), params);
455  assert(adapter);
456 
457  if (adapter->Open() == 0) {
458  return 0;
459  } else {
460  delete adapter;
461  return 1;
462  }
463 
464  } catch (...) {
465  jack_info("NetAdapter allocation error");
466  return 1;
467  }
468  }
469 
470  SERVER_EXPORT int jack_initialize(jack_client_t* jack_client, const char* load_init)
471  {
472  JSList* params = NULL;
473  bool parse_params = true;
474  int res = 1;
475  jack_driver_desc_t* desc = jack_get_descriptor();
476 
477  Jack::JackArgParser parser(load_init);
478  if (parser.GetArgc() > 0) {
479  parse_params = parser.ParseParams(desc, &params);
480  }
481 
482  if (parse_params) {
483  res = jack_internal_initialize(jack_client, params);
484  parser.FreeParams(params);
485  }
486  return res;
487  }
488 
489  SERVER_EXPORT void jack_finish(void* arg)
490  {
491  Jack::JackAudioAdapter* adapter = static_cast<Jack::JackAudioAdapter*>(arg);
492 
493  if (adapter) {
494  jack_log("Unloading netadapter");
495  adapter->Close();
496  delete adapter;
497  }
498  }
499 
500 #ifdef __cplusplus
501 }
502 #endif