📄 pa_win_wmme.c
字号:
wmmeStreamData->abortEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); if( wmmeStreamData->abortEvent == NULL ) { result = paHostError; sPaHostError = GetLastError(); goto error; } wmmeStreamData->abortEventInited = 1; mmresult = waveOutOpen( &wmmeStreamData->hWaveOut, outputMmID, &wfx, (DWORD)wmmeStreamData->bufferEvent, (DWORD) stream, CALLBACK_EVENT );#endif if( mmresult != MMSYSERR_NOERROR ) { ERR_RPT(("PortAudio: PaHost_OpenOutputStream() failed!\n")); result = paHostError; sPaHostError = mmresult; goto error; } /* Allocate an array to hold the buffer pointers. */ wmmeStreamData->outputBuffers = (WAVEHDR *) PaHost_AllocateTrackedMemory( sizeof(WAVEHDR)*wmmeStreamData->numHostBuffers ); /* MEM */ if( wmmeStreamData->outputBuffers == NULL ) { result = paInsufficientMemory; goto error; } /* Allocate each buffer. */ for( i=0; i<wmmeStreamData->numHostBuffers; i++ ) { wmmeStreamData->outputBuffers[i].lpData = (char *) PaHost_AllocateTrackedMemory( wmmeStreamData->bytesPerHostOutputBuffer ); /* MEM */ if( wmmeStreamData->outputBuffers[i].lpData == NULL ) { result = paInsufficientMemory; goto error; } wmmeStreamData->outputBuffers[i].dwBufferLength = wmmeStreamData->bytesPerHostOutputBuffer; wmmeStreamData->outputBuffers[i].dwUser = i; if( (mmresult = waveOutPrepareHeader( wmmeStreamData->hWaveOut, &wmmeStreamData->outputBuffers[i], sizeof(WAVEHDR) )) != MMSYSERR_NOERROR ) { result = paHostError; sPaHostError = mmresult; goto error; } } return result;error: return result;}/*******************************************************************/PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *stream ){ PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; return wmmeStreamData->numHostBuffers * wmmeStreamData->framesPerHostBuffer;}/******************************************************************* * Determine number of WAVE Buffers * and how many User Buffers we can put into each WAVE buffer. */static void PaHost_CalcNumHostBuffers( internalPortAudioStream *stream ){ PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; unsigned int minNumBuffers; int minframesPerHostBuffer; int maxframesPerHostBuffer; int minTotalFrames; int userBuffersPerHostBuffer; int framesPerHostBuffer; int numHostBuffers; /* Calculate minimum and maximum sizes based on timing and sample rate. */ minframesPerHostBuffer = (int) (PA_MIN_MSEC_PER_HOST_BUFFER * stream->past_SampleRate * 0.001); minframesPerHostBuffer = (minframesPerHostBuffer + 7) & ~7; DBUG(("PaHost_CalcNumHostBuffers: minframesPerHostBuffer = %d\n", minframesPerHostBuffer )); maxframesPerHostBuffer = (int) (PA_MAX_MSEC_PER_HOST_BUFFER * stream->past_SampleRate * 0.001); maxframesPerHostBuffer = (maxframesPerHostBuffer + 7) & ~7; DBUG(("PaHost_CalcNumHostBuffers: maxframesPerHostBuffer = %d\n", maxframesPerHostBuffer )); /* Determine number of user buffers based on minimum latency. */ minNumBuffers = Pa_GetMinNumBuffers( stream->past_FramesPerUserBuffer, stream->past_SampleRate ); stream->past_NumUserBuffers = ( minNumBuffers > stream->past_NumUserBuffers ) ? minNumBuffers : stream->past_NumUserBuffers; DBUG(("PaHost_CalcNumHostBuffers: min past_NumUserBuffers = %d\n", stream->past_NumUserBuffers )); minTotalFrames = stream->past_NumUserBuffers * stream->past_FramesPerUserBuffer; /* We cannot make the WAVE buffers too small because they may not get serviced quickly enough. */ if( (int) stream->past_FramesPerUserBuffer < minframesPerHostBuffer ) { userBuffersPerHostBuffer = (minframesPerHostBuffer + stream->past_FramesPerUserBuffer - 1) / stream->past_FramesPerUserBuffer; } else { userBuffersPerHostBuffer = 1; } framesPerHostBuffer = stream->past_FramesPerUserBuffer * userBuffersPerHostBuffer; /* Calculate number of WAVE buffers needed. Round up to cover minTotalFrames. */ numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer; /* Make sure we have anough WAVE buffers. */ if( numHostBuffers < PA_MIN_NUM_HOST_BUFFERS) { numHostBuffers = PA_MIN_NUM_HOST_BUFFERS; } else if( (numHostBuffers > PA_MAX_NUM_HOST_BUFFERS) && ((int) stream->past_FramesPerUserBuffer < (maxframesPerHostBuffer/2) ) ) { /* If we have too many WAVE buffers, try to put more user buffers in a wave buffer. */ while(numHostBuffers > PA_MAX_NUM_HOST_BUFFERS) { userBuffersPerHostBuffer += 1; framesPerHostBuffer = stream->past_FramesPerUserBuffer * userBuffersPerHostBuffer; numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer; /* If we have gone too far, back up one. */ if( (framesPerHostBuffer > maxframesPerHostBuffer) || (numHostBuffers < PA_MAX_NUM_HOST_BUFFERS) ) { userBuffersPerHostBuffer -= 1; framesPerHostBuffer = stream->past_FramesPerUserBuffer * userBuffersPerHostBuffer; numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer; break; } } } wmmeStreamData->userBuffersPerHostBuffer = userBuffersPerHostBuffer; wmmeStreamData->framesPerHostBuffer = framesPerHostBuffer; wmmeStreamData->numHostBuffers = numHostBuffers; DBUG(("PaHost_CalcNumHostBuffers: userBuffersPerHostBuffer = %d\n", wmmeStreamData->userBuffersPerHostBuffer )); DBUG(("PaHost_CalcNumHostBuffers: numHostBuffers = %d\n", wmmeStreamData->numHostBuffers )); DBUG(("PaHost_CalcNumHostBuffers: framesPerHostBuffer = %d\n", wmmeStreamData->framesPerHostBuffer )); DBUG(("PaHost_CalcNumHostBuffers: past_NumUserBuffers = %d\n", stream->past_NumUserBuffers ));}/*******************************************************************/PaError PaHost_OpenStream( internalPortAudioStream *stream ){ PaError result = paNoError; PaWMMEStreamData *wmmeStreamData; result = PaHost_AllocateWMMEStreamData( stream ); if( result != paNoError ) return result; wmmeStreamData = PaHost_GetWMMEStreamData( stream ); /* Figure out how user buffers fit into WAVE buffers. */ PaHost_CalcNumHostBuffers( stream ); { int msecLatency = (int) ((PaHost_GetTotalBufferFrames(stream) * 1000) / stream->past_SampleRate); DBUG(("PortAudio on WMME - Latency = %d frames, %d msec\n", PaHost_GetTotalBufferFrames(stream), msecLatency )); } InitializeCriticalSection( &wmmeStreamData->streamLock ); wmmeStreamData->streamLockInited = 1;#if (PA_USE_TIMER_CALLBACK == 0) wmmeStreamData->bufferEventInited = 0; wmmeStreamData->bufferEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); if( wmmeStreamData->bufferEvent == NULL ) { result = paHostError; sPaHostError = GetLastError(); goto error; } wmmeStreamData->bufferEventInited = 1;#endif /* (PA_USE_TIMER_CALLBACK == 0) */ /* ------------------ OUTPUT */ wmmeStreamData->bytesPerUserOutputBuffer = stream->past_FramesPerUserBuffer * stream->past_NumOutputChannels * sizeof(short); wmmeStreamData->bytesPerHostOutputBuffer = wmmeStreamData->userBuffersPerHostBuffer * wmmeStreamData->bytesPerUserOutputBuffer; if( (stream->past_OutputDeviceID != paNoDevice) && (stream->past_NumOutputChannels > 0) ) { result = PaHost_OpenOutputStream( stream ); if( result < 0 ) goto error; } /* ------------------ INPUT */ wmmeStreamData->bytesPerUserInputBuffer = stream->past_FramesPerUserBuffer * stream->past_NumInputChannels * sizeof(short); wmmeStreamData->bytesPerHostInputBuffer = wmmeStreamData->userBuffersPerHostBuffer * wmmeStreamData->bytesPerUserInputBuffer; if( (stream->past_InputDeviceID != paNoDevice) && (stream->past_NumInputChannels > 0) ) { result = PaHost_OpenInputStream( stream ); if( result < 0 ) goto error; } Pa_InitializeCpuUsageScalar( stream ); return result;error: PaHost_CloseStream( stream ); return result;}/*************************************************************************/PaError PaHost_StartOutput( internalPortAudioStream *stream ){ PaError result = paNoError; MMRESULT mmresult; int i; PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( stream ); if( wmmeStreamData == NULL ) return paInternalError; if( stream->past_OutputDeviceID != paNoDevice ) { if( (mmresult = waveOutPause( wmmeStreamData->hWaveOut )) != MMSYSERR_NOERROR ) { result = paHostError; sPaHostError = mmresult; goto error; } for( i=0; i<wmmeStreamData->numHostBuffers; i++ ) { ZeroMemory( wmmeStreamData->outputBuffers[i].lpData, wmmeStreamData->outputBuffers[i].dwBufferLength ); mmresult = waveOutWrite( wmmeStreamData->hWaveOut, &wmmeStreamData->outputBuffers[i], sizeof(WAVEHDR) ); if( mmresult != MMSYSERR_NOERROR ) { result = paHostError; sPaHostError = mmresult; goto error; } stream->past_FrameCount += wmmeStreamData->framesPerHostBuffer; } wmmeStreamData->currentOutputBuffer = 0; if( (mmresult = waveOutRestart( wmmeStreamData->hWaveOut )) != MMSYSERR_NOERROR ) { result = paHostError; sPaHostError = mmresult; goto error; } }error: DBUG(("PaHost_StartOutput: wave returned mmresult = 0x%X.\n", mmresult)); return result;}/*************************************************************************/PaError PaHost_StartInput( internalPortAudioStream *internalStream ){ PaError result = paNoError; MMRESULT mmresult; int i; PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( internalStream ); if( wmmeStreamData == NULL ) return paInternalError; if( internalStream->past_InputDeviceID != paNoDevice ) { for( i=0; i<wmmeStreamData->numHostBuffers; i++ ) { mmresult = waveInAddBuffer( wmmeStreamData->hWaveIn, &wmmeStreamData->inputBuffers[i], sizeof(WAVEHDR) ); if( mmresult != MMSYSERR_NOERROR ) { result = paHostError; sPaHostError = mmresult; goto error; } } wmmeStreamData->currentInputBuffer = 0; mmresult = waveInStart( wmmeStreamData->hWaveIn ); DBUG(("Pa_StartStream: waveInStart returned = 0x%X.\n", mmresult)); if( mmresult != MMSYSERR_NOERROR ) { result = paHostError; sPaHostError = mmresult; goto error; } }error: return result;}/*************************************************************************/PaError PaHost_StartEngine( internalPortAudioStream *stream ){ PaError result = paNoError; PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( stream );#if PA_USE_TIMER_CALLBACK int resolution; int bufsPerTimerCallback; int msecPerBuffer;#endif /* PA_USE_TIMER_CALLBACK */ if( wmmeStreamData == NULL ) return paInternalError; stream->past_StopSoon = 0; stream->past_StopNow = 0; stream->past_IsActive = 1; wmmeStreamData->framesPlayed = 0.0; wmmeStreamData->lastPosition = 0;#if PA_TRACE_START_STOP AddTraceMessage( "PaHost_StartEngine: TimeSlice() returned ", result );#endif#if PA_USE_TIMER_CALLBACK /* Create timer that will wake us up so we can fill the DSound buffer. */ bufsPerTimerCallback = wmmeStreamData->numHostBuffers/4; if( bufsPerTimerCallback < 1 ) bufsPerTimerCallback = 1; if( bufsPerTimerCallback < 1 ) bufsPerTimerCallback = 1; msecPerBuffer = (1000 * bufsPerTimerCallback * wmmeStreamData->userBuffersPerHostBuffer * internalStream->past_FramesPerUserBuffer ) / (int) internalStream->past_SampleRate; if( msecPerBuffer < 10 ) msecPerBuffer = 10; else if( msecPerBuffer > 100 ) msecPerBuffer = 100; resolution = msecPerBuffer/4; wmmeStreamData->timerID = timeSetEvent( msecPerBuffer, resolution, (LPTIMECALLBACK) Pa_TimerCallback, (DWORD) stream, TIME_PERIODIC ); if( wmmeStreamData->timerID == 0 ) { result = paHostError; sPaHostError = GetLastError();; goto error; }#else /* PA_USE_TIMER_CALLBACK */ ResetEvent( wmmeStreamData->abortEvent ); /* Create thread that waits for audio buffers to be ready for processing. */ wmmeStreamData->engineThread = CreateThread( 0, 0, WinMMPa_OutputThreadProc, stream, 0, &wmmeStreamData->engineThreadID ); if( wmmeStreamData->engineThread == NULL ) { result = paHostError; sPaHostError = GetLastError();; goto error; }#if PA_TRACE_START_STOP AddTraceMessage( "PaHost_StartEngine: thread ", (int) wmmeStreamData->engineThread );#endif /* I used to pass the thread which was failing. I now pass GetCurrentProcess(). * This fix could improve latency for some applications. It could also result in CPU * starvation if the callback did too much processing. * I also added result checks, so we might see more failures at initialization. * Thanks to Alberto di Bene for spotting this. */#if 0 /* dmazzoni: this seems to cause problems */ if( !SetPriorityClass( GetCurrentProcess(), HIGH_PRIORITY_CLASS ) ) /* PLB20010816 */ { result = paHostError; sPaHostError = GetLastError();; goto error; }#endif if( !SetThreadPriority( wmmeStreamData->engineThread, THREAD_PRIORITY_HIGHEST ) ) { result = paHostError; sPaHostError = GetLastError();; goto error;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -