📄 pa_win_wasapi.cpp
字号:
(int)in.SubFormat.Data4[6],
(int)in.SubFormat.Data4[7]));
}
PRINT(("Samples.wValidBitsPerSample=%d\n", in.Samples.wValidBitsPerSample));
PRINT(("dwChannelMask=0x%X\n",in.dwChannelMask));
}break;
case WAVE_FORMAT_PCM: PRINT(("wFormatTag=WAVE_FORMAT_PCM\n")); break;
case WAVE_FORMAT_IEEE_FLOAT: PRINT(("wFormatTag=WAVE_FORMAT_IEEE_FLOAT\n")); break;
default : PRINT(("wFormatTag=UNKNOWN(%d)\n",old->wFormatTag)); break;
}
PRINT(("nChannels =%d\n",old->nChannels));
PRINT(("nSamplesPerSec =%d\n",old->nSamplesPerSec));
PRINT(("nAvgBytesPerSec=%d\n",old->nAvgBytesPerSec));
PRINT(("nBlockAlign =%d\n",old->nBlockAlign));
PRINT(("wBitsPerSample =%d\n",old->wBitsPerSample));
PRINT(("cbSize =%d\n",old->cbSize));
}
/*
WAVEFORMATXXX is always interleaved
*/
static PaSampleFormat
waveformatToPaFormat(const WAVEFORMATEXTENSIBLE &in){
const WAVEFORMATEX *old = (WAVEFORMATEX *)∈
switch (old->wFormatTag){
case WAVE_FORMAT_EXTENSIBLE:
{
if (in.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT){
if (in.Samples.wValidBitsPerSample == 32)
return paFloat32;
else
return paCustomFormat;
}
else if (in.SubFormat == KSDATAFORMAT_SUBTYPE_PCM){
switch (old->wBitsPerSample){
case 32: return paInt32; break;
case 24: return paInt24;break;
case 8: return paUInt8;break;
case 16: return paInt16;break;
default: return paCustomFormat;break;
}
}
else
return paCustomFormat;
}
break;
case WAVE_FORMAT_IEEE_FLOAT:
return paFloat32;
break;
case WAVE_FORMAT_PCM:
{
switch (old->wBitsPerSample){
case 32: return paInt32; break;
case 24: return paInt24;break;
case 8: return paUInt8;break;
case 16: return paInt16;break;
default: return paCustomFormat;break;
}
}
break;
default:
return paCustomFormat;
break;
}
return paCustomFormat;
}
static PaError
waveformatFromParams(WAVEFORMATEXTENSIBLE &wav,
const PaStreamParameters * params,
double sampleRate){
size_t bytesPerSample = 0;
switch( params->sampleFormat & ~paNonInterleaved ){
case paFloat32:
case paInt32: bytesPerSample=4;break;
case paInt16: bytesPerSample=2;break;
case paInt24: bytesPerSample=3;break;
case paInt8:
case paUInt8: bytesPerSample=1;break;
case paCustomFormat:
default: return paSampleFormatNotSupported;break;
}
memset(&wav,0,sizeof(WAVEFORMATEXTENSIBLE));
WAVEFORMATEX *old = (WAVEFORMATEX *)&wav;
old->nChannels = (WORD)params->channelCount;
old->nSamplesPerSec = (DWORD)sampleRate;
old->wBitsPerSample = bytesPerSample*8;
old->nAvgBytesPerSec = old->nSamplesPerSec * old->nChannels * bytesPerSample;
old->nBlockAlign = (WORD)(old->nChannels * bytesPerSample);
//WAVEFORMATEX
if (params->channelCount <=2 && (bytesPerSample == 2 || bytesPerSample == 1)){
old->cbSize = 0;
old->wFormatTag = WAVE_FORMAT_PCM;
}
//WAVEFORMATEXTENSIBLE
else{
old->wFormatTag = WAVE_FORMAT_EXTENSIBLE;
old->cbSize = sizeof (WAVEFORMATEXTENSIBLE) - sizeof (WAVEFORMATEX);
if ((params->sampleFormat & ~paNonInterleaved) == paFloat32)
wav.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
else
wav.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
wav.Samples.wValidBitsPerSample = old->wBitsPerSample; //no extra padding!
switch(params->channelCount){
case 1: wav.dwChannelMask = SPEAKER_FRONT_CENTER; break;
case 2: wav.dwChannelMask = 0x1 | 0x2; break;
case 4: wav.dwChannelMask = 0x1 | 0x2 | 0x10 | 0x20; break;
case 6: wav.dwChannelMask = 0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20; break;
case 8: wav.dwChannelMask = 0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20 | 0x40 | 0x80; break;
default: wav.dwChannelMask = 0; break;
}
}
return paNoError;
}
enum PaWasapiFormatAnswer {PWFA_OK,PWFA_NO,PWFA_SUGGESTED};
static PaWasapiFormatAnswer
IsFormatSupportedInternal(IAudioClient * myClient, WAVEFORMATEXTENSIBLE &wavex){
PaWasapiFormatAnswer answer = PWFA_OK;
WAVEFORMATEX *closestMatch=0;
HRESULT hResult = myClient->IsFormatSupported(
//AUDCLNT_SHAREMODE_EXCLUSIVE,
AUDCLNT_SHAREMODE_SHARED,
(WAVEFORMATEX*)&wavex,&closestMatch);
if (hResult == S_OK)
answer = PWFA_OK;
else if (closestMatch){
WAVEFORMATEXTENSIBLE* ext = (WAVEFORMATEXTENSIBLE*)closestMatch;
if (closestMatch->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
memcpy(&wavex,closestMatch,sizeof(WAVEFORMATEXTENSIBLE));
else
memcpy(&wavex,closestMatch,sizeof(WAVEFORMATEX));
CoTaskMemFree(closestMatch);
answer = PWFA_SUGGESTED;
}else if (hResult != S_OK){
logAUDCLNT_E(hResult);
answer = PWFA_NO;
}
return answer;
}
static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
const PaStreamParameters *inputParameters,
const PaStreamParameters *outputParameters,
double sampleRate )
{
int inputChannelCount, outputChannelCount;
PaSampleFormat inputSampleFormat, outputSampleFormat;
if( inputParameters )
{
inputChannelCount = inputParameters->channelCount;
inputSampleFormat = inputParameters->sampleFormat;
/* all standard sample formats are supported by the buffer adapter,
this implementation doesn't support any custom sample formats */
if( inputSampleFormat & paCustomFormat )
return paSampleFormatNotSupported;
/* 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 inputStreamInfo */
if( inputParameters->hostApiSpecificStreamInfo )
return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
PaWinWasapiHostApiRepresentation *paWasapi = (PaWinWasapiHostApiRepresentation*)hostApi;
WAVEFORMATEXTENSIBLE wavex;
waveformatFromParams(wavex,inputParameters,sampleRate);
IAudioClient *myClient=0;
HRESULT hResult = paWasapi->devInfo[inputParameters->device].device->Activate(
__uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL, (void**)&myClient);
if (hResult != S_OK){
logAUDCLNT_E(hResult);
return paInvalidDevice;
}
PaWasapiFormatAnswer answer = IsFormatSupportedInternal(myClient,wavex);
myClient->Release();
switch (answer){
case PWFA_OK: break;
case PWFA_NO: return paSampleFormatNotSupported;
case PWFA_SUGGESTED:
{
PRINT(("Suggested format:"));
LogWAVEFORMATEXTENSIBLE(wavex);
if (wavex.Format.nSamplesPerSec == (DWORD)sampleRate){
//no problem its a format issue only
}
else{
return paInvalidSampleRate;
}
}
}
}
else
{
inputChannelCount = 0;
}
if( outputParameters )
{
outputChannelCount = outputParameters->channelCount;
outputSampleFormat = outputParameters->sampleFormat;
/* all standard sample formats are supported by the buffer adapter,
this implementation doesn't support any custom sample formats */
if( outputSampleFormat & paCustomFormat )
return paSampleFormatNotSupported;
/* unless alternate device specification is supported, reject the use of
paUseHostApiSpecificDeviceSpecification */
if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
return paInvalidDevice;
/* check that output device can support outputChannelCount */
if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
return paInvalidChannelCount;
/* validate outputStreamInfo */
if( outputParameters->hostApiSpecificStreamInfo )
return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
PaWinWasapiHostApiRepresentation *paWasapi = (PaWinWasapiHostApiRepresentation*)hostApi;
WAVEFORMATEXTENSIBLE wavex;
waveformatFromParams(wavex,outputParameters,sampleRate);
IAudioClient *myClient=0;
HRESULT hResult = paWasapi->devInfo[outputParameters->device].device->Activate(
__uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL, (void**)&myClient);
if (hResult != S_OK){
logAUDCLNT_E(hResult);
return paInvalidDevice;
}
PaWasapiFormatAnswer answer = IsFormatSupportedInternal(myClient,wavex);
myClient->Release();
switch (answer){
case PWFA_OK: break;
case PWFA_NO: return paSampleFormatNotSupported;
case PWFA_SUGGESTED:
{
PRINT(("Suggested format:"));
LogWAVEFORMATEXTENSIBLE(wavex);
if (wavex.Format.nSamplesPerSec == (DWORD)sampleRate){
//no problem its a format issue only
}
else{
return paInvalidSampleRate;
}
}
}
}
else
{
outputChannelCount = 0;
}
return paFormatIsSupported;
}
/* 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;
PaWinWasapiHostApiRepresentation *paWasapi = (PaWinWasapiHostApiRepresentation*)hostApi;
PaWinWasapiStream *stream = 0;
int inputChannelCount, outputChannelCount;
PaSampleFormat inputSampleFormat, outputSampleFormat;
PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
stream = (PaWinWasapiStream*)PaUtil_AllocateMemory( sizeof(PaWinWasapiStream) );
if( !stream ){
result = paInsufficientMemory;
goto error;
}
if( inputParameters )
{
inputChannelCount = inputParameters->channelCount;
inputSampleFormat = inputParameters->sampleFormat;
/* 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 inputStreamInfo */
if( inputParameters->hostApiSpecificStreamInfo )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -