moved trunk into place

This commit is contained in:
bjornroche 2008-03-20 14:24:39 +00:00
commit c1e1d067d2
260 changed files with 96276 additions and 0 deletions

View file

@ -0,0 +1,92 @@
/*
* $Id$
* Portable Audio I/O Library UNIX initialization table
*
* 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 unix_src
*/
#include "pa_hostapi.h"
PaError PaJack_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
PaError PaOSS_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
/* Added for IRIX, Pieter, oct 2, 2003: */
PaError PaSGI_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
/* Linux AudioScience HPI */
PaError PaAsiHpi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
/** Note that ALSA is placed before OSS so that the latter is preferred over the
* latter on Linux.
*/
PaUtilHostApiInitializer *paHostApiInitializers[] =
{
#ifdef PA_USE_ALSA
PaAlsa_Initialize,
#endif
#ifdef PA_USE_OSS
PaOSS_Initialize,
#endif
#ifdef PA_USE_JACK
PaJack_Initialize,
#endif
/* Added for IRIX, Pieter, oct 2, 2003: */
#ifdef PA_USE_SGI
PaSGI_Initialize,
#endif
#ifdef PA_USE_ASIHPI
PaAsiHpi_Initialize,
#endif
#ifdef PA_USE_COREAUDIO
PaMacCore_Initialize,
#endif
#ifdef PA_USE_SKELETON
PaSkeleton_Initialize,
#endif
0 /* NULL terminated array */
};
int paDefaultHostApiIndex = 0;

666
src/os/unix/pa_unix_util.c Normal file
View file

