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"
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
);
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
;
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
;
71 JackNetDriver::~JackNetDriver()
73 delete[] fMidiCapturePortList
;
74 delete[] fMidiPlaybackPortList
;
80 //open, close, attach and detach------------------------------------------------------
82 int JackNetDriver::Close()
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()
99 int JackNetDriver::Detach()
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");
116 // New loading, but existing socket, restart the driver
117 if (fSocket
.IsSocket()) {
118 jack_info("Restarting driver...");
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");
132 if (!JackNetSlaveInterface::Init()) {
133 jack_error("Starting network fails...");
137 // Set global parameters
139 jack_error("SetParams error...");
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.");
167 // Init done, display parameters
168 SessionParamsDisplay(&fParams
);
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"),
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);
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();
208 void JackNetDriver::FreeAll()
214 delete fNetAudioCaptureBuffer
;
215 delete fNetAudioPlaybackBuffer
;
216 delete fNetMidiCaptureBuffer
;
217 delete fNetMidiPlaybackBuffer
;
218 delete[] fMidiCapturePortList
;
219 delete[] fMidiPlaybackPortList
;
223 fNetAudioCaptureBuffer
= NULL
;
224 fNetAudioPlaybackBuffer
= NULL
;
225 fNetMidiCaptureBuffer
= NULL
;
226 fNetMidiPlaybackBuffer
= NULL
;
227 fMidiCapturePortList
= NULL
;
228 fMidiPlaybackPortList
= NULL
;
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_"
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
;
256 jack_latency_range_t range
;
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
);
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
);
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());
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
);
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
);
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());
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;
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
]));
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()));
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
410 if (fSendTransportData
.fTimebaseMaster
== TIMEBASEMASTER
) {
411 fEngineControl
->fTransport
.GetTimebaseMaster(refnum
, conditional
);
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.");
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
);
434 case JackTransportRolling
:
435 //fEngineControl->fTransport.SetCommand(TransportCommandStart);
436 fEngineControl
->fTransport
.SetState(JackTransportRolling
);
437 jack_info("Master is rolling.");
443 void JackNetDriver::EncodeTransportData()
445 //is there a timebase master change ?
448 fEngineControl
->fTransport
.GetTimebaseMaster(refnum
, conditional
);
449 if (refnum
!= fLastTimebaseMaster
) {
450 //timebase master has released its function
452 fReturnTransportData
.fTimebaseMaster
= RELEASE_TIMEBASEMASTER
;
453 jack_info("Sending a timebase master release request.");
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
;
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()
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
));
491 fNetAudioCaptureBuffer
->SetBuffer(audio_port_index
, NULL
);
494 fNetAudioCaptureBuffer
->SetBuffer(audio_port_index
, GetInputBuffer(audio_port_index
));
502 //receive sync (launch the cycle)
503 if (SyncRecv() == SOCKET_ERROR
) {
509 fRcvSyncUst
= GetMicroSeconds();
513 //if there is an error, don't return -1, it will skip Write() and the network error probably won't be identified
517 fNetTimeMon
->Add(float(GetMicroSeconds() - fRcvSyncUst
) / float(fEngineControl
->fPeriodUsecs
) * 100.f
);
519 //audio, midi or sync if driver is late
520 int res
= DataRecv();
521 if (res
== 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();
532 fNetTimeMon
->Add(float(GetMicroSeconds() - fRcvSyncUst
) / float(fEngineControl
->fPeriodUsecs
) * 100.f
);
538 int JackNetDriver::Write()
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
));
552 fNetAudioPlaybackBuffer
->SetBuffer(audio_port_index
, NULL
);
555 fNetAudioPlaybackBuffer
->SetBuffer(audio_port_index
, NULL
);
558 fNetAudioPlaybackBuffer
->SetBuffer(audio_port_index
, GetOutputBuffer(audio_port_index
));
563 fNetTimeMon
->AddLast(float(GetMicroSeconds() - fRcvSyncUst
) / float(fEngineControl
->fPeriodUsecs
) * 100.f
);
570 if (SyncSend() == SOCKET_ERROR
) {
575 fNetTimeMon
->Add(((float)(GetMicroSeconds() - fRcvSyncUst
) / (float)fEngineControl
->fPeriodUsecs
) * 100.f
);
579 if (DataSend() == SOCKET_ERROR
) {
584 fNetTimeMon
->AddLast(((float)(GetMicroSeconds() - fRcvSyncUst
) / (float)fEngineControl
->fPeriodUsecs
) * 100.f
);
590 //driver loader-----------------------------------------------------------------------
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
);
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");
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
);
624 jack_driver_descriptor_add_parameter(desc
, &filler
, "celt", 'c', JackDriverParamInt
, &value
, NULL
, "Set CELT encoding and number of kBits per channel", NULL
);
628 jack_driver_descriptor_add_parameter(desc
, &filler
, "opus", 'O', JackDriverParamInt
, &value
, NULL
, "Set Opus encoding and number of kBits per channel", NULL
);
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..
636 jack_driver_descriptor_add_parameter(desc, &filler, "transport-sync", 't', JackDriverParamUInt, &value, NULL, "Sync transport with master's", NULL);
640 jack_driver_descriptor_add_parameter(desc
, &filler
, "latency", 'l', JackDriverParamUInt
, &value
, NULL
, "Network latency", NULL
);
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];
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;
664 const jack_driver_param_t
* param
;
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
);
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
)
684 assert(strlen(param
->value
.str
) < 32);
685 strcpy(multicast_ip
, param
->value
.str
);
688 udp_port
= param
->value
.ui
;
691 mtu
= param
->value
.i
;
694 audio_capture_ports
= param
->value
.i
;
697 audio_playback_ports
= param
->value
.i
;
700 midi_input_ports
= param
->value
.i
;
703 midi_output_ports
= param
->value
.i
;
707 celt_encoding
= param
->value
.i
;
712 opus_encoding
= param
->value
.i
;
716 strncpy(net_name
, param
->value
.str
, JACK_CLIENT_NAME_SIZE
);
719 Deactivated for now..
721 transport_sync = param->value.ui;
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
);
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) {