duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.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 }