- Update to r53061
[reactos.git] / lib / drivers / sound / mmebuddy / mmewrap.c
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 == TRUE)
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