3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998 Rob Riggs
5 * Copyright 2000-2002 TransGaming Technologies, Inc.
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include <sys/types.h>
26 #include <sys/fcntl.h>
32 #include <math.h> /* Insomnia - pow() function */
42 #include "wine/windef16.h"
43 #include "wine/debug.h"
46 #include "dsound_private.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
50 /*******************************************************************************
53 static HRESULT WINAPI IDirectSoundNotifyImpl_QueryInterface(
54 LPDIRECTSOUNDNOTIFY iface,REFIID riid,LPVOID *ppobj
56 ICOM_THIS(IDirectSoundNotifyImpl,iface);
57 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
59 if ( IsEqualGUID(riid, &IID_IUnknown) ||
60 IsEqualGUID(riid, &IID_IDirectSoundNotify) ||
61 IsEqualGUID(riid, &IID_IDirectSoundNotify8) ) {
62 IDirectSoundNotify_AddRef(iface);
67 FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
74 static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface) {
75 ICOM_THIS(IDirectSoundNotifyImpl,iface);
78 TRACE("(%p) ref was %ld\n", This, This->ref);
80 ref = InterlockedIncrement(&(This->ref));
84 static ULONG WINAPI IDirectSoundNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface) {
85 ICOM_THIS(IDirectSoundNotifyImpl,iface);
88 TRACE("(%p) ref was %ld\n", This, This->ref);
90 ref = InterlockedDecrement(&(This->ref));
91 /* FIXME: A notification should be a part of a buffer rather than pointed
92 * to from a buffer. Hence the -1 ref count */
94 if (This->notifies != NULL)
95 HeapFree(GetProcessHeap(), 0, This->notifies);
97 HeapFree(GetProcessHeap(),0,This);
103 static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(
104 LPDIRECTSOUNDNOTIFY iface,DWORD howmuch,LPCDSBPOSITIONNOTIFY notify
106 ICOM_THIS(IDirectSoundNotifyImpl,iface);
107 TRACE("(%p,0x%08lx,%p)\n",This,howmuch,notify);
110 WARN("invalid parameter\n");
111 return DSERR_INVALIDPARAM;
114 if (TRACE_ON(dsound)) {
116 for (i=0;i<howmuch;i++)
117 TRACE("notify at %ld to 0x%08lx\n",
118 notify[i].dwOffset,(DWORD)notify[i].hEventNotify);
121 if (This->hwnotify) {
122 return IDsDriverNotify_SetNotificationPositions(This->hwnotify, howmuch, notify);
125 /* Make an internal copy of the caller-supplied array.
126 * Replace the existing copy if one is already present. */
127 This->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
128 This->notifies, howmuch * sizeof(DSBPOSITIONNOTIFY));
129 memcpy(This->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
130 This->nrofnotifies = howmuch;
136 ICOM_VTABLE(IDirectSoundNotify) dsnvt =
138 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
139 IDirectSoundNotifyImpl_QueryInterface,
140 IDirectSoundNotifyImpl_AddRef,
141 IDirectSoundNotifyImpl_Release,
142 IDirectSoundNotifyImpl_SetNotificationPositions,
145 /*******************************************************************************
149 static HRESULT WINAPI IDirectSoundBufferImpl_SetFormat(
150 LPDIRECTSOUNDBUFFER8 iface,LPWAVEFORMATEX wfex
152 ICOM_THIS(IDirectSoundBufferImpl,iface);
154 TRACE("(%p,%p)\n",This,wfex);
155 /* This method is not available on secondary buffers */
156 return DSERR_INVALIDCALL;
159 static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume(
160 LPDIRECTSOUNDBUFFER8 iface,LONG vol
162 ICOM_THIS(IDirectSoundBufferImpl,iface);
165 TRACE("(%p,%ld)\n",This,vol);
167 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME))
168 return DSERR_CONTROLUNAVAIL;
170 if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN))
171 return DSERR_INVALIDPARAM;
174 EnterCriticalSection(&(This->lock));
176 if (This->dsbd.dwFlags & DSBCAPS_CTRL3D) {
177 oldVol = This->ds3db->lVolume;
178 This->ds3db->lVolume = vol;
180 oldVol = This->volpan.lVolume;
181 This->volpan.lVolume = vol;
182 if (vol != oldVol) DSOUND_RecalcVolPan(&(This->volpan));
187 IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
189 else DSOUND_ForceRemix(This);
192 LeaveCriticalSection(&(This->lock));
198 static HRESULT WINAPI IDirectSoundBufferImpl_GetVolume(
199 LPDIRECTSOUNDBUFFER8 iface,LPLONG vol
201 ICOM_THIS(IDirectSoundBufferImpl,iface);
202 TRACE("(%p,%p)\n",This,vol);
205 return DSERR_INVALIDPARAM;
207 if (This->dsbd.dwFlags & DSBCAPS_CTRL3D)
208 *vol = This->ds3db->lVolume;
210 *vol = This->volpan.lVolume;
214 static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency(
215 LPDIRECTSOUNDBUFFER8 iface,DWORD freq
217 ICOM_THIS(IDirectSoundBufferImpl,iface);
220 TRACE("(%p,%ld)\n",This,freq);
222 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLFREQUENCY))
223 return DSERR_CONTROLUNAVAIL;
225 if (freq == DSBFREQUENCY_ORIGINAL)
226 freq = This->wfx.nSamplesPerSec;
228 if ((freq < DSBFREQUENCY_MIN) || (freq > DSBFREQUENCY_MAX))
229 return DSERR_INVALIDPARAM;
232 EnterCriticalSection(&(This->lock));
234 oldFreq = This->freq;
236 if (freq != oldFreq) {
237 This->freqAdjust = (freq << DSOUND_FREQSHIFT) / This->dsound->wfx.nSamplesPerSec;
238 This->nAvgBytesPerSec = freq * This->wfx.nBlockAlign;
239 DSOUND_RecalcFormat(This);
240 if (!This->hwbuf) DSOUND_ForceRemix(This);
243 LeaveCriticalSection(&(This->lock));
249 static HRESULT WINAPI IDirectSoundBufferImpl_Play(
250 LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags
252 ICOM_THIS(IDirectSoundBufferImpl,iface);
253 TRACE("(%p,%08lx,%08lx,%08lx)\n",
254 This,reserved1,reserved2,flags
258 EnterCriticalSection(&(This->lock));
260 This->playflags = flags;
261 if (This->state == STATE_STOPPED) {
263 This->startpos = This->buf_mixpos;
264 This->state = STATE_STARTING;
265 } else if (This->state == STATE_STOPPING)
266 This->state = STATE_PLAYING;
268 IDsDriverBuffer_Play(This->hwbuf, 0, 0, This->playflags);
269 This->state = STATE_PLAYING;
272 LeaveCriticalSection(&(This->lock));
278 static HRESULT WINAPI IDirectSoundBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface)
280 ICOM_THIS(IDirectSoundBufferImpl,iface);
281 TRACE("(%p)\n",This);
284 EnterCriticalSection(&(This->lock));
286 if (This->state == STATE_PLAYING)
287 This->state = STATE_STOPPING;
288 else if (This->state == STATE_STARTING)
289 This->state = STATE_STOPPED;
291 IDsDriverBuffer_Stop(This->hwbuf);
292 This->state = STATE_STOPPED;
294 DSOUND_CheckEvent(This, 0);
296 LeaveCriticalSection(&(This->lock));
302 static DWORD WINAPI IDirectSoundBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface) {
303 ICOM_THIS(IDirectSoundBufferImpl,iface);
306 TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
308 ref = InterlockedIncrement(&(This->ref));
310 FIXME("thread-safety alert! AddRef-ing with a zero refcount!\n");
314 static DWORD WINAPI IDirectSoundBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface) {
315 ICOM_THIS(IDirectSoundBufferImpl,iface);
319 TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
321 ref = InterlockedDecrement(&(This->ref));
324 RtlAcquireResourceExclusive(&(This->dsound->lock), TRUE);
325 for (i=0;i<This->dsound->nrofbuffers;i++)
326 if (This->dsound->buffers[i] == This)
329 if (i < This->dsound->nrofbuffers) {
330 /* Put the last buffer of the list in the (now empty) position */
331 This->dsound->buffers[i] = This->dsound->buffers[This->dsound->nrofbuffers - 1];
332 This->dsound->nrofbuffers--;
333 This->dsound->buffers = HeapReAlloc(GetProcessHeap(),0,This->dsound->buffers,sizeof(LPDIRECTSOUNDBUFFER8)*This->dsound->nrofbuffers);
334 TRACE("buffer count is now %d\n", This->dsound->nrofbuffers);
335 IDirectSound_Release((LPDIRECTSOUND)This->dsound);
337 RtlReleaseResource(&(This->dsound->lock));
339 DeleteCriticalSection(&(This->lock));
341 IDsDriverBuffer_Release(This->hwbuf);
342 if (This->dsound->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY)
343 HeapFree(GetProcessHeap(),0,This->buffer);
345 else if (!This->parent)
346 HeapFree(GetProcessHeap(),0,This->buffer);
348 DeleteCriticalSection(&This->ds3db->lock);
349 HeapFree(GetProcessHeap(), 0, This->ds3db);
352 HeapFree(GetProcessHeap(), 0, This->iks);
355 IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)This->parent);
357 HeapFree(GetProcessHeap(),0,This);
362 DWORD DSOUND_CalcPlayPosition(IDirectSoundBufferImpl *This,
363 DWORD state, DWORD pplay, DWORD pwrite, DWORD pmix, DWORD bmix)
367 TRACE("primary playpos=%ld, mixpos=%ld\n", pplay, pmix);
368 TRACE("this mixpos=%ld, time=%ld\n", bmix, GetTickCount());
370 /* the actual primary play position (pplay) is always behind last mixed (pmix),
371 * unless the computer is too slow or something */
372 /* we need to know how far away we are from there */
373 #if 0 /* we'll never fill the primary entirely */
375 if ((state == STATE_PLAYING) || (state == STATE_STOPPING)) {
376 /* wow, the software mixer is really doing well,
377 * seems the entire primary buffer is filled! */
378 pmix += This->dsound->buflen;
380 /* else: the primary buffer is not playing, so probably empty */
383 if (pmix < pplay) pmix += This->dsound->buflen; /* wraparound */
385 /* detect buffer underrun */
386 if (pwrite < pplay) pwrite += This->dsound->buflen; /* wraparound */
388 if (pmix > (ds_snd_queue_max * This->dsound->fraglen + pwrite + This->dsound->writelead)) {
389 WARN("detected an underrun: primary queue was %ld\n",pmix);
392 /* divide the offset by its sample size */
393 pmix /= This->dsound->wfx.nBlockAlign;
394 TRACE("primary back-samples=%ld\n",pmix);
395 /* adjust for our frequency */
396 pmix = (pmix * This->freqAdjust) >> DSOUND_FREQSHIFT;
397 /* multiply by our own sample size */
398 pmix *= This->wfx.nBlockAlign;
399 TRACE("this back-offset=%ld\n", pmix);
400 /* subtract from our last mixed position */
402 while (bplay < pmix) bplay += This->buflen; /* wraparound */
404 if (This->leadin && ((bplay < This->startpos) || (bplay > bmix))) {
405 /* seems we haven't started playing yet */
406 TRACE("this still in lead-in phase\n");
407 bplay = This->startpos;
409 /* return the result */
413 static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(
414 LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos
417 ICOM_THIS(IDirectSoundBufferImpl,iface);
418 TRACE("(%p,%p,%p)\n",This,playpos,writepos);
420 hres=IDsDriverBuffer_GetPosition(This->hwbuf,playpos,writepos);
425 if (playpos && (This->state != STATE_PLAYING)) {
426 /* we haven't been merged into the primary buffer (yet) */
427 *playpos = This->buf_mixpos;
430 DWORD pplay, pwrite, lplay, splay, pstate;
431 /* let's get this exact; first, recursively call GetPosition on the primary */
432 EnterCriticalSection(&(This->dsound->mixlock));
433 DSOUND_PrimaryGetPosition(This->dsound, &pplay, &pwrite);
434 /* detect HEL mode underrun */
435 pstate = This->dsound->state;
436 if (!(This->dsound->hwbuf || This->dsound->pwqueue)) {
437 TRACE("detected an underrun\n");
439 if (pstate == STATE_PLAYING)
440 pstate = STATE_STARTING;
441 else if (pstate == STATE_STOPPING)
442 pstate = STATE_STOPPED;
444 /* get data for ourselves while we still have the lock */
445 pstate &= This->state;
446 lplay = This->primary_mixpos;
447 splay = This->buf_mixpos;
448 if ((This->dsbd.dwFlags & DSBCAPS_GETCURRENTPOSITION2) || This->dsound->hwbuf) {
449 /* calculate play position using this */
450 *playpos = DSOUND_CalcPlayPosition(This, pstate, pplay, pwrite, lplay, splay);
452 /* (unless the app isn't using GETCURRENTPOSITION2) */
453 /* don't know exactly how this should be handled...
454 * the docs says that play cursor is reported as directly
455 * behind write cursor, hmm... */
456 /* let's just do what might work for Half-Life */
458 wp = (This->dsound->pwplay + ds_hel_margin) * This->dsound->fraglen;
459 while (wp >= This->dsound->buflen)
460 wp -= This->dsound->buflen;
461 *playpos = DSOUND_CalcPlayPosition(This, pstate, wp, pwrite, lplay, splay);
463 LeaveCriticalSection(&(This->dsound->mixlock));
465 if (writepos) *writepos = This->buf_mixpos;
468 if (This->state != STATE_STOPPED)
469 /* apply the documented 10ms lead to writepos */
470 *writepos += This->writelead;
471 while (*writepos >= This->buflen) *writepos -= This->buflen;
473 if (playpos) This->last_playpos = *playpos;
474 TRACE("playpos = %ld, writepos = %ld (%p, time=%ld)\n", playpos?*playpos:0, writepos?*writepos:0, This, GetTickCount());
478 static HRESULT WINAPI IDirectSoundBufferImpl_GetStatus(
479 LPDIRECTSOUNDBUFFER8 iface,LPDWORD status
481 ICOM_THIS(IDirectSoundBufferImpl,iface);
482 TRACE("(%p,%p), thread is %04lx\n",This,status,GetCurrentThreadId());
485 return DSERR_INVALIDPARAM;
488 if ((This->state == STATE_STARTING) || (This->state == STATE_PLAYING)) {
489 *status |= DSBSTATUS_PLAYING;
490 if (This->playflags & DSBPLAY_LOOPING)
491 *status |= DSBSTATUS_LOOPING;
494 TRACE("status=%lx\n", *status);
499 static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat(
500 LPDIRECTSOUNDBUFFER8 iface,LPWAVEFORMATEX lpwf,DWORD wfsize,LPDWORD wfwritten
502 ICOM_THIS(IDirectSoundBufferImpl,iface);
503 TRACE("(%p,%p,%ld,%p)\n",This,lpwf,wfsize,wfwritten);
505 if (wfsize>sizeof(This->wfx))
506 wfsize = sizeof(This->wfx);
507 if (lpwf) { /* NULL is valid */
508 memcpy(lpwf,&(This->wfx),wfsize);
513 *wfwritten = sizeof(This->wfx);
515 return DSERR_INVALIDPARAM;
520 static HRESULT WINAPI IDirectSoundBufferImpl_Lock(
521 LPDIRECTSOUNDBUFFER8 iface,DWORD writecursor,DWORD writebytes,LPVOID lplpaudioptr1,LPDWORD audiobytes1,LPVOID lplpaudioptr2,LPDWORD audiobytes2,DWORD flags
523 ICOM_THIS(IDirectSoundBufferImpl,iface);
525 TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx) at %ld\n",
537 if (flags & DSBLOCK_FROMWRITECURSOR) {
539 /* GetCurrentPosition does too much magic to duplicate here */
540 IDirectSoundBufferImpl_GetCurrentPosition(iface, NULL, &writepos);
541 writecursor += writepos;
543 while (writecursor >= This->buflen)
544 writecursor -= This->buflen;
545 if (flags & DSBLOCK_ENTIREBUFFER)
546 writebytes = This->buflen;
547 if (writebytes > This->buflen)
548 writebytes = This->buflen;
550 assert(audiobytes1!=audiobytes2);
551 assert(lplpaudioptr1!=lplpaudioptr2);
553 EnterCriticalSection(&(This->lock));
555 if ((writebytes == This->buflen) &&
556 ((This->state == STATE_STARTING) ||
557 (This->state == STATE_PLAYING)))
558 /* some games, like Half-Life, try to be clever (not) and
559 * keep one secondary buffer, and mix sounds into it itself,
560 * locking the entire buffer every time... so we can just forget
561 * about tracking the last-written-to-position... */
562 This->probably_valid_to = (DWORD)-1;
564 This->probably_valid_to = writecursor;
566 if (!(This->dsound->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
567 IDsDriverBuffer_Lock(This->hwbuf,
568 lplpaudioptr1, audiobytes1,
569 lplpaudioptr2, audiobytes2,
570 writecursor, writebytes,
575 if (writecursor+writebytes <= This->buflen) {
576 *(LPBYTE*)lplpaudioptr1 = This->buffer+writecursor;
577 *audiobytes1 = writebytes;
579 *(LPBYTE*)lplpaudioptr2 = NULL;
582 TRACE("->%ld.0\n",writebytes);
584 *(LPBYTE*)lplpaudioptr1 = This->buffer+writecursor;
585 *audiobytes1 = This->buflen-writecursor;
587 *(LPBYTE*)lplpaudioptr2 = This->buffer;
589 *audiobytes2 = writebytes-(This->buflen-writecursor);
590 TRACE("->%ld.%ld\n",*audiobytes1,audiobytes2?*audiobytes2:0);
592 if (This->state == STATE_PLAYING) {
593 /* if the segment between playpos and buf_mixpos is touched,
594 * we need to cancel some mixing */
595 /* we'll assume that the app always calls GetCurrentPosition before
596 * locking a playing buffer, so that last_playpos is up-to-date */
597 if (This->buf_mixpos >= This->last_playpos) {
598 if (This->buf_mixpos > writecursor &&
599 This->last_playpos < writecursor+writebytes)
603 if (This->buf_mixpos > writecursor ||
604 This->last_playpos < writecursor+writebytes)
608 TRACE("locking prebuffered region, ouch\n");
609 DSOUND_MixCancelAt(This, writecursor);
614 LeaveCriticalSection(&(This->lock));
618 static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(
619 LPDIRECTSOUNDBUFFER8 iface,DWORD newpos
621 ICOM_THIS(IDirectSoundBufferImpl,iface);
622 TRACE("(%p,%ld)\n",This,newpos);
625 EnterCriticalSection(&(This->lock));
627 while (newpos >= This->buflen)
628 newpos -= This->buflen;
629 This->buf_mixpos = newpos;
631 IDsDriverBuffer_SetPosition(This->hwbuf, This->buf_mixpos);
633 LeaveCriticalSection(&(This->lock));
639 static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(
640 LPDIRECTSOUNDBUFFER8 iface,LONG pan
642 ICOM_THIS(IDirectSoundBufferImpl,iface);
645 TRACE("(%p,%ld)\n",This,pan);
647 if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT))
648 return DSERR_INVALIDPARAM;
650 /* You cannot use both pan and 3D controls */
651 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
652 (This->dsbd.dwFlags & DSBCAPS_CTRL3D))
653 return DSERR_CONTROLUNAVAIL;
656 EnterCriticalSection(&(This->lock));
658 oldPan = This->volpan.lPan;
659 This->volpan.lPan = pan;
662 DSOUND_RecalcVolPan(&(This->volpan));
665 IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
667 else DSOUND_ForceRemix(This);
670 LeaveCriticalSection(&(This->lock));
676 static HRESULT WINAPI IDirectSoundBufferImpl_GetPan(
677 LPDIRECTSOUNDBUFFER8 iface,LPLONG pan
679 ICOM_THIS(IDirectSoundBufferImpl,iface);
680 TRACE("(%p,%p)\n",This,pan);
683 return DSERR_INVALIDPARAM;
685 *pan = This->volpan.lPan;
690 static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(
691 LPDIRECTSOUNDBUFFER8 iface,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2
693 ICOM_THIS(IDirectSoundBufferImpl,iface);
694 DWORD probably_valid_to;
696 TRACE("(%p,%p,%ld,%p,%ld)\n", This,p1,x1,p2,x2);
699 /* Preprocess 3D buffers... */
701 /* This is highly experimental and liable to break things */
702 if (This->dsbd.dwFlags & DSBCAPS_CTRL3D)
703 DSOUND_Create3DBuffer(This);
706 if (!(This->dsound->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
707 IDsDriverBuffer_Unlock(This->hwbuf, p1, x1, p2, x2);
710 if (p2) probably_valid_to = (((LPBYTE)p2)-This->buffer) + x2;
711 else probably_valid_to = (((LPBYTE)p1)-This->buffer) + x1;
712 while (probably_valid_to >= This->buflen)
713 probably_valid_to -= This->buflen;
714 if ((probably_valid_to == 0) && ((x1+x2) == This->buflen) &&
715 ((This->state == STATE_STARTING) ||
716 (This->state == STATE_PLAYING)))
717 /* see IDirectSoundBufferImpl_Lock */
718 probably_valid_to = (DWORD)-1;
719 This->probably_valid_to = probably_valid_to;
724 static HRESULT WINAPI IDirectSoundBufferImpl_Restore(
725 LPDIRECTSOUNDBUFFER8 iface
727 ICOM_THIS(IDirectSoundBufferImpl,iface);
728 FIXME("(%p):stub\n",This);
732 static HRESULT WINAPI IDirectSoundBufferImpl_GetFrequency(
733 LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq
735 ICOM_THIS(IDirectSoundBufferImpl,iface);
736 TRACE("(%p,%p)\n",This,freq);
739 return DSERR_INVALIDPARAM;
742 TRACE("-> %ld\n", *freq);
747 static HRESULT WINAPI IDirectSoundBufferImpl_SetFX(
748 LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes
750 ICOM_THIS(IDirectSoundBufferImpl,iface);
753 FIXME("(%p,%lu,%p,%p): stub\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
756 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
758 return DSERR_CONTROLUNAVAIL;
761 static HRESULT WINAPI IDirectSoundBufferImpl_AcquireResources(
762 LPDIRECTSOUNDBUFFER8 iface,DWORD dwFlags,DWORD dwEffectsCount,LPDWORD pdwResultCodes
764 ICOM_THIS(IDirectSoundBufferImpl,iface);
767 FIXME("(%p,%08lu,%lu,%p): stub\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
770 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
772 return DSERR_CONTROLUNAVAIL;
775 static HRESULT WINAPI IDirectSoundBufferImpl_GetObjectInPath(
776 LPDIRECTSOUNDBUFFER8 iface,REFGUID rguidObject,DWORD dwIndex,REFGUID rguidInterface,LPVOID* ppObject
778 ICOM_THIS(IDirectSoundBufferImpl,iface);
780 FIXME("(%p,%s,%lu,%s,%p): stub\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
782 return DSERR_CONTROLUNAVAIL;
785 static HRESULT WINAPI IDirectSoundBufferImpl_Initialize(
786 LPDIRECTSOUNDBUFFER8 iface,LPDIRECTSOUND8 dsound,LPDSBUFFERDESC dbsd
788 ICOM_THIS(IDirectSoundBufferImpl,iface);
789 FIXME("(%p,%p,%p):stub\n",This,dsound,dbsd);
790 DPRINTF("Re-Init!!!\n");
791 return DSERR_ALREADYINITIALIZED;
794 static HRESULT WINAPI IDirectSoundBufferImpl_GetCaps(
795 LPDIRECTSOUNDBUFFER8 iface,LPDSBCAPS caps
797 ICOM_THIS(IDirectSoundBufferImpl,iface);
798 TRACE("(%p)->(%p)\n",This,caps);
800 if (caps == NULL || caps->dwSize!=sizeof(*caps))
801 return DSERR_INVALIDPARAM;
803 caps->dwFlags = This->dsbd.dwFlags;
804 if (This->hwbuf) caps->dwFlags |= DSBCAPS_LOCHARDWARE;
805 else caps->dwFlags |= DSBCAPS_LOCSOFTWARE;
807 caps->dwBufferBytes = This->buflen;
809 /* This value represents the speed of the "unlock" command.
810 As unlock is quite fast (it does not do anything), I put
811 4096 ko/s = 4 Mo / s */
812 /* FIXME: hwbuf speed */
813 caps->dwUnlockTransferRate = 4096;
814 caps->dwPlayCpuOverhead = 0;
819 static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface(
820 LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj
822 ICOM_THIS(IDirectSoundBufferImpl,iface);
824 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
826 if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ||
827 IsEqualGUID( &IID_IDirectSoundNotify8, riid ) ) {
829 This->notify = (IDirectSoundNotifyImpl*)HeapAlloc(GetProcessHeap(),
830 HEAP_ZERO_MEMORY,sizeof(*This->notify));
832 This->notify->ref = 0; /* release when ref == -1 */
833 This->notify->lpVtbl = &dsnvt;
837 IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify);
838 *ppobj = (LPVOID)This->notify;
845 if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) {
847 IDirectSound3DBufferImpl_Create(This, &This->ds3db);
848 *ppobj = This->ds3db;
850 IDirectSound3DBuffer_AddRef((LPDIRECTSOUND3DBUFFER)*ppobj);
857 if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
858 ERR("app requested IDirectSound3DListener on secondary buffer\n");
863 if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) {
865 IKsPropertySetImpl_Create(This, &This->iks);
868 IKsPropertySet_AddRef((LPKSPROPERTYSET)*ppobj);
875 if ( IsEqualGUID( &IID_IDirectSoundBuffer8, riid ) ) {
876 IDirectSoundBuffer8_AddRef(iface);
881 FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
885 return E_NOINTERFACE;
888 static ICOM_VTABLE(IDirectSoundBuffer8) dsbvt =
890 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
891 IDirectSoundBufferImpl_QueryInterface,
892 IDirectSoundBufferImpl_AddRef,
893 IDirectSoundBufferImpl_Release,
894 IDirectSoundBufferImpl_GetCaps,
895 IDirectSoundBufferImpl_GetCurrentPosition,
896 IDirectSoundBufferImpl_GetFormat,
897 IDirectSoundBufferImpl_GetVolume,
898 IDirectSoundBufferImpl_GetPan,
899 IDirectSoundBufferImpl_GetFrequency,
900 IDirectSoundBufferImpl_GetStatus,
901 IDirectSoundBufferImpl_Initialize,
902 IDirectSoundBufferImpl_Lock,
903 IDirectSoundBufferImpl_Play,
904 IDirectSoundBufferImpl_SetCurrentPosition,
905 IDirectSoundBufferImpl_SetFormat,
906 IDirectSoundBufferImpl_SetVolume,
907 IDirectSoundBufferImpl_SetPan,
908 IDirectSoundBufferImpl_SetFrequency,
909 IDirectSoundBufferImpl_Stop,
910 IDirectSoundBufferImpl_Unlock,
911 IDirectSoundBufferImpl_Restore,
912 IDirectSoundBufferImpl_SetFX,
913 IDirectSoundBufferImpl_AcquireResources,
914 IDirectSoundBufferImpl_GetObjectInPath
917 HRESULT WINAPI SecondaryBuffer_Create(
918 IDirectSoundImpl *This,
919 IDirectSoundBufferImpl **pdsb,
922 IDirectSoundBufferImpl *dsb;
923 LPWAVEFORMATEX wfex = dsbd->lpwfxFormat;
928 if (dsbd->dwBufferBytes < DSBSIZE_MIN || dsbd->dwBufferBytes > DSBSIZE_MAX) {
929 ERR("invalid sound buffer size %ld\n", dsbd->dwBufferBytes);
930 return DSERR_INVALIDPARAM; /* FIXME: which error? */
933 dsb = (IDirectSoundBufferImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
937 dsb->lpVtbl = &dsbvt;
939 memcpy(&dsb->dsbd, dsbd, sizeof(*dsbd));
941 memcpy(&dsb->wfx, wfex, sizeof(dsb->wfx));
943 TRACE("Created buffer at %p\n", dsb);
945 dsb->buflen = dsbd->dwBufferBytes;
946 dsb->freq = dsbd->lpwfxFormat->nSamplesPerSec;
948 /* Check necessary hardware mixing capabilities */
949 if (wfex->nChannels==2) capf |= DSCAPS_SECONDARYSTEREO;
950 else capf |= DSCAPS_SECONDARYMONO;
951 if (wfex->wBitsPerSample==16) capf |= DSCAPS_SECONDARY16BIT;
952 else capf |= DSCAPS_SECONDARY8BIT;
953 use_hw = (This->drvcaps.dwFlags & capf) == capf;
955 /* FIXME: check hardware sample rate mixing capabilities */
956 /* FIXME: check app hints for software/hardware buffer (STATIC, LOCHARDWARE, etc) */
957 /* FIXME: check whether any hardware buffers are left */
958 /* FIXME: handle DSDHEAP_CREATEHEAP for hardware buffers */
960 /* Allocate system memory if applicable */
961 if ((This->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) || !use_hw) {
962 dsb->buffer = (LPBYTE)HeapAlloc(GetProcessHeap(),0,dsb->buflen);
963 if (dsb->buffer == NULL)
964 err = DSERR_OUTOFMEMORY;
967 /* Allocate the hardware buffer */
968 if (use_hw && (err == DS_OK)) {
969 err = IDsDriver_CreateSoundBuffer(This->driver,wfex,dsbd->dwFlags,0,
970 &(dsb->buflen),&(dsb->buffer),
971 (LPVOID*)&(dsb->hwbuf));
976 HeapFree(GetProcessHeap(),0,dsb->buffer);
977 HeapFree(GetProcessHeap(),0,dsb);
981 /* calculate fragment size and write lead */
982 DSOUND_RecalcFormat(dsb);
984 /* It's not necessary to initialize values to zero since */
985 /* we allocated this structure with HEAP_ZERO_MEMORY... */
988 dsb->state = STATE_STOPPED;
990 dsb->freqAdjust = (dsb->freq << DSOUND_FREQSHIFT) /
991 This->wfx.nSamplesPerSec;
992 dsb->nAvgBytesPerSec = dsb->freq *
993 dsbd->lpwfxFormat->nBlockAlign;
995 if (dsbd->dwFlags & DSBCAPS_CTRL3D) {
996 IDirectSound3DBufferImpl_Create(dsb, &dsb->ds3db);
999 DSOUND_RecalcVolPan(&(dsb->volpan));
1001 InitializeCriticalSection(&(dsb->lock));
1003 /* register buffer */
1004 RtlAcquireResourceExclusive(&(This->lock), TRUE);
1005 if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
1006 IDirectSoundBufferImpl **newbuffers = (IDirectSoundBufferImpl**)HeapReAlloc(GetProcessHeap(),0,This->buffers,sizeof(IDirectSoundBufferImpl*)*(This->nrofbuffers+1));
1008 This->buffers = newbuffers;
1009 This->buffers[This->nrofbuffers] = dsb;
1010 This->nrofbuffers++;
1011 TRACE("buffer count is now %d\n", This->nrofbuffers);
1013 ERR("out of memory for buffer list! Current buffer count is %d\n", This->nrofbuffers);
1014 err = DSERR_OUTOFMEMORY;
1017 RtlReleaseResource(&(This->lock));
1018 IDirectSound8_AddRef((LPDIRECTSOUND8)This);
1022 IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)dsb);