crypt32: Add tests for opening signed message to encode.
[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 "wine/debug.h"
32 #include "dsound.h"
33 #include "dsdriver.h"
34 #include "dsound_private.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
37
38 static HRESULT SecondaryBufferImpl_Destroy(SecondaryBufferImpl *pdsb);
39
40 /*******************************************************************************
41  *              IDirectSoundNotify
42  */
43
44 struct IDirectSoundNotifyImpl
45 {
46     /* IUnknown fields */
47     const IDirectSoundNotifyVtbl *lpVtbl;
48     LONG                        ref;
49     IDirectSoundBufferImpl*     dsb;
50 };
51
52 static HRESULT IDirectSoundNotifyImpl_Create(IDirectSoundBufferImpl *dsb,
53                                              IDirectSoundNotifyImpl **pdsn);
54 static HRESULT IDirectSoundNotifyImpl_Destroy(IDirectSoundNotifyImpl *pdsn);
55
56 static HRESULT WINAPI IDirectSoundNotifyImpl_QueryInterface(
57         LPDIRECTSOUNDNOTIFY iface,REFIID riid,LPVOID *ppobj
58 ) {
59         IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
60         TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
61
62         if (This->dsb == NULL) {
63                 WARN("invalid parameter\n");
64                 return E_INVALIDARG;
65         }
66
67         return IDirectSoundBuffer_QueryInterface((LPDIRECTSOUNDBUFFER)This->dsb, riid, ppobj);
68 }
69
70 static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface)
71 {
72     IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
73     ULONG ref = InterlockedIncrement(&(This->ref));
74     TRACE("(%p) ref was %d\n", This, ref - 1);
75     return ref;
76 }
77
78 static ULONG WINAPI IDirectSoundNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface)
79 {
80     IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
81     ULONG ref = InterlockedDecrement(&(This->ref));
82     TRACE("(%p) ref was %d\n", This, ref + 1);
83
84     if (!ref) {
85         IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->dsb);
86         This->dsb->notify = NULL;
87         HeapFree(GetProcessHeap(), 0, This);
88         TRACE("(%p) released\n", This);
89     }
90     return ref;
91 }
92
93 static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(
94         LPDIRECTSOUNDNOTIFY iface,DWORD howmuch,LPCDSBPOSITIONNOTIFY notify
95 ) {
96         IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
97         TRACE("(%p,0x%08x,%p)\n",This,howmuch,notify);
98
99         if (howmuch > 0 && notify == NULL) {
100             WARN("invalid parameter: notify == NULL\n");
101             return DSERR_INVALIDPARAM;
102         }
103
104         if (TRACE_ON(dsound)) {
105             unsigned int        i;
106             for (i=0;i<howmuch;i++)
107                 TRACE("notify at %d to %p\n",
108                     notify[i].dwOffset,notify[i].hEventNotify);
109         }
110
111         if (This->dsb->hwnotify) {
112             HRESULT hres;
113             hres = IDsDriverNotify_SetNotificationPositions(This->dsb->hwnotify, howmuch, notify);
114             if (hres != DS_OK)
115                     WARN("IDsDriverNotify_SetNotificationPositions failed\n");
116             return hres;
117         } else if (howmuch > 0) {
118             /* Make an internal copy of the caller-supplied array.
119              * Replace the existing copy if one is already present. */
120             if (This->dsb->notifies)
121                     This->dsb->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
122                         This->dsb->notifies, howmuch * sizeof(DSBPOSITIONNOTIFY));
123             else
124                     This->dsb->notifies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
125                         howmuch * sizeof(DSBPOSITIONNOTIFY));
126
127             if (This->dsb->notifies == NULL) {
128                     WARN("out of memory\n");
129                     return DSERR_OUTOFMEMORY;
130             }
131             CopyMemory(This->dsb->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
132             This->dsb->nrofnotifies = howmuch;
133         } else {
134            HeapFree(GetProcessHeap(), 0, This->dsb->notifies);
135            This->dsb->notifies = NULL;
136            This->dsb->nrofnotifies = 0;
137         }
138
139         return S_OK;
140 }
141
142 static const IDirectSoundNotifyVtbl dsnvt =
143 {
144     IDirectSoundNotifyImpl_QueryInterface,
145     IDirectSoundNotifyImpl_AddRef,
146     IDirectSoundNotifyImpl_Release,
147     IDirectSoundNotifyImpl_SetNotificationPositions,
148 };
149
150 static HRESULT IDirectSoundNotifyImpl_Create(
151     IDirectSoundBufferImpl * dsb,
152     IDirectSoundNotifyImpl **pdsn)
153 {
154     IDirectSoundNotifyImpl * dsn;
155     TRACE("(%p,%p)\n",dsb,pdsn);
156
157     dsn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dsn));
158
159     if (dsn == NULL) {
160         WARN("out of memory\n");
161         return DSERR_OUTOFMEMORY;
162     }
163
164     dsn->ref = 0;
165     dsn->lpVtbl = &dsnvt;
166     dsn->dsb = dsb;
167     dsb->notify = dsn;
168     IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)dsb);
169
170     *pdsn = dsn;
171     return DS_OK;
172 }
173
174 static HRESULT IDirectSoundNotifyImpl_Destroy(
175     IDirectSoundNotifyImpl *pdsn)
176 {
177     TRACE("(%p)\n",pdsn);
178
179     while (IDirectSoundNotifyImpl_Release((LPDIRECTSOUNDNOTIFY)pdsn) > 0);
180
181     return DS_OK;
182 }
183
184 /*******************************************************************************
185  *              IDirectSoundBuffer
186  */
187
188 static HRESULT WINAPI IDirectSoundBufferImpl_SetFormat(
189         LPDIRECTSOUNDBUFFER8 iface,LPCWAVEFORMATEX wfex
190 ) {
191         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
192
193         TRACE("(%p,%p)\n",This,wfex);
194         /* This method is not available on secondary buffers */
195         WARN("invalid call\n");
196         return DSERR_INVALIDCALL;
197 }
198
199 static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume(
200         LPDIRECTSOUNDBUFFER8 iface,LONG vol
201 ) {
202         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
203         LONG oldVol;
204         HRESULT hres = DS_OK;
205
206         TRACE("(%p,%d)\n",This,vol);
207
208         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
209                 WARN("control unavailable: This->dsbd.dwFlags = 0x%08x\n", This->dsbd.dwFlags);
210                 return DSERR_CONTROLUNAVAIL;
211         }
212
213         if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN)) {
214                 WARN("invalid parameter: vol = %d\n", vol);
215                 return DSERR_INVALIDPARAM;
216         }
217
218         /* **** */
219         EnterCriticalSection(&(This->lock));
220
221         if (This->dsbd.dwFlags & DSBCAPS_CTRL3D) {
222                 oldVol = This->ds3db_lVolume;
223                 This->ds3db_lVolume = vol;
224                 if (vol != oldVol)
225                         /* recalc 3d volume, which in turn recalcs the pans */
226                         DSOUND_Calc3DBuffer(This);
227         } else {
228                 oldVol = This->volpan.lVolume;
229                 This->volpan.lVolume = vol;
230                 if (vol != oldVol)
231                         DSOUND_RecalcVolPan(&(This->volpan));
232         }
233
234         if (vol != oldVol) {
235                 if (This->hwbuf) {
236                         hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
237                         if (hres != DS_OK)
238                                 WARN("IDsDriverBuffer_SetVolumePan failed\n");
239                 }
240         }
241
242         LeaveCriticalSection(&(This->lock));
243         /* **** */
244
245         return hres;
246 }
247
248 static HRESULT WINAPI IDirectSoundBufferImpl_GetVolume(
249         LPDIRECTSOUNDBUFFER8 iface,LPLONG vol
250 ) {
251         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
252         TRACE("(%p,%p)\n",This,vol);
253
254         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
255                 WARN("control unavailable\n");
256                 return DSERR_CONTROLUNAVAIL;
257         }
258
259         if (vol == NULL) {
260                 WARN("invalid parameter: vol == NULL\n");
261                 return DSERR_INVALIDPARAM;
262         }
263
264         *vol = This->volpan.lVolume;
265
266         return DS_OK;
267 }
268
269 static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency(
270         LPDIRECTSOUNDBUFFER8 iface,DWORD freq
271 ) {
272         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
273         DWORD oldFreq;
274
275         TRACE("(%p,%d)\n",This,freq);
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         EnterCriticalSection(&(This->lock));
292
293         oldFreq = This->freq;
294         This->freq = freq;
295         if (freq != oldFreq) {
296                 This->freqAdjust = (freq << DSOUND_FREQSHIFT) / This->device->pwfx->nSamplesPerSec;
297                 This->nAvgBytesPerSec = freq * This->pwfx->nBlockAlign;
298                 DSOUND_RecalcFormat(This);
299         }
300
301         LeaveCriticalSection(&(This->lock));
302         /* **** */
303
304         return DS_OK;
305 }
306
307 static HRESULT WINAPI IDirectSoundBufferImpl_Play(
308         LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags
309 ) {
310         HRESULT hres = DS_OK;
311         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
312         TRACE("(%p,%08x,%08x,%08x)\n",This,reserved1,reserved2,flags);
313
314         /* **** */
315         EnterCriticalSection(&(This->lock));
316
317         This->playflags = flags;
318         if (This->state == STATE_STOPPED) {
319                 This->leadin = TRUE;
320                 This->startpos = This->buf_mixpos;
321                 This->state = STATE_STARTING;
322         } else if (This->state == STATE_STOPPING)
323                 This->state = STATE_PLAYING;
324         if (This->hwbuf) {
325                 hres = IDsDriverBuffer_Play(This->hwbuf, 0, 0, This->playflags);
326                 if (hres != DS_OK)
327                         WARN("IDsDriverBuffer_Play failed\n");
328                 else
329                         This->state = STATE_PLAYING;
330         }
331
332         LeaveCriticalSection(&(This->lock));
333         /* **** */
334
335         return hres;
336 }
337
338 static HRESULT WINAPI IDirectSoundBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface)
339 {
340         HRESULT hres = DS_OK;
341         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
342         TRACE("(%p)\n",This);
343
344         /* **** */
345         EnterCriticalSection(&(This->lock));
346
347         if (This->state == STATE_PLAYING)
348                 This->state = STATE_STOPPING;
349         else if (This->state == STATE_STARTING)
350                 This->state = STATE_STOPPED;
351         if (This->hwbuf) {
352                 hres = IDsDriverBuffer_Stop(This->hwbuf);
353                 if (hres != DS_OK)
354                         WARN("IDsDriverBuffer_Stop failed\n");
355                 else
356                         This->state = STATE_STOPPED;
357         }
358         DSOUND_CheckEvent(This, 0, 0);
359
360         LeaveCriticalSection(&(This->lock));
361         /* **** */
362
363         return hres;
364 }
365
366 static ULONG WINAPI IDirectSoundBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface)
367 {
368     IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
369     ULONG ref = InterlockedIncrement(&(This->ref));
370     TRACE("(%p) ref was %d\n", This, ref - 1);
371     return ref;
372 }
373
374 static ULONG WINAPI IDirectSoundBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface)
375 {
376     IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
377     ULONG ref = InterlockedDecrement(&(This->ref));
378     TRACE("(%p) ref was %d\n", This, ref + 1);
379
380     if (!ref) {
381         DirectSoundDevice_RemoveBuffer(This->device, This);
382
383         This->lock.DebugInfo->Spare[0] = 0;
384         DeleteCriticalSection(&(This->lock));
385
386         if (This->hwbuf) {
387                 IDsDriverBuffer_Release(This->hwbuf);
388                 if (This->device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) {
389                         This->buffer->ref--;
390                         if (This->buffer->ref==0) {
391                                 HeapFree(GetProcessHeap(),0,This->buffer->memory);
392                                 HeapFree(GetProcessHeap(),0,This->buffer);
393                         }
394                 }
395         } else {
396                 This->buffer->ref--;
397                 if (This->buffer->ref==0) {
398                         HeapFree(GetProcessHeap(),0,This->buffer->memory);
399                         HeapFree(GetProcessHeap(),0,This->buffer);
400                 }
401         }
402
403         HeapFree(GetProcessHeap(), 0, This->notifies);
404         HeapFree(GetProcessHeap(), 0, This->pwfx);
405         HeapFree(GetProcessHeap(), 0, This);
406
407         TRACE("(%p) released\n", This);
408     }
409     return ref;
410 }
411
412 static DWORD DSOUND_CalcPlayPosition(IDirectSoundBufferImpl *This)
413 {
414         DWORD bplay = This->buf_mixpos;
415
416         /* check for lead-in */
417         if (This->leadin && ((bplay < This->startpos) || (bplay > This->buf_mixpos))) {
418                 /* seems we haven't started playing yet */
419                 TRACE("this still in lead-in phase\n");
420                 bplay = This->startpos;
421         }
422
423         /* sanity */
424         if (bplay >= This->buflen){
425                 FIXME("Bad play position. bplay: %d, buflen: %d\n", bplay, This->buflen);
426                 bplay %= This->buflen;
427         }
428
429         /* return the result */
430         return bplay;
431 }
432
433 static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(
434         LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos
435 ) {
436         HRESULT hres;
437         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
438         TRACE("(%p,%p,%p)\n",This,playpos,writepos);
439         if (This->hwbuf) {
440                 hres=IDsDriverBuffer_GetPosition(This->hwbuf,playpos,writepos);
441                 if (hres != DS_OK) {
442                     WARN("IDsDriverBuffer_GetPosition failed\n");
443                     return hres;
444                 }
445         } else {
446                 if (playpos && (This->state != STATE_PLAYING))
447                         /* we haven't been merged into the primary buffer (yet) */
448                         *playpos = This->buf_mixpos;
449                 else if (playpos)
450                         *playpos = DSOUND_CalcPlayPosition(This);
451                 if (writepos)
452                     *writepos = (playpos ? *playpos : This->buf_mixpos);
453         }
454         if (writepos) {
455                 if (This->state != STATE_STOPPED) {
456                         /* apply the documented 10ms lead to writepos */
457                         *writepos += This->writelead;
458                 }
459                 *writepos %= This->buflen;
460         }
461
462         TRACE("playpos = %d, writepos = %d, buflen=%d (%p, time=%d)\n",
463                 playpos?*playpos:-1, writepos?*writepos:-1, This->buflen, This, GetTickCount());
464
465         return DS_OK;
466 }
467
468 static HRESULT WINAPI IDirectSoundBufferImpl_GetStatus(
469         LPDIRECTSOUNDBUFFER8 iface,LPDWORD status
470 ) {
471         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
472         TRACE("(%p,%p), thread is %04x\n",This,status,GetCurrentThreadId());
473
474         if (status == NULL) {
475                 WARN("invalid parameter: status = NULL\n");
476                 return DSERR_INVALIDPARAM;
477         }
478
479         *status = 0;
480         if ((This->state == STATE_STARTING) || (This->state == STATE_PLAYING)) {
481                 *status |= DSBSTATUS_PLAYING;
482                 if (This->playflags & DSBPLAY_LOOPING)
483                         *status |= DSBSTATUS_LOOPING;
484         }
485
486         TRACE("status=%x\n", *status);
487         return DS_OK;
488 }
489
490
491 static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat(
492     LPDIRECTSOUNDBUFFER8 iface,
493     LPWAVEFORMATEX lpwf,
494     DWORD wfsize,
495     LPDWORD wfwritten)
496 {
497     DWORD size;
498     IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
499     TRACE("(%p,%p,%d,%p)\n",This,lpwf,wfsize,wfwritten);
500
501     size = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;
502
503     if (lpwf) { /* NULL is valid */
504         if (wfsize >= size) {
505             CopyMemory(lpwf,This->pwfx,size);
506             if (wfwritten)
507                 *wfwritten = size;
508         } else {
509             WARN("invalid parameter: wfsize too small\n");
510             if (wfwritten)
511                 *wfwritten = 0;
512             return DSERR_INVALIDPARAM;
513         }
514     } else {
515         if (wfwritten)
516             *wfwritten = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;
517         else {
518             WARN("invalid parameter: wfwritten == NULL\n");
519             return DSERR_INVALIDPARAM;
520         }
521     }
522
523     return DS_OK;
524 }
525
526 static HRESULT WINAPI IDirectSoundBufferImpl_Lock(
527         LPDIRECTSOUNDBUFFER8 iface,DWORD writecursor,DWORD writebytes,LPVOID *lplpaudioptr1,LPDWORD audiobytes1,LPVOID *lplpaudioptr2,LPDWORD audiobytes2,DWORD flags
528 ) {
529         HRESULT hres = DS_OK;
530         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
531
532         TRACE("(%p,%d,%d,%p,%p,%p,%p,0x%08x) at %d\n",
533                 This,
534                 writecursor,
535                 writebytes,
536                 lplpaudioptr1,
537                 audiobytes1,
538                 lplpaudioptr2,
539                 audiobytes2,
540                 flags,
541                 GetTickCount()
542         );
543
544         /* when this flag is set, writecursor is meaningless and must be calculated */
545         if (flags & DSBLOCK_FROMWRITECURSOR) {
546                 /* GetCurrentPosition does too much magic to duplicate here */
547                 hres = IDirectSoundBufferImpl_GetCurrentPosition(iface, NULL, &writecursor);
548                 if (hres != DS_OK) {
549                         WARN("IDirectSoundBufferImpl_GetCurrentPosition failed\n");
550                         return hres;
551                 }
552         }
553
554         /* when this flag is set, writebytes is meaningless and must be set */
555         if (flags & DSBLOCK_ENTIREBUFFER)
556                 writebytes = This->buflen;
557
558         if (writecursor >= This->buflen) {
559                 WARN("Invalid parameter, writecursor: %u >= buflen: %u\n",
560                      writecursor, This->buflen);
561                 return DSERR_INVALIDPARAM;
562         }
563
564         if (writebytes > This->buflen) {
565                 WARN("Invalid parameter, writebytes: %u > buflen: %u\n",
566                      writebytes, This->buflen);
567                 return DSERR_INVALIDPARAM;
568         }
569
570         /* **** */
571         EnterCriticalSection(&(This->lock));
572
573         if (!(This->device->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
574                 hres = IDsDriverBuffer_Lock(This->hwbuf,
575                                      lplpaudioptr1, audiobytes1,
576                                      lplpaudioptr2, audiobytes2,
577                                      writecursor, writebytes,
578                                      0);
579                 if (hres != DS_OK) {
580                         WARN("IDsDriverBuffer_Lock failed\n");
581                         LeaveCriticalSection(&(This->lock));
582                         return hres;
583                 }
584         } else {
585                 if (writecursor+writebytes <= This->buflen) {
586                         *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
587                         *audiobytes1 = writebytes;
588                         if (lplpaudioptr2)
589                                 *(LPBYTE*)lplpaudioptr2 = NULL;
590                         if (audiobytes2)
591                                 *audiobytes2 = 0;
592                         TRACE("Locked %p(%i bytes) and %p(%i bytes) writecursor=%d\n",
593                           *(LPBYTE*)lplpaudioptr1, *audiobytes1, lplpaudioptr2 ? *(LPBYTE*)lplpaudioptr2 : NULL, audiobytes2 ? *audiobytes2: 0, writecursor);
594                         TRACE("->%d.0\n",writebytes);
595                 } else {
596                         *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
597                         *audiobytes1 = This->buflen-writecursor;
598                         if (lplpaudioptr2)
599                                 *(LPBYTE*)lplpaudioptr2 = This->buffer->memory;
600                         if (audiobytes2)
601                                 *audiobytes2 = writebytes-(This->buflen-writecursor);
602                         TRACE("Locked %p(%i bytes) and %p(%i bytes) writecursor=%d\n", *(LPBYTE*)lplpaudioptr1, *audiobytes1, lplpaudioptr2 ? *(LPBYTE*)lplpaudioptr2 : NULL, audiobytes2 ? *audiobytes2: 0, writecursor);
603                 }
604         }
605
606         LeaveCriticalSection(&(This->lock));
607         /* **** */
608
609         return DS_OK;
610 }
611
612 static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(
613         LPDIRECTSOUNDBUFFER8 iface,DWORD newpos
614 ) {
615         HRESULT hres = DS_OK;
616         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
617         TRACE("(%p,%d)\n",This,newpos);
618
619         /* **** */
620         EnterCriticalSection(&(This->lock));
621
622         /* start mixing from this new location instead */
623         newpos %= This->buflen;
624         newpos -= newpos%This->pwfx->nBlockAlign;
625         This->buf_mixpos = newpos;
626
627         /* at this point, do not attempt to reset buffers, mess with primary mix position,
628            or anything like that to reduce latancy. The data already prebuffered cannot be changed */
629
630         /* position HW buffer if applicable */
631         if (This->hwbuf) {
632                 hres = IDsDriverBuffer_SetPosition(This->hwbuf, This->buf_mixpos);
633                 if (hres != DS_OK)
634                         WARN("IDsDriverBuffer_SetPosition failed\n");
635         }
636
637         LeaveCriticalSection(&(This->lock));
638         /* **** */
639
640         return hres;
641 }
642
643 static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(
644         LPDIRECTSOUNDBUFFER8 iface,LONG pan
645 ) {
646         HRESULT hres = DS_OK;
647         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
648
649         TRACE("(%p,%d)\n",This,pan);
650
651         if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT)) {
652                 WARN("invalid parameter: pan = %d\n", pan);
653                 return DSERR_INVALIDPARAM;
654         }
655
656         /* You cannot use both pan and 3D controls */
657         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
658             (This->dsbd.dwFlags & DSBCAPS_CTRL3D)) {
659                 WARN("control unavailable\n");
660                 return DSERR_CONTROLUNAVAIL;
661         }
662
663         /* **** */
664         EnterCriticalSection(&(This->lock));
665
666         if (This->volpan.lPan != pan) {
667                 This->volpan.lPan = pan;
668                 DSOUND_RecalcVolPan(&(This->volpan));
669
670                 if (This->hwbuf) {
671                         hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
672                         if (hres != DS_OK)
673                                 WARN("IDsDriverBuffer_SetVolumePan failed\n");
674                 }
675         }
676
677         LeaveCriticalSection(&(This->lock));
678         /* **** */
679
680         return hres;
681 }
682
683 static HRESULT WINAPI IDirectSoundBufferImpl_GetPan(
684         LPDIRECTSOUNDBUFFER8 iface,LPLONG pan
685 ) {
686         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
687         TRACE("(%p,%p)\n",This,pan);
688
689         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN)) {
690                 WARN("control unavailable\n");
691                 return DSERR_CONTROLUNAVAIL;
692         }
693
694         if (pan == NULL) {
695                 WARN("invalid parameter: pan = NULL\n");
696                 return DSERR_INVALIDPARAM;
697         }
698
699         *pan = This->volpan.lPan;
700
701         return DS_OK;
702 }
703
704 static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(
705         LPDIRECTSOUNDBUFFER8 iface,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2
706 ) {
707         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
708         HRESULT hres = DS_OK;
709
710         TRACE("(%p,%p,%d,%p,%d)\n", This,p1,x1,p2,x2);
711
712         /* **** */
713         EnterCriticalSection(&(This->lock));
714
715         if (!(This->device->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
716                 hres = IDsDriverBuffer_Unlock(This->hwbuf, p1, x1, p2, x2);
717                 if (hres != DS_OK)
718                         WARN("IDsDriverBuffer_Unlock failed\n");
719         }
720
721         LeaveCriticalSection(&(This->lock));
722         /* **** */
723
724         return hres;
725 }
726
727 static HRESULT WINAPI IDirectSoundBufferImpl_Restore(
728         LPDIRECTSOUNDBUFFER8 iface
729 ) {
730         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
731         FIXME("(%p):stub\n",This);
732         return DS_OK;
733 }
734
735 static HRESULT WINAPI IDirectSoundBufferImpl_GetFrequency(
736         LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq
737 ) {
738         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
739         TRACE("(%p,%p)\n",This,freq);
740
741         if (freq == NULL) {
742                 WARN("invalid parameter: freq = NULL\n");
743                 return DSERR_INVALIDPARAM;
744         }
745
746         *freq = This->freq;
747         TRACE("-> %d\n", *freq);
748
749         return DS_OK;
750 }
751
752 static HRESULT WINAPI IDirectSoundBufferImpl_SetFX(
753         LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes
754 ) {
755         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
756         DWORD u;
757
758         FIXME("(%p,%u,%p,%p): stub\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
759
760         if (pdwResultCodes)
761                 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
762
763         WARN("control unavailable\n");
764         return DSERR_CONTROLUNAVAIL;
765 }
766
767 static HRESULT WINAPI IDirectSoundBufferImpl_AcquireResources(
768         LPDIRECTSOUNDBUFFER8 iface,DWORD dwFlags,DWORD dwEffectsCount,LPDWORD pdwResultCodes
769 ) {
770         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
771         DWORD u;
772
773         FIXME("(%p,%08u,%u,%p): stub\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
774
775         if (pdwResultCodes)
776                 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
777
778         WARN("control unavailable\n");
779         return DSERR_CONTROLUNAVAIL;
780 }
781
782 static HRESULT WINAPI IDirectSoundBufferImpl_GetObjectInPath(
783         LPDIRECTSOUNDBUFFER8 iface,REFGUID rguidObject,DWORD dwIndex,REFGUID rguidInterface,LPVOID* ppObject
784 ) {
785         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
786
787         FIXME("(%p,%s,%u,%s,%p): stub\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
788
789         WARN("control unavailable\n");
790         return DSERR_CONTROLUNAVAIL;
791 }
792
793 static HRESULT WINAPI IDirectSoundBufferImpl_Initialize(
794         LPDIRECTSOUNDBUFFER8 iface,LPDIRECTSOUND dsound,LPCDSBUFFERDESC dbsd
795 ) {
796         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
797         FIXME("(%p,%p,%p):stub\n",This,dsound,dbsd);
798         DPRINTF("Re-Init!!!\n");
799         WARN("already initialized\n");
800         return DSERR_ALREADYINITIALIZED;
801 }
802
803 static HRESULT WINAPI IDirectSoundBufferImpl_GetCaps(
804         LPDIRECTSOUNDBUFFER8 iface,LPDSBCAPS caps
805 ) {
806         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
807         TRACE("(%p)->(%p)\n",This,caps);
808
809         if (caps == NULL) {
810                 WARN("invalid parameter: caps == NULL\n");
811                 return DSERR_INVALIDPARAM;
812         }
813
814         if (caps->dwSize < sizeof(*caps)) {
815                 WARN("invalid parameter: caps->dwSize = %d\n",caps->dwSize);
816                 return DSERR_INVALIDPARAM;
817         }
818
819         caps->dwFlags = This->dsbd.dwFlags;
820         if (This->hwbuf) caps->dwFlags |= DSBCAPS_LOCHARDWARE;
821         else caps->dwFlags |= DSBCAPS_LOCSOFTWARE;
822
823         caps->dwBufferBytes = This->buflen;
824
825         /* According to windows, this is zero*/
826         caps->dwUnlockTransferRate = 0;
827         caps->dwPlayCpuOverhead = 0;
828
829         return DS_OK;
830 }
831
832 static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface(
833         LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj
834 ) {
835         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
836
837         TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
838
839         if (ppobj == NULL) {
840                 WARN("invalid parameter\n");
841                 return E_INVALIDARG;
842         }
843
844         *ppobj = NULL;  /* assume failure */
845
846         if ( IsEqualGUID(riid, &IID_IUnknown) ||
847              IsEqualGUID(riid, &IID_IDirectSoundBuffer) ||
848              IsEqualGUID(riid, &IID_IDirectSoundBuffer8) ) {
849                 if (!This->secondary)
850                         SecondaryBufferImpl_Create(This, &(This->secondary));
851                 if (This->secondary) {
852                         IDirectSoundBuffer8_AddRef((LPDIRECTSOUNDBUFFER8)This->secondary);
853                         *ppobj = This->secondary;
854                         return S_OK;
855                 }
856                 WARN("IID_IDirectSoundBuffer\n");
857                 return E_NOINTERFACE;
858         }
859
860         if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
861                 if (!This->notify)
862                         IDirectSoundNotifyImpl_Create(This, &(This->notify));
863                 if (This->notify) {
864                         IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify);
865                         *ppobj = This->notify;
866                         return S_OK;
867                 }
868                 WARN("IID_IDirectSoundNotify\n");
869                 return E_NOINTERFACE;
870         }
871
872         if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) {
873                 if (!This->ds3db)
874                         IDirectSound3DBufferImpl_Create(This, &(This->ds3db));
875                 if (This->ds3db) {
876                         IDirectSound3DBuffer_AddRef((LPDIRECTSOUND3DBUFFER)This->ds3db);
877                         *ppobj = This->ds3db;
878                         return S_OK;
879                 }
880                 WARN("IID_IDirectSound3DBuffer\n");
881                 return E_NOINTERFACE;
882         }
883
884         if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
885                 ERR("app requested IDirectSound3DListener on secondary buffer\n");
886                 return E_NOINTERFACE;
887         }
888
889         if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) {
890                 if (!This->iks)
891                         IKsBufferPropertySetImpl_Create(This, &(This->iks));
892                 if (This->iks) {
893                         IKsPropertySet_AddRef((LPKSPROPERTYSET)This->iks);
894                         *ppobj = This->iks;
895                         return S_OK;
896                 }
897                 WARN("IID_IKsPropertySet\n");
898                 return E_NOINTERFACE;
899         }
900
901         FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
902
903         return E_NOINTERFACE;
904 }
905
906 static const IDirectSoundBuffer8Vtbl dsbvt =
907 {
908         IDirectSoundBufferImpl_QueryInterface,
909         IDirectSoundBufferImpl_AddRef,
910         IDirectSoundBufferImpl_Release,
911         IDirectSoundBufferImpl_GetCaps,
912         IDirectSoundBufferImpl_GetCurrentPosition,
913         IDirectSoundBufferImpl_GetFormat,
914         IDirectSoundBufferImpl_GetVolume,
915         IDirectSoundBufferImpl_GetPan,
916         IDirectSoundBufferImpl_GetFrequency,
917         IDirectSoundBufferImpl_GetStatus,
918         IDirectSoundBufferImpl_Initialize,
919         IDirectSoundBufferImpl_Lock,
920         IDirectSoundBufferImpl_Play,
921         IDirectSoundBufferImpl_SetCurrentPosition,
922         IDirectSoundBufferImpl_SetFormat,
923         IDirectSoundBufferImpl_SetVolume,
924         IDirectSoundBufferImpl_SetPan,
925         IDirectSoundBufferImpl_SetFrequency,
926         IDirectSoundBufferImpl_Stop,
927         IDirectSoundBufferImpl_Unlock,
928         IDirectSoundBufferImpl_Restore,
929         IDirectSoundBufferImpl_SetFX,
930         IDirectSoundBufferImpl_AcquireResources,
931         IDirectSoundBufferImpl_GetObjectInPath
932 };
933
934 HRESULT IDirectSoundBufferImpl_Create(
935         DirectSoundDevice * device,
936         IDirectSoundBufferImpl **pdsb,
937         LPCDSBUFFERDESC dsbd)
938 {
939         IDirectSoundBufferImpl *dsb;
940         LPWAVEFORMATEX wfex = dsbd->lpwfxFormat;
941         HRESULT err = DS_OK;
942         DWORD capf = 0;
943         int use_hw, alloc_size, cp_size;
944         TRACE("(%p,%p,%p)\n",device,pdsb,dsbd);
945
946         if (dsbd->dwBufferBytes < DSBSIZE_MIN || dsbd->dwBufferBytes > DSBSIZE_MAX) {
947                 WARN("invalid parameter: dsbd->dwBufferBytes = %d\n", dsbd->dwBufferBytes);
948                 *pdsb = NULL;
949                 return DSERR_INVALIDPARAM; /* FIXME: which error? */
950         }
951
952         dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
953
954         if (dsb == 0) {
955                 WARN("out of memory\n");
956                 *pdsb = NULL;
957                 return DSERR_OUTOFMEMORY;
958         }
959
960         TRACE("Created buffer at %p\n", dsb);
961
962         dsb->ref = 0;
963         dsb->secondary = 0;
964         dsb->device = device;
965         dsb->lpVtbl = &dsbvt;
966         dsb->iks = NULL;
967
968         /* size depends on version */
969         CopyMemory(&dsb->dsbd, dsbd, dsbd->dwSize);
970
971         /* variable sized struct so calculate size based on format */
972         if (wfex->wFormatTag == WAVE_FORMAT_PCM) {
973                 alloc_size = sizeof(WAVEFORMATEX);
974                 cp_size = sizeof(PCMWAVEFORMAT);
975         } else 
976                 alloc_size = cp_size = sizeof(WAVEFORMATEX) + wfex->cbSize;
977
978         dsb->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,alloc_size);
979         if (dsb->pwfx == NULL) {
980                 WARN("out of memory\n");
981                 HeapFree(GetProcessHeap(),0,dsb);
982                 *pdsb = NULL;
983                 return DSERR_OUTOFMEMORY;
984         }
985
986         CopyMemory(dsb->pwfx, wfex, cp_size);
987
988         if (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign)
989                 dsb->buflen = dsbd->dwBufferBytes + 
990                         (dsbd->lpwfxFormat->nBlockAlign - 
991                         (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign));
992         else
993                 dsb->buflen = dsbd->dwBufferBytes;
994
995         dsb->freq = dsbd->lpwfxFormat->nSamplesPerSec;
996         dsb->notify = NULL;
997         dsb->notifies = NULL;
998         dsb->nrofnotifies = 0;
999         dsb->hwnotify = 0;
1000
1001         /* Check necessary hardware mixing capabilities */
1002         if (wfex->nChannels==2) capf |= DSCAPS_SECONDARYSTEREO;
1003         else capf |= DSCAPS_SECONDARYMONO;
1004         if (wfex->wBitsPerSample==16) capf |= DSCAPS_SECONDARY16BIT;
1005         else capf |= DSCAPS_SECONDARY8BIT;
1006
1007         use_hw = (device->drvcaps.dwFlags & capf) == capf;
1008         TRACE("use_hw = 0x%08x, capf = 0x%08x, device->drvcaps.dwFlags = 0x%08x\n", use_hw, capf, device->drvcaps.dwFlags);
1009
1010         /* FIXME: check hardware sample rate mixing capabilities */
1011         /* FIXME: check app hints for software/hardware buffer (STATIC, LOCHARDWARE, etc) */
1012         /* FIXME: check whether any hardware buffers are left */
1013         /* FIXME: handle DSDHEAP_CREATEHEAP for hardware buffers */
1014
1015         /* Allocate an empty buffer */
1016         dsb->buffer = HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb->buffer)));
1017         if (dsb->buffer == NULL) {
1018                 WARN("out of memory\n");
1019                 HeapFree(GetProcessHeap(),0,dsb->pwfx);
1020                 HeapFree(GetProcessHeap(),0,dsb);
1021                 *pdsb = NULL;
1022                 return DSERR_OUTOFMEMORY;
1023         }
1024
1025         /* Allocate system memory for buffer if applicable */
1026         if ((device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) || !use_hw) {
1027                 dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen);
1028                 if (dsb->buffer->memory == NULL) {
1029                         WARN("out of memory\n");
1030                         HeapFree(GetProcessHeap(),0,dsb->pwfx);
1031                         HeapFree(GetProcessHeap(),0,dsb->buffer);
1032                         HeapFree(GetProcessHeap(),0,dsb);
1033                         *pdsb = NULL;
1034                         return DSERR_OUTOFMEMORY;
1035                 }
1036                 dsb->buffer->ref = 1;
1037                 FillMemory(dsb->buffer->memory, dsb->buflen, dsbd->lpwfxFormat->wBitsPerSample == 8 ? 128 : 0);
1038         }
1039
1040         /* Allocate the hardware buffer */
1041         if (use_hw) {
1042                 err = IDsDriver_CreateSoundBuffer(device->driver,wfex,dsbd->dwFlags,0,
1043                                                   &(dsb->buflen),&(dsb->buffer->memory),
1044                                                   (LPVOID*)&(dsb->hwbuf));
1045                 /* fall back to software buffer on failure */
1046                 if (err != DS_OK) {
1047                         TRACE("IDsDriver_CreateSoundBuffer failed, falling back to software buffer\n");
1048                         use_hw = 0;
1049                         if (device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) {
1050                                 dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen);
1051                                 if (dsb->buffer->memory == NULL) {
1052                                         WARN("out of memory\n");
1053                                         HeapFree(GetProcessHeap(),0,dsb->buffer);
1054                                         HeapFree(GetProcessHeap(),0,dsb->pwfx);
1055                                         HeapFree(GetProcessHeap(),0,dsb);
1056                                         *pdsb = NULL;
1057                                         return DSERR_OUTOFMEMORY;
1058                                 }
1059                                 dsb->buffer->ref = 1;
1060                                 FillMemory(dsb->buffer->memory, dsb->buflen, dsbd->lpwfxFormat->wBitsPerSample == 8 ? 128 : 0);
1061                         }
1062                         err = DS_OK;
1063                 }
1064         }
1065
1066         /* calculate fragment size and write lead */
1067         DSOUND_RecalcFormat(dsb);
1068
1069         /* It's not necessary to initialize values to zero since */
1070         /* we allocated this structure with HEAP_ZERO_MEMORY... */
1071         dsb->buf_mixpos = 0;
1072         dsb->state = STATE_STOPPED;
1073
1074         dsb->freqAdjust = (dsb->freq << DSOUND_FREQSHIFT) /
1075                 device->pwfx->nSamplesPerSec;
1076         dsb->nAvgBytesPerSec = dsb->freq *
1077                 dsbd->lpwfxFormat->nBlockAlign;
1078
1079         if (dsb->dsbd.dwFlags & DSBCAPS_CTRL3D) {
1080                 dsb->ds3db_ds3db.dwSize = sizeof(DS3DBUFFER);
1081                 dsb->ds3db_ds3db.vPosition.x = 0.0;
1082                 dsb->ds3db_ds3db.vPosition.y = 0.0;
1083                 dsb->ds3db_ds3db.vPosition.z = 0.0;
1084                 dsb->ds3db_ds3db.vVelocity.x = 0.0;
1085                 dsb->ds3db_ds3db.vVelocity.y = 0.0;
1086                 dsb->ds3db_ds3db.vVelocity.z = 0.0;
1087                 dsb->ds3db_ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
1088                 dsb->ds3db_ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
1089                 dsb->ds3db_ds3db.vConeOrientation.x = 0.0;
1090                 dsb->ds3db_ds3db.vConeOrientation.y = 0.0;
1091                 dsb->ds3db_ds3db.vConeOrientation.z = 0.0;
1092                 dsb->ds3db_ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
1093                 dsb->ds3db_ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE;
1094                 dsb->ds3db_ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
1095                 dsb->ds3db_ds3db.dwMode = DS3DMODE_NORMAL;
1096
1097                 dsb->ds3db_need_recalc = FALSE;
1098                 DSOUND_Calc3DBuffer(dsb);
1099         } else
1100                 DSOUND_RecalcVolPan(&(dsb->volpan));
1101
1102         InitializeCriticalSection(&(dsb->lock));
1103         dsb->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectSoundBufferImpl.lock");
1104
1105         /* register buffer if not primary */
1106         if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
1107                 err = DirectSoundDevice_AddBuffer(device, dsb);
1108                 if (err != DS_OK) {
1109                         HeapFree(GetProcessHeap(),0,dsb->buffer->memory);
1110                         HeapFree(GetProcessHeap(),0,dsb->buffer);
1111                         dsb->lock.DebugInfo->Spare[0] = 0;
1112                         DeleteCriticalSection(&(dsb->lock));
1113                         HeapFree(GetProcessHeap(),0,dsb->pwfx);
1114                         HeapFree(GetProcessHeap(),0,dsb);
1115                         dsb = NULL;
1116                 }
1117         }
1118
1119         *pdsb = dsb;
1120         return err;
1121 }
1122
1123 HRESULT IDirectSoundBufferImpl_Destroy(
1124     IDirectSoundBufferImpl *pdsb)
1125 {
1126     TRACE("(%p)\n",pdsb);
1127
1128     /* This keeps the *_Destroy functions from possibly deleting
1129      * this object until it is ready to be deleted */
1130     IDirectSoundBufferImpl_AddRef((LPDIRECTSOUNDBUFFER8)pdsb);
1131
1132     if (pdsb->iks) {
1133         WARN("iks not NULL\n");
1134         IKsBufferPropertySetImpl_Destroy(pdsb->iks);
1135         pdsb->iks = NULL;
1136     }
1137
1138     if (pdsb->ds3db) {
1139         WARN("ds3db not NULL\n");
1140         IDirectSound3DBufferImpl_Destroy(pdsb->ds3db);
1141         pdsb->ds3db = NULL;
1142     }
1143
1144     if (pdsb->notify) {
1145         WARN("notify not NULL\n");
1146         IDirectSoundNotifyImpl_Destroy(pdsb->notify);
1147         pdsb->notify = NULL;
1148     }
1149
1150     if (pdsb->secondary) {
1151         WARN("dsb not NULL\n");
1152         SecondaryBufferImpl_Destroy(pdsb->secondary);
1153         pdsb->secondary = NULL;
1154     }
1155
1156     while (IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)pdsb) > 0);
1157
1158     return S_OK;
1159 }
1160
1161 HRESULT IDirectSoundBufferImpl_Duplicate(
1162     DirectSoundDevice *device,
1163     IDirectSoundBufferImpl **ppdsb,
1164     IDirectSoundBufferImpl *pdsb)
1165 {
1166     IDirectSoundBufferImpl *dsb;
1167     HRESULT hres = DS_OK;
1168     int size;
1169     TRACE("(%p,%p,%p)\n", device, pdsb, pdsb);
1170
1171     dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
1172
1173     if (dsb == NULL) {
1174         WARN("out of memory\n");
1175         *ppdsb = NULL;
1176         return DSERR_OUTOFMEMORY;
1177     }
1178
1179     CopyMemory(dsb, pdsb, sizeof(IDirectSoundBufferImpl));
1180
1181     if (pdsb->hwbuf) {
1182         TRACE("duplicating hardware buffer\n");
1183
1184         hres = IDsDriver_DuplicateSoundBuffer(device->driver, pdsb->hwbuf,
1185                                               (LPVOID *)&dsb->hwbuf);
1186         if (hres != DS_OK) {
1187             TRACE("IDsDriver_DuplicateSoundBuffer failed, falling back to "
1188                   "software buffer\n");
1189             dsb->hwbuf = NULL;
1190             /* allocate buffer */
1191             if (device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) {
1192                 dsb->buffer = HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb->buffer)));
1193                 if (dsb->buffer == NULL) {
1194                     WARN("out of memory\n");
1195                     HeapFree(GetProcessHeap(),0,dsb);
1196                     *ppdsb = NULL;
1197                     return DSERR_OUTOFMEMORY;
1198                 }
1199
1200                 dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen);
1201                 if (dsb->buffer->memory == NULL) {
1202                     WARN("out of memory\n");
1203                     HeapFree(GetProcessHeap(),0,dsb->buffer);
1204                     HeapFree(GetProcessHeap(),0,dsb);
1205                     *ppdsb = NULL;
1206                     return DSERR_OUTOFMEMORY;
1207                 }
1208                 dsb->buffer->ref = 1;
1209
1210                 /* FIXME: copy buffer ? */
1211             }
1212         }
1213     } else {
1214         dsb->hwbuf = NULL;
1215         dsb->buffer->ref++;
1216     }
1217
1218     dsb->ref = 0;
1219     dsb->state = STATE_STOPPED;
1220     dsb->buf_mixpos = 0;
1221     dsb->device = device;
1222     dsb->ds3db = NULL;
1223     dsb->iks = NULL; /* FIXME? */
1224     dsb->secondary = NULL;
1225
1226     /* variable sized struct so calculate size based on format */
1227     size = sizeof(WAVEFORMATEX) + pdsb->pwfx->cbSize;
1228
1229     dsb->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
1230     if (dsb->pwfx == NULL) {
1231             WARN("out of memory\n");
1232             HeapFree(GetProcessHeap(),0,dsb->buffer);
1233             HeapFree(GetProcessHeap(),0,dsb);
1234             *ppdsb = NULL;
1235             return DSERR_OUTOFMEMORY;
1236     }
1237
1238     CopyMemory(dsb->pwfx, pdsb->pwfx, size);
1239
1240     InitializeCriticalSection(&(dsb->lock));
1241     dsb->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectSoundBufferImpl.lock");
1242
1243     /* register buffer */
1244     hres = DirectSoundDevice_AddBuffer(device, dsb);
1245     if (hres != DS_OK) {
1246         dsb->lock.DebugInfo->Spare[0] = 0;
1247         DeleteCriticalSection(&(dsb->lock));
1248         HeapFree(GetProcessHeap(),0,dsb->buffer);
1249         HeapFree(GetProcessHeap(),0,dsb->pwfx);
1250         HeapFree(GetProcessHeap(),0,dsb);
1251         *ppdsb = 0;
1252     }
1253
1254     *ppdsb = dsb;
1255     return hres;
1256 }
1257
1258 /*******************************************************************************
1259  *              SecondaryBuffer
1260  */
1261
1262 static HRESULT WINAPI SecondaryBufferImpl_QueryInterface(
1263         LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj)
1264 {
1265         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1266         TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
1267
1268         return IDirectSoundBufferImpl_QueryInterface((LPDIRECTSOUNDBUFFER8)This->dsb,riid,ppobj);
1269 }
1270
1271 static ULONG WINAPI SecondaryBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface)
1272 {
1273     SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1274     ULONG ref = InterlockedIncrement(&(This->ref));
1275     TRACE("(%p) ref was %d\n", This, ref - 1);
1276     return ref;
1277 }
1278
1279 static ULONG WINAPI SecondaryBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface)
1280 {
1281     SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1282     ULONG ref;
1283     TRACE("(%p)\n", This);
1284     ref = InterlockedDecrement(&(This->ref));
1285     TRACE("ref was %d\n", ref + 1);
1286
1287     if (!ref) {
1288         This->dsb->secondary = NULL;
1289         IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER8)This->dsb);
1290         HeapFree(GetProcessHeap(), 0, This);
1291         TRACE("(%p) released\n", This);
1292     }
1293     return ref;
1294 }
1295
1296 static HRESULT WINAPI SecondaryBufferImpl_GetCaps(
1297         LPDIRECTSOUNDBUFFER8 iface,LPDSBCAPS caps)
1298 {
1299         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1300         TRACE("(%p)->(%p)\n",This,caps);
1301
1302         return IDirectSoundBufferImpl_GetCaps((LPDIRECTSOUNDBUFFER8)This->dsb,caps);
1303 }
1304
1305 static HRESULT WINAPI SecondaryBufferImpl_GetCurrentPosition(
1306         LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos)
1307 {
1308         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1309         TRACE("(%p,%p,%p)\n",This,playpos,writepos);
1310
1311         return IDirectSoundBufferImpl_GetCurrentPosition((LPDIRECTSOUNDBUFFER8)This->dsb,playpos,writepos);
1312 }
1313
1314 static HRESULT WINAPI SecondaryBufferImpl_GetFormat(
1315         LPDIRECTSOUNDBUFFER8 iface,LPWAVEFORMATEX lpwf,DWORD wfsize,LPDWORD wfwritten)
1316 {
1317         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1318         TRACE("(%p,%p,%d,%p)\n",This,lpwf,wfsize,wfwritten);
1319
1320         return IDirectSoundBufferImpl_GetFormat((LPDIRECTSOUNDBUFFER8)This->dsb,lpwf,wfsize,wfwritten);
1321 }
1322
1323 static HRESULT WINAPI SecondaryBufferImpl_GetVolume(
1324         LPDIRECTSOUNDBUFFER8 iface,LPLONG vol)
1325 {
1326         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1327         TRACE("(%p,%p)\n",This,vol);
1328
1329         return IDirectSoundBufferImpl_GetVolume((LPDIRECTSOUNDBUFFER8)This->dsb,vol);
1330 }
1331
1332 static HRESULT WINAPI SecondaryBufferImpl_GetPan(
1333         LPDIRECTSOUNDBUFFER8 iface,LPLONG pan)
1334 {
1335         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1336         TRACE("(%p,%p)\n",This,pan);
1337
1338         return IDirectSoundBufferImpl_GetPan((LPDIRECTSOUNDBUFFER8)This->dsb,pan);
1339 }
1340
1341 static HRESULT WINAPI SecondaryBufferImpl_GetFrequency(
1342         LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq)
1343 {
1344         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1345         TRACE("(%p,%p)\n",This,freq);
1346
1347         return IDirectSoundBufferImpl_GetFrequency((LPDIRECTSOUNDBUFFER8)This->dsb,freq);
1348 }
1349
1350 static HRESULT WINAPI SecondaryBufferImpl_GetStatus(
1351         LPDIRECTSOUNDBUFFER8 iface,LPDWORD status)
1352 {
1353         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1354         TRACE("(%p,%p)\n",This,status);
1355
1356         return IDirectSoundBufferImpl_GetStatus((LPDIRECTSOUNDBUFFER8)This->dsb,status);
1357 }
1358
1359 static HRESULT WINAPI SecondaryBufferImpl_Initialize(
1360         LPDIRECTSOUNDBUFFER8 iface,LPDIRECTSOUND dsound,LPCDSBUFFERDESC dbsd)
1361 {
1362         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1363         TRACE("(%p,%p,%p)\n",This,dsound,dbsd);
1364
1365         return IDirectSoundBufferImpl_Initialize((LPDIRECTSOUNDBUFFER8)This->dsb,dsound,dbsd);
1366 }
1367
1368 static HRESULT WINAPI SecondaryBufferImpl_Lock(
1369     LPDIRECTSOUNDBUFFER8 iface,
1370     DWORD writecursor,
1371     DWORD writebytes,
1372     LPVOID *lplpaudioptr1,
1373     LPDWORD audiobytes1,
1374     LPVOID *lplpaudioptr2,
1375     LPDWORD audiobytes2,
1376     DWORD dwFlags)
1377 {
1378     SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1379     TRACE("(%p,%d,%d,%p,%p,%p,%p,0x%08x)\n",
1380         This,writecursor,writebytes,lplpaudioptr1,audiobytes1,lplpaudioptr2,audiobytes2,dwFlags);
1381
1382     return IDirectSoundBufferImpl_Lock((LPDIRECTSOUNDBUFFER8)This->dsb,
1383         writecursor,writebytes,lplpaudioptr1,audiobytes1,lplpaudioptr2,audiobytes2,dwFlags);
1384 }
1385
1386 static HRESULT WINAPI SecondaryBufferImpl_Play(
1387         LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags)
1388 {
1389         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1390         TRACE("(%p,%08x,%08x,%08x)\n",This,reserved1,reserved2,flags);
1391
1392         return IDirectSoundBufferImpl_Play((LPDIRECTSOUNDBUFFER8)This->dsb,reserved1,reserved2,flags);
1393 }
1394
1395 static HRESULT WINAPI SecondaryBufferImpl_SetCurrentPosition(
1396         LPDIRECTSOUNDBUFFER8 iface,DWORD newpos)
1397 {
1398         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1399         TRACE("(%p,%d)\n",This,newpos);
1400
1401         return IDirectSoundBufferImpl_SetCurrentPosition((LPDIRECTSOUNDBUFFER8)This->dsb,newpos);
1402 }
1403
1404 static HRESULT WINAPI SecondaryBufferImpl_SetFormat(
1405         LPDIRECTSOUNDBUFFER8 iface,LPCWAVEFORMATEX wfex)
1406 {
1407         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1408         TRACE("(%p,%p)\n",This,wfex);
1409
1410         return IDirectSoundBufferImpl_SetFormat((LPDIRECTSOUNDBUFFER8)This->dsb,wfex);
1411 }
1412
1413 static HRESULT WINAPI SecondaryBufferImpl_SetVolume(
1414         LPDIRECTSOUNDBUFFER8 iface,LONG vol)
1415 {
1416         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1417         TRACE("(%p,%d)\n",This,vol);
1418
1419         return IDirectSoundBufferImpl_SetVolume((LPDIRECTSOUNDBUFFER8)This->dsb,vol);
1420 }
1421
1422 static HRESULT WINAPI SecondaryBufferImpl_SetPan(
1423         LPDIRECTSOUNDBUFFER8 iface,LONG pan)
1424 {
1425         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1426         TRACE("(%p,%d)\n",This,pan);
1427
1428         return IDirectSoundBufferImpl_SetPan((LPDIRECTSOUNDBUFFER8)This->dsb,pan);
1429 }
1430
1431 static HRESULT WINAPI SecondaryBufferImpl_SetFrequency(
1432         LPDIRECTSOUNDBUFFER8 iface,DWORD freq)
1433 {
1434         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1435         TRACE("(%p,%d)\n",This,freq);
1436
1437         return IDirectSoundBufferImpl_SetFrequency((LPDIRECTSOUNDBUFFER8)This->dsb,freq);
1438 }
1439
1440 static HRESULT WINAPI SecondaryBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface)
1441 {
1442         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1443         TRACE("(%p)\n",This);
1444
1445         return IDirectSoundBufferImpl_Stop((LPDIRECTSOUNDBUFFER8)This->dsb);
1446 }
1447
1448 static HRESULT WINAPI SecondaryBufferImpl_Unlock(
1449     LPDIRECTSOUNDBUFFER8 iface,
1450     LPVOID lpvAudioPtr1,
1451     DWORD dwAudioBytes1,
1452     LPVOID lpvAudioPtr2,
1453     DWORD dwAudioBytes2)
1454 {
1455     SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1456     TRACE("(%p,%p,%d,%p,%d)\n",
1457         This, lpvAudioPtr1, dwAudioBytes1, lpvAudioPtr2, dwAudioBytes2);
1458
1459     return IDirectSoundBufferImpl_Unlock((LPDIRECTSOUNDBUFFER8)This->dsb,
1460         lpvAudioPtr1,dwAudioBytes1,lpvAudioPtr2,dwAudioBytes2);
1461 }
1462
1463 static HRESULT WINAPI SecondaryBufferImpl_Restore(
1464         LPDIRECTSOUNDBUFFER8 iface)
1465 {
1466         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1467         TRACE("(%p)\n",This);
1468
1469         return IDirectSoundBufferImpl_Restore((LPDIRECTSOUNDBUFFER8)This->dsb);
1470 }
1471
1472 static HRESULT WINAPI SecondaryBufferImpl_SetFX(
1473         LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes)
1474 {
1475         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1476         TRACE("(%p,%u,%p,%p)\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
1477
1478         return IDirectSoundBufferImpl_SetFX((LPDIRECTSOUNDBUFFER8)This->dsb,dwEffectsCount,pDSFXDesc,pdwResultCodes);
1479 }
1480
1481 static HRESULT WINAPI SecondaryBufferImpl_AcquireResources(
1482         LPDIRECTSOUNDBUFFER8 iface,DWORD dwFlags,DWORD dwEffectsCount,LPDWORD pdwResultCodes)
1483 {
1484         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1485         TRACE("(%p,%08u,%u,%p)\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
1486
1487         return IDirectSoundBufferImpl_AcquireResources((LPDIRECTSOUNDBUFFER8)This->dsb,dwFlags,dwEffectsCount,pdwResultCodes);
1488 }
1489
1490 static HRESULT WINAPI SecondaryBufferImpl_GetObjectInPath(
1491         LPDIRECTSOUNDBUFFER8 iface,REFGUID rguidObject,DWORD dwIndex,REFGUID rguidInterface,LPVOID* ppObject)
1492 {
1493         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1494         TRACE("(%p,%s,%u,%s,%p)\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
1495
1496         return IDirectSoundBufferImpl_GetObjectInPath((LPDIRECTSOUNDBUFFER8)This->dsb,rguidObject,dwIndex,rguidInterface,ppObject);
1497 }
1498
1499 static const IDirectSoundBuffer8Vtbl sbvt =
1500 {
1501         SecondaryBufferImpl_QueryInterface,
1502         SecondaryBufferImpl_AddRef,
1503         SecondaryBufferImpl_Release,
1504         SecondaryBufferImpl_GetCaps,
1505         SecondaryBufferImpl_GetCurrentPosition,
1506         SecondaryBufferImpl_GetFormat,
1507         SecondaryBufferImpl_GetVolume,
1508         SecondaryBufferImpl_GetPan,
1509         SecondaryBufferImpl_GetFrequency,
1510         SecondaryBufferImpl_GetStatus,
1511         SecondaryBufferImpl_Initialize,
1512         SecondaryBufferImpl_Lock,
1513         SecondaryBufferImpl_Play,
1514         SecondaryBufferImpl_SetCurrentPosition,
1515         SecondaryBufferImpl_SetFormat,
1516         SecondaryBufferImpl_SetVolume,
1517         SecondaryBufferImpl_SetPan,
1518         SecondaryBufferImpl_SetFrequency,
1519         SecondaryBufferImpl_Stop,
1520         SecondaryBufferImpl_Unlock,
1521         SecondaryBufferImpl_Restore,
1522         SecondaryBufferImpl_SetFX,
1523         SecondaryBufferImpl_AcquireResources,
1524         SecondaryBufferImpl_GetObjectInPath
1525 };
1526
1527 HRESULT SecondaryBufferImpl_Create(
1528         IDirectSoundBufferImpl *dsb,
1529         SecondaryBufferImpl **psb)
1530 {
1531         SecondaryBufferImpl *sb;
1532         TRACE("(%p,%p)\n",dsb,psb);
1533
1534         sb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*sb));
1535
1536         if (sb == 0) {
1537                 WARN("out of memory\n");
1538                 *psb = NULL;
1539                 return DSERR_OUTOFMEMORY;
1540         }
1541         sb->ref = 0;
1542         sb->dsb = dsb;
1543         sb->lpVtbl = &sbvt;
1544
1545         IDirectSoundBuffer8_AddRef((LPDIRECTSOUNDBUFFER8)dsb);
1546         *psb = sb;
1547         return S_OK;
1548 }
1549
1550 static HRESULT SecondaryBufferImpl_Destroy(
1551     SecondaryBufferImpl *pdsb)
1552 {
1553     TRACE("(%p)\n",pdsb);
1554
1555     while (SecondaryBufferImpl_Release((LPDIRECTSOUNDBUFFER8)pdsb) > 0);
1556
1557     return S_OK;
1558 }