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