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