kernel32: Add a 64-bit flag to the MODULE_GetBinaryType return value.
[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, alloc_size, cp_size;
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         /* variable sized struct so calculate size based on format */
989         if (wfex->wFormatTag == WAVE_FORMAT_PCM) {
990                 alloc_size = sizeof(WAVEFORMATEX);
991                 cp_size = sizeof(PCMWAVEFORMAT);
992         } else 
993                 alloc_size = cp_size = sizeof(WAVEFORMATEX) + wfex->cbSize;
994
995         dsb->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,alloc_size);
996         if (dsb->pwfx == NULL) {
997                 WARN("out of memory\n");
998                 HeapFree(GetProcessHeap(),0,dsb);
999                 *pdsb = NULL;
1000                 return DSERR_OUTOFMEMORY;
1001         }
1002
1003         CopyMemory(dsb->pwfx, wfex, cp_size);
1004
1005         if (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign)
1006                 dsb->buflen = dsbd->dwBufferBytes + 
1007                         (dsbd->lpwfxFormat->nBlockAlign - 
1008                         (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign));
1009         else
1010                 dsb->buflen = dsbd->dwBufferBytes;
1011
1012         dsb->freq = dsbd->lpwfxFormat->nSamplesPerSec;
1013         dsb->notify = NULL;
1014         dsb->notifies = NULL;
1015         dsb->nrofnotifies = 0;
1016         dsb->hwnotify = 0;
1017
1018         /* Check necessary hardware mixing capabilities */
1019         if (wfex->nChannels==2) capf |= DSCAPS_SECONDARYSTEREO;
1020         else capf |= DSCAPS_SECONDARYMONO;
1021         if (wfex->wBitsPerSample==16) capf |= DSCAPS_SECONDARY16BIT;
1022         else capf |= DSCAPS_SECONDARY8BIT;
1023
1024         use_hw = !!(dsbd->dwFlags & DSBCAPS_LOCHARDWARE);
1025         TRACE("use_hw = %d, capf = 0x%08x, device->drvcaps.dwFlags = 0x%08x\n", use_hw, capf, device->drvcaps.dwFlags);
1026         if (use_hw && ((device->drvcaps.dwFlags & capf) != capf || !device->driver))
1027         {
1028                 if (device->driver)
1029                         WARN("Format not supported for hardware buffer\n");
1030                 HeapFree(GetProcessHeap(),0,dsb->pwfx);
1031                 HeapFree(GetProcessHeap(),0,dsb);
1032                 *pdsb = NULL;
1033                 if ((device->drvcaps.dwFlags & capf) != capf)
1034                         return DSERR_BADFORMAT;
1035                 return DSERR_GENERIC;
1036         }
1037
1038         /* FIXME: check hardware sample rate mixing capabilities */
1039         /* FIXME: check app hints for software/hardware buffer (STATIC, LOCHARDWARE, etc) */
1040         /* FIXME: check whether any hardware buffers are left */
1041         /* FIXME: handle DSDHEAP_CREATEHEAP for hardware buffers */
1042
1043         /* Allocate an empty buffer */
1044         dsb->buffer = HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb->buffer)));
1045         if (dsb->buffer == NULL) {
1046                 WARN("out of memory\n");
1047                 HeapFree(GetProcessHeap(),0,dsb->pwfx);
1048                 HeapFree(GetProcessHeap(),0,dsb);
1049                 *pdsb = NULL;
1050                 return DSERR_OUTOFMEMORY;
1051         }
1052
1053         /* Allocate system memory for buffer if applicable */
1054         if ((device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) || !use_hw) {
1055                 dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen);
1056                 if (dsb->buffer->memory == NULL) {
1057                         WARN("out of memory\n");
1058                         HeapFree(GetProcessHeap(),0,dsb->pwfx);
1059                         HeapFree(GetProcessHeap(),0,dsb->buffer);
1060                         HeapFree(GetProcessHeap(),0,dsb);
1061                         *pdsb = NULL;
1062                         return DSERR_OUTOFMEMORY;
1063                 }
1064         }
1065
1066         /* Allocate the hardware buffer */
1067         if (use_hw) {
1068                 err = IDsDriver_CreateSoundBuffer(device->driver,wfex,dsbd->dwFlags,0,
1069                                                   &(dsb->buflen),&(dsb->buffer->memory),
1070                                                   (LPVOID*)&(dsb->hwbuf));
1071                 if (FAILED(err))
1072                 {
1073                         WARN("Failed to create hardware secondary buffer: %08x\n", err);
1074                         if (device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY)
1075                                 HeapFree(GetProcessHeap(),0,dsb->buffer->memory);
1076                         HeapFree(GetProcessHeap(),0,dsb->buffer);
1077                         HeapFree(GetProcessHeap(),0,dsb->pwfx);
1078                         HeapFree(GetProcessHeap(),0,dsb);
1079                         *pdsb = NULL;
1080                         return DSERR_GENERIC;
1081                 }
1082         }
1083
1084         dsb->buffer->ref = 1;
1085         list_init(&dsb->buffer->buffers);
1086         list_add_head(&dsb->buffer->buffers, &dsb->entry);
1087         FillMemory(dsb->buffer->memory, dsb->buflen, dsbd->lpwfxFormat->wBitsPerSample == 8 ? 128 : 0);
1088
1089         /* It's not necessary to initialize values to zero since */
1090         /* we allocated this structure with HEAP_ZERO_MEMORY... */
1091         dsb->buf_mixpos = dsb->sec_mixpos = 0;
1092         dsb->state = STATE_STOPPED;
1093
1094         dsb->freqAdjust = ((DWORD64)dsb->freq << DSOUND_FREQSHIFT) / device->pwfx->nSamplesPerSec;
1095         dsb->nAvgBytesPerSec = dsb->freq *
1096                 dsbd->lpwfxFormat->nBlockAlign;
1097
1098         /* calculate fragment size and write lead */
1099         DSOUND_RecalcFormat(dsb);
1100
1101         if (dsb->dsbd.dwFlags & DSBCAPS_CTRL3D) {
1102                 dsb->ds3db_ds3db.dwSize = sizeof(DS3DBUFFER);
1103                 dsb->ds3db_ds3db.vPosition.x = 0.0;
1104                 dsb->ds3db_ds3db.vPosition.y = 0.0;
1105                 dsb->ds3db_ds3db.vPosition.z = 0.0;
1106                 dsb->ds3db_ds3db.vVelocity.x = 0.0;
1107                 dsb->ds3db_ds3db.vVelocity.y = 0.0;
1108                 dsb->ds3db_ds3db.vVelocity.z = 0.0;
1109                 dsb->ds3db_ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
1110                 dsb->ds3db_ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
1111                 dsb->ds3db_ds3db.vConeOrientation.x = 0.0;
1112                 dsb->ds3db_ds3db.vConeOrientation.y = 0.0;
1113                 dsb->ds3db_ds3db.vConeOrientation.z = 0.0;
1114                 dsb->ds3db_ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
1115                 dsb->ds3db_ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE;
1116                 dsb->ds3db_ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
1117                 dsb->ds3db_ds3db.dwMode = DS3DMODE_NORMAL;
1118
1119                 dsb->ds3db_need_recalc = FALSE;
1120                 DSOUND_Calc3DBuffer(dsb);
1121         } else
1122                 DSOUND_RecalcVolPan(&(dsb->volpan));
1123
1124         RtlInitializeResource(&dsb->lock);
1125
1126         /* register buffer if not primary */
1127         if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
1128                 err = DirectSoundDevice_AddBuffer(device, dsb);
1129                 if (err != DS_OK) {
1130                         HeapFree(GetProcessHeap(),0,dsb->buffer->memory);
1131                         HeapFree(GetProcessHeap(),0,dsb->buffer);
1132                         RtlDeleteResource(&dsb->lock);
1133                         HeapFree(GetProcessHeap(),0,dsb->pwfx);
1134                         HeapFree(GetProcessHeap(),0,dsb);
1135                         dsb = NULL;
1136                 }
1137         }
1138
1139         *pdsb = dsb;
1140         return err;
1141 }
1142
1143 HRESULT IDirectSoundBufferImpl_Destroy(
1144     IDirectSoundBufferImpl *pdsb)
1145 {
1146     TRACE("(%p)\n",pdsb);
1147
1148     /* This keeps the *_Destroy functions from possibly deleting
1149      * this object until it is ready to be deleted */
1150     IDirectSoundBufferImpl_AddRef((LPDIRECTSOUNDBUFFER8)pdsb);
1151
1152     if (pdsb->iks) {
1153         WARN("iks not NULL\n");
1154         IKsBufferPropertySetImpl_Destroy(pdsb->iks);
1155         pdsb->iks = NULL;
1156     }
1157
1158     if (pdsb->ds3db) {
1159         WARN("ds3db not NULL\n");
1160         IDirectSound3DBufferImpl_Destroy(pdsb->ds3db);
1161         pdsb->ds3db = NULL;
1162     }
1163
1164     if (pdsb->notify) {
1165         WARN("notify not NULL\n");
1166         IDirectSoundNotifyImpl_Destroy(pdsb->notify);
1167         pdsb->notify = NULL;
1168     }
1169
1170     if (pdsb->secondary) {
1171         WARN("dsb not NULL\n");
1172         SecondaryBufferImpl_Destroy(pdsb->secondary);
1173         pdsb->secondary = NULL;
1174     }
1175
1176     while (IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)pdsb) > 0);
1177
1178     return S_OK;
1179 }
1180
1181 HRESULT IDirectSoundBufferImpl_Duplicate(
1182     DirectSoundDevice *device,
1183     IDirectSoundBufferImpl **ppdsb,
1184     IDirectSoundBufferImpl *pdsb)
1185 {
1186     IDirectSoundBufferImpl *dsb;
1187     HRESULT hres = DS_OK;
1188     int size;
1189     TRACE("(%p,%p,%p)\n", device, pdsb, pdsb);
1190
1191     dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
1192
1193     if (dsb == NULL) {
1194         WARN("out of memory\n");
1195         *ppdsb = NULL;
1196         return DSERR_OUTOFMEMORY;
1197     }
1198
1199     CopyMemory(dsb, pdsb, sizeof(IDirectSoundBufferImpl));
1200
1201     if (pdsb->hwbuf) {
1202         TRACE("duplicating hardware buffer\n");
1203
1204         hres = IDsDriver_DuplicateSoundBuffer(device->driver, pdsb->hwbuf,
1205                                               (LPVOID *)&dsb->hwbuf);
1206         if (FAILED(hres)) {
1207             WARN("IDsDriver_DuplicateSoundBuffer failed (%08x)\n", hres);
1208             HeapFree(GetProcessHeap(),0,dsb);
1209             *ppdsb = NULL;
1210             return hres;
1211         }
1212     }
1213
1214     dsb->buffer->ref++;
1215     list_add_head(&dsb->buffer->buffers, &dsb->entry);
1216     dsb->ref = 0;
1217     dsb->state = STATE_STOPPED;
1218     dsb->buf_mixpos = dsb->sec_mixpos = 0;
1219     dsb->device = device;
1220     dsb->ds3db = NULL;
1221     dsb->iks = NULL; /* FIXME? */
1222     dsb->secondary = NULL;
1223     dsb->tmp_buffer = NULL;
1224     DSOUND_RecalcFormat(dsb);
1225     DSOUND_MixToTemporary(dsb, 0, dsb->buflen, FALSE);
1226
1227     /* variable sized struct so calculate size based on format */
1228     size = sizeof(WAVEFORMATEX) + pdsb->pwfx->cbSize;
1229
1230     dsb->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
1231     if (dsb->pwfx == NULL) {
1232             WARN("out of memory\n");
1233             HeapFree(GetProcessHeap(),0,dsb->buffer);
1234             HeapFree(GetProcessHeap(),0,dsb);
1235             *ppdsb = NULL;
1236             return DSERR_OUTOFMEMORY;
1237     }
1238
1239     CopyMemory(dsb->pwfx, pdsb->pwfx, size);
1240
1241     RtlInitializeResource(&dsb->lock);
1242
1243     /* register buffer */
1244     hres = DirectSoundDevice_AddBuffer(device, dsb);
1245     if (hres != DS_OK) {
1246         RtlDeleteResource(&dsb->lock);
1247         HeapFree(GetProcessHeap(),0,dsb->tmp_buffer);
1248         HeapFree(GetProcessHeap(),0,dsb->buffer);
1249         HeapFree(GetProcessHeap(),0,dsb->pwfx);
1250         HeapFree(GetProcessHeap(),0,dsb);
1251         *ppdsb = 0;
1252     }
1253
1254     *ppdsb = dsb;
1255     return hres;
1256 }
1257
1258 /*******************************************************************************
1259  *              SecondaryBuffer
1260  */
1261
1262 static HRESULT WINAPI SecondaryBufferImpl_QueryInterface(
1263         LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj)
1264 {
1265         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1266         TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
1267
1268         return IDirectSoundBufferImpl_QueryInterface((LPDIRECTSOUNDBUFFER8)This->dsb,riid,ppobj);
1269 }
1270
1271 static ULONG WINAPI SecondaryBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface)
1272 {
1273     SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1274     ULONG ref = InterlockedIncrement(&(This->ref));
1275     TRACE("(%p) ref was %d\n", This, ref - 1);
1276     return ref;
1277 }
1278
1279 static ULONG WINAPI SecondaryBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface)
1280 {
1281     SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1282     ULONG ref;
1283     TRACE("(%p)\n", This);
1284     ref = InterlockedDecrement(&(This->ref));
1285     TRACE("ref was %d\n", ref + 1);
1286
1287     if (!ref) {
1288         This->dsb->secondary = NULL;
1289         IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER8)This->dsb);
1290         HeapFree(GetProcessHeap(), 0, This);
1291         TRACE("(%p) released\n", This);
1292     }
1293     return ref;
1294 }
1295
1296 static HRESULT WINAPI SecondaryBufferImpl_GetCaps(
1297         LPDIRECTSOUNDBUFFER8 iface,LPDSBCAPS caps)
1298 {
1299         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1300         TRACE("(%p)->(%p)\n",This,caps);
1301
1302         return IDirectSoundBufferImpl_GetCaps((LPDIRECTSOUNDBUFFER8)This->dsb,caps);
1303 }
1304
1305 static HRESULT WINAPI SecondaryBufferImpl_GetCurrentPosition(
1306         LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos)
1307 {
1308         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1309         TRACE("(%p,%p,%p)\n",This,playpos,writepos);
1310
1311         return IDirectSoundBufferImpl_GetCurrentPosition((LPDIRECTSOUNDBUFFER8)This->dsb,playpos,writepos);
1312 }
1313
1314 static HRESULT WINAPI SecondaryBufferImpl_GetFormat(
1315         LPDIRECTSOUNDBUFFER8 iface,LPWAVEFORMATEX lpwf,DWORD wfsize,LPDWORD wfwritten)
1316 {
1317         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1318         TRACE("(%p,%p,%d,%p)\n",This,lpwf,wfsize,wfwritten);
1319
1320         return IDirectSoundBufferImpl_GetFormat((LPDIRECTSOUNDBUFFER8)This->dsb,lpwf,wfsize,wfwritten);
1321 }
1322
1323 static HRESULT WINAPI SecondaryBufferImpl_GetVolume(
1324         LPDIRECTSOUNDBUFFER8 iface,LPLONG vol)
1325 {
1326         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1327         TRACE("(%p,%p)\n",This,vol);
1328
1329         return IDirectSoundBufferImpl_GetVolume((LPDIRECTSOUNDBUFFER8)This->dsb,vol);
1330 }
1331
1332 static HRESULT WINAPI SecondaryBufferImpl_GetPan(
1333         LPDIRECTSOUNDBUFFER8 iface,LPLONG pan)
1334 {
1335         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1336         TRACE("(%p,%p)\n",This,pan);
1337
1338         return IDirectSoundBufferImpl_GetPan((LPDIRECTSOUNDBUFFER8)This->dsb,pan);
1339 }
1340
1341 static HRESULT WINAPI SecondaryBufferImpl_GetFrequency(
1342         LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq)
1343 {
1344         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1345         TRACE("(%p,%p)\n",This,freq);
1346
1347         return IDirectSoundBufferImpl_GetFrequency((LPDIRECTSOUNDBUFFER8)This->dsb,freq);
1348 }
1349
1350 static HRESULT WINAPI SecondaryBufferImpl_GetStatus(
1351         LPDIRECTSOUNDBUFFER8 iface,LPDWORD status)
1352 {
1353         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1354         TRACE("(%p,%p)\n",This,status);
1355
1356         return IDirectSoundBufferImpl_GetStatus((LPDIRECTSOUNDBUFFER8)This->dsb,status);
1357 }
1358
1359 static HRESULT WINAPI SecondaryBufferImpl_Initialize(
1360         LPDIRECTSOUNDBUFFER8 iface,LPDIRECTSOUND dsound,LPCDSBUFFERDESC dbsd)
1361 {
1362         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1363         TRACE("(%p,%p,%p)\n",This,dsound,dbsd);
1364
1365         return IDirectSoundBufferImpl_Initialize((LPDIRECTSOUNDBUFFER8)This->dsb,dsound,dbsd);
1366 }
1367
1368 static HRESULT WINAPI SecondaryBufferImpl_Lock(
1369     LPDIRECTSOUNDBUFFER8 iface,
1370     DWORD writecursor,
1371     DWORD writebytes,
1372     LPVOID *lplpaudioptr1,
1373     LPDWORD audiobytes1,
1374     LPVOID *lplpaudioptr2,
1375     LPDWORD audiobytes2,
1376     DWORD dwFlags)
1377 {
1378     SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1379     TRACE("(%p,%d,%d,%p,%p,%p,%p,0x%08x)\n",
1380         This,writecursor,writebytes,lplpaudioptr1,audiobytes1,lplpaudioptr2,audiobytes2,dwFlags);
1381
1382     return IDirectSoundBufferImpl_Lock((LPDIRECTSOUNDBUFFER8)This->dsb,
1383         writecursor,writebytes,lplpaudioptr1,audiobytes1,lplpaudioptr2,audiobytes2,dwFlags);
1384 }
1385
1386 static HRESULT WINAPI SecondaryBufferImpl_Play(
1387         LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags)
1388 {
1389         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1390         TRACE("(%p,%08x,%08x,%08x)\n",This,reserved1,reserved2,flags);
1391
1392         return IDirectSoundBufferImpl_Play((LPDIRECTSOUNDBUFFER8)This->dsb,reserved1,reserved2,flags);
1393 }
1394
1395 static HRESULT WINAPI SecondaryBufferImpl_SetCurrentPosition(
1396         LPDIRECTSOUNDBUFFER8 iface,DWORD newpos)
1397 {
1398         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1399         TRACE("(%p,%d)\n",This,newpos);
1400
1401         return IDirectSoundBufferImpl_SetCurrentPosition((LPDIRECTSOUNDBUFFER8)This->dsb,newpos);
1402 }
1403
1404 static HRESULT WINAPI SecondaryBufferImpl_SetFormat(
1405         LPDIRECTSOUNDBUFFER8 iface,LPCWAVEFORMATEX wfex)
1406 {
1407         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1408         TRACE("(%p,%p)\n",This,wfex);
1409
1410         return IDirectSoundBufferImpl_SetFormat((LPDIRECTSOUNDBUFFER8)This->dsb,wfex);
1411 }
1412
1413 static HRESULT WINAPI SecondaryBufferImpl_SetVolume(
1414         LPDIRECTSOUNDBUFFER8 iface,LONG vol)
1415 {
1416         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1417         TRACE("(%p,%d)\n",This,vol);
1418
1419         return IDirectSoundBufferImpl_SetVolume((LPDIRECTSOUNDBUFFER8)This->dsb,vol);
1420 }
1421
1422 static HRESULT WINAPI SecondaryBufferImpl_SetPan(
1423         LPDIRECTSOUNDBUFFER8 iface,LONG pan)
1424 {
1425         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1426         TRACE("(%p,%d)\n",This,pan);
1427
1428         return IDirectSoundBufferImpl_SetPan((LPDIRECTSOUNDBUFFER8)This->dsb,pan);
1429 }
1430
1431 static HRESULT WINAPI SecondaryBufferImpl_SetFrequency(
1432         LPDIRECTSOUNDBUFFER8 iface,DWORD freq)
1433 {
1434         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1435         TRACE("(%p,%d)\n",This,freq);
1436
1437         return IDirectSoundBufferImpl_SetFrequency((LPDIRECTSOUNDBUFFER8)This->dsb,freq);
1438 }
1439
1440 static HRESULT WINAPI SecondaryBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface)
1441 {
1442         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1443         TRACE("(%p)\n",This);
1444
1445         return IDirectSoundBufferImpl_Stop((LPDIRECTSOUNDBUFFER8)This->dsb);
1446 }
1447
1448 static HRESULT WINAPI SecondaryBufferImpl_Unlock(
1449     LPDIRECTSOUNDBUFFER8 iface,
1450     LPVOID lpvAudioPtr1,
1451     DWORD dwAudioBytes1,
1452     LPVOID lpvAudioPtr2,
1453     DWORD dwAudioBytes2)
1454 {
1455     SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1456     TRACE("(%p,%p,%d,%p,%d)\n",
1457         This, lpvAudioPtr1, dwAudioBytes1, lpvAudioPtr2, dwAudioBytes2);
1458
1459     return IDirectSoundBufferImpl_Unlock((LPDIRECTSOUNDBUFFER8)This->dsb,
1460         lpvAudioPtr1,dwAudioBytes1,lpvAudioPtr2,dwAudioBytes2);
1461 }
1462
1463 static HRESULT WINAPI SecondaryBufferImpl_Restore(
1464         LPDIRECTSOUNDBUFFER8 iface)
1465 {
1466         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1467         TRACE("(%p)\n",This);
1468
1469         return IDirectSoundBufferImpl_Restore((LPDIRECTSOUNDBUFFER8)This->dsb);
1470 }
1471
1472 static HRESULT WINAPI SecondaryBufferImpl_SetFX(
1473         LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes)
1474 {
1475         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1476         TRACE("(%p,%u,%p,%p)\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
1477
1478         return IDirectSoundBufferImpl_SetFX((LPDIRECTSOUNDBUFFER8)This->dsb,dwEffectsCount,pDSFXDesc,pdwResultCodes);
1479 }
1480
1481 static HRESULT WINAPI SecondaryBufferImpl_AcquireResources(
1482         LPDIRECTSOUNDBUFFER8 iface,DWORD dwFlags,DWORD dwEffectsCount,LPDWORD pdwResultCodes)
1483 {
1484         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1485         TRACE("(%p,%08u,%u,%p)\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
1486
1487         return IDirectSoundBufferImpl_AcquireResources((LPDIRECTSOUNDBUFFER8)This->dsb,dwFlags,dwEffectsCount,pdwResultCodes);
1488 }
1489
1490 static HRESULT WINAPI SecondaryBufferImpl_GetObjectInPath(
1491         LPDIRECTSOUNDBUFFER8 iface,REFGUID rguidObject,DWORD dwIndex,REFGUID rguidInterface,LPVOID* ppObject)
1492 {
1493         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1494         TRACE("(%p,%s,%u,%s,%p)\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
1495
1496         return IDirectSoundBufferImpl_GetObjectInPath((LPDIRECTSOUNDBUFFER8)This->dsb,rguidObject,dwIndex,rguidInterface,ppObject);
1497 }
1498
1499 static const IDirectSoundBuffer8Vtbl sbvt =
1500 {
1501         SecondaryBufferImpl_QueryInterface,
1502         SecondaryBufferImpl_AddRef,
1503         SecondaryBufferImpl_Release,
1504         SecondaryBufferImpl_GetCaps,
1505         SecondaryBufferImpl_GetCurrentPosition,
1506         SecondaryBufferImpl_GetFormat,
1507         SecondaryBufferImpl_GetVolume,
1508         SecondaryBufferImpl_GetPan,
1509         SecondaryBufferImpl_GetFrequency,
1510         SecondaryBufferImpl_GetStatus,
1511         SecondaryBufferImpl_Initialize,
1512         SecondaryBufferImpl_Lock,
1513         SecondaryBufferImpl_Play,
1514         SecondaryBufferImpl_SetCurrentPosition,
1515         SecondaryBufferImpl_SetFormat,
1516         SecondaryBufferImpl_SetVolume,
1517         SecondaryBufferImpl_SetPan,
1518         SecondaryBufferImpl_SetFrequency,
1519         SecondaryBufferImpl_Stop,
1520         SecondaryBufferImpl_Unlock,
1521         SecondaryBufferImpl_Restore,
1522         SecondaryBufferImpl_SetFX,
1523         SecondaryBufferImpl_AcquireResources,
1524         SecondaryBufferImpl_GetObjectInPath
1525 };
1526
1527 HRESULT SecondaryBufferImpl_Create(
1528         IDirectSoundBufferImpl *dsb,
1529         SecondaryBufferImpl **psb)
1530 {
1531         SecondaryBufferImpl *sb;
1532         TRACE("(%p,%p)\n",dsb,psb);
1533
1534         sb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*sb));
1535
1536         if (sb == 0) {
1537                 WARN("out of memory\n");
1538                 *psb = NULL;
1539                 return DSERR_OUTOFMEMORY;
1540         }
1541         sb->ref = 0;
1542         sb->dsb = dsb;
1543         sb->lpVtbl = &sbvt;
1544
1545         IDirectSoundBuffer8_AddRef((LPDIRECTSOUNDBUFFER8)dsb);
1546         *psb = sb;
1547         return S_OK;
1548 }
1549
1550 static HRESULT SecondaryBufferImpl_Destroy(
1551     SecondaryBufferImpl *pdsb)
1552 {
1553     TRACE("(%p)\n",pdsb);
1554
1555     while (SecondaryBufferImpl_Release((LPDIRECTSOUNDBUFFER8)pdsb) > 0);
1556
1557     return S_OK;
1558 }