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 */ 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 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 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 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 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 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 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 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 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 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 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 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 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 */ 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 */ 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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