Jack2: JackNetAdapter.cpp Source File

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
210 bool JackNetAdapter::Init()
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;
419 jack_driver_desc_filler_t filler;
420 jack_driver_param_value_t value;
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
Jack::JackArgParser
Definition: JackArgParser.h:37
Jack
Definition: JackAC3Encoder.cpp:30
jack_driver_param_value_t
Definition: driver_interface.h:64
Jack::JackNetSlaveInterface
Definition: JackNetInterface.h:199
jack_transport_query
LIB_EXPORT jack_transport_state_t jack_transport_query(const jack_client_t *client, jack_position_t *pos)
Definition: JackAPI.cpp:1583
jack_error
SERVER_EXPORT void jack_error(const char *fmt,...)
Definition: JackError.cpp:92
jack_info
SERVER_EXPORT void jack_info(const char *fmt,...)
Definition: JackError.cpp:100
Jack::JackAudioAdapterInterface
Base class for audio adapters.
Definition: JackAudioAdapterInterface.h:65
jack_transport_start
LIB_EXPORT void jack_transport_start(jack_client_t *client)
Definition: JackAPI.cpp:1623
Jack::JackAudioAdapter
Audio adapter : Jack client side.
Definition: JackAudioAdapter.h:33
jack_get_buffer_size
LIB_EXPORT jack_nframes_t jack_get_buffer_size(jack_client_t *)
Definition: JackAPI.cpp:1275
jack_transport_stop
LIB_EXPORT void jack_transport_stop(jack_client_t *client)
Definition: JackAPI.cpp:1635
jack_transport_reposition
LIB_EXPORT int jack_transport_reposition(jack_client_t *client, const jack_position_t *pos)
Definition: JackAPI.cpp:1609
Jack::JackNetAdapter
Net adapter.
Definition: JackNetAdapter.h:33
jack_get_sample_rate
LIB_EXPORT jack_nframes_t jack_get_sample_rate(jack_client_t *)
Definition: JackAPI.cpp:1261
jack_driver_desc_filler_t
Definition: driver_interface.h:142
Jack::JackNetAdapter::Init
bool Init()
Definition: JackNetAdapter.cpp:210
Jack::JackNetException
Exception possibly thrown by Net slaves.
Definition: JackException.h:103
jack_driver_param_t
Definition: driver_interface.h:125
_JSList
Definition: linux/alsa/jslist.h:35
jack_log
SERVER_EXPORT void jack_log(const char *fmt,...)
Definition: JackError.cpp:108
jack_driver_desc_t
Definition: driver_interface.h:132