1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
|
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
PURPOSE.
Module Name:
KeywordDetector.h
Abstract:
Sample Keyword Detector.
--*/
#pragma once
#include <wil\resource.h>
#include "ContosoEventDetector.h"
#include "soundwirecontroller.h"
#include "sdcastreaming.h"
#define KEYWORDDETECTOR_POOLTAG 'KWS0'
typedef struct
{
VAD_DESCRIPTOR Descriptor;
WAVEFORMATEXTENSIBLE ExtraFormats[10];
} VAD_DESCRIPTOR_FORMAT, * PVAD_DESCRIPTOR_FORMAT;
typedef struct
{
ULONG EntitiesCount;
ENTITY_INFO ExtraEntities[25];
} VAD_ENTITIES_EXTRA, * PVAD_ENTITIES_EXTRA;
class CKeywordDetector
{
public:
CKeywordDetector(_In_ WDFDEVICE Device, _In_ ACXCIRCUIT Circuit, _In_ PWAVEFORMATEXTENSIBLE Format);
~CKeywordDetector();
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS Initialize();
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS ResetDetector(_In_ GUID eventId);
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS DownloadDetectorData(_In_ GUID eventId, _In_ LONGLONG Data);
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS GetDetectorData(_In_ GUID eventId, _Out_ LONGLONG *Data);
_IRQL_requires_max_(PASSIVE_LEVEL)
ULONGLONG GetStartTimestamp();
_IRQL_requires_max_(PASSIVE_LEVEL)
ULONGLONG GetStopTimestamp();
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS SetArmed(_In_ GUID eventId, _In_ BOOLEAN Arm);
_IRQL_requires_max_(PASSIVE_LEVEL)
VOID NotifyDetection();
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS GetArmed(_In_ GUID eventId, _Out_ BOOLEAN *Arm);
_IRQL_requires_max_(PASSIVE_LEVEL)
VOID Run();
_IRQL_requires_max_(PASSIVE_LEVEL)
VOID Stop();
_IRQL_requires_min_(DISPATCH_LEVEL)
VOID DpcRoutine(_In_ LONGLONG PerformanceCounter, _In_ LONGLONG PerformanceFrequency, _Out_ BOOLEAN *isRealtime, _Out_ LONGLONG *NewPacketNumber, _Out_ ULONGLONG *NewPerformanceCount);
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS GetReadPacket(_In_ ULONG PacketCount, _In_ ULONG PacketSize, _In_reads_(PacketSize) PVOID *Packets, _Out_ ULONG *PacketNumber,
_Out_ ULONGLONG *PerformanceCount, _Out_ BOOLEAN *MoreData, _Out_ ULONG *NextPacketNumber, _Out_ ULONGLONG *NextPerformanceCount);
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS GetFifoStart(_Out_ ULONG *PacketNumber, _Out_ ULONGLONG *PerformanceCount);
private:
_IRQL_requires_max_(PASSIVE_LEVEL)
VOID UpdateBufferingState();
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS ReadKeywordTimestampRegistry();
PAGED_CODE_SEG
NTSTATUS
SendPropertyTo
(
_In_ GUID PropertySet,
_In_ ULONG PropertyId,
_In_ ACX_PROPERTY_VERB Verb,
_In_ PVOID Control,
_In_ ULONG ControlCb,
_Inout_ PVOID Value,
_In_ ULONG ValueCb,
_Out_ ULONG_PTR* Information
);
PAGED_CODE_SEG
NTSTATUS
GetDeviceFunctionInformation(
_Out_ PSDCA_FUNCTION_INFORMATION_LIST *FunctionInfo
);
PAGED_CODE_SEG
NTSTATUS
GetDeviceKwsCapabilityDescriptor(
_Out_ PDEVICE_KWS_CAPABILITY_DESCRIPTOR Descriptor
);
PAGED_CODE_SEG
NTSTATUS
GetVadDescriptor(
_Out_ PVAD_DESCRIPTOR_FORMAT Descriptor
);
PAGED_CODE_SEG
NTSTATUS
GetVadEntities (
_Out_ PVAD_ENTITIES_EXTRA Entities
);
PAGED_CODE_SEG
NTSTATUS
SetSuspendAccessEvent(
_In_ PSDCA_KWS_NOTIFICATIONS Events
);
PAGED_CODE_SEG
_Requires_lock_held_(m_csLock)
NTSTATUS
UpdateVadStreamState();
PAGED_CODE_SEG
_Requires_lock_held_(m_csLock)
NTSTATUS
ConfigureVadPort(
_In_ PSDCA_KWS_PREPARE_PARAMS PrepareParams
);
PAGED_CODE_SEG
_Requires_lock_held_(m_csLock)
NTSTATUS
CleanupVadPort(
);
static KSTART_ROUTINE s_HandleNotifications;
PAGED_CODE_SEG
void
HandleNotifications();
// The Contoso keyword detector processes 10ms packets of 16KHz 16-bit PCM
// audio samples
static const int SamplesPerSecond = 16000;
static const int SamplesPerPacket = (10 * SamplesPerSecond / 1000);
typedef struct
{
LIST_ENTRY ListEntry;
LONGLONG PacketNumber;
LONGLONG QpcWhenSampled;
UINT16 Samples[SamplesPerPacket];
} PACKET_ENTRY;
// set at initialization, safe to use in all threads
WDFDEVICE m_Device;
ACXCIRCUIT m_Circuit;
LONGLONG m_qpcFrequency;
BOOLEAN m_Initialized;
SDCA_KWS_PREPARE_PARAMS m_PrepareParams;
PSDCA_FUNCTION_INFORMATION_LIST m_FunctionInformation;
DEVICE_KWS_CAPABILITY_DESCRIPTOR m_CapabilityDescriptor;
VAD_DESCRIPTOR_FORMAT m_VadDescriptor;
SDCA_KWS_NOTIFICATIONS m_Events;
PACKET_ENTRY m_PacketPool[1 * SamplesPerSecond / SamplesPerPacket]; // Enough storage for 1 second of audio data
VAD_ENTITIES_EXTRA m_VadEntities;
// single thread access, no lock necessary
LONGLONG m_SoundDetectorData1;
LONGLONG m_SoundDetectorData2;
ULONGLONG m_ullKeywordStartTimestamp;
ULONGLONG m_ullKeywordStopTimestamp;
BOOLEAN m_streamRunning;
// the following state variables are shared between dpc and stream state
KSPIN_LOCK m_BufferingStateSpinLock;
_Guarded_by_(m_BufferingStateSpinLock)
LONGLONG m_qpcStartCapture;
_Guarded_by_(m_BufferingStateSpinLock)
LONGLONG m_nLastQueuedPacket;
// protected through interlocked access to the packet pool
KSPIN_LOCK m_PacketPoolSpinLock;
LIST_ENTRY m_PacketPoolHead;
// protected through interlocked access to the packet pool
KSPIN_LOCK m_PacketFifoSpinLock;
LIST_ENTRY m_PacketFifoHead;
// the following variables are shared with the sdca notification event
// handler thread, and are protected by m_csLock
mutable wil::fast_mutex_with_critical_region m_csLock;
PETHREAD m_dispatchThread;
mutable wil::kernel_event_auto_reset m_threadExitEvent;
mutable wil::kernel_event_manual_reset m_threadExitedEvent{ true };
_Guarded_by_(m_csLock)
BOOLEAN m_Prepared;
_Guarded_by_(m_csLock)
BOOLEAN m_Suspended;
_Guarded_by_(m_csLock)
BOOLEAN m_SoundDetectorArmed1;
_Guarded_by_(m_csLock)
BOOLEAN m_SoundDetectorArmed2;
};
|