Return error from low level driver when necessary.
[wine/multimedia.git] / dlls / dsound / buffer.c
blob85fdde5b36f9cae958426c85bca126cd0cf0f48c
1 /* DirectSound
3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998 Rob Riggs
5 * Copyright 2000-2002 TransGaming Technologies, Inc.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "config.h"
23 #include <assert.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <sys/types.h>
27 #include <sys/fcntl.h>
28 #ifdef HAVE_UNISTD_H
29 # include <unistd.h>
30 #endif
31 #include <stdlib.h>
32 #include <string.h>
33 #include <math.h>
35 #define NONAMELESSSTRUCT
36 #define NONAMELESSUNION
37 #include "windef.h"
38 #include "winbase.h"
39 #include "wingdi.h"
40 #include "winuser.h"
41 #include "winerror.h"
42 #include "mmsystem.h"
43 #include "winreg.h"
44 #include "winternl.h"
45 #include "mmddk.h"
46 #include "wine/windef16.h"
47 #include "wine/debug.h"
48 #include "dsound.h"
49 #include "dsdriver.h"
50 #include "dsound_private.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
54 /*******************************************************************************
55 * IDirectSoundNotify
57 static HRESULT WINAPI IDirectSoundNotifyImpl_QueryInterface(
58 LPDIRECTSOUNDNOTIFY iface,REFIID riid,LPVOID *ppobj
59 ) {
60 IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
61 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
63 if (This->dsb == NULL) {
64 WARN("invalid parameter\n");
65 return E_INVALIDARG;
68 return IDirectSoundBuffer_QueryInterface((LPDIRECTSOUNDBUFFER)This->dsb, riid, ppobj);
71 static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface) {
72 IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
73 DWORD ref;
75 TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
77 ref = InterlockedIncrement(&(This->ref));
78 return ref;
81 static ULONG WINAPI IDirectSoundNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface) {
82 IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
83 DWORD ref;
85 TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
87 ref = InterlockedDecrement(&(This->ref));
88 if (ref == 0) {
89 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->dsb);
90 This->dsb->notify = NULL;
91 HeapFree(GetProcessHeap(),0,This);
92 TRACE("(%p) released\n",This);
94 return ref;
97 static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(
98 LPDIRECTSOUNDNOTIFY iface,DWORD howmuch,LPCDSBPOSITIONNOTIFY notify
99 ) {
100 IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
101 TRACE("(%p,0x%08lx,%p)\n",This,howmuch,notify);
103 if (howmuch > 0 && notify == NULL) {
104 WARN("invalid parameter: notify == NULL\n");
105 return DSERR_INVALIDPARAM;
108 if (TRACE_ON(dsound)) {
109 unsigned int i;
110 for (i=0;i<howmuch;i++)
111 TRACE("notify at %ld to 0x%08lx\n",
112 notify[i].dwOffset,(DWORD)notify[i].hEventNotify);
115 if (This->dsb->hwnotify) {
116 HRESULT hres;
117 hres = IDsDriverNotify_SetNotificationPositions(This->dsb->hwnotify, howmuch, notify);
118 if (hres != DS_OK)
119 WARN("IDsDriverNotify_SetNotificationPositions failed\n");
120 return hres;
121 } else if (howmuch > 0) {
122 /* Make an internal copy of the caller-supplied array.
123 * Replace the existing copy if one is already present. */
124 if (This->dsb->notifies)
125 This->dsb->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
126 This->dsb->notifies, howmuch * sizeof(DSBPOSITIONNOTIFY));
127 else
128 This->dsb->notifies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
129 howmuch * sizeof(DSBPOSITIONNOTIFY));
131 if (This->dsb->notifies == NULL) {
132 WARN("out of memory\n");
133 return DSERR_OUTOFMEMORY;
135 memcpy(This->dsb->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
136 This->dsb->nrofnotifies = howmuch;
137 } else {
138 if (This->dsb->notifies) {
139 HeapFree(GetProcessHeap(), 0, This->dsb->notifies);
140 This->dsb->notifies = NULL;
142 This->dsb->nrofnotifies = 0;
145 return S_OK;
148 IDirectSoundNotifyVtbl dsnvt =
150 IDirectSoundNotifyImpl_QueryInterface,
151 IDirectSoundNotifyImpl_AddRef,
152 IDirectSoundNotifyImpl_Release,
153 IDirectSoundNotifyImpl_SetNotificationPositions,
156 HRESULT WINAPI IDirectSoundNotifyImpl_Create(
157 IDirectSoundBufferImpl * dsb,
158 IDirectSoundNotifyImpl **pdsn)
160 IDirectSoundNotifyImpl * dsn;
161 TRACE("(%p,%p)\n",dsb,pdsn);
163 dsn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dsn));
165 if (dsn == NULL) {
166 WARN("out of memory\n");
167 return DSERR_OUTOFMEMORY;
170 dsn->ref = 0;
171 dsn->lpVtbl = &dsnvt;
172 dsn->dsb = dsb;
173 dsb->notify = dsn;
174 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)dsb);
176 *pdsn = dsn;
177 return DS_OK;
180 HRESULT WINAPI IDirectSoundNotifyImpl_Destroy(
181 IDirectSoundNotifyImpl *pdsn)
183 TRACE("(%p)\n",pdsn);
185 while (IDirectSoundNotifyImpl_Release((LPDIRECTSOUNDNOTIFY)pdsn) > 0);
187 return DS_OK;
190 /*******************************************************************************
191 * IDirectSoundBuffer
194 static HRESULT WINAPI IDirectSoundBufferImpl_SetFormat(
195 LPDIRECTSOUNDBUFFER8 iface,LPCWAVEFORMATEX wfex
197 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
199 TRACE("(%p,%p)\n",This,wfex);
200 /* This method is not available on secondary buffers */
201 WARN("invalid call\n");
202 return DSERR_INVALIDCALL;
205 static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume(
206 LPDIRECTSOUNDBUFFER8 iface,LONG vol
208 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
209 LONG oldVol;
210 HRESULT hres = DS_OK;
212 TRACE("(%p,%ld)\n",This,vol);
214 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
215 WARN("control unavailable: This->dsbd.dwFlags = 0x%08lx\n", This->dsbd.dwFlags);
216 return DSERR_CONTROLUNAVAIL;
219 if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN)) {
220 WARN("invalid parameter: vol = %ld\n", vol);
221 return DSERR_INVALIDPARAM;
224 /* **** */
225 EnterCriticalSection(&(This->lock));
227 if (This->dsbd.dwFlags & DSBCAPS_CTRL3D) {
228 oldVol = This->ds3db_lVolume;
229 This->ds3db_lVolume = vol;
230 } else {
231 oldVol = This->volpan.lVolume;
232 This->volpan.lVolume = vol;
233 if (vol != oldVol)
234 DSOUND_RecalcVolPan(&(This->volpan));
237 if (vol != oldVol) {
238 if (This->hwbuf) {
239 hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
240 if (hres != DS_OK)
241 WARN("IDsDriverBuffer_SetVolumePan failed\n");
242 } else
243 DSOUND_ForceRemix(This);
246 LeaveCriticalSection(&(This->lock));
247 /* **** */
249 return hres;
252 static HRESULT WINAPI IDirectSoundBufferImpl_GetVolume(
253 LPDIRECTSOUNDBUFFER8 iface,LPLONG vol
255 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
256 TRACE("(%p,%p)\n",This,vol);
258 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
259 WARN("control unavailable\n");
260 return DSERR_CONTROLUNAVAIL;
263 if (vol == NULL) {
264 WARN("invalid parameter: vol == NULL\n");
265 return DSERR_INVALIDPARAM;
268 *vol = This->volpan.lVolume;
270 return DS_OK;
273 static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency(
274 LPDIRECTSOUNDBUFFER8 iface,DWORD freq
276 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
277 DWORD oldFreq;
279 TRACE("(%p,%ld)\n",This,freq);
281 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLFREQUENCY)) {
282 WARN("control unavailable\n");
283 return DSERR_CONTROLUNAVAIL;
286 if (freq == DSBFREQUENCY_ORIGINAL)
287 freq = This->pwfx->nSamplesPerSec;
289 if ((freq < DSBFREQUENCY_MIN) || (freq > DSBFREQUENCY_MAX)) {
290 WARN("invalid parameter: freq = %ld\n", freq);
291 return DSERR_INVALIDPARAM;
294 /* **** */
295 EnterCriticalSection(&(This->lock));
297 oldFreq = This->freq;
298 This->freq = freq;
299 if (freq != oldFreq) {
300 This->freqAdjust = (freq << DSOUND_FREQSHIFT) / This->dsound->pwfx->nSamplesPerSec;
301 This->nAvgBytesPerSec = freq * This->pwfx->nBlockAlign;
302 DSOUND_RecalcFormat(This);
303 if (!This->hwbuf)
304 DSOUND_ForceRemix(This);
307 LeaveCriticalSection(&(This->lock));
308 /* **** */
310 return DS_OK;
313 static HRESULT WINAPI IDirectSoundBufferImpl_Play(
314 LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags
316 HRESULT hres = DS_OK;
317 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
318 TRACE("(%p,%08lx,%08lx,%08lx)\n",This,reserved1,reserved2,flags);
320 /* **** */
321 EnterCriticalSection(&(This->lock));
323 This->playflags = flags;
324 if (This->state == STATE_STOPPED) {
325 This->leadin = TRUE;
326 This->startpos = This->buf_mixpos;
327 This->state = STATE_STARTING;
328 } else if (This->state == STATE_STOPPING)
329 This->state = STATE_PLAYING;
330 if (This->hwbuf) {
331 hres = IDsDriverBuffer_Play(This->hwbuf, 0, 0, This->playflags);
332 if (hres != DS_OK)
333 WARN("IDsDriverBuffer_Play failed\n");
334 else
335 This->state = STATE_PLAYING;
338 LeaveCriticalSection(&(This->lock));
339 /* **** */
341 return hres;
344 static HRESULT WINAPI IDirectSoundBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface)
346 HRESULT hres = DS_OK;
347 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
348 TRACE("(%p)\n",This);
350 /* **** */
351 EnterCriticalSection(&(This->lock));
353 if (This->state == STATE_PLAYING)
354 This->state = STATE_STOPPING;
355 else if (This->state == STATE_STARTING)
356 This->state = STATE_STOPPED;
357 if (This->hwbuf) {
358 hres = IDsDriverBuffer_Stop(This->hwbuf);
359 if (hres != DS_OK)
360 WARN("IDsDriverBuffer_Stop failed\n");
361 else
362 This->state = STATE_STOPPED;
364 DSOUND_CheckEvent(This, 0);
366 LeaveCriticalSection(&(This->lock));
367 /* **** */
369 return hres;
372 static DWORD WINAPI IDirectSoundBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface) {
373 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
374 DWORD ref;
376 TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
378 ref = InterlockedIncrement(&(This->ref));
379 if (!ref) {
380 FIXME("thread-safety alert! AddRef-ing with a zero refcount!\n");
382 return ref;
385 static DWORD WINAPI IDirectSoundBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface)
387 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
388 DWORD ref;
390 TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
392 ref = InterlockedDecrement(&(This->ref));
393 if (ref) return ref;
395 DSOUND_RemoveBuffer(This->dsound, This);
397 DeleteCriticalSection(&(This->lock));
399 if (This->hwbuf) {
400 IDsDriverBuffer_Release(This->hwbuf);
401 if (This->dsound->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) {
402 This->buffer->ref--;
403 if (This->buffer->ref==0) {
404 HeapFree(GetProcessHeap(),0,This->buffer->memory);
405 HeapFree(GetProcessHeap(),0,This->buffer);
408 } else {
409 This->buffer->ref--;
410 if (This->buffer->ref==0) {
411 HeapFree(GetProcessHeap(),0,This->buffer->memory);
412 HeapFree(GetProcessHeap(),0,This->buffer);
416 if (This->notifies != NULL)
417 HeapFree(GetProcessHeap(), 0, This->notifies);
419 if (This->pwfx)
420 HeapFree(GetProcessHeap(), 0, This->pwfx);
422 HeapFree(GetProcessHeap(),0,This);
424 TRACE("(%p) released\n",This);
425 return 0;
428 DWORD DSOUND_CalcPlayPosition(IDirectSoundBufferImpl *This,
429 DWORD state, DWORD pplay, DWORD pwrite, DWORD pmix, DWORD bmix)
431 DWORD bplay;
433 TRACE("primary playpos=%ld, mixpos=%ld\n", pplay, pmix);
434 TRACE("this mixpos=%ld, time=%ld\n", bmix, GetTickCount());
436 /* the actual primary play position (pplay) is always behind last mixed (pmix),
437 * unless the computer is too slow or something */
438 /* we need to know how far away we are from there */
439 #if 0 /* we'll never fill the primary entirely */
440 if (pmix == pplay) {
441 if ((state == STATE_PLAYING) || (state == STATE_STOPPING)) {
442 /* wow, the software mixer is really doing well,
443 * seems the entire primary buffer is filled! */
444 pmix += This->dsound->buflen;
446 /* else: the primary buffer is not playing, so probably empty */
448 #endif
449 if (pmix < pplay) pmix += This->dsound->buflen; /* wraparound */
450 pmix -= pplay;
451 /* detect buffer underrun */
452 if (pwrite < pplay) pwrite += This->dsound->buflen; /* wraparound */
453 pwrite -= pplay;
454 if (pmix > (ds_snd_queue_max * This->dsound->fraglen + pwrite + This->dsound->writelead)) {
455 WARN("detected an underrun: primary queue was %ld\n",pmix);
456 pmix = 0;
458 /* divide the offset by its sample size */
459 pmix /= This->dsound->pwfx->nBlockAlign;
460 TRACE("primary back-samples=%ld\n",pmix);
461 /* adjust for our frequency */
462 pmix = (pmix * This->freqAdjust) >> DSOUND_FREQSHIFT;
463 /* multiply by our own sample size */
464 pmix *= This->pwfx->nBlockAlign;
465 TRACE("this back-offset=%ld\n", pmix);
466 /* subtract from our last mixed position */
467 bplay = bmix;
468 while (bplay < pmix) bplay += This->buflen; /* wraparound */
469 bplay -= pmix;
470 if (This->leadin && ((bplay < This->startpos) || (bplay > bmix))) {
471 /* seems we haven't started playing yet */
472 TRACE("this still in lead-in phase\n");
473 bplay = This->startpos;
475 /* return the result */
476 return bplay;
479 static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(
480 LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos
482 HRESULT hres;
483 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
484 TRACE("(%p,%p,%p)\n",This,playpos,writepos);
485 if (This->hwbuf) {
486 hres=IDsDriverBuffer_GetPosition(This->hwbuf,playpos,writepos);
487 if (hres != DS_OK) {
488 WARN("IDsDriverBuffer_GetPosition failed\n");
489 return hres;
491 } else {
492 if (playpos && (This->state != STATE_PLAYING)) {
493 /* we haven't been merged into the primary buffer (yet) */
494 *playpos = This->buf_mixpos;
495 } else if (playpos) {
496 DWORD pplay, pwrite, lplay, splay, pstate;
497 /* let's get this exact; first, recursively call GetPosition on the primary */
498 EnterCriticalSection(&(This->dsound->mixlock));
499 if (DSOUND_PrimaryGetPosition(This->dsound, &pplay, &pwrite) != DS_OK)
500 WARN("DSOUND_PrimaryGetPosition failed\n");
501 /* detect HEL mode underrun */
502 pstate = This->dsound->state;
503 if (!(This->dsound->hwbuf || This->dsound->pwqueue)) {
504 TRACE("detected an underrun\n");
505 /* pplay = ? */
506 if (pstate == STATE_PLAYING)
507 pstate = STATE_STARTING;
508 else if (pstate == STATE_STOPPING)
509 pstate = STATE_STOPPED;
511 /* get data for ourselves while we still have the lock */
512 pstate &= This->state;
513 lplay = This->primary_mixpos;
514 splay = This->buf_mixpos;
515 if ((This->dsbd.dwFlags & DSBCAPS_GETCURRENTPOSITION2) || This->dsound->hwbuf) {
516 /* calculate play position using this */
517 *playpos = DSOUND_CalcPlayPosition(This, pstate, pplay, pwrite, lplay, splay);
518 } else {
519 /* (unless the app isn't using GETCURRENTPOSITION2) */
520 /* don't know exactly how this should be handled...
521 * the docs says that play cursor is reported as directly
522 * behind write cursor, hmm... */
523 /* let's just do what might work for Half-Life */
524 DWORD wp;
525 wp = (This->dsound->pwplay + ds_hel_margin) * This->dsound->fraglen;
526 wp %= This->dsound->buflen;
527 *playpos = DSOUND_CalcPlayPosition(This, pstate, wp, pwrite, lplay, splay);
529 LeaveCriticalSection(&(This->dsound->mixlock));
531 if (writepos)
532 *writepos = This->buf_mixpos;
534 if (writepos) {
535 if (This->state != STATE_STOPPED) {
536 /* apply the documented 10ms lead to writepos */
537 *writepos += This->writelead;
539 *writepos %= This->buflen;
541 if (playpos)
542 This->last_playpos = *playpos;
543 TRACE("playpos = %ld, writepos = %ld (%p, time=%ld)\n", playpos?*playpos:0, writepos?*writepos:0, This, GetTickCount());
544 return DS_OK;
547 static HRESULT WINAPI IDirectSoundBufferImpl_GetStatus(
548 LPDIRECTSOUNDBUFFER8 iface,LPDWORD status
550 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
551 TRACE("(%p,%p), thread is %04lx\n",This,status,GetCurrentThreadId());
553 if (status == NULL) {
554 WARN("invalid parameter: status = NULL\n");
555 return DSERR_INVALIDPARAM;
558 *status = 0;
559 if ((This->state == STATE_STARTING) || (This->state == STATE_PLAYING)) {
560 *status |= DSBSTATUS_PLAYING;
561 if (This->playflags & DSBPLAY_LOOPING)
562 *status |= DSBSTATUS_LOOPING;
565 TRACE("status=%lx\n", *status);
566 return DS_OK;
570 static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat(
571 LPDIRECTSOUNDBUFFER8 iface,
572 LPWAVEFORMATEX lpwf,
573 DWORD wfsize,
574 LPDWORD wfwritten)
576 DWORD size;
577 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
578 TRACE("(%p,%p,%ld,%p)\n",This,lpwf,wfsize,wfwritten);
580 size = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;
582 if (lpwf) { /* NULL is valid */
583 if (wfsize >= size) {
584 memcpy(lpwf,This->pwfx,size);
585 if (wfwritten)
586 *wfwritten = size;
587 } else {
588 WARN("invalid parameter: wfsize to small\n");
589 if (wfwritten)
590 *wfwritten = 0;
591 return DSERR_INVALIDPARAM;
593 } else {
594 if (wfwritten)
595 *wfwritten = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;
596 else {
597 WARN("invalid parameter: wfwritten == NULL\n");
598 return DSERR_INVALIDPARAM;
602 return DS_OK;
605 static HRESULT WINAPI IDirectSoundBufferImpl_Lock(
606 LPDIRECTSOUNDBUFFER8 iface,DWORD writecursor,DWORD writebytes,LPVOID lplpaudioptr1,LPDWORD audiobytes1,LPVOID lplpaudioptr2,LPDWORD audiobytes2,DWORD flags
608 HRESULT hres = DS_OK;
609 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
611 TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx) at %ld\n",
612 This,
613 writecursor,
614 writebytes,
615 lplpaudioptr1,
616 audiobytes1,
617 lplpaudioptr2,
618 audiobytes2,
619 flags,
620 GetTickCount()
623 if (flags & DSBLOCK_FROMWRITECURSOR) {
624 DWORD writepos;
625 /* GetCurrentPosition does too much magic to duplicate here */
626 hres = IDirectSoundBufferImpl_GetCurrentPosition(iface, NULL, &writepos);
627 if (hres != DS_OK) {
628 WARN("IDirectSoundBufferImpl_GetCurrentPosition failed\n");
629 return hres;
631 writecursor += writepos;
633 writecursor %= This->buflen;
634 if (flags & DSBLOCK_ENTIREBUFFER)
635 writebytes = This->buflen;
636 if (writebytes > This->buflen)
637 writebytes = This->buflen;
639 EnterCriticalSection(&(This->lock));
641 if ((writebytes == This->buflen) &&
642 ((This->state == STATE_STARTING) ||
643 (This->state == STATE_PLAYING)))
644 /* some games, like Half-Life, try to be clever (not) and
645 * keep one secondary buffer, and mix sounds into it itself,
646 * locking the entire buffer every time... so we can just forget
647 * about tracking the last-written-to-position... */
648 This->probably_valid_to = (DWORD)-1;
649 else
650 This->probably_valid_to = writecursor;
652 if (!(This->dsound->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
653 hres = IDsDriverBuffer_Lock(This->hwbuf,
654 lplpaudioptr1, audiobytes1,
655 lplpaudioptr2, audiobytes2,
656 writecursor, writebytes,
658 if (hres != DS_OK) {
659 WARN("IDsDriverBuffer_Lock failed\n");
660 LeaveCriticalSection(&(This->lock));
661 return hres;
663 } else {
664 BOOL remix = FALSE;
665 if (writecursor+writebytes <= This->buflen) {
666 *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
667 *audiobytes1 = writebytes;
668 if (lplpaudioptr2)
669 *(LPBYTE*)lplpaudioptr2 = NULL;
670 if (audiobytes2)
671 *audiobytes2 = 0;
672 TRACE("->%ld.0\n",writebytes);
673 } else {
674 *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
675 *audiobytes1 = This->buflen-writecursor;
676 if (lplpaudioptr2)
677 *(LPBYTE*)lplpaudioptr2 = This->buffer->memory;
678 if (audiobytes2)
679 *audiobytes2 = writebytes-(This->buflen-writecursor);
680 TRACE("->%ld.%ld\n",*audiobytes1,audiobytes2?*audiobytes2:0);
682 if (This->state == STATE_PLAYING) {
683 /* if the segment between playpos and buf_mixpos is touched,
684 * we need to cancel some mixing */
685 /* we'll assume that the app always calls GetCurrentPosition before
686 * locking a playing buffer, so that last_playpos is up-to-date */
687 if (This->buf_mixpos >= This->last_playpos) {
688 if (This->buf_mixpos > writecursor &&
689 This->last_playpos < writecursor+writebytes)
690 remix = TRUE;
691 } else {
692 if (This->buf_mixpos > writecursor ||
693 This->last_playpos < writecursor+writebytes)
694 remix = TRUE;
696 if (remix) {
697 TRACE("locking prebuffered region, ouch\n");
698 DSOUND_MixCancelAt(This, writecursor);
703 LeaveCriticalSection(&(This->lock));
704 return DS_OK;
707 static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(
708 LPDIRECTSOUNDBUFFER8 iface,DWORD newpos
710 HRESULT hres = DS_OK;
711 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
712 TRACE("(%p,%ld)\n",This,newpos);
714 /* **** */
715 EnterCriticalSection(&(This->lock));
717 newpos %= This->buflen;
718 This->buf_mixpos = newpos;
719 if (This->hwbuf) {
720 hres = IDsDriverBuffer_SetPosition(This->hwbuf, This->buf_mixpos);
721 if (hres != DS_OK)
722 WARN("IDsDriverBuffer_SetPosition failed\n");
725 LeaveCriticalSection(&(This->lock));
726 /* **** */
728 return hres;
731 static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(
732 LPDIRECTSOUNDBUFFER8 iface,LONG pan
734 HRESULT hres = DS_OK;
735 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
737 TRACE("(%p,%ld)\n",This,pan);
739 if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT)) {
740 WARN("invalid parameter: pan = %ld\n", pan);
741 return DSERR_INVALIDPARAM;
744 /* You cannot use both pan and 3D controls */
745 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
746 (This->dsbd.dwFlags & DSBCAPS_CTRL3D)) {
747 WARN("control unavailable\n");
748 return DSERR_CONTROLUNAVAIL;
751 /* **** */
752 EnterCriticalSection(&(This->lock));
754 if (This->volpan.lPan != pan) {
755 This->volpan.lPan = pan;
756 DSOUND_RecalcVolPan(&(This->volpan));
758 if (This->hwbuf) {
759 hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
760 if (hres != DS_OK)
761 WARN("IDsDriverBuffer_SetVolumePan failed\n");
762 } else
763 DSOUND_ForceRemix(This);
766 LeaveCriticalSection(&(This->lock));
767 /* **** */
769 return hres;
772 static HRESULT WINAPI IDirectSoundBufferImpl_GetPan(
773 LPDIRECTSOUNDBUFFER8 iface,LPLONG pan
775 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
776 TRACE("(%p,%p)\n",This,pan);
778 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN)) {
779 WARN("control unavailable\n");
780 return DSERR_CONTROLUNAVAIL;
783 if (pan == NULL) {
784 WARN("invalid parameter: pan = NULL\n");
785 return DSERR_INVALIDPARAM;
788 *pan = This->volpan.lPan;
790 return DS_OK;
793 static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(
794 LPDIRECTSOUNDBUFFER8 iface,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2
796 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
797 DWORD probably_valid_to;
798 HRESULT hres = DS_OK;
800 TRACE("(%p,%p,%ld,%p,%ld)\n", This,p1,x1,p2,x2);
802 /* **** */
803 EnterCriticalSection(&(This->lock));
805 if (!(This->dsound->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
806 hres = IDsDriverBuffer_Unlock(This->hwbuf, p1, x1, p2, x2);
807 if (hres != DS_OK)
808 WARN("IDsDriverBuffer_Unlock failed\n");
811 if (hres == DS_OK) {
812 if (p2) probably_valid_to = (((LPBYTE)p2)-This->buffer->memory) + x2;
813 else probably_valid_to = (((LPBYTE)p1)-This->buffer->memory) + x1;
814 probably_valid_to %= This->buflen;
815 if ((probably_valid_to == 0) && ((x1+x2) == This->buflen) &&
816 ((This->state == STATE_STARTING) ||
817 (This->state == STATE_PLAYING)))
818 /* see IDirectSoundBufferImpl_Lock */
819 probably_valid_to = (DWORD)-1;
820 This->probably_valid_to = probably_valid_to;
823 LeaveCriticalSection(&(This->lock));
824 /* **** */
826 TRACE("probably_valid_to=%ld\n", This->probably_valid_to);
827 return hres;
830 static HRESULT WINAPI IDirectSoundBufferImpl_Restore(
831 LPDIRECTSOUNDBUFFER8 iface
833 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
834 FIXME("(%p):stub\n",This);
835 return DS_OK;
838 static HRESULT WINAPI IDirectSoundBufferImpl_GetFrequency(
839 LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq
841 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
842 TRACE("(%p,%p)\n",This,freq);
844 if (freq == NULL) {
845 WARN("invalid parameter: freq = NULL\n");
846 return DSERR_INVALIDPARAM;
849 *freq = This->freq;
850 TRACE("-> %ld\n", *freq);
852 return DS_OK;
855 static HRESULT WINAPI IDirectSoundBufferImpl_SetFX(
856 LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes
858 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
859 DWORD u;
861 FIXME("(%p,%lu,%p,%p): stub\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
863 if (pdwResultCodes)
864 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
866 WARN("control unavailable\n");
867 return DSERR_CONTROLUNAVAIL;
870 static HRESULT WINAPI IDirectSoundBufferImpl_AcquireResources(
871 LPDIRECTSOUNDBUFFER8 iface,DWORD dwFlags,DWORD dwEffectsCount,LPDWORD pdwResultCodes
873 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
874 DWORD u;
876 FIXME("(%p,%08lu,%lu,%p): stub\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
878 if (pdwResultCodes)
879 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
881 WARN("control unavailable\n");
882 return DSERR_CONTROLUNAVAIL;
885 static HRESULT WINAPI IDirectSoundBufferImpl_GetObjectInPath(
886 LPDIRECTSOUNDBUFFER8 iface,REFGUID rguidObject,DWORD dwIndex,REFGUID rguidInterface,LPVOID* ppObject
888 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
890 FIXME("(%p,%s,%lu,%s,%p): stub\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
892 WARN("control unavailable\n");
893 return DSERR_CONTROLUNAVAIL;
896 static HRESULT WINAPI IDirectSoundBufferImpl_Initialize(
897 LPDIRECTSOUNDBUFFER8 iface,LPDIRECTSOUND dsound,LPCDSBUFFERDESC dbsd
899 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
900 FIXME("(%p,%p,%p):stub\n",This,dsound,dbsd);
901 DPRINTF("Re-Init!!!\n");
902 WARN("already initialized\n");
903 return DSERR_ALREADYINITIALIZED;
906 static HRESULT WINAPI IDirectSoundBufferImpl_GetCaps(
907 LPDIRECTSOUNDBUFFER8 iface,LPDSBCAPS caps
909 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
910 TRACE("(%p)->(%p)\n",This,caps);
912 if (caps == NULL) {
913 WARN("invalid parameter: caps == NULL\n");
914 return DSERR_INVALIDPARAM;
917 if (caps->dwSize < sizeof(*caps)) {
918 WARN("invalid parameter: caps->dwSize = %ld < %d\n",caps->dwSize, sizeof(*caps));
919 return DSERR_INVALIDPARAM;
922 caps->dwFlags = This->dsbd.dwFlags;
923 if (This->hwbuf) caps->dwFlags |= DSBCAPS_LOCHARDWARE;
924 else caps->dwFlags |= DSBCAPS_LOCSOFTWARE;
926 caps->dwBufferBytes = This->buflen;
928 /* This value represents the speed of the "unlock" command.
929 As unlock is quite fast (it does not do anything), I put
930 4096 ko/s = 4 Mo / s */
931 /* FIXME: hwbuf speed */
932 caps->dwUnlockTransferRate = 4096;
933 caps->dwPlayCpuOverhead = 0;
935 return DS_OK;
938 static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface(
939 LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj
941 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
943 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
945 if (ppobj == NULL) {
946 WARN("invalid parameter\n");
947 return E_INVALIDARG;
950 *ppobj = NULL; /* assume failure */
952 if ( IsEqualGUID(riid, &IID_IUnknown) ||
953 IsEqualGUID(riid, &IID_IDirectSoundBuffer) ||
954 IsEqualGUID(riid, &IID_IDirectSoundBuffer8) ) {
955 if (!This->dsb)
956 SecondaryBufferImpl_Create(This, &(This->dsb));
957 if (This->dsb) {
958 IDirectSoundBuffer8_AddRef((LPDIRECTSOUNDBUFFER8)This->dsb);
959 *ppobj = This->dsb;
960 return S_OK;
962 WARN("IID_IDirectSoundBuffer\n");
963 return E_NOINTERFACE;
966 if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
967 if (!This->notify)
968 IDirectSoundNotifyImpl_Create(This, &(This->notify));
969 if (This->notify) {
970 IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify);
971 *ppobj = This->notify;
972 return S_OK;
974 WARN("IID_IDirectSoundNotify\n");
975 return E_NOINTERFACE;
978 if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) {
979 if (!This->ds3db)
980 IDirectSound3DBufferImpl_Create(This, &(This->ds3db));
981 if (This->ds3db) {
982 IDirectSound3DBuffer_AddRef((LPDIRECTSOUND3DBUFFER)This->ds3db);
983 *ppobj = This->ds3db;
984 return S_OK;
986 WARN("IID_IDirectSound3DBuffer\n");
987 return E_NOINTERFACE;
990 if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
991 ERR("app requested IDirectSound3DListener on secondary buffer\n");
992 return E_NOINTERFACE;
995 if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) {
996 /* only supported on hardware 3D secondary buffers */
997 if (!(This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER) &&
998 (This->dsbd.dwFlags & DSBCAPS_CTRL3D) &&
999 (This->hwbuf != NULL) ) {
1000 if (!This->iks)
1001 IKsBufferPropertySetImpl_Create(This, &(This->iks));
1002 if (This->iks) {
1003 IKsPropertySet_AddRef((LPKSPROPERTYSET)*ppobj);
1004 *ppobj = This->iks;
1005 return S_OK;
1008 WARN("IID_IKsPropertySet\n");
1009 return E_NOINTERFACE;
1012 FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
1014 return E_NOINTERFACE;
1017 static IDirectSoundBuffer8Vtbl dsbvt =
1019 IDirectSoundBufferImpl_QueryInterface,
1020 IDirectSoundBufferImpl_AddRef,
1021 IDirectSoundBufferImpl_Release,
1022 IDirectSoundBufferImpl_GetCaps,
1023 IDirectSoundBufferImpl_GetCurrentPosition,
1024 IDirectSoundBufferImpl_GetFormat,
1025 IDirectSoundBufferImpl_GetVolume,
1026 IDirectSoundBufferImpl_GetPan,
1027 IDirectSoundBufferImpl_GetFrequency,
1028 IDirectSoundBufferImpl_GetStatus,
1029 IDirectSoundBufferImpl_Initialize,
1030 IDirectSoundBufferImpl_Lock,
1031 IDirectSoundBufferImpl_Play,
1032 IDirectSoundBufferImpl_SetCurrentPosition,
1033 IDirectSoundBufferImpl_SetFormat,
1034 IDirectSoundBufferImpl_SetVolume,
1035 IDirectSoundBufferImpl_SetPan,
1036 IDirectSoundBufferImpl_SetFrequency,
1037 IDirectSoundBufferImpl_Stop,
1038 IDirectSoundBufferImpl_Unlock,
1039 IDirectSoundBufferImpl_Restore,
1040 IDirectSoundBufferImpl_SetFX,
1041 IDirectSoundBufferImpl_AcquireResources,
1042 IDirectSoundBufferImpl_GetObjectInPath
1045 HRESULT WINAPI IDirectSoundBufferImpl_Create(
1046 IDirectSoundImpl *ds,
1047 IDirectSoundBufferImpl **pdsb,
1048 LPCDSBUFFERDESC dsbd)
1050 IDirectSoundBufferImpl *dsb;
1051 LPWAVEFORMATEX wfex = dsbd->lpwfxFormat;
1052 HRESULT err = DS_OK;
1053 DWORD capf = 0;
1054 int use_hw, alloc_size, cp_size;
1055 TRACE("(%p,%p,%p)\n",ds,pdsb,dsbd);
1057 if (dsbd->dwBufferBytes < DSBSIZE_MIN || dsbd->dwBufferBytes > DSBSIZE_MAX) {
1058 WARN("invalid parameter: dsbd->dwBufferBytes = %ld\n", dsbd->dwBufferBytes);
1059 *pdsb = NULL;
1060 return DSERR_INVALIDPARAM; /* FIXME: which error? */
1063 dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
1065 if (dsb == 0) {
1066 WARN("out of memory\n");
1067 *pdsb = NULL;
1068 return DSERR_OUTOFMEMORY;
1071 TRACE("Created buffer at %p\n", dsb);
1073 dsb->ref = 0;
1074 dsb->dsb = 0;
1075 dsb->dsound = ds;
1076 dsb->lpVtbl = &dsbvt;
1077 dsb->iks = NULL;
1079 /* size depends on version */
1080 memcpy(&dsb->dsbd, dsbd, dsbd->dwSize);
1082 /* variable sized struct so calculate size based on format */
1083 if (wfex->wFormatTag == WAVE_FORMAT_PCM) {
1084 alloc_size = sizeof(WAVEFORMATEX);
1085 cp_size = sizeof(PCMWAVEFORMAT);
1086 } else
1087 alloc_size = cp_size = sizeof(WAVEFORMATEX) + wfex->cbSize;
1089 dsb->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,alloc_size);
1090 if (dsb->pwfx == NULL) {
1091 WARN("out of memory\n");
1092 HeapFree(GetProcessHeap(),0,dsb);
1093 *pdsb = NULL;
1094 return DSERR_OUTOFMEMORY;
1097 memcpy(dsb->pwfx, wfex, cp_size);
1099 dsb->buflen = dsbd->dwBufferBytes;
1100 dsb->freq = dsbd->lpwfxFormat->nSamplesPerSec;
1102 dsb->notify = NULL;
1103 dsb->notifies = NULL;
1104 dsb->nrofnotifies = 0;
1105 dsb->hwnotify = 0;
1107 /* Check necessary hardware mixing capabilities */
1108 if (wfex->nChannels==2) capf |= DSCAPS_SECONDARYSTEREO;
1109 else capf |= DSCAPS_SECONDARYMONO;
1110 if (wfex->wBitsPerSample==16) capf |= DSCAPS_SECONDARY16BIT;
1111 else capf |= DSCAPS_SECONDARY8BIT;
1113 use_hw = (ds->drvcaps.dwFlags & capf) == capf;
1114 TRACE("use_hw = 0x%08x, capf = 0x%08lx, ds->drvcaps.dwFlags = 0x%08lx\n", use_hw, capf, ds->drvcaps.dwFlags);
1116 /* FIXME: check hardware sample rate mixing capabilities */
1117 /* FIXME: check app hints for software/hardware buffer (STATIC, LOCHARDWARE, etc) */
1118 /* FIXME: check whether any hardware buffers are left */
1119 /* FIXME: handle DSDHEAP_CREATEHEAP for hardware buffers */
1121 /* Allocate system memory if applicable */
1122 if ((ds->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) || !use_hw) {
1123 dsb->buffer = HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb->buffer)));
1124 if (dsb->buffer == NULL) {
1125 WARN("out of memory\n");
1126 HeapFree(GetProcessHeap(),0,dsb->pwfx);
1127 HeapFree(GetProcessHeap(),0,dsb);
1128 *pdsb = NULL;
1129 return DSERR_OUTOFMEMORY;
1132 dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen);
1133 if (dsb->buffer->memory == NULL) {
1134 WARN("out of memory\n");
1135 HeapFree(GetProcessHeap(),0,dsb->pwfx);
1136 HeapFree(GetProcessHeap(),0,dsb->buffer);
1137 HeapFree(GetProcessHeap(),0,dsb);
1138 *pdsb = NULL;
1139 return DSERR_OUTOFMEMORY;
1141 dsb->buffer->ref = 1;
1144 /* Allocate the hardware buffer */
1145 if (use_hw) {
1146 err = IDsDriver_CreateSoundBuffer(ds->driver,wfex,dsbd->dwFlags,0,
1147 &(dsb->buflen),&(dsb->buffer->memory),
1148 (LPVOID*)&(dsb->hwbuf));
1149 /* fall back to software buffer on failure */
1150 if (err != DS_OK) {
1151 TRACE("IDsDriver_CreateSoundBuffer failed, falling back to software buffer\n");
1152 use_hw = 0;
1153 if (ds->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) {
1154 dsb->buffer = HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb->buffer)));
1155 if (dsb->buffer == NULL) {
1156 WARN("out of memory\n");
1157 HeapFree(GetProcessHeap(),0,dsb->pwfx);
1158 HeapFree(GetProcessHeap(),0,dsb);
1159 *pdsb = NULL;
1160 return DSERR_OUTOFMEMORY;
1163 dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen);
1164 if (dsb->buffer->memory == NULL) {
1165 WARN("out of memory\n");
1166 HeapFree(GetProcessHeap(),0,dsb->buffer);
1167 HeapFree(GetProcessHeap(),0,dsb->pwfx);
1168 HeapFree(GetProcessHeap(),0,dsb);
1169 *pdsb = NULL;
1170 return DSERR_OUTOFMEMORY;
1172 dsb->buffer->ref = 1;
1174 err = DS_OK;
1178 /* calculate fragment size and write lead */
1179 DSOUND_RecalcFormat(dsb);
1181 /* It's not necessary to initialize values to zero since */
1182 /* we allocated this structure with HEAP_ZERO_MEMORY... */
1183 dsb->playpos = 0;
1184 dsb->buf_mixpos = 0;
1185 dsb->state = STATE_STOPPED;
1187 dsb->freqAdjust = (dsb->freq << DSOUND_FREQSHIFT) /
1188 ds->pwfx->nSamplesPerSec;
1189 dsb->nAvgBytesPerSec = dsb->freq *
1190 dsbd->lpwfxFormat->nBlockAlign;
1192 if (dsb->dsbd.dwFlags & DSBCAPS_CTRL3D) {
1193 dsb->ds3db_ds3db.dwSize = sizeof(DS3DBUFFER);
1194 dsb->ds3db_ds3db.vPosition.x = 0.0;
1195 dsb->ds3db_ds3db.vPosition.y = 0.0;
1196 dsb->ds3db_ds3db.vPosition.z = 0.0;
1197 dsb->ds3db_ds3db.vVelocity.x = 0.0;
1198 dsb->ds3db_ds3db.vVelocity.y = 0.0;
1199 dsb->ds3db_ds3db.vVelocity.z = 0.0;
1200 dsb->ds3db_ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
1201 dsb->ds3db_ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
1202 dsb->ds3db_ds3db.vConeOrientation.x = 0.0;
1203 dsb->ds3db_ds3db.vConeOrientation.y = 0.0;
1204 dsb->ds3db_ds3db.vConeOrientation.z = 0.0;
1205 dsb->ds3db_ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
1206 dsb->ds3db_ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE;
1207 dsb->ds3db_ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
1208 dsb->ds3db_ds3db.dwMode = DS3DMODE_NORMAL;
1210 dsb->ds3db_need_recalc = FALSE;
1211 DSOUND_Calc3DBuffer(dsb);
1212 } else
1213 DSOUND_RecalcVolPan(&(dsb->volpan));
1215 InitializeCriticalSection(&(dsb->lock));
1216 dsb->lock.DebugInfo->Spare[1] = (DWORD)"DSOUNDBUFFER_lock";
1218 /* register buffer if not primary */
1219 if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
1220 err = DSOUND_AddBuffer(ds, dsb);
1221 if (err != DS_OK) {
1222 if (dsb->buffer->memory)
1223 HeapFree(GetProcessHeap(),0,dsb->buffer->memory);
1224 if (dsb->buffer)
1225 HeapFree(GetProcessHeap(),0,dsb->buffer);
1226 DeleteCriticalSection(&(dsb->lock));
1227 HeapFree(GetProcessHeap(),0,dsb->pwfx);
1228 HeapFree(GetProcessHeap(),0,dsb);
1229 dsb = NULL;
1233 *pdsb = dsb;
1234 return err;
1237 HRESULT WINAPI IDirectSoundBufferImpl_Destroy(
1238 IDirectSoundBufferImpl *pdsb)
1240 TRACE("(%p)\n",pdsb);
1242 /* This keeps the *_Destroy functions from possibly deleting
1243 * this object until it is ready to be deleted */
1244 IDirectSoundBufferImpl_AddRef((LPDIRECTSOUNDBUFFER8)pdsb);
1246 if (pdsb->iks) {
1247 WARN("iks not NULL\n");
1248 IKsBufferPropertySetImpl_Destroy(pdsb->iks);
1249 pdsb->iks = NULL;
1252 if (pdsb->ds3db) {
1253 WARN("ds3db not NULL\n");
1254 IDirectSound3DBufferImpl_Destroy(pdsb->ds3db);
1255 pdsb->ds3db = NULL;
1258 if (pdsb->notify) {
1259 WARN("notify not NULL\n");
1260 IDirectSoundNotifyImpl_Destroy(pdsb->notify);
1261 pdsb->notify = NULL;
1264 if (pdsb->dsb) {
1265 WARN("dsb not NULL\n");
1266 SecondaryBufferImpl_Destroy(pdsb->dsb);
1267 pdsb->dsb = NULL;
1270 while (IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)pdsb) > 0);
1272 return S_OK;
1275 /*******************************************************************************
1276 * SecondaryBuffer
1279 static HRESULT WINAPI SecondaryBufferImpl_QueryInterface(
1280 LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj)
1282 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1283 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
1285 return IDirectSoundBufferImpl_QueryInterface((LPDIRECTSOUNDBUFFER8)This->dsb,riid,ppobj);
1288 static DWORD WINAPI SecondaryBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface)
1290 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
1291 DWORD ref;
1292 TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
1294 ref = InterlockedIncrement(&(This->ref));
1295 if (!ref) {
1296 FIXME("thread-safety alert! AddRef-ing with a zero refcount!\n");
1298 return ref;
1301 static DWORD WINAPI SecondaryBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface)
1303 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
1304 DWORD ref;
1305 TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
1307 ref = InterlockedDecrement(&(This->ref));
1308 if (!ref) {
1309 This->dsb->dsb = NULL;
1310 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER8)This->dsb);
1311 HeapFree(GetProcessHeap(),0,This);
1312 TRACE("(%p) released\n",This);
1314 return ref;
1317 static HRESULT WINAPI SecondaryBufferImpl_GetCaps(
1318 LPDIRECTSOUNDBUFFER8 iface,LPDSBCAPS caps)
1320 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1321 TRACE("(%p)->(%p)\n",This,caps);
1323 return IDirectSoundBufferImpl_GetCaps((LPDIRECTSOUNDBUFFER8)This->dsb,caps);
1326 static HRESULT WINAPI SecondaryBufferImpl_GetCurrentPosition(
1327 LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos)
1329 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1330 TRACE("(%p,%p,%p)\n",This,playpos,writepos);
1332 return IDirectSoundBufferImpl_GetCurrentPosition((LPDIRECTSOUNDBUFFER8)This->dsb,playpos,writepos);
1335 static HRESULT WINAPI SecondaryBufferImpl_GetFormat(
1336 LPDIRECTSOUNDBUFFER8 iface,LPWAVEFORMATEX lpwf,DWORD wfsize,LPDWORD wfwritten)
1338 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1339 TRACE("(%p,%p,%ld,%p)\n",This,lpwf,wfsize,wfwritten);
1341 return IDirectSoundBufferImpl_GetFormat((LPDIRECTSOUNDBUFFER8)This->dsb,lpwf,wfsize,wfwritten);
1344 static HRESULT WINAPI SecondaryBufferImpl_GetVolume(
1345 LPDIRECTSOUNDBUFFER8 iface,LPLONG vol)
1347 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1348 TRACE("(%p,%p)\n",This,vol);
1350 return IDirectSoundBufferImpl_GetVolume((LPDIRECTSOUNDBUFFER8)This->dsb,vol);
1353 static HRESULT WINAPI SecondaryBufferImpl_GetPan(
1354 LPDIRECTSOUNDBUFFER8 iface,LPLONG pan)
1356 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1357 TRACE("(%p,%p)\n",This,pan);
1359 return IDirectSoundBufferImpl_GetPan((LPDIRECTSOUNDBUFFER8)This->dsb,pan);
1362 static HRESULT WINAPI SecondaryBufferImpl_GetFrequency(
1363 LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq)
1365 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1366 TRACE("(%p,%p)\n",This,freq);
1368 return IDirectSoundBufferImpl_GetFrequency((LPDIRECTSOUNDBUFFER8)This->dsb,freq);
1371 static HRESULT WINAPI SecondaryBufferImpl_GetStatus(
1372 LPDIRECTSOUNDBUFFER8 iface,LPDWORD status)
1374 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1375 TRACE("(%p,%p)\n",This,status);
1377 return IDirectSoundBufferImpl_GetStatus((LPDIRECTSOUNDBUFFER8)This->dsb,status);
1380 static HRESULT WINAPI SecondaryBufferImpl_Initialize(
1381 LPDIRECTSOUNDBUFFER8 iface,LPDIRECTSOUND dsound,LPCDSBUFFERDESC dbsd)
1383 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1384 TRACE("(%p,%p,%p)\n",This,dsound,dbsd);
1386 return IDirectSoundBufferImpl_Initialize((LPDIRECTSOUNDBUFFER8)This->dsb,dsound,dbsd);
1389 static HRESULT WINAPI SecondaryBufferImpl_Lock(
1390 LPDIRECTSOUNDBUFFER8 iface,
1391 DWORD writecursor,
1392 DWORD writebytes,
1393 LPVOID lplpaudioptr1,
1394 LPDWORD audiobytes1,
1395 LPVOID lplpaudioptr2,
1396 LPDWORD audiobytes2,
1397 DWORD dwFlags)
1399 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1400 TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx)\n",
1401 This,writecursor,writebytes,lplpaudioptr1,audiobytes1,lplpaudioptr2,audiobytes2,dwFlags);
1403 return IDirectSoundBufferImpl_Lock((LPDIRECTSOUNDBUFFER8)This->dsb,
1404 writecursor,writebytes,lplpaudioptr1,audiobytes1,lplpaudioptr2,audiobytes2,dwFlags);
1407 static HRESULT WINAPI SecondaryBufferImpl_Play(
1408 LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags)
1410 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1411 TRACE("(%p,%08lx,%08lx,%08lx)\n",This,reserved1,reserved2,flags);
1413 return IDirectSoundBufferImpl_Play((LPDIRECTSOUNDBUFFER8)This->dsb,reserved1,reserved2,flags);
1416 static HRESULT WINAPI SecondaryBufferImpl_SetCurrentPosition(
1417 LPDIRECTSOUNDBUFFER8 iface,DWORD newpos)
1419 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1420 TRACE("(%p,%ld)\n",This,newpos);
1422 return IDirectSoundBufferImpl_SetCurrentPosition((LPDIRECTSOUNDBUFFER8)This->dsb,newpos);
1425 static HRESULT WINAPI SecondaryBufferImpl_SetFormat(
1426 LPDIRECTSOUNDBUFFER8 iface,LPCWAVEFORMATEX wfex)
1428 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1429 TRACE("(%p,%p)\n",This,wfex);
1431 return IDirectSoundBufferImpl_SetFormat((LPDIRECTSOUNDBUFFER8)This->dsb,wfex);
1434 static HRESULT WINAPI SecondaryBufferImpl_SetVolume(
1435 LPDIRECTSOUNDBUFFER8 iface,LONG vol)
1437 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1438 TRACE("(%p,%ld)\n",This,vol);
1440 return IDirectSoundBufferImpl_SetVolume((LPDIRECTSOUNDBUFFER8)This->dsb,vol);
1443 static HRESULT WINAPI SecondaryBufferImpl_SetPan(
1444 LPDIRECTSOUNDBUFFER8 iface,LONG pan)
1446 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1447 TRACE("(%p,%ld)\n",This,pan);
1449 return IDirectSoundBufferImpl_SetPan((LPDIRECTSOUNDBUFFER8)This->dsb,pan);
1452 static HRESULT WINAPI SecondaryBufferImpl_SetFrequency(
1453 LPDIRECTSOUNDBUFFER8 iface,DWORD freq)
1455 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1456 TRACE("(%p,%ld)\n",This,freq);
1458 return IDirectSoundBufferImpl_SetFrequency((LPDIRECTSOUNDBUFFER8)This->dsb,freq);
1461 static HRESULT WINAPI SecondaryBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface)
1463 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1464 TRACE("(%p)\n",This);
1466 return IDirectSoundBufferImpl_Stop((LPDIRECTSOUNDBUFFER8)This->dsb);
1469 static HRESULT WINAPI SecondaryBufferImpl_Unlock(
1470 LPDIRECTSOUNDBUFFER8 iface,
1471 LPVOID lpvAudioPtr1,
1472 DWORD dwAudioBytes1,
1473 LPVOID lpvAudioPtr2,
1474 DWORD dwAudioBytes2)
1476 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1477 TRACE("(%p,%p,%ld,%p,%ld)\n",
1478 This, lpvAudioPtr1, dwAudioBytes1, lpvAudioPtr2, dwAudioBytes2);
1480 return IDirectSoundBufferImpl_Unlock((LPDIRECTSOUNDBUFFER8)This->dsb,
1481 lpvAudioPtr1,dwAudioBytes1,lpvAudioPtr2,dwAudioBytes2);
1484 static HRESULT WINAPI SecondaryBufferImpl_Restore(
1485 LPDIRECTSOUNDBUFFER8 iface)
1487 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1488 TRACE("(%p)\n",This);
1490 return IDirectSoundBufferImpl_Restore((LPDIRECTSOUNDBUFFER8)This->dsb);
1493 static HRESULT WINAPI SecondaryBufferImpl_SetFX(
1494 LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes)
1496 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1497 TRACE("(%p,%lu,%p,%p)\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
1499 return IDirectSoundBufferImpl_SetFX((LPDIRECTSOUNDBUFFER8)This->dsb,dwEffectsCount,pDSFXDesc,pdwResultCodes);
1502 static HRESULT WINAPI SecondaryBufferImpl_AcquireResources(
1503 LPDIRECTSOUNDBUFFER8 iface,DWORD dwFlags,DWORD dwEffectsCount,LPDWORD pdwResultCodes)
1505 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1506 TRACE("(%p,%08lu,%lu,%p)\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
1508 return IDirectSoundBufferImpl_AcquireResources((LPDIRECTSOUNDBUFFER8)This->dsb,dwFlags,dwEffectsCount,pdwResultCodes);
1511 static HRESULT WINAPI SecondaryBufferImpl_GetObjectInPath(
1512 LPDIRECTSOUNDBUFFER8 iface,REFGUID rguidObject,DWORD dwIndex,REFGUID rguidInterface,LPVOID* ppObject)
1514 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1515 TRACE("(%p,%s,%lu,%s,%p)\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
1517 return IDirectSoundBufferImpl_GetObjectInPath((LPDIRECTSOUNDBUFFER8)This->dsb,rguidObject,dwIndex,rguidInterface,ppObject);
1520 static IDirectSoundBuffer8Vtbl sbvt =
1522 SecondaryBufferImpl_QueryInterface,
1523 SecondaryBufferImpl_AddRef,
1524 SecondaryBufferImpl_Release,
1525 SecondaryBufferImpl_GetCaps,
1526 SecondaryBufferImpl_GetCurrentPosition,
1527 SecondaryBufferImpl_GetFormat,
1528 SecondaryBufferImpl_GetVolume,
1529 SecondaryBufferImpl_GetPan,
1530 SecondaryBufferImpl_GetFrequency,
1531 SecondaryBufferImpl_GetStatus,
1532 SecondaryBufferImpl_Initialize,
1533 SecondaryBufferImpl_Lock,
1534 SecondaryBufferImpl_Play,
1535 SecondaryBufferImpl_SetCurrentPosition,
1536 SecondaryBufferImpl_SetFormat,
1537 SecondaryBufferImpl_SetVolume,
1538 SecondaryBufferImpl_SetPan,
1539 SecondaryBufferImpl_SetFrequency,
1540 SecondaryBufferImpl_Stop,
1541 SecondaryBufferImpl_Unlock,
1542 SecondaryBufferImpl_Restore,
1543 SecondaryBufferImpl_SetFX,
1544 SecondaryBufferImpl_AcquireResources,
1545 SecondaryBufferImpl_GetObjectInPath
1548 HRESULT WINAPI SecondaryBufferImpl_Create(
1549 IDirectSoundBufferImpl *dsb,
1550 SecondaryBufferImpl **psb)
1552 SecondaryBufferImpl *sb;
1553 TRACE("(%p,%p)\n",dsb,psb);
1555 sb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*sb));
1557 if (sb == 0) {
1558 WARN("out of memory\n");
1559 *psb = NULL;
1560 return DSERR_OUTOFMEMORY;
1562 sb->ref = 0;
1563 sb->dsb = dsb;
1564 sb->lpVtbl = &sbvt;
1566 IDirectSoundBuffer8_AddRef((LPDIRECTSOUNDBUFFER8)dsb);
1567 *psb = sb;
1568 return S_OK;
1571 HRESULT WINAPI SecondaryBufferImpl_Destroy(
1572 SecondaryBufferImpl *pdsb)
1574 TRACE("(%p)\n",pdsb);
1576 while (SecondaryBufferImpl_Release((LPDIRECTSOUNDBUFFER8)pdsb) > 0);
1578 return S_OK;