📄 pa_win_wmme.c
字号:
/* 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; } } return result;error: return result;}/*******************************************************************/PaError PaHost_OpenOutputStream( internalPortAudioStream *stream ){ PaError result = paNoError; MMRESULT mmresult; PaWMMEStreamData *wmmeStreamData; int i; int outputMmID; int bytesPerOutputFrame; WAVEFORMATEX wfx; const PaDeviceInfo *deviceInfo; wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", stream->past_OutputDeviceID)); deviceInfo = Pa_GetDeviceInfo( stream->past_OutputDeviceID ); if( deviceInfo == NULL ) return paInternalError; switch( deviceInfo->nativeSampleFormats ) { case paInt32: case paFloat32: bytesPerOutputFrame = sizeof(float) * stream->past_NumOutputChannels; break; default: bytesPerOutputFrame = sizeof(short) * stream->past_NumOutputChannels; break; } wfx.wFormatTag = WAVE_FORMAT_PCM;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -