JACKNetworkPlayer.cxx

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