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);
109 if (notify == NULL) {
110 WARN("invalid parameter: notify == NULL\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) {
123 hres = IDsDriverNotify_SetNotificationPositions(This->hwnotify, howmuch, notify);
125 WARN("IDsDriverNotify_SetNotificationPositions failed\n");
128 /* Make an internal copy of the caller-supplied array.
129 * Replace the existing copy if one is already present. */
130 This->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
131 This->notifies, howmuch * sizeof(DSBPOSITIONNOTIFY));
132 if (This->notifies == NULL) {
133 WARN("out of memory\n");
134 return DSERR_OUTOFMEMORY;
136 memcpy(This->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
137 This->nrofnotifies = howmuch;
143 ICOM_VTABLE(IDirectSoundNotify) dsnvt =
145 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
146 IDirectSoundNotifyImpl_QueryInterface,
147 IDirectSoundNotifyImpl_AddRef,
148 IDirectSoundNotifyImpl_Release,
149 IDirectSoundNotifyImpl_SetNotificationPositions,
152 /*******************************************************************************
156 static HRESULT WINAPI IDirectSoundBufferImpl_SetFormat(
157 LPDIRECTSOUNDBUFFER8 iface,LPWAVEFORMATEX wfex
159 ICOM_THIS(IDirectSoundBufferImpl,iface);
161 TRACE("(%p,%p)\n",This,wfex);
162 /* This method is not available on secondary buffers */
163 WARN("invalid call\n");
164 return DSERR_INVALIDCALL;
167 static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume(
168 LPDIRECTSOUNDBUFFER8 iface,LONG vol
170 ICOM_THIS(IDirectSoundBufferImpl,iface);
173 TRACE("(%p,%ld)\n",This,vol);
175 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
176 WARN("control unavailable: This->dsbd.dwFlags = 0x%08lx\n", This->dsbd.dwFlags);
177 return DSERR_CONTROLUNAVAIL;
180 if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN)) {
181 WARN("invalid parameter: vol = %ld\n", vol);
182 return DSERR_INVALIDPARAM;
186 EnterCriticalSection(&(This->lock));
188 if (This->dsbd.dwFlags & DSBCAPS_CTRL3D) {
189 oldVol = This->ds3db->lVolume;
190 This->ds3db->lVolume = vol;
192 oldVol = This->volpan.lVolume;
193 This->volpan.lVolume = vol;
195 DSOUND_RecalcVolPan(&(This->volpan));
201 hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
203 WARN("IDsDriverBuffer_SetVolumePan failed\n");
205 DSOUND_ForceRemix(This);
208 LeaveCriticalSection(&(This->lock));
214 static HRESULT WINAPI IDirectSoundBufferImpl_GetVolume(
215 LPDIRECTSOUNDBUFFER8 iface,LPLONG vol
217 ICOM_THIS(IDirectSoundBufferImpl,iface);
218 TRACE("(%p,%p)\n",This,vol);
221 WARN("invalid parameter: vol == NULL\n");
222 return DSERR_INVALIDPARAM;
225 if (This->dsbd.dwFlags & DSBCAPS_CTRL3D)
226 *vol = This->ds3db->lVolume;
228 *vol = This->volpan.lVolume;
232 static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency(
233 LPDIRECTSOUNDBUFFER8 iface,DWORD freq
235 ICOM_THIS(IDirectSoundBufferImpl,iface);
238 TRACE("(%p,%ld)\n",This,freq);
240 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLFREQUENCY)) {
241 WARN("control unavailable\n");
242 return DSERR_CONTROLUNAVAIL;
245 if (freq == DSBFREQUENCY_ORIGINAL)
246 freq = This->wfx.nSamplesPerSec;
248 if ((freq < DSBFREQUENCY_MIN) || (freq > DSBFREQUENCY_MAX)) {
249 WARN("invalid parameter: freq = %ld\n", freq);
250 return DSERR_INVALIDPARAM;
254 EnterCriticalSection(&(This->lock));
256 oldFreq = This->freq;
258 if (freq != oldFreq) {
259 This->freqAdjust = (freq << DSOUND_FREQSHIFT) / This->dsound->wfx.nSamplesPerSec;
260 This->nAvgBytesPerSec = freq * This->wfx.nBlockAlign;
261 DSOUND_RecalcFormat(This);
263 DSOUND_ForceRemix(This);
266 LeaveCriticalSection(&(This->lock));
272 static HRESULT WINAPI IDirectSoundBufferImpl_Play(
273 LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags
275 HRESULT hres = DS_OK;
276 ICOM_THIS(IDirectSoundBufferImpl,iface);
277 TRACE("(%p,%08lx,%08lx,%08lx)\n",This,reserved1,reserved2,flags);
280 EnterCriticalSection(&(This->lock));
282 This->playflags = flags;
283 if (This->state == STATE_STOPPED) {
285 This->startpos = This->buf_mixpos;
286 This->state = STATE_STARTING;
287 } else if (This->state == STATE_STOPPING)
288 This->state = STATE_PLAYING;
290 hres = IDsDriverBuffer_Play(This->hwbuf, 0, 0, This->playflags);
292 WARN("IDsDriverBuffer_Play failed\n");
294 This->state = STATE_PLAYING;
297 LeaveCriticalSection(&(This->lock));
303 static HRESULT WINAPI IDirectSoundBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface)
305 HRESULT hres = DS_OK;
306 ICOM_THIS(IDirectSoundBufferImpl,iface);
307 TRACE("(%p)\n",This);
310 EnterCriticalSection(&(This->lock));
312 if (This->state == STATE_PLAYING)
313 This->state = STATE_STOPPING;
314 else if (This->state == STATE_STARTING)
315 This->state = STATE_STOPPED;
317 hres = IDsDriverBuffer_Stop(This->hwbuf);
319 WARN("IDsDriverBuffer_Stop failed\n");
321 This->state = STATE_STOPPED;
323 DSOUND_CheckEvent(This, 0);
325 LeaveCriticalSection(&(This->lock));
331 static DWORD WINAPI IDirectSoundBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface) {
332 ICOM_THIS(IDirectSoundBufferImpl,iface);
335 TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
337 ref = InterlockedIncrement(&(This->ref));
339 FIXME("thread-safety alert! AddRef-ing with a zero refcount!\n");
343 static DWORD WINAPI IDirectSoundBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface) {
344 ICOM_THIS(IDirectSoundBufferImpl,iface);
348 TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
350 ref = InterlockedDecrement(&(This->ref));
353 RtlAcquireResourceExclusive(&(This->dsound->lock), TRUE);
354 for (i=0;i<This->dsound->nrofbuffers;i++)
355 if (This->dsound->buffers[i] == This)
358 if (i < This->dsound->nrofbuffers) {
359 /* Put the last buffer of the list in the (now empty) position */
360 This->dsound->buffers[i] = This->dsound->buffers[This->dsound->nrofbuffers - 1];
361 This->dsound->nrofbuffers--;
362 This->dsound->buffers = HeapReAlloc(GetProcessHeap(),0,This->dsound->buffers,sizeof(LPDIRECTSOUNDBUFFER8)*This->dsound->nrofbuffers);
363 TRACE("buffer count is now %d\n", This->dsound->nrofbuffers);
364 IDirectSound_Release((LPDIRECTSOUND)This->dsound);
366 RtlReleaseResource(&(This->dsound->lock));
368 DeleteCriticalSection(&(This->lock));
370 IDsDriverBuffer_Release(This->hwbuf);
371 if (This->dsound->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY)
372 HeapFree(GetProcessHeap(),0,This->buffer);
374 else if (!This->parent)
375 HeapFree(GetProcessHeap(),0,This->buffer);
377 IDirectSound3DBuffer_Release((LPDIRECTSOUND3DBUFFER)This->ds3db);
379 if (This->dsound->listener) {
380 if (IDirectSound3DListener_Release((LPDIRECTSOUND3DLISTENER)This->dsound->listener) == 0)
381 This->dsound->listener = 0;
384 HeapFree(GetProcessHeap(), 0, This->iks);
387 IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)This->parent);
389 HeapFree(GetProcessHeap(),0,This);
394 DWORD DSOUND_CalcPlayPosition(IDirectSoundBufferImpl *This,
395 DWORD state, DWORD pplay, DWORD pwrite, DWORD pmix, DWORD bmix)
399 TRACE("primary playpos=%ld, mixpos=%ld\n", pplay, pmix);
400 TRACE("this mixpos=%ld, time=%ld\n", bmix, GetTickCount());
402 /* the actual primary play position (pplay) is always behind last mixed (pmix),
403 * unless the computer is too slow or something */
404 /* we need to know how far away we are from there */
405 #if 0 /* we'll never fill the primary entirely */
407 if ((state == STATE_PLAYING) || (state == STATE_STOPPING)) {
408 /* wow, the software mixer is really doing well,
409 * seems the entire primary buffer is filled! */
410 pmix += This->dsound->buflen;
412 /* else: the primary buffer is not playing, so probably empty */
415 if (pmix < pplay) pmix += This->dsound->buflen; /* wraparound */
417 /* detect buffer underrun */
418 if (pwrite < pplay) pwrite += This->dsound->buflen; /* wraparound */
420 if (pmix > (ds_snd_queue_max * This->dsound->fraglen + pwrite + This->dsound->writelead)) {
421 WARN("detected an underrun: primary queue was %ld\n",pmix);
424 /* divide the offset by its sample size */
425 pmix /= This->dsound->wfx.nBlockAlign;
426 TRACE("primary back-samples=%ld\n",pmix);
427 /* adjust for our frequency */
428 pmix = (pmix * This->freqAdjust) >> DSOUND_FREQSHIFT;
429 /* multiply by our own sample size */
430 pmix *= This->wfx.nBlockAlign;
431 TRACE("this back-offset=%ld\n", pmix);
432 /* subtract from our last mixed position */
434 while (bplay < pmix) bplay += This->buflen; /* wraparound */
436 if (This->leadin && ((bplay < This->startpos) || (bplay > bmix))) {
437 /* seems we haven't started playing yet */
438 TRACE("this still in lead-in phase\n");
439 bplay = This->startpos;
441 /* return the result */
445 static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(
446 LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos
449 ICOM_THIS(IDirectSoundBufferImpl,iface);
450 TRACE("(%p,%p,%p)\n",This,playpos,writepos);
452 hres=IDsDriverBuffer_GetPosition(This->hwbuf,playpos,writepos);
454 WARN("IDsDriverBuffer_GetPosition failed\n");
459 if (playpos && (This->state != STATE_PLAYING)) {
460 /* we haven't been merged into the primary buffer (yet) */
461 *playpos = This->buf_mixpos;
464 DWORD pplay, pwrite, lplay, splay, pstate;
465 /* let's get this exact; first, recursively call GetPosition on the primary */
466 EnterCriticalSection(&(This->dsound->mixlock));
467 if (DSOUND_PrimaryGetPosition(This->dsound, &pplay, &pwrite) != DS_OK)
468 WARN("DSOUND_PrimaryGetPosition failed\n");
469 /* detect HEL mode underrun */
470 pstate = This->dsound->state;
471 if (!(This->dsound->hwbuf || This->dsound->pwqueue)) {
472 TRACE("detected an underrun\n");
474 if (pstate == STATE_PLAYING)
475 pstate = STATE_STARTING;
476 else if (pstate == STATE_STOPPING)
477 pstate = STATE_STOPPED;
479 /* get data for ourselves while we still have the lock */
480 pstate &= This->state;
481 lplay = This->primary_mixpos;
482 splay = This->buf_mixpos;
483 if ((This->dsbd.dwFlags & DSBCAPS_GETCURRENTPOSITION2) || This->dsound->hwbuf) {
484 /* calculate play position using this */
485 *playpos = DSOUND_CalcPlayPosition(This, pstate, pplay, pwrite, lplay, splay);
487 /* (unless the app isn't using GETCURRENTPOSITION2) */
488 /* don't know exactly how this should be handled...
489 * the docs says that play cursor is reported as directly
490 * behind write cursor, hmm... */
491 /* let's just do what might work for Half-Life */
493 wp = (This->dsound->pwplay + ds_hel_margin) * This->dsound->fraglen;
494 while (wp >= This->dsound->buflen)
495 wp -= This->dsound->buflen;
496 *playpos = DSOUND_CalcPlayPosition(This, pstate, wp, pwrite, lplay, splay);
498 LeaveCriticalSection(&(This->dsound->mixlock));
500 if (writepos) *writepos = This->buf_mixpos;
503 if (This->state != STATE_STOPPED)
504 /* apply the documented 10ms lead to writepos */
505 *writepos += This->writelead;
506 while (*writepos >= This->buflen) *writepos -= This->buflen;
508 if (playpos) This->last_playpos = *playpos;
509 TRACE("playpos = %ld, writepos = %ld (%p, time=%ld)\n", playpos?*playpos:0, writepos?*writepos:0, This, GetTickCount());
513 static HRESULT WINAPI IDirectSoundBufferImpl_GetStatus(
514 LPDIRECTSOUNDBUFFER8 iface,LPDWORD status
516 ICOM_THIS(IDirectSoundBufferImpl,iface);
517 TRACE("(%p,%p), thread is %04lx\n",This,status,GetCurrentThreadId());
519 if (status == NULL) {
520 WARN("invalid parameter: status = NULL\n");
521 return DSERR_INVALIDPARAM;
525 if ((This->state == STATE_STARTING) || (This->state == STATE_PLAYING)) {
526 *status |= DSBSTATUS_PLAYING;
527 if (This->playflags & DSBPLAY_LOOPING)
528 *status |= DSBSTATUS_LOOPING;
531 TRACE("status=%lx\n", *status);
536 static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat(
537 LPDIRECTSOUNDBUFFER8 iface,LPWAVEFORMATEX lpwf,DWORD wfsize,LPDWORD wfwritten
539 ICOM_THIS(IDirectSoundBufferImpl,iface);
540 TRACE("(%p,%p,%ld,%p)\n",This,lpwf,wfsize,wfwritten);
542 if (wfsize>sizeof(This->wfx))
543 wfsize = sizeof(This->wfx);
544 if (lpwf) { /* NULL is valid */
545 memcpy(lpwf,&(This->wfx),wfsize);
550 *wfwritten = sizeof(This->wfx);
552 WARN("invalid parameter: wfwritten == NULL\n");
553 return DSERR_INVALIDPARAM;
560 static HRESULT WINAPI IDirectSoundBufferImpl_Lock(
561 LPDIRECTSOUNDBUFFER8 iface,DWORD writecursor,DWORD writebytes,LPVOID lplpaudioptr1,LPDWORD audiobytes1,LPVOID lplpaudioptr2,LPDWORD audiobytes2,DWORD flags
563 HRESULT hres = DS_OK;
564 ICOM_THIS(IDirectSoundBufferImpl,iface);
566 TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx) at %ld\n",
578 if (flags & DSBLOCK_FROMWRITECURSOR) {
580 /* GetCurrentPosition does too much magic to duplicate here */
581 hres = IDirectSoundBufferImpl_GetCurrentPosition(iface, NULL, &writepos);
583 WARN("IDirectSoundBufferImpl_GetCurrentPosition failed\n");
586 writecursor += writepos;
588 while (writecursor >= This->buflen)
589 writecursor -= This->buflen;
590 if (flags & DSBLOCK_ENTIREBUFFER)
591 writebytes = This->buflen;
592 if (writebytes > This->buflen)
593 writebytes = This->buflen;
595 assert(audiobytes1!=audiobytes2);
596 assert(lplpaudioptr1!=lplpaudioptr2);
598 EnterCriticalSection(&(This->lock));
600 if ((writebytes == This->buflen) &&
601 ((This->state == STATE_STARTING) ||
602 (This->state == STATE_PLAYING)))
603 /* some games, like Half-Life, try to be clever (not) and
604 * keep one secondary buffer, and mix sounds into it itself,
605 * locking the entire buffer every time... so we can just forget
606 * about tracking the last-written-to-position... */
607 This->probably_valid_to = (DWORD)-1;
609 This->probably_valid_to = writecursor;
611 if (!(This->dsound->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
612 hres = IDsDriverBuffer_Lock(This->hwbuf,
613 lplpaudioptr1, audiobytes1,
614 lplpaudioptr2, audiobytes2,
615 writecursor, writebytes,
618 WARN("IDsDriverBuffer_Lock failed\n");
619 LeaveCriticalSection(&(This->lock));
624 if (writecursor+writebytes <= This->buflen) {
625 *(LPBYTE*)lplpaudioptr1 = This->buffer+writecursor;
626 *audiobytes1 = writebytes;
628 *(LPBYTE*)lplpaudioptr2 = NULL;
631 TRACE("->%ld.0\n",writebytes);
633 *(LPBYTE*)lplpaudioptr1 = This->buffer+writecursor;
634 *audiobytes1 = This->buflen-writecursor;
636 *(LPBYTE*)lplpaudioptr2 = This->buffer;
638 *audiobytes2 = writebytes-(This->buflen-writecursor);
639 TRACE("->%ld.%ld\n",*audiobytes1,audiobytes2?*audiobytes2:0);
641 if (This->state == STATE_PLAYING) {
642 /* if the segment between playpos and buf_mixpos is touched,
643 * we need to cancel some mixing */
644 /* we'll assume that the app always calls GetCurrentPosition before
645 * locking a playing buffer, so that last_playpos is up-to-date */
646 if (This->buf_mixpos >= This->last_playpos) {
647 if (This->buf_mixpos > writecursor &&
648 This->last_playpos < writecursor+writebytes)
652 if (This->buf_mixpos > writecursor ||
653 This->last_playpos < writecursor+writebytes)
657 TRACE("locking prebuffered region, ouch\n");
658 DSOUND_MixCancelAt(This, writecursor);
663 LeaveCriticalSection(&(This->lock));
667 static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(
668 LPDIRECTSOUNDBUFFER8 iface,DWORD newpos
670 HRESULT hres = DS_OK;
671 ICOM_THIS(IDirectSoundBufferImpl,iface);
672 TRACE("(%p,%ld)\n",This,newpos);
675 EnterCriticalSection(&(This->lock));
677 while (newpos >= This->buflen)
678 newpos -= This->buflen;
679 This->buf_mixpos = newpos;
681 hres = IDsDriverBuffer_SetPosition(This->hwbuf, This->buf_mixpos);
683 WARN("IDsDriverBuffer_SetPosition failed\n");
686 LeaveCriticalSection(&(This->lock));
692 static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(
693 LPDIRECTSOUNDBUFFER8 iface,LONG pan
695 HRESULT hres = DS_OK;
696 ICOM_THIS(IDirectSoundBufferImpl,iface);
699 TRACE("(%p,%ld)\n",This,pan);
701 if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT)) {
702 WARN("invalid parameter: pan = %ld\n", pan);
703 return DSERR_INVALIDPARAM;
706 /* You cannot use both pan and 3D controls */
707 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
708 (This->dsbd.dwFlags & DSBCAPS_CTRL3D)) {
709 WARN("control unavailable\n");
710 return DSERR_CONTROLUNAVAIL;
714 EnterCriticalSection(&(This->lock));
716 oldPan = This->volpan.lPan;
717 This->volpan.lPan = pan;
720 DSOUND_RecalcVolPan(&(This->volpan));
723 hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
725 WARN("IDsDriverBuffer_SetVolumePan failed\n");
727 DSOUND_ForceRemix(This);
730 LeaveCriticalSection(&(This->lock));
736 static HRESULT WINAPI IDirectSoundBufferImpl_GetPan(
737 LPDIRECTSOUNDBUFFER8 iface,LPLONG pan
739 ICOM_THIS(IDirectSoundBufferImpl,iface);
740 TRACE("(%p,%p)\n",This,pan);
743 WARN("invalid parameter: pan = NULL\n");
744 return DSERR_INVALIDPARAM;
747 *pan = This->volpan.lPan;
752 static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(
753 LPDIRECTSOUNDBUFFER8 iface,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2
755 ICOM_THIS(IDirectSoundBufferImpl,iface);
756 DWORD probably_valid_to;
758 TRACE("(%p,%p,%ld,%p,%ld)\n", This,p1,x1,p2,x2);
761 /* Preprocess 3D buffers... */
763 /* This is highly experimental and liable to break things */
764 if (This->dsbd.dwFlags & DSBCAPS_CTRL3D)
765 DSOUND_Create3DBuffer(This);
768 if (!(This->dsound->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
770 hres = IDsDriverBuffer_Unlock(This->hwbuf, p1, x1, p2, x2);
772 WARN("IDsDriverBuffer_Unlock failed\n");
777 if (p2) probably_valid_to = (((LPBYTE)p2)-This->buffer) + x2;
778 else probably_valid_to = (((LPBYTE)p1)-This->buffer) + x1;
779 while (probably_valid_to >= This->buflen)
780 probably_valid_to -= This->buflen;
781 if ((probably_valid_to == 0) && ((x1+x2) == This->buflen) &&
782 ((This->state == STATE_STARTING) ||
783 (This->state == STATE_PLAYING)))
784 /* see IDirectSoundBufferImpl_Lock */
785 probably_valid_to = (DWORD)-1;
786 This->probably_valid_to = probably_valid_to;
791 static HRESULT WINAPI IDirectSoundBufferImpl_Restore(
792 LPDIRECTSOUNDBUFFER8 iface
794 ICOM_THIS(IDirectSoundBufferImpl,iface);
795 FIXME("(%p):stub\n",This);
799 static HRESULT WINAPI IDirectSoundBufferImpl_GetFrequency(
800 LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq
802 ICOM_THIS(IDirectSoundBufferImpl,iface);
803 TRACE("(%p,%p)\n",This,freq);
806 WARN("invalid parameter: freq = NULL\n");
807 return DSERR_INVALIDPARAM;
811 TRACE("-> %ld\n", *freq);
816 static HRESULT WINAPI IDirectSoundBufferImpl_SetFX(
817 LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes
819 ICOM_THIS(IDirectSoundBufferImpl,iface);
822 FIXME("(%p,%lu,%p,%p): stub\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
825 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
827 WARN("control unavailable\n");
828 return DSERR_CONTROLUNAVAIL;
831 static HRESULT WINAPI IDirectSoundBufferImpl_AcquireResources(
832 LPDIRECTSOUNDBUFFER8 iface,DWORD dwFlags,DWORD dwEffectsCount,LPDWORD pdwResultCodes
834 ICOM_THIS(IDirectSoundBufferImpl,iface);
837 FIXME("(%p,%08lu,%lu,%p): stub\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
840 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
842 WARN("control unavailable\n");
843 return DSERR_CONTROLUNAVAIL;
846 static HRESULT WINAPI IDirectSoundBufferImpl_GetObjectInPath(
847 LPDIRECTSOUNDBUFFER8 iface,REFGUID rguidObject,DWORD dwIndex,REFGUID rguidInterface,LPVOID* ppObject
849 ICOM_THIS(IDirectSoundBufferImpl,iface);
851 FIXME("(%p,%s,%lu,%s,%p): stub\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
853 WARN("control unavailable\n");
854 return DSERR_CONTROLUNAVAIL;
857 static HRESULT WINAPI IDirectSoundBufferImpl_Initialize(
858 LPDIRECTSOUNDBUFFER8 iface,LPDIRECTSOUND8 dsound,LPDSBUFFERDESC dbsd
860 ICOM_THIS(IDirectSoundBufferImpl,iface);
861 FIXME("(%p,%p,%p):stub\n",This,dsound,dbsd);
862 DPRINTF("Re-Init!!!\n");
863 WARN("already initialized\n");
864 return DSERR_ALREADYINITIALIZED;
867 static HRESULT WINAPI IDirectSoundBufferImpl_GetCaps(
868 LPDIRECTSOUNDBUFFER8 iface,LPDSBCAPS caps
870 ICOM_THIS(IDirectSoundBufferImpl,iface);
871 TRACE("(%p)->(%p)\n",This,caps);
874 WARN("invalid parameter: caps == NULL\n");
875 return DSERR_INVALIDPARAM;
878 if (caps->dwSize < sizeof(*caps)) {
879 WARN("invalid parameter: caps->dwSize = %ld < %d\n",caps->dwSize, sizeof(*caps));
880 return DSERR_INVALIDPARAM;
883 caps->dwFlags = This->dsbd.dwFlags;
884 if (This->hwbuf) caps->dwFlags |= DSBCAPS_LOCHARDWARE;
885 else caps->dwFlags |= DSBCAPS_LOCSOFTWARE;
887 caps->dwBufferBytes = This->buflen;
889 /* This value represents the speed of the "unlock" command.
890 As unlock is quite fast (it does not do anything), I put
891 4096 ko/s = 4 Mo / s */
892 /* FIXME: hwbuf speed */
893 caps->dwUnlockTransferRate = 4096;
894 caps->dwPlayCpuOverhead = 0;
899 static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface(
900 LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj
902 ICOM_THIS(IDirectSoundBufferImpl,iface);
904 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
906 if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ||
907 IsEqualGUID( &IID_IDirectSoundNotify8, riid ) ) {
909 This->notify = (IDirectSoundNotifyImpl*)HeapAlloc(GetProcessHeap(),
910 HEAP_ZERO_MEMORY,sizeof(*This->notify));
912 This->notify->ref = 0; /* release when ref == -1 */
913 This->notify->lpVtbl = &dsnvt;
917 IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify);
918 *ppobj = (LPVOID)This->notify;
922 WARN("IID_IDirectSoundNotify\n");
926 if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) {
928 IDirectSound3DBufferImpl_Create(This, &This->ds3db);
929 *ppobj = This->ds3db;
931 IDirectSound3DBuffer_AddRef((LPDIRECTSOUND3DBUFFER)*ppobj);
935 WARN("IID_IDirectSound3DBuffer\n");
939 if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
940 ERR("app requested IDirectSound3DListener on secondary buffer\n");
945 if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) {
947 IKsPropertySetImpl_Create(This, &This->iks);
950 IKsPropertySet_AddRef((LPKSPROPERTYSET)*ppobj);
954 WARN("IID_IKsPropertySet\n");
958 if ( IsEqualGUID( &IID_IDirectSoundBuffer8, riid ) ) {
959 IDirectSoundBuffer8_AddRef(iface);
964 FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
968 return E_NOINTERFACE;
971 static ICOM_VTABLE(IDirectSoundBuffer8) dsbvt =
973 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
974 IDirectSoundBufferImpl_QueryInterface,
975 IDirectSoundBufferImpl_AddRef,
976 IDirectSoundBufferImpl_Release,
977 IDirectSoundBufferImpl_GetCaps,
978 IDirectSoundBufferImpl_GetCurrentPosition,
979 IDirectSoundBufferImpl_GetFormat,
980 IDirectSoundBufferImpl_GetVolume,
981 IDirectSoundBufferImpl_GetPan,
982 IDirectSoundBufferImpl_GetFrequency,
983 IDirectSoundBufferImpl_GetStatus,
984 IDirectSoundBufferImpl_Initialize,
985 IDirectSoundBufferImpl_Lock,
986 IDirectSoundBufferImpl_Play,
987 IDirectSoundBufferImpl_SetCurrentPosition,
988 IDirectSoundBufferImpl_SetFormat,
989 IDirectSoundBufferImpl_SetVolume,
990 IDirectSoundBufferImpl_SetPan,
991 IDirectSoundBufferImpl_SetFrequency,
992 IDirectSoundBufferImpl_Stop,
993 IDirectSoundBufferImpl_Unlock,
994 IDirectSoundBufferImpl_Restore,
995 IDirectSoundBufferImpl_SetFX,
996 IDirectSoundBufferImpl_AcquireResources,
997 IDirectSoundBufferImpl_GetObjectInPath
1000 HRESULT WINAPI SecondaryBuffer_Create(
1001 IDirectSoundImpl *This,
1002 IDirectSoundBufferImpl **pdsb,
1003 LPDSBUFFERDESC dsbd)
1005 IDirectSoundBufferImpl *dsb;
1006 LPWAVEFORMATEX wfex = dsbd->lpwfxFormat;
1007 HRESULT err = DS_OK;
1011 if (dsbd->dwBufferBytes < DSBSIZE_MIN || dsbd->dwBufferBytes > DSBSIZE_MAX) {
1012 ERR("invalid parameter: dsbd->dwBufferBytes = %ld\n", dsbd->dwBufferBytes);
1014 return DSERR_INVALIDPARAM; /* FIXME: which error? */
1017 dsb = (IDirectSoundBufferImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
1020 WARN("out of memory\n");
1022 return DSERR_OUTOFMEMORY;
1027 dsb->lpVtbl = &dsbvt;
1029 memcpy(&dsb->dsbd, dsbd, sizeof(*dsbd));
1031 memcpy(&dsb->wfx, wfex, sizeof(dsb->wfx));
1033 TRACE("Created buffer at %p\n", dsb);
1035 dsb->buflen = dsbd->dwBufferBytes;
1036 dsb->freq = dsbd->lpwfxFormat->nSamplesPerSec;
1038 /* Check necessary hardware mixing capabilities */
1039 if (wfex->nChannels==2) capf |= DSCAPS_SECONDARYSTEREO;
1040 else capf |= DSCAPS_SECONDARYMONO;
1041 if (wfex->wBitsPerSample==16) capf |= DSCAPS_SECONDARY16BIT;
1042 else capf |= DSCAPS_SECONDARY8BIT;
1043 use_hw = (This->drvcaps.dwFlags & capf) == capf;
1045 /* FIXME: check hardware sample rate mixing capabilities */
1046 /* FIXME: check app hints for software/hardware buffer (STATIC, LOCHARDWARE, etc) */
1047 /* FIXME: check whether any hardware buffers are left */
1048 /* FIXME: handle DSDHEAP_CREATEHEAP for hardware buffers */
1050 /* Allocate system memory if applicable */
1051 if ((This->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) || !use_hw) {
1052 dsb->buffer = (LPBYTE)HeapAlloc(GetProcessHeap(),0,dsb->buflen);
1053 if (dsb->buffer == NULL) {
1054 WARN("out of memory\n");
1055 HeapFree(GetProcessHeap(),0,dsb);
1057 return DSERR_OUTOFMEMORY;
1061 /* Allocate the hardware buffer */
1063 err = IDsDriver_CreateSoundBuffer(This->driver,wfex,dsbd->dwFlags,0,
1064 &(dsb->buflen),&(dsb->buffer),
1065 (LPVOID*)&(dsb->hwbuf));
1067 WARN("IDsDriver_CreateSoundBuffer failed\n");
1069 HeapFree(GetProcessHeap(),0,dsb->buffer);
1070 HeapFree(GetProcessHeap(),0,dsb);
1076 /* calculate fragment size and write lead */
1077 DSOUND_RecalcFormat(dsb);
1079 /* It's not necessary to initialize values to zero since */
1080 /* we allocated this structure with HEAP_ZERO_MEMORY... */
1082 dsb->buf_mixpos = 0;
1083 dsb->state = STATE_STOPPED;
1085 dsb->freqAdjust = (dsb->freq << DSOUND_FREQSHIFT) /
1086 This->wfx.nSamplesPerSec;
1087 dsb->nAvgBytesPerSec = dsb->freq *
1088 dsbd->lpwfxFormat->nBlockAlign;
1090 if (dsbd->dwFlags & DSBCAPS_CTRL3D) {
1091 err = IDirectSound3DBufferImpl_Create(dsb, &dsb->ds3db);
1093 WARN("IDirectSound3DBufferImpl_Create failed\n");
1095 HeapFree(GetProcessHeap(),0,dsb->buffer);
1096 HeapFree(GetProcessHeap(),0,dsb);
1101 DSOUND_RecalcVolPan(&(dsb->volpan));
1103 InitializeCriticalSection(&(dsb->lock));
1105 /* register buffer */
1106 RtlAcquireResourceExclusive(&(This->lock), TRUE);
1107 if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
1108 IDirectSoundBufferImpl **newbuffers = (IDirectSoundBufferImpl**)HeapReAlloc(GetProcessHeap(),0,This->buffers,sizeof(IDirectSoundBufferImpl*)*(This->nrofbuffers+1));
1110 This->buffers = newbuffers;
1111 This->buffers[This->nrofbuffers] = dsb;
1112 This->nrofbuffers++;
1113 TRACE("buffer count is now %d\n", This->nrofbuffers);
1115 ERR("out of memory for buffer list! Current buffer count is %d\n", This->nrofbuffers);
1117 HeapFree(GetProcessHeap(),0,dsb->buffer);
1118 DeleteCriticalSection(&(dsb->lock));
1119 RtlReleaseResource(&(This->lock));
1120 HeapFree(GetProcessHeap(),0,dsb);
1122 return DSERR_OUTOFMEMORY;
1125 RtlReleaseResource(&(This->lock));
1126 IDirectSound8_AddRef((LPDIRECTSOUND8)This);