Sync to trunk head (r42241)
[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 Call the client application when something interesting happens (MME API
20 defines "interesting things" as device open, close, and buffer
21 completion.)
22 */
23 VOID
24 NotifyMmeClient(
25 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
26 IN UINT Message,
27 IN DWORD_PTR Parameter)
28 {
29 SND_ASSERT( SoundDeviceInstance );
30
31 SND_TRACE(L"MME client callback - message %d, parameter %d\n",
32 (int) Message,
33 (int) Parameter);
34
35 if ( SoundDeviceInstance->WinMM.ClientCallback )
36 {
37 DriverCallback(SoundDeviceInstance->WinMM.ClientCallback,
38 HIWORD(SoundDeviceInstance->WinMM.Flags),
39 SoundDeviceInstance->WinMM.Handle,
40 Message,
41 SoundDeviceInstance->WinMM.ClientCallbackInstanceData,
42 Parameter,
43 0);
44 }
45 }
46
47 /*
48 This is a helper function to alleviate some of the repetition involved with
49 implementing the various MME message functions.
50 */
51 MMRESULT
52 MmeGetSoundDeviceCapabilities(
53 IN MMDEVICE_TYPE DeviceType,
54 IN DWORD DeviceId,
55 IN DWORD_PTR Capabilities,
56 IN DWORD CapabilitiesSize)
57 {
58 PSOUND_DEVICE SoundDevice;
59 MMRESULT Result;
60
61 SND_TRACE(L"MME *_GETCAPS for device %d of type %d\n", DeviceId, DeviceType);
62
63 /* FIXME: Validate device ID */
64 VALIDATE_MMSYS_PARAMETER( Capabilities );
65 VALIDATE_MMSYS_PARAMETER( IS_VALID_SOUND_DEVICE_TYPE(DeviceType) );
66
67 /* Our parameter checks are done elsewhere */
68
69 Result = GetSoundDevice(DeviceType, DeviceId, &SoundDevice);
70
71 if ( ! MMSUCCESS(Result) )
72 return Result;
73
74 return GetSoundDeviceCapabilities(SoundDevice,
75 DeviceId,
76 Capabilities,
77 CapabilitiesSize);
78 }
79
80 MMRESULT
81 MmeOpenWaveDevice(
82 IN MMDEVICE_TYPE DeviceType,
83 IN UINT DeviceId,
84 IN LPWAVEOPENDESC OpenParameters,
85 IN DWORD Flags,
86 OUT SIZE_T* PrivateHandle)
87 {
88 MMRESULT Result;
89
90 PSOUND_DEVICE SoundDevice;
91 PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
92 LPWAVEFORMATEX Format;
93
94 SND_TRACE(L"Opening wave device (WIDM_OPEN / WODM_OPEN)");
95
96 VALIDATE_MMSYS_PARAMETER( IS_WAVE_DEVICE_TYPE(DeviceType) ); /* FIXME? wave in too? */
97 VALIDATE_MMSYS_PARAMETER( OpenParameters );
98
99 Format = OpenParameters->lpFormat;
100
101 Result = GetSoundDevice(DeviceType, DeviceId, &SoundDevice);
102 if ( ! MMSUCCESS(Result) )
103 return TranslateInternalMmResult(Result);
104
105 /* Does this device support the format? */
106 Result = QueryWaveDeviceFormatSupport(SoundDevice, Format, sizeof(WAVEFORMATEX));
107 if ( ! MMSUCCESS(Result) )
108 {
109 SND_ERR(L"Format not supported\n");
110 return TranslateInternalMmResult(Result);
111 }
112
113 /* If the caller just wanted to know if a format is supported, end here */
114 if ( Flags & WAVE_FORMAT_QUERY )
115 return MMSYSERR_NOERROR;
116
117 /* Check that winmm gave us a private handle to fill */
118 VALIDATE_MMSYS_PARAMETER( PrivateHandle );
119
120 /* Create a sound device instance and open the sound device */
121 Result = CreateSoundDeviceInstance(SoundDevice, &SoundDeviceInstance);
122 if ( ! MMSUCCESS(Result) )
123 return TranslateInternalMmResult(Result);
124
125 Result = SetWaveDeviceFormat(SoundDeviceInstance, DeviceId, Format, sizeof(WAVEFORMATEX));
126 if ( ! MMSUCCESS(Result) )
127 {
128 /* TODO: Destroy sound instance */
129 return TranslateInternalMmResult(Result);
130 }
131
132 /* Store the device instance pointer in the private handle */
133 *PrivateHandle = (DWORD_PTR)SoundDeviceInstance;
134
135 /* Store the additional information we were given - FIXME: Need flags! */
136 SetSoundDeviceInstanceMmeData(SoundDeviceInstance,
137 (HDRVR)OpenParameters->hWave,
138 OpenParameters->dwCallback,
139 OpenParameters->dwInstance,
140 Flags);
141
142 /* Let the application know the device is open */
143 ReleaseEntrypointMutex(DeviceType);
144 NotifyMmeClient(SoundDeviceInstance,
145 DeviceType == WAVE_OUT_DEVICE_TYPE ? WOM_OPEN : WIM_OPEN,
146 0);
147
148 AcquireEntrypointMutex(DeviceType);
149
150 SND_TRACE(L"Wave device now open\n");
151
152 return MMSYSERR_NOERROR;
153 }
154
155 MMRESULT
156 MmeCloseDevice(
157 IN SIZE_T PrivateHandle)
158 {
159 MMRESULT Result;
160 PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
161 PSOUND_DEVICE SoundDevice;
162 MMDEVICE_TYPE DeviceType;
163
164 SND_TRACE(L"Closing wave device (WIDM_CLOSE / WODM_CLOSE)\n");
165
166 VALIDATE_MMSYS_PARAMETER( PrivateHandle );
167 SoundDeviceInstance = (PSOUND_DEVICE_INSTANCE) PrivateHandle;
168
169 if ( ! IsValidSoundDeviceInstance(SoundDeviceInstance) )
170 return MMSYSERR_INVALHANDLE;
171
172 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
173 if ( ! MMSUCCESS(Result) )
174 return TranslateInternalMmResult(Result);
175
176 Result = GetSoundDeviceType(SoundDevice, &DeviceType);
177 if ( ! MMSUCCESS(Result) )
178 return TranslateInternalMmResult(Result);
179
180
181 /* TODO: Check device is stopped! */
182
183 ReleaseEntrypointMutex(DeviceType);
184 /* TODO: Work with MIDI devices too */
185 NotifyMmeClient(SoundDeviceInstance,
186 DeviceType == WAVE_OUT_DEVICE_TYPE ? WOM_CLOSE : WIM_CLOSE,
187 0);
188 AcquireEntrypointMutex(DeviceType);
189
190 Result = DestroySoundDeviceInstance(SoundDeviceInstance);
191
192 return Result;
193 }
194
195 MMRESULT
196 MmeResetWavePlayback(
197 IN SIZE_T PrivateHandle)
198 {
199 PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
200
201 SND_TRACE(L"Resetting wave device (WODM_RESET)\n");
202
203 VALIDATE_MMSYS_PARAMETER( PrivateHandle );
204 SoundDeviceInstance = (PSOUND_DEVICE_INSTANCE) PrivateHandle;
205
206 return StopStreaming(SoundDeviceInstance);
207 }
208
209 MMRESULT
210 MmeGetPosition(
211 IN MMDEVICE_TYPE DeviceType,
212 IN DWORD DeviceId,
213 IN DWORD PrivateHandle,
214 IN MMTIME* Time,
215 IN DWORD Size)
216 {
217 MMRESULT Result;
218 PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
219 PSOUND_DEVICE SoundDevice;
220 PMMFUNCTION_TABLE FunctionTable;
221
222 VALIDATE_MMSYS_PARAMETER( PrivateHandle );
223 SoundDeviceInstance = (PSOUND_DEVICE_INSTANCE) PrivateHandle;
224
225 if ( ! IsValidSoundDeviceInstance(SoundDeviceInstance) )
226 return MMSYSERR_INVALHANDLE;
227
228 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
229 if ( ! MMSUCCESS(Result) )
230 return TranslateInternalMmResult(Result);
231
232 if ( Size != sizeof(MMTIME) )
233 return MMSYSERR_INVALPARAM;
234
235 Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
236 if ( ! MMSUCCESS(Result) )
237 return TranslateInternalMmResult(Result);
238
239 if ( FunctionTable->GetPos == NULL )
240 {
241 /* This indicates bad practice, really! If you can open, why not close?! */
242 return MMSYSERR_NOTSUPPORTED;
243 }
244
245 /* Call the driver */
246 Result = FunctionTable->GetPos(SoundDeviceInstance, Time);
247
248 return Result;
249 }
250