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