Commit | Line | Data |
---|---|---|
935e3df3 OK |
1 | /* DirectSound |
2 | * | |
3 | * Copyright 1998 Marcus Meissner | |
4 | * Copyright 1998 Rob Riggs | |
5 | * Copyright 2000-2002 TransGaming Technologies, Inc. | |
6 | * | |
7 | * This library is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU Lesser General Public | |
9 | * License as published by the Free Software Foundation; either | |
10 | * version 2.1 of the License, or (at your option) any later version. | |
11 | * | |
12 | * This library is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * Lesser General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU Lesser General Public | |
18 | * License along with this library; if not, write to the Free Software | |
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
20 | */ | |
21 | ||
22 | #include "config.h" | |
23 | #include <assert.h> | |
e37c6e18 | 24 | #include <stdarg.h> |
935e3df3 OK |
25 | #include <stdio.h> |
26 | #include <sys/types.h> | |
27 | #include <sys/fcntl.h> | |
d016f819 PS |
28 | #ifdef HAVE_UNISTD_H |
29 | # include <unistd.h> | |
30 | #endif | |
935e3df3 OK |
31 | #include <stdlib.h> |
32 | #include <string.h> | |
33 | #include <math.h> /* Insomnia - pow() function */ | |
34 | ||
35 | #include "windef.h" | |
36 | #include "winbase.h" | |
37 | #include "wingdi.h" | |
38 | #include "winuser.h" | |
39 | #include "winerror.h" | |
40 | #include "mmsystem.h" | |
e37c6e18 | 41 | #include "winreg.h" |
9c1de6de | 42 | #include "winternl.h" |
935e3df3 OK |
43 | #include "mmddk.h" |
44 | #include "wine/windef16.h" | |
45 | #include "wine/debug.h" | |
46 | #include "dsound.h" | |
47 | #include "dsdriver.h" | |
48 | #include "dsound_private.h" | |
49 | ||
50 | WINE_DEFAULT_DEBUG_CHANNEL(dsound); | |
51 | ||
935e3df3 OK |
52 | void DSOUND_RecalcPrimary(IDirectSoundImpl *This) |
53 | { | |
54 | DWORD sw; | |
772539a8 | 55 | TRACE("(%p)\n",This); |
935e3df3 OK |
56 | |
57 | sw = This->wfx.nChannels * (This->wfx.wBitsPerSample / 8); | |
58 | if (This->hwbuf) { | |
59 | DWORD fraglen; | |
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); | |
67 | } | |
68 | /* calculate the 10ms write lead */ | |
69 | This->writelead = (This->wfx.nSamplesPerSec / 100) * sw; | |
70 | } | |
71 | ||
72 | static HRESULT DSOUND_PrimaryOpen(IDirectSoundImpl *This) | |
73 | { | |
74 | HRESULT err = DS_OK; | |
772539a8 | 75 | TRACE("(%p)\n",This); |
935e3df3 | 76 | |
99b0e8fa RR |
77 | DSOUND_RecalcVolPan(&(This->volpan)); |
78 | ||
935e3df3 | 79 | /* are we using waveOut stuff? */ |
41b89ddd | 80 | if (!This->driver) { |
935e3df3 OK |
81 | LPBYTE newbuf; |
82 | DWORD buflen; | |
83 | HRESULT merr = DS_OK; | |
84 | /* Start in pause mode, to allow buffers to get filled */ | |
85 | waveOutPause(This->hwo); | |
86 | if (This->state == STATE_PLAYING) This->state = STATE_STARTING; | |
87 | else if (This->state == STATE_STOPPING) This->state = STATE_STOPPED; | |
88 | /* use fragments of 10ms (1/100s) each (which should get us within | |
89 | * the documented write cursor lead of 10-15ms) */ | |
90 | buflen = ((This->wfx.nAvgBytesPerSec / 100) & ~3) * DS_HEL_FRAGS; | |
91 | TRACE("desired buflen=%ld, old buffer=%p\n", buflen, This->buffer); | |
92 | /* reallocate emulated primary buffer */ | |
de12a970 OP |
93 | |
94 | if (This->buffer) | |
95 | newbuf = (LPBYTE)HeapReAlloc(GetProcessHeap(),0,This->buffer,buflen); | |
96 | else | |
97 | newbuf = (LPBYTE)HeapAlloc(GetProcessHeap(),0,buflen); | |
98 | ||
935e3df3 OK |
99 | if (newbuf == NULL) { |
100 | ERR("failed to allocate primary buffer\n"); | |
101 | merr = DSERR_OUTOFMEMORY; | |
32140ade | 102 | /* but the old buffer might still exist and must be re-prepared */ |
935e3df3 OK |
103 | } else { |
104 | This->buffer = newbuf; | |
105 | This->buflen = buflen; | |
106 | } | |
107 | if (This->buffer) { | |
108 | unsigned c; | |
109 | ||
110 | This->fraglen = This->buflen / DS_HEL_FRAGS; | |
111 | ||
112 | /* prepare fragment headers */ | |
113 | for (c=0; c<DS_HEL_FRAGS; c++) { | |
114 | This->pwave[c]->lpData = This->buffer + c*This->fraglen; | |
115 | This->pwave[c]->dwBufferLength = This->fraglen; | |
116 | This->pwave[c]->dwUser = (DWORD)This; | |
117 | This->pwave[c]->dwFlags = 0; | |
118 | This->pwave[c]->dwLoops = 0; | |
119 | err = mmErr(waveOutPrepareHeader(This->hwo,This->pwave[c],sizeof(WAVEHDR))); | |
120 | if (err != DS_OK) { | |
121 | while (c--) | |
122 | waveOutUnprepareHeader(This->hwo,This->pwave[c],sizeof(WAVEHDR)); | |
123 | break; | |
124 | } | |
125 | } | |
126 | ||
127 | This->pwplay = 0; | |
128 | This->pwwrite = 0; | |
129 | This->pwqueue = 0; | |
a4ed8e77 RR |
130 | This->playpos = 0; |
131 | This->mixpos = 0; | |
935e3df3 OK |
132 | memset(This->buffer, (This->wfx.wBitsPerSample == 16) ? 0 : 128, This->buflen); |
133 | TRACE("fraglen=%ld\n", This->fraglen); | |
134 | DSOUND_WaveQueue(This, (DWORD)-1); | |
135 | } | |
136 | if ((err == DS_OK) && (merr != DS_OK)) | |
137 | err = merr; | |
99b0e8fa RR |
138 | |
139 | if (!err) { | |
140 | DWORD vol = (This->volpan.dwTotalLeftAmpFactor & 0xffff) | (This->volpan.dwTotalRightAmpFactor << 16); | |
141 | err = mmErr(waveOutSetVolume(This->hwo, vol)); | |
142 | } | |
143 | } else { | |
41b89ddd RR |
144 | if (!This->hwbuf) { |
145 | err = IDsDriver_CreateSoundBuffer(This->driver,&(This->wfx), | |
146 | DSBCAPS_PRIMARYBUFFER,0, | |
147 | &(This->buflen),&(This->buffer), | |
148 | (LPVOID*)&(This->hwbuf)); | |
149 | if (err != DS_OK) { | |
150 | WARN("IDsDriver_CreateSoundBuffer failed\n"); | |
151 | return err; | |
152 | } | |
153 | ||
154 | if (dsound->state == STATE_PLAYING) dsound->state = STATE_STARTING; | |
155 | else if (dsound->state == STATE_STOPPING) dsound->state = STATE_STOPPED; | |
156 | } | |
99b0e8fa | 157 | err = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan)); |
935e3df3 | 158 | } |
99b0e8fa | 159 | |
935e3df3 OK |
160 | return err; |
161 | } | |
162 | ||
163 | ||
164 | static void DSOUND_PrimaryClose(IDirectSoundImpl *This) | |
165 | { | |
772539a8 RR |
166 | TRACE("(%p)\n",This); |
167 | ||
935e3df3 OK |
168 | /* are we using waveOut stuff? */ |
169 | if (!This->hwbuf) { | |
170 | unsigned c; | |
171 | ||
172 | This->pwqueue = (DWORD)-1; /* resetting queues */ | |
173 | waveOutReset(This->hwo); | |
174 | for (c=0; c<DS_HEL_FRAGS; c++) | |
175 | waveOutUnprepareHeader(This->hwo, This->pwave[c], sizeof(WAVEHDR)); | |
176 | This->pwqueue = 0; | |
41b89ddd RR |
177 | } else { |
178 | if (IDsDriverBuffer_Release(This->hwbuf) == 0) | |
179 | This->hwbuf = 0; | |
935e3df3 OK |
180 | } |
181 | } | |
182 | ||
183 | HRESULT DSOUND_PrimaryCreate(IDirectSoundImpl *This) | |
184 | { | |
185 | HRESULT err = DS_OK; | |
772539a8 | 186 | TRACE("(%p)\n",This); |
935e3df3 OK |
187 | |
188 | This->buflen = This->wfx.nAvgBytesPerSec; | |
189 | ||
190 | /* FIXME: verify that hardware capabilities (DSCAPS_PRIMARY flags) match */ | |
191 | ||
192 | if (This->driver) { | |
193 | err = IDsDriver_CreateSoundBuffer(This->driver,&(This->wfx), | |
194 | DSBCAPS_PRIMARYBUFFER,0, | |
195 | &(This->buflen),&(This->buffer), | |
196 | (LPVOID*)&(This->hwbuf)); | |
a4ed8e77 RR |
197 | if (err != DS_OK) { |
198 | WARN("IDsDriver_CreateSoundBuffer failed\n"); | |
199 | return err; | |
200 | } | |
935e3df3 | 201 | } |
6bbce6cd FG |
202 | if (!This->hwbuf) { |
203 | /* Allocate memory for HEL buffer headers */ | |
204 | unsigned c; | |
205 | for (c=0; c<DS_HEL_FRAGS; c++) { | |
206 | This->pwave[c] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(WAVEHDR)); | |
207 | if (!This->pwave[c]) { | |
208 | /* Argh, out of memory */ | |
209 | while (c--) { | |
210 | HeapFree(GetProcessHeap(),0,This->pwave[c]); | |
211 | } | |
a4ed8e77 RR |
212 | WARN("out of memory\n"); |
213 | return DSERR_OUTOFMEMORY; | |
6bbce6cd FG |
214 | } |
215 | } | |
216 | } | |
a4ed8e77 RR |
217 | |
218 | err = DSOUND_PrimaryOpen(This); | |
219 | ||
220 | if (err != DS_OK) { | |
221 | WARN("DSOUND_PrimaryOpen failed\n"); | |
935e3df3 | 222 | return err; |
a4ed8e77 RR |
223 | } |
224 | ||
935e3df3 OK |
225 | /* calculate fragment size and write lead */ |
226 | DSOUND_RecalcPrimary(This); | |
227 | This->state = STATE_STOPPED; | |
228 | return DS_OK; | |
229 | } | |
230 | ||
231 | HRESULT DSOUND_PrimaryDestroy(IDirectSoundImpl *This) | |
232 | { | |
772539a8 RR |
233 | TRACE("(%p)\n",This); |
234 | ||
935e3df3 | 235 | DSOUND_PrimaryClose(This); |
41b89ddd RR |
236 | if (This->driver) { |
237 | if (This->hwbuf) { | |
238 | if (IDsDriverBuffer_Release(This->hwbuf) == 0) | |
239 | This->hwbuf = 0; | |
240 | } | |
6bbce6cd FG |
241 | } else { |
242 | unsigned c; | |
243 | for (c=0; c<DS_HEL_FRAGS; c++) { | |
244 | HeapFree(GetProcessHeap(),0,This->pwave[c]); | |
245 | } | |
935e3df3 OK |
246 | } |
247 | return DS_OK; | |
248 | } | |
249 | ||
250 | HRESULT DSOUND_PrimaryPlay(IDirectSoundImpl *This) | |
251 | { | |
252 | HRESULT err = DS_OK; | |
772539a8 RR |
253 | TRACE("(%p)\n",This); |
254 | ||
a4ed8e77 | 255 | if (This->hwbuf) { |
935e3df3 | 256 | err = IDsDriverBuffer_Play(This->hwbuf, 0, 0, DSBPLAY_LOOPING); |
a4ed8e77 RR |
257 | if (err != DS_OK) |
258 | WARN("IDsDriverBuffer_Play failed\n"); | |
259 | } else { | |
935e3df3 | 260 | err = mmErr(waveOutRestart(This->hwo)); |
a4ed8e77 RR |
261 | if (err != DS_OK) |
262 | WARN("waveOutRestart failed\n"); | |
263 | } | |
264 | ||
935e3df3 OK |
265 | return err; |
266 | } | |
267 | ||
268 | HRESULT DSOUND_PrimaryStop(IDirectSoundImpl *This) | |
269 | { | |
270 | HRESULT err = DS_OK; | |
772539a8 | 271 | TRACE("(%p)\n",This); |
935e3df3 OK |
272 | |
273 | if (This->hwbuf) { | |
274 | err = IDsDriverBuffer_Stop(This->hwbuf); | |
275 | if (err == DSERR_BUFFERLOST) { | |
8c2ec131 RR |
276 | DWORD flags = CALLBACK_FUNCTION; |
277 | if (ds_hw_accel != DS_HW_ACCEL_EMULATION) | |
278 | flags |= WAVE_DIRECTSOUND; | |
935e3df3 OK |
279 | /* Wine-only: the driver wants us to reopen the device */ |
280 | /* FIXME: check for errors */ | |
281 | IDsDriverBuffer_Release(This->hwbuf); | |
282 | waveOutClose(This->hwo); | |
283 | This->hwo = 0; | |
284 | err = mmErr(waveOutOpen(&(This->hwo), This->drvdesc.dnDevNode, | |
285 | &(This->wfx), (DWORD)DSOUND_callback, (DWORD)This, | |
8c2ec131 | 286 | flags)); |
a4ed8e77 | 287 | if (err == DS_OK) { |
935e3df3 OK |
288 | err = IDsDriver_CreateSoundBuffer(This->driver,&(This->wfx), |
289 | DSBCAPS_PRIMARYBUFFER,0, | |
290 | &(This->buflen),&(This->buffer), | |
291 | (LPVOID)&(This->hwbuf)); | |
a4ed8e77 RR |
292 | if (err != DS_OK) |
293 | WARN("IDsDriver_CreateSoundBuffer failed\n"); | |
294 | } else { | |
295 | WARN("waveOutOpen failed\n"); | |
296 | } | |
297 | } else if (err != DS_OK) { | |
298 | WARN("IDsDriverBuffer_Stop failed\n"); | |
935e3df3 | 299 | } |
a4ed8e77 | 300 | } else { |
935e3df3 | 301 | err = mmErr(waveOutPause(This->hwo)); |
a4ed8e77 RR |
302 | if (err != DS_OK) |
303 | WARN("waveOutPause failed\n"); | |
304 | } | |
935e3df3 OK |
305 | return err; |
306 | } | |
307 | ||
308 | HRESULT DSOUND_PrimaryGetPosition(IDirectSoundImpl *This, LPDWORD playpos, LPDWORD writepos) | |
309 | { | |
772539a8 RR |
310 | TRACE("(%p,%p,%p)\n",This,playpos,writepos); |
311 | ||
935e3df3 OK |
312 | if (This->hwbuf) { |
313 | HRESULT err=IDsDriverBuffer_GetPosition(This->hwbuf,playpos,writepos); | |
a4ed8e77 RR |
314 | if (err) { |
315 | WARN("IDsDriverBuffer_GetPosition failed\n"); | |
316 | return err; | |
317 | } | |
935e3df3 OK |
318 | } |
319 | else { | |
320 | if (playpos) { | |
321 | MMTIME mtime; | |
322 | mtime.wType = TIME_BYTES; | |
323 | waveOutGetPosition(This->hwo, &mtime, sizeof(mtime)); | |
324 | mtime.u.cb = mtime.u.cb % This->buflen; | |
325 | *playpos = mtime.u.cb; | |
326 | } | |
327 | if (writepos) { | |
328 | /* the writepos should only be used by apps with WRITEPRIMARY priority, | |
329 | * in which case our software mixer is disabled anyway */ | |
330 | *writepos = (This->pwplay + ds_hel_margin) * This->fraglen; | |
331 | while (*writepos >= This->buflen) | |
332 | *writepos -= This->buflen; | |
333 | } | |
334 | } | |
335 | TRACE("playpos = %ld, writepos = %ld (%p, time=%ld)\n", playpos?*playpos:0, writepos?*writepos:0, This, GetTickCount()); | |
336 | return DS_OK; | |
337 | } | |
338 | ||
339 | ||
340 | /******************************************************************************* | |
5ec32cec | 341 | * PrimaryBuffer |
935e3df3 OK |
342 | */ |
343 | /* This sets this format for the <em>Primary Buffer Only</em> */ | |
344 | /* See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 120 */ | |
345 | static HRESULT WINAPI PrimaryBufferImpl_SetFormat( | |
7dd63746 | 346 | LPDIRECTSOUNDBUFFER8 iface,LPCWAVEFORMATEX wfex |
935e3df3 OK |
347 | ) { |
348 | ICOM_THIS(PrimaryBufferImpl,iface); | |
349 | IDirectSoundImpl* dsound = This->dsound; | |
935e3df3 OK |
350 | HRESULT err = DS_OK; |
351 | int i; | |
772539a8 | 352 | TRACE("(%p,%p)\n",This,wfex); |
935e3df3 OK |
353 | |
354 | if (This->dsound->priolevel == DSSCL_NORMAL) { | |
a4ed8e77 | 355 | WARN("failed priority check!\n"); |
935e3df3 OK |
356 | return DSERR_PRIOLEVELNEEDED; |
357 | } | |
358 | ||
359 | /* Let's be pedantic! */ | |
32140ade | 360 | if (wfex == NULL) { |
a4ed8e77 | 361 | WARN("invalid parameter: wfex==NULL!\n"); |
32140ade FG |
362 | return DSERR_INVALIDPARAM; |
363 | } | |
364 | TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld," | |
365 | "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n", | |
366 | wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec, | |
367 | wfex->nAvgBytesPerSec, wfex->nBlockAlign, | |
368 | wfex->wBitsPerSample, wfex->cbSize); | |
369 | ||
370 | if ((wfex->wFormatTag != WAVE_FORMAT_PCM) || | |
935e3df3 OK |
371 | (wfex->nChannels < 1) || (wfex->nChannels > 2) || |
372 | (wfex->nSamplesPerSec < 1) || | |
935e3df3 | 373 | ((wfex->wBitsPerSample != 8) && (wfex->wBitsPerSample != 16))) { |
a4ed8e77 | 374 | WARN("invalid paramemer: unsupported format!\n"); |
935e3df3 OK |
375 | return DSERR_INVALIDPARAM; |
376 | } | |
377 | ||
378 | /* **** */ | |
379 | RtlAcquireResourceExclusive(&(dsound->lock), TRUE); | |
380 | ||
32140ade FG |
381 | dsound->wfx.nSamplesPerSec = wfex->nSamplesPerSec; |
382 | dsound->wfx.nChannels = wfex->nChannels; | |
383 | dsound->wfx.wBitsPerSample = wfex->wBitsPerSample; | |
384 | dsound->wfx.nBlockAlign = dsound->wfx.wBitsPerSample / 8 * dsound->wfx.nChannels; | |
935e3df3 OK |
385 | dsound->wfx.nAvgBytesPerSec = |
386 | dsound->wfx.nSamplesPerSec * dsound->wfx.nBlockAlign; | |
387 | ||
388 | if (dsound->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMSETFORMAT) { | |
8c2ec131 RR |
389 | DWORD flags = CALLBACK_FUNCTION; |
390 | if (ds_hw_accel != DS_HW_ACCEL_EMULATION) | |
391 | flags |= WAVE_DIRECTSOUND; | |
935e3df3 OK |
392 | /* FIXME: check for errors */ |
393 | DSOUND_PrimaryClose(dsound); | |
394 | waveOutClose(dsound->hwo); | |
395 | dsound->hwo = 0; | |
396 | err = mmErr(waveOutOpen(&(dsound->hwo), dsound->drvdesc.dnDevNode, | |
397 | &(dsound->wfx), (DWORD)DSOUND_callback, (DWORD)dsound, | |
8c2ec131 | 398 | flags)); |
a4ed8e77 RR |
399 | if (err == DS_OK) { |
400 | err = DSOUND_PrimaryOpen(dsound); | |
401 | if (err != DS_OK) { | |
402 | WARN("DSOUND_PrimaryOpen failed\n"); | |
403 | RtlReleaseResource(&(dsound->lock)); | |
404 | return err; | |
405 | } | |
406 | } else { | |
407 | WARN("waveOutOpen failed\n"); | |
408 | RtlReleaseResource(&(dsound->lock)); | |
409 | return err; | |
410 | } | |
41b89ddd | 411 | } else if (dsound->hwbuf) { |
935e3df3 OK |
412 | err = IDsDriverBuffer_SetFormat(dsound->hwbuf, &(dsound->wfx)); |
413 | if (err == DSERR_BUFFERLOST) { | |
414 | /* Wine-only: the driver wants us to recreate the HW buffer */ | |
415 | IDsDriverBuffer_Release(dsound->hwbuf); | |
416 | err = IDsDriver_CreateSoundBuffer(dsound->driver,&(dsound->wfx), | |
417 | DSBCAPS_PRIMARYBUFFER,0, | |
418 | &(dsound->buflen),&(dsound->buffer), | |
419 | (LPVOID)&(dsound->hwbuf)); | |
a4ed8e77 RR |
420 | if (err != DS_OK) { |
421 | WARN("IDsDriver_CreateSoundBuffer failed\n"); | |
422 | RtlReleaseResource(&(dsound->lock)); | |
423 | return err; | |
424 | } | |
935e3df3 OK |
425 | if (dsound->state == STATE_PLAYING) dsound->state = STATE_STARTING; |
426 | else if (dsound->state == STATE_STOPPING) dsound->state = STATE_STOPPED; | |
a4ed8e77 RR |
427 | } else { |
428 | WARN("IDsDriverBuffer_SetFormat failed\n"); | |
429 | RtlReleaseResource(&(dsound->lock)); | |
430 | return err; | |
935e3df3 OK |
431 | } |
432 | /* FIXME: should we set err back to DS_OK in all cases ? */ | |
433 | } | |
434 | DSOUND_RecalcPrimary(dsound); | |
435 | ||
2ea305b0 RR |
436 | if (dsound->wfx.nSamplesPerSec != wfex->nSamplesPerSec) { |
437 | IDirectSoundBufferImpl** dsb = dsound->buffers; | |
438 | for (i = 0; i < dsound->nrofbuffers; i++, dsb++) { | |
439 | /* **** */ | |
440 | EnterCriticalSection(&((*dsb)->lock)); | |
441 | ||
442 | (*dsb)->freqAdjust = ((*dsb)->freq << DSOUND_FREQSHIFT) / | |
443 | wfex->nSamplesPerSec; | |
444 | ||
445 | LeaveCriticalSection(&((*dsb)->lock)); | |
446 | /* **** */ | |
447 | } | |
448 | } | |
449 | ||
935e3df3 OK |
450 | RtlReleaseResource(&(dsound->lock)); |
451 | /* **** */ | |
452 | ||
453 | return err; | |
454 | } | |
455 | ||
456 | static HRESULT WINAPI PrimaryBufferImpl_SetVolume( | |
457 | LPDIRECTSOUNDBUFFER8 iface,LONG vol | |
458 | ) { | |
459 | ICOM_THIS(PrimaryBufferImpl,iface); | |
460 | IDirectSoundImpl* dsound = This->dsound; | |
461 | LONG oldVol; | |
462 | ||
463 | TRACE("(%p,%ld)\n",This,vol); | |
464 | ||
9dacf206 | 465 | if (!(This->dsound->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) { |
a4ed8e77 | 466 | WARN("control unavailable\n"); |
935e3df3 | 467 | return DSERR_CONTROLUNAVAIL; |
a4ed8e77 | 468 | } |
935e3df3 | 469 | |
a4ed8e77 RR |
470 | if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN)) { |
471 | WARN("invalid parameter: vol = %ld\n", vol); | |
935e3df3 | 472 | return DSERR_INVALIDPARAM; |
a4ed8e77 | 473 | } |
935e3df3 OK |
474 | |
475 | /* **** */ | |
476 | EnterCriticalSection(&(dsound->mixlock)); | |
477 | ||
478 | oldVol = dsound->volpan.lVolume; | |
479 | dsound->volpan.lVolume = vol; | |
480 | DSOUND_RecalcVolPan(&dsound->volpan); | |
481 | ||
482 | if (vol != oldVol) { | |
483 | if (dsound->hwbuf) { | |
a4ed8e77 RR |
484 | HRESULT hres; |
485 | hres = IDsDriverBuffer_SetVolumePan(dsound->hwbuf, &(dsound->volpan)); | |
486 | if (hres != DS_OK) { | |
487 | LeaveCriticalSection(&(dsound->mixlock)); | |
488 | WARN("IDsDriverBuffer_SetVolumePan failed\n"); | |
489 | return hres; | |
490 | } | |
99b0e8fa RR |
491 | } else { |
492 | DWORD vol = (dsound->volpan.dwTotalLeftAmpFactor & 0xffff) | (dsound->volpan.dwTotalRightAmpFactor << 16); | |
935e3df3 | 493 | waveOutSetVolume(dsound->hwo, vol); |
935e3df3 OK |
494 | } |
495 | } | |
496 | ||
497 | LeaveCriticalSection(&(dsound->mixlock)); | |
498 | /* **** */ | |
499 | ||
500 | return DS_OK; | |
501 | } | |
502 | ||
503 | static HRESULT WINAPI PrimaryBufferImpl_GetVolume( | |
504 | LPDIRECTSOUNDBUFFER8 iface,LPLONG vol | |
505 | ) { | |
506 | ICOM_THIS(PrimaryBufferImpl,iface); | |
507 | TRACE("(%p,%p)\n",This,vol); | |
508 | ||
9dacf206 RR |
509 | if (!(This->dsound->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) { |
510 | WARN("control unavailable\n"); | |
511 | return DSERR_CONTROLUNAVAIL; | |
512 | } | |
513 | ||
a4ed8e77 RR |
514 | if (vol == NULL) { |
515 | WARN("invalid parameter: vol = NULL\n"); | |
935e3df3 | 516 | return DSERR_INVALIDPARAM; |
a4ed8e77 | 517 | } |
935e3df3 OK |
518 | |
519 | *vol = This->dsound->volpan.lVolume; | |
520 | return DS_OK; | |
521 | } | |
522 | ||
523 | static HRESULT WINAPI PrimaryBufferImpl_SetFrequency( | |
524 | LPDIRECTSOUNDBUFFER8 iface,DWORD freq | |
525 | ) { | |
526 | ICOM_THIS(PrimaryBufferImpl,iface); | |
527 | ||
528 | TRACE("(%p,%ld)\n",This,freq); | |
529 | ||
530 | /* You cannot set the frequency of the primary buffer */ | |
a4ed8e77 | 531 | WARN("control unavailable\n"); |
935e3df3 OK |
532 | return DSERR_CONTROLUNAVAIL; |
533 | } | |
534 | ||
535 | static HRESULT WINAPI PrimaryBufferImpl_Play( | |
536 | LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags | |
537 | ) { | |
538 | ICOM_THIS(PrimaryBufferImpl,iface); | |
539 | IDirectSoundImpl* dsound = This->dsound; | |
540 | ||
541 | TRACE("(%p,%08lx,%08lx,%08lx)\n", | |
542 | This,reserved1,reserved2,flags | |
543 | ); | |
544 | ||
a4ed8e77 RR |
545 | if (!(flags & DSBPLAY_LOOPING)) { |
546 | WARN("invalid parameter: flags = %08lx\n", flags); | |
935e3df3 | 547 | return DSERR_INVALIDPARAM; |
a4ed8e77 | 548 | } |
935e3df3 OK |
549 | |
550 | /* **** */ | |
551 | EnterCriticalSection(&(dsound->mixlock)); | |
552 | ||
553 | if (dsound->state == STATE_STOPPED) | |
554 | dsound->state = STATE_STARTING; | |
555 | else if (dsound->state == STATE_STOPPING) | |
556 | dsound->state = STATE_PLAYING; | |
557 | ||
558 | LeaveCriticalSection(&(dsound->mixlock)); | |
559 | /* **** */ | |
560 | ||
561 | return DS_OK; | |
562 | } | |
563 | ||
564 | static HRESULT WINAPI PrimaryBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface) | |
565 | { | |
566 | ICOM_THIS(PrimaryBufferImpl,iface); | |
567 | IDirectSoundImpl* dsound = This->dsound; | |
568 | ||
569 | TRACE("(%p)\n",This); | |
570 | ||
571 | /* **** */ | |
572 | EnterCriticalSection(&(dsound->mixlock)); | |
573 | ||
574 | if (dsound->state == STATE_PLAYING) | |
575 | dsound->state = STATE_STOPPING; | |
576 | else if (dsound->state == STATE_STARTING) | |
577 | dsound->state = STATE_STOPPED; | |
578 | ||
579 | LeaveCriticalSection(&(dsound->mixlock)); | |
580 | /* **** */ | |
581 | ||
582 | return DS_OK; | |
583 | } | |
584 | ||
585 | static DWORD WINAPI PrimaryBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface) { | |
586 | ICOM_THIS(PrimaryBufferImpl,iface); | |
587 | DWORD ref; | |
588 | ||
9dacf206 | 589 | TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId()); |
935e3df3 | 590 | ref = InterlockedIncrement(&(This->ref)); |
9dacf206 | 591 | |
935e3df3 OK |
592 | return ref; |
593 | } | |
9dacf206 | 594 | |
935e3df3 OK |
595 | static DWORD WINAPI PrimaryBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface) { |
596 | ICOM_THIS(PrimaryBufferImpl,iface); | |
597 | DWORD ref; | |
598 | ||
9dacf206 | 599 | TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId()); |
935e3df3 | 600 | ref = InterlockedDecrement(&(This->ref)); |
935e3df3 | 601 | |
5ec32cec | 602 | if (ref == 0) { |
9dacf206 | 603 | This->dsound->primary = NULL; |
5ec32cec | 604 | IDirectSound_Release((LPDIRECTSOUND)This->dsound); |
a4ed8e77 | 605 | HeapFree(GetProcessHeap(),0,This); |
5ec32cec | 606 | TRACE("(%p) released\n",This); |
a4ed8e77 | 607 | } |
935e3df3 | 608 | |
a4ed8e77 | 609 | return ref; |
935e3df3 OK |
610 | } |
611 | ||
612 | static HRESULT WINAPI PrimaryBufferImpl_GetCurrentPosition( | |
613 | LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos | |
614 | ) { | |
a4ed8e77 | 615 | HRESULT hres; |
935e3df3 OK |
616 | ICOM_THIS(PrimaryBufferImpl,iface); |
617 | IDirectSoundImpl* dsound = This->dsound; | |
618 | ||
619 | TRACE("(%p,%p,%p)\n",This,playpos,writepos); | |
a4ed8e77 RR |
620 | hres = DSOUND_PrimaryGetPosition(dsound, playpos, writepos); |
621 | if (hres != DS_OK) { | |
622 | WARN("DSOUND_PrimaryGetPosition failed\n"); | |
623 | return hres; | |
624 | } | |
935e3df3 OK |
625 | if (writepos) { |
626 | if (dsound->state != STATE_STOPPED) | |
627 | /* apply the documented 10ms lead to writepos */ | |
628 | *writepos += dsound->writelead; | |
629 | while (*writepos >= dsound->buflen) *writepos -= dsound->buflen; | |
630 | } | |
631 | TRACE("playpos = %ld, writepos = %ld (%p, time=%ld)\n", playpos?*playpos:0, writepos?*writepos:0, This, GetTickCount()); | |
632 | return DS_OK; | |
633 | } | |
634 | ||
635 | static HRESULT WINAPI PrimaryBufferImpl_GetStatus( | |
636 | LPDIRECTSOUNDBUFFER8 iface,LPDWORD status | |
637 | ) { | |
638 | ICOM_THIS(PrimaryBufferImpl,iface); | |
9dacf206 | 639 | TRACE("(%p,%p), thread is %04lx\n",This,status,GetCurrentThreadId()); |
935e3df3 | 640 | |
a4ed8e77 RR |
641 | if (status == NULL) { |
642 | WARN("invalid parameter: status == NULL\n"); | |
935e3df3 | 643 | return DSERR_INVALIDPARAM; |
a4ed8e77 | 644 | } |
935e3df3 OK |
645 | |
646 | *status = 0; | |
647 | if ((This->dsound->state == STATE_STARTING) || | |
648 | (This->dsound->state == STATE_PLAYING)) | |
649 | *status |= DSBSTATUS_PLAYING | DSBSTATUS_LOOPING; | |
650 | ||
651 | TRACE("status=%lx\n", *status); | |
652 | return DS_OK; | |
653 | } | |
654 | ||
655 | ||
656 | static HRESULT WINAPI PrimaryBufferImpl_GetFormat( | |
657 | LPDIRECTSOUNDBUFFER8 iface,LPWAVEFORMATEX lpwf,DWORD wfsize,LPDWORD wfwritten | |
658 | ) { | |
659 | ICOM_THIS(PrimaryBufferImpl,iface); | |
660 | TRACE("(%p,%p,%ld,%p)\n",This,lpwf,wfsize,wfwritten); | |
661 | ||
662 | if (wfsize>sizeof(This->dsound->wfx)) | |
663 | wfsize = sizeof(This->dsound->wfx); | |
664 | if (lpwf) { /* NULL is valid */ | |
665 | memcpy(lpwf,&(This->dsound->wfx),wfsize); | |
666 | if (wfwritten) | |
667 | *wfwritten = wfsize; | |
a4ed8e77 | 668 | } else { |
935e3df3 OK |
669 | if (wfwritten) |
670 | *wfwritten = sizeof(This->dsound->wfx); | |
a4ed8e77 RR |
671 | else { |
672 | WARN("invalid parameter: wfwritten == NULL\n"); | |
935e3df3 | 673 | return DSERR_INVALIDPARAM; |
a4ed8e77 RR |
674 | } |
675 | } | |
935e3df3 OK |
676 | |
677 | return DS_OK; | |
678 | } | |
679 | ||
680 | static HRESULT WINAPI PrimaryBufferImpl_Lock( | |
681 | LPDIRECTSOUNDBUFFER8 iface,DWORD writecursor,DWORD writebytes,LPVOID lplpaudioptr1,LPDWORD audiobytes1,LPVOID lplpaudioptr2,LPDWORD audiobytes2,DWORD flags | |
682 | ) { | |
683 | ICOM_THIS(PrimaryBufferImpl,iface); | |
684 | IDirectSoundImpl* dsound = This->dsound; | |
685 | ||
686 | TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx) at %ld\n", | |
687 | This, | |
688 | writecursor, | |
689 | writebytes, | |
690 | lplpaudioptr1, | |
691 | audiobytes1, | |
692 | lplpaudioptr2, | |
693 | audiobytes2, | |
694 | flags, | |
695 | GetTickCount() | |
696 | ); | |
697 | ||
a4ed8e77 RR |
698 | if (dsound->priolevel != DSSCL_WRITEPRIMARY) { |
699 | WARN("failed priority check!\n"); | |
935e3df3 | 700 | return DSERR_PRIOLEVELNEEDED; |
a4ed8e77 | 701 | } |
935e3df3 OK |
702 | |
703 | if (flags & DSBLOCK_FROMWRITECURSOR) { | |
704 | DWORD writepos; | |
a4ed8e77 | 705 | HRESULT hres; |
935e3df3 | 706 | /* GetCurrentPosition does too much magic to duplicate here */ |
a4ed8e77 RR |
707 | hres = IDirectSoundBuffer_GetCurrentPosition(iface, NULL, &writepos); |
708 | if (hres != DS_OK) { | |
709 | WARN("IDirectSoundBuffer_GetCurrentPosition failed\n"); | |
710 | return hres; | |
711 | } | |
935e3df3 OK |
712 | writecursor += writepos; |
713 | } | |
714 | while (writecursor >= dsound->buflen) | |
715 | writecursor -= dsound->buflen; | |
716 | if (flags & DSBLOCK_ENTIREBUFFER) | |
717 | writebytes = dsound->buflen; | |
718 | if (writebytes > dsound->buflen) | |
719 | writebytes = dsound->buflen; | |
720 | ||
721 | assert(audiobytes1!=audiobytes2); | |
722 | assert(lplpaudioptr1!=lplpaudioptr2); | |
723 | ||
724 | if (!(dsound->drvdesc.dwFlags & DSDDESC_DONTNEEDPRIMARYLOCK) && dsound->hwbuf) { | |
a4ed8e77 RR |
725 | HRESULT hres; |
726 | hres = IDsDriverBuffer_Lock(dsound->hwbuf, | |
727 | lplpaudioptr1, audiobytes1, | |
728 | lplpaudioptr2, audiobytes2, | |
729 | writecursor, writebytes, | |
730 | 0); | |
731 | if (hres != DS_OK) { | |
732 | WARN("IDsDriverBuffer_Lock failed\n"); | |
733 | return hres; | |
734 | } | |
735 | } else { | |
935e3df3 OK |
736 | if (writecursor+writebytes <= dsound->buflen) { |
737 | *(LPBYTE*)lplpaudioptr1 = dsound->buffer+writecursor; | |
738 | *audiobytes1 = writebytes; | |
739 | if (lplpaudioptr2) | |
740 | *(LPBYTE*)lplpaudioptr2 = NULL; | |
741 | if (audiobytes2) | |
742 | *audiobytes2 = 0; | |
743 | TRACE("->%ld.0\n",writebytes); | |
744 | } else { | |
745 | *(LPBYTE*)lplpaudioptr1 = dsound->buffer+writecursor; | |
746 | *audiobytes1 = dsound->buflen-writecursor; | |
747 | if (lplpaudioptr2) | |
748 | *(LPBYTE*)lplpaudioptr2 = dsound->buffer; | |
749 | if (audiobytes2) | |
750 | *audiobytes2 = writebytes-(dsound->buflen-writecursor); | |
751 | TRACE("->%ld.%ld\n",*audiobytes1,audiobytes2?*audiobytes2:0); | |
752 | } | |
753 | } | |
754 | return DS_OK; | |
755 | } | |
756 | ||
757 | static HRESULT WINAPI PrimaryBufferImpl_SetCurrentPosition( | |
758 | LPDIRECTSOUNDBUFFER8 iface,DWORD newpos | |
759 | ) { | |
760 | ICOM_THIS(PrimaryBufferImpl,iface); | |
761 | TRACE("(%p,%ld)\n",This,newpos); | |
762 | ||
763 | /* You cannot set the position of the primary buffer */ | |
a4ed8e77 | 764 | WARN("invalid call\n"); |
935e3df3 OK |
765 | return DSERR_INVALIDCALL; |
766 | } | |
767 | ||
768 | static HRESULT WINAPI PrimaryBufferImpl_SetPan( | |
769 | LPDIRECTSOUNDBUFFER8 iface,LONG pan | |
770 | ) { | |
771 | ICOM_THIS(PrimaryBufferImpl,iface); | |
725d8c39 RR |
772 | IDirectSoundImpl* dsound = This->dsound; |
773 | LONG oldPan; | |
774 | ||
935e3df3 OK |
775 | TRACE("(%p,%ld)\n",This,pan); |
776 | ||
725d8c39 RR |
777 | if (!(This->dsound->dsbd.dwFlags & DSBCAPS_CTRLPAN)) { |
778 | WARN("control unavailable\n"); | |
779 | return DSERR_CONTROLUNAVAIL; | |
780 | } | |
781 | ||
782 | if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT)) { | |
783 | WARN("invalid parameter: pan = %ld\n", pan); | |
784 | return DSERR_INVALIDPARAM; | |
785 | } | |
786 | ||
787 | /* **** */ | |
788 | EnterCriticalSection(&(dsound->mixlock)); | |
789 | ||
790 | oldPan = dsound->volpan.lPan; | |
791 | dsound->volpan.lPan = pan; | |
792 | DSOUND_RecalcVolPan(&dsound->volpan); | |
793 | ||
794 | if (pan != oldPan) { | |
795 | if (dsound->hwbuf) { | |
796 | HRESULT hres; | |
797 | hres = IDsDriverBuffer_SetVolumePan(dsound->hwbuf, &(dsound->volpan)); | |
798 | if (hres != DS_OK) { | |
799 | LeaveCriticalSection(&(dsound->mixlock)); | |
800 | WARN("IDsDriverBuffer_SetVolumePan failed\n"); | |
801 | return hres; | |
802 | } | |
803 | } | |
804 | else { | |
99b0e8fa | 805 | DWORD vol = (dsound->volpan.dwTotalLeftAmpFactor & 0xffff) | (dsound->volpan.dwTotalRightAmpFactor << 16); |
725d8c39 | 806 | waveOutSetVolume(dsound->hwo, vol); |
725d8c39 RR |
807 | } |
808 | } | |
809 | ||
810 | LeaveCriticalSection(&(dsound->mixlock)); | |
811 | /* **** */ | |
812 | ||
813 | return DS_OK; | |
935e3df3 OK |
814 | } |
815 | ||
816 | static HRESULT WINAPI PrimaryBufferImpl_GetPan( | |
817 | LPDIRECTSOUNDBUFFER8 iface,LPLONG pan | |
818 | ) { | |
819 | ICOM_THIS(PrimaryBufferImpl,iface); | |
820 | TRACE("(%p,%p)\n",This,pan); | |
821 | ||
725d8c39 RR |
822 | if (!(This->dsound->dsbd.dwFlags & DSBCAPS_CTRLPAN)) { |
823 | WARN("control unavailable\n"); | |
824 | return DSERR_CONTROLUNAVAIL; | |
825 | } | |
826 | ||
a4ed8e77 RR |
827 | if (pan == NULL) { |
828 | WARN("invalid parameter: pan == NULL\n"); | |
935e3df3 | 829 | return DSERR_INVALIDPARAM; |
a4ed8e77 | 830 | } |
935e3df3 OK |
831 | |
832 | *pan = This->dsound->volpan.lPan; | |
833 | ||
834 | return DS_OK; | |
835 | } | |
836 | ||
837 | static HRESULT WINAPI PrimaryBufferImpl_Unlock( | |
838 | LPDIRECTSOUNDBUFFER8 iface,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2 | |
839 | ) { | |
840 | ICOM_THIS(PrimaryBufferImpl,iface); | |
841 | IDirectSoundImpl* dsound = This->dsound; | |
842 | ||
725d8c39 | 843 | TRACE("(%p,%p,%ld,%p,%ld)\n", This,p1,x1,p2,x2); |
935e3df3 | 844 | |
a4ed8e77 RR |
845 | if (dsound->priolevel != DSSCL_WRITEPRIMARY) { |
846 | WARN("failed priority check!\n"); | |
935e3df3 | 847 | return DSERR_PRIOLEVELNEEDED; |
a4ed8e77 | 848 | } |
935e3df3 OK |
849 | |
850 | if (!(dsound->drvdesc.dwFlags & DSDDESC_DONTNEEDPRIMARYLOCK) && dsound->hwbuf) { | |
a4ed8e77 RR |
851 | HRESULT hres; |
852 | ||
853 | hres = IDsDriverBuffer_Unlock(dsound->hwbuf, p1, x1, p2, x2); | |
854 | if (hres != DS_OK) { | |
855 | WARN("IDsDriverBuffer_Unlock failed\n"); | |
856 | return hres; | |
857 | } | |
935e3df3 OK |
858 | } |
859 | ||
860 | return DS_OK; | |
861 | } | |
862 | ||
863 | static HRESULT WINAPI PrimaryBufferImpl_Restore( | |
864 | LPDIRECTSOUNDBUFFER8 iface | |
865 | ) { | |
866 | ICOM_THIS(PrimaryBufferImpl,iface); | |
867 | FIXME("(%p):stub\n",This); | |
868 | return DS_OK; | |
869 | } | |
870 | ||
871 | static HRESULT WINAPI PrimaryBufferImpl_GetFrequency( | |
872 | LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq | |
873 | ) { | |
874 | ICOM_THIS(PrimaryBufferImpl,iface); | |
875 | TRACE("(%p,%p)\n",This,freq); | |
876 | ||
a4ed8e77 RR |
877 | if (freq == NULL) { |
878 | WARN("invalid parameter: freq == NULL\n"); | |
935e3df3 | 879 | return DSERR_INVALIDPARAM; |
a4ed8e77 | 880 | } |
935e3df3 | 881 | |
9dacf206 RR |
882 | if (!(This->dsound->dsbd.dwFlags & DSBCAPS_CTRLFREQUENCY)) { |
883 | WARN("control unavailable\n"); | |
884 | return DSERR_CONTROLUNAVAIL; | |
885 | } | |
886 | ||
935e3df3 OK |
887 | *freq = This->dsound->wfx.nSamplesPerSec; |
888 | TRACE("-> %ld\n", *freq); | |
889 | ||
890 | return DS_OK; | |
891 | } | |
892 | ||
893 | static HRESULT WINAPI PrimaryBufferImpl_SetFX( | |
894 | LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes | |
895 | ) { | |
896 | ICOM_THIS(PrimaryBufferImpl,iface); | |
897 | DWORD u; | |
898 | ||
899 | FIXME("(%p,%lu,%p,%p): stub\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes); | |
900 | ||
901 | if (pdwResultCodes) | |
902 | for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN; | |
903 | ||
a4ed8e77 | 904 | WARN("control unavailable\n"); |
935e3df3 OK |
905 | return DSERR_CONTROLUNAVAIL; |
906 | } | |
907 | ||
908 | static HRESULT WINAPI PrimaryBufferImpl_AcquireResources( | |
909 | LPDIRECTSOUNDBUFFER8 iface,DWORD dwFlags,DWORD dwEffectsCount,LPDWORD pdwResultCodes | |
910 | ) { | |
911 | ICOM_THIS(PrimaryBufferImpl,iface); | |
912 | DWORD u; | |
913 | ||
914 | FIXME("(%p,%08lu,%lu,%p): stub\n",This,dwFlags,dwEffectsCount,pdwResultCodes); | |
915 | ||
916 | if (pdwResultCodes) | |
917 | for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN; | |
918 | ||
a4ed8e77 | 919 | WARN("control unavailable\n"); |
935e3df3 OK |
920 | return DSERR_CONTROLUNAVAIL; |
921 | } | |
922 | ||
923 | static HRESULT WINAPI PrimaryBufferImpl_GetObjectInPath( | |
924 | LPDIRECTSOUNDBUFFER8 iface,REFGUID rguidObject,DWORD dwIndex,REFGUID rguidInterface,LPVOID* ppObject | |
925 | ) { | |
926 | ICOM_THIS(PrimaryBufferImpl,iface); | |
927 | ||
928 | FIXME("(%p,%s,%lu,%s,%p): stub\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject); | |
929 | ||
a4ed8e77 | 930 | WARN("control unavailable\n"); |
935e3df3 OK |
931 | return DSERR_CONTROLUNAVAIL; |
932 | } | |
933 | ||
934 | static HRESULT WINAPI PrimaryBufferImpl_Initialize( | |
7dd63746 | 935 | LPDIRECTSOUNDBUFFER8 iface,LPDIRECTSOUND8 dsound,LPCDSBUFFERDESC dbsd |
935e3df3 OK |
936 | ) { |
937 | ICOM_THIS(PrimaryBufferImpl,iface); | |
938 | FIXME("(%p,%p,%p):stub\n",This,dsound,dbsd); | |
939 | DPRINTF("Re-Init!!!\n"); | |
a4ed8e77 | 940 | WARN("already initialized\n"); |
935e3df3 OK |
941 | return DSERR_ALREADYINITIALIZED; |
942 | } | |
943 | ||
944 | static HRESULT WINAPI PrimaryBufferImpl_GetCaps( | |
945 | LPDIRECTSOUNDBUFFER8 iface,LPDSBCAPS caps | |
946 | ) { | |
947 | ICOM_THIS(PrimaryBufferImpl,iface); | |
948 | TRACE("(%p)->(%p)\n",This,caps); | |
949 | ||
a4ed8e77 RR |
950 | if (caps == NULL) { |
951 | WARN("invalid parameter: caps == NULL\n"); | |
935e3df3 | 952 | return DSERR_INVALIDPARAM; |
a4ed8e77 RR |
953 | } |
954 | ||
955 | if (caps->dwSize < sizeof(*caps)) { | |
956 | WARN("invalid parameter: caps->dwSize = %ld: < %d\n", caps->dwSize, sizeof(*caps)); | |
957 | return DSERR_INVALIDPARAM; | |
958 | } | |
935e3df3 | 959 | |
9dacf206 | 960 | caps->dwFlags = This->dsound->dsbd.dwFlags; |
935e3df3 OK |
961 | if (This->dsound->hwbuf) caps->dwFlags |= DSBCAPS_LOCHARDWARE; |
962 | else caps->dwFlags |= DSBCAPS_LOCSOFTWARE; | |
963 | ||
964 | caps->dwBufferBytes = This->dsound->buflen; | |
965 | ||
966 | /* This value represents the speed of the "unlock" command. | |
967 | As unlock is quite fast (it does not do anything), I put | |
968 | 4096 ko/s = 4 Mo / s */ | |
969 | /* FIXME: hwbuf speed */ | |
970 | caps->dwUnlockTransferRate = 4096; | |
971 | caps->dwPlayCpuOverhead = 0; | |
972 | ||
973 | return DS_OK; | |
974 | } | |
975 | ||
976 | static HRESULT WINAPI PrimaryBufferImpl_QueryInterface( | |
977 | LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj | |
978 | ) { | |
979 | ICOM_THIS(PrimaryBufferImpl,iface); | |
935e3df3 OK |
980 | TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); |
981 | ||
f5080c86 RR |
982 | if (ppobj == NULL) { |
983 | WARN("invalid parameter\n"); | |
984 | return E_INVALIDARG; | |
985 | } | |
986 | ||
9dacf206 RR |
987 | *ppobj = NULL; /* assume failure */ |
988 | ||
989 | if ( IsEqualGUID(riid, &IID_IUnknown) || | |
990 | IsEqualGUID(riid, &IID_IDirectSoundBuffer) ) { | |
991 | IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)This); | |
992 | *ppobj = This; | |
993 | return S_OK; | |
994 | } | |
995 | ||
996 | /* DirectSoundBuffer and DirectSoundBuffer8 are different and */ | |
997 | /* a primary buffer can't have a DirectSoundBuffer8 interface */ | |
998 | if ( IsEqualGUID( &IID_IDirectSoundBuffer8, riid ) ) { | |
999 | WARN("app requested DirectSoundBuffer8 on primary buffer\n"); | |
1000 | return E_NOINTERFACE; | |
1001 | } | |
1002 | ||
935e3df3 OK |
1003 | if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) { |
1004 | ERR("app requested IDirectSoundNotify on primary buffer\n"); | |
a4ed8e77 | 1005 | /* FIXME: should we support this? */ |
9dacf206 | 1006 | return E_NOINTERFACE; |
935e3df3 OK |
1007 | } |
1008 | ||
1009 | if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) { | |
1010 | ERR("app requested IDirectSound3DBuffer on primary buffer\n"); | |
935e3df3 OK |
1011 | return E_NOINTERFACE; |
1012 | } | |
1013 | ||
1014 | if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) { | |
5ec32cec RR |
1015 | if (!This->dsound->listener) |
1016 | IDirectSound3DListenerImpl_Create(This, &This->dsound->listener); | |
1017 | if (This->dsound->listener) { | |
9dacf206 | 1018 | *ppobj = This->dsound->listener; |
5ec32cec RR |
1019 | IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER)*ppobj); |
1020 | return S_OK; | |
935e3df3 | 1021 | } |
9dacf206 | 1022 | |
a4ed8e77 | 1023 | WARN("IID_IDirectSound3DListener failed\n"); |
9dacf206 | 1024 | return E_NOINTERFACE; |
935e3df3 OK |
1025 | } |
1026 | ||
1027 | if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) { | |
935e3df3 | 1028 | FIXME("app requested IKsPropertySet on primary buffer\n"); |
9dacf206 | 1029 | return E_NOINTERFACE; |
935e3df3 OK |
1030 | } |
1031 | ||
1032 | FIXME( "Unknown IID %s\n", debugstr_guid( riid ) ); | |
935e3df3 OK |
1033 | return E_NOINTERFACE; |
1034 | } | |
1035 | ||
1036 | static ICOM_VTABLE(IDirectSoundBuffer8) dspbvt = | |
1037 | { | |
1038 | ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE | |
1039 | PrimaryBufferImpl_QueryInterface, | |
1040 | PrimaryBufferImpl_AddRef, | |
1041 | PrimaryBufferImpl_Release, | |
1042 | PrimaryBufferImpl_GetCaps, | |
1043 | PrimaryBufferImpl_GetCurrentPosition, | |
1044 | PrimaryBufferImpl_GetFormat, | |
1045 | PrimaryBufferImpl_GetVolume, | |
1046 | PrimaryBufferImpl_GetPan, | |
1047 | PrimaryBufferImpl_GetFrequency, | |
1048 | PrimaryBufferImpl_GetStatus, | |
1049 | PrimaryBufferImpl_Initialize, | |
1050 | PrimaryBufferImpl_Lock, | |
1051 | PrimaryBufferImpl_Play, | |
1052 | PrimaryBufferImpl_SetCurrentPosition, | |
1053 | PrimaryBufferImpl_SetFormat, | |
1054 | PrimaryBufferImpl_SetVolume, | |
1055 | PrimaryBufferImpl_SetPan, | |
1056 | PrimaryBufferImpl_SetFrequency, | |
1057 | PrimaryBufferImpl_Stop, | |
1058 | PrimaryBufferImpl_Unlock, | |
1059 | PrimaryBufferImpl_Restore, | |
1060 | PrimaryBufferImpl_SetFX, | |
1061 | PrimaryBufferImpl_AcquireResources, | |
1062 | PrimaryBufferImpl_GetObjectInPath | |
1063 | }; | |
1064 | ||
5ec32cec RR |
1065 | HRESULT WINAPI PrimaryBufferImpl_Create( |
1066 | IDirectSoundImpl *ds, | |
935e3df3 | 1067 | PrimaryBufferImpl **pdsb, |
7dd63746 | 1068 | LPCDSBUFFERDESC dsbd) |
935e3df3 OK |
1069 | { |
1070 | PrimaryBufferImpl *dsb; | |
1071 | ||
5ec32cec | 1072 | TRACE("%p,%p,%p)\n",ds,pdsb,dsbd); |
772539a8 | 1073 | |
a4ed8e77 RR |
1074 | if (dsbd->lpwfxFormat) { |
1075 | WARN("invalid parameter: dsbd->lpwfxFormat != NULL\n"); | |
1076 | *pdsb = NULL; | |
935e3df3 | 1077 | return DSERR_INVALIDPARAM; |
a4ed8e77 | 1078 | } |
935e3df3 OK |
1079 | |
1080 | dsb = (PrimaryBufferImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb)); | |
a4ed8e77 RR |
1081 | |
1082 | if (dsb == NULL) { | |
1083 | WARN("out of memory\n"); | |
1084 | *pdsb = NULL; | |
1085 | return DSERR_OUTOFMEMORY; | |
1086 | } | |
1087 | ||
5ec32cec RR |
1088 | dsb->ref = 0; |
1089 | dsb->dsound = ds; | |
c2ebe1ff | 1090 | dsb->lpVtbl = &dspbvt; |
935e3df3 | 1091 | |
5ec32cec | 1092 | memcpy(&ds->dsbd, dsbd, sizeof(*dsbd)); |
935e3df3 OK |
1093 | |
1094 | TRACE("Created primary buffer at %p\n", dsb); | |
772539a8 RR |
1095 | TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld," |
1096 | "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n", | |
5ec32cec RR |
1097 | ds->wfx.wFormatTag, ds->wfx.nChannels, ds->wfx.nSamplesPerSec, |
1098 | ds->wfx.nAvgBytesPerSec, ds->wfx.nBlockAlign, | |
1099 | ds->wfx.wBitsPerSample, ds->wfx.cbSize); | |
935e3df3 | 1100 | |
5ec32cec | 1101 | IDirectSound_AddRef((LPDIRECTSOUND)ds); |
935e3df3 OK |
1102 | *pdsb = dsb; |
1103 | return S_OK; | |
1104 | } |