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"
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];
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;
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
);
64 strcpy(multicast_ip
, DEFAULT_MULTICAST_IP
);
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
) {
76 assert(strlen(param
->value
.str
) < 32);
77 strcpy(multicast_ip
, param
->value
.str
);
80 udp_port
= param
->value
.ui
;
83 fParams
.fMtu
= param
->value
.i
;
86 send_audio
= param
->value
.i
;
89 return_audio
= param
->value
.i
;
92 strncpy(fParams
.fName
, param
->value
.str
, JACK_CLIENT_NAME_SIZE
);
95 fParams
.fTransportSync
= param
->value
.ui
;
99 if (param
->value
.i
> 0) {
100 fParams
.fSampleEncoder
= JackCeltEncoder
;
101 fParams
.fKBps
= param
->value
.i
;
107 if (param
->value
.i
> 0) {
108 fParams
.fSampleEncoder
= JackOpusEncoder
;
109 fParams
.fKBps
= param
->value
.i
;
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();
121 fQuality
= param
->value
.ui
;
124 fRingbufferCurSize
= param
->value
.ui
;
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");
183 int JackNetAdapter::Close()
186 jack_log("JackNetAdapter::Close");
189 fTable
.Save(fHostBufferSize
, fHostSampleRate
, fAdaptedSampleRate
, fAdaptedBufferSize
);
192 if (fThread
.Kill() < 0) {
193 jack_error("Cannot kill thread");
201 int JackNetAdapter::SetBufferSize(jack_nframes_t buffer_size
)
203 JackAudioAdapterInterface::SetHostBufferSize(buffer_size
);
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...");
220 //then set global parameters
222 jack_error("SetParams error...");
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");
253 set_threaded_log_function();
256 //init done, display parameters
257 SessionParamsDisplay(&fParams
);
261 bool JackNetAdapter::Execute()
264 // Keep running even in case of error
265 while (fThread
.GetStatus() == JackThread::kRunning
) {
266 if (Process() == SOCKET_ERROR
) {
271 } catch (JackNetException
& e
) {
272 // Otherwise just restart...
274 jack_info("NetAdapter is restarted");
276 fThread
.DropSelfRealTime();
277 fThread
.SetStatus(JackThread::kIniting
);
279 fThread
.SetStatus(JackThread::kRunning
);
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");
301 case JackTransportStarting
:
302 jack_transport_reposition(fClient
, &fSendTransportData
.fPosition
);
303 jack_transport_start(fClient
);
304 jack_info("NetMaster : transport starts");
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");
317 void JackNetAdapter::EncodeTransportData()
319 //is there a timebase master change ?
321 bool conditional
= 0;
322 //TODO : get the actual timebase master
323 if (refnum
!= fLastTimebaseMaster
) {
324 //timebase master has released its function
326 fReturnTransportData
.fTimebaseMaster
= RELEASE_TIMEBASEMASTER
;
327 jack_info("Sending a timebase master release request.");
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
;
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()) {
358 case SYNC_PACKET_ERROR
:
359 // Since sync packet is incorrect, don't decode it and continue with data
365 DecodeSyncPacket(unused_frames
);
372 int JackNetAdapter::Write()
376 if (SyncSend() == SOCKET_ERROR
) {
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
) {
392 PushAndPull(fSoftCaptureBuffer
, fSoftPlaybackBuffer
, fAdaptedBufferSize
);
394 //then write data to network
395 //in case of failure, stop process
396 if (Write() == SOCKET_ERROR
) {
405 //loader------------------------------------------------------------------------------
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
);
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
);
439 jack_driver_descriptor_add_parameter(desc
, &filler
, "celt", 'c', JackDriverParamInt
, &value
, NULL
, "Set CELT encoding and number of kBits per channel", NULL
);
444 jack_driver_descriptor_add_parameter(desc
, &filler
, "opus", 'O', JackDriverParamInt
, &value
, NULL
, "Set Opus encoding and number of kBits per channel", NULL
);
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
);
451 jack_driver_descriptor_add_parameter(desc
, &filler
, "transport-sync", 't', JackDriverParamUInt
, &value
, NULL
, "Sync transport with master's", NULL
);
454 jack_driver_descriptor_add_parameter(desc
, &filler
, "latency", 'l', JackDriverParamUInt
, &value
, NULL
, "Network latency", NULL
);
457 jack_driver_descriptor_add_parameter(desc
, &filler
, "quality", 'q', JackDriverParamInt
, &value
, NULL
, "Resample algorithm quality (0 - 4)", NULL
);
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)");
463 jack_driver_descriptor_add_parameter(desc
, &filler
, "auto-connect", 'c', JackDriverParamBool
, &value
, NULL
, "Auto connect netadapter to system ports", NULL
);
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
);
478 adapter
= new Jack::JackAudioAdapter(client
, new Jack::JackNetAdapter(client
, buffer_size
, sample_rate
, params
), params
);
481 if (adapter
->Open() == 0) {
489 jack_info("netadapter allocation error");
494 SERVER_EXPORT
int jack_initialize(jack_client_t
* jack_client
, const char* load_init
)
496 JSList
* params
= NULL
;
497 bool parse_params
= true;
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
, ¶ms
);
507 res
= jack_internal_initialize(jack_client
, params
);
508 parser
.FreeParams(params
);
513 SERVER_EXPORT
void jack_finish(void* arg
)
515 Jack::JackAudioAdapter
* adapter
= static_cast<Jack::JackAudioAdapter
*>(arg
);
518 jack_log("Unloading netadapter");