Merge branch 'master' into develop
[jack2.git] / common / JackNetDriver.cpp
blobaf5e80975fc8217dc762c29d670626037fc5259d
1 /*
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"
26 using namespace std;
28 namespace Jack
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);
43 fParams.fMtu = mtu;
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;
54 } else {
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;
71 #ifdef JACK_MONITOR
72 fNetTimeMon = NULL;
73 fRcvSyncUst = 0;
74 #endif
77 JackNetDriver::~JackNetDriver()
79 delete[] fMidiCapturePortList;
80 delete[] fMidiPlaybackPortList;
81 #ifdef JACK_MONITOR
82 delete fNetTimeMon;
83 #endif
86 //open, close, attach and detach------------------------------------------------------
88 int JackNetDriver::Open(jack_nframes_t buffer_size,
89 jack_nframes_t samplerate,
90 bool capturing,
91 bool playing,
92 int inchannels,
93 int outchannels,
94 bool monitor,
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,
104 capturing, playing,
105 inchannels, outchannels,
106 monitor,
107 capture_driver_name, playback_driver_name,
108 capture_latency, playback_latency);
111 int JackNetDriver::Close()
113 #ifdef JACK_MONITOR
114 if (fNetTimeMon) {
115 fNetTimeMon->Save();
117 #endif
118 FreeAll();
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()
125 return 0;
128 int JackNetDriver::Detach()
130 return 0;
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");
142 if (fAutoSave) {
143 SaveConnections(0);
145 FreePorts();
147 // New loading, but existing socket, restart the driver
148 if (fSocket.IsSocket()) {
149 jack_info("Restarting driver...");
150 FreeAll();
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");
166 // Init network
167 if (!JackNetSlaveInterface::Init()) {
168 jack_error("Starting network fails...");
169 return false;
172 // Set global parameters
173 if (!SetParams()) {
174 jack_error("SetParams error...");
175 return false;
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.");
207 return false;
210 // Init done, display parameters
211 SessionParamsDisplay(&fParams);
213 // Monitor
214 #ifdef JACK_MONITOR
215 string plot_name;
216 // NetTimeMon
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"),
227 string("sync send"),
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);
236 #endif
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);
247 if (fAutoSave) {
248 LoadConnections(0);
250 return true;
253 void JackNetDriver::FreeAll()
255 FreePorts();
257 delete[] fTxBuffer;
258 delete[] fRxBuffer;
259 delete fNetAudioCaptureBuffer;
260 delete fNetAudioPlaybackBuffer;
261 delete fNetMidiCaptureBuffer;
262 delete fNetMidiPlaybackBuffer;
263 delete[] fMidiCapturePortList;
264 delete[] fMidiPlaybackPortList;
266 fTxBuffer = NULL;
267 fRxBuffer = NULL;
268 fNetAudioCaptureBuffer = NULL;
269 fNetAudioPlaybackBuffer = NULL;
270 fNetMidiCaptureBuffer = NULL;
271 fNetMidiPlaybackBuffer = NULL;
272 fMidiCapturePortList = NULL;
273 fMidiPlaybackPortList = NULL;
275 #ifdef JACK_MONITOR
276 delete fNetTimeMon;
277 fNetTimeMon = NULL;
278 #endif
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_"
319 JackPort* port;
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;
324 int midi_port_index;
326 //audio
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);
333 return -1;
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);
348 return -1;
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());
357 //midi
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);
364 return -1;
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);
378 return -1;
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());
386 UpdateLatencies();
387 return 0;
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;
421 return 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]);
437 free(connections);
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());
450 free(connections);
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
473 int refnum;
474 bool conditional;
475 if (fSendTransportData.fTimebaseMaster == TIMEBASEMASTER) {
476 fEngineControl->fTransport.GetTimebaseMaster(refnum, conditional);
477 if (refnum != -1) {
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.");
491 break;
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);
497 break;
499 case JackTransportRolling :
500 //fEngineControl->fTransport.SetCommand(TransportCommandStart);
501 fEngineControl->fTransport.SetState(JackTransportRolling);
502 jack_info("Master is rolling.");
503 break;
508 void JackNetDriver::EncodeTransportData()
510 // is there a timebase master change ?
511 int refnum;
512 bool conditional;
513 fEngineControl->fTransport.GetTimebaseMaster(refnum, conditional);
514 if (refnum != fLastTimebaseMaster) {
515 // timebase master has released its function
516 if (refnum == -1) {
517 fReturnTransportData.fTimebaseMaster = RELEASE_TIMEBASEMASTER;
518 jack_info("Sending a timebase master release request.");
519 } else {
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;
525 } else {
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()
546 // buffers
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));
555 } else {
556 fNetAudioCaptureBuffer->SetBuffer(audio_port_index, NULL);
558 #else
559 fNetAudioCaptureBuffer->SetBuffer(audio_port_index, GetInputBuffer(audio_port_index));
560 #endif
563 #ifdef JACK_MONITOR
564 fNetTimeMon->New();
565 #endif
567 switch (SyncRecv()) {
569 case SOCKET_ERROR:
570 return SOCKET_ERROR;
572 case SYNC_PACKET_ERROR:
573 // since sync packet is incorrect, don't decode it and continue with data
574 break;
576 default:
577 // decode sync
578 int unused_frames;
579 DecodeSyncPacket(unused_frames);
580 break;
583 #ifdef JACK_MONITOR
584 // For timing
585 fRcvSyncUst = GetMicroSeconds();
586 #endif
588 #ifdef JACK_MONITOR
589 fNetTimeMon->Add(float(GetMicroSeconds() - fRcvSyncUst) / float(fEngineControl->fPeriodUsecs) * 100.f);
590 #endif
591 // audio, midi or sync if driver is late
592 switch (DataRecv()) {
594 case SOCKET_ERROR:
595 return SOCKET_ERROR;
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...
600 break;
603 // take the time at the beginning of the cycle
604 JackDriver::CycleTakeBeginTime();
606 #ifdef JACK_MONITOR
607 fNetTimeMon->Add(float(GetMicroSeconds() - fRcvSyncUst) / float(fEngineControl->fPeriodUsecs) * 100.f);
608 #endif
610 return 0;
613 int JackNetDriver::Write()
615 // buffers
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));
626 } else {
627 fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, NULL);
629 #else
630 fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, GetOutputBuffer(audio_port_index));
631 #endif
634 #ifdef JACK_MONITOR
635 fNetTimeMon->AddLast(float(GetMicroSeconds() - fRcvSyncUst) / float(fEngineControl->fPeriodUsecs) * 100.f);
636 #endif
638 EncodeSyncPacket();
640 // send sync
641 if (SyncSend() == SOCKET_ERROR) {
642 return SOCKET_ERROR;
645 #ifdef JACK_MONITOR
646 fNetTimeMon->Add(((float)(GetMicroSeconds() - fRcvSyncUst) / (float)fEngineControl->fPeriodUsecs) * 100.f);
647 #endif
649 // send data
650 if (DataSend() == SOCKET_ERROR) {
651 return SOCKET_ERROR;
654 #ifdef JACK_MONITOR
655 fNetTimeMon->AddLast(((float)(GetMicroSeconds() - fRcvSyncUst) / (float)fEngineControl->fPeriodUsecs) * 100.f);
656 #endif
658 return 0;
661 //driver loader-----------------------------------------------------------------------
663 #ifdef __cplusplus
664 extern "C"
666 #endif
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);
685 value.i = -1;
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");
689 value.i = -1;
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");
693 #if HAVE_CELT
694 value.i = -1;
695 jack_driver_descriptor_add_parameter(desc, &filler, "celt", 'c', JackDriverParamInt, &value, NULL, "Set CELT encoding and number of kBits per channel", NULL);
696 #endif
697 #if HAVE_OPUS
698 value.i = -1;
699 jack_driver_descriptor_add_parameter(desc, &filler, "opus", 'O', JackDriverParamInt, &value, NULL, "Set Opus encoding and number of kBits per channel", NULL);
700 #endif
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);
704 value.i = false;
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..
710 value.ui = 0U;
711 jack_driver_descriptor_add_parameter(desc, &filler, "transport-sync", 't', JackDriverParamUInt, &value, NULL, "Sync transport with master's", NULL);
714 value.ui = 5U;
715 jack_driver_descriptor_add_parameter(desc, &filler, "latency", 'l', JackDriverParamUInt, &value, NULL, "Network latency", NULL);
717 return desc;
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};
724 int udp_port;
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;
738 const JSList* node;
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)
754 case 'a' :
755 assert(strlen(param->value.str) < 32);
756 strcpy(multicast_ip, param->value.str);
757 break;
758 case 'p':
759 udp_port = param->value.ui;
760 break;
761 case 'M':
762 mtu = param->value.i;
763 break;
764 case 'C':
765 audio_capture_ports = param->value.i;
766 break;
767 case 'P':
768 audio_playback_ports = param->value.i;
769 break;
770 case 'i':
771 midi_input_ports = param->value.i;
772 break;
773 case 'o':
774 midi_output_ports = param->value.i;
775 break;
776 #if HAVE_CELT
777 case 'c':
778 celt_encoding = param->value.i;
779 break;
780 #endif
781 #if HAVE_OPUS
782 case 'O':
783 opus_encoding = param->value.i;
784 break;
785 #endif
786 case 'n' :
787 strncpy(net_name, param->value.str, JACK_CLIENT_NAME_SIZE);
788 break;
789 case 's':
790 auto_save = true;
791 break;
793 Deactivated for now..
794 case 't' :
795 transport_sync = param->value.ui;
796 break;
798 case 'l' :
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);
802 return NULL;
804 break;
808 try {
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) {
816 return driver;
817 } else {
818 delete driver;
819 return NULL;
822 } catch (...) {
823 return NULL;
827 #ifdef __cplusplus
829 #endif