📄 pa_win_wmme.c
字号:
if( inputChannelCount > 0 ) /* full duplex */
{
if( *framesPerHostInputBuffer != *framesPerHostOutputBuffer )
{
if( inputStreamInfo
&& ( inputStreamInfo->flags & paWinMmeUseLowLevelLatencyParameters ) )
{
/* a custom StreamInfo was used for specifying both input
and output buffer sizes, the larger buffer size
must be a multiple of the smaller buffer size */
if( *framesPerHostInputBuffer < *framesPerHostOutputBuffer )
{
if( *framesPerHostOutputBuffer % *framesPerHostInputBuffer != 0 )
{
result = paIncompatibleHostApiSpecificStreamInfo;
goto error;
}
}
else
{
assert( *framesPerHostInputBuffer > *framesPerHostOutputBuffer );
if( *framesPerHostInputBuffer % *framesPerHostOutputBuffer != 0 )
{
result = paIncompatibleHostApiSpecificStreamInfo;
goto error;
}
}
}
else
{
/* a custom StreamInfo was not used for specifying the input buffer size,
so use the output buffer size, and approximately the same latency. */
*framesPerHostInputBuffer = *framesPerHostOutputBuffer;
*hostInputBufferCount = (((unsigned long)(suggestedInputLatency * sampleRate)) / *framesPerHostInputBuffer) + 1;
if( *hostInputBufferCount < PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_ )
*hostInputBufferCount = PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_;
}
}
}
}
else
{
unsigned long hostBufferSizeBytes, hostBufferCount;
unsigned long minimumBufferCount = PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_;
unsigned long maximumBufferSize;
int hostOutputFrameSize;
int hostOutputSampleSize;
hostOutputSampleSize = Pa_GetSampleSize( hostOutputSampleFormat );
if( hostOutputSampleSize < 0 )
{
result = hostOutputSampleSize;
goto error;
}
if( outputStreamInfo
&& ( outputStreamInfo->flags & paWinMmeUseMultipleDevices ) )
{
/* set effectiveOutputChannelCount to the largest number of
channels on any one device.
*/
effectiveOutputChannelCount = 0;
for( i=0; i< outputStreamInfo->deviceCount; ++i )
{
if( outputStreamInfo->devices[i].channelCount > effectiveOutputChannelCount )
effectiveOutputChannelCount = outputStreamInfo->devices[i].channelCount;
}
}
else
{
effectiveOutputChannelCount = outputChannelCount;
}
hostOutputFrameSize = hostOutputSampleSize * effectiveOutputChannelCount;
maximumBufferSize = (long) ((PA_MME_MAX_HOST_BUFFER_SECS_ * sampleRate) * hostOutputFrameSize);
if( maximumBufferSize > PA_MME_MAX_HOST_BUFFER_BYTES_ )
maximumBufferSize = PA_MME_MAX_HOST_BUFFER_BYTES_;
/* compute the following in bytes, then convert back to frames */
SelectBufferSizeAndCount(
((framesPerBuffer == paFramesPerBufferUnspecified)
? PA_MME_MIN_HOST_BUFFER_FRAMES_WHEN_UNSPECIFIED_
: framesPerBuffer ) * hostOutputFrameSize, /* baseBufferSize */
((unsigned long)(suggestedOutputLatency * sampleRate)) * hostOutputFrameSize, /* suggestedLatency */
4, /* baseBufferCount */
minimumBufferCount,
maximumBufferSize,
&hostBufferSizeBytes, &hostBufferCount );
*framesPerHostOutputBuffer = hostBufferSizeBytes / hostOutputFrameSize;
*hostOutputBufferCount = hostBufferCount;
if( inputChannelCount > 0 )
{
/* ensure that both input and output buffer sizes are the same.
if they don't match at this stage, choose the smallest one
and use that for input and output
*/
if( *framesPerHostOutputBuffer != *framesPerHostInputBuffer )
{
if( framesPerHostInputBuffer < framesPerHostOutputBuffer )
{
unsigned long framesPerHostBuffer = *framesPerHostInputBuffer;
minimumBufferCount = PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_;
ReselectBufferCount(
framesPerHostBuffer * hostOutputFrameSize, /* bufferSize */
((unsigned long)(suggestedOutputLatency * sampleRate)) * hostOutputFrameSize, /* suggestedLatency */
4, /* baseBufferCount */
minimumBufferCount,
&hostBufferCount );
*framesPerHostOutputBuffer = framesPerHostBuffer;
*hostOutputBufferCount = hostBufferCount;
}
else
{
unsigned long framesPerHostBuffer = *framesPerHostOutputBuffer;
minimumBufferCount = PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_;
ReselectBufferCount(
framesPerHostBuffer * hostInputFrameSize, /* bufferSize */
((unsigned long)(suggestedInputLatency * sampleRate)) * hostInputFrameSize, /* suggestedLatency */
4, /* baseBufferCount */
minimumBufferCount,
&hostBufferCount );
*framesPerHostInputBuffer = framesPerHostBuffer;
*hostInputBufferCount = hostBufferCount;
}
}
}
}
}
else
{
*framesPerHostOutputBuffer = 0;
*hostOutputBufferCount = 0;
}
error:
return result;
}
typedef struct
{
HANDLE bufferEvent;
void *waveHandles;
unsigned int deviceCount;
/* unsigned int channelCount; */
WAVEHDR **waveHeaders; /* waveHeaders[device][buffer] */
unsigned int bufferCount;
unsigned int currentBufferIndex;
unsigned int framesPerBuffer;
unsigned int framesUsedInCurrentBuffer;
}PaWinMmeSingleDirectionHandlesAndBuffers;
/* prototypes for functions operating on PaWinMmeSingleDirectionHandlesAndBuffers */
static void InitializeSingleDirectionHandlesAndBuffers( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers );
static PaError InitializeWaveHandles( PaWinMmeHostApiRepresentation *winMmeHostApi,
PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers,
unsigned long bytesPerHostSample,
double sampleRate, PaWinMmeDeviceAndChannelCount *devices,
unsigned int deviceCount, int isInput );
static PaError TerminateWaveHandles( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, int isInput, int currentlyProcessingAnError );
static PaError InitializeWaveHeaders( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers,
unsigned long hostBufferCount,
PaSampleFormat hostSampleFormat,
unsigned long framesPerHostBuffer,
PaWinMmeDeviceAndChannelCount *devices,
int isInput );
static void TerminateWaveHeaders( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, int isInput );
static void InitializeSingleDirectionHandlesAndBuffers( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers )
{
handlesAndBuffers->bufferEvent = 0;
handlesAndBuffers->waveHandles = 0;
handlesAndBuffers->deviceCount = 0;
handlesAndBuffers->waveHeaders = 0;
handlesAndBuffers->bufferCount = 0;
}
static PaError InitializeWaveHandles( PaWinMmeHostApiRepresentation *winMmeHostApi,
PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers,
unsigned long bytesPerHostSample,
double sampleRate, PaWinMmeDeviceAndChannelCount *devices,
unsigned int deviceCount, int isInput )
{
PaError result;
MMRESULT mmresult;
unsigned long bytesPerFrame;
WAVEFORMATEX wfx;
signed int i;
/* for error cleanup we expect that InitializeSingleDirectionHandlesAndBuffers()
has already been called to zero some fields */
result = CreateEventWithPaError( &handlesAndBuffers->bufferEvent, NULL, FALSE, FALSE, NULL );
if( result != paNoError ) goto error;
if( isInput )
handlesAndBuffers->waveHandles = (void*)PaUtil_AllocateMemory( sizeof(HWAVEIN) * deviceCount );
else
handlesAndBuffers->waveHandles = (void*)PaUtil_AllocateMemory( sizeof(HWAVEOUT) * deviceCount );
if( !handlesAndBuffers->waveHandles )
{
result = paInsufficientMemory;
goto error;
}
handlesAndBuffers->deviceCount = deviceCount;
for( i = 0; i < (signed int)deviceCount; ++i )
{
if( isInput )
((HWAVEIN*)handlesAndBuffers->waveHandles)[i] = 0;
else
((HWAVEOUT*)handlesAndBuffers->waveHandles)[i] = 0;
}
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nSamplesPerSec = (DWORD) sampleRate;
wfx.cbSize = 0;
for( i = 0; i < (signed int)deviceCount; ++i )
{
UINT winMmeDeviceId;
winMmeDeviceId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, devices[i].device );
wfx.nChannels = (WORD)devices[i].channelCount;
bytesPerFrame = wfx.nChannels * bytesPerHostSample;
wfx.nAvgBytesPerSec = (DWORD)(bytesPerFrame * sampleRate);
wfx.nBlockAlign = (WORD)bytesPerFrame;
wfx.wBitsPerSample = (WORD)((bytesPerFrame/wfx.nChannels) * 8);
/* REVIEW: consider not firing an event for input when a full duplex
stream is being used. this would probably depend on the
neverDropInput flag. */
if( isInput )
mmresult = waveInOpen( &((HWAVEIN*)handlesAndBuffers->waveHandles)[i], winMmeDeviceId, &wfx,
(DWORD)handlesAndBuffers->bufferEvent, (DWORD)0, CALLBACK_EVENT );
else
mmresult = waveOutOpen( &((HWAVEOUT*)handlesAndBuffers->waveHandles)[i], winMmeDeviceId, &wfx,
(DWORD)handlesAndBuffers->bufferEvent, (DWORD)0, CALLBACK_EVENT );
if( mmresult != MMSYSERR_NOERROR )
{
switch( mmresult )
{
case MMSYSERR_ALLOCATED: /* Specified resource is already allocated. */
result = paDeviceUnavailable;
break;
case MMSYSERR_NODRIVER: /* No device driver is present. */
result = paDeviceUnavailable;
break;
case MMSYSERR_NOMEM: /* Unable to allocate or lock memory. */
result = paInsufficientMemory;
break;
case MMSYSERR_BADDEVICEID: /* Specified device identifier is out of range. */
/* falls through */
case WAVERR_BADFORMAT: /* Attempted to open with an unsupported waveform-audio format. */
/* falls through */
default:
result = paUnanticipatedHostError;
if( isInput )
{
PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
}
else
{
PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
}
}
goto error;
}
}
return result;
error:
TerminateWaveHandles( handlesAndBuffers, isInput, 1 /* currentlyProcessingAnError */ );
return result;
}
static PaError TerminateWaveHandles( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, int isInput, int currentlyProcessingAnError )
{
PaError result = paNoError;
MMRESULT mmresult = 0;
signed int i;
if( handlesAndBuffers->waveHandles )
{
for( i = handlesAndBuffers->deviceCount-1; i >= 0; --i )
{
if( isInput )
{
if( ((HWAVEIN*)handlesAndBuffers->waveHandles)[i] )
mmresult = waveInClose( ((HWAVEIN*)handlesAndBuffers->waveHandles)[i] );
}
else
{
if( ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i] )
mmresult = waveOutClose( ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i] );
}
if( mmresult != MMSYSERR_NOERROR &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -