Commit 70e3684d authored by robiwan's avatar robiwan

CMake: Added PA_WDMKS_NO_KSGUID_LIB to WDMKS and solution folders

WDMKS: Support for default device (see caveat for input devices though in ScanDeviceInfos)
       Added possibility to set channel mask


git-svn-id: https://subversion.assembla.com/svn/portaudio/portaudio/trunk@1924 0f58301d-fd10-0410-b4af-bbb618454e57
parent 7e7df88f
......@@ -7,6 +7,8 @@ PROJECT( portaudio )
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
SET_PROPERTY(GLOBAL PROPERTY USE_FOLDERS ON)
OPTION(PA_CONFIG_LIB_OUTPUT_PATH "Make sure that output paths are kept neat" OFF)
IF(CMAKE_CL_64)
SET(TARGET_POSTFIX x64)
......@@ -173,6 +175,7 @@ SOURCE_GROUP("hostapi\\wasapi" FILES
ENDIF(PA_USE_WASAPI)
IF(PA_USE_WDMKS)
ADD_DEFINITIONS(-DPA_WDMKS_NO_KSGUID_LIB)
SET(PA_WDMKS_INCLUDES
include/pa_win_wdmks.h
......@@ -328,8 +331,10 @@ IF(PA_USE_WDMKS)
TARGET_LINK_LIBRARIES(portaudio setupapi)
ENDIF(PA_USE_WDMKS)
SET_TARGET_PROPERTIES(portaudio PROPERTIES OUTPUT_NAME portaudio_${TARGET_POSTFIX})
SET_TARGET_PROPERTIES(portaudio_static PROPERTIES OUTPUT_NAME portaudio_static_${TARGET_POSTFIX})
SET_TARGET_PROPERTIES(portaudio PROPERTIES OUTPUT_NAME portaudio_${TARGET_POSTFIX}
FOLDER "Portaudio")
SET_TARGET_PROPERTIES(portaudio_static PROPERTIES OUTPUT_NAME portaudio_static_${TARGET_POSTFIX}
FOLDER "Portaudio")
ENDIF(WIN32)
OPTION(PA_BUILD_TESTS "Include test projects" OFF)
......
......@@ -3,11 +3,19 @@
MACRO(ADD_EXAMPLE appl_name)
ADD_EXECUTABLE(${appl_name} "${appl_name}.c")
TARGET_LINK_LIBRARIES(${appl_name} portaudio_static)
SET_TARGET_PROPERTIES(${appl_name}
PROPERTIES
FOLDER "Examples C"
)
ENDMACRO(ADD_EXAMPLE)
MACRO(ADD_EXAMPLE_CPP appl_name)
ADD_EXECUTABLE(${appl_name} "${appl_name}.cpp")
TARGET_LINK_LIBRARIES(${appl_name} portaudio_static)
SET_TARGET_PROPERTIES(${appl_name}
PROPERTIES
FOLDER "Examples C++"
)
ENDMACRO(ADD_EXAMPLE_CPP)
ADD_EXAMPLE(pa_devs)
......
......@@ -78,6 +78,12 @@ public:
return false;
}
const PaDeviceInfo* pInfo = Pa_GetDeviceInfo(index);
if (pInfo != 0)
{
printf("Output device name: '%s'\r", pInfo->name);
}
outputParameters.channelCount = 2; /* stereo output */
outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */
outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
......@@ -88,7 +94,7 @@ public:
NULL, /* no input */
&outputParameters,
SAMPLE_RATE,
FRAMES_PER_BUFFER,
paFramesPerBufferUnspecified,
paClipOff, /* we won't output out of range samples so don't bother clipping them */
&Sine::paCallback,
this /* Using 'this' for userData so we can cast to Sine* in paCallback method */
......@@ -212,18 +218,38 @@ private:
char message[20];
};
class ScopedPaHandler
{
public:
ScopedPaHandler()
: _result(Pa_Initialize())
{
}
~ScopedPaHandler()
{
if (_result == paNoError)
{
Pa_Terminate();
}
}
PaError result() const { return _result; }
private:
PaError _result;
};
/*******************************************************************/
int main(void);
int main(void)
{
PaError err;
Sine sine;
printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER);
err = Pa_Initialize();
if( err != paNoError ) goto error;
ScopedPaHandler paInit;
if( paInit.result() != paNoError ) goto error;
if (sine.open(Pa_GetDefaultOutputDevice()))
{
......@@ -238,15 +264,12 @@ int main(void)
sine.close();
}
Pa_Terminate();
printf("Test finished.\n");
return err;
return paNoError;
error:
Pa_Terminate();
fprintf( stderr, "An error occured while using the portaudio stream\n" );
fprintf( stderr, "Error number: %d\n", err );
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
return err;
fprintf( stderr, "Error number: %d\n", paInit.result() );
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( paInit.result() ) );
return 1;
}
......@@ -52,13 +52,29 @@
extern "C"
{
#endif /* __cplusplus */
/* Setup flags */
typedef enum PaWinWDMKSFlags
{
/* Makes WDMKS use the supplied latency figures instead of relying on the frame size reported
by the WaveCyclic device. Use at own risk! */
paWinWDMKSOverrideFramesize = (1 << 0),
/* Makes WDMKS (output stream) use the given channelMask instead of the default */
paWinWDMKSUseGivenChannelMask = (1 << 1),
} PaWinWDMKSFlags;
typedef struct PaWinWDMKSInfo{
unsigned long size; /**< sizeof(PaWinWDMKSInfo) */
PaHostApiTypeId hostApiType; /**< paWDMKS */
unsigned long version; /**< 1 */
unsigned long flags;
/* The number of packets to use for WaveCyclic devices, range is [2, 8]. Set to zero for default value of 2. */
unsigned noOfPackets;
/* If paWinWDMKSUseGivenChannelMask bit is set in flags, use this as channelMask instead of default */
unsigned channelMask;
} PaWinWDMKSInfo;
typedef enum PaWDMKSType
......
......@@ -86,6 +86,13 @@ of a device for the duration of active stream using those devices
#include "pa_win_wdmks.h"
#ifndef DRV_QUERYDEVICEINTERFACE
#define DRV_QUERYDEVICEINTERFACE (DRV_RESERVED + 12)
#endif
#ifndef DRV_QUERYDEVICEINTERFACESIZE
#define DRV_QUERYDEVICEINTERFACESIZE (DRV_RESERVED + 13)
#endif
#include <windows.h>
#include <winioctl.h>
#include <process.h>
......@@ -506,8 +513,9 @@ static PaError PinRegisterPositionRegister(PaWinWdmPin* pPin);
static PaError PinRegisterNotificationHandle(PaWinWdmPin* pPin, HANDLE handle);
static PaError PinUnregisterNotificationHandle(PaWinWdmPin* pPin, HANDLE handle);
static PaError PinGetHwLatency(PaWinWdmPin* pPin, ULONG* pFifoSize, ULONG* pChipsetDelay, ULONG* pCodecDelay);
static PaError PinGetAudioPositionDirect(PaWinWdmPin* pPin, ULONG* pPosition);
static PaError PinGetAudioPositionViaIOCTL(PaWinWdmPin* pPin, ULONG* pPosition);
static PaError PinGetAudioPositionMemoryMapped(PaWinWdmPin* pPin, ULONG* pPosition);
static PaError PinGetAudioPositionViaIOCTLRead(PaWinWdmPin* pPin, ULONG* pPosition);
static PaError PinGetAudioPositionViaIOCTLWrite(PaWinWdmPin* pPin, ULONG* pPosition);
/* Filter management functions */
static PaWinWdmFilter* FilterNew(PaWDMKSType type, DWORD devNode, const wchar_t* filterName, const wchar_t* friendlyName, PaError* error);
......@@ -2221,12 +2229,7 @@ static PaError PinIsFormatSupported(PaWinWdmPin* pin, const WAVEFORMATEX* format
if (pFormatExt != 0)
{
if ( dataRange->MinimumBitsPerSample > pFormatExt->Samples.wValidBitsPerSample )
{
result = paSampleFormatNotSupported;
continue;
}
if ( dataRange->MaximumBitsPerSample < pFormatExt->Samples.wValidBitsPerSample )
if (!IsBitsWithinRange(dataRange, pFormatExt->Samples.wValidBitsPerSample))
{
result = paSampleFormatNotSupported;
continue;
......@@ -2234,26 +2237,14 @@ static PaError PinIsFormatSupported(PaWinWdmPin* pin, const WAVEFORMATEX* format
}
else
{
if( dataRange->MinimumBitsPerSample > format->wBitsPerSample )
{
result = paSampleFormatNotSupported;
continue;
}
if( dataRange->MaximumBitsPerSample < format->wBitsPerSample )
if (!IsBitsWithinRange(dataRange, format->wBitsPerSample))
{
result = paSampleFormatNotSupported;
continue;
}
}
if( dataRange->MinimumSampleFrequency > format->nSamplesPerSec )
{
result = paInvalidSampleRate;
continue;
}
if( dataRange->MaximumSampleFrequency < format->nSamplesPerSec )
if (!IsFrequencyWithinRange(dataRange, format->nSamplesPerSec))
{
result = paInvalidSampleRate;
continue;
......@@ -2466,7 +2457,7 @@ static PaError PinRegisterNotificationHandle(PaWinWdmPin* pPin, HANDLE handle)
prop.NotificationEvent = handle;
prop.Property.Set = KSPROPSETID_RtAudio;
prop.Property.Id = KSPROPERTY_RTAUDIO_REGISTER_NOTIFICATION_EVENT;
prop.Property.Flags = KSPROPERTY_TYPE_GET;
prop.Property.Flags = KSPROPERTY_TYPE_SET;
result = WdmSyncIoctl(pPin->handle,
IOCTL_KS_PROPERTY,
......@@ -2497,7 +2488,7 @@ static PaError PinUnregisterNotificationHandle(PaWinWdmPin* pPin, HANDLE handle)
prop.NotificationEvent = handle;
prop.Property.Set = KSPROPSETID_RtAudio;
prop.Property.Id = KSPROPERTY_RTAUDIO_UNREGISTER_NOTIFICATION_EVENT;
prop.Property.Flags = KSPROPERTY_TYPE_GET;
prop.Property.Flags = KSPROPERTY_TYPE_SET;
result = WdmSyncIoctl(pPin->handle,
IOCTL_KS_PROPERTY,
......@@ -2552,14 +2543,14 @@ static PaError PinGetHwLatency(PaWinWdmPin* pPin, ULONG* pFifoSize, ULONG* pChip
}
/* This one is used for WaveRT */
static PaError PinGetAudioPositionDirect(PaWinWdmPin* pPin, ULONG* pPosition)
static PaError PinGetAudioPositionMemoryMapped(PaWinWdmPin* pPin, ULONG* pPosition)
{
*pPosition = (*pPin->positionRegister);
return paNoError;
}
/* This one also, but in case the driver hasn't implemented memory mapped access to the position register */
static PaError PinGetAudioPositionViaIOCTL(PaWinWdmPin* pPin, ULONG* pPosition)
static PaError PinGetAudioPositionViaIOCTLRead(PaWinWdmPin* pPin, ULONG* pPosition)
{
PaError result = paNoError;
KSPROPERTY propIn;
......@@ -2583,7 +2574,41 @@ static PaError PinGetAudioPositionViaIOCTL(PaWinWdmPin* pPin, ULONG* pPosition)
}
else
{
PA_DEBUG(("Failed to get audio position!\n"));
PA_DEBUG(("Failed to get audio play position!\n"));
}
PA_LOGL_;
return result;
}
/* This one also, but in case the driver hasn't implemented memory mapped access to the position register */
static PaError PinGetAudioPositionViaIOCTLWrite(PaWinWdmPin* pPin, ULONG* pPosition)
{
PaError result = paNoError;
KSPROPERTY propIn;
KSAUDIO_POSITION propOut;
PA_LOGE_;
propIn.Set = KSPROPSETID_Audio;
propIn.Id = KSPROPERTY_AUDIO_POSITION;
propIn.Flags = KSPROPERTY_TYPE_GET;
result = WdmSyncIoctl(pPin->handle,
IOCTL_KS_PROPERTY,
&propIn, sizeof(KSPROPERTY),
&propOut, sizeof(KSAUDIO_POSITION),
NULL);
if (result == paNoError)
{
*pPosition = (ULONG)(propOut.WriteOffset);
}
else
{
PA_DEBUG(("Failed to get audio write position!\n"));
}
PA_LOGL_;
......@@ -2800,7 +2825,6 @@ error:
*/
static void FilterFree(PaWinWdmFilter* filter)
{
int pinId;
PA_LOGL_;
if( filter )
{
......@@ -2810,13 +2834,14 @@ static void FilterFree(PaWinWdmFilter* filter)
return;
}
if (filter->topologyFilter)
if ( filter->topologyFilter )
{
FilterFree(filter->topologyFilter);
filter->topologyFilter = 0;
}
if ( filter->pins )
{
int pinId;
for( pinId = 0; pinId < filter->pinCount; pinId++ )
PinFree(filter->pins[pinId]);
PaUtil_FreeMemory( filter->pins );
......@@ -3374,6 +3399,10 @@ static PaError ScanDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaH
int filterCount = 0;
int totalDeviceCount = 0;
int idxDevice = 0;
DWORD defaultInDevPathSize = 0;
DWORD defaultOutDevPathSize = 0;
wchar_t* defaultInDevPath = 0;
wchar_t* defaultOutDevPath = 0;
ppFilters = BuildFilterList( &filterCount, &totalDeviceCount, &result );
if( result != paNoError )
......@@ -3381,11 +3410,24 @@ static PaError ScanDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaH
goto error;
}
// Get hold of default device paths for capture & playback
if( waveInMessage(0, DRV_QUERYDEVICEINTERFACESIZE, (DWORD_PTR)&defaultInDevPathSize, 0 ) == MMSYSERR_NOERROR )
{
defaultInDevPath = (wchar_t *)PaUtil_AllocateMemory((defaultInDevPathSize + 1) * sizeof(wchar_t));
waveInMessage(0, DRV_QUERYDEVICEINTERFACE, (DWORD_PTR)defaultInDevPath, defaultInDevPathSize);
}
if( waveOutMessage(0, DRV_QUERYDEVICEINTERFACESIZE, (DWORD_PTR)&defaultOutDevPathSize, 0 ) == MMSYSERR_NOERROR )
{
defaultOutDevPath = (wchar_t *)PaUtil_AllocateMemory((defaultOutDevPathSize + 1) * sizeof(wchar_t));
waveOutMessage(0, DRV_QUERYDEVICEINTERFACE, (DWORD_PTR)defaultOutDevPath, defaultOutDevPathSize);
}
if( totalDeviceCount > 0 )
{
PaWinWdmDeviceInfo *deviceInfoArray = 0;
int idxFilter;
int i;
unsigned devIsDefaultIn = 0, devIsDefaultOut = 0;
/* Allocate the out param for all the info we need */
outArgument = (PaWinWDMScanDeviceInfosResults *) PaUtil_GroupAllocateMemory(
......@@ -3440,6 +3482,9 @@ static PaError ScanDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaH
continue;
}
devIsDefaultIn = (defaultInDevPath && (_wcsicmp(pFilter->devInfo.filterPath, defaultInDevPath) == 0));
devIsDefaultOut = (defaultOutDevPath && (_wcsicmp(pFilter->devInfo.filterPath, defaultOutDevPath) == 0));
for (i = 0; i < pFilter->pinCount; ++i)
{
unsigned m;
......@@ -3501,14 +3546,19 @@ static PaError ScanDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaH
/* Convert wide char string to utf-8 */
WideCharToMultiByte(CP_UTF8, 0, localCompositeName, -1, wdmDeviceInfo->compositeName, MAX_PATH, NULL, NULL);
/* NB! WDM/KS has no concept of a full-duplex device, each pin is either an input or and output */
/* NB! WDM/KS has no concept of a full-duplex device, each pin is either an input or an output */
if (isInput)
{
/* INPUT ! */
deviceInfo->maxInputChannels = pin->maxChannels;
deviceInfo->maxOutputChannels = 0;
if (outArgument->defaultInputDevice == paNoDevice)
/* RoBi NB: Due to the fact that input audio endpoints in Vista (& later OSs) can be the same device, but with
different input mux settings, there might be a discrepancy between the default input device chosen, and
that which will be used by Portaudio. Not much to do about that unfortunately.
*/
if ((defaultInDevPath == 0 || devIsDefaultIn) &&
outArgument->defaultInputDevice == paNoDevice)
{
outArgument->defaultInputDevice = idxDevice;
}
......@@ -3519,7 +3569,8 @@ static PaError ScanDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaH
deviceInfo->maxInputChannels = 0;
deviceInfo->maxOutputChannels = pin->maxChannels;
if (outArgument->defaultOutputDevice == paNoDevice)
if ((defaultOutDevPath == 0 || devIsDefaultOut) &&
outArgument->defaultOutputDevice == paNoDevice)
{
outArgument->defaultOutputDevice = idxDevice;
}
......@@ -4159,7 +4210,8 @@ static unsigned NextPowerOf2(unsigned val)
static PaError ValidateSpecificStreamParameters(
const PaStreamParameters *streamParameters,
const PaWinWDMKSInfo *streamInfo)
const PaWinWDMKSInfo *streamInfo,
unsigned isInput)
{
if( streamInfo )
{
......@@ -4170,6 +4222,12 @@ static PaError ValidateSpecificStreamParameters(
return paIncompatibleHostApiSpecificStreamInfo;
}
if (!!(streamInfo->flags & ~(paWinWDMKSOverrideFramesize | paWinWDMKSUseGivenChannelMask)))
{
PA_DEBUG(("Stream parameters: non supported flags set"));
return paIncompatibleHostApiSpecificStreamInfo;
}
if (streamInfo->noOfPackets != 0 &&
(streamInfo->noOfPackets < 2 || streamInfo->noOfPackets > 8))
{
......@@ -4177,6 +4235,21 @@ static PaError ValidateSpecificStreamParameters(
return paIncompatibleHostApiSpecificStreamInfo;
}
if (streamInfo->flags & paWinWDMKSUseGivenChannelMask)
{
if (isInput)
{
PA_DEBUG(("Stream parameters: Channels mask setting not supported for input stream"));
return paIncompatibleHostApiSpecificStreamInfo;
}
if (streamInfo->channelMask & PAWIN_SPEAKER_RESERVED)
{
PA_DEBUG(("Stream parameters: Given channels mask 0x%08X not supported", streamInfo->channelMask));
return paIncompatibleHostApiSpecificStreamInfo;
}
}
}
return paNoError;
......@@ -4184,6 +4257,7 @@ static PaError ValidateSpecificStreamParameters(
/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
......@@ -4231,7 +4305,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
}
/* validate inputStreamInfo */
result = ValidateSpecificStreamParameters(inputParameters, inputParameters->hostApiSpecificStreamInfo);
result = ValidateSpecificStreamParameters(inputParameters, inputParameters->hostApiSpecificStreamInfo, 1 );
if(result != paNoError)
{
PaWinWDM_SetLastErrorInfo(result, "Host API stream info not supported (in)");
......@@ -4266,7 +4340,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
}
/* validate outputStreamInfo */
result = ValidateSpecificStreamParameters( outputParameters, outputParameters->hostApiSpecificStreamInfo );
result = ValidateSpecificStreamParameters( outputParameters, outputParameters->hostApiSpecificStreamInfo, 0 );
if (result != paNoError)
{
PaWinWDM_SetLastErrorInfo(result, "Host API stream info not supported (out)");
......@@ -4471,8 +4545,16 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
PaWinWdmFilter* pFilter;
PaWinWdmDeviceInfo* pDeviceInfo;
PaWinWdmPin* pPin;
PaWinWDMKSInfo* pInfo = (PaWinWDMKSInfo*)(outputParameters->hostApiSpecificStreamInfo);
unsigned validBitsPerSample = 0;
PaWinWaveFormatChannelMask channelMask = PaWin_DefaultChannelMask( userOutputChannels );
if (pInfo && (pInfo->flags & paWinWDMKSUseGivenChannelMask))
{
PA_DEBUG(("Using channelMask 0x%08X instead of default 0x%08X\n",
pInfo->channelMask,
channelMask));
channelMask = pInfo->channelMask;
}
result = paSampleFormatNotSupported;
pDeviceInfo = (PaWinWdmDeviceInfo*)wdmHostApi->inheritedHostApiRep.deviceInfos[outputParameters->device];
......@@ -4960,8 +5042,8 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
if (result != paNoError)
{
unsigned long pos = 0xdeadc0de;
PA_DEBUG(("Failed to register capture position register, using PinGetAudioPositionViaIOCTL\n"));
stream->capture.pPin->fnAudioPosition = PinGetAudioPositionViaIOCTL;
PA_DEBUG(("Failed to register capture position register, using PinGetAudioPositionViaIOCTLWrite\n"));
stream->capture.pPin->fnAudioPosition = PinGetAudioPositionViaIOCTLWrite;
/* Test position function */
result = (stream->capture.pPin->fnAudioPosition)(stream->capture.pPin, &pos);
if (result != paNoError || pos != 0x0)
......@@ -4974,7 +5056,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
}
else
{
stream->capture.pPin->fnAudioPosition = PinGetAudioPositionDirect;
stream->capture.pPin->fnAudioPosition = PinGetAudioPositionMemoryMapped;
}
}
break;
......@@ -5082,8 +5164,8 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
if (result != paNoError)
{
unsigned long pos = 0xdeadc0de;
PA_DEBUG(("Failed to register rendering position register, using PinGetAudioPositionViaIOCTL\n"));
stream->render.pPin->fnAudioPosition = PinGetAudioPositionViaIOCTL;
PA_DEBUG(("Failed to register rendering position register, using PinGetAudioPositionViaIOCTLRead\n"));
stream->render.pPin->fnAudioPosition = PinGetAudioPositionViaIOCTLRead;
/* Test position function */
result = (stream->render.pPin->fnAudioPosition)(stream->render.pPin, &pos);
if (result != paNoError || pos != 0x0)
......@@ -5096,7 +5178,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
}
else
{
stream->render.pPin->fnAudioPosition = PinGetAudioPositionDirect;
stream->render.pPin->fnAudioPosition = PinGetAudioPositionMemoryMapped;
}
}
break;
......
......@@ -4,6 +4,10 @@
MACRO(ADD_TEST appl_name)
ADD_EXECUTABLE(${appl_name} "${appl_name}.c")
TARGET_LINK_LIBRARIES(${appl_name} portaudio_static)
SET_TARGET_PROPERTIES(${appl_name}
PROPERTIES
FOLDER "Test"
)
ENDMACRO(ADD_TEST)
ADD_TEST(patest_longsine)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment