2 * PROJECT: ReactOS Sound System
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/wdmaud.drv/mmixer.c
6 * PURPOSE: WDM Audio Mixer API (User-mode part)
7 * PROGRAMMERS: Johannes Anderwald
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
);
24 MIXER_CONTEXT MixerContext
=
26 sizeof(MIXER_CONTEXT
),
39 GUID CategoryGuid
= {STATIC_KSCATEGORY_AUDIO
};
45 OUT PVOID
* ResultBuffer
,
46 OUT PULONG ResultLength
,
49 if (RegQueryValueExW((HKEY
)hKey
, KeyName
, NULL
, KeyType
, NULL
, ResultLength
) == ERROR_FILE_NOT_FOUND
)
50 return MM_STATUS_UNSUCCESSFUL
;
52 *ResultBuffer
= HeapAlloc(GetProcessHeap(), 0, *ResultLength
);
53 if (*ResultBuffer
== NULL
)
54 return MM_STATUS_NO_MEMORY
;
56 if (RegQueryValueExW((HKEY
)hKey
, KeyName
, NULL
, KeyType
, *ResultBuffer
, ResultLength
) != ERROR_SUCCESS
)
58 HeapFree(GetProcessHeap(), 0, *ResultBuffer
);
59 return MM_STATUS_UNSUCCESSFUL
;
61 return MM_STATUS_SUCCESS
;
68 IN ULONG DesiredAccess
,
71 if (RegOpenKeyExW((HKEY
)hKey
, SubKey
, 0, DesiredAccess
, (PHKEY
)OutKey
) == ERROR_SUCCESS
)
72 return MM_STATUS_SUCCESS
;
74 return MM_STATUS_UNSUCCESSFUL
;
81 RegCloseKey((HKEY
)hKey
);
82 return MM_STATUS_SUCCESS
;
86 PVOID
Alloc(ULONG NumBytes
)
88 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, NumBytes
);
94 if (CloseHandle(hDevice
))
95 return MM_STATUS_SUCCESS
;
97 return MM_STATUS_UNSUCCESSFUL
;
103 HeapFree(GetProcessHeap(), 0, Block
);
107 Copy(PVOID Src
, PVOID Dst
, ULONG NumBytes
)
109 CopyMemory(Src
, Dst
, NumBytes
);
114 IN LPWSTR DevicePath
,
117 DevicePath
[1] = L
'\\';
118 *hDevice
= CreateFileW(DevicePath
,
119 GENERIC_READ
| GENERIC_WRITE
,
123 FILE_FLAG_OVERLAPPED
,
125 if (*hDevice
== INVALID_HANDLE_VALUE
)
127 return MM_STATUS_UNSUCCESSFUL
;
130 return MM_STATUS_SUCCESS
;
136 IN ULONG dwIoControlCode
,
138 IN ULONG nInBufferSize
,
139 OUT PVOID lpOutBuffer
,
140 ULONG nOutBufferSize
,
141 PULONG lpBytesReturned
)
143 OVERLAPPED Overlapped
;
145 DWORD Transferred
= 0;
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
);
151 if ( ! Overlapped
.hEvent
)
152 return MM_STATUS_NO_MEMORY
;
154 /* Talk to the device */
155 IoResult
= DeviceIoControl(hMixer
,
164 /* If failure occurs, make sure it's not just due to the overlapped I/O */
167 if ( GetLastError() != ERROR_IO_PENDING
)
169 CloseHandle(Overlapped
.hEvent
);
171 if (GetLastError() == ERROR_MORE_DATA
|| GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
173 if ( lpBytesReturned
)
174 *lpBytesReturned
= Transferred
;
175 return MM_STATUS_MORE_ENTRIES
;
178 return MM_STATUS_UNSUCCESSFUL
;
182 /* Wait for the I/O to complete */
183 IoResult
= GetOverlappedResult(hMixer
,
188 /* Don't need this any more */
189 CloseHandle(Overlapped
.hEvent
);
192 return MM_STATUS_UNSUCCESSFUL
;
194 if ( lpBytesReturned
)
195 *lpBytesReturned
= Transferred
;
197 return MM_STATUS_SUCCESS
;
202 IN PVOID EnumContext
,
203 IN ULONG DeviceIndex
,
204 OUT LPWSTR
* DeviceName
,
205 OUT PHANDLE OutHandle
,
208 SP_DEVICE_INTERFACE_DATA InterfaceData
;
209 SP_DEVINFO_DATA DeviceData
;
210 PSP_DEVICE_INTERFACE_DETAIL_DATA_W DetailData
;
215 //printf("Enum EnumContext %p DeviceIndex %lu OutHandle %p\n", EnumContext, DeviceIndex, OutHandle);
217 InterfaceData
.cbSize
= sizeof(InterfaceData
);
218 InterfaceData
.Reserved
= 0;
220 Result
= SetupDiEnumDeviceInterfaces(EnumContext
,
228 if (GetLastError() == ERROR_NO_MORE_ITEMS
)
230 return MM_STATUS_NO_MORE_DEVICES
;
232 return MM_STATUS_UNSUCCESSFUL
;
235 Length
= sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W
) + MAX_PATH
* sizeof(WCHAR
);
236 DetailData
= (PSP_DEVICE_INTERFACE_DETAIL_DATA_W
)HeapAlloc(GetProcessHeap(),
239 DetailData
->cbSize
= sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W
);
240 DeviceData
.cbSize
= sizeof(DeviceData
);
241 DeviceData
.Reserved
= 0;
243 Result
= SetupDiGetDeviceInterfaceDetailW(EnumContext
,
252 DPRINT("SetupDiGetDeviceInterfaceDetailW failed with %lu\n", GetLastError());
253 return MM_STATUS_UNSUCCESSFUL
;
257 *OutKey
= SetupDiOpenDeviceInterfaceRegKey(EnumContext
, &InterfaceData
, 0, KEY_READ
);
258 if ((HKEY
)*OutKey
== INVALID_HANDLE_VALUE
)
260 HeapFree(GetProcessHeap(), 0, DetailData
);
261 return MM_STATUS_UNSUCCESSFUL
;
264 Status
= Open(DetailData
->DevicePath
, OutHandle
);
266 if (Status
!= MM_STATUS_SUCCESS
)
268 RegCloseKey((HKEY
)*OutKey
);
269 HeapFree(GetProcessHeap(), 0, DetailData
);
273 *DeviceName
= (LPWSTR
)HeapAlloc(GetProcessHeap(), 0, (wcslen(DetailData
->DevicePath
)+1) * sizeof(WCHAR
));
274 if (*DeviceName
== NULL
)
276 CloseHandle(*OutHandle
);
277 RegCloseKey((HKEY
)*OutKey
);
278 HeapFree(GetProcessHeap(), 0, DetailData
);
279 return MM_STATUS_NO_MEMORY
;
282 wcscpy(*DeviceName
, DetailData
->DevicePath
);
283 HeapFree(GetProcessHeap(), 0, DetailData
);
289 WdmAudInitUserModeMixer()
291 HDEVINFO DeviceHandle
;
294 /* create a device list */
295 DeviceHandle
= SetupDiGetClassDevs(&CategoryGuid
,
298 DIGCF_DEVICEINTERFACE
|DIGCF_PRESENT
);
300 if (DeviceHandle
== INVALID_HANDLE_VALUE
)
302 /* failed to create a device list */
307 /* initialize the mixer library */
308 Status
= MMixerInitialize(&MixerContext
, Enum
, (PVOID
)DeviceHandle
);
310 /* free device list */
311 SetupDiDestroyDeviceInfoList(DeviceHandle
);
313 if (Status
!= MM_STATUS_SUCCESS
)
315 /* failed to initialize mixer library */
316 DPRINT1("Failed to initialize mixer library with %x\n", Status
);
320 /* completed successfully */
325 WdmAudGetMixerCount()
327 /* return number of mixers available */
328 return MMixerGetCount(&MixerContext
);
332 WdmAudGetMixerCapabilties(
334 LPMIXERCAPSW Capabilities
)
336 if (MMixerGetCapabilities(&MixerContext
, DeviceId
, Capabilities
) == MM_STATUS_SUCCESS
)
337 return MMSYSERR_NOERROR
;
339 return MMSYSERR_BADDEVICEID
;
345 IN HANDLE hNotifyEvent
)
348 return MMSYSERR_NOERROR
;
355 IN HANDLE hNotifyEvent
)
357 if (MMixerOpen(&MixerContext
, DeviceId
, hNotifyEvent
, NULL
/* FIXME */, hMixer
) == MM_STATUS_SUCCESS
)
358 return MMSYSERR_NOERROR
;
360 return MMSYSERR_BADDEVICEID
;
366 IN LPMIXERLINE MixLine
,
369 if (MMixerGetLineInfo(&MixerContext
, hMixer
, Flags
, MixLine
) == MM_STATUS_SUCCESS
)
370 return MMSYSERR_NOERROR
;
372 return MMSYSERR_ERROR
;
376 WdmAudGetLineControls(
378 IN LPMIXERLINECONTROLSW MixControls
,
381 if (MMixerGetLineControls(&MixerContext
, hMixer
, Flags
, MixControls
) == MM_STATUS_SUCCESS
)
382 return MMSYSERR_NOERROR
;
384 return MMSYSERR_ERROR
;
388 WdmAudSetControlDetails(
390 IN LPMIXERCONTROLDETAILS MixDetails
,
393 if (MMixerSetControlDetails(&MixerContext
, hMixer
, Flags
, MixDetails
) == MM_STATUS_SUCCESS
)
394 return MMSYSERR_NOERROR
;
396 return MMSYSERR_ERROR
;
401 WdmAudGetControlDetails(
403 IN LPMIXERCONTROLDETAILS MixDetails
,
406 if (MMixerGetControlDetails(&MixerContext
, hMixer
, Flags
, MixDetails
) == MM_STATUS_SUCCESS
)
407 return MMSYSERR_NOERROR
;
409 return MMSYSERR_ERROR
;