[MMEBUDDY]
[reactos.git] / reactos / 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 <windows.h>
12 #include <mmsystem.h>
13 #include <mmddk.h>
14 #include <ntddsnd.h>
15 #include <sndtypes.h>
16 #include <mmebuddy.h>
17
18
19 /*
20 Sets the device into running or stopped state
21 */
22
23 MMRESULT
24 MmeSetState(
25 IN DWORD_PTR PrivateHandle,
26 IN BOOL bStart)
27 {
28 MMRESULT Result;
29 PMMFUNCTION_TABLE FunctionTable;
30 PSOUND_DEVICE SoundDevice;
31 PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
32
33 VALIDATE_MMSYS_PARAMETER( PrivateHandle );
34 SoundDeviceInstance = (PSOUND_DEVICE_INSTANCE) PrivateHandle;
35
36 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
37
38 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
39 if ( ! MMSUCCESS(Result) )
40 return TranslateInternalMmResult(Result);
41
42 /* Get the function table, and validate it */
43 Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
44 if ( ! MMSUCCESS(Result) )
45 return TranslateInternalMmResult(Result);
46
47 SND_ASSERT( FunctionTable->SetState );
48 if ( FunctionTable->SetState == NULL )
49 {
50 /* FIXME */
51 return MMSYSERR_NOTSUPPORTED;
52 }
53 /* Try change state */
54 Result = FunctionTable->SetState(SoundDeviceInstance, bStart);
55
56 return Result;
57 }
58
59 /*
60 Call the client application when something interesting happens (MME API
61 defines "interesting things" as device open, close, and buffer
62 completion.)
63 */
64 VOID
65 NotifyMmeClient(
66 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
67 IN UINT Message,
68 IN DWORD_PTR Parameter)
69 {
70 SND_ASSERT( SoundDeviceInstance );
71
72 SND_TRACE(L"MME client callback - message %d, parameter %d\n",
73 (int) Message,
74 (int) Parameter);
75
76 if ( SoundDeviceInstance->WinMM.ClientCallback )
77 {
78 DriverCallback(SoundDeviceInstance->WinMM.ClientCallback,
79 HIWORD(SoundDeviceInstance->WinMM.Flags),
80 SoundDeviceInstance->WinMM.Handle,
81 Message,
82 SoundDeviceInstance->WinMM.ClientCallbackInstanceData,
83 Parameter,
84 0);
85 }
86 }
87
88 /*
89 This is a helper function to alleviate some of the repetition involved with
90 implementing the various MME message functions.
91 */
92 MMRESULT
93 MmeGetSoundDeviceCapabilities(
94 IN MMDEVICE_TYPE DeviceType,
95 IN DWORD DeviceId,
96 IN PVOID Capabilities,
97 IN DWORD CapabilitiesSize)
98 {
99 PSOUND_DEVICE SoundDevice;
100 MMRESULT Result;
101
102 SND_TRACE(L"MME *_GETCAPS for device %d of type %d\n", DeviceId, DeviceType);
103
104 /* FIXME: Validate device ID */
105 VALIDATE_MMSYS_PARAMETER( Capabilities );
106 VALIDATE_MMSYS_PARAMETER( IS_VALID_SOUND_DEVICE_TYPE(DeviceType) );
107
108 /* Our parameter checks are done elsewhere */
109
110 Result = GetSoundDevice(DeviceType, DeviceId, &SoundDevice);
111
112 if ( ! MMSUCCESS(Result) )
113 return Result;
114
115 return GetSoundDeviceCapabilities(SoundDevice,
116 DeviceId,
117 Capabilities,
118 CapabilitiesSize);
119 }
120
121 MMRESULT
122 MmeOpenDevice(
123 IN MMDEVICE_TYPE DeviceType,
124 IN UINT DeviceId,
125 IN LPWAVEOPENDESC OpenParameters,
126 IN DWORD Flags,
127 OUT DWORD_PTR* PrivateHandle)
128 {
129 MMRESULT Result;
130 UINT Message;
131 PSOUND_DEVICE SoundDevice;
132 PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
133 LPWAVEFORMATEX Format;
134
135 SND_TRACE(L"Opening device");
136
137 VALIDATE_MMSYS_PARAMETER( IS_WAVE_DEVICE_TYPE(DeviceType) ); /* FIXME? wave in too? */
138 VALIDATE_MMSYS_PARAMETER( OpenParameters );
139
140 Result = GetSoundDevice(DeviceType, DeviceId, &SoundDevice);
141 if ( ! MMSUCCESS(Result) )
142 return TranslateInternalMmResult(Result);
143
144 if (DeviceType == WAVE_IN_DEVICE_TYPE || DeviceType == WAVE_OUT_DEVICE_TYPE)
145 {
146 Format = OpenParameters->lpFormat;
147
148 /* Does this device support the format? */
149 Result = QueryWaveDeviceFormatSupport(SoundDevice, Format, sizeof(WAVEFORMATEX));
150 if ( ! MMSUCCESS(Result) )
151 {
152 SND_ERR(L"Format not supported\n");
153 return TranslateInternalMmResult(Result);
154 }
155
156 /* If the caller just wanted to know if a format is supported, end here */
157 if ( Flags & WAVE_FORMAT_QUERY )
158 return MMSYSERR_NOERROR;
159 }
160
161 /* Check that winmm gave us a private handle to fill */
162 VALIDATE_MMSYS_PARAMETER( PrivateHandle );
163
164 /* Create a sound device instance and open the sound device */
165 Result = CreateSoundDeviceInstance(SoundDevice, &SoundDeviceInstance);
166 if ( ! MMSUCCESS(Result) )
167 return TranslateInternalMmResult(Result);
168
169 Result = SetWaveDeviceFormat(SoundDeviceInstance, DeviceId, Format, sizeof(WAVEFORMATEX));
170 if ( ! MMSUCCESS(Result) )
171 {
172 /* TODO: Destroy sound instance */
173 return TranslateInternalMmResult(Result);
174 }
175
176 /* Store the device instance pointer in the private handle */
177 *PrivateHandle = (DWORD_PTR)SoundDeviceInstance;
178
179 /* Store the additional information we were given - FIXME: Need flags! */
180 SetSoundDeviceInstanceMmeData(SoundDeviceInstance,
181 (HDRVR)OpenParameters->hWave, /* works because LPMIXEROPENDESC/etc has also the handle as first member */
182 OpenParameters->dwCallback,
183 OpenParameters->dwInstance,
184 Flags);
185
186 if (DeviceType == WAVE_OUT_DEVICE_TYPE || DeviceType == WAVE_IN_DEVICE_TYPE ||
187 DeviceType == MIDI_OUT_DEVICE_TYPE || DeviceType == MIDI_IN_DEVICE_TYPE)
188 {
189 /* Let the application know the device is open */
190
191 if (DeviceType == WAVE_OUT_DEVICE_TYPE)
192 Message = WOM_OPEN;
193 else if (DeviceType == WAVE_IN_DEVICE_TYPE)
194 Message = WIM_OPEN;
195 else if (DeviceType == MIDI_IN_DEVICE_TYPE)
196 Message = MIM_OPEN;
197 else
198 Message = MOM_OPEN;
199
200 ReleaseEntrypointMutex(DeviceType);
201
202 NotifyMmeClient(SoundDeviceInstance,
203 Message,
204 0);
205
206 AcquireEntrypointMutex(DeviceType);
207 }
208
209 SND_TRACE(L"device now open\n");
210
211 return MMSYSERR_NOERROR;
212 }
213
214 MMRESULT
215 MmeCloseDevice(
216 IN DWORD_PTR PrivateHandle)
217 {
218 MMRESULT Result;
219 PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
220 PSOUND_DEVICE SoundDevice;
221 MMDEVICE_TYPE DeviceType;
222 UINT Message = 0;
223
224 SND_TRACE(L"Closing wave device (WIDM_CLOSE / WODM_CLOSE)\n");
225
226 VALIDATE_MMSYS_PARAMETER( PrivateHandle );
227 SoundDeviceInstance = (PSOUND_DEVICE_INSTANCE) PrivateHandle;
228
229 if ( ! IsValidSoundDeviceInstance(SoundDeviceInstance) )
230 return MMSYSERR_INVALHANDLE;
231
232 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
233 if ( ! MMSUCCESS(Result) )
234 return TranslateInternalMmResult(Result);
235
236 Result = GetSoundDeviceType(SoundDevice, &DeviceType);
237 if ( ! MMSUCCESS(Result) )
238 return TranslateInternalMmResult(Result);
239
240
241 /* TODO: Check device is stopped! */
242
243
244 if (DeviceType != MIXER_DEVICE_TYPE)
245 {
246 ReleaseEntrypointMutex(DeviceType);
247
248 if (DeviceType == WAVE_OUT_DEVICE_TYPE)
249 Message = WOM_CLOSE;
250 else if (DeviceType == WAVE_IN_DEVICE_TYPE)
251 Message = WIM_CLOSE;
252 else if (DeviceType == MIDI_IN_DEVICE_TYPE)
253 Message = MIM_CLOSE;
254 else if (DeviceType == MIDI_OUT_DEVICE_TYPE)
255 Message = MOM_CLOSE;
256
257 /* TODO: Work with MIDI devices too */
258 NotifyMmeClient(SoundDeviceInstance,
259 Message,
260 0);
261 AcquireEntrypointMutex(DeviceType);
262 }
263
264 Result = DestroySoundDeviceInstance(SoundDeviceInstance);
265
266 return Result;
267 }
268
269 MMRESULT
270 MmeResetWavePlayback(
271 IN DWORD_PTR PrivateHandle)
272 {
273 PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
274
275 SND_TRACE(L"Resetting wave device (WODM_RESET)\n");
276
277 VALIDATE_MMSYS_PARAMETER( PrivateHandle );
278 SoundDeviceInstance = (PSOUND_DEVICE_INSTANCE) PrivateHandle;
279
280 return StopStreaming(SoundDeviceInstance);
281 }
282
283 MMRESULT
284 MmeGetDeviceInterfaceString(
285 IN MMDEVICE_TYPE DeviceType,
286 IN DWORD DeviceId,
287 IN LPWSTR Interface,
288 IN DWORD InterfaceLength,
289 OUT DWORD * InterfaceSize)
290 {
291 MMRESULT Result;
292 PSOUND_DEVICE SoundDevice;
293 PMMFUNCTION_TABLE FunctionTable;
294
295 Result = GetSoundDevice(DeviceType, DeviceId, &SoundDevice);
296 if ( ! MMSUCCESS(Result) )
297 return TranslateInternalMmResult(Result);
298
299 Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
300 if ( ! MMSUCCESS(Result) )
301 return TranslateInternalMmResult(Result);
302
303 if ( FunctionTable->GetDeviceInterfaceString == NULL )
304 {
305 /* querying device interface string / size not supported */
306 return MMSYSERR_NOTSUPPORTED;
307 }
308
309 /* Call the driver */
310 Result = FunctionTable->GetDeviceInterfaceString(DeviceType, DeviceId, Interface, InterfaceLength, InterfaceSize);
311
312 return Result;
313 }
314
315
316 MMRESULT
317 MmeGetPosition(
318 IN MMDEVICE_TYPE DeviceType,
319 IN DWORD DeviceId,
320 IN DWORD_PTR PrivateHandle,
321 IN MMTIME* Time,
322 IN DWORD Size)
323 {
324 MMRESULT Result;
325 PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
326 PSOUND_DEVICE SoundDevice;
327 PMMFUNCTION_TABLE FunctionTable;
328
329 VALIDATE_MMSYS_PARAMETER( PrivateHandle );
330 SoundDeviceInstance = (PSOUND_DEVICE_INSTANCE) PrivateHandle;
331
332 if ( ! IsValidSoundDeviceInstance(SoundDeviceInstance) )
333 return MMSYSERR_INVALHANDLE;
334
335 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
336 if ( ! MMSUCCESS(Result) )
337 return TranslateInternalMmResult(Result);
338
339 if ( Size != sizeof(MMTIME) )
340 return MMSYSERR_INVALPARAM;
341
342 Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
343 if ( ! MMSUCCESS(Result) )
344 return TranslateInternalMmResult(Result);
345
346 if ( FunctionTable->GetPos == NULL )
347 {
348 /* This indicates bad practice, really! If you can open, why not close?! */
349 return MMSYSERR_NOTSUPPORTED;
350 }
351
352 /* Call the driver */
353 Result = FunctionTable->GetPos(SoundDeviceInstance, Time);
354
355 return Result;
356 }
357