Fallback to software buffer if failed to create hardware buffer.
[wine/gsoc_dplay.git] / dlls / dsound / buffer.c
blob4c55e25343c11f76a12e41c764fbdb51573ed51c
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 ICOM_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 ICOM_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 ICOM_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 ICOM_THIS(IDirectSoundNotifyImpl,iface);
101 TRACE("(%p,0x%08lx,%p)\n",This,howmuch,notify);
103 if (notify == NULL) {
104 WARN("invalid parameter: notify == NULL\n");
105 return DSERR_INVALIDPARAM;
108 if (TRACE_ON(dsound)) {
109 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 {
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;
139 return S_OK;
142 ICOM_VTABLE(IDirectSoundNotify) dsnvt =
144 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
145 IDirectSoundNotifyImpl_QueryInterface,
146 IDirectSoundNotifyImpl_AddRef,
147 IDirectSoundNotifyImpl_Release,
148 IDirectSoundNotifyImpl_SetNotificationPositions,
151 HRESULT WINAPI IDirectSoundNotifyImpl_Create(
152 IDirectSoundBufferImpl * dsb,
153 IDirectSoundNotifyImpl **pdsn)
155 IDirectSoundNotifyImpl * dsn;
156 TRACE("(%p,%p)\n",dsb,pdsn);
158 dsn = (IDirectSoundNotifyImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dsn));
160 if (dsn == NULL) {
161 WARN("out of memory\n");
162 return DSERR_OUTOFMEMORY;
165 dsn->ref = 0;
166 dsn->lpVtbl = &dsnvt;
167 dsn->dsb = dsb;
168 dsb->notify = dsn;
169 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)dsb);
171 *pdsn = dsn;
172 return DS_OK;
175 /*******************************************************************************
176 * IDirectSoundBuffer
179 static HRESULT WINAPI IDirectSoundBufferImpl_SetFormat(
180 LPDIRECTSOUNDBUFFER8 iface,LPCWAVEFORMATEX wfex
182 ICOM_THIS(IDirectSoundBufferImpl,iface);
184 TRACE("(%p,%p)\n",This,wfex);
185 /* This method is not available on secondary buffers */
186 WARN("invalid call\n");
187 return DSERR_INVALIDCALL;
190 static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume(
191 LPDIRECTSOUNDBUFFER8 iface,LONG vol
193 ICOM_THIS(IDirectSoundBufferImpl,iface);
194 LONG oldVol;
196 TRACE("(%p,%ld)\n",This,vol);
198 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
199 WARN("control unavailable: This->dsbd.dwFlags = 0x%08lx\n", This->dsbd.dwFlags);
200 return DSERR_CONTROLUNAVAIL;
203 if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN)) {
204 WARN("invalid parameter: vol = %ld\n", vol);
205 return DSERR_INVALIDPARAM;
208 /* **** */
209 EnterCriticalSection(&(This->lock));
211 if (This->dsbd.dwFlags & DSBCAPS_CTRL3D) {
212 oldVol = This->ds3db_lVolume;
213 This->ds3db_lVolume = vol;
214 } else {
215 oldVol = This->volpan.lVolume;
216 This->volpan.lVolume = vol;
217 if (vol != oldVol)
218 DSOUND_RecalcVolPan(&(This->volpan));
221 if (vol != oldVol) {
222 if (This->hwbuf) {
223 HRESULT hres;
224 hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
225 if (hres != DS_OK)
226 WARN("IDsDriverBuffer_SetVolumePan failed\n");
227 } else
228 DSOUND_ForceRemix(This);
231 LeaveCriticalSection(&(This->lock));
232 /* **** */
234 return DS_OK;
237 static HRESULT WINAPI IDirectSoundBufferImpl_GetVolume(
238 LPDIRECTSOUNDBUFFER8 iface,LPLONG vol
240 ICOM_THIS(IDirectSoundBufferImpl,iface);
241 TRACE("(%p,%p)\n",This,vol);
243 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
244 WARN("control unavailable\n");
245 return DSERR_CONTROLUNAVAIL;
248 if (vol == NULL) {
249 WARN("invalid parameter: vol == NULL\n");
250 return DSERR_INVALIDPARAM;
253 *vol = This->volpan.lVolume;
255 return DS_OK;
258 static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency(
259 LPDIRECTSOUNDBUFFER8 iface,DWORD freq
261 ICOM_THIS(IDirectSoundBufferImpl,iface);
262 DWORD oldFreq;
264 TRACE("(%p,%ld)\n",This,freq);
266 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLFREQUENCY)) {
267 WARN("control unavailable\n");
268 return DSERR_CONTROLUNAVAIL;
271 if (freq == DSBFREQUENCY_ORIGINAL)
272 freq = This->wfx.nSamplesPerSec;
274 if ((freq < DSBFREQUENCY_MIN) || (freq > DSBFREQUENCY_MAX)) {
275 WARN("invalid parameter: freq = %ld\n", freq);
276 return DSERR_INVALIDPARAM;
279 /* **** */
280 EnterCriticalSection(&(This->lock));
282 oldFreq = This->freq;
283 This->freq = freq;
284 if (freq != oldFreq) {
285 This->freqAdjust = (freq << DSOUND_FREQSHIFT) / This->dsound->wfx.nSamplesPerSec;
286 This->nAvgBytesPerSec = freq * This->wfx.nBlockAlign;
287 DSOUND_RecalcFormat(This);
288 if (!This->hwbuf)
289 DSOUND_ForceRemix(This);
292 LeaveCriticalSection(&(This->lock));
293 /* **** */
295 return DS_OK;
298 static HRESULT WINAPI IDirectSoundBufferImpl_Play(
299 LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags
301 HRESULT hres = DS_OK;
302 ICOM_THIS(IDirectSoundBufferImpl,iface);
303 TRACE("(%p,%08lx,%08lx,%08lx)\n",This,reserved1,reserved2,flags);
305 /* **** */
306 EnterCriticalSection(&(This->lock));
308 This->playflags = flags;
309 if (This->state == STATE_STOPPED) {
310 This->leadin = TRUE;
311 This->startpos = This->buf_mixpos;
312 This->state = STATE_STARTING;
313 } else if (This->state == STATE_STOPPING)
314 This->state = STATE_PLAYING;
315 if (This->hwbuf) {
316 hres = IDsDriverBuffer_Play(This->hwbuf, 0, 0, This->playflags);
317 if (hres != DS_OK)
318 WARN("IDsDriverBuffer_Play failed\n");
319 else
320 This->state = STATE_PLAYING;
323 LeaveCriticalSection(&(This->lock));
324 /* **** */
326 return hres;
329 static HRESULT WINAPI IDirectSoundBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface)
331 HRESULT hres = DS_OK;
332 ICOM_THIS(IDirectSoundBufferImpl,iface);
333 TRACE("(%p)\n",This);
335 /* **** */
336 EnterCriticalSection(&(This->lock));
338 if (This->state == STATE_PLAYING)
339 This->state = STATE_STOPPING;
340 else if (This->state == STATE_STARTING)
341 This->state = STATE_STOPPED;
342 if (This->hwbuf) {
343 hres = IDsDriverBuffer_Stop(This->hwbuf);
344 if (hres != DS_OK)
345 WARN("IDsDriverBuffer_Stop failed\n");
346 else
347 This->state = STATE_STOPPED;
349 DSOUND_CheckEvent(This, 0);
351 LeaveCriticalSection(&(This->lock));
352 /* **** */
354 return hres;
357 static DWORD WINAPI IDirectSoundBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface) {
358 ICOM_THIS(IDirectSoundBufferImpl,iface);
359 DWORD ref;
361 TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
363 ref = InterlockedIncrement(&(This->ref));
364 if (!ref) {
365 FIXME("thread-safety alert! AddRef-ing with a zero refcount!\n");
367 return ref;
370 static DWORD WINAPI IDirectSoundBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface) {
371 ICOM_THIS(IDirectSoundBufferImpl,iface);
372 int i;
373 DWORD ref;
375 TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
377 ref = InterlockedDecrement(&(This->ref));
378 if (ref) return ref;
380 RtlAcquireResourceExclusive(&(This->dsound->lock), TRUE);
381 for (i=0;i<This->dsound->nrofbuffers;i++)
382 if (This->dsound->buffers[i] == This)
383 break;
384 if (i < This->dsound->nrofbuffers) {
385 /* Put the last buffer of the list in the (now empty) position */
386 This->dsound->buffers[i] = This->dsound->buffers[This->dsound->nrofbuffers - 1];
387 This->dsound->nrofbuffers--;
388 This->dsound->buffers = HeapReAlloc(GetProcessHeap(),0,This->dsound->buffers,sizeof(LPDIRECTSOUNDBUFFER8)*This->dsound->nrofbuffers);
389 TRACE("(%p) buffer count is now %d\n", This, This->dsound->nrofbuffers);
390 IDirectSound_Release((LPDIRECTSOUND)This->dsound);
392 RtlReleaseResource(&(This->dsound->lock));
394 DeleteCriticalSection(&(This->lock));
396 if (This->hwbuf) {
397 IDsDriverBuffer_Release(This->hwbuf);
398 if (This->dsound->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) {
399 This->buffer->ref--;
400 if (This->buffer->ref==0) {
401 HeapFree(GetProcessHeap(),0,This->buffer->memory);
402 HeapFree(GetProcessHeap(),0,This->buffer);
405 } else {
406 This->buffer->ref--;
407 if (This->buffer->ref==0) {
408 HeapFree(GetProcessHeap(),0,This->buffer->memory);
409 HeapFree(GetProcessHeap(),0,This->buffer);
413 if (This->notifies != NULL)
414 HeapFree(GetProcessHeap(), 0, This->notifies);
416 HeapFree(GetProcessHeap(),0,This);
418 TRACE("(%p) released\n",This);
419 return 0;
422 DWORD DSOUND_CalcPlayPosition(IDirectSoundBufferImpl *This,
423 DWORD state, DWORD pplay, DWORD pwrite, DWORD pmix, DWORD bmix)
425 DWORD bplay;
427 TRACE("primary playpos=%ld, mixpos=%ld\n", pplay, pmix);
428 TRACE("this mixpos=%ld, time=%ld\n", bmix, GetTickCount());
430 /* the actual primary play position (pplay) is always behind last mixed (pmix),
431 * unless the computer is too slow or something */
432 /* we need to know how far away we are from there */
433 #if 0 /* we'll never fill the primary entirely */
434 if (pmix == pplay) {
435 if ((state == STATE_PLAYING) || (state == STATE_STOPPING)) {
436 /* wow, the software mixer is really doing well,
437 * seems the entire primary buffer is filled! */
438 pmix += This->dsound->buflen;
440 /* else: the primary buffer is not playing, so probably empty */
442 #endif
443 if (pmix < pplay) pmix += This->dsound->buflen; /* wraparound */
444 pmix -= pplay;
445 /* detect buffer underrun */
446 if (pwrite < pplay) pwrite += This->dsound->buflen; /* wraparound */
447 pwrite -= pplay;
448 if (pmix > (ds_snd_queue_max * This->dsound->fraglen + pwrite + This->dsound->writelead)) {
449 WARN("detected an underrun: primary queue was %ld\n",pmix);
450 pmix = 0;
452 /* divide the offset by its sample size */
453 pmix /= This->dsound->wfx.nBlockAlign;
454 TRACE("primary back-samples=%ld\n",pmix);
455 /* adjust for our frequency */
456 pmix = (pmix * This->freqAdjust) >> DSOUND_FREQSHIFT;
457 /* multiply by our own sample size */
458 pmix *= This->wfx.nBlockAlign;
459 TRACE("this back-offset=%ld\n", pmix);
460 /* subtract from our last mixed position */
461 bplay = bmix;
462 while (bplay < pmix) bplay += This->buflen; /* wraparound */
463 bplay -= pmix;
464 if (This->leadin && ((bplay < This->startpos) || (bplay > bmix))) {
465 /* seems we haven't started playing yet */
466 TRACE("this still in lead-in phase\n");
467 bplay = This->startpos;
469 /* return the result */
470 return bplay;
473 static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(
474 LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos
476 HRESULT hres;
477 ICOM_THIS(IDirectSoundBufferImpl,iface);
478 TRACE("(%p,%p,%p)\n",This,playpos,writepos);
479 if (This->hwbuf) {
480 hres=IDsDriverBuffer_GetPosition(This->hwbuf,playpos,writepos);
481 if (hres != DS_OK) {
482 WARN("IDsDriverBuffer_GetPosition failed\n");
483 return hres;
486 else {
487 if (playpos && (This->state != STATE_PLAYING)) {
488 /* we haven't been merged into the primary buffer (yet) */
489 *playpos = This->buf_mixpos;
491 else if (playpos) {
492 DWORD pplay, pwrite, lplay, splay, pstate;
493 /* let's get this exact; first, recursively call GetPosition on the primary */
494 EnterCriticalSection(&(This->dsound->mixlock));
495 if (DSOUND_PrimaryGetPosition(This->dsound, &pplay, &pwrite) != DS_OK)
496 WARN("DSOUND_PrimaryGetPosition failed\n");
497 /* detect HEL mode underrun */
498 pstate = This->dsound->state;
499 if (!(This->dsound->hwbuf || This->dsound->pwqueue)) {
500 TRACE("detected an underrun\n");
501 /* pplay = ? */
502 if (pstate == STATE_PLAYING)
503 pstate = STATE_STARTING;
504 else if (pstate == STATE_STOPPING)
505 pstate = STATE_STOPPED;
507 /* get data for ourselves while we still have the lock */
508 pstate &= This->state;
509 lplay = This->primary_mixpos;
510 splay = This->buf_mixpos;
511 if ((This->dsbd.dwFlags & DSBCAPS_GETCURRENTPOSITION2) || This->dsound->hwbuf) {
512 /* calculate play position using this */
513 *playpos = DSOUND_CalcPlayPosition(This, pstate, pplay, pwrite, lplay, splay);
514 } else {
515 /* (unless the app isn't using GETCURRENTPOSITION2) */
516 /* don't know exactly how this should be handled...
517 * the docs says that play cursor is reported as directly
518 * behind write cursor, hmm... */
519 /* let's just do what might work for Half-Life */
520 DWORD wp;
521 wp = (This->dsound->pwplay + ds_hel_margin) * This->dsound->fraglen;
522 while (wp >= This->dsound->buflen)
523 wp -= This->dsound->buflen;
524 *playpos = DSOUND_CalcPlayPosition(This, pstate, wp, pwrite, lplay, splay);
526 LeaveCriticalSection(&(This->dsound->mixlock));
528 if (writepos) *writepos = This->buf_mixpos;
530 if (writepos) {
531 if (This->state != STATE_STOPPED)
532 /* apply the documented 10ms lead to writepos */
533 *writepos += This->writelead;
534 while (*writepos >= This->buflen) *writepos -= This->buflen;
536 if (playpos) This->last_playpos = *playpos;
537 TRACE("playpos = %ld, writepos = %ld (%p, time=%ld)\n", playpos?*playpos:0, writepos?*writepos:0, This, GetTickCount());
538 return DS_OK;
541 static HRESULT WINAPI IDirectSoundBufferImpl_GetStatus(
542 LPDIRECTSOUNDBUFFER8 iface,LPDWORD status
544 ICOM_THIS(IDirectSoundBufferImpl,iface);
545 TRACE("(%p,%p), thread is %04lx\n",This,status,GetCurrentThreadId());
547 if (status == NULL) {
548 WARN("invalid parameter: status = NULL\n");
549 return DSERR_INVALIDPARAM;
552 *status = 0;
553 if ((This->state == STATE_STARTING) || (This->state == STATE_PLAYING)) {
554 *status |= DSBSTATUS_PLAYING;
555 if (This->playflags & DSBPLAY_LOOPING)
556 *status |= DSBSTATUS_LOOPING;
559 TRACE("status=%lx\n", *status);
560 return DS_OK;
564 static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat(
565 LPDIRECTSOUNDBUFFER8 iface,LPWAVEFORMATEX lpwf,DWORD wfsize,LPDWORD wfwritten
567 ICOM_THIS(IDirectSoundBufferImpl,iface);
568 TRACE("(%p,%p,%ld,%p)\n",This,lpwf,wfsize,wfwritten);
570 if (wfsize>sizeof(This->wfx))
571 wfsize = sizeof(This->wfx);
572 if (lpwf) { /* NULL is valid */
573 memcpy(lpwf,&(This->wfx),wfsize);
574 if (wfwritten)
575 *wfwritten = wfsize;
576 } else {
577 if (wfwritten)
578 *wfwritten = sizeof(This->wfx);
579 else {
580 WARN("invalid parameter: wfwritten == NULL\n");
581 return DSERR_INVALIDPARAM;
585 return DS_OK;
588 static HRESULT WINAPI IDirectSoundBufferImpl_Lock(
589 LPDIRECTSOUNDBUFFER8 iface,DWORD writecursor,DWORD writebytes,LPVOID lplpaudioptr1,LPDWORD audiobytes1,LPVOID lplpaudioptr2,LPDWORD audiobytes2,DWORD flags
591 HRESULT hres = DS_OK;
592 ICOM_THIS(IDirectSoundBufferImpl,iface);
594 TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx) at %ld\n",
595 This,
596 writecursor,
597 writebytes,
598 lplpaudioptr1,
599 audiobytes1,
600 lplpaudioptr2,
601 audiobytes2,
602 flags,
603 GetTickCount()
606 if (flags & DSBLOCK_FROMWRITECURSOR) {
607 DWORD writepos;
608 /* GetCurrentPosition does too much magic to duplicate here */
609 hres = IDirectSoundBufferImpl_GetCurrentPosition(iface, NULL, &writepos);
610 if (hres != DS_OK) {
611 WARN("IDirectSoundBufferImpl_GetCurrentPosition failed\n");
612 return hres;
614 writecursor += writepos;
616 while (writecursor >= This->buflen)
617 writecursor -= This->buflen;
618 if (flags & DSBLOCK_ENTIREBUFFER)
619 writebytes = This->buflen;
620 if (writebytes > This->buflen)
621 writebytes = This->buflen;
623 assert(audiobytes1!=audiobytes2);
624 assert(lplpaudioptr1!=lplpaudioptr2);
626 EnterCriticalSection(&(This->lock));
628 if ((writebytes == This->buflen) &&
629 ((This->state == STATE_STARTING) ||
630 (This->state == STATE_PLAYING)))
631 /* some games, like Half-Life, try to be clever (not) and
632 * keep one secondary buffer, and mix sounds into it itself,
633 * locking the entire buffer every time... so we can just forget
634 * about tracking the last-written-to-position... */
635 This->probably_valid_to = (DWORD)-1;
636 else
637 This->probably_valid_to = writecursor;
639 if (!(This->dsound->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
640 hres = IDsDriverBuffer_Lock(This->hwbuf,
641 lplpaudioptr1, audiobytes1,
642 lplpaudioptr2, audiobytes2,
643 writecursor, writebytes,
645 if (hres != DS_OK) {
646 WARN("IDsDriverBuffer_Lock failed\n");
647 LeaveCriticalSection(&(This->lock));
648 return hres;
650 } else {
651 BOOL remix = FALSE;
652 if (writecursor+writebytes <= This->buflen) {
653 *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
654 *audiobytes1 = writebytes;
655 if (lplpaudioptr2)
656 *(LPBYTE*)lplpaudioptr2 = NULL;
657 if (audiobytes2)
658 *audiobytes2 = 0;
659 TRACE("->%ld.0\n",writebytes);
660 } else {
661 *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
662 *audiobytes1 = This->buflen-writecursor;
663 if (lplpaudioptr2)
664 *(LPBYTE*)lplpaudioptr2 = This->buffer->memory;
665 if (audiobytes2)
666 *audiobytes2 = writebytes-(This->buflen-writecursor);
667 TRACE("->%ld.%ld\n",*audiobytes1,audiobytes2?*audiobytes2:0);
669 if (This->state == STATE_PLAYING) {
670 /* if the segment between playpos and buf_mixpos is touched,
671 * we need to cancel some mixing */
672 /* we'll assume that the app always calls GetCurrentPosition before
673 * locking a playing buffer, so that last_playpos is up-to-date */
674 if (This->buf_mixpos >= This->last_playpos) {
675 if (This->buf_mixpos > writecursor &&
676 This->last_playpos < writecursor+writebytes)
677 remix = TRUE;
679 else {
680 if (This->buf_mixpos > writecursor ||
681 This->last_playpos < writecursor+writebytes)
682 remix = TRUE;
684 if (remix) {
685 TRACE("locking prebuffered region, ouch\n");
686 DSOUND_MixCancelAt(This, writecursor);
691 LeaveCriticalSection(&(This->lock));
692 return DS_OK;
695 static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(
696 LPDIRECTSOUNDBUFFER8 iface,DWORD newpos
698 HRESULT hres = DS_OK;
699 ICOM_THIS(IDirectSoundBufferImpl,iface);
700 TRACE("(%p,%ld)\n",This,newpos);
702 /* **** */
703 EnterCriticalSection(&(This->lock));
705 while (newpos >= This->buflen)
706 newpos -= This->buflen;
707 This->buf_mixpos = newpos;
708 if (This->hwbuf) {
709 hres = IDsDriverBuffer_SetPosition(This->hwbuf, This->buf_mixpos);
710 if (hres != DS_OK)
711 WARN("IDsDriverBuffer_SetPosition failed\n");
714 LeaveCriticalSection(&(This->lock));
715 /* **** */
717 return hres;
720 static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(
721 LPDIRECTSOUNDBUFFER8 iface,LONG pan
723 HRESULT hres = DS_OK;
724 ICOM_THIS(IDirectSoundBufferImpl,iface);
725 LONG oldPan;
727 TRACE("(%p,%ld)\n",This,pan);
729 if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT)) {
730 WARN("invalid parameter: pan = %ld\n", pan);
731 return DSERR_INVALIDPARAM;
734 /* You cannot use both pan and 3D controls */
735 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
736 (This->dsbd.dwFlags & DSBCAPS_CTRL3D)) {
737 WARN("control unavailable\n");
738 return DSERR_CONTROLUNAVAIL;
741 /* **** */
742 EnterCriticalSection(&(This->lock));
744 oldPan = This->volpan.lPan;
745 This->volpan.lPan = pan;
747 if (pan != oldPan) {
748 DSOUND_RecalcVolPan(&(This->volpan));
750 if (This->hwbuf) {
751 hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
752 if (hres != DS_OK)
753 WARN("IDsDriverBuffer_SetVolumePan failed\n");
754 } else
755 DSOUND_ForceRemix(This);
758 LeaveCriticalSection(&(This->lock));
759 /* **** */
761 return hres;
764 static HRESULT WINAPI IDirectSoundBufferImpl_GetPan(
765 LPDIRECTSOUNDBUFFER8 iface,LPLONG pan
767 ICOM_THIS(IDirectSoundBufferImpl,iface);
768 TRACE("(%p,%p)\n",This,pan);
770 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN)) {
771 WARN("control unavailable\n");
772 return DSERR_CONTROLUNAVAIL;
775 if (pan == NULL) {
776 WARN("invalid parameter: pan = NULL\n");
777 return DSERR_INVALIDPARAM;
780 *pan = This->volpan.lPan;
782 return DS_OK;
785 static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(
786 LPDIRECTSOUNDBUFFER8 iface,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2
788 ICOM_THIS(IDirectSoundBufferImpl,iface);
789 DWORD probably_valid_to;
791 TRACE("(%p,%p,%ld,%p,%ld)\n", This,p1,x1,p2,x2);
793 if (!(This->dsound->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
794 HRESULT hres;
795 hres = IDsDriverBuffer_Unlock(This->hwbuf, p1, x1, p2, x2);
796 if (hres != DS_OK) {
797 WARN("IDsDriverBuffer_Unlock failed\n");
798 return hres;
802 if (p2) probably_valid_to = (((LPBYTE)p2)-This->buffer->memory) + x2;
803 else probably_valid_to = (((LPBYTE)p1)-This->buffer->memory) + x1;
804 while (probably_valid_to >= This->buflen)
805 probably_valid_to -= This->buflen;
806 if ((probably_valid_to == 0) && ((x1+x2) == This->buflen) &&
807 ((This->state == STATE_STARTING) ||
808 (This->state == STATE_PLAYING)))
809 /* see IDirectSoundBufferImpl_Lock */
810 probably_valid_to = (DWORD)-1;
811 This->probably_valid_to = probably_valid_to;
813 return DS_OK;
816 static HRESULT WINAPI IDirectSoundBufferImpl_Restore(
817 LPDIRECTSOUNDBUFFER8 iface
819 ICOM_THIS(IDirectSoundBufferImpl,iface);
820 FIXME("(%p):stub\n",This);
821 return DS_OK;
824 static HRESULT WINAPI IDirectSoundBufferImpl_GetFrequency(
825 LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq
827 ICOM_THIS(IDirectSoundBufferImpl,iface);
828 TRACE("(%p,%p)\n",This,freq);
830 if (freq == NULL) {
831 WARN("invalid parameter: freq = NULL\n");
832 return DSERR_INVALIDPARAM;
835 *freq = This->freq;
836 TRACE("-> %ld\n", *freq);
838 return DS_OK;
841 static HRESULT WINAPI IDirectSoundBufferImpl_SetFX(
842 LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes
844 ICOM_THIS(IDirectSoundBufferImpl,iface);
845 DWORD u;
847 FIXME("(%p,%lu,%p,%p): stub\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
849 if (pdwResultCodes)
850 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
852 WARN("control unavailable\n");
853 return DSERR_CONTROLUNAVAIL;
856 static HRESULT WINAPI IDirectSoundBufferImpl_AcquireResources(
857 LPDIRECTSOUNDBUFFER8 iface,DWORD dwFlags,DWORD dwEffectsCount,LPDWORD pdwResultCodes
859 ICOM_THIS(IDirectSoundBufferImpl,iface);
860 DWORD u;
862 FIXME("(%p,%08lu,%lu,%p): stub\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
864 if (pdwResultCodes)
865 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
867 WARN("control unavailable\n");
868 return DSERR_CONTROLUNAVAIL;
871 static HRESULT WINAPI IDirectSoundBufferImpl_GetObjectInPath(
872 LPDIRECTSOUNDBUFFER8 iface,REFGUID rguidObject,DWORD dwIndex,REFGUID rguidInterface,LPVOID* ppObject
874 ICOM_THIS(IDirectSoundBufferImpl,iface);
876 FIXME("(%p,%s,%lu,%s,%p): stub\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
878 WARN("control unavailable\n");
879 return DSERR_CONTROLUNAVAIL;
882 static HRESULT WINAPI IDirectSoundBufferImpl_Initialize(
883 LPDIRECTSOUNDBUFFER8 iface,LPDIRECTSOUND8 dsound,LPCDSBUFFERDESC dbsd
885 ICOM_THIS(IDirectSoundBufferImpl,iface);
886 FIXME("(%p,%p,%p):stub\n",This,dsound,dbsd);
887 DPRINTF("Re-Init!!!\n");
888 WARN("already initialized\n");
889 return DSERR_ALREADYINITIALIZED;
892 static HRESULT WINAPI IDirectSoundBufferImpl_GetCaps(
893 LPDIRECTSOUNDBUFFER8 iface,LPDSBCAPS caps
895 ICOM_THIS(IDirectSoundBufferImpl,iface);
896 TRACE("(%p)->(%p)\n",This,caps);
898 if (caps == NULL) {
899 WARN("invalid parameter: caps == NULL\n");
900 return DSERR_INVALIDPARAM;
903 if (caps->dwSize < sizeof(*caps)) {
904 WARN("invalid parameter: caps->dwSize = %ld < %d\n",caps->dwSize, sizeof(*caps));
905 return DSERR_INVALIDPARAM;
908 caps->dwFlags = This->dsbd.dwFlags;
909 if (This->hwbuf) caps->dwFlags |= DSBCAPS_LOCHARDWARE;
910 else caps->dwFlags |= DSBCAPS_LOCSOFTWARE;
912 caps->dwBufferBytes = This->buflen;
914 /* This value represents the speed of the "unlock" command.
915 As unlock is quite fast (it does not do anything), I put
916 4096 ko/s = 4 Mo / s */
917 /* FIXME: hwbuf speed */
918 caps->dwUnlockTransferRate = 4096;
919 caps->dwPlayCpuOverhead = 0;
921 return DS_OK;
924 static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface(
925 LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj
927 ICOM_THIS(IDirectSoundBufferImpl,iface);
929 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
931 if (ppobj == NULL) {
932 WARN("invalid parameter\n");
933 return E_INVALIDARG;
936 *ppobj = NULL; /* assume failure */
938 if ( IsEqualGUID(riid, &IID_IUnknown) ||
939 IsEqualGUID(riid, &IID_IDirectSoundBuffer) ||
940 IsEqualGUID(riid, &IID_IDirectSoundBuffer8) ) {
941 if (!This->dsb)
942 SecondaryBufferImpl_Create(This, &(This->dsb));
943 if (This->dsb) {
944 IDirectSoundBuffer8_AddRef((LPDIRECTSOUNDBUFFER8)This->dsb);
945 *ppobj = This->dsb;
946 return S_OK;
948 WARN("IID_IDirectSoundBuffer\n");
949 return E_NOINTERFACE;
952 if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ||
953 IsEqualGUID( &IID_IDirectSoundNotify8, riid ) ) {
954 if (!This->notify)
955 IDirectSoundNotifyImpl_Create(This, &(This->notify));
956 if (This->notify) {
957 IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify);
958 *ppobj = This->notify;
959 return S_OK;
961 WARN("IID_IDirectSoundNotify\n");
962 return E_NOINTERFACE;
965 if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) {
966 if (!This->ds3db)
967 IDirectSound3DBufferImpl_Create(This, &(This->ds3db));
968 if (This->ds3db) {
969 IDirectSound3DBuffer_AddRef((LPDIRECTSOUND3DBUFFER)This->ds3db);
970 *ppobj = This->ds3db;
971 return S_OK;
973 WARN("IID_IDirectSound3DBuffer\n");
974 return E_NOINTERFACE;
977 if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
978 ERR("app requested IDirectSound3DListener on secondary buffer\n");
979 return E_NOINTERFACE;
982 if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) {
983 /* only supported on hardware 3D secondary buffers */
984 if (!(This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER) &&
985 (This->dsbd.dwFlags & DSBCAPS_CTRL3D) &&
986 (This->hwbuf != NULL) ) {
987 if (!This->iks)
988 IKsBufferPropertySetImpl_Create(This, &(This->iks));
989 if (This->iks) {
990 IKsPropertySet_AddRef((LPKSPROPERTYSET)*ppobj);
991 *ppobj = This->iks;
992 return S_OK;
995 WARN("IID_IKsPropertySet\n");
996 return E_NOINTERFACE;
999 FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
1001 return E_NOINTERFACE;
1004 static ICOM_VTABLE(IDirectSoundBuffer8) dsbvt =
1006 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1007 IDirectSoundBufferImpl_QueryInterface,
1008 IDirectSoundBufferImpl_AddRef,
1009 IDirectSoundBufferImpl_Release,
1010 IDirectSoundBufferImpl_GetCaps,
1011 IDirectSoundBufferImpl_GetCurrentPosition,
1012 IDirectSoundBufferImpl_GetFormat,
1013 IDirectSoundBufferImpl_GetVolume,
1014 IDirectSoundBufferImpl_GetPan,
1015 IDirectSoundBufferImpl_GetFrequency,
1016 IDirectSoundBufferImpl_GetStatus,
1017 IDirectSoundBufferImpl_Initialize,
1018 IDirectSoundBufferImpl_Lock,
1019 IDirectSoundBufferImpl_Play,
1020 IDirectSoundBufferImpl_SetCurrentPosition,
1021 IDirectSoundBufferImpl_SetFormat,
1022 IDirectSoundBufferImpl_SetVolume,
1023 IDirectSoundBufferImpl_SetPan,
1024 IDirectSoundBufferImpl_SetFrequency,
1025 IDirectSoundBufferImpl_Stop,
1026 IDirectSoundBufferImpl_Unlock,
1027 IDirectSoundBufferImpl_Restore,
1028 IDirectSoundBufferImpl_SetFX,
1029 IDirectSoundBufferImpl_AcquireResources,
1030 IDirectSoundBufferImpl_GetObjectInPath
1033 HRESULT WINAPI IDirectSoundBufferImpl_Create(
1034 IDirectSoundImpl *ds,
1035 IDirectSoundBufferImpl **pdsb,
1036 LPCDSBUFFERDESC dsbd)
1038 IDirectSoundBufferImpl *dsb;
1039 LPWAVEFORMATEX wfex = dsbd->lpwfxFormat;
1040 HRESULT err = DS_OK;
1041 DWORD capf = 0;
1042 int use_hw;
1043 TRACE("(%p,%p,%p)\n",ds,pdsb,dsbd);
1045 if (dsbd->dwBufferBytes < DSBSIZE_MIN || dsbd->dwBufferBytes > DSBSIZE_MAX) {
1046 WARN("invalid parameter: dsbd->dwBufferBytes = %ld\n", dsbd->dwBufferBytes);
1047 *pdsb = NULL;
1048 return DSERR_INVALIDPARAM; /* FIXME: which error? */
1051 dsb = (IDirectSoundBufferImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
1053 if (dsb == 0) {
1054 WARN("out of memory\n");
1055 *pdsb = NULL;
1056 return DSERR_OUTOFMEMORY;
1058 dsb->ref = 0;
1059 dsb->dsb = 0;
1060 dsb->dsound = ds;
1061 dsb->lpVtbl = &dsbvt;
1062 dsb->iks = NULL;
1064 memcpy(&dsb->dsbd, dsbd, sizeof(*dsbd));
1065 if (wfex)
1066 memcpy(&dsb->wfx, wfex, sizeof(dsb->wfx));
1068 TRACE("Created buffer at %p\n", dsb);
1070 dsb->buflen = dsbd->dwBufferBytes;
1071 dsb->freq = dsbd->lpwfxFormat->nSamplesPerSec;
1073 dsb->notify = NULL;
1074 dsb->notifies = NULL;
1075 dsb->nrofnotifies = 0;
1076 dsb->hwnotify = 0;
1078 /* Check necessary hardware mixing capabilities */
1079 if (wfex->nChannels==2) capf |= DSCAPS_SECONDARYSTEREO;
1080 else capf |= DSCAPS_SECONDARYMONO;
1081 if (wfex->wBitsPerSample==16) capf |= DSCAPS_SECONDARY16BIT;
1082 else capf |= DSCAPS_SECONDARY8BIT;
1084 use_hw = (ds->drvcaps.dwFlags & capf) == capf;
1085 TRACE("use_hw = 0x%08x, capf = 0x%08lx, ds->drvcaps.dwFlags = 0x%08lx\n", use_hw, capf, ds->drvcaps.dwFlags);
1087 /* FIXME: check hardware sample rate mixing capabilities */
1088 /* FIXME: check app hints for software/hardware buffer (STATIC, LOCHARDWARE, etc) */
1089 /* FIXME: check whether any hardware buffers are left */
1090 /* FIXME: handle DSDHEAP_CREATEHEAP for hardware buffers */
1092 /* Allocate system memory if applicable */
1093 if ((ds->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) || !use_hw) {
1094 dsb->buffer = HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb->buffer)));
1095 if (dsb->buffer == NULL) {
1096 WARN("out of memory\n");
1097 HeapFree(GetProcessHeap(),0,dsb);
1098 *pdsb = NULL;
1099 return DSERR_OUTOFMEMORY;
1102 dsb->buffer->memory = (LPBYTE)HeapAlloc(GetProcessHeap(),0,dsb->buflen);
1103 if (dsb->buffer->memory == NULL) {
1104 WARN("out of memory\n");
1105 HeapFree(GetProcessHeap(),0,dsb->buffer);
1106 HeapFree(GetProcessHeap(),0,dsb);
1107 *pdsb = NULL;
1108 return DSERR_OUTOFMEMORY;
1110 dsb->buffer->ref = 1;
1113 /* Allocate the hardware buffer */
1114 if (use_hw) {
1115 err = IDsDriver_CreateSoundBuffer(ds->driver,wfex,dsbd->dwFlags,0,
1116 &(dsb->buflen),&(dsb->buffer->memory),
1117 (LPVOID*)&(dsb->hwbuf));
1118 /* fall back to software buffer on failure */
1119 if (err != DS_OK) {
1120 TRACE("IDsDriver_CreateSoundBuffer failed, falling back to software buffer\n");
1121 use_hw = 0;
1122 if (ds->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) {
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);
1127 *pdsb = NULL;
1128 return DSERR_OUTOFMEMORY;
1131 dsb->buffer->memory = (LPBYTE)HeapAlloc(GetProcessHeap(),0,dsb->buflen);
1132 if (dsb->buffer->memory == NULL) {
1133 WARN("out of memory\n");
1134 HeapFree(GetProcessHeap(),0,dsb->buffer);
1135 HeapFree(GetProcessHeap(),0,dsb);
1136 *pdsb = NULL;
1137 return DSERR_OUTOFMEMORY;
1139 dsb->buffer->ref = 1;
1144 /* calculate fragment size and write lead */
1145 DSOUND_RecalcFormat(dsb);
1147 /* It's not necessary to initialize values to zero since */
1148 /* we allocated this structure with HEAP_ZERO_MEMORY... */
1149 dsb->playpos = 0;
1150 dsb->buf_mixpos = 0;
1151 dsb->state = STATE_STOPPED;
1153 dsb->freqAdjust = (dsb->freq << DSOUND_FREQSHIFT) /
1154 ds->wfx.nSamplesPerSec;
1155 dsb->nAvgBytesPerSec = dsb->freq *
1156 dsbd->lpwfxFormat->nBlockAlign;
1158 if (dsb->dsbd.dwFlags & DSBCAPS_CTRL3D) {
1159 dsb->ds3db_ds3db.dwSize = sizeof(DS3DBUFFER);
1160 dsb->ds3db_ds3db.vPosition.x = 0.0;
1161 dsb->ds3db_ds3db.vPosition.y = 0.0;
1162 dsb->ds3db_ds3db.vPosition.z = 0.0;
1163 dsb->ds3db_ds3db.vVelocity.x = 0.0;
1164 dsb->ds3db_ds3db.vVelocity.y = 0.0;
1165 dsb->ds3db_ds3db.vVelocity.z = 0.0;
1166 dsb->ds3db_ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
1167 dsb->ds3db_ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
1168 dsb->ds3db_ds3db.vConeOrientation.x = 0.0;
1169 dsb->ds3db_ds3db.vConeOrientation.y = 0.0;
1170 dsb->ds3db_ds3db.vConeOrientation.z = 0.0;
1171 dsb->ds3db_ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
1172 dsb->ds3db_ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE;
1173 dsb->ds3db_ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
1174 dsb->ds3db_ds3db.dwMode = DS3DMODE_NORMAL;
1176 dsb->ds3db_need_recalc = FALSE;
1177 DSOUND_Calc3DBuffer(dsb);
1178 } else
1179 DSOUND_RecalcVolPan(&(dsb->volpan));
1181 InitializeCriticalSection(&(dsb->lock));
1183 /* register buffer */
1184 RtlAcquireResourceExclusive(&(ds->lock), TRUE);
1185 if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
1186 IDirectSoundBufferImpl **newbuffers;
1187 if (ds->buffers)
1188 newbuffers = (IDirectSoundBufferImpl**)HeapReAlloc(GetProcessHeap(),0,ds->buffers,sizeof(IDirectSoundBufferImpl*)*(ds->nrofbuffers+1));
1189 else
1190 newbuffers = (IDirectSoundBufferImpl**)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundBufferImpl*)*(ds->nrofbuffers+1));
1192 if (newbuffers) {
1193 ds->buffers = newbuffers;
1194 ds->buffers[ds->nrofbuffers] = dsb;
1195 ds->nrofbuffers++;
1196 TRACE("buffer count is now %d\n", ds->nrofbuffers);
1197 } else {
1198 ERR("out of memory for buffer list! Current buffer count is %d\n", ds->nrofbuffers);
1199 if (dsb->buffer->memory)
1200 HeapFree(GetProcessHeap(),0,dsb->buffer->memory);
1201 if (dsb->buffer)
1202 HeapFree(GetProcessHeap(),0,dsb->buffer);
1203 DeleteCriticalSection(&(dsb->lock));
1204 RtlReleaseResource(&(ds->lock));
1205 HeapFree(GetProcessHeap(),0,dsb);
1206 *pdsb = NULL;
1207 return DSERR_OUTOFMEMORY;
1210 RtlReleaseResource(&(ds->lock));
1211 IDirectSound8_AddRef((LPDIRECTSOUND8)ds);
1212 *pdsb = dsb;
1213 return S_OK;
1216 /*******************************************************************************
1217 * SecondaryBuffer
1220 static HRESULT WINAPI SecondaryBufferImpl_QueryInterface(
1221 LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj)
1223 ICOM_THIS(SecondaryBufferImpl,iface);
1224 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
1226 return IDirectSoundBufferImpl_QueryInterface((LPDIRECTSOUNDBUFFER8)This->dsb,riid,ppobj);
1229 static DWORD WINAPI SecondaryBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface)
1231 ICOM_THIS(IDirectSoundBufferImpl,iface);
1232 DWORD ref;
1233 TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
1235 ref = InterlockedIncrement(&(This->ref));
1236 if (!ref) {
1237 FIXME("thread-safety alert! AddRef-ing with a zero refcount!\n");
1239 return ref;
1242 static DWORD WINAPI SecondaryBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface)
1244 ICOM_THIS(IDirectSoundBufferImpl,iface);
1245 DWORD ref;
1246 TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
1248 ref = InterlockedDecrement(&(This->ref));
1249 if (!ref) {
1250 This->dsb->dsb = NULL;
1251 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER8)This->dsb);
1252 HeapFree(GetProcessHeap(),0,This);
1253 TRACE("(%p) released\n",This);
1255 return ref;
1258 static HRESULT WINAPI SecondaryBufferImpl_GetCaps(
1259 LPDIRECTSOUNDBUFFER8 iface,LPDSBCAPS caps)
1261 ICOM_THIS(SecondaryBufferImpl,iface);
1262 TRACE("(%p)->(%p)\n",This,caps);
1264 return IDirectSoundBufferImpl_GetCaps((LPDIRECTSOUNDBUFFER8)This->dsb,caps);
1267 static HRESULT WINAPI SecondaryBufferImpl_GetCurrentPosition(
1268 LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos)
1270 ICOM_THIS(SecondaryBufferImpl,iface);
1271 TRACE("(%p,%p,%p)\n",This,playpos,writepos);
1273 return IDirectSoundBufferImpl_GetCurrentPosition((LPDIRECTSOUNDBUFFER8)This->dsb,playpos,writepos);
1276 static HRESULT WINAPI SecondaryBufferImpl_GetFormat(
1277 LPDIRECTSOUNDBUFFER8 iface,LPWAVEFORMATEX lpwf,DWORD wfsize,LPDWORD wfwritten)
1279 ICOM_THIS(SecondaryBufferImpl,iface);
1280 TRACE("(%p,%p,%ld,%p)\n",This,lpwf,wfsize,wfwritten);
1282 return IDirectSoundBufferImpl_GetFormat((LPDIRECTSOUNDBUFFER8)This->dsb,lpwf,wfsize,wfwritten);
1285 static HRESULT WINAPI SecondaryBufferImpl_GetVolume(
1286 LPDIRECTSOUNDBUFFER8 iface,LPLONG vol)
1288 ICOM_THIS(SecondaryBufferImpl,iface);
1289 TRACE("(%p,%p)\n",This,vol);
1291 return IDirectSoundBufferImpl_GetVolume((LPDIRECTSOUNDBUFFER8)This->dsb,vol);
1294 static HRESULT WINAPI SecondaryBufferImpl_GetPan(
1295 LPDIRECTSOUNDBUFFER8 iface,LPLONG pan)
1297 ICOM_THIS(SecondaryBufferImpl,iface);
1298 TRACE("(%p,%p)\n",This,pan);
1300 return IDirectSoundBufferImpl_GetPan((LPDIRECTSOUNDBUFFER8)This->dsb,pan);
1303 static HRESULT WINAPI SecondaryBufferImpl_GetFrequency(
1304 LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq)
1306 ICOM_THIS(SecondaryBufferImpl,iface);
1307 TRACE("(%p,%p)\n",This,freq);
1309 return IDirectSoundBufferImpl_GetFrequency((LPDIRECTSOUNDBUFFER8)This->dsb,freq);
1312 static HRESULT WINAPI SecondaryBufferImpl_GetStatus(
1313 LPDIRECTSOUNDBUFFER8 iface,LPDWORD status)
1315 ICOM_THIS(SecondaryBufferImpl,iface);
1316 TRACE("(%p,%p)\n",This,status);
1318 return IDirectSoundBufferImpl_GetStatus((LPDIRECTSOUNDBUFFER8)This->dsb,status);
1321 static HRESULT WINAPI SecondaryBufferImpl_Initialize(
1322 LPDIRECTSOUNDBUFFER8 iface,LPDIRECTSOUND8 dsound,LPCDSBUFFERDESC dbsd)
1324 ICOM_THIS(SecondaryBufferImpl,iface);
1325 TRACE("(%p,%p,%p)\n",This,dsound,dbsd);
1327 return IDirectSoundBufferImpl_Initialize((LPDIRECTSOUNDBUFFER8)This->dsb,dsound,dbsd);
1330 static HRESULT WINAPI SecondaryBufferImpl_Lock(
1331 LPDIRECTSOUNDBUFFER8 iface,
1332 DWORD writecursor,
1333 DWORD writebytes,
1334 LPVOID lplpaudioptr1,
1335 LPDWORD audiobytes1,
1336 LPVOID lplpaudioptr2,
1337 LPDWORD audiobytes2,
1338 DWORD dwFlags)
1340 ICOM_THIS(SecondaryBufferImpl,iface);
1341 TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx)\n",
1342 This,writecursor,writebytes,lplpaudioptr1,audiobytes1,lplpaudioptr2,audiobytes2,dwFlags);
1344 return IDirectSoundBufferImpl_Lock((LPDIRECTSOUNDBUFFER8)This->dsb,
1345 writecursor,writebytes,lplpaudioptr1,audiobytes1,lplpaudioptr2,audiobytes2,dwFlags);
1348 static HRESULT WINAPI SecondaryBufferImpl_Play(
1349 LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags)
1351 ICOM_THIS(SecondaryBufferImpl,iface);
1352 TRACE("(%p,%08lx,%08lx,%08lx)\n",This,reserved1,reserved2,flags);
1354 return IDirectSoundBufferImpl_Play((LPDIRECTSOUNDBUFFER8)This->dsb,reserved1,reserved2,flags);
1357 static HRESULT WINAPI SecondaryBufferImpl_SetCurrentPosition(
1358 LPDIRECTSOUNDBUFFER8 iface,DWORD newpos)
1360 ICOM_THIS(SecondaryBufferImpl,iface);
1361 TRACE("(%p,%ld)\n",This,newpos);
1363 return IDirectSoundBufferImpl_SetCurrentPosition((LPDIRECTSOUNDBUFFER8)This->dsb,newpos);
1366 static HRESULT WINAPI SecondaryBufferImpl_SetFormat(
1367 LPDIRECTSOUNDBUFFER8 iface,LPCWAVEFORMATEX wfex)
1369 ICOM_THIS(SecondaryBufferImpl,iface);
1370 TRACE("(%p,%p)\n",This,wfex);
1372 return IDirectSoundBufferImpl_SetFormat((LPDIRECTSOUNDBUFFER8)This->dsb,wfex);
1375 static HRESULT WINAPI SecondaryBufferImpl_SetVolume(
1376 LPDIRECTSOUNDBUFFER8 iface,LONG vol)
1378 ICOM_THIS(SecondaryBufferImpl,iface);
1379 TRACE("(%p,%ld)\n",This,vol);
1381 return IDirectSoundBufferImpl_SetVolume((LPDIRECTSOUNDBUFFER8)This->dsb,vol);
1384 static HRESULT WINAPI SecondaryBufferImpl_SetPan(
1385 LPDIRECTSOUNDBUFFER8 iface,LONG pan)
1387 ICOM_THIS(SecondaryBufferImpl,iface);
1388 TRACE("(%p,%ld)\n",This,pan);
1390 return IDirectSoundBufferImpl_SetPan((LPDIRECTSOUNDBUFFER8)This->dsb,pan);
1393 static HRESULT WINAPI SecondaryBufferImpl_SetFrequency(
1394 LPDIRECTSOUNDBUFFER8 iface,DWORD freq)
1396 ICOM_THIS(SecondaryBufferImpl,iface);
1397 TRACE("(%p,%ld)\n",This,freq);
1399 return IDirectSoundBufferImpl_SetFrequency((LPDIRECTSOUNDBUFFER8)This->dsb,freq);
1402 static HRESULT WINAPI SecondaryBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface)
1404 ICOM_THIS(SecondaryBufferImpl,iface);
1405 TRACE("(%p)\n",This);
1407 return IDirectSoundBufferImpl_Stop((LPDIRECTSOUNDBUFFER8)This->dsb);
1410 static HRESULT WINAPI SecondaryBufferImpl_Unlock(
1411 LPDIRECTSOUNDBUFFER8 iface,
1412 LPVOID lpvAudioPtr1,
1413 DWORD dwAudioBytes1,
1414 LPVOID lpvAudioPtr2,
1415 DWORD dwAudioBytes2)
1417 ICOM_THIS(SecondaryBufferImpl,iface);
1418 TRACE("(%p,%p,%ld,%p,%ld)\n",
1419 This, lpvAudioPtr1, dwAudioBytes1, lpvAudioPtr2, dwAudioBytes2);
1421 return IDirectSoundBufferImpl_Unlock((LPDIRECTSOUNDBUFFER8)This->dsb,
1422 lpvAudioPtr1,dwAudioBytes1,lpvAudioPtr2,dwAudioBytes2);
1425 static HRESULT WINAPI SecondaryBufferImpl_Restore(
1426 LPDIRECTSOUNDBUFFER8 iface)
1428 ICOM_THIS(SecondaryBufferImpl,iface);
1429 TRACE("(%p)\n",This);
1431 return IDirectSoundBufferImpl_Restore((LPDIRECTSOUNDBUFFER8)This->dsb);
1434 static HRESULT WINAPI SecondaryBufferImpl_SetFX(
1435 LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes)
1437 ICOM_THIS(SecondaryBufferImpl,iface);
1438 TRACE("(%p,%lu,%p,%p)\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
1440 return IDirectSoundBufferImpl_SetFX((LPDIRECTSOUNDBUFFER8)This->dsb,dwEffectsCount,pDSFXDesc,pdwResultCodes);
1443 static HRESULT WINAPI SecondaryBufferImpl_AcquireResources(
1444 LPDIRECTSOUNDBUFFER8 iface,DWORD dwFlags,DWORD dwEffectsCount,LPDWORD pdwResultCodes)
1446 ICOM_THIS(SecondaryBufferImpl,iface);
1447 TRACE("(%p,%08lu,%lu,%p)\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
1449 return IDirectSoundBufferImpl_AcquireResources((LPDIRECTSOUNDBUFFER8)This->dsb,dwFlags,dwEffectsCount,pdwResultCodes);
1452 static HRESULT WINAPI SecondaryBufferImpl_GetObjectInPath(
1453 LPDIRECTSOUNDBUFFER8 iface,REFGUID rguidObject,DWORD dwIndex,REFGUID rguidInterface,LPVOID* ppObject)
1455 ICOM_THIS(SecondaryBufferImpl,iface);
1456 TRACE("(%p,%s,%lu,%s,%p)\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
1458 return IDirectSoundBufferImpl_GetObjectInPath((LPDIRECTSOUNDBUFFER8)This->dsb,rguidObject,dwIndex,rguidInterface,ppObject);
1461 static ICOM_VTABLE(IDirectSoundBuffer8) sbvt =
1463 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1464 SecondaryBufferImpl_QueryInterface,
1465 SecondaryBufferImpl_AddRef,
1466 SecondaryBufferImpl_Release,
1467 SecondaryBufferImpl_GetCaps,
1468 SecondaryBufferImpl_GetCurrentPosition,
1469 SecondaryBufferImpl_GetFormat,
1470 SecondaryBufferImpl_GetVolume,
1471 SecondaryBufferImpl_GetPan,
1472 SecondaryBufferImpl_GetFrequency,
1473 SecondaryBufferImpl_GetStatus,
1474 SecondaryBufferImpl_Initialize,
1475 SecondaryBufferImpl_Lock,
1476 SecondaryBufferImpl_Play,
1477 SecondaryBufferImpl_SetCurrentPosition,
1478 SecondaryBufferImpl_SetFormat,
1479 SecondaryBufferImpl_SetVolume,
1480 SecondaryBufferImpl_SetPan,
1481 SecondaryBufferImpl_SetFrequency,
1482 SecondaryBufferImpl_Stop,
1483 SecondaryBufferImpl_Unlock,
1484 SecondaryBufferImpl_Restore,
1485 SecondaryBufferImpl_SetFX,
1486 SecondaryBufferImpl_AcquireResources,
1487 SecondaryBufferImpl_GetObjectInPath
1490 HRESULT WINAPI SecondaryBufferImpl_Create(
1491 IDirectSoundBufferImpl *dsb,
1492 SecondaryBufferImpl **psb)
1494 SecondaryBufferImpl *sb;
1495 TRACE("(%p,%p)\n",dsb,psb);
1497 sb = (SecondaryBufferImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*sb));
1499 if (sb == 0) {
1500 WARN("out of memory\n");
1501 *psb = NULL;
1502 return DSERR_OUTOFMEMORY;
1504 sb->ref = 0;
1505 sb->dsb = dsb;
1506 sb->lpVtbl = &sbvt;
1508 IDirectSoundBuffer8_AddRef((LPDIRECTSOUNDBUFFER8)dsb);
1509 *psb = sb;
1510 return S_OK;