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