eba8e89e4a966990a129c6eae6e39c6ae62a1e3e
[reactos.git] / reactos / dll / directx / dsound_new / capturebuffer.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Configuration of network devices
4 * FILE: dll/directx/dsound_new/capturebuffer.c
5 * PURPOSE: IDirectSoundCaptureBuffer8 implementation
6 *
7 * PROGRAMMERS: Johannes Anderwald (janderwald@reactos.org)
8 */
9
10
11 #include "precomp.h"
12
13 const GUID KSINTERFACESETID_Standard = {0x1A8766A0L, 0x62CE, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
14 const GUID KSMEDIUMSETID_Standard = {0x4747B320L, 0x62CE, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
15 const GUID KSDATAFORMAT_TYPE_AUDIO = {0x73647561L, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
16 const GUID KSDATAFORMAT_SPECIFIER_WAVEFORMATEX = {0x05589f81L, 0xc356, 0x11ce, {0xbf, 0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a}};
17 const GUID KSPROPSETID_Connection = {0x1D58C920L, 0xAC9B, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
18
19
20 typedef struct
21 {
22 IDirectSoundCaptureBuffer8Vtbl *lpVtbl;
23 LONG ref;
24 LPFILTERINFO Filter;
25 HANDLE hPin;
26 PUCHAR Buffer;
27 DWORD BufferSize;
28 LPWAVEFORMATEX Format;
29 WAVEFORMATEX MixFormat;
30 BOOL bMix;
31 BOOL bLoop;
32 KSSTATE State;
33
34 }CDirectSoundCaptureBufferImpl, *LPCDirectSoundCaptureBufferImpl;
35
36 HRESULT
37 WINAPI
38 IDirectSoundCaptureBufferImpl_QueryInterface(
39 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
40 IN REFIID riid,
41 LPVOID* ppobj)
42 {
43 LPOLESTR pStr;
44 LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl, lpVtbl);
45
46 /* check if requested interface is supported */
47 if (IsEqualIID(riid, &IID_IUnknown) ||
48 IsEqualIID(riid, &IID_IDirectSoundCaptureBuffer) ||
49 IsEqualIID(riid, &IID_IDirectSoundCaptureBuffer8))
50 {
51 *ppobj = (LPVOID)&This->lpVtbl;
52 InterlockedIncrement(&This->ref);
53 return S_OK;
54 }
55
56 /* interface not supported */
57 if (SUCCEEDED(StringFromIID(riid, &pStr)))
58 {
59 DPRINT("No Interface for class %s\n", pStr);
60 CoTaskMemFree(pStr);
61 }
62 return E_NOINTERFACE;
63 }
64
65 ULONG
66 WINAPI
67 IDirectSoundCaptureBufferImpl_AddRef(
68 LPDIRECTSOUNDCAPTUREBUFFER8 iface)
69 {
70 ULONG ref;
71 LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl, lpVtbl);
72
73 /* increment reference count */
74 ref = InterlockedIncrement(&This->ref);
75
76 return ref;
77
78 }
79
80 ULONG
81 WINAPI
82 IDirectSoundCaptureBufferImpl_Release(
83 LPDIRECTSOUNDCAPTUREBUFFER8 iface)
84 {
85 ULONG ref;
86 LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl, lpVtbl);
87
88 /* release reference count */
89 ref = InterlockedDecrement(&(This->ref));
90
91 if (!ref)
92 {
93 if (This->hPin)
94 {
95 /* close pin handle */
96 CloseHandle(This->hPin);
97 }
98
99 /* free capture buffer */
100 HeapFree(GetProcessHeap(), 0, This->Buffer);
101 /* free wave format */
102 HeapFree(GetProcessHeap(), 0, This->Format);
103 /* free capture buffer */
104 HeapFree(GetProcessHeap(), 0, This);
105 }
106
107 return ref;
108 }
109
110
111 HRESULT
112 WINAPI
113 IDirectSoundCaptureBufferImpl_GetCaps(
114 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
115 LPDSCBCAPS lpDSCBCaps )
116 {
117 LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl, lpVtbl);
118
119 if (!lpDSCBCaps)
120 {
121 /* invalid parameter */
122 return DSERR_INVALIDPARAM;
123 }
124
125 if (lpDSCBCaps->dwSize != sizeof(DSCBCAPS))
126 {
127 /* invalid parameter */
128 return DSERR_INVALIDPARAM;
129 }
130
131 lpDSCBCaps->dwBufferBytes = This->BufferSize;
132 lpDSCBCaps->dwReserved = 0;
133 //lpDSCBCaps->dwFlags = DSCBCAPS_WAVEMAPPED;
134
135 return DS_OK;
136 }
137
138 HRESULT
139 WINAPI
140 IDirectSoundCaptureBufferImpl_GetCurrentPosition(
141 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
142 LPDWORD lpdwCapturePosition,
143 LPDWORD lpdwReadPosition)
144 {
145 KSAUDIO_POSITION Position;
146 KSPROPERTY Request;
147 DWORD Result;
148
149 LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl, lpVtbl);
150
151 if (!This->hPin)
152 {
153 if (lpdwCapturePosition)
154 *lpdwCapturePosition = 0;
155
156 if (lpdwReadPosition)
157 *lpdwReadPosition = 0;
158
159 DPRINT("No Audio Pin\n");
160 return DS_OK;
161 }
162
163 /* setup audio position property request */
164 Request.Id = KSPROPERTY_AUDIO_POSITION;
165 Request.Set = KSPROPSETID_Audio;
166 Request.Flags = KSPROPERTY_TYPE_GET;
167
168
169 Result = SyncOverlappedDeviceIoControl(This->hPin, IOCTL_KS_PROPERTY, (PVOID)&Request, sizeof(KSPROPERTY), (PVOID)&Position, sizeof(KSAUDIO_POSITION), NULL);
170
171 if (Result != ERROR_SUCCESS)
172 {
173 DPRINT("GetPosition failed with %x\n", Result);
174 return DSERR_UNSUPPORTED;
175 }
176
177 //DPRINT("Play %I64u Write %I64u \n", Position.PlayOffset, Position.WriteOffset);
178
179 if (lpdwCapturePosition)
180 *lpdwCapturePosition = (DWORD)Position.PlayOffset;
181
182 if (lpdwReadPosition)
183 *lpdwReadPosition = (DWORD)Position.WriteOffset;
184
185 return DS_OK;
186 }
187
188
189 HRESULT
190 WINAPI
191 IDirectSoundCaptureBufferImpl_GetFormat(
192 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
193 LPWAVEFORMATEX lpwfxFormat,
194 DWORD dwSizeAllocated,
195 LPDWORD lpdwSizeWritten)
196 {
197 DWORD FormatSize;
198 LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl, lpVtbl);
199
200 FormatSize = sizeof(WAVEFORMATEX) + This->Format->cbSize;
201
202 if (!lpwfxFormat && !lpdwSizeWritten)
203 {
204 /* invalid parameter */
205 return DSERR_INVALIDPARAM;
206 }
207
208 if (!lpwfxFormat)
209 {
210 /* return required format size */
211 *lpdwSizeWritten = FormatSize;
212 return DS_OK;
213 }
214 else
215 {
216 if (dwSizeAllocated >= FormatSize)
217 {
218 /* copy format */
219 CopyMemory(lpwfxFormat, This->Format, FormatSize);
220
221 if (lpdwSizeWritten)
222 *lpdwSizeWritten = FormatSize;
223
224 return DS_OK;
225 }
226 /* buffer too small */
227 if (lpdwSizeWritten)
228 *lpdwSizeWritten = 0;
229 return DSERR_INVALIDPARAM;
230 }
231 }
232
233 HRESULT
234 WINAPI
235 IDirectSoundCaptureBufferImpl_GetStatus(
236 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
237 LPDWORD lpdwStatus )
238 {
239 LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl, lpVtbl);
240
241 if (!lpdwStatus)
242 {
243 /* invalid parameter */
244 return DSERR_INVALIDPARAM;
245 }
246
247 /* reset flags */
248 *lpdwStatus = 0;
249
250 /* check if pin is running */
251 if (This->State == KSSTATE_RUN)
252 *lpdwStatus |= DSCBSTATUS_CAPTURING;
253
254 /* check if a looped buffer is used */
255 if (This->bLoop)
256 *lpdwStatus |= DSCBSTATUS_LOOPING;
257
258 /* done */
259 return DS_OK;
260 }
261
262 HRESULT
263 WINAPI
264 IDirectSoundCaptureBufferImpl_Initialize(
265 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
266 LPDIRECTSOUNDCAPTURE lpDSC,
267 LPCDSCBUFFERDESC lpcDSCBDesc)
268 {
269 /* capture buffer is already initialized */
270 return DSERR_ALREADYINITIALIZED;
271 }
272
273 HRESULT
274 WINAPI
275 IDirectSoundCaptureBufferImpl_Lock(
276 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
277 DWORD dwReadCusor,
278 DWORD dwReadBytes,
279 LPVOID* lplpvAudioPtr1,
280 LPDWORD lpdwAudioBytes1,
281 LPVOID* lplpvAudioPtr2,
282 LPDWORD lpdwAudioBytes2,
283 DWORD dwFlags )
284 {
285 UNIMPLEMENTED
286 return DSERR_INVALIDPARAM;
287 }
288
289 HRESULT
290 WINAPI
291 IDirectSoundCaptureBufferImpl_Start(
292 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
293 DWORD dwFlags )
294 {
295 KSPROPERTY Property;
296 KSSTREAM_HEADER Header;
297 DWORD Result, BytesTransferred;
298 OVERLAPPED Overlapped;
299 KSSTATE State;
300 LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl, lpVtbl);
301
302 DPRINT("IDirectSoundCaptureBufferImpl_Start Flags %x\n", dwFlags);
303 ASSERT(dwFlags == DSCBSTART_LOOPING);
304
305 /* check if pin is already running */
306 if (This->State == KSSTATE_RUN)
307 return DS_OK;
308
309 /* sanity check */
310 ASSERT(This->hPin);
311
312 /* setup request */
313 Property.Set = KSPROPSETID_Connection;
314 Property.Id = KSPROPERTY_CONNECTION_STATE;
315 Property.Flags = KSPROPERTY_TYPE_SET;
316 State = KSSTATE_RUN;
317
318 /* set pin to run */
319 Result = SyncOverlappedDeviceIoControl(This->hPin, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&State, sizeof(KSSTATE), &BytesTransferred);
320
321 ASSERT(Result == ERROR_SUCCESS);
322
323 if (Result == ERROR_SUCCESS)
324 {
325 /* store result */
326 This->State = State;
327 }
328
329 /* initialize overlapped struct */
330 ZeroMemory(&Overlapped, sizeof(OVERLAPPED));
331 Overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
332
333 /* clear stream header */
334 ZeroMemory(&Header, sizeof(KSSTREAM_HEADER));
335
336 /* initialize stream header */
337 Header.FrameExtent = This->BufferSize;
338 Header.DataUsed = 0;
339 Header.Data = This->Buffer;
340 Header.Size = sizeof(KSSTREAM_HEADER);
341 Header.PresentationTime.Numerator = 1;
342 Header.PresentationTime.Denominator = 1;
343
344 Result = DeviceIoControl(This->hPin, IOCTL_KS_WRITE_STREAM, NULL, 0, &Header, sizeof(KSSTREAM_HEADER), &BytesTransferred, &Overlapped);
345
346 if (Result != ERROR_SUCCESS)
347 {
348 DPRINT("Failed submit buffer with %lx\n", Result);
349 return DSERR_GENERIC;
350 }
351
352 return DS_OK;
353 }
354
355 HRESULT
356 WINAPI
357 IDirectSoundCaptureBufferImpl_Stop( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
358 {
359 UNIMPLEMENTED
360 return DSERR_INVALIDPARAM;
361 }
362
363 HRESULT
364 WINAPI
365 IDirectSoundCaptureBufferImpl_Unlock(
366 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
367 LPVOID lpvAudioPtr1,
368 DWORD dwAudioBytes1,
369 LPVOID lpvAudioPtr2,
370 DWORD dwAudioBytes2 )
371 {
372 UNIMPLEMENTED
373 return DSERR_INVALIDPARAM;
374 }
375
376 HRESULT
377 WINAPI
378 IDirectSoundCaptureBufferImpl_GetObjectInPath(
379 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
380 REFGUID rguidObject,
381 DWORD dwIndex,
382 REFGUID rguidInterface,
383 LPVOID* ppObject )
384 {
385 UNIMPLEMENTED
386 return DSERR_INVALIDPARAM;
387 }
388
389 HRESULT
390 WINAPI
391 IDirectSoundCaptureBufferImpl_GetFXStatus(
392 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
393 DWORD dwFXCount,
394 LPDWORD pdwFXStatus )
395 {
396 UNIMPLEMENTED
397 return DSERR_INVALIDPARAM;
398 }
399
400
401 static IDirectSoundCaptureBuffer8Vtbl vt_DirectSoundCaptureBuffer8 =
402 {
403 /* IUnknown methods */
404 IDirectSoundCaptureBufferImpl_QueryInterface,
405 IDirectSoundCaptureBufferImpl_AddRef,
406 IDirectSoundCaptureBufferImpl_Release,
407
408 /* IDirectSoundCaptureBuffer methods */
409 IDirectSoundCaptureBufferImpl_GetCaps,
410 IDirectSoundCaptureBufferImpl_GetCurrentPosition,
411 IDirectSoundCaptureBufferImpl_GetFormat,
412 IDirectSoundCaptureBufferImpl_GetStatus,
413 IDirectSoundCaptureBufferImpl_Initialize,
414 IDirectSoundCaptureBufferImpl_Lock,
415 IDirectSoundCaptureBufferImpl_Start,
416 IDirectSoundCaptureBufferImpl_Stop,
417 IDirectSoundCaptureBufferImpl_Unlock,
418
419 /* IDirectSoundCaptureBuffer methods */
420 IDirectSoundCaptureBufferImpl_GetObjectInPath,
421 IDirectSoundCaptureBufferImpl_GetFXStatus
422 };
423
424
425 HRESULT
426 NewDirectSoundCaptureBuffer(
427 LPDIRECTSOUNDCAPTUREBUFFER8 *OutBuffer,
428 LPFILTERINFO Filter,
429 LPCDSCBUFFERDESC lpcDSBufferDesc)
430 {
431 DWORD FormatSize;
432 ULONG DeviceId = 0, PinId;
433 DWORD Result = ERROR_SUCCESS;
434 WAVEFORMATEX MixFormat;
435
436 LPCDirectSoundCaptureBufferImpl This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CDirectSoundCaptureBufferImpl));
437
438 if (!This)
439 {
440 /* not enough memory */
441 return DSERR_OUTOFMEMORY;
442 }
443
444 /* calculate format size */
445 FormatSize = sizeof(WAVEFORMATEX) + lpcDSBufferDesc->lpwfxFormat->cbSize;
446 /* allocate format struct */
447 This->Format = HeapAlloc(GetProcessHeap(), 0, FormatSize);
448 if (!This->Format)
449 {
450 /* not enough memory */
451 HeapFree(GetProcessHeap(), 0, This);
452 return DSERR_OUTOFMEMORY;
453 }
454
455 /* sanity check */
456 ASSERT(lpcDSBufferDesc->dwBufferBytes);
457
458 /* allocate capture buffer */
459 This->Buffer = HeapAlloc(GetProcessHeap(), 0, lpcDSBufferDesc->dwBufferBytes);
460 if (!This->Buffer)
461 {
462 /* not enough memory */
463 HeapFree(GetProcessHeap(), 0, This->Format);
464 HeapFree(GetProcessHeap(), 0, This);
465 return DSERR_OUTOFMEMORY;
466 }
467
468 /* store buffer size */
469 This->BufferSize = lpcDSBufferDesc->dwBufferBytes;
470 ASSERT(lpcDSBufferDesc->lpwfxFormat->cbSize == 0);
471
472 do
473 {
474 /* try all available recording pins on that filter */
475 PinId = GetPinIdFromFilter(Filter, TRUE, DeviceId);
476
477 if (PinId == ULONG_MAX)
478 break;
479
480 Result = OpenPin(Filter->hFilter, PinId, lpcDSBufferDesc->lpwfxFormat, &This->hPin, TRUE);
481 if (Result == ERROR_SUCCESS)
482 break;
483
484 DeviceId++;
485 }while(TRUE);
486
487 if (Result != ERROR_SUCCESS)
488 {
489 /* failed to instantiate the capture pin with the native format
490 * try to compute a compatible format and use that
491 * we could use the mixer api for this purpose but... the kmixer isnt working very good atm
492 */
493
494 DeviceId = 0;
495 do
496 {
497 /* try all available recording pins on that filter */
498 PinId = GetPinIdFromFilter(Filter, TRUE, DeviceId);
499 DPRINT("PinId %u DeviceId %u\n", PinId, DeviceId);
500
501 if (PinId == ULONG_MAX)
502 break;
503
504 if (CreateCompatiblePin(Filter->hFilter, PinId, TRUE, lpcDSBufferDesc->lpwfxFormat, &MixFormat, &This->hPin))
505 {
506 This->bMix = TRUE;
507 CopyMemory(&This->MixFormat, &MixFormat, sizeof(WAVEFORMATEX));
508 break;
509 }
510
511 DeviceId++;
512 }while(TRUE);
513
514
515 if (!This->bMix)
516 {
517 /* FIXME should not happen */
518 DPRINT("failed to compute a compatible format\n");
519 HeapFree(GetProcessHeap(), 0, This->Buffer);
520 HeapFree(GetProcessHeap(), 0, This->Format);
521 HeapFree(GetProcessHeap(), 0, This);
522 return DSERR_GENERIC;
523 }
524 }
525
526 /* initialize capture buffer */
527 This->ref = 1;
528 This->lpVtbl = &vt_DirectSoundCaptureBuffer8;
529 This->Filter = Filter;
530 This->State = KSSTATE_STOP;
531 This->bLoop = TRUE;
532
533 RtlMoveMemory(This->Format, lpcDSBufferDesc->lpwfxFormat, FormatSize);
534
535 *OutBuffer = (LPDIRECTSOUNDCAPTUREBUFFER8)&This->lpVtbl;
536 return DS_OK;
537 }