📄 pa_win_wmme.c
字号:
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; *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, strlen( wic.szPname ) + 1 + sizeof(constInputMapperSuffix_) ); if( !deviceName ) { result = paInsufficientMemory; goto error; } strcpy( deviceName, wic.szPname ); strcat( deviceName, constInputMapperSuffix_ ); } else { deviceName = (char*)PaUtil_GroupAllocateMemory( winMmeHostApi->allocations, strlen( wic.szPname ) + 1 ); if( !deviceName ) { result = paInsufficientMemory; goto error; } strcpy( deviceName, wic.szPname ); } 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; *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. */ return paNoError; } if( winMmeOutputDeviceId == WAVE_MAPPER ) { /* Append I/O suffix to WAVE_MAPPER device. */ deviceName = (char *)PaUtil_GroupAllocateMemory( winMmeHostApi->allocations, strlen( woc.szPname ) + 1 + sizeof(constOutputMapperSuffix_) ); if( !deviceName ) { result = paInsufficientMemory; goto error; } strcpy( deviceName, woc.szPname ); strcat( deviceName, constOutputMapperSuffix_ ); } else { deviceName = (char*)PaUtil_GroupAllocateMemory( winMmeHostApi->allocations, strlen( woc.szPname ) + 1 ); if( !deviceName ) { result = paInsufficientMemory; goto error; } strcpy( deviceName, woc.szPname ); } deviceInfo->name = deviceName; deviceInfo->maxOutputChannels = woc.wChannels; /* Sometimes a device can return a rediculously large number of channels. * This happened with an SBLive card on a Windows ME box.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -