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
;
174 WaveHdr
= (PWAVEHDR
) SoundOverlapped
->Header
;
175 SND_ASSERT( WaveHdr
);
177 SND_ASSERT( ERROR_SUCCESS
== dwErrorCode
);
179 HdrExtension
= (PWAVEHDR_EXTENSION
) WaveHdr
->reserved
;
180 SND_ASSERT( HdrExtension
);
182 SoundDeviceInstance
= SoundOverlapped
->SoundDeviceInstance
;
184 Result
= GetSoundDeviceFromInstance(SoundDeviceInstance
, &SoundDevice
);
185 SND_ASSERT( MMSUCCESS(Result
) );
187 Result
= GetSoundDeviceType(SoundDevice
, &DeviceType
);
188 SND_ASSERT( MMSUCCESS(Result
) );
190 HdrExtension
->BytesCompleted
+= dwNumberOfBytesTransferred
;
191 SND_TRACE(L
"%d/%d bytes of wavehdr completed\n", HdrExtension
->BytesCompleted
, WaveHdr
->dwBufferLength
);
193 /* We have an available buffer now */
194 -- SoundDeviceInstance
->OutstandingBuffers
;
196 /* Did we finish a WAVEHDR and aren't looping? */
197 if ( HdrExtension
->BytesCompleted
== WaveHdr
->dwBufferLength
&&
198 SoundOverlapped
->PerformCompletion
)
200 CompleteWaveHeader(SoundDeviceInstance
, WaveHdr
);
203 DoWaveStreaming(SoundDeviceInstance
);
205 //CompleteWavePortion(SoundDeviceInstance, dwNumberOfBytesTransferred);
207 FreeMemory(lpOverlapped
);
211 WriteFileEx_Committer(
212 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance
,
215 IN PSOUND_OVERLAPPED Overlap
,
216 IN LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine
)
220 VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance
);
221 VALIDATE_MMSYS_PARAMETER( OffsetPtr
);
222 VALIDATE_MMSYS_PARAMETER( Overlap
);
223 VALIDATE_MMSYS_PARAMETER( CompletionRoutine
);
225 GetSoundDeviceInstanceHandle(SoundDeviceInstance
, &Handle
);
227 if ( ! WriteFileEx(Handle
, OffsetPtr
, Length
, (LPOVERLAPPED
)Overlap
, CompletionRoutine
) )
232 return MMSYSERR_NOERROR
;
237 Stream control functions
238 (External/internal thread pairs)
240 TODO - Move elsewhere as these shouldn't be wave specific!
244 StopStreamingInSoundThread(
245 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance
,
248 /* complete all pending headers */
249 while(SoundDeviceInstance
->HeadWaveHeader
)
250 CompleteWaveHeader(SoundDeviceInstance
, SoundDeviceInstance
->HeadWaveHeader
);
252 SND_ASSERT( NULL
== SoundDeviceInstance
->HeadWaveHeader
);
253 SND_ASSERT( NULL
== SoundDeviceInstance
->TailWaveHeader
);
254 return MMSYSERR_NOERROR
;
259 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance
)
262 PSOUND_DEVICE SoundDevice
;
263 MMDEVICE_TYPE DeviceType
;
265 if ( ! IsValidSoundDeviceInstance(SoundDeviceInstance
) )
266 return MMSYSERR_INVALHANDLE
;
268 Result
= GetSoundDeviceFromInstance(SoundDeviceInstance
, &SoundDevice
);
269 if ( ! MMSUCCESS(Result
) )
270 return TranslateInternalMmResult(Result
);
272 Result
= GetSoundDeviceType(SoundDevice
, &DeviceType
);
273 if ( ! MMSUCCESS(Result
) )
274 return TranslateInternalMmResult(Result
);
276 if ( DeviceType
!= WAVE_OUT_DEVICE_TYPE
&& DeviceType
!= WAVE_IN_DEVICE_TYPE
)
277 return MMSYSERR_NOTSUPPORTED
;
279 return CallSoundThread(SoundDeviceInstance
,
280 StopStreamingInSoundThread
,