From 8ffcdad009e4d410f92fabc4e322a76a0be3a69d Mon Sep 17 00:00:00 2001 From: Daniel Rugerio <50124185+darugeri@users.noreply.github.com> Date: Fri, 28 Jun 2019 16:08:54 -0700 Subject: Update audio samples (#387) * Update SysVAD public sample. * Add WaveTest public sample. --- audio/tests/wavetest/PropertyHelper.cpp | 1095 +++++++++++++++++++++++++++++++ 1 file changed, 1095 insertions(+) create mode 100644 audio/tests/wavetest/PropertyHelper.cpp (limited to 'audio/tests/wavetest/PropertyHelper.cpp') diff --git a/audio/tests/wavetest/PropertyHelper.cpp b/audio/tests/wavetest/PropertyHelper.cpp new file mode 100644 index 00000000..fb60d3cc --- /dev/null +++ b/audio/tests/wavetest/PropertyHelper.cpp @@ -0,0 +1,1095 @@ +// ------------------------------------------------------------------------------ +// +// Copyright (C) Microsoft. All rights reserved. +// +// Module Name: +// +// EndpointPropertyHelpers.cpp +// +// Abstract: +// +// Implementation for common helpers of endpoint property +// +// ------------------------------------------------------------------------------- +#include "PreComp.h" +#include +#include +#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 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 spAudioFilter; + wil::com_ptr_nothrow spKsControl; + KSP_PIN pinProp; + ULONG cbNeeded = 0; + ULONG cbProperty; + PKSMULTIPLE_ITEM pProperty = NULL; + ULONG cbReturned = 0; + AUDIO_SIGNALPROCESSINGMODE* pModes = NULL; + CComHeapPtr 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(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 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 spAudioFilter; + wil::com_ptr_nothrow spAudioFilterTopology; + wil::com_ptr_nothrow spPart; + wil::com_ptr_nothrow 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(&KsWfex); + cbKsFormat = sizeof(KsWfex); + } + else + { + pKsFormat = reinterpret_cast(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; + } + + 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 spAudioFilter; + wil::com_ptr_nothrow spAudioFilterTopology; + wil::com_ptr_nothrow 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 spAudioFilter; + wil::com_ptr_nothrow 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; +} -- cgit v1.3.1