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