19 #include "JackNetDriver.h"
20 #include "JackEngineControl.h"
21 #include "JackLockedEngine.h"
22 #include "JackWaitThreadedDriver.h"
28 JackNetDriver::JackNetDriver(
const char* name,
const char* alias, JackLockedEngine* engine, JackSynchro* table,
29 const char* ip,
int udp_port,
int mtu,
int midi_input_ports,
int midi_output_ports,
30 char* net_name, uint transport_sync,
int network_latency,
int celt_encoding)
31 : JackWaiterDriver(name, alias, engine, table), JackNetSlaveInterface(ip, udp_port)
33 jack_log(
"JackNetDriver::JackNetDriver ip %s, port %d", ip, udp_port);
36 if (strcmp(net_name,
"") == 0) {
37 GetHostName(net_name, JACK_CLIENT_NAME_SIZE);
41 fParams.fSendMidiChannels = midi_input_ports;
42 fParams.fReturnMidiChannels = midi_output_ports;
43 if (celt_encoding > 0) {
44 fParams.fSampleEncoder = JackCeltEncoder;
45 fParams.fKBps = celt_encoding;
47 fParams.fSampleEncoder = JackFloatEncoder;
50 strcpy(fParams.fName, net_name);
51 fSocket.GetName(fParams.fSlaveNetName);
52 fParams.fTransportSync = transport_sync;
53 fParams.fNetworkLatency = network_latency;
54 fSendTransportData.fState = -1;
55 fReturnTransportData.fState = -1;
56 fLastTransportState = -1;
57 fLastTimebaseMaster = -1;
58 fMidiCapturePortList = NULL;
59 fMidiPlaybackPortList = NULL;
66 JackNetDriver::~JackNetDriver()
68 delete[] fMidiCapturePortList;
69 delete[] fMidiPlaybackPortList;
77 int JackNetDriver::Close()
85 return JackWaiterDriver::Close();
89 int JackNetDriver::Attach()
94 int JackNetDriver::Detach()
105 bool JackNetDriver::Initialize()
107 jack_log(
"JackNetDriver::Initialize");
112 if (fSocket.IsSocket()) {
118 fParams.fSendAudioChannels = fCaptureChannels;
119 fParams.fReturnAudioChannels = fPlaybackChannels;
120 fParams.fSlaveSyncMode = fEngineControl->fSyncMode;
123 jack_info(
"NetDriver started in %s mode %s Master's transport sync.",
124 (fParams.fSlaveSyncMode) ?
"sync" :
"async", (fParams.fTransportSync) ?
"with" :
"without");
127 if (!JackNetSlaveInterface::Init()) {
139 fCaptureChannels = fParams.fSendAudioChannels;
140 fPlaybackChannels = fParams.fReturnAudioChannels;
143 fMidiCapturePortList =
new jack_port_id_t [fParams.fSendMidiChannels];
144 fMidiPlaybackPortList =
new jack_port_id_t [fParams.fReturnMidiChannels];
146 assert(fMidiCapturePortList);
147 assert(fMidiPlaybackPortList);
149 for (
int midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
150 fMidiCapturePortList[midi_port_index] = 0;
152 for (
int midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
153 fMidiPlaybackPortList[midi_port_index] = 0;
157 if (AllocPorts() != 0) {
163 SessionParamsDisplay(&fParams);
169 plot_name = string(fParams.fName);
170 plot_name += string(
"_slave");
171 plot_name += (fEngineControl->fSyncMode) ?
string(
"_sync") : string(
"_async");
172 plot_name += string(
"_latency");
173 fNetTimeMon =
new JackGnuPlotMonitor<float>(128, 5, plot_name);
174 string net_time_mon_fields[] =
176 string(
"sync decoded"),
177 string(
"end of read"),
178 string(
"start of write"),
180 string(
"end of write")
182 string net_time_mon_options[] =
184 string(
"set xlabel \"audio cycles\""),
185 string(
"set ylabel \"% of audio cycle\"")
187 fNetTimeMon->SetPlotFile(net_time_mon_options, 2, net_time_mon_fields, 5);
190 JackTimedDriver::SetBufferSize(fParams.fPeriodSize);
191 JackTimedDriver::SetSampleRate(fParams.fSampleRate);
193 JackDriver::NotifyBufferSize(fParams.fPeriodSize);
194 JackDriver::NotifySampleRate(fParams.fSampleRate);
197 fEngineControl->fTransport.SetNetworkSync(fParams.fTransportSync);
199 RestoreConnections();
203 void JackNetDriver::FreeAll()
209 delete fNetAudioCaptureBuffer;
210 delete fNetAudioPlaybackBuffer;
211 delete fNetMidiCaptureBuffer;
212 delete fNetMidiPlaybackBuffer;
213 delete[] fMidiCapturePortList;
214 delete[] fMidiPlaybackPortList;
218 fNetAudioCaptureBuffer = NULL;
219 fNetAudioPlaybackBuffer = NULL;
220 fNetMidiCaptureBuffer = NULL;
221 fNetMidiPlaybackBuffer = NULL;
222 fMidiCapturePortList = NULL;
223 fMidiPlaybackPortList = NULL;
232 int JackNetDriver::AllocPorts()
234 jack_log(
"JackNetDriver::AllocPorts fBufferSize = %ld fSampleRate = %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate);
246 jack_port_id_t port_index;
247 char name[REAL_JACK_PORT_NAME_SIZE];
248 char alias[REAL_JACK_PORT_NAME_SIZE];
249 int audio_port_index;
254 for (audio_port_index = 0; audio_port_index < fCaptureChannels; audio_port_index++) {
255 snprintf(alias,
sizeof(alias),
"%s:%s:out%d", fAliasName, fCaptureDriverName, audio_port_index + 1);
256 snprintf(name,
sizeof(name),
"%s:capture_%d", fClientControl.fName, audio_port_index + 1);
257 if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE,
258 CaptureDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) {
259 jack_error(
"driver: cannot register port for %s", name);
264 port = fGraphManager->GetPort(port_index);
265 port->SetAlias(alias);
266 range.
min = range.
max = fEngineControl->fBufferSize;
267 port->SetLatencyRange(JackCaptureLatency, &range);
268 fCapturePortList[audio_port_index] = port_index;
269 jack_log(
"JackNetDriver::AllocPorts() fCapturePortList[%d] audio_port_index = %ld fPortLatency = %ld", audio_port_index, port_index, port->GetLatency());
272 for (audio_port_index = 0; audio_port_index < fPlaybackChannels; audio_port_index++) {
273 snprintf(alias,
sizeof(alias),
"%s:%s:in%d", fAliasName, fPlaybackDriverName, audio_port_index + 1);
274 snprintf(name,
sizeof(name),
"%s:playback_%d",fClientControl.fName, audio_port_index + 1);
275 if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE,
276 PlaybackDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) {
277 jack_error(
"driver: cannot register port for %s", name);
282 port = fGraphManager->GetPort(port_index);
283 port->SetAlias(alias);
284 range.
min = range.
max = (fParams.fNetworkLatency * fEngineControl->fBufferSize + (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize);
285 port->SetLatencyRange(JackPlaybackLatency, &range);
286 fPlaybackPortList[audio_port_index] = port_index;
287 jack_log(
"JackNetDriver::AllocPorts() fPlaybackPortList[%d] audio_port_index = %ld fPortLatency = %ld", audio_port_index, port_index, port->GetLatency());
291 for (midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
292 snprintf(alias,
sizeof(alias),
"%s:%s:out%d", fAliasName, fCaptureDriverName, midi_port_index + 1);
293 snprintf(name,
sizeof (name),
"%s:midi_capture_%d", fClientControl.fName, midi_port_index + 1);
294 if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_MIDI_TYPE,
295 CaptureDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) {
296 jack_error(
"driver: cannot register port for %s", name);
301 port = fGraphManager->GetPort(port_index);
302 range.
min = range.
max = fEngineControl->fBufferSize;
303 port->SetLatencyRange(JackCaptureLatency, &range);
304 fMidiCapturePortList[midi_port_index] = port_index;
305 jack_log(
"JackNetDriver::AllocPorts() fMidiCapturePortList[%d] midi_port_index = %ld fPortLatency = %ld", midi_port_index, port_index, port->GetLatency());
308 for (midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
309 snprintf(alias,
sizeof(alias),
"%s:%s:in%d", fAliasName, fPlaybackDriverName, midi_port_index + 1);
310 snprintf(name,
sizeof(name),
"%s:midi_playback_%d", fClientControl.fName, midi_port_index + 1);
311 if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_MIDI_TYPE,
312 PlaybackDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) {
313 jack_error(
"driver: cannot register port for %s", name);
318 port = fGraphManager->GetPort(port_index);
319 range.
min = range.
max = (fParams.fNetworkLatency * fEngineControl->fBufferSize + (fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize);
320 port->SetLatencyRange(JackPlaybackLatency, &range);
321 fMidiPlaybackPortList[midi_port_index] = port_index;
322 jack_log(
"JackNetDriver::AllocPorts() fMidiPlaybackPortList[%d] midi_port_index = %ld fPortLatency = %ld", midi_port_index, port_index, port->GetLatency());
328 int JackNetDriver::FreePorts()
330 jack_log(
"JackNetDriver::FreePorts");
332 for (
int audio_port_index = 0; audio_port_index < fCaptureChannels; audio_port_index++) {
333 if (fCapturePortList[audio_port_index] > 0) {
334 fEngine->PortUnRegister(fClientControl.fRefNum, fCapturePortList[audio_port_index]);
335 fCapturePortList[audio_port_index] = 0;
339 for (
int audio_port_index = 0; audio_port_index < fPlaybackChannels; audio_port_index++) {
340 if (fPlaybackPortList[audio_port_index] > 0) {
341 fEngine->PortUnRegister(fClientControl.fRefNum, fPlaybackPortList[audio_port_index]);
342 fPlaybackPortList[audio_port_index] = 0;
346 for (
int midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
347 if (fMidiCapturePortList && fMidiCapturePortList[midi_port_index] > 0) {
348 fGraphManager->ReleasePort(fClientControl.fRefNum, fMidiCapturePortList[midi_port_index]);
349 fMidiCapturePortList[midi_port_index] = 0;
353 for (
int midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
354 if (fMidiPlaybackPortList && fMidiPlaybackPortList[midi_port_index] > 0) {
355 fEngine->PortUnRegister(fClientControl.fRefNum, fMidiPlaybackPortList[midi_port_index]);
356 fMidiPlaybackPortList[midi_port_index] = 0;
362 void JackNetDriver::SaveConnections()
364 JackDriver::SaveConnections();
365 const char** connections;
367 for (
int i = 0; i < fParams.fSendMidiChannels; ++i) {
368 if (fCapturePortList[i] && (connections = fGraphManager->GetConnections(fMidiCapturePortList[i])) != 0) {
369 for (
int j = 0; connections[j]; j++) {
370 fConnections.push_back(make_pair(fGraphManager->GetPort(fMidiCapturePortList[i])->GetName(), connections[j]));
376 for (
int i = 0; i < fParams.fReturnMidiChannels; ++i) {
377 if (fPlaybackPortList[i] && (connections = fGraphManager->GetConnections(fMidiPlaybackPortList[i])) != 0) {
378 for (
int j = 0; connections[j]; j++) {
379 fConnections.push_back(make_pair(connections[j], fGraphManager->GetPort(fMidiPlaybackPortList[i])->GetName()));
386 JackMidiBuffer* JackNetDriver::GetMidiInputBuffer(
int port_index)
388 return static_cast<JackMidiBuffer*
>(fGraphManager->GetBuffer(fMidiCapturePortList[port_index], fEngineControl->fBufferSize));
391 JackMidiBuffer* JackNetDriver::GetMidiOutputBuffer(
int port_index)
393 return static_cast<JackMidiBuffer*
>(fGraphManager->GetBuffer(fMidiPlaybackPortList[port_index], fEngineControl->fBufferSize));
397 void JackNetDriver::DecodeTransportData()
405 if (fSendTransportData.fTimebaseMaster == TIMEBASEMASTER) {
406 fEngineControl->fTransport.GetTimebaseMaster(refnum, conditional);
408 fEngineControl->fTransport.ResetTimebase(refnum);
410 jack_info(
"The NetMaster is now the new timebase master.");
414 if (fSendTransportData.fNewState &&(fSendTransportData.fState != fEngineControl->fTransport.GetState())) {
416 switch (fSendTransportData.fState)
418 case JackTransportStopped :
419 fEngineControl->fTransport.SetCommand(TransportCommandStop);
423 case JackTransportStarting :
424 fEngineControl->fTransport.RequestNewPos(&fSendTransportData.fPosition);
425 fEngineControl->fTransport.SetCommand(TransportCommandStart);
426 jack_info(
"Master starts transport frame = %d", fSendTransportData.fPosition.frame);
429 case JackTransportRolling :
431 fEngineControl->fTransport.SetState(JackTransportRolling);
438 void JackNetDriver::EncodeTransportData()
443 fEngineControl->fTransport.GetTimebaseMaster(refnum, conditional);
444 if (refnum != fLastTimebaseMaster) {
447 fReturnTransportData.fTimebaseMaster = RELEASE_TIMEBASEMASTER;
448 jack_info(
"Sending a timebase master release request.");
451 fReturnTransportData.fTimebaseMaster = (conditional) ? CONDITIONAL_TIMEBASEMASTER : TIMEBASEMASTER;
452 jack_info(
"Sending a %s timebase master request.", (conditional) ?
"conditional" :
"non-conditional");
454 fLastTimebaseMaster = refnum;
456 fReturnTransportData.fTimebaseMaster = NO_CHANGE;
460 fReturnTransportData.fState = fEngineControl->fTransport.Query(&fReturnTransportData.fPosition);
463 fReturnTransportData.fNewState = ((fReturnTransportData.fState == JackTransportNetStarting) &&
464 (fReturnTransportData.fState != fLastTransportState) &&
465 (fReturnTransportData.fState != fSendTransportData.fState));
466 if (fReturnTransportData.fNewState) {
467 jack_info(
"Sending '%s'.", GetTransportState(fReturnTransportData.fState));
469 fLastTransportState = fReturnTransportData.fState;
474 int JackNetDriver::Read()
477 for (
int midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
478 fNetMidiCaptureBuffer->SetBuffer(midi_port_index, GetMidiInputBuffer(midi_port_index));
481 for (
int audio_port_index = 0; audio_port_index < fParams.fSendAudioChannels; audio_port_index++) {
482 #ifdef OPTIMIZED_PROTOCOL
483 if (fGraphManager->GetConnectionsNum(fCapturePortList[audio_port_index]) > 0) {
484 fNetAudioCaptureBuffer->SetBuffer(audio_port_index, GetInputBuffer(audio_port_index));
486 fNetAudioCaptureBuffer->SetBuffer(audio_port_index, NULL);
489 fNetAudioCaptureBuffer->SetBuffer(audio_port_index, GetInputBuffer(audio_port_index));
498 if (SyncRecv() == SOCKET_ERROR) {
504 fRcvSyncUst = GetMicroSeconds();
512 fNetTimeMon->Add((
float(GetMicroSeconds() - fRcvSyncUst) /
float(fEngineControl->fPeriodUsecs) * 100.f);
515 int res = DataRecv();
516 if (res == SOCKET_ERROR) {
518 }
else if (res == NET_PACKET_ERROR) {
519 jack_time_t cur_time = GetMicroSeconds();
520 NotifyXRun(cur_time,
float(cur_time - fBeginDateUst));
524 JackDriver::CycleTakeBeginTime();
527 fNetTimeMon->Add((
float(GetMicroSeconds() - fRcvSyncUst) /
float(fEngineControl->fPeriodUsecs) * 100.f);
533 int JackNetDriver::Write()
536 for (
int midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
537 fNetMidiPlaybackBuffer->SetBuffer(midi_port_index, GetMidiOutputBuffer(midi_port_index));
540 for (
int audio_port_index = 0; audio_port_index < fPlaybackChannels; audio_port_index++) {
541 #ifdef OPTIMIZED_PROTOCOL
543 if (fNetAudioPlaybackBuffer->GetConnected(audio_port_index)) {
544 if (fGraphManager->GetConnectionsNum(fPlaybackPortList[audio_port_index]) > 0) {
545 fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, GetOutputBuffer(audio_port_index));
547 fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, NULL);
550 fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, NULL);
553 fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, GetOutputBuffer(audio_port_index));
558 fNetTimeMon->AddLast((
float(GetMicroSeconds() - fRcvSyncUst) /
float(fEngineControl->fPeriodUsecs) * 100.f);
565 if (SyncSend() == SOCKET_ERROR) {
570 fNetTimeMon->Add(((
float)(GetMicroSeconds() - fRcvSyncUst) / (
float)fEngineControl->fPeriodUsecs) * 100.f);
574 if (DataSend() == SOCKET_ERROR) {
579 fNetTimeMon->AddLast(((
float)(GetMicroSeconds() - fRcvSyncUst) / (
float)fEngineControl->fPeriodUsecs) * 100.f);
597 desc = jack_driver_descriptor_construct(
"net", JackDriverMaster,
"netjack slave backend component", &filler);
599 strcpy(value.str, DEFAULT_MULTICAST_IP);
600 jack_driver_descriptor_add_parameter(desc, &filler,
"multicast-ip",
'a', JackDriverParamString, &value, NULL,
"Multicast Address", NULL);
602 value.i = DEFAULT_PORT;
603 jack_driver_descriptor_add_parameter(desc, &filler,
"udp-net-port",
'p', JackDriverParamInt, &value, NULL,
"UDP port", NULL);
605 value.i = DEFAULT_MTU;
606 jack_driver_descriptor_add_parameter(desc, &filler,
"mtu",
'M', JackDriverParamInt, &value, NULL,
"MTU to the master", NULL);
609 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");
610 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");
613 jack_driver_descriptor_add_parameter(desc, &filler,
"midi-in-ports",
'i', JackDriverParamInt, &value, NULL,
"Number of midi input ports", NULL);
614 jack_driver_descriptor_add_parameter(desc, &filler,
"midi-out-ports",
'o', JackDriverParamInt, &value, NULL,
"Number of midi output ports", NULL);
618 jack_driver_descriptor_add_parameter(desc, &filler,
"celt",
'c', JackDriverParamInt, &value, NULL,
"Set CELT encoding and number of kBits per channel", NULL);
620 strcpy(value.str,
"'hostname'");
621 jack_driver_descriptor_add_parameter(desc, &filler,
"client-name",
'n', JackDriverParamString, &value, NULL,
"Name of the jack client", NULL);
624 jack_driver_descriptor_add_parameter(desc, &filler,
"transport-sync",
't', JackDriverParamUInt, &value, NULL,
"Sync transport with master's", NULL);
627 jack_driver_descriptor_add_parameter(desc, &filler,
"latency",
'l', JackDriverParamUInt, &value, NULL,
"Network latency", NULL);
634 char multicast_ip[32];
635 char net_name[JACK_CLIENT_NAME_SIZE + 1];
637 int mtu = DEFAULT_MTU;
639 uint transport_sync = 0;
640 jack_nframes_t period_size = 1024;
641 jack_nframes_t sample_rate = 48000;
642 int audio_capture_ports = -1;
643 int audio_playback_ports = -1;
644 int midi_input_ports = 0;
645 int midi_output_ports = 0;
646 int celt_encoding = -1;
647 bool monitor =
false;
648 int network_latency = 5;
655 const char* default_udp_port = getenv(
"JACK_NETJACK_PORT");
656 udp_port = (default_udp_port) ? atoi(default_udp_port) : DEFAULT_PORT;
658 const char* default_multicast_ip = getenv(
"JACK_NETJACK_MULTICAST");
659 if (default_multicast_ip) {
660 strcpy(multicast_ip, default_multicast_ip);
662 strcpy(multicast_ip, DEFAULT_MULTICAST_IP);
665 for (node = params; node; node = jack_slist_next(node)) {
667 switch (param->character)
670 assert(strlen(param->value.str) < 32);
671 strcpy(multicast_ip, param->value.str);
674 udp_port = param->value.ui;
677 mtu = param->value.i;
680 audio_capture_ports = param->value.i;
683 audio_playback_ports = param->value.i;
686 midi_input_ports = param->value.i;
689 midi_output_ports = param->value.i;
693 celt_encoding = param->value.i;
697 strncpy(net_name, param->value.str, JACK_CLIENT_NAME_SIZE);
700 transport_sync = param->value.ui;
703 network_latency = param->value.ui;
704 if (network_latency > NETWORK_MAX_LATENCY) {
705 printf(
"Error : network latency is limited to %d\n", NETWORK_MAX_LATENCY);
716 midi_input_ports, midi_output_ports,
717 net_name, transport_sync,
718 network_latency, celt_encoding));
719 if (driver->Open(period_size, sample_rate, 1, 1, audio_capture_ports, audio_playback_ports, monitor,
"from_master_",
"to_master_", 0, 0) == 0) {