Correct jackdmp.cpp (failures case were not correct..). Improve JackCoreAudioDriver...
[jack2.git] / common / JackNetAdapter.cpp
blob931f7651575c4fb4c2f32882edfe03efc4b88a52
1 /*
2 Copyright (C) 2008 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" );
33 //global parametering
34 //we can't call JackNetSlaveInterface constructor with some parameters before
35 //because we don't have full parametering right now
36 //parameters will be parsed from the param list, and then JackNetSlaveInterface will be filled with proper values
37 strcpy ( fMulticastIP, DEFAULT_MULTICAST_IP );
38 uint port = DEFAULT_PORT;
39 GetHostName ( fParams.fName, JACK_CLIENT_NAME_SIZE );
40 fSocket.GetName ( fParams.fSlaveNetName );
41 fParams.fMtu = DEFAULT_MTU;
42 fParams.fTransportSync = 0;
43 fParams.fSendAudioChannels = 2;
44 fParams.fReturnAudioChannels = 2;
45 fParams.fSendMidiChannels = 0;
46 fParams.fReturnMidiChannels = 0;
47 fParams.fSampleRate = sample_rate;
48 fParams.fPeriodSize = buffer_size;
49 fParams.fSlaveSyncMode = 1;
50 fParams.fNetworkMode = 's';
51 fJackClient = jack_client;
53 //options parsing
54 const JSList* node;
55 const jack_driver_param_t* param;
56 for ( node = params; node; node = jack_slist_next ( node ) )
58 param = ( const jack_driver_param_t* ) node->data;
59 switch ( param->character )
61 case 'a' :
62 if (strlen (param->value.str) < 32)
63 strcpy(fMulticastIP, param->value.str);
64 else
65 jack_error("Can't use multicast address %s, using default %s", param->value.ui, DEFAULT_MULTICAST_IP);
66 break;
67 case 'p' :
68 fSocket.SetPort ( param->value.ui );
69 break;
70 case 'M' :
71 fParams.fMtu = param->value.i;
72 break;
73 case 'C' :
74 fParams.fSendAudioChannels = param->value.i;
75 break;
76 case 'P' :
77 fParams.fReturnAudioChannels = param->value.i;
78 break;
79 case 'n' :
80 strncpy ( fParams.fName, param->value.str, JACK_CLIENT_NAME_SIZE );
81 break;
82 case 't' :
83 //fParams.fTransportSync = param->value.ui;
84 break;
85 case 'm' :
86 if ( strcmp ( param->value.str, "normal" ) == 0 )
87 fParams.fNetworkMode = 'n';
88 else if ( strcmp ( param->value.str, "slow" ) == 0 )
89 fParams.fNetworkMode = 's';
90 else if ( strcmp ( param->value.str, "fast" ) == 0 )
91 fParams.fNetworkMode = 'f';
92 else
93 jack_error ( "Unknown network mode, using 'normal' mode." );
94 break;
95 case 'q':
96 fQuality = param->value.ui;
97 break;
98 case 'g':
99 fRingbufferCurSize = param->value.ui;
100 fAdaptative = false;
101 break;
105 //set the socket parameters
106 fSocket.SetPort ( port );
107 fSocket.SetAddress ( fMulticastIP, port );
109 //set the audio adapter interface channel values
110 SetInputs ( fParams.fSendAudioChannels );
111 SetOutputs ( fParams.fReturnAudioChannels );
113 //soft buffers will be allocated later (once network initialization done)
114 fSoftCaptureBuffer = NULL;
115 fSoftPlaybackBuffer = NULL;
118 JackNetAdapter::~JackNetAdapter()
120 jack_log ( "JackNetAdapter::~JackNetAdapter" );
122 int port_index;
123 if ( fSoftCaptureBuffer )
125 for ( port_index = 0; port_index < fCaptureChannels; port_index++ )
126 delete[] fSoftCaptureBuffer[port_index];
127 delete[] fSoftCaptureBuffer;
129 if ( fSoftPlaybackBuffer )
131 for ( port_index = 0; port_index < fPlaybackChannels; port_index++ )
132 delete[] fSoftPlaybackBuffer[port_index];
133 delete[] fSoftPlaybackBuffer;
137 //open/close--------------------------------------------------------------------------
138 int JackNetAdapter::Open()
140 jack_log ( "JackNetAdapter::Open" );
142 jack_info ( "NetAdapter started in %s mode %s Master's transport sync.",
143 ( fParams.fSlaveSyncMode ) ? "sync" : "async", ( fParams.fTransportSync ) ? "with" : "without" );
145 if ( fThread.StartSync() < 0 )
147 jack_error ( "Cannot start netadapter thread" );
148 return -1;
151 return 0;
154 int JackNetAdapter::Close()
156 jack_log ( "JackNetAdapter::Close" );
158 #ifdef JACK_MONITOR
159 fTable.Save(fHostBufferSize, fHostSampleRate, fAdaptedSampleRate, fAdaptedBufferSize);
160 #endif
162 switch ( fThread.GetStatus() )
164 // Kill the thread in Init phase
165 case JackThread::kStarting:
166 case JackThread::kIniting:
167 if ( fThread.Kill() < 0 )
169 jack_error ( "Cannot kill thread" );
170 return -1;
172 break;
173 // Stop when the thread cycle is finished
175 case JackThread::kRunning:
176 if ( fThread.Stop() < 0 )
178 jack_error ( "Cannot stop thread" );
179 return -1;
181 break;
183 default:
184 break;
186 fSocket.Close();
187 return 0;
190 int JackNetAdapter::SetBufferSize ( jack_nframes_t buffer_size )
192 JackAudioAdapterInterface::SetHostBufferSize ( buffer_size );
193 return 0;
196 //thread------------------------------------------------------------------------------
197 bool JackNetAdapter::Init()
199 jack_log ( "JackNetAdapter::Init" );
201 int port_index;
203 //init network connection
204 if ( !JackNetSlaveInterface::Init() )
205 return false;
207 //then set global parameters
208 SetParams();
210 //set buffers
211 fSoftCaptureBuffer = new sample_t*[fCaptureChannels];
212 for ( port_index = 0; port_index < fCaptureChannels; port_index++ )
214 fSoftCaptureBuffer[port_index] = new sample_t[fParams.fPeriodSize];
215 fNetAudioCaptureBuffer->SetBuffer ( port_index, fSoftCaptureBuffer[port_index] );
217 fSoftPlaybackBuffer = new sample_t*[fPlaybackChannels];
218 for ( port_index = 0; port_index < fCaptureChannels; port_index++ )
220 fSoftPlaybackBuffer[port_index] = new sample_t[fParams.fPeriodSize];
221 fNetAudioPlaybackBuffer->SetBuffer ( port_index, fSoftPlaybackBuffer[port_index] );
224 //set audio adapter parameters
225 SetAdaptedBufferSize ( fParams.fPeriodSize );
226 SetAdaptedSampleRate ( fParams.fSampleRate );
228 // Will do "something" on OSX only...
229 fThread.SetParams(GetEngineControl()->fPeriod, GetEngineControl()->fComputation, GetEngineControl()->fConstraint);
231 if (fThread.AcquireRealTime(GetEngineControl()->fClientPriority) < 0) {
232 jack_error("AcquireRealTime error");
233 } else {
234 set_threaded_log_function();
237 //init done, display parameters
238 SessionParamsDisplay ( &fParams );
239 return true;
242 bool JackNetAdapter::Execute()
244 try {
245 // Keep running even in case of error
246 while (fThread.GetStatus() == JackThread::kRunning)
247 if (Process() == SOCKET_ERROR)
248 return false;
249 return false;
250 } catch (JackNetException& e) {
251 e.PrintMessage();
252 jack_info("NetAdapter is restarted.");
253 Reset();
254 fThread.DropRealTime();
255 fThread.SetStatus(JackThread::kIniting);
256 if (Init()) {
257 fThread.SetStatus(JackThread::kRunning);
258 return true;
259 } else {
260 return false;
265 //transport---------------------------------------------------------------------------
266 void JackNetAdapter::DecodeTransportData()
268 //TODO : we need here to get the actual timebase master to eventually release it from its duty (see JackNetDriver)
270 //is there a new transport state ?
271 if ( fSendTransportData.fNewState && ( fSendTransportData.fState != jack_transport_query ( fJackClient, NULL ) ) )
273 switch ( fSendTransportData.fState )
275 case JackTransportStopped :
276 jack_transport_stop ( fJackClient );
277 jack_info ( "NetMaster : transport stops." );
278 break;
280 case JackTransportStarting :
281 jack_transport_reposition ( fJackClient, &fSendTransportData.fPosition );
282 jack_transport_start ( fJackClient );
283 jack_info ( "NetMaster : transport starts." );
284 break;
286 case JackTransportRolling :
287 //TODO , we need to :
288 // - find a way to call TransportEngine->SetNetworkSync()
289 // - turn the transport state to JackTransportRolling
290 jack_info ( "NetMaster : transport rolls." );
291 break;
296 void JackNetAdapter::EncodeTransportData()
298 //is there a timebase master change ?
299 int refnum = -1;
300 bool conditional = 0;
301 //TODO : get the actual timebase master
302 if ( refnum != fLastTimebaseMaster )
304 //timebase master has released its function
305 if ( refnum == -1 )
307 fReturnTransportData.fTimebaseMaster = RELEASE_TIMEBASEMASTER;
308 jack_info ( "Sending a timebase master release request." );
310 //there is a new timebase master
311 else
313 fReturnTransportData.fTimebaseMaster = ( conditional ) ? CONDITIONAL_TIMEBASEMASTER : TIMEBASEMASTER;
314 jack_info ( "Sending a %s timebase master request.", ( conditional ) ? "conditional" : "non-conditional" );
316 fLastTimebaseMaster = refnum;
318 else
319 fReturnTransportData.fTimebaseMaster = NO_CHANGE;
321 //update transport state and position
322 fReturnTransportData.fState = jack_transport_query ( fJackClient, &fReturnTransportData.fPosition );
324 //is it a new state (that the master need to know...) ?
325 fReturnTransportData.fNewState = ( ( fReturnTransportData.fState != fLastTransportState ) &&
326 ( fReturnTransportData.fState != fSendTransportData.fState ) );
327 if ( fReturnTransportData.fNewState )
328 jack_info ( "Sending transport state '%s'.", GetTransportState ( fReturnTransportData.fState ) );
329 fLastTransportState = fReturnTransportData.fState;
332 //read/write operations---------------------------------------------------------------
333 int JackNetAdapter::Read()
335 //don't return -1 in case of sync recv failure
336 //we need the process to continue for network error detection
337 if ( SyncRecv() == SOCKET_ERROR )
338 return 0;
340 DecodeSyncPacket();
341 return DataRecv();
344 int JackNetAdapter::Write()
346 EncodeSyncPacket();
348 if ( SyncSend() == SOCKET_ERROR )
349 return SOCKET_ERROR;
351 return DataSend();
354 //process-----------------------------------------------------------------------------
355 int JackNetAdapter::Process()
357 //read data from the network
358 //in case of fatal network error, stop the process
359 if (Read() == SOCKET_ERROR)
360 return SOCKET_ERROR;
362 PushAndPull(fSoftCaptureBuffer, fSoftPlaybackBuffer, fAdaptedBufferSize);
364 //then write data to network
365 //in case of failure, stop process
366 if (Write() == SOCKET_ERROR)
367 return SOCKET_ERROR;
369 return 0;
372 } // namespace Jack
374 //loader------------------------------------------------------------------------------
375 #ifdef __cplusplus
376 extern "C"
378 #endif
380 #include "driver_interface.h"
381 #include "JackAudioAdapter.h"
383 using namespace Jack;
385 SERVER_EXPORT jack_driver_desc_t* jack_get_descriptor()
387 jack_driver_desc_t* desc = ( jack_driver_desc_t* ) calloc ( 1, sizeof ( jack_driver_desc_t ) );
389 strcpy(desc->name, "netadapter"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1
390 strcpy(desc->desc, "netjack net <==> audio backend adapter"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1
392 desc->nparams = 11;
393 desc->params = ( jack_driver_param_desc_t* ) calloc ( desc->nparams, sizeof ( jack_driver_param_desc_t ) );
395 int i = 0;
396 strcpy ( desc->params[i].name, "multicast_ip" );
397 desc->params[i].character = 'a';
398 desc->params[i].type = JackDriverParamString;
399 strcpy ( desc->params[i].value.str, DEFAULT_MULTICAST_IP );
400 strcpy ( desc->params[i].short_desc, "Multicast Address" );
401 strcpy ( desc->params[i].long_desc, desc->params[i].short_desc );
403 i++;
404 strcpy ( desc->params[i].name, "udp_net_port" );
405 desc->params[i].character = 'p';
406 desc->params[i].type = JackDriverParamInt;
407 desc->params[i].value.i = DEFAULT_PORT;
408 strcpy ( desc->params[i].short_desc, "UDP port" );
409 strcpy ( desc->params[i].long_desc, desc->params[i].short_desc );
411 i++;
412 strcpy ( desc->params[i].name, "mtu" );
413 desc->params[i].character = 'M';
414 desc->params[i].type = JackDriverParamInt;
415 desc->params[i].value.i = DEFAULT_MTU;
416 strcpy ( desc->params[i].short_desc, "MTU to the master" );
417 strcpy ( desc->params[i].long_desc, desc->params[i].short_desc );
419 i++;
420 strcpy ( desc->params[i].name, "input-ports" );
421 desc->params[i].character = 'C';
422 desc->params[i].type = JackDriverParamInt;
423 desc->params[i].value.i = 2;
424 strcpy ( desc->params[i].short_desc, "Number of audio input ports" );
425 strcpy ( desc->params[i].long_desc, desc->params[i].short_desc );
427 i++;
428 strcpy ( desc->params[i].name, "output-ports" );
429 desc->params[i].character = 'P';
430 desc->params[i].type = JackDriverParamInt;
431 desc->params[i].value.i = 2;
432 strcpy ( desc->params[i].short_desc, "Number of audio output ports" );
433 strcpy ( desc->params[i].long_desc, desc->params[i].short_desc );
435 i++;
436 strcpy ( desc->params[i].name, "client-name" );
437 desc->params[i].character = 'n';
438 desc->params[i].type = JackDriverParamString;
439 strcpy ( desc->params[i].value.str, "'hostname'" );
440 strcpy ( desc->params[i].short_desc, "Name of the jack client" );
441 strcpy ( desc->params[i].long_desc, desc->params[i].short_desc );
443 i++;
444 strcpy ( desc->params[i].name, "transport-sync" );
445 desc->params[i].character = 't';
446 desc->params[i].type = JackDriverParamUInt;
447 desc->params[i].value.ui = 1U;
448 strcpy ( desc->params[i].short_desc, "Sync transport with master's" );
449 strcpy ( desc->params[i].long_desc, desc->params[i].short_desc );
451 i++;
452 strcpy ( desc->params[i].name, "mode" );
453 desc->params[i].character = 'm';
454 desc->params[i].type = JackDriverParamString;
455 strcpy ( desc->params[i].value.str, "slow" );
456 strcpy ( desc->params[i].short_desc, "Slow, Normal or Fast mode." );
457 strcpy ( desc->params[i].long_desc, desc->params[i].short_desc );
459 i++;
460 strcpy(desc->params[i].name, "quality");
461 desc->params[i].character = 'q';
462 desc->params[i].type = JackDriverParamInt;
463 desc->params[i].value.ui = 0;
464 strcpy(desc->params[i].short_desc, "Resample algorithm quality (0 - 4)");
465 strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
467 i++;
468 strcpy(desc->params[i].name, "ring-buffer");
469 desc->params[i].character = 'g';
470 desc->params[i].type = JackDriverParamInt;
471 desc->params[i].value.ui = 32768;
472 strcpy(desc->params[i].short_desc, "Fixed ringbuffer size");
473 strcpy(desc->params[i].long_desc, "Fixed ringbuffer size (if not set => automatic adaptative)");
475 i++;
476 strcpy ( desc->params[i].name, "auto-connect" );
477 desc->params[i].character = 'c';
478 desc->params[i].type = JackDriverParamBool;
479 desc->params[i].value.i = false;
480 strcpy ( desc->params[i].short_desc, "Auto connect netmaster to system ports" );
481 strcpy ( desc->params[i].long_desc, desc->params[i].short_desc );
483 return desc;
486 SERVER_EXPORT int jack_internal_initialize ( jack_client_t* jack_client, const JSList* params )
488 jack_log ( "Loading netadapter" );
490 Jack::JackAudioAdapter* adapter;
491 jack_nframes_t buffer_size = jack_get_buffer_size ( jack_client );
492 jack_nframes_t sample_rate = jack_get_sample_rate ( jack_client );
494 try {
496 adapter = new Jack::JackAudioAdapter(jack_client, new Jack::JackNetAdapter(jack_client, buffer_size, sample_rate, params), params, false);
497 assert ( adapter );
499 if ( adapter->Open() == 0 )
500 return 0;
501 else
503 delete adapter;
504 return 1;
507 } catch (...) {
508 return 1;
512 SERVER_EXPORT int jack_initialize ( jack_client_t* jack_client, const char* load_init )
514 JSList* params = NULL;
515 bool parse_params = true;
516 int res = 1;
517 jack_driver_desc_t* desc = jack_get_descriptor();
519 Jack::JackArgParser parser ( load_init );
520 if ( parser.GetArgc() > 0 )
521 parse_params = parser.ParseParams ( desc, &params );
523 if (parse_params) {
524 res = jack_internal_initialize ( jack_client, params );
525 parser.FreeParams ( params );
527 return res;
530 SERVER_EXPORT void jack_finish ( void* arg )
532 Jack::JackAudioAdapter* adapter = static_cast<Jack::JackAudioAdapter*> ( arg );
534 if (adapter) {
535 jack_log ( "Unloading netadapter" );
536 adapter->Close();
537 delete adapter;
541 #ifdef __cplusplus
543 #endif