Closing of wave output devices is functional and terminates the sound thread
[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"\\\\Device\\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 ( ! Result )
61 {
62 *DeviceCount = 0;
63 return TranslateInternalMmResult(Result);
64 }
65
66 *DeviceCount = DeviceInfo.DeviceCount;
67
68 return MMSYSERR_NOERROR;
69 }
70
71 MMRESULT
72 GetWdmDeviceCapabilities(
73 IN PSOUND_DEVICE SoundDevice,
74 OUT PVOID Capabilities,
75 IN DWORD CapabilitiesSize)
76 {
77 /* NOTE - At this time, WDMAUD does not support this properly */
78
79 MMRESULT Result;
80 MMDEVICE_TYPE DeviceType;
81
82 SND_ASSERT( SoundDevice );
83 SND_ASSERT( Capabilities );
84
85 SND_TRACE(L"WDMAUD - GetWdmDeviceCapabilities\n");
86
87 Result = GetSoundDeviceType(SoundDevice, &DeviceType);
88 SND_ASSERT( Result == MMSYSERR_NOERROR );
89
90 if ( ! MMSUCCESS(Result) )
91 return Result;
92
93 /* This is pretty much a big hack right now */
94 switch ( DeviceType )
95 {
96 case WAVE_OUT_DEVICE_TYPE :
97 {
98 LPWAVEOUTCAPS WaveOutCaps = (LPWAVEOUTCAPS) Capabilities;
99 WaveOutCaps->wMid = 0;
100 WaveOutCaps->wPid = 0;
101 WaveOutCaps->vDriverVersion = 0x0001;
102 CopyWideString(WaveOutCaps->szPname, UnknownWaveOut);
103
104 /* HACK: We may not really support all formats! */
105 WaveOutCaps->dwFormats = 0xffffffff;
106 WaveOutCaps->wChannels = 2;
107 WaveOutCaps->dwSupport = 0;
108 break;
109 }
110 case WAVE_IN_DEVICE_TYPE :
111 {
112 LPWAVEINCAPS WaveInCaps = (LPWAVEINCAPS) Capabilities;
113 CopyWideString(WaveInCaps->szPname, UnknownWaveIn);
114 /* TODO... other fields */
115 break;
116 }
117 }
118
119 return MMSYSERR_NOERROR;
120 }
121
122
123 MMRESULT
124 OpenWdmSoundDevice(
125 IN struct _SOUND_DEVICE* SoundDevice, /* NOT USED */
126 OUT PVOID* Handle)
127 {
128 /* Only open this if it's not already open */
129 if ( KernelHandle == INVALID_HANDLE_VALUE )
130 {
131 KernelHandle = CreateFile(KERNEL_DEVICE_NAME,
132 GENERIC_READ | GENERIC_WRITE,
133 0,
134 NULL,
135 OPEN_EXISTING,
136 FILE_FLAG_OVERLAPPED,
137 NULL);
138 }
139
140 if ( KernelHandle == INVALID_HANDLE_VALUE )
141 return MMSYSERR_ERROR;
142
143 SND_ASSERT( Handle );
144
145 *Handle = KernelHandle;
146 ++ OpenCount;
147
148 return MMSYSERR_NOERROR;
149 }
150
151 MMRESULT
152 CloseWdmSoundDevice(
153 IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance, /* NOT USED */
154 IN PVOID Handle)
155 {
156 SND_ASSERT( OpenCount > 0 );
157 SND_ASSERT( KernelHandle != INVALID_HANDLE_VALUE );
158
159 -- OpenCount;
160
161 if ( OpenCount < 1 )
162 {
163 CloseHandle(KernelHandle);
164 KernelHandle = INVALID_HANDLE_VALUE;
165 }
166
167 return MMSYSERR_NOERROR;
168 }
169
170
171 MMRESULT
172 QueryWdmWaveDeviceFormatSupport(
173 IN PSOUND_DEVICE Device,
174 IN PWAVEFORMATEX WaveFormat,
175 IN DWORD WaveFormatSize)
176 {
177 /* Whatever... */
178 return MMSYSERR_NOERROR;
179 }
180
181 MMRESULT
182 SetWdmWaveDeviceFormat(
183 IN PSOUND_DEVICE_INSTANCE Instance,
184 IN PWAVEFORMATEX WaveFormat,
185 IN DWORD WaveFormatSize)
186 {
187 MMRESULT Result;
188 PSOUND_DEVICE SoundDevice;
189 PVOID Identifier;
190 WDMAUD_DEVICE_INFO DeviceInfo;
191
192 Result = GetSoundDeviceFromInstance(Instance, &SoundDevice);
193
194 if ( ! MMSUCCESS(Result) )
195 {
196 return TranslateInternalMmResult(Result);
197 }
198
199 Result = GetSoundDeviceIdentifier(SoundDevice, &Identifier);
200
201 if ( ! MMSUCCESS(Result) )
202 {
203 return TranslateInternalMmResult(Result);
204 }
205
206 ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
207 DeviceInfo.u.WaveFormatEx.cbSize = WaveFormat->cbSize;
208 DeviceInfo.u.WaveFormatEx.wFormatTag = WaveFormat->wFormatTag;
209 DeviceInfo.u.WaveFormatEx.nChannels = WaveFormat->nChannels;
210 DeviceInfo.u.WaveFormatEx.nSamplesPerSec = WaveFormat->nSamplesPerSec;
211 DeviceInfo.u.WaveFormatEx.nBlockAlign = WaveFormat->nBlockAlign;
212 DeviceInfo.u.WaveFormatEx.nAvgBytesPerSec = WaveFormat->nAvgBytesPerSec;
213 DeviceInfo.u.WaveFormatEx.wBitsPerSample = WaveFormat->wBitsPerSample;
214
215 Result = SyncOverlappedDeviceIoControl(KernelHandle,
216 IOCTL_OPEN_WDMAUD,
217 (LPVOID) &DeviceInfo,
218 sizeof(WDMAUD_DEVICE_INFO),
219 (LPVOID) &DeviceInfo,
220 sizeof(WDMAUD_DEVICE_INFO),
221 NULL);
222
223 if ( ! MMSUCCESS(Result) )
224 {
225 return TranslateInternalMmResult(Result);
226 }
227
228 return MMSYSERR_NOERROR;
229 }
230
231
232 MMRESULT
233 PopulateWdmDeviceList(
234 HANDLE Handle,
235 MMDEVICE_TYPE DeviceType)
236 {
237 MMRESULT Result;
238 DWORD DeviceCount = 0;
239 PSOUND_DEVICE SoundDevice = NULL;
240 MMFUNCTION_TABLE FuncTable;
241 DWORD i;
242
243 VALIDATE_MMSYS_PARAMETER( Handle != INVALID_HANDLE_VALUE );
244 VALIDATE_MMSYS_PARAMETER( IS_VALID_SOUND_DEVICE_TYPE(DeviceType) );
245
246 Result = GetNumWdmDevs(Handle, DeviceType, &DeviceCount);
247
248 if ( ! MMSUCCESS(Result) )
249 {
250 SND_ERR(L"Error %d while obtaining number of devices\n", Result);
251 return TranslateInternalMmResult(Result);
252 }
253
254 SND_TRACE(L"%d devices of type %d found\n", DeviceCount, DeviceType);
255
256
257 for ( i = 0; i < DeviceCount; ++ i )
258 {
259 Result = ListSoundDevice(DeviceType, (PVOID) i, &SoundDevice);
260
261 if ( ! MMSUCCESS(Result) )
262 {
263 SND_ERR(L"Failed to list sound device - error %d\n", Result);
264 return TranslateInternalMmResult(Result);
265 }
266
267 /* Set up our function table */
268 ZeroMemory(&FuncTable, sizeof(MMFUNCTION_TABLE));
269 FuncTable.GetCapabilities = GetWdmDeviceCapabilities;
270 FuncTable.QueryWaveFormatSupport = QueryWdmWaveDeviceFormatSupport;
271 FuncTable.SetWaveFormat = SetWdmWaveDeviceFormat;
272 FuncTable.Open = OpenWdmSoundDevice;
273 FuncTable.Close = CloseWdmSoundDevice;
274 //FuncTable.CommitWaveBuffer = WriteFileEx_Committer;
275
276 SetSoundDeviceFunctionTable(SoundDevice, &FuncTable);
277 }
278
279 return MMSYSERR_NOERROR;
280 }
281
282
283
284 APIENTRY LONG
285 DriverProc(
286 DWORD DriverId,
287 HANDLE DriverHandle,
288 UINT Message,
289 LONG Parameter1,
290 LONG Parameter2)
291 {
292 MMRESULT Result;
293
294 switch ( Message )
295 {
296 case DRV_LOAD :
297 {
298 HANDLE Handle;
299 SND_TRACE(L"DRV_LOAD\n");
300
301 Result = InitEntrypointMutexes();
302
303 if ( ! MMSUCCESS(Result) )
304 return 0L;
305
306 OpenWdmSoundDevice(NULL, &Handle);
307
308 if ( Handle == INVALID_HANDLE_VALUE )
309 {
310 SND_ERR(L"Failed to open %s\n", KERNEL_DEVICE_NAME);
311 CleanupEntrypointMutexes();
312
313 //UnlistAllSoundDevices();
314
315 return 0L;
316 }
317
318 /* Populate the device lists */
319 SND_TRACE(L"Populating device lists\n");
320 PopulateWdmDeviceList(KernelHandle, WAVE_OUT_DEVICE_TYPE);
321 PopulateWdmDeviceList(KernelHandle, WAVE_IN_DEVICE_TYPE);
322 PopulateWdmDeviceList(KernelHandle, MIDI_OUT_DEVICE_TYPE);
323 PopulateWdmDeviceList(KernelHandle, MIDI_IN_DEVICE_TYPE);
324 PopulateWdmDeviceList(KernelHandle, AUX_DEVICE_TYPE);
325 PopulateWdmDeviceList(KernelHandle, MIXER_DEVICE_TYPE);
326
327 CloseWdmSoundDevice(NULL, Handle);
328
329 SND_TRACE(L"Initialisation complete\n");
330
331 return 1L;
332 }
333
334 case DRV_FREE :
335 {
336 SND_TRACE(L"DRV_FREE\n");
337
338 if ( KernelHandle != INVALID_HANDLE_VALUE )
339 {
340 CloseHandle(KernelHandle);
341 KernelHandle = INVALID_HANDLE_VALUE;
342 }
343
344 /* TODO: Clean up the path names! */
345 UnlistAllSoundDevices();
346
347 CleanupEntrypointMutexes();
348
349 SND_TRACE(L"Unfreed memory blocks: %d\n",
350 GetMemoryAllocationCount());
351
352 return 1L;
353 }
354
355 case DRV_ENABLE :
356 case DRV_DISABLE :
357 {
358 SND_TRACE(L"DRV_ENABLE / DRV_DISABLE\n");
359 return 1L;
360 }
361
362 case DRV_OPEN :
363 case DRV_CLOSE :
364 {
365 SND_TRACE(L"DRV_OPEN / DRV_CLOSE\n");
366 return 1L;
367 }
368
369 case DRV_QUERYCONFIGURE :
370 {
371 SND_TRACE(L"DRV_QUERYCONFIGURE\n");
372 return 0L;
373 }
374 case DRV_CONFIGURE :
375 return DRVCNF_OK;
376
377 default :
378 SND_TRACE(L"Unhandled message %d\n", Message);
379 return DefDriverProc(DriverId,
380 DriverHandle,
381 Message,
382 Parameter1,
383 Parameter2);
384 }
385 }
386
387
388 BOOL WINAPI DllMain(
389 HINSTANCE hinstDLL,
390 DWORD fdwReason,
391 LPVOID lpvReserved)
392 {
393 switch ( fdwReason )
394 {
395 case DLL_PROCESS_ATTACH :
396 SND_TRACE(L"WDMAUD.DRV - Process attached\n");
397 break;
398 case DLL_PROCESS_DETACH :
399 SND_TRACE(L"WDMAUD.DRV - Process detached\n");
400 break;
401 case DLL_THREAD_ATTACH :
402 SND_TRACE(L"WDMAUD.DRV - Thread attached\n");
403 break;
404 case DLL_THREAD_DETACH :
405 SND_TRACE(L"WDMAUD.DRV - Thread detached\n");
406 break;
407 }
408
409 return TRUE;
410 }