Sync to trunk (r44371)
[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 DWORD Message,
68 IN DWORD 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 MmeOpenWaveDevice(
123 IN MMDEVICE_TYPE DeviceType,
124 IN DWORD DeviceId,
125 IN LPWAVEOPENDESC OpenParameters,
126 IN DWORD Flags,
127 OUT DWORD* PrivateHandle)
128 {
129 MMRESULT Result;
130
131 PSOUND_DEVICE SoundDevice;
132 PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
133 LPWAVEFORMATEX Format;
134
135 SND_TRACE(L"Opening wave device (WIDM_OPEN / WODM_OPEN)");
136
137 VALIDATE_MMSYS_PARAMETER( IS_WAVE_DEVICE_TYPE(DeviceType) ); /* FIXME? wave in too? */
138 VALIDATE_MMSYS_PARAMETER( OpenParameters );
139
140 Format = OpenParameters->lpFormat;
141
142 Result = GetSoundDevice(DeviceType, DeviceId, &SoundDevice);
143 if ( ! MMSUCCESS(Result) )
144 return TranslateInternalMmResult(Result);
145
146 /* Does this device support the format? */
147 Result = QueryWaveDeviceFormatSupport(SoundDevice, Format, sizeof(WAVEFORMATEX));
148 if ( ! MMSUCCESS(Result) )
149 {
150 SND_ERR(L"Format not supported\n");
151 return TranslateInternalMmResult(Result);
152 }
153
154 /* If the caller just wanted to know if a format is supported, end here */
155 if ( Flags & WAVE_FORMAT_QUERY )
156 return MMSYSERR_NOERROR;
157
158 /* Check that winmm gave us a private handle to fill */
159 VALIDATE_MMSYS_PARAMETER( PrivateHandle );
160
161 /* Create a sound device instance and open the sound device */
162 Result = CreateSoundDeviceInstance(SoundDevice, &SoundDeviceInstance);
163 if ( ! MMSUCCESS(Result) )
164 return TranslateInternalMmResult(Result);
165
166 Result = SetWaveDeviceFormat(SoundDeviceInstance, DeviceId, Format, sizeof(WAVEFORMATEX));
167 if ( ! MMSUCCESS(Result) )
168 {
169 /* TODO: Destroy sound instance */
170 return TranslateInternalMmResult(Result);
171 }
172
173 /* Store the device instance pointer in the private handle */
174 *PrivateHandle = (DWORD_PTR)SoundDeviceInstance;
175
176 /* Store the additional information we were given - FIXME: Need flags! */
177 SetSoundDeviceInstanceMmeData(SoundDeviceInstance,
178 (HDRVR)OpenParameters->hWave,
179 OpenParameters->dwCallback,
180 OpenParameters->dwInstance,
181 Flags);
182
183 /* Let the application know the device is open */
184 ReleaseEntrypointMutex(DeviceType);
185 NotifyMmeClient(SoundDeviceInstance,
186 DeviceType == WAVE_OUT_DEVICE_TYPE ? WOM_OPEN : WIM_OPEN,
187 0);
188
189 AcquireEntrypointMutex(DeviceType);
190
191 SND_TRACE(L"Wave device now open\n");
192
193 return MMSYSERR_NOERROR;
194 }
195
196 MMRESULT
197 MmeCloseDevice(
198 IN DWORD_PTR PrivateHandle)
199 {
200 MMRESULT Result;
201 PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
202 PSOUND_DEVICE SoundDevice;
203 MMDEVICE_TYPE DeviceType;
204
205 SND_TRACE(L"Closing wave device (WIDM_CLOSE / WODM_CLOSE)\n");
206
207 VALIDATE_MMSYS_PARAMETER( PrivateHandle );
208 SoundDeviceInstance = (PSOUND_DEVICE_INSTANCE) PrivateHandle;
209
210 if ( ! IsValidSoundDeviceInstance(SoundDeviceInstance) )
211 return MMSYSERR_INVALHANDLE;
212
213 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
214 if ( ! MMSUCCESS(Result) )
215 return TranslateInternalMmResult(Result);
216
217 Result = GetSoundDeviceType(SoundDevice, &DeviceType);
218 if ( ! MMSUCCESS(Result) )
219 return TranslateInternalMmResult(Result);
220
221
222 /* TODO: Check device is stopped! */
223
224 ReleaseEntrypointMutex(DeviceType);
225 /* TODO: Work with MIDI devices too */
226 NotifyMmeClient(SoundDeviceInstance,
227 DeviceType == WAVE_OUT_DEVICE_TYPE ? WOM_CLOSE : WIM_CLOSE,
228 0);
229 AcquireEntrypointMutex(DeviceType);
230
231 Result = DestroySoundDeviceInstance(SoundDeviceInstance);
232
233 return Result;
234 }
235
236 MMRESULT
237 MmeResetWavePlayback(
238 IN DWORD_PTR PrivateHandle)
239 {
240 PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
241
242 SND_TRACE(L"Resetting wave device (WODM_RESET)\n");
243
244 VALIDATE_MMSYS_PARAMETER( PrivateHandle );
245 SoundDeviceInstance = (PSOUND_DEVICE_INSTANCE) PrivateHandle;
246
247 return StopStreaming(SoundDeviceInstance);
248 }
249
250 MMRESULT
251 MmeGetDeviceInterfaceString(
252 IN MMDEVICE_TYPE DeviceType,
253 IN DWORD DeviceId,
254 IN LPWSTR Interface,
255 IN DWORD InterfaceLength,
256 OUT DWORD * InterfaceSize)
257 {
258 MMRESULT Result;
259 PSOUND_DEVICE SoundDevice;
260 PMMFUNCTION_TABLE FunctionTable;
261
262 Result = GetSoundDevice(DeviceType, DeviceId, &SoundDevice);
263 if ( ! MMSUCCESS(Result) )
264 return TranslateInternalMmResult(Result);
265
266 Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
267 if ( ! MMSUCCESS(Result) )
268 return TranslateInternalMmResult(Result);
269
270 if ( FunctionTable->GetDeviceInterfaceString == NULL )
271 {
272 /* querying device interface string / size not supported */
273 return MMSYSERR_NOTSUPPORTED;
274 }
275
276 /* Call the driver */
277 Result = FunctionTable->GetDeviceInterfaceString(DeviceType, DeviceId, Interface, InterfaceLength, InterfaceSize);
278
279 return Result;
280 }
281
282
283 MMRESULT
284 MmeGetPosition(
285 IN MMDEVICE_TYPE DeviceType,
286 IN DWORD DeviceId,
287 IN DWORD_PTR PrivateHandle,
288 IN MMTIME* Time,
289 IN DWORD Size)
290 {
291 MMRESULT Result;
292 PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
293 PSOUND_DEVICE SoundDevice;
294 PMMFUNCTION_TABLE FunctionTable;
295
296 VALIDATE_MMSYS_PARAMETER( PrivateHandle );
297 SoundDeviceInstance = (PSOUND_DEVICE_INSTANCE) PrivateHandle;
298
299 if ( ! IsValidSoundDeviceInstance(SoundDeviceInstance) )
300 return MMSYSERR_INVALHANDLE;
301
302 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
303 if ( ! MMSUCCESS(Result) )
304 return TranslateInternalMmResult(Result);
305
306 if ( Size != sizeof(MMTIME) )
307 return MMSYSERR_INVALPARAM;
308
309 Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
310 if ( ! MMSUCCESS(Result) )
311 return TranslateInternalMmResult(Result);
312
313 if ( FunctionTable->GetPos == NULL )
314 {
315 /* This indicates bad practice, really! If you can open, why not close?! */
316 return MMSYSERR_NOTSUPPORTED;
317 }
318
319 /* Call the driver */
320 Result = FunctionTable->GetPos(SoundDeviceInstance, Time);
321
322 return Result;
323 }
324