@ -8,53 +8,59 @@
*/
# define _DEFAULT_SOURCE
# define _BSD_SOURCE
# if !defined(__FreeBSD__) && !defined(__APPLE__)
# if ndef __FreeBSD__
# define _POSIX_SOURCE
# endif
# include <dlfcn.h>
# include <stdio.h>
# include <string.h>
# include <limits.h>
# include <stdlib.h>
# include <pthread.h>
# include <math.h>
# include "cubeb/cubeb.h"
# include "cubeb-internal.h"
# include "cubeb/cubeb.h"
# include "cubeb_resampler.h"
# include "cubeb_utils.h"
# include <dlfcn.h>
# include <limits.h>
# include <math.h>
# include <pthread.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <jack/jack.h>
# include <jack/statistics.h>
# define JACK_API_VISIT(X) \
X ( jack_activate ) \
X ( jack_client_close ) \
X ( jack_client_open ) \
X ( jack_connect ) \
X ( jack_free ) \
X ( jack_get_ports ) \
X ( jack_get_sample_rate ) \
X ( jack_get_xrun_delayed_usecs ) \
X ( jack_get_buffer_size ) \
X ( jack_port_get_buffer ) \
X ( jack_port_name ) \
X ( jack_port_register ) \
X ( jack_port_unregister ) \
X ( jack_port_get_latency_range ) \
X ( jack_set_process_callback ) \
X ( jack_set_xrun_callback ) \
X ( jack_set_graph_order_callback ) \
X ( jack_set_error_function ) \
# ifdef DISABLE_LIBJACK_DLOPEN
# define WRAP(x) x
# else
# define WRAP(x) (*api_##x)
# define JACK_API_VISIT(X) \
X ( jack_activate ) \
X ( jack_client_close ) \
X ( jack_client_open ) \
X ( jack_connect ) \
X ( jack_free ) \
X ( jack_get_ports ) \
X ( jack_get_sample_rate ) \
X ( jack_get_xrun_delayed_usecs ) \
X ( jack_get_buffer_size ) \
X ( jack_port_get_buffer ) \
X ( jack_port_name ) \
X ( jack_port_register ) \
X ( jack_port_unregister ) \
X ( jack_port_get_latency_range ) \
X ( jack_set_process_callback ) \
X ( jack_set_xrun_callback ) \
X ( jack_set_graph_order_callback ) \
X ( jack_set_error_function ) \
X ( jack_set_info_function )
# define IMPORT_FUNC(x) static decltype(x) * api_##x;
JACK_API_VISIT ( IMPORT_FUNC ) ;
# undef IMPORT_FUNC
# endif
# define JACK_DEFAULT_IN "JACK capture"
# define JACK_DEFAULT_OUT "JACK playback"
static const int MAX_STREAMS = 16 ;
static const int MAX_CHANNELS = 8 ;
static const int MAX_CHANNELS = 8 ;
static const int FIFO_SIZE = 4096 * sizeof ( float ) ;
enum devstream {
@ -64,6 +70,12 @@ enum devstream {
DUPLEX ,
} ;
enum cbjack_connect_ports_options {
CBJACK_CP_OPTIONS_NONE = 0x0 ,
CBJACK_CP_OPTIONS_SKIP_OUTPUT = 0x1 ,
CBJACK_CP_OPTIONS_SKIP_INPUT = 0x2 ,
} ;
static void
s16ne_to_float ( float * dst , const int16_t * src , size_t n )
{
@ -75,71 +87,95 @@ static void
float_to_s16ne ( int16_t * dst , float * src , size_t n )
{
for ( size_t i = 0 ; i < n ; i + + ) {
if ( * src > 1.f ) * src = 1.f ;
if ( * src < - 1.f ) * src = - 1.f ;
if ( * src > 1.f )
* src = 1.f ;
if ( * src < - 1.f )
* src = - 1.f ;
* ( dst + + ) = ( int16_t ) ( ( int16_t ) ( * ( src + + ) * 32767 ) ) ;
}
}
extern " C "
{
/*static*/ int jack_init ( cubeb * * context , char const * context_name ) ;
extern " C " {
/*static*/ int
jack_init ( cubeb * * context , char const * context_name ) ;
}
static char const * cbjack_get_backend_id ( cubeb * context ) ;
static int cbjack_get_max_channel_count ( cubeb * ctx , uint32_t * max_channels ) ;
static int cbjack_get_min_latency ( cubeb * ctx , cubeb_stream_params params , uint32_t * latency_frames ) ;
static int cbjack_get_latency ( cubeb_stream * stm , unsigned int * latency_frames ) ;
static int cbjack_get_preferred_sample_rate ( cubeb * ctx , uint32_t * rate ) ;
static void cbjack_destroy ( cubeb * context ) ;
static void cbjack_interleave_capture ( cubeb_stream * stream , float * * in , jack_nframes_t nframes , bool format_mismatch ) ;
static void cbjack_deinterleave_playback_refill_s16ne ( cubeb_stream * stream , short * * bufs_in , float * * bufs_out , jack_nframes_t nframes ) ;
static void cbjack_deinterleave_playback_refill_float ( cubeb_stream * stream , float * * bufs_in , float * * bufs_out , jack_nframes_t nframes ) ;
static int cbjack_stream_device_destroy ( cubeb_stream * stream ,
cubeb_device * device ) ;
static int cbjack_stream_get_current_device ( cubeb_stream * stm , cubeb_device * * const device ) ;
static int cbjack_enumerate_devices ( cubeb * context , cubeb_device_type type ,
cubeb_device_collection * collection ) ;
static int cbjack_device_collection_destroy ( cubeb * context ,
cubeb_device_collection * collection ) ;
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 latency_frames ,
cubeb_data_callback data_callback ,
cubeb_state_callback state_callback ,
void * user_ptr ) ;
static void cbjack_stream_destroy ( cubeb_stream * stream ) ;
static int cbjack_stream_start ( cubeb_stream * stream ) ;
static int cbjack_stream_stop ( cubeb_stream * stream ) ;
static int cbjack_stream_get_position ( cubeb_stream * stream , uint64_t * position ) ;
static int cbjack_stream_set_volume ( cubeb_stream * stm , float volume ) ;
static char const *
cbjack_get_backend_id ( cubeb * context ) ;
static int
cbjack_get_max_channel_count ( cubeb * ctx , uint32_t * max_channels ) ;
static int
cbjack_get_min_latency ( cubeb * ctx , cubeb_stream_params params ,
uint32_t * latency_frames ) ;
static int
cbjack_get_latency ( cubeb_stream * stm , unsigned int * latency_frames ) ;
static int
cbjack_get_preferred_sample_rate ( cubeb * ctx , uint32_t * rate ) ;
static void
cbjack_destroy ( cubeb * context ) ;
static void
cbjack_interleave_capture ( cubeb_stream * stream , float * * in ,
jack_nframes_t nframes , bool format_mismatch ) ;
static void
cbjack_deinterleave_playback_refill_s16ne ( cubeb_stream * stream ,
short * * bufs_in , float * * bufs_out ,
jack_nframes_t nframes ) ;
static void
cbjack_deinterleave_playback_refill_float ( cubeb_stream * stream ,
float * * bufs_in , float * * bufs_out ,
jack_nframes_t nframes ) ;
static int
cbjack_stream_device_destroy ( cubeb_stream * stream , cubeb_device * device ) ;
static int
cbjack_stream_get_current_device ( cubeb_stream * stm ,
cubeb_device * * const device ) ;
static int
cbjack_enumerate_devices ( cubeb * context , cubeb_device_type type ,
cubeb_device_collection * collection ) ;
static int
cbjack_device_collection_destroy ( cubeb * context ,
cubeb_device_collection * collection ) ;
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 latency_frames ,
cubeb_data_callback data_callback ,
cubeb_state_callback state_callback , void * user_ptr ) ;
static void
cbjack_stream_destroy ( cubeb_stream * stream ) ;
static int
cbjack_stream_start ( cubeb_stream * stream ) ;
static int
cbjack_stream_stop ( cubeb_stream * stream ) ;
static int
cbjack_stream_get_position ( cubeb_stream * stream , uint64_t * position ) ;
static int
cbjack_stream_set_volume ( cubeb_stream * stm , float volume ) ;
static struct cubeb_ops const cbjack_ops = {
. init = jack_init ,
. get_backend_id = cbjack_get_backend_id ,
. get_max_channel_count = cbjack_get_max_channel_count ,
. get_min_latency = cbjack_get_min_latency ,
. get_preferred_sample_rate = cbjack_get_preferred_sample_rate ,
. enumerate_devices = cbjack_enumerate_devices ,
. device_collection_destroy = cbjack_device_collection_destroy ,
. destroy = cbjack_destroy ,
. stream_init = cbjack_stream_init ,
. stream_destroy = cbjack_stream_destroy ,
. stream_start = cbjack_stream_start ,
. stream_stop = cbjack_stream_stop ,
. stream_reset_default_device = NULL ,
. stream_get_position = cbjack_stream_get_position ,
. stream_get_latency = cbjack_get_latency ,
. stream_get_input_latency = NULL ,
. stream_set_volume = cbjack_stream_set_volume ,
. stream_set_name = NULL ,
. stream_get_current_device = cbjack_stream_get_current_device ,
. stream_device_destroy = cbjack_stream_device_destroy ,
. stream_register_device_changed_callback = NULL ,
. register_device_collection_changed = NULL
} ;
. init = jack_init ,
. get_backend_id = cbjack_get_backend_id ,
. get_max_channel_count = cbjack_get_max_channel_count ,
. get_min_latency = cbjack_get_min_latency ,
. get_preferred_sample_rate = cbjack_get_preferred_sample_rate ,
. enumerate_devices = cbjack_enumerate_devices ,
. device_collection_destroy = cbjack_device_collection_destroy ,
. destroy = cbjack_destroy ,
. stream_init = cbjack_stream_init ,
. stream_destroy = cbjack_stream_destroy ,
. stream_start = cbjack_stream_start ,
. stream_stop = cbjack_stream_stop ,
. stream_get_position = cbjack_stream_get_position ,
. stream_get_latency = cbjack_get_latency ,
. stream_get_input_latency = NULL ,
. stream_set_volume = cbjack_stream_set_volume ,
. stream_set_name = NULL ,
. stream_get_current_device = cbjack_stream_get_current_device ,
. stream_device_destroy = cbjack_stream_device_destroy ,
. stream_register_device_changed_callback = NULL ,
. register_device_collection_changed = NULL } ;
struct cubeb_stream {
/* Note: Must match cubeb_stream layout in cubeb.c. */
@ -150,7 +186,7 @@ struct cubeb_stream {
/**< Mutex for each stream */
pthread_mutex_t mutex ;
bool in_use ; /**< Set to false iff the stream is free */
bool in_use ; /**< Set to false iff the stream is free */
bool ports_ready ; /**< Set to true iff the JACK ports are ready */
cubeb_data_callback data_callback ;
@ -205,15 +241,16 @@ struct cubeb {
static int
load_jack_lib ( cubeb * context )
{
# ifndef DISABLE_LIBJACK_DLOPEN
# ifdef __APPLE__
context - > libjack = dlopen ( " libjack.0.dylib " , RTLD_LAZY ) ;
context - > libjack = dlopen ( " /usr/local/lib/libjack.0.dylib " , RTLD_LAZY ) ;
# elif defined(__WIN32__)
# ifdef _WIN64
context - > libjack = LoadLibrary ( " libjack64.dll " ) ;
# else
context - > libjack = LoadLibrary ( " libjack.dll " ) ;
# endif
# ifdef _WIN64
context - > libjack = LoadLibrary ( " libjack64.dll " ) ;
# else
context - > libjack = LoadLibrary ( " libjack.dll " ) ;
# endif
# else
context - > libjack = dlopen ( " libjack.so.0 " , RTLD_LAZY ) ;
if ( ! context - > libjack ) {
@ -224,56 +261,59 @@ load_jack_lib(cubeb * context)
return CUBEB_ERROR ;
}
# define LOAD(x) \
{ \
api_ # # x = ( decltype ( x ) * ) dlsym ( context - > libjack , # x ) ; \
if ( ! api_ # # x ) { \
dlclose ( context - > libjack ) ; \
return CUBEB_ERROR ; \
} \
# define LOAD(x) \
{ \
api_ # # x = ( decltype ( x ) * ) dlsym ( context - > libjack , # x ) ; \
if ( ! api_ # # x ) { \
dlclose ( context - > libjack ) ; \
return CUBEB_ERROR ; \
} \
}
JACK_API_VISIT ( LOAD ) ;
# undef LOAD
# endif
return CUBEB_OK ;
}
static void
cbjack_connect_port_out ( cubeb_stream * stream , const size_t out_port , const char * const phys_in_port )
cbjack_connect_port_out ( cubeb_stream * stream , const size_t out_port ,
const char * const phys_in_port )
{
const char * src_port = api_jack_port_name ( stream - > output_ports [ out_port ] ) ;
const char * src_port = WRAP ( jack_port_name ) ( stream - > output_ports [ out_port ] ) ;
api_jack_connect ( stream - > context - > jack_client , src_port , phys_in_port ) ;
WRAP( jack_connect ) ( stream - > context - > jack_client , src_port , phys_in_port ) ;
}
static void
cbjack_connect_port_in ( cubeb_stream * stream , const char * const phys_out_port , size_t in_port )
cbjack_connect_port_in ( cubeb_stream * stream , const char * const phys_out_port ,
size_t in_port )
{
const char * src_port = api_jack_port_name ( stream - > input_ports [ in_port ] ) ;
const char * src_port = WRAP ( jack_port_name ) ( stream - > input_ports [ in_port ] ) ;
api_jack_connect ( stream - > context - > jack_client , phys_out_port , src_port ) ;
WRAP( jack_connect ) ( stream - > context - > jack_client , phys_out_port , src_port ) ;
}
static int
cbjack_connect_ports ( cubeb_stream * stream )
cbjack_connect_ports ( cubeb_stream * stream ,
enum cbjack_connect_ports_options options )
{
int r = CUBEB_ERROR ;
const char * * phys_in_ports = api_jack_get_ports ( stream - > context - > jack_client ,
NULL , NULL ,
JackPortIsInput
| JackPortIsPhysical ) ;
const char * * phys_out_ports = api_jack_get_ports ( stream - > context - > jack_client ,
NULL , NULL ,
JackPortIsOutput
| JackPortIsPhysical ) ;
if ( phys_in_ports = = NULL | | * phys_in_ports = = NULL ) {
const char * * phys_in_ports =
WRAP ( jack_get_ports ) ( stream - > context - > jack_client , NULL , NULL ,
JackPortIsInput | JackPortIsPhysical ) ;
const char * * phys_out_ports =
WRAP ( jack_get_ports ) ( stream - > context - > jack_client , NULL , NULL ,
JackPortIsOutput | JackPortIsPhysical ) ;
if ( phys_in_ports = = NULL | | * phys_in_ports = = NULL | |
options & CBJACK_CP_OPTIONS_SKIP_OUTPUT ) {
goto skipplayback ;
}
// Connect outputs to playback
for ( unsigned int c = 0 ; c < stream - > out_params . channels & & phys_in_ports [ c ] ! = NULL ; c + + ) {
for ( unsigned int c = 0 ;
c < stream - > out_params . channels & & phys_in_ports [ c ] ! = NULL ; c + + ) {
cbjack_connect_port_out ( stream , c , phys_in_ports [ c ] ) ;
}
@ -285,20 +325,22 @@ cbjack_connect_ports (cubeb_stream * stream)
r = CUBEB_OK ;
skipplayback :
if ( phys_out_ports = = NULL | | * phys_out_ports = = NULL ) {
if ( phys_out_ports = = NULL | | * phys_out_ports = = NULL | |
options & CBJACK_CP_OPTIONS_SKIP_INPUT ) {
goto end ;
}
// Connect inputs to capture
for ( unsigned int c = 0 ; c < stream - > in_params . channels & & phys_out_ports [ c ] ! = NULL ; c + + ) {
for ( unsigned int c = 0 ;
c < stream - > in_params . channels & & phys_out_ports [ c ] ! = NULL ; c + + ) {
cbjack_connect_port_in ( stream , phys_out_ports [ c ] , c ) ;
}
r = CUBEB_OK ;
end :
if ( phys_out_ports ) {
api_jack_free ( phys_out_ports ) ;
WRAP( jack_free ) ( phys_out_ports ) ;
}
if ( phys_in_ports ) {
api_jack_free ( phys_in_ports ) ;
WRAP( jack_free ) ( phys_in_ports ) ;
}
return r ;
}
@ -308,8 +350,9 @@ cbjack_xrun_callback(void * arg)
{
cubeb * ctx = ( cubeb * ) arg ;
float delay = api_jack_get_xrun_delayed_usecs ( ctx - > jack_client ) ;
float fragments = ceilf ( ( ( delay / 1000000.0 ) * ctx - > jack_sample_rate ) / ctx - > jack_buffer_size ) ;
float delay = WRAP ( jack_get_xrun_delayed_usecs ) ( ctx - > jack_client ) ;
float fragments = ceilf ( ( ( delay / 1000000.0 ) * ctx - > jack_sample_rate ) /
ctx - > jack_buffer_size ) ;
ctx - > jack_xruns + = ( unsigned int ) fragments ;
return 0 ;
@ -324,7 +367,7 @@ cbjack_graph_order_callback(void * arg)
jack_nframes_t port_latency , max_latency = 0 ;
for ( int j = 0 ; j < MAX_STREAMS ; j + + ) {
cubeb_stream * stm = & ctx - > streams [ j ] ;
cubeb_stream * stm = & ctx - > streams [ j ] ;
if ( ! stm - > in_use )
continue ;
@ -332,10 +375,11 @@ cbjack_graph_order_callback(void * arg)
continue ;
for ( i = 0 ; i < ( int ) stm - > out_params . channels ; + + i ) {
api_jack_port_get_latency_range ( stm - > output_ports [ i ] , JackPlaybackLatency , & latency_range ) ;
WRAP ( jack_port_get_latency_range )
( stm - > output_ports [ i ] , JackPlaybackLatency , & latency_range ) ;
port_latency = latency_range . max ;
if ( port_latency > max_latency )
max_latency = port_latency ;
max_latency = port_latency ;
}
/* Cap minimum latency to 128 frames */
if ( max_latency < 128 )
@ -357,9 +401,9 @@ cbjack_process(jack_nframes_t nframes, void * arg)
ctx - > jack_xruns = 0 ;
for ( int j = 0 ; j < MAX_STREAMS ; j + + ) {
cubeb_stream * stm = & ctx - > streams [ j ] ;
float * bufs_out [ stm - > out_params . channels ] ;
float * bufs_in [ stm - > in_params . channels ] ;
cubeb_stream * stm = & ctx - > streams [ j ] ;
float * bufs_out [ stm - > out_params . channels ] ;
float * bufs_in [ stm - > in_params . channels ] ;
if ( ! stm - > in_use )
continue ;
@ -373,18 +417,20 @@ cbjack_process(jack_nframes_t nframes, void * arg)
if ( stm - > devs & OUT_ONLY ) {
// get jack output buffers
for ( i = 0 ; i < ( int ) stm - > out_params . channels ; i + + )
bufs_out [ i ] = ( float * ) api_jack_port_get_buffer ( stm - > output_ports [ i ] , nframes ) ;
bufs_out [ i ] =
( float * ) WRAP ( jack_port_get_buffer ) ( stm - > output_ports [ i ] , nframes ) ;
}
if ( stm - > devs & IN_ONLY ) {
// get jack input buffers
for ( i = 0 ; i < ( int ) stm - > in_params . channels ; i + + )
bufs_in [ i ] = ( float * ) api_jack_port_get_buffer ( stm - > input_ports [ i ] , nframes ) ;
bufs_in [ i ] =
( float * ) WRAP ( jack_port_get_buffer ) ( stm - > input_ports [ i ] , nframes ) ;
}
if ( stm - > pause ) {
// paused, play silence on output
if ( stm - > devs & OUT_ONLY ) {
for ( unsigned int c = 0 ; c < stm - > out_params . channels ; c + + ) {
float * buffer_out = bufs_out [ c ] ;
float * buffer_out = bufs_out [ c ] ;
for ( long f = 0 ; f < nframes ; f + + ) {
buffer_out [ f ] = 0.f ;
}
@ -393,7 +439,7 @@ cbjack_process(jack_nframes_t nframes, void * arg)
if ( stm - > devs & IN_ONLY ) {
// paused, capture silence
for ( unsigned int c = 0 ; c < stm - > in_params . channels ; c + + ) {
float * buffer_in = bufs_in [ c ] ;
float * buffer_in = bufs_in [ c ] ;
for ( long f = 0 ; f < nframes ; f + + ) {
buffer_in [ f ] = 0.f ;
}
@ -404,31 +450,38 @@ cbjack_process(jack_nframes_t nframes, void * arg)
// try to lock stream mutex
if ( pthread_mutex_trylock ( & stm - > mutex ) = = 0 ) {
int16_t * in_s16ne = stm - > context - > in_resampled_interleaved_buffer_s16ne ;
float * in_float = stm - > context - > in_resampled_interleaved_buffer_float ;
int16_t * in_s16ne =
stm - > context - > in_resampled_interleaved_buffer_s16ne ;
float * in_float = stm - > context - > in_resampled_interleaved_buffer_float ;
// unpaused, play audio
if ( stm - > devs = = DUPLEX ) {
if ( stm - > out_params . format = = CUBEB_SAMPLE_S16NE ) {
cbjack_interleave_capture ( stm , bufs_in , nframes , true ) ;
cbjack_deinterleave_playback_refill_s16ne ( stm , & in_s16ne , bufs_out , nframes ) ;
cbjack_deinterleave_playback_refill_s16ne ( stm , & in_s16ne , bufs_out ,
nframes ) ;
} else if ( stm - > out_params . format = = CUBEB_SAMPLE_FLOAT32NE ) {
cbjack_interleave_capture ( stm , bufs_in , nframes , false ) ;
cbjack_deinterleave_playback_refill_float ( stm , & in_float , bufs_out , nframes ) ;
cbjack_deinterleave_playback_refill_float ( stm , & in_float , bufs_out ,
nframes ) ;
}
} else if ( stm - > devs = = IN_ONLY ) {
if ( stm - > in_params . format = = CUBEB_SAMPLE_S16NE ) {
cbjack_interleave_capture ( stm , bufs_in , nframes , true ) ;
cbjack_deinterleave_playback_refill_s16ne ( stm , & in_s16ne , nullptr , nframes ) ;
cbjack_deinterleave_playback_refill_s16ne ( stm , & in_s16ne , nullptr ,
nframes ) ;
} else if ( stm - > in_params . format = = CUBEB_SAMPLE_FLOAT32NE ) {
cbjack_interleave_capture ( stm , bufs_in , nframes , false ) ;
cbjack_deinterleave_playback_refill_float ( stm , & in_float , nullptr , nframes ) ;
cbjack_deinterleave_playback_refill_float ( stm , & in_float , nullptr ,
nframes ) ;
}
} else if ( stm - > devs = = OUT_ONLY ) {
if ( stm - > out_params . format = = CUBEB_SAMPLE_S16NE ) {
cbjack_deinterleave_playback_refill_s16ne ( stm , nullptr , bufs_out , nframes ) ;
cbjack_deinterleave_playback_refill_s16ne ( stm , nullptr , bufs_out ,
nframes ) ;
} else if ( stm - > out_params . format = = CUBEB_SAMPLE_FLOAT32NE ) {
cbjack_deinterleave_playback_refill_float ( stm , nullptr , bufs_out , nframes ) ;
cbjack_deinterleave_playback_refill_float ( stm , nullptr , bufs_out ,
nframes ) ;
}
}
// unlock stream mutex
@ -439,7 +492,7 @@ cbjack_process(jack_nframes_t nframes, void * arg)
// output silence
if ( stm - > devs & OUT_ONLY ) {
for ( unsigned int c = 0 ; c < stm - > out_params . channels ; c + + ) {
float * buffer_out = bufs_out [ c ] ;
float * buffer_out = bufs_out [ c ] ;
for ( long f = 0 ; f < nframes ; f + + ) {
buffer_out [ f ] = 0.f ;
}
@ -448,7 +501,7 @@ cbjack_process(jack_nframes_t nframes, void * arg)
if ( stm - > devs & IN_ONLY ) {
// capture silence
for ( unsigned int c = 0 ; c < stm - > in_params . channels ; c + + ) {
float * buffer_in = bufs_in [ c ] ;
float * buffer_in = bufs_in [ c ] ;
for ( long f = 0 ; f < nframes ; f + + ) {
buffer_in [ f ] = 0.f ;
}
@ -461,7 +514,9 @@ cbjack_process(jack_nframes_t nframes, void * arg)
}
static void
cbjack_deinterleave_playback_refill_float ( cubeb_stream * stream , float * * in , float * * bufs_out , jack_nframes_t nframes )
cbjack_deinterleave_playback_refill_float ( cubeb_stream * stream , float * * in ,
float * * bufs_out ,
jack_nframes_t nframes )
{
float * out_interleaved_buffer = nullptr ;
@ -472,20 +527,24 @@ cbjack_deinterleave_playback_refill_float(cubeb_stream * stream, float ** in, fl
long done_frames = 0 ;
long input_frames_count = ( in ! = NULL ) ? nframes : 0 ;
done_frames = cubeb_resampler_fill ( stream - > resampler ,
inptr ,
& input_frames_count ,
( bufs_out ! = NULL ) ? stream - > context - > out_resampled_interleaved_buffer_float : NULL ,
needed_frames ) ;
done_frames = cubeb_resampler_fill (
stream - > resampler , inptr , & input_frames_count ,
( bufs_out ! = NULL )
? stream - > context - > out_resampled_interleaved_buffer_float
: NULL ,
needed_frames ) ;
out_interleaved_buffer = stream - > context - > out_resampled_interleaved_buffer_float ;
out_interleaved_buffer =
stream - > context - > out_resampled_interleaved_buffer_float ;
if ( outptr ) {
// convert interleaved output buffers to contiguous buffers
for ( unsigned int c = 0 ; c < stream - > out_params . channels ; c + + ) {
float * buffer = bufs_out [ c ] ;
float * buffer = bufs_out [ c ] ;
for ( long f = 0 ; f < done_frames ; f + + ) {
buffer [ f ] = out_interleaved_buffer [ ( f * stream - > out_params . channels ) + c ] * stream - > volume ;
buffer [ f ] =
out_interleaved_buffer [ ( f * stream - > out_params . channels ) + c ] *
stream - > volume ;
}
if ( done_frames < needed_frames ) {
// draining
@ -519,7 +578,9 @@ cbjack_deinterleave_playback_refill_float(cubeb_stream * stream, float ** in, fl
}
static void
cbjack_deinterleave_playback_refill_s16ne ( cubeb_stream * stream , short * * in , float * * bufs_out , jack_nframes_t nframes )
cbjack_deinterleave_playback_refill_s16ne ( cubeb_stream * stream , short * * in ,
float * * bufs_out ,
jack_nframes_t nframes )
{
float * out_interleaved_buffer = nullptr ;
@ -530,22 +591,28 @@ cbjack_deinterleave_playback_refill_s16ne(cubeb_stream * stream, short ** in, fl
long done_frames = 0 ;
long input_frames_count = ( in ! = NULL ) ? nframes : 0 ;
done_frames = cubeb_resampler_fill ( stream - > resampler ,
inptr ,
& input_frames_count ,
( bufs_out ! = NULL ) ? stream - > context - > out_resampled_interleaved_buffer_s16ne : NULL ,
needed_frames ) ;
done_frames = cubeb_resampler_fill (
stream - > resampler , inptr , & input_frames_count ,
( bufs_out ! = NULL )
? stream - > context - > out_resampled_interleaved_buffer_s16ne
: NULL ,
needed_frames ) ;
s16ne_to_float ( stream - > context - > out_resampled_interleaved_buffer_float , stream - > context - > out_resampled_interleaved_buffer_s16ne , done_frames * stream - > out_params . channels ) ;
s16ne_to_float ( stream - > context - > out_resampled_interleaved_buffer_float ,
stream - > context - > out_resampled_interleaved_buffer_s16ne ,
done_frames * stream - > out_params . channels ) ;
out_interleaved_buffer = stream - > context - > out_resampled_interleaved_buffer_float ;
out_interleaved_buffer =
stream - > context - > out_resampled_interleaved_buffer_float ;
if ( outptr ) {
// convert interleaved output buffers to contiguous buffers
for ( unsigned int c = 0 ; c < stream - > out_params . channels ; c + + ) {
float * buffer = bufs_out [ c ] ;
float * buffer = bufs_out [ c ] ;
for ( long f = 0 ; f < done_frames ; f + + ) {
buffer [ f ] = out_interleaved_buffer [ ( f * stream - > out_params . channels ) + c ] * stream - > volume ;
buffer [ f ] =
out_interleaved_buffer [ ( f * stream - > out_params . channels ) + c ] *
stream - > volume ;
}
if ( done_frames < needed_frames ) {
// draining
@ -579,20 +646,25 @@ cbjack_deinterleave_playback_refill_s16ne(cubeb_stream * stream, short ** in, fl
}
static void
cbjack_interleave_capture ( cubeb_stream * stream , float * * in , jack_nframes_t nframes , bool format_mismatch )
cbjack_interleave_capture ( cubeb_stream * stream , float * * in ,
jack_nframes_t nframes , bool format_mismatch )
{
float * in_buffer = stream - > context - > in_float_interleaved_buffer ;
float * in_buffer = stream - > context - > in_float_interleaved_buffer ;
for ( unsigned int c = 0 ; c < stream - > in_params . channels ; c + + ) {
for ( long f = 0 ; f < nframes ; f + + ) {
in_buffer [ ( f * stream - > in_params . channels ) + c ] = in [ c ] [ f ] * stream - > volume ;
in_buffer [ ( f * stream - > in_params . channels ) + c ] =
in [ c ] [ f ] * stream - > volume ;
}
}
if ( format_mismatch ) {
float_to_s16ne ( stream - > context - > in_resampled_interleaved_buffer_s16ne , in_buffer , nframes * stream - > in_params . channels ) ;
float_to_s16ne ( stream - > context - > in_resampled_interleaved_buffer_s16ne ,
in_buffer , nframes * stream - > in_params . channels ) ;
} else {
memset ( stream - > context - > in_resampled_interleaved_buffer_float , 0 , ( FIFO_SIZE * MAX_CHANNELS * 3 ) * sizeof ( float ) ) ;
memcpy ( stream - > context - > in_resampled_interleaved_buffer_float , in_buffer , ( FIFO_SIZE * MAX_CHANNELS * 2 ) * sizeof ( float ) ) ;
memset ( stream - > context - > in_resampled_interleaved_buffer_float , 0 ,
( FIFO_SIZE * MAX_CHANNELS * 3 ) * sizeof ( float ) ) ;
memcpy ( stream - > context - > in_resampled_interleaved_buffer_float , in_buffer ,
( FIFO_SIZE * MAX_CHANNELS * 2 ) * sizeof ( float ) ) ;
}
}
@ -602,7 +674,7 @@ silent_jack_error_callback(char const * /*msg*/)
}
/*static*/ int
jack_init ( cubeb * * context , char const * context_name )
jack_init ( cubeb * * context , char const * context_name )
{
int r ;
@ -619,8 +691,8 @@ jack_init (cubeb ** context, char const * context_name)
return CUBEB_ERROR ;
}
api_jack_set_error_function ( silent_jack_error_callback ) ;
api_jack_set_info_function ( silent_jack_error_callback ) ;
WRAP( jack_set_error_function ) ( silent_jack_error_callback ) ;
WRAP( jack_set_info_function ) ( silent_jack_error_callback ) ;
ctx - > ops = & cbjack_ops ;
@ -633,9 +705,8 @@ jack_init (cubeb ** context, char const * context_name)
if ( context_name )
jack_client_name = context_name ;
ctx - > jack_client = api_jack_client_open ( jack_client_name ,
JackNoStartServer ,
NULL ) ;
ctx - > jack_client =
WRAP ( jack_client_open ) ( jack_client_name , JackNoStartServer , NULL ) ;
if ( ctx - > jack_client = = NULL ) {
cbjack_destroy ( ctx ) ;
@ -644,16 +715,17 @@ jack_init (cubeb ** context, char const * context_name)
ctx - > jack_xruns = 0 ;
api_jack_set_process_callback ( ctx - > jack_client , cbjack_process , ctx ) ;
api_jack_set_xrun_callback ( ctx - > jack_client , cbjack_xrun_callback , ctx ) ;
api_jack_set_graph_order_callback ( ctx - > jack_client , cbjack_graph_order_callback , ctx ) ;
WRAP ( jack_set_process_callback ) ( ctx - > jack_client , cbjack_process , ctx ) ;
WRAP ( jack_set_xrun_callback ) ( ctx - > jack_client , cbjack_xrun_callback , ctx ) ;
WRAP ( jack_set_graph_order_callback )
( ctx - > jack_client , cbjack_graph_order_callback , ctx ) ;
if ( api_jack_activate ( ctx - > jack_client ) ) {
if ( WRAP( jack_activate ) ( ctx - > jack_client ) ) {
cbjack_destroy ( ctx ) ;
return CUBEB_ERROR ;
}
ctx - > jack_sample_rate = api_jack_get_sample_rate ( ctx - > jack_client ) ;
ctx - > jack_sample_rate = WRAP( jack_get_sample_rate ) ( ctx - > jack_client ) ;
ctx - > jack_latency = 128 * 1000 / ctx - > jack_sample_rate ;
ctx - > active = true ;
@ -683,7 +755,8 @@ cbjack_get_latency(cubeb_stream * stm, unsigned int * latency_ms)
}
static int
cbjack_get_min_latency ( cubeb * ctx , cubeb_stream_params /*params*/ , uint32_t * latency_ms )
cbjack_get_min_latency ( cubeb * ctx , cubeb_stream_params /*params*/ ,
uint32_t * latency_ms )
{
* latency_ms = ctx - > jack_latency ;
return CUBEB_OK ;
@ -693,18 +766,17 @@ static int
cbjack_get_preferred_sample_rate ( cubeb * ctx , uint32_t * rate )
{
if ( ! ctx - > jack_client ) {
jack_client_t * testclient = api_jack_client_open ( " test-samplerate " ,
JackNoStartServer ,
NULL ) ;
jack_client_t * testclient =
WRAP ( jack_client_open ) ( " test-samplerate " , JackNoStartServer , NULL ) ;
if ( ! testclient ) {
return CUBEB_ERROR ;
}
* rate = api_jack_get_sample_rate ( testclient ) ;
api_jack_client_close ( testclient ) ;
* rate = WRAP( jack_get_sample_rate ) ( testclient ) ;
WRAP( jack_client_close ) ( testclient ) ;
} else {
* rate = api_jack_get_sample_rate ( ctx - > jack_client ) ;
* rate = WRAP( jack_get_sample_rate ) ( ctx - > jack_client ) ;
}
return CUBEB_OK ;
}
@ -715,7 +787,7 @@ cbjack_destroy(cubeb * context)
context - > active = false ;
if ( context - > jack_client ! = NULL )
api_jack_client_close ( context - > jack_client ) ;
WRAP( jack_client_close ) ( context - > jack_client ) ;
if ( context - > libjack )
dlclose ( context - > libjack ) ;
@ -738,30 +810,27 @@ context_alloc_stream(cubeb * context, char const * stream_name)
}
static int
cbjack_stream_init ( cubeb * context , cubeb_stream * * stream , char const * stream_name ,
cubeb_devid input_device ,
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 /*latency_frames*/ ,
cubeb_data_callback data_callback ,
cubeb_state_callback state_callback ,
void * user_ptr )
cubeb_state_callback state_callback , void * user_ptr )
{
int stream_actual_rate = 0 ;
int jack_rate = api_jack_get_sample_rate ( context - > jack_client ) ;
int jack_rate = WRAP( jack_get_sample_rate ) ( context - > jack_client ) ;
if ( output_stream_params
& & ( output_stream_params - > format ! = CUBEB_SAMPLE_FLOAT32NE & &
output_stream_params - > format ! = CUBEB_SAMPLE_S16NE )
) {
if ( output_stream_params & &
( output_stream_params - > format ! = CUBEB_SAMPLE_FLOAT32NE & &
output_stream_params - > format ! = CUBEB_SAMPLE_S16NE ) ) {
return CUBEB_ERROR_INVALID_FORMAT ;
}
if ( input_stream_params
& & ( input_stream_params - > format ! = CUBEB_SAMPLE_FLOAT32NE & &
input_stream_params - > format ! = CUBEB_SAMPLE_S16NE )
) {
if ( input_stream_params & &
( input_stream_params - > format ! = CUBEB_SAMPLE_FLOAT32NE & &
input_stream_params - > format ! = CUBEB_SAMPLE_S16NE ) ) {
return CUBEB_ERROR_INVALID_FORMAT ;
}
@ -771,8 +840,10 @@ cbjack_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_
}
// Loopback is unsupported
if ( ( input_stream_params & & ( input_stream_params - > prefs & CUBEB_STREAM_PREF_LOOPBACK ) ) | |
( output_stream_params & & ( output_stream_params - > prefs & CUBEB_STREAM_PREF_LOOPBACK ) ) ) {
if ( ( input_stream_params & &
( input_stream_params - > prefs & CUBEB_STREAM_PREF_LOOPBACK ) ) | |
( output_stream_params & &
( output_stream_params - > prefs & CUBEB_STREAM_PREF_LOOPBACK ) ) ) {
return CUBEB_ERROR_NOT_SUPPORTED ;
}
@ -841,7 +912,7 @@ cbjack_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_
stm - > state_callback = state_callback ;
stm - > position = 0 ;
stm - > volume = 1.0f ;
context - > jack_buffer_size = api_jack_get_buffer_size ( context - > jack_client ) ;
context - > jack_buffer_size = WRAP( jack_get_buffer_size ) ( context - > jack_client ) ;
context - > fragment_size = context - > jack_buffer_size ;
if ( stm - > devs = = NONE ) {
@ -852,29 +923,20 @@ cbjack_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_
stm - > resampler = NULL ;
if ( stm - > devs = = DUPLEX ) {
stm - > resampler = cubeb_resampler_create ( stm ,
& stm - > in_params ,
& stm - > out_params ,
stream_actual_rate ,
stm - > data_callback ,
stm - > user_ptr ,
CUBEB_RESAMPLER_QUALITY_DESKTOP ) ;
stm - > resampler = cubeb_resampler_create (
stm , & stm - > in_params , & stm - > out_params , stream_actual_rate ,
stm - > data_callback , stm - > user_ptr , CUBEB_RESAMPLER_QUALITY_DESKTOP ,
CUBEB_RESAMPLER_RECLOCK_NONE ) ;
} else if ( stm - > devs = = IN_ONLY ) {
stm - > resampler = cubeb_resampler_create ( stm ,
& stm - > in_params ,
nullptr ,
stream_actual_rate ,
stm - > data_callback ,
stm - > user_ptr ,
CUBEB_RESAMPLER_QUALITY_DESKTOP ) ;
stm - > resampler = cubeb_resampler_create (
stm , & stm - > in_params , nullptr , stream_actual_rate , stm - > data_callback ,
stm - > user_ptr , CUBEB_RESAMPLER_QUALITY_DESKTOP ,
CUBEB_RESAMPLER_RECLOCK_NONE ) ;
} else if ( stm - > devs = = OUT_ONLY ) {
stm - > resampler = cubeb_resampler_create ( stm ,
nullptr ,
& stm - > out_params ,
stream_actual_rate ,
stm - > data_callback ,
stm - > user_ptr ,
CUBEB_RESAMPLER_QUALITY_DESKTOP ) ;
stm - > resampler = cubeb_resampler_create (
stm , nullptr , & stm - > out_params , stream_actual_rate , stm - > data_callback ,
stm - > user_ptr , CUBEB_RESAMPLER_QUALITY_DESKTOP ,
CUBEB_RESAMPLER_RECLOCK_NONE ) ;
}
if ( ! stm - > resampler ) {
@ -887,11 +949,18 @@ cbjack_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_
for ( unsigned int c = 0 ; c < stm - > out_params . channels ; c + + ) {
char portname [ 256 ] ;
snprintf ( portname , 255 , " %s_out_%d " , stm - > stream_name , c ) ;
stm - > output_ports [ c ] = api_jack_port_register ( stm - > context - > jack_client ,
portname ,
JACK_DEFAULT_AUDIO_TYPE ,
JackPortIsOutput ,
0 ) ;
stm - > output_ports [ c ] = WRAP ( jack_port_register ) (
stm - > context - > jack_client , portname , JACK_DEFAULT_AUDIO_TYPE ,
JackPortIsOutput , 0 ) ;
if ( ! ( output_stream_params - > prefs &
CUBEB_STREAM_PREF_JACK_NO_AUTO_CONNECT ) ) {
if ( cbjack_connect_ports ( stm , CBJACK_CP_OPTIONS_SKIP_INPUT ) ! =
CUBEB_OK ) {
pthread_mutex_unlock ( & stm - > mutex ) ;
cbjack_stream_destroy ( stm ) ;
return CUBEB_ERROR ;
}
}
}
}
@ -899,19 +968,18 @@ cbjack_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_
for ( unsigned int c = 0 ; c < stm - > in_params . channels ; c + + ) {
char portname [ 256 ] ;
snprintf ( portname , 255 , " %s_in_%d " , stm - > stream_name , c ) ;
stm - > input_ports [ c ] = api_jack_port_register ( stm - > context - > jack_client ,
portname ,
JACK_DEFAULT_AUDIO_TYPE ,
JackPortIsInput ,
0 ) ;
}
}
if ( ! input_stream_params - > prefs & CUBEB_STREAM_PREF_JACK_NO_AUTO_CONNECT ) {
if ( cbjack_connect_ports ( stm ) ! = CUBEB_OK ) {
pthread_mutex_unlock ( & stm - > mutex ) ;
cbjack_stream_destroy ( stm ) ;
return CUBEB_ERROR ;
stm - > input_ports [ c ] =
WRAP ( jack_port_register ) ( stm - > context - > jack_client , portname ,
JACK_DEFAULT_AUDIO_TYPE , JackPortIsInput , 0 ) ;
if ( ! ( input_stream_params - > prefs &
CUBEB_STREAM_PREF_JACK_NO_AUTO_CONNECT ) ) {
if ( cbjack_connect_ports ( stm , CBJACK_CP_OPTIONS_SKIP_OUTPUT ) ! =
CUBEB_OK ) {
pthread_mutex_unlock ( & stm - > mutex ) ;
cbjack_stream_destroy ( stm ) ;
return CUBEB_ERROR ;
}
}
}
}
@ -933,7 +1001,8 @@ cbjack_stream_destroy(cubeb_stream * stream)
if ( stream - > devs = = DUPLEX | | stream - > devs = = OUT_ONLY ) {
for ( unsigned int c = 0 ; c < stream - > out_params . channels ; c + + ) {
if ( stream - > output_ports [ c ] ) {
api_jack_port_unregister ( stream - > context - > jack_client , stream - > output_ports [ c ] ) ;
WRAP ( jack_port_unregister )
( stream - > context - > jack_client , stream - > output_ports [ c ] ) ;
stream - > output_ports [ c ] = NULL ;
}
}
@ -942,7 +1011,8 @@ cbjack_stream_destroy(cubeb_stream * stream)
if ( stream - > devs = = DUPLEX | | stream - > devs = = IN_ONLY ) {
for ( unsigned int c = 0 ; c < stream - > in_params . channels ; c + + ) {
if ( stream - > input_ports [ c ] ) {
api_jack_port_unregister ( stream - > context - > jack_client , stream - > input_ports [ c ] ) ;
WRAP ( jack_port_unregister )
( stream - > context - > jack_client , stream - > input_ports [ c ] ) ;
stream - > input_ports [ c ] = NULL ;
}
}
@ -987,7 +1057,8 @@ cbjack_stream_set_volume(cubeb_stream * stm, float volume)
}
static int
cbjack_stream_get_current_device ( cubeb_stream * stm , cubeb_device * * const device )
cbjack_stream_get_current_device ( cubeb_stream * stm ,
cubeb_device * * const device )
{
* device = ( cubeb_device * ) calloc ( 1 , sizeof ( cubeb_device ) ) ;
if ( * device = = NULL )
@ -1012,8 +1083,7 @@ cbjack_stream_get_current_device(cubeb_stream * stm, cubeb_device ** const devic
}
static int
cbjack_stream_device_destroy ( cubeb_stream * /*stream*/ ,
cubeb_device * device )
cbjack_stream_device_destroy ( cubeb_stream * /*stream*/ , cubeb_device * device )
{
if ( device - > input_name )
free ( device - > input_name ) ;
@ -1042,7 +1112,7 @@ cbjack_enumerate_devices(cubeb * context, cubeb_device_type type,
if ( type & CUBEB_DEVICE_TYPE_OUTPUT ) {
cubeb_device_info * cur = & devices [ collection - > count ] ;
cur - > device_id = JACK_DEFAULT_OUT ;
cur - > devid = ( cubeb_devid ) cur - > device_id ;
cur - > devid = ( cubeb_devid ) cur - > device_id ;
cur - > friendly_name = JACK_DEFAULT_OUT ;
cur - > group_id = JACK_DEFAULT_OUT ;
cur - > vendor_name = JACK_DEFAULT_OUT ;
@ -1057,13 +1127,13 @@ cbjack_enumerate_devices(cubeb * context, cubeb_device_type type,
cur - > default_rate = rate ;
cur - > latency_lo = 0 ;
cur - > latency_hi = 0 ;
collection - > count + = 1 ;
collection - > count + = 1 ;
}
if ( type & CUBEB_DEVICE_TYPE_INPUT ) {
cubeb_device_info * cur = & devices [ collection - > count ] ;
cur - > device_id = JACK_DEFAULT_IN ;
cur - > devid = ( cubeb_devid ) cur - > device_id ;
cur - > devid = ( cubeb_devid ) cur - > device_id ;
cur - > friendly_name = JACK_DEFAULT_IN ;
cur - > group_id = JACK_DEFAULT_IN ;
cur - > vendor_name = JACK_DEFAULT_IN ;
@ -1091,6 +1161,6 @@ cbjack_device_collection_destroy(cubeb * /*ctx*/,
cubeb_device_collection * collection )
{
XASSERT ( collection ) ;
delete [ ] collection - > device ;
delete [ ] collection - > device ;
return CUBEB_OK ;
}