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