📄 pa_win_wmme.c
字号:
for( i = 0; i < sNumDevices; i++ )
sDevicePtrs[i] = NULL; /* RDB20020417 explicitly set each ptr to NULL */
}
else
{
sDevicePtrs = NULL;
}
return paNoError;
}
/*************************************************************************/
long Pa_GetHostError()
{
return sPaHostError;
}
/*************************************************************************/
int Pa_CountDevices()
{
if( PaHost_IsInitialized() )
return sNumDevices;
else
return 0;
}
/*************************************************************************
* If a PaDeviceInfo structure has not already been created,
* then allocate one and fill it in for the selected device.
*
* We create one extra input and one extra output device for the WAVE_MAPPER.
* [Does anyone know how to query the default device and get its name?]
*/
const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id )
{
#define NUM_STANDARDSAMPLINGRATES 3 /* 11025, 22050, 44100 */
static DWORD customSamplingRates[] = { 8000, 32000, 48000, 64000, 88200, 96000 };
#define NUM_CUSTOMSAMPLINGRATES (sizeof(customSamplingRates)/sizeof(DWORD))
#define MAX_NUMSAMPLINGRATES (NUM_STANDARDSAMPLINGRATES+NUM_CUSTOMSAMPLINGRATES)
PaDeviceInfo *deviceInfo;
double *sampleRates; /* non-const ptr */
int i;
char *s;
DBUG(( "Pa_GetDeviceInfo( %d )\n", id ));
if( id < 0 || id >= sNumDevices )
return NULL;
if( sDevicePtrs[ id ] != NULL )
{
return sDevicePtrs[ id ];
}
deviceInfo = (PaDeviceInfo *)PaHost_AllocateTrackedMemory( sizeof(PaDeviceInfo) ); /* MEM */
if( deviceInfo == NULL ) return NULL;
deviceInfo->structVersion = 1;
deviceInfo->maxInputChannels = 0;
deviceInfo->maxOutputChannels = 0;
deviceInfo->numSampleRates = 0;
sampleRates = (double*)PaHost_AllocateTrackedMemory( MAX_NUMSAMPLINGRATES * sizeof(double) ); /* MEM */
deviceInfo->sampleRates = sampleRates;
deviceInfo->nativeSampleFormats = paInt16; /* should query for higher bit depths below */
if( id < sNumInputDevices )
{
/* input device */
int inputMmID = PaDeviceIdToWinId(id);
WAVEINCAPS wic;
if( waveInGetDevCaps( inputMmID, &wic, sizeof( WAVEINCAPS ) ) != MMSYSERR_NOERROR )
goto error;
/* Append I/O suffix to WAVE_MAPPER device. */
if( inputMmID == WAVE_MAPPER )
{
s = (char *) PaHost_AllocateTrackedMemory( strlen( wic.szPname ) + 1 + sizeof(sMapperSuffixInput) ); /* MEM */
strcpy( s, wic.szPname );
strcat( s, sMapperSuffixInput );
}
else
{
s = (char *) PaHost_AllocateTrackedMemory( strlen( wic.szPname ) + 1 ); /* MEM */
strcpy( s, wic.szPname );
}
deviceInfo->name = s;
deviceInfo->maxInputChannels = wic.wChannels;
DBUG(( "Pa_GetDeviceInfo: input %s, maxChannels = %d\n", deviceInfo->name, deviceInfo->maxInputChannels ));
/* 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) )
{
ERR_RPT(("Pa_GetDeviceInfo: Num input channels reported as %d! Changed to 2.\n", deviceInfo->maxOutputChannels ));
deviceInfo->maxInputChannels = 2;
}
/* Add a sample rate to the list if we can do stereo 16 bit at that rate
* based on the format flags. */
if( wic.dwFormats & WAVE_FORMAT_1M16 ||wic.dwFormats & WAVE_FORMAT_1S16 )
sampleRates[ deviceInfo->numSampleRates++ ] = 11025.;
if( wic.dwFormats & WAVE_FORMAT_2M16 ||wic.dwFormats & WAVE_FORMAT_2S16 )
sampleRates[ deviceInfo->numSampleRates++ ] = 22050.;
if( wic.dwFormats & WAVE_FORMAT_4M16 ||wic.dwFormats & WAVE_FORMAT_4S16 )
sampleRates[ deviceInfo->numSampleRates++ ] = 44100.;
/* Add a sample rate to the list if we can do stereo 16 bit at that rate
* based on opening the device successfully. */
for( i=0; i < NUM_CUSTOMSAMPLINGRATES; i++ )
{
WAVEFORMATEX wfx;
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nSamplesPerSec = customSamplingRates[i];
wfx.wBitsPerSample = 16;
wfx.cbSize = 0; /* ignored */
wfx.nChannels = (WORD)deviceInfo->maxInputChannels;
wfx.nAvgBytesPerSec = wfx.nChannels * wfx.nSamplesPerSec * sizeof(short);
wfx.nBlockAlign = (WORD)(wfx.nChannels * sizeof(short));
if( waveInOpen( NULL, inputMmID, &wfx, 0, 0, WAVE_FORMAT_QUERY ) == MMSYSERR_NOERROR )
{
sampleRates[ deviceInfo->numSampleRates++ ] = customSamplingRates[i];
}
}
}
else if( id - sNumInputDevices < sNumOutputDevices )
{
/* output device */
int outputMmID = PaDeviceIdToWinId(id);
WAVEOUTCAPS woc;
if( waveOutGetDevCaps( outputMmID, &woc, sizeof( WAVEOUTCAPS ) ) != MMSYSERR_NOERROR )
goto error;
/* Append I/O suffix to WAVE_MAPPER device. */
if( outputMmID == WAVE_MAPPER )
{
s = (char *) PaHost_AllocateTrackedMemory( strlen( woc.szPname ) + 1 + sizeof(sMapperSuffixOutput) ); /* MEM */
strcpy( s, woc.szPname );
strcat( s, sMapperSuffixOutput );
}
else
{
s = (char *) PaHost_AllocateTrackedMemory( strlen( woc.szPname ) + 1 ); /* MEM */
strcpy( s, woc.szPname );
}
deviceInfo->name = s;
deviceInfo->maxOutputChannels = woc.wChannels;
DBUG(( "Pa_GetDeviceInfo: output %s, maxChannels = %d\n", deviceInfo->name, deviceInfo->maxOutputChannels ));
/* Sometimes a device can return a rediculously large number of channels.
* This happened with an SBLive card on a Windows ME box.
* It also happens on Win XP!
*/
if( (deviceInfo->maxOutputChannels < 1) || (deviceInfo->maxOutputChannels > 256) )
{
#if 1
deviceInfo->maxOutputChannels = 2;
#else
/* If channel max is goofy, then query for max channels. PLB20020228
* This doesn't seem to help. Disable code for now. Remove it later.
*/
ERR_RPT(("Pa_GetDeviceInfo: Num output channels reported as %d!", deviceInfo->maxOutputChannels ));
deviceInfo->maxOutputChannels = 0;
/* Attempt to find the correct maximum by querying the device. */
for( i=2; i<16; i += 2 )
{
WAVEFORMATEX wfx;
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nSamplesPerSec = 44100;
wfx.wBitsPerSample = 16;
wfx.cbSize = 0; /* ignored */
wfx.nChannels = (WORD) i;
wfx.nAvgBytesPerSec = wfx.nChannels * wfx.nSamplesPerSec * sizeof(short);
wfx.nBlockAlign = (WORD)(wfx.nChannels * sizeof(short));
if( waveOutOpen( NULL, outputMmID, &wfx, 0, 0, WAVE_FORMAT_QUERY ) == MMSYSERR_NOERROR )
{
deviceInfo->maxOutputChannels = i;
}
else
{
break;
}
}
#endif
ERR_RPT((" Changed to %d.\n", deviceInfo->maxOutputChannels ));
}
/* Add a sample rate to the list if we can do stereo 16 bit at that rate
* based on the format flags. */
if( woc.dwFormats & WAVE_FORMAT_1M16 ||woc.dwFormats & WAVE_FORMAT_1S16 )
sampleRates[ deviceInfo->numSampleRates++ ] = 11025.;
if( woc.dwFormats & WAVE_FORMAT_2M16 ||woc.dwFormats & WAVE_FORMAT_2S16 )
sampleRates[ deviceInfo->numSampleRates++ ] = 22050.;
if( woc.dwFormats & WAVE_FORMAT_4M16 ||woc.dwFormats & WAVE_FORMAT_4S16 )
sampleRates[ deviceInfo->numSampleRates++ ] = 44100.;
/* Add a sample rate to the list if we can do stereo 16 bit at that rate
* based on opening the device successfully. */
for( i=0; i < NUM_CUSTOMSAMPLINGRATES; i++ )
{
WAVEFORMATEX wfx;
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nSamplesPerSec = customSamplingRates[i];
wfx.wBitsPerSample = 16;
wfx.cbSize = 0; /* ignored */
wfx.nChannels = (WORD)deviceInfo->maxOutputChannels;
wfx.nAvgBytesPerSec = wfx.nChannels * wfx.nSamplesPerSec * sizeof(short);
wfx.nBlockAlign = (WORD)(wfx.nChannels * sizeof(short));
DBUG(( "Pa_GetDeviceInfo: waveOutOpen( ... WAVE_FORMAT_QUERY at SR = %d\n", customSamplingRates[i] ));
if( waveOutOpen( NULL, outputMmID, &wfx, 0, 0, WAVE_FORMAT_QUERY ) == MMSYSERR_NOERROR )
{
sampleRates[ deviceInfo->numSampleRates++ ] = customSamplingRates[i];
}
}
}
DBUG(( "Pa_GetDeviceInfo: done.\n" ));
sDevicePtrs[ id ] = deviceInfo;
return deviceInfo;
error:
PaHost_FreeTrackedMemory( sampleRates ); /* MEM */
PaHost_FreeTrackedMemory( deviceInfo ); /* MEM */
return NULL;
}
/*************************************************************************
* 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 PaDeviceID PaHost_GetEnvDefaultDeviceID( char *envName )
{
DWORD hresult;
char envbuf[PA_ENV_BUF_SIZE];
PaDeviceID recommendedID = paNoDevice;
/* 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) )
{
recommendedID = atoi( envbuf );
}
return recommendedID;
}
/**********************************************************************
* Check for environment variable, else query devices and use result.
*/
PaDeviceID Pa_GetDefaultInputDeviceID( void )
{
PaDeviceID result;
result = PaHost_GetEnvDefaultDeviceID( PA_REC_IN_DEV_ENV_NAME );
if( result == paNoDevice || result < 0 || result >= sNumInputDevices )
{
result = sDefaultInputDeviceID;
}
return result;
}
PaDeviceID Pa_GetDefaultOutputDeviceID( void )
{
PaDeviceID result;
result = PaHost_GetEnvDefaultDeviceID( PA_REC_OUT_DEV_ENV_NAME );
if( result == paNoDevice || result < sNumInputDevices || result >= sNumDevices )
{
result = sDefaultOutputDeviceID;
}
return result;
}
/**********************************************************************
* Initialize Host dependant part of API.
*/
PaError PaHost_Init( void )
{
#if PA_TRACK_MEMORY
PRINT(("PaHost_Init: sNumAllocations = %d\n", sNumAllocations ));
#endif
#if PA_SIMULATE_UNDERFLOW
PRINT(("WARNING - Underflow Simulation Enabled - Expect a Big Glitch!!!\n"));
#endif
Pa_InitializeNumDevices();
return Pa_AllocateDevicePtrs();
}
/**********************************************************************
* Check WAVE buffers to see if they are done.
* Fill any available output buffers and use any available
* input buffers by calling user callback.
*
* This routine will loop until:
* user callback returns !=0 OR
* all output buffers are filled OR
* past->past_StopSoon is set OR
* an error occurs when calling WMME.
*
* Returns >0 when user requests a stop, <0 on error.
*
*/
static PaError Pa_TimeSlice( internalPortAudioStream *stream )
{
PaError result = paNoError;
MMRESULT mmresult;
char *inBufPtr;
char *outBufPtr;
int gotInput = 0;
int gotOutput = 0;
int i;
int buffersProcessed = 0;
int done = 0;
PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData;
if( wmmeStreamData == NULL ) return paInternalError;
stream->past_NumCallbacks += 1;
#if PA_TRACE_RUN
AddTraceMessage("Pa_TimeSlice: past_NumCallbacks ", stream->past_NumCallbacks );
#endif
/* JM20020118 - prevent hung thread when buffers underflow. */
/* while( !done ) /* BAD */
while( !done && !stream->past_StopSoon ) /* GOOD */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -