ReactOS 0.4.15-dev-7918-g2a2556c
streaming.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/streaming.c
5 *
6 * PURPOSE: Wave streaming
7 *
8 * PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
9*/
10
11#include "precomp.h"
12
13
14/*
15 DoWaveStreaming
16 Check if there is streaming to be done, and if so, do it.
17*/
18
19VOID
21 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
22{
25 PSOUND_DEVICE SoundDevice;
28 PWAVEHDR_EXTENSION HeaderExtension;
29
30 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
32
33 Result = GetSoundDeviceType(SoundDevice, &DeviceType);
35
39 SND_ASSERT( FunctionTable->CommitWaveBuffer );
40
41 /* No point in doing anything if no resources available to use */
42 if ( SoundDeviceInstance->OutstandingBuffers >= SoundDeviceInstance->BufferCount )
43 {
44 SND_TRACE(L"DoWaveStreaming: No available buffers to stream with - doing nothing\n");
45 return;
46 }
47
48 /* Is there any work to do? */
49 Header = SoundDeviceInstance->HeadWaveHeader;
50
51 if ( ! Header )
52 {
53 SND_TRACE(L"DoWaveStreaming: No work to do - doing nothing\n");
54 return;
55 }
56
57 while ( ( SoundDeviceInstance->OutstandingBuffers < SoundDeviceInstance->BufferCount ) &&
58 ( Header ) && SoundDeviceInstance->ResetInProgress == FALSE)
59 {
60 HeaderExtension = (PWAVEHDR_EXTENSION) Header->reserved;
61 SND_ASSERT( HeaderExtension );
62
63 /* Saniy checks */
65 SND_ASSERT(Header->dwFlags & WHDR_INQUEUE);
66
67 /* Can never be *above* the length */
68 SND_ASSERT( HeaderExtension->BytesCommitted <= Header->dwBufferLength );
69
70 /* Is this header entirely committed? */
71 if ( HeaderExtension->BytesCommitted == Header->dwBufferLength )
72 {
73 {
74 /* Move on to the next header */
75 SND_ASSERT(Header != Header->lpNext);
76 Header = Header->lpNext;
77 }
78 }
79 else
80 {
81 PSOUND_OVERLAPPED Overlap;
82 LPVOID OffsetPtr;
83 DWORD BytesRemaining, BytesToCommit;
84 BOOL OK;
85
86 /* Where within the header buffer to stream from */
87 OffsetPtr = Header->lpData + HeaderExtension->BytesCommitted;
88
89 /* How much of this header has not been committed */
90 BytesRemaining = Header->dwBufferLength - HeaderExtension->BytesCommitted;
91
92 /* We can commit anything up to the buffer size limit */
93 BytesToCommit = BytesRemaining > SoundDeviceInstance->FrameSize ?
94 SoundDeviceInstance->FrameSize :
95 BytesRemaining;
96
97 /* Should always have something to commit by this point */
98 SND_ASSERT( BytesToCommit > 0 );
99
100 /* We need a new overlapped info structure for each buffer */
102
103 if ( Overlap )
104 {
105 ZeroMemory(Overlap, sizeof(SOUND_OVERLAPPED));
106 Overlap->SoundDeviceInstance = SoundDeviceInstance;
107 Overlap->Header = Header;
108
109 /* Don't complete this header if it's part of a loop */
110 Overlap->PerformCompletion = TRUE;
111// ( SoundDeviceInstance->LoopsRemaining > 0 );
112
113 /* Adjust the commit-related counters */
114 HeaderExtension->BytesCommitted += BytesToCommit;
115 ++ SoundDeviceInstance->OutstandingBuffers;
116
117 OK = MMSUCCESS(FunctionTable->CommitWaveBuffer(SoundDeviceInstance,
118 OffsetPtr,
119 BytesToCommit,
120 Overlap,
121 CompleteIO));
122
123 if ( ! OK )
124 {
125 /* Clean-up and try again on the next iteration (is this OK?) */
126 SND_WARN(L"FAILED\n");
127
128 FreeMemory(Overlap);
129 HeaderExtension->BytesCommitted -= BytesToCommit;
130 -- SoundDeviceInstance->OutstandingBuffers;
131 }
132 }
133 }
134 }
135}
136
137
138/*
139 CompleteIO
140 An APC called as a result of a call to CommitWaveHeaderToKernelDevice.
141 This will count up the number of bytes which have been dealt with,
142 and when the entire wave header has been dealt with, will call
143 CompleteWaveHeader to have the wave header returned to the client.
144
145 CommitWaveHeaderToKernelDevice
146 Sends portions of the buffer described by the wave header to a kernel
147 device. This must only be called from within the context of the sound
148 thread. The caller supplies either their own commit routine, or uses
149 WriteFileEx_Committer. The committer is called with portions of the
150 buffer specified in the wave header.
151
152 WriteFileEx_Committer
153 Commit buffers using the WriteFileEx API.
154*/
155
158 IN DWORD dwErrorCode,
159 IN DWORD dwNumberOfBytesTransferred,
161{
163 PSOUND_DEVICE SoundDevice;
164 PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
166 PWAVEHDR WaveHdr;
167 PWAVEHDR_EXTENSION HdrExtension;
169 DWORD Bytes;
170
171 WaveHdr = (PWAVEHDR) SoundOverlapped->Header;
172 SND_ASSERT( WaveHdr );
173
174 HdrExtension = (PWAVEHDR_EXTENSION) WaveHdr->reserved;
175 SND_ASSERT( HdrExtension );
176
177 SoundDeviceInstance = SoundOverlapped->SoundDeviceInstance;
178
179 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
181
182 Result = GetSoundDeviceType(SoundDevice, &DeviceType);
184
185 do
186 {
187
188 /* We have an available buffer now */
189 -- SoundDeviceInstance->OutstandingBuffers;
190
191 /* Did we finish a WAVEHDR and aren't looping? */
192 if ( HdrExtension->BytesCompleted + dwNumberOfBytesTransferred >= WaveHdr->dwBufferLength &&
193 SoundOverlapped->PerformCompletion )
194 {
195 /* Wave buffer fully completed */
196 Bytes = WaveHdr->dwBufferLength - HdrExtension->BytesCompleted;
197
198 HdrExtension->BytesCompleted += Bytes;
199 dwNumberOfBytesTransferred -= Bytes;
200
201 CompleteWaveHeader(SoundDeviceInstance, WaveHdr);
202 SND_TRACE(L"%d/%d bytes of wavehdr completed\n", HdrExtension->BytesCompleted, WaveHdr->dwBufferLength);
203 }
204 else
205 {
206 /* Partially completed */
207 HdrExtension->BytesCompleted += dwNumberOfBytesTransferred;
208 SND_TRACE(L"%d/%d bytes of wavehdr completed\n", HdrExtension->BytesCompleted, WaveHdr->dwBufferLength);
209 break;
210 }
211
212 /* Move to next wave header */
213 WaveHdr = WaveHdr->lpNext;
214
215 if (!WaveHdr)
216 {
217 /* No following WaveHdr */
218 SND_ASSERT(dwNumberOfBytesTransferred == 0);
219 break;
220 }
221
222 HdrExtension = (PWAVEHDR_EXTENSION) WaveHdr->reserved;
223 SND_ASSERT( HdrExtension );
224
225
226 }while(dwNumberOfBytesTransferred);
227
228 // AUDIO-BRANCH DIFF
229 // completion callback is performed in a thread
230 DoWaveStreaming(SoundDeviceInstance);
231
232 //CompleteWavePortion(SoundDeviceInstance, dwNumberOfBytesTransferred);
233
235}
236
239 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
240 IN PVOID OffsetPtr,
242 IN PSOUND_OVERLAPPED Overlap,
244{
246
247 VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance );
248 VALIDATE_MMSYS_PARAMETER( OffsetPtr );
249 VALIDATE_MMSYS_PARAMETER( Overlap );
251
252 GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle);
253
254 if ( ! WriteFileEx(Handle, OffsetPtr, Length, (LPOVERLAPPED)Overlap, CompletionRoutine) )
255 {
256 // TODO
257 }
258
259 return MMSYSERR_NOERROR;
260}
261
262
263/*
264 Stream control functions
265 (External/internal thread pairs)
266
267 TODO - Move elsewhere as these shouldn't be wave specific!
268*/
269
272 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
274{
278 PSOUND_DEVICE SoundDevice;
279
280 /* set state reset in progress */
281 SoundDeviceInstance->ResetInProgress = TRUE;
282
283 /* Get sound device */
284 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
286
287 /* Obtain the function table */
290
291 /* Obtain device instance type */
292 Result = GetSoundDeviceType(SoundDevice, &DeviceType);
294
295 /* Check if reset function is supported */
296 if (FunctionTable->ResetStream)
297 {
298 /* cancel all current audio buffers */
299 FunctionTable->ResetStream(SoundDeviceInstance, DeviceType, TRUE);
300 }
301 while(SoundDeviceInstance->OutstandingBuffers)
302 {
303 SND_TRACE(L"StopStreamingInSoundThread OutStandingBufferCount %lu\n", SoundDeviceInstance->OutstandingBuffers);
304 /* wait until pending i/o has completed */
305 SleepEx(10, TRUE);
306 }
307
308 /* complete all current headers */
309 while( SoundDeviceInstance->HeadWaveHeader )
310 {
311 SND_TRACE(L"StopStreamingInSoundThread: Completing Header %p\n", SoundDeviceInstance->HeadWaveHeader);
312 CompleteWaveHeader( SoundDeviceInstance, SoundDeviceInstance->HeadWaveHeader );
313 }
314
315 /* there should be no oustanding buffers now */
316 SND_ASSERT(SoundDeviceInstance->OutstandingBuffers == 0);
317
318
319 /* Check if reset function is supported */
320 if (FunctionTable->ResetStream)
321 {
322 /* finish the reset */
323 FunctionTable->ResetStream(SoundDeviceInstance, DeviceType, FALSE);
324 }
325
326 /* clear state reset in progress */
327 SoundDeviceInstance->ResetInProgress = FALSE;
328
329
330 return MMSYSERR_NOERROR;
331}
332
335 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
336{
338 PSOUND_DEVICE SoundDevice;
340
341 if ( ! IsValidSoundDeviceInstance(SoundDeviceInstance) )
343
344 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
345 if ( ! MMSUCCESS(Result) )
347
348 Result = GetSoundDeviceType(SoundDevice, &DeviceType);
349 if ( ! MMSUCCESS(Result) )
351
354
355 return CallSoundThread(SoundDeviceInstance,
357 NULL);
358}
359
362 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
364{
365 DoWaveStreaming(SoundDeviceInstance);
366
367 return MMSYSERR_NOERROR;
368}
369
370DWORD
371WINAPI
373 IN PVOID lpParameter)
374{
377 NULL);
378
379 ExitThread(0);
380}
381
382VOID
384 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
385{
387
388 hThread = CreateThread(NULL, 0, WaveActivateSoundStreaming, (PVOID)SoundDeviceInstance, 0, NULL);
389
390 if (hThread != NULL)
392}
static VOID FreeMemory(PCREATE_DATA Data)
Definition: create.c:134
Definition: Header.h:9
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define CloseHandle
Definition: compat.h:739
#define CALLBACK
Definition: compat.h:35
BOOL WINAPI WriteFileEx(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, IN LPOVERLAPPED lpOverlapped, IN LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
Definition: rw.c:262
VOID WINAPI ExitThread(IN DWORD uExitCode)
Definition: thread.c:365
HANDLE WINAPI DECLSPEC_HOTPATCH CreateThread(IN LPSECURITY_ATTRIBUTES lpThreadAttributes, IN DWORD dwStackSize, IN LPTHREAD_START_ROUTINE lpStartAddress, IN LPVOID lpParameter, IN DWORD dwCreationFlags, OUT LPDWORD lpThreadId)
Definition: thread.c:137
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
ULONG Handle
Definition: gdb_input.c:15
_In_ UINT Bytes
Definition: mmcopy.h:9
DeviceType
Definition: mmdrv.h:42
struct _WAVEHDR_EXTENSION * PWAVEHDR_EXTENSION
struct _SOUND_OVERLAPPED * PSOUND_OVERLAPPED
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
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 GetSoundDeviceInstanceHandle(IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, OUT PVOID *Handle)
MMRESULT GetSoundDeviceType(IN PSOUND_DEVICE SoundDevice, OUT PMMDEVICE_TYPE DeviceType)
Definition: devicelist.c:346
VOID CompleteWaveHeader(IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, IN PWAVEHDR Header)
Definition: header.c:274
#define MMSUCCESS(result)
Definition: mmebuddy.h:80
BOOLEAN IsValidSoundDeviceInstance(IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
#define SND_TRACE(...)
#define SND_ASSERT(condition)
#define SND_WARN(...)
UINT MMRESULT
Definition: mmsystem.h:962
struct wavehdr_tag * PWAVEHDR
#define MMSYSERR_NOTSUPPORTED
Definition: mmsystem.h:104
#define WHDR_INQUEUE
Definition: mmsystem.h:197
#define MMSYSERR_INVALHANDLE
Definition: mmsystem.h:101
#define MMSYSERR_NOERROR
Definition: mmsystem.h:96
#define WHDR_PREPARED
Definition: mmsystem.h:194
_In_ HANDLE _In_ DWORD _In_ DWORD _Inout_opt_ LPOVERLAPPED lpOverlapped
Definition: mswsock.h:93
HANDLE hThread
Definition: wizard.c:28
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
#define L(x)
Definition: ntvdm.h:50
@ WAVE_IN_DEVICE_TYPE
Definition: sndtypes.h:28
@ WAVE_OUT_DEVICE_TYPE
Definition: sndtypes.h:29
MMRESULT WriteFileEx_Committer(IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, IN PVOID OffsetPtr, IN DWORD Length, IN PSOUND_OVERLAPPED Overlap, IN LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine)
Definition: streaming.c:238
VOID DoWaveStreaming(IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
Definition: streaming.c:20
VOID InitiateSoundStreaming(IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
Definition: streaming.c:383
MMRESULT StopStreaming(IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
Definition: streaming.c:334
MMRESULT StopStreamingInSoundThread(IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, IN PVOID Parameter)
Definition: streaming.c:271
DWORD WINAPI WaveActivateSoundStreaming(IN PVOID lpParameter)
Definition: streaming.c:372
VOID CALLBACK CompleteIO(IN DWORD dwErrorCode, IN DWORD dwNumberOfBytesTransferred, IN LPOVERLAPPED lpOverlapped)
Definition: streaming.c:157
MMRESULT PerformWaveStreaming(IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, IN PVOID Parameter)
Definition: streaming.c:361
BOOL PerformCompletion
Definition: mmebuddy.h:123
PWAVEHDR Header
Definition: mmebuddy.h:122
struct _SOUND_DEVICE_INSTANCE * SoundDeviceInstance
Definition: mmebuddy.h:121
DWORD BytesCommitted
Definition: mmebuddy.h:312
DWORD BytesCompleted
Definition: mmebuddy.h:313
DWORD dwBufferLength
Definition: mmsystem.h:1015
DWORD_PTR reserved
Definition: mmsystem.h:1021
struct wavehdr_tag * lpNext
Definition: mmsystem.h:1020
DWORD WINAPI SleepEx(IN DWORD dwMilliseconds, IN BOOL bAlertable)
Definition: synch.c:802
#define IN
Definition: typedefs.h:39
#define OK(condition, fail_message,...)
_In_ WDFREQUEST _In_opt_ PFN_WDF_REQUEST_COMPLETION_ROUTINE CompletionRoutine
Definition: wdfrequest.h:895
#define ZeroMemory
Definition: winbase.h:1712
void(CALLBACK * LPOVERLAPPED_COMPLETION_ROUTINE)(DWORD, DWORD, LPOVERLAPPED)
Definition: winbase.h:1451
#define WINAPI
Definition: msvc.h:6
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:323