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)
17 Restrain ourselves from flooding the kernel device!
20 #define SOUND_KERNEL_BUFFER_COUNT 10
21 #define SOUND_KERNEL_BUFFER_SIZE 16384
24 AllocateSoundDeviceInstance(
25 OUT PSOUND_DEVICE_INSTANCE
* SoundDeviceInstance
)
27 PSOUND_DEVICE_INSTANCE NewInstance
;
29 VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance
);
31 /* Allocate memory for the new instance */
32 NewInstance
= AllocateStruct(SOUND_DEVICE_INSTANCE
);
35 return MMSYSERR_NOMEM
;
37 /* Use default frame size */
38 NewInstance
->FrameSize
= SOUND_KERNEL_BUFFER_SIZE
;
39 /* Use default buffer count */
40 NewInstance
->BufferCount
= SOUND_KERNEL_BUFFER_COUNT
;
42 /* Provide the caller with the new instance pointer */
43 *SoundDeviceInstance
= NewInstance
;
45 return MMSYSERR_NOERROR
;
49 FreeSoundDeviceInstance(
50 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance
)
53 Device is marked as invalid by now, but we can still do some sanity
56 SND_ASSERT( SoundDeviceInstance
->Thread
== NULL
);
58 ZeroMemory(SoundDeviceInstance
, sizeof(SOUND_DEVICE_INSTANCE
));
59 FreeMemory(SoundDeviceInstance
);
63 IsValidSoundDeviceInstance(
64 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance
)
66 PSOUND_DEVICE SoundDevice
;
67 PSOUND_DEVICE_INSTANCE CurrentInstance
;
69 if ( ! SoundDeviceInstance
)
72 /* GetSoundDeviceFromInstance would send us into a recursive loop... */
73 SoundDevice
= SoundDeviceInstance
->Device
;
74 SND_ASSERT(SoundDevice
);
76 CurrentInstance
= SoundDevice
->HeadInstance
;
78 while ( CurrentInstance
)
80 if ( CurrentInstance
== SoundDeviceInstance
)
83 CurrentInstance
= CurrentInstance
->Next
;
90 ListSoundDeviceInstance(
91 IN PSOUND_DEVICE SoundDevice
,
92 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance
)
94 VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice
) );
95 VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance
);
97 SND_TRACE(L
"Listing sound device instance\n");
99 if ( ! SoundDevice
->HeadInstance
)
101 /* First entry - assign to head and tail */
102 SoundDevice
->HeadInstance
= SoundDeviceInstance
;
103 SoundDevice
->TailInstance
= SoundDeviceInstance
;
107 /* Attach to the end */
108 SoundDevice
->TailInstance
->Next
= SoundDeviceInstance
;
109 SoundDevice
->TailInstance
= SoundDeviceInstance
;
112 return MMSYSERR_NOERROR
;
116 UnlistSoundDeviceInstance(
117 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance
)
120 PSOUND_DEVICE SoundDevice
;
121 PSOUND_DEVICE_INSTANCE CurrentInstance
, PreviousInstance
;
123 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance
) );
125 SND_TRACE(L
"Unlisting sound device instance\n");
127 Result
= GetSoundDeviceFromInstance(SoundDeviceInstance
, &SoundDevice
);
128 SND_ASSERT( MMSUCCESS(Result
) );
129 if ( ! MMSUCCESS(Result
) )
130 return TranslateInternalMmResult(Result
);
132 PreviousInstance
= NULL
;
133 CurrentInstance
= SoundDevice
->HeadInstance
;
135 while ( CurrentInstance
)
137 if ( CurrentInstance
== SoundDeviceInstance
)
139 if ( ! PreviousInstance
)
141 /* This is the head node */
142 SoundDevice
->HeadInstance
= SoundDevice
->HeadInstance
->Next
;
146 /* There are nodes before this one - cut ours out */
147 PreviousInstance
->Next
= CurrentInstance
->Next
;
150 if ( ! CurrentInstance
->Next
)
152 /* This is the tail node */
153 SoundDevice
->TailInstance
= PreviousInstance
;
157 PreviousInstance
= CurrentInstance
;
158 CurrentInstance
= CurrentInstance
->Next
;
161 return MMSYSERR_NOERROR
;
165 CreateSoundDeviceInstance(
166 IN PSOUND_DEVICE SoundDevice
,
167 OUT PSOUND_DEVICE_INSTANCE
* SoundDeviceInstance
)
170 PMMFUNCTION_TABLE FunctionTable
;
172 SND_TRACE(L
"Creating a sound device instance\n");
174 VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice
) );
175 VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance
!= NULL
);
177 Result
= AllocateSoundDeviceInstance(SoundDeviceInstance
);
179 if ( ! MMSUCCESS(Result
) )
180 return TranslateInternalMmResult(Result
);
182 /* Get the "open" routine from the function table, and validate it */
183 Result
= GetSoundDeviceFunctionTable(SoundDevice
, &FunctionTable
);
184 if ( ! MMSUCCESS(Result
) )
186 FreeSoundDeviceInstance(*SoundDeviceInstance
);
187 return TranslateInternalMmResult(Result
);
190 if ( FunctionTable
->Open
== NULL
)
192 FreeSoundDeviceInstance(*SoundDeviceInstance
);
193 return MMSYSERR_NOTSUPPORTED
;
196 /* Set up the members of the structure */
197 (*SoundDeviceInstance
)->Next
= NULL
;
198 (*SoundDeviceInstance
)->Device
= SoundDevice
;
199 (*SoundDeviceInstance
)->Handle
= NULL
;
200 (*SoundDeviceInstance
)->Thread
= NULL
;
202 (*SoundDeviceInstance
)->WinMM
.Handle
= INVALID_HANDLE_VALUE
;
203 (*SoundDeviceInstance
)->WinMM
.ClientCallback
= 0;
204 (*SoundDeviceInstance
)->WinMM
.ClientCallbackInstanceData
= 0;
205 (*SoundDeviceInstance
)->WinMM
.Flags
= 0;
207 /* Initialise the members of the struct used by the sound thread */
208 (*SoundDeviceInstance
)->HeadWaveHeader
= NULL
;
209 (*SoundDeviceInstance
)->TailWaveHeader
= NULL
;
211 (*SoundDeviceInstance
)->OutstandingBuffers
= 0;
213 (*SoundDeviceInstance
)->LoopsRemaining
= 0;
215 /* Create the streaming thread (TODO - is this for wave only?) */
216 Result
= CreateSoundThread(&(*SoundDeviceInstance
)->Thread
);
217 if ( ! MMSUCCESS(Result
) )
219 FreeSoundDeviceInstance(*SoundDeviceInstance
);
220 return TranslateInternalMmResult(Result
);
223 /* Add the instance to the list */
224 Result
= ListSoundDeviceInstance(SoundDevice
, *SoundDeviceInstance
);
225 if ( ! MMSUCCESS(Result
) )
227 FreeSoundDeviceInstance(*SoundDeviceInstance
);
228 return TranslateInternalMmResult(Result
);
231 /* Try and open the device */
232 Result
= FunctionTable
->Open(SoundDevice
, (&(*SoundDeviceInstance
)->Handle
));
233 if ( ! MMSUCCESS(Result
) )
235 UnlistSoundDeviceInstance(*SoundDeviceInstance
);
236 FreeSoundDeviceInstance(*SoundDeviceInstance
);
237 return TranslateInternalMmResult(Result
);
240 return MMSYSERR_NOERROR
;
244 DestroySoundDeviceInstance(
245 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance
)
248 PMMFUNCTION_TABLE FunctionTable
;
249 PSOUND_DEVICE SoundDevice
;
252 SND_TRACE(L
"Destroying a sound device instance\n");
254 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance
) );
256 Result
= GetSoundDeviceFromInstance(SoundDeviceInstance
, &SoundDevice
);
257 if ( ! MMSUCCESS(Result
) )
258 return TranslateInternalMmResult(Result
);
260 Result
= GetSoundDeviceInstanceHandle(SoundDeviceInstance
, &Handle
);
261 if ( ! MMSUCCESS(Result
) )
262 return TranslateInternalMmResult(Result
);
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
);
269 SND_ASSERT( FunctionTable
->Close
);
270 if ( FunctionTable
->Close
== NULL
)
272 /* This indicates bad practice, really! If you can open, why not close?! */
273 return MMSYSERR_NOTSUPPORTED
;
276 /* Stop the streaming thread (TODO - is this for wave only?) */
277 Result
= DestroySoundThread(SoundDeviceInstance
->Thread
);
278 SND_ASSERT( MMSUCCESS(Result
) ); /* It should succeed! */
279 if ( ! MMSUCCESS(Result
) )
281 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
;
311 SoundDeviceInstance
= SoundDevice
->HeadInstance
;
313 while ( SoundDeviceInstance
)
315 Result
= DestroySoundDeviceInstance(SoundDeviceInstance
);
316 SND_ASSERT( MMSUCCESS(Result
) );
317 SoundDeviceInstance
= SoundDeviceInstance
->Next
;
320 return MMSYSERR_NOERROR
;
324 GetSoundDeviceFromInstance(
325 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance
,
326 OUT PSOUND_DEVICE
* SoundDevice
)
328 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance
) );
329 VALIDATE_MMSYS_PARAMETER( SoundDevice
);
331 *SoundDevice
= SoundDeviceInstance
->Device
;
333 return MMSYSERR_NOERROR
;
337 GetSoundDeviceInstanceHandle(
338 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance
,
341 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance
) );
342 VALIDATE_MMSYS_PARAMETER( Handle
);
344 *Handle
= SoundDeviceInstance
->Handle
;
346 return MMSYSERR_NOERROR
;
350 SetSoundDeviceInstanceMmeData(
351 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance
,
353 IN DWORD ClientCallback
,
354 IN DWORD ClientCallbackData
,
357 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance
) );
359 SND_TRACE(L
"Setting MME data - handle %x, callback %x, instance data %x, flags %x\n",
360 MmeHandle
, ClientCallback
, ClientCallbackData
, Flags
);
362 SoundDeviceInstance
->WinMM
.Handle
= MmeHandle
;
363 SoundDeviceInstance
->WinMM
.ClientCallback
= ClientCallback
;
364 SoundDeviceInstance
->WinMM
.ClientCallbackInstanceData
= ClientCallbackData
;
365 SoundDeviceInstance
->WinMM
.Flags
= Flags
;
367 return MMSYSERR_NOERROR
;