xref: /reactos/dll/win32/wdmaud.drv/mmixer.c (revision 9046cc97)
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