[DSOUND_NEW]
[reactos.git] / reactos / dll / directx / dsound_new / primary.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Configuration of network devices
4 * FILE: dll/directx/dsound_new/primary.c
5 * PURPOSE: Primary IDirectSoundBuffer8 implementation
6 *
7 * PROGRAMMERS: Johannes Anderwald (janderwald@reactos.org)
8 */
9
10
11 #include "precomp.h"
12
13 typedef struct
14 {
15 const IDirectSoundBuffer8Vtbl *lpVtbl;
16 LONG ref;
17
18 LPFILTERINFO Filter;
19 DWORD dwLevel;
20 WAVEFORMATEX Format;
21 HANDLE hPin;
22 CRITICAL_SECTION Lock;
23 KSSTATE State;
24 }CDirectSoundBuffer, *LPCDirectSoundBuffer;
25
26 HRESULT
27 WINAPI
28 PrimaryDirectSoundBuffer8Impl_fnQueryInterface(
29 LPDIRECTSOUNDBUFFER8 iface,
30 IN REFIID riid,
31 LPVOID* ppobj)
32 {
33 LPOLESTR pStr;
34 LPCDirectSoundBuffer This = (LPCDirectSoundBuffer)CONTAINING_RECORD(iface, CDirectSoundBuffer, lpVtbl);
35
36 if (IsEqualIID(riid, &IID_IUnknown) ||
37 IsEqualIID(riid, &IID_IDirectSoundBuffer) ||
38 IsEqualIID(riid, &IID_IDirectSoundBuffer8))
39 {
40 *ppobj = (LPVOID)&This->lpVtbl;
41 InterlockedIncrement(&This->ref);
42 return S_OK;
43 }
44
45 if (SUCCEEDED(StringFromIID(riid, &pStr)))
46 {
47 DPRINT("No Interface for class %s\n", pStr);
48 CoTaskMemFree(pStr);
49 }
50 return E_NOINTERFACE;
51 }
52
53 ULONG
54 WINAPI
55 PrimaryDirectSoundBuffer8Impl_fnAddRef(
56 LPDIRECTSOUNDBUFFER8 iface)
57 {
58 ULONG ref;
59 LPCDirectSoundBuffer This = (LPCDirectSoundBuffer)CONTAINING_RECORD(iface, CDirectSoundBuffer, lpVtbl);
60
61 ref = InterlockedIncrement(&This->ref);
62
63 return ref;
64
65 }
66
67 ULONG
68 WINAPI
69 PrimaryDirectSoundBuffer8Impl_fnRelease(
70 LPDIRECTSOUNDBUFFER8 iface)
71 {
72 ULONG ref;
73 LPCDirectSoundBuffer This = (LPCDirectSoundBuffer)CONTAINING_RECORD(iface, CDirectSoundBuffer, lpVtbl);
74
75 ref = InterlockedDecrement(&(This->ref));
76
77 if (!ref)
78 {
79 if (This->hPin)
80 {
81 /* close pin handle */
82 CloseHandle(This->hPin);
83 }
84 /* free primary buffer */
85 HeapFree(GetProcessHeap(), 0, This);
86 }
87
88 return ref;
89 }
90
91 HRESULT
92 WINAPI
93 PrimaryDirectSoundBuffer8Impl_fnGetCaps(
94 LPDIRECTSOUNDBUFFER8 iface,
95 LPDSBCAPS pDSBufferCaps)
96 {
97 UNIMPLEMENTED
98 return DSERR_INVALIDPARAM;
99 }
100
101 HRESULT
102 WINAPI
103 PrimaryDirectSoundBuffer8Impl_fnGetCurrentPosition(
104 LPDIRECTSOUNDBUFFER8 iface,
105 LPDWORD pdwCurrentPlayCursor,
106 LPDWORD pdwCurrentWriteCursor)
107 {
108 UNIMPLEMENTED
109 return DSERR_INVALIDPARAM;
110 }
111
112 HRESULT
113 WINAPI
114 PrimaryDirectSoundBuffer8Impl_fnGetFormat(
115 LPDIRECTSOUNDBUFFER8 iface,
116 LPWAVEFORMATEX pwfxFormat,
117 DWORD dwSizeAllocated,
118 LPDWORD pdwSizeWritten)
119 {
120 DWORD FormatSize;
121 LPCDirectSoundBuffer This = (LPCDirectSoundBuffer)CONTAINING_RECORD(iface, CDirectSoundBuffer, lpVtbl);
122
123 FormatSize = sizeof(WAVEFORMATEX) + This->Format.cbSize;
124
125 if (!pwfxFormat && !pdwSizeWritten)
126 {
127 /* invalid parameter */
128 return DSERR_INVALIDPARAM;
129 }
130
131 if (!pwfxFormat)
132 {
133 /* return required format size */
134 *pdwSizeWritten = FormatSize;
135 return DS_OK;
136 }
137 else
138 {
139 if (dwSizeAllocated >= FormatSize)
140 {
141 /* copy format */
142 CopyMemory(pwfxFormat, &This->Format, FormatSize);
143
144 if (pdwSizeWritten)
145 *pdwSizeWritten = FormatSize;
146
147 return DS_OK;
148 }
149 /* buffer too small */
150 if (pdwSizeWritten)
151 *pdwSizeWritten = 0;
152
153 return DSERR_INVALIDPARAM;
154 }
155 }
156
157 HRESULT
158 WINAPI
159 PrimaryDirectSoundBuffer8Impl_fnGetVolume(
160 LPDIRECTSOUNDBUFFER8 iface,
161 LPLONG plVolume)
162 {
163 UNIMPLEMENTED
164 return DSERR_INVALIDPARAM;
165 }
166
167 HRESULT
168 WINAPI
169 PrimaryDirectSoundBuffer8Impl_fnGetPan(
170 LPDIRECTSOUNDBUFFER8 iface,
171 LPLONG plPan)
172 {
173 UNIMPLEMENTED
174 return DSERR_INVALIDPARAM;
175 }
176
177 HRESULT
178 WINAPI
179 PrimaryDirectSoundBuffer8Impl_fnGetFrequency(
180 LPDIRECTSOUNDBUFFER8 iface,
181 LPDWORD pdwFrequency)
182 {
183 UNIMPLEMENTED
184 return DSERR_INVALIDPARAM;
185 }
186
187 HRESULT
188 WINAPI
189 PrimaryDirectSoundBuffer8Impl_fnGetStatus(
190 LPDIRECTSOUNDBUFFER8 iface,
191 LPDWORD pdwStatus)
192 {
193 UNIMPLEMENTED
194 return DSERR_INVALIDPARAM;
195 }
196
197 HRESULT
198 WINAPI
199 PrimaryDirectSoundBuffer8Impl_fnInitialize(
200 LPDIRECTSOUNDBUFFER8 iface,
201 LPDIRECTSOUND pDirectSound,
202 LPCDSBUFFERDESC pcDSBufferDesc)
203 {
204 UNIMPLEMENTED
205 return DSERR_INVALIDPARAM;
206 }
207
208 HRESULT
209 WINAPI
210 PrimaryDirectSoundBuffer8Impl_fnLock(
211 LPDIRECTSOUNDBUFFER8 iface,
212 DWORD dwOffset,
213 DWORD dwBytes,
214 LPVOID *ppvAudioPtr1,
215 LPDWORD pdwAudioBytes1,
216 LPVOID *ppvAudioPtr2,
217 LPDWORD pdwAudioBytes2,
218 DWORD dwFlags)
219 {
220 UNIMPLEMENTED
221 return DSERR_INVALIDPARAM;
222 }
223
224 HRESULT
225 WINAPI
226 PrimaryDirectSoundBuffer8Impl_fnPlay(
227 LPDIRECTSOUNDBUFFER8 iface,
228 DWORD dwReserved1,
229 DWORD dwPriority,
230 DWORD dwFlags)
231 {
232 LPCDirectSoundBuffer This = (LPCDirectSoundBuffer)CONTAINING_RECORD(iface, CDirectSoundBuffer, lpVtbl);
233
234 if (dwReserved1 != 0 || !(dwFlags & DSBPLAY_LOOPING))
235 {
236 /* invalid parameter */
237 return DSERR_INVALIDPARAM;
238 }
239
240 PrimaryDirectSoundBuffer_AcquireLock(iface);
241
242 if (This->State == KSSTATE_STOP)
243 {
244 PrimaryDirectSoundBuffer_SetState(iface, KSSTATE_ACQUIRE);
245 ASSERT(This->State == KSSTATE_ACQUIRE);
246 }
247
248 if (This->State == KSSTATE_ACQUIRE)
249 {
250 PrimaryDirectSoundBuffer_SetState(iface, KSSTATE_PAUSE);
251 ASSERT(This->State == KSSTATE_PAUSE);
252 }
253
254 if (This->State == KSSTATE_PAUSE)
255 {
256 PrimaryDirectSoundBuffer_SetState(iface, KSSTATE_RUN);
257 ASSERT(This->State == KSSTATE_RUN);
258 }
259
260 PrimaryDirectSoundBuffer_ReleaseLock(iface);
261
262 return DS_OK;
263 }
264
265 HRESULT
266 WINAPI
267 PrimaryDirectSoundBuffer8Impl_fnSetCurrentPosition(
268 LPDIRECTSOUNDBUFFER8 iface,
269 DWORD dwNewPosition)
270 {
271 /* The position of a primary buffer can't be set */
272 return DSERR_INVALIDCALL;
273 }
274
275 HRESULT
276 WINAPI
277 PrimaryDirectSoundBuffer8Impl_fnSetFormat(
278 LPDIRECTSOUNDBUFFER8 iface,
279 LPCWAVEFORMATEX pcfxFormat)
280 {
281 LPCDirectSoundBuffer This = (LPCDirectSoundBuffer)CONTAINING_RECORD(iface, CDirectSoundBuffer, lpVtbl);
282
283 if (This->dwLevel == DSSCL_NORMAL)
284 {
285 /* can't change format with this level */
286 return DSERR_PRIOLEVELNEEDED;
287 }
288
289 ASSERT(pcfxFormat->cbSize == 0);
290
291
292 DPRINT("This %p Format: Tag %x nChannels %u nSamplesPerSec %u nAvgBytesPerSec %u nBlockAlign %u wBitsPerSample %u cbSize %u\n", This,
293 pcfxFormat->wFormatTag, pcfxFormat->nChannels, pcfxFormat->nSamplesPerSec, pcfxFormat->nAvgBytesPerSec, pcfxFormat->nBlockAlign, pcfxFormat->wBitsPerSample, pcfxFormat->cbSize);
294
295 CopyMemory(&This->Format, pcfxFormat, sizeof(WAVEFORMATEX));
296
297 return DS_OK;
298 }
299
300 HRESULT
301 WINAPI
302 PrimaryDirectSoundBuffer8Impl_fnSetVolume(
303 LPDIRECTSOUNDBUFFER8 iface,
304 LONG lVolume)
305 {
306 UNIMPLEMENTED
307 return DSERR_INVALIDPARAM;
308 }
309
310 HRESULT
311 WINAPI
312 PrimaryDirectSoundBuffer8Impl_fnSetPan(
313 LPDIRECTSOUNDBUFFER8 iface,
314 LONG lPan)
315 {
316 UNIMPLEMENTED
317 return DSERR_INVALIDPARAM;
318 }
319
320 HRESULT
321 WINAPI
322 PrimaryDirectSoundBuffer8Impl_fnSetFrequency(
323 LPDIRECTSOUNDBUFFER8 iface,
324 DWORD dwFrequency)
325 {
326 UNIMPLEMENTED
327 return DSERR_INVALIDPARAM;
328 }
329
330 HRESULT
331 WINAPI
332 PrimaryDirectSoundBuffer8Impl_fnStop(
333 LPDIRECTSOUNDBUFFER8 iface)
334 {
335 LPCDirectSoundBuffer This = (LPCDirectSoundBuffer)CONTAINING_RECORD(iface, CDirectSoundBuffer, lpVtbl);
336
337 PrimaryDirectSoundBuffer_AcquireLock(iface);
338
339 if (This->State == KSSTATE_RUN)
340 {
341 PrimaryDirectSoundBuffer_SetState(iface, KSSTATE_PAUSE);
342 ASSERT(This->State == KSSTATE_PAUSE);
343 }
344
345 if (This->State == KSSTATE_PAUSE)
346 {
347 PrimaryDirectSoundBuffer_SetState(iface, KSSTATE_ACQUIRE);
348 ASSERT(This->State == KSSTATE_ACQUIRE);
349 }
350
351 if (This->State == KSSTATE_ACQUIRE)
352 {
353 PrimaryDirectSoundBuffer_SetState(iface, KSSTATE_STOP);
354 ASSERT(This->State == KSSTATE_STOP);
355 }
356
357 PrimaryDirectSoundBuffer_ReleaseLock(iface);
358
359 return DS_OK;
360 }
361
362
363 HRESULT
364 WINAPI
365 PrimaryDirectSoundBuffer8Impl_fnUnlock(
366 LPDIRECTSOUNDBUFFER8 iface,
367 LPVOID pvAudioPtr1,
368 DWORD dwAudioBytes1,
369 LPVOID pvAudioPtr2,
370 DWORD dwAudioBytes2)
371 {
372 UNIMPLEMENTED
373 return DSERR_INVALIDPARAM;
374 }
375
376
377
378
379 HRESULT
380 WINAPI
381 PrimaryDirectSoundBuffer8Impl_fnRestore(
382 LPDIRECTSOUNDBUFFER8 iface)
383 {
384 UNIMPLEMENTED
385 return DSERR_INVALIDPARAM;
386 }
387
388
389 HRESULT
390 WINAPI
391 PrimaryDirectSoundBuffer8Impl_fnSetFX(
392 LPDIRECTSOUNDBUFFER8 iface,
393 DWORD dwEffectsCount,
394 LPDSEFFECTDESC pDSFXDesc,
395 LPDWORD pdwResultCodes)
396 {
397 UNIMPLEMENTED
398 return DSERR_INVALIDPARAM;
399 }
400
401 HRESULT
402 WINAPI
403 PrimaryDirectSoundBuffer8Impl_fnAcquireResources(
404 LPDIRECTSOUNDBUFFER8 iface,
405 DWORD dwFlags,
406 DWORD dwEffectsCount,
407 LPDWORD pdwResultCodes)
408 {
409 UNIMPLEMENTED
410 return DSERR_INVALIDPARAM;
411 }
412
413 HRESULT
414 WINAPI
415 PrimaryDirectSoundBuffer8Impl_fnGetObjectInPath(
416 LPDIRECTSOUNDBUFFER8 iface,
417 REFGUID rguidObject,
418 DWORD dwIndex,
419 REFGUID rguidInterface,
420 LPVOID *ppObject)
421 {
422 UNIMPLEMENTED
423 return DSERR_INVALIDPARAM;
424 }
425
426 static IDirectSoundBuffer8Vtbl vt_DirectSoundBuffer8 =
427 {
428 /* IUnknown methods */
429 PrimaryDirectSoundBuffer8Impl_fnQueryInterface,
430 PrimaryDirectSoundBuffer8Impl_fnAddRef,
431 PrimaryDirectSoundBuffer8Impl_fnRelease,
432 /* IDirectSoundBuffer methods */
433 PrimaryDirectSoundBuffer8Impl_fnGetCaps,
434 PrimaryDirectSoundBuffer8Impl_fnGetCurrentPosition,
435 PrimaryDirectSoundBuffer8Impl_fnGetFormat,
436 PrimaryDirectSoundBuffer8Impl_fnGetVolume,
437 PrimaryDirectSoundBuffer8Impl_fnGetPan,
438 PrimaryDirectSoundBuffer8Impl_fnGetFrequency,
439 PrimaryDirectSoundBuffer8Impl_fnGetStatus,
440 PrimaryDirectSoundBuffer8Impl_fnInitialize,
441 PrimaryDirectSoundBuffer8Impl_fnLock,
442 PrimaryDirectSoundBuffer8Impl_fnPlay,
443 PrimaryDirectSoundBuffer8Impl_fnSetCurrentPosition,
444 PrimaryDirectSoundBuffer8Impl_fnSetFormat,
445 PrimaryDirectSoundBuffer8Impl_fnSetVolume,
446 PrimaryDirectSoundBuffer8Impl_fnSetPan,
447 PrimaryDirectSoundBuffer8Impl_fnSetFrequency,
448 PrimaryDirectSoundBuffer8Impl_fnStop,
449 PrimaryDirectSoundBuffer8Impl_fnUnlock,
450 PrimaryDirectSoundBuffer8Impl_fnRestore,
451 /* IDirectSoundBuffer8 methods */
452 PrimaryDirectSoundBuffer8Impl_fnSetFX,
453 PrimaryDirectSoundBuffer8Impl_fnAcquireResources,
454 PrimaryDirectSoundBuffer8Impl_fnGetObjectInPath
455 };
456
457 DWORD
458 PrimaryDirectSoundBuffer_Write(
459 LPDIRECTSOUNDBUFFER8 iface,
460 LPVOID Buffer,
461 DWORD BufferSize)
462 {
463 KSSTREAM_HEADER Header;
464 DWORD Result, BytesTransferred;
465 OVERLAPPED Overlapped;
466
467 LPCDirectSoundBuffer This = (LPCDirectSoundBuffer)CONTAINING_RECORD(iface, CDirectSoundBuffer, lpVtbl);
468
469 ZeroMemory(&Overlapped, sizeof(OVERLAPPED));
470 Overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
471
472
473 ASSERT(This->hPin);
474 ZeroMemory(&Header, sizeof(KSSTREAM_HEADER));
475
476 Header.FrameExtent = BufferSize;
477 Header.DataUsed = BufferSize;
478 Header.Data = Buffer;
479 Header.Size = sizeof(KSSTREAM_HEADER);
480 Header.PresentationTime.Numerator = 1;
481 Header.PresentationTime.Denominator = 1;
482
483 Result = DeviceIoControl(This->hPin, IOCTL_KS_WRITE_STREAM, NULL, 0, &Header, sizeof(KSSTREAM_HEADER), &BytesTransferred, &Overlapped);
484
485 if (Result != ERROR_SUCCESS)
486 return 0;
487
488 return BytesTransferred;
489 }
490
491 VOID
492 PrimaryDirectSoundBuffer_SetState(
493 LPDIRECTSOUNDBUFFER8 iface,
494 KSSTATE State)
495 {
496 KSPROPERTY Property;
497 DWORD Result, BytesTransferred;
498 LPCDirectSoundBuffer This = (LPCDirectSoundBuffer)CONTAINING_RECORD(iface, CDirectSoundBuffer, lpVtbl);
499
500 if (This->State == State)
501 return;
502
503 Property.Set = KSPROPSETID_Connection;
504 Property.Id = KSPROPERTY_CONNECTION_STATE;
505 Property.Flags = KSPROPERTY_TYPE_SET;
506
507 Result = SyncOverlappedDeviceIoControl(This->hPin, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&State, sizeof(KSSTATE), &BytesTransferred);
508 if (Result == ERROR_SUCCESS)
509 {
510 This->State = State;
511 }
512 }
513
514 HRESULT
515 PrimaryDirectSoundBuffer_GetPosition(
516 LPDIRECTSOUNDBUFFER8 iface,
517 LPDWORD pdwCurrentPlayCursor,
518 LPDWORD pdwCurrentWriteCursor)
519 {
520 KSAUDIO_POSITION Position;
521 KSPROPERTY Request;
522 DWORD Result;
523
524 LPCDirectSoundBuffer This = (LPCDirectSoundBuffer)CONTAINING_RECORD(iface, CDirectSoundBuffer, lpVtbl);
525
526 if (!This->hPin)
527 {
528 if (pdwCurrentPlayCursor)
529 *pdwCurrentPlayCursor = 0;
530
531 if (pdwCurrentWriteCursor)
532 *pdwCurrentWriteCursor = 0;
533
534 DPRINT("No Audio Pin\n");
535 return DS_OK;
536 }
537
538 /* setup audio position property request */
539 Request.Id = KSPROPERTY_AUDIO_POSITION;
540 Request.Set = KSPROPSETID_Audio;
541 Request.Flags = KSPROPERTY_TYPE_GET;
542
543
544 Result = SyncOverlappedDeviceIoControl(This->hPin, IOCTL_KS_PROPERTY, (PVOID)&Request, sizeof(KSPROPERTY), (PVOID)&Position, sizeof(KSAUDIO_POSITION), NULL);
545
546 if (Result != ERROR_SUCCESS)
547 {
548 DPRINT("GetPosition failed with %x\n", Result);
549 return DSERR_UNSUPPORTED;
550 }
551
552 //DPRINT("Play %I64u Write %I64u \n", Position.PlayOffset, Position.WriteOffset);
553
554 if (pdwCurrentPlayCursor)
555 *pdwCurrentPlayCursor = (DWORD)Position.PlayOffset;
556
557 if (pdwCurrentWriteCursor)
558 *pdwCurrentWriteCursor = (DWORD)Position.WriteOffset;
559
560 return DS_OK;
561 }
562
563 HRESULT
564 PrimaryDirectSoundBuffer_SetFormat(
565 LPDIRECTSOUNDBUFFER8 iface,
566 LPWAVEFORMATEX pcfxFormat,
567 BOOL bLooped)
568 {
569 ULONG PinId, DeviceId = 0, Result;
570 LPCDirectSoundBuffer This = (LPCDirectSoundBuffer)CONTAINING_RECORD(iface, CDirectSoundBuffer, lpVtbl);
571
572 if (This->hPin)
573 {
574 // FIXME
575 // check if multiple buffers are active
576 // in that case need mixing
577
578 if (SetPinFormat(This->hPin, pcfxFormat))
579 return DS_OK;
580 else
581 return DSERR_GENERIC;
582 }
583
584 do
585 {
586 /* try all available recording pins on that filter */
587 PinId = GetPinIdFromFilter(This->Filter, FALSE, DeviceId);
588 DPRINT("PinId %u DeviceId %u\n", PinId, DeviceId);
589
590 if (PinId == ULONG_MAX)
591 break;
592
593 Result = OpenPin(This->Filter->hFilter, PinId, (LPWAVEFORMATEX)pcfxFormat, &This->hPin, bLooped);
594 DPRINT("PinId %u Result %u\n", PinId, Result);
595 if (Result == ERROR_SUCCESS)
596 break;
597
598 This->hPin = NULL;
599 DeviceId++;
600 }while(TRUE);
601
602 if (!This->hPin)
603 {
604 DPRINT("PrimaryDirectSoundBuffer8Impl_fnSetFormat failed\n");
605 return DSERR_INVALIDPARAM;
606 }
607
608 DPRINT("PrimaryDirectSoundBuffer8Impl_fnSetFormat success\n");
609 return DS_OK;
610 }
611
612 VOID
613 PrimaryDirectSoundBuffer_AcquireLock(
614 LPDIRECTSOUNDBUFFER8 iface)
615 {
616 LPCDirectSoundBuffer This = (LPCDirectSoundBuffer)CONTAINING_RECORD(iface, CDirectSoundBuffer, lpVtbl);
617
618 EnterCriticalSection(&This->Lock);
619
620
621 }
622
623 VOID
624 PrimaryDirectSoundBuffer_ReleaseLock(
625 LPDIRECTSOUNDBUFFER8 iface)
626 {
627 LPCDirectSoundBuffer This = (LPCDirectSoundBuffer)CONTAINING_RECORD(iface, CDirectSoundBuffer, lpVtbl);
628
629 LeaveCriticalSection(&This->Lock);
630
631 }
632
633
634 HRESULT
635 NewPrimarySoundBuffer(
636 LPDIRECTSOUNDBUFFER8 *OutBuffer,
637 LPFILTERINFO Filter,
638 DWORD dwLevel)
639 {
640 LPCDirectSoundBuffer This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CDirectSoundBuffer));
641
642 if (!This)
643 {
644 /* not enough memory */
645 return DSERR_OUTOFMEMORY;
646 }
647
648 This->ref = 1;
649 This->lpVtbl = &vt_DirectSoundBuffer8;
650 This->Filter = Filter;
651 This->dwLevel = dwLevel;
652 This->hPin = NULL;
653
654 InitializeCriticalSection(&This->Lock);
655
656 *OutBuffer = (LPDIRECTSOUNDBUFFER8)&This->lpVtbl;
657 return DS_OK;
658 }
659