Jack2 1.9.12

JackNetManager.cpp
1 /*
2 Copyright(C) 2008-2011 Romain Moret at Grame
3
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.
8
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.
13
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.
17 */
18
19 #include "JackNetManager.h"
20 #include "JackArgParser.h"
21 #include "JackServerGlobals.h"
22 #include "JackLockedEngine.h"
23 #include "thread.h"
24
25 using namespace std;
26
27 namespace Jack
28 {
29 //JackNetMaster******************************************************************************************************
30
31 JackNetMaster::JackNetMaster(JackNetSocket& socket, session_params_t& params, const char* multicast_ip)
32 : JackNetMasterInterface(params, socket, multicast_ip)
33 {
34 jack_log("JackNetMaster::JackNetMaster");
35
36 //settings
37 fName = const_cast<char*>(fParams.fName);
38 fClient = NULL;
39 fSendTransportData.fState = -1;
40 fReturnTransportData.fState = -1;
41 fLastTransportState = -1;
42 int port_index;
43
44 //jack audio ports
45 fAudioCapturePorts = new jack_port_t* [fParams.fSendAudioChannels];
46 for (port_index = 0; port_index < fParams.fSendAudioChannels; port_index++) {
47 fAudioCapturePorts[port_index] = NULL;
48 }
49
50 fAudioPlaybackPorts = new jack_port_t* [fParams.fReturnAudioChannels];
51 for (port_index = 0; port_index < fParams.fReturnAudioChannels; port_index++) {
52 fAudioPlaybackPorts[port_index] = NULL;
53 }
54
55 //jack midi ports
56 fMidiCapturePorts = new jack_port_t* [fParams.fSendMidiChannels];
57 for (port_index = 0; port_index < fParams.fSendMidiChannels; port_index++) {
58 fMidiCapturePorts[port_index] = NULL;
59 }
60
61 fMidiPlaybackPorts = new jack_port_t* [fParams.fReturnMidiChannels];
62 for (port_index = 0; port_index < fParams.fReturnMidiChannels; port_index++) {
63 fMidiPlaybackPorts[port_index] = NULL;
64 }
65
66 //monitor
67 #ifdef JACK_MONITOR
68 fPeriodUsecs = (int)(1000000.f * ((float) fParams.fPeriodSize / (float) fParams.fSampleRate));
69 string plot_name;
70 plot_name = string(fParams.fName);
71 plot_name += string("_master");
72 plot_name += string((fParams.fSlaveSyncMode) ? "_sync" : "_async");
73 plot_name += string("_latency");
74 fNetTimeMon = new JackGnuPlotMonitor<float>(128, 4, plot_name);
75 string net_time_mon_fields[] =
76 {
77 string("sync send"),
78 string("end of send"),
79 string("sync recv"),
80 string("end of cycle")
81 };
82 string net_time_mon_options[] =
83 {
84 string("set xlabel \"audio cycles\""),
85 string("set ylabel \"% of audio cycle\"")
86 };
87 fNetTimeMon->SetPlotFile(net_time_mon_options, 2, net_time_mon_fields, 4);
88 #endif
89 }
90
91 JackNetMaster::~JackNetMaster()
92 {
93 jack_log("JackNetMaster::~JackNetMaster ID = %u", fParams.fID);
94
95 if (fClient) {
96 jack_deactivate(fClient);
97 FreePorts();
98 jack_client_close(fClient);
99 }
100 delete[] fAudioCapturePorts;
101 delete[] fAudioPlaybackPorts;
102 delete[] fMidiCapturePorts;
103 delete[] fMidiPlaybackPorts;
104 #ifdef JACK_MONITOR
105 fNetTimeMon->Save();
106 delete fNetTimeMon;
107 #endif
108 }
109 //init--------------------------------------------------------------------------------
110 bool JackNetMaster::Init(bool auto_connect)
111 {
112 //network init
113 if (!JackNetMasterInterface::Init()) {
114 jack_error("JackNetMasterInterface::Init() error...");
115 return false;
116 }
117
118 //set global parameters
119 if (!SetParams()) {
120 jack_error("SetParams error...");
121 return false;
122 }
123
124 //jack client and process
125 jack_status_t status;
126 if ((fClient = jack_client_open(fName, JackNullOption, &status, NULL)) == NULL) {
127 jack_error("Can't open a new JACK client");
128 return false;
129 }
130
131 if (jack_set_process_callback(fClient, SetProcess, this) < 0) {
132 goto fail;
133 }
134
135 if (jack_set_buffer_size_callback(fClient, SetBufferSize, this) < 0) {
136 goto fail;
137 }
138
139 if (jack_set_sample_rate_callback(fClient, SetSampleRate, this) < 0) {
140 goto fail;
141 }
142
143 if (jack_set_latency_callback(fClient, LatencyCallback, this) < 0) {
144 goto fail;
145 }
146
147 /*
148 if (jack_set_port_connect_callback(fClient, SetConnectCallback, this) < 0) {
149 goto fail;
150 }
151 */
152
153 if (AllocPorts() != 0) {
154 jack_error("Can't allocate JACK ports");
155 goto fail;
156 }
157
158 //process can now run
159 fRunning = true;
160
161 //finally activate jack client
162 if (jack_activate(fClient) != 0) {
163 jack_error("Can't activate JACK client");
164 goto fail;
165 }
166
167 if (auto_connect) {
168 ConnectPorts();
169 }
170 jack_info("New NetMaster started");
171 return true;
172
173 fail:
174 FreePorts();
175 jack_client_close(fClient);
176 fClient = NULL;
177 return false;
178 }
179
180 //jack ports--------------------------------------------------------------------------
181 int JackNetMaster::AllocPorts()
182 {
183 int i;
184 char name[32];
185 jack_log("JackNetMaster::AllocPorts");
186
187 //audio
188 for (i = 0; i < fParams.fSendAudioChannels; i++) {
189 snprintf(name, sizeof(name), "to_slave_%d", i+1);
190 if ((fAudioCapturePorts[i] = jack_port_register(fClient, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0)) == NULL) {
191 return -1;
192 }
193 }
194
195 for (i = 0; i < fParams.fReturnAudioChannels; i++) {
196 snprintf(name, sizeof(name), "from_slave_%d", i+1);
197 if ((fAudioPlaybackPorts[i] = jack_port_register(fClient, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput | JackPortIsTerminal, 0)) == NULL) {
198 return -1;
199 }
200 }
201
202 //midi
203 for (i = 0; i < fParams.fSendMidiChannels; i++) {
204 snprintf(name, sizeof(name), "midi_to_slave_%d", i+1);
205 if ((fMidiCapturePorts[i] = jack_port_register(fClient, name, JACK_DEFAULT_MIDI_TYPE, JackPortIsInput | JackPortIsTerminal, 0)) == NULL) {
206 return -1;
207 }
208 }
209
210 for (i = 0; i < fParams.fReturnMidiChannels; i++) {
211 snprintf(name, sizeof(name), "midi_from_slave_%d", i+1);
212 if ((fMidiPlaybackPorts[i] = jack_port_register(fClient, name, JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput | JackPortIsTerminal, 0)) == NULL) {
213 return -1;
214 }
215 }
216 return 0;
217 }
218
219 void JackNetMaster::ConnectPorts()
220 {
221 const char** ports = jack_get_ports(fClient, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortIsPhysical | JackPortIsOutput);
222 if (ports != NULL) {
223 for (int i = 0; i < fParams.fSendAudioChannels && ports[i]; i++) {
224 jack_connect(fClient, ports[i], jack_port_name(fAudioCapturePorts[i]));
225 }
226 jack_free(ports);
227 }
228
229 ports = jack_get_ports(fClient, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortIsPhysical | JackPortIsInput);
230 if (ports != NULL) {
231 for (int i = 0; i < fParams.fReturnAudioChannels && ports[i]; i++) {
232 jack_connect(fClient, jack_port_name(fAudioPlaybackPorts[i]), ports[i]);
233 }
234 jack_free(ports);
235 }
236 }
237
238 void JackNetMaster::FreePorts()
239 {
240 jack_log("JackNetMaster::FreePorts ID = %u", fParams.fID);
241
242 int port_index;
243 for (port_index = 0; port_index < fParams.fSendAudioChannels; port_index++) {
244 if (fAudioCapturePorts[port_index]) {
245 jack_port_unregister(fClient, fAudioCapturePorts[port_index]);
246 }
247 }
248 for (port_index = 0; port_index < fParams.fReturnAudioChannels; port_index++) {
249 if (fAudioPlaybackPorts[port_index]) {
250 jack_port_unregister(fClient, fAudioPlaybackPorts[port_index]);
251 }
252 }
253 for (port_index = 0; port_index < fParams.fSendMidiChannels; port_index++) {
254 if (fMidiCapturePorts[port_index]) {
255 jack_port_unregister(fClient, fMidiCapturePorts[port_index]);
256 }
257 }
258 for (port_index = 0; port_index < fParams.fReturnMidiChannels; port_index++) {
259 if (fMidiPlaybackPorts[port_index]) {
260 jack_port_unregister(fClient, fMidiPlaybackPorts[port_index]);
261 }
262 }
263 }
264
265 //transport---------------------------------------------------------------------------
266 void JackNetMaster::EncodeTransportData()
267 {
268 //is there a new timebase master ?
269 //TODO : check if any timebase callback has been called (and if it's conditional or not) and set correct value...
270 fSendTransportData.fTimebaseMaster = NO_CHANGE;
271
272 //update state and position
273 fSendTransportData.fState = static_cast<uint>(jack_transport_query(fClient, &fSendTransportData.fPosition));
274
275 //is it a new state ?
276 fSendTransportData.fNewState = ((fSendTransportData.fState != fLastTransportState) && (fSendTransportData.fState != fReturnTransportData.fState));
277 if (fSendTransportData.fNewState) {
278 jack_info("Sending '%s' to '%s' frame = %ld", GetTransportState(fSendTransportData.fState), fParams.fName, fSendTransportData.fPosition.frame);
279 }
280 fLastTransportState = fSendTransportData.fState;
281 }
282
283 void JackNetMaster::DecodeTransportData()
284 {
285 //is there timebase master change ?
286 if (fReturnTransportData.fTimebaseMaster != NO_CHANGE) {
287
288 int timebase = 0;
289 switch (fReturnTransportData.fTimebaseMaster)
290 {
291 case RELEASE_TIMEBASEMASTER :
292 timebase = jack_release_timebase(fClient);
293 if (timebase < 0) {
294 jack_error("Can't release timebase master");
295 } else {
296 jack_info("'%s' isn't the timebase master anymore", fParams.fName);
297 }
298 break;
299
300 case TIMEBASEMASTER :
301 timebase = jack_set_timebase_callback(fClient, 0, SetTimebaseCallback, this);
302 if (timebase < 0) {
303 jack_error("Can't set a new timebase master");
304 } else {
305 jack_info("'%s' is the new timebase master", fParams.fName);
306 }
307 break;
308
309 case CONDITIONAL_TIMEBASEMASTER :
310 timebase = jack_set_timebase_callback(fClient, 1, SetTimebaseCallback, this);
311 if (timebase != EBUSY) {
312 if (timebase < 0)
313 jack_error("Can't set a new timebase master");
314 else
315 jack_info("'%s' is the new timebase master", fParams.fName);
316 }
317 break;
318 }
319 }
320
321 //is the slave in a new transport state and is this state different from master's ?
322 if (fReturnTransportData.fNewState && (fReturnTransportData.fState != jack_transport_query(fClient, NULL))) {
323
324 switch (fReturnTransportData.fState)
325 {
326 case JackTransportStopped :
327 jack_transport_stop(fClient);
328 jack_info("'%s' stops transport", fParams.fName);
329 break;
330
331 case JackTransportStarting :
332 if (jack_transport_reposition(fClient, &fReturnTransportData.fPosition) == EINVAL)
333 jack_error("Can't set new position");
334 jack_transport_start(fClient);
335 jack_info("'%s' starts transport frame = %d", fParams.fName, fReturnTransportData.fPosition.frame);
336 break;
337
338 case JackTransportNetStarting :
339 jack_info("'%s' is ready to roll...", fParams.fName);
340 break;
341
342 case JackTransportRolling :
343 jack_info("'%s' is rolling", fParams.fName);
344 break;
345 }
346 }
347 }
348
349 void JackNetMaster::SetTimebaseCallback(jack_transport_state_t state, jack_nframes_t nframes, jack_position_t* pos, int new_pos, void* arg)
350 {
351 static_cast<JackNetMaster*>(arg)->TimebaseCallback(pos);
352 }
353
354 void JackNetMaster::TimebaseCallback(jack_position_t* pos)
355 {
356 pos->bar = fReturnTransportData.fPosition.bar;
357 pos->beat = fReturnTransportData.fPosition.beat;
358 pos->tick = fReturnTransportData.fPosition.tick;
359 pos->bar_start_tick = fReturnTransportData.fPosition.bar_start_tick;
360 pos->beats_per_bar = fReturnTransportData.fPosition.beats_per_bar;
361 pos->beat_type = fReturnTransportData.fPosition.beat_type;
362 pos->ticks_per_beat = fReturnTransportData.fPosition.ticks_per_beat;
363 pos->beats_per_minute = fReturnTransportData.fPosition.beats_per_minute;
364 }
365
366 //sync--------------------------------------------------------------------------------
367
368 bool JackNetMaster::IsSlaveReadyToRoll()
369 {
370 return (fReturnTransportData.fState == JackTransportNetStarting);
371 }
372
373 int JackNetMaster::SetBufferSize(jack_nframes_t nframes, void* arg)
374 {
375 JackNetMaster* obj = static_cast<JackNetMaster*>(arg);
376 if (nframes != obj->fParams.fPeriodSize) {
377 jack_error("Cannot currently handle buffer size change, so JackNetMaster proxy will be removed...");
378 obj->Exit();
379 }
380 return 0;
381 }
382
383 int JackNetMaster::SetSampleRate(jack_nframes_t nframes, void* arg)
384 {
385 JackNetMaster* obj = static_cast<JackNetMaster*>(arg);
386 if (nframes != obj->fParams.fSampleRate) {
387 jack_error("Cannot currently handle sample rate change, so JackNetMaster proxy will be removed...");
388 obj->Exit();
389 }
390 return 0;
391 }
392
393 void JackNetMaster::LatencyCallback(jack_latency_callback_mode_t mode, void* arg)
394 {
395 JackNetMaster* obj = static_cast<JackNetMaster*>(arg);
396 jack_nframes_t port_latency = jack_get_buffer_size(obj->fClient);
397 jack_latency_range_t range;
398
399 //audio
400 for (int i = 0; i < obj->fParams.fSendAudioChannels; i++) {
401 //port latency
402 range.min = range.max = float(obj->fParams.fNetworkLatency * port_latency) / 2.f;
403 jack_port_set_latency_range(obj->fAudioCapturePorts[i], JackPlaybackLatency, &range);
404 }
405
406 //audio
407 for (int i = 0; i < obj->fParams.fReturnAudioChannels; i++) {
408 //port latency
409 range.min = range.max = float(obj->fParams.fNetworkLatency * port_latency) / 2.f + ((obj->fParams.fSlaveSyncMode) ? 0 : port_latency);
410 jack_port_set_latency_range(obj->fAudioPlaybackPorts[i], JackCaptureLatency, &range);
411 }
412
413 //midi
414 for (int i = 0; i < obj->fParams.fSendMidiChannels; i++) {
415 //port latency
416 range.min = range.max = float(obj->fParams.fNetworkLatency * port_latency) / 2.f;
417 jack_port_set_latency_range(obj->fMidiCapturePorts[i], JackPlaybackLatency, &range);
418 }
419
420 //midi
421 for (int i = 0; i < obj->fParams.fReturnMidiChannels; i++) {
422 //port latency
423 range.min = range.max = obj->fParams.fNetworkLatency * port_latency + ((obj->fParams.fSlaveSyncMode) ? 0 : port_latency);
424 jack_port_set_latency_range(obj->fMidiPlaybackPorts[i], JackCaptureLatency, &range);
425 }
426 }
427
428 //process-----------------------------------------------------------------------------
429 int JackNetMaster::SetProcess(jack_nframes_t nframes, void* arg)
430 {
431 try {
432 return static_cast<JackNetMaster*>(arg)->Process();
433 } catch (JackNetException& e) {
434 return 0;
435 }
436 }
437
438 void JackNetMaster::SetConnectCallback(jack_port_id_t a, jack_port_id_t b, int connect, void* arg)
439 {
440 static_cast<JackNetMaster*>(arg)->ConnectCallback(a, b, connect);
441 }
442
443 void JackNetMaster::ConnectCallback(jack_port_id_t a, jack_port_id_t b, int connect)
444 {
445 jack_info("JackNetMaster::ConnectCallback a = %d b = %d connect = %d", a, b, connect);
446 if (connect) {
447 jack_connect(fClient, jack_port_name(jack_port_by_id(fClient, a)), "system:playback_1");
448 }
449 }
450
451 int JackNetMaster::Process()
452 {
453 if (!fRunning) {
454 return 0;
455 }
456
457 #ifdef JACK_MONITOR
458 jack_time_t begin_time = GetMicroSeconds();
459 fNetTimeMon->New();
460 #endif
461
462 //buffers
463 for (int midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
464 fNetMidiCaptureBuffer->SetBuffer(midi_port_index,
465 static_cast<JackMidiBuffer*>(jack_port_get_buffer(fMidiCapturePorts[midi_port_index],
466 fParams.fPeriodSize)));
467 }
468 for (int audio_port_index = 0; audio_port_index < fParams.fSendAudioChannels; audio_port_index++) {
469
470 #ifdef OPTIMIZED_PROTOCOL
471 if (fNetAudioCaptureBuffer->GetConnected(audio_port_index)) {
472 // Port is connected on other side...
473 fNetAudioCaptureBuffer->SetBuffer(audio_port_index,
474 ((jack_port_connected(fAudioCapturePorts[audio_port_index]) > 0)
475 ? static_cast<sample_t*>(jack_port_get_buffer(fAudioCapturePorts[audio_port_index], fParams.fPeriodSize))
476 : NULL));
477 } else {
478 fNetAudioCaptureBuffer->SetBuffer(audio_port_index, NULL);
479 }
480 #else
481 fNetAudioCaptureBuffer->SetBuffer(audio_port_index,
482 static_cast<sample_t*>(jack_port_get_buffer(fAudioCapturePorts[audio_port_index],
483 fParams.fPeriodSize)));
484 #endif
485 // TODO
486 }
487
488 for (int midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
489 fNetMidiPlaybackBuffer->SetBuffer(midi_port_index,
490 static_cast<JackMidiBuffer*>(jack_port_get_buffer(fMidiPlaybackPorts[midi_port_index],
491 fParams.fPeriodSize)));
492 }
493 for (int audio_port_index = 0; audio_port_index < fParams.fReturnAudioChannels; audio_port_index++) {
494
495 #ifdef OPTIMIZED_PROTOCOL
496 sample_t* out = (jack_port_connected(fAudioPlaybackPorts[audio_port_index]) > 0)
497 ? static_cast<sample_t*>(jack_port_get_buffer(fAudioPlaybackPorts[audio_port_index], fParams.fPeriodSize))
498 : NULL;
499 if (out) {
500 memset(out, 0, sizeof(float) * fParams.fPeriodSize);
501 }
502 fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, out);
503 #else
504 sample_t* out = static_cast<sample_t*>(jack_port_get_buffer(fAudioPlaybackPorts[audio_port_index], fParams.fPeriodSize));
505 if (out) {
506 memset(out, 0, sizeof(float) * fParams.fPeriodSize);
507 }
508 fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, out)));
509 #endif
510 }
511
512 // encode the first packet
513 EncodeSyncPacket();
514
515 if (SyncSend() == SOCKET_ERROR) {
516 return SOCKET_ERROR;
517 }
518
519 #ifdef JACK_MONITOR
520 fNetTimeMon->Add((((float)(GetMicroSeconds() - begin_time)) / (float) fPeriodUsecs) * 100.f);
521 #endif
522
523 // send data
524 if (DataSend() == SOCKET_ERROR) {
525 return SOCKET_ERROR;
526 }
527
528 #ifdef JACK_MONITOR
529 fNetTimeMon->Add((((float)(GetMicroSeconds() - begin_time)) / (float) fPeriodUsecs) * 100.f);
530 #endif
531
532 // receive sync
533 int res = SyncRecv();
534 switch (res) {
535
536 case NET_SYNCHING:
537 case SOCKET_ERROR:
538 return res;
539
540 case SYNC_PACKET_ERROR:
541 // Since sync packet is incorrect, don't decode it and continue with data
542 break;
543
544 default:
545 // Decode sync
546 int unused_frames;
547 DecodeSyncPacket(unused_frames);
548 break;
549 }
550
551 #ifdef JACK_MONITOR
552 fNetTimeMon->Add((((float)(GetMicroSeconds() - begin_time)) / (float) fPeriodUsecs) * 100.f);
553 #endif
554
555 // receive data
556 res = DataRecv();
557 switch (res) {
558
559 case 0:
560 case SOCKET_ERROR:
561 return res;
562
563 case DATA_PACKET_ERROR:
564 // Well not a real XRun...
565 JackServerGlobals::fInstance->GetEngine()->NotifyClientXRun(ALL_CLIENTS);
566 break;
567 }
568
569 #ifdef JACK_MONITOR
570 fNetTimeMon->AddLast((((float)(GetMicroSeconds() - begin_time)) / (float) fPeriodUsecs) * 100.f);
571 #endif
572 return 0;
573 }
574
575 void JackNetMaster::SaveConnections(connections_list_t& connections)
576 {
577 // Audio
578 for (int i = 0; i < fParams.fSendAudioChannels; i++) {
579 const char** connected_port = jack_port_get_all_connections(fClient, fAudioCapturePorts[i]);
580 if (connected_port != NULL) {
581 for (int port = 0; connected_port[port]; port++) {
582 connections.push_back(make_pair(connected_port[port], jack_port_name(fAudioCapturePorts[i])));
583 jack_log("INPUT %s ==> %s", connected_port[port], jack_port_name(fAudioCapturePorts[i]));
584 }
585 jack_free(connected_port);
586 }
587 }
588
589 for (int i = 0; i < fParams.fReturnAudioChannels; i++) {
590 const char** connected_port = jack_port_get_all_connections(fClient, fAudioPlaybackPorts[i]);
591 if (connected_port != NULL) {
592 for (int port = 0; connected_port[port]; port++) {
593 connections.push_back(make_pair(jack_port_name(fAudioPlaybackPorts[i]), connected_port[port]));
594 jack_log("OUTPUT %s ==> %s", jack_port_name(fAudioPlaybackPorts[i]), connected_port[port]);
595 }
596 jack_free(connected_port);
597 }
598 }
599
600 // MIDI
601 for (int i = 0; i < fParams.fSendMidiChannels; i++) {
602 const char** connected_port = jack_port_get_all_connections(fClient, fMidiCapturePorts[i]);
603 if (connected_port != NULL) {
604 for (int port = 0; connected_port[port]; port++) {
605 connections.push_back(make_pair(connected_port[port], jack_port_name(fMidiCapturePorts[i])));
606 jack_log("INPUT %s ==> %s", connected_port[port], jack_port_name(fMidiCapturePorts[i]));
607 }
608 jack_free(connected_port);
609 }
610 }
611
612 for (int i = 0; i < fParams.fReturnMidiChannels; i++) {
613 const char** connected_port = jack_port_get_all_connections(fClient, fMidiPlaybackPorts[i]);
614 if (connected_port != NULL) {
615 for (int port = 0; connected_port[port]; port++) {
616 connections.push_back(make_pair(jack_port_name(fMidiPlaybackPorts[i]), connected_port[port]));
617 jack_log("OUTPUT %s ==> %s", jack_port_name(fMidiPlaybackPorts[i]), connected_port[port]);
618 }
619 jack_free(connected_port);
620 }
621 }
622 }
623
624 void JackNetMaster::LoadConnections(const connections_list_t& connections)
625 {
626 list<pair<string, string> >::const_iterator it;
627 for (it = connections.begin(); it != connections.end(); it++) {
628 pair<string, string> connection = *it;
629 jack_connect(fClient, connection.first.c_str(), connection.second.c_str());
630 }
631 }
632
633
634 //JackNetMasterManager***********************************************************************************************
635
636 JackNetMasterManager::JackNetMasterManager(jack_client_t* client, const JSList* params) : fSocket()
637 {
638 jack_log("JackNetMasterManager::JackNetMasterManager");
639
640 fClient = client;
641 fName = jack_get_client_name(fClient);
642 fGlobalID = 0;
643 fRunning = true;
644 fAutoConnect = false;
645 fAutoSave = false;
646
647 const JSList* node;
648 const jack_driver_param_t* param;
649
650 jack_on_shutdown(fClient, SetShutDown, this);
651
652 // Possibly use env variable
653 const char* default_udp_port = getenv("JACK_NETJACK_PORT");
654 fSocket.SetPort((default_udp_port) ? atoi(default_udp_port) : DEFAULT_PORT);
655
656 const char* default_multicast_ip = getenv("JACK_NETJACK_MULTICAST");
657 if (default_multicast_ip) {
658 strcpy(fMulticastIP, default_multicast_ip);
659 } else {
660 strcpy(fMulticastIP, DEFAULT_MULTICAST_IP);
661 }
662
663 for (node = params; node; node = jack_slist_next(node)) {
664
665 param = (const jack_driver_param_t*) node->data;
666 switch (param->character) {
667 case 'a' :
668 if (strlen(param->value.str) < 32) {
669 strcpy(fMulticastIP, param->value.str);
670 } else {
671 jack_error("Can't use multicast address %s, using default %s", param->value.ui, DEFAULT_MULTICAST_IP);
672 }
673 break;
674
675 case 'p':
676 fSocket.SetPort(param->value.ui);
677 break;
678
679 case 'c':
680 fAutoConnect = true;
681 break;
682
683 case 's':
684 fAutoSave = true;
685 break;
686 }
687 }
688
689 //set sync callback
690 jack_set_sync_callback(fClient, SetSyncCallback, this);
691
692 //activate the client (for sync callback)
693 if (jack_activate(fClient) != 0) {
694 jack_error("Can't activate the NetManager client, transport disabled");
695 }
696
697 //launch the manager thread
698 if (jack_client_create_thread(fClient, &fThread, 0, 0, NetManagerThread, this)) {
699 jack_error("Can't create the NetManager control thread");
700 }
701 }
702
703 JackNetMasterManager::~JackNetMasterManager()
704 {
705 jack_log("JackNetMasterManager::~JackNetMasterManager");
706 ShutDown();
707 }
708
709 int JackNetMasterManager::CountIO(const char* type, int flags)
710 {
711 int count = 0;
712 const char** ports = jack_get_ports(fClient, NULL, type, flags);
713 if (ports != NULL) {
714 while (ports[count]) { count++; }
715 jack_free(ports);
716 }
717 return count;
718 }
719
720 void JackNetMasterManager::SetShutDown(void* arg)
721 {
722 static_cast<JackNetMasterManager*>(arg)->ShutDown();
723 }
724
725 void JackNetMasterManager::ShutDown()
726 {
727 jack_log("JackNetMasterManager::ShutDown");
728 if (fRunning) {
729 jack_client_kill_thread(fClient, fThread);
730 fRunning = false;
731 }
732 master_list_t::iterator it;
733 for (it = fMasterList.begin(); it != fMasterList.end(); it++) {
734 delete (*it);
735 }
736 fMasterList.clear();
737 fSocket.Close();
738 SocketAPIEnd();
739 }
740
741 int JackNetMasterManager::SetSyncCallback(jack_transport_state_t state, jack_position_t* pos, void* arg)
742 {
743 return static_cast<JackNetMasterManager*>(arg)->SyncCallback(state, pos);
744 }
745
746 int JackNetMasterManager::SyncCallback(jack_transport_state_t state, jack_position_t* pos)
747 {
748 //check if each slave is ready to roll
749 int res = 1;
750 master_list_it_t it;
751 for (it = fMasterList.begin(); it != fMasterList.end(); it++) {
752 if (!(*it)->IsSlaveReadyToRoll()) {
753 res = 0;
754 }
755 }
756 jack_log("JackNetMasterManager::SyncCallback returns '%s'", (res) ? "true" : "false");
757 return res;
758 }
759
760 void* JackNetMasterManager::NetManagerThread(void* arg)
761 {
762 JackNetMasterManager* master_manager = static_cast<JackNetMasterManager*>(arg);
763 jack_info("Starting Jack NetManager");
764 jack_info("Listening on '%s:%d'", master_manager->fMulticastIP, master_manager->fSocket.GetPort());
765 master_manager->Run();
766 return NULL;
767 }
768
769 void JackNetMasterManager::Run()
770 {
771 jack_log("JackNetMasterManager::Run");
772 //utility variables
773 int attempt = 0;
774
775 //data
776 session_params_t host_params;
777 int rx_bytes = 0;
778 JackNetMaster* net_master;
779
780 //init socket API (win32)
781 if (SocketAPIInit() < 0) {
782 jack_error("Can't init Socket API, exiting...");
783 return;
784 }
785
786 //socket
787 if (fSocket.NewSocket() == SOCKET_ERROR) {
788 jack_error("Can't create NetManager input socket : %s", StrError(NET_ERROR_CODE));
789 return;
790 }
791
792 //bind the socket to the local port
793 if (fSocket.Bind() == SOCKET_ERROR) {
794 jack_error("Can't bind NetManager socket : %s", StrError(NET_ERROR_CODE));
795 fSocket.Close();
796 return;
797 }
798
799 //join multicast group
800 if (fSocket.JoinMCastGroup(fMulticastIP) == SOCKET_ERROR) {
801 jack_error("Can't join multicast group : %s", StrError(NET_ERROR_CODE));
802 }
803
804 //local loop
805 if (fSocket.SetLocalLoop() == SOCKET_ERROR) {
806 jack_error("Can't set local loop : %s", StrError(NET_ERROR_CODE));
807 }
808
809 //set a timeout on the multicast receive (the thread can now be cancelled)
810 if (fSocket.SetTimeOut(MANAGER_INIT_TIMEOUT) == SOCKET_ERROR) {
811 jack_error("Can't set timeout : %s", StrError(NET_ERROR_CODE));
812 }
813
814 //main loop, wait for data, deal with it and wait again
815 do
816 {
817 session_params_t net_params;
818 rx_bytes = fSocket.CatchHost(&net_params, sizeof(session_params_t), 0);
819 SessionParamsNToH(&net_params, &host_params);
820
821 if ((rx_bytes == SOCKET_ERROR) && (fSocket.GetError() != NET_NO_DATA)) {
822 jack_error("Error in receive : %s", StrError(NET_ERROR_CODE));
823 if (++attempt == 10) {
824 jack_error("Can't receive on the socket, exiting net manager");
825 return;
826 }
827 }
828
829 if (rx_bytes == sizeof(session_params_t)) {
830 switch (GetPacketType(&host_params))
831 {
832 case SLAVE_AVAILABLE:
833 if ((net_master = InitMaster(host_params))) {
834 SessionParamsDisplay(&net_master->fParams);
835 } else {
836 jack_error("Can't init new NetMaster...");
837 }
838 jack_info("Waiting for a slave...");
839 break;
840 case KILL_MASTER:
841 if (KillMaster(&host_params)) {
842 jack_info("Waiting for a slave...");
843 }
844 break;
845 default:
846 break;
847 }
848 }
849 }
850 while (fRunning);
851 }
852
853 JackNetMaster* JackNetMasterManager::InitMaster(session_params_t& params)
854 {
855 jack_log("JackNetMasterManager::InitMaster slave : %s", params.fName);
856
857 //check MASTER <<==> SLAVE network protocol coherency
858 if (params.fProtocolVersion != NETWORK_PROTOCOL) {
859 jack_error("Error : slave '%s' is running with a different protocol %d != %d", params.fName, params.fProtocolVersion, NETWORK_PROTOCOL);
860 return NULL;
861 }
862
863 //settings
864 fSocket.GetName(params.fMasterNetName);
865 params.fID = ++fGlobalID;
866 params.fSampleRate = jack_get_sample_rate(fClient);
867 params.fPeriodSize = jack_get_buffer_size(fClient);
868
869 if (params.fSendAudioChannels == -1) {
870 params.fSendAudioChannels = CountIO(JACK_DEFAULT_AUDIO_TYPE, JackPortIsPhysical | JackPortIsOutput);
871 jack_info("Takes physical %d audio input(s) for slave", params.fSendAudioChannels);
872 }
873
874 if (params.fReturnAudioChannels == -1) {
875 params.fReturnAudioChannels = CountIO(JACK_DEFAULT_AUDIO_TYPE, JackPortIsPhysical | JackPortIsInput);
876 jack_info("Takes physical %d audio output(s) for slave", params.fReturnAudioChannels);
877 }
878
879 if (params.fSendMidiChannels == -1) {
880 params.fSendMidiChannels = CountIO(JACK_DEFAULT_MIDI_TYPE, JackPortIsPhysical | JackPortIsOutput);
881 jack_info("Takes physical %d MIDI input(s) for slave", params.fSendMidiChannels);
882 }
883
884 if (params.fReturnMidiChannels == -1) {
885 params.fReturnMidiChannels = CountIO(JACK_DEFAULT_MIDI_TYPE, JackPortIsPhysical | JackPortIsInput);
886 jack_info("Takes physical %d MIDI output(s) for slave", params.fReturnMidiChannels);
887 }
888
889 //create a new master and add it to the list
890 JackNetMaster* master = new JackNetMaster(fSocket, params, fMulticastIP);
891 if (master->Init(fAutoConnect)) {
892 fMasterList.push_back(master);
893 if (fAutoSave && fMasterConnectionList.find(params.fName) != fMasterConnectionList.end()) {
894 master->LoadConnections(fMasterConnectionList[params.fName]);
895 }
896 return master;
897 } else {
898 delete master;
899 return NULL;
900 }
901 }
902
903 master_list_it_t JackNetMasterManager::FindMaster(uint32_t id)
904 {
905 jack_log("JackNetMasterManager::FindMaster ID = %u", id);
906
907 master_list_it_t it;
908 for (it = fMasterList.begin(); it != fMasterList.end(); it++) {
909 if ((*it)->fParams.fID == id) {
910 return it;
911 }
912 }
913 return it;
914 }
915
916 int JackNetMasterManager::KillMaster(session_params_t* params)
917 {
918 jack_log("JackNetMasterManager::KillMaster ID = %u", params->fID);
919
920 master_list_it_t master_it = FindMaster(params->fID);
921 if (master_it != fMasterList.end()) {
922 if (fAutoSave) {
923 fMasterConnectionList[params->fName].clear();
924 (*master_it)->SaveConnections(fMasterConnectionList[params->fName]);
925 }
926 fMasterList.erase(master_it);
927 delete (*master_it);
928 return 1;
929 }
930 return 0;
931 }
932 }//namespace
933
934 static Jack::JackNetMasterManager* master_manager = NULL;
935
936 #ifdef __cplusplus
937 extern "C"
938 {
939 #endif
940
941 SERVER_EXPORT jack_driver_desc_t* jack_get_descriptor()
942 {
943 jack_driver_desc_t * desc;
944 jack_driver_desc_filler_t filler;
945 jack_driver_param_value_t value;
946
947 desc = jack_driver_descriptor_construct("netmanager", JackDriverNone, "netjack multi-cast master component", &filler);
948
949 strcpy(value.str, DEFAULT_MULTICAST_IP);
950 jack_driver_descriptor_add_parameter(desc, &filler, "multicast-ip", 'a', JackDriverParamString, &value, NULL, "Multicast address", NULL);
951
952 value.i = DEFAULT_PORT;
953 jack_driver_descriptor_add_parameter(desc, &filler, "udp-net-port", 'p', JackDriverParamInt, &value, NULL, "UDP port", NULL);
954
955 value.i = false;
956 jack_driver_descriptor_add_parameter(desc, &filler, "auto-connect", 'c', JackDriverParamBool, &value, NULL, "Auto connect netmaster to system ports", NULL);
957
958 value.i = false;
959 jack_driver_descriptor_add_parameter(desc, &filler, "auto-save", 's', JackDriverParamBool, &value, NULL, "Save/restore netmaster connection state when restarted", NULL);
960
961 return desc;
962 }
963
964 SERVER_EXPORT int jack_internal_initialize(jack_client_t* jack_client, const JSList* params)
965 {
966 if (master_manager) {
967 jack_error("Master Manager already loaded");
968 return 1;
969 } else {
970 jack_log("Loading Master Manager");
971 master_manager = new Jack::JackNetMasterManager(jack_client, params);
972 return (master_manager) ? 0 : 1;
973 }
974 }
975
976 SERVER_EXPORT int jack_initialize(jack_client_t* jack_client, const char* load_init)
977 {
978 JSList* params = NULL;
979 bool parse_params = true;
980 int res = 1;
981 jack_driver_desc_t* desc = jack_get_descriptor();
982
983 Jack::JackArgParser parser(load_init);
984 if (parser.GetArgc() > 0) {
985 parse_params = parser.ParseParams(desc, &params);
986 }
987
988 if (parse_params) {
989 res = jack_internal_initialize(jack_client, params);
990 parser.FreeParams(params);
991 }
992 return res;
993 }
994
995 SERVER_EXPORT void jack_finish(void* arg)
996 {
997 if (master_manager) {
998 jack_log("Unloading Master Manager");
999 delete master_manager;
1000 master_manager = NULL;
1001 }
1002 }
1003
1004 #ifdef __cplusplus
1005 }
1006 #endif
_jack_position
Definition: types.h:554
jack_port_unregister
LIB_EXPORT int jack_port_unregister(jack_client_t *, jack_port_t *)
Definition: JackAPI.cpp:1109
Jack::JackArgParser
Definition: JackArgParser.h:37
jack_port_by_id
LIB_EXPORT jack_port_t * jack_port_by_id(jack_client_t *client, jack_port_id_t port_id)
Definition: JackAPI.cpp:1326
jack_driver_param_value_t
Definition: driver_interface.h:64
jack_transport_query
LIB_EXPORT jack_transport_state_t jack_transport_query(const jack_client_t *client, jack_position_t *pos)
Definition: JackAPI.cpp:1583
jack_set_process_callback
LIB_EXPORT int jack_set_process_callback(jack_client_t *client, JackProcessCallback process_callback, void *arg)
Definition: JackAPI.cpp:829
jack_activate
LIB_EXPORT int jack_activate(jack_client_t *client)
Definition: JackAPI.cpp:1067
jack_error
SERVER_EXPORT void jack_error(const char *fmt,...)
Definition: JackError.cpp:92
jack_port_set_latency_range
LIB_EXPORT void jack_port_set_latency_range(jack_port_t *port, jack_latency_callback_mode_t mode, jack_latency_range_t *range)
Definition: JackAPI.cpp:586
jack_connect
LIB_EXPORT int jack_connect(jack_client_t *, const char *source_port, const char *destination_port)
Definition: JackAPI.cpp:1211
_jack_position::beat_type
float beat_type
Definition: types.h:571
_jack_latency_range::min
jack_nframes_t min
Definition: types.h:270
jack_port_register
LIB_EXPORT jack_port_t * jack_port_register(jack_client_t *client, const char *port_name, const char *port_type, unsigned long flags, unsigned long buffer_size)
Definition: JackAPI.cpp:1093
jack_release_timebase
LIB_EXPORT int jack_release_timebase(jack_client_t *client)
Definition: JackAPI.cpp:1517
jack_port_get_all_connections
LIB_EXPORT const char ** jack_port_get_all_connections(const jack_client_t *client, const jack_port_t *port)
Definition: JackAPI.cpp:1162
jack_info
SERVER_EXPORT void jack_info(const char *fmt,...)
Definition: JackError.cpp:100
jack_on_shutdown
LIB_EXPORT void jack_on_shutdown(jack_client_t *client, JackShutdownCallback shutdown_callback, void *arg)
Definition: JackAPI.cpp:805
jack_client_open
LIB_EXPORT jack_client_t * jack_client_open(const char *client_name, jack_options_t options, jack_status_t *status,...)
Definition: JackLibAPI.cpp:167
_jack_position::tick
int32_t tick
Definition: types.h:567
jack_get_client_name
LIB_EXPORT char * jack_get_client_name(jack_client_t *client)
Definition: JackAPI.cpp:1469
thread.h
_jack_latency_range
Definition: types.h:265
jack_transport_start
LIB_EXPORT void jack_transport_start(jack_client_t *client)
Definition: JackAPI.cpp:1623
_jack_latency_range::max
jack_nframes_t max
Definition: types.h:274
_jack_position::beats_per_bar
float beats_per_bar
Definition: types.h:570
jack_get_buffer_size
LIB_EXPORT jack_nframes_t jack_get_buffer_size(jack_client_t *)
Definition: JackAPI.cpp:1275
jack_set_sample_rate_callback
LIB_EXPORT int jack_set_sample_rate_callback(jack_client_t *client, JackSampleRateCallback srate_callback, void *arg)
Definition: JackAPI.cpp:948
jack_port_get_buffer
LIB_EXPORT void * jack_port_get_buffer(jack_port_t *, jack_nframes_t)
Definition: JackAPI.cpp:363
jack_transport_stop
LIB_EXPORT void jack_transport_stop(jack_client_t *client)
Definition: JackAPI.cpp:1635
jack_client_create_thread
LIB_EXPORT int jack_client_create_thread(jack_client_t *client, jack_native_thread_t *thread, int priority, int realtime, thread_routine routine, void *arg)
Definition: JackAPI.cpp:1745
jack_transport_reposition
LIB_EXPORT int jack_transport_reposition(jack_client_t *client, const jack_position_t *pos)
Definition: JackAPI.cpp:1609
_jack_position::frame
jack_nframes_t frame
Definition: types.h:560
jack_get_sample_rate
LIB_EXPORT jack_nframes_t jack_get_sample_rate(jack_client_t *)
Definition: JackAPI.cpp:1261
jack_driver_desc_filler_t
Definition: driver_interface.h:142
_jack_position::beat
int32_t beat
Definition: types.h:566
jack_set_timebase_callback
LIB_EXPORT int jack_set_timebase_callback(jack_client_t *client, int conditional, JackTimebaseCallback timebase_callback, void *arg)
Definition: JackAPI.cpp:1556
_jack_position::bar
int32_t bar
Definition: types.h:565
jack_set_buffer_size_callback
LIB_EXPORT int jack_set_buffer_size_callback(jack_client_t *client, JackBufferSizeCallback bufsize_callback, void *arg)
Definition: JackAPI.cpp:935
jack_set_sync_callback
LIB_EXPORT int jack_set_sync_callback(jack_client_t *client, JackSyncCallback sync_callback, void *arg)
Definition: JackAPI.cpp:1530
jack_port_connected
LIB_EXPORT int jack_port_connected(const jack_port_t *port)
Definition: JackAPI.cpp:458
jack_port_name
LIB_EXPORT const char * jack_port_name(const jack_port_t *port)
Definition: JackAPI.cpp:383
jack_driver_param_t
Definition: driver_interface.h:125
jack_get_ports
LIB_EXPORT const char ** jack_get_ports(jack_client_t *, const char *port_name_pattern, const char *type_name_pattern, unsigned long flags)
Definition: JackAPI.cpp:1289
jack_deactivate
LIB_EXPORT int jack_deactivate(jack_client_t *client)
Definition: JackAPI.cpp:1080
_JSList
Definition: linux/alsa/jslist.h:35
Jack::JackNetMasterManager
Definition: JackNetManager.h:102
jack_log
SERVER_EXPORT void jack_log(const char *fmt,...)
Definition: JackError.cpp:108
jack_driver_desc_t
Definition: driver_interface.h:132
jack_client_kill_thread
LIB_EXPORT int jack_client_kill_thread(jack_client_t *client, jack_native_thread_t thread)
Definition: JackAPI.cpp:1772
jack_client_close
LIB_EXPORT int jack_client_close(jack_client_t *client)
Definition: JackLibAPI.cpp:189