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)
20 Restrain ourselves from flooding the kernel device!
23 #define SOUND_KERNEL_BUFFER_COUNT 10
24 #define SOUND_KERNEL_BUFFER_SIZE 200000
29 Check if there is streaming to be done, and if so, do it.
34 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance
)
37 PSOUND_DEVICE SoundDevice
;
38 PMMFUNCTION_TABLE FunctionTable
;
40 Result
= GetSoundDeviceFromInstance(SoundDeviceInstance
, &SoundDevice
);
41 SND_ASSERT( MMSUCCESS(Result
) );
43 Result
= GetSoundDeviceFunctionTable(SoundDevice
, &FunctionTable
);
44 SND_ASSERT( MMSUCCESS(Result
) );
45 SND_ASSERT( FunctionTable
);
46 SND_ASSERT( FunctionTable
->CommitWaveBuffer
);
49 SND_TRACE(L
"Calling buffer submit routine\n");
51 if ( ! SoundDeviceInstance
->CurrentWaveHeader
)
53 /* Start from the beginning (always a good idea) */
54 SoundDeviceInstance
->CurrentWaveHeader
= SoundDeviceInstance
->HeadWaveHeader
;
57 if ( SoundDeviceInstance
->CurrentWaveHeader
)
59 /* Stream or continue streaming this header */
61 Result
= CommitWaveHeaderToKernelDevice(SoundDeviceInstance
,
62 SoundDeviceInstance
->CurrentWaveHeader
,
63 FunctionTable
->CommitWaveBuffer
);
67 SND_TRACE(L
"NOTHING TO DO - REC/PLAY STOPPED\n");
76 An APC called as a result of a call to CommitWaveHeaderToKernelDevice.
77 This will count up the number of bytes which have been dealt with,
78 and when the entire wave header has been dealt with, will call
79 CompleteWaveHeader to have the wave header returned to the client.
81 CommitWaveHeaderToKernelDevice
82 Sends portions of the buffer described by the wave header to a kernel
83 device. This must only be called from within the context of the sound
84 thread. The caller supplies either their own commit routine, or uses
85 WriteFileEx_Committer. The committer is called with portions of the
86 buffer specified in the wave header.
89 Commit buffers using the WriteFileEx API.
95 IN DWORD dwNumberOfBytesTransferred
,
96 IN LPOVERLAPPED lpOverlapped
)
98 PSOUND_DEVICE_INSTANCE SoundDeviceInstance
;
99 PSOUND_OVERLAPPED SoundOverlapped
= (PSOUND_OVERLAPPED
) lpOverlapped
;
101 PWAVEHDR_EXTENSION HdrExtension
;
103 WaveHdr
= (PWAVEHDR
) SoundOverlapped
->Header
;
104 SND_ASSERT( WaveHdr
);
106 HdrExtension
= (PWAVEHDR_EXTENSION
) WaveHdr
->reserved
;
107 SND_ASSERT( HdrExtension
);
109 SoundDeviceInstance
= SoundOverlapped
->SoundDeviceInstance
;
111 HdrExtension
->BytesCompleted
+= dwNumberOfBytesTransferred
;
112 SND_TRACE(L
"%d/%d bytes of wavehdr completed\n", HdrExtension
->BytesCompleted
, WaveHdr
->dwBufferLength
);
114 /* We have an available buffer now */
115 -- SoundDeviceInstance
->OutstandingBuffers
;
117 if ( HdrExtension
->BytesCompleted
== WaveHdr
->dwBufferLength
)
119 CompleteWaveHeader(SoundDeviceInstance
, WaveHdr
);
122 DoWaveStreaming(SoundDeviceInstance
);
124 //CompleteWavePortion(SoundDeviceInstance, dwNumberOfBytesTransferred);
126 FreeMemory(lpOverlapped
);
130 CommitWaveHeaderToKernelDevice(
131 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance
,
133 IN WAVE_COMMIT_FUNC CommitFunction
)
135 PSOUND_OVERLAPPED Overlap
;
136 DWORD BytesToWrite
, BytesRemaining
;
137 PWAVEHDR_EXTENSION HdrExtension
;
140 VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance
);
141 VALIDATE_MMSYS_PARAMETER( Header
);
142 VALIDATE_MMSYS_PARAMETER( CommitFunction
);
144 HdrExtension
= (PWAVEHDR_EXTENSION
) Header
->reserved
;
145 VALIDATE_MMSYS_PARAMETER( HdrExtension
);
147 /* Loop whilst there is data and sufficient available buffers */
148 while ( ( SoundDeviceInstance
->OutstandingBuffers
< SOUND_KERNEL_BUFFER_COUNT
) &&
149 ( HdrExtension
->BytesCommitted
< Header
->dwBufferLength
) )
151 /* Is this the start of a loop? */
152 SoundDeviceInstance
->WaveLoopStart
= Header
;
154 /* Where to start pulling the data from within the buffer */
155 Offset
= Header
->lpData
+ HdrExtension
->BytesCommitted
;
157 /* How much of this header is not committed? */
158 BytesRemaining
= Header
->dwBufferLength
- HdrExtension
->BytesCommitted
;
160 /* We can write anything up to the buffer size limit */
161 BytesToWrite
= BytesRemaining
> SOUND_KERNEL_BUFFER_SIZE
?
162 SOUND_KERNEL_BUFFER_SIZE
:
165 /* If there's nothing left in the current header, move to the next */
166 if ( BytesToWrite
== 0 )
168 Header
= Header
->lpNext
;
169 HdrExtension
= (PWAVEHDR_EXTENSION
) Header
->reserved
;
170 SND_ASSERT( HdrExtension
);
171 SND_ASSERT( HdrExtension
->BytesCommitted
== 0 );
172 SND_ASSERT( HdrExtension
->BytesCompleted
== 0 );
176 HdrExtension
->BytesCommitted
+= BytesToWrite
;
178 /* We're using up a buffer so update this */
179 ++ SoundDeviceInstance
->OutstandingBuffers
;
181 SND_TRACE(L
"COMMIT: Offset 0x%x amount %d remain %d totalcommit %d",
182 Offset
, BytesToWrite
, BytesRemaining
, HdrExtension
->BytesCommitted
);
184 /* We need a new overlapped info structure for each buffer */
185 Overlap
= AllocateStruct(SOUND_OVERLAPPED
);
189 ZeroMemory(Overlap
, sizeof(SOUND_OVERLAPPED
));
190 Overlap
->SoundDeviceInstance
= SoundDeviceInstance
;
191 Overlap
->Header
= Header
;
194 if ( ! MMSUCCESS(CommitFunction(SoundDeviceInstance
, Offset
, BytesToWrite
, Overlap
, CompleteIO
)) )
196 /* Just pretend it played if we fail... Show must go on, etc. etc. */
197 SND_WARN(L
"FAILED\n");
198 HdrExtension
->BytesCompleted
+= BytesToWrite
;
203 return MMSYSERR_NOERROR
;
207 WriteFileEx_Committer(
208 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance
,
211 IN PSOUND_OVERLAPPED Overlap
,
212 IN LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine
)
216 VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance
);
217 VALIDATE_MMSYS_PARAMETER( OffsetPtr
);
218 VALIDATE_MMSYS_PARAMETER( Overlap
);
219 VALIDATE_MMSYS_PARAMETER( CompletionRoutine
);
221 GetSoundDeviceInstanceHandle(SoundDeviceInstance
, &Handle
);
223 if ( ! WriteFileEx(Handle
, OffsetPtr
, Length
, (LPOVERLAPPED
)Overlap
, CompletionRoutine
) )
228 return MMSYSERR_NOERROR
;