- Implement retrieving position
[reactos.git] / reactos / dll / win32 / wdmaud.drv / wdmaud.c
1 /*
2 * PROJECT: ReactOS Sound System
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/wdmaud.drv/wdmaud.c
5 *
6 * PURPOSE: WDM Audio Driver (User-mode part)
7 * PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
8 *
9 * NOTES: Looking for wodMessage & co? You won't find them here. Try
10 * the MME Buddy library, which is where these routines are
11 * actually implemented.
12 *
13 */
14
15 #include <windows.h>
16 #include <ntddsnd.h>
17 #include <sndtypes.h>
18 #include <mmddk.h>
19 #include <mmebuddy.h>
20
21 #include <ks.h>
22 #include <ksmedia.h>
23 #include "interface.h"
24
25 #define KERNEL_DEVICE_NAME L"\\\\.\\wdmaud"
26
27 PWSTR UnknownWaveIn = L"Wave Input";
28 PWSTR UnknownWaveOut = L"Wave Output";
29 PWSTR UnknownMidiIn = L"Midi Input";
30 PWSTR UnknownMidiOut = L"Midi Output";
31
32 HANDLE KernelHandle = INVALID_HANDLE_VALUE;
33 DWORD OpenCount = 0;
34
35
36 MMRESULT
37 GetNumWdmDevs(
38 IN HANDLE Handle,
39 IN MMDEVICE_TYPE DeviceType,
40 OUT DWORD* DeviceCount)
41 {
42 MMRESULT Result;
43 WDMAUD_DEVICE_INFO DeviceInfo;
44
45 VALIDATE_MMSYS_PARAMETER( Handle != INVALID_HANDLE_VALUE );
46 VALIDATE_MMSYS_PARAMETER( IS_VALID_SOUND_DEVICE_TYPE(DeviceType) );
47 VALIDATE_MMSYS_PARAMETER( DeviceCount );
48
49 ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
50 DeviceInfo.DeviceType = DeviceType;
51
52 Result = SyncOverlappedDeviceIoControl(Handle,
53 IOCTL_GETNUMDEVS_TYPE,
54 (LPVOID) &DeviceInfo,
55 sizeof(WDMAUD_DEVICE_INFO),
56 (LPVOID) &DeviceInfo,
57 sizeof(WDMAUD_DEVICE_INFO),
58 NULL);
59
60 if ( ! MMSUCCESS( Result ) )
61 {
62 SND_ERR(L"Call to IOCTL_GETNUMDEVS_TYPE failed\n");
63 *DeviceCount = 0;
64 return TranslateInternalMmResult(Result);
65 }
66
67 *DeviceCount = DeviceInfo.DeviceCount;
68
69 return MMSYSERR_NOERROR;
70 }
71
72 MMRESULT
73 GetWdmDeviceCapabilities(
74 IN PSOUND_DEVICE SoundDevice,
75 OUT PVOID Capabilities,
76 IN DWORD CapabilitiesSize)
77 {
78 /* NOTE - At this time, WDMAUD does not support this properly */
79
80 MMRESULT Result;
81 MMDEVICE_TYPE DeviceType;
82 WDMAUD_DEVICE_INFO DeviceInfo;
83
84 SND_ASSERT( SoundDevice );
85 SND_ASSERT( Capabilities );
86
87 SND_TRACE(L"WDMAUD - GetWdmDeviceCapabilities\n");
88
89 Result = GetSoundDeviceType(SoundDevice, &DeviceType);
90 SND_ASSERT( Result == MMSYSERR_NOERROR );
91
92 if ( ! MMSUCCESS(Result) )
93 return Result;
94
95
96 ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
97 DeviceInfo.DeviceType = DeviceType;
98 DeviceInfo.DeviceIndex = 0; //FIXME
99
100 Result = SyncOverlappedDeviceIoControl(KernelHandle,
101 IOCTL_GETCAPABILITIES,
102 (LPVOID) &DeviceInfo,
103 sizeof(WDMAUD_DEVICE_INFO),
104 (LPVOID) &DeviceInfo,
105 sizeof(WDMAUD_DEVICE_INFO),
106 NULL);
107
108 if ( ! MMSUCCESS(Result) )
109 {
110 return TranslateInternalMmResult(Result);
111 }
112
113
114 /* This is pretty much a big hack right now */
115 switch ( DeviceType )
116 {
117 case WAVE_OUT_DEVICE_TYPE :
118 {
119 LPWAVEOUTCAPS WaveOutCaps = (LPWAVEOUTCAPS) Capabilities;
120 WaveOutCaps->wMid = DeviceInfo.u.WaveOutCaps.wMid;
121 WaveOutCaps->wPid = DeviceInfo.u.WaveOutCaps.wPid;
122
123 WaveOutCaps->vDriverVersion = 0x0001;
124 CopyWideString(WaveOutCaps->szPname, UnknownWaveOut);
125
126 WaveOutCaps->dwFormats = DeviceInfo.u.WaveOutCaps.dwFormats;
127 WaveOutCaps->wChannels = DeviceInfo.u.WaveOutCaps.wChannels;
128 WaveOutCaps->dwSupport = DeviceInfo.u.WaveOutCaps.dwSupport;
129 break;
130 }
131 case WAVE_IN_DEVICE_TYPE :
132 {
133 LPWAVEINCAPS WaveInCaps = (LPWAVEINCAPS) Capabilities;
134 CopyWideString(WaveInCaps->szPname, UnknownWaveIn);
135 /* TODO... other fields */
136 break;
137 }
138 }
139
140 return MMSYSERR_NOERROR;
141 }
142
143
144 MMRESULT
145 OpenWdmSoundDevice(
146 IN struct _SOUND_DEVICE* SoundDevice, /* NOT USED */
147 OUT PVOID* Handle)
148 {
149 /* Only open this if it's not already open */
150 if ( KernelHandle == INVALID_HANDLE_VALUE )
151 {
152 SND_TRACE(L"Opening wdmaud device\n");
153 KernelHandle = CreateFileW(KERNEL_DEVICE_NAME,
154 GENERIC_READ | GENERIC_WRITE,
155 0,
156 NULL,
157 OPEN_EXISTING,
158 FILE_FLAG_OVERLAPPED,
159 NULL);
160 }
161
162 if ( KernelHandle == INVALID_HANDLE_VALUE )
163 return MMSYSERR_ERROR;
164
165 SND_ASSERT( Handle );
166
167 *Handle = KernelHandle;
168 ++ OpenCount;
169
170 return MMSYSERR_NOERROR;
171 }
172
173 MMRESULT
174 CloseWdmSoundDevice(
175 IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
176 IN PVOID Handle)
177 {
178 WDMAUD_DEVICE_INFO DeviceInfo;
179 MMRESULT Result;
180 MMDEVICE_TYPE DeviceType;
181 PSOUND_DEVICE SoundDevice;
182
183 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
184
185 if ( ! MMSUCCESS(Result) )
186 {
187 return TranslateInternalMmResult(Result);
188 }
189
190 if ( OpenCount == 0 )
191 {
192 return MMSYSERR_NOERROR;
193 }
194
195 SND_ASSERT( KernelHandle != INVALID_HANDLE_VALUE );
196
197 Result = GetSoundDeviceType(SoundDevice, &DeviceType);
198 SND_ASSERT( Result == MMSYSERR_NOERROR );
199
200 if (SoundDeviceInstance->Handle != (PVOID)KernelHandle)
201 {
202 ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
203
204 DeviceInfo.DeviceType = DeviceType;
205 DeviceInfo.hDevice = SoundDeviceInstance->Handle;
206
207 SyncOverlappedDeviceIoControl(KernelHandle,
208 IOCTL_CLOSE_WDMAUD,
209 (LPVOID) &DeviceInfo,
210 sizeof(WDMAUD_DEVICE_INFO),
211 (LPVOID) &DeviceInfo,
212 sizeof(WDMAUD_DEVICE_INFO),
213 NULL);
214 }
215
216 --OpenCount;
217
218 if ( OpenCount < 1 )
219 {
220 CloseHandle(KernelHandle);
221 KernelHandle = INVALID_HANDLE_VALUE;
222 }
223
224 return MMSYSERR_NOERROR;
225 }
226
227
228 MMRESULT
229 QueryWdmWaveDeviceFormatSupport(
230 IN PSOUND_DEVICE Device,
231 IN PWAVEFORMATEX WaveFormat,
232 IN DWORD WaveFormatSize)
233 {
234 /* Whatever... */
235 return MMSYSERR_NOERROR;
236 }
237
238 MMRESULT
239 SetWdmWaveDeviceFormat(
240 IN PSOUND_DEVICE_INSTANCE Instance,
241 IN DWORD DeviceId,
242 IN PWAVEFORMATEX WaveFormat,
243 IN DWORD WaveFormatSize)
244 {
245 MMRESULT Result;
246 PSOUND_DEVICE SoundDevice;
247 PVOID Identifier;
248 WDMAUD_DEVICE_INFO DeviceInfo;
249 MMDEVICE_TYPE DeviceType;
250
251 Result = GetSoundDeviceFromInstance(Instance, &SoundDevice);
252
253 if ( ! MMSUCCESS(Result) )
254 {
255 return TranslateInternalMmResult(Result);
256 }
257
258 Result = GetSoundDeviceIdentifier(SoundDevice, &Identifier);
259
260 if ( ! MMSUCCESS(Result) )
261 {
262 return TranslateInternalMmResult(Result);
263 }
264
265 if (Instance->Handle != KernelHandle)
266 {
267 /* device is already open */
268 return MMSYSERR_NOERROR;
269 }
270
271
272 Result = GetSoundDeviceType(SoundDevice, &DeviceType);
273 SND_ASSERT( Result == MMSYSERR_NOERROR );
274
275 ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
276 DeviceInfo.DeviceType = DeviceType;
277 DeviceInfo.DeviceIndex = DeviceId;
278 DeviceInfo.u.WaveFormatEx.cbSize = WaveFormat->cbSize;
279 DeviceInfo.u.WaveFormatEx.wFormatTag = WaveFormat->wFormatTag;
280 DeviceInfo.u.WaveFormatEx.nChannels = WaveFormat->nChannels;
281 DeviceInfo.u.WaveFormatEx.nSamplesPerSec = WaveFormat->nSamplesPerSec;
282 DeviceInfo.u.WaveFormatEx.nBlockAlign = WaveFormat->nBlockAlign;
283 DeviceInfo.u.WaveFormatEx.nAvgBytesPerSec = WaveFormat->nAvgBytesPerSec;
284 DeviceInfo.u.WaveFormatEx.wBitsPerSample = WaveFormat->wBitsPerSample;
285
286 Result = SyncOverlappedDeviceIoControl(KernelHandle,
287 IOCTL_OPEN_WDMAUD,
288 (LPVOID) &DeviceInfo,
289 sizeof(WDMAUD_DEVICE_INFO),
290 (LPVOID) &DeviceInfo,
291 sizeof(WDMAUD_DEVICE_INFO),
292 NULL);
293
294 if ( ! MMSUCCESS(Result) )
295 {
296 return TranslateInternalMmResult(Result);
297 }
298
299 Instance->Handle = (PVOID)DeviceInfo.hDevice;
300
301 return MMSYSERR_NOERROR;
302 }
303
304 MMRESULT
305 WriteFileEx_Committer2(
306 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
307 IN PVOID OffsetPtr,
308 IN DWORD Length,
309 IN PSOUND_OVERLAPPED Overlap,
310 IN LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine)
311 {
312 HANDLE Handle;
313 WDMAUD_DEVICE_INFO DeviceInfo;
314
315
316 VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance );
317 VALIDATE_MMSYS_PARAMETER( OffsetPtr );
318 VALIDATE_MMSYS_PARAMETER( Overlap );
319 VALIDATE_MMSYS_PARAMETER( CompletionRoutine );
320
321 GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle);
322
323 SND_ASSERT(Handle);
324
325 ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
326 DeviceInfo.hDevice = Handle;
327 DeviceInfo.DeviceType = WAVE_OUT_DEVICE_TYPE; //FIXME
328 DeviceInfo.Buffer = OffsetPtr;
329 DeviceInfo.BufferSize = Length;
330
331 Overlap->Standard.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
332
333 if ( ! WriteFileEx(KernelHandle, &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPOVERLAPPED)Overlap, CompletionRoutine))
334 {
335 SND_TRACE(L"WriteFileEx failed with %x\n", GetLastError());
336 }
337 else
338 {
339 WaitForSingleObjectEx (KernelHandle, INFINITE, TRUE);
340
341 }
342
343 return MMSYSERR_NOERROR;
344 }
345
346 MMRESULT
347 GetWdmPosition(
348 IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
349 IN MMTIME* Time)
350 {
351 MMRESULT Result;
352 PSOUND_DEVICE SoundDevice;
353 WDMAUD_DEVICE_INFO DeviceInfo;
354 MMDEVICE_TYPE DeviceType;
355 HANDLE Handle;
356
357 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
358
359 if ( ! MMSUCCESS(Result) )
360 {
361 return TranslateInternalMmResult(Result);
362 }
363
364 Result = GetSoundDeviceType(SoundDevice, &DeviceType);
365 SND_ASSERT( Result == MMSYSERR_NOERROR );
366
367 Result = GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle);
368 SND_ASSERT( Result == MMSYSERR_NOERROR );
369
370 ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
371 DeviceInfo.hDevice = Handle;
372 DeviceInfo.DeviceType = DeviceType;
373
374 Result = SyncOverlappedDeviceIoControl(KernelHandle,
375 IOCTL_OPEN_WDMAUD,
376 (LPVOID) &DeviceInfo,
377 sizeof(WDMAUD_DEVICE_INFO),
378 (LPVOID) &DeviceInfo,
379 sizeof(WDMAUD_DEVICE_INFO),
380 NULL);
381
382 if ( ! MMSUCCESS(Result) )
383 {
384 return TranslateInternalMmResult(Result);
385 }
386
387 Time->wType = TIME_BYTES;
388 Time->u.cb = (DWORD)DeviceInfo.u.Position;
389
390 return MMSYSERR_NOERROR;
391 }
392
393
394 MMRESULT
395 PopulateWdmDeviceList(
396 HANDLE Handle,
397 MMDEVICE_TYPE DeviceType)
398 {
399 MMRESULT Result;
400 DWORD DeviceCount = 0;
401 PSOUND_DEVICE SoundDevice = NULL;
402 MMFUNCTION_TABLE FuncTable;
403 DWORD i;
404
405 VALIDATE_MMSYS_PARAMETER( Handle != INVALID_HANDLE_VALUE );
406 VALIDATE_MMSYS_PARAMETER( IS_VALID_SOUND_DEVICE_TYPE(DeviceType) );
407
408 Result = GetNumWdmDevs(Handle, DeviceType, &DeviceCount);
409
410 if ( ! MMSUCCESS(Result) )
411 {
412 SND_ERR(L"Error %d while obtaining number of devices\n", Result);
413 return TranslateInternalMmResult(Result);
414 }
415
416 SND_TRACE(L"%d devices of type %d found\n", DeviceCount, DeviceType);
417
418
419 for ( i = 0; i < DeviceCount; ++ i )
420 {
421 Result = ListSoundDevice(DeviceType, (PVOID) i, &SoundDevice);
422
423 if ( ! MMSUCCESS(Result) )
424 {
425 SND_ERR(L"Failed to list sound device - error %d\n", Result);
426 return TranslateInternalMmResult(Result);
427 }
428
429 /* Set up our function table */
430 ZeroMemory(&FuncTable, sizeof(MMFUNCTION_TABLE));
431 FuncTable.GetCapabilities = GetWdmDeviceCapabilities;
432 FuncTable.QueryWaveFormatSupport = QueryWdmWaveDeviceFormatSupport;
433 FuncTable.SetWaveFormat = SetWdmWaveDeviceFormat;
434 FuncTable.Open = OpenWdmSoundDevice;
435 FuncTable.Close = CloseWdmSoundDevice;
436 FuncTable.CommitWaveBuffer = WriteFileEx_Committer2;
437 FuncTable.GetPos = GetWdmPosition;
438
439 SetSoundDeviceFunctionTable(SoundDevice, &FuncTable);
440 }
441
442 return MMSYSERR_NOERROR;
443 }
444
445
446
447 APIENTRY LONG
448 DriverProc(
449 DWORD DriverId,
450 HANDLE DriverHandle,
451 UINT Message,
452 LONG Parameter1,
453 LONG Parameter2)
454 {
455 MMRESULT Result;
456
457 switch ( Message )
458 {
459 case DRV_LOAD :
460 {
461 HANDLE Handle;
462 SND_TRACE(L"DRV_LOAD\n");
463
464 Result = InitEntrypointMutexes();
465
466 if ( ! MMSUCCESS(Result) )
467 return 0L;
468
469 OpenWdmSoundDevice(NULL, &Handle);
470
471 if ( Handle == INVALID_HANDLE_VALUE )
472 {
473 SND_ERR(L"Failed to open %s\n", KERNEL_DEVICE_NAME);
474 CleanupEntrypointMutexes();
475
476 //UnlistAllSoundDevices();
477
478 return 0L;
479 }
480
481 /* Populate the device lists */
482 SND_TRACE(L"Populating device lists\n");
483 PopulateWdmDeviceList(KernelHandle, WAVE_OUT_DEVICE_TYPE);
484 PopulateWdmDeviceList(KernelHandle, WAVE_IN_DEVICE_TYPE);
485 PopulateWdmDeviceList(KernelHandle, MIDI_OUT_DEVICE_TYPE);
486 PopulateWdmDeviceList(KernelHandle, MIDI_IN_DEVICE_TYPE);
487 PopulateWdmDeviceList(KernelHandle, AUX_DEVICE_TYPE);
488 PopulateWdmDeviceList(KernelHandle, MIXER_DEVICE_TYPE);
489
490 SND_TRACE(L"Initialisation complete\n");
491
492 return 1L;
493 }
494
495 case DRV_FREE :
496 {
497 SND_TRACE(L"DRV_FREE\n");
498
499 if ( KernelHandle != INVALID_HANDLE_VALUE )
500 {
501 CloseHandle(KernelHandle);
502 KernelHandle = INVALID_HANDLE_VALUE;
503 }
504
505 /* TODO: Clean up the path names! */
506 UnlistAllSoundDevices();
507
508 CleanupEntrypointMutexes();
509
510 SND_TRACE(L"Unfreed memory blocks: %d\n",
511 GetMemoryAllocationCount());
512
513 return 1L;
514 }
515
516 case DRV_ENABLE :
517 case DRV_DISABLE :
518 {
519 SND_TRACE(L"DRV_ENABLE / DRV_DISABLE\n");
520 return 1L;
521 }
522
523 case DRV_OPEN :
524 case DRV_CLOSE :
525 {
526 SND_TRACE(L"DRV_OPEN / DRV_CLOSE\n");
527 return 1L;
528 }
529
530 case DRV_QUERYCONFIGURE :
531 {
532 SND_TRACE(L"DRV_QUERYCONFIGURE\n");
533 return 0L;
534 }
535 case DRV_CONFIGURE :
536 return DRVCNF_OK;
537
538 default :
539 SND_TRACE(L"Unhandled message %d\n", Message);
540 return DefDriverProc(DriverId,
541 DriverHandle,
542 Message,
543 Parameter1,
544 Parameter2);
545 }
546 }
547
548
549 BOOL WINAPI DllMain(
550 HINSTANCE hinstDLL,
551 DWORD fdwReason,
552 LPVOID lpvReserved)
553 {
554 switch ( fdwReason )
555 {
556 case DLL_PROCESS_ATTACH :
557 SND_TRACE(L"WDMAUD.DRV - Process attached\n");
558 break;
559 case DLL_PROCESS_DETACH :
560 SND_TRACE(L"WDMAUD.DRV - Process detached\n");
561 break;
562 case DLL_THREAD_ATTACH :
563 SND_TRACE(L"WDMAUD.DRV - Thread attached\n");
564 break;
565 case DLL_THREAD_DETACH :
566 SND_TRACE(L"WDMAUD.DRV - Thread detached\n");
567 break;
568 }
569
570 return TRUE;
571 }