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