3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998 Rob Riggs
5 * Copyright 2000 Ove Kåven, TransGaming Technologies, Inc.
8 * Most thread locking is complete. There may be a few race
9 * conditions still lurking.
11 * Tested with a Soundblaster clone, a Gravis UltraSound Classic,
12 * and a Turtle Beach Tropez+.
15 * Implement DirectSoundCapture API
16 * Implement SetCooperativeLevel properly (need to address focus issues)
17 * Implement DirectSound3DBuffers (stubs in place)
18 * Use hardware 3D support if available
19 * Add critical section locking inside Release and AddRef methods
20 * Handle static buffers - put those in hardware, non-static not in hardware
21 * Hardware DuplicateSoundBuffer
22 * Proper volume calculation, and setting volume in HEL primary buffer
23 * Optimize WINMM and negotiate fragment size, decrease DS_HEL_MARGIN
29 #include <sys/types.h>
30 #include <sys/fcntl.h>
34 #include <math.h> /* Insomnia - pow() function */
41 #include "wine/windef16.h"
42 #include "debugtools.h"
48 DEFAULT_DEBUG_CHANNEL(dsound);
50 /* these are eligible for tuning... they must be high on slow machines... */
51 /* especially since the WINMM overhead is pretty high, and could be improved quite a bit;
52 * the high DS_HEL_MARGIN reflects the currently high wineoss/HEL latency
53 * some settings here should probably get ported to wine.conf */
54 #define DS_EMULDRIVER 1 /* some games (Quake 2, UT) refuse to accept
55 emulated dsound devices. set to 0 ! */
56 #define DS_HEL_FRAGS 48 /* HEL only: number of waveOut fragments in primary buffer */
57 #define DS_HEL_QUEUE 28 /* HEL only: number of waveOut fragments to prebuffer */
58 /* (Starcraft videos won't work with higher than 32 x10ms) */
59 #define DS_HEL_MARGIN 4 /* HEL only: number of waveOut fragments ahead to mix in new buffers */
61 #define DS_HAL_QUEUE 28 /* HAL only: max number of fragments to prebuffer */
63 /* Linux does not support better timing than 10ms */
64 #define DS_TIME_RES 10 /* Resolution of multimedia timer */
65 #define DS_TIME_DEL 10 /* Delay of multimedia timer callback, and duration of HEL fragment */
67 /*****************************************************************************
68 * Predeclare the interface implementation structures
70 typedef struct IDirectSoundImpl IDirectSoundImpl;
71 typedef struct IDirectSoundBufferImpl IDirectSoundBufferImpl;
72 typedef struct IDirectSoundNotifyImpl IDirectSoundNotifyImpl;
73 typedef struct IDirectSound3DListenerImpl IDirectSound3DListenerImpl;
74 typedef struct IDirectSound3DBufferImpl IDirectSound3DBufferImpl;
75 typedef struct IDirectSoundCaptureImpl IDirectSoundCaptureImpl;
76 typedef struct IDirectSoundCaptureBufferImpl IDirectSoundCaptureBufferImpl;
78 /*****************************************************************************
79 * IDirectSound implementation structure
81 struct IDirectSoundImpl
84 ICOM_VFIELD(IDirectSound);
86 /* IDirectSoundImpl fields */
91 LPWAVEHDR pwave[DS_HEL_FRAGS];
92 UINT timerID, pwplay, pwwrite, pwqueue;
96 IDirectSoundBufferImpl** buffers;
97 IDirectSoundBufferImpl* primary;
98 IDirectSound3DListenerImpl* listener;
99 WAVEFORMATEX wfx; /* current main waveformat */
100 CRITICAL_SECTION lock;
103 /*****************************************************************************
104 * IDirectSoundBuffer implementation structure
106 struct IDirectSoundBufferImpl
108 /* IUnknown fields */
109 ICOM_VFIELD(IDirectSoundBuffer);
111 /* IDirectSoundBufferImpl fields */
112 PIDSDRIVERBUFFER hwbuf;
115 IDirectSound3DBufferImpl* ds3db;
116 DWORD playflags,state,leadin;
117 DWORD playpos,mixpos,startpos,writelead,buflen;
118 DWORD nAvgBytesPerSec;
122 IDirectSoundBufferImpl* parent; /* for duplicates */
123 IDirectSoundImpl* dsound;
125 LPDSBPOSITIONNOTIFY notifies;
127 CRITICAL_SECTION lock;
130 #define STATE_STOPPED 0
131 #define STATE_STARTING 1
132 #define STATE_PLAYING 2
133 #define STATE_STOPPING 3
135 /*****************************************************************************
136 * IDirectSoundNotify implementation structure
138 struct IDirectSoundNotifyImpl
140 /* IUnknown fields */
141 ICOM_VFIELD(IDirectSoundNotify);
143 /* IDirectSoundNotifyImpl fields */
144 IDirectSoundBufferImpl* dsb;
147 /*****************************************************************************
148 * IDirectSound3DListener implementation structure
150 struct IDirectSound3DListenerImpl
152 /* IUnknown fields */
153 ICOM_VFIELD(IDirectSound3DListener);
155 /* IDirectSound3DListenerImpl fields */
156 IDirectSoundBufferImpl* dsb;
158 CRITICAL_SECTION lock;
161 /*****************************************************************************
162 * IDirectSound3DBuffer implementation structure
164 struct IDirectSound3DBufferImpl
166 /* IUnknown fields */
167 ICOM_VFIELD(IDirectSound3DBuffer);
169 /* IDirectSound3DBufferImpl fields */
170 IDirectSoundBufferImpl* dsb;
174 CRITICAL_SECTION lock;
178 /*****************************************************************************
179 * IDirectSoundCapture implementation structure
181 struct IDirectSoundCaptureImpl
183 /* IUnknown fields */
184 ICOM_VFIELD(IDirectSoundCapture);
187 /* IDirectSoundCaptureImpl fields */
188 CRITICAL_SECTION lock;
191 /*****************************************************************************
192 * IDirectSoundCapture implementation structure
194 struct IDirectSoundCaptureBufferImpl
196 /* IUnknown fields */
197 ICOM_VFIELD(IDirectSoundCaptureBuffer);
200 /* IDirectSoundCaptureBufferImpl fields */
201 CRITICAL_SECTION lock;
205 /* #define USE_DSOUND3D 1 */
207 #define DSOUND_FREQSHIFT (14)
209 static IDirectSoundImpl* dsound = NULL;
211 static IDirectSoundBufferImpl* primarybuf = NULL;
213 static void DSOUND_CheckEvent(IDirectSoundBufferImpl *dsb, int len);
215 static HRESULT DSOUND_CreateDirectSoundCapture( LPVOID* ppobj );
216 static HRESULT DSOUND_CreateDirectSoundCaptureBuffer( LPCDSCBUFFERDESC lpcDSCBufferDesc, LPVOID* ppobj );
218 static ICOM_VTABLE(IDirectSoundCapture) dscvt;
219 static ICOM_VTABLE(IDirectSoundCaptureBuffer) dscbvt;
221 static HRESULT mmErr(UINT err)
224 case MMSYSERR_NOERROR:
226 case MMSYSERR_ALLOCATED:
227 return DSERR_ALLOCATED;
228 case MMSYSERR_INVALHANDLE:
229 return DSERR_GENERIC; /* FIXME */
230 case MMSYSERR_NODRIVER:
231 return DSERR_NODRIVER;
233 return DSERR_OUTOFMEMORY;
234 case MMSYSERR_INVALPARAM:
235 return DSERR_INVALIDPARAM;
237 FIXME("Unknown MMSYS error %d\n",err);
238 return DSERR_GENERIC;
242 /***************************************************************************
243 * DirectSoundEnumerateA [DSOUND.2]
245 * Enumerate all DirectSound drivers installed in the system
249 * Failure: DSERR_INVALIDPARAM
251 HRESULT WINAPI DirectSoundEnumerateA(
252 LPDSENUMCALLBACKA lpDSEnumCallback,
255 TRACE("lpDSEnumCallback = %p, lpContext = %p\n",
256 lpDSEnumCallback, lpContext);
259 if (lpDSEnumCallback != NULL)
260 lpDSEnumCallback(NULL,"WINE DirectSound using Open Sound System",
267 /***************************************************************************
268 * DirectSoundEnumerateW [DSOUND.3]
270 * Enumerate all DirectSound drivers installed in the system
274 * Failure: DSERR_INVALIDPARAM
276 HRESULT WINAPI DirectSoundEnumerateW(
277 LPDSENUMCALLBACKW lpDSEnumCallback,
280 FIXME("lpDSEnumCallback = %p, lpContext = %p: stub\n",
281 lpDSEnumCallback, lpContext);
287 static void _dump_DSBCAPS(DWORD xmask) {
292 #define FE(x) { x, #x },
293 FE(DSBCAPS_PRIMARYBUFFER)
295 FE(DSBCAPS_LOCHARDWARE)
296 FE(DSBCAPS_LOCSOFTWARE)
298 FE(DSBCAPS_CTRLFREQUENCY)
300 FE(DSBCAPS_CTRLVOLUME)
301 FE(DSBCAPS_CTRLPOSITIONNOTIFY)
302 FE(DSBCAPS_CTRLDEFAULT)
304 FE(DSBCAPS_STICKYFOCUS)
305 FE(DSBCAPS_GLOBALFOCUS)
306 FE(DSBCAPS_GETCURRENTPOSITION2)
307 FE(DSBCAPS_MUTE3DATMAXDISTANCE)
312 for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
313 if ((flags[i].mask & xmask) == flags[i].mask)
314 DPRINTF("%s ",flags[i].name);
317 /*******************************************************************************
318 * IDirectSound3DBuffer
321 /* IUnknown methods */
323 static HRESULT WINAPI IDirectSound3DBufferImpl_QueryInterface(
324 LPDIRECTSOUND3DBUFFER iface, REFIID riid, LPVOID *ppobj)
326 ICOM_THIS(IDirectSound3DBufferImpl,iface);
328 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
334 static ULONG WINAPI IDirectSound3DBufferImpl_AddRef(LPDIRECTSOUND3DBUFFER iface)
336 ICOM_THIS(IDirectSound3DBufferImpl,iface);
343 static ULONG WINAPI IDirectSound3DBufferImpl_Release(LPDIRECTSOUND3DBUFFER iface)
345 ICOM_THIS(IDirectSound3DBufferImpl,iface);
347 TRACE("(%p) ref was %ld\n", This, This->ref);
353 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->dsb);
355 DeleteCriticalSection(&This->lock);
357 HeapFree(GetProcessHeap(),0,This->buffer);
358 HeapFree(GetProcessHeap(),0,This);
364 /* IDirectSound3DBuffer methods */
366 static HRESULT WINAPI IDirectSound3DBufferImpl_GetAllParameters(
367 LPDIRECTSOUND3DBUFFER iface,
368 LPDS3DBUFFER lpDs3dBuffer)
376 static HRESULT WINAPI IDirectSound3DBufferImpl_GetConeAngles(
377 LPDIRECTSOUND3DBUFFER iface,
378 LPDWORD lpdwInsideConeAngle,
379 LPDWORD lpdwOutsideConeAngle)
387 static HRESULT WINAPI IDirectSound3DBufferImpl_GetConeOrientation(
388 LPDIRECTSOUND3DBUFFER iface,
389 LPD3DVECTOR lpvConeOrientation)
397 static HRESULT WINAPI IDirectSound3DBufferImpl_GetConeOutsideVolume(
398 LPDIRECTSOUND3DBUFFER iface,
399 LPLONG lplConeOutsideVolume)
407 static HRESULT WINAPI IDirectSound3DBufferImpl_GetMaxDistance(
408 LPDIRECTSOUND3DBUFFER iface,
409 LPD3DVALUE lpfMaxDistance)
417 static HRESULT WINAPI IDirectSound3DBufferImpl_GetMinDistance(
418 LPDIRECTSOUND3DBUFFER iface,
419 LPD3DVALUE lpfMinDistance)
427 static HRESULT WINAPI IDirectSound3DBufferImpl_GetMode(
428 LPDIRECTSOUND3DBUFFER iface,
437 static HRESULT WINAPI IDirectSound3DBufferImpl_GetPosition(
438 LPDIRECTSOUND3DBUFFER iface,
439 LPD3DVECTOR lpvPosition)
447 static HRESULT WINAPI IDirectSound3DBufferImpl_GetVelocity(
448 LPDIRECTSOUND3DBUFFER iface,
449 LPD3DVECTOR lpvVelocity)
457 static HRESULT WINAPI IDirectSound3DBufferImpl_SetAllParameters(
458 LPDIRECTSOUND3DBUFFER iface,
459 LPCDS3DBUFFER lpcDs3dBuffer,
468 static HRESULT WINAPI IDirectSound3DBufferImpl_SetConeAngles(
469 LPDIRECTSOUND3DBUFFER iface,
470 DWORD dwInsideConeAngle,
471 DWORD dwOutsideConeAngle,
480 static HRESULT WINAPI IDirectSound3DBufferImpl_SetConeOrientation(
481 LPDIRECTSOUND3DBUFFER iface,
482 D3DVALUE x, D3DVALUE y, D3DVALUE z,
491 static HRESULT WINAPI IDirectSound3DBufferImpl_SetConeOutsideVolume(
492 LPDIRECTSOUND3DBUFFER iface,
493 LONG lConeOutsideVolume,
502 static HRESULT WINAPI IDirectSound3DBufferImpl_SetMaxDistance(
503 LPDIRECTSOUND3DBUFFER iface,
504 D3DVALUE fMaxDistance,
513 static HRESULT WINAPI IDirectSound3DBufferImpl_SetMinDistance(
514 LPDIRECTSOUND3DBUFFER iface,
515 D3DVALUE fMinDistance,
524 static HRESULT WINAPI IDirectSound3DBufferImpl_SetMode(
525 LPDIRECTSOUND3DBUFFER iface,
529 ICOM_THIS(IDirectSound3DBufferImpl,iface);
530 TRACE("mode = %lx\n", dwMode);
531 This->ds3db.dwMode = dwMode;
537 static HRESULT WINAPI IDirectSound3DBufferImpl_SetPosition(
538 LPDIRECTSOUND3DBUFFER iface,
539 D3DVALUE x, D3DVALUE y, D3DVALUE z,
548 static HRESULT WINAPI IDirectSound3DBufferImpl_SetVelocity(
549 LPDIRECTSOUND3DBUFFER iface,
550 D3DVALUE x, D3DVALUE y, D3DVALUE z,
559 static ICOM_VTABLE(IDirectSound3DBuffer) ds3dbvt =
561 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
562 /* IUnknown methods */
563 IDirectSound3DBufferImpl_QueryInterface,
564 IDirectSound3DBufferImpl_AddRef,
565 IDirectSound3DBufferImpl_Release,
566 /* IDirectSound3DBuffer methods */
567 IDirectSound3DBufferImpl_GetAllParameters,
568 IDirectSound3DBufferImpl_GetConeAngles,
569 IDirectSound3DBufferImpl_GetConeOrientation,
570 IDirectSound3DBufferImpl_GetConeOutsideVolume,
571 IDirectSound3DBufferImpl_GetMaxDistance,
572 IDirectSound3DBufferImpl_GetMinDistance,
573 IDirectSound3DBufferImpl_GetMode,
574 IDirectSound3DBufferImpl_GetPosition,
575 IDirectSound3DBufferImpl_GetVelocity,
576 IDirectSound3DBufferImpl_SetAllParameters,
577 IDirectSound3DBufferImpl_SetConeAngles,
578 IDirectSound3DBufferImpl_SetConeOrientation,
579 IDirectSound3DBufferImpl_SetConeOutsideVolume,
580 IDirectSound3DBufferImpl_SetMaxDistance,
581 IDirectSound3DBufferImpl_SetMinDistance,
582 IDirectSound3DBufferImpl_SetMode,
583 IDirectSound3DBufferImpl_SetPosition,
584 IDirectSound3DBufferImpl_SetVelocity,
589 static int DSOUND_Create3DBuffer(IDirectSoundBufferImpl* dsb)
591 DWORD i, temp, iSize, oSize, offset;
592 LPBYTE bIbuf, bObuf, bTbuf = NULL;
593 LPWORD wIbuf, wObuf, wTbuf = NULL;
595 /* Inside DirectX says it's stupid but allowed */
596 if (dsb->wfx.nChannels == 2) {
597 /* Convert to mono */
598 if (dsb->wfx.wBitsPerSample == 16) {
599 iSize = dsb->buflen / 4;
600 wTbuf = malloc(dsb->buflen / 2);
602 return DSERR_OUTOFMEMORY;
603 for (i = 0; i < iSize; i++)
604 wTbuf[i] = (dsb->buffer[i] + dsb->buffer[(i * 2) + 1]) / 2;
607 iSize = dsb->buflen / 2;
608 bTbuf = malloc(dsb->buflen / 2);
610 return DSERR_OUTOFMEMORY;
611 for (i = 0; i < iSize; i++)
612 bTbuf[i] = (dsb->buffer[i] + dsb->buffer[(i * 2) + 1]) / 2;
616 if (dsb->wfx.wBitsPerSample == 16) {
617 iSize = dsb->buflen / 2;
618 wIbuf = (LPWORD) dsb->buffer;
620 bIbuf = (LPBYTE) dsb->buffer;
625 if (primarybuf->wfx.wBitsPerSample == 16) {
626 wObuf = (LPWORD) dsb->ds3db->buffer;
627 oSize = dsb->ds3db->buflen / 2;
629 bObuf = (LPBYTE) dsb->ds3db->buffer;
630 oSize = dsb->ds3db->buflen;
633 offset = primarybuf->wfx.nSamplesPerSec / 100; /* 10ms */
634 if (primarybuf->wfx.wBitsPerSample == 16 && dsb->wfx.wBitsPerSample == 16)
635 for (i = 0; i < iSize; i++) {
638 temp += wIbuf[i - offset] >> 9;
640 temp += wIbuf[i + iSize - offset] >> 9;
642 wObuf[(i * 2) + 1] = temp;
644 else if (primarybuf->wfx.wBitsPerSample == 8 && dsb->wfx.wBitsPerSample == 8)
645 for (i = 0; i < iSize; i++) {
648 temp += bIbuf[i - offset] >> 5;
650 temp += bIbuf[i + iSize - offset] >> 5;
652 bObuf[(i * 2) + 1] = temp;
663 /*******************************************************************************
664 * IDirectSound3DListener
667 /* IUnknown methods */
668 static HRESULT WINAPI IDirectSound3DListenerImpl_QueryInterface(
669 LPDIRECTSOUND3DLISTENER iface, REFIID riid, LPVOID *ppobj)
671 ICOM_THIS(IDirectSound3DListenerImpl,iface);
673 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
677 static ULONG WINAPI IDirectSound3DListenerImpl_AddRef(LPDIRECTSOUND3DLISTENER iface)
679 ICOM_THIS(IDirectSound3DListenerImpl,iface);
684 static ULONG WINAPI IDirectSound3DListenerImpl_Release(LPDIRECTSOUND3DLISTENER iface)
687 ICOM_THIS(IDirectSound3DListenerImpl,iface);
689 TRACE("(%p) ref was %ld\n", This, This->ref);
691 ulReturn = --This->ref;
693 /* Free all resources */
694 if( ulReturn == 0 ) {
696 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->dsb);
697 DeleteCriticalSection(&This->lock);
698 HeapFree(GetProcessHeap(),0,This);
704 /* IDirectSound3DListener methods */
705 static HRESULT WINAPI IDirectSound3DListenerImpl_GetAllParameter(
706 LPDIRECTSOUND3DLISTENER iface,
707 LPDS3DLISTENER lpDS3DL)
713 static HRESULT WINAPI IDirectSound3DListenerImpl_GetDistanceFactor(
714 LPDIRECTSOUND3DLISTENER iface,
715 LPD3DVALUE lpfDistanceFactor)
721 static HRESULT WINAPI IDirectSound3DListenerImpl_GetDopplerFactor(
722 LPDIRECTSOUND3DLISTENER iface,
723 LPD3DVALUE lpfDopplerFactor)
729 static HRESULT WINAPI IDirectSound3DListenerImpl_GetOrientation(
730 LPDIRECTSOUND3DLISTENER iface,
731 LPD3DVECTOR lpvOrientFront,
732 LPD3DVECTOR lpvOrientTop)
738 static HRESULT WINAPI IDirectSound3DListenerImpl_GetPosition(
739 LPDIRECTSOUND3DLISTENER iface,
740 LPD3DVECTOR lpvPosition)
746 static HRESULT WINAPI IDirectSound3DListenerImpl_GetRolloffFactor(
747 LPDIRECTSOUND3DLISTENER iface,
748 LPD3DVALUE lpfRolloffFactor)
754 static HRESULT WINAPI IDirectSound3DListenerImpl_GetVelocity(
755 LPDIRECTSOUND3DLISTENER iface,
756 LPD3DVECTOR lpvVelocity)
762 static HRESULT WINAPI IDirectSound3DListenerImpl_SetAllParameters(
763 LPDIRECTSOUND3DLISTENER iface,
764 LPCDS3DLISTENER lpcDS3DL,
771 static HRESULT WINAPI IDirectSound3DListenerImpl_SetDistanceFactor(
772 LPDIRECTSOUND3DLISTENER iface,
773 D3DVALUE fDistanceFactor,
780 static HRESULT WINAPI IDirectSound3DListenerImpl_SetDopplerFactor(
781 LPDIRECTSOUND3DLISTENER iface,
782 D3DVALUE fDopplerFactor,
789 static HRESULT WINAPI IDirectSound3DListenerImpl_SetOrientation(
790 LPDIRECTSOUND3DLISTENER iface,
791 D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront,
792 D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop,
799 static HRESULT WINAPI IDirectSound3DListenerImpl_SetPosition(
800 LPDIRECTSOUND3DLISTENER iface,
801 D3DVALUE x, D3DVALUE y, D3DVALUE z,
808 static HRESULT WINAPI IDirectSound3DListenerImpl_SetRolloffFactor(
809 LPDIRECTSOUND3DLISTENER iface,
810 D3DVALUE fRolloffFactor,
817 static HRESULT WINAPI IDirectSound3DListenerImpl_SetVelocity(
818 LPDIRECTSOUND3DLISTENER iface,
819 D3DVALUE x, D3DVALUE y, D3DVALUE z,
826 static HRESULT WINAPI IDirectSound3DListenerImpl_CommitDeferredSettings(
827 LPDIRECTSOUND3DLISTENER iface)
834 static ICOM_VTABLE(IDirectSound3DListener) ds3dlvt =
836 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
837 /* IUnknown methods */
838 IDirectSound3DListenerImpl_QueryInterface,
839 IDirectSound3DListenerImpl_AddRef,
840 IDirectSound3DListenerImpl_Release,
841 /* IDirectSound3DListener methods */
842 IDirectSound3DListenerImpl_GetAllParameter,
843 IDirectSound3DListenerImpl_GetDistanceFactor,
844 IDirectSound3DListenerImpl_GetDopplerFactor,
845 IDirectSound3DListenerImpl_GetOrientation,
846 IDirectSound3DListenerImpl_GetPosition,
847 IDirectSound3DListenerImpl_GetRolloffFactor,
848 IDirectSound3DListenerImpl_GetVelocity,
849 IDirectSound3DListenerImpl_SetAllParameters,
850 IDirectSound3DListenerImpl_SetDistanceFactor,
851 IDirectSound3DListenerImpl_SetDopplerFactor,
852 IDirectSound3DListenerImpl_SetOrientation,
853 IDirectSound3DListenerImpl_SetPosition,
854 IDirectSound3DListenerImpl_SetRolloffFactor,
855 IDirectSound3DListenerImpl_SetVelocity,
856 IDirectSound3DListenerImpl_CommitDeferredSettings,
859 /*******************************************************************************
862 static HRESULT WINAPI IDirectSoundNotifyImpl_QueryInterface(
863 LPDIRECTSOUNDNOTIFY iface,REFIID riid,LPVOID *ppobj
865 ICOM_THIS(IDirectSoundNotifyImpl,iface);
867 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
871 static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface) {
872 ICOM_THIS(IDirectSoundNotifyImpl,iface);
873 return ++(This->ref);
876 static ULONG WINAPI IDirectSoundNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface) {
877 ICOM_THIS(IDirectSoundNotifyImpl,iface);
879 TRACE("(%p) ref was %ld\n", This, This->ref);
883 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->dsb);
884 HeapFree(GetProcessHeap(),0,This);
890 static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(
891 LPDIRECTSOUNDNOTIFY iface,DWORD howmuch,LPCDSBPOSITIONNOTIFY notify
893 ICOM_THIS(IDirectSoundNotifyImpl,iface);
896 if (TRACE_ON(dsound)) {
897 TRACE("(%p,0x%08lx,%p)\n",This,howmuch,notify);
898 for (i=0;i<howmuch;i++)
899 TRACE("notify at %ld to 0x%08lx\n",
900 notify[i].dwOffset,(DWORD)notify[i].hEventNotify);
902 This->dsb->notifies = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,This->dsb->notifies,(This->dsb->nrofnotifies+howmuch)*sizeof(DSBPOSITIONNOTIFY));
903 memcpy( This->dsb->notifies+This->dsb->nrofnotifies,
905 howmuch*sizeof(DSBPOSITIONNOTIFY)
907 This->dsb->nrofnotifies+=howmuch;
912 static ICOM_VTABLE(IDirectSoundNotify) dsnvt =
914 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
915 IDirectSoundNotifyImpl_QueryInterface,
916 IDirectSoundNotifyImpl_AddRef,
917 IDirectSoundNotifyImpl_Release,
918 IDirectSoundNotifyImpl_SetNotificationPositions,
921 /*******************************************************************************
925 static void DSOUND_RecalcVolPan(PDSVOLUMEPAN volpan)
929 /* the AmpFactors are expressed in 16.16 fixed point */
930 volpan->dwVolAmpFactor = (ULONG) (pow(2.0, volpan->lVolume / 600.0) * 65536);
931 /* FIXME: dwPan{Left|Right}AmpFactor */
933 /* FIXME: use calculated vol and pan ampfactors */
934 temp = (double) (volpan->lVolume - (volpan->lPan > 0 ? volpan->lPan : 0));
935 volpan->dwTotalLeftAmpFactor = (ULONG) (pow(2.0, temp / 600.0) * 65536);
936 temp = (double) (volpan->lVolume + (volpan->lPan < 0 ? volpan->lPan : 0));
937 volpan->dwTotalRightAmpFactor = (ULONG) (pow(2.0, temp / 600.0) * 65536);
939 TRACE("left = %lx, right = %lx\n", volpan->dwTotalLeftAmpFactor, volpan->dwTotalRightAmpFactor);
942 static void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb)
946 sw = dsb->wfx.nChannels * (dsb->wfx.wBitsPerSample / 8);
947 if ((dsb->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER) && dsb->hwbuf) {
949 /* let fragment size approximate the timer delay */
950 fraglen = (dsb->freq * DS_TIME_DEL / 1000) * sw;
951 /* reduce fragment size until an integer number of them fits in the buffer */
952 /* (FIXME: this may or may not be a good idea) */
953 while (dsb->buflen % fraglen) fraglen -= sw;
954 dsb->dsound->fraglen = fraglen;
955 TRACE("fraglen=%ld\n", dsb->dsound->fraglen);
957 /* calculate the 10ms write lead */
958 dsb->writelead = (dsb->freq / 100) * sw;
961 static HRESULT DSOUND_PrimaryOpen(IDirectSoundBufferImpl *dsb)
965 /* are we using waveOut stuff? */
969 HRESULT merr = DS_OK;
970 /* Start in pause mode, to allow buffers to get filled */
971 waveOutPause(dsb->dsound->hwo);
972 /* use fragments of 10ms (1/100s) each (which should get us within
973 * the documented write cursor lead of 10-15ms) */
974 buflen = ((dsb->wfx.nAvgBytesPerSec / 100) & ~3) * DS_HEL_FRAGS;
975 TRACE("desired buflen=%ld, old buffer=%p\n", buflen, dsb->buffer);
976 /* reallocate emulated primary buffer */
977 newbuf = (LPBYTE)HeapReAlloc(GetProcessHeap(),0,dsb->buffer,buflen);
978 if (newbuf == NULL) {
979 ERR("failed to allocate primary buffer\n");
980 merr = DSERR_OUTOFMEMORY;
981 /* but the old buffer might still exists and must be re-prepared */
983 dsb->buffer = newbuf;
984 dsb->buflen = buflen;
988 IDirectSoundImpl *ds = dsb->dsound;
990 ds->fraglen = dsb->buflen / DS_HEL_FRAGS;
992 /* prepare fragment headers */
993 for (c=0; c<DS_HEL_FRAGS; c++) {
994 ds->pwave[c]->lpData = dsb->buffer + c*ds->fraglen;
995 ds->pwave[c]->dwBufferLength = ds->fraglen;
996 ds->pwave[c]->dwUser = (DWORD)dsb;
997 ds->pwave[c]->dwFlags = 0;
998 ds->pwave[c]->dwLoops = 0;
999 err = mmErr(waveOutPrepareHeader(ds->hwo,ds->pwave[c],sizeof(WAVEHDR)));
1002 waveOutUnprepareHeader(ds->hwo,ds->pwave[c],sizeof(WAVEHDR));
1010 memset(dsb->buffer, (dsb->wfx.wBitsPerSample == 16) ? 0 : 128, dsb->buflen);
1011 TRACE("fraglen=%ld\n", ds->fraglen);
1013 if ((err == DS_OK) && (merr != DS_OK))
1020 static void DSOUND_PrimaryClose(IDirectSoundBufferImpl *dsb)
1022 /* are we using waveOut stuff? */
1025 IDirectSoundImpl *ds = dsb->dsound;
1027 waveOutReset(ds->hwo);
1028 for (c=0; c<DS_HEL_FRAGS; c++)
1029 waveOutUnprepareHeader(ds->hwo, ds->pwave[c], sizeof(WAVEHDR));
1033 /* This sets this format for the <em>Primary Buffer Only</em> */
1034 /* See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 120 */
1035 static HRESULT WINAPI IDirectSoundBufferImpl_SetFormat(
1036 LPDIRECTSOUNDBUFFER iface,LPWAVEFORMATEX wfex
1038 ICOM_THIS(IDirectSoundBufferImpl,iface);
1039 IDirectSoundBufferImpl** dsb;
1040 HRESULT err = DS_OK;
1043 /* Let's be pedantic! */
1044 if ((wfex == NULL) ||
1045 (wfex->wFormatTag != WAVE_FORMAT_PCM) ||
1046 (wfex->nChannels < 1) || (wfex->nChannels > 2) ||
1047 (wfex->nSamplesPerSec < 1) ||
1048 (wfex->nBlockAlign < 1) || (wfex->nChannels > 4) ||
1049 ((wfex->wBitsPerSample != 8) && (wfex->wBitsPerSample != 16))) {
1050 TRACE("failed pedantic check!\n");
1051 return DSERR_INVALIDPARAM;
1055 EnterCriticalSection(&(This->dsound->lock));
1057 if (primarybuf->wfx.nSamplesPerSec != wfex->nSamplesPerSec) {
1058 dsb = dsound->buffers;
1059 for (i = 0; i < dsound->nrofbuffers; i++, dsb++) {
1061 EnterCriticalSection(&((*dsb)->lock));
1063 (*dsb)->freqAdjust = ((*dsb)->freq << DSOUND_FREQSHIFT) /
1064 wfex->nSamplesPerSec;
1066 LeaveCriticalSection(&((*dsb)->lock));
1071 memcpy(&(primarybuf->wfx), wfex, sizeof(primarybuf->wfx));
1073 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
1074 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1075 wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
1076 wfex->nAvgBytesPerSec, wfex->nBlockAlign,
1077 wfex->wBitsPerSample, wfex->cbSize);
1079 primarybuf->wfx.nAvgBytesPerSec =
1080 This->wfx.nSamplesPerSec * This->wfx.nBlockAlign;
1081 if (primarybuf->dsound->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMSETFORMAT) {
1082 /* FIXME: check for errors */
1083 DSOUND_PrimaryClose(primarybuf);
1084 waveOutClose(This->dsound->hwo);
1085 This->dsound->hwo = 0;
1086 waveOutOpen(&(This->dsound->hwo), This->dsound->drvdesc.dnDevNode,
1087 &(primarybuf->wfx), 0, 0, CALLBACK_NULL | WAVE_DIRECTSOUND);
1088 DSOUND_PrimaryOpen(primarybuf);
1090 if (primarybuf->hwbuf) {
1091 err = IDsDriverBuffer_SetFormat(primarybuf->hwbuf, &(primarybuf->wfx));
1092 if (err == DSERR_BUFFERLOST) {
1093 /* Wine-only: the driver wants us to recreate the HW buffer */
1094 IDsDriverBuffer_Release(primarybuf->hwbuf);
1095 err = IDsDriver_CreateSoundBuffer(primarybuf->dsound->driver,&(primarybuf->wfx),primarybuf->dsbd.dwFlags,0,
1096 &(primarybuf->buflen),&(primarybuf->buffer),
1097 (LPVOID)&(primarybuf->hwbuf));
1100 DSOUND_RecalcFormat(primarybuf);
1102 LeaveCriticalSection(&(This->dsound->lock));
1108 static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume(
1109 LPDIRECTSOUNDBUFFER iface,LONG vol
1111 ICOM_THIS(IDirectSoundBufferImpl,iface);
1113 TRACE("(%p,%ld)\n",This,vol);
1115 /* I'm not sure if we need this for primary buffer */
1116 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME))
1117 return DSERR_CONTROLUNAVAIL;
1119 if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN))
1120 return DSERR_INVALIDPARAM;
1123 EnterCriticalSection(&(This->lock));
1125 This->volpan.lVolume = vol;
1127 DSOUND_RecalcVolPan(&(This->volpan));
1130 IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
1132 else if (This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER) {
1133 #if 0 /* should we really do this? */
1134 /* the DS volume ranges from 0 (max, 0dB attenuation) to -10000 (min, 100dB attenuation) */
1135 /* the MM volume ranges from 0 to 0xffff in an unspecified logarithmic scale */
1136 WORD cvol = 0xffff + vol*6 + vol/2;
1137 DWORD vol = cvol | ((DWORD)cvol << 16)
1138 waveOutSetVolume(This->dsound->hwo, vol);
1142 LeaveCriticalSection(&(This->lock));
1148 static HRESULT WINAPI IDirectSoundBufferImpl_GetVolume(
1149 LPDIRECTSOUNDBUFFER iface,LPLONG vol
1151 ICOM_THIS(IDirectSoundBufferImpl,iface);
1152 TRACE("(%p,%p)\n",This,vol);
1155 return DSERR_INVALIDPARAM;
1157 *vol = This->volpan.lVolume;
1161 static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency(
1162 LPDIRECTSOUNDBUFFER iface,DWORD freq
1164 ICOM_THIS(IDirectSoundBufferImpl,iface);
1165 TRACE("(%p,%ld)\n",This,freq);
1167 /* You cannot set the frequency of the primary buffer */
1168 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLFREQUENCY) ||
1169 (This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER))
1170 return DSERR_CONTROLUNAVAIL;
1172 if (!freq) freq = This->wfx.nSamplesPerSec;
1174 if ((freq < DSBFREQUENCY_MIN) || (freq > DSBFREQUENCY_MAX))
1175 return DSERR_INVALIDPARAM;
1178 EnterCriticalSection(&(This->lock));
1181 This->freqAdjust = (freq << DSOUND_FREQSHIFT) / primarybuf->wfx.nSamplesPerSec;
1182 This->nAvgBytesPerSec = freq * This->wfx.nBlockAlign;
1183 DSOUND_RecalcFormat(This);
1185 LeaveCriticalSection(&(This->lock));
1191 static HRESULT WINAPI IDirectSoundBufferImpl_Play(
1192 LPDIRECTSOUNDBUFFER iface,DWORD reserved1,DWORD reserved2,DWORD flags
1194 ICOM_THIS(IDirectSoundBufferImpl,iface);
1195 TRACE("(%p,%08lx,%08lx,%08lx)\n",
1196 This,reserved1,reserved2,flags
1198 This->playflags = flags;
1199 if (This->state == STATE_STOPPED) {
1200 This->leadin = TRUE;
1201 This->startpos = This->mixpos;
1202 This->state = STATE_STARTING;
1203 } else if (This->state == STATE_STOPPING)
1204 This->state = STATE_PLAYING;
1205 if (!(This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER) && This->hwbuf) {
1206 IDsDriverBuffer_Play(This->hwbuf, 0, 0, This->playflags);
1207 This->state = STATE_PLAYING;
1212 static HRESULT WINAPI IDirectSoundBufferImpl_Stop(LPDIRECTSOUNDBUFFER iface)
1214 ICOM_THIS(IDirectSoundBufferImpl,iface);
1215 TRACE("(%p)\n",This);
1218 EnterCriticalSection(&(This->lock));
1220 if (This->state == STATE_PLAYING)
1221 This->state = STATE_STOPPING;
1222 else if (This->state == STATE_STARTING)
1223 This->state = STATE_STOPPED;
1224 if (!(This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER) && This->hwbuf) {
1225 IDsDriverBuffer_Stop(This->hwbuf);
1226 This->state = STATE_STOPPED;
1228 DSOUND_CheckEvent(This, 0);
1230 LeaveCriticalSection(&(This->lock));
1236 static DWORD WINAPI IDirectSoundBufferImpl_AddRef(LPDIRECTSOUNDBUFFER iface) {
1237 ICOM_THIS(IDirectSoundBufferImpl,iface);
1240 TRACE("(%p) ref was %ld, thread is %lx\n",This, This->ref, GetCurrentThreadId());
1242 ref = InterlockedIncrement(&(This->ref));
1244 FIXME("thread-safety alert! AddRef-ing with a zero refcount!\n");
1248 static DWORD WINAPI IDirectSoundBufferImpl_Release(LPDIRECTSOUNDBUFFER iface) {
1249 ICOM_THIS(IDirectSoundBufferImpl,iface);
1253 TRACE("(%p) ref was %ld, thread is %lx\n",This, This->ref, GetCurrentThreadId());
1255 ref = InterlockedDecrement(&(This->ref));
1256 if (ref) return ref;
1258 EnterCriticalSection(&(This->dsound->lock));
1259 for (i=0;i<This->dsound->nrofbuffers;i++)
1260 if (This->dsound->buffers[i] == This)
1263 if (i < This->dsound->nrofbuffers) {
1264 /* Put the last buffer of the list in the (now empty) position */
1265 This->dsound->buffers[i] = This->dsound->buffers[This->dsound->nrofbuffers - 1];
1266 This->dsound->nrofbuffers--;
1267 This->dsound->buffers = HeapReAlloc(GetProcessHeap(),0,This->dsound->buffers,sizeof(LPDIRECTSOUNDBUFFER)*This->dsound->nrofbuffers);
1268 TRACE("buffer count is now %d\n", This->dsound->nrofbuffers);
1269 IDirectSound_Release((LPDIRECTSOUND)This->dsound);
1271 LeaveCriticalSection(&(This->dsound->lock));
1273 DeleteCriticalSection(&(This->lock));
1274 if (This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER)
1275 DSOUND_PrimaryClose(This);
1277 IDsDriverBuffer_Release(This->hwbuf);
1280 IDirectSound3DBuffer_Release((LPDIRECTSOUND3DBUFFER)This->ds3db);
1282 /* this is a duplicate buffer */
1283 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->parent);
1285 /* this is a toplevel buffer */
1286 HeapFree(GetProcessHeap(),0,This->buffer);
1288 HeapFree(GetProcessHeap(),0,This);
1290 if (This == primarybuf)
1296 static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(
1297 LPDIRECTSOUNDBUFFER iface,LPDWORD playpos,LPDWORD writepos
1299 ICOM_THIS(IDirectSoundBufferImpl,iface);
1300 TRACE("(%p,%p,%p)\n",This,playpos,writepos);
1302 IDsDriverBuffer_GetPosition(This->hwbuf, playpos, writepos);
1304 else if (This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER) {
1305 if (playpos && (This->dsbd.dwFlags & DSBCAPS_GETCURRENTPOSITION2)) {
1307 mtime.wType = TIME_BYTES;
1308 waveOutGetPosition(This->dsound->hwo, &mtime, sizeof(mtime));
1309 mtime.u.cb = mtime.u.cb % This->buflen;
1310 *playpos = mtime.u.cb;
1312 /* don't know how exactly non-GETCURRENTPOSITION2 behaves,
1313 * but I think this works for Starcraft */
1314 else if (playpos) *playpos = This->playpos;
1316 /* the writepos should only be used by apps with WRITEPRIMARY priority,
1317 * in which case our software mixer is disabled anyway */
1318 *writepos = This->playpos + DS_HEL_MARGIN * This->dsound->fraglen;
1319 while (*writepos >= This->buflen)
1320 *writepos -= This->buflen;
1323 if (playpos && (This->state != STATE_PLAYING)) {
1324 /* we haven't been merged into the primary buffer (yet) */
1325 *playpos = This->mixpos;
1328 DWORD pplay, lplay, splay, tplay, pstate;
1329 /* let's get this exact; first, recursively call GetPosition on the primary */
1330 EnterCriticalSection(&(primarybuf->lock));
1331 if ((This->dsbd.dwFlags & DSBCAPS_GETCURRENTPOSITION2) || primarybuf->hwbuf) {
1332 IDirectSoundBufferImpl_GetCurrentPosition((LPDIRECTSOUNDBUFFER)primarybuf, &pplay, NULL);
1334 /* (unless the app isn't using GETCURRENTPOSITION2) */
1335 /* don't know exactly how this should be handled either */
1336 pplay = primarybuf->playpos;
1338 /* get last mixed primary play position */
1339 lplay = primarybuf->mixpos;
1340 pstate = primarybuf->state;
1341 /* detect HEL mode underrun */
1342 if (!(primarybuf->hwbuf || primarybuf->dsound->pwqueue)) {
1343 TRACE("detected an underrun\n");
1345 if (pstate == STATE_PLAYING)
1346 pstate = STATE_STARTING;
1347 else if (pstate == STATE_STOPPING)
1348 pstate = STATE_STOPPED;
1350 /* get our own last mixed position while we still have the lock */
1351 splay = This->mixpos;
1352 LeaveCriticalSection(&(primarybuf->lock));
1353 TRACE("primary playpos=%ld, mixpos=%ld\n", pplay, lplay);
1354 TRACE("this mixpos=%ld\n", splay);
1356 /* the actual primary play position (pplay) is always behind last mixed (lplay),
1357 * unless the computer is too slow or something */
1358 /* we need to know how far away we are from there */
1359 if (lplay == pplay) {
1360 if ((pstate == STATE_PLAYING) || (pstate == STATE_STOPPING)) {
1361 /* wow, the software mixer is really doing well,
1362 * seems the entire primary buffer is filled! */
1363 lplay += primarybuf->buflen;
1365 /* else: the primary buffer is not playing, so probably empty */
1367 if (lplay < pplay) lplay += primarybuf->buflen; /* wraparound */
1369 /* detect HAL mode underrun */
1370 if (primarybuf->hwbuf &&
1371 (lplay > ((DS_HAL_QUEUE + 1) * primarybuf->dsound->fraglen + primarybuf->writelead))) {
1372 TRACE("detected an underrun: primary queue was %ld\n",lplay);
1375 /* divide the offset by its sample size */
1376 lplay /= primarybuf->wfx.nChannels * (primarybuf->wfx.wBitsPerSample / 8);
1377 TRACE("primary back-samples=%ld\n",lplay);
1378 /* adjust for our frequency */
1379 lplay = (lplay * This->freqAdjust) >> DSOUND_FREQSHIFT;
1380 /* multiply by our own sample size */
1381 lplay *= This->wfx.nChannels * (This->wfx.wBitsPerSample / 8);
1382 TRACE("this back-offset=%ld\n", lplay);
1383 /* subtract from our last mixed position */
1385 while (tplay < lplay) tplay += This->buflen; /* wraparound */
1387 if (This->leadin && ((tplay < This->startpos) || (tplay > splay))) {
1388 /* seems we haven't started playing yet */
1389 TRACE("this still in lead-in phase\n");
1390 tplay = This->startpos;
1392 /* return the result */
1395 if (writepos) *writepos = This->mixpos;
1398 if (This->state != STATE_STOPPED)
1399 /* apply the documented 10ms lead to writepos */
1400 *writepos += This->writelead;
1401 while (*writepos >= This->buflen) *writepos -= This->buflen;
1403 TRACE("playpos = %ld, writepos = %ld (%p, time=%ld)\n", playpos?*playpos:0, writepos?*writepos:0, This, GetTickCount());
1407 static HRESULT WINAPI IDirectSoundBufferImpl_GetStatus(
1408 LPDIRECTSOUNDBUFFER iface,LPDWORD status
1410 ICOM_THIS(IDirectSoundBufferImpl,iface);
1411 TRACE("(%p,%p), thread is %lx\n",This,status,GetCurrentThreadId());
1414 return DSERR_INVALIDPARAM;
1417 if ((This->state == STATE_STARTING) || (This->state == STATE_PLAYING))
1418 *status |= DSBSTATUS_PLAYING;
1419 if (This->playflags & DSBPLAY_LOOPING)
1420 *status |= DSBSTATUS_LOOPING;
1422 TRACE("status=%lx\n", *status);
1427 static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat(
1428 LPDIRECTSOUNDBUFFER iface,LPWAVEFORMATEX lpwf,DWORD wfsize,LPDWORD wfwritten
1430 ICOM_THIS(IDirectSoundBufferImpl,iface);
1431 TRACE("(%p,%p,%ld,%p)\n",This,lpwf,wfsize,wfwritten);
1433 if (wfsize>sizeof(This->wfx))
1434 wfsize = sizeof(This->wfx);
1435 if (lpwf) { /* NULL is valid */
1436 memcpy(lpwf,&(This->wfx),wfsize);
1438 *wfwritten = wfsize;
1441 *wfwritten = sizeof(This->wfx);
1443 return DSERR_INVALIDPARAM;
1448 static HRESULT WINAPI IDirectSoundBufferImpl_Lock(
1449 LPDIRECTSOUNDBUFFER iface,DWORD writecursor,DWORD writebytes,LPVOID lplpaudioptr1,LPDWORD audiobytes1,LPVOID lplpaudioptr2,LPDWORD audiobytes2,DWORD flags
1451 ICOM_THIS(IDirectSoundBufferImpl,iface);
1454 TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx)\n",
1465 if (flags & DSBLOCK_FROMWRITECURSOR) {
1467 /* GetCurrentPosition does too much magic to duplicate here */
1468 IDirectSoundBufferImpl_GetCurrentPosition(iface, NULL, &writepos);
1469 writecursor += writepos;
1471 if (flags & DSBLOCK_ENTIREBUFFER)
1472 writebytes = This->buflen;
1473 if (writebytes > This->buflen)
1474 writebytes = This->buflen;
1476 assert(audiobytes1!=audiobytes2);
1477 assert(lplpaudioptr1!=lplpaudioptr2);
1479 if (This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER)
1480 capf = DSDDESC_DONTNEEDPRIMARYLOCK;
1482 capf = DSDDESC_DONTNEEDSECONDARYLOCK;
1483 if (!(This->dsound->drvdesc.dwFlags & capf) && This->hwbuf) {
1484 IDsDriverBuffer_Lock(This->hwbuf,
1485 lplpaudioptr1, audiobytes1,
1486 lplpaudioptr2, audiobytes2,
1487 writecursor, writebytes,
1490 if (writecursor+writebytes <= This->buflen) {
1491 *(LPBYTE*)lplpaudioptr1 = This->buffer+writecursor;
1492 *audiobytes1 = writebytes;
1494 *(LPBYTE*)lplpaudioptr2 = NULL;
1497 TRACE("->%ld.0\n",writebytes);
1499 *(LPBYTE*)lplpaudioptr1 = This->buffer+writecursor;
1500 *audiobytes1 = This->buflen-writecursor;
1502 *(LPBYTE*)lplpaudioptr2 = This->buffer;
1504 *audiobytes2 = writebytes-(This->buflen-writecursor);
1505 TRACE("->%ld.%ld\n",*audiobytes1,audiobytes2?*audiobytes2:0);
1510 static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(
1511 LPDIRECTSOUNDBUFFER iface,DWORD newpos
1513 ICOM_THIS(IDirectSoundBufferImpl,iface);
1514 TRACE("(%p,%ld)\n",This,newpos);
1517 EnterCriticalSection(&(This->lock));
1519 This->mixpos = newpos;
1521 IDsDriverBuffer_SetPosition(This->hwbuf, This->mixpos);
1523 LeaveCriticalSection(&(This->lock));
1529 static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(
1530 LPDIRECTSOUNDBUFFER iface,LONG pan
1532 ICOM_THIS(IDirectSoundBufferImpl,iface);
1534 TRACE("(%p,%ld)\n",This,pan);
1536 if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT))
1537 return DSERR_INVALIDPARAM;
1539 /* You cannot set the pan of the primary buffer */
1540 /* and you cannot use both pan and 3D controls */
1541 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
1542 (This->dsbd.dwFlags & DSBCAPS_CTRL3D) ||
1543 (This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER))
1544 return DSERR_CONTROLUNAVAIL;
1547 EnterCriticalSection(&(This->lock));
1549 This->volpan.lPan = pan;
1551 DSOUND_RecalcVolPan(&(This->volpan));
1554 IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
1557 LeaveCriticalSection(&(This->lock));
1563 static HRESULT WINAPI IDirectSoundBufferImpl_GetPan(
1564 LPDIRECTSOUNDBUFFER iface,LPLONG pan
1566 ICOM_THIS(IDirectSoundBufferImpl,iface);
1567 TRACE("(%p,%p)\n",This,pan);
1570 return DSERR_INVALIDPARAM;
1572 *pan = This->volpan.lPan;
1577 static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(
1578 LPDIRECTSOUNDBUFFER iface,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2
1580 ICOM_THIS(IDirectSoundBufferImpl,iface);
1583 TRACE("(%p,%p,%ld,%p,%ld):stub\n", This,p1,x1,p2,x2);
1586 /* Preprocess 3D buffers... */
1588 /* This is highly experimental and liable to break things */
1589 if (This->dsbd.dwFlags & DSBCAPS_CTRL3D)
1590 DSOUND_Create3DBuffer(This);
1593 if (This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER)
1594 capf = DSDDESC_DONTNEEDPRIMARYLOCK;
1596 capf = DSDDESC_DONTNEEDSECONDARYLOCK;
1597 if (!(This->dsound->drvdesc.dwFlags & capf) && This->hwbuf) {
1598 IDsDriverBuffer_Unlock(This->hwbuf, p1, x1, p2, x2);
1604 static HRESULT WINAPI IDirectSoundBufferImpl_Restore(
1605 LPDIRECTSOUNDBUFFER iface
1607 ICOM_THIS(IDirectSoundBufferImpl,iface);
1608 FIXME("(%p):stub\n",This);
1612 static HRESULT WINAPI IDirectSoundBufferImpl_GetFrequency(
1613 LPDIRECTSOUNDBUFFER iface,LPDWORD freq
1615 ICOM_THIS(IDirectSoundBufferImpl,iface);
1616 TRACE("(%p,%p)\n",This,freq);
1619 return DSERR_INVALIDPARAM;
1622 TRACE("-> %ld\n", *freq);
1627 static HRESULT WINAPI IDirectSoundBufferImpl_Initialize(
1628 LPDIRECTSOUNDBUFFER iface,LPDIRECTSOUND dsound,LPDSBUFFERDESC dbsd
1630 ICOM_THIS(IDirectSoundBufferImpl,iface);
1631 FIXME("(%p,%p,%p):stub\n",This,dsound,dbsd);
1632 DPRINTF("Re-Init!!!\n");
1633 return DSERR_ALREADYINITIALIZED;
1636 static HRESULT WINAPI IDirectSoundBufferImpl_GetCaps(
1637 LPDIRECTSOUNDBUFFER iface,LPDSBCAPS caps
1639 ICOM_THIS(IDirectSoundBufferImpl,iface);
1640 TRACE("(%p)->(%p)\n",This,caps);
1643 return DSERR_INVALIDPARAM;
1645 /* I think we should check this value, not set it. See */
1646 /* Inside DirectX, p215. That should apply here, too. */
1647 caps->dwSize = sizeof(*caps);
1649 caps->dwFlags = This->dsbd.dwFlags;
1650 if (This->hwbuf) caps->dwFlags |= DSBCAPS_LOCHARDWARE;
1651 else caps->dwFlags |= DSBCAPS_LOCSOFTWARE;
1653 caps->dwBufferBytes = This->dsbd.dwBufferBytes;
1655 /* This value represents the speed of the "unlock" command.
1656 As unlock is quite fast (it does not do anything), I put
1657 4096 ko/s = 4 Mo / s */
1658 /* FIXME: hwbuf speed */
1659 caps->dwUnlockTransferRate = 4096;
1660 caps->dwPlayCpuOverhead = 0;
1665 static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface(
1666 LPDIRECTSOUNDBUFFER iface,REFIID riid,LPVOID *ppobj
1668 ICOM_THIS(IDirectSoundBufferImpl,iface);
1670 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
1672 if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
1673 IDirectSoundNotifyImpl *dsn;
1675 dsn = (IDirectSoundNotifyImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(*dsn));
1678 IDirectSoundBuffer_AddRef(iface);
1679 ICOM_VTBL(dsn) = &dsnvt;
1680 *ppobj = (LPVOID)dsn;
1685 if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) {
1686 IDirectSound3DBufferImpl *ds3db;
1688 *ppobj = This->ds3db;
1690 IDirectSound3DBuffer_AddRef((LPDIRECTSOUND3DBUFFER)This->ds3db);
1694 ds3db = (IDirectSound3DBufferImpl*)HeapAlloc(GetProcessHeap(),
1697 ds3db->dsb = (*ippdsb);
1698 ICOM_VTBL(ds3db) = &ds3dbvt;
1699 InitializeCriticalSection(&ds3db->lock);
1701 ds3db->ds3db = This;
1702 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)This);
1704 ds3db->ds3db.dwSize = sizeof(DS3DBUFFER);
1705 ds3db->ds3db.vPosition.x.x = 0.0;
1706 ds3db->ds3db.vPosition.y.y = 0.0;
1707 ds3db->ds3db.vPosition.z.z = 0.0;
1708 ds3db->ds3db.vVelocity.x.x = 0.0;
1709 ds3db->ds3db.vVelocity.y.y = 0.0;
1710 ds3db->ds3db.vVelocity.z.z = 0.0;
1711 ds3db->ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
1712 ds3db->ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
1713 ds3db->ds3db.vConeOrientation.x.x = 0.0;
1714 ds3db->ds3db.vConeOrientation.y.y = 0.0;
1715 ds3db->ds3db.vConeOrientation.z.z = 0.0;
1716 ds3db->ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME; ds3db->ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE;
1717 ds3db->ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
1718 ds3db->ds3db.dwMode = DS3DMODE_NORMAL;
1719 ds3db->buflen = ((*ippdsb)->buflen * primarybuf->wfx.nBlockAlign) /
1720 (*ippdsb)->wfx.nBlockAlign;
1721 ds3db->buffer = HeapAlloc(GetProcessHeap(), 0, ds3db->buflen);
1722 if (ds3db->buffer == NULL) {
1724 ds3db->ds3db.dwMode = DS3DMODE_DISABLE;
1731 if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
1732 IDirectSound3DListenerImpl* dsl;
1734 if (This->dsound->listener) {
1735 *ppobj = This->dsound->listener;
1736 IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER)This->dsound->listener);
1740 dsl = (IDirectSound3DListenerImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(*dsl));
1742 ICOM_VTBL(dsl) = &ds3dlvt;
1743 *ppobj = (LPVOID)dsl;
1745 dsl->ds3dl.dwSize = sizeof(DS3DLISTENER);
1746 dsl->ds3dl.vPosition.u1.x = 0.0;
1747 dsl->ds3dl.vPosition.u2.y = 0.0;
1748 dsl->ds3dl.vPosition.u3.z = 0.0;
1749 dsl->ds3dl.vVelocity.u1.x = 0.0;
1750 dsl->ds3dl.vVelocity.u2.y = 0.0;
1751 dsl->ds3dl.vVelocity.u3.z = 0.0;
1752 dsl->ds3dl.vOrientFront.u1.x = 0.0;
1753 dsl->ds3dl.vOrientFront.u2.y = 0.0;
1754 dsl->ds3dl.vOrientFront.u3.z = 1.0;
1755 dsl->ds3dl.vOrientTop.u1.x = 0.0;
1756 dsl->ds3dl.vOrientTop.u2.y = 1.0;
1757 dsl->ds3dl.vOrientTop.u3.z = 0.0;
1758 dsl->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
1759 dsl->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
1761 InitializeCriticalSection(&dsl->lock);
1764 IDirectSoundBuffer_AddRef(iface);
1766 This->dsound->listener = dsl;
1767 IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER)dsl);
1772 FIXME( "Unknown GUID %s\n", debugstr_guid( riid ) );
1779 static ICOM_VTABLE(IDirectSoundBuffer) dsbvt =
1781 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1782 IDirectSoundBufferImpl_QueryInterface,
1783 IDirectSoundBufferImpl_AddRef,
1784 IDirectSoundBufferImpl_Release,
1785 IDirectSoundBufferImpl_GetCaps,
1786 IDirectSoundBufferImpl_GetCurrentPosition,
1787 IDirectSoundBufferImpl_GetFormat,
1788 IDirectSoundBufferImpl_GetVolume,
1789 IDirectSoundBufferImpl_GetPan,
1790 IDirectSoundBufferImpl_GetFrequency,
1791 IDirectSoundBufferImpl_GetStatus,
1792 IDirectSoundBufferImpl_Initialize,
1793 IDirectSoundBufferImpl_Lock,
1794 IDirectSoundBufferImpl_Play,
1795 IDirectSoundBufferImpl_SetCurrentPosition,
1796 IDirectSoundBufferImpl_SetFormat,
1797 IDirectSoundBufferImpl_SetVolume,
1798 IDirectSoundBufferImpl_SetPan,
1799 IDirectSoundBufferImpl_SetFrequency,
1800 IDirectSoundBufferImpl_Stop,
1801 IDirectSoundBufferImpl_Unlock,
1802 IDirectSoundBufferImpl_Restore
1805 /*******************************************************************************
1809 static HRESULT WINAPI IDirectSoundImpl_SetCooperativeLevel(
1810 LPDIRECTSOUND iface,HWND hwnd,DWORD level
1812 ICOM_THIS(IDirectSoundImpl,iface);
1814 FIXME("(%p,%08lx,%ld):stub\n",This,(DWORD)hwnd,level);
1816 This->priolevel = level;
1821 static HRESULT WINAPI IDirectSoundImpl_CreateSoundBuffer(
1822 LPDIRECTSOUND iface,LPDSBUFFERDESC dsbd,LPLPDIRECTSOUNDBUFFER ppdsb,LPUNKNOWN lpunk
1824 ICOM_THIS(IDirectSoundImpl,iface);
1825 IDirectSoundBufferImpl** ippdsb=(IDirectSoundBufferImpl**)ppdsb;
1826 LPWAVEFORMATEX wfex;
1827 HRESULT err = DS_OK;
1829 TRACE("(%p,%p,%p,%p)\n",This,dsbd,ippdsb,lpunk);
1831 if ((This == NULL) || (dsbd == NULL) || (ippdsb == NULL))
1832 return DSERR_INVALIDPARAM;
1834 if (TRACE_ON(dsound)) {
1835 TRACE("(structsize=%ld)\n",dsbd->dwSize);
1836 TRACE("(flags=0x%08lx:\n",dsbd->dwFlags);
1837 _dump_DSBCAPS(dsbd->dwFlags);
1839 TRACE("(bufferbytes=%ld)\n",dsbd->dwBufferBytes);
1840 TRACE("(lpwfxFormat=%p)\n",dsbd->lpwfxFormat);
1843 wfex = dsbd->lpwfxFormat;
1846 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
1847 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1848 wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
1849 wfex->nAvgBytesPerSec, wfex->nBlockAlign,
1850 wfex->wBitsPerSample, wfex->cbSize);
1852 if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
1854 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)primarybuf);
1855 *ippdsb = primarybuf;
1856 primarybuf->dsbd.dwFlags = dsbd->dwFlags;
1858 } /* Else create primary buffer */
1861 *ippdsb = (IDirectSoundBufferImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundBufferImpl));
1862 if (*ippdsb == NULL)
1863 return DSERR_OUTOFMEMORY;
1864 ICOM_VTBL(*ippdsb) = &dsbvt;
1866 (*ippdsb)->dsound = This;
1867 (*ippdsb)->parent = NULL;
1868 (*ippdsb)->buffer = NULL;
1870 memcpy(&((*ippdsb)->dsbd),dsbd,sizeof(*dsbd));
1871 if (dsbd->lpwfxFormat)
1872 memcpy(&((*ippdsb)->wfx), dsbd->lpwfxFormat, sizeof((*ippdsb)->wfx));
1874 TRACE("Created buffer at %p\n", *ippdsb);
1876 if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
1877 (*ippdsb)->buflen = dsound->wfx.nAvgBytesPerSec;
1878 (*ippdsb)->freq = dsound->wfx.nSamplesPerSec;
1880 /* FIXME: verify that hardware capabilities (DSCAPS_PRIMARY flags) match */
1883 err = IDsDriver_CreateSoundBuffer(This->driver,wfex,dsbd->dwFlags,0,
1884 &((*ippdsb)->buflen),&((*ippdsb)->buffer),
1885 (LPVOID*)&((*ippdsb)->hwbuf));
1888 err = DSOUND_PrimaryOpen(*ippdsb);
1893 (*ippdsb)->buflen = dsbd->dwBufferBytes;
1894 (*ippdsb)->freq = dsbd->lpwfxFormat->nSamplesPerSec;
1896 /* Check necessary hardware mixing capabilities */
1897 if (wfex->nChannels==2) capf |= DSCAPS_SECONDARYSTEREO;
1898 else capf |= DSCAPS_SECONDARYMONO;
1899 if (wfex->wBitsPerSample==16) capf |= DSCAPS_SECONDARY16BIT;
1900 else capf |= DSCAPS_SECONDARY8BIT;
1901 use_hw = (This->drvcaps.dwFlags & capf) == capf;
1903 /* FIXME: check hardware sample rate mixing capabilities */
1904 /* FIXME: check app hints for software/hardware buffer (STATIC, LOCHARDWARE, etc) */
1905 /* FIXME: check whether any hardware buffers are left */
1906 /* FIXME: handle DSDHEAP_CREATEHEAP for hardware buffers */
1908 /* Allocate system memory if applicable */
1909 if ((This->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) || !use_hw) {
1910 (*ippdsb)->buffer = (LPBYTE)HeapAlloc(GetProcessHeap(),0,(*ippdsb)->buflen);
1911 if ((*ippdsb)->buffer == NULL)
1912 err = DSERR_OUTOFMEMORY;
1915 /* Allocate the hardware buffer */
1916 if (use_hw && (err == DS_OK)) {
1917 err = IDsDriver_CreateSoundBuffer(This->driver,wfex,dsbd->dwFlags,0,
1918 &((*ippdsb)->buflen),&((*ippdsb)->buffer),
1919 (LPVOID*)&((*ippdsb)->hwbuf));
1924 if ((*ippdsb)->buffer)
1925 HeapFree(GetProcessHeap(),0,(*ippdsb)->buffer);
1926 HeapFree(GetProcessHeap(),0,(*ippdsb));
1930 /* calculate fragment size and write lead */
1931 DSOUND_RecalcFormat(*ippdsb);
1933 /* It's not necessary to initialize values to zero since */
1934 /* we allocated this structure with HEAP_ZERO_MEMORY... */
1935 (*ippdsb)->playpos = 0;
1936 (*ippdsb)->mixpos = 0;
1937 (*ippdsb)->state = STATE_STOPPED;
1938 DSOUND_RecalcVolPan(&((*ippdsb)->volpan));
1940 if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
1941 (*ippdsb)->freqAdjust = ((*ippdsb)->freq << DSOUND_FREQSHIFT) /
1942 primarybuf->wfx.nSamplesPerSec;
1943 (*ippdsb)->nAvgBytesPerSec = (*ippdsb)->freq *
1944 dsbd->lpwfxFormat->nBlockAlign;
1947 EnterCriticalSection(&(This->lock));
1948 /* register buffer */
1949 if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
1950 IDirectSoundBufferImpl **newbuffers = (IDirectSoundBufferImpl**)HeapReAlloc(GetProcessHeap(),0,This->buffers,sizeof(IDirectSoundBufferImpl*)*(This->nrofbuffers+1));
1952 This->buffers = newbuffers;
1953 This->buffers[This->nrofbuffers] = *ippdsb;
1954 This->nrofbuffers++;
1955 TRACE("buffer count is now %d\n", This->nrofbuffers);
1957 ERR("out of memory for buffer list! Current buffer count is %d\n", This->nrofbuffers);
1958 err = DSERR_OUTOFMEMORY;
1961 LeaveCriticalSection(&(This->lock));
1963 IDirectSound_AddRef(iface);
1965 InitializeCriticalSection(&((*ippdsb)->lock));
1969 IDirectSoundBuffer_Release(*ppdsb);
1975 if (dsbd->dwFlags & DSBCAPS_CTRL3D) {
1976 IDirectSound3DBufferImpl *ds3db;
1978 ds3db = (IDirectSound3DBufferImpl*)HeapAlloc(GetProcessHeap(),
1980 ICOM_VTBL(ds3db) = &ds3dbvt;
1982 (*ippdsb)->ds3db = ds3db;
1984 ds3db->dsb = (*ippdsb);
1985 IDirectSoundBufferImpl_AddRef((LPDIRECTSOUNDBUFFER)ippdsb);
1987 InitializeCriticalSection(&ds3db->lock);
1989 ds3db->ds3db.dwSize = sizeof(DS3DBUFFER);
1990 ds3db->ds3db.vPosition.x.x = 0.0;
1991 ds3db->ds3db.vPosition.y.y = 0.0;
1992 ds3db->ds3db.vPosition.z.z = 0.0;
1993 ds3db->ds3db.vVelocity.x.x = 0.0;
1994 ds3db->ds3db.vVelocity.y.y = 0.0;
1995 ds3db->ds3db.vVelocity.z.z = 0.0;
1996 ds3db->ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
1997 ds3db->ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
1998 ds3db->ds3db.vConeOrientation.x.x = 0.0;
1999 ds3db->ds3db.vConeOrientation.y.y = 0.0;
2000 ds3db->ds3db.vConeOrientation.z.z = 0.0;
2001 ds3db->ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
2002 ds3db->ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE;
2003 ds3db->ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
2004 ds3db->ds3db.dwMode = DS3DMODE_NORMAL;
2005 ds3db->buflen = ((*ippdsb)->buflen * primarybuf->wfx.nBlockAlign) /
2006 (*ippdsb)->wfx.nBlockAlign;
2007 ds3db->buffer = HeapAlloc(GetProcessHeap(), 0, ds3db->buflen);
2008 if (ds3db->buffer == NULL) {
2010 ds3db->ds3db.dwMode = DS3DMODE_DISABLE;
2017 static HRESULT WINAPI IDirectSoundImpl_DuplicateSoundBuffer(
2018 LPDIRECTSOUND iface,LPDIRECTSOUNDBUFFER pdsb,LPLPDIRECTSOUNDBUFFER ppdsb
2020 ICOM_THIS(IDirectSoundImpl,iface);
2021 IDirectSoundBufferImpl* ipdsb=(IDirectSoundBufferImpl*)pdsb;
2022 IDirectSoundBufferImpl** ippdsb=(IDirectSoundBufferImpl**)ppdsb;
2023 TRACE("(%p,%p,%p)\n",This,ipdsb,ippdsb);
2026 FIXME("need to duplicate hardware buffer\n");
2029 *ippdsb = (IDirectSoundBufferImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundBufferImpl));
2031 IDirectSoundBuffer_AddRef(pdsb);
2032 memcpy(*ippdsb, ipdsb, sizeof(IDirectSoundBufferImpl));
2034 (*ippdsb)->playpos = 0;
2035 (*ippdsb)->mixpos = 0;
2036 (*ippdsb)->dsound = This;
2037 (*ippdsb)->parent = ipdsb;
2038 memcpy(&((*ippdsb)->wfx), &(ipdsb->wfx), sizeof((*ippdsb)->wfx));
2039 InitializeCriticalSection(&(*ippdsb)->lock);
2040 /* register buffer */
2041 EnterCriticalSection(&(This->lock));
2043 IDirectSoundBufferImpl **newbuffers = (IDirectSoundBufferImpl**)HeapReAlloc(GetProcessHeap(),0,This->buffers,sizeof(IDirectSoundBufferImpl**)*(This->nrofbuffers+1));
2045 This->buffers = newbuffers;
2046 This->buffers[This->nrofbuffers] = *ippdsb;
2047 This->nrofbuffers++;
2048 TRACE("buffer count is now %d\n", This->nrofbuffers);
2050 ERR("out of memory for buffer list! Current buffer count is %d\n", This->nrofbuffers);
2051 /* FIXME: release buffer */
2054 LeaveCriticalSection(&(This->lock));
2055 IDirectSound_AddRef(iface);
2060 static HRESULT WINAPI IDirectSoundImpl_GetCaps(LPDIRECTSOUND iface,LPDSCAPS caps) {
2061 ICOM_THIS(IDirectSoundImpl,iface);
2062 TRACE("(%p,%p)\n",This,caps);
2063 TRACE("(flags=0x%08lx)\n",caps->dwFlags);
2066 return DSERR_INVALIDPARAM;
2068 /* We should check this value, not set it. See Inside DirectX, p215. */
2069 caps->dwSize = sizeof(*caps);
2071 caps->dwFlags = This->drvcaps.dwFlags;
2073 /* FIXME: copy caps from This->drvcaps */
2074 caps->dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
2075 caps->dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
2077 caps->dwPrimaryBuffers = 1;
2079 caps->dwMaxHwMixingAllBuffers = 0;
2080 caps->dwMaxHwMixingStaticBuffers = 0;
2081 caps->dwMaxHwMixingStreamingBuffers = 0;
2083 caps->dwFreeHwMixingAllBuffers = 0;
2084 caps->dwFreeHwMixingStaticBuffers = 0;
2085 caps->dwFreeHwMixingStreamingBuffers = 0;
2087 caps->dwMaxHw3DAllBuffers = 0;
2088 caps->dwMaxHw3DStaticBuffers = 0;
2089 caps->dwMaxHw3DStreamingBuffers = 0;
2091 caps->dwFreeHw3DAllBuffers = 0;
2092 caps->dwFreeHw3DStaticBuffers = 0;
2093 caps->dwFreeHw3DStreamingBuffers = 0;
2095 caps->dwTotalHwMemBytes = 0;
2097 caps->dwFreeHwMemBytes = 0;
2099 caps->dwMaxContigFreeHwMemBytes = 0;
2101 caps->dwUnlockTransferRateHwBuffers = 4096; /* But we have none... */
2103 caps->dwPlayCpuOverheadSwBuffers = 1; /* 1% */
2108 static ULONG WINAPI IDirectSoundImpl_AddRef(LPDIRECTSOUND iface) {
2109 ICOM_THIS(IDirectSoundImpl,iface);
2110 return ++(This->ref);
2113 static ULONG WINAPI IDirectSoundImpl_Release(LPDIRECTSOUND iface) {
2114 ICOM_THIS(IDirectSoundImpl,iface);
2115 TRACE("(%p), ref was %ld\n",This,This->ref);
2116 if (!--(This->ref)) {
2119 timeKillEvent(This->timerID);
2120 timeEndPeriod(DS_TIME_RES);
2123 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)primarybuf);
2125 if (This->buffers) {
2126 for( i=0;i<This->nrofbuffers;i++)
2127 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->buffers[i]);
2131 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->primary);
2133 DeleteCriticalSection(&This->lock);
2135 IDsDriver_Close(This->driver);
2138 for (c=0; c<DS_HEL_FRAGS; c++)
2139 HeapFree(GetProcessHeap(),0,This->pwave[c]);
2141 if (This->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN) {
2142 waveOutClose(This->hwo);
2145 IDsDriver_Release(This->driver);
2147 HeapFree(GetProcessHeap(),0,This);
2154 static HRESULT WINAPI IDirectSoundImpl_SetSpeakerConfig(
2155 LPDIRECTSOUND iface,DWORD config
2157 ICOM_THIS(IDirectSoundImpl,iface);
2158 FIXME("(%p,0x%08lx):stub\n",This,config);
2162 static HRESULT WINAPI IDirectSoundImpl_QueryInterface(
2163 LPDIRECTSOUND iface,REFIID riid,LPVOID *ppobj
2165 ICOM_THIS(IDirectSoundImpl,iface);
2167 if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
2169 if (This->listener) {
2170 *ppobj = This->listener;
2171 IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER)This->listener);
2175 This->listener = (IDirectSound3DListenerImpl*)HeapAlloc(
2176 GetProcessHeap(), 0, sizeof(*(This->listener)));
2177 This->listener->ref = 1;
2178 ICOM_VTBL(This->listener) = &ds3dlvt;
2179 *ppobj = (LPVOID)This->listener;
2180 IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER)*ppobj);
2182 This->listener->dsb = NULL;
2184 This->listener->ds3dl.dwSize = sizeof(DS3DLISTENER);
2185 This->listener->ds3dl.vPosition.u1.x = 0.0;
2186 This->listener->ds3dl.vPosition.u2.y = 0.0;
2187 This->listener->ds3dl.vPosition.u3.z = 0.0;
2188 This->listener->ds3dl.vVelocity.u1.x = 0.0;
2189 This->listener->ds3dl.vVelocity.u2.y = 0.0;
2190 This->listener->ds3dl.vVelocity.u3.z = 0.0;
2191 This->listener->ds3dl.vOrientFront.u1.x = 0.0;
2192 This->listener->ds3dl.vOrientFront.u2.y = 0.0;
2193 This->listener->ds3dl.vOrientFront.u3.z = 1.0;
2194 This->listener->ds3dl.vOrientTop.u1.x = 0.0;
2195 This->listener->ds3dl.vOrientTop.u2.y = 1.0;
2196 This->listener->ds3dl.vOrientTop.u3.z = 0.0;
2197 This->listener->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
2198 This->listener->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
2199 This->listener->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
2201 InitializeCriticalSection(&This->listener->lock);
2206 FIXME("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
2210 static HRESULT WINAPI IDirectSoundImpl_Compact(
2211 LPDIRECTSOUND iface)
2213 ICOM_THIS(IDirectSoundImpl,iface);
2214 TRACE("(%p)\n", This);
2218 static HRESULT WINAPI IDirectSoundImpl_GetSpeakerConfig(
2219 LPDIRECTSOUND iface,
2220 LPDWORD lpdwSpeakerConfig)
2222 ICOM_THIS(IDirectSoundImpl,iface);
2223 TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
2224 *lpdwSpeakerConfig = DSSPEAKER_STEREO | (DSSPEAKER_GEOMETRY_NARROW << 16);
2228 static HRESULT WINAPI IDirectSoundImpl_Initialize(
2229 LPDIRECTSOUND iface,
2232 ICOM_THIS(IDirectSoundImpl,iface);
2233 TRACE("(%p, %p)\n", This, lpcGuid);
2237 static ICOM_VTABLE(IDirectSound) dsvt =
2239 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
2240 IDirectSoundImpl_QueryInterface,
2241 IDirectSoundImpl_AddRef,
2242 IDirectSoundImpl_Release,
2243 IDirectSoundImpl_CreateSoundBuffer,
2244 IDirectSoundImpl_GetCaps,
2245 IDirectSoundImpl_DuplicateSoundBuffer,
2246 IDirectSoundImpl_SetCooperativeLevel,
2247 IDirectSoundImpl_Compact,
2248 IDirectSoundImpl_GetSpeakerConfig,
2249 IDirectSoundImpl_SetSpeakerConfig,
2250 IDirectSoundImpl_Initialize
2254 static void DSOUND_CheckEvent(IDirectSoundBufferImpl *dsb, int len)
2258 LPDSBPOSITIONNOTIFY event;
2260 if (dsb->nrofnotifies == 0)
2263 TRACE("(%p) buflen = %ld, playpos = %ld, len = %d\n",
2264 dsb, dsb->buflen, dsb->playpos, len);
2265 for (i = 0; i < dsb->nrofnotifies ; i++) {
2266 event = dsb->notifies + i;
2267 offset = event->dwOffset;
2268 TRACE("checking %d, position %ld, event = %d\n",
2269 i, offset, event->hEventNotify);
2270 /* DSBPN_OFFSETSTOP has to be the last element. So this is */
2271 /* OK. [Inside DirectX, p274] */
2273 /* This also means we can't sort the entries by offset, */
2274 /* because DSBPN_OFFSETSTOP == -1 */
2275 if (offset == DSBPN_OFFSETSTOP) {
2276 if (dsb->state == STATE_STOPPED) {
2277 SetEvent(event->hEventNotify);
2278 TRACE("signalled event %d (%d)\n", event->hEventNotify, i);
2283 if ((dsb->playpos + len) >= dsb->buflen) {
2284 if ((offset < ((dsb->playpos + len) % dsb->buflen)) ||
2285 (offset >= dsb->playpos)) {
2286 TRACE("signalled event %d (%d)\n", event->hEventNotify, i);
2287 SetEvent(event->hEventNotify);
2290 if ((offset >= dsb->playpos) && (offset < (dsb->playpos + len))) {
2291 TRACE("signalled event %d (%d)\n", event->hEventNotify, i);
2292 SetEvent(event->hEventNotify);
2298 /* WAV format info can be found at: */
2300 /* http://www.cwi.nl/ftp/audio/AudioFormats.part2 */
2301 /* ftp://ftp.cwi.nl/pub/audio/RIFF-format */
2303 /* Import points to remember: */
2305 /* 8-bit WAV is unsigned */
2306 /* 16-bit WAV is signed */
2308 static inline INT16 cvtU8toS16(BYTE byte)
2310 INT16 s = (byte - 128) << 8;
2315 static inline BYTE cvtS16toU8(INT16 word)
2317 BYTE b = (word + 32768) >> 8;
2323 /* We should be able to optimize these two inline functions */
2324 /* so that we aren't doing 8->16->8 conversions when it is */
2325 /* not necessary. But this is still a WIP. Optimize later. */
2326 static inline void get_fields(const IDirectSoundBufferImpl *dsb, BYTE *buf, INT *fl, INT *fr)
2328 INT16 *bufs = (INT16 *) buf;
2330 /* TRACE("(%p)", buf); */
2331 if ((dsb->wfx.wBitsPerSample == 8) && dsb->wfx.nChannels == 2) {
2332 *fl = cvtU8toS16(*buf);
2333 *fr = cvtU8toS16(*(buf + 1));
2337 if ((dsb->wfx.wBitsPerSample == 16) && dsb->wfx.nChannels == 2) {
2343 if ((dsb->wfx.wBitsPerSample == 8) && dsb->wfx.nChannels == 1) {
2344 *fl = cvtU8toS16(*buf);
2349 if ((dsb->wfx.wBitsPerSample == 16) && dsb->wfx.nChannels == 1) {
2355 FIXME("get_fields found an unsupported configuration\n");
2359 static inline void set_fields(BYTE *buf, INT fl, INT fr)
2361 INT16 *bufs = (INT16 *) buf;
2363 if ((primarybuf->wfx.wBitsPerSample == 8) && (primarybuf->wfx.nChannels == 2)) {
2364 *buf = cvtS16toU8(fl);
2365 *(buf + 1) = cvtS16toU8(fr);
2369 if ((primarybuf->wfx.wBitsPerSample == 16) && (primarybuf->wfx.nChannels == 2)) {
2375 if ((primarybuf->wfx.wBitsPerSample == 8) && (primarybuf->wfx.nChannels == 1)) {
2376 *buf = cvtS16toU8((fl + fr) >> 1);
2380 if ((primarybuf->wfx.wBitsPerSample == 16) && (primarybuf->wfx.nChannels == 1)) {
2381 *bufs = (fl + fr) >> 1;
2384 FIXME("set_fields found an unsupported configuration\n");
2388 /* Now with PerfectPitch (tm) technology */
2389 static INT DSOUND_MixerNorm(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len)
2391 INT i, size, ipos, ilen, fieldL, fieldR;
2393 INT iAdvance = dsb->wfx.nBlockAlign;
2394 INT oAdvance = primarybuf->wfx.nBlockAlign;
2396 ibp = dsb->buffer + dsb->mixpos;
2399 TRACE("(%p, %p, %p), mixpos=%ld\n", dsb, ibp, obp, dsb->mixpos);
2400 /* Check for the best case */
2401 if ((dsb->freq == primarybuf->wfx.nSamplesPerSec) &&
2402 (dsb->wfx.wBitsPerSample == primarybuf->wfx.wBitsPerSample) &&
2403 (dsb->wfx.nChannels == primarybuf->wfx.nChannels)) {
2404 DWORD bytesleft = dsb->buflen - dsb->mixpos;
2405 TRACE("(%p) Best case\n", dsb);
2406 if (len <= bytesleft )
2407 memcpy(obp, ibp, len);
2409 memcpy(obp, ibp, bytesleft );
2410 memcpy(obp + bytesleft, dsb->buffer, len - bytesleft);
2415 /* Check for same sample rate */
2416 if (dsb->freq == primarybuf->wfx.nSamplesPerSec) {
2417 TRACE("(%p) Same sample rate %ld = primary %ld\n", dsb,
2418 dsb->freq, primarybuf->wfx.nSamplesPerSec);
2420 for (i = 0; i < len; i += oAdvance) {
2421 get_fields(dsb, ibp, &fieldL, &fieldR);
2424 set_fields(obp, fieldL, fieldR);
2426 if (ibp >= (BYTE *)(dsb->buffer + dsb->buflen))
2427 ibp = dsb->buffer; /* wrap */
2432 /* Mix in different sample rates */
2434 /* New PerfectPitch(tm) Technology (c) 1998 Rob Riggs */
2435 /* Patent Pending :-] */
2437 TRACE("(%p) Adjusting frequency: %ld -> %ld\n",
2438 dsb, dsb->freq, primarybuf->wfx.nSamplesPerSec);
2440 size = len / oAdvance;
2441 ilen = ((size * dsb->freqAdjust) >> DSOUND_FREQSHIFT) * iAdvance;
2442 for (i = 0; i < size; i++) {
2444 ipos = (((i * dsb->freqAdjust) >> DSOUND_FREQSHIFT) * iAdvance) + dsb->mixpos;
2446 if (ipos >= dsb->buflen)
2447 ipos %= dsb->buflen; /* wrap */
2449 get_fields(dsb, (dsb->buffer + ipos), &fieldL, &fieldR);
2450 set_fields(obp, fieldL, fieldR);
2456 static void DSOUND_MixerVol(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len)
2458 INT i, inc = primarybuf->wfx.wBitsPerSample >> 3;
2460 INT16 *bps = (INT16 *) buf;
2462 TRACE("(%p) left = %lx, right = %lx\n", dsb,
2463 dsb->volpan.dwTotalLeftAmpFactor, dsb->volpan.dwTotalRightAmpFactor);
2464 if ((!(dsb->dsbd.dwFlags & DSBCAPS_CTRLPAN) || (dsb->volpan.lPan == 0)) &&
2465 (!(dsb->dsbd.dwFlags & DSBCAPS_CTRLVOLUME) || (dsb->volpan.lVolume == 0)) &&
2466 !(dsb->dsbd.dwFlags & DSBCAPS_CTRL3D))
2467 return; /* Nothing to do */
2469 /* If we end up with some bozo coder using panning or 3D sound */
2470 /* with a mono primary buffer, it could sound very weird using */
2471 /* this method. Oh well, tough patooties. */
2473 for (i = 0; i < len; i += inc) {
2479 /* 8-bit WAV is unsigned, but we need to operate */
2480 /* on signed data for this to work properly */
2482 val = ((val * (i & inc ? dsb->volpan.dwTotalRightAmpFactor : dsb->volpan.dwTotalLeftAmpFactor)) >> 16);
2487 /* 16-bit WAV is signed -- much better */
2489 val = ((val * ((i & inc) ? dsb->volpan.dwTotalRightAmpFactor : dsb->volpan.dwTotalLeftAmpFactor)) >> 16);
2495 FIXME("MixerVol had a nasty error\n");
2501 static void DSOUND_Mixer3D(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len)
2504 DWORD buflen, mixpos;
2506 buflen = dsb->ds3db->buflen;
2507 mixpos = (dsb->mixpos * primarybuf->wfx.nBlockAlign) / dsb->wfx.nBlockAlign;
2508 ibp = dsb->ds3db->buffer + mixpos;
2511 if (mixpos > buflen) {
2512 FIXME("Major breakage");
2516 if (len <= (mixpos + buflen))
2517 memcpy(obp, ibp, len);
2519 memcpy(obp, ibp, buflen - mixpos);
2520 memcpy(obp + (buflen - mixpos),
2522 len - (buflen - mixpos));
2528 static void *tmp_buffer;
2529 static size_t tmp_buffer_len = 0;
2531 static void *DSOUND_tmpbuffer(size_t len)
2533 if (len>tmp_buffer_len) {
2534 void *new_buffer = realloc(tmp_buffer, len);
2536 tmp_buffer = new_buffer;
2537 tmp_buffer_len = len;
2544 static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD fraglen)
2546 INT i, len, ilen, temp, field;
2547 INT advance = primarybuf->wfx.wBitsPerSample >> 3;
2548 BYTE *buf, *ibuf, *obuf;
2549 INT16 *ibufs, *obufs;
2552 if (!(dsb->playflags & DSBPLAY_LOOPING)) {
2553 temp = MulDiv(primarybuf->wfx.nAvgBytesPerSec, dsb->buflen,
2554 dsb->nAvgBytesPerSec) -
2555 MulDiv(primarybuf->wfx.nAvgBytesPerSec, dsb->mixpos,
2556 dsb->nAvgBytesPerSec);
2557 len = (len > temp) ? temp : len;
2559 len &= ~3; /* 4 byte alignment */
2562 /* This should only happen if we aren't looping and temp < 4 */
2564 /* We skip the remainder, so check for possible events */
2565 DSOUND_CheckEvent(dsb, dsb->buflen - dsb->mixpos);
2567 dsb->state = STATE_STOPPED;
2570 dsb->leadin = FALSE;
2571 /* Check for DSBPN_OFFSETSTOP */
2572 DSOUND_CheckEvent(dsb, 0);
2576 /* Been seeing segfaults in malloc() for some reason... */
2577 TRACE("allocating buffer (size = %d)\n", len);
2578 if ((buf = ibuf = (BYTE *) DSOUND_tmpbuffer(len)) == NULL)
2581 TRACE("MixInBuffer (%p) len = %d, dest = %ld\n", dsb, len, writepos);
2583 ilen = DSOUND_MixerNorm(dsb, ibuf, len);
2584 if ((dsb->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
2585 (dsb->dsbd.dwFlags & DSBCAPS_CTRLVOLUME))
2586 DSOUND_MixerVol(dsb, ibuf, len);
2588 obuf = primarybuf->buffer + writepos;
2589 for (i = 0; i < len; i += advance) {
2590 obufs = (INT16 *) obuf;
2591 ibufs = (INT16 *) ibuf;
2592 if (primarybuf->wfx.wBitsPerSample == 8) {
2593 /* 8-bit WAV is unsigned */
2594 field = (*ibuf - 128);
2595 field += (*obuf - 128);
2596 field = field > 127 ? 127 : field;
2597 field = field < -128 ? -128 : field;
2598 *obuf = field + 128;
2600 /* 16-bit WAV is signed */
2603 field = field > 32767 ? 32767 : field;
2604 field = field < -32768 ? -32768 : field;
2609 if (obuf >= (BYTE *)(primarybuf->buffer + primarybuf->buflen))
2610 obuf = primarybuf->buffer;
2614 if (dsb->dsbd.dwFlags & DSBCAPS_CTRLPOSITIONNOTIFY)
2615 DSOUND_CheckEvent(dsb, ilen);
2617 if (dsb->leadin && (dsb->startpos > dsb->mixpos) && (dsb->startpos <= dsb->mixpos + ilen)) {
2618 /* HACK... leadin should be reset when the PLAY position reaches the startpos,
2619 * not the MIX position... but if the sound buffer is bigger than our prebuffering
2620 * (which must be the case for the streaming buffers that need this hack anyway)
2621 * plus DS_HEL_MARGIN or equivalent, then this ought to work anyway. */
2622 dsb->leadin = FALSE;
2625 dsb->mixpos += ilen;
2627 if (dsb->mixpos >= dsb->buflen) {
2628 if (!(dsb->playflags & DSBPLAY_LOOPING)) {
2629 dsb->state = STATE_STOPPED;
2632 dsb->leadin = FALSE;
2633 DSOUND_CheckEvent(dsb, 0); /* For DSBPN_OFFSETSTOP */
2636 while (dsb->mixpos >= dsb->buflen)
2637 dsb->mixpos -= dsb->buflen;
2638 if (dsb->leadin && (dsb->startpos <= dsb->mixpos))
2639 dsb->leadin = FALSE; /* HACK: see above */
2646 static DWORD WINAPI DSOUND_MixPrimary(DWORD writepos, DWORD fraglen, BOOL starting)
2648 INT i, len, maxlen = 0;
2649 IDirectSoundBufferImpl *dsb;
2651 TRACE("(%ld,%ld,%d)\n", writepos, fraglen, starting);
2652 for (i = dsound->nrofbuffers - 1; i >= 0; i--) {
2653 dsb = dsound->buffers[i];
2655 if (!dsb || !(ICOM_VTBL(dsb)))
2657 if (dsb->buflen && dsb->state && !(starting && (dsb->state != STATE_STARTING))) {
2658 TRACE("Checking %p\n", dsb);
2659 EnterCriticalSection(&(dsb->lock));
2660 if (dsb->state == STATE_STOPPING) {
2661 /* FIXME: perhaps attempt to remove the buffer from the prebuffer */
2662 dsb->state = STATE_STOPPED;
2664 len = DSOUND_MixInBuffer(dsb, writepos, fraglen);
2665 maxlen = len > maxlen ? len : maxlen;
2667 LeaveCriticalSection(&(dsb->lock));
2674 static void WINAPI DSOUND_MarkPlaying(void)
2677 IDirectSoundBufferImpl *dsb;
2679 for (i = dsound->nrofbuffers - 1; i >= 0; i--) {
2680 dsb = dsound->buffers[i];
2682 if (!dsb || !(ICOM_VTBL(dsb)))
2684 if (dsb->buflen && (dsb->state == STATE_STARTING))
2685 dsb->state = STATE_PLAYING;
2689 static void CALLBACK DSOUND_timer(UINT timerID, UINT msg, DWORD dwUser, DWORD dw1, DWORD dw2)
2695 if (!dsound || !primarybuf) {
2696 ERR("dsound died without killing us?\n");
2697 timeKillEvent(timerID);
2698 timeEndPeriod(DS_TIME_RES);
2702 EnterCriticalSection(&(dsound->lock));
2704 if (!primarybuf || !primarybuf->ref) {
2705 /* seems the primary buffer is currently being released */
2706 LeaveCriticalSection(&(dsound->lock));
2710 /* the sound of silence */
2711 nfiller = primarybuf->wfx.wBitsPerSample == 8 ? 128 : 0;
2713 /* whether the primary is forced to play even without secondary buffers */
2714 forced = ((primarybuf->state == STATE_PLAYING) || (primarybuf->state == STATE_STARTING));
2716 if (primarybuf->hwbuf) {
2717 if (dsound->priolevel != DSSCL_WRITEPRIMARY) {
2718 BOOL paused = ((primarybuf->state == STATE_STOPPED) || (primarybuf->state == STATE_STARTING));
2719 DWORD playpos, writepos, inq, maxq, mixq, frag;
2720 IDsDriverBuffer_GetPosition(primarybuf->hwbuf, &playpos, &writepos);
2721 /* Well, we *could* do Just-In-Time mixing using the writepos,
2722 * but that's a little bit ambitious and unnecessary... */
2723 /* rather add our safety margin to the writepos, if we're playing */
2725 writepos += primarybuf->writelead;
2726 while (writepos >= primarybuf->buflen)
2727 writepos -= primarybuf->buflen;
2728 } else writepos = playpos;
2729 TRACE("primary playpos=%ld, writepos=%ld, clrpos=%ld, mixpos=%ld\n",
2730 playpos,writepos,primarybuf->playpos,primarybuf->mixpos);
2731 /* wipe out just-played sound data */
2732 if (playpos < primarybuf->playpos) {
2733 memset(primarybuf->buffer + primarybuf->playpos, nfiller, primarybuf->buflen - primarybuf->playpos);
2734 memset(primarybuf->buffer, nfiller, playpos);
2736 memset(primarybuf->buffer + primarybuf->playpos, nfiller, playpos - primarybuf->playpos);
2738 primarybuf->playpos = playpos;
2740 /* check how much prebuffering is left */
2741 inq = primarybuf->mixpos;
2743 inq += primarybuf->buflen;
2746 /* find the maximum we can prebuffer */
2749 if (maxq < writepos)
2750 maxq += primarybuf->buflen;
2752 } else maxq = primarybuf->buflen;
2754 /* clip maxq to DS_HAL_QUEUE */
2755 frag = DS_HAL_QUEUE * dsound->fraglen;
2756 if (maxq > frag) maxq = frag;
2758 EnterCriticalSection(&(primarybuf->lock));
2760 /* check for consistency */
2762 /* the playback position must have passed our last
2763 * mixed position, i.e. it's an underrun, or we have
2764 * nothing more to play */
2766 /* stop the playback now, to allow buffers to refill */
2767 IDsDriverBuffer_Stop(primarybuf->hwbuf);
2768 if (primarybuf->state == STATE_PLAYING) {
2769 primarybuf->state = STATE_STARTING;
2771 else if (primarybuf->state == STATE_STOPPING) {
2772 primarybuf->state = STATE_STOPPED;
2775 /* how can we have an underrun if we aren't playing? */
2776 ERR("unexpected primary state (%ld)\n", primarybuf->state);
2778 /* the Stop is supposed to reset play position to beginning of buffer */
2779 /* unfortunately, OSS is not able to do so, so get current pointer */
2780 IDsDriverBuffer_GetPosition(primarybuf->hwbuf, &playpos, NULL);
2782 primarybuf->playpos = playpos;
2783 primarybuf->mixpos = playpos;
2785 maxq = primarybuf->buflen;
2786 if (maxq > frag) maxq = frag;
2787 memset(primarybuf->buffer, nfiller, primarybuf->buflen);
2791 /* see if some new buffers have been started that we want to merge into our prebuffer;
2792 * this should minimize latency even when we have a large prebuffer */
2794 if (primarybuf->mixpos < writepos) {
2795 /* mix to end of buffer */
2796 len = DSOUND_MixPrimary(writepos, primarybuf->buflen - writepos, TRUE);
2797 if ((len + writepos) < primarybuf->buflen)
2798 goto addmix_complete;
2799 /* mix from beginning of buffer */
2800 if (primarybuf->mixpos)
2801 len = DSOUND_MixPrimary(0, primarybuf->mixpos, TRUE);
2803 /* mix middle of buffer */
2804 len = DSOUND_MixPrimary(writepos, primarybuf->mixpos - writepos, TRUE);
2808 DSOUND_MarkPlaying();
2811 TRACE("queued %ld, max %ld, mixing %ld, paused %d\n", inq, maxq, mixq, paused);
2812 /* it's too inefficient to mix less than a fragment at a time */
2813 if (mixq >= dsound->fraglen) {
2815 #define FRAG_MIXER \
2816 if (frag > mixq) frag = mixq; \
2817 len = DSOUND_MixPrimary(primarybuf->mixpos, frag, FALSE); \
2818 if (forced) len = frag; \
2819 primarybuf->mixpos += len; \
2820 mixq -= len; inq += len
2822 if ((playpos < writepos) || (paused && (playpos == writepos))) {
2823 if (primarybuf->mixpos) {
2824 /* mix to end of buffer */
2825 frag = primarybuf->buflen - primarybuf->mixpos;
2827 if (primarybuf->mixpos < primarybuf->buflen)
2829 primarybuf->mixpos = 0;
2831 if (mixq >= dsound->fraglen) {
2832 /* mix from beginning of buffer */
2834 if ((!frag) && paused) frag = primarybuf->buflen;
2838 else if (playpos > writepos) {
2839 /* mix middle of buffer */
2840 frag = playpos - primarybuf->mixpos;
2844 /* this should preferably not happen... */
2845 ERR("mixer malfunction (ambiguous writepos)!\n");
2851 /* buffers have been filled, restart playback */
2852 if (primarybuf->state == STATE_STARTING) {
2853 IDsDriverBuffer_Play(primarybuf->hwbuf, 0, 0, DSBPLAY_LOOPING);
2854 primarybuf->state = STATE_PLAYING;
2856 else if (primarybuf->state == STATE_STOPPED) {
2857 /* the primarybuf is supposed to play if there's something to play
2858 * even if it is reported as stopped, so don't let this confuse you */
2859 IDsDriverBuffer_Play(primarybuf->hwbuf, 0, 0, DSBPLAY_LOOPING);
2860 primarybuf->state = STATE_STOPPING;
2863 LeaveCriticalSection(&(primarybuf->lock));
2865 /* in the DSSCL_WRITEPRIMARY mode, the app is totally in charge... */
2866 if (primarybuf->state == STATE_STARTING) {
2867 IDsDriverBuffer_Play(primarybuf->hwbuf, 0, 0, DSBPLAY_LOOPING);
2868 primarybuf->state = STATE_PLAYING;
2870 else if (primarybuf->state == STATE_STOPPING) {
2871 IDsDriverBuffer_Stop(primarybuf->hwbuf);
2872 primarybuf->state = STATE_STOPPED;
2876 /* using waveOut stuff */
2877 /* if no buffers are playing, we should be in pause mode now */
2879 /* clean out completed fragments */
2880 while (dsound->pwqueue && (dsound->pwave[dsound->pwplay]->dwFlags & WHDR_DONE)) {
2881 if (dsound->priolevel != DSSCL_WRITEPRIMARY) {
2882 DWORD pos = dsound->pwplay * dsound->fraglen;
2883 TRACE("done playing primary pos=%ld\n",pos);
2884 memset(primarybuf->buffer + pos, nfiller, dsound->fraglen);
2887 if (dsound->pwplay >= DS_HEL_FRAGS) dsound->pwplay = 0;
2890 primarybuf->playpos = dsound->pwplay * dsound->fraglen;
2891 TRACE("primary playpos=%ld, mixpos=%ld\n",primarybuf->playpos,primarybuf->mixpos);
2892 EnterCriticalSection(&(primarybuf->lock));
2893 if (!dsound->pwqueue) {
2894 /* this is either an underrun or we have nothing more to play...
2895 * since playback has already stopped now, we can enter pause mode,
2896 * in order to allow buffers to refill */
2897 if (primarybuf->state == STATE_PLAYING) {
2898 waveOutPause(dsound->hwo);
2899 primarybuf->state = STATE_STARTING;
2901 else if (primarybuf->state == STATE_STOPPING) {
2902 waveOutPause(dsound->hwo);
2903 primarybuf->state = STATE_STOPPED;
2907 /* find next write position, plus some extra margin */
2908 writepos = primarybuf->playpos + DS_HEL_MARGIN * dsound->fraglen;
2909 while (writepos >= primarybuf->buflen) writepos -= primarybuf->buflen;
2911 /* see if some new buffers have been started that we want to merge into our prebuffer;
2912 * this should minimize latency even when we have a large prebuffer */
2913 if (dsound->priolevel != DSSCL_WRITEPRIMARY) {
2914 if ((primarybuf->state == STATE_PLAYING) || (primarybuf->state == STATE_STOPPING)) {
2915 while (writepos != primarybuf->mixpos) {
2916 len = DSOUND_MixPrimary(writepos, dsound->fraglen, TRUE);
2918 writepos += dsound->fraglen;
2919 if (writepos >= primarybuf->buflen)
2920 writepos -= primarybuf->buflen;
2923 DSOUND_MarkPlaying();
2926 /* we want at least DS_HEL_QUEUE fragments in the prebuffer outqueue;
2927 * mix a bunch of fragments now as necessary */
2928 while (dsound->pwqueue < DS_HEL_QUEUE) {
2929 if (dsound->priolevel != DSSCL_WRITEPRIMARY) {
2930 len = DSOUND_MixPrimary(primarybuf->mixpos, dsound->fraglen, FALSE);
2932 if (forced) len = dsound->fraglen;
2933 /* if we have nothing to play, don't bother to */
2935 if (len < dsound->fraglen) {
2936 TRACE("len=%ld is less than fraglen=%ld\n",len,dsound->fraglen);
2938 /* ok, we have something to play */
2939 /* advance mix positions */
2940 primarybuf->mixpos += dsound->fraglen;
2941 if (primarybuf->mixpos >= primarybuf->buflen)
2942 primarybuf->mixpos -= primarybuf->buflen;
2944 waveOutWrite(dsound->hwo, dsound->pwave[dsound->pwwrite], sizeof(WAVEHDR));
2946 if (dsound->pwwrite >= DS_HEL_FRAGS) dsound->pwwrite = 0;
2949 if (dsound->pwqueue) {
2950 /* buffers have been filled, restart playback */
2951 if (primarybuf->state == STATE_STARTING) {
2952 waveOutRestart(dsound->hwo);
2953 primarybuf->state = STATE_PLAYING;
2955 else if (primarybuf->state == STATE_STOPPED) {
2956 /* the primarybuf is supposed to play if there's something to play
2957 * even if it is reported as stopped, so don't let this confuse you */
2958 waveOutRestart(dsound->hwo);
2959 primarybuf->state = STATE_STOPPING;
2962 LeaveCriticalSection(&(primarybuf->lock));
2964 LeaveCriticalSection(&(dsound->lock));
2967 /*******************************************************************************
2970 HRESULT WINAPI DirectSoundCreate(REFGUID lpGUID,LPDIRECTSOUND *ppDS,IUnknown *pUnkOuter )
2972 IDirectSoundImpl** ippDS=(IDirectSoundImpl**)ppDS;
2973 PIDSDRIVER drv = NULL;
2976 HRESULT err = DS_OK;
2979 TRACE("(%p,%p,%p)\n",lpGUID,ippDS,pUnkOuter);
2981 TRACE("DirectSoundCreate (%p)\n", ippDS);
2984 return DSERR_INVALIDPARAM;
2987 IDirectSound_AddRef((LPDIRECTSOUND)dsound);
2992 /* Enumerate WINMM audio devices and find the one we want */
2993 wodn = waveOutGetNumDevs();
2994 if (!wodn) return DSERR_NODRIVER;
2996 /* FIXME: How do we find the GUID of an audio device? */
2997 /* Well, just use the first available device for now... */
2999 /* Get output device caps */
3000 waveOutGetDevCapsA(wod, &wcaps, sizeof(wcaps));
3001 /* 0x810 is a "Wine extension" to get the DSound interface */
3002 waveOutMessage(wod, 0x810, (DWORD)&drv, 0);
3004 /* Allocate memory */
3005 *ippDS = (IDirectSoundImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundImpl));
3007 return DSERR_OUTOFMEMORY;
3009 ICOM_VTBL(*ippDS) = &dsvt;
3012 (*ippDS)->driver = drv;
3013 (*ippDS)->fraglen = 0;
3014 (*ippDS)->priolevel = DSSCL_NORMAL;
3015 (*ippDS)->nrofbuffers = 0;
3016 (*ippDS)->buffers = NULL;
3017 (*ippDS)->primary = NULL;
3018 (*ippDS)->listener = NULL;
3020 /* Get driver description */
3022 IDsDriver_GetDriverDesc(drv,&((*ippDS)->drvdesc));
3024 /* if no DirectSound interface available, use WINMM API instead */
3025 (*ippDS)->drvdesc.dwFlags = DSDDESC_DOMMSYSTEMOPEN | DSDDESC_DOMMSYSTEMSETFORMAT;
3026 (*ippDS)->drvdesc.dnDevNode = wod; /* FIXME? */
3029 /* Set default wave format (may need it for waveOutOpen) */
3030 (*ippDS)->wfx.wFormatTag = WAVE_FORMAT_PCM;
3031 (*ippDS)->wfx.nChannels = 2;
3032 (*ippDS)->wfx.nSamplesPerSec = 22050;
3033 (*ippDS)->wfx.nAvgBytesPerSec = 44100;
3034 (*ippDS)->wfx.nBlockAlign = 2;
3035 (*ippDS)->wfx.wBitsPerSample = 8;
3037 /* If the driver requests being opened through MMSYSTEM
3038 * (which is recommended by the DDK), it is supposed to happen
3039 * before the DirectSound interface is opened */
3040 if ((*ippDS)->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN) {
3041 /* FIXME: is this right? */
3042 err = mmErr(waveOutOpen(&((*ippDS)->hwo), (*ippDS)->drvdesc.dnDevNode, &((*ippDS)->wfx),
3043 0, 0, CALLBACK_NULL | WAVE_DIRECTSOUND));
3046 if (drv && (err == DS_OK))
3047 err = IDsDriver_Open(drv);
3049 /* FIXME: do we want to handle a temporarily busy device? */
3051 HeapFree(GetProcessHeap(),0,*ippDS);
3056 /* the driver is now open, so it's now allowed to call GetCaps */
3058 IDsDriver_GetCaps(drv,&((*ippDS)->drvcaps));
3062 /* FIXME: look at wcaps */
3063 (*ippDS)->drvcaps.dwFlags =
3064 DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYSTEREO;
3066 (*ippDS)->drvcaps.dwFlags |= DSCAPS_EMULDRIVER;
3068 /* Allocate memory for HEL buffer headers */
3069 for (c=0; c<DS_HEL_FRAGS; c++) {
3070 (*ippDS)->pwave[c] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(WAVEHDR));
3071 if (!(*ippDS)->pwave[c]) {
3072 /* Argh, out of memory */
3074 HeapFree(GetProcessHeap(),0,(*ippDS)->pwave[c]);
3075 waveOutClose((*ippDS)->hwo);
3076 HeapFree(GetProcessHeap(),0,*ippDS);
3078 return DSERR_OUTOFMEMORY;
3084 InitializeCriticalSection(&((*ippDS)->lock));
3088 if (primarybuf == NULL) {
3092 dsbd.dwSize = sizeof(DSBUFFERDESC);
3093 dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_GETCURRENTPOSITION2;
3094 dsbd.dwBufferBytes = 0;
3095 dsbd.lpwfxFormat = &(dsound->wfx);
3096 hr = IDirectSound_CreateSoundBuffer(*ppDS, &dsbd, (LPDIRECTSOUNDBUFFER*)&primarybuf, NULL);
3100 /* dsound->primary is NULL - don't need to Release */
3101 dsound->primary = primarybuf;
3102 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)primarybuf);
3104 timeBeginPeriod(DS_TIME_RES);
3105 dsound->timerID = timeSetEvent(DS_TIME_DEL, DS_TIME_RES, DSOUND_timer,
3106 (DWORD)dsound, TIME_PERIODIC | TIME_CALLBACK_FUNCTION);
3111 /***************************************************************************
3112 * DirectSoundCaptureCreate [DSOUND.6]
3114 * Create and initialize a DirectSoundCapture interface
3118 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
3121 HRESULT WINAPI DirectSoundCaptureCreate(
3123 LPDIRECTSOUNDCAPTURE* lplpDSC,
3124 LPUNKNOWN pUnkOuter )
3126 TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), lplpDSC, pUnkOuter);
3129 return DSERR_NOAGGREGATION;
3132 /* Default device? */
3134 return DSOUND_CreateDirectSoundCapture( (LPVOID*)lplpDSC );
3137 FIXME( "Unknown GUID %s\n", debugstr_guid(lpcGUID) );
3140 return DSERR_OUTOFMEMORY;
3143 /***************************************************************************
3144 * DirectSoundCaptureEnumerateA [DSOUND.7]
3146 * Enumerate all DirectSound drivers installed in the system
3150 * Failure: DSERR_INVALIDPARAM
3152 HRESULT WINAPI DirectSoundCaptureEnumerateA(
3153 LPDSENUMCALLBACKA lpDSEnumCallback,
3156 TRACE("(%p,%p)\n", lpDSEnumCallback, lpContext );
3158 if ( lpDSEnumCallback )
3159 lpDSEnumCallback(NULL,"WINE Primary Sound Capture Driver",
3160 "SoundCap",lpContext);
3166 /***************************************************************************
3167 * DirectSoundCaptureEnumerateW [DSOUND.8]
3169 * Enumerate all DirectSound drivers installed in the system
3173 * Failure: DSERR_INVALIDPARAM
3175 HRESULT WINAPI DirectSoundCaptureEnumerateW(
3176 LPDSENUMCALLBACKW lpDSEnumCallback,
3179 FIXME("(%p,%p):stub\n", lpDSEnumCallback, lpContext );
3184 DSOUND_CreateDirectSoundCapture( LPVOID* ppobj )
3186 *ppobj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( IDirectSoundCaptureImpl ) );
3188 if ( *ppobj == NULL ) {
3189 return DSERR_OUTOFMEMORY;
3193 ICOM_THIS(IDirectSoundCaptureImpl,*ppobj);
3196 ICOM_VTBL(This) = &dscvt;
3198 InitializeCriticalSection( &This->lock );
3204 static HRESULT WINAPI
3205 IDirectSoundCaptureImpl_QueryInterface(
3206 LPDIRECTSOUNDCAPTURE iface,
3210 ICOM_THIS(IDirectSoundCaptureImpl,iface);
3212 FIXME( "(%p)->(%s,%p): stub\n", This, debugstr_guid(riid), ppobj );
3218 IDirectSoundCaptureImpl_AddRef( LPDIRECTSOUNDCAPTURE iface )
3221 ICOM_THIS(IDirectSoundCaptureImpl,iface);
3223 EnterCriticalSection( &This->lock );
3225 TRACE( "(%p) was 0x%08lx\n", This, This->ref );
3226 uRef = ++(This->ref);
3228 LeaveCriticalSection( &This->lock );
3234 IDirectSoundCaptureImpl_Release( LPDIRECTSOUNDCAPTURE iface )
3237 ICOM_THIS(IDirectSoundCaptureImpl,iface);
3239 EnterCriticalSection( &This->lock );
3241 TRACE( "(%p) was 0x%08lx\n", This, This->ref );
3242 uRef = --(This->ref);
3244 LeaveCriticalSection( &This->lock );
3247 DeleteCriticalSection( &This->lock );
3248 HeapFree( GetProcessHeap(), 0, This );
3254 static HRESULT WINAPI
3255 IDirectSoundCaptureImpl_CreateCaptureBuffer(
3256 LPDIRECTSOUNDCAPTURE iface,
3257 LPCDSCBUFFERDESC lpcDSCBufferDesc,
3258 LPDIRECTSOUNDCAPTUREBUFFER* lplpDSCaptureBuffer,
3262 ICOM_THIS(IDirectSoundCaptureImpl,iface);
3264 TRACE( "(%p)->(%p,%p,%p)\n", This, lpcDSCBufferDesc, lplpDSCaptureBuffer, pUnk );
3267 return DSERR_INVALIDPARAM;
3270 hr = DSOUND_CreateDirectSoundCaptureBuffer( lpcDSCBufferDesc, (LPVOID*)lplpDSCaptureBuffer );
3275 static HRESULT WINAPI
3276 IDirectSoundCaptureImpl_GetCaps(
3277 LPDIRECTSOUNDCAPTURE iface,
3278 LPDSCCAPS lpDSCCaps )
3280 ICOM_THIS(IDirectSoundCaptureImpl,iface);
3282 FIXME( "(%p)->(%p): stub\n", This, lpDSCCaps );
3287 static HRESULT WINAPI
3288 IDirectSoundCaptureImpl_Initialize(
3289 LPDIRECTSOUNDCAPTURE iface,
3292 ICOM_THIS(IDirectSoundCaptureImpl,iface);
3294 FIXME( "(%p)->(%p): stub\n", This, lpcGUID );
3300 static ICOM_VTABLE(IDirectSoundCapture) dscvt =
3302 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
3303 /* IUnknown methods */
3304 IDirectSoundCaptureImpl_QueryInterface,
3305 IDirectSoundCaptureImpl_AddRef,
3306 IDirectSoundCaptureImpl_Release,
3308 /* IDirectSoundCapture methods */
3309 IDirectSoundCaptureImpl_CreateCaptureBuffer,
3310 IDirectSoundCaptureImpl_GetCaps,
3311 IDirectSoundCaptureImpl_Initialize
3315 DSOUND_CreateDirectSoundCaptureBuffer( LPCDSCBUFFERDESC lpcDSCBufferDesc, LPVOID* ppobj )
3318 FIXME( "(%p,%p): ignoring lpcDSCBufferDesc\n", lpcDSCBufferDesc, ppobj );
3320 *ppobj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( IDirectSoundCaptureBufferImpl ) );
3322 if ( *ppobj == NULL ) {
3323 return DSERR_OUTOFMEMORY;
3327 ICOM_THIS(IDirectSoundCaptureBufferImpl,*ppobj);
3330 ICOM_VTBL(This) = &dscbvt;
3332 InitializeCriticalSection( &This->lock );
3339 static HRESULT WINAPI
3340 IDirectSoundCaptureBufferImpl_QueryInterface(
3341 LPDIRECTSOUNDCAPTUREBUFFER iface,
3345 ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3347 FIXME( "(%p)->(%s,%p): stub\n", This, debugstr_guid(riid), ppobj );
3353 IDirectSoundCaptureBufferImpl_AddRef( LPDIRECTSOUNDCAPTUREBUFFER iface )
3356 ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3358 EnterCriticalSection( &This->lock );
3360 TRACE( "(%p) was 0x%08lx\n", This, This->ref );
3361 uRef = ++(This->ref);
3363 LeaveCriticalSection( &This->lock );
3369 IDirectSoundCaptureBufferImpl_Release( LPDIRECTSOUNDCAPTUREBUFFER iface )
3372 ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3374 EnterCriticalSection( &This->lock );
3376 TRACE( "(%p) was 0x%08lx\n", This, This->ref );
3377 uRef = --(This->ref);
3379 LeaveCriticalSection( &This->lock );
3382 DeleteCriticalSection( &This->lock );
3383 HeapFree( GetProcessHeap(), 0, This );
3389 static HRESULT WINAPI
3390 IDirectSoundCaptureBufferImpl_GetCaps(
3391 LPDIRECTSOUNDCAPTUREBUFFER iface,
3392 LPDSCBCAPS lpDSCBCaps )
3394 ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3396 FIXME( "(%p)->(%p): stub\n", This, lpDSCBCaps );
3401 static HRESULT WINAPI
3402 IDirectSoundCaptureBufferImpl_GetCurrentPosition(
3403 LPDIRECTSOUNDCAPTUREBUFFER iface,
3404 LPDWORD lpdwCapturePosition,
3405 LPDWORD lpdwReadPosition )
3407 ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3409 FIXME( "(%p)->(%p,%p): stub\n", This, lpdwCapturePosition, lpdwReadPosition );
3414 static HRESULT WINAPI
3415 IDirectSoundCaptureBufferImpl_GetFormat(
3416 LPDIRECTSOUNDCAPTUREBUFFER iface,
3417 LPWAVEFORMATEX lpwfxFormat,
3418 DWORD dwSizeAllocated,
3419 LPDWORD lpdwSizeWritten )
3421 ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3423 FIXME( "(%p)->(%p,0x%08lx,%p): stub\n", This, lpwfxFormat, dwSizeAllocated, lpdwSizeWritten );
3428 static HRESULT WINAPI
3429 IDirectSoundCaptureBufferImpl_GetStatus(
3430 LPDIRECTSOUNDCAPTUREBUFFER iface,
3431 LPDWORD lpdwStatus )
3433 ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3435 FIXME( "(%p)->(%p): stub\n", This, lpdwStatus );
3440 static HRESULT WINAPI
3441 IDirectSoundCaptureBufferImpl_Initialize(
3442 LPDIRECTSOUNDCAPTUREBUFFER iface,
3443 LPDIRECTSOUNDCAPTURE lpDSC,
3444 LPCDSCBUFFERDESC lpcDSCBDesc )
3446 ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3448 FIXME( "(%p)->(%p,%p): stub\n", This, lpDSC, lpcDSCBDesc );
3453 static HRESULT WINAPI
3454 IDirectSoundCaptureBufferImpl_Lock(
3455 LPDIRECTSOUNDCAPTUREBUFFER iface,
3458 LPVOID* lplpvAudioPtr1,
3459 LPDWORD lpdwAudioBytes1,
3460 LPVOID* lplpvAudioPtr2,
3461 LPDWORD lpdwAudioBytes2,
3464 ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3466 FIXME( "(%p)->(%08lu,%08lu,%p,%p,%p,%p,0x%08lx): stub\n", This, dwReadCusor, dwReadBytes, lplpvAudioPtr1, lpdwAudioBytes1, lplpvAudioPtr2, lpdwAudioBytes2, dwFlags );
3471 static HRESULT WINAPI
3472 IDirectSoundCaptureBufferImpl_Start(
3473 LPDIRECTSOUNDCAPTUREBUFFER iface,
3476 ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3478 FIXME( "(%p)->(0x%08lx): stub\n", This, dwFlags );
3483 static HRESULT WINAPI
3484 IDirectSoundCaptureBufferImpl_Stop( LPDIRECTSOUNDCAPTUREBUFFER iface )
3486 ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3488 FIXME( "(%p): stub\n", This );
3493 static HRESULT WINAPI
3494 IDirectSoundCaptureBufferImpl_Unlock(
3495 LPDIRECTSOUNDCAPTUREBUFFER iface,
3496 LPVOID lpvAudioPtr1,
3497 DWORD dwAudioBytes1,
3498 LPVOID lpvAudioPtr2,
3499 DWORD dwAudioBytes2 )
3501 ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3503 FIXME( "(%p)->(%p,%08lu,%p,%08lu): stub\n", This, lpvAudioPtr1, dwAudioBytes1, lpvAudioPtr2, dwAudioBytes2 );
3509 static ICOM_VTABLE(IDirectSoundCaptureBuffer) dscbvt =
3511 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
3512 /* IUnknown methods */
3513 IDirectSoundCaptureBufferImpl_QueryInterface,
3514 IDirectSoundCaptureBufferImpl_AddRef,
3515 IDirectSoundCaptureBufferImpl_Release,
3517 /* IDirectSoundCaptureBuffer methods */
3518 IDirectSoundCaptureBufferImpl_GetCaps,
3519 IDirectSoundCaptureBufferImpl_GetCurrentPosition,
3520 IDirectSoundCaptureBufferImpl_GetFormat,
3521 IDirectSoundCaptureBufferImpl_GetStatus,
3522 IDirectSoundCaptureBufferImpl_Initialize,
3523 IDirectSoundCaptureBufferImpl_Lock,
3524 IDirectSoundCaptureBufferImpl_Start,
3525 IDirectSoundCaptureBufferImpl_Stop,
3526 IDirectSoundCaptureBufferImpl_Unlock
3529 /*******************************************************************************
3530 * DirectSound ClassFactory
3534 /* IUnknown fields */
3535 ICOM_VFIELD(IClassFactory);
3537 } IClassFactoryImpl;
3539 static HRESULT WINAPI
3540 DSCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
3541 ICOM_THIS(IClassFactoryImpl,iface);
3543 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
3544 return E_NOINTERFACE;
3548 DSCF_AddRef(LPCLASSFACTORY iface) {
3549 ICOM_THIS(IClassFactoryImpl,iface);
3550 return ++(This->ref);
3553 static ULONG WINAPI DSCF_Release(LPCLASSFACTORY iface) {
3554 ICOM_THIS(IClassFactoryImpl,iface);
3555 /* static class, won't be freed */
3556 return --(This->ref);
3559 static HRESULT WINAPI DSCF_CreateInstance(
3560 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
3562 ICOM_THIS(IClassFactoryImpl,iface);
3564 TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
3565 if ( IsEqualGUID( &IID_IDirectSound, riid ) ) {
3566 /* FIXME: reuse already created dsound if present? */
3567 return DirectSoundCreate(riid,(LPDIRECTSOUND*)ppobj,pOuter);
3569 return E_NOINTERFACE;
3572 static HRESULT WINAPI DSCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
3573 ICOM_THIS(IClassFactoryImpl,iface);
3574 FIXME("(%p)->(%d),stub!\n",This,dolock);
3578 static ICOM_VTABLE(IClassFactory) DSCF_Vtbl = {
3579 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
3580 DSCF_QueryInterface,
3583 DSCF_CreateInstance,
3586 static IClassFactoryImpl DSOUND_CF = {&DSCF_Vtbl, 1 };
3588 /*******************************************************************************
3589 * DllGetClassObject [DSOUND.4]
3590 * Retrieves class object from a DLL object
3593 * Docs say returns STDAPI
3596 * rclsid [I] CLSID for the class object
3597 * riid [I] Reference to identifier of interface for class object
3598 * ppv [O] Address of variable to receive interface pointer for riid
3602 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
3605 DWORD WINAPI DSOUND_DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID *ppv)
3607 TRACE("(%p,%p,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
3608 if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) {
3609 *ppv = (LPVOID)&DSOUND_CF;
3610 IClassFactory_AddRef((IClassFactory*)*ppv);
3614 FIXME("(%p,%p,%p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
3615 return CLASS_E_CLASSNOTAVAILABLE;
3619 /*******************************************************************************
3620 * DllCanUnloadNow [DSOUND.3] Determines whether the DLL is in use.
3626 DWORD WINAPI DSOUND_DllCanUnloadNow(void)
3628 FIXME("(void): stub\n");