📄 pa_win_wasapi.cpp
字号:
goto error;
}
paWasapi->allocations = PaUtil_CreateAllocationGroup();
if( !paWasapi->allocations ){
result = paInsufficientMemory;
goto error;
}
*hostApi = &paWasapi->inheritedHostApiRep;
(*hostApi)->info.structVersion = 1;
(*hostApi)->info.type = paWASAPI;
(*hostApi)->info.name = "Windows WASAPI";
(*hostApi)->info.deviceCount = 0; //so far, we must investigate each
(*hostApi)->info.defaultInputDevice = paNoDevice; /* IMPLEMENT ME */
(*hostApi)->info.defaultOutputDevice = paNoDevice; /* IMPLEMENT ME */
HRESULT hResult = S_OK;
IMMDeviceCollection* spEndpoints=0;
paWasapi->enumerator = 0;
if (!setupAVRT()){
PRINT(("Windows WASAPI : No AVRT! (not VISTA?)"));
goto error;
}
hResult = CoCreateInstance(
__uuidof(MMDeviceEnumerator), NULL,CLSCTX_INPROC_SERVER,
__uuidof(IMMDeviceEnumerator),
(void**)&paWasapi->enumerator);
IF_FAILED_JUMP(hResult, error);
//getting default device ids in the eMultimedia "role"
{
{
IMMDevice* defaultRenderer=0;
hResult = paWasapi->enumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &defaultRenderer);
IF_FAILED_JUMP(hResult, error);
WCHAR* pszDeviceId = NULL;
hResult = defaultRenderer->GetId(&pszDeviceId);
IF_FAILED_JUMP(hResult, error);
StringCchCopyW(paWasapi->defaultRenderer, MAX_STR_LEN-1, pszDeviceId);
CoTaskMemFree(pszDeviceId);
defaultRenderer->Release();
}
{
IMMDevice* defaultCapturer=0;
hResult = paWasapi->enumerator->GetDefaultAudioEndpoint(eCapture, eMultimedia, &defaultCapturer);
IF_FAILED_JUMP(hResult, error);
WCHAR* pszDeviceId = NULL;
hResult = defaultCapturer->GetId(&pszDeviceId);
IF_FAILED_JUMP(hResult, error);
StringCchCopyW(paWasapi->defaultCapturer, MAX_STR_LEN-1, pszDeviceId);
CoTaskMemFree(pszDeviceId);
defaultCapturer->Release();
}
}
hResult = paWasapi->enumerator->EnumAudioEndpoints(eAll, DEVICE_STATE_ACTIVE, &spEndpoints);
IF_FAILED_JUMP(hResult, error);
hResult = spEndpoints->GetCount(&paWasapi->deviceCount);
IF_FAILED_JUMP(hResult, error);
paWasapi->devInfo = new PaWinWasapiDeviceInfo[paWasapi->deviceCount];
{
for (size_t step=0;step<paWasapi->deviceCount;++step)
memset(&paWasapi->devInfo[step],0,sizeof(PaWinWasapiDeviceInfo));
}
if( paWasapi->deviceCount > 0 )
{
(*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
paWasapi->allocations, sizeof(PaDeviceInfo*) * paWasapi->deviceCount );
if( !(*hostApi)->deviceInfos ){
result = paInsufficientMemory;
goto error;
}
/* allocate all device info structs in a contiguous block */
deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory(
paWasapi->allocations, sizeof(PaDeviceInfo) * paWasapi->deviceCount );
if( !deviceInfoArray ){
result = paInsufficientMemory;
goto error;
}
for( UINT i=0; i < paWasapi->deviceCount; ++i ){
PaDeviceInfo *deviceInfo = &deviceInfoArray[i];
deviceInfo->structVersion = 2;
deviceInfo->hostApi = hostApiIndex;
hResult = spEndpoints->Item(i, &paWasapi->devInfo[i].device);
IF_FAILED_JUMP(hResult, error);
//getting ID
{
WCHAR* pszDeviceId = NULL;
hResult = paWasapi->devInfo[i].device->GetId(&pszDeviceId);
IF_FAILED_JUMP(hResult, error);
StringCchCopyW(paWasapi->devInfo[i].szDeviceID, MAX_STR_LEN-1, pszDeviceId);
CoTaskMemFree(pszDeviceId);
if (lstrcmpW(paWasapi->devInfo[i].szDeviceID, paWasapi->defaultCapturer)==0){
//we found the default input!
(*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount;
}
if (lstrcmpW(paWasapi->devInfo[i].szDeviceID, paWasapi->defaultRenderer)==0){
//we found the default output!
(*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount;
}
}
DWORD state=0;
hResult = paWasapi->devInfo[i].device->GetState(&paWasapi->devInfo[i].state);
IF_FAILED_JUMP(hResult, error);
if (paWasapi->devInfo[i].state != DEVICE_STATE_ACTIVE){
PRINT(("WASAPI device:%d is not currently available (state:%d)\n",i,state));
//spDevice->Release();
//continue;
}
{
IPropertyStore* spProperties;
hResult = paWasapi->devInfo[i].device->OpenPropertyStore(STGM_READ, &spProperties);
IF_FAILED_JUMP(hResult, error);
//getting "Friendly" Name
{
PROPVARIANT value;
PropVariantInit(&value);
hResult = spProperties->GetValue(PKEY_Device_FriendlyName, &value);
IF_FAILED_JUMP(hResult, error);
deviceInfo->name = 0;
char* deviceName = (char*)PaUtil_GroupAllocateMemory( paWasapi->allocations, MAX_STR_LEN + 1 );
if( !deviceName ){
result = paInsufficientMemory;
goto error;
}
if (value.pwszVal)
wcstombs(deviceName, value.pwszVal,MAX_STR_LEN-1); //todo proper size
else{
sprintf(deviceName,"baddev%d",i);
}
deviceInfo->name = deviceName;
PropVariantClear(&value);
}
#if 0
DWORD numProps = 0;
hResult = spProperties->GetCount(&numProps);
IF_FAILED_JUMP(hResult, error);
{
for (DWORD i=0;i<numProps;++i){
PROPERTYKEY pkey;
hResult = spProperties->GetAt(i,&pkey);
PROPVARIANT value;
PropVariantInit(&value);
hResult = spProperties->GetValue(pkey, &value);
switch(value.vt){
case 11:
PRINT(("property*%u*\n",value.ulVal));
break;
case 19:
PRINT(("property*%d*\n",value.boolVal));
break;
case 31:
{
char temp[512];
wcstombs(temp, value.pwszVal,MAX_STR_LEN-1);
PRINT(("property*%s*\n",temp));
}
break;
default:break;
}
PropVariantClear(&value);
}
}
#endif
/* These look interresting... but they are undocumented
PKEY_AudioEndpoint_FormFactor
PKEY_AudioEndpoint_ControlPanelPageProvider
PKEY_AudioEndpoint_Association
PKEY_AudioEndpoint_PhysicalSpeakerConfig
PKEY_AudioEngine_DeviceFormat
*/
spProperties->Release();
}
//getting the Endpoint data
{
IMMEndpoint *endpoint=0;
hResult = paWasapi->devInfo[i].device->QueryInterface(__uuidof(IMMEndpoint),(void **)&endpoint);
if (SUCCEEDED(hResult)){
hResult = endpoint->GetDataFlow(&paWasapi->devInfo[i].flow);
endpoint->Release();
}
}
//Getting a temporary IAudioDevice for more fields
//we make sure NOT to call Initialize yet!
{
IAudioClient *myClient=0;
hResult = paWasapi->devInfo[i].device->Activate(__uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL, (void**)&myClient);
IF_FAILED_JUMP(hResult, error);
hResult = myClient->GetDevicePeriod(
&paWasapi->devInfo[i].DefaultDevicePeriod,
&paWasapi->devInfo[i].MinimumDevicePeriod);
IF_FAILED_JUMP(hResult, error);
hResult = myClient->GetMixFormat(&paWasapi->devInfo[i].MixFormat);
IF_FAILED_JUMP(hResult, error);
myClient->Release();
}
//we can now fill in portaudio device data
deviceInfo->maxInputChannels = 0; //for now
deviceInfo->maxOutputChannels = 0; //for now
switch(paWasapi->devInfo[i].flow){
case eRender:
//hum not exaclty maximum, more like "default"
deviceInfo->maxOutputChannels = paWasapi->devInfo[i].MixFormat->nChannels;
deviceInfo->defaultHighOutputLatency = nano100ToSeconds(paWasapi->devInfo[i].DefaultDevicePeriod);
deviceInfo->defaultLowOutputLatency = nano100ToSeconds(paWasapi->devInfo[i].MinimumDevicePeriod);
break;
case eCapture:
//hum not exaclty maximum, more like "default"
deviceInfo->maxInputChannels = paWasapi->devInfo[i].MixFormat->nChannels;
deviceInfo->defaultHighInputLatency = nano100ToSeconds(paWasapi->devInfo[i].DefaultDevicePeriod);
deviceInfo->defaultLowInputLatency = nano100ToSeconds(paWasapi->devInfo[i].MinimumDevicePeriod);
break;
default:
PRINT(("WASAPI device:%d bad Data FLow! \n",i));
goto error;
break;
}
deviceInfo->defaultSampleRate = (double)paWasapi->devInfo[i].MixFormat->nSamplesPerSec;
(*hostApi)->deviceInfos[i] = deviceInfo;
++(*hostApi)->info.deviceCount;
}
}
spEndpoints->Release();
(*hostApi)->Terminate = Terminate;
(*hostApi)->OpenStream = OpenStream;
(*hostApi)->IsFormatSupported = IsFormatSupported;
PaUtil_InitializeStreamInterface( &paWasapi->callbackStreamInterface, CloseStream, StartStream,
StopStream, AbortStream, IsStreamStopped, IsStreamActive,
GetStreamTime, GetStreamCpuLoad,
PaUtil_DummyRead, PaUtil_DummyWrite,
PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );
PaUtil_InitializeStreamInterface( &paWasapi->blockingStreamInterface, CloseStream, StartStream,
StopStream, AbortStream, IsStreamStopped, IsStreamActive,
GetStreamTime, PaUtil_DummyGetCpuLoad,
ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
return result;
error:
if (spEndpoints)
spEndpoints->Release();
if (paWasapi->enumerator)
paWasapi->enumerator->Release();
if( paWasapi )
{
if( paWasapi->allocations )
{
PaUtil_FreeAllAllocations( paWasapi->allocations );
PaUtil_DestroyAllocationGroup( paWasapi->allocations );
}
PaUtil_FreeMemory( paWasapi );
}
return result;
}
static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
{
PaWinWasapiHostApiRepresentation *paWasapi = (PaWinWasapiHostApiRepresentation*)hostApi;
paWasapi->enumerator->Release();
for (UINT i=0;i<paWasapi->deviceCount;++i){
PaWinWasapiDeviceInfo *info = &paWasapi->devInfo[i];
if (info->device)
info->device->Release();
if (info->MixFormat)
CoTaskMemFree(info->MixFormat);
}
delete [] paWasapi->devInfo;
CoUninitialize();
if( paWasapi->allocations ){
PaUtil_FreeAllAllocations( paWasapi->allocations );
PaUtil_DestroyAllocationGroup( paWasapi->allocations );
}
PaUtil_FreeMemory( paWasapi );
}
static void
LogWAVEFORMATEXTENSIBLE(const WAVEFORMATEXTENSIBLE &in){
const WAVEFORMATEX *old = (WAVEFORMATEX *)∈
switch (old->wFormatTag){
case WAVE_FORMAT_EXTENSIBLE:{
PRINT(("wFormatTag=WAVE_FORMAT_EXTENSIBLE\n"));
if (in.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT){
PRINT(("SubFormat=KSDATAFORMAT_SUBTYPE_IEEE_FLOAT\n"));
}
else if (in.SubFormat == KSDATAFORMAT_SUBTYPE_PCM){
PRINT(("SubFormat=KSDATAFORMAT_SUBTYPE_PCM\n"));
}
else{
PRINT(("SubFormat=CUSTOM GUID{%d:%d:%d:%d%d%d%d%d%d%d%d}\n",
in.SubFormat.Data1,
in.SubFormat.Data2,
in.SubFormat.Data3,
(int)in.SubFormat.Data4[0],
(int)in.SubFormat.Data4[1],
(int)in.SubFormat.Data4[2],
(int)in.SubFormat.Data4[3],
(int)in.SubFormat.Data4[4],
(int)in.SubFormat.Data4[5],
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -