dsound/tests: Add some COM tests for capture.
[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                 if (!This->ds3db)
816                         IDirectSound3DBufferImpl_Create(This, &(This->ds3db));
817                 if (This->ds3db) {
818                         IDirectSound3DBuffer_AddRef((LPDIRECTSOUND3DBUFFER)This->ds3db);
819                         *ppobj = This->ds3db;
820                         return S_OK;
821                 }
822                 WARN("IID_IDirectSound3DBuffer\n");
823                 return E_NOINTERFACE;
824         }
825
826         if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
827                 ERR("app requested IDirectSound3DListener on secondary buffer\n");
828                 return E_NOINTERFACE;
829         }
830
831         if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) {
832                 if (!This->iks)
833                         IKsBufferPropertySetImpl_Create(This, &(This->iks));
834                 if (This->iks) {
835                         IKsPropertySet_AddRef((LPKSPROPERTYSET)This->iks);
836                         *ppobj = This->iks;
837                         return S_OK;
838                 }
839                 WARN("IID_IKsPropertySet\n");
840                 return E_NOINTERFACE;
841         }
842
843         FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
844
845         return E_NOINTERFACE;
846 }
847
848 static const IDirectSoundBuffer8Vtbl dsbvt =
849 {
850         IDirectSoundBufferImpl_QueryInterface,
851         IDirectSoundBufferImpl_AddRef,
852         IDirectSoundBufferImpl_Release,
853         IDirectSoundBufferImpl_GetCaps,
854         IDirectSoundBufferImpl_GetCurrentPosition,
855         IDirectSoundBufferImpl_GetFormat,
856         IDirectSoundBufferImpl_GetVolume,
857         IDirectSoundBufferImpl_GetPan,
858         IDirectSoundBufferImpl_GetFrequency,
859         IDirectSoundBufferImpl_GetStatus,
860         IDirectSoundBufferImpl_Initialize,
861         IDirectSoundBufferImpl_Lock,
862         IDirectSoundBufferImpl_Play,
863         IDirectSoundBufferImpl_SetCurrentPosition,
864         IDirectSoundBufferImpl_SetFormat,
865         IDirectSoundBufferImpl_SetVolume,
866         IDirectSoundBufferImpl_SetPan,
867         IDirectSoundBufferImpl_SetFrequency,
868         IDirectSoundBufferImpl_Stop,
869         IDirectSoundBufferImpl_Unlock,
870         IDirectSoundBufferImpl_Restore,
871         IDirectSoundBufferImpl_SetFX,
872         IDirectSoundBufferImpl_AcquireResources,
873         IDirectSoundBufferImpl_GetObjectInPath
874 };
875
876 HRESULT IDirectSoundBufferImpl_Create(
877         DirectSoundDevice * device,
878         IDirectSoundBufferImpl **pdsb,
879         LPCDSBUFFERDESC dsbd)
880 {
881         IDirectSoundBufferImpl *dsb;
882         LPWAVEFORMATEX wfex = dsbd->lpwfxFormat;
883         HRESULT err = DS_OK;
884         DWORD capf = 0;
885         TRACE("(%p,%p,%p)\n",device,pdsb,dsbd);
886
887         if (dsbd->dwBufferBytes < DSBSIZE_MIN || dsbd->dwBufferBytes > DSBSIZE_MAX) {
888                 WARN("invalid parameter: dsbd->dwBufferBytes = %d\n", dsbd->dwBufferBytes);
889                 *pdsb = NULL;
890                 return DSERR_INVALIDPARAM; /* FIXME: which error? */
891         }
892
893         dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
894
895         if (dsb == 0) {
896                 WARN("out of memory\n");
897                 *pdsb = NULL;
898                 return DSERR_OUTOFMEMORY;
899         }
900
901         TRACE("Created buffer at %p\n", dsb);
902
903         dsb->ref = 1;
904         dsb->numIfaces = 1;
905         dsb->device = device;
906         dsb->IDirectSoundBuffer8_iface.lpVtbl = &dsbvt;
907         dsb->iks = NULL;
908
909         /* size depends on version */
910         CopyMemory(&dsb->dsbd, dsbd, dsbd->dwSize);
911
912         dsb->pwfx = DSOUND_CopyFormat(wfex);
913         if (dsb->pwfx == NULL) {
914                 HeapFree(GetProcessHeap(),0,dsb);
915                 *pdsb = NULL;
916                 return DSERR_OUTOFMEMORY;
917         }
918
919         if (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign)
920                 dsb->buflen = dsbd->dwBufferBytes + 
921                         (dsbd->lpwfxFormat->nBlockAlign - 
922                         (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign));
923         else
924                 dsb->buflen = dsbd->dwBufferBytes;
925
926         dsb->freq = dsbd->lpwfxFormat->nSamplesPerSec;
927         dsb->notify = NULL;
928         dsb->notifies = NULL;
929         dsb->nrofnotifies = 0;
930
931         /* Check necessary hardware mixing capabilities */
932         if (wfex->nChannels==2) capf |= DSCAPS_SECONDARYSTEREO;
933         else capf |= DSCAPS_SECONDARYMONO;
934         if (wfex->wBitsPerSample==16) capf |= DSCAPS_SECONDARY16BIT;
935         else capf |= DSCAPS_SECONDARY8BIT;
936
937         TRACE("capf = 0x%08x, device->drvcaps.dwFlags = 0x%08x\n", capf, device->drvcaps.dwFlags);
938
939         /* Allocate an empty buffer */
940         dsb->buffer = HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb->buffer)));
941         if (dsb->buffer == NULL) {
942                 WARN("out of memory\n");
943                 HeapFree(GetProcessHeap(),0,dsb->pwfx);
944                 HeapFree(GetProcessHeap(),0,dsb);
945                 *pdsb = NULL;
946                 return DSERR_OUTOFMEMORY;
947         }
948
949         /* Allocate system memory for buffer */
950         dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen);
951         if (dsb->buffer->memory == NULL) {
952                 WARN("out of memory\n");
953                 HeapFree(GetProcessHeap(),0,dsb->pwfx);
954                 HeapFree(GetProcessHeap(),0,dsb->buffer);
955                 HeapFree(GetProcessHeap(),0,dsb);
956                 *pdsb = NULL;
957                 return DSERR_OUTOFMEMORY;
958         }
959
960         dsb->buffer->ref = 1;
961         list_init(&dsb->buffer->buffers);
962         list_add_head(&dsb->buffer->buffers, &dsb->entry);
963         FillMemory(dsb->buffer->memory, dsb->buflen, dsbd->lpwfxFormat->wBitsPerSample == 8 ? 128 : 0);
964
965         /* It's not necessary to initialize values to zero since */
966         /* we allocated this structure with HEAP_ZERO_MEMORY... */
967         dsb->buf_mixpos = dsb->sec_mixpos = 0;
968         dsb->state = STATE_STOPPED;
969
970         dsb->freqAdjust = ((DWORD64)dsb->freq << DSOUND_FREQSHIFT) / device->pwfx->nSamplesPerSec;
971         dsb->nAvgBytesPerSec = dsb->freq *
972                 dsbd->lpwfxFormat->nBlockAlign;
973
974         /* calculate fragment size and write lead */
975         DSOUND_RecalcFormat(dsb);
976
977         if (dsb->dsbd.dwFlags & DSBCAPS_CTRL3D) {
978                 dsb->ds3db_ds3db.dwSize = sizeof(DS3DBUFFER);
979                 dsb->ds3db_ds3db.vPosition.x = 0.0;
980                 dsb->ds3db_ds3db.vPosition.y = 0.0;
981                 dsb->ds3db_ds3db.vPosition.z = 0.0;
982                 dsb->ds3db_ds3db.vVelocity.x = 0.0;
983                 dsb->ds3db_ds3db.vVelocity.y = 0.0;
984                 dsb->ds3db_ds3db.vVelocity.z = 0.0;
985                 dsb->ds3db_ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
986                 dsb->ds3db_ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
987                 dsb->ds3db_ds3db.vConeOrientation.x = 0.0;
988                 dsb->ds3db_ds3db.vConeOrientation.y = 0.0;
989                 dsb->ds3db_ds3db.vConeOrientation.z = 0.0;
990                 dsb->ds3db_ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
991                 dsb->ds3db_ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE;
992                 dsb->ds3db_ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
993                 dsb->ds3db_ds3db.dwMode = DS3DMODE_NORMAL;
994
995                 dsb->ds3db_need_recalc = FALSE;
996                 DSOUND_Calc3DBuffer(dsb);
997         } else
998                 DSOUND_RecalcVolPan(&(dsb->volpan));
999
1000         RtlInitializeResource(&dsb->lock);
1001
1002         /* register buffer if not primary */
1003         if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
1004                 err = DirectSoundDevice_AddBuffer(device, dsb);
1005                 if (err != DS_OK) {
1006                         HeapFree(GetProcessHeap(),0,dsb->buffer->memory);
1007                         HeapFree(GetProcessHeap(),0,dsb->buffer);
1008                         RtlDeleteResource(&dsb->lock);
1009                         HeapFree(GetProcessHeap(),0,dsb->pwfx);
1010                         HeapFree(GetProcessHeap(),0,dsb);
1011                         dsb = NULL;
1012                 }
1013         }
1014
1015         *pdsb = dsb;
1016         return err;
1017 }
1018
1019 void secondarybuffer_destroy(IDirectSoundBufferImpl *This)
1020 {
1021     DirectSoundDevice_RemoveBuffer(This->device, This);
1022     RtlDeleteResource(&This->lock);
1023
1024     This->buffer->ref--;
1025     list_remove(&This->entry);
1026     if (This->buffer->ref == 0) {
1027         HeapFree(GetProcessHeap(), 0, This->buffer->memory);
1028         HeapFree(GetProcessHeap(), 0, This->buffer);
1029     }
1030
1031     HeapFree(GetProcessHeap(), 0, This->notifies);
1032     HeapFree(GetProcessHeap(), 0, This->pwfx);
1033     HeapFree(GetProcessHeap(), 0, This);
1034
1035     TRACE("(%p) released\n", This);
1036 }
1037
1038 HRESULT IDirectSoundBufferImpl_Destroy(
1039     IDirectSoundBufferImpl *pdsb)
1040 {
1041     TRACE("(%p)\n",pdsb);
1042
1043     /* This keeps the *_Destroy functions from possibly deleting
1044      * this object until it is ready to be deleted */
1045     InterlockedIncrement(&pdsb->numIfaces);
1046
1047     if (pdsb->iks) {
1048         WARN("iks not NULL\n");
1049         IKsBufferPropertySetImpl_Destroy(pdsb->iks);
1050         pdsb->iks = NULL;
1051     }
1052
1053     if (pdsb->ds3db) {
1054         WARN("ds3db not NULL\n");
1055         IDirectSound3DBufferImpl_Destroy(pdsb->ds3db);
1056         pdsb->ds3db = NULL;
1057     }
1058
1059     if (pdsb->notify) {
1060         WARN("notify not NULL\n");
1061         IDirectSoundNotifyImpl_Destroy(pdsb->notify);
1062         pdsb->notify = NULL;
1063     }
1064
1065     secondarybuffer_destroy(pdsb);
1066
1067     return S_OK;
1068 }
1069
1070 HRESULT IDirectSoundBufferImpl_Duplicate(
1071     DirectSoundDevice *device,
1072     IDirectSoundBufferImpl **ppdsb,
1073     IDirectSoundBufferImpl *pdsb)
1074 {
1075     IDirectSoundBufferImpl *dsb;
1076     HRESULT hres = DS_OK;
1077     TRACE("(%p,%p,%p)\n", device, ppdsb, pdsb);
1078
1079     dsb = HeapAlloc(GetProcessHeap(),0,sizeof(*dsb));
1080     if (dsb == NULL) {
1081         WARN("out of memory\n");
1082         *ppdsb = NULL;
1083         return DSERR_OUTOFMEMORY;
1084     }
1085     CopyMemory(dsb, pdsb, sizeof(*dsb));
1086
1087     dsb->pwfx = DSOUND_CopyFormat(pdsb->pwfx);
1088     if (dsb->pwfx == NULL) {
1089         HeapFree(GetProcessHeap(),0,dsb);
1090         *ppdsb = NULL;
1091         return DSERR_OUTOFMEMORY;
1092     }
1093
1094     dsb->buffer->ref++;
1095     list_add_head(&dsb->buffer->buffers, &dsb->entry);
1096     dsb->ref = 1;
1097     dsb->numIfaces = 1;
1098     dsb->state = STATE_STOPPED;
1099     dsb->buf_mixpos = dsb->sec_mixpos = 0;
1100     dsb->notify = NULL;
1101     dsb->notifies = NULL;
1102     dsb->nrofnotifies = 0;
1103     dsb->device = device;
1104     dsb->ds3db = NULL;
1105     dsb->iks = NULL; /* FIXME? */
1106     DSOUND_RecalcFormat(dsb);
1107
1108     RtlInitializeResource(&dsb->lock);
1109
1110     /* register buffer */
1111     hres = DirectSoundDevice_AddBuffer(device, dsb);
1112     if (hres != DS_OK) {
1113         RtlDeleteResource(&dsb->lock);
1114         list_remove(&dsb->entry);
1115         dsb->buffer->ref--;
1116         HeapFree(GetProcessHeap(),0,dsb->pwfx);
1117         HeapFree(GetProcessHeap(),0,dsb);
1118         dsb = NULL;
1119     }
1120
1121     *ppdsb = dsb;
1122     return hres;
1123 }
1124
1125 /*******************************************************************************
1126  *              IKsBufferPropertySet
1127  */
1128
1129 /* IUnknown methods */
1130 static HRESULT WINAPI IKsBufferPropertySetImpl_QueryInterface(
1131     LPKSPROPERTYSET iface,
1132     REFIID riid,
1133     LPVOID *ppobj )
1134 {
1135     IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
1136     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
1137
1138     return IDirectSoundBuffer_QueryInterface((LPDIRECTSOUNDBUFFER8)This->dsb, riid, ppobj);
1139 }
1140
1141 static ULONG WINAPI IKsBufferPropertySetImpl_AddRef(LPKSPROPERTYSET iface)
1142 {
1143     IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
1144     ULONG ref = InterlockedIncrement(&(This->ref));
1145     TRACE("(%p) ref was %d\n", This, ref - 1);
1146     return ref;
1147 }
1148
1149 static ULONG WINAPI IKsBufferPropertySetImpl_Release(LPKSPROPERTYSET iface)
1150 {
1151     IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
1152     ULONG ref = InterlockedDecrement(&(This->ref));
1153     TRACE("(%p) ref was %d\n", This, ref + 1);
1154
1155     if (!ref) {
1156     This->dsb->iks = 0;
1157     IDirectSoundBuffer_Release((LPDIRECTSOUND3DBUFFER)This->dsb);
1158     HeapFree(GetProcessHeap(), 0, This);
1159     TRACE("(%p) released\n", This);
1160     }
1161     return ref;
1162 }
1163
1164 static HRESULT WINAPI IKsBufferPropertySetImpl_Get(
1165     LPKSPROPERTYSET iface,
1166     REFGUID guidPropSet,
1167     ULONG dwPropID,
1168     LPVOID pInstanceData,
1169     ULONG cbInstanceData,
1170     LPVOID pPropData,
1171     ULONG cbPropData,
1172     PULONG pcbReturned )
1173 {
1174     IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
1175
1176     TRACE("(iface=%p,guidPropSet=%s,dwPropID=%d,pInstanceData=%p,cbInstanceData=%d,pPropData=%p,cbPropData=%d,pcbReturned=%p)\n",
1177     This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData,pcbReturned);
1178
1179     return E_PROP_ID_UNSUPPORTED;
1180 }
1181
1182 static HRESULT WINAPI IKsBufferPropertySetImpl_Set(
1183     LPKSPROPERTYSET iface,
1184     REFGUID guidPropSet,
1185     ULONG dwPropID,
1186     LPVOID pInstanceData,
1187     ULONG cbInstanceData,
1188     LPVOID pPropData,
1189     ULONG cbPropData )
1190 {
1191     IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
1192
1193     TRACE("(%p,%s,%d,%p,%d,%p,%d)\n",This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData);
1194
1195     return E_PROP_ID_UNSUPPORTED;
1196 }
1197
1198 static HRESULT WINAPI IKsBufferPropertySetImpl_QuerySupport(
1199     LPKSPROPERTYSET iface,
1200     REFGUID guidPropSet,
1201     ULONG dwPropID,
1202     PULONG pTypeSupport )
1203 {
1204     IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
1205
1206     TRACE("(%p,%s,%d,%p)\n",This,debugstr_guid(guidPropSet),dwPropID,pTypeSupport);
1207
1208     return E_PROP_ID_UNSUPPORTED;
1209 }
1210
1211 static const IKsPropertySetVtbl iksbvt = {
1212     IKsBufferPropertySetImpl_QueryInterface,
1213     IKsBufferPropertySetImpl_AddRef,
1214     IKsBufferPropertySetImpl_Release,
1215     IKsBufferPropertySetImpl_Get,
1216     IKsBufferPropertySetImpl_Set,
1217     IKsBufferPropertySetImpl_QuerySupport
1218 };
1219
1220 HRESULT IKsBufferPropertySetImpl_Create(
1221     IDirectSoundBufferImpl *dsb,
1222     IKsBufferPropertySetImpl **piks)
1223 {
1224     IKsBufferPropertySetImpl *iks;
1225     TRACE("(%p,%p)\n",dsb,piks);
1226     *piks = NULL;
1227
1228     iks = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*iks));
1229     if (iks == 0) {
1230         WARN("out of memory\n");
1231         *piks = NULL;
1232         return DSERR_OUTOFMEMORY;
1233     }
1234
1235     iks->ref = 0;
1236     iks->dsb = dsb;
1237     dsb->iks = iks;
1238     iks->lpVtbl = &iksbvt;
1239
1240     IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)dsb);
1241
1242     *piks = iks;
1243     return S_OK;
1244 }
1245
1246 HRESULT IKsBufferPropertySetImpl_Destroy(
1247     IKsBufferPropertySetImpl *piks)
1248 {
1249     TRACE("(%p)\n",piks);
1250
1251     while (IKsBufferPropertySetImpl_Release((LPKSPROPERTYSET)piks) > 0);
1252
1253     return S_OK;
1254 }