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