dsound: Capture cleanup.
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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->dsound->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         DSOUND_RemoveBuffer(This->dsound, 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->dsound->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         TRACE("(%p, pplay=%lu, pwrite=%lu)\n", This, pplay, pwrite);
403
404         /* the actual primary play position (pplay) is always behind last mixed (pmix),
405          * unless the computer is too slow or something */
406         /* we need to know how far away we are from there */
407         if (pmix < pplay) pmix += This->dsound->device->buflen; /* wraparound */
408         pmix -= pplay;
409         /* detect buffer underrun */
410         if (pwrite < pplay) pwrite += This->dsound->device->buflen; /* wraparound */
411         pwrite -= pplay;
412         if (pmix > (ds_snd_queue_max * This->dsound->device->fraglen + pwrite + This->dsound->device->writelead)) {
413                 WARN("detected an underrun: primary queue was %ld\n",pmix);
414                 pmix = 0;
415         }
416         /* divide the offset by its sample size */
417         pmix /= This->dsound->device->pwfx->nBlockAlign;
418         TRACE("primary back-samples=%ld\n",pmix);
419         /* adjust for our frequency */
420         pmix = (pmix * This->freqAdjust) >> DSOUND_FREQSHIFT;
421         /* multiply by our own sample size */
422         pmix *= This->pwfx->nBlockAlign;
423         TRACE("this back-offset=%ld\n", pmix);
424         /* subtract from our last mixed position */
425         while (bplay < pmix) bplay += This->buflen; /* wraparound */
426         bplay -= pmix;
427         if (This->leadin && ((bplay < This->startpos) || (bplay > This->buf_mixpos))) {
428                 /* seems we haven't started playing yet */
429                 TRACE("this still in lead-in phase\n");
430                 bplay = This->startpos;
431         }
432         /* return the result */
433         return bplay;
434 }
435
436 static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(
437         LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos
438 ) {
439         HRESULT hres;
440         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
441         TRACE("(%p,%p,%p)\n",This,playpos,writepos);
442         if (This->hwbuf) {
443                 hres=IDsDriverBuffer_GetPosition(This->hwbuf,playpos,writepos);
444                 if (hres != DS_OK) {
445                     WARN("IDsDriverBuffer_GetPosition failed\n");
446                     return hres;
447                 }
448         } else {
449                 if (playpos && (This->state != STATE_PLAYING)) {
450                         /* we haven't been merged into the primary buffer (yet) */
451                         *playpos = This->buf_mixpos;
452                 } else if (playpos) {
453                         DWORD pplay, pwrite;
454                         /* let's get this exact; first, recursively call GetPosition on the primary */
455                         EnterCriticalSection(&(This->dsound->device->mixlock));
456                         if (DSOUND_PrimaryGetPosition(This->dsound->device, &pplay, &pwrite) != DS_OK)
457                                 WARN("DSOUND_PrimaryGetPosition failed\n");
458                         /* detect HEL mode underrun */
459                         if (!(This->dsound->device->hwbuf || This->dsound->device->pwqueue))
460                                 TRACE("detected an underrun\n");
461                         if ((This->dsbd.dwFlags & DSBCAPS_GETCURRENTPOSITION2) || This->dsound->device->hwbuf) {
462                                 /* calculate play position using this */
463                                 *playpos = DSOUND_CalcPlayPosition(This, pplay, pwrite);
464                         } else {
465                                 /* (unless the app isn't using GETCURRENTPOSITION2) */
466                                 /* don't know exactly how this should be handled...
467                                  * the docs says that play cursor is reported as directly
468                                  * behind write cursor, hmm... */
469                                 /* let's just do what might work for Half-Life */
470                                 DWORD wp;
471                                 wp = (This->dsound->device->pwplay + ds_hel_margin) * This->dsound->device->fraglen;
472                                 wp %= This->dsound->device->buflen;
473                                 *playpos = DSOUND_CalcPlayPosition(This, wp, pwrite);
474                         }
475                         LeaveCriticalSection(&(This->dsound->device->mixlock));
476                 }
477                 if (writepos)
478                     *writepos = This->buf_mixpos;
479         }
480         if (writepos) {
481                 if (This->state != STATE_STOPPED) {
482                         /* apply the documented 10ms lead to writepos */
483                         *writepos += This->writelead;
484                 }
485                 *writepos %= This->buflen;
486         }
487         if (playpos)
488             This->last_playpos = *playpos;
489         TRACE("playpos = %ld, writepos = %ld (%p, time=%ld)\n", playpos?*playpos:0, writepos?*writepos:0, This, GetTickCount());
490         return DS_OK;
491 }
492
493 static HRESULT WINAPI IDirectSoundBufferImpl_GetStatus(
494         LPDIRECTSOUNDBUFFER8 iface,LPDWORD status
495 ) {
496         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
497         TRACE("(%p,%p), thread is %04lx\n",This,status,GetCurrentThreadId());
498
499         if (status == NULL) {
500                 WARN("invalid parameter: status = NULL\n");
501                 return DSERR_INVALIDPARAM;
502         }
503
504         *status = 0;
505         if ((This->state == STATE_STARTING) || (This->state == STATE_PLAYING)) {
506                 *status |= DSBSTATUS_PLAYING;
507                 if (This->playflags & DSBPLAY_LOOPING)
508                         *status |= DSBSTATUS_LOOPING;
509         }
510
511         TRACE("status=%lx\n", *status);
512         return DS_OK;
513 }
514
515
516 static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat(
517     LPDIRECTSOUNDBUFFER8 iface,
518     LPWAVEFORMATEX lpwf,
519     DWORD wfsize,
520     LPDWORD wfwritten)
521 {
522     DWORD size;
523     IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
524     TRACE("(%p,%p,%ld,%p)\n",This,lpwf,wfsize,wfwritten);
525
526     size = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;
527
528     if (lpwf) { /* NULL is valid */
529         if (wfsize >= size) {
530             CopyMemory(lpwf,This->pwfx,size);
531             if (wfwritten)
532                 *wfwritten = size;
533         } else {
534             WARN("invalid parameter: wfsize too small\n");
535             if (wfwritten)
536                 *wfwritten = 0;
537             return DSERR_INVALIDPARAM;
538         }
539     } else {
540         if (wfwritten)
541             *wfwritten = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;
542         else {
543             WARN("invalid parameter: wfwritten == NULL\n");
544             return DSERR_INVALIDPARAM;
545         }
546     }
547
548     return DS_OK;
549 }
550
551 static HRESULT WINAPI IDirectSoundBufferImpl_Lock(
552         LPDIRECTSOUNDBUFFER8 iface,DWORD writecursor,DWORD writebytes,LPVOID lplpaudioptr1,LPDWORD audiobytes1,LPVOID lplpaudioptr2,LPDWORD audiobytes2,DWORD flags
553 ) {
554         HRESULT hres = DS_OK;
555         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
556
557         TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx) at %ld\n",
558                 This,
559                 writecursor,
560                 writebytes,
561                 lplpaudioptr1,
562                 audiobytes1,
563                 lplpaudioptr2,
564                 audiobytes2,
565                 flags,
566                 GetTickCount()
567         );
568
569         if (flags & DSBLOCK_FROMWRITECURSOR) {
570                 DWORD writepos;
571                 /* GetCurrentPosition does too much magic to duplicate here */
572                 hres = IDirectSoundBufferImpl_GetCurrentPosition(iface, NULL, &writepos);
573                 if (hres != DS_OK) {
574                         WARN("IDirectSoundBufferImpl_GetCurrentPosition failed\n");
575                         return hres;
576                 }
577                 writecursor += writepos;
578         }
579         writecursor %= This->buflen;
580         if (flags & DSBLOCK_ENTIREBUFFER)
581                 writebytes = This->buflen;
582         if (writebytes > This->buflen)
583                 writebytes = This->buflen;
584
585         EnterCriticalSection(&(This->lock));
586
587         if ((writebytes == This->buflen) &&
588             ((This->state == STATE_STARTING) ||
589              (This->state == STATE_PLAYING)))
590                 /* some games, like Half-Life, try to be clever (not) and
591                  * keep one secondary buffer, and mix sounds into it itself,
592                  * locking the entire buffer every time... so we can just forget
593                  * about tracking the last-written-to-position... */
594                 This->probably_valid_to = (DWORD)-1;
595         else
596                 This->probably_valid_to = writecursor;
597
598         if (!(This->dsound->device->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
599                 hres = IDsDriverBuffer_Lock(This->hwbuf,
600                                      lplpaudioptr1, audiobytes1,
601                                      lplpaudioptr2, audiobytes2,
602                                      writecursor, writebytes,
603                                      0);
604                 if (hres != DS_OK) {
605                         WARN("IDsDriverBuffer_Lock failed\n");
606                         LeaveCriticalSection(&(This->lock));
607                         return hres;
608                 }
609         } else {
610                 BOOL remix = FALSE;
611                 if (writecursor+writebytes <= This->buflen) {
612                         *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
613                         *audiobytes1 = writebytes;
614                         if (lplpaudioptr2)
615                                 *(LPBYTE*)lplpaudioptr2 = NULL;
616                         if (audiobytes2)
617                                 *audiobytes2 = 0;
618                         TRACE("->%ld.0\n",writebytes);
619                 } else {
620                         *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
621                         *audiobytes1 = This->buflen-writecursor;
622                         if (lplpaudioptr2)
623                                 *(LPBYTE*)lplpaudioptr2 = This->buffer->memory;
624                         if (audiobytes2)
625                                 *audiobytes2 = writebytes-(This->buflen-writecursor);
626                         TRACE("->%ld.%ld\n",*audiobytes1,audiobytes2?*audiobytes2:0);
627                 }
628                 if (This->state == STATE_PLAYING) {
629                         /* if the segment between playpos and buf_mixpos is touched,
630                          * we need to cancel some mixing */
631                         /* we'll assume that the app always calls GetCurrentPosition before
632                          * locking a playing buffer, so that last_playpos is up-to-date */
633                         if (This->buf_mixpos >= This->last_playpos) {
634                                 if (This->buf_mixpos > writecursor &&
635                                     This->last_playpos < writecursor+writebytes)
636                                         remix = TRUE;
637                         } else {
638                                 if (This->buf_mixpos > writecursor ||
639                                     This->last_playpos < writecursor+writebytes)
640                                         remix = TRUE;
641                         }
642                         if (remix) {
643                                 TRACE("locking prebuffered region, ouch\n");
644                                 DSOUND_MixCancelAt(This, writecursor);
645                         }
646                 }
647         }
648
649         LeaveCriticalSection(&(This->lock));
650         return DS_OK;
651 }
652
653 static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(
654         LPDIRECTSOUNDBUFFER8 iface,DWORD newpos
655 ) {
656         HRESULT hres = DS_OK;
657         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
658         TRACE("(%p,%ld)\n",This,newpos);
659
660         /* **** */
661         EnterCriticalSection(&(This->lock));
662
663         newpos %= This->buflen;
664         This->buf_mixpos = newpos;
665         if (This->hwbuf) {
666                 hres = IDsDriverBuffer_SetPosition(This->hwbuf, This->buf_mixpos);
667                 if (hres != DS_OK)
668                         WARN("IDsDriverBuffer_SetPosition failed\n");
669         }
670
671         LeaveCriticalSection(&(This->lock));
672         /* **** */
673
674         return hres;
675 }
676
677 static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(
678         LPDIRECTSOUNDBUFFER8 iface,LONG pan
679 ) {
680         HRESULT hres = DS_OK;
681         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
682
683         TRACE("(%p,%ld)\n",This,pan);
684
685         if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT)) {
686                 WARN("invalid parameter: pan = %ld\n", pan);
687                 return DSERR_INVALIDPARAM;
688         }
689
690         /* You cannot use both pan and 3D controls */
691         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
692             (This->dsbd.dwFlags & DSBCAPS_CTRL3D)) {
693                 WARN("control unavailable\n");
694                 return DSERR_CONTROLUNAVAIL;
695         }
696
697         /* **** */
698         EnterCriticalSection(&(This->lock));
699
700         if (This->volpan.lPan != pan) {
701                 This->volpan.lPan = pan;
702                 DSOUND_RecalcVolPan(&(This->volpan));
703
704                 if (This->hwbuf) {
705                         hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
706                         if (hres != DS_OK)
707                                 WARN("IDsDriverBuffer_SetVolumePan failed\n");
708                 } else
709                         DSOUND_ForceRemix(This);
710         }
711
712         LeaveCriticalSection(&(This->lock));
713         /* **** */
714
715         return hres;
716 }
717
718 static HRESULT WINAPI IDirectSoundBufferImpl_GetPan(
719         LPDIRECTSOUNDBUFFER8 iface,LPLONG pan
720 ) {
721         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
722         TRACE("(%p,%p)\n",This,pan);
723
724         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN)) {
725                 WARN("control unavailable\n");
726                 return DSERR_CONTROLUNAVAIL;
727         }
728
729         if (pan == NULL) {
730                 WARN("invalid parameter: pan = NULL\n");
731                 return DSERR_INVALIDPARAM;
732         }
733
734         *pan = This->volpan.lPan;
735
736         return DS_OK;
737 }
738
739 static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(
740         LPDIRECTSOUNDBUFFER8 iface,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2
741 ) {
742         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
743         DWORD probably_valid_to;
744         HRESULT hres = DS_OK;
745
746         TRACE("(%p,%p,%ld,%p,%ld)\n", This,p1,x1,p2,x2);
747
748         /* **** */
749         EnterCriticalSection(&(This->lock));
750
751         if (!(This->dsound->device->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
752                 hres = IDsDriverBuffer_Unlock(This->hwbuf, p1, x1, p2, x2);
753                 if (hres != DS_OK)
754                         WARN("IDsDriverBuffer_Unlock failed\n");
755         }
756
757         if (hres == DS_OK) {
758                 if (p2) probably_valid_to = (((LPBYTE)p2)-This->buffer->memory) + x2;
759                 else probably_valid_to = (((LPBYTE)p1)-This->buffer->memory) + x1;
760                 probably_valid_to %= This->buflen;
761                 if ((probably_valid_to == 0) && ((x1+x2) == This->buflen) &&
762                     ((This->state == STATE_STARTING) ||
763                      (This->state == STATE_PLAYING)))
764                         /* see IDirectSoundBufferImpl_Lock */
765                         probably_valid_to = (DWORD)-1;
766                 This->probably_valid_to = probably_valid_to;
767         }
768
769         LeaveCriticalSection(&(This->lock));
770         /* **** */
771
772         TRACE("probably_valid_to=%ld\n", This->probably_valid_to);
773         return hres;
774 }
775
776 static HRESULT WINAPI IDirectSoundBufferImpl_Restore(
777         LPDIRECTSOUNDBUFFER8 iface
778 ) {
779         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
780         FIXME("(%p):stub\n",This);
781         return DS_OK;
782 }
783
784 static HRESULT WINAPI IDirectSoundBufferImpl_GetFrequency(
785         LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq
786 ) {
787         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
788         TRACE("(%p,%p)\n",This,freq);
789
790         if (freq == NULL) {
791                 WARN("invalid parameter: freq = NULL\n");
792                 return DSERR_INVALIDPARAM;
793         }
794
795         *freq = This->freq;
796         TRACE("-> %ld\n", *freq);
797
798         return DS_OK;
799 }
800
801 static HRESULT WINAPI IDirectSoundBufferImpl_SetFX(
802         LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes
803 ) {
804         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
805         DWORD u;
806
807         FIXME("(%p,%lu,%p,%p): stub\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
808
809         if (pdwResultCodes)
810                 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
811
812         WARN("control unavailable\n");
813         return DSERR_CONTROLUNAVAIL;
814 }
815
816 static HRESULT WINAPI IDirectSoundBufferImpl_AcquireResources(
817         LPDIRECTSOUNDBUFFER8 iface,DWORD dwFlags,DWORD dwEffectsCount,LPDWORD pdwResultCodes
818 ) {
819         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
820         DWORD u;
821
822         FIXME("(%p,%08lu,%lu,%p): stub\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
823
824         if (pdwResultCodes)
825                 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
826
827         WARN("control unavailable\n");
828         return DSERR_CONTROLUNAVAIL;
829 }
830
831 static HRESULT WINAPI IDirectSoundBufferImpl_GetObjectInPath(
832         LPDIRECTSOUNDBUFFER8 iface,REFGUID rguidObject,DWORD dwIndex,REFGUID rguidInterface,LPVOID* ppObject
833 ) {
834         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
835
836         FIXME("(%p,%s,%lu,%s,%p): stub\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
837
838         WARN("control unavailable\n");
839         return DSERR_CONTROLUNAVAIL;
840 }
841
842 static HRESULT WINAPI IDirectSoundBufferImpl_Initialize(
843         LPDIRECTSOUNDBUFFER8 iface,LPDIRECTSOUND dsound,LPCDSBUFFERDESC dbsd
844 ) {
845         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
846         FIXME("(%p,%p,%p):stub\n",This,dsound,dbsd);
847         DPRINTF("Re-Init!!!\n");
848         WARN("already initialized\n");
849         return DSERR_ALREADYINITIALIZED;
850 }
851
852 static HRESULT WINAPI IDirectSoundBufferImpl_GetCaps(
853         LPDIRECTSOUNDBUFFER8 iface,LPDSBCAPS caps
854 ) {
855         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
856         TRACE("(%p)->(%p)\n",This,caps);
857
858         if (caps == NULL) {
859                 WARN("invalid parameter: caps == NULL\n");
860                 return DSERR_INVALIDPARAM;
861         }
862
863         if (caps->dwSize < sizeof(*caps)) {
864                 WARN("invalid parameter: caps->dwSize = %ld < %d\n",caps->dwSize, sizeof(*caps));
865                 return DSERR_INVALIDPARAM;
866         }
867
868         caps->dwFlags = This->dsbd.dwFlags;
869         if (This->hwbuf) caps->dwFlags |= DSBCAPS_LOCHARDWARE;
870         else caps->dwFlags |= DSBCAPS_LOCSOFTWARE;
871
872         caps->dwBufferBytes = This->buflen;
873
874         /* This value represents the speed of the "unlock" command.
875            As unlock is quite fast (it does not do anything), I put
876            4096 ko/s = 4 Mo / s */
877         /* FIXME: hwbuf speed */
878         caps->dwUnlockTransferRate = 4096;
879         caps->dwPlayCpuOverhead = 0;
880
881         return DS_OK;
882 }
883
884 static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface(
885         LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj
886 ) {
887         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
888
889         TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
890
891         if (ppobj == NULL) {
892                 WARN("invalid parameter\n");
893                 return E_INVALIDARG;
894         }
895
896         *ppobj = NULL;  /* assume failure */
897
898         if ( IsEqualGUID(riid, &IID_IUnknown) ||
899              IsEqualGUID(riid, &IID_IDirectSoundBuffer) ||
900              IsEqualGUID(riid, &IID_IDirectSoundBuffer8) ) {
901                 if (!This->secondary)
902                         SecondaryBufferImpl_Create(This, &(This->secondary));
903                 if (This->secondary) {
904                         IDirectSoundBuffer8_AddRef((LPDIRECTSOUNDBUFFER8)This->secondary);
905                         *ppobj = This->secondary;
906                         return S_OK;
907                 }
908                 WARN("IID_IDirectSoundBuffer\n");
909                 return E_NOINTERFACE;
910         }
911
912         if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
913                 if (!This->notify)
914                         IDirectSoundNotifyImpl_Create(This, &(This->notify));
915                 if (This->notify) {
916                         IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify);
917                         *ppobj = This->notify;
918                         return S_OK;
919                 }
920                 WARN("IID_IDirectSoundNotify\n");
921                 return E_NOINTERFACE;
922         }
923
924         if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) {
925                 if (!This->ds3db)
926                         IDirectSound3DBufferImpl_Create(This, &(This->ds3db));
927                 if (This->ds3db) {
928                         IDirectSound3DBuffer_AddRef((LPDIRECTSOUND3DBUFFER)This->ds3db);
929                         *ppobj = This->ds3db;
930                         return S_OK;
931                 }
932                 WARN("IID_IDirectSound3DBuffer\n");
933                 return E_NOINTERFACE;
934         }
935
936         if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
937                 ERR("app requested IDirectSound3DListener on secondary buffer\n");
938                 return E_NOINTERFACE;
939         }
940
941         if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) {
942                 if (!This->iks)
943                         IKsBufferPropertySetImpl_Create(This, &(This->iks));
944                 if (This->iks) {
945                         IKsPropertySet_AddRef((LPKSPROPERTYSET)This->iks);
946                         *ppobj = This->iks;
947                         return S_OK;
948                 }
949                 WARN("IID_IKsPropertySet\n");
950                 return E_NOINTERFACE;
951         }
952
953         FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
954
955         return E_NOINTERFACE;
956 }
957
958 static const IDirectSoundBuffer8Vtbl dsbvt =
959 {
960         IDirectSoundBufferImpl_QueryInterface,
961         IDirectSoundBufferImpl_AddRef,
962         IDirectSoundBufferImpl_Release,
963         IDirectSoundBufferImpl_GetCaps,
964         IDirectSoundBufferImpl_GetCurrentPosition,
965         IDirectSoundBufferImpl_GetFormat,
966         IDirectSoundBufferImpl_GetVolume,
967         IDirectSoundBufferImpl_GetPan,
968         IDirectSoundBufferImpl_GetFrequency,
969         IDirectSoundBufferImpl_GetStatus,
970         IDirectSoundBufferImpl_Initialize,
971         IDirectSoundBufferImpl_Lock,
972         IDirectSoundBufferImpl_Play,
973         IDirectSoundBufferImpl_SetCurrentPosition,
974         IDirectSoundBufferImpl_SetFormat,
975         IDirectSoundBufferImpl_SetVolume,
976         IDirectSoundBufferImpl_SetPan,
977         IDirectSoundBufferImpl_SetFrequency,
978         IDirectSoundBufferImpl_Stop,
979         IDirectSoundBufferImpl_Unlock,
980         IDirectSoundBufferImpl_Restore,
981         IDirectSoundBufferImpl_SetFX,
982         IDirectSoundBufferImpl_AcquireResources,
983         IDirectSoundBufferImpl_GetObjectInPath
984 };
985
986 HRESULT IDirectSoundBufferImpl_Create(
987         IDirectSoundImpl *ds,
988         IDirectSoundBufferImpl **pdsb,
989         LPCDSBUFFERDESC dsbd)
990 {
991         IDirectSoundBufferImpl *dsb;
992         LPWAVEFORMATEX wfex = dsbd->lpwfxFormat;
993         HRESULT err = DS_OK;
994         DWORD capf = 0;
995         int use_hw, alloc_size, cp_size;
996         TRACE("(%p,%p,%p)\n",ds,pdsb,dsbd);
997
998         if (dsbd->dwBufferBytes < DSBSIZE_MIN || dsbd->dwBufferBytes > DSBSIZE_MAX) {
999                 WARN("invalid parameter: dsbd->dwBufferBytes = %ld\n", dsbd->dwBufferBytes);
1000                 *pdsb = NULL;
1001                 return DSERR_INVALIDPARAM; /* FIXME: which error? */
1002         }
1003
1004         dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
1005
1006         if (dsb == 0) {
1007                 WARN("out of memory\n");
1008                 *pdsb = NULL;
1009                 return DSERR_OUTOFMEMORY;
1010         }
1011
1012         TRACE("Created buffer at %p\n", dsb);
1013
1014         dsb->ref = 0;
1015         dsb->secondary = 0;
1016         dsb->dsound = ds;
1017         dsb->lpVtbl = &dsbvt;
1018         dsb->iks = NULL;
1019
1020         /* size depends on version */
1021         CopyMemory(&dsb->dsbd, dsbd, dsbd->dwSize);
1022
1023         /* variable sized struct so calculate size based on format */
1024         if (wfex->wFormatTag == WAVE_FORMAT_PCM) {
1025                 alloc_size = sizeof(WAVEFORMATEX);
1026                 cp_size = sizeof(PCMWAVEFORMAT);
1027         } else 
1028                 alloc_size = cp_size = sizeof(WAVEFORMATEX) + wfex->cbSize;
1029
1030         dsb->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,alloc_size);
1031         if (dsb->pwfx == NULL) {
1032                 WARN("out of memory\n");
1033                 HeapFree(GetProcessHeap(),0,dsb);
1034                 *pdsb = NULL;
1035                 return DSERR_OUTOFMEMORY;
1036         }
1037
1038         CopyMemory(dsb->pwfx, wfex, cp_size);
1039
1040         if (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign)
1041                 dsb->buflen = dsbd->dwBufferBytes + 
1042                         (dsbd->lpwfxFormat->nBlockAlign - 
1043                         (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign));
1044         else
1045                 dsb->buflen = dsbd->dwBufferBytes;
1046
1047         dsb->freq = dsbd->lpwfxFormat->nSamplesPerSec;
1048         dsb->notify = NULL;
1049         dsb->notifies = NULL;
1050         dsb->nrofnotifies = 0;
1051         dsb->hwnotify = 0;
1052
1053         /* Check necessary hardware mixing capabilities */
1054         if (wfex->nChannels==2) capf |= DSCAPS_SECONDARYSTEREO;
1055         else capf |= DSCAPS_SECONDARYMONO;
1056         if (wfex->wBitsPerSample==16) capf |= DSCAPS_SECONDARY16BIT;
1057         else capf |= DSCAPS_SECONDARY8BIT;
1058
1059         use_hw = (ds->device->drvcaps.dwFlags & capf) == capf;
1060         TRACE("use_hw = 0x%08x, capf = 0x%08lx, ds->drvcaps.dwFlags = 0x%08lx\n", use_hw, capf, ds->device->drvcaps.dwFlags);
1061
1062         /* FIXME: check hardware sample rate mixing capabilities */
1063         /* FIXME: check app hints for software/hardware buffer (STATIC, LOCHARDWARE, etc) */
1064         /* FIXME: check whether any hardware buffers are left */
1065         /* FIXME: handle DSDHEAP_CREATEHEAP for hardware buffers */
1066
1067         /* Allocate an empty buffer */
1068         dsb->buffer = HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb->buffer)));
1069         if (dsb->buffer == NULL) {
1070                 WARN("out of memory\n");
1071                 HeapFree(GetProcessHeap(),0,dsb->pwfx);
1072                 HeapFree(GetProcessHeap(),0,dsb);
1073                 *pdsb = NULL;
1074                 return DSERR_OUTOFMEMORY;
1075         }
1076
1077         /* Allocate system memory for buffer if applicable */
1078         if ((ds->device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) || !use_hw) {
1079                 dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen);
1080                 if (dsb->buffer->memory == NULL) {
1081                         WARN("out of memory\n");
1082                         HeapFree(GetProcessHeap(),0,dsb->pwfx);
1083                         HeapFree(GetProcessHeap(),0,dsb->buffer);
1084                         HeapFree(GetProcessHeap(),0,dsb);
1085                         *pdsb = NULL;
1086                         return DSERR_OUTOFMEMORY;
1087                 }
1088                 dsb->buffer->ref = 1;
1089                 FillMemory(dsb->buffer->memory, dsb->buflen, dsbd->lpwfxFormat->wBitsPerSample == 8 ? 128 : 0);
1090         }
1091
1092         /* Allocate the hardware buffer */
1093         if (use_hw) {
1094                 err = IDsDriver_CreateSoundBuffer(ds->device->driver,wfex,dsbd->dwFlags,0,
1095                                                   &(dsb->buflen),&(dsb->buffer->memory),
1096                                                   (LPVOID*)&(dsb->hwbuf));
1097                 /* fall back to software buffer on failure */
1098                 if (err != DS_OK) {
1099                         TRACE("IDsDriver_CreateSoundBuffer failed, falling back to software buffer\n");
1100                         use_hw = 0;
1101                         if (ds->device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) {
1102                                 dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen);
1103                                 if (dsb->buffer->memory == NULL) {
1104                                         WARN("out of memory\n");
1105                                         HeapFree(GetProcessHeap(),0,dsb->buffer);
1106                                         HeapFree(GetProcessHeap(),0,dsb->pwfx);
1107                                         HeapFree(GetProcessHeap(),0,dsb);
1108                                         *pdsb = NULL;
1109                                         return DSERR_OUTOFMEMORY;
1110                                 }
1111                                 dsb->buffer->ref = 1;
1112                                 FillMemory(dsb->buffer->memory, dsb->buflen, dsbd->lpwfxFormat->wBitsPerSample == 8 ? 128 : 0);
1113                         }
1114                         err = DS_OK;
1115                 }
1116         }
1117
1118         /* calculate fragment size and write lead */
1119         DSOUND_RecalcFormat(dsb);
1120
1121         /* It's not necessary to initialize values to zero since */
1122         /* we allocated this structure with HEAP_ZERO_MEMORY... */
1123         dsb->playpos = 0;
1124         dsb->buf_mixpos = 0;
1125         dsb->state = STATE_STOPPED;
1126
1127         dsb->freqAdjust = (dsb->freq << DSOUND_FREQSHIFT) /
1128                 ds->device->pwfx->nSamplesPerSec;
1129         dsb->nAvgBytesPerSec = dsb->freq *
1130                 dsbd->lpwfxFormat->nBlockAlign;
1131
1132         if (dsb->dsbd.dwFlags & DSBCAPS_CTRL3D) {
1133                 dsb->ds3db_ds3db.dwSize = sizeof(DS3DBUFFER);
1134                 dsb->ds3db_ds3db.vPosition.x = 0.0;
1135                 dsb->ds3db_ds3db.vPosition.y = 0.0;
1136                 dsb->ds3db_ds3db.vPosition.z = 0.0;
1137                 dsb->ds3db_ds3db.vVelocity.x = 0.0;
1138                 dsb->ds3db_ds3db.vVelocity.y = 0.0;
1139                 dsb->ds3db_ds3db.vVelocity.z = 0.0;
1140                 dsb->ds3db_ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
1141                 dsb->ds3db_ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
1142                 dsb->ds3db_ds3db.vConeOrientation.x = 0.0;
1143                 dsb->ds3db_ds3db.vConeOrientation.y = 0.0;
1144                 dsb->ds3db_ds3db.vConeOrientation.z = 0.0;
1145                 dsb->ds3db_ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
1146                 dsb->ds3db_ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE;
1147                 dsb->ds3db_ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
1148                 dsb->ds3db_ds3db.dwMode = DS3DMODE_NORMAL;
1149
1150                 dsb->ds3db_need_recalc = FALSE;
1151                 DSOUND_Calc3DBuffer(dsb);
1152         } else
1153                 DSOUND_RecalcVolPan(&(dsb->volpan));
1154
1155         InitializeCriticalSection(&(dsb->lock));
1156         dsb->lock.DebugInfo->Spare[0] = (DWORD_PTR)"DSOUNDBUFFER_lock";
1157
1158         /* register buffer if not primary */
1159         if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
1160                 err = DSOUND_AddBuffer(ds, dsb);
1161                 if (err != DS_OK) {
1162                         HeapFree(GetProcessHeap(),0,dsb->buffer->memory);
1163                         HeapFree(GetProcessHeap(),0,dsb->buffer);
1164                         dsb->lock.DebugInfo->Spare[0] = 0;
1165                         DeleteCriticalSection(&(dsb->lock));
1166                         HeapFree(GetProcessHeap(),0,dsb->pwfx);
1167                         HeapFree(GetProcessHeap(),0,dsb);
1168                         dsb = NULL;
1169                 }
1170         }
1171
1172         *pdsb = dsb;
1173         return err;
1174 }
1175
1176 HRESULT IDirectSoundBufferImpl_Destroy(
1177     IDirectSoundBufferImpl *pdsb)
1178 {
1179     TRACE("(%p)\n",pdsb);
1180
1181     /* This keeps the *_Destroy functions from possibly deleting
1182      * this object until it is ready to be deleted */
1183     IDirectSoundBufferImpl_AddRef((LPDIRECTSOUNDBUFFER8)pdsb);
1184
1185     if (pdsb->iks) {
1186         WARN("iks not NULL\n");
1187         IKsBufferPropertySetImpl_Destroy(pdsb->iks);
1188         pdsb->iks = NULL;
1189     }
1190
1191     if (pdsb->ds3db) {
1192         WARN("ds3db not NULL\n");
1193         IDirectSound3DBufferImpl_Destroy(pdsb->ds3db);
1194         pdsb->ds3db = NULL;
1195     }
1196
1197     if (pdsb->notify) {
1198         WARN("notify not NULL\n");
1199         IDirectSoundNotifyImpl_Destroy(pdsb->notify);
1200         pdsb->notify = NULL;
1201     }
1202
1203     if (pdsb->secondary) {
1204         WARN("dsb not NULL\n");
1205         SecondaryBufferImpl_Destroy(pdsb->secondary);
1206         pdsb->secondary = NULL;
1207     }
1208
1209     while (IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)pdsb) > 0);
1210
1211     return S_OK;
1212 }
1213
1214 /*******************************************************************************
1215  *              SecondaryBuffer
1216  */
1217
1218 static HRESULT WINAPI SecondaryBufferImpl_QueryInterface(
1219         LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj)
1220 {
1221         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1222         TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
1223
1224         return IDirectSoundBufferImpl_QueryInterface((LPDIRECTSOUNDBUFFER8)This->dsb,riid,ppobj);
1225 }
1226
1227 static ULONG WINAPI SecondaryBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface)
1228 {
1229     SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1230     ULONG ref = InterlockedIncrement(&(This->ref));
1231     TRACE("(%p) ref was %ld\n", This, ref - 1);
1232     return ref;
1233 }
1234
1235 static ULONG WINAPI SecondaryBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface)
1236 {
1237     SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1238     ULONG ref = InterlockedDecrement(&(This->ref));
1239     TRACE("(%p) ref was %ld\n", This, ref + 1);
1240
1241     if (!ref) {
1242         This->dsb->secondary = NULL;
1243         IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER8)This->dsb);
1244         HeapFree(GetProcessHeap(), 0, This);
1245         TRACE("(%p) released\n", This);
1246     }
1247     return ref;
1248 }
1249
1250 static HRESULT WINAPI SecondaryBufferImpl_GetCaps(
1251         LPDIRECTSOUNDBUFFER8 iface,LPDSBCAPS caps)
1252 {
1253         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1254         TRACE("(%p)->(%p)\n",This,caps);
1255
1256         return IDirectSoundBufferImpl_GetCaps((LPDIRECTSOUNDBUFFER8)This->dsb,caps);
1257 }
1258
1259 static HRESULT WINAPI SecondaryBufferImpl_GetCurrentPosition(
1260         LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos)
1261 {
1262         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1263         TRACE("(%p,%p,%p)\n",This,playpos,writepos);
1264
1265         return IDirectSoundBufferImpl_GetCurrentPosition((LPDIRECTSOUNDBUFFER8)This->dsb,playpos,writepos);
1266 }
1267
1268 static HRESULT WINAPI SecondaryBufferImpl_GetFormat(
1269         LPDIRECTSOUNDBUFFER8 iface,LPWAVEFORMATEX lpwf,DWORD wfsize,LPDWORD wfwritten)
1270 {
1271         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1272         TRACE("(%p,%p,%ld,%p)\n",This,lpwf,wfsize,wfwritten);
1273
1274         return IDirectSoundBufferImpl_GetFormat((LPDIRECTSOUNDBUFFER8)This->dsb,lpwf,wfsize,wfwritten);
1275 }
1276
1277 static HRESULT WINAPI SecondaryBufferImpl_GetVolume(
1278         LPDIRECTSOUNDBUFFER8 iface,LPLONG vol)
1279 {
1280         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1281         TRACE("(%p,%p)\n",This,vol);
1282
1283         return IDirectSoundBufferImpl_GetVolume((LPDIRECTSOUNDBUFFER8)This->dsb,vol);
1284 }
1285
1286 static HRESULT WINAPI SecondaryBufferImpl_GetPan(
1287         LPDIRECTSOUNDBUFFER8 iface,LPLONG pan)
1288 {
1289         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1290         TRACE("(%p,%p)\n",This,pan);
1291
1292         return IDirectSoundBufferImpl_GetPan((LPDIRECTSOUNDBUFFER8)This->dsb,pan);
1293 }
1294
1295 static HRESULT WINAPI SecondaryBufferImpl_GetFrequency(
1296         LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq)
1297 {
1298         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1299         TRACE("(%p,%p)\n",This,freq);
1300
1301         return IDirectSoundBufferImpl_GetFrequency((LPDIRECTSOUNDBUFFER8)This->dsb,freq);
1302 }
1303
1304 static HRESULT WINAPI SecondaryBufferImpl_GetStatus(
1305         LPDIRECTSOUNDBUFFER8 iface,LPDWORD status)
1306 {
1307         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1308         TRACE("(%p,%p)\n",This,status);
1309
1310         return IDirectSoundBufferImpl_GetStatus((LPDIRECTSOUNDBUFFER8)This->dsb,status);
1311 }
1312
1313 static HRESULT WINAPI SecondaryBufferImpl_Initialize(
1314         LPDIRECTSOUNDBUFFER8 iface,LPDIRECTSOUND dsound,LPCDSBUFFERDESC dbsd)
1315 {
1316         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1317         TRACE("(%p,%p,%p)\n",This,dsound,dbsd);
1318
1319         return IDirectSoundBufferImpl_Initialize((LPDIRECTSOUNDBUFFER8)This->dsb,dsound,dbsd);
1320 }
1321
1322 static HRESULT WINAPI SecondaryBufferImpl_Lock(
1323     LPDIRECTSOUNDBUFFER8 iface,
1324     DWORD writecursor,
1325     DWORD writebytes,
1326     LPVOID lplpaudioptr1,
1327     LPDWORD audiobytes1,
1328     LPVOID lplpaudioptr2,
1329     LPDWORD audiobytes2,
1330     DWORD dwFlags)
1331 {
1332     SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1333     TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx)\n",
1334         This,writecursor,writebytes,lplpaudioptr1,audiobytes1,lplpaudioptr2,audiobytes2,dwFlags);
1335
1336     return IDirectSoundBufferImpl_Lock((LPDIRECTSOUNDBUFFER8)This->dsb,
1337         writecursor,writebytes,lplpaudioptr1,audiobytes1,lplpaudioptr2,audiobytes2,dwFlags);
1338 }
1339
1340 static HRESULT WINAPI SecondaryBufferImpl_Play(
1341         LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags)
1342 {
1343         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1344         TRACE("(%p,%08lx,%08lx,%08lx)\n",This,reserved1,reserved2,flags);
1345
1346         return IDirectSoundBufferImpl_Play((LPDIRECTSOUNDBUFFER8)This->dsb,reserved1,reserved2,flags);
1347 }
1348
1349 static HRESULT WINAPI SecondaryBufferImpl_SetCurrentPosition(
1350         LPDIRECTSOUNDBUFFER8 iface,DWORD newpos)
1351 {
1352         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1353         TRACE("(%p,%ld)\n",This,newpos);
1354
1355         return IDirectSoundBufferImpl_SetCurrentPosition((LPDIRECTSOUNDBUFFER8)This->dsb,newpos);
1356 }
1357
1358 static HRESULT WINAPI SecondaryBufferImpl_SetFormat(
1359         LPDIRECTSOUNDBUFFER8 iface,LPCWAVEFORMATEX wfex)
1360 {
1361         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1362         TRACE("(%p,%p)\n",This,wfex);
1363
1364         return IDirectSoundBufferImpl_SetFormat((LPDIRECTSOUNDBUFFER8)This->dsb,wfex);
1365 }
1366
1367 static HRESULT WINAPI SecondaryBufferImpl_SetVolume(
1368         LPDIRECTSOUNDBUFFER8 iface,LONG vol)
1369 {
1370         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1371         TRACE("(%p,%ld)\n",This,vol);
1372
1373         return IDirectSoundBufferImpl_SetVolume((LPDIRECTSOUNDBUFFER8)This->dsb,vol);
1374 }
1375
1376 static HRESULT WINAPI SecondaryBufferImpl_SetPan(
1377         LPDIRECTSOUNDBUFFER8 iface,LONG pan)
1378 {
1379         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1380         TRACE("(%p,%ld)\n",This,pan);
1381
1382         return IDirectSoundBufferImpl_SetPan((LPDIRECTSOUNDBUFFER8)This->dsb,pan);
1383 }
1384
1385 static HRESULT WINAPI SecondaryBufferImpl_SetFrequency(
1386         LPDIRECTSOUNDBUFFER8 iface,DWORD freq)
1387 {
1388         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1389         TRACE("(%p,%ld)\n",This,freq);
1390
1391         return IDirectSoundBufferImpl_SetFrequency((LPDIRECTSOUNDBUFFER8)This->dsb,freq);
1392 }
1393
1394 static HRESULT WINAPI SecondaryBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface)
1395 {
1396         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1397         TRACE("(%p)\n",This);
1398
1399         return IDirectSoundBufferImpl_Stop((LPDIRECTSOUNDBUFFER8)This->dsb);
1400 }
1401
1402 static HRESULT WINAPI SecondaryBufferImpl_Unlock(
1403     LPDIRECTSOUNDBUFFER8 iface,
1404     LPVOID lpvAudioPtr1,
1405     DWORD dwAudioBytes1,
1406     LPVOID lpvAudioPtr2,
1407     DWORD dwAudioBytes2)
1408 {
1409     SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1410     TRACE("(%p,%p,%ld,%p,%ld)\n",
1411         This, lpvAudioPtr1, dwAudioBytes1, lpvAudioPtr2, dwAudioBytes2);
1412
1413     return IDirectSoundBufferImpl_Unlock((LPDIRECTSOUNDBUFFER8)This->dsb,
1414         lpvAudioPtr1,dwAudioBytes1,lpvAudioPtr2,dwAudioBytes2);
1415 }
1416
1417 static HRESULT WINAPI SecondaryBufferImpl_Restore(
1418         LPDIRECTSOUNDBUFFER8 iface)
1419 {
1420         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1421         TRACE("(%p)\n",This);
1422
1423         return IDirectSoundBufferImpl_Restore((LPDIRECTSOUNDBUFFER8)This->dsb);
1424 }
1425
1426 static HRESULT WINAPI SecondaryBufferImpl_SetFX(
1427         LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes)
1428 {
1429         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1430         TRACE("(%p,%lu,%p,%p)\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
1431
1432         return IDirectSoundBufferImpl_SetFX((LPDIRECTSOUNDBUFFER8)This->dsb,dwEffectsCount,pDSFXDesc,pdwResultCodes);
1433 }
1434
1435 static HRESULT WINAPI SecondaryBufferImpl_AcquireResources(
1436         LPDIRECTSOUNDBUFFER8 iface,DWORD dwFlags,DWORD dwEffectsCount,LPDWORD pdwResultCodes)
1437 {
1438         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1439         TRACE("(%p,%08lu,%lu,%p)\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
1440
1441         return IDirectSoundBufferImpl_AcquireResources((LPDIRECTSOUNDBUFFER8)This->dsb,dwFlags,dwEffectsCount,pdwResultCodes);
1442 }
1443
1444 static HRESULT WINAPI SecondaryBufferImpl_GetObjectInPath(
1445         LPDIRECTSOUNDBUFFER8 iface,REFGUID rguidObject,DWORD dwIndex,REFGUID rguidInterface,LPVOID* ppObject)
1446 {
1447         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1448         TRACE("(%p,%s,%lu,%s,%p)\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
1449
1450         return IDirectSoundBufferImpl_GetObjectInPath((LPDIRECTSOUNDBUFFER8)This->dsb,rguidObject,dwIndex,rguidInterface,ppObject);
1451 }
1452
1453 static const IDirectSoundBuffer8Vtbl sbvt =
1454 {
1455         SecondaryBufferImpl_QueryInterface,
1456         SecondaryBufferImpl_AddRef,
1457         SecondaryBufferImpl_Release,
1458         SecondaryBufferImpl_GetCaps,
1459         SecondaryBufferImpl_GetCurrentPosition,
1460         SecondaryBufferImpl_GetFormat,
1461         SecondaryBufferImpl_GetVolume,
1462         SecondaryBufferImpl_GetPan,
1463         SecondaryBufferImpl_GetFrequency,
1464         SecondaryBufferImpl_GetStatus,
1465         SecondaryBufferImpl_Initialize,
1466         SecondaryBufferImpl_Lock,
1467         SecondaryBufferImpl_Play,
1468         SecondaryBufferImpl_SetCurrentPosition,
1469         SecondaryBufferImpl_SetFormat,
1470         SecondaryBufferImpl_SetVolume,
1471         SecondaryBufferImpl_SetPan,
1472         SecondaryBufferImpl_SetFrequency,
1473         SecondaryBufferImpl_Stop,
1474         SecondaryBufferImpl_Unlock,
1475         SecondaryBufferImpl_Restore,
1476         SecondaryBufferImpl_SetFX,
1477         SecondaryBufferImpl_AcquireResources,
1478         SecondaryBufferImpl_GetObjectInPath
1479 };
1480
1481 HRESULT SecondaryBufferImpl_Create(
1482         IDirectSoundBufferImpl *dsb,
1483         SecondaryBufferImpl **psb)
1484 {
1485         SecondaryBufferImpl *sb;
1486         TRACE("(%p,%p)\n",dsb,psb);
1487
1488         sb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*sb));
1489
1490         if (sb == 0) {
1491                 WARN("out of memory\n");
1492                 *psb = NULL;
1493                 return DSERR_OUTOFMEMORY;
1494         }
1495         sb->ref = 0;
1496         sb->dsb = dsb;
1497         sb->lpVtbl = &sbvt;
1498
1499         IDirectSoundBuffer8_AddRef((LPDIRECTSOUNDBUFFER8)dsb);
1500         *psb = sb;
1501         return S_OK;
1502 }
1503
1504 HRESULT SecondaryBufferImpl_Destroy(
1505     SecondaryBufferImpl *pdsb)
1506 {
1507     TRACE("(%p)\n",pdsb);
1508
1509     while (SecondaryBufferImpl_Release((LPDIRECTSOUNDBUFFER8)pdsb) > 0);
1510
1511     return S_OK;
1512 }