CLAM-Development
1.1
|
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