xref: /reactos/sdk/lib/drivers/sound/mmebuddy/mmewrap.c (revision ea291af4)
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