📄 pa_win_ds.c
字号:
PaError PaWinDs_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
{
PaError result = paNoError;
int i, deviceCount;
PaWinDsHostApiRepresentation *winDsHostApi;
DSDeviceNameAndGUIDVector inputNamesAndGUIDs, outputNamesAndGUIDs;
PaDeviceInfo *deviceInfoArray;
HRESULT hr = CoInitialize(NULL); /** @todo: should uninitialize too */
if( FAILED(hr) ){
return paUnanticipatedHostError;
}
/* initialise guid vectors so they can be safely deleted on error */
inputNamesAndGUIDs.items = NULL;
outputNamesAndGUIDs.items = NULL;
DSW_InitializeDSoundEntryPoints();
winDsHostApi = (PaWinDsHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaWinDsHostApiRepresentation) );
if( !winDsHostApi )
{
result = paInsufficientMemory;
goto error;
}
winDsHostApi->allocations = PaUtil_CreateAllocationGroup();
if( !winDsHostApi->allocations )
{
result = paInsufficientMemory;
goto error;
}
*hostApi = &winDsHostApi->inheritedHostApiRep;
(*hostApi)->info.structVersion = 1;
(*hostApi)->info.type = paDirectSound;
(*hostApi)->info.name = "Windows DirectSound";
(*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( &inputNamesAndGUIDs, winDsHostApi->allocations );
if( result != paNoError )
goto error;
result = InitializeDSDeviceNameAndGUIDVector( &outputNamesAndGUIDs, winDsHostApi->allocations );
if( result != paNoError )
goto error;
dswDSoundEntryPoints.DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK)CollectGUIDsProc, (void *)&inputNamesAndGUIDs );
dswDSoundEntryPoints.DirectSoundEnumerate( (LPDSENUMCALLBACK)CollectGUIDsProc, (void *)&outputNamesAndGUIDs );
if( inputNamesAndGUIDs.enumerationError != paNoError )
{
result = inputNamesAndGUIDs.enumerationError;
goto error;
}
if( outputNamesAndGUIDs.enumerationError != paNoError )
{
result = outputNamesAndGUIDs.enumerationError;
goto error;
}
deviceCount = inputNamesAndGUIDs.count + outputNamesAndGUIDs.count;
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 = (PaDeviceInfo*)PaUtil_GroupAllocateMemory(
winDsHostApi->allocations, sizeof(PaDeviceInfo) * deviceCount );
if( !deviceInfoArray )
{
result = paInsufficientMemory;
goto error;
}
/* allocate all DSound specific info structs in a contiguous block */
winDsHostApi->winDsDeviceInfos = (PaWinDsDeviceInfo*)PaUtil_GroupAllocateMemory(
winDsHostApi->allocations, sizeof(PaWinDsDeviceInfo) * deviceCount );
if( !winDsHostApi->winDsDeviceInfos )
{
result = paInsufficientMemory;
goto error;
}
for( i=0; i < deviceCount; ++i )
{
PaDeviceInfo *deviceInfo = &deviceInfoArray[i];
deviceInfo->structVersion = 2;
deviceInfo->hostApi = hostApiIndex;
deviceInfo->name = 0;
(*hostApi)->deviceInfos[i] = deviceInfo;
}
for( i=0; i< inputNamesAndGUIDs.count; ++i )
{
result = AddInputDeviceInfoFromDirectSoundCapture( winDsHostApi,
inputNamesAndGUIDs.items[i].name,
inputNamesAndGUIDs.items[i].lpGUID );
if( result != paNoError )
goto error;
}
for( i=0; i< outputNamesAndGUIDs.count; ++i )
{
result = AddOutputDeviceInfoFromDirectSound( winDsHostApi,
outputNamesAndGUIDs.items[i].name,
outputNamesAndGUIDs.items[i].lpGUID );
if( result != paNoError )
goto error;
}
}
result = TerminateDSDeviceNameAndGUIDVector( &inputNamesAndGUIDs );
if( result != paNoError )
goto error;
result = TerminateDSDeviceNameAndGUIDVector( &outputNamesAndGUIDs );
if( result != paNoError )
goto error;
(*hostApi)->Terminate = Terminate;
(*hostApi)->OpenStream = OpenStream;
(*hostApi)->IsFormatSupported = IsFormatSupported;
PaUtil_InitializeStreamInterface( &winDsHostApi->callbackStreamInterface, CloseStream, StartStream,
StopStream, AbortStream, IsStreamStopped, IsStreamActive,
GetStreamTime, GetStreamCpuLoad,
PaUtil_DummyRead, PaUtil_DummyWrite,
PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );
PaUtil_InitializeStreamInterface( &winDsHostApi->blockingStreamInterface, CloseStream, StartStream,
StopStream, AbortStream, IsStreamStopped, IsStreamActive,
GetStreamTime, PaUtil_DummyGetCpuLoad,
ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
return result;
error:
if( winDsHostApi )
{
if( winDsHostApi->allocations )
{
PaUtil_FreeAllAllocations( winDsHostApi->allocations );
PaUtil_DestroyAllocationGroup( winDsHostApi->allocations );
}
PaUtil_FreeMemory( winDsHostApi );
}
TerminateDSDeviceNameAndGUIDVector( &inputNamesAndGUIDs );
TerminateDSDeviceNameAndGUIDVector( &outputNamesAndGUIDs );
return result;
}
/***********************************************************************************/
static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
{
PaWinDsHostApiRepresentation *winDsHostApi = (PaWinDsHostApiRepresentation*)hostApi;
/*
IMPLEMENT ME:
- clean up any resources not handled by the allocation group
*/
if( winDsHostApi->allocations )
{
PaUtil_FreeAllAllocations( winDsHostApi->allocations );
PaUtil_DestroyAllocationGroup( winDsHostApi->allocations );
}
PaUtil_FreeMemory( winDsHostApi );
DSW_TerminateDSoundEntryPoints();
CoUninitialize();
}
/* Set minimal latency based on whether NT or Win95.
* NT has higher latency.
*/
static int PaWinDS_GetMinSystemLatency( void )
{
int minLatencyMsec;
/* Set minimal latency based on whether NT or other OS.
* NT has higher latency.
*/
OSVERSIONINFO osvi;
osvi.dwOSVersionInfoSize = sizeof( osvi );
GetVersionEx( &osvi );
DBUG(("PA - PlatformId = 0x%x\n", osvi.dwPlatformId ));
DBUG(("PA - MajorVersion = 0x%x\n", osvi.dwMajorVersion ));
DBUG(("PA - MinorVersion = 0x%x\n", osvi.dwMinorVersion ));
/* Check for NT */
if( (osvi.dwMajorVersion == 4) && (osvi.dwPlatformId == 2) )
{
minLatencyMsec = PA_WIN_NT_LATENCY;
}
else if(osvi.dwMajorVersion >= 5)
{
minLatencyMsec = PA_WIN_WDM_LATENCY;
}
else
{
minLatencyMsec = PA_WIN_9X_LATENCY;
}
return minLatencyMsec;
}
/***********************************************************************************/
static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
const PaStreamParameters *inputParameters,
const PaStreamParameters *outputParameters,
double sampleRate )
{
int inputChannelCount, outputChannelCount;
PaSampleFormat inputSampleFormat, outputSampleFormat;
if( inputParameters )
{
inputChannelCount = inputParameters->channelCount;
inputSampleFormat = inputParameters->sampleFormat;
/* unless alternate device specification is supported, reject the use of
paUseHostApiSpecificDeviceSpecification */
if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
return paInvalidDevice;
/* check that input device can support inputChannelCount */
if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
return paInvalidChannelCount;
/* validate inputStreamInfo */
if( inputParameters->hostApiSpecificStreamInfo )
return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
}
else
{
inputChannelCount = 0;
}
if( outputParameters )
{
outputChannelCount = outputParameters->channelCount;
outputSampleFormat = outputParameters->sampleFormat;
/* unless alternate device specification is supported, reject the use of
paUseHostApiSpecificDeviceSpecification */
if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
return paInvalidDevice;
/* check that output device can support inputChannelCount */
if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
return paInvalidChannelCount;
/* validate outputStreamInfo */
if( outputParameters->hostApiSpecificStreamInfo )
return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
}
else
{
outputChannelCount = 0;
}
/*
IMPLEMENT ME:
- if a full duplex stream is requested, check that the combination
of input and output parameters is supported if necessary
- check that the device supports sampleRate
Because the buffer adapter handles conversion between all standard
sample formats, the following checks are only required if paCustomFormat
is implemented, or under some other unusual conditions.
- check that input device can support inputSampleFormat, or that
we have the capability to convert from outputSampleFormat to
a native format
- check that output device can support outputSampleFormat, or that
we have the capability to convert from outputSampleFormat to
a native format
*/
return paFormatIsSupported;
}
/*************************************************************************
** Determine minimum number of buffers required for this host based
** on minimum latency. Latency can be optionally set by user by setting
** an environment variable. For example, to set latency to 200 msec, put:
**
** set PA_MIN_LATENCY_MSEC=200
**
** in the AUTOEXEC.BAT file and reboot.
** If the environment variable is not set, then the latency will be determined
** based on the OS. Windows NT has higher latency than Win95.
*/
#define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC")
#define PA_ENV_BUF_SIZE (32)
static int PaWinDs_GetMinLatencyFrames( double sampleRate )
{
char envbuf[PA_ENV_BUF_SIZE];
DWORD hresult;
int minLatencyMsec = 0;
/* Let user determine minimal latency by setting environment variable. */
#ifdef UNDER_CE
hresult = 0;
#else
hresult = GetEnvironmentVariable( PA_LATENCY_ENV_NAME, envbuf, PA_ENV_BUF_SIZE );
#endif
if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) )
{
minLatencyMsec = atoi( envbuf );
}
else
{
minLatencyMsec = PaWinDS_GetMinSystemLatency();
#if PA_USE_HIGH_LATENCY
PRINT(("PA - Minimum Latency set to %d msec!\n", minLatencyMsec ));
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -