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
)
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
;
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
;
68 JackNetDriver::~JackNetDriver()
70 delete[] fMidiCapturePortList
;
71 delete[] fMidiPlaybackPortList
;
77 //open, close, attach and detach------------------------------------------------------
79 int JackNetDriver::Close()
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()
96 int JackNetDriver::Detach()
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");
113 // New loading, but existing socket, restart the driver
114 if (fSocket
.IsSocket()) {
115 jack_info("Restarting driver...");
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");
129 if (!JackNetSlaveInterface::Init()) {
130 jack_error("Starting network fails...");
134 // Set global parameters
136 jack_error("SetParams error...");
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.");
164 // Init done, display parameters
165 SessionParamsDisplay(&fParams
);
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"),
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);
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();
205 void JackNetDriver::FreeAll()
211 delete fNetAudioCaptureBuffer
;
212 delete fNetAudioPlaybackBuffer
;
213 delete fNetMidiCaptureBuffer
;
214 delete fNetMidiPlaybackBuffer
;
215 delete[] fMidiCapturePortList
;
216 delete[] fMidiPlaybackPortList
;
220 fNetAudioCaptureBuffer
= NULL
;
221 fNetAudioPlaybackBuffer
= NULL
;
222 fNetMidiCaptureBuffer
= NULL
;
223 fNetMidiPlaybackBuffer
= NULL
;
224 fMidiCapturePortList
= NULL
;
225 fMidiPlaybackPortList
= NULL
;
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_"
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
;
253 jack_latency_range_t range
;
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
);
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
);
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());
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
);
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
);
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());
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;
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
]));
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()));
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
407 if (fSendTransportData
.fTimebaseMaster
== TIMEBASEMASTER
) {
408 fEngineControl
->fTransport
.GetTimebaseMaster(refnum
, conditional
);
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.");
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
);
431 case JackTransportRolling
:
432 //fEngineControl->fTransport.SetCommand(TransportCommandStart);
433 fEngineControl
->fTransport
.SetState(JackTransportRolling
);
434 jack_info("Master is rolling.");
440 void JackNetDriver::EncodeTransportData()
442 //is there a timebase master change ?
445 fEngineControl
->fTransport
.GetTimebaseMaster(refnum
, conditional
);
446 if (refnum
!= fLastTimebaseMaster
) {
447 //timebase master has released its function
449 fReturnTransportData
.fTimebaseMaster
= RELEASE_TIMEBASEMASTER
;
450 jack_info("Sending a timebase master release request.");
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
;
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()
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
));
488 fNetAudioCaptureBuffer
->SetBuffer(audio_port_index
, NULL
);
491 fNetAudioCaptureBuffer
->SetBuffer(audio_port_index
, GetInputBuffer(audio_port_index
));
499 //receive sync (launch the cycle)
500 if (SyncRecv() == SOCKET_ERROR
) {
506 fRcvSyncUst
= GetMicroSeconds();
510 //if there is an error, don't return -1, it will skip Write() and the network error probably won't be identified
514 fNetTimeMon
->Add(float(GetMicroSeconds() - fRcvSyncUst
) / float(fEngineControl
->fPeriodUsecs
) * 100.f
);
516 //audio, midi or sync if driver is late
517 int res
= DataRecv();
518 if (res
== 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();
529 fNetTimeMon
->Add(float(GetMicroSeconds() - fRcvSyncUst
) / float(fEngineControl
->fPeriodUsecs
) * 100.f
);
535 int JackNetDriver::Write()
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
));
549 fNetAudioPlaybackBuffer
->SetBuffer(audio_port_index
, NULL
);
552 fNetAudioPlaybackBuffer
->SetBuffer(audio_port_index
, NULL
);
555 fNetAudioPlaybackBuffer
->SetBuffer(audio_port_index
, GetOutputBuffer(audio_port_index
));
560 fNetTimeMon
->AddLast(float(GetMicroSeconds() - fRcvSyncUst
) / float(fEngineControl
->fPeriodUsecs
) * 100.f
);
567 if (SyncSend() == SOCKET_ERROR
) {
572 fNetTimeMon
->Add(((float)(GetMicroSeconds() - fRcvSyncUst
) / (float)fEngineControl
->fPeriodUsecs
) * 100.f
);
576 if (DataSend() == SOCKET_ERROR
) {
581 fNetTimeMon
->AddLast(((float)(GetMicroSeconds() - fRcvSyncUst
) / (float)fEngineControl
->fPeriodUsecs
) * 100.f
);
587 //driver loader-----------------------------------------------------------------------
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
);
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");
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
);
621 jack_driver_descriptor_add_parameter(desc
, &filler
, "celt", 'c', JackDriverParamInt
, &value
, NULL
, "Set CELT encoding and number of kBits per channel", NULL
);
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..
629 jack_driver_descriptor_add_parameter(desc, &filler, "transport-sync", 't', JackDriverParamUInt, &value, NULL, "Sync transport with master's", NULL);
633 jack_driver_descriptor_add_parameter(desc
, &filler
, "latency", 'l', JackDriverParamUInt
, &value
, NULL
, "Network latency", NULL
);
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];
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;
656 const jack_driver_param_t
* param
;
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
);
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
)
676 assert(strlen(param
->value
.str
) < 32);
677 strcpy(multicast_ip
, param
->value
.str
);
680 udp_port
= param
->value
.ui
;
683 mtu
= param
->value
.i
;
686 audio_capture_ports
= param
->value
.i
;
689 audio_playback_ports
= param
->value
.i
;
692 midi_input_ports
= param
->value
.i
;
695 midi_output_ports
= param
->value
.i
;
699 celt_encoding
= param
->value
.i
;
703 strncpy(net_name
, param
->value
.str
, JACK_CLIENT_NAME_SIZE
);
706 Deactivated for now..
708 transport_sync = param->value.ui;
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
);
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) {