2 * PROJECT: ReactOS Sound System
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/wdmaud.drv/wdmaud.c
6 * PURPOSE: WDM Audio Driver (User-mode part)
7 * PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
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.
23 #include "interface.h"
25 #define KERNEL_DEVICE_NAME L"\\\\.\\wdmaud"
27 PWSTR UnknownWaveIn
= L
"Wave Input";
28 PWSTR UnknownWaveOut
= L
"Wave Output";
29 PWSTR UnknownMidiIn
= L
"Midi Input";
30 PWSTR UnknownMidiOut
= L
"Midi Output";
32 HANDLE KernelHandle
= INVALID_HANDLE_VALUE
;
37 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance
,
40 IN PSOUND_OVERLAPPED Overlap
,
41 IN LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine
);
48 IN MMDEVICE_TYPE DeviceType
,
49 OUT DWORD
* DeviceCount
)
52 WDMAUD_DEVICE_INFO DeviceInfo
;
54 VALIDATE_MMSYS_PARAMETER( Handle
!= INVALID_HANDLE_VALUE
);
55 VALIDATE_MMSYS_PARAMETER( IS_VALID_SOUND_DEVICE_TYPE(DeviceType
) );
56 VALIDATE_MMSYS_PARAMETER( DeviceCount
);
58 ZeroMemory(&DeviceInfo
, sizeof(WDMAUD_DEVICE_INFO
));
59 DeviceInfo
.DeviceType
= DeviceType
;
61 Result
= SyncOverlappedDeviceIoControl(Handle
,
62 IOCTL_GETNUMDEVS_TYPE
,
64 sizeof(WDMAUD_DEVICE_INFO
),
66 sizeof(WDMAUD_DEVICE_INFO
),
69 if ( ! MMSUCCESS( Result
) )
71 SND_ERR(L
"Call to IOCTL_GETNUMDEVS_TYPE failed\n");
73 return TranslateInternalMmResult(Result
);
76 *DeviceCount
= DeviceInfo
.DeviceCount
;
78 return MMSYSERR_NOERROR
;
82 GetWdmDeviceCapabilities(
83 IN PSOUND_DEVICE SoundDevice
,
85 OUT PVOID Capabilities
,
86 IN DWORD CapabilitiesSize
)
88 /* NOTE - At this time, WDMAUD does not support this properly */
91 MMDEVICE_TYPE DeviceType
;
92 WDMAUD_DEVICE_INFO DeviceInfo
;
94 SND_ASSERT( SoundDevice
);
95 SND_ASSERT( Capabilities
);
97 SND_TRACE(L
"WDMAUD - GetWdmDeviceCapabilities\n");
99 Result
= GetSoundDeviceType(SoundDevice
, &DeviceType
);
100 SND_ASSERT( Result
== MMSYSERR_NOERROR
);
102 if ( ! MMSUCCESS(Result
) )
106 ZeroMemory(&DeviceInfo
, sizeof(WDMAUD_DEVICE_INFO
));
107 DeviceInfo
.DeviceType
= DeviceType
;
108 DeviceInfo
.DeviceIndex
= DeviceId
;
110 Result
= SyncOverlappedDeviceIoControl(KernelHandle
,
111 IOCTL_GETCAPABILITIES
,
112 (LPVOID
) &DeviceInfo
,
113 sizeof(WDMAUD_DEVICE_INFO
),
114 (LPVOID
) &DeviceInfo
,
115 sizeof(WDMAUD_DEVICE_INFO
),
118 if ( ! MMSUCCESS(Result
) )
120 return TranslateInternalMmResult(Result
);
123 SND_TRACE(L
"WDMAUD Name %S\n", DeviceInfo
.u
.WaveOutCaps
.szPname
);
125 /* This is pretty much a big hack right now */
126 switch ( DeviceType
)
128 case WAVE_OUT_DEVICE_TYPE
:
130 LPWAVEOUTCAPS WaveOutCaps
= (LPWAVEOUTCAPS
) Capabilities
;
131 WaveOutCaps
->wMid
= DeviceInfo
.u
.WaveOutCaps
.wMid
;
132 WaveOutCaps
->wPid
= DeviceInfo
.u
.WaveOutCaps
.wPid
;
134 WaveOutCaps
->vDriverVersion
= 0x0001;
135 CopyWideString(WaveOutCaps
->szPname
, DeviceInfo
.u
.WaveOutCaps
.szPname
);
137 WaveOutCaps
->dwFormats
= DeviceInfo
.u
.WaveOutCaps
.dwFormats
;
138 WaveOutCaps
->wChannels
= DeviceInfo
.u
.WaveOutCaps
.wChannels
;
139 WaveOutCaps
->dwSupport
= DeviceInfo
.u
.WaveOutCaps
.dwSupport
;
142 case WAVE_IN_DEVICE_TYPE
:
144 LPWAVEINCAPS WaveInCaps
= (LPWAVEINCAPS
) Capabilities
;
145 CopyWideString(WaveInCaps
->szPname
, DeviceInfo
.u
.WaveOutCaps
.szPname
);
146 /* TODO... other fields */
151 return MMSYSERR_NOERROR
;
157 IN
struct _SOUND_DEVICE
* SoundDevice
, /* NOT USED */
160 /* Only open this if it's not already open */
161 if ( KernelHandle
== INVALID_HANDLE_VALUE
)
163 SND_TRACE(L
"Opening wdmaud device\n");
164 KernelHandle
= CreateFileW(KERNEL_DEVICE_NAME
,
165 GENERIC_READ
| GENERIC_WRITE
,
169 FILE_FLAG_OVERLAPPED
,
173 if ( KernelHandle
== INVALID_HANDLE_VALUE
)
174 return MMSYSERR_ERROR
;
176 SND_ASSERT( Handle
);
178 *Handle
= KernelHandle
;
181 return MMSYSERR_NOERROR
;
186 IN
struct _SOUND_DEVICE_INSTANCE
* SoundDeviceInstance
,
189 WDMAUD_DEVICE_INFO DeviceInfo
;
191 MMDEVICE_TYPE DeviceType
;
192 PSOUND_DEVICE SoundDevice
;
194 Result
= GetSoundDeviceFromInstance(SoundDeviceInstance
, &SoundDevice
);
196 if ( ! MMSUCCESS(Result
) )
198 return TranslateInternalMmResult(Result
);
201 if ( OpenCount
== 0 )
203 return MMSYSERR_NOERROR
;
206 SND_ASSERT( KernelHandle
!= INVALID_HANDLE_VALUE
);
208 Result
= GetSoundDeviceType(SoundDevice
, &DeviceType
);
209 SND_ASSERT( Result
== MMSYSERR_NOERROR
);
211 if (SoundDeviceInstance
->Handle
!= (PVOID
)KernelHandle
)
213 ZeroMemory(&DeviceInfo
, sizeof(WDMAUD_DEVICE_INFO
));
215 DeviceInfo
.DeviceType
= DeviceType
;
216 DeviceInfo
.hDevice
= SoundDeviceInstance
->Handle
;
218 /* First stop the stream */
219 if (DeviceType
!= MIXER_DEVICE_TYPE
)
221 DeviceInfo
.u
.State
= KSSTATE_STOP
;
222 SyncOverlappedDeviceIoControl(KernelHandle
,
223 IOCTL_SETDEVICE_STATE
,
224 (LPVOID
) &DeviceInfo
,
225 sizeof(WDMAUD_DEVICE_INFO
),
226 (LPVOID
) &DeviceInfo
,
227 sizeof(WDMAUD_DEVICE_INFO
),
231 SyncOverlappedDeviceIoControl(KernelHandle
,
233 (LPVOID
) &DeviceInfo
,
234 sizeof(WDMAUD_DEVICE_INFO
),
235 (LPVOID
) &DeviceInfo
,
236 sizeof(WDMAUD_DEVICE_INFO
),
244 CloseHandle(KernelHandle
);
245 KernelHandle
= INVALID_HANDLE_VALUE
;
248 return MMSYSERR_NOERROR
;
253 QueryWdmWaveDeviceFormatSupport(
254 IN PSOUND_DEVICE Device
,
255 IN PWAVEFORMATEX WaveFormat
,
256 IN DWORD WaveFormatSize
)
259 return MMSYSERR_NOERROR
;
264 SetWdmMixerDeviceFormat(
265 IN PSOUND_DEVICE_INSTANCE Instance
,
267 IN PWAVEFORMATEX WaveFormat
,
268 IN DWORD WaveFormatSize
)
271 PSOUND_DEVICE SoundDevice
;
273 WDMAUD_DEVICE_INFO DeviceInfo
;
274 MMDEVICE_TYPE DeviceType
;
276 Result
= GetSoundDeviceFromInstance(Instance
, &SoundDevice
);
278 if ( ! MMSUCCESS(Result
) )
280 return TranslateInternalMmResult(Result
);
283 Result
= GetSoundDeviceIdentifier(SoundDevice
, &Identifier
);
285 if ( ! MMSUCCESS(Result
) )
287 return TranslateInternalMmResult(Result
);
290 if (Instance
->Handle
!= KernelHandle
)
292 /* device is already open */
293 return MMSYSERR_NOERROR
;
297 Result
= GetSoundDeviceType(SoundDevice
, &DeviceType
);
298 SND_ASSERT( Result
== MMSYSERR_NOERROR
);
300 ZeroMemory(&DeviceInfo
, sizeof(WDMAUD_DEVICE_INFO
));
301 DeviceInfo
.DeviceType
= DeviceType
;
302 DeviceInfo
.DeviceIndex
= DeviceId
;
304 Result
= SyncOverlappedDeviceIoControl(KernelHandle
,
306 (LPVOID
) &DeviceInfo
,
307 sizeof(WDMAUD_DEVICE_INFO
),
308 (LPVOID
) &DeviceInfo
,
309 sizeof(WDMAUD_DEVICE_INFO
),
312 if ( ! MMSUCCESS(Result
) )
314 return TranslateInternalMmResult(Result
);
317 /* Store sound device handle instance handle */
318 Instance
->Handle
= (PVOID
)DeviceInfo
.hDevice
;
320 return MMSYSERR_NOERROR
;
324 SetWdmWaveDeviceFormat(
325 IN PSOUND_DEVICE_INSTANCE Instance
,
327 IN PWAVEFORMATEX WaveFormat
,
328 IN DWORD WaveFormatSize
)
331 PSOUND_DEVICE SoundDevice
;
333 WDMAUD_DEVICE_INFO DeviceInfo
;
334 MMDEVICE_TYPE DeviceType
;
336 Result
= GetSoundDeviceFromInstance(Instance
, &SoundDevice
);
338 if ( ! MMSUCCESS(Result
) )
340 return TranslateInternalMmResult(Result
);
343 Result
= GetSoundDeviceIdentifier(SoundDevice
, &Identifier
);
345 if ( ! MMSUCCESS(Result
) )
347 return TranslateInternalMmResult(Result
);
350 if (Instance
->Handle
!= KernelHandle
)
352 /* device is already open */
353 return MMSYSERR_NOERROR
;
357 Result
= GetSoundDeviceType(SoundDevice
, &DeviceType
);
358 SND_ASSERT( Result
== MMSYSERR_NOERROR
);
360 ZeroMemory(&DeviceInfo
, sizeof(WDMAUD_DEVICE_INFO
));
361 DeviceInfo
.DeviceType
= DeviceType
;
362 DeviceInfo
.DeviceIndex
= DeviceId
;
363 DeviceInfo
.u
.WaveFormatEx
.cbSize
= WaveFormat
->cbSize
;
364 DeviceInfo
.u
.WaveFormatEx
.wFormatTag
= WaveFormat
->wFormatTag
;
365 #ifdef USERMODE_MIXER
366 DeviceInfo
.u
.WaveFormatEx
.nChannels
= 2;
367 DeviceInfo
.u
.WaveFormatEx
.nSamplesPerSec
= 44100;
368 DeviceInfo
.u
.WaveFormatEx
.nBlockAlign
= 4;
369 DeviceInfo
.u
.WaveFormatEx
.nAvgBytesPerSec
= 176400;
370 DeviceInfo
.u
.WaveFormatEx
.wBitsPerSample
= 16;
372 DeviceInfo
.u
.WaveFormatEx
.nChannels
= WaveFormat
->nChannels
;
373 DeviceInfo
.u
.WaveFormatEx
.nSamplesPerSec
= WaveFormat
->nSamplesPerSec
;
374 DeviceInfo
.u
.WaveFormatEx
.nBlockAlign
= WaveFormat
->nBlockAlign
;
375 DeviceInfo
.u
.WaveFormatEx
.nAvgBytesPerSec
= WaveFormat
->nAvgBytesPerSec
;
376 DeviceInfo
.u
.WaveFormatEx
.wBitsPerSample
= WaveFormat
->wBitsPerSample
;
379 Result
= SyncOverlappedDeviceIoControl(KernelHandle
,
381 (LPVOID
) &DeviceInfo
,
382 sizeof(WDMAUD_DEVICE_INFO
),
383 (LPVOID
) &DeviceInfo
,
384 sizeof(WDMAUD_DEVICE_INFO
),
387 if ( ! MMSUCCESS(Result
) )
389 return TranslateInternalMmResult(Result
);
393 Instance
->WaveFormatEx
.cbSize
= WaveFormat
->cbSize
;
394 Instance
->WaveFormatEx
.wFormatTag
= WaveFormat
->wFormatTag
;
395 Instance
->WaveFormatEx
.nChannels
= WaveFormat
->nChannels
;
396 Instance
->WaveFormatEx
.nSamplesPerSec
= WaveFormat
->nSamplesPerSec
;
397 Instance
->WaveFormatEx
.nBlockAlign
= WaveFormat
->nBlockAlign
;
398 Instance
->WaveFormatEx
.nAvgBytesPerSec
= WaveFormat
->nAvgBytesPerSec
;
399 Instance
->WaveFormatEx
.wBitsPerSample
= WaveFormat
->wBitsPerSample
;
401 /* Store sound device handle instance handle */
402 Instance
->Handle
= (PVOID
)DeviceInfo
.hDevice
;
404 /* Now determine framing requirements */
405 Result
= SyncOverlappedDeviceIoControl(KernelHandle
,
407 (LPVOID
) &DeviceInfo
,
408 sizeof(WDMAUD_DEVICE_INFO
),
409 (LPVOID
) &DeviceInfo
,
410 sizeof(WDMAUD_DEVICE_INFO
),
413 if ( MMSUCCESS(Result
) )
415 if (DeviceInfo
.u
.FrameSize
)
417 //Instance->FrameSize = DeviceInfo.u.FrameSize;
418 Instance
->BufferCount
= WaveFormat
->nAvgBytesPerSec
/ Instance
->FrameSize
;
419 SND_TRACE(L
"FrameSize %u BufferCount %u\n", Instance
->FrameSize
, Instance
->BufferCount
);
423 /* Now start the stream */
424 DeviceInfo
.u
.State
= KSSTATE_RUN
;
425 SyncOverlappedDeviceIoControl(KernelHandle
,
426 IOCTL_SETDEVICE_STATE
,
427 (LPVOID
) &DeviceInfo
,
428 sizeof(WDMAUD_DEVICE_INFO
),
429 (LPVOID
) &DeviceInfo
,
430 sizeof(WDMAUD_DEVICE_INFO
),
433 return MMSYSERR_NOERROR
;
437 WriteFileEx_Committer2(
438 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance
,
441 IN PSOUND_OVERLAPPED Overlap
,
442 IN LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine
)
445 WDMAUD_DEVICE_INFO DeviceInfo
;
448 VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance
);
449 VALIDATE_MMSYS_PARAMETER( OffsetPtr
);
450 VALIDATE_MMSYS_PARAMETER( Overlap
);
451 VALIDATE_MMSYS_PARAMETER( CompletionRoutine
);
453 GetSoundDeviceInstanceHandle(SoundDeviceInstance
, &Handle
);
457 ZeroMemory(&DeviceInfo
, sizeof(WDMAUD_DEVICE_INFO
));
458 DeviceInfo
.Header
.FrameExtent
= Length
;
459 DeviceInfo
.Header
.DataUsed
= Length
;
460 DeviceInfo
.Header
.Data
= OffsetPtr
;
461 DeviceInfo
.Header
.Size
= sizeof(KSSTREAM_HEADER
);
462 DeviceInfo
.Header
.PresentationTime
.Numerator
= 1;
463 DeviceInfo
.Header
.PresentationTime
.Denominator
= 1;
464 DeviceInfo
.hDevice
= Handle
;
465 DeviceInfo
.DeviceType
= WAVE_OUT_DEVICE_TYPE
; //FIXME
467 Overlap
->Standard
.hEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
469 if ( ! WriteFileEx(KernelHandle
, &DeviceInfo
, sizeof(WDMAUD_DEVICE_INFO
), (LPOVERLAPPED
)Overlap
, CompletionRoutine
))
471 SND_TRACE(L
"WriteFileEx failed with %x\n", GetLastError());
475 WaitForSingleObjectEx (KernelHandle
, INFINITE
, TRUE
);
479 return MMSYSERR_NOERROR
;
484 IN
struct _SOUND_DEVICE_INSTANCE
* SoundDeviceInstance
,
488 PSOUND_DEVICE SoundDevice
;
489 WDMAUD_DEVICE_INFO DeviceInfo
;
490 MMDEVICE_TYPE DeviceType
;
493 Result
= GetSoundDeviceFromInstance(SoundDeviceInstance
, &SoundDevice
);
495 if ( ! MMSUCCESS(Result
) )
497 return TranslateInternalMmResult(Result
);
500 Result
= GetSoundDeviceType(SoundDevice
, &DeviceType
);
501 SND_ASSERT( Result
== MMSYSERR_NOERROR
);
503 Result
= GetSoundDeviceInstanceHandle(SoundDeviceInstance
, &Handle
);
504 SND_ASSERT( Result
== MMSYSERR_NOERROR
);
506 ZeroMemory(&DeviceInfo
, sizeof(WDMAUD_DEVICE_INFO
));
507 DeviceInfo
.hDevice
= Handle
;
508 DeviceInfo
.DeviceType
= DeviceType
;
510 Result
= SyncOverlappedDeviceIoControl(KernelHandle
,
512 (LPVOID
) &DeviceInfo
,
513 sizeof(WDMAUD_DEVICE_INFO
),
514 (LPVOID
) &DeviceInfo
,
515 sizeof(WDMAUD_DEVICE_INFO
),
518 if ( ! MMSUCCESS(Result
) )
520 return TranslateInternalMmResult(Result
);
523 Time
->wType
= TIME_BYTES
;
524 Time
->u
.cb
= (DWORD
)DeviceInfo
.u
.Position
;
526 return MMSYSERR_NOERROR
;
531 PopulateWdmDeviceList(
533 MMDEVICE_TYPE DeviceType
)
536 DWORD DeviceCount
= 0;
537 PSOUND_DEVICE SoundDevice
= NULL
;
538 MMFUNCTION_TABLE FuncTable
;
541 VALIDATE_MMSYS_PARAMETER( Handle
!= INVALID_HANDLE_VALUE
);
542 VALIDATE_MMSYS_PARAMETER( IS_VALID_SOUND_DEVICE_TYPE(DeviceType
) );
544 Result
= GetNumWdmDevs(Handle
, DeviceType
, &DeviceCount
);
546 if ( ! MMSUCCESS(Result
) )
548 SND_ERR(L
"Error %d while obtaining number of devices\n", Result
);
549 return TranslateInternalMmResult(Result
);
552 SND_TRACE(L
"%d devices of type %d found\n", DeviceCount
, DeviceType
);
555 for ( i
= 0; i
< DeviceCount
; ++ i
)
557 Result
= ListSoundDevice(DeviceType
, (PVOID
) i
, &SoundDevice
);
559 if ( ! MMSUCCESS(Result
) )
561 SND_ERR(L
"Failed to list sound device - error %d\n", Result
);
562 return TranslateInternalMmResult(Result
);
565 /* Set up our function table */
566 ZeroMemory(&FuncTable
, sizeof(MMFUNCTION_TABLE
));
567 FuncTable
.GetCapabilities
= GetWdmDeviceCapabilities
;
568 FuncTable
.QueryWaveFormatSupport
= QueryWdmWaveDeviceFormatSupport
;
569 if (DeviceType
== MIXER_DEVICE_TYPE
)
571 FuncTable
.SetWaveFormat
= SetWdmMixerDeviceFormat
;
575 FuncTable
.SetWaveFormat
= SetWdmWaveDeviceFormat
;
578 FuncTable
.Open
= OpenWdmSoundDevice
;
579 FuncTable
.Close
= CloseWdmSoundDevice
;
580 #ifndef USERMODE_MIXER
581 FuncTable
.CommitWaveBuffer
= WriteFileEx_Committer2
;
583 FuncTable
.CommitWaveBuffer
= WriteFileEx_Remixer
;
585 FuncTable
.GetPos
= GetWdmPosition
;
587 SetSoundDeviceFunctionTable(SoundDevice
, &FuncTable
);
590 return MMSYSERR_NOERROR
;
611 SND_TRACE(L
"DRV_LOAD\n");
613 Result
= InitEntrypointMutexes();
615 if ( ! MMSUCCESS(Result
) )
618 OpenWdmSoundDevice(NULL
, &Handle
);
620 if ( Handle
== INVALID_HANDLE_VALUE
)
622 SND_ERR(L
"Failed to open %s\n", KERNEL_DEVICE_NAME
);
623 CleanupEntrypointMutexes();
625 //UnlistAllSoundDevices();
630 /* Populate the device lists */
631 SND_TRACE(L
"Populating device lists\n");
632 PopulateWdmDeviceList(KernelHandle
, WAVE_OUT_DEVICE_TYPE
);
633 PopulateWdmDeviceList(KernelHandle
, WAVE_IN_DEVICE_TYPE
);
634 PopulateWdmDeviceList(KernelHandle
, MIDI_OUT_DEVICE_TYPE
);
635 PopulateWdmDeviceList(KernelHandle
, MIDI_IN_DEVICE_TYPE
);
636 PopulateWdmDeviceList(KernelHandle
, AUX_DEVICE_TYPE
);
637 PopulateWdmDeviceList(KernelHandle
, MIXER_DEVICE_TYPE
);
639 SND_TRACE(L
"Initialisation complete\n");
646 SND_TRACE(L
"DRV_FREE\n");
648 if ( KernelHandle
!= INVALID_HANDLE_VALUE
)
650 CloseHandle(KernelHandle
);
651 KernelHandle
= INVALID_HANDLE_VALUE
;
654 /* TODO: Clean up the path names! */
655 UnlistAllSoundDevices();
657 CleanupEntrypointMutexes();
659 SND_TRACE(L
"Unfreed memory blocks: %d\n",
660 GetMemoryAllocationCount());
668 SND_TRACE(L
"DRV_ENABLE / DRV_DISABLE\n");
675 SND_TRACE(L
"DRV_OPEN / DRV_CLOSE\n");
679 case DRV_QUERYCONFIGURE
:
681 SND_TRACE(L
"DRV_QUERYCONFIGURE\n");
688 SND_TRACE(L
"Unhandled message %d\n", Message
);
689 return DefDriverProc(DriverId
,
705 case DLL_PROCESS_ATTACH
:
706 SND_TRACE(L
"WDMAUD.DRV - Process attached\n");
708 case DLL_PROCESS_DETACH
:
709 SND_TRACE(L
"WDMAUD.DRV - Process detached\n");
711 case DLL_THREAD_ATTACH
:
712 SND_TRACE(L
"WDMAUD.DRV - Thread attached\n");
714 case DLL_THREAD_DETACH
:
715 SND_TRACE(L
"WDMAUD.DRV - Thread detached\n");