svapp
1.9
|
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 00002 00003 /* 00004 Sonic Visualiser 00005 An audio file viewer and annotation editor. 00006 Centre for Digital Music, Queen Mary, University of London. 00007 This file copyright 2006 Chris Cannam. 00008 00009 This program is free software; you can redistribute it and/or 00010 modify it under the terms of the GNU General Public License as 00011 published by the Free Software Foundation; either version 2 of the 00012 License, or (at your option) any later version. See the file 00013 COPYING included with this distribution for more information. 00014 */ 00015 00016 #ifdef HAVE_JACK 00017 00018 #include "AudioJACKTarget.h" 00019 #include "AudioCallbackPlaySource.h" 00020 00021 #include <iostream> 00022 #include <cmath> 00023 00024 #include <alloca.h> 00025 00026 //#define DEBUG_AUDIO_JACK_TARGET 1 00027 00028 #ifdef BUILD_STATIC 00029 #ifdef Q_OS_LINUX 00030 00031 // Some lunacy to enable JACK support in static builds. JACK isn't 00032 // supposed to be linked statically, because it depends on a 00033 // consistent shared memory layout between client library and daemon, 00034 // so it's very fragile in the face of version mismatches. 00035 // 00036 // Therefore for static builds on Linux we avoid linking against JACK 00037 // at all during the build, instead using dlopen and runtime symbol 00038 // lookup to switch on JACK support at runtime. The following big 00039 // mess (down to the #endifs) is the code that implements this. 00040 00041 static void *symbol(const char *name) 00042 { 00043 static bool attempted = false; 00044 static void *library = 0; 00045 static std::map<const char *, void *> symbols; 00046 if (symbols.find(name) != symbols.end()) return symbols[name]; 00047 if (!library) { 00048 if (!attempted) { 00049 library = ::dlopen("libjack.so.1", RTLD_NOW); 00050 if (!library) library = ::dlopen("libjack.so.0", RTLD_NOW); 00051 if (!library) library = ::dlopen("libjack.so", RTLD_NOW); 00052 if (!library) { 00053 cerr << "WARNING: AudioJACKTarget: Failed to load JACK library: " 00054 << ::dlerror() << " (tried .so, .so.0, .so.1)" 00055 << endl; 00056 } 00057 attempted = true; 00058 } 00059 if (!library) return 0; 00060 } 00061 void *symbol = ::dlsym(library, name); 00062 if (!symbol) { 00063 cerr << "WARNING: AudioJACKTarget: Failed to locate symbol " 00064 << name << ": " << ::dlerror() << endl; 00065 } 00066 symbols[name] = symbol; 00067 return symbol; 00068 } 00069 00070 static jack_client_t *dynamic_jack_client_open(const char *client_name, 00071 jack_options_t options, 00072 jack_status_t *status, ...) 00073 { 00074 typedef jack_client_t *(*func)(const char *client_name, 00075 jack_options_t options, 00076 jack_status_t *status, ...); 00077 void *s = symbol("jack_client_open"); 00078 if (!s) return 0; 00079 func f = (func)s; 00080 return f(client_name, options, status); // varargs not supported here 00081 } 00082 00083 static int dynamic_jack_set_process_callback(jack_client_t *client, 00084 JackProcessCallback process_callback, 00085 void *arg) 00086 { 00087 typedef int (*func)(jack_client_t *client, 00088 JackProcessCallback process_callback, 00089 void *arg); 00090 void *s = symbol("jack_set_process_callback"); 00091 if (!s) return 1; 00092 func f = (func)s; 00093 return f(client, process_callback, arg); 00094 } 00095 00096 static int dynamic_jack_set_xrun_callback(jack_client_t *client, 00097 JackXRunCallback xrun_callback, 00098 void *arg) 00099 { 00100 typedef int (*func)(jack_client_t *client, 00101 JackXRunCallback xrun_callback, 00102 void *arg); 00103 void *s = symbol("jack_set_xrun_callback"); 00104 if (!s) return 1; 00105 func f = (func)s; 00106 return f(client, xrun_callback, arg); 00107 } 00108 00109 static const char **dynamic_jack_get_ports(jack_client_t *client, 00110 const char *port_name_pattern, 00111 const char *type_name_pattern, 00112 unsigned long flags) 00113 { 00114 typedef const char **(*func)(jack_client_t *client, 00115 const char *port_name_pattern, 00116 const char *type_name_pattern, 00117 unsigned long flags); 00118 void *s = symbol("jack_get_ports"); 00119 if (!s) return 0; 00120 func f = (func)s; 00121 return f(client, port_name_pattern, type_name_pattern, flags); 00122 } 00123 00124 static jack_port_t *dynamic_jack_port_register(jack_client_t *client, 00125 const char *port_name, 00126 const char *port_type, 00127 unsigned long flags, 00128 unsigned long buffer_size) 00129 { 00130 typedef jack_port_t *(*func)(jack_client_t *client, 00131 const char *port_name, 00132 const char *port_type, 00133 unsigned long flags, 00134 unsigned long buffer_size); 00135 void *s = symbol("jack_port_register"); 00136 if (!s) return 0; 00137 func f = (func)s; 00138 return f(client, port_name, port_type, flags, buffer_size); 00139 } 00140 00141 static int dynamic_jack_connect(jack_client_t *client, 00142 const char *source, 00143 const char *dest) 00144 { 00145 typedef int (*func)(jack_client_t *client, 00146 const char *source, 00147 const char *dest); 00148 void *s = symbol("jack_connect"); 00149 if (!s) return 1; 00150 func f = (func)s; 00151 return f(client, source, dest); 00152 } 00153 00154 static void *dynamic_jack_port_get_buffer(jack_port_t *port, 00155 jack_nframes_t sz) 00156 { 00157 typedef void *(*func)(jack_port_t *, jack_nframes_t); 00158 void *s = symbol("jack_port_get_buffer"); 00159 if (!s) return 0; 00160 func f = (func)s; 00161 return f(port, sz); 00162 } 00163 00164 static int dynamic_jack_port_unregister(jack_client_t *client, 00165 jack_port_t *port) 00166 { 00167 typedef int(*func)(jack_client_t *, jack_port_t *); 00168 void *s = symbol("jack_port_unregister"); 00169 if (!s) return 0; 00170 func f = (func)s; 00171 return f(client, port); 00172 } 00173 00174 static void dynamic_jack_port_get_latency_range(jack_port_t *port, 00175 jack_latency_callback_mode_t mode, 00176 jack_latency_range_t *range) 00177 { 00178 typedef void (*func)(jack_port_t *, jack_latency_callback_mode_t, jack_latency_range_t *); 00179 void *s = symbol("jack_port_get_latency_range"); 00180 if (!s) { 00181 range.min = range.max = 0; 00182 return; 00183 } 00184 func f = (func)s; 00185 f(port, mode, range); 00186 } 00187 00188 #define dynamic1(rv, name, argtype, failval) \ 00189 static rv dynamic_##name(argtype arg) { \ 00190 typedef rv (*func) (argtype); \ 00191 void *s = symbol(#name); \ 00192 if (!s) return failval; \ 00193 func f = (func) s; \ 00194 return f(arg); \ 00195 } 00196 00197 dynamic1(jack_client_t *, jack_client_new, const char *, 0); 00198 dynamic1(jack_nframes_t, jack_get_buffer_size, jack_client_t *, 0); 00199 dynamic1(jack_nframes_t, jack_get_sample_rate, jack_client_t *, 0); 00200 dynamic1(int, jack_activate, jack_client_t *, 1); 00201 dynamic1(int, jack_deactivate, jack_client_t *, 1); 00202 dynamic1(int, jack_client_close, jack_client_t *, 1); 00203 dynamic1(jack_nframes_t, jack_frame_time, jack_client_t *, 0); 00204 dynamic1(const char *, jack_port_name, const jack_port_t *, 0); 00205 00206 #define jack_client_new dynamic_jack_client_new 00207 #define jack_client_open dynamic_jack_client_open 00208 #define jack_get_buffer_size dynamic_jack_get_buffer_size 00209 #define jack_get_sample_rate dynamic_jack_get_sample_rate 00210 #define jack_set_process_callback dynamic_jack_set_process_callback 00211 #define jack_set_xrun_callback dynamic_jack_set_xrun_callback 00212 #define jack_activate dynamic_jack_activate 00213 #define jack_deactivate dynamic_jack_deactivate 00214 #define jack_client_close dynamic_jack_client_close 00215 #define jack_frame_time dynamic_jack_frame_time 00216 #define jack_get_ports dynamic_jack_get_ports 00217 #define jack_port_register dynamic_jack_port_register 00218 #define jack_port_unregister dynamic_jack_port_unregister 00219 #define jack_port_name dynamic_jack_port_name 00220 #define jack_connect dynamic_jack_connect 00221 #define jack_port_get_buffer dynamic_jack_port_get_buffer 00222 00223 #endif 00224 #endif 00225 00226 AudioJACKTarget::AudioJACKTarget(AudioCallbackPlaySource *source) : 00227 AudioCallbackPlayTarget(source), 00228 m_client(0), 00229 m_bufferSize(0), 00230 m_sampleRate(0), 00231 m_done(false) 00232 { 00233 JackOptions options = JackNullOption; 00234 #ifdef HAVE_PORTAUDIO_2_0 00235 options = JackNoStartServer; 00236 #endif 00237 #ifdef HAVE_LIBPULSE 00238 options = JackNoStartServer; 00239 #endif 00240 00241 JackStatus status = JackStatus(0); 00242 m_client = jack_client_open(source->getClientName().toLocal8Bit().data(), 00243 options, &status); 00244 00245 if (!m_client) { 00246 cerr << "AudioJACKTarget: Failed to connect to JACK server: status code " 00247 << status << endl; 00248 return; 00249 } 00250 00251 m_bufferSize = jack_get_buffer_size(m_client); 00252 m_sampleRate = jack_get_sample_rate(m_client); 00253 00254 jack_set_xrun_callback(m_client, xrunStatic, this); 00255 jack_set_process_callback(m_client, processStatic, this); 00256 00257 if (jack_activate(m_client)) { 00258 cerr << "ERROR: AudioJACKTarget: Failed to activate JACK client" 00259 << endl; 00260 } 00261 00262 if (m_source) { 00263 sourceModelReplaced(); 00264 } 00265 00266 // Mainstream JACK (though not jackdmp) calls mlockall() to lock 00267 // down all memory for real-time operation. That isn't a terribly 00268 // good idea in an application like this that may have very high 00269 // dynamic memory usage in other threads, as mlockall() applies 00270 // across all threads. We're far better off undoing it here and 00271 // accepting the possible loss of true RT capability. 00272 MUNLOCKALL(); 00273 } 00274 00275 AudioJACKTarget::~AudioJACKTarget() 00276 { 00277 SVDEBUG << "AudioJACKTarget::~AudioJACKTarget()" << endl; 00278 00279 if (m_source) { 00280 m_source->setTarget(0, m_bufferSize); 00281 } 00282 00283 shutdown(); 00284 00285 if (m_client) { 00286 00287 while (m_outputs.size() > 0) { 00288 std::vector<jack_port_t *>::iterator itr = m_outputs.end(); 00289 --itr; 00290 jack_port_t *port = *itr; 00291 cerr << "unregister " << m_outputs.size() << endl; 00292 if (port) jack_port_unregister(m_client, port); 00293 m_outputs.erase(itr); 00294 } 00295 cerr << "Deactivating... "; 00296 jack_deactivate(m_client); 00297 cerr << "done\nClosing... "; 00298 jack_client_close(m_client); 00299 cerr << "done" << endl; 00300 } 00301 00302 m_client = 0; 00303 00304 SVDEBUG << "AudioJACKTarget::~AudioJACKTarget() done" << endl; 00305 } 00306 00307 void 00308 AudioJACKTarget::shutdown() 00309 { 00310 m_done = true; 00311 } 00312 00313 bool 00314 AudioJACKTarget::isOK() const 00315 { 00316 return (m_client != 0); 00317 } 00318 00319 double 00320 AudioJACKTarget::getCurrentTime() const 00321 { 00322 if (m_client && m_sampleRate) { 00323 return double(jack_frame_time(m_client)) / double(m_sampleRate); 00324 } else { 00325 return 0.0; 00326 } 00327 } 00328 00329 int 00330 AudioJACKTarget::processStatic(jack_nframes_t nframes, void *arg) 00331 { 00332 return ((AudioJACKTarget *)arg)->process(nframes); 00333 } 00334 00335 int 00336 AudioJACKTarget::xrunStatic(void *arg) 00337 { 00338 return ((AudioJACKTarget *)arg)->xrun(); 00339 } 00340 00341 void 00342 AudioJACKTarget::sourceModelReplaced() 00343 { 00344 m_mutex.lock(); 00345 00346 m_source->setTarget(this, m_bufferSize); 00347 m_source->setTargetSampleRate(m_sampleRate); 00348 00349 int channels = m_source->getSourceChannelCount(); 00350 00351 // Because we offer pan, we always want at least 2 channels 00352 if (channels < 2) channels = 2; 00353 00354 if (channels == (int)m_outputs.size() || !m_client) { 00355 m_mutex.unlock(); 00356 return; 00357 } 00358 00359 const char **ports = 00360 jack_get_ports(m_client, NULL, NULL, 00361 JackPortIsPhysical | JackPortIsInput); 00362 int physicalPortCount = 0; 00363 while (ports[physicalPortCount]) ++physicalPortCount; 00364 00365 #ifdef DEBUG_AUDIO_JACK_TARGET 00366 SVDEBUG << "AudioJACKTarget::sourceModelReplaced: have " << channels << " channels and " << physicalPortCount << " physical ports" << endl; 00367 #endif 00368 00369 while ((int)m_outputs.size() < channels) { 00370 00371 char name[20]; 00372 jack_port_t *port; 00373 00374 sprintf(name, "out %d", int(m_outputs.size() + 1)); 00375 00376 port = jack_port_register(m_client, 00377 name, 00378 JACK_DEFAULT_AUDIO_TYPE, 00379 JackPortIsOutput, 00380 0); 00381 00382 if (!port) { 00383 cerr 00384 << "ERROR: AudioJACKTarget: Failed to create JACK output port " 00385 << m_outputs.size() << endl; 00386 } else { 00387 jack_latency_range_t range; 00388 jack_port_get_latency_range(port, JackPlaybackLatency, &range); 00389 m_source->setTargetPlayLatency(range.max); 00390 cerr << "AudioJACKTarget: output latency is " << range.max << endl; 00391 } 00392 00393 if ((int)m_outputs.size() < physicalPortCount) { 00394 jack_connect(m_client, jack_port_name(port), ports[m_outputs.size()]); 00395 } 00396 00397 m_outputs.push_back(port); 00398 } 00399 00400 while ((int)m_outputs.size() > channels) { 00401 std::vector<jack_port_t *>::iterator itr = m_outputs.end(); 00402 --itr; 00403 jack_port_t *port = *itr; 00404 if (port) jack_port_unregister(m_client, port); 00405 m_outputs.erase(itr); 00406 } 00407 00408 m_mutex.unlock(); 00409 } 00410 00411 int 00412 AudioJACKTarget::process(jack_nframes_t nframes) 00413 { 00414 if (m_done) return 0; 00415 00416 if (!m_mutex.tryLock()) { 00417 return 0; 00418 } 00419 00420 if (m_outputs.empty()) { 00421 m_mutex.unlock(); 00422 return 0; 00423 } 00424 00425 #ifdef DEBUG_AUDIO_JACK_TARGET 00426 cout << "AudioJACKTarget::process(" << nframes << "): have a source" << endl; 00427 #endif 00428 00429 #ifdef DEBUG_AUDIO_JACK_TARGET 00430 if (m_bufferSize != nframes) { 00431 cerr << "WARNING: m_bufferSize != nframes (" << m_bufferSize << " != " << nframes << ")" << endl; 00432 } 00433 #endif 00434 00435 float **buffers = (float **)alloca(m_outputs.size() * sizeof(float *)); 00436 00437 for (int ch = 0; ch < (int)m_outputs.size(); ++ch) { 00438 buffers[ch] = (float *)jack_port_get_buffer(m_outputs[ch], nframes); 00439 } 00440 00441 int received = 0; 00442 00443 if (m_source) { 00444 received = m_source->getSourceSamples(nframes, buffers); 00445 } 00446 00447 for (int ch = 0; ch < (int)m_outputs.size(); ++ch) { 00448 for (int i = received; i < (int)nframes; ++i) { 00449 buffers[ch][i] = 0.0; 00450 } 00451 } 00452 00453 float peakLeft = 0.0, peakRight = 0.0; 00454 00455 for (int ch = 0; ch < (int)m_outputs.size(); ++ch) { 00456 00457 float peak = 0.0; 00458 00459 for (int i = 0; i < (int)nframes; ++i) { 00460 buffers[ch][i] *= m_outputGain; 00461 float sample = fabsf(buffers[ch][i]); 00462 if (sample > peak) peak = sample; 00463 } 00464 00465 if (ch == 0) peakLeft = peak; 00466 if (ch > 0 || m_outputs.size() == 1) peakRight = peak; 00467 } 00468 00469 if (m_source) { 00470 m_source->setOutputLevels(peakLeft, peakRight); 00471 } 00472 00473 m_mutex.unlock(); 00474 return 0; 00475 } 00476 00477 int 00478 AudioJACKTarget::xrun() 00479 { 00480 cerr << "AudioJACKTarget: xrun!" << endl; 00481 if (m_source) m_source->audioProcessingOverload(); 00482 return 0; 00483 } 00484 00485 #endif /* HAVE_JACK */ 00486