xref: /reactos/dll/win32/wdmaud.drv/mmixer.c (revision cadfdc55)
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
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
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
97 CloseKey(
98     IN HANDLE hKey)
99 {
100     RegCloseKey((HKEY)hKey);
101     return MM_STATUS_SUCCESS;
102 }
103 
104 
105 PVOID Alloc(ULONG NumBytes)
106 {
107     return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, NumBytes);
108 }
109 
110 MIXER_STATUS
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
120 Free(PVOID Block)
121 {
122     HeapFree(GetProcessHeap(), 0, Block);
123 }
124 
125 VOID
126 Copy(PVOID Src, PVOID Dst, ULONG NumBytes)
127 {
128     RtlMoveMemory(Src, Dst, NumBytes);
129 }
130 
131 MIXER_STATUS
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
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
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
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
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
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
382 WdmAudCleanupByMMixer()
383 {
384     /* TODO */
385     return MMSYSERR_NOERROR;
386 }
387 
388 MMRESULT
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 static
809 VOID WINAPI
810 CommitWaveBufferApc(PVOID ApcContext,
811            PIO_STATUS_BLOCK IoStatusBlock,
812            ULONG Reserved)
813 {
814     DWORD dwErrorCode;
815     PSOUND_OVERLAPPED Overlap;
816     KSSTREAM_HEADER* lpHeader;
817 
818     dwErrorCode = RtlNtStatusToDosError(IoStatusBlock->Status);
819     Overlap = (PSOUND_OVERLAPPED)IoStatusBlock;
820     lpHeader = Overlap->CompletionContext;
821 
822     /* Call mmebuddy overlap routine */
823     Overlap->OriginalCompletionRoutine(dwErrorCode,
824         lpHeader->DataUsed, &Overlap->Standard);
825 
826     HeapFree(GetProcessHeap(), 0, lpHeader);
827 }
828 
829 MMRESULT
830 WdmAudCommitWaveBufferByMMixer(
831     IN  PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
832     IN  PVOID OffsetPtr,
833     IN  DWORD Length,
834     IN  PSOUND_OVERLAPPED Overlap,
835     IN  LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine)
836 {
837     PSOUND_DEVICE SoundDevice;
838     MMDEVICE_TYPE DeviceType;
839     MMRESULT Result;
840     ULONG IoCtl;
841     KSSTREAM_HEADER* lpHeader;
842     NTSTATUS Status;
843 
844     Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
845 
846     if ( ! MMSUCCESS(Result) )
847     {
848         return TranslateInternalMmResult(Result);
849     }
850 
851     Result = GetSoundDeviceType(SoundDevice, &DeviceType);
852     SND_ASSERT( Result == MMSYSERR_NOERROR );
853 
854     lpHeader = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(KSSTREAM_HEADER));
855     if ( ! lpHeader )
856     {
857         /* no memory */
858         return MMSYSERR_NOMEM;
859     }
860 
861     /* setup stream packet */
862     lpHeader->Size = sizeof(KSSTREAM_HEADER);
863     lpHeader->PresentationTime.Numerator = 1;
864     lpHeader->PresentationTime.Denominator = 1;
865     lpHeader->Data = OffsetPtr;
866     lpHeader->FrameExtent = Length;
867     Overlap->CompletionContext = lpHeader;
868     Overlap->OriginalCompletionRoutine = CompletionRoutine;
869     IoCtl = (DeviceType == WAVE_OUT_DEVICE_TYPE ? IOCTL_KS_WRITE_STREAM : IOCTL_KS_READ_STREAM);
870 
871     if (DeviceType == WAVE_OUT_DEVICE_TYPE)
872     {
873         lpHeader->DataUsed = Length;
874     }
875 
876     Status = NtDeviceIoControlFile(SoundDeviceInstance->Handle,
877                                    NULL,
878                                    CommitWaveBufferApc,
879                                    NULL,
880                                    (PIO_STATUS_BLOCK)Overlap,
881                                    IoCtl,
882                                    NULL,
883                                    0,
884                                    lpHeader,
885                                    sizeof(KSSTREAM_HEADER));
886 
887     if (!NT_SUCCESS(Status))
888     {
889         DPRINT1("NtDeviceIoControlFile() failed with status %08lx\n", Status);
890         return MMSYSERR_ERROR;
891     }
892 
893     return MMSYSERR_NOERROR;
894 }
895