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: [PATCH] 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 +-
.../EndpointsCommon/minwavertstream.cpp | 4 +-
audio/sysvad/EndpointsCommon/speakertopo.cpp | 1 -
.../sysvad/EndpointsCommon/speakertoptable.h | 13 +-
audio/sysvad/Package/package.VcxProj | 4 +-
.../ComponentizedApoSample.inx | Bin 18736 -> 18770 bytes
.../ComponentizedAudioSample.inx | Bin 50422 -> 50456 bytes
.../ComponentizedAudioSampleExtension.inx | Bin 11224 -> 11262 bytes
.../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 ++
.../HalfApp.cpp | 73 ++-
audio/tests/PinResourceHelpers/PreComp.h | 143 +++++
.../PropertyHelper.cpp | 172 +++++-
.../TestResource.cpp | 6 +-
.../TestResourceHelper.h | 4 +-
audio/tests/wavetest/HalfApp.h | 195 -------
audio/tests/wavetest/PreComp.h | 107 ----
audio/tests/wavetest/PropertyHelper.h | 190 -------
audio/tests/wavetest/TestResource.h | 66 ---
audio/tests/wavetest/TestResourceBuild.cpp | 55 +-
audio/tests/wavetest/WaveTestTaef.cpp | 6 +-
audio/tests/wavetest/WaveTestTaef.h | 5 +-
audio/tests/wavetest/comptest.cpp | 15 +-
audio/tests/wavetest/tests.h | 2 +-
32 files changed, 1905 insertions(+), 630 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
rename audio/tests/{wavetest => PinResourceHelpers}/HalfApp.cpp (88%)
create mode 100644 audio/tests/PinResourceHelpers/PreComp.h
rename audio/tests/{wavetest => PinResourceHelpers}/PropertyHelper.cpp (80%)
rename audio/tests/{wavetest => PinResourceHelpers}/TestResource.cpp (99%)
rename audio/tests/{wavetest => PinResourceHelpers}/TestResourceHelper.h (98%)
delete mode 100644 audio/tests/wavetest/HalfApp.h
delete mode 100644 audio/tests/wavetest/PropertyHelper.h
delete mode 100644 audio/tests/wavetest/TestResource.h
diff --git a/audio/sysvad/EndpointsCommon/mintopo.cpp b/audio/sysvad/EndpointsCommon/mintopo.cpp
index 28ddf4199..4f2bf4fab 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 4aa3d2de4..266fc81d5 100644
--- a/audio/sysvad/EndpointsCommon/mintopo.h
+++ b/audio/sysvad/EndpointsCommon/mintopo.h
@@ -73,17 +73,17 @@ class CMiniportTopology :
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 93ecdcf33..499d5b38e 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 cca4dac94..fee3d5428 100644
--- a/audio/sysvad/EndpointsCommon/speakertopo.cpp
+++ b/audio/sysvad/EndpointsCommon/speakertopo.cpp
@@ -22,7 +22,6 @@ Module Name:
#pragma code_seg("PAGE")
-
//=============================================================================
NTSTATUS
PropertyHandler_SpeakerTopoFilter
diff --git a/audio/sysvad/EndpointsCommon/speakertoptable.h b/audio/sysvad/EndpointsCommon/speakertoptable.h
index 50f58c7b8..eb12173a0 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 cef0bc336..0b47036c5 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 a6bfb4aff26a56ddd998f694ad9c8d3c38752e36..be9428fba5995db714b96ffb517889470baf5269 100644
GIT binary patch
delta 40
ucmdlmiSg1T#tr)zMFSY}7z!AC81fmC8L}B%fOI)S-eg4w;mt=FbKC*^mJ6-`
delta 14
UcmcaKiE#rE?PJ{hfU(FO05dWMWdHyG
diff --git a/audio/sysvad/TabletAudioSample/ComponentizedAudioSample.inx b/audio/sysvad/TabletAudioSample/ComponentizedAudioSample.inx
index a5e6e73f551052d1c108d1b2a61b55e4df5f63c2..ccaa7327351e8e6d69e008a44def3af7e9338abe 100644
GIT binary patch
delta 44
vcmey?$vmTrc|#tfYyd+ZLji*iLq0lJjN9`W8Tq9FQR@qw
delta 18
acmZ3mljYwImJKD0&C?jSPh(`{k_G@z2L{Uk
diff --git a/audio/sysvad/sysvad.sln b/audio/sysvad/sysvad.sln
index 1935f7493..6a58b6df1 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 000000000..b92f9e4f4
--- /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 000000000..5fdfc9db6
--- /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 000000000..93959089c
--- /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 000000000..60336eb50
--- /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 000000000..57e35b07c
--- /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 000000000..ec0a68cc3
--- /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 000000000..d8026716e
--- /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/wavetest/HalfApp.cpp b/audio/tests/PinResourceHelpers/HalfApp.cpp
similarity index 88%
rename from audio/tests/wavetest/HalfApp.cpp
rename to audio/tests/PinResourceHelpers/HalfApp.cpp
index 14a15c080..83c9c8f31 100644
--- a/audio/tests/wavetest/HalfApp.cpp
+++ b/audio/tests/PinResourceHelpers/HalfApp.cpp
@@ -12,15 +12,16 @@
//
// -------------------------------------------------------------------------------
-#include "PreComp.h"
-#include "WaveTestTaef.h"
-#include "HalfApp.h"
-#include "TestResourceHelper.h"
-#include "PropertyHelper.h"
-#include
-#include
-#include
-#include
+
+
+
+
+
+
+
+
+
+
HRESULT
CHalfApp::InitializeEndpoint
@@ -114,6 +115,9 @@ CHalfApp::InitializeEndpoint
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;
}
@@ -134,6 +138,7 @@ CHalfApp::ReleaseEndpoint
m_pAudioEndpointControl.reset();
m_pAudioEndpoint.reset();
m_pAudioEndpointRT.reset();
+ m_pAudioClock.reset();
return hr;
}
@@ -380,6 +385,7 @@ CHalfApp::GetSecondHalfApp
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;
@@ -393,7 +399,26 @@ CHalfApp::GetSecondHalfApp
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);
+ 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;
@@ -432,6 +457,7 @@ CHalfApp::GetHostHalfApp
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);
@@ -474,7 +500,26 @@ CHalfApp::GetHostHalfApp
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);
+ 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;
@@ -987,13 +1032,9 @@ inline void CHalfApp::CancelTimer(HANDLE timer)
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))) {
+ if (!VERIFY_SUCCEEDED(m_pAudioClock->GetPosition(pu64Position, pu64hnsQPCPosition))) {
return hr;
}
diff --git a/audio/tests/PinResourceHelpers/PreComp.h b/audio/tests/PinResourceHelpers/PreComp.h
new file mode 100644
index 000000000..85fc4f833
--- /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/wavetest/PropertyHelper.cpp b/audio/tests/PinResourceHelpers/PropertyHelper.cpp
similarity index 80%
rename from audio/tests/wavetest/PropertyHelper.cpp
rename to audio/tests/PinResourceHelpers/PropertyHelper.cpp
index fb60d3cc9..6e85e53ee 100644
--- a/audio/tests/wavetest/PropertyHelper.cpp
+++ b/audio/tests/PinResourceHelpers/PropertyHelper.cpp
@@ -4,7 +4,7 @@
//
// Module Name:
//
-// EndpointPropertyHelpers.cpp
+// PropertyHelper.cpp
//
// Abstract:
//
@@ -14,7 +14,8 @@
#include "PreComp.h"
#include
#include
-#include "PropertyHelper.h"
+#include
+#include
///////////////////////////////////////////////////////////////////////////////////////////////////////////
//
@@ -722,6 +723,8 @@ HRESULT IsFormatSupported
return hr;
}
+ CoTaskMemFree(pKsRequestedFormat);
+
return hr;
}
@@ -1093,3 +1096,168 @@ HRESULT GetAvailiablePinInstanceCount
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/wavetest/TestResource.cpp b/audio/tests/PinResourceHelpers/TestResource.cpp
similarity index 99%
rename from audio/tests/wavetest/TestResource.cpp
rename to audio/tests/PinResourceHelpers/TestResource.cpp
index 67f3ca79f..f3762b848 100644
--- a/audio/tests/wavetest/TestResource.cpp
+++ b/audio/tests/PinResourceHelpers/TestResource.cpp
@@ -13,8 +13,8 @@
// -------------------------------------------------------------------------------
#include "PreComp.h"
-#include "HalfApp.h"
-#include "TestResource.h"
+#include
+#include
using namespace WEX::Logging;
using namespace WEX::TestExecution;
@@ -328,4 +328,4 @@ LPWSTR CPinTestResource::PinName(EndpointConnectorType eConnectorType)
default:
return L"UNKNOWN";
}
-}
\ No newline at end of file
+}
diff --git a/audio/tests/wavetest/TestResourceHelper.h b/audio/tests/PinResourceHelpers/TestResourceHelper.h
similarity index 98%
rename from audio/tests/wavetest/TestResourceHelper.h
rename to audio/tests/PinResourceHelpers/TestResourceHelper.h
index 24bae634a..08fafa23d 100644
--- a/audio/tests/wavetest/TestResourceHelper.h
+++ b/audio/tests/PinResourceHelpers/TestResourceHelper.h
@@ -13,6 +13,8 @@
// -------------------------------------------------------------------------------
#pragma once
+#include
+
// ----------------------------------------------------------------------
HRESULT GetProcessingModesForConnector
(
@@ -68,4 +70,4 @@ HRESULT GetSupportedFormatRecordsForConnector
STACKWISE_DATAFLOW dataFlow,
ULONG* pCount,
FORMAT_RECORD** ppFormatRecords
-);
\ No newline at end of file
+);
diff --git a/audio/tests/wavetest/HalfApp.h b/audio/tests/wavetest/HalfApp.h
deleted file mode 100644
index 1bf14de91..000000000
--- 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 2044d6b12..76210090e 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.h b/audio/tests/wavetest/PropertyHelper.h
deleted file mode 100644
index 9f01a9a79..000000000
--- 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.h b/audio/tests/wavetest/TestResource.h
deleted file mode 100644
index 49dee5a56..000000000
--- 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 51cce52dd..5ca2ff0d2 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/WaveTestTaef.cpp b/audio/tests/wavetest/WaveTestTaef.cpp
index dacf44ab9..be5d47f31 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 a8d38305a..8c87a7f85 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 ef41972cb..db823156d 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 38a6aaa17..e3ae06913 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