cubeb_jack.cpp (36974B)
1 /* 2 * Copyright © 2012 David Richards 3 * Copyright © 2013 Sebastien Alaiwan 4 * Copyright © 2016 Damien Zammit 5 * 6 * This program is made available under an ISC-style license. See the 7 * accompanying file LICENSE for details. 8 */ 9 #define _DEFAULT_SOURCE 10 #define _BSD_SOURCE 11 #if !defined(__FreeBSD__) && !defined(__NetBSD__) 12 #define _POSIX_SOURCE 13 #endif 14 #include "cubeb-internal.h" 15 #include "cubeb/cubeb.h" 16 #include "cubeb_resampler.h" 17 #include "cubeb_utils.h" 18 #include <dlfcn.h> 19 #include <limits.h> 20 #include <math.h> 21 #include <pthread.h> 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <string.h> 25 26 #include <jack/jack.h> 27 #include <jack/statistics.h> 28 29 #ifdef DISABLE_LIBJACK_DLOPEN 30 #define WRAP(x) x 31 #else 32 #define WRAP(x) (*api_##x) 33 #define JACK_API_VISIT(X) \ 34 X(jack_activate) \ 35 X(jack_client_close) \ 36 X(jack_client_open) \ 37 X(jack_connect) \ 38 X(jack_free) \ 39 X(jack_get_ports) \ 40 X(jack_get_sample_rate) \ 41 X(jack_get_xrun_delayed_usecs) \ 42 X(jack_get_buffer_size) \ 43 X(jack_port_get_buffer) \ 44 X(jack_port_name) \ 45 X(jack_port_register) \ 46 X(jack_port_unregister) \ 47 X(jack_port_get_latency_range) \ 48 X(jack_set_process_callback) \ 49 X(jack_set_xrun_callback) \ 50 X(jack_set_graph_order_callback) \ 51 X(jack_set_error_function) \ 52 X(jack_set_info_function) 53 54 #define IMPORT_FUNC(x) static decltype(x) * api_##x; 55 JACK_API_VISIT(IMPORT_FUNC); 56 #undef IMPORT_FUNC 57 #endif 58 59 #define JACK_DEFAULT_IN "JACK capture" 60 #define JACK_DEFAULT_OUT "JACK playback" 61 62 static const int MAX_STREAMS = 16; 63 static const int MAX_CHANNELS = 8; 64 static const int FIFO_SIZE = 4096 * sizeof(float); 65 66 enum devstream { 67 NONE = 0, 68 IN_ONLY, 69 OUT_ONLY, 70 DUPLEX, 71 }; 72 73 enum cbjack_connect_ports_options { 74 CBJACK_CP_OPTIONS_NONE = 0x0, 75 CBJACK_CP_OPTIONS_SKIP_OUTPUT = 0x1, 76 CBJACK_CP_OPTIONS_SKIP_INPUT = 0x2, 77 }; 78 79 static void 80 s16ne_to_float(float * dst, const int16_t * src, size_t n) 81 { 82 for (size_t i = 0; i < n; i++) 83 *(dst++) = (float)((float)*(src++) / 32767.0f); 84 } 85 86 static void 87 float_to_s16ne(int16_t * dst, float * src, size_t n) 88 { 89 for (size_t i = 0; i < n; i++) { 90 if (*src > 1.f) 91 *src = 1.f; 92 if (*src < -1.f) 93 *src = -1.f; 94 *(dst++) = (int16_t)((int16_t)(*(src++) * 32767)); 95 } 96 } 97 98 extern "C" { 99 /*static*/ int 100 jack_init(cubeb ** context, char const * context_name); 101 } 102 static char const * 103 cbjack_get_backend_id(cubeb * context); 104 static int 105 cbjack_get_max_channel_count(cubeb * ctx, uint32_t * max_channels); 106 static int 107 cbjack_get_min_latency(cubeb * ctx, cubeb_stream_params params, 108 uint32_t * latency_frames); 109 static int 110 cbjack_get_latency(cubeb_stream * stm, unsigned int * latency_frames); 111 static int 112 cbjack_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate); 113 static void 114 cbjack_destroy(cubeb * context); 115 static void 116 cbjack_interleave_capture(cubeb_stream * stream, float ** in, 117 jack_nframes_t nframes, bool format_mismatch); 118 static void 119 cbjack_deinterleave_playback_refill_s16ne(cubeb_stream * stream, 120 short ** bufs_in, float ** bufs_out, 121 jack_nframes_t nframes); 122 static void 123 cbjack_deinterleave_playback_refill_float(cubeb_stream * stream, 124 float ** bufs_in, float ** bufs_out, 125 jack_nframes_t nframes); 126 static int 127 cbjack_stream_device_destroy(cubeb_stream * stream, cubeb_device * device); 128 static int 129 cbjack_stream_get_current_device(cubeb_stream * stm, 130 cubeb_device ** const device); 131 static int 132 cbjack_enumerate_devices(cubeb * context, cubeb_device_type type, 133 cubeb_device_collection * collection); 134 static int 135 cbjack_device_collection_destroy(cubeb * context, 136 cubeb_device_collection * collection); 137 static int 138 cbjack_stream_init(cubeb * context, cubeb_stream ** stream, 139 char const * stream_name, cubeb_devid input_device, 140 cubeb_stream_params * input_stream_params, 141 cubeb_devid output_device, 142 cubeb_stream_params * output_stream_params, 143 unsigned int latency_frames, 144 cubeb_data_callback data_callback, 145 cubeb_state_callback state_callback, void * user_ptr); 146 static void 147 cbjack_stream_destroy(cubeb_stream * stream); 148 static int 149 cbjack_stream_start(cubeb_stream * stream); 150 static int 151 cbjack_stream_stop(cubeb_stream * stream); 152 static int 153 cbjack_stream_get_position(cubeb_stream * stream, uint64_t * position); 154 static int 155 cbjack_stream_set_volume(cubeb_stream * stm, float volume); 156 157 static struct cubeb_ops const cbjack_ops = { 158 .init = jack_init, 159 .get_backend_id = cbjack_get_backend_id, 160 .get_max_channel_count = cbjack_get_max_channel_count, 161 .get_min_latency = cbjack_get_min_latency, 162 .get_preferred_sample_rate = cbjack_get_preferred_sample_rate, 163 .get_supported_input_processing_params = NULL, 164 .enumerate_devices = cbjack_enumerate_devices, 165 .device_collection_destroy = cbjack_device_collection_destroy, 166 .destroy = cbjack_destroy, 167 .stream_init = cbjack_stream_init, 168 .stream_destroy = cbjack_stream_destroy, 169 .stream_start = cbjack_stream_start, 170 .stream_stop = cbjack_stream_stop, 171 .stream_get_position = cbjack_stream_get_position, 172 .stream_get_latency = cbjack_get_latency, 173 .stream_get_input_latency = NULL, 174 .stream_set_volume = cbjack_stream_set_volume, 175 .stream_set_name = NULL, 176 .stream_get_current_device = cbjack_stream_get_current_device, 177 .stream_set_input_mute = NULL, 178 .stream_set_input_processing_params = NULL, 179 .stream_device_destroy = cbjack_stream_device_destroy, 180 .stream_register_device_changed_callback = NULL, 181 .register_device_collection_changed = NULL}; 182 183 struct cubeb_stream { 184 /* Note: Must match cubeb_stream layout in cubeb.c. */ 185 cubeb * context; 186 void * user_ptr; 187 /**/ 188 189 /**< Mutex for each stream */ 190 pthread_mutex_t mutex; 191 192 bool in_use; /**< Set to false iff the stream is free */ 193 bool ports_ready; /**< Set to true iff the JACK ports are ready */ 194 195 cubeb_data_callback data_callback; 196 cubeb_state_callback state_callback; 197 cubeb_stream_params in_params; 198 cubeb_stream_params out_params; 199 200 cubeb_resampler * resampler; 201 202 uint64_t position; 203 bool pause; 204 float ratio; 205 enum devstream devs; 206 char stream_name[256]; 207 jack_port_t * output_ports[MAX_CHANNELS]; 208 jack_port_t * input_ports[MAX_CHANNELS]; 209 float volume; 210 }; 211 212 struct cubeb { 213 struct cubeb_ops const * ops; 214 void * libjack; 215 216 /**< Mutex for whole context */ 217 pthread_mutex_t mutex; 218 219 /**< Audio buffers, converted to float */ 220 float in_float_interleaved_buffer[FIFO_SIZE * MAX_CHANNELS]; 221 float out_float_interleaved_buffer[FIFO_SIZE * MAX_CHANNELS]; 222 223 /**< Audio buffer, at the sampling rate of the output */ 224 float in_resampled_interleaved_buffer_float[FIFO_SIZE * MAX_CHANNELS * 3]; 225 int16_t in_resampled_interleaved_buffer_s16ne[FIFO_SIZE * MAX_CHANNELS * 3]; 226 float out_resampled_interleaved_buffer_float[FIFO_SIZE * MAX_CHANNELS * 3]; 227 int16_t out_resampled_interleaved_buffer_s16ne[FIFO_SIZE * MAX_CHANNELS * 3]; 228 229 cubeb_stream streams[MAX_STREAMS]; 230 unsigned int active_streams; 231 232 cubeb_device_collection_changed_callback collection_changed_callback; 233 234 bool active; 235 unsigned int jack_sample_rate; 236 unsigned int jack_latency; 237 unsigned int jack_xruns; 238 unsigned int jack_buffer_size; 239 unsigned int fragment_size; 240 unsigned int output_bytes_per_frame; 241 jack_client_t * jack_client; 242 }; 243 244 static int 245 load_jack_lib(cubeb * context) 246 { 247 #ifndef DISABLE_LIBJACK_DLOPEN 248 #ifdef __APPLE__ 249 context->libjack = dlopen("libjack.0.dylib", RTLD_LAZY); 250 context->libjack = dlopen("/usr/local/lib/libjack.0.dylib", RTLD_LAZY); 251 #elif defined(__WIN32__) 252 #ifdef _WIN64 253 context->libjack = LoadLibrary("libjack64.dll"); 254 #else 255 context->libjack = LoadLibrary("libjack.dll"); 256 #endif 257 #else 258 context->libjack = dlopen("libjack.so.0", RTLD_LAZY); 259 if (!context->libjack) { 260 context->libjack = dlopen("libjack.so", RTLD_LAZY); 261 } 262 #endif 263 if (!context->libjack) { 264 return CUBEB_ERROR; 265 } 266 267 #define LOAD(x) \ 268 { \ 269 api_##x = (decltype(x) *)dlsym(context->libjack, #x); \ 270 if (!api_##x) { \ 271 dlclose(context->libjack); \ 272 return CUBEB_ERROR; \ 273 } \ 274 } 275 276 JACK_API_VISIT(LOAD); 277 #undef LOAD 278 #endif 279 return CUBEB_OK; 280 } 281 282 static void 283 cbjack_connect_port_out(cubeb_stream * stream, const size_t out_port, 284 const char * const phys_in_port) 285 { 286 const char * src_port = WRAP(jack_port_name)(stream->output_ports[out_port]); 287 288 WRAP(jack_connect)(stream->context->jack_client, src_port, phys_in_port); 289 } 290 291 static void 292 cbjack_connect_port_in(cubeb_stream * stream, const char * const phys_out_port, 293 size_t in_port) 294 { 295 const char * src_port = WRAP(jack_port_name)(stream->input_ports[in_port]); 296 297 WRAP(jack_connect)(stream->context->jack_client, phys_out_port, src_port); 298 } 299 300 static int 301 cbjack_connect_ports(cubeb_stream * stream, 302 enum cbjack_connect_ports_options options) 303 { 304 int r = CUBEB_ERROR; 305 const char ** phys_in_ports = 306 WRAP(jack_get_ports)(stream->context->jack_client, NULL, NULL, 307 JackPortIsInput | JackPortIsPhysical); 308 const char ** phys_out_ports = 309 WRAP(jack_get_ports)(stream->context->jack_client, NULL, NULL, 310 JackPortIsOutput | JackPortIsPhysical); 311 312 if (phys_in_ports == NULL || *phys_in_ports == NULL || 313 options & CBJACK_CP_OPTIONS_SKIP_OUTPUT) { 314 goto skipplayback; 315 } 316 317 // Connect outputs to playback 318 for (unsigned int c = 0; 319 c < stream->out_params.channels && phys_in_ports[c] != NULL; c++) { 320 cbjack_connect_port_out(stream, c, phys_in_ports[c]); 321 } 322 323 // Special case playing mono source in stereo 324 if (stream->out_params.channels == 1 && phys_in_ports[1] != NULL) { 325 cbjack_connect_port_out(stream, 0, phys_in_ports[1]); 326 } 327 328 r = CUBEB_OK; 329 330 skipplayback: 331 if (phys_out_ports == NULL || *phys_out_ports == NULL || 332 options & CBJACK_CP_OPTIONS_SKIP_INPUT) { 333 goto end; 334 } 335 // Connect inputs to capture 336 for (unsigned int c = 0; 337 c < stream->in_params.channels && phys_out_ports[c] != NULL; c++) { 338 cbjack_connect_port_in(stream, phys_out_ports[c], c); 339 } 340 r = CUBEB_OK; 341 end: 342 if (phys_out_ports) { 343 WRAP(jack_free)(phys_out_ports); 344 } 345 if (phys_in_ports) { 346 WRAP(jack_free)(phys_in_ports); 347 } 348 return r; 349 } 350 351 static int 352 cbjack_xrun_callback(void * arg) 353 { 354 cubeb * ctx = (cubeb *)arg; 355 356 float delay = WRAP(jack_get_xrun_delayed_usecs)(ctx->jack_client); 357 float fragments = ceilf(((delay / 1000000.0) * ctx->jack_sample_rate) / 358 ctx->jack_buffer_size); 359 360 ctx->jack_xruns += (unsigned int)fragments; 361 return 0; 362 } 363 364 static int 365 cbjack_graph_order_callback(void * arg) 366 { 367 cubeb * ctx = (cubeb *)arg; 368 int i; 369 jack_latency_range_t latency_range; 370 jack_nframes_t port_latency, max_latency = 0; 371 372 for (int j = 0; j < MAX_STREAMS; j++) { 373 cubeb_stream * stm = &ctx->streams[j]; 374 375 if (!stm->in_use) 376 continue; 377 if (!stm->ports_ready) 378 continue; 379 380 for (i = 0; i < (int)stm->out_params.channels; ++i) { 381 WRAP(jack_port_get_latency_range) 382 (stm->output_ports[i], JackPlaybackLatency, &latency_range); 383 port_latency = latency_range.max; 384 if (port_latency > max_latency) 385 max_latency = port_latency; 386 } 387 /* Cap minimum latency to 128 frames */ 388 if (max_latency < 128) 389 max_latency = 128; 390 } 391 392 ctx->jack_latency = max_latency; 393 394 return 0; 395 } 396 397 static int 398 cbjack_process(jack_nframes_t nframes, void * arg) 399 { 400 cubeb * ctx = (cubeb *)arg; 401 unsigned int t_jack_xruns = ctx->jack_xruns; 402 int i; 403 404 ctx->jack_xruns = 0; 405 406 for (int j = 0; j < MAX_STREAMS; j++) { 407 cubeb_stream * stm = &ctx->streams[j]; 408 float * bufs_out[stm->out_params.channels]; 409 float * bufs_in[stm->in_params.channels]; 410 411 if (!stm->in_use) 412 continue; 413 414 // handle xruns by skipping audio that should have been played 415 stm->position += t_jack_xruns * ctx->fragment_size * stm->ratio; 416 417 if (!stm->ports_ready) 418 continue; 419 420 if (stm->devs & OUT_ONLY) { 421 // get jack output buffers 422 for (i = 0; i < (int)stm->out_params.channels; i++) 423 bufs_out[i] = 424 (float *)WRAP(jack_port_get_buffer)(stm->output_ports[i], nframes); 425 } 426 if (stm->devs & IN_ONLY) { 427 // get jack input buffers 428 for (i = 0; i < (int)stm->in_params.channels; i++) 429 bufs_in[i] = 430 (float *)WRAP(jack_port_get_buffer)(stm->input_ports[i], nframes); 431 } 432 if (stm->pause) { 433 // paused, play silence on output 434 if (stm->devs & OUT_ONLY) { 435 for (unsigned int c = 0; c < stm->out_params.channels; c++) { 436 float * buffer_out = bufs_out[c]; 437 if (buffer_out) { 438 for (long f = 0; f < nframes; f++) { 439 buffer_out[f] = 0.f; 440 } 441 } 442 } 443 } 444 if (stm->devs & IN_ONLY) { 445 // paused, capture silence 446 for (unsigned int c = 0; c < stm->in_params.channels; c++) { 447 float * buffer_in = bufs_in[c]; 448 if (buffer_in) { 449 for (long f = 0; f < nframes; f++) { 450 buffer_in[f] = 0.f; 451 } 452 } 453 } 454 } 455 } else { 456 457 // try to lock stream mutex 458 if (pthread_mutex_trylock(&stm->mutex) == 0) { 459 460 int16_t * in_s16ne = 461 stm->context->in_resampled_interleaved_buffer_s16ne; 462 float * in_float = stm->context->in_resampled_interleaved_buffer_float; 463 464 // unpaused, play audio 465 if (stm->devs == DUPLEX) { 466 if (stm->out_params.format == CUBEB_SAMPLE_S16NE) { 467 cbjack_interleave_capture(stm, bufs_in, nframes, true); 468 cbjack_deinterleave_playback_refill_s16ne(stm, &in_s16ne, bufs_out, 469 nframes); 470 } else if (stm->out_params.format == CUBEB_SAMPLE_FLOAT32NE) { 471 cbjack_interleave_capture(stm, bufs_in, nframes, false); 472 cbjack_deinterleave_playback_refill_float(stm, &in_float, bufs_out, 473 nframes); 474 } 475 } else if (stm->devs == IN_ONLY) { 476 if (stm->in_params.format == CUBEB_SAMPLE_S16NE) { 477 cbjack_interleave_capture(stm, bufs_in, nframes, true); 478 cbjack_deinterleave_playback_refill_s16ne(stm, &in_s16ne, nullptr, 479 nframes); 480 } else if (stm->in_params.format == CUBEB_SAMPLE_FLOAT32NE) { 481 cbjack_interleave_capture(stm, bufs_in, nframes, false); 482 cbjack_deinterleave_playback_refill_float(stm, &in_float, nullptr, 483 nframes); 484 } 485 } else if (stm->devs == OUT_ONLY) { 486 if (stm->out_params.format == CUBEB_SAMPLE_S16NE) { 487 cbjack_deinterleave_playback_refill_s16ne(stm, nullptr, bufs_out, 488 nframes); 489 } else if (stm->out_params.format == CUBEB_SAMPLE_FLOAT32NE) { 490 cbjack_deinterleave_playback_refill_float(stm, nullptr, bufs_out, 491 nframes); 492 } 493 } 494 // unlock stream mutex 495 pthread_mutex_unlock(&stm->mutex); 496 497 } else { 498 // could not lock mutex 499 // output silence 500 if (stm->devs & OUT_ONLY) { 501 for (unsigned int c = 0; c < stm->out_params.channels; c++) { 502 float * buffer_out = bufs_out[c]; 503 if (buffer_out) { 504 for (long f = 0; f < nframes; f++) { 505 buffer_out[f] = 0.f; 506 } 507 } 508 } 509 } 510 if (stm->devs & IN_ONLY) { 511 // capture silence 512 for (unsigned int c = 0; c < stm->in_params.channels; c++) { 513 float * buffer_in = bufs_in[c]; 514 if (buffer_in) { 515 for (long f = 0; f < nframes; f++) { 516 buffer_in[f] = 0.f; 517 } 518 } 519 } 520 } 521 } 522 } 523 } 524 return 0; 525 } 526 527 static void 528 cbjack_deinterleave_playback_refill_float(cubeb_stream * stream, float ** in, 529 float ** bufs_out, 530 jack_nframes_t nframes) 531 { 532 float * out_interleaved_buffer = nullptr; 533 534 float * inptr = (in != NULL) ? *in : nullptr; 535 float * outptr = (bufs_out != NULL) ? *bufs_out : nullptr; 536 537 long needed_frames = (bufs_out != NULL) ? nframes : 0; 538 long done_frames = 0; 539 long input_frames_count = (in != NULL) ? nframes : 0; 540 541 done_frames = cubeb_resampler_fill( 542 stream->resampler, inptr, &input_frames_count, 543 (bufs_out != NULL) 544 ? stream->context->out_resampled_interleaved_buffer_float 545 : NULL, 546 needed_frames); 547 548 out_interleaved_buffer = 549 stream->context->out_resampled_interleaved_buffer_float; 550 551 if (outptr) { 552 // convert interleaved output buffers to contiguous buffers 553 for (unsigned int c = 0; c < stream->out_params.channels; c++) { 554 float * buffer = bufs_out[c]; 555 for (long f = 0; f < done_frames; f++) { 556 if (buffer) { 557 buffer[f] = 558 out_interleaved_buffer[(f * stream->out_params.channels) + c] * 559 stream->volume; 560 } 561 } 562 if (done_frames < needed_frames) { 563 // draining 564 for (long f = done_frames; f < needed_frames; f++) { 565 if (buffer) { 566 buffer[f] = 0.f; 567 } 568 } 569 } 570 if (done_frames == 0) { 571 // stop, but first zero out the existing buffer 572 for (long f = 0; f < needed_frames; f++) { 573 if (buffer) { 574 buffer[f] = 0.f; 575 } 576 } 577 } 578 } 579 } 580 581 if (done_frames >= 0 && done_frames < needed_frames) { 582 // set drained 583 stream->state_callback(stream, stream->user_ptr, CUBEB_STATE_DRAINED); 584 // stop stream 585 cbjack_stream_stop(stream); 586 } 587 if (done_frames > 0 && done_frames <= needed_frames) { 588 // advance stream position 589 stream->position += done_frames * stream->ratio; 590 } 591 if (done_frames < 0 || done_frames > needed_frames) { 592 // stream error 593 stream->state_callback(stream, stream->user_ptr, CUBEB_STATE_ERROR); 594 } 595 } 596 597 static void 598 cbjack_deinterleave_playback_refill_s16ne(cubeb_stream * stream, short ** in, 599 float ** bufs_out, 600 jack_nframes_t nframes) 601 { 602 float * out_interleaved_buffer = nullptr; 603 604 short * inptr = (in != NULL) ? *in : nullptr; 605 float * outptr = (bufs_out != NULL) ? *bufs_out : nullptr; 606 607 long needed_frames = (bufs_out != NULL) ? nframes : 0; 608 long done_frames = 0; 609 long input_frames_count = (in != NULL) ? nframes : 0; 610 611 done_frames = cubeb_resampler_fill( 612 stream->resampler, inptr, &input_frames_count, 613 (bufs_out != NULL) 614 ? stream->context->out_resampled_interleaved_buffer_s16ne 615 : NULL, 616 needed_frames); 617 618 s16ne_to_float(stream->context->out_resampled_interleaved_buffer_float, 619 stream->context->out_resampled_interleaved_buffer_s16ne, 620 done_frames * stream->out_params.channels); 621 622 out_interleaved_buffer = 623 stream->context->out_resampled_interleaved_buffer_float; 624 625 if (outptr) { 626 // convert interleaved output buffers to contiguous buffers 627 for (unsigned int c = 0; c < stream->out_params.channels; c++) { 628 float * buffer = bufs_out[c]; 629 for (long f = 0; f < done_frames; f++) { 630 buffer[f] = 631 out_interleaved_buffer[(f * stream->out_params.channels) + c] * 632 stream->volume; 633 } 634 if (done_frames < needed_frames) { 635 // draining 636 for (long f = done_frames; f < needed_frames; f++) { 637 buffer[f] = 0.f; 638 } 639 } 640 if (done_frames == 0) { 641 // stop, but first zero out the existing buffer 642 for (long f = 0; f < needed_frames; f++) { 643 buffer[f] = 0.f; 644 } 645 } 646 } 647 } 648 649 if (done_frames >= 0 && done_frames < needed_frames) { 650 // set drained 651 stream->state_callback(stream, stream->user_ptr, CUBEB_STATE_DRAINED); 652 // stop stream 653 cbjack_stream_stop(stream); 654 } 655 if (done_frames > 0 && done_frames <= needed_frames) { 656 // advance stream position 657 stream->position += done_frames * stream->ratio; 658 } 659 if (done_frames < 0 || done_frames > needed_frames) { 660 // stream error 661 stream->state_callback(stream, stream->user_ptr, CUBEB_STATE_ERROR); 662 } 663 } 664 665 static void 666 cbjack_interleave_capture(cubeb_stream * stream, float ** in, 667 jack_nframes_t nframes, bool format_mismatch) 668 { 669 float * in_buffer = stream->context->in_float_interleaved_buffer; 670 671 for (unsigned int c = 0; c < stream->in_params.channels; c++) { 672 for (long f = 0; f < nframes; f++) { 673 in_buffer[(f * stream->in_params.channels) + c] = 674 in[c][f] * stream->volume; 675 } 676 } 677 if (format_mismatch) { 678 float_to_s16ne(stream->context->in_resampled_interleaved_buffer_s16ne, 679 in_buffer, nframes * stream->in_params.channels); 680 } else { 681 memset(stream->context->in_resampled_interleaved_buffer_float, 0, 682 (FIFO_SIZE * MAX_CHANNELS * 3) * sizeof(float)); 683 memcpy(stream->context->in_resampled_interleaved_buffer_float, in_buffer, 684 (FIFO_SIZE * MAX_CHANNELS * 2) * sizeof(float)); 685 } 686 } 687 688 static void 689 silent_jack_error_callback(char const * /*msg*/) 690 { 691 } 692 693 /*static*/ int 694 jack_init(cubeb ** context, char const * context_name) 695 { 696 int r; 697 698 *context = NULL; 699 700 cubeb * ctx = (cubeb *)calloc(1, sizeof(*ctx)); 701 if (ctx == NULL) { 702 return CUBEB_ERROR; 703 } 704 705 r = load_jack_lib(ctx); 706 if (r != 0) { 707 cbjack_destroy(ctx); 708 return CUBEB_ERROR; 709 } 710 711 WRAP(jack_set_error_function)(silent_jack_error_callback); 712 WRAP(jack_set_info_function)(silent_jack_error_callback); 713 714 ctx->ops = &cbjack_ops; 715 716 ctx->mutex = PTHREAD_MUTEX_INITIALIZER; 717 for (r = 0; r < MAX_STREAMS; r++) { 718 ctx->streams[r].mutex = PTHREAD_MUTEX_INITIALIZER; 719 } 720 721 const char * jack_client_name = "cubeb"; 722 if (context_name) 723 jack_client_name = context_name; 724 725 ctx->jack_client = 726 WRAP(jack_client_open)(jack_client_name, JackNoStartServer, NULL); 727 728 if (ctx->jack_client == NULL) { 729 cbjack_destroy(ctx); 730 return CUBEB_ERROR; 731 } 732 733 ctx->jack_xruns = 0; 734 735 WRAP(jack_set_process_callback)(ctx->jack_client, cbjack_process, ctx); 736 WRAP(jack_set_xrun_callback)(ctx->jack_client, cbjack_xrun_callback, ctx); 737 WRAP(jack_set_graph_order_callback) 738 (ctx->jack_client, cbjack_graph_order_callback, ctx); 739 740 if (WRAP(jack_activate)(ctx->jack_client)) { 741 cbjack_destroy(ctx); 742 return CUBEB_ERROR; 743 } 744 745 ctx->jack_sample_rate = WRAP(jack_get_sample_rate)(ctx->jack_client); 746 ctx->jack_latency = 128 * 1000 / ctx->jack_sample_rate; 747 748 ctx->active = true; 749 *context = ctx; 750 751 return CUBEB_OK; 752 } 753 754 static char const * 755 cbjack_get_backend_id(cubeb * /*context*/) 756 { 757 return "jack"; 758 } 759 760 static int 761 cbjack_get_max_channel_count(cubeb * /*ctx*/, uint32_t * max_channels) 762 { 763 *max_channels = MAX_CHANNELS; 764 return CUBEB_OK; 765 } 766 767 static int 768 cbjack_get_latency(cubeb_stream * stm, unsigned int * latency_ms) 769 { 770 *latency_ms = stm->context->jack_latency; 771 return CUBEB_OK; 772 } 773 774 static int 775 cbjack_get_min_latency(cubeb * ctx, cubeb_stream_params /*params*/, 776 uint32_t * latency_ms) 777 { 778 *latency_ms = ctx->jack_latency; 779 return CUBEB_OK; 780 } 781 782 static int 783 cbjack_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate) 784 { 785 if (!ctx->jack_client) { 786 jack_client_t * testclient = 787 WRAP(jack_client_open)("test-samplerate", JackNoStartServer, NULL); 788 if (!testclient) { 789 return CUBEB_ERROR; 790 } 791 792 *rate = WRAP(jack_get_sample_rate)(testclient); 793 WRAP(jack_client_close)(testclient); 794 795 } else { 796 *rate = WRAP(jack_get_sample_rate)(ctx->jack_client); 797 } 798 return CUBEB_OK; 799 } 800 801 static void 802 cbjack_destroy(cubeb * context) 803 { 804 context->active = false; 805 806 if (context->jack_client != NULL) 807 WRAP(jack_client_close)(context->jack_client); 808 #ifndef DISABLE_LIBJACK_DLOPEN 809 if (context->libjack) 810 dlclose(context->libjack); 811 #endif 812 free(context); 813 } 814 815 static cubeb_stream * 816 context_alloc_stream(cubeb * context, char const * stream_name) 817 { 818 for (int i = 0; i < MAX_STREAMS; i++) { 819 if (!context->streams[i].in_use) { 820 cubeb_stream * stm = &context->streams[i]; 821 stm->in_use = true; 822 snprintf(stm->stream_name, 255, "%s_%u", stream_name, i); 823 return stm; 824 } 825 } 826 return NULL; 827 } 828 829 static int 830 cbjack_stream_init(cubeb * context, cubeb_stream ** stream, 831 char const * stream_name, cubeb_devid input_device, 832 cubeb_stream_params * input_stream_params, 833 cubeb_devid output_device, 834 cubeb_stream_params * output_stream_params, 835 unsigned int /*latency_frames*/, 836 cubeb_data_callback data_callback, 837 cubeb_state_callback state_callback, void * user_ptr) 838 { 839 int stream_actual_rate = 0; 840 int jack_rate = WRAP(jack_get_sample_rate)(context->jack_client); 841 842 if (output_stream_params && 843 (output_stream_params->format != CUBEB_SAMPLE_FLOAT32NE && 844 output_stream_params->format != CUBEB_SAMPLE_S16NE)) { 845 return CUBEB_ERROR_INVALID_FORMAT; 846 } 847 848 if (input_stream_params && 849 (input_stream_params->format != CUBEB_SAMPLE_FLOAT32NE && 850 input_stream_params->format != CUBEB_SAMPLE_S16NE)) { 851 return CUBEB_ERROR_INVALID_FORMAT; 852 } 853 854 if ((input_device && input_device != JACK_DEFAULT_IN) || 855 (output_device && output_device != JACK_DEFAULT_OUT)) { 856 return CUBEB_ERROR_NOT_SUPPORTED; 857 } 858 859 // Loopback is unsupported 860 if ((input_stream_params && 861 (input_stream_params->prefs & CUBEB_STREAM_PREF_LOOPBACK)) || 862 (output_stream_params && 863 (output_stream_params->prefs & CUBEB_STREAM_PREF_LOOPBACK))) { 864 return CUBEB_ERROR_NOT_SUPPORTED; 865 } 866 867 *stream = NULL; 868 869 // Find a free stream. 870 pthread_mutex_lock(&context->mutex); 871 cubeb_stream * stm = context_alloc_stream(context, stream_name); 872 873 // No free stream? 874 if (stm == NULL) { 875 pthread_mutex_unlock(&context->mutex); 876 return CUBEB_ERROR; 877 } 878 879 // unlock context mutex 880 pthread_mutex_unlock(&context->mutex); 881 882 // Lock active stream 883 pthread_mutex_lock(&stm->mutex); 884 885 stm->ports_ready = false; 886 stm->user_ptr = user_ptr; 887 stm->context = context; 888 stm->devs = NONE; 889 if (output_stream_params && !input_stream_params) { 890 stm->out_params = *output_stream_params; 891 stream_actual_rate = stm->out_params.rate; 892 stm->out_params.rate = jack_rate; 893 stm->devs = OUT_ONLY; 894 if (stm->out_params.format == CUBEB_SAMPLE_FLOAT32NE) { 895 context->output_bytes_per_frame = sizeof(float); 896 } else { 897 context->output_bytes_per_frame = sizeof(short); 898 } 899 } 900 if (input_stream_params && output_stream_params) { 901 stm->in_params = *input_stream_params; 902 stm->out_params = *output_stream_params; 903 stream_actual_rate = stm->out_params.rate; 904 stm->in_params.rate = jack_rate; 905 stm->out_params.rate = jack_rate; 906 stm->devs = DUPLEX; 907 if (stm->out_params.format == CUBEB_SAMPLE_FLOAT32NE) { 908 context->output_bytes_per_frame = sizeof(float); 909 stm->in_params.format = CUBEB_SAMPLE_FLOAT32NE; 910 } else { 911 context->output_bytes_per_frame = sizeof(short); 912 stm->in_params.format = CUBEB_SAMPLE_S16NE; 913 } 914 } else if (input_stream_params && !output_stream_params) { 915 stm->in_params = *input_stream_params; 916 stream_actual_rate = stm->in_params.rate; 917 stm->in_params.rate = jack_rate; 918 stm->devs = IN_ONLY; 919 if (stm->in_params.format == CUBEB_SAMPLE_FLOAT32NE) { 920 context->output_bytes_per_frame = sizeof(float); 921 } else { 922 context->output_bytes_per_frame = sizeof(short); 923 } 924 } 925 926 stm->ratio = (float)stream_actual_rate / (float)jack_rate; 927 928 stm->data_callback = data_callback; 929 stm->state_callback = state_callback; 930 stm->position = 0; 931 stm->volume = 1.0f; 932 context->jack_buffer_size = WRAP(jack_get_buffer_size)(context->jack_client); 933 context->fragment_size = context->jack_buffer_size; 934 935 if (stm->devs == NONE) { 936 pthread_mutex_unlock(&stm->mutex); 937 return CUBEB_ERROR; 938 } 939 940 stm->resampler = NULL; 941 942 if (stm->devs == DUPLEX) { 943 stm->resampler = cubeb_resampler_create( 944 stm, &stm->in_params, &stm->out_params, stream_actual_rate, 945 stm->data_callback, stm->user_ptr, CUBEB_RESAMPLER_QUALITY_DESKTOP, 946 CUBEB_RESAMPLER_RECLOCK_NONE); 947 } else if (stm->devs == IN_ONLY) { 948 stm->resampler = cubeb_resampler_create( 949 stm, &stm->in_params, nullptr, stream_actual_rate, stm->data_callback, 950 stm->user_ptr, CUBEB_RESAMPLER_QUALITY_DESKTOP, 951 CUBEB_RESAMPLER_RECLOCK_NONE); 952 } else if (stm->devs == OUT_ONLY) { 953 stm->resampler = cubeb_resampler_create( 954 stm, nullptr, &stm->out_params, stream_actual_rate, stm->data_callback, 955 stm->user_ptr, CUBEB_RESAMPLER_QUALITY_DESKTOP, 956 CUBEB_RESAMPLER_RECLOCK_NONE); 957 } 958 959 if (!stm->resampler) { 960 stm->in_use = false; 961 pthread_mutex_unlock(&stm->mutex); 962 return CUBEB_ERROR; 963 } 964 965 if (stm->devs == DUPLEX || stm->devs == OUT_ONLY) { 966 for (unsigned int c = 0; c < stm->out_params.channels; c++) { 967 char portname[256]; 968 snprintf(portname, 255, "%s_out_%d", stm->stream_name, c); 969 stm->output_ports[c] = WRAP(jack_port_register)( 970 stm->context->jack_client, portname, JACK_DEFAULT_AUDIO_TYPE, 971 JackPortIsOutput, 0); 972 if (!(output_stream_params->prefs & 973 CUBEB_STREAM_PREF_JACK_NO_AUTO_CONNECT)) { 974 if (cbjack_connect_ports(stm, CBJACK_CP_OPTIONS_SKIP_INPUT) != 975 CUBEB_OK) { 976 pthread_mutex_unlock(&stm->mutex); 977 cbjack_stream_destroy(stm); 978 return CUBEB_ERROR; 979 } 980 } 981 } 982 } 983 984 if (stm->devs == DUPLEX || stm->devs == IN_ONLY) { 985 for (unsigned int c = 0; c < stm->in_params.channels; c++) { 986 char portname[256]; 987 snprintf(portname, 255, "%s_in_%d", stm->stream_name, c); 988 stm->input_ports[c] = 989 WRAP(jack_port_register)(stm->context->jack_client, portname, 990 JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); 991 if (!(input_stream_params->prefs & 992 CUBEB_STREAM_PREF_JACK_NO_AUTO_CONNECT)) { 993 if (cbjack_connect_ports(stm, CBJACK_CP_OPTIONS_SKIP_OUTPUT) != 994 CUBEB_OK) { 995 pthread_mutex_unlock(&stm->mutex); 996 cbjack_stream_destroy(stm); 997 return CUBEB_ERROR; 998 } 999 } 1000 } 1001 } 1002 1003 *stream = stm; 1004 1005 stm->ports_ready = true; 1006 stm->pause = true; 1007 pthread_mutex_unlock(&stm->mutex); 1008 1009 return CUBEB_OK; 1010 } 1011 1012 static void 1013 cbjack_stream_destroy(cubeb_stream * stream) 1014 { 1015 pthread_mutex_lock(&stream->mutex); 1016 stream->ports_ready = false; 1017 1018 if (stream->devs == DUPLEX || stream->devs == OUT_ONLY) { 1019 for (unsigned int c = 0; c < stream->out_params.channels; c++) { 1020 if (stream->output_ports[c]) { 1021 WRAP(jack_port_unregister) 1022 (stream->context->jack_client, stream->output_ports[c]); 1023 stream->output_ports[c] = NULL; 1024 } 1025 } 1026 } 1027 1028 if (stream->devs == DUPLEX || stream->devs == IN_ONLY) { 1029 for (unsigned int c = 0; c < stream->in_params.channels; c++) { 1030 if (stream->input_ports[c]) { 1031 WRAP(jack_port_unregister) 1032 (stream->context->jack_client, stream->input_ports[c]); 1033 stream->input_ports[c] = NULL; 1034 } 1035 } 1036 } 1037 1038 if (stream->resampler) { 1039 cubeb_resampler_destroy(stream->resampler); 1040 stream->resampler = NULL; 1041 } 1042 stream->in_use = false; 1043 pthread_mutex_unlock(&stream->mutex); 1044 } 1045 1046 static int 1047 cbjack_stream_start(cubeb_stream * stream) 1048 { 1049 stream->pause = false; 1050 stream->state_callback(stream, stream->user_ptr, CUBEB_STATE_STARTED); 1051 return CUBEB_OK; 1052 } 1053 1054 static int 1055 cbjack_stream_stop(cubeb_stream * stream) 1056 { 1057 stream->pause = true; 1058 stream->state_callback(stream, stream->user_ptr, CUBEB_STATE_STOPPED); 1059 return CUBEB_OK; 1060 } 1061 1062 static int 1063 cbjack_stream_get_position(cubeb_stream * stream, uint64_t * position) 1064 { 1065 *position = stream->position; 1066 return CUBEB_OK; 1067 } 1068 1069 static int 1070 cbjack_stream_set_volume(cubeb_stream * stm, float volume) 1071 { 1072 stm->volume = volume; 1073 return CUBEB_OK; 1074 } 1075 1076 static int 1077 cbjack_stream_get_current_device(cubeb_stream * stm, 1078 cubeb_device ** const device) 1079 { 1080 *device = (cubeb_device *)calloc(1, sizeof(cubeb_device)); 1081 if (*device == NULL) 1082 return CUBEB_ERROR; 1083 1084 const char * j_in = JACK_DEFAULT_IN; 1085 const char * j_out = JACK_DEFAULT_OUT; 1086 const char * empty = ""; 1087 1088 if (stm->devs == DUPLEX) { 1089 (*device)->input_name = strdup(j_in); 1090 (*device)->output_name = strdup(j_out); 1091 } else if (stm->devs == IN_ONLY) { 1092 (*device)->input_name = strdup(j_in); 1093 (*device)->output_name = strdup(empty); 1094 } else if (stm->devs == OUT_ONLY) { 1095 (*device)->input_name = strdup(empty); 1096 (*device)->output_name = strdup(j_out); 1097 } 1098 1099 return CUBEB_OK; 1100 } 1101 1102 static int 1103 cbjack_stream_device_destroy(cubeb_stream * /*stream*/, cubeb_device * device) 1104 { 1105 if (device->input_name) 1106 free(device->input_name); 1107 if (device->output_name) 1108 free(device->output_name); 1109 free(device); 1110 return CUBEB_OK; 1111 } 1112 1113 static int 1114 cbjack_enumerate_devices(cubeb * context, cubeb_device_type type, 1115 cubeb_device_collection * collection) 1116 { 1117 if (!context) 1118 return CUBEB_ERROR; 1119 1120 uint32_t rate; 1121 cbjack_get_preferred_sample_rate(context, &rate); 1122 1123 cubeb_device_info * devices = new cubeb_device_info[2]; 1124 if (!devices) 1125 return CUBEB_ERROR; 1126 PodZero(devices, 2); 1127 collection->count = 0; 1128 1129 if (type & CUBEB_DEVICE_TYPE_OUTPUT) { 1130 cubeb_device_info * cur = &devices[collection->count]; 1131 cur->device_id = JACK_DEFAULT_OUT; 1132 cur->devid = (cubeb_devid)cur->device_id; 1133 cur->friendly_name = JACK_DEFAULT_OUT; 1134 cur->group_id = JACK_DEFAULT_OUT; 1135 cur->vendor_name = JACK_DEFAULT_OUT; 1136 cur->type = CUBEB_DEVICE_TYPE_OUTPUT; 1137 cur->state = CUBEB_DEVICE_STATE_ENABLED; 1138 cur->preferred = CUBEB_DEVICE_PREF_ALL; 1139 cur->format = CUBEB_DEVICE_FMT_F32NE; 1140 cur->default_format = CUBEB_DEVICE_FMT_F32NE; 1141 cur->max_channels = MAX_CHANNELS; 1142 cur->min_rate = rate; 1143 cur->max_rate = rate; 1144 cur->default_rate = rate; 1145 cur->latency_lo = 0; 1146 cur->latency_hi = 0; 1147 collection->count += 1; 1148 } 1149 1150 if (type & CUBEB_DEVICE_TYPE_INPUT) { 1151 cubeb_device_info * cur = &devices[collection->count]; 1152 cur->device_id = JACK_DEFAULT_IN; 1153 cur->devid = (cubeb_devid)cur->device_id; 1154 cur->friendly_name = JACK_DEFAULT_IN; 1155 cur->group_id = JACK_DEFAULT_IN; 1156 cur->vendor_name = JACK_DEFAULT_IN; 1157 cur->type = CUBEB_DEVICE_TYPE_INPUT; 1158 cur->state = CUBEB_DEVICE_STATE_ENABLED; 1159 cur->preferred = CUBEB_DEVICE_PREF_ALL; 1160 cur->format = CUBEB_DEVICE_FMT_F32NE; 1161 cur->default_format = CUBEB_DEVICE_FMT_F32NE; 1162 cur->max_channels = MAX_CHANNELS; 1163 cur->min_rate = rate; 1164 cur->max_rate = rate; 1165 cur->default_rate = rate; 1166 cur->latency_lo = 0; 1167 cur->latency_hi = 0; 1168 collection->count += 1; 1169 } 1170 1171 collection->device = devices; 1172 1173 return CUBEB_OK; 1174 } 1175 1176 static int 1177 cbjack_device_collection_destroy(cubeb * /*ctx*/, 1178 cubeb_device_collection * collection) 1179 { 1180 XASSERT(collection); 1181 delete[] collection->device; 1182 return CUBEB_OK; 1183 }