data->frameIndex += PaUtil_WriteRingBuffer(&data->ringBuffer, rptr, elementsToWrite);
- return paContinue;
}
/* This routine will be called by the PortAudio engine when audio is needed.
void *userData )
{
paTestData *data = (paTestData*)userData;
+
ring_buffer_size_t elementsToPlay = PaUtil_GetRingBufferReadAvailable(&data->ringBuffer);
- ring_buffer_size_t elementsToRead = rbs_min(elementsToPlay, (ring_buffer_size_t)(framesPerBuffer * NUM_CHANNELS));
+
+ ring_buffer_size_t elementsToRead = rbs_min( elementsToPlay,
+ (ring_buffer_size_t)(framesPerBuffer * NUM_CHANNELS) );
SAMPLE* wptr = (SAMPLE*)outputBuffer;
(void) inputBuffer; /* Prevent unused variable warnings. */
--- /dev/null
+#include <time.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "portaudio.h"
+
+int main()
+{
+ PaError err = paNoError;
+
+ PaDeviceIndex defaultOutputDevice;
+ PaDeviceIndex defaultInputDevice;
+
+ err = Pa_Initialize();
+ if( err != paNoError )
+ {
+ printf( "ERROR: Pa_Initialize returned 0x%x\n", err );
+ goto error;
+ }
+
+ printf( "PortAudio version: 0x%08X\n", Pa_GetVersion());
+ // printf( "Version text: '%s'\n", Pa_GetVersionInfo()->versionText );
+
+ const int count = 20;
+ for (int i = 0; i < count; ++i)
+ {
+ defaultInputDevice = Pa_GetDefaultInputDevice();
+ defaultOutputDevice = Pa_GetDefaultOutputDevice();
+ printf("Input: %i, Output: %i\n", defaultInputDevice, defaultOutputDevice);
+
+ err = Pa_RefreshDevices();
+ if( err != paNoError )
+ {
+ printf( "ERROR: Pa_RefreshDevices returned 0x%x\n", err );
+ goto error;
+ }
+
+ sleep(2);
+ }
+
+ Pa_Terminate();
+
+ printf("----------------------------------------------\n");
+ return 0;
+error:
+ return 1;
+}
\ No newline at end of file
if( err != paNoError ) goto error;
printf("Play for %d seconds.\n", NUM_SECONDS );
+
Pa_Sleep( NUM_SECONDS * 1000 );
err = Pa_StopStream( stream );
PaDeviceIndex Pa_GetDefaultOutputDevice( void );
+/** Normally the list of devices is frozen after initialization, until the
+ next time port audio is re-initialized. This provides API stability but
+ has the side effect that hot-pluggable devices such as USB audio headsets
+ might not be up-to-date while the program is running. This method is used
+ to refresh the list of devices within port audio without closing open
+ streams.
+ @return an error code which indicates whether the device refresh was successful.
+ */
+ PaError Pa_RefreshDevices( void );
+
+
/** The type used to represent monotonic time in seconds. PaTime is
used for the fields of the PaStreamCallbackTimeInfo argument to the
PaStreamCallback and as the result of Pa_GetStreamTime().
}
+PaError Pa_RefreshDevices( void )
+ {
+ int i, baseDeviceIndex;
+ PaError result = paNoError;
+
+ PA_LOGAPI_ENTER( "Pa_RefreshDeviceList" );
+ if( !PA_IS_INITIALISED_ )
+ return paNotInitialized;
+
+ baseDeviceIndex = 0;
+ deviceCount_ = 0;
+
+ for( i=0; i < hostApisCount_; ++i )
+ {
+ PaUtilHostApiRepresentation *hostApi = hostApis_[i];
+ if( hostApi->RefreshDevices == NULL )
+ {
+ /* RefreshDevices not yet implemented for this backend. Just
+ assume that the baseDeviceIndex and the deviceCount_ are
+ incremented according to the values in the info */
+ baseDeviceIndex += hostApi->info.deviceCount;
+ deviceCount_ += hostApi->info.deviceCount;
+ continue;
+ }
+
+ PA_DEBUG(( "refreshing device list for host api %d.\n",i));
+
+ if(( result = hostApi->RefreshDevices( hostApi, i )) != paNoError )
+ return result;
+
+ assert( hostApi->info.defaultInputDevice < hostApi->info.deviceCount );
+ assert( hostApi->info.defaultOutputDevice < hostApi->info.deviceCount );
+
+ hostApi->privatePaFrontInfo.baseDeviceIndex = baseDeviceIndex;
+
+ if( hostApi->info.defaultInputDevice != paNoDevice )
+ hostApi->info.defaultInputDevice += baseDeviceIndex;
+
+ if( hostApi->info.defaultOutputDevice != paNoDevice )
+ hostApi->info.defaultOutputDevice += baseDeviceIndex;
+
+ baseDeviceIndex += hostApi->info.deviceCount;
+ deviceCount_ += hostApi->info.deviceCount;
+ }
+
+ return result;
+ }
+
+
const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceIndex device )
{
int hostSpecificDeviceIndex;
const PaStreamParameters *inputParameters,
const PaStreamParameters *outputParameters,
double sampleRate );
+
+ PaError (*RefreshDevices)( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index );
} PaUtilHostApiRepresentation;
PaStreamFlags streamFlags,
PaStreamCallback *streamCallback,
void *userData );
+static PaError RefreshDevices( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index );
static PaError CloseStream( PaStream* stream );
static PaError StartStream( PaStream *stream );
static PaError StopStream( PaStream *stream );
(*hostApi)->Terminate = Terminate;
(*hostApi)->OpenStream = OpenStream;
(*hostApi)->IsFormatSupported = IsFormatSupported;
+ (*hostApi)->RefreshDevices = RefreshDevices;
PaUtil_InitializeStreamInterface( &auhalHostApi->callbackStreamInterface,
CloseStream, StartStream,
#define HOST_TIME_TO_PA_TIME( x ) ( AudioConvertHostTimeToNanos( (x) ) * 1.0E-09) /* convert to nanoseconds and then to seconds */
+
+PaError RefreshDevices( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex hostApiIndex )
+{
+ PaMacAUHAL *auhalHostApi = (PaMacAUHAL*)hostApi;
+ PaError result = paNoError;
+ PaDeviceInfo *deviceInfoArray;
+ int i;
+
+ VVDBUG(("RefreshDevices(): hostApiIndex=%d\n", hostApiIndex));
+
+ auhalHostApi->devIds = NULL;
+ auhalHostApi->devCount = 0;
+
+ /* get the info we need about the devices */
+ result = gatherDeviceInfo( auhalHostApi );
+ if( result != paNoError )
+ goto error;
+
+ hostApi->info.defaultInputDevice = paNoDevice;
+ hostApi->info.defaultOutputDevice = paNoDevice;
+ hostApi->info.deviceCount = 0;
+
+ /* If the device infos already exist, free the old memory */
+ if( hostApi->deviceInfos != NULL )
+ {
+ PaUtil_GroupFreeMemory( auhalHostApi->allocations, hostApi->deviceInfos );
+ hostApi->deviceInfos = NULL;
+ }
+
+ if( auhalHostApi->devCount > 0 )
+ {
+ hostApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
+ auhalHostApi->allocations, sizeof(PaDeviceInfo*) * auhalHostApi->devCount);
+ if( !hostApi->deviceInfos )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ /* allocate all device info structs in a contiguous block */
+ deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory(
+ auhalHostApi->allocations, sizeof(PaDeviceInfo) * auhalHostApi->devCount );
+ if( !deviceInfoArray )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ for( i=0; i < auhalHostApi->devCount; ++i )
+ {
+ int err;
+ err = InitializeDeviceInfo( auhalHostApi, &deviceInfoArray[i],
+ auhalHostApi->devIds[i],
+ hostApiIndex );
+ if (err == paNoError)
+ { /* copy some info and set the defaults */
+ hostApi->deviceInfos[hostApi->info.deviceCount] = &deviceInfoArray[i];
+ if (auhalHostApi->devIds[i] == auhalHostApi->defaultIn)
+ hostApi->info.defaultInputDevice = hostApi->info.deviceCount;
+ if (auhalHostApi->devIds[i] == auhalHostApi->defaultOut)
+ hostApi->info.defaultOutputDevice = hostApi->info.deviceCount;
+ hostApi->info.deviceCount++;
+ }
+ else
+ { /* there was an error. we need to shift the devices down, so we ignore this one */
+ int j;
+ auhalHostApi->devCount--;
+ for( j=i; j<auhalHostApi->devCount; ++j )
+ auhalHostApi->devIds[j] = auhalHostApi->devIds[j+1];
+ i--;
+ }
+ }
+ }
+
+error:
+ return result;
+}
+
+
PaTime GetStreamTime( PaStream *s )
{
return HOST_TIME_TO_PA_TIME( AudioGetCurrentHostTime() );
const PaStreamParameters *inputParameters,
const PaStreamParameters *outputParameters,
double sampleRate );
+static PaError RefreshDevices( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index );
static PaError CloseStream( PaStream* stream );
static PaError StartStream( PaStream *stream );
static PaError StopStream( PaStream *stream );
(*hostApi)->Terminate = Terminate;
(*hostApi)->OpenStream = OpenStream;
(*hostApi)->IsFormatSupported = IsFormatSupported;
+ (*hostApi)->RefreshDevices = RefreshDevices;
PaUtil_InitializeStreamInterface( &winDsHostApi->callbackStreamInterface, CloseStream, StartStream,
StopStream, AbortStream, IsStreamStopped, IsStreamActive,
}
+/***********************************************************************************/
+static PaError RefreshDevices( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex hostApiIndex )
+{
+ PaWinDsHostApiRepresentation *winDsHostApi = (PaWinDsHostApiRepresentation*)hostApi;
+ DSDeviceNamesAndGUIDs deviceNamesAndGUIDs;
+ PaWinDsDeviceInfo *deviceInfoArray;
+ int i = 0, deviceCount = 0;
+ char comWasInitialized = winDsHostApi->comWasInitialized;
+ PaError result = paNoError;
+
+ if( !comWasInitialized )
+ return paInternalError;
+
+ /* initialise guid vectors so they can be safely deleted on error */
+ deviceNamesAndGUIDs.winDsHostApi = NULL;
+ deviceNamesAndGUIDs.inputNamesAndGUIDs.items = NULL;
+ deviceNamesAndGUIDs.outputNamesAndGUIDs.items = NULL;
+
+ hostApi->info.deviceCount = 0;
+ hostApi->info.defaultInputDevice = paNoDevice;
+ hostApi->info.defaultOutputDevice = paNoDevice;
+
+ /* DSound - enumerate devices to count them and to gather their GUIDs */
+ result = InitializeDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.inputNamesAndGUIDs, winDsHostApi->allocations );
+ if( result != paNoError )
+ goto error;
+
+ result = InitializeDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.outputNamesAndGUIDs, winDsHostApi->allocations );
+ if( result != paNoError )
+ goto error;
+
+ paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateA( (LPDSENUMCALLBACK)CollectGUIDsProc, (void *)&deviceNamesAndGUIDs.inputNamesAndGUIDs );
+ paWinDsDSoundEntryPoints.DirectSoundEnumerateA( (LPDSENUMCALLBACK)CollectGUIDsProc, (void *)&deviceNamesAndGUIDs.outputNamesAndGUIDs );
+
+ if( deviceNamesAndGUIDs.inputNamesAndGUIDs.enumerationError != paNoError )
+ {
+ result = deviceNamesAndGUIDs.inputNamesAndGUIDs.enumerationError;
+ goto error;
+ }
+
+ if( deviceNamesAndGUIDs.outputNamesAndGUIDs.enumerationError != paNoError )
+ {
+ result = deviceNamesAndGUIDs.outputNamesAndGUIDs.enumerationError;
+ goto error;
+ }
+
+ /* Free any old memory which might be in the device info */
+ if( hostApi->deviceInfos )
+ {
+ PaUtil_GroupFreeMemory( winDsHostApi->allocations, hostApi->deviceInfos );
+ hostApi->deviceInfos = NULL;
+ }
+
+ deviceCount = deviceNamesAndGUIDs.inputNamesAndGUIDs.count + deviceNamesAndGUIDs.outputNamesAndGUIDs.count;
+
+#ifdef PAWIN_USE_WDMKS_DEVICE_INFO
+ if( deviceCount > 0 )
+ {
+ deviceNamesAndGUIDs.winDsHostApi = winDsHostApi;
+ FindDevicePnpInterfaces( &deviceNamesAndGUIDs );
+ }
+#endif /* PAWIN_USE_WDMKS_DEVICE_INFO */
+
+ if( deviceCount > 0 )
+ {
+ /* allocate array for pointers to PaDeviceInfo structs */
+ hostApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
+ winDsHostApi->allocations, sizeof(PaDeviceInfo*) * deviceCount );
+ if( !hostApi->deviceInfos )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ /* allocate all PaDeviceInfo structs in a contiguous block */
+ deviceInfoArray = (PaWinDsDeviceInfo*)PaUtil_GroupAllocateMemory(
+ winDsHostApi->allocations, sizeof(PaWinDsDeviceInfo) * deviceCount );
+ if( !deviceInfoArray )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ for( i=0; i < deviceCount; ++i )
+ {
+ PaDeviceInfo *deviceInfo = &deviceInfoArray[i].inheritedDeviceInfo;
+ deviceInfo->structVersion = 2;
+ deviceInfo->hostApi = hostApiIndex;
+ deviceInfo->name = 0;
+ hostApi->deviceInfos[i] = deviceInfo;
+ }
+
+ for( i=0; i < deviceNamesAndGUIDs.inputNamesAndGUIDs.count; ++i )
+ {
+ result = AddInputDeviceInfoFromDirectSoundCapture( winDsHostApi,
+ deviceNamesAndGUIDs.inputNamesAndGUIDs.items[i].name,
+ deviceNamesAndGUIDs.inputNamesAndGUIDs.items[i].lpGUID,
+ deviceNamesAndGUIDs.inputNamesAndGUIDs.items[i].pnpInterface );
+ if( result != paNoError )
+ goto error;
+ }
+
+ for( i=0; i < deviceNamesAndGUIDs.outputNamesAndGUIDs.count; ++i )
+ {
+ result = AddOutputDeviceInfoFromDirectSound( winDsHostApi,
+ deviceNamesAndGUIDs.outputNamesAndGUIDs.items[i].name,
+ deviceNamesAndGUIDs.outputNamesAndGUIDs.items[i].lpGUID,
+ deviceNamesAndGUIDs.outputNamesAndGUIDs.items[i].pnpInterface );
+ if( result != paNoError )
+ goto error;
+ }
+ }
+
+ result = TerminateDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.inputNamesAndGUIDs );
+ if( result != paNoError )
+ goto error;
+
+ result = TerminateDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.outputNamesAndGUIDs );
+ if( result != paNoError )
+ goto error;
+
+ return result;
+
+error:
+ if( winDsHostApi )
+ {
+ if( winDsHostApi->allocations )
+ {
+ PaUtil_FreeAllAllocations( winDsHostApi->allocations );
+ PaUtil_DestroyAllocationGroup( winDsHostApi->allocations );
+ }
+ }
+
+ TerminateDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.inputNamesAndGUIDs );
+ TerminateDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.outputNamesAndGUIDs );
+
+
+ return result;
+}
+
+
#ifdef PAWIN_USE_DIRECTSOUNDFULLDUPLEXCREATE
static HRESULT InitFullDuplexInputOutputBuffers( PaWinDsStream *stream,
PaWinDsDeviceInfo *inputDevice,