| 
							- /*
 - Copyright(C) 2008-2011 Romain Moret at Grame
 - 
 - This program is free software; you can redistribute it and/or modify
 - it under the terms of the GNU General Public License as published by
 - the Free Software Foundation; either version 2 of the License, or
 - (at your option) any later version.
 - 
 - This program is distributed in the hope that it will be useful,
 - but WITHOUT ANY WARRANTY; without even the implied warranty of
 - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 - GNU General Public License for more details.
 - 
 - You should have received a copy of the GNU General Public License
 - along with this program; if not, write to the Free Software
 - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 - */
 - 
 - #include "JackNetManager.h"
 - #include "JackArgParser.h"
 - #include "JackServerGlobals.h"
 - #include "JackLockedEngine.h"
 - #include "thread.h"
 - 
 - using namespace std;
 - 
 - namespace Jack
 - {
 - //JackNetMaster******************************************************************************************************
 - 
 -     JackNetMaster::JackNetMaster(JackNetSocket& socket, session_params_t& params, const char* multicast_ip)
 -             : JackNetMasterInterface(params, socket, multicast_ip)
 -     {
 -         jack_log("JackNetMaster::JackNetMaster");
 - 
 -         //settings
 -         fName = const_cast<char*>(fParams.fName);
 -         fClient = NULL;
 -         fSendTransportData.fState = -1;
 -         fReturnTransportData.fState = -1;
 -         fLastTransportState = -1;
 -         int port_index;
 - 
 -         //jack audio ports
 -         fAudioCapturePorts = new jack_port_t* [fParams.fSendAudioChannels];
 -         for (port_index = 0; port_index < fParams.fSendAudioChannels; port_index++) {
 -             fAudioCapturePorts[port_index] = NULL;
 -         }
 - 
 -         fAudioPlaybackPorts = new jack_port_t* [fParams.fReturnAudioChannels];
 -         for (port_index = 0; port_index < fParams.fReturnAudioChannels; port_index++) {
 -             fAudioPlaybackPorts[port_index] = NULL;
 -         }
 - 
 -         //jack midi ports
 -         fMidiCapturePorts = new jack_port_t* [fParams.fSendMidiChannels];
 -         for (port_index = 0; port_index < fParams.fSendMidiChannels; port_index++) {
 -             fMidiCapturePorts[port_index] = NULL;
 -         }
 - 
 -         fMidiPlaybackPorts = new jack_port_t* [fParams.fReturnMidiChannels];
 -         for (port_index = 0; port_index < fParams.fReturnMidiChannels; port_index++) {
 -             fMidiPlaybackPorts[port_index] = NULL;
 -         }
 -     
 -         //monitor
 - #ifdef JACK_MONITOR
 -         fPeriodUsecs = (int)(1000000.f * ((float) fParams.fPeriodSize / (float) fParams.fSampleRate));
 -         string plot_name;
 -         plot_name = string(fParams.fName);
 -         plot_name += string("_master");
 -         plot_name += string((fParams.fSlaveSyncMode) ? "_sync" : "_async");
 -         plot_name += string("_latency");
 -         fNetTimeMon = new JackGnuPlotMonitor<float>(128, 4, plot_name);
 -         string net_time_mon_fields[] =
 -         {
 -             string("sync send"),
 -             string("end of send"),
 -             string("sync recv"),
 -             string("end of cycle")
 -         };
 -         string net_time_mon_options[] =
 -         {
 -             string("set xlabel \"audio cycles\""),
 -             string("set ylabel \"% of audio cycle\"")
 -         };
 -         fNetTimeMon->SetPlotFile(net_time_mon_options, 2, net_time_mon_fields, 4);
 - #endif
 -     }
 - 
 -     JackNetMaster::~JackNetMaster()
 -     {
 -         jack_log("JackNetMaster::~JackNetMaster ID = %u", fParams.fID);
 - 
 -         if (fClient) {
 -             jack_deactivate(fClient);
 -             FreePorts();
 -             jack_client_close(fClient);
 -         }
 -         delete[] fAudioCapturePorts;
 -         delete[] fAudioPlaybackPorts;
 -         delete[] fMidiCapturePorts;
 -         delete[] fMidiPlaybackPorts;
 - #ifdef JACK_MONITOR
 -         fNetTimeMon->Save();
 -         delete fNetTimeMon;
 - #endif
 -     }
 - //init--------------------------------------------------------------------------------
 -     bool JackNetMaster::Init(bool auto_connect)
 -     {
 -         //network init
 -         if (!JackNetMasterInterface::Init()) {
 -             jack_error("JackNetMasterInterface::Init() error...");
 -             return false;
 -         }
 - 
 -         //set global parameters
 -         if (!SetParams()) {
 -             jack_error("SetParams error...");
 -             return false;
 -         }
 - 
 -         //jack client and process
 -         jack_status_t status;
 -         if ((fClient = jack_client_open(fName, JackNullOption, &status, NULL)) == NULL) {
 -             jack_error("Can't open a new JACK client");
 -             return false;
 -         }
 -         
 -         if (jack_set_process_callback(fClient, SetProcess, this) < 0) {
 -             goto fail;
 -         }
 - 
 -         if (jack_set_buffer_size_callback(fClient, SetBufferSize, this) < 0) {
 -             goto fail;
 -         }
 -         
 -         if (jack_set_sample_rate_callback(fClient, SetSampleRate, this) < 0) {
 -             goto fail;
 -         }
 -         
 -         if (jack_set_latency_callback(fClient, LatencyCallback, this) < 0) {
 -             goto fail;
 -         }
 -         
 -         /*
 -         if (jack_set_port_connect_callback(fClient, SetConnectCallback, this) < 0) {
 -             goto fail;
 -         }
 -         */
 -      
 -         if (AllocPorts() != 0) {
 -             jack_error("Can't allocate JACK ports");
 -             goto fail;
 -         }
 - 
 -         //process can now run
 -         fRunning = true;
 - 
 -         //finally activate jack client
 -         if (jack_activate(fClient) != 0) {
 -             jack_error("Can't activate JACK client");
 -             goto fail;
 -         }
 - 
 -         if (auto_connect) {
 -             ConnectPorts();
 -         }
 -         jack_info("New NetMaster started");
 -         return true;
 - 
 -     fail:
 -         FreePorts();
 -         jack_client_close(fClient);
 -         fClient = NULL;
 -         return false;
 -     }
 - 
 - //jack ports--------------------------------------------------------------------------
 -     int JackNetMaster::AllocPorts()
 -     {
 -         int i;
 -         char name[32];
 -         jack_log("JackNetMaster::AllocPorts");
 - 
 -         //audio
 -         for (i = 0; i < fParams.fSendAudioChannels; i++) {
 -             snprintf(name, sizeof(name), "to_slave_%d", i+1);
 -             if ((fAudioCapturePorts[i] = jack_port_register(fClient, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0)) == NULL) {
 -                 return -1;
 -             }
 -         }
 - 
 -         for (i = 0; i < fParams.fReturnAudioChannels; i++) {
 -             snprintf(name, sizeof(name), "from_slave_%d", i+1);
 -             if ((fAudioPlaybackPorts[i] = jack_port_register(fClient, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput | JackPortIsTerminal, 0)) == NULL) {
 -                 return -1;
 -             }
 -         }
 - 
 -         //midi
 -         for (i = 0; i < fParams.fSendMidiChannels; i++) {
 -             snprintf(name, sizeof(name), "midi_to_slave_%d", i+1);
 -             if ((fMidiCapturePorts[i] = jack_port_register(fClient, name, JACK_DEFAULT_MIDI_TYPE, JackPortIsInput | JackPortIsTerminal, 0)) == NULL) {
 -                 return -1;
 -             }
 -         }
 - 
 -         for (i = 0; i < fParams.fReturnMidiChannels; i++) {
 -             snprintf(name, sizeof(name), "midi_from_slave_%d", i+1);
 -             if ((fMidiPlaybackPorts[i] = jack_port_register(fClient, name, JACK_DEFAULT_MIDI_TYPE,  JackPortIsOutput | JackPortIsTerminal, 0)) == NULL) {
 -                 return -1;
 -             }
 -         }
 -         return 0;
 -     }
 - 
 -     void JackNetMaster::ConnectPorts()
 -     {
 -         const char** ports = jack_get_ports(fClient, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortIsPhysical | JackPortIsOutput);
 -         if (ports != NULL) {
 -             for (int i = 0; i < fParams.fSendAudioChannels && ports[i]; i++) {
 -                 jack_connect(fClient, ports[i], jack_port_name(fAudioCapturePorts[i]));
 -             }
 -             jack_free(ports);
 -         }
 - 
 -         ports = jack_get_ports(fClient, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortIsPhysical | JackPortIsInput);
 -         if (ports != NULL) {
 -             for (int i = 0; i < fParams.fReturnAudioChannels && ports[i]; i++) {
 -                 jack_connect(fClient, jack_port_name(fAudioPlaybackPorts[i]), ports[i]);
 -             }
 -             jack_free(ports);
 -         }
 -     }
 - 
 -     void JackNetMaster::FreePorts()
 -     {
 -         jack_log("JackNetMaster::FreePorts ID = %u", fParams.fID);
 - 
 -         int port_index;
 -         for (port_index = 0; port_index < fParams.fSendAudioChannels; port_index++) {
 -             if (fAudioCapturePorts[port_index]) {
 -                 jack_port_unregister(fClient, fAudioCapturePorts[port_index]);
 -             }
 -         }
 -         for (port_index = 0; port_index < fParams.fReturnAudioChannels; port_index++) {
 -             if (fAudioPlaybackPorts[port_index]) {
 -                 jack_port_unregister(fClient, fAudioPlaybackPorts[port_index]);
 -             }
 -         }
 -         for (port_index = 0; port_index < fParams.fSendMidiChannels; port_index++) {
 -             if (fMidiCapturePorts[port_index]) {
 -                 jack_port_unregister(fClient, fMidiCapturePorts[port_index]);
 -             }
 -         }
 -         for (port_index = 0; port_index < fParams.fReturnMidiChannels; port_index++) {
 -             if (fMidiPlaybackPorts[port_index]) {
 -                 jack_port_unregister(fClient, fMidiPlaybackPorts[port_index]);
 -             }
 -         }
 -     }
 - 
 - //transport---------------------------------------------------------------------------
 -     void JackNetMaster::EncodeTransportData()
 -     {
 -         //is there a new timebase master ?
 -         //TODO : check if any timebase callback has been called (and if it's conditional or not) and set correct value...
 -         fSendTransportData.fTimebaseMaster = NO_CHANGE;
 - 
 -         //update state and position
 -         fSendTransportData.fState = static_cast<uint>(jack_transport_query(fClient, &fSendTransportData.fPosition));
 - 
 -         //is it a new state ?
 -         fSendTransportData.fNewState = ((fSendTransportData.fState != fLastTransportState) && (fSendTransportData.fState != fReturnTransportData.fState));
 -         if (fSendTransportData.fNewState) {
 -             jack_info("Sending '%s' to '%s' frame = %ld", GetTransportState(fSendTransportData.fState), fParams.fName, fSendTransportData.fPosition.frame);
 -         }
 -         fLastTransportState = fSendTransportData.fState;
 -    }
 - 
 -     void JackNetMaster::DecodeTransportData()
 -     {
 -         //is there timebase master change ?
 -         if (fReturnTransportData.fTimebaseMaster != NO_CHANGE) {
 - 
 -             int timebase = 0;
 -             switch (fReturnTransportData.fTimebaseMaster)
 -             {
 -                 case RELEASE_TIMEBASEMASTER :
 -                     timebase = jack_release_timebase(fClient);
 -                     if (timebase < 0) {
 -                         jack_error("Can't release timebase master");
 -                     } else {
 -                         jack_info("'%s' isn't the timebase master anymore", fParams.fName);
 -                     }
 -                     break;
 - 
 -                 case TIMEBASEMASTER :
 -                     timebase = jack_set_timebase_callback(fClient, 0, SetTimebaseCallback, this);
 -                     if (timebase < 0) {
 -                         jack_error("Can't set a new timebase master");
 -                     } else {
 -                         jack_info("'%s' is the new timebase master", fParams.fName);
 -                     }
 -                     break;
 - 
 -                 case CONDITIONAL_TIMEBASEMASTER :
 -                     timebase = jack_set_timebase_callback(fClient, 1, SetTimebaseCallback, this);
 -                     if (timebase != EBUSY) {
 -                         if (timebase < 0)
 -                             jack_error("Can't set a new timebase master");
 -                         else
 -                             jack_info("'%s' is the new timebase master", fParams.fName);
 -                     }
 -                     break;
 -             }
 -         }
 - 
 -         //is the slave in a new transport state and is this state different from master's ?
 -         if (fReturnTransportData.fNewState && (fReturnTransportData.fState != jack_transport_query(fClient, NULL))) {
 - 
 -             switch (fReturnTransportData.fState)
 -             {
 -                 case JackTransportStopped :
 -                     jack_transport_stop(fClient);
 -                     jack_info("'%s' stops transport", fParams.fName);
 -                     break;
 - 
 -                 case JackTransportStarting :
 -                     if (jack_transport_reposition(fClient, &fReturnTransportData.fPosition) == EINVAL)
 -                         jack_error("Can't set new position");
 -                     jack_transport_start(fClient);
 -                     jack_info("'%s' starts transport frame = %d", fParams.fName, fReturnTransportData.fPosition.frame);
 -                     break;
 - 
 -                 case JackTransportNetStarting :
 -                     jack_info("'%s' is ready to roll...", fParams.fName);
 -                     break;
 - 
 -                 case JackTransportRolling :
 -                     jack_info("'%s' is rolling", fParams.fName);
 -                     break;
 -             }
 -         }
 -     }
 - 
 -     void JackNetMaster::SetTimebaseCallback(jack_transport_state_t state, jack_nframes_t nframes, jack_position_t* pos, int new_pos, void* arg)
 -     {
 -         static_cast<JackNetMaster*>(arg)->TimebaseCallback(pos);
 -     }
 - 
 -     void JackNetMaster::TimebaseCallback(jack_position_t* pos)
 -     {
 -         pos->bar = fReturnTransportData.fPosition.bar;
 -         pos->beat = fReturnTransportData.fPosition.beat;
 -         pos->tick = fReturnTransportData.fPosition.tick;
 -         pos->bar_start_tick = fReturnTransportData.fPosition.bar_start_tick;
 -         pos->beats_per_bar = fReturnTransportData.fPosition.beats_per_bar;
 -         pos->beat_type = fReturnTransportData.fPosition.beat_type;
 -         pos->ticks_per_beat = fReturnTransportData.fPosition.ticks_per_beat;
 -         pos->beats_per_minute = fReturnTransportData.fPosition.beats_per_minute;
 -     }
 - 
 - //sync--------------------------------------------------------------------------------
 - 
 -     bool JackNetMaster::IsSlaveReadyToRoll()
 -     {
 -         return (fReturnTransportData.fState == JackTransportNetStarting);
 -     }
 - 
 -     int JackNetMaster::SetBufferSize(jack_nframes_t nframes, void* arg)
 -     {
 -         JackNetMaster* obj = static_cast<JackNetMaster*>(arg);
 -         if (nframes != obj->fParams.fPeriodSize) {
 -             jack_error("Cannot currently handle buffer size change, so JackNetMaster proxy will be removed...");
 -             obj->Exit();
 -         }
 -         return 0;
 -     }
 -     
 -     int JackNetMaster::SetSampleRate(jack_nframes_t nframes, void* arg)
 -     {
 -         JackNetMaster* obj = static_cast<JackNetMaster*>(arg);
 -         if (nframes != obj->fParams.fSampleRate) {
 -             jack_error("Cannot currently handle sample rate change, so JackNetMaster proxy will be removed...");
 -             obj->Exit();
 -         }
 -         return 0;
 -     }
 -     
 -     void JackNetMaster::LatencyCallback(jack_latency_callback_mode_t mode, void* arg)
 -     {
 -         JackNetMaster* obj = static_cast<JackNetMaster*>(arg);
 -         jack_nframes_t port_latency = jack_get_buffer_size(obj->fClient);
 -         jack_latency_range_t range;
 -         
 -         //audio
 -         for (int i = 0; i < obj->fParams.fSendAudioChannels; i++) {
 -             //port latency
 -             range.min = range.max = float(obj->fParams.fNetworkLatency * port_latency) / 2.f;
 -             jack_port_set_latency_range(obj->fAudioCapturePorts[i], JackPlaybackLatency, &range);
 -         }
 -         
 -         //audio
 -         for (int i = 0; i < obj->fParams.fReturnAudioChannels; i++) {
 -             //port latency
 -             range.min = range.max = float(obj->fParams.fNetworkLatency * port_latency) / 2.f + ((obj->fParams.fSlaveSyncMode) ? 0 : port_latency);
 -             jack_port_set_latency_range(obj->fAudioPlaybackPorts[i], JackCaptureLatency, &range);
 -         }
 -         
 -         //midi
 -         for (int i = 0; i < obj->fParams.fSendMidiChannels; i++) {
 -             //port latency
 -             range.min = range.max = float(obj->fParams.fNetworkLatency * port_latency) / 2.f;
 -             jack_port_set_latency_range(obj->fMidiCapturePorts[i], JackPlaybackLatency, &range);
 -         }
 -     
 -         //midi
 -         for (int i = 0; i < obj->fParams.fReturnMidiChannels; i++) {
 -             //port latency
 -             range.min = range.max = obj->fParams.fNetworkLatency * port_latency + ((obj->fParams.fSlaveSyncMode) ? 0 : port_latency);
 -             jack_port_set_latency_range(obj->fMidiPlaybackPorts[i], JackCaptureLatency, &range);
 -         }
 -     }
 - 
 - //process-----------------------------------------------------------------------------
 -     int JackNetMaster::SetProcess(jack_nframes_t nframes, void* arg)
 -     {
 -         try {
 -             return static_cast<JackNetMaster*>(arg)->Process();
 -         } catch (JackNetException& e) {
 -             return 0;
 -         }
 -     }
 -     
 -     void JackNetMaster::SetConnectCallback(jack_port_id_t a, jack_port_id_t b, int connect, void* arg)
 -     {
 -         static_cast<JackNetMaster*>(arg)->ConnectCallback(a, b, connect);
 -     }
 -     
 -     void JackNetMaster::ConnectCallback(jack_port_id_t a, jack_port_id_t b, int connect)
 -     {
 -         jack_info("JackNetMaster::ConnectCallback a = %d b = %d connect = %d", a, b, connect);
 -         if (connect) {
 -             jack_connect(fClient, jack_port_name(jack_port_by_id(fClient, a)), "system:playback_1");
 -         }
 -     }
 - 
 -     int JackNetMaster::Process()
 -     {
 -         if (!fRunning) {
 -             return 0;
 -         }
 - 
 - #ifdef JACK_MONITOR
 -         jack_time_t begin_time = GetMicroSeconds();
 -         fNetTimeMon->New();
 - #endif
 - 
 -         //buffers
 -         for (int midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
 -             fNetMidiCaptureBuffer->SetBuffer(midi_port_index,
 -                                             static_cast<JackMidiBuffer*>(jack_port_get_buffer(fMidiCapturePorts[midi_port_index],
 -                                             fParams.fPeriodSize)));
 -         }
 -         for (int audio_port_index = 0; audio_port_index < fParams.fSendAudioChannels; audio_port_index++) {
 - 
 -         #ifdef OPTIMIZED_PROTOCOL
 -             if (fNetAudioCaptureBuffer->GetConnected(audio_port_index)) {
 -                 // Port is connected on other side...
 -                 fNetAudioCaptureBuffer->SetBuffer(audio_port_index,
 -                                                 ((jack_port_connected(fAudioCapturePorts[audio_port_index]) > 0)
 -                                                 ? static_cast<sample_t*>(jack_port_get_buffer(fAudioCapturePorts[audio_port_index], fParams.fPeriodSize))
 -                                                 : NULL));
 -             } else {
 -                 fNetAudioCaptureBuffer->SetBuffer(audio_port_index, NULL);
 -             }
 -         #else
 -             fNetAudioCaptureBuffer->SetBuffer(audio_port_index,
 -                                             static_cast<sample_t*>(jack_port_get_buffer(fAudioCapturePorts[audio_port_index],
 -                                             fParams.fPeriodSize)));
 -         #endif
 -             // TODO
 -         }
 - 
 -         for (int midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
 -             fNetMidiPlaybackBuffer->SetBuffer(midi_port_index,
 -                                                 static_cast<JackMidiBuffer*>(jack_port_get_buffer(fMidiPlaybackPorts[midi_port_index],
 -                                                 fParams.fPeriodSize)));
 -         }
 -         for (int audio_port_index = 0; audio_port_index < fParams.fReturnAudioChannels; audio_port_index++) {
 - 
 -         #ifdef OPTIMIZED_PROTOCOL
 -             sample_t* out = (jack_port_connected(fAudioPlaybackPorts[audio_port_index]) > 0)
 -                 ? static_cast<sample_t*>(jack_port_get_buffer(fAudioPlaybackPorts[audio_port_index], fParams.fPeriodSize))
 -                 : NULL;
 -             if (out) {
 -                 memset(out, 0, sizeof(float) * fParams.fPeriodSize);
 -             }
 -             fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, out);
 -         #else
 -             sample_t* out = static_cast<sample_t*>(jack_port_get_buffer(fAudioPlaybackPorts[audio_port_index], fParams.fPeriodSize));
 -             if (out) {
 -                 memset(out, 0, sizeof(float) * fParams.fPeriodSize);
 -             }
 -             fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, out)));
 -         #endif
 -         }
 - 
 -         // encode the first packet
 -         EncodeSyncPacket();
 - 
 -         if (SyncSend() == SOCKET_ERROR) {
 -             return SOCKET_ERROR;
 -         }
 - 
 - #ifdef JACK_MONITOR
 -         fNetTimeMon->Add((((float)(GetMicroSeconds() - begin_time)) / (float) fPeriodUsecs) * 100.f);
 - #endif
 - 
 -         // send data
 -         if (DataSend() == SOCKET_ERROR) {
 -             return SOCKET_ERROR;
 -         }
 - 
 - #ifdef JACK_MONITOR
 -         fNetTimeMon->Add((((float)(GetMicroSeconds() - begin_time)) / (float) fPeriodUsecs) * 100.f);
 - #endif
 - 
 -         // receive sync
 -         int res = SyncRecv();
 -         switch (res) {
 -         
 -             case NET_SYNCHING:
 -             case SOCKET_ERROR:
 -                 return res;
 -                 
 -             case SYNC_PACKET_ERROR:
 -                  // Since sync packet is incorrect, don't decode it and continue with data
 -                  break;
 -                 
 -             default:
 -                 // Decode sync
 -                 int unused_frames;
 -                 DecodeSyncPacket(unused_frames);
 -                 break;
 -         }
 - 
 - #ifdef JACK_MONITOR
 -         fNetTimeMon->Add((((float)(GetMicroSeconds() - begin_time)) / (float) fPeriodUsecs) * 100.f);
 - #endif
 -       
 -         // receive data
 -         res = DataRecv();
 -         switch (res) {
 -         
 -             case 0:
 -             case SOCKET_ERROR:
 -                 return res;
 -                 
 -             case DATA_PACKET_ERROR:
 -                 // Well not a real XRun...
 -                 JackServerGlobals::fInstance->GetEngine()->NotifyClientXRun(ALL_CLIENTS);
 -                 break;
 -         }
 - 
 - #ifdef JACK_MONITOR
 -         fNetTimeMon->AddLast((((float)(GetMicroSeconds() - begin_time)) / (float) fPeriodUsecs) * 100.f);
 - #endif
 -         return 0;
 -     }
 -     
 -     void JackNetMaster::SaveConnections(connections_list_t& connections)
 -     {
 -         // Audio
 -         for (int i = 0; i < fParams.fSendAudioChannels; i++) {
 -             const char** connected_port = jack_port_get_all_connections(fClient, fAudioCapturePorts[i]);
 -             if (connected_port != NULL) {
 -                 for (int port = 0; connected_port[port]; port++) {
 -                     connections.push_back(make_pair(connected_port[port], jack_port_name(fAudioCapturePorts[i])));
 -                     jack_log("INPUT %s ==> %s", connected_port[port], jack_port_name(fAudioCapturePorts[i]));
 -                 }
 -                 jack_free(connected_port);
 -             }
 -         }
 -    
 -         for (int i = 0; i < fParams.fReturnAudioChannels; i++) {
 -             const char** connected_port = jack_port_get_all_connections(fClient, fAudioPlaybackPorts[i]);
 -             if (connected_port != NULL) {
 -                 for (int port = 0; connected_port[port]; port++) {
 -                     connections.push_back(make_pair(jack_port_name(fAudioPlaybackPorts[i]), connected_port[port]));
 -                     jack_log("OUTPUT %s ==> %s", jack_port_name(fAudioPlaybackPorts[i]), connected_port[port]);
 -                 }
 -                 jack_free(connected_port);
 -             }
 -         }
 -         
 -         // MIDI
 -         for (int i = 0; i < fParams.fSendMidiChannels; i++) {
 -             const char** connected_port = jack_port_get_all_connections(fClient, fMidiCapturePorts[i]);
 -             if (connected_port != NULL) {
 -                 for (int port = 0; connected_port[port]; port++) {
 -                     connections.push_back(make_pair(connected_port[port], jack_port_name(fMidiCapturePorts[i])));
 -                     jack_log("INPUT %s ==> %s", connected_port[port], jack_port_name(fMidiCapturePorts[i]));
 -                 }
 -                 jack_free(connected_port);
 -             }
 -         }
 -    
 -         for (int i = 0; i < fParams.fReturnMidiChannels; i++) {
 -             const char** connected_port = jack_port_get_all_connections(fClient, fMidiPlaybackPorts[i]);
 -             if (connected_port != NULL) {
 -                 for (int port = 0; connected_port[port]; port++) {
 -                     connections.push_back(make_pair(jack_port_name(fMidiPlaybackPorts[i]), connected_port[port]));
 -                     jack_log("OUTPUT %s ==> %s", jack_port_name(fMidiPlaybackPorts[i]), connected_port[port]);
 -                 }
 -                 jack_free(connected_port);
 -             }
 -         }
 -     }
 -     
 -     void JackNetMaster::LoadConnections(const connections_list_t& connections)
 -     {
 -         list<pair<string, string> >::const_iterator it;
 -         for (it = connections.begin(); it != connections.end(); it++) {
 -             pair<string, string> connection = *it;
 -             jack_connect(fClient, connection.first.c_str(), connection.second.c_str());
 -         }
 -     }
 - 
 - 
 - //JackNetMasterManager***********************************************************************************************
 - 
 -     JackNetMasterManager::JackNetMasterManager(jack_client_t* client, const JSList* params) : fSocket()
 -     {
 -         jack_log("JackNetMasterManager::JackNetMasterManager");
 - 
 -         fClient = client;
 -         fName = jack_get_client_name(fClient);
 -         fGlobalID = 0;
 -         fRunning = true;
 -         fAutoConnect = false;
 -         fAutoSave = false;
 - 
 -         const JSList* node;
 -         const jack_driver_param_t* param;
 -      
 -         jack_on_shutdown(fClient, SetShutDown, this);
 -     
 -         // Possibly use env variable
 -         const char* default_udp_port = getenv("JACK_NETJACK_PORT");
 -         fSocket.SetPort((default_udp_port) ? atoi(default_udp_port) : DEFAULT_PORT);
 - 
 -         const char* default_multicast_ip = getenv("JACK_NETJACK_MULTICAST");
 -         if (default_multicast_ip) {
 -             strcpy(fMulticastIP, default_multicast_ip);
 -         } else {
 -             strcpy(fMulticastIP, DEFAULT_MULTICAST_IP);
 -         }
 - 
 -         for (node = params; node; node = jack_slist_next(node)) {
 - 
 -             param = (const jack_driver_param_t*) node->data;
 -             switch (param->character) {
 -                 case 'a' :
 -                     if (strlen(param->value.str) < 32) {
 -                         strcpy(fMulticastIP, param->value.str);
 -                     } else {
 -                         jack_error("Can't use multicast address %s, using default %s", param->value.ui, DEFAULT_MULTICAST_IP);
 -                     }
 -                     break;
 - 
 -                 case 'p':
 -                     fSocket.SetPort(param->value.ui);
 -                     break;
 - 
 -                 case 'c':
 -                     fAutoConnect = true;
 -                     break;
 -                     
 -                 case 's':
 -                     fAutoSave = true;
 -                     break;
 -             }
 -         }
 - 
 -         //set sync callback
 -         jack_set_sync_callback(fClient, SetSyncCallback, this);
 - 
 -         //activate the client (for sync callback)
 -         if (jack_activate(fClient) != 0) {
 -             jack_error("Can't activate the NetManager client, transport disabled");
 -         }
 - 
 -         //launch the manager thread
 -         if (jack_client_create_thread(fClient, &fThread, 0, 0, NetManagerThread, this)) {
 -             jack_error("Can't create the NetManager control thread");
 -         }
 -     }
 - 
 -     JackNetMasterManager::~JackNetMasterManager()
 -     {
 -         jack_log("JackNetMasterManager::~JackNetMasterManager");
 -         ShutDown();
 -     }
 - 
 -     int JackNetMasterManager::CountIO(const char* type, int flags)
 -     {
 -         int count = 0;
 -         const char** ports = jack_get_ports(fClient, NULL, type, flags);
 -         if (ports != NULL) {
 -             while (ports[count]) { count++; }
 -             jack_free(ports);
 -         }
 -         return count;
 -     }
 -     
 -     void JackNetMasterManager::SetShutDown(void* arg)
 -     {
 -         static_cast<JackNetMasterManager*>(arg)->ShutDown();
 -     }
 -     
 -     void JackNetMasterManager::ShutDown()
 -     {
 -         jack_log("JackNetMasterManager::ShutDown");
 -         if (fRunning) {
 -             jack_client_kill_thread(fClient, fThread);
 -             fRunning = false;
 -         }
 -         master_list_t::iterator it;
 -         for (it = fMasterList.begin(); it != fMasterList.end(); it++) {
 -             delete (*it);
 -         }
 -         fMasterList.clear();
 -         fSocket.Close();
 -         SocketAPIEnd();
 -     }
 - 
 -     int JackNetMasterManager::SetSyncCallback(jack_transport_state_t state, jack_position_t* pos, void* arg)
 -     {
 -         return static_cast<JackNetMasterManager*>(arg)->SyncCallback(state, pos);
 -     }
 - 
 -     int JackNetMasterManager::SyncCallback(jack_transport_state_t state, jack_position_t* pos)
 -     {
 -         //check if each slave is ready to roll
 -         int res = 1;
 -         master_list_it_t it;
 -         for (it = fMasterList.begin(); it != fMasterList.end(); it++) {
 -             if (!(*it)->IsSlaveReadyToRoll()) {
 -                 res = 0;
 -             }
 -         }
 -         jack_log("JackNetMasterManager::SyncCallback returns '%s'", (res) ? "true" : "false");
 -         return res;
 -     }
 - 
 -     void* JackNetMasterManager::NetManagerThread(void* arg)
 -     {
 -         JackNetMasterManager* master_manager = static_cast<JackNetMasterManager*>(arg);
 -         jack_info("Starting Jack NetManager");
 -         jack_info("Listening on '%s:%d'", master_manager->fMulticastIP, master_manager->fSocket.GetPort());
 -         master_manager->Run();
 -         return NULL;
 -     }
 - 
 -     void JackNetMasterManager::Run()
 -     {
 -         jack_log("JackNetMasterManager::Run");
 -         //utility variables
 -         int attempt = 0;
 - 
 -         //data
 -         session_params_t host_params;
 -         int rx_bytes = 0;
 -         JackNetMaster* net_master;
 - 
 -         //init socket API (win32)
 -         if (SocketAPIInit() < 0) {
 -             jack_error("Can't init Socket API, exiting...");
 -             return;
 -         }
 - 
 -         //socket
 -         if (fSocket.NewSocket() == SOCKET_ERROR) {
 -             jack_error("Can't create NetManager input socket : %s", StrError(NET_ERROR_CODE));
 -             return;
 -         }
 - 
 -         //bind the socket to the local port
 -         if (fSocket.Bind() == SOCKET_ERROR) {
 -             jack_error("Can't bind NetManager socket : %s", StrError(NET_ERROR_CODE));
 -             fSocket.Close();
 -             return;
 -         }
 - 
 -         //join multicast group
 -         if (fSocket.JoinMCastGroup(fMulticastIP) == SOCKET_ERROR) {
 -             jack_error("Can't join multicast group : %s", StrError(NET_ERROR_CODE));
 -         }
 - 
 -         //local loop
 -         if (fSocket.SetLocalLoop() == SOCKET_ERROR) {
 -             jack_error("Can't set local loop : %s", StrError(NET_ERROR_CODE));
 -         }
 - 
 -         //set a timeout on the multicast receive (the thread can now be cancelled)
 -         if (fSocket.SetTimeOut(MANAGER_INIT_TIMEOUT) == SOCKET_ERROR) {
 -             jack_error("Can't set timeout : %s", StrError(NET_ERROR_CODE));
 -         }
 - 
 -         //main loop, wait for data, deal with it and wait again
 -         do
 -         {
 -             session_params_t net_params;
 -             rx_bytes = fSocket.CatchHost(&net_params, sizeof(session_params_t), 0);
 -             SessionParamsNToH(&net_params, &host_params);
 -             
 -             if ((rx_bytes == SOCKET_ERROR) && (fSocket.GetError() != NET_NO_DATA)) {
 -                 jack_error("Error in receive : %s", StrError(NET_ERROR_CODE));
 -                 if (++attempt == 10) {
 -                     jack_error("Can't receive on the socket, exiting net manager");
 -                     return;
 -                 }
 -             }
 - 
 -             if (rx_bytes == sizeof(session_params_t)) {
 -                 switch (GetPacketType(&host_params))
 -                 {
 -                     case SLAVE_AVAILABLE:
 -                         if ((net_master = InitMaster(host_params))) {
 -                             SessionParamsDisplay(&net_master->fParams);
 -                         } else {
 -                             jack_error("Can't init new NetMaster...");
 -                         }
 -                         jack_info("Waiting for a slave...");
 -                         break;
 -                     case KILL_MASTER:
 -                         if (KillMaster(&host_params)) {
 -                             jack_info("Waiting for a slave...");
 -                         }
 -                         break;
 -                     default:
 -                         break;
 -                 }
 -             }
 -         }
 -         while (fRunning);
 -     }
 - 
 -     JackNetMaster* JackNetMasterManager::InitMaster(session_params_t& params)
 -     {
 -         jack_log("JackNetMasterManager::InitMaster slave : %s", params.fName);
 - 
 -         //check MASTER <<==> SLAVE network protocol coherency
 -         if (params.fProtocolVersion != NETWORK_PROTOCOL) {
 -             jack_error("Error : slave '%s' is running with a different protocol %d != %d", params.fName, params.fProtocolVersion, NETWORK_PROTOCOL);
 -             return NULL;
 -         }
 - 
 -         //settings
 -         fSocket.GetName(params.fMasterNetName);
 -         params.fID = ++fGlobalID;
 -         params.fSampleRate = jack_get_sample_rate(fClient);
 -         params.fPeriodSize = jack_get_buffer_size(fClient);
 - 
 -         if (params.fSendAudioChannels == -1) {
 -             params.fSendAudioChannels = CountIO(JACK_DEFAULT_AUDIO_TYPE, JackPortIsPhysical | JackPortIsOutput);
 -             jack_info("Takes physical %d audio input(s) for slave", params.fSendAudioChannels);
 -         }
 - 
 -         if (params.fReturnAudioChannels == -1) {
 -             params.fReturnAudioChannels = CountIO(JACK_DEFAULT_AUDIO_TYPE, JackPortIsPhysical | JackPortIsInput);
 -             jack_info("Takes physical %d audio output(s) for slave", params.fReturnAudioChannels);
 -         }
 -         
 -         if (params.fSendMidiChannels == -1) {
 -             params.fSendMidiChannels = CountIO(JACK_DEFAULT_MIDI_TYPE, JackPortIsPhysical | JackPortIsOutput);
 -             jack_info("Takes physical %d MIDI input(s) for slave", params.fSendMidiChannels);
 -         }
 - 
 -         if (params.fReturnMidiChannels == -1) {
 -             params.fReturnMidiChannels = CountIO(JACK_DEFAULT_MIDI_TYPE, JackPortIsPhysical | JackPortIsInput);
 -             jack_info("Takes physical %d MIDI output(s) for slave", params.fReturnMidiChannels);
 -         }
 - 
 -         //create a new master and add it to the list
 -         JackNetMaster* master = new JackNetMaster(fSocket, params, fMulticastIP);
 -         if (master->Init(fAutoConnect)) {
 -             fMasterList.push_back(master);
 -             if (fAutoSave && fMasterConnectionList.find(params.fName) != fMasterConnectionList.end()) {
 -                 master->LoadConnections(fMasterConnectionList[params.fName]);
 -             }
 -             return master;
 -         } else {
 -             delete master;
 -             return NULL;
 -         }
 -     }
 - 
 -     master_list_it_t JackNetMasterManager::FindMaster(uint32_t id)
 -     {
 -         jack_log("JackNetMasterManager::FindMaster ID = %u", id);
 - 
 -         master_list_it_t it;
 -         for (it = fMasterList.begin(); it != fMasterList.end(); it++) {
 -             if ((*it)->fParams.fID == id) {
 -                 return it;
 -             }
 -         }
 -         return it;
 -     }
 - 
 -     int JackNetMasterManager::KillMaster(session_params_t* params)
 -     {
 -         jack_log("JackNetMasterManager::KillMaster ID = %u", params->fID);
 - 
 -         master_list_it_t master_it = FindMaster(params->fID);
 -         if (master_it != fMasterList.end()) {
 -             if (fAutoSave) {
 -                 fMasterConnectionList[params->fName].clear();
 -                 (*master_it)->SaveConnections(fMasterConnectionList[params->fName]);
 -             }
 -             fMasterList.erase(master_it);
 -             delete (*master_it);
 -             return 1;
 -         }
 -         return 0;
 -     }
 - }//namespace
 - 
 - static Jack::JackNetMasterManager* master_manager = NULL;
 - 
 - #ifdef __cplusplus
 - extern "C"
 - {
 - #endif
 - 
 -     SERVER_EXPORT jack_driver_desc_t* jack_get_descriptor()
 -     {
 -         jack_driver_desc_t * desc;
 -         jack_driver_desc_filler_t filler;
 -         jack_driver_param_value_t value;
 - 
 -         desc = jack_driver_descriptor_construct("netmanager", JackDriverNone, "netjack multi-cast master component", &filler);
 - 
 -         strcpy(value.str, DEFAULT_MULTICAST_IP);
 -         jack_driver_descriptor_add_parameter(desc, &filler, "multicast-ip", 'a', JackDriverParamString, &value, NULL, "Multicast address", NULL);
 - 
 -         value.i = DEFAULT_PORT;
 -         jack_driver_descriptor_add_parameter(desc, &filler, "udp-net-port", 'p', JackDriverParamInt, &value, NULL, "UDP port", NULL);
 - 
 -         value.i = false;
 -         jack_driver_descriptor_add_parameter(desc, &filler, "auto-connect", 'c', JackDriverParamBool, &value, NULL, "Auto connect netmaster to system ports", NULL);
 - 
 -         value.i = false;
 -         jack_driver_descriptor_add_parameter(desc, &filler, "auto-save", 's', JackDriverParamBool, &value, NULL, "Save/restore netmaster connection state when restarted", NULL);
 - 
 -         return desc;
 -     }
 - 
 -     SERVER_EXPORT int jack_internal_initialize(jack_client_t* jack_client, const JSList* params)
 -     {
 -         if (master_manager) {
 -             jack_error("Master Manager already loaded");
 -             return 1;
 -         } else {
 -             jack_log("Loading Master Manager");
 -             master_manager = new Jack::JackNetMasterManager(jack_client, params);
 -             return (master_manager) ? 0 : 1;
 -         }
 -     }
 - 
 -     SERVER_EXPORT int jack_initialize(jack_client_t* jack_client, const char* load_init)
 -     {
 -         JSList* params = NULL;
 -         bool parse_params = true;
 -         int res = 1;
 -         jack_driver_desc_t* desc = jack_get_descriptor();
 - 
 -         Jack::JackArgParser parser(load_init);
 -         if (parser.GetArgc() > 0) {
 -             parse_params = parser.ParseParams(desc, ¶ms);
 -         }
 - 
 -         if (parse_params) {
 -             res = jack_internal_initialize(jack_client, params);
 -             parser.FreeParams(params);
 -         }
 -         return res;
 -     }
 - 
 -     SERVER_EXPORT void jack_finish(void* arg)
 -     {
 -         if (master_manager) {
 -             jack_log("Unloading Master Manager");
 -             delete master_manager;
 -             master_manager = NULL;
 -         }
 -     }
 - 
 - #ifdef __cplusplus
 - }
 - #endif
 
 
  |