64dcbff55318d68c9b910ecee12e749a14fc4e1b
[reactos.git] / reactos / lib / drivers / sound / mmebuddy / deviceinstance.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/deviceinstance.c
5 *
6 * PURPOSE: Manages instances of sound devices.
7 *
8 * PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
9 */
10
11 #include <windows.h>
12 #include <mmsystem.h>
13 #include <mmddk.h>
14 #include <mmebuddy.h>
15
16 MMRESULT
17 AllocateSoundDeviceInstance(
18 OUT PSOUND_DEVICE_INSTANCE* SoundDeviceInstance)
19 {
20 PSOUND_DEVICE_INSTANCE NewInstance;
21
22 VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance );
23
24 /* Allocate memory for the new instance */
25 NewInstance = AllocateStruct(SOUND_DEVICE_INSTANCE);
26
27 if ( ! NewInstance )
28 return MMSYSERR_NOMEM;
29
30 /* Provide the caller with the new instance pointer */
31 *SoundDeviceInstance = NewInstance;
32
33 return MMSYSERR_NOERROR;
34 }
35
36 VOID
37 FreeSoundDeviceInstance(
38 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
39 {
40 /* This won't work as the device is no longer valid by this point! */
41 /*SND_ASSERT( IsValidSoundDeviceInstance(SoundDeviceInstance) );*/
42 ZeroMemory(SoundDeviceInstance, sizeof(SOUND_DEVICE_INSTANCE));
43 FreeMemory(SoundDeviceInstance);
44 }
45
46 BOOLEAN
47 IsValidSoundDeviceInstance(
48 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
49 {
50 PSOUND_DEVICE SoundDevice;
51 PSOUND_DEVICE_INSTANCE CurrentInstance;
52
53 if ( ! SoundDeviceInstance )
54 return FALSE;
55
56 /* GetSoundDeviceFromInstance would send us into a recursive loop... */
57 SoundDevice = SoundDeviceInstance->Device;
58 SND_ASSERT(SoundDevice);
59
60 CurrentInstance = SoundDevice->HeadInstance;
61
62 while ( CurrentInstance )
63 {
64 if ( CurrentInstance == SoundDeviceInstance )
65 return TRUE;
66
67 CurrentInstance = CurrentInstance->Next;
68 }
69
70 return FALSE;
71 }
72
73 MMRESULT
74 ListSoundDeviceInstance(
75 IN PSOUND_DEVICE SoundDevice,
76 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
77 {
78 VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice) );
79 VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance );
80
81 SND_TRACE(L"Listing sound device instance\n");
82
83 if ( ! SoundDevice->HeadInstance )
84 {
85 /* First entry - assign to head and tail */
86 SoundDevice->HeadInstance = SoundDeviceInstance;
87 SoundDevice->TailInstance = SoundDeviceInstance;
88 }
89 else
90 {
91 /* Attach to the end */
92 SoundDevice->TailInstance->Next = SoundDeviceInstance;
93 SoundDevice->TailInstance = SoundDeviceInstance;
94 }
95
96 return MMSYSERR_NOERROR;
97 }
98
99 MMRESULT
100 UnlistSoundDeviceInstance(
101 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
102 {
103 MMRESULT Result;
104 PSOUND_DEVICE SoundDevice;
105 PSOUND_DEVICE_INSTANCE CurrentInstance, PreviousInstance;
106
107 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
108
109 SND_TRACE(L"Unlisting sound device instance\n");
110
111 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
112 SND_ASSERT( MMSUCCESS(Result) );
113
114 PreviousInstance = NULL;
115 CurrentInstance = SoundDevice->HeadInstance;
116
117 while ( CurrentInstance )
118 {
119 if ( CurrentInstance == SoundDeviceInstance )
120 {
121 if ( ! PreviousInstance )
122 {
123 /* This is the head node */
124 SoundDevice->HeadInstance = SoundDevice->HeadInstance->Next;
125 }
126 else
127 {
128 /* There are nodes before this one - cut ours out */
129 PreviousInstance->Next = CurrentInstance->Next;
130 }
131
132 if ( ! CurrentInstance->Next )
133 {
134 /* This is the tail node */
135 SoundDevice->TailInstance = PreviousInstance;
136 }
137 }
138
139 PreviousInstance = CurrentInstance;
140 CurrentInstance = CurrentInstance->Next;
141 }
142
143 return MMSYSERR_NOERROR;
144 }
145
146 MMRESULT
147 CreateSoundDeviceInstance(
148 IN PSOUND_DEVICE SoundDevice,
149 OUT PSOUND_DEVICE_INSTANCE* SoundDeviceInstance)
150 {
151 MMRESULT Result;
152 PMMFUNCTION_TABLE FunctionTable;
153
154 SND_TRACE(L"Creating a sound device instance\n");
155
156 VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice) );
157 VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance != NULL );
158
159 Result = AllocateSoundDeviceInstance(SoundDeviceInstance);
160
161 if ( ! MMSUCCESS(Result) )
162 return TranslateInternalMmResult(Result);
163
164 /* Get the "open" routine from the function table, and validate it */
165 Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
166 if ( ! MMSUCCESS(Result) )
167 {
168 FreeSoundDeviceInstance(*SoundDeviceInstance);
169 return TranslateInternalMmResult(Result);
170 }
171
172 if ( FunctionTable->Open == NULL )
173 {
174 FreeSoundDeviceInstance(*SoundDeviceInstance);
175 return MMSYSERR_NOTSUPPORTED;
176 }
177
178 /* Set up the members of the structure */
179 (*SoundDeviceInstance)->Next = NULL;
180 (*SoundDeviceInstance)->Device = SoundDevice;
181 (*SoundDeviceInstance)->Handle = NULL;
182 (*SoundDeviceInstance)->Thread = NULL;
183
184 (*SoundDeviceInstance)->WinMM.Handle = INVALID_HANDLE_VALUE;
185 (*SoundDeviceInstance)->WinMM.ClientCallback = 0;
186 (*SoundDeviceInstance)->WinMM.ClientCallbackInstanceData = 0;
187 (*SoundDeviceInstance)->WinMM.Flags = 0;
188
189 /* Create the streaming thread (TODO - is this for wave only?) */
190 Result = CreateSoundThread(&(*SoundDeviceInstance)->Thread);
191 if ( ! MMSUCCESS(Result) )
192 {
193 FreeSoundDeviceInstance(*SoundDeviceInstance);
194 return TranslateInternalMmResult(Result);
195 }
196
197 /* Add the instance to the list */
198 Result = ListSoundDeviceInstance(SoundDevice, *SoundDeviceInstance);
199 if ( ! MMSUCCESS(Result) )
200 {
201 FreeSoundDeviceInstance(*SoundDeviceInstance);
202 return TranslateInternalMmResult(Result);
203 }
204
205 /* Try and open the device */
206 Result = FunctionTable->Open(SoundDevice, (&(*SoundDeviceInstance)->Handle));
207 if ( ! MMSUCCESS(Result) )
208 {
209 UnlistSoundDeviceInstance(*SoundDeviceInstance);
210 FreeSoundDeviceInstance(*SoundDeviceInstance);
211 return TranslateInternalMmResult(Result);
212 }
213
214 return MMSYSERR_NOERROR;
215 }
216
217 MMRESULT
218 DestroySoundDeviceInstance(
219 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
220 {
221 MMRESULT Result;
222 PMMFUNCTION_TABLE FunctionTable;
223 PSOUND_DEVICE SoundDevice;
224 PVOID Handle;
225
226 SND_TRACE(L"Destroying a sound device instance\n");
227
228 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
229
230 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
231 if ( ! MMSUCCESS(Result) )
232 return TranslateInternalMmResult(Result);
233
234 Result = GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle);
235 if ( ! MMSUCCESS(Result) )
236 return TranslateInternalMmResult(Result);
237
238 /* Get the "close" routine from the function table, and validate it */
239 Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
240 if ( ! MMSUCCESS(Result) )
241 return TranslateInternalMmResult(Result);
242
243 SND_ASSERT( FunctionTable->Close );
244 if ( FunctionTable->Close == NULL )
245 {
246 /* This indicates bad practice, really! If you can open, why not close?! */
247 return MMSYSERR_NOTSUPPORTED;
248 }
249
250 /* Try and close the device */
251 Result = FunctionTable->Close(SoundDeviceInstance, Handle);
252 if ( ! MMSUCCESS(Result) )
253 return TranslateInternalMmResult(Result);
254
255 /* Drop it from the list */
256 Result = UnlistSoundDeviceInstance(SoundDeviceInstance);
257 if ( ! MMSUCCESS(Result) )
258 return TranslateInternalMmResult(Result);
259
260 FreeSoundDeviceInstance(SoundDeviceInstance);
261
262 return MMSYSERR_NOERROR;
263 }
264
265 MMRESULT
266 DestroyAllSoundDeviceInstances(
267 IN PSOUND_DEVICE SoundDevice)
268 {
269 return MMSYSERR_NOTSUPPORTED;
270 }
271
272 MMRESULT
273 GetSoundDeviceFromInstance(
274 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
275 OUT PSOUND_DEVICE* SoundDevice)
276 {
277 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
278 VALIDATE_MMSYS_PARAMETER( SoundDevice );
279
280 *SoundDevice = SoundDeviceInstance->Device;
281
282 return MMSYSERR_NOERROR;
283 }
284
285 MMRESULT
286 GetSoundDeviceInstanceHandle(
287 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
288 OUT PVOID* Handle)
289 {
290 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
291 VALIDATE_MMSYS_PARAMETER( Handle );
292
293 *Handle = SoundDeviceInstance->Handle;
294
295 return MMSYSERR_NOERROR;
296 }
297
298 MMRESULT
299 SetSoundDeviceInstanceMmeData(
300 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
301 IN HDRVR MmeHandle,
302 IN DWORD ClientCallback,
303 IN DWORD ClientCallbackData,
304 IN DWORD Flags)
305 {
306 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
307
308 SND_TRACE(L"Setting MME data - handle %x, callback %x, instance data %x, flags %x\n",
309 MmeHandle, ClientCallback, ClientCallbackData, Flags);
310
311 SoundDeviceInstance->WinMM.Handle = MmeHandle;
312 SoundDeviceInstance->WinMM.ClientCallback = ClientCallback;
313 SoundDeviceInstance->WinMM.ClientCallbackInstanceData = ClientCallbackData;
314 SoundDeviceInstance->WinMM.Flags = Flags;
315
316 return MMSYSERR_NOERROR;
317 }