static pthread_t mainThread_;
static char *jackErr_ = NULL;
static const char* clientName_ = "PortAudio";
+static const char* port_regex_suffix = ":.*";
#define STRINGIZE_HELPER(expr) #expr
#define STRINGIZE(expr) STRINGIZE_HELPER(expr)
/* ---- 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
const char **jack_ports = NULL;
char **client_names = NULL;
- char *regex_pattern = NULL;
+ char *port_regex_string = NULL;
+ char *device_name_regex_escaped = 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);
int port_index, client_index, i;
double globalSampleRate;
regex_t port_regex;
* associated with the previous list */
PaUtil_FreeAllAllocations( jackApi->deviceInfoMemory );
- regex_pattern = PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory, jack_client_name_size() + 3 );
+ port_regex_string = PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory, port_regex_size );
+ device_name_regex_escaped = PaUtil_GroupAllocateMemory(
+ jackApi->deviceInfoMemory, device_name_regex_escaped_size );
tmp_client_name = PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory, jack_client_name_size() );
/* We can only retrieve the list of clients indirectly, by first
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 */
/* 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( device_name_regex_escaped,
+ client_names[client_index],
+ device_name_regex_escaped_size );
+ strncpy( port_regex_string, device_name_regex_escaped, port_regex_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.;
}
/* ... 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.;
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;
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 );
+ // 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_length = jack_client_name_size() * 2 + 1;
+ char *regex_escaped_client_name = PaUtil_GroupAllocateMemory(
+ jackHostApi->deviceInfoMemory, regex_escaped_client_name_length );
+ unsigned long regex_size = jack_client_name_size() * 2 + 1 + strlen(port_regex_suffix);
+ char *regex_pattern = PaUtil_GroupAllocateMemory( jackHostApi->deviceInfoMemory, regex_size );
const char **jack_ports = NULL;
/* int jack_max_buffer_size = jack_get_buffer_size( jackHostApi->jack_client ); */
int i;
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_escaped_client_name,
+ hostApi->deviceInfos[ inputParameters->device ]->name,
+ regex_escaped_client_name_length );
+ strncpy( regex_pattern, regex_escaped_client_name, regex_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++ )
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_escaped_client_name,
+ hostApi->deviceInfos[ outputParameters->device ]->name,
+ regex_escaped_client_name_length );
+ strncpy( regex_pattern, regex_escaped_client_name, regex_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++ )
error:
return result;
}
+