1 /*
2 * PROJECT: ReactOS Sound System "MME Buddy" Library
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: lib/drivers/sound/mmebuddy/mmewrap.c
5 *
6 * PURPOSE: Interface between MME functions and MME Buddy's own.
7 *
8 * PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
9 */
10
11 #include "precomp.h"
12
13
14 /*
15 Sets the device into running or stopped state
16 */
17
18 MMRESULT
MmeSetState(IN DWORD_PTR PrivateHandle,IN BOOL bStart)19 MmeSetState(
20 IN DWORD_PTR PrivateHandle,
21 IN BOOL bStart)
22 {
23 MMRESULT Result;
24 PMMFUNCTION_TABLE FunctionTable;
25 PSOUND_DEVICE SoundDevice;
26 PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
27 BOOL OldState;
28
29 VALIDATE_MMSYS_PARAMETER( PrivateHandle );
30 SoundDeviceInstance = (PSOUND_DEVICE_INSTANCE) PrivateHandle;
31
32 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
33
34 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
35 if ( ! MMSUCCESS(Result) )
36 return TranslateInternalMmResult(Result);
37
38 /* Get the function table, and validate it */
39 Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
40 if ( ! MMSUCCESS(Result) )
41 return TranslateInternalMmResult(Result);
42
43 SND_ASSERT( FunctionTable->SetState );
44 if ( FunctionTable->SetState == NULL )
45 {
46 /* FIXME */
47 return MMSYSERR_NOTSUPPORTED;
48 }
49 /* Try change state */
50 Result = FunctionTable->SetState(SoundDeviceInstance, bStart);
51
52 if ( MMSUCCESS(Result) )
53 {
54 /* Get old audio stream state */
55 OldState = SoundDeviceInstance->bPaused;
56
57 /* Store audio stream pause state */
58 SoundDeviceInstance->bPaused = !bStart;
59
60 if (SoundDeviceInstance->bPaused == FALSE && OldState)
61 {
62 InitiateSoundStreaming(SoundDeviceInstance);
63 }
64 }
65
66 return Result;
67 }
68
69 /*
70 Call the client application when something interesting happens (MME API
71 defines "interesting things" as device open, close, and buffer
72 completion.)
73 */
74 VOID
NotifyMmeClient(IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,IN UINT Message,IN DWORD_PTR Parameter)75 NotifyMmeClient(
76 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
77 IN UINT Message,
78 IN DWORD_PTR Parameter)
79 {
80 SND_ASSERT( SoundDeviceInstance );
81
82 SND_TRACE(L"MME client callback - message %d, parameter %d\n",
83 (int) Message,
84 (int) Parameter);
85
86 if ( SoundDeviceInstance->WinMM.ClientCallback )
87 {
88 DriverCallback(SoundDeviceInstance->WinMM.ClientCallback,
89 HIWORD(SoundDeviceInstance->WinMM.Flags),
90 SoundDeviceInstance->WinMM.Handle,
91 Message,
92 SoundDeviceInstance->WinMM.ClientCallbackInstanceData,
93 Parameter,
94 0);
95 }
96 }
97
98 /*
99 This is a helper function to alleviate some of the repetition involved with
100 implementing the various MME message functions.
101 */
102 MMRESULT
MmeGetSoundDeviceCapabilities(IN MMDEVICE_TYPE DeviceType,IN DWORD DeviceId,IN PVOID Capabilities,IN DWORD CapabilitiesSize)103 MmeGetSoundDeviceCapabilities(
104 IN MMDEVICE_TYPE DeviceType,
105 IN DWORD DeviceId,
106 IN PVOID Capabilities,
107 IN DWORD CapabilitiesSize)
108 {
109 PSOUND_DEVICE SoundDevice;
110 MMRESULT Result;
111
112 SND_TRACE(L"MME *_GETCAPS for device %d of type %d\n", DeviceId, DeviceType);
113
114 /* FIXME: Validate device ID */
115 VALIDATE_MMSYS_PARAMETER( Capabilities );
116 VALIDATE_MMSYS_PARAMETER( IS_VALID_SOUND_DEVICE_TYPE(DeviceType) );
117
118 /* Our parameter checks are done elsewhere */
119
120 Result = GetSoundDevice(DeviceType, DeviceId, &SoundDevice);
121
122 if ( ! MMSUCCESS(Result) )
123 return Result;
124
125 return GetSoundDeviceCapabilities(SoundDevice,
126 DeviceId,
127 Capabilities,
128 CapabilitiesSize);
129 }
130
131 MMRESULT
MmeOpenDevice(IN MMDEVICE_TYPE DeviceType,IN UINT DeviceId,IN LPWAVEOPENDESC OpenParameters,IN DWORD Flags,OUT DWORD_PTR * PrivateHandle)132 MmeOpenDevice(
133 IN MMDEVICE_TYPE DeviceType,
134 IN UINT DeviceId,
135 IN LPWAVEOPENDESC OpenParameters,
136 IN DWORD Flags,
137 OUT DWORD_PTR* PrivateHandle)
138 {
139 MMRESULT Result;
140 UINT Message;
141 PSOUND_DEVICE SoundDevice;
142 PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
143 LPWAVEFORMATEX Format = NULL;
144
145 SND_TRACE(L"Opening device\n");
146
147 VALIDATE_MMSYS_PARAMETER( IS_WAVE_DEVICE_TYPE(DeviceType) || IS_MIXER_DEVICE_TYPE(DeviceType) || IS_MIDI_DEVICE_TYPE(DeviceType) ); /* FIXME? wave in too? */
148 VALIDATE_MMSYS_PARAMETER( OpenParameters );
149
150 Result = GetSoundDevice(DeviceType, DeviceId, &SoundDevice);
151 if ( ! MMSUCCESS(Result) )
152 return TranslateInternalMmResult(Result);
153
154 if (DeviceType == WAVE_IN_DEVICE_TYPE || DeviceType == WAVE_OUT_DEVICE_TYPE)
155 {
156 Format = OpenParameters->lpFormat;
157
158 /* Does this device support the format? */
159 Result = QueryWaveDeviceFormatSupport(SoundDevice, Format, sizeof(WAVEFORMATEX));
160 if ( ! MMSUCCESS(Result) )
161 {
162 SND_ERR(L"Format not supported\n");
163 return TranslateInternalMmResult(Result);
164 }
165
166 /* If the caller just wanted to know if a format is supported, end here */
167 if ( Flags & WAVE_FORMAT_QUERY )
168 return MMSYSERR_NOERROR;
169 }
170
171 /* Check that winmm gave us a private handle to fill */
172 VALIDATE_MMSYS_PARAMETER( PrivateHandle );
173
174 /* Create a sound device instance and open the sound device */
175 Result = CreateSoundDeviceInstance(SoundDevice, &SoundDeviceInstance);
176 if ( ! MMSUCCESS(Result) )
177 return TranslateInternalMmResult(Result);
178
179 Result = SetWaveDeviceFormat(SoundDeviceInstance, DeviceId, Format, sizeof(WAVEFORMATEX));
180 if ( ! MMSUCCESS(Result) )
181 {
182 /* TODO: Destroy sound instance */
183 return TranslateInternalMmResult(Result);
184 }
185
186 /* Store the device instance pointer in the private handle */
187 *PrivateHandle = (DWORD_PTR)SoundDeviceInstance;
188
189 /* Store the additional information we were given - FIXME: Need flags! */
190 SetSoundDeviceInstanceMmeData(SoundDeviceInstance,
191 (HDRVR)OpenParameters->hWave, /* works because LPMIXEROPENDESC/etc has also the handle as first member */
192 OpenParameters->dwCallback,
193 OpenParameters->dwInstance,
194 Flags);
195
196 if (DeviceType == WAVE_OUT_DEVICE_TYPE || DeviceType == WAVE_IN_DEVICE_TYPE ||
197 DeviceType == MIDI_OUT_DEVICE_TYPE || DeviceType == MIDI_IN_DEVICE_TYPE)
198 {
199 /* Let the application know the device is open */
200
201 if (DeviceType == WAVE_OUT_DEVICE_TYPE)
202 Message = WOM_OPEN;
203 else if (DeviceType == WAVE_IN_DEVICE_TYPE)
204 Message = WIM_OPEN;
205 else if (DeviceType == MIDI_IN_DEVICE_TYPE)
206 Message = MIM_OPEN;
207 else
208 Message = MOM_OPEN;
209
210 ReleaseEntrypointMutex(DeviceType);
211
212 NotifyMmeClient(SoundDeviceInstance,
213 Message,
214 0);
215
216 AcquireEntrypointMutex(DeviceType);
217 }
218
219 SND_TRACE(L"device now open\n");
220
221 return MMSYSERR_NOERROR;
222 }
223
224 MMRESULT
MmeCloseDevice(IN DWORD_PTR PrivateHandle)225 MmeCloseDevice(
226 IN DWORD_PTR PrivateHandle)
227 {
228 MMRESULT Result;
229 PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
230 PSOUND_DEVICE SoundDevice;
231 MMDEVICE_TYPE DeviceType;
232 UINT Message = 0;
233
234 SND_TRACE(L"Closing wave device (WIDM_CLOSE / WODM_CLOSE)\n");
235
236 VALIDATE_MMSYS_PARAMETER( PrivateHandle );
237 SoundDeviceInstance = (PSOUND_DEVICE_INSTANCE) PrivateHandle;
238
239 if ( ! IsValidSoundDeviceInstance(SoundDeviceInstance) )
240 return MMSYSERR_INVALHANDLE;
241
242 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
243 if ( ! MMSUCCESS(Result) )
244 return TranslateInternalMmResult(Result);
245
246 Result = GetSoundDeviceType(SoundDevice, &DeviceType);
247 if ( ! MMSUCCESS(Result) )
248 return TranslateInternalMmResult(Result);
249
250
251 /* TODO: Check device is stopped! */
252
253
254 if (DeviceType != MIXER_DEVICE_TYPE)
255 {
256 ReleaseEntrypointMutex(DeviceType);
257
258 if (DeviceType == WAVE_OUT_DEVICE_TYPE)
259 Message = WOM_CLOSE;
260 else if (DeviceType == WAVE_IN_DEVICE_TYPE)
261 Message = WIM_CLOSE;
262 else if (DeviceType == MIDI_IN_DEVICE_TYPE)
263 Message = MIM_CLOSE;
264 else if (DeviceType == MIDI_OUT_DEVICE_TYPE)
265 Message = MOM_CLOSE;
266
267 /* TODO: Work with MIDI devices too */
268 NotifyMmeClient(SoundDeviceInstance,
269 Message,
270 0);
271 AcquireEntrypointMutex(DeviceType);
272 }
273
274 Result = DestroySoundDeviceInstance(SoundDeviceInstance);
275
276 return Result;
277 }
278
279 MMRESULT
MmeResetWavePlayback(IN DWORD_PTR PrivateHandle)280 MmeResetWavePlayback(
281 IN DWORD_PTR PrivateHandle)
282 {
283 PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
284
285 SND_TRACE(L"Resetting wave device (WODM_RESET)\n");
286
287 VALIDATE_MMSYS_PARAMETER( PrivateHandle );
288 SoundDeviceInstance = (PSOUND_DEVICE_INSTANCE) PrivateHandle;
289
290 return StopStreaming(SoundDeviceInstance);
291 }
292
293 MMRESULT
MmeGetDeviceInterfaceString(IN MMDEVICE_TYPE DeviceType,IN DWORD DeviceId,IN LPWSTR Interface,IN DWORD InterfaceLength,OUT DWORD * InterfaceSize)294 MmeGetDeviceInterfaceString(
295 IN MMDEVICE_TYPE DeviceType,
296 IN DWORD DeviceId,
297 IN LPWSTR Interface,
298 IN DWORD InterfaceLength,
299 OUT DWORD * InterfaceSize)
300 {
301 MMRESULT Result;
302 PSOUND_DEVICE SoundDevice;
303 PMMFUNCTION_TABLE FunctionTable;
304
305 Result = GetSoundDevice(DeviceType, DeviceId, &SoundDevice);
306 if ( ! MMSUCCESS(Result) )
307 return TranslateInternalMmResult(Result);
308
309 Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
310 if ( ! MMSUCCESS(Result) )
311 return TranslateInternalMmResult(Result);
312
313 if ( FunctionTable->GetDeviceInterfaceString == NULL )
314 {
315 /* querying device interface string / size not supported */
316 return MMSYSERR_NOTSUPPORTED;
317 }
318
319 /* Call the driver */
320 Result = FunctionTable->GetDeviceInterfaceString(DeviceType, DeviceId, Interface, InterfaceLength, InterfaceSize);
321
322 return Result;
323 }
324
325
326 MMRESULT
MmeGetPosition(IN MMDEVICE_TYPE DeviceType,IN DWORD DeviceId,IN DWORD_PTR PrivateHandle,IN MMTIME * Time,IN DWORD Size)327 MmeGetPosition(
328 IN MMDEVICE_TYPE DeviceType,
329 IN DWORD DeviceId,
330 IN DWORD_PTR PrivateHandle,
331 IN MMTIME* Time,
332 IN DWORD Size)
333 {
334 MMRESULT Result;
335 PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
336 PSOUND_DEVICE SoundDevice;
337 PMMFUNCTION_TABLE FunctionTable;
338
339 VALIDATE_MMSYS_PARAMETER( PrivateHandle );
340 SoundDeviceInstance = (PSOUND_DEVICE_INSTANCE) PrivateHandle;
341
342 if ( ! IsValidSoundDeviceInstance(SoundDeviceInstance) )
343 return MMSYSERR_INVALHANDLE;
344
345 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
346 if ( ! MMSUCCESS(Result) )
347 return TranslateInternalMmResult(Result);
348
349 if ( Size != sizeof(MMTIME) )
350 return MMSYSERR_INVALPARAM;
351
352 Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
353 if ( ! MMSUCCESS(Result) )
354 return TranslateInternalMmResult(Result);
355
356 if ( FunctionTable->GetPos == NULL )
357 {
358 /* This indicates bad practice, really! If you can open, why not close?! */
359 return MMSYSERR_NOTSUPPORTED;
360 }
361
362 /* Call the driver */
363 Result = FunctionTable->GetPos(SoundDeviceInstance, Time);
364
365 return Result;
366 }
367
368 MMRESULT
MmeGetVolume(_In_ MMDEVICE_TYPE DeviceType,_In_ DWORD DeviceId,_In_ DWORD_PTR PrivateHandle,_Out_ DWORD_PTR pdwVolume)369 MmeGetVolume(
370 _In_ MMDEVICE_TYPE DeviceType,
371 _In_ DWORD DeviceId,
372 _In_ DWORD_PTR PrivateHandle,
373 _Out_ DWORD_PTR pdwVolume)
374 {
375 MMRESULT Result;
376 PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
377 PSOUND_DEVICE SoundDevice;
378 PMMFUNCTION_TABLE FunctionTable;
379
380 /* Sanity check */
381 SND_ASSERT(DeviceType == AUX_DEVICE_TYPE ||
382 DeviceType == MIDI_OUT_DEVICE_TYPE ||
383 DeviceType == WAVE_OUT_DEVICE_TYPE);
384
385 VALIDATE_MMSYS_PARAMETER(PrivateHandle);
386 SoundDeviceInstance = (PSOUND_DEVICE_INSTANCE)PrivateHandle;
387
388 if (!IsValidSoundDeviceInstance(SoundDeviceInstance))
389 return MMSYSERR_INVALHANDLE;
390
391 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
392 if (!MMSUCCESS(Result))
393 return TranslateInternalMmResult(Result);
394
395 Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
396 if (!MMSUCCESS(Result))
397 return TranslateInternalMmResult(Result);
398
399 if (!FunctionTable->GetVolume)
400 return MMSYSERR_NOTSUPPORTED;
401
402 /* Call the driver */
403 Result = FunctionTable->GetVolume(SoundDeviceInstance, DeviceId, (PDWORD)pdwVolume);
404
405 return Result;
406 }
407
408 MMRESULT
MmeSetVolume(_In_ MMDEVICE_TYPE DeviceType,_In_ DWORD DeviceId,_In_ DWORD_PTR PrivateHandle,_In_ DWORD_PTR dwVolume)409 MmeSetVolume(
410 _In_ MMDEVICE_TYPE DeviceType,
411 _In_ DWORD DeviceId,
412 _In_ DWORD_PTR PrivateHandle,
413 _In_ DWORD_PTR dwVolume)
414 {
415 MMRESULT Result;
416 PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
417 PSOUND_DEVICE SoundDevice;
418 PMMFUNCTION_TABLE FunctionTable;
419
420 /* Sanity check */
421 SND_ASSERT(DeviceType == AUX_DEVICE_TYPE ||
422 DeviceType == MIDI_OUT_DEVICE_TYPE ||
423 DeviceType == WAVE_OUT_DEVICE_TYPE);
424
425 VALIDATE_MMSYS_PARAMETER(PrivateHandle);
426 SoundDeviceInstance = (PSOUND_DEVICE_INSTANCE)PrivateHandle;
427
428 if (!IsValidSoundDeviceInstance(SoundDeviceInstance))
429 return MMSYSERR_INVALHANDLE;
430
431 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
432 if (!MMSUCCESS(Result))
433 return TranslateInternalMmResult(Result);
434
435 Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
436 if (!MMSUCCESS(Result))
437 return TranslateInternalMmResult(Result);
438
439 if (!FunctionTable->SetVolume)
440 return MMSYSERR_NOTSUPPORTED;
441
442 /* Call the driver */
443 Result = FunctionTable->SetVolume(SoundDeviceInstance, DeviceId, (DWORD)dwVolume);
444
445 return Result;
446 }
447