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
,
33 int celt_encoding
, int opus_encoding
, bool auto_save
)
34 : JackWaiterDriver(name
, alias
, engine
, table
), JackNetSlaveInterface(ip
, udp_port
)
36 jack_log("JackNetDriver::JackNetDriver ip %s, port %d", ip
, udp_port
);
38 // Use the hostname if no name parameter was given
39 if (strcmp(net_name
, "") == 0) {
40 GetHostName(net_name
, JACK_CLIENT_NAME_SIZE
);
45 fWantedMIDICaptureChannels
= midi_input_ports
;
46 fWantedMIDIPlaybackChannels
= midi_output_ports
;
48 if (celt_encoding
> 0) {
49 fParams
.fSampleEncoder
= JackCeltEncoder
;
50 fParams
.fKBps
= celt_encoding
;
51 } else if (opus_encoding
> 0) {
52 fParams
.fSampleEncoder
= JackOpusEncoder
;
53 fParams
.fKBps
= opus_encoding
;
55 fParams
.fSampleEncoder
= JackFloatEncoder
;
56 //fParams.fSampleEncoder = JackIntEncoder;
58 strcpy(fParams
.fName
, net_name
);
59 fSocket
.GetName(fParams
.fSlaveNetName
);
60 fParams
.fTransportSync
= transport_sync
;
61 fParams
.fNetworkLatency
= network_latency
;
62 fSendTransportData
.fState
= -1;
63 fReturnTransportData
.fState
= -1;
64 fLastTransportState
= -1;
65 fLastTimebaseMaster
= -1;
66 fMidiCapturePortList
= NULL
;
67 fMidiPlaybackPortList
= NULL
;
68 fWantedAudioCaptureChannels
= -1;
69 fWantedAudioPlaybackChannels
= -1;
70 fAutoSave
= auto_save
;
77 JackNetDriver::~JackNetDriver()
79 delete[] fMidiCapturePortList
;
80 delete[] fMidiPlaybackPortList
;
86 //open, close, attach and detach------------------------------------------------------
88 int JackNetDriver::Open(jack_nframes_t buffer_size
,
89 jack_nframes_t samplerate
,
95 const char* capture_driver_name
,
96 const char* playback_driver_name
,
97 jack_nframes_t capture_latency
,
98 jack_nframes_t playback_latency
)
100 // Keep initial wanted values
101 fWantedAudioCaptureChannels
= inchannels
;
102 fWantedAudioPlaybackChannels
= outchannels
;
103 return JackWaiterDriver::Open(buffer_size
, samplerate
,
105 inchannels
, outchannels
,
107 capture_driver_name
, playback_driver_name
,
108 capture_latency
, playback_latency
);
111 int JackNetDriver::Close()
119 return JackWaiterDriver::Close();
122 // Attach and Detach are defined as empty methods: port allocation is done when driver actually start (that is in Init)
123 int JackNetDriver::Attach()
128 int JackNetDriver::Detach()
133 //init and restart--------------------------------------------------------------------
135 JackNetDriver is wrapped in a JackWaitThreadedDriver decorator that behaves
136 as a "dummy driver, until Init method returns.
139 bool JackNetDriver::Initialize()
141 jack_log("JackNetDriver::Initialize");
147 // New loading, but existing socket, restart the driver
148 if (fSocket
.IsSocket()) {
149 jack_info("Restarting driver...");
153 // Set the parameters to send
154 fParams
.fSendAudioChannels
= fWantedAudioCaptureChannels
;
155 fParams
.fReturnAudioChannels
= fWantedAudioPlaybackChannels
;
157 fParams
.fSendMidiChannels
= fWantedMIDICaptureChannels
;
158 fParams
.fReturnMidiChannels
= fWantedMIDIPlaybackChannels
;
160 fParams
.fSlaveSyncMode
= fEngineControl
->fSyncMode
;
162 // Display some additional infos
163 jack_info("NetDriver started in %s mode %s Master's transport sync.",
164 (fParams
.fSlaveSyncMode
) ? "sync" : "async", (fParams
.fTransportSync
) ? "with" : "without");
167 if (!JackNetSlaveInterface::Init()) {
168 jack_error("Starting network fails...");
172 // Set global parameters
174 jack_error("SetParams error...");
178 // If -1 at connection time for audio, in/out audio channels count is sent by the master
179 fCaptureChannels
= fParams
.fSendAudioChannels
;
180 fPlaybackChannels
= fParams
.fReturnAudioChannels
;
182 // If -1 at connection time for MIDI, in/out MIDI channels count is sent by the master (in fParams struct)
184 // Allocate midi ports lists
185 delete[] fMidiCapturePortList
;
186 delete[] fMidiPlaybackPortList
;
188 if (fParams
.fSendMidiChannels
> 0) {
189 fMidiCapturePortList
= new jack_port_id_t
[fParams
.fSendMidiChannels
];
190 assert(fMidiCapturePortList
);
191 for (int midi_port_index
= 0; midi_port_index
< fParams
.fSendMidiChannels
; midi_port_index
++) {
192 fMidiCapturePortList
[midi_port_index
] = 0;
196 if (fParams
.fReturnMidiChannels
> 0) {
197 fMidiPlaybackPortList
= new jack_port_id_t
[fParams
.fReturnMidiChannels
];
198 assert(fMidiPlaybackPortList
);
199 for (int midi_port_index
= 0; midi_port_index
< fParams
.fReturnMidiChannels
; midi_port_index
++) {
200 fMidiPlaybackPortList
[midi_port_index
] = 0;
204 // Register jack ports
205 if (AllocPorts() != 0) {
206 jack_error("Can't allocate ports.");
210 // Init done, display parameters
211 SessionParamsDisplay(&fParams
);
217 plot_name
= string(fParams
.fName
);
218 plot_name
+= string("_slave");
219 plot_name
+= (fEngineControl
->fSyncMode
) ? string("_sync") : string("_async");
220 plot_name
+= string("_latency");
221 fNetTimeMon
= new JackGnuPlotMonitor
<float>(128, 5, plot_name
);
222 string net_time_mon_fields
[] =
224 string("sync decoded"),
225 string("end of read"),
226 string("start of write"),
228 string("end of write")
230 string net_time_mon_options
[] =
232 string("set xlabel \"audio cycles\""),
233 string("set ylabel \"% of audio cycle\"")
235 fNetTimeMon
->SetPlotFile(net_time_mon_options
, 2, net_time_mon_fields
, 5);
237 // Driver parametering
238 JackTimedDriver::SetBufferSize(fParams
.fPeriodSize
);
239 JackTimedDriver::SetSampleRate(fParams
.fSampleRate
);
241 JackDriver::NotifyBufferSize(fParams
.fPeriodSize
);
242 JackDriver::NotifySampleRate(fParams
.fSampleRate
);
244 // Transport engine parametering
245 fEngineControl
->fTransport
.SetNetworkSync(fParams
.fTransportSync
);
253 void JackNetDriver::FreeAll()
259 delete fNetAudioCaptureBuffer
;
260 delete fNetAudioPlaybackBuffer
;
261 delete fNetMidiCaptureBuffer
;
262 delete fNetMidiPlaybackBuffer
;
263 delete[] fMidiCapturePortList
;
264 delete[] fMidiPlaybackPortList
;
268 fNetAudioCaptureBuffer
= NULL
;
269 fNetAudioPlaybackBuffer
= NULL
;
270 fNetMidiCaptureBuffer
= NULL
;
271 fNetMidiPlaybackBuffer
= NULL
;
272 fMidiCapturePortList
= NULL
;
273 fMidiPlaybackPortList
= NULL
;
281 void JackNetDriver::UpdateLatencies()
283 jack_latency_range_t input_range
;
284 jack_latency_range_t output_range
;
285 jack_latency_range_t monitor_range
;
287 for (int i
= 0; i
< fCaptureChannels
; i
++) {
288 input_range
.max
= input_range
.min
= float(fParams
.fNetworkLatency
* fEngineControl
->fBufferSize
) / 2.f
;
289 fGraphManager
->GetPort(fCapturePortList
[i
])->SetLatencyRange(JackCaptureLatency
, &input_range
);
292 for (int i
= 0; i
< fPlaybackChannels
; i
++) {
293 output_range
.max
= output_range
.min
= float(fParams
.fNetworkLatency
* fEngineControl
->fBufferSize
) / 2.f
;
294 if (!fEngineControl
->fSyncMode
) {
295 output_range
.max
= output_range
.min
+= fEngineControl
->fBufferSize
;
297 fGraphManager
->GetPort(fPlaybackPortList
[i
])->SetLatencyRange(JackPlaybackLatency
, &output_range
);
298 if (fWithMonitorPorts
) {
299 monitor_range
.min
= monitor_range
.max
= 0;
300 fGraphManager
->GetPort(fMonitorPortList
[i
])->SetLatencyRange(JackCaptureLatency
, &monitor_range
);
305 //jack ports and buffers--------------------------------------------------------------
306 int JackNetDriver::AllocPorts()
308 jack_log("JackNetDriver::AllocPorts fBufferSize = %ld fSampleRate = %ld", fEngineControl
->fBufferSize
, fEngineControl
->fSampleRate
);
311 fNetAudioCaptureBuffer fNetAudioPlaybackBuffer
312 fSendAudioChannels fReturnAudioChannels
314 fCapturePortList fPlaybackPortList
315 fCaptureChannels ==> SLAVE ==> fPlaybackChannels
316 "capture_" "playback_"
320 jack_port_id_t port_index
;
321 char name
[REAL_JACK_PORT_NAME_SIZE
+1];
322 char alias
[REAL_JACK_PORT_NAME_SIZE
+1];
323 int audio_port_index
;
327 for (audio_port_index
= 0; audio_port_index
< fCaptureChannels
; audio_port_index
++) {
328 snprintf(alias
, sizeof(alias
), "%s:%s:out%d", fAliasName
, fCaptureDriverName
, audio_port_index
+ 1);
329 snprintf(name
, sizeof(name
), "%s:capture_%d", fClientControl
.fName
, audio_port_index
+ 1);
330 if (fEngine
->PortRegister(fClientControl
.fRefNum
, name
, JACK_DEFAULT_AUDIO_TYPE
,
331 CaptureDriverFlags
, fEngineControl
->fBufferSize
, &port_index
) < 0) {
332 jack_error("driver: cannot register port for %s", name
);
336 port
= fGraphManager
->GetPort(port_index
);
337 port
->SetAlias(alias
);
338 fCapturePortList
[audio_port_index
] = port_index
;
339 jack_log("JackNetDriver::AllocPorts() fCapturePortList[%d] audio_port_index = %ld fPortLatency = %ld", audio_port_index
, port_index
, port
->GetLatency());
342 for (audio_port_index
= 0; audio_port_index
< fPlaybackChannels
; audio_port_index
++) {
343 snprintf(alias
, sizeof(alias
), "%s:%s:in%d", fAliasName
, fPlaybackDriverName
, audio_port_index
+ 1);
344 snprintf(name
, sizeof(name
), "%s:playback_%d",fClientControl
.fName
, audio_port_index
+ 1);
345 if (fEngine
->PortRegister(fClientControl
.fRefNum
, name
, JACK_DEFAULT_AUDIO_TYPE
,
346 PlaybackDriverFlags
, fEngineControl
->fBufferSize
, &port_index
) < 0) {
347 jack_error("driver: cannot register port for %s", name
);
351 port
= fGraphManager
->GetPort(port_index
);
352 port
->SetAlias(alias
);
353 fPlaybackPortList
[audio_port_index
] = port_index
;
354 jack_log("JackNetDriver::AllocPorts() fPlaybackPortList[%d] audio_port_index = %ld fPortLatency = %ld", audio_port_index
, port_index
, port
->GetLatency());
358 for (midi_port_index
= 0; midi_port_index
< fParams
.fSendMidiChannels
; midi_port_index
++) {
359 snprintf(alias
, sizeof(alias
), "%s:%s:out%d", fAliasName
, fCaptureDriverName
, midi_port_index
+ 1);
360 snprintf(name
, sizeof (name
), "%s:midi_capture_%d", fClientControl
.fName
, midi_port_index
+ 1);
361 if (fEngine
->PortRegister(fClientControl
.fRefNum
, name
, JACK_DEFAULT_MIDI_TYPE
,
362 CaptureDriverFlags
, fEngineControl
->fBufferSize
, &port_index
) < 0) {
363 jack_error("driver: cannot register port for %s", name
);
367 port
= fGraphManager
->GetPort(port_index
);
368 fMidiCapturePortList
[midi_port_index
] = port_index
;
369 jack_log("JackNetDriver::AllocPorts() fMidiCapturePortList[%d] midi_port_index = %ld fPortLatency = %ld", midi_port_index
, port_index
, port
->GetLatency());
372 for (midi_port_index
= 0; midi_port_index
< fParams
.fReturnMidiChannels
; midi_port_index
++) {
373 snprintf(alias
, sizeof(alias
), "%s:%s:in%d", fAliasName
, fPlaybackDriverName
, midi_port_index
+ 1);
374 snprintf(name
, sizeof(name
), "%s:midi_playback_%d", fClientControl
.fName
, midi_port_index
+ 1);
375 if (fEngine
->PortRegister(fClientControl
.fRefNum
, name
, JACK_DEFAULT_MIDI_TYPE
,
376 PlaybackDriverFlags
, fEngineControl
->fBufferSize
, &port_index
) < 0) {
377 jack_error("driver: cannot register port for %s", name
);
381 port
= fGraphManager
->GetPort(port_index
);
382 fMidiPlaybackPortList
[midi_port_index
] = port_index
;
383 jack_log("JackNetDriver::AllocPorts() fMidiPlaybackPortList[%d] midi_port_index = %ld fPortLatency = %ld", midi_port_index
, port_index
, port
->GetLatency());
390 int JackNetDriver::FreePorts()
392 jack_log("JackNetDriver::FreePorts");
394 for (int audio_port_index
= 0; audio_port_index
< fCaptureChannels
; audio_port_index
++) {
395 if (fCapturePortList
[audio_port_index
] > 0) {
396 fEngine
->PortUnRegister(fClientControl
.fRefNum
, fCapturePortList
[audio_port_index
]);
397 fCapturePortList
[audio_port_index
] = 0;
401 for (int audio_port_index
= 0; audio_port_index
< fPlaybackChannels
; audio_port_index
++) {
402 if (fPlaybackPortList
[audio_port_index
] > 0) {
403 fEngine
->PortUnRegister(fClientControl
.fRefNum
, fPlaybackPortList
[audio_port_index
]);
404 fPlaybackPortList
[audio_port_index
] = 0;
408 for (int midi_port_index
= 0; midi_port_index
< fParams
.fSendMidiChannels
; midi_port_index
++) {
409 if (fMidiCapturePortList
&& fMidiCapturePortList
[midi_port_index
] > 0) {
410 fGraphManager
->ReleasePort(fClientControl
.fRefNum
, fMidiCapturePortList
[midi_port_index
]);
411 fMidiCapturePortList
[midi_port_index
] = 0;
415 for (int midi_port_index
= 0; midi_port_index
< fParams
.fReturnMidiChannels
; midi_port_index
++) {
416 if (fMidiPlaybackPortList
&& fMidiPlaybackPortList
[midi_port_index
] > 0) {
417 fEngine
->PortUnRegister(fClientControl
.fRefNum
, fMidiPlaybackPortList
[midi_port_index
]);
418 fMidiPlaybackPortList
[midi_port_index
] = 0;
424 void JackNetDriver::SaveConnections(int alias
)
426 JackDriver::SaveConnections(alias
);
427 const char** connections
;
429 if (fMidiCapturePortList
) {
430 for (int i
= 0; i
< fParams
.fSendMidiChannels
; ++i
) {
431 if (fMidiCapturePortList
[i
] && (connections
= fGraphManager
->GetConnections(fMidiCapturePortList
[i
])) != 0) {
432 for (int j
= 0; connections
[j
]; j
++) {
433 JackPort
* port_id
= fGraphManager
->GetPort(fGraphManager
->GetPort(connections
[j
]));
434 fConnections
.push_back(make_pair(port_id
->GetType(), make_pair(fGraphManager
->GetPort(fMidiCapturePortList
[i
])->GetName(), connections
[j
])));
435 jack_info("Save connection: %s %s", fGraphManager
->GetPort(fMidiCapturePortList
[i
])->GetName(), connections
[j
]);
442 if (fMidiPlaybackPortList
) {
443 for (int i
= 0; i
< fParams
.fReturnMidiChannels
; ++i
) {
444 if (fMidiPlaybackPortList
[i
] && (connections
= fGraphManager
->GetConnections(fMidiPlaybackPortList
[i
])) != 0) {
445 for (int j
= 0; connections
[j
]; j
++) {
446 JackPort
* port_id
= fGraphManager
->GetPort(fGraphManager
->GetPort(connections
[j
]));
447 fConnections
.push_back(make_pair(port_id
->GetType(), make_pair(connections
[j
], fGraphManager
->GetPort(fMidiPlaybackPortList
[i
])->GetName())));
448 jack_info("Save connection: %s %s", connections
[j
], fGraphManager
->GetPort(fMidiPlaybackPortList
[i
])->GetName());
456 JackMidiBuffer
* JackNetDriver::GetMidiInputBuffer(int port_index
)
458 return static_cast<JackMidiBuffer
*>(fGraphManager
->GetBuffer(fMidiCapturePortList
[port_index
], fEngineControl
->fBufferSize
));
461 JackMidiBuffer
* JackNetDriver::GetMidiOutputBuffer(int port_index
)
463 return static_cast<JackMidiBuffer
*>(fGraphManager
->GetBuffer(fMidiPlaybackPortList
[port_index
], fEngineControl
->fBufferSize
));
466 //transport---------------------------------------------------------------------------
467 void JackNetDriver::DecodeTransportData()
469 //is there a new timebase master on the net master ?
470 // - release timebase master only if it's a non-conditional request
471 // - no change or no request : don't do anything
472 // - conditional request : don't change anything too, the master will know if this slave is actually the timebase master
475 if (fSendTransportData
.fTimebaseMaster
== TIMEBASEMASTER
) {
476 fEngineControl
->fTransport
.GetTimebaseMaster(refnum
, conditional
);
478 fEngineControl
->fTransport
.ResetTimebase(refnum
);
480 jack_info("The NetMaster is now the new timebase master.");
483 //is there a transport state change to handle ?
484 if (fSendTransportData
.fNewState
&&(fSendTransportData
.fState
!= fEngineControl
->fTransport
.GetState())) {
486 switch (fSendTransportData
.fState
)
488 case JackTransportStopped
:
489 fEngineControl
->fTransport
.SetCommand(TransportCommandStop
);
490 jack_info("Master stops transport.");
493 case JackTransportStarting
:
494 fEngineControl
->fTransport
.RequestNewPos(&fSendTransportData
.fPosition
);
495 fEngineControl
->fTransport
.SetCommand(TransportCommandStart
);
496 jack_info("Master starts transport frame = %d", fSendTransportData
.fPosition
.frame
);
499 case JackTransportRolling
:
500 //fEngineControl->fTransport.SetCommand(TransportCommandStart);
501 fEngineControl
->fTransport
.SetState(JackTransportRolling
);
502 jack_info("Master is rolling.");
508 void JackNetDriver::EncodeTransportData()
510 // is there a timebase master change ?
513 fEngineControl
->fTransport
.GetTimebaseMaster(refnum
, conditional
);
514 if (refnum
!= fLastTimebaseMaster
) {
515 // timebase master has released its function
517 fReturnTransportData
.fTimebaseMaster
= RELEASE_TIMEBASEMASTER
;
518 jack_info("Sending a timebase master release request.");
520 // there is a new timebase master
521 fReturnTransportData
.fTimebaseMaster
= (conditional
) ? CONDITIONAL_TIMEBASEMASTER
: TIMEBASEMASTER
;
522 jack_info("Sending a %s timebase master request.", (conditional
) ? "conditional" : "non-conditional");
524 fLastTimebaseMaster
= refnum
;
526 fReturnTransportData
.fTimebaseMaster
= NO_CHANGE
;
529 // update transport state and position
530 fReturnTransportData
.fState
= fEngineControl
->fTransport
.Query(&fReturnTransportData
.fPosition
);
532 // is it a new state (that the master need to know...) ?
533 fReturnTransportData
.fNewState
= ((fReturnTransportData
.fState
== JackTransportNetStarting
) &&
534 (fReturnTransportData
.fState
!= fLastTransportState
) &&
535 (fReturnTransportData
.fState
!= fSendTransportData
.fState
));
536 if (fReturnTransportData
.fNewState
) {
537 jack_info("Sending '%s'.", GetTransportState(fReturnTransportData
.fState
));
539 fLastTransportState
= fReturnTransportData
.fState
;
542 //driver processes--------------------------------------------------------------------
544 int JackNetDriver::Read()
547 for (int midi_port_index
= 0; midi_port_index
< fParams
.fSendMidiChannels
; midi_port_index
++) {
548 fNetMidiCaptureBuffer
->SetBuffer(midi_port_index
, GetMidiInputBuffer(midi_port_index
));
551 for (int audio_port_index
= 0; audio_port_index
< fParams
.fSendAudioChannels
; audio_port_index
++) {
552 #ifdef OPTIMIZED_PROTOCOL
553 if (fGraphManager
->GetConnectionsNum(fCapturePortList
[audio_port_index
]) > 0) {
554 fNetAudioCaptureBuffer
->SetBuffer(audio_port_index
, GetInputBuffer(audio_port_index
));
556 fNetAudioCaptureBuffer
->SetBuffer(audio_port_index
, NULL
);
559 fNetAudioCaptureBuffer
->SetBuffer(audio_port_index
, GetInputBuffer(audio_port_index
));
567 switch (SyncRecv()) {
572 case SYNC_PACKET_ERROR
:
573 // since sync packet is incorrect, don't decode it and continue with data
579 DecodeSyncPacket(unused_frames
);
585 fRcvSyncUst
= GetMicroSeconds();
589 fNetTimeMon
->Add(float(GetMicroSeconds() - fRcvSyncUst
) / float(fEngineControl
->fPeriodUsecs
) * 100.f
);
591 // audio, midi or sync if driver is late
592 switch (DataRecv()) {
597 case DATA_PACKET_ERROR
:
598 jack_time_t cur_time
= GetMicroSeconds();
599 NotifyXRun(cur_time
, float(cur_time
- fBeginDateUst
)); // Better this value than nothing...
603 // take the time at the beginning of the cycle
604 JackDriver::CycleTakeBeginTime();
607 fNetTimeMon
->Add(float(GetMicroSeconds() - fRcvSyncUst
) / float(fEngineControl
->fPeriodUsecs
) * 100.f
);
613 int JackNetDriver::Write()
616 for (int midi_port_index
= 0; midi_port_index
< fParams
.fReturnMidiChannels
; midi_port_index
++) {
617 fNetMidiPlaybackBuffer
->SetBuffer(midi_port_index
, GetMidiOutputBuffer(midi_port_index
));
620 for (int audio_port_index
= 0; audio_port_index
< fPlaybackChannels
; audio_port_index
++) {
621 #ifdef OPTIMIZED_PROTOCOL
622 // Port is connected on other side...
623 if (fNetAudioPlaybackBuffer
->GetConnected(audio_port_index
)
624 && (fGraphManager
->GetConnectionsNum(fPlaybackPortList
[audio_port_index
]) > 0)) {
625 fNetAudioPlaybackBuffer
->SetBuffer(audio_port_index
, GetOutputBuffer(audio_port_index
));
627 fNetAudioPlaybackBuffer
->SetBuffer(audio_port_index
, NULL
);
630 fNetAudioPlaybackBuffer
->SetBuffer(audio_port_index
, GetOutputBuffer(audio_port_index
));
635 fNetTimeMon
->AddLast(float(GetMicroSeconds() - fRcvSyncUst
) / float(fEngineControl
->fPeriodUsecs
) * 100.f
);
641 if (SyncSend() == SOCKET_ERROR
) {
646 fNetTimeMon
->Add(((float)(GetMicroSeconds() - fRcvSyncUst
) / (float)fEngineControl
->fPeriodUsecs
) * 100.f
);
650 if (DataSend() == SOCKET_ERROR
) {
655 fNetTimeMon
->AddLast(((float)(GetMicroSeconds() - fRcvSyncUst
) / (float)fEngineControl
->fPeriodUsecs
) * 100.f
);
661 //driver loader-----------------------------------------------------------------------
668 SERVER_EXPORT jack_driver_desc_t
* driver_get_descriptor()
670 jack_driver_desc_t
* desc
;
671 jack_driver_desc_filler_t filler
;
672 jack_driver_param_value_t value
;
674 desc
= jack_driver_descriptor_construct("net", JackDriverMaster
, "netjack slave backend component", &filler
);
676 strcpy(value
.str
, DEFAULT_MULTICAST_IP
);
677 jack_driver_descriptor_add_parameter(desc
, &filler
, "multicast-ip", 'a', JackDriverParamString
, &value
, NULL
, "Multicast address, or explicit IP of the master", NULL
);
679 value
.i
= DEFAULT_PORT
;
680 jack_driver_descriptor_add_parameter(desc
, &filler
, "udp-net-port", 'p', JackDriverParamInt
, &value
, NULL
, "UDP port", NULL
);
682 value
.i
= DEFAULT_MTU
;
683 jack_driver_descriptor_add_parameter(desc
, &filler
, "mtu", 'M', JackDriverParamInt
, &value
, NULL
, "MTU to the master", NULL
);
686 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");
687 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");
690 jack_driver_descriptor_add_parameter(desc
, &filler
, "midi-in-ports", 'i', JackDriverParamInt
, &value
, NULL
, "Number of midi input ports", "Number of MIDI input ports. If -1, MIDI physical input from the master");
691 jack_driver_descriptor_add_parameter(desc
, &filler
, "midi-out-ports", 'o', JackDriverParamInt
, &value
, NULL
, "Number of midi output ports", "Number of MIDI output ports. If -1, MIDI physical output from the master");
695 jack_driver_descriptor_add_parameter(desc
, &filler
, "celt", 'c', JackDriverParamInt
, &value
, NULL
, "Set CELT encoding and number of kBits per channel", NULL
);
699 jack_driver_descriptor_add_parameter(desc
, &filler
, "opus", 'O', JackDriverParamInt
, &value
, NULL
, "Set Opus encoding and number of kBits per channel", NULL
);
701 strcpy(value
.str
, "'hostname'");
702 jack_driver_descriptor_add_parameter(desc
, &filler
, "client-name", 'n', JackDriverParamString
, &value
, NULL
, "Name of the jack client", NULL
);
705 jack_driver_descriptor_add_parameter(desc
, &filler
, "auto-save", 's', JackDriverParamBool
, &value
, NULL
, "Save/restore connection state when restarting", NULL
);
709 Deactivated for now..
711 jack_driver_descriptor_add_parameter(desc, &filler, "transport-sync", 't', JackDriverParamUInt, &value, NULL, "Sync transport with master's", NULL);
715 jack_driver_descriptor_add_parameter(desc
, &filler
, "latency", 'l', JackDriverParamUInt
, &value
, NULL
, "Network latency", NULL
);
720 SERVER_EXPORT
Jack::JackDriverClientInterface
* driver_initialize(Jack::JackLockedEngine
* engine
, Jack::JackSynchro
* table
, const JSList
* params
)
722 char multicast_ip
[32];
723 char net_name
[JACK_CLIENT_NAME_SIZE
+1] = {0};
725 int mtu
= DEFAULT_MTU
;
726 // Deactivated for now...
727 uint transport_sync
= 0;
728 jack_nframes_t period_size
= 1024; // to be used while waiting for master period_size
729 jack_nframes_t sample_rate
= 48000; // to be used while waiting for master sample_rate
730 int audio_capture_ports
= -1;
731 int audio_playback_ports
= -1;
732 int midi_input_ports
= -1;
733 int midi_output_ports
= -1;
734 int celt_encoding
= -1;
735 int opus_encoding
= -1;
736 bool monitor
= false;
737 int network_latency
= 5;
739 const jack_driver_param_t
* param
;
740 bool auto_save
= false;
742 // Possibly use env variable for UDP port
743 const char* default_udp_port
= getenv("JACK_NETJACK_PORT");
744 udp_port
= (default_udp_port
) ? atoi(default_udp_port
) : DEFAULT_PORT
;
746 // Possibly use env variable for multicast IP
747 const char* default_multicast_ip
= getenv("JACK_NETJACK_MULTICAST");
748 strcpy(multicast_ip
, (default_multicast_ip
) ? default_multicast_ip
: DEFAULT_MULTICAST_IP
);
750 for (node
= params
; node
; node
= jack_slist_next(node
)) {
751 param
= (const jack_driver_param_t
*) node
->data
;
752 switch (param
->character
)
755 assert(strlen(param
->value
.str
) < 32);
756 strcpy(multicast_ip
, param
->value
.str
);
759 udp_port
= param
->value
.ui
;
762 mtu
= param
->value
.i
;
765 audio_capture_ports
= param
->value
.i
;
768 audio_playback_ports
= param
->value
.i
;
771 midi_input_ports
= param
->value
.i
;
774 midi_output_ports
= param
->value
.i
;
778 celt_encoding
= param
->value
.i
;
783 opus_encoding
= param
->value
.i
;
787 strncpy(net_name
, param
->value
.str
, JACK_CLIENT_NAME_SIZE
);
793 Deactivated for now..
795 transport_sync = param->value.ui;
799 network_latency
= param
->value
.ui
;
800 if (network_latency
> NETWORK_MAX_LATENCY
) {
801 printf("Error : network latency is limited to %d\n", NETWORK_MAX_LATENCY
);
810 Jack::JackDriverClientInterface
* driver
= new Jack::JackWaitThreadedDriver(
811 new Jack::JackNetDriver("system", "net_pcm", engine
, table
, multicast_ip
, udp_port
, mtu
,
812 midi_input_ports
, midi_output_ports
,
813 net_name
, transport_sync
,
814 network_latency
, celt_encoding
, opus_encoding
, auto_save
));
815 if (driver
->Open(period_size
, sample_rate
, 1, 1, audio_capture_ports
, audio_playback_ports
, monitor
, "from_master_", "to_master_", 0, 0) == 0) {