📄 pa_win_wasapi.cpp
字号:
return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
PaWinWasapiDeviceInfo &info = paWasapi->devInfo[inputParameters->device];
HRESULT hResult = info.device->Activate(
__uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL,
(void**)&stream->in.client);
if (hResult != S_OK)
return paInvalidDevice;
waveformatFromParams(stream->in.wavex,outputParameters,sampleRate);
PaWasapiFormatAnswer answer = IsFormatSupportedInternal(stream->in.client,
stream->in.wavex);
switch (answer){
case PWFA_OK: break;
case PWFA_NO: return paSampleFormatNotSupported;
case PWFA_SUGGESTED:
{
PRINT(("Suggested format:"));
LogWAVEFORMATEXTENSIBLE(stream->in.wavex);
if (stream->in.wavex.Format.nSamplesPerSec == (DWORD)sampleRate){
//no problem its a format issue only
}
else{
return paInvalidSampleRate;
}
}
}
//stream->out.period = info.DefaultDevicePeriod;
stream->in.period = info.MinimumDevicePeriod;
hResult = stream->in.client->Initialize(
AUDCLNT_SHAREMODE_SHARED,
//AUDCLNT_SHAREMODE_EXCLUSIVE,
0, //no flags
stream->in.period*3, //tripple buffer
0,//stream->out.period,
(WAVEFORMATEX*)&stream->in.wavex,
&stream->session
);
if (hResult != S_OK){
logAUDCLNT_E(hResult);
return paInvalidDevice;
}
hResult = stream->in.client->GetBufferSize(&stream->in.bufferSize);
if (hResult != S_OK)
return paInvalidDevice;
hResult = stream->in.client->GetStreamLatency(&stream->in.latency);
if (hResult != S_OK)
return paInvalidDevice;
double periodsPerSecond = 1.0/nano100ToSeconds(stream->in.period);
double samplesPerPeriod = (double)(stream->in.wavex.Format.nSamplesPerSec)/periodsPerSecond;
//this is the number of samples that are required at each period
stream->in.framesPerHostCallback = (unsigned long)samplesPerPeriod;//unrelated to channels
/* IMPLEMENT ME - establish which host formats are available */
hostInputSampleFormat =
PaUtil_SelectClosestAvailableFormat( waveformatToPaFormat(stream->in.wavex), inputSampleFormat );
}
else
{
inputChannelCount = 0;
inputSampleFormat = hostInputSampleFormat = paInt16; /* Surpress 'uninitialised var' warnings. */
}
if( outputParameters )
{
outputChannelCount = outputParameters->channelCount;
outputSampleFormat = outputParameters->sampleFormat;
/* 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 outputStreamInfo */
if( outputParameters->hostApiSpecificStreamInfo )
return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
PaWinWasapiDeviceInfo &info = paWasapi->devInfo[outputParameters->device];
HRESULT hResult = info.device->Activate(
__uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL,
(void**)&stream->out.client);
if (hResult != S_OK)
return paInvalidDevice;
waveformatFromParams(stream->out.wavex,outputParameters,sampleRate);
PaWasapiFormatAnswer answer = IsFormatSupportedInternal(stream->out.client,
stream->out.wavex);
switch (answer){
case PWFA_OK: break;
case PWFA_NO: return paSampleFormatNotSupported;
case PWFA_SUGGESTED:
{
PRINT(("Suggested format:"));
LogWAVEFORMATEXTENSIBLE(stream->out.wavex);
if (stream->out.wavex.Format.nSamplesPerSec == (DWORD)sampleRate){
//no problem its a format issue only
}
else{
return paInvalidSampleRate;
}
}
}
//stream->out.period = info.DefaultDevicePeriod;
stream->out.period = info.MinimumDevicePeriod;
hResult = stream->out.client->Initialize(
AUDCLNT_SHAREMODE_SHARED,
//AUDCLNT_SHAREMODE_EXCLUSIVE,
0, //no flags
stream->out.period*3, //tripple buffer
0,//stream->out.period,
(WAVEFORMATEX*)&stream->out.wavex,
&stream->session
);
if (hResult != S_OK){
logAUDCLNT_E(hResult);
return paInvalidDevice;
}
hResult = stream->out.client->GetBufferSize(&stream->out.bufferSize);
if (hResult != S_OK)
return paInvalidDevice;
hResult = stream->out.client->GetStreamLatency(&stream->out.latency);
if (hResult != S_OK)
return paInvalidDevice;
double periodsPerSecond = 1.0/nano100ToSeconds(stream->out.period);
double samplesPerPeriod = (double)(stream->out.wavex.Format.nSamplesPerSec)/periodsPerSecond;
//this is the number of samples that are required at each period
stream->out.framesPerHostCallback = (unsigned long)samplesPerPeriod;//unrelated to channels
/* IMPLEMENT ME - establish which host formats are available */
hostOutputSampleFormat =
PaUtil_SelectClosestAvailableFormat( waveformatToPaFormat(stream->out.wavex), outputSampleFormat );
}
else
{
outputChannelCount = 0;
outputSampleFormat = hostOutputSampleFormat = paInt16; /* Surpress 'uninitialized var' warnings. */
}
/*
IMPLEMENT ME:
( the following two checks are taken care of by PaUtil_InitializeBufferProcessor() FIXME - checks needed? )
- 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 */
if( streamCallback )
{
PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
&paWasapi->callbackStreamInterface, streamCallback, userData );
}
else
{
PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
&paWasapi->blockingStreamInterface, streamCallback, userData );
}
PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
if (outputParameters && inputParameters){
//serious problem #1
if (stream->in.period != stream->out.period){
PRINT(("OpenStream: period discrepancy\n"));
goto error;
}
//serious problem #2
if (stream->out.framesPerHostCallback != stream->in.framesPerHostCallback){
PRINT(("OpenStream: framesPerHostCallback discrepancy\n"));
goto error;
}
}
unsigned long framesPerHostCallback = (outputParameters)?
stream->out.framesPerHostCallback:
stream->in.framesPerHostCallback;
/* we assume a fixed host buffer size in this example, but the buffer processor
can also support bounded and unknown host buffer sizes by passing
paUtilBoundedHostBufferSize or paUtilUnknownHostBufferSize instead of
paUtilFixedHostBufferSize below. */
result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
inputChannelCount, inputSampleFormat, hostInputSampleFormat,
outputChannelCount, outputSampleFormat, hostOutputSampleFormat,
sampleRate, streamFlags, framesPerBuffer,
framesPerHostCallback, paUtilFixedHostBufferSize,
streamCallback, userData );
if( result != paNoError )
goto error;
/*
IMPLEMENT ME: initialise the following fields with estimated or actual
values.
*/
stream->streamRepresentation.streamInfo.inputLatency =
PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor)
+ ((inputParameters)?nano100ToSeconds(stream->in.latency) :0);
stream->streamRepresentation.streamInfo.outputLatency =
PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor)
+ ((outputParameters)?nano100ToSeconds(stream->out.latency) :0);
stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
*s = (PaStream*)stream;
return result;
error:
if( stream )
PaUtil_FreeMemory( stream );
return result;
}
/*
When CloseStream() is called, the multi-api layer ensures that
the stream has already been stopped or aborted.
*/
#define SAFE_RELEASE(punk) \
if ((punk) != NULL) \
{ (punk)->Release(); (punk) = NULL; }
static PaError CloseStream( PaStream* s )
{
PaError result = paNoError;
PaWinWasapiStream *stream = (PaWinWasapiStream*)s;
/*
IMPLEMENT ME:
- additional stream closing + cleanup
*/
SAFE_RELEASE(stream->out.client);
SAFE_RELEASE(stream->in.client);
SAFE_RELEASE(stream->cclient);
SAFE_RELEASE(stream->rclient);
CloseHandle(stream->hThread);
PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
PaUtil_FreeMemory( stream );
return result;
}
VOID ProcThread(void *client);
static PaError StartStream( PaStream *s )
{
PaError result = paNoError;
PaWinWasapiStream *stream = (PaWinWasapiStream*)s;
PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
HRESULT hResult=S_OK;
if (stream->out.client){
hResult = stream->out.client->GetService(__uuidof(IAudioRenderClient),(void**)&stream->rclient);
logAUDCLNT_E(hResult);
if (hResult!=S_OK)
return paUnanticipatedHostError;
}
if (stream->in.client){
hResult = stream->in.client->GetService(__uuidof(IAudioCaptureClient),(void**)&stream->cclient);
logAUDCLNT_E(hResult);
if (hResult!=S_OK)
return paUnanticipatedHostError;
}
// Create a thread for this client.
stream->hThread = CreateThread(
NULL, // no security attribute
0, // default stack size
(LPTHREAD_START_ROUTINE) ProcThread,
(LPVOID) stream, // thread parameter
0, // not suspended
&stream->dwThreadId); // returns thread ID
if (stream->hThread == NULL)
return paUnanticipatedHostError;
return paNoError;
}
static PaError StopStream( PaStream *s )
{
PaError result = paNoError;
PaWinWasapiStream *stream = (PaWinWasapiStream*)s;
/* suppress unused variable warnings */
stream->closeRequest = true;
//todo something MUCH better than this
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -