ReactOS 0.4.16-dev-91-g764881a
header.c
Go to the documentation of this file.
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/wave/header.c
5 *
6 * PURPOSE: Wave header preparation and submission routines
7 *
8 * PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
9*/
10
11#include "precomp.h"
12
13
14/*
15 This structure gets used locally within functions as a way to shuttle data
16 to the sound thread. It's safe to use locally since CallSoundThread will
17 not return until the operation has been carried out.
18*/
19
20typedef struct
21{
25
26
27/*
28 Helper routines to simplify the call to the sound thread for the header
29 functions.
30*/
31
34 PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
36{
38 return Parameters->Function(SoundDeviceInstance, Parameters->Header);
39}
40
44 PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
46{
48
49 Parameters.Function = Function;
50 Parameters.Header = Header;
51
52 return CallSoundThread(SoundDeviceInstance,
54 &Parameters);
55}
56
57
58/*
59 SanitizeWaveHeader
60 Clean up a header / reinitialize
61*/
62
63VOID
66{
69
70 Header->dwBytesRecorded = 0;
71
72 Extension->BytesCommitted = 0;
73 Extension->BytesCompleted = 0;
74}
75
76
77/*
78 The following routines are basically handlers for:
79 - WODM_PREPARE
80 - WODM_UNPREPARE
81 - WODM_WRITE
82
83 All of these calls are ultimately dealt with in the context of the
84 appropriate sound thread, so the implementation should expect itself to
85 be running in this other thread when any of these operations take place.
86*/
87
90 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
92{
94 PSOUND_DEVICE SoundDevice;
97
100
101 SND_TRACE(L"Preparing wave header\n");
102
103 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
104 if ( ! MMSUCCESS(Result) )
106
108 if ( ! MMSUCCESS(Result) )
110
112 if ( ! Extension )
113 return MMSYSERR_NOMEM;
114
115 Header->reserved = (DWORD_PTR) Extension;
116 Extension->BytesCommitted = 0;
117 Extension->BytesCompleted = 0;
118
119 /* Configure the flags */
120 Header->dwFlags |= WHDR_PREPARED;
121
122 return MMSYSERR_NOERROR;
123}
124
127 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
129{
131 PSOUND_DEVICE SoundDevice;
134
137
138 SND_TRACE(L"Un-preparing wave header\n");
139
140 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
141 if ( ! MMSUCCESS(Result) )
143
145 if ( ! MMSUCCESS(Result) )
147
148 SND_ASSERT( Header->reserved );
149 Extension = (PWAVEHDR_EXTENSION) Header->reserved;
151
152 /* Configure the flags */
153 Header->dwFlags &= ~WHDR_PREPARED;
154
155 return MMSYSERR_NOERROR;
156}
157
160 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
162{
164 PSOUND_DEVICE SoundDevice;
166
169
170 SND_TRACE(L"Submitting wave header\n");
171
172 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
173 if ( ! MMSUCCESS(Result) )
175
177 if ( ! MMSUCCESS(Result) )
179
180 if ( ! FunctionTable->CommitWaveBuffer )
182
183 /*
184 A few minor sanity checks - any custom checks should've been carried
185 out during wave header preparation etc.
186 */
188 VALIDATE_MMSYS_PARAMETER( Header->dwBufferLength > 0 );
191
193
194 /* Clear the "done" flag for the buffer */
195 Header->dwFlags &= ~WHDR_DONE;
196
197 Result = CallSoundThread(SoundDeviceInstance,
199 Header);
200
201 return Result;
202}
203
204
205/*
206 EnqueueWaveHeader
207 Put the header in the record/playback queue. This is performed within
208 the context of the sound thread, it must NEVER be called from another
209 thread.
210
211 CompleteWaveHeader
212 Set the header information to indicate that it has finished playing,
213 and return it to the client application. This again must be called
214 within the context of the sound thread.
215*/
216
219 PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
221{
222 PWAVEHDR WaveHeader = (PWAVEHDR) Parameter;
223
224 VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance );
226
227 /* Initialise */
228 WaveHeader->lpNext = NULL;
229
230 /* Set the "in queue" flag */
231 WaveHeader->dwFlags |= WHDR_INQUEUE;
232
233 if ( ! SoundDeviceInstance->HeadWaveHeader )
234 {
235 /* This is the first header in the queue */
236 SND_TRACE(L"Enqueued first wave header\n");
237 SoundDeviceInstance->HeadWaveHeader = WaveHeader;
238 SoundDeviceInstance->TailWaveHeader = WaveHeader;
239
240 /* Only do wave streaming when the stream has not been paused */
241 if (SoundDeviceInstance->bPaused == FALSE)
242 {
243 DoWaveStreaming(SoundDeviceInstance);
244 }
245 }
246 else
247 {
248 /* There are already queued headers - make this one the tail */
249 SND_TRACE(L"Enqueued next wave header\n");
250
251 /* FIXME - Make sure that the buffer has not already been added to the list */
252 if ( SoundDeviceInstance->TailWaveHeader != WaveHeader )
253 {
254 SND_ASSERT(SoundDeviceInstance->TailWaveHeader != WaveHeader);
255
256 SoundDeviceInstance->TailWaveHeader->lpNext = WaveHeader;
257 SoundDeviceInstance->TailWaveHeader = WaveHeader;
258 DUMP_WAVEHDR_QUEUE(SoundDeviceInstance);
259
260 /* Only do wave streaming when the stream has not been paused */
261 if ( SoundDeviceInstance->bPaused == FALSE )
262 {
263 DoWaveStreaming(SoundDeviceInstance);
264 }
265 }
266 }
267
268 DUMP_WAVEHDR_QUEUE(SoundDeviceInstance);
269
270 return MMSYSERR_NOERROR;
271}
272
273VOID
275 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
277{
278 PWAVEHDR PrevHdr = NULL, CurrHdr = NULL;
280 PSOUND_DEVICE SoundDevice;
283
284 SND_TRACE(L"BUFFER COMPLETE :)\n");
285
286 // TODO: Set header flags?
287 // TODO: Call client
288 // TODO: Streaming
289
290 //DoWaveStreaming(SoundDeviceInstance);
291
292 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
294 Result = GetSoundDeviceType(SoundDevice, &DeviceType);
296
299
300 /* Remove the header from the queue, like so */
301 if ( SoundDeviceInstance->HeadWaveHeader == Header )
302 {
303 SoundDeviceInstance->HeadWaveHeader = Header->lpNext;
304
305 SND_TRACE(L"Dropping head node\n");
306
307 /* If nothing after the head, then there is no tail */
308 if ( Header->lpNext == NULL )
309 {
310 SND_TRACE(L"Dropping tail node\n");
311 SoundDeviceInstance->TailWaveHeader = NULL;
312 }
313 }
314 else
315 {
316 PrevHdr = NULL;
317 CurrHdr = SoundDeviceInstance->HeadWaveHeader;
318
319 SND_TRACE(L"Relinking nodes\n");
320
321 while ( CurrHdr != Header )
322 {
323 PrevHdr = CurrHdr;
324 CurrHdr = CurrHdr->lpNext;
325 SND_ASSERT( CurrHdr );
326 }
327
328 SND_ASSERT( PrevHdr );
329
330 PrevHdr->lpNext = CurrHdr->lpNext;
331
332 /* If this is the tail node, update the tail */
333 if ( Header->lpNext == NULL )
334 {
335 SND_TRACE(L"Updating tail node\n");
336 SoundDeviceInstance->TailWaveHeader = PrevHdr;
337 }
338 }
339
340 /* Make sure we're not using this as the current buffer any more, either! */
341/*
342 if ( SoundDeviceInstance->CurrentWaveHeader == Header )
343 {
344 SoundDeviceInstance->CurrentWaveHeader = Header->lpNext;
345 }
346*/
347
348 DUMP_WAVEHDR_QUEUE(SoundDeviceInstance);
349
350 SND_TRACE(L"Returning buffer to client...\n");
351
352 /* Update the header */
353 Header->dwFlags &= ~WHDR_INQUEUE;
354 Header->dwFlags |= WHDR_DONE;
355
357 {
358 // FIXME: We won't be called on incomplete buffer!
359 Header->dwBytesRecorded = Extension->BytesCompleted;
360 }
361
362 /* Safe to do this without thread protection, as we're done with the header */
363 NotifyMmeClient(SoundDeviceInstance,
366}
static VOID FreeMemory(PCREATE_DATA Data)
Definition: create.c:134
_In_ CDROM_SCAN_FOR_SPECIAL_INFO _In_ PCDROM_SCAN_FOR_SPECIAL_HANDLER Function
Definition: cdrom.h:1156
Definition: Header.h:9
#define NULL
Definition: types.h:112
#define FALSE
Definition: types.h:117
_Inout_opt_ PUNICODE_STRING Extension
Definition: fltkernel.h:1092
DeviceType
Definition: mmdrv.h:42
struct _WAVEHDR_EXTENSION * PWAVEHDR_EXTENSION
VOID DoWaveStreaming(IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
Definition: streaming.c:19
MMRESULT CallSoundThread(IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, IN SOUND_THREAD_REQUEST_HANDLER RequestHandler, IN PVOID Parameter OPTIONAL)
Definition: thread.c:71
#define VALIDATE_MMSYS_PARAMETER(parameter_condition)
Definition: mmebuddy.h:71
#define AllocateStruct(thing)
Definition: mmebuddy.h:27
MMRESULT GetSoundDeviceFunctionTable(IN PSOUND_DEVICE SoundDevice, OUT PMMFUNCTION_TABLE *FunctionTable)
Definition: functiontable.c:47
VOID NotifyMmeClient(IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, IN UINT Message, IN DWORD_PTR Parameter)
Definition: mmewrap.c:75
UCHAR MMDEVICE_TYPE
Definition: mmebuddy.h:88
MMRESULT GetSoundDeviceFromInstance(IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, OUT PSOUND_DEVICE *SoundDevice)
MMRESULT TranslateInternalMmResult(IN MMRESULT Result)
Definition: utility.c:132
MMRESULT GetSoundDeviceType(IN PSOUND_DEVICE SoundDevice, OUT PMMDEVICE_TYPE DeviceType)
Definition: devicelist.c:346
MMRESULT(* MMWAVEHEADER_FUNC)(IN struct _SOUND_DEVICE_INSTANCE *SoundDeviceInstance, IN PWAVEHDR WaveHeader)
Definition: mmebuddy.h:162
#define MMSUCCESS(result)
Definition: mmebuddy.h:80
BOOLEAN IsValidSoundDeviceInstance(IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
#define DUMP_WAVEHDR_QUEUE(sound_device_instance)
#define SND_TRACE(...)
#define SND_ASSERT(condition)
#define WOM_DONE
Definition: mmsystem.h:183
#define MMSYSERR_NOMEM
Definition: mmsystem.h:103
UINT MMRESULT
Definition: mmsystem.h:962
struct wavehdr_tag * PWAVEHDR
#define MMSYSERR_NOTSUPPORTED
Definition: mmsystem.h:104
#define WIM_DATA
Definition: mmsystem.h:186
#define WHDR_INQUEUE
Definition: mmsystem.h:197
#define MMSYSERR_NOERROR
Definition: mmsystem.h:96
#define WHDR_PREPARED
Definition: mmsystem.h:194
#define WHDR_DONE
Definition: mmsystem.h:193
#define L(x)
Definition: ntvdm.h:50
MMRESULT EnqueueWaveHeader(PSOUND_DEVICE_INSTANCE SoundDeviceInstance, IN PVOID Parameter)
Definition: header.c:218
VOID SanitizeWaveHeader(PWAVEHDR Header)
Definition: header.c:64
MMRESULT WaveHeaderOperation(MMWAVEHEADER_FUNC Function, PSOUND_DEVICE_INSTANCE SoundDeviceInstance, PWAVEHDR Header)
Definition: header.c:42
MMRESULT WriteWaveHeader(IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, IN PWAVEHDR Header)
Definition: header.c:159
MMRESULT WaveHeaderOperationInSoundThread(PSOUND_DEVICE_INSTANCE SoundDeviceInstance, IN PVOID Parameter)
Definition: header.c:33
MMRESULT UnprepareWaveHeader(IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, IN PWAVEHDR Header)
Definition: header.c:126
MMRESULT PrepareWaveHeader(IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, IN PWAVEHDR Header)
Definition: header.c:89
VOID CompleteWaveHeader(IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, IN PWAVEHDR Header)
Definition: header.c:274
@ WAVE_IN_DEVICE_TYPE
Definition: sndtypes.h:28
@ WAVE_OUT_DEVICE_TYPE
Definition: sndtypes.h:29
MMWAVEHEADER_FUNC Function
Definition: header.c:22
PWAVEHDR TailWaveHeader
Definition: mmebuddy.h:304
PWAVEHDR HeadWaveHeader
Definition: mmebuddy.h:299
DWORD dwFlags
Definition: mmsystem.h:1018
struct wavehdr_tag * lpNext
Definition: mmsystem.h:1020
#define DWORD_PTR
Definition: treelist.c:76
uint32_t DWORD_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
_Must_inspect_result_ _In_ WDFQUEUE _In_opt_ WDFREQUEST _In_opt_ WDFFILEOBJECT _Inout_opt_ PWDF_REQUEST_PARAMETERS Parameters
Definition: wdfio.h:869
static WLX_DISPATCH_VERSION_1_4 FunctionTable
Definition: wlx.c:722
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:409
_Inout_opt_ PVOID Parameter
Definition: rtltypes.h:336