📄 pa_win_wmme.c
字号:
{
result = paUnanticipatedHostError;
PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );
}
}
return result;
}
/* PaWinMmeHostApiRepresentation - host api datastructure specific to this implementation */
typedef struct
{
PaUtilHostApiRepresentation inheritedHostApiRep;
PaUtilStreamInterface callbackStreamInterface;
PaUtilStreamInterface blockingStreamInterface;
PaUtilAllocationGroup *allocations;
int inputDeviceCount, outputDeviceCount;
/** winMmeDeviceIds is an array of WinMme device ids.
fields in the range [0, inputDeviceCount) are input device ids,
and [inputDeviceCount, inputDeviceCount + outputDeviceCount) are output
device ids.
*/
UINT *winMmeDeviceIds;
}
PaWinMmeHostApiRepresentation;
typedef struct
{
PaDeviceInfo inheritedDeviceInfo;
DWORD dwFormats; /**<< standard formats bitmask from the WAVEINCAPS and WAVEOUTCAPS structures */
}
PaWinMmeDeviceInfo;
/*************************************************************************
* Returns recommended device ID.
* On the PC, the recommended device can be specified by the user by
* setting an environment variable. For example, to use device #1.
*
* set PA_RECOMMENDED_OUTPUT_DEVICE=1
*
* The user should first determine the available device ID by using
* the supplied application "pa_devs".
*/
#define PA_ENV_BUF_SIZE_ (32)
#define PA_REC_IN_DEV_ENV_NAME_ ("PA_RECOMMENDED_INPUT_DEVICE")
#define PA_REC_OUT_DEV_ENV_NAME_ ("PA_RECOMMENDED_OUTPUT_DEVICE")
static PaDeviceIndex GetEnvDefaultDeviceID( char *envName )
{
PaDeviceIndex recommendedIndex = paNoDevice;
DWORD hresult;
char envbuf[PA_ENV_BUF_SIZE_];
#ifndef WIN32_PLATFORM_PSPC /* no GetEnvironmentVariable on PocketPC */
/* Let user determine default device by setting environment variable. */
hresult = GetEnvironmentVariable( envName, envbuf, PA_ENV_BUF_SIZE_ );
if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE_) )
{
recommendedIndex = atoi( envbuf );
}
#endif
return recommendedIndex;
}
static void InitializeDefaultDeviceIdsFromEnv( PaWinMmeHostApiRepresentation *hostApi )
{
PaDeviceIndex device;
/* input */
device = GetEnvDefaultDeviceID( PA_REC_IN_DEV_ENV_NAME_ );
if( device != paNoDevice &&
( device >= 0 && device < hostApi->inheritedHostApiRep.info.deviceCount ) &&
hostApi->inheritedHostApiRep.deviceInfos[ device ]->maxInputChannels > 0 )
{
hostApi->inheritedHostApiRep.info.defaultInputDevice = device;
}
/* output */
device = GetEnvDefaultDeviceID( PA_REC_OUT_DEV_ENV_NAME_ );
if( device != paNoDevice &&
( device >= 0 && device < hostApi->inheritedHostApiRep.info.deviceCount ) &&
hostApi->inheritedHostApiRep.deviceInfos[ device ]->maxOutputChannels > 0 )
{
hostApi->inheritedHostApiRep.info.defaultOutputDevice = device;
}
}
/** Convert external PA ID to a windows multimedia device ID
*/
static UINT LocalDeviceIndexToWinMmeDeviceId( PaWinMmeHostApiRepresentation *hostApi, PaDeviceIndex device )
{
assert( device >= 0 && device < hostApi->inputDeviceCount + hostApi->outputDeviceCount );
return hostApi->winMmeDeviceIds[ device ];
}
static PaError QueryInputWaveFormatEx( int deviceId, WAVEFORMATEX *waveFormatEx )
{
MMRESULT mmresult;
switch( mmresult = waveInOpen( NULL, deviceId, waveFormatEx, 0, 0, WAVE_FORMAT_QUERY ) )
{
case MMSYSERR_NOERROR:
return paNoError;
case MMSYSERR_ALLOCATED: /* Specified resource is already allocated. */
return paDeviceUnavailable;
case MMSYSERR_NODRIVER: /* No device driver is present. */
return paDeviceUnavailable;
case MMSYSERR_NOMEM: /* Unable to allocate or lock memory. */
return paInsufficientMemory;
case WAVERR_BADFORMAT: /* Attempted to open with an unsupported waveform-audio format. */
return paSampleFormatNotSupported;
case MMSYSERR_BADDEVICEID: /* Specified device identifier is out of range. */
/* falls through */
default:
PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
return paUnanticipatedHostError;
}
}
static PaError QueryOutputWaveFormatEx( int deviceId, WAVEFORMATEX *waveFormatEx )
{
MMRESULT mmresult;
switch( mmresult = waveOutOpen( NULL, deviceId, waveFormatEx, 0, 0, WAVE_FORMAT_QUERY ) )
{
case MMSYSERR_NOERROR:
return paNoError;
case MMSYSERR_ALLOCATED: /* Specified resource is already allocated. */
return paDeviceUnavailable;
case MMSYSERR_NODRIVER: /* No device driver is present. */
return paDeviceUnavailable;
case MMSYSERR_NOMEM: /* Unable to allocate or lock memory. */
return paInsufficientMemory;
case WAVERR_BADFORMAT: /* Attempted to open with an unsupported waveform-audio format. */
return paSampleFormatNotSupported;
case MMSYSERR_BADDEVICEID: /* Specified device identifier is out of range. */
/* falls through */
default:
PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
return paUnanticipatedHostError;
}
}
static PaError QueryFormatSupported( PaDeviceInfo *deviceInfo,
PaError (*waveFormatExQueryFunction)(int, WAVEFORMATEX*),
int winMmeDeviceId, int channels, double sampleRate )
{
PaWinMmeDeviceInfo *winMmeDeviceInfo = (PaWinMmeDeviceInfo*)deviceInfo;
WAVEFORMATEX waveFormatEx;
if( sampleRate == 11025.0
&& ( (channels == 1 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_1M16))
|| (channels == 2 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_1S16)) ) ){
return paNoError;
}
if( sampleRate == 22050.0
&& ( (channels == 1 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_2M16))
|| (channels == 2 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_2S16)) ) ){
return paNoError;
}
if( sampleRate == 44100.0
&& ( (channels == 1 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_4M16))
|| (channels == 2 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_4S16)) ) ){
return paNoError;
}
waveFormatEx.wFormatTag = WAVE_FORMAT_PCM;
waveFormatEx.nChannels = (WORD)channels;
waveFormatEx.nSamplesPerSec = (DWORD)sampleRate;
waveFormatEx.nAvgBytesPerSec = waveFormatEx.nSamplesPerSec * channels * sizeof(short);
waveFormatEx.nBlockAlign = (WORD)(channels * sizeof(short));
waveFormatEx.wBitsPerSample = 16;
waveFormatEx.cbSize = 0;
return waveFormatExQueryFunction( winMmeDeviceId, &waveFormatEx );
}
#define PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_ (13) /* must match array length below */
static double defaultSampleRateSearchOrder_[] =
{ 44100.0, 48000.0, 32000.0, 24000.0, 22050.0, 88200.0, 96000.0, 192000.0,
16000.0, 12000.0, 11025.0, 9600.0, 8000.0 };
static void DetectDefaultSampleRate( PaWinMmeDeviceInfo *winMmeDeviceInfo, int winMmeDeviceId,
PaError (*waveFormatExQueryFunction)(int, WAVEFORMATEX*), int maxChannels )
{
PaDeviceInfo *deviceInfo = &winMmeDeviceInfo->inheritedDeviceInfo;
int i;
deviceInfo->defaultSampleRate = 0.;
for( i=0; i < PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_; ++i )
{
double sampleRate = defaultSampleRateSearchOrder_[ i ];
PaError paerror = QueryFormatSupported( deviceInfo, waveFormatExQueryFunction, winMmeDeviceId, maxChannels, sampleRate );
if( paerror == paNoError )
{
deviceInfo->defaultSampleRate = sampleRate;
break;
}
}
}
static PaError InitializeInputDeviceInfo( PaWinMmeHostApiRepresentation *winMmeHostApi,
PaWinMmeDeviceInfo *winMmeDeviceInfo, UINT winMmeInputDeviceId, int *success )
{
PaError result = paNoError;
char *deviceName; /* non-const ptr */
MMRESULT mmresult;
WAVEINCAPS wic;
PaDeviceInfo *deviceInfo = &winMmeDeviceInfo->inheritedDeviceInfo;
PJ_DECL_ANSI_TEMP_BUF(abuf,128)
*success = 0;
mmresult = waveInGetDevCaps( winMmeInputDeviceId, &wic, sizeof( WAVEINCAPS ) );
if( mmresult == MMSYSERR_NOMEM )
{
result = paInsufficientMemory;
goto error;
}
else if( mmresult != MMSYSERR_NOERROR )
{
/* instead of returning paUnanticipatedHostError we return
paNoError, but leave success set as 0. This allows
Pa_Initialize to just ignore this device, without failing
the entire initialisation process.
*/
return paNoError;
}
if( winMmeInputDeviceId == WAVE_MAPPER )
{
/* Append I/O suffix to WAVE_MAPPER device. */
deviceName = (char*)PaUtil_GroupAllocateMemory(
winMmeHostApi->allocations,
pj_native_strlen( wic.szPname ) + sizeof(pj_char_t) + sizeof(constInputMapperSuffix_) );
if( !deviceName )
{
result = paInsufficientMemory;
goto error;
}
strcpy( deviceName, PJ_NATIVE_TO_STRING(wic.szPname,abuf,sizeof(abuf)) );
strcat( deviceName, PJ_NATIVE_TO_STRING(constInputMapperSuffix_,abuf,sizeof(abuf)) );
}
else
{
deviceName = (char*)PaUtil_GroupAllocateMemory(
winMmeHostApi->allocations, pj_native_strlen( wic.szPname ) + sizeof(pj_char_t) );
if( !deviceName )
{
result = paInsufficientMemory;
goto error;
}
strcpy( deviceName, PJ_NATIVE_TO_STRING(wic.szPname,abuf,sizeof(abuf)) );
}
deviceInfo->name = deviceName;
deviceInfo->maxInputChannels = wic.wChannels;
/* Sometimes a device can return a rediculously large number of channels.
* This happened with an SBLive card on a Windows ME box.
* If that happens, then force it to 2 channels. PLB20010413
*/
if( (deviceInfo->maxInputChannels < 1) || (deviceInfo->maxInputChannels > 256) )
{
PA_DEBUG(("Pa_GetDeviceInfo: Num input channels reported as %d! Changed to 2.\n", deviceInfo->maxInputChannels ));
deviceInfo->maxInputChannels = 2;
}
winMmeDeviceInfo->dwFormats = wic.dwFormats;
DetectDefaultSampleRate( winMmeDeviceInfo, winMmeInputDeviceId,
QueryInputWaveFormatEx, deviceInfo->maxInputChannels );
*success = 1;
error:
return result;
}
static PaError InitializeOutputDeviceInfo( PaWinMmeHostApiRepresentation *winMmeHostApi,
PaWinMmeDeviceInfo *winMmeDeviceInfo, UINT winMmeOutputDeviceId, int *success )
{
PaError result = paNoError;
char *deviceName; /* non-const ptr */
MMRESULT mmresult;
WAVEOUTCAPS woc;
PaDeviceInfo *deviceInfo = &winMmeDeviceInfo->inheritedDeviceInfo;
PJ_DECL_ANSI_TEMP_BUF(abuf,128)
*success = 0;
mmresult = waveOutGetDevCaps( winMmeOutputDeviceId, &woc, sizeof( WAVEOUTCAPS ) );
if( mmresult == MMSYSERR_NOMEM )
{
result = paInsufficientMemory;
goto error;
}
else if( mmresult != MMSYSERR_NOERROR )
{
/* instead of returning paUnanticipatedHostError we return
paNoError, but leave success set as 0. This allows
Pa_Initialize to just ignore this device, without failing
the entire initialisation process.
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -