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