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