xref: /reactos/dll/win32/wdmaud.drv/mmixer.c (revision 9046cc97)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * PROJECT:     ReactOS Sound System
3c2c66affSColin Finck  * LICENSE:     GPL - See COPYING in the top level directory
4c2c66affSColin Finck  * FILE:        dll/win32/wdmaud.drv/mmixer.c
5c2c66affSColin Finck  *
6c2c66affSColin Finck  * PURPOSE:     WDM Audio Mixer API (User-mode part)
7c2c66affSColin Finck  * PROGRAMMERS: Johannes Anderwald
8c2c66affSColin Finck  */
9c2c66affSColin Finck 
10c2c66affSColin Finck #include "wdmaud.h"
11c2c66affSColin Finck 
12c2c66affSColin Finck #include <winreg.h>
13c2c66affSColin Finck #include <setupapi.h>
14c2c66affSColin Finck #include <mmixer.h>
15b8e936a5SMichael Stamper #define NTOS_MODE_USER
16b8e936a5SMichael Stamper #include <ndk/rtlfuncs.h>
17b8e936a5SMichael Stamper #include <ndk/iofuncs.h>
18c2c66affSColin Finck 
19c2c66affSColin Finck #define NDEBUG
20c2c66affSColin Finck #include <debug.h>
21c2c66affSColin Finck #include <mmebuddy_debug.h>
22c2c66affSColin Finck 
23c2c66affSColin Finck 
24c2c66affSColin Finck BOOL MMixerLibraryInitialized = FALSE;
25c2c66affSColin Finck 
26c2c66affSColin Finck 
27c2c66affSColin Finck 
28c2c66affSColin Finck PVOID Alloc(ULONG NumBytes);
29c2c66affSColin Finck MIXER_STATUS Close(HANDLE hDevice);
30c2c66affSColin Finck VOID Free(PVOID Block);
31c2c66affSColin Finck VOID Copy(PVOID Src, PVOID Dst, ULONG NumBytes);
32c2c66affSColin Finck MIXER_STATUS Open(IN LPWSTR DevicePath, OUT PHANDLE hDevice);
33c2c66affSColin Finck MIXER_STATUS Control(IN HANDLE hMixer, IN ULONG dwIoControlCode, IN PVOID lpInBuffer, IN ULONG nInBufferSize, OUT PVOID lpOutBuffer, ULONG nOutBufferSize, PULONG lpBytesReturned);
34c2c66affSColin Finck MIXER_STATUS Enum(IN  PVOID EnumContext, IN  ULONG DeviceIndex, OUT LPWSTR * DeviceName, OUT PHANDLE OutHandle, OUT PHANDLE OutKey);
35c2c66affSColin Finck MIXER_STATUS OpenKey(IN HANDLE hKey, IN LPWSTR SubKey, IN ULONG DesiredAccess, OUT PHANDLE OutKey);
36c2c66affSColin Finck MIXER_STATUS CloseKey(IN HANDLE hKey);
37c2c66affSColin Finck MIXER_STATUS QueryKeyValue(IN HANDLE hKey, IN LPWSTR KeyName, OUT PVOID * ResultBuffer, OUT PULONG ResultLength, OUT PULONG KeyType);
38c2c66affSColin Finck PVOID AllocEventData(IN ULONG ExtraSize);
39c2c66affSColin Finck VOID FreeEventData(IN PVOID EventData);
40c2c66affSColin Finck 
41c2c66affSColin Finck MIXER_CONTEXT MixerContext =
42c2c66affSColin Finck {
43c2c66affSColin Finck     sizeof(MIXER_CONTEXT),
44c2c66affSColin Finck     NULL,
45c2c66affSColin Finck     Alloc,
46c2c66affSColin Finck     Control,
47c2c66affSColin Finck     Free,
48c2c66affSColin Finck     Open,
49c2c66affSColin Finck     Close,
50c2c66affSColin Finck     Copy,
51c2c66affSColin Finck     OpenKey,
52c2c66affSColin Finck     QueryKeyValue,
53c2c66affSColin Finck     CloseKey,
54c2c66affSColin Finck     AllocEventData,
55c2c66affSColin Finck     FreeEventData
56c2c66affSColin Finck };
57c2c66affSColin Finck 
58c2c66affSColin Finck GUID CategoryGuid = {STATIC_KSCATEGORY_AUDIO};
59c2c66affSColin Finck 
60c2c66affSColin Finck MIXER_STATUS
QueryKeyValue(IN HANDLE hKey,IN LPWSTR KeyName,OUT PVOID * ResultBuffer,OUT PULONG ResultLength,OUT PULONG KeyType)61c2c66affSColin Finck QueryKeyValue(
62c2c66affSColin Finck     IN HANDLE hKey,
63c2c66affSColin Finck     IN LPWSTR KeyName,
64c2c66affSColin Finck     OUT PVOID * ResultBuffer,
65c2c66affSColin Finck     OUT PULONG ResultLength,
66c2c66affSColin Finck     OUT PULONG KeyType)
67c2c66affSColin Finck {
68c2c66affSColin Finck     if (RegQueryValueExW((HKEY)hKey, KeyName, NULL, KeyType, NULL, ResultLength) == ERROR_FILE_NOT_FOUND)
69c2c66affSColin Finck         return MM_STATUS_UNSUCCESSFUL;
70c2c66affSColin Finck 
71c2c66affSColin Finck     *ResultBuffer = HeapAlloc(GetProcessHeap(), 0, *ResultLength);
72c2c66affSColin Finck     if (*ResultBuffer == NULL)
73c2c66affSColin Finck         return MM_STATUS_NO_MEMORY;
74c2c66affSColin Finck 
75c2c66affSColin Finck     if (RegQueryValueExW((HKEY)hKey, KeyName, NULL, KeyType, *ResultBuffer, ResultLength) != ERROR_SUCCESS)
76c2c66affSColin Finck     {
77c2c66affSColin Finck         HeapFree(GetProcessHeap(), 0, *ResultBuffer);
78c2c66affSColin Finck         return MM_STATUS_UNSUCCESSFUL;
79c2c66affSColin Finck     }
80c2c66affSColin Finck     return MM_STATUS_SUCCESS;
81c2c66affSColin Finck }
82c2c66affSColin Finck 
83c2c66affSColin Finck MIXER_STATUS
OpenKey(IN HANDLE hKey,IN LPWSTR SubKey,IN ULONG DesiredAccess,OUT PHANDLE OutKey)84c2c66affSColin Finck OpenKey(
85c2c66affSColin Finck     IN HANDLE hKey,
86c2c66affSColin Finck     IN LPWSTR SubKey,
87c2c66affSColin Finck     IN ULONG DesiredAccess,
88c2c66affSColin Finck     OUT PHANDLE OutKey)
89c2c66affSColin Finck {
90c2c66affSColin Finck     if (RegOpenKeyExW((HKEY)hKey, SubKey, 0, DesiredAccess, (PHKEY)OutKey) == ERROR_SUCCESS)
91c2c66affSColin Finck         return MM_STATUS_SUCCESS;
92c2c66affSColin Finck 
93c2c66affSColin Finck     return MM_STATUS_UNSUCCESSFUL;
94c2c66affSColin Finck }
95c2c66affSColin Finck 
96c2c66affSColin Finck MIXER_STATUS
CloseKey(IN HANDLE hKey)97c2c66affSColin Finck CloseKey(
98c2c66affSColin Finck     IN HANDLE hKey)
99c2c66affSColin Finck {
100c2c66affSColin Finck     RegCloseKey((HKEY)hKey);
101c2c66affSColin Finck     return MM_STATUS_SUCCESS;
102c2c66affSColin Finck }
103c2c66affSColin Finck 
104c2c66affSColin Finck 
Alloc(ULONG NumBytes)105c2c66affSColin Finck PVOID Alloc(ULONG NumBytes)
106c2c66affSColin Finck {
107c2c66affSColin Finck     return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, NumBytes);
108c2c66affSColin Finck }
109c2c66affSColin Finck 
110c2c66affSColin Finck MIXER_STATUS
Close(HANDLE hDevice)111c2c66affSColin Finck Close(HANDLE hDevice)
112c2c66affSColin Finck {
113c2c66affSColin Finck     if (CloseHandle(hDevice))
114c2c66affSColin Finck         return MM_STATUS_SUCCESS;
115c2c66affSColin Finck     else
116c2c66affSColin Finck         return MM_STATUS_UNSUCCESSFUL;
117c2c66affSColin Finck }
118c2c66affSColin Finck 
119c2c66affSColin Finck VOID
Free(PVOID Block)120c2c66affSColin Finck Free(PVOID Block)
121c2c66affSColin Finck {
122c2c66affSColin Finck     HeapFree(GetProcessHeap(), 0, Block);
123c2c66affSColin Finck }
124c2c66affSColin Finck 
125c2c66affSColin Finck VOID
Copy(PVOID Src,PVOID Dst,ULONG NumBytes)126c2c66affSColin Finck Copy(PVOID Src, PVOID Dst, ULONG NumBytes)
127c2c66affSColin Finck {
128c2c66affSColin Finck     RtlMoveMemory(Src, Dst, NumBytes);
129c2c66affSColin Finck }
130c2c66affSColin Finck 
131c2c66affSColin Finck MIXER_STATUS
Open(IN LPWSTR DevicePath,OUT PHANDLE hDevice)132c2c66affSColin Finck Open(
133c2c66affSColin Finck     IN LPWSTR DevicePath,
134c2c66affSColin Finck     OUT PHANDLE hDevice)
135c2c66affSColin Finck {
136c2c66affSColin Finck      DevicePath[1] = L'\\';
137c2c66affSColin Finck     *hDevice = CreateFileW(DevicePath,
138c2c66affSColin Finck                            GENERIC_READ | GENERIC_WRITE,
139c2c66affSColin Finck                            0,
140c2c66affSColin Finck                            NULL,
141c2c66affSColin Finck                            OPEN_EXISTING,
142c2c66affSColin Finck                            FILE_FLAG_OVERLAPPED,
143c2c66affSColin Finck                            NULL);
144c2c66affSColin Finck     if (*hDevice == INVALID_HANDLE_VALUE)
145c2c66affSColin Finck     {
146c2c66affSColin Finck         return MM_STATUS_UNSUCCESSFUL;
147c2c66affSColin Finck     }
148c2c66affSColin Finck 
149c2c66affSColin Finck     return MM_STATUS_SUCCESS;
150c2c66affSColin Finck }
151c2c66affSColin Finck 
152c2c66affSColin Finck MIXER_STATUS
Control(IN HANDLE hMixer,IN ULONG dwIoControlCode,IN PVOID lpInBuffer,IN ULONG nInBufferSize,OUT PVOID lpOutBuffer,ULONG nOutBufferSize,PULONG lpBytesReturned)153c2c66affSColin Finck Control(
154c2c66affSColin Finck     IN HANDLE hMixer,
155c2c66affSColin Finck     IN ULONG dwIoControlCode,
156c2c66affSColin Finck     IN PVOID lpInBuffer,
157c2c66affSColin Finck     IN ULONG nInBufferSize,
158c2c66affSColin Finck     OUT PVOID lpOutBuffer,
159c2c66affSColin Finck     ULONG nOutBufferSize,
160c2c66affSColin Finck     PULONG lpBytesReturned)
161c2c66affSColin Finck {
162c2c66affSColin Finck     OVERLAPPED Overlapped;
163c2c66affSColin Finck     BOOLEAN IoResult;
164c2c66affSColin Finck     DWORD Transferred = 0;
165c2c66affSColin Finck 
166c2c66affSColin Finck     /* Overlapped I/O is done here - this is used for waiting for completion */
167c2c66affSColin Finck     ZeroMemory(&Overlapped, sizeof(OVERLAPPED));
168c2c66affSColin Finck     Overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
169c2c66affSColin Finck 
170c2c66affSColin Finck     if ( ! Overlapped.hEvent )
171c2c66affSColin Finck         return MM_STATUS_NO_MEMORY;
172c2c66affSColin Finck 
173c2c66affSColin Finck     /* Talk to the device */
174c2c66affSColin Finck     IoResult = DeviceIoControl(hMixer,
175c2c66affSColin Finck                                dwIoControlCode,
176c2c66affSColin Finck                                lpInBuffer,
177c2c66affSColin Finck                                nInBufferSize,
178c2c66affSColin Finck                                lpOutBuffer,
179c2c66affSColin Finck                                nOutBufferSize,
180c2c66affSColin Finck                                &Transferred,
181c2c66affSColin Finck                                &Overlapped);
182c2c66affSColin Finck 
183c2c66affSColin Finck     /* If failure occurs, make sure it's not just due to the overlapped I/O */
184c2c66affSColin Finck     if ( ! IoResult )
185c2c66affSColin Finck     {
186c2c66affSColin Finck         if ( GetLastError() != ERROR_IO_PENDING )
187c2c66affSColin Finck         {
188c2c66affSColin Finck             CloseHandle(Overlapped.hEvent);
189c2c66affSColin Finck 
190c2c66affSColin Finck             if (GetLastError() == ERROR_MORE_DATA || GetLastError() == ERROR_INSUFFICIENT_BUFFER)
191c2c66affSColin Finck             {
192c2c66affSColin Finck                 if ( lpBytesReturned )
193c2c66affSColin Finck                     *lpBytesReturned = Transferred;
194c2c66affSColin Finck                 return MM_STATUS_MORE_ENTRIES;
195c2c66affSColin Finck             }
196c2c66affSColin Finck 
197c2c66affSColin Finck             return MM_STATUS_UNSUCCESSFUL;
198c2c66affSColin Finck         }
199c2c66affSColin Finck     }
200c2c66affSColin Finck 
201c2c66affSColin Finck     /* Wait for the I/O to complete */
202c2c66affSColin Finck     IoResult = GetOverlappedResult(hMixer,
203c2c66affSColin Finck                                    &Overlapped,
204c2c66affSColin Finck                                    &Transferred,
205c2c66affSColin Finck                                    TRUE);
206c2c66affSColin Finck 
207c2c66affSColin Finck     /* Don't need this any more */
208c2c66affSColin Finck     CloseHandle(Overlapped.hEvent);
209c2c66affSColin Finck 
210c2c66affSColin Finck     if ( ! IoResult )
211c2c66affSColin Finck         return MM_STATUS_UNSUCCESSFUL;
212c2c66affSColin Finck 
213c2c66affSColin Finck     if ( lpBytesReturned )
214c2c66affSColin Finck         *lpBytesReturned = Transferred;
215c2c66affSColin Finck 
216c2c66affSColin Finck     return MM_STATUS_SUCCESS;
217c2c66affSColin Finck }
218c2c66affSColin Finck 
219c2c66affSColin Finck MIXER_STATUS
Enum(IN PVOID EnumContext,IN ULONG DeviceIndex,OUT LPWSTR * DeviceName,OUT PHANDLE OutHandle,OUT PHANDLE OutKey)220c2c66affSColin Finck Enum(
221c2c66affSColin Finck     IN  PVOID EnumContext,
222c2c66affSColin Finck     IN  ULONG DeviceIndex,
223c2c66affSColin Finck     OUT LPWSTR * DeviceName,
224c2c66affSColin Finck     OUT PHANDLE OutHandle,
225c2c66affSColin Finck     OUT PHANDLE OutKey)
226c2c66affSColin Finck {
227c2c66affSColin Finck     SP_DEVICE_INTERFACE_DATA InterfaceData;
228c2c66affSColin Finck     SP_DEVINFO_DATA DeviceData;
229c2c66affSColin Finck     PSP_DEVICE_INTERFACE_DETAIL_DATA_W DetailData;
230c2c66affSColin Finck     BOOL Result;
231c2c66affSColin Finck     DWORD Length;
232c2c66affSColin Finck     MIXER_STATUS Status;
233c2c66affSColin Finck 
234c2c66affSColin Finck     //printf("Enum EnumContext %p DeviceIndex %lu OutHandle %p\n", EnumContext, DeviceIndex, OutHandle);
235c2c66affSColin Finck 
236c2c66affSColin Finck     InterfaceData.cbSize = sizeof(InterfaceData);
237c2c66affSColin Finck     InterfaceData.Reserved = 0;
238c2c66affSColin Finck 
239c2c66affSColin Finck     Result = SetupDiEnumDeviceInterfaces(EnumContext,
240c2c66affSColin Finck                                 NULL,
241c2c66affSColin Finck                                 &CategoryGuid,
242c2c66affSColin Finck                                 DeviceIndex,
243c2c66affSColin Finck                                 &InterfaceData);
244c2c66affSColin Finck 
245c2c66affSColin Finck     if (!Result)
246c2c66affSColin Finck     {
247c2c66affSColin Finck         if (GetLastError() == ERROR_NO_MORE_ITEMS)
248c2c66affSColin Finck         {
249c2c66affSColin Finck             return MM_STATUS_NO_MORE_DEVICES;
250c2c66affSColin Finck         }
251c2c66affSColin Finck         return MM_STATUS_UNSUCCESSFUL;
252c2c66affSColin Finck     }
253c2c66affSColin Finck 
254c2c66affSColin Finck     Length = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + MAX_PATH * sizeof(WCHAR);
255c2c66affSColin Finck     DetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)HeapAlloc(GetProcessHeap(),
256c2c66affSColin Finck                                                              0,
257c2c66affSColin Finck                                                              Length);
258c2c66affSColin Finck     DetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
259c2c66affSColin Finck     DeviceData.cbSize = sizeof(DeviceData);
260c2c66affSColin Finck     DeviceData.Reserved = 0;
261c2c66affSColin Finck 
262c2c66affSColin Finck     Result = SetupDiGetDeviceInterfaceDetailW(EnumContext,
263c2c66affSColin Finck                                     &InterfaceData,
264c2c66affSColin Finck                                     DetailData,
265c2c66affSColin Finck                                     Length,
266c2c66affSColin Finck                                     NULL,
267c2c66affSColin Finck                                     &DeviceData);
268c2c66affSColin Finck 
269c2c66affSColin Finck     if (!Result)
270c2c66affSColin Finck     {
271c2c66affSColin Finck         DPRINT("SetupDiGetDeviceInterfaceDetailW failed with %lu\n", GetLastError());
272c2c66affSColin Finck         return MM_STATUS_UNSUCCESSFUL;
273c2c66affSColin Finck     }
274c2c66affSColin Finck 
275c2c66affSColin Finck 
276c2c66affSColin Finck     *OutKey = SetupDiOpenDeviceInterfaceRegKey(EnumContext, &InterfaceData, 0, KEY_READ);
277c2c66affSColin Finck      if ((HKEY)*OutKey == INVALID_HANDLE_VALUE)
278c2c66affSColin Finck      {
279c2c66affSColin Finck         HeapFree(GetProcessHeap(), 0, DetailData);
280c2c66affSColin Finck         return MM_STATUS_UNSUCCESSFUL;
281c2c66affSColin Finck     }
282c2c66affSColin Finck 
283c2c66affSColin Finck     Status = Open(DetailData->DevicePath, OutHandle);
284c2c66affSColin Finck 
285c2c66affSColin Finck     if (Status != MM_STATUS_SUCCESS)
286c2c66affSColin Finck     {
287c2c66affSColin Finck         RegCloseKey((HKEY)*OutKey);
288c2c66affSColin Finck         HeapFree(GetProcessHeap(), 0, DetailData);
289c2c66affSColin Finck         return Status;
290c2c66affSColin Finck     }
291c2c66affSColin Finck 
292c2c66affSColin Finck     *DeviceName = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wcslen(DetailData->DevicePath)+1) * sizeof(WCHAR));
293c2c66affSColin Finck     if (*DeviceName == NULL)
294c2c66affSColin Finck     {
295c2c66affSColin Finck         CloseHandle(*OutHandle);
296c2c66affSColin Finck         RegCloseKey((HKEY)*OutKey);
297c2c66affSColin Finck         HeapFree(GetProcessHeap(), 0, DetailData);
298c2c66affSColin Finck         return MM_STATUS_NO_MEMORY;
299c2c66affSColin Finck     }
300c2c66affSColin Finck     wcscpy(*DeviceName, DetailData->DevicePath);
301c2c66affSColin Finck     HeapFree(GetProcessHeap(), 0, DetailData);
302c2c66affSColin Finck 
303c2c66affSColin Finck     return Status;
304c2c66affSColin Finck }
305c2c66affSColin Finck 
306c2c66affSColin Finck PVOID
AllocEventData(IN ULONG ExtraSize)307c2c66affSColin Finck AllocEventData(
308c2c66affSColin Finck     IN ULONG ExtraSize)
309c2c66affSColin Finck {
310c2c66affSColin Finck     PKSEVENTDATA Data = (PKSEVENTDATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(KSEVENTDATA) + ExtraSize);
311c2c66affSColin Finck     if (!Data)
312c2c66affSColin Finck         return NULL;
313c2c66affSColin Finck 
314c2c66affSColin Finck     Data->EventHandle.Event = CreateEventW(NULL, FALSE, FALSE, NULL);
315c2c66affSColin Finck     if (!Data->EventHandle.Event)
316c2c66affSColin Finck     {
317c2c66affSColin Finck         HeapFree(GetProcessHeap(), 0, Data);
318c2c66affSColin Finck         return NULL;
319c2c66affSColin Finck     }
320c2c66affSColin Finck 
321c2c66affSColin Finck     Data->NotificationType = KSEVENTF_EVENT_HANDLE;
322c2c66affSColin Finck     return Data;
323c2c66affSColin Finck }
324c2c66affSColin Finck 
325c2c66affSColin Finck VOID
FreeEventData(IN PVOID EventData)326c2c66affSColin Finck FreeEventData(IN PVOID EventData)
327c2c66affSColin Finck {
328c2c66affSColin Finck     PKSEVENTDATA Data = (PKSEVENTDATA)EventData;
329c2c66affSColin Finck 
330c2c66affSColin Finck     CloseHandle(Data->EventHandle.Event);
331c2c66affSColin Finck     HeapFree(GetProcessHeap(), 0, Data);
332c2c66affSColin Finck }
333c2c66affSColin Finck 
334c2c66affSColin Finck 
335c2c66affSColin Finck BOOL
WdmAudInitUserModeMixer()336c2c66affSColin Finck WdmAudInitUserModeMixer()
337c2c66affSColin Finck {
338c2c66affSColin Finck     HDEVINFO DeviceHandle;
339c2c66affSColin Finck     MIXER_STATUS Status;
340c2c66affSColin Finck 
341c2c66affSColin Finck     if (MMixerLibraryInitialized)
342c2c66affSColin Finck     {
343c2c66affSColin Finck         /* library is already initialized */
344c2c66affSColin Finck         return TRUE;
345c2c66affSColin Finck     }
346c2c66affSColin Finck 
347c2c66affSColin Finck 
348c2c66affSColin Finck     /* create a device list */
349c2c66affSColin Finck     DeviceHandle = SetupDiGetClassDevs(&CategoryGuid,
350c2c66affSColin Finck                                        NULL,
351c2c66affSColin Finck                                        NULL,
352c2c66affSColin Finck                                        DIGCF_DEVICEINTERFACE/* FIXME |DIGCF_PRESENT*/);
353c2c66affSColin Finck 
354c2c66affSColin Finck     if (DeviceHandle == INVALID_HANDLE_VALUE)
355c2c66affSColin Finck     {
356c2c66affSColin Finck         /* failed to create a device list */
357c2c66affSColin Finck         return FALSE;
358c2c66affSColin Finck     }
359c2c66affSColin Finck 
360c2c66affSColin Finck 
361c2c66affSColin Finck     /* initialize the mixer library */
362c2c66affSColin Finck     Status = MMixerInitialize(&MixerContext, Enum, (PVOID)DeviceHandle);
363c2c66affSColin Finck 
364c2c66affSColin Finck     /* free device list */
365c2c66affSColin Finck     SetupDiDestroyDeviceInfoList(DeviceHandle);
366c2c66affSColin Finck 
367c2c66affSColin Finck     if (Status != MM_STATUS_SUCCESS)
368c2c66affSColin Finck     {
369c2c66affSColin Finck         /* failed to initialize mixer library */
370c2c66affSColin Finck         DPRINT1("Failed to initialize mixer library with %x\n", Status);
371c2c66affSColin Finck         return FALSE;
372c2c66affSColin Finck     }
373c2c66affSColin Finck 
374c2c66affSColin Finck     /* library is now initialized */
375c2c66affSColin Finck     MMixerLibraryInitialized = TRUE;
376c2c66affSColin Finck 
377c2c66affSColin Finck     /* completed successfully */
378c2c66affSColin Finck     return TRUE;
379c2c66affSColin Finck }
380c2c66affSColin Finck 
381c2c66affSColin Finck MMRESULT
WdmAudCleanupByMMixer()382c2c66affSColin Finck WdmAudCleanupByMMixer()
383c2c66affSColin Finck {
384c2c66affSColin Finck     /* TODO */
385c2c66affSColin Finck     return MMSYSERR_NOERROR;
386c2c66affSColin Finck }
387c2c66affSColin Finck 
388c2c66affSColin Finck MMRESULT
WdmAudGetMixerCapabilities(IN ULONG DeviceId,LPMIXERCAPSW Capabilities)389c2c66affSColin Finck WdmAudGetMixerCapabilities(
390c2c66affSColin Finck     IN ULONG DeviceId,
391c2c66affSColin Finck     LPMIXERCAPSW Capabilities)
392c2c66affSColin Finck {
393c2c66affSColin Finck     if (MMixerGetCapabilities(&MixerContext, DeviceId, Capabilities) == MM_STATUS_SUCCESS)
394c2c66affSColin Finck         return MMSYSERR_NOERROR;
395c2c66affSColin Finck 
396c2c66affSColin Finck     return MMSYSERR_BADDEVICEID;
397c2c66affSColin Finck }
398c2c66affSColin Finck 
399c2c66affSColin Finck MMRESULT
WdmAudGetLineInfo(IN HANDLE hMixer,IN DWORD MixerId,IN LPMIXERLINEW MixLine,IN ULONG Flags)400c2c66affSColin Finck WdmAudGetLineInfo(
401c2c66affSColin Finck     IN HANDLE hMixer,
402c2c66affSColin Finck     IN DWORD MixerId,
403c2c66affSColin Finck     IN LPMIXERLINEW MixLine,
404c2c66affSColin Finck     IN ULONG Flags)
405c2c66affSColin Finck {
406c2c66affSColin Finck     if (MMixerGetLineInfo(&MixerContext, hMixer, MixerId, Flags, MixLine)  == MM_STATUS_SUCCESS)
407c2c66affSColin Finck         return MMSYSERR_NOERROR;
408c2c66affSColin Finck 
409c2c66affSColin Finck     return MMSYSERR_ERROR;
410c2c66affSColin Finck }
411c2c66affSColin Finck 
412c2c66affSColin Finck MMRESULT
WdmAudGetLineControls(IN HANDLE hMixer,IN DWORD MixerId,IN LPMIXERLINECONTROLSW MixControls,IN ULONG Flags)413c2c66affSColin Finck WdmAudGetLineControls(
414c2c66affSColin Finck     IN HANDLE hMixer,
415c2c66affSColin Finck     IN DWORD MixerId,
416c2c66affSColin Finck     IN LPMIXERLINECONTROLSW MixControls,
417c2c66affSColin Finck     IN ULONG Flags)
418c2c66affSColin Finck {
419c2c66affSColin Finck     if (MMixerGetLineControls(&MixerContext, hMixer, MixerId, Flags, MixControls) == MM_STATUS_SUCCESS)
420c2c66affSColin Finck         return MMSYSERR_NOERROR;
421c2c66affSColin Finck 
422c2c66affSColin Finck     return MMSYSERR_ERROR;
423c2c66affSColin Finck }
424c2c66affSColin Finck 
425c2c66affSColin Finck MMRESULT
WdmAudSetControlDetails(IN HANDLE hMixer,IN DWORD MixerId,IN LPMIXERCONTROLDETAILS MixDetails,IN ULONG Flags)426c2c66affSColin Finck WdmAudSetControlDetails(
427c2c66affSColin Finck     IN HANDLE hMixer,
428c2c66affSColin Finck     IN DWORD MixerId,
429c2c66affSColin Finck     IN LPMIXERCONTROLDETAILS MixDetails,
430c2c66affSColin Finck     IN ULONG Flags)
431c2c66affSColin Finck {
432c2c66affSColin Finck     if (MMixerSetControlDetails(&MixerContext, hMixer, MixerId, Flags, MixDetails) == MM_STATUS_SUCCESS)
433c2c66affSColin Finck         return MMSYSERR_NOERROR;
434c2c66affSColin Finck 
435c2c66affSColin Finck     return MMSYSERR_ERROR;
436c2c66affSColin Finck 
437c2c66affSColin Finck }
438c2c66affSColin Finck 
439c2c66affSColin Finck MMRESULT
WdmAudGetControlDetails(IN HANDLE hMixer,IN DWORD MixerId,IN LPMIXERCONTROLDETAILS MixDetails,IN ULONG Flags)440c2c66affSColin Finck WdmAudGetControlDetails(
441c2c66affSColin Finck     IN HANDLE hMixer,
442c2c66affSColin Finck     IN DWORD MixerId,
443c2c66affSColin Finck     IN LPMIXERCONTROLDETAILS MixDetails,
444c2c66affSColin Finck     IN ULONG Flags)
445c2c66affSColin Finck {
446c2c66affSColin Finck     if (MMixerGetControlDetails(&MixerContext, hMixer, MixerId, Flags, MixDetails) == MM_STATUS_SUCCESS)
447c2c66affSColin Finck         return MMSYSERR_NOERROR;
448c2c66affSColin Finck 
449c2c66affSColin Finck     return MMSYSERR_ERROR;
450c2c66affSColin Finck }
451c2c66affSColin Finck 
452c2c66affSColin Finck MMRESULT
WdmAudGetWaveOutCapabilities(IN ULONG DeviceId,LPWAVEOUTCAPSW Capabilities)453c2c66affSColin Finck WdmAudGetWaveOutCapabilities(
454c2c66affSColin Finck     IN ULONG DeviceId,
455c2c66affSColin Finck     LPWAVEOUTCAPSW Capabilities)
456c2c66affSColin Finck {
457c2c66affSColin Finck     if (MMixerWaveOutCapabilities(&MixerContext, DeviceId, Capabilities) == MM_STATUS_SUCCESS)
458c2c66affSColin Finck         return MMSYSERR_NOERROR;
459c2c66affSColin Finck 
460c2c66affSColin Finck     return MMSYSERR_ERROR;
461c2c66affSColin Finck 
462c2c66affSColin Finck }
463c2c66affSColin Finck 
464c2c66affSColin Finck MMRESULT
WdmAudGetWaveInCapabilities(IN ULONG DeviceId,LPWAVEINCAPSW Capabilities)465c2c66affSColin Finck WdmAudGetWaveInCapabilities(
466c2c66affSColin Finck     IN ULONG DeviceId,
467c2c66affSColin Finck     LPWAVEINCAPSW Capabilities)
468c2c66affSColin Finck {
469c2c66affSColin Finck     if (MMixerWaveInCapabilities(&MixerContext, DeviceId, Capabilities) == MM_STATUS_SUCCESS)
470c2c66affSColin Finck         return MMSYSERR_NOERROR;
471c2c66affSColin Finck 
472c2c66affSColin Finck     return MMSYSERR_ERROR;
473c2c66affSColin Finck }
474c2c66affSColin Finck 
475c2c66affSColin Finck MMRESULT
WdmAudSetWaveDeviceFormatByMMixer(IN PSOUND_DEVICE_INSTANCE Instance,IN DWORD DeviceId,IN PWAVEFORMATEX WaveFormat,IN DWORD WaveFormatSize)476c2c66affSColin Finck WdmAudSetWaveDeviceFormatByMMixer(
477c2c66affSColin Finck     IN  PSOUND_DEVICE_INSTANCE Instance,
478c2c66affSColin Finck     IN  DWORD DeviceId,
479c2c66affSColin Finck     IN  PWAVEFORMATEX WaveFormat,
480c2c66affSColin Finck     IN  DWORD WaveFormatSize)
481c2c66affSColin Finck {
482c2c66affSColin Finck     MMDEVICE_TYPE DeviceType;
483c2c66affSColin Finck     PSOUND_DEVICE SoundDevice;
484c2c66affSColin Finck     MMRESULT Result;
485c2c66affSColin Finck     BOOL bWaveIn;
486c2c66affSColin Finck 
487c2c66affSColin Finck     Result = GetSoundDeviceFromInstance(Instance, &SoundDevice);
488c2c66affSColin Finck 
489c2c66affSColin Finck     if ( ! MMSUCCESS(Result) )
490c2c66affSColin Finck     {
491c2c66affSColin Finck         return TranslateInternalMmResult(Result);
492c2c66affSColin Finck     }
493c2c66affSColin Finck 
494c2c66affSColin Finck     Result = GetSoundDeviceType(SoundDevice, &DeviceType);
495c2c66affSColin Finck     SND_ASSERT( Result == MMSYSERR_NOERROR );
496c2c66affSColin Finck 
497c2c66affSColin Finck     bWaveIn = (DeviceType == WAVE_IN_DEVICE_TYPE ? TRUE : FALSE);
498c2c66affSColin Finck 
499c2c66affSColin Finck     if (MMixerOpenWave(&MixerContext, DeviceId, bWaveIn, WaveFormat, NULL, NULL, &Instance->Handle) == MM_STATUS_SUCCESS)
500c2c66affSColin Finck     {
501c2c66affSColin Finck         if (DeviceType == WAVE_OUT_DEVICE_TYPE)
502c2c66affSColin Finck         {
503c2c66affSColin Finck             MMixerSetWaveStatus(&MixerContext, Instance->Handle, KSSTATE_ACQUIRE);
504c2c66affSColin Finck             MMixerSetWaveStatus(&MixerContext, Instance->Handle, KSSTATE_PAUSE);
505c2c66affSColin Finck             MMixerSetWaveStatus(&MixerContext, Instance->Handle, KSSTATE_RUN);
506c2c66affSColin Finck         }
507c2c66affSColin Finck         return MMSYSERR_NOERROR;
508c2c66affSColin Finck     }
509c2c66affSColin Finck     return MMSYSERR_ERROR;
510c2c66affSColin Finck }
511c2c66affSColin Finck 
512c2c66affSColin Finck 
513c2c66affSColin Finck MMRESULT
WdmAudGetCapabilitiesByMMixer(IN PSOUND_DEVICE SoundDevice,IN DWORD DeviceId,OUT PVOID Capabilities,IN DWORD CapabilitiesSize)514c2c66affSColin Finck WdmAudGetCapabilitiesByMMixer(
515c2c66affSColin Finck     IN  PSOUND_DEVICE SoundDevice,
516c2c66affSColin Finck     IN  DWORD DeviceId,
517c2c66affSColin Finck     OUT PVOID Capabilities,
518c2c66affSColin Finck     IN  DWORD CapabilitiesSize)
519c2c66affSColin Finck {
520c2c66affSColin Finck     MMDEVICE_TYPE DeviceType;
521c2c66affSColin Finck     MMRESULT Result;
522c2c66affSColin Finck 
523c2c66affSColin Finck     Result = GetSoundDeviceType(SoundDevice, &DeviceType);
524c2c66affSColin Finck     SND_ASSERT( Result == MMSYSERR_NOERROR );
525c2c66affSColin Finck 
526c2c66affSColin Finck     if (DeviceType == MIXER_DEVICE_TYPE)
527c2c66affSColin Finck     {
528c2c66affSColin Finck         return WdmAudGetMixerCapabilities(DeviceId, (LPMIXERCAPSW)Capabilities);
529c2c66affSColin Finck     }
530c2c66affSColin Finck     else if (DeviceType == WAVE_OUT_DEVICE_TYPE)
531c2c66affSColin Finck     {
532c2c66affSColin Finck         return WdmAudGetWaveOutCapabilities(DeviceId, (LPWAVEOUTCAPSW)Capabilities);
533c2c66affSColin Finck     }
534c2c66affSColin Finck     else if (DeviceType == WAVE_IN_DEVICE_TYPE)
535c2c66affSColin Finck     {
536c2c66affSColin Finck         return WdmAudGetWaveInCapabilities(DeviceId, (LPWAVEINCAPSW)Capabilities);
537c2c66affSColin Finck     }
538c2c66affSColin Finck     else
539c2c66affSColin Finck     {
540c2c66affSColin Finck         // not supported
541c2c66affSColin Finck         return MMSYSERR_ERROR;
542c2c66affSColin Finck     }
543c2c66affSColin Finck }
544c2c66affSColin Finck 
545c2c66affSColin Finck MMRESULT
WdmAudOpenSoundDeviceByMMixer(IN struct _SOUND_DEVICE * SoundDevice,OUT PVOID * Handle)546c2c66affSColin Finck WdmAudOpenSoundDeviceByMMixer(
547c2c66affSColin Finck     IN  struct _SOUND_DEVICE* SoundDevice,
548c2c66affSColin Finck     OUT PVOID* Handle)
549c2c66affSColin Finck {
550c2c66affSColin Finck     if (WdmAudInitUserModeMixer())
551c2c66affSColin Finck         return MMSYSERR_NOERROR;
552c2c66affSColin Finck     else
553c2c66affSColin Finck         return MMSYSERR_ERROR;
554c2c66affSColin Finck }
555c2c66affSColin Finck 
556c2c66affSColin Finck MMRESULT
WdmAudCloseSoundDeviceByMMixer(IN struct _SOUND_DEVICE_INSTANCE * SoundDeviceInstance,IN PVOID Handle)557c2c66affSColin Finck WdmAudCloseSoundDeviceByMMixer(
558c2c66affSColin Finck     IN  struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
559c2c66affSColin Finck     IN  PVOID Handle)
560c2c66affSColin Finck {
561c2c66affSColin Finck     MMDEVICE_TYPE DeviceType;
562c2c66affSColin Finck     PSOUND_DEVICE SoundDevice;
563c2c66affSColin Finck     MMRESULT Result;
564c2c66affSColin Finck 
565c2c66affSColin Finck     Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
566c2c66affSColin Finck 
567c2c66affSColin Finck     if ( ! MMSUCCESS(Result) )
568c2c66affSColin Finck     {
569c2c66affSColin Finck         return TranslateInternalMmResult(Result);
570c2c66affSColin Finck     }
571c2c66affSColin Finck 
572c2c66affSColin Finck     Result = GetSoundDeviceType(SoundDevice, &DeviceType);
573c2c66affSColin Finck     SND_ASSERT( Result == MMSYSERR_NOERROR );
574c2c66affSColin Finck 
575c2c66affSColin Finck     if (DeviceType == MIXER_DEVICE_TYPE)
576c2c66affSColin Finck     {
577c2c66affSColin Finck         /* no op */
578c2c66affSColin Finck         return MMSYSERR_NOERROR;
579c2c66affSColin Finck     }
580c2c66affSColin Finck     else if (DeviceType == WAVE_IN_DEVICE_TYPE || DeviceType == WAVE_OUT_DEVICE_TYPE)
581c2c66affSColin Finck     {
582c2c66affSColin Finck         /* make sure the pin is stopped */
583c2c66affSColin Finck         MMixerSetWaveStatus(&MixerContext, SoundDeviceInstance->Handle, KSSTATE_PAUSE);
584c2c66affSColin Finck         MMixerSetWaveStatus(&MixerContext, SoundDeviceInstance->Handle, KSSTATE_ACQUIRE);
585c2c66affSColin Finck         MMixerSetWaveStatus(&MixerContext, SoundDeviceInstance->Handle, KSSTATE_STOP);
586c2c66affSColin Finck 
587c2c66affSColin Finck         CloseHandle(Handle);
588c2c66affSColin Finck         return MMSYSERR_NOERROR;
589c2c66affSColin Finck     }
590c2c66affSColin Finck 
591c2c66affSColin Finck     /* midi is not supported */
592c2c66affSColin Finck     return MMSYSERR_ERROR;
593c2c66affSColin Finck }
594c2c66affSColin Finck 
595c2c66affSColin Finck MMRESULT
WdmAudGetNumWdmDevsByMMixer(IN MMDEVICE_TYPE DeviceType,OUT DWORD * DeviceCount)596c2c66affSColin Finck WdmAudGetNumWdmDevsByMMixer(
597c2c66affSColin Finck     IN  MMDEVICE_TYPE DeviceType,
598c2c66affSColin Finck     OUT DWORD* DeviceCount)
599c2c66affSColin Finck {
600c2c66affSColin Finck     switch(DeviceType)
601c2c66affSColin Finck     {
602c2c66affSColin Finck         case MIXER_DEVICE_TYPE:
603c2c66affSColin Finck             *DeviceCount = MMixerGetCount(&MixerContext);
604c2c66affSColin Finck             break;
605c2c66affSColin Finck         case WAVE_OUT_DEVICE_TYPE:
606c2c66affSColin Finck             *DeviceCount = MMixerGetWaveOutCount(&MixerContext);
607c2c66affSColin Finck             break;
608c2c66affSColin Finck         case WAVE_IN_DEVICE_TYPE:
609c2c66affSColin Finck             *DeviceCount = MMixerGetWaveInCount(&MixerContext);
610c2c66affSColin Finck             break;
611c2c66affSColin Finck         default:
612c2c66affSColin Finck             *DeviceCount = 0;
613c2c66affSColin Finck     }
614c2c66affSColin Finck     return MMSYSERR_NOERROR;
615c2c66affSColin Finck }
616c2c66affSColin Finck 
617c2c66affSColin Finck MMRESULT
WdmAudQueryMixerInfoByMMixer(IN struct _SOUND_DEVICE_INSTANCE * SoundDeviceInstance,IN DWORD MixerId,IN UINT uMsg,IN LPVOID Parameter,IN DWORD Flags)618c2c66affSColin Finck WdmAudQueryMixerInfoByMMixer(
619c2c66affSColin Finck     IN  struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
620c2c66affSColin Finck     IN DWORD MixerId,
621c2c66affSColin Finck     IN UINT uMsg,
622c2c66affSColin Finck     IN LPVOID Parameter,
623c2c66affSColin Finck     IN DWORD Flags)
624c2c66affSColin Finck {
625c2c66affSColin Finck     LPMIXERLINEW MixLine;
626c2c66affSColin Finck     LPMIXERLINECONTROLSW MixControls;
627c2c66affSColin Finck     LPMIXERCONTROLDETAILS MixDetails;
628c2c66affSColin Finck     HANDLE hMixer = NULL;
629c2c66affSColin Finck 
630c2c66affSColin Finck     MixLine = (LPMIXERLINEW)Parameter;
631c2c66affSColin Finck     MixControls = (LPMIXERLINECONTROLSW)Parameter;
632c2c66affSColin Finck     MixDetails = (LPMIXERCONTROLDETAILS)Parameter;
633c2c66affSColin Finck 
634c2c66affSColin Finck     /* FIXME param checks */
635c2c66affSColin Finck 
636c2c66affSColin Finck     if (SoundDeviceInstance)
637c2c66affSColin Finck     {
638c2c66affSColin Finck         hMixer = SoundDeviceInstance->Handle;
639c2c66affSColin Finck     }
640c2c66affSColin Finck 
641c2c66affSColin Finck     switch(uMsg)
642c2c66affSColin Finck     {
643c2c66affSColin Finck         case MXDM_GETLINEINFO:
644c2c66affSColin Finck             return WdmAudGetLineInfo(hMixer, MixerId, MixLine, Flags);
645c2c66affSColin Finck         case MXDM_GETLINECONTROLS:
646c2c66affSColin Finck             return WdmAudGetLineControls(hMixer, MixerId, MixControls, Flags);
647c2c66affSColin Finck        case MXDM_SETCONTROLDETAILS:
648c2c66affSColin Finck             return WdmAudSetControlDetails(hMixer, MixerId, MixDetails, Flags);
649c2c66affSColin Finck        case MXDM_GETCONTROLDETAILS:
650c2c66affSColin Finck             return WdmAudGetControlDetails(hMixer, MixerId, MixDetails, Flags);
651c2c66affSColin Finck        default:
652c2c66affSColin Finck            DPRINT1("MixerId %lu, uMsg %lu, Parameter %p, Flags %lu\n", MixerId, uMsg, Parameter, Flags);
653c2c66affSColin Finck            SND_ASSERT(0);
654c2c66affSColin Finck            return MMSYSERR_NOTSUPPORTED;
655c2c66affSColin Finck     }
656c2c66affSColin Finck }
657c2c66affSColin Finck 
658c2c66affSColin Finck MMRESULT
WdmAudGetDeviceInterfaceStringByMMixer(IN MMDEVICE_TYPE DeviceType,IN DWORD DeviceId,IN LPWSTR Interface,IN DWORD InterfaceLength,OUT DWORD * InterfaceSize)659c2c66affSColin Finck WdmAudGetDeviceInterfaceStringByMMixer(
660c2c66affSColin Finck     IN  MMDEVICE_TYPE DeviceType,
661c2c66affSColin Finck     IN  DWORD DeviceId,
662c2c66affSColin Finck     IN  LPWSTR Interface,
663c2c66affSColin Finck     IN  DWORD  InterfaceLength,
664c2c66affSColin Finck     OUT  DWORD * InterfaceSize)
665c2c66affSColin Finck {
666c2c66affSColin Finck     /* FIXME */
667c2c66affSColin Finck     return MMSYSERR_NOTSUPPORTED;
668c2c66affSColin Finck }
669c2c66affSColin Finck 
670c2c66affSColin Finck VOID
671c2c66affSColin Finck CALLBACK
MixerEventCallback(IN PVOID MixerEventContext,IN HANDLE hMixer,IN ULONG NotificationType,IN ULONG Value)672c2c66affSColin Finck MixerEventCallback(
673c2c66affSColin Finck     IN PVOID MixerEventContext,
674c2c66affSColin Finck     IN HANDLE hMixer,
675c2c66affSColin Finck     IN ULONG NotificationType,
676c2c66affSColin Finck     IN ULONG Value)
677c2c66affSColin Finck {
678c2c66affSColin Finck     PSOUND_DEVICE_INSTANCE Instance = (PSOUND_DEVICE_INSTANCE)MixerEventContext;
679c2c66affSColin Finck 
680c2c66affSColin Finck     DriverCallback(Instance->WinMM.ClientCallback,
681c2c66affSColin Finck                    HIWORD(Instance->WinMM.Flags),
682c2c66affSColin Finck                    Instance->WinMM.Handle,
683c2c66affSColin Finck                    NotificationType,
684c2c66affSColin Finck                    Instance->WinMM.ClientCallbackInstanceData,
685c2c66affSColin Finck                    (DWORD_PTR)Value,
686c2c66affSColin Finck                    0);
687c2c66affSColin Finck }
688c2c66affSColin Finck 
689c2c66affSColin Finck MMRESULT
WdmAudSetMixerDeviceFormatByMMixer(IN PSOUND_DEVICE_INSTANCE Instance,IN DWORD DeviceId,IN PWAVEFORMATEX WaveFormat,IN DWORD WaveFormatSize)690c2c66affSColin Finck WdmAudSetMixerDeviceFormatByMMixer(
691c2c66affSColin Finck     IN  PSOUND_DEVICE_INSTANCE Instance,
692c2c66affSColin Finck     IN  DWORD DeviceId,
693c2c66affSColin Finck     IN  PWAVEFORMATEX WaveFormat,
694c2c66affSColin Finck     IN  DWORD WaveFormatSize)
695c2c66affSColin Finck {
696c2c66affSColin Finck     if (MMixerOpen(&MixerContext, DeviceId, (PVOID)Instance, MixerEventCallback, &Instance->Handle) == MM_STATUS_SUCCESS)
697c2c66affSColin Finck         return MMSYSERR_NOERROR;
698c2c66affSColin Finck 
699c2c66affSColin Finck     return MMSYSERR_BADDEVICEID;
700c2c66affSColin Finck }
701c2c66affSColin Finck 
702c2c66affSColin Finck MMRESULT
WdmAudSetWaveStateByMMixer(IN struct _SOUND_DEVICE_INSTANCE * SoundDeviceInstance,IN BOOL bStart)703c2c66affSColin Finck WdmAudSetWaveStateByMMixer(
704c2c66affSColin Finck     IN  struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
705c2c66affSColin Finck     IN BOOL bStart)
706c2c66affSColin Finck {
707c2c66affSColin Finck     MMDEVICE_TYPE DeviceType;
708c2c66affSColin Finck     PSOUND_DEVICE SoundDevice;
709c2c66affSColin Finck     MMRESULT Result;
710c2c66affSColin Finck 
711c2c66affSColin Finck     Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
712c2c66affSColin Finck     SND_ASSERT( Result == MMSYSERR_NOERROR );
713c2c66affSColin Finck 
714c2c66affSColin Finck 
715c2c66affSColin Finck     Result = GetSoundDeviceType(SoundDevice, &DeviceType);
716c2c66affSColin Finck     SND_ASSERT( Result == MMSYSERR_NOERROR );
717c2c66affSColin Finck 
718c2c66affSColin Finck     if (DeviceType == WAVE_IN_DEVICE_TYPE || DeviceType == WAVE_OUT_DEVICE_TYPE)
719c2c66affSColin Finck     {
720c2c66affSColin Finck         if (bStart)
721c2c66affSColin Finck         {
722c2c66affSColin Finck             MMixerSetWaveStatus(&MixerContext, SoundDeviceInstance->Handle, KSSTATE_ACQUIRE);
723c2c66affSColin Finck             MMixerSetWaveStatus(&MixerContext, SoundDeviceInstance->Handle, KSSTATE_PAUSE);
724c2c66affSColin Finck             MMixerSetWaveStatus(&MixerContext, SoundDeviceInstance->Handle, KSSTATE_RUN);
725c2c66affSColin Finck         }
726c2c66affSColin Finck         else
727c2c66affSColin Finck         {
728c2c66affSColin Finck             MMixerSetWaveStatus(&MixerContext, SoundDeviceInstance->Handle, KSSTATE_PAUSE);
729c2c66affSColin Finck             MMixerSetWaveStatus(&MixerContext, SoundDeviceInstance->Handle, KSSTATE_ACQUIRE);
730c2c66affSColin Finck             MMixerSetWaveStatus(&MixerContext, SoundDeviceInstance->Handle, KSSTATE_STOP);
731c2c66affSColin Finck         }
732c2c66affSColin Finck     }
733c2c66affSColin Finck     else if (DeviceType == MIDI_IN_DEVICE_TYPE || DeviceType == MIDI_OUT_DEVICE_TYPE)
734c2c66affSColin Finck     {
735c2c66affSColin Finck         if (bStart)
736c2c66affSColin Finck         {
737c2c66affSColin Finck             MMixerSetMidiStatus(&MixerContext, SoundDeviceInstance->Handle, KSSTATE_ACQUIRE);
738c2c66affSColin Finck             MMixerSetMidiStatus(&MixerContext, SoundDeviceInstance->Handle, KSSTATE_PAUSE);
739c2c66affSColin Finck             MMixerSetMidiStatus(&MixerContext, SoundDeviceInstance->Handle, KSSTATE_RUN);
740c2c66affSColin Finck         }
741c2c66affSColin Finck         else
742c2c66affSColin Finck         {
743c2c66affSColin Finck             MMixerSetMidiStatus(&MixerContext, SoundDeviceInstance->Handle, KSSTATE_PAUSE);
744c2c66affSColin Finck             MMixerSetMidiStatus(&MixerContext, SoundDeviceInstance->Handle, KSSTATE_ACQUIRE);
745c2c66affSColin Finck             MMixerSetMidiStatus(&MixerContext, SoundDeviceInstance->Handle, KSSTATE_STOP);
746c2c66affSColin Finck         }
747c2c66affSColin Finck     }
748c2c66affSColin Finck 
749c2c66affSColin Finck     return MMSYSERR_NOERROR;
750c2c66affSColin Finck }
751c2c66affSColin Finck 
752c2c66affSColin Finck MMRESULT
WdmAudResetStreamByMMixer(IN struct _SOUND_DEVICE_INSTANCE * SoundDeviceInstance,IN MMDEVICE_TYPE DeviceType,IN BOOLEAN bStartReset)753c2c66affSColin Finck WdmAudResetStreamByMMixer(
754c2c66affSColin Finck     IN  struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
755c2c66affSColin Finck     IN  MMDEVICE_TYPE DeviceType,
756c2c66affSColin Finck     IN  BOOLEAN bStartReset)
757c2c66affSColin Finck {
758c2c66affSColin Finck     MIXER_STATUS Status;
759c2c66affSColin Finck 
760c2c66affSColin Finck     if (DeviceType == WAVE_IN_DEVICE_TYPE || DeviceType == WAVE_OUT_DEVICE_TYPE)
761c2c66affSColin Finck     {
762c2c66affSColin Finck         Status = MMixerSetWaveResetState(&MixerContext, SoundDeviceInstance->Handle, bStartReset);
763c2c66affSColin Finck         if (Status == MM_STATUS_SUCCESS)
764c2c66affSColin Finck         {
765c2c66affSColin Finck             /* completed successfully */
766c2c66affSColin Finck             return MMSYSERR_NOERROR;
767c2c66affSColin Finck         }
768c2c66affSColin Finck     }
769c2c66affSColin Finck 
770c2c66affSColin Finck 
771c2c66affSColin Finck     return MMSYSERR_NOTSUPPORTED;
772c2c66affSColin Finck }
773c2c66affSColin Finck 
774c2c66affSColin Finck MMRESULT
WdmAudGetWavePositionByMMixer(IN struct _SOUND_DEVICE_INSTANCE * SoundDeviceInstance,IN MMTIME * Time)775c2c66affSColin Finck WdmAudGetWavePositionByMMixer(
776c2c66affSColin Finck     IN  struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
777c2c66affSColin Finck     IN  MMTIME* Time)
778c2c66affSColin Finck {
779d1b8feb6SOleg Dubinskiy     PSOUND_DEVICE SoundDevice;
780d1b8feb6SOleg Dubinskiy     MMDEVICE_TYPE DeviceType;
781d1b8feb6SOleg Dubinskiy     MIXER_STATUS Status;
782d1b8feb6SOleg Dubinskiy     MMRESULT Result;
783d1b8feb6SOleg Dubinskiy     DWORD Position;
784d1b8feb6SOleg Dubinskiy 
785d1b8feb6SOleg Dubinskiy     Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
786d1b8feb6SOleg Dubinskiy     if (!MMSUCCESS(Result))
787d1b8feb6SOleg Dubinskiy         return TranslateInternalMmResult(Result);
788d1b8feb6SOleg Dubinskiy 
789d1b8feb6SOleg Dubinskiy     Result = GetSoundDeviceType(SoundDevice, &DeviceType);
790d1b8feb6SOleg Dubinskiy     SND_ASSERT(Result == MMSYSERR_NOERROR);
791d1b8feb6SOleg Dubinskiy 
792d1b8feb6SOleg Dubinskiy     if (DeviceType == WAVE_IN_DEVICE_TYPE || DeviceType == WAVE_OUT_DEVICE_TYPE)
793d1b8feb6SOleg Dubinskiy     {
794d1b8feb6SOleg Dubinskiy         Status = MMixerGetWavePosition(&MixerContext, SoundDeviceInstance->Handle, &Position);
795d1b8feb6SOleg Dubinskiy         if (Status == MM_STATUS_SUCCESS)
796d1b8feb6SOleg Dubinskiy         {
797d1b8feb6SOleg Dubinskiy             /* Store position */
798d1b8feb6SOleg Dubinskiy             Time->wType = TIME_BYTES;
799d1b8feb6SOleg Dubinskiy             Time->u.cb = Position;
800d1b8feb6SOleg Dubinskiy 
801d1b8feb6SOleg Dubinskiy             /* Completed successfully */
802d1b8feb6SOleg Dubinskiy             return MMSYSERR_NOERROR;
803d1b8feb6SOleg Dubinskiy         }
804d1b8feb6SOleg Dubinskiy     }
805c2c66affSColin Finck     return MMSYSERR_NOTSUPPORTED;
806c2c66affSColin Finck }
807c2c66affSColin Finck 
808*9046cc97SOleg Dubinskiy MMRESULT
WdmAudGetVolumeByMMixer(_In_ PSOUND_DEVICE_INSTANCE SoundDeviceInstance,_In_ DWORD DeviceId,_Out_ PDWORD pdwVolume)809*9046cc97SOleg Dubinskiy WdmAudGetVolumeByMMixer(
810*9046cc97SOleg Dubinskiy     _In_ PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
811*9046cc97SOleg Dubinskiy     _In_ DWORD DeviceId,
812*9046cc97SOleg Dubinskiy     _Out_ PDWORD pdwVolume)
813*9046cc97SOleg Dubinskiy {
814*9046cc97SOleg Dubinskiy     MMRESULT Result;
815*9046cc97SOleg Dubinskiy     MIXERLINE MixLine;
816*9046cc97SOleg Dubinskiy     MIXERCONTROL MixControl;
817*9046cc97SOleg Dubinskiy     MIXERLINECONTROLS MixLineControls;
818*9046cc97SOleg Dubinskiy     MIXERCONTROLDETAILS MixControlDetails;
819*9046cc97SOleg Dubinskiy     MIXERCONTROLDETAILS_UNSIGNED MixControlDetailsU[2]; // For 2 (stereo) channels
820*9046cc97SOleg Dubinskiy 
821*9046cc97SOleg Dubinskiy     MixLine.cbStruct = sizeof(MixLine);
822*9046cc97SOleg Dubinskiy     MixLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
823*9046cc97SOleg Dubinskiy 
824*9046cc97SOleg Dubinskiy     /* Get line info */
825*9046cc97SOleg Dubinskiy     Result = WdmAudGetLineInfo(SoundDeviceInstance->Handle,
826*9046cc97SOleg Dubinskiy                                DeviceId,
827*9046cc97SOleg Dubinskiy                                &MixLine,
828*9046cc97SOleg Dubinskiy                                MIXER_OBJECTF_MIXER | MIXER_GETLINEINFOF_COMPONENTTYPE);
829*9046cc97SOleg Dubinskiy     if (!MMSUCCESS(Result))
830*9046cc97SOleg Dubinskiy         return TranslateInternalMmResult(Result);
831*9046cc97SOleg Dubinskiy 
832*9046cc97SOleg Dubinskiy     MixLineControls.cbStruct = sizeof(MixLineControls);
833*9046cc97SOleg Dubinskiy     MixLineControls.dwLineID = MixLine.dwLineID;
834*9046cc97SOleg Dubinskiy     MixLineControls.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
835*9046cc97SOleg Dubinskiy     MixLineControls.cControls = 1;
836*9046cc97SOleg Dubinskiy     MixLineControls.cbmxctrl = sizeof(MixControl);
837*9046cc97SOleg Dubinskiy     MixLineControls.pamxctrl = &MixControl;
838*9046cc97SOleg Dubinskiy 
839*9046cc97SOleg Dubinskiy     /* Get line controls */
840*9046cc97SOleg Dubinskiy     Result = WdmAudGetLineControls(SoundDeviceInstance->Handle,
841*9046cc97SOleg Dubinskiy                                    DeviceId,
842*9046cc97SOleg Dubinskiy                                    &MixLineControls,
843*9046cc97SOleg Dubinskiy                                    MIXER_OBJECTF_MIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE);
844*9046cc97SOleg Dubinskiy     if (!MMSUCCESS(Result))
845*9046cc97SOleg Dubinskiy         return TranslateInternalMmResult(Result);
846*9046cc97SOleg Dubinskiy 
847*9046cc97SOleg Dubinskiy     MixControlDetails.cbStruct = sizeof(MixControlDetails);
848*9046cc97SOleg Dubinskiy     MixControlDetails.dwControlID = MixControl.dwControlID;
849*9046cc97SOleg Dubinskiy     MixControlDetails.cChannels = MixLine.cChannels;
850*9046cc97SOleg Dubinskiy     MixControlDetails.cMultipleItems = 0;
851*9046cc97SOleg Dubinskiy     MixControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
852*9046cc97SOleg Dubinskiy     MixControlDetails.paDetails = MixControlDetailsU;
853*9046cc97SOleg Dubinskiy 
854*9046cc97SOleg Dubinskiy     /* Get volume control details */
855*9046cc97SOleg Dubinskiy     Result = WdmAudGetControlDetails(SoundDeviceInstance->Handle,
856*9046cc97SOleg Dubinskiy                                      DeviceId,
857*9046cc97SOleg Dubinskiy                                      &MixControlDetails,
858*9046cc97SOleg Dubinskiy                                      MIXER_OBJECTF_MIXER);
859*9046cc97SOleg Dubinskiy     if (MMSUCCESS(Result))
860*9046cc97SOleg Dubinskiy         *pdwVolume = MAKELONG(LOWORD(MixControlDetailsU[0].dwValue), HIWORD(MixControlDetailsU[1].dwValue));
861*9046cc97SOleg Dubinskiy 
862*9046cc97SOleg Dubinskiy     return Result;
863*9046cc97SOleg Dubinskiy }
864*9046cc97SOleg Dubinskiy 
865*9046cc97SOleg Dubinskiy MMRESULT
WdmAudSetVolumeByMMixer(_In_ PSOUND_DEVICE_INSTANCE SoundDeviceInstance,_In_ DWORD DeviceId,_In_ DWORD dwVolume)866*9046cc97SOleg Dubinskiy WdmAudSetVolumeByMMixer(
867*9046cc97SOleg Dubinskiy     _In_ PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
868*9046cc97SOleg Dubinskiy     _In_ DWORD DeviceId,
869*9046cc97SOleg Dubinskiy     _In_ DWORD dwVolume)
870*9046cc97SOleg Dubinskiy {
871*9046cc97SOleg Dubinskiy     MMRESULT Result;
872*9046cc97SOleg Dubinskiy     MIXERLINE MixLine;
873*9046cc97SOleg Dubinskiy     MIXERCONTROL MixControl;
874*9046cc97SOleg Dubinskiy     MIXERLINECONTROLS MixLineControls;
875*9046cc97SOleg Dubinskiy     MIXERCONTROLDETAILS MixControlDetails;
876*9046cc97SOleg Dubinskiy     MIXERCONTROLDETAILS_UNSIGNED MixControlDetailsU[2]; // For 2 (stereo) channels
877*9046cc97SOleg Dubinskiy 
878*9046cc97SOleg Dubinskiy     MixLine.cbStruct = sizeof(MixLine);
879*9046cc97SOleg Dubinskiy     MixLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
880*9046cc97SOleg Dubinskiy 
881*9046cc97SOleg Dubinskiy     /* Get line info */
882*9046cc97SOleg Dubinskiy     Result = WdmAudGetLineInfo(SoundDeviceInstance->Handle,
883*9046cc97SOleg Dubinskiy                                DeviceId,
884*9046cc97SOleg Dubinskiy                                &MixLine,
885*9046cc97SOleg Dubinskiy                                MIXER_OBJECTF_MIXER | MIXER_GETLINEINFOF_COMPONENTTYPE);
886*9046cc97SOleg Dubinskiy     if (!MMSUCCESS(Result))
887*9046cc97SOleg Dubinskiy         return TranslateInternalMmResult(Result);
888*9046cc97SOleg Dubinskiy 
889*9046cc97SOleg Dubinskiy     MixLineControls.cbStruct = sizeof(MixLineControls);
890*9046cc97SOleg Dubinskiy     MixLineControls.dwLineID = MixLine.dwLineID;
891*9046cc97SOleg Dubinskiy     MixLineControls.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
892*9046cc97SOleg Dubinskiy     MixLineControls.cControls = 1;
893*9046cc97SOleg Dubinskiy     MixLineControls.cbmxctrl = sizeof(MixControl);
894*9046cc97SOleg Dubinskiy     MixLineControls.pamxctrl = &MixControl;
895*9046cc97SOleg Dubinskiy 
896*9046cc97SOleg Dubinskiy     /* Get line controls */
897*9046cc97SOleg Dubinskiy     Result = WdmAudGetLineControls(SoundDeviceInstance->Handle,
898*9046cc97SOleg Dubinskiy                                    DeviceId,
899*9046cc97SOleg Dubinskiy                                    &MixLineControls,
900*9046cc97SOleg Dubinskiy                                    MIXER_OBJECTF_MIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE);
901*9046cc97SOleg Dubinskiy     if (!MMSUCCESS(Result))
902*9046cc97SOleg Dubinskiy         return TranslateInternalMmResult(Result);
903*9046cc97SOleg Dubinskiy 
904*9046cc97SOleg Dubinskiy     /* Convert volume level to be set */
905*9046cc97SOleg Dubinskiy     MixControlDetailsU[0].dwValue = LOWORD(dwVolume); // Left channel
906*9046cc97SOleg Dubinskiy     MixControlDetailsU[1].dwValue = HIWORD(dwVolume); // Right channel
907*9046cc97SOleg Dubinskiy 
908*9046cc97SOleg Dubinskiy     MixControlDetails.cbStruct = sizeof(MixControlDetails);
909*9046cc97SOleg Dubinskiy     MixControlDetails.dwControlID = MixControl.dwControlID;
910*9046cc97SOleg Dubinskiy     MixControlDetails.cChannels = MixLine.cChannels;
911*9046cc97SOleg Dubinskiy     MixControlDetails.cMultipleItems = 0;
912*9046cc97SOleg Dubinskiy     MixControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
913*9046cc97SOleg Dubinskiy     MixControlDetails.paDetails = MixControlDetailsU;
914*9046cc97SOleg Dubinskiy 
915*9046cc97SOleg Dubinskiy     /* Set volume control details */
916*9046cc97SOleg Dubinskiy     Result = WdmAudSetControlDetails(SoundDeviceInstance->Handle,
917*9046cc97SOleg Dubinskiy                                      DeviceId,
918*9046cc97SOleg Dubinskiy                                      &MixControlDetails,
919*9046cc97SOleg Dubinskiy                                      MIXER_OBJECTF_MIXER);
920*9046cc97SOleg Dubinskiy     return Result;
921*9046cc97SOleg Dubinskiy }
922*9046cc97SOleg Dubinskiy 
923b8e936a5SMichael Stamper static
924b8e936a5SMichael Stamper VOID WINAPI
CommitWaveBufferApc(PVOID ApcContext,PIO_STATUS_BLOCK IoStatusBlock,ULONG Reserved)925b8e936a5SMichael Stamper CommitWaveBufferApc(PVOID ApcContext,
926b8e936a5SMichael Stamper            PIO_STATUS_BLOCK IoStatusBlock,
927b8e936a5SMichael Stamper            ULONG Reserved)
928c2c66affSColin Finck {
929b8e936a5SMichael Stamper     DWORD dwErrorCode;
930b8e936a5SMichael Stamper     PSOUND_OVERLAPPED Overlap;
931b8e936a5SMichael Stamper     KSSTREAM_HEADER* lpHeader;
932c2c66affSColin Finck 
933b8e936a5SMichael Stamper     dwErrorCode = RtlNtStatusToDosError(IoStatusBlock->Status);
934b8e936a5SMichael Stamper     Overlap = (PSOUND_OVERLAPPED)IoStatusBlock;
935b8e936a5SMichael Stamper     lpHeader = Overlap->CompletionContext;
936c2c66affSColin Finck 
937b8e936a5SMichael Stamper     /* Call mmebuddy overlap routine */
938b8e936a5SMichael Stamper     Overlap->OriginalCompletionRoutine(dwErrorCode,
939b8e936a5SMichael Stamper         lpHeader->DataUsed, &Overlap->Standard);
940c2c66affSColin Finck 
941b8e936a5SMichael Stamper     HeapFree(GetProcessHeap(), 0, lpHeader);
942c2c66affSColin Finck }
943c2c66affSColin Finck 
944c2c66affSColin Finck MMRESULT
WdmAudCommitWaveBufferByMMixer(IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,IN PVOID OffsetPtr,IN DWORD Length,IN PSOUND_OVERLAPPED Overlap,IN LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine)945c2c66affSColin Finck WdmAudCommitWaveBufferByMMixer(
946c2c66affSColin Finck     IN  PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
947c2c66affSColin Finck     IN  PVOID OffsetPtr,
948c2c66affSColin Finck     IN  DWORD Length,
949c2c66affSColin Finck     IN  PSOUND_OVERLAPPED Overlap,
950c2c66affSColin Finck     IN  LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine)
951c2c66affSColin Finck {
952c2c66affSColin Finck     PSOUND_DEVICE SoundDevice;
953c2c66affSColin Finck     MMDEVICE_TYPE DeviceType;
954c2c66affSColin Finck     MMRESULT Result;
955b8e936a5SMichael Stamper     ULONG IoCtl;
956b8e936a5SMichael Stamper     KSSTREAM_HEADER* lpHeader;
957b8e936a5SMichael Stamper     NTSTATUS Status;
958c2c66affSColin Finck 
959c2c66affSColin Finck     Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
960c2c66affSColin Finck 
961c2c66affSColin Finck     if ( ! MMSUCCESS(Result) )
962c2c66affSColin Finck     {
963c2c66affSColin Finck         return TranslateInternalMmResult(Result);
964c2c66affSColin Finck     }
965c2c66affSColin Finck 
966c2c66affSColin Finck     Result = GetSoundDeviceType(SoundDevice, &DeviceType);
967c2c66affSColin Finck     SND_ASSERT( Result == MMSYSERR_NOERROR );
968c2c66affSColin Finck 
969b8e936a5SMichael Stamper     lpHeader = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(KSSTREAM_HEADER));
970b8e936a5SMichael Stamper     if ( ! lpHeader )
971c2c66affSColin Finck     {
972c2c66affSColin Finck         /* no memory */
973c2c66affSColin Finck         return MMSYSERR_NOMEM;
974c2c66affSColin Finck     }
975c2c66affSColin Finck 
976c2c66affSColin Finck     /* setup stream packet */
977b8e936a5SMichael Stamper     lpHeader->Size = sizeof(KSSTREAM_HEADER);
978b8e936a5SMichael Stamper     lpHeader->PresentationTime.Numerator = 1;
979b8e936a5SMichael Stamper     lpHeader->PresentationTime.Denominator = 1;
980b8e936a5SMichael Stamper     lpHeader->Data = OffsetPtr;
981b8e936a5SMichael Stamper     lpHeader->FrameExtent = Length;
982b8e936a5SMichael Stamper     Overlap->CompletionContext = lpHeader;
983b8e936a5SMichael Stamper     Overlap->OriginalCompletionRoutine = CompletionRoutine;
984b8e936a5SMichael Stamper     IoCtl = (DeviceType == WAVE_OUT_DEVICE_TYPE ? IOCTL_KS_WRITE_STREAM : IOCTL_KS_READ_STREAM);
985c2c66affSColin Finck 
986c2c66affSColin Finck     if (DeviceType == WAVE_OUT_DEVICE_TYPE)
987c2c66affSColin Finck     {
988b8e936a5SMichael Stamper         lpHeader->DataUsed = Length;
989c2c66affSColin Finck     }
990c2c66affSColin Finck 
991b8e936a5SMichael Stamper     Status = NtDeviceIoControlFile(SoundDeviceInstance->Handle,
992b8e936a5SMichael Stamper                                    NULL,
993b8e936a5SMichael Stamper                                    CommitWaveBufferApc,
994b8e936a5SMichael Stamper                                    NULL,
995b8e936a5SMichael Stamper                                    (PIO_STATUS_BLOCK)Overlap,
996b8e936a5SMichael Stamper                                    IoCtl,
997b8e936a5SMichael Stamper                                    NULL,
998b8e936a5SMichael Stamper                                    0,
999b8e936a5SMichael Stamper                                    lpHeader,
1000b8e936a5SMichael Stamper                                    sizeof(KSSTREAM_HEADER));
1001b8e936a5SMichael Stamper 
1002b8e936a5SMichael Stamper     if (!NT_SUCCESS(Status))
1003c2c66affSColin Finck     {
1004b8e936a5SMichael Stamper         DPRINT1("NtDeviceIoControlFile() failed with status %08lx\n", Status);
1005c2c66affSColin Finck         return MMSYSERR_ERROR;
1006c2c66affSColin Finck     }
1007c2c66affSColin Finck 
1008c2c66affSColin Finck     return MMSYSERR_NOERROR;
1009c2c66affSColin Finck }
1010