0c9ab6bcb033e9aa34e382cd67e302937dbc3c1a
[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 dwOffset,
278 DWORD dwBytes,
279 LPVOID* ppvAudioPtr1,
280 LPDWORD pdwAudioBytes1,
281 LPVOID* ppvAudioPtr2,
282 LPDWORD pdwAudioBytes2,
283 DWORD dwFlags )
284 {
285 LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl, lpVtbl);
286
287 DPRINT("This %p dwOffset %u dwBytes %u ppvAudioPtr1 %p pdwAudioBytes1 %p ppvAudioPtr2 %p pdwAudioBytes2 %p dwFlags %x This->BufferSize %u\n",
288 This, dwOffset, dwBytes, ppvAudioPtr1, pdwAudioBytes1, ppvAudioPtr2, pdwAudioBytes2, dwFlags, This->BufferSize);
289
290 if (dwFlags == DSBLOCK_ENTIREBUFFER)
291 {
292 *ppvAudioPtr1 = (LPVOID)This->Buffer;
293 *pdwAudioBytes1 = This->BufferSize;
294 if (ppvAudioPtr2)
295 *ppvAudioPtr2 = NULL;
296 if (pdwAudioBytes2)
297 *pdwAudioBytes2 = 0;
298
299 return DS_OK;
300 }
301 else
302 {
303 ASSERT(dwOffset < This->BufferSize);
304 ASSERT(dwBytes < This->BufferSize);
305 ASSERT(dwBytes + dwOffset <= This->BufferSize);
306
307 *ppvAudioPtr1 = This->Buffer + dwOffset;
308 *pdwAudioBytes1 = dwBytes;
309 if (ppvAudioPtr2)
310 *ppvAudioPtr2 = NULL;
311 if (pdwAudioBytes2)
312 *pdwAudioBytes2 = 0;
313
314 return DS_OK;
315 }
316 }
317
318 HRESULT
319 WINAPI
320 IDirectSoundCaptureBufferImpl_Start(
321 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
322 DWORD dwFlags )
323 {
324 KSPROPERTY Property;
325 KSSTREAM_HEADER Header;
326 DWORD Result, BytesTransferred;
327 OVERLAPPED Overlapped;
328 KSSTATE State;
329 LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl, lpVtbl);
330
331 DPRINT("IDirectSoundCaptureBufferImpl_Start Flags %x\n", dwFlags);
332 ASSERT(dwFlags == DSCBSTART_LOOPING);
333
334 /* check if pin is already running */
335 if (This->State == KSSTATE_RUN)
336 return DS_OK;
337
338 /* sanity check */
339 ASSERT(This->hPin);
340
341 /* setup request */
342 Property.Set = KSPROPSETID_Connection;
343 Property.Id = KSPROPERTY_CONNECTION_STATE;
344 Property.Flags = KSPROPERTY_TYPE_SET;
345 State = KSSTATE_RUN;
346
347 /* set pin to run */
348 Result = SyncOverlappedDeviceIoControl(This->hPin, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&State, sizeof(KSSTATE), &BytesTransferred);
349
350 ASSERT(Result == ERROR_SUCCESS);
351
352 if (Result == ERROR_SUCCESS)
353 {
354 /* store result */
355 This->State = State;
356 }
357
358 /* initialize overlapped struct */
359 ZeroMemory(&Overlapped, sizeof(OVERLAPPED));
360 Overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
361
362 /* clear stream header */
363 ZeroMemory(&Header, sizeof(KSSTREAM_HEADER));
364
365 /* initialize stream header */
366 Header.FrameExtent = This->BufferSize;
367 Header.DataUsed = 0;
368 Header.Data = This->Buffer;
369 Header.Size = sizeof(KSSTREAM_HEADER);
370 Header.PresentationTime.Numerator = 1;
371 Header.PresentationTime.Denominator = 1;
372
373 Result = DeviceIoControl(This->hPin, IOCTL_KS_WRITE_STREAM, NULL, 0, &Header, sizeof(KSSTREAM_HEADER), &BytesTransferred, &Overlapped);
374
375 if (Result != ERROR_SUCCESS)
376 {
377 DPRINT("Failed submit buffer with %lx\n", Result);
378 return DSERR_GENERIC;
379 }
380
381 return DS_OK;
382 }
383
384 HRESULT
385 WINAPI
386 IDirectSoundCaptureBufferImpl_Stop( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
387 {
388 UNIMPLEMENTED
389 return DSERR_INVALIDPARAM;
390 }
391
392 HRESULT
393 WINAPI
394 IDirectSoundCaptureBufferImpl_Unlock(
395 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
396 LPVOID lpvAudioPtr1,
397 DWORD dwAudioBytes1,
398 LPVOID lpvAudioPtr2,
399 DWORD dwAudioBytes2 )
400 {
401 return DS_OK;
402 }
403
404 HRESULT
405 WINAPI
406 IDirectSoundCaptureBufferImpl_GetObjectInPath(
407 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
408 REFGUID rguidObject,
409 DWORD dwIndex,
410 REFGUID rguidInterface,
411 LPVOID* ppObject )
412 {
413 UNIMPLEMENTED
414 return DSERR_INVALIDPARAM;
415 }
416
417 HRESULT
418 WINAPI
419 IDirectSoundCaptureBufferImpl_GetFXStatus(
420 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
421 DWORD dwFXCount,
422 LPDWORD pdwFXStatus )
423 {
424 UNIMPLEMENTED
425 return DSERR_INVALIDPARAM;
426 }
427
428
429 static IDirectSoundCaptureBuffer8Vtbl vt_DirectSoundCaptureBuffer8 =
430 {
431 /* IUnknown methods */
432 IDirectSoundCaptureBufferImpl_QueryInterface,
433 IDirectSoundCaptureBufferImpl_AddRef,
434 IDirectSoundCaptureBufferImpl_Release,
435
436 /* IDirectSoundCaptureBuffer methods */
437 IDirectSoundCaptureBufferImpl_GetCaps,
438 IDirectSoundCaptureBufferImpl_GetCurrentPosition,
439 IDirectSoundCaptureBufferImpl_GetFormat,
440 IDirectSoundCaptureBufferImpl_GetStatus,
441 IDirectSoundCaptureBufferImpl_Initialize,
442 IDirectSoundCaptureBufferImpl_Lock,
443 IDirectSoundCaptureBufferImpl_Start,
444 IDirectSoundCaptureBufferImpl_Stop,
445 IDirectSoundCaptureBufferImpl_Unlock,
446
447 /* IDirectSoundCaptureBuffer methods */
448 IDirectSoundCaptureBufferImpl_GetObjectInPath,
449 IDirectSoundCaptureBufferImpl_GetFXStatus
450 };
451
452
453 HRESULT
454 NewDirectSoundCaptureBuffer(
455 LPDIRECTSOUNDCAPTUREBUFFER8 *OutBuffer,
456 LPFILTERINFO Filter,
457 LPCDSCBUFFERDESC lpcDSBufferDesc)
458 {
459 DWORD FormatSize;
460 ULONG DeviceId = 0, PinId;
461 DWORD Result = ERROR_SUCCESS;
462 WAVEFORMATEX MixFormat;
463
464 LPCDirectSoundCaptureBufferImpl This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CDirectSoundCaptureBufferImpl));
465
466 if (!This)
467 {
468 /* not enough memory */
469 return DSERR_OUTOFMEMORY;
470 }
471
472 /* calculate format size */
473 FormatSize = sizeof(WAVEFORMATEX) + lpcDSBufferDesc->lpwfxFormat->cbSize;
474 /* allocate format struct */
475 This->Format = HeapAlloc(GetProcessHeap(), 0, FormatSize);
476 if (!This->Format)
477 {
478 /* not enough memory */
479 HeapFree(GetProcessHeap(), 0, This);
480 return DSERR_OUTOFMEMORY;
481 }
482
483 /* sanity check */
484 ASSERT(lpcDSBufferDesc->dwBufferBytes);
485
486 /* allocate capture buffer */
487 This->Buffer = HeapAlloc(GetProcessHeap(), 0, lpcDSBufferDesc->dwBufferBytes);
488 if (!This->Buffer)
489 {
490 /* not enough memory */
491 HeapFree(GetProcessHeap(), 0, This->Format);
492 HeapFree(GetProcessHeap(), 0, This);
493 return DSERR_OUTOFMEMORY;
494 }
495
496 /* store buffer size */
497 This->BufferSize = lpcDSBufferDesc->dwBufferBytes;
498 ASSERT(lpcDSBufferDesc->lpwfxFormat->cbSize == 0);
499
500 do
501 {
502 /* try all available recording pins on that filter */
503 PinId = GetPinIdFromFilter(Filter, TRUE, DeviceId);
504
505 if (PinId == ULONG_MAX)
506 break;
507
508 Result = OpenPin(Filter->hFilter, PinId, lpcDSBufferDesc->lpwfxFormat, &This->hPin, TRUE);
509 if (Result == ERROR_SUCCESS)
510 break;
511
512 DeviceId++;
513 }while(TRUE);
514
515 if (Result != ERROR_SUCCESS)
516 {
517 /* failed to instantiate the capture pin with the native format
518 * try to compute a compatible format and use that
519 * we could use the mixer api for this purpose but... the kmixer isnt working very good atm
520 */
521
522 DeviceId = 0;
523 do
524 {
525 /* try all available recording pins on that filter */
526 PinId = GetPinIdFromFilter(Filter, TRUE, DeviceId);
527 DPRINT("PinId %u DeviceId %u\n", PinId, DeviceId);
528
529 if (PinId == ULONG_MAX)
530 break;
531
532 if (CreateCompatiblePin(Filter->hFilter, PinId, TRUE, lpcDSBufferDesc->lpwfxFormat, &MixFormat, &This->hPin))
533 {
534 This->bMix = TRUE;
535 CopyMemory(&This->MixFormat, &MixFormat, sizeof(WAVEFORMATEX));
536 break;
537 }
538
539 DeviceId++;
540 }while(TRUE);
541
542
543 if (!This->bMix)
544 {
545 /* FIXME should not happen */
546 DPRINT("failed to compute a compatible format\n");
547 HeapFree(GetProcessHeap(), 0, This->Buffer);
548 HeapFree(GetProcessHeap(), 0, This->Format);
549 HeapFree(GetProcessHeap(), 0, This);
550 return DSERR_GENERIC;
551 }
552 }
553
554 /* initialize capture buffer */
555 This->ref = 1;
556 This->lpVtbl = &vt_DirectSoundCaptureBuffer8;
557 This->Filter = Filter;
558 This->State = KSSTATE_STOP;
559 This->bLoop = TRUE;
560
561 RtlMoveMemory(This->Format, lpcDSBufferDesc->lpwfxFormat, FormatSize);
562
563 *OutBuffer = (LPDIRECTSOUNDCAPTUREBUFFER8)&This->lpVtbl;
564 return DS_OK;
565 }