ReactOS  0.4.14-dev-114-gc8cbd56
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 
20 typedef 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 
63 VOID
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 
125 MMRESULT
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 
158 MMRESULT
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 )
181  return MMSYSERR_NOTSUPPORTED;
182 
183  /*
184  A few minor sanity checks - any custom checks should've been carried
185  out during wave header preparation etc.
186  */
187  VALIDATE_MMSYS_PARAMETER( Header->lpData != NULL );
188  VALIDATE_MMSYS_PARAMETER( Header->dwBufferLength > 0 );
190  VALIDATE_MMSYS_PARAMETER( ! (Header->dwFlags & WHDR_INQUEUE) );
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 
217 MMRESULT
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 
273 VOID
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 
297  Extension = (PWAVEHDR_EXTENSION)Header->reserved;
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,
365  (DWORD_PTR)Header);
366 }
struct wavehdr_tag * PWAVEHDR
#define WOM_DONE
Definition: mmsystem.h:183
#define IN
Definition: typedefs.h:38
static VOID FreeMemory(PCREATE_DATA Data)
Definition: create.c:134
VOID SanitizeWaveHeader(PWAVEHDR Header)
Definition: header.c:64
#define DWORD_PTR
Definition: treelist.c:76
MMRESULT CallSoundThread(IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, IN SOUND_THREAD_REQUEST_HANDLER RequestHandler, IN PVOID Parameter OPTIONAL)
Definition: thread.c:71
#define MMSUCCESS(result)
Definition: mmebuddy.h:80
DeviceType
Definition: mmdrv.h:41
MMRESULT TranslateInternalMmResult(IN MMRESULT Result)
Definition: utility.c:132
UINT MMRESULT
Definition: mmsystem.h:962
PWAVEHDR HeadWaveHeader
Definition: mmebuddy.h:287
_In_ PVOID Parameter
Definition: ldrtypes.h:241
MMRESULT PrepareWaveHeader(IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, IN PWAVEHDR Header)
Definition: header.c:89
#define DUMP_WAVEHDR_QUEUE(sound_device_instance)
#define VALIDATE_MMSYS_PARAMETER(parameter_condition)
Definition: mmebuddy.h:71
MMRESULT EnqueueWaveHeader(PSOUND_DEVICE_INSTANCE SoundDeviceInstance, IN PVOID Parameter)
Definition: header.c:218
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 GetSoundDeviceFunctionTable(IN PSOUND_DEVICE SoundDevice, OUT PMMFUNCTION_TABLE *FunctionTable)
Definition: functiontable.c:47
#define MMSYSERR_NOMEM
Definition: mmsystem.h:103
static LPOVERLAPPED_COMPLETION_ROUTINE Function
Definition: sync.c:684
Definition: Header.h:8
DWORD dwFlags
Definition: mmsystem.h:1018
VOID DoWaveStreaming(IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
Definition: streaming.c:20
smooth NULL
Definition: ftsmooth.c:416
#define SND_ASSERT(condition)
_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:426
BOOLEAN IsValidSoundDeviceInstance(IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
MMRESULT WaveHeaderOperation(MMWAVEHEADER_FUNC Function, PSOUND_DEVICE_INSTANCE SoundDeviceInstance, PWAVEHDR Header)
Definition: header.c:42
#define MMSYSERR_NOERROR
Definition: mmsystem.h:96
#define AllocateStruct(thing)
Definition: mmebuddy.h:27
VOID CompleteWaveHeader(IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, IN PWAVEHDR Header)
Definition: header.c:274
struct _WAVEHDR_EXTENSION * PWAVEHDR_EXTENSION
#define MMSYSERR_NOTSUPPORTED
Definition: mmsystem.h:104
_In_ PPCI_DEVICE_PRESENCE_PARAMETERS Parameters
Definition: iotypes.h:872
static const WCHAR L[]
Definition: oid.c:1250
PWAVEHDR TailWaveHeader
Definition: mmebuddy.h:292
uint32_t DWORD_PTR
Definition: typedefs.h:63
struct wavehdr_tag * lpNext
Definition: mmsystem.h:1020
MMWAVEHEADER_FUNC Function
Definition: header.c:22
MMRESULT GetSoundDeviceType(IN PSOUND_DEVICE SoundDevice, OUT PMMDEVICE_TYPE DeviceType)
Definition: devicelist.c:346
#define WHDR_INQUEUE
Definition: mmsystem.h:197
#define WHDR_PREPARED
Definition: mmsystem.h:194
MMRESULT WriteWaveHeader(IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, IN PWAVEHDR Header)
Definition: header.c:159
MMRESULT(* MMWAVEHEADER_FUNC)(IN struct _SOUND_DEVICE_INSTANCE *SoundDeviceInstance, IN PWAVEHDR WaveHeader)
Definition: mmebuddy.h:163
#define WHDR_DONE
Definition: mmsystem.h:193
MMRESULT WaveHeaderOperationInSoundThread(PSOUND_DEVICE_INSTANCE SoundDeviceInstance, IN PVOID Parameter)
Definition: header.c:33
#define WIM_DATA
Definition: mmsystem.h:186
static WLX_DISPATCH_VERSION_1_4 FunctionTable
Definition: wlx.c:736
MMRESULT UnprepareWaveHeader(IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, IN PWAVEHDR Header)
Definition: header.c:126
MMRESULT GetSoundDeviceFromInstance(IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, OUT PSOUND_DEVICE *SoundDevice)
_Inout_opt_ PUNICODE_STRING Extension
Definition: fltkernel.h:1092
#define SND_TRACE(...)