📄 pa_win_ds.c
字号:
dsw = &stream->directSoundWrapper;
/* How much input data is available? */
if( stream->bufferProcessor.inputChannelCount > 0 )
{
DSW_QueryInputFilled( dsw, &bytesFilled );
framesToXfer = numInFramesReady = bytesFilled / dsw->dsw_BytesPerInputFrame;
outputLatency = ((double)bytesFilled) * stream->secondsPerHostByte;
/** @todo Check for overflow */
}
/* How much output room is available? */
if( stream->bufferProcessor.outputChannelCount > 0 )
{
UINT previousUnderflowCount = dsw->dsw_OutputUnderflows;
DSW_QueryOutputSpace( dsw, &bytesEmpty );
framesToXfer = numOutFramesReady = bytesEmpty / dsw->dsw_BytesPerOutputFrame;
/* Check for underflow */
if( dsw->dsw_OutputUnderflows != previousUnderflowCount )
stream->callbackFlags |= paOutputUnderflow;
}
if( (numInFramesReady > 0) && (numOutFramesReady > 0) )
{
framesToXfer = (numOutFramesReady < numInFramesReady) ? numOutFramesReady : numInFramesReady;
}
if( framesToXfer > 0 )
{
PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
/* The outputBufferDacTime parameter should indicates the time at which
the first sample of the output buffer is heard at the DACs. */
timeInfo.currentTime = PaUtil_GetTime();
timeInfo.outputBufferDacTime = timeInfo.currentTime + outputLatency;
PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, stream->callbackFlags );
stream->callbackFlags = 0;
/* Input */
if( stream->bufferProcessor.inputChannelCount > 0 )
{
bytesToXfer = framesToXfer * dsw->dsw_BytesPerInputFrame;
hresult = IDirectSoundCaptureBuffer_Lock ( dsw->dsw_InputBuffer,
dsw->dsw_ReadOffset, bytesToXfer,
(void **) &lpInBuf1, &dwInSize1,
(void **) &lpInBuf2, &dwInSize2, 0);
if (hresult != DS_OK)
{
ERR_RPT(("DirectSound IDirectSoundCaptureBuffer_Lock failed, hresult = 0x%x\n",hresult));
result = paUnanticipatedHostError;
PA_DS_SET_LAST_DIRECTSOUND_ERROR( hresult );
goto error2;
}
numFrames = dwInSize1 / dsw->dsw_BytesPerInputFrame;
PaUtil_SetInputFrameCount( &stream->bufferProcessor, numFrames );
PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, 0, lpInBuf1, 0 );
/* Is input split into two regions. */
if( dwInSize2 > 0 )
{
numFrames = dwInSize2 / dsw->dsw_BytesPerInputFrame;
PaUtil_Set2ndInputFrameCount( &stream->bufferProcessor, numFrames );
PaUtil_Set2ndInterleavedInputChannels( &stream->bufferProcessor, 0, lpInBuf2, 0 );
}
}
/* Output */
if( stream->bufferProcessor.outputChannelCount > 0 )
{
bytesToXfer = framesToXfer * dsw->dsw_BytesPerOutputFrame;
hresult = IDirectSoundBuffer_Lock ( dsw->dsw_OutputBuffer,
dsw->dsw_WriteOffset, bytesToXfer,
(void **) &lpOutBuf1, &dwOutSize1,
(void **) &lpOutBuf2, &dwOutSize2, 0);
if (hresult != DS_OK)
{
ERR_RPT(("DirectSound IDirectSoundBuffer_Lock failed, hresult = 0x%x\n",hresult));
result = paUnanticipatedHostError;
PA_DS_SET_LAST_DIRECTSOUND_ERROR( hresult );
goto error1;
}
numFrames = dwOutSize1 / dsw->dsw_BytesPerOutputFrame;
PaUtil_SetOutputFrameCount( &stream->bufferProcessor, numFrames );
PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, 0, lpOutBuf1, 0 );
/* Is output split into two regions. */
if( dwOutSize2 > 0 )
{
numFrames = dwOutSize2 / dsw->dsw_BytesPerOutputFrame;
PaUtil_Set2ndOutputFrameCount( &stream->bufferProcessor, numFrames );
PaUtil_Set2ndInterleavedOutputChannels( &stream->bufferProcessor, 0, lpOutBuf2, 0 );
}
}
result = paContinue;
numFrames = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &result );
stream->framesWritten += numFrames;
if( stream->bufferProcessor.outputChannelCount > 0 )
{
/* FIXME: an underflow could happen here */
/* Update our buffer offset and unlock sound buffer */
bytesProcessed = numFrames * dsw->dsw_BytesPerOutputFrame;
dsw->dsw_WriteOffset = (dsw->dsw_WriteOffset + bytesProcessed) % dsw->dsw_OutputSize;
IDirectSoundBuffer_Unlock( dsw->dsw_OutputBuffer, lpOutBuf1, dwOutSize1, lpOutBuf2, dwOutSize2);
dsw->dsw_FramesWritten += numFrames;
}
error1:
if( stream->bufferProcessor.inputChannelCount > 0 )
{
/* FIXME: an overflow could happen here */
/* Update our buffer offset and unlock sound buffer */
bytesProcessed = numFrames * dsw->dsw_BytesPerInputFrame;
dsw->dsw_ReadOffset = (dsw->dsw_ReadOffset + bytesProcessed) % dsw->dsw_InputSize;
IDirectSoundCaptureBuffer_Unlock( dsw->dsw_InputBuffer, lpInBuf1, dwInSize1, lpInBuf2, dwInSize2);
}
error2:
PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, numFrames );
}
return result;
}
/*******************************************************************/
static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
{
PaWinDsStream *stream;
/* suppress unused variable warnings */
(void) uID;
(void) uMsg;
(void) dw1;
(void) dw2;
stream = (PaWinDsStream *) dwUser;
if( stream == NULL ) return;
if( stream->isActive )
{
if( stream->abortProcessing )
{
stream->isActive = 0;
}
else if( stream->stopProcessing )
{
DSoundWrapper *dsw = &stream->directSoundWrapper;
if( stream->bufferProcessor.outputChannelCount > 0 )
{
DSW_ZeroEmptySpace( dsw );
/* clear isActive when all sound played */
if( dsw->dsw_FramesPlayed >= stream->framesWritten )
{
stream->isActive = 0;
}
}
else
{
stream->isActive = 0;
}
}
else
{
if( Pa_TimeSlice( stream ) != 0) /* Call time slice independant of timing method. */
{
/* FIXME implement handling of paComplete and paAbort if possible */
stream->stopProcessing = 1;
}
}
if( !stream->isActive ){
if( stream->streamRepresentation.streamFinishedCallback != 0 )
stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
}
}
}
/***********************************************************************************
When CloseStream() is called, the multi-api layer ensures that
the stream has already been stopped or aborted.
*/
static PaError CloseStream( PaStream* s )
{
PaError result = paNoError;
PaWinDsStream *stream = (PaWinDsStream*)s;
DSW_Term( &stream->directSoundWrapper );
PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
PaUtil_FreeMemory( stream );
return result;
}
/***********************************************************************************/
static PaError StartStream( PaStream *s )
{
PaError result = paNoError;
PaWinDsStream *stream = (PaWinDsStream*)s;
HRESULT hr;
PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
if( stream->bufferProcessor.inputChannelCount > 0 )
{
hr = DSW_StartInput( &stream->directSoundWrapper );
DBUG(("StartStream: DSW_StartInput returned = 0x%X.\n", hr));
if( hr != DS_OK )
{
result = paUnanticipatedHostError;
PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );
goto error;
}
}
stream->framesWritten = 0;
stream->callbackFlags = 0;
stream->abortProcessing = 0;
stream->stopProcessing = 0;
stream->isActive = 1;
if( stream->bufferProcessor.outputChannelCount > 0 )
{
/* Give user callback a chance to pre-fill buffer. REVIEW - i thought we weren't pre-filling, rb. */
result = Pa_TimeSlice( stream );
if( result != paNoError ) return result; // FIXME - what if finished?
hr = DSW_StartOutput( &stream->directSoundWrapper );
DBUG(("PaHost_StartOutput: DSW_StartOutput returned = 0x%X.\n", hr));
if( hr != DS_OK )
{
result = paUnanticipatedHostError;
PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );
goto error;
}
}
/* Create timer that will wake us up so we can fill the DSound buffer. */
{
int resolution;
int framesPerWakeup = stream->framesPerDSBuffer / 4;
int msecPerWakeup = MSEC_PER_SECOND * framesPerWakeup / (int) stream->streamRepresentation.streamInfo.sampleRate;
if( msecPerWakeup < 10 ) msecPerWakeup = 10;
else if( msecPerWakeup > 100 ) msecPerWakeup = 100;
resolution = msecPerWakeup/4;
stream->timerID = timeSetEvent( msecPerWakeup, resolution, (LPTIMECALLBACK) Pa_TimerCallback,
(DWORD) stream, TIME_PERIODIC );
}
if( stream->timerID == 0 )
{
stream->isActive = 0;
result = paUnanticipatedHostError;
PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );
goto error;
}
stream->isStarted = TRUE;
error:
return result;
}
/***********************************************************************************/
static PaError StopStream( PaStream *s )
{
PaError result = paNoError;
PaWinDsStream *stream = (PaWinDsStream*)s;
HRESULT hr;
int timeoutMsec;
stream->stopProcessing = 1;
/* Set timeout at 20% beyond maximum time we might wait. */
timeoutMsec = (int) (1200.0 * stream->framesPerDSBuffer / stream->streamRepresentation.streamInfo.sampleRate);
while( stream->isActive && (timeoutMsec > 0) )
{
Sleep(10);
timeoutMsec -= 10;
}
if( stream->timerID != 0 )
{
timeKillEvent(stream->timerID); /* Stop callback timer. */
stream->timerID = 0;
}
if( stream->bufferProcessor.outputChannelCount > 0 )
{
hr = DSW_StopOutput( &stream->directSoundWrapper );
}
if( stream->bufferProcessor.inputChannelCount > 0 )
{
hr = DSW_StopInput( &stream->directSoundWrapper );
}
stream->isStarted = FALSE;
return result;
}
/***********************************************************************************/
static PaError AbortStream( PaStream *s )
{
PaWinDsStream *stream = (PaWinDsStream*)s;
stream->abortProcessing = 1;
return StopStream( s );
}
/***********************************************************************************/
static PaError IsStreamStopped( PaStream *s )
{
PaWinDsStream *stream = (PaWinDsStream*)s;
return !stream->isStarted;
}
/***********************************************************************************/
static PaError IsStreamActive( PaStream *s )
{
PaWinDsStream *stream = (PaWinDsStream*)s;
return stream->isActive;
}
/***********************************************************************************/
static PaTime GetStreamTime( PaStream *s )
{
/* suppress unused variable warnings */
(void) s;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -