3 #define WIN32_NO_STATUS
11 #include <ndk/ntndk.h>
14 #include "interface.h"
17 #define _2pi 6.283185307179586476925286766559
24 GUID CategoryGuid
= {STATIC_KSCATEGORY_AUDIO
};
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}};
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
;
59 // Get a handle to KS Audio Interfaces
61 DeviceHandle
= SetupDiGetClassDevs(&CategoryGuid
,
64 DIGCF_DEVICEINTERFACE
); //DIGCF_PRESENT
66 printf("DeviceHandle %p\n", DeviceHandle
);
69 // Enumerate the first interface
71 InterfaceData
.cbSize
= sizeof(InterfaceData
);
72 InterfaceData
.Reserved
= 0;
73 Result
= SetupDiEnumDeviceInterfaces(DeviceHandle
,
79 printf("SetupDiEnumDeviceInterfaces %u Error %ld\n", Result
, GetLastError());
82 // Get the interface details (namely the device path)
84 Length
= sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA
) + MAX_PATH
* sizeof(WCHAR
);
85 DetailData
= (PSP_DEVICE_INTERFACE_DETAIL_DATA
)HeapAlloc(GetProcessHeap(),
88 DetailData
->cbSize
= sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA
);
89 DeviceData
.cbSize
= sizeof(DeviceData
);
90 DeviceData
.Reserved
= 0;
91 Result
= SetupDiGetDeviceInterfaceDetail(DeviceHandle
,
98 wprintf(L
"SetupDiGetDeviceInterfaceDetail %u Path DetailData %s\n", Result
, (LPWSTR
)&DetailData
->DevicePath
[0]);
101 // Open a handle to the device
103 FilterHandle
= CreateFile(DetailData
->DevicePath
,
104 GENERIC_READ
| GENERIC_WRITE
,
108 FILE_ATTRIBUTE_NORMAL
,
111 printf("Handle %p\n", FilterHandle
);
114 // Close the interface handle and clean up
116 SetupDiDestroyDeviceInfoList(DeviceHandle
);
119 // Allocate a KS Pin Connection Request Structure
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);
127 // Setup the KS Pin Data
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;
141 // Setup the KS Data Format Information
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;
162 Status
= KsCreatePin(FilterHandle
, PinConnect
, GENERIC_WRITE
, &PinHandle
);
164 printf("PinHandle %p Status %lx\n", PinHandle
, Status
);
167 // Allocate a buffer for 1 second
170 SoundBuffer
= (PSHORT
)HeapAlloc(GetProcessHeap(), 0, Length
);
173 // Fill the buffer with a 500 Hz sine tone
175 while (i
< Length
/ 2)
178 // Generate the wave for each channel:
179 // Amplitude * sin( Sample * Frequency * 2PI / SamplesPerSecond )
181 SoundBuffer
[i
] = 0x7FFF * sin(0.5 * (i
- 1) * 500 * _2pi
/ 48000);
183 SoundBuffer
[i
] = 0x7FFF * sin((0.5 * i
- 2) * 500 * _2pi
/ 48000);
188 // Create and fill out the KS Stream Packet
190 Packet
= (PKSSTREAM_HEADER
)HeapAlloc(GetProcessHeap(),
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;
201 // Setup a KS Property to change the state
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
;
209 // Change the state to run
212 DeviceIoControl(PinHandle
,
222 // Play our 1-second buffer
224 DeviceIoControl(PinHandle
,
225 IOCTL_KS_WRITE_STREAM
,
234 // Change the state to stop
236 State
= KSSTATE_STOP
;
237 DeviceIoControl(PinHandle
,
246 CloseHandle(PinHandle
);
247 CloseHandle(FilterHandle
);
252 main(int argc
, char* argv
[])
258 OVERLAPPED Overlapped
;
261 WDMAUD_DEVICE_INFO DeviceInfo
;
266 hWdmAud
= CreateFileW(L
"\\\\.\\wdmaud",
267 GENERIC_READ
| GENERIC_WRITE
,
271 FILE_FLAG_OVERLAPPED
,
275 printf("Failed to open wdmaud with %lx\n", GetLastError());
279 printf("WDMAUD: opened\n");
281 /* clear device info */
282 RtlZeroMemory(&DeviceInfo
, sizeof(WDMAUD_DEVICE_INFO
));
284 ZeroMemory(&Overlapped
, sizeof(OVERLAPPED
));
285 Overlapped
.hEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
287 DeviceInfo
.DeviceType
= WAVE_OUT_DEVICE_TYPE
;
290 Status
= DeviceIoControl(hWdmAud
, IOCTL_GETNUMDEVS_TYPE
, (LPVOID
)&DeviceInfo
, sizeof(WDMAUD_DEVICE_INFO
), (LPVOID
)&DeviceInfo
, sizeof(WDMAUD_DEVICE_INFO
), &BytesReturned
, &Overlapped
);
294 if (WaitForSingleObject(&Overlapped
.hEvent
, 5000) != WAIT_OBJECT_0
)
296 printf("Failed to get num of wave out devices with %lx\n", GetLastError());
297 CloseHandle(hWdmAud
);
302 printf("WDMAUD: Num Devices %lu\n", DeviceInfo
.DeviceCount
);
304 if (!DeviceInfo
.DeviceCount
)
306 CloseHandle(hWdmAud
);
310 Status
= DeviceIoControl(hWdmAud
, IOCTL_GETCAPABILITIES
, (LPVOID
)&DeviceInfo
, sizeof(WDMAUD_DEVICE_INFO
), (LPVOID
)&DeviceInfo
, sizeof(WDMAUD_DEVICE_INFO
), &BytesReturned
, &Overlapped
);
314 if (WaitForSingleObject(&Overlapped
.hEvent
, 5000) != WAIT_OBJECT_0
)
316 printf("Failed to get iocaps %lx\n", GetLastError());
319 printf("WDMAUD: Capabilites NumChannels %x dwFormats %lx\n", DeviceInfo
.u
.WaveOutCaps
.wChannels
, DeviceInfo
.u
.WaveOutCaps
.dwFormats
);
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;
331 Status
= DeviceIoControl(hWdmAud
, IOCTL_OPEN_WDMAUD
, (LPVOID
)&DeviceInfo
, sizeof(WDMAUD_DEVICE_INFO
), &DeviceInfo
, sizeof(WDMAUD_DEVICE_INFO
), &BytesReturned
, &Overlapped
);
334 if (WaitForSingleObject(&Overlapped
.hEvent
, 5000) != WAIT_OBJECT_0
)
336 printf("Failed to open device with %lx\n", GetLastError());
337 CloseHandle(hWdmAud
);
342 printf("WDMAUD: opened device\n");
345 // Allocate a buffer for 1 second
348 SoundBuffer
= (PSHORT
)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, Length
);
351 // Fill the buffer with a 500 Hz sine tone
353 while (i
< Length
/ 2)
356 // Generate the wave for each channel:
357 // Amplitude * sin( Sample * Frequency * 2PI / SamplesPerSecond )
359 SoundBuffer
[i
] = 0x7FFF * sin(0.5 * (i
- 1) * 500 * _2pi
/ 48000);
361 SoundBuffer
[i
] = 0x7FFF * sin((0.5 * i
- 2) * 500 * _2pi
/ 48000);
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
);
369 if (WaitForSingleObject(&Overlapped
.hEvent
, 5000) != WAIT_OBJECT_0
)
371 printf("Failed to set device into run state %lx\n", GetLastError());
372 CloseHandle(hWdmAud
);
378 // Play our 1-second buffer
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
);
385 if (WaitForSingleObject(&Overlapped
.hEvent
, 5000) != WAIT_OBJECT_0
)
387 printf("Failed to play buffer %lx\n", GetLastError());
388 CloseHandle(hWdmAud
);
393 printf("WDMAUD: Played buffer\n");
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
);
399 if (WaitForSingleObject(&Overlapped
.hEvent
, 5000) != WAIT_OBJECT_0
)
401 printf("Failed to set device into stop state %lx\n", GetLastError());
402 CloseHandle(hWdmAud
);
406 printf("WDMAUD: STOPPED\n");
407 CloseHandle(&Overlapped
.hEvent
);
408 CloseHandle(hWdmAud
);
409 printf("WDMAUD: COMPLETE\n");