📄 pa_win_wmme.c
字号:
}#endiferror: return result;}/*************************************************************************/PaError PaHost_StopEngine( internalPortAudioStream *internalStream, int abort ){ int timeOut; PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( internalStream ); if( wmmeStreamData == NULL ) return paNoError; /* Tell background thread to stop generating more data and to let current data play out. */ internalStream->past_StopSoon = 1; /* If aborting, tell background thread to stop NOW! */ if( abort ) internalStream->past_StopNow = 1; /* Calculate timeOut longer than longest time it could take to play all buffers. */ timeOut = (DWORD) (1500.0 * PaHost_GetTotalBufferFrames( internalStream ) / internalStream->past_SampleRate); if( timeOut < MIN_TIMEOUT_MSEC ) timeOut = MIN_TIMEOUT_MSEC;#if PA_USE_TIMER_CALLBACK if( (internalStream->past_OutputDeviceID != paNoDevice) && internalStream->past_IsActive && (wmmeStreamData->timerID != 0) ) { /* Wait for IsActive to drop. */ while( (internalStream->past_IsActive) && (timeOut > 0) ) { Sleep(10); timeOut -= 10; } timeKillEvent( wmmeStreamData->timerID ); /* Stop callback timer. */ wmmeStreamData->timerID = 0; }#else /* PA_USE_TIMER_CALLBACK */#if PA_TRACE_START_STOP AddTraceMessage( "PaHost_StopEngine: thread ", (int) wmmeStreamData->engineThread );#endif if( (internalStream->past_OutputDeviceID != paNoDevice) && (internalStream->past_IsActive) && (wmmeStreamData->engineThread != NULL) ) { DWORD got; /* Tell background thread to stop generating more data and to let current data play out. */ DBUG(("PaHost_StopEngine: waiting for background thread.\n")); got = WaitForSingleObject( wmmeStreamData->engineThread, timeOut ); if( got == WAIT_TIMEOUT ) { ERR_RPT(("PaHost_StopEngine: timed out while waiting for background thread to finish.\n")); return paTimedOut; } CloseHandle( wmmeStreamData->engineThread ); wmmeStreamData->engineThread = NULL; }#endif /* PA_USE_TIMER_CALLBACK */ internalStream->past_IsActive = 0; return paNoError;}/*************************************************************************/PaError PaHost_StopInput( internalPortAudioStream *stream, int abort ){ MMRESULT mmresult; PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( stream ); if( wmmeStreamData == NULL ) return paNoError; /* FIXME: why return paNoError? */ (void) abort; /* unused parameter */ if( wmmeStreamData->hWaveIn != NULL ) { mmresult = waveInReset( wmmeStreamData->hWaveIn ); if( mmresult != MMSYSERR_NOERROR ) { sPaHostError = mmresult; return paHostError; } } return paNoError;}/*************************************************************************/PaError PaHost_StopOutput( internalPortAudioStream *internalStream, int abort ){ MMRESULT mmresult; PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( internalStream ); if( wmmeStreamData == NULL ) return paNoError; /* FIXME: why return paNoError? */ (void) abort; /* unused parameter */#if PA_TRACE_START_STOP AddTraceMessage( "PaHost_StopOutput: hWaveOut ", (int) wmmeStreamData->hWaveOut );#endif if( wmmeStreamData->hWaveOut != NULL ) { mmresult = waveOutReset( wmmeStreamData->hWaveOut ); if( mmresult != MMSYSERR_NOERROR ) { sPaHostError = mmresult; return paHostError; } } return paNoError;}/*******************************************************************/PaError PaHost_CloseStream( internalPortAudioStream *stream ){ int i; PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( stream ); if( stream == NULL ) return paBadStreamPtr; if( wmmeStreamData == NULL ) return paNoError; /* FIXME: why return no error? */#if PA_TRACE_START_STOP AddTraceMessage( "PaHost_CloseStream: hWaveOut ", (int) wmmeStreamData->hWaveOut );#endif /* Free data and device for output. */ if( wmmeStreamData->hWaveOut ) { if( wmmeStreamData->outputBuffers ) { for( i=0; i<wmmeStreamData->numHostBuffers; i++ ) { waveOutUnprepareHeader( wmmeStreamData->hWaveOut, &wmmeStreamData->outputBuffers[i], sizeof(WAVEHDR) ); PaHost_FreeTrackedMemory( wmmeStreamData->outputBuffers[i].lpData ); /* MEM */ } PaHost_FreeTrackedMemory( wmmeStreamData->outputBuffers ); /* MEM */ } waveOutClose( wmmeStreamData->hWaveOut ); } /* Free data and device for input. */ if( wmmeStreamData->hWaveIn ) { if( wmmeStreamData->inputBuffers ) { for( i=0; i<wmmeStreamData->numHostBuffers; i++ ) { waveInUnprepareHeader( wmmeStreamData->hWaveIn, &wmmeStreamData->inputBuffers[i], sizeof(WAVEHDR) ); PaHost_FreeTrackedMemory( wmmeStreamData->inputBuffers[i].lpData ); /* MEM */ } PaHost_FreeTrackedMemory( wmmeStreamData->inputBuffers ); /* MEM */ } waveInClose( wmmeStreamData->hWaveIn ); }#if (PA_USE_TIMER_CALLBACK == 0) if( wmmeStreamData->abortEventInited ) CloseHandle( wmmeStreamData->abortEvent ); if( wmmeStreamData->bufferEventInited ) CloseHandle( wmmeStreamData->bufferEvent );#endif if( wmmeStreamData->streamLockInited ) DeleteCriticalSection( &wmmeStreamData->streamLock ); PaHost_FreeWMMEStreamData( stream ); return paNoError;}/************************************************************************* * Determine minimum number of buffers required for this host based * on minimum latency. Latency can be optionally set by user by setting * an environment variable. For example, to set latency to 200 msec, put: * * set PA_MIN_LATENCY_MSEC=200 * * in the AUTOEXEC.BAT file and reboot. * If the environment variable is not set, then the latency will be determined * based on the OS. Windows NT has higher latency than Win95. */#define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC")int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ){ char envbuf[PA_ENV_BUF_SIZE]; DWORD hresult; int minLatencyMsec = 0; double msecPerBuffer = (1000.0 * framesPerBuffer) / sampleRate; int minBuffers; /* Let user determine minimal latency by setting environment variable. */ hresult = GetEnvironmentVariable( PA_LATENCY_ENV_NAME, envbuf, PA_ENV_BUF_SIZE ); if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) ) { minLatencyMsec = atoi( envbuf ); /* REVIEW: will we crash if the environment variable contains some nasty value? */ } else { /* Set minimal latency based on whether NT or other OS. * NT has higher latency. */ OSVERSIONINFO osvi; osvi.dwOSVersionInfoSize = sizeof( osvi ); GetVersionEx( &osvi ); DBUG(("PA - PlatformId = 0x%x\n", osvi.dwPlatformId )); DBUG(("PA - MajorVersion = 0x%x\n", osvi.dwMajorVersion )); DBUG(("PA - MinorVersion = 0x%x\n", osvi.dwMinorVersion )); /* Check for NT */ if( (osvi.dwMajorVersion == 4) && (osvi.dwPlatformId == 2) ) { minLatencyMsec = PA_WIN_NT_LATENCY; } else if(osvi.dwMajorVersion >= 5) { minLatencyMsec = PA_WIN_WDM_LATENCY; } else { minLatencyMsec = PA_WIN_9X_LATENCY; }#if PA_USE_HIGH_LATENCY PRINT(("PA - Minimum Latency set to %d msec!\n", minLatencyMsec ));#endif } DBUG(("PA - Minimum Latency set to %d msec!\n", minLatencyMsec )); minBuffers = (int) (1.0 + ((double)minLatencyMsec / msecPerBuffer)); if( minBuffers < 2 ) minBuffers = 2; return minBuffers;}/************************************************************************* * Cleanup device info. */PaError PaHost_Term( void ){ int i; if( sNumDevices > 0 ) { if( sDevicePtrs != NULL ) { for( i=0; i<sNumDevices; i++ ) { if( sDevicePtrs[i] != NULL ) { PaHost_FreeTrackedMemory( (char*)sDevicePtrs[i]->name ); /* MEM */ PaHost_FreeTrackedMemory( (void*)sDevicePtrs[i]->sampleRates ); /* MEM */ PaHost_FreeTrackedMemory( sDevicePtrs[i] ); /* MEM */ } } PaHost_FreeTrackedMemory( sDevicePtrs ); /* MEM */ sDevicePtrs = NULL; } sNumDevices = 0; }#if PA_TRACK_MEMORY PRINT(("PaHost_Term: sNumAllocations = %d\n", sNumAllocations ));#endif return paNoError;}/*************************************************************************/void Pa_Sleep( long msec ){ Sleep( msec );}/*************************************************************************FIXME: the following memory allocation routines should not be declared here * Allocate memory that can be accessed in real-time. * This may need to be held in physical memory so that it is not * paged to virtual memory. * This call MUST be balanced with a call to PaHost_FreeFastMemory(). * Memory will be set to zero. */void *PaHost_AllocateFastMemory( long numBytes ){ return PaHost_AllocateTrackedMemory( numBytes ); /* FIXME - do we need physical memory? Use VirtualLock() */ /* MEM */}/************************************************************************* * Free memory that could be accessed in real-time. * This call MUST be balanced with a call to PaHost_AllocateFastMemory(). */void PaHost_FreeFastMemory( void *addr, long numBytes ){ (void) numBytes; /* unused parameter */ PaHost_FreeTrackedMemory( addr ); /* MEM */}/************************************************************************* * Track memory allocations to avoid leaks. */static void *PaHost_AllocateTrackedMemory( long numBytes ){ void *result = GlobalAlloc( GPTR, numBytes ); /* MEM */#if PA_TRACK_MEMORY if( result != NULL ) sNumAllocations += 1;#endif return result;}static void PaHost_FreeTrackedMemory( void *addr ){ if( addr != NULL ) { GlobalFree( addr ); /* MEM */#if PA_TRACK_MEMORY sNumAllocations -= 1;#endif }}/***********************************************************************/PaError PaHost_StreamActive( internalPortAudioStream *internalStream ){ if( internalStream == NULL ) return paBadStreamPtr; return (PaError) internalStream->past_IsActive;}/************************************************************************* * This must be called periodically because mmtime.u.sample * is a DWORD and can wrap and lose sync after a few hours. */static PaError PaHost_UpdateStreamTime( PaWMMEStreamData *wmmeStreamData ){ MMRESULT mmresult; MMTIME mmtime; const int shift = 6; mmtime.wType = TIME_SAMPLES; if( wmmeStreamData->hWaveOut != NULL ) { mmresult = waveOutGetPosition( wmmeStreamData->hWaveOut, &mmtime, sizeof(mmtime) ); } else { mmresult = waveInGetPosition( wmmeStreamData->hWaveIn, &mmtime, sizeof(mmtime) ); } if( mmresult != MMSYSERR_NOERROR ) { sPaHostError = mmresult; return paHostError; } /* This data has two variables and is shared by foreground and background. * So we need to make it thread safe. */ EnterCriticalSection( &wmmeStreamData->streamLock );// The casting and shifting in computing frames played is// to deal with wrap-around.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -