📄 pa_dsound.c
字号:
{
int i;
ERR_RPT(("Creation of requested Audio Capture device '%s' failed.\n",
((pad->pad_lpGUID == NULL) ? "Default" : pad->pad_Info.name) ));
for( i=0; i<Pa_CountDevices(); i++ )
{
pad = Pa_GetInternalDevice( i );
if( pad->pad_Info.maxInputChannels >= past->past_NumInputChannels )
{
PRINT(("Try device '%s' instead.\n", pad->pad_Info.name ));
hr = DirectSoundCaptureCreate( pad->pad_lpGUID, &dsw->dsw_pDirectSoundCapture, NULL );
if( hr == DS_OK ) break;
}
}
}
if( hr != DS_OK )
{
ERR_RPT(("PortAudio: DirectSoundCaptureCreate() failed!\n"));
result = paHostError;
sPaHostError = hr;
goto error;
}
hr = DSW_InitInputBuffer( dsw,
(unsigned long) (past->past_SampleRate + 0.5),
past->past_NumInputChannels, numBytes );
DBUG(("DSW_InitInputBuffer() returns %x\n", hr));
if( hr != DS_OK )
{
ERR_RPT(("PortAudio: DSW_InitInputBuffer() returns %x\n", hr));
result = paHostError;
sPaHostError = hr;
goto error;
}
}
#endif /* SUPPORT_AUDIO_CAPTURE */
/* Calculate scalar used in CPULoad calculation. */
{
LARGE_INTEGER frequency;
if( QueryPerformanceFrequency( &frequency ) == 0 )
{
pahsc->pahsc_InverseTicksPerUserBuffer = 0.0;
}
else
{
pahsc->pahsc_InverseTicksPerUserBuffer = past->past_SampleRate /
( (double)frequency.QuadPart * past->past_FramesPerUserBuffer );
DBUG(("pahsc_InverseTicksPerUserBuffer = %g\n", pahsc->pahsc_InverseTicksPerUserBuffer ));
}
}
return result;
error:
PaHost_CloseStream( past );
return result;
}
/*************************************************************************/
PaError PaHost_StartOutput( internalPortAudioStream *past )
{
HRESULT hr;
PaHostSoundControl *pahsc;
PaError result = paNoError;
pahsc = (PaHostSoundControl *) past->past_DeviceData;
/* Give user callback a chance to pre-fill buffer. */
result = Pa_TimeSlice( past );
if( result != paNoError ) return result; // FIXME - what if finished?
hr = DSW_StartOutput( &pahsc->pahsc_DSoundWrapper );
DBUG(("PaHost_StartOutput: DSW_StartOutput returned = 0x%X.\n", hr));
if( hr != DS_OK )
{
result = paHostError;
sPaHostError = hr;
goto error;
}
error:
return result;
}
/*************************************************************************/
PaError PaHost_StartInput( internalPortAudioStream *past )
{
PaError result = paNoError;
#if SUPPORT_AUDIO_CAPTURE
HRESULT hr;
PaHostSoundControl *pahsc;
pahsc = (PaHostSoundControl *) past->past_DeviceData;
hr = DSW_StartInput( &pahsc->pahsc_DSoundWrapper );
DBUG(("Pa_StartStream: DSW_StartInput returned = 0x%X.\n", hr));
if( hr != DS_OK )
{
result = paHostError;
sPaHostError = hr;
goto error;
}
error:
#endif /* SUPPORT_AUDIO_CAPTURE */
return result;
}
/*************************************************************************/
PaError PaHost_StartEngine( internalPortAudioStream *past )
{
PaHostSoundControl *pahsc;
PaError result = paNoError;
pahsc = (PaHostSoundControl *) past->past_DeviceData;
past->past_StopNow = 0;
past->past_StopSoon = 0;
past->past_IsActive = 1;
/* Create timer that will wake us up so we can fill the DSound buffer. */
{
int msecPerBuffer;
int resolution;
int bufsPerInterrupt;
DBUG(("PaHost_StartEngine: past_NumUserBuffers = %d\n", past->past_NumUserBuffers));
/* Decide how often to wake up and fill the buffers. */
if( past->past_NumUserBuffers == 2 )
{
/* Generate two timer interrupts per user buffer. */
msecPerBuffer = (500 * past->past_FramesPerUserBuffer) / (int) past->past_SampleRate;
}
else
{
if ( past->past_NumUserBuffers >= 16 ) bufsPerInterrupt = past->past_NumUserBuffers/8;
else if ( past->past_NumUserBuffers >= 8 ) bufsPerInterrupt = 2;
else bufsPerInterrupt = 1;
msecPerBuffer = 1000 * (bufsPerInterrupt * past->past_FramesPerUserBuffer) / (int) past->past_SampleRate;
DBUG(("PaHost_StartEngine: bufsPerInterrupt = %d\n", bufsPerInterrupt));
}
DBUG(("PaHost_StartEngine: msecPerBuffer = %d\n", msecPerBuffer));
if( msecPerBuffer < 10 ) msecPerBuffer = 10;
else if( msecPerBuffer > 100 ) msecPerBuffer = 100;
DBUG(("PaHost_StartEngine: clipped msecPerBuffer = %d\n", msecPerBuffer));
resolution = msecPerBuffer/4;
pahsc->pahsc_TimerID = timeSetEvent( msecPerBuffer, resolution, (LPTIMECALLBACK) Pa_TimerCallback,
(DWORD) past, TIME_PERIODIC );
}
if( pahsc->pahsc_TimerID == 0 )
{
past->past_IsActive = 0;
result = paHostError;
sPaHostError = 0;
goto error;
}
error:
return result;
}
/*************************************************************************/
PaError PaHost_StopEngine( internalPortAudioStream *past, int abort )
{
int timeoutMsec;
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
if( pahsc == NULL ) return paNoError;
if( abort ) past->past_StopNow = 1;
past->past_StopSoon = 1;
/* Set timeout at 20% beyond maximum time we might wait. */
timeoutMsec = (int) (1200.0 * pahsc->pahsc_FramesPerDSBuffer / past->past_SampleRate);
while( past->past_IsActive && (timeoutMsec > 0) )
{
Sleep(10);
timeoutMsec -= 10;
}
if( pahsc->pahsc_TimerID != 0 )
{
timeKillEvent(pahsc->pahsc_TimerID); /* Stop callback timer. */
pahsc->pahsc_TimerID = 0;
}
return paNoError;
}
/*************************************************************************/
PaError PaHost_StopInput( internalPortAudioStream *past, int abort )
{
#if SUPPORT_AUDIO_CAPTURE
HRESULT hr;
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
if( pahsc == NULL ) return paNoError;
(void) abort;
hr = DSW_StopInput( &pahsc->pahsc_DSoundWrapper );
DBUG(("DSW_StopInput() result is %x\n", hr));
#endif /* SUPPORT_AUDIO_CAPTURE */
return paNoError;
}
/*************************************************************************/
PaError PaHost_StopOutput( internalPortAudioStream *past, int abort )
{
HRESULT hr;
PaHostSoundControl *pahsc;
pahsc = (PaHostSoundControl *) past->past_DeviceData;
if( pahsc == NULL ) return paNoError;
(void) abort;
hr = DSW_StopOutput( &pahsc->pahsc_DSoundWrapper );
DBUG(("DSW_StopOutput() result is %x\n", hr));
return paNoError;
}
/*******************************************************************/
PaError PaHost_CloseStream( internalPortAudioStream *past )
{
PaHostSoundControl *pahsc;
if( past == NULL ) return paBadStreamPtr;
pahsc = (PaHostSoundControl *) past->past_DeviceData;
if( pahsc == NULL ) return paNoError;
DSW_Term( &pahsc->pahsc_DSoundWrapper );
if( pahsc->pahsc_NativeBuffer )
{
PaHost_FreeFastMemory( pahsc->pahsc_NativeBuffer, pahsc->pahsc_BytesPerBuffer ); /* MEM */
pahsc->pahsc_NativeBuffer = NULL;
}
PaHost_FreeFastMemory( pahsc, sizeof(PaHostSoundControl) ); /* MEM */
past->past_DeviceData = NULL;
return paNoError;
}
/* Set minimal latency based on whether NT or Win95.
* NT has higher latency.
*/
static int PaHost_GetMinSystemLatency( void )
{
int minLatencyMsec;
/* 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;
}
return minLatencyMsec;
}
/*************************************************************************
** 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 );
}
else
{
minLatencyMsec = PaHost_GetMinSystemLatency();
#if PA_USE_HIGH_LATENCY
PRINT(("PA - Minimum Latency set to %d msec!\n", minLatencyMsec ));
#endif
}
minBuffers = (int) (1.0 + ((double)minLatencyMsec / msecPerBuffer));
if( minBuffers < 2 ) minBuffers = 2;
return minBuffers;
}
/*************************************************************************/
PaError PaHost_Term( void )
{
int i;
/* Free names allocated during enumeration. */
for( i=0; i<sNumDevices; i++ )
{
if( sDevices[i].pad_Info.name != NULL )
{
free( (void *) sDevices[i].pad_Info.name );
sDevices[i].pad_Info.name = NULL;
}
}
if( sDevices != NULL )
{
PaHost_FreeFastMemory( sDevices, sNumDevices * sizeof(internalPortAudioDevice) ); /* MEM */
sDevices = NULL;
sNumDevices = 0;
}
return 0;
}
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);
}
/*************************************************************************/
PaTimestamp Pa_StreamTime( PortAudioStream *stream )
{
DSoundWrapper *dsw;
internalPortAudioStream *past = (internalPortAudioStream *) stream;
PaHostSoundControl *pahsc;
if( past == NULL ) return paBadStreamPtr;
pahsc = (PaHostSoundControl *) past->past_DeviceData;
dsw = &pahsc->pahsc_DSoundWrapper;
return dsw->dsw_FramesPlayed;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -