wine.inf: We should not override existing associations.
[wine/hacks.git] / dlls / dsound / buffer.c
blob303eb9c96c3fba161129c80179977f549bf7ec65
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <stdarg.h>
24 #define NONAMELESSSTRUCT
25 #define NONAMELESSUNION
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "mmsystem.h"
30 #include "winreg.h"
31 #include "winternl.h"
32 #include "wine/debug.h"
33 #include "dsound.h"
34 #include "dsdriver.h"
35 #include "dsound_private.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
39 static HRESULT SecondaryBufferImpl_Destroy(SecondaryBufferImpl *pdsb);
41 /*******************************************************************************
42 * IDirectSoundNotify
45 struct IDirectSoundNotifyImpl
47 /* IUnknown fields */
48 const IDirectSoundNotifyVtbl *lpVtbl;
49 LONG ref;
50 IDirectSoundBufferImpl* dsb;
53 static HRESULT IDirectSoundNotifyImpl_Create(IDirectSoundBufferImpl *dsb,
54 IDirectSoundNotifyImpl **pdsn);
55 static HRESULT IDirectSoundNotifyImpl_Destroy(IDirectSoundNotifyImpl *pdsn);
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)
73 IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
74 ULONG ref = InterlockedIncrement(&(This->ref));
75 TRACE("(%p) ref was %ld\n", This, ref - 1);
76 return ref;
79 static ULONG WINAPI IDirectSoundNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface)
81 IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
82 ULONG ref = InterlockedDecrement(&(This->ref));
83 TRACE("(%p) ref was %ld\n", This, ref + 1);
85 if (!ref) {
86 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->dsb);
87 This->dsb->notify = NULL;
88 HeapFree(GetProcessHeap(), 0, This);
89 TRACE("(%p) released\n", This);
91 return ref;
94 static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(
95 LPDIRECTSOUNDNOTIFY iface,DWORD howmuch,LPCDSBPOSITIONNOTIFY notify
96 ) {
97 IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
98 TRACE("(%p,0x%08lx,%p)\n",This,howmuch,notify);
100 if (howmuch > 0 && notify == NULL) {
101 WARN("invalid parameter: notify == NULL\n");
102 return DSERR_INVALIDPARAM;
105 if (TRACE_ON(dsound)) {
106 unsigned int i;
107 for (i=0;i<howmuch;i++)
108 TRACE("notify at %ld to %p\n",
109 notify[i].dwOffset,notify[i].hEventNotify);
112 if (This->dsb->hwnotify) {
113 HRESULT hres;
114 hres = IDsDriverNotify_SetNotificationPositions(This->dsb->hwnotify, howmuch, notify);
115 if (hres != DS_OK)
116 WARN("IDsDriverNotify_SetNotificationPositions failed\n");
117 return hres;
118 } else if (howmuch > 0) {
119 /* Make an internal copy of the caller-supplied array.
120 * Replace the existing copy if one is already present. */
121 if (This->dsb->notifies)
122 This->dsb->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
123 This->dsb->notifies, howmuch * sizeof(DSBPOSITIONNOTIFY));
124 else
125 This->dsb->notifies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
126 howmuch * sizeof(DSBPOSITIONNOTIFY));
128 if (This->dsb->notifies == NULL) {
129 WARN("out of memory\n");
130 return DSERR_OUTOFMEMORY;
132 CopyMemory(This->dsb->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
133 This->dsb->nrofnotifies = howmuch;
134 } else {
135 HeapFree(GetProcessHeap(), 0, This->dsb->notifies);
136 This->dsb->notifies = NULL;
137 This->dsb->nrofnotifies = 0;
140 return S_OK;
143 static const IDirectSoundNotifyVtbl dsnvt =
145 IDirectSoundNotifyImpl_QueryInterface,
146 IDirectSoundNotifyImpl_AddRef,
147 IDirectSoundNotifyImpl_Release,
148 IDirectSoundNotifyImpl_SetNotificationPositions,
151 static HRESULT IDirectSoundNotifyImpl_Create(
152 IDirectSoundBufferImpl * dsb,
153 IDirectSoundNotifyImpl **pdsn)
155 IDirectSoundNotifyImpl * dsn;
156 TRACE("(%p,%p)\n",dsb,pdsn);
158 dsn = 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 static HRESULT IDirectSoundNotifyImpl_Destroy(
176 IDirectSoundNotifyImpl *pdsn)
178 TRACE("(%p)\n",pdsn);
180 while (IDirectSoundNotifyImpl_Release((LPDIRECTSOUNDNOTIFY)pdsn) > 0);
182 return DS_OK;
185 /*******************************************************************************
186 * IDirectSoundBuffer
189 static HRESULT WINAPI IDirectSoundBufferImpl_SetFormat(
190 LPDIRECTSOUNDBUFFER8 iface,LPCWAVEFORMATEX wfex
192 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
194 TRACE("(%p,%p)\n",This,wfex);
195 /* This method is not available on secondary buffers */
196 WARN("invalid call\n");
197 return DSERR_INVALIDCALL;
200 static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume(
201 LPDIRECTSOUNDBUFFER8 iface,LONG vol
203 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
204 LONG oldVol;
205 HRESULT hres = DS_OK;
207 TRACE("(%p,%ld)\n",This,vol);
209 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
210 WARN("control unavailable: This->dsbd.dwFlags = 0x%08lx\n", This->dsbd.dwFlags);
211 return DSERR_CONTROLUNAVAIL;
214 if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN)) {
215 WARN("invalid parameter: vol = %ld\n", vol);
216 return DSERR_INVALIDPARAM;
219 /* **** */
220 EnterCriticalSection(&(This->lock));
222 if (This->dsbd.dwFlags & DSBCAPS_CTRL3D) {
223 oldVol = This->ds3db_lVolume;
224 This->ds3db_lVolume = vol;
225 } else {
226 oldVol = This->volpan.lVolume;
227 This->volpan.lVolume = vol;
228 if (vol != oldVol)
229 DSOUND_RecalcVolPan(&(This->volpan));
232 if (vol != oldVol) {
233 if (This->hwbuf) {
234 hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
235 if (hres != DS_OK)
236 WARN("IDsDriverBuffer_SetVolumePan failed\n");
237 } else
238 DSOUND_ForceRemix(This);
241 LeaveCriticalSection(&(This->lock));
242 /* **** */
244 return hres;
247 static HRESULT WINAPI IDirectSoundBufferImpl_GetVolume(
248 LPDIRECTSOUNDBUFFER8 iface,LPLONG vol
250 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
251 TRACE("(%p,%p)\n",This,vol);
253 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
254 WARN("control unavailable\n");
255 return DSERR_CONTROLUNAVAIL;
258 if (vol == NULL) {
259 WARN("invalid parameter: vol == NULL\n");
260 return DSERR_INVALIDPARAM;
263 *vol = This->volpan.lVolume;
265 return DS_OK;
268 static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency(
269 LPDIRECTSOUNDBUFFER8 iface,DWORD freq
271 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
272 DWORD oldFreq;
274 TRACE("(%p,%ld)\n",This,freq);
276 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLFREQUENCY)) {
277 WARN("control unavailable\n");
278 return DSERR_CONTROLUNAVAIL;
281 if (freq == DSBFREQUENCY_ORIGINAL)
282 freq = This->pwfx->nSamplesPerSec;
284 if ((freq < DSBFREQUENCY_MIN) || (freq > DSBFREQUENCY_MAX)) {
285 WARN("invalid parameter: freq = %ld\n", freq);
286 return DSERR_INVALIDPARAM;
289 /* **** */
290 EnterCriticalSection(&(This->lock));
292 oldFreq = This->freq;
293 This->freq = freq;
294 if (freq != oldFreq) {
295 This->freqAdjust = (freq << DSOUND_FREQSHIFT) / This->device->pwfx->nSamplesPerSec;
296 This->nAvgBytesPerSec = freq * This->pwfx->nBlockAlign;
297 DSOUND_RecalcFormat(This);
298 if (!This->hwbuf)
299 DSOUND_ForceRemix(This);
302 LeaveCriticalSection(&(This->lock));
303 /* **** */
305 return DS_OK;
308 static HRESULT WINAPI IDirectSoundBufferImpl_Play(
309 LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags
311 HRESULT hres = DS_OK;
312 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
313 TRACE("(%p,%08lx,%08lx,%08lx)\n",This,reserved1,reserved2,flags);
315 /* **** */
316 EnterCriticalSection(&(This->lock));
318 This->playflags = flags;
319 if (This->state == STATE_STOPPED) {
320 This->leadin = TRUE;
321 This->startpos = This->buf_mixpos;
322 This->state = STATE_STARTING;
323 } else if (This->state == STATE_STOPPING)
324 This->state = STATE_PLAYING;
325 if (This->hwbuf) {
326 hres = IDsDriverBuffer_Play(This->hwbuf, 0, 0, This->playflags);
327 if (hres != DS_OK)
328 WARN("IDsDriverBuffer_Play failed\n");
329 else
330 This->state = STATE_PLAYING;
333 LeaveCriticalSection(&(This->lock));
334 /* **** */
336 return hres;
339 static HRESULT WINAPI IDirectSoundBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface)
341 HRESULT hres = DS_OK;
342 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
343 TRACE("(%p)\n",This);
345 /* **** */
346 EnterCriticalSection(&(This->lock));
348 if (This->state == STATE_PLAYING)
349 This->state = STATE_STOPPING;
350 else if (This->state == STATE_STARTING)
351 This->state = STATE_STOPPED;
352 if (This->hwbuf) {
353 hres = IDsDriverBuffer_Stop(This->hwbuf);
354 if (hres != DS_OK)
355 WARN("IDsDriverBuffer_Stop failed\n");
356 else
357 This->state = STATE_STOPPED;
359 DSOUND_CheckEvent(This, 0);
361 LeaveCriticalSection(&(This->lock));
362 /* **** */
364 return hres;
367 static ULONG WINAPI IDirectSoundBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface)
369 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
370 ULONG ref = InterlockedIncrement(&(This->ref));
371 TRACE("(%p) ref was %ld\n", This, ref - 1);
372 return ref;
375 static ULONG WINAPI IDirectSoundBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface)
377 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
378 ULONG ref = InterlockedDecrement(&(This->ref));
379 TRACE("(%p) ref was %ld\n", This, ref + 1);
381 if (!ref) {
382 DirectSoundDevice_RemoveBuffer(This->device, This);
384 This->lock.DebugInfo->Spare[0] = 0;
385 DeleteCriticalSection(&(This->lock));
387 if (This->hwbuf) {
388 IDsDriverBuffer_Release(This->hwbuf);
389 if (This->device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) {
390 This->buffer->ref--;
391 if (This->buffer->ref==0) {
392 HeapFree(GetProcessHeap(),0,This->buffer->memory);
393 HeapFree(GetProcessHeap(),0,This->buffer);
396 } else {
397 This->buffer->ref--;
398 if (This->buffer->ref==0) {
399 HeapFree(GetProcessHeap(),0,This->buffer->memory);
400 HeapFree(GetProcessHeap(),0,This->buffer);
404 HeapFree(GetProcessHeap(), 0, This->notifies);
405 HeapFree(GetProcessHeap(), 0, This->pwfx);
406 HeapFree(GetProcessHeap(), 0, This);
408 TRACE("(%p) released\n", This);
410 return ref;
413 DWORD DSOUND_CalcPlayPosition(IDirectSoundBufferImpl *This, DWORD pplay, DWORD pwrite)
415 DWORD bplay = This->buf_mixpos;
416 DWORD pmix = This->primary_mixpos;
417 DirectSoundDevice * device = This->device;
418 TRACE("(%p, pplay=%lu, pwrite=%lu)\n", This, pplay, pwrite);
420 /* the actual primary play position (pplay) is always behind last mixed (pmix),
421 * unless the computer is too slow or something */
422 /* we need to know how far away we are from there */
423 if (pmix < pplay) pmix += device->buflen; /* wraparound */
424 pmix -= pplay;
425 /* detect buffer underrun */
426 if (pwrite < pplay) pwrite += device->buflen; /* wraparound */
427 pwrite -= pplay;
428 if (pmix > (ds_snd_queue_max * device->fraglen + pwrite + device->writelead)) {
429 WARN("detected an underrun: primary queue was %ld\n",pmix);
430 pmix = 0;
432 /* divide the offset by its sample size */
433 pmix /= device->pwfx->nBlockAlign;
434 TRACE("primary back-samples=%ld\n",pmix);
435 /* adjust for our frequency */
436 pmix = (pmix * This->freqAdjust) >> DSOUND_FREQSHIFT;
437 /* multiply by our own sample size */
438 pmix *= This->pwfx->nBlockAlign;
439 TRACE("this back-offset=%ld\n", pmix);
440 /* subtract from our last mixed position */
441 while (bplay < pmix) bplay += This->buflen; /* wraparound */
442 bplay -= pmix;
443 if (This->leadin && ((bplay < This->startpos) || (bplay > This->buf_mixpos))) {
444 /* seems we haven't started playing yet */
445 TRACE("this still in lead-in phase\n");
446 bplay = This->startpos;
448 /* return the result */
449 return bplay;
452 static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(
453 LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos
455 HRESULT hres;
456 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
457 TRACE("(%p,%p,%p)\n",This,playpos,writepos);
458 if (This->hwbuf) {
459 hres=IDsDriverBuffer_GetPosition(This->hwbuf,playpos,writepos);
460 if (hres != DS_OK) {
461 WARN("IDsDriverBuffer_GetPosition failed\n");
462 return hres;
464 } else {
465 if (playpos && (This->state != STATE_PLAYING)) {
466 /* we haven't been merged into the primary buffer (yet) */
467 *playpos = This->buf_mixpos;
468 } else if (playpos) {
469 DWORD pplay, pwrite;
470 /* let's get this exact; first, recursively call GetPosition on the primary */
471 EnterCriticalSection(&(This->device->mixlock));
472 if (DSOUND_PrimaryGetPosition(This->device, &pplay, &pwrite) != DS_OK)
473 WARN("DSOUND_PrimaryGetPosition failed\n");
474 /* detect HEL mode underrun */
475 if (!(This->device->hwbuf || This->device->pwqueue))
476 TRACE("detected an underrun\n");
477 if ((This->dsbd.dwFlags & DSBCAPS_GETCURRENTPOSITION2) || This->device->hwbuf) {
478 /* calculate play position using this */
479 *playpos = DSOUND_CalcPlayPosition(This, pplay, pwrite);
480 } else {
481 /* (unless the app isn't using GETCURRENTPOSITION2) */
482 /* don't know exactly how this should be handled...
483 * the docs says that play cursor is reported as directly
484 * behind write cursor, hmm... */
485 /* let's just do what might work for Half-Life */
486 DWORD wp;
487 wp = (This->device->pwplay + ds_hel_margin) * This->device->fraglen;
488 wp %= This->device->buflen;
489 *playpos = DSOUND_CalcPlayPosition(This, wp, pwrite);
491 LeaveCriticalSection(&(This->device->mixlock));
493 if (writepos)
494 *writepos = This->buf_mixpos;
496 if (writepos) {
497 if (This->state != STATE_STOPPED) {
498 /* apply the documented 10ms lead to writepos */
499 *writepos += This->writelead;
501 *writepos %= This->buflen;
503 if (playpos)
504 This->last_playpos = *playpos;
505 TRACE("playpos = %ld, writepos = %ld (%p, time=%ld)\n", playpos?*playpos:0, writepos?*writepos:0, This, GetTickCount());
506 return DS_OK;
509 static HRESULT WINAPI IDirectSoundBufferImpl_GetStatus(
510 LPDIRECTSOUNDBUFFER8 iface,LPDWORD status
512 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
513 TRACE("(%p,%p), thread is %04lx\n",This,status,GetCurrentThreadId());
515 if (status == NULL) {
516 WARN("invalid parameter: status = NULL\n");
517 return DSERR_INVALIDPARAM;
520 *status = 0;
521 if ((This->state == STATE_STARTING) || (This->state == STATE_PLAYING)) {
522 *status |= DSBSTATUS_PLAYING;
523 if (This->playflags & DSBPLAY_LOOPING)
524 *status |= DSBSTATUS_LOOPING;
527 TRACE("status=%lx\n", *status);
528 return DS_OK;
532 static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat(
533 LPDIRECTSOUNDBUFFER8 iface,
534 LPWAVEFORMATEX lpwf,
535 DWORD wfsize,
536 LPDWORD wfwritten)
538 DWORD size;
539 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
540 TRACE("(%p,%p,%ld,%p)\n",This,lpwf,wfsize,wfwritten);
542 size = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;
544 if (lpwf) { /* NULL is valid */
545 if (wfsize >= size) {
546 CopyMemory(lpwf,This->pwfx,size);
547 if (wfwritten)
548 *wfwritten = size;
549 } else {
550 WARN("invalid parameter: wfsize too small\n");
551 if (wfwritten)
552 *wfwritten = 0;
553 return DSERR_INVALIDPARAM;
555 } else {
556 if (wfwritten)
557 *wfwritten = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;
558 else {
559 WARN("invalid parameter: wfwritten == NULL\n");
560 return DSERR_INVALIDPARAM;
564 return DS_OK;
567 static HRESULT WINAPI IDirectSoundBufferImpl_Lock(
568 LPDIRECTSOUNDBUFFER8 iface,DWORD writecursor,DWORD writebytes,LPVOID lplpaudioptr1,LPDWORD audiobytes1,LPVOID lplpaudioptr2,LPDWORD audiobytes2,DWORD flags
570 HRESULT hres = DS_OK;
571 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
573 TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx) at %ld\n",
574 This,
575 writecursor,
576 writebytes,
577 lplpaudioptr1,
578 audiobytes1,
579 lplpaudioptr2,
580 audiobytes2,
581 flags,
582 GetTickCount()
585 /* when this flag is set, writecursor is meaningless and must be calculated */
586 if (flags & DSBLOCK_FROMWRITECURSOR) {
587 /* GetCurrentPosition does too much magic to duplicate here */
588 hres = IDirectSoundBufferImpl_GetCurrentPosition(iface, NULL, &writecursor);
589 if (hres != DS_OK) {
590 WARN("IDirectSoundBufferImpl_GetCurrentPosition failed\n");
591 return hres;
595 /* when this flag is set, writebytes is meaningless and must be set */
596 if (flags & DSBLOCK_ENTIREBUFFER)
597 writebytes = This->buflen;
599 if (writecursor >= This->buflen) {
600 WARN("Invalid parameter, writecursor: %lu >= buflen: %lu\n",
601 writecursor, This->buflen);
602 return DSERR_INVALIDPARAM;
605 if (writebytes > This->buflen) {
606 WARN("Invalid parameter, writebytes: %lu > buflen: %lu\n",
607 writebytes, This->buflen);
608 return DSERR_INVALIDPARAM;
611 EnterCriticalSection(&(This->lock));
613 if ((writebytes == This->buflen) &&
614 ((This->state == STATE_STARTING) ||
615 (This->state == STATE_PLAYING)))
616 /* some games, like Half-Life, try to be clever (not) and
617 * keep one secondary buffer, and mix sounds into it itself,
618 * locking the entire buffer every time... so we can just forget
619 * about tracking the last-written-to-position... */
620 This->probably_valid_to = (DWORD)-1;
621 else
622 This->probably_valid_to = writecursor;
624 if (!(This->device->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
625 hres = IDsDriverBuffer_Lock(This->hwbuf,
626 lplpaudioptr1, audiobytes1,
627 lplpaudioptr2, audiobytes2,
628 writecursor, writebytes,
630 if (hres != DS_OK) {
631 WARN("IDsDriverBuffer_Lock failed\n");
632 LeaveCriticalSection(&(This->lock));
633 return hres;
635 } else {
636 BOOL remix = FALSE;
637 if (writecursor+writebytes <= This->buflen) {
638 *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
639 *audiobytes1 = writebytes;
640 if (lplpaudioptr2)
641 *(LPBYTE*)lplpaudioptr2 = NULL;
642 if (audiobytes2)
643 *audiobytes2 = 0;
644 TRACE("->%ld.0\n",writebytes);
645 } else {
646 *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
647 *audiobytes1 = This->buflen-writecursor;
648 if (lplpaudioptr2)
649 *(LPBYTE*)lplpaudioptr2 = This->buffer->memory;
650 if (audiobytes2)
651 *audiobytes2 = writebytes-(This->buflen-writecursor);
652 TRACE("->%ld.%ld\n",*audiobytes1,audiobytes2?*audiobytes2:0);
654 if (This->state == STATE_PLAYING) {
655 /* if the segment between playpos and buf_mixpos is touched,
656 * we need to cancel some mixing */
657 /* we'll assume that the app always calls GetCurrentPosition before
658 * locking a playing buffer, so that last_playpos is up-to-date */
659 if (This->buf_mixpos >= This->last_playpos) {
660 if (This->buf_mixpos > writecursor &&
661 This->last_playpos < writecursor+writebytes)
662 remix = TRUE;
663 } else {
664 if (This->buf_mixpos > writecursor ||
665 This->last_playpos < writecursor+writebytes)
666 remix = TRUE;
668 if (remix) {
669 TRACE("locking prebuffered region, ouch\n");
670 DSOUND_MixCancelAt(This, writecursor);
675 LeaveCriticalSection(&(This->lock));
677 return DS_OK;
680 static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(
681 LPDIRECTSOUNDBUFFER8 iface,DWORD newpos
683 HRESULT hres = DS_OK;
684 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
685 TRACE("(%p,%ld)\n",This,newpos);
687 /* **** */
688 EnterCriticalSection(&(This->lock));
690 newpos %= This->buflen;
691 This->buf_mixpos = newpos;
692 if (This->hwbuf) {
693 hres = IDsDriverBuffer_SetPosition(This->hwbuf, This->buf_mixpos);
694 if (hres != DS_OK)
695 WARN("IDsDriverBuffer_SetPosition failed\n");
698 LeaveCriticalSection(&(This->lock));
699 /* **** */
701 return hres;
704 static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(
705 LPDIRECTSOUNDBUFFER8 iface,LONG pan
707 HRESULT hres = DS_OK;
708 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
710 TRACE("(%p,%ld)\n",This,pan);
712 if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT)) {
713 WARN("invalid parameter: pan = %ld\n", pan);
714 return DSERR_INVALIDPARAM;
717 /* You cannot use both pan and 3D controls */
718 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
719 (This->dsbd.dwFlags & DSBCAPS_CTRL3D)) {
720 WARN("control unavailable\n");
721 return DSERR_CONTROLUNAVAIL;
724 /* **** */
725 EnterCriticalSection(&(This->lock));
727 if (This->volpan.lPan != pan) {
728 This->volpan.lPan = pan;
729 DSOUND_RecalcVolPan(&(This->volpan));
731 if (This->hwbuf) {
732 hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
733 if (hres != DS_OK)
734 WARN("IDsDriverBuffer_SetVolumePan failed\n");
735 } else
736 DSOUND_ForceRemix(This);
739 LeaveCriticalSection(&(This->lock));
740 /* **** */
742 return hres;
745 static HRESULT WINAPI IDirectSoundBufferImpl_GetPan(
746 LPDIRECTSOUNDBUFFER8 iface,LPLONG pan
748 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
749 TRACE("(%p,%p)\n",This,pan);
751 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN)) {
752 WARN("control unavailable\n");
753 return DSERR_CONTROLUNAVAIL;
756 if (pan == NULL) {
757 WARN("invalid parameter: pan = NULL\n");
758 return DSERR_INVALIDPARAM;
761 *pan = This->volpan.lPan;
763 return DS_OK;
766 static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(
767 LPDIRECTSOUNDBUFFER8 iface,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2
769 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
770 DWORD probably_valid_to;
771 HRESULT hres = DS_OK;
773 TRACE("(%p,%p,%ld,%p,%ld)\n", This,p1,x1,p2,x2);
775 /* **** */
776 EnterCriticalSection(&(This->lock));
778 if (!(This->device->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
779 hres = IDsDriverBuffer_Unlock(This->hwbuf, p1, x1, p2, x2);
780 if (hres != DS_OK)
781 WARN("IDsDriverBuffer_Unlock failed\n");
784 if (hres == DS_OK) {
785 if (p2) probably_valid_to = (((LPBYTE)p2)-This->buffer->memory) + x2;
786 else probably_valid_to = (((LPBYTE)p1)-This->buffer->memory) + x1;
787 probably_valid_to %= This->buflen;
788 if ((probably_valid_to == 0) && ((x1+x2) == This->buflen) &&
789 ((This->state == STATE_STARTING) ||
790 (This->state == STATE_PLAYING)))
791 /* see IDirectSoundBufferImpl_Lock */
792 probably_valid_to = (DWORD)-1;
793 This->probably_valid_to = probably_valid_to;
796 LeaveCriticalSection(&(This->lock));
797 /* **** */
799 TRACE("probably_valid_to=%ld\n", This->probably_valid_to);
800 return hres;
803 static HRESULT WINAPI IDirectSoundBufferImpl_Restore(
804 LPDIRECTSOUNDBUFFER8 iface
806 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
807 FIXME("(%p):stub\n",This);
808 return DS_OK;
811 static HRESULT WINAPI IDirectSoundBufferImpl_GetFrequency(
812 LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq
814 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
815 TRACE("(%p,%p)\n",This,freq);
817 if (freq == NULL) {
818 WARN("invalid parameter: freq = NULL\n");
819 return DSERR_INVALIDPARAM;
822 *freq = This->freq;
823 TRACE("-> %ld\n", *freq);
825 return DS_OK;
828 static HRESULT WINAPI IDirectSoundBufferImpl_SetFX(
829 LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes
831 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
832 DWORD u;
834 FIXME("(%p,%lu,%p,%p): stub\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
836 if (pdwResultCodes)
837 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
839 WARN("control unavailable\n");
840 return DSERR_CONTROLUNAVAIL;
843 static HRESULT WINAPI IDirectSoundBufferImpl_AcquireResources(
844 LPDIRECTSOUNDBUFFER8 iface,DWORD dwFlags,DWORD dwEffectsCount,LPDWORD pdwResultCodes
846 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
847 DWORD u;
849 FIXME("(%p,%08lu,%lu,%p): stub\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
851 if (pdwResultCodes)
852 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
854 WARN("control unavailable\n");
855 return DSERR_CONTROLUNAVAIL;
858 static HRESULT WINAPI IDirectSoundBufferImpl_GetObjectInPath(
859 LPDIRECTSOUNDBUFFER8 iface,REFGUID rguidObject,DWORD dwIndex,REFGUID rguidInterface,LPVOID* ppObject
861 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
863 FIXME("(%p,%s,%lu,%s,%p): stub\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
865 WARN("control unavailable\n");
866 return DSERR_CONTROLUNAVAIL;
869 static HRESULT WINAPI IDirectSoundBufferImpl_Initialize(
870 LPDIRECTSOUNDBUFFER8 iface,LPDIRECTSOUND dsound,LPCDSBUFFERDESC dbsd
872 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
873 FIXME("(%p,%p,%p):stub\n",This,dsound,dbsd);
874 DPRINTF("Re-Init!!!\n");
875 WARN("already initialized\n");
876 return DSERR_ALREADYINITIALIZED;
879 static HRESULT WINAPI IDirectSoundBufferImpl_GetCaps(
880 LPDIRECTSOUNDBUFFER8 iface,LPDSBCAPS caps
882 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
883 TRACE("(%p)->(%p)\n",This,caps);
885 if (caps == NULL) {
886 WARN("invalid parameter: caps == NULL\n");
887 return DSERR_INVALIDPARAM;
890 if (caps->dwSize < sizeof(*caps)) {
891 WARN("invalid parameter: caps->dwSize = %ld\n",caps->dwSize);
892 return DSERR_INVALIDPARAM;
895 caps->dwFlags = This->dsbd.dwFlags;
896 if (This->hwbuf) caps->dwFlags |= DSBCAPS_LOCHARDWARE;
897 else caps->dwFlags |= DSBCAPS_LOCSOFTWARE;
899 caps->dwBufferBytes = This->buflen;
901 /* This value represents the speed of the "unlock" command.
902 As unlock is quite fast (it does not do anything), I put
903 4096 ko/s = 4 Mo / s */
904 /* FIXME: hwbuf speed */
905 caps->dwUnlockTransferRate = 4096;
906 caps->dwPlayCpuOverhead = 0;
908 return DS_OK;
911 static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface(
912 LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj
914 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
916 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
918 if (ppobj == NULL) {
919 WARN("invalid parameter\n");
920 return E_INVALIDARG;
923 *ppobj = NULL; /* assume failure */
925 if ( IsEqualGUID(riid, &IID_IUnknown) ||
926 IsEqualGUID(riid, &IID_IDirectSoundBuffer) ||
927 IsEqualGUID(riid, &IID_IDirectSoundBuffer8) ) {
928 if (!This->secondary)
929 SecondaryBufferImpl_Create(This, &(This->secondary));
930 if (This->secondary) {
931 IDirectSoundBuffer8_AddRef((LPDIRECTSOUNDBUFFER8)This->secondary);
932 *ppobj = This->secondary;
933 return S_OK;
935 WARN("IID_IDirectSoundBuffer\n");
936 return E_NOINTERFACE;
939 if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
940 if (!This->notify)
941 IDirectSoundNotifyImpl_Create(This, &(This->notify));
942 if (This->notify) {
943 IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify);
944 *ppobj = This->notify;
945 return S_OK;
947 WARN("IID_IDirectSoundNotify\n");
948 return E_NOINTERFACE;
951 if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) {
952 if (!This->ds3db)
953 IDirectSound3DBufferImpl_Create(This, &(This->ds3db));
954 if (This->ds3db) {
955 IDirectSound3DBuffer_AddRef((LPDIRECTSOUND3DBUFFER)This->ds3db);
956 *ppobj = This->ds3db;
957 return S_OK;
959 WARN("IID_IDirectSound3DBuffer\n");
960 return E_NOINTERFACE;
963 if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
964 ERR("app requested IDirectSound3DListener on secondary buffer\n");
965 return E_NOINTERFACE;
968 if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) {
969 if (!This->iks)
970 IKsBufferPropertySetImpl_Create(This, &(This->iks));
971 if (This->iks) {
972 IKsPropertySet_AddRef((LPKSPROPERTYSET)This->iks);
973 *ppobj = This->iks;
974 return S_OK;
976 WARN("IID_IKsPropertySet\n");
977 return E_NOINTERFACE;
980 FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
982 return E_NOINTERFACE;
985 static const IDirectSoundBuffer8Vtbl dsbvt =
987 IDirectSoundBufferImpl_QueryInterface,
988 IDirectSoundBufferImpl_AddRef,
989 IDirectSoundBufferImpl_Release,
990 IDirectSoundBufferImpl_GetCaps,
991 IDirectSoundBufferImpl_GetCurrentPosition,
992 IDirectSoundBufferImpl_GetFormat,
993 IDirectSoundBufferImpl_GetVolume,
994 IDirectSoundBufferImpl_GetPan,
995 IDirectSoundBufferImpl_GetFrequency,
996 IDirectSoundBufferImpl_GetStatus,
997 IDirectSoundBufferImpl_Initialize,
998 IDirectSoundBufferImpl_Lock,
999 IDirectSoundBufferImpl_Play,
1000 IDirectSoundBufferImpl_SetCurrentPosition,
1001 IDirectSoundBufferImpl_SetFormat,
1002 IDirectSoundBufferImpl_SetVolume,
1003 IDirectSoundBufferImpl_SetPan,
1004 IDirectSoundBufferImpl_SetFrequency,
1005 IDirectSoundBufferImpl_Stop,
1006 IDirectSoundBufferImpl_Unlock,
1007 IDirectSoundBufferImpl_Restore,
1008 IDirectSoundBufferImpl_SetFX,
1009 IDirectSoundBufferImpl_AcquireResources,
1010 IDirectSoundBufferImpl_GetObjectInPath
1013 HRESULT IDirectSoundBufferImpl_Create(
1014 DirectSoundDevice * device,
1015 IDirectSoundBufferImpl **pdsb,
1016 LPCDSBUFFERDESC dsbd)
1018 IDirectSoundBufferImpl *dsb;
1019 LPWAVEFORMATEX wfex = dsbd->lpwfxFormat;
1020 HRESULT err = DS_OK;
1021 DWORD capf = 0;
1022 int use_hw, alloc_size, cp_size;
1023 TRACE("(%p,%p,%p)\n",device,pdsb,dsbd);
1025 if (dsbd->dwBufferBytes < DSBSIZE_MIN || dsbd->dwBufferBytes > DSBSIZE_MAX) {
1026 WARN("invalid parameter: dsbd->dwBufferBytes = %ld\n", dsbd->dwBufferBytes);
1027 *pdsb = NULL;
1028 return DSERR_INVALIDPARAM; /* FIXME: which error? */
1031 dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
1033 if (dsb == 0) {
1034 WARN("out of memory\n");
1035 *pdsb = NULL;
1036 return DSERR_OUTOFMEMORY;
1039 TRACE("Created buffer at %p\n", dsb);
1041 dsb->ref = 0;
1042 dsb->secondary = 0;
1043 dsb->device = device;
1044 dsb->lpVtbl = &dsbvt;
1045 dsb->iks = NULL;
1047 /* size depends on version */
1048 CopyMemory(&dsb->dsbd, dsbd, dsbd->dwSize);
1050 /* variable sized struct so calculate size based on format */
1051 if (wfex->wFormatTag == WAVE_FORMAT_PCM) {
1052 alloc_size = sizeof(WAVEFORMATEX);
1053 cp_size = sizeof(PCMWAVEFORMAT);
1054 } else
1055 alloc_size = cp_size = sizeof(WAVEFORMATEX) + wfex->cbSize;
1057 dsb->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,alloc_size);
1058 if (dsb->pwfx == NULL) {
1059 WARN("out of memory\n");
1060 HeapFree(GetProcessHeap(),0,dsb);
1061 *pdsb = NULL;
1062 return DSERR_OUTOFMEMORY;
1065 CopyMemory(dsb->pwfx, wfex, cp_size);
1067 if (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign)
1068 dsb->buflen = dsbd->dwBufferBytes +
1069 (dsbd->lpwfxFormat->nBlockAlign -
1070 (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign));
1071 else
1072 dsb->buflen = dsbd->dwBufferBytes;
1074 dsb->freq = dsbd->lpwfxFormat->nSamplesPerSec;
1075 dsb->notify = NULL;
1076 dsb->notifies = NULL;
1077 dsb->nrofnotifies = 0;
1078 dsb->hwnotify = 0;
1080 /* Check necessary hardware mixing capabilities */
1081 if (wfex->nChannels==2) capf |= DSCAPS_SECONDARYSTEREO;
1082 else capf |= DSCAPS_SECONDARYMONO;
1083 if (wfex->wBitsPerSample==16) capf |= DSCAPS_SECONDARY16BIT;
1084 else capf |= DSCAPS_SECONDARY8BIT;
1086 use_hw = (device->drvcaps.dwFlags & capf) == capf;
1087 TRACE("use_hw = 0x%08x, capf = 0x%08lx, device->drvcaps.dwFlags = 0x%08lx\n", use_hw, capf, device->drvcaps.dwFlags);
1089 /* FIXME: check hardware sample rate mixing capabilities */
1090 /* FIXME: check app hints for software/hardware buffer (STATIC, LOCHARDWARE, etc) */
1091 /* FIXME: check whether any hardware buffers are left */
1092 /* FIXME: handle DSDHEAP_CREATEHEAP for hardware buffers */
1094 /* Allocate an empty buffer */
1095 dsb->buffer = HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb->buffer)));
1096 if (dsb->buffer == NULL) {
1097 WARN("out of memory\n");
1098 HeapFree(GetProcessHeap(),0,dsb->pwfx);
1099 HeapFree(GetProcessHeap(),0,dsb);
1100 *pdsb = NULL;
1101 return DSERR_OUTOFMEMORY;
1104 /* Allocate system memory for buffer if applicable */
1105 if ((device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) || !use_hw) {
1106 dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen);
1107 if (dsb->buffer->memory == NULL) {
1108 WARN("out of memory\n");
1109 HeapFree(GetProcessHeap(),0,dsb->pwfx);
1110 HeapFree(GetProcessHeap(),0,dsb->buffer);
1111 HeapFree(GetProcessHeap(),0,dsb);
1112 *pdsb = NULL;
1113 return DSERR_OUTOFMEMORY;
1115 dsb->buffer->ref = 1;
1116 FillMemory(dsb->buffer->memory, dsb->buflen, dsbd->lpwfxFormat->wBitsPerSample == 8 ? 128 : 0);
1119 /* Allocate the hardware buffer */
1120 if (use_hw) {
1121 err = IDsDriver_CreateSoundBuffer(device->driver,wfex,dsbd->dwFlags,0,
1122 &(dsb->buflen),&(dsb->buffer->memory),
1123 (LPVOID*)&(dsb->hwbuf));
1124 /* fall back to software buffer on failure */
1125 if (err != DS_OK) {
1126 TRACE("IDsDriver_CreateSoundBuffer failed, falling back to software buffer\n");
1127 use_hw = 0;
1128 if (device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) {
1129 dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen);
1130 if (dsb->buffer->memory == NULL) {
1131 WARN("out of memory\n");
1132 HeapFree(GetProcessHeap(),0,dsb->buffer);
1133 HeapFree(GetProcessHeap(),0,dsb->pwfx);
1134 HeapFree(GetProcessHeap(),0,dsb);
1135 *pdsb = NULL;
1136 return DSERR_OUTOFMEMORY;
1138 dsb->buffer->ref = 1;
1139 FillMemory(dsb->buffer->memory, dsb->buflen, dsbd->lpwfxFormat->wBitsPerSample == 8 ? 128 : 0);
1141 err = DS_OK;
1145 /* calculate fragment size and write lead */
1146 DSOUND_RecalcFormat(dsb);
1148 /* It's not necessary to initialize values to zero since */
1149 /* we allocated this structure with HEAP_ZERO_MEMORY... */
1150 dsb->playpos = 0;
1151 dsb->buf_mixpos = 0;
1152 dsb->state = STATE_STOPPED;
1154 dsb->freqAdjust = (dsb->freq << DSOUND_FREQSHIFT) /
1155 device->pwfx->nSamplesPerSec;
1156 dsb->nAvgBytesPerSec = dsb->freq *
1157 dsbd->lpwfxFormat->nBlockAlign;
1159 if (dsb->dsbd.dwFlags & DSBCAPS_CTRL3D) {
1160 dsb->ds3db_ds3db.dwSize = sizeof(DS3DBUFFER);
1161 dsb->ds3db_ds3db.vPosition.x = 0.0;
1162 dsb->ds3db_ds3db.vPosition.y = 0.0;
1163 dsb->ds3db_ds3db.vPosition.z = 0.0;
1164 dsb->ds3db_ds3db.vVelocity.x = 0.0;
1165 dsb->ds3db_ds3db.vVelocity.y = 0.0;
1166 dsb->ds3db_ds3db.vVelocity.z = 0.0;
1167 dsb->ds3db_ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
1168 dsb->ds3db_ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
1169 dsb->ds3db_ds3db.vConeOrientation.x = 0.0;
1170 dsb->ds3db_ds3db.vConeOrientation.y = 0.0;
1171 dsb->ds3db_ds3db.vConeOrientation.z = 0.0;
1172 dsb->ds3db_ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
1173 dsb->ds3db_ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE;
1174 dsb->ds3db_ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
1175 dsb->ds3db_ds3db.dwMode = DS3DMODE_NORMAL;
1177 dsb->ds3db_need_recalc = FALSE;
1178 DSOUND_Calc3DBuffer(dsb);
1179 } else
1180 DSOUND_RecalcVolPan(&(dsb->volpan));
1182 InitializeCriticalSection(&(dsb->lock));
1183 dsb->lock.DebugInfo->Spare[0] = (DWORD_PTR)"DSOUNDBUFFER_lock";
1185 /* register buffer if not primary */
1186 if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
1187 err = DirectSoundDevice_AddBuffer(device, dsb);
1188 if (err != DS_OK) {
1189 HeapFree(GetProcessHeap(),0,dsb->buffer->memory);
1190 HeapFree(GetProcessHeap(),0,dsb->buffer);
1191 dsb->lock.DebugInfo->Spare[0] = 0;
1192 DeleteCriticalSection(&(dsb->lock));
1193 HeapFree(GetProcessHeap(),0,dsb->pwfx);
1194 HeapFree(GetProcessHeap(),0,dsb);
1195 dsb = NULL;
1199 *pdsb = dsb;
1200 return err;
1203 HRESULT IDirectSoundBufferImpl_Destroy(
1204 IDirectSoundBufferImpl *pdsb)
1206 TRACE("(%p)\n",pdsb);
1208 /* This keeps the *_Destroy functions from possibly deleting
1209 * this object until it is ready to be deleted */
1210 IDirectSoundBufferImpl_AddRef((LPDIRECTSOUNDBUFFER8)pdsb);
1212 if (pdsb->iks) {
1213 WARN("iks not NULL\n");
1214 IKsBufferPropertySetImpl_Destroy(pdsb->iks);
1215 pdsb->iks = NULL;
1218 if (pdsb->ds3db) {
1219 WARN("ds3db not NULL\n");
1220 IDirectSound3DBufferImpl_Destroy(pdsb->ds3db);
1221 pdsb->ds3db = NULL;
1224 if (pdsb->notify) {
1225 WARN("notify not NULL\n");
1226 IDirectSoundNotifyImpl_Destroy(pdsb->notify);
1227 pdsb->notify = NULL;
1230 if (pdsb->secondary) {
1231 WARN("dsb not NULL\n");
1232 SecondaryBufferImpl_Destroy(pdsb->secondary);
1233 pdsb->secondary = NULL;
1236 while (IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)pdsb) > 0);
1238 return S_OK;
1241 HRESULT IDirectSoundBufferImpl_Duplicate(
1242 DirectSoundDevice *device,
1243 IDirectSoundBufferImpl **ppdsb,
1244 IDirectSoundBufferImpl *pdsb)
1246 IDirectSoundBufferImpl *dsb;
1247 HRESULT hres = DS_OK;
1248 int size;
1249 TRACE("(%p,%p,%p)\n", device, pdsb, pdsb);
1251 dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
1253 if (dsb == NULL) {
1254 WARN("out of memory\n");
1255 *ppdsb = NULL;
1256 return DSERR_OUTOFMEMORY;
1259 CopyMemory(dsb, pdsb, sizeof(IDirectSoundBufferImpl));
1261 if (pdsb->hwbuf) {
1262 TRACE("duplicating hardware buffer\n");
1264 hres = IDsDriver_DuplicateSoundBuffer(device->driver, pdsb->hwbuf,
1265 (LPVOID *)&dsb->hwbuf);
1266 if (hres != DS_OK) {
1267 TRACE("IDsDriver_DuplicateSoundBuffer failed, falling back to "
1268 "software buffer\n");
1269 dsb->hwbuf = NULL;
1270 /* allocate buffer */
1271 if (device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) {
1272 dsb->buffer = HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb->buffer)));
1273 if (dsb->buffer == NULL) {
1274 WARN("out of memory\n");
1275 HeapFree(GetProcessHeap(),0,dsb);
1276 *ppdsb = NULL;
1277 return DSERR_OUTOFMEMORY;
1280 dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen);
1281 if (dsb->buffer->memory == NULL) {
1282 WARN("out of memory\n");
1283 HeapFree(GetProcessHeap(),0,dsb->buffer);
1284 HeapFree(GetProcessHeap(),0,dsb);
1285 *ppdsb = NULL;
1286 return DSERR_OUTOFMEMORY;
1288 dsb->buffer->ref = 1;
1290 /* FIXME: copy buffer ? */
1293 } else {
1294 dsb->hwbuf = NULL;
1295 dsb->buffer->ref++;
1298 dsb->ref = 0;
1299 dsb->state = STATE_STOPPED;
1300 dsb->playpos = 0;
1301 dsb->buf_mixpos = 0;
1302 dsb->device = device;
1303 dsb->ds3db = NULL;
1304 dsb->iks = NULL; /* FIXME? */
1305 dsb->secondary = NULL;
1307 /* variable sized struct so calculate size based on format */
1308 size = sizeof(WAVEFORMATEX) + pdsb->pwfx->cbSize;
1310 dsb->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
1311 if (dsb->pwfx == NULL) {
1312 WARN("out of memory\n");
1313 HeapFree(GetProcessHeap(),0,dsb->buffer);
1314 HeapFree(GetProcessHeap(),0,dsb);
1315 *ppdsb = NULL;
1316 return DSERR_OUTOFMEMORY;
1319 CopyMemory(dsb->pwfx, pdsb->pwfx, size);
1321 InitializeCriticalSection(&(dsb->lock));
1322 dsb->lock.DebugInfo->Spare[0] = (DWORD_PTR)"DSOUNDBUFFER_lock";
1324 /* register buffer */
1325 hres = DirectSoundDevice_AddBuffer(device, dsb);
1326 if (hres != DS_OK) {
1327 dsb->lock.DebugInfo->Spare[0] = 0;
1328 DeleteCriticalSection(&(dsb->lock));
1329 HeapFree(GetProcessHeap(),0,dsb->buffer);
1330 HeapFree(GetProcessHeap(),0,dsb->pwfx);
1331 HeapFree(GetProcessHeap(),0,dsb);
1332 *ppdsb = 0;
1335 *ppdsb = dsb;
1336 return hres;
1339 /*******************************************************************************
1340 * SecondaryBuffer
1343 static HRESULT WINAPI SecondaryBufferImpl_QueryInterface(
1344 LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj)
1346 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1347 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
1349 return IDirectSoundBufferImpl_QueryInterface((LPDIRECTSOUNDBUFFER8)This->dsb,riid,ppobj);
1352 static ULONG WINAPI SecondaryBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface)
1354 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1355 ULONG ref = InterlockedIncrement(&(This->ref));
1356 TRACE("(%p) ref was %ld\n", This, ref - 1);
1357 return ref;
1360 static ULONG WINAPI SecondaryBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface)
1362 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1363 ULONG ref;
1364 TRACE("(%p)\n", This);
1365 ref = InterlockedDecrement(&(This->ref));
1366 TRACE("ref was %ld\n", ref + 1);
1368 if (!ref) {
1369 This->dsb->secondary = NULL;
1370 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER8)This->dsb);
1371 HeapFree(GetProcessHeap(), 0, This);
1372 TRACE("(%p) released\n", This);
1374 return ref;
1377 static HRESULT WINAPI SecondaryBufferImpl_GetCaps(
1378 LPDIRECTSOUNDBUFFER8 iface,LPDSBCAPS caps)
1380 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1381 TRACE("(%p)->(%p)\n",This,caps);
1383 return IDirectSoundBufferImpl_GetCaps((LPDIRECTSOUNDBUFFER8)This->dsb,caps);
1386 static HRESULT WINAPI SecondaryBufferImpl_GetCurrentPosition(
1387 LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos)
1389 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1390 TRACE("(%p,%p,%p)\n",This,playpos,writepos);
1392 return IDirectSoundBufferImpl_GetCurrentPosition((LPDIRECTSOUNDBUFFER8)This->dsb,playpos,writepos);
1395 static HRESULT WINAPI SecondaryBufferImpl_GetFormat(
1396 LPDIRECTSOUNDBUFFER8 iface,LPWAVEFORMATEX lpwf,DWORD wfsize,LPDWORD wfwritten)
1398 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1399 TRACE("(%p,%p,%ld,%p)\n",This,lpwf,wfsize,wfwritten);
1401 return IDirectSoundBufferImpl_GetFormat((LPDIRECTSOUNDBUFFER8)This->dsb,lpwf,wfsize,wfwritten);
1404 static HRESULT WINAPI SecondaryBufferImpl_GetVolume(
1405 LPDIRECTSOUNDBUFFER8 iface,LPLONG vol)
1407 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1408 TRACE("(%p,%p)\n",This,vol);
1410 return IDirectSoundBufferImpl_GetVolume((LPDIRECTSOUNDBUFFER8)This->dsb,vol);
1413 static HRESULT WINAPI SecondaryBufferImpl_GetPan(
1414 LPDIRECTSOUNDBUFFER8 iface,LPLONG pan)
1416 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1417 TRACE("(%p,%p)\n",This,pan);
1419 return IDirectSoundBufferImpl_GetPan((LPDIRECTSOUNDBUFFER8)This->dsb,pan);
1422 static HRESULT WINAPI SecondaryBufferImpl_GetFrequency(
1423 LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq)
1425 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1426 TRACE("(%p,%p)\n",This,freq);
1428 return IDirectSoundBufferImpl_GetFrequency((LPDIRECTSOUNDBUFFER8)This->dsb,freq);
1431 static HRESULT WINAPI SecondaryBufferImpl_GetStatus(
1432 LPDIRECTSOUNDBUFFER8 iface,LPDWORD status)
1434 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1435 TRACE("(%p,%p)\n",This,status);
1437 return IDirectSoundBufferImpl_GetStatus((LPDIRECTSOUNDBUFFER8)This->dsb,status);
1440 static HRESULT WINAPI SecondaryBufferImpl_Initialize(
1441 LPDIRECTSOUNDBUFFER8 iface,LPDIRECTSOUND dsound,LPCDSBUFFERDESC dbsd)
1443 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1444 TRACE("(%p,%p,%p)\n",This,dsound,dbsd);
1446 return IDirectSoundBufferImpl_Initialize((LPDIRECTSOUNDBUFFER8)This->dsb,dsound,dbsd);
1449 static HRESULT WINAPI SecondaryBufferImpl_Lock(
1450 LPDIRECTSOUNDBUFFER8 iface,
1451 DWORD writecursor,
1452 DWORD writebytes,
1453 LPVOID lplpaudioptr1,
1454 LPDWORD audiobytes1,
1455 LPVOID lplpaudioptr2,
1456 LPDWORD audiobytes2,
1457 DWORD dwFlags)
1459 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1460 TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx)\n",
1461 This,writecursor,writebytes,lplpaudioptr1,audiobytes1,lplpaudioptr2,audiobytes2,dwFlags);
1463 return IDirectSoundBufferImpl_Lock((LPDIRECTSOUNDBUFFER8)This->dsb,
1464 writecursor,writebytes,lplpaudioptr1,audiobytes1,lplpaudioptr2,audiobytes2,dwFlags);
1467 static HRESULT WINAPI SecondaryBufferImpl_Play(
1468 LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags)
1470 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1471 TRACE("(%p,%08lx,%08lx,%08lx)\n",This,reserved1,reserved2,flags);
1473 return IDirectSoundBufferImpl_Play((LPDIRECTSOUNDBUFFER8)This->dsb,reserved1,reserved2,flags);
1476 static HRESULT WINAPI SecondaryBufferImpl_SetCurrentPosition(
1477 LPDIRECTSOUNDBUFFER8 iface,DWORD newpos)
1479 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1480 TRACE("(%p,%ld)\n",This,newpos);
1482 return IDirectSoundBufferImpl_SetCurrentPosition((LPDIRECTSOUNDBUFFER8)This->dsb,newpos);
1485 static HRESULT WINAPI SecondaryBufferImpl_SetFormat(
1486 LPDIRECTSOUNDBUFFER8 iface,LPCWAVEFORMATEX wfex)
1488 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1489 TRACE("(%p,%p)\n",This,wfex);
1491 return IDirectSoundBufferImpl_SetFormat((LPDIRECTSOUNDBUFFER8)This->dsb,wfex);
1494 static HRESULT WINAPI SecondaryBufferImpl_SetVolume(
1495 LPDIRECTSOUNDBUFFER8 iface,LONG vol)
1497 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1498 TRACE("(%p,%ld)\n",This,vol);
1500 return IDirectSoundBufferImpl_SetVolume((LPDIRECTSOUNDBUFFER8)This->dsb,vol);
1503 static HRESULT WINAPI SecondaryBufferImpl_SetPan(
1504 LPDIRECTSOUNDBUFFER8 iface,LONG pan)
1506 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1507 TRACE("(%p,%ld)\n",This,pan);
1509 return IDirectSoundBufferImpl_SetPan((LPDIRECTSOUNDBUFFER8)This->dsb,pan);
1512 static HRESULT WINAPI SecondaryBufferImpl_SetFrequency(
1513 LPDIRECTSOUNDBUFFER8 iface,DWORD freq)
1515 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1516 TRACE("(%p,%ld)\n",This,freq);
1518 return IDirectSoundBufferImpl_SetFrequency((LPDIRECTSOUNDBUFFER8)This->dsb,freq);
1521 static HRESULT WINAPI SecondaryBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface)
1523 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1524 TRACE("(%p)\n",This);
1526 return IDirectSoundBufferImpl_Stop((LPDIRECTSOUNDBUFFER8)This->dsb);
1529 static HRESULT WINAPI SecondaryBufferImpl_Unlock(
1530 LPDIRECTSOUNDBUFFER8 iface,
1531 LPVOID lpvAudioPtr1,
1532 DWORD dwAudioBytes1,
1533 LPVOID lpvAudioPtr2,
1534 DWORD dwAudioBytes2)
1536 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1537 TRACE("(%p,%p,%ld,%p,%ld)\n",
1538 This, lpvAudioPtr1, dwAudioBytes1, lpvAudioPtr2, dwAudioBytes2);
1540 return IDirectSoundBufferImpl_Unlock((LPDIRECTSOUNDBUFFER8)This->dsb,
1541 lpvAudioPtr1,dwAudioBytes1,lpvAudioPtr2,dwAudioBytes2);
1544 static HRESULT WINAPI SecondaryBufferImpl_Restore(
1545 LPDIRECTSOUNDBUFFER8 iface)
1547 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1548 TRACE("(%p)\n",This);
1550 return IDirectSoundBufferImpl_Restore((LPDIRECTSOUNDBUFFER8)This->dsb);
1553 static HRESULT WINAPI SecondaryBufferImpl_SetFX(
1554 LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes)
1556 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1557 TRACE("(%p,%lu,%p,%p)\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
1559 return IDirectSoundBufferImpl_SetFX((LPDIRECTSOUNDBUFFER8)This->dsb,dwEffectsCount,pDSFXDesc,pdwResultCodes);
1562 static HRESULT WINAPI SecondaryBufferImpl_AcquireResources(
1563 LPDIRECTSOUNDBUFFER8 iface,DWORD dwFlags,DWORD dwEffectsCount,LPDWORD pdwResultCodes)
1565 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1566 TRACE("(%p,%08lu,%lu,%p)\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
1568 return IDirectSoundBufferImpl_AcquireResources((LPDIRECTSOUNDBUFFER8)This->dsb,dwFlags,dwEffectsCount,pdwResultCodes);
1571 static HRESULT WINAPI SecondaryBufferImpl_GetObjectInPath(
1572 LPDIRECTSOUNDBUFFER8 iface,REFGUID rguidObject,DWORD dwIndex,REFGUID rguidInterface,LPVOID* ppObject)
1574 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1575 TRACE("(%p,%s,%lu,%s,%p)\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
1577 return IDirectSoundBufferImpl_GetObjectInPath((LPDIRECTSOUNDBUFFER8)This->dsb,rguidObject,dwIndex,rguidInterface,ppObject);
1580 static const IDirectSoundBuffer8Vtbl sbvt =
1582 SecondaryBufferImpl_QueryInterface,
1583 SecondaryBufferImpl_AddRef,
1584 SecondaryBufferImpl_Release,
1585 SecondaryBufferImpl_GetCaps,
1586 SecondaryBufferImpl_GetCurrentPosition,
1587 SecondaryBufferImpl_GetFormat,
1588 SecondaryBufferImpl_GetVolume,
1589 SecondaryBufferImpl_GetPan,
1590 SecondaryBufferImpl_GetFrequency,
1591 SecondaryBufferImpl_GetStatus,
1592 SecondaryBufferImpl_Initialize,
1593 SecondaryBufferImpl_Lock,
1594 SecondaryBufferImpl_Play,
1595 SecondaryBufferImpl_SetCurrentPosition,
1596 SecondaryBufferImpl_SetFormat,
1597 SecondaryBufferImpl_SetVolume,
1598 SecondaryBufferImpl_SetPan,
1599 SecondaryBufferImpl_SetFrequency,
1600 SecondaryBufferImpl_Stop,
1601 SecondaryBufferImpl_Unlock,
1602 SecondaryBufferImpl_Restore,
1603 SecondaryBufferImpl_SetFX,
1604 SecondaryBufferImpl_AcquireResources,
1605 SecondaryBufferImpl_GetObjectInPath
1608 HRESULT SecondaryBufferImpl_Create(
1609 IDirectSoundBufferImpl *dsb,
1610 SecondaryBufferImpl **psb)
1612 SecondaryBufferImpl *sb;
1613 TRACE("(%p,%p)\n",dsb,psb);
1615 sb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*sb));
1617 if (sb == 0) {
1618 WARN("out of memory\n");
1619 *psb = NULL;
1620 return DSERR_OUTOFMEMORY;
1622 sb->ref = 0;
1623 sb->dsb = dsb;
1624 sb->lpVtbl = &sbvt;
1626 IDirectSoundBuffer8_AddRef((LPDIRECTSOUNDBUFFER8)dsb);
1627 *psb = sb;
1628 return S_OK;
1631 static HRESULT SecondaryBufferImpl_Destroy(
1632 SecondaryBufferImpl *pdsb)
1634 TRACE("(%p)\n",pdsb);
1636 while (SecondaryBufferImpl_Release((LPDIRECTSOUNDBUFFER8)pdsb) > 0);
1638 return S_OK;