dsound: Correct deallocations when DuplicateSoundBuffer fails.
[wine] / dlls / dsound / buffer.c
1 /*                      DirectSound
2  *
3  * Copyright 1998 Marcus Meissner
4  * Copyright 1998 Rob Riggs
5  * Copyright 2000-2002 TransGaming Technologies, Inc.
6  *
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.
11  *
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.
16  *
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
20  */
21
22 #include <stdarg.h>
23
24 #define NONAMELESSSTRUCT
25 #define NONAMELESSUNION
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "mmsystem.h"
30 #include "winternl.h"
31 #include "wine/debug.h"
32 #include "dsound.h"
33 #include "dsdriver.h"
34 #include "dsound_private.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
37
38 static HRESULT SecondaryBufferImpl_Destroy(SecondaryBufferImpl *pdsb);
39
40 /*******************************************************************************
41  *              IDirectSoundNotify
42  */
43
44 struct IDirectSoundNotifyImpl
45 {
46     /* IUnknown fields */
47     const IDirectSoundNotifyVtbl *lpVtbl;
48     LONG                        ref;
49     IDirectSoundBufferImpl*     dsb;
50 };
51
52 static HRESULT IDirectSoundNotifyImpl_Create(IDirectSoundBufferImpl *dsb,
53                                              IDirectSoundNotifyImpl **pdsn);
54 static HRESULT IDirectSoundNotifyImpl_Destroy(IDirectSoundNotifyImpl *pdsn);
55
56 static HRESULT WINAPI IDirectSoundNotifyImpl_QueryInterface(
57         LPDIRECTSOUNDNOTIFY iface,REFIID riid,LPVOID *ppobj
58 ) {
59         IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
60         TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
61
62         if (This->dsb == NULL) {
63                 WARN("invalid parameter\n");
64                 return E_INVALIDARG;
65         }
66
67         return IDirectSoundBuffer_QueryInterface((LPDIRECTSOUNDBUFFER)This->dsb, riid, ppobj);
68 }
69
70 static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface)
71 {
72     IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
73     ULONG ref = InterlockedIncrement(&(This->ref));
74     TRACE("(%p) ref was %d\n", This, ref - 1);
75     return ref;
76 }
77
78 static ULONG WINAPI IDirectSoundNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface)
79 {
80     IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
81     ULONG ref = InterlockedDecrement(&(This->ref));
82     TRACE("(%p) ref was %d\n", This, ref + 1);
83
84     if (!ref) {
85         This->dsb->notify = NULL;
86         IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->dsb);
87         HeapFree(GetProcessHeap(), 0, This);
88         TRACE("(%p) released\n", This);
89     }
90     return ref;
91 }
92
93 static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(
94         LPDIRECTSOUNDNOTIFY iface,DWORD howmuch,LPCDSBPOSITIONNOTIFY notify
95 ) {
96         IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
97         TRACE("(%p,0x%08x,%p)\n",This,howmuch,notify);
98
99         if (howmuch > 0 && notify == NULL) {
100             WARN("invalid parameter: notify == NULL\n");
101             return DSERR_INVALIDPARAM;
102         }
103
104         if (TRACE_ON(dsound)) {
105             unsigned int        i;
106             for (i=0;i<howmuch;i++)
107                 TRACE("notify at %d to %p\n",
108                     notify[i].dwOffset,notify[i].hEventNotify);
109         }
110
111         if (This->dsb->hwnotify) {
112             HRESULT hres;
113             hres = IDsDriverNotify_SetNotificationPositions(This->dsb->hwnotify, howmuch, notify);
114             if (hres != DS_OK)
115                     WARN("IDsDriverNotify_SetNotificationPositions failed\n");
116             return hres;
117         } else if (howmuch > 0) {
118             /* Make an internal copy of the caller-supplied array.
119              * Replace the existing copy if one is already present. */
120             HeapFree(GetProcessHeap(), 0, This->dsb->notifies);
121             This->dsb->notifies = HeapAlloc(GetProcessHeap(), 0,
122                         howmuch * sizeof(DSBPOSITIONNOTIFY));
123
124             if (This->dsb->notifies == NULL) {
125                     WARN("out of memory\n");
126                     return DSERR_OUTOFMEMORY;
127             }
128             CopyMemory(This->dsb->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
129             This->dsb->nrofnotifies = howmuch;
130         } else {
131            HeapFree(GetProcessHeap(), 0, This->dsb->notifies);
132            This->dsb->notifies = NULL;
133            This->dsb->nrofnotifies = 0;
134         }
135
136         return S_OK;
137 }
138
139 static const IDirectSoundNotifyVtbl dsnvt =
140 {
141     IDirectSoundNotifyImpl_QueryInterface,
142     IDirectSoundNotifyImpl_AddRef,
143     IDirectSoundNotifyImpl_Release,
144     IDirectSoundNotifyImpl_SetNotificationPositions,
145 };
146
147 static HRESULT IDirectSoundNotifyImpl_Create(
148     IDirectSoundBufferImpl * dsb,
149     IDirectSoundNotifyImpl **pdsn)
150 {
151     IDirectSoundNotifyImpl * dsn;
152     TRACE("(%p,%p)\n",dsb,pdsn);
153
154     dsn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dsn));
155
156     if (dsn == NULL) {
157         WARN("out of memory\n");
158         return DSERR_OUTOFMEMORY;
159     }
160
161     dsn->ref = 0;
162     dsn->lpVtbl = &dsnvt;
163     dsn->dsb = dsb;
164     dsb->notify = dsn;
165     IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)dsb);
166
167     *pdsn = dsn;
168     return DS_OK;
169 }
170
171 static HRESULT IDirectSoundNotifyImpl_Destroy(
172     IDirectSoundNotifyImpl *pdsn)
173 {
174     TRACE("(%p)\n",pdsn);
175
176     while (IDirectSoundNotifyImpl_Release((LPDIRECTSOUNDNOTIFY)pdsn) > 0);
177
178     return DS_OK;
179 }
180
181 /*******************************************************************************
182  *              IDirectSoundBuffer
183  */
184
185 static HRESULT WINAPI IDirectSoundBufferImpl_SetFormat(
186         LPDIRECTSOUNDBUFFER8 iface,LPCWAVEFORMATEX wfex
187 ) {
188         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
189
190         TRACE("(%p,%p)\n",This,wfex);
191         /* This method is not available on secondary buffers */
192         WARN("invalid call\n");
193         return DSERR_INVALIDCALL;
194 }
195
196 static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume(
197         LPDIRECTSOUNDBUFFER8 iface,LONG vol
198 ) {
199         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
200         LONG oldVol;
201         HRESULT hres = DS_OK;
202
203         TRACE("(%p,%d)\n",This,vol);
204
205         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
206                 WARN("control unavailable: This->dsbd.dwFlags = 0x%08x\n", This->dsbd.dwFlags);
207                 return DSERR_CONTROLUNAVAIL;
208         }
209
210         if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN)) {
211                 WARN("invalid parameter: vol = %d\n", vol);
212                 return DSERR_INVALIDPARAM;
213         }
214
215         /* **** */
216         RtlAcquireResourceExclusive(&This->lock, TRUE);
217
218         if (This->dsbd.dwFlags & DSBCAPS_CTRL3D) {
219                 oldVol = This->ds3db_lVolume;
220                 This->ds3db_lVolume = vol;
221                 if (vol != oldVol)
222                         /* recalc 3d volume, which in turn recalcs the pans */
223                         DSOUND_Calc3DBuffer(This);
224         } else {
225                 oldVol = This->volpan.lVolume;
226                 This->volpan.lVolume = vol;
227                 if (vol != oldVol)
228                         DSOUND_RecalcVolPan(&(This->volpan));
229         }
230
231         if (vol != oldVol) {
232                 if (This->hwbuf) {
233                         hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
234                         if (hres != DS_OK)
235                                 WARN("IDsDriverBuffer_SetVolumePan failed\n");
236                 }
237         }
238
239         RtlReleaseResource(&This->lock);
240         /* **** */
241
242         return hres;
243 }
244
245 static HRESULT WINAPI IDirectSoundBufferImpl_GetVolume(
246         LPDIRECTSOUNDBUFFER8 iface,LPLONG vol
247 ) {
248         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
249         TRACE("(%p,%p)\n",This,vol);
250
251         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
252                 WARN("control unavailable\n");
253                 return DSERR_CONTROLUNAVAIL;
254         }
255
256         if (vol == NULL) {
257                 WARN("invalid parameter: vol == NULL\n");
258                 return DSERR_INVALIDPARAM;
259         }
260
261         *vol = This->volpan.lVolume;
262
263         return DS_OK;
264 }
265
266 static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency(
267         LPDIRECTSOUNDBUFFER8 iface,DWORD freq
268 ) {
269         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
270         DWORD oldFreq;
271
272         TRACE("(%p,%d)\n",This,freq);
273
274         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLFREQUENCY)) {
275                 WARN("control unavailable\n");
276                 return DSERR_CONTROLUNAVAIL;
277         }
278
279         if (freq == DSBFREQUENCY_ORIGINAL)
280                 freq = This->pwfx->nSamplesPerSec;
281
282         if ((freq < DSBFREQUENCY_MIN) || (freq > DSBFREQUENCY_MAX)) {
283                 WARN("invalid parameter: freq = %d\n", freq);
284                 return DSERR_INVALIDPARAM;
285         }
286
287         /* **** */
288         RtlAcquireResourceExclusive(&This->lock, TRUE);
289
290         oldFreq = This->freq;
291         This->freq = freq;
292         if (freq != oldFreq) {
293                 This->freqAdjust = ((DWORD64)This->freq << DSOUND_FREQSHIFT) / This->device->pwfx->nSamplesPerSec;
294                 This->nAvgBytesPerSec = freq * This->pwfx->nBlockAlign;
295                 DSOUND_RecalcFormat(This);
296                 DSOUND_MixToTemporary(This, 0, This->buflen, FALSE);
297         }
298
299         RtlReleaseResource(&This->lock);
300         /* **** */
301
302         return DS_OK;
303 }
304
305 static HRESULT WINAPI IDirectSoundBufferImpl_Play(
306         LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags
307 ) {
308         HRESULT hres = DS_OK;
309         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
310         TRACE("(%p,%08x,%08x,%08x)\n",This,reserved1,reserved2,flags);
311
312         /* **** */
313         RtlAcquireResourceExclusive(&This->lock, TRUE);
314
315         This->playflags = flags;
316         if (This->state == STATE_STOPPED && !This->hwbuf) {
317                 This->leadin = TRUE;
318                 This->state = STATE_STARTING;
319         } else if (This->state == STATE_STOPPING)
320                 This->state = STATE_PLAYING;
321         if (This->hwbuf) {
322                 hres = IDsDriverBuffer_Play(This->hwbuf, 0, 0, This->playflags);
323                 if (hres != DS_OK)
324                         WARN("IDsDriverBuffer_Play failed\n");
325                 else
326                         This->state = STATE_PLAYING;
327         }
328
329         RtlReleaseResource(&This->lock);
330         /* **** */
331
332         return hres;
333 }
334
335 static HRESULT WINAPI IDirectSoundBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface)
336 {
337         HRESULT hres = DS_OK;
338         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
339         TRACE("(%p)\n",This);
340
341         /* **** */
342         RtlAcquireResourceExclusive(&This->lock, TRUE);
343
344         if (This->state == STATE_PLAYING)
345                 This->state = STATE_STOPPING;
346         else if (This->state == STATE_STARTING)
347         {
348                 This->state = STATE_STOPPED;
349                 DSOUND_CheckEvent(This, 0, 0);
350         }
351         if (This->hwbuf) {
352                 hres = IDsDriverBuffer_Stop(This->hwbuf);
353                 if (hres != DS_OK)
354                         WARN("IDsDriverBuffer_Stop failed\n");
355                 else
356                         This->state = STATE_STOPPED;
357         }
358
359         RtlReleaseResource(&This->lock);
360         /* **** */
361
362         return hres;
363 }
364
365 static ULONG WINAPI IDirectSoundBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface)
366 {
367     IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
368     ULONG ref = InterlockedIncrement(&(This->ref));
369     TRACE("(%p) ref was %d\n", This, ref - 1);
370     return ref;
371 }
372
373 static ULONG WINAPI IDirectSoundBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface)
374 {
375     IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
376     ULONG ref = InterlockedDecrement(&(This->ref));
377     TRACE("(%p) ref was %d\n", This, ref + 1);
378
379     if (!ref) {
380         DirectSoundDevice_RemoveBuffer(This->device, This);
381         RtlDeleteResource(&This->lock);
382
383         if (This->hwbuf)
384                 IDsDriverBuffer_Release(This->hwbuf);
385         if (!This->hwbuf || (This->device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY)) {
386                 This->buffer->ref--;
387                 list_remove(&This->entry);
388                 if (This->buffer->ref==0) {
389                         HeapFree(GetProcessHeap(),0,This->buffer->memory);
390                         HeapFree(GetProcessHeap(),0,This->buffer);
391                 }
392         }
393
394         HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
395         HeapFree(GetProcessHeap(), 0, This->notifies);
396         HeapFree(GetProcessHeap(), 0, This->pwfx);
397         HeapFree(GetProcessHeap(), 0, This);
398
399         TRACE("(%p) released\n", This);
400     }
401     return ref;
402 }
403
404 static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(
405         LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos
406 ) {
407         HRESULT hres;
408         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
409         TRACE("(%p,%p,%p)\n",This,playpos,writepos);
410
411         RtlAcquireResourceShared(&This->lock, TRUE);
412         if (This->hwbuf) {
413                 hres=IDsDriverBuffer_GetPosition(This->hwbuf,playpos,writepos);
414                 if (hres != DS_OK) {
415                     WARN("IDsDriverBuffer_GetPosition failed\n");
416                     return hres;
417                 }
418         } else {
419                 DWORD pos = This->sec_mixpos;
420
421                 /* sanity */
422                 if (pos >= This->buflen){
423                         FIXME("Bad play position. playpos: %d, buflen: %d\n", pos, This->buflen);
424                         pos %= This->buflen;
425                 }
426
427                 if (playpos)
428                         *playpos = pos;
429                 if (writepos)
430                         *writepos = pos;
431         }
432         if (writepos && This->state != STATE_STOPPED && (!This->hwbuf || !(This->device->drvdesc.dwFlags & DSDDESC_DONTNEEDWRITELEAD))) {
433                 /* apply the documented 10ms lead to writepos */
434                 *writepos += This->writelead;
435                 *writepos %= This->buflen;
436         }
437         RtlReleaseResource(&This->lock);
438
439         TRACE("playpos = %d, writepos = %d, buflen=%d (%p, time=%d)\n",
440                 playpos?*playpos:-1, writepos?*writepos:-1, This->buflen, This, GetTickCount());
441
442         return DS_OK;
443 }
444
445 static HRESULT WINAPI IDirectSoundBufferImpl_GetStatus(
446         LPDIRECTSOUNDBUFFER8 iface,LPDWORD status
447 ) {
448         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
449         TRACE("(%p,%p), thread is %04x\n",This,status,GetCurrentThreadId());
450
451         if (status == NULL) {
452                 WARN("invalid parameter: status = NULL\n");
453                 return DSERR_INVALIDPARAM;
454         }
455
456         *status = 0;
457         RtlAcquireResourceShared(&This->lock, TRUE);
458         if ((This->state == STATE_STARTING) || (This->state == STATE_PLAYING)) {
459                 *status |= DSBSTATUS_PLAYING;
460                 if (This->playflags & DSBPLAY_LOOPING)
461                         *status |= DSBSTATUS_LOOPING;
462         }
463         RtlReleaseResource(&This->lock);
464
465         TRACE("status=%x\n", *status);
466         return DS_OK;
467 }
468
469
470 static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat(
471     LPDIRECTSOUNDBUFFER8 iface,
472     LPWAVEFORMATEX lpwf,
473     DWORD wfsize,
474     LPDWORD wfwritten)
475 {
476     DWORD size;
477     IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
478     TRACE("(%p,%p,%d,%p)\n",This,lpwf,wfsize,wfwritten);
479
480     size = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;
481
482     if (lpwf) { /* NULL is valid */
483         if (wfsize >= size) {
484             CopyMemory(lpwf,This->pwfx,size);
485             if (wfwritten)
486                 *wfwritten = size;
487         } else {
488             WARN("invalid parameter: wfsize too small\n");
489             CopyMemory(lpwf,This->pwfx,wfsize);
490             if (wfwritten)
491                 *wfwritten = wfsize;
492             return DSERR_INVALIDPARAM;
493         }
494     } else {
495         if (wfwritten)
496             *wfwritten = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;
497         else {
498             WARN("invalid parameter: wfwritten == NULL\n");
499             return DSERR_INVALIDPARAM;
500         }
501     }
502
503     return DS_OK;
504 }
505
506 static HRESULT WINAPI IDirectSoundBufferImpl_Lock(
507         LPDIRECTSOUNDBUFFER8 iface,DWORD writecursor,DWORD writebytes,LPVOID *lplpaudioptr1,LPDWORD audiobytes1,LPVOID *lplpaudioptr2,LPDWORD audiobytes2,DWORD flags
508 ) {
509         HRESULT hres = DS_OK;
510         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
511
512         TRACE("(%p,%d,%d,%p,%p,%p,%p,0x%08x) at %d\n",
513                 This,
514                 writecursor,
515                 writebytes,
516                 lplpaudioptr1,
517                 audiobytes1,
518                 lplpaudioptr2,
519                 audiobytes2,
520                 flags,
521                 GetTickCount()
522         );
523
524         if (!audiobytes1)
525             return DSERR_INVALIDPARAM;
526
527         /* when this flag is set, writecursor is meaningless and must be calculated */
528         if (flags & DSBLOCK_FROMWRITECURSOR) {
529                 /* GetCurrentPosition does too much magic to duplicate here */
530                 hres = IDirectSoundBufferImpl_GetCurrentPosition(iface, NULL, &writecursor);
531                 if (hres != DS_OK) {
532                         WARN("IDirectSoundBufferImpl_GetCurrentPosition failed\n");
533                         return hres;
534                 }
535         }
536
537         /* when this flag is set, writebytes is meaningless and must be set */
538         if (flags & DSBLOCK_ENTIREBUFFER)
539                 writebytes = This->buflen;
540
541         if (writecursor >= This->buflen) {
542                 WARN("Invalid parameter, writecursor: %u >= buflen: %u\n",
543                      writecursor, This->buflen);
544                 return DSERR_INVALIDPARAM;
545         }
546
547         if (writebytes > This->buflen) {
548                 WARN("Invalid parameter, writebytes: %u > buflen: %u\n",
549                      writebytes, This->buflen);
550                 return DSERR_INVALIDPARAM;
551         }
552
553         /* **** */
554         RtlAcquireResourceShared(&This->lock, TRUE);
555
556         if (!(This->device->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
557                 hres = IDsDriverBuffer_Lock(This->hwbuf,
558                                      lplpaudioptr1, audiobytes1,
559                                      lplpaudioptr2, audiobytes2,
560                                      writecursor, writebytes,
561                                      0);
562                 if (hres != DS_OK) {
563                         WARN("IDsDriverBuffer_Lock failed\n");
564                         RtlReleaseResource(&This->lock);
565                         return hres;
566                 }
567         } else {
568                 if (writecursor+writebytes <= This->buflen) {
569                         *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
570                         if (This->sec_mixpos >= writecursor && This->sec_mixpos < writecursor + writebytes && This->state == STATE_PLAYING)
571                                 WARN("Overwriting mixing position, case 1\n");
572                         *audiobytes1 = writebytes;
573                         if (lplpaudioptr2)
574                                 *(LPBYTE*)lplpaudioptr2 = NULL;
575                         if (audiobytes2)
576                                 *audiobytes2 = 0;
577                         TRACE("Locked %p(%i bytes) and %p(%i bytes) writecursor=%d\n",
578                           *(LPBYTE*)lplpaudioptr1, *audiobytes1, lplpaudioptr2 ? *(LPBYTE*)lplpaudioptr2 : NULL, audiobytes2 ? *audiobytes2: 0, writecursor);
579                         TRACE("->%d.0\n",writebytes);
580                 } else {
581                         DWORD remainder = writebytes + writecursor - This->buflen;
582                         *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
583                         *audiobytes1 = This->buflen-writecursor;
584                         if (This->sec_mixpos >= writecursor && This->sec_mixpos < writecursor + writebytes && This->state == STATE_PLAYING)
585                                 WARN("Overwriting mixing position, case 2\n");
586                         if (lplpaudioptr2)
587                                 *(LPBYTE*)lplpaudioptr2 = This->buffer->memory;
588                         if (audiobytes2)
589                                 *audiobytes2 = writebytes-(This->buflen-writecursor);
590                         if (audiobytes2 && This->sec_mixpos < remainder && This->state == STATE_PLAYING)
591                                 WARN("Overwriting mixing position, case 3\n");
592                         TRACE("Locked %p(%i bytes) and %p(%i bytes) writecursor=%d\n", *(LPBYTE*)lplpaudioptr1, *audiobytes1, lplpaudioptr2 ? *(LPBYTE*)lplpaudioptr2 : NULL, audiobytes2 ? *audiobytes2: 0, writecursor);
593                 }
594         }
595
596         RtlReleaseResource(&This->lock);
597         /* **** */
598
599         return DS_OK;
600 }
601
602 static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(
603         LPDIRECTSOUNDBUFFER8 iface,DWORD newpos
604 ) {
605         HRESULT hres = DS_OK;
606         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
607         DWORD oldpos;
608         TRACE("(%p,%d)\n",This,newpos);
609
610         /* **** */
611         RtlAcquireResourceExclusive(&This->lock, TRUE);
612
613         oldpos = This->sec_mixpos;
614
615         /* start mixing from this new location instead */
616         newpos %= This->buflen;
617         newpos -= newpos%This->pwfx->nBlockAlign;
618         This->sec_mixpos = newpos;
619
620         /* at this point, do not attempt to reset buffers, mess with primary mix position,
621            or anything like that to reduce latancy. The data already prebuffered cannot be changed */
622
623         /* position HW buffer if applicable, else just start mixing from new location instead */
624         if (This->hwbuf) {
625                 hres = IDsDriverBuffer_SetPosition(This->hwbuf, This->buf_mixpos);
626                 if (hres != DS_OK)
627                         WARN("IDsDriverBuffer_SetPosition failed\n");
628         }
629         else if (oldpos != newpos)
630                 /* FIXME: Perhaps add a call to DSOUND_MixToTemporary here? Not sure it's needed */
631                 This->buf_mixpos = DSOUND_secpos_to_bufpos(This, newpos, 0, NULL);
632
633         RtlReleaseResource(&This->lock);
634         /* **** */
635
636         return hres;
637 }
638
639 static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(
640         LPDIRECTSOUNDBUFFER8 iface,LONG pan
641 ) {
642         HRESULT hres = DS_OK;
643         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
644
645         TRACE("(%p,%d)\n",This,pan);
646
647         if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT)) {
648                 WARN("invalid parameter: pan = %d\n", pan);
649                 return DSERR_INVALIDPARAM;
650         }
651
652         /* You cannot use both pan and 3D controls */
653         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
654             (This->dsbd.dwFlags & DSBCAPS_CTRL3D)) {
655                 WARN("control unavailable\n");
656                 return DSERR_CONTROLUNAVAIL;
657         }
658
659         /* **** */
660         RtlAcquireResourceExclusive(&This->lock, TRUE);
661
662         if (This->volpan.lPan != pan) {
663                 This->volpan.lPan = pan;
664                 DSOUND_RecalcVolPan(&(This->volpan));
665
666                 if (This->hwbuf) {
667                         hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
668                         if (hres != DS_OK)
669                                 WARN("IDsDriverBuffer_SetVolumePan failed\n");
670                 }
671         }
672
673         RtlReleaseResource(&This->lock);
674         /* **** */
675
676         return hres;
677 }
678
679 static HRESULT WINAPI IDirectSoundBufferImpl_GetPan(
680         LPDIRECTSOUNDBUFFER8 iface,LPLONG pan
681 ) {
682         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
683         TRACE("(%p,%p)\n",This,pan);
684
685         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN)) {
686                 WARN("control unavailable\n");
687                 return DSERR_CONTROLUNAVAIL;
688         }
689
690         if (pan == NULL) {
691                 WARN("invalid parameter: pan = NULL\n");
692                 return DSERR_INVALIDPARAM;
693         }
694
695         *pan = This->volpan.lPan;
696
697         return DS_OK;
698 }
699
700 static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(
701         LPDIRECTSOUNDBUFFER8 iface,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2
702 ) {
703         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface, *iter;
704         HRESULT hres = DS_OK;
705
706         TRACE("(%p,%p,%d,%p,%d)\n", This,p1,x1,p2,x2);
707
708         /* **** */
709         RtlAcquireResourceShared(&This->lock, TRUE);
710
711         if (!(This->device->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
712                 hres = IDsDriverBuffer_Unlock(This->hwbuf, p1, x1, p2, x2);
713                 if (hres != DS_OK)
714                         WARN("IDsDriverBuffer_Unlock failed\n");
715         }
716
717         RtlReleaseResource(&This->lock);
718         /* **** */
719
720         if (!p2)
721                 x2 = 0;
722
723         if (!This->hwbuf && (x1 || x2))
724         {
725                 RtlAcquireResourceShared(&This->device->buffer_list_lock, TRUE);
726                 LIST_FOR_EACH_ENTRY(iter, &This->buffer->buffers, IDirectSoundBufferImpl, entry )
727                 {
728                         RtlAcquireResourceShared(&iter->lock, TRUE);
729                         if (x1)
730                         {
731                             if(x1 + (DWORD_PTR)p1 - (DWORD_PTR)iter->buffer->memory > iter->buflen)
732                               hres = DSERR_INVALIDPARAM;
733                             else
734                               DSOUND_MixToTemporary(iter, (DWORD_PTR)p1 - (DWORD_PTR)iter->buffer->memory, x1, FALSE);
735                         }
736                         if (x2)
737                                 DSOUND_MixToTemporary(iter, 0, x2, FALSE);
738                         RtlReleaseResource(&iter->lock);
739                 }
740                 RtlReleaseResource(&This->device->buffer_list_lock);
741         }
742
743         return hres;
744 }
745
746 static HRESULT WINAPI IDirectSoundBufferImpl_Restore(
747         LPDIRECTSOUNDBUFFER8 iface
748 ) {
749         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
750         FIXME("(%p):stub\n",This);
751         return DS_OK;
752 }
753
754 static HRESULT WINAPI IDirectSoundBufferImpl_GetFrequency(
755         LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq
756 ) {
757         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
758         TRACE("(%p,%p)\n",This,freq);
759
760         if (freq == NULL) {
761                 WARN("invalid parameter: freq = NULL\n");
762                 return DSERR_INVALIDPARAM;
763         }
764
765         *freq = This->freq;
766         TRACE("-> %d\n", *freq);
767
768         return DS_OK;
769 }
770
771 static HRESULT WINAPI IDirectSoundBufferImpl_SetFX(
772         LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes
773 ) {
774         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
775         DWORD u;
776
777         FIXME("(%p,%u,%p,%p): stub\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
778
779         if (pdwResultCodes)
780                 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
781
782         WARN("control unavailable\n");
783         return DSERR_CONTROLUNAVAIL;
784 }
785
786 static HRESULT WINAPI IDirectSoundBufferImpl_AcquireResources(
787         LPDIRECTSOUNDBUFFER8 iface,DWORD dwFlags,DWORD dwEffectsCount,LPDWORD pdwResultCodes
788 ) {
789         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
790         DWORD u;
791
792         FIXME("(%p,%08u,%u,%p): stub\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
793
794         if (pdwResultCodes)
795                 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
796
797         WARN("control unavailable\n");
798         return DSERR_CONTROLUNAVAIL;
799 }
800
801 static HRESULT WINAPI IDirectSoundBufferImpl_GetObjectInPath(
802         LPDIRECTSOUNDBUFFER8 iface,REFGUID rguidObject,DWORD dwIndex,REFGUID rguidInterface,LPVOID* ppObject
803 ) {
804         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
805
806         FIXME("(%p,%s,%u,%s,%p): stub\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
807
808         WARN("control unavailable\n");
809         return DSERR_CONTROLUNAVAIL;
810 }
811
812 static HRESULT WINAPI IDirectSoundBufferImpl_Initialize(
813         LPDIRECTSOUNDBUFFER8 iface,LPDIRECTSOUND dsound,LPCDSBUFFERDESC dbsd
814 ) {
815         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
816         WARN("(%p) already initialized\n", This);
817         return DSERR_ALREADYINITIALIZED;
818 }
819
820 static HRESULT WINAPI IDirectSoundBufferImpl_GetCaps(
821         LPDIRECTSOUNDBUFFER8 iface,LPDSBCAPS caps
822 ) {
823         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
824         TRACE("(%p)->(%p)\n",This,caps);
825
826         if (caps == NULL) {
827                 WARN("invalid parameter: caps == NULL\n");
828                 return DSERR_INVALIDPARAM;
829         }
830
831         if (caps->dwSize < sizeof(*caps)) {
832                 WARN("invalid parameter: caps->dwSize = %d\n",caps->dwSize);
833                 return DSERR_INVALIDPARAM;
834         }
835
836         caps->dwFlags = This->dsbd.dwFlags;
837         if (This->hwbuf) caps->dwFlags |= DSBCAPS_LOCHARDWARE;
838         else caps->dwFlags |= DSBCAPS_LOCSOFTWARE;
839
840         caps->dwBufferBytes = This->buflen;
841
842         /* According to windows, this is zero*/
843         caps->dwUnlockTransferRate = 0;
844         caps->dwPlayCpuOverhead = 0;
845
846         return DS_OK;
847 }
848
849 static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface(
850         LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj
851 ) {
852         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
853
854         TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
855
856         if (ppobj == NULL) {
857                 WARN("invalid parameter\n");
858                 return E_INVALIDARG;
859         }
860
861         *ppobj = NULL;  /* assume failure */
862
863         if ( IsEqualGUID(riid, &IID_IUnknown) ||
864              IsEqualGUID(riid, &IID_IDirectSoundBuffer) ||
865              IsEqualGUID(riid, &IID_IDirectSoundBuffer8) ) {
866                 if (!This->secondary)
867                         SecondaryBufferImpl_Create(This, &(This->secondary));
868                 if (This->secondary) {
869                         IDirectSoundBuffer8_AddRef((LPDIRECTSOUNDBUFFER8)This->secondary);
870                         *ppobj = This->secondary;
871                         return S_OK;
872                 }
873                 WARN("IID_IDirectSoundBuffer\n");
874                 return E_NOINTERFACE;
875         }
876
877         if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
878                 if (!This->notify)
879                         IDirectSoundNotifyImpl_Create(This, &(This->notify));
880                 if (This->notify) {
881                         IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify);
882                         *ppobj = This->notify;
883                         return S_OK;
884                 }
885                 WARN("IID_IDirectSoundNotify\n");
886                 return E_NOINTERFACE;
887         }
888
889         if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) {
890                 if (!This->ds3db)
891                         IDirectSound3DBufferImpl_Create(This, &(This->ds3db));
892                 if (This->ds3db) {
893                         IDirectSound3DBuffer_AddRef((LPDIRECTSOUND3DBUFFER)This->ds3db);
894                         *ppobj = This->ds3db;
895                         return S_OK;
896                 }
897                 WARN("IID_IDirectSound3DBuffer\n");
898                 return E_NOINTERFACE;
899         }
900
901         if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
902                 ERR("app requested IDirectSound3DListener on secondary buffer\n");
903                 return E_NOINTERFACE;
904         }
905
906         if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) {
907                 if (!This->iks)
908                         IKsBufferPropertySetImpl_Create(This, &(This->iks));
909                 if (This->iks) {
910                         IKsPropertySet_AddRef((LPKSPROPERTYSET)This->iks);
911                         *ppobj = This->iks;
912                         return S_OK;
913                 }
914                 WARN("IID_IKsPropertySet\n");
915                 return E_NOINTERFACE;
916         }
917
918         FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
919
920         return E_NOINTERFACE;
921 }
922
923 static const IDirectSoundBuffer8Vtbl dsbvt =
924 {
925         IDirectSoundBufferImpl_QueryInterface,
926         IDirectSoundBufferImpl_AddRef,
927         IDirectSoundBufferImpl_Release,
928         IDirectSoundBufferImpl_GetCaps,
929         IDirectSoundBufferImpl_GetCurrentPosition,
930         IDirectSoundBufferImpl_GetFormat,
931         IDirectSoundBufferImpl_GetVolume,
932         IDirectSoundBufferImpl_GetPan,
933         IDirectSoundBufferImpl_GetFrequency,
934         IDirectSoundBufferImpl_GetStatus,
935         IDirectSoundBufferImpl_Initialize,
936         IDirectSoundBufferImpl_Lock,
937         IDirectSoundBufferImpl_Play,
938         IDirectSoundBufferImpl_SetCurrentPosition,
939         IDirectSoundBufferImpl_SetFormat,
940         IDirectSoundBufferImpl_SetVolume,
941         IDirectSoundBufferImpl_SetPan,
942         IDirectSoundBufferImpl_SetFrequency,
943         IDirectSoundBufferImpl_Stop,
944         IDirectSoundBufferImpl_Unlock,
945         IDirectSoundBufferImpl_Restore,
946         IDirectSoundBufferImpl_SetFX,
947         IDirectSoundBufferImpl_AcquireResources,
948         IDirectSoundBufferImpl_GetObjectInPath
949 };
950
951 HRESULT IDirectSoundBufferImpl_Create(
952         DirectSoundDevice * device,
953         IDirectSoundBufferImpl **pdsb,
954         LPCDSBUFFERDESC dsbd)
955 {
956         IDirectSoundBufferImpl *dsb;
957         LPWAVEFORMATEX wfex = dsbd->lpwfxFormat;
958         HRESULT err = DS_OK;
959         DWORD capf = 0;
960         int use_hw;
961         TRACE("(%p,%p,%p)\n",device,pdsb,dsbd);
962
963         if (dsbd->dwBufferBytes < DSBSIZE_MIN || dsbd->dwBufferBytes > DSBSIZE_MAX) {
964                 WARN("invalid parameter: dsbd->dwBufferBytes = %d\n", dsbd->dwBufferBytes);
965                 *pdsb = NULL;
966                 return DSERR_INVALIDPARAM; /* FIXME: which error? */
967         }
968
969         dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
970
971         if (dsb == 0) {
972                 WARN("out of memory\n");
973                 *pdsb = NULL;
974                 return DSERR_OUTOFMEMORY;
975         }
976
977         TRACE("Created buffer at %p\n", dsb);
978
979         dsb->ref = 0;
980         dsb->secondary = 0;
981         dsb->device = device;
982         dsb->lpVtbl = &dsbvt;
983         dsb->iks = NULL;
984
985         /* size depends on version */
986         CopyMemory(&dsb->dsbd, dsbd, dsbd->dwSize);
987
988         dsb->pwfx = DSOUND_CopyFormat(wfex);
989         if (dsb->pwfx == NULL) {
990                 HeapFree(GetProcessHeap(),0,dsb);
991                 *pdsb = NULL;
992                 return DSERR_OUTOFMEMORY;
993         }
994
995         if (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign)
996                 dsb->buflen = dsbd->dwBufferBytes + 
997                         (dsbd->lpwfxFormat->nBlockAlign - 
998                         (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign));
999         else
1000                 dsb->buflen = dsbd->dwBufferBytes;
1001
1002         dsb->freq = dsbd->lpwfxFormat->nSamplesPerSec;
1003         dsb->notify = NULL;
1004         dsb->notifies = NULL;
1005         dsb->nrofnotifies = 0;
1006         dsb->hwnotify = 0;
1007
1008         /* Check necessary hardware mixing capabilities */
1009         if (wfex->nChannels==2) capf |= DSCAPS_SECONDARYSTEREO;
1010         else capf |= DSCAPS_SECONDARYMONO;
1011         if (wfex->wBitsPerSample==16) capf |= DSCAPS_SECONDARY16BIT;
1012         else capf |= DSCAPS_SECONDARY8BIT;
1013
1014         use_hw = !!(dsbd->dwFlags & DSBCAPS_LOCHARDWARE);
1015         TRACE("use_hw = %d, capf = 0x%08x, device->drvcaps.dwFlags = 0x%08x\n", use_hw, capf, device->drvcaps.dwFlags);
1016         if (use_hw && ((device->drvcaps.dwFlags & capf) != capf || !device->driver))
1017         {
1018                 if (device->driver)
1019                         WARN("Format not supported for hardware buffer\n");
1020                 HeapFree(GetProcessHeap(),0,dsb->pwfx);
1021                 HeapFree(GetProcessHeap(),0,dsb);
1022                 *pdsb = NULL;
1023                 if ((device->drvcaps.dwFlags & capf) != capf)
1024                         return DSERR_BADFORMAT;
1025                 return DSERR_GENERIC;
1026         }
1027
1028         /* FIXME: check hardware sample rate mixing capabilities */
1029         /* FIXME: check app hints for software/hardware buffer (STATIC, LOCHARDWARE, etc) */
1030         /* FIXME: check whether any hardware buffers are left */
1031         /* FIXME: handle DSDHEAP_CREATEHEAP for hardware buffers */
1032
1033         /* Allocate an empty buffer */
1034         dsb->buffer = HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb->buffer)));
1035         if (dsb->buffer == NULL) {
1036                 WARN("out of memory\n");
1037                 HeapFree(GetProcessHeap(),0,dsb->pwfx);
1038                 HeapFree(GetProcessHeap(),0,dsb);
1039                 *pdsb = NULL;
1040                 return DSERR_OUTOFMEMORY;
1041         }
1042
1043         /* Allocate system memory for buffer if applicable */
1044         if ((device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) || !use_hw) {
1045                 dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen);
1046                 if (dsb->buffer->memory == NULL) {
1047                         WARN("out of memory\n");
1048                         HeapFree(GetProcessHeap(),0,dsb->pwfx);
1049                         HeapFree(GetProcessHeap(),0,dsb->buffer);
1050                         HeapFree(GetProcessHeap(),0,dsb);
1051                         *pdsb = NULL;
1052                         return DSERR_OUTOFMEMORY;
1053                 }
1054         }
1055
1056         /* Allocate the hardware buffer */
1057         if (use_hw) {
1058                 err = IDsDriver_CreateSoundBuffer(device->driver,wfex,dsbd->dwFlags,0,
1059                                                   &(dsb->buflen),&(dsb->buffer->memory),
1060                                                   (LPVOID*)&(dsb->hwbuf));
1061                 if (FAILED(err))
1062                 {
1063                         WARN("Failed to create hardware secondary buffer: %08x\n", err);
1064                         if (device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY)
1065                                 HeapFree(GetProcessHeap(),0,dsb->buffer->memory);
1066                         HeapFree(GetProcessHeap(),0,dsb->buffer);
1067                         HeapFree(GetProcessHeap(),0,dsb->pwfx);
1068                         HeapFree(GetProcessHeap(),0,dsb);
1069                         *pdsb = NULL;
1070                         return DSERR_GENERIC;
1071                 }
1072         }
1073
1074         dsb->buffer->ref = 1;
1075         list_init(&dsb->buffer->buffers);
1076         list_add_head(&dsb->buffer->buffers, &dsb->entry);
1077         FillMemory(dsb->buffer->memory, dsb->buflen, dsbd->lpwfxFormat->wBitsPerSample == 8 ? 128 : 0);
1078
1079         /* It's not necessary to initialize values to zero since */
1080         /* we allocated this structure with HEAP_ZERO_MEMORY... */
1081         dsb->buf_mixpos = dsb->sec_mixpos = 0;
1082         dsb->state = STATE_STOPPED;
1083
1084         dsb->freqAdjust = ((DWORD64)dsb->freq << DSOUND_FREQSHIFT) / device->pwfx->nSamplesPerSec;
1085         dsb->nAvgBytesPerSec = dsb->freq *
1086                 dsbd->lpwfxFormat->nBlockAlign;
1087
1088         /* calculate fragment size and write lead */
1089         DSOUND_RecalcFormat(dsb);
1090
1091         if (dsb->dsbd.dwFlags & DSBCAPS_CTRL3D) {
1092                 dsb->ds3db_ds3db.dwSize = sizeof(DS3DBUFFER);
1093                 dsb->ds3db_ds3db.vPosition.x = 0.0;
1094                 dsb->ds3db_ds3db.vPosition.y = 0.0;
1095                 dsb->ds3db_ds3db.vPosition.z = 0.0;
1096                 dsb->ds3db_ds3db.vVelocity.x = 0.0;
1097                 dsb->ds3db_ds3db.vVelocity.y = 0.0;
1098                 dsb->ds3db_ds3db.vVelocity.z = 0.0;
1099                 dsb->ds3db_ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
1100                 dsb->ds3db_ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
1101                 dsb->ds3db_ds3db.vConeOrientation.x = 0.0;
1102                 dsb->ds3db_ds3db.vConeOrientation.y = 0.0;
1103                 dsb->ds3db_ds3db.vConeOrientation.z = 0.0;
1104                 dsb->ds3db_ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
1105                 dsb->ds3db_ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE;
1106                 dsb->ds3db_ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
1107                 dsb->ds3db_ds3db.dwMode = DS3DMODE_NORMAL;
1108
1109                 dsb->ds3db_need_recalc = FALSE;
1110                 DSOUND_Calc3DBuffer(dsb);
1111         } else
1112                 DSOUND_RecalcVolPan(&(dsb->volpan));
1113
1114         RtlInitializeResource(&dsb->lock);
1115
1116         /* register buffer if not primary */
1117         if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
1118                 err = DirectSoundDevice_AddBuffer(device, dsb);
1119                 if (err != DS_OK) {
1120                         HeapFree(GetProcessHeap(),0,dsb->buffer->memory);
1121                         HeapFree(GetProcessHeap(),0,dsb->buffer);
1122                         RtlDeleteResource(&dsb->lock);
1123                         HeapFree(GetProcessHeap(),0,dsb->pwfx);
1124                         HeapFree(GetProcessHeap(),0,dsb);
1125                         dsb = NULL;
1126                 }
1127         }
1128
1129         *pdsb = dsb;
1130         return err;
1131 }
1132
1133 HRESULT IDirectSoundBufferImpl_Destroy(
1134     IDirectSoundBufferImpl *pdsb)
1135 {
1136     TRACE("(%p)\n",pdsb);
1137
1138     /* This keeps the *_Destroy functions from possibly deleting
1139      * this object until it is ready to be deleted */
1140     IDirectSoundBufferImpl_AddRef((LPDIRECTSOUNDBUFFER8)pdsb);
1141
1142     if (pdsb->iks) {
1143         WARN("iks not NULL\n");
1144         IKsBufferPropertySetImpl_Destroy(pdsb->iks);
1145         pdsb->iks = NULL;
1146     }
1147
1148     if (pdsb->ds3db) {
1149         WARN("ds3db not NULL\n");
1150         IDirectSound3DBufferImpl_Destroy(pdsb->ds3db);
1151         pdsb->ds3db = NULL;
1152     }
1153
1154     if (pdsb->notify) {
1155         WARN("notify not NULL\n");
1156         IDirectSoundNotifyImpl_Destroy(pdsb->notify);
1157         pdsb->notify = NULL;
1158     }
1159
1160     if (pdsb->secondary) {
1161         WARN("dsb not NULL\n");
1162         SecondaryBufferImpl_Destroy(pdsb->secondary);
1163         pdsb->secondary = NULL;
1164     }
1165
1166     while (IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)pdsb) > 0);
1167
1168     return S_OK;
1169 }
1170
1171 HRESULT IDirectSoundBufferImpl_Duplicate(
1172     DirectSoundDevice *device,
1173     IDirectSoundBufferImpl **ppdsb,
1174     IDirectSoundBufferImpl *pdsb)
1175 {
1176     IDirectSoundBufferImpl *dsb;
1177     HRESULT hres = DS_OK;
1178     TRACE("(%p,%p,%p)\n", device, pdsb, pdsb);
1179
1180     dsb = HeapAlloc(GetProcessHeap(),0,sizeof(*dsb));
1181     if (dsb == NULL) {
1182         WARN("out of memory\n");
1183         *ppdsb = NULL;
1184         return DSERR_OUTOFMEMORY;
1185     }
1186     CopyMemory(dsb, pdsb, sizeof(*dsb));
1187
1188     dsb->pwfx = DSOUND_CopyFormat(pdsb->pwfx);
1189     if (dsb->pwfx == NULL) {
1190         HeapFree(GetProcessHeap(),0,dsb);
1191         *ppdsb = NULL;
1192         return DSERR_OUTOFMEMORY;
1193     }
1194
1195     if (pdsb->hwbuf) {
1196         TRACE("duplicating hardware buffer\n");
1197
1198         hres = IDsDriver_DuplicateSoundBuffer(device->driver, pdsb->hwbuf,
1199                                               (LPVOID *)&dsb->hwbuf);
1200         if (FAILED(hres)) {
1201             WARN("IDsDriver_DuplicateSoundBuffer failed (%08x)\n", hres);
1202             HeapFree(GetProcessHeap(),0,dsb->pwfx);
1203             HeapFree(GetProcessHeap(),0,dsb);
1204             *ppdsb = NULL;
1205             return hres;
1206         }
1207     }
1208
1209     dsb->buffer->ref++;
1210     list_add_head(&dsb->buffer->buffers, &dsb->entry);
1211     dsb->ref = 0;
1212     dsb->state = STATE_STOPPED;
1213     dsb->buf_mixpos = dsb->sec_mixpos = 0;
1214     dsb->device = device;
1215     dsb->ds3db = NULL;
1216     dsb->iks = NULL; /* FIXME? */
1217     dsb->secondary = NULL;
1218     dsb->tmp_buffer = NULL;
1219     DSOUND_RecalcFormat(dsb);
1220     DSOUND_MixToTemporary(dsb, 0, dsb->buflen, FALSE);
1221
1222     RtlInitializeResource(&dsb->lock);
1223
1224     /* register buffer */
1225     hres = DirectSoundDevice_AddBuffer(device, dsb);
1226     if (hres != DS_OK) {
1227         RtlDeleteResource(&dsb->lock);
1228         HeapFree(GetProcessHeap(),0,dsb->tmp_buffer);
1229         list_remove(&dsb->entry);
1230         dsb->buffer->ref--;
1231         HeapFree(GetProcessHeap(),0,dsb->pwfx);
1232         HeapFree(GetProcessHeap(),0,dsb);
1233         dsb = NULL;
1234     }
1235
1236     *ppdsb = dsb;
1237     return hres;
1238 }
1239
1240 /*******************************************************************************
1241  *              SecondaryBuffer
1242  */
1243
1244 static HRESULT WINAPI SecondaryBufferImpl_QueryInterface(
1245         LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj)
1246 {
1247         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1248         TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
1249
1250         return IDirectSoundBufferImpl_QueryInterface((LPDIRECTSOUNDBUFFER8)This->dsb,riid,ppobj);
1251 }
1252
1253 static ULONG WINAPI SecondaryBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface)
1254 {
1255     SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1256     ULONG ref = InterlockedIncrement(&(This->ref));
1257     TRACE("(%p) ref was %d\n", This, ref - 1);
1258     return ref;
1259 }
1260
1261 static ULONG WINAPI SecondaryBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface)
1262 {
1263     SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1264     ULONG ref;
1265     TRACE("(%p)\n", This);
1266     ref = InterlockedDecrement(&(This->ref));
1267     TRACE("ref was %d\n", ref + 1);
1268
1269     if (!ref) {
1270         This->dsb->secondary = NULL;
1271         IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER8)This->dsb);
1272         HeapFree(GetProcessHeap(), 0, This);
1273         TRACE("(%p) released\n", This);
1274     }
1275     return ref;
1276 }
1277
1278 static HRESULT WINAPI SecondaryBufferImpl_GetCaps(
1279         LPDIRECTSOUNDBUFFER8 iface,LPDSBCAPS caps)
1280 {
1281         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1282         TRACE("(%p)->(%p)\n",This,caps);
1283
1284         return IDirectSoundBufferImpl_GetCaps((LPDIRECTSOUNDBUFFER8)This->dsb,caps);
1285 }
1286
1287 static HRESULT WINAPI SecondaryBufferImpl_GetCurrentPosition(
1288         LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos)
1289 {
1290         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1291         TRACE("(%p,%p,%p)\n",This,playpos,writepos);
1292
1293         return IDirectSoundBufferImpl_GetCurrentPosition((LPDIRECTSOUNDBUFFER8)This->dsb,playpos,writepos);
1294 }
1295
1296 static HRESULT WINAPI SecondaryBufferImpl_GetFormat(
1297         LPDIRECTSOUNDBUFFER8 iface,LPWAVEFORMATEX lpwf,DWORD wfsize,LPDWORD wfwritten)
1298 {
1299         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1300         TRACE("(%p,%p,%d,%p)\n",This,lpwf,wfsize,wfwritten);
1301
1302         return IDirectSoundBufferImpl_GetFormat((LPDIRECTSOUNDBUFFER8)This->dsb,lpwf,wfsize,wfwritten);
1303 }
1304
1305 static HRESULT WINAPI SecondaryBufferImpl_GetVolume(
1306         LPDIRECTSOUNDBUFFER8 iface,LPLONG vol)
1307 {
1308         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1309         TRACE("(%p,%p)\n",This,vol);
1310
1311         return IDirectSoundBufferImpl_GetVolume((LPDIRECTSOUNDBUFFER8)This->dsb,vol);
1312 }
1313
1314 static HRESULT WINAPI SecondaryBufferImpl_GetPan(
1315         LPDIRECTSOUNDBUFFER8 iface,LPLONG pan)
1316 {
1317         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1318         TRACE("(%p,%p)\n",This,pan);
1319
1320         return IDirectSoundBufferImpl_GetPan((LPDIRECTSOUNDBUFFER8)This->dsb,pan);
1321 }
1322
1323 static HRESULT WINAPI SecondaryBufferImpl_GetFrequency(
1324         LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq)
1325 {
1326         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1327         TRACE("(%p,%p)\n",This,freq);
1328
1329         return IDirectSoundBufferImpl_GetFrequency((LPDIRECTSOUNDBUFFER8)This->dsb,freq);
1330 }
1331
1332 static HRESULT WINAPI SecondaryBufferImpl_GetStatus(
1333         LPDIRECTSOUNDBUFFER8 iface,LPDWORD status)
1334 {
1335         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1336         TRACE("(%p,%p)\n",This,status);
1337
1338         return IDirectSoundBufferImpl_GetStatus((LPDIRECTSOUNDBUFFER8)This->dsb,status);
1339 }
1340
1341 static HRESULT WINAPI SecondaryBufferImpl_Initialize(
1342         LPDIRECTSOUNDBUFFER8 iface,LPDIRECTSOUND dsound,LPCDSBUFFERDESC dbsd)
1343 {
1344         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1345         TRACE("(%p,%p,%p)\n",This,dsound,dbsd);
1346
1347         return IDirectSoundBufferImpl_Initialize((LPDIRECTSOUNDBUFFER8)This->dsb,dsound,dbsd);
1348 }
1349
1350 static HRESULT WINAPI SecondaryBufferImpl_Lock(
1351     LPDIRECTSOUNDBUFFER8 iface,
1352     DWORD writecursor,
1353     DWORD writebytes,
1354     LPVOID *lplpaudioptr1,
1355     LPDWORD audiobytes1,
1356     LPVOID *lplpaudioptr2,
1357     LPDWORD audiobytes2,
1358     DWORD dwFlags)
1359 {
1360     SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1361     TRACE("(%p,%d,%d,%p,%p,%p,%p,0x%08x)\n",
1362         This,writecursor,writebytes,lplpaudioptr1,audiobytes1,lplpaudioptr2,audiobytes2,dwFlags);
1363
1364     return IDirectSoundBufferImpl_Lock((LPDIRECTSOUNDBUFFER8)This->dsb,
1365         writecursor,writebytes,lplpaudioptr1,audiobytes1,lplpaudioptr2,audiobytes2,dwFlags);
1366 }
1367
1368 static HRESULT WINAPI SecondaryBufferImpl_Play(
1369         LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags)
1370 {
1371         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1372         TRACE("(%p,%08x,%08x,%08x)\n",This,reserved1,reserved2,flags);
1373
1374         return IDirectSoundBufferImpl_Play((LPDIRECTSOUNDBUFFER8)This->dsb,reserved1,reserved2,flags);
1375 }
1376
1377 static HRESULT WINAPI SecondaryBufferImpl_SetCurrentPosition(
1378         LPDIRECTSOUNDBUFFER8 iface,DWORD newpos)
1379 {
1380         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1381         TRACE("(%p,%d)\n",This,newpos);
1382
1383         return IDirectSoundBufferImpl_SetCurrentPosition((LPDIRECTSOUNDBUFFER8)This->dsb,newpos);
1384 }
1385
1386 static HRESULT WINAPI SecondaryBufferImpl_SetFormat(
1387         LPDIRECTSOUNDBUFFER8 iface,LPCWAVEFORMATEX wfex)
1388 {
1389         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1390         TRACE("(%p,%p)\n",This,wfex);
1391
1392         return IDirectSoundBufferImpl_SetFormat((LPDIRECTSOUNDBUFFER8)This->dsb,wfex);
1393 }
1394
1395 static HRESULT WINAPI SecondaryBufferImpl_SetVolume(
1396         LPDIRECTSOUNDBUFFER8 iface,LONG vol)
1397 {
1398         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1399         TRACE("(%p,%d)\n",This,vol);
1400
1401         return IDirectSoundBufferImpl_SetVolume((LPDIRECTSOUNDBUFFER8)This->dsb,vol);
1402 }
1403
1404 static HRESULT WINAPI SecondaryBufferImpl_SetPan(
1405         LPDIRECTSOUNDBUFFER8 iface,LONG pan)
1406 {
1407         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1408         TRACE("(%p,%d)\n",This,pan);
1409
1410         return IDirectSoundBufferImpl_SetPan((LPDIRECTSOUNDBUFFER8)This->dsb,pan);
1411 }
1412
1413 static HRESULT WINAPI SecondaryBufferImpl_SetFrequency(
1414         LPDIRECTSOUNDBUFFER8 iface,DWORD freq)
1415 {
1416         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1417         TRACE("(%p,%d)\n",This,freq);
1418
1419         return IDirectSoundBufferImpl_SetFrequency((LPDIRECTSOUNDBUFFER8)This->dsb,freq);
1420 }
1421
1422 static HRESULT WINAPI SecondaryBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface)
1423 {
1424         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1425         TRACE("(%p)\n",This);
1426
1427         return IDirectSoundBufferImpl_Stop((LPDIRECTSOUNDBUFFER8)This->dsb);
1428 }
1429
1430 static HRESULT WINAPI SecondaryBufferImpl_Unlock(
1431     LPDIRECTSOUNDBUFFER8 iface,
1432     LPVOID lpvAudioPtr1,
1433     DWORD dwAudioBytes1,
1434     LPVOID lpvAudioPtr2,
1435     DWORD dwAudioBytes2)
1436 {
1437     SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1438     TRACE("(%p,%p,%d,%p,%d)\n",
1439         This, lpvAudioPtr1, dwAudioBytes1, lpvAudioPtr2, dwAudioBytes2);
1440
1441     return IDirectSoundBufferImpl_Unlock((LPDIRECTSOUNDBUFFER8)This->dsb,
1442         lpvAudioPtr1,dwAudioBytes1,lpvAudioPtr2,dwAudioBytes2);
1443 }
1444
1445 static HRESULT WINAPI SecondaryBufferImpl_Restore(
1446         LPDIRECTSOUNDBUFFER8 iface)
1447 {
1448         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1449         TRACE("(%p)\n",This);
1450
1451         return IDirectSoundBufferImpl_Restore((LPDIRECTSOUNDBUFFER8)This->dsb);
1452 }
1453
1454 static HRESULT WINAPI SecondaryBufferImpl_SetFX(
1455         LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes)
1456 {
1457         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1458         TRACE("(%p,%u,%p,%p)\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
1459
1460         return IDirectSoundBufferImpl_SetFX((LPDIRECTSOUNDBUFFER8)This->dsb,dwEffectsCount,pDSFXDesc,pdwResultCodes);
1461 }
1462
1463 static HRESULT WINAPI SecondaryBufferImpl_AcquireResources(
1464         LPDIRECTSOUNDBUFFER8 iface,DWORD dwFlags,DWORD dwEffectsCount,LPDWORD pdwResultCodes)
1465 {
1466         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1467         TRACE("(%p,%08u,%u,%p)\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
1468
1469         return IDirectSoundBufferImpl_AcquireResources((LPDIRECTSOUNDBUFFER8)This->dsb,dwFlags,dwEffectsCount,pdwResultCodes);
1470 }
1471
1472 static HRESULT WINAPI SecondaryBufferImpl_GetObjectInPath(
1473         LPDIRECTSOUNDBUFFER8 iface,REFGUID rguidObject,DWORD dwIndex,REFGUID rguidInterface,LPVOID* ppObject)
1474 {
1475         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1476         TRACE("(%p,%s,%u,%s,%p)\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
1477
1478         return IDirectSoundBufferImpl_GetObjectInPath((LPDIRECTSOUNDBUFFER8)This->dsb,rguidObject,dwIndex,rguidInterface,ppObject);
1479 }
1480
1481 static const IDirectSoundBuffer8Vtbl sbvt =
1482 {
1483         SecondaryBufferImpl_QueryInterface,
1484         SecondaryBufferImpl_AddRef,
1485         SecondaryBufferImpl_Release,
1486         SecondaryBufferImpl_GetCaps,
1487         SecondaryBufferImpl_GetCurrentPosition,
1488         SecondaryBufferImpl_GetFormat,
1489         SecondaryBufferImpl_GetVolume,
1490         SecondaryBufferImpl_GetPan,
1491         SecondaryBufferImpl_GetFrequency,
1492         SecondaryBufferImpl_GetStatus,
1493         SecondaryBufferImpl_Initialize,
1494         SecondaryBufferImpl_Lock,
1495         SecondaryBufferImpl_Play,
1496         SecondaryBufferImpl_SetCurrentPosition,
1497         SecondaryBufferImpl_SetFormat,
1498         SecondaryBufferImpl_SetVolume,
1499         SecondaryBufferImpl_SetPan,
1500         SecondaryBufferImpl_SetFrequency,
1501         SecondaryBufferImpl_Stop,
1502         SecondaryBufferImpl_Unlock,
1503         SecondaryBufferImpl_Restore,
1504         SecondaryBufferImpl_SetFX,
1505         SecondaryBufferImpl_AcquireResources,
1506         SecondaryBufferImpl_GetObjectInPath
1507 };
1508
1509 HRESULT SecondaryBufferImpl_Create(
1510         IDirectSoundBufferImpl *dsb,
1511         SecondaryBufferImpl **psb)
1512 {
1513         SecondaryBufferImpl *sb;
1514         TRACE("(%p,%p)\n",dsb,psb);
1515
1516         sb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*sb));
1517
1518         if (sb == 0) {
1519                 WARN("out of memory\n");
1520                 *psb = NULL;
1521                 return DSERR_OUTOFMEMORY;
1522         }
1523         sb->ref = 0;
1524         sb->dsb = dsb;
1525         sb->lpVtbl = &sbvt;
1526
1527         IDirectSoundBuffer8_AddRef((LPDIRECTSOUNDBUFFER8)dsb);
1528         *psb = sb;
1529         return S_OK;
1530 }
1531
1532 static HRESULT SecondaryBufferImpl_Destroy(
1533     SecondaryBufferImpl *pdsb)
1534 {
1535     TRACE("(%p)\n",pdsb);
1536
1537     while (SecondaryBufferImpl_Release((LPDIRECTSOUNDBUFFER8)pdsb) > 0);
1538
1539     return S_OK;
1540 }