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