annotate audioio/AudioJACKSource.cpp @ 17:3cbd40805795 tip

Remove obsolete stuff from README
author Chris Cannam
date Tue, 03 Dec 2013 16:33:08 +0000
parents df33703ace3b
children
rev   line source
cannam@0 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
cannam@0 2
cannam@0 3 #ifdef HAVE_JACK
cannam@0 4
cannam@0 5 #include "AudioJACKSource.h"
cannam@0 6 #include "AudioCallbackRecordTarget.h"
cannam@0 7
cannam@0 8 #include <iostream>
cannam@0 9 #include <cmath>
cannam@0 10
Chris@15 11 #include <cstdio>
Chris@15 12
cannam@0 13 //#define DEBUG_AUDIO_JACK_SOURCE 1
cannam@0 14
cannam@0 15 #ifdef BUILD_STATIC
cannam@0 16 #ifdef Q_OS_LINUX
cannam@0 17
cannam@0 18 // Some lunacy to enable JACK support in static builds. JACK isn't
cannam@0 19 // supposed to be linked statically, because it depends on a
cannam@0 20 // consistent shared memory layout between client library and daemon,
cannam@0 21 // so it's very fragile in the face of version mismatches.
cannam@0 22 //
cannam@0 23 // Therefore for static builds on Linux we avoid linking against JACK
cannam@0 24 // at all during the build, instead using dlopen and runtime symbol
cannam@0 25 // lookup to switch on JACK support at runtime. The following big
cannam@0 26 // mess (down to the #endifs) is the code that implements this.
cannam@0 27
cannam@0 28 static void *symbol(const char *name)
cannam@0 29 {
cannam@0 30 static bool attempted = false;
cannam@0 31 static void *library = 0;
cannam@0 32 static std::map<const char *, void *> symbols;
cannam@0 33 if (symbols.find(name) != symbols.end()) return symbols[name];
cannam@0 34 if (!library) {
cannam@0 35 if (!attempted) {
cannam@0 36 library = ::dlopen("libjack.so.1", RTLD_NOW);
cannam@0 37 if (!library) library = ::dlopen("libjack.so.0", RTLD_NOW);
cannam@0 38 if (!library) library = ::dlopen("libjack.so", RTLD_NOW);
cannam@0 39 if (!library) {
cannam@0 40 std::cerr << "WARNING: AudioJACKSource: Failed to load JACK library: "
cannam@0 41 << ::dlerror() << " (tried .so, .so.0, .so.1)"
cannam@0 42 << std::endl;
cannam@0 43 }
cannam@0 44 attempted = true;
cannam@0 45 }
cannam@0 46 if (!library) return 0;
cannam@0 47 }
cannam@0 48 void *symbol = ::dlsym(library, name);
cannam@0 49 if (!symbol) {
cannam@0 50 std::cerr << "WARNING: AudioJACKSource: Failed to locate symbol "
cannam@0 51 << name << ": " << ::dlerror() << std::endl;
cannam@0 52 }
cannam@0 53 symbols[name] = symbol;
cannam@0 54 return symbol;
cannam@0 55 }
cannam@0 56
Chris@15 57 static jack_client_t *dynamic_jack_client_open(const char *client_name,
Chris@15 58 jack_options_t options,
Chris@15 59 jack_status_t *status, ...)
Chris@15 60 {
Chris@15 61 typedef jack_client_t *(*func)(const char *client_name,
Chris@15 62 jack_options_t options,
Chris@15 63 jack_status_t *status, ...);
Chris@15 64 void *s = symbol("jack_client_open");
Chris@15 65 if (!s) return 0;
Chris@15 66 func f = (func)s;
Chris@15 67 return f(client_name, options, status); // varargs not supported here
Chris@15 68 }
Chris@15 69
cannam@0 70 static int dynamic_jack_set_process_callback(jack_client_t *client,
cannam@0 71 JackProcessCallback process_callback,
cannam@0 72 void *arg)
cannam@0 73 {
cannam@0 74 typedef int (*func)(jack_client_t *client,
cannam@0 75 JackProcessCallback process_callback,
cannam@0 76 void *arg);
cannam@0 77 void *s = symbol("jack_set_process_callback");
cannam@0 78 if (!s) return 1;
cannam@0 79 func f = (func)s;
cannam@0 80 return f(client, process_callback, arg);
cannam@0 81 }
cannam@0 82
cannam@0 83 static int dynamic_jack_set_xrun_callback(jack_client_t *client,
cannam@0 84 JackXRunCallback xrun_callback,
cannam@0 85 void *arg)
cannam@0 86 {
cannam@0 87 typedef int (*func)(jack_client_t *client,
cannam@0 88 JackXRunCallback xrun_callback,
cannam@0 89 void *arg);
cannam@0 90 void *s = symbol("jack_set_xrun_callback");
cannam@0 91 if (!s) return 1;
cannam@0 92 func f = (func)s;
cannam@0 93 return f(client, xrun_callback, arg);
cannam@0 94 }
cannam@0 95
cannam@0 96 static const char **dynamic_jack_get_ports(jack_client_t *client,
cannam@0 97 const char *port_name_pattern,
cannam@0 98 const char *type_name_pattern,
cannam@0 99 unsigned long flags)
cannam@0 100 {
cannam@0 101 typedef const char **(*func)(jack_client_t *client,
cannam@0 102 const char *port_name_pattern,
cannam@0 103 const char *type_name_pattern,
cannam@0 104 unsigned long flags);
cannam@0 105 void *s = symbol("jack_get_ports");
cannam@0 106 if (!s) return 0;
cannam@0 107 func f = (func)s;
cannam@0 108 return f(client, port_name_pattern, type_name_pattern, flags);
cannam@0 109 }
cannam@0 110
cannam@0 111 static jack_port_t *dynamic_jack_port_register(jack_client_t *client,
cannam@0 112 const char *port_name,
cannam@0 113 const char *port_type,
cannam@0 114 unsigned long flags,
cannam@0 115 unsigned long buffer_size)
cannam@0 116 {
cannam@0 117 typedef jack_port_t *(*func)(jack_client_t *client,
cannam@0 118 const char *port_name,
cannam@0 119 const char *port_type,
cannam@0 120 unsigned long flags,
cannam@0 121 unsigned long buffer_size);
cannam@0 122 void *s = symbol("jack_port_register");
cannam@0 123 if (!s) return 0;
cannam@0 124 func f = (func)s;
cannam@0 125 return f(client, port_name, port_type, flags, buffer_size);
cannam@0 126 }
cannam@0 127
cannam@0 128 static int dynamic_jack_connect(jack_client_t *client,
cannam@0 129 const char *source,
cannam@0 130 const char *dest)
cannam@0 131 {
cannam@0 132 typedef int (*func)(jack_client_t *client,
cannam@0 133 const char *source,
cannam@0 134 const char *dest);
cannam@0 135 void *s = symbol("jack_connect");
cannam@0 136 if (!s) return 1;
cannam@0 137 func f = (func)s;
cannam@0 138 return f(client, source, dest);
cannam@0 139 }
cannam@0 140
cannam@0 141 static void *dynamic_jack_port_get_buffer(jack_port_t *port,
cannam@0 142 jack_nframes_t sz)
cannam@0 143 {
cannam@0 144 typedef void *(*func)(jack_port_t *, jack_nframes_t);
cannam@0 145 void *s = symbol("jack_port_get_buffer");
cannam@0 146 if (!s) return 0;
cannam@0 147 func f = (func)s;
cannam@0 148 return f(port, sz);
cannam@0 149 }
cannam@0 150
cannam@0 151 static int dynamic_jack_port_unregister(jack_client_t *client,
cannam@0 152 jack_port_t *port)
cannam@0 153 {
cannam@0 154 typedef int(*func)(jack_client_t *, jack_port_t *);
cannam@0 155 void *s = symbol("jack_port_unregister");
cannam@0 156 if (!s) return 0;
cannam@0 157 func f = (func)s;
cannam@0 158 return f(client, port);
cannam@0 159 }
cannam@0 160
cannam@0 161 #define dynamic1(rv, name, argtype, failval) \
cannam@0 162 static rv dynamic_##name(argtype arg) { \
cannam@0 163 typedef rv (*func) (argtype); \
cannam@0 164 void *s = symbol(#name); \
cannam@0 165 if (!s) return failval; \
cannam@0 166 func f = (func) s; \
cannam@0 167 return f(arg); \
cannam@0 168 }
cannam@0 169
cannam@0 170 dynamic1(jack_client_t *, jack_client_new, const char *, 0);
cannam@0 171 dynamic1(jack_nframes_t, jack_get_buffer_size, jack_client_t *, 0);
cannam@0 172 dynamic1(jack_nframes_t, jack_get_sample_rate, jack_client_t *, 0);
cannam@0 173 dynamic1(int, jack_activate, jack_client_t *, 1);
cannam@0 174 dynamic1(int, jack_deactivate, jack_client_t *, 1);
cannam@0 175 dynamic1(int, jack_client_close, jack_client_t *, 1);
cannam@0 176 dynamic1(jack_nframes_t, jack_port_get_latency, jack_port_t *, 0);
cannam@0 177 dynamic1(const char *, jack_port_name, const jack_port_t *, 0);
cannam@0 178
cannam@0 179 #define jack_client_new dynamic_jack_client_new
Chris@15 180 #define jack_client_open dynamic_jack_client_open
cannam@0 181 #define jack_get_buffer_size dynamic_jack_get_buffer_size
cannam@0 182 #define jack_get_sample_rate dynamic_jack_get_sample_rate
cannam@0 183 #define jack_set_process_callback dynamic_jack_set_process_callback
cannam@0 184 #define jack_set_xrun_callback dynamic_jack_set_xrun_callback
cannam@0 185 #define jack_activate dynamic_jack_activate
cannam@0 186 #define jack_deactivate dynamic_jack_deactivate
cannam@0 187 #define jack_client_close dynamic_jack_client_close
cannam@0 188 #define jack_get_ports dynamic_jack_get_ports
cannam@0 189 #define jack_port_register dynamic_jack_port_register
cannam@0 190 #define jack_port_unregister dynamic_jack_port_unregister
cannam@0 191 #define jack_port_get_latency dynamic_jack_port_get_latency
cannam@0 192 #define jack_port_name dynamic_jack_port_name
cannam@0 193 #define jack_connect dynamic_jack_connect
cannam@0 194 #define jack_port_get_buffer dynamic_jack_port_get_buffer
cannam@0 195
cannam@0 196 #endif
cannam@0 197 #endif
cannam@0 198
cannam@0 199 AudioJACKSource::AudioJACKSource(AudioCallbackRecordTarget *target) :
cannam@0 200 AudioCallbackRecordSource(target),
cannam@0 201 m_client(0),
cannam@0 202 m_bufferSize(0),
cannam@0 203 m_sampleRate(0)
cannam@0 204 {
Chris@15 205 JackOptions options = JackNullOption;
Chris@15 206 #ifdef HAVE_PORTAUDIO_2_0
Chris@15 207 options = JackNoStartServer;
Chris@15 208 #endif
Chris@15 209 #ifdef HAVE_LIBPULSE
Chris@15 210 options = JackNoStartServer;
Chris@15 211 #endif
Chris@15 212
Chris@15 213 JackStatus status = JackStatus(0);
Chris@15 214 m_client = jack_client_open("vamp-live-host", options, &status);
cannam@0 215
cannam@0 216 if (!m_client) {
Chris@15 217 std::cerr
Chris@15 218 << "ERROR: AudioJACKSource: Failed to connect to JACK server"
Chris@15 219 << std::endl;
Chris@15 220 return;
cannam@0 221 }
cannam@0 222
cannam@0 223 m_bufferSize = jack_get_buffer_size(m_client);
cannam@0 224 m_sampleRate = jack_get_sample_rate(m_client);
cannam@0 225
cannam@0 226 jack_set_xrun_callback(m_client, xrunStatic, this);
cannam@0 227 jack_set_process_callback(m_client, processStatic, this);
cannam@0 228
cannam@0 229 if (jack_activate(m_client)) {
cannam@0 230 std::cerr << "ERROR: AudioJACKSource: Failed to activate JACK client"
cannam@0 231 << std::endl;
cannam@0 232 }
cannam@0 233
cannam@0 234 m_target->setSourceBlockSize(m_bufferSize);
cannam@0 235 m_target->setSourceSampleRate(m_sampleRate);
cannam@0 236
cannam@0 237 size_t channels = m_target->getChannelCount();
cannam@0 238
cannam@0 239 while (m_inputs.size() < channels) {
cannam@0 240
cannam@0 241 char name[20];
cannam@0 242 jack_port_t *port;
cannam@0 243
Chris@15 244 sprintf(name, "in %d", (int)(m_inputs.size() + 1));
cannam@0 245
cannam@0 246 port = jack_port_register(m_client,
cannam@0 247 name,
cannam@0 248 JACK_DEFAULT_AUDIO_TYPE,
cannam@0 249 JackPortIsInput,
cannam@0 250 0);
cannam@0 251
cannam@0 252 if (!port) {
cannam@0 253 std::cerr
cannam@0 254 << "ERROR: AudioJACKSource: Failed to create JACK input port "
cannam@0 255 << m_inputs.size() << std::endl;
cannam@0 256 } else {
cannam@0 257 m_target->setSourceRecordLatency(jack_port_get_latency(port));
cannam@0 258 }
cannam@0 259
cannam@0 260 m_inputs.push_back(port);
cannam@0 261 }
cannam@0 262 }
cannam@0 263
cannam@0 264 AudioJACKSource::~AudioJACKSource()
cannam@0 265 {
cannam@0 266 if (m_client) {
cannam@0 267 jack_deactivate(m_client);
cannam@0 268 jack_client_close(m_client);
cannam@0 269 }
cannam@0 270 }
cannam@0 271
cannam@0 272 bool
cannam@0 273 AudioJACKSource::isOK() const
cannam@0 274 {
cannam@0 275 return (m_client != 0);
cannam@0 276 }
cannam@0 277
cannam@0 278 int
cannam@0 279 AudioJACKSource::processStatic(jack_nframes_t nframes, void *arg)
cannam@0 280 {
cannam@0 281 return ((AudioJACKSource *)arg)->process(nframes);
cannam@0 282 }
cannam@0 283
cannam@0 284 int
cannam@0 285 AudioJACKSource::xrunStatic(void *arg)
cannam@0 286 {
cannam@0 287 return ((AudioJACKSource *)arg)->xrun();
cannam@0 288 }
cannam@0 289
cannam@0 290 int
cannam@0 291 AudioJACKSource::process(jack_nframes_t nframes)
cannam@0 292 {
cannam@0 293 if (m_inputs.size() < m_target->getChannelCount()) {
cannam@0 294 return 0;
cannam@0 295 }
cannam@0 296
cannam@0 297 #ifdef DEBUG_AUDIO_JACK_SOURCE
cannam@0 298 std::cout << "AudioJACKSource::process(" << nframes << "), have " << m_inputs.size() << " inputs" << std::endl;
cannam@0 299 #endif
cannam@0 300
cannam@0 301 #ifdef DEBUG_AUDIO_JACK_SOURCE
cannam@0 302 if (m_bufferSize != nframes) {
cannam@0 303 std::cerr << "WARNING: m_bufferSize != nframes (" << m_bufferSize << " != " << nframes << ")" << std::endl;
cannam@0 304 }
cannam@0 305 #endif
cannam@0 306
cannam@0 307 float **buffers = (float **)alloca(m_inputs.size() * sizeof(float *));
cannam@0 308
cannam@0 309 for (size_t ch = 0; ch < m_inputs.size(); ++ch) {
cannam@0 310 buffers[ch] = (float *)jack_port_get_buffer(m_inputs[ch], nframes);
cannam@0 311 }
cannam@0 312
cannam@0 313 if (m_target) {
cannam@0 314 m_target->putSamples(nframes, buffers);
cannam@0 315 }
cannam@0 316
cannam@0 317 float peakLeft = 0.0, peakRight = 0.0;
cannam@0 318
cannam@0 319 for (size_t ch = 0; ch < m_inputs.size(); ++ch) {
cannam@0 320
cannam@0 321 float peak = 0.0;
cannam@0 322
cannam@0 323 for (size_t i = 0; i < nframes; ++i) {
cannam@0 324 float sample = fabsf(buffers[ch][i]);
cannam@0 325 if (sample > peak) peak = sample;
cannam@0 326 }
cannam@0 327
cannam@0 328 if (ch == 0) peakLeft = peak;
cannam@0 329 if (ch > 0 || m_inputs.size() == 1) peakRight = peak;
cannam@0 330 }
cannam@0 331
cannam@0 332 if (m_target) {
cannam@0 333 m_target->setInputLevels(peakLeft, peakRight);
cannam@0 334 }
cannam@0 335
cannam@0 336 return 0;
cannam@0 337 }
cannam@0 338
cannam@0 339 int
cannam@0 340 AudioJACKSource::xrun()
cannam@0 341 {
cannam@0 342 std::cerr << "AudioJACKSource: xrun!" << std::endl;
cannam@0 343 if (m_target) m_target->audioProcessingOverload();
cannam@0 344 return 0;
cannam@0 345 }
cannam@0 346
cannam@0 347 #endif /* HAVE_JACK */
cannam@0 348