gdi32/tests: Add some tests for the behavior of a printer DC.
[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                 DSOUND_MixToTemporary(This, 0, This->buflen, FALSE);
300         }
301
302         RtlReleaseResource(&This->lock);
303         /* **** */
304
305         return DS_OK;
306 }
307
308 static HRESULT WINAPI IDirectSoundBufferImpl_Play(IDirectSoundBuffer8 *iface, DWORD reserved1,
309         DWORD reserved2, DWORD flags)
310 {
311         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
312         HRESULT hres = DS_OK;
313
314         TRACE("(%p,%08x,%08x,%08x)\n",This,reserved1,reserved2,flags);
315
316         /* **** */
317         RtlAcquireResourceExclusive(&This->lock, TRUE);
318
319         This->playflags = flags;
320         if (This->state == STATE_STOPPED) {
321                 This->leadin = TRUE;
322                 This->state = STATE_STARTING;
323         } else if (This->state == STATE_STOPPING)
324                 This->state = STATE_PLAYING;
325
326         RtlReleaseResource(&This->lock);
327         /* **** */
328
329         return hres;
330 }
331
332 static HRESULT WINAPI IDirectSoundBufferImpl_Stop(IDirectSoundBuffer8 *iface)
333 {
334         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
335         HRESULT hres = DS_OK;
336
337         TRACE("(%p)\n",This);
338
339         /* **** */
340         RtlAcquireResourceExclusive(&This->lock, TRUE);
341
342         if (This->state == STATE_PLAYING)
343                 This->state = STATE_STOPPING;
344         else if (This->state == STATE_STARTING)
345         {
346                 This->state = STATE_STOPPED;
347                 DSOUND_CheckEvent(This, 0, 0);
348         }
349
350         RtlReleaseResource(&This->lock);
351         /* **** */
352
353         return hres;
354 }
355
356 static ULONG WINAPI IDirectSoundBufferImpl_AddRef(IDirectSoundBuffer8 *iface)
357 {
358     IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
359     ULONG ref = InterlockedIncrement(&This->ref);
360
361     TRACE("(%p) ref was %d\n", This, ref - 1);
362
363     if(ref == 1)
364         InterlockedIncrement(&This->numIfaces);
365
366     return ref;
367 }
368
369 static ULONG WINAPI IDirectSoundBufferImpl_Release(IDirectSoundBuffer8 *iface)
370 {
371     IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
372     ULONG ref = InterlockedDecrement(&This->ref);
373
374     TRACE("(%p) ref was %d\n", This, ref + 1);
375
376     if (!ref && !InterlockedDecrement(&This->numIfaces)) {
377         if (is_primary_buffer(This))
378             primarybuffer_destroy(This);
379         else
380             secondarybuffer_destroy(This);
381     }
382     return ref;
383 }
384
385 static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(IDirectSoundBuffer8 *iface,
386         DWORD *playpos, DWORD *writepos)
387 {
388         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
389         DWORD pos;
390
391         TRACE("(%p,%p,%p)\n",This,playpos,writepos);
392
393         RtlAcquireResourceShared(&This->lock, TRUE);
394
395         pos = This->sec_mixpos;
396
397         /* sanity */
398         if (pos >= This->buflen){
399                 FIXME("Bad play position. playpos: %d, buflen: %d\n", pos, This->buflen);
400                 pos %= This->buflen;
401         }
402
403         if (playpos)
404                 *playpos = pos;
405         if (writepos)
406                 *writepos = pos;
407
408         if (writepos && This->state != STATE_STOPPED) {
409                 /* apply the documented 10ms lead to writepos */
410                 *writepos += This->writelead;
411                 *writepos %= This->buflen;
412         }
413
414         RtlReleaseResource(&This->lock);
415
416         TRACE("playpos = %d, writepos = %d, buflen=%d (%p, time=%d)\n",
417                 playpos?*playpos:-1, writepos?*writepos:-1, This->buflen, This, GetTickCount());
418
419         return DS_OK;
420 }
421
422 static HRESULT WINAPI IDirectSoundBufferImpl_GetStatus(IDirectSoundBuffer8 *iface, DWORD *status)
423 {
424         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
425
426         TRACE("(%p,%p), thread is %04x\n",This,status,GetCurrentThreadId());
427
428         if (status == NULL) {
429                 WARN("invalid parameter: status = NULL\n");
430                 return DSERR_INVALIDPARAM;
431         }
432
433         *status = 0;
434         RtlAcquireResourceShared(&This->lock, TRUE);
435         if ((This->state == STATE_STARTING) || (This->state == STATE_PLAYING)) {
436                 *status |= DSBSTATUS_PLAYING;
437                 if (This->playflags & DSBPLAY_LOOPING)
438                         *status |= DSBSTATUS_LOOPING;
439         }
440         RtlReleaseResource(&This->lock);
441
442         TRACE("status=%x\n", *status);
443         return DS_OK;
444 }
445
446
447 static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat(IDirectSoundBuffer8 *iface,
448         LPWAVEFORMATEX lpwf, DWORD wfsize, DWORD *wfwritten)
449 {
450     IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
451     DWORD size;
452
453     TRACE("(%p,%p,%d,%p)\n",This,lpwf,wfsize,wfwritten);
454
455     size = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;
456
457     if (lpwf) { /* NULL is valid */
458         if (wfsize >= size) {
459             CopyMemory(lpwf,This->pwfx,size);
460             if (wfwritten)
461                 *wfwritten = size;
462         } else {
463             WARN("invalid parameter: wfsize too small\n");
464             CopyMemory(lpwf,This->pwfx,wfsize);
465             if (wfwritten)
466                 *wfwritten = wfsize;
467             return DSERR_INVALIDPARAM;
468         }
469     } else {
470         if (wfwritten)
471             *wfwritten = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;
472         else {
473             WARN("invalid parameter: wfwritten == NULL\n");
474             return DSERR_INVALIDPARAM;
475         }
476     }
477
478     return DS_OK;
479 }
480
481 static HRESULT WINAPI IDirectSoundBufferImpl_Lock(IDirectSoundBuffer8 *iface, DWORD writecursor,
482         DWORD writebytes, void **lplpaudioptr1, DWORD *audiobytes1, void **lplpaudioptr2,
483         DWORD *audiobytes2, DWORD flags)
484 {
485         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
486         HRESULT hres = DS_OK;
487
488         TRACE("(%p,%d,%d,%p,%p,%p,%p,0x%08x) at %d\n", This, writecursor, writebytes, lplpaudioptr1,
489                 audiobytes1, lplpaudioptr2, audiobytes2, flags, GetTickCount());
490
491         if (!audiobytes1)
492             return DSERR_INVALIDPARAM;
493
494         /* when this flag is set, writecursor is meaningless and must be calculated */
495         if (flags & DSBLOCK_FROMWRITECURSOR) {
496                 /* GetCurrentPosition does too much magic to duplicate here */
497                 hres = IDirectSoundBufferImpl_GetCurrentPosition(iface, NULL, &writecursor);
498                 if (hres != DS_OK) {
499                         WARN("IDirectSoundBufferImpl_GetCurrentPosition failed\n");
500                         return hres;
501                 }
502         }
503
504         /* when this flag is set, writebytes is meaningless and must be set */
505         if (flags & DSBLOCK_ENTIREBUFFER)
506                 writebytes = This->buflen;
507
508         if (writecursor >= This->buflen) {
509                 WARN("Invalid parameter, writecursor: %u >= buflen: %u\n",
510                      writecursor, This->buflen);
511                 return DSERR_INVALIDPARAM;
512         }
513
514         if (writebytes > This->buflen) {
515                 WARN("Invalid parameter, writebytes: %u > buflen: %u\n",
516                      writebytes, This->buflen);
517                 return DSERR_INVALIDPARAM;
518         }
519
520         /* **** */
521         RtlAcquireResourceShared(&This->lock, TRUE);
522
523         if (writecursor+writebytes <= This->buflen) {
524                 *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
525                 if (This->sec_mixpos >= writecursor && This->sec_mixpos < writecursor + writebytes && This->state == STATE_PLAYING)
526                         WARN("Overwriting mixing position, case 1\n");
527                 *audiobytes1 = writebytes;
528                 if (lplpaudioptr2)
529                         *(LPBYTE*)lplpaudioptr2 = NULL;
530                 if (audiobytes2)
531                         *audiobytes2 = 0;
532                 TRACE("Locked %p(%i bytes) and %p(%i bytes) writecursor=%d\n",
533                   *(LPBYTE*)lplpaudioptr1, *audiobytes1, lplpaudioptr2 ? *(LPBYTE*)lplpaudioptr2 : NULL, audiobytes2 ? *audiobytes2: 0, writecursor);
534                 TRACE("->%d.0\n",writebytes);
535         } else {
536                 DWORD remainder = writebytes + writecursor - This->buflen;
537                 *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
538                 *audiobytes1 = This->buflen-writecursor;
539                 if (This->sec_mixpos >= writecursor && This->sec_mixpos < writecursor + writebytes && This->state == STATE_PLAYING)
540                         WARN("Overwriting mixing position, case 2\n");
541                 if (lplpaudioptr2)
542                         *(LPBYTE*)lplpaudioptr2 = This->buffer->memory;
543                 if (audiobytes2)
544                         *audiobytes2 = writebytes-(This->buflen-writecursor);
545                 if (audiobytes2 && This->sec_mixpos < remainder && This->state == STATE_PLAYING)
546                         WARN("Overwriting mixing position, case 3\n");
547                 TRACE("Locked %p(%i bytes) and %p(%i bytes) writecursor=%d\n", *(LPBYTE*)lplpaudioptr1, *audiobytes1, lplpaudioptr2 ? *(LPBYTE*)lplpaudioptr2 : NULL, audiobytes2 ? *audiobytes2: 0, writecursor);
548         }
549
550         RtlReleaseResource(&This->lock);
551         /* **** */
552
553         return DS_OK;
554 }
555
556 static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(IDirectSoundBuffer8 *iface,
557         DWORD newpos)
558 {
559         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
560         HRESULT hres = DS_OK;
561         DWORD oldpos;
562
563         TRACE("(%p,%d)\n",This,newpos);
564
565         /* **** */
566         RtlAcquireResourceExclusive(&This->lock, TRUE);
567
568         oldpos = This->sec_mixpos;
569
570         /* start mixing from this new location instead */
571         newpos %= This->buflen;
572         newpos -= newpos%This->pwfx->nBlockAlign;
573         This->sec_mixpos = newpos;
574
575         /* at this point, do not attempt to reset buffers, mess with primary mix position,
576            or anything like that to reduce latency. The data already prebuffered cannot be changed */
577
578         /* position HW buffer if applicable, else just start mixing from new location instead */
579         if (oldpos != newpos)
580                 /* FIXME: Perhaps add a call to DSOUND_MixToTemporary here? Not sure it's needed */
581                 This->buf_mixpos = DSOUND_secpos_to_bufpos(This, newpos, 0, NULL);
582
583         RtlReleaseResource(&This->lock);
584         /* **** */
585
586         return hres;
587 }
588
589 static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(IDirectSoundBuffer8 *iface, LONG pan)
590 {
591         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
592         HRESULT hres = DS_OK;
593
594         TRACE("(%p,%d)\n",This,pan);
595
596         if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT)) {
597                 WARN("invalid parameter: pan = %d\n", pan);
598                 return DSERR_INVALIDPARAM;
599         }
600
601         /* You cannot use both pan and 3D controls */
602         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
603             (This->dsbd.dwFlags & DSBCAPS_CTRL3D)) {
604                 WARN("control unavailable\n");
605                 return DSERR_CONTROLUNAVAIL;
606         }
607
608         /* **** */
609         RtlAcquireResourceExclusive(&This->lock, TRUE);
610
611         if (This->volpan.lPan != pan) {
612                 This->volpan.lPan = pan;
613                 DSOUND_RecalcVolPan(&(This->volpan));
614         }
615
616         RtlReleaseResource(&This->lock);
617         /* **** */
618
619         return hres;
620 }
621
622 static HRESULT WINAPI IDirectSoundBufferImpl_GetPan(IDirectSoundBuffer8 *iface, LONG *pan)
623 {
624         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
625
626         TRACE("(%p,%p)\n",This,pan);
627
628         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN)) {
629                 WARN("control unavailable\n");
630                 return DSERR_CONTROLUNAVAIL;
631         }
632
633         if (pan == NULL) {
634                 WARN("invalid parameter: pan = NULL\n");
635                 return DSERR_INVALIDPARAM;
636         }
637
638         *pan = This->volpan.lPan;
639
640         return DS_OK;
641 }
642
643 static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(IDirectSoundBuffer8 *iface, void *p1, DWORD x1,
644         void *p2, DWORD x2)
645 {
646         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface), *iter;
647         HRESULT hres = DS_OK;
648
649         TRACE("(%p,%p,%d,%p,%d)\n", This,p1,x1,p2,x2);
650
651         if (!p2)
652                 x2 = 0;
653
654     if((p1 && ((BYTE*)p1 < This->buffer->memory ||
655                     (BYTE*)p1 >= This->buffer->memory + This->buflen)) ||
656             (p2 && ((BYTE*)p2 < This->buffer->memory ||
657                     (BYTE*)p2 >= This->buffer->memory + This->buflen)))
658         return DSERR_INVALIDPARAM;
659
660         if (x1 || x2)
661         {
662                 RtlAcquireResourceShared(&This->device->buffer_list_lock, TRUE);
663                 LIST_FOR_EACH_ENTRY(iter, &This->buffer->buffers, IDirectSoundBufferImpl, entry )
664                 {
665                         RtlAcquireResourceShared(&iter->lock, TRUE);
666                         if (x1)
667                         {
668                             if(x1 + (DWORD_PTR)p1 - (DWORD_PTR)iter->buffer->memory > iter->buflen)
669                               hres = DSERR_INVALIDPARAM;
670                             else
671                               DSOUND_MixToTemporary(iter, (DWORD_PTR)p1 - (DWORD_PTR)iter->buffer->memory, x1, FALSE);
672                         }
673                         if (x2)
674                                 DSOUND_MixToTemporary(iter, 0, x2, FALSE);
675                         RtlReleaseResource(&iter->lock);
676                 }
677                 RtlReleaseResource(&This->device->buffer_list_lock);
678         }
679
680         return hres;
681 }
682
683 static HRESULT WINAPI IDirectSoundBufferImpl_Restore(IDirectSoundBuffer8 *iface)
684 {
685         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
686
687         FIXME("(%p):stub\n",This);
688         return DS_OK;
689 }
690
691 static HRESULT WINAPI IDirectSoundBufferImpl_GetFrequency(IDirectSoundBuffer8 *iface, DWORD *freq)
692 {
693         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
694
695         TRACE("(%p,%p)\n",This,freq);
696
697         if (freq == NULL) {
698                 WARN("invalid parameter: freq = NULL\n");
699                 return DSERR_INVALIDPARAM;
700         }
701
702         *freq = This->freq;
703         TRACE("-> %d\n", *freq);
704
705         return DS_OK;
706 }
707
708 static HRESULT WINAPI IDirectSoundBufferImpl_SetFX(IDirectSoundBuffer8 *iface, DWORD dwEffectsCount,
709         LPDSEFFECTDESC pDSFXDesc, DWORD *pdwResultCodes)
710 {
711         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
712         DWORD u;
713
714         FIXME("(%p,%u,%p,%p): stub\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
715
716         if (pdwResultCodes)
717                 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
718
719         WARN("control unavailable\n");
720         return DSERR_CONTROLUNAVAIL;
721 }
722
723 static HRESULT WINAPI IDirectSoundBufferImpl_AcquireResources(IDirectSoundBuffer8 *iface,
724         DWORD dwFlags, DWORD dwEffectsCount, DWORD *pdwResultCodes)
725 {
726         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
727         DWORD u;
728
729         FIXME("(%p,%08u,%u,%p): stub, faking success\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
730
731         if (pdwResultCodes)
732                 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
733
734         WARN("control unavailable\n");
735         return DS_OK;
736 }
737
738 static HRESULT WINAPI IDirectSoundBufferImpl_GetObjectInPath(IDirectSoundBuffer8 *iface,
739         REFGUID rguidObject, DWORD dwIndex, REFGUID rguidInterface, void **ppObject)
740 {
741         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
742
743         FIXME("(%p,%s,%u,%s,%p): stub\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
744
745         WARN("control unavailable\n");
746         return DSERR_CONTROLUNAVAIL;
747 }
748
749 static HRESULT WINAPI IDirectSoundBufferImpl_Initialize(IDirectSoundBuffer8 *iface,
750         IDirectSound *dsound, LPCDSBUFFERDESC dbsd)
751 {
752         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
753
754         WARN("(%p) already initialized\n", This);
755         return DSERR_ALREADYINITIALIZED;
756 }
757
758 static HRESULT WINAPI IDirectSoundBufferImpl_GetCaps(IDirectSoundBuffer8 *iface, LPDSBCAPS caps)
759 {
760         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
761
762         TRACE("(%p)->(%p)\n",This,caps);
763
764         if (caps == NULL) {
765                 WARN("invalid parameter: caps == NULL\n");
766                 return DSERR_INVALIDPARAM;
767         }
768
769         if (caps->dwSize < sizeof(*caps)) {
770                 WARN("invalid parameter: caps->dwSize = %d\n",caps->dwSize);
771                 return DSERR_INVALIDPARAM;
772         }
773
774         caps->dwFlags = This->dsbd.dwFlags;
775         caps->dwFlags |= DSBCAPS_LOCSOFTWARE;
776
777         caps->dwBufferBytes = This->buflen;
778
779         /* According to windows, this is zero*/
780         caps->dwUnlockTransferRate = 0;
781         caps->dwPlayCpuOverhead = 0;
782
783         return DS_OK;
784 }
785
786 static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface(IDirectSoundBuffer8 *iface, REFIID riid,
787         void **ppobj)
788 {
789         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
790
791         TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
792
793         if (ppobj == NULL) {
794                 WARN("invalid parameter\n");
795                 return E_INVALIDARG;
796         }
797
798         *ppobj = NULL;  /* assume failure */
799
800         if ( IsEqualGUID(riid, &IID_IUnknown) ||
801              IsEqualGUID(riid, &IID_IDirectSoundBuffer) ||
802              IsEqualGUID(riid, &IID_IDirectSoundBuffer8) ) {
803                 IDirectSoundBuffer8_AddRef(iface);
804                 *ppobj = iface;
805                 return S_OK;
806         }
807
808         if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
809                 if (!This->notify)
810                         IDirectSoundNotifyImpl_Create(This, &(This->notify));
811                 if (This->notify) {
812                         IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify);
813                         *ppobj = This->notify;
814                         return S_OK;
815                 }
816                 WARN("IID_IDirectSoundNotify\n");
817                 return E_NOINTERFACE;
818         }
819
820         if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) {
821                 if (!This->ds3db)
822                         IDirectSound3DBufferImpl_Create(This, &(This->ds3db));
823                 if (This->ds3db) {
824                         IDirectSound3DBuffer_AddRef((LPDIRECTSOUND3DBUFFER)This->ds3db);
825                         *ppobj = This->ds3db;
826                         return S_OK;
827                 }
828                 WARN("IID_IDirectSound3DBuffer\n");
829                 return E_NOINTERFACE;
830         }
831
832         if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
833                 ERR("app requested IDirectSound3DListener on secondary buffer\n");
834                 return E_NOINTERFACE;
835         }
836
837         if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) {
838                 if (!This->iks)
839                         IKsBufferPropertySetImpl_Create(This, &(This->iks));
840                 if (This->iks) {
841                         IKsPropertySet_AddRef((LPKSPROPERTYSET)This->iks);
842                         *ppobj = This->iks;
843                         return S_OK;
844                 }
845                 WARN("IID_IKsPropertySet\n");
846                 return E_NOINTERFACE;
847         }
848
849         FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
850
851         return E_NOINTERFACE;
852 }
853
854 static const IDirectSoundBuffer8Vtbl dsbvt =
855 {
856         IDirectSoundBufferImpl_QueryInterface,
857         IDirectSoundBufferImpl_AddRef,
858         IDirectSoundBufferImpl_Release,
859         IDirectSoundBufferImpl_GetCaps,
860         IDirectSoundBufferImpl_GetCurrentPosition,
861         IDirectSoundBufferImpl_GetFormat,
862         IDirectSoundBufferImpl_GetVolume,
863         IDirectSoundBufferImpl_GetPan,
864         IDirectSoundBufferImpl_GetFrequency,
865         IDirectSoundBufferImpl_GetStatus,
866         IDirectSoundBufferImpl_Initialize,
867         IDirectSoundBufferImpl_Lock,
868         IDirectSoundBufferImpl_Play,
869         IDirectSoundBufferImpl_SetCurrentPosition,
870         IDirectSoundBufferImpl_SetFormat,
871         IDirectSoundBufferImpl_SetVolume,
872         IDirectSoundBufferImpl_SetPan,
873         IDirectSoundBufferImpl_SetFrequency,
874         IDirectSoundBufferImpl_Stop,
875         IDirectSoundBufferImpl_Unlock,
876         IDirectSoundBufferImpl_Restore,
877         IDirectSoundBufferImpl_SetFX,
878         IDirectSoundBufferImpl_AcquireResources,
879         IDirectSoundBufferImpl_GetObjectInPath
880 };
881
882 HRESULT IDirectSoundBufferImpl_Create(
883         DirectSoundDevice * device,
884         IDirectSoundBufferImpl **pdsb,
885         LPCDSBUFFERDESC dsbd)
886 {
887         IDirectSoundBufferImpl *dsb;
888         LPWAVEFORMATEX wfex = dsbd->lpwfxFormat;
889         HRESULT err = DS_OK;
890         DWORD capf = 0;
891         TRACE("(%p,%p,%p)\n",device,pdsb,dsbd);
892
893         if (dsbd->dwBufferBytes < DSBSIZE_MIN || dsbd->dwBufferBytes > DSBSIZE_MAX) {
894                 WARN("invalid parameter: dsbd->dwBufferBytes = %d\n", dsbd->dwBufferBytes);
895                 *pdsb = NULL;
896                 return DSERR_INVALIDPARAM; /* FIXME: which error? */
897         }
898
899         dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
900
901         if (dsb == 0) {
902                 WARN("out of memory\n");
903                 *pdsb = NULL;
904                 return DSERR_OUTOFMEMORY;
905         }
906
907         TRACE("Created buffer at %p\n", dsb);
908
909         dsb->ref = 1;
910         dsb->numIfaces = 1;
911         dsb->device = device;
912         dsb->IDirectSoundBuffer8_iface.lpVtbl = &dsbvt;
913         dsb->iks = NULL;
914
915         /* size depends on version */
916         CopyMemory(&dsb->dsbd, dsbd, dsbd->dwSize);
917
918         dsb->pwfx = DSOUND_CopyFormat(wfex);
919         if (dsb->pwfx == NULL) {
920                 HeapFree(GetProcessHeap(),0,dsb);
921                 *pdsb = NULL;
922                 return DSERR_OUTOFMEMORY;
923         }
924
925         if (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign)
926                 dsb->buflen = dsbd->dwBufferBytes + 
927                         (dsbd->lpwfxFormat->nBlockAlign - 
928                         (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign));
929         else
930                 dsb->buflen = dsbd->dwBufferBytes;
931
932         dsb->freq = dsbd->lpwfxFormat->nSamplesPerSec;
933         dsb->notify = NULL;
934         dsb->notifies = NULL;
935         dsb->nrofnotifies = 0;
936
937         /* Check necessary hardware mixing capabilities */
938         if (wfex->nChannels==2) capf |= DSCAPS_SECONDARYSTEREO;
939         else capf |= DSCAPS_SECONDARYMONO;
940         if (wfex->wBitsPerSample==16) capf |= DSCAPS_SECONDARY16BIT;
941         else capf |= DSCAPS_SECONDARY8BIT;
942
943         TRACE("capf = 0x%08x, device->drvcaps.dwFlags = 0x%08x\n", capf, device->drvcaps.dwFlags);
944
945         /* Allocate an empty buffer */
946         dsb->buffer = HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb->buffer)));
947         if (dsb->buffer == NULL) {
948                 WARN("out of memory\n");
949                 HeapFree(GetProcessHeap(),0,dsb->pwfx);
950                 HeapFree(GetProcessHeap(),0,dsb);
951                 *pdsb = NULL;
952                 return DSERR_OUTOFMEMORY;
953         }
954
955         /* Allocate system memory for buffer */
956         dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen);
957         if (dsb->buffer->memory == NULL) {
958                 WARN("out of memory\n");
959                 HeapFree(GetProcessHeap(),0,dsb->pwfx);
960                 HeapFree(GetProcessHeap(),0,dsb->buffer);
961                 HeapFree(GetProcessHeap(),0,dsb);
962                 *pdsb = NULL;
963                 return DSERR_OUTOFMEMORY;
964         }
965
966         dsb->buffer->ref = 1;
967         list_init(&dsb->buffer->buffers);
968         list_add_head(&dsb->buffer->buffers, &dsb->entry);
969         FillMemory(dsb->buffer->memory, dsb->buflen, dsbd->lpwfxFormat->wBitsPerSample == 8 ? 128 : 0);
970
971         /* It's not necessary to initialize values to zero since */
972         /* we allocated this structure with HEAP_ZERO_MEMORY... */
973         dsb->buf_mixpos = dsb->sec_mixpos = 0;
974         dsb->state = STATE_STOPPED;
975
976         dsb->freqAdjust = ((DWORD64)dsb->freq << DSOUND_FREQSHIFT) / device->pwfx->nSamplesPerSec;
977         dsb->nAvgBytesPerSec = dsb->freq *
978                 dsbd->lpwfxFormat->nBlockAlign;
979
980         /* calculate fragment size and write lead */
981         DSOUND_RecalcFormat(dsb);
982
983         if (dsb->dsbd.dwFlags & DSBCAPS_CTRL3D) {
984                 dsb->ds3db_ds3db.dwSize = sizeof(DS3DBUFFER);
985                 dsb->ds3db_ds3db.vPosition.x = 0.0;
986                 dsb->ds3db_ds3db.vPosition.y = 0.0;
987                 dsb->ds3db_ds3db.vPosition.z = 0.0;
988                 dsb->ds3db_ds3db.vVelocity.x = 0.0;
989                 dsb->ds3db_ds3db.vVelocity.y = 0.0;
990                 dsb->ds3db_ds3db.vVelocity.z = 0.0;
991                 dsb->ds3db_ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
992                 dsb->ds3db_ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
993                 dsb->ds3db_ds3db.vConeOrientation.x = 0.0;
994                 dsb->ds3db_ds3db.vConeOrientation.y = 0.0;
995                 dsb->ds3db_ds3db.vConeOrientation.z = 0.0;
996                 dsb->ds3db_ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
997                 dsb->ds3db_ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE;
998                 dsb->ds3db_ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
999                 dsb->ds3db_ds3db.dwMode = DS3DMODE_NORMAL;
1000
1001                 dsb->ds3db_need_recalc = FALSE;
1002                 DSOUND_Calc3DBuffer(dsb);
1003         } else
1004                 DSOUND_RecalcVolPan(&(dsb->volpan));
1005
1006         RtlInitializeResource(&dsb->lock);
1007
1008         /* register buffer if not primary */
1009         if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
1010                 err = DirectSoundDevice_AddBuffer(device, dsb);
1011                 if (err != DS_OK) {
1012                         HeapFree(GetProcessHeap(),0,dsb->buffer->memory);
1013                         HeapFree(GetProcessHeap(),0,dsb->buffer);
1014                         RtlDeleteResource(&dsb->lock);
1015                         HeapFree(GetProcessHeap(),0,dsb->pwfx);
1016                         HeapFree(GetProcessHeap(),0,dsb);
1017                         dsb = NULL;
1018                 }
1019         }
1020
1021         *pdsb = dsb;
1022         return err;
1023 }
1024
1025 void secondarybuffer_destroy(IDirectSoundBufferImpl *This)
1026 {
1027     DirectSoundDevice_RemoveBuffer(This->device, This);
1028     RtlDeleteResource(&This->lock);
1029
1030     This->buffer->ref--;
1031     list_remove(&This->entry);
1032     if (This->buffer->ref == 0) {
1033         HeapFree(GetProcessHeap(), 0, This->buffer->memory);
1034         HeapFree(GetProcessHeap(), 0, This->buffer);
1035     }
1036
1037     HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
1038     HeapFree(GetProcessHeap(), 0, This->notifies);
1039     HeapFree(GetProcessHeap(), 0, This->pwfx);
1040     HeapFree(GetProcessHeap(), 0, This);
1041
1042     TRACE("(%p) released\n", This);
1043 }
1044
1045 HRESULT IDirectSoundBufferImpl_Destroy(
1046     IDirectSoundBufferImpl *pdsb)
1047 {
1048     TRACE("(%p)\n",pdsb);
1049
1050     /* This keeps the *_Destroy functions from possibly deleting
1051      * this object until it is ready to be deleted */
1052     InterlockedIncrement(&pdsb->numIfaces);
1053
1054     if (pdsb->iks) {
1055         WARN("iks not NULL\n");
1056         IKsBufferPropertySetImpl_Destroy(pdsb->iks);
1057         pdsb->iks = NULL;
1058     }
1059
1060     if (pdsb->ds3db) {
1061         WARN("ds3db not NULL\n");
1062         IDirectSound3DBufferImpl_Destroy(pdsb->ds3db);
1063         pdsb->ds3db = NULL;
1064     }
1065
1066     if (pdsb->notify) {
1067         WARN("notify not NULL\n");
1068         IDirectSoundNotifyImpl_Destroy(pdsb->notify);
1069         pdsb->notify = NULL;
1070     }
1071
1072     secondarybuffer_destroy(pdsb);
1073
1074     return S_OK;
1075 }
1076
1077 HRESULT IDirectSoundBufferImpl_Duplicate(
1078     DirectSoundDevice *device,
1079     IDirectSoundBufferImpl **ppdsb,
1080     IDirectSoundBufferImpl *pdsb)
1081 {
1082     IDirectSoundBufferImpl *dsb;
1083     HRESULT hres = DS_OK;
1084     TRACE("(%p,%p,%p)\n", device, ppdsb, pdsb);
1085
1086     dsb = HeapAlloc(GetProcessHeap(),0,sizeof(*dsb));
1087     if (dsb == NULL) {
1088         WARN("out of memory\n");
1089         *ppdsb = NULL;
1090         return DSERR_OUTOFMEMORY;
1091     }
1092     CopyMemory(dsb, pdsb, sizeof(*dsb));
1093
1094     dsb->pwfx = DSOUND_CopyFormat(pdsb->pwfx);
1095     if (dsb->pwfx == NULL) {
1096         HeapFree(GetProcessHeap(),0,dsb);
1097         *ppdsb = NULL;
1098         return DSERR_OUTOFMEMORY;
1099     }
1100
1101     dsb->buffer->ref++;
1102     list_add_head(&dsb->buffer->buffers, &dsb->entry);
1103     dsb->ref = 1;
1104     dsb->numIfaces = 1;
1105     dsb->state = STATE_STOPPED;
1106     dsb->buf_mixpos = dsb->sec_mixpos = 0;
1107     dsb->notify = NULL;
1108     dsb->notifies = NULL;
1109     dsb->nrofnotifies = 0;
1110     dsb->device = device;
1111     dsb->ds3db = NULL;
1112     dsb->iks = NULL; /* FIXME? */
1113     dsb->tmp_buffer = NULL;
1114     DSOUND_RecalcFormat(dsb);
1115     DSOUND_MixToTemporary(dsb, 0, dsb->buflen, FALSE);
1116
1117     RtlInitializeResource(&dsb->lock);
1118
1119     /* register buffer */
1120     hres = DirectSoundDevice_AddBuffer(device, dsb);
1121     if (hres != DS_OK) {
1122         RtlDeleteResource(&dsb->lock);
1123         HeapFree(GetProcessHeap(),0,dsb->tmp_buffer);
1124         list_remove(&dsb->entry);
1125         dsb->buffer->ref--;
1126         HeapFree(GetProcessHeap(),0,dsb->pwfx);
1127         HeapFree(GetProcessHeap(),0,dsb);
1128         dsb = NULL;
1129     }
1130
1131     *ppdsb = dsb;
1132     return hres;
1133 }
1134
1135 /*******************************************************************************
1136  *              IKsBufferPropertySet
1137  */
1138
1139 /* IUnknown methods */
1140 static HRESULT WINAPI IKsBufferPropertySetImpl_QueryInterface(
1141     LPKSPROPERTYSET iface,
1142     REFIID riid,
1143     LPVOID *ppobj )
1144 {
1145     IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
1146     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
1147
1148     return IDirectSoundBuffer_QueryInterface((LPDIRECTSOUNDBUFFER8)This->dsb, riid, ppobj);
1149 }
1150
1151 static ULONG WINAPI IKsBufferPropertySetImpl_AddRef(LPKSPROPERTYSET iface)
1152 {
1153     IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
1154     ULONG ref = InterlockedIncrement(&(This->ref));
1155     TRACE("(%p) ref was %d\n", This, ref - 1);
1156     return ref;
1157 }
1158
1159 static ULONG WINAPI IKsBufferPropertySetImpl_Release(LPKSPROPERTYSET iface)
1160 {
1161     IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
1162     ULONG ref = InterlockedDecrement(&(This->ref));
1163     TRACE("(%p) ref was %d\n", This, ref + 1);
1164
1165     if (!ref) {
1166     This->dsb->iks = 0;
1167     IDirectSoundBuffer_Release((LPDIRECTSOUND3DBUFFER)This->dsb);
1168     HeapFree(GetProcessHeap(), 0, This);
1169     TRACE("(%p) released\n", This);
1170     }
1171     return ref;
1172 }
1173
1174 static HRESULT WINAPI IKsBufferPropertySetImpl_Get(
1175     LPKSPROPERTYSET iface,
1176     REFGUID guidPropSet,
1177     ULONG dwPropID,
1178     LPVOID pInstanceData,
1179     ULONG cbInstanceData,
1180     LPVOID pPropData,
1181     ULONG cbPropData,
1182     PULONG pcbReturned )
1183 {
1184     IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
1185
1186     TRACE("(iface=%p,guidPropSet=%s,dwPropID=%d,pInstanceData=%p,cbInstanceData=%d,pPropData=%p,cbPropData=%d,pcbReturned=%p)\n",
1187     This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData,pcbReturned);
1188
1189     return E_PROP_ID_UNSUPPORTED;
1190 }
1191
1192 static HRESULT WINAPI IKsBufferPropertySetImpl_Set(
1193     LPKSPROPERTYSET iface,
1194     REFGUID guidPropSet,
1195     ULONG dwPropID,
1196     LPVOID pInstanceData,
1197     ULONG cbInstanceData,
1198     LPVOID pPropData,
1199     ULONG cbPropData )
1200 {
1201     IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
1202
1203     TRACE("(%p,%s,%d,%p,%d,%p,%d)\n",This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData);
1204
1205     return E_PROP_ID_UNSUPPORTED;
1206 }
1207
1208 static HRESULT WINAPI IKsBufferPropertySetImpl_QuerySupport(
1209     LPKSPROPERTYSET iface,
1210     REFGUID guidPropSet,
1211     ULONG dwPropID,
1212     PULONG pTypeSupport )
1213 {
1214     IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
1215
1216     TRACE("(%p,%s,%d,%p)\n",This,debugstr_guid(guidPropSet),dwPropID,pTypeSupport);
1217
1218     return E_PROP_ID_UNSUPPORTED;
1219 }
1220
1221 static const IKsPropertySetVtbl iksbvt = {
1222     IKsBufferPropertySetImpl_QueryInterface,
1223     IKsBufferPropertySetImpl_AddRef,
1224     IKsBufferPropertySetImpl_Release,
1225     IKsBufferPropertySetImpl_Get,
1226     IKsBufferPropertySetImpl_Set,
1227     IKsBufferPropertySetImpl_QuerySupport
1228 };
1229
1230 HRESULT IKsBufferPropertySetImpl_Create(
1231     IDirectSoundBufferImpl *dsb,
1232     IKsBufferPropertySetImpl **piks)
1233 {
1234     IKsBufferPropertySetImpl *iks;
1235     TRACE("(%p,%p)\n",dsb,piks);
1236     *piks = NULL;
1237
1238     iks = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*iks));
1239     if (iks == 0) {
1240         WARN("out of memory\n");
1241         *piks = NULL;
1242         return DSERR_OUTOFMEMORY;
1243     }
1244
1245     iks->ref = 0;
1246     iks->dsb = dsb;
1247     dsb->iks = iks;
1248     iks->lpVtbl = &iksbvt;
1249
1250     IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)dsb);
1251
1252     *piks = iks;
1253     return S_OK;
1254 }
1255
1256 HRESULT IKsBufferPropertySetImpl_Destroy(
1257     IKsBufferPropertySetImpl *piks)
1258 {
1259     TRACE("(%p)\n",piks);
1260
1261     while (IKsBufferPropertySetImpl_Release((LPKSPROPERTYSET)piks) > 0);
1262
1263     return S_OK;
1264 }