📄 pa_win_wmme.c
字号:
pa_stdout = fopen("\\Program Files\\myApp\\pa_Host_StartEngine.txt","w+t");
past->past_StopSoon = 0;
past->past_StopNow = 0;
past->past_IsActive = 1;
pahsc->pahsc_FramesPlayed = 0.0;
pahsc->pahsc_LastPosition = 0;
#if PA_TRACE_START_STOP
pa_len=sprintf(pa_buf,"PaHost_StartEngine: TimeSlice() returned ", result );
pa_nbw = fwrite(pa_buf,1,pa_len,pa_stdout); fflush(pa_stdout);
#endif
#if PA_USE_TIMER_CALLBACK
/* Create timer that will wake us up so we can fill the DSound buffer. */
bufsPerTimerCallback = pahsc->pahsc_NumHostBuffers/4;
if( bufsPerTimerCallback < 1 ) bufsPerTimerCallback = 1;
if( bufsPerTimerCallback < 1 ) bufsPerTimerCallback = 1;
msecPerBuffer = (1000 * bufsPerTimerCallback *
pahsc->pahsc_UserBuffersPerHostBuffer *
past->past_FramesPerUserBuffer ) / (int) past->past_SampleRate;
if( msecPerBuffer < 10 ) msecPerBuffer = 10;
else if( msecPerBuffer > 100 ) msecPerBuffer = 100;
resolution = msecPerBuffer/4;
pahsc->pahsc_TimerID = timeSetEvent( msecPerBuffer, resolution,
(LPTIMECALLBACK) Pa_TimerCallback,
(DWORD) past, TIME_PERIODIC );
if( pahsc->pahsc_TimerID == 0 )
{
result = paHostError;
sPaHostError = GetLastError();;
pa_len=sprintf(pa_buf,"PaHost_StartEngine: checkpoint#1 result=%d", result );
pa_nbw = fwrite(pa_buf,1,pa_len,pa_stdout); fflush(pa_stdout);
goto error;
}
#else /* PA_USE_TIMER_CALLBACK */
ResetEvent( pahsc->pahsc_AbortEvent );
/* Create thread that waits for audio buffers to be ready for processing. */
pahsc->pahsc_EngineThread = CreateThread( 0, 0, WinMMPa_OutputThreadProc, past, 0, &pahsc->pahsc_EngineThreadID );
if( pahsc->pahsc_EngineThread == NULL )
{
result = paHostError;
sPaHostError = GetLastError();;
pa_len=sprintf(pa_buf,"PaHost_StartEngine: checkpoint#2 result=%d", result );
pa_nbw = fwrite(pa_buf,1,pa_len,pa_stdout); fflush(pa_stdout);
goto error;
}
#if PA_TRACE_START_STOP
pa_len=sprintf(pa_buf,"PaHost_StartEngine: thread ", (int) pahsc->pahsc_EngineThread);
pa_nbw = fwrite(pa_buf,1,pa_len,pa_stdout); fflush(pa_stdout);
#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( !SetPriorityClass( GetCurrentProcess(), HIGH_PRIORITY_CLASS ) ) */ /* PLB20010816 */
// disable this code because it is causing a run-time termimation
// if( !SetThreadPriority( GetCurrentProcess(), THREAD_PRIORITY_HIGHEST ) ) /* GJG20020929 */
// {
// result = paHostError;
// sPaHostError = GetLastError();;
// pa_len=sprintf(pa_buf,"PaHost_StartEngine: checkpoint#3 result=%d", result );
// pa_nbw = fwrite(pa_buf,1,pa_len,pa_stdout); fflush(pa_stdout);
// goto error;
// }
if( !SetThreadPriority( pahsc->pahsc_EngineThread, THREAD_PRIORITY_HIGHEST ) )
{
result = paHostError;
sPaHostError = GetLastError();;
pa_len=sprintf(pa_buf,"PaHost_StartEngine: checkpoint#4 result=%d", result );
pa_nbw = fwrite(pa_buf,1,pa_len,pa_stdout); fflush(pa_stdout);
goto error;
}
#endif
error:
fclose(pa_stdout);
return result;
}
/*************************************************************************/
PaError PaHost_StopEngine( internalPortAudioStream *past, int abort )
{
int timeOut;
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
if( pahsc == NULL ) return paNoError;
/* Tell background thread to stop generating more data and to let current data play out. */
past->past_StopSoon = 1;
/* If aborting, tell background thread to stop NOW! */
if( abort ) past->past_StopNow = 1;
/* Calculate timeOut longer than longest time it could take to play all buffers. */
timeOut = (DWORD) (1500.0 * PaHost_GetTotalBufferFrames( past ) / past->past_SampleRate);
if( timeOut < MIN_TIMEOUT_MSEC ) timeOut = MIN_TIMEOUT_MSEC;
#if PA_USE_TIMER_CALLBACK
if( (past->past_OutputDeviceID != paNoDevice) &&
past->past_IsActive &&
(pahsc->pahsc_TimerID != 0) )
{
/* Wait for IsActive to drop. */
while( (past->past_IsActive) && (timeOut > 0) )
{
Sleep(10);
timeOut -= 10;
}
timeKillEvent(pahsc->pahsc_TimerID); /* Stop callback timer. */
pahsc->pahsc_TimerID = 0;
}
#else /* PA_USE_TIMER_CALLBACK */
#if PA_TRACE_START_STOP
AddTraceMessage( "PaHost_StopEngine: thread ", (int) pahsc->pahsc_EngineThread );
#endif
if( (past->past_OutputDeviceID != paNoDevice) &&
(past->past_IsActive) &&
(pahsc->pahsc_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( pahsc->pahsc_EngineThread, timeOut );
if( got == WAIT_TIMEOUT )
{
ERR_RPT(("PaHost_StopEngine: timed out while waiting for background thread.\n"));
return paTimedOut;
}
CloseHandle( pahsc->pahsc_EngineThread );
pahsc->pahsc_EngineThread = NULL;
}
#endif /* PA_USE_TIMER_CALLBACK */
past->past_IsActive = 0;
return paNoError;
}
/*************************************************************************/
PaError PaHost_StopInput( internalPortAudioStream *past, int abort )
{
MMRESULT mr;
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
if( pahsc == NULL ) return paNoError;
(void) abort;
if( pahsc->pahsc_HWaveIn != NULL )
{
mr = waveInReset( pahsc->pahsc_HWaveIn );
if( mr != MMSYSERR_NOERROR )
{
sPaHostError = mr;
return paHostError;
}
}
return paNoError;
}
/*************************************************************************/
PaError PaHost_StopOutput( internalPortAudioStream *past, int abort )
{
MMRESULT mr;
PaHostSoundControl *pahsc;
pahsc = (PaHostSoundControl *) past->past_DeviceData;
if( pahsc == NULL ) return paNoError;
(void) abort;
#if PA_TRACE_START_STOP
AddTraceMessage( "PaHost_StopOutput: pahsc_HWaveOut ", (int) pahsc->pahsc_HWaveOut );
#endif
if( pahsc->pahsc_HWaveOut != NULL )
{
mr = waveOutReset( pahsc->pahsc_HWaveOut );
if( mr != MMSYSERR_NOERROR )
{
sPaHostError = mr;
return paHostError;
}
}
return paNoError;
}
/*******************************************************************/
PaError PaHost_CloseStream( internalPortAudioStream *past )
{
int i;
PaHostSoundControl *pahsc;
if( past == NULL ) return paBadStreamPtr;
pahsc = (PaHostSoundControl *) past->past_DeviceData;
if( pahsc == NULL ) return paNoError;
#if PA_TRACE_START_STOP
AddTraceMessage( "PaHost_CloseStream: pahsc_HWaveOut ", (int) pahsc->pahsc_HWaveOut );
#endif
/* Free data and device for output. */
if( pahsc->pahsc_HWaveOut )
{
if( pahsc->pahsc_OutputBuffers )
{
for( i=0; i<pahsc->pahsc_NumHostBuffers; i++ )
{
waveOutUnprepareHeader( pahsc->pahsc_HWaveOut, &pahsc->pahsc_OutputBuffers[i], sizeof(WAVEHDR) );
GlobalFree( pahsc->pahsc_OutputBuffers[i].lpData ); /* MEM */
}
GlobalFree( pahsc->pahsc_OutputBuffers ); /* MEM */
}
waveOutClose( pahsc->pahsc_HWaveOut );
}
/* Free data and device for input. */
if( pahsc->pahsc_HWaveIn )
{
if( pahsc->pahsc_InputBuffers )
{
for( i=0; i<pahsc->pahsc_NumHostBuffers; i++ )
{
waveInUnprepareHeader( pahsc->pahsc_HWaveIn, &pahsc->pahsc_InputBuffers[i], sizeof(WAVEHDR) );
GlobalFree( pahsc->pahsc_InputBuffers[i].lpData ); /* MEM */
}
GlobalFree( pahsc->pahsc_InputBuffers ); /* MEM */
}
waveInClose( pahsc->pahsc_HWaveIn );
}
#if (PA_USE_TIMER_CALLBACK == 0)
if( pahsc->pahsc_AbortEventInited ) CloseHandle( pahsc->pahsc_AbortEvent );
if( pahsc->pahsc_BufferEventInited ) CloseHandle( pahsc->pahsc_BufferEvent );
#endif
if( pahsc->pahsc_StreamLockInited )
DeleteCriticalSection( &pahsc->pahsc_StreamLock );
PaHost_FreeFastMemory( pahsc, sizeof(PaHostSoundControl) ); /* MEM */
past->past_DeviceData = NULL;
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 hostVersion;
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 ); */
/* GJG20020928 - GetEnvironmentVariable not supported under Windows CE. */
/* ref. Programming Microsoft Windows CE 2nd Ed. Douglas Boling p.488 */
hresult=0;
if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) )
{
minLatencyMsec = atoi( envbuf );
}
else
{
/* Set minimal latency based on whether NT or Win95.
* NT has higher latency.
*/
/* hostVersion = GetVersion(); */
/* GJG20020928 - GetVersion not supported by Windows CE */
/* Windows CE can call GetVersionEx() but a structure needs to be defined for the info. */
/* I am going to just return 1 and ask the developers if they wish to change this. */
hostVersion=1; /* 0=NT/Win2000/XP; 1=Win95/98/Me
/* High bit clear if NT */
minLatencyMsec = ( (hostVersion & 0x80000000) == 0 ) ? PA_WIN_NT_LATENCY : 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 )
{
GlobalFree( (char*)sDevicePtrs[i]->name ); /* MEM */
GlobalFree( (void*)sDevicePtrs[i]->sampleRates ); /* MEM */
GlobalFree( sDevicePtrs[i] ); /* MEM */
}
}
GlobalFree( sDevicePtrs ); /* MEM */
sDevicePtrs = NULL;
}
sNumDevices = 0;
}
return paNoError;
}
/*************************************************************************/
void Pa_Sleep( long msec )
{
Sleep( msec );
}
/*************************************************************************
* 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 )
{
void *addr = GlobalAlloc( GPTR, numBytes ); /* FIXME - do we need physical memory? Use VirtualLock() */ /* MEM */
return addr;
}
/*************************************************************************
* 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 )
{
if( addr != NULL ) GlobalFree( addr ); /* MEM */
}
/***********************************************************************/
PaError PaHost_StreamActive( internalPortAudioStream *past )
{
PaHostSoundControl *pahsc;
if( past == NULL ) return paBadStreamPtr;
pahsc = (PaHostSoundControl *) past->past_DeviceData;
if( pahsc == NULL ) return paInternalError;
return (PaError) past->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( PaHostSoundControl *pahsc )
{
MMRESULT mr;
MMTIME mmtime;
mmtime.wType = TIME_SAMPLES;
if( pahsc->pahsc_HWaveOut != NULL )
{
mr = waveOutGetPosition( pahsc->pahsc_HWaveOut, &mmtime, sizeof(mmtime) );
}
else
{
mr = waveInGetPosition( pahsc->pahsc_HWaveIn, &mmtime, sizeof(mmtime) );
}
if( mr != MMSYSERR_NOERROR )
{
sPaHostError = mr;
return paHostError;
}
/* This data has two variables and is shared by foreground and background. */
/* So we need to make it thread safe. */
EnterCriticalSection( &pahsc->pahsc_StreamLock );
pahsc->pahsc_FramesPlayed += ((long)mmtime.u.sample) - pahsc->pahsc_LastPosition;
pahsc->pahsc_LastPosition = (long)mmtime.u.sample;
LeaveCriticalSection( &pahsc->pahsc_StreamLock );
return paNoError;
}
/*************************************************************************/
PaTimestamp Pa_StreamTime( PortAudioStream *stream )
{
PaHostSoundControl *pahsc;
internalPortAudioStream *past = (internalPortAudioStream *) stream;
if( past == NULL ) return paBadStreamPtr;
pahsc = (PaHostSoundControl *) past->past_DeviceData;
PaHost_UpdateStreamTime( pahsc );
return pahsc->pahsc_FramesPlayed;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -