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