Jack2  1.9.12
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 = NETWORK_DEFAULT_LATENCY;
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  }
270  return false;
271  } catch (JackNetException& e) {
272  // Otherwise just restart...
273  e.PrintMessage();
274  jack_info("NetAdapter is restarted");
275  Reset();
276  fThread.DropSelfRealTime();
277  fThread.SetStatus(JackThread::kIniting);
278  if (Init()) {
279  fThread.SetStatus(JackThread::kRunning);
280  return true;
281  } else {
282  return false;
283  }
284  }
285  }
286 
287 //transport---------------------------------------------------------------------------
288  void JackNetAdapter::DecodeTransportData()
289  {
290  //TODO : we need here to get the actual timebase master to eventually release it from its duty (see JackNetDriver)
291 
292  //is there a new transport state ?
293  if (fSendTransportData.fNewState &&(fSendTransportData.fState != jack_transport_query(fClient, NULL))) {
294  switch (fSendTransportData.fState)
295  {
296  case JackTransportStopped :
297  jack_transport_stop(fClient);
298  jack_info("NetMaster : transport stops");
299  break;
300 
301  case JackTransportStarting :
302  jack_transport_reposition(fClient, &fSendTransportData.fPosition);
303  jack_transport_start(fClient);
304  jack_info("NetMaster : transport starts");
305  break;
306 
307  case JackTransportRolling :
308  // TODO, we need to :
309  // - find a way to call TransportEngine->SetNetworkSync()
310  // - turn the transport state to JackTransportRolling
311  jack_info("NetMaster : transport rolls");
312  break;
313  }
314  }
315  }
316 
317  void JackNetAdapter::EncodeTransportData()
318  {
319  //is there a timebase master change ?
320  int refnum = -1;
321  bool conditional = 0;
322  //TODO : get the actual timebase master
323  if (refnum != fLastTimebaseMaster) {
324  //timebase master has released its function
325  if (refnum == -1) {
326  fReturnTransportData.fTimebaseMaster = RELEASE_TIMEBASEMASTER;
327  jack_info("Sending a timebase master release request.");
328  } else {
329  //there is a new timebase master
330  fReturnTransportData.fTimebaseMaster = (conditional) ? CONDITIONAL_TIMEBASEMASTER : TIMEBASEMASTER;
331  jack_info("Sending a %s timebase master request.", (conditional) ? "conditional" : "non-conditional");
332  }
333  fLastTimebaseMaster = refnum;
334  } else {
335  fReturnTransportData.fTimebaseMaster = NO_CHANGE;
336  }
337 
338  //update transport state and position
339  fReturnTransportData.fState = jack_transport_query(fClient, &fReturnTransportData.fPosition);
340 
341  //is it a new state (that the master need to know...) ?
342  fReturnTransportData.fNewState = ((fReturnTransportData.fState != fLastTransportState) &&
343  (fReturnTransportData.fState != fSendTransportData.fState));
344  if (fReturnTransportData.fNewState) {
345  jack_info("Sending transport state '%s'.", GetTransportState(fReturnTransportData.fState));
346  }
347  fLastTransportState = fReturnTransportData.fState;
348  }
349 
350 //read/write operations---------------------------------------------------------------
351  int JackNetAdapter::Read()
352  {
353  switch (SyncRecv()) {
354 
355  case SOCKET_ERROR:
356  return SOCKET_ERROR;
357 
358  case SYNC_PACKET_ERROR:
359  // Since sync packet is incorrect, don't decode it and continue with data
360  break;
361 
362  default:
363  //decode sync
364  int unused_frames;
365  DecodeSyncPacket(unused_frames);
366  break;
367  }
368 
369  return DataRecv();
370  }
371 
372  int JackNetAdapter::Write()
373  {
374  EncodeSyncPacket();
375 
376  if (SyncSend() == SOCKET_ERROR) {
377  return SOCKET_ERROR;
378  }
379 
380  return DataSend();
381  }
382 
383 //process-----------------------------------------------------------------------------
384  int JackNetAdapter::Process()
385  {
386  //read data from the network
387  //in case of fatal network error, stop the process
388  if (Read() == SOCKET_ERROR) {
389  return SOCKET_ERROR;
390  }
391 
392  PushAndPull(fSoftCaptureBuffer, fSoftPlaybackBuffer, fAdaptedBufferSize);
393 
394  //then write data to network
395  //in case of failure, stop process
396  if (Write() == SOCKET_ERROR) {
397  return SOCKET_ERROR;
398  }
399 
400  return 0;
401  }
402 
403 } // namespace Jack
404 
405 //loader------------------------------------------------------------------------------
406 #ifdef __cplusplus
407 extern "C"
408 {
409 #endif
410 
411 #include "driver_interface.h"
412 #include "JackAudioAdapter.h"
413 
414  using namespace Jack;
415 
416  SERVER_EXPORT jack_driver_desc_t* jack_get_descriptor()
417  {
418  jack_driver_desc_t * desc;
421 
422  desc = jack_driver_descriptor_construct("netadapter", JackDriverNone, "netjack net <==> audio backend adapter", &filler);
423 
424  strcpy(value.str, DEFAULT_MULTICAST_IP);
425  jack_driver_descriptor_add_parameter(desc, &filler, "multicast-ip", 'a', JackDriverParamString, &value, NULL, "Multicast address, or explicit IP of the master", NULL);
426 
427  value.i = DEFAULT_PORT;
428  jack_driver_descriptor_add_parameter(desc, &filler, "udp-net-port", 'p', JackDriverParamInt, &value, NULL, "UDP port", NULL);
429 
430  value.i = DEFAULT_MTU;
431  jack_driver_descriptor_add_parameter(desc, &filler, "mtu", 'M', JackDriverParamInt, &value, NULL, "MTU to the master", NULL);
432 
433  value.i = 2;
434  jack_driver_descriptor_add_parameter(desc, &filler, "input-ports", 'C', JackDriverParamInt, &value, NULL, "Number of audio input ports", NULL);
435  jack_driver_descriptor_add_parameter(desc, &filler, "output-ports", 'P', JackDriverParamInt, &value, NULL, "Number of audio output ports", NULL);
436 
437  #if HAVE_CELT
438  value.i = -1;
439  jack_driver_descriptor_add_parameter(desc, &filler, "celt", 'c', JackDriverParamInt, &value, NULL, "Set CELT encoding and number of kBits per channel", NULL);
440  #endif
441 
442  #if HAVE_OPUS
443  value.i = -1;
444  jack_driver_descriptor_add_parameter(desc, &filler, "opus", 'O', JackDriverParamInt, &value, NULL, "Set Opus encoding and number of kBits per channel", NULL);
445  #endif
446 
447  strcpy(value.str, "'hostname'");
448  jack_driver_descriptor_add_parameter(desc, &filler, "client-name", 'n', JackDriverParamString, &value, NULL, "Name of the jack client", NULL);
449 
450  value.ui = 0U;
451  jack_driver_descriptor_add_parameter(desc, &filler, "transport-sync", 't', JackDriverParamUInt, &value, NULL, "Sync transport with master's", NULL);
452 
453  value.ui = 5U;
454  jack_driver_descriptor_add_parameter(desc, &filler, "latency", 'l', JackDriverParamUInt, &value, NULL, "Network latency", NULL);
455 
456  value.i = 0;
457  jack_driver_descriptor_add_parameter(desc, &filler, "quality", 'q', JackDriverParamInt, &value, NULL, "Resample algorithm quality (0 - 4)", NULL);
458 
459  value.i = 32768;
460  jack_driver_descriptor_add_parameter(desc, &filler, "ring-buffer", 'g', JackDriverParamInt, &value, NULL, "Fixed ringbuffer size", "Fixed ringbuffer size (if not set => automatic adaptative)");
461 
462  value.i = false;
463  jack_driver_descriptor_add_parameter(desc, &filler, "auto-connect", 'c', JackDriverParamBool, &value, NULL, "Auto connect netadapter to system ports", NULL);
464 
465  return desc;
466  }
467 
468  SERVER_EXPORT int jack_internal_initialize(jack_client_t* client, const JSList* params)
469  {
470  jack_log("Loading netadapter");
471 
472  Jack::JackAudioAdapter* adapter;
473  jack_nframes_t buffer_size = jack_get_buffer_size(client);
474  jack_nframes_t sample_rate = jack_get_sample_rate(client);
475 
476  try {
477 
478  adapter = new Jack::JackAudioAdapter(client, new Jack::JackNetAdapter(client, buffer_size, sample_rate, params), params);
479  assert(adapter);
480 
481  if (adapter->Open() == 0) {
482  return 0;
483  } else {
484  delete adapter;
485  return 1;
486  }
487 
488  } catch (...) {
489  jack_info("netadapter allocation error");
490  return 1;
491  }
492  }
493 
494  SERVER_EXPORT int jack_initialize(jack_client_t* jack_client, const char* load_init)
495  {
496  JSList* params = NULL;
497  bool parse_params = true;
498  int res = 1;
499  jack_driver_desc_t* desc = jack_get_descriptor();
500 
501  Jack::JackArgParser parser(load_init);
502  if (parser.GetArgc() > 0) {
503  parse_params = parser.ParseParams(desc, &params);
504  }
505 
506  if (parse_params) {
507  res = jack_internal_initialize(jack_client, params);
508  parser.FreeParams(params);
509  }
510  return res;
511  }
512 
513  SERVER_EXPORT void jack_finish(void* arg)
514  {
515  Jack::JackAudioAdapter* adapter = static_cast<Jack::JackAudioAdapter*>(arg);
516 
517  if (adapter) {
518  jack_log("Unloading netadapter");
519  adapter->Close();
520  delete adapter;
521  }
522  }
523 
524 #ifdef __cplusplus
525 }
526 #endif
LIB_EXPORT jack_transport_state_t jack_transport_query(const jack_client_t *client, jack_position_t *pos)
Definition: JackAPI.cpp:1583
SERVER_EXPORT void jack_error(const char *fmt,...)
Definition: JackError.cpp:92
SERVER_EXPORT void jack_info(const char *fmt,...)
Definition: JackError.cpp:100
Base class for audio adapters.
LIB_EXPORT void jack_transport_start(jack_client_t *client)
Definition: JackAPI.cpp:1623
Audio adapter : Jack client side.
LIB_EXPORT jack_nframes_t jack_get_buffer_size(jack_client_t *)
Definition: JackAPI.cpp:1275
LIB_EXPORT void jack_transport_stop(jack_client_t *client)
Definition: JackAPI.cpp:1635
LIB_EXPORT int jack_transport_reposition(jack_client_t *client, const jack_position_t *pos)
Definition: JackAPI.cpp:1609
LIB_EXPORT jack_nframes_t jack_get_sample_rate(jack_client_t *)
Definition: JackAPI.cpp:1261
Exception possibly thrown by Net slaves.
SERVER_EXPORT void jack_log(const char *fmt,...)
Definition: JackError.cpp:108