Merge pull request #23 from jackaudio/device_reservation_fixes
[jack2.git] / common / JackNetDriver.cpp
blob12019ba0111500948507f001dd8b7007608aac77
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, int opus_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 if (opus_encoding > 0) {
49 fParams.fSampleEncoder = JackOpusEncoder;
50 fParams.fKBps = opus_encoding;
51 } else {
52 fParams.fSampleEncoder = JackFloatEncoder;
53 //fParams.fSampleEncoder = JackIntEncoder;
55 strcpy(fParams.fName, net_name);
56 fSocket.GetName(fParams.fSlaveNetName);
57 fParams.fTransportSync = transport_sync;
58 fParams.fNetworkLatency = network_latency;
59 fSendTransportData.fState = -1;
60 fReturnTransportData.fState = -1;
61 fLastTransportState = -1;
62 fLastTimebaseMaster = -1;
63 fMidiCapturePortList = NULL;
64 fMidiPlaybackPortList = NULL;
65 #ifdef JACK_MONITOR
66 fNetTimeMon = NULL;
67 fRcvSyncUst = 0;
68 #endif
71 JackNetDriver::~JackNetDriver()
73 delete[] fMidiCapturePortList;
74 delete[] fMidiPlaybackPortList;
75 #ifdef JACK_MONITOR
76 delete fNetTimeMon;
77 #endif
80 //open, close, attach and detach------------------------------------------------------
82 int JackNetDriver::Close()
84 #ifdef JACK_MONITOR
85 if (fNetTimeMon) {
86 fNetTimeMon->Save();
88 #endif
89 FreeAll();
90 return JackWaiterDriver::Close();
93 // Attach and Detach are defined as empty methods: port allocation is done when driver actually start (that is in Init)
94 int JackNetDriver::Attach()
96 return 0;
99 int JackNetDriver::Detach()
101 return 0;
104 //init and restart--------------------------------------------------------------------
106 JackNetDriver is wrapped in a JackWaitThreadedDriver decorator that behaves
107 as a "dummy driver, until Init method returns.
110 bool JackNetDriver::Initialize()
112 jack_log("JackNetDriver::Initialize");
113 SaveConnections();
114 FreePorts();
116 // New loading, but existing socket, restart the driver
117 if (fSocket.IsSocket()) {
118 jack_info("Restarting driver...");
119 FreeAll();
122 // Set the parameters to send
123 fParams.fSendAudioChannels = fCaptureChannels;
124 fParams.fReturnAudioChannels = fPlaybackChannels;
125 fParams.fSlaveSyncMode = fEngineControl->fSyncMode;
127 // Display some additional infos
128 jack_info("NetDriver started in %s mode %s Master's transport sync.",
129 (fParams.fSlaveSyncMode) ? "sync" : "async", (fParams.fTransportSync) ? "with" : "without");
131 // Init network
132 if (!JackNetSlaveInterface::Init()) {
133 jack_error("Starting network fails...");
134 return false;
137 // Set global parameters
138 if (!SetParams()) {
139 jack_error("SetParams error...");
140 return false;
143 // If -1 at connection time, in/out channels count is sent by the master
144 fCaptureChannels = fParams.fSendAudioChannels;
145 fPlaybackChannels = fParams.fReturnAudioChannels;
147 // Allocate midi ports lists
148 fMidiCapturePortList = new jack_port_id_t [fParams.fSendMidiChannels];
149 fMidiPlaybackPortList = new jack_port_id_t [fParams.fReturnMidiChannels];
151 assert(fMidiCapturePortList);
152 assert(fMidiPlaybackPortList);
154 for (int midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
155 fMidiCapturePortList[midi_port_index] = 0;
157 for (int midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
158 fMidiPlaybackPortList[midi_port_index] = 0;
161 // Register jack ports
162 if (AllocPorts() != 0) {
163 jack_error("Can't allocate ports.");
164 return false;
167 // Init done, display parameters
168 SessionParamsDisplay(&fParams);
170 // Monitor
171 #ifdef JACK_MONITOR
172 string plot_name;
173 // NetTimeMon
174 plot_name = string(fParams.fName);
175 plot_name += string("_slave");
176 plot_name += (fEngineControl->fSyncMode) ? string("_sync") : string("_async");
177 plot_name += string("_latency");
178 fNetTimeMon = new JackGnuPlotMonitor<float>(128, 5, plot_name);
179 string net_time_mon_fields[] =
181 string("sync decoded"),
182 string("end of read"),
183 string("start of write"),
184 string("sync send"),
185 string("end of write")
187 string net_time_mon_options[] =
189 string("set xlabel \"audio cycles\""),
190 string("set ylabel \"% of audio cycle\"")
192 fNetTimeMon->SetPlotFile(net_time_mon_options, 2, net_time_mon_fields, 5);
193 #endif
194 // Driver parametering
195 JackTimedDriver::SetBufferSize(fParams.fPeriodSize);
196 JackTimedDriver::SetSampleRate(fParams.fSampleRate);
198 JackDriver::NotifyBufferSize(fParams.fPeriodSize);
199 JackDriver::NotifySampleRate(fParams.fSampleRate);
201 // Transport engine parametering
202 fEngineControl->fTransport.SetNetworkSync(fParams.fTransportSync);
204 RestoreConnections();
205 return true;
208 void JackNetDriver::FreeAll()
210 FreePorts();
212 delete[] fTxBuffer;
213 delete[] fRxBuffer;
214 delete fNetAudioCaptureBuffer;
215 delete fNetAudioPlaybackBuffer;
216 delete fNetMidiCaptureBuffer;
217 delete fNetMidiPlaybackBuffer;
218 delete[] fMidiCapturePortList;
219 delete[] fMidiPlaybackPortList;
221 fTxBuffer = NULL;
222 fRxBuffer = NULL;
223 fNetAudioCaptureBuffer = NULL;
224 fNetAudioPlaybackBuffer = NULL;
225 fNetMidiCaptureBuffer = NULL;
226 fNetMidiPlaybackBuffer = NULL;
227 fMidiCapturePortList = NULL;
228 fMidiPlaybackPortList = NULL;
230 #ifdef JACK_MONITOR
231 delete fNetTimeMon;
232 fNetTimeMon = NULL;
233 #endif
236 //jack ports and buffers--------------------------------------------------------------
237 int JackNetDriver::AllocPorts()
239 jack_log("JackNetDriver::AllocPorts fBufferSize = %ld fSampleRate = %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate);
242 fNetAudioCaptureBuffer fNetAudioPlaybackBuffer
243 fSendAudioChannels fReturnAudioChannels
245 fCapturePortList fPlaybackPortList
246 fCaptureChannels ==> SLAVE ==> fPlaybackChannels
247 "capture_" "playback_"
250 JackPort* port;
251 jack_port_id_t port_index;
252 char name[REAL_JACK_PORT_NAME_SIZE];
253 char alias[REAL_JACK_PORT_NAME_SIZE];
254 int audio_port_index;
255 int midi_port_index;
256 jack_latency_range_t range;
258 //audio
259 for (audio_port_index = 0; audio_port_index < fCaptureChannels; audio_port_index++) {
260 snprintf(alias, sizeof(alias), "%s:%s:out%d", fAliasName, fCaptureDriverName, audio_port_index + 1);
261 snprintf(name, sizeof(name), "%s:capture_%d", fClientControl.fName, audio_port_index + 1);
262 if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE,
263 CaptureDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) {
264 jack_error("driver: cannot register port for %s", name);
265 return -1;
268 //port latency
269 port = fGraphManager->GetPort(port_index);
270 port->SetAlias(alias);
271 range.min = range.max = fEngineControl->fBufferSize;
272 port->SetLatencyRange(JackCaptureLatency, &range);
273 fCapturePortList[audio_port_index] = port_index;
274 jack_log("JackNetDriver::AllocPorts() fCapturePortList[%d] audio_port_index = %ld fPortLatency = %ld", audio_port_index, port_index, port->GetLatency());
277 for (audio_port_index = 0; audio_port_index < fPlaybackChannels; audio_port_index++) {
278 snprintf(alias, sizeof(alias), "%s:%s:in%d", fAliasName, fPlaybackDriverName, audio_port_index + 1);
279 snprintf(name, sizeof(name), "%s:playback_%d",fClientControl.fName, audio_port_index + 1);
280 if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE,
281 PlaybackDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) {
282 jack_error("driver: cannot register port for %s", name);
283 return -1;
286 //port latency
287 port = fGraphManager->GetPort(port_index);
288 port->SetAlias(alias);
289 range.min = range.max = (fParams.fNetworkLatency * fEngineControl->fBufferSize + (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize);
290 port->SetLatencyRange(JackPlaybackLatency, &range);
291 fPlaybackPortList[audio_port_index] = port_index;
292 jack_log("JackNetDriver::AllocPorts() fPlaybackPortList[%d] audio_port_index = %ld fPortLatency = %ld", audio_port_index, port_index, port->GetLatency());
295 //midi
296 for (midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
297 snprintf(alias, sizeof(alias), "%s:%s:out%d", fAliasName, fCaptureDriverName, midi_port_index + 1);
298 snprintf(name, sizeof (name), "%s:midi_capture_%d", fClientControl.fName, midi_port_index + 1);
299 if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_MIDI_TYPE,
300 CaptureDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) {
301 jack_error("driver: cannot register port for %s", name);
302 return -1;
305 //port latency
306 port = fGraphManager->GetPort(port_index);
307 range.min = range.max = fEngineControl->fBufferSize;
308 port->SetLatencyRange(JackCaptureLatency, &range);
309 fMidiCapturePortList[midi_port_index] = port_index;
310 jack_log("JackNetDriver::AllocPorts() fMidiCapturePortList[%d] midi_port_index = %ld fPortLatency = %ld", midi_port_index, port_index, port->GetLatency());
313 for (midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
314 snprintf(alias, sizeof(alias), "%s:%s:in%d", fAliasName, fPlaybackDriverName, midi_port_index + 1);
315 snprintf(name, sizeof(name), "%s:midi_playback_%d", fClientControl.fName, midi_port_index + 1);
316 if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_MIDI_TYPE,
317 PlaybackDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) {
318 jack_error("driver: cannot register port for %s", name);
319 return -1;
322 //port latency
323 port = fGraphManager->GetPort(port_index);
324 range.min = range.max = (fParams.fNetworkLatency * fEngineControl->fBufferSize + (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize);
325 port->SetLatencyRange(JackPlaybackLatency, &range);
326 fMidiPlaybackPortList[midi_port_index] = port_index;
327 jack_log("JackNetDriver::AllocPorts() fMidiPlaybackPortList[%d] midi_port_index = %ld fPortLatency = %ld", midi_port_index, port_index, port->GetLatency());
330 return 0;
333 int JackNetDriver::FreePorts()
335 jack_log("JackNetDriver::FreePorts");
337 for (int audio_port_index = 0; audio_port_index < fCaptureChannels; audio_port_index++) {
338 if (fCapturePortList[audio_port_index] > 0) {
339 fEngine->PortUnRegister(fClientControl.fRefNum, fCapturePortList[audio_port_index]);
340 fCapturePortList[audio_port_index] = 0;
344 for (int audio_port_index = 0; audio_port_index < fPlaybackChannels; audio_port_index++) {
345 if (fPlaybackPortList[audio_port_index] > 0) {
346 fEngine->PortUnRegister(fClientControl.fRefNum, fPlaybackPortList[audio_port_index]);
347 fPlaybackPortList[audio_port_index] = 0;
351 for (int midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
352 if (fMidiCapturePortList && fMidiCapturePortList[midi_port_index] > 0) {
353 fGraphManager->ReleasePort(fClientControl.fRefNum, fMidiCapturePortList[midi_port_index]);
354 fMidiCapturePortList[midi_port_index] = 0;
358 for (int midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
359 if (fMidiPlaybackPortList && fMidiPlaybackPortList[midi_port_index] > 0) {
360 fEngine->PortUnRegister(fClientControl.fRefNum, fMidiPlaybackPortList[midi_port_index]);
361 fMidiPlaybackPortList[midi_port_index] = 0;
364 return 0;
367 void JackNetDriver::SaveConnections()
369 JackDriver::SaveConnections();
370 const char** connections;
372 for (int i = 0; i < fParams.fSendMidiChannels; ++i) {
373 if (fCapturePortList[i] && (connections = fGraphManager->GetConnections(fMidiCapturePortList[i])) != 0) {
374 for (int j = 0; connections[j]; j++) {
375 fConnections.push_back(make_pair(fGraphManager->GetPort(fMidiCapturePortList[i])->GetName(), connections[j]));
377 free(connections);
381 for (int i = 0; i < fParams.fReturnMidiChannels; ++i) {
382 if (fPlaybackPortList[i] && (connections = fGraphManager->GetConnections(fMidiPlaybackPortList[i])) != 0) {
383 for (int j = 0; connections[j]; j++) {
384 fConnections.push_back(make_pair(connections[j], fGraphManager->GetPort(fMidiPlaybackPortList[i])->GetName()));
386 free(connections);
391 JackMidiBuffer* JackNetDriver::GetMidiInputBuffer(int port_index)
393 return static_cast<JackMidiBuffer*>(fGraphManager->GetBuffer(fMidiCapturePortList[port_index], fEngineControl->fBufferSize));
396 JackMidiBuffer* JackNetDriver::GetMidiOutputBuffer(int port_index)
398 return static_cast<JackMidiBuffer*>(fGraphManager->GetBuffer(fMidiPlaybackPortList[port_index], fEngineControl->fBufferSize));
401 //transport---------------------------------------------------------------------------
402 void JackNetDriver::DecodeTransportData()
404 //is there a new timebase master on the net master ?
405 // - release timebase master only if it's a non-conditional request
406 // - no change or no request : don't do anything
407 // - conditional request : don't change anything too, the master will know if this slave is actually the timebase master
408 int refnum;
409 bool conditional;
410 if (fSendTransportData.fTimebaseMaster == TIMEBASEMASTER) {
411 fEngineControl->fTransport.GetTimebaseMaster(refnum, conditional);
412 if (refnum != -1) {
413 fEngineControl->fTransport.ResetTimebase(refnum);
415 jack_info("The NetMaster is now the new timebase master.");
418 //is there a transport state change to handle ?
419 if (fSendTransportData.fNewState &&(fSendTransportData.fState != fEngineControl->fTransport.GetState())) {
421 switch (fSendTransportData.fState)
423 case JackTransportStopped :
424 fEngineControl->fTransport.SetCommand(TransportCommandStop);
425 jack_info("Master stops transport.");
426 break;
428 case JackTransportStarting :
429 fEngineControl->fTransport.RequestNewPos(&fSendTransportData.fPosition);
430 fEngineControl->fTransport.SetCommand(TransportCommandStart);
431 jack_info("Master starts transport frame = %d", fSendTransportData.fPosition.frame);
432 break;
434 case JackTransportRolling :
435 //fEngineControl->fTransport.SetCommand(TransportCommandStart);
436 fEngineControl->fTransport.SetState(JackTransportRolling);
437 jack_info("Master is rolling.");
438 break;
443 void JackNetDriver::EncodeTransportData()
445 //is there a timebase master change ?
446 int refnum;
447 bool conditional;
448 fEngineControl->fTransport.GetTimebaseMaster(refnum, conditional);
449 if (refnum != fLastTimebaseMaster) {
450 //timebase master has released its function
451 if (refnum == -1) {
452 fReturnTransportData.fTimebaseMaster = RELEASE_TIMEBASEMASTER;
453 jack_info("Sending a timebase master release request.");
454 } else {
455 //there is a new timebase master
456 fReturnTransportData.fTimebaseMaster = (conditional) ? CONDITIONAL_TIMEBASEMASTER : TIMEBASEMASTER;
457 jack_info("Sending a %s timebase master request.", (conditional) ? "conditional" : "non-conditional");
459 fLastTimebaseMaster = refnum;
460 } else {
461 fReturnTransportData.fTimebaseMaster = NO_CHANGE;
464 //update transport state and position
465 fReturnTransportData.fState = fEngineControl->fTransport.Query(&fReturnTransportData.fPosition);
467 //is it a new state (that the master need to know...) ?
468 fReturnTransportData.fNewState = ((fReturnTransportData.fState == JackTransportNetStarting) &&
469 (fReturnTransportData.fState != fLastTransportState) &&
470 (fReturnTransportData.fState != fSendTransportData.fState));
471 if (fReturnTransportData.fNewState) {
472 jack_info("Sending '%s'.", GetTransportState(fReturnTransportData.fState));
474 fLastTransportState = fReturnTransportData.fState;
477 //driver processes--------------------------------------------------------------------
479 int JackNetDriver::Read()
481 //buffers
482 for (int midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
483 fNetMidiCaptureBuffer->SetBuffer(midi_port_index, GetMidiInputBuffer(midi_port_index));
486 for (int audio_port_index = 0; audio_port_index < fParams.fSendAudioChannels; audio_port_index++) {
487 #ifdef OPTIMIZED_PROTOCOL
488 if (fGraphManager->GetConnectionsNum(fCapturePortList[audio_port_index]) > 0) {
489 fNetAudioCaptureBuffer->SetBuffer(audio_port_index, GetInputBuffer(audio_port_index));
490 } else {
491 fNetAudioCaptureBuffer->SetBuffer(audio_port_index, NULL);
493 #else
494 fNetAudioCaptureBuffer->SetBuffer(audio_port_index, GetInputBuffer(audio_port_index));
495 #endif
498 #ifdef JACK_MONITOR
499 fNetTimeMon->New();
500 #endif
502 //receive sync (launch the cycle)
503 if (SyncRecv() == SOCKET_ERROR) {
504 return SOCKET_ERROR;
507 #ifdef JACK_MONITOR
508 // For timing
509 fRcvSyncUst = GetMicroSeconds();
510 #endif
512 //decode sync
513 //if there is an error, don't return -1, it will skip Write() and the network error probably won't be identified
514 DecodeSyncPacket();
516 #ifdef JACK_MONITOR
517 fNetTimeMon->Add(float(GetMicroSeconds() - fRcvSyncUst) / float(fEngineControl->fPeriodUsecs) * 100.f);
518 #endif
519 //audio, midi or sync if driver is late
520 int res = DataRecv();
521 if (res == SOCKET_ERROR) {
522 return SOCKET_ERROR;
523 } else if (res == NET_PACKET_ERROR) {
524 jack_time_t cur_time = GetMicroSeconds();
525 NotifyXRun(cur_time, float(cur_time - fBeginDateUst)); // Better this value than nothing...
528 //take the time at the beginning of the cycle
529 JackDriver::CycleTakeBeginTime();
531 #ifdef JACK_MONITOR
532 fNetTimeMon->Add(float(GetMicroSeconds() - fRcvSyncUst) / float(fEngineControl->fPeriodUsecs) * 100.f);
533 #endif
535 return 0;
538 int JackNetDriver::Write()
540 //buffers
541 for (int midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
542 fNetMidiPlaybackBuffer->SetBuffer(midi_port_index, GetMidiOutputBuffer(midi_port_index));
545 for (int audio_port_index = 0; audio_port_index < fPlaybackChannels; audio_port_index++) {
546 #ifdef OPTIMIZED_PROTOCOL
547 // Port is connected on other side...
548 if (fNetAudioPlaybackBuffer->GetConnected(audio_port_index)) {
549 if (fGraphManager->GetConnectionsNum(fPlaybackPortList[audio_port_index]) > 0) {
550 fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, GetOutputBuffer(audio_port_index));
551 } else {
552 fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, NULL);
554 } else {
555 fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, NULL);
557 #else
558 fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, GetOutputBuffer(audio_port_index));
559 #endif
562 #ifdef JACK_MONITOR
563 fNetTimeMon->AddLast(float(GetMicroSeconds() - fRcvSyncUst) / float(fEngineControl->fPeriodUsecs) * 100.f);
564 #endif
566 //sync
567 EncodeSyncPacket();
569 //send sync
570 if (SyncSend() == SOCKET_ERROR) {
571 return SOCKET_ERROR;
574 #ifdef JACK_MONITOR
575 fNetTimeMon->Add(((float)(GetMicroSeconds() - fRcvSyncUst) / (float)fEngineControl->fPeriodUsecs) * 100.f);
576 #endif
578 //send data
579 if (DataSend() == SOCKET_ERROR) {
580 return SOCKET_ERROR;
583 #ifdef JACK_MONITOR
584 fNetTimeMon->AddLast(((float)(GetMicroSeconds() - fRcvSyncUst) / (float)fEngineControl->fPeriodUsecs) * 100.f);
585 #endif
587 return 0;
590 //driver loader-----------------------------------------------------------------------
592 #ifdef __cplusplus
593 extern "C"
595 #endif
597 SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor()
599 jack_driver_desc_t * desc;
600 jack_driver_desc_filler_t filler;
601 jack_driver_param_value_t value;
603 desc = jack_driver_descriptor_construct("net", JackDriverMaster, "netjack slave backend component", &filler);
605 strcpy(value.str, DEFAULT_MULTICAST_IP);
606 jack_driver_descriptor_add_parameter(desc, &filler, "multicast-ip", 'a', JackDriverParamString, &value, NULL, "Multicast address, or explicit IP of the master", NULL);
608 value.i = DEFAULT_PORT;
609 jack_driver_descriptor_add_parameter(desc, &filler, "udp-net-port", 'p', JackDriverParamInt, &value, NULL, "UDP port", NULL);
611 value.i = DEFAULT_MTU;
612 jack_driver_descriptor_add_parameter(desc, &filler, "mtu", 'M', JackDriverParamInt, &value, NULL, "MTU to the master", NULL);
614 value.i = -1;
615 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");
616 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");
618 value.i = 0;
619 jack_driver_descriptor_add_parameter(desc, &filler, "midi-in-ports", 'i', JackDriverParamInt, &value, NULL, "Number of midi input ports", NULL);
620 jack_driver_descriptor_add_parameter(desc, &filler, "midi-out-ports", 'o', JackDriverParamInt, &value, NULL, "Number of midi output ports", NULL);
622 #if HAVE_CELT
623 value.i = -1;
624 jack_driver_descriptor_add_parameter(desc, &filler, "celt", 'c', JackDriverParamInt, &value, NULL, "Set CELT encoding and number of kBits per channel", NULL);
625 #endif
626 #if HAVE_OPUS
627 value.i = -1;
628 jack_driver_descriptor_add_parameter(desc, &filler, "opus", 'O', JackDriverParamInt, &value, NULL, "Set Opus encoding and number of kBits per channel", NULL);
629 #endif
630 strcpy(value.str, "'hostname'");
631 jack_driver_descriptor_add_parameter(desc, &filler, "client-name", 'n', JackDriverParamString, &value, NULL, "Name of the jack client", NULL);
634 Deactivated for now..
635 value.ui = 0U;
636 jack_driver_descriptor_add_parameter(desc, &filler, "transport-sync", 't', JackDriverParamUInt, &value, NULL, "Sync transport with master's", NULL);
639 value.ui = 5U;
640 jack_driver_descriptor_add_parameter(desc, &filler, "latency", 'l', JackDriverParamUInt, &value, NULL, "Network latency", NULL);
642 return desc;
645 SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
647 char multicast_ip[32];
648 char net_name[JACK_CLIENT_NAME_SIZE + 1];
649 int udp_port;
650 int mtu = DEFAULT_MTU;
651 // Desactivated for now...
652 uint transport_sync = 0;
653 jack_nframes_t period_size = 1024;
654 jack_nframes_t sample_rate = 48000;
655 int audio_capture_ports = -1;
656 int audio_playback_ports = -1;
657 int midi_input_ports = 0;
658 int midi_output_ports = 0;
659 int celt_encoding = -1;
660 int opus_encoding = -1;
661 bool monitor = false;
662 int network_latency = 5;
663 const JSList* node;
664 const jack_driver_param_t* param;
666 net_name[0] = 0;
668 // Possibly use env variable
669 const char* default_udp_port = getenv("JACK_NETJACK_PORT");
670 udp_port = (default_udp_port) ? atoi(default_udp_port) : DEFAULT_PORT;
672 const char* default_multicast_ip = getenv("JACK_NETJACK_MULTICAST");
673 if (default_multicast_ip) {
674 strcpy(multicast_ip, default_multicast_ip);
675 } else {
676 strcpy(multicast_ip, DEFAULT_MULTICAST_IP);
679 for (node = params; node; node = jack_slist_next(node)) {
680 param = (const jack_driver_param_t*) node->data;
681 switch (param->character)
683 case 'a' :
684 assert(strlen(param->value.str) < 32);
685 strcpy(multicast_ip, param->value.str);
686 break;
687 case 'p':
688 udp_port = param->value.ui;
689 break;
690 case 'M':
691 mtu = param->value.i;
692 break;
693 case 'C':
694 audio_capture_ports = param->value.i;
695 break;
696 case 'P':
697 audio_playback_ports = param->value.i;
698 break;
699 case 'i':
700 midi_input_ports = param->value.i;
701 break;
702 case 'o':
703 midi_output_ports = param->value.i;
704 break;
705 #if HAVE_CELT
706 case 'c':
707 celt_encoding = param->value.i;
708 break;
709 #endif
710 #if HAVE_OPUS
711 case 'O':
712 opus_encoding = param->value.i;
713 break;
714 #endif
715 case 'n' :
716 strncpy(net_name, param->value.str, JACK_CLIENT_NAME_SIZE);
717 break;
719 Deactivated for now..
720 case 't' :
721 transport_sync = param->value.ui;
722 break;
724 case 'l' :
725 network_latency = param->value.ui;
726 if (network_latency > NETWORK_MAX_LATENCY) {
727 printf("Error : network latency is limited to %d\n", NETWORK_MAX_LATENCY);
728 return NULL;
730 break;
734 try {
736 Jack::JackDriverClientInterface* driver = new Jack::JackWaitThreadedDriver(
737 new Jack::JackNetDriver("system", "net_pcm", engine, table, multicast_ip, udp_port, mtu,
738 midi_input_ports, midi_output_ports,
739 net_name, transport_sync,
740 network_latency, celt_encoding, opus_encoding));
741 if (driver->Open(period_size, sample_rate, 1, 1, audio_capture_ports, audio_playback_ports, monitor, "from_master_", "to_master_", 0, 0) == 0) {
742 return driver;
743 } else {
744 delete driver;
745 return NULL;
748 } catch (...) {
749 return NULL;
753 #ifdef __cplusplus
755 #endif