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 fName =
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);
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 ((fClient =
jack_client_open(fName, JackNullOption, &status, NULL)) == NULL) {
144 if (AllocPorts() != 0) {
172 int JackNetMaster::AllocPorts()
179 jack_log(
"JackNetMaster::AllocPorts");
182 for (i = 0; i < fParams.fSendAudioChannels; i++) {
183 snprintf(name,
sizeof(name),
"to_slave_%d", i+1);
184 if ((fAudioCapturePorts[i] =
jack_port_register(fClient, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0)) == NULL)
187 range.
min = range.
max = 0;
191 for (i = 0; i < fParams.fReturnAudioChannels; i++) {
192 snprintf(name,
sizeof(name),
"from_slave_%d", i+1);
193 if ((fAudioPlaybackPorts[i] =
jack_port_register(fClient, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput | JackPortIsTerminal, 0)) == NULL)
196 range.
min = range.
max = fParams.fNetworkLatency * port_latency + (fParams.fSlaveSyncMode) ? 0 : port_latency;
201 for (i = 0; i < fParams.fSendMidiChannels; i++) {
202 snprintf(name,
sizeof(name),
"midi_to_slave_%d", i+1);
203 if ((fMidiCapturePorts[i] =
jack_port_register(fClient, name, JACK_DEFAULT_MIDI_TYPE, JackPortIsInput | JackPortIsTerminal, 0)) == NULL)
206 range.
min = range.
max = 0;
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)
215 range.
min = range.
max = fParams.fNetworkLatency * port_latency + (fParams.fSlaveSyncMode) ? 0 : port_latency;
221 void JackNetMaster::ConnectPorts()
225 ports =
jack_get_ports(fClient, NULL, NULL, JackPortIsPhysical | JackPortIsOutput);
227 for (
int i = 0; i < fParams.fSendAudioChannels && ports[i]; i++) {
233 ports =
jack_get_ports(fClient, NULL, NULL, JackPortIsPhysical | JackPortIsInput);
235 for (
int i = 0; i < fParams.fReturnAudioChannels && ports[i]; i++) {
242 void JackNetMaster::FreePorts()
244 jack_log(
"JackNetMaster::FreePorts ID = %u", fParams.fID);
247 for (port_index = 0; port_index < fParams.fSendAudioChannels; port_index++) {
248 if (fAudioCapturePorts[port_index]) {
252 for (port_index = 0; port_index < fParams.fReturnAudioChannels; port_index++) {
253 if (fAudioPlaybackPorts[port_index]) {
257 for (port_index = 0; port_index < fParams.fSendMidiChannels; port_index++) {
258 if (fMidiCapturePorts[port_index]) {
262 for (port_index = 0; port_index < fParams.fReturnMidiChannels; port_index++) {
263 if (fMidiPlaybackPorts[port_index]) {
270 void JackNetMaster::EncodeTransportData()
274 fSendTransportData.fTimebaseMaster = NO_CHANGE;
277 fSendTransportData.fState =
static_cast<uint
>(
jack_transport_query(fClient, &fSendTransportData.fPosition));
280 fSendTransportData.fNewState = ((fSendTransportData.fState != fLastTransportState) && (fSendTransportData.fState != fReturnTransportData.fState));
281 if (fSendTransportData.fNewState) {
282 jack_info(
"Sending '%s' to '%s' frame = %ld", GetTransportState(fSendTransportData.fState), fParams.fName, fSendTransportData.fPosition.
frame);
284 fLastTransportState = fSendTransportData.fState;
287 void JackNetMaster::DecodeTransportData()
290 if (fReturnTransportData.fTimebaseMaster != NO_CHANGE) {
293 switch (fReturnTransportData.fTimebaseMaster)
295 case RELEASE_TIMEBASEMASTER :
300 jack_info(
"'%s' isn't the timebase master anymore", fParams.fName);
304 case TIMEBASEMASTER :
307 jack_error(
"Can't set a new timebase master");
309 jack_info(
"'%s' is the new timebase master", fParams.fName);
313 case CONDITIONAL_TIMEBASEMASTER :
315 if (timebase != EBUSY) {
317 jack_error(
"Can't set a new timebase master");
319 jack_info(
"'%s' is the new timebase master", fParams.fName);
326 if (fReturnTransportData.fNewState && (fReturnTransportData.fState !=
jack_transport_query(fClient, NULL))) {
328 switch (fReturnTransportData.fState)
330 case JackTransportStopped :
332 jack_info(
"'%s' stops transport", fParams.fName);
335 case JackTransportStarting :
339 jack_info(
"'%s' starts transport frame = %d", fParams.fName, fReturnTransportData.fPosition.
frame);
342 case JackTransportNetStarting :
343 jack_info(
"'%s' is ready to roll...", fParams.fName);
346 case JackTransportRolling :
347 jack_info(
"'%s' is rolling", fParams.fName);
353 void JackNetMaster::SetTimebaseCallback(jack_transport_state_t state, jack_nframes_t nframes,
jack_position_t* pos,
int new_pos,
void* arg)
355 static_cast<JackNetMaster*
>(arg)->TimebaseCallback(pos);
360 pos->
bar = fReturnTransportData.fPosition.
bar;
361 pos->
beat = fReturnTransportData.fPosition.
beat;
362 pos->
tick = fReturnTransportData.fPosition.
tick;
363 pos->bar_start_tick = fReturnTransportData.fPosition.bar_start_tick;
366 pos->ticks_per_beat = fReturnTransportData.fPosition.ticks_per_beat;
367 pos->beats_per_minute = fReturnTransportData.fPosition.beats_per_minute;
372 bool JackNetMaster::IsSlaveReadyToRoll()
374 return (fReturnTransportData.fState == JackTransportNetStarting);
377 int JackNetMaster::SetBufferSize(jack_nframes_t nframes,
void* arg)
379 JackNetMaster* obj =
static_cast<JackNetMaster*
>(arg);
380 if (nframes != obj->fParams.fPeriodSize) {
381 jack_error(
"Cannot handle buffer size change, so JackNetMaster proxy will be removed...");
388 int JackNetMaster::SetProcess(jack_nframes_t nframes,
void* arg)
391 return static_cast<JackNetMaster*
>(arg)->Process();
392 }
catch (JackNetException& e) {
397 void JackNetMaster::SetConnectCallback(jack_port_id_t a, jack_port_id_t b,
int connect,
void* arg)
399 static_cast<JackNetMaster*
>(arg)->ConnectCallback(a, b, connect);
402 void JackNetMaster::ConnectCallback(jack_port_id_t a, jack_port_id_t b,
int connect)
404 jack_info(
"JackNetMaster::ConnectCallback a = %d b = %d connect = %d", a, b, connect);
410 int JackNetMaster::Process()
417 jack_time_t begin_time = GetMicroSeconds();
422 for (
int midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
423 fNetMidiCaptureBuffer->SetBuffer(midi_port_index,
425 fParams.fPeriodSize)));
427 for (
int audio_port_index = 0; audio_port_index < fParams.fSendAudioChannels; audio_port_index++) {
429 #ifdef OPTIMIZED_PROTOCOL
430 if (fNetAudioCaptureBuffer->GetConnected(audio_port_index)) {
432 fNetAudioCaptureBuffer->SetBuffer(audio_port_index,
434 ? static_cast<sample_t*>(
jack_port_get_buffer(fAudioCapturePorts[audio_port_index], fParams.fPeriodSize))
437 fNetAudioCaptureBuffer->SetBuffer(audio_port_index, NULL);
440 fNetAudioCaptureBuffer->SetBuffer(audio_port_index,
442 fParams.fPeriodSize)));
447 for (
int midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
448 fNetMidiPlaybackBuffer->SetBuffer(midi_port_index,
450 fParams.fPeriodSize)));
452 for (
int audio_port_index = 0; audio_port_index < fParams.fReturnAudioChannels; audio_port_index++) {
454 #ifdef OPTIMIZED_PROTOCOL
456 ? static_cast<sample_t*>(
jack_port_get_buffer(fAudioPlaybackPorts[audio_port_index], fParams.fPeriodSize))
459 memset(out, 0,
sizeof(
float) * fParams.fPeriodSize);
461 fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, out);
463 sample_t* out =
static_cast<sample_t*
>(
jack_port_get_buffer(fAudioPlaybackPorts[audio_port_index], fParams.fPeriodSize));
465 memset(out, 0,
sizeof(
float) * fParams.fPeriodSize);
467 fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, out)));
476 if (SyncSend() == SOCKET_ERROR) {
481 fNetTimeMon->Add((((
float)(GetMicroSeconds() - begin_time)) / (
float) fPeriodUsecs) * 100.f);
485 if (DataSend() == SOCKET_ERROR) {
490 fNetTimeMon->Add((((
float)(GetMicroSeconds() - begin_time)) / (
float) fPeriodUsecs) * 100.f);
494 jack_info(
"Connection is not synched, skip cycle...");
498 int res = SyncRecv();
499 if ((res == 0) || (res == SOCKET_ERROR)) {
504 fNetTimeMon->Add((((
float)(GetMicroSeconds() - begin_time)) / (
float) fPeriodUsecs) * 100.f);
512 if ((res == 0) || (res == SOCKET_ERROR)) {
514 }
else if (res == NET_PACKET_ERROR) {
516 JackServerGlobals::fInstance->GetEngine()->NotifyXRun(GetMicroSeconds(), 0);
520 fNetTimeMon->AddLast((((
float)(GetMicroSeconds() - begin_time)) / (
float) fPeriodUsecs) * 100.f);
527 JackNetMasterManager::JackNetMasterManager(jack_client_t* client,
const JSList* params) : fSocket()
529 jack_log(
"JackNetMasterManager::JackNetMasterManager");
535 fAutoConnect =
false;
543 const char* default_udp_port = getenv(
"JACK_NETJACK_PORT");
544 fSocket.SetPort((default_udp_port) ? atoi(default_udp_port) : DEFAULT_PORT);
546 const char* default_multicast_ip = getenv(
"JACK_NETJACK_MULTICAST");
547 if (default_multicast_ip) {
548 strcpy(fMulticastIP, default_multicast_ip);
550 strcpy(fMulticastIP, DEFAULT_MULTICAST_IP);
553 for (node = params; node; node = jack_slist_next(node)) {
556 switch (param->character)
559 if (strlen(param->value.str) < 32) {
560 strcpy(fMulticastIP, param->value.str);
562 jack_error(
"Can't use multicast address %s, using default %s", param->value.ui, DEFAULT_MULTICAST_IP);
567 fSocket.SetPort(param->value.ui);
571 fAutoConnect = param->value.i;
581 jack_error(
"Can't activate the NetManager client, transport disabled");
586 jack_error(
"Can't create the NetManager control thread");
590 JackNetMasterManager::~JackNetMasterManager()
592 jack_log(
"JackNetMasterManager::~JackNetMasterManager");
596 int JackNetMasterManager::CountIO(
int flags)
606 && (strcmp(
jack_port_type(port), JACK_DEFAULT_AUDIO_TYPE) == 0)) {
614 void JackNetMasterManager::SetShutDown(
void* arg)
616 static_cast<JackNetMasterManager*
>(arg)->ShutDown();
619 void JackNetMasterManager::ShutDown()
621 jack_log(
"JackNetMasterManager::ShutDown");
626 master_list_t::iterator it;
627 for (it = fMasterList.begin(); it != fMasterList.end(); it++) {
635 int JackNetMasterManager::SetSyncCallback(jack_transport_state_t state,
jack_position_t* pos,
void* arg)
637 return static_cast<JackNetMasterManager*
>(arg)->SyncCallback(state, pos);
640 int JackNetMasterManager::SyncCallback(jack_transport_state_t state,
jack_position_t* pos)
645 for (it = fMasterList.begin(); it != fMasterList.end(); it++) {
646 if (!(*it)->IsSlaveReadyToRoll()) {
650 jack_log(
"JackNetMasterManager::SyncCallback returns '%s'", (ret) ?
"true" :
"false");
654 void* JackNetMasterManager::NetManagerThread(
void* arg)
656 JackNetMasterManager* master_manager =
static_cast<JackNetMasterManager*
>(arg);
658 jack_info(
"Listening on '%s:%d'", master_manager->fMulticastIP, master_manager->fSocket.GetPort());
659 master_manager->Run();
663 void JackNetMasterManager::Run()
665 jack_log(
"JackNetMasterManager::Run");
670 session_params_t host_params;
672 JackNetMaster* net_master;
675 if (SocketAPIInit() < 0) {
676 jack_error(
"Can't init Socket API, exiting...");
681 if (fSocket.NewSocket() == SOCKET_ERROR) {
682 jack_error(
"Can't create NetManager input socket : %s", StrError(NET_ERROR_CODE));
687 if (fSocket.Bind() == SOCKET_ERROR) {
688 jack_error(
"Can't bind NetManager socket : %s", StrError(NET_ERROR_CODE));
694 if (fSocket.JoinMCastGroup(fMulticastIP) == SOCKET_ERROR) {
695 jack_error(
"Can't join multicast group : %s", StrError(NET_ERROR_CODE));
699 if (fSocket.SetLocalLoop() == SOCKET_ERROR) {
700 jack_error(
"Can't set local loop : %s", StrError(NET_ERROR_CODE));
704 if (fSocket.SetTimeOut(MANAGER_INIT_TIMEOUT) == SOCKET_ERROR) {
705 jack_error(
"Can't set timeout : %s", StrError(NET_ERROR_CODE));
711 session_params_t net_params;
712 rx_bytes = fSocket.CatchHost(&net_params,
sizeof(session_params_t), 0);
713 SessionParamsNToH(&net_params, &host_params);
715 if ((rx_bytes == SOCKET_ERROR) && (fSocket.GetError() != NET_NO_DATA)) {
716 jack_error(
"Error in receive : %s", StrError(NET_ERROR_CODE));
717 if (++attempt == 10) {
718 jack_error(
"Can't receive on the socket, exiting net manager");
723 if (rx_bytes ==
sizeof(session_params_t)) {
724 switch (GetPacketType(&host_params))
726 case SLAVE_AVAILABLE:
727 if ((net_master = InitMaster(host_params))) {
728 SessionParamsDisplay(&net_master->fParams);
735 if (KillMaster(&host_params)) {
747 JackNetMaster* JackNetMasterManager::InitMaster(session_params_t& params)
749 jack_log(
"JackNetMasterManager::InitMaster, Slave : %s", params.fName);
752 if (params.fProtocolVersion != MASTER_PROTOCOL) {
753 jack_error(
"Error : slave %s is running with a different protocol %d != %d", params.fName, params.fProtocolVersion, MASTER_PROTOCOL);
758 fSocket.GetName(params.fMasterNetName);
759 params.fID = ++fGlobalID;
763 if (params.fSendAudioChannels == -1) {
764 params.fSendAudioChannels = CountIO(JackPortIsPhysical | JackPortIsOutput);
765 jack_info(
"Takes physical %d inputs for client", params.fSendAudioChannels);
768 if (params.fReturnAudioChannels == -1) {
769 params.fReturnAudioChannels = CountIO(JackPortIsPhysical | JackPortIsInput);
770 jack_info(
"Takes physical %d outputs for client", params.fReturnAudioChannels);
774 JackNetMaster* master =
new JackNetMaster(fSocket, params, fMulticastIP);
775 if (master->Init(fAutoConnect)) {
776 fMasterList.push_back(master);
783 master_list_it_t JackNetMasterManager::FindMaster(uint32_t
id)
785 jack_log(
"JackNetMasterManager::FindMaster ID = %u",
id);
788 for (it = fMasterList.begin(); it != fMasterList.end(); it++) {
789 if ((*it)->fParams.fID ==
id) {
796 int JackNetMasterManager::KillMaster(session_params_t* params)
798 jack_log(
"JackNetMasterManager::KillMaster ID = %u", params->fID);
800 master_list_it_t master = FindMaster(params->fID);
801 if (master != fMasterList.end()) {
802 fMasterList.erase(master);
823 desc = jack_driver_descriptor_construct(
"netmanager", JackDriverNone,
"netjack multi-cast master component", &filler);
825 strcpy(value.str, DEFAULT_MULTICAST_IP);
826 jack_driver_descriptor_add_parameter(desc, &filler,
"multicast-ip",
'a', JackDriverParamString, &value, NULL,
"Multicast address", NULL);
828 value.i = DEFAULT_PORT;
829 jack_driver_descriptor_add_parameter(desc, &filler,
"udp-net-port",
'p', JackDriverParamInt, &value, NULL,
"UDP port", NULL);
832 jack_driver_descriptor_add_parameter(desc, &filler,
"auto-connect",
'c', JackDriverParamBool, &value, NULL,
"Auto connect netmaster to system ports", NULL);
837 SERVER_EXPORT
int jack_internal_initialize(jack_client_t* jack_client,
const JSList* params)
839 if (master_manager) {
845 return (master_manager) ? 0 : 1;
849 SERVER_EXPORT
int jack_initialize(jack_client_t* jack_client,
const char* load_init)
852 bool parse_params =
true;
857 if (parser.GetArgc() > 0) {
858 parse_params = parser.ParseParams(desc, ¶ms);
862 res = jack_internal_initialize(jack_client, params);
863 parser.FreeParams(params);
868 SERVER_EXPORT
void jack_finish(
void* arg)
870 if (master_manager) {
871 jack_log(
"Unloading Master Manager");
872 delete master_manager;
873 master_manager = NULL;
LIB_EXPORT int jack_port_unregister(jack_client_t *, jack_port_t *)
LIB_EXPORT jack_port_t * jack_port_by_id(jack_client_t *client, jack_port_id_t port_id)
LIB_EXPORT jack_transport_state_t jack_transport_query(const jack_client_t *client, jack_position_t *pos)
LIB_EXPORT int jack_set_process_callback(jack_client_t *client, JackProcessCallback process_callback, void *arg)
LIB_EXPORT int jack_activate(jack_client_t *client)
LIB_EXPORT const char * jack_port_type(const jack_port_t *port)
SERVER_EXPORT void jack_error(const char *fmt,...)
LIB_EXPORT void jack_port_set_latency_range(jack_port_t *port, jack_latency_callback_mode_t mode, jack_latency_range_t *range)
LIB_EXPORT int jack_connect(jack_client_t *, const char *source_port, const char *destination_port)
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)
LIB_EXPORT int jack_release_timebase(jack_client_t *client)
SERVER_EXPORT void jack_info(const char *fmt,...)
LIB_EXPORT void jack_on_shutdown(jack_client_t *client, JackShutdownCallback shutdown_callback, void *arg)
LIB_EXPORT jack_client_t * jack_client_open(const char *client_name, jack_options_t options, jack_status_t *status,...)
LIB_EXPORT char * jack_get_client_name(jack_client_t *client)
LIB_EXPORT void jack_transport_start(jack_client_t *client)
LIB_EXPORT jack_nframes_t jack_get_buffer_size(jack_client_t *)
LIB_EXPORT void * jack_port_get_buffer(jack_port_t *, jack_nframes_t)
LIB_EXPORT void jack_transport_stop(jack_client_t *client)
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)
LIB_EXPORT int jack_transport_reposition(jack_client_t *client, const jack_position_t *pos)
LIB_EXPORT jack_port_t * jack_port_by_name(jack_client_t *, const char *port_name)
LIB_EXPORT jack_nframes_t jack_get_sample_rate(jack_client_t *)
LIB_EXPORT int jack_set_timebase_callback(jack_client_t *client, int conditional, JackTimebaseCallback timebase_callback, void *arg)
LIB_EXPORT int jack_set_buffer_size_callback(jack_client_t *client, JackBufferSizeCallback bufsize_callback, void *arg)
LIB_EXPORT int jack_set_sync_callback(jack_client_t *client, JackSyncCallback sync_callback, void *arg)
LIB_EXPORT int jack_port_connected(const jack_port_t *port)
LIB_EXPORT const char * jack_port_name(const jack_port_t *port)
LIB_EXPORT const char ** jack_get_ports(jack_client_t *, const char *port_name_pattern, const char *type_name_pattern, unsigned long flags)
LIB_EXPORT int jack_deactivate(jack_client_t *client)
SERVER_EXPORT void jack_log(const char *fmt,...)
LIB_EXPORT int jack_client_kill_thread(jack_client_t *client, jack_native_thread_t thread)
LIB_EXPORT int jack_client_close(jack_client_t *client)