Removed hooks for prepare/unprepare/stream of WAVEHDR. These are handled
[reactos.git] / reactos / lib / drivers / sound / mmebuddy / wave / streaming.c
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 <windows.h>
12 #include <mmsystem.h>
13 #include <mmddk.h>
14 #include <ntddsnd.h>
15 #include <mmebuddy.h>
16 #include <sndtypes.h>
17
18
19 /*
20 Restrain ourselves from flooding the kernel device!
21 */
22
23 #define SOUND_KERNEL_BUFFER_COUNT 10
24 #define SOUND_KERNEL_BUFFER_SIZE 200000
25
26
27 /*
28 DoWaveStreaming
29 Check if there is streaming to be done, and if so, do it.
30 */
31
32 MMRESULT
33 DoWaveStreaming(
34 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
35 {
36 MMRESULT Result;
37 PSOUND_DEVICE SoundDevice;
38 PMMFUNCTION_TABLE FunctionTable;
39
40 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
41 SND_ASSERT( MMSUCCESS(Result) );
42
43 Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
44 SND_ASSERT( MMSUCCESS(Result) );
45 SND_ASSERT( FunctionTable );
46 SND_ASSERT( FunctionTable->CommitWaveBuffer );
47
48 // HACK
49 SND_TRACE(L"Calling buffer submit routine\n");
50
51 if ( ! SoundDeviceInstance->CurrentWaveHeader )
52 {
53 /* Start from the beginning (always a good idea) */
54 SoundDeviceInstance->CurrentWaveHeader = SoundDeviceInstance->HeadWaveHeader;
55 }
56
57 if ( SoundDeviceInstance->CurrentWaveHeader )
58 {
59 /* Stream or continue streaming this header */
60
61 Result = CommitWaveHeaderToKernelDevice(SoundDeviceInstance,
62 SoundDeviceInstance->CurrentWaveHeader,
63 FunctionTable->CommitWaveBuffer);
64 }
65 else
66 {
67 SND_TRACE(L"NOTHING TO DO - REC/PLAY STOPPED\n");
68 }
69
70 return Result;
71 }
72
73
74 /*
75 CompleteIO
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.
80
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.
87
88 WriteFileEx_Committer
89 Commit buffers using the WriteFileEx API.
90 */
91
92 VOID CALLBACK
93 CompleteIO(
94 IN DWORD dwErrorCode,
95 IN DWORD dwNumberOfBytesTransferred,
96 IN LPOVERLAPPED lpOverlapped)
97 {
98 PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
99 PSOUND_OVERLAPPED SoundOverlapped = (PSOUND_OVERLAPPED) lpOverlapped;
100 PWAVEHDR WaveHdr;
101 PWAVEHDR_EXTENSION HdrExtension;
102
103 WaveHdr = (PWAVEHDR) SoundOverlapped->Header;
104 SND_ASSERT( WaveHdr );
105
106 HdrExtension = (PWAVEHDR_EXTENSION) WaveHdr->reserved;
107 SND_ASSERT( HdrExtension );
108
109 SoundDeviceInstance = SoundOverlapped->SoundDeviceInstance;
110
111 HdrExtension->BytesCompleted += dwNumberOfBytesTransferred;
112 SND_TRACE(L"%d/%d bytes of wavehdr completed\n", HdrExtension->BytesCompleted, WaveHdr->dwBufferLength);
113
114 /* We have an available buffer now */
115 -- SoundDeviceInstance->OutstandingBuffers;
116
117 if ( HdrExtension->BytesCompleted == WaveHdr->dwBufferLength )
118 {
119 CompleteWaveHeader(SoundDeviceInstance, WaveHdr);
120 }
121
122 DoWaveStreaming(SoundDeviceInstance);
123
124 //CompleteWavePortion(SoundDeviceInstance, dwNumberOfBytesTransferred);
125
126 FreeMemory(lpOverlapped);
127 }
128
129 MMRESULT
130 CommitWaveHeaderToKernelDevice(
131 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
132 IN PWAVEHDR Header,
133 IN WAVE_COMMIT_FUNC CommitFunction)
134 {
135 PSOUND_OVERLAPPED Overlap;
136 DWORD BytesToWrite, BytesRemaining;
137 PWAVEHDR_EXTENSION HdrExtension;
138 LPVOID Offset;
139
140 VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance );
141 VALIDATE_MMSYS_PARAMETER( Header );
142 VALIDATE_MMSYS_PARAMETER( CommitFunction );
143
144 HdrExtension = (PWAVEHDR_EXTENSION) Header->reserved;
145 VALIDATE_MMSYS_PARAMETER( HdrExtension );
146
147 /* Loop whilst there is data and sufficient available buffers */
148 while ( ( SoundDeviceInstance->OutstandingBuffers < SOUND_KERNEL_BUFFER_COUNT ) &&
149 ( HdrExtension->BytesCommitted < Header->dwBufferLength ) )
150 {
151 /* Is this the start of a loop? */
152 SoundDeviceInstance->WaveLoopStart = Header;
153
154 /* Where to start pulling the data from within the buffer */
155 Offset = Header->lpData + HdrExtension->BytesCommitted;
156
157 /* How much of this header is not committed? */
158 BytesRemaining = Header->dwBufferLength - HdrExtension->BytesCommitted;
159
160 /* We can write anything up to the buffer size limit */
161 BytesToWrite = BytesRemaining > SOUND_KERNEL_BUFFER_SIZE ?
162 SOUND_KERNEL_BUFFER_SIZE :
163 BytesRemaining;
164
165 /* If there's nothing left in the current header, move to the next */
166 if ( BytesToWrite == 0 )
167 {
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 );
173 continue;
174 }
175
176 HdrExtension->BytesCommitted += BytesToWrite;
177
178 /* We're using up a buffer so update this */
179 ++ SoundDeviceInstance->OutstandingBuffers;
180
181 SND_TRACE(L"COMMIT: Offset 0x%x amount %d remain %d totalcommit %d",
182 Offset, BytesToWrite, BytesRemaining, HdrExtension->BytesCommitted);
183
184 /* We need a new overlapped info structure for each buffer */
185 Overlap = AllocateStruct(SOUND_OVERLAPPED);
186
187 if ( Overlap )
188 {
189 ZeroMemory(Overlap, sizeof(SOUND_OVERLAPPED));
190 Overlap->SoundDeviceInstance = SoundDeviceInstance;
191 Overlap->Header = Header;
192
193
194 if ( ! MMSUCCESS(CommitFunction(SoundDeviceInstance, Offset, BytesToWrite, Overlap, CompleteIO)) )
195 {
196 /* Just pretend it played if we fail... Show must go on, etc. etc. */
197 SND_WARN(L"FAILED\n");
198 HdrExtension->BytesCompleted += BytesToWrite;
199 }
200 }
201 }
202
203 return MMSYSERR_NOERROR;
204 }
205
206 MMRESULT
207 WriteFileEx_Committer(
208 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
209 IN PVOID OffsetPtr,
210 IN DWORD Length,
211 IN PSOUND_OVERLAPPED Overlap,
212 IN LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine)
213 {
214 HANDLE Handle;
215
216 VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance );
217 VALIDATE_MMSYS_PARAMETER( OffsetPtr );
218 VALIDATE_MMSYS_PARAMETER( Overlap );
219 VALIDATE_MMSYS_PARAMETER( CompletionRoutine );
220
221 GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle);
222
223 if ( ! WriteFileEx(Handle, OffsetPtr, Length, (LPOVERLAPPED)Overlap, CompletionRoutine) )
224 {
225 // TODO
226 }
227
228 return MMSYSERR_NOERROR;
229 }