[MMEBUDDY]
[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 Result = SyncOverlappedDeviceIoControl(KernelHandle,
325 IOCTL_GET_MIXER_EVENT,
326 (LPVOID) &DeviceInfo,
327 sizeof(WDMAUD_DEVICE_INFO),
328 (LPVOID) &DeviceInfo,
329 sizeof(WDMAUD_DEVICE_INFO),
330 NULL);
331
332 if (Result == MMSYSERR_NOERROR)
333 {
334 DriverCallback(Instance->WinMM.ClientCallback,
335 HIWORD(Instance->WinMM.Flags),
336 Instance->WinMM.Handle,
337 DeviceInfo.u.MixerEvent.NotificationType,
338 Instance->WinMM.ClientCallbackInstanceData,
339 (DWORD_PTR)DeviceInfo.u.MixerEvent.Value,
340 0);
341 }
342 }while(TRUE);
343
344 /* done */
345 return 0;
346 }
347
348
349 MMRESULT
350 SetWdmMixerDeviceFormat(
351 IN PSOUND_DEVICE_INSTANCE Instance,
352 IN DWORD DeviceId,
353 IN PWAVEFORMATEX WaveFormat,
354 IN DWORD WaveFormatSize)
355 {
356 MMRESULT Result;
357 WDMAUD_DEVICE_INFO DeviceInfo;
358 HANDLE hThread;
359
360 if (Instance->Handle != KernelHandle)
361 {
362 /* device is already open */
363 return MMSYSERR_NOERROR;
364 }
365
366 Instance->hNotifyEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
367 if ( ! Instance->hNotifyEvent )
368 return MMSYSERR_NOMEM;
369
370 Instance->hStopEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
371 if ( ! Instance->hStopEvent )
372 return MMSYSERR_NOMEM;
373
374 ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
375 DeviceInfo.DeviceType = MIXER_DEVICE_TYPE;
376 DeviceInfo.DeviceIndex = DeviceId;
377 DeviceInfo.u.hNotifyEvent = Instance->hNotifyEvent;
378
379 Result = SyncOverlappedDeviceIoControl(KernelHandle,
380 IOCTL_OPEN_WDMAUD,
381 (LPVOID) &DeviceInfo,
382 sizeof(WDMAUD_DEVICE_INFO),
383 (LPVOID) &DeviceInfo,
384 sizeof(WDMAUD_DEVICE_INFO),
385 NULL);
386
387 if ( ! MMSUCCESS(Result) )
388 {
389 CloseHandle(Instance->hNotifyEvent);
390 CloseHandle(Instance->hStopEvent);
391 return TranslateInternalMmResult(Result);
392 }
393
394 hThread = CreateThread(NULL, 0, MixerEventThreadRoutine, (LPVOID)Instance, 0, NULL);
395 if ( hThread )
396 {
397 CloseHandle(hThread);
398 }
399
400 /* Store sound device handle instance handle */
401 Instance->Handle = (PVOID)DeviceInfo.hDevice;
402
403 return MMSYSERR_NOERROR;
404 }
405
406 MMRESULT
407 SetWdmWaveDeviceFormat(
408 IN PSOUND_DEVICE_INSTANCE Instance,
409 IN DWORD DeviceId,
410 IN PWAVEFORMATEX WaveFormat,
411 IN DWORD WaveFormatSize)
412 {
413 MMRESULT Result;
414 PSOUND_DEVICE SoundDevice;
415 PVOID Identifier;
416 WDMAUD_DEVICE_INFO DeviceInfo;
417 MMDEVICE_TYPE DeviceType;
418
419 Result = GetSoundDeviceFromInstance(Instance, &SoundDevice);
420
421 if ( ! MMSUCCESS(Result) )
422 {
423 return TranslateInternalMmResult(Result);
424 }
425
426 Result = GetSoundDeviceIdentifier(SoundDevice, &Identifier);
427
428 if ( ! MMSUCCESS(Result) )
429 {
430 return TranslateInternalMmResult(Result);
431 }
432
433 if (Instance->Handle != KernelHandle)
434 {
435 /* device is already open */
436 return MMSYSERR_NOERROR;
437 }
438
439
440 Result = GetSoundDeviceType(SoundDevice, &DeviceType);
441 SND_ASSERT( Result == MMSYSERR_NOERROR );
442
443 ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
444 DeviceInfo.DeviceType = DeviceType;
445 DeviceInfo.DeviceIndex = DeviceId;
446 DeviceInfo.u.WaveFormatEx.cbSize = WaveFormat->cbSize;
447 DeviceInfo.u.WaveFormatEx.wFormatTag = WaveFormat->wFormatTag;
448 #ifdef USERMODE_MIXER
449 DeviceInfo.u.WaveFormatEx.nChannels = 2;
450 DeviceInfo.u.WaveFormatEx.nSamplesPerSec = 44100;
451 DeviceInfo.u.WaveFormatEx.nBlockAlign = 4;
452 DeviceInfo.u.WaveFormatEx.nAvgBytesPerSec = 176400;
453 DeviceInfo.u.WaveFormatEx.wBitsPerSample = 16;
454 #else
455 DeviceInfo.u.WaveFormatEx.nChannels = WaveFormat->nChannels;
456 DeviceInfo.u.WaveFormatEx.nSamplesPerSec = WaveFormat->nSamplesPerSec;
457 DeviceInfo.u.WaveFormatEx.nBlockAlign = WaveFormat->nBlockAlign;
458 DeviceInfo.u.WaveFormatEx.nAvgBytesPerSec = WaveFormat->nAvgBytesPerSec;
459 DeviceInfo.u.WaveFormatEx.wBitsPerSample = WaveFormat->wBitsPerSample;
460 #endif
461
462 Result = SyncOverlappedDeviceIoControl(KernelHandle,
463 IOCTL_OPEN_WDMAUD,
464 (LPVOID) &DeviceInfo,
465 sizeof(WDMAUD_DEVICE_INFO),
466 (LPVOID) &DeviceInfo,
467 sizeof(WDMAUD_DEVICE_INFO),
468 NULL);
469
470 if ( ! MMSUCCESS(Result) )
471 {
472 return TranslateInternalMmResult(Result);
473 }
474
475 /* Store format */
476 Instance->WaveFormatEx.cbSize = WaveFormat->cbSize;
477 Instance->WaveFormatEx.wFormatTag = WaveFormat->wFormatTag;
478 Instance->WaveFormatEx.nChannels = WaveFormat->nChannels;
479 Instance->WaveFormatEx.nSamplesPerSec = WaveFormat->nSamplesPerSec;
480 Instance->WaveFormatEx.nBlockAlign = WaveFormat->nBlockAlign;
481 Instance->WaveFormatEx.nAvgBytesPerSec = WaveFormat->nAvgBytesPerSec;
482 Instance->WaveFormatEx.wBitsPerSample = WaveFormat->wBitsPerSample;
483
484 /* Store sound device handle instance handle */
485 Instance->Handle = (PVOID)DeviceInfo.hDevice;
486
487 /* Now determine framing requirements */
488 Result = SyncOverlappedDeviceIoControl(KernelHandle,
489 IOCTL_GETFRAMESIZE,
490 (LPVOID) &DeviceInfo,
491 sizeof(WDMAUD_DEVICE_INFO),
492 (LPVOID) &DeviceInfo,
493 sizeof(WDMAUD_DEVICE_INFO),
494 NULL);
495
496 if ( MMSUCCESS(Result) )
497 {
498 if (DeviceInfo.u.FrameSize)
499 {
500 Instance->FrameSize = DeviceInfo.u.FrameSize * 2;
501 Instance->BufferCount = WaveFormat->nAvgBytesPerSec / Instance->FrameSize;
502 SND_TRACE(L"FrameSize %u BufferCount %u\n", Instance->FrameSize, Instance->BufferCount);
503 }
504 }
505 else
506 {
507 // use a default of 100 buffers
508 Instance->BufferCount = 100;
509 }
510
511 if (DeviceType == WAVE_OUT_DEVICE_TYPE)
512 {
513 /* Now start the stream */
514 DeviceInfo.u.State = KSSTATE_RUN;
515 SyncOverlappedDeviceIoControl(KernelHandle,
516 IOCTL_SETDEVICE_STATE,
517 (LPVOID) &DeviceInfo,
518 sizeof(WDMAUD_DEVICE_INFO),
519 (LPVOID) &DeviceInfo,
520 sizeof(WDMAUD_DEVICE_INFO),
521 NULL);
522 }
523
524 return MMSYSERR_NOERROR;
525 }
526
527 MMRESULT
528 WriteFileEx_Committer2(
529 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
530 IN PVOID OffsetPtr,
531 IN DWORD Length,
532 IN PSOUND_OVERLAPPED Overlap,
533 IN LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine)
534 {
535 HANDLE Handle;
536 MMRESULT Result;
537 WDMAUD_DEVICE_INFO DeviceInfo;
538 PSOUND_DEVICE SoundDevice;
539 MMDEVICE_TYPE DeviceType;
540 BOOL Ret;
541
542 VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance );
543 VALIDATE_MMSYS_PARAMETER( OffsetPtr );
544 VALIDATE_MMSYS_PARAMETER( Overlap );
545 VALIDATE_MMSYS_PARAMETER( CompletionRoutine );
546
547 GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle);
548
549
550 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
551
552 if ( ! MMSUCCESS(Result) )
553 {
554 return TranslateInternalMmResult(Result);
555 }
556
557 Result = GetSoundDeviceType(SoundDevice, &DeviceType);
558 SND_ASSERT( Result == MMSYSERR_NOERROR );
559
560 SND_ASSERT(Handle);
561
562 ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
563
564 DeviceInfo.Header.FrameExtent = Length;
565 if (DeviceType == WAVE_OUT_DEVICE_TYPE)
566 {
567 DeviceInfo.Header.DataUsed = Length;
568 }
569 DeviceInfo.Header.Data = OffsetPtr;
570 DeviceInfo.Header.Size = sizeof(WDMAUD_DEVICE_INFO);
571 DeviceInfo.Header.PresentationTime.Numerator = 1;
572 DeviceInfo.Header.PresentationTime.Denominator = 1;
573 DeviceInfo.hDevice = Handle;
574 DeviceInfo.DeviceType = DeviceType;
575
576 Overlap->Standard.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
577
578 if (DeviceType == WAVE_OUT_DEVICE_TYPE)
579 {
580 Ret = WriteFileEx(KernelHandle, &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPOVERLAPPED)Overlap, CompletionRoutine);
581 if (Ret)
582 WaitForSingleObjectEx (KernelHandle, INFINITE, TRUE);
583 }
584 else if (DeviceType == WAVE_IN_DEVICE_TYPE)
585 {
586 Ret = ReadFileEx(KernelHandle, &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPOVERLAPPED)Overlap, CompletionRoutine);
587 //if (Ret)
588 // WaitForSingleObjectEx (KernelHandle, INFINITE, TRUE);
589 }
590
591 return MMSYSERR_NOERROR;
592 }
593
594 MMRESULT
595 SetWdmWaveState(
596 IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
597 IN BOOL bStart)
598 {
599 MMRESULT Result;
600 PSOUND_DEVICE SoundDevice;
601 WDMAUD_DEVICE_INFO DeviceInfo;
602 MMDEVICE_TYPE DeviceType;
603 HANDLE Handle;
604
605 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
606
607 if ( ! MMSUCCESS(Result) )
608 {
609 return TranslateInternalMmResult(Result);
610 }
611
612 Result = GetSoundDeviceType(SoundDevice, &DeviceType);
613 SND_ASSERT( Result == MMSYSERR_NOERROR );
614
615 Result = GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle);
616 SND_ASSERT( Result == MMSYSERR_NOERROR );
617
618 ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
619 DeviceInfo.hDevice = Handle;
620 DeviceInfo.DeviceType = DeviceType;
621
622 if (bStart)
623 DeviceInfo.u.State = KSSTATE_RUN;
624 else
625 DeviceInfo.u.State = KSSTATE_PAUSE;
626 Result = SyncOverlappedDeviceIoControl(KernelHandle,
627 IOCTL_SETDEVICE_STATE,
628 (LPVOID) &DeviceInfo,
629 sizeof(WDMAUD_DEVICE_INFO),
630 (LPVOID) &DeviceInfo,
631 sizeof(WDMAUD_DEVICE_INFO),
632 NULL);
633
634 return Result;
635 }
636
637 MMRESULT
638 GetDeviceInterfaceString(
639 IN MMDEVICE_TYPE DeviceType,
640 IN DWORD DeviceId,
641 IN LPWSTR Interface,
642 IN DWORD InterfaceLength,
643 OUT DWORD * InterfaceSize)
644 {
645 WDMAUD_DEVICE_INFO DeviceInfo;
646 MMRESULT Result;
647
648 ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
649 DeviceInfo.DeviceType = DeviceType;
650 DeviceInfo.DeviceIndex = DeviceId;
651
652
653 Result = SyncOverlappedDeviceIoControl(KernelHandle,
654 IOCTL_QUERYDEVICEINTERFACESTRING,
655 (LPVOID) &DeviceInfo,
656 sizeof(WDMAUD_DEVICE_INFO),
657 (LPVOID) &DeviceInfo,
658 sizeof(WDMAUD_DEVICE_INFO),
659 NULL);
660
661
662 if ( ! MMSUCCESS(Result) )
663 {
664 return TranslateInternalMmResult(Result);
665 }
666
667
668 if (!Interface)
669 {
670 SND_ASSERT(InterfaceSize);
671
672 *InterfaceSize = DeviceInfo.u.Interface.DeviceInterfaceStringSize;
673 return MMSYSERR_NOERROR;
674 }
675
676 if (InterfaceLength < DeviceInfo.u.Interface.DeviceInterfaceStringSize)
677 {
678 /* buffer is too small */
679 return MMSYSERR_MOREDATA;
680 }
681
682 DeviceInfo.u.Interface.DeviceInterfaceStringSize = InterfaceLength;
683 DeviceInfo.u.Interface.DeviceInterfaceString = Interface;
684
685 Result = SyncOverlappedDeviceIoControl(KernelHandle,
686 IOCTL_QUERYDEVICEINTERFACESTRING,
687 (LPVOID) &DeviceInfo,
688 sizeof(WDMAUD_DEVICE_INFO),
689 (LPVOID) &DeviceInfo,
690 sizeof(WDMAUD_DEVICE_INFO),
691 NULL);
692
693 if ( MMSUCCESS(Result) && InterfaceLength > 2)
694 {
695 Interface[1] = L'\\';
696 Interface[InterfaceLength-1] = L'\0';
697 }
698
699 return Result;
700 }
701
702 MMRESULT
703 GetWdmPosition(
704 IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
705 IN MMTIME* Time)
706 {
707 MMRESULT Result;
708 PSOUND_DEVICE SoundDevice;
709 WDMAUD_DEVICE_INFO DeviceInfo;
710 MMDEVICE_TYPE DeviceType;
711 HANDLE Handle;
712
713 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
714
715 if ( ! MMSUCCESS(Result) )
716 {
717 return TranslateInternalMmResult(Result);
718 }
719
720 Result = GetSoundDeviceType(SoundDevice, &DeviceType);
721 SND_ASSERT( Result == MMSYSERR_NOERROR );
722
723 Result = GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle);
724 SND_ASSERT( Result == MMSYSERR_NOERROR );
725
726 ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
727 DeviceInfo.hDevice = Handle;
728 DeviceInfo.DeviceType = DeviceType;
729
730 Result = SyncOverlappedDeviceIoControl(KernelHandle,
731 IOCTL_OPEN_WDMAUD,
732 (LPVOID) &DeviceInfo,
733 sizeof(WDMAUD_DEVICE_INFO),
734 (LPVOID) &DeviceInfo,
735 sizeof(WDMAUD_DEVICE_INFO),
736 NULL);
737
738 if ( ! MMSUCCESS(Result) )
739 {
740 return TranslateInternalMmResult(Result);
741 }
742
743 Time->wType = TIME_BYTES;
744 Time->u.cb = (DWORD)DeviceInfo.u.Position;
745
746 return MMSYSERR_NOERROR;
747 }
748
749 MMRESULT
750 QueryMixerInfo(
751 IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
752 IN UINT uMsg,
753 IN LPVOID Parameter,
754 IN DWORD Flags)
755 {
756 MMRESULT Result;
757 WDMAUD_DEVICE_INFO DeviceInfo;
758 HANDLE Handle;
759 DWORD IoControlCode;
760 LPMIXERLINEW MixLine;
761 LPMIXERLINECONTROLSW MixControls;
762 LPMIXERCONTROLDETAILS MixDetails;
763
764 SND_TRACE(L"uMsg %x Flags %x\n", uMsg, Flags);
765
766 Result = GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle);
767 SND_ASSERT( Result == MMSYSERR_NOERROR );
768
769 ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
770 DeviceInfo.hDevice = Handle;
771 DeviceInfo.DeviceType = MIXER_DEVICE_TYPE;
772 DeviceInfo.Flags = Flags;
773
774 MixLine = (LPMIXERLINEW)Parameter;
775 MixControls = (LPMIXERLINECONTROLSW)Parameter;
776 MixDetails = (LPMIXERCONTROLDETAILS)Parameter;
777
778 switch(uMsg)
779 {
780 case MXDM_GETLINEINFO:
781 RtlCopyMemory(&DeviceInfo.u.MixLine, MixLine, sizeof(MIXERLINEW));
782 IoControlCode = IOCTL_GETLINEINFO;
783 break;
784 case MXDM_GETLINECONTROLS:
785 RtlCopyMemory(&DeviceInfo.u.MixControls, MixControls, sizeof(MIXERLINECONTROLSW));
786 IoControlCode = IOCTL_GETLINECONTROLS;
787 break;
788 case MXDM_SETCONTROLDETAILS:
789 RtlCopyMemory(&DeviceInfo.u.MixDetails, MixDetails, sizeof(MIXERCONTROLDETAILS));
790 IoControlCode = IOCTL_SETCONTROLDETAILS;
791 break;
792 case MXDM_GETCONTROLDETAILS:
793 RtlCopyMemory(&DeviceInfo.u.MixDetails, MixDetails, sizeof(MIXERCONTROLDETAILS));
794 IoControlCode = IOCTL_GETCONTROLDETAILS;
795 break;
796 default:
797 SND_ASSERT(0);
798 return MMSYSERR_NOTSUPPORTED;
799 }
800
801 Result = SyncOverlappedDeviceIoControl(KernelHandle,
802 IoControlCode,
803 (LPVOID) &DeviceInfo,
804 sizeof(WDMAUD_DEVICE_INFO),
805 (LPVOID) &DeviceInfo,
806 sizeof(WDMAUD_DEVICE_INFO),
807 NULL);
808
809 if ( ! MMSUCCESS(Result) )
810 {
811 return TranslateInternalMmResult(Result);
812 }
813
814 switch(uMsg)
815 {
816 case MXDM_GETLINEINFO:
817 {
818 RtlCopyMemory(MixLine, &DeviceInfo.u.MixLine, sizeof(MIXERLINEW));
819 break;
820 }
821 }
822
823 return Result;
824 }
825
826
827 MMRESULT
828 PopulateWdmDeviceList(
829 HANDLE Handle,
830 MMDEVICE_TYPE DeviceType)
831 {
832 MMRESULT Result;
833 DWORD DeviceCount = 0;
834 PSOUND_DEVICE SoundDevice = NULL;
835 MMFUNCTION_TABLE FuncTable;
836 DWORD i;
837
838 VALIDATE_MMSYS_PARAMETER( Handle != INVALID_HANDLE_VALUE );
839 VALIDATE_MMSYS_PARAMETER( IS_VALID_SOUND_DEVICE_TYPE(DeviceType) );
840
841 Result = GetNumWdmDevs(Handle, DeviceType, &DeviceCount);
842
843 if ( ! MMSUCCESS(Result) )
844 {
845 SND_ERR(L"Error %d while obtaining number of devices\n", Result);
846 return TranslateInternalMmResult(Result);
847 }
848
849 SND_TRACE(L"%d devices of type %d found\n", DeviceCount, DeviceType);
850
851
852 for ( i = 0; i < DeviceCount; ++ i )
853 {
854 Result = ListSoundDevice(DeviceType, (PVOID) i, &SoundDevice);
855
856 if ( ! MMSUCCESS(Result) )
857 {
858 SND_ERR(L"Failed to list sound device - error %d\n", Result);
859 return TranslateInternalMmResult(Result);
860 }
861
862 /* Set up our function table */
863 ZeroMemory(&FuncTable, sizeof(MMFUNCTION_TABLE));
864 FuncTable.GetCapabilities = GetWdmDeviceCapabilities;
865 FuncTable.QueryWaveFormatSupport = QueryWdmWaveDeviceFormatSupport;
866 if (DeviceType == MIXER_DEVICE_TYPE)
867 {
868 FuncTable.SetWaveFormat = SetWdmMixerDeviceFormat;
869 FuncTable.QueryMixerInfo = QueryMixerInfo;
870 }
871 else
872 {
873 FuncTable.SetWaveFormat = SetWdmWaveDeviceFormat;
874 }
875
876 if (DeviceType == WAVE_IN_DEVICE_TYPE || DeviceType == WAVE_OUT_DEVICE_TYPE)
877 {
878 FuncTable.SetState = SetWdmWaveState;
879 }
880
881 FuncTable.Open = OpenWdmSoundDevice;
882 FuncTable.Close = CloseWdmSoundDevice;
883 FuncTable.GetDeviceInterfaceString = GetDeviceInterfaceString;
884 #ifndef USERMODE_MIXER
885 FuncTable.CommitWaveBuffer = WriteFileEx_Committer2;
886 #else
887 FuncTable.CommitWaveBuffer = WriteFileEx_Remixer;
888 #endif
889 FuncTable.GetPos = GetWdmPosition;
890
891 SetSoundDeviceFunctionTable(SoundDevice, &FuncTable);
892 }
893
894 return MMSYSERR_NOERROR;
895 }
896
897
898
899 LONG
900 APIENTRY
901 DriverProc(
902 DWORD DriverId,
903 HANDLE DriverHandle,
904 UINT Message,
905 LONG Parameter1,
906 LONG Parameter2)
907 {
908 MMRESULT Result;
909
910 switch ( Message )
911 {
912 case DRV_LOAD :
913 {
914 HANDLE Handle;
915 SND_TRACE(L"DRV_LOAD\n");
916
917 Result = InitEntrypointMutexes();
918
919 if ( ! MMSUCCESS(Result) )
920 return 0L;
921
922 OpenWdmSoundDevice(NULL, &Handle);
923
924 if ( Handle == INVALID_HANDLE_VALUE )
925 {
926 SND_ERR(L"Failed to open %s\n", KERNEL_DEVICE_NAME);
927 CleanupEntrypointMutexes();
928
929 //UnlistAllSoundDevices();
930
931 return 0L;
932 }
933
934 /* Populate the device lists */
935 SND_TRACE(L"Populating device lists\n");
936 PopulateWdmDeviceList(KernelHandle, WAVE_OUT_DEVICE_TYPE);
937 PopulateWdmDeviceList(KernelHandle, WAVE_IN_DEVICE_TYPE);
938 PopulateWdmDeviceList(KernelHandle, MIDI_OUT_DEVICE_TYPE);
939 PopulateWdmDeviceList(KernelHandle, MIDI_IN_DEVICE_TYPE);
940 PopulateWdmDeviceList(KernelHandle, AUX_DEVICE_TYPE);
941 PopulateWdmDeviceList(KernelHandle, MIXER_DEVICE_TYPE);
942
943 SND_TRACE(L"Initialisation complete\n");
944
945 return 1L;
946 }
947
948 case DRV_FREE :
949 {
950 SND_TRACE(L"DRV_FREE\n");
951
952 if ( KernelHandle != INVALID_HANDLE_VALUE )
953 {
954 CloseHandle(KernelHandle);
955 KernelHandle = INVALID_HANDLE_VALUE;
956 }
957
958 /* TODO: Clean up the path names! */
959 UnlistAllSoundDevices();
960
961 CleanupEntrypointMutexes();
962
963 SND_TRACE(L"Unfreed memory blocks: %d\n",
964 GetMemoryAllocationCount());
965
966 return 1L;
967 }
968
969 case DRV_ENABLE :
970 case DRV_DISABLE :
971 {
972 SND_TRACE(L"DRV_ENABLE / DRV_DISABLE\n");
973 return 1L;
974 }
975
976 case DRV_OPEN :
977 case DRV_CLOSE :
978 {
979 SND_TRACE(L"DRV_OPEN / DRV_CLOSE\n");
980 return 1L;
981 }
982
983 case DRV_QUERYCONFIGURE :
984 {
985 SND_TRACE(L"DRV_QUERYCONFIGURE\n");
986 return 0L;
987 }
988 case DRV_CONFIGURE :
989 return DRVCNF_OK;
990
991 default :
992 SND_TRACE(L"Unhandled message %d\n", Message);
993 return DefDriverProc(DriverId,
994 DriverHandle,
995 Message,
996 Parameter1,
997 Parameter2);
998 }
999 }
1000
1001
1002 BOOL WINAPI DllMain(
1003 HINSTANCE hinstDLL,
1004 DWORD fdwReason,
1005 LPVOID lpvReserved)
1006 {
1007 switch ( fdwReason )
1008 {
1009 case DLL_PROCESS_ATTACH :
1010 SND_TRACE(L"WDMAUD.DRV - Process attached\n");
1011 break;
1012 case DLL_PROCESS_DETACH :
1013 SND_TRACE(L"WDMAUD.DRV - Process detached\n");
1014 break;
1015 case DLL_THREAD_ATTACH :
1016 SND_TRACE(L"WDMAUD.DRV - Thread attached\n");
1017 break;
1018 case DLL_THREAD_DETACH :
1019 SND_TRACE(L"WDMAUD.DRV - Thread detached\n");
1020 break;
1021 }
1022
1023 return TRUE;
1024 }