[WDMAUD.DRV]
[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);
20
21 MIXER_CONTEXT MixerContext =
22 {
23 sizeof(MIXER_CONTEXT),
24 NULL,
25 Alloc,
26 Control,
27 Free,
28 Open,
29 Close,
30 Copy
31 };
32
33 GUID CategoryGuid = {STATIC_KSCATEGORY_AUDIO};
34
35 PVOID Alloc(ULONG NumBytes)
36 {
37 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, NumBytes);
38 }
39
40 MIXER_STATUS
41 Close(HANDLE hDevice)
42 {
43 if (CloseHandle(hDevice))
44 return MM_STATUS_SUCCESS;
45 else
46 return MM_STATUS_UNSUCCESSFUL;
47 }
48
49 VOID
50 Free(PVOID Block)
51 {
52 HeapFree(GetProcessHeap(), 0, Block);
53 }
54
55 VOID
56 Copy(PVOID Src, PVOID Dst, ULONG NumBytes)
57 {
58 CopyMemory(Src, Dst, NumBytes);
59 }
60
61 MIXER_STATUS
62 Open(
63 IN LPWSTR DevicePath,
64 OUT PHANDLE hDevice)
65 {
66 DevicePath[1] = L'\\';
67 *hDevice = CreateFileW(DevicePath,
68 GENERIC_READ | GENERIC_WRITE,
69 0,
70 NULL,
71 OPEN_EXISTING,
72 FILE_FLAG_OVERLAPPED,
73 NULL);
74 if (*hDevice == INVALID_HANDLE_VALUE)
75 {
76 return MM_STATUS_UNSUCCESSFUL;
77 }
78
79 return MM_STATUS_SUCCESS;
80 }
81
82 MIXER_STATUS
83 Control(
84 IN HANDLE hMixer,
85 IN ULONG dwIoControlCode,
86 IN PVOID lpInBuffer,
87 IN ULONG nInBufferSize,
88 OUT PVOID lpOutBuffer,
89 ULONG nOutBufferSize,
90 PULONG lpBytesReturned)
91 {
92 OVERLAPPED Overlapped;
93 BOOLEAN IoResult;
94 DWORD Transferred = 0;
95
96 /* Overlapped I/O is done here - this is used for waiting for completion */
97 ZeroMemory(&Overlapped, sizeof(OVERLAPPED));
98 Overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
99
100 if ( ! Overlapped.hEvent )
101 return MM_STATUS_NO_MEMORY;
102
103 /* Talk to the device */
104 IoResult = DeviceIoControl(hMixer,
105 dwIoControlCode,
106 lpInBuffer,
107 nInBufferSize,
108 lpOutBuffer,
109 nOutBufferSize,
110 &Transferred,
111 &Overlapped);
112
113 /* If failure occurs, make sure it's not just due to the overlapped I/O */
114 if ( ! IoResult )
115 {
116 if ( GetLastError() != ERROR_IO_PENDING )
117 {
118 CloseHandle(Overlapped.hEvent);
119
120 if (GetLastError() == ERROR_MORE_DATA || GetLastError() == ERROR_INSUFFICIENT_BUFFER)
121 {
122 if ( lpBytesReturned )
123 *lpBytesReturned = Transferred;
124 return MM_STATUS_MORE_ENTRIES;
125 }
126
127 return MM_STATUS_UNSUCCESSFUL;
128 }
129 }
130
131 /* Wait for the I/O to complete */
132 IoResult = GetOverlappedResult(hMixer,
133 &Overlapped,
134 &Transferred,
135 TRUE);
136
137 /* Don't need this any more */
138 CloseHandle(Overlapped.hEvent);
139
140 if ( ! IoResult )
141 return MM_STATUS_UNSUCCESSFUL;
142
143 if ( lpBytesReturned )
144 *lpBytesReturned = Transferred;
145
146 return MM_STATUS_SUCCESS;
147 }
148
149 MIXER_STATUS
150 Enum(
151 IN PVOID EnumContext,
152 IN ULONG DeviceIndex,
153 OUT LPWSTR * DeviceName,
154 OUT PHANDLE OutHandle)
155 {
156 SP_DEVICE_INTERFACE_DATA InterfaceData;
157 SP_DEVINFO_DATA DeviceData;
158 PSP_DEVICE_INTERFACE_DETAIL_DATA_W DetailData;
159 BOOL Result;
160 DWORD Length;
161
162 //printf("Enum EnumContext %p DeviceIndex %lu OutHandle %p\n", EnumContext, DeviceIndex, OutHandle);
163
164 InterfaceData.cbSize = sizeof(InterfaceData);
165 InterfaceData.Reserved = 0;
166
167 Result = SetupDiEnumDeviceInterfaces(EnumContext,
168 NULL,
169 &CategoryGuid,
170 DeviceIndex,
171 &InterfaceData);
172
173 if (!Result)
174 {
175 if (GetLastError() == ERROR_NO_MORE_ITEMS)
176 {
177 return MM_STATUS_NO_MORE_DEVICES;
178 }
179 return MM_STATUS_UNSUCCESSFUL;
180 }
181
182 Length = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + MAX_PATH * sizeof(WCHAR);
183 DetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)HeapAlloc(GetProcessHeap(),
184 0,
185 Length);
186 DetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
187 DeviceData.cbSize = sizeof(DeviceData);
188 DeviceData.Reserved = 0;
189
190 Result = SetupDiGetDeviceInterfaceDetailW(EnumContext,
191 &InterfaceData,
192 DetailData,
193 Length,
194 NULL,
195 &DeviceData);
196
197 if (!Result)
198 {
199 return MM_STATUS_UNSUCCESSFUL;
200 }
201
202 // copy path
203 *DeviceName = (LPWSTR)&DetailData->DevicePath[0];
204 return Open(DetailData->DevicePath, OutHandle);
205 }
206
207 BOOL
208 WdmAudInitUserModeMixer()
209 {
210 HDEVINFO DeviceHandle;
211 MIXER_STATUS Status;
212
213 /* create a device list */
214 DeviceHandle = SetupDiGetClassDevs(&CategoryGuid,
215 NULL,
216 NULL,
217 DIGCF_DEVICEINTERFACE|DIGCF_PRESENT);
218
219 if (DeviceHandle == INVALID_HANDLE_VALUE)
220 {
221 /* failed to create a device list */
222 return FALSE;
223 }
224
225
226 /* initialize the mixer library */
227 Status = MMixerInitialize(&MixerContext, Enum, (PVOID)DeviceHandle);
228
229 /* free device list */
230 SetupDiDestroyDeviceInfoList(DeviceHandle);
231
232 if (Status != MM_STATUS_SUCCESS)
233 {
234 /* failed to initialize mixer library */
235 DPRINT1("Failed to initialize mixer library with %x\n", Status);
236 return FALSE;
237 }
238
239 /* completed successfully */
240 return TRUE;
241 }
242
243 ULONG
244 WdmAudGetMixerCount()
245 {
246 /* return number of mixers available */
247 return MMixerGetCount(&MixerContext);
248 }
249
250 MMRESULT
251 WdmAudGetMixerCapabilties(
252 IN ULONG DeviceId,
253 LPMIXERCAPSW Capabilities)
254 {
255 if (MMixerGetCapabilities(&MixerContext, DeviceId, Capabilities) == MM_STATUS_SUCCESS)
256 return MMSYSERR_NOERROR;
257
258 return MMSYSERR_BADDEVICEID;
259 }
260
261 MMRESULT
262 WdmAudCloseMixer(
263 IN HMIXER Handle,
264 IN HANDLE hNotifyEvent)
265 {
266 /* FIXME */
267 return MMSYSERR_NOERROR;
268 }
269
270 MMRESULT
271 WdmAudOpenMixer(
272 IN PHANDLE hMixer,
273 IN ULONG DeviceId,
274 IN HANDLE hNotifyEvent)
275 {
276 if (MMixerOpen(&MixerContext, DeviceId, hNotifyEvent, NULL /* FIXME */, hMixer) == MM_STATUS_SUCCESS)
277 return MMSYSERR_NOERROR;
278
279 return MMSYSERR_BADDEVICEID;
280 }
281
282 MMRESULT
283 WdmAudGetLineInfo(
284 IN HANDLE hMixer,
285 IN LPMIXERLINE MixLine,
286 IN ULONG Flags)
287 {
288 if (MMixerGetLineInfo(&MixerContext, hMixer, Flags, MixLine) == MM_STATUS_SUCCESS)
289 return MMSYSERR_NOERROR;
290
291 return MMSYSERR_ERROR;
292 }
293
294 MMRESULT
295 WdmAudGetLineControls(
296 IN HANDLE hMixer,
297 IN LPMIXERLINECONTROLSW MixControls,
298 IN ULONG Flags)
299 {
300 if (MMixerGetLineControls(&MixerContext, hMixer, Flags, MixControls) == MM_STATUS_SUCCESS)
301 return MMSYSERR_NOERROR;
302
303 return MMSYSERR_ERROR;
304 }
305
306 MMRESULT
307 WdmAudSetControlDetails(
308 IN HANDLE hMixer,
309 IN LPMIXERCONTROLDETAILS MixDetails,
310 IN ULONG Flags)
311 {
312 if (MMixerSetControlDetails(&MixerContext, hMixer, Flags, MixDetails) == MM_STATUS_SUCCESS)
313 return MMSYSERR_NOERROR;
314
315 return MMSYSERR_ERROR;
316
317 }
318
319 MMRESULT
320 WdmAudGetControlDetails(
321 IN HANDLE hMixer,
322 IN LPMIXERCONTROLDETAILS MixDetails,
323 IN ULONG Flags)
324 {
325 if (MMixerGetControlDetails(&MixerContext, hMixer, Flags, MixDetails) == MM_STATUS_SUCCESS)
326 return MMSYSERR_NOERROR;
327
328 return MMSYSERR_ERROR;
329 }