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