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