Jack2  1.9.8
JackNetManager.cpp
00001 /*
00002 Copyright(C) 2008-2011 Romain Moret at Grame
00003 
00004 This program is free software; you can redistribute it and/or modify
00005 it under the terms of the GNU General Public License as published by
00006 the Free Software Foundation; either version 2 of the License, or
00007 (at your option) any later version.
00008 
00009 This program is distributed in the hope that it will be useful,
00010 but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 GNU General Public License for more details.
00013 
00014 You should have received a copy of the GNU General Public License
00015 along with this program; if not, write to the Free Software
00016 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00017 */
00018 
00019 #include "JackNetManager.h"
00020 #include "JackArgParser.h"
00021 #include "JackServerGlobals.h"
00022 #include "JackLockedEngine.h"
00023 
00024 using namespace std;
00025 
00026 namespace Jack
00027 {
00028 //JackNetMaster******************************************************************************************************
00029 
00030     JackNetMaster::JackNetMaster(JackNetSocket& socket, session_params_t& params, const char* multicast_ip)
00031             : JackNetMasterInterface(params, socket, multicast_ip)
00032     {
00033         jack_log("JackNetMaster::JackNetMaster");
00034 
00035         //settings
00036         fClientName = const_cast<char*>(fParams.fName);
00037         fJackClient = NULL;
00038         fSendTransportData.fState = -1;
00039         fReturnTransportData.fState = -1;
00040         fLastTransportState = -1;
00041         int port_index;
00042 
00043         //jack audio ports
00044         fAudioCapturePorts = new jack_port_t* [fParams.fSendAudioChannels];
00045         for (port_index = 0; port_index < fParams.fSendAudioChannels; port_index++) {
00046             fAudioCapturePorts[port_index] = NULL;
00047         }
00048 
00049         fAudioPlaybackPorts = new jack_port_t* [fParams.fReturnAudioChannels];
00050         for (port_index = 0; port_index < fParams.fReturnAudioChannels; port_index++) {
00051             fAudioPlaybackPorts[port_index] = NULL;
00052         }
00053 
00054         //jack midi ports
00055         fMidiCapturePorts = new jack_port_t* [fParams.fSendMidiChannels];
00056         for (port_index = 0; port_index < fParams.fSendMidiChannels; port_index++) {
00057             fMidiCapturePorts[port_index] = NULL;
00058         }
00059 
00060         fMidiPlaybackPorts = new jack_port_t* [fParams.fReturnMidiChannels];
00061         for (port_index = 0; port_index < fParams.fReturnMidiChannels; port_index++) {
00062             fMidiPlaybackPorts[port_index] = NULL;
00063         }
00064 
00065         //monitor
00066 #ifdef JACK_MONITOR
00067         fPeriodUsecs = (int)(1000000.f * ((float) fParams.fPeriodSize / (float) fParams.fSampleRate));
00068         string plot_name;
00069         plot_name = string(fParams.fName);
00070         plot_name += string("_master");
00071         plot_name += string((fParams.fSlaveSyncMode) ? "_sync" : "_async");
00072         plot_name += string("_latency");
00073         fNetTimeMon = new JackGnuPlotMonitor<float>(128, 4, plot_name);
00074         string net_time_mon_fields[] =
00075         {
00076             string("sync send"),
00077             string("end of send"),
00078             string("sync recv"),
00079             string("end of cycle")
00080         };
00081         string net_time_mon_options[] =
00082         {
00083             string("set xlabel \"audio cycles\""),
00084             string("set ylabel \"% of audio cycle\"")
00085         };
00086         fNetTimeMon->SetPlotFile(net_time_mon_options, 2, net_time_mon_fields, 4);
00087 #endif
00088     }
00089 
00090     JackNetMaster::~JackNetMaster()
00091     {
00092         jack_log("JackNetMaster::~JackNetMaster ID = %u", fParams.fID);
00093 
00094         if (fJackClient) {
00095             jack_deactivate(fJackClient);
00096             FreePorts();
00097             jack_client_close(fJackClient);
00098         }
00099         delete[] fAudioCapturePorts;
00100         delete[] fAudioPlaybackPorts;
00101         delete[] fMidiCapturePorts;
00102         delete[] fMidiPlaybackPorts;
00103 #ifdef JACK_MONITOR
00104         fNetTimeMon->Save();
00105         delete fNetTimeMon;
00106 #endif
00107     }
00108 //init--------------------------------------------------------------------------------
00109     bool JackNetMaster::Init(bool auto_connect)
00110     {
00111         //network init
00112         if (!JackNetMasterInterface::Init()) {
00113             jack_error("JackNetMasterInterface::Init() error...");
00114             return false;
00115         }
00116 
00117         //set global parameters
00118         if (!SetParams()) {
00119             jack_error("SetParams error...");
00120             return false;
00121         }
00122 
00123         //jack client and process
00124         jack_status_t status;
00125         if ((fJackClient = jack_client_open(fClientName, JackNullOption, &status, NULL)) == NULL) {
00126             jack_error("Can't open a new JACK client");
00127             return false;
00128         }
00129 
00130         if (jack_set_process_callback(fJackClient, SetProcess, this) < 0) {
00131             goto fail;
00132         }
00133 
00134         if (jack_set_buffer_size_callback(fJackClient, SetBufferSize, this) < 0) {
00135             goto fail;
00136         }
00137 
00138         if (AllocPorts() != 0) {
00139             jack_error("Can't allocate JACK ports");
00140             goto fail;
00141         }
00142 
00143         //process can now run
00144         fRunning = true;
00145 
00146         //finally activate jack client
00147         if (jack_activate(fJackClient) != 0) {
00148             jack_error("Can't activate JACK client");
00149             goto fail;
00150         }
00151 
00152         if (auto_connect) {
00153             ConnectPorts();
00154         }
00155         jack_info("New NetMaster started");
00156         return true;
00157 
00158     fail:
00159         FreePorts();
00160         jack_client_close(fJackClient);
00161         fJackClient = NULL;
00162         return false;
00163     }
00164 
00165 //jack ports--------------------------------------------------------------------------
00166     int JackNetMaster::AllocPorts()
00167     {
00168         int i;
00169         char name[24];
00170         jack_nframes_t port_latency = jack_get_buffer_size(fJackClient);
00171         jack_latency_range_t range;
00172 
00173         jack_log("JackNetMaster::AllocPorts");
00174 
00175         //audio
00176         for (i = 0; i < fParams.fSendAudioChannels; i++) {
00177             snprintf(name, sizeof(name), "to_slave_%d", i+1);
00178             if ((fAudioCapturePorts[i] = jack_port_register(fJackClient, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0)) == NULL)
00179                 return -1;
00180             //port latency
00181             range.min = range.max = 0;
00182             jack_port_set_latency_range(fAudioCapturePorts[i], JackCaptureLatency, &range);
00183         }
00184 
00185         for (i = 0; i < fParams.fReturnAudioChannels; i++) {
00186             snprintf(name, sizeof(name), "from_slave_%d", i+1);
00187             if ((fAudioPlaybackPorts[i] = jack_port_register(fJackClient, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput | JackPortIsTerminal, 0)) == NULL)
00188                 return -1;
00189             //port latency
00190             range.min = range.max = fParams.fNetworkLatency * port_latency + (fParams.fSlaveSyncMode) ? 0 : port_latency;
00191             jack_port_set_latency_range(fAudioPlaybackPorts[i], JackPlaybackLatency, &range);
00192         }
00193 
00194         //midi
00195         for (i = 0; i < fParams.fSendMidiChannels; i++) {
00196             snprintf(name, sizeof(name), "midi_to_slave_%d", i+1);
00197             if ((fMidiCapturePorts[i] = jack_port_register(fJackClient, name, JACK_DEFAULT_MIDI_TYPE, JackPortIsInput | JackPortIsTerminal, 0)) == NULL)
00198                 return -1;
00199             //port latency
00200             range.min = range.max = 0;
00201             jack_port_set_latency_range(fMidiCapturePorts[i], JackCaptureLatency, &range);
00202         }
00203 
00204         for (i = 0; i < fParams.fReturnMidiChannels; i++) {
00205             snprintf(name, sizeof(name), "midi_from_slave_%d", i+1);
00206             if ((fMidiPlaybackPorts[i] = jack_port_register(fJackClient, name, JACK_DEFAULT_MIDI_TYPE,  JackPortIsOutput | JackPortIsTerminal, 0)) == NULL)
00207                 return -1;
00208             //port latency
00209             range.min = range.max = fParams.fNetworkLatency * port_latency + (fParams.fSlaveSyncMode) ? 0 : port_latency;
00210             jack_port_set_latency_range(fMidiPlaybackPorts[i], JackPlaybackLatency, &range);
00211         }
00212         return 0;
00213     }
00214 
00215     void JackNetMaster::ConnectPorts()
00216     {
00217         const char **ports;
00218 
00219         ports = jack_get_ports(fJackClient, NULL, NULL, JackPortIsPhysical | JackPortIsOutput);
00220         if (ports != NULL) {
00221             for (int i = 0; i < fParams.fSendAudioChannels && ports[i]; i++) {
00222                 jack_connect(fJackClient, ports[i], jack_port_name(fAudioCapturePorts[i]));
00223             }
00224             free(ports);
00225         }
00226 
00227         ports = jack_get_ports(fJackClient, NULL, NULL, JackPortIsPhysical | JackPortIsInput);
00228         if (ports != NULL) {
00229             for (int i = 0; i < fParams.fReturnAudioChannels && ports[i]; i++) {
00230                 jack_connect(fJackClient, jack_port_name(fAudioPlaybackPorts[i]), ports[i]);
00231             }
00232             free(ports);
00233         }
00234     }
00235 
00236     void JackNetMaster::FreePorts()
00237     {
00238         jack_log("JackNetMaster::FreePorts ID = %u", fParams.fID);
00239 
00240         int port_index;
00241         for (port_index = 0; port_index < fParams.fSendAudioChannels; port_index++) {
00242             if (fAudioCapturePorts[port_index]) {
00243                 jack_port_unregister(fJackClient, fAudioCapturePorts[port_index]);
00244             }
00245         }
00246         for (port_index = 0; port_index < fParams.fReturnAudioChannels; port_index++) {
00247             if (fAudioPlaybackPorts[port_index]) {
00248                 jack_port_unregister(fJackClient, fAudioPlaybackPorts[port_index]);
00249             }
00250         }
00251         for (port_index = 0; port_index < fParams.fSendMidiChannels; port_index++) {
00252             if (fMidiCapturePorts[port_index]) {
00253                 jack_port_unregister(fJackClient, fMidiCapturePorts[port_index]);
00254             }
00255         }
00256         for (port_index = 0; port_index < fParams.fReturnMidiChannels; port_index++) {
00257             if (fMidiPlaybackPorts[port_index]) {
00258                 jack_port_unregister(fJackClient, fMidiPlaybackPorts[port_index]);
00259             }
00260         }
00261     }
00262 
00263 //transport---------------------------------------------------------------------------
00264     void JackNetMaster::EncodeTransportData()
00265     {
00266         //is there a new timebase master ?
00267         //TODO : check if any timebase callback has been called (and if it's conditional or not) and set correct value...
00268         fSendTransportData.fTimebaseMaster = NO_CHANGE;
00269 
00270         //update state and position
00271         fSendTransportData.fState = static_cast<uint>(jack_transport_query(fJackClient, &fSendTransportData.fPosition));
00272 
00273         //is it a new state ?
00274         fSendTransportData.fNewState = ((fSendTransportData.fState != fLastTransportState) && (fSendTransportData.fState != fReturnTransportData.fState));
00275         if (fSendTransportData.fNewState) {
00276             jack_info("Sending '%s' to '%s' frame = %ld", GetTransportState(fSendTransportData.fState), fParams.fName, fSendTransportData.fPosition.frame);
00277         }
00278         fLastTransportState = fSendTransportData.fState;
00279    }
00280 
00281     void JackNetMaster::DecodeTransportData()
00282     {
00283         //is there timebase master change ?
00284         if (fReturnTransportData.fTimebaseMaster != NO_CHANGE) {
00285 
00286             int timebase = 0;
00287             switch (fReturnTransportData.fTimebaseMaster)
00288             {
00289                 case RELEASE_TIMEBASEMASTER :
00290                     timebase = jack_release_timebase(fJackClient);
00291                     if (timebase < 0) {
00292                         jack_error("Can't release timebase master");
00293                     } else {
00294                         jack_info("'%s' isn't the timebase master anymore", fParams.fName);
00295                     }
00296                     break;
00297 
00298                 case TIMEBASEMASTER :
00299                     timebase = jack_set_timebase_callback(fJackClient, 0, SetTimebaseCallback, this);
00300                     if (timebase < 0) {
00301                         jack_error("Can't set a new timebase master");
00302                     } else {
00303                         jack_info("'%s' is the new timebase master", fParams.fName);
00304                     }
00305                     break;
00306 
00307                 case CONDITIONAL_TIMEBASEMASTER :
00308                     timebase = jack_set_timebase_callback(fJackClient, 1, SetTimebaseCallback, this);
00309                     if (timebase != EBUSY) {
00310                         if (timebase < 0)
00311                             jack_error("Can't set a new timebase master");
00312                         else
00313                             jack_info("'%s' is the new timebase master", fParams.fName);
00314                     }
00315                     break;
00316             }
00317         }
00318 
00319         //is the slave in a new transport state and is this state different from master's ?
00320         if (fReturnTransportData.fNewState && (fReturnTransportData.fState != jack_transport_query(fJackClient, NULL))) {
00321 
00322             switch (fReturnTransportData.fState)
00323             {
00324                 case JackTransportStopped :
00325                     jack_transport_stop(fJackClient);
00326                     jack_info("'%s' stops transport", fParams.fName);
00327                     break;
00328 
00329                 case JackTransportStarting :
00330                     if (jack_transport_reposition(fJackClient, &fReturnTransportData.fPosition) == EINVAL)
00331                         jack_error("Can't set new position");
00332                     jack_transport_start(fJackClient);
00333                     jack_info("'%s' starts transport frame = %d", fParams.fName, fReturnTransportData.fPosition.frame);
00334                     break;
00335 
00336                 case JackTransportNetStarting :
00337                     jack_info("'%s' is ready to roll...", fParams.fName);
00338                     break;
00339 
00340                 case JackTransportRolling :
00341                     jack_info("'%s' is rolling", fParams.fName);
00342                     break;
00343             }
00344         }
00345     }
00346 
00347     void JackNetMaster::SetTimebaseCallback(jack_transport_state_t state, jack_nframes_t nframes, jack_position_t* pos, int new_pos, void* arg)
00348     {
00349         static_cast<JackNetMaster*>(arg)->TimebaseCallback(pos);
00350     }
00351 
00352     void JackNetMaster::TimebaseCallback(jack_position_t* pos)
00353     {
00354         pos->bar = fReturnTransportData.fPosition.bar;
00355         pos->beat = fReturnTransportData.fPosition.beat;
00356         pos->tick = fReturnTransportData.fPosition.tick;
00357         pos->bar_start_tick = fReturnTransportData.fPosition.bar_start_tick;
00358         pos->beats_per_bar = fReturnTransportData.fPosition.beats_per_bar;
00359         pos->beat_type = fReturnTransportData.fPosition.beat_type;
00360         pos->ticks_per_beat = fReturnTransportData.fPosition.ticks_per_beat;
00361         pos->beats_per_minute = fReturnTransportData.fPosition.beats_per_minute;
00362     }
00363 
00364 //sync--------------------------------------------------------------------------------
00365 
00366     bool JackNetMaster::IsSlaveReadyToRoll()
00367     {
00368         return (fReturnTransportData.fState == JackTransportNetStarting);
00369     }
00370 
00371     int JackNetMaster::SetBufferSize(jack_nframes_t nframes, void* arg)
00372     {
00373         JackNetMaster* obj = static_cast<JackNetMaster*>(arg);
00374         if (nframes != obj->fParams.fPeriodSize) {
00375             jack_error("Cannot handle buffer size change, so JackNetMaster proxy will be removed...");
00376             obj->Exit();
00377         }
00378         return 0;
00379     }
00380 
00381 //process-----------------------------------------------------------------------------
00382     int JackNetMaster::SetProcess(jack_nframes_t nframes, void* arg)
00383     {
00384         try {
00385             return static_cast<JackNetMaster*>(arg)->Process();
00386         } catch (JackNetException& e) {
00387             return 0;
00388         }
00389     }
00390 
00391     int JackNetMaster::Process()
00392     {
00393         int res;
00394 
00395         if (!fRunning) {
00396             return 0;
00397         }
00398 
00399 #ifdef JACK_MONITOR
00400         jack_time_t begin_time = GetMicroSeconds();
00401         fNetTimeMon->New();
00402 #endif
00403 
00404         //buffers
00405         for (int midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
00406             fNetMidiCaptureBuffer->SetBuffer(midi_port_index,
00407                                             static_cast<JackMidiBuffer*>(jack_port_get_buffer(fMidiCapturePorts[midi_port_index],
00408                                             fParams.fPeriodSize)));
00409         }
00410         for (int audio_port_index = 0; audio_port_index < fParams.fSendAudioChannels; audio_port_index++) {
00411 
00412         #ifdef OPTIMIZED_PROTOCOL
00413             if (fNetAudioCaptureBuffer->GetConnected(audio_port_index)) {
00414                 // Port is connected on other side...
00415                 fNetAudioCaptureBuffer->SetBuffer(audio_port_index,
00416                                                 ((jack_port_connected(fAudioCapturePorts[audio_port_index]) > 0)
00417                                                 ? static_cast<sample_t*>(jack_port_get_buffer(fAudioCapturePorts[audio_port_index], fParams.fPeriodSize))
00418                                                 : NULL));
00419             } else {
00420                 fNetAudioCaptureBuffer->SetBuffer(audio_port_index, NULL);
00421             }
00422         #else
00423             fNetAudioCaptureBuffer->SetBuffer(audio_port_index,
00424                                             static_cast<sample_t*>(jack_port_get_buffer(fAudioCapturePorts[audio_port_index],
00425                                             fParams.fPeriodSize)));
00426         #endif
00427             // TODO
00428         }
00429 
00430         for (int midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
00431             fNetMidiPlaybackBuffer->SetBuffer(midi_port_index,
00432                                                 static_cast<JackMidiBuffer*>(jack_port_get_buffer(fMidiPlaybackPorts[midi_port_index],
00433                                                 fParams.fPeriodSize)));
00434         }
00435         for (int audio_port_index = 0; audio_port_index < fParams.fReturnAudioChannels; audio_port_index++) {
00436 
00437         #ifdef OPTIMIZED_PROTOCOL
00438             sample_t* out = (jack_port_connected(fAudioPlaybackPorts[audio_port_index]) > 0)
00439                 ? static_cast<sample_t*>(jack_port_get_buffer(fAudioPlaybackPorts[audio_port_index], fParams.fPeriodSize))
00440                 : NULL;
00441             if (out) {
00442                 memset(out, 0, sizeof(float) * fParams.fPeriodSize);
00443             }
00444             fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, out);
00445         #else
00446             sample_t* out = static_cast<sample_t*>(jack_port_get_buffer(fAudioPlaybackPorts[audio_port_index], fParams.fPeriodSize));
00447             if (out) {
00448                 memset(out, 0, sizeof(float) * fParams.fPeriodSize);
00449             }
00450             fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, out)));
00451         #endif
00452         }
00453 
00454         if (IsSynched()) {  // only send if connection is "synched"
00455 
00456             //encode the first packet
00457             EncodeSyncPacket();
00458 
00459             if (SyncSend() == SOCKET_ERROR) {
00460                 return SOCKET_ERROR;
00461             }
00462 
00463     #ifdef JACK_MONITOR
00464             fNetTimeMon->Add((((float)(GetMicroSeconds() - begin_time)) / (float) fPeriodUsecs) * 100.f);
00465     #endif
00466 
00467             //send data
00468             if (DataSend() == SOCKET_ERROR) {
00469                 return SOCKET_ERROR;
00470             }
00471 
00472     #ifdef JACK_MONITOR
00473             fNetTimeMon->Add((((float)(GetMicroSeconds() - begin_time)) / (float) fPeriodUsecs) * 100.f);
00474     #endif
00475 
00476         } else {
00477             jack_error("Connection is not synched, skip cycle...");
00478         }
00479 
00480         //receive sync
00481         res = SyncRecv();
00482         if ((res == 0) || (res == SOCKET_ERROR)) {
00483             return res;
00484         }
00485 
00486         /*
00487         switch (SyncRecv()) {
00488 
00489             case 0:
00490                 jack_error("Connection is not yet synched, skip cycle...");
00491                 return 0;
00492 
00493             case SOCKET_ERROR:
00494                 jack_error("Connection is lost, quit master...");
00495                 //ask to the manager to properly remove the master
00496                 Exit();
00497                 //UGLY temporary way to be sure the thread does not call code possibly causing a deadlock in JackEngine.
00498                 ThreadExit();
00499                 break;
00500 
00501             default:
00502                 break;
00503         }
00504         */
00505 
00506 #ifdef JACK_MONITOR
00507         fNetTimeMon->Add((((float)(GetMicroSeconds() - begin_time)) / (float) fPeriodUsecs) * 100.f);
00508 #endif
00509 
00510         //decode sync
00511         DecodeSyncPacket();
00512 
00513         //receive data
00514         res = DataRecv();
00515         if ((res == 0) || (res == SOCKET_ERROR)) {
00516             return res;
00517         } else if (res == NET_PACKET_ERROR) {
00518             // Well not a real XRun...
00519             JackServerGlobals::fInstance->GetEngine()->NotifyXRun(GetMicroSeconds(), 0);
00520         }
00521 
00522         /*
00523         switch (DataRecv()) {
00524 
00525             case 0:
00526                 jack_error("Connection is not yet synched, skip cycle...");
00527                 return 0;
00528 
00529             case SOCKET_ERROR:
00530                 jack_error("Connection is lost, quit master...");
00531                 //ask to the manager to properly remove the master
00532                 Exit();
00533                 //UGLY temporary way to be sure the thread does not call code possibly causing a deadlock in JackEngine.
00534                 ThreadExit();
00535                 break;
00536 
00537             default:
00538                 break;
00539         }
00540         */
00541 
00542 #ifdef JACK_MONITOR
00543         fNetTimeMon->AddLast((((float)(GetMicroSeconds() - begin_time)) / (float) fPeriodUsecs) * 100.f);
00544 #endif
00545         return 0;
00546     }
00547 
00548 //JackNetMasterManager***********************************************************************************************
00549 
00550     JackNetMasterManager::JackNetMasterManager(jack_client_t* client, const JSList* params) : fSocket()
00551     {
00552         jack_log("JackNetMasterManager::JackNetMasterManager");
00553 
00554         fManagerClient = client;
00555         fManagerName = jack_get_client_name(fManagerClient);
00556         fGlobalID = 0;
00557         fRunning = true;
00558         fAutoConnect = false;
00559 
00560         const JSList* node;
00561         const jack_driver_param_t* param;
00562 
00563         // Possibly use env variable
00564         const char* default_udp_port = getenv("JACK_NETJACK_PORT");
00565         fSocket.SetPort((default_udp_port) ? atoi(default_udp_port) : DEFAULT_PORT);
00566 
00567         const char* default_multicast_ip = getenv("JACK_NETJACK_MULTICAST");
00568         if (default_multicast_ip) {
00569             strcpy(fMulticastIP, default_multicast_ip);
00570         } else {
00571             strcpy(fMulticastIP, DEFAULT_MULTICAST_IP);
00572         }
00573 
00574         for (node = params; node; node = jack_slist_next(node)) {
00575 
00576             param = (const jack_driver_param_t*) node->data;
00577             switch (param->character)
00578             {
00579                 case 'a' :
00580                     if (strlen(param->value.str) < 32) {
00581                         strcpy(fMulticastIP, param->value.str);
00582                     } else {
00583                         jack_error("Can't use multicast address %s, using default %s", param->value.ui, DEFAULT_MULTICAST_IP);
00584                     }
00585                     break;
00586 
00587                 case 'p':
00588                     fSocket.SetPort(param->value.ui);
00589                     break;
00590 
00591                 case 'c':
00592                     fAutoConnect = param->value.i;
00593                     break;
00594             }
00595         }
00596 
00597         //set sync callback
00598         jack_set_sync_callback(fManagerClient, SetSyncCallback, this);
00599 
00600         //activate the client (for sync callback)
00601         if (jack_activate(fManagerClient) != 0) {
00602             jack_error("Can't activate the NetManager client, transport disabled");
00603         }
00604 
00605         //launch the manager thread
00606         if (jack_client_create_thread(fManagerClient, &fManagerThread, 0, 0, NetManagerThread, this)) {
00607             jack_error("Can't create the NetManager control thread");
00608         }
00609     }
00610 
00611     JackNetMasterManager::~JackNetMasterManager()
00612     {
00613         jack_log("JackNetMasterManager::~JackNetMasterManager");
00614         jack_info("Exiting NetManager...");
00615         fRunning = false;
00616         jack_client_kill_thread(fManagerClient, fManagerThread);
00617         master_list_t::iterator it;
00618         for (it = fMasterList.begin(); it != fMasterList.end(); it++) {
00619             delete(*it);
00620         }
00621         fSocket.Close();
00622         SocketAPIEnd();
00623     }
00624 
00625     int JackNetMasterManager::CountIO(int flags)
00626     {
00627         const char **ports;
00628         int count = 0;
00629         jack_port_t* port;
00630 
00631         ports = jack_get_ports(fManagerClient, NULL, NULL, flags);
00632         if (ports != NULL) {
00633             while (ports[count]
00634                     && (port = jack_port_by_name(fManagerClient, ports[count]))
00635                     && (strcmp(jack_port_type(port), JACK_DEFAULT_AUDIO_TYPE) == 0)) {
00636                 count++;
00637             }
00638             free(ports);
00639         }
00640         return count;
00641     }
00642 
00643     int JackNetMasterManager::SetSyncCallback(jack_transport_state_t state, jack_position_t* pos, void* arg)
00644     {
00645         return static_cast<JackNetMasterManager*>(arg)->SyncCallback(state, pos);
00646     }
00647 
00648     int JackNetMasterManager::SyncCallback(jack_transport_state_t state, jack_position_t* pos)
00649     {
00650         //check if each slave is ready to roll
00651         int ret = 1;
00652         master_list_it_t it;
00653         for (it = fMasterList.begin(); it != fMasterList.end(); it++) {
00654             if (!(*it)->IsSlaveReadyToRoll()) {
00655                 ret = 0;
00656             }
00657         }
00658         jack_log("JackNetMasterManager::SyncCallback returns '%s'", (ret) ? "true" : "false");
00659         return ret;
00660     }
00661 
00662     void* JackNetMasterManager::NetManagerThread(void* arg)
00663     {
00664         JackNetMasterManager* master_manager = static_cast<JackNetMasterManager*>(arg);
00665         jack_info("Starting Jack NetManager");
00666         jack_info("Listening on '%s:%d'", master_manager->fMulticastIP, master_manager->fSocket.GetPort());
00667         master_manager->Run();
00668         return NULL;
00669     }
00670 
00671     void JackNetMasterManager::Run()
00672     {
00673         jack_log("JackNetMasterManager::Run");
00674         //utility variables
00675         int attempt = 0;
00676 
00677         //data
00678         session_params_t host_params;
00679         int rx_bytes = 0;
00680         JackNetMaster* net_master;
00681 
00682         //init socket API (win32)
00683         if (SocketAPIInit() < 0) {
00684             jack_error("Can't init Socket API, exiting...");
00685             return;
00686         }
00687 
00688         //socket
00689         if (fSocket.NewSocket() == SOCKET_ERROR) {
00690             jack_error("Can't create NetManager input socket : %s", StrError(NET_ERROR_CODE));
00691             return;
00692         }
00693 
00694         //bind the socket to the local port
00695         if (fSocket.Bind() == SOCKET_ERROR) {
00696             jack_error("Can't bind NetManager socket : %s", StrError(NET_ERROR_CODE));
00697             fSocket.Close();
00698             return;
00699         }
00700 
00701         //join multicast group
00702         if (fSocket.JoinMCastGroup(fMulticastIP) == SOCKET_ERROR) {
00703             jack_error("Can't join multicast group : %s", StrError(NET_ERROR_CODE));
00704         }
00705 
00706         //local loop
00707         if (fSocket.SetLocalLoop() == SOCKET_ERROR) {
00708             jack_error("Can't set local loop : %s", StrError(NET_ERROR_CODE));
00709         }
00710 
00711         //set a timeout on the multicast receive (the thread can now be cancelled)
00712         if (fSocket.SetTimeOut(MANAGER_INIT_TIMEOUT) == SOCKET_ERROR) {
00713             jack_error("Can't set timeout : %s", StrError(NET_ERROR_CODE));
00714         }
00715 
00716         //main loop, wait for data, deal with it and wait again
00717         do
00718         {
00719             session_params_t net_params;
00720             rx_bytes = fSocket.CatchHost(&net_params, sizeof(session_params_t), 0);
00721             SessionParamsNToH(&net_params, &host_params);
00722             if ((rx_bytes == SOCKET_ERROR) && (fSocket.GetError() != NET_NO_DATA)) {
00723                 jack_error("Error in receive : %s", StrError(NET_ERROR_CODE));
00724                 if (++attempt == 10) {
00725                     jack_error("Can't receive on the socket, exiting net manager");
00726                     return;
00727                 }
00728             }
00729 
00730             if (rx_bytes == sizeof(session_params_t)) {
00731                 switch (GetPacketType (&host_params))
00732                 {
00733                     case SLAVE_AVAILABLE:
00734                         if ((net_master = InitMaster(host_params))) {
00735                             SessionParamsDisplay(&net_master->fParams);
00736                         } else {
00737                             jack_error("Can't init new NetMaster...");
00738                         }
00739                         jack_info("Waiting for a slave...");
00740                         break;
00741                     case KILL_MASTER:
00742                         if (KillMaster(&host_params)) {
00743                             jack_info("Waiting for a slave...");
00744                         }
00745                         break;
00746                     default:
00747                         break;
00748                 }
00749             }
00750         }
00751         while (fRunning);
00752     }
00753 
00754     JackNetMaster* JackNetMasterManager::InitMaster(session_params_t& params)
00755     {
00756         jack_log("JackNetMasterManager::InitMaster, Slave : %s", params.fName);
00757 
00758         //check MASTER <<==> SLAVE network protocol coherency
00759         if (params.fProtocolVersion != MASTER_PROTOCOL) {
00760             jack_error("Error : slave %s is running with a different protocol %d != %d", params.fName,  params.fProtocolVersion, MASTER_PROTOCOL);
00761             return NULL;
00762         }
00763 
00764         //settings
00765         fSocket.GetName(params.fMasterNetName);
00766         params.fID = ++fGlobalID;
00767         params.fSampleRate = jack_get_sample_rate(fManagerClient);
00768         params.fPeriodSize = jack_get_buffer_size(fManagerClient);
00769 
00770         if (params.fSendAudioChannels == -1) {
00771             params.fSendAudioChannels = CountIO(JackPortIsPhysical | JackPortIsOutput);
00772             jack_info("Takes physical %d inputs for client", params.fSendAudioChannels);
00773         }
00774 
00775         if (params.fReturnAudioChannels == -1) {
00776             params.fReturnAudioChannels = CountIO(JackPortIsPhysical | JackPortIsInput);
00777             jack_info("Takes physical %d outputs for client", params.fReturnAudioChannels);
00778         }
00779 
00780         //create a new master and add it to the list
00781         JackNetMaster* master = new JackNetMaster(fSocket, params, fMulticastIP);
00782         if (master->Init(fAutoConnect)) {
00783             fMasterList.push_back(master);
00784             return master;
00785         }
00786         delete master;
00787         return NULL;
00788     }
00789 
00790     master_list_it_t JackNetMasterManager::FindMaster(uint32_t id)
00791     {
00792         jack_log("JackNetMasterManager::FindMaster ID = %u", id);
00793 
00794         master_list_it_t it;
00795         for (it = fMasterList.begin(); it != fMasterList.end(); it++) {
00796             if ((*it)->fParams.fID == id) {
00797                 return it;
00798             }
00799         }
00800         return it;
00801     }
00802 
00803     int JackNetMasterManager::KillMaster(session_params_t* params)
00804     {
00805         jack_log("JackNetMasterManager::KillMaster ID = %u", params->fID);
00806 
00807         master_list_it_t master = FindMaster(params->fID);
00808         if (master != fMasterList.end()) {
00809             fMasterList.erase(master);
00810             delete *master;
00811             return 1;
00812         }
00813         return 0;
00814     }
00815 }//namespace
00816 
00817 static Jack::JackNetMasterManager* master_manager = NULL;
00818 
00819 #ifdef __cplusplus
00820 extern "C"
00821 {
00822 #endif
00823 
00824     SERVER_EXPORT jack_driver_desc_t* jack_get_descriptor()
00825     {
00826         jack_driver_desc_t * desc;
00827         jack_driver_desc_filler_t filler;
00828         jack_driver_param_value_t value;
00829 
00830         desc = jack_driver_descriptor_construct("netmanager", JackDriverNone, "netjack multi-cast master component", &filler);
00831 
00832         strcpy(value.str, DEFAULT_MULTICAST_IP);
00833         jack_driver_descriptor_add_parameter(desc, &filler, "multicast-ip", 'a', JackDriverParamString, &value, NULL, "Multicast Address", NULL);
00834 
00835         value.i = DEFAULT_PORT;
00836         jack_driver_descriptor_add_parameter(desc, &filler, "udp-net-port", 'p', JackDriverParamInt, &value, NULL, "UDP port", NULL);
00837 
00838         value.i = false;
00839         jack_driver_descriptor_add_parameter(desc, &filler, "auto-connect", 'c', JackDriverParamBool, &value, NULL, "Auto connect netmaster to system ports", NULL);
00840 
00841         return desc;
00842     }
00843 
00844     SERVER_EXPORT int jack_internal_initialize(jack_client_t* jack_client, const JSList* params)
00845     {
00846         if (master_manager) {
00847             jack_error("Master Manager already loaded");
00848             return 1;
00849         } else {
00850             jack_log("Loading Master Manager");
00851             master_manager = new Jack::JackNetMasterManager(jack_client, params);
00852             return (master_manager) ? 0 : 1;
00853         }
00854     }
00855 
00856     SERVER_EXPORT int jack_initialize(jack_client_t* jack_client, const char* load_init)
00857     {
00858         JSList* params = NULL;
00859         bool parse_params = true;
00860         int res = 1;
00861         jack_driver_desc_t* desc = jack_get_descriptor();
00862 
00863         Jack::JackArgParser parser(load_init);
00864         if (parser.GetArgc() > 0) {
00865             parse_params = parser.ParseParams(desc, &params);
00866         }
00867 
00868         if (parse_params) {
00869             res = jack_internal_initialize(jack_client, params);
00870             parser.FreeParams(params);
00871         }
00872         return res;
00873     }
00874 
00875     SERVER_EXPORT void jack_finish(void* arg)
00876     {
00877         if (master_manager) {
00878             jack_log ("Unloading Master Manager");
00879             delete master_manager;
00880             master_manager = NULL;
00881         }
00882     }
00883 
00884 #ifdef __cplusplus
00885 }
00886 #endif