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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 *
21 * TODO:
22 * When PrimarySetFormat (via ReopenDevice or PrimaryOpen) fails,
23 * it leaves dsound in unusable (not really open) state.
24 */
25
26 #include "dsound_private.h"
27
28 /** Calculate how long a fragment length of about 10 ms should be in frames
29 *
30 * nSamplesPerSec: Frequency rate in samples per second
31 * nBlockAlign: Size of a single blockalign
32 *
33 * Returns:
34 * Size in bytes of a single fragment
35 */
DSOUND_fraglen(DWORD nSamplesPerSec,DWORD nBlockAlign)36 DWORD DSOUND_fraglen(DWORD nSamplesPerSec, DWORD nBlockAlign)
37 {
38 /* Given a timer delay of 10ms, the fragment size is approximately:
39 * fraglen = (nSamplesPerSec * 10 / 1000) * nBlockAlign
40 * ==> fraglen = (nSamplesPerSec / 100) * nBlockSize
41 *
42 * ALSA uses buffers that are powers of 2. Because of this, fraglen
43 * is rounded up to the nearest power of 2:
44 */
45
46 if (nSamplesPerSec <= 12800)
47 return 128 * nBlockAlign;
48
49 if (nSamplesPerSec <= 25600)
50 return 256 * nBlockAlign;
51
52 if (nSamplesPerSec <= 51200)
53 return 512 * nBlockAlign;
54
55 return 1024 * nBlockAlign;
56 }
57
DSOUND_RecalcPrimary(DirectSoundDevice * device)58 static void DSOUND_RecalcPrimary(DirectSoundDevice *device)
59 {
60 TRACE("(%p)\n", device);
61
62 device->fraglen = DSOUND_fraglen(device->pwfx->nSamplesPerSec, device->pwfx->nBlockAlign);
63 device->helfrags = device->buflen / device->fraglen;
64 TRACE("fraglen=%d helfrags=%d\n", device->fraglen, device->helfrags);
65
66 if (device->hwbuf && device->drvdesc.dwFlags & DSDDESC_DONTNEEDWRITELEAD)
67 device->writelead = 0;
68 else
69 /* calculate the 10ms write lead */
70 device->writelead = (device->pwfx->nSamplesPerSec / 100) * device->pwfx->nBlockAlign;
71 }
72
DSOUND_ReopenDevice(DirectSoundDevice * device,BOOL forcewave)73 HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave)
74 {
75 HRESULT hres = DS_OK;
76 TRACE("(%p, %d)\n", device, forcewave);
77
78 if (device->driver)
79 {
80 IDsDriver_Close(device->driver);
81 if (device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN)
82 waveOutClose(device->hwo);
83 IDsDriver_Release(device->driver);
84 device->driver = NULL;
85 device->buffer = NULL;
86 device->hwo = 0;
87 }
88 else if (device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN)
89 waveOutClose(device->hwo);
90
91 /* DRV_QUERYDSOUNDIFACE is a "Wine extension" to get the DSound interface */
92 if (ds_hw_accel != DS_HW_ACCEL_EMULATION && !forcewave)
93 waveOutMessage((HWAVEOUT)(DWORD_PTR)device->drvdesc.dnDevNode, DRV_QUERYDSOUNDIFACE, (DWORD_PTR)&device->driver, 0);
94
95 /* Get driver description */
96 if (device->driver) {
97 DWORD wod = device->drvdesc.dnDevNode;
98 hres = IDsDriver_GetDriverDesc(device->driver,&(device->drvdesc));
99 device->drvdesc.dnDevNode = wod;
100 if (FAILED(hres)) {
101 WARN("IDsDriver_GetDriverDesc failed: %08x\n", hres);
102 IDsDriver_Release(device->driver);
103 device->driver = NULL;
104 }
105 }
106
107 /* if no DirectSound interface available, use WINMM API instead */
108 if (!device->driver)
109 device->drvdesc.dwFlags = DSDDESC_DOMMSYSTEMOPEN | DSDDESC_DOMMSYSTEMSETFORMAT;
110
111 if (device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN)
112 {
113 DWORD flags = CALLBACK_FUNCTION | WAVE_MAPPED;
114
115 if (device->driver)
116 flags |= WAVE_DIRECTSOUND;
117
118 hres = mmErr(waveOutOpen(&(device->hwo), device->drvdesc.dnDevNode, device->pwfx, (DWORD_PTR)DSOUND_callback, (DWORD_PTR)device, flags));
119 if (FAILED(hres)) {
120 WARN("waveOutOpen failed\n");
121 if (device->driver)
122 {
123 IDsDriver_Release(device->driver);
124 device->driver = NULL;
125 }
126 return hres;
127 }
128 }
129
130 if (device->driver)
131 hres = IDsDriver_Open(device->driver);
132
133 return hres;
134 }
135
DSOUND_PrimaryOpen(DirectSoundDevice * device)136 static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device)
137 {
138 DWORD buflen;
139 HRESULT err = DS_OK;
140 TRACE("(%p)\n", device);
141
142 /* on original windows, the buffer it set to a fixed size, no matter what the settings are.
143 on windows this size is always fixed (tested on win-xp) */
144 if (!device->buflen)
145 device->buflen = ds_hel_buflen;
146 buflen = device->buflen;
147 buflen -= buflen % device->pwfx->nBlockAlign;
148 device->buflen = buflen;
149
150 if (device->driver)
151 {
152 err = IDsDriver_CreateSoundBuffer(device->driver,device->pwfx,
153 DSBCAPS_PRIMARYBUFFER,0,
154 &(device->buflen),&(device->buffer),
155 (LPVOID*)&(device->hwbuf));
156
157 if (err != DS_OK) {
158 WARN("IDsDriver_CreateSoundBuffer failed (%08x), falling back to waveout\n", err);
159 err = DSOUND_ReopenDevice(device, TRUE);
160 if (FAILED(err))
161 {
162 WARN("Falling back to waveout failed too! Giving up\n");
163 return err;
164 }
165 }
166 if (device->hwbuf)
167 IDsDriverBuffer_SetVolumePan(device->hwbuf, &device->volpan);
168
169 DSOUND_RecalcPrimary(device);
170 device->prebuf = ds_snd_queue_max;
171 if (device->helfrags < ds_snd_queue_min)
172 {
173 WARN("Too little sound buffer to be effective (%d/%d) falling back to waveout\n", device->buflen, ds_snd_queue_min * device->fraglen);
174 device->buflen = buflen;
175 IDsDriverBuffer_Release(device->hwbuf);
176 device->hwbuf = NULL;
177 err = DSOUND_ReopenDevice(device, TRUE);
178 if (FAILED(err))
179 {
180 WARN("Falling back to waveout failed too! Giving up\n");
181 return err;
182 }
183 }
184 else if (device->helfrags < ds_snd_queue_max)
185 device->prebuf = device->helfrags;
186 }
187
188 device->mix_buffer_len = DSOUND_bufpos_to_mixpos(device, device->buflen);
189 device->mix_buffer = HeapAlloc(GetProcessHeap(), 0, device->mix_buffer_len);
190 if (!device->mix_buffer)
191 {
192 if (device->hwbuf)
193 IDsDriverBuffer_Release(device->hwbuf);
194 device->hwbuf = NULL;
195 return DSERR_OUTOFMEMORY;
196 }
197
198 if (device->state == STATE_PLAYING) device->state = STATE_STARTING;
199 else if (device->state == STATE_STOPPING) device->state = STATE_STOPPED;
200
201 /* are we using waveOut stuff? */
202 if (!device->driver) {
203 LPBYTE newbuf;
204 LPWAVEHDR headers = NULL;
205 DWORD overshot;
206 unsigned int c;
207
208 /* Start in pause mode, to allow buffers to get filled */
209 waveOutPause(device->hwo);
210
211 TRACE("desired buflen=%d, old buffer=%p\n", buflen, device->buffer);
212
213 /* reallocate emulated primary buffer */
214 if (device->buffer)
215 newbuf = HeapReAlloc(GetProcessHeap(),0,device->buffer, buflen);
216 else
217 newbuf = HeapAlloc(GetProcessHeap(),0, buflen);
218
219 if (!newbuf) {
220 ERR("failed to allocate primary buffer\n");
221 return DSERR_OUTOFMEMORY;
222 /* but the old buffer might still exist and must be re-prepared */
223 }
224
225 DSOUND_RecalcPrimary(device);
226 if (device->pwave)
227 headers = HeapReAlloc(GetProcessHeap(),0,device->pwave, device->helfrags * sizeof(WAVEHDR));
228 else
229 headers = HeapAlloc(GetProcessHeap(),0,device->helfrags * sizeof(WAVEHDR));
230
231 if (!headers) {
232 ERR("failed to allocate wave headers\n");
233 HeapFree(GetProcessHeap(), 0, newbuf);
234 DSOUND_RecalcPrimary(device);
235 return DSERR_OUTOFMEMORY;
236 }
237
238 device->buffer = newbuf;
239 device->pwave = headers;
240
241 /* prepare fragment headers */
242 for (c=0; c<device->helfrags; c++) {
243 device->pwave[c].lpData = (char*)device->buffer + c*device->fraglen;
244 device->pwave[c].dwBufferLength = device->fraglen;
245 device->pwave[c].dwUser = (DWORD_PTR)device;
246 device->pwave[c].dwFlags = 0;
247 device->pwave[c].dwLoops = 0;
248 err = mmErr(waveOutPrepareHeader(device->hwo,&device->pwave[c],sizeof(WAVEHDR)));
249 if (err != DS_OK) {
250 while (c--)
251 waveOutUnprepareHeader(device->hwo,&device->pwave[c],sizeof(WAVEHDR));
252 break;
253 }
254 }
255
256 overshot = device->buflen % device->fraglen;
257 /* sanity */
258 if(overshot)
259 {
260 overshot -= overshot % device->pwfx->nBlockAlign;
261 device->pwave[device->helfrags - 1].dwBufferLength += overshot;
262 }
263
264 TRACE("fraglen=%d, overshot=%d\n", device->fraglen, overshot);
265 }
266 device->mixfunction = mixfunctions[device->pwfx->wBitsPerSample/8 - 1];
267 device->normfunction = normfunctions[device->pwfx->wBitsPerSample/8 - 1];
268 FillMemory(device->buffer, device->buflen, (device->pwfx->wBitsPerSample == 8) ? 128 : 0);
269 FillMemory(device->mix_buffer, device->mix_buffer_len, 0);
270 device->pwplay = device->pwqueue = device->playpos = device->mixpos = 0;
271 return err;
272 }
273
274
DSOUND_PrimaryClose(DirectSoundDevice * device)275 static void DSOUND_PrimaryClose(DirectSoundDevice *device)
276 {
277 TRACE("(%p)\n", device);
278
279 /* are we using waveOut stuff? */
280 if (!device->hwbuf) {
281 unsigned c;
282
283 /* get out of CS when calling the wave system */
284 LeaveCriticalSection(&(device->mixlock));
285 /* **** */
286 device->pwqueue = (DWORD)-1; /* resetting queues */
287 waveOutReset(device->hwo);
288 for (c=0; c<device->helfrags; c++)
289 waveOutUnprepareHeader(device->hwo, &device->pwave[c], sizeof(WAVEHDR));
290 /* **** */
291 EnterCriticalSection(&(device->mixlock));
292
293 /* clear the queue */
294 device->pwqueue = 0;
295 } else {
296 ULONG ref = IDsDriverBuffer_Release(device->hwbuf);
297 if (!ref)
298 device->hwbuf = 0;
299 else
300 ERR("Still %d references on primary buffer, refcount leak?\n", ref);
301 }
302 }
303
DSOUND_PrimaryCreate(DirectSoundDevice * device)304 HRESULT DSOUND_PrimaryCreate(DirectSoundDevice *device)
305 {
306 HRESULT err = DS_OK;
307 TRACE("(%p)\n", device);
308
309 device->buflen = ds_hel_buflen;
310 err = DSOUND_PrimaryOpen(device);
311
312 if (err != DS_OK) {
313 WARN("DSOUND_PrimaryOpen failed\n");
314 return err;
315 }
316
317 device->state = STATE_STOPPED;
318 return DS_OK;
319 }
320
DSOUND_PrimaryDestroy(DirectSoundDevice * device)321 HRESULT DSOUND_PrimaryDestroy(DirectSoundDevice *device)
322 {
323 TRACE("(%p)\n", device);
324
325 /* **** */
326 EnterCriticalSection(&(device->mixlock));
327
328 DSOUND_PrimaryClose(device);
329 if (device->driver) {
330 if (device->hwbuf) {
331 if (IDsDriverBuffer_Release(device->hwbuf) == 0)
332 device->hwbuf = 0;
333 }
334 } else
335 HeapFree(GetProcessHeap(),0,device->pwave);
336 HeapFree(GetProcessHeap(),0,device->pwfx);
337 device->pwfx=NULL;
338
339 LeaveCriticalSection(&(device->mixlock));
340 /* **** */
341
342 return DS_OK;
343 }
344
DSOUND_PrimaryPlay(DirectSoundDevice * device)345 HRESULT DSOUND_PrimaryPlay(DirectSoundDevice *device)
346 {
347 HRESULT err = DS_OK;
348 TRACE("(%p)\n", device);
349
350 if (device->hwbuf) {
351 err = IDsDriverBuffer_Play(device->hwbuf, 0, 0, DSBPLAY_LOOPING);
352 if (err != DS_OK)
353 WARN("IDsDriverBuffer_Play failed\n");
354 } else {
355 err = mmErr(waveOutRestart(device->hwo));
356 if (err != DS_OK)
357 WARN("waveOutRestart failed\n");
358 }
359
360 return err;
361 }
362
DSOUND_PrimaryStop(DirectSoundDevice * device)363 HRESULT DSOUND_PrimaryStop(DirectSoundDevice *device)
364 {
365 HRESULT err = DS_OK;
366 TRACE("(%p)\n", device);
367
368 if (device->hwbuf) {
369 err = IDsDriverBuffer_Stop(device->hwbuf);
370 if (err == DSERR_BUFFERLOST) {
371 DSOUND_PrimaryClose(device);
372 err = DSOUND_ReopenDevice(device, FALSE);
373 if (FAILED(err))
374 ERR("DSOUND_ReopenDevice failed\n");
375 else
376 {
377 err = DSOUND_PrimaryOpen(device);
378 if (FAILED(err))
379 WARN("DSOUND_PrimaryOpen failed\n");
380 }
381 } else if (err != DS_OK) {
382 WARN("IDsDriverBuffer_Stop failed\n");
383 }
384 } else {
385
386 /* don't call the wave system with the lock set */
387 LeaveCriticalSection(&(device->mixlock));
388 /* **** */
389
390 err = mmErr(waveOutPause(device->hwo));
391
392 /* **** */
393 EnterCriticalSection(&(device->mixlock));
394
395 if (err != DS_OK)
396 WARN("waveOutPause failed\n");
397 }
398
399 return err;
400 }
401
DSOUND_PrimaryGetPosition(DirectSoundDevice * device,LPDWORD playpos,LPDWORD writepos)402 HRESULT DSOUND_PrimaryGetPosition(DirectSoundDevice *device, LPDWORD playpos, LPDWORD writepos)
403 {
404 TRACE("(%p,%p,%p)\n", device, playpos, writepos);
405
406 if (device->hwbuf) {
407 HRESULT err=IDsDriverBuffer_GetPosition(device->hwbuf,playpos,writepos);
408 if (err != S_OK) {
409 WARN("IDsDriverBuffer_GetPosition failed\n");
410 return err;
411 }
412 } else {
413 TRACE("pwplay=%i, pwqueue=%i\n", device->pwplay, device->pwqueue);
414
415 /* check if playpos was requested */
416 if (playpos)
417 /* use the cached play position */
418 *playpos = device->pwplay * device->fraglen;
419
420 /* check if writepos was requested */
421 if (writepos)
422 /* the writepos is the first non-queued position */
423 *writepos = ((device->pwplay + device->pwqueue) % device->helfrags) * device->fraglen;
424 }
425 TRACE("playpos = %d, writepos = %d (%p, time=%d)\n", playpos?*playpos:-1, writepos?*writepos:-1, device, GetTickCount());
426 return DS_OK;
427 }
428
DSOUND_GetFormatSize(LPCWAVEFORMATEX wfex)429 static DWORD DSOUND_GetFormatSize(LPCWAVEFORMATEX wfex)
430 {
431 if (wfex->wFormatTag == WAVE_FORMAT_PCM)
432 return sizeof(WAVEFORMATEX);
433 else
434 return sizeof(WAVEFORMATEX) + wfex->cbSize;
435 }
436
DSOUND_CopyFormat(LPCWAVEFORMATEX wfex)437 LPWAVEFORMATEX DSOUND_CopyFormat(LPCWAVEFORMATEX wfex)
438 {
439 DWORD size = DSOUND_GetFormatSize(wfex);
440 LPWAVEFORMATEX pwfx = HeapAlloc(GetProcessHeap(),0,size);
441 if (pwfx == NULL) {
442 WARN("out of memory\n");
443 } else if (wfex->wFormatTag != WAVE_FORMAT_PCM) {
444 CopyMemory(pwfx, wfex, size);
445 } else {
446 CopyMemory(pwfx, wfex, sizeof(PCMWAVEFORMAT));
447 pwfx->cbSize=0;
448 if (pwfx->nBlockAlign != pwfx->nChannels * pwfx->wBitsPerSample/8) {
449 WARN("Fixing bad nBlockAlign (%u)\n", pwfx->nBlockAlign);
450 pwfx->nBlockAlign = pwfx->nChannels * pwfx->wBitsPerSample/8;
451 }
452 if (pwfx->nAvgBytesPerSec != pwfx->nSamplesPerSec * pwfx->nBlockAlign) {
453 WARN("Fixing bad nAvgBytesPerSec (%u)\n", pwfx->nAvgBytesPerSec);
454 pwfx->nAvgBytesPerSec = pwfx->nSamplesPerSec * pwfx->nBlockAlign;
455 }
456 }
457 return pwfx;
458 }
459
primarybuffer_SetFormat(DirectSoundDevice * device,LPCWAVEFORMATEX wfex)460 HRESULT primarybuffer_SetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX wfex)
461 {
462 HRESULT err = DSERR_BUFFERLOST;
463 int i;
464 DWORD nSamplesPerSec, bpp, chans;
465 LPWAVEFORMATEX oldpwfx;
466 BOOL forced = device->priolevel == DSSCL_WRITEPRIMARY;
467
468 TRACE("(%p,%p)\n", device, wfex);
469
470 if (device->priolevel == DSSCL_NORMAL) {
471 WARN("failed priority check!\n");
472 return DSERR_PRIOLEVELNEEDED;
473 }
474
475 /* Let's be pedantic! */
476 if (wfex == NULL) {
477 WARN("invalid parameter: wfex==NULL!\n");
478 return DSERR_INVALIDPARAM;
479 }
480 TRACE("(formattag=0x%04x,chans=%d,samplerate=%d,"
481 "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
482 wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
483 wfex->nAvgBytesPerSec, wfex->nBlockAlign,
484 wfex->wBitsPerSample, wfex->cbSize);
485
486 /* **** */
487 RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
488 EnterCriticalSection(&(device->mixlock));
489
490 nSamplesPerSec = device->pwfx->nSamplesPerSec;
491 bpp = device->pwfx->wBitsPerSample;
492 chans = device->pwfx->nChannels;
493
494 oldpwfx = device->pwfx;
495 device->pwfx = DSOUND_CopyFormat(wfex);
496 if (device->pwfx == NULL) {
497 device->pwfx = oldpwfx;
498 oldpwfx = NULL;
499 err = DSERR_OUTOFMEMORY;
500 goto done;
501 }
502
503 if (!(device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMSETFORMAT) && device->hwbuf) {
504 err = IDsDriverBuffer_SetFormat(device->hwbuf, device->pwfx);
505
506 /* On bad format, try to re-create, big chance it will work then, only do this if we <HAVE> to */
507 if (forced && (device->pwfx->nSamplesPerSec/100 != wfex->nSamplesPerSec/100 || err == DSERR_BADFORMAT))
508 {
509 DWORD cp_size = wfex->wFormatTag == WAVE_FORMAT_PCM ?
510 sizeof(PCMWAVEFORMAT) : sizeof(WAVEFORMATEX) + wfex->cbSize;
511 err = DSERR_BUFFERLOST;
512 CopyMemory(device->pwfx, wfex, cp_size);
513 }
514
515 if (err != DSERR_BUFFERLOST && FAILED(err)) {
516 DWORD size = DSOUND_GetFormatSize(oldpwfx);
517 WARN("IDsDriverBuffer_SetFormat failed\n");
518 if (!forced) {
519 CopyMemory(device->pwfx, oldpwfx, size);
520 err = DS_OK;
521 }
522 goto done;
523 }
524
525 if (err == S_FALSE)
526 {
527 /* ALSA specific: S_FALSE tells that recreation was successful,
528 * but size and location may be changed, and buffer has to be restarted
529 * I put it here, so if frequency doesn't match the error will be changed to DSERR_BUFFERLOST
530 * and the entire re-initialization will occur anyway
531 */
532 IDsDriverBuffer_Lock(device->hwbuf, (LPVOID *)&device->buffer, &device->buflen, NULL, NULL, 0, 0, DSBLOCK_ENTIREBUFFER);
533 IDsDriverBuffer_Unlock(device->hwbuf, device->buffer, 0, NULL, 0);
534
535 if (device->state == STATE_PLAYING) device->state = STATE_STARTING;
536 else if (device->state == STATE_STOPPING) device->state = STATE_STOPPED;
537 device->pwplay = device->pwqueue = device->playpos = device->mixpos = 0;
538 err = DS_OK;
539 }
540 DSOUND_RecalcPrimary(device);
541 }
542
543 if (err == DSERR_BUFFERLOST)
544 {
545 DSOUND_PrimaryClose(device);
546
547 err = DSOUND_ReopenDevice(device, FALSE);
548 if (FAILED(err))
549 {
550 WARN("DSOUND_ReopenDevice failed: %08x\n", err);
551 goto done;
552 }
553 err = DSOUND_PrimaryOpen(device);
554 if (err != DS_OK) {
555 WARN("DSOUND_PrimaryOpen failed\n");
556 goto done;
557 }
558
559 if (wfex->nSamplesPerSec/100 != device->pwfx->nSamplesPerSec/100 && forced && device->buffer)
560 {
561 DSOUND_PrimaryClose(device);
562 device->pwfx->nSamplesPerSec = wfex->nSamplesPerSec;
563 err = DSOUND_ReopenDevice(device, TRUE);
564 if (FAILED(err))
565 WARN("DSOUND_ReopenDevice(2) failed: %08x\n", err);
566 else if (FAILED((err = DSOUND_PrimaryOpen(device))))
567 WARN("DSOUND_PrimaryOpen(2) failed: %08x\n", err);
568 }
569 }
570
571 device->mix_buffer_len = DSOUND_bufpos_to_mixpos(device, device->buflen);
572 device->mix_buffer = HeapReAlloc(GetProcessHeap(), 0, device->mix_buffer, device->mix_buffer_len);
573 FillMemory(device->mix_buffer, device->mix_buffer_len, 0);
574 device->mixfunction = mixfunctions[device->pwfx->wBitsPerSample/8 - 1];
575 device->normfunction = normfunctions[device->pwfx->wBitsPerSample/8 - 1];
576
577 if (nSamplesPerSec != device->pwfx->nSamplesPerSec || bpp != device->pwfx->wBitsPerSample || chans != device->pwfx->nChannels) {
578 IDirectSoundBufferImpl** dsb = device->buffers;
579 for (i = 0; i < device->nrofbuffers; i++, dsb++) {
580 /* **** */
581 RtlAcquireResourceExclusive(&(*dsb)->lock, TRUE);
582
583 (*dsb)->freqAdjust = ((DWORD64)(*dsb)->freq << DSOUND_FREQSHIFT) / device->pwfx->nSamplesPerSec;
584 DSOUND_RecalcFormat((*dsb));
585 DSOUND_MixToTemporary((*dsb), 0, (*dsb)->buflen, FALSE);
586 (*dsb)->primary_mixpos = 0;
587
588 RtlReleaseResource(&(*dsb)->lock);
589 /* **** */
590 }
591 }
592
593 done:
594 LeaveCriticalSection(&(device->mixlock));
595 RtlReleaseResource(&(device->buffer_list_lock));
596 /* **** */
597
598 HeapFree(GetProcessHeap(), 0, oldpwfx);
599 return err;
600 }
601
602 /*******************************************************************************
603 * PrimaryBuffer
604 */
impl_from_IDirectSoundBuffer(IDirectSoundBuffer * iface)605 static inline IDirectSoundBufferImpl *impl_from_IDirectSoundBuffer(IDirectSoundBuffer *iface)
606 {
607 /* IDirectSoundBuffer and IDirectSoundBuffer8 use the same iface. */
608 return CONTAINING_RECORD(iface, IDirectSoundBufferImpl, IDirectSoundBuffer8_iface);
609 }
610
611 /* This sets this format for the <em>Primary Buffer Only</em> */
612 /* See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 120 */
PrimaryBufferImpl_SetFormat(LPDIRECTSOUNDBUFFER iface,LPCWAVEFORMATEX wfex)613 static HRESULT WINAPI PrimaryBufferImpl_SetFormat(
614 LPDIRECTSOUNDBUFFER iface,
615 LPCWAVEFORMATEX wfex)
616 {
617 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
618 TRACE("(%p,%p)\n", iface, wfex);
619 return primarybuffer_SetFormat(This->device, wfex);
620 }
621
PrimaryBufferImpl_SetVolume(LPDIRECTSOUNDBUFFER iface,LONG vol)622 static HRESULT WINAPI PrimaryBufferImpl_SetVolume(
623 LPDIRECTSOUNDBUFFER iface,LONG vol
624 ) {
625 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
626 DirectSoundDevice *device = This->device;
627 DWORD ampfactors;
628 HRESULT hres = DS_OK;
629 TRACE("(%p,%d)\n", iface, vol);
630
631 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
632 WARN("control unavailable\n");
633 return DSERR_CONTROLUNAVAIL;
634 }
635
636 if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN)) {
637 WARN("invalid parameter: vol = %d\n", vol);
638 return DSERR_INVALIDPARAM;
639 }
640
641 /* **** */
642 EnterCriticalSection(&(device->mixlock));
643
644 waveOutGetVolume(device->hwo, &factors);
645 device->volpan.dwTotalLeftAmpFactor=ampfactors & 0xffff;
646 device->volpan.dwTotalRightAmpFactor=ampfactors >> 16;
647 DSOUND_AmpFactorToVolPan(&device->volpan);
648 if (vol != device->volpan.lVolume) {
649 device->volpan.lVolume=vol;
650 DSOUND_RecalcVolPan(&device->volpan);
651 if (device->hwbuf) {
652 hres = IDsDriverBuffer_SetVolumePan(device->hwbuf, &device->volpan);
653 if (hres != DS_OK)
654 WARN("IDsDriverBuffer_SetVolumePan failed\n");
655 } else {
656 ampfactors = (device->volpan.dwTotalLeftAmpFactor & 0xffff) | (device->volpan.dwTotalRightAmpFactor << 16);
657 waveOutSetVolume(device->hwo, ampfactors);
658 }
659 }
660
661 LeaveCriticalSection(&(device->mixlock));
662 /* **** */
663
664 return hres;
665 }
666
PrimaryBufferImpl_GetVolume(LPDIRECTSOUNDBUFFER iface,LPLONG vol)667 static HRESULT WINAPI PrimaryBufferImpl_GetVolume(
668 LPDIRECTSOUNDBUFFER iface,LPLONG vol
669 ) {
670 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
671 DirectSoundDevice *device = This->device;
672 DWORD ampfactors;
673 TRACE("(%p,%p)\n", iface, vol);
674
675 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
676 WARN("control unavailable\n");
677 return DSERR_CONTROLUNAVAIL;
678 }
679
680 if (vol == NULL) {
681 WARN("invalid parameter: vol = NULL\n");
682 return DSERR_INVALIDPARAM;
683 }
684
685 if (!device->hwbuf)
686 {
687 waveOutGetVolume(device->hwo, &factors);
688 device->volpan.dwTotalLeftAmpFactor=ampfactors & 0xffff;
689 device->volpan.dwTotalRightAmpFactor=ampfactors >> 16;
690 DSOUND_AmpFactorToVolPan(&device->volpan);
691 }
692 *vol = device->volpan.lVolume;
693 return DS_OK;
694 }
695
PrimaryBufferImpl_SetFrequency(LPDIRECTSOUNDBUFFER iface,DWORD freq)696 static HRESULT WINAPI PrimaryBufferImpl_SetFrequency(
697 LPDIRECTSOUNDBUFFER iface,DWORD freq
698 ) {
699 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
700 TRACE("(%p,%d)\n",This,freq);
701
702 /* You cannot set the frequency of the primary buffer */
703 WARN("control unavailable\n");
704 return DSERR_CONTROLUNAVAIL;
705 }
706
PrimaryBufferImpl_Play(LPDIRECTSOUNDBUFFER iface,DWORD reserved1,DWORD reserved2,DWORD flags)707 static HRESULT WINAPI PrimaryBufferImpl_Play(
708 LPDIRECTSOUNDBUFFER iface,DWORD reserved1,DWORD reserved2,DWORD flags
709 ) {
710 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
711 DirectSoundDevice *device = This->device;
712 TRACE("(%p,%08x,%08x,%08x)\n", iface, reserved1, reserved2, flags);
713
714 if (!(flags & DSBPLAY_LOOPING)) {
715 WARN("invalid parameter: flags = %08x\n", flags);
716 return DSERR_INVALIDPARAM;
717 }
718
719 /* **** */
720 EnterCriticalSection(&(device->mixlock));
721
722 if (device->state == STATE_STOPPED)
723 device->state = STATE_STARTING;
724 else if (device->state == STATE_STOPPING)
725 device->state = STATE_PLAYING;
726
727 LeaveCriticalSection(&(device->mixlock));
728 /* **** */
729
730 return DS_OK;
731 }
732
PrimaryBufferImpl_Stop(LPDIRECTSOUNDBUFFER iface)733 static HRESULT WINAPI PrimaryBufferImpl_Stop(LPDIRECTSOUNDBUFFER iface)
734 {
735 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
736 DirectSoundDevice *device = This->device;
737 TRACE("(%p)\n", iface);
738
739 /* **** */
740 EnterCriticalSection(&(device->mixlock));
741
742 if (device->state == STATE_PLAYING)
743 device->state = STATE_STOPPING;
744 else if (device->state == STATE_STARTING)
745 device->state = STATE_STOPPED;
746
747 LeaveCriticalSection(&(device->mixlock));
748 /* **** */
749
750 return DS_OK;
751 }
752
PrimaryBufferImpl_AddRef(LPDIRECTSOUNDBUFFER iface)753 static ULONG WINAPI PrimaryBufferImpl_AddRef(LPDIRECTSOUNDBUFFER iface)
754 {
755 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
756 ULONG ref = InterlockedIncrement(&(This->ref));
757 TRACE("(%p) ref was %d\n", This, ref - 1);
758 if(ref == 1)
759 InterlockedIncrement(&This->numIfaces);
760 return ref;
761 }
762
primarybuffer_destroy(IDirectSoundBufferImpl * This)763 void primarybuffer_destroy(IDirectSoundBufferImpl *This)
764 {
765 This->device->primary = NULL;
766 HeapFree(GetProcessHeap(), 0, This);
767 TRACE("(%p) released\n", This);
768 }
769
PrimaryBufferImpl_Release(LPDIRECTSOUNDBUFFER iface)770 static ULONG WINAPI PrimaryBufferImpl_Release(LPDIRECTSOUNDBUFFER iface)
771 {
772 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
773 DWORD ref = InterlockedDecrement(&(This->ref));
774 TRACE("(%p) ref was %d\n", This, ref + 1);
775
776 if (!ref && !InterlockedDecrement(&This->numIfaces))
777 primarybuffer_destroy(This);
778 return ref;
779 }
780
PrimaryBufferImpl_GetCurrentPosition(LPDIRECTSOUNDBUFFER iface,LPDWORD playpos,LPDWORD writepos)781 static HRESULT WINAPI PrimaryBufferImpl_GetCurrentPosition(
782 LPDIRECTSOUNDBUFFER iface,LPDWORD playpos,LPDWORD writepos
783 ) {
784 HRESULT hres;
785 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
786 DirectSoundDevice *device = This->device;
787 TRACE("(%p,%p,%p)\n", iface, playpos, writepos);
788
789 /* **** */
790 EnterCriticalSection(&(device->mixlock));
791
792 hres = DSOUND_PrimaryGetPosition(device, playpos, writepos);
793 if (hres != DS_OK) {
794 WARN("DSOUND_PrimaryGetPosition failed\n");
795 LeaveCriticalSection(&(device->mixlock));
796 return hres;
797 }
798 if (writepos) {
799 if (device->state != STATE_STOPPED)
800 /* apply the documented 10ms lead to writepos */
801 *writepos += device->writelead;
802 while (*writepos >= device->buflen) *writepos -= device->buflen;
803 }
804
805 LeaveCriticalSection(&(device->mixlock));
806 /* **** */
807
808 TRACE("playpos = %d, writepos = %d (%p, time=%d)\n", playpos?*playpos:0, writepos?*writepos:0, device, GetTickCount());
809 return DS_OK;
810 }
811
PrimaryBufferImpl_GetStatus(LPDIRECTSOUNDBUFFER iface,LPDWORD status)812 static HRESULT WINAPI PrimaryBufferImpl_GetStatus(
813 LPDIRECTSOUNDBUFFER iface,LPDWORD status
814 ) {
815 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
816 DirectSoundDevice *device = This->device;
817 TRACE("(%p,%p)\n", iface, status);
818
819 if (status == NULL) {
820 WARN("invalid parameter: status == NULL\n");
821 return DSERR_INVALIDPARAM;
822 }
823
824 *status = 0;
825 if ((device->state == STATE_STARTING) ||
826 (device->state == STATE_PLAYING))
827 *status |= DSBSTATUS_PLAYING | DSBSTATUS_LOOPING;
828
829 TRACE("status=%x\n", *status);
830 return DS_OK;
831 }
832
833
PrimaryBufferImpl_GetFormat(LPDIRECTSOUNDBUFFER iface,LPWAVEFORMATEX lpwf,DWORD wfsize,LPDWORD wfwritten)834 static HRESULT WINAPI PrimaryBufferImpl_GetFormat(
835 LPDIRECTSOUNDBUFFER iface,
836 LPWAVEFORMATEX lpwf,
837 DWORD wfsize,
838 LPDWORD wfwritten)
839 {
840 DWORD size;
841 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
842 DirectSoundDevice *device = This->device;
843 TRACE("(%p,%p,%d,%p)\n", iface, lpwf, wfsize, wfwritten);
844
845 size = sizeof(WAVEFORMATEX) + device->pwfx->cbSize;
846
847 if (lpwf) { /* NULL is valid */
848 if (wfsize >= size) {
849 CopyMemory(lpwf,device->pwfx,size);
850 if (wfwritten)
851 *wfwritten = size;
852 } else {
853 WARN("invalid parameter: wfsize too small\n");
854 if (wfwritten)
855 *wfwritten = 0;
856 return DSERR_INVALIDPARAM;
857 }
858 } else {
859 if (wfwritten)
860 *wfwritten = sizeof(WAVEFORMATEX) + device->pwfx->cbSize;
861 else {
862 WARN("invalid parameter: wfwritten == NULL\n");
863 return DSERR_INVALIDPARAM;
864 }
865 }
866
867 return DS_OK;
868 }
869
PrimaryBufferImpl_Lock(LPDIRECTSOUNDBUFFER iface,DWORD writecursor,DWORD writebytes,LPVOID * lplpaudioptr1,LPDWORD audiobytes1,LPVOID * lplpaudioptr2,LPDWORD audiobytes2,DWORD flags)870 static HRESULT WINAPI PrimaryBufferImpl_Lock(
871 LPDIRECTSOUNDBUFFER iface,DWORD writecursor,DWORD writebytes,LPVOID *lplpaudioptr1,LPDWORD audiobytes1,LPVOID *lplpaudioptr2,LPDWORD audiobytes2,DWORD flags
872 ) {
873 HRESULT hres;
874 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
875 DirectSoundDevice *device = This->device;
876 TRACE("(%p,%d,%d,%p,%p,%p,%p,0x%08x) at %d\n",
877 iface,
878 writecursor,
879 writebytes,
880 lplpaudioptr1,
881 audiobytes1,
882 lplpaudioptr2,
883 audiobytes2,
884 flags,
885 GetTickCount()
886 );
887
888 if (!audiobytes1)
889 return DSERR_INVALIDPARAM;
890
891 if (device->priolevel != DSSCL_WRITEPRIMARY) {
892 WARN("failed priority check!\n");
893 return DSERR_PRIOLEVELNEEDED;
894 }
895
896 /* when this flag is set, writecursor is meaningless and must be calculated */
897 if (flags & DSBLOCK_FROMWRITECURSOR) {
898 /* GetCurrentPosition does too much magic to duplicate here */
899 hres = IDirectSoundBuffer_GetCurrentPosition(iface, NULL, &writecursor);
900 if (hres != DS_OK) {
901 WARN("IDirectSoundBuffer_GetCurrentPosition failed\n");
902 return hres;
903 }
904 }
905
906 /* when this flag is set, writebytes is meaningless and must be set */
907 if (flags & DSBLOCK_ENTIREBUFFER)
908 writebytes = device->buflen;
909
910 if (writecursor >= device->buflen) {
911 WARN("Invalid parameter, writecursor: %u >= buflen: %u\n",
912 writecursor, device->buflen);
913 return DSERR_INVALIDPARAM;
914 }
915
916 if (writebytes > device->buflen) {
917 WARN("Invalid parameter, writebytes: %u > buflen: %u\n",
918 writebytes, device->buflen);
919 return DSERR_INVALIDPARAM;
920 }
921
922 if (!(device->drvdesc.dwFlags & DSDDESC_DONTNEEDPRIMARYLOCK) && device->hwbuf) {
923 hres = IDsDriverBuffer_Lock(device->hwbuf,
924 lplpaudioptr1, audiobytes1,
925 lplpaudioptr2, audiobytes2,
926 writecursor, writebytes,
927 0);
928 if (hres != DS_OK) {
929 WARN("IDsDriverBuffer_Lock failed\n");
930 return hres;
931 }
932 } else {
933 if (writecursor+writebytes <= device->buflen) {
934 *(LPBYTE*)lplpaudioptr1 = device->buffer+writecursor;
935 *audiobytes1 = writebytes;
936 if (lplpaudioptr2)
937 *(LPBYTE*)lplpaudioptr2 = NULL;
938 if (audiobytes2)
939 *audiobytes2 = 0;
940 TRACE("->%d.0\n",writebytes);
941 } else {
942 *(LPBYTE*)lplpaudioptr1 = device->buffer+writecursor;
943 *audiobytes1 = device->buflen-writecursor;
944 if (lplpaudioptr2)
945 *(LPBYTE*)lplpaudioptr2 = device->buffer;
946 if (audiobytes2)
947 *audiobytes2 = writebytes-(device->buflen-writecursor);
948 TRACE("->%d.%d\n",*audiobytes1,audiobytes2?*audiobytes2:0);
949 }
950 }
951 return DS_OK;
952 }
953
PrimaryBufferImpl_SetCurrentPosition(LPDIRECTSOUNDBUFFER iface,DWORD newpos)954 static HRESULT WINAPI PrimaryBufferImpl_SetCurrentPosition(
955 LPDIRECTSOUNDBUFFER iface,DWORD newpos
956 ) {
957 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
958 TRACE("(%p,%d)\n",This,newpos);
959
960 /* You cannot set the position of the primary buffer */
961 WARN("invalid call\n");
962 return DSERR_INVALIDCALL;
963 }
964
PrimaryBufferImpl_SetPan(LPDIRECTSOUNDBUFFER iface,LONG pan)965 static HRESULT WINAPI PrimaryBufferImpl_SetPan(
966 LPDIRECTSOUNDBUFFER iface,LONG pan
967 ) {
968 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
969 DirectSoundDevice *device = This->device;
970 DWORD ampfactors;
971 HRESULT hres = DS_OK;
972 TRACE("(%p,%d)\n", iface, pan);
973
974 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN)) {
975 WARN("control unavailable\n");
976 return DSERR_CONTROLUNAVAIL;
977 }
978
979 if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT)) {
980 WARN("invalid parameter: pan = %d\n", pan);
981 return DSERR_INVALIDPARAM;
982 }
983
984 /* **** */
985 EnterCriticalSection(&(device->mixlock));
986
987 if (!device->hwbuf)
988 {
989 waveOutGetVolume(device->hwo, &factors);
990 device->volpan.dwTotalLeftAmpFactor=ampfactors & 0xffff;
991 device->volpan.dwTotalRightAmpFactor=ampfactors >> 16;
992 DSOUND_AmpFactorToVolPan(&device->volpan);
993 }
994 if (pan != device->volpan.lPan) {
995 device->volpan.lPan=pan;
996 DSOUND_RecalcVolPan(&device->volpan);
997 if (device->hwbuf) {
998 hres = IDsDriverBuffer_SetVolumePan(device->hwbuf, &device->volpan);
999 if (hres != DS_OK)
1000 WARN("IDsDriverBuffer_SetVolumePan failed\n");
1001 } else {
1002 ampfactors = (device->volpan.dwTotalLeftAmpFactor & 0xffff) | (device->volpan.dwTotalRightAmpFactor << 16);
1003 waveOutSetVolume(device->hwo, ampfactors);
1004 }
1005 }
1006
1007 LeaveCriticalSection(&(device->mixlock));
1008 /* **** */
1009
1010 return hres;
1011 }
1012
PrimaryBufferImpl_GetPan(LPDIRECTSOUNDBUFFER iface,LPLONG pan)1013 static HRESULT WINAPI PrimaryBufferImpl_GetPan(
1014 LPDIRECTSOUNDBUFFER iface,LPLONG pan
1015 ) {
1016 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
1017 DirectSoundDevice *device = This->device;
1018 DWORD ampfactors;
1019 TRACE("(%p,%p)\n", iface, pan);
1020
1021 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN)) {
1022 WARN("control unavailable\n");
1023 return DSERR_CONTROLUNAVAIL;
1024 }
1025
1026 if (pan == NULL) {
1027 WARN("invalid parameter: pan == NULL\n");
1028 return DSERR_INVALIDPARAM;
1029 }
1030
1031 if (!device->hwbuf)
1032 {
1033 waveOutGetVolume(device->hwo, &factors);
1034 device->volpan.dwTotalLeftAmpFactor=ampfactors & 0xffff;
1035 device->volpan.dwTotalRightAmpFactor=ampfactors >> 16;
1036 DSOUND_AmpFactorToVolPan(&device->volpan);
1037 }
1038 *pan = device->volpan.lPan;
1039 return DS_OK;
1040 }
1041
PrimaryBufferImpl_Unlock(LPDIRECTSOUNDBUFFER iface,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2)1042 static HRESULT WINAPI PrimaryBufferImpl_Unlock(
1043 LPDIRECTSOUNDBUFFER iface,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2
1044 ) {
1045 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
1046 DirectSoundDevice *device = This->device;
1047 TRACE("(%p,%p,%d,%p,%d)\n", iface, p1, x1, p2, x2);
1048
1049 if (device->priolevel != DSSCL_WRITEPRIMARY) {
1050 WARN("failed priority check!\n");
1051 return DSERR_PRIOLEVELNEEDED;
1052 }
1053
1054 if (!(device->drvdesc.dwFlags & DSDDESC_DONTNEEDPRIMARYLOCK) && device->hwbuf) {
1055 HRESULT hres;
1056
1057 if ((char *)p1 - (char *)device->buffer + x1 > device->buflen)
1058 hres = DSERR_INVALIDPARAM;
1059 else
1060 hres = IDsDriverBuffer_Unlock(device->hwbuf, p1, x1, p2, x2);
1061
1062 if (hres != DS_OK) {
1063 WARN("IDsDriverBuffer_Unlock failed\n");
1064 return hres;
1065 }
1066 }
1067
1068 return DS_OK;
1069 }
1070
PrimaryBufferImpl_Restore(LPDIRECTSOUNDBUFFER iface)1071 static HRESULT WINAPI PrimaryBufferImpl_Restore(
1072 LPDIRECTSOUNDBUFFER iface
1073 ) {
1074 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
1075 FIXME("(%p):stub\n",This);
1076 return DS_OK;
1077 }
1078
PrimaryBufferImpl_GetFrequency(LPDIRECTSOUNDBUFFER iface,LPDWORD freq)1079 static HRESULT WINAPI PrimaryBufferImpl_GetFrequency(
1080 LPDIRECTSOUNDBUFFER iface,LPDWORD freq
1081 ) {
1082 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
1083 DirectSoundDevice *device = This->device;
1084 TRACE("(%p,%p)\n", iface, freq);
1085
1086 if (freq == NULL) {
1087 WARN("invalid parameter: freq == NULL\n");
1088 return DSERR_INVALIDPARAM;
1089 }
1090
1091 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLFREQUENCY)) {
1092 WARN("control unavailable\n");
1093 return DSERR_CONTROLUNAVAIL;
1094 }
1095
1096 *freq = device->pwfx->nSamplesPerSec;
1097 TRACE("-> %d\n", *freq);
1098
1099 return DS_OK;
1100 }
1101
PrimaryBufferImpl_Initialize(LPDIRECTSOUNDBUFFER iface,LPDIRECTSOUND dsound,LPCDSBUFFERDESC dbsd)1102 static HRESULT WINAPI PrimaryBufferImpl_Initialize(
1103 LPDIRECTSOUNDBUFFER iface,LPDIRECTSOUND dsound,LPCDSBUFFERDESC dbsd
1104 ) {
1105 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
1106 WARN("(%p) already initialized\n", This);
1107 return DSERR_ALREADYINITIALIZED;
1108 }
1109
PrimaryBufferImpl_GetCaps(LPDIRECTSOUNDBUFFER iface,LPDSBCAPS caps)1110 static HRESULT WINAPI PrimaryBufferImpl_GetCaps(
1111 LPDIRECTSOUNDBUFFER iface,LPDSBCAPS caps
1112 ) {
1113 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
1114 DirectSoundDevice *device = This->device;
1115 TRACE("(%p,%p)\n", iface, caps);
1116
1117 if (caps == NULL) {
1118 WARN("invalid parameter: caps == NULL\n");
1119 return DSERR_INVALIDPARAM;
1120 }
1121
1122 if (caps->dwSize < sizeof(*caps)) {
1123 WARN("invalid parameter: caps->dwSize = %d\n", caps->dwSize);
1124 return DSERR_INVALIDPARAM;
1125 }
1126
1127 caps->dwFlags = This->dsbd.dwFlags;
1128 caps->dwBufferBytes = device->buflen;
1129
1130 /* Windows reports these as zero */
1131 caps->dwUnlockTransferRate = 0;
1132 caps->dwPlayCpuOverhead = 0;
1133
1134 return DS_OK;
1135 }
1136
PrimaryBufferImpl_QueryInterface(LPDIRECTSOUNDBUFFER iface,REFIID riid,LPVOID * ppobj)1137 static HRESULT WINAPI PrimaryBufferImpl_QueryInterface(
1138 LPDIRECTSOUNDBUFFER iface,REFIID riid,LPVOID *ppobj
1139 ) {
1140 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
1141 DirectSoundDevice *device = This->device;
1142 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(riid), ppobj);
1143
1144 if (ppobj == NULL) {
1145 WARN("invalid parameter\n");
1146 return E_INVALIDARG;
1147 }
1148
1149 *ppobj = NULL; /* assume failure */
1150
1151 if ( IsEqualGUID(riid, &IID_IUnknown) ||
1152 IsEqualGUID(riid, &IID_IDirectSoundBuffer) ) {
1153 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)This);
1154 *ppobj = This;
1155 return S_OK;
1156 }
1157
1158 /* DirectSoundBuffer and DirectSoundBuffer8 are different and */
1159 /* a primary buffer can't have a DirectSoundBuffer8 interface */
1160 if ( IsEqualGUID( &IID_IDirectSoundBuffer8, riid ) ) {
1161 WARN("app requested DirectSoundBuffer8 on primary buffer\n");
1162 return E_NOINTERFACE;
1163 }
1164
1165 if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
1166 ERR("app requested IDirectSoundNotify on primary buffer\n");
1167 /* FIXME: should we support this? */
1168 return E_NOINTERFACE;
1169 }
1170
1171 if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) {
1172 ERR("app requested IDirectSound3DBuffer on primary buffer\n");
1173 return E_NOINTERFACE;
1174 }
1175
1176 if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
1177 if (!device->listener)
1178 IDirectSound3DListenerImpl_Create(device, &device->listener);
1179 if (device->listener) {
1180 *ppobj = device->listener;
1181 IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER)*ppobj);
1182 return S_OK;
1183 }
1184
1185 WARN("IID_IDirectSound3DListener failed\n");
1186 return E_NOINTERFACE;
1187 }
1188
1189 if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) {
1190 FIXME("app requested IKsPropertySet on primary buffer\n");
1191 return E_NOINTERFACE;
1192 }
1193
1194 FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
1195 return E_NOINTERFACE;
1196 }
1197
1198 static const IDirectSoundBufferVtbl dspbvt =
1199 {
1200 PrimaryBufferImpl_QueryInterface,
1201 PrimaryBufferImpl_AddRef,
1202 PrimaryBufferImpl_Release,
1203 PrimaryBufferImpl_GetCaps,
1204 PrimaryBufferImpl_GetCurrentPosition,
1205 PrimaryBufferImpl_GetFormat,
1206 PrimaryBufferImpl_GetVolume,
1207 PrimaryBufferImpl_GetPan,
1208 PrimaryBufferImpl_GetFrequency,
1209 PrimaryBufferImpl_GetStatus,
1210 PrimaryBufferImpl_Initialize,
1211 PrimaryBufferImpl_Lock,
1212 PrimaryBufferImpl_Play,
1213 PrimaryBufferImpl_SetCurrentPosition,
1214 PrimaryBufferImpl_SetFormat,
1215 PrimaryBufferImpl_SetVolume,
1216 PrimaryBufferImpl_SetPan,
1217 PrimaryBufferImpl_SetFrequency,
1218 PrimaryBufferImpl_Stop,
1219 PrimaryBufferImpl_Unlock,
1220 PrimaryBufferImpl_Restore
1221 };
1222
primarybuffer_create(DirectSoundDevice * device,IDirectSoundBufferImpl ** ppdsb,const DSBUFFERDESC * dsbd)1223 HRESULT primarybuffer_create(DirectSoundDevice *device, IDirectSoundBufferImpl **ppdsb,
1224 const DSBUFFERDESC *dsbd)
1225 {
1226 IDirectSoundBufferImpl *dsb;
1227 TRACE("%p,%p,%p)\n",device,ppdsb,dsbd);
1228
1229 if (dsbd->lpwfxFormat) {
1230 WARN("invalid parameter: dsbd->lpwfxFormat != NULL\n");
1231 *ppdsb = NULL;
1232 return DSERR_INVALIDPARAM;
1233 }
1234
1235 dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
1236
1237 if (dsb == NULL) {
1238 WARN("out of memory\n");
1239 *ppdsb = NULL;
1240 return DSERR_OUTOFMEMORY;
1241 }
1242
1243 dsb->ref = 1;
1244 dsb->numIfaces = 1;
1245 dsb->device = device;
1246 dsb->IDirectSoundBuffer8_iface.lpVtbl = (IDirectSoundBuffer8Vtbl *)&dspbvt;
1247 dsb->dsbd = *dsbd;
1248
1249 TRACE("Created primary buffer at %p\n", dsb);
1250 TRACE("(formattag=0x%04x,chans=%d,samplerate=%d,"
1251 "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1252 device->pwfx->wFormatTag, device->pwfx->nChannels,
1253 device->pwfx->nSamplesPerSec, device->pwfx->nAvgBytesPerSec,
1254 device->pwfx->nBlockAlign, device->pwfx->wBitsPerSample,
1255 device->pwfx->cbSize);
1256
1257 *ppdsb = dsb;
1258 return S_OK;
1259 }
1260