Sync to trunk (r44371)
[reactos.git] / reactos / dll / win32 / wdmaud.drv / wdmaud.c
1 /*
2 * PROJECT: ReactOS Sound System
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/wdmaud.drv/wdmaud.c
5 *
6 * PURPOSE: WDM Audio Driver (User-mode part)
7 * PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
8 *
9 * NOTES: Looking for wodMessage & co? You won't find them here. Try
10 * the MME Buddy library, which is where these routines are
11 * actually implemented.
12 *
13 */
14
15 #include <windows.h>
16 #include <ntddsnd.h>
17 #include <sndtypes.h>
18 #include <mmddk.h>
19 #include <mmebuddy.h>
20
21 #include <ks.h>
22 #include <ksmedia.h>
23 #include "interface.h"
24
25 #define KERNEL_DEVICE_NAME L"\\\\.\\wdmaud"
26
27 PWSTR UnknownWaveIn = L"Wave Input";
28 PWSTR UnknownWaveOut = L"Wave Output";
29 PWSTR UnknownMidiIn = L"Midi Input";
30 PWSTR UnknownMidiOut = L"Midi Output";
31
32 HANDLE KernelHandle = INVALID_HANDLE_VALUE;
33 DWORD OpenCount = 0;
34
35 MMRESULT
36 WriteFileEx_Remixer(
37 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
38 IN PVOID OffsetPtr,
39 IN DWORD Length,
40 IN PSOUND_OVERLAPPED Overlap,
41 IN LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine);
42
43
44
45 MMRESULT
46 GetNumWdmDevs(
47 IN HANDLE Handle,
48 IN MMDEVICE_TYPE DeviceType,
49 OUT DWORD* DeviceCount)
50 {
51 MMRESULT Result;
52 WDMAUD_DEVICE_INFO DeviceInfo;
53
54 VALIDATE_MMSYS_PARAMETER( Handle != INVALID_HANDLE_VALUE );
55 VALIDATE_MMSYS_PARAMETER( IS_VALID_SOUND_DEVICE_TYPE(DeviceType) );
56 VALIDATE_MMSYS_PARAMETER( DeviceCount );
57
58 ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
59 DeviceInfo.DeviceType = DeviceType;
60
61 Result = SyncOverlappedDeviceIoControl(Handle,
62 IOCTL_GETNUMDEVS_TYPE,
63 (LPVOID) &DeviceInfo,
64 sizeof(WDMAUD_DEVICE_INFO),
65 (LPVOID) &DeviceInfo,
66 sizeof(WDMAUD_DEVICE_INFO),
67 NULL);
68
69 if ( ! MMSUCCESS( Result ) )
70 {
71 SND_ERR(L"Call to IOCTL_GETNUMDEVS_TYPE failed\n");
72 *DeviceCount = 0;
73 return TranslateInternalMmResult(Result);
74 }
75
76 *DeviceCount = DeviceInfo.DeviceCount;
77
78 return MMSYSERR_NOERROR;
79 }
80
81 MMRESULT
82 GetWdmDeviceCapabilities(
83 IN PSOUND_DEVICE SoundDevice,
84 IN DWORD DeviceId,
85 OUT PVOID Capabilities,
86 IN DWORD CapabilitiesSize)
87 {
88 /* NOTE - At this time, WDMAUD does not support this properly */
89
90 MMRESULT Result;
91 MMDEVICE_TYPE DeviceType;
92 WDMAUD_DEVICE_INFO DeviceInfo;
93
94 SND_ASSERT( SoundDevice );
95 SND_ASSERT( Capabilities );
96
97 Result = GetSoundDeviceType(SoundDevice, &DeviceType);
98 SND_ASSERT( Result == MMSYSERR_NOERROR );
99
100 if ( ! MMSUCCESS(Result) )
101 return Result;
102
103 SND_TRACE(L"WDMAUD - GetWdmDeviceCapabilities DeviceType %u DeviceId %u\n", DeviceType, DeviceId);
104
105 ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
106 DeviceInfo.DeviceType = DeviceType;
107 DeviceInfo.DeviceIndex = DeviceId;
108
109 Result = SyncOverlappedDeviceIoControl(KernelHandle,
110 IOCTL_GETCAPABILITIES,
111 (LPVOID) &DeviceInfo,
112 sizeof(WDMAUD_DEVICE_INFO),
113 (LPVOID) &DeviceInfo,
114 sizeof(WDMAUD_DEVICE_INFO),
115 NULL);
116
117 if ( ! MMSUCCESS(Result) )
118 {
119 return TranslateInternalMmResult(Result);
120 }
121
122 /* This is pretty much a big hack right now */
123 switch ( DeviceType )
124 {
125 case MIXER_DEVICE_TYPE:
126 {
127 LPMIXERCAPS MixerCaps = (LPMIXERCAPS) Capabilities;
128
129 DeviceInfo.u.MixCaps.szPname[MAXPNAMELEN-1] = L'\0';
130 CopyWideString(MixerCaps->szPname, DeviceInfo.u.MixCaps.szPname);
131
132 MixerCaps->cDestinations = DeviceInfo.u.MixCaps.cDestinations;
133 MixerCaps->fdwSupport = DeviceInfo.u.MixCaps.fdwSupport;
134 MixerCaps->vDriverVersion = DeviceInfo.u.MixCaps.vDriverVersion;
135 MixerCaps->wMid = DeviceInfo.u.MixCaps.wMid;
136 MixerCaps->wPid = DeviceInfo.u.MixCaps.wPid;
137 break;
138 }
139 case WAVE_OUT_DEVICE_TYPE :
140 {
141 LPWAVEOUTCAPS WaveOutCaps = (LPWAVEOUTCAPS) Capabilities;
142
143 DeviceInfo.u.WaveOutCaps.szPname[MAXPNAMELEN-1] = L'\0';
144 WaveOutCaps->wMid = DeviceInfo.u.WaveOutCaps.wMid;
145 WaveOutCaps->wPid = DeviceInfo.u.WaveOutCaps.wPid;
146
147 WaveOutCaps->vDriverVersion = 0x0001;
148 CopyWideString(WaveOutCaps->szPname, DeviceInfo.u.WaveOutCaps.szPname);
149
150 WaveOutCaps->dwFormats = DeviceInfo.u.WaveOutCaps.dwFormats;
151 WaveOutCaps->wChannels = DeviceInfo.u.WaveOutCaps.wChannels;
152 WaveOutCaps->dwSupport = DeviceInfo.u.WaveOutCaps.dwSupport;
153 break;
154 }
155 case WAVE_IN_DEVICE_TYPE :
156 {
157 LPWAVEINCAPSW WaveInCaps = (LPWAVEINCAPSW) Capabilities;
158
159 DeviceInfo.u.WaveInCaps.szPname[MAXPNAMELEN-1] = L'\0';
160
161 WaveInCaps->wMid = DeviceInfo.u.WaveInCaps.wMid;
162 WaveInCaps->wPid = DeviceInfo.u.WaveInCaps.wPid;
163
164 WaveInCaps->vDriverVersion = 0x0001;
165 CopyWideString(WaveInCaps->szPname, DeviceInfo.u.WaveInCaps.szPname);
166
167 WaveInCaps->dwFormats = DeviceInfo.u.WaveInCaps.dwFormats;
168 WaveInCaps->wChannels = DeviceInfo.u.WaveInCaps.wChannels;
169 WaveInCaps->wReserved1 = 0;
170 break;
171 }
172 }
173
174 return MMSYSERR_NOERROR;
175 }
176
177
178 MMRESULT
179 OpenWdmSoundDevice(
180 IN struct _SOUND_DEVICE* SoundDevice, /* NOT USED */
181 OUT PVOID* Handle)
182 {
183 /* Only open this if it's not already open */
184 if ( KernelHandle == INVALID_HANDLE_VALUE )
185 {
186 SND_TRACE(L"Opening wdmaud device\n");
187 KernelHandle = CreateFileW(KERNEL_DEVICE_NAME,
188 GENERIC_READ | GENERIC_WRITE,
189 0,
190 NULL,
191 OPEN_EXISTING,
192 FILE_FLAG_OVERLAPPED,
193 NULL);
194 }
195
196 if ( KernelHandle == INVALID_HANDLE_VALUE )
197 return MMSYSERR_ERROR;
198
199 SND_ASSERT( Handle );
200
201 *Handle = KernelHandle;
202 ++ OpenCount;
203
204 return MMSYSERR_NOERROR;
205 }
206
207 MMRESULT
208 CloseWdmSoundDevice(
209 IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
210 IN PVOID Handle)
211 {
212 WDMAUD_DEVICE_INFO DeviceInfo;
213 MMRESULT Result;
214 MMDEVICE_TYPE DeviceType;
215 PSOUND_DEVICE SoundDevice;
216
217 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
218
219 if ( ! MMSUCCESS(Result) )
220 {
221 return TranslateInternalMmResult(Result);
222 }
223
224 if ( OpenCount == 0 )
225 {
226 return MMSYSERR_NOERROR;
227 }
228
229 SND_ASSERT( KernelHandle != INVALID_HANDLE_VALUE );
230
231 Result = GetSoundDeviceType(SoundDevice, &DeviceType);
232 SND_ASSERT( Result == MMSYSERR_NOERROR );
233
234 if (SoundDeviceInstance->Handle != (PVOID)KernelHandle)
235 {
236 ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
237
238 DeviceInfo.DeviceType = DeviceType;
239 DeviceInfo.hDevice = SoundDeviceInstance->Handle;
240
241 /* First stop the stream */
242 if (DeviceType != MIXER_DEVICE_TYPE)
243 {
244 DeviceInfo.u.State = KSSTATE_STOP;
245 SyncOverlappedDeviceIoControl(KernelHandle,
246 IOCTL_SETDEVICE_STATE,
247 (LPVOID) &DeviceInfo,
248 sizeof(WDMAUD_DEVICE_INFO),
249 (LPVOID) &DeviceInfo,
250 sizeof(WDMAUD_DEVICE_INFO),
251 NULL);
252 }
253
254 SyncOverlappedDeviceIoControl(KernelHandle,
255 IOCTL_CLOSE_WDMAUD,
256 (LPVOID) &DeviceInfo,
257 sizeof(WDMAUD_DEVICE_INFO),
258 (LPVOID) &DeviceInfo,
259 sizeof(WDMAUD_DEVICE_INFO),
260 NULL);
261 }
262
263 if (DeviceType == MIXER_DEVICE_TYPE)
264 {
265 SetEvent(SoundDeviceInstance->hStopEvent);
266 CloseHandle(SoundDeviceInstance->hStopEvent);
267 CloseHandle(SoundDeviceInstance->hNotifyEvent);
268 }
269
270 --OpenCount;
271
272 if ( OpenCount < 1 )
273 {
274 CloseHandle(KernelHandle);
275 KernelHandle = INVALID_HANDLE_VALUE;
276 }
277
278 return MMSYSERR_NOERROR;
279 }
280
281
282 MMRESULT
283 QueryWdmWaveDeviceFormatSupport(
284 IN PSOUND_DEVICE Device,
285 IN PWAVEFORMATEX WaveFormat,
286 IN DWORD WaveFormatSize)
287 {
288 /* Whatever... */
289 return MMSYSERR_NOERROR;
290 }
291
292
293 DWORD
294 WINAPI
295 MixerEventThreadRoutine(
296 LPVOID Parameter)
297 {
298 HANDLE WaitObjects[2];
299 DWORD dwResult;
300 MMRESULT Result;
301 WDMAUD_DEVICE_INFO DeviceInfo;
302 PSOUND_DEVICE_INSTANCE Instance = (PSOUND_DEVICE_INSTANCE)Parameter;
303
304 /* setup wait objects */
305 WaitObjects[0] = Instance->hNotifyEvent;
306 WaitObjects[1] = Instance->hStopEvent;
307
308 /* zero device info */
309 ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
310
311 DeviceInfo.hDevice = Instance->Handle;
312 DeviceInfo.DeviceType = MIXER_DEVICE_TYPE;
313
314 do
315 {
316 dwResult = WaitForMultipleObjects(2, WaitObjects, FALSE, INFINITE);
317
318 if (dwResult == WAIT_OBJECT_0 + 1)
319 {
320 /* stop event was signalled */
321 break;
322 }
323
324 do
325 {
326 Result = SyncOverlappedDeviceIoControl(KernelHandle,
327 IOCTL_GET_MIXER_EVENT,
328 (LPVOID) &DeviceInfo,
329 sizeof(WDMAUD_DEVICE_INFO),
330 (LPVOID) &DeviceInfo,
331 sizeof(WDMAUD_DEVICE_INFO),
332 NULL);
333
334 if (Result == MMSYSERR_NOERROR)
335 {
336 DriverCallback(Instance->WinMM.ClientCallback,
337 HIWORD(Instance->WinMM.Flags),
338 Instance->WinMM.Handle,
339 DeviceInfo.u.MixerEvent.NotificationType,
340 Instance->WinMM.ClientCallbackInstanceData,
341 (DWORD_PTR)DeviceInfo.u.MixerEvent.Value,
342 0);
343 }
344 }while(Result == MMSYSERR_NOERROR);
345 }while(TRUE);
346
347 /* done */
348 return 0;
349 }
350
351
352 MMRESULT
353 SetWdmMixerDeviceFormat(
354 IN PSOUND_DEVICE_INSTANCE Instance,
355 IN DWORD DeviceId,
356 IN PWAVEFORMATEX WaveFormat,
357 IN DWORD WaveFormatSize)
358 {
359 MMRESULT Result;
360 WDMAUD_DEVICE_INFO DeviceInfo;
361 HANDLE hThread;
362
363 if (Instance->Handle != KernelHandle)
364 {
365 /* device is already open */
366 return MMSYSERR_NOERROR;
367 }
368
369 Instance->hNotifyEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
370 if ( ! Instance->hNotifyEvent )
371 return MMSYSERR_NOMEM;
372
373 Instance->hStopEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
374 if ( ! Instance->hStopEvent )
375 return MMSYSERR_NOMEM;
376
377 ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
378 DeviceInfo.DeviceType = MIXER_DEVICE_TYPE;
379 DeviceInfo.DeviceIndex = DeviceId;
380 DeviceInfo.u.hNotifyEvent = Instance->hNotifyEvent;
381
382 Result = SyncOverlappedDeviceIoControl(KernelHandle,
383 IOCTL_OPEN_WDMAUD,
384 (LPVOID) &DeviceInfo,
385 sizeof(WDMAUD_DEVICE_INFO),
386 (LPVOID) &DeviceInfo,
387 sizeof(WDMAUD_DEVICE_INFO),
388 NULL);
389
390 if ( ! MMSUCCESS(Result) )
391 {
392 CloseHandle(Instance->hNotifyEvent);
393 CloseHandle(Instance->hStopEvent);
394 return TranslateInternalMmResult(Result);
395 }
396
397 hThread = CreateThread(NULL, 0, MixerEventThreadRoutine, (LPVOID)Instance, 0, NULL);
398 if ( hThread )
399 {
400 CloseHandle(hThread);
401 }
402
403 /* Store sound device handle instance handle */
404 Instance->Handle = (PVOID)DeviceInfo.hDevice;
405
406 return MMSYSERR_NOERROR;
407 }
408
409 MMRESULT
410 SetWdmWaveDeviceFormat(
411 IN PSOUND_DEVICE_INSTANCE Instance,
412 IN DWORD DeviceId,
413 IN PWAVEFORMATEX WaveFormat,
414 IN DWORD WaveFormatSize)
415 {
416 MMRESULT Result;
417 PSOUND_DEVICE SoundDevice;
418 PVOID Identifier;
419 WDMAUD_DEVICE_INFO DeviceInfo;
420 MMDEVICE_TYPE DeviceType;
421
422 Result = GetSoundDeviceFromInstance(Instance, &SoundDevice);
423
424 if ( ! MMSUCCESS(Result) )
425 {
426 return TranslateInternalMmResult(Result);
427 }
428
429 Result = GetSoundDeviceIdentifier(SoundDevice, &Identifier);
430
431 if ( ! MMSUCCESS(Result) )
432 {
433 return TranslateInternalMmResult(Result);
434 }
435
436 if (Instance->Handle != KernelHandle)
437 {
438 /* device is already open */
439 return MMSYSERR_NOERROR;
440 }
441
442
443 Result = GetSoundDeviceType(SoundDevice, &DeviceType);
444 SND_ASSERT( Result == MMSYSERR_NOERROR );
445
446 ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
447 DeviceInfo.DeviceType = DeviceType;
448 DeviceInfo.DeviceIndex = DeviceId;
449 DeviceInfo.u.WaveFormatEx.cbSize = sizeof(WAVEFORMATEX); //WaveFormat->cbSize;
450 DeviceInfo.u.WaveFormatEx.wFormatTag = WaveFormat->wFormatTag;
451 #ifdef USERMODE_MIXER
452 DeviceInfo.u.WaveFormatEx.nChannels = 2;
453 DeviceInfo.u.WaveFormatEx.nSamplesPerSec = 44100;
454 DeviceInfo.u.WaveFormatEx.nBlockAlign = 4;
455 DeviceInfo.u.WaveFormatEx.nAvgBytesPerSec = 176400;
456 DeviceInfo.u.WaveFormatEx.wBitsPerSample = 16;
457 #else
458 DeviceInfo.u.WaveFormatEx.nChannels = WaveFormat->nChannels;
459 DeviceInfo.u.WaveFormatEx.nSamplesPerSec = WaveFormat->nSamplesPerSec;
460 DeviceInfo.u.WaveFormatEx.nBlockAlign = WaveFormat->nBlockAlign;
461 DeviceInfo.u.WaveFormatEx.nAvgBytesPerSec = WaveFormat->nAvgBytesPerSec;
462 DeviceInfo.u.WaveFormatEx.wBitsPerSample = WaveFormat->wBitsPerSample;
463 #endif
464
465 Result = SyncOverlappedDeviceIoControl(KernelHandle,
466 IOCTL_OPEN_WDMAUD,
467 (LPVOID) &DeviceInfo,
468 sizeof(WDMAUD_DEVICE_INFO),
469 (LPVOID) &DeviceInfo,
470 sizeof(WDMAUD_DEVICE_INFO),
471 NULL);
472
473 if ( ! MMSUCCESS(Result) )
474 {
475 return TranslateInternalMmResult(Result);
476 }
477
478 /* Store format */
479 Instance->WaveFormatEx.cbSize = WaveFormat->cbSize;
480 Instance->WaveFormatEx.wFormatTag = WaveFormat->wFormatTag;
481 Instance->WaveFormatEx.nChannels = WaveFormat->nChannels;
482 Instance->WaveFormatEx.nSamplesPerSec = WaveFormat->nSamplesPerSec;
483 Instance->WaveFormatEx.nBlockAlign = WaveFormat->nBlockAlign;
484 Instance->WaveFormatEx.nAvgBytesPerSec = WaveFormat->nAvgBytesPerSec;
485 Instance->WaveFormatEx.wBitsPerSample = WaveFormat->wBitsPerSample;
486
487 /* Store sound device handle instance handle */
488 Instance->Handle = (PVOID)DeviceInfo.hDevice;
489
490 /* Now determine framing requirements */
491 Result = SyncOverlappedDeviceIoControl(KernelHandle,
492 IOCTL_GETFRAMESIZE,
493 (LPVOID) &DeviceInfo,
494 sizeof(WDMAUD_DEVICE_INFO),
495 (LPVOID) &DeviceInfo,
496 sizeof(WDMAUD_DEVICE_INFO),
497 NULL);
498
499 if ( MMSUCCESS(Result) )
500 {
501 if (DeviceInfo.u.FrameSize)
502 {
503 Instance->FrameSize = DeviceInfo.u.FrameSize * 2;
504 Instance->BufferCount = WaveFormat->nAvgBytesPerSec / Instance->FrameSize;
505 SND_TRACE(L"FrameSize %u BufferCount %u\n", Instance->FrameSize, Instance->BufferCount);
506 }
507 }
508 else
509 {
510 // use a default of 100 buffers
511 Instance->BufferCount = 100;
512 }
513
514 if (DeviceType == WAVE_OUT_DEVICE_TYPE)
515 {
516 /* Now start the stream */
517 DeviceInfo.u.State = KSSTATE_RUN;
518 SyncOverlappedDeviceIoControl(KernelHandle,
519 IOCTL_SETDEVICE_STATE,
520 (LPVOID) &DeviceInfo,
521 sizeof(WDMAUD_DEVICE_INFO),
522 (LPVOID) &DeviceInfo,
523 sizeof(WDMAUD_DEVICE_INFO),
524 NULL);
525 }
526
527 return MMSYSERR_NOERROR;
528 }
529
530 MMRESULT
531 WriteFileEx_Committer2(
532 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
533 IN PVOID OffsetPtr,
534 IN DWORD Length,
535 IN PSOUND_OVERLAPPED Overlap,
536 IN LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine)
537 {
538 HANDLE Handle;
539 MMRESULT Result;
540 WDMAUD_DEVICE_INFO DeviceInfo;
541 PSOUND_DEVICE SoundDevice;
542 MMDEVICE_TYPE DeviceType;
543 BOOL Ret;
544
545 VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance );
546 VALIDATE_MMSYS_PARAMETER( OffsetPtr );
547 VALIDATE_MMSYS_PARAMETER( Overlap );
548 VALIDATE_MMSYS_PARAMETER( CompletionRoutine );
549
550 GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle);
551
552
553 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
554
555 if ( ! MMSUCCESS(Result) )
556 {
557 return TranslateInternalMmResult(Result);
558 }
559
560 Result = GetSoundDeviceType(SoundDevice, &DeviceType);
561 SND_ASSERT( Result == MMSYSERR_NOERROR );
562
563 SND_ASSERT(Handle);
564
565 ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
566
567 DeviceInfo.Header.FrameExtent = Length;
568 if (DeviceType == WAVE_OUT_DEVICE_TYPE)
569 {
570 DeviceInfo.Header.DataUsed = Length;
571 }
572 DeviceInfo.Header.Data = OffsetPtr;
573 DeviceInfo.Header.Size = sizeof(WDMAUD_DEVICE_INFO);
574 DeviceInfo.Header.PresentationTime.Numerator = 1;
575 DeviceInfo.Header.PresentationTime.Denominator = 1;
576 DeviceInfo.hDevice = Handle;
577 DeviceInfo.DeviceType = DeviceType;
578
579 Overlap->Standard.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
580
581 if (DeviceType == WAVE_OUT_DEVICE_TYPE)
582 {
583 Ret = WriteFileEx(KernelHandle, &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPOVERLAPPED)Overlap, CompletionRoutine);
584 if (Ret)
585 WaitForSingleObjectEx (KernelHandle, INFINITE, TRUE);
586 }
587 else if (DeviceType == WAVE_IN_DEVICE_TYPE)
588 {
589 Ret = ReadFileEx(KernelHandle, &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPOVERLAPPED)Overlap, CompletionRoutine);
590 //if (Ret)
591 // WaitForSingleObjectEx (KernelHandle, INFINITE, TRUE);
592 }
593
594 return MMSYSERR_NOERROR;
595 }
596
597 MMRESULT
598 SetWdmWaveState(
599 IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
600 IN BOOL bStart)
601 {
602 MMRESULT Result;
603 PSOUND_DEVICE SoundDevice;
604 WDMAUD_DEVICE_INFO DeviceInfo;
605 MMDEVICE_TYPE DeviceType;
606 HANDLE Handle;
607
608 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
609
610 if ( ! MMSUCCESS(Result) )
611 {
612 return TranslateInternalMmResult(Result);
613 }
614
615 Result = GetSoundDeviceType(SoundDevice, &DeviceType);
616 SND_ASSERT( Result == MMSYSERR_NOERROR );
617
618 Result = GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle);
619 SND_ASSERT( Result == MMSYSERR_NOERROR );
620
621 ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
622 DeviceInfo.hDevice = Handle;
623 DeviceInfo.DeviceType = DeviceType;
624
625 if (bStart)
626 DeviceInfo.u.State = KSSTATE_RUN;
627 else
628 DeviceInfo.u.State = KSSTATE_PAUSE;
629 Result = SyncOverlappedDeviceIoControl(KernelHandle,
630 IOCTL_SETDEVICE_STATE,
631 (LPVOID) &DeviceInfo,
632 sizeof(WDMAUD_DEVICE_INFO),
633 (LPVOID) &DeviceInfo,
634 sizeof(WDMAUD_DEVICE_INFO),
635 NULL);
636
637 return Result;
638 }
639
640 MMRESULT
641 GetDeviceInterfaceString(
642 IN MMDEVICE_TYPE DeviceType,
643 IN DWORD DeviceId,
644 IN LPWSTR Interface,
645 IN DWORD InterfaceLength,
646 OUT DWORD * InterfaceSize)
647 {
648 WDMAUD_DEVICE_INFO DeviceInfo;
649 MMRESULT Result;
650
651 ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
652 DeviceInfo.DeviceType = DeviceType;
653 DeviceInfo.DeviceIndex = DeviceId;
654
655
656 Result = SyncOverlappedDeviceIoControl(KernelHandle,
657 IOCTL_QUERYDEVICEINTERFACESTRING,
658 (LPVOID) &DeviceInfo,
659 sizeof(WDMAUD_DEVICE_INFO),
660 (LPVOID) &DeviceInfo,
661 sizeof(WDMAUD_DEVICE_INFO),
662 NULL);
663
664
665 if ( ! MMSUCCESS(Result) )
666 {
667 return TranslateInternalMmResult(Result);
668 }
669
670
671 if (!Interface)
672 {
673 SND_ASSERT(InterfaceSize);
674
675 *InterfaceSize = DeviceInfo.u.Interface.DeviceInterfaceStringSize;
676 return MMSYSERR_NOERROR;
677 }
678
679 if (InterfaceLength < DeviceInfo.u.Interface.DeviceInterfaceStringSize)
680 {
681 /* buffer is too small */
682 return MMSYSERR_MOREDATA;
683 }
684
685 DeviceInfo.u.Interface.DeviceInterfaceStringSize = InterfaceLength;
686 DeviceInfo.u.Interface.DeviceInterfaceString = Interface;
687
688 Result = SyncOverlappedDeviceIoControl(KernelHandle,
689 IOCTL_QUERYDEVICEINTERFACESTRING,
690 (LPVOID) &DeviceInfo,
691 sizeof(WDMAUD_DEVICE_INFO),
692 (LPVOID) &DeviceInfo,
693 sizeof(WDMAUD_DEVICE_INFO),
694 NULL);
695
696 if ( MMSUCCESS(Result) && InterfaceLength > 2)
697 {
698 Interface[1] = L'\\';
699 Interface[InterfaceLength-1] = L'\0';
700 }
701
702 return Result;
703 }
704
705 MMRESULT
706 GetWdmPosition(
707 IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
708 IN MMTIME* Time)
709 {
710 MMRESULT Result;
711 PSOUND_DEVICE SoundDevice;
712 WDMAUD_DEVICE_INFO DeviceInfo;
713 MMDEVICE_TYPE DeviceType;
714 HANDLE Handle;
715
716 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
717
718 if ( ! MMSUCCESS(Result) )
719 {
720 return TranslateInternalMmResult(Result);
721 }
722
723 Result = GetSoundDeviceType(SoundDevice, &DeviceType);
724 SND_ASSERT( Result == MMSYSERR_NOERROR );
725
726 Result = GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle);
727 SND_ASSERT( Result == MMSYSERR_NOERROR );
728
729 ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
730 DeviceInfo.hDevice = Handle;
731 DeviceInfo.DeviceType = DeviceType;
732
733 Result = SyncOverlappedDeviceIoControl(KernelHandle,
734 IOCTL_OPEN_WDMAUD,
735 (LPVOID) &DeviceInfo,
736 sizeof(WDMAUD_DEVICE_INFO),
737 (LPVOID) &DeviceInfo,
738 sizeof(WDMAUD_DEVICE_INFO),
739 NULL);
740
741 if ( ! MMSUCCESS(Result) )
742 {
743 return TranslateInternalMmResult(Result);
744 }
745
746 Time->wType = TIME_BYTES;
747 Time->u.cb = (DWORD)DeviceInfo.u.Position;
748
749 return MMSYSERR_NOERROR;
750 }
751
752 MMRESULT
753 ResetStream(
754 IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
755 IN MMDEVICE_TYPE DeviceType,
756 IN BOOLEAN bStartReset)
757 {
758 MMRESULT Result;
759 HANDLE Handle;
760 WDMAUD_DEVICE_INFO DeviceInfo;
761
762 Result = GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle);
763 SND_ASSERT( Result == MMSYSERR_NOERROR );
764
765 ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
766 DeviceInfo.hDevice = Handle;
767 DeviceInfo.DeviceType = DeviceType;
768 DeviceInfo.u.ResetStream = (bStartReset ? KSRESET_BEGIN : KSRESET_END);
769
770 Result = SyncOverlappedDeviceIoControl(KernelHandle,
771 IOCTL_RESET_STREAM,
772 (LPVOID) &DeviceInfo,
773 sizeof(WDMAUD_DEVICE_INFO),
774 (LPVOID) &DeviceInfo,
775 sizeof(WDMAUD_DEVICE_INFO),
776 NULL);
777 return Result;
778 }
779
780
781 MMRESULT
782 QueryMixerInfo(
783 IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
784 IN UINT uMsg,
785 IN LPVOID Parameter,
786 IN DWORD Flags)
787 {
788 MMRESULT Result;
789 WDMAUD_DEVICE_INFO DeviceInfo;
790 HANDLE Handle;
791 DWORD IoControlCode;
792 LPMIXERLINEW MixLine;
793 LPMIXERLINECONTROLSW MixControls;
794 LPMIXERCONTROLDETAILS MixDetails;
795
796 SND_TRACE(L"uMsg %x Flags %x\n", uMsg, Flags);
797
798 Result = GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle);
799 SND_ASSERT( Result == MMSYSERR_NOERROR );
800
801 ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
802 DeviceInfo.hDevice = Handle;
803 DeviceInfo.DeviceType = MIXER_DEVICE_TYPE;
804 DeviceInfo.Flags = Flags;
805
806 MixLine = (LPMIXERLINEW)Parameter;
807 MixControls = (LPMIXERLINECONTROLSW)Parameter;
808 MixDetails = (LPMIXERCONTROLDETAILS)Parameter;
809
810 switch(uMsg)
811 {
812 case MXDM_GETLINEINFO:
813 RtlCopyMemory(&DeviceInfo.u.MixLine, MixLine, sizeof(MIXERLINEW));
814 IoControlCode = IOCTL_GETLINEINFO;
815 break;
816 case MXDM_GETLINECONTROLS:
817 RtlCopyMemory(&DeviceInfo.u.MixControls, MixControls, sizeof(MIXERLINECONTROLSW));
818 IoControlCode = IOCTL_GETLINECONTROLS;
819 break;
820 case MXDM_SETCONTROLDETAILS:
821 RtlCopyMemory(&DeviceInfo.u.MixDetails, MixDetails, sizeof(MIXERCONTROLDETAILS));
822 IoControlCode = IOCTL_SETCONTROLDETAILS;
823 break;
824 case MXDM_GETCONTROLDETAILS:
825 RtlCopyMemory(&DeviceInfo.u.MixDetails, MixDetails, sizeof(MIXERCONTROLDETAILS));
826 IoControlCode = IOCTL_GETCONTROLDETAILS;
827 break;
828 default:
829 SND_ASSERT(0);
830 return MMSYSERR_NOTSUPPORTED;
831 }
832
833 Result = SyncOverlappedDeviceIoControl(KernelHandle,
834 IoControlCode,
835 (LPVOID) &DeviceInfo,
836 sizeof(WDMAUD_DEVICE_INFO),
837 (LPVOID) &DeviceInfo,
838 sizeof(WDMAUD_DEVICE_INFO),
839 NULL);
840
841 if ( ! MMSUCCESS(Result) )
842 {
843 return Result;
844 }
845
846 switch(uMsg)
847 {
848 case MXDM_GETLINEINFO:
849 {
850 RtlCopyMemory(MixLine, &DeviceInfo.u.MixLine, sizeof(MIXERLINEW));
851 break;
852 }
853 }
854
855 return Result;
856 }
857
858
859 MMRESULT
860 PopulateWdmDeviceList(
861 HANDLE Handle,
862 MMDEVICE_TYPE DeviceType)
863 {
864 MMRESULT Result;
865 DWORD DeviceCount = 0;
866 PSOUND_DEVICE SoundDevice = NULL;
867 MMFUNCTION_TABLE FuncTable;
868 DWORD i;
869
870 VALIDATE_MMSYS_PARAMETER( Handle != INVALID_HANDLE_VALUE );
871 VALIDATE_MMSYS_PARAMETER( IS_VALID_SOUND_DEVICE_TYPE(DeviceType) );
872
873 Result = GetNumWdmDevs(Handle, DeviceType, &DeviceCount);
874
875 if ( ! MMSUCCESS(Result) )
876 {
877 SND_ERR(L"Error %d while obtaining number of devices\n", Result);
878 return TranslateInternalMmResult(Result);
879 }
880
881 SND_TRACE(L"%d devices of type %d found\n", DeviceCount, DeviceType);
882
883
884 for ( i = 0; i < DeviceCount; ++ i )
885 {
886 Result = ListSoundDevice(DeviceType, UlongToPtr(i), &SoundDevice);
887
888 if ( ! MMSUCCESS(Result) )
889 {
890 SND_ERR(L"Failed to list sound device - error %d\n", Result);
891 return TranslateInternalMmResult(Result);
892 }
893
894 /* Set up our function table */
895 ZeroMemory(&FuncTable, sizeof(MMFUNCTION_TABLE));
896 FuncTable.GetCapabilities = GetWdmDeviceCapabilities;
897 FuncTable.QueryWaveFormatSupport = QueryWdmWaveDeviceFormatSupport;
898 if (DeviceType == MIXER_DEVICE_TYPE)
899 {
900 FuncTable.SetWaveFormat = SetWdmMixerDeviceFormat;
901 FuncTable.QueryMixerInfo = QueryMixerInfo;
902 }
903 else
904 {
905 FuncTable.SetWaveFormat = SetWdmWaveDeviceFormat;
906 }
907
908 if (DeviceType == WAVE_IN_DEVICE_TYPE || DeviceType == WAVE_OUT_DEVICE_TYPE)
909 {
910 FuncTable.SetState = SetWdmWaveState;
911 FuncTable.ResetStream = ResetStream;
912 }
913
914 FuncTable.Open = OpenWdmSoundDevice;
915 FuncTable.Close = CloseWdmSoundDevice;
916 FuncTable.GetDeviceInterfaceString = GetDeviceInterfaceString;
917 #ifndef USERMODE_MIXER
918 FuncTable.CommitWaveBuffer = WriteFileEx_Committer2;
919 #else
920 FuncTable.CommitWaveBuffer = WriteFileEx_Remixer;
921 #endif
922 FuncTable.GetPos = GetWdmPosition;
923
924 SetSoundDeviceFunctionTable(SoundDevice, &FuncTable);
925 }
926
927 return MMSYSERR_NOERROR;
928 }
929
930
931
932 LONG
933 APIENTRY
934 DriverProc(
935 DWORD DriverId,
936 HANDLE DriverHandle,
937 UINT Message,
938 LONG Parameter1,
939 LONG Parameter2)
940 {
941 MMRESULT Result;
942
943 switch ( Message )
944 {
945 case DRV_LOAD :
946 {
947 HANDLE Handle;
948 SND_TRACE(L"DRV_LOAD\n");
949
950 Result = InitEntrypointMutexes();
951
952 if ( ! MMSUCCESS(Result) )
953 return 0L;
954
955 OpenWdmSoundDevice(NULL, &Handle);
956
957 if ( Handle == INVALID_HANDLE_VALUE )
958 {
959 SND_ERR(L"Failed to open %s\n", KERNEL_DEVICE_NAME);
960 CleanupEntrypointMutexes();
961
962 //UnlistAllSoundDevices();
963
964 return 0L;
965 }
966
967 /* Populate the device lists */
968 SND_TRACE(L"Populating device lists\n");
969 PopulateWdmDeviceList(KernelHandle, WAVE_OUT_DEVICE_TYPE);
970 PopulateWdmDeviceList(KernelHandle, WAVE_IN_DEVICE_TYPE);
971 PopulateWdmDeviceList(KernelHandle, MIDI_OUT_DEVICE_TYPE);
972 PopulateWdmDeviceList(KernelHandle, MIDI_IN_DEVICE_TYPE);
973 PopulateWdmDeviceList(KernelHandle, AUX_DEVICE_TYPE);
974 PopulateWdmDeviceList(KernelHandle, MIXER_DEVICE_TYPE);
975
976 SND_TRACE(L"Initialisation complete\n");
977
978 return 1L;
979 }
980
981 case DRV_FREE :
982 {
983 SND_TRACE(L"DRV_FREE\n");
984
985 if ( KernelHandle != INVALID_HANDLE_VALUE )
986 {
987 CloseHandle(KernelHandle);
988 KernelHandle = INVALID_HANDLE_VALUE;
989 }
990
991 /* TODO: Clean up the path names! */
992 UnlistAllSoundDevices();
993
994 CleanupEntrypointMutexes();
995
996 SND_TRACE(L"Unfreed memory blocks: %d\n",
997 GetMemoryAllocationCount());
998
999 return 1L;
1000 }
1001
1002 case DRV_ENABLE :
1003 case DRV_DISABLE :
1004 {
1005 SND_TRACE(L"DRV_ENABLE / DRV_DISABLE\n");
1006 return 1L;
1007 }
1008
1009 case DRV_OPEN :
1010 case DRV_CLOSE :
1011 {
1012 SND_TRACE(L"DRV_OPEN / DRV_CLOSE\n");
1013 return 1L;
1014 }
1015
1016 case DRV_QUERYCONFIGURE :
1017 {
1018 SND_TRACE(L"DRV_QUERYCONFIGURE\n");
1019 return 0L;
1020 }
1021 case DRV_CONFIGURE :
1022 return DRVCNF_OK;
1023
1024 default :
1025 SND_TRACE(L"Unhandled message %d\n", Message);
1026 return DefDriverProc(DriverId,
1027 DriverHandle,
1028 Message,
1029 Parameter1,
1030 Parameter2);
1031 }
1032 }
1033
1034
1035 BOOL WINAPI DllMain(
1036 HINSTANCE hinstDLL,
1037 DWORD fdwReason,
1038 LPVOID lpvReserved)
1039 {
1040 switch ( fdwReason )
1041 {
1042 case DLL_PROCESS_ATTACH :
1043 SND_TRACE(L"WDMAUD.DRV - Process attached\n");
1044 break;
1045 case DLL_PROCESS_DETACH :
1046 SND_TRACE(L"WDMAUD.DRV - Process detached\n");
1047 break;
1048 case DLL_THREAD_ATTACH :
1049 SND_TRACE(L"WDMAUD.DRV - Thread attached\n");
1050 break;
1051 case DLL_THREAD_DETACH :
1052 SND_TRACE(L"WDMAUD.DRV - Thread detached\n");
1053 break;
1054 }
1055
1056 return TRUE;
1057 }