@ -0,0 +1,666 @@
/*
* $Id$
* Portable Audio I/O Library
* UNIX platform-specific support functions
*
* Based on the Open Source API proposed by Ross Bencina
* Copyright (c) 1999-2000 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 unix_src
*/
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <assert.h>
#include <string.h> /* For memset */
#include <math.h>
#include <errno.h>
#include "pa_util.h"
#include "pa_unix_util.h"
#include "pa_debugprint.h"
/*
Track memory allocations to avoid leaks.
*/
#if PA_TRACK_MEMORY
static int numAllocations_ = 0;
#endif
void *PaUtil_AllocateMemory( long size )
{
void *result = malloc( size );
#if PA_TRACK_MEMORY
if( result != NULL ) numAllocations_ += 1;
#endif
return result;
}
void PaUtil_FreeMemory( void *block )
{
if( block != NULL )
{
free( block );
#if PA_TRACK_MEMORY
numAllocations_ -= 1;
#endif
}
}
int PaUtil_CountCurrentlyAllocatedBlocks( void )
{
#if PA_TRACK_MEMORY
return numAllocations_;
#else
return 0;
#endif
}
void Pa_Sleep( long msec )
{
#ifdef HAVE_NANOSLEEP
struct timespec req = {0}, rem = {0};
PaTime time = msec / 1.e3;
req.tv_sec = (time_t)time;
assert(time - req.tv_sec < 1.0);
req.tv_nsec = (long)((time - req.tv_sec) * 1.e9);
nanosleep(&req, &rem);
/* XXX: Try sleeping the remaining time (contained in rem) if interrupted by a signal? */
#else
while( msec > 999 ) /* For OpenBSD and IRIX, argument */
{ /* to usleep must be < 1000000. */
usleep( 999000 );
msec -= 999;
}
usleep( msec * 1000 );
#endif
}
/* *** NOT USED YET: ***
static int usePerformanceCounter_;
static double microsecondsPerTick_;
*/
void PaUtil_InitializeClock( void )
{
/* TODO */
}
PaTime PaUtil_GetTime( void )
{
#ifdef HAVE_CLOCK_GETTIME
struct timespec tp;
clock_gettime(CLOCK_REALTIME, &tp);
return (PaTime)(tp.tv_sec + tp.tv_nsec / 1.e9);
#else
struct timeval tv;
gettimeofday( &tv, NULL );
return (PaTime) tv.tv_usec / 1000000. + tv.tv_sec;
#endif
}
PaError PaUtil_InitializeThreading( PaUtilThreading *threading )
{
(void) paUtilErr_;
return paNoError;
}
void PaUtil_TerminateThreading( PaUtilThreading *threading )
{
}
PaError PaUtil_StartThreading( PaUtilThreading *threading, void *(*threadRoutine)(void *), void *data )
{
pthread_create( &threading->callbackThread, NULL, threadRoutine, data );
return paNoError;
}
PaError PaUtil_CancelThreading( PaUtilThreading *threading, int wait, PaError *exitResult )
{
PaError result = paNoError;
void *pret;
if( exitResult )
*exitResult = paNoError;
/* Only kill the thread if it isn't in the process of stopping (flushing adaptation buffers) */
if( !wait )
pthread_cancel( threading->callbackThread ); /* XXX: Safe to call this if the thread has exited on its own? */
pthread_join( threading->callbackThread, &pret );
#ifdef PTHREAD_CANCELED
if( pret && PTHREAD_CANCELED != pret )
#else
/* !wait means the thread may have been canceled */
if( pret && wait )
#endif
{
if( exitResult )
*exitResult = *(PaError *) pret;
free( pret );
}
return result;
}
/* Threading */
/* paUnixMainThread
* We have to be a bit careful with defining this global variable,
* as explained below. */
#ifdef __apple__
/* apple/gcc has a "problem" with global vars and dynamic libs.
Initializing it seems to fix the problem.
Described a bit in this thread:
http://gcc.gnu.org/ml/gcc/2005-06/msg00179.html
*/
pthread_t paUnixMainThread = 0;
#else
/*pthreads are opaque. We don't know that asigning it an int value
always makes sense, so we don't initialize it unless we have to.*/
pthread_t paUnixMainThread = 0;
#endif
PaError PaUnixThreading_Initialize()
{
paUnixMainThread = pthread_self();
return paNoError;
}
static PaError BoostPriority( PaUnixThread* self )
{
PaError result = paNoError;
struct sched_param spm = { 0 };
/* Priority should only matter between contending FIFO threads? */
spm.sched_priority = 1;
assert( self );
if( pthread_setschedparam( self->thread, SCHED_FIFO, &spm ) != 0 )
{
PA_UNLESS( errno == EPERM, paInternalError ); /* Lack permission to raise priority */
PA_DEBUG(( "Failed bumping priority\n" ));
result = 0;
}
else
{
result = 1; /* Success */
}
error:
return result;
}
PaError PaUnixThread_New( PaUnixThread* self, void* (*threadFunc)( void* ), void* threadArg, PaTime waitForChild,
int rtSched )
{
PaError result = paNoError;
pthread_attr_t attr;
int started = 0;
memset( self, 0, sizeof (PaUnixThread) );
PaUnixMutex_Initialize( &self->mtx );
PA_ASSERT_CALL( pthread_cond_init( &self->cond, NULL ), 0 );
self->parentWaiting = 0 != waitForChild;
/* Spawn thread */
/* Temporarily disabled since we should test during configuration for presence of required mman.h header */
#if 0
#if defined _POSIX_MEMLOCK && (_POSIX_MEMLOCK != -1)
if( rtSched )
{
if( mlockall( MCL_CURRENT | MCL_FUTURE ) < 0 )
{
int savedErrno = errno; /* In case errno gets overwritten */
assert( savedErrno != EINVAL ); /* Most likely a programmer error */
PA_UNLESS( (savedErrno == EPERM), paInternalError );
PA_DEBUG(( "%s: Failed locking memory\n", __FUNCTION__ ));
}
else
PA_DEBUG(( "%s: Successfully locked memory\n", __FUNCTION__ ));
}
#endif
#endif
PA_UNLESS( !pthread_attr_init( &attr ), paInternalError );
/* Priority relative to other processes */
PA_UNLESS( !pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ), paInternalError );
PA_UNLESS( !pthread_create( &self->thread, &attr, threadFunc, threadArg ), paInternalError );
started = 1;
if( rtSched )
{
#if 0
if( self->useWatchdog )
{
int err;
struct sched_param wdSpm = { 0 };
/* Launch watchdog, watchdog sets callback thread priority */
int prio = PA_MIN( self->rtPrio + 4, sched_get_priority_max( SCHED_FIFO ) );
wdSpm.sched_priority = prio;
PA_UNLESS( !pthread_attr_init( &attr ), paInternalError );
PA_UNLESS( !pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ), paInternalError );
PA_UNLESS( !pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ), paInternalError );
PA_UNLESS( !pthread_attr_setschedpolicy( &attr, SCHED_FIFO ), paInternalError );
PA_UNLESS( !pthread_attr_setschedparam( &attr, &wdSpm ), paInternalError );
if( (err = pthread_create( &self->watchdogThread, &attr, &WatchdogFunc, self )) )
{
PA_UNLESS( err == EPERM, paInternalError );
/* Permission error, go on without realtime privileges */
PA_DEBUG(( "Failed bumping priority\n" ));
}
else
{
int policy;
self->watchdogRunning = 1;
PA_ENSURE_SYSTEM( pthread_getschedparam( self->watchdogThread, &policy, &wdSpm ), 0 );
/* Check if priority is right, policy could potentially differ from SCHED_FIFO (but that's alright) */
if( wdSpm.sched_priority != prio )
{
PA_DEBUG(( "Watchdog priority not set correctly (%d)\n", wdSpm.sched_priority ));
PA_ENSURE( paInternalError );
}
}
}
else
#endif
PA_ENSURE( BoostPriority( self ) );
{
int policy;
struct sched_param spm;
pthread_getschedparam(self->thread, &policy, &spm);
}
}
if( self->parentWaiting )
{
PaTime till;
struct timespec ts;
int res = 0;
PaTime now;
PA_ENSURE( PaUnixMutex_Lock( &self->mtx ) );
/* Wait for stream to be started */
now = PaUtil_GetTime();
till = now + waitForChild;
while( self->parentWaiting && !res )
{
if( waitForChild > 0 )
{
ts.tv_sec = (time_t) floor( till );
ts.tv_nsec = (long) ((till - floor( till )) * 1e9);
res = pthread_cond_timedwait( &self->cond, &self->mtx.mtx, &ts );
}
else
{
res = pthread_cond_wait( &self->cond, &self->mtx.mtx );
}
}
PA_ENSURE( PaUnixMutex_Unlock( &self->mtx ) );
PA_UNLESS( !res || ETIMEDOUT == res, paInternalError );
PA_DEBUG(( "%s: Waited for %g seconds for stream to start\n", __FUNCTION__, PaUtil_GetTime() - now ));
if( ETIMEDOUT == res )
{
PA_ENSURE( paTimedOut );
}
}
end:
return result;
error:
if( started )
{
PaUnixThread_Terminate( self, 0, NULL );
}
goto end;
}
PaError PaUnixThread_Terminate( PaUnixThread* self, int wait, PaError* exitResult )
{
PaError result = paNoError;
void* pret;
if( exitResult )
{
*exitResult = paNoError;
}
#if 0
if( watchdogExitResult )
*watchdogExitResult = paNoError;
if( th->watchdogRunning )
{
pthread_cancel( th->watchdogThread );
PA_ENSURE_SYSTEM( pthread_join( th->watchdogThread, &pret ), 0 );
if( pret && pret != PTHREAD_CANCELED )
{
if( watchdogExitResult )
*watchdogExitResult = *(PaError *) pret;
free( pret );
}
}
#endif
/* Only kill the thread if it isn't in the process of stopping (flushing adaptation buffers) */
/* TODO: Make join time out */
self->stopRequested = wait;
if( !wait )
{
PA_DEBUG(( "%s: Canceling thread %d\n", __FUNCTION__, self->thread ));
/* XXX: Safe to call this if the thread has exited on its own? */
pthread_cancel( self->thread );
}
PA_DEBUG(( "%s: Joining thread %d\n", __FUNCTION__, self->thread ));
PA_ENSURE_SYSTEM( pthread_join( self->thread, &pret ), 0 );
if( pret && PTHREAD_CANCELED != pret )
{
if( exitResult )
{
*exitResult = *(PaError*)pret;
}
free( pret );
}
error:
PA_ASSERT_CALL( PaUnixMutex_Terminate( &self->mtx ), paNoError );
PA_ASSERT_CALL( pthread_cond_destroy( &self->cond ), 0 );
return result;
}
PaError PaUnixThread_PrepareNotify( PaUnixThread* self )
{
PaError result = paNoError;
PA_UNLESS( self->parentWaiting, paInternalError );
PA_ENSURE( PaUnixMutex_Lock( &self->mtx ) );
self->locked = 1;
error:
return result;
}
PaError PaUnixThread_NotifyParent( PaUnixThread* self )
{
PaError result = paNoError;
PA_UNLESS( self->parentWaiting, paInternalError );
if( !self->locked )
{
PA_ENSURE( PaUnixMutex_Lock( &self->mtx ) );
self->locked = 1;
}
self->parentWaiting = 0;
pthread_cond_signal( &self->cond );
PA_ENSURE( PaUnixMutex_Unlock( &self->mtx ) );
self->locked = 0;
error:
return result;
}
int PaUnixThread_StopRequested( PaUnixThread* self )
{
return self->stopRequested;
}
PaError PaUnixMutex_Initialize( PaUnixMutex* self )
{
PaError result = paNoError;
PA_ASSERT_CALL( pthread_mutex_init( &self->mtx, NULL ), 0 );
return result;
}
PaError PaUnixMutex_Terminate( PaUnixMutex* self )
{
PaError result = paNoError;
PA_ASSERT_CALL( pthread_mutex_destroy( &self->mtx ), 0 );
return result;
}
/** Lock mutex.
*
* We're disabling thread cancellation while the thread is holding a lock, so mutexes are
* properly unlocked at termination time.
*/
PaError PaUnixMutex_Lock( PaUnixMutex* self )
{
PaError result = paNoError;
int oldState;
PA_ENSURE_SYSTEM( pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, &oldState ), 0 );
PA_ENSURE_SYSTEM( pthread_mutex_lock( &self->mtx ), 0 );
error:
return result;
}
/** Unlock mutex.
*
* Thread cancellation is enabled again after the mutex is properly unlocked.
*/
PaError PaUnixMutex_Unlock( PaUnixMutex* self )
{
PaError result = paNoError;
int oldState;
PA_ENSURE_SYSTEM( pthread_mutex_unlock( &self->mtx ), 0 );
PA_ENSURE_SYSTEM( pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &oldState ), 0 );
error:
return result;
}
#if 0
static void OnWatchdogExit( void *userData )
{
PaAlsaThreading *th = (PaAlsaThreading *) userData;
struct sched_param spm = { 0 };
assert( th );
PA_ASSERT_CALL( pthread_setschedparam( th->callbackThread, SCHED_OTHER, &spm ), 0 ); /* Lower before exiting */
PA_DEBUG(( "Watchdog exiting\n" ));
}
static void *WatchdogFunc( void *userData )
{
PaError result = paNoError, *pres = NULL;
int err;
PaAlsaThreading *th = (PaAlsaThreading *) userData;
unsigned intervalMsec = 500;
const PaTime maxSeconds = 3.; /* Max seconds between callbacks */
PaTime timeThen = PaUtil_GetTime(), timeNow, timeElapsed, cpuTimeThen, cpuTimeNow, cpuTimeElapsed;
double cpuLoad, avgCpuLoad = 0.;
int throttled = 0;
assert( th );
/* Execute OnWatchdogExit when exiting */
pthread_cleanup_push( &OnWatchdogExit, th );
/* Boost priority of callback thread */
PA_ENSURE( result = BoostPriority( th ) );
if( !result )
{
/* Boost failed, might as well exit */
pthread_exit( NULL );
}
cpuTimeThen = th->callbackCpuTime;
{
int policy;
struct sched_param spm = { 0 };
pthread_getschedparam( pthread_self(), &policy, &spm );
PA_DEBUG(( "%s: Watchdog priority is %d\n", __FUNCTION__, spm.sched_priority ));
}
while( 1 )
{
double lowpassCoeff = 0.9, lowpassCoeff1 = 0.99999 - lowpassCoeff;
/* Test before and after in case whatever underlying sleep call isn't interrupted by pthread_cancel */
pthread_testcancel();
Pa_Sleep( intervalMsec );
pthread_testcancel();
if( PaUtil_GetTime() - th->callbackTime > maxSeconds )
{
PA_DEBUG(( "Watchdog: Terminating callback thread\n" ));
/* Tell thread to terminate */
err = pthread_kill( th->callbackThread, SIGKILL );
pthread_exit( NULL );
}
PA_DEBUG(( "%s: PortAudio reports CPU load: %g\n", __FUNCTION__, PaUtil_GetCpuLoad( th->cpuLoadMeasurer ) ));
/* Check if we should throttle, or unthrottle :P */
cpuTimeNow = th->callbackCpuTime;
cpuTimeElapsed = cpuTimeNow - cpuTimeThen;
cpuTimeThen = cpuTimeNow;
timeNow = PaUtil_GetTime();
timeElapsed = timeNow - timeThen;
timeThen = timeNow;
cpuLoad = cpuTimeElapsed / timeElapsed;
avgCpuLoad = avgCpuLoad * lowpassCoeff + cpuLoad * lowpassCoeff1;
/*
if( throttled )
PA_DEBUG(( "Watchdog: CPU load: %g, %g\n", avgCpuLoad, cpuTimeElapsed ));
*/
if( PaUtil_GetCpuLoad( th->cpuLoadMeasurer ) > .925 )
{
static int policy;
static struct sched_param spm = { 0 };
static const struct sched_param defaultSpm = { 0 };
PA_DEBUG(( "%s: Throttling audio thread, priority %d\n", __FUNCTION__, spm.sched_priority ));
pthread_getschedparam( th->callbackThread, &policy, &spm );
if( !pthread_setschedparam( th->callbackThread, SCHED_OTHER, &defaultSpm ) )
{
throttled = 1;
}
else
PA_DEBUG(( "Watchdog: Couldn't lower priority of audio thread: %s\n", strerror( errno ) ));
/* Give other processes a go, before raising priority again */
PA_DEBUG(( "%s: Watchdog sleeping for %lu msecs before unthrottling\n", __FUNCTION__, th->throttledSleepTime ));
Pa_Sleep( th->throttledSleepTime );
/* Reset callback priority */
if( pthread_setschedparam( th->callbackThread, SCHED_FIFO, &spm ) != 0 )
{
PA_DEBUG(( "%s: Couldn't raise priority of audio thread: %s\n", __FUNCTION__, strerror( errno ) ));
}
if( PaUtil_GetCpuLoad( th->cpuLoadMeasurer ) >= .99 )
intervalMsec = 50;
else
intervalMsec = 100;
/*
lowpassCoeff = .97;
lowpassCoeff1 = .99999 - lowpassCoeff;
*/
}
else if( throttled && avgCpuLoad < .8 )
{
intervalMsec = 500;
throttled = 0;
/*
lowpassCoeff = .9;
lowpassCoeff1 = .99999 - lowpassCoeff;
*/
}
}
pthread_cleanup_pop( 1 ); /* Execute cleanup on exit */
error:
/* Shouldn't get here in the normal case */
/* Pass on error code */
pres = malloc( sizeof (PaError) );
*pres = result;
pthread_exit( pres );
}
static void CallbackUpdate( PaAlsaThreading *th )
{
th->callbackTime = PaUtil_GetTime();
th->callbackCpuTime = PaUtil_GetCpuLoad( th->cpuLoadMeasurer );
}
/*
static void *CanaryFunc( void *userData )
{
const unsigned intervalMsec = 1000;
PaUtilThreading *th = (PaUtilThreading *) userData;
while( 1 )
{
th->canaryTime = PaUtil_GetTime();
pthread_testcancel();
Pa_Sleep( intervalMsec );
}
pthread_exit( NULL );
}
*/
#endif

