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