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