224
src/os/unix/pa_unix_util.h Normal file
View file

@ -0,0 +1,224 @@
/*
* $Id$
* Portable Audio I/O Library
* UNIX platform-specific support functions
*
* Based on the Open Source API proposed by Ross Bencina
* Copyright (c) 1999-2000 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 unix_src
*/
#ifndef PA_UNIX_UTIL_H
#define PA_UNIX_UTIL_H
#include "pa_cpuload.h"
#include <assert.h>
#include <pthread.h>
#include <signal.h>
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
#define PA_MIN(x,y) ( (x) < (y) ? (x) : (y) )
#define PA_MAX(x,y) ( (x) > (y) ? (x) : (y) )
/* Utilize GCC branch prediction for error tests */
#if defined __GNUC__ && __GNUC__ >= 3
#define UNLIKELY(expr) __builtin_expect( (expr), 0 )
#else
#define UNLIKELY(expr) (expr)
#endif
#define STRINGIZE_HELPER(expr) #expr
#define STRINGIZE(expr) STRINGIZE_HELPER(expr)
#define PA_UNLESS(expr, code) \
do { \
if( UNLIKELY( (expr) == 0 ) ) \
{ \
PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \
result = (code); \
goto error; \
} \
} while (0);
static PaError paUtilErr_; /* Used with PA_ENSURE */
/* Check PaError */
#define PA_ENSURE(expr) \
do { \
if( UNLIKELY( (paUtilErr_ = (expr)) < paNoError ) ) \
{ \
PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \
result = paUtilErr_; \
goto error; \
} \
} while (0);
#define PA_ASSERT_CALL(expr, success) \
paUtilErr_ = (expr); \
assert( success == paUtilErr_ );
#define PA_ENSURE_SYSTEM(expr, success) \
do { \
if( UNLIKELY( (paUtilErr_ = (expr)) != success ) ) \
{ \
/* PaUtil_SetLastHostErrorInfo should only be used in the main thread */ \
if( pthread_equal(pthread_self(), paUnixMainThread) ) \
{ \
PaUtil_SetLastHostErrorInfo( paALSA, paUtilErr_, strerror( paUtilErr_ ) ); \
} \
PaUtil_DebugPrint( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" ); \
result = paUnanticipatedHostError; \
goto error; \
} \
} while( 0 );
typedef struct {
pthread_t callbackThread;
} PaUtilThreading;
PaError PaUtil_InitializeThreading( PaUtilThreading *threading );
void PaUtil_TerminateThreading( PaUtilThreading *threading );
PaError PaUtil_StartThreading( PaUtilThreading *threading, void *(*threadRoutine)(void *), void *data );
PaError PaUtil_CancelThreading( PaUtilThreading *threading, int wait, PaError *exitResult );
/* State accessed by utility functions */
/*
void PaUnix_SetRealtimeScheduling( int rt );
void PaUtil_InitializeThreading( PaUtilThreading *th, PaUtilCpuLoadMeasurer *clm );
PaError PaUtil_CreateCallbackThread( PaUtilThreading *th, void *(*CallbackThreadFunc)( void * ), PaStream *s );
PaError PaUtil_KillCallbackThread( PaUtilThreading *th, PaError *exitResult );
void PaUtil_CallbackUpdate( PaUtilThreading *th );
*/
extern pthread_t paUnixMainThread;
typedef struct
{
pthread_mutex_t mtx;
} PaUnixMutex;
PaError PaUnixMutex_Initialize( PaUnixMutex* self );
PaError PaUnixMutex_Terminate( PaUnixMutex* self );
PaError PaUnixMutex_Lock( PaUnixMutex* self );
PaError PaUnixMutex_Unlock( PaUnixMutex* self );
typedef struct
{
pthread_t thread;
int parentWaiting;
int stopRequested;
int locked;
PaUnixMutex mtx;
pthread_cond_t cond;
volatile sig_atomic_t stopRequest;
} PaUnixThread;
/** Initialize global threading state.
*/
PaError PaUnixThreading_Initialize();
/** Perish, passing on eventual error code.
*
* A thin wrapper around pthread_exit, will automatically pass on any error code to the joining thread.
* If the result indicates an error, i.e. it is not equal to paNoError, this function will automatically
* allocate a pointer so the error is passed on with pthread_exit. If the result indicates that all is
* well however, only a NULL pointer will be handed to pthread_exit. Thus, the joining thread should
* check whether a non-NULL result pointer is obtained from pthread_join and make sure to free it.
* @param result: The error code to pass on to the joining thread.
*/
#define PaUnixThreading_EXIT(result) \
do { \
PaError* pres = NULL; \
if( paNoError != (result) ) \
{ \
pres = malloc( sizeof (PaError) ); \
*pres = (result); \
} \
pthread_exit( pres ); \
} while (0);
/** Spawn a thread.
*
* Intended for spawning the callback thread from the main thread. This function can even block (for a certain
* time or indefinitely) untill notified by the callback thread (using PaUnixThread_NotifyParent), which can be
* useful in order to make sure that callback has commenced before returning from Pa_StartStream.
* @param threadFunc: The function to be executed in the child thread.
* @param waitForChild: If not 0, wait for child thread to call PaUnixThread_NotifyParent. Less than 0 means
* wait for ever, greater than 0 wait for the specified time.
* @param rtSched: Enable realtime scheduling?
* @return: If timed out waiting on child, paTimedOut.
*/
PaError PaUnixThread_New( PaUnixThread* self, void* (*threadFunc)( void* ), void* threadArg, PaTime waitForChild,
int rtSched );
/** Terminate thread.
*
* @param wait: If true, request that background thread stop and wait untill it does, else cancel it.
* @param exitResult: If non-null this will upon return contain the exit status of the thread.
*/
PaError PaUnixThread_Terminate( PaUnixThread* self, int wait, PaError* exitResult );
/** Prepare to notify waiting parent thread.
*
* An internal lock must be held before the parent is notified in PaUnixThread_NotifyParent, call this to
* acquire it beforehand.
* @return: If parent is not waiting, paInternalError.
*/
PaError PaUnixThread_PrepareNotify( PaUnixThread* self );
/** Notify waiting parent thread.
*
* @return: If parent timed out waiting, paTimedOut. If parent was never waiting, paInternalError.
*/
PaError PaUnixThread_NotifyParent( PaUnixThread* self );
/** Has the parent thread requested this thread to stop?
*/
int PaUnixThread_StopRequested( PaUnixThread* self );
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif

View file

@ -0,0 +1,100 @@
/*
* $Id$
* Portable Audio I/O Library Windows initialization table
*
* 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 win_src
@brief Win32 host API initialization function table.
@todo Consider using PA_USE_WMME etc instead of PA_NO_WMME. This is what
the Unix version does, we should consider being consistent.
*/
#include "pa_hostapi.h"
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
PaError PaWinDs_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
PaError PaWinWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
#ifdef __cplusplus
}
#endif /* __cplusplus */
PaUtilHostApiInitializer *paHostApiInitializers[] =
{
#ifndef PA_NO_WMME
PaWinMme_Initialize,
#endif
#ifndef PA_NO_DS
PaWinDs_Initialize,
#endif
#ifndef PA_NO_ASIO
PaAsio_Initialize,
#endif
/*
#ifndef PA_NO_WASAPI
PaWinWasapi_Initialize,
#endif
#ifndef PA_NO_WDMKS
PaWinWdm_Initialize,
#endif
*/
PaSkeleton_Initialize, /* just for testing */
0 /* NULL terminated array */
};
int paDefaultHostApiIndex = 0;

147
src/os/win/pa_win_util.c Normal file
View file

@ -0,0 +1,147 @@
/*
* $Id$
* Portable Audio I/O Library
* Win32 platform-specific support functions
*
* Based on the Open Source API proposed by Ross Bencina
* Copyright (c) 1999-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 win_src
@brief Win32 implementation of platform-specific PaUtil support functions.
@todo Implement workaround for QueryPerformanceCounter() skipping forward
bug. (see msdn kb Q274323).
*/
#include <windows.h>
#include <mmsystem.h> /* for timeGetTime() */
#include "pa_util.h"
/*
Track memory allocations to avoid leaks.
*/
#if PA_TRACK_MEMORY
static int numAllocations_ = 0;
#endif
void *PaUtil_AllocateMemory( long size )
{
void *result = GlobalAlloc( GPTR, size );
#if PA_TRACK_MEMORY
if( result != NULL ) numAllocations_ += 1;
#endif
return result;
}
void PaUtil_FreeMemory( void *block )
{
if( block != NULL )
{
GlobalFree( block );
#if PA_TRACK_MEMORY
numAllocations_ -= 1;
#endif
}
}
int PaUtil_CountCurrentlyAllocatedBlocks( void )
{
#if PA_TRACK_MEMORY
return numAllocations_;
#else
return 0;
#endif
}
void Pa_Sleep( long msec )
{
Sleep( msec );
}
static int usePerformanceCounter_;
static double secondsPerTick_;
void PaUtil_InitializeClock( void )
{
LARGE_INTEGER ticksPerSecond;
if( QueryPerformanceFrequency( &ticksPerSecond ) != 0 )
{
usePerformanceCounter_ = 1;
secondsPerTick_ = 1.0 / (double)ticksPerSecond.QuadPart;
}
else
{
usePerformanceCounter_ = 0;
}
}
double PaUtil_GetTime( void )
{
LARGE_INTEGER time;
if( usePerformanceCounter_ )
{
/* FIXME:
according to this knowledge-base article, QueryPerformanceCounter
can skip forward by seconds!
http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q274323&
it may be better to use the rtdsc instruction using inline asm,
however then a method is needed to calculate a ticks/seconds ratio.
*/
QueryPerformanceCounter( &time );
return time.QuadPart * secondsPerTick_;
}
else
{
#ifndef UNDER_CE
return timeGetTime() * .001;
#else
return GetTickCount() * .001;
#endif
}
}

View file

@ -0,0 +1,159 @@
/*
* PortAudio Portable Real-Time Audio Library
* Windows WAVEFORMAT* data structure utilities
* portaudio.h should be included before this file.
*
* Copyright (c) 2007 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.
*/
#include <windows.h>
#include <mmsystem.h>
#include "portaudio.h"
#include "pa_win_waveformat.h"
#if !defined(WAVE_FORMAT_EXTENSIBLE)
#define WAVE_FORMAT_EXTENSIBLE 0xFFFE
#endif
#if !defined(WAVE_FORMAT_IEEE_FLOAT)
#define WAVE_FORMAT_IEEE_FLOAT 0x0003
#endif
static GUID pawin_ksDataFormatSubtypePcm =
{ (USHORT)(WAVE_FORMAT_PCM), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 };
static GUID pawin_ksDataFormatSubtypeIeeeFloat =
{ (USHORT)(WAVE_FORMAT_IEEE_FLOAT), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 };
void PaWin_InitializeWaveFormatEx( PaWinWaveFormat *waveFormat,
int numChannels, PaSampleFormat sampleFormat, double sampleRate )
{
WAVEFORMATEX *waveFormatEx = (WAVEFORMATEX*)waveFormat;
int bytesPerSample = Pa_GetSampleSize(sampleFormat);
unsigned long bytesPerFrame = numChannels * bytesPerSample;
if( sampleFormat == paFloat32 )
waveFormatEx->wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
else
waveFormatEx->wFormatTag = WAVE_FORMAT_PCM;
waveFormatEx->nChannels = (WORD)numChannels;
waveFormatEx->nSamplesPerSec = (DWORD)sampleRate;
waveFormatEx->nAvgBytesPerSec = waveFormatEx->nSamplesPerSec * bytesPerFrame;
waveFormatEx->nBlockAlign = (WORD)bytesPerFrame;
waveFormatEx->wBitsPerSample = bytesPerSample * 8;
waveFormatEx->cbSize = 0;
}
void PaWin_InitializeWaveFormatExtensible( PaWinWaveFormat *waveFormat,
int numChannels, PaSampleFormat sampleFormat, double sampleRate,
PaWinWaveFormatChannelMask channelMask )
{
WAVEFORMATEX *waveFormatEx = (WAVEFORMATEX*)waveFormat;
int bytesPerSample = Pa_GetSampleSize(sampleFormat);
unsigned long bytesPerFrame = numChannels * bytesPerSample;
waveFormatEx->wFormatTag = WAVE_FORMAT_EXTENSIBLE;
waveFormatEx->nChannels = (WORD)numChannels;
waveFormatEx->nSamplesPerSec = (DWORD)sampleRate;
waveFormatEx->nAvgBytesPerSec = waveFormatEx->nSamplesPerSec * bytesPerFrame;
waveFormatEx->nBlockAlign = (WORD)bytesPerFrame;
waveFormatEx->wBitsPerSample = bytesPerSample * 8;
waveFormatEx->cbSize = 22;
*((WORD*)&waveFormat->fields[PAWIN_INDEXOF_WVALIDBITSPERSAMPLE]) =
waveFormatEx->wBitsPerSample;
*((DWORD*)&waveFormat->fields[PAWIN_INDEXOF_DWCHANNELMASK]) = channelMask;
if( sampleFormat == paFloat32 )
*((GUID*)&waveFormat->fields[PAWIN_INDEXOF_SUBFORMAT]) =
pawin_ksDataFormatSubtypeIeeeFloat;
else
*((GUID*)&waveFormat->fields[PAWIN_INDEXOF_SUBFORMAT]) =
pawin_ksDataFormatSubtypePcm;
}
PaWinWaveFormatChannelMask PaWin_DefaultChannelMask( int numChannels )
{
switch( numChannels ){
case 1:
return PAWIN_SPEAKER_MONO;
case 2:
return PAWIN_SPEAKER_STEREO;
case 3:
return PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_CENTER | PAWIN_SPEAKER_FRONT_RIGHT;
case 4:
return PAWIN_SPEAKER_QUAD;
case 5:
return PAWIN_SPEAKER_QUAD | PAWIN_SPEAKER_FRONT_CENTER;
case 6:
/* The meaning of the PAWIN_SPEAKER_5POINT1 flag has changed over time:
http://msdn2.microsoft.com/en-us/library/aa474707.aspx
We use PAWIN_SPEAKER_5POINT1 (not PAWIN_SPEAKER_5POINT1_SURROUND)
because on some cards (eg Audigy) PAWIN_SPEAKER_5POINT1_SURROUND
results in a virtual mixdown placing the rear output in the
front _and_ rear speakers.
*/
return PAWIN_SPEAKER_5POINT1;
/* case 7: */
case 8:
return PAWIN_SPEAKER_7POINT1;
}
/* Apparently some Audigy drivers will output silence
if the direct-out constant (0) is used. So this is not ideal.
*/
return PAWIN_SPEAKER_DIRECTOUT;
/* Note that Alec Rogers proposed the following as an alternate method to
generate the default channel mask, however it doesn't seem to be an improvement
over the above, since some drivers will matrix outputs mapping to non-present
speakers accross multiple physical speakers.
if(nChannels==1) {
pwfFormat->dwChannelMask = SPEAKER_FRONT_CENTER;
}
else {
pwfFormat->dwChannelMask = 0;
for(i=0; i<nChannels; i++)
pwfFormat->dwChannelMask = (pwfFormat->dwChannelMask << 1) | 0x1;
}
*/
}

View file

@ -0,0 +1,260 @@
/*
* PortAudio Portable Real-Time Audio Library
* Windows WDM KS utilities
*
* Copyright (c) 1999 - 2007 Andrew Baldwin, 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.
*/
#include <windows.h>
#include <mmreg.h>
#include <ks.h>
#include <ksmedia.h>
#include <stdio.h> // just for some development printfs
#include "portaudio.h"
#include "pa_util.h"
#include "pa_win_wdmks_utils.h"
static PaError WdmGetPinPropertySimple(
HANDLE handle,
unsigned long pinId,
unsigned long property,
void* value,
unsigned long valueSize )
{
DWORD bytesReturned;
KSP_PIN ksPProp;
ksPProp.Property.Set = KSPROPSETID_Pin;
ksPProp.Property.Id = property;
ksPProp.Property.Flags = KSPROPERTY_TYPE_GET;
ksPProp.PinId = pinId;
ksPProp.Reserved = 0;
if( DeviceIoControl( handle, IOCTL_KS_PROPERTY, &ksPProp, sizeof(KSP_PIN),
value, valueSize, &bytesReturned, NULL ) == 0 || bytesReturned != valueSize )
{
return paUnanticipatedHostError;
}
else
{
return paNoError;
}
}
static PaError WdmGetPinPropertyMulti(
HANDLE handle,
unsigned long pinId,
unsigned long property,
KSMULTIPLE_ITEM** ksMultipleItem)
{
unsigned long multipleItemSize = 0;
KSP_PIN ksPProp;
DWORD bytesReturned;
*ksMultipleItem = 0;
ksPProp.Property.Set = KSPROPSETID_Pin;
ksPProp.Property.Id = property;
ksPProp.Property.Flags = KSPROPERTY_TYPE_GET;
ksPProp.PinId = pinId;
ksPProp.Reserved = 0;
if( DeviceIoControl( handle, IOCTL_KS_PROPERTY, &ksPProp.Property,
sizeof(KSP_PIN), NULL, 0, &multipleItemSize, NULL ) == 0 && GetLastError() != ERROR_MORE_DATA )
{
return paUnanticipatedHostError;
}
*ksMultipleItem = (KSMULTIPLE_ITEM*)PaUtil_AllocateMemory( multipleItemSize );
if( !*ksMultipleItem )
{
return paInsufficientMemory;
}
if( DeviceIoControl( handle, IOCTL_KS_PROPERTY, &ksPProp, sizeof(KSP_PIN),
(void*)*ksMultipleItem, multipleItemSize, &bytesReturned, NULL ) == 0 || bytesReturned != multipleItemSize )
{
PaUtil_FreeMemory( ksMultipleItem );
return paUnanticipatedHostError;
}
return paNoError;
}
static int GetKSFilterPinCount( HANDLE deviceHandle )
{
DWORD result;
if( WdmGetPinPropertySimple( deviceHandle, 0, KSPROPERTY_PIN_CTYPES, &result, sizeof(result) ) == paNoError ){
return result;
}else{
return 0;
}
}
static KSPIN_COMMUNICATION GetKSFilterPinPropertyCommunication( HANDLE deviceHandle, int pinId )
{
KSPIN_COMMUNICATION result;
if( WdmGetPinPropertySimple( deviceHandle, pinId, KSPROPERTY_PIN_COMMUNICATION, &result, sizeof(result) ) == paNoError ){
return result;
}else{
return KSPIN_COMMUNICATION_NONE;
}
}
static KSPIN_DATAFLOW GetKSFilterPinPropertyDataflow( HANDLE deviceHandle, int pinId )
{
KSPIN_DATAFLOW result;
if( WdmGetPinPropertySimple( deviceHandle, pinId, KSPROPERTY_PIN_DATAFLOW, &result, sizeof(result) ) == paNoError ){
return result;
}else{
return (KSPIN_DATAFLOW)0;
}
}
static int KSFilterPinPropertyIdentifiersInclude(
HANDLE deviceHandle, int pinId, unsigned long property, const GUID *identifierSet, unsigned long identifierId )
{
KSMULTIPLE_ITEM* item = NULL;
KSIDENTIFIER* identifier;
int i;
int result = 0;
if( WdmGetPinPropertyMulti( deviceHandle, pinId, property, &item) != paNoError )
return 0;
identifier = (KSIDENTIFIER*)(item+1);
for( i = 0; i < (int)item->Count; i++ )
{
if( !memcmp( (void*)&identifier[i].Set, (void*)identifierSet, sizeof( GUID ) ) &&
( identifier[i].Id == identifierId ) )
{
result = 1;
break;
}
}
PaUtil_FreeMemory( item );
return result;
}
/* return the maximum channel count supported by any pin on the device.
if isInput is non-zero we query input pins, otherwise output pins.
*/
int PaWin_WDMKS_QueryFilterMaximumChannelCount( void *wcharDevicePath, int isInput )
{
HANDLE deviceHandle;
int pinCount, pinId, i;
int result = 0;
KSPIN_DATAFLOW requiredDataflowDirection = (isInput ? KSPIN_DATAFLOW_OUT : KSPIN_DATAFLOW_IN );
if( !wcharDevicePath )
return 0;
deviceHandle = CreateFileW( (LPCWSTR)wcharDevicePath, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL );
if( deviceHandle == INVALID_HANDLE_VALUE )
return 0;
pinCount = GetKSFilterPinCount( deviceHandle );
for( pinId = 0; pinId < pinCount; ++pinId )
{
KSPIN_COMMUNICATION communication = GetKSFilterPinPropertyCommunication( deviceHandle, pinId );
KSPIN_DATAFLOW dataflow = GetKSFilterPinPropertyDataflow( deviceHandle, pinId );
if( ( dataflow == requiredDataflowDirection ) &&
(( communication == KSPIN_COMMUNICATION_SINK) ||
( communication == KSPIN_COMMUNICATION_BOTH))
&& ( KSFilterPinPropertyIdentifiersInclude( deviceHandle, pinId,
KSPROPERTY_PIN_INTERFACES, &KSINTERFACESETID_Standard, KSINTERFACE_STANDARD_STREAMING )
|| KSFilterPinPropertyIdentifiersInclude( deviceHandle, pinId,
KSPROPERTY_PIN_INTERFACES, &KSINTERFACESETID_Standard, KSINTERFACE_STANDARD_LOOPED_STREAMING ) )
&& KSFilterPinPropertyIdentifiersInclude( deviceHandle, pinId,
KSPROPERTY_PIN_MEDIUMS, &KSMEDIUMSETID_Standard, KSMEDIUM_STANDARD_DEVIO ) )
{
KSMULTIPLE_ITEM* item = NULL;
if( WdmGetPinPropertyMulti( deviceHandle, pinId, KSPROPERTY_PIN_DATARANGES, &item ) == paNoError )
{
KSDATARANGE *dataRange = (KSDATARANGE*)(item+1);
for( i=0; i < item->Count; ++i ){
if( IS_VALID_WAVEFORMATEX_GUID(&dataRange->SubFormat)
|| memcmp( (void*)&dataRange->SubFormat, (void*)&KSDATAFORMAT_SUBTYPE_PCM, sizeof(GUID) ) == 0
|| memcmp( (void*)&dataRange->SubFormat, (void*)&KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof(GUID) ) == 0
|| ( ( memcmp( (void*)&dataRange->MajorFormat, (void*)&KSDATAFORMAT_TYPE_AUDIO, sizeof(GUID) ) == 0 )
&& ( memcmp( (void*)&dataRange->SubFormat, (void*)&KSDATAFORMAT_SUBTYPE_WILDCARD, sizeof(GUID) ) == 0 ) ) )
{
KSDATARANGE_AUDIO *dataRangeAudio = (KSDATARANGE_AUDIO*)dataRange;
/*
printf( ">>> %d %d %d %d %S\n", isInput, dataflow, communication, dataRangeAudio->MaximumChannels, devicePath );
if( memcmp((void*)&dataRange->Specifier, (void*)&KSDATAFORMAT_SPECIFIER_WAVEFORMATEX, sizeof(GUID) ) == 0 )
printf( "\tspecifier: KSDATAFORMAT_SPECIFIER_WAVEFORMATEX\n" );
else if( memcmp((void*)&dataRange->Specifier, (void*)&KSDATAFORMAT_SPECIFIER_DSOUND, sizeof(GUID) ) == 0 )
printf( "\tspecifier: KSDATAFORMAT_SPECIFIER_DSOUND\n" );
else if( memcmp((void*)&dataRange->Specifier, (void*)&KSDATAFORMAT_SPECIFIER_WILDCARD, sizeof(GUID) ) == 0 )
printf( "\tspecifier: KSDATAFORMAT_SPECIFIER_WILDCARD\n" );
else
printf( "\tspecifier: ?\n" );
*/
/*
We assume that very high values for MaximumChannels are not useful and indicate
that the driver isn't prepared to tell us the real number of channels which it supports.
*/
if( dataRangeAudio->MaximumChannels < 0xFFFFUL && (int)dataRangeAudio->MaximumChannels > result )
result = (int)dataRangeAudio->MaximumChannels;
}
dataRange = (KSDATARANGE*)( ((char*)dataRange) + dataRange->FormatSize);
}
PaUtil_FreeMemory( item );
}
}
}
CloseHandle( deviceHandle );
return result;
}

View file

@ -0,0 +1,65 @@
#ifndef PA_WIN_WDMKS_UTILS_H
#define PA_WIN_WDMKS_UTILS_H
/*
* PortAudio Portable Real-Time Audio Library
* Windows WDM KS utilities
*
* Copyright (c) 1999 - 2007 Ross Bencina, Andrew Baldwin
*
* 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
@brief Utilities for working with the Windows WDM KS API
*/
#ifdef __cplusplus
extern "C" {
#endif
/**
Query for the maximum number of channels supported by any pin of the
specified device. Returns 0 if the query fails for any reason.
@param wcharDevicePath A system level PnP interface path, supplied as a WCHAR unicode string.
Declard as void* to avoid introducing a dependency on wchar_t here.
@param isInput A flag specifying whether to query for input (non-zero) or output (zero) channels.
*/
int PaWin_WDMKS_QueryFilterMaximumChannelCount( void *wcharDevicePath, int isInput );
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* PA_WIN_WDMKS_UTILS_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,60 @@
/*
* Plain Intel IA32 assembly implementations of PortAudio sample converter functions.
* 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 win_src
*/
#ifndef PA_X86_PLAIN_CONVERTERS_H
#define PA_X86_PLAIN_CONVERTERS_H
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
/**
@brief Install optimised converter functions suitable for all IA32 processors
It is recommended to call PaUtil_InitializeX86PlainConverters prior to calling Pa_Initialize
*/
void PaUtil_InitializeX86PlainConverters( void );
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* PA_X86_PLAIN_CONVERTERS_H */