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 VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance
);
228 VALIDATE_MMSYS_PARAMETER( Parameter
);
230 PWAVEHDR WaveHeader
= (PWAVEHDR
) 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");
251 SoundDeviceInstance
->TailWaveHeader
->lpNext
= WaveHeader
;
252 SoundDeviceInstance
->TailWaveHeader
= WaveHeader
;
254 DoWaveStreaming(SoundDeviceInstance
);
257 DUMP_WAVEHDR_QUEUE(SoundDeviceInstance
);
259 return MMSYSERR_NOERROR
;
264 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance
,
267 PWAVEHDR PrevHdr
= NULL
, CurrHdr
= NULL
;
268 PWAVEHDR_EXTENSION Extension
;
269 PSOUND_DEVICE SoundDevice
;
270 MMDEVICE_TYPE DeviceType
;
273 SND_TRACE(L
"BUFFER COMPLETE :)\n");
275 // TODO: Set header flags?
279 //DoWaveStreaming(SoundDeviceInstance);
281 Result
= GetSoundDeviceFromInstance(SoundDeviceInstance
, &SoundDevice
);
282 SND_ASSERT( MMSUCCESS(Result
) );
283 Result
= GetSoundDeviceType(SoundDevice
, &DeviceType
);
284 SND_ASSERT( MMSUCCESS(Result
) );
286 Extension
= (PWAVEHDR_EXTENSION
)Header
->reserved
;
287 SND_ASSERT( Extension
);
289 /* Remove the header from the queue, like so */
290 if ( SoundDeviceInstance
->HeadWaveHeader
== Header
)
292 SoundDeviceInstance
->HeadWaveHeader
= Header
->lpNext
;
294 SND_TRACE(L
"Dropping head node\n");
296 /* If nothing after the head, then there is no tail */
297 if ( Header
->lpNext
== NULL
)
299 SND_TRACE(L
"Dropping tail node\n");
300 SoundDeviceInstance
->TailWaveHeader
= NULL
;
306 CurrHdr
= SoundDeviceInstance
->HeadWaveHeader
;
308 SND_TRACE(L
"Relinking nodes\n");
310 while ( CurrHdr
!= Header
)
313 CurrHdr
= CurrHdr
->lpNext
;
314 SND_ASSERT( CurrHdr
);
317 SND_ASSERT( PrevHdr
);
319 PrevHdr
->lpNext
= CurrHdr
->lpNext
;
321 /* If this is the tail node, update the tail */
322 if ( Header
->lpNext
== NULL
)
324 SND_TRACE(L
"Updating tail node\n");
325 SoundDeviceInstance
->TailWaveHeader
= PrevHdr
;
329 /* Make sure we're not using this as the current buffer any more, either! */
331 if ( SoundDeviceInstance->CurrentWaveHeader == Header )
333 SoundDeviceInstance->CurrentWaveHeader = Header->lpNext;
337 DUMP_WAVEHDR_QUEUE(SoundDeviceInstance
);
339 SND_TRACE(L
"Returning buffer to client...\n");
341 /* Update the header */
342 Header
->dwFlags
&= ~WHDR_INQUEUE
;
343 Header
->dwFlags
|= WHDR_DONE
;
345 if ( DeviceType
== WAVE_IN_DEVICE_TYPE
)
347 // FIXME: We won't be called on incomplete buffer!
348 Header
->dwBytesRecorded
= Extension
->BytesCompleted
;
351 /* Safe to do this without thread protection, as we're done with the header */
352 NotifyMmeClient(SoundDeviceInstance
,
353 DeviceType
== WAVE_OUT_DEVICE_TYPE
? WOM_DONE
: WIM_DATA
,