summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/portaudio/src/hostapi/jack/pa_jack.c
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/portaudio/src/hostapi/jack/pa_jack.c')
-rw-r--r--3rdparty/portaudio/src/hostapi/jack/pa_jack.c147
1 files changed, 100 insertions, 47 deletions
diff --git a/3rdparty/portaudio/src/hostapi/jack/pa_jack.c b/3rdparty/portaudio/src/hostapi/jack/pa_jack.c
index a800f8e1dd9..5c20b4420d0 100644
--- a/3rdparty/portaudio/src/hostapi/jack/pa_jack.c
+++ b/3rdparty/portaudio/src/hostapi/jack/pa_jack.c
@@ -53,10 +53,10 @@
#include <stdio.h>
#include <assert.h>
#include <sys/types.h>
-#include <unistd.h>
#include <errno.h> /* EBUSY */
#include <signal.h> /* sig_atomic_t */
#include <math.h>
+#include <pthread.h>
#include <semaphore.h>
#include <jack/types.h>
@@ -71,12 +71,12 @@
#include "pa_ringbuffer.h"
#include "pa_debugprint.h"
+#include "pa_jack.h"
+
static pthread_t mainThread_;
static char *jackErr_ = NULL;
static const char* clientName_ = "PortAudio";
-
-#define STRINGIZE_HELPER(expr) #expr
-#define STRINGIZE(expr) STRINGIZE_HELPER(expr)
+static const char* port_regex_suffix = ":.*";
/* Check PaError */
#define ENSURE_PA(expr) \
@@ -84,13 +84,13 @@ static const char* clientName_ = "PortAudio";
PaError paErr; \
if( (paErr = (expr)) < paNoError ) \
{ \
- if( (paErr) == paUnanticipatedHostError && pthread_self() == mainThread_ ) \
+ if( (paErr) == paUnanticipatedHostError && pthread_equal( pthread_self(), mainThread_ ) ) \
{ \
const char *err = jackErr_; \
if (! err ) err = "unknown error"; \
PaUtil_SetLastHostErrorInfo( paJACK, -1, err ); \
} \
- PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \
+ PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " PA_STRINGIZE( __LINE__ ) "\n" )); \
result = paErr; \
goto error; \
} \
@@ -100,13 +100,13 @@ static const char* clientName_ = "PortAudio";
do { \
if( (expr) == 0 ) \
{ \
- if( (code) == paUnanticipatedHostError && pthread_self() == mainThread_ ) \
+ if( (code) == paUnanticipatedHostError && pthread_equal( pthread_self(), mainThread_ ) ) \
{ \
const char *err = jackErr_; \
if (!err) err = "unknown error"; \
PaUtil_SetLastHostErrorInfo( paJACK, -1, err ); \
} \
- PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \
+ PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " PA_STRINGIZE( __LINE__ ) "\n" )); \
result = (code); \
goto error; \
} \
@@ -275,10 +275,10 @@ static PaError BlockingTermFIFO( PaUtilRingBuffer *rbuf )
static int
BlockingCallback( const void *inputBuffer,
void *outputBuffer,
- unsigned long framesPerBuffer,
- const PaStreamCallbackTimeInfo* timeInfo,
- PaStreamCallbackFlags statusFlags,
- void *userData )
+ unsigned long framesPerBuffer,
+ const PaStreamCallbackTimeInfo* timeInfo,
+ PaStreamCallbackFlags statusFlags,
+ void *userData )
{
struct PaJackStream *stream = (PaJackStream *)userData;
long numBytes = stream->bytesPerFrame * framesPerBuffer;
@@ -449,6 +449,38 @@ BlockingWaitEmpty( PaStream *s )
/* ---- jack driver ---- */
+/* copy null terminated string source to destination, escaping regex characters with '\\' in the process */
+static void copy_string_and_escape_regex_chars( char *destination, const char *source, size_t destbuffersize )
+{
+ assert( destination != source );
+ assert( destbuffersize > 0 );
+
+ char *dest = destination;
+ /* dest_stop is the last location that we can null-terminate the string */
+ char *dest_stop = destination + (destbuffersize - 1);
+
+ const char *src = source;
+
+ while ( *src != '\0' && dest != dest_stop )
+ {
+ const char c = *src;
+ if ( strchr( "\\()[]{}*+?|$^.", c ) != NULL )
+ {
+ if( (dest + 1) == dest_stop )
+ break; /* only proceed if we can write both c and the escape */
+
+ *dest = '\\';
+ dest++;
+ }
+ *dest = c;
+ dest++;
+
+ src++;
+ }
+
+ *dest = '\0';
+}
+
/* BuildDeviceList():
*
* The process of determining a list of PortAudio "devices" from
@@ -470,8 +502,12 @@ static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi )
const char **jack_ports = NULL;
char **client_names = NULL;
- char *regex_pattern = NULL;
- int port_index, client_index, i;
+ char *port_regex_string = NULL;
+ // In the worst case scenario, every character would be escaped, doubling the string size.
+ // Add 1 for null terminator.
+ size_t device_name_regex_escaped_size = jack_client_name_size() * 2 + 1;
+ size_t port_regex_size = device_name_regex_escaped_size + strlen(port_regex_suffix);
+ unsigned long port_index, client_index, i;
double globalSampleRate;
regex_t port_regex;
unsigned long numClients = 0, numPorts = 0;
@@ -488,8 +524,8 @@ static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi )
* associated with the previous list */
PaUtil_FreeAllAllocations( jackApi->deviceInfoMemory );
- regex_pattern = PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory, jack_client_name_size() + 3 );
- tmp_client_name = PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory, jack_client_name_size() );
+ port_regex_string = PaUtil_GroupAllocateZeroInitializedMemory( jackApi->deviceInfoMemory, port_regex_size );
+ tmp_client_name = PaUtil_GroupAllocateZeroInitializedMemory( jackApi->deviceInfoMemory, jack_client_name_size() );
/* We can only retrieve the list of clients indirectly, by first
* asking for a list of all ports, then parsing the port names
@@ -501,7 +537,7 @@ static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi )
while( jack_ports[numPorts] )
++numPorts;
/* At least there will be one port per client :) */
- UNLESS( client_names = PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory, numPorts *
+ UNLESS( client_names = PaUtil_GroupAllocateZeroInitializedMemory( jackApi->deviceInfoMemory, numPorts *
sizeof (char *) ), paInsufficientMemory );
/* Build a list of clients from the list of ports */
@@ -510,11 +546,12 @@ static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi )
int client_seen = FALSE;
regmatch_t match_info;
const char *port = jack_ports[port_index];
+ PA_DEBUG(( "JACK port found: %s\n", port ));
/* extract the client name from the port name, using a regex
* that parses the clientname:portname syntax */
UNLESS( !regexec( &port_regex, port, 1, &match_info, 0 ), paInternalError );
- assert(match_info.rm_eo - match_info.rm_so < jack_client_name_size());
+ assert(match_info.rm_eo - match_info.rm_so <= jack_client_name_size());
memcpy( tmp_client_name, port + match_info.rm_so,
match_info.rm_eo - match_info.rm_so );
tmp_client_name[match_info.rm_eo - match_info.rm_so] = '\0';
@@ -529,7 +566,7 @@ static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi )
if (client_seen)
continue; /* A: Nothing to see here, move along */
- UNLESS( client_names[numClients] = (char*)PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory,
+ UNLESS( client_names[numClients] = (char*)PaUtil_GroupAllocateZeroInitializedMemory( jackApi->deviceInfoMemory,
strlen(tmp_client_name) + 1), paInsufficientMemory );
/* The alsa_pcm client should go in spot 0. If this
@@ -556,7 +593,7 @@ static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi )
/* there is one global sample rate all clients must conform to */
globalSampleRate = jack_get_sample_rate( jackApi->jack_client );
- UNLESS( commonApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory,
+ UNLESS( commonApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateZeroInitializedMemory( jackApi->deviceInfoMemory,
sizeof(PaDeviceInfo*) * numClients ), paInsufficientMemory );
assert( commonApi->info.deviceCount == 0 );
@@ -567,9 +604,9 @@ static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi )
PaDeviceInfo *curDevInfo;
const char **clientPorts = NULL;
- UNLESS( curDevInfo = (PaDeviceInfo*)PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory,
+ UNLESS( curDevInfo = (PaDeviceInfo*)PaUtil_GroupAllocateZeroInitializedMemory( jackApi->deviceInfoMemory,
sizeof(PaDeviceInfo) ), paInsufficientMemory );
- UNLESS( curDevInfo->name = (char*)PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory,
+ UNLESS( curDevInfo->name = (char*)PaUtil_GroupAllocateZeroInitializedMemory( jackApi->deviceInfoMemory,
strlen(client_names[client_index]) + 1 ), paInsufficientMemory );
strcpy( (char *)curDevInfo->name, client_names[client_index] );
@@ -582,11 +619,13 @@ static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi )
/* To determine how many input and output channels are available,
* we re-query jackd with more specific parameters. */
-
- sprintf( regex_pattern, "%s:.*", client_names[client_index] );
+ copy_string_and_escape_regex_chars( port_regex_string,
+ client_names[client_index],
+ device_name_regex_escaped_size );
+ strncat( port_regex_string, port_regex_suffix, port_regex_size );
/* ... what are your output ports (that we could input from)? */
- clientPorts = jack_get_ports( jackApi->jack_client, regex_pattern,
+ clientPorts = jack_get_ports( jackApi->jack_client, port_regex_string,
JACK_PORT_TYPE_FILTER, JackPortIsOutput);
curDevInfo->maxInputChannels = 0;
curDevInfo->defaultLowInputLatency = 0.;
@@ -607,7 +646,7 @@ static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi )
}
/* ... what are your input ports (that we could output to)? */
- clientPorts = jack_get_ports( jackApi->jack_client, regex_pattern,
+ clientPorts = jack_get_ports( jackApi->jack_client, port_regex_string,
JACK_PORT_TYPE_FILTER, JackPortIsInput);
curDevInfo->maxOutputChannels = 0;
curDevInfo->defaultLowOutputLatency = 0.;
@@ -627,6 +666,11 @@ static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi )
free(clientPorts);
}
+ PA_DEBUG(( "Adding JACK device %s with %d input channels and %d output channels\n",
+ client_names[client_index],
+ curDevInfo->maxInputChannels,
+ curDevInfo->maxOutputChannels ));
+
/* Add this client to the list of devices */
commonApi->deviceInfos[client_index] = curDevInfo;
++commonApi->info.deviceCount;
@@ -651,7 +695,7 @@ static void UpdateSampleRate( PaJackStream *stream, double sampleRate )
static void JackErrorCallback( const char *msg )
{
- if( pthread_self() == mainThread_ )
+ if( pthread_equal( pthread_self(), mainThread_ ) )
{
assert( msg );
jackErr_ = realloc( jackErr_, strlen( msg ) + 1 );
@@ -716,7 +760,7 @@ PaError PaJack_Initialize( PaUtilHostApiRepresentation **hostApi,
*hostApi = NULL; /* Initialize to NULL */
UNLESS( jackHostApi = (PaJackHostApiRepresentation*)
- PaUtil_AllocateMemory( sizeof(PaJackHostApiRepresentation) ), paInsufficientMemory );
+ PaUtil_AllocateZeroInitializedMemory( sizeof(PaJackHostApiRepresentation) ), paInsufficientMemory );
UNLESS( jackHostApi->deviceInfoMemory = PaUtil_CreateAllocationGroup(), paInsufficientMemory );
mainThread_ = pthread_self();
@@ -916,7 +960,7 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
#define ABS(x) ( (x) > 0 ? (x) : -(x) )
if( ABS(sampleRate - jack_get_sample_rate(((PaJackHostApiRepresentation *) hostApi)->jack_client )) > 1 )
- return paInvalidSampleRate;
+ return paInvalidSampleRate;
#undef ABS
return paFormatIsSupported;
@@ -937,24 +981,24 @@ static PaError InitializeStream( PaJackStream *stream, PaJackHostApiRepresentati
if( numInputChannels > 0 )
{
UNLESS( stream->local_input_ports =
- (jack_port_t**) PaUtil_GroupAllocateMemory( stream->stream_memory, sizeof(jack_port_t*) * numInputChannels ),
+ (jack_port_t**) PaUtil_GroupAllocateZeroInitializedMemory( stream->stream_memory, sizeof(jack_port_t*) * numInputChannels ),
paInsufficientMemory );
- memset( stream->local_input_ports, 0, sizeof(jack_port_t*) * numInputChannels );
+ /* NOTE: we depend on stream->local_input_ports being zero-initialized */
UNLESS( stream->remote_output_ports =
- (jack_port_t**) PaUtil_GroupAllocateMemory( stream->stream_memory, sizeof(jack_port_t*) * numInputChannels ),
+ (jack_port_t**) PaUtil_GroupAllocateZeroInitializedMemory( stream->stream_memory, sizeof(jack_port_t*) * numInputChannels ),
paInsufficientMemory );
- memset( stream->remote_output_ports, 0, sizeof(jack_port_t*) * numInputChannels );
+ /* NOTE: we depend on stream->remote_output_ports being zero-initialized */
}
if( numOutputChannels > 0 )
{
UNLESS( stream->local_output_ports =
- (jack_port_t**) PaUtil_GroupAllocateMemory( stream->stream_memory, sizeof(jack_port_t*) * numOutputChannels ),
+ (jack_port_t**) PaUtil_GroupAllocateZeroInitializedMemory( stream->stream_memory, sizeof(jack_port_t*) * numOutputChannels ),
paInsufficientMemory );
- memset( stream->local_output_ports, 0, sizeof(jack_port_t*) * numOutputChannels );
+ /* NOTE: we depend on stream->local_output_ports being zero-initialized */
UNLESS( stream->remote_input_ports =
- (jack_port_t**) PaUtil_GroupAllocateMemory( stream->stream_memory, sizeof(jack_port_t*) * numOutputChannels ),
+ (jack_port_t**) PaUtil_GroupAllocateZeroInitializedMemory( stream->stream_memory, sizeof(jack_port_t*) * numOutputChannels ),
paInsufficientMemory );
- memset( stream->remote_input_ports, 0, sizeof(jack_port_t*) * numOutputChannels );
+ /* NOTE: we depend on stream->remote_input_ports being zero-initialized */
}
stream->num_incoming_connections = numInputChannels;
@@ -1077,9 +1121,12 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
PaError result = paNoError;
PaJackHostApiRepresentation *jackHostApi = (PaJackHostApiRepresentation*)hostApi;
PaJackStream *stream = NULL;
- char *port_string = PaUtil_GroupAllocateMemory( jackHostApi->deviceInfoMemory, jack_port_name_size() );
- unsigned long regexSz = jack_client_name_size() + 3;
- char *regex_pattern = PaUtil_GroupAllocateMemory( jackHostApi->deviceInfoMemory, regexSz );
+ char *port_string = PaUtil_GroupAllocateZeroInitializedMemory( jackHostApi->deviceInfoMemory, jack_port_name_size() );
+ // In the worst case every character would be escaped which would double the string length.
+ // Add 1 for null terminator
+ size_t regex_escaped_client_name_size = jack_client_name_size() * 2 + 1;
+ unsigned long regex_size = regex_escaped_client_name_size + strlen(port_regex_suffix);
+ char *regex_pattern = PaUtil_GroupAllocateZeroInitializedMemory( jackHostApi->deviceInfoMemory, regex_size );
const char **jack_ports = NULL;
/* int jack_max_buffer_size = jack_get_buffer_size( jackHostApi->jack_client ); */
int i;
@@ -1159,17 +1206,17 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
#define ABS(x) ( (x) > 0 ? (x) : -(x) )
if( ABS(sampleRate - jackSr) > 1 )
- return paInvalidSampleRate;
+ return paInvalidSampleRate;
#undef ABS
- UNLESS( stream = (PaJackStream*)PaUtil_AllocateMemory( sizeof(PaJackStream) ), paInsufficientMemory );
+ UNLESS( stream = (PaJackStream*)PaUtil_AllocateZeroInitializedMemory( sizeof(PaJackStream) ), paInsufficientMemory );
ENSURE_PA( InitializeStream( stream, jackHostApi, inputChannelCount, outputChannelCount ) );
/* the blocking emulation, if necessary */
stream->isBlockingStream = !streamCallback;
if( stream->isBlockingStream )
{
- float latency = 0.001; /* 1ms is the absolute minimum we support */
+ float latency = 0.001f; /* 1ms is the absolute minimum we support */
int minimum_buffer_frames = 0;
if( inputParameters && inputParameters->suggestedLatency > latency )
@@ -1237,7 +1284,10 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
int err = 0;
/* Get output ports of our capture device */
- snprintf( regex_pattern, regexSz, "%s:.*", hostApi->deviceInfos[ inputParameters->device ]->name );
+ copy_string_and_escape_regex_chars( regex_pattern,
+ hostApi->deviceInfos[ inputParameters->device ]->name,
+ regex_escaped_client_name_size );
+ strncat( regex_pattern, port_regex_suffix, regex_size );
UNLESS( jack_ports = jack_get_ports( jackHostApi->jack_client, regex_pattern,
JACK_PORT_TYPE_FILTER, JackPortIsOutput ), paUnanticipatedHostError );
for( i = 0; i < inputChannelCount && jack_ports[i]; i++ )
@@ -1261,7 +1311,10 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
int err = 0;
/* Get input ports of our playback device */
- snprintf( regex_pattern, regexSz, "%s:.*", hostApi->deviceInfos[ outputParameters->device ]->name );
+ copy_string_and_escape_regex_chars( regex_pattern,
+ hostApi->deviceInfos[ outputParameters->device ]->name,
+ regex_escaped_client_name_size );
+ strncat( regex_pattern, port_regex_suffix, regex_size );
UNLESS( jack_ports = jack_get_ports( jackHostApi->jack_client, regex_pattern,
JACK_PORT_TYPE_FILTER, JackPortIsInput ), paUnanticipatedHostError );
for( i = 0; i < outputChannelCount && jack_ports[i]; i++ )
@@ -1608,7 +1661,7 @@ static PaError StartStream( PaStream *s )
{
int r = jack_connect( stream->jack_client, jack_port_name( stream->remote_output_ports[i] ),
jack_port_name( stream->local_input_ports[i] ) );
- UNLESS( 0 == r || EEXIST == r, paUnanticipatedHostError );
+ UNLESS( 0 == r || EEXIST == r, paUnanticipatedHostError );
}
}
@@ -1618,7 +1671,7 @@ static PaError StartStream( PaStream *s )
{
int r = jack_connect( stream->jack_client, jack_port_name( stream->local_output_ports[i] ),
jack_port_name( stream->remote_input_ports[i] ) );
- UNLESS( 0 == r || EEXIST == r, paUnanticipatedHostError );
+ UNLESS( 0 == r || EEXIST == r, paUnanticipatedHostError );
}
}