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
6 * PURPOSE: Wave streaming
8 * PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
21 Check if there is streaming to be done, and if so, do it.
26 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance
)
29 MMDEVICE_TYPE DeviceType
;
30 PSOUND_DEVICE SoundDevice
;
31 PMMFUNCTION_TABLE FunctionTable
;
33 PWAVEHDR_EXTENSION HeaderExtension
;
35 Result
= GetSoundDeviceFromInstance(SoundDeviceInstance
, &SoundDevice
);
36 SND_ASSERT( MMSUCCESS(Result
) );
38 Result
= GetSoundDeviceType(SoundDevice
, &DeviceType
);
39 SND_ASSERT( MMSUCCESS(Result
) );
41 Result
= GetSoundDeviceFunctionTable(SoundDevice
, &FunctionTable
);
42 SND_ASSERT( MMSUCCESS(Result
) );
43 SND_ASSERT( FunctionTable
);
44 SND_ASSERT( FunctionTable
->CommitWaveBuffer
);
46 /* No point in doing anything if no resources available to use */
47 if ( SoundDeviceInstance
->OutstandingBuffers
>= SoundDeviceInstance
->BufferCount
)
49 SND_TRACE(L
"DoWaveStreaming: No available buffers to stream with - doing nothing\n");
53 /* Is there any work to do? */
54 Header
= SoundDeviceInstance
->HeadWaveHeader
;
58 SND_TRACE(L
"DoWaveStreaming: No work to do - doing nothing\n");
62 while ( ( SoundDeviceInstance
->OutstandingBuffers
< SoundDeviceInstance
->BufferCount
) &&
65 HeaderExtension
= (PWAVEHDR_EXTENSION
) Header
->reserved
;
66 SND_ASSERT( HeaderExtension
);
69 SND_ASSERT(Header
->dwFlags
& WHDR_PREPARED
);
70 SND_ASSERT(Header
->dwFlags
& WHDR_INQUEUE
);
72 /* Can never be *above* the length */
73 SND_ASSERT( HeaderExtension
->BytesCommitted
<= Header
->dwBufferLength
);
75 /* Is this header entirely committed? */
76 if ( HeaderExtension
->BytesCommitted
== Header
->dwBufferLength
)
79 /* Move on to the next header */
80 Header
= Header
->lpNext
;
85 PSOUND_OVERLAPPED Overlap
;
87 DWORD BytesRemaining
, BytesToCommit
;
90 /* Where within the header buffer to stream from */
91 OffsetPtr
= Header
->lpData
+ HeaderExtension
->BytesCommitted
;
93 /* How much of this header has not been committed */
94 BytesRemaining
= Header
->dwBufferLength
- HeaderExtension
->BytesCommitted
;
96 /* We can commit anything up to the buffer size limit */
97 BytesToCommit
= BytesRemaining
> SoundDeviceInstance
->FrameSize
?
98 SoundDeviceInstance
->FrameSize
:
101 /* Should always have something to commit by this point */
102 SND_ASSERT( BytesToCommit
> 0 );
104 /* We need a new overlapped info structure for each buffer */
105 Overlap
= AllocateStruct(SOUND_OVERLAPPED
);
109 ZeroMemory(Overlap
, sizeof(SOUND_OVERLAPPED
));
110 Overlap
->SoundDeviceInstance
= SoundDeviceInstance
;
111 Overlap
->Header
= Header
;
113 /* Don't complete this header if it's part of a loop */
114 Overlap
->PerformCompletion
= TRUE
;
115 // ( SoundDeviceInstance->LoopsRemaining > 0 );
117 /* Adjust the commit-related counters */
118 HeaderExtension
->BytesCommitted
+= BytesToCommit
;
119 ++ SoundDeviceInstance
->OutstandingBuffers
;
121 OK
= MMSUCCESS(FunctionTable
->CommitWaveBuffer(SoundDeviceInstance
,
129 /* Clean-up and try again on the next iteration (is this OK?) */
130 SND_WARN(L
"FAILED\n");
133 HeaderExtension
->BytesCommitted
-= BytesToCommit
;
134 -- SoundDeviceInstance
->OutstandingBuffers
;
144 An APC called as a result of a call to CommitWaveHeaderToKernelDevice.
145 This will count up the number of bytes which have been dealt with,
146 and when the entire wave header has been dealt with, will call
147 CompleteWaveHeader to have the wave header returned to the client.
149 CommitWaveHeaderToKernelDevice
150 Sends portions of the buffer described by the wave header to a kernel
151 device. This must only be called from within the context of the sound
152 thread. The caller supplies either their own commit routine, or uses
153 WriteFileEx_Committer. The committer is called with portions of the
154 buffer specified in the wave header.
156 WriteFileEx_Committer
157 Commit buffers using the WriteFileEx API.
162 IN DWORD dwErrorCode
,
163 IN DWORD dwNumberOfBytesTransferred
,
164 IN LPOVERLAPPED lpOverlapped
)
166 MMDEVICE_TYPE DeviceType
;
167 PSOUND_DEVICE SoundDevice
;
168 PSOUND_DEVICE_INSTANCE SoundDeviceInstance
;
169 PSOUND_OVERLAPPED SoundOverlapped
= (PSOUND_OVERLAPPED
) lpOverlapped
;
171 PWAVEHDR_EXTENSION HdrExtension
;
175 WaveHdr
= (PWAVEHDR
) SoundOverlapped
->Header
;
176 SND_ASSERT( WaveHdr
);
178 SND_ASSERT( ERROR_SUCCESS
== dwErrorCode
);
180 HdrExtension
= (PWAVEHDR_EXTENSION
) WaveHdr
->reserved
;
181 SND_ASSERT( HdrExtension
);
183 SoundDeviceInstance
= SoundOverlapped
->SoundDeviceInstance
;
185 Result
= GetSoundDeviceFromInstance(SoundDeviceInstance
, &SoundDevice
);
186 SND_ASSERT( MMSUCCESS(Result
) );
188 Result
= GetSoundDeviceType(SoundDevice
, &DeviceType
);
189 SND_ASSERT( MMSUCCESS(Result
) );
194 /* We have an available buffer now */
195 -- SoundDeviceInstance
->OutstandingBuffers
;
197 /* Did we finish a WAVEHDR and aren't looping? */
198 if ( HdrExtension
->BytesCompleted
+ dwNumberOfBytesTransferred
>= WaveHdr
->dwBufferLength
&&
199 SoundOverlapped
->PerformCompletion
)
201 /* Wave buffer fully completed */
202 Bytes
= WaveHdr
->dwBufferLength
- HdrExtension
->BytesCompleted
;
204 HdrExtension
->BytesCompleted
+= Bytes
;
205 dwNumberOfBytesTransferred
-= Bytes
;
207 CompleteWaveHeader(SoundDeviceInstance
, WaveHdr
);
208 SND_TRACE(L
"%d/%d bytes of wavehdr completed\n", HdrExtension
->BytesCompleted
, WaveHdr
->dwBufferLength
);
212 SND_TRACE(L
"%d/%d bytes of wavehdr completed\n", HdrExtension
->BytesCompleted
, WaveHdr
->dwBufferLength
);
213 /* Partially completed */
214 HdrExtension
->BytesCompleted
+= dwNumberOfBytesTransferred
;
218 /* Move to next wave header */
219 WaveHdr
= WaveHdr
->lpNext
;
223 /* No following WaveHdr */
224 SND_ASSERT(dwNumberOfBytesTransferred
== 0);
228 HdrExtension
= (PWAVEHDR_EXTENSION
) WaveHdr
->reserved
;
229 SND_ASSERT( HdrExtension
);
232 }while(dwNumberOfBytesTransferred
);
234 DoWaveStreaming(SoundDeviceInstance
);
236 //CompleteWavePortion(SoundDeviceInstance, dwNumberOfBytesTransferred);
238 FreeMemory(lpOverlapped
);
242 WriteFileEx_Committer(
243 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance
,
246 IN PSOUND_OVERLAPPED Overlap
,
247 IN LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine
)
251 VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance
);
252 VALIDATE_MMSYS_PARAMETER( OffsetPtr
);
253 VALIDATE_MMSYS_PARAMETER( Overlap
);
254 VALIDATE_MMSYS_PARAMETER( CompletionRoutine
);
256 GetSoundDeviceInstanceHandle(SoundDeviceInstance
, &Handle
);
258 if ( ! WriteFileEx(Handle
, OffsetPtr
, Length
, (LPOVERLAPPED
)Overlap
, CompletionRoutine
) )
263 return MMSYSERR_NOERROR
;
268 Stream control functions
269 (External/internal thread pairs)
271 TODO - Move elsewhere as these shouldn't be wave specific!
275 StopStreamingInSoundThread(
276 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance
,
280 return MMSYSERR_NOTSUPPORTED
;
285 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance
)
288 PSOUND_DEVICE SoundDevice
;
289 MMDEVICE_TYPE DeviceType
;
291 if ( ! IsValidSoundDeviceInstance(SoundDeviceInstance
) )
292 return MMSYSERR_INVALHANDLE
;
294 Result
= GetSoundDeviceFromInstance(SoundDeviceInstance
, &SoundDevice
);
295 if ( ! MMSUCCESS(Result
) )
296 return TranslateInternalMmResult(Result
);
298 Result
= GetSoundDeviceType(SoundDevice
, &DeviceType
);
299 if ( ! MMSUCCESS(Result
) )
300 return TranslateInternalMmResult(Result
);
302 if ( DeviceType
!= WAVE_OUT_DEVICE_TYPE
&& DeviceType
!= WAVE_IN_DEVICE_TYPE
)
303 return MMSYSERR_NOTSUPPORTED
;
305 return CallSoundThread(SoundDeviceInstance
,
306 StopStreamingInSoundThread
,