📄 pa_win_ds.c
字号:
}
return (int) (minLatencyMsec * sampleRate * SECONDS_PER_MSEC);
}
#ifndef NDEBUG
#define EZ = 0
#else
#define EZ
#endif
/***********************************************************************************/
/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
PaStream** s,
const PaStreamParameters *inputParameters,
const PaStreamParameters *outputParameters,
double sampleRate,
unsigned long framesPerBuffer,
PaStreamFlags streamFlags,
PaStreamCallback *streamCallback,
void *userData )
{
PaError result = paNoError;
PaWinDsHostApiRepresentation *winDsHostApi = (PaWinDsHostApiRepresentation*)hostApi;
PaWinDsStream *stream = 0;
int inputChannelCount, outputChannelCount;
PaSampleFormat inputSampleFormat EZ, outputSampleFormat EZ;
PaSampleFormat hostInputSampleFormat EZ, hostOutputSampleFormat EZ;
unsigned long suggestedInputLatencyFrames, suggestedOutputLatencyFrames;
if( inputParameters )
{
inputChannelCount = inputParameters->channelCount;
inputSampleFormat = inputParameters->sampleFormat;
suggestedInputLatencyFrames = (unsigned long)(inputParameters->suggestedLatency * sampleRate);
/* IDEA: the following 3 checks could be performed by default by pa_front
unless some flag indicated otherwise */
/* unless alternate device specification is supported, reject the use of
paUseHostApiSpecificDeviceSpecification */
if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
return paInvalidDevice;
/* check that input device can support inputChannelCount */
if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
return paInvalidChannelCount;
/* validate hostApiSpecificStreamInfo */
if( inputParameters->hostApiSpecificStreamInfo )
return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
}
else
{
inputChannelCount = 0;
suggestedInputLatencyFrames = 0;
}
if( outputParameters )
{
outputChannelCount = outputParameters->channelCount;
outputSampleFormat = outputParameters->sampleFormat;
suggestedOutputLatencyFrames = (unsigned long)(outputParameters->suggestedLatency * sampleRate);
/* unless alternate device specification is supported, reject the use of
paUseHostApiSpecificDeviceSpecification */
if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
return paInvalidDevice;
/* check that output device can support inputChannelCount */
if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
return paInvalidChannelCount;
/* validate hostApiSpecificStreamInfo */
if( outputParameters->hostApiSpecificStreamInfo )
return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
}
else
{
outputChannelCount = 0;
suggestedOutputLatencyFrames = 0;
}
/*
IMPLEMENT ME:
( the following two checks are taken care of by PaUtil_InitializeBufferProcessor() )
- check that input device can support inputSampleFormat, or that
we have the capability to convert from outputSampleFormat to
a native format
- check that output device can support outputSampleFormat, or that
we have the capability to convert from outputSampleFormat to
a native format
- if a full duplex stream is requested, check that the combination
of input and output parameters is supported
- check that the device supports sampleRate
- alter sampleRate to a close allowable rate if possible / necessary
- validate suggestedInputLatency and suggestedOutputLatency parameters,
use default values where necessary
*/
/* validate platform specific flags */
if( (streamFlags & paPlatformSpecificFlags) != 0 )
return paInvalidFlag; /* unexpected platform specific flag */
stream = (PaWinDsStream*)PaUtil_AllocateMemory( sizeof(PaWinDsStream) );
if( !stream )
{
result = paInsufficientMemory;
goto error;
}
if( streamCallback )
{
PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
&winDsHostApi->callbackStreamInterface, streamCallback, userData );
}
else
{
PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
&winDsHostApi->blockingStreamInterface, streamCallback, userData );
}
PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
if( inputParameters )
{
/* IMPLEMENT ME - establish which host formats are available */
hostInputSampleFormat =
PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, inputParameters->sampleFormat );
}
if( outputParameters )
{
/* IMPLEMENT ME - establish which host formats are available */
hostOutputSampleFormat =
PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, outputParameters->sampleFormat );
}
result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
inputChannelCount, inputSampleFormat, hostInputSampleFormat,
outputChannelCount, outputSampleFormat, hostOutputSampleFormat,
sampleRate, streamFlags, framesPerBuffer,
framesPerBuffer, /* ignored in paUtilVariableHostBufferSizePartialUsageAllowed mode. */
/* This next mode is required because DS can split the host buffer when it wraps around. */
paUtilVariableHostBufferSizePartialUsageAllowed,
streamCallback, userData );
if( result != paNoError )
goto error;
stream->streamRepresentation.streamInfo.inputLatency =
PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor); /* FIXME: not initialised anywhere else */
stream->streamRepresentation.streamInfo.outputLatency =
PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor); /* FIXME: not initialised anywhere else */
stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
/* DirectSound specific initialization */
{
HRESULT hr;
int bytesPerDirectSoundBuffer;
DSoundWrapper *dsw;
int userLatencyFrames;
int minLatencyFrames;
stream->timerID = 0;
dsw = &stream->directSoundWrapper;
DSW_Init( dsw );
/* Get system minimum latency. */
minLatencyFrames = PaWinDs_GetMinLatencyFrames( sampleRate );
/* Let user override latency by passing latency parameter. */
userLatencyFrames = (suggestedInputLatencyFrames > suggestedOutputLatencyFrames)
? suggestedInputLatencyFrames
: suggestedOutputLatencyFrames;
if( userLatencyFrames > 0 ) minLatencyFrames = userLatencyFrames;
/* Calculate stream->framesPerDSBuffer depending on framesPerBuffer */
if( framesPerBuffer == paFramesPerBufferUnspecified )
{
/* App support variable framesPerBuffer */
stream->framesPerDSBuffer = minLatencyFrames;
stream->streamRepresentation.streamInfo.outputLatency = (double)(minLatencyFrames - 1) / sampleRate;
}
else
{
/* Round up to number of buffers needed to guarantee that latency. */
int numUserBuffers = (minLatencyFrames + framesPerBuffer - 1) / framesPerBuffer;
if( numUserBuffers < 1 ) numUserBuffers = 1;
numUserBuffers += 1; /* So we have latency worth of buffers ahead of current buffer. */
stream->framesPerDSBuffer = framesPerBuffer * numUserBuffers;
stream->streamRepresentation.streamInfo.outputLatency = (double)(framesPerBuffer * (numUserBuffers-1)) / sampleRate;
}
{
/** @todo REVIEW: this calculation seems incorrect to me - rossb. */
int msecLatency = (int) ((stream->framesPerDSBuffer * MSEC_PER_SECOND) / sampleRate);
PRINT(("PortAudio on DirectSound - Latency = %d frames, %d msec\n", stream->framesPerDSBuffer, msecLatency ));
}
/* ------------------ OUTPUT */
if( outputParameters )
{
/*
PaDeviceInfo *deviceInfo = hostApi->deviceInfos[ outputParameters->device ];
DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", outputParameters->device));
*/
bytesPerDirectSoundBuffer = stream->framesPerDSBuffer * outputParameters->channelCount * sizeof(short);
if( bytesPerDirectSoundBuffer < DSBSIZE_MIN )
{
result = paBufferTooSmall;
goto error;
}
else if( bytesPerDirectSoundBuffer > DSBSIZE_MAX )
{
result = paBufferTooBig;
goto error;
}
hr = dswDSoundEntryPoints.DirectSoundCreate( winDsHostApi->winDsDeviceInfos[outputParameters->device].lpGUID,
&dsw->dsw_pDirectSound, NULL );
if( hr != DS_OK )
{
ERR_RPT(("PortAudio: DirectSoundCreate() failed!\n"));
result = paUnanticipatedHostError;
PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );
goto error;
}
hr = DSW_InitOutputBuffer( dsw,
(unsigned long) (sampleRate + 0.5),
(WORD)outputParameters->channelCount, bytesPerDirectSoundBuffer );
DBUG(("DSW_InitOutputBuffer() returns %x\n", hr));
if( hr != DS_OK )
{
result = paUnanticipatedHostError;
PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );
goto error;
}
/* Calculate value used in latency calculation to avoid real-time divides. */
stream->secondsPerHostByte = 1.0 /
(stream->bufferProcessor.bytesPerHostOutputSample *
outputChannelCount * sampleRate);
}
/* ------------------ INPUT */
if( inputParameters )
{
/*
PaDeviceInfo *deviceInfo = hostApi->deviceInfos[ inputParameters->device ];
DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", inputParameters->device));
*/
bytesPerDirectSoundBuffer = stream->framesPerDSBuffer * inputParameters->channelCount * sizeof(short);
if( bytesPerDirectSoundBuffer < DSBSIZE_MIN )
{
result = paBufferTooSmall;
goto error;
}
else if( bytesPerDirectSoundBuffer > DSBSIZE_MAX )
{
result = paBufferTooBig;
goto error;
}
hr = dswDSoundEntryPoints.DirectSoundCaptureCreate( winDsHostApi->winDsDeviceInfos[inputParameters->device].lpGUID,
&dsw->dsw_pDirectSoundCapture, NULL );
if( hr != DS_OK )
{
ERR_RPT(("PortAudio: DirectSoundCaptureCreate() failed!\n"));
result = paUnanticipatedHostError;
PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );
goto error;
}
hr = DSW_InitInputBuffer( dsw,
(unsigned long) (sampleRate + 0.5),
(WORD)inputParameters->channelCount, bytesPerDirectSoundBuffer );
DBUG(("DSW_InitInputBuffer() returns %x\n", hr));
if( hr != DS_OK )
{
ERR_RPT(("PortAudio: DSW_InitInputBuffer() returns %x\n", hr));
result = paUnanticipatedHostError;
PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );
goto error;
}
}
}
*s = (PaStream*)stream;
return result;
error:
if( stream )
PaUtil_FreeMemory( stream );
return result;
}
/***********************************************************************************/
static PaError Pa_TimeSlice( PaWinDsStream *stream )
{
PaError result = 0; /* FIXME: this should be declared int and this function should also return that type (same as stream callback return type)*/
DSoundWrapper *dsw;
long numFrames = 0;
long bytesEmpty = 0;
long bytesFilled = 0;
long bytesToXfer = 0;
long framesToXfer = 0;
long numInFramesReady = 0;
long numOutFramesReady = 0;
long bytesProcessed;
HRESULT hresult;
double outputLatency = 0;
PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /** @todo implement inputBufferAdcTime */
/* Input */
LPBYTE lpInBuf1 = NULL;
LPBYTE lpInBuf2 = NULL;
DWORD dwInSize1 = 0;
DWORD dwInSize2 = 0;
/* Output */
LPBYTE lpOutBuf1 = NULL;
LPBYTE lpOutBuf2 = NULL;
DWORD dwOutSize1 = 0;
DWORD dwOutSize2 = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -