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