tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }