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
26 #include <sys/types.h>
27 #include <sys/fcntl.h>
33 #include <math.h> /* Insomnia - pow() function */
44 #include "wine/windef16.h"
45 #include "wine/debug.h"
48 #include "dsound_private.h"
50 WINE_DEFAULT_DEBUG_CHANNEL(dsound
);
52 void DSOUND_RecalcPrimary(IDirectSoundImpl
*This
)
57 sw
= This
->wfx
.nChannels
* (This
->wfx
.wBitsPerSample
/ 8);
60 /* let fragment size approximate the timer delay */
61 fraglen
= (This
->wfx
.nSamplesPerSec
* DS_TIME_DEL
/ 1000) * sw
;
62 /* reduce fragment size until an integer number of them fits in the buffer */
63 /* (FIXME: this may or may not be a good idea) */
64 while (This
->buflen
% fraglen
) fraglen
-= sw
;
65 This
->fraglen
= fraglen
;
66 TRACE("fraglen=%ld\n", This
->fraglen
);
68 /* calculate the 10ms write lead */
69 This
->writelead
= (This
->wfx
.nSamplesPerSec
/ 100) * sw
;
72 static HRESULT
DSOUND_PrimaryOpen(IDirectSoundImpl
*This
)
77 /* are we using waveOut stuff? */
82 /* Start in pause mode, to allow buffers to get filled */
83 waveOutPause(This
->hwo
);
84 if (This
->state
== STATE_PLAYING
) This
->state
= STATE_STARTING
;
85 else if (This
->state
== STATE_STOPPING
) This
->state
= STATE_STOPPED
;
86 /* use fragments of 10ms (1/100s) each (which should get us within
87 * the documented write cursor lead of 10-15ms) */
88 buflen
= ((This
->wfx
.nAvgBytesPerSec
/ 100) & ~3) * DS_HEL_FRAGS
;
89 TRACE("desired buflen=%ld, old buffer=%p\n", buflen
, This
->buffer
);
90 /* reallocate emulated primary buffer */
91 newbuf
= (LPBYTE
)HeapReAlloc(GetProcessHeap(),0,This
->buffer
,buflen
);
93 ERR("failed to allocate primary buffer\n");
94 merr
= DSERR_OUTOFMEMORY
;
95 /* but the old buffer might still exist and must be re-prepared */
97 This
->buffer
= newbuf
;
98 This
->buflen
= buflen
;
103 This
->fraglen
= This
->buflen
/ DS_HEL_FRAGS
;
105 /* prepare fragment headers */
106 for (c
=0; c
<DS_HEL_FRAGS
; c
++) {
107 This
->pwave
[c
]->lpData
= This
->buffer
+ c
*This
->fraglen
;
108 This
->pwave
[c
]->dwBufferLength
= This
->fraglen
;
109 This
->pwave
[c
]->dwUser
= (DWORD
)This
;
110 This
->pwave
[c
]->dwFlags
= 0;
111 This
->pwave
[c
]->dwLoops
= 0;
112 err
= mmErr(waveOutPrepareHeader(This
->hwo
,This
->pwave
[c
],sizeof(WAVEHDR
)));
115 waveOutUnprepareHeader(This
->hwo
,This
->pwave
[c
],sizeof(WAVEHDR
));
125 memset(This
->buffer
, (This
->wfx
.wBitsPerSample
== 16) ? 0 : 128, This
->buflen
);
126 TRACE("fraglen=%ld\n", This
->fraglen
);
127 DSOUND_WaveQueue(This
, (DWORD
)-1);
129 if ((err
== DS_OK
) && (merr
!= DS_OK
))
136 static void DSOUND_PrimaryClose(IDirectSoundImpl
*This
)
138 TRACE("(%p)\n",This
);
140 /* are we using waveOut stuff? */
144 This
->pwqueue
= (DWORD
)-1; /* resetting queues */
145 waveOutReset(This
->hwo
);
146 for (c
=0; c
<DS_HEL_FRAGS
; c
++)
147 waveOutUnprepareHeader(This
->hwo
, This
->pwave
[c
], sizeof(WAVEHDR
));
152 HRESULT
DSOUND_PrimaryCreate(IDirectSoundImpl
*This
)
155 TRACE("(%p)\n",This
);
157 This
->buflen
= This
->wfx
.nAvgBytesPerSec
;
159 /* FIXME: verify that hardware capabilities (DSCAPS_PRIMARY flags) match */
162 err
= IDsDriver_CreateSoundBuffer(This
->driver
,&(This
->wfx
),
163 DSBCAPS_PRIMARYBUFFER
,0,
164 &(This
->buflen
),&(This
->buffer
),
165 (LPVOID
*)&(This
->hwbuf
));
167 WARN("IDsDriver_CreateSoundBuffer failed\n");
172 /* Allocate memory for HEL buffer headers */
174 for (c
=0; c
<DS_HEL_FRAGS
; c
++) {
175 This
->pwave
[c
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(WAVEHDR
));
176 if (!This
->pwave
[c
]) {
177 /* Argh, out of memory */
179 HeapFree(GetProcessHeap(),0,This
->pwave
[c
]);
181 WARN("out of memory\n");
182 return DSERR_OUTOFMEMORY
;
187 err
= DSOUND_PrimaryOpen(This
);
190 WARN("DSOUND_PrimaryOpen failed\n");
194 /* calculate fragment size and write lead */
195 DSOUND_RecalcPrimary(This
);
196 This
->state
= STATE_STOPPED
;
200 HRESULT
DSOUND_PrimaryDestroy(IDirectSoundImpl
*This
)
202 TRACE("(%p)\n",This
);
204 DSOUND_PrimaryClose(This
);
206 if (IDsDriverBuffer_Release(This
->hwbuf
) == 0)
210 for (c
=0; c
<DS_HEL_FRAGS
; c
++) {
211 HeapFree(GetProcessHeap(),0,This
->pwave
[c
]);
217 HRESULT
DSOUND_PrimaryPlay(IDirectSoundImpl
*This
)
220 TRACE("(%p)\n",This
);
223 err
= IDsDriverBuffer_Play(This
->hwbuf
, 0, 0, DSBPLAY_LOOPING
);
225 WARN("IDsDriverBuffer_Play failed\n");
227 err
= mmErr(waveOutRestart(This
->hwo
));
229 WARN("waveOutRestart failed\n");
235 HRESULT
DSOUND_PrimaryStop(IDirectSoundImpl
*This
)
238 TRACE("(%p)\n",This
);
241 err
= IDsDriverBuffer_Stop(This
->hwbuf
);
242 if (err
== DSERR_BUFFERLOST
) {
243 DWORD flags
= CALLBACK_FUNCTION
;
244 if (ds_hw_accel
!= DS_HW_ACCEL_EMULATION
)
245 flags
|= WAVE_DIRECTSOUND
;
246 /* Wine-only: the driver wants us to reopen the device */
247 /* FIXME: check for errors */
248 IDsDriverBuffer_Release(This
->hwbuf
);
249 waveOutClose(This
->hwo
);
251 err
= mmErr(waveOutOpen(&(This
->hwo
), This
->drvdesc
.dnDevNode
,
252 &(This
->wfx
), (DWORD
)DSOUND_callback
, (DWORD
)This
,
255 err
= IDsDriver_CreateSoundBuffer(This
->driver
,&(This
->wfx
),
256 DSBCAPS_PRIMARYBUFFER
,0,
257 &(This
->buflen
),&(This
->buffer
),
258 (LPVOID
)&(This
->hwbuf
));
260 WARN("IDsDriver_CreateSoundBuffer failed\n");
262 WARN("waveOutOpen failed\n");
264 } else if (err
!= DS_OK
) {
265 WARN("IDsDriverBuffer_Stop failed\n");
268 err
= mmErr(waveOutPause(This
->hwo
));
270 WARN("waveOutPause failed\n");
275 HRESULT
DSOUND_PrimaryGetPosition(IDirectSoundImpl
*This
, LPDWORD playpos
, LPDWORD writepos
)
277 TRACE("(%p,%p,%p)\n",This
,playpos
,writepos
);
280 HRESULT err
=IDsDriverBuffer_GetPosition(This
->hwbuf
,playpos
,writepos
);
282 WARN("IDsDriverBuffer_GetPosition failed\n");
289 mtime
.wType
= TIME_BYTES
;
290 waveOutGetPosition(This
->hwo
, &mtime
, sizeof(mtime
));
291 mtime
.u
.cb
= mtime
.u
.cb
% This
->buflen
;
292 *playpos
= mtime
.u
.cb
;
295 /* the writepos should only be used by apps with WRITEPRIMARY priority,
296 * in which case our software mixer is disabled anyway */
297 *writepos
= (This
->pwplay
+ ds_hel_margin
) * This
->fraglen
;
298 while (*writepos
>= This
->buflen
)
299 *writepos
-= This
->buflen
;
302 TRACE("playpos = %ld, writepos = %ld (%p, time=%ld)\n", playpos
?*playpos
:0, writepos
?*writepos
:0, This
, GetTickCount());
307 /*******************************************************************************
310 /* This sets this format for the <em>Primary Buffer Only</em> */
311 /* See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 120 */
312 static HRESULT WINAPI
PrimaryBufferImpl_SetFormat(
313 LPDIRECTSOUNDBUFFER8 iface
,LPWAVEFORMATEX wfex
315 ICOM_THIS(PrimaryBufferImpl
,iface
);
316 IDirectSoundImpl
* dsound
= This
->dsound
;
317 IDirectSoundBufferImpl
** dsb
;
320 TRACE("(%p,%p)\n",This
,wfex
);
322 if (This
->dsound
->priolevel
== DSSCL_NORMAL
) {
323 WARN("failed priority check!\n");
324 return DSERR_PRIOLEVELNEEDED
;
327 /* Let's be pedantic! */
329 WARN("invalid parameter: wfex==NULL!\n");
330 return DSERR_INVALIDPARAM
;
332 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
333 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
334 wfex
->wFormatTag
, wfex
->nChannels
, wfex
->nSamplesPerSec
,
335 wfex
->nAvgBytesPerSec
, wfex
->nBlockAlign
,
336 wfex
->wBitsPerSample
, wfex
->cbSize
);
338 if ((wfex
->wFormatTag
!= WAVE_FORMAT_PCM
) ||
339 (wfex
->nChannels
< 1) || (wfex
->nChannels
> 2) ||
340 (wfex
->nSamplesPerSec
< 1) ||
341 ((wfex
->wBitsPerSample
!= 8) && (wfex
->wBitsPerSample
!= 16))) {
342 WARN("invalid paramemer: unsupported format!\n");
343 return DSERR_INVALIDPARAM
;
347 RtlAcquireResourceExclusive(&(dsound
->lock
), TRUE
);
349 if (dsound
->wfx
.nSamplesPerSec
!= wfex
->nSamplesPerSec
) {
350 dsb
= dsound
->buffers
;
351 for (i
= 0; i
< dsound
->nrofbuffers
; i
++, dsb
++) {
353 EnterCriticalSection(&((*dsb
)->lock
));
355 (*dsb
)->freqAdjust
= ((*dsb
)->freq
<< DSOUND_FREQSHIFT
) /
356 wfex
->nSamplesPerSec
;
358 LeaveCriticalSection(&((*dsb
)->lock
));
363 dsound
->wfx
.nSamplesPerSec
= wfex
->nSamplesPerSec
;
364 dsound
->wfx
.nChannels
= wfex
->nChannels
;
365 dsound
->wfx
.wBitsPerSample
= wfex
->wBitsPerSample
;
366 dsound
->wfx
.nBlockAlign
= dsound
->wfx
.wBitsPerSample
/ 8 * dsound
->wfx
.nChannels
;
367 dsound
->wfx
.nAvgBytesPerSec
=
368 dsound
->wfx
.nSamplesPerSec
* dsound
->wfx
.nBlockAlign
;
370 if (dsound
->drvdesc
.dwFlags
& DSDDESC_DOMMSYSTEMSETFORMAT
) {
371 DWORD flags
= CALLBACK_FUNCTION
;
372 if (ds_hw_accel
!= DS_HW_ACCEL_EMULATION
)
373 flags
|= WAVE_DIRECTSOUND
;
374 /* FIXME: check for errors */
375 DSOUND_PrimaryClose(dsound
);
376 waveOutClose(dsound
->hwo
);
378 err
= mmErr(waveOutOpen(&(dsound
->hwo
), dsound
->drvdesc
.dnDevNode
,
379 &(dsound
->wfx
), (DWORD
)DSOUND_callback
, (DWORD
)dsound
,
382 err
= DSOUND_PrimaryOpen(dsound
);
384 WARN("DSOUND_PrimaryOpen failed\n");
385 RtlReleaseResource(&(dsound
->lock
));
389 WARN("waveOutOpen failed\n");
390 RtlReleaseResource(&(dsound
->lock
));
395 err
= IDsDriverBuffer_SetFormat(dsound
->hwbuf
, &(dsound
->wfx
));
396 if (err
== DSERR_BUFFERLOST
) {
397 /* Wine-only: the driver wants us to recreate the HW buffer */
398 IDsDriverBuffer_Release(dsound
->hwbuf
);
399 err
= IDsDriver_CreateSoundBuffer(dsound
->driver
,&(dsound
->wfx
),
400 DSBCAPS_PRIMARYBUFFER
,0,
401 &(dsound
->buflen
),&(dsound
->buffer
),
402 (LPVOID
)&(dsound
->hwbuf
));
404 WARN("IDsDriver_CreateSoundBuffer failed\n");
405 RtlReleaseResource(&(dsound
->lock
));
408 if (dsound
->state
== STATE_PLAYING
) dsound
->state
= STATE_STARTING
;
409 else if (dsound
->state
== STATE_STOPPING
) dsound
->state
= STATE_STOPPED
;
411 WARN("IDsDriverBuffer_SetFormat failed\n");
412 RtlReleaseResource(&(dsound
->lock
));
415 /* FIXME: should we set err back to DS_OK in all cases ? */
417 DSOUND_RecalcPrimary(dsound
);
419 RtlReleaseResource(&(dsound
->lock
));
425 static HRESULT WINAPI
PrimaryBufferImpl_SetVolume(
426 LPDIRECTSOUNDBUFFER8 iface
,LONG vol
428 ICOM_THIS(PrimaryBufferImpl
,iface
);
429 IDirectSoundImpl
* dsound
= This
->dsound
;
432 TRACE("(%p,%ld)\n",This
,vol
);
434 /* I'm not sure if we need this for primary buffer */
435 if (!(This
->dsound
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
)) {
436 WARN("control unavailable\n");
437 return DSERR_CONTROLUNAVAIL
;
440 if ((vol
> DSBVOLUME_MAX
) || (vol
< DSBVOLUME_MIN
)) {
441 WARN("invalid parameter: vol = %ld\n", vol
);
442 return DSERR_INVALIDPARAM
;
446 EnterCriticalSection(&(dsound
->mixlock
));
448 oldVol
= dsound
->volpan
.lVolume
;
449 dsound
->volpan
.lVolume
= vol
;
450 DSOUND_RecalcVolPan(&dsound
->volpan
);
455 hres
= IDsDriverBuffer_SetVolumePan(dsound
->hwbuf
, &(dsound
->volpan
));
457 LeaveCriticalSection(&(dsound
->mixlock
));
458 WARN("IDsDriverBuffer_SetVolumePan failed\n");
463 #if 0 /* should we really do this? */
464 /* the DS volume ranges from 0 (max, 0dB attenuation) to -10000 (min, 100dB attenuation) */
465 /* the MM volume ranges from 0 to 0xffff in an unspecified logarithmic scale */
466 WORD cvol
= 0xffff + vol
*6 + vol
/2;
467 DWORD vol
= cvol
| ((DWORD
)cvol
<< 16)
468 waveOutSetVolume(dsound
->hwo
, vol
);
473 LeaveCriticalSection(&(dsound
->mixlock
));
479 static HRESULT WINAPI
PrimaryBufferImpl_GetVolume(
480 LPDIRECTSOUNDBUFFER8 iface
,LPLONG vol
482 ICOM_THIS(PrimaryBufferImpl
,iface
);
483 TRACE("(%p,%p)\n",This
,vol
);
485 if (!(This
->dsound
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
)) {
486 WARN("control unavailable\n");
487 return DSERR_CONTROLUNAVAIL
;
491 WARN("invalid parameter: vol = NULL\n");
492 return DSERR_INVALIDPARAM
;
495 *vol
= This
->dsound
->volpan
.lVolume
;
499 static HRESULT WINAPI
PrimaryBufferImpl_SetFrequency(
500 LPDIRECTSOUNDBUFFER8 iface
,DWORD freq
502 ICOM_THIS(PrimaryBufferImpl
,iface
);
504 TRACE("(%p,%ld)\n",This
,freq
);
506 /* You cannot set the frequency of the primary buffer */
507 WARN("control unavailable\n");
508 return DSERR_CONTROLUNAVAIL
;
511 static HRESULT WINAPI
PrimaryBufferImpl_Play(
512 LPDIRECTSOUNDBUFFER8 iface
,DWORD reserved1
,DWORD reserved2
,DWORD flags
514 ICOM_THIS(PrimaryBufferImpl
,iface
);
515 IDirectSoundImpl
* dsound
= This
->dsound
;
517 TRACE("(%p,%08lx,%08lx,%08lx)\n",
518 This
,reserved1
,reserved2
,flags
521 if (!(flags
& DSBPLAY_LOOPING
)) {
522 WARN("invalid parameter: flags = %08lx\n", flags
);
523 return DSERR_INVALIDPARAM
;
527 EnterCriticalSection(&(dsound
->mixlock
));
529 if (dsound
->state
== STATE_STOPPED
)
530 dsound
->state
= STATE_STARTING
;
531 else if (dsound
->state
== STATE_STOPPING
)
532 dsound
->state
= STATE_PLAYING
;
534 LeaveCriticalSection(&(dsound
->mixlock
));
540 static HRESULT WINAPI
PrimaryBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface
)
542 ICOM_THIS(PrimaryBufferImpl
,iface
);
543 IDirectSoundImpl
* dsound
= This
->dsound
;
545 TRACE("(%p)\n",This
);
548 EnterCriticalSection(&(dsound
->mixlock
));
550 if (dsound
->state
== STATE_PLAYING
)
551 dsound
->state
= STATE_STOPPING
;
552 else if (dsound
->state
== STATE_STARTING
)
553 dsound
->state
= STATE_STOPPED
;
555 LeaveCriticalSection(&(dsound
->mixlock
));
561 static DWORD WINAPI
PrimaryBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface
) {
562 ICOM_THIS(PrimaryBufferImpl
,iface
);
565 TRACE("(%p) ref was %ld, thread is %04lx\n",This
, This
->ref
, GetCurrentThreadId());
566 ref
= InterlockedIncrement(&(This
->ref
));
571 static DWORD WINAPI
PrimaryBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface
) {
572 ICOM_THIS(PrimaryBufferImpl
,iface
);
575 TRACE("(%p) ref was %ld, thread is %04lx\n",This
, This
->ref
, GetCurrentThreadId());
576 ref
= InterlockedDecrement(&(This
->ref
));
579 This
->dsound
->primary
= NULL
;
580 IDirectSound_Release((LPDIRECTSOUND
)This
->dsound
);
581 HeapFree(GetProcessHeap(),0,This
);
582 TRACE("(%p) released\n",This
);
588 static HRESULT WINAPI
PrimaryBufferImpl_GetCurrentPosition(
589 LPDIRECTSOUNDBUFFER8 iface
,LPDWORD playpos
,LPDWORD writepos
592 ICOM_THIS(PrimaryBufferImpl
,iface
);
593 IDirectSoundImpl
* dsound
= This
->dsound
;
595 TRACE("(%p,%p,%p)\n",This
,playpos
,writepos
);
596 hres
= DSOUND_PrimaryGetPosition(dsound
, playpos
, writepos
);
598 WARN("DSOUND_PrimaryGetPosition failed\n");
602 if (dsound
->state
!= STATE_STOPPED
)
603 /* apply the documented 10ms lead to writepos */
604 *writepos
+= dsound
->writelead
;
605 while (*writepos
>= dsound
->buflen
) *writepos
-= dsound
->buflen
;
607 TRACE("playpos = %ld, writepos = %ld (%p, time=%ld)\n", playpos
?*playpos
:0, writepos
?*writepos
:0, This
, GetTickCount());
611 static HRESULT WINAPI
PrimaryBufferImpl_GetStatus(
612 LPDIRECTSOUNDBUFFER8 iface
,LPDWORD status
614 ICOM_THIS(PrimaryBufferImpl
,iface
);
615 TRACE("(%p,%p), thread is %04lx\n",This
,status
,GetCurrentThreadId());
617 if (status
== NULL
) {
618 WARN("invalid parameter: status == NULL\n");
619 return DSERR_INVALIDPARAM
;
623 if ((This
->dsound
->state
== STATE_STARTING
) ||
624 (This
->dsound
->state
== STATE_PLAYING
))
625 *status
|= DSBSTATUS_PLAYING
| DSBSTATUS_LOOPING
;
627 TRACE("status=%lx\n", *status
);
632 static HRESULT WINAPI
PrimaryBufferImpl_GetFormat(
633 LPDIRECTSOUNDBUFFER8 iface
,LPWAVEFORMATEX lpwf
,DWORD wfsize
,LPDWORD wfwritten
635 ICOM_THIS(PrimaryBufferImpl
,iface
);
636 TRACE("(%p,%p,%ld,%p)\n",This
,lpwf
,wfsize
,wfwritten
);
638 if (wfsize
>sizeof(This
->dsound
->wfx
))
639 wfsize
= sizeof(This
->dsound
->wfx
);
640 if (lpwf
) { /* NULL is valid */
641 memcpy(lpwf
,&(This
->dsound
->wfx
),wfsize
);
646 *wfwritten
= sizeof(This
->dsound
->wfx
);
648 WARN("invalid parameter: wfwritten == NULL\n");
649 return DSERR_INVALIDPARAM
;
656 static HRESULT WINAPI
PrimaryBufferImpl_Lock(
657 LPDIRECTSOUNDBUFFER8 iface
,DWORD writecursor
,DWORD writebytes
,LPVOID lplpaudioptr1
,LPDWORD audiobytes1
,LPVOID lplpaudioptr2
,LPDWORD audiobytes2
,DWORD flags
659 ICOM_THIS(PrimaryBufferImpl
,iface
);
660 IDirectSoundImpl
* dsound
= This
->dsound
;
662 TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx) at %ld\n",
674 if (dsound
->priolevel
!= DSSCL_WRITEPRIMARY
) {
675 WARN("failed priority check!\n");
676 return DSERR_PRIOLEVELNEEDED
;
679 if (flags
& DSBLOCK_FROMWRITECURSOR
) {
682 /* GetCurrentPosition does too much magic to duplicate here */
683 hres
= IDirectSoundBuffer_GetCurrentPosition(iface
, NULL
, &writepos
);
685 WARN("IDirectSoundBuffer_GetCurrentPosition failed\n");
688 writecursor
+= writepos
;
690 while (writecursor
>= dsound
->buflen
)
691 writecursor
-= dsound
->buflen
;
692 if (flags
& DSBLOCK_ENTIREBUFFER
)
693 writebytes
= dsound
->buflen
;
694 if (writebytes
> dsound
->buflen
)
695 writebytes
= dsound
->buflen
;
697 assert(audiobytes1
!=audiobytes2
);
698 assert(lplpaudioptr1
!=lplpaudioptr2
);
700 if (!(dsound
->drvdesc
.dwFlags
& DSDDESC_DONTNEEDPRIMARYLOCK
) && dsound
->hwbuf
) {
702 hres
= IDsDriverBuffer_Lock(dsound
->hwbuf
,
703 lplpaudioptr1
, audiobytes1
,
704 lplpaudioptr2
, audiobytes2
,
705 writecursor
, writebytes
,
708 WARN("IDsDriverBuffer_Lock failed\n");
712 if (writecursor
+writebytes
<= dsound
->buflen
) {
713 *(LPBYTE
*)lplpaudioptr1
= dsound
->buffer
+writecursor
;
714 *audiobytes1
= writebytes
;
716 *(LPBYTE
*)lplpaudioptr2
= NULL
;
719 TRACE("->%ld.0\n",writebytes
);
721 *(LPBYTE
*)lplpaudioptr1
= dsound
->buffer
+writecursor
;
722 *audiobytes1
= dsound
->buflen
-writecursor
;
724 *(LPBYTE
*)lplpaudioptr2
= dsound
->buffer
;
726 *audiobytes2
= writebytes
-(dsound
->buflen
-writecursor
);
727 TRACE("->%ld.%ld\n",*audiobytes1
,audiobytes2
?*audiobytes2
:0);
733 static HRESULT WINAPI
PrimaryBufferImpl_SetCurrentPosition(
734 LPDIRECTSOUNDBUFFER8 iface
,DWORD newpos
736 ICOM_THIS(PrimaryBufferImpl
,iface
);
737 TRACE("(%p,%ld)\n",This
,newpos
);
739 /* You cannot set the position of the primary buffer */
740 WARN("invalid call\n");
741 return DSERR_INVALIDCALL
;
744 static HRESULT WINAPI
PrimaryBufferImpl_SetPan(
745 LPDIRECTSOUNDBUFFER8 iface
,LONG pan
747 ICOM_THIS(PrimaryBufferImpl
,iface
);
748 TRACE("(%p,%ld)\n",This
,pan
);
750 /* You cannot set the pan of the primary buffer */
751 WARN("control unavailable\n");
752 return DSERR_CONTROLUNAVAIL
;
755 static HRESULT WINAPI
PrimaryBufferImpl_GetPan(
756 LPDIRECTSOUNDBUFFER8 iface
,LPLONG pan
758 ICOM_THIS(PrimaryBufferImpl
,iface
);
759 TRACE("(%p,%p)\n",This
,pan
);
762 WARN("invalid parameter: pan == NULL\n");
763 return DSERR_INVALIDPARAM
;
766 *pan
= This
->dsound
->volpan
.lPan
;
771 static HRESULT WINAPI
PrimaryBufferImpl_Unlock(
772 LPDIRECTSOUNDBUFFER8 iface
,LPVOID p1
,DWORD x1
,LPVOID p2
,DWORD x2
774 ICOM_THIS(PrimaryBufferImpl
,iface
);
775 IDirectSoundImpl
* dsound
= This
->dsound
;
777 TRACE("(%p,%p,%ld,%p,%ld):stub\n", This
,p1
,x1
,p2
,x2
);
779 if (dsound
->priolevel
!= DSSCL_WRITEPRIMARY
) {
780 WARN("failed priority check!\n");
781 return DSERR_PRIOLEVELNEEDED
;
784 if (!(dsound
->drvdesc
.dwFlags
& DSDDESC_DONTNEEDPRIMARYLOCK
) && dsound
->hwbuf
) {
787 hres
= IDsDriverBuffer_Unlock(dsound
->hwbuf
, p1
, x1
, p2
, x2
);
789 WARN("IDsDriverBuffer_Unlock failed\n");
797 static HRESULT WINAPI
PrimaryBufferImpl_Restore(
798 LPDIRECTSOUNDBUFFER8 iface
800 ICOM_THIS(PrimaryBufferImpl
,iface
);
801 FIXME("(%p):stub\n",This
);
805 static HRESULT WINAPI
PrimaryBufferImpl_GetFrequency(
806 LPDIRECTSOUNDBUFFER8 iface
,LPDWORD freq
808 ICOM_THIS(PrimaryBufferImpl
,iface
);
809 TRACE("(%p,%p)\n",This
,freq
);
812 WARN("invalid parameter: freq == NULL\n");
813 return DSERR_INVALIDPARAM
;
816 if (!(This
->dsound
->dsbd
.dwFlags
& DSBCAPS_CTRLFREQUENCY
)) {
817 WARN("control unavailable\n");
818 return DSERR_CONTROLUNAVAIL
;
821 *freq
= This
->dsound
->wfx
.nSamplesPerSec
;
822 TRACE("-> %ld\n", *freq
);
827 static HRESULT WINAPI
PrimaryBufferImpl_SetFX(
828 LPDIRECTSOUNDBUFFER8 iface
,DWORD dwEffectsCount
,LPDSEFFECTDESC pDSFXDesc
,LPDWORD pdwResultCodes
830 ICOM_THIS(PrimaryBufferImpl
,iface
);
833 FIXME("(%p,%lu,%p,%p): stub\n",This
,dwEffectsCount
,pDSFXDesc
,pdwResultCodes
);
836 for (u
=0; u
<dwEffectsCount
; u
++) pdwResultCodes
[u
] = DSFXR_UNKNOWN
;
838 WARN("control unavailable\n");
839 return DSERR_CONTROLUNAVAIL
;
842 static HRESULT WINAPI
PrimaryBufferImpl_AcquireResources(
843 LPDIRECTSOUNDBUFFER8 iface
,DWORD dwFlags
,DWORD dwEffectsCount
,LPDWORD pdwResultCodes
845 ICOM_THIS(PrimaryBufferImpl
,iface
);
848 FIXME("(%p,%08lu,%lu,%p): stub\n",This
,dwFlags
,dwEffectsCount
,pdwResultCodes
);
851 for (u
=0; u
<dwEffectsCount
; u
++) pdwResultCodes
[u
] = DSFXR_UNKNOWN
;
853 WARN("control unavailable\n");
854 return DSERR_CONTROLUNAVAIL
;
857 static HRESULT WINAPI
PrimaryBufferImpl_GetObjectInPath(
858 LPDIRECTSOUNDBUFFER8 iface
,REFGUID rguidObject
,DWORD dwIndex
,REFGUID rguidInterface
,LPVOID
* ppObject
860 ICOM_THIS(PrimaryBufferImpl
,iface
);
862 FIXME("(%p,%s,%lu,%s,%p): stub\n",This
,debugstr_guid(rguidObject
),dwIndex
,debugstr_guid(rguidInterface
),ppObject
);
864 WARN("control unavailable\n");
865 return DSERR_CONTROLUNAVAIL
;
868 static HRESULT WINAPI
PrimaryBufferImpl_Initialize(
869 LPDIRECTSOUNDBUFFER8 iface
,LPDIRECTSOUND8 dsound
,LPDSBUFFERDESC dbsd
871 ICOM_THIS(PrimaryBufferImpl
,iface
);
872 FIXME("(%p,%p,%p):stub\n",This
,dsound
,dbsd
);
873 DPRINTF("Re-Init!!!\n");
874 WARN("already initialized\n");
875 return DSERR_ALREADYINITIALIZED
;
878 static HRESULT WINAPI
PrimaryBufferImpl_GetCaps(
879 LPDIRECTSOUNDBUFFER8 iface
,LPDSBCAPS caps
881 ICOM_THIS(PrimaryBufferImpl
,iface
);
882 TRACE("(%p)->(%p)\n",This
,caps
);
885 WARN("invalid parameter: caps == NULL\n");
886 return DSERR_INVALIDPARAM
;
889 if (caps
->dwSize
< sizeof(*caps
)) {
890 WARN("invalid parameter: caps->dwSize = %ld: < %d\n", caps
->dwSize
, sizeof(*caps
));
891 return DSERR_INVALIDPARAM
;
894 caps
->dwFlags
= This
->dsound
->dsbd
.dwFlags
;
895 if (This
->dsound
->hwbuf
) caps
->dwFlags
|= DSBCAPS_LOCHARDWARE
;
896 else caps
->dwFlags
|= DSBCAPS_LOCSOFTWARE
;
898 caps
->dwBufferBytes
= This
->dsound
->buflen
;
900 /* This value represents the speed of the "unlock" command.
901 As unlock is quite fast (it does not do anything), I put
902 4096 ko/s = 4 Mo / s */
903 /* FIXME: hwbuf speed */
904 caps
->dwUnlockTransferRate
= 4096;
905 caps
->dwPlayCpuOverhead
= 0;
910 static HRESULT WINAPI
PrimaryBufferImpl_QueryInterface(
911 LPDIRECTSOUNDBUFFER8 iface
,REFIID riid
,LPVOID
*ppobj
913 ICOM_THIS(PrimaryBufferImpl
,iface
);
914 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
917 WARN("invalid parameter\n");
921 *ppobj
= NULL
; /* assume failure */
923 if ( IsEqualGUID(riid
, &IID_IUnknown
) ||
924 IsEqualGUID(riid
, &IID_IDirectSoundBuffer
) ) {
925 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER
)This
);
930 /* DirectSoundBuffer and DirectSoundBuffer8 are different and */
931 /* a primary buffer can't have a DirectSoundBuffer8 interface */
932 if ( IsEqualGUID( &IID_IDirectSoundBuffer8
, riid
) ) {
933 WARN("app requested DirectSoundBuffer8 on primary buffer\n");
934 return E_NOINTERFACE
;
937 if ( IsEqualGUID( &IID_IDirectSoundNotify
, riid
) ) {
938 ERR("app requested IDirectSoundNotify on primary buffer\n");
939 /* FIXME: should we support this? */
940 return E_NOINTERFACE
;
943 if ( IsEqualGUID( &IID_IDirectSound3DBuffer
, riid
) ) {
944 ERR("app requested IDirectSound3DBuffer on primary buffer\n");
945 return E_NOINTERFACE
;
948 if ( IsEqualGUID( &IID_IDirectSound3DListener
, riid
) ) {
949 if (!This
->dsound
->listener
)
950 IDirectSound3DListenerImpl_Create(This
, &This
->dsound
->listener
);
951 if (This
->dsound
->listener
) {
952 *ppobj
= This
->dsound
->listener
;
953 IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER
)*ppobj
);
957 WARN("IID_IDirectSound3DListener failed\n");
958 return E_NOINTERFACE
;
961 if ( IsEqualGUID( &IID_IKsPropertySet
, riid
) ) {
962 FIXME("app requested IKsPropertySet on primary buffer\n");
963 return E_NOINTERFACE
;
966 FIXME( "Unknown IID %s\n", debugstr_guid( riid
) );
967 return E_NOINTERFACE
;
970 static ICOM_VTABLE(IDirectSoundBuffer8
) dspbvt
=
972 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
973 PrimaryBufferImpl_QueryInterface
,
974 PrimaryBufferImpl_AddRef
,
975 PrimaryBufferImpl_Release
,
976 PrimaryBufferImpl_GetCaps
,
977 PrimaryBufferImpl_GetCurrentPosition
,
978 PrimaryBufferImpl_GetFormat
,
979 PrimaryBufferImpl_GetVolume
,
980 PrimaryBufferImpl_GetPan
,
981 PrimaryBufferImpl_GetFrequency
,
982 PrimaryBufferImpl_GetStatus
,
983 PrimaryBufferImpl_Initialize
,
984 PrimaryBufferImpl_Lock
,
985 PrimaryBufferImpl_Play
,
986 PrimaryBufferImpl_SetCurrentPosition
,
987 PrimaryBufferImpl_SetFormat
,
988 PrimaryBufferImpl_SetVolume
,
989 PrimaryBufferImpl_SetPan
,
990 PrimaryBufferImpl_SetFrequency
,
991 PrimaryBufferImpl_Stop
,
992 PrimaryBufferImpl_Unlock
,
993 PrimaryBufferImpl_Restore
,
994 PrimaryBufferImpl_SetFX
,
995 PrimaryBufferImpl_AcquireResources
,
996 PrimaryBufferImpl_GetObjectInPath
999 HRESULT WINAPI
PrimaryBufferImpl_Create(
1000 IDirectSoundImpl
*ds
,
1001 PrimaryBufferImpl
**pdsb
,
1002 LPDSBUFFERDESC dsbd
)
1004 PrimaryBufferImpl
*dsb
;
1006 TRACE("%p,%p,%p)\n",ds
,pdsb
,dsbd
);
1008 if (dsbd
->lpwfxFormat
) {
1009 WARN("invalid parameter: dsbd->lpwfxFormat != NULL\n");
1011 return DSERR_INVALIDPARAM
;
1014 dsb
= (PrimaryBufferImpl
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(*dsb
));
1017 WARN("out of memory\n");
1019 return DSERR_OUTOFMEMORY
;
1024 dsb
->lpVtbl
= &dspbvt
;
1026 memcpy(&ds
->dsbd
, dsbd
, sizeof(*dsbd
));
1028 TRACE("Created primary buffer at %p\n", dsb
);
1029 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
1030 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1031 ds
->wfx
.wFormatTag
, ds
->wfx
.nChannels
, ds
->wfx
.nSamplesPerSec
,
1032 ds
->wfx
.nAvgBytesPerSec
, ds
->wfx
.nBlockAlign
,
1033 ds
->wfx
.wBitsPerSample
, ds
->wfx
.cbSize
);
1035 IDirectSound_AddRef((LPDIRECTSOUND
)ds
);