diff options
Diffstat (limited to 'audio/tests/PinResourceHelpers/PropertyHelper.cpp')
| -rw-r--r-- | audio/tests/PinResourceHelpers/PropertyHelper.cpp | 1263 |
1 files changed, 1263 insertions, 0 deletions
diff --git a/audio/tests/PinResourceHelpers/PropertyHelper.cpp b/audio/tests/PinResourceHelpers/PropertyHelper.cpp new file mode 100644 index 00000000..6e85e53e --- /dev/null +++ b/audio/tests/PinResourceHelpers/PropertyHelper.cpp @@ -0,0 +1,1263 @@ +// ------------------------------------------------------------------------------ +// +// Copyright (C) Microsoft. All rights reserved. +// +// Module Name: +// +// PropertyHelper.cpp +// +// Abstract: +// +// Implementation for common helpers of endpoint property +// +// ------------------------------------------------------------------------------- +#include "PreComp.h" +#include <AVEndpointKeys.h> +#include <Functiondiscoverykeys_devpkey.h> +#include <devpkey.h> +#include <PropertyHelper.h> + +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// GetConnectorId +// +// Retrieve the connector id from the property store and checks if the connector exists +// +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +HRESULT GetConnectorId +( + IMMDevice* pDevice, + EndpointConnectorType eConnectorType, + bool* hasConnector, + UINT* pConnectorId +) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// GetEndpointFriendlyName +// +// Retrieve the endpoint friendly name from the property store +// +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +HRESULT GetEndpointFriendlyName +( + IMMDevice* pDevice, + LPWSTR* ppwszEndpointName +) +{ + HRESULT hr = S_OK; + wil::com_ptr_nothrow<IPropertyStore> spPropertyStore; + wil::unique_prop_variant var; + wil::unique_cotaskmem_string pwszName; + + *ppwszEndpointName = NULL; + + // Retrieve the endpoint friendly name from the propertey store + if (!VERIFY_SUCCEEDED(hr = pDevice->OpenPropertyStore(STGM_READ, &spPropertyStore))) { + return hr; + } + if (!VERIFY_SUCCEEDED(hr = spPropertyStore->GetValue(PKEY_Device_FriendlyName, &var))) { + return hr; + } + if (!VERIFY_IS_TRUE(var.vt == VT_LPWSTR)) { + hr = E_FAIL; + return hr; + } + + pwszName = wil::make_cotaskmem_string_nothrow(var.pwszVal); + if (!VERIFY_IS_TRUE(pwszName.get() && wcslen(pwszName.get()) != 0)) { + hr = E_FAIL; + return hr; + } + + *ppwszEndpointName = pwszName.release(); + + return hr; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// GetAudioFilterAsDevice +// +// Get the audio filter from MMDevice. This method is called to activate IKsControl, IKsFormatSupport or IKsGetProposedFormat. +// +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +HRESULT GetAudioFilterAsDevice +( + IMMDevice* pDevice, + IMMDevice** ppAudioFilterAsDevice +) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// GetCachedProcessingModes +// +// Read the processing mode characteristics from the property store and get all processing modes. This method applies to host and keyword detector pins only. +// +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +HRESULT GetCachedProcessingModes +( + IMMDevice* pDevice, + EndpointConnectorType eConnectorType, + ULONG *pCount, + AUDIO_SIGNALPROCESSINGMODE **ppModes +) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// GetProcessingModes +// +// Query for connector's processing modes property +// +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +HRESULT GetProcessingModes +( + IMMDevice* pDevice, + UINT pinId, + ULONG *pCount, + AUDIO_SIGNALPROCESSINGMODE **ppModes +) +{ + HRESULT hr = S_OK; + wil::com_ptr_nothrow<IMMDevice> spAudioFilter; + wil::com_ptr_nothrow<IKsControl> spKsControl; + KSP_PIN pinProp; + ULONG cbNeeded = 0; + ULONG cbProperty; + PKSMULTIPLE_ITEM pProperty = NULL; + ULONG cbReturned = 0; + AUDIO_SIGNALPROCESSINGMODE* pModes = NULL; + CComHeapPtr<AUDIO_SIGNALPROCESSINGMODE> spModes; + + *pCount = 0; + *ppModes = NULL; + + // Get the audio filter + if (!VERIFY_SUCCEEDED(hr = GetAudioFilterAsDevice(pDevice, &spAudioFilter))) { + return hr; + } + + // Activate IKsControl + if (!VERIFY_SUCCEEDED(hr = spAudioFilter->Activate(__uuidof(IKsControl), CLSCTX_ALL, NULL, (VOID**)&spKsControl))) { + return hr; + } + + // Read the audio signal processing mode property + pinProp.Property.Set = KSPROPSETID_AudioSignalProcessing; + pinProp.Property.Id = KSPROPERTY_AUDIOSIGNALPROCESSING_MODES; + pinProp.Property.Flags = KSPROPERTY_TYPE_GET; + pinProp.PinId = pinId & PARTID_MASK; + pinProp.Reserved = 0; + + // Determined the needed size + if (!VERIFY_SUCCEEDED(hr = spKsControl->KsProperty(&pinProp.Property, sizeof(KSP_PIN), NULL, 0, &cbNeeded))) { + return hr; + } + if (!VERIFY_IS_TRUE(cbNeeded > 0) || !VERIFY_IS_TRUE((cbNeeded - sizeof(KSMULTIPLE_ITEM)) % sizeof(GUID) == 0)) { + hr = E_NOTFOUND; + return hr; + } + + cbProperty = cbNeeded; + pProperty = (PKSMULTIPLE_ITEM)CoTaskMemAlloc(cbNeeded); + + if (!VERIFY_IS_NOT_NULL(pProperty)) { + hr = E_OUTOFMEMORY; + cbProperty = 0; + return hr; + } + + // Query the processing mode property + if (!VERIFY_SUCCEEDED(hr = spKsControl->KsProperty(&pinProp.Property, sizeof(KSP_PIN), pProperty, cbNeeded, &cbReturned))) { + goto Exit; + } + + if (!VERIFY_IS_NOT_NULL(pProperty)) { + hr = E_NOTFOUND; + goto Exit; + } + + if (!VERIFY_IS_TRUE(cbProperty >= (sizeof(KSMULTIPLE_ITEM) + pProperty->Count * sizeof(GUID)))) { + hr = E_NOTFOUND; + goto Exit; + } + + pModes = reinterpret_cast<GUID*>(pProperty + 1); + + if (!VERIFY_IS_TRUE(spModes.Allocate(pProperty->Count))) + { + hr = E_OUTOFMEMORY; + goto Exit; + } + + memcpy(spModes, pModes, sizeof(AUDIO_SIGNALPROCESSINGMODE)*(pProperty->Count)); + + *pCount = pProperty->Count; + *ppModes = spModes.Detach(); + +Exit: + if (pProperty != NULL) { + CoTaskMemFree(pProperty); + } + cbProperty = 0; + + return hr; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// GetCachedSupportedFormatRecords +// +// Read the processing mode characteristics from the property store and get all supported formats for processing mode. This method applies to host and keyword detector pins only. +// +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +HRESULT GetCachedSupportedFormatRecords +( + IMMDevice* pDevice, + EndpointConnectorType eConnectorType, + AUDIO_SIGNALPROCESSINGMODE mode, + ULONG *pCount, + FORMAT_RECORD **ppFormatRecords +) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// GetSupportedFormatRecords +// +// For pins do not have cached supported formats information, such as offload pin, we provide our predefined format list and check whether each is supported by the pin. +// +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +HRESULT GetSupportedFormatRecords +( + IMMDevice* pDevice, + UINT pinId, + EndpointConnectorType eConnectorType, + AUDIO_SIGNALPROCESSINGMODE mode, + STACKWISE_DATAFLOW dataFlow, + ULONG *pCount, + FORMAT_RECORD **ppFormatRecords +) +{ + HRESULT hr = S_OK; + FORMAT_RECORD *pFormatRecords; + UINT cFormatRecords = 0; + CComHeapPtr<FORMAT_RECORD> spFormatRecords; + BOOL isSupported = false; + WAVEFORMATEX *pWfx; + UINT32 u32DefaultPeriodicityInFrames = 0; + UINT32 u32FundamentalPeriodicityInFrames = 0; + UINT32 u32MinPeriodicityInFrames = 0; + UINT32 u32MaxPeriodicityInFrames = 0; + UINT32 u32MaxPeriodicityInFramesExtended = 0; + + // Init return + *pCount = 0; + *ppFormatRecords = NULL; + + pFormatRecords = new FORMAT_RECORD[COUNT_FORMATS]; + if (!VERIFY_IS_NOT_NULL(pFormatRecords)) { + hr = E_OUTOFMEMORY; + return hr; + } + memset(pFormatRecords, 0, sizeof(FORMAT_RECORD)*COUNT_FORMATS); + + for (ULONG i = 0; i < COUNT_FORMATS; i++) { + pWfx = (WAVEFORMATEX*)&ListofFormats[i]; + + // Check if format is supported + if (!VERIFY_SUCCEEDED(hr = IsFormatSupported(pDevice, pinId, pWfx, &isSupported))) { + return hr; + } + + // If the format is supported, we discover the periodicity characteristics for the format and store them along with the format in our FORMAT_RECORD struct. + if (isSupported) { + if (!VERIFY_SUCCEEDED(hr = DiscoverPeriodicityCharacteristicsForFormat(pDevice, eConnectorType, mode, pWfx, dataFlow, &u32DefaultPeriodicityInFrames, &u32FundamentalPeriodicityInFrames, &u32MinPeriodicityInFrames, &u32MaxPeriodicityInFrames, &u32MaxPeriodicityInFramesExtended))) { + return hr; + } + + pFormatRecords[cFormatRecords].defaultPeriodInFrames = u32DefaultPeriodicityInFrames; + pFormatRecords[cFormatRecords].fundamentalPeriodInFrames = u32FundamentalPeriodicityInFrames; + pFormatRecords[cFormatRecords].minPeriodInFrames = u32MinPeriodicityInFrames; + pFormatRecords[cFormatRecords].maxPeriodInFrames = u32MaxPeriodicityInFrames; + pFormatRecords[cFormatRecords].maxPeriodInFramesExtended = u32MaxPeriodicityInFramesExtended; + memcpy(&pFormatRecords[cFormatRecords].wfxEx, &ListofFormats[i], sizeof(WAVEFORMATEX) + ListofFormats[i].Format.cbSize); + cFormatRecords++; + } + } + + if (!VERIFY_IS_TRUE(spFormatRecords.Allocate(cFormatRecords))) { + hr = E_OUTOFMEMORY; + return hr; + } + + memcpy(spFormatRecords, pFormatRecords, sizeof(FORMAT_RECORD)*cFormatRecords); + delete[] pFormatRecords; + + *pCount = cFormatRecords; + *ppFormatRecords = spFormatRecords.Detach(); + + return hr; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// IsFormatSupported +// +// Wrap up the IKsFormatSupport::IsFormatSupported method. +// +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +HRESULT IsFormatSupported +( + IMMDevice* pDevice, + UINT pinId, + WAVEFORMATEX *pWfx, + BOOL* pbSupported +) +{ + HRESULT hr = S_OK; + wil::com_ptr_nothrow<IMMDevice> spAudioFilter; + wil::com_ptr_nothrow<IDeviceTopology> spAudioFilterTopology; + wil::com_ptr_nothrow<IPart> spPart; + wil::com_ptr_nothrow<IKsFormatSupport> spFormatSupport; + PKSDATAFORMAT_WAVEFORMATEXTENSIBLE pKsRequestedFormat = NULL; + PKSDATAFORMAT pKsFormat = NULL; + KSDATAFORMAT_WAVEFORMATEXTENSIBLE KsWfex = {}; + DWORD cbKsFormat = 0; + + // Init return + *pbSupported = FALSE; + + // Get the audio filter + if (!VERIFY_SUCCEEDED(hr = GetAudioFilterAsDevice(pDevice, &spAudioFilter))) { + return hr; + } + + // Activate an IDeviceTopology on the filter + if (!VERIFY_SUCCEEDED(hr = spAudioFilter->Activate(__uuidof(IDeviceTopology), CLSCTX_ALL, NULL, (void**)&spAudioFilterTopology))) { + return hr; + } + + // Get the connector + if (!VERIFY_SUCCEEDED(hr = spAudioFilterTopology->GetPartById(pinId, &spPart))) { + return hr; + } + + // Activate IKsFormatSupport interface + if (!VERIFY_SUCCEEDED(hr = spPart->Activate(CLSCTX_ALL, __uuidof(IKsFormatSupport), (void**)&spFormatSupport))) { + return hr; + } + + // Convert to KSDATAFORMAT_WAVEFORMATEX + if (!VERIFY_SUCCEEDED(hr = CreateKSFormatFromWFXFormat(pWfx, (KSDATAFORMAT_WAVEFORMATEX**)&pKsRequestedFormat))) { + return hr; + } + + if (pKsRequestedFormat->DataFormat.FormatSize < sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE)) + { + memcpy(&KsWfex, pKsRequestedFormat, pKsRequestedFormat->DataFormat.FormatSize); + pKsFormat = reinterpret_cast<KSDATAFORMAT *>(&KsWfex); + cbKsFormat = sizeof(KsWfex); + } + else + { + pKsFormat = reinterpret_cast<KSDATAFORMAT *>(pKsRequestedFormat); + cbKsFormat = pKsRequestedFormat->DataFormat.FormatSize; + } + + // Expect that pbFormat is really a KSDATAFORMAT + if (!VERIFY_IS_TRUE(cbKsFormat >= sizeof(KSDATAFORMAT))) { + hr = E_INVALIDARG; + return hr; + } + + // validate return pointers (this is an externally callable method) + if (!VERIFY_IS_TRUE(pKsFormat)) { + hr = E_POINTER; + return hr; + } + + if (!VERIFY_SUCCEEDED(hr = spFormatSupport->IsFormatSupported(pKsFormat, cbKsFormat, pbSupported))) { + return hr; + } + + CoTaskMemFree(pKsRequestedFormat); + + return hr; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// DiscoverPeriodicityCharacteristicsForFormat +// +// Discover the periodicity characteristics for given format. +// +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +HRESULT DiscoverPeriodicityCharacteristicsForFormat +( + IMMDevice* pDevice, + EndpointConnectorType eConnectorType, + AUDIO_SIGNALPROCESSINGMODE mode, + WAVEFORMATEX *pWfx, + STACKWISE_DATAFLOW dataFlow, + UINT32 *pDefaultPeriodicityInFrames, + UINT32 *pFundamentalPeriodicityInFrames, + UINT32 *pMinPeriodicityInFrames, + UINT32 *pMaxPeriodicityInFrames, + UINT32 *pMaxPeriodicityInFramesExtended +) +{ + HRESULT hr = S_OK; + HNSTIME hnsDefaultPeriod = kSystemDefaultPeriod; + UINT32 ActualPeriodicityInFrames; + + // Verify format is not null + if (!VERIFY_IS_NOT_NULL(pWfx)) { + hr = E_INVALIDARG; + return hr; + } + + *pDefaultPeriodicityInFrames = + *pFundamentalPeriodicityInFrames = + *pMinPeriodicityInFrames = + *pMaxPeriodicityInFrames = HNSTIME_TO_FRAMES_DOUBLE(hnsDefaultPeriod, pWfx->nSamplesPerSec); + + // Check to see whether the endpoint supports the default periodicity and return the actual periodicity + if (!VERIFY_SUCCEEDED(hr = CheckConnectorSupportForPeriodicity(pDevice, eConnectorType, mode, pWfx, dataFlow, hnsDefaultPeriod, &ActualPeriodicityInFrames))) { + return hr; + } + + // Use what we get as the default, max, min and fundamental periodicity + *pDefaultPeriodicityInFrames = + *pFundamentalPeriodicityInFrames = + *pMinPeriodicityInFrames = + *pMaxPeriodicityInFrames = ActualPeriodicityInFrames; + + // Max periodicity is capped to the default periodicity for all clients except extended periodicity clients + *pMaxPeriodicityInFramesExtended = *pMaxPeriodicityInFrames; + if (*pMaxPeriodicityInFrames > *pDefaultPeriodicityInFrames) + { + *pMaxPeriodicityInFrames = *pDefaultPeriodicityInFrames; + } + + return hr; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// CheckConnectorSupportForPeriodicity +// +// Check to see if the connector supports the specified periodicity and return the actual periodicity. +// +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +HRESULT CheckConnectorSupportForPeriodicity +( + IMMDevice* pDevice, + EndpointConnectorType eConnectorType, + AUDIO_SIGNALPROCESSINGMODE mode, + WAVEFORMATEX *pWfx, + STACKWISE_DATAFLOW dataFlow, + HNSTIME RequestedPeriodicity, + UINT32 *pActualPeriodicityInFrames +) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// GetCachedDefaultFormat +// +// Read the default device format from the property store. Use audio engine device format for all other pin types. For Keyword Detector pin, it has a different default device format. +// +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +HRESULT GetCachedDefaultFormat +( + IMMDevice* pDevice, + EndpointConnectorType eConnectorType, + WAVEFORMATEX** ppDefaultFormat +) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// GetProposedFormatForProcessingMode +// +// Wrap up the IKsGetProposedFormat::GetProposedFormatForMode method. +// +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +HRESULT GetProposedFormatForProcessingMode +( + IMMDevice* pDevice, + UINT pinId, + AUDIO_SIGNALPROCESSINGMODE mode, + WAVEFORMATEX **ppProposedFormat +) +{ + HRESULT hr = S_OK; + wil::com_ptr_nothrow<IMMDevice> spAudioFilter; + wil::com_ptr_nothrow<IDeviceTopology> spAudioFilterTopology; + wil::com_ptr_nothrow<IPart> spPart; + + + + PKSDATAFORMAT pKsProposedFormat = NULL; + WAVEFORMATEXTENSIBLE* pWfxEx = NULL; + + // Init return + *ppProposedFormat = NULL; + + if (!VERIFY_SUCCEEDED(hr = GetAudioFilterAsDevice(pDevice, &spAudioFilter))) { + return hr; + } + + // Activate an IDeviceTopology on the filter + if (!VERIFY_SUCCEEDED(hr = spAudioFilter->Activate(__uuidof(IDeviceTopology), CLSCTX_ALL, NULL, (void**)&spAudioFilterTopology))) { + return hr; + } + + // Get the connector + if (!VERIFY_SUCCEEDED(hr = spAudioFilterTopology->GetPartById(pinId, &spPart))) { + return hr; + } + + // Retrieve the proposed format for a specific processing mode and store it in pKsProposedFormat... + + + + + + + + + + + + + // Allocate memory for ppOffloadDefaultFormat and copy pKsDataDeviceFormat to ppOffloadDefaultFormat + pWfxEx = (WAVEFORMATEXTENSIBLE *)CoTaskMemAlloc(sizeof(WAVEFORMATEX) + ((PKSDATAFORMAT_WAVEFORMATEX)pKsProposedFormat)->WaveFormatEx.cbSize); + if (!VERIFY_IS_NOT_NULL(pWfxEx)) { + CoTaskMemFree(pKsProposedFormat); + hr = E_OUTOFMEMORY; + return hr; + } + memcpy(pWfxEx, &(((PKSDATAFORMAT_WAVEFORMATEX)pKsProposedFormat)->WaveFormatEx), sizeof(WAVEFORMATEX) + ((PKSDATAFORMAT_WAVEFORMATEX)pKsProposedFormat)->WaveFormatEx.cbSize); + *ppProposedFormat = (WAVEFORMATEX*)pWfxEx; + + return hr; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// GetCurrentAvailiablePinInstanceCount +// +// Query for the connector's pin instance count property. +// +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +HRESULT GetAvailiablePinInstanceCount +( + IMMDevice* pDevice, + UINT pinId, + UINT32* pAvailablePinInstanceCount +) +{ + HRESULT hr = S_OK; + wil::com_ptr_nothrow<IMMDevice> spAudioFilter; + wil::com_ptr_nothrow<IKsControl> spKsControl; + KSP_PIN pinProp; + KSPIN_CINSTANCES pinInstances; + ULONG cbReturned = 0; + + *pAvailablePinInstanceCount = 0; + + if (!VERIFY_SUCCEEDED(hr = GetAudioFilterAsDevice(pDevice, &spAudioFilter))) { + return hr; + } + + if (!VERIFY_SUCCEEDED(hr = spAudioFilter->Activate(__uuidof(IKsControl), CLSCTX_ALL, NULL, (VOID**)&spKsControl))) { + return hr; + } + + // Read the pin instance count + pinProp.Property.Set = KSPROPSETID_Pin; + pinProp.Property.Id = KSPROPERTY_PIN_CINSTANCES; + pinProp.Property.Flags = KSPROPERTY_TYPE_GET; + pinProp.PinId = pinId & PARTID_MASK; + pinProp.Reserved = 0; + + if (!VERIFY_SUCCEEDED(hr = spKsControl->KsProperty(&pinProp.Property, sizeof(KSP_PIN), &pinInstances, sizeof(KSPIN_CINSTANCES), &cbReturned))) { + return hr; + } + + *pAvailablePinInstanceCount = pinInstances.PossibleCount - pinInstances.CurrentCount; + + return hr; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// IsAVStream +// +// Check if audio device is AVStream +// +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +HRESULT IsAVStream +( + IMMDevice* pDevice, + bool* pIsAVStream +) +{ + HRESULT hr = S_OK; + wil::com_ptr_nothrow<IMMDevice> spDevnodeDevice; + wil::com_ptr_nothrow<IPropertyStore> spPnpProperties; + wil::unique_prop_variant varDeviceService; + + *pIsAVStream = false; + + // Find the associated PnP device + if (!VERIFY_SUCCEEDED(hr = GetPnpDevnodeFromMMDevice(pDevice, &spDevnodeDevice))) { + return hr; + } + + // Open pnp device property store + if (!VERIFY_SUCCEEDED(hr = spDevnodeDevice->OpenPropertyStore(STGM_READ, &spPnpProperties))) { + return hr; + } + + // Read the DEVPKEY_Device_Service + if (!VERIFY_SUCCEEDED(hr = spPnpProperties->GetValue((REFPROPERTYKEY)DEVPKEY_Device_Service, &varDeviceService))) { + return hr; + } + + if (!VERIFY_IS_TRUE(varDeviceService.vt == VT_LPWSTR && varDeviceService.pwszVal != nullptr)) { + hr = E_FAIL; + return hr; + } + + if (0 == _wcsicmp(varDeviceService.pwszVal, L"usbaudio") || 0 == _wcsicmp(varDeviceService.pwszVal, L"BthHFAud") || 0 == _wcsicmp(varDeviceService.pwszVal, L"BthA2dp")) { + *pIsAVStream = true; + } + + return hr; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// IsBluetooth +// +// Check if audio device is Bluetooth +// +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +HRESULT IsBluetooth +( + IMMDevice* pDevice, + bool* pIsBluetooth +) +{ + HRESULT hr = S_OK; + wil::com_ptr_nothrow<IPropertyStore> spPropertyStore; + wil::unique_prop_variant varIsBluetooth; + + *pIsBluetooth = false; + + // Open pnp device property store + if (!VERIFY_SUCCEEDED(hr = pDevice->OpenPropertyStore(STGM_READ, &spPropertyStore))) { + return hr; + } + + // Read the PKEY_Endpoint_IsBluetooth + hr = spPropertyStore->GetValue((REFPROPERTYKEY)PKEY_Endpoint_IsBluetooth, &varIsBluetooth); + if (hr != S_OK) { + return hr; + } + + if (varIsBluetooth.vt == VT_BOOL) + { + *pIsBluetooth = varIsBluetooth.boolVal == VARIANT_TRUE ? true : false; + } + + return hr; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// IsSideband +// +// Check if audio device is side band +// +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +HRESULT IsSideband +( + IMMDevice* pDevice, + bool* pIsSideband +) +{ + HRESULT hr = S_OK; + wil::com_ptr_nothrow<IPropertyStore> spPropertyStore; + wil::unique_prop_variant varIsSideband; + + *pIsSideband = false; + + // Open pnp device property store + if (!VERIFY_SUCCEEDED(hr = pDevice->OpenPropertyStore(STGM_READ, &spPropertyStore))) { + return hr; + } + + // Read the PKEY_Endpoint_IsBluetooth + hr = spPropertyStore->GetValue((REFPROPERTYKEY)PKEY_Endpoint_IsSideband, &varIsSideband); + if (hr != S_OK) { + return hr; + } + + if (varIsSideband.vt == VT_BOOL) + { + *pIsSideband = varIsSideband.boolVal == VARIANT_TRUE ? true : false; + } + + return hr; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// GetPnpDevnodeFromMMDeivce +// +// Get pnp devnode from mm device +// +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +HRESULT GetPnpDevnodeFromMMDevice +( + IMMDevice* pDevice, + IMMDevice** pDevnodeDevice +) +{ + HRESULT hr = S_OK; + wil::com_ptr_nothrow<IMMDeviceEnumerator> spEnumerator; + wil::com_ptr_nothrow<IPropertyStore> spProps; + wil::com_ptr_nothrow<IMMDevice> spDevnodeAsDevice; + wil::com_ptr_nothrow<IPropertyStore> spDevnodeProps; + wil::unique_prop_variant varDevnode; + + // Create an enumerator + if (!VERIFY_SUCCEEDED(hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void **)&spEnumerator))) { + return hr; + } + + // Read the PKEY_Endpoint_Devnode + if (!VERIFY_SUCCEEDED(hr = pDevice->OpenPropertyStore(STGM_READ, &spProps))) { + return hr; + } + if (!VERIFY_SUCCEEDED(hr = spProps->GetValue(PKEY_Endpoint_Devnode, &varDevnode))) { + return hr; + } + + // Get the devnode as an IMMDevice + if (!VERIFY_SUCCEEDED(hr = spEnumerator->GetDevice(varDevnode.pwszVal, &spDevnodeAsDevice))) { + return hr; + } + *pDevnodeDevice = spDevnodeAsDevice.detach(); + + return hr; +} |
