19 #include "JackNetManager.h"
20 #include "JackArgParser.h"
21 #include "JackServerGlobals.h"
22 #include "JackLockedEngine.h"
30 JackNetMaster::JackNetMaster(JackNetSocket& socket, session_params_t& params,
const char* multicast_ip)
31 : JackNetMasterInterface(params, socket, multicast_ip)
33 jack_log(
"JackNetMaster::JackNetMaster");
36 fClientName =
const_cast<char*
>(fParams.fName);
38 fSendTransportData.fState = -1;
39 fReturnTransportData.fState = -1;
40 fLastTransportState = -1;
44 fAudioCapturePorts =
new jack_port_t* [fParams.fSendAudioChannels];
45 for (port_index = 0; port_index < fParams.fSendAudioChannels; port_index++) {
46 fAudioCapturePorts[port_index] = NULL;
49 fAudioPlaybackPorts =
new jack_port_t* [fParams.fReturnAudioChannels];
50 for (port_index = 0; port_index < fParams.fReturnAudioChannels; port_index++) {
51 fAudioPlaybackPorts[port_index] = NULL;
55 fMidiCapturePorts =
new jack_port_t* [fParams.fSendMidiChannels];
56 for (port_index = 0; port_index < fParams.fSendMidiChannels; port_index++) {
57 fMidiCapturePorts[port_index] = NULL;
60 fMidiPlaybackPorts =
new jack_port_t* [fParams.fReturnMidiChannels];
61 for (port_index = 0; port_index < fParams.fReturnMidiChannels; port_index++) {
62 fMidiPlaybackPorts[port_index] = NULL;
67 fPeriodUsecs = (int)(1000000.f * ((
float) fParams.fPeriodSize / (float) fParams.fSampleRate));
69 plot_name = string(fParams.fName);
70 plot_name += string(
"_master");
71 plot_name += string((fParams.fSlaveSyncMode) ?
"_sync" :
"_async");
72 plot_name += string(
"_latency");
73 fNetTimeMon =
new JackGnuPlotMonitor<float>(128, 4, plot_name);
74 string net_time_mon_fields[] =
77 string(
"end of send"),
79 string(
"end of cycle")
81 string net_time_mon_options[] =
83 string(
"set xlabel \"audio cycles\""),
84 string(
"set ylabel \"% of audio cycle\"")
86 fNetTimeMon->SetPlotFile(net_time_mon_options, 2, net_time_mon_fields, 4);
90 JackNetMaster::~JackNetMaster()
92 jack_log(
"JackNetMaster::~JackNetMaster ID = %u", fParams.fID);
95 jack_deactivate(fJackClient);
97 jack_client_close(fJackClient);
99 delete[] fAudioCapturePorts;
100 delete[] fAudioPlaybackPorts;
101 delete[] fMidiCapturePorts;
102 delete[] fMidiPlaybackPorts;
109 bool JackNetMaster::Init(
bool auto_connect)
112 if (!JackNetMasterInterface::Init()) {
113 jack_error(
"JackNetMasterInterface::Init() error...");
124 jack_status_t status;
125 if ((fJackClient = jack_client_open(fClientName, JackNullOption, &status, NULL)) == NULL) {
138 if (AllocPorts() != 0) {
147 if (jack_activate(fJackClient) != 0) {
160 jack_client_close(fJackClient);
166 int JackNetMaster::AllocPorts()
173 jack_log(
"JackNetMaster::AllocPorts");
176 for (i = 0; i < fParams.fSendAudioChannels; i++) {
177 snprintf(name,
sizeof(name),
"to_slave_%d", i+1);
178 if ((fAudioCapturePorts[i] =
jack_port_register(fJackClient, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0)) == NULL)
181 range.
min = range.
max = 0;
185 for (i = 0; i < fParams.fReturnAudioChannels; i++) {
186 snprintf(name,
sizeof(name),
"from_slave_%d", i+1);
187 if ((fAudioPlaybackPorts[i] =
jack_port_register(fJackClient, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput | JackPortIsTerminal, 0)) == NULL)
190 range.
min = range.
max = fParams.fNetworkLatency * port_latency + (fParams.fSlaveSyncMode) ? 0 : port_latency;
195 for (i = 0; i < fParams.fSendMidiChannels; i++) {
196 snprintf(name,
sizeof(name),
"midi_to_slave_%d", i+1);
197 if ((fMidiCapturePorts[i] =
jack_port_register(fJackClient, name, JACK_DEFAULT_MIDI_TYPE, JackPortIsInput | JackPortIsTerminal, 0)) == NULL)
200 range.
min = range.
max = 0;
204 for (i = 0; i < fParams.fReturnMidiChannels; i++) {
205 snprintf(name,
sizeof(name),
"midi_from_slave_%d", i+1);
206 if ((fMidiPlaybackPorts[i] =
jack_port_register(fJackClient, name, JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput | JackPortIsTerminal, 0)) == NULL)
209 range.
min = range.
max = fParams.fNetworkLatency * port_latency + (fParams.fSlaveSyncMode) ? 0 : port_latency;
215 void JackNetMaster::ConnectPorts()
219 ports =
jack_get_ports(fJackClient, NULL, NULL, JackPortIsPhysical | JackPortIsOutput);
221 for (
int i = 0; i < fParams.fSendAudioChannels && ports[i]; i++) {
227 ports =
jack_get_ports(fJackClient, NULL, NULL, JackPortIsPhysical | JackPortIsInput);
229 for (
int i = 0; i < fParams.fReturnAudioChannels && ports[i]; i++) {
236 void JackNetMaster::FreePorts()
238 jack_log(
"JackNetMaster::FreePorts ID = %u", fParams.fID);
241 for (port_index = 0; port_index < fParams.fSendAudioChannels; port_index++) {
242 if (fAudioCapturePorts[port_index]) {
246 for (port_index = 0; port_index < fParams.fReturnAudioChannels; port_index++) {
247 if (fAudioPlaybackPorts[port_index]) {
251 for (port_index = 0; port_index < fParams.fSendMidiChannels; port_index++) {
252 if (fMidiCapturePorts[port_index]) {
256 for (port_index = 0; port_index < fParams.fReturnMidiChannels; port_index++) {
257 if (fMidiPlaybackPorts[port_index]) {
264 void JackNetMaster::EncodeTransportData()
268 fSendTransportData.fTimebaseMaster = NO_CHANGE;
271 fSendTransportData.fState =
static_cast<uint
>(
jack_transport_query(fJackClient, &fSendTransportData.fPosition));
274 fSendTransportData.fNewState = ((fSendTransportData.fState != fLastTransportState) && (fSendTransportData.fState != fReturnTransportData.fState));
275 if (fSendTransportData.fNewState) {
276 jack_info(
"Sending '%s' to '%s' frame = %ld", GetTransportState(fSendTransportData.fState), fParams.fName, fSendTransportData.fPosition.
frame);
278 fLastTransportState = fSendTransportData.fState;
281 void JackNetMaster::DecodeTransportData()
284 if (fReturnTransportData.fTimebaseMaster != NO_CHANGE) {
287 switch (fReturnTransportData.fTimebaseMaster)
289 case RELEASE_TIMEBASEMASTER :
294 jack_info(
"'%s' isn't the timebase master anymore", fParams.fName);
298 case TIMEBASEMASTER :
301 jack_error(
"Can't set a new timebase master");
303 jack_info(
"'%s' is the new timebase master", fParams.fName);
307 case CONDITIONAL_TIMEBASEMASTER :
309 if (timebase != EBUSY) {
311 jack_error(
"Can't set a new timebase master");
313 jack_info(
"'%s' is the new timebase master", fParams.fName);
320 if (fReturnTransportData.fNewState && (fReturnTransportData.fState !=
jack_transport_query(fJackClient, NULL))) {
322 switch (fReturnTransportData.fState)
324 case JackTransportStopped :
326 jack_info(
"'%s' stops transport", fParams.fName);
329 case JackTransportStarting :
333 jack_info(
"'%s' starts transport frame = %d", fParams.fName, fReturnTransportData.fPosition.
frame);
336 case JackTransportNetStarting :
337 jack_info(
"'%s' is ready to roll...", fParams.fName);
340 case JackTransportRolling :
341 jack_info(
"'%s' is rolling", fParams.fName);
347 void JackNetMaster::SetTimebaseCallback(jack_transport_state_t state, jack_nframes_t nframes,
jack_position_t* pos,
int new_pos,
void* arg)
349 static_cast<JackNetMaster*
>(arg)->TimebaseCallback(pos);
354 pos->
bar = fReturnTransportData.fPosition.
bar;
355 pos->
beat = fReturnTransportData.fPosition.
beat;
356 pos->
tick = fReturnTransportData.fPosition.
tick;
357 pos->bar_start_tick = fReturnTransportData.fPosition.bar_start_tick;
360 pos->ticks_per_beat = fReturnTransportData.fPosition.ticks_per_beat;
361 pos->beats_per_minute = fReturnTransportData.fPosition.beats_per_minute;
366 bool JackNetMaster::IsSlaveReadyToRoll()
368 return (fReturnTransportData.fState == JackTransportNetStarting);
371 int JackNetMaster::SetBufferSize(jack_nframes_t nframes,
void* arg)
373 JackNetMaster* obj =
static_cast<JackNetMaster*
>(arg);
374 if (nframes != obj->fParams.fPeriodSize) {
375 jack_error(
"Cannot handle buffer size change, so JackNetMaster proxy will be removed...");
382 int JackNetMaster::SetProcess(jack_nframes_t nframes,
void* arg)
385 return static_cast<JackNetMaster*
>(arg)->Process();
386 }
catch (JackNetException& e) {
391 int JackNetMaster::Process()
400 jack_time_t begin_time = GetMicroSeconds();
405 for (
int midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
406 fNetMidiCaptureBuffer->SetBuffer(midi_port_index,
408 fParams.fPeriodSize)));
410 for (
int audio_port_index = 0; audio_port_index < fParams.fSendAudioChannels; audio_port_index++) {
412 #ifdef OPTIMIZED_PROTOCOL
413 if (fNetAudioCaptureBuffer->GetConnected(audio_port_index)) {
415 fNetAudioCaptureBuffer->SetBuffer(audio_port_index,
417 ? static_cast<sample_t*>(
jack_port_get_buffer(fAudioCapturePorts[audio_port_index], fParams.fPeriodSize))
420 fNetAudioCaptureBuffer->SetBuffer(audio_port_index, NULL);
423 fNetAudioCaptureBuffer->SetBuffer(audio_port_index,
425 fParams.fPeriodSize)));
430 for (
int midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
431 fNetMidiPlaybackBuffer->SetBuffer(midi_port_index,
433 fParams.fPeriodSize)));
435 for (
int audio_port_index = 0; audio_port_index < fParams.fReturnAudioChannels; audio_port_index++) {
437 #ifdef OPTIMIZED_PROTOCOL
439 ? static_cast<sample_t*>(
jack_port_get_buffer(fAudioPlaybackPorts[audio_port_index], fParams.fPeriodSize))
442 memset(out, 0,
sizeof(
float) * fParams.fPeriodSize);
444 fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, out);
446 sample_t* out =
static_cast<sample_t*
>(
jack_port_get_buffer(fAudioPlaybackPorts[audio_port_index], fParams.fPeriodSize));
448 memset(out, 0,
sizeof(
float) * fParams.fPeriodSize);
450 fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, out)));
459 if (SyncSend() == SOCKET_ERROR) {
464 fNetTimeMon->Add((((
float)(GetMicroSeconds() - begin_time)) / (
float) fPeriodUsecs) * 100.f);
468 if (DataSend() == SOCKET_ERROR) {
473 fNetTimeMon->Add((((
float)(GetMicroSeconds() - begin_time)) / (
float) fPeriodUsecs) * 100.f);
477 jack_error(
"Connection is not synched, skip cycle...");
482 if ((res == 0) || (res == SOCKET_ERROR)) {
507 fNetTimeMon->Add((((
float)(GetMicroSeconds() - begin_time)) / (
float) fPeriodUsecs) * 100.f);
515 if ((res == 0) || (res == SOCKET_ERROR)) {
517 }
else if (res == NET_PACKET_ERROR) {
519 JackServerGlobals::fInstance->GetEngine()->NotifyXRun(GetMicroSeconds(), 0);
543 fNetTimeMon->AddLast((((
float)(GetMicroSeconds() - begin_time)) / (
float) fPeriodUsecs) * 100.f);
550 JackNetMasterManager::JackNetMasterManager(jack_client_t* client,
const JSList* params) : fSocket()
552 jack_log(
"JackNetMasterManager::JackNetMasterManager");
554 fManagerClient = client;
555 fManagerName = jack_get_client_name(fManagerClient);
558 fAutoConnect =
false;
564 const char* default_udp_port = getenv(
"JACK_NETJACK_PORT");
565 fSocket.SetPort((default_udp_port) ? atoi(default_udp_port) : DEFAULT_PORT);
567 const char* default_multicast_ip = getenv(
"JACK_NETJACK_MULTICAST");
568 if (default_multicast_ip) {
569 strcpy(fMulticastIP, default_multicast_ip);
571 strcpy(fMulticastIP, DEFAULT_MULTICAST_IP);
574 for (node = params; node; node = jack_slist_next(node)) {
577 switch (param->character)
580 if (strlen(param->value.str) < 32) {
581 strcpy(fMulticastIP, param->value.str);
583 jack_error(
"Can't use multicast address %s, using default %s", param->value.ui, DEFAULT_MULTICAST_IP);
588 fSocket.SetPort(param->value.ui);
592 fAutoConnect = param->value.i;
601 if (jack_activate(fManagerClient) != 0) {
602 jack_error(
"Can't activate the NetManager client, transport disabled");
607 jack_error(
"Can't create the NetManager control thread");
611 JackNetMasterManager::~JackNetMasterManager()
613 jack_log(
"JackNetMasterManager::~JackNetMasterManager");
617 master_list_t::iterator it;
618 for (it = fMasterList.begin(); it != fMasterList.end(); it++) {
625 int JackNetMasterManager::CountIO(
int flags)
635 && (strcmp(
jack_port_type(port), JACK_DEFAULT_AUDIO_TYPE) == 0)) {
643 int JackNetMasterManager::SetSyncCallback(jack_transport_state_t state,
jack_position_t* pos,
void* arg)
645 return static_cast<JackNetMasterManager*
>(arg)->SyncCallback(state, pos);
648 int JackNetMasterManager::SyncCallback(jack_transport_state_t state,
jack_position_t* pos)
653 for (it = fMasterList.begin(); it != fMasterList.end(); it++) {
654 if (!(*it)->IsSlaveReadyToRoll()) {
658 jack_log(
"JackNetMasterManager::SyncCallback returns '%s'", (ret) ?
"true" :
"false");
662 void* JackNetMasterManager::NetManagerThread(
void* arg)
664 JackNetMasterManager* master_manager =
static_cast<JackNetMasterManager*
>(arg);
666 jack_info(
"Listening on '%s:%d'", master_manager->fMulticastIP, master_manager->fSocket.GetPort());
667 master_manager->Run();
671 void JackNetMasterManager::Run()
673 jack_log(
"JackNetMasterManager::Run");
678 session_params_t host_params;
680 JackNetMaster* net_master;
683 if (SocketAPIInit() < 0) {
684 jack_error(
"Can't init Socket API, exiting...");
689 if (fSocket.NewSocket() == SOCKET_ERROR) {
690 jack_error(
"Can't create NetManager input socket : %s", StrError(NET_ERROR_CODE));
695 if (fSocket.Bind() == SOCKET_ERROR) {
696 jack_error(
"Can't bind NetManager socket : %s", StrError(NET_ERROR_CODE));
702 if (fSocket.JoinMCastGroup(fMulticastIP) == SOCKET_ERROR) {
703 jack_error(
"Can't join multicast group : %s", StrError(NET_ERROR_CODE));
707 if (fSocket.SetLocalLoop() == SOCKET_ERROR) {
708 jack_error(
"Can't set local loop : %s", StrError(NET_ERROR_CODE));
712 if (fSocket.SetTimeOut(MANAGER_INIT_TIMEOUT) == SOCKET_ERROR) {
713 jack_error(
"Can't set timeout : %s", StrError(NET_ERROR_CODE));
719 session_params_t net_params;
720 rx_bytes = fSocket.CatchHost(&net_params,
sizeof(session_params_t), 0);
721 SessionParamsNToH(&net_params, &host_params);
722 if ((rx_bytes == SOCKET_ERROR) && (fSocket.GetError() != NET_NO_DATA)) {
723 jack_error(
"Error in receive : %s", StrError(NET_ERROR_CODE));
724 if (++attempt == 10) {
725 jack_error(
"Can't receive on the socket, exiting net manager");
730 if (rx_bytes ==
sizeof(session_params_t)) {
731 switch (GetPacketType (&host_params))
733 case SLAVE_AVAILABLE:
734 if ((net_master = InitMaster(host_params))) {
735 SessionParamsDisplay(&net_master->fParams);
742 if (KillMaster(&host_params)) {
754 JackNetMaster* JackNetMasterManager::InitMaster(session_params_t& params)
756 jack_log(
"JackNetMasterManager::InitMaster, Slave : %s", params.fName);
759 if (params.fProtocolVersion != MASTER_PROTOCOL) {
760 jack_error(
"Error : slave %s is running with a different protocol %d != %d", params.fName, params.fProtocolVersion, MASTER_PROTOCOL);
765 fSocket.GetName(params.fMasterNetName);
766 params.fID = ++fGlobalID;
770 if (params.fSendAudioChannels == -1) {
771 params.fSendAudioChannels = CountIO(JackPortIsPhysical | JackPortIsOutput);
772 jack_info(
"Takes physical %d inputs for client", params.fSendAudioChannels);
775 if (params.fReturnAudioChannels == -1) {
776 params.fReturnAudioChannels = CountIO(JackPortIsPhysical | JackPortIsInput);
777 jack_info(
"Takes physical %d outputs for client", params.fReturnAudioChannels);
781 JackNetMaster* master =
new JackNetMaster(fSocket, params, fMulticastIP);
782 if (master->Init(fAutoConnect)) {
783 fMasterList.push_back(master);
790 master_list_it_t JackNetMasterManager::FindMaster(uint32_t
id)
792 jack_log(
"JackNetMasterManager::FindMaster ID = %u",
id);
795 for (it = fMasterList.begin(); it != fMasterList.end(); it++) {
796 if ((*it)->fParams.fID ==
id) {
803 int JackNetMasterManager::KillMaster(session_params_t* params)
805 jack_log(
"JackNetMasterManager::KillMaster ID = %u", params->fID);
807 master_list_it_t master = FindMaster(params->fID);
808 if (master != fMasterList.end()) {
809 fMasterList.erase(master);
830 desc = jack_driver_descriptor_construct(
"netmanager", JackDriverNone,
"netjack multi-cast master component", &filler);
832 strcpy(value.str, DEFAULT_MULTICAST_IP);
833 jack_driver_descriptor_add_parameter(desc, &filler,
"multicast-ip",
'a', JackDriverParamString, &value, NULL,
"Multicast Address", NULL);
835 value.i = DEFAULT_PORT;
836 jack_driver_descriptor_add_parameter(desc, &filler,
"udp-net-port",
'p', JackDriverParamInt, &value, NULL,
"UDP port", NULL);
839 jack_driver_descriptor_add_parameter(desc, &filler,
"auto-connect",
'c', JackDriverParamBool, &value, NULL,
"Auto connect netmaster to system ports", NULL);
844 SERVER_EXPORT
int jack_internal_initialize(jack_client_t* jack_client,
const JSList* params)
846 if (master_manager) {
852 return (master_manager) ? 0 : 1;
856 SERVER_EXPORT
int jack_initialize(jack_client_t* jack_client,
const char* load_init)
859 bool parse_params =
true;
864 if (parser.GetArgc() > 0) {
865 parse_params = parser.ParseParams(desc, ¶ms);
869 res = jack_internal_initialize(jack_client, params);
870 parser.FreeParams(params);
875 SERVER_EXPORT
void jack_finish(
void* arg)
877 if (master_manager) {
878 jack_log (
"Unloading Master Manager");
879 delete master_manager;
880 master_manager = NULL;