From bf0b0fe11d8b301cdfcc6d13f12a778cdd1c14b5 Mon Sep 17 00:00:00 2001
From: Daniel Rugerio <50124185+darugeri@users.noreply.github.com>
Date: Wed, 13 May 2020 16:23:40 -0700
Subject: Update to SysVAD, Wave test and public sample of KS Position Test
(#496)
* Update to Wave test and public sample of KS Position test.
* Update to the SysVAD audio driver sample.
* Add the PnpLockDown property.
---
audio/sysvad/EndpointsCommon/mintopo.cpp | 2 +-
audio/sysvad/EndpointsCommon/mintopo.h | 14 +-
audio/sysvad/EndpointsCommon/minwavertstream.cpp | 4 +-
audio/sysvad/EndpointsCommon/speakertopo.cpp | 1 -
audio/sysvad/EndpointsCommon/speakertoptable.h | 13 +-
audio/sysvad/Package/package.VcxProj | 4 +-
.../TabletAudioSample/ComponentizedApoSample.inx | Bin 18736 -> 18770 bytes
.../TabletAudioSample/ComponentizedAudioSample.inx | Bin 50422 -> 50456 bytes
.../ComponentizedAudioSampleExtension.inx | Bin 11224 -> 11262 bytes
.../sysvad/TabletAudioSample/tabletaudiosample.inx | Bin 72830 -> 72864 bytes
audio/sysvad/sysvad.sln | 2 +-
audio/tests/KSPosTst/KsPosTestTaef.cpp | 215 ++++
audio/tests/KSPosTst/PreComp.h | 108 ++
audio/tests/KSPosTst/TestResourceBuild.cpp | 522 ++++++++
audio/tests/KSPosTst/locallimits.h | 25 +
audio/tests/KSPosTst/pintest.cpp | 518 ++++++++
audio/tests/KSPosTst/tests.h | 18 +
audio/tests/KSPosTst/timetest.cpp | 50 +
audio/tests/PinResourceHelpers/HalfApp.cpp | 1042 ++++++++++++++++
audio/tests/PinResourceHelpers/PreComp.h | 143 +++
audio/tests/PinResourceHelpers/PropertyHelper.cpp | 1263 ++++++++++++++++++++
audio/tests/PinResourceHelpers/TestResource.cpp | 331 +++++
.../tests/PinResourceHelpers/TestResourceHelper.h | 73 ++
audio/tests/wavetest/HalfApp.cpp | 1001 ----------------
audio/tests/wavetest/HalfApp.h | 195 ---
audio/tests/wavetest/PreComp.h | 107 --
audio/tests/wavetest/PropertyHelper.cpp | 1095 -----------------
audio/tests/wavetest/PropertyHelper.h | 190 ---
audio/tests/wavetest/TestResource.cpp | 331 -----
audio/tests/wavetest/TestResource.h | 66 -
audio/tests/wavetest/TestResourceBuild.cpp | 55 +-
audio/tests/wavetest/TestResourceHelper.h | 71 --
audio/tests/wavetest/WaveTestTaef.cpp | 6 +-
audio/tests/wavetest/WaveTestTaef.h | 5 +-
audio/tests/wavetest/comptest.cpp | 15 +-
audio/tests/wavetest/tests.h | 2 +-
36 files changed, 4381 insertions(+), 3106 deletions(-)
create mode 100644 audio/tests/KSPosTst/KsPosTestTaef.cpp
create mode 100644 audio/tests/KSPosTst/PreComp.h
create mode 100644 audio/tests/KSPosTst/TestResourceBuild.cpp
create mode 100644 audio/tests/KSPosTst/locallimits.h
create mode 100644 audio/tests/KSPosTst/pintest.cpp
create mode 100644 audio/tests/KSPosTst/tests.h
create mode 100644 audio/tests/KSPosTst/timetest.cpp
create mode 100644 audio/tests/PinResourceHelpers/HalfApp.cpp
create mode 100644 audio/tests/PinResourceHelpers/PreComp.h
create mode 100644 audio/tests/PinResourceHelpers/PropertyHelper.cpp
create mode 100644 audio/tests/PinResourceHelpers/TestResource.cpp
create mode 100644 audio/tests/PinResourceHelpers/TestResourceHelper.h
delete mode 100644 audio/tests/wavetest/HalfApp.cpp
delete mode 100644 audio/tests/wavetest/HalfApp.h
delete mode 100644 audio/tests/wavetest/PropertyHelper.cpp
delete mode 100644 audio/tests/wavetest/PropertyHelper.h
delete mode 100644 audio/tests/wavetest/TestResource.cpp
delete mode 100644 audio/tests/wavetest/TestResource.h
delete mode 100644 audio/tests/wavetest/TestResourceHelper.h
diff --git a/audio/sysvad/EndpointsCommon/mintopo.cpp b/audio/sysvad/EndpointsCommon/mintopo.cpp
index 28ddf419..4f2bf4fa 100644
--- a/audio/sysvad/EndpointsCommon/mintopo.cpp
+++ b/audio/sysvad/EndpointsCommon/mintopo.cpp
@@ -570,7 +570,7 @@ Return Value:
// 0x00000002 - JACKDESC2_DYNAMIC_FORMAT_CHANGE_CAPABILITY
//
pDesc->JackCapabilities = JackCapabilities;
-
+
ntStatus = STATUS_SUCCESS;
}
}
diff --git a/audio/sysvad/EndpointsCommon/mintopo.h b/audio/sysvad/EndpointsCommon/mintopo.h
index 4aa3d2de..266fc81d 100644
--- a/audio/sysvad/EndpointsCommon/mintopo.h
+++ b/audio/sysvad/EndpointsCommon/mintopo.h
@@ -73,17 +73,17 @@ public:
NTSTATUS PropertyHandlerJackDescription
(
- _In_ PPCPROPERTY_REQUEST PropertyRequest,
- _In_ ULONG cJackDescriptions,
- _In_reads_(cJackDescriptions) PKSJACK_DESCRIPTION * JackDescriptions
+ _In_ PPCPROPERTY_REQUEST PropertyRequest,
+ _In_ ULONG cJackDescriptions,
+ _In_reads_(cJackDescriptions) PKSJACK_DESCRIPTION *JackDescriptions
);
NTSTATUS PropertyHandlerJackDescription2
(
- _In_ PPCPROPERTY_REQUEST PropertyRequest,
- _In_ ULONG cJackDescriptions,
- _In_reads_(cJackDescriptions) PKSJACK_DESCRIPTION * JackDescriptions,
- _In_ DWORD JackCapabilities
+ _In_ PPCPROPERTY_REQUEST PropertyRequest,
+ _In_ ULONG cJackDescriptions,
+ _In_reads_(cJackDescriptions) PKSJACK_DESCRIPTION *JackDescriptions,
+ _In_ DWORD JackCapabilities
);
#if defined(SYSVAD_BTH_BYPASS) || defined(SYSVAD_USB_SIDEBAND)
diff --git a/audio/sysvad/EndpointsCommon/minwavertstream.cpp b/audio/sysvad/EndpointsCommon/minwavertstream.cpp
index 93ecdcf3..499d5b38 100644
--- a/audio/sysvad/EndpointsCommon/minwavertstream.cpp
+++ b/audio/sysvad/EndpointsCommon/minwavertstream.cpp
@@ -968,12 +968,12 @@ NTSTATUS CMiniportWaveRTStream::GetReadPacket
// Return next packet number to be read
*PacketNumber = availablePacketNumber;
- // Compute and return timestamp corresponding to start of the available packet. In a real hardware
+ // Compute and return timestamp corresponding to the end of the available packet. In a real hardware
// driver, the timestamp would be computed in a driver and hardware specific manner. In this sample
// driver, it is extrapolated from the sample driver's internal simulated position correlation
// [m_ullLinearPosition @ m_ullDmaTimeStamp] and the sample's internal 64-bit packet counter, subtracting
// 1 from the packet counter to compute the time at the start of that last completed packet.
- ULONGLONG linearPositionOfAvailablePacket = (packetCounter - 1) * (m_ulDmaBufferSize / m_ulNotificationsPerBuffer);
+ ULONGLONG linearPositionOfAvailablePacket = packetCounter * (m_ulDmaBufferSize / m_ulNotificationsPerBuffer);
// Need to divide by (1000 * 10000 because m_ulDmaMovementRate is average bytes per sec
ULONGLONG carryForwardBytes = (hnsElapsedTimeCarryForward * m_ulDmaMovementRate) / 10000000;
ULONGLONG deltaLinearPosition = ullLinearPosition + carryForwardBytes - linearPositionOfAvailablePacket;
diff --git a/audio/sysvad/EndpointsCommon/speakertopo.cpp b/audio/sysvad/EndpointsCommon/speakertopo.cpp
index cca4dac9..fee3d542 100644
--- a/audio/sysvad/EndpointsCommon/speakertopo.cpp
+++ b/audio/sysvad/EndpointsCommon/speakertopo.cpp
@@ -22,7 +22,6 @@ Abstract:
#pragma code_seg("PAGE")
-
//=============================================================================
NTSTATUS
PropertyHandler_SpeakerTopoFilter
diff --git a/audio/sysvad/EndpointsCommon/speakertoptable.h b/audio/sysvad/EndpointsCommon/speakertoptable.h
index 50f58c7b..eb12173a 100644
--- a/audio/sysvad/EndpointsCommon/speakertoptable.h
+++ b/audio/sysvad/EndpointsCommon/speakertoptable.h
@@ -85,7 +85,7 @@ PCPIN_DESCRIPTOR SpeakerTopoMiniportPins[] =
//=============================================================================
static
-KSJACK_DESCRIPTION SpeakerJackDescSpeakers =
+KSJACK_DESCRIPTION SpeakerJackDescBridge =
{
KSAUDIO_SPEAKER_STEREO,
0xB3C98C, // Color spec for green
@@ -101,7 +101,7 @@ static
PKSJACK_DESCRIPTION SpeakerJackDescriptions[] =
{
NULL,
- &SpeakerJackDescSpeakers
+ &SpeakerJackDescBridge
};
//=============================================================================
@@ -120,17 +120,20 @@ PCPROPERTY_ITEM PropertiesSpeakerTopoFilter[] =
{
&KSPROPSETID_Jack,
KSPROPERTY_JACK_DESCRIPTION,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
+ KSPROPERTY_TYPE_GET |
+ KSPROPERTY_TYPE_BASICSUPPORT,
PropertyHandler_SpeakerTopoFilter
},
{
&KSPROPSETID_Jack,
KSPROPERTY_JACK_DESCRIPTION2,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
+ KSPROPERTY_TYPE_GET |
+ KSPROPERTY_TYPE_BASICSUPPORT,
PropertyHandler_SpeakerTopoFilter
}
};
+
DEFINE_PCAUTOMATION_TABLE_PROP(AutomationSpeakerTopoFilter, PropertiesSpeakerTopoFilter);
//=============================================================================
@@ -152,4 +155,4 @@ PCFILTER_DESCRIPTOR SpeakerTopoMiniportFilterDescriptor =
};
#endif // _SYSVAD_SPEAKERTOPTABLE_H_
-
+
diff --git a/audio/sysvad/Package/package.VcxProj b/audio/sysvad/Package/package.VcxProj
index cef0bc33..0b47036c 100644
--- a/audio/sysvad/Package/package.VcxProj
+++ b/audio/sysvad/Package/package.VcxProj
@@ -1,4 +1,4 @@
-
+
@@ -109,4 +109,4 @@
-
\ No newline at end of file
+
diff --git a/audio/sysvad/TabletAudioSample/ComponentizedApoSample.inx b/audio/sysvad/TabletAudioSample/ComponentizedApoSample.inx
index a6bfb4af..be9428fb 100644
Binary files a/audio/sysvad/TabletAudioSample/ComponentizedApoSample.inx and b/audio/sysvad/TabletAudioSample/ComponentizedApoSample.inx differ
diff --git a/audio/sysvad/TabletAudioSample/ComponentizedAudioSample.inx b/audio/sysvad/TabletAudioSample/ComponentizedAudioSample.inx
index a5e6e73f..ccaa7327 100644
Binary files a/audio/sysvad/TabletAudioSample/ComponentizedAudioSample.inx and b/audio/sysvad/TabletAudioSample/ComponentizedAudioSample.inx differ
diff --git a/audio/sysvad/TabletAudioSample/ComponentizedAudioSampleExtension.inx b/audio/sysvad/TabletAudioSample/ComponentizedAudioSampleExtension.inx
index ce3ed335..1c89827a 100644
Binary files a/audio/sysvad/TabletAudioSample/ComponentizedAudioSampleExtension.inx and b/audio/sysvad/TabletAudioSample/ComponentizedAudioSampleExtension.inx differ
diff --git a/audio/sysvad/TabletAudioSample/tabletaudiosample.inx b/audio/sysvad/TabletAudioSample/tabletaudiosample.inx
index ba96faee..58ee4d88 100644
Binary files a/audio/sysvad/TabletAudioSample/tabletaudiosample.inx and b/audio/sysvad/TabletAudioSample/tabletaudiosample.inx differ
diff --git a/audio/sysvad/sysvad.sln b/audio/sysvad/sysvad.sln
index 1935f749..6a58b6df 100644
--- a/audio/sysvad/sysvad.sln
+++ b/audio/sysvad/sysvad.sln
@@ -1,4 +1,4 @@
-
+
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27703.2042
diff --git a/audio/tests/KSPosTst/KsPosTestTaef.cpp b/audio/tests/KSPosTst/KsPosTestTaef.cpp
new file mode 100644
index 00000000..b92f9e4f
--- /dev/null
+++ b/audio/tests/KSPosTst/KsPosTestTaef.cpp
@@ -0,0 +1,215 @@
+// ------------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// File Name:
+//
+// KsPosTestTaef.cpp
+//
+// Abstract:
+//
+// Implementation file for KsPosTestTaef
+//
+// -------------------------------------------------------------------------------
+#include "PreComp.h"
+#include "KsPosTestTaef.h"
+#include "tests.h"
+
+using namespace WEX::Common;
+using namespace WEX::Logging;
+using namespace WEX::TestExecution;
+
+#define RUN_TEST_CASE(testfn) \
+{ \
+ SetVerifyOutput verifySettings(VerifyOutputSettings::LogOnlyFailures); \
+ testfn(); \
+}
+
+IBasicLog * g_pBasicLog = NULL;
+WDMAudio::KsPosTest* g_pKsPosTst = NULL;
+
+TIMER_MECHANISM g_Timer =
+{
+ tpQPC, "QueryPerformanceCounter"
+};
+
+void LogWaveFormat(WAVEFORMATEX* pwfx)
+{
+ WAVEFORMATEXTENSIBLE* wfex = (WAVEFORMATEXTENSIBLE*)pwfx;
+
+ switch (pwfx->wFormatTag)
+ {
+ case WAVE_FORMAT_PCM:
+ LOG(g_pBasicLog, L" wFormatTag = WAVE_FORMAT_PCM");
+ break;
+ case WAVE_FORMAT_IEEE_FLOAT:
+ LOG(g_pBasicLog, L" wFormatTag = WAVE_FORMAT_IEEE_FLOAT");
+ break;
+ case WAVE_FORMAT_EXTENSIBLE:
+ LOG(g_pBasicLog, L" wFormatTag = WAVE_FORMAT_EXTENSIBLE");
+ if (wfex->SubFormat.Data1 == WAVE_FORMAT_PCM)
+ LOG(g_pBasicLog, L" SubFormat = WAVE_FORMAT_PCM");
+ if (wfex->SubFormat.Data1 == WAVE_FORMAT_IEEE_FLOAT)
+ LOG(g_pBasicLog, L" SubFormat = WAVE_FORMAT_IEEE_FLOAT");
+ break;
+ default:
+ LOG(g_pBasicLog, L" wFormatTag = UNKNOWN!");
+ }
+ LOG(g_pBasicLog, L" nChannel = %d", pwfx->nChannels);
+ LOG(g_pBasicLog, L" nSamplesPerSec = %d", pwfx->nSamplesPerSec);
+ LOG(g_pBasicLog, L" nAvgBytesPerSe = %d", pwfx->nAvgBytesPerSec);
+ LOG(g_pBasicLog, L" nBlockAlign = %d", pwfx->nBlockAlign);
+ LOG(g_pBasicLog, L" wBitsPerSample = %d", pwfx->wBitsPerSample);
+
+
+ if (pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
+ {
+ LOG(g_pBasicLog, L" wValidBitsPerSample = %d", wfex->Samples.wValidBitsPerSample);
+ LOG(g_pBasicLog, L" dwChannelMask = %hd", wfex->dwChannelMask);
+ }
+}
+
+// -------------------------------------------------------------------------------
+namespace WDMAudio
+{
+ BEGIN_MODULE()
+ MODULE_PROPERTY(L"Feature", L"PortCls HCK Tests")
+ MODULE_PROPERTY(L"TestResourceDependent", L"true")
+ END_MODULE()
+
+ // Create WEXBasicLog, Coinitialize Etc
+ MODULE_SETUP(WDMAudioSetup)
+
+ // Release stuff acquired in WDMAudioSetup
+ MODULE_CLEANUP(WDMAudioCleanup)
+};
+
+bool WDMAudio::WDMAudioSetup()
+{
+ if (NULL == g_pBasicLog)
+ {
+ if (!(VERIFY_SUCCEEDED(CreateWexBasicLog(&g_pBasicLog))))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool WDMAudio::WDMAudioCleanup()
+{
+ if (g_pBasicLog)
+ {
+ g_pBasicLog->Release();
+ }
+
+ return true;
+}
+
+// -------------------------------------------------------------------------------
+bool WDMAudio::KsPosTest::KsPosTestSetup()
+{
+ g_pKsPosTst = this;
+ m_pTimer = &g_Timer;
+ // The histograms can be displayed by using the command line parameter checked below
+ // If the parameter is not specified, the default is to not log anything
+ bool param = true;
+ WEX::TestExecution::RuntimeParameters::TryGetValue(L"logHistograms", param);
+ m_fLogHistograms = param;
+ return true;
+}
+
+bool WDMAudio::KsPosTest::KsPosTestCleanUp()
+{
+ g_pKsPosTst = NULL;
+
+ return true;
+}
+
+// -------------------------------------------------------------------------------
+bool WDMAudio::KsPosTest::TestCaseSetup()
+{
+ CComPtr spResource;
+ CComQIPtr spHalfContainer;
+
+ SetVerifyOutput verifySettings(VerifyOutputSettings::LogOnlyFailures);
+
+ Log::Comment(L"");
+ Log::Comment(L"------------------------------------------------------");
+ Log::Comment(L"Running test case setup");
+
+ size_t count = Resources::Count();
+ if (!VERIFY_ARE_EQUAL(count, (size_t)1)) { return false; }
+ if (!VERIFY_SUCCEEDED(Resources::Item(0, &spResource))) { return false; }
+
+ // 1. Assign m_pHalf
+ spHalfContainer = spResource;
+ if (!VERIFY_IS_NOT_NULL(spHalfContainer)) { return false; }
+ if (!VERIFY_SUCCEEDED(spHalfContainer->GetHalfApp(&m_pHalf))) { return false; }
+
+ // 2. Check if this is a loopback pin. If so, assign the host pin's HalfApp
+ if (m_pHalf->m_ConnectorType == eLoopbackConnector)
+ {
+ VERIFY_SUCCEEDED(m_pHalf->GetHostHalfApp(&m_pHostHalf));
+ }
+ else
+ {
+ m_pHostHalf = NULL;
+ }
+
+ Log::Comment(L"The test will run on the following format:");
+ if (m_pHostHalf != NULL)
+ {
+ LogWaveFormat(m_pHostHalf->m_pCurrentFormat.get());
+ }
+ else
+ {
+ LogWaveFormat(m_pHalf->m_pCurrentFormat.get());
+ }
+
+ return true;
+}
+
+bool WDMAudio::KsPosTest::TestCaseCleanUp()
+{
+ // Stop the timer here, in case any latency test fails
+ NtSetTimerResolution(0, FALSE, &actualTimerResolution);
+
+ if (!CompareWaveFormat(m_pHalf->m_pCurrentFormat.get(), m_pHalf->m_pPreferredFormat.get())) {
+ CloneWaveFormat(m_pHalf->m_pPreferredFormat.get(), wil::out_param(m_pHalf->m_pCurrentFormat));
+ m_pHalf->m_u32CurrentDefaultPeriodicityInFrames = m_pHalf->m_u32DefaultPeriodicityInFrames;
+ m_pHalf->m_u32CurrentFundamentalPeriodicityInFrames = m_pHalf->m_u32FundamentalPeriodicityInFrames;
+ m_pHalf->m_u32CurrentMinPeriodicityInFrames = m_pHalf->m_u32MinPeriodicityInFrames;
+ m_pHalf->m_u32CurrentMaxPeriodicityInFrames = m_pHalf->m_u32MaxPeriodicityInFrames;
+ }
+
+ if (m_pHostHalf != NULL) {
+ if (!VERIFY_SUCCEEDED(m_pHostHalf->CleanupStream())) { return false; }
+ if (!VERIFY_SUCCEEDED(m_pHostHalf->ReleaseEndpoint())) { return false; }
+ if (!VERIFY_SUCCEEDED(m_pHostHalf->ReleaseSineToneDataBuffer())) { return false; }
+ delete m_pHostHalf;
+ m_pHostHalf = NULL;
+ }
+
+ if (m_pHalf != NULL) {
+ if (!VERIFY_SUCCEEDED(m_pHalf->CleanupStream())) { return false; }
+ if (!VERIFY_SUCCEEDED(m_pHalf->ReleaseEndpoint())) { return false; }
+ if (!VERIFY_SUCCEEDED(m_pHalf->ReleaseSineToneDataBuffer())) { return false; }
+
+ m_pHalf = NULL;
+ }
+
+ return true;
+}
+
+// -------------------------------------------------------------------------------
+void WDMAudio::KsPosTest::TAEF_DriftAndJitter()
+{
+ RUN_TEST_CASE(Test_DriftAndJitter_Default);
+}
+
+void WDMAudio::KsPosTest::TAEF_Latency()
+{
+ RUN_TEST_CASE(Test_Latency_Default);
+}
diff --git a/audio/tests/KSPosTst/PreComp.h b/audio/tests/KSPosTst/PreComp.h
new file mode 100644
index 00000000..5fdfc9db
--- /dev/null
+++ b/audio/tests/KSPosTst/PreComp.h
@@ -0,0 +1,108 @@
+// ------------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// File Name:
+//
+// PreComp.h
+//
+// Abstract:
+//
+// Precompiled common headers
+//
+// -------------------------------------------------------------------------------
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// Number of milliseconds that the test will be delayed to wait for the stream to stabilize
+#define DELAY_FOR_STABILIZE 100
+
+// Number of milliseconds in a second
+#define MILLISECONDS_PER_SECOND 1000
+
+// Number of HNS units in one second
+#define HNSTIME_UNITS_PER_SECOND 10000000
+
+// Number of HNS units in one millisecond
+#define HNSTIME_UNITS_PER_MILLISECOND 10000
+
+typedef double (*TIMEPROC) (void);
+double tpQPC(void);
+
+typedef struct _tag_tm
+{
+ TIMEPROC Proc;
+ LPCSTR strRep;
+} TIMER_MECHANISM, * PTIMER_MECHANISM;
+
+// ----------------------------------------------------------
+// Timer functions
+extern "C" __kernel_entry NTSYSCALLAPI NTSTATUS NTAPI NtSetTimerResolution(
+ _In_ ULONG DesiredTime, _In_ BOOLEAN SetResolution, _Out_ PULONG ActualTime);
+
+// 1 ms timer resolution
+static ULONG timerResolution = (1 * 10000);
+static ULONG actualTimerResolution;
+
+// ------------------------------------------------------------------------------
+// structs used to hold results of perf tests
+#define DATA_POINTS 100
+
+typedef struct
+{
+ double testTime; // Time the sample was taken, in milliseconds, relative to the start of the sample collection
+ double positionTime; // Time of the reported position, in milliseconds, relative to the start of the sample collection
+ double position; // Position, in seconds, relative to the start of the sample collection
+} POSITION_SET, * PPOSITION_SET;
+
+typedef struct
+{
+ PPOSITION_SET argPosSets;
+ ULONG cPosSets;
+ ULONG ctLatencyMeas;
+ ULONG csBufferMeas;
+ double bytesPerSecond; // measured (in bytes/sec, NOT samples/sec)
+ double dOffset; // measured
+} PERF_RESULTS, * PPERF_RESULTS;
+
+typedef struct
+{
+ WAVEFORMATEXTENSIBLE wfxFormat;
+ PERF_RESULTS perfResults; //
+} FORMAT_ENTRY, * PFORMAT_ENTRY;
diff --git a/audio/tests/KSPosTst/TestResourceBuild.cpp b/audio/tests/KSPosTst/TestResourceBuild.cpp
new file mode 100644
index 00000000..93959089
--- /dev/null
+++ b/audio/tests/KSPosTst/TestResourceBuild.cpp
@@ -0,0 +1,522 @@
+// ------------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// File Name:
+//
+// TestResourceBuild.cpp
+//
+// Abstract:
+//
+// TAEF BuildResourceList implementation
+//
+// ------------------------------------------------------------------------------
+#include "PreComp.h"
+#include
+#include
+
+using namespace WEX::Common;
+using namespace WEX::Logging;
+using namespace WEX::TestExecution;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// CreateTestResource
+//
+// Create the test resource with MMDevice, device id, device name, data flow, connector type, connector id, mode,
+// list of formats
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+HRESULT CreateTestResource
+(
+ ResourceList& resourceList,
+ DeviceDescriptor descriptor
+)
+{
+ HRESULT hr = S_OK;
+
+ CComHeapPtr spHalfApp;
+ wil::com_ptr_nothrow spTestResource;
+ GUID ResourceGUID;
+ CComBSTR szResourceName;
+
+ // Create HalfApp
+ spHalfApp.Attach(new CHalfApp(descriptor));
+ if (!VERIFY_IS_NOT_NULL(spHalfApp)) {
+ hr = E_OUTOFMEMORY;
+ return hr;
+ }
+
+ // Create PinTestResource
+ if (!VERIFY_SUCCEEDED(hr = CoCreateGuid(&ResourceGUID))) {
+ return hr;
+ }
+ if (!VERIFY_SUCCEEDED(hr = CPinTestResource::CreateInstance(
+ spHalfApp, ResourceGUID, &spTestResource))) {
+ return hr;
+ }
+
+ // Add to resource list
+ spHalfApp.Detach();
+ if (!VERIFY_SUCCEEDED(hr = resourceList.Add(spTestResource.get()))) {
+ return hr;
+ }
+ if (!VERIFY_SUCCEEDED(hr = spTestResource->GetValue(CComBSTR(TestResourceProperty::c_szName), &szResourceName))) {
+ return hr;
+ }
+ Log::Comment(String().Format(L"Test Resource (%s) added", (PCWSTR)szResourceName));
+
+ return hr;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// GetProcessingModesForConnector
+//
+// For host/keyword detector pin, processing mode info is cached in property store and can be directly read. For offload
+// pin, query for ks processing mode property. For loopback pin, it doesn't support any processing modes, return GUID_NULL.
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+HRESULT GetProcessingModesForConnector
+(
+ IMMDevice* pDevice,
+ UINT uConnectorId,
+ EndpointConnectorType eConnectorType,
+ ULONG *pCount,
+ AUDIO_SIGNALPROCESSINGMODE **ppModes
+)
+{
+ HRESULT hr = S_OK;
+
+ *pCount = 0;
+ *ppModes = NULL;
+
+ if (eConnectorType == eHostProcessConnector || eConnectorType == eKeywordDetectorConnector) {
+ if (!VERIFY_SUCCEEDED(hr = GetCachedProcessingModes(pDevice, eConnectorType, pCount, ppModes))) {
+ return hr;
+ }
+ }
+ else if (eConnectorType == eOffloadConnector) {
+ if (!VERIFY_SUCCEEDED(hr = GetProcessingModes(pDevice, uConnectorId, pCount, ppModes))) {
+ return hr;
+ }
+ }
+ else if (eConnectorType == eLoopbackConnector) {
+ // Loopback pin doesn't support any processing modes, so put 1 GUID_NULL
+ CComHeapPtr spModes;
+
+ if (!spModes.Allocate(1))
+ return E_OUTOFMEMORY;
+
+ spModes[0] = GUID_NULL;
+
+ *pCount = 1;
+ *ppModes = spModes.Detach();
+ }
+
+ return hr;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// GetDefaultFormatForConnector
+//
+// Read audio engine device format from property store as default format.
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+HRESULT GetDefaultFormatForConnector
+(
+ IMMDevice* pDevice,
+ EndpointConnectorType eConnectorType,
+ WAVEFORMATEX **ppDefaultFormat
+)
+{
+ HRESULT hr = S_OK;
+
+ *ppDefaultFormat = NULL;
+ if (!VERIFY_SUCCEEDED(hr = GetCachedDefaultFormat(pDevice, eConnectorType, ppDefaultFormat))){
+ return hr;
+ }
+
+ return hr;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// GetSupportedFormatsForConnector
+//
+// For host/keyword detector pin, supported formats info is cached in property store and can be directly read. For offload
+// pin, provide with a predefined list of formats and check whether format is supported. For loopback pin, it matches the format
+// of host pin so put 0 format record.
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+HRESULT GetSupportedFormatRecordsForConnector
+(
+ IMMDevice* pDevice,
+ UINT uConnectorId,
+ EndpointConnectorType eConnectorType,
+ AUDIO_SIGNALPROCESSINGMODE mode,
+ STACKWISE_DATAFLOW dataFlow,
+ ULONG *pCount,
+ FORMAT_RECORD **ppFormatRecords
+)
+{
+ HRESULT hr = S_OK;
+
+ *pCount = 0;
+ *ppFormatRecords = NULL;
+
+ if (eConnectorType == eHostProcessConnector || eConnectorType == eKeywordDetectorConnector) {
+ if (!VERIFY_SUCCEEDED(hr = GetCachedSupportedFormatRecords(pDevice, eConnectorType, mode, pCount, ppFormatRecords))) {
+ return hr;
+ }
+ }
+ else if (eConnectorType == eOffloadConnector) {
+ if (!VERIFY_SUCCEEDED(hr = GetSupportedFormatRecords(pDevice, uConnectorId, eConnectorType, mode, dataFlow, pCount, ppFormatRecords))) {
+ return hr;
+ }
+ }
+ else if (eConnectorType == eLoopbackConnector) {
+ *pCount = 0;
+ *ppFormatRecords = NULL;
+ }
+
+ return hr;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// GetPreferredFormatForConnector
+//
+// If KSPROPERTY_PIN_PROPOSEDATAFORMAT2 is supported, use the proposed format for mode as preferred format for mode.
+// Otherwise, use default format as preferred format.
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+HRESULT GetPreferredFormatForConnector
+(
+ IMMDevice* pDevice,
+ UINT uConnectorId,
+ EndpointConnectorType eConnectorType,
+ AUDIO_SIGNALPROCESSINGMODE mode,
+ WAVEFORMATEX **ppPreferredFormat
+)
+{
+ HRESULT hr = S_OK;
+ wil::unique_cotaskmem_ptr pDefaultFormat;
+ wil::unique_cotaskmem_ptr pProposedFormat;
+
+ *ppPreferredFormat = NULL;
+
+
+ // Get default format for connector
+ if (!VERIFY_SUCCEEDED(hr = GetDefaultFormatForConnector(pDevice, eConnectorType, wil::out_param(pDefaultFormat)))) {
+ return hr;
+ }
+
+ // Return the processing mode specific format proposed by the driver
+ hr = GetProposedFormatForProcessingMode(pDevice, uConnectorId, mode, wil::out_param(pProposedFormat));
+ if (hr == S_OK) {
+ CloneWaveFormat(pProposedFormat.get(), ppPreferredFormat);
+ }
+ else {
+ CloneWaveFormat(pDefaultFormat.get(), ppPreferredFormat);
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// GetPreferredFormatPeriodicityCharacteristicsForConnector
+//
+// Get periodicity characteristics for format. For host/keyword detector pin, periodicity info is cached along with format
+// in property store and can be searched from supported format list. For offload pin, it should be calculate from
+// DiscoverPeriodicityCharacteristicsForFormat.
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+HRESULT GetPreferredFormatPeriodicityCharacteristicsForConnector
+(
+ IMMDevice* pDevice,
+ EndpointConnectorType eConnectorType,
+ AUDIO_SIGNALPROCESSINGMODE mode,
+ STACKWISE_DATAFLOW dataFlow,
+ WAVEFORMATEX *pPreferredFormat,
+ ULONG cFormatRecords,
+ PFORMAT_RECORD pFormatRecords,
+ UINT32 *pDefaultPeriodicityInFrames,
+ UINT32 *pFundamentalPeriodicityInFrames,
+ UINT32 *pMinPeriodicityInFrames,
+ UINT32 *pMaxPeriodicityInFrames,
+ UINT32 *pMaxPeriodicityInFramesExtended
+)
+{
+ HRESULT hr = S_OK;
+ bool bFormatInList = false;
+
+ for (ULONG i = 0; i < cFormatRecords; i++) {
+ if (CompareWaveFormat((WAVEFORMATEX *)&pFormatRecords[i].wfxEx, pPreferredFormat)) {
+ bFormatInList = true;
+ *pDefaultPeriodicityInFrames = pFormatRecords[i].defaultPeriodInFrames;
+ *pFundamentalPeriodicityInFrames = pFormatRecords[i].fundamentalPeriodInFrames;
+ *pMinPeriodicityInFrames = pFormatRecords[i].minPeriodInFrames;
+ *pMaxPeriodicityInFrames = pFormatRecords[i].maxPeriodInFrames;
+ *pMaxPeriodicityInFramesExtended = pFormatRecords[i].maxPeriodInFramesExtended;
+ break;
+ }
+ }
+
+ if (eConnectorType == eHostProcessConnector || eConnectorType == eKeywordDetectorConnector) {
+ if (!VERIFY_IS_TRUE(bFormatInList)) {
+ hr = E_NOTFOUND;
+ return hr;
+ }
+ }
+ else if (eConnectorType == eOffloadConnector || eConnectorType == eLoopbackConnector) {
+ if (!VERIFY_SUCCEEDED(hr = DiscoverPeriodicityCharacteristicsForFormat(pDevice, eConnectorType, mode, pPreferredFormat, dataFlow, pDefaultPeriodicityInFrames, pFundamentalPeriodicityInFrames, pMinPeriodicityInFrames, pMaxPeriodicityInFrames, pMaxPeriodicityInFramesExtended))) {
+ return hr;
+ }
+ }
+
+ return hr;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// AddTestResourceForConnector
+//
+// For each connector, read connector id, get all processing modes, identify default and preferred format for each mode
+// and also enumerate a list of supported formats for each mode. Store all the infos in test resource.
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+HRESULT AddTestResourceForConnector
+(
+ ResourceList& resourceList,
+ LPWSTR deviceId,
+ LPWSTR deviceName,
+ IMMDevice* pDevice,
+ EndpointConnectorType eConnectorType,
+ STACKWISE_DATAFLOW dataFlow
+)
+{
+ HRESULT hr = S_OK;
+ bool bHasConnector = false;
+ UINT uConnectorId;
+ ULONG cModes = 0;
+ CComHeapPtr spModes;
+ AUDIO_SIGNALPROCESSINGMODE mode;
+ ULONG cFormatRecords = 0;
+ CComHeapPtr spFormatRecords;
+ wil::unique_cotaskmem_ptr pPreferredFormat;
+ UINT32 u32DefaultPeriodicityInFrames;
+ UINT32 u32FundamentalPeriodicityInFrames;
+ UINT32 u32MinPeriodicityInFrames;
+ UINT32 u32MaxPeriodicityInFrames;
+ UINT32 u32MaxPeriodicityInFramesExtended;
+ bool isAVStream = false;
+ bool isBluetooth = false;
+ bool isSideband = false;
+
+ // Get connector id
+ if (!VERIFY_SUCCEEDED(hr = GetConnectorId(pDevice, eConnectorType, &bHasConnector, &uConnectorId))) {
+ return hr;
+ }
+ if (!bHasConnector) {
+ return hr;
+ }
+
+ Log::Comment(String().Format(L"Adding Test Resource for pin [%u]:", (uConnectorId & PARTID_MASK)));
+
+
+ // Get all signal processing modes for connector
+ if (!VERIFY_SUCCEEDED(hr = GetProcessingModesForConnector(pDevice, uConnectorId, eConnectorType, &cModes, &spModes))) {
+ return hr;
+ }
+
+ // Loop through each mode, get preferred format and list of formats and create test resource for each mode
+ for (ULONG i = 0; i < cModes; i++) {
+
+ mode = spModes[i];
+
+ if (!VERIFY_SUCCEEDED(hr = GetSupportedFormatRecordsForConnector(pDevice, uConnectorId, eConnectorType, mode, dataFlow, &cFormatRecords, &spFormatRecords))) {
+ return hr;
+ }
+
+ if (!VERIFY_SUCCEEDED(hr = GetPreferredFormatForConnector(pDevice, uConnectorId, eConnectorType, mode, wil::out_param(pPreferredFormat)))) {
+ return hr;
+ }
+
+ if (!VERIFY_SUCCEEDED(hr = GetPreferredFormatPeriodicityCharacteristicsForConnector(pDevice, eConnectorType, mode, dataFlow, pPreferredFormat.get(), cFormatRecords, spFormatRecords, &u32DefaultPeriodicityInFrames, &u32FundamentalPeriodicityInFrames, &u32MinPeriodicityInFrames, &u32MaxPeriodicityInFrames, &u32MaxPeriodicityInFramesExtended))) {
+ return hr;
+ }
+
+ // Check if audio endpoint is AVStream
+ if (!VERIFY_SUCCEEDED(hr = IsAVStream(pDevice, &isAVStream))) {
+ return hr;
+ }
+
+ // Check if audio endpoint is Bluetooth
+ if (!VERIFY_SUCCEEDED(hr = IsBluetooth(pDevice, &isBluetooth))) {
+ return hr;
+ }
+
+ // Check if audio endpoint is side band
+ if (!VERIFY_SUCCEEDED(hr = IsSideband(pDevice, &isSideband))) {
+ return hr;
+ }
+
+ DeviceDescriptor descriptor = { 0 };
+ descriptor.pDevice = pDevice;
+ descriptor.pwstrAudioEndpointId = deviceId;
+ descriptor.pwstrAudioEndpointFriendlyName = deviceName;
+ descriptor.dataFlow = dataFlow;
+ descriptor.eConnectorType = eConnectorType;
+ descriptor.uConnectorId = uConnectorId;
+ descriptor.mode = mode;
+ descriptor.cModes = cModes;
+ descriptor.pModes = spModes;
+ descriptor.cFormatRecords = cFormatRecords;
+ descriptor.pFormatRecords = spFormatRecords;
+ descriptor.pPreferredFormat = pPreferredFormat.get();
+ descriptor.u32DefaultPeriodicityInFrames = u32DefaultPeriodicityInFrames;
+ descriptor.u32FundamentalPeriodicityInFrames = u32FundamentalPeriodicityInFrames;
+ descriptor.u32MinPeriodicityInFrames = u32MinPeriodicityInFrames;
+ descriptor.u32MaxPeriodicityInFrames = u32MaxPeriodicityInFrames;
+ descriptor.bIsAVStream = isAVStream;
+ descriptor.bIsBluetooth = isBluetooth;
+ descriptor.bIsSideband = isSideband;
+
+ if (!VERIFY_SUCCEEDED(hr = CreateTestResource(resourceList, descriptor))) {
+ return hr;
+ }
+
+ spFormatRecords.Free();
+ }
+
+ return hr;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// AddTestResourcesForDevice
+//
+// Identify the existence of all pin types and add test resources for each pin
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+HRESULT AddTestResourcesForDevice
+(
+ ResourceList& resourceList,
+ LPWSTR deviceId,
+ LPWSTR deviceName,
+ STACKWISE_DATAFLOW dataFlow
+)
+{
+ HRESULT hr = S_OK;
+ wil::com_ptr_nothrow spEnumerator;
+ wil::com_ptr_nothrow spDevice;
+
+ Log::Comment(String().Format(L"Adding Test Resource for Device [%s]:", deviceName));
+
+ // Read the default device format from the property store
+ if (!VERIFY_SUCCEEDED(hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void **)&spEnumerator))) {
+ return hr;
+ }
+ if (!VERIFY_SUCCEEDED(hr = spEnumerator->GetDevice(deviceId, &spDevice))) {
+ return hr;
+ }
+
+ // Identify existence of host pin. Add test resources for host pin.
+ if (!VERIFY_SUCCEEDED(hr = AddTestResourceForConnector(resourceList, deviceId, deviceName, spDevice.get(), eHostProcessConnector, dataFlow))) {
+ return hr;
+ }
+
+ // Identify existence of offload pin. Add test resources for offload pin.
+ if (!VERIFY_SUCCEEDED(hr = AddTestResourceForConnector(resourceList, deviceId, deviceName, spDevice.get(), eOffloadConnector, dataFlow))) {
+ return hr;
+ }
+
+ // Identify existence of loopback pin. Add test resources for loopback pin.
+ if (!VERIFY_SUCCEEDED(hr = AddTestResourceForConnector(resourceList, deviceId, deviceName, spDevice.get(), eLoopbackConnector, capture ))) {
+ return hr;
+ }
+
+ /*
+ // Identify existence of keyword detector pin. Add test resources for keyword detector pin.
+ if (!VERIFY_SUCCEEDED(hr = AddTestResourceForConnector(resourceList, deviceId, deviceName, spDevice.get(), eKeywordDetectorConnector, dataFlow))) {
+ return hr;
+ }
+ */
+
+ return hr;
+}
+
+HRESULT __cdecl BuildResourceList(ResourceList& resourceList)
+{
+ HRESULT hr = S_OK;
+ wil::com_ptr_nothrow spEnumerator;
+ wil::com_ptr_nothrow spRenderEndpoints;
+ wil::com_ptr_nothrow spCaptureEndpoints;
+ wil::com_ptr_nothrow spEndpoint;
+ UINT cRenderDevices = 0;
+ UINT cCaptureDevices = 0;
+ UINT i = 0;
+ wil::unique_cotaskmem_string id;
+ wil::unique_cotaskmem_string friendlyName;
+
+ SetVerifyOutput verifySettings(VerifyOutputSettings::LogOnlyFailures);
+ DisableVerifyExceptions disable;
+
+ VERIFY_SUCCEEDED(::CoInitializeEx(NULL, COINIT_MULTITHREADED));
+
+ Log::Comment(L"In BuildResourceList");
+
+ // Create IMMDevice Enumerator
+ VERIFY_SUCCEEDED(CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void **)&spEnumerator));
+
+ // Enumerate all render endpoints
+ VERIFY_SUCCEEDED(spEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &spRenderEndpoints));
+ VERIFY_SUCCEEDED(spRenderEndpoints->GetCount(&cRenderDevices));
+
+ // Enumerate all capture endpoints
+ VERIFY_SUCCEEDED(spEnumerator->EnumAudioEndpoints(eCapture, DEVICE_STATE_ACTIVE, &spCaptureEndpoints));
+ VERIFY_SUCCEEDED(spCaptureEndpoints->GetCount(&cCaptureDevices));
+
+ if (!VERIFY_IS_TRUE(cRenderDevices | cCaptureDevices))
+ {
+ hr = E_FAIL;
+ Log::Comment(L"No device was found!");
+ goto Exit;
+ }
+
+ Log::Comment(String().Format(L"Found %d viable rendering device!", cRenderDevices));
+ // Add test resources for render endpoints
+ if (cRenderDevices) {
+ for (i = 0; i < cRenderDevices; i++) {
+ VERIFY_SUCCEEDED(spRenderEndpoints->Item(i, &spEndpoint));
+ VERIFY_SUCCEEDED(spEndpoint->GetId(&id));
+ VERIFY_SUCCEEDED(GetEndpointFriendlyName(spEndpoint.get(), &friendlyName));
+
+ Log::Comment(String().Format(L"\\\\ Device: %s (%s)", friendlyName.get(), id.get()));
+ VERIFY_SUCCEEDED(AddTestResourcesForDevice(resourceList, id.get(), friendlyName.get(), render));
+ }
+ }
+
+ Log::Comment(String().Format(L"Found %d viable capture device!", cCaptureDevices));
+ // Add test resources for capture endpoints
+ if (cCaptureDevices) {
+ for (i = 0; i < cCaptureDevices; i++) {
+ VERIFY_SUCCEEDED(spCaptureEndpoints->Item(i, &spEndpoint));
+ VERIFY_SUCCEEDED(spEndpoint->GetId(&id));
+ VERIFY_SUCCEEDED(GetEndpointFriendlyName(spEndpoint.get(), &friendlyName));
+
+ Log::Comment(String().Format(L"\\\\ Device: %s (%s)", friendlyName.get(), id.get()));
+ VERIFY_SUCCEEDED(AddTestResourcesForDevice(resourceList, id.get(), friendlyName.get(), capture));
+ }
+ }
+
+ Log::Comment(L"Resource enumeration complete.");
+ Log::Comment(String().Format(L"Enumerated %u resources", resourceList.Count()));
+
+Exit:
+ return hr;
+}
diff --git a/audio/tests/KSPosTst/locallimits.h b/audio/tests/KSPosTst/locallimits.h
new file mode 100644
index 00000000..60336eb5
--- /dev/null
+++ b/audio/tests/KSPosTst/locallimits.h
@@ -0,0 +1,25 @@
+// ------------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// Module Name:
+//
+// locallimits.h
+//
+// Abstract:
+//
+// defines the tolerances for WHQL failures for this test app
+//
+// -------------------------------------------------------------------------------
+
+// max latency for rendering or capturing is 20 ms
+#define LATENCY_THRESHOLD 20.
+
+// Real time sampling rates must be within 1% of the theoretical rate,
+// per the format, as required by the PC98/PC99 HW Design Guide.
+#define SAMPLERATE_THRESHOLD 1.0
+
+// audio devices are required to be SAMPLEACCURATE (PC9x HW Design Guide)..
+// but for some reason we are making them ms accurate??
+#define JITTER_STD_THRESHOLD 1.0 // 1 ms max allowed for std-deviation
+#define JITTER_MAX_THRESHOLD 4.0 // 4 ms max allowed for max deviation
diff --git a/audio/tests/KSPosTst/pintest.cpp b/audio/tests/KSPosTst/pintest.cpp
new file mode 100644
index 00000000..57e35b07
--- /dev/null
+++ b/audio/tests/KSPosTst/pintest.cpp
@@ -0,0 +1,518 @@
+// ------------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// Module Name:
+//
+// pintest.cpp
+//
+// Abstract:
+//
+// Implementation file for test cases
+//
+// -------------------------------------------------------------------------------
+
+#include "PreComp.h"
+#include "KsPosTestTaef.h"
+#include "tests.h"
+
+#include
+#include
+
+#define DEFAULT_PERIODICITY 0
+#define DEFAULT_LATENCY_COEFFICIENT 0
+#define xGetTime g_pKsPosTst->m_pTimer->Proc
+
+// ------------------------------------
+// Test_DriftAndJitter helper functions
+// ------------------------------------
+
+HRESULT CollectSampleData
+(
+ CHalfApp* pHalfApp,
+ PFORMAT_ENTRY pFormatEntry,
+ HNSTIME requestedPeriodicity
+)
+{
+ DWORD periodicityInMs = (DWORD)ceil(HNSTIME_TO_MILLISECONDS_DOUBLE(requestedPeriodicity));
+
+ if (!pFormatEntry)
+ {
+ ERR(g_pBasicLog, "FAIL: Current Format Entry is NULL.");
+ return E_INVALIDARG;
+ }
+
+ PPERF_RESULTS pResults = &pFormatEntry->perfResults;
+ PPOSITION_SET pPosSet = pResults->argPosSets;
+ double tStart = 0, tPre = 0, tPost = 0;
+ UINT i = 0;
+ UINT64 u64Position;
+ UINT64 positionHNS;
+ UINT64 u64Frequency;
+ double testStartHns;
+ LARGE_INTEGER liNow;
+ LARGE_INTEGER liFrequency;
+ QueryPerformanceFrequency(&liFrequency);
+
+ VERIFY_SUCCEEDED(pHalfApp->InitializeEndpoint());
+ VERIFY_SUCCEEDED(pHalfApp->CreateSineToneDataBuffer(pHalfApp->m_pCurrentFormat.get()));
+ VERIFY_SUCCEEDED(pHalfApp->InitializeStream(requestedPeriodicity, DEFAULT_LATENCY_COEFFICIENT));
+
+ // run the adapter sink pin
+ VERIFY_SUCCEEDED(pHalfApp->StartStream());
+
+ // Get a HNS reference from the begining of the test so the HNS from system and driver times won't be so large
+ QueryPerformanceCounter(&liNow);
+ testStartHns = (double)liNow.QuadPart * HNSTIME_UNITS_PER_SECOND / (double)liFrequency.QuadPart;
+
+ tStart = xGetTime();
+ Sleep(DELAY_FOR_STABILIZE);
+ // Get the stream frequency in order to determine the time offset
+ VERIFY_SUCCEEDED(pHalfApp->m_pAudioClock->GetFrequency(&u64Frequency));
+
+ // Start collecting the data
+ for (i = 0; i < DATA_POINTS;)
+ {
+ Sleep(periodicityInMs);
+
+ tPre = xGetTime();
+ VERIFY_SUCCEEDED(pHalfApp->GetPosition(&u64Position, &positionHNS));
+ QueryPerformanceCounter(&liNow);
+ tPost = xGetTime();
+
+ if (u64Position > 0)
+ {
+ // only count this result if the GetPosition and GetTime happened relatively atomically
+ if ((tPost - tPre) < 1.)
+ {
+ double testHNS = (double)liNow.QuadPart * HNSTIME_UNITS_PER_SECOND / (double)liFrequency.QuadPart;
+ // In both sampling rate and jitter calculation, the time used is in milliseconds, so we can convert it right here
+ pPosSet[i].testTime = HNSTIME_TO_MILLISECONDS_DOUBLE(testHNS - testStartHns);
+ pPosSet[i].positionTime = HNSTIME_TO_MILLISECONDS_DOUBLE(positionHNS - testStartHns);
+ // We store the values as seconds because it is easier to convert to bytes per second, on sampling rate calculation, and milliseconds, on jitter calculation.
+ pPosSet[i].position = (double)u64Position / (double)u64Frequency;
+
+ // Ignore repeated positions (that means they have the same QPC and should have the same position value)
+ if ((i > 0) && (pPosSet[i - 1].positionTime == pPosSet[i].positionTime))
+ {
+ // If the position is the same, decrement the count so that sample gets discarded by overwriting it
+ i--;
+ WARN(g_pBasicLog, "The same position was reported at %f ms: pos = %f seconds", pPosSet[i].testTime, pPosSet[i].position);
+ }
+ i++;
+ }
+ else
+ {
+ LOG(g_pBasicLog, "GetPosition function too slow");
+ }
+ }
+ // If a non-zero position has not been reported during one second, break the loop and check if there is enough data
+ else if ((tPost - tStart) > MILLISECONDS_PER_SECOND)
+ {
+ break;
+ }
+
+ pResults->cPosSets = i;
+ }
+
+ VERIFY_SUCCEEDED(pHalfApp->StopStream());
+
+ // Did we get enough data?
+ VERIFY_IS_TRUE(pResults->cPosSets >= 30);
+
+ return S_OK;
+}
+
+// --------------------------------------------------------------------------------------------------
+// CalculateSampleRate
+// --------------------------------------------------------------------------------------------------
+HRESULT CalculateSampleRate
+(
+ PFORMAT_ENTRY pFormatEntry
+)
+{
+ WAVEFORMATEX* pwfx = &pFormatEntry->wfxFormat.Format;
+ PPERF_RESULTS pResults = &pFormatEntry->perfResults;
+
+ double dError, dErrorPercent;
+
+ // Pair the positions with test HNS time to find the slope
+ // Alocate memory for this type-specific array
+ wil::unique_cotaskmem_ptr pointArray((PDPOINT)CoTaskMemAlloc(DATA_POINTS * sizeof(DPOINT)));
+ PDPOINT pArray = pointArray.get();
+ // Get a pointer to the sample set
+ PPOSITION_SET posSet = pResults->argPosSets;
+ for (int i = 0; i < DATA_POINTS; i++)
+ {
+ pArray[i].x = posSet[i].positionTime;
+ pArray[i].y = posSet[i].position * pwfx->nAvgBytesPerSec; // Convert to bytes
+ }
+
+ ULONG cArray = pResults->cPosSets; // number of points
+
+ // calculate the slope and intercept (bytes per second and latency)
+ pResults->bytesPerSecond = SLOPE(pArray, cArray);
+ pResults->dOffset = INTERCEPT(pArray, cArray, pResults->bytesPerSecond);
+
+ // Convert from bytes/ms to bytes/sec
+ pResults->bytesPerSecond *= MILLISECONDS_PER_SECOND;
+
+ // The offset is used in the jitter calculation and it is used in milliseconds, so we can save it in those units
+ pResults->dOffset = pResults->dOffset / pResults->bytesPerSecond * MILLISECONDS_PER_SECOND;
+
+ // calculate errors
+ dError = pResults->bytesPerSecond - (double)pwfx->nAvgBytesPerSec;
+ dErrorPercent = (dError / (double)pwfx->nAvgBytesPerSec) * 100.0;
+
+ if (g_pKsPosTst->m_fLogHistograms)
+ {
+ LOG(g_pBasicLog, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
+ LOG(g_pBasicLog, "SampleRate calculated from histogram (method of least squares)\n");
+
+ LOG(g_pBasicLog, "Collected %d data points", pResults->cPosSets);
+ LOG(g_pBasicLog, "Specified sample rate = %6.3f bytes/sec, %6.3f samples/sec", (double)(pwfx->nBlockAlign * pwfx->nSamplesPerSec), (double)pwfx->nSamplesPerSec);
+ LOG(g_pBasicLog, "Calculated sample rate = %6.3f bytes/sec, %6.3f samples/sec", pResults->bytesPerSecond, pResults->bytesPerSecond / (double)pwfx->nBlockAlign);
+ LOG(g_pBasicLog, "Error = %.3f %%", dErrorPercent);
+ LOG(g_pBasicLog, "Calculated time offset = %f ms", pResults->dOffset);
+ }
+
+ // evaluate the results
+ VERIFY_IS_TRUE(abs(dErrorPercent) <= SAMPLERATE_THRESHOLD);
+
+ return S_OK;
+}
+
+// --------------------------------------------------------------------------------------------------
+// CalculateJitter
+// --------------------------------------------------------------------------------------------------
+HRESULT CalculateJitter
+(
+ PFORMAT_ENTRY pFormatEntry
+)
+{
+ PPERF_RESULTS pResults = &pFormatEntry->perfResults;
+
+ double dError = 0.0;
+ double dErrorAve = 0.0;
+ double dErrorMax = 0.0;
+ double dStdDeviation = 0.0;
+ double reportedPosition;
+ double timeDifference;
+ ULONG i;
+ PPOSITION_SET pPosSet = pResults->argPosSets;
+
+ if (g_pKsPosTst->m_fLogHistograms)
+ {
+ LOG(g_pBasicLog, "Reported QPC Compensated Expected");
+ LOG(g_pBasicLog, "position adjust position position Error");
+ LOG(g_pBasicLog, "(ms) (ms) (ms) (ms) (ms)");
+ LOG(g_pBasicLog, "========== ========== ========== ========== ==========");
+ }
+
+ for (i = 0; i < pResults->cPosSets; i++)
+ {
+ // Convert the time offset from seconds to milliseconds
+ reportedPosition = pPosSet[i].position * MILLISECONDS_PER_SECOND; // milliseconds
+
+ // First, we compensate for the latency of the samples (they were taken 100 ms after stream start)
+ pPosSet[i].position = reportedPosition - pResults->dOffset; // The offset is already in ms
+
+ // Then, before comparing the expected and actual position, adjust the given sample to get the position corresponding to the test time.
+ timeDifference = pPosSet[i].testTime - pPosSet[i].positionTime; // milliseconds
+ // If the difference is positive, the time of the position is behind of what is expected and that position gets increased accordingly.
+ // If the difference is negative, the time of the position is ahead of what is expected and that position gets decreased accordingly.
+ // In the rare case when the QPC and time are the same, the difference is zero because we are on the spot and that is the position that should be compared.
+ pPosSet[i].position += timeDifference; // milliseconds
+
+ dError = pPosSet[i].testTime - pPosSet[i].position;
+ dErrorAve += dError;
+
+ if (g_pKsPosTst->m_fLogHistograms)
+ {
+ LOG(g_pBasicLog, "%10.2f, %10.2f, %10.2f, %10.2f, %10.2f", reportedPosition, timeDifference, pPosSet[i].position, pPosSet[i].testTime, dError);
+ }
+
+ if (dError < 0.)
+ dError = -dError;
+ if (dError > dErrorMax)
+ dErrorMax = dError;
+ }
+
+ dErrorAve /= (double)pResults->cPosSets;
+
+ VERIFY_IS_TRUE((ULONG)dErrorAve < 2); // if this is not true then, there's something wrong with our compensation...
+
+ for (i = 0; i < pResults->cPosSets; i++)
+ {
+ dError = pPosSet[i].testTime - pPosSet[i].position;
+ dStdDeviation += ((dError - dErrorAve) * (dError - dErrorAve));
+ }
+
+ dStdDeviation /= (double)pResults->cPosSets;
+ dStdDeviation = sqrt(dStdDeviation);
+
+ if (g_pKsPosTst->m_fLogHistograms)
+ {
+ LOG(g_pBasicLog, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
+ LOG(g_pBasicLog, "Jitter calculated from histogram (with (samplerate drift and latency) compensation)\n");
+ LOG(g_pBasicLog, "Max deviation = %6.3f ms", dErrorMax);
+ LOG(g_pBasicLog, "Standard deviation = %6.3f ms", dStdDeviation);
+ }
+
+ // evaluate the results ~~~~~~~~~~~~~
+ VERIFY_IS_TRUE(abs(dErrorMax) < JITTER_MAX_THRESHOLD);
+ VERIFY_IS_TRUE(abs(dStdDeviation) < JITTER_STD_THRESHOLD);
+
+ return S_OK;
+}
+
+// ------------------------------------------------------------------------------
+// ------------------------------------------------------------------------------
+void Test_DriftAndJitter_Main
+(
+ HNSTIME requestedPeriodicity
+)
+{
+ CHalfApp* pHalfApp = g_pKsPosTst->m_pHalf;
+ CHalfApp* pHostHalfApp = g_pKsPosTst->m_pHostHalf;
+ BOOL isLoopbackPin = pHalfApp->m_ConnectorType == eLoopbackConnector;
+
+ // Test will ignore Bluetooth devices until proper thresholds are in place.
+ if (pHalfApp->m_bIsBluetooth)
+ {
+ SKIP(g_pBasicLog, "Test is not supported for Bluetooth pins");
+ return;
+ }
+
+ // If this is a loobpack pin, start the host pin's stream
+ // This can be done before collecting the samples, since the host pin will keep playing until stopped
+ if (isLoopbackPin)
+ {
+ // Match loopback stream format with host stream format
+ CloneWaveFormat(pHostHalfApp->m_pCurrentFormat.get(), wil::out_param(pHalfApp->m_pCurrentFormat));
+ pHalfApp->m_u32CurrentDefaultPeriodicityInFrames = pHostHalfApp->m_u32CurrentDefaultPeriodicityInFrames;
+ pHalfApp->m_u32CurrentFundamentalPeriodicityInFrames = pHostHalfApp->m_u32CurrentFundamentalPeriodicityInFrames;
+ pHalfApp->m_u32CurrentMinPeriodicityInFrames = pHostHalfApp->m_u32CurrentMinPeriodicityInFrames;
+ pHalfApp->m_u32CurrentMaxPeriodicityInFrames = pHostHalfApp->m_u32CurrentMaxPeriodicityInFrames;
+
+ // Initialize and start host stream
+ VERIFY_SUCCEEDED(pHostHalfApp->InitializeEndpoint());
+ VERIFY_SUCCEEDED(pHostHalfApp->CreateSineToneDataBuffer(pHostHalfApp->m_pCurrentFormat.get()));
+ VERIFY_SUCCEEDED(pHostHalfApp->InitializeStream(requestedPeriodicity, DEFAULT_LATENCY_COEFFICIENT));
+ VERIFY_SUCCEEDED(pHostHalfApp->StartStream());
+ }
+
+ FORMAT_ENTRY results;
+ memset(&results, 0, sizeof(FORMAT_ENTRY));
+ results.wfxFormat.Format = *pHalfApp->m_pCurrentFormat.get();
+ // Alocate memory for the sample data
+ wil::unique_cotaskmem_ptr pPositionSet((PPOSITION_SET)CoTaskMemAlloc(DATA_POINTS * sizeof(POSITION_SET)));
+ results.perfResults.argPosSets = pPositionSet.get();
+
+ // collect the data ~~~~~~~~~~~~~~~~~
+ VERIFY_SUCCEEDED(CollectSampleData(pHalfApp, &results, requestedPeriodicity));
+
+ // Stop and cleanup the host stream since we are done collecting samples
+ if (isLoopbackPin)
+ {
+ VERIFY_SUCCEEDED(pHostHalfApp->StopStream());
+ VERIFY_SUCCEEDED(pHostHalfApp->CleanupStream());
+ VERIFY_SUCCEEDED(pHostHalfApp->ReleaseEndpoint());
+ VERIFY_SUCCEEDED(pHostHalfApp->ReleaseSineToneDataBuffer());
+ }
+
+ // calculate drift ~~~~~~~~~~~~~~~~~~
+ VERIFY_SUCCEEDED(CalculateSampleRate(&results));
+
+ // calculate Jitter ~~~~~~~~~~~~~~~~~
+ VERIFY_SUCCEEDED(CalculateJitter(&results));
+}
+
+// ------------------------------------------------------------------------------
+// ------------------------------------------------------------------------------
+void Test_DriftAndJitter_Default(void)
+{
+ HNSTIME requestedTime = FRAMES_TO_HNSTIME_DOUBLE(g_pKsPosTst->m_pHalf->m_u32CurrentDefaultPeriodicityInFrames, g_pKsPosTst->m_pHalf->m_pCurrentFormat->nSamplesPerSec);
+ if (g_pKsPosTst->m_fLogHistograms)
+ {
+ LOG(g_pBasicLog, "Periodicity: %d frames, %f ms", g_pKsPosTst->m_pHalf->m_u32CurrentDefaultPeriodicityInFrames, HNSTIME_TO_MILLISECONDS_DOUBLE(requestedTime));
+ }
+ Test_DriftAndJitter_Main(requestedTime);
+}
+
+/*
+ Perform a cycle of creating a pin, starting a stream, stoping and destroying.
+
+ This is done with the idea of putting the driver and audio hardware in an active state
+ before doing time sensitive tests.
+*/
+void ActivateDriver(CHalfApp* pHalfApp)
+{
+ VERIFY_SUCCEEDED(pHalfApp->InitializeEndpoint());
+ VERIFY_SUCCEEDED(pHalfApp->CreateSineToneDataBuffer(pHalfApp->m_pCurrentFormat.get()));
+ VERIFY_SUCCEEDED(pHalfApp->InitializeStream(DEFAULT_PERIODICITY, DEFAULT_LATENCY_COEFFICIENT));
+ VERIFY_SUCCEEDED(pHalfApp->StartStream());
+ Sleep(100);
+ VERIFY_SUCCEEDED(pHalfApp->StopStream());
+ VERIFY_SUCCEEDED(pHalfApp->CleanupStream());
+ VERIFY_SUCCEEDED(pHalfApp->ReleaseEndpoint());
+ VERIFY_SUCCEEDED(pHalfApp->ReleaseSineToneDataBuffer());
+}
+
+// ------------------------------------------------------------------------------
+// ------------------------------------------------------------------------------
+void Test_Latency_Main (HNSTIME requestedPeriodicity)
+{
+ CHalfApp* pHalfApp = g_pKsPosTst->m_pHalf;
+ CHalfApp* pHostHalfApp = g_pKsPosTst->m_pHostHalf;
+ NTSTATUS lTimerResStatus;
+ BOOL isLoopbackPin = pHalfApp->m_ConnectorType == eLoopbackConnector;
+
+ // Test will ignore Bluetooth devices until proper thresholds are in place.
+ if (pHalfApp->m_bIsBluetooth)
+ {
+ SKIP(g_pBasicLog, "Test is not supported for Bluetooth pins");
+ return;
+ }
+
+ lTimerResStatus = NtSetTimerResolution(timerResolution, TRUE, &actualTimerResolution);
+
+ if (!NT_SUCCESS(lTimerResStatus))
+ {
+ SKIP(g_pBasicLog, "Fail to set timer precision. Skip the test.");
+ return;
+ }
+
+ // If it is a loopback pin, get the host pin and start the stream
+ if (isLoopbackPin)
+ {
+ // Match loopback stream format with host stream format
+ CloneWaveFormat(pHostHalfApp->m_pCurrentFormat.get(), wil::out_param(pHalfApp->m_pCurrentFormat));
+ pHalfApp->m_u32CurrentDefaultPeriodicityInFrames = pHostHalfApp->m_u32CurrentDefaultPeriodicityInFrames;
+ pHalfApp->m_u32CurrentFundamentalPeriodicityInFrames = pHostHalfApp->m_u32CurrentFundamentalPeriodicityInFrames;
+ pHalfApp->m_u32CurrentMinPeriodicityInFrames = pHostHalfApp->m_u32CurrentMinPeriodicityInFrames;
+ pHalfApp->m_u32CurrentMaxPeriodicityInFrames = pHostHalfApp->m_u32CurrentMaxPeriodicityInFrames;
+
+ // Initialize and start host stream
+ VERIFY_SUCCEEDED(pHostHalfApp->InitializeEndpoint());
+ VERIFY_SUCCEEDED(pHostHalfApp->CreateSineToneDataBuffer(pHostHalfApp->m_pCurrentFormat.get()));
+ VERIFY_SUCCEEDED(pHostHalfApp->InitializeStream(requestedPeriodicity, DEFAULT_LATENCY_COEFFICIENT));
+ VERIFY_SUCCEEDED(pHostHalfApp->StartStream());
+ }
+
+ // Perform a stream cycle to make sure the driver is on a good state
+ ActivateDriver(pHalfApp);
+
+ // Initialize the stream
+ VERIFY_SUCCEEDED(pHalfApp->InitializeEndpoint());
+ VERIFY_SUCCEEDED(pHalfApp->CreateSineToneDataBuffer(pHalfApp->m_pCurrentFormat.get()));
+ VERIFY_SUCCEEDED(pHalfApp->InitializeStream(requestedPeriodicity, DEFAULT_LATENCY_COEFFICIENT));
+
+ UINT64 u64Position = 0;
+ UINT64 driverHns = 0;
+
+ double tPosPre = 0.0;
+ double tPosPost = 0.0;
+
+ LARGE_INTEGER liFrequency = { 0 };
+ LARGE_INTEGER timeStamp = { 0 };
+ QueryPerformanceFrequency(&liFrequency);
+
+ // mark the time
+ double tRunPre = xGetTime();
+ // Start the stream
+ VERIFY_SUCCEEDED(pHalfApp->StartStream());
+ // mark the time
+ double tRunPost = xGetTime();
+
+ LOG(g_pBasicLog, "Starting the stream took %.03f ms", (tRunPost - tRunPre));
+
+ // loop until we get a non-zero position
+ while (u64Position == 0)
+ {
+ Sleep(1);
+ // timer before position call
+ tPosPre = xGetTime();
+ VERIFY_SUCCEEDED(pHalfApp->GetPosition(&u64Position, &driverHns));
+ QueryPerformanceCounter(&timeStamp);
+ // timer after position call
+ tPosPost = xGetTime();
+ if (g_pKsPosTst->m_fLogHistograms)
+ {
+ LOG(g_pBasicLog, "Testing first non-zero position reported: %u samples, %u HNS at %.03f ms", u64Position, driverHns, tPosPost - tRunPre);
+ }
+
+ // Fail if the cursor does not move within 500 ms
+ VERIFY_IS_TRUE((tPosPost - tRunPost) < 500.0);
+ }
+
+ // Before stopping, get the frequency of the stream
+ UINT64 u64Frequency;
+ VERIFY_SUCCEEDED(pHalfApp->m_pAudioClock->GetFrequency(&u64Frequency));
+
+ // the uncertainty in time is the max possible value minus the min possible value divided by 2 (for +/- purposes)
+ double tMax = tPosPost - tRunPre;
+ double tMin = tPosPre - tRunPost;
+ double tAve = (tMax + tMin) / 2.0;
+ double tUncertainty = (tMax - tMin) / 2.0;
+
+ // Convert the stream position to an offset of milliseconds
+ double tOffset = MILLISECONDS_PER_SECOND * (double)u64Position / (double)u64Frequency;
+
+ // Calculate the difference in time of the position time versus the test time
+ UINT64 testHns = 10000000 * timeStamp.QuadPart / liFrequency.QuadPart;
+ INT64 timeDiff = testHns - driverHns;
+
+ // Compensate the positon to take this difference into account
+ tOffset += (double)timeDiff / HNSTIME_UNITS_PER_MILLISECOND;
+
+ if (g_pKsPosTst->m_fLogHistograms)
+ {
+ LOG(g_pBasicLog, "Times (HNS): %u, %u", testHns, driverHns);
+ LOG(g_pBasicLog, "Time difference: %d HNS (%f ms)", timeDiff, (double)timeDiff / HNSTIME_UNITS_PER_MILLISECOND);
+ LOG(g_pBasicLog, "First non-zero position = %u at %g ms", u64Position, tAve);
+ LOG(g_pBasicLog, "Time offset / max time: %f ms / %f ms", tOffset, tMax);
+ LOG(g_pBasicLog, "Frequency: %lu", u64Frequency);
+ }
+
+ double tLatency;
+ tLatency = tAve - tOffset;
+ if (tLatency < 0)
+ {
+ // This means that the position is between the average and max times, which should be OK (as long as it is not above the max)
+ tLatency *= -1;
+ LOG(g_pBasicLog, "The position is greater than the average time");
+ }
+ LOG(g_pBasicLog, "Adjusted latency = %.03f ms (+/- %.3f ms)", tLatency, tUncertainty);
+
+ // if the reported position is outside the max time for this call (see tUncertainty calculation above), then fail
+ // temp fix until we know how far can be the data in front of the
+ // real time because of buffering
+ VERIFY_IS_FALSE(tOffset > tMax);
+
+ // Verify that the latency is within the threshold
+ VERIFY_IS_TRUE(tLatency <= LATENCY_THRESHOLD); // ms
+
+ // Stop the endpoint
+ VERIFY_SUCCEEDED(pHalfApp->StopStream());
+ // If this was a loopback pin, stop the host stream also
+ if (isLoopbackPin)
+ {
+ VERIFY_SUCCEEDED(pHostHalfApp->StopStream());
+ VERIFY_SUCCEEDED(pHostHalfApp->CleanupStream());
+ VERIFY_SUCCEEDED(pHostHalfApp->ReleaseEndpoint());
+ VERIFY_SUCCEEDED(pHostHalfApp->ReleaseSineToneDataBuffer());
+ }
+
+ // Turn off the higher resolution timer
+ NtSetTimerResolution(0, FALSE, &actualTimerResolution);
+}
+
+// ------------------------------------------------------------------------------
+// ------------------------------------------------------------------------------
+void Test_Latency_Default(void)
+{
+ HNSTIME requestedTime = FRAMES_TO_HNSTIME_DOUBLE(g_pKsPosTst->m_pHalf->m_u32CurrentDefaultPeriodicityInFrames, g_pKsPosTst->m_pHalf->m_pCurrentFormat->nSamplesPerSec);
+ LOG(g_pBasicLog, "Periodicity: %d frames, %f ms", g_pKsPosTst->m_pHalf->m_u32CurrentDefaultPeriodicityInFrames, HNSTIME_TO_MILLISECONDS_DOUBLE(requestedTime));
+ Test_Latency_Main(requestedTime);
+}
diff --git a/audio/tests/KSPosTst/tests.h b/audio/tests/KSPosTst/tests.h
new file mode 100644
index 00000000..ec0a68cc
--- /dev/null
+++ b/audio/tests/KSPosTst/tests.h
@@ -0,0 +1,18 @@
+// ------------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// Module Name:
+//
+// tests.h
+//
+// Abstract:
+//
+// Header for testcases
+//
+// -------------------------------------------------------------------------------
+#pragma once
+
+void Test_DriftAndJitter_Default(void);
+
+void Test_Latency_Default(void);
diff --git a/audio/tests/KSPosTst/timetest.cpp b/audio/tests/KSPosTst/timetest.cpp
new file mode 100644
index 00000000..d8026716
--- /dev/null
+++ b/audio/tests/KSPosTst/timetest.cpp
@@ -0,0 +1,50 @@
+// ------------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// Module Name:
+//
+// timetest.cpp
+//
+// Abstract:
+//
+// Functions to precisely measure time.
+//
+// -------------------------------------------------------------------------------
+
+#include "PreComp.h"
+#include
+
+// ------------------------------------------------------------------------------
+// returns millisecs
+double tpQPC (void)
+{
+ static LARGE_INTEGER liFrequency = { 0 };
+ static LARGE_INTEGER liStart = { 0 };
+ static bool bInitialized = false;
+
+ if (!bInitialized)
+ {
+ if (!QueryPerformanceFrequency(&liFrequency))
+ {
+ throw ("QueryPerformanceFrequency failed");
+ }
+
+ if (!QueryPerformanceCounter(&liStart))
+ {
+ throw ("QueryPerformanceCounter failed");
+ }
+
+ bInitialized = true;
+ }
+
+ LARGE_INTEGER liNow = { 0 };
+
+ if (!QueryPerformanceCounter(&liNow))
+ {
+ throw ("QueryPerformanceCounter failed");
+ }
+
+ // milliseconds since test start
+ return 1000.0 * (liNow.QuadPart - liStart.QuadPart) / liFrequency.QuadPart;
+}
diff --git a/audio/tests/PinResourceHelpers/HalfApp.cpp b/audio/tests/PinResourceHelpers/HalfApp.cpp
new file mode 100644
index 00000000..83c9c8f3
--- /dev/null
+++ b/audio/tests/PinResourceHelpers/HalfApp.cpp
@@ -0,0 +1,1042 @@
+// ------------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft. All rights reserved.
+//
+// Module Name:
+//
+// HalfApp.cpp
+//
+// Abstract:
+//
+// Implementation for CHalfApp class
+//
+// -------------------------------------------------------------------------------
+
+
+
+
+
+
+
+
+
+
+
+
+HRESULT
+CHalfApp::InitializeEndpoint
+(
+ void
+)
+{
+ HRESULT hr = S_OK;
+
+
+
+ wil::unique_prop_variant varActivationParameter;
+
+
+
+ WAVEFORMATEX* pWfx = m_pCurrentFormat.get();
+
+ if (!VERIFY_IS_NOT_NULL(pWfx)) {
+ hr = E_NOTFOUND;
+ return hr;
+ }
+
+
+
+
+
+
+
+
+
+ // Allocate a structure for endpoint creation.
+ varActivationParameter.vt = VT_BLOB;
+
+ // Fill the endpoint creation structure...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ // Activate the endpoint
+ if (m_DataFlow == render) {
+ wil::com_ptr_nothrow spAudioOutputEndpointRT;
+ if (!VERIFY_SUCCEEDED(hr = m_pDevice->Activate(
+ __uuidof(IAudioOutputEndpointRT),
+ CLSCTX_INPROC_SERVER,
+ &varActivationParameter,
+ reinterpret_cast(&spAudioOutputEndpointRT)))) {
+ return hr;
+ }
+ spAudioOutputEndpointRT.query_to(&m_pAudioDeviceEndpoint);
+ if (!VERIFY_IS_NOT_NULL(m_pAudioDeviceEndpoint)) {
+ hr = E_FAIL;
+ return hr;
+ }
+ }
+ else {
+ wil::com_ptr_nothrow spAudioInputEndpointRT;
+ if (!VERIFY_SUCCEEDED(hr = m_pDevice->Activate(
+ __uuidof(IAudioInputEndpointRT),
+ CLSCTX_INPROC_SERVER,
+ &varActivationParameter,
+ reinterpret_cast(&spAudioInputEndpointRT)))) {
+ return hr;
+ }
+ spAudioInputEndpointRT.query_to(&m_pAudioDeviceEndpoint);
+ if (!VERIFY_IS_NOT_NULL(m_pAudioDeviceEndpoint)) {
+ hr = E_FAIL;
+ return hr;
+ }
+ }
+
+ // Initialize other endpoint interfaces
+ if (!VERIFY_SUCCEEDED(hr = m_pAudioDeviceEndpoint.query_to(&m_pAudioEndpointControl))) {
+ return hr;
+ }
+ if (!VERIFY_SUCCEEDED(hr = m_pAudioDeviceEndpoint.query_to(&m_pAudioEndpoint))) {
+ return hr;
+ }
+ if (!VERIFY_SUCCEEDED(hr = m_pAudioDeviceEndpoint.query_to(&m_pAudioEndpointRT))) {
+ return hr;
+ }
+ if (!VERIFY_SUCCEEDED(hr = m_pAudioDeviceEndpoint.query_to(&m_pAudioClock))) {
+ return hr;
+ }
+
+ return hr;
+}
+
+HRESULT
+CHalfApp::ReleaseEndpoint
+(
+ void
+)
+{
+ HRESULT hr = S_OK;
+
+ if (m_pAudioEndpointControl) {
+ m_pAudioEndpointControl->Reset();
+ }
+
+ m_pAudioDeviceEndpoint.reset();
+ m_pAudioEndpointControl.reset();
+ m_pAudioEndpoint.reset();
+ m_pAudioEndpointRT.reset();
+ m_pAudioClock.reset();
+
+ return hr;
+}
+
+HRESULT
+CHalfApp::StartEndpoint
+(
+ void
+)
+{
+ HRESULT hr = S_OK;
+ auto lock = m_CritSec.lock();
+
+ if (!VERIFY_SUCCEEDED(hr = m_pAudioEndpointControl->Start())) {
+ return hr;
+ }
+
+ return hr;
+}
+
+HRESULT
+CHalfApp::StopEndpoint
+(
+ void
+)
+{
+ HRESULT hr = S_OK;
+ auto lock = m_CritSec.lock();
+
+ if (!VERIFY_SUCCEEDED(hr = m_pAudioEndpointControl->Stop())) {
+ return hr;
+ }
+
+ return hr;
+}
+
+HRESULT
+CHalfApp::ResetEndpoint
+(
+ void
+)
+{
+ HRESULT hr = S_OK;
+ auto lock = m_CritSec.lock();
+
+ if (!VERIFY_SUCCEEDED(hr = m_pAudioEndpointControl->Reset())) {
+ return hr;
+ }
+
+ return hr;
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+//
+// Creates a pre-load data buffer used by the stream render and capture routines.
+//
+// If the current endpoint is a render one, the data buffer consists of a sine tone
+// wich gets loaded into a stream render routine.
+//
+// In the case of a capture endpoint, the pre-load data consists of silence.
+//
+////////////////////////////////////////////////////////////////////////////////////
+HRESULT
+CHalfApp::CreateSineToneDataBuffer
+(
+ WAVEFORMATEX* pWfx
+)
+{
+ HRESULT hr = S_OK;
+
+ if (!VERIFY_IS_NOT_NULL(pWfx)) {
+ hr = E_FAIL;
+ return hr;
+ }
+
+ m_dwSineToneDataBufferSize = (DWORD)(((ULONGLONG)BUF_LEN_IN_MS * pWfx->nSamplesPerSec / 1000) * pWfx->nBlockAlign);
+ m_pbSineToneDataBuffer.reset((BYTE*)LocalAlloc(LPTR, m_dwSineToneDataBufferSize));
+ if (!VERIFY_IS_NOT_NULL(m_pbSineToneDataBuffer)) {
+ hr = E_OUTOFMEMORY;
+ return hr;
+ }
+
+ if (m_DataFlow == render) // Sine tone for render
+ {
+ if (!VERIFY_SUCCEEDED(hr = FillBufferWithSineSignal(
+ g_pBasicLog, XFAIL,
+ pWfx,
+ TEST_AMPLITUDE, // amplitude
+ TEST_FREQUENCY, // frequency
+ 0.0, // initial phase,
+ 0.0, // dc
+ Method_NoDithering,
+ m_pbSineToneDataBuffer.get(),
+ m_dwSineToneDataBufferSize / pWfx->nBlockAlign,
+ m_dwSineToneDataBufferSize
+ ))) {
+ return hr;
+ }
+
+ m_dwSineToneDataBufferPosition = 0;
+ }
+ else // Silence for capture
+ {
+ memset(m_pbSineToneDataBuffer.get(), 0, m_dwSineToneDataBufferSize);
+ m_dwSineToneDataBufferPosition = 0;
+ }
+
+ return hr;
+}
+
+//////////////////////////////////
+//
+// Clears the current data buffer.
+//
+//////////////////////////////////
+HRESULT
+CHalfApp::ReleaseSineToneDataBuffer
+(
+ void
+)
+{
+ m_pbSineToneDataBuffer = nullptr;
+ m_dwSineToneDataBufferSize = 0;
+ m_dwSineToneDataBufferPosition = 0;
+
+ return S_OK;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+HRESULT
+CHalfApp::InitializeAndSetBuffer
+(
+ HNSTIME requestedPeriodicity,
+ UINT32 u32LatencyCoefficient
+)
+{
+ HRESULT hr = S_OK;
+ BOOL bIsEventCapable = false;
+
+ // If no requested periodicity is provided, use default.
+ if (requestedPeriodicity == 0) {
+ m_hnsPeriod = FRAMES_TO_HNSTIME_DOUBLE(m_u32CurrentDefaultPeriodicityInFrames, m_pCurrentFormat->nSamplesPerSec);
+ }
+ else {
+ m_hnsPeriod = requestedPeriodicity;
+ }
+
+ if (m_ConnectorType == eOffloadConnector) {
+ bIsEventCapable = true;
+ }
+ else {
+ if (!VERIFY_SUCCEEDED(hr = m_pAudioDeviceEndpoint->GetEventDrivenCapable(&bIsEventCapable))) {
+ return hr;
+ }
+ }
+
+ if (bIsEventCapable)
+ {
+ if (!VERIFY_SUCCEEDED(hr = m_pAudioEndpoint->SetStreamFlags(AUDCLNT_STREAMFLAGS_EVENTCALLBACK))) {
+ return hr;
+ }
+ }
+
+ if (!VERIFY_SUCCEEDED(hr = m_pAudioDeviceEndpoint->SetBuffer(m_hnsPeriod, u32LatencyCoefficient))) {
+ return hr;
+ }
+
+ return hr;
+}
+
+HRESULT
+CHalfApp::GetCurrentAvailiablePinInstanceCount
+(
+ UINT32 *pAvailablePinInstanceCount
+)
+{
+ HRESULT hr = S_OK;
+
+ // Read the current pin instance counts
+ if (!VERIFY_SUCCEEDED(hr = GetAvailiablePinInstanceCount(m_pDevice.get(), m_uConnectorId, pAvailablePinInstanceCount))) {
+ return hr;
+ }
+
+ return hr;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+//
+// Gets a CHalfApp instance based on the current one, but with a different processing mode.
+//
+// The processing mode for the new instance is specified through the secondMode parameter.
+//
+///////////////////////////////////////////////////////////////////////////////////////////
+HRESULT
+CHalfApp::GetSecondHalfApp
+(
+ AUDIO_SIGNALPROCESSINGMODE secondMode,
+ CHalfApp** ppSecondHalfApp
+)
+{
+ HRESULT hr = S_OK;
+ ULONG cFormatRecords = 0;
+ CComHeapPtr spFormatRecords;
+ wil::unique_cotaskmem_ptr pPreferredFormat;
+ UINT32 u32DefaultPeriodicityInFrames;
+ UINT32 u32FundamentalPeriodicityInFrames;
+ UINT32 u32MinPeriodicityInFrames;
+ UINT32 u32MaxPeriodicityInFrames;
+ UINT32 u32MaxPeriodicityInFramesExtended;
+ DeviceDescriptor descriptor = { 0 };
+
+ if (!VERIFY_SUCCEEDED(hr = GetSupportedFormatRecordsForConnector(m_pDevice.get(), m_uConnectorId, m_ConnectorType, secondMode, m_DataFlow, &cFormatRecords, &spFormatRecords))) {
+ return hr;
+ }
+
+ if (!VERIFY_SUCCEEDED(hr = GetPreferredFormatForConnector(m_pDevice.get(), m_uConnectorId, m_ConnectorType, secondMode, wil::out_param(pPreferredFormat)))) {
+ return hr;
+ }
+
+ if (!VERIFY_SUCCEEDED(hr = GetPreferredFormatPeriodicityCharacteristicsForConnector(m_pDevice.get(), m_ConnectorType, secondMode, m_DataFlow, pPreferredFormat.get(), cFormatRecords, spFormatRecords, &u32DefaultPeriodicityInFrames, &u32FundamentalPeriodicityInFrames, &u32MinPeriodicityInFrames, &u32MaxPeriodicityInFrames, &u32MaxPeriodicityInFramesExtended))) {
+ return hr;
+ }
+
+ descriptor.pDevice = m_pDevice.get();
+ descriptor.pwstrAudioEndpointId = m_pwstrDeviceId.get();
+ descriptor.pwstrAudioEndpointFriendlyName = m_pwstrDeviceFriendlyName.get();
+ descriptor.dataFlow = m_DataFlow;
+ descriptor.eConnectorType = m_ConnectorType;
+ descriptor.uConnectorId = m_uConnectorId;
+ descriptor.mode = secondMode;
+ descriptor.cModes = m_cModes;
+ descriptor.pModes = m_pModes;
+ descriptor.cFormatRecords = cFormatRecords;
+ descriptor.pFormatRecords = spFormatRecords;
+ descriptor.pPreferredFormat = pPreferredFormat.get();
+ descriptor.u32DefaultPeriodicityInFrames = u32DefaultPeriodicityInFrames;
+ descriptor.u32FundamentalPeriodicityInFrames = u32FundamentalPeriodicityInFrames;
+ descriptor.u32MinPeriodicityInFrames = u32MinPeriodicityInFrames;
+ descriptor.u32MaxPeriodicityInFrames = u32MaxPeriodicityInFrames;
+ descriptor.bIsAVStream = m_bIsAVStream;
+ descriptor.bIsBluetooth = m_bIsBluetooth;
+ descriptor.bIsSideband = m_bIsSideband;
+ *ppSecondHalfApp = new CHalfApp(descriptor);
+ if (*ppSecondHalfApp == NULL) {
+ hr = E_OUTOFMEMORY;
+ return hr;
+ }
+
+ return hr;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Gets a CHalfApp instance corresponding to the host pin of the current audio endpoint.
+//
+// This function is usually called on a test method that involves a loopback pin,
+// in order to be able to start and control a stream in the host pin and get loopback data.
+//
+////////////////////////////////////////////////////////////////////////////////////////////
+HRESULT
+CHalfApp::GetHostHalfApp
+(
+ CHalfApp** ppHostHalfApp
+)
+{
+ HRESULT hr = S_OK;
+ bool bHasConnector = false;
+ UINT uConnectorId;
+ ULONG cModes = 0;
+ CComHeapPtr spModes;
+ bool bRawSupport = false;
+ bool bDefaultSupport = false;
+ AUDIO_SIGNALPROCESSINGMODE mode;
+ ULONG cFormatRecords = 0;
+ CComHeapPtr spFormatRecords;
+ wil::unique_cotaskmem_ptr pPreferredFormat;
+ UINT32 u32DefaultPeriodicityInFrames;
+ UINT32 u32FundamentalPeriodicityInFrames;
+ UINT32 u32MinPeriodicityInFrames;
+ UINT32 u32MaxPeriodicityInFrames;
+ UINT32 u32MaxPeriodicityInFramesExtended;
+ DeviceDescriptor descriptor = { 0 };
+
+ // It is only used when testing on loopback pin. When preparing loopback pin, we also need prepare the host pin.
+ VERIFY_IS_TRUE(m_ConnectorType == eLoopbackConnector);
+
+ // Get host connector id
+ if (!VERIFY_SUCCEEDED(hr = GetConnectorId(m_pDevice.get(), eHostProcessConnector, &bHasConnector, &uConnectorId))) {
+ return hr;
+ }
+ if (!bHasConnector) {
+ return hr;
+ }
+
+ // Get all signal processing modes for host connector
+ if (!VERIFY_SUCCEEDED(hr = GetProcessingModesForConnector(m_pDevice.get(), uConnectorId, eHostProcessConnector, &cModes, &spModes))) {
+ return hr;
+ }
+
+ // It is possible that host pin support multiple processing modes so we pick up one mode. If host pin support default, use default mode. If host pin support raw, use raw mode.
+ for (ULONG i = 0; i < cModes; i++) {
+ if (spModes[i] == AUDIO_SIGNALPROCESSINGMODE_RAW)
+ bRawSupport = true;
+ if (spModes[i] == AUDIO_SIGNALPROCESSINGMODE_DEFAULT)
+ bDefaultSupport = true;
+ }
+ if (!VERIFY_IS_TRUE(bRawSupport || bDefaultSupport)) {
+ hr = E_FAIL;
+ return hr;
+ }
+ mode = bDefaultSupport ? AUDIO_SIGNALPROCESSINGMODE_DEFAULT : AUDIO_SIGNALPROCESSINGMODE_RAW;
+
+ if (!VERIFY_SUCCEEDED(hr = GetSupportedFormatRecordsForConnector(m_pDevice.get(), uConnectorId, eHostProcessConnector, mode, render, &cFormatRecords, &spFormatRecords))) {
+ return hr;
+ }
+
+ if (!VERIFY_SUCCEEDED(hr = GetPreferredFormatForConnector(m_pDevice.get(), uConnectorId, eHostProcessConnector, mode, wil::out_param(pPreferredFormat)))) {
+ return hr;
+ }
+
+ if (!VERIFY_SUCCEEDED(hr = GetPreferredFormatPeriodicityCharacteristicsForConnector(m_pDevice.get(), eHostProcessConnector, mode, render, pPreferredFormat.get(), cFormatRecords, spFormatRecords, &u32DefaultPeriodicityInFrames, &u32FundamentalPeriodicityInFrames, &u32MinPeriodicityInFrames, &u32MaxPeriodicityInFrames, &u32MaxPeriodicityInFramesExtended))) {
+ return hr;
+ }
+
+ descriptor.pDevice = m_pDevice.get();
+ descriptor.pwstrAudioEndpointId = m_pwstrDeviceId.get();
+ descriptor.pwstrAudioEndpointFriendlyName = m_pwstrDeviceFriendlyName.get();
+ descriptor.dataFlow = render;
+ descriptor.eConnectorType = eHostProcessConnector;
+ descriptor.uConnectorId = uConnectorId;
+ descriptor.mode = mode;
+ descriptor.cModes = cModes;
+ descriptor.pModes = spModes;
+ descriptor.cFormatRecords = cFormatRecords;
+ descriptor.pFormatRecords = spFormatRecords;
+ descriptor.pPreferredFormat = pPreferredFormat.get();
+ descriptor.u32DefaultPeriodicityInFrames = u32DefaultPeriodicityInFrames;
+ descriptor.u32FundamentalPeriodicityInFrames = u32FundamentalPeriodicityInFrames;
+ descriptor.u32MinPeriodicityInFrames = u32MinPeriodicityInFrames;
+ descriptor.u32MaxPeriodicityInFrames = u32MaxPeriodicityInFrames;
+ descriptor.bIsAVStream = m_bIsAVStream;
+ descriptor.bIsBluetooth = m_bIsBluetooth;
+ descriptor.bIsSideband = m_bIsSideband;
+ *ppHostHalfApp = new CHalfApp(descriptor);
+ if (*ppHostHalfApp == NULL) {
+ hr = E_OUTOFMEMORY;
+ return hr;
+ }
+
+ return hr;
+}
+
+
+HRESULT
+CHalfApp::InitializeStream
+(
+ HNSTIME requestedPeriodicity,
+ UINT32 u32LatencyCoefficient
+)
+{
+ HRESULT hr = S_OK;
+ BOOL bIsEventCapable;
+ wil::unique_cotaskmem_ptr pDeviceFormat;
+
+ if (!VERIFY_IS_TRUE(!m_bStreamInitialized)) {
+ hr = AEERR_ALREADY_INITIALIZED;
+ }
+
+ if (!VERIFY_SUCCEEDED(hr = InitializeAndSetBuffer(requestedPeriodicity, u32LatencyCoefficient))) {
+ return hr;
+ }
+
+ if (!VERIFY_SUCCEEDED(hr = m_pAudioEndpoint->GetFrameFormat(out_param(pDeviceFormat)))) {
+ return hr;
+ }
+ m_f32EndpointFrameRate = (FLOAT32)pDeviceFormat->nAvgBytesPerSec / (FLOAT32)pDeviceFormat->nBlockAlign;
+ if (!VERIFY_SUCCEEDED(hr = m_pAudioEndpoint->GetLatency(&m_hnsEndpointLatency))) {
+ return hr;
+ }
+
+ if (!VERIFY_SUCCEEDED(hr = m_hProcessThreadStartedEvent.create())) {
+ return hr;
+ }
+
+ if (!VERIFY_SUCCEEDED(hr = m_hTerminate.create(wil::EventOptions::ManualReset))) {
+ return hr;
+ }
+
+ if (!VERIFY_SUCCEEDED(hr = m_pAudioDeviceEndpoint->GetEventDrivenCapable(&bIsEventCapable))) {
+ return hr;
+ }
+
+ if (bIsEventCapable || m_ConnectorType == eOffloadConnector) {
+ m_bIsEventCapable = true;
+ }
+
+ if (m_bIsEventCapable)
+ {
+ if (!VERIFY_SUCCEEDED(hr = m_hEndpointBufferCompleteEvent.create())) {
+ return hr;
+ }
+ if (!VERIFY_SUCCEEDED(hr = m_pAudioEndpoint->SetEventHandle(m_hEndpointBufferCompleteEvent.get()))) {
+ return hr;
+ }
+ }
+
+ if (!m_bIsEventCapable) {
+ m_hTimer.reset(CreateWaitableTimerEx(NULL, NULL, 0, TIMER_ALL_ACCESS));
+ }
+
+ if (m_DataFlow == render) {
+ m_pStreamRoutine = RenderStreamRoutine;
+ }
+ else {
+ m_pStreamRoutine = CaptureStreamRoutine;
+ }
+
+ // To-do: Adjust for offload streaming
+
+ m_bStreamInitialized = true;
+
+ return hr;
+}
+
+HRESULT
+CHalfApp::CleanupStream
+(
+ void
+)
+{
+ HRESULT hr = S_OK;
+
+ // If the thread thread is still active, stop it
+ if (m_hStreamThread)
+ {
+ SignalAndWaitForThread();
+ }
+
+ m_hnsPeriod = 0;
+ m_f32EndpointFrameRate = 0.F;
+ m_hnsEndpointLatency = 0;
+
+ m_pStreamRoutine = nullptr;
+
+ m_hTerminate.reset();
+ m_hEndpointBufferCompleteEvent.reset();
+ m_hProcessThreadStartedEvent.reset();
+ m_hTimer.reset();
+
+ m_bIsEventCapable = false;
+ m_bStreamInitialized = false;
+ m_bStreamThreadTerminate = false;
+ m_bYieldActive = false;
+
+ return hr;
+}
+
+DWORD CALLBACK
+CHalfApp::RenderStreamRoutine
+(
+ PVOID lpParameter
+)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+DWORD CALLBACK
+CHalfApp::CaptureStreamRoutine
+(
+ PVOID lpParameter
+)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+HRESULT
+CHalfApp::StartStream
+(
+ void
+)
+{
+ HRESULT hr = S_OK;
+
+ if (!VERIFY_IS_TRUE(m_bStreamInitialized)) {
+ hr = AEERR_NOT_INITIALIZED;
+ return hr;
+ }
+ if (!VERIFY_IS_TRUE(!m_hStreamThread)) {
+ hr = AEERR_ALREADY_RUNNING;
+ return hr;
+ }
+
+ m_bStreamThreadTerminate = false;
+ m_hTerminate.ResetEvent();
+ m_hProcessThreadStartedEvent.ResetEvent();
+
+ DWORD dwThreadID;
+ m_hStreamThread.reset(CreateThread(NULL, 0, m_pStreamRoutine, this, 0, &dwThreadID));
+ if (!VERIFY_IS_NOT_NULL(m_hStreamThread)) {
+ DWORD dwError = GetLastError();
+ hr = HRESULT_FROM_WIN32(dwError);
+ return hr;
+ }
+ if (m_hStreamThread)
+ {
+ SetThreadPriority(m_hStreamThread.get(), THREAD_PRIORITY_HIGHEST);
+ }
+
+ // Wait for the processing thread to be started or to error out. To avoid the Start call from being blocked forever, give up waiting after 10 seconds, which is a duration quite unlikely to hit -- something must have gone wrong in the thread creation.
+ WaitForSingleObjectEx(m_hProcessThreadStartedEvent.get(), 10000, FALSE);
+
+ // Set timer
+ if (!m_bIsEventCapable) {
+ SetTimer(m_hTimer.get(), m_hnsPeriod, true);
+ }
+
+ if (!VERIFY_SUCCEEDED(hr = StartEndpoint())) {
+ return hr;
+ }
+
+ return hr;
+}
+
+HRESULT
+CHalfApp::StopStream
+(
+ void
+)
+{
+ HRESULT hr = S_OK;
+
+ m_bStreamThreadTerminate = true;
+
+ if (!VERIFY_IS_TRUE(m_bStreamInitialized)) {
+ hr = AEERR_NOT_INITIALIZED;
+ return hr;
+ }
+ if (!VERIFY_IS_NOT_NULL(m_hStreamThread)) {
+ hr = AEERR_NOT_RUNNING;
+ return hr;
+ }
+
+ SignalAndWaitForThread();
+
+ //Cancel timer
+ if (!m_bIsEventCapable) {
+ CancelTimer(m_hTimer.get());
+ }
+
+ if (!VERIFY_SUCCEEDED(hr = StopEndpoint())) {
+ return hr;
+ }
+
+ return hr;
+}
+
+void
+CHalfApp::SignalAndWaitForThread
+(
+ void
+)
+{
+ DWORD dwReturn;
+
+ m_bStreamThreadTerminate = true;
+ m_hTerminate.SetEvent();
+
+ dwReturn = WaitForSingleObjectEx(m_hStreamThread.get(), INFINITE, FALSE);
+
+ VERIFY_IS_TRUE(WAIT_OBJECT_0 == dwReturn);
+
+ m_hStreamThread.reset();
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+inline HRESULT CHalfApp::SetTimer(HANDLE timer, HNSTIME timeDuration, bool fireImmediatley)
+{
+ if (timer)
+ {
+ LARGE_INTEGER DueTime;
+
+ if (fireImmediatley)
+ {
+ DueTime.QuadPart = 0;
+ }
+ else
+ {
+ // Negate this to mean relative in call to SetWaitableTimer
+ DueTime.QuadPart = -timeDuration;
+ }
+
+ SetWaitableTimer(timer, &DueTime,
+ static_cast(MF_TO_MS(timeDuration)),
+ nullptr, nullptr, FALSE);
+ }
+ return S_OK;
+}
+
+inline void CHalfApp::CancelTimer(HANDLE timer)
+{
+ if (timer)
+ {
+ // Cancel the waitable timer
+ CancelWaitableTimer(timer);
+
+ // There is a race condition where the timer could have fired before it was canceled, which would leave the handle set to fire the next time events are waited upon. CancelWaitableTimer will not reset the state of the handle so
+ // wait for 0 ms for the timer to fire to clear it.
+ WaitForSingleObject(timer, 0);
+ }
+}
+
+HRESULT CHalfApp::GetPosition(UINT64* pu64Position, UINT64* pu64hnsQPCPosition)
+{
+ HRESULT hr = S_OK;
+ auto lock = m_CritSec.lock();
+
+ if (!VERIFY_SUCCEEDED(m_pAudioClock->GetPosition(pu64Position, pu64hnsQPCPosition))) {
+ return hr;
+ }
+
+ return S_OK;
+}
diff --git a/audio/tests/PinResourceHelpers/PreComp.h b/audio/tests/PinResourceHelpers/PreComp.h
new file mode 100644
index 00000000..85fc4f83
--- /dev/null
+++ b/audio/tests/PinResourceHelpers/PreComp.h
@@ -0,0 +1,143 @@
+// ------------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft. All rights reserved.
+//
+// File Name:
+//
+// PreComp.h
+//
+// Abstract:
+//
+// Precompiled common headers
+//
+// -------------------------------------------------------------------------------
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// Define custom test resource properties
+namespace WEX {
+ namespace TestExecution {
+ namespace TestResourceProperty
+ {
+ static const wchar_t c_szMode[] = L"Mode";
+ static const wchar_t c_szPin[] = L"Pin";
+ }
+ }
+}
+
+// ----------------------------------------------------------
+// Parameters for test sine tone
+#define TEST_AMPLITUDE 1.0f
+#define TEST_FREQUENCY 200.0f
+
+// ----------------------------------------------------------
+// Predefined format list for offload streaming
+#define COUNT_FORMATS 4
+
+static WAVEFORMATEXTENSIBLE ListofFormats[COUNT_FORMATS] =
+{
+ // 1
+ {
+ // Format
+ {
+ WAVE_FORMAT_EXTENSIBLE, // wFormatTag
+ 2, // nChannels
+ 44100, // nSamplesPerSec
+ 176400, // nAvgBytesPerSec
+ 4, // nBlockAlign
+ 16, // wBitsPerSample
+ 22 // cbSize
+ },
+ // Samples
+ {
+ 16 // wValidBitsPerSample
+ },
+ KSAUDIO_SPEAKER_STEREO, // dwChannelMask
+ KSDATAFORMAT_SUBTYPE_PCM // SubFormat
+ },
+ // 2
+ {
+ // Format
+ {
+ WAVE_FORMAT_EXTENSIBLE, // wFormatTag
+ 2, // nChannels
+ 48000, // nSamplesPerSec
+ 192000, // nAvgBytesPerSec
+ 4, // nBlockAlign
+ 16, // wBitsPerSample
+ 22 // cbSize
+ },
+ // Samples
+ {
+ 16 // wValidBitsPerSample
+ },
+ KSAUDIO_SPEAKER_STEREO, // dwChannelMask
+ KSDATAFORMAT_SUBTYPE_PCM // SubFormat
+ },
+ // 3
+ {
+ // Format
+ {
+ WAVE_FORMAT_EXTENSIBLE, // wFormatTag
+ 2, // nChannels
+ 88200, // nSamplesPerSec
+ 352800, // nAvgBytesPerSec
+ 4, // nBlockAlign
+ 16, // wBitsPerSample
+ 22 // cbSize
+ },
+ // Samples
+ {
+ 16 // wValidBitsPerSample
+ },
+ KSAUDIO_SPEAKER_STEREO, // dwChannelMask
+ KSDATAFORMAT_SUBTYPE_PCM // SubFormat
+ },
+ // 4
+ {
+ // Format
+ {
+ WAVE_FORMAT_EXTENSIBLE, // wFormatTag
+ 2, // nChannels
+ 96000, // nSamplesPerSec
+ 384000, // nAvgBytesPerSec
+ 4, // nBlockAlign
+ 16, // wBitsPerSample
+ 22 // cbSize
+ },
+ // Samples
+ {
+ 16 // wValidBitsPerSample
+ },
+ KSAUDIO_SPEAKER_STEREO, // dwChannelMask
+ KSDATAFORMAT_SUBTYPE_PCM // SubFormat
+ },
+};
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
+#include
+#include
+#include
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// 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;
+ }
+
+ 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 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;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// IsAVStream
+//
+// Check if audio device is AVStream
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+HRESULT IsAVStream
+(
+ IMMDevice* pDevice,
+ bool* pIsAVStream
+)
+{
+ HRESULT hr = S_OK;
+ wil::com_ptr_nothrow spDevnodeDevice;
+ wil::com_ptr_nothrow 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 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 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 spEnumerator;
+ wil::com_ptr_nothrow spProps;
+ wil::com_ptr_nothrow spDevnodeAsDevice;
+ wil::com_ptr_nothrow 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;
+}
diff --git a/audio/tests/PinResourceHelpers/TestResource.cpp b/audio/tests/PinResourceHelpers/TestResource.cpp
new file mode 100644
index 00000000..f3762b84
--- /dev/null
+++ b/audio/tests/PinResourceHelpers/TestResource.cpp
@@ -0,0 +1,331 @@
+// ------------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft. All rights reserved.
+//
+// File Name:
+//
+// TestResource.cpp
+//
+// Abstract:
+//
+// TAEF Test Resource implementation
+//
+// -------------------------------------------------------------------------------
+
+#include "PreComp.h"
+#include
+#include
+
+using namespace WEX::Logging;
+using namespace WEX::TestExecution;
+
+CPinTestResource::CPinTestResource() :
+ m_cRef(1)
+{}
+
+CPinTestResource::~CPinTestResource()
+{}
+
+HRESULT STDMETHODCALLTYPE
+CPinTestResource::CreateInstance
+(
+ CHalfApp * pHalf,
+ REFGUID guid,
+ ITestResource ** ppOut
+)
+{
+ HRESULT hr = S_OK;
+ CPinTestResource * pTestResource;
+ SetVerifyOutput verifySettings(VerifyOutputSettings::LogOnlyFailures);
+
+ if (!VERIFY_IS_NOT_NULL(pHalf))
+ {
+ return E_INVALIDARG;
+ }
+
+ if (!VERIFY_IS_NOT_NULL(ppOut))
+ {
+ return E_POINTER;
+ }
+
+ pTestResource = new CPinTestResource();
+ if (!VERIFY_IS_NOT_NULL(pTestResource))
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ if (!VERIFY_SUCCEEDED(hr = pTestResource->Initialize(
+ pHalf, guid))) {
+ pTestResource->Release();
+ return hr;
+ }
+
+ *ppOut = pTestResource;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE
+CPinTestResource::Initialize
+(
+ CHalfApp * pHalf,
+ REFGUID guid
+)
+{
+ HRESULT hr = S_OK;
+
+ WCHAR szStr[MAX_PATH];
+ LPWSTR szMode;
+ LPWSTR szPin;
+
+ SetVerifyOutput verifySettings(VerifyOutputSettings::LogOnlyFailures);
+
+ m_guid = guid;
+ m_spHalfApp.Attach(pHalf);
+
+ // Dataflow
+ if (m_spHalfApp->m_DataFlow == capture)
+ {
+ m_szType.Attach(W2BSTR(L"Capture"));
+ if (!VERIFY_IS_NOT_NULL(m_szType)) { return E_OUTOFMEMORY; }
+ }
+ else
+ {
+ m_szType.Attach(W2BSTR(L"Render"));
+ if (!VERIFY_IS_NOT_NULL(m_szType)) { return E_OUTOFMEMORY; }
+ }
+
+ szMode = ModeName(m_spHalfApp->m_Mode);
+ szPin = PinName(m_spHalfApp->m_ConnectorType);
+
+ // Id: Combine device Id, pin type and mode
+ m_szId.Attach(W2BSTR(m_spHalfApp->m_pwstrDeviceId.get()));
+ if (!VERIFY_SUCCEEDED(hr = StringCchPrintfW(
+ szStr, MAX_PATH, L"#%s#%s",
+ szPin,
+ szMode))) {
+ return hr;
+ }
+ if (!VERIFY_SUCCEEDED(hr = m_szId.Append(szStr))) {
+ return hr;
+ }
+ if (!VERIFY_IS_NOT_NULL(m_szId)) { return E_OUTOFMEMORY; }
+
+ // Name: Combine device friendly name, pin type, and mode
+ m_szName.Attach(W2BSTR(m_spHalfApp->m_pwstrDeviceFriendlyName.get()));
+ if (!VERIFY_SUCCEEDED(hr = StringCchPrintfW(
+ szStr, MAX_PATH, L" Pin %s Mode %s",
+ szPin,
+ szMode))) {
+ return hr;
+ }
+ if (!VERIFY_SUCCEEDED(hr = m_szName.Append(szStr))) {
+ return hr;
+ }
+ if (!VERIFY_IS_NOT_NULL(m_szName)) { return E_OUTOFMEMORY; }
+
+ // Mode
+ m_szMode.Attach(W2BSTR(szMode));
+ if (!VERIFY_IS_NOT_NULL(m_szMode)) { return E_OUTOFMEMORY; }
+
+ // Pin
+ m_szPin.Attach(W2BSTR(szPin));
+ if (!VERIFY_IS_NOT_NULL(m_szPin)) { return E_OUTOFMEMORY; }
+
+ return hr;
+}
+
+STDMETHODIMP_(ULONG)
+CPinTestResource::AddRef()
+{
+ return InterlockedIncrement(&m_cRef);
+}
+
+STDMETHODIMP_(ULONG)
+CPinTestResource::Release()
+{
+ ULONG cRef = InterlockedDecrement(&m_cRef);
+ if (0 == cRef)
+ {
+ delete this;
+ }
+
+ return cRef;
+}
+
+STDMETHODIMP
+CPinTestResource::QueryInterface(
+ __in REFIID riid,
+ __deref_out void ** ppvObject
+)
+{
+ HRESULT hr = S_OK;
+
+ //IF_FALSE_EXIT_HR( (NULL != ppvObject), E_POINTER);
+
+ if (IsEqualIID(riid, __uuidof(IUnknown)))
+ {
+ *ppvObject = static_cast(this);
+ }
+ else if (IsEqualIID(riid, __uuidof(ITestResource)))
+ {
+ *ppvObject = static_cast(this);
+ }
+ else if (IsEqualIID(riid, __uuidof(IHalfAppContainer)))
+ {
+ *ppvObject = static_cast(this);
+ }
+ else
+ {
+ *ppvObject = NULL;
+ hr = E_NOINTERFACE;
+ goto Exit;
+ }
+
+ AddRef();
+
+Exit:
+ return hr;
+}
+
+STDMETHODIMP
+CPinTestResource::GetGuid(GUID* pGuid) {
+ // don't want to see VERIFY spew
+ SetVerifyOutput verifySettings(VerifyOutputSettings::LogOnlyFailures);
+
+ if (!VERIFY_IS_NOT_NULL(pGuid)) { return E_POINTER; }
+
+ *pGuid = m_guid;
+ return S_OK;
+}
+
+STDMETHODIMP
+CPinTestResource::SetGuid(GUID guid) {
+ m_guid = guid;
+ return S_OK;
+}
+
+STDMETHODIMP
+CPinTestResource::GetValue(BSTR name, BSTR* pValue) {
+ // don't want to see VERIFY spew
+ SetVerifyOutput verifySettings(VerifyOutputSettings::LogOnlyFailures);
+
+ if (!VERIFY_IS_NOT_NULL(name)) { return E_POINTER; }
+ if (!VERIFY_IS_NOT_NULL(pValue)) { return E_POINTER; }
+
+ if (0 == wcscmp(name, TestResourceProperty::c_szName)) {
+ if (!VERIFY_IS_NOT_NULL(*pValue = SysAllocString(m_szName))) { return E_OUTOFMEMORY; }
+ return S_OK;
+ }
+
+ if (0 == wcscmp(name, TestResourceProperty::c_szId)) {
+ if (!VERIFY_IS_NOT_NULL(*pValue = SysAllocString(m_szId))) { return E_OUTOFMEMORY; }
+ return S_OK;
+ }
+
+ if (0 == wcscmp(name, TestResourceProperty::c_szType)) {
+ if (!VERIFY_IS_NOT_NULL(*pValue = SysAllocString(m_szType))) { return E_OUTOFMEMORY; }
+ return S_OK;
+ }
+
+ if (0 == wcscmp(name, TestResourceProperty::c_szMode)) {
+ if (!VERIFY_IS_NOT_NULL(*pValue = SysAllocString(m_szMode))) { return E_OUTOFMEMORY; }
+ return S_OK;
+ }
+
+ if (0 == wcscmp(name, TestResourceProperty::c_szPin)) {
+ if (!VERIFY_IS_NOT_NULL(*pValue = SysAllocString(m_szPin))) { return E_OUTOFMEMORY; }
+ return S_OK;
+ }
+
+ Log::Error(L"CDevice::GetValue name not found");
+ return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
+}
+
+STDMETHODIMP
+CPinTestResource::SetValue(BSTR name, BSTR value) {
+ // don't want to see VERIFY spew
+ SetVerifyOutput verifySettings(VerifyOutputSettings::LogOnlyFailures);
+
+ if (!VERIFY_IS_NOT_NULL(name)) { return E_POINTER; }
+ if (!VERIFY_IS_NOT_NULL(value)) { return E_POINTER; }
+
+ if (0 == wcscmp(name, TestResourceProperty::c_szName)) {
+ return m_szName.AssignBSTR(value);
+ }
+
+ if (0 == wcscmp(name, TestResourceProperty::c_szId)) {
+ return m_szId.AssignBSTR(value);
+ }
+
+ if (0 == wcscmp(name, TestResourceProperty::c_szType)) {
+ return m_szType.AssignBSTR(value);
+ }
+
+ if (0 == wcscmp(name, TestResourceProperty::c_szMode)) {
+ return m_szMode.AssignBSTR(value);
+ }
+
+ if (0 == wcscmp(name, TestResourceProperty::c_szPin)) {
+ return m_szPin.AssignBSTR(value);
+ }
+
+ Log::Error(L"CDevice::SetValue name not found");
+
+ return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
+}
+
+STDMETHODIMP
+CPinTestResource::GetHalfApp(CHalfApp ** ppHalfApp)
+{
+ SetVerifyOutput verifySettings(VerifyOutputSettings::LogOnlyFailures);
+
+ if (!VERIFY_IS_NOT_NULL(ppHalfApp)) { return E_POINTER; }
+
+ *ppHalfApp = m_spHalfApp;
+
+ return S_OK;
+}
+
+static const struct
+{
+ GUID mode;
+ LPWSTR name;
+}knownModes[] =
+{
+ { GUID_NULL, L"NO_MODE" },
+ { AUDIO_SIGNALPROCESSINGMODE_RAW, L"RAW" },
+ { AUDIO_SIGNALPROCESSINGMODE_DEFAULT, L"DEFAULT" },
+ { AUDIO_SIGNALPROCESSINGMODE_COMMUNICATIONS, L"COMMUNICATIONS" },
+ { AUDIO_SIGNALPROCESSINGMODE_SPEECH, L"SPEECH" },
+ { AUDIO_SIGNALPROCESSINGMODE_MEDIA, L"MEDIA" },
+ { AUDIO_SIGNALPROCESSINGMODE_MOVIE, L"MOVIE" },
+ { AUDIO_SIGNALPROCESSINGMODE_NOTIFICATION, L"NOTIFICATION" },
+};
+
+
+LPWSTR CPinTestResource::ModeName(REFGUID guidMode)
+{
+ for (auto m : knownModes)
+ {
+ if (m.mode == guidMode) { return m.name; }
+ }
+
+ return L"UNKNOWN";
+}
+
+LPWSTR CPinTestResource::PinName(EndpointConnectorType eConnectorType)
+{
+ switch (eConnectorType)
+ {
+ case eHostProcessConnector:
+ return L"HOST";
+ case eOffloadConnector:
+ return L"OFFLOAD";
+ case eLoopbackConnector:
+ return L"LOOPBACK";
+ case eKeywordDetectorConnector:
+ return L"KEYWORD";
+ default:
+ return L"UNKNOWN";
+ }
+}
diff --git a/audio/tests/PinResourceHelpers/TestResourceHelper.h b/audio/tests/PinResourceHelpers/TestResourceHelper.h
new file mode 100644
index 00000000..08fafa23
--- /dev/null
+++ b/audio/tests/PinResourceHelpers/TestResourceHelper.h
@@ -0,0 +1,73 @@
+// ------------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft. All rights reserved.
+//
+// Module Name:
+//
+// TestResourceHelpers.h
+//
+// Abstract:
+//
+// Header for BuildResourceList helpers.
+//
+// -------------------------------------------------------------------------------
+#pragma once
+
+#include
+
+// ----------------------------------------------------------------------
+HRESULT GetProcessingModesForConnector
+(
+ IMMDevice* pDevice,
+ UINT uConnectorId,
+ EndpointConnectorType eConnectorType,
+ ULONG* pCount,
+ AUDIO_SIGNALPROCESSINGMODE** ppModes
+);
+
+// ----------------------------------------------------------------------
+HRESULT GetDefaultFormatForConnector
+(
+ IMMDevice* pDevice,
+ EndpointConnectorType eConnectorType,
+ WAVEFORMATEX** ppDefaultFormat
+);
+
+// ----------------------------------------------------------------------
+HRESULT GetPreferredFormatForConnector
+(
+ IMMDevice* pDevice,
+ UINT uConnectorId,
+ EndpointConnectorType eConnectorType,
+ AUDIO_SIGNALPROCESSINGMODE mode,
+ WAVEFORMATEX** ppPreferredFormat
+);
+
+// ----------------------------------------------------------------------
+HRESULT GetPreferredFormatPeriodicityCharacteristicsForConnector
+(
+ IMMDevice* pDevice,
+ EndpointConnectorType eConnectorType,
+ AUDIO_SIGNALPROCESSINGMODE mode,
+ STACKWISE_DATAFLOW dataFlow,
+ WAVEFORMATEX* pPreferredFormat,
+ ULONG cFormatRecords,
+ PFORMAT_RECORD pFormatRecords,
+ UINT32* pDefaultPeriodicityInFrames,
+ UINT32* pFundamentalPeriodicityInFrames,
+ UINT32* pMinPeriodicityInFrames,
+ UINT32* pMaxPeriodicityInFrames,
+ UINT32* pMaxPeriodicityInFramesExtended
+);
+
+// ----------------------------------------------------------------------
+HRESULT GetSupportedFormatRecordsForConnector
+(
+ IMMDevice* pDevice,
+ UINT uConnectorId,
+ EndpointConnectorType eConnectorType,
+ AUDIO_SIGNALPROCESSINGMODE mode,
+ STACKWISE_DATAFLOW dataFlow,
+ ULONG* pCount,
+ FORMAT_RECORD** ppFormatRecords
+);
diff --git a/audio/tests/wavetest/HalfApp.cpp b/audio/tests/wavetest/HalfApp.cpp
deleted file mode 100644
index 14a15c08..00000000
--- a/audio/tests/wavetest/HalfApp.cpp
+++ /dev/null
@@ -1,1001 +0,0 @@
-// ------------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft. All rights reserved.
-//
-// Module Name:
-//
-// HalfApp.cpp
-//
-// Abstract:
-//
-// Implementation for CHalfApp class
-//
-// -------------------------------------------------------------------------------
-
-#include "PreComp.h"
-#include "WaveTestTaef.h"
-#include "HalfApp.h"
-#include "TestResourceHelper.h"
-#include "PropertyHelper.h"
-#include
-#include
-#include
-#include
-
-HRESULT
-CHalfApp::InitializeEndpoint
-(
- void
-)
-{
- HRESULT hr = S_OK;
-
-
-
- wil::unique_prop_variant varActivationParameter;
-
-
-
- WAVEFORMATEX* pWfx = m_pCurrentFormat.get();
-
- if (!VERIFY_IS_NOT_NULL(pWfx)) {
- hr = E_NOTFOUND;
- return hr;
- }
-
-
-
-
-
-
-
-
-
- // Allocate a structure for endpoint creation.
- varActivationParameter.vt = VT_BLOB;
-
- // Fill the endpoint creation structure...
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- // Activate the endpoint
- if (m_DataFlow == render) {
- wil::com_ptr_nothrow spAudioOutputEndpointRT;
- if (!VERIFY_SUCCEEDED(hr = m_pDevice->Activate(
- __uuidof(IAudioOutputEndpointRT),
- CLSCTX_INPROC_SERVER,
- &varActivationParameter,
- reinterpret_cast(&spAudioOutputEndpointRT)))) {
- return hr;
- }
- spAudioOutputEndpointRT.query_to(&m_pAudioDeviceEndpoint);
- if (!VERIFY_IS_NOT_NULL(m_pAudioDeviceEndpoint)) {
- hr = E_FAIL;
- return hr;
- }
- }
- else {
- wil::com_ptr_nothrow spAudioInputEndpointRT;
- if (!VERIFY_SUCCEEDED(hr = m_pDevice->Activate(
- __uuidof(IAudioInputEndpointRT),
- CLSCTX_INPROC_SERVER,
- &varActivationParameter,
- reinterpret_cast(&spAudioInputEndpointRT)))) {
- return hr;
- }
- spAudioInputEndpointRT.query_to(&m_pAudioDeviceEndpoint);
- if (!VERIFY_IS_NOT_NULL(m_pAudioDeviceEndpoint)) {
- hr = E_FAIL;
- return hr;
- }
- }
-
- // Initialize other endpoint interfaces
- if (!VERIFY_SUCCEEDED(hr = m_pAudioDeviceEndpoint.query_to(&m_pAudioEndpointControl))) {
- return hr;
- }
- if (!VERIFY_SUCCEEDED(hr = m_pAudioDeviceEndpoint.query_to(&m_pAudioEndpoint))) {
- return hr;
- }
- if (!VERIFY_SUCCEEDED(hr = m_pAudioDeviceEndpoint.query_to(&m_pAudioEndpointRT))) {
- return hr;
- }
-
- return hr;
-}
-
-HRESULT
-CHalfApp::ReleaseEndpoint
-(
- void
-)
-{
- HRESULT hr = S_OK;
-
- if (m_pAudioEndpointControl) {
- m_pAudioEndpointControl->Reset();
- }
-
- m_pAudioDeviceEndpoint.reset();
- m_pAudioEndpointControl.reset();
- m_pAudioEndpoint.reset();
- m_pAudioEndpointRT.reset();
-
- return hr;
-}
-
-HRESULT
-CHalfApp::StartEndpoint
-(
- void
-)
-{
- HRESULT hr = S_OK;
- auto lock = m_CritSec.lock();
-
- if (!VERIFY_SUCCEEDED(hr = m_pAudioEndpointControl->Start())) {
- return hr;
- }
-
- return hr;
-}
-
-HRESULT
-CHalfApp::StopEndpoint
-(
- void
-)
-{
- HRESULT hr = S_OK;
- auto lock = m_CritSec.lock();
-
- if (!VERIFY_SUCCEEDED(hr = m_pAudioEndpointControl->Stop())) {
- return hr;
- }
-
- return hr;
-}
-
-HRESULT
-CHalfApp::ResetEndpoint
-(
- void
-)
-{
- HRESULT hr = S_OK;
- auto lock = m_CritSec.lock();
-
- if (!VERIFY_SUCCEEDED(hr = m_pAudioEndpointControl->Reset())) {
- return hr;
- }
-
- return hr;
-}
-
-////////////////////////////////////////////////////////////////////////////////////
-//
-// Creates a pre-load data buffer used by the stream render and capture routines.
-//
-// If the current endpoint is a render one, the data buffer consists of a sine tone
-// wich gets loaded into a stream render routine.
-//
-// In the case of a capture endpoint, the pre-load data consists of silence.
-//
-////////////////////////////////////////////////////////////////////////////////////
-HRESULT
-CHalfApp::CreateSineToneDataBuffer
-(
- WAVEFORMATEX* pWfx
-)
-{
- HRESULT hr = S_OK;
-
- if (!VERIFY_IS_NOT_NULL(pWfx)) {
- hr = E_FAIL;
- return hr;
- }
-
- m_dwSineToneDataBufferSize = (DWORD)(((ULONGLONG)BUF_LEN_IN_MS * pWfx->nSamplesPerSec / 1000) * pWfx->nBlockAlign);
- m_pbSineToneDataBuffer.reset((BYTE*)LocalAlloc(LPTR, m_dwSineToneDataBufferSize));
- if (!VERIFY_IS_NOT_NULL(m_pbSineToneDataBuffer)) {
- hr = E_OUTOFMEMORY;
- return hr;
- }
-
- if (m_DataFlow == render) // Sine tone for render
- {
- if (!VERIFY_SUCCEEDED(hr = FillBufferWithSineSignal(
- g_pBasicLog, XFAIL,
- pWfx,
- TEST_AMPLITUDE, // amplitude
- TEST_FREQUENCY, // frequency
- 0.0, // initial phase,
- 0.0, // dc
- Method_NoDithering,
- m_pbSineToneDataBuffer.get(),
- m_dwSineToneDataBufferSize / pWfx->nBlockAlign,
- m_dwSineToneDataBufferSize
- ))) {
- return hr;
- }
-
- m_dwSineToneDataBufferPosition = 0;
- }
- else // Silence for capture
- {
- memset(m_pbSineToneDataBuffer.get(), 0, m_dwSineToneDataBufferSize);
- m_dwSineToneDataBufferPosition = 0;
- }
-
- return hr;
-}
-
-//////////////////////////////////
-//
-// Clears the current data buffer.
-//
-//////////////////////////////////
-HRESULT
-CHalfApp::ReleaseSineToneDataBuffer
-(
- void
-)
-{
- m_pbSineToneDataBuffer = nullptr;
- m_dwSineToneDataBufferSize = 0;
- m_dwSineToneDataBufferPosition = 0;
-
- return S_OK;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-HRESULT
-CHalfApp::InitializeAndSetBuffer
-(
- HNSTIME requestedPeriodicity,
- UINT32 u32LatencyCoefficient
-)
-{
- HRESULT hr = S_OK;
- BOOL bIsEventCapable = false;
-
- // If no requested periodicity is provided, use default.
- if (requestedPeriodicity == 0) {
- m_hnsPeriod = FRAMES_TO_HNSTIME_DOUBLE(m_u32CurrentDefaultPeriodicityInFrames, m_pCurrentFormat->nSamplesPerSec);
- }
- else {
- m_hnsPeriod = requestedPeriodicity;
- }
-
- if (m_ConnectorType == eOffloadConnector) {
- bIsEventCapable = true;
- }
- else {
- if (!VERIFY_SUCCEEDED(hr = m_pAudioDeviceEndpoint->GetEventDrivenCapable(&bIsEventCapable))) {
- return hr;
- }
- }
-
- if (bIsEventCapable)
- {
- if (!VERIFY_SUCCEEDED(hr = m_pAudioEndpoint->SetStreamFlags(AUDCLNT_STREAMFLAGS_EVENTCALLBACK))) {
- return hr;
- }
- }
-
- if (!VERIFY_SUCCEEDED(hr = m_pAudioDeviceEndpoint->SetBuffer(m_hnsPeriod, u32LatencyCoefficient))) {
- return hr;
- }
-
- return hr;
-}
-
-HRESULT
-CHalfApp::GetCurrentAvailiablePinInstanceCount
-(
- UINT32 *pAvailablePinInstanceCount
-)
-{
- HRESULT hr = S_OK;
-
- // Read the current pin instance counts
- if (!VERIFY_SUCCEEDED(hr = GetAvailiablePinInstanceCount(m_pDevice.get(), m_uConnectorId, pAvailablePinInstanceCount))) {
- return hr;
- }
-
- return hr;
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////
-//
-// Gets a CHalfApp instance based on the current one, but with a different processing mode.
-//
-// The processing mode for the new instance is specified through the secondMode parameter.
-//
-///////////////////////////////////////////////////////////////////////////////////////////
-HRESULT
-CHalfApp::GetSecondHalfApp
-(
- AUDIO_SIGNALPROCESSINGMODE secondMode,
- CHalfApp** ppSecondHalfApp
-)
-{
- HRESULT hr = S_OK;
- ULONG cFormatRecords = 0;
- CComHeapPtr spFormatRecords;
- wil::unique_cotaskmem_ptr pPreferredFormat;
- UINT32 u32DefaultPeriodicityInFrames;
- UINT32 u32FundamentalPeriodicityInFrames;
- UINT32 u32MinPeriodicityInFrames;
- UINT32 u32MaxPeriodicityInFrames;
- UINT32 u32MaxPeriodicityInFramesExtended;
-
- if (!VERIFY_SUCCEEDED(hr = GetSupportedFormatRecordsForConnector(m_pDevice.get(), m_uConnectorId, m_ConnectorType, secondMode, m_DataFlow, &cFormatRecords, &spFormatRecords))) {
- return hr;
- }
-
- if (!VERIFY_SUCCEEDED(hr = GetPreferredFormatForConnector(m_pDevice.get(), m_uConnectorId, m_ConnectorType, secondMode, wil::out_param(pPreferredFormat)))) {
- return hr;
- }
-
- if (!VERIFY_SUCCEEDED(hr = GetPreferredFormatPeriodicityCharacteristicsForConnector(m_pDevice.get(), m_ConnectorType, secondMode, m_DataFlow, pPreferredFormat.get(), cFormatRecords, spFormatRecords, &u32DefaultPeriodicityInFrames, &u32FundamentalPeriodicityInFrames, &u32MinPeriodicityInFrames, &u32MaxPeriodicityInFrames, &u32MaxPeriodicityInFramesExtended))) {
- return hr;
- }
-
- *ppSecondHalfApp = new CHalfApp(m_pDevice.get(), m_pwstrDeviceId.get(), m_pwstrDeviceFriendlyName.get(), m_DataFlow, m_ConnectorType, m_uConnectorId, secondMode, m_cModes, m_pModes, cFormatRecords, spFormatRecords, pPreferredFormat.get(), u32DefaultPeriodicityInFrames, u32FundamentalPeriodicityInFrames, u32MinPeriodicityInFrames, u32MaxPeriodicityInFrames);
- if (*ppSecondHalfApp == NULL) {
- hr = E_OUTOFMEMORY;
- return hr;
- }
-
- return hr;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////
-//
-// Gets a CHalfApp instance corresponding to the host pin of the current audio endpoint.
-//
-// This function is usually called on a test method that involves a loopback pin,
-// in order to be able to start and control a stream in the host pin and get loopback data.
-//
-////////////////////////////////////////////////////////////////////////////////////////////
-HRESULT
-CHalfApp::GetHostHalfApp
-(
- CHalfApp** ppHostHalfApp
-)
-{
- HRESULT hr = S_OK;
- bool bHasConnector = false;
- UINT uConnectorId;
- ULONG cModes = 0;
- CComHeapPtr spModes;
- bool bRawSupport = false;
- bool bDefaultSupport = false;
- AUDIO_SIGNALPROCESSINGMODE mode;
- ULONG cFormatRecords = 0;
- CComHeapPtr spFormatRecords;
- wil::unique_cotaskmem_ptr pPreferredFormat;
- UINT32 u32DefaultPeriodicityInFrames;
- UINT32 u32FundamentalPeriodicityInFrames;
- UINT32 u32MinPeriodicityInFrames;
- UINT32 u32MaxPeriodicityInFrames;
- UINT32 u32MaxPeriodicityInFramesExtended;
-
- // It is only used when testing on loopback pin. When preparing loopback pin, we also need prepare the host pin.
- VERIFY_IS_TRUE(m_ConnectorType == eLoopbackConnector);
-
- // Get host connector id
- if (!VERIFY_SUCCEEDED(hr = GetConnectorId(m_pDevice.get(), eHostProcessConnector, &bHasConnector, &uConnectorId))) {
- return hr;
- }
- if (!bHasConnector) {
- return hr;
- }
-
- // Get all signal processing modes for host connector
- if (!VERIFY_SUCCEEDED(hr = GetProcessingModesForConnector(m_pDevice.get(), uConnectorId, eHostProcessConnector, &cModes, &spModes))) {
- return hr;
- }
-
- // It is possible that host pin support multiple processing modes so we pick up one mode. If host pin support default, use default mode. If host pin support raw, use raw mode.
- for (ULONG i = 0; i < cModes; i++) {
- if (spModes[i] == AUDIO_SIGNALPROCESSINGMODE_RAW)
- bRawSupport = true;
- if (spModes[i] == AUDIO_SIGNALPROCESSINGMODE_DEFAULT)
- bDefaultSupport = true;
- }
- if (!VERIFY_IS_TRUE(bRawSupport || bDefaultSupport)) {
- hr = E_FAIL;
- return hr;
- }
- mode = bDefaultSupport ? AUDIO_SIGNALPROCESSINGMODE_DEFAULT : AUDIO_SIGNALPROCESSINGMODE_RAW;
-
- if (!VERIFY_SUCCEEDED(hr = GetSupportedFormatRecordsForConnector(m_pDevice.get(), uConnectorId, eHostProcessConnector, mode, render, &cFormatRecords, &spFormatRecords))) {
- return hr;
- }
-
- if (!VERIFY_SUCCEEDED(hr = GetPreferredFormatForConnector(m_pDevice.get(), uConnectorId, eHostProcessConnector, mode, wil::out_param(pPreferredFormat)))) {
- return hr;
- }
-
- if (!VERIFY_SUCCEEDED(hr = GetPreferredFormatPeriodicityCharacteristicsForConnector(m_pDevice.get(), eHostProcessConnector, mode, render, pPreferredFormat.get(), cFormatRecords, spFormatRecords, &u32DefaultPeriodicityInFrames, &u32FundamentalPeriodicityInFrames, &u32MinPeriodicityInFrames, &u32MaxPeriodicityInFrames, &u32MaxPeriodicityInFramesExtended))) {
- return hr;
- }
-
- *ppHostHalfApp = new CHalfApp(m_pDevice.get(), m_pwstrDeviceId.get(), m_pwstrDeviceFriendlyName.get(), render, eHostProcessConnector, uConnectorId, mode, cModes, spModes, cFormatRecords, spFormatRecords, pPreferredFormat.get(), u32DefaultPeriodicityInFrames, u32FundamentalPeriodicityInFrames, u32MinPeriodicityInFrames, u32MaxPeriodicityInFrames);
- if (*ppHostHalfApp == NULL) {
- hr = E_OUTOFMEMORY;
- return hr;
- }
-
- return hr;
-}
-
-
-HRESULT
-CHalfApp::InitializeStream
-(
- HNSTIME requestedPeriodicity,
- UINT32 u32LatencyCoefficient
-)
-{
- HRESULT hr = S_OK;
- BOOL bIsEventCapable;
- wil::unique_cotaskmem_ptr pDeviceFormat;
-
- if (!VERIFY_IS_TRUE(!m_bStreamInitialized)) {
- hr = AEERR_ALREADY_INITIALIZED;
- }
-
- if (!VERIFY_SUCCEEDED(hr = InitializeAndSetBuffer(requestedPeriodicity, u32LatencyCoefficient))) {
- return hr;
- }
-
- if (!VERIFY_SUCCEEDED(hr = m_pAudioEndpoint->GetFrameFormat(out_param(pDeviceFormat)))) {
- return hr;
- }
- m_f32EndpointFrameRate = (FLOAT32)pDeviceFormat->nAvgBytesPerSec / (FLOAT32)pDeviceFormat->nBlockAlign;
- if (!VERIFY_SUCCEEDED(hr = m_pAudioEndpoint->GetLatency(&m_hnsEndpointLatency))) {
- return hr;
- }
-
- if (!VERIFY_SUCCEEDED(hr = m_hProcessThreadStartedEvent.create())) {
- return hr;
- }
-
- if (!VERIFY_SUCCEEDED(hr = m_hTerminate.create(wil::EventOptions::ManualReset))) {
- return hr;
- }
-
- if (!VERIFY_SUCCEEDED(hr = m_pAudioDeviceEndpoint->GetEventDrivenCapable(&bIsEventCapable))) {
- return hr;
- }
-
- if (bIsEventCapable || m_ConnectorType == eOffloadConnector) {
- m_bIsEventCapable = true;
- }
-
- if (m_bIsEventCapable)
- {
- if (!VERIFY_SUCCEEDED(hr = m_hEndpointBufferCompleteEvent.create())) {
- return hr;
- }
- if (!VERIFY_SUCCEEDED(hr = m_pAudioEndpoint->SetEventHandle(m_hEndpointBufferCompleteEvent.get()))) {
- return hr;
- }
- }
-
- if (!m_bIsEventCapable) {
- m_hTimer.reset(CreateWaitableTimerEx(NULL, NULL, 0, TIMER_ALL_ACCESS));
- }
-
- if (m_DataFlow == render) {
- m_pStreamRoutine = RenderStreamRoutine;
- }
- else {
- m_pStreamRoutine = CaptureStreamRoutine;
- }
-
- // To-do: Adjust for offload streaming
-
- m_bStreamInitialized = true;
-
- return hr;
-}
-
-HRESULT
-CHalfApp::CleanupStream
-(
- void
-)
-{
- HRESULT hr = S_OK;
-
- // If the thread thread is still active, stop it
- if (m_hStreamThread)
- {
- SignalAndWaitForThread();
- }
-
- m_hnsPeriod = 0;
- m_f32EndpointFrameRate = 0.F;
- m_hnsEndpointLatency = 0;
-
- m_pStreamRoutine = nullptr;
-
- m_hTerminate.reset();
- m_hEndpointBufferCompleteEvent.reset();
- m_hProcessThreadStartedEvent.reset();
- m_hTimer.reset();
-
- m_bIsEventCapable = false;
- m_bStreamInitialized = false;
- m_bStreamThreadTerminate = false;
- m_bYieldActive = false;
-
- return hr;
-}
-
-DWORD CALLBACK
-CHalfApp::RenderStreamRoutine
-(
- PVOID lpParameter
-)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-DWORD CALLBACK
-CHalfApp::CaptureStreamRoutine
-(
- PVOID lpParameter
-)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-HRESULT
-CHalfApp::StartStream
-(
- void
-)
-{
- HRESULT hr = S_OK;
-
- if (!VERIFY_IS_TRUE(m_bStreamInitialized)) {
- hr = AEERR_NOT_INITIALIZED;
- return hr;
- }
- if (!VERIFY_IS_TRUE(!m_hStreamThread)) {
- hr = AEERR_ALREADY_RUNNING;
- return hr;
- }
-
- m_bStreamThreadTerminate = false;
- m_hTerminate.ResetEvent();
- m_hProcessThreadStartedEvent.ResetEvent();
-
- DWORD dwThreadID;
- m_hStreamThread.reset(CreateThread(NULL, 0, m_pStreamRoutine, this, 0, &dwThreadID));
- if (!VERIFY_IS_NOT_NULL(m_hStreamThread)) {
- DWORD dwError = GetLastError();
- hr = HRESULT_FROM_WIN32(dwError);
- return hr;
- }
- if (m_hStreamThread)
- {
- SetThreadPriority(m_hStreamThread.get(), THREAD_PRIORITY_HIGHEST);
- }
-
- // Wait for the processing thread to be started or to error out. To avoid the Start call from being blocked forever, give up waiting after 10 seconds, which is a duration quite unlikely to hit -- something must have gone wrong in the thread creation.
- WaitForSingleObjectEx(m_hProcessThreadStartedEvent.get(), 10000, FALSE);
-
- // Set timer
- if (!m_bIsEventCapable) {
- SetTimer(m_hTimer.get(), m_hnsPeriod, true);
- }
-
- if (!VERIFY_SUCCEEDED(hr = StartEndpoint())) {
- return hr;
- }
-
- return hr;
-}
-
-HRESULT
-CHalfApp::StopStream
-(
- void
-)
-{
- HRESULT hr = S_OK;
-
- m_bStreamThreadTerminate = true;
-
- if (!VERIFY_IS_TRUE(m_bStreamInitialized)) {
- hr = AEERR_NOT_INITIALIZED;
- return hr;
- }
- if (!VERIFY_IS_NOT_NULL(m_hStreamThread)) {
- hr = AEERR_NOT_RUNNING;
- return hr;
- }
-
- SignalAndWaitForThread();
-
- //Cancel timer
- if (!m_bIsEventCapable) {
- CancelTimer(m_hTimer.get());
- }
-
- if (!VERIFY_SUCCEEDED(hr = StopEndpoint())) {
- return hr;
- }
-
- return hr;
-}
-
-void
-CHalfApp::SignalAndWaitForThread
-(
- void
-)
-{
- DWORD dwReturn;
-
- m_bStreamThreadTerminate = true;
- m_hTerminate.SetEvent();
-
- dwReturn = WaitForSingleObjectEx(m_hStreamThread.get(), INFINITE, FALSE);
-
- VERIFY_IS_TRUE(WAIT_OBJECT_0 == dwReturn);
-
- m_hStreamThread.reset();
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-inline HRESULT CHalfApp::SetTimer(HANDLE timer, HNSTIME timeDuration, bool fireImmediatley)
-{
- if (timer)
- {
- LARGE_INTEGER DueTime;
-
- if (fireImmediatley)
- {
- DueTime.QuadPart = 0;
- }
- else
- {
- // Negate this to mean relative in call to SetWaitableTimer
- DueTime.QuadPart = -timeDuration;
- }
-
- SetWaitableTimer(timer, &DueTime,
- static_cast(MF_TO_MS(timeDuration)),
- nullptr, nullptr, FALSE);
- }
- return S_OK;
-}
-
-inline void CHalfApp::CancelTimer(HANDLE timer)
-{
- if (timer)
- {
- // Cancel the waitable timer
- CancelWaitableTimer(timer);
-
- // There is a race condition where the timer could have fired before it was canceled, which would leave the handle set to fire the next time events are waited upon. CancelWaitableTimer will not reset the state of the handle so
- // wait for 0 ms for the timer to fire to clear it.
- WaitForSingleObject(timer, 0);
- }
-}
-
-HRESULT CHalfApp::GetPosition(UINT64* pu64Position, UINT64* pu64hnsQPCPosition)
-{
- HRESULT hr = S_OK;
- wil::com_ptr_nothrow spAudioClock;
- auto lock = m_CritSec.lock();
-
- if (!VERIFY_SUCCEEDED(m_pAudioDeviceEndpoint.query_to(&spAudioClock))) {
- return hr;
- }
- if (!VERIFY_SUCCEEDED(spAudioClock->GetPosition(pu64Position, pu64hnsQPCPosition))) {
- return hr;
- }
-
- return S_OK;
-}
diff --git a/audio/tests/wavetest/HalfApp.h b/audio/tests/wavetest/HalfApp.h
deleted file mode 100644
index 1bf14de9..00000000
--- a/audio/tests/wavetest/HalfApp.h
+++ /dev/null
@@ -1,195 +0,0 @@
-// ------------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft. All rights reserved.
-//
-// File Name:
-//
-// HalfApp.h
-//
-// Abstract:
-//
-// CHalfApp declarations
-//
-// -------------------------------------------------------------------------------
-#pragma once
-
-#define BUF_LEN_IN_MS 1000 // 1 second
-
-class CHalfApp
-{
-public:
- // Basic pin infos
- wil::com_ptr_nothrow m_pDevice;
- wil::unique_cotaskmem_string m_pwstrDeviceId;
- wil::unique_cotaskmem_string m_pwstrDeviceFriendlyName;
- STACKWISE_DATAFLOW m_DataFlow;
- EndpointConnectorType m_ConnectorType;
- UINT m_uConnectorId;
- GUID m_Mode;
- ULONG m_cModes;
- GUID* m_pModes; // All processing modes
-
- // Formats
- wil::unique_cotaskmem_ptr m_pPreferredFormat;
- UINT32 m_u32DefaultPeriodicityInFrames;
- UINT32 m_u32FundamentalPeriodicityInFrames;
- UINT32 m_u32MinPeriodicityInFrames;
- UINT32 m_u32MaxPeriodicityInFrames;
-
- PFORMAT_RECORD m_pFormatRecords;
- ULONG m_cFormatRecords;
-
- wil::unique_cotaskmem_ptr m_pCurrentFormat;
- UINT32 m_u32CurrentDefaultPeriodicityInFrames;
- UINT32 m_u32CurrentFundamentalPeriodicityInFrames;
- UINT32 m_u32CurrentMinPeriodicityInFrames;
- UINT32 m_u32CurrentMaxPeriodicityInFrames;
-
- // Audio endpoint interfaces
- wil::com_ptr_nothrow m_pAudioDeviceEndpoint;
- wil::com_ptr_nothrow m_pAudioEndpoint;
- wil::com_ptr_nothrow m_pAudioEndpointControl;
- wil::com_ptr_nothrow m_pAudioEndpointRT;
-
- // Data buffer
- wil::unique_hlocal_ptr m_pbSineToneDataBuffer;
- DWORD m_dwSineToneDataBufferSize;
- DWORD m_dwSineToneDataBufferPosition;
-
- // Stream
- HNSTIME m_hnsPeriod = 0;
- FLOAT32 m_f32EndpointFrameRate = 0.F;
- HNSTIME m_hnsEndpointLatency = 0;
- bool m_bIsEventCapable = false;
- bool m_bStreamInitialized = false;
- volatile bool m_bStreamThreadTerminate = false;
- bool m_bYieldActive = false;
- bool m_bIsBackupTimerRequired = true;
-
- wil::unique_handle m_hStreamThread;
-
- LPTHREAD_START_ROUTINE m_pStreamRoutine = nullptr;
- wil::unique_event_nothrow m_hProcessThreadStartedEvent;
- wil::unique_event_nothrow m_hTerminate;
- wil::unique_event_nothrow m_hEndpointBufferCompleteEvent;
- wil::unique_handle m_hTimer;
-
- wil::critical_section m_CritSec;
-
- typedef enum
- {
- ET_DO_NOTHING = 0x00,
- ET_TERMINATE = 0x01,
- ET_OBJECT_BUFFER_COMPLETE = 0x02,
- ET_CLIENT_RELEASE_BUFFER = 0x04,
- ET_TIMER = 0x08,
- ET_PAUSE_PUMP = 0x10,
- ET_RESUME_PUMP = 0x20,
- } TEventType;
-
- CHalfApp(
- _In_ IMMDevice* pDevice,
- _In_ LPWSTR pwstrAudioEndpointId,
- _In_ LPWSTR pwstrAudioEndpointFriendlyName,
- _In_ STACKWISE_DATAFLOW dataFlow,
- _In_ EndpointConnectorType eConnectorType,
- _In_ UINT uConnectorId,
- _In_ GUID mode,
- _In_ ULONG cModes,
- _In_ GUID* pModes,
- _In_ ULONG cFormatRecords,
- _In_ PFORMAT_RECORD pFormatRecords,
- _In_ PWAVEFORMATEX pPreferredFormat,
- _In_ UINT32 u32DefaultPeriodicityInFrames,
- _In_ UINT32 u32FundamentalPeriodicityInFrames,
- _In_ UINT32 u32MinPeriodicityInFrames,
- _In_ UINT32 u32MaxPeriodicityInFrames
- )
- : m_DataFlow(dataFlow)
- , m_ConnectorType(eConnectorType)
- , m_uConnectorId(uConnectorId)
- , m_cModes(cModes)
- , m_cFormatRecords(cFormatRecords)
- , m_u32DefaultPeriodicityInFrames(u32DefaultPeriodicityInFrames)
- , m_u32FundamentalPeriodicityInFrames(u32FundamentalPeriodicityInFrames)
- , m_u32MinPeriodicityInFrames(u32MinPeriodicityInFrames)
- , m_u32MaxPeriodicityInFrames(u32MaxPeriodicityInFrames)
- , m_u32CurrentDefaultPeriodicityInFrames(u32DefaultPeriodicityInFrames)
- , m_u32CurrentFundamentalPeriodicityInFrames(u32FundamentalPeriodicityInFrames)
- , m_u32CurrentMinPeriodicityInFrames(u32MinPeriodicityInFrames)
- , m_u32CurrentMaxPeriodicityInFrames(u32MaxPeriodicityInFrames)
- {
- m_pDevice = pDevice;
- m_pAudioDeviceEndpoint = nullptr;
- m_pAudioEndpointControl = nullptr;
-
- m_pwstrDeviceId = wil::make_cotaskmem_string_nothrow(pwstrAudioEndpointId, wcslen(pwstrAudioEndpointId));
- m_pwstrDeviceFriendlyName = wil::make_cotaskmem_string_nothrow(pwstrAudioEndpointFriendlyName, wcslen(pwstrAudioEndpointFriendlyName));
- m_Mode = mode;
-
- m_pModes = new GUID[cModes];
- memcpy(m_pModes, pModes, sizeof(GUID)*cModes);
- m_pFormatRecords = new FORMAT_RECORD[cFormatRecords];
- memcpy(m_pFormatRecords, pFormatRecords, sizeof(FORMAT_RECORD)*cFormatRecords);
-
- CloneWaveFormat(pPreferredFormat, wil::out_param(m_pPreferredFormat));
- CloneWaveFormat(pPreferredFormat, wil::out_param(m_pCurrentFormat)); // Use preferred format as current format
- }
-
- ~CHalfApp(void)
- {
- if (m_pModes)
- delete[] m_pModes;
- if (m_pFormatRecords)
- delete[] m_pFormatRecords;
- }
-
- // Audio endpoint interfaces
- HRESULT InitializeEndpoint();
- HRESULT ReleaseEndpoint();
- HRESULT StartEndpoint();
- HRESULT StopEndpoint();
- HRESULT ResetEndpoint();
-
- // Sine tone data buffer
- HRESULT CreateSineToneDataBuffer(WAVEFORMATEX* pWfx);
- HRESULT ReleaseSineToneDataBuffer();
-
-
-
-
- // Stream
- HRESULT InitializeAndSetBuffer(HNSTIME hnsPeriod, UINT32 u32LatencyCoefficient);
- HRESULT InitializeStream(HNSTIME requestedPeriodicity, UINT32 u32LatencyCoefficient);
- HRESULT CleanupStream();
- HRESULT StartStream();
- HRESULT StopStream();
- static DWORD CALLBACK RenderStreamRoutine(PVOID lpParameter);
- static DWORD CALLBACK CaptureStreamRoutine(PVOID lpParameter);
- void SignalAndWaitForThread();
-
-
-
- HRESULT SetTimer(HANDLE timer, HNSTIME timeDuration, bool fireImmediatley);
- void CancelTimer(HANDLE timer);
- HRESULT GetPosition(UINT64* pu64Position, UINT64* pu64hnsQPCPosition);
-
- // Multiple pin instances
- HRESULT GetCurrentAvailiablePinInstanceCount(UINT32* pAvailablePinInstanceCount);
- HRESULT GetSecondHalfApp(AUDIO_SIGNALPROCESSINGMODE secondMode, CHalfApp** ppSecondHalfApp);
-
- // Only for loopback testcases
- HRESULT GetHostHalfApp(CHalfApp** ppHostHalfApp);
-};
-
-// {571BF784-A9D6-420A-BCA0-C579A8710236}
-DEFINE_GUID(IID_IHalfAppContainer,
- 0x571bf784, 0xa9d6, 0x420a, 0xbc, 0xa0, 0xc5, 0x79, 0xa8, 071, 0x02, 0x36);
-
-DECLARE_INTERFACE_IID_(
-IHalfAppContainer,
-IUnknown,
-"571BF784-A9D6-420A-BCA0-C579A8710236")
-{
- STDMETHOD(GetHalfApp)(THIS_ CHalfApp ** ppHalfApp) PURE;
-};
diff --git a/audio/tests/wavetest/PreComp.h b/audio/tests/wavetest/PreComp.h
index 2044d6b1..76210090 100644
--- a/audio/tests/wavetest/PreComp.h
+++ b/audio/tests/wavetest/PreComp.h
@@ -24,13 +24,11 @@
#include
#include
#include
-#include
#include
#include
#include
-#include
#include
#include
#include
@@ -47,108 +45,3 @@
#define WARN(log, ...) BasicLogPrintf( log, XWARN, 1, __VA_ARGS__ )
#define BLOCK(log, ...) BasicLogPrintf( log, XBLOCK, 1, __VA_ARGS__ )
#define ERR(log, ...) BasicLogPrintf( log, XFAIL, 1, __VA_ARGS__ )
-
-// ------------------------------------------------------------------------------
-// Data flow
-enum STACKWISE_DATAFLOW { render, capture };
-
-// ------------------------------------------------------------------------------
-// Structs used to hold results of format records
-typedef struct
-{
- WAVEFORMATEXTENSIBLE wfxEx;
- UINT32 fundamentalPeriodInFrames;
- UINT32 defaultPeriodInFrames;
- UINT32 minPeriodInFrames;
- UINT32 maxPeriodInFrames;
- UINT32 maxPeriodInFramesExtended;
-} FORMAT_RECORD, *PFORMAT_RECORD;
-
-// ----------------------------------------------------------
-// Parameters for test sine tone
-#define TEST_AMPLITUDE 1.0f
-#define TEST_FREQUENCY 200.0f
-
-// ----------------------------------------------------------
-// Predefined format list for offload streaming
-#define COUNT_FORMATS 4
-
-static WAVEFORMATEXTENSIBLE ListofFormats[COUNT_FORMATS] =
-{
- // 1
- {
- // Format
- {
- WAVE_FORMAT_EXTENSIBLE, // wFormatTag
- 2, // nChannels
- 44100, // nSamplesPerSec
- 176400, // nAvgBytesPerSec
- 4, // nBlockAlign
- 16, // wBitsPerSample
- 22 // cbSize
- },
- // Samples
- {
- 16 // wValidBitsPerSample
- },
- KSAUDIO_SPEAKER_STEREO, // dwChannelMask
- KSDATAFORMAT_SUBTYPE_PCM // SubFormat
- },
- // 2
- {
- // Format
- {
- WAVE_FORMAT_EXTENSIBLE, // wFormatTag
- 2, // nChannels
- 48000, // nSamplesPerSec
- 192000, // nAvgBytesPerSec
- 4, // nBlockAlign
- 16, // wBitsPerSample
- 22 // cbSize
- },
- // Samples
- {
- 16 // wValidBitsPerSample
- },
- KSAUDIO_SPEAKER_STEREO, // dwChannelMask
- KSDATAFORMAT_SUBTYPE_PCM // SubFormat
- },
- // 3
- {
- // Format
- {
- WAVE_FORMAT_EXTENSIBLE, // wFormatTag
- 2, // nChannels
- 88200, // nSamplesPerSec
- 352800, // nAvgBytesPerSec
- 4, // nBlockAlign
- 16, // wBitsPerSample
- 22 // cbSize
- },
- // Samples
- {
- 16 // wValidBitsPerSample
- },
- KSAUDIO_SPEAKER_STEREO, // dwChannelMask
- KSDATAFORMAT_SUBTYPE_PCM // SubFormat
- },
- // 4
- {
- // Format
- {
- WAVE_FORMAT_EXTENSIBLE, // wFormatTag
- 2, // nChannels
- 96000, // nSamplesPerSec
- 384000, // nAvgBytesPerSec
- 4, // nBlockAlign
- 16, // wBitsPerSample
- 22 // cbSize
- },
- // Samples
- {
- 16 // wValidBitsPerSample
- },
- KSAUDIO_SPEAKER_STEREO, // dwChannelMask
- KSDATAFORMAT_SUBTYPE_PCM // SubFormat
- },
-};
\ No newline at end of file
diff --git a/audio/tests/wavetest/PropertyHelper.cpp b/audio/tests/wavetest/PropertyHelper.cpp
deleted file mode 100644
index fb60d3cc..00000000
--- a/audio/tests/wavetest/PropertyHelper.cpp
+++ /dev/null
@@ -1,1095 +0,0 @@
-// ------------------------------------------------------------------------------
-//
-// 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;
-}
diff --git a/audio/tests/wavetest/PropertyHelper.h b/audio/tests/wavetest/PropertyHelper.h
deleted file mode 100644
index 9f01a9a7..00000000
--- a/audio/tests/wavetest/PropertyHelper.h
+++ /dev/null
@@ -1,190 +0,0 @@
-// ------------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft. All rights reserved.
-//
-// Module Name:
-//
-// PropertyHelpers.h
-//
-// Abstract:
-//
-// Header for common helpers/defines of property
-//
-// -------------------------------------------------------------------------------
-#pragma once
-
-#define kSystemDefaultPeriod 100000 // 10 milliseconds
-#define kSystemMinPeriodForNonRTCapableEndpoints 20000 // 2 milliseconds
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-// ----------------------------------------------------------------------
-HRESULT GetConnectorId
-(
- IMMDevice* pDevice,
- EndpointConnectorType eConnectorType,
- bool* hasConnector,
- UINT* pConnectorId
-);
-
-// ----------------------------------------------------------------------
-HRESULT GetEndpointFriendlyName
-(
- IMMDevice* pDevice,
- LPWSTR* ppwszEndpointName
-);
-
-// ----------------------------------------------------------------------
-HRESULT GetAudioFilterAsDevice
-(
- IMMDevice* pDevice,
- IMMDevice** ppAudioFilterAsDevice
-);
-
-// ----------------------------------------------------------------------
-HRESULT GetCachedProcessingModes
-(
- IMMDevice* pDevice,
- EndpointConnectorType eConnectorType,
- ULONG *pCount,
- AUDIO_SIGNALPROCESSINGMODE **ppModes
-);
-
-
-
-
-
-
-
-
-
-
-
-
-// ----------------------------------------------------------------------
-HRESULT GetProcessingModes
-(
- IMMDevice* pDevice,
- UINT pinId,
- ULONG *pCount,
- AUDIO_SIGNALPROCESSINGMODE **ppModes
-);
-
-// ----------------------------------------------------------------------
-HRESULT GetCachedSupportedFormatRecords
-(
- IMMDevice* pDevice,
- EndpointConnectorType eConnectorType,
- AUDIO_SIGNALPROCESSINGMODE mode,
- ULONG *pCount,
- FORMAT_RECORD **ppFormatRecords
-);
-
-
-
-
-
-
-
-
-
-
-
-
-
-// ----------------------------------------------------------------------
-HRESULT GetSupportedFormatRecords
-(
- IMMDevice* pDevice,
- UINT pinId,
- EndpointConnectorType eConnectorType,
- AUDIO_SIGNALPROCESSINGMODE mode,
- STACKWISE_DATAFLOW dataFlow,
- ULONG *pCount,
- FORMAT_RECORD **ppFormatRecords
-);
-
-// ----------------------------------------------------------------------
-HRESULT IsFormatSupported
-(
- IMMDevice* pDevice,
- UINT pinId,
- WAVEFORMATEX *pWfx,
- BOOL* pbSupported
-);
-
-// ----------------------------------------------------------------------
-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 CheckConnectorSupportForPeriodicity
-(
- IMMDevice* pDevice,
- EndpointConnectorType eConnectorType,
- AUDIO_SIGNALPROCESSINGMODE mode,
- WAVEFORMATEX *pWfx,
- STACKWISE_DATAFLOW dataFlow,
- HNSTIME RequestedPeriodicity,
- UINT32 *pActualPeriodicityInFrames
-);
-
-// ----------------------------------------------------------------------
-HRESULT GetCachedDefaultFormat
-(
- IMMDevice* pDevice,
- EndpointConnectorType eConnectorType,
- WAVEFORMATEX** ppDefaultFormat
-);
-
-// ----------------------------------------------------------------------
-HRESULT GetProposedFormatForProcessingMode
-(
- IMMDevice* pDevice,
- UINT pinId,
- AUDIO_SIGNALPROCESSINGMODE mode,
- WAVEFORMATEX **ppProposedFormat
-);
-
-// ----------------------------------------------------------------------
-HRESULT GetAvailiablePinInstanceCount
-(
- IMMDevice* pDevice,
- UINT pinId,
- UINT32* pAvailablePinInstanceCount
-);
diff --git a/audio/tests/wavetest/TestResource.cpp b/audio/tests/wavetest/TestResource.cpp
deleted file mode 100644
index 67f3ca79..00000000
--- a/audio/tests/wavetest/TestResource.cpp
+++ /dev/null
@@ -1,331 +0,0 @@
-// ------------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft. All rights reserved.
-//
-// File Name:
-//
-// TestResource.cpp
-//
-// Abstract:
-//
-// TAEF Test Resource implementation
-//
-// -------------------------------------------------------------------------------
-
-#include "PreComp.h"
-#include "HalfApp.h"
-#include "TestResource.h"
-
-using namespace WEX::Logging;
-using namespace WEX::TestExecution;
-
-CPinTestResource::CPinTestResource() :
- m_cRef(1)
-{}
-
-CPinTestResource::~CPinTestResource()
-{}
-
-HRESULT STDMETHODCALLTYPE
-CPinTestResource::CreateInstance
-(
- CHalfApp * pHalf,
- REFGUID guid,
- ITestResource ** ppOut
-)
-{
- HRESULT hr = S_OK;
- CPinTestResource * pTestResource;
- SetVerifyOutput verifySettings(VerifyOutputSettings::LogOnlyFailures);
-
- if (!VERIFY_IS_NOT_NULL(pHalf))
- {
- return E_INVALIDARG;
- }
-
- if (!VERIFY_IS_NOT_NULL(ppOut))
- {
- return E_POINTER;
- }
-
- pTestResource = new CPinTestResource();
- if (!VERIFY_IS_NOT_NULL(pTestResource))
- {
- return E_OUTOFMEMORY;
- }
-
- if (!VERIFY_SUCCEEDED(hr = pTestResource->Initialize(
- pHalf, guid))) {
- pTestResource->Release();
- return hr;
- }
-
- *ppOut = pTestResource;
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE
-CPinTestResource::Initialize
-(
- CHalfApp * pHalf,
- REFGUID guid
-)
-{
- HRESULT hr = S_OK;
-
- WCHAR szStr[MAX_PATH];
- LPWSTR szMode;
- LPWSTR szPin;
-
- SetVerifyOutput verifySettings(VerifyOutputSettings::LogOnlyFailures);
-
- m_guid = guid;
- m_spHalfApp.Attach(pHalf);
-
- // Dataflow
- if (m_spHalfApp->m_DataFlow == capture)
- {
- m_szType.Attach(W2BSTR(L"Capture"));
- if (!VERIFY_IS_NOT_NULL(m_szType)) { return E_OUTOFMEMORY; }
- }
- else
- {
- m_szType.Attach(W2BSTR(L"Render"));
- if (!VERIFY_IS_NOT_NULL(m_szType)) { return E_OUTOFMEMORY; }
- }
-
- szMode = ModeName(m_spHalfApp->m_Mode);
- szPin = PinName(m_spHalfApp->m_ConnectorType);
-
- // Id: Combine device Id, pin type and mode
- m_szId.Attach(W2BSTR(m_spHalfApp->m_pwstrDeviceId.get()));
- if (!VERIFY_SUCCEEDED(hr = StringCchPrintfW(
- szStr, MAX_PATH, L"#%s#%s",
- szPin,
- szMode))) {
- return hr;
- }
- if (!VERIFY_SUCCEEDED(hr = m_szId.Append(szStr))) {
- return hr;
- }
- if (!VERIFY_IS_NOT_NULL(m_szId)) { return E_OUTOFMEMORY; }
-
- // Name: Combine device friendly name, pin type, and mode
- m_szName.Attach(W2BSTR(m_spHalfApp->m_pwstrDeviceFriendlyName.get()));
- if (!VERIFY_SUCCEEDED(hr = StringCchPrintfW(
- szStr, MAX_PATH, L" Pin %s Mode %s",
- szPin,
- szMode))) {
- return hr;
- }
- if (!VERIFY_SUCCEEDED(hr = m_szName.Append(szStr))) {
- return hr;
- }
- if (!VERIFY_IS_NOT_NULL(m_szName)) { return E_OUTOFMEMORY; }
-
- // Mode
- m_szMode.Attach(W2BSTR(szMode));
- if (!VERIFY_IS_NOT_NULL(m_szMode)) { return E_OUTOFMEMORY; }
-
- // Pin
- m_szPin.Attach(W2BSTR(szPin));
- if (!VERIFY_IS_NOT_NULL(m_szPin)) { return E_OUTOFMEMORY; }
-
- return hr;
-}
-
-STDMETHODIMP_(ULONG)
-CPinTestResource::AddRef()
-{
- return InterlockedIncrement(&m_cRef);
-}
-
-STDMETHODIMP_(ULONG)
-CPinTestResource::Release()
-{
- ULONG cRef = InterlockedDecrement(&m_cRef);
- if (0 == cRef)
- {
- delete this;
- }
-
- return cRef;
-}
-
-STDMETHODIMP
-CPinTestResource::QueryInterface(
- __in REFIID riid,
- __deref_out void ** ppvObject
-)
-{
- HRESULT hr = S_OK;
-
- //IF_FALSE_EXIT_HR( (NULL != ppvObject), E_POINTER);
-
- if (IsEqualIID(riid, __uuidof(IUnknown)))
- {
- *ppvObject = static_cast(this);
- }
- else if (IsEqualIID(riid, __uuidof(ITestResource)))
- {
- *ppvObject = static_cast(this);
- }
- else if (IsEqualIID(riid, __uuidof(IHalfAppContainer)))
- {
- *ppvObject = static_cast(this);
- }
- else
- {
- *ppvObject = NULL;
- hr = E_NOINTERFACE;
- goto Exit;
- }
-
- AddRef();
-
-Exit:
- return hr;
-}
-
-STDMETHODIMP
-CPinTestResource::GetGuid(GUID* pGuid) {
- // don't want to see VERIFY spew
- SetVerifyOutput verifySettings(VerifyOutputSettings::LogOnlyFailures);
-
- if (!VERIFY_IS_NOT_NULL(pGuid)) { return E_POINTER; }
-
- *pGuid = m_guid;
- return S_OK;
-}
-
-STDMETHODIMP
-CPinTestResource::SetGuid(GUID guid) {
- m_guid = guid;
- return S_OK;
-}
-
-STDMETHODIMP
-CPinTestResource::GetValue(BSTR name, BSTR* pValue) {
- // don't want to see VERIFY spew
- SetVerifyOutput verifySettings(VerifyOutputSettings::LogOnlyFailures);
-
- if (!VERIFY_IS_NOT_NULL(name)) { return E_POINTER; }
- if (!VERIFY_IS_NOT_NULL(pValue)) { return E_POINTER; }
-
- if (0 == wcscmp(name, TestResourceProperty::c_szName)) {
- if (!VERIFY_IS_NOT_NULL(*pValue = SysAllocString(m_szName))) { return E_OUTOFMEMORY; }
- return S_OK;
- }
-
- if (0 == wcscmp(name, TestResourceProperty::c_szId)) {
- if (!VERIFY_IS_NOT_NULL(*pValue = SysAllocString(m_szId))) { return E_OUTOFMEMORY; }
- return S_OK;
- }
-
- if (0 == wcscmp(name, TestResourceProperty::c_szType)) {
- if (!VERIFY_IS_NOT_NULL(*pValue = SysAllocString(m_szType))) { return E_OUTOFMEMORY; }
- return S_OK;
- }
-
- if (0 == wcscmp(name, TestResourceProperty::c_szMode)) {
- if (!VERIFY_IS_NOT_NULL(*pValue = SysAllocString(m_szMode))) { return E_OUTOFMEMORY; }
- return S_OK;
- }
-
- if (0 == wcscmp(name, TestResourceProperty::c_szPin)) {
- if (!VERIFY_IS_NOT_NULL(*pValue = SysAllocString(m_szPin))) { return E_OUTOFMEMORY; }
- return S_OK;
- }
-
- Log::Error(L"CDevice::GetValue name not found");
- return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
-}
-
-STDMETHODIMP
-CPinTestResource::SetValue(BSTR name, BSTR value) {
- // don't want to see VERIFY spew
- SetVerifyOutput verifySettings(VerifyOutputSettings::LogOnlyFailures);
-
- if (!VERIFY_IS_NOT_NULL(name)) { return E_POINTER; }
- if (!VERIFY_IS_NOT_NULL(value)) { return E_POINTER; }
-
- if (0 == wcscmp(name, TestResourceProperty::c_szName)) {
- return m_szName.AssignBSTR(value);
- }
-
- if (0 == wcscmp(name, TestResourceProperty::c_szId)) {
- return m_szId.AssignBSTR(value);
- }
-
- if (0 == wcscmp(name, TestResourceProperty::c_szType)) {
- return m_szType.AssignBSTR(value);
- }
-
- if (0 == wcscmp(name, TestResourceProperty::c_szMode)) {
- return m_szMode.AssignBSTR(value);
- }
-
- if (0 == wcscmp(name, TestResourceProperty::c_szPin)) {
- return m_szPin.AssignBSTR(value);
- }
-
- Log::Error(L"CDevice::SetValue name not found");
-
- return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
-}
-
-STDMETHODIMP
-CPinTestResource::GetHalfApp(CHalfApp ** ppHalfApp)
-{
- SetVerifyOutput verifySettings(VerifyOutputSettings::LogOnlyFailures);
-
- if (!VERIFY_IS_NOT_NULL(ppHalfApp)) { return E_POINTER; }
-
- *ppHalfApp = m_spHalfApp;
-
- return S_OK;
-}
-
-static const struct
-{
- GUID mode;
- LPWSTR name;
-}knownModes[] =
-{
- { GUID_NULL, L"NO_MODE" },
- { AUDIO_SIGNALPROCESSINGMODE_RAW, L"RAW" },
- { AUDIO_SIGNALPROCESSINGMODE_DEFAULT, L"DEFAULT" },
- { AUDIO_SIGNALPROCESSINGMODE_COMMUNICATIONS, L"COMMUNICATIONS" },
- { AUDIO_SIGNALPROCESSINGMODE_SPEECH, L"SPEECH" },
- { AUDIO_SIGNALPROCESSINGMODE_MEDIA, L"MEDIA" },
- { AUDIO_SIGNALPROCESSINGMODE_MOVIE, L"MOVIE" },
- { AUDIO_SIGNALPROCESSINGMODE_NOTIFICATION, L"NOTIFICATION" },
-};
-
-
-LPWSTR CPinTestResource::ModeName(REFGUID guidMode)
-{
- for (auto m : knownModes)
- {
- if (m.mode == guidMode) { return m.name; }
- }
-
- return L"UNKNOWN";
-}
-
-LPWSTR CPinTestResource::PinName(EndpointConnectorType eConnectorType)
-{
- switch (eConnectorType)
- {
- case eHostProcessConnector:
- return L"HOST";
- case eOffloadConnector:
- return L"OFFLOAD";
- case eLoopbackConnector:
- return L"LOOPBACK";
- case eKeywordDetectorConnector:
- return L"KEYWORD";
- default:
- return L"UNKNOWN";
- }
-}
\ No newline at end of file
diff --git a/audio/tests/wavetest/TestResource.h b/audio/tests/wavetest/TestResource.h
deleted file mode 100644
index 49dee5a5..00000000
--- a/audio/tests/wavetest/TestResource.h
+++ /dev/null
@@ -1,66 +0,0 @@
-// ------------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft. All rights reserved.
-//
-// File Name:
-//
-// TestResource.h
-//
-// Abstract:
-//
-// TAEF Test Resource
-//
-// -------------------------------------------------------------------------------
-#include "WaveTestTaef.h"
-
-class CPinTestResource :
- public WEX::TestExecution::ITestResource,
- public IHalfAppContainer
-{
-public:
- //IUnknown
- STDMETHODIMP_(ULONG) AddRef();
- STDMETHODIMP_(ULONG) Release();
- STDMETHODIMP QueryInterface(
- __in REFIID riid,
- __deref_out VOID **ppvObject
- );
- // ITestResouce
- STDMETHODIMP GetGuid(GUID* pGuid);
- STDMETHODIMP SetGuid(GUID guid);
- STDMETHODIMP GetValue(BSTR name, BSTR* pValue);
- STDMETHODIMP SetValue(BSTR name, BSTR value);
-
- //IHalfAppContainer
- STDMETHODIMP GetHalfApp(CHalfApp ** ppHalfApp);
-
- static HRESULT STDMETHODCALLTYPE CreateInstance(
- CHalfApp * pHalf,
- REFGUID guid,
- WEX::TestExecution::ITestResource ** ppOut
- );
-
-private:
-
- CPinTestResource();
- ~CPinTestResource();
-
- HRESULT STDMETHODCALLTYPE Initialize(
- CHalfApp * pHalf,
- REFGUID guid
- );
-
- LPWSTR ModeName(REFGUID guidMode);
- LPWSTR PinName(EndpointConnectorType eConnectorType);
-
- CComBSTR m_szType;
- CComBSTR m_szName;
- CComBSTR m_szId;
- CComBSTR m_szMode;
- CComBSTR m_szPin;
-
- CAutoPtr m_spHalfApp;
-
- ULONG m_cRef;
- GUID m_guid;
-};
\ No newline at end of file
diff --git a/audio/tests/wavetest/TestResourceBuild.cpp b/audio/tests/wavetest/TestResourceBuild.cpp
index 51cce52d..5ca2ff0d 100644
--- a/audio/tests/wavetest/TestResourceBuild.cpp
+++ b/audio/tests/wavetest/TestResourceBuild.cpp
@@ -12,8 +12,8 @@
//
// ------------------------------------------------------------------------------
#include "PreComp.h"
-#include "TestResource.h"
-#include "PropertyHelper.h"
+#include
+#include
using namespace WEX::Common;
using namespace WEX::Logging;
@@ -30,32 +30,18 @@ using namespace WEX::TestExecution;
HRESULT CreateTestResource
(
ResourceList& resourceList,
- LPWSTR deviceId,
- LPWSTR deviceName,
- IMMDevice* pDevice,
- STACKWISE_DATAFLOW dataFlow,
- EndpointConnectorType eConnectorType,
- UINT uConnectorId,
- AUDIO_SIGNALPROCESSINGMODE mode,
- ULONG cModes,
- AUDIO_SIGNALPROCESSINGMODE* pModes,
- ULONG cFormatRecords,
- PFORMAT_RECORD pFormatRecords,
- PWAVEFORMATEX pPreferredFormat,
- UINT32 defaultPeriodicityInFrames,
- UINT32 fundamentalPeriodicityInFrames,
- UINT32 minPeriodicityInFrames,
- UINT32 maxPeriodicityInFrames
+ DeviceDescriptor descriptor
)
{
HRESULT hr = S_OK;
+
CComHeapPtr spHalfApp;
wil::com_ptr_nothrow spTestResource;
GUID ResourceGUID;
CComBSTR szResourceName;
// Create HalfApp
- spHalfApp.Attach(new CHalfApp(pDevice, deviceId, deviceName, dataFlow, eConnectorType, uConnectorId, mode, cModes, pModes, cFormatRecords, pFormatRecords, pPreferredFormat, defaultPeriodicityInFrames, fundamentalPeriodicityInFrames, minPeriodicityInFrames, maxPeriodicityInFrames));
+ spHalfApp.Attach(new CHalfApp(descriptor));
if (!VERIFY_IS_NOT_NULL(spHalfApp)) {
hr = E_OUTOFMEMORY;
return hr;
@@ -327,6 +313,7 @@ HRESULT AddTestResourceForConnector
UINT32 u32MinPeriodicityInFrames;
UINT32 u32MaxPeriodicityInFrames;
UINT32 u32MaxPeriodicityInFramesExtended;
+ bool isAVStream = false;
// Get connector id
if (!VERIFY_SUCCEEDED(hr = GetConnectorId(pDevice, eConnectorType, &bHasConnector, &uConnectorId))) {
@@ -338,6 +325,7 @@ HRESULT AddTestResourceForConnector
Log::Comment(String().Format(L"Adding Test Resource for pin [%u]:", (uConnectorId & PARTID_MASK)));
+
// Get all signal processing modes for connector
if (!VERIFY_SUCCEEDED(hr = GetProcessingModesForConnector(pDevice, uConnectorId, eConnectorType, &cModes, &spModes))) {
return hr;
@@ -345,6 +333,7 @@ HRESULT AddTestResourceForConnector
// Loop through each mode, get preferred format and list of formats and create test resource for each mode
for (ULONG i = 0; i < cModes; i++) {
+
mode = spModes[i];
if (!VERIFY_SUCCEEDED(hr = GetSupportedFormatRecordsForConnector(pDevice, uConnectorId, eConnectorType, mode, dataFlow, &cFormatRecords, &spFormatRecords))) {
@@ -358,8 +347,32 @@ HRESULT AddTestResourceForConnector
if (!VERIFY_SUCCEEDED(hr = GetPreferredFormatPeriodicityCharacteristicsForConnector(pDevice, eConnectorType, mode, dataFlow, pPreferredFormat.get(), cFormatRecords, spFormatRecords, &u32DefaultPeriodicityInFrames, &u32FundamentalPeriodicityInFrames, &u32MinPeriodicityInFrames, &u32MaxPeriodicityInFrames, &u32MaxPeriodicityInFramesExtended))) {
return hr;
}
-
- if (!VERIFY_SUCCEEDED(hr = CreateTestResource(resourceList, deviceId, deviceName, pDevice, dataFlow, eConnectorType, uConnectorId, mode, cModes, spModes, cFormatRecords, spFormatRecords, pPreferredFormat.get(), u32DefaultPeriodicityInFrames, u32FundamentalPeriodicityInFrames, u32MinPeriodicityInFrames, u32MaxPeriodicityInFrames))) {
+
+ // Check if audio endpoint is AVStream
+ if (!VERIFY_SUCCEEDED(hr = IsAVStream(pDevice, &isAVStream))) {
+ return hr;
+ }
+
+ DeviceDescriptor descriptor = { 0 };
+ descriptor.pDevice = pDevice;
+ descriptor.pwstrAudioEndpointId = deviceId;
+ descriptor.pwstrAudioEndpointFriendlyName = deviceName;
+ descriptor.dataFlow = dataFlow;
+ descriptor.eConnectorType = eConnectorType;
+ descriptor.uConnectorId = uConnectorId;
+ descriptor.mode = mode;
+ descriptor.cModes = cModes;
+ descriptor.pModes = spModes;
+ descriptor.cFormatRecords = cFormatRecords;
+ descriptor.pFormatRecords = spFormatRecords;
+ descriptor.pPreferredFormat = pPreferredFormat.get();
+ descriptor.u32DefaultPeriodicityInFrames = u32DefaultPeriodicityInFrames;
+ descriptor.u32FundamentalPeriodicityInFrames = u32FundamentalPeriodicityInFrames;
+ descriptor.u32MinPeriodicityInFrames = u32MinPeriodicityInFrames;
+ descriptor.u32MaxPeriodicityInFrames = u32MaxPeriodicityInFrames;
+ descriptor.bIsAVStream = isAVStream;
+
+ if (!VERIFY_SUCCEEDED(hr = CreateTestResource(resourceList, descriptor))) {
return hr;
}
}
diff --git a/audio/tests/wavetest/TestResourceHelper.h b/audio/tests/wavetest/TestResourceHelper.h
deleted file mode 100644
index 24bae634..00000000
--- a/audio/tests/wavetest/TestResourceHelper.h
+++ /dev/null
@@ -1,71 +0,0 @@
-// ------------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft. All rights reserved.
-//
-// Module Name:
-//
-// TestResourceHelpers.h
-//
-// Abstract:
-//
-// Header for BuildResourceList helpers.
-//
-// -------------------------------------------------------------------------------
-#pragma once
-
-// ----------------------------------------------------------------------
-HRESULT GetProcessingModesForConnector
-(
- IMMDevice* pDevice,
- UINT uConnectorId,
- EndpointConnectorType eConnectorType,
- ULONG* pCount,
- AUDIO_SIGNALPROCESSINGMODE** ppModes
-);
-
-// ----------------------------------------------------------------------
-HRESULT GetDefaultFormatForConnector
-(
- IMMDevice* pDevice,
- EndpointConnectorType eConnectorType,
- WAVEFORMATEX** ppDefaultFormat
-);
-
-// ----------------------------------------------------------------------
-HRESULT GetPreferredFormatForConnector
-(
- IMMDevice* pDevice,
- UINT uConnectorId,
- EndpointConnectorType eConnectorType,
- AUDIO_SIGNALPROCESSINGMODE mode,
- WAVEFORMATEX** ppPreferredFormat
-);
-
-// ----------------------------------------------------------------------
-HRESULT GetPreferredFormatPeriodicityCharacteristicsForConnector
-(
- IMMDevice* pDevice,
- EndpointConnectorType eConnectorType,
- AUDIO_SIGNALPROCESSINGMODE mode,
- STACKWISE_DATAFLOW dataFlow,
- WAVEFORMATEX* pPreferredFormat,
- ULONG cFormatRecords,
- PFORMAT_RECORD pFormatRecords,
- UINT32* pDefaultPeriodicityInFrames,
- UINT32* pFundamentalPeriodicityInFrames,
- UINT32* pMinPeriodicityInFrames,
- UINT32* pMaxPeriodicityInFrames,
- UINT32* pMaxPeriodicityInFramesExtended
-);
-
-// ----------------------------------------------------------------------
-HRESULT GetSupportedFormatRecordsForConnector
-(
- IMMDevice* pDevice,
- UINT uConnectorId,
- EndpointConnectorType eConnectorType,
- AUDIO_SIGNALPROCESSINGMODE mode,
- STACKWISE_DATAFLOW dataFlow,
- ULONG* pCount,
- FORMAT_RECORD** ppFormatRecords
-);
\ No newline at end of file
diff --git a/audio/tests/wavetest/WaveTestTaef.cpp b/audio/tests/wavetest/WaveTestTaef.cpp
index dacf44ab..be5d47f3 100644
--- a/audio/tests/wavetest/WaveTestTaef.cpp
+++ b/audio/tests/wavetest/WaveTestTaef.cpp
@@ -164,7 +164,7 @@ void WDMAudio::WaveTest::TAEF_StreamMultipleModes()
RUN_TEST_CASE(Test_StreamMultipleModes)
}
-void WDMAudio::WaveTest::TAEF_VerifyPinSupportsPullMode()
+void WDMAudio::WaveTest::TAEF_VerifyPinWaveRTConformance()
{
- RUN_TEST_CASE(Test_VerifyPinSupportsPullMode)
-}
\ No newline at end of file
+ RUN_TEST_CASE(Test_VerifyPinWaveRTConformance)
+}
diff --git a/audio/tests/wavetest/WaveTestTaef.h b/audio/tests/wavetest/WaveTestTaef.h
index a8d38305..8c87a7f8 100644
--- a/audio/tests/wavetest/WaveTestTaef.h
+++ b/audio/tests/wavetest/WaveTestTaef.h
@@ -13,7 +13,7 @@
// -------------------------------------------------------------------------------
#pragma once
-#include "HalfApp.h"
+#include
extern IBasicLog* g_pBasicLog;
@@ -41,6 +41,7 @@ namespace WDMAudio
TEST_CLASS_PROPERTY(L"Kits.SupportedOS", L"Windows v10.0 Server x64")
TEST_CLASS_PROPERTY(L"Kits.MinRelease", L"19H1")
TEST_CLASS_PROPERTY(L"Kits.CorePackageComposition", L"Full")
+ TEST_CLASS_PROPERTY(L"Kits.CorePackageComposition", L"OnecoreUAP")
TEST_CLASS_PROPERTY(L"Kits.IsInProc", L"True")
TEST_CLASS_PROPERTY(L"Kits.Parameter", L"DeviceID")
TEST_CLASS_PROPERTY(L"Kits.Parameter.DeviceID.Description", L"Device id of device under test")
@@ -109,7 +110,7 @@ namespace WDMAudio
TEST_METHOD_PROPERTY(L"ResourceSelection", L"@Id = '*RAW' OR @Id = '*DEFAULT'")
END_TEST_METHOD()
- BEGIN_TEST_METHOD(TAEF_VerifyPinSupportsPullMode)
+ BEGIN_TEST_METHOD(TAEF_VerifyPinWaveRTConformance)
TEST_METHOD_PROPERTY(L"HCKCategory", L"Functional")
TEST_METHOD_PROPERTY(L"HCKCategory", L"Certification")
TEST_METHOD_PROPERTY(L"TestClassification:Scope", L"Feature")
diff --git a/audio/tests/wavetest/comptest.cpp b/audio/tests/wavetest/comptest.cpp
index ef41972c..db823156 100644
--- a/audio/tests/wavetest/comptest.cpp
+++ b/audio/tests/wavetest/comptest.cpp
@@ -17,8 +17,8 @@
#include "tests.h"
// ------------------------------------------------------------------------------
-// Test_VerifyPinSupportsPullMode: Test the requirement that WaveRT drivers must support pull mode audio streaming technology.
-void Test_VerifyPinSupportsPullMode(void)
+// Test_VerifyPinSupportsPullMode: Test the requirement that new drivers must be WaveRT and WaveRT drivers must support event driven audio streaming technology.
+void Test_VerifyPinWaveRTConformance(void)
{
CHalfApp* pHalfApp = g_pWaveTest->m_pHalf;
BOOL bIsRTCapable = false;
@@ -28,10 +28,17 @@ void Test_VerifyPinSupportsPullMode(void)
VERIFY_SUCCEEDED(pHalfApp->m_pAudioDeviceEndpoint->GetRTCaps(&bIsRTCapable));
- // Only require pull mode for WaveRT drivers
+ // Check for our new requirement - new drivers must be WaveRT. Here we skip the test on AVStream (UAC1/HFP/A2dp)
+ // For other old drivers that are not WaveRT, may issue Errata to cover the failure.
+ if (!pHalfApp->m_bIsAVStream)
+ {
+ VERIFY_IS_TRUE(bIsRTCapable);
+ }
+
+ // Only require event driven for WaveRT drivers
if (bIsRTCapable)
{
VERIFY_SUCCEEDED(pHalfApp->m_pAudioDeviceEndpoint->GetEventDrivenCapable(&bIsEventCapable));
VERIFY_IS_TRUE(bIsEventCapable);
}
-}
\ No newline at end of file
+}
diff --git a/audio/tests/wavetest/tests.h b/audio/tests/wavetest/tests.h
index 38a6aaa1..e3ae0691 100644
--- a/audio/tests/wavetest/tests.h
+++ b/audio/tests/wavetest/tests.h
@@ -24,4 +24,4 @@ void Test_LoopbackStreamDifferentFormat(void);
void Test_StreamMultipleModes(void);
// Compliance test
-void Test_VerifyPinSupportsPullMode(void);
\ No newline at end of file
+void Test_VerifyPinWaveRTConformance(void);
\ No newline at end of file
--
cgit v1.3.1