dsound: Merge IDirectSound3DBuffer into the secondary buffer object.
[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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include <stdarg.h>
23
24 #define NONAMELESSSTRUCT
25 #define NONAMELESSUNION
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "mmsystem.h"
30 #include "winternl.h"
31 #include "vfwmsgs.h"
32 #include "wine/debug.h"
33 #include "dsound.h"
34 #include "dsound_private.h"
35 #include "dsconf.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
38
39 /*******************************************************************************
40  *              IDirectSoundNotify
41  */
42
43 struct IDirectSoundNotifyImpl
44 {
45     /* IUnknown fields */
46     const IDirectSoundNotifyVtbl *lpVtbl;
47     LONG                        ref;
48     IDirectSoundBufferImpl*     dsb;
49 };
50
51 static HRESULT IDirectSoundNotifyImpl_Create(IDirectSoundBufferImpl *dsb,
52                                              IDirectSoundNotifyImpl **pdsn);
53 static HRESULT IDirectSoundNotifyImpl_Destroy(IDirectSoundNotifyImpl *pdsn);
54
55 static HRESULT WINAPI IDirectSoundNotifyImpl_QueryInterface(
56         LPDIRECTSOUNDNOTIFY iface,REFIID riid,LPVOID *ppobj
57 ) {
58         IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
59         TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
60
61         if (This->dsb == NULL) {
62                 WARN("invalid parameter\n");
63                 return E_INVALIDARG;
64         }
65
66         return IDirectSoundBuffer_QueryInterface((LPDIRECTSOUNDBUFFER)This->dsb, riid, ppobj);
67 }
68
69 static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface)
70 {
71     IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
72     ULONG ref = InterlockedIncrement(&(This->ref));
73     TRACE("(%p) ref was %d\n", This, ref - 1);
74     return ref;
75 }
76
77 static ULONG WINAPI IDirectSoundNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface)
78 {
79     IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
80     ULONG ref = InterlockedDecrement(&(This->ref));
81     TRACE("(%p) ref was %d\n", This, ref + 1);
82
83     if (!ref) {
84         This->dsb->notify = NULL;
85         IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->dsb);
86         HeapFree(GetProcessHeap(), 0, This);
87         TRACE("(%p) released\n", This);
88     }
89     return ref;
90 }
91
92 static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(
93         LPDIRECTSOUNDNOTIFY iface,DWORD howmuch,LPCDSBPOSITIONNOTIFY notify
94 ) {
95         IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
96         TRACE("(%p,0x%08x,%p)\n",This,howmuch,notify);
97
98         if (howmuch > 0 && notify == NULL) {
99             WARN("invalid parameter: notify == NULL\n");
100             return DSERR_INVALIDPARAM;
101         }
102
103         if (TRACE_ON(dsound)) {
104             unsigned int        i;
105             for (i=0;i<howmuch;i++)
106                 TRACE("notify at %d to %p\n",
107                     notify[i].dwOffset,notify[i].hEventNotify);
108         }
109
110         if (howmuch > 0) {
111             /* Make an internal copy of the caller-supplied array.
112              * Replace the existing copy if one is already present. */
113             HeapFree(GetProcessHeap(), 0, This->dsb->notifies);
114             This->dsb->notifies = HeapAlloc(GetProcessHeap(), 0,
115                         howmuch * sizeof(DSBPOSITIONNOTIFY));
116
117             if (This->dsb->notifies == NULL) {
118                     WARN("out of memory\n");
119                     return DSERR_OUTOFMEMORY;
120             }
121             CopyMemory(This->dsb->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
122             This->dsb->nrofnotifies = howmuch;
123         } else {
124            HeapFree(GetProcessHeap(), 0, This->dsb->notifies);
125            This->dsb->notifies = NULL;
126            This->dsb->nrofnotifies = 0;
127         }
128
129         return S_OK;
130 }
131
132 static const IDirectSoundNotifyVtbl dsnvt =
133 {
134     IDirectSoundNotifyImpl_QueryInterface,
135     IDirectSoundNotifyImpl_AddRef,
136     IDirectSoundNotifyImpl_Release,
137     IDirectSoundNotifyImpl_SetNotificationPositions,
138 };
139
140 static HRESULT IDirectSoundNotifyImpl_Create(
141     IDirectSoundBufferImpl * dsb,
142     IDirectSoundNotifyImpl **pdsn)
143 {
144     IDirectSoundNotifyImpl * dsn;
145     TRACE("(%p,%p)\n",dsb,pdsn);
146
147     dsn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dsn));
148
149     if (dsn == NULL) {
150         WARN("out of memory\n");
151         return DSERR_OUTOFMEMORY;
152     }
153
154     dsn->ref = 0;
155     dsn->lpVtbl = &dsnvt;
156     dsn->dsb = dsb;
157     dsb->notify = dsn;
158     IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)dsb);
159
160     *pdsn = dsn;
161     return DS_OK;
162 }
163
164 static HRESULT IDirectSoundNotifyImpl_Destroy(
165     IDirectSoundNotifyImpl *pdsn)
166 {
167     TRACE("(%p)\n",pdsn);
168
169     while (IDirectSoundNotifyImpl_Release((LPDIRECTSOUNDNOTIFY)pdsn) > 0);
170
171     return DS_OK;
172 }
173
174 /*******************************************************************************
175  *              IDirectSoundBuffer
176  */
177
178 static inline IDirectSoundBufferImpl *impl_from_IDirectSoundBuffer8(IDirectSoundBuffer8 *iface)
179 {
180     return CONTAINING_RECORD(iface, IDirectSoundBufferImpl, IDirectSoundBuffer8_iface);
181 }
182
183 static inline BOOL is_primary_buffer(IDirectSoundBufferImpl *This)
184 {
185     return This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER ? TRUE : FALSE;
186 }
187
188 static HRESULT WINAPI IDirectSoundBufferImpl_SetFormat(IDirectSoundBuffer8 *iface,
189         LPCWAVEFORMATEX wfex)
190 {
191     IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
192
193     TRACE("(%p,%p)\n", iface, wfex);
194
195     if (is_primary_buffer(This))
196         return primarybuffer_SetFormat(This->device, wfex);
197     else {
198         WARN("not available for secondary buffers.\n");
199         return DSERR_INVALIDCALL;
200     }
201 }
202
203 static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume(IDirectSoundBuffer8 *iface, LONG vol)
204 {
205         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
206         LONG oldVol;
207
208         HRESULT hres = DS_OK;
209
210         TRACE("(%p,%d)\n",This,vol);
211
212         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
213                 WARN("control unavailable: This->dsbd.dwFlags = 0x%08x\n", This->dsbd.dwFlags);
214                 return DSERR_CONTROLUNAVAIL;
215         }
216
217         if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN)) {
218                 WARN("invalid parameter: vol = %d\n", vol);
219                 return DSERR_INVALIDPARAM;
220         }
221
222         /* **** */
223         RtlAcquireResourceExclusive(&This->lock, TRUE);
224
225         if (This->dsbd.dwFlags & DSBCAPS_CTRL3D) {
226                 oldVol = This->ds3db_lVolume;
227                 This->ds3db_lVolume = vol;
228                 if (vol != oldVol)
229                         /* recalc 3d volume, which in turn recalcs the pans */
230                         DSOUND_Calc3DBuffer(This);
231         } else {
232                 oldVol = This->volpan.lVolume;
233                 This->volpan.lVolume = vol;
234                 if (vol != oldVol)
235                         DSOUND_RecalcVolPan(&(This->volpan));
236         }
237
238         RtlReleaseResource(&This->lock);
239         /* **** */
240
241         return hres;
242 }
243
244 static HRESULT WINAPI IDirectSoundBufferImpl_GetVolume(IDirectSoundBuffer8 *iface, LONG *vol)
245 {
246         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
247
248         TRACE("(%p,%p)\n",This,vol);
249
250         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
251                 WARN("control unavailable\n");
252                 return DSERR_CONTROLUNAVAIL;
253         }
254
255         if (vol == NULL) {
256                 WARN("invalid parameter: vol == NULL\n");
257                 return DSERR_INVALIDPARAM;
258         }
259
260         *vol = This->volpan.lVolume;
261
262         return DS_OK;
263 }
264
265 static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency(IDirectSoundBuffer8 *iface, DWORD freq)
266 {
267         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
268         DWORD oldFreq;
269
270         TRACE("(%p,%d)\n",This,freq);
271
272         if (is_primary_buffer(This)) {
273                 WARN("not available for primary buffers.\n");
274                 return DSERR_CONTROLUNAVAIL;
275         }
276
277         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLFREQUENCY)) {
278                 WARN("control unavailable\n");
279                 return DSERR_CONTROLUNAVAIL;
280         }
281
282         if (freq == DSBFREQUENCY_ORIGINAL)
283                 freq = This->pwfx->nSamplesPerSec;
284
285         if ((freq < DSBFREQUENCY_MIN) || (freq > DSBFREQUENCY_MAX)) {
286                 WARN("invalid parameter: freq = %d\n", freq);
287                 return DSERR_INVALIDPARAM;
288         }
289
290         /* **** */
291         RtlAcquireResourceExclusive(&This->lock, TRUE);
292
293         oldFreq = This->freq;
294         This->freq = freq;
295         if (freq != oldFreq) {
296                 This->freqAdjust = ((DWORD64)This->freq << DSOUND_FREQSHIFT) / This->device->pwfx->nSamplesPerSec;
297                 This->nAvgBytesPerSec = freq * This->pwfx->nBlockAlign;
298                 DSOUND_RecalcFormat(This);
299         }
300
301         RtlReleaseResource(&This->lock);
302         /* **** */
303
304         return DS_OK;
305 }
306
307 static HRESULT WINAPI IDirectSoundBufferImpl_Play(IDirectSoundBuffer8 *iface, DWORD reserved1,
308         DWORD reserved2, DWORD flags)
309 {
310         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
311         HRESULT hres = DS_OK;
312
313         TRACE("(%p,%08x,%08x,%08x)\n",This,reserved1,reserved2,flags);
314
315         /* **** */
316         RtlAcquireResourceExclusive(&This->lock, TRUE);
317
318         This->playflags = flags;
319         if (This->state == STATE_STOPPED) {
320                 This->leadin = TRUE;
321                 This->state = STATE_STARTING;
322         } else if (This->state == STATE_STOPPING)
323                 This->state = STATE_PLAYING;
324
325         RtlReleaseResource(&This->lock);
326         /* **** */
327
328         return hres;
329 }
330
331 static HRESULT WINAPI IDirectSoundBufferImpl_Stop(IDirectSoundBuffer8 *iface)
332 {
333         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
334         HRESULT hres = DS_OK;
335
336         TRACE("(%p)\n",This);
337
338         /* **** */
339         RtlAcquireResourceExclusive(&This->lock, TRUE);
340
341         if (This->state == STATE_PLAYING)
342                 This->state = STATE_STOPPING;
343         else if (This->state == STATE_STARTING)
344         {
345                 This->state = STATE_STOPPED;
346                 DSOUND_CheckEvent(This, 0, 0);
347         }
348
349         RtlReleaseResource(&This->lock);
350         /* **** */
351
352         return hres;
353 }
354
355 static ULONG WINAPI IDirectSoundBufferImpl_AddRef(IDirectSoundBuffer8 *iface)
356 {
357     IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
358     ULONG ref = InterlockedIncrement(&This->ref);
359
360     TRACE("(%p) ref was %d\n", This, ref - 1);
361
362     if(ref == 1)
363         InterlockedIncrement(&This->numIfaces);
364
365     return ref;
366 }
367
368 static ULONG WINAPI IDirectSoundBufferImpl_Release(IDirectSoundBuffer8 *iface)
369 {
370     IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
371     ULONG ref = InterlockedDecrement(&This->ref);
372
373     TRACE("(%p) ref was %d\n", This, ref + 1);
374
375     if (!ref && !InterlockedDecrement(&This->numIfaces)) {
376         if (is_primary_buffer(This))
377             primarybuffer_destroy(This);
378         else
379             secondarybuffer_destroy(This);
380     }
381     return ref;
382 }
383
384 static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(IDirectSoundBuffer8 *iface,
385         DWORD *playpos, DWORD *writepos)
386 {
387         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
388         DWORD pos;
389
390         TRACE("(%p,%p,%p)\n",This,playpos,writepos);
391
392         RtlAcquireResourceShared(&This->lock, TRUE);
393
394         pos = This->sec_mixpos;
395
396         /* sanity */
397         if (pos >= This->buflen){
398                 FIXME("Bad play position. playpos: %d, buflen: %d\n", pos, This->buflen);
399                 pos %= This->buflen;
400         }
401
402         if (playpos)
403                 *playpos = pos;
404         if (writepos)
405                 *writepos = pos;
406
407         if (writepos && This->state != STATE_STOPPED) {
408                 /* apply the documented 10ms lead to writepos */
409                 *writepos += This->writelead;
410                 *writepos %= This->buflen;
411         }
412
413         RtlReleaseResource(&This->lock);
414
415         TRACE("playpos = %d, writepos = %d, buflen=%d (%p, time=%d)\n",
416                 playpos?*playpos:-1, writepos?*writepos:-1, This->buflen, This, GetTickCount());
417
418         return DS_OK;
419 }
420
421 static HRESULT WINAPI IDirectSoundBufferImpl_GetStatus(IDirectSoundBuffer8 *iface, DWORD *status)
422 {
423         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
424
425         TRACE("(%p,%p), thread is %04x\n",This,status,GetCurrentThreadId());
426
427         if (status == NULL) {
428                 WARN("invalid parameter: status = NULL\n");
429                 return DSERR_INVALIDPARAM;
430         }
431
432         *status = 0;
433         RtlAcquireResourceShared(&This->lock, TRUE);
434         if ((This->state == STATE_STARTING) || (This->state == STATE_PLAYING)) {
435                 *status |= DSBSTATUS_PLAYING;
436                 if (This->playflags & DSBPLAY_LOOPING)
437                         *status |= DSBSTATUS_LOOPING;
438         }
439         RtlReleaseResource(&This->lock);
440
441         TRACE("status=%x\n", *status);
442         return DS_OK;
443 }
444
445
446 static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat(IDirectSoundBuffer8 *iface,
447         LPWAVEFORMATEX lpwf, DWORD wfsize, DWORD *wfwritten)
448 {
449     IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
450     DWORD size;
451
452     TRACE("(%p,%p,%d,%p)\n",This,lpwf,wfsize,wfwritten);
453
454     size = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;
455
456     if (lpwf) { /* NULL is valid */
457         if (wfsize >= size) {
458             CopyMemory(lpwf,This->pwfx,size);
459             if (wfwritten)
460                 *wfwritten = size;
461         } else {
462             WARN("invalid parameter: wfsize too small\n");
463             CopyMemory(lpwf,This->pwfx,wfsize);
464             if (wfwritten)
465                 *wfwritten = wfsize;
466             return DSERR_INVALIDPARAM;
467         }
468     } else {
469         if (wfwritten)
470             *wfwritten = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;
471         else {
472             WARN("invalid parameter: wfwritten == NULL\n");
473             return DSERR_INVALIDPARAM;
474         }
475     }
476
477     return DS_OK;
478 }
479
480 static HRESULT WINAPI IDirectSoundBufferImpl_Lock(IDirectSoundBuffer8 *iface, DWORD writecursor,
481         DWORD writebytes, void **lplpaudioptr1, DWORD *audiobytes1, void **lplpaudioptr2,
482         DWORD *audiobytes2, DWORD flags)
483 {
484         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
485         HRESULT hres = DS_OK;
486
487         TRACE("(%p,%d,%d,%p,%p,%p,%p,0x%08x) at %d\n", This, writecursor, writebytes, lplpaudioptr1,
488                 audiobytes1, lplpaudioptr2, audiobytes2, flags, GetTickCount());
489
490         if (!audiobytes1)
491             return DSERR_INVALIDPARAM;
492
493         /* when this flag is set, writecursor is meaningless and must be calculated */
494         if (flags & DSBLOCK_FROMWRITECURSOR) {
495                 /* GetCurrentPosition does too much magic to duplicate here */
496                 hres = IDirectSoundBufferImpl_GetCurrentPosition(iface, NULL, &writecursor);
497                 if (hres != DS_OK) {
498                         WARN("IDirectSoundBufferImpl_GetCurrentPosition failed\n");
499                         return hres;
500                 }
501         }
502
503         /* when this flag is set, writebytes is meaningless and must be set */
504         if (flags & DSBLOCK_ENTIREBUFFER)
505                 writebytes = This->buflen;
506
507         if (writecursor >= This->buflen) {
508                 WARN("Invalid parameter, writecursor: %u >= buflen: %u\n",
509                      writecursor, This->buflen);
510                 return DSERR_INVALIDPARAM;
511         }
512
513         if (writebytes > This->buflen) {
514                 WARN("Invalid parameter, writebytes: %u > buflen: %u\n",
515                      writebytes, This->buflen);
516                 return DSERR_INVALIDPARAM;
517         }
518
519         /* **** */
520         RtlAcquireResourceShared(&This->lock, TRUE);
521
522         if (writecursor+writebytes <= This->buflen) {
523                 *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
524                 if (This->sec_mixpos >= writecursor && This->sec_mixpos < writecursor + writebytes && This->state == STATE_PLAYING)
525                         WARN("Overwriting mixing position, case 1\n");
526                 *audiobytes1 = writebytes;
527                 if (lplpaudioptr2)
528                         *(LPBYTE*)lplpaudioptr2 = NULL;
529                 if (audiobytes2)
530                         *audiobytes2 = 0;
531                 TRACE("Locked %p(%i bytes) and %p(%i bytes) writecursor=%d\n",
532                   *(LPBYTE*)lplpaudioptr1, *audiobytes1, lplpaudioptr2 ? *(LPBYTE*)lplpaudioptr2 : NULL, audiobytes2 ? *audiobytes2: 0, writecursor);
533                 TRACE("->%d.0\n",writebytes);
534         } else {
535                 DWORD remainder = writebytes + writecursor - This->buflen;
536                 *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
537                 *audiobytes1 = This->buflen-writecursor;
538                 if (This->sec_mixpos >= writecursor && This->sec_mixpos < writecursor + writebytes && This->state == STATE_PLAYING)
539                         WARN("Overwriting mixing position, case 2\n");
540                 if (lplpaudioptr2)
541                         *(LPBYTE*)lplpaudioptr2 = This->buffer->memory;
542                 if (audiobytes2)
543                         *audiobytes2 = writebytes-(This->buflen-writecursor);
544                 if (audiobytes2 && This->sec_mixpos < remainder && This->state == STATE_PLAYING)
545                         WARN("Overwriting mixing position, case 3\n");
546                 TRACE("Locked %p(%i bytes) and %p(%i bytes) writecursor=%d\n", *(LPBYTE*)lplpaudioptr1, *audiobytes1, lplpaudioptr2 ? *(LPBYTE*)lplpaudioptr2 : NULL, audiobytes2 ? *audiobytes2: 0, writecursor);
547         }
548
549         RtlReleaseResource(&This->lock);
550         /* **** */
551
552         return DS_OK;
553 }
554
555 static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(IDirectSoundBuffer8 *iface,
556         DWORD newpos)
557 {
558         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
559         HRESULT hres = DS_OK;
560         DWORD oldpos;
561
562         TRACE("(%p,%d)\n",This,newpos);
563
564         /* **** */
565         RtlAcquireResourceExclusive(&This->lock, TRUE);
566
567         oldpos = This->sec_mixpos;
568
569         /* start mixing from this new location instead */
570         newpos %= This->buflen;
571         newpos -= newpos%This->pwfx->nBlockAlign;
572         This->sec_mixpos = newpos;
573
574         /* at this point, do not attempt to reset buffers, mess with primary mix position,
575            or anything like that to reduce latency. The data already prebuffered cannot be changed */
576
577         /* position HW buffer if applicable, else just start mixing from new location instead */
578         if (oldpos != newpos)
579                 This->buf_mixpos = DSOUND_secpos_to_bufpos(This, newpos, 0, NULL);
580
581         RtlReleaseResource(&This->lock);
582         /* **** */
583
584         return hres;
585 }
586
587 static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(IDirectSoundBuffer8 *iface, LONG pan)
588 {
589         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
590         HRESULT hres = DS_OK;
591
592         TRACE("(%p,%d)\n",This,pan);
593
594         if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT)) {
595                 WARN("invalid parameter: pan = %d\n", pan);
596                 return DSERR_INVALIDPARAM;
597         }
598
599         /* You cannot use both pan and 3D controls */
600         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
601             (This->dsbd.dwFlags & DSBCAPS_CTRL3D)) {
602                 WARN("control unavailable\n");
603                 return DSERR_CONTROLUNAVAIL;
604         }
605
606         /* **** */
607         RtlAcquireResourceExclusive(&This->lock, TRUE);
608
609         if (This->volpan.lPan != pan) {
610                 This->volpan.lPan = pan;
611                 DSOUND_RecalcVolPan(&(This->volpan));
612         }
613
614         RtlReleaseResource(&This->lock);
615         /* **** */
616
617         return hres;
618 }
619
620 static HRESULT WINAPI IDirectSoundBufferImpl_GetPan(IDirectSoundBuffer8 *iface, LONG *pan)
621 {
622         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
623
624         TRACE("(%p,%p)\n",This,pan);
625
626         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN)) {
627                 WARN("control unavailable\n");
628                 return DSERR_CONTROLUNAVAIL;
629         }
630
631         if (pan == NULL) {
632                 WARN("invalid parameter: pan = NULL\n");
633                 return DSERR_INVALIDPARAM;
634         }
635
636         *pan = This->volpan.lPan;
637
638         return DS_OK;
639 }
640
641 static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(IDirectSoundBuffer8 *iface, void *p1, DWORD x1,
642         void *p2, DWORD x2)
643 {
644         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface), *iter;
645         HRESULT hres = DS_OK;
646
647         TRACE("(%p,%p,%d,%p,%d)\n", This,p1,x1,p2,x2);
648
649         if (!p2)
650                 x2 = 0;
651
652     if((p1 && ((BYTE*)p1 < This->buffer->memory ||
653                     (BYTE*)p1 >= This->buffer->memory + This->buflen)) ||
654             (p2 && ((BYTE*)p2 < This->buffer->memory ||
655                     (BYTE*)p2 >= This->buffer->memory + This->buflen)))
656         return DSERR_INVALIDPARAM;
657
658         if (x1 || x2)
659         {
660                 RtlAcquireResourceShared(&This->device->buffer_list_lock, TRUE);
661                 LIST_FOR_EACH_ENTRY(iter, &This->buffer->buffers, IDirectSoundBufferImpl, entry )
662                 {
663                         RtlAcquireResourceShared(&iter->lock, TRUE);
664                         if (x1)
665                         {
666                             if(x1 + (DWORD_PTR)p1 - (DWORD_PTR)iter->buffer->memory > iter->buflen)
667                               hres = DSERR_INVALIDPARAM;
668                         }
669                         RtlReleaseResource(&iter->lock);
670                 }
671                 RtlReleaseResource(&This->device->buffer_list_lock);
672         }
673
674         return hres;
675 }
676
677 static HRESULT WINAPI IDirectSoundBufferImpl_Restore(IDirectSoundBuffer8 *iface)
678 {
679         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
680
681         FIXME("(%p):stub\n",This);
682         return DS_OK;
683 }
684
685 static HRESULT WINAPI IDirectSoundBufferImpl_GetFrequency(IDirectSoundBuffer8 *iface, DWORD *freq)
686 {
687         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
688
689         TRACE("(%p,%p)\n",This,freq);
690
691         if (freq == NULL) {
692                 WARN("invalid parameter: freq = NULL\n");
693                 return DSERR_INVALIDPARAM;
694         }
695
696         *freq = This->freq;
697         TRACE("-> %d\n", *freq);
698
699         return DS_OK;
700 }
701
702 static HRESULT WINAPI IDirectSoundBufferImpl_SetFX(IDirectSoundBuffer8 *iface, DWORD dwEffectsCount,
703         LPDSEFFECTDESC pDSFXDesc, DWORD *pdwResultCodes)
704 {
705         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
706         DWORD u;
707
708         FIXME("(%p,%u,%p,%p): stub\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
709
710         if (pdwResultCodes)
711                 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
712
713         WARN("control unavailable\n");
714         return DSERR_CONTROLUNAVAIL;
715 }
716
717 static HRESULT WINAPI IDirectSoundBufferImpl_AcquireResources(IDirectSoundBuffer8 *iface,
718         DWORD dwFlags, DWORD dwEffectsCount, DWORD *pdwResultCodes)
719 {
720         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
721         DWORD u;
722
723         FIXME("(%p,%08u,%u,%p): stub, faking success\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
724
725         if (pdwResultCodes)
726                 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
727
728         WARN("control unavailable\n");
729         return DS_OK;
730 }
731
732 static HRESULT WINAPI IDirectSoundBufferImpl_GetObjectInPath(IDirectSoundBuffer8 *iface,
733         REFGUID rguidObject, DWORD dwIndex, REFGUID rguidInterface, void **ppObject)
734 {
735         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
736
737         FIXME("(%p,%s,%u,%s,%p): stub\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
738
739         WARN("control unavailable\n");
740         return DSERR_CONTROLUNAVAIL;
741 }
742
743 static HRESULT WINAPI IDirectSoundBufferImpl_Initialize(IDirectSoundBuffer8 *iface,
744         IDirectSound *dsound, LPCDSBUFFERDESC dbsd)
745 {
746         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
747
748         WARN("(%p) already initialized\n", This);
749         return DSERR_ALREADYINITIALIZED;
750 }
751
752 static HRESULT WINAPI IDirectSoundBufferImpl_GetCaps(IDirectSoundBuffer8 *iface, LPDSBCAPS caps)
753 {
754         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
755
756         TRACE("(%p)->(%p)\n",This,caps);
757
758         if (caps == NULL) {
759                 WARN("invalid parameter: caps == NULL\n");
760                 return DSERR_INVALIDPARAM;
761         }
762
763         if (caps->dwSize < sizeof(*caps)) {
764                 WARN("invalid parameter: caps->dwSize = %d\n",caps->dwSize);
765                 return DSERR_INVALIDPARAM;
766         }
767
768         caps->dwFlags = This->dsbd.dwFlags;
769         caps->dwFlags |= DSBCAPS_LOCSOFTWARE;
770
771         caps->dwBufferBytes = This->buflen;
772
773         /* According to windows, this is zero*/
774         caps->dwUnlockTransferRate = 0;
775         caps->dwPlayCpuOverhead = 0;
776
777         return DS_OK;
778 }
779
780 static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface(IDirectSoundBuffer8 *iface, REFIID riid,
781         void **ppobj)
782 {
783         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
784
785         TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
786
787         if (ppobj == NULL) {
788                 WARN("invalid parameter\n");
789                 return E_INVALIDARG;
790         }
791
792         *ppobj = NULL;  /* assume failure */
793
794         if ( IsEqualGUID(riid, &IID_IUnknown) ||
795              IsEqualGUID(riid, &IID_IDirectSoundBuffer) ||
796              IsEqualGUID(riid, &IID_IDirectSoundBuffer8) ) {
797                 IDirectSoundBuffer8_AddRef(iface);
798                 *ppobj = iface;
799                 return S_OK;
800         }
801
802         if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
803                 if (!This->notify)
804                         IDirectSoundNotifyImpl_Create(This, &(This->notify));
805                 if (This->notify) {
806                         IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify);
807                         *ppobj = This->notify;
808                         return S_OK;
809                 }
810                 WARN("IID_IDirectSoundNotify\n");
811                 return E_NOINTERFACE;
812         }
813
814         if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) {
815                 IDirectSound3DBuffer_AddRef(&This->IDirectSound3DBuffer_iface);
816                 *ppobj = &This->IDirectSound3DBuffer_iface;
817                 return S_OK;
818         }
819
820         if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
821                 ERR("app requested IDirectSound3DListener on secondary buffer\n");
822                 return E_NOINTERFACE;
823         }
824
825         if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) {
826                 IKsPropertySet_AddRef(&This->IKsPropertySet_iface);
827                 *ppobj = &This->IKsPropertySet_iface;
828                 return S_OK;
829         }
830
831         FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
832
833         return E_NOINTERFACE;
834 }
835
836 static const IDirectSoundBuffer8Vtbl dsbvt =
837 {
838         IDirectSoundBufferImpl_QueryInterface,
839         IDirectSoundBufferImpl_AddRef,
840         IDirectSoundBufferImpl_Release,
841         IDirectSoundBufferImpl_GetCaps,
842         IDirectSoundBufferImpl_GetCurrentPosition,
843         IDirectSoundBufferImpl_GetFormat,
844         IDirectSoundBufferImpl_GetVolume,
845         IDirectSoundBufferImpl_GetPan,
846         IDirectSoundBufferImpl_GetFrequency,
847         IDirectSoundBufferImpl_GetStatus,
848         IDirectSoundBufferImpl_Initialize,
849         IDirectSoundBufferImpl_Lock,
850         IDirectSoundBufferImpl_Play,
851         IDirectSoundBufferImpl_SetCurrentPosition,
852         IDirectSoundBufferImpl_SetFormat,
853         IDirectSoundBufferImpl_SetVolume,
854         IDirectSoundBufferImpl_SetPan,
855         IDirectSoundBufferImpl_SetFrequency,
856         IDirectSoundBufferImpl_Stop,
857         IDirectSoundBufferImpl_Unlock,
858         IDirectSoundBufferImpl_Restore,
859         IDirectSoundBufferImpl_SetFX,
860         IDirectSoundBufferImpl_AcquireResources,
861         IDirectSoundBufferImpl_GetObjectInPath
862 };
863
864 HRESULT IDirectSoundBufferImpl_Create(
865         DirectSoundDevice * device,
866         IDirectSoundBufferImpl **pdsb,
867         LPCDSBUFFERDESC dsbd)
868 {
869         IDirectSoundBufferImpl *dsb;
870         LPWAVEFORMATEX wfex = dsbd->lpwfxFormat;
871         HRESULT err = DS_OK;
872         DWORD capf = 0;
873         TRACE("(%p,%p,%p)\n",device,pdsb,dsbd);
874
875         if (dsbd->dwBufferBytes < DSBSIZE_MIN || dsbd->dwBufferBytes > DSBSIZE_MAX) {
876                 WARN("invalid parameter: dsbd->dwBufferBytes = %d\n", dsbd->dwBufferBytes);
877                 *pdsb = NULL;
878                 return DSERR_INVALIDPARAM; /* FIXME: which error? */
879         }
880
881         dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
882
883         if (dsb == 0) {
884                 WARN("out of memory\n");
885                 *pdsb = NULL;
886                 return DSERR_OUTOFMEMORY;
887         }
888
889         TRACE("Created buffer at %p\n", dsb);
890
891         dsb->ref = 0;
892         dsb->ref3D = 0;
893         dsb->refiks = 0;
894         dsb->numIfaces = 0;
895         dsb->device = device;
896         dsb->IDirectSoundBuffer8_iface.lpVtbl = &dsbvt;
897         dsb->IDirectSound3DBuffer_iface.lpVtbl = &ds3dbvt;
898         dsb->IKsPropertySet_iface.lpVtbl = &iksbvt;
899
900         /* size depends on version */
901         CopyMemory(&dsb->dsbd, dsbd, dsbd->dwSize);
902
903         dsb->pwfx = DSOUND_CopyFormat(wfex);
904         if (dsb->pwfx == NULL) {
905                 HeapFree(GetProcessHeap(),0,dsb);
906                 *pdsb = NULL;
907                 return DSERR_OUTOFMEMORY;
908         }
909
910         if (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign)
911                 dsb->buflen = dsbd->dwBufferBytes + 
912                         (dsbd->lpwfxFormat->nBlockAlign - 
913                         (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign));
914         else
915                 dsb->buflen = dsbd->dwBufferBytes;
916
917         dsb->freq = dsbd->lpwfxFormat->nSamplesPerSec;
918         dsb->notify = NULL;
919         dsb->notifies = NULL;
920         dsb->nrofnotifies = 0;
921
922         /* Check necessary hardware mixing capabilities */
923         if (wfex->nChannels==2) capf |= DSCAPS_SECONDARYSTEREO;
924         else capf |= DSCAPS_SECONDARYMONO;
925         if (wfex->wBitsPerSample==16) capf |= DSCAPS_SECONDARY16BIT;
926         else capf |= DSCAPS_SECONDARY8BIT;
927
928         TRACE("capf = 0x%08x, device->drvcaps.dwFlags = 0x%08x\n", capf, device->drvcaps.dwFlags);
929
930         /* Allocate an empty buffer */
931         dsb->buffer = HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb->buffer)));
932         if (dsb->buffer == NULL) {
933                 WARN("out of memory\n");
934                 HeapFree(GetProcessHeap(),0,dsb->pwfx);
935                 HeapFree(GetProcessHeap(),0,dsb);
936                 *pdsb = NULL;
937                 return DSERR_OUTOFMEMORY;
938         }
939
940         /* Allocate system memory for buffer */
941         dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen);
942         if (dsb->buffer->memory == NULL) {
943                 WARN("out of memory\n");
944                 HeapFree(GetProcessHeap(),0,dsb->pwfx);
945                 HeapFree(GetProcessHeap(),0,dsb->buffer);
946                 HeapFree(GetProcessHeap(),0,dsb);
947                 *pdsb = NULL;
948                 return DSERR_OUTOFMEMORY;
949         }
950
951         dsb->buffer->ref = 1;
952         list_init(&dsb->buffer->buffers);
953         list_add_head(&dsb->buffer->buffers, &dsb->entry);
954         FillMemory(dsb->buffer->memory, dsb->buflen, dsbd->lpwfxFormat->wBitsPerSample == 8 ? 128 : 0);
955
956         /* It's not necessary to initialize values to zero since */
957         /* we allocated this structure with HEAP_ZERO_MEMORY... */
958         dsb->buf_mixpos = dsb->sec_mixpos = 0;
959         dsb->state = STATE_STOPPED;
960
961         dsb->freqAdjust = ((DWORD64)dsb->freq << DSOUND_FREQSHIFT) / device->pwfx->nSamplesPerSec;
962         dsb->nAvgBytesPerSec = dsb->freq *
963                 dsbd->lpwfxFormat->nBlockAlign;
964
965         /* calculate fragment size and write lead */
966         DSOUND_RecalcFormat(dsb);
967
968         if (dsb->dsbd.dwFlags & DSBCAPS_CTRL3D) {
969                 dsb->ds3db_ds3db.dwSize = sizeof(DS3DBUFFER);
970                 dsb->ds3db_ds3db.vPosition.x = 0.0;
971                 dsb->ds3db_ds3db.vPosition.y = 0.0;
972                 dsb->ds3db_ds3db.vPosition.z = 0.0;
973                 dsb->ds3db_ds3db.vVelocity.x = 0.0;
974                 dsb->ds3db_ds3db.vVelocity.y = 0.0;
975                 dsb->ds3db_ds3db.vVelocity.z = 0.0;
976                 dsb->ds3db_ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
977                 dsb->ds3db_ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
978                 dsb->ds3db_ds3db.vConeOrientation.x = 0.0;
979                 dsb->ds3db_ds3db.vConeOrientation.y = 0.0;
980                 dsb->ds3db_ds3db.vConeOrientation.z = 0.0;
981                 dsb->ds3db_ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
982                 dsb->ds3db_ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE;
983                 dsb->ds3db_ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
984                 dsb->ds3db_ds3db.dwMode = DS3DMODE_NORMAL;
985
986                 dsb->ds3db_need_recalc = FALSE;
987                 DSOUND_Calc3DBuffer(dsb);
988         } else
989                 DSOUND_RecalcVolPan(&(dsb->volpan));
990
991         RtlInitializeResource(&dsb->lock);
992
993         /* register buffer if not primary */
994         if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
995                 err = DirectSoundDevice_AddBuffer(device, dsb);
996                 if (err != DS_OK) {
997                         HeapFree(GetProcessHeap(),0,dsb->buffer->memory);
998                         HeapFree(GetProcessHeap(),0,dsb->buffer);
999                         RtlDeleteResource(&dsb->lock);
1000                         HeapFree(GetProcessHeap(),0,dsb->pwfx);
1001                         HeapFree(GetProcessHeap(),0,dsb);
1002                         dsb = NULL;
1003                 }
1004         }
1005
1006         IDirectSoundBuffer8_AddRef(&dsb->IDirectSoundBuffer8_iface);
1007         *pdsb = dsb;
1008         return err;
1009 }
1010
1011 void secondarybuffer_destroy(IDirectSoundBufferImpl *This)
1012 {
1013     DirectSoundDevice_RemoveBuffer(This->device, This);
1014     RtlDeleteResource(&This->lock);
1015
1016     This->buffer->ref--;
1017     list_remove(&This->entry);
1018     if (This->buffer->ref == 0) {
1019         HeapFree(GetProcessHeap(), 0, This->buffer->memory);
1020         HeapFree(GetProcessHeap(), 0, This->buffer);
1021     }
1022
1023     HeapFree(GetProcessHeap(), 0, This->notifies);
1024     HeapFree(GetProcessHeap(), 0, This->pwfx);
1025     HeapFree(GetProcessHeap(), 0, This);
1026
1027     TRACE("(%p) released\n", This);
1028 }
1029
1030 HRESULT IDirectSoundBufferImpl_Destroy(
1031     IDirectSoundBufferImpl *pdsb)
1032 {
1033     TRACE("(%p)\n",pdsb);
1034
1035     /* This keeps the *_Destroy functions from possibly deleting
1036      * this object until it is ready to be deleted */
1037     InterlockedIncrement(&pdsb->numIfaces);
1038
1039     if (pdsb->notify) {
1040         WARN("notify not NULL\n");
1041         IDirectSoundNotifyImpl_Destroy(pdsb->notify);
1042         pdsb->notify = NULL;
1043     }
1044
1045     secondarybuffer_destroy(pdsb);
1046
1047     return S_OK;
1048 }
1049
1050 HRESULT IDirectSoundBufferImpl_Duplicate(
1051     DirectSoundDevice *device,
1052     IDirectSoundBufferImpl **ppdsb,
1053     IDirectSoundBufferImpl *pdsb)
1054 {
1055     IDirectSoundBufferImpl *dsb;
1056     HRESULT hres = DS_OK;
1057     TRACE("(%p,%p,%p)\n", device, ppdsb, pdsb);
1058
1059     dsb = HeapAlloc(GetProcessHeap(),0,sizeof(*dsb));
1060     if (dsb == NULL) {
1061         WARN("out of memory\n");
1062         *ppdsb = NULL;
1063         return DSERR_OUTOFMEMORY;
1064     }
1065
1066     RtlAcquireResourceShared(&pdsb->lock, TRUE);
1067
1068     CopyMemory(dsb, pdsb, sizeof(*dsb));
1069
1070     dsb->pwfx = DSOUND_CopyFormat(pdsb->pwfx);
1071
1072     RtlReleaseResource(&pdsb->lock);
1073
1074     if (dsb->pwfx == NULL) {
1075         HeapFree(GetProcessHeap(),0,dsb);
1076         *ppdsb = NULL;
1077         return DSERR_OUTOFMEMORY;
1078     }
1079
1080     dsb->buffer->ref++;
1081     list_add_head(&dsb->buffer->buffers, &dsb->entry);
1082     dsb->ref = 0;
1083     dsb->ref3D = 0;
1084     dsb->refiks = 0;
1085     dsb->numIfaces = 0;
1086     dsb->state = STATE_STOPPED;
1087     dsb->buf_mixpos = dsb->sec_mixpos = 0;
1088     dsb->notify = NULL;
1089     dsb->notifies = NULL;
1090     dsb->nrofnotifies = 0;
1091     dsb->device = device;
1092     DSOUND_RecalcFormat(dsb);
1093
1094     RtlInitializeResource(&dsb->lock);
1095
1096     /* register buffer */
1097     hres = DirectSoundDevice_AddBuffer(device, dsb);
1098     if (hres != DS_OK) {
1099         RtlDeleteResource(&dsb->lock);
1100         list_remove(&dsb->entry);
1101         dsb->buffer->ref--;
1102         HeapFree(GetProcessHeap(),0,dsb->pwfx);
1103         HeapFree(GetProcessHeap(),0,dsb);
1104         dsb = NULL;
1105     }
1106
1107     IDirectSoundBuffer8_AddRef(&dsb->IDirectSoundBuffer8_iface);
1108     *ppdsb = dsb;
1109     return hres;
1110 }
1111
1112 /*******************************************************************************
1113  *              IKsPropertySet
1114  */
1115
1116 static inline IDirectSoundBufferImpl *impl_from_IKsPropertySet(IKsPropertySet *iface)
1117 {
1118     return CONTAINING_RECORD(iface, IDirectSoundBufferImpl, IKsPropertySet_iface);
1119 }
1120
1121 /* IUnknown methods */
1122 static HRESULT WINAPI IKsPropertySetImpl_QueryInterface(IKsPropertySet *iface, REFIID riid,
1123         void **ppobj)
1124 {
1125     IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1126
1127     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
1128
1129     return IDirectSoundBuffer_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppobj);
1130 }
1131
1132 static ULONG WINAPI IKsPropertySetImpl_AddRef(IKsPropertySet *iface)
1133 {
1134     IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1135     ULONG ref = InterlockedIncrement(&This->refiks);
1136
1137     TRACE("(%p) ref was %d\n", This, ref - 1);
1138
1139     if(ref == 1)
1140         InterlockedIncrement(&This->numIfaces);
1141
1142     return ref;
1143 }
1144
1145 static ULONG WINAPI IKsPropertySetImpl_Release(IKsPropertySet *iface)
1146 {
1147     IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1148     ULONG ref = InterlockedDecrement(&This->refiks);
1149
1150     TRACE("(%p) ref was %d\n", This, ref + 1);
1151
1152     if (!ref && !InterlockedDecrement(&This->numIfaces)) {
1153         if (is_primary_buffer(This))
1154             primarybuffer_destroy(This);
1155         else
1156             secondarybuffer_destroy(This);
1157     }
1158     return ref;
1159 }
1160
1161 static HRESULT WINAPI IKsPropertySetImpl_Get(IKsPropertySet *iface, REFGUID guidPropSet,
1162         ULONG dwPropID, void *pInstanceData, ULONG cbInstanceData, void *pPropData,
1163         ULONG cbPropData, ULONG *pcbReturned)
1164 {
1165     IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1166
1167     TRACE("(iface=%p,guidPropSet=%s,dwPropID=%d,pInstanceData=%p,cbInstanceData=%d,pPropData=%p,cbPropData=%d,pcbReturned=%p)\n",
1168     This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData,pcbReturned);
1169
1170     return E_PROP_ID_UNSUPPORTED;
1171 }
1172
1173 static HRESULT WINAPI IKsPropertySetImpl_Set(IKsPropertySet *iface, REFGUID guidPropSet,
1174         ULONG dwPropID, void *pInstanceData, ULONG cbInstanceData, void *pPropData,
1175         ULONG cbPropData)
1176 {
1177     IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1178
1179     TRACE("(%p,%s,%d,%p,%d,%p,%d)\n",This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData);
1180
1181     return E_PROP_ID_UNSUPPORTED;
1182 }
1183
1184 static HRESULT WINAPI IKsPropertySetImpl_QuerySupport(IKsPropertySet *iface, REFGUID guidPropSet,
1185         ULONG dwPropID, ULONG *pTypeSupport)
1186 {
1187     IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1188
1189     TRACE("(%p,%s,%d,%p)\n",This,debugstr_guid(guidPropSet),dwPropID,pTypeSupport);
1190
1191     return E_PROP_ID_UNSUPPORTED;
1192 }
1193
1194 const IKsPropertySetVtbl iksbvt = {
1195     IKsPropertySetImpl_QueryInterface,
1196     IKsPropertySetImpl_AddRef,
1197     IKsPropertySetImpl_Release,
1198     IKsPropertySetImpl_Get,
1199     IKsPropertySetImpl_Set,
1200     IKsPropertySetImpl_QuerySupport
1201 };