- Merge audio components from head
[reactos.git] / drivers / wdm / audio / backpln / audio_test / audio_test.c
1 #define _UNICODE
2 #define UNICODE
3 #define WIN32_NO_STATUS
4 #define _KSDDK_
5
6 #include <windows.h>
7 #include <mmsystem.h>
8 #include <stdio.h>
9 #include <math.h>
10 #include <setupapi.h>
11 #include <ndk/ntndk.h>
12 #include <ks.h>
13 #include <ksmedia.h>
14 #include "interface.h"
15
16
17 #define _2pi 6.283185307179586476925286766559
18
19
20
21 #include <ks.h>
22
23
24 GUID CategoryGuid = {STATIC_KSCATEGORY_AUDIO};
25
26
27 const GUID KSPROPSETID_Pin = {0x8C134960L, 0x51AD, 0x11CF, {0x87, 0x8A, 0x94, 0xF8, 0x01, 0xC1, 0x00, 0x00}};
28 const GUID KSPROPSETID_Connection = {0x1D58C920L, 0xAC9B, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
29 const GUID KSPROPSETID_Sysaudio = {0xCBE3FAA0L, 0xCC75, 0x11D0, {0xB4, 0x65, 0x00, 0x00, 0x1A, 0x18, 0x18, 0xE6}};
30 const GUID KSPROPSETID_General = {0x1464EDA5L, 0x6A8F, 0x11D1, {0x9A, 0xA7, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
31 const GUID KSINTERFACESETID_Standard = {0x1A8766A0L, 0x62CE, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
32 const GUID KSMEDIUMSETID_Standard = {0x4747B320L, 0x62CE, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
33 const GUID KSDATAFORMAT_TYPE_AUDIO = {0x73647561L, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
34 const GUID KSDATAFORMAT_SUBTYPE_PCM = {0x00000001L, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
35 const GUID KSDATAFORMAT_SPECIFIER_WAVEFORMATEX = {0x05589f81L, 0xc356, 0x11ce, {0xbf, 0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a}};
36
37
38 VOID
39 TestKs()
40 {
41 SP_DEVICE_INTERFACE_DATA InterfaceData;
42 SP_DEVINFO_DATA DeviceData;
43 PSP_DEVICE_INTERFACE_DETAIL_DATA DetailData;
44 HDEVINFO DeviceHandle;
45 PKSDATAFORMAT_WAVEFORMATEX DataFormat;
46 PKSPIN_CONNECT PinConnect;
47 PKSSTREAM_HEADER Packet;
48 PKSPROPERTY Property;
49 KSSTATE State;
50 DWORD Length;
51 HANDLE FilterHandle;
52 HANDLE PinHandle;
53 PSHORT SoundBuffer;
54 UINT i = 0;
55 BOOL Result;
56 NTSTATUS Status;
57
58 //
59 // Get a handle to KS Audio Interfaces
60 //
61 DeviceHandle = SetupDiGetClassDevs(&CategoryGuid,
62 NULL,
63 NULL,
64 DIGCF_DEVICEINTERFACE); //DIGCF_PRESENT
65
66 printf("DeviceHandle %p\n", DeviceHandle);
67
68 //
69 // Enumerate the first interface
70 //
71 InterfaceData.cbSize = sizeof(InterfaceData);
72 InterfaceData.Reserved = 0;
73 Result = SetupDiEnumDeviceInterfaces(DeviceHandle,
74 NULL,
75 &CategoryGuid,
76 1,
77 &InterfaceData);
78
79 printf("SetupDiEnumDeviceInterfaces %u Error %ld\n", Result, GetLastError());
80
81 //
82 // Get the interface details (namely the device path)
83 //
84 Length = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + MAX_PATH * sizeof(WCHAR);
85 DetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)HeapAlloc(GetProcessHeap(),
86 0,
87 Length);
88 DetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
89 DeviceData.cbSize = sizeof(DeviceData);
90 DeviceData.Reserved = 0;
91 Result = SetupDiGetDeviceInterfaceDetail(DeviceHandle,
92 &InterfaceData,
93 DetailData,
94 Length,
95 NULL,
96 &DeviceData);
97
98 wprintf(L"SetupDiGetDeviceInterfaceDetail %u Path DetailData %s\n", Result, (LPWSTR)&DetailData->DevicePath[0]);
99
100 //
101 // Open a handle to the device
102 //
103 FilterHandle = CreateFile(DetailData->DevicePath,
104 GENERIC_READ | GENERIC_WRITE,
105 0,
106 NULL,
107 OPEN_EXISTING,
108 FILE_ATTRIBUTE_NORMAL,
109 NULL);
110
111 printf("Handle %p\n", FilterHandle);
112
113 //
114 // Close the interface handle and clean up
115 //
116 SetupDiDestroyDeviceInfoList(DeviceHandle);
117
118 //
119 // Allocate a KS Pin Connection Request Structure
120 //
121 Length = sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT_WAVEFORMATEX);
122 printf("Length %ld KSPIN %u DATAFORMAT %u\n", Length, sizeof(KSPIN_CONNECT), sizeof(KSDATAFORMAT_WAVEFORMATEX));
123 PinConnect = (PKSPIN_CONNECT)HeapAlloc(GetProcessHeap(), 0, Length);
124 DataFormat = (PKSDATAFORMAT_WAVEFORMATEX)(PinConnect + 1);
125
126 //
127 // Setup the KS Pin Data
128 //
129 PinConnect->Interface.Set = KSINTERFACESETID_Standard;
130 PinConnect->Interface.Id = KSINTERFACE_STANDARD_STREAMING;
131 PinConnect->Interface.Flags = 0;
132 PinConnect->Medium.Set = KSMEDIUMSETID_Standard;
133 PinConnect->Medium.Id = KSMEDIUM_TYPE_ANYINSTANCE;
134 PinConnect->Medium.Flags = 0;
135 PinConnect->PinId = 0;
136 PinConnect->PinToHandle = NULL;
137 PinConnect->Priority.PriorityClass = KSPRIORITY_NORMAL;
138 PinConnect->Priority.PrioritySubClass = 1;
139
140 //
141 // Setup the KS Data Format Information
142 //
143 DataFormat->WaveFormatEx.wFormatTag = WAVE_FORMAT_PCM;
144 DataFormat->WaveFormatEx.nChannels = 2;
145 DataFormat->WaveFormatEx.nSamplesPerSec = 48000;
146 DataFormat->WaveFormatEx.nBlockAlign = 4;
147 DataFormat->WaveFormatEx.nAvgBytesPerSec = 48000 * 4;
148 DataFormat->WaveFormatEx.wBitsPerSample = 16;
149 DataFormat->WaveFormatEx.cbSize = 0;
150 DataFormat->DataFormat.FormatSize = sizeof(KSDATAFORMAT) +
151 sizeof(WAVEFORMATEX);
152 DataFormat->DataFormat.Flags = KSDATAFORMAT_ATTRIBUTES;
153 DataFormat->DataFormat.Reserved = 0;
154 DataFormat->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
155 DataFormat->DataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
156 DataFormat->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
157 DataFormat->DataFormat.SampleSize = 4;
158
159 //
160 // Create the pin
161 //
162 Status = KsCreatePin(FilterHandle, PinConnect, GENERIC_WRITE, &PinHandle);
163
164 printf("PinHandle %p Status %lx\n", PinHandle, Status);
165
166 //
167 // Allocate a buffer for 1 second
168 //
169 Length = 48000 * 4;
170 SoundBuffer = (PSHORT)HeapAlloc(GetProcessHeap(), 0, Length);
171
172 //
173 // Fill the buffer with a 500 Hz sine tone
174 //
175 while (i < Length / 2)
176 {
177 //
178 // Generate the wave for each channel:
179 // Amplitude * sin( Sample * Frequency * 2PI / SamplesPerSecond )
180 //
181 SoundBuffer[i] = 0x7FFF * sin(0.5 * (i - 1) * 500 * _2pi / 48000);
182 i++;
183 SoundBuffer[i] = 0x7FFF * sin((0.5 * i - 2) * 500 * _2pi / 48000);
184 i++;
185 }
186
187 //
188 // Create and fill out the KS Stream Packet
189 //
190 Packet = (PKSSTREAM_HEADER)HeapAlloc(GetProcessHeap(),
191 HEAP_ZERO_MEMORY,
192 sizeof(KSSTREAM_HEADER));
193 Packet->Data = SoundBuffer;
194 Packet->FrameExtent = Length;
195 Packet->DataUsed = Length;
196 Packet->Size = sizeof(KSSTREAM_HEADER);
197 Packet->PresentationTime.Numerator = 1;
198 Packet->PresentationTime.Denominator = 1;
199
200 //
201 // Setup a KS Property to change the state
202 //
203 Property = (PKSPROPERTY)HeapAlloc(GetProcessHeap(), 0, sizeof(KSPROPERTY));
204 Property->Set = KSPROPSETID_Connection;
205 Property->Id = KSPROPERTY_CONNECTION_STATE;
206 Property->Flags = KSPROPERTY_TYPE_SET;
207
208 //
209 // Change the state to run
210 //
211 State = KSSTATE_RUN;
212 DeviceIoControl(PinHandle,
213 IOCTL_KS_PROPERTY,
214 Property,
215 sizeof(KSPROPERTY),
216 &State,
217 sizeof(State),
218 &Length,
219 NULL);
220
221 //
222 // Play our 1-second buffer
223 //
224 DeviceIoControl(PinHandle,
225 IOCTL_KS_WRITE_STREAM,
226 NULL,
227 0,
228 Packet,
229 Packet->Size,
230 &Length,
231 NULL);
232
233 //
234 // Change the state to stop
235 //
236 State = KSSTATE_STOP;
237 DeviceIoControl(PinHandle,
238 IOCTL_KS_PROPERTY,
239 Property,
240 sizeof(KSPROPERTY),
241 &State,
242 sizeof(State),
243 &Length,
244 NULL);
245
246 CloseHandle(PinHandle);
247 CloseHandle(FilterHandle);
248 }
249
250 int
251 __cdecl
252 main(int argc, char* argv[])
253 {
254 ULONG Length;
255 PSHORT SoundBuffer;
256 ULONG i = 0;
257 BOOL Status;
258 OVERLAPPED Overlapped;
259 DWORD BytesReturned;
260 HANDLE hWdmAud;
261 WDMAUD_DEVICE_INFO DeviceInfo;
262
263 TestKs();
264 return 0;
265
266 hWdmAud = CreateFileW(L"\\\\.\\wdmaud",
267 GENERIC_READ | GENERIC_WRITE,
268 0,
269 NULL,
270 OPEN_EXISTING,
271 FILE_FLAG_OVERLAPPED,
272 NULL);
273 if (!hWdmAud)
274 {
275 printf("Failed to open wdmaud with %lx\n", GetLastError());
276 return -1;
277 }
278
279 printf("WDMAUD: opened\n");
280
281 /* clear device info */
282 RtlZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
283
284 ZeroMemory(&Overlapped, sizeof(OVERLAPPED));
285 Overlapped.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
286
287 DeviceInfo.DeviceType = WAVE_OUT_DEVICE_TYPE;
288
289
290 Status = DeviceIoControl(hWdmAud, IOCTL_GETNUMDEVS_TYPE, (LPVOID)&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPVOID)&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), &BytesReturned, &Overlapped);
291
292 if (!Status)
293 {
294 if (WaitForSingleObject(&Overlapped.hEvent, 5000) != WAIT_OBJECT_0)
295 {
296 printf("Failed to get num of wave out devices with %lx\n", GetLastError());
297 CloseHandle(hWdmAud);
298 return -1;
299 }
300 }
301
302 printf("WDMAUD: Num Devices %lu\n", DeviceInfo.DeviceCount);
303
304 if (!DeviceInfo.DeviceCount)
305 {
306 CloseHandle(hWdmAud);
307 return 0;
308 }
309
310 Status = DeviceIoControl(hWdmAud, IOCTL_GETCAPABILITIES, (LPVOID)&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPVOID)&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), &BytesReturned, &Overlapped);
311
312 if (!Status)
313 {
314 if (WaitForSingleObject(&Overlapped.hEvent, 5000) != WAIT_OBJECT_0)
315 {
316 printf("Failed to get iocaps %lx\n", GetLastError());
317 }
318 }
319 printf("WDMAUD: Capabilites NumChannels %x dwFormats %lx\n", DeviceInfo.u.WaveOutCaps.wChannels, DeviceInfo.u.WaveOutCaps.dwFormats);
320
321 DeviceInfo.u.WaveFormatEx.cbSize = sizeof(WAVEFORMATEX);
322 DeviceInfo.u.WaveFormatEx.wFormatTag = WAVE_FORMAT_PCM;
323 DeviceInfo.u.WaveFormatEx.nChannels = 2;
324 DeviceInfo.u.WaveFormatEx.nSamplesPerSec = 48000;
325 DeviceInfo.u.WaveFormatEx.nBlockAlign = 4;
326 DeviceInfo.u.WaveFormatEx.nAvgBytesPerSec = 48000 * 4;
327 DeviceInfo.u.WaveFormatEx.wBitsPerSample = 16;
328
329
330
331 Status = DeviceIoControl(hWdmAud, IOCTL_OPEN_WDMAUD, (LPVOID)&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), &BytesReturned, &Overlapped);
332 if (!Status)
333 {
334 if (WaitForSingleObject(&Overlapped.hEvent, 5000) != WAIT_OBJECT_0)
335 {
336 printf("Failed to open device with %lx\n", GetLastError());
337 CloseHandle(hWdmAud);
338 return -1;
339 }
340 }
341
342 printf("WDMAUD: opened device\n");
343
344 //
345 // Allocate a buffer for 1 second
346 //
347 Length = 48000 * 4;
348 SoundBuffer = (PSHORT)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Length);
349
350 //
351 // Fill the buffer with a 500 Hz sine tone
352 //
353 while (i < Length / 2)
354 {
355 //
356 // Generate the wave for each channel:
357 // Amplitude * sin( Sample * Frequency * 2PI / SamplesPerSecond )
358 //
359 SoundBuffer[i] = 0x7FFF * sin(0.5 * (i - 1) * 500 * _2pi / 48000);
360 i++;
361 SoundBuffer[i] = 0x7FFF * sin((0.5 * i - 2) * 500 * _2pi / 48000);
362 i++;
363 }
364
365 DeviceInfo.u.State = KSSTATE_RUN;
366 Status = DeviceIoControl(hWdmAud, IOCTL_SETDEVICE_STATE, (LPVOID)&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), &BytesReturned, &Overlapped);
367 if (!Status)
368 {
369 if (WaitForSingleObject(&Overlapped.hEvent, 5000) != WAIT_OBJECT_0)
370 {
371 printf("Failed to set device into run state %lx\n", GetLastError());
372 CloseHandle(hWdmAud);
373 return -1;
374 }
375 }
376
377 //
378 // Play our 1-second buffer
379 //
380 DeviceInfo.Header.Data = (PUCHAR)SoundBuffer;
381 DeviceInfo.Header.DataUsed = DeviceInfo.Header.FrameExtent = Length;
382 Status = DeviceIoControl(hWdmAud, IOCTL_WRITEDATA, (LPVOID)&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), &BytesReturned, &Overlapped);
383 if (!Status)
384 {
385 if (WaitForSingleObject(&Overlapped.hEvent, 5000) != WAIT_OBJECT_0)
386 {
387 printf("Failed to play buffer %lx\n", GetLastError());
388 CloseHandle(hWdmAud);
389 return -1;
390 }
391 }
392
393 printf("WDMAUD: Played buffer\n");
394
395 DeviceInfo.u.State = KSSTATE_STOP;
396 Status = DeviceIoControl(hWdmAud, IOCTL_SETDEVICE_STATE, (LPVOID)&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), &BytesReturned, &Overlapped);
397 if (!Status)
398 {
399 if (WaitForSingleObject(&Overlapped.hEvent, 5000) != WAIT_OBJECT_0)
400 {
401 printf("Failed to set device into stop state %lx\n", GetLastError());
402 CloseHandle(hWdmAud);
403 return -1;
404 }
405 }
406 printf("WDMAUD: STOPPED\n");
407 CloseHandle(&Overlapped.hEvent);
408 CloseHandle(hWdmAud);
409 printf("WDMAUD: COMPLETE\n");
410 return 0;
411 }