📄 pa_win_wmme.c
字号:
{
#if PA_SIMULATE_UNDERFLOW
if(gUnderCallbackCounter++ == UNDER_SLEEP_AT)
{
Sleep(UNDER_SLEEP_FOR);
}
#endif
/* If we are using output, then we need an empty output buffer. */
gotOutput = 0;
outBufPtr = NULL;
if( stream->past_NumOutputChannels > 0 )
{
if((wmmeStreamData->outputBuffers[ wmmeStreamData->currentOutputBuffer ].dwFlags & WHDR_DONE) == 0)
{
break; /* If none empty then bail and try again later. */
}
else
{
outBufPtr = wmmeStreamData->outputBuffers[ wmmeStreamData->currentOutputBuffer ].lpData;
gotOutput = 1;
}
}
/* Use an input buffer if one is available. */
gotInput = 0;
inBufPtr = NULL;
if( ( stream->past_NumInputChannels > 0 ) &&
(wmmeStreamData->inputBuffers[ wmmeStreamData->currentInputBuffer ].dwFlags & WHDR_DONE) )
{
inBufPtr = wmmeStreamData->inputBuffers[ wmmeStreamData->currentInputBuffer ].lpData;
gotInput = 1;
#if PA_TRACE_RUN
AddTraceMessage("Pa_TimeSlice: got input buffer at ", (int)inBufPtr );
AddTraceMessage("Pa_TimeSlice: got input buffer # ", wmmeStreamData->currentInputBuffer );
#endif
}
/* If we can't do anything then bail out. */
if( !gotInput && !gotOutput ) break;
buffersProcessed += 1;
/* Each Wave buffer contains multiple user buffers so do them all now. */
/* Base Usage on time it took to process one host buffer. */
Pa_StartUsageCalculation( stream );
for( i=0; i<wmmeStreamData->userBuffersPerHostBuffer; i++ )
{
if( done )
{
if( gotOutput )
{
/* Clear remainder of wave buffer if we are waiting for stop. */
AddTraceMessage("Pa_TimeSlice: zero rest of wave buffer ", i );
memset( outBufPtr, 0, wmmeStreamData->bytesPerUserOutputBuffer );
}
}
else
{
/* Convert 16 bit native data to user data and call user routine. */
result = Pa_CallConvertInt16( stream, (short *) inBufPtr, (short *) outBufPtr );
if( result != 0) done = 1;
}
if( gotInput ) inBufPtr += wmmeStreamData->bytesPerUserInputBuffer;
if( gotOutput) outBufPtr += wmmeStreamData->bytesPerUserOutputBuffer;
}
Pa_EndUsageCalculation( stream );
/* Send WAVE buffer to Wave Device to be refilled. */
if( gotInput )
{
mmresult = waveInAddBuffer( wmmeStreamData->hWaveIn,
&wmmeStreamData->inputBuffers[ wmmeStreamData->currentInputBuffer ],
sizeof(WAVEHDR) );
if( mmresult != MMSYSERR_NOERROR )
{
sPaHostError = mmresult;
result = paHostError;
break;
}
wmmeStreamData->currentInputBuffer = (wmmeStreamData->currentInputBuffer+1 >= wmmeStreamData->numHostBuffers) ?
0 : wmmeStreamData->currentInputBuffer+1;
}
/* Write WAVE buffer to Wave Device. */
if( gotOutput )
{
#if PA_TRACE_START_STOP
AddTraceMessage( "Pa_TimeSlice: writing buffer ", wmmeStreamData->currentOutputBuffer );
#endif
mmresult = waveOutWrite( wmmeStreamData->hWaveOut,
&wmmeStreamData->outputBuffers[ wmmeStreamData->currentOutputBuffer ],
sizeof(WAVEHDR) );
if( mmresult != MMSYSERR_NOERROR )
{
sPaHostError = mmresult;
result = paHostError;
break;
}
wmmeStreamData->currentOutputBuffer = (wmmeStreamData->currentOutputBuffer+1 >= wmmeStreamData->numHostBuffers) ?
0 : wmmeStreamData->currentOutputBuffer+1;
}
}
#if PA_TRACE_RUN
AddTraceMessage("Pa_TimeSlice: buffersProcessed ", buffersProcessed );
#endif
return (result != 0) ? result : done;
}
/*******************************************************************/
static PaError PaHost_BackgroundManager( internalPortAudioStream *stream )
{
PaError result = paNoError;
int i;
int numQueuedoutputBuffers = 0;
PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData;
/* Has someone asked us to abort by calling Pa_AbortStream()? */
if( stream->past_StopNow )
{
stream->past_IsActive = 0; /* Will cause thread to return. */
}
/* Has someone asked us to stop by calling Pa_StopStream()
* OR has a user callback returned '1' to indicate finished.
*/
else if( stream->past_StopSoon )
{
/* Poll buffer and when all have played then exit thread. */
/* Count how many output buffers are queued. */
numQueuedoutputBuffers = 0;
if( stream->past_NumOutputChannels > 0 )
{
for( i=0; i<wmmeStreamData->numHostBuffers; i++ )
{
if( !( wmmeStreamData->outputBuffers[ i ].dwFlags & WHDR_DONE) )
{
#if PA_TRACE_START_STOP
AddTraceMessage( "PaHost_BackgroundManager: waiting for buffer ", i );
#endif
numQueuedoutputBuffers++;
}
}
}
#if PA_TRACE_START_STOP
AddTraceMessage( "PaHost_BackgroundManager: numQueuedoutputBuffers ", numQueuedoutputBuffers );
#endif
if( numQueuedoutputBuffers == 0 )
{
stream->past_IsActive = 0; /* Will cause thread to return. */
}
}
else
{
/* Process full input buffer and fill up empty output buffers. */
if( (result = Pa_TimeSlice( stream )) != 0)
{
/* User callback has asked us to stop. */
#if PA_TRACE_START_STOP
AddTraceMessage( "PaHost_BackgroundManager: TimeSlice() returned ", result );
#endif
stream->past_StopSoon = 1; /* Request that audio play out then stop. */
result = paNoError;
}
}
PaHost_UpdateStreamTime( wmmeStreamData );
return result;
}
#if PA_USE_TIMER_CALLBACK
/*******************************************************************/
static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
{
internalPortAudioStream *stream;
PaWMMEStreamData *wmmeStreamData;
PaError result;
stream = (internalPortAudioStream *) dwUser;
if( stream == NULL ) return;
wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData;
if( wmmeStreamData == NULL ) return;
if( wmmeStreamData->ifInsideCallback )
{
if( wmmeStreamData->timerID != 0 )
{
timeKillEvent(wmmeStreamData->timerID); /* Stop callback timer. */
wmmeStreamData->timerID = 0;
}
return;
}
wmmeStreamData->ifInsideCallback = 1;
/* Manage flags and audio processing. */
result = PaHost_BackgroundManager( stream );
if( result != paNoError )
{
stream->past_IsActive = 0;
}
wmmeStreamData->ifInsideCallback = 0;
}
#else /* PA_USE_TIMER_CALLBACK */
/*******************************************************************/
static DWORD WINAPI WinMMPa_OutputThreadProc( void *pArg )
{
internalPortAudioStream *stream;
PaWMMEStreamData *wmmeStreamData;
HANDLE events[2];
int numEvents = 0;
DWORD result = 0;
DWORD waitResult;
DWORD numTimeouts = 0;
DWORD timeOut;
stream = (internalPortAudioStream *) pArg;
wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData;
#if PA_TRACE_START_STOP
AddTraceMessage( "WinMMPa_OutputThreadProc: timeoutPeriod", timeoutPeriod );
AddTraceMessage( "WinMMPa_OutputThreadProc: past_NumUserBuffers", stream->past_NumUserBuffers );
#endif
/* Calculate timeOut as half the time it would take to play all buffers. */
timeOut = (DWORD) (500.0 * PaHost_GetTotalBufferFrames( stream ) / stream->past_SampleRate);
/* Get event(s) ready for wait. */
events[numEvents++] = wmmeStreamData->bufferEvent;
if( wmmeStreamData->abortEventInited ) events[numEvents++] = wmmeStreamData->abortEvent;
/* Stay in this thread as long as we are "active". */
while( stream->past_IsActive )
{
/*******************************************************************/
/******** WAIT here for an event from WMME or PA *******************/
/*******************************************************************/
waitResult = WaitForMultipleObjects( numEvents, events, FALSE, timeOut );
/* Error? */
if( waitResult == WAIT_FAILED )
{
sPaHostError = GetLastError();
result = paHostError;
stream->past_IsActive = 0;
}
/* Timeout? Don't stop. Just keep polling for DONE.*/
else if( waitResult == WAIT_TIMEOUT )
{
#if PA_TRACE_START_STOP
AddTraceMessage( "WinMMPa_OutputThreadProc: timed out ", numQueuedoutputBuffers );
#endif
numTimeouts += 1;
}
/* Manage flags and audio processing. */
result = PaHost_BackgroundManager( stream );
if( result != paNoError )
{
stream->past_IsActive = 0;
}
}
return result;
}
#endif
/*******************************************************************/
PaError PaHost_OpenInputStream( internalPortAudioStream *stream )
{
PaError result = paNoError;
MMRESULT mmresult;
PaWMMEStreamData *wmmeStreamData;
int i;
int inputMmId;
int bytesPerInputFrame;
WAVEFORMATEX wfx;
const PaDeviceInfo *deviceInfo;
wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData;
DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", stream->past_InputDeviceID));
deviceInfo = Pa_GetDeviceInfo( stream->past_InputDeviceID );
if( deviceInfo == NULL ) return paInternalError;
switch( deviceInfo->nativeSampleFormats )
{
case paInt32:
case paFloat32:
bytesPerInputFrame = sizeof(float) * stream->past_NumInputChannels;
break;
default:
bytesPerInputFrame = sizeof(short) * stream->past_NumInputChannels;
break;
}
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = (WORD) stream->past_NumInputChannels;
wfx.nSamplesPerSec = (DWORD) stream->past_SampleRate;
wfx.nAvgBytesPerSec = (DWORD)(bytesPerInputFrame * stream->past_SampleRate);
wfx.nBlockAlign = (WORD)bytesPerInputFrame;
wfx.wBitsPerSample = (WORD)((bytesPerInputFrame/stream->past_NumInputChannels) * 8);
wfx.cbSize = 0;
inputMmId = PaDeviceIdToWinId( stream->past_InputDeviceID );
#if PA_USE_TIMER_CALLBACK
mmresult = waveInOpen( &wmmeStreamData->hWaveIn, inputMmId, &wfx,
0, 0, CALLBACK_NULL );
#else
mmresult = waveInOpen( &wmmeStreamData->hWaveIn, inputMmId, &wfx,
(DWORD)wmmeStreamData->bufferEvent, (DWORD) stream, CALLBACK_EVENT );
#endif
if( mmresult != MMSYSERR_NOERROR )
{
ERR_RPT(("PortAudio: PaHost_OpenInputStream() failed!\n"));
result = paHostError;
sPaHostError = mmresult;
goto error;
}
/* Allocate an array to hold the buffer pointers. */
wmmeStreamData->inputBuffers = (WAVEHDR *) PaHost_AllocateTrackedMemory( sizeof(WAVEHDR)*wmmeStreamData->numHostBuffers ); /* MEM */
if( wmmeStreamData->inputBuffers == NULL )
{
result = paInsufficientMemory;
goto error;
}
/* Allocate each buffer. */
for( i=0; i<wmmeStreamData->numHostBuffers; i++ )
{
wmmeStreamData->inputBuffers[i].lpData = (char *)PaHost_AllocateTrackedMemory( wmmeStreamData->bytesPerHostInputBuffer ); /* MEM */
if( wmmeStreamData->inputBuffers[i].lpData == NULL )
{
result = paInsufficientMemory;
goto error;
}
wmmeStreamData->inputBuffers[i].dwBufferLength = wmmeStreamData->bytesPerHostInputBuffer;
wmmeStreamData->inputBuffers[i].dwUser = i;
if( ( mmresult = waveInPrepareHeader( wmmeStreamData->hWaveIn, &wmmeStreamData->inputBuffers[i], sizeof(WAVEHDR) )) != MMSYSERR_NOERROR )
{
result = paHostError;
sPaHostError = mmresult;
goto error;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -