Fixed typo.
[wine/multimedia.git] / dlls / dsound / buffer.c
blob576d60bafd28d80fd7c3ce6c1d657d0197ae22ab
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 <stdio.h>
25 #include <sys/types.h>
26 #include <sys/fcntl.h>
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30 #include <stdlib.h>
31 #include <string.h>
32 #include <math.h>
34 #define NONAMELESSSTRUCT
35 #define NONAMELESSUNION
36 #include "windef.h"
37 #include "winbase.h"
38 #include "wingdi.h"
39 #include "winuser.h"
40 #include "winerror.h"
41 #include "mmsystem.h"
42 #include "winternl.h"
43 #include "mmddk.h"
44 #include "wine/windef16.h"
45 #include "wine/debug.h"
46 #include "dsound.h"
47 #include "dsdriver.h"
48 #include "dsound_private.h"
50 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
52 /*******************************************************************************
53 * IDirectSoundNotify
55 static HRESULT WINAPI IDirectSoundNotifyImpl_QueryInterface(
56 LPDIRECTSOUNDNOTIFY iface,REFIID riid,LPVOID *ppobj
57 ) {
58 ICOM_THIS(IDirectSoundNotifyImpl,iface);
59 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
61 if (This->dsb == NULL) {
62 WARN("invalid parameter\n");
63 return E_INVALIDARG;
66 return IDirectSoundBuffer_QueryInterface((LPDIRECTSOUNDBUFFER)This->dsb, riid, ppobj);
69 static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface) {
70 ICOM_THIS(IDirectSoundNotifyImpl,iface);
71 DWORD ref;
73 TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
75 ref = InterlockedIncrement(&(This->ref));
76 return ref;
79 static ULONG WINAPI IDirectSoundNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface) {
80 ICOM_THIS(IDirectSoundNotifyImpl,iface);
81 DWORD ref;
83 TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
85 ref = InterlockedDecrement(&(This->ref));
86 if (ref == 0) {
87 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->dsb);
88 This->dsb->notify = NULL;
89 HeapFree(GetProcessHeap(),0,This);
90 TRACE("(%p) released\n",This);
92 return ref;
95 static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(
96 LPDIRECTSOUNDNOTIFY iface,DWORD howmuch,LPCDSBPOSITIONNOTIFY notify
97 ) {
98 ICOM_THIS(IDirectSoundNotifyImpl,iface);
99 TRACE("(%p,0x%08lx,%p)\n",This,howmuch,notify);
101 if (notify == NULL) {
102 WARN("invalid parameter: notify == NULL\n");
103 return DSERR_INVALIDPARAM;
106 if (TRACE_ON(dsound)) {
107 int i;
108 for (i=0;i<howmuch;i++)
109 TRACE("notify at %ld to 0x%08lx\n",
110 notify[i].dwOffset,(DWORD)notify[i].hEventNotify);
113 if (This->dsb->hwnotify) {
114 HRESULT hres;
115 hres = IDsDriverNotify_SetNotificationPositions(This->dsb->hwnotify, howmuch, notify);
116 if (hres != DS_OK)
117 WARN("IDsDriverNotify_SetNotificationPositions failed\n");
118 return hres;
119 } else {
120 /* Make an internal copy of the caller-supplied array.
121 * Replace the existing copy if one is already present. */
122 This->dsb->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
123 This->dsb->notifies, howmuch * sizeof(DSBPOSITIONNOTIFY));
124 if (This->dsb->notifies == NULL) {
125 WARN("out of memory\n");
126 return DSERR_OUTOFMEMORY;
128 memcpy(This->dsb->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
129 This->dsb->nrofnotifies = howmuch;
132 return S_OK;
135 ICOM_VTABLE(IDirectSoundNotify) dsnvt =
137 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
138 IDirectSoundNotifyImpl_QueryInterface,
139 IDirectSoundNotifyImpl_AddRef,
140 IDirectSoundNotifyImpl_Release,
141 IDirectSoundNotifyImpl_SetNotificationPositions,
144 HRESULT WINAPI IDirectSoundNotifyImpl_Create(
145 IDirectSoundBufferImpl * dsb,
146 IDirectSoundNotifyImpl **pdsn)
148 IDirectSoundNotifyImpl * dsn;
149 TRACE("(%p,%p)\n",dsb,pdsn);
151 dsn = (IDirectSoundNotifyImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dsn));
153 if (dsn == NULL) {
154 WARN("out of memory\n");
155 return DSERR_OUTOFMEMORY;
158 dsn->ref = 0;
159 dsn->lpVtbl = &dsnvt;
160 dsn->dsb = dsb;
161 dsb->notify = dsn;
162 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)dsb);
164 *pdsn = dsn;
165 return DS_OK;
168 /*******************************************************************************
169 * IDirectSoundBuffer
172 static HRESULT WINAPI IDirectSoundBufferImpl_SetFormat(
173 LPDIRECTSOUNDBUFFER8 iface,LPWAVEFORMATEX wfex
175 ICOM_THIS(IDirectSoundBufferImpl,iface);
177 TRACE("(%p,%p)\n",This,wfex);
178 /* This method is not available on secondary buffers */
179 WARN("invalid call\n");
180 return DSERR_INVALIDCALL;
183 static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume(
184 LPDIRECTSOUNDBUFFER8 iface,LONG vol
186 ICOM_THIS(IDirectSoundBufferImpl,iface);
187 LONG oldVol;
189 TRACE("(%p,%ld)\n",This,vol);
191 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
192 WARN("control unavailable: This->dsbd.dwFlags = 0x%08lx\n", This->dsbd.dwFlags);
193 return DSERR_CONTROLUNAVAIL;
196 if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN)) {
197 WARN("invalid parameter: vol = %ld\n", vol);
198 return DSERR_INVALIDPARAM;
201 /* **** */
202 EnterCriticalSection(&(This->lock));
204 if (This->dsbd.dwFlags & DSBCAPS_CTRL3D) {
205 oldVol = This->ds3db_lVolume;
206 This->ds3db_lVolume = vol;
207 } else {
208 oldVol = This->volpan.lVolume;
209 This->volpan.lVolume = vol;
210 if (vol != oldVol)
211 DSOUND_RecalcVolPan(&(This->volpan));
214 if (vol != oldVol) {
215 if (This->hwbuf) {
216 HRESULT hres;
217 hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
218 if (hres != DS_OK)
219 WARN("IDsDriverBuffer_SetVolumePan failed\n");
220 } else
221 DSOUND_ForceRemix(This);
224 LeaveCriticalSection(&(This->lock));
225 /* **** */
227 return DS_OK;
230 static HRESULT WINAPI IDirectSoundBufferImpl_GetVolume(
231 LPDIRECTSOUNDBUFFER8 iface,LPLONG vol
233 ICOM_THIS(IDirectSoundBufferImpl,iface);
234 TRACE("(%p,%p)\n",This,vol);
236 if (vol == NULL) {
237 WARN("invalid parameter: vol == NULL\n");
238 return DSERR_INVALIDPARAM;
241 if (This->dsbd.dwFlags & DSBCAPS_CTRL3D)
242 *vol = This->ds3db_lVolume;
243 else
244 *vol = This->volpan.lVolume;
245 return DS_OK;
248 static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency(
249 LPDIRECTSOUNDBUFFER8 iface,DWORD freq
251 ICOM_THIS(IDirectSoundBufferImpl,iface);
252 DWORD oldFreq;
254 TRACE("(%p,%ld)\n",This,freq);
256 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLFREQUENCY)) {
257 WARN("control unavailable\n");
258 return DSERR_CONTROLUNAVAIL;
261 if (freq == DSBFREQUENCY_ORIGINAL)
262 freq = This->wfx.nSamplesPerSec;
264 if ((freq < DSBFREQUENCY_MIN) || (freq > DSBFREQUENCY_MAX)) {
265 WARN("invalid parameter: freq = %ld\n", freq);
266 return DSERR_INVALIDPARAM;
269 /* **** */
270 EnterCriticalSection(&(This->lock));
272 oldFreq = This->freq;
273 This->freq = freq;
274 if (freq != oldFreq) {
275 This->freqAdjust = (freq << DSOUND_FREQSHIFT) / This->dsound->wfx.nSamplesPerSec;
276 This->nAvgBytesPerSec = freq * This->wfx.nBlockAlign;
277 DSOUND_RecalcFormat(This);
278 if (!This->hwbuf)
279 DSOUND_ForceRemix(This);
282 LeaveCriticalSection(&(This->lock));
283 /* **** */
285 return DS_OK;
288 static HRESULT WINAPI IDirectSoundBufferImpl_Play(
289 LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags
291 HRESULT hres = DS_OK;
292 ICOM_THIS(IDirectSoundBufferImpl,iface);
293 TRACE("(%p,%08lx,%08lx,%08lx)\n",This,reserved1,reserved2,flags);
295 /* **** */
296 EnterCriticalSection(&(This->lock));
298 This->playflags = flags;
299 if (This->state == STATE_STOPPED) {
300 This->leadin = TRUE;
301 This->startpos = This->buf_mixpos;
302 This->state = STATE_STARTING;
303 } else if (This->state == STATE_STOPPING)
304 This->state = STATE_PLAYING;
305 if (This->hwbuf) {
306 hres = IDsDriverBuffer_Play(This->hwbuf, 0, 0, This->playflags);
307 if (hres != DS_OK)
308 WARN("IDsDriverBuffer_Play failed\n");
309 else
310 This->state = STATE_PLAYING;
313 LeaveCriticalSection(&(This->lock));
314 /* **** */
316 return hres;
319 static HRESULT WINAPI IDirectSoundBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface)
321 HRESULT hres = DS_OK;
322 ICOM_THIS(IDirectSoundBufferImpl,iface);
323 TRACE("(%p)\n",This);
325 /* **** */
326 EnterCriticalSection(&(This->lock));
328 if (This->state == STATE_PLAYING)
329 This->state = STATE_STOPPING;
330 else if (This->state == STATE_STARTING)
331 This->state = STATE_STOPPED;
332 if (This->hwbuf) {
333 hres = IDsDriverBuffer_Stop(This->hwbuf);
334 if (hres != DS_OK)
335 WARN("IDsDriverBuffer_Stop failed\n");
336 else
337 This->state = STATE_STOPPED;
339 DSOUND_CheckEvent(This, 0);
341 LeaveCriticalSection(&(This->lock));
342 /* **** */
344 return hres;
347 static DWORD WINAPI IDirectSoundBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface) {
348 ICOM_THIS(IDirectSoundBufferImpl,iface);
349 DWORD ref;
351 TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
353 ref = InterlockedIncrement(&(This->ref));
354 if (!ref) {
355 FIXME("thread-safety alert! AddRef-ing with a zero refcount!\n");
357 return ref;
360 static DWORD WINAPI IDirectSoundBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface) {
361 ICOM_THIS(IDirectSoundBufferImpl,iface);
362 int i;
363 DWORD ref;
365 TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
367 ref = InterlockedDecrement(&(This->ref));
368 if (ref) return ref;
370 RtlAcquireResourceExclusive(&(This->dsound->lock), TRUE);
371 for (i=0;i<This->dsound->nrofbuffers;i++)
372 if (This->dsound->buffers[i] == This)
373 break;
374 if (i < This->dsound->nrofbuffers) {
375 /* Put the last buffer of the list in the (now empty) position */
376 This->dsound->buffers[i] = This->dsound->buffers[This->dsound->nrofbuffers - 1];
377 This->dsound->nrofbuffers--;
378 This->dsound->buffers = HeapReAlloc(GetProcessHeap(),0,This->dsound->buffers,sizeof(LPDIRECTSOUNDBUFFER8)*This->dsound->nrofbuffers);
379 TRACE("buffer count is now %d\n", This->dsound->nrofbuffers);
380 IDirectSound_Release((LPDIRECTSOUND)This->dsound);
382 RtlReleaseResource(&(This->dsound->lock));
384 DeleteCriticalSection(&(This->lock));
386 if (This->hwbuf) {
387 IDsDriverBuffer_Release(This->hwbuf);
388 if (This->dsound->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) {
389 This->buffer->ref--;
390 if (This->buffer->ref==0) {
391 HeapFree(GetProcessHeap(),0,This->buffer->memory);
392 HeapFree(GetProcessHeap(),0,This->buffer);
395 } else {
396 This->buffer->ref--;
397 if (This->buffer->ref==0) {
398 HeapFree(GetProcessHeap(),0,This->buffer->memory);
399 HeapFree(GetProcessHeap(),0,This->buffer);
403 if (This->ds3db) {
404 WARN("ds3db still has reference\n");
405 EnterCriticalSection(&(This->ds3db->lock));
406 This->ds3db->dsb = NULL;
407 LeaveCriticalSection(&(This->ds3db->lock));
410 if (This->iks)
411 IKsPropertySet_Release((LPKSPROPERTYSET)This->iks);
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 (pan == NULL) {
771 WARN("invalid parameter: pan = NULL\n");
772 return DSERR_INVALIDPARAM;
775 *pan = This->volpan.lPan;
777 return DS_OK;
780 static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(
781 LPDIRECTSOUNDBUFFER8 iface,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2
783 ICOM_THIS(IDirectSoundBufferImpl,iface);
784 DWORD probably_valid_to;
786 TRACE("(%p,%p,%ld,%p,%ld)\n", This,p1,x1,p2,x2);
788 if (!(This->dsound->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
789 HRESULT hres;
790 hres = IDsDriverBuffer_Unlock(This->hwbuf, p1, x1, p2, x2);
791 if (hres != DS_OK) {
792 WARN("IDsDriverBuffer_Unlock failed\n");
793 return hres;
797 if (p2) probably_valid_to = (((LPBYTE)p2)-This->buffer->memory) + x2;
798 else probably_valid_to = (((LPBYTE)p1)-This->buffer->memory) + x1;
799 while (probably_valid_to >= This->buflen)
800 probably_valid_to -= This->buflen;
801 if ((probably_valid_to == 0) && ((x1+x2) == This->buflen) &&
802 ((This->state == STATE_STARTING) ||
803 (This->state == STATE_PLAYING)))
804 /* see IDirectSoundBufferImpl_Lock */
805 probably_valid_to = (DWORD)-1;
806 This->probably_valid_to = probably_valid_to;
808 return DS_OK;
811 static HRESULT WINAPI IDirectSoundBufferImpl_Restore(
812 LPDIRECTSOUNDBUFFER8 iface
814 ICOM_THIS(IDirectSoundBufferImpl,iface);
815 FIXME("(%p):stub\n",This);
816 return DS_OK;
819 static HRESULT WINAPI IDirectSoundBufferImpl_GetFrequency(
820 LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq
822 ICOM_THIS(IDirectSoundBufferImpl,iface);
823 TRACE("(%p,%p)\n",This,freq);
825 if (freq == NULL) {
826 WARN("invalid parameter: freq = NULL\n");
827 return DSERR_INVALIDPARAM;
830 *freq = This->freq;
831 TRACE("-> %ld\n", *freq);
833 return DS_OK;
836 static HRESULT WINAPI IDirectSoundBufferImpl_SetFX(
837 LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes
839 ICOM_THIS(IDirectSoundBufferImpl,iface);
840 DWORD u;
842 FIXME("(%p,%lu,%p,%p): stub\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
844 if (pdwResultCodes)
845 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
847 WARN("control unavailable\n");
848 return DSERR_CONTROLUNAVAIL;
851 static HRESULT WINAPI IDirectSoundBufferImpl_AcquireResources(
852 LPDIRECTSOUNDBUFFER8 iface,DWORD dwFlags,DWORD dwEffectsCount,LPDWORD pdwResultCodes
854 ICOM_THIS(IDirectSoundBufferImpl,iface);
855 DWORD u;
857 FIXME("(%p,%08lu,%lu,%p): stub\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
859 if (pdwResultCodes)
860 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
862 WARN("control unavailable\n");
863 return DSERR_CONTROLUNAVAIL;
866 static HRESULT WINAPI IDirectSoundBufferImpl_GetObjectInPath(
867 LPDIRECTSOUNDBUFFER8 iface,REFGUID rguidObject,DWORD dwIndex,REFGUID rguidInterface,LPVOID* ppObject
869 ICOM_THIS(IDirectSoundBufferImpl,iface);
871 FIXME("(%p,%s,%lu,%s,%p): stub\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
873 WARN("control unavailable\n");
874 return DSERR_CONTROLUNAVAIL;
877 static HRESULT WINAPI IDirectSoundBufferImpl_Initialize(
878 LPDIRECTSOUNDBUFFER8 iface,LPDIRECTSOUND8 dsound,LPDSBUFFERDESC dbsd
880 ICOM_THIS(IDirectSoundBufferImpl,iface);
881 FIXME("(%p,%p,%p):stub\n",This,dsound,dbsd);
882 DPRINTF("Re-Init!!!\n");
883 WARN("already initialized\n");
884 return DSERR_ALREADYINITIALIZED;
887 static HRESULT WINAPI IDirectSoundBufferImpl_GetCaps(
888 LPDIRECTSOUNDBUFFER8 iface,LPDSBCAPS caps
890 ICOM_THIS(IDirectSoundBufferImpl,iface);
891 TRACE("(%p)->(%p)\n",This,caps);
893 if (caps == NULL) {
894 WARN("invalid parameter: caps == NULL\n");
895 return DSERR_INVALIDPARAM;
898 if (caps->dwSize < sizeof(*caps)) {
899 WARN("invalid parameter: caps->dwSize = %ld < %d\n",caps->dwSize, sizeof(*caps));
900 return DSERR_INVALIDPARAM;
903 caps->dwFlags = This->dsbd.dwFlags;
904 if (This->hwbuf) caps->dwFlags |= DSBCAPS_LOCHARDWARE;
905 else caps->dwFlags |= DSBCAPS_LOCSOFTWARE;
907 caps->dwBufferBytes = This->buflen;
909 /* This value represents the speed of the "unlock" command.
910 As unlock is quite fast (it does not do anything), I put
911 4096 ko/s = 4 Mo / s */
912 /* FIXME: hwbuf speed */
913 caps->dwUnlockTransferRate = 4096;
914 caps->dwPlayCpuOverhead = 0;
916 return DS_OK;
919 static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface(
920 LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj
922 ICOM_THIS(IDirectSoundBufferImpl,iface);
924 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
926 if (ppobj == NULL) {
927 WARN("invalid parameter\n");
928 return E_INVALIDARG;
931 *ppobj = NULL; /* assume failure */
933 if ( IsEqualGUID(riid, &IID_IUnknown) ||
934 IsEqualGUID(riid, &IID_IDirectSoundBuffer) ||
935 IsEqualGUID(riid, &IID_IDirectSoundBuffer8) ) {
936 if (!This->dsb)
937 SecondaryBufferImpl_Create(This, &(This->dsb));
938 if (This->dsb) {
939 IDirectSoundBuffer8_AddRef((LPDIRECTSOUNDBUFFER8)This->dsb);
940 *ppobj = This->dsb;
941 return S_OK;
943 WARN("IID_IDirectSoundBuffer\n");
944 return E_NOINTERFACE;
947 if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ||
948 IsEqualGUID( &IID_IDirectSoundNotify8, riid ) ) {
949 if (!This->notify)
950 IDirectSoundNotifyImpl_Create(This, &(This->notify));
951 if (This->notify) {
952 IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify);
953 *ppobj = This->notify;
954 return S_OK;
956 WARN("IID_IDirectSoundNotify\n");
957 return E_NOINTERFACE;
960 if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) {
961 if (!This->ds3db)
962 IDirectSound3DBufferImpl_Create(This, &(This->ds3db));
963 if (This->ds3db) {
964 IDirectSound3DBuffer_AddRef((LPDIRECTSOUND3DBUFFER)This->ds3db);
965 *ppobj = This->ds3db;
966 return S_OK;
968 WARN("IID_IDirectSound3DBuffer\n");
969 return E_NOINTERFACE;
972 if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
973 ERR("app requested IDirectSound3DListener on secondary buffer\n");
974 return E_NOINTERFACE;
977 if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) {
978 /* only supported on hardware 3D secondary buffers */
979 if (!(This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER) &&
980 (This->dsbd.dwFlags & DSBCAPS_CTRL3D) &&
981 (This->hwbuf != NULL) ) {
982 if (!This->iks)
983 IKsBufferPropertySetImpl_Create(This, &(This->iks));
984 if (This->iks) {
985 IKsPropertySet_AddRef((LPKSPROPERTYSET)*ppobj);
986 *ppobj = This->iks;
987 return S_OK;
990 WARN("IID_IKsPropertySet\n");
991 return E_NOINTERFACE;
994 FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
996 return E_NOINTERFACE;
999 static ICOM_VTABLE(IDirectSoundBuffer8) dsbvt =
1001 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1002 IDirectSoundBufferImpl_QueryInterface,
1003 IDirectSoundBufferImpl_AddRef,
1004 IDirectSoundBufferImpl_Release,
1005 IDirectSoundBufferImpl_GetCaps,
1006 IDirectSoundBufferImpl_GetCurrentPosition,
1007 IDirectSoundBufferImpl_GetFormat,
1008 IDirectSoundBufferImpl_GetVolume,
1009 IDirectSoundBufferImpl_GetPan,
1010 IDirectSoundBufferImpl_GetFrequency,
1011 IDirectSoundBufferImpl_GetStatus,
1012 IDirectSoundBufferImpl_Initialize,
1013 IDirectSoundBufferImpl_Lock,
1014 IDirectSoundBufferImpl_Play,
1015 IDirectSoundBufferImpl_SetCurrentPosition,
1016 IDirectSoundBufferImpl_SetFormat,
1017 IDirectSoundBufferImpl_SetVolume,
1018 IDirectSoundBufferImpl_SetPan,
1019 IDirectSoundBufferImpl_SetFrequency,
1020 IDirectSoundBufferImpl_Stop,
1021 IDirectSoundBufferImpl_Unlock,
1022 IDirectSoundBufferImpl_Restore,
1023 IDirectSoundBufferImpl_SetFX,
1024 IDirectSoundBufferImpl_AcquireResources,
1025 IDirectSoundBufferImpl_GetObjectInPath
1028 HRESULT WINAPI IDirectSoundBufferImpl_Create(
1029 IDirectSoundImpl *ds,
1030 IDirectSoundBufferImpl **pdsb,
1031 LPDSBUFFERDESC dsbd)
1033 IDirectSoundBufferImpl *dsb;
1034 LPWAVEFORMATEX wfex = dsbd->lpwfxFormat;
1035 HRESULT err = DS_OK;
1036 DWORD capf = 0;
1037 int use_hw;
1038 TRACE("(%p,%p,%p)\n",ds,pdsb,dsbd);
1040 if (dsbd->dwBufferBytes < DSBSIZE_MIN || dsbd->dwBufferBytes > DSBSIZE_MAX) {
1041 WARN("invalid parameter: dsbd->dwBufferBytes = %ld\n", dsbd->dwBufferBytes);
1042 *pdsb = NULL;
1043 return DSERR_INVALIDPARAM; /* FIXME: which error? */
1046 dsb = (IDirectSoundBufferImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
1048 if (dsb == 0) {
1049 WARN("out of memory\n");
1050 *pdsb = NULL;
1051 return DSERR_OUTOFMEMORY;
1053 dsb->ref = 0;
1054 dsb->dsb = 0;
1055 dsb->dsound = ds;
1056 dsb->lpVtbl = &dsbvt;
1058 memcpy(&dsb->dsbd, dsbd, sizeof(*dsbd));
1059 if (wfex)
1060 memcpy(&dsb->wfx, wfex, sizeof(dsb->wfx));
1062 TRACE("Created buffer at %p\n", dsb);
1064 dsb->buflen = dsbd->dwBufferBytes;
1065 dsb->freq = dsbd->lpwfxFormat->nSamplesPerSec;
1067 dsb->notify = NULL;
1068 dsb->notifies = NULL;
1069 dsb->nrofnotifies = 0;
1070 dsb->hwnotify = 0;
1072 /* Check necessary hardware mixing capabilities */
1073 if (wfex->nChannels==2) capf |= DSCAPS_SECONDARYSTEREO;
1074 else capf |= DSCAPS_SECONDARYMONO;
1075 if (wfex->wBitsPerSample==16) capf |= DSCAPS_SECONDARY16BIT;
1076 else capf |= DSCAPS_SECONDARY8BIT;
1077 use_hw = (ds->drvcaps.dwFlags & capf) == capf;
1079 /* FIXME: check hardware sample rate mixing capabilities */
1080 /* FIXME: check app hints for software/hardware buffer (STATIC, LOCHARDWARE, etc) */
1081 /* FIXME: check whether any hardware buffers are left */
1082 /* FIXME: handle DSDHEAP_CREATEHEAP for hardware buffers */
1084 /* Allocate system memory if applicable */
1085 if ((ds->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) || !use_hw) {
1086 dsb->buffer = HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb->buffer)));
1087 if (dsb->buffer == NULL) {
1088 WARN("out of memory\n");
1089 HeapFree(GetProcessHeap(),0,dsb);
1090 *pdsb = NULL;
1091 return DSERR_OUTOFMEMORY;
1094 dsb->buffer->memory = (LPBYTE)HeapAlloc(GetProcessHeap(),0,dsb->buflen);
1095 if (dsb->buffer->memory == NULL) {
1096 WARN("out of memory\n");
1097 HeapFree(GetProcessHeap(),0,dsb->buffer);
1098 HeapFree(GetProcessHeap(),0,dsb);
1099 *pdsb = NULL;
1100 return DSERR_OUTOFMEMORY;
1104 /* Allocate the hardware buffer */
1105 if (use_hw) {
1106 err = IDsDriver_CreateSoundBuffer(ds->driver,wfex,dsbd->dwFlags,0,
1107 &(dsb->buflen),&(dsb->buffer->memory),
1108 (LPVOID*)&(dsb->hwbuf));
1109 if (err != DS_OK) {
1110 WARN("IDsDriver_CreateSoundBuffer failed\n");
1111 if (dsb->buffer->memory)
1112 HeapFree(GetProcessHeap(),0,dsb->buffer->memory);
1113 if (dsb->buffer)
1114 HeapFree(GetProcessHeap(),0,dsb->buffer);
1115 HeapFree(GetProcessHeap(),0,dsb);
1116 *pdsb = NULL;
1117 return err;
1121 /* calculate fragment size and write lead */
1122 DSOUND_RecalcFormat(dsb);
1124 /* It's not necessary to initialize values to zero since */
1125 /* we allocated this structure with HEAP_ZERO_MEMORY... */
1126 dsb->playpos = 0;
1127 dsb->buf_mixpos = 0;
1128 dsb->state = STATE_STOPPED;
1130 dsb->freqAdjust = (dsb->freq << DSOUND_FREQSHIFT) /
1131 ds->wfx.nSamplesPerSec;
1132 dsb->nAvgBytesPerSec = dsb->freq *
1133 dsbd->lpwfxFormat->nBlockAlign;
1135 if (dsb->dsbd.dwFlags & DSBCAPS_CTRL3D) {
1136 dsb->ds3db_ds3db.dwSize = sizeof(DS3DBUFFER);
1137 dsb->ds3db_ds3db.vPosition.u1.x = 0.0;
1138 dsb->ds3db_ds3db.vPosition.u2.y = 0.0;
1139 dsb->ds3db_ds3db.vPosition.u3.z = 0.0;
1140 dsb->ds3db_ds3db.vVelocity.u1.x = 0.0;
1141 dsb->ds3db_ds3db.vVelocity.u2.y = 0.0;
1142 dsb->ds3db_ds3db.vVelocity.u3.z = 0.0;
1143 dsb->ds3db_ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
1144 dsb->ds3db_ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
1145 dsb->ds3db_ds3db.vConeOrientation.u1.x = 0.0;
1146 dsb->ds3db_ds3db.vConeOrientation.u2.y = 0.0;
1147 dsb->ds3db_ds3db.vConeOrientation.u3.z = 0.0;
1148 dsb->ds3db_ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
1149 dsb->ds3db_ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE;
1150 dsb->ds3db_ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
1151 dsb->ds3db_ds3db.dwMode = DS3DMODE_NORMAL;
1153 dsb->ds3db_need_recalc = FALSE;
1154 DSOUND_Calc3DBuffer(dsb);
1155 } else
1156 DSOUND_RecalcVolPan(&(dsb->volpan));
1158 InitializeCriticalSection(&(dsb->lock));
1160 /* register buffer */
1161 RtlAcquireResourceExclusive(&(ds->lock), TRUE);
1162 if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
1163 IDirectSoundBufferImpl **newbuffers = (IDirectSoundBufferImpl**)HeapReAlloc(GetProcessHeap(),0,ds->buffers,sizeof(IDirectSoundBufferImpl*)*(ds->nrofbuffers+1));
1164 if (newbuffers) {
1165 ds->buffers = newbuffers;
1166 ds->buffers[ds->nrofbuffers] = dsb;
1167 ds->nrofbuffers++;
1168 TRACE("buffer count is now %d\n", ds->nrofbuffers);
1169 } else {
1170 ERR("out of memory for buffer list! Current buffer count is %d\n", ds->nrofbuffers);
1171 if (dsb->buffer->memory)
1172 HeapFree(GetProcessHeap(),0,dsb->buffer->memory);
1173 if (dsb->buffer)
1174 HeapFree(GetProcessHeap(),0,dsb->buffer);
1175 DeleteCriticalSection(&(dsb->lock));
1176 RtlReleaseResource(&(ds->lock));
1177 HeapFree(GetProcessHeap(),0,dsb);
1178 *pdsb = NULL;
1179 return DSERR_OUTOFMEMORY;
1182 RtlReleaseResource(&(ds->lock));
1183 IDirectSound8_AddRef((LPDIRECTSOUND8)ds);
1184 *pdsb = dsb;
1185 return S_OK;
1188 /*******************************************************************************
1189 * SecondaryBuffer
1192 static HRESULT WINAPI SecondaryBufferImpl_QueryInterface(
1193 LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj)
1195 ICOM_THIS(SecondaryBufferImpl,iface);
1196 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
1198 return IDirectSoundBufferImpl_QueryInterface((LPDIRECTSOUNDBUFFER8)This->dsb,riid,ppobj);
1201 static DWORD WINAPI SecondaryBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface)
1203 ICOM_THIS(IDirectSoundBufferImpl,iface);
1204 DWORD ref;
1205 TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
1207 ref = InterlockedIncrement(&(This->ref));
1208 if (!ref) {
1209 FIXME("thread-safety alert! AddRef-ing with a zero refcount!\n");
1211 return ref;
1214 static DWORD WINAPI SecondaryBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface)
1216 ICOM_THIS(IDirectSoundBufferImpl,iface);
1217 DWORD ref;
1218 TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
1220 ref = InterlockedDecrement(&(This->ref));
1221 if (!ref) {
1222 This->dsb->dsb = NULL;
1223 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER8)This->dsb);
1224 HeapFree(GetProcessHeap(),0,This);
1225 TRACE("(%p) released\n",This);
1227 return ref;
1230 static HRESULT WINAPI SecondaryBufferImpl_GetCaps(
1231 LPDIRECTSOUNDBUFFER8 iface,LPDSBCAPS caps)
1233 ICOM_THIS(SecondaryBufferImpl,iface);
1234 TRACE("(%p)->(%p)\n",This,caps);
1236 return IDirectSoundBufferImpl_GetCaps((LPDIRECTSOUNDBUFFER8)This->dsb,caps);
1239 static HRESULT WINAPI SecondaryBufferImpl_GetCurrentPosition(
1240 LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos)
1242 ICOM_THIS(SecondaryBufferImpl,iface);
1243 TRACE("(%p,%p,%p)\n",This,playpos,writepos);
1245 return IDirectSoundBufferImpl_GetCurrentPosition((LPDIRECTSOUNDBUFFER8)This->dsb,playpos,writepos);
1248 static HRESULT WINAPI SecondaryBufferImpl_GetFormat(
1249 LPDIRECTSOUNDBUFFER8 iface,LPWAVEFORMATEX lpwf,DWORD wfsize,LPDWORD wfwritten)
1251 ICOM_THIS(SecondaryBufferImpl,iface);
1252 TRACE("(%p,%p,%ld,%p)\n",This,lpwf,wfsize,wfwritten);
1254 return IDirectSoundBufferImpl_GetFormat((LPDIRECTSOUNDBUFFER8)This->dsb,lpwf,wfsize,wfwritten);
1257 static HRESULT WINAPI SecondaryBufferImpl_GetVolume(
1258 LPDIRECTSOUNDBUFFER8 iface,LPLONG vol)
1260 ICOM_THIS(SecondaryBufferImpl,iface);
1261 TRACE("(%p,%p)\n",This,vol);
1263 return IDirectSoundBufferImpl_GetVolume((LPDIRECTSOUNDBUFFER8)This->dsb,vol);
1266 static HRESULT WINAPI SecondaryBufferImpl_GetPan(
1267 LPDIRECTSOUNDBUFFER8 iface,LPLONG pan)
1269 ICOM_THIS(SecondaryBufferImpl,iface);
1270 TRACE("(%p,%p)\n",This,pan);
1272 return IDirectSoundBufferImpl_GetPan((LPDIRECTSOUNDBUFFER8)This->dsb,pan);
1275 static HRESULT WINAPI SecondaryBufferImpl_GetFrequency(
1276 LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq)
1278 ICOM_THIS(SecondaryBufferImpl,iface);
1279 TRACE("(%p,%p)\n",This,freq);
1281 return IDirectSoundBufferImpl_GetFrequency((LPDIRECTSOUNDBUFFER8)This->dsb,freq);
1284 static HRESULT WINAPI SecondaryBufferImpl_GetStatus(
1285 LPDIRECTSOUNDBUFFER8 iface,LPDWORD status)
1287 ICOM_THIS(SecondaryBufferImpl,iface);
1288 TRACE("(%p,%p)\n",This,status);
1290 return IDirectSoundBufferImpl_GetStatus((LPDIRECTSOUNDBUFFER8)This->dsb,status);
1293 static HRESULT WINAPI SecondaryBufferImpl_Initialize(
1294 LPDIRECTSOUNDBUFFER8 iface,LPDIRECTSOUND8 dsound,LPDSBUFFERDESC dbsd)
1296 ICOM_THIS(SecondaryBufferImpl,iface);
1297 TRACE("(%p,%p,%p)\n",This,dsound,dbsd);
1299 return IDirectSoundBufferImpl_Initialize((LPDIRECTSOUNDBUFFER8)This->dsb,dsound,dbsd);
1302 static HRESULT WINAPI SecondaryBufferImpl_Lock(
1303 LPDIRECTSOUNDBUFFER8 iface,DWORD writecursor,DWORD writebytes,LPVOID lplpaudioptr1,LPDWORD audiobytes1,LPVOID lplpaudioptr2,LPDWORD audiobytes2,DWORD flags)
1305 ICOM_THIS(SecondaryBufferImpl,iface);
1306 TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx)\n",
1307 This,writecursor,writebytes,lplpaudioptr1,audiobytes1,lplpaudioptr2,audiobytes2,flags);
1309 return IDirectSoundBufferImpl_Lock((LPDIRECTSOUNDBUFFER8)This->dsb,writecursor,writebytes,lplpaudioptr1,audiobytes1,lplpaudioptr2,audiobytes2,flags);
1312 static HRESULT WINAPI SecondaryBufferImpl_Play(
1313 LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags)
1315 ICOM_THIS(SecondaryBufferImpl,iface);
1316 TRACE("(%p,%08lx,%08lx,%08lx)\n",This,reserved1,reserved2,flags);
1318 return IDirectSoundBufferImpl_Play((LPDIRECTSOUNDBUFFER8)This->dsb,reserved1,reserved2,flags);
1321 static HRESULT WINAPI SecondaryBufferImpl_SetCurrentPosition(
1322 LPDIRECTSOUNDBUFFER8 iface,DWORD newpos)
1324 ICOM_THIS(SecondaryBufferImpl,iface);
1325 TRACE("(%p,%ld)\n",This,newpos);
1327 return IDirectSoundBufferImpl_SetCurrentPosition((LPDIRECTSOUNDBUFFER8)This->dsb,newpos);
1330 static HRESULT WINAPI SecondaryBufferImpl_SetFormat(
1331 LPDIRECTSOUNDBUFFER8 iface,LPWAVEFORMATEX wfex)
1333 ICOM_THIS(SecondaryBufferImpl,iface);
1334 TRACE("(%p,%p)\n",This,wfex);
1336 return IDirectSoundBufferImpl_SetFormat((LPDIRECTSOUNDBUFFER8)This->dsb,wfex);
1339 static HRESULT WINAPI SecondaryBufferImpl_SetVolume(
1340 LPDIRECTSOUNDBUFFER8 iface,LONG vol)
1342 ICOM_THIS(SecondaryBufferImpl,iface);
1343 TRACE("(%p,%ld)\n",This,vol);
1345 return IDirectSoundBufferImpl_SetVolume((LPDIRECTSOUNDBUFFER8)This->dsb,vol);
1348 static HRESULT WINAPI SecondaryBufferImpl_SetPan(
1349 LPDIRECTSOUNDBUFFER8 iface,LONG pan)
1351 ICOM_THIS(SecondaryBufferImpl,iface);
1352 TRACE("(%p,%ld)\n",This,pan);
1354 return IDirectSoundBufferImpl_SetPan((LPDIRECTSOUNDBUFFER8)This->dsb,pan);
1357 static HRESULT WINAPI SecondaryBufferImpl_SetFrequency(
1358 LPDIRECTSOUNDBUFFER8 iface,DWORD freq)
1360 ICOM_THIS(SecondaryBufferImpl,iface);
1361 TRACE("(%p,%ld)\n",This,freq);
1363 return IDirectSoundBufferImpl_SetFrequency((LPDIRECTSOUNDBUFFER8)This->dsb,freq);
1366 static HRESULT WINAPI SecondaryBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface)
1368 ICOM_THIS(SecondaryBufferImpl,iface);
1369 TRACE("(%p)\n",This);
1371 return IDirectSoundBufferImpl_Stop((LPDIRECTSOUNDBUFFER8)This->dsb);
1374 static HRESULT WINAPI SecondaryBufferImpl_Unlock(
1375 LPDIRECTSOUNDBUFFER8 iface,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2)
1377 ICOM_THIS(SecondaryBufferImpl,iface);
1378 TRACE("(%p,%p,%ld,%p,%ld)\n", This,p1,x1,p2,x2);
1380 return IDirectSoundBufferImpl_Unlock((LPDIRECTSOUNDBUFFER8)This->dsb,p1,x1,p2,x2);
1383 static HRESULT WINAPI SecondaryBufferImpl_Restore(
1384 LPDIRECTSOUNDBUFFER8 iface)
1386 ICOM_THIS(SecondaryBufferImpl,iface);
1387 TRACE("(%p)\n",This);
1389 return IDirectSoundBufferImpl_Restore((LPDIRECTSOUNDBUFFER8)This->dsb);
1392 static HRESULT WINAPI SecondaryBufferImpl_SetFX(
1393 LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes)
1395 ICOM_THIS(SecondaryBufferImpl,iface);
1396 TRACE("(%p,%lu,%p,%p)\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
1398 return IDirectSoundBufferImpl_SetFX((LPDIRECTSOUNDBUFFER8)This->dsb,dwEffectsCount,pDSFXDesc,pdwResultCodes);
1401 static HRESULT WINAPI SecondaryBufferImpl_AcquireResources(
1402 LPDIRECTSOUNDBUFFER8 iface,DWORD dwFlags,DWORD dwEffectsCount,LPDWORD pdwResultCodes)
1404 ICOM_THIS(SecondaryBufferImpl,iface);
1405 TRACE("(%p,%08lu,%lu,%p)\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
1407 return IDirectSoundBufferImpl_AcquireResources((LPDIRECTSOUNDBUFFER8)This->dsb,dwFlags,dwEffectsCount,pdwResultCodes);
1410 static HRESULT WINAPI SecondaryBufferImpl_GetObjectInPath(
1411 LPDIRECTSOUNDBUFFER8 iface,REFGUID rguidObject,DWORD dwIndex,REFGUID rguidInterface,LPVOID* ppObject)
1413 ICOM_THIS(SecondaryBufferImpl,iface);
1414 TRACE("(%p,%s,%lu,%s,%p)\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
1416 return IDirectSoundBufferImpl_GetObjectInPath((LPDIRECTSOUNDBUFFER8)This->dsb,rguidObject,dwIndex,rguidInterface,ppObject);
1419 static ICOM_VTABLE(IDirectSoundBuffer8) sbvt =
1421 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1422 SecondaryBufferImpl_QueryInterface,
1423 SecondaryBufferImpl_AddRef,
1424 SecondaryBufferImpl_Release,
1425 SecondaryBufferImpl_GetCaps,
1426 SecondaryBufferImpl_GetCurrentPosition,
1427 SecondaryBufferImpl_GetFormat,
1428 SecondaryBufferImpl_GetVolume,
1429 SecondaryBufferImpl_GetPan,
1430 SecondaryBufferImpl_GetFrequency,
1431 SecondaryBufferImpl_GetStatus,
1432 SecondaryBufferImpl_Initialize,
1433 SecondaryBufferImpl_Lock,
1434 SecondaryBufferImpl_Play,
1435 SecondaryBufferImpl_SetCurrentPosition,
1436 SecondaryBufferImpl_SetFormat,
1437 SecondaryBufferImpl_SetVolume,
1438 SecondaryBufferImpl_SetPan,
1439 SecondaryBufferImpl_SetFrequency,
1440 SecondaryBufferImpl_Stop,
1441 SecondaryBufferImpl_Unlock,
1442 SecondaryBufferImpl_Restore,
1443 SecondaryBufferImpl_SetFX,
1444 SecondaryBufferImpl_AcquireResources,
1445 SecondaryBufferImpl_GetObjectInPath
1448 HRESULT WINAPI SecondaryBufferImpl_Create(
1449 IDirectSoundBufferImpl *dsb,
1450 SecondaryBufferImpl **psb)
1452 SecondaryBufferImpl *sb;
1453 TRACE("(%p,%p)\n",dsb,psb);
1455 sb = (SecondaryBufferImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*sb));
1457 if (sb == 0) {
1458 WARN("out of memory\n");
1459 *psb = NULL;
1460 return DSERR_OUTOFMEMORY;
1462 sb->ref = 0;
1463 sb->dsb = dsb;
1464 sb->lpVtbl = &sbvt;
1466 IDirectSoundBuffer8_AddRef((LPDIRECTSOUNDBUFFER8)dsb);
1467 *psb = sb;
1468 return S_OK;