JACKNetworkPlayer.cxx

Go to the documentation of this file.
00001 
00002 #include "JACKNetworkPlayer.hxx"
00003 
00004 #include "PushFlowControl.hxx"
00005 #include "XMLStorage.hxx"
00006 
00007 namespace CLAM
00008 {
00009 
00010 //JACK CODE
00011 inline int JackProcessingCallback (jack_nframes_t nframes, void *arg)
00012 {
00013         JACKNetworkPlayer* player=(JACKNetworkPlayer*)arg;
00014         player->Do(nframes);
00015         return 0;
00016 }
00017 
00018 inline void JackShutdownCallback (void *arg)
00019 {
00020         JACKNetworkPlayer* player=(JACKNetworkPlayer*)arg;
00021         player->OnShutdown();
00022 }
00023 
00024 JACKNetworkPlayer::JACKNetworkPlayer(const std::string & name)
00025         : _jackClientName(name)
00026 {
00027         _autoConnect=false;
00028         _jackClient=0;
00029         InitClient();
00030 }
00031 
00032 JACKNetworkPlayer::~JACKNetworkPlayer()
00033 {
00034         Stop();
00035         
00036         if (not _jackClient) return;
00037         bool error = jack_client_close (_jackClient);
00038         if (error)
00039         {
00040                 std::cerr << "JACK ERROR: cannot close client" << std::endl;
00041                 exit(1);
00042         }
00043 }
00044 
00045 bool JACKNetworkPlayer::IsWorking() const
00046 {
00047         return _jackClient != 0;
00048 }
00049 
00050 std::string JACKNetworkPlayer::NonWorkingReason() const
00051 {
00052         if (_jackClient) return "";
00053         return "No connection to JACK server available";
00054 }
00055 
00056 void JACKNetworkPlayer::InitClient()
00057 {
00058         jack_status_t jackStatus;
00059         _jackClient = jack_client_open ( _jackClientName.c_str(), JackNullOption, &jackStatus );
00060         if (not _jackClient)
00061         {
00062                 // TODO: Check jackStatus to be more informative
00063                 std::cerr << "JACK ERROR: server not running?"<< std::endl;
00064                 return;
00065         }
00066         
00067         //Register callback method for processing
00068         bool err = jack_set_process_callback (_jackClient, JackProcessingCallback, this);
00069         CLAM_ASSERT(not err, "JACK ERROR: registering process callbacks");
00070         
00071         //Register shutdown callback
00072         jack_on_shutdown (_jackClient, JackShutdownCallback, this);
00073         
00074         //Get JACK information
00075         _jackSampleRate=(int)jack_get_sample_rate (_jackClient);
00076         _jackBufferSize=(int)jack_get_buffer_size (_jackClient);
00077 }
00078 
00079 
00080 void JACKNetworkPlayer::RegisterPorts()
00081 {
00082         RegisterInputPorts( GetNetwork() );
00083         RegisterOutputPorts( GetNetwork() );
00084 }
00085 
00086 void JACKNetworkPlayer::RegisterInputPorts(const Network& net)
00087 {
00088         CLAM_ASSERT( _sourceJackBindings.empty(), "JACKNetworkPlayer::RegisterInputPorts() : there are already registered input ports");
00089         
00090         SourceJackBinding pair;
00091         
00092         //Get them from the Network and add it to local list            
00093         for (Network::ProcessingsMap::const_iterator it=net.BeginProcessings(); it!=net.EndProcessings(); it++)
00094         {
00095                 std::string processingClass = it->second->GetClassName();
00096                 if (processingClass != "AudioSource") continue;
00097 
00098                 //Get Processing address
00099                 pair.source=(AudioSource*)it->second;
00100                 pair.source->SetFrameAndHopSize(_jackBufferSize);
00101 
00102                 //Register port on the JACK server
00103                 const std::string & processingName = it->first;
00104                 pair.jackPort=jack_port_register (_jackClient,
00105                         processingName.c_str(),
00106                         JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
00107 
00108                 //Add the pair (jack port, clam jack receiver) to the list
00109                 _sourceJackBindings.push_back(pair);
00110         }
00111 }
00112 
00113 void JACKNetworkPlayer::RegisterOutputPorts(const Network& net)
00114 {
00115         CLAM_ASSERT( _sinkJackBindings.empty(), "JACKNetworkPlayer::RegisterOutputPorts() : there are already registered output ports");
00116         
00117         SinkJackBinding pair;
00118         
00119         //Get them from the Network and add it to local list            
00120         for (Network::ProcessingsMap::const_iterator it=net.BeginProcessings(); it!=net.EndProcessings(); it++)
00121         {
00122                 std::string processingClass = it->second->GetClassName();
00123                 if (processingClass != "AudioSink") continue;
00124 
00125                 //Get Processing address
00126                 pair.sink=(AudioSink*)it->second;
00127                 pair.sink->SetFrameAndHopSize(_jackBufferSize);
00128 
00129                 //Register port on the JACK server
00130                 const std::string & processingName = it->first;
00131                 pair.jackPort=jack_port_register (_jackClient,
00132                         processingName.c_str(),
00133                         JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
00134 
00135                 //Add the pair (jack port, clam jack receiver) to the list
00136                 _sinkJackBindings.push_back(pair);
00137         }
00138 }
00139 
00140 void JACKNetworkPlayer::UnRegisterPorts()
00141 {
00142         for (SinkJackBindings::iterator it=_sinkJackBindings.begin(); it!=_sinkJackBindings.end(); it++)
00143         {
00144                 if ( jack_port_unregister ( _jackClient, it->jackPort) )
00145                 {
00146                         std::cerr << "JACK ERROR: unregistering port " << it->PortName() << std::endl;
00147                         exit(1);
00148                 }
00149         }
00150         _sinkJackBindings.clear();
00151         
00152         for (SourceJackBindings::iterator it=_sourceJackBindings.begin(); it!=_sourceJackBindings.end(); it++)
00153         {
00154                 if ( jack_port_unregister ( _jackClient, it->jackPort) )
00155                 {
00156                         std::cerr << "JACK ERROR: unregistering port " << it->PortName() << std::endl;
00157                         exit(1);
00158                 }
00159         }
00160         _sourceJackBindings.clear();
00161 }
00162 
00163 void JACKNetworkPlayer::CopyJackBuffersToGenerators(const jack_nframes_t nframes)
00164 {
00165         for (SourceJackBindings::iterator it=_sourceJackBindings.begin(); it!=_sourceJackBindings.end(); it++)
00166         {
00167                 //Retrieve JACK buffer location
00168                 jack_default_audio_sample_t *jackInBuffer = 
00169                         (jack_default_audio_sample_t*) jack_port_get_buffer ( it->jackPort, nframes);
00170                 //Tell the AudioSource where to look for data in its Do()
00171                 it->source->SetExternalBuffer( jackInBuffer, nframes );
00172 
00173         }
00174 
00175 }
00176 
00177 void JACKNetworkPlayer::CopySinksToJackBuffers(const jack_nframes_t nframes)
00178 {
00179         for (SinkJackBindings::iterator it=_sinkJackBindings.begin(); it!=_sinkJackBindings.end(); it++)
00180         {
00181                 //Retrieve JACK buffer location
00182                 jack_default_audio_sample_t *jackOutBuffer = 
00183                         (jack_default_audio_sample_t*) jack_port_get_buffer ( it->jackPort, nframes);
00184                 //Tell the AudioSource where to copy data consumed in its Do()
00185                 it->sink->SetExternalBuffer( jackOutBuffer, nframes);   
00186         }
00187 }
00188 
00189 void JACKNetworkPlayer::Start()
00190 {
00191         if (!IsStopped()) return;
00192 
00193         if (!_jackClient) InitClient();
00194         if (!_jackClient) return;
00195         
00196         SetStopped(false);
00197         
00198         UnRegisterPorts();
00199         RegisterPorts();
00200                 
00201         //JACK CODE (the init order of network, ... should be decided)
00202         if (jack_activate (_jackClient)) {
00203                 std::cerr << "JACK ERROR: cannot activate client" << std::endl;
00204                 exit(1);
00205         }
00206 
00207         if (_autoConnect)
00208                 AutoConnectPorts();
00209         else
00210                 RestoreConnections();
00211 }
00212 void JACKNetworkPlayer::Init()
00213 {
00214         InitClient();
00215 }
00216 void JACKNetworkPlayer::OnShutdown()
00217 {
00218         if (not _jackClient) return;
00219         SetStopped(true);
00220         GetNetwork().Stop();
00221         _sinkJackBindings.clear(); // TODO: May we save them?
00222         _sourceJackBindings.clear(); // TODO: May we save them?;
00223         _jackClient=0;
00224 }
00225 
00226 void JACKNetworkPlayer::Stop()
00227 {
00228         if (IsStopped()) return;
00229         SetStopped(true);
00230 
00231         StoreConnections();
00232         
00233         if ( jack_deactivate (_jackClient) )
00234         {
00235                 std::cerr << "JACK ERROR: cannot deactivate client" << std::endl;
00236                 exit(1);
00237         }
00238 }
00239 
00240 void JACKNetworkPlayer::Do(const jack_nframes_t nframes)
00241 {
00242         if (IsStopped()) return;
00243 
00244         CopyJackBuffersToGenerators(nframes);
00245         CopySinksToJackBuffers(nframes);
00246         GetNetwork().Do();
00247 }
00248 
00249 //Saves the connections made to our local in/out jack ports
00250 void JACKNetworkPlayer::StoreConnections()
00251 {
00252         for (SourceJackBindings::iterator it=_sourceJackBindings.begin(); it!=_sourceJackBindings.end(); it++)
00253         {
00254                 JackConnection connection;
00255                 connection.processingName = it->PortName();
00256                 connection.outsideConnections = jack_port_get_connections ( it->jackPort );
00257                 _incomingJackConnections.push_back(connection);
00258         }
00259         
00260         for (SinkJackBindings::iterator it=_sinkJackBindings.begin(); it!=_sinkJackBindings.end(); it++)
00261         {
00262                 JackConnection connection;
00263                 connection.processingName = it->PortName();
00264                 connection.outsideConnections = jack_port_get_connections ( it->jackPort );
00265                 _outgoingJackConnections.push_back(connection);
00266         }
00267 }
00268 
00269 //Loads the connections made to our local in/out jack ports
00270 void JACKNetworkPlayer::RestoreConnections()
00271 {
00272         for (JackConnections::iterator it=_incomingJackConnections.begin(); it!=_incomingJackConnections.end(); it++)
00273         {
00274                 if (not it->outsideConnections) continue;
00275                 for (unsigned i=0; it->outsideConnections[i]; i++)
00276                 {
00277                         bool error = jack_connect ( _jackClient, it->outsideConnections[i], it->processingName.c_str() );
00278                         if (error)
00279                                 std::cerr << "JACK WARNING: could not reconnect ports ( " <<
00280                                         it->processingName << " , " << it->outsideConnections[i] << " )" <<std::endl;
00281                 }
00282                 free(it->outsideConnections);
00283         }
00284         _incomingJackConnections.clear();
00285 
00286         for (JackConnections::iterator it=_outgoingJackConnections.begin(); it!=_outgoingJackConnections.end(); it++)
00287         {
00288                 if (not it->outsideConnections) continue;
00289                 for (unsigned i=0; it->outsideConnections[i]; i++)
00290                 {
00291                         bool error = jack_connect ( _jackClient, it->processingName.c_str(), it->outsideConnections[i] );
00292                         if (error)
00293                                 std::cerr << "JACK WARNING: could not reconnect ports ( " <<
00294                                         it->outsideConnections[i] << " , " << it->processingName << " )" <<std::endl;
00295                 }
00296                 free(it->outsideConnections);
00297         }
00298         _outgoingJackConnections.clear();
00299 }
00300 
00301 void JACKNetworkPlayer::AutoConnectPorts()
00302 {
00303         //Automatically connect the ports to external jack ports
00304         std::cout << "Automatically connecting to JACK input and output ports" << std::endl;
00305         
00306         //CONNECT JACK OUTPUT PORTS TO CLAM EXTERNGENERATORS
00307         const char ** portnames= jack_get_ports ( _jackClient , _jackOutPortAutoConnectList.c_str(), NULL, JackPortIsOutput);
00308 
00309         if (portnames==NULL)
00310         {
00311                 std::cout << " -WARNING: couldn't locate any JACK output port <"
00312                         << _jackOutPortAutoConnectList << ">"<<std::endl;
00313         }
00314         else
00315         {
00316                 int i=0;
00317 
00318                 //Double iterate AudioSources & found JACK out ports
00319                 for ( SourceJackBindings::iterator it= _sourceJackBindings.begin(); it!=_sourceJackBindings.end(); it++)
00320                 {
00321                         std::cout << "- Connecting " << portnames[i] << " -> " 
00322                                 << it->PortName() << std::endl;
00323 
00324                         if ( jack_connect( _jackClient, portnames[i], 
00325                                                 it->PortName() ) !=0 )
00326                         {
00327                                 std::cerr << " -WARNING: couldn't connect" << std::endl;
00328                         }
00329                 
00330                         i++;
00331                         if (portnames[i]==NULL) break;
00332                 }       
00333         }               
00334         free(portnames);
00335 
00336         //CONNECT CLAM EXTERNSINKS TO JACK INPUT PORTS
00337         portnames= jack_get_ports ( _jackClient , _jackInPortAutoConnectList.c_str(), NULL, JackPortIsInput);
00338 
00339         if (portnames==NULL)
00340         {
00341                 std::cout << " -WARNING: couldn't locate any JACK input port <"
00342                         << _jackInPortAutoConnectList << ">"<<std::endl;
00343         }
00344         else
00345         {
00346                 int i=0;
00347 
00348                 //Double iterate found JACK in ports & ExterSinks
00349                 for (SinkJackBindings::iterator it= _sinkJackBindings.begin(); it!=_sinkJackBindings.end(); it++)
00350                 {
00351                         std::cout << "- Connecting "<< it->PortName()
00352                                 << " -> " << portnames[i] << std::endl;
00353 
00354                         if ( jack_connect( _jackClient, it->PortName(),
00355                                                 portnames[i]) != 0)
00356                         {
00357                                 std::cerr << " -WARNING: couldn't connect" << std::endl;
00358                         }
00359                 
00360                         i++;
00361                         if (portnames[i]==NULL) break;
00362                 }
00363         }                       
00364         free(portnames);
00365 }
00366 
00367 
00368 
00369 } //namespace CLAM
00370 
00371 

Generated on Tue Aug 12 22:33:43 2008 for CLAM by  doxygen 1.5.5