[MMIXER_TEST]
[reactos.git] / rostests / tests / mmixer_test / test.c
1 #include <windows.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <setupapi.h>
5 #include <ks.h>
6 #include <ksmedia.h>
7 #include <mmsystem.h>
8 #include <mmreg.h>
9 #include "mmixer.h"
10
11 MIXER_CONTEXT MixerContext;
12 GUID CategoryGuid = {STATIC_KSCATEGORY_AUDIO};
13
14 PVOID Alloc(ULONG NumBytes)
15 {
16 //printf("Alloc: %lu\n", NumBytes);
17 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, NumBytes);
18 }
19
20 MIXER_STATUS
21 Close(HANDLE hDevice)
22 {
23 //printf("Close: Handle %p\n", hDevice);
24 if (CloseHandle(hDevice))
25 return MM_STATUS_SUCCESS;
26 else
27 return MM_STATUS_UNSUCCESSFUL;
28 }
29
30 VOID
31 Free(PVOID Block)
32 {
33 //printf("Free: %p\n", Block);
34 HeapFree(GetProcessHeap(), 0, Block);
35 }
36
37 VOID
38 Copy(PVOID Src, PVOID Dst, ULONG NumBytes)
39 {
40 //printf("Copy: Src %p Dst %p NumBytes %lu\n", Src, Dst, NumBytes);
41 CopyMemory(Src, Dst, NumBytes);
42 }
43
44 MIXER_STATUS
45 Open(
46 IN LPWSTR DevicePath,
47 OUT PHANDLE hDevice)
48 {
49 DevicePath[1] = L'\\';
50 *hDevice = CreateFileW(DevicePath,
51 GENERIC_READ | GENERIC_WRITE,
52 0,
53 NULL,
54 OPEN_EXISTING,
55 FILE_FLAG_OVERLAPPED,
56 NULL);
57 if (*hDevice == INVALID_HANDLE_VALUE)
58 {
59 //wprintf(L" Failed to open %s Error %lu\n", DevicePath, GetLastError());
60 return MM_STATUS_UNSUCCESSFUL;
61 }
62 wprintf(L"Open: %s hDevice %p\n", DevicePath, *hDevice);
63
64 return MM_STATUS_SUCCESS;
65 }
66
67 MIXER_STATUS
68 Control(
69 IN HANDLE hMixer,
70 IN ULONG dwIoControlCode,
71 IN PVOID lpInBuffer,
72 IN ULONG nInBufferSize,
73 OUT PVOID lpOutBuffer,
74 ULONG nOutBufferSize,
75 PULONG lpBytesReturned)
76 {
77 OVERLAPPED Overlapped;
78 BOOLEAN IoResult;
79 DWORD Transferred = 0;
80
81 //printf("hMixer %p dwIoControlCode %lx lpInBuffer %p nInBufferSize %lu lpOutBuffer %p nOutBufferSize %lu lpBytesReturned %p\n",
82 // hMixer, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned);
83
84 /* Overlapped I/O is done here - this is used for waiting for completion */
85 ZeroMemory(&Overlapped, sizeof(OVERLAPPED));
86 Overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
87
88 if ( ! Overlapped.hEvent )
89 return MM_STATUS_NO_MEMORY;
90
91 /* Talk to the device */
92 IoResult = DeviceIoControl(hMixer,
93 dwIoControlCode,
94 lpInBuffer,
95 nInBufferSize,
96 lpOutBuffer,
97 nOutBufferSize,
98 &Transferred,
99 &Overlapped);
100
101 /* If failure occurs, make sure it's not just due to the overlapped I/O */
102 if ( ! IoResult )
103 {
104 if ( GetLastError() != ERROR_IO_PENDING )
105 {
106 CloseHandle(Overlapped.hEvent);
107
108 printf("Control: Failed with %lu Transferred %lu\n", GetLastError(), Transferred);
109
110 if (GetLastError() == ERROR_MORE_DATA || GetLastError() == ERROR_INSUFFICIENT_BUFFER)
111 {
112 if ( lpBytesReturned )
113 *lpBytesReturned = Transferred;
114 return MM_STATUS_MORE_ENTRIES;
115 }
116
117 return MM_STATUS_UNSUCCESSFUL;
118 }
119 }
120
121 /* Wait for the I/O to complete */
122 IoResult = GetOverlappedResult(hMixer,
123 &Overlapped,
124 &Transferred,
125 TRUE);
126
127 /* Don't need this any more */
128 CloseHandle(Overlapped.hEvent);
129
130 if ( ! IoResult )
131 return MM_STATUS_UNSUCCESSFUL;
132
133 //printf("Transferred %lu bytes in Sync overlapped I/O\n", Transferred);
134
135 if ( lpBytesReturned )
136 *lpBytesReturned = Transferred;
137
138 return MM_STATUS_SUCCESS;
139 }
140
141 MIXER_STATUS
142 Enum(
143 IN PVOID EnumContext,
144 IN ULONG DeviceIndex,
145 OUT LPWSTR * DeviceName,
146 OUT PHANDLE OutHandle,
147 OUT PHANDLE OutKey)
148 {
149 SP_DEVICE_INTERFACE_DATA InterfaceData;
150 SP_DEVINFO_DATA DeviceData;
151 PSP_DEVICE_INTERFACE_DETAIL_DATA_W DetailData;
152 BOOL Result;
153 DWORD Length;
154 MIXER_STATUS Status;
155
156 //printf("Enum EnumContext %p DeviceIndex %lu OutHandle %p\n", EnumContext, DeviceIndex, OutHandle);
157
158 InterfaceData.cbSize = sizeof(InterfaceData);
159 InterfaceData.Reserved = 0;
160
161 Result = SetupDiEnumDeviceInterfaces(EnumContext,
162 NULL,
163 &CategoryGuid,
164 DeviceIndex,
165 &InterfaceData);
166
167 if (!Result)
168 {
169 if (GetLastError() == ERROR_NO_MORE_ITEMS)
170 {
171 printf("LastDevice\n");
172 return MM_STATUS_NO_MORE_DEVICES;
173 }
174 printf("SetupDiEnumDeviceInterfaces failed with %lu\n", GetLastError());
175 return MM_STATUS_UNSUCCESSFUL;
176 }
177
178 Length = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + MAX_PATH * sizeof(WCHAR);
179 DetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)HeapAlloc(GetProcessHeap(),
180 0,
181 Length);
182 DetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
183 DeviceData.cbSize = sizeof(DeviceData);
184 DeviceData.Reserved = 0;
185
186 Result = SetupDiGetDeviceInterfaceDetailW(EnumContext,
187 &InterfaceData,
188 DetailData,
189 Length,
190 NULL,
191 &DeviceData);
192
193 if (!Result)
194 {
195 printf("SetupDiGetDeviceInterfaceDetailW failed with %lu\n", GetLastError());
196 return MM_STATUS_UNSUCCESSFUL;
197 }
198
199
200 *OutKey = SetupDiOpenDeviceInterfaceRegKey(EnumContext, &InterfaceData, 0, KEY_READ);
201 if ((HKEY)*OutKey == INVALID_HANDLE_VALUE)
202 {
203 printf("SetupDiOpenDeviceInterfaceRegKey failed with %lx\n", GetLastError());
204 HeapFree(GetProcessHeap(), 0, DetailData);
205 return MM_STATUS_UNSUCCESSFUL;
206 }
207
208 Status = Open(DetailData->DevicePath, OutHandle);
209
210 if (Status != MM_STATUS_SUCCESS)
211 {
212 RegCloseKey((HKEY)*OutKey);
213 HeapFree(GetProcessHeap(), 0, DetailData);
214 return Status;
215 }
216
217 *DeviceName = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wcslen(DetailData->DevicePath)+1) * sizeof(WCHAR));
218 if (*DeviceName == NULL)
219 {
220 CloseHandle(*OutHandle);
221 RegCloseKey((HKEY)*OutKey);
222 HeapFree(GetProcessHeap(), 0, DetailData);
223 return MM_STATUS_NO_MEMORY;
224 }
225
226 wcscpy(*DeviceName, DetailData->DevicePath);
227 HeapFree(GetProcessHeap(), 0, DetailData);
228
229 return Status;
230 }
231
232 MIXER_STATUS
233 QueryKeyValue(
234 IN HANDLE hKey,
235 IN LPWSTR KeyName,
236 OUT PVOID * ResultBuffer,
237 OUT PULONG ResultLength,
238 OUT PULONG KeyType)
239 {
240 if (RegQueryValueExW((HKEY)hKey, KeyName, NULL, KeyType, NULL, ResultLength) == ERROR_FILE_NOT_FOUND)
241 return MM_STATUS_UNSUCCESSFUL;
242
243 *ResultBuffer = HeapAlloc(GetProcessHeap(), 0, *ResultLength);
244 if (*ResultBuffer == NULL)
245 return MM_STATUS_NO_MEMORY;
246
247 if (RegQueryValueExW((HKEY)hKey, KeyName, NULL, KeyType, *ResultBuffer, ResultLength) != ERROR_SUCCESS)
248 {
249 HeapFree(GetProcessHeap(), 0, *ResultBuffer);
250 return MM_STATUS_UNSUCCESSFUL;
251 }
252 return MM_STATUS_SUCCESS;
253 }
254
255 MIXER_STATUS
256 OpenKey(
257 IN HANDLE hKey,
258 IN LPWSTR SubKey,
259 IN ULONG DesiredAccess,
260 OUT PHANDLE OutKey)
261 {
262 if (RegOpenKeyExW((HKEY)hKey, SubKey, 0, DesiredAccess, (PHKEY)OutKey) == ERROR_SUCCESS)
263 return MM_STATUS_SUCCESS;
264
265 return MM_STATUS_UNSUCCESSFUL;
266 }
267
268 MIXER_STATUS
269 CloseKey(
270 IN HANDLE hKey)
271 {
272 RegCloseKey((HKEY)hKey);
273 return MM_STATUS_SUCCESS;
274 }
275
276 PVOID
277 AllocEventData(
278 IN ULONG ExtraSize)
279 {
280 PKSEVENTDATA Data = (PKSEVENTDATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(KSEVENTDATA) + ExtraSize);
281 if (!Data)
282 return NULL;
283
284 Data->EventHandle.Event = CreateEventW(NULL, FALSE, FALSE, NULL);
285 if (!Data->EventHandle.Event)
286 {
287 HeapFree(GetProcessHeap(), 0, Data);
288 return NULL;
289 }
290
291 Data->NotificationType = KSEVENTF_EVENT_HANDLE;
292 return Data;
293 }
294
295 VOID
296 FreeEventData(IN PVOID EventData)
297 {
298 PKSEVENTDATA Data = (PKSEVENTDATA)EventData;
299
300 CloseHandle(Data->EventHandle.Event);
301 HeapFree(GetProcessHeap(), 0, Data);
302 }
303
304 int main(int argc, char**argv)
305 {
306 MIXER_STATUS Status;
307 HDEVINFO DeviceHandle;
308 MIXERCAPSW MixCaps1, MixCaps2;
309 ULONG Index, SubIndex;
310 HANDLE hMixer2;
311 HMIXER hMixer1;
312 MIXERLINEW MixerLine1, MixerLine2;
313 MIXERLINECONTROLSW Controls1, Controls2;
314
315 ZeroMemory(&MixerContext, sizeof(MIXER_CONTEXT));
316
317 DeviceHandle = SetupDiGetClassDevs(&CategoryGuid,
318 NULL,
319 NULL,
320 DIGCF_DEVICEINTERFACE/*|DIGCF_PRESENT */);
321 if (DeviceHandle == INVALID_HANDLE_VALUE)
322 {
323 printf("SetupDiGetClassDevs failed with %lx\n", GetLastError());
324 return 0;
325 }
326
327 printf("DeviceHandle %p\n", DeviceHandle);
328
329 MixerContext.SizeOfStruct = sizeof(MIXER_CONTEXT);
330 MixerContext.Alloc = Alloc;
331 MixerContext.Close = Close;
332 MixerContext.Control = Control;
333 MixerContext.Copy = Copy;
334 MixerContext.Free = Free;
335 MixerContext.Open = Open;
336 MixerContext.OpenKey = OpenKey;
337 MixerContext.CloseKey = CloseKey;
338 MixerContext.QueryKeyValue = QueryKeyValue;
339 MixerContext.AllocEventData = AllocEventData;
340 MixerContext.FreeEventData = FreeEventData;
341
342 Status = MMixerInitialize(&MixerContext, Enum, (PVOID)DeviceHandle);
343
344 printf("Status %x\n", Status);
345 printf("NumberOfMixers %lu mixerGetNumDevs %u\n", MMixerGetCount(&MixerContext), mixerGetNumDevs());
346
347 for(Index = 0; Index < MMixerGetCount(&MixerContext); Index++)
348 {
349 mixerGetDevCapsW(Index, &MixCaps1, sizeof(MIXERCAPSW));
350 wprintf(L"WINM: cDestination %u fdwSupport %lx szPname %s vDriverVersion %u wMid %x wPid %x\n", MixCaps1.cDestinations, MixCaps1.fdwSupport, MixCaps1.szPname, MixCaps1.vDriverVersion, MixCaps1.wMid, MixCaps1.wPid);
351 MMixerGetCapabilities(&MixerContext, Index, &MixCaps2);
352 wprintf(L"MMIX: cDestination %u fdwSupport %lx szPname %s vDriverVersion %u wMid %x wPid %x\n", MixCaps2.cDestinations, MixCaps2.fdwSupport, MixCaps2.szPname, MixCaps2.vDriverVersion, MixCaps2.wMid, MixCaps2.wPid);
353
354 mixerOpen(&hMixer1, Index, 0, 0, MIXER_OBJECTF_HMIXER);
355 MMixerOpen(&MixerContext, Index, NULL, NULL, &hMixer2);
356
357 ZeroMemory(&MixerLine1, sizeof(MIXERLINEW));
358 ZeroMemory(&MixerLine2, sizeof(MIXERLINEW));
359 MixerLine1.cbStruct = sizeof(MIXERLINEW);
360 MixerLine2.cbStruct = sizeof(MIXERLINEW);
361 mixerGetLineInfoW((HMIXEROBJ)hMixer1, &MixerLine1, MIXER_GETLINEINFOF_DESTINATION);
362 MMixerGetLineInfo(&MixerContext, hMixer2, MIXER_GETLINEINFOF_DESTINATION, &MixerLine2);
363
364 wprintf(L"WINM: dwDestination %lx dwSource %lx dwLineID %lx dwUser %lx dwComponentType %lx cChannels %lx cConnections %lx cControls %lx szShortName %s szName %s\n\n",
365 MixerLine1.dwDestination, MixerLine1.dwSource, MixerLine1.dwLineID, MixerLine1.dwUser, MixerLine1.dwComponentType, MixerLine1.cChannels, MixerLine1.cConnections, MixerLine1.cControls, MixerLine1.szShortName, MixerLine1.szName);
366
367 wprintf(L"MMIX: dwDestination %lx dwSource %lx dwLineID %lx dwUser %lx dwComponentType %lx cChannels %lx cConnections %lx cControls %lx szShortName %s szName %s\n\n",
368 MixerLine2.dwDestination, MixerLine2.dwSource, MixerLine2.dwLineID, MixerLine2.dwUser, MixerLine2.dwComponentType, MixerLine2.cChannels, MixerLine2.cConnections, MixerLine2.cControls, MixerLine2.szShortName, MixerLine2.szName);
369
370 Controls1.cbStruct = sizeof(MIXERLINECONTROLSW);
371 Controls2.cbStruct = sizeof(MIXERLINECONTROLSW);
372
373 Controls1.cbmxctrl = sizeof(MIXERCONTROL);
374 Controls2.cbmxctrl = sizeof(MIXERCONTROL);
375
376 Controls1.cControls = MixerLine1.cControls;
377 Controls2.cControls = MixerLine2.cControls;
378
379 Controls1.dwLineID = MixerLine1.dwLineID;
380 Controls2.dwLineID = MixerLine2.dwLineID;
381
382
383
384 Controls1.pamxctrl = (LPMIXERCONTROLW)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MIXERCONTROLW) * Controls1.cControls);
385 Controls2.pamxctrl = (LPMIXERCONTROLW)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MIXERCONTROLW) * Controls2.cControls);
386
387 for(SubIndex = 0; SubIndex < Controls1.cControls; SubIndex++)
388 Controls1.pamxctrl[SubIndex].cbStruct = sizeof(MIXERCONTROLW);
389
390 for(SubIndex = 0; SubIndex < Controls2.cControls; SubIndex++)
391 Controls2.pamxctrl[SubIndex].cbStruct = sizeof(MIXERCONTROLW);
392
393 mixerGetLineControlsW((HMIXEROBJ)hMixer1, &Controls1, MIXER_GETLINECONTROLSF_ALL);
394 MMixerGetLineControls(&MixerContext, hMixer2, MIXER_GETLINECONTROLSF_ALL, &Controls2);
395
396 wprintf(L"----------------------------------------\n");
397 for(SubIndex = 0; SubIndex < Controls1.cControls || SubIndex < Controls2.cControls; SubIndex++)
398 {
399 if (SubIndex < Controls1.cControls)
400 {
401 wprintf(L"WINM: Index %d dwControlID %lx dwControlType %lx fdwControl %lx cMultipleItems %lx szName %s szShortName %s \n", SubIndex, Controls1.pamxctrl[SubIndex].dwControlID, Controls1.pamxctrl[SubIndex].dwControlType, Controls1.pamxctrl[SubIndex].fdwControl, Controls1.pamxctrl[SubIndex].cMultipleItems, Controls1.pamxctrl[SubIndex].szName, Controls1.pamxctrl[SubIndex].szShortName);
402 }
403
404 if (SubIndex < Controls2.cControls)
405 {
406 wprintf(L"MMIX: Index %d dwControlID %lx dwControlType %lx fdwControl %lx cMultipleItems %lx szName %s szShortName %s \n", SubIndex, Controls2.pamxctrl[SubIndex].dwControlID, Controls2.pamxctrl[SubIndex].dwControlType, Controls2.pamxctrl[SubIndex].fdwControl, Controls2.pamxctrl[SubIndex].cMultipleItems, Controls2.pamxctrl[SubIndex].szName, Controls2.pamxctrl[SubIndex].szShortName);
407 }
408
409 }
410 wprintf(L"----------------------------------------\n");
411
412
413 wprintf(L"=======================\n");
414 }
415
416 wprintf(L"//////////////////////\n");
417 wprintf(L"NumWaveOut %lu NumWaveIn %lu\n", MMixerGetWaveOutCount(&MixerContext), MMixerGetWaveInCount(&MixerContext));
418 wprintf(L"waveOut %lu waveIn %lu\n", waveOutGetNumDevs(), waveInGetNumDevs());
419 return 0;
420 }