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"
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 //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
;
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
)
62 if (strlen (param
->value
.str
) < 32)
63 strcpy(fMulticastIP
, param
->value
.str
);
65 jack_error("Can't use multicast address %s, using default %s", param
->value
.ui
, DEFAULT_MULTICAST_IP
);
68 fSocket
.SetPort ( param
->value
.ui
);
71 fParams
.fMtu
= param
->value
.i
;
74 fParams
.fSendAudioChannels
= param
->value
.i
;
77 fParams
.fReturnAudioChannels
= param
->value
.i
;
80 strncpy ( fParams
.fName
, param
->value
.str
, JACK_CLIENT_NAME_SIZE
);
83 //fParams.fTransportSync = param->value.ui;
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';
93 jack_error ( "Unknown network mode, using 'normal' mode." );
96 fQuality
= param
->value
.ui
;
99 fRingbufferCurSize
= param
->value
.ui
;
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" );
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" );
154 int JackNetAdapter::Close()
156 jack_log ( "JackNetAdapter::Close" );
159 fTable
.Save(fHostBufferSize
, fHostSampleRate
, fAdaptedSampleRate
, fAdaptedBufferSize
);
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" );
173 // Stop when the thread cycle is finished
175 case JackThread::kRunning
:
176 if ( fThread
.Stop() < 0 )
178 jack_error ( "Cannot stop thread" );
190 int JackNetAdapter::SetBufferSize ( jack_nframes_t buffer_size
)
192 JackAudioAdapterInterface::SetHostBufferSize ( buffer_size
);
196 //thread------------------------------------------------------------------------------
197 bool JackNetAdapter::Init()
199 jack_log ( "JackNetAdapter::Init" );
203 //init network connection
204 if ( !JackNetSlaveInterface::Init() )
207 //then set global parameters
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");
234 set_threaded_log_function();
237 //init done, display parameters
238 SessionParamsDisplay ( &fParams
);
242 bool JackNetAdapter::Execute()
245 // Keep running even in case of error
246 while (fThread
.GetStatus() == JackThread::kRunning
)
247 if (Process() == SOCKET_ERROR
)
250 } catch (JackNetException
& e
) {
252 jack_info("NetAdapter is restarted.");
254 fThread
.DropRealTime();
255 fThread
.SetStatus(JackThread::kIniting
);
257 fThread
.SetStatus(JackThread::kRunning
);
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." );
280 case JackTransportStarting
:
281 jack_transport_reposition ( fJackClient
, &fSendTransportData
.fPosition
);
282 jack_transport_start ( fJackClient
);
283 jack_info ( "NetMaster : transport starts." );
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." );
296 void JackNetAdapter::EncodeTransportData()
298 //is there a timebase master change ?
300 bool conditional
= 0;
301 //TODO : get the actual timebase master
302 if ( refnum
!= fLastTimebaseMaster
)
304 //timebase master has released its function
307 fReturnTransportData
.fTimebaseMaster
= RELEASE_TIMEBASEMASTER
;
308 jack_info ( "Sending a timebase master release request." );
310 //there is a new timebase master
313 fReturnTransportData
.fTimebaseMaster
= ( conditional
) ? CONDITIONAL_TIMEBASEMASTER
: TIMEBASEMASTER
;
314 jack_info ( "Sending a %s timebase master request.", ( conditional
) ? "conditional" : "non-conditional" );
316 fLastTimebaseMaster
= refnum
;
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
)
344 int JackNetAdapter::Write()
348 if ( SyncSend() == SOCKET_ERROR
)
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
)
362 PushAndPull(fSoftCaptureBuffer
, fSoftPlaybackBuffer
, fAdaptedBufferSize
);
364 //then write data to network
365 //in case of failure, stop process
366 if (Write() == SOCKET_ERROR
)
374 //loader------------------------------------------------------------------------------
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
393 desc
->params
= ( jack_driver_param_desc_t
* ) calloc ( desc
->nparams
, sizeof ( jack_driver_param_desc_t
) );
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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)");
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
);
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
);
496 adapter
= new Jack::JackAudioAdapter(jack_client
, new Jack::JackNetAdapter(jack_client
, buffer_size
, sample_rate
, params
), params
, false);
499 if ( adapter
->Open() == 0 )
512 SERVER_EXPORT
int jack_initialize ( jack_client_t
* jack_client
, const char* load_init
)
514 JSList
* params
= NULL
;
515 bool parse_params
= true;
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
, ¶ms
);
524 res
= jack_internal_initialize ( jack_client
, params
);
525 parser
.FreeParams ( params
);
530 SERVER_EXPORT
void jack_finish ( void* arg
)
532 Jack::JackAudioAdapter
* adapter
= static_cast<Jack::JackAudioAdapter
*> ( arg
);
535 jack_log ( "Unloading netadapter" );