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