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
6 * PURPOSE: Manages instances of sound devices.
8 * PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
14 Restrain ourselves from flooding the kernel device!
17 #define SOUND_KERNEL_BUFFER_COUNT 10
18 #define SOUND_KERNEL_BUFFER_SIZE 16384
21 AllocateSoundDeviceInstance(
22 OUT PSOUND_DEVICE_INSTANCE
* SoundDeviceInstance
)
24 PSOUND_DEVICE_INSTANCE NewInstance
;
26 VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance
);
28 /* Allocate memory for the new instance */
29 NewInstance
= AllocateStruct(SOUND_DEVICE_INSTANCE
);
32 return MMSYSERR_NOMEM
;
34 /* Use default frame size */
35 NewInstance
->FrameSize
= SOUND_KERNEL_BUFFER_SIZE
;
36 /* Use default buffer count */
37 NewInstance
->BufferCount
= SOUND_KERNEL_BUFFER_COUNT
;
39 /* Provide the caller with the new instance pointer */
40 *SoundDeviceInstance
= NewInstance
;
42 return MMSYSERR_NOERROR
;
46 FreeSoundDeviceInstance(
47 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance
)
50 Device is marked as invalid by now, but we can still do some sanity
53 SND_ASSERT( SoundDeviceInstance
->Thread
== NULL
);
55 ZeroMemory(SoundDeviceInstance
, sizeof(SOUND_DEVICE_INSTANCE
));
56 FreeMemory(SoundDeviceInstance
);
60 IsValidSoundDeviceInstance(
61 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance
)
63 PSOUND_DEVICE SoundDevice
;
64 PSOUND_DEVICE_INSTANCE CurrentInstance
;
66 if ( ! SoundDeviceInstance
)
69 /* GetSoundDeviceFromInstance would send us into a recursive loop... */
70 SoundDevice
= SoundDeviceInstance
->Device
;
71 SND_ASSERT(SoundDevice
);
73 CurrentInstance
= SoundDevice
->HeadInstance
;
75 while ( CurrentInstance
)
77 if ( CurrentInstance
== SoundDeviceInstance
)
80 CurrentInstance
= CurrentInstance
->Next
;
87 ListSoundDeviceInstance(
88 IN PSOUND_DEVICE SoundDevice
,
89 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance
)
91 VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice
) );
92 VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance
);
94 SND_TRACE(L
"Listing sound device instance\n");
96 if ( ! SoundDevice
->HeadInstance
)
98 /* First entry - assign to head and tail */
99 SoundDevice
->HeadInstance
= SoundDeviceInstance
;
100 SoundDevice
->TailInstance
= SoundDeviceInstance
;
104 /* Attach to the end */
105 SoundDevice
->TailInstance
->Next
= SoundDeviceInstance
;
106 SoundDevice
->TailInstance
= SoundDeviceInstance
;
109 return MMSYSERR_NOERROR
;
113 UnlistSoundDeviceInstance(
114 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance
)
117 PSOUND_DEVICE SoundDevice
;
118 PSOUND_DEVICE_INSTANCE CurrentInstance
, PreviousInstance
;
120 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance
) );
122 SND_TRACE(L
"Unlisting sound device instance\n");
124 Result
= GetSoundDeviceFromInstance(SoundDeviceInstance
, &SoundDevice
);
125 SND_ASSERT( MMSUCCESS(Result
) );
126 if ( ! MMSUCCESS(Result
) )
127 return TranslateInternalMmResult(Result
);
129 PreviousInstance
= NULL
;
130 CurrentInstance
= SoundDevice
->HeadInstance
;
132 while ( CurrentInstance
)
134 if ( CurrentInstance
== SoundDeviceInstance
)
136 if ( ! PreviousInstance
)
138 /* This is the head node */
139 SoundDevice
->HeadInstance
= SoundDevice
->HeadInstance
->Next
;
143 /* There are nodes before this one - cut ours out */
144 PreviousInstance
->Next
= CurrentInstance
->Next
;
147 if ( ! CurrentInstance
->Next
)
149 /* This is the tail node */
150 SoundDevice
->TailInstance
= PreviousInstance
;
154 PreviousInstance
= CurrentInstance
;
155 CurrentInstance
= CurrentInstance
->Next
;
158 return MMSYSERR_NOERROR
;
162 CreateSoundDeviceInstance(
163 IN PSOUND_DEVICE SoundDevice
,
164 OUT PSOUND_DEVICE_INSTANCE
* SoundDeviceInstance
)
167 PMMFUNCTION_TABLE FunctionTable
;
169 SND_TRACE(L
"Creating a sound device instance\n");
171 VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice
) );
172 VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance
!= NULL
);
174 Result
= AllocateSoundDeviceInstance(SoundDeviceInstance
);
176 if ( ! MMSUCCESS(Result
) )
177 return TranslateInternalMmResult(Result
);
179 /* Get the "open" routine from the function table, and validate it */
180 Result
= GetSoundDeviceFunctionTable(SoundDevice
, &FunctionTable
);
181 if ( ! MMSUCCESS(Result
) )
183 FreeSoundDeviceInstance(*SoundDeviceInstance
);
184 return TranslateInternalMmResult(Result
);
187 if ( FunctionTable
->Open
== NULL
)
189 FreeSoundDeviceInstance(*SoundDeviceInstance
);
190 return MMSYSERR_NOTSUPPORTED
;
193 /* Set up the members of the structure */
194 (*SoundDeviceInstance
)->Next
= NULL
;
195 (*SoundDeviceInstance
)->Device
= SoundDevice
;
196 (*SoundDeviceInstance
)->Handle
= NULL
;
197 (*SoundDeviceInstance
)->Thread
= NULL
;
199 (*SoundDeviceInstance
)->WinMM
.Handle
= INVALID_HANDLE_VALUE
;
200 (*SoundDeviceInstance
)->WinMM
.ClientCallback
= 0;
201 (*SoundDeviceInstance
)->WinMM
.ClientCallbackInstanceData
= 0;
202 (*SoundDeviceInstance
)->WinMM
.Flags
= 0;
204 /* Initialise the members of the struct used by the sound thread */
205 (*SoundDeviceInstance
)->HeadWaveHeader
= NULL
;
206 (*SoundDeviceInstance
)->TailWaveHeader
= NULL
;
208 (*SoundDeviceInstance
)->OutstandingBuffers
= 0;
210 (*SoundDeviceInstance
)->LoopsRemaining
= 0;
212 /* Create the streaming thread (TODO - is this for wave only?) */
213 Result
= CreateSoundThread(&(*SoundDeviceInstance
)->Thread
);
214 if ( ! MMSUCCESS(Result
) )
216 FreeSoundDeviceInstance(*SoundDeviceInstance
);
217 return TranslateInternalMmResult(Result
);
220 /* Add the instance to the list */
221 Result
= ListSoundDeviceInstance(SoundDevice
, *SoundDeviceInstance
);
222 if ( ! MMSUCCESS(Result
) )
224 FreeSoundDeviceInstance(*SoundDeviceInstance
);
225 return TranslateInternalMmResult(Result
);
228 /* Try and open the device */
229 Result
= FunctionTable
->Open(SoundDevice
, (&(*SoundDeviceInstance
)->Handle
));
230 if ( ! MMSUCCESS(Result
) )
232 UnlistSoundDeviceInstance(*SoundDeviceInstance
);
233 FreeSoundDeviceInstance(*SoundDeviceInstance
);
234 return TranslateInternalMmResult(Result
);
237 return MMSYSERR_NOERROR
;
241 DestroySoundDeviceInstance(
242 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance
)
245 PMMFUNCTION_TABLE FunctionTable
;
246 PSOUND_DEVICE SoundDevice
;
249 SND_TRACE(L
"Destroying a sound device instance\n");
251 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance
) );
253 Result
= GetSoundDeviceFromInstance(SoundDeviceInstance
, &SoundDevice
);
254 if ( ! MMSUCCESS(Result
) )
255 return TranslateInternalMmResult(Result
);
257 Result
= GetSoundDeviceInstanceHandle(SoundDeviceInstance
, &Handle
);
258 if ( ! MMSUCCESS(Result
) )
259 return TranslateInternalMmResult(Result
);
261 /* Get the "close" routine from the function table, and validate it */
262 Result
= GetSoundDeviceFunctionTable(SoundDevice
, &FunctionTable
);
263 if ( ! MMSUCCESS(Result
) )
264 return TranslateInternalMmResult(Result
);
266 SND_ASSERT( FunctionTable
->Close
);
267 if ( FunctionTable
->Close
== NULL
)
269 /* This indicates bad practice, really! If you can open, why not close?! */
270 return MMSYSERR_NOTSUPPORTED
;
273 /* Stop the streaming thread */
274 if ( SoundDeviceInstance
->Thread
)
276 Result
= DestroySoundThread(SoundDeviceInstance
->Thread
);
277 SND_ASSERT( MMSUCCESS(Result
) ); /* It should succeed! */
278 if ( ! MMSUCCESS(Result
) )
280 return TranslateInternalMmResult(Result
);
284 /* Blank this out here */
285 SoundDeviceInstance
->Thread
= NULL
;
287 /* Try and close the device */
288 Result
= FunctionTable
->Close(SoundDeviceInstance
, Handle
);
289 SND_ASSERT( MMSUCCESS(Result
) ); /* It should succeed! */
290 if ( ! MMSUCCESS(Result
) )
291 return TranslateInternalMmResult(Result
);
293 /* Drop it from the list */
294 Result
= UnlistSoundDeviceInstance(SoundDeviceInstance
);
295 SND_ASSERT( MMSUCCESS(Result
) ); /* It should succeed! */
296 if ( ! MMSUCCESS(Result
) )
297 return TranslateInternalMmResult(Result
);
299 FreeSoundDeviceInstance(SoundDeviceInstance
);
301 return MMSYSERR_NOERROR
;
305 DestroyAllSoundDeviceInstances(
306 IN PSOUND_DEVICE SoundDevice
)
309 PSOUND_DEVICE_INSTANCE SoundDeviceInstance
, NextDeviceInstance
;
311 SoundDeviceInstance
= SoundDevice
->HeadInstance
;
313 while ( SoundDeviceInstance
)
315 NextDeviceInstance
= SoundDeviceInstance
->Next
;
316 Result
= DestroySoundDeviceInstance(SoundDeviceInstance
);
317 SND_ASSERT( MMSUCCESS(Result
) );
318 SoundDeviceInstance
= NextDeviceInstance
;
321 return MMSYSERR_NOERROR
;
325 GetSoundDeviceFromInstance(
326 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance
,
327 OUT PSOUND_DEVICE
* SoundDevice
)
329 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance
) );
330 VALIDATE_MMSYS_PARAMETER( SoundDevice
);
332 *SoundDevice
= SoundDeviceInstance
->Device
;
334 return MMSYSERR_NOERROR
;
338 GetSoundDeviceInstanceHandle(
339 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance
,
342 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance
) );
343 VALIDATE_MMSYS_PARAMETER( Handle
);
345 *Handle
= SoundDeviceInstance
->Handle
;
347 return MMSYSERR_NOERROR
;
351 SetSoundDeviceInstanceMmeData(
352 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance
,
354 IN DWORD_PTR ClientCallback
,
355 IN DWORD_PTR ClientCallbackData
,
358 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance
) );
360 SND_TRACE(L
"Setting MME data - handle %x, callback %x, instance data %x, flags %x\n",
361 MmeHandle
, ClientCallback
, ClientCallbackData
, Flags
);
363 SoundDeviceInstance
->WinMM
.Handle
= MmeHandle
;
364 SoundDeviceInstance
->WinMM
.ClientCallback
= ClientCallback
;
365 SoundDeviceInstance
->WinMM
.ClientCallbackInstanceData
= ClientCallbackData
;
366 SoundDeviceInstance
->WinMM
.Flags
= Flags
;
368 return MMSYSERR_NOERROR
;