991454e5572c7044de2c486e11f2c3b29c25ad3e
[reactos.git] / reactos / dll / win32 / wdmaud.drv / mmixer.c
1 /*
2 * PROJECT: ReactOS Sound System
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/wdmaud.drv/mmixer.c
5 *
6 * PURPOSE: WDM Audio Mixer API (User-mode part)
7 * PROGRAMMERS: Johannes Anderwald
8 */
9
10 #include "wdmaud.h"
11
12
13 PVOID Alloc(ULONG NumBytes);
14 MIXER_STATUS Close(HANDLE hDevice);
15 VOID Free(PVOID Block);
16 VOID Copy(PVOID Src, PVOID Dst, ULONG NumBytes);
17 MIXER_STATUS Open(IN LPWSTR DevicePath, OUT PHANDLE hDevice);
18 MIXER_STATUS Control(IN HANDLE hMixer, IN ULONG dwIoControlCode, IN PVOID lpInBuffer, IN ULONG nInBufferSize, OUT PVOID lpOutBuffer, ULONG nOutBufferSize, PULONG lpBytesReturned);
19 MIXER_STATUS Enum(IN PVOID EnumContext, IN ULONG DeviceIndex, OUT LPWSTR * DeviceName, OUT PHANDLE OutHandle, OUT PHANDLE OutKey);
20 MIXER_STATUS OpenKey(IN HANDLE hKey, IN LPWSTR SubKey, IN ULONG DesiredAccess, OUT PHANDLE OutKey);
21 MIXER_STATUS CloseKey(IN HANDLE hKey);
22 MIXER_STATUS QueryKeyValue(IN HANDLE hKey, IN LPWSTR KeyName, OUT PVOID * ResultBuffer, OUT PULONG ResultLength, OUT PULONG KeyType);
23
24 MIXER_CONTEXT MixerContext =
25 {
26 sizeof(MIXER_CONTEXT),
27 NULL,
28 Alloc,
29 Control,
30 Free,
31 Open,
32 Close,
33 Copy,
34 OpenKey,
35 QueryKeyValue,
36 CloseKey
37 };
38
39 GUID CategoryGuid = {STATIC_KSCATEGORY_AUDIO};
40
41 MIXER_STATUS
42 QueryKeyValue(
43 IN HANDLE hKey,
44 IN LPWSTR KeyName,
45 OUT PVOID * ResultBuffer,
46 OUT PULONG ResultLength,
47 OUT PULONG KeyType)
48 {
49 if (RegQueryValueExW((HKEY)hKey, KeyName, NULL, KeyType, NULL, ResultLength) == ERROR_FILE_NOT_FOUND)
50 return MM_STATUS_UNSUCCESSFUL;
51
52 *ResultBuffer = HeapAlloc(GetProcessHeap(), 0, *ResultLength);
53 if (*ResultBuffer == NULL)
54 return MM_STATUS_NO_MEMORY;
55
56 if (RegQueryValueExW((HKEY)hKey, KeyName, NULL, KeyType, *ResultBuffer, ResultLength) != ERROR_SUCCESS)
57 {
58 HeapFree(GetProcessHeap(), 0, *ResultBuffer);
59 return MM_STATUS_UNSUCCESSFUL;
60 }
61 return MM_STATUS_SUCCESS;
62 }
63
64 MIXER_STATUS
65 OpenKey(
66 IN HANDLE hKey,
67 IN LPWSTR SubKey,
68 IN ULONG DesiredAccess,
69 OUT PHANDLE OutKey)
70 {
71 if (RegOpenKeyExW((HKEY)hKey, SubKey, 0, DesiredAccess, (PHKEY)OutKey) == ERROR_SUCCESS)
72 return MM_STATUS_SUCCESS;
73
74 return MM_STATUS_UNSUCCESSFUL;
75 }
76
77 MIXER_STATUS
78 CloseKey(
79 IN HANDLE hKey)
80 {
81 RegCloseKey((HKEY)hKey);
82 return MM_STATUS_SUCCESS;
83 }
84
85
86 PVOID Alloc(ULONG NumBytes)
87 {
88 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, NumBytes);
89 }
90
91 MIXER_STATUS
92 Close(HANDLE hDevice)
93 {
94 if (CloseHandle(hDevice))
95 return MM_STATUS_SUCCESS;
96 else
97 return MM_STATUS_UNSUCCESSFUL;
98 }
99
100 VOID
101 Free(PVOID Block)
102 {
103 HeapFree(GetProcessHeap(), 0, Block);
104 }
105
106 VOID
107 Copy(PVOID Src, PVOID Dst, ULONG NumBytes)
108 {
109 CopyMemory(Src, Dst, NumBytes);
110 }
111
112 MIXER_STATUS
113 Open(
114 IN LPWSTR DevicePath,
115 OUT PHANDLE hDevice)
116 {
117 DevicePath[1] = L'\\';
118 *hDevice = CreateFileW(DevicePath,
119 GENERIC_READ | GENERIC_WRITE,
120 0,
121 NULL,
122 OPEN_EXISTING,
123 FILE_FLAG_OVERLAPPED,
124 NULL);
125 if (*hDevice == INVALID_HANDLE_VALUE)
126 {
127 return MM_STATUS_UNSUCCESSFUL;
128 }
129
130 return MM_STATUS_SUCCESS;
131 }
132
133 MIXER_STATUS
134 Control(
135 IN HANDLE hMixer,
136 IN ULONG dwIoControlCode,
137 IN PVOID lpInBuffer,
138 IN ULONG nInBufferSize,
139 OUT PVOID lpOutBuffer,
140 ULONG nOutBufferSize,
141 PULONG lpBytesReturned)
142 {
143 OVERLAPPED Overlapped;
144 BOOLEAN IoResult;
145 DWORD Transferred = 0;
146
147 /* Overlapped I/O is done here - this is used for waiting for completion */
148 ZeroMemory(&Overlapped, sizeof(OVERLAPPED));
149 Overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
150
151 if ( ! Overlapped.hEvent )
152 return MM_STATUS_NO_MEMORY;
153
154 /* Talk to the device */
155 IoResult = DeviceIoControl(hMixer,
156 dwIoControlCode,
157 lpInBuffer,
158 nInBufferSize,
159 lpOutBuffer,
160 nOutBufferSize,
161 &Transferred,
162 &Overlapped);
163
164 /* If failure occurs, make sure it's not just due to the overlapped I/O */
165 if ( ! IoResult )
166 {
167 if ( GetLastError() != ERROR_IO_PENDING )
168 {
169 CloseHandle(Overlapped.hEvent);
170
171 if (GetLastError() == ERROR_MORE_DATA || GetLastError() == ERROR_INSUFFICIENT_BUFFER)
172 {
173 if ( lpBytesReturned )
174 *lpBytesReturned = Transferred;
175 return MM_STATUS_MORE_ENTRIES;
176 }
177
178 return MM_STATUS_UNSUCCESSFUL;
179 }
180 }
181
182 /* Wait for the I/O to complete */
183 IoResult = GetOverlappedResult(hMixer,
184 &Overlapped,
185 &Transferred,
186 TRUE);
187
188 /* Don't need this any more */
189 CloseHandle(Overlapped.hEvent);
190
191 if ( ! IoResult )
192 return MM_STATUS_UNSUCCESSFUL;
193
194 if ( lpBytesReturned )
195 *lpBytesReturned = Transferred;
196
197 return MM_STATUS_SUCCESS;
198 }
199
200 MIXER_STATUS
201 Enum(
202 IN PVOID EnumContext,
203 IN ULONG DeviceIndex,
204 OUT LPWSTR * DeviceName,
205 OUT PHANDLE OutHandle,
206 OUT PHANDLE OutKey)
207 {
208 SP_DEVICE_INTERFACE_DATA InterfaceData;
209 SP_DEVINFO_DATA DeviceData;
210 PSP_DEVICE_INTERFACE_DETAIL_DATA_W DetailData;
211 BOOL Result;
212 DWORD Length;
213 MIXER_STATUS Status;
214
215 //printf("Enum EnumContext %p DeviceIndex %lu OutHandle %p\n", EnumContext, DeviceIndex, OutHandle);
216
217 InterfaceData.cbSize = sizeof(InterfaceData);
218 InterfaceData.Reserved = 0;
219
220 Result = SetupDiEnumDeviceInterfaces(EnumContext,
221 NULL,
222 &CategoryGuid,
223 DeviceIndex,
224 &InterfaceData);
225
226 if (!Result)
227 {
228 if (GetLastError() == ERROR_NO_MORE_ITEMS)
229 {
230 return MM_STATUS_NO_MORE_DEVICES;
231 }
232 return MM_STATUS_UNSUCCESSFUL;
233 }
234
235 Length = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + MAX_PATH * sizeof(WCHAR);
236 DetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)HeapAlloc(GetProcessHeap(),
237 0,
238 Length);
239 DetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
240 DeviceData.cbSize = sizeof(DeviceData);
241 DeviceData.Reserved = 0;
242
243 Result = SetupDiGetDeviceInterfaceDetailW(EnumContext,
244 &InterfaceData,
245 DetailData,
246 Length,
247 NULL,
248 &DeviceData);
249
250 if (!Result)
251 {
252 DPRINT("SetupDiGetDeviceInterfaceDetailW failed with %lu\n", GetLastError());
253 return MM_STATUS_UNSUCCESSFUL;
254 }
255
256
257 *OutKey = SetupDiOpenDeviceInterfaceRegKey(EnumContext, &InterfaceData, 0, KEY_READ);
258 if ((HKEY)*OutKey == INVALID_HANDLE_VALUE)
259 {
260 HeapFree(GetProcessHeap(), 0, DetailData);
261 return MM_STATUS_UNSUCCESSFUL;
262 }
263
264 Status = Open(DetailData->DevicePath, OutHandle);
265
266 if (Status != MM_STATUS_SUCCESS)
267 {
268 RegCloseKey((HKEY)*OutKey);
269 HeapFree(GetProcessHeap(), 0, DetailData);
270 return Status;
271 }
272
273 *DeviceName = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wcslen(DetailData->DevicePath)+1) * sizeof(WCHAR));
274 if (*DeviceName == NULL)
275 {
276 CloseHandle(*OutHandle);
277 RegCloseKey((HKEY)*OutKey);
278 HeapFree(GetProcessHeap(), 0, DetailData);
279 return MM_STATUS_NO_MEMORY;
280 }
281
282 wcscpy(*DeviceName, DetailData->DevicePath);
283 HeapFree(GetProcessHeap(), 0, DetailData);
284
285 return Status;
286 }
287
288 BOOL
289 WdmAudInitUserModeMixer()
290 {
291 HDEVINFO DeviceHandle;
292 MIXER_STATUS Status;
293
294 /* create a device list */
295 DeviceHandle = SetupDiGetClassDevs(&CategoryGuid,
296 NULL,
297 NULL,
298 DIGCF_DEVICEINTERFACE|DIGCF_PRESENT);
299
300 if (DeviceHandle == INVALID_HANDLE_VALUE)
301 {
302 /* failed to create a device list */
303 return FALSE;
304 }
305
306
307 /* initialize the mixer library */
308 Status = MMixerInitialize(&MixerContext, Enum, (PVOID)DeviceHandle);
309
310 /* free device list */
311 SetupDiDestroyDeviceInfoList(DeviceHandle);
312
313 if (Status != MM_STATUS_SUCCESS)
314 {
315 /* failed to initialize mixer library */
316 DPRINT1("Failed to initialize mixer library with %x\n", Status);
317 return FALSE;
318 }
319
320 /* completed successfully */
321 return TRUE;
322 }
323
324 ULONG
325 WdmAudGetMixerCount()
326 {
327 /* return number of mixers available */
328 return MMixerGetCount(&MixerContext);
329 }
330
331 MMRESULT
332 WdmAudGetMixerCapabilties(
333 IN ULONG DeviceId,
334 LPMIXERCAPSW Capabilities)
335 {
336 if (MMixerGetCapabilities(&MixerContext, DeviceId, Capabilities) == MM_STATUS_SUCCESS)
337 return MMSYSERR_NOERROR;
338
339 return MMSYSERR_BADDEVICEID;
340 }
341
342 MMRESULT
343 WdmAudCloseMixer(
344 IN HMIXER Handle,
345 IN HANDLE hNotifyEvent)
346 {
347 /* FIXME */
348 return MMSYSERR_NOERROR;
349 }
350
351 MMRESULT
352 WdmAudOpenMixer(
353 IN PHANDLE hMixer,
354 IN ULONG DeviceId,
355 IN HANDLE hNotifyEvent)
356 {
357 if (MMixerOpen(&MixerContext, DeviceId, hNotifyEvent, NULL /* FIXME */, hMixer) == MM_STATUS_SUCCESS)
358 return MMSYSERR_NOERROR;
359
360 return MMSYSERR_BADDEVICEID;
361 }
362
363 MMRESULT
364 WdmAudGetLineInfo(
365 IN HANDLE hMixer,
366 IN LPMIXERLINE MixLine,
367 IN ULONG Flags)
368 {
369 if (MMixerGetLineInfo(&MixerContext, hMixer, Flags, MixLine) == MM_STATUS_SUCCESS)
370 return MMSYSERR_NOERROR;
371
372 return MMSYSERR_ERROR;
373 }
374
375 MMRESULT
376 WdmAudGetLineControls(
377 IN HANDLE hMixer,
378 IN LPMIXERLINECONTROLSW MixControls,
379 IN ULONG Flags)
380 {
381 if (MMixerGetLineControls(&MixerContext, hMixer, Flags, MixControls) == MM_STATUS_SUCCESS)
382 return MMSYSERR_NOERROR;
383
384 return MMSYSERR_ERROR;
385 }
386
387 MMRESULT
388 WdmAudSetControlDetails(
389 IN HANDLE hMixer,
390 IN LPMIXERCONTROLDETAILS MixDetails,
391 IN ULONG Flags)
392 {
393 if (MMixerSetControlDetails(&MixerContext, hMixer, Flags, MixDetails) == MM_STATUS_SUCCESS)
394 return MMSYSERR_NOERROR;
395
396 return MMSYSERR_ERROR;
397
398 }
399
400 MMRESULT
401 WdmAudGetControlDetails(
402 IN HANDLE hMixer,
403 IN LPMIXERCONTROLDETAILS MixDetails,
404 IN ULONG Flags)
405 {
406 if (MMixerGetControlDetails(&MixerContext, hMixer, Flags, MixDetails) == MM_STATUS_SUCCESS)
407 return MMSYSERR_NOERROR;
408
409 return MMSYSERR_ERROR;
410 }