2 * PROJECT: ReactOS Sound System "MME Buddy" Library
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: lib/drivers/sound/mmebuddy/wave/header.c
6 * PURPOSE: Wave header preparation and submission routines
8 * PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
20 This structure gets used locally within functions as a way to shuttle data
21 to the sound thread. It's safe to use locally since CallSoundThread will
22 not return until the operation has been carried out.
27 MMWAVEHEADER_FUNC Function
;
29 } THREADED_WAVEHEADER_PARAMETERS
;
33 Helper routines to simplify the call to the sound thread for the header
38 WaveHeaderOperationInSoundThread(
39 PSOUND_DEVICE_INSTANCE SoundDeviceInstance
,
42 THREADED_WAVEHEADER_PARAMETERS
* Parameters
= (THREADED_WAVEHEADER_PARAMETERS
*) Parameter
;
43 return Parameters
->Function(SoundDeviceInstance
, Parameters
->Header
);
48 MMWAVEHEADER_FUNC Function
,
49 PSOUND_DEVICE_INSTANCE SoundDeviceInstance
,
52 THREADED_WAVEHEADER_PARAMETERS Parameters
;
54 Parameters
.Function
= Function
;
55 Parameters
.Header
= Header
;
57 return CallSoundThread(SoundDeviceInstance
,
58 WaveHeaderOperationInSoundThread
,
65 Clean up a header / reinitialize
72 PWAVEHDR_EXTENSION Extension
= (PWAVEHDR_EXTENSION
) Header
->reserved
;
73 SND_ASSERT( Extension
);
75 Header
->dwBytesRecorded
= 0;
77 Extension
->BytesCommitted
= 0;
78 Extension
->BytesCompleted
= 0;
83 The following routines are basically handlers for:
88 All of these calls are ultimately dealt with in the context of the
89 appropriate sound thread, so the implementation should expect itself to
90 be running in this other thread when any of these operations take place.
95 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance
,
99 PSOUND_DEVICE SoundDevice
;
100 PMMFUNCTION_TABLE FunctionTable
;
101 PWAVEHDR_EXTENSION Extension
;
103 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance
) );
104 VALIDATE_MMSYS_PARAMETER( Header
);
106 SND_TRACE(L
"Preparing wave header\n");
108 Result
= GetSoundDeviceFromInstance(SoundDeviceInstance
, &SoundDevice
);
109 if ( ! MMSUCCESS(Result
) )
110 return TranslateInternalMmResult(Result
);
112 Result
= GetSoundDeviceFunctionTable(SoundDevice
, &FunctionTable
);
113 if ( ! MMSUCCESS(Result
) )
114 return TranslateInternalMmResult(Result
);
116 Extension
= AllocateStruct(WAVEHDR_EXTENSION
);
118 return MMSYSERR_NOMEM
;
120 Header
->reserved
= (DWORD_PTR
) Extension
;
121 Extension
->BytesCommitted
= 0;
122 Extension
->BytesCompleted
= 0;
124 /* Configure the flags */
125 Header
->dwFlags
|= WHDR_PREPARED
;
127 return MMSYSERR_NOERROR
;
132 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance
,
136 PSOUND_DEVICE SoundDevice
;
137 PMMFUNCTION_TABLE FunctionTable
;
138 PWAVEHDR_EXTENSION Extension
;
140 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance
) );
141 VALIDATE_MMSYS_PARAMETER( Header
);
143 SND_TRACE(L
"Un-preparing wave header\n");
145 Result
= GetSoundDeviceFromInstance(SoundDeviceInstance
, &SoundDevice
);
146 if ( ! MMSUCCESS(Result
) )
147 return TranslateInternalMmResult(Result
);
149 Result
= GetSoundDeviceFunctionTable(SoundDevice
, &FunctionTable
);
150 if ( ! MMSUCCESS(Result
) )
151 return TranslateInternalMmResult(Result
);
153 SND_ASSERT( Header
->reserved
);
154 Extension
= (PWAVEHDR_EXTENSION
) Header
->reserved
;
155 FreeMemory(Extension
);
157 /* Configure the flags */
158 Header
->dwFlags
&= ~WHDR_PREPARED
;
160 return MMSYSERR_NOERROR
;
165 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance
,
169 PSOUND_DEVICE SoundDevice
;
170 PMMFUNCTION_TABLE FunctionTable
;
172 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance
) );
173 VALIDATE_MMSYS_PARAMETER( Header
);
175 SND_TRACE(L
"Submitting wave header\n");
177 Result
= GetSoundDeviceFromInstance(SoundDeviceInstance
, &SoundDevice
);
178 if ( ! MMSUCCESS(Result
) )
179 return TranslateInternalMmResult(Result
);
181 Result
= GetSoundDeviceFunctionTable(SoundDevice
, &FunctionTable
);
182 if ( ! MMSUCCESS(Result
) )
183 return TranslateInternalMmResult(Result
);
185 if ( ! FunctionTable
->CommitWaveBuffer
)
186 return MMSYSERR_NOTSUPPORTED
;
189 A few minor sanity checks - any custom checks should've been carried
190 out during wave header preparation etc.
192 VALIDATE_MMSYS_PARAMETER( Header
->lpData
!= NULL
);
193 VALIDATE_MMSYS_PARAMETER( Header
->dwBufferLength
> 0 );
194 VALIDATE_MMSYS_PARAMETER( Header
->dwFlags
& WHDR_PREPARED
);
195 VALIDATE_MMSYS_PARAMETER( ! (Header
->dwFlags
& WHDR_INQUEUE
) );
197 SanitizeWaveHeader(Header
);
199 /* Clear the "done" flag for the buffer */
200 Header
->dwFlags
&= ~WHDR_DONE
;
202 Result
= CallSoundThread(SoundDeviceInstance
,
212 Put the header in the record/playback queue. This is performed within
213 the context of the sound thread, it must NEVER be called from another
217 Set the header information to indicate that it has finished playing,
218 and return it to the client application. This again must be called
219 within the context of the sound thread.
224 PSOUND_DEVICE_INSTANCE SoundDeviceInstance
,
227 PWAVEHDR WaveHeader
= (PWAVEHDR
) Parameter
;
229 VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance
);
230 VALIDATE_MMSYS_PARAMETER( Parameter
);
233 WaveHeader
->lpNext
= NULL
;
235 /* Set the "in queue" flag */
236 WaveHeader
->dwFlags
|= WHDR_INQUEUE
;
238 if ( ! SoundDeviceInstance
->HeadWaveHeader
)
240 /* This is the first header in the queue */
241 SND_TRACE(L
"Enqueued first wave header\n");
242 SoundDeviceInstance
->HeadWaveHeader
= WaveHeader
;
243 SoundDeviceInstance
->TailWaveHeader
= WaveHeader
;
245 DoWaveStreaming(SoundDeviceInstance
);
249 /* There are already queued headers - make this one the tail */
250 SND_TRACE(L
"Enqueued next wave header\n");
252 /* FIXME - Make sure that the buffer has not already been added to the list */
253 if ( SoundDeviceInstance
->TailWaveHeader
!= WaveHeader
)
255 SND_ASSERT(SoundDeviceInstance
->TailWaveHeader
!= WaveHeader
);
257 SoundDeviceInstance
->TailWaveHeader
->lpNext
= WaveHeader
;
258 SoundDeviceInstance
->TailWaveHeader
= WaveHeader
;
259 DUMP_WAVEHDR_QUEUE(SoundDeviceInstance
);
261 DoWaveStreaming(SoundDeviceInstance
);
265 DUMP_WAVEHDR_QUEUE(SoundDeviceInstance
);
267 return MMSYSERR_NOERROR
;
272 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance
,
275 PWAVEHDR PrevHdr
= NULL
, CurrHdr
= NULL
;
276 PWAVEHDR_EXTENSION Extension
;
277 PSOUND_DEVICE SoundDevice
;
278 MMDEVICE_TYPE DeviceType
;
281 SND_TRACE(L
"BUFFER COMPLETE :)\n");
283 // TODO: Set header flags?
287 //DoWaveStreaming(SoundDeviceInstance);
289 Result
= GetSoundDeviceFromInstance(SoundDeviceInstance
, &SoundDevice
);
290 SND_ASSERT( MMSUCCESS(Result
) );
291 Result
= GetSoundDeviceType(SoundDevice
, &DeviceType
);
292 SND_ASSERT( MMSUCCESS(Result
) );
294 Extension
= (PWAVEHDR_EXTENSION
)Header
->reserved
;
295 SND_ASSERT( Extension
);
297 /* Remove the header from the queue, like so */
298 if ( SoundDeviceInstance
->HeadWaveHeader
== Header
)
300 SoundDeviceInstance
->HeadWaveHeader
= Header
->lpNext
;
302 SND_TRACE(L
"Dropping head node\n");
304 /* If nothing after the head, then there is no tail */
305 if ( Header
->lpNext
== NULL
)
307 SND_TRACE(L
"Dropping tail node\n");
308 SoundDeviceInstance
->TailWaveHeader
= NULL
;
314 CurrHdr
= SoundDeviceInstance
->HeadWaveHeader
;
316 SND_TRACE(L
"Relinking nodes\n");
318 while ( CurrHdr
!= Header
)
321 CurrHdr
= CurrHdr
->lpNext
;
322 SND_ASSERT( CurrHdr
);
325 SND_ASSERT( PrevHdr
);
327 PrevHdr
->lpNext
= CurrHdr
->lpNext
;
329 /* If this is the tail node, update the tail */
330 if ( Header
->lpNext
== NULL
)
332 SND_TRACE(L
"Updating tail node\n");
333 SoundDeviceInstance
->TailWaveHeader
= PrevHdr
;
337 /* Make sure we're not using this as the current buffer any more, either! */
339 if ( SoundDeviceInstance->CurrentWaveHeader == Header )
341 SoundDeviceInstance->CurrentWaveHeader = Header->lpNext;
345 DUMP_WAVEHDR_QUEUE(SoundDeviceInstance
);
347 SND_TRACE(L
"Returning buffer to client...\n");
349 /* Update the header */
350 Header
->dwFlags
&= ~WHDR_INQUEUE
;
351 Header
->dwFlags
|= WHDR_DONE
;
353 if ( DeviceType
== WAVE_IN_DEVICE_TYPE
)
355 // FIXME: We won't be called on incomplete buffer!
356 Header
->dwBytesRecorded
= Extension
->BytesCompleted
;
359 /* Safe to do this without thread protection, as we're done with the header */
360 NotifyMmeClient(SoundDeviceInstance
,
361 DeviceType
== WAVE_OUT_DEVICE_TYPE
? WOM_DONE
: WIM_DATA
,