Correct netjack2 components help.
[jack2.git] / common / JackNetDriver.cpp
blob1f3681f4f37daf1c5cb5648ef57b3acbf5716aab
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 "JackCompilerDeps.h"
20 #include "driver_interface.h"
21 #include "JackNetDriver.h"
22 #include "JackEngineControl.h"
23 #include "JackLockedEngine.h"
24 #include "JackWaitThreadedDriver.h"
26 using namespace std;
28 namespace Jack
30 JackNetDriver::JackNetDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table,
31 const char* ip, int udp_port, int mtu, int midi_input_ports, int midi_output_ports,
32 char* net_name, uint transport_sync, int network_latency, int celt_encoding)
33 : JackWaiterDriver(name, alias, engine, table), JackNetSlaveInterface(ip, udp_port)
35 jack_log("JackNetDriver::JackNetDriver ip %s, port %d", ip, udp_port);
37 // Use the hostname if no name parameter was given
38 if (strcmp(net_name, "") == 0) {
39 GetHostName(net_name, JACK_CLIENT_NAME_SIZE);
42 fParams.fMtu = mtu;
43 fParams.fSendMidiChannels = midi_input_ports;
44 fParams.fReturnMidiChannels = midi_output_ports;
45 if (celt_encoding > 0) {
46 fParams.fSampleEncoder = JackCeltEncoder;
47 fParams.fKBps = celt_encoding;
48 } else {
49 fParams.fSampleEncoder = JackFloatEncoder;
50 //fParams.fSampleEncoder = JackIntEncoder;
52 strcpy(fParams.fName, net_name);
53 fSocket.GetName(fParams.fSlaveNetName);
54 fParams.fTransportSync = transport_sync;
55 fParams.fNetworkLatency = network_latency;
56 fSendTransportData.fState = -1;
57 fReturnTransportData.fState = -1;
58 fLastTransportState = -1;
59 fLastTimebaseMaster = -1;
60 fMidiCapturePortList = NULL;
61 fMidiPlaybackPortList = NULL;
62 #ifdef JACK_MONITOR
63 fNetTimeMon = NULL;
64 fRcvSyncUst = 0;
65 #endif
68 JackNetDriver::~JackNetDriver()
70 delete[] fMidiCapturePortList;
71 delete[] fMidiPlaybackPortList;
72 #ifdef JACK_MONITOR
73 delete fNetTimeMon;
74 #endif
77 //open, close, attach and detach------------------------------------------------------
79 int JackNetDriver::Close()
81 #ifdef JACK_MONITOR
82 if (fNetTimeMon) {
83 fNetTimeMon->Save();
85 #endif
86 FreeAll();
87 return JackWaiterDriver::Close();
90 // Attach and Detach are defined as empty methods: port allocation is done when driver actually start (that is in Init)
91 int JackNetDriver::Attach()
93 return 0;
96 int JackNetDriver::Detach()
98 return 0;
101 //init and restart--------------------------------------------------------------------
103 JackNetDriver is wrapped in a JackWaitThreadedDriver decorator that behaves
104 as a "dummy driver, until Init method returns.
107 bool JackNetDriver::Initialize()
109 jack_log("JackNetDriver::Initialize");
110 SaveConnections();
111 FreePorts();
113 // New loading, but existing socket, restart the driver
114 if (fSocket.IsSocket()) {
115 jack_info("Restarting driver...");
116 FreeAll();
119 // Set the parameters to send
120 fParams.fSendAudioChannels = fCaptureChannels;
121 fParams.fReturnAudioChannels = fPlaybackChannels;
122 fParams.fSlaveSyncMode = fEngineControl->fSyncMode;
124 // Display some additional infos
125 jack_info("NetDriver started in %s mode %s Master's transport sync.",
126 (fParams.fSlaveSyncMode) ? "sync" : "async", (fParams.fTransportSync) ? "with" : "without");
128 // Init network
129 if (!JackNetSlaveInterface::Init()) {
130 jack_error("Starting network fails...");
131 return false;
134 // Set global parameters
135 if (!SetParams()) {
136 jack_error("SetParams error...");
137 return false;
140 // If -1 at connection time, in/out channels count is sent by the master
141 fCaptureChannels = fParams.fSendAudioChannels;
142 fPlaybackChannels = fParams.fReturnAudioChannels;
144 // Allocate midi ports lists
145 fMidiCapturePortList = new jack_port_id_t [fParams.fSendMidiChannels];
146 fMidiPlaybackPortList = new jack_port_id_t [fParams.fReturnMidiChannels];
148 assert(fMidiCapturePortList);
149 assert(fMidiPlaybackPortList);
151 for (int midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
152 fMidiCapturePortList[midi_port_index] = 0;
154 for (int midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
155 fMidiPlaybackPortList[midi_port_index] = 0;
158 // Register jack ports
159 if (AllocPorts() != 0) {
160 jack_error("Can't allocate ports.");
161 return false;
164 // Init done, display parameters
165 SessionParamsDisplay(&fParams);
167 // Monitor
168 #ifdef JACK_MONITOR
169 string plot_name;
170 // NetTimeMon
171 plot_name = string(fParams.fName);
172 plot_name += string("_slave");
173 plot_name += (fEngineControl->fSyncMode) ? string("_sync") : string("_async");
174 plot_name += string("_latency");
175 fNetTimeMon = new JackGnuPlotMonitor<float>(128, 5, plot_name);
176 string net_time_mon_fields[] =
178 string("sync decoded"),
179 string("end of read"),
180 string("start of write"),
181 string("sync send"),
182 string("end of write")
184 string net_time_mon_options[] =
186 string("set xlabel \"audio cycles\""),
187 string("set ylabel \"% of audio cycle\"")
189 fNetTimeMon->SetPlotFile(net_time_mon_options, 2, net_time_mon_fields, 5);
190 #endif
191 // Driver parametering
192 JackTimedDriver::SetBufferSize(fParams.fPeriodSize);
193 JackTimedDriver::SetSampleRate(fParams.fSampleRate);
195 JackDriver::NotifyBufferSize(fParams.fPeriodSize);
196 JackDriver::NotifySampleRate(fParams.fSampleRate);
198 // Transport engine parametering
199 fEngineControl->fTransport.SetNetworkSync(fParams.fTransportSync);
201 RestoreConnections();
202 return true;
205 void JackNetDriver::FreeAll()
207 FreePorts();
209 delete[] fTxBuffer;
210 delete[] fRxBuffer;
211 delete fNetAudioCaptureBuffer;
212 delete fNetAudioPlaybackBuffer;
213 delete fNetMidiCaptureBuffer;
214 delete fNetMidiPlaybackBuffer;
215 delete[] fMidiCapturePortList;
216 delete[] fMidiPlaybackPortList;
218 fTxBuffer = NULL;
219 fRxBuffer = NULL;
220 fNetAudioCaptureBuffer = NULL;
221 fNetAudioPlaybackBuffer = NULL;
222 fNetMidiCaptureBuffer = NULL;
223 fNetMidiPlaybackBuffer = NULL;
224 fMidiCapturePortList = NULL;
225 fMidiPlaybackPortList = NULL;
227 #ifdef JACK_MONITOR
228 delete fNetTimeMon;
229 fNetTimeMon = NULL;
230 #endif
233 //jack ports and buffers--------------------------------------------------------------
234 int JackNetDriver::AllocPorts()
236 jack_log("JackNetDriver::AllocPorts fBufferSize = %ld fSampleRate = %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate);
239 fNetAudioCaptureBuffer fNetAudioPlaybackBuffer
240 fSendAudioChannels fReturnAudioChannels
242 fCapturePortList fPlaybackPortList
243 fCaptureChannels ==> SLAVE ==> fPlaybackChannels
244 "capture_" "playback_"
247 JackPort* port;
248 jack_port_id_t port_index;
249 char name[REAL_JACK_PORT_NAME_SIZE];
250 char alias[REAL_JACK_PORT_NAME_SIZE];
251 int audio_port_index;
252 int midi_port_index;
253 jack_latency_range_t range;
255 //audio
256 for (audio_port_index = 0; audio_port_index < fCaptureChannels; audio_port_index++) {
257 snprintf(alias, sizeof(alias), "%s:%s:out%d", fAliasName, fCaptureDriverName, audio_port_index + 1);
258 snprintf(name, sizeof(name), "%s:capture_%d", fClientControl.fName, audio_port_index + 1);
259 if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE,
260 CaptureDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) {
261 jack_error("driver: cannot register port for %s", name);
262 return -1;
265 //port latency
266 port = fGraphManager->GetPort(port_index);
267 port->SetAlias(alias);
268 range.min = range.max = fEngineControl->fBufferSize;
269 port->SetLatencyRange(JackCaptureLatency, &range);
270 fCapturePortList[audio_port_index] = port_index;
271 jack_log("JackNetDriver::AllocPorts() fCapturePortList[%d] audio_port_index = %ld fPortLatency = %ld", audio_port_index, port_index, port->GetLatency());
274 for (audio_port_index = 0; audio_port_index < fPlaybackChannels; audio_port_index++) {
275 snprintf(alias, sizeof(alias), "%s:%s:in%d", fAliasName, fPlaybackDriverName, audio_port_index + 1);
276 snprintf(name, sizeof(name), "%s:playback_%d",fClientControl.fName, audio_port_index + 1);
277 if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE,
278 PlaybackDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) {
279 jack_error("driver: cannot register port for %s", name);
280 return -1;
283 //port latency
284 port = fGraphManager->GetPort(port_index);
285 port->SetAlias(alias);
286 range.min = range.max = (fParams.fNetworkLatency * fEngineControl->fBufferSize + (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize);
287 port->SetLatencyRange(JackPlaybackLatency, &range);
288 fPlaybackPortList[audio_port_index] = port_index;
289 jack_log("JackNetDriver::AllocPorts() fPlaybackPortList[%d] audio_port_index = %ld fPortLatency = %ld", audio_port_index, port_index, port->GetLatency());
292 //midi
293 for (midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
294 snprintf(alias, sizeof(alias), "%s:%s:out%d", fAliasName, fCaptureDriverName, midi_port_index + 1);
295 snprintf(name, sizeof (name), "%s:midi_capture_%d", fClientControl.fName, midi_port_index + 1);
296 if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_MIDI_TYPE,
297 CaptureDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) {
298 jack_error("driver: cannot register port for %s", name);
299 return -1;
302 //port latency
303 port = fGraphManager->GetPort(port_index);
304 range.min = range.max = fEngineControl->fBufferSize;
305 port->SetLatencyRange(JackCaptureLatency, &range);
306 fMidiCapturePortList[midi_port_index] = port_index;
307 jack_log("JackNetDriver::AllocPorts() fMidiCapturePortList[%d] midi_port_index = %ld fPortLatency = %ld", midi_port_index, port_index, port->GetLatency());
310 for (midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
311 snprintf(alias, sizeof(alias), "%s:%s:in%d", fAliasName, fPlaybackDriverName, midi_port_index + 1);
312 snprintf(name, sizeof(name), "%s:midi_playback_%d", fClientControl.fName, midi_port_index + 1);
313 if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_MIDI_TYPE,
314 PlaybackDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) {
315 jack_error("driver: cannot register port for %s", name);
316 return -1;
319 //port latency
320 port = fGraphManager->GetPort(port_index);
321 range.min = range.max = (fParams.fNetworkLatency * fEngineControl->fBufferSize + (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize);
322 port->SetLatencyRange(JackPlaybackLatency, &range);
323 fMidiPlaybackPortList[midi_port_index] = port_index;
324 jack_log("JackNetDriver::AllocPorts() fMidiPlaybackPortList[%d] midi_port_index = %ld fPortLatency = %ld", midi_port_index, port_index, port->GetLatency());
327 return 0;
330 int JackNetDriver::FreePorts()
332 jack_log("JackNetDriver::FreePorts");
334 for (int audio_port_index = 0; audio_port_index < fCaptureChannels; audio_port_index++) {
335 if (fCapturePortList[audio_port_index] > 0) {
336 fEngine->PortUnRegister(fClientControl.fRefNum, fCapturePortList[audio_port_index]);
337 fCapturePortList[audio_port_index] = 0;
341 for (int audio_port_index = 0; audio_port_index < fPlaybackChannels; audio_port_index++) {
342 if (fPlaybackPortList[audio_port_index] > 0) {
343 fEngine->PortUnRegister(fClientControl.fRefNum, fPlaybackPortList[audio_port_index]);
344 fPlaybackPortList[audio_port_index] = 0;
348 for (int midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
349 if (fMidiCapturePortList && fMidiCapturePortList[midi_port_index] > 0) {
350 fGraphManager->ReleasePort(fClientControl.fRefNum, fMidiCapturePortList[midi_port_index]);
351 fMidiCapturePortList[midi_port_index] = 0;
355 for (int midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
356 if (fMidiPlaybackPortList && fMidiPlaybackPortList[midi_port_index] > 0) {
357 fEngine->PortUnRegister(fClientControl.fRefNum, fMidiPlaybackPortList[midi_port_index]);
358 fMidiPlaybackPortList[midi_port_index] = 0;
361 return 0;
364 void JackNetDriver::SaveConnections()
366 JackDriver::SaveConnections();
367 const char** connections;
369 for (int i = 0; i < fParams.fSendMidiChannels; ++i) {
370 if (fCapturePortList[i] && (connections = fGraphManager->GetConnections(fMidiCapturePortList[i])) != 0) {
371 for (int j = 0; connections[j]; j++) {
372 fConnections.push_back(make_pair(fGraphManager->GetPort(fMidiCapturePortList[i])->GetName(), connections[j]));
374 free(connections);
378 for (int i = 0; i < fParams.fReturnMidiChannels; ++i) {
379 if (fPlaybackPortList[i] && (connections = fGraphManager->GetConnections(fMidiPlaybackPortList[i])) != 0) {
380 for (int j = 0; connections[j]; j++) {
381 fConnections.push_back(make_pair(connections[j], fGraphManager->GetPort(fMidiPlaybackPortList[i])->GetName()));
383 free(connections);
388 JackMidiBuffer* JackNetDriver::GetMidiInputBuffer(int port_index)
390 return static_cast<JackMidiBuffer*>(fGraphManager->GetBuffer(fMidiCapturePortList[port_index], fEngineControl->fBufferSize));
393 JackMidiBuffer* JackNetDriver::GetMidiOutputBuffer(int port_index)
395 return static_cast<JackMidiBuffer*>(fGraphManager->GetBuffer(fMidiPlaybackPortList[port_index], fEngineControl->fBufferSize));
398 //transport---------------------------------------------------------------------------
399 void JackNetDriver::DecodeTransportData()
401 //is there a new timebase master on the net master ?
402 // - release timebase master only if it's a non-conditional request
403 // - no change or no request : don't do anything
404 // - conditional request : don't change anything too, the master will know if this slave is actually the timebase master
405 int refnum;
406 bool conditional;
407 if (fSendTransportData.fTimebaseMaster == TIMEBASEMASTER) {
408 fEngineControl->fTransport.GetTimebaseMaster(refnum, conditional);
409 if (refnum != -1) {
410 fEngineControl->fTransport.ResetTimebase(refnum);
412 jack_info("The NetMaster is now the new timebase master.");
415 //is there a transport state change to handle ?
416 if (fSendTransportData.fNewState &&(fSendTransportData.fState != fEngineControl->fTransport.GetState())) {
418 switch (fSendTransportData.fState)
420 case JackTransportStopped :
421 fEngineControl->fTransport.SetCommand(TransportCommandStop);
422 jack_info("Master stops transport.");
423 break;
425 case JackTransportStarting :
426 fEngineControl->fTransport.RequestNewPos(&fSendTransportData.fPosition);
427 fEngineControl->fTransport.SetCommand(TransportCommandStart);
428 jack_info("Master starts transport frame = %d", fSendTransportData.fPosition.frame);
429 break;
431 case JackTransportRolling :
432 //fEngineControl->fTransport.SetCommand(TransportCommandStart);
433 fEngineControl->fTransport.SetState(JackTransportRolling);
434 jack_info("Master is rolling.");
435 break;
440 void JackNetDriver::EncodeTransportData()
442 //is there a timebase master change ?
443 int refnum;
444 bool conditional;
445 fEngineControl->fTransport.GetTimebaseMaster(refnum, conditional);
446 if (refnum != fLastTimebaseMaster) {
447 //timebase master has released its function
448 if (refnum == -1) {
449 fReturnTransportData.fTimebaseMaster = RELEASE_TIMEBASEMASTER;
450 jack_info("Sending a timebase master release request.");
451 } else {
452 //there is a new timebase master
453 fReturnTransportData.fTimebaseMaster = (conditional) ? CONDITIONAL_TIMEBASEMASTER : TIMEBASEMASTER;
454 jack_info("Sending a %s timebase master request.", (conditional) ? "conditional" : "non-conditional");
456 fLastTimebaseMaster = refnum;
457 } else {
458 fReturnTransportData.fTimebaseMaster = NO_CHANGE;
461 //update transport state and position
462 fReturnTransportData.fState = fEngineControl->fTransport.Query(&fReturnTransportData.fPosition);
464 //is it a new state (that the master need to know...) ?
465 fReturnTransportData.fNewState = ((fReturnTransportData.fState == JackTransportNetStarting) &&
466 (fReturnTransportData.fState != fLastTransportState) &&
467 (fReturnTransportData.fState != fSendTransportData.fState));
468 if (fReturnTransportData.fNewState) {
469 jack_info("Sending '%s'.", GetTransportState(fReturnTransportData.fState));
471 fLastTransportState = fReturnTransportData.fState;
474 //driver processes--------------------------------------------------------------------
476 int JackNetDriver::Read()
478 //buffers
479 for (int midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
480 fNetMidiCaptureBuffer->SetBuffer(midi_port_index, GetMidiInputBuffer(midi_port_index));
483 for (int audio_port_index = 0; audio_port_index < fParams.fSendAudioChannels; audio_port_index++) {
484 #ifdef OPTIMIZED_PROTOCOL
485 if (fGraphManager->GetConnectionsNum(fCapturePortList[audio_port_index]) > 0) {
486 fNetAudioCaptureBuffer->SetBuffer(audio_port_index, GetInputBuffer(audio_port_index));
487 } else {
488 fNetAudioCaptureBuffer->SetBuffer(audio_port_index, NULL);
490 #else
491 fNetAudioCaptureBuffer->SetBuffer(audio_port_index, GetInputBuffer(audio_port_index));
492 #endif
495 #ifdef JACK_MONITOR
496 fNetTimeMon->New();
497 #endif
499 //receive sync (launch the cycle)
500 if (SyncRecv() == SOCKET_ERROR) {
501 return SOCKET_ERROR;
504 #ifdef JACK_MONITOR
505 // For timing
506 fRcvSyncUst = GetMicroSeconds();
507 #endif
509 //decode sync
510 //if there is an error, don't return -1, it will skip Write() and the network error probably won't be identified
511 DecodeSyncPacket();
513 #ifdef JACK_MONITOR
514 fNetTimeMon->Add(float(GetMicroSeconds() - fRcvSyncUst) / float(fEngineControl->fPeriodUsecs) * 100.f);
515 #endif
516 //audio, midi or sync if driver is late
517 int res = DataRecv();
518 if (res == SOCKET_ERROR) {
519 return SOCKET_ERROR;
520 } else if (res == NET_PACKET_ERROR) {
521 jack_time_t cur_time = GetMicroSeconds();
522 NotifyXRun(cur_time, float(cur_time - fBeginDateUst)); // Better this value than nothing...
525 //take the time at the beginning of the cycle
526 JackDriver::CycleTakeBeginTime();
528 #ifdef JACK_MONITOR
529 fNetTimeMon->Add(float(GetMicroSeconds() - fRcvSyncUst) / float(fEngineControl->fPeriodUsecs) * 100.f);
530 #endif
532 return 0;
535 int JackNetDriver::Write()
537 //buffers
538 for (int midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
539 fNetMidiPlaybackBuffer->SetBuffer(midi_port_index, GetMidiOutputBuffer(midi_port_index));
542 for (int audio_port_index = 0; audio_port_index < fPlaybackChannels; audio_port_index++) {
543 #ifdef OPTIMIZED_PROTOCOL
544 // Port is connected on other side...
545 if (fNetAudioPlaybackBuffer->GetConnected(audio_port_index)) {
546 if (fGraphManager->GetConnectionsNum(fPlaybackPortList[audio_port_index]) > 0) {
547 fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, GetOutputBuffer(audio_port_index));
548 } else {
549 fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, NULL);
551 } else {
552 fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, NULL);
554 #else
555 fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, GetOutputBuffer(audio_port_index));
556 #endif
559 #ifdef JACK_MONITOR
560 fNetTimeMon->AddLast(float(GetMicroSeconds() - fRcvSyncUst) / float(fEngineControl->fPeriodUsecs) * 100.f);
561 #endif
563 //sync
564 EncodeSyncPacket();
566 //send sync
567 if (SyncSend() == SOCKET_ERROR) {
568 return SOCKET_ERROR;
571 #ifdef JACK_MONITOR
572 fNetTimeMon->Add(((float)(GetMicroSeconds() - fRcvSyncUst) / (float)fEngineControl->fPeriodUsecs) * 100.f);
573 #endif
575 //send data
576 if (DataSend() == SOCKET_ERROR) {
577 return SOCKET_ERROR;
580 #ifdef JACK_MONITOR
581 fNetTimeMon->AddLast(((float)(GetMicroSeconds() - fRcvSyncUst) / (float)fEngineControl->fPeriodUsecs) * 100.f);
582 #endif
584 return 0;
587 //driver loader-----------------------------------------------------------------------
589 #ifdef __cplusplus
590 extern "C"
592 #endif
594 SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor()
596 jack_driver_desc_t * desc;
597 jack_driver_desc_filler_t filler;
598 jack_driver_param_value_t value;
600 desc = jack_driver_descriptor_construct("net", JackDriverMaster, "netjack slave backend component", &filler);
602 strcpy(value.str, DEFAULT_MULTICAST_IP);
603 jack_driver_descriptor_add_parameter(desc, &filler, "multicast-ip", 'a', JackDriverParamString, &value, NULL, "Multicast address, or explicit IP of the master", NULL);
605 value.i = DEFAULT_PORT;
606 jack_driver_descriptor_add_parameter(desc, &filler, "udp-net-port", 'p', JackDriverParamInt, &value, NULL, "UDP port", NULL);
608 value.i = DEFAULT_MTU;
609 jack_driver_descriptor_add_parameter(desc, &filler, "mtu", 'M', JackDriverParamInt, &value, NULL, "MTU to the master", NULL);
611 value.i = -1;
612 jack_driver_descriptor_add_parameter(desc, &filler, "input-ports", 'C', JackDriverParamInt, &value, NULL, "Number of audio input ports", "Number of audio input ports. If -1, audio physical input from the master");
613 jack_driver_descriptor_add_parameter(desc, &filler, "output-ports", 'P', JackDriverParamInt, &value, NULL, "Number of audio output ports", "Number of audio output ports. If -1, audio physical output from the master");
615 value.i = 0;
616 jack_driver_descriptor_add_parameter(desc, &filler, "midi-in-ports", 'i', JackDriverParamInt, &value, NULL, "Number of midi input ports", NULL);
617 jack_driver_descriptor_add_parameter(desc, &filler, "midi-out-ports", 'o', JackDriverParamInt, &value, NULL, "Number of midi output ports", NULL);
619 #if HAVE_CELT
620 value.i = -1;
621 jack_driver_descriptor_add_parameter(desc, &filler, "celt", 'c', JackDriverParamInt, &value, NULL, "Set CELT encoding and number of kBits per channel", NULL);
622 #endif
623 strcpy(value.str, "'hostname'");
624 jack_driver_descriptor_add_parameter(desc, &filler, "client-name", 'n', JackDriverParamString, &value, NULL, "Name of the jack client", NULL);
627 Deactivated for now..
628 value.ui = 0U;
629 jack_driver_descriptor_add_parameter(desc, &filler, "transport-sync", 't', JackDriverParamUInt, &value, NULL, "Sync transport with master's", NULL);
632 value.ui = 5U;
633 jack_driver_descriptor_add_parameter(desc, &filler, "latency", 'l', JackDriverParamUInt, &value, NULL, "Network latency", NULL);
635 return desc;
638 SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
640 char multicast_ip[32];
641 char net_name[JACK_CLIENT_NAME_SIZE + 1];
642 int udp_port;
643 int mtu = DEFAULT_MTU;
644 // Desactivated for now...
645 uint transport_sync = 0;
646 jack_nframes_t period_size = 1024;
647 jack_nframes_t sample_rate = 48000;
648 int audio_capture_ports = -1;
649 int audio_playback_ports = -1;
650 int midi_input_ports = 0;
651 int midi_output_ports = 0;
652 int celt_encoding = -1;
653 bool monitor = false;
654 int network_latency = 5;
655 const JSList* node;
656 const jack_driver_param_t* param;
658 net_name[0] = 0;
660 // Possibly use env variable
661 const char* default_udp_port = getenv("JACK_NETJACK_PORT");
662 udp_port = (default_udp_port) ? atoi(default_udp_port) : DEFAULT_PORT;
664 const char* default_multicast_ip = getenv("JACK_NETJACK_MULTICAST");
665 if (default_multicast_ip) {
666 strcpy(multicast_ip, default_multicast_ip);
667 } else {
668 strcpy(multicast_ip, DEFAULT_MULTICAST_IP);
671 for (node = params; node; node = jack_slist_next(node)) {
672 param = (const jack_driver_param_t*) node->data;
673 switch (param->character)
675 case 'a' :
676 assert(strlen(param->value.str) < 32);
677 strcpy(multicast_ip, param->value.str);
678 break;
679 case 'p':
680 udp_port = param->value.ui;
681 break;
682 case 'M':
683 mtu = param->value.i;
684 break;
685 case 'C':
686 audio_capture_ports = param->value.i;
687 break;
688 case 'P':
689 audio_playback_ports = param->value.i;
690 break;
691 case 'i':
692 midi_input_ports = param->value.i;
693 break;
694 case 'o':
695 midi_output_ports = param->value.i;
696 break;
697 #if HAVE_CELT
698 case 'c':
699 celt_encoding = param->value.i;
700 break;
701 #endif
702 case 'n' :
703 strncpy(net_name, param->value.str, JACK_CLIENT_NAME_SIZE);
704 break;
706 Deactivated for now..
707 case 't' :
708 transport_sync = param->value.ui;
709 break;
711 case 'l' :
712 network_latency = param->value.ui;
713 if (network_latency > NETWORK_MAX_LATENCY) {
714 printf("Error : network latency is limited to %d\n", NETWORK_MAX_LATENCY);
715 return NULL;
717 break;
721 try {
723 Jack::JackDriverClientInterface* driver = new Jack::JackWaitThreadedDriver(
724 new Jack::JackNetDriver("system", "net_pcm", engine, table, multicast_ip, udp_port, mtu,
725 midi_input_ports, midi_output_ports,
726 net_name, transport_sync,
727 network_latency, celt_encoding));
728 if (driver->Open(period_size, sample_rate, 1, 1, audio_capture_ports, audio_playback_ports, monitor, "from_master_", "to_master_", 0, 0) == 0) {
729 return driver;
730 } else {
731 delete driver;
732 return NULL;
735 } catch (...) {
736 return NULL;
740 #ifdef __cplusplus
742 #endif