3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998 Rob Riggs
5 * Copyright 2000-2001 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 */
43 #include "wine/windef16.h"
44 #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_MARGIN 4 /* HEL only: number of waveOut fragments ahead to mix in new buffers */
59 #define DS_SND_QUEUE 28 /* max number of fragments to prebuffer */
61 /* Linux does not support better timing than 10ms */
62 #define DS_TIME_RES 10 /* Resolution of multimedia timer */
63 #define DS_TIME_DEL 10 /* Delay of multimedia timer callback, and duration of HEL fragment */
65 /*****************************************************************************
66 * Predeclare the interface implementation structures
68 typedef struct IDirectSoundImpl IDirectSoundImpl
;
69 typedef struct IDirectSoundBufferImpl IDirectSoundBufferImpl
;
70 typedef struct IDirectSoundNotifyImpl IDirectSoundNotifyImpl
;
71 typedef struct IDirectSound3DListenerImpl IDirectSound3DListenerImpl
;
72 typedef struct IDirectSound3DBufferImpl IDirectSound3DBufferImpl
;
73 typedef struct IDirectSoundCaptureImpl IDirectSoundCaptureImpl
;
74 typedef struct IDirectSoundCaptureBufferImpl IDirectSoundCaptureBufferImpl
;
75 typedef struct IKsPropertySetImpl IKsPropertySetImpl
;
77 /*****************************************************************************
78 * IDirectSound implementation structure
80 struct IDirectSoundImpl
83 ICOM_VFIELD(IDirectSound
);
85 /* IDirectSoundImpl fields */
90 LPWAVEHDR pwave
[DS_HEL_FRAGS
];
91 UINT timerID
, pwplay
, pwwrite
, pwqueue
;
95 IDirectSoundBufferImpl
** buffers
;
96 IDirectSoundBufferImpl
* primary
;
97 IDirectSound3DListenerImpl
* listener
;
98 WAVEFORMATEX wfx
; /* current main waveformat */
99 CRITICAL_SECTION lock
;
102 /*****************************************************************************
103 * IDirectSoundBuffer implementation structure
105 struct IDirectSoundBufferImpl
107 /* FIXME: document */
108 /* IUnknown fields */
109 ICOM_VFIELD(IDirectSoundBuffer
);
111 /* IDirectSoundBufferImpl fields */
112 PIDSDRIVERBUFFER hwbuf
;
115 IDirectSound3DBufferImpl
* ds3db
;
116 DWORD playflags
,state
,leadin
;
117 DWORD playpos
,startpos
,writelead
,buflen
;
118 DWORD nAvgBytesPerSec
;
121 IDirectSoundBufferImpl
* parent
; /* for duplicates */
122 IDirectSoundImpl
* dsound
;
124 LPDSBPOSITIONNOTIFY notifies
;
126 CRITICAL_SECTION lock
;
127 /* used for frequency conversion (PerfectPitch) */
128 ULONG freqAdjust
, freqAcc
;
129 /* used for intelligent (well, sort of) prebuffering */
130 DWORD probably_valid_to
;
131 DWORD primary_mixpos
, buf_mixpos
;
134 #define STATE_STOPPED 0
135 #define STATE_STARTING 1
136 #define STATE_PLAYING 2
137 #define STATE_STOPPING 3
139 /*****************************************************************************
140 * IDirectSoundNotify implementation structure
142 struct IDirectSoundNotifyImpl
144 /* IUnknown fields */
145 ICOM_VFIELD(IDirectSoundNotify
);
147 /* IDirectSoundNotifyImpl fields */
148 IDirectSoundBufferImpl
* dsb
;
151 /*****************************************************************************
152 * IDirectSound3DListener implementation structure
154 struct IDirectSound3DListenerImpl
156 /* IUnknown fields */
157 ICOM_VFIELD(IDirectSound3DListener
);
159 /* IDirectSound3DListenerImpl fields */
160 IDirectSoundBufferImpl
* dsb
;
162 CRITICAL_SECTION lock
;
165 struct IKsPropertySetImpl
167 /* IUnknown fields */
168 ICOM_VFIELD(IKsPropertySet
);
170 /* IKsPropertySetImpl fields */
171 IDirectSound3DBufferImpl
*ds3db
; /* backptr, no ref */
174 /*****************************************************************************
175 * IDirectSound3DBuffer implementation structure
177 struct IDirectSound3DBufferImpl
179 /* IUnknown fields */
180 ICOM_VFIELD(IDirectSound3DBuffer
);
182 /* IDirectSound3DBufferImpl fields */
183 IDirectSoundBufferImpl
* dsb
;
187 CRITICAL_SECTION lock
;
188 IKsPropertySetImpl
* iks
;
192 /*****************************************************************************
193 * IDirectSoundCapture implementation structure
195 struct IDirectSoundCaptureImpl
197 /* IUnknown fields */
198 ICOM_VFIELD(IDirectSoundCapture
);
201 /* IDirectSoundCaptureImpl fields */
202 CRITICAL_SECTION lock
;
205 /*****************************************************************************
206 * IDirectSoundCapture implementation structure
208 struct IDirectSoundCaptureBufferImpl
210 /* IUnknown fields */
211 ICOM_VFIELD(IDirectSoundCaptureBuffer
);
214 /* IDirectSoundCaptureBufferImpl fields */
215 CRITICAL_SECTION lock
;
219 /* #define USE_DSOUND3D 1 */
221 #define DSOUND_FREQSHIFT (14)
223 static IDirectSoundImpl
* dsound
= NULL
;
225 static IDirectSoundBufferImpl
* primarybuf
= NULL
;
227 static void DSOUND_CheckEvent(IDirectSoundBufferImpl
*dsb
, int len
);
229 static HRESULT
DSOUND_CreateDirectSoundCapture( LPVOID
* ppobj
);
230 static HRESULT
DSOUND_CreateDirectSoundCaptureBuffer( LPCDSCBUFFERDESC lpcDSCBufferDesc
, LPVOID
* ppobj
);
232 static ICOM_VTABLE(IDirectSoundCapture
) dscvt
;
233 static ICOM_VTABLE(IDirectSoundCaptureBuffer
) dscbvt
;
235 static HRESULT
mmErr(UINT err
)
238 case MMSYSERR_NOERROR
:
240 case MMSYSERR_ALLOCATED
:
241 return DSERR_ALLOCATED
;
242 case MMSYSERR_INVALHANDLE
:
243 return DSERR_GENERIC
; /* FIXME */
244 case MMSYSERR_NODRIVER
:
245 return DSERR_NODRIVER
;
247 return DSERR_OUTOFMEMORY
;
248 case MMSYSERR_INVALPARAM
:
249 return DSERR_INVALIDPARAM
;
251 FIXME("Unknown MMSYS error %d\n",err
);
252 return DSERR_GENERIC
;
256 /***************************************************************************
257 * DirectSoundEnumerateA [DSOUND.2]
259 * Enumerate all DirectSound drivers installed in the system
263 * Failure: DSERR_INVALIDPARAM
265 HRESULT WINAPI
DirectSoundEnumerateA(
266 LPDSENUMCALLBACKA lpDSEnumCallback
,
269 TRACE("lpDSEnumCallback = %p, lpContext = %p\n",
270 lpDSEnumCallback
, lpContext
);
273 if (lpDSEnumCallback
!= NULL
)
274 lpDSEnumCallback(NULL
,"WINE DirectSound using Open Sound System",
281 /***************************************************************************
282 * DirectSoundEnumerateW [DSOUND.3]
284 * Enumerate all DirectSound drivers installed in the system
288 * Failure: DSERR_INVALIDPARAM
290 HRESULT WINAPI
DirectSoundEnumerateW(
291 LPDSENUMCALLBACKW lpDSEnumCallback
,
294 FIXME("lpDSEnumCallback = %p, lpContext = %p: stub\n",
295 lpDSEnumCallback
, lpContext
);
301 static void _dump_DSBCAPS(DWORD xmask
) {
306 #define FE(x) { x, #x },
307 FE(DSBCAPS_PRIMARYBUFFER
)
309 FE(DSBCAPS_LOCHARDWARE
)
310 FE(DSBCAPS_LOCSOFTWARE
)
312 FE(DSBCAPS_CTRLFREQUENCY
)
314 FE(DSBCAPS_CTRLVOLUME
)
315 FE(DSBCAPS_CTRLPOSITIONNOTIFY
)
316 FE(DSBCAPS_CTRLDEFAULT
)
318 FE(DSBCAPS_STICKYFOCUS
)
319 FE(DSBCAPS_GLOBALFOCUS
)
320 FE(DSBCAPS_GETCURRENTPOSITION2
)
321 FE(DSBCAPS_MUTE3DATMAXDISTANCE
)
326 for (i
=0;i
<sizeof(flags
)/sizeof(flags
[0]);i
++)
327 if ((flags
[i
].mask
& xmask
) == flags
[i
].mask
)
328 DPRINTF("%s ",flags
[i
].name
);
331 /*******************************************************************************
335 /* IUnknown methods */
337 static HRESULT WINAPI
IKsPropertySetImpl_QueryInterface(
338 LPKSPROPERTYSET iface
, REFIID riid
, LPVOID
*ppobj
340 ICOM_THIS(IKsPropertySetImpl
,iface
);
342 FIXME("(%p,%s,%p), stub!\n",This
,debugstr_guid(riid
),ppobj
);
348 static ULONG WINAPI
IKsPropertySetImpl_AddRef(LPKSPROPERTYSET iface
) {
349 ICOM_THIS(IKsPropertySetImpl
,iface
);
357 static ULONG WINAPI
IKsPropertySetImpl_Release(LPKSPROPERTYSET iface
) {
358 ICOM_THIS(IKsPropertySetImpl
,iface
);
366 static HRESULT WINAPI
IKsPropertySetImpl_Get(LPKSPROPERTYSET iface
,
367 REFGUID guidPropSet
, ULONG dwPropID
,
368 LPVOID pInstanceData
, ULONG cbInstanceData
,
369 LPVOID pPropData
, ULONG cbPropData
,
372 ICOM_THIS(IKsPropertySetImpl
,iface
);
374 FIXME("(%p,%s,%ld,%p,%ld,%p,%ld,%p), stub!\n",This
,debugstr_guid(guidPropSet
),dwPropID
,pInstanceData
,cbInstanceData
,pPropData
,cbPropData
,pcbReturned
);
375 return E_PROP_ID_UNSUPPORTED
;
380 static HRESULT WINAPI
IKsPropertySetImpl_Set(LPKSPROPERTYSET iface
,
381 REFGUID guidPropSet
, ULONG dwPropID
,
382 LPVOID pInstanceData
, ULONG cbInstanceData
,
383 LPVOID pPropData
, ULONG cbPropData
385 ICOM_THIS(IKsPropertySetImpl
,iface
);
387 FIXME("(%p,%s,%ld,%p,%ld,%p,%ld), stub!\n",This
,debugstr_guid(guidPropSet
),dwPropID
,pInstanceData
,cbInstanceData
,pPropData
,cbPropData
);
388 return E_PROP_ID_UNSUPPORTED
;
393 static HRESULT WINAPI
IKsPropertySetImpl_QuerySupport(LPKSPROPERTYSET iface
,
394 REFGUID guidPropSet
, ULONG dwPropID
, PULONG pTypeSupport
396 ICOM_THIS(IKsPropertySetImpl
,iface
);
398 FIXME("(%p,%s,%ld,%p), stub!\n",This
,debugstr_guid(guidPropSet
),dwPropID
,pTypeSupport
);
399 return E_PROP_ID_UNSUPPORTED
;
404 static ICOM_VTABLE(IKsPropertySet
) iksvt
= {
405 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
406 IKsPropertySetImpl_QueryInterface
,
407 IKsPropertySetImpl_AddRef
,
408 IKsPropertySetImpl_Release
,
409 IKsPropertySetImpl_Get
,
410 IKsPropertySetImpl_Set
,
411 IKsPropertySetImpl_QuerySupport
415 /*******************************************************************************
416 * IDirectSound3DBuffer
419 /* IUnknown methods */
421 static HRESULT WINAPI
IDirectSound3DBufferImpl_QueryInterface(
422 LPDIRECTSOUND3DBUFFER iface
, REFIID riid
, LPVOID
*ppobj
)
424 ICOM_THIS(IDirectSound3DBufferImpl
,iface
);
426 if ( IsEqualGUID( &IID_IKsPropertySet
, riid
) ) {
427 IDirectSound3DBuffer_AddRef(iface
);
432 FIXME("(%p,%s,%p), no such interface.\n",This
,debugstr_guid(riid
),ppobj
);
438 static ULONG WINAPI
IDirectSound3DBufferImpl_AddRef(LPDIRECTSOUND3DBUFFER iface
)
440 ICOM_THIS(IDirectSound3DBufferImpl
,iface
);
447 static ULONG WINAPI
IDirectSound3DBufferImpl_Release(LPDIRECTSOUND3DBUFFER iface
)
449 ICOM_THIS(IDirectSound3DBufferImpl
,iface
);
451 TRACE("(%p) ref was %ld\n", This
, This
->ref
);
457 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)This
->dsb
);
459 DeleteCriticalSection(&This
->lock
);
461 HeapFree(GetProcessHeap(),0,This
->buffer
);
462 HeapFree(GetProcessHeap(),0,This
);
468 /* IDirectSound3DBuffer methods */
470 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetAllParameters(
471 LPDIRECTSOUND3DBUFFER iface
,
472 LPDS3DBUFFER lpDs3dBuffer
)
480 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetConeAngles(
481 LPDIRECTSOUND3DBUFFER iface
,
482 LPDWORD lpdwInsideConeAngle
,
483 LPDWORD lpdwOutsideConeAngle
)
491 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetConeOrientation(
492 LPDIRECTSOUND3DBUFFER iface
,
493 LPD3DVECTOR lpvConeOrientation
)
501 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetConeOutsideVolume(
502 LPDIRECTSOUND3DBUFFER iface
,
503 LPLONG lplConeOutsideVolume
)
511 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetMaxDistance(
512 LPDIRECTSOUND3DBUFFER iface
,
513 LPD3DVALUE lpfMaxDistance
)
521 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetMinDistance(
522 LPDIRECTSOUND3DBUFFER iface
,
523 LPD3DVALUE lpfMinDistance
)
531 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetMode(
532 LPDIRECTSOUND3DBUFFER iface
,
541 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetPosition(
542 LPDIRECTSOUND3DBUFFER iface
,
543 LPD3DVECTOR lpvPosition
)
551 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetVelocity(
552 LPDIRECTSOUND3DBUFFER iface
,
553 LPD3DVECTOR lpvVelocity
)
561 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetAllParameters(
562 LPDIRECTSOUND3DBUFFER iface
,
563 LPCDS3DBUFFER lpcDs3dBuffer
,
572 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetConeAngles(
573 LPDIRECTSOUND3DBUFFER iface
,
574 DWORD dwInsideConeAngle
,
575 DWORD dwOutsideConeAngle
,
584 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetConeOrientation(
585 LPDIRECTSOUND3DBUFFER iface
,
586 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
595 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetConeOutsideVolume(
596 LPDIRECTSOUND3DBUFFER iface
,
597 LONG lConeOutsideVolume
,
606 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetMaxDistance(
607 LPDIRECTSOUND3DBUFFER iface
,
608 D3DVALUE fMaxDistance
,
617 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetMinDistance(
618 LPDIRECTSOUND3DBUFFER iface
,
619 D3DVALUE fMinDistance
,
628 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetMode(
629 LPDIRECTSOUND3DBUFFER iface
,
633 ICOM_THIS(IDirectSound3DBufferImpl
,iface
);
634 TRACE("mode = %lx\n", dwMode
);
635 This
->ds3db
.dwMode
= dwMode
;
641 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetPosition(
642 LPDIRECTSOUND3DBUFFER iface
,
643 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
652 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetVelocity(
653 LPDIRECTSOUND3DBUFFER iface
,
654 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
663 static ICOM_VTABLE(IDirectSound3DBuffer
) ds3dbvt
=
665 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
666 /* IUnknown methods */
667 IDirectSound3DBufferImpl_QueryInterface
,
668 IDirectSound3DBufferImpl_AddRef
,
669 IDirectSound3DBufferImpl_Release
,
670 /* IDirectSound3DBuffer methods */
671 IDirectSound3DBufferImpl_GetAllParameters
,
672 IDirectSound3DBufferImpl_GetConeAngles
,
673 IDirectSound3DBufferImpl_GetConeOrientation
,
674 IDirectSound3DBufferImpl_GetConeOutsideVolume
,
675 IDirectSound3DBufferImpl_GetMaxDistance
,
676 IDirectSound3DBufferImpl_GetMinDistance
,
677 IDirectSound3DBufferImpl_GetMode
,
678 IDirectSound3DBufferImpl_GetPosition
,
679 IDirectSound3DBufferImpl_GetVelocity
,
680 IDirectSound3DBufferImpl_SetAllParameters
,
681 IDirectSound3DBufferImpl_SetConeAngles
,
682 IDirectSound3DBufferImpl_SetConeOrientation
,
683 IDirectSound3DBufferImpl_SetConeOutsideVolume
,
684 IDirectSound3DBufferImpl_SetMaxDistance
,
685 IDirectSound3DBufferImpl_SetMinDistance
,
686 IDirectSound3DBufferImpl_SetMode
,
687 IDirectSound3DBufferImpl_SetPosition
,
688 IDirectSound3DBufferImpl_SetVelocity
,
693 static int DSOUND_Create3DBuffer(IDirectSoundBufferImpl
* dsb
)
695 DWORD i
, temp
, iSize
, oSize
, offset
;
696 LPBYTE bIbuf
, bObuf
, bTbuf
= NULL
;
697 LPWORD wIbuf
, wObuf
, wTbuf
= NULL
;
699 /* Inside DirectX says it's stupid but allowed */
700 if (dsb
->wfx
.nChannels
== 2) {
701 /* Convert to mono */
702 if (dsb
->wfx
.wBitsPerSample
== 16) {
703 iSize
= dsb
->buflen
/ 4;
704 wTbuf
= malloc(dsb
->buflen
/ 2);
706 return DSERR_OUTOFMEMORY
;
707 for (i
= 0; i
< iSize
; i
++)
708 wTbuf
[i
] = (dsb
->buffer
[i
* 2] + dsb
->buffer
[(i
* 2) + 1]) / 2;
711 iSize
= dsb
->buflen
/ 2;
712 bTbuf
= malloc(dsb
->buflen
/ 2);
714 return DSERR_OUTOFMEMORY
;
715 for (i
= 0; i
< iSize
; i
++)
716 bTbuf
[i
] = (dsb
->buffer
[i
* 2] + dsb
->buffer
[(i
* 2) + 1]) / 2;
720 if (dsb
->wfx
.wBitsPerSample
== 16) {
721 iSize
= dsb
->buflen
/ 2;
722 wIbuf
= (LPWORD
) dsb
->buffer
;
724 bIbuf
= (LPBYTE
) dsb
->buffer
;
729 if (primarybuf
->wfx
.wBitsPerSample
== 16) {
730 wObuf
= (LPWORD
) dsb
->ds3db
->buffer
;
731 oSize
= dsb
->ds3db
->buflen
/ 2;
733 bObuf
= (LPBYTE
) dsb
->ds3db
->buffer
;
734 oSize
= dsb
->ds3db
->buflen
;
737 offset
= primarybuf
->wfx
.nSamplesPerSec
/ 100; /* 10ms */
738 if (primarybuf
->wfx
.wBitsPerSample
== 16 && dsb
->wfx
.wBitsPerSample
== 16)
739 for (i
= 0; i
< iSize
; i
++) {
742 temp
+= wIbuf
[i
- offset
] >> 9;
744 temp
+= wIbuf
[i
+ iSize
- offset
] >> 9;
746 wObuf
[(i
* 2) + 1] = temp
;
748 else if (primarybuf
->wfx
.wBitsPerSample
== 8 && dsb
->wfx
.wBitsPerSample
== 8)
749 for (i
= 0; i
< iSize
; i
++) {
752 temp
+= bIbuf
[i
- offset
] >> 5;
754 temp
+= bIbuf
[i
+ iSize
- offset
] >> 5;
756 bObuf
[(i
* 2) + 1] = temp
;
767 /*******************************************************************************
768 * IDirectSound3DListener
771 /* IUnknown methods */
772 static HRESULT WINAPI
IDirectSound3DListenerImpl_QueryInterface(
773 LPDIRECTSOUND3DLISTENER iface
, REFIID riid
, LPVOID
*ppobj
)
775 ICOM_THIS(IDirectSound3DListenerImpl
,iface
);
777 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
781 static ULONG WINAPI
IDirectSound3DListenerImpl_AddRef(LPDIRECTSOUND3DLISTENER iface
)
783 ICOM_THIS(IDirectSound3DListenerImpl
,iface
);
788 static ULONG WINAPI
IDirectSound3DListenerImpl_Release(LPDIRECTSOUND3DLISTENER iface
)
791 ICOM_THIS(IDirectSound3DListenerImpl
,iface
);
793 TRACE("(%p) ref was %ld\n", This
, This
->ref
);
795 ulReturn
= --This
->ref
;
797 /* Free all resources */
798 if( ulReturn
== 0 ) {
800 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)This
->dsb
);
801 DeleteCriticalSection(&This
->lock
);
802 HeapFree(GetProcessHeap(),0,This
);
808 /* IDirectSound3DListener methods */
809 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetAllParameter(
810 LPDIRECTSOUND3DLISTENER iface
,
811 LPDS3DLISTENER lpDS3DL
)
817 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetDistanceFactor(
818 LPDIRECTSOUND3DLISTENER iface
,
819 LPD3DVALUE lpfDistanceFactor
)
825 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetDopplerFactor(
826 LPDIRECTSOUND3DLISTENER iface
,
827 LPD3DVALUE lpfDopplerFactor
)
833 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetOrientation(
834 LPDIRECTSOUND3DLISTENER iface
,
835 LPD3DVECTOR lpvOrientFront
,
836 LPD3DVECTOR lpvOrientTop
)
842 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetPosition(
843 LPDIRECTSOUND3DLISTENER iface
,
844 LPD3DVECTOR lpvPosition
)
850 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetRolloffFactor(
851 LPDIRECTSOUND3DLISTENER iface
,
852 LPD3DVALUE lpfRolloffFactor
)
858 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetVelocity(
859 LPDIRECTSOUND3DLISTENER iface
,
860 LPD3DVECTOR lpvVelocity
)
866 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetAllParameters(
867 LPDIRECTSOUND3DLISTENER iface
,
868 LPCDS3DLISTENER lpcDS3DL
,
875 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetDistanceFactor(
876 LPDIRECTSOUND3DLISTENER iface
,
877 D3DVALUE fDistanceFactor
,
884 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetDopplerFactor(
885 LPDIRECTSOUND3DLISTENER iface
,
886 D3DVALUE fDopplerFactor
,
893 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetOrientation(
894 LPDIRECTSOUND3DLISTENER iface
,
895 D3DVALUE xFront
, D3DVALUE yFront
, D3DVALUE zFront
,
896 D3DVALUE xTop
, D3DVALUE yTop
, D3DVALUE zTop
,
903 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetPosition(
904 LPDIRECTSOUND3DLISTENER iface
,
905 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
912 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetRolloffFactor(
913 LPDIRECTSOUND3DLISTENER iface
,
914 D3DVALUE fRolloffFactor
,
921 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetVelocity(
922 LPDIRECTSOUND3DLISTENER iface
,
923 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
930 static HRESULT WINAPI
IDirectSound3DListenerImpl_CommitDeferredSettings(
931 LPDIRECTSOUND3DLISTENER iface
)
938 static ICOM_VTABLE(IDirectSound3DListener
) ds3dlvt
=
940 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
941 /* IUnknown methods */
942 IDirectSound3DListenerImpl_QueryInterface
,
943 IDirectSound3DListenerImpl_AddRef
,
944 IDirectSound3DListenerImpl_Release
,
945 /* IDirectSound3DListener methods */
946 IDirectSound3DListenerImpl_GetAllParameter
,
947 IDirectSound3DListenerImpl_GetDistanceFactor
,
948 IDirectSound3DListenerImpl_GetDopplerFactor
,
949 IDirectSound3DListenerImpl_GetOrientation
,
950 IDirectSound3DListenerImpl_GetPosition
,
951 IDirectSound3DListenerImpl_GetRolloffFactor
,
952 IDirectSound3DListenerImpl_GetVelocity
,
953 IDirectSound3DListenerImpl_SetAllParameters
,
954 IDirectSound3DListenerImpl_SetDistanceFactor
,
955 IDirectSound3DListenerImpl_SetDopplerFactor
,
956 IDirectSound3DListenerImpl_SetOrientation
,
957 IDirectSound3DListenerImpl_SetPosition
,
958 IDirectSound3DListenerImpl_SetRolloffFactor
,
959 IDirectSound3DListenerImpl_SetVelocity
,
960 IDirectSound3DListenerImpl_CommitDeferredSettings
,
963 /*******************************************************************************
966 static HRESULT WINAPI
IDirectSoundNotifyImpl_QueryInterface(
967 LPDIRECTSOUNDNOTIFY iface
,REFIID riid
,LPVOID
*ppobj
969 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
971 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
975 static ULONG WINAPI
IDirectSoundNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface
) {
976 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
977 return ++(This
->ref
);
980 static ULONG WINAPI
IDirectSoundNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface
) {
981 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
983 TRACE("(%p) ref was %ld\n", This
, This
->ref
);
987 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)This
->dsb
);
988 HeapFree(GetProcessHeap(),0,This
);
994 static HRESULT WINAPI
IDirectSoundNotifyImpl_SetNotificationPositions(
995 LPDIRECTSOUNDNOTIFY iface
,DWORD howmuch
,LPCDSBPOSITIONNOTIFY notify
997 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
1000 if (TRACE_ON(dsound
)) {
1001 TRACE("(%p,0x%08lx,%p)\n",This
,howmuch
,notify
);
1002 for (i
=0;i
<howmuch
;i
++)
1003 TRACE("notify at %ld to 0x%08lx\n",
1004 notify
[i
].dwOffset
,(DWORD
)notify
[i
].hEventNotify
);
1006 This
->dsb
->notifies
= HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,This
->dsb
->notifies
,(This
->dsb
->nrofnotifies
+howmuch
)*sizeof(DSBPOSITIONNOTIFY
));
1007 memcpy( This
->dsb
->notifies
+This
->dsb
->nrofnotifies
,
1009 howmuch
*sizeof(DSBPOSITIONNOTIFY
)
1011 This
->dsb
->nrofnotifies
+=howmuch
;
1016 static ICOM_VTABLE(IDirectSoundNotify
) dsnvt
=
1018 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1019 IDirectSoundNotifyImpl_QueryInterface
,
1020 IDirectSoundNotifyImpl_AddRef
,
1021 IDirectSoundNotifyImpl_Release
,
1022 IDirectSoundNotifyImpl_SetNotificationPositions
,
1025 /*******************************************************************************
1026 * IDirectSoundBuffer
1029 static void DSOUND_RecalcVolPan(PDSVOLUMEPAN volpan
)
1033 /* the AmpFactors are expressed in 16.16 fixed point */
1034 volpan
->dwVolAmpFactor
= (ULONG
) (pow(2.0, volpan
->lVolume
/ 600.0) * 65536);
1035 /* FIXME: dwPan{Left|Right}AmpFactor */
1037 /* FIXME: use calculated vol and pan ampfactors */
1038 temp
= (double) (volpan
->lVolume
- (volpan
->lPan
> 0 ? volpan
->lPan
: 0));
1039 volpan
->dwTotalLeftAmpFactor
= (ULONG
) (pow(2.0, temp
/ 600.0) * 65536);
1040 temp
= (double) (volpan
->lVolume
+ (volpan
->lPan
< 0 ? volpan
->lPan
: 0));
1041 volpan
->dwTotalRightAmpFactor
= (ULONG
) (pow(2.0, temp
/ 600.0) * 65536);
1043 TRACE("left = %lx, right = %lx\n", volpan
->dwTotalLeftAmpFactor
, volpan
->dwTotalRightAmpFactor
);
1046 static void DSOUND_RecalcFormat(IDirectSoundBufferImpl
*dsb
)
1050 sw
= dsb
->wfx
.nChannels
* (dsb
->wfx
.wBitsPerSample
/ 8);
1051 if ((dsb
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
) && dsb
->hwbuf
) {
1053 /* let fragment size approximate the timer delay */
1054 fraglen
= (dsb
->freq
* DS_TIME_DEL
/ 1000) * sw
;
1055 /* reduce fragment size until an integer number of them fits in the buffer */
1056 /* (FIXME: this may or may not be a good idea) */
1057 while (dsb
->buflen
% fraglen
) fraglen
-= sw
;
1058 dsb
->dsound
->fraglen
= fraglen
;
1059 TRACE("fraglen=%ld\n", dsb
->dsound
->fraglen
);
1061 /* calculate the 10ms write lead */
1062 dsb
->writelead
= (dsb
->freq
/ 100) * sw
;
1065 static HRESULT
DSOUND_PrimaryOpen(IDirectSoundBufferImpl
*dsb
)
1067 HRESULT err
= DS_OK
;
1069 /* are we using waveOut stuff? */
1073 HRESULT merr
= DS_OK
;
1074 /* Start in pause mode, to allow buffers to get filled */
1075 waveOutPause(dsb
->dsound
->hwo
);
1076 if (dsb
->state
== STATE_PLAYING
) dsb
->state
= STATE_STARTING
;
1077 else if (dsb
->state
== STATE_STOPPING
) dsb
->state
= STATE_STOPPED
;
1078 /* use fragments of 10ms (1/100s) each (which should get us within
1079 * the documented write cursor lead of 10-15ms) */
1080 buflen
= ((dsb
->wfx
.nAvgBytesPerSec
/ 100) & ~3) * DS_HEL_FRAGS
;
1081 TRACE("desired buflen=%ld, old buffer=%p\n", buflen
, dsb
->buffer
);
1082 /* reallocate emulated primary buffer */
1083 newbuf
= (LPBYTE
)HeapReAlloc(GetProcessHeap(),0,dsb
->buffer
,buflen
);
1084 if (newbuf
== NULL
) {
1085 ERR("failed to allocate primary buffer\n");
1086 merr
= DSERR_OUTOFMEMORY
;
1087 /* but the old buffer might still exists and must be re-prepared */
1089 dsb
->buffer
= newbuf
;
1090 dsb
->buflen
= buflen
;
1094 IDirectSoundImpl
*ds
= dsb
->dsound
;
1096 ds
->fraglen
= dsb
->buflen
/ DS_HEL_FRAGS
;
1098 /* prepare fragment headers */
1099 for (c
=0; c
<DS_HEL_FRAGS
; c
++) {
1100 ds
->pwave
[c
]->lpData
= dsb
->buffer
+ c
*ds
->fraglen
;
1101 ds
->pwave
[c
]->dwBufferLength
= ds
->fraglen
;
1102 ds
->pwave
[c
]->dwUser
= (DWORD
)dsb
;
1103 ds
->pwave
[c
]->dwFlags
= 0;
1104 ds
->pwave
[c
]->dwLoops
= 0;
1105 err
= mmErr(waveOutPrepareHeader(ds
->hwo
,ds
->pwave
[c
],sizeof(WAVEHDR
)));
1108 waveOutUnprepareHeader(ds
->hwo
,ds
->pwave
[c
],sizeof(WAVEHDR
));
1116 memset(dsb
->buffer
, (dsb
->wfx
.wBitsPerSample
== 16) ? 0 : 128, dsb
->buflen
);
1117 TRACE("fraglen=%ld\n", ds
->fraglen
);
1119 if ((err
== DS_OK
) && (merr
!= DS_OK
))
1126 static void DSOUND_PrimaryClose(IDirectSoundBufferImpl
*dsb
)
1128 /* are we using waveOut stuff? */
1131 IDirectSoundImpl
*ds
= dsb
->dsound
;
1133 waveOutReset(ds
->hwo
);
1134 for (c
=0; c
<DS_HEL_FRAGS
; c
++)
1135 waveOutUnprepareHeader(ds
->hwo
, ds
->pwave
[c
], sizeof(WAVEHDR
));
1139 static HRESULT
DSOUND_PrimaryPlay(IDirectSoundBufferImpl
*dsb
)
1141 HRESULT err
= DS_OK
;
1143 err
= IDsDriverBuffer_Play(dsb
->hwbuf
, 0, 0, DSBPLAY_LOOPING
);
1147 static HRESULT
DSOUND_PrimaryStop(IDirectSoundBufferImpl
*dsb
)
1149 HRESULT err
= DS_OK
;
1151 err
= IDsDriverBuffer_Stop(dsb
->hwbuf
);
1152 if (err
== DSERR_BUFFERLOST
) {
1153 /* Wine-only: the driver wants us to reopen the device */
1154 /* FIXME: check for errors */
1155 IDsDriverBuffer_Release(primarybuf
->hwbuf
);
1156 waveOutClose(dsb
->dsound
->hwo
);
1157 dsb
->dsound
->hwo
= 0;
1158 waveOutOpen(&(dsb
->dsound
->hwo
), dsb
->dsound
->drvdesc
.dnDevNode
,
1159 &(primarybuf
->wfx
), 0, 0, CALLBACK_NULL
| WAVE_DIRECTSOUND
);
1160 err
= IDsDriver_CreateSoundBuffer(dsb
->dsound
->driver
,&(dsb
->wfx
),dsb
->dsbd
.dwFlags
,0,
1161 &(dsb
->buflen
),&(dsb
->buffer
),
1162 (LPVOID
)&(dsb
->hwbuf
));
1168 /* This sets this format for the <em>Primary Buffer Only</em> */
1169 /* See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 120 */
1170 static HRESULT WINAPI
IDirectSoundBufferImpl_SetFormat(
1171 LPDIRECTSOUNDBUFFER iface
,LPWAVEFORMATEX wfex
1173 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1174 IDirectSoundBufferImpl
** dsb
;
1175 HRESULT err
= DS_OK
;
1178 /* Let's be pedantic! */
1179 if ((wfex
== NULL
) ||
1180 (wfex
->wFormatTag
!= WAVE_FORMAT_PCM
) ||
1181 (wfex
->nChannels
< 1) || (wfex
->nChannels
> 2) ||
1182 (wfex
->nSamplesPerSec
< 1) ||
1183 (wfex
->nBlockAlign
< 1) || (wfex
->nChannels
> 4) ||
1184 ((wfex
->wBitsPerSample
!= 8) && (wfex
->wBitsPerSample
!= 16))) {
1185 TRACE("failed pedantic check!\n");
1186 return DSERR_INVALIDPARAM
;
1190 EnterCriticalSection(&(This
->dsound
->lock
));
1192 if (primarybuf
->wfx
.nSamplesPerSec
!= wfex
->nSamplesPerSec
) {
1193 dsb
= dsound
->buffers
;
1194 for (i
= 0; i
< dsound
->nrofbuffers
; i
++, dsb
++) {
1196 EnterCriticalSection(&((*dsb
)->lock
));
1198 (*dsb
)->freqAdjust
= ((*dsb
)->freq
<< DSOUND_FREQSHIFT
) /
1199 wfex
->nSamplesPerSec
;
1201 LeaveCriticalSection(&((*dsb
)->lock
));
1206 memcpy(&(primarybuf
->wfx
), wfex
, sizeof(primarybuf
->wfx
));
1208 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
1209 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1210 wfex
->wFormatTag
, wfex
->nChannels
, wfex
->nSamplesPerSec
,
1211 wfex
->nAvgBytesPerSec
, wfex
->nBlockAlign
,
1212 wfex
->wBitsPerSample
, wfex
->cbSize
);
1214 primarybuf
->wfx
.nAvgBytesPerSec
=
1215 This
->wfx
.nSamplesPerSec
* This
->wfx
.nBlockAlign
;
1216 if (primarybuf
->dsound
->drvdesc
.dwFlags
& DSDDESC_DOMMSYSTEMSETFORMAT
) {
1217 /* FIXME: check for errors */
1218 DSOUND_PrimaryClose(primarybuf
);
1219 waveOutClose(This
->dsound
->hwo
);
1220 This
->dsound
->hwo
= 0;
1221 waveOutOpen(&(This
->dsound
->hwo
), This
->dsound
->drvdesc
.dnDevNode
,
1222 &(primarybuf
->wfx
), 0, 0, CALLBACK_NULL
| WAVE_DIRECTSOUND
);
1223 DSOUND_PrimaryOpen(primarybuf
);
1225 if (primarybuf
->hwbuf
) {
1226 err
= IDsDriverBuffer_SetFormat(primarybuf
->hwbuf
, &(primarybuf
->wfx
));
1227 if (err
== DSERR_BUFFERLOST
) {
1228 /* Wine-only: the driver wants us to recreate the HW buffer */
1229 IDsDriverBuffer_Release(primarybuf
->hwbuf
);
1230 err
= IDsDriver_CreateSoundBuffer(primarybuf
->dsound
->driver
,&(primarybuf
->wfx
),primarybuf
->dsbd
.dwFlags
,0,
1231 &(primarybuf
->buflen
),&(primarybuf
->buffer
),
1232 (LPVOID
)&(primarybuf
->hwbuf
));
1233 if (primarybuf
->state
== STATE_PLAYING
) primarybuf
->state
= STATE_STARTING
;
1234 else if (primarybuf
->state
== STATE_STOPPING
) primarybuf
->state
= STATE_STOPPED
;
1237 DSOUND_RecalcFormat(primarybuf
);
1239 LeaveCriticalSection(&(This
->dsound
->lock
));
1245 static HRESULT WINAPI
IDirectSoundBufferImpl_SetVolume(
1246 LPDIRECTSOUNDBUFFER iface
,LONG vol
1248 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1250 TRACE("(%p,%ld)\n",This
,vol
);
1252 /* I'm not sure if we need this for primary buffer */
1253 if (!(This
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
))
1254 return DSERR_CONTROLUNAVAIL
;
1256 if ((vol
> DSBVOLUME_MAX
) || (vol
< DSBVOLUME_MIN
))
1257 return DSERR_INVALIDPARAM
;
1260 EnterCriticalSection(&(This
->lock
));
1262 This
->volpan
.lVolume
= vol
;
1264 DSOUND_RecalcVolPan(&(This
->volpan
));
1267 IDsDriverBuffer_SetVolumePan(This
->hwbuf
, &(This
->volpan
));
1269 else if (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
1270 #if 0 /* should we really do this? */
1271 /* the DS volume ranges from 0 (max, 0dB attenuation) to -10000 (min, 100dB attenuation) */
1272 /* the MM volume ranges from 0 to 0xffff in an unspecified logarithmic scale */
1273 WORD cvol
= 0xffff + vol
*6 + vol
/2;
1274 DWORD vol
= cvol
| ((DWORD
)cvol
<< 16)
1275 waveOutSetVolume(This
->dsound
->hwo
, vol
);
1279 LeaveCriticalSection(&(This
->lock
));
1285 static HRESULT WINAPI
IDirectSoundBufferImpl_GetVolume(
1286 LPDIRECTSOUNDBUFFER iface
,LPLONG vol
1288 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1289 TRACE("(%p,%p)\n",This
,vol
);
1292 return DSERR_INVALIDPARAM
;
1294 *vol
= This
->volpan
.lVolume
;
1298 static HRESULT WINAPI
IDirectSoundBufferImpl_SetFrequency(
1299 LPDIRECTSOUNDBUFFER iface
,DWORD freq
1301 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1302 TRACE("(%p,%ld)\n",This
,freq
);
1304 /* You cannot set the frequency of the primary buffer */
1305 if (!(This
->dsbd
.dwFlags
& DSBCAPS_CTRLFREQUENCY
) ||
1306 (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
))
1307 return DSERR_CONTROLUNAVAIL
;
1309 if (!freq
) freq
= This
->wfx
.nSamplesPerSec
;
1311 if ((freq
< DSBFREQUENCY_MIN
) || (freq
> DSBFREQUENCY_MAX
))
1312 return DSERR_INVALIDPARAM
;
1315 EnterCriticalSection(&(This
->lock
));
1318 This
->freqAdjust
= (freq
<< DSOUND_FREQSHIFT
) / primarybuf
->wfx
.nSamplesPerSec
;
1319 This
->nAvgBytesPerSec
= freq
* This
->wfx
.nBlockAlign
;
1320 DSOUND_RecalcFormat(This
);
1322 LeaveCriticalSection(&(This
->lock
));
1328 static HRESULT WINAPI
IDirectSoundBufferImpl_Play(
1329 LPDIRECTSOUNDBUFFER iface
,DWORD reserved1
,DWORD reserved2
,DWORD flags
1331 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1332 TRACE("(%p,%08lx,%08lx,%08lx)\n",
1333 This
,reserved1
,reserved2
,flags
1337 EnterCriticalSection(&(This
->lock
));
1339 This
->playflags
= flags
;
1340 if (This
->state
== STATE_STOPPED
) {
1341 This
->leadin
= TRUE
;
1342 This
->startpos
= This
->buf_mixpos
;
1343 This
->state
= STATE_STARTING
;
1344 } else if (This
->state
== STATE_STOPPING
)
1345 This
->state
= STATE_PLAYING
;
1346 if (!(This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
) && This
->hwbuf
) {
1347 IDsDriverBuffer_Play(This
->hwbuf
, 0, 0, This
->playflags
);
1348 This
->state
= STATE_PLAYING
;
1351 LeaveCriticalSection(&(This
->lock
));
1357 static HRESULT WINAPI
IDirectSoundBufferImpl_Stop(LPDIRECTSOUNDBUFFER iface
)
1359 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1360 TRACE("(%p)\n",This
);
1363 EnterCriticalSection(&(This
->lock
));
1365 if (This
->state
== STATE_PLAYING
)
1366 This
->state
= STATE_STOPPING
;
1367 else if (This
->state
== STATE_STARTING
)
1368 This
->state
= STATE_STOPPED
;
1369 if (!(This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
) && This
->hwbuf
) {
1370 IDsDriverBuffer_Stop(This
->hwbuf
);
1371 This
->state
= STATE_STOPPED
;
1373 DSOUND_CheckEvent(This
, 0);
1375 LeaveCriticalSection(&(This
->lock
));
1381 static DWORD WINAPI
IDirectSoundBufferImpl_AddRef(LPDIRECTSOUNDBUFFER iface
) {
1382 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1385 TRACE("(%p) ref was %ld, thread is %lx\n",This
, This
->ref
, GetCurrentThreadId());
1387 ref
= InterlockedIncrement(&(This
->ref
));
1389 FIXME("thread-safety alert! AddRef-ing with a zero refcount!\n");
1393 static DWORD WINAPI
IDirectSoundBufferImpl_Release(LPDIRECTSOUNDBUFFER iface
) {
1394 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1398 TRACE("(%p) ref was %ld, thread is %lx\n",This
, This
->ref
, GetCurrentThreadId());
1400 ref
= InterlockedDecrement(&(This
->ref
));
1401 if (ref
) return ref
;
1403 EnterCriticalSection(&(This
->dsound
->lock
));
1404 for (i
=0;i
<This
->dsound
->nrofbuffers
;i
++)
1405 if (This
->dsound
->buffers
[i
] == This
)
1408 if (i
< This
->dsound
->nrofbuffers
) {
1409 /* Put the last buffer of the list in the (now empty) position */
1410 This
->dsound
->buffers
[i
] = This
->dsound
->buffers
[This
->dsound
->nrofbuffers
- 1];
1411 This
->dsound
->nrofbuffers
--;
1412 This
->dsound
->buffers
= HeapReAlloc(GetProcessHeap(),0,This
->dsound
->buffers
,sizeof(LPDIRECTSOUNDBUFFER
)*This
->dsound
->nrofbuffers
);
1413 TRACE("buffer count is now %d\n", This
->dsound
->nrofbuffers
);
1414 IDirectSound_Release((LPDIRECTSOUND
)This
->dsound
);
1416 LeaveCriticalSection(&(This
->dsound
->lock
));
1418 DeleteCriticalSection(&(This
->lock
));
1419 if (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
)
1420 DSOUND_PrimaryClose(This
);
1422 IDsDriverBuffer_Release(This
->hwbuf
);
1425 IDirectSound3DBuffer_Release((LPDIRECTSOUND3DBUFFER
)This
->ds3db
);
1427 /* this is a duplicate buffer */
1428 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)This
->parent
);
1430 /* this is a toplevel buffer */
1431 HeapFree(GetProcessHeap(),0,This
->buffer
);
1433 HeapFree(GetProcessHeap(),0,This
);
1435 if (This
== primarybuf
)
1441 static DWORD
DSOUND_CalcPlayPosition(IDirectSoundBufferImpl
*This
,
1442 DWORD state
, DWORD pplay
, DWORD pwrite
, DWORD pmix
, DWORD bmix
)
1446 TRACE("primary playpos=%ld, mixpos=%ld\n", pplay
, pmix
);
1447 TRACE("this mixpos=%ld\n", bmix
);
1449 /* the actual primary play position (pplay) is always behind last mixed (pmix),
1450 * unless the computer is too slow or something */
1451 /* we need to know how far away we are from there */
1452 if (pmix
== pplay
) {
1453 if ((state
== STATE_PLAYING
) || (state
== STATE_STOPPING
)) {
1454 /* wow, the software mixer is really doing well,
1455 * seems the entire primary buffer is filled! */
1456 pmix
+= primarybuf
->buflen
;
1458 /* else: the primary buffer is not playing, so probably empty */
1460 if (pmix
< pplay
) pmix
+= primarybuf
->buflen
; /* wraparound */
1462 /* detect buffer underrun */
1463 if (pwrite
< pplay
) pwrite
+= primarybuf
->buflen
; /* wraparound */
1465 if (pmix
> (DS_SND_QUEUE
* primarybuf
->dsound
->fraglen
+ pwrite
+ primarybuf
->writelead
)) {
1466 WARN("detected an underrun: primary queue was %ld\n",pmix
);
1469 /* divide the offset by its sample size */
1470 pmix
/= primarybuf
->wfx
.nBlockAlign
;
1471 TRACE("primary back-samples=%ld\n",pmix
);
1472 /* adjust for our frequency */
1473 pmix
= (pmix
* This
->freqAdjust
) >> DSOUND_FREQSHIFT
;
1474 /* multiply by our own sample size */
1475 pmix
*= This
->wfx
.nBlockAlign
;
1476 TRACE("this back-offset=%ld\n", pmix
);
1477 /* subtract from our last mixed position */
1479 while (bplay
< pmix
) bplay
+= This
->buflen
; /* wraparound */
1481 if (This
->leadin
&& ((bplay
< This
->startpos
) || (bplay
> bmix
))) {
1482 /* seems we haven't started playing yet */
1483 TRACE("this still in lead-in phase\n");
1484 bplay
= This
->startpos
;
1486 /* return the result */
1490 static HRESULT WINAPI
IDirectSoundBufferImpl_GetCurrentPosition(
1491 LPDIRECTSOUNDBUFFER iface
,LPDWORD playpos
,LPDWORD writepos
1494 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1495 TRACE("(%p,%p,%p)\n",This
,playpos
,writepos
);
1497 hres
=IDsDriverBuffer_GetPosition(This
->hwbuf
,playpos
,writepos
);
1502 else if (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
1505 mtime
.wType
= TIME_BYTES
;
1506 waveOutGetPosition(This
->dsound
->hwo
, &mtime
, sizeof(mtime
));
1507 mtime
.u
.cb
= mtime
.u
.cb
% This
->buflen
;
1508 *playpos
= mtime
.u
.cb
;
1511 /* the writepos should only be used by apps with WRITEPRIMARY priority,
1512 * in which case our software mixer is disabled anyway */
1513 *writepos
= This
->playpos
+ DS_HEL_MARGIN
* This
->dsound
->fraglen
;
1514 while (*writepos
>= This
->buflen
)
1515 *writepos
-= This
->buflen
;
1518 if (playpos
&& (This
->state
!= STATE_PLAYING
)) {
1519 /* we haven't been merged into the primary buffer (yet) */
1520 *playpos
= This
->buf_mixpos
;
1523 DWORD pplay
, pwrite
, lplay
, splay
, pstate
;
1524 /* let's get this exact; first, recursively call GetPosition on the primary */
1525 EnterCriticalSection(&(primarybuf
->lock
));
1526 if ((This
->dsbd
.dwFlags
& DSBCAPS_GETCURRENTPOSITION2
) || primarybuf
->hwbuf
|| !DS_EMULDRIVER
) {
1527 IDirectSoundBufferImpl_GetCurrentPosition((LPDIRECTSOUNDBUFFER
)primarybuf
, &pplay
, &pwrite
);
1528 /* detect HEL mode underrun */
1529 pstate
= primarybuf
->state
;
1530 if (!(primarybuf
->hwbuf
|| primarybuf
->dsound
->pwqueue
)) {
1531 TRACE("detected an underrun\n");
1533 if (pstate
== STATE_PLAYING
)
1534 pstate
= STATE_STARTING
;
1535 else if (pstate
== STATE_STOPPING
)
1536 pstate
= STATE_STOPPED
;
1538 /* get data for ourselves while we still have the lock */
1539 pstate
&= This
->state
;
1540 lplay
= This
->primary_mixpos
;
1541 splay
= This
->buf_mixpos
;
1542 /* calculate play position using this */
1543 *playpos
= DSOUND_CalcPlayPosition(This
, pstate
, pplay
, pwrite
, lplay
, splay
);
1545 /* (unless the app isn't using GETCURRENTPOSITION2) */
1546 /* don't know exactly how this should be handled...
1547 * the docs says that play cursor is reported as directly
1548 * behind write cursor, hmm... */
1549 *playpos
= This
->playpos
;
1551 LeaveCriticalSection(&(primarybuf
->lock
));
1553 if (writepos
) *writepos
= This
->buf_mixpos
;
1556 if (This
->state
!= STATE_STOPPED
)
1557 /* apply the documented 10ms lead to writepos */
1558 *writepos
+= This
->writelead
;
1559 while (*writepos
>= This
->buflen
) *writepos
-= This
->buflen
;
1561 TRACE("playpos = %ld, writepos = %ld (%p, time=%ld)\n", playpos
?*playpos
:0, writepos
?*writepos
:0, This
, GetTickCount());
1565 static HRESULT WINAPI
IDirectSoundBufferImpl_GetStatus(
1566 LPDIRECTSOUNDBUFFER iface
,LPDWORD status
1568 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1569 TRACE("(%p,%p), thread is %lx\n",This
,status
,GetCurrentThreadId());
1572 return DSERR_INVALIDPARAM
;
1575 if ((This
->state
== STATE_STARTING
) || (This
->state
== STATE_PLAYING
))
1576 *status
|= DSBSTATUS_PLAYING
;
1577 if (This
->playflags
& DSBPLAY_LOOPING
)
1578 *status
|= DSBSTATUS_LOOPING
;
1580 TRACE("status=%lx\n", *status
);
1585 static HRESULT WINAPI
IDirectSoundBufferImpl_GetFormat(
1586 LPDIRECTSOUNDBUFFER iface
,LPWAVEFORMATEX lpwf
,DWORD wfsize
,LPDWORD wfwritten
1588 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1589 TRACE("(%p,%p,%ld,%p)\n",This
,lpwf
,wfsize
,wfwritten
);
1591 if (wfsize
>sizeof(This
->wfx
))
1592 wfsize
= sizeof(This
->wfx
);
1593 if (lpwf
) { /* NULL is valid */
1594 memcpy(lpwf
,&(This
->wfx
),wfsize
);
1596 *wfwritten
= wfsize
;
1599 *wfwritten
= sizeof(This
->wfx
);
1601 return DSERR_INVALIDPARAM
;
1606 static HRESULT WINAPI
IDirectSoundBufferImpl_Lock(
1607 LPDIRECTSOUNDBUFFER iface
,DWORD writecursor
,DWORD writebytes
,LPVOID lplpaudioptr1
,LPDWORD audiobytes1
,LPVOID lplpaudioptr2
,LPDWORD audiobytes2
,DWORD flags
1609 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1612 TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx)\n",
1623 if (flags
& DSBLOCK_FROMWRITECURSOR
) {
1625 /* GetCurrentPosition does too much magic to duplicate here */
1626 IDirectSoundBufferImpl_GetCurrentPosition(iface
, NULL
, &writepos
);
1627 writecursor
+= writepos
;
1629 if (flags
& DSBLOCK_ENTIREBUFFER
)
1630 writebytes
= This
->buflen
;
1631 if (writebytes
> This
->buflen
)
1632 writebytes
= This
->buflen
;
1634 assert(audiobytes1
!=audiobytes2
);
1635 assert(lplpaudioptr1
!=lplpaudioptr2
);
1637 if ((writebytes
== This
->buflen
) &&
1638 ((This
->state
== STATE_STARTING
) ||
1639 (This
->state
== STATE_PLAYING
)))
1640 /* some games, like Half-Life, try to be clever (not) and
1641 * keep one secondary buffer, and mix sounds into it itself,
1642 * locking the entire buffer every time... so we can just forget
1643 * about tracking the last-written-to-position... */
1644 This
->probably_valid_to
= (DWORD
)-1;
1646 This
->probably_valid_to
= writecursor
;
1648 if (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
)
1649 capf
= DSDDESC_DONTNEEDPRIMARYLOCK
;
1651 capf
= DSDDESC_DONTNEEDSECONDARYLOCK
;
1652 if (!(This
->dsound
->drvdesc
.dwFlags
& capf
) && This
->hwbuf
) {
1653 IDsDriverBuffer_Lock(This
->hwbuf
,
1654 lplpaudioptr1
, audiobytes1
,
1655 lplpaudioptr2
, audiobytes2
,
1656 writecursor
, writebytes
,
1659 if (writecursor
+writebytes
<= This
->buflen
) {
1660 *(LPBYTE
*)lplpaudioptr1
= This
->buffer
+writecursor
;
1661 *audiobytes1
= writebytes
;
1663 *(LPBYTE
*)lplpaudioptr2
= NULL
;
1666 TRACE("->%ld.0\n",writebytes
);
1668 *(LPBYTE
*)lplpaudioptr1
= This
->buffer
+writecursor
;
1669 *audiobytes1
= This
->buflen
-writecursor
;
1671 *(LPBYTE
*)lplpaudioptr2
= This
->buffer
;
1673 *audiobytes2
= writebytes
-(This
->buflen
-writecursor
);
1674 TRACE("->%ld.%ld\n",*audiobytes1
,audiobytes2
?*audiobytes2
:0);
1679 static HRESULT WINAPI
IDirectSoundBufferImpl_SetCurrentPosition(
1680 LPDIRECTSOUNDBUFFER iface
,DWORD newpos
1682 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1683 TRACE("(%p,%ld)\n",This
,newpos
);
1686 EnterCriticalSection(&(This
->lock
));
1688 This
->buf_mixpos
= newpos
;
1690 IDsDriverBuffer_SetPosition(This
->hwbuf
, This
->buf_mixpos
);
1692 LeaveCriticalSection(&(This
->lock
));
1698 static HRESULT WINAPI
IDirectSoundBufferImpl_SetPan(
1699 LPDIRECTSOUNDBUFFER iface
,LONG pan
1701 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1703 TRACE("(%p,%ld)\n",This
,pan
);
1705 if ((pan
> DSBPAN_RIGHT
) || (pan
< DSBPAN_LEFT
))
1706 return DSERR_INVALIDPARAM
;
1708 /* You cannot set the pan of the primary buffer */
1709 /* and you cannot use both pan and 3D controls */
1710 if (!(This
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) ||
1711 (This
->dsbd
.dwFlags
& DSBCAPS_CTRL3D
) ||
1712 (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
))
1713 return DSERR_CONTROLUNAVAIL
;
1716 EnterCriticalSection(&(This
->lock
));
1718 This
->volpan
.lPan
= pan
;
1720 DSOUND_RecalcVolPan(&(This
->volpan
));
1723 IDsDriverBuffer_SetVolumePan(This
->hwbuf
, &(This
->volpan
));
1726 LeaveCriticalSection(&(This
->lock
));
1732 static HRESULT WINAPI
IDirectSoundBufferImpl_GetPan(
1733 LPDIRECTSOUNDBUFFER iface
,LPLONG pan
1735 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1736 TRACE("(%p,%p)\n",This
,pan
);
1739 return DSERR_INVALIDPARAM
;
1741 *pan
= This
->volpan
.lPan
;
1746 static HRESULT WINAPI
IDirectSoundBufferImpl_Unlock(
1747 LPDIRECTSOUNDBUFFER iface
,LPVOID p1
,DWORD x1
,LPVOID p2
,DWORD x2
1749 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1750 DWORD capf
, probably_valid_to
;
1752 TRACE("(%p,%p,%ld,%p,%ld):stub\n", This
,p1
,x1
,p2
,x2
);
1755 /* Preprocess 3D buffers... */
1757 /* This is highly experimental and liable to break things */
1758 if (This
->dsbd
.dwFlags
& DSBCAPS_CTRL3D
)
1759 DSOUND_Create3DBuffer(This
);
1762 if (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
)
1763 capf
= DSDDESC_DONTNEEDPRIMARYLOCK
;
1765 capf
= DSDDESC_DONTNEEDSECONDARYLOCK
;
1766 if (!(This
->dsound
->drvdesc
.dwFlags
& capf
) && This
->hwbuf
) {
1767 IDsDriverBuffer_Unlock(This
->hwbuf
, p1
, x1
, p2
, x2
);
1770 if (p2
) probably_valid_to
= (((LPBYTE
)p2
)-This
->buffer
) + x2
;
1771 else probably_valid_to
= (((LPBYTE
)p1
)-This
->buffer
) + x1
;
1772 while (probably_valid_to
>= This
->buflen
)
1773 probably_valid_to
-= This
->buflen
;
1774 if ((probably_valid_to
== 0) && ((x1
+x2
) == This
->buflen
) &&
1775 ((This
->state
== STATE_STARTING
) ||
1776 (This
->state
== STATE_PLAYING
)))
1777 /* see IDirectSoundBufferImpl_Lock */
1778 probably_valid_to
= (DWORD
)-1;
1779 This
->probably_valid_to
= probably_valid_to
;
1784 static HRESULT WINAPI
IDirectSoundBufferImpl_Restore(
1785 LPDIRECTSOUNDBUFFER iface
1787 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1788 FIXME("(%p):stub\n",This
);
1792 static HRESULT WINAPI
IDirectSoundBufferImpl_GetFrequency(
1793 LPDIRECTSOUNDBUFFER iface
,LPDWORD freq
1795 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1796 TRACE("(%p,%p)\n",This
,freq
);
1799 return DSERR_INVALIDPARAM
;
1802 TRACE("-> %ld\n", *freq
);
1807 static HRESULT WINAPI
IDirectSoundBufferImpl_Initialize(
1808 LPDIRECTSOUNDBUFFER iface
,LPDIRECTSOUND dsound
,LPDSBUFFERDESC dbsd
1810 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1811 FIXME("(%p,%p,%p):stub\n",This
,dsound
,dbsd
);
1812 DPRINTF("Re-Init!!!\n");
1813 return DSERR_ALREADYINITIALIZED
;
1816 static HRESULT WINAPI
IDirectSoundBufferImpl_GetCaps(
1817 LPDIRECTSOUNDBUFFER iface
,LPDSBCAPS caps
1819 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1820 TRACE("(%p)->(%p)\n",This
,caps
);
1823 return DSERR_INVALIDPARAM
;
1825 /* I think we should check this value, not set it. See */
1826 /* Inside DirectX, p215. That should apply here, too. */
1827 caps
->dwSize
= sizeof(*caps
);
1829 caps
->dwFlags
= This
->dsbd
.dwFlags
;
1830 if (This
->hwbuf
) caps
->dwFlags
|= DSBCAPS_LOCHARDWARE
;
1831 else caps
->dwFlags
|= DSBCAPS_LOCSOFTWARE
;
1833 caps
->dwBufferBytes
= This
->dsbd
.dwBufferBytes
;
1835 /* This value represents the speed of the "unlock" command.
1836 As unlock is quite fast (it does not do anything), I put
1837 4096 ko/s = 4 Mo / s */
1838 /* FIXME: hwbuf speed */
1839 caps
->dwUnlockTransferRate
= 4096;
1840 caps
->dwPlayCpuOverhead
= 0;
1845 static HRESULT WINAPI
IDirectSoundBufferImpl_QueryInterface(
1846 LPDIRECTSOUNDBUFFER iface
,REFIID riid
,LPVOID
*ppobj
1848 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1850 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
1852 if ( IsEqualGUID( &IID_IDirectSoundNotify
, riid
) ) {
1853 IDirectSoundNotifyImpl
*dsn
;
1855 dsn
= (IDirectSoundNotifyImpl
*)HeapAlloc(GetProcessHeap(),0,sizeof(*dsn
));
1858 IDirectSoundBuffer_AddRef(iface
);
1859 ICOM_VTBL(dsn
) = &dsnvt
;
1860 *ppobj
= (LPVOID
)dsn
;
1865 if ( IsEqualGUID( &IID_IDirectSound3DBuffer
, riid
) ) {
1866 IDirectSound3DBufferImpl
*ds3db
;
1868 *ppobj
= This
->ds3db
;
1870 IDirectSound3DBuffer_AddRef((LPDIRECTSOUND3DBUFFER
)This
->ds3db
);
1874 ds3db
= (IDirectSound3DBufferImpl
*)HeapAlloc(GetProcessHeap(),
1878 ICOM_VTBL(ds3db
) = &ds3dbvt
;
1879 InitializeCriticalSection(&ds3db
->lock
);
1881 IDirectSoundBuffer_AddRef(iface
);
1883 ds3db
->ds3db
.dwSize
= sizeof(DS3DBUFFER
);
1884 ds3db
->ds3db
.vPosition
.u1
.x
= 0.0;
1885 ds3db
->ds3db
.vPosition
.u2
.y
= 0.0;
1886 ds3db
->ds3db
.vPosition
.u3
.z
= 0.0;
1887 ds3db
->ds3db
.vVelocity
.u1
.x
= 0.0;
1888 ds3db
->ds3db
.vVelocity
.u2
.y
= 0.0;
1889 ds3db
->ds3db
.vVelocity
.u3
.z
= 0.0;
1890 ds3db
->ds3db
.dwInsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1891 ds3db
->ds3db
.dwOutsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1892 ds3db
->ds3db
.vConeOrientation
.u1
.x
= 0.0;
1893 ds3db
->ds3db
.vConeOrientation
.u2
.y
= 0.0;
1894 ds3db
->ds3db
.vConeOrientation
.u3
.z
= 0.0;
1895 ds3db
->ds3db
.lConeOutsideVolume
= DS3D_DEFAULTCONEOUTSIDEVOLUME
; ds3db
->ds3db
.flMinDistance
= DS3D_DEFAULTMINDISTANCE
;
1896 ds3db
->ds3db
.flMaxDistance
= DS3D_DEFAULTMAXDISTANCE
;
1897 ds3db
->ds3db
.dwMode
= DS3DMODE_NORMAL
;
1898 ds3db
->buflen
= (This
->buflen
* primarybuf
->wfx
.nBlockAlign
) /
1899 This
->wfx
.nBlockAlign
;
1900 ds3db
->buffer
= HeapAlloc(GetProcessHeap(), 0, ds3db
->buflen
);
1901 if (ds3db
->buffer
== NULL
) {
1903 ds3db
->ds3db
.dwMode
= DS3DMODE_DISABLE
;
1906 ds3db
->iks
= (IKsPropertySetImpl
*)HeapAlloc(GetProcessHeap(),0,sizeof(*(ds3db
->iks
)));
1907 ds3db
->iks
->ref
= 1;
1908 ds3db
->iks
->ds3db
= ds3db
;
1909 ICOM_VTBL(ds3db
->iks
) = &iksvt
;
1914 if ( IsEqualGUID( &IID_IDirectSound3DBuffer
, riid
) ) {
1915 FIXME("%s: I know about this GUID, but don't support it yet\n",
1916 debugstr_guid( riid
));
1922 if ( IsEqualGUID( &IID_IDirectSound3DListener
, riid
) ) {
1923 IDirectSound3DListenerImpl
* dsl
;
1925 if (This
->dsound
->listener
) {
1926 *ppobj
= This
->dsound
->listener
;
1927 IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER
)This
->dsound
->listener
);
1931 dsl
= (IDirectSound3DListenerImpl
*)HeapAlloc(GetProcessHeap(),0,sizeof(*dsl
));
1933 ICOM_VTBL(dsl
) = &ds3dlvt
;
1934 *ppobj
= (LPVOID
)dsl
;
1936 dsl
->ds3dl
.dwSize
= sizeof(DS3DLISTENER
);
1937 dsl
->ds3dl
.vPosition
.u1
.x
= 0.0;
1938 dsl
->ds3dl
.vPosition
.u2
.y
= 0.0;
1939 dsl
->ds3dl
.vPosition
.u3
.z
= 0.0;
1940 dsl
->ds3dl
.vVelocity
.u1
.x
= 0.0;
1941 dsl
->ds3dl
.vVelocity
.u2
.y
= 0.0;
1942 dsl
->ds3dl
.vVelocity
.u3
.z
= 0.0;
1943 dsl
->ds3dl
.vOrientFront
.u1
.x
= 0.0;
1944 dsl
->ds3dl
.vOrientFront
.u2
.y
= 0.0;
1945 dsl
->ds3dl
.vOrientFront
.u3
.z
= 1.0;
1946 dsl
->ds3dl
.vOrientTop
.u1
.x
= 0.0;
1947 dsl
->ds3dl
.vOrientTop
.u2
.y
= 1.0;
1948 dsl
->ds3dl
.vOrientTop
.u3
.z
= 0.0;
1949 dsl
->ds3dl
.flDistanceFactor
= DS3D_DEFAULTDISTANCEFACTOR
;
1950 dsl
->ds3dl
.flRolloffFactor
= DS3D_DEFAULTROLLOFFFACTOR
;
1952 InitializeCriticalSection(&dsl
->lock
);
1955 IDirectSoundBuffer_AddRef(iface
);
1957 This
->dsound
->listener
= dsl
;
1958 IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER
)dsl
);
1963 FIXME( "Unknown GUID %s\n", debugstr_guid( riid
) );
1970 static ICOM_VTABLE(IDirectSoundBuffer
) dsbvt
=
1972 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1973 IDirectSoundBufferImpl_QueryInterface
,
1974 IDirectSoundBufferImpl_AddRef
,
1975 IDirectSoundBufferImpl_Release
,
1976 IDirectSoundBufferImpl_GetCaps
,
1977 IDirectSoundBufferImpl_GetCurrentPosition
,
1978 IDirectSoundBufferImpl_GetFormat
,
1979 IDirectSoundBufferImpl_GetVolume
,
1980 IDirectSoundBufferImpl_GetPan
,
1981 IDirectSoundBufferImpl_GetFrequency
,
1982 IDirectSoundBufferImpl_GetStatus
,
1983 IDirectSoundBufferImpl_Initialize
,
1984 IDirectSoundBufferImpl_Lock
,
1985 IDirectSoundBufferImpl_Play
,
1986 IDirectSoundBufferImpl_SetCurrentPosition
,
1987 IDirectSoundBufferImpl_SetFormat
,
1988 IDirectSoundBufferImpl_SetVolume
,
1989 IDirectSoundBufferImpl_SetPan
,
1990 IDirectSoundBufferImpl_SetFrequency
,
1991 IDirectSoundBufferImpl_Stop
,
1992 IDirectSoundBufferImpl_Unlock
,
1993 IDirectSoundBufferImpl_Restore
1996 /*******************************************************************************
2000 static HRESULT WINAPI
IDirectSoundImpl_SetCooperativeLevel(
2001 LPDIRECTSOUND iface
,HWND hwnd
,DWORD level
2003 ICOM_THIS(IDirectSoundImpl
,iface
);
2005 FIXME("(%p,%08lx,%ld):stub\n",This
,(DWORD
)hwnd
,level
);
2007 This
->priolevel
= level
;
2012 static HRESULT WINAPI
IDirectSoundImpl_CreateSoundBuffer(
2013 LPDIRECTSOUND iface
,LPDSBUFFERDESC dsbd
,LPLPDIRECTSOUNDBUFFER ppdsb
,LPUNKNOWN lpunk
2015 ICOM_THIS(IDirectSoundImpl
,iface
);
2016 IDirectSoundBufferImpl
** ippdsb
=(IDirectSoundBufferImpl
**)ppdsb
;
2017 LPWAVEFORMATEX wfex
;
2018 HRESULT err
= DS_OK
;
2020 TRACE("(%p,%p,%p,%p)\n",This
,dsbd
,ippdsb
,lpunk
);
2022 if ((This
== NULL
) || (dsbd
== NULL
) || (ippdsb
== NULL
))
2023 return DSERR_INVALIDPARAM
;
2025 if (TRACE_ON(dsound
)) {
2026 TRACE("(structsize=%ld)\n",dsbd
->dwSize
);
2027 TRACE("(flags=0x%08lx:\n",dsbd
->dwFlags
);
2028 _dump_DSBCAPS(dsbd
->dwFlags
);
2030 TRACE("(bufferbytes=%ld)\n",dsbd
->dwBufferBytes
);
2031 TRACE("(lpwfxFormat=%p)\n",dsbd
->lpwfxFormat
);
2034 wfex
= dsbd
->lpwfxFormat
;
2037 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
2038 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
2039 wfex
->wFormatTag
, wfex
->nChannels
, wfex
->nSamplesPerSec
,
2040 wfex
->nAvgBytesPerSec
, wfex
->nBlockAlign
,
2041 wfex
->wBitsPerSample
, wfex
->cbSize
);
2043 if (dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
2045 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER
)primarybuf
);
2046 *ippdsb
= primarybuf
;
2047 primarybuf
->dsbd
.dwFlags
= dsbd
->dwFlags
;
2049 } /* Else create primary buffer */
2052 *ippdsb
= (IDirectSoundBufferImpl
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundBufferImpl
));
2053 if (*ippdsb
== NULL
)
2054 return DSERR_OUTOFMEMORY
;
2055 ICOM_VTBL(*ippdsb
) = &dsbvt
;
2057 (*ippdsb
)->dsound
= This
;
2058 (*ippdsb
)->parent
= NULL
;
2059 (*ippdsb
)->buffer
= NULL
;
2061 memcpy(&((*ippdsb
)->dsbd
),dsbd
,sizeof(*dsbd
));
2062 if (dsbd
->lpwfxFormat
)
2063 memcpy(&((*ippdsb
)->wfx
), dsbd
->lpwfxFormat
, sizeof((*ippdsb
)->wfx
));
2065 TRACE("Created buffer at %p\n", *ippdsb
);
2067 if (dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
2068 (*ippdsb
)->buflen
= dsound
->wfx
.nAvgBytesPerSec
;
2069 (*ippdsb
)->freq
= dsound
->wfx
.nSamplesPerSec
;
2071 /* FIXME: verify that hardware capabilities (DSCAPS_PRIMARY flags) match */
2074 err
= IDsDriver_CreateSoundBuffer(This
->driver
,wfex
,dsbd
->dwFlags
,0,
2075 &((*ippdsb
)->buflen
),&((*ippdsb
)->buffer
),
2076 (LPVOID
*)&((*ippdsb
)->hwbuf
));
2079 err
= DSOUND_PrimaryOpen(*ippdsb
);
2084 (*ippdsb
)->buflen
= dsbd
->dwBufferBytes
;
2085 (*ippdsb
)->freq
= dsbd
->lpwfxFormat
->nSamplesPerSec
;
2087 /* Check necessary hardware mixing capabilities */
2088 if (wfex
->nChannels
==2) capf
|= DSCAPS_SECONDARYSTEREO
;
2089 else capf
|= DSCAPS_SECONDARYMONO
;
2090 if (wfex
->wBitsPerSample
==16) capf
|= DSCAPS_SECONDARY16BIT
;
2091 else capf
|= DSCAPS_SECONDARY8BIT
;
2092 use_hw
= (This
->drvcaps
.dwFlags
& capf
) == capf
;
2094 /* FIXME: check hardware sample rate mixing capabilities */
2095 /* FIXME: check app hints for software/hardware buffer (STATIC, LOCHARDWARE, etc) */
2096 /* FIXME: check whether any hardware buffers are left */
2097 /* FIXME: handle DSDHEAP_CREATEHEAP for hardware buffers */
2099 /* Allocate system memory if applicable */
2100 if ((This
->drvdesc
.dwFlags
& DSDDESC_USESYSTEMMEMORY
) || !use_hw
) {
2101 (*ippdsb
)->buffer
= (LPBYTE
)HeapAlloc(GetProcessHeap(),0,(*ippdsb
)->buflen
);
2102 if ((*ippdsb
)->buffer
== NULL
)
2103 err
= DSERR_OUTOFMEMORY
;
2106 /* Allocate the hardware buffer */
2107 if (use_hw
&& (err
== DS_OK
)) {
2108 err
= IDsDriver_CreateSoundBuffer(This
->driver
,wfex
,dsbd
->dwFlags
,0,
2109 &((*ippdsb
)->buflen
),&((*ippdsb
)->buffer
),
2110 (LPVOID
*)&((*ippdsb
)->hwbuf
));
2115 if ((*ippdsb
)->buffer
)
2116 HeapFree(GetProcessHeap(),0,(*ippdsb
)->buffer
);
2117 HeapFree(GetProcessHeap(),0,(*ippdsb
));
2121 /* calculate fragment size and write lead */
2122 DSOUND_RecalcFormat(*ippdsb
);
2124 /* It's not necessary to initialize values to zero since */
2125 /* we allocated this structure with HEAP_ZERO_MEMORY... */
2126 (*ippdsb
)->playpos
= 0;
2127 (*ippdsb
)->buf_mixpos
= 0;
2128 (*ippdsb
)->state
= STATE_STOPPED
;
2129 DSOUND_RecalcVolPan(&((*ippdsb
)->volpan
));
2131 if (!(dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
)) {
2132 (*ippdsb
)->freqAdjust
= ((*ippdsb
)->freq
<< DSOUND_FREQSHIFT
) /
2133 primarybuf
->wfx
.nSamplesPerSec
;
2134 (*ippdsb
)->nAvgBytesPerSec
= (*ippdsb
)->freq
*
2135 dsbd
->lpwfxFormat
->nBlockAlign
;
2138 EnterCriticalSection(&(This
->lock
));
2139 /* register buffer */
2140 if (!(dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
)) {
2141 IDirectSoundBufferImpl
**newbuffers
= (IDirectSoundBufferImpl
**)HeapReAlloc(GetProcessHeap(),0,This
->buffers
,sizeof(IDirectSoundBufferImpl
*)*(This
->nrofbuffers
+1));
2143 This
->buffers
= newbuffers
;
2144 This
->buffers
[This
->nrofbuffers
] = *ippdsb
;
2145 This
->nrofbuffers
++;
2146 TRACE("buffer count is now %d\n", This
->nrofbuffers
);
2148 ERR("out of memory for buffer list! Current buffer count is %d\n", This
->nrofbuffers
);
2149 err
= DSERR_OUTOFMEMORY
;
2152 LeaveCriticalSection(&(This
->lock
));
2154 IDirectSound_AddRef(iface
);
2156 InitializeCriticalSection(&((*ippdsb
)->lock
));
2160 IDirectSoundBuffer_Release(*ppdsb
);
2166 if (dsbd
->dwFlags
& DSBCAPS_CTRL3D
) {
2167 IDirectSound3DBufferImpl
*ds3db
;
2169 ds3db
= (IDirectSound3DBufferImpl
*)HeapAlloc(GetProcessHeap(),
2171 ICOM_VTBL(ds3db
) = &ds3dbvt
;
2173 (*ippdsb
)->ds3db
= ds3db
;
2175 ds3db
->dsb
= (*ippdsb
);
2176 IDirectSoundBufferImpl_AddRef((LPDIRECTSOUNDBUFFER
)(*ippdsb
));
2178 InitializeCriticalSection(&ds3db
->lock
);
2180 ds3db
->ds3db
.dwSize
= sizeof(DS3DBUFFER
);
2181 ds3db
->ds3db
.vPosition
.u1
.x
= 0.0;
2182 ds3db
->ds3db
.vPosition
.u2
.y
= 0.0;
2183 ds3db
->ds3db
.vPosition
.u3
.z
= 0.0;
2184 ds3db
->ds3db
.vVelocity
.u1
.x
= 0.0;
2185 ds3db
->ds3db
.vVelocity
.u2
.y
= 0.0;
2186 ds3db
->ds3db
.vVelocity
.u3
.z
= 0.0;
2187 ds3db
->ds3db
.dwInsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
2188 ds3db
->ds3db
.dwOutsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
2189 ds3db
->ds3db
.vConeOrientation
.u1
.x
= 0.0;
2190 ds3db
->ds3db
.vConeOrientation
.u2
.y
= 0.0;
2191 ds3db
->ds3db
.vConeOrientation
.u3
.z
= 0.0;
2192 ds3db
->ds3db
.lConeOutsideVolume
= DS3D_DEFAULTCONEOUTSIDEVOLUME
;
2193 ds3db
->ds3db
.flMinDistance
= DS3D_DEFAULTMINDISTANCE
;
2194 ds3db
->ds3db
.flMaxDistance
= DS3D_DEFAULTMAXDISTANCE
;
2195 ds3db
->ds3db
.dwMode
= DS3DMODE_NORMAL
;
2196 ds3db
->buflen
= ((*ippdsb
)->buflen
* primarybuf
->wfx
.nBlockAlign
) /
2197 (*ippdsb
)->wfx
.nBlockAlign
;
2198 ds3db
->buffer
= HeapAlloc(GetProcessHeap(), 0, ds3db
->buflen
);
2199 if (ds3db
->buffer
== NULL
) {
2201 ds3db
->ds3db
.dwMode
= DS3DMODE_DISABLE
;
2203 ds3db
->iks
= (IKsPropertySetImpl
*)HeapAlloc(GetProcessHeap(),0,sizeof(*(ds3db
->iks
)));
2204 ds3db
->iks
->ref
= 1;
2205 ds3db
->iks
->ds3db
= ds3db
;
2206 ICOM_VTBL(ds3db
->iks
) = &iksvt
;
2213 static HRESULT WINAPI
IDirectSoundImpl_DuplicateSoundBuffer(
2214 LPDIRECTSOUND iface
,LPDIRECTSOUNDBUFFER pdsb
,LPLPDIRECTSOUNDBUFFER ppdsb
2216 ICOM_THIS(IDirectSoundImpl
,iface
);
2217 IDirectSoundBufferImpl
* ipdsb
=(IDirectSoundBufferImpl
*)pdsb
;
2218 IDirectSoundBufferImpl
** ippdsb
=(IDirectSoundBufferImpl
**)ppdsb
;
2219 TRACE("(%p,%p,%p)\n",This
,ipdsb
,ippdsb
);
2222 FIXME("need to duplicate hardware buffer\n");
2225 *ippdsb
= (IDirectSoundBufferImpl
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundBufferImpl
));
2227 IDirectSoundBuffer_AddRef(pdsb
);
2228 memcpy(*ippdsb
, ipdsb
, sizeof(IDirectSoundBufferImpl
));
2230 (*ippdsb
)->state
= STATE_STOPPED
;
2231 (*ippdsb
)->playpos
= 0;
2232 (*ippdsb
)->buf_mixpos
= 0;
2233 (*ippdsb
)->dsound
= This
;
2234 (*ippdsb
)->parent
= ipdsb
;
2235 memcpy(&((*ippdsb
)->wfx
), &(ipdsb
->wfx
), sizeof((*ippdsb
)->wfx
));
2236 InitializeCriticalSection(&(*ippdsb
)->lock
);
2237 /* register buffer */
2238 EnterCriticalSection(&(This
->lock
));
2240 IDirectSoundBufferImpl
**newbuffers
= (IDirectSoundBufferImpl
**)HeapReAlloc(GetProcessHeap(),0,This
->buffers
,sizeof(IDirectSoundBufferImpl
**)*(This
->nrofbuffers
+1));
2242 This
->buffers
= newbuffers
;
2243 This
->buffers
[This
->nrofbuffers
] = *ippdsb
;
2244 This
->nrofbuffers
++;
2245 TRACE("buffer count is now %d\n", This
->nrofbuffers
);
2247 ERR("out of memory for buffer list! Current buffer count is %d\n", This
->nrofbuffers
);
2248 /* FIXME: release buffer */
2251 LeaveCriticalSection(&(This
->lock
));
2252 IDirectSound_AddRef(iface
);
2257 static HRESULT WINAPI
IDirectSoundImpl_GetCaps(LPDIRECTSOUND iface
,LPDSCAPS caps
) {
2258 ICOM_THIS(IDirectSoundImpl
,iface
);
2259 TRACE("(%p,%p)\n",This
,caps
);
2260 TRACE("(flags=0x%08lx)\n",caps
->dwFlags
);
2263 return DSERR_INVALIDPARAM
;
2265 /* We should check this value, not set it. See Inside DirectX, p215. */
2266 caps
->dwSize
= sizeof(*caps
);
2268 caps
->dwFlags
= This
->drvcaps
.dwFlags
;
2270 /* FIXME: copy caps from This->drvcaps */
2271 caps
->dwMinSecondarySampleRate
= DSBFREQUENCY_MIN
;
2272 caps
->dwMaxSecondarySampleRate
= DSBFREQUENCY_MAX
;
2274 caps
->dwPrimaryBuffers
= 1;
2276 caps
->dwMaxHwMixingAllBuffers
= 0;
2277 caps
->dwMaxHwMixingStaticBuffers
= 0;
2278 caps
->dwMaxHwMixingStreamingBuffers
= 0;
2280 caps
->dwFreeHwMixingAllBuffers
= 0;
2281 caps
->dwFreeHwMixingStaticBuffers
= 0;
2282 caps
->dwFreeHwMixingStreamingBuffers
= 0;
2284 caps
->dwMaxHw3DAllBuffers
= 0;
2285 caps
->dwMaxHw3DStaticBuffers
= 0;
2286 caps
->dwMaxHw3DStreamingBuffers
= 0;
2288 caps
->dwFreeHw3DAllBuffers
= 0;
2289 caps
->dwFreeHw3DStaticBuffers
= 0;
2290 caps
->dwFreeHw3DStreamingBuffers
= 0;
2292 caps
->dwTotalHwMemBytes
= 0;
2294 caps
->dwFreeHwMemBytes
= 0;
2296 caps
->dwMaxContigFreeHwMemBytes
= 0;
2298 caps
->dwUnlockTransferRateHwBuffers
= 4096; /* But we have none... */
2300 caps
->dwPlayCpuOverheadSwBuffers
= 1; /* 1% */
2305 static ULONG WINAPI
IDirectSoundImpl_AddRef(LPDIRECTSOUND iface
) {
2306 ICOM_THIS(IDirectSoundImpl
,iface
);
2307 return ++(This
->ref
);
2310 static ULONG WINAPI
IDirectSoundImpl_Release(LPDIRECTSOUND iface
) {
2311 ICOM_THIS(IDirectSoundImpl
,iface
);
2312 TRACE("(%p), ref was %ld\n",This
,This
->ref
);
2313 if (!--(This
->ref
)) {
2316 timeKillEvent(This
->timerID
);
2317 timeEndPeriod(DS_TIME_RES
);
2320 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)primarybuf
);
2322 if (This
->buffers
) {
2323 for( i
=0;i
<This
->nrofbuffers
;i
++)
2324 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)This
->buffers
[i
]);
2328 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)This
->primary
);
2330 DeleteCriticalSection(&This
->lock
);
2332 IDsDriver_Close(This
->driver
);
2335 for (c
=0; c
<DS_HEL_FRAGS
; c
++)
2336 HeapFree(GetProcessHeap(),0,This
->pwave
[c
]);
2338 if (This
->drvdesc
.dwFlags
& DSDDESC_DOMMSYSTEMOPEN
) {
2339 waveOutClose(This
->hwo
);
2342 IDsDriver_Release(This
->driver
);
2344 HeapFree(GetProcessHeap(),0,This
);
2351 static HRESULT WINAPI
IDirectSoundImpl_SetSpeakerConfig(
2352 LPDIRECTSOUND iface
,DWORD config
2354 ICOM_THIS(IDirectSoundImpl
,iface
);
2355 FIXME("(%p,0x%08lx):stub\n",This
,config
);
2359 static HRESULT WINAPI
IDirectSoundImpl_QueryInterface(
2360 LPDIRECTSOUND iface
,REFIID riid
,LPVOID
*ppobj
2362 ICOM_THIS(IDirectSoundImpl
,iface
);
2364 if ( IsEqualGUID( &IID_IDirectSound3DListener
, riid
) ) {
2366 if (This
->listener
) {
2367 *ppobj
= This
->listener
;
2368 IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER
)This
->listener
);
2372 This
->listener
= (IDirectSound3DListenerImpl
*)HeapAlloc(
2373 GetProcessHeap(), 0, sizeof(*(This
->listener
)));
2374 This
->listener
->ref
= 1;
2375 ICOM_VTBL(This
->listener
) = &ds3dlvt
;
2376 *ppobj
= (LPVOID
)This
->listener
;
2377 IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER
)*ppobj
);
2379 This
->listener
->dsb
= NULL
;
2381 This
->listener
->ds3dl
.dwSize
= sizeof(DS3DLISTENER
);
2382 This
->listener
->ds3dl
.vPosition
.u1
.x
= 0.0;
2383 This
->listener
->ds3dl
.vPosition
.u2
.y
= 0.0;
2384 This
->listener
->ds3dl
.vPosition
.u3
.z
= 0.0;
2385 This
->listener
->ds3dl
.vVelocity
.u1
.x
= 0.0;
2386 This
->listener
->ds3dl
.vVelocity
.u2
.y
= 0.0;
2387 This
->listener
->ds3dl
.vVelocity
.u3
.z
= 0.0;
2388 This
->listener
->ds3dl
.vOrientFront
.u1
.x
= 0.0;
2389 This
->listener
->ds3dl
.vOrientFront
.u2
.y
= 0.0;
2390 This
->listener
->ds3dl
.vOrientFront
.u3
.z
= 1.0;
2391 This
->listener
->ds3dl
.vOrientTop
.u1
.x
= 0.0;
2392 This
->listener
->ds3dl
.vOrientTop
.u2
.y
= 1.0;
2393 This
->listener
->ds3dl
.vOrientTop
.u3
.z
= 0.0;
2394 This
->listener
->ds3dl
.flDistanceFactor
= DS3D_DEFAULTDISTANCEFACTOR
;
2395 This
->listener
->ds3dl
.flRolloffFactor
= DS3D_DEFAULTROLLOFFFACTOR
;
2396 This
->listener
->ds3dl
.flDopplerFactor
= DS3D_DEFAULTDOPPLERFACTOR
;
2398 InitializeCriticalSection(&This
->listener
->lock
);
2403 FIXME("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
2407 static HRESULT WINAPI
IDirectSoundImpl_Compact(
2408 LPDIRECTSOUND iface
)
2410 ICOM_THIS(IDirectSoundImpl
,iface
);
2411 TRACE("(%p)\n", This
);
2415 static HRESULT WINAPI
IDirectSoundImpl_GetSpeakerConfig(
2416 LPDIRECTSOUND iface
,
2417 LPDWORD lpdwSpeakerConfig
)
2419 ICOM_THIS(IDirectSoundImpl
,iface
);
2420 TRACE("(%p, %p)\n", This
, lpdwSpeakerConfig
);
2421 *lpdwSpeakerConfig
= DSSPEAKER_STEREO
| (DSSPEAKER_GEOMETRY_NARROW
<< 16);
2425 static HRESULT WINAPI
IDirectSoundImpl_Initialize(
2426 LPDIRECTSOUND iface
,
2429 ICOM_THIS(IDirectSoundImpl
,iface
);
2430 TRACE("(%p, %p)\n", This
, lpcGuid
);
2434 static ICOM_VTABLE(IDirectSound
) dsvt
=
2436 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
2437 IDirectSoundImpl_QueryInterface
,
2438 IDirectSoundImpl_AddRef
,
2439 IDirectSoundImpl_Release
,
2440 IDirectSoundImpl_CreateSoundBuffer
,
2441 IDirectSoundImpl_GetCaps
,
2442 IDirectSoundImpl_DuplicateSoundBuffer
,
2443 IDirectSoundImpl_SetCooperativeLevel
,
2444 IDirectSoundImpl_Compact
,
2445 IDirectSoundImpl_GetSpeakerConfig
,
2446 IDirectSoundImpl_SetSpeakerConfig
,
2447 IDirectSoundImpl_Initialize
2451 static void DSOUND_CheckEvent(IDirectSoundBufferImpl
*dsb
, int len
)
2455 LPDSBPOSITIONNOTIFY event
;
2457 if (dsb
->nrofnotifies
== 0)
2460 TRACE("(%p) buflen = %ld, playpos = %ld, len = %d\n",
2461 dsb
, dsb
->buflen
, dsb
->playpos
, len
);
2462 for (i
= 0; i
< dsb
->nrofnotifies
; i
++) {
2463 event
= dsb
->notifies
+ i
;
2464 offset
= event
->dwOffset
;
2465 TRACE("checking %d, position %ld, event = %d\n",
2466 i
, offset
, event
->hEventNotify
);
2467 /* DSBPN_OFFSETSTOP has to be the last element. So this is */
2468 /* OK. [Inside DirectX, p274] */
2470 /* This also means we can't sort the entries by offset, */
2471 /* because DSBPN_OFFSETSTOP == -1 */
2472 if (offset
== DSBPN_OFFSETSTOP
) {
2473 if (dsb
->state
== STATE_STOPPED
) {
2474 SetEvent(event
->hEventNotify
);
2475 TRACE("signalled event %d (%d)\n", event
->hEventNotify
, i
);
2480 if ((dsb
->playpos
+ len
) >= dsb
->buflen
) {
2481 if ((offset
< ((dsb
->playpos
+ len
) % dsb
->buflen
)) ||
2482 (offset
>= dsb
->playpos
)) {
2483 TRACE("signalled event %d (%d)\n", event
->hEventNotify
, i
);
2484 SetEvent(event
->hEventNotify
);
2487 if ((offset
>= dsb
->playpos
) && (offset
< (dsb
->playpos
+ len
))) {
2488 TRACE("signalled event %d (%d)\n", event
->hEventNotify
, i
);
2489 SetEvent(event
->hEventNotify
);
2495 /* WAV format info can be found at: */
2497 /* http://www.cwi.nl/ftp/audio/AudioFormats.part2 */
2498 /* ftp://ftp.cwi.nl/pub/audio/RIFF-format */
2500 /* Import points to remember: */
2502 /* 8-bit WAV is unsigned */
2503 /* 16-bit WAV is signed */
2505 static inline INT16
cvtU8toS16(BYTE byte
)
2507 INT16 s
= (byte
- 128) << 8;
2512 static inline BYTE
cvtS16toU8(INT16 word
)
2514 BYTE b
= (word
+ 32768) >> 8;
2520 /* We should be able to optimize these two inline functions */
2521 /* so that we aren't doing 8->16->8 conversions when it is */
2522 /* not necessary. But this is still a WIP. Optimize later. */
2523 static inline void get_fields(const IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT
*fl
, INT
*fr
)
2525 INT16
*bufs
= (INT16
*) buf
;
2527 /* TRACE("(%p)\n", buf); */
2528 if ((dsb
->wfx
.wBitsPerSample
== 8) && dsb
->wfx
.nChannels
== 2) {
2529 *fl
= cvtU8toS16(*buf
);
2530 *fr
= cvtU8toS16(*(buf
+ 1));
2534 if ((dsb
->wfx
.wBitsPerSample
== 16) && dsb
->wfx
.nChannels
== 2) {
2540 if ((dsb
->wfx
.wBitsPerSample
== 8) && dsb
->wfx
.nChannels
== 1) {
2541 *fl
= cvtU8toS16(*buf
);
2546 if ((dsb
->wfx
.wBitsPerSample
== 16) && dsb
->wfx
.nChannels
== 1) {
2552 FIXME("get_fields found an unsupported configuration\n");
2556 static inline void set_fields(BYTE
*buf
, INT fl
, INT fr
)
2558 INT16
*bufs
= (INT16
*) buf
;
2560 if ((primarybuf
->wfx
.wBitsPerSample
== 8) && (primarybuf
->wfx
.nChannels
== 2)) {
2561 *buf
= cvtS16toU8(fl
);
2562 *(buf
+ 1) = cvtS16toU8(fr
);
2566 if ((primarybuf
->wfx
.wBitsPerSample
== 16) && (primarybuf
->wfx
.nChannels
== 2)) {
2572 if ((primarybuf
->wfx
.wBitsPerSample
== 8) && (primarybuf
->wfx
.nChannels
== 1)) {
2573 *buf
= cvtS16toU8((fl
+ fr
) >> 1);
2577 if ((primarybuf
->wfx
.wBitsPerSample
== 16) && (primarybuf
->wfx
.nChannels
== 1)) {
2578 *bufs
= (fl
+ fr
) >> 1;
2581 FIXME("set_fields found an unsupported configuration\n");
2585 /* Now with PerfectPitch (tm) technology */
2586 static INT
DSOUND_MixerNorm(IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT len
)
2588 INT i
, size
, ipos
, ilen
, fieldL
, fieldR
;
2590 INT iAdvance
= dsb
->wfx
.nBlockAlign
;
2591 INT oAdvance
= primarybuf
->wfx
.nBlockAlign
;
2593 ibp
= dsb
->buffer
+ dsb
->buf_mixpos
;
2596 TRACE("(%p, %p, %p), buf_mixpos=%ld\n", dsb
, ibp
, obp
, dsb
->buf_mixpos
);
2597 /* Check for the best case */
2598 if ((dsb
->freq
== primarybuf
->wfx
.nSamplesPerSec
) &&
2599 (dsb
->wfx
.wBitsPerSample
== primarybuf
->wfx
.wBitsPerSample
) &&
2600 (dsb
->wfx
.nChannels
== primarybuf
->wfx
.nChannels
)) {
2601 DWORD bytesleft
= dsb
->buflen
- dsb
->buf_mixpos
;
2602 TRACE("(%p) Best case\n", dsb
);
2603 if (len
<= bytesleft
)
2604 memcpy(obp
, ibp
, len
);
2606 memcpy(obp
, ibp
, bytesleft
);
2607 memcpy(obp
+ bytesleft
, dsb
->buffer
, len
- bytesleft
);
2612 /* Check for same sample rate */
2613 if (dsb
->freq
== primarybuf
->wfx
.nSamplesPerSec
) {
2614 TRACE("(%p) Same sample rate %ld = primary %ld\n", dsb
,
2615 dsb
->freq
, primarybuf
->wfx
.nSamplesPerSec
);
2617 for (i
= 0; i
< len
; i
+= oAdvance
) {
2618 get_fields(dsb
, ibp
, &fieldL
, &fieldR
);
2621 set_fields(obp
, fieldL
, fieldR
);
2623 if (ibp
>= (BYTE
*)(dsb
->buffer
+ dsb
->buflen
))
2624 ibp
= dsb
->buffer
; /* wrap */
2629 /* Mix in different sample rates */
2631 /* New PerfectPitch(tm) Technology (c) 1998 Rob Riggs */
2632 /* Patent Pending :-] */
2634 /* Patent enhancements (c) 2000 Ove KÃ¥ven,
2635 * TransGaming Technologies Inc. */
2637 TRACE("(%p) Adjusting frequency: %ld -> %ld\n",
2638 dsb
, dsb
->freq
, primarybuf
->wfx
.nSamplesPerSec
);
2640 size
= len
/ oAdvance
;
2642 ipos
= dsb
->buf_mixpos
;
2643 for (i
= 0; i
< size
; i
++) {
2644 get_fields(dsb
, (dsb
->buffer
+ ipos
), &fieldL
, &fieldR
);
2645 set_fields(obp
, fieldL
, fieldR
);
2648 dsb
->freqAcc
+= dsb
->freqAdjust
;
2649 if (dsb
->freqAcc
>= (1<<DSOUND_FREQSHIFT
)) {
2650 ULONG adv
= (dsb
->freqAcc
>>DSOUND_FREQSHIFT
) * iAdvance
;
2651 dsb
->freqAcc
&= (1<<DSOUND_FREQSHIFT
)-1;
2652 ipos
+= adv
; ilen
+= adv
;
2653 while (ipos
>= dsb
->buflen
)
2654 ipos
-= dsb
->buflen
;
2660 static void DSOUND_MixerVol(IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT len
)
2662 INT i
, inc
= primarybuf
->wfx
.wBitsPerSample
>> 3;
2664 INT16
*bps
= (INT16
*) buf
;
2666 TRACE("(%p) left = %lx, right = %lx\n", dsb
,
2667 dsb
->volpan
.dwTotalLeftAmpFactor
, dsb
->volpan
.dwTotalRightAmpFactor
);
2668 if ((!(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) || (dsb
->volpan
.lPan
== 0)) &&
2669 (!(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
) || (dsb
->volpan
.lVolume
== 0)) &&
2670 !(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRL3D
))
2671 return; /* Nothing to do */
2673 /* If we end up with some bozo coder using panning or 3D sound */
2674 /* with a mono primary buffer, it could sound very weird using */
2675 /* this method. Oh well, tough patooties. */
2677 for (i
= 0; i
< len
; i
+= inc
) {
2683 /* 8-bit WAV is unsigned, but we need to operate */
2684 /* on signed data for this to work properly */
2686 val
= ((val
* (i
& inc
? dsb
->volpan
.dwTotalRightAmpFactor
: dsb
->volpan
.dwTotalLeftAmpFactor
)) >> 16);
2691 /* 16-bit WAV is signed -- much better */
2693 val
= ((val
* ((i
& inc
) ? dsb
->volpan
.dwTotalRightAmpFactor
: dsb
->volpan
.dwTotalLeftAmpFactor
)) >> 16);
2699 FIXME("MixerVol had a nasty error\n");
2705 static void DSOUND_Mixer3D(IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT len
)
2708 DWORD buflen
, buf_mixpos
;
2710 buflen
= dsb
->ds3db
->buflen
;
2711 buf_mixpos
= (dsb
->buf_mixpos
* primarybuf
->wfx
.nBlockAlign
) / dsb
->wfx
.nBlockAlign
;
2712 ibp
= dsb
->ds3db
->buffer
+ buf_mixpos
;
2715 if (buf_mixpos
> buflen
) {
2716 FIXME("Major breakage\n");
2720 if (len
<= (buf_mixpos
+ buflen
))
2721 memcpy(obp
, ibp
, len
);
2723 memcpy(obp
, ibp
, buflen
- buf_mixpos
);
2724 memcpy(obp
+ (buflen
- buf_mixpos
),
2726 len
- (buflen
- buf_mixpos
));
2732 static void *tmp_buffer
;
2733 static size_t tmp_buffer_len
= 0;
2735 static void *DSOUND_tmpbuffer(size_t len
)
2737 if (len
>tmp_buffer_len
) {
2738 void *new_buffer
= realloc(tmp_buffer
, len
);
2740 tmp_buffer
= new_buffer
;
2741 tmp_buffer_len
= len
;
2748 static DWORD
DSOUND_MixInBuffer(IDirectSoundBufferImpl
*dsb
, DWORD writepos
, DWORD fraglen
)
2750 INT i
, len
, ilen
, temp
, field
;
2751 INT advance
= primarybuf
->wfx
.wBitsPerSample
>> 3;
2752 BYTE
*buf
, *ibuf
, *obuf
;
2753 INT16
*ibufs
, *obufs
;
2756 if (!(dsb
->playflags
& DSBPLAY_LOOPING
)) {
2757 temp
= MulDiv(primarybuf
->wfx
.nAvgBytesPerSec
, dsb
->buflen
,
2758 dsb
->nAvgBytesPerSec
) -
2759 MulDiv(primarybuf
->wfx
.nAvgBytesPerSec
, dsb
->buf_mixpos
,
2760 dsb
->nAvgBytesPerSec
);
2761 len
= (len
> temp
) ? temp
: len
;
2763 len
&= ~3; /* 4 byte alignment */
2766 /* This should only happen if we aren't looping and temp < 4 */
2768 /* We skip the remainder, so check for possible events */
2769 DSOUND_CheckEvent(dsb
, dsb
->buflen
- dsb
->buf_mixpos
);
2771 dsb
->state
= STATE_STOPPED
;
2773 dsb
->buf_mixpos
= 0;
2774 dsb
->leadin
= FALSE
;
2775 /* Check for DSBPN_OFFSETSTOP */
2776 DSOUND_CheckEvent(dsb
, 0);
2780 /* Been seeing segfaults in malloc() for some reason... */
2781 TRACE("allocating buffer (size = %d)\n", len
);
2782 if ((buf
= ibuf
= (BYTE
*) DSOUND_tmpbuffer(len
)) == NULL
)
2785 TRACE("MixInBuffer (%p) len = %d, dest = %ld\n", dsb
, len
, writepos
);
2787 ilen
= DSOUND_MixerNorm(dsb
, ibuf
, len
);
2788 if ((dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) ||
2789 (dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
))
2790 DSOUND_MixerVol(dsb
, ibuf
, len
);
2792 obuf
= primarybuf
->buffer
+ writepos
;
2793 for (i
= 0; i
< len
; i
+= advance
) {
2794 obufs
= (INT16
*) obuf
;
2795 ibufs
= (INT16
*) ibuf
;
2796 if (primarybuf
->wfx
.wBitsPerSample
== 8) {
2797 /* 8-bit WAV is unsigned */
2798 field
= (*ibuf
- 128);
2799 field
+= (*obuf
- 128);
2800 field
= field
> 127 ? 127 : field
;
2801 field
= field
< -128 ? -128 : field
;
2802 *obuf
= field
+ 128;
2804 /* 16-bit WAV is signed */
2807 field
= field
> 32767 ? 32767 : field
;
2808 field
= field
< -32768 ? -32768 : field
;
2813 if (obuf
>= (BYTE
*)(primarybuf
->buffer
+ primarybuf
->buflen
))
2814 obuf
= primarybuf
->buffer
;
2818 if (dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPOSITIONNOTIFY
)
2819 DSOUND_CheckEvent(dsb
, ilen
);
2821 if (dsb
->leadin
&& (dsb
->startpos
> dsb
->buf_mixpos
) && (dsb
->startpos
<= dsb
->buf_mixpos
+ ilen
)) {
2822 /* HACK... leadin should be reset when the PLAY position reaches the startpos,
2823 * not the MIX position... but if the sound buffer is bigger than our prebuffering
2824 * (which must be the case for the streaming buffers that need this hack anyway)
2825 * plus DS_HEL_MARGIN or equivalent, then this ought to work anyway. */
2826 dsb
->leadin
= FALSE
;
2829 dsb
->buf_mixpos
+= ilen
;
2831 if (dsb
->buf_mixpos
>= dsb
->buflen
) {
2832 if (!(dsb
->playflags
& DSBPLAY_LOOPING
)) {
2833 dsb
->state
= STATE_STOPPED
;
2835 dsb
->buf_mixpos
= 0;
2836 dsb
->leadin
= FALSE
;
2837 DSOUND_CheckEvent(dsb
, 0); /* For DSBPN_OFFSETSTOP */
2840 while (dsb
->buf_mixpos
>= dsb
->buflen
)
2841 dsb
->buf_mixpos
-= dsb
->buflen
;
2842 if (dsb
->leadin
&& (dsb
->startpos
<= dsb
->buf_mixpos
))
2843 dsb
->leadin
= FALSE
; /* HACK: see above */
2850 static void DSOUND_MixCancel(IDirectSoundBufferImpl
*dsb
, DWORD writepos
)
2852 FIXME("prebuffer cancel not implemented yet\n");
2855 static DWORD
DSOUND_MixOne(IDirectSoundBufferImpl
*dsb
, DWORD playpos
, DWORD writepos
, DWORD mixlen
)
2858 /* determine this buffer's write position */
2859 DWORD buf_writepos
= DSOUND_CalcPlayPosition(dsb
, dsb
->state
& primarybuf
->state
, writepos
,
2860 writepos
, dsb
->primary_mixpos
, dsb
->buf_mixpos
);
2861 /* determine how much already-mixed data exists */
2863 ((dsb
->buf_mixpos
< buf_writepos
) ? dsb
->buflen
: 0) +
2864 dsb
->buf_mixpos
- buf_writepos
;
2865 DWORD primary_done
=
2866 ((dsb
->primary_mixpos
< writepos
) ? primarybuf
->buflen
: 0) +
2867 dsb
->primary_mixpos
- writepos
;
2869 ((primarybuf
->buf_mixpos
< writepos
) ? primarybuf
->buflen
: 0) +
2870 primarybuf
->buf_mixpos
- writepos
;
2873 TRACE("buf_writepos=%ld, primary_writepos=%ld\n", buf_writepos
, writepos
);
2874 TRACE("buf_done=%ld, primary_done=%ld\n", buf_done
, primary_done
);
2875 TRACE("buf_mixpos=%ld, primary_mixpos=%ld, mixlen=%ld\n", dsb
->buf_mixpos
, dsb
->primary_mixpos
,
2877 TRACE("looping=%ld, startpos=%ld, leadin=%ld\n", dsb
->playflags
, dsb
->startpos
, dsb
->leadin
);
2879 /* save write position for non-GETCURRENTPOSITION2... */
2880 dsb
->playpos
= buf_writepos
;
2882 /* check whether CalcPlayPosition detected a mixing underrun */
2883 if ((buf_done
== 0) && (dsb
->primary_mixpos
!= writepos
)) {
2884 /* it did, but did we have more to play? */
2885 if ((dsb
->playflags
& DSBPLAY_LOOPING
) ||
2886 (dsb
->buf_mixpos
< dsb
->buflen
)) {
2887 /* yes, have to recover */
2888 ERR("underrun on sound buffer %p\n", dsb
);
2889 TRACE("recovering from underrun: primary_mixpos=%ld\n", writepos
);
2891 dsb
->primary_mixpos
= writepos
;
2894 /* determine how far ahead we should mix */
2895 if (((dsb
->playflags
& DSBPLAY_LOOPING
) ||
2896 (dsb
->leadin
&& (dsb
->probably_valid_to
!= 0))) &&
2897 !(dsb
->dsbd
.dwFlags
& DSBCAPS_STATIC
)) {
2898 /* if this is a streaming buffer, it typically means that
2899 * we should defer mixing past probably_valid_to as long
2900 * as we can, to avoid unnecessary remixing */
2901 /* the heavy-looking calculations shouldn't be that bad,
2902 * as any game isn't likely to be have more than 1 or 2
2903 * streaming buffers in use at any time anyway... */
2904 DWORD probably_valid_left
=
2905 (dsb
->probably_valid_to
== (DWORD
)-1) ? dsb
->buflen
:
2906 ((dsb
->probably_valid_to
< buf_writepos
) ? dsb
->buflen
: 0) +
2907 dsb
->probably_valid_to
- buf_writepos
;
2908 /* check for leadin condition */
2909 if ((probably_valid_left
== 0) &&
2910 (dsb
->probably_valid_to
== dsb
->startpos
) &&
2912 probably_valid_left
= dsb
->buflen
;
2913 TRACE("streaming buffer probably_valid_to=%ld, probably_valid_left=%ld\n",
2914 dsb
->probably_valid_to
, probably_valid_left
);
2915 /* check whether the app's time is already up */
2916 if (probably_valid_left
< dsb
->writelead
) {
2917 WARN("probably_valid_to now within writelead, possible streaming underrun\n");
2918 /* once we pass the point of no return,
2919 * no reason to hold back anymore */
2920 dsb
->probably_valid_to
= (DWORD
)-1;
2921 /* we just have to go ahead and mix what we have,
2922 * there's no telling what the app is thinking anyway */
2924 /* divide valid length by our sample size */
2925 probably_valid_left
/= dsb
->wfx
.nBlockAlign
;
2926 /* adjust for our frequency */
2927 probably_valid_left
= (probably_valid_left
<< DSOUND_FREQSHIFT
) / dsb
->freqAdjust
;
2928 /* multiply by primary sample size */
2929 probably_valid_left
*= primarybuf
->wfx
.nBlockAlign
;
2930 /* check whether to clip mix_len */
2931 if (probably_valid_left
< mixlen
) {
2932 TRACE("clipping to probably_valid_left=%ld\n", probably_valid_left
);
2933 mixlen
= probably_valid_left
;
2937 /* cut mixlen with what's already been mixed */
2938 if (mixlen
< primary_done
) {
2939 /* huh? and still CalcPlayPosition didn't
2940 * detect an underrun? */
2941 FIXME("problem with underrun detection (mixlen=%ld < primary_done=%ld)\n", mixlen
, primary_done
);
2944 len
= mixlen
- primary_done
;
2945 TRACE("remaining mixlen=%ld\n", len
);
2947 if (len
< primarybuf
->dsound
->fraglen
) {
2948 /* smaller than a fragment, wait until it gets larger
2949 * before we take the mixing overhead */
2950 TRACE("mixlen not worth it, deferring mixing\n");
2954 /* ok, we know how much to mix, let's go */
2955 still_behind
= (adv_done
> primary_done
);
2957 slen
= primarybuf
->buflen
- dsb
->primary_mixpos
;
2958 if (slen
> len
) slen
= len
;
2959 slen
= DSOUND_MixInBuffer(dsb
, dsb
->primary_mixpos
, slen
);
2961 if ((dsb
->primary_mixpos
< primarybuf
->buf_mixpos
) &&
2962 (dsb
->primary_mixpos
+ slen
>= primarybuf
->buf_mixpos
))
2963 still_behind
= FALSE
;
2965 dsb
->primary_mixpos
+= slen
; len
-= slen
;
2966 while (dsb
->primary_mixpos
>= primarybuf
->buflen
)
2967 dsb
->primary_mixpos
-= primarybuf
->buflen
;
2969 if ((dsb
->state
== STATE_STOPPED
) || !slen
) break;
2971 TRACE("new primary_mixpos=%ld, primary_advbase=%ld\n", dsb
->primary_mixpos
, primarybuf
->buf_mixpos
);
2972 TRACE("mixed data len=%ld, still_behind=%d\n", mixlen
-len
, still_behind
);
2973 /* return how far we think the primary buffer can
2974 * advance its underrun detector...*/
2975 if (still_behind
) return 0;
2976 if ((mixlen
- len
) < primary_done
) return 0;
2977 slen
= ((dsb
->primary_mixpos
< primarybuf
->buf_mixpos
) ?
2978 primarybuf
->buflen
: 0) + dsb
->primary_mixpos
-
2979 primarybuf
->buf_mixpos
;
2980 if (slen
> mixlen
) {
2981 /* the primary_done and still_behind checks above should have worked */
2982 FIXME("problem with advancement calculation (advlen=%ld > mixlen=%ld)\n", slen
, mixlen
);
2988 static DWORD
DSOUND_MixToPrimary(DWORD playpos
, DWORD writepos
, DWORD mixlen
, BOOL recover
)
2990 INT i
, len
, maxlen
= 0;
2991 IDirectSoundBufferImpl
*dsb
;
2993 TRACE("(%ld,%ld,%ld)\n", playpos
, writepos
, mixlen
);
2994 for (i
= dsound
->nrofbuffers
- 1; i
>= 0; i
--) {
2995 dsb
= dsound
->buffers
[i
];
2997 if (!dsb
|| !(ICOM_VTBL(dsb
)))
2999 if (dsb
->buflen
&& dsb
->state
&& !dsb
->hwbuf
) {
3000 TRACE("Checking %p, mixlen=%ld\n", dsb
, mixlen
);
3001 EnterCriticalSection(&(dsb
->lock
));
3002 if (dsb
->state
== STATE_STOPPING
) {
3003 DSOUND_MixCancel(dsb
, writepos
);
3004 dsb
->state
= STATE_STOPPED
;
3006 if ((dsb
->state
== STATE_STARTING
) || recover
)
3007 dsb
->primary_mixpos
= writepos
;
3008 len
= DSOUND_MixOne(dsb
, playpos
, writepos
, mixlen
);
3009 if (dsb
->state
== STATE_STARTING
)
3010 dsb
->state
= STATE_PLAYING
;
3011 maxlen
= (len
> maxlen
) ? len
: maxlen
;
3013 LeaveCriticalSection(&(dsb
->lock
));
3020 static void CALLBACK
DSOUND_timer(UINT timerID
, UINT msg
, DWORD dwUser
, DWORD dw1
, DWORD dw2
)
3026 if (!dsound
|| !primarybuf
) {
3027 ERR("dsound died without killing us?\n");
3028 timeKillEvent(timerID
);
3029 timeEndPeriod(DS_TIME_RES
);
3033 EnterCriticalSection(&(dsound
->lock
));
3035 if (!primarybuf
|| !primarybuf
->ref
) {
3036 /* seems the primary buffer is currently being released */
3037 LeaveCriticalSection(&(dsound
->lock
));
3041 /* the sound of silence */
3042 nfiller
= primarybuf
->wfx
.wBitsPerSample
== 8 ? 128 : 0;
3044 /* whether the primary is forced to play even without secondary buffers */
3045 forced
= ((primarybuf
->state
== STATE_PLAYING
) || (primarybuf
->state
== STATE_STARTING
));
3047 if (primarybuf
->hwbuf
) {
3048 if (dsound
->priolevel
!= DSSCL_WRITEPRIMARY
) {
3049 BOOL paused
= ((primarybuf
->state
== STATE_STOPPED
) || (primarybuf
->state
== STATE_STARTING
));
3050 /* FIXME: document variables */
3051 DWORD playpos
, writepos
, inq
, maxq
, frag
;
3052 hres
= IDsDriverBuffer_GetPosition(primarybuf
->hwbuf
, &playpos
, &writepos
);
3054 LeaveCriticalSection(&(dsound
->lock
));
3057 /* Well, we *could* do Just-In-Time mixing using the writepos,
3058 * but that's a little bit ambitious and unnecessary... */
3059 /* rather add our safety margin to the writepos, if we're playing */
3061 writepos
+= primarybuf
->writelead
;
3062 while (writepos
>= primarybuf
->buflen
)
3063 writepos
-= primarybuf
->buflen
;
3064 } else writepos
= playpos
;
3065 TRACE("primary playpos=%ld, writepos=%ld, clrpos=%ld, mixpos=%ld\n",
3066 playpos
,writepos
,primarybuf
->playpos
,primarybuf
->buf_mixpos
);
3067 /* wipe out just-played sound data */
3068 if (playpos
< primarybuf
->playpos
) {
3069 memset(primarybuf
->buffer
+ primarybuf
->playpos
, nfiller
, primarybuf
->buflen
- primarybuf
->playpos
);
3070 memset(primarybuf
->buffer
, nfiller
, playpos
);
3072 memset(primarybuf
->buffer
+ primarybuf
->playpos
, nfiller
, playpos
- primarybuf
->playpos
);
3074 primarybuf
->playpos
= playpos
;
3076 /* check how much prebuffering is left */
3077 inq
= primarybuf
->buf_mixpos
;
3079 inq
+= primarybuf
->buflen
;
3082 /* find the maximum we can prebuffer */
3085 if (maxq
< writepos
)
3086 maxq
+= primarybuf
->buflen
;
3088 } else maxq
= primarybuf
->buflen
;
3090 /* clip maxq to DS_SND_QUEUE */
3091 frag
= DS_SND_QUEUE
* dsound
->fraglen
;
3092 if (maxq
> frag
) maxq
= frag
;
3094 EnterCriticalSection(&(primarybuf
->lock
));
3096 /* check for consistency */
3098 /* the playback position must have passed our last
3099 * mixed position, i.e. it's an underrun, or we have
3100 * nothing more to play */
3101 TRACE("reached end of mixed data (inq=%ld, maxq=%ld)\n", inq
, maxq
);
3103 /* stop the playback now, to allow buffers to refill */
3104 DSOUND_PrimaryStop(primarybuf
);
3105 if (primarybuf
->state
== STATE_PLAYING
) {
3106 primarybuf
->state
= STATE_STARTING
;
3108 else if (primarybuf
->state
== STATE_STOPPING
) {
3109 primarybuf
->state
= STATE_STOPPED
;
3112 /* how can we have an underrun if we aren't playing? */
3113 WARN("unexpected primary state (%ld)\n", primarybuf
->state
);
3115 /* the Stop is supposed to reset play position to beginning of buffer */
3116 /* unfortunately, OSS is not able to do so, so get current pointer */
3117 hres
= IDsDriverBuffer_GetPosition(primarybuf
->hwbuf
, &playpos
, NULL
);
3119 LeaveCriticalSection(&(dsound
->lock
));
3120 LeaveCriticalSection(&(primarybuf
->lock
));
3124 primarybuf
->playpos
= playpos
;
3125 primarybuf
->buf_mixpos
= writepos
;
3127 maxq
= primarybuf
->buflen
;
3128 if (maxq
> frag
) maxq
= frag
;
3129 memset(primarybuf
->buffer
, nfiller
, primarybuf
->buflen
);
3134 frag
= DSOUND_MixToPrimary(playpos
, writepos
, maxq
, paused
);
3135 if (forced
) frag
= maxq
- inq
;
3136 primarybuf
->buf_mixpos
+= frag
;
3137 while (primarybuf
->buf_mixpos
>= primarybuf
->buflen
)
3138 primarybuf
->buf_mixpos
-= primarybuf
->buflen
;
3141 /* buffers have been filled, restart playback */
3142 if (primarybuf
->state
== STATE_STARTING
) {
3143 DSOUND_PrimaryPlay(primarybuf
);
3144 primarybuf
->state
= STATE_PLAYING
;
3145 TRACE("starting playback\n");
3147 else if (primarybuf
->state
== STATE_STOPPED
) {
3148 /* the primarybuf is supposed to play if there's something to play
3149 * even if it is reported as stopped, so don't let this confuse you */
3150 DSOUND_PrimaryPlay(primarybuf
);
3151 primarybuf
->state
= STATE_STOPPING
;
3152 TRACE("starting playback\n");
3155 LeaveCriticalSection(&(primarybuf
->lock
));
3157 /* in the DSSCL_WRITEPRIMARY mode, the app is totally in charge... */
3158 if (primarybuf
->state
== STATE_STARTING
) {
3159 DSOUND_PrimaryPlay(primarybuf
);
3160 primarybuf
->state
= STATE_PLAYING
;
3162 else if (primarybuf
->state
== STATE_STOPPING
) {
3163 DSOUND_PrimaryStop(primarybuf
);
3164 primarybuf
->state
= STATE_STOPPED
;
3168 /* using waveOut stuff */
3169 /* if no buffers are playing, we should be in pause mode now */
3170 DWORD writepos
, mixq
;
3171 /* clean out completed fragments */
3172 while (dsound
->pwqueue
&& (dsound
->pwave
[dsound
->pwplay
]->dwFlags
& WHDR_DONE
)) {
3173 if (dsound
->priolevel
!= DSSCL_WRITEPRIMARY
) {
3174 DWORD pos
= dsound
->pwplay
* dsound
->fraglen
;
3175 TRACE("done playing primary pos=%ld\n",pos
);
3176 memset(primarybuf
->buffer
+ pos
, nfiller
, dsound
->fraglen
);
3179 if (dsound
->pwplay
>= DS_HEL_FRAGS
) dsound
->pwplay
= 0;
3182 primarybuf
->playpos
= dsound
->pwplay
* dsound
->fraglen
;
3183 TRACE("primary playpos=%ld, mixpos=%ld\n",primarybuf
->playpos
,primarybuf
->buf_mixpos
);
3184 EnterCriticalSection(&(primarybuf
->lock
));
3186 if (!dsound
->pwqueue
) {
3187 /* this is either an underrun or we have nothing more to play...
3188 * since playback has already stopped now, we can enter pause mode,
3189 * in order to allow buffers to refill */
3190 if (primarybuf
->state
== STATE_PLAYING
) {
3191 TRACE("no more fragments ready to play\n");
3192 waveOutPause(dsound
->hwo
);
3193 primarybuf
->state
= STATE_STARTING
;
3195 else if (primarybuf
->state
== STATE_STOPPING
) {
3196 TRACE("no more fragments ready to play\n");
3197 waveOutPause(dsound
->hwo
);
3198 primarybuf
->state
= STATE_STOPPED
;
3202 /* find next write position, plus some extra margin, if necessary */
3203 mixq
= DS_HEL_MARGIN
;
3204 if (mixq
> dsound
->pwqueue
) mixq
= dsound
->pwqueue
;
3205 writepos
= primarybuf
->playpos
+ mixq
* dsound
->fraglen
;
3206 while (writepos
>= primarybuf
->buflen
) writepos
-= primarybuf
->buflen
;
3209 if (dsound
->priolevel
!= DSSCL_WRITEPRIMARY
) {
3210 DWORD frag
, maxq
= DS_SND_QUEUE
* dsound
->fraglen
;
3211 frag
= DSOUND_MixToPrimary(primarybuf
->playpos
, writepos
, maxq
, FALSE
);
3212 mixq
= frag
/ dsound
->fraglen
;
3213 if (frag
- (mixq
* dsound
->fraglen
))
3216 if (forced
) mixq
= DS_SND_QUEUE
;
3219 for (; mixq
; mixq
--) {
3220 waveOutWrite(dsound
->hwo
, dsound
->pwave
[dsound
->pwwrite
], sizeof(WAVEHDR
));
3222 if (dsound
->pwwrite
>= DS_HEL_FRAGS
) dsound
->pwwrite
= 0;
3225 primarybuf
->buf_mixpos
= dsound
->pwwrite
* dsound
->fraglen
;
3227 if (dsound
->pwqueue
) {
3228 /* buffers have been filled, restart playback */
3229 if (primarybuf
->state
== STATE_STARTING
) {
3230 waveOutRestart(dsound
->hwo
);
3231 primarybuf
->state
= STATE_PLAYING
;
3232 TRACE("starting playback\n");
3234 else if (primarybuf
->state
== STATE_STOPPED
) {
3235 /* the primarybuf is supposed to play if there's something to play
3236 * even if it is reported as stopped, so don't let this confuse you */
3237 waveOutRestart(dsound
->hwo
);
3238 primarybuf
->state
= STATE_STOPPING
;
3239 TRACE("starting playback\n");
3242 LeaveCriticalSection(&(primarybuf
->lock
));
3244 TRACE("completed processing\n");
3245 LeaveCriticalSection(&(dsound
->lock
));
3248 /*******************************************************************************
3249 * DirectSoundCreate (DSOUND.1)
3251 HRESULT WINAPI
DirectSoundCreate(REFGUID lpGUID
,LPDIRECTSOUND
*ppDS
,IUnknown
*pUnkOuter
)
3253 IDirectSoundImpl
** ippDS
=(IDirectSoundImpl
**)ppDS
;
3254 PIDSDRIVER drv
= NULL
;
3257 HRESULT err
= DS_OK
;
3260 TRACE("(%p,%p,%p)\n",lpGUID
,ippDS
,pUnkOuter
);
3262 TRACE("DirectSoundCreate (%p)\n", ippDS
);
3265 return DSERR_INVALIDPARAM
;
3268 IDirectSound_AddRef((LPDIRECTSOUND
)dsound
);
3273 /* Enumerate WINMM audio devices and find the one we want */
3274 wodn
= waveOutGetNumDevs();
3275 if (!wodn
) return DSERR_NODRIVER
;
3277 /* FIXME: How do we find the GUID of an audio device? */
3278 /* Well, just use the first available device for now... */
3280 /* Get output device caps */
3281 waveOutGetDevCapsA(wod
, &wcaps
, sizeof(wcaps
));
3282 /* DRV_QUERYDSOUNDIFACE is a "Wine extension" to get the DSound interface */
3283 waveOutMessage(wod
, DRV_QUERYDSOUNDIFACE
, (DWORD
)&drv
, 0);
3285 /* Allocate memory */
3286 *ippDS
= (IDirectSoundImpl
*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundImpl
));
3288 return DSERR_OUTOFMEMORY
;
3290 ICOM_VTBL(*ippDS
) = &dsvt
;
3293 (*ippDS
)->driver
= drv
;
3294 (*ippDS
)->fraglen
= 0;
3295 (*ippDS
)->priolevel
= DSSCL_NORMAL
;
3296 (*ippDS
)->nrofbuffers
= 0;
3297 (*ippDS
)->buffers
= NULL
;
3298 (*ippDS
)->primary
= NULL
;
3299 (*ippDS
)->listener
= NULL
;
3301 /* Get driver description */
3303 IDsDriver_GetDriverDesc(drv
,&((*ippDS
)->drvdesc
));
3305 /* if no DirectSound interface available, use WINMM API instead */
3306 (*ippDS
)->drvdesc
.dwFlags
= DSDDESC_DOMMSYSTEMOPEN
| DSDDESC_DOMMSYSTEMSETFORMAT
;
3307 (*ippDS
)->drvdesc
.dnDevNode
= wod
; /* FIXME? */
3310 /* Set default wave format (may need it for waveOutOpen) */
3311 (*ippDS
)->wfx
.wFormatTag
= WAVE_FORMAT_PCM
;
3312 (*ippDS
)->wfx
.nChannels
= 2;
3313 (*ippDS
)->wfx
.nSamplesPerSec
= 22050;
3314 (*ippDS
)->wfx
.nAvgBytesPerSec
= 44100;
3315 (*ippDS
)->wfx
.nBlockAlign
= 2;
3316 (*ippDS
)->wfx
.wBitsPerSample
= 8;
3318 /* If the driver requests being opened through MMSYSTEM
3319 * (which is recommended by the DDK), it is supposed to happen
3320 * before the DirectSound interface is opened */
3321 if ((*ippDS
)->drvdesc
.dwFlags
& DSDDESC_DOMMSYSTEMOPEN
) {
3322 /* FIXME: is this right? */
3323 err
= mmErr(waveOutOpen(&((*ippDS
)->hwo
), (*ippDS
)->drvdesc
.dnDevNode
, &((*ippDS
)->wfx
),
3324 0, 0, CALLBACK_NULL
| WAVE_DIRECTSOUND
));
3327 if (drv
&& (err
== DS_OK
))
3328 err
= IDsDriver_Open(drv
);
3330 /* FIXME: do we want to handle a temporarily busy device? */
3332 HeapFree(GetProcessHeap(),0,*ippDS
);
3337 /* the driver is now open, so it's now allowed to call GetCaps */
3339 IDsDriver_GetCaps(drv
,&((*ippDS
)->drvcaps
));
3343 /* FIXME: look at wcaps */
3344 (*ippDS
)->drvcaps
.dwFlags
=
3345 DSCAPS_PRIMARY16BIT
| DSCAPS_PRIMARYSTEREO
;
3347 (*ippDS
)->drvcaps
.dwFlags
|= DSCAPS_EMULDRIVER
;
3349 /* Allocate memory for HEL buffer headers */
3350 for (c
=0; c
<DS_HEL_FRAGS
; c
++) {
3351 (*ippDS
)->pwave
[c
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(WAVEHDR
));
3352 if (!(*ippDS
)->pwave
[c
]) {
3353 /* Argh, out of memory */
3355 HeapFree(GetProcessHeap(),0,(*ippDS
)->pwave
[c
]);
3356 waveOutClose((*ippDS
)->hwo
);
3357 HeapFree(GetProcessHeap(),0,*ippDS
);
3359 return DSERR_OUTOFMEMORY
;
3365 InitializeCriticalSection(&((*ippDS
)->lock
));
3369 if (primarybuf
== NULL
) {
3373 dsbd
.dwSize
= sizeof(DSBUFFERDESC
);
3374 dsbd
.dwFlags
= DSBCAPS_PRIMARYBUFFER
;
3375 dsbd
.dwBufferBytes
= 0;
3376 dsbd
.lpwfxFormat
= &(dsound
->wfx
);
3377 hr
= IDirectSound_CreateSoundBuffer(*ppDS
, &dsbd
, (LPDIRECTSOUNDBUFFER
*)&primarybuf
, NULL
);
3381 /* dsound->primary is NULL - don't need to Release */
3382 dsound
->primary
= primarybuf
;
3383 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER
)primarybuf
);
3385 timeBeginPeriod(DS_TIME_RES
);
3386 dsound
->timerID
= timeSetEvent(DS_TIME_DEL
, DS_TIME_RES
, DSOUND_timer
,
3387 (DWORD
)dsound
, TIME_PERIODIC
| TIME_CALLBACK_FUNCTION
);
3392 /***************************************************************************
3393 * DirectSoundCaptureCreate [DSOUND.6]
3395 * Create and initialize a DirectSoundCapture interface
3399 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
3402 HRESULT WINAPI
DirectSoundCaptureCreate(
3404 LPDIRECTSOUNDCAPTURE
* lplpDSC
,
3405 LPUNKNOWN pUnkOuter
)
3407 TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID
), lplpDSC
, pUnkOuter
);
3410 return DSERR_NOAGGREGATION
;
3413 /* Default device? */
3415 return DSOUND_CreateDirectSoundCapture( (LPVOID
*)lplpDSC
);
3418 FIXME( "Unknown GUID %s\n", debugstr_guid(lpcGUID
) );
3421 return DSERR_OUTOFMEMORY
;
3424 /***************************************************************************
3425 * DirectSoundCaptureEnumerateA [DSOUND.7]
3427 * Enumerate all DirectSound drivers installed in the system
3431 * Failure: DSERR_INVALIDPARAM
3433 HRESULT WINAPI
DirectSoundCaptureEnumerateA(
3434 LPDSENUMCALLBACKA lpDSEnumCallback
,
3437 TRACE("(%p,%p)\n", lpDSEnumCallback
, lpContext
);
3439 if ( lpDSEnumCallback
)
3440 lpDSEnumCallback(NULL
,"WINE Primary Sound Capture Driver",
3441 "SoundCap",lpContext
);
3447 /***************************************************************************
3448 * DirectSoundCaptureEnumerateW [DSOUND.8]
3450 * Enumerate all DirectSound drivers installed in the system
3454 * Failure: DSERR_INVALIDPARAM
3456 HRESULT WINAPI
DirectSoundCaptureEnumerateW(
3457 LPDSENUMCALLBACKW lpDSEnumCallback
,
3460 FIXME("(%p,%p):stub\n", lpDSEnumCallback
, lpContext
);
3465 DSOUND_CreateDirectSoundCapture( LPVOID
* ppobj
)
3467 *ppobj
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof( IDirectSoundCaptureImpl
) );
3469 if ( *ppobj
== NULL
) {
3470 return DSERR_OUTOFMEMORY
;
3474 ICOM_THIS(IDirectSoundCaptureImpl
,*ppobj
);
3477 ICOM_VTBL(This
) = &dscvt
;
3479 InitializeCriticalSection( &This
->lock
);
3485 static HRESULT WINAPI
3486 IDirectSoundCaptureImpl_QueryInterface(
3487 LPDIRECTSOUNDCAPTURE iface
,
3491 ICOM_THIS(IDirectSoundCaptureImpl
,iface
);
3493 FIXME( "(%p)->(%s,%p): stub\n", This
, debugstr_guid(riid
), ppobj
);
3499 IDirectSoundCaptureImpl_AddRef( LPDIRECTSOUNDCAPTURE iface
)
3502 ICOM_THIS(IDirectSoundCaptureImpl
,iface
);
3504 EnterCriticalSection( &This
->lock
);
3506 TRACE( "(%p) was 0x%08lx\n", This
, This
->ref
);
3507 uRef
= ++(This
->ref
);
3509 LeaveCriticalSection( &This
->lock
);
3515 IDirectSoundCaptureImpl_Release( LPDIRECTSOUNDCAPTURE iface
)
3518 ICOM_THIS(IDirectSoundCaptureImpl
,iface
);
3520 EnterCriticalSection( &This
->lock
);
3522 TRACE( "(%p) was 0x%08lx\n", This
, This
->ref
);
3523 uRef
= --(This
->ref
);
3525 LeaveCriticalSection( &This
->lock
);
3528 DeleteCriticalSection( &This
->lock
);
3529 HeapFree( GetProcessHeap(), 0, This
);
3535 static HRESULT WINAPI
3536 IDirectSoundCaptureImpl_CreateCaptureBuffer(
3537 LPDIRECTSOUNDCAPTURE iface
,
3538 LPCDSCBUFFERDESC lpcDSCBufferDesc
,
3539 LPDIRECTSOUNDCAPTUREBUFFER
* lplpDSCaptureBuffer
,
3543 ICOM_THIS(IDirectSoundCaptureImpl
,iface
);
3545 TRACE( "(%p)->(%p,%p,%p)\n", This
, lpcDSCBufferDesc
, lplpDSCaptureBuffer
, pUnk
);
3548 return DSERR_INVALIDPARAM
;
3551 hr
= DSOUND_CreateDirectSoundCaptureBuffer( lpcDSCBufferDesc
, (LPVOID
*)lplpDSCaptureBuffer
);
3556 static HRESULT WINAPI
3557 IDirectSoundCaptureImpl_GetCaps(
3558 LPDIRECTSOUNDCAPTURE iface
,
3559 LPDSCCAPS lpDSCCaps
)
3561 ICOM_THIS(IDirectSoundCaptureImpl
,iface
);
3563 FIXME( "(%p)->(%p): stub\n", This
, lpDSCCaps
);
3568 static HRESULT WINAPI
3569 IDirectSoundCaptureImpl_Initialize(
3570 LPDIRECTSOUNDCAPTURE iface
,
3573 ICOM_THIS(IDirectSoundCaptureImpl
,iface
);
3575 FIXME( "(%p)->(%p): stub\n", This
, lpcGUID
);
3581 static ICOM_VTABLE(IDirectSoundCapture
) dscvt
=
3583 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
3584 /* IUnknown methods */
3585 IDirectSoundCaptureImpl_QueryInterface
,
3586 IDirectSoundCaptureImpl_AddRef
,
3587 IDirectSoundCaptureImpl_Release
,
3589 /* IDirectSoundCapture methods */
3590 IDirectSoundCaptureImpl_CreateCaptureBuffer
,
3591 IDirectSoundCaptureImpl_GetCaps
,
3592 IDirectSoundCaptureImpl_Initialize
3596 DSOUND_CreateDirectSoundCaptureBuffer( LPCDSCBUFFERDESC lpcDSCBufferDesc
, LPVOID
* ppobj
)
3599 FIXME( "(%p,%p): ignoring lpcDSCBufferDesc\n", lpcDSCBufferDesc
, ppobj
);
3601 *ppobj
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof( IDirectSoundCaptureBufferImpl
) );
3603 if ( *ppobj
== NULL
) {
3604 return DSERR_OUTOFMEMORY
;
3608 ICOM_THIS(IDirectSoundCaptureBufferImpl
,*ppobj
);
3611 ICOM_VTBL(This
) = &dscbvt
;
3613 InitializeCriticalSection( &This
->lock
);
3620 static HRESULT WINAPI
3621 IDirectSoundCaptureBufferImpl_QueryInterface(
3622 LPDIRECTSOUNDCAPTUREBUFFER iface
,
3626 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3628 FIXME( "(%p)->(%s,%p): stub\n", This
, debugstr_guid(riid
), ppobj
);
3634 IDirectSoundCaptureBufferImpl_AddRef( LPDIRECTSOUNDCAPTUREBUFFER iface
)
3637 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3639 EnterCriticalSection( &This
->lock
);
3641 TRACE( "(%p) was 0x%08lx\n", This
, This
->ref
);
3642 uRef
= ++(This
->ref
);
3644 LeaveCriticalSection( &This
->lock
);
3650 IDirectSoundCaptureBufferImpl_Release( LPDIRECTSOUNDCAPTUREBUFFER iface
)
3653 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3655 EnterCriticalSection( &This
->lock
);
3657 TRACE( "(%p) was 0x%08lx\n", This
, This
->ref
);
3658 uRef
= --(This
->ref
);
3660 LeaveCriticalSection( &This
->lock
);
3663 DeleteCriticalSection( &This
->lock
);
3664 HeapFree( GetProcessHeap(), 0, This
);
3670 static HRESULT WINAPI
3671 IDirectSoundCaptureBufferImpl_GetCaps(
3672 LPDIRECTSOUNDCAPTUREBUFFER iface
,
3673 LPDSCBCAPS lpDSCBCaps
)
3675 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3677 FIXME( "(%p)->(%p): stub\n", This
, lpDSCBCaps
);
3682 static HRESULT WINAPI
3683 IDirectSoundCaptureBufferImpl_GetCurrentPosition(
3684 LPDIRECTSOUNDCAPTUREBUFFER iface
,
3685 LPDWORD lpdwCapturePosition
,
3686 LPDWORD lpdwReadPosition
)
3688 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3690 FIXME( "(%p)->(%p,%p): stub\n", This
, lpdwCapturePosition
, lpdwReadPosition
);
3695 static HRESULT WINAPI
3696 IDirectSoundCaptureBufferImpl_GetFormat(
3697 LPDIRECTSOUNDCAPTUREBUFFER iface
,
3698 LPWAVEFORMATEX lpwfxFormat
,
3699 DWORD dwSizeAllocated
,
3700 LPDWORD lpdwSizeWritten
)
3702 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3704 FIXME( "(%p)->(%p,0x%08lx,%p): stub\n", This
, lpwfxFormat
, dwSizeAllocated
, lpdwSizeWritten
);
3709 static HRESULT WINAPI
3710 IDirectSoundCaptureBufferImpl_GetStatus(
3711 LPDIRECTSOUNDCAPTUREBUFFER iface
,
3712 LPDWORD lpdwStatus
)
3714 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3716 FIXME( "(%p)->(%p): stub\n", This
, lpdwStatus
);
3721 static HRESULT WINAPI
3722 IDirectSoundCaptureBufferImpl_Initialize(
3723 LPDIRECTSOUNDCAPTUREBUFFER iface
,
3724 LPDIRECTSOUNDCAPTURE lpDSC
,
3725 LPCDSCBUFFERDESC lpcDSCBDesc
)
3727 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3729 FIXME( "(%p)->(%p,%p): stub\n", This
, lpDSC
, lpcDSCBDesc
);
3734 static HRESULT WINAPI
3735 IDirectSoundCaptureBufferImpl_Lock(
3736 LPDIRECTSOUNDCAPTUREBUFFER iface
,
3739 LPVOID
* lplpvAudioPtr1
,
3740 LPDWORD lpdwAudioBytes1
,
3741 LPVOID
* lplpvAudioPtr2
,
3742 LPDWORD lpdwAudioBytes2
,
3745 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3747 FIXME( "(%p)->(%08lu,%08lu,%p,%p,%p,%p,0x%08lx): stub\n", This
, dwReadCusor
, dwReadBytes
, lplpvAudioPtr1
, lpdwAudioBytes1
, lplpvAudioPtr2
, lpdwAudioBytes2
, dwFlags
);
3752 static HRESULT WINAPI
3753 IDirectSoundCaptureBufferImpl_Start(
3754 LPDIRECTSOUNDCAPTUREBUFFER iface
,
3757 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3759 FIXME( "(%p)->(0x%08lx): stub\n", This
, dwFlags
);
3764 static HRESULT WINAPI
3765 IDirectSoundCaptureBufferImpl_Stop( LPDIRECTSOUNDCAPTUREBUFFER iface
)
3767 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3769 FIXME( "(%p): stub\n", This
);
3774 static HRESULT WINAPI
3775 IDirectSoundCaptureBufferImpl_Unlock(
3776 LPDIRECTSOUNDCAPTUREBUFFER iface
,
3777 LPVOID lpvAudioPtr1
,
3778 DWORD dwAudioBytes1
,
3779 LPVOID lpvAudioPtr2
,
3780 DWORD dwAudioBytes2
)
3782 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3784 FIXME( "(%p)->(%p,%08lu,%p,%08lu): stub\n", This
, lpvAudioPtr1
, dwAudioBytes1
, lpvAudioPtr2
, dwAudioBytes2
);
3790 static ICOM_VTABLE(IDirectSoundCaptureBuffer
) dscbvt
=
3792 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
3793 /* IUnknown methods */
3794 IDirectSoundCaptureBufferImpl_QueryInterface
,
3795 IDirectSoundCaptureBufferImpl_AddRef
,
3796 IDirectSoundCaptureBufferImpl_Release
,
3798 /* IDirectSoundCaptureBuffer methods */
3799 IDirectSoundCaptureBufferImpl_GetCaps
,
3800 IDirectSoundCaptureBufferImpl_GetCurrentPosition
,
3801 IDirectSoundCaptureBufferImpl_GetFormat
,
3802 IDirectSoundCaptureBufferImpl_GetStatus
,
3803 IDirectSoundCaptureBufferImpl_Initialize
,
3804 IDirectSoundCaptureBufferImpl_Lock
,
3805 IDirectSoundCaptureBufferImpl_Start
,
3806 IDirectSoundCaptureBufferImpl_Stop
,
3807 IDirectSoundCaptureBufferImpl_Unlock
3810 /*******************************************************************************
3811 * DirectSound ClassFactory
3815 /* IUnknown fields */
3816 ICOM_VFIELD(IClassFactory
);
3818 } IClassFactoryImpl
;
3820 static HRESULT WINAPI
3821 DSCF_QueryInterface(LPCLASSFACTORY iface
,REFIID riid
,LPVOID
*ppobj
) {
3822 ICOM_THIS(IClassFactoryImpl
,iface
);
3824 FIXME("(%p)->(%s,%p),stub!\n",This
,debugstr_guid(riid
),ppobj
);
3825 return E_NOINTERFACE
;
3829 DSCF_AddRef(LPCLASSFACTORY iface
) {
3830 ICOM_THIS(IClassFactoryImpl
,iface
);
3831 return ++(This
->ref
);
3834 static ULONG WINAPI
DSCF_Release(LPCLASSFACTORY iface
) {
3835 ICOM_THIS(IClassFactoryImpl
,iface
);
3836 /* static class, won't be freed */
3837 return --(This
->ref
);
3840 static HRESULT WINAPI
DSCF_CreateInstance(
3841 LPCLASSFACTORY iface
,LPUNKNOWN pOuter
,REFIID riid
,LPVOID
*ppobj
3843 ICOM_THIS(IClassFactoryImpl
,iface
);
3845 TRACE("(%p)->(%p,%s,%p)\n",This
,pOuter
,debugstr_guid(riid
),ppobj
);
3846 if ( IsEqualGUID( &IID_IDirectSound
, riid
) ) {
3847 /* FIXME: reuse already created dsound if present? */
3848 return DirectSoundCreate(riid
,(LPDIRECTSOUND
*)ppobj
,pOuter
);
3850 return E_NOINTERFACE
;
3853 static HRESULT WINAPI
DSCF_LockServer(LPCLASSFACTORY iface
,BOOL dolock
) {
3854 ICOM_THIS(IClassFactoryImpl
,iface
);
3855 FIXME("(%p)->(%d),stub!\n",This
,dolock
);
3859 static ICOM_VTABLE(IClassFactory
) DSCF_Vtbl
= {
3860 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
3861 DSCF_QueryInterface
,
3864 DSCF_CreateInstance
,
3867 static IClassFactoryImpl DSOUND_CF
= {&DSCF_Vtbl
, 1 };
3869 /*******************************************************************************
3870 * DllGetClassObject [DSOUND.5]
3871 * Retrieves class object from a DLL object
3874 * Docs say returns STDAPI
3877 * rclsid [I] CLSID for the class object
3878 * riid [I] Reference to identifier of interface for class object
3879 * ppv [O] Address of variable to receive interface pointer for riid
3883 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
3886 DWORD WINAPI
DSOUND_DllGetClassObject(REFCLSID rclsid
,REFIID riid
,LPVOID
*ppv
)
3888 TRACE("(%p,%p,%p)\n", debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
3889 if ( IsEqualCLSID( &IID_IClassFactory
, riid
) ) {
3890 *ppv
= (LPVOID
)&DSOUND_CF
;
3891 IClassFactory_AddRef((IClassFactory
*)*ppv
);
3895 FIXME("(%p,%p,%p): no interface found.\n", debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
3896 return CLASS_E_CLASSNOTAVAILABLE
;
3900 /*******************************************************************************
3901 * DllCanUnloadNow [DSOUND.4] Determines whether the DLL is in use.
3907 DWORD WINAPI
DSOUND_DllCanUnloadNow(void)
3909 FIXME("(void): stub\n");