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