Merge branch 'master' into develop
[jack2.git] / common / JackNetAdapter.cpp
blobdc254a15f7d9e20aa17eafb0065587061898dad8
1 /*
2 Copyright (C) 2008-2011 Romain Moret at Grame
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.
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.
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.
19 #include "JackNetAdapter.h"
20 #include "JackException.h"
21 #include "JackServerGlobals.h"
22 #include "JackEngineControl.h"
23 #include "JackArgParser.h"
24 #include <assert.h>
26 namespace Jack
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)
31 jack_log("JackNetAdapter::JackNetAdapter");
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.
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 // Deactivated 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;
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;
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);
67 //options parsing
68 const JSList* node;
69 const jack_driver_param_t* param;
70 for (node = params; node; node = jack_slist_next(node))
72 param = (const jack_driver_param_t*) node->data;
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;
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;
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();
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;
130 strcpy(fMulticastIP, multicast_ip);
132 // Set the socket parameters
133 fSocket.SetPort(udp_port);
134 fSocket.SetAddress(fMulticastIP, udp_port);
136 // If not set, takes default
137 fParams.fSendAudioChannels = (send_audio == -1) ? 2 : send_audio;
139 // If not set, takes default
140 fParams.fReturnAudioChannels = (return_audio == -1) ? 2 : return_audio;
142 // Set the audio adapter interface channel values
143 SetInputs(fParams.fSendAudioChannels);
144 SetOutputs(fParams.fReturnAudioChannels);
146 // Soft buffers will be allocated later (once network initialization done)
147 fSoftCaptureBuffer = NULL;
148 fSoftPlaybackBuffer = NULL;
151 JackNetAdapter::~JackNetAdapter()
153 jack_log("JackNetAdapter::~JackNetAdapter");
155 if (fSoftCaptureBuffer) {
156 for (int port_index = 0; port_index < fCaptureChannels; port_index++) {
157 delete[] fSoftCaptureBuffer[port_index];
159 delete[] fSoftCaptureBuffer;
161 if (fSoftPlaybackBuffer) {
162 for (int port_index = 0; port_index < fPlaybackChannels; port_index++) {
163 delete[] fSoftPlaybackBuffer[port_index];
165 delete[] fSoftPlaybackBuffer;
169 //open/close--------------------------------------------------------------------------
170 int JackNetAdapter::Open()
172 jack_info("NetAdapter started in %s mode %s Master's transport sync.",
173 (fParams.fSlaveSyncMode) ? "sync" : "async", (fParams.fTransportSync) ? "with" : "without");
175 if (fThread.StartSync() < 0) {
176 jack_error("Cannot start netadapter thread");
177 return -1;
180 return 0;
183 int JackNetAdapter::Close()
185 int res = 0;
186 jack_log("JackNetAdapter::Close");
188 #ifdef JACK_MONITOR
189 fTable.Save(fHostBufferSize, fHostSampleRate, fAdaptedSampleRate, fAdaptedBufferSize);
190 #endif
192 if (fThread.Kill() < 0) {
193 jack_error("Cannot kill thread");
194 res = -1;
197 fSocket.Close();
198 return res;
201 int JackNetAdapter::SetBufferSize(jack_nframes_t buffer_size)
203 JackAudioAdapterInterface::SetHostBufferSize(buffer_size);
204 return 0;
207 //thread------------------------------------------------------------------------------
208 // TODO : if failure, thread exist... need to restart ?
210 bool JackNetAdapter::Init()
212 jack_log("JackNetAdapter::Init");
214 //init network connection
215 if (!JackNetSlaveInterface::Init()) {
216 jack_error("JackNetSlaveInterface::Init() error...");
217 return false;
220 //then set global parameters
221 if (!SetParams()) {
222 jack_error("SetParams error...");
223 return false;
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]);
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]);
243 //set audio adapter parameters
244 SetAdaptedBufferSize(fParams.fPeriodSize);
245 SetAdaptedSampleRate(fParams.fSampleRate);
247 // Will do "something" on OSX only...
248 fThread.SetParams(GetEngineControl()->fPeriod, GetEngineControl()->fComputation, GetEngineControl()->fConstraint);
250 if (fThread.AcquireSelfRealTime(GetEngineControl()->fClientPriority) < 0) {
251 jack_error("AcquireSelfRealTime error");
252 } else {
253 set_threaded_log_function();
256 //init done, display parameters
257 SessionParamsDisplay(&fParams);
258 return true;
261 bool JackNetAdapter::Execute()
263 try {
264 // Keep running even in case of error
265 while (fThread.GetStatus() == JackThread::kRunning) {
266 if (Process() == SOCKET_ERROR) {
267 return false;
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;
287 //transport---------------------------------------------------------------------------
288 void JackNetAdapter::DecodeTransportData()
290 //TODO : we need here to get the actual timebase master to eventually release it from its duty (see JackNetDriver)
292 //is there a new transport state ?
293 if (fSendTransportData.fNewState &&(fSendTransportData.fState != jack_transport_query(fClient, NULL))) {
294 switch (fSendTransportData.fState)
296 case JackTransportStopped :
297 jack_transport_stop(fClient);
298 jack_info("NetMaster : transport stops");
299 break;
301 case JackTransportStarting :
302 jack_transport_reposition(fClient, &fSendTransportData.fPosition);
303 jack_transport_start(fClient);
304 jack_info("NetMaster : transport starts");
305 break;
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;
317 void JackNetAdapter::EncodeTransportData()
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");
333 fLastTimebaseMaster = refnum;
334 } else {
335 fReturnTransportData.fTimebaseMaster = NO_CHANGE;
338 //update transport state and position
339 fReturnTransportData.fState = jack_transport_query(fClient, &fReturnTransportData.fPosition);
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));
347 fLastTransportState = fReturnTransportData.fState;
350 //read/write operations---------------------------------------------------------------
351 int JackNetAdapter::Read()
353 switch (SyncRecv()) {
355 case SOCKET_ERROR:
356 return SOCKET_ERROR;
358 case SYNC_PACKET_ERROR:
359 // Since sync packet is incorrect, don't decode it and continue with data
360 break;
362 default:
363 //decode sync
364 int unused_frames;
365 DecodeSyncPacket(unused_frames);
366 break;
369 return DataRecv();
372 int JackNetAdapter::Write()
374 EncodeSyncPacket();
376 if (SyncSend() == SOCKET_ERROR) {
377 return SOCKET_ERROR;
380 return DataSend();
383 //process-----------------------------------------------------------------------------
384 int JackNetAdapter::Process()
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;
392 PushAndPull(fSoftCaptureBuffer, fSoftPlaybackBuffer, fAdaptedBufferSize);
394 //then write data to network
395 //in case of failure, stop process
396 if (Write() == SOCKET_ERROR) {
397 return SOCKET_ERROR;
400 return 0;
403 } // namespace Jack
405 //loader------------------------------------------------------------------------------
406 #ifdef __cplusplus
407 extern "C"
409 #endif
411 #include "driver_interface.h"
412 #include "JackAudioAdapter.h"
414 using namespace Jack;
416 SERVER_EXPORT jack_driver_desc_t* jack_get_descriptor()
418 jack_driver_desc_t * desc;
419 jack_driver_desc_filler_t filler;
420 jack_driver_param_value_t value;
422 desc = jack_driver_descriptor_construct("netadapter", JackDriverNone, "netjack net <==> audio backend adapter", &filler);
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);
427 value.i = DEFAULT_PORT;
428 jack_driver_descriptor_add_parameter(desc, &filler, "udp-net-port", 'p', JackDriverParamInt, &value, NULL, "UDP port", NULL);
430 value.i = DEFAULT_MTU;
431 jack_driver_descriptor_add_parameter(desc, &filler, "mtu", 'M', JackDriverParamInt, &value, NULL, "MTU to the master", NULL);
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);
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
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
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);
450 value.ui = 0U;
451 jack_driver_descriptor_add_parameter(desc, &filler, "transport-sync", 't', JackDriverParamUInt, &value, NULL, "Sync transport with master's", NULL);
453 value.ui = 5U;
454 jack_driver_descriptor_add_parameter(desc, &filler, "latency", 'l', JackDriverParamUInt, &value, NULL, "Network latency", NULL);
456 value.i = 0;
457 jack_driver_descriptor_add_parameter(desc, &filler, "quality", 'q', JackDriverParamInt, &value, NULL, "Resample algorithm quality (0 - 4)", NULL);
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)");
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);
465 return desc;
468 SERVER_EXPORT int jack_internal_initialize(jack_client_t* client, const JSList* params)
470 jack_log("Loading netadapter");
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);
476 try {
478 adapter = new Jack::JackAudioAdapter(client, new Jack::JackNetAdapter(client, buffer_size, sample_rate, params), params);
479 assert(adapter);
481 if (adapter->Open() == 0) {
482 return 0;
483 } else {
484 delete adapter;
485 return 1;
488 } catch (...) {
489 jack_info("netadapter allocation error");
490 return 1;
494 SERVER_EXPORT int jack_initialize(jack_client_t* jack_client, const char* load_init)
496 JSList* params = NULL;
497 bool parse_params = true;
498 int res = 1;
499 jack_driver_desc_t* desc = jack_get_descriptor();
501 Jack::JackArgParser parser(load_init);
502 if (parser.GetArgc() > 0) {
503 parse_params = parser.ParseParams(desc, &params);
506 if (parse_params) {
507 res = jack_internal_initialize(jack_client, params);
508 parser.FreeParams(params);
510 return res;
513 SERVER_EXPORT void jack_finish(void* arg)
515 Jack::JackAudioAdapter* adapter = static_cast<Jack::JackAudioAdapter*>(arg);
517 if (adapter) {
518 jack_log("Unloading netadapter");
519 adapter->Close();
520 delete adapter;
524 #ifdef __cplusplus
526 #endif