[PSDK]
[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 /*
17 Restrain ourselves from flooding the kernel device!
18 */
19
20 #define SOUND_KERNEL_BUFFER_COUNT 10
21 #define SOUND_KERNEL_BUFFER_SIZE 16384
22
23 MMRESULT
24 AllocateSoundDeviceInstance(
25 OUT PSOUND_DEVICE_INSTANCE* SoundDeviceInstance)
26 {
27 PSOUND_DEVICE_INSTANCE NewInstance;
28
29 VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance );
30
31 /* Allocate memory for the new instance */
32 NewInstance = AllocateStruct(SOUND_DEVICE_INSTANCE);
33
34 if ( ! NewInstance )
35 return MMSYSERR_NOMEM;
36
37 /* Use default frame size */
38 NewInstance->FrameSize = SOUND_KERNEL_BUFFER_SIZE;
39 /* Use default buffer count */
40 NewInstance->BufferCount = SOUND_KERNEL_BUFFER_COUNT;
41
42 /* Provide the caller with the new instance pointer */
43 *SoundDeviceInstance = NewInstance;
44
45 return MMSYSERR_NOERROR;
46 }
47
48 VOID
49 FreeSoundDeviceInstance(
50 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
51 {
52 /*
53 Device is marked as invalid by now, but we can still do some sanity
54 checking.
55 */
56 SND_ASSERT( SoundDeviceInstance->Thread == NULL );
57
58 ZeroMemory(SoundDeviceInstance, sizeof(SOUND_DEVICE_INSTANCE));
59 FreeMemory(SoundDeviceInstance);
60 }
61
62 BOOLEAN
63 IsValidSoundDeviceInstance(
64 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
65 {
66 PSOUND_DEVICE SoundDevice;
67 PSOUND_DEVICE_INSTANCE CurrentInstance;
68
69 if ( ! SoundDeviceInstance )
70 return FALSE;
71
72 /* GetSoundDeviceFromInstance would send us into a recursive loop... */
73 SoundDevice = SoundDeviceInstance->Device;
74 SND_ASSERT(SoundDevice);
75
76 CurrentInstance = SoundDevice->HeadInstance;
77
78 while ( CurrentInstance )
79 {
80 if ( CurrentInstance == SoundDeviceInstance )
81 return TRUE;
82
83 CurrentInstance = CurrentInstance->Next;
84 }
85
86 return FALSE;
87 }
88
89 MMRESULT
90 ListSoundDeviceInstance(
91 IN PSOUND_DEVICE SoundDevice,
92 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
93 {
94 VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice) );
95 VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance );
96
97 SND_TRACE(L"Listing sound device instance\n");
98
99 if ( ! SoundDevice->HeadInstance )
100 {
101 /* First entry - assign to head and tail */
102 SoundDevice->HeadInstance = SoundDeviceInstance;
103 SoundDevice->TailInstance = SoundDeviceInstance;
104 }
105 else
106 {
107 /* Attach to the end */
108 SoundDevice->TailInstance->Next = SoundDeviceInstance;
109 SoundDevice->TailInstance = SoundDeviceInstance;
110 }
111
112 return MMSYSERR_NOERROR;
113 }
114
115 MMRESULT
116 UnlistSoundDeviceInstance(
117 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
118 {
119 MMRESULT Result;
120 PSOUND_DEVICE SoundDevice;
121 PSOUND_DEVICE_INSTANCE CurrentInstance, PreviousInstance;
122
123 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
124
125 SND_TRACE(L"Unlisting sound device instance\n");
126
127 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
128 SND_ASSERT( MMSUCCESS(Result) );
129 if ( ! MMSUCCESS(Result) )
130 return TranslateInternalMmResult(Result);
131
132 PreviousInstance = NULL;
133 CurrentInstance = SoundDevice->HeadInstance;
134
135 while ( CurrentInstance )
136 {
137 if ( CurrentInstance == SoundDeviceInstance )
138 {
139 if ( ! PreviousInstance )
140 {
141 /* This is the head node */
142 SoundDevice->HeadInstance = SoundDevice->HeadInstance->Next;
143 }
144 else
145 {
146 /* There are nodes before this one - cut ours out */
147 PreviousInstance->Next = CurrentInstance->Next;
148 }
149
150 if ( ! CurrentInstance->Next )
151 {
152 /* This is the tail node */
153 SoundDevice->TailInstance = PreviousInstance;
154 }
155 }
156
157 PreviousInstance = CurrentInstance;
158 CurrentInstance = CurrentInstance->Next;
159 }
160
161 return MMSYSERR_NOERROR;
162 }
163
164 MMRESULT
165 CreateSoundDeviceInstance(
166 IN PSOUND_DEVICE SoundDevice,
167 OUT PSOUND_DEVICE_INSTANCE* SoundDeviceInstance)
168 {
169 MMRESULT Result;
170 PMMFUNCTION_TABLE FunctionTable;
171
172 SND_TRACE(L"Creating a sound device instance\n");
173
174 VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice) );
175 VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance != NULL );
176
177 Result = AllocateSoundDeviceInstance(SoundDeviceInstance);
178
179 if ( ! MMSUCCESS(Result) )
180 return TranslateInternalMmResult(Result);
181
182 /* Get the "open" routine from the function table, and validate it */
183 Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
184 if ( ! MMSUCCESS(Result) )
185 {
186 FreeSoundDeviceInstance(*SoundDeviceInstance);
187 return TranslateInternalMmResult(Result);
188 }
189
190 if ( FunctionTable->Open == NULL )
191 {
192 FreeSoundDeviceInstance(*SoundDeviceInstance);
193 return MMSYSERR_NOTSUPPORTED;
194 }
195
196 /* Set up the members of the structure */
197 (*SoundDeviceInstance)->Next = NULL;
198 (*SoundDeviceInstance)->Device = SoundDevice;
199 (*SoundDeviceInstance)->Handle = NULL;
200 (*SoundDeviceInstance)->Thread = NULL;
201
202 (*SoundDeviceInstance)->WinMM.Handle = INVALID_HANDLE_VALUE;
203 (*SoundDeviceInstance)->WinMM.ClientCallback = 0;
204 (*SoundDeviceInstance)->WinMM.ClientCallbackInstanceData = 0;
205 (*SoundDeviceInstance)->WinMM.Flags = 0;
206
207 /* Initialise the members of the struct used by the sound thread */
208 (*SoundDeviceInstance)->HeadWaveHeader = NULL;
209 (*SoundDeviceInstance)->TailWaveHeader = NULL;
210
211 (*SoundDeviceInstance)->OutstandingBuffers = 0;
212
213 (*SoundDeviceInstance)->LoopsRemaining = 0;
214
215 /* Create the streaming thread (TODO - is this for wave only?) */
216 Result = CreateSoundThread(&(*SoundDeviceInstance)->Thread);
217 if ( ! MMSUCCESS(Result) )
218 {
219 FreeSoundDeviceInstance(*SoundDeviceInstance);
220 return TranslateInternalMmResult(Result);
221 }
222
223 /* Add the instance to the list */
224 Result = ListSoundDeviceInstance(SoundDevice, *SoundDeviceInstance);
225 if ( ! MMSUCCESS(Result) )
226 {
227 FreeSoundDeviceInstance(*SoundDeviceInstance);
228 return TranslateInternalMmResult(Result);
229 }
230
231 /* Try and open the device */
232 Result = FunctionTable->Open(SoundDevice, (&(*SoundDeviceInstance)->Handle));
233 if ( ! MMSUCCESS(Result) )
234 {
235 UnlistSoundDeviceInstance(*SoundDeviceInstance);
236 FreeSoundDeviceInstance(*SoundDeviceInstance);
237 return TranslateInternalMmResult(Result);
238 }
239
240 return MMSYSERR_NOERROR;
241 }
242
243 MMRESULT
244 DestroySoundDeviceInstance(
245 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
246 {
247 MMRESULT Result;
248 PMMFUNCTION_TABLE FunctionTable;
249 PSOUND_DEVICE SoundDevice;
250 PVOID Handle;
251
252 SND_TRACE(L"Destroying a sound device instance\n");
253
254 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
255
256 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
257 if ( ! MMSUCCESS(Result) )
258 return TranslateInternalMmResult(Result);
259
260 Result = GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle);
261 if ( ! MMSUCCESS(Result) )
262 return TranslateInternalMmResult(Result);
263
264 /* Get the "close" routine from the function table, and validate it */
265 Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
266 if ( ! MMSUCCESS(Result) )
267 return TranslateInternalMmResult(Result);
268
269 SND_ASSERT( FunctionTable->Close );
270 if ( FunctionTable->Close == NULL )
271 {
272 /* This indicates bad practice, really! If you can open, why not close?! */
273 return MMSYSERR_NOTSUPPORTED;
274 }
275
276 /* Stop the streaming thread */
277 if ( SoundDeviceInstance->Thread )
278 {
279 Result = DestroySoundThread(SoundDeviceInstance->Thread);
280 SND_ASSERT( MMSUCCESS(Result) ); /* It should succeed! */
281 if ( ! MMSUCCESS(Result ) )
282 {
283 return TranslateInternalMmResult(Result);
284 }
285 }
286
287 /* Blank this out here */
288 SoundDeviceInstance->Thread = NULL;
289
290 /* Try and close the device */
291 Result = FunctionTable->Close(SoundDeviceInstance, Handle);
292 SND_ASSERT( MMSUCCESS(Result) ); /* It should succeed! */
293 if ( ! MMSUCCESS(Result) )
294 return TranslateInternalMmResult(Result);
295
296 /* Drop it from the list */
297 Result = UnlistSoundDeviceInstance(SoundDeviceInstance);
298 SND_ASSERT( MMSUCCESS(Result) ); /* It should succeed! */
299 if ( ! MMSUCCESS(Result) )
300 return TranslateInternalMmResult(Result);
301
302 FreeSoundDeviceInstance(SoundDeviceInstance);
303
304 return MMSYSERR_NOERROR;
305 }
306
307 MMRESULT
308 DestroyAllSoundDeviceInstances(
309 IN PSOUND_DEVICE SoundDevice)
310 {
311 MMRESULT Result;
312 PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
313
314 SoundDeviceInstance = SoundDevice->HeadInstance;
315
316 while ( SoundDeviceInstance )
317 {
318 Result = DestroySoundDeviceInstance(SoundDeviceInstance);
319 SND_ASSERT( MMSUCCESS(Result) );
320 SoundDeviceInstance = SoundDeviceInstance->Next;
321 }
322
323 return MMSYSERR_NOERROR;
324 }
325
326 MMRESULT
327 GetSoundDeviceFromInstance(
328 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
329 OUT PSOUND_DEVICE* SoundDevice)
330 {
331 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
332 VALIDATE_MMSYS_PARAMETER( SoundDevice );
333
334 *SoundDevice = SoundDeviceInstance->Device;
335
336 return MMSYSERR_NOERROR;
337 }
338
339 MMRESULT
340 GetSoundDeviceInstanceHandle(
341 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
342 OUT PVOID* Handle)
343 {
344 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
345 VALIDATE_MMSYS_PARAMETER( Handle );
346
347 *Handle = SoundDeviceInstance->Handle;
348
349 return MMSYSERR_NOERROR;
350 }
351
352 MMRESULT
353 SetSoundDeviceInstanceMmeData(
354 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
355 IN HDRVR MmeHandle,
356 IN DWORD_PTR ClientCallback,
357 IN DWORD_PTR ClientCallbackData,
358 IN DWORD Flags)
359 {
360 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
361
362 SND_TRACE(L"Setting MME data - handle %x, callback %x, instance data %x, flags %x\n",
363 MmeHandle, ClientCallback, ClientCallbackData, Flags);
364
365 SoundDeviceInstance->WinMM.Handle = MmeHandle;
366 SoundDeviceInstance->WinMM.ClientCallback = ClientCallback;
367 SoundDeviceInstance->WinMM.ClientCallbackInstanceData = ClientCallbackData;
368 SoundDeviceInstance->WinMM.Flags = Flags;
369
370 return MMSYSERR_NOERROR;
371 }