CLAM-Development  1.4.0
JACKNetworkPlayer.cxx
Go to the documentation of this file.
1 
2 #include "JACKNetworkPlayer.hxx"
3 #include "PushFlowControl.hxx"
4 #include "AudioSource.hxx"
5 #include "AudioSink.hxx"
6 
7 #include <iostream>
8 
9 namespace CLAM
10 {
11 
12 //JACK CODE
13 inline int JackProcessingCallback (jack_nframes_t nframes, void *arg)
14 {
16  player->Do(nframes);
17  return 0;
18 }
19 
20 inline void JackShutdownCallback (void *arg)
21 {
23  player->OnShutdown();
24 }
25 
26 JACKNetworkPlayer::JACKNetworkPlayer(const std::string & name)
27  : _jackClient(0)
28  , _jackClientName(name)
29 {
30  _autoConnect=false;
31  _jackClient=0;
32  InitClient();
33 }
34 
36 {
37  Stop();
38 
39  if (not _jackClient) return;
40  bool error = jack_client_close (_jackClient);
41  if (error)
42  {
43  std::cerr << "JACK ERROR: cannot close client" << std::endl;
44  exit(1);
45  }
46 }
47 
49 {
50  return _jackClient != 0;
51 }
52 
54 {
55  if (_jackClient) return "";
56  return "No connection to JACK server available";
57 }
58 
60 {
61  unsigned jackClientNameMaxSize=jack_client_name_size();
62  if (jackClientNameMaxSize<=_jackClientName.size()) // the = is because the 0 of the c string...
63  {
64  std::cerr << "JACK WARNING: jack client name \"" << _jackClientName
65  <<"\" truncated to " << jackClientNameMaxSize << " characters"<<std::endl;
66  _jackClientName.resize(jackClientNameMaxSize-1);
67  }
68 
69  CLAM_ASSERT(not _jackClient, "JACKNetworkPlayer: Initializing a client without closing the previous one");
70  jack_status_t jackStatus;
71  _jackClient = jack_client_open ( _jackClientName.c_str(), JackNullOption, &jackStatus );
72  if (not _jackClient)
73  {
74  // TODO: Check jackStatus to be more informative
75  std::cerr << "JACK ERROR: server not running?"<< std::endl;
76  return;
77  }
78 
79  //Register callback method for processing
80  bool err = jack_set_process_callback (_jackClient, JackProcessingCallback, this);
81  CLAM_ASSERT(not err, "JACK ERROR: registering process callbacks");
82 
83  //Register shutdown callback
84  jack_on_shutdown (_jackClient, JackShutdownCallback, this);
85 
86  //Get JACK information
87  _jackSampleRate=(int)jack_get_sample_rate (_jackClient);
88  _jackBufferSize=(int)jack_get_buffer_size (_jackClient);
89 }
90 
91 
93 {
96 }
97 
99 {
100  CLAM_ASSERT( _sourceJackPorts.empty(),
101  "JACKNetworkPlayer::RegisterInputPorts() : there are already registered input ports");
102  unsigned nPorts = GetNSources();
103  _sourceJackPorts.resize(nPorts);
104  for (unsigned i=0; i<nPorts; i++)
105  {
106  _sourceJackPorts[i] = jack_port_register(
107  _jackClient, SourceName(i).c_str(),
108  JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
109  SetSourceFrameSize(i,_jackBufferSize);
110  }
111 }
112 
114 {
115  CLAM_ASSERT( _sinkJackPorts.empty(),
116  "JACKNetworkPlayer::RegisterOutputPorts() : there are already registered output ports");
117  unsigned nPorts = GetNSinks();
118  _sinkJackPorts.resize(nPorts);
119  for(unsigned i = 0; i < nPorts; ++i)
120  {
121  _sinkJackPorts[i] = jack_port_register(
122  _jackClient, SinkName(i).c_str(),
123  JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
124  SetSinkFrameSize(i, _jackBufferSize);
125  }
126 }
127 
129 {
130  for (unsigned i=0; i<_sinkJackPorts.size(); i++)
131  {
132  if ( jack_port_unregister ( _jackClient, _sinkJackPorts[i]) )
133  {
134  std::cerr << "JACK ERROR: unregistering port " << PortName(_sinkJackPorts[i]) << std::endl;
135  exit(1);
136  }
137  }
138  _sinkJackPorts.clear();
139 
140  for (unsigned i=0; i<_sourceJackPorts.size(); i++)
141  {
142  if ( jack_port_unregister ( _jackClient, _sourceJackPorts[i]) )
143  {
144  std::cerr << "JACK ERROR: unregistering port " << PortName(_sourceJackPorts[i]) << std::endl;
145  exit(1);
146  }
147  }
148  _sourceJackPorts.clear();
149 }
150 
151 void JACKNetworkPlayer::CopyJackBuffersToSources(const jack_nframes_t nframes)
152 {
153  for (unsigned i=0; i<_sourceJackPorts.size(); i++)
154  {
155  jack_default_audio_sample_t *jackInBuffer =
156  (jack_default_audio_sample_t*) jack_port_get_buffer(_sourceJackPorts[i], nframes);
157  SetSourceBuffer(i, jackInBuffer, nframes);
158  }
159 }
160 
161 void JACKNetworkPlayer::CopySinksToJackBuffers(const jack_nframes_t nframes)
162 {
163  for (unsigned i=0; i<_sinkJackPorts.size(); i++)
164  {
165  jack_default_audio_sample_t* jackOutBuffer =
166  (jack_default_audio_sample_t*) jack_port_get_buffer(_sinkJackPorts[i], nframes);
167  SetSinkBuffer(i, jackOutBuffer, nframes);
168  }
169 }
170 
171 void JACKNetworkPlayer::BlankJackBuffers(const jack_nframes_t nframes)
172 {
173  for (unsigned i=0; i<_sinkJackPorts.size(); i++)
174  {
175  jack_default_audio_sample_t *jackOutBuffer =
176  (jack_default_audio_sample_t*) jack_port_get_buffer ( _sinkJackPorts[i], nframes);
177  std::memset(jackOutBuffer, 0, nframes*sizeof(jack_default_audio_sample_t));
178  }
179 }
180 
182 {
183  if (IsPlaying()) return;
184  if (IsPaused())
185  {
186  BePlaying();
187  return;
188  }
189  if (!_jackClient) InitClient();
190  if (!_jackClient) return;
191 
193 
194  BePlaying();
195  UnRegisterPorts();
196  RegisterPorts();
197  GetNetwork().Start();
198 
199  //JACK CODE (the init order of network, ... should be decided)
200  if (jack_activate (_jackClient)) {
201  std::cerr << "JACK ERROR: cannot activate client" << std::endl;
202  exit(1);
203  }
204 
205  if (_autoConnect)
207  else
209 }
211 {
212  if (not _jackClient) InitClient();
213 }
215 {
216  if (not _jackClient) return;
217  BeStopped();
218  GetNetwork().Stop();
219  _sinkJackPorts.clear(); // TODO: May we save them?
220  _sourceJackPorts.clear(); // TODO: May we save them?;
221  _jackClient=0;
222 }
223 
225 {
226  if (IsStopped()) return;
228  if ( jack_deactivate (_jackClient) )
229  {
230  std::cerr << "JACK ERROR: cannot deactivate client" << std::endl;
231  exit(1);
232  }
233  BeStopped();
234  GetNetwork().Stop();
235 }
236 
237 void JACKNetworkPlayer::Do(const jack_nframes_t nframes)
238 {
239  if (IsStopped()) return;
240  if (IsPaused())
241  {
242  BlankJackBuffers(nframes);
243  return;
244  }
245 
246  CopyJackBuffersToSources(nframes);
247  CopySinksToJackBuffers(nframes);
248  GetNetwork().Do();
249 }
250 
251 //Saves the connections made to our local in/out jack ports
253 {
254  for (unsigned i=0; i<_sourceJackPorts.size(); i++)
255  {
256  JackConnection connection;
257  connection.processingName = PortName(_sourceJackPorts[i]);
258  connection.outsideConnections = jack_port_get_connections ( _sourceJackPorts[i] );
259  _incomingJackConnections.push_back(connection);
260  }
261 
262  for (unsigned i=0; i<_sinkJackPorts.size(); i++)
263  {
264  JackConnection connection;
265  connection.processingName = PortName(_sinkJackPorts[i]);
266  connection.outsideConnections = jack_port_get_connections ( _sinkJackPorts[i] );
267  _outgoingJackConnections.push_back(connection);
268  }
269 }
270 
271 //Loads the connections made to our local in/out jack ports
273 {
274  for (JackConnections::iterator it=_incomingJackConnections.begin(); it!=_incomingJackConnections.end(); it++)
275  {
276  if (not it->outsideConnections) continue;
277  for (unsigned i=0; it->outsideConnections[i]; i++)
278  {
279  bool error = jack_connect ( _jackClient, it->outsideConnections[i], it->processingName.c_str() );
280  if (error)
281  std::cerr << "JACK WARNING: could not reconnect ports ( " <<
282  it->processingName << " , " << it->outsideConnections[i] << " )" <<std::endl;
283  }
284  free(it->outsideConnections);
285  }
286  _incomingJackConnections.clear();
287 
288  for (JackConnections::iterator it=_outgoingJackConnections.begin(); it!=_outgoingJackConnections.end(); it++)
289  {
290  if (not it->outsideConnections) continue;
291  for (unsigned i=0; it->outsideConnections[i]; i++)
292  {
293  bool error = jack_connect ( _jackClient, it->processingName.c_str(), it->outsideConnections[i] );
294  if (error)
295  std::cerr << "JACK WARNING: could not reconnect ports ( " <<
296  it->outsideConnections[i] << " , " << it->processingName << " )" <<std::endl;
297  }
298  free(it->outsideConnections);
299  }
300  _outgoingJackConnections.clear();
301 }
302 
304 {
305  //Automatically connect the ports to external jack ports
306 
307  //CONNECT JACK OUTPUT PORTS TO CLAM EXTERNGENERATORS
308  const char ** portnames= jack_get_ports ( _jackClient , _jackOutPortAutoConnectList.c_str(), NULL, JackPortIsOutput);
309  if (not portnames)
310  {
311  std::cout << " -WARNING: couldn't locate any JACK output port <"
312  << _jackOutPortAutoConnectList << ">"<<std::endl;
313  }
314  else
315  {
316  for (unsigned i=0; i<_sourceJackPorts.size() && portnames[i]; i++)
317  {
318  jack_port_t * port = _sourceJackPorts[i];
319  std::cout << "- Connecting " << portnames[i] << " -> "
320  << PortName(port) << std::endl;
321 
322  if ( jack_connect( _jackClient, portnames[i], PortName(port) ) !=0 )
323  std::cerr << " -WARNING: couldn't connect" << std::endl;
324  }
325  free(portnames);
326  }
327 
328  //CONNECT CLAM EXTERNSINKS TO JACK INPUT PORTS
329  portnames= jack_get_ports ( _jackClient , _jackInPortAutoConnectList.c_str(), NULL, JackPortIsInput);
330  if ( not portnames)
331  {
332  std::cout << " -WARNING: couldn't locate any JACK input port <"
333  << _jackInPortAutoConnectList << ">"<<std::endl;
334  }
335  else
336  {
337  for (unsigned i=0; i<_sinkJackPorts.size() && portnames[i]; i++)
338  {
339  const char * localPortName = PortName(_sinkJackPorts[i]);
340  std::cout << "- Connecting "<< localPortName
341  << " -> " << portnames[i] << std::endl;
342 
343  if ( jack_connect( _jackClient, localPortName, portnames[i]) != 0)
344  std::cerr << " -WARNING: couldn't connect" << std::endl;
345  }
346  free(portnames);
347  }
348 }
349 
350 } //namespace CLAM
351 
352