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