Converted implementation of _stat and _fstat to _stati64 and
[wine/multimedia.git] / dlls / dsound / primary.c
blobfc28794fd36bcfdb1fda177fb8e7bae5295c793d
1 /* DirectSound
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
22 #include "config.h"
23 #include <assert.h>
24 #include <stdio.h>
25 #include <sys/types.h>
26 #include <sys/fcntl.h>
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30 #include <stdlib.h>
31 #include <string.h>
32 #include <math.h> /* Insomnia - pow() function */
34 #include "windef.h"
35 #include "winbase.h"
36 #include "wingdi.h"
37 #include "winuser.h"
38 #include "winerror.h"
39 #include "mmsystem.h"
40 #include "winternl.h"
41 #include "mmddk.h"
42 #include "wine/windef16.h"
43 #include "wine/debug.h"
44 #include "dsound.h"
45 #include "dsdriver.h"
46 #include "dsound_private.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
50 static HRESULT mmErr(UINT err)
52 switch(err) {
53 case MMSYSERR_NOERROR:
54 return DS_OK;
55 case MMSYSERR_ALLOCATED:
56 return DSERR_ALLOCATED;
57 case MMSYSERR_INVALHANDLE:
58 return DSERR_GENERIC; /* FIXME */
59 case MMSYSERR_NODRIVER:
60 return DSERR_NODRIVER;
61 case MMSYSERR_NOMEM:
62 return DSERR_OUTOFMEMORY;
63 case MMSYSERR_INVALPARAM:
64 return DSERR_INVALIDPARAM;
65 default:
66 FIXME("Unknown MMSYS error %d\n",err);
67 return DSERR_GENERIC;
71 void DSOUND_RecalcPrimary(IDirectSoundImpl *This)
73 DWORD sw;
75 sw = This->wfx.nChannels * (This->wfx.wBitsPerSample / 8);
76 if (This->hwbuf) {
77 DWORD fraglen;
78 /* let fragment size approximate the timer delay */
79 fraglen = (This->wfx.nSamplesPerSec * DS_TIME_DEL / 1000) * sw;
80 /* reduce fragment size until an integer number of them fits in the buffer */
81 /* (FIXME: this may or may not be a good idea) */
82 while (This->buflen % fraglen) fraglen -= sw;
83 This->fraglen = fraglen;
84 TRACE("fraglen=%ld\n", This->fraglen);
86 /* calculate the 10ms write lead */
87 This->writelead = (This->wfx.nSamplesPerSec / 100) * sw;
90 static HRESULT DSOUND_PrimaryOpen(IDirectSoundImpl *This)
92 HRESULT err = DS_OK;
94 /* are we using waveOut stuff? */
95 if (!This->hwbuf) {
96 LPBYTE newbuf;
97 DWORD buflen;
98 HRESULT merr = DS_OK;
99 /* Start in pause mode, to allow buffers to get filled */
100 waveOutPause(This->hwo);
101 if (This->state == STATE_PLAYING) This->state = STATE_STARTING;
102 else if (This->state == STATE_STOPPING) This->state = STATE_STOPPED;
103 /* use fragments of 10ms (1/100s) each (which should get us within
104 * the documented write cursor lead of 10-15ms) */
105 buflen = ((This->wfx.nAvgBytesPerSec / 100) & ~3) * DS_HEL_FRAGS;
106 TRACE("desired buflen=%ld, old buffer=%p\n", buflen, This->buffer);
107 /* reallocate emulated primary buffer */
108 newbuf = (LPBYTE)HeapReAlloc(GetProcessHeap(),0,This->buffer,buflen);
109 if (newbuf == NULL) {
110 ERR("failed to allocate primary buffer\n");
111 merr = DSERR_OUTOFMEMORY;
112 /* but the old buffer might still exists and must be re-prepared */
113 } else {
114 This->buffer = newbuf;
115 This->buflen = buflen;
117 if (This->buffer) {
118 unsigned c;
120 This->fraglen = This->buflen / DS_HEL_FRAGS;
122 /* prepare fragment headers */
123 for (c=0; c<DS_HEL_FRAGS; c++) {
124 This->pwave[c]->lpData = This->buffer + c*This->fraglen;
125 This->pwave[c]->dwBufferLength = This->fraglen;
126 This->pwave[c]->dwUser = (DWORD)This;
127 This->pwave[c]->dwFlags = 0;
128 This->pwave[c]->dwLoops = 0;
129 err = mmErr(waveOutPrepareHeader(This->hwo,This->pwave[c],sizeof(WAVEHDR)));
130 if (err != DS_OK) {
131 while (c--)
132 waveOutUnprepareHeader(This->hwo,This->pwave[c],sizeof(WAVEHDR));
133 break;
137 This->pwplay = 0;
138 This->pwwrite = 0;
139 This->pwqueue = 0;
140 memset(This->buffer, (This->wfx.wBitsPerSample == 16) ? 0 : 128, This->buflen);
141 TRACE("fraglen=%ld\n", This->fraglen);
142 DSOUND_WaveQueue(This, (DWORD)-1);
144 if ((err == DS_OK) && (merr != DS_OK))
145 err = merr;
147 return err;
151 static void DSOUND_PrimaryClose(IDirectSoundImpl *This)
153 /* are we using waveOut stuff? */
154 if (!This->hwbuf) {
155 unsigned c;
157 This->pwqueue = (DWORD)-1; /* resetting queues */
158 waveOutReset(This->hwo);
159 for (c=0; c<DS_HEL_FRAGS; c++)
160 waveOutUnprepareHeader(This->hwo, This->pwave[c], sizeof(WAVEHDR));
161 This->pwqueue = 0;
165 HRESULT DSOUND_PrimaryCreate(IDirectSoundImpl *This)
167 HRESULT err = DS_OK;
169 This->buflen = This->wfx.nAvgBytesPerSec;
171 /* FIXME: verify that hardware capabilities (DSCAPS_PRIMARY flags) match */
173 if (This->driver) {
174 err = IDsDriver_CreateSoundBuffer(This->driver,&(This->wfx),
175 DSBCAPS_PRIMARYBUFFER,0,
176 &(This->buflen),&(This->buffer),
177 (LPVOID*)&(This->hwbuf));
179 if (err == DS_OK)
180 err = DSOUND_PrimaryOpen(This);
181 if (err != DS_OK)
182 return err;
183 /* calculate fragment size and write lead */
184 DSOUND_RecalcPrimary(This);
185 This->state = STATE_STOPPED;
186 return DS_OK;
189 HRESULT DSOUND_PrimaryDestroy(IDirectSoundImpl *This)
191 DSOUND_PrimaryClose(This);
192 if (This->hwbuf) {
193 IDsDriverBuffer_Release(This->hwbuf);
195 return DS_OK;
198 HRESULT DSOUND_PrimaryPlay(IDirectSoundImpl *This)
200 HRESULT err = DS_OK;
201 if (This->hwbuf)
202 err = IDsDriverBuffer_Play(This->hwbuf, 0, 0, DSBPLAY_LOOPING);
203 else
204 err = mmErr(waveOutRestart(This->hwo));
205 return err;
208 HRESULT DSOUND_PrimaryStop(IDirectSoundImpl *This)
210 HRESULT err = DS_OK;
212 TRACE("\n");
214 if (This->hwbuf) {
215 err = IDsDriverBuffer_Stop(This->hwbuf);
216 if (err == DSERR_BUFFERLOST) {
217 /* Wine-only: the driver wants us to reopen the device */
218 /* FIXME: check for errors */
219 IDsDriverBuffer_Release(This->hwbuf);
220 waveOutClose(This->hwo);
221 This->hwo = 0;
222 err = mmErr(waveOutOpen(&(This->hwo), This->drvdesc.dnDevNode,
223 &(This->wfx), (DWORD)DSOUND_callback, (DWORD)This,
224 CALLBACK_FUNCTION | WAVE_DIRECTSOUND));
225 if (err == DS_OK)
226 err = IDsDriver_CreateSoundBuffer(This->driver,&(This->wfx),
227 DSBCAPS_PRIMARYBUFFER,0,
228 &(This->buflen),&(This->buffer),
229 (LPVOID)&(This->hwbuf));
232 else
233 err = mmErr(waveOutPause(This->hwo));
234 return err;
237 HRESULT DSOUND_PrimaryGetPosition(IDirectSoundImpl *This, LPDWORD playpos, LPDWORD writepos)
239 if (This->hwbuf) {
240 HRESULT err=IDsDriverBuffer_GetPosition(This->hwbuf,playpos,writepos);
241 if (err) return err;
243 else {
244 if (playpos) {
245 MMTIME mtime;
246 mtime.wType = TIME_BYTES;
247 waveOutGetPosition(This->hwo, &mtime, sizeof(mtime));
248 mtime.u.cb = mtime.u.cb % This->buflen;
249 *playpos = mtime.u.cb;
251 if (writepos) {
252 /* the writepos should only be used by apps with WRITEPRIMARY priority,
253 * in which case our software mixer is disabled anyway */
254 *writepos = (This->pwplay + ds_hel_margin) * This->fraglen;
255 while (*writepos >= This->buflen)
256 *writepos -= This->buflen;
259 TRACE("playpos = %ld, writepos = %ld (%p, time=%ld)\n", playpos?*playpos:0, writepos?*writepos:0, This, GetTickCount());
260 return DS_OK;
264 /*******************************************************************************
265 * IDirectSoundBuffer
267 /* This sets this format for the <em>Primary Buffer Only</em> */
268 /* See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 120 */
269 static HRESULT WINAPI PrimaryBufferImpl_SetFormat(
270 LPDIRECTSOUNDBUFFER8 iface,LPWAVEFORMATEX wfex
272 ICOM_THIS(PrimaryBufferImpl,iface);
273 IDirectSoundImpl* dsound = This->dsound;
274 IDirectSoundBufferImpl** dsb;
275 HRESULT err = DS_OK;
276 int i;
278 if (This->dsound->priolevel == DSSCL_NORMAL) {
279 TRACE("failed priority check!\n");
280 return DSERR_PRIOLEVELNEEDED;
283 /* Let's be pedantic! */
284 if ((wfex == NULL) ||
285 (wfex->wFormatTag != WAVE_FORMAT_PCM) ||
286 (wfex->nChannels < 1) || (wfex->nChannels > 2) ||
287 (wfex->nSamplesPerSec < 1) ||
288 (wfex->nBlockAlign < 1) || (wfex->nChannels > 4) ||
289 ((wfex->wBitsPerSample != 8) && (wfex->wBitsPerSample != 16))) {
290 TRACE("failed pedantic check!\n");
291 return DSERR_INVALIDPARAM;
294 /* **** */
295 RtlAcquireResourceExclusive(&(dsound->lock), TRUE);
297 if (dsound->wfx.nSamplesPerSec != wfex->nSamplesPerSec) {
298 dsb = dsound->buffers;
299 for (i = 0; i < dsound->nrofbuffers; i++, dsb++) {
300 /* **** */
301 EnterCriticalSection(&((*dsb)->lock));
303 (*dsb)->freqAdjust = ((*dsb)->freq << DSOUND_FREQSHIFT) /
304 wfex->nSamplesPerSec;
306 LeaveCriticalSection(&((*dsb)->lock));
307 /* **** */
311 memcpy(&(dsound->wfx), wfex, sizeof(dsound->wfx));
313 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
314 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
315 wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
316 wfex->nAvgBytesPerSec, wfex->nBlockAlign,
317 wfex->wBitsPerSample, wfex->cbSize);
319 dsound->wfx.nAvgBytesPerSec =
320 dsound->wfx.nSamplesPerSec * dsound->wfx.nBlockAlign;
322 if (dsound->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMSETFORMAT) {
323 /* FIXME: check for errors */
324 DSOUND_PrimaryClose(dsound);
325 waveOutClose(dsound->hwo);
326 dsound->hwo = 0;
327 err = mmErr(waveOutOpen(&(dsound->hwo), dsound->drvdesc.dnDevNode,
328 &(dsound->wfx), (DWORD)DSOUND_callback, (DWORD)dsound,
329 CALLBACK_FUNCTION | WAVE_DIRECTSOUND));
330 if (err == DS_OK)
331 DSOUND_PrimaryOpen(dsound);
333 if (dsound->hwbuf) {
334 err = IDsDriverBuffer_SetFormat(dsound->hwbuf, &(dsound->wfx));
335 if (err == DSERR_BUFFERLOST) {
336 /* Wine-only: the driver wants us to recreate the HW buffer */
337 IDsDriverBuffer_Release(dsound->hwbuf);
338 err = IDsDriver_CreateSoundBuffer(dsound->driver,&(dsound->wfx),
339 DSBCAPS_PRIMARYBUFFER,0,
340 &(dsound->buflen),&(dsound->buffer),
341 (LPVOID)&(dsound->hwbuf));
342 if (dsound->state == STATE_PLAYING) dsound->state = STATE_STARTING;
343 else if (dsound->state == STATE_STOPPING) dsound->state = STATE_STOPPED;
345 /* FIXME: should we set err back to DS_OK in all cases ? */
347 DSOUND_RecalcPrimary(dsound);
349 RtlReleaseResource(&(dsound->lock));
350 /* **** */
352 return err;
355 static HRESULT WINAPI PrimaryBufferImpl_SetVolume(
356 LPDIRECTSOUNDBUFFER8 iface,LONG vol
358 ICOM_THIS(PrimaryBufferImpl,iface);
359 IDirectSoundImpl* dsound = This->dsound;
360 LONG oldVol;
362 TRACE("(%p,%ld)\n",This,vol);
364 /* I'm not sure if we need this for primary buffer */
365 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME))
366 return DSERR_CONTROLUNAVAIL;
368 if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN))
369 return DSERR_INVALIDPARAM;
371 /* **** */
372 EnterCriticalSection(&(dsound->mixlock));
374 oldVol = dsound->volpan.lVolume;
375 dsound->volpan.lVolume = vol;
376 DSOUND_RecalcVolPan(&dsound->volpan);
378 if (vol != oldVol) {
379 if (dsound->hwbuf) {
380 IDsDriverBuffer_SetVolumePan(dsound->hwbuf, &(dsound->volpan));
382 else {
383 #if 0 /* should we really do this? */
384 /* the DS volume ranges from 0 (max, 0dB attenuation) to -10000 (min, 100dB attenuation) */
385 /* the MM volume ranges from 0 to 0xffff in an unspecified logarithmic scale */
386 WORD cvol = 0xffff + vol*6 + vol/2;
387 DWORD vol = cvol | ((DWORD)cvol << 16)
388 waveOutSetVolume(dsound->hwo, vol);
389 #endif
393 LeaveCriticalSection(&(dsound->mixlock));
394 /* **** */
396 return DS_OK;
399 static HRESULT WINAPI PrimaryBufferImpl_GetVolume(
400 LPDIRECTSOUNDBUFFER8 iface,LPLONG vol
402 ICOM_THIS(PrimaryBufferImpl,iface);
403 TRACE("(%p,%p)\n",This,vol);
405 if (vol == NULL)
406 return DSERR_INVALIDPARAM;
408 *vol = This->dsound->volpan.lVolume;
409 return DS_OK;
412 static HRESULT WINAPI PrimaryBufferImpl_SetFrequency(
413 LPDIRECTSOUNDBUFFER8 iface,DWORD freq
415 ICOM_THIS(PrimaryBufferImpl,iface);
417 TRACE("(%p,%ld)\n",This,freq);
419 /* You cannot set the frequency of the primary buffer */
420 return DSERR_CONTROLUNAVAIL;
423 static HRESULT WINAPI PrimaryBufferImpl_Play(
424 LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags
426 ICOM_THIS(PrimaryBufferImpl,iface);
427 IDirectSoundImpl* dsound = This->dsound;
429 TRACE("(%p,%08lx,%08lx,%08lx)\n",
430 This,reserved1,reserved2,flags
433 if (!(flags & DSBPLAY_LOOPING))
434 return DSERR_INVALIDPARAM;
436 /* **** */
437 EnterCriticalSection(&(dsound->mixlock));
439 if (dsound->state == STATE_STOPPED)
440 dsound->state = STATE_STARTING;
441 else if (dsound->state == STATE_STOPPING)
442 dsound->state = STATE_PLAYING;
444 LeaveCriticalSection(&(dsound->mixlock));
445 /* **** */
447 return DS_OK;
450 static HRESULT WINAPI PrimaryBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface)
452 ICOM_THIS(PrimaryBufferImpl,iface);
453 IDirectSoundImpl* dsound = This->dsound;
455 TRACE("(%p)\n",This);
457 /* **** */
458 EnterCriticalSection(&(dsound->mixlock));
460 if (dsound->state == STATE_PLAYING)
461 dsound->state = STATE_STOPPING;
462 else if (dsound->state == STATE_STARTING)
463 dsound->state = STATE_STOPPED;
465 LeaveCriticalSection(&(dsound->mixlock));
466 /* **** */
468 return DS_OK;
471 static DWORD WINAPI PrimaryBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface) {
472 ICOM_THIS(PrimaryBufferImpl,iface);
473 DWORD ref;
475 TRACE("(%p) ref was %ld, thread is %lx\n",This, This->ref, GetCurrentThreadId());
477 ref = InterlockedIncrement(&(This->ref));
478 if (!ref) {
479 FIXME("thread-safety alert! AddRef-ing with a zero refcount!\n");
481 return ref;
483 static DWORD WINAPI PrimaryBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface) {
484 ICOM_THIS(PrimaryBufferImpl,iface);
485 DWORD ref;
487 TRACE("(%p) ref was %ld, thread is %lx\n",This, This->ref, GetCurrentThreadId());
489 ref = InterlockedDecrement(&(This->ref));
490 if (ref) return ref;
492 IDirectSound_Release((LPDIRECTSOUND)This->dsound);
494 #if 0
495 if (This->iks) {
496 HeapFree(GetProcessHeap(), 0, This->iks);
498 #endif
500 HeapFree(GetProcessHeap(),0,This);
502 return 0;
505 static HRESULT WINAPI PrimaryBufferImpl_GetCurrentPosition(
506 LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos
508 ICOM_THIS(PrimaryBufferImpl,iface);
509 IDirectSoundImpl* dsound = This->dsound;
511 TRACE("(%p,%p,%p)\n",This,playpos,writepos);
512 DSOUND_PrimaryGetPosition(dsound, playpos, writepos);
513 if (writepos) {
514 if (dsound->state != STATE_STOPPED)
515 /* apply the documented 10ms lead to writepos */
516 *writepos += dsound->writelead;
517 while (*writepos >= dsound->buflen) *writepos -= dsound->buflen;
519 TRACE("playpos = %ld, writepos = %ld (%p, time=%ld)\n", playpos?*playpos:0, writepos?*writepos:0, This, GetTickCount());
520 return DS_OK;
523 static HRESULT WINAPI PrimaryBufferImpl_GetStatus(
524 LPDIRECTSOUNDBUFFER8 iface,LPDWORD status
526 ICOM_THIS(PrimaryBufferImpl,iface);
527 TRACE("(%p,%p), thread is %lx\n",This,status,GetCurrentThreadId());
529 if (status == NULL)
530 return DSERR_INVALIDPARAM;
532 *status = 0;
533 if ((This->dsound->state == STATE_STARTING) ||
534 (This->dsound->state == STATE_PLAYING))
535 *status |= DSBSTATUS_PLAYING | DSBSTATUS_LOOPING;
537 TRACE("status=%lx\n", *status);
538 return DS_OK;
542 static HRESULT WINAPI PrimaryBufferImpl_GetFormat(
543 LPDIRECTSOUNDBUFFER8 iface,LPWAVEFORMATEX lpwf,DWORD wfsize,LPDWORD wfwritten
545 ICOM_THIS(PrimaryBufferImpl,iface);
546 TRACE("(%p,%p,%ld,%p)\n",This,lpwf,wfsize,wfwritten);
548 if (wfsize>sizeof(This->dsound->wfx))
549 wfsize = sizeof(This->dsound->wfx);
550 if (lpwf) { /* NULL is valid */
551 memcpy(lpwf,&(This->dsound->wfx),wfsize);
552 if (wfwritten)
553 *wfwritten = wfsize;
554 } else
555 if (wfwritten)
556 *wfwritten = sizeof(This->dsound->wfx);
557 else
558 return DSERR_INVALIDPARAM;
560 return DS_OK;
563 static HRESULT WINAPI PrimaryBufferImpl_Lock(
564 LPDIRECTSOUNDBUFFER8 iface,DWORD writecursor,DWORD writebytes,LPVOID lplpaudioptr1,LPDWORD audiobytes1,LPVOID lplpaudioptr2,LPDWORD audiobytes2,DWORD flags
566 ICOM_THIS(PrimaryBufferImpl,iface);
567 IDirectSoundImpl* dsound = This->dsound;
569 TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx) at %ld\n",
570 This,
571 writecursor,
572 writebytes,
573 lplpaudioptr1,
574 audiobytes1,
575 lplpaudioptr2,
576 audiobytes2,
577 flags,
578 GetTickCount()
581 if (dsound->priolevel != DSSCL_WRITEPRIMARY)
582 return DSERR_PRIOLEVELNEEDED;
584 if (flags & DSBLOCK_FROMWRITECURSOR) {
585 DWORD writepos;
586 /* GetCurrentPosition does too much magic to duplicate here */
587 IDirectSoundBuffer_GetCurrentPosition(iface, NULL, &writepos);
588 writecursor += writepos;
590 while (writecursor >= dsound->buflen)
591 writecursor -= dsound->buflen;
592 if (flags & DSBLOCK_ENTIREBUFFER)
593 writebytes = dsound->buflen;
594 if (writebytes > dsound->buflen)
595 writebytes = dsound->buflen;
597 assert(audiobytes1!=audiobytes2);
598 assert(lplpaudioptr1!=lplpaudioptr2);
600 if (!(dsound->drvdesc.dwFlags & DSDDESC_DONTNEEDPRIMARYLOCK) && dsound->hwbuf) {
601 IDsDriverBuffer_Lock(dsound->hwbuf,
602 lplpaudioptr1, audiobytes1,
603 lplpaudioptr2, audiobytes2,
604 writecursor, writebytes,
607 else {
608 if (writecursor+writebytes <= dsound->buflen) {
609 *(LPBYTE*)lplpaudioptr1 = dsound->buffer+writecursor;
610 *audiobytes1 = writebytes;
611 if (lplpaudioptr2)
612 *(LPBYTE*)lplpaudioptr2 = NULL;
613 if (audiobytes2)
614 *audiobytes2 = 0;
615 TRACE("->%ld.0\n",writebytes);
616 } else {
617 *(LPBYTE*)lplpaudioptr1 = dsound->buffer+writecursor;
618 *audiobytes1 = dsound->buflen-writecursor;
619 if (lplpaudioptr2)
620 *(LPBYTE*)lplpaudioptr2 = dsound->buffer;
621 if (audiobytes2)
622 *audiobytes2 = writebytes-(dsound->buflen-writecursor);
623 TRACE("->%ld.%ld\n",*audiobytes1,audiobytes2?*audiobytes2:0);
626 return DS_OK;
629 static HRESULT WINAPI PrimaryBufferImpl_SetCurrentPosition(
630 LPDIRECTSOUNDBUFFER8 iface,DWORD newpos
632 ICOM_THIS(PrimaryBufferImpl,iface);
633 TRACE("(%p,%ld)\n",This,newpos);
635 /* You cannot set the position of the primary buffer */
636 return DSERR_INVALIDCALL;
639 static HRESULT WINAPI PrimaryBufferImpl_SetPan(
640 LPDIRECTSOUNDBUFFER8 iface,LONG pan
642 ICOM_THIS(PrimaryBufferImpl,iface);
643 TRACE("(%p,%ld)\n",This,pan);
645 /* You cannot set the pan of the primary buffer */
646 return DSERR_CONTROLUNAVAIL;
649 static HRESULT WINAPI PrimaryBufferImpl_GetPan(
650 LPDIRECTSOUNDBUFFER8 iface,LPLONG pan
652 ICOM_THIS(PrimaryBufferImpl,iface);
653 TRACE("(%p,%p)\n",This,pan);
655 if (pan == NULL)
656 return DSERR_INVALIDPARAM;
658 *pan = This->dsound->volpan.lPan;
660 return DS_OK;
663 static HRESULT WINAPI PrimaryBufferImpl_Unlock(
664 LPDIRECTSOUNDBUFFER8 iface,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2
666 ICOM_THIS(PrimaryBufferImpl,iface);
667 IDirectSoundImpl* dsound = This->dsound;
669 TRACE("(%p,%p,%ld,%p,%ld):stub\n", This,p1,x1,p2,x2);
671 if (dsound->priolevel != DSSCL_WRITEPRIMARY)
672 return DSERR_PRIOLEVELNEEDED;
674 if (!(dsound->drvdesc.dwFlags & DSDDESC_DONTNEEDPRIMARYLOCK) && dsound->hwbuf) {
675 IDsDriverBuffer_Unlock(dsound->hwbuf, p1, x1, p2, x2);
678 return DS_OK;
681 static HRESULT WINAPI PrimaryBufferImpl_Restore(
682 LPDIRECTSOUNDBUFFER8 iface
684 ICOM_THIS(PrimaryBufferImpl,iface);
685 FIXME("(%p):stub\n",This);
686 return DS_OK;
689 static HRESULT WINAPI PrimaryBufferImpl_GetFrequency(
690 LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq
692 ICOM_THIS(PrimaryBufferImpl,iface);
693 TRACE("(%p,%p)\n",This,freq);
695 if (freq == NULL)
696 return DSERR_INVALIDPARAM;
698 *freq = This->dsound->wfx.nSamplesPerSec;
699 TRACE("-> %ld\n", *freq);
701 return DS_OK;
704 static HRESULT WINAPI PrimaryBufferImpl_SetFX(
705 LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes
707 ICOM_THIS(PrimaryBufferImpl,iface);
708 DWORD u;
710 FIXME("(%p,%lu,%p,%p): stub\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
712 if (pdwResultCodes)
713 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
715 return DSERR_CONTROLUNAVAIL;
718 static HRESULT WINAPI PrimaryBufferImpl_AcquireResources(
719 LPDIRECTSOUNDBUFFER8 iface,DWORD dwFlags,DWORD dwEffectsCount,LPDWORD pdwResultCodes
721 ICOM_THIS(PrimaryBufferImpl,iface);
722 DWORD u;
724 FIXME("(%p,%08lu,%lu,%p): stub\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
726 if (pdwResultCodes)
727 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
729 return DSERR_CONTROLUNAVAIL;
732 static HRESULT WINAPI PrimaryBufferImpl_GetObjectInPath(
733 LPDIRECTSOUNDBUFFER8 iface,REFGUID rguidObject,DWORD dwIndex,REFGUID rguidInterface,LPVOID* ppObject
735 ICOM_THIS(PrimaryBufferImpl,iface);
737 FIXME("(%p,%s,%lu,%s,%p): stub\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
739 return DSERR_CONTROLUNAVAIL;
742 static HRESULT WINAPI PrimaryBufferImpl_Initialize(
743 LPDIRECTSOUNDBUFFER8 iface,LPDIRECTSOUND8 dsound,LPDSBUFFERDESC dbsd
745 ICOM_THIS(PrimaryBufferImpl,iface);
746 FIXME("(%p,%p,%p):stub\n",This,dsound,dbsd);
747 DPRINTF("Re-Init!!!\n");
748 return DSERR_ALREADYINITIALIZED;
751 static HRESULT WINAPI PrimaryBufferImpl_GetCaps(
752 LPDIRECTSOUNDBUFFER8 iface,LPDSBCAPS caps
754 ICOM_THIS(PrimaryBufferImpl,iface);
755 TRACE("(%p)->(%p)\n",This,caps);
757 if (caps == NULL)
758 return DSERR_INVALIDPARAM;
760 /* I think we should check this value, not set it. See */
761 /* Inside DirectX, p215. That should apply here, too. */
762 caps->dwSize = sizeof(*caps);
764 caps->dwFlags = This->dsbd.dwFlags;
765 if (This->dsound->hwbuf) caps->dwFlags |= DSBCAPS_LOCHARDWARE;
766 else caps->dwFlags |= DSBCAPS_LOCSOFTWARE;
768 caps->dwBufferBytes = This->dsound->buflen;
770 /* This value represents the speed of the "unlock" command.
771 As unlock is quite fast (it does not do anything), I put
772 4096 ko/s = 4 Mo / s */
773 /* FIXME: hwbuf speed */
774 caps->dwUnlockTransferRate = 4096;
775 caps->dwPlayCpuOverhead = 0;
777 return DS_OK;
780 static HRESULT WINAPI PrimaryBufferImpl_QueryInterface(
781 LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj
783 ICOM_THIS(PrimaryBufferImpl,iface);
785 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
787 if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
788 ERR("app requested IDirectSoundNotify on primary buffer\n");
789 /* should we support this? */
790 *ppobj = NULL;
791 return E_FAIL;
794 if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) {
795 ERR("app requested IDirectSound3DBuffer on primary buffer\n");
796 *ppobj = NULL;
797 return E_NOINTERFACE;
800 if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
801 if (!This->dsound->listener)
802 IDirectSound3DListenerImpl_Create(This, &This->dsound->listener);
803 *ppobj = This->dsound->listener;
804 if (This->dsound->listener) {
805 IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER)*ppobj);
806 return DS_OK;
808 return E_FAIL;
811 if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) {
812 #if 0
813 if (!This->iks)
814 IKsPropertySetImpl_Create(This, &This->iks);
815 *ppobj = This->iks;
816 if (*ppobj) {
817 IKsPropertySet_AddRef((LPKSPROPERTYSET)*ppobj);
818 return S_OK;
820 return E_FAIL;
821 #else
822 FIXME("app requested IKsPropertySet on primary buffer\n");
823 *ppobj = NULL;
824 return E_FAIL;
825 #endif
828 FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
830 *ppobj = NULL;
832 return E_NOINTERFACE;
835 static ICOM_VTABLE(IDirectSoundBuffer8) dspbvt =
837 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
838 PrimaryBufferImpl_QueryInterface,
839 PrimaryBufferImpl_AddRef,
840 PrimaryBufferImpl_Release,
841 PrimaryBufferImpl_GetCaps,
842 PrimaryBufferImpl_GetCurrentPosition,
843 PrimaryBufferImpl_GetFormat,
844 PrimaryBufferImpl_GetVolume,
845 PrimaryBufferImpl_GetPan,
846 PrimaryBufferImpl_GetFrequency,
847 PrimaryBufferImpl_GetStatus,
848 PrimaryBufferImpl_Initialize,
849 PrimaryBufferImpl_Lock,
850 PrimaryBufferImpl_Play,
851 PrimaryBufferImpl_SetCurrentPosition,
852 PrimaryBufferImpl_SetFormat,
853 PrimaryBufferImpl_SetVolume,
854 PrimaryBufferImpl_SetPan,
855 PrimaryBufferImpl_SetFrequency,
856 PrimaryBufferImpl_Stop,
857 PrimaryBufferImpl_Unlock,
858 PrimaryBufferImpl_Restore,
859 PrimaryBufferImpl_SetFX,
860 PrimaryBufferImpl_AcquireResources,
861 PrimaryBufferImpl_GetObjectInPath
864 HRESULT WINAPI PrimaryBuffer_Create(
865 IDirectSoundImpl *This,
866 PrimaryBufferImpl **pdsb,
867 LPDSBUFFERDESC dsbd)
869 PrimaryBufferImpl *dsb;
871 if (dsbd->lpwfxFormat)
872 return DSERR_INVALIDPARAM;
874 dsb = (PrimaryBufferImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
875 dsb->ref = 1;
876 dsb->dsound = This;
877 ICOM_VTBL(dsb) = &dspbvt;
879 memcpy(&dsb->dsbd, dsbd, sizeof(*dsbd));
881 TRACE("Created primary buffer at %p\n", dsb);
883 if (dsbd->dwFlags & DSBCAPS_CTRL3D) {
884 /* FIXME: IDirectSound3DListener */
887 IDirectSound8_AddRef((LPDIRECTSOUND8)This);
889 *pdsb = dsb;
890 return S_OK;