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);
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;
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;
82 int JackNetDriver::Close()
90 return JackWaiterDriver::Close();
94 int JackNetDriver::Attach()
99 int JackNetDriver::Detach()
110 bool JackNetDriver::Initialize()
112 jack_log(
"JackNetDriver::Initialize");
117 if (fSocket.IsSocket()) {
123 fParams.fSendAudioChannels = fCaptureChannels;
124 fParams.fReturnAudioChannels = fPlaybackChannels;
125 fParams.fSlaveSyncMode = fEngineControl->fSyncMode;
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()) {
144 fCaptureChannels = fParams.fSendAudioChannels;
145 fPlaybackChannels = fParams.fReturnAudioChannels;
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;
162 if (AllocPorts() != 0) {
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);
195 JackTimedDriver::SetBufferSize(fParams.fPeriodSize);
196 JackTimedDriver::SetSampleRate(fParams.fSampleRate);
198 JackDriver::NotifyBufferSize(fParams.fPeriodSize);
199 JackDriver::NotifySampleRate(fParams.fSampleRate);
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;
237 int JackNetDriver::AllocPorts()
239 jack_log(
"JackNetDriver::AllocPorts fBufferSize = %ld fSampleRate = %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate);
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;
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));
402 void JackNetDriver::DecodeTransportData()
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.");
419 if (fSendTransportData.fNewState &&(fSendTransportData.fState != fEngineControl->fTransport.GetState())) {
421 switch (fSendTransportData.fState)
423 case JackTransportStopped :
424 fEngineControl->fTransport.SetCommand(TransportCommandStop);
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 :
436 fEngineControl->fTransport.SetState(JackTransportRolling);
443 void JackNetDriver::EncodeTransportData()
448 fEngineControl->fTransport.GetTimebaseMaster(refnum, conditional);
449 if (refnum != fLastTimebaseMaster) {
452 fReturnTransportData.fTimebaseMaster = RELEASE_TIMEBASEMASTER;
453 jack_info(
"Sending a timebase master release request.");
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;
465 fReturnTransportData.fState = fEngineControl->fTransport.Query(&fReturnTransportData.fPosition);
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;
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));
503 if (SyncRecv() == SOCKET_ERROR) {
509 fRcvSyncUst = GetMicroSeconds();
517 fNetTimeMon->Add(
float(GetMicroSeconds() - fRcvSyncUst) /
float(fEngineControl->fPeriodUsecs) * 100.f);
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));
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
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);
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);
640 jack_driver_descriptor_add_parameter(desc, &filler,
"latency",
'l', JackDriverParamUInt, &value, NULL,
"Network latency", NULL);
647 char multicast_ip[32];
648 char net_name[JACK_CLIENT_NAME_SIZE + 1];
650 int mtu = DEFAULT_MTU;
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;
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)) {
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);
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);
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) {
To be used as a wrapper of JackNetDriver.
Inter process synchronization using using Mach semaphore.
Locked Engine, access to methods is serialized using a mutex.
SERVER_EXPORT void jack_error(const char *fmt,...)
SERVER_EXPORT void jack_info(const char *fmt,...)
The base interface for drivers clients.
SERVER_EXPORT void jack_log(const char *fmt,...)