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