Index: portaudio-v19/src/common/pa_dynload.c =================================================================== --- portaudio-v19/src/common/pa_dynload.c (revision 0) +++ portaudio-v19/src/common/pa_dynload.c (working copy) @@ -0,0 +1,108 @@ +/* + * $Id: pa_dynlink.c 1339 2008-02-15 07:50:33Z rossb $ + * Portable Audio I/O Library + * dynamic library helper + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 2008 Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup common_src + + @brief dynamic library helper functions. +*/ + +#if defined(WIN32) +#include +#else +#include +#endif + +#include "pa_debugprint.h" +#include "pa_dynload.h" + +#if !defined(NULL) +#define NULL 0 +#endif + +paDynamicLib PaDL_Load( char *name ) +{ + paDynamicLib lib; + +#if defined(WIN32) + lib = LoadLibrary(name); +#else + lib = dlopen(name, RTLD_LAZY); +#endif + + if (!lib) { +#if defined(WIN32) + PA_DEBUG(("Couldn't load %s, error code: %d\n", name, GetLastError())); +#else + PA_DEBUG(("Couldn't load %s, error: %s\n", name, dlerror())); +#endif + } + + return lib; +} + +void PaDL_Unload( paDynamicLib lib ) +{ +#if defined(WIN32) + FreeLibrary(lib); +#else + dlclose(lib); +#endif +} + +void *PaDL_FindSymbol( paDynamicLib lib, char *name ) +{ + void *addr; + +#if defined(WIN32) + addr = (void *) GetProcAddress(lib, name); +#else + addr = dlsym(lib, name); +#endif + + if (addr == NULL) { +#if defined(WIN32) + PA_DEBUG(("Couldn't find %s function, error code: %d\n", name, GetLastError())); +#else + PA_DEBUG(("Couldn't find %s function, error: %s\n", name, dlerror())); +#endif + } + + return addr; +} Index: portaudio-v19/src/common/pa_dynload.h =================================================================== --- portaudio-v19/src/common/pa_dynload.h (revision 0) +++ portaudio-v19/src/common/pa_dynload.h (working copy) @@ -0,0 +1,136 @@ +#ifndef PA_DYNLINK_H +#define PA_DYNLINK_H +/* + * $Id: pa_dynlink.h 1339 2008-02-15 07:50:33Z rossb $ + * Portable Audio I/O Library + * Dynamic library helper + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2008 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup common_src + + @brief Dynamic library helper functions. +*/ + + +#include "pa_debugprint.h" + +#if defined(WIN32) +#include +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#if defined(WIN32) +typedef HANDLE paDynamicLib; +#define PADL_INLINE __inline +#else +typedef void * paDynamicLib; +#define PADL_INLINE inline +#endif + +paDynamicLib PaDL_Load( char *name ); +void PaDL_Unload( paDynamicLib lib ); +void *PaDL_FindSymbol( paDynamicLib lib, char *name ); + +/* A little explanation of what's going on here. + * + * Only one source file should define PADL_DEFINE_POINTERS before including the header which + * defines the functions. This will cause the compiler to dump all of the function pointers + * to a single object file and prevent duplicate symbol definitions during link. + * + * The PADL_FUNC_WITH_RETURN and PADL_FUNC_NO_RETURN macros do two things each: + * 1) Define or reference the variable that contains the actual function pointer + * 2) Define an inline function to pass control to the real function + * + * Since the macros redefine the real functions of the same name, the compiler will make + * sure that the definitions are the same. If not, it will complain. For this to occur, + * the functions MUST be defined in an extern "C" block otherwise the compiler just thinks the + * functions are being overloaded. + * + * The compiler should optimize away the inline function since it just passes control to the real + * function and we should wind up with about the same function call we had before, only now it is + * safer due to the validation. + * + * The PADL_FUNC_WITH_RETURN takes 4 arguments: + * 1) The return type <---| + * 2) The function name | Taken from the real funciton prototype + * 3) The function arguments <---| + * 4) The argument list to pass to the real function + * + * The PADL_FUNC_NO_RETURN takes 3 arguments: + * 1) The function name <---| Taken from the FFmpeg funciton prototype + * 2) The function arguments <---| + * 3) The argument list to pass to the real function + * + * The PADL_FINDSYMBOL macro is responsible for retrieving the address of the real function + * and storing that address in the function pointer variable. + */ +#if defined(PADL_DEFINE_POINTERS) + #define FFX +#else + #define FFX extern +#endif + +#define PADL_FUNC_WITH_RETURN(r, n, a, p) \ + FFX r (*paDynFunc_ ## n ## _fp) a; \ + PADL_INLINE r n a \ + { \ + return paDynFunc_ ## n ## _fp p; \ + } \ + +#define PADL_FUNC_NO_RETURN(n, a, p) \ + FFX void (*paDynFunc_ ## n ## _fp) a; \ + PADL_INLINE void n a \ + { \ + paDynFunc_ ## n ## _fp p; \ + } \ + +#define PADL_FINDSYMBOL(l, f, e) \ + *(void**)& paDynFunc_ ## f ## _fp = PaDL_FindSymbol(l, #f); \ + if (!paDynFunc_ ## f ## _fp) \ + { \ + PA_DEBUG(("Could not locate address of %s\n", #f)); \ + e; \ + } + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* PA_DYNLINK_H */ Index: portaudio-v19/src/hostapi/jack/pa_jack.c =================================================================== --- portaudio-v19/src/hostapi/jack/pa_jack.c (revision 12233) +++ portaudio-v19/src/hostapi/jack/pa_jack.c (working copy) @@ -48,16 +48,22 @@ */ #include -#include #include #include #include #include +#if !defined(_WIN32) #include +#endif #include /* EBUSY */ #include /* sig_atomic_t */ #include +#if defined(_WIN32) +#include +#else #include +#include +#endif #include #include @@ -71,7 +77,13 @@ #include "pa_ringbuffer.h" #include "pa_debugprint.h" +#include "pa_jack_dynload.h" + +#if defined(WIN32) +static DWORD mainThread_; +#else static pthread_t mainThread_; +#endif static char *jackErr_ = NULL; static const char* clientName_ = "PortAudio"; @@ -84,7 +96,7 @@ PaError paErr; \ if( (paErr = (expr)) < paNoError ) \ { \ - if( (paErr) == paUnanticipatedHostError && pthread_self() == mainThread_ ) \ + if( (paErr) == paUnanticipatedHostError && PaJack_IsOnMainThread() ) \ { \ const char *err = jackErr_; \ if (! err ) err = "unknown error"; \ @@ -100,7 +112,7 @@ do { \ if( (expr) == 0 ) \ { \ - if( (code) == paUnanticipatedHostError && pthread_self() == mainThread_ ) \ + if( (code) == paUnanticipatedHostError && PaJack_IsOnMainThread() ) \ { \ const char *err = jackErr_; \ if (!err) err = "unknown error"; \ @@ -166,8 +178,13 @@ int jack_buffer_size; PaHostApiIndex hostApiIndex; +#if defined(WIN32) + HANDLE mtx; + HANDLE cond; +#else pthread_mutex_t mtx; pthread_cond_t cond; +#endif unsigned long inputBase, outputBase; /* For dealing with the process thread */ @@ -224,7 +241,11 @@ PaUtilRingBuffer inFIFO; PaUtilRingBuffer outFIFO; volatile sig_atomic_t data_available; +#if defined(WIN32) + HANDLE data_event; +#else sem_t data_semaphore; +#endif int bytesPerFrame; int samplesPerFrame; @@ -248,6 +269,178 @@ * */ +static void PaJack_InitMainThread( void ) +{ +#if defined(WIN32) + mainThread_ = GetCurrentThreadId(); +#else + mainThread_ = pthread_self(); +#endif +} + +static int PaJack_IsOnMainThread( void ) +{ +#if defined(WIN32) + return GetCurrentThreadId() == mainThread_; +#else + return pthread_self() == mainThread_; +#endif +} + +static void PaJack_InitHostApiMutex( PaJackHostApiRepresentation *hostApi ) +{ +#if defined(WIN32) + ASSERT_CALL( (hostApi->mtx = CreateMutex( NULL, FALSE, NULL )) == NULL, 0 ); +#else + ASSERT_CALL( pthread_mutex_init( &hostApi->mtx, NULL ), 0 ); +#endif +} + +static void PaJack_TerminateHostApiMutex( PaJackHostApiRepresentation *hostApi ) +{ +#if defined(WIN32) + CloseHandle( hostApi->mtx ); + hostApi->mtx = NULL; +#else + ASSERT_CALL( pthread_mutex_destroy( &hostApi->mtx ), 0 ); +#endif +} + +static void PaJack_LockHostAPI( PaJackHostApiRepresentation *hostApi ) +{ +#if defined(WIN32) + ASSERT_CALL( WaitForSingleObject( hostApi->mtx, INFINITE ), 0 ); +#else + ASSERT_CALL( pthread_mutex_lock( &hostApi->mtx ), 0 ); +#endif +} + +/* returns 0 on success, -1 on failure ??? or similar. document make sure it's correct etc */ +static int PaJack_TryLockHostAPI( PaJackHostApiRepresentation *hostApi ) +{ +#if defined(WIN32) + return WaitForSingleObject( hostApi->mtx, 0 ) == WAIT_OBJECT_0 ? 0 : -1; +#else + return ( pthread_mutex_trylock( &hostApi->mtx ) == 0 ? 0 : -1 ); +#endif +} + +static void PaJack_UnlockHostAPI( PaJackHostApiRepresentation *hostApi ) +{ +#if defined(WIN32) + ReleaseMutex( hostApi->mtx ); +#else + ASSERT_CALL( pthread_mutex_unlock( &hostApi->mtx ), 0 ); +#endif +} + +static void PaJack_InitCommandSync( PaJackHostApiRepresentation *hostApi ) +{ +#if defined(WIN32) + hostApi->cond = CreateEvent( NULL, FALSE, FALSE, NULL ); + assert( hostApi->cond ); +#else + ASSERT_CALL( pthread_cond_init( &hostApi->cond, NULL ), 0 ); +#endif +} + +static void PaJack_TerminateCommandSync( PaJackHostApiRepresentation *hostApi ) +{ +#if defined(WIN32) + CloseHandle( hostApi->cond ); + hostApi->cond = NULL; +#else + ASSERT_CALL( pthread_cond_init( &hostApi->cond, NULL ), 0 ); +#endif +} + +static void PaJack_SignalCommandCompleted( PaJackHostApiRepresentation *hostApi ) +{ +#if defined(WIN32) + ASSERT_CALL( !SetEvent( hostApi->cond ), 0 ); +#else + ASSERT_CALL( pthread_cond_signal( &hostApi->cond ), 0 ); +#endif +} + +static PaError WaitForCommandToComplete( PaJackHostApiRepresentation *hostApi ) +{ + PaError result = paNoError; + +#if defined(WIN32) + switch( SignalObjectAndWait( hostApi->mtx, hostApi->cond, 10 * 60 * 1000, FALSE ) ) + { + case WAIT_OBJECT_0: + result = paNoError; + break; + case WAIT_TIMEOUT: + result = paTimedOut; + break; + default: + result = paInternalError; + break; + } + PaJack_LockHostAPI( hostApi ); +#else + int err = 0; + PaTime pt = PaUtil_GetTime(); + struct timespec ts; + + ts.tv_sec = (time_t) floor( pt + 10 * 60 /* 10 minutes */ ); + ts.tv_nsec = (long) ((pt - floor( pt )) * 1000000000); + /* XXX: Best enclose in loop, in case of spurious wakeups? */ + err = pthread_cond_timedwait( &hostApi->cond, &hostApi->mtx, &ts ); + + /* Make sure we didn't time out */ + UNLESS( err != ETIMEDOUT, paTimedOut ); + UNLESS( !err, paInternalError ); +error: +#endif + + return result; +} + +static void PaJack_InitStreamDataSync( PaJackStream *stream ) +{ +#if defined(WIN32) + stream->data_event = CreateEvent( NULL, FALSE, FALSE, NULL ); + assert( stream->data_event ); +#else + ASSERT_CALL( sem_init( &stream->data_semaphore, 0, 0 ) == -1, 0); +#endif +} + +static void PaJack_TerminateStreamDataSync( PaJackStream *stream ) +{ +#if defined(WIN32) + CloseHandle( stream->data_event ); +#else + sem_destroy( &stream->data_semaphore ); +#endif +} + +static void PaJack_SignalStreamDataAvailable( PaJackStream *stream ) +{ +#if defined(WIN32) + SetEvent( stream->data_event ); +#else + sem_post( &stream->data_semaphore ); +#endif +} + +static void PaJack_WaitForStreamDataToBecomeAvailable( PaJackStream *stream ) +{ +#if defined(WIN32) + WaitForSingleObject( stream->data_event, INFINITE ); +#else + sem_wait( &stream->data_semaphore ); +#endif +} + +#if defined(WIN32) +#define snprintf _snprintf +#endif + /* ---- blocking emulation layer ---- */ /* Allocate buffer. */ @@ -294,7 +487,7 @@ if( !stream->data_available ) { stream->data_available = 1; - sem_post( &stream->data_semaphore ); + PaJack_SignalStreamDataAvailable( stream ); } return paContinue; } @@ -333,7 +526,7 @@ } stream->data_available = 0; - sem_init( &stream->data_semaphore, 0, 0 ); + PaJack_InitStreamDataSync( stream ); error: return result; @@ -345,7 +538,7 @@ BlockingTermFIFO( &stream->inFIFO ); BlockingTermFIFO( &stream->outFIFO ); - sem_destroy( &stream->data_semaphore ); + PaJack_TerminateStreamDataSync( stream ); } static PaError BlockingReadStream( PaStream* s, void *data, unsigned long numFrames ) @@ -367,7 +560,7 @@ if( stream->data_available ) stream->data_available = 0; else - sem_wait( &stream->data_semaphore ); + PaJack_WaitForStreamDataToBecomeAvailable( stream ); } } @@ -405,7 +598,7 @@ if( stream->data_available ) stream->data_available = 0; else - sem_wait( &stream->data_semaphore ); + PaJack_WaitForStreamDataToBecomeAvailable( stream ); } } @@ -438,7 +631,7 @@ while( PaUtil_GetRingBufferReadAvailable( &stream->outFIFO ) > 0 ) { stream->data_available = 0; - sem_wait( &stream->data_semaphore ); + PaJack_WaitForStreamDataToBecomeAvailable( stream ); } return 0; } @@ -469,7 +662,6 @@ char *regex_pattern = NULL; int port_index, client_index, i; double globalSampleRate; - regex_t port_regex; unsigned long numClients = 0, numPorts = 0; char *tmp_client_name = NULL; @@ -477,9 +669,6 @@ commonApi->info.defaultOutputDevice = paNoDevice; commonApi->info.deviceCount = 0; - /* Parse the list of ports, using a regex to grab the client names */ - ASSERT_CALL( regcomp( &port_regex, "^[^:]*", REG_EXTENDED ), 0 ); - /* since we are rebuilding the list of devices, free all memory * associated with the previous list */ PaUtil_FreeAllAllocations( jackApi->deviceInfoMemory ); @@ -492,7 +681,7 @@ * according to the client_name:port_name convention (which is * enforced by jackd) * A: If jack_get_ports returns NULL, there's nothing for us to do */ - UNLESS( (jack_ports = jack_get_ports( jackApi->jack_client, "", "", 0 )) && jack_ports[0], paNoError ); + UNLESS( (jack_ports = jack_get_ports( jackApi->jack_client, "^[^:]*", "", 0 )) && jack_ports[0], paNoError ); /* Find number of ports */ while( jack_ports[numPorts] ) ++numPorts; @@ -504,16 +693,15 @@ for( numClients = 0, port_index = 0; jack_ports[port_index] != NULL; port_index++ ) { int client_seen = FALSE; - regmatch_t match_info; const char *port = jack_ports[port_index]; + const char *colon; /* 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()); - 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'; + UNLESS( colon = strchr(port, ':'), paInternalError ); + assert(colon - port < jack_client_name_size()); + memcpy( tmp_client_name, port, colon - port ); + tmp_client_name[colon - port] = '\0'; /* do we know about this port's client yet? */ for( i = 0; i < numClients; i++ ) @@ -599,7 +787,7 @@ * We don't care what they are, we just care how many */ curDevInfo->maxInputChannels++; } - free(clientPorts); + jack_free(clientPorts); } /* ... what are your input ports (that we could output to)? */ @@ -620,7 +808,7 @@ * We don't care what they are, we just care how many */ curDevInfo->maxOutputChannels++; } - free(clientPorts); + jack_free(clientPorts); } /* Add this client to the list of devices */ @@ -633,8 +821,7 @@ } error: - regfree( &port_regex ); - free( jack_ports ); + jack_free( jack_ports ); return result; } @@ -647,7 +834,7 @@ static void JackErrorCallback( const char *msg ) { - if( pthread_self() == mainThread_ ) + if( PaJack_IsOnMainThread() ) { assert( msg ); jackErr_ = realloc( jackErr_, strlen( msg ) + 1 ); @@ -667,11 +854,10 @@ } /* Make sure that the main thread doesn't get stuck waiting on the condition */ - ASSERT_CALL( pthread_mutex_lock( &jackApi->mtx ), 0 ); + PaJack_LockHostAPI( jackApi ); jackApi->jackIsDown = 1; - ASSERT_CALL( pthread_cond_signal( &jackApi->cond ), 0 ); - ASSERT_CALL( pthread_mutex_unlock( &jackApi->mtx ), 0 ); - + PaJack_SignalCommandCompleted( jackApi ); + PaJack_UnlockHostAPI( jackApi ); } static int JackSrCb( jack_nframes_t nframes, void *arg ) @@ -706,18 +892,20 @@ PaHostApiIndex hostApiIndex ) { PaError result = paNoError; - PaJackHostApiRepresentation *jackHostApi; + PaJackHostApiRepresentation *jackHostApi = NULL; int activated = 0; jack_status_t jackStatus = 0; *hostApi = NULL; /* Initialize to NULL */ + UNLESS( PaJack_Load(), paNoError ); + UNLESS( jackHostApi = (PaJackHostApiRepresentation*) PaUtil_AllocateMemory( sizeof(PaJackHostApiRepresentation) ), paInsufficientMemory ); UNLESS( jackHostApi->deviceInfoMemory = PaUtil_CreateAllocationGroup(), paInsufficientMemory ); - mainThread_ = pthread_self(); - ASSERT_CALL( pthread_mutex_init( &jackHostApi->mtx, NULL ), 0 ); - ASSERT_CALL( pthread_cond_init( &jackHostApi->cond, NULL ), 0 ); + PaJack_InitMainThread(); + PaJack_InitHostApiMutex( jackHostApi ); + PaJack_InitCommandSync( jackHostApi ); /* Try to become a client of the JACK server. If we cannot do * this, then this API cannot be used. @@ -803,6 +991,9 @@ PaUtil_FreeMemory( jackHostApi ); } + + PaJack_Unload(); + return result; } @@ -815,8 +1006,8 @@ * client is not allowed to have any ports connected */ ASSERT_CALL( jack_deactivate( jackHostApi->jack_client ), 0 ); - ASSERT_CALL( pthread_mutex_destroy( &jackHostApi->mtx ), 0 ); - ASSERT_CALL( pthread_cond_destroy( &jackHostApi->cond ), 0 ); + PaJack_TerminateHostApiMutex( jackHostApi ); + PaJack_TerminateCommandSync( jackHostApi ); ASSERT_CALL( jack_client_close( jackHostApi->jack_client ), 0 ); @@ -830,6 +1021,8 @@ free( jackErr_ ); jackErr_ = NULL; + + PaJack_Unload(); } static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, @@ -997,39 +1190,19 @@ PaUtil_FreeMemory( stream ); } -static PaError WaitCondition( PaJackHostApiRepresentation *hostApi ) -{ - PaError result = paNoError; - int err = 0; - PaTime pt = PaUtil_GetTime(); - struct timespec ts; - - ts.tv_sec = (time_t) floor( pt + 10 * 60 /* 10 minutes */ ); - ts.tv_nsec = (long) ((pt - floor( pt )) * 1000000000); - /* XXX: Best enclose in loop, in case of spurious wakeups? */ - err = pthread_cond_timedwait( &hostApi->cond, &hostApi->mtx, &ts ); - - /* Make sure we didn't time out */ - UNLESS( err != ETIMEDOUT, paTimedOut ); - UNLESS( !err, paInternalError ); - -error: - return result; -} - static PaError AddStream( PaJackStream *stream ) { PaError result = paNoError; PaJackHostApiRepresentation *hostApi = stream->hostApi; /* Add to queue of streams that should be processed */ - ASSERT_CALL( pthread_mutex_lock( &hostApi->mtx ), 0 ); + PaJack_LockHostAPI( hostApi ); if( !hostApi->jackIsDown ) { hostApi->toAdd = stream; /* Unlock mutex and await signal from processing thread */ - result = WaitCondition( stream->hostApi ); + result = WaitForCommandToComplete( stream->hostApi ); } - ASSERT_CALL( pthread_mutex_unlock( &hostApi->mtx ), 0 ); + PaJack_UnlockHostAPI( hostApi ); ENSURE_PA( result ); UNLESS( !hostApi->jackIsDown, paDeviceUnavailable ); @@ -1045,14 +1218,14 @@ PaJackHostApiRepresentation *hostApi = stream->hostApi; /* Add to queue over streams that should be processed */ - ASSERT_CALL( pthread_mutex_lock( &hostApi->mtx ), 0 ); + PaJack_LockHostAPI( hostApi ); if( !hostApi->jackIsDown ) { hostApi->toRemove = stream; /* Unlock mutex and await signal from processing thread */ - result = WaitCondition( stream->hostApi ); + result = WaitForCommandToComplete( stream->hostApi ); } - ASSERT_CALL( pthread_mutex_unlock( &hostApi->mtx ), 0 ); + PaJack_UnlockHostAPI( hostApi ); ENSURE_PA( result ); error: @@ -1165,7 +1338,7 @@ stream->isBlockingStream = !streamCallback; if( stream->isBlockingStream ) { - float latency = 0.001; /* 1ms is the absolute minimum we support */ + PaTime latency = 0.001f; /* 1ms is the absolute minimum we support */ int minimum_buffer_frames = 0; if( inputParameters && inputParameters->suggestedLatency > latency ) @@ -1245,7 +1418,7 @@ break; } } - free( jack_ports ); + jack_free( jack_ports ); UNLESS( !err, paInsufficientMemory ); /* Fewer ports than expected? */ @@ -1269,7 +1442,7 @@ break; } } - free( jack_ports ); + jack_free( jack_ports ); UNLESS( !err , paInsufficientMemory ); /* Fewer ports than expected? */ @@ -1423,9 +1596,9 @@ const double jackSr = jack_get_sample_rate( hostApi->jack_client ); int err; - if( (err = pthread_mutex_trylock( &hostApi->mtx )) != 0 ) + if( (err = PaJack_TryLockHostAPI( hostApi )) != 0 ) { - assert( err == EBUSY ); + assert( err ); return paNoError; } @@ -1484,11 +1657,11 @@ if( queueModified ) { /* Signal that we've done what was asked of us */ - ASSERT_CALL( pthread_cond_signal( &hostApi->cond ), 0 ); + PaJack_SignalCommandCompleted( hostApi ); } error: - ASSERT_CALL( pthread_mutex_unlock( &hostApi->mtx ), 0 ); + PaJack_UnlockHostAPI( hostApi ); return result; } @@ -1517,7 +1690,7 @@ if( stream->doStart ) { /* If we can't obtain a lock, we'll try next time */ - int err = pthread_mutex_trylock( &stream->hostApi->mtx ); + int err = PaJack_TryLockHostAPI( stream->hostApi ); if( !err ) { if( stream->doStart ) /* Could potentially change before obtaining the lock */ @@ -1525,12 +1698,12 @@ stream->is_active = 1; stream->doStart = 0; PA_DEBUG(( "%s: Starting stream\n", __FUNCTION__ )); - ASSERT_CALL( pthread_cond_signal( &stream->hostApi->cond ), 0 ); + PaJack_SignalCommandCompleted( hostApi ); stream->callbackResult = paContinue; stream->isSilenced = 0; } - ASSERT_CALL( pthread_mutex_unlock( &stream->hostApi->mtx ), 0 ); + PaJack_UnlockHostAPI( stream->hostApi ); } else assert( err == EBUSY ); @@ -1568,15 +1741,15 @@ if( !stream->is_active ) /* Ok, signal to the main thread that we've carried out the operation */ { /* If we can't obtain a lock, we'll try next time */ - int err = pthread_mutex_trylock( &stream->hostApi->mtx ); + int err = PaJack_TryLockHostAPI( stream->hostApi ); if( !err ) { stream->doStop = stream->doAbort = 0; - ASSERT_CALL( pthread_cond_signal( &stream->hostApi->cond ), 0 ); - ASSERT_CALL( pthread_mutex_unlock( &stream->hostApi->mtx ), 0 ); + PaJack_SignalCommandCompleted( stream->hostApi ); + PaJack_UnlockHostAPI( stream->hostApi ); } else - assert( err == EBUSY ); + assert( err ); } } } @@ -1622,11 +1795,11 @@ /* Enable processing */ - ASSERT_CALL( pthread_mutex_lock( &stream->hostApi->mtx ), 0 ); + PaJack_LockHostAPI( stream->hostApi ); stream->doStart = 1; /* Wait for stream to be started */ - result = WaitCondition( stream->hostApi ); + result = WaitForCommandToComplete( stream->hostApi ); /* do { @@ -1638,7 +1811,7 @@ stream->doStart = 0; stream->is_active = 0; /* Cancel any processing */ } - ASSERT_CALL( pthread_mutex_unlock( &stream->hostApi->mtx ), 0 ); + PaJack_UnlockHostAPI( stream->hostApi ); ENSURE_PA( result ); @@ -1657,15 +1830,15 @@ if( stream->isBlockingStream ) BlockingWaitEmpty ( stream ); - ASSERT_CALL( pthread_mutex_lock( &stream->hostApi->mtx ), 0 ); + PaJack_LockHostAPI( stream->hostApi ); if( abort ) stream->doAbort = 1; else stream->doStop = 1; /* Wait for stream to be stopped */ - result = WaitCondition( stream->hostApi ); - ASSERT_CALL( pthread_mutex_unlock( &stream->hostApi->mtx ), 0 ); + result = WaitForCommandToComplete( stream->hostApi ); + PaJack_UnlockHostAPI( stream->hostApi ); ENSURE_PA( result ); UNLESS( !stream->is_active, paInternalError ); Index: portaudio-v19/src/hostapi/jack/pa_jack_dynload.c =================================================================== --- portaudio-v19/src/hostapi/jack/pa_jack_dynload.c (revision 0) +++ portaudio-v19/src/hostapi/jack/pa_jack_dynload.c (working copy) @@ -0,0 +1,162 @@ +/* + * $Id: pa_jack.c 1668 2011-05-02 17:07:11Z rossb $ + * PortAudio Portable Real-Time Audio Library + * Latest Version at: http://www.portaudio.com + * JACK Implementation by Joshua Haberman + * + * Copyright (c) 2004 Stefan Westerfeld + * Copyright (c) 2004 Arve Knudsen + * Copyright (c) 2002 Joshua Haberman + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** + @file + @ingroup hostapi_src +*/ + +#define PADL_DEFINE_POINTERS +#include "pa_dynload.h" +#include "pa_jack_dynload.h" + +#if defined(PA_DYNAMIC_JACK) +static paDynamicLib jacklib = NULL; +#endif + +int PaJack_Load(void) +{ +#if !defined(PA_DYNAMIC_JACK) + return 1; +#else + +#if defined(__APPLE__) + jacklib = PaDL_Load("libjack.dylib"); +#elif defined(_WIN64) + jacklib = PaDL_Load("libjack64.dll"); +#elif defined(WIN32) + jacklib = PaDL_Load("libjack.dll"); +#else + jacklib = PaDL_Load("libjack.so"); +#endif + + if (!jacklib) { + return 0; + } + + PADL_FINDSYMBOL(jacklib, jack_client_name_size, goto error); + PADL_FINDSYMBOL(jacklib, jack_client_name_size, goto error); + PADL_FINDSYMBOL(jacklib, jack_get_ports, goto error); + PADL_FINDSYMBOL(jacklib, jack_get_sample_rate, goto error); + PADL_FINDSYMBOL(jacklib, jack_get_ports, goto error); + PADL_FINDSYMBOL(jacklib, jack_port_by_name, goto error); + PADL_FINDSYMBOL(jacklib, jack_port_get_latency, goto error); + PADL_FINDSYMBOL(jacklib, jack_free, goto error); + PADL_FINDSYMBOL(jacklib, jack_get_ports, goto error); + PADL_FINDSYMBOL(jacklib, jack_port_by_name, goto error); + PADL_FINDSYMBOL(jacklib, jack_port_get_latency, goto error); + PADL_FINDSYMBOL(jacklib, jack_free, goto error); + PADL_FINDSYMBOL(jacklib, jack_client_open, goto error); + PADL_FINDSYMBOL(jacklib, jack_on_shutdown, goto error); + PADL_FINDSYMBOL(jacklib, jack_set_error_function, goto error); + PADL_FINDSYMBOL(jacklib, jack_get_buffer_size, goto error); + PADL_FINDSYMBOL(jacklib, jack_set_sample_rate_callback, goto error); + PADL_FINDSYMBOL(jacklib, jack_set_xrun_callback, goto error); + PADL_FINDSYMBOL(jacklib, jack_set_process_callback, goto error); + PADL_FINDSYMBOL(jacklib, jack_activate, goto error); + PADL_FINDSYMBOL(jacklib, jack_deactivate, goto error); + PADL_FINDSYMBOL(jacklib, jack_client_close, goto error); + PADL_FINDSYMBOL(jacklib, jack_deactivate, goto error); + PADL_FINDSYMBOL(jacklib, jack_client_close, goto error); + PADL_FINDSYMBOL(jacklib, jack_get_sample_rate, goto error); + PADL_FINDSYMBOL(jacklib, jack_port_unregister, goto error); + PADL_FINDSYMBOL(jacklib, jack_port_unregister, goto error); + PADL_FINDSYMBOL(jacklib, jack_port_name_size, goto error); + PADL_FINDSYMBOL(jacklib, jack_client_name_size, goto error); + PADL_FINDSYMBOL(jacklib, jack_get_sample_rate, goto error); + PADL_FINDSYMBOL(jacklib, jack_get_sample_rate, goto error); + PADL_FINDSYMBOL(jacklib, jack_port_name_size, goto error); + PADL_FINDSYMBOL(jacklib, jack_port_register, goto error); + PADL_FINDSYMBOL(jacklib, jack_port_name_size, goto error); + PADL_FINDSYMBOL(jacklib, jack_port_register, goto error); + PADL_FINDSYMBOL(jacklib, jack_get_ports, goto error); + PADL_FINDSYMBOL(jacklib, jack_port_by_name, goto error); + PADL_FINDSYMBOL(jacklib, jack_free, goto error); + PADL_FINDSYMBOL(jacklib, jack_get_ports, goto error); + PADL_FINDSYMBOL(jacklib, jack_port_by_name, goto error); + PADL_FINDSYMBOL(jacklib, jack_free, goto error); + PADL_FINDSYMBOL(jacklib, jack_port_get_latency, goto error); + PADL_FINDSYMBOL(jacklib, jack_get_buffer_size, goto error); + PADL_FINDSYMBOL(jacklib, jack_port_get_latency, goto error); + PADL_FINDSYMBOL(jacklib, jack_get_buffer_size, goto error); + PADL_FINDSYMBOL(jacklib, jack_frame_time, goto error); + PADL_FINDSYMBOL(jacklib, jack_get_sample_rate, goto error); + PADL_FINDSYMBOL(jacklib, jack_frame_time, goto error); + PADL_FINDSYMBOL(jacklib, jack_port_get_latency, goto error); + PADL_FINDSYMBOL(jacklib, jack_port_get_latency, goto error); + PADL_FINDSYMBOL(jacklib, jack_port_get_buffer, goto error); + PADL_FINDSYMBOL(jacklib, jack_port_get_buffer, goto error); + PADL_FINDSYMBOL(jacklib, jack_get_sample_rate, goto error); + PADL_FINDSYMBOL(jacklib, jack_port_get_buffer, goto error); + PADL_FINDSYMBOL(jacklib, jack_connect, goto error); + PADL_FINDSYMBOL(jacklib, jack_port_name, goto error); + PADL_FINDSYMBOL(jacklib, jack_connect, goto error); + PADL_FINDSYMBOL(jacklib, jack_port_name, goto error); + PADL_FINDSYMBOL(jacklib, jack_port_connected, goto error); + PADL_FINDSYMBOL(jacklib, jack_port_disconnect, goto error); + PADL_FINDSYMBOL(jacklib, jack_port_connected, goto error); + PADL_FINDSYMBOL(jacklib, jack_port_disconnect, goto error); + PADL_FINDSYMBOL(jacklib, jack_frame_time, goto error); + PADL_FINDSYMBOL(jacklib, jack_client_name_size, goto error); + PADL_FINDSYMBOL(jacklib, jack_get_client_name, goto error); + + return 1; + +error: + + PaJack_Unload(); + + return 0; +#endif +} + +void PaJack_Unload(void) +{ +#if defined(PA_DYNAMIC_JACK) + if (jacklib) { + PaDL_Unload(jacklib); + jacklib = NULL; + } +#endif +} Index: portaudio-v19/src/hostapi/jack/pa_jack_dynload.h =================================================================== --- portaudio-v19/src/hostapi/jack/pa_jack_dynload.h (revision 0) +++ portaudio-v19/src/hostapi/jack/pa_jack_dynload.h (working copy) @@ -0,0 +1,224 @@ +/* + * $Id: pa_jack.c 1668 2011-05-02 17:07:11Z rossb $ + * PortAudio Portable Real-Time Audio Library + * Latest Version at: http://www.portaudio.com + * JACK Implementation by Joshua Haberman + * + * Copyright (c) 2004 Stefan Westerfeld + * Copyright (c) 2004 Arve Knudsen + * Copyright (c) 2002 Joshua Haberman + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** + @file + @ingroup hostapi_src +*/ +#ifndef INCLUDED_PA_JACK_DYNLINK_H +#define INCLUDED_PA_JACK_DYNLINK_H + +#include + +#include "pa_dynload.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#if defined(PA_DYNAMIC_JACK) + +PADL_FUNC_WITH_RETURN( + int, + jack_activate, + (jack_client_t *client), + (client) +); +PADL_FUNC_WITH_RETURN( + int, + jack_client_close, + (jack_client_t *client), + (client) +); +PADL_FUNC_WITH_RETURN( + int, + jack_client_name_size, + (void), + () +); +PADL_FUNC_WITH_RETURN( + jack_client_t *, + jack_client_open, + (const char *client_name, jack_options_t options, jack_status_t *status, ...), + (client_name, options, status) +); +PADL_FUNC_WITH_RETURN( + int, + jack_connect, + (jack_client_t *client, const char *source_port, const char *destination_port), + (client, source_port, destination_port) +); +PADL_FUNC_WITH_RETURN( + int, + jack_deactivate, + (jack_client_t *client), + (client) +); +PADL_FUNC_WITH_RETURN( + jack_nframes_t, + jack_frame_time, + (const jack_client_t *client), + (client) +); +PADL_FUNC_NO_RETURN( + jack_free, + (void *ptr), + (ptr) +); +PADL_FUNC_WITH_RETURN( + jack_nframes_t, + jack_get_buffer_size, + (jack_client_t *client), + (client) +); +PADL_FUNC_WITH_RETURN( + char *, + jack_get_client_name, + (jack_client_t *client), + (client) +); +PADL_FUNC_WITH_RETURN( + const char **, + jack_get_ports, + (jack_client_t *client, const char *port_name_pattern, const char *type_name_pattern, unsigned long flags), + (client, port_name_pattern, type_name_pattern, flags) +); +PADL_FUNC_WITH_RETURN( + jack_nframes_t, + jack_get_sample_rate, + (jack_client_t *client), + (client) +); +PADL_FUNC_NO_RETURN( + jack_on_shutdown, + (jack_client_t *client, JackShutdownCallback shutdown_callback, void *arg), + (client, shutdown_callback, arg) +); +PADL_FUNC_WITH_RETURN( + jack_port_t *, + jack_port_by_name, + (jack_client_t *client, const char *port_name), + (client, port_name) +); +PADL_FUNC_WITH_RETURN( + int, + jack_port_connected, + (const jack_port_t *port), + (port) +); +PADL_FUNC_WITH_RETURN( + int, + jack_port_disconnect, + (jack_client_t *client, jack_port_t *port), + (client, port) +); +PADL_FUNC_WITH_RETURN( + void *, + jack_port_get_buffer, + (jack_port_t *port, jack_nframes_t frames), + (port, frames) +); +PADL_FUNC_WITH_RETURN( + jack_nframes_t, + jack_port_get_latency, + (jack_port_t *port), + (port) +); +PADL_FUNC_WITH_RETURN( + const char *, + jack_port_name, + (const jack_port_t *port), + (port) +); +PADL_FUNC_WITH_RETURN( + int, + jack_port_name_size, + (void), + () +); +PADL_FUNC_WITH_RETURN( + jack_port_t *, + jack_port_register, + (jack_client_t *client, const char *port_name, const char *port_type, unsigned long flags, unsigned long buffer_size), + (client, port_name, port_type, flags, buffer_size) +); +PADL_FUNC_WITH_RETURN( + int, + jack_port_unregister, + (jack_client_t *client, jack_port_t *port), + (client, port) +); +PADL_FUNC_NO_RETURN( + jack_set_error_function, + (void (*func)(const char *)), + (func) +); +PADL_FUNC_WITH_RETURN( + int, + jack_set_process_callback, + (jack_client_t *client, JackProcessCallback process_callback, void *arg), + (client, process_callback, arg) +); +PADL_FUNC_WITH_RETURN( + int, + jack_set_sample_rate_callback, + (jack_client_t *client, JackSampleRateCallback srate_callback, void *arg), + (client, srate_callback, arg) +); +PADL_FUNC_WITH_RETURN( + int, + jack_set_xrun_callback, + (jack_client_t *client, JackXRunCallback xrun_callback, void *arg), + (client, xrun_callback, arg) +); +#endif /* PA_DYNAMIC_JACK */ + +int PaJack_Load(void); +void PaJack_Unload(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* INCLUDED_PA_JACK_DYNLINK_H */ Index: portaudio-v19/src/os/win/pa_win_hostapis.c =================================================================== --- portaudio-v19/src/os/win/pa_win_hostapis.c (revision 12233) +++ portaudio-v19/src/os/win/pa_win_hostapis.c (working copy) @@ -63,6 +63,7 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); +PaError PaJack_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); #ifdef __cplusplus } @@ -92,6 +93,10 @@ PaWinWdm_Initialize, #endif +#if PA_USE_JACK + PaJack_Initialize, +#endif + #if PA_USE_SKELETON PaSkeleton_Initialize, /* just for testing. last in list so it isn't marked as default. */ #endif