Reduce MAX_HWBUFFERS to 128
[dsound-openal.git] / buffer.c
blob302eb5baca8a39c9af5c7fc165a2ff913f6813f6
1 /* DirectSound COM interface
3 * Copyright 2009 Maarten Lankhorst
5 * Some code taken from the original dsound-openal implementation
6 * Copyright 2007-2009 Chris Robinson
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #define CONST_VTABLE
24 #include <stdarg.h>
25 #include <string.h>
27 #include "windows.h"
28 #include "dsound.h"
29 #include "mmsystem.h"
30 #include "ks.h"
31 #include <devpropdef.h>
33 #include "dsound_private.h"
36 #ifndef DS_INCOMPLETE
37 #define DS_INCOMPLETE ((HRESULT)0x08780020)
38 #endif
40 #ifndef WAVE_FORMAT_IEEE_FLOAT
41 #define WAVE_FORMAT_IEEE_FLOAT 3
42 #endif
45 /* TODO: when bufferlost is set, return from all calls except initialize with
46 * DSERR_BUFFERLOST
48 static IDirectSoundBuffer8Vtbl DSBuffer_Vtbl;
49 static IDirectSound3DBufferVtbl DSBuffer3d_Vtbl;
50 static IDirectSoundNotifyVtbl DSBufferNot_Vtbl;
51 static IKsPropertySetVtbl DSBufferProp_Vtbl;
54 static inline DSBuffer *impl_from_IDirectSoundBuffer8(IDirectSoundBuffer8 *iface)
56 return CONTAINING_RECORD(iface, DSBuffer, IDirectSoundBuffer8_iface);
59 static inline DSBuffer *impl_from_IDirectSoundBuffer(IDirectSoundBuffer *iface)
61 return CONTAINING_RECORD(iface, DSBuffer, IDirectSoundBuffer8_iface);
64 static inline DSBuffer *impl_from_IDirectSound3DBuffer(IDirectSound3DBuffer *iface)
66 return CONTAINING_RECORD(iface, DSBuffer, IDirectSound3DBuffer_iface);
69 static inline DSBuffer *impl_from_IDirectSoundNotify(IDirectSoundNotify *iface)
71 return CONTAINING_RECORD(iface, DSBuffer, IDirectSoundNotify_iface);
74 static inline DSBuffer *impl_from_IKsPropertySet(IKsPropertySet *iface)
76 return CONTAINING_RECORD(iface, DSBuffer, IKsPropertySet_iface);
80 /* Should be called with critsect held and context set.. */
81 static void DSBuffer_addnotify(DSBuffer *buf)
83 DSPrimary *prim = buf->primary;
84 DSBuffer **list;
85 DWORD i;
87 list = prim->notifies;
88 for(i = 0; i < prim->nnotifies; ++i)
90 if(buf == list[i])
92 ERR("Buffer %p already in notification list\n", buf);
93 return;
96 if(prim->nnotifies == prim->sizenotifies)
98 list = HeapReAlloc(GetProcessHeap(), 0, list, (prim->nnotifies + 1) * sizeof(*list));
99 if(!list) return;
100 prim->sizenotifies++;
102 list[prim->nnotifies++] = buf;
103 prim->notifies = list;
107 static const char *get_fmtstr_PCM(const DSPrimary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out)
109 out->Format = *format;
110 out->Format.cbSize = 0;
112 if(out->Format.nChannels != 1 && out->Format.nChannels != 2 &&
113 !HAS_EXTENSION(prim->share, EXT_MCFORMATS))
115 WARN("Multi-channel not available\n");
116 return NULL;
119 if(format->wBitsPerSample == 8)
121 switch(format->nChannels)
123 case 1: return "AL_FORMAT_MONO8";
124 case 2: return "AL_FORMAT_STEREO8";
125 case 4: return "AL_FORMAT_QUAD8";
126 case 6: return "AL_FORMAT_51CHN8";
127 case 7: return "AL_FORMAT_61CHN8";
128 case 8: return "AL_FORMAT_71CHN8";
131 else if(format->wBitsPerSample == 16)
133 switch(format->nChannels)
135 case 1: return "AL_FORMAT_MONO16";
136 case 2: return "AL_FORMAT_STEREO16";
137 case 4: return "AL_FORMAT_QUAD16";
138 case 6: return "AL_FORMAT_51CHN16";
139 case 7: return "AL_FORMAT_61CHN16";
140 case 8: return "AL_FORMAT_71CHN16";
144 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
145 format->wBitsPerSample, format->nChannels);
146 return NULL;
149 static const char *get_fmtstr_FLOAT(const DSPrimary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out)
151 out->Format = *format;
152 out->Format.cbSize = 0;
154 if(out->Format.nChannels != 1 && out->Format.nChannels != 2 &&
155 !HAS_EXTENSION(prim->share, EXT_MCFORMATS))
157 WARN("Multi-channel not available\n");
158 return NULL;
161 if(format->wBitsPerSample == 32 && HAS_EXTENSION(prim->share, EXT_FLOAT32))
163 switch(format->nChannels)
165 case 1: return "AL_FORMAT_MONO_FLOAT32";
166 case 2: return "AL_FORMAT_STEREO_FLOAT32";
167 case 4: return "AL_FORMAT_QUAD32";
168 case 6: return "AL_FORMAT_51CHN32";
169 case 7: return "AL_FORMAT_61CHN32";
170 case 8: return "AL_FORMAT_71CHN32";
174 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
175 format->wBitsPerSample, format->nChannels);
176 return NULL;
179 /* Speaker configs */
180 #define MONO SPEAKER_FRONT_CENTER
181 #define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)
182 #define REAR (SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
183 #define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
184 #define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
185 #define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
186 #define X7DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
188 static const char *get_fmtstr_EXT(const DSPrimary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out)
190 *out = *CONTAINING_RECORD(format, const WAVEFORMATEXTENSIBLE, Format);
191 out->Format.cbSize = sizeof(*out) - sizeof(out->Format);
193 if(!out->Samples.wValidBitsPerSample)
194 out->Samples.wValidBitsPerSample = out->Format.wBitsPerSample;
195 else if(out->Samples.wValidBitsPerSample > out->Format.wBitsPerSample)
197 WARN("Invalid ValidBitsPerSample (%u > %u)\n", out->Samples.wValidBitsPerSample, out->Format.wBitsPerSample);
198 return NULL;
200 else if(out->Samples.wValidBitsPerSample < out->Format.wBitsPerSample)
202 FIXME("Padded samples not supported (%u of %u)\n", out->Samples.wValidBitsPerSample, out->Format.wBitsPerSample);
203 return NULL;
206 if(out->dwChannelMask != MONO && out->dwChannelMask != STEREO &&
207 !HAS_EXTENSION(prim->share, EXT_MCFORMATS))
209 WARN("Multi-channel not available\n");
210 return NULL;
213 if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
215 if(out->Samples.wValidBitsPerSample == 8)
217 switch(out->dwChannelMask)
219 case MONO: return "AL_FORMAT_MONO8";
220 case STEREO: return "AL_FORMAT_STEREO8";
221 case REAR: return "AL_FORMAT_REAR8";
222 case QUAD: return "AL_FORMAT_QUAD8";
223 case X5DOT1: return "AL_FORMAT_51CHN8";
224 case X6DOT1: return "AL_FORMAT_61CHN8";
225 case X7DOT1: return "AL_FORMAT_71CHN8";
228 else if(out->Samples.wValidBitsPerSample == 16)
230 switch(out->dwChannelMask)
232 case MONO: return "AL_FORMAT_MONO16";
233 case STEREO: return "AL_FORMAT_STEREO16";
234 case REAR: return "AL_FORMAT_REAR16";
235 case QUAD: return "AL_FORMAT_QUAD16";
236 case X5DOT1: return "AL_FORMAT_51CHN16";
237 case X6DOT1: return "AL_FORMAT_61CHN16";
238 case X7DOT1: return "AL_FORMAT_71CHN16";
242 FIXME("Could not get OpenAL PCM format (%d-bit, channelmask %#lx)\n",
243 out->Samples.wValidBitsPerSample, out->dwChannelMask);
244 return NULL;
246 else if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) &&
247 HAS_EXTENSION(prim->share, EXT_FLOAT32))
249 if(out->Samples.wValidBitsPerSample == 32)
251 switch(out->dwChannelMask)
253 case MONO: return "AL_FORMAT_MONO_FLOAT32";
254 case STEREO: return "AL_FORMAT_STEREO_FLOAT32";
255 case REAR: return "AL_FORMAT_REAR32";
256 case QUAD: return "AL_FORMAT_QUAD32";
257 case X5DOT1: return "AL_FORMAT_51CHN32";
258 case X6DOT1: return "AL_FORMAT_61CHN32";
259 case X7DOT1: return "AL_FORMAT_71CHN32";
262 else
264 WARN("Invalid float bits: %u\n", out->Samples.wValidBitsPerSample);
265 return NULL;
268 FIXME("Could not get OpenAL float format (%d-bit, channelmask %#lx)\n",
269 out->Samples.wValidBitsPerSample, out->dwChannelMask);
270 return NULL;
272 else if(!IsEqualGUID(&out->SubFormat, &GUID_NULL))
273 ERR("Unhandled extensible format: %s\n", debugstr_guid(&out->SubFormat));
274 return NULL;
277 static void DSData_Release(DSData *This);
278 static HRESULT DSData_Create(DSData **ppv, const DSBUFFERDESC *desc, DSPrimary *prim)
280 HRESULT hr = DSERR_INVALIDPARAM;
281 const WAVEFORMATEX *format;
282 const char *fmt_str = NULL;
283 DSData *pBuffer;
284 DWORD buf_size;
286 format = desc->lpwfxFormat;
287 TRACE("Requested buffer format:\n"
288 " FormatTag = 0x%04x\n"
289 " Channels = %d\n"
290 " SamplesPerSec = %lu\n"
291 " AvgBytesPerSec = %lu\n"
292 " BlockAlign = %d\n"
293 " BitsPerSample = %d\n",
294 format->wFormatTag, format->nChannels,
295 format->nSamplesPerSec, format->nAvgBytesPerSec,
296 format->nBlockAlign, format->wBitsPerSample);
298 if(format->nChannels <= 0)
300 WARN("Invalid Channels %d\n", format->nChannels);
301 return DSERR_INVALIDPARAM;
303 if(format->nSamplesPerSec < DSBFREQUENCY_MIN || format->nSamplesPerSec > DSBFREQUENCY_MAX)
305 WARN("Invalid SamplesPerSec %lu\n", format->nSamplesPerSec);
306 return DSERR_INVALIDPARAM;
308 if(format->nBlockAlign <= 0)
310 WARN("Invalid BlockAlign %d\n", format->nBlockAlign);
311 return DSERR_INVALIDPARAM;
313 if(format->wBitsPerSample == 0 || (format->wBitsPerSample%8) != 0)
315 WARN("Invalid BitsPerSample %d\n", format->wBitsPerSample);
316 return DSERR_INVALIDPARAM;
318 if(format->nBlockAlign != format->nChannels*format->wBitsPerSample/8)
320 WARN("Invalid BlockAlign %d (expected %u = %u*%u/8)\n",
321 format->nBlockAlign, format->nChannels*format->wBitsPerSample/8,
322 format->nChannels, format->wBitsPerSample);
323 return DSERR_INVALIDPARAM;
325 /* HACK: Some games provide an incorrect value here and expect to work.
326 * This is clearly not supposed to succeed with just anything, but until
327 * the amount of leeway allowed is discovered, be very lenient.
329 if(format->nAvgBytesPerSec == 0)
331 WARN("Invalid AvgBytesPerSec %lu (expected %lu = %lu*%u)\n",
332 format->nAvgBytesPerSec, format->nSamplesPerSec*format->nBlockAlign,
333 format->nSamplesPerSec, format->nBlockAlign);
334 return DSERR_INVALIDPARAM;
336 if(format->nAvgBytesPerSec != format->nBlockAlign*format->nSamplesPerSec)
337 WARN("Unexpected AvgBytesPerSec %lu (expected %lu = %lu*%u)\n",
338 format->nAvgBytesPerSec, format->nSamplesPerSec*format->nBlockAlign,
339 format->nSamplesPerSec, format->nBlockAlign);
341 if((desc->dwFlags&(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE)) == (DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE))
343 WARN("Hardware and software location requested\n");
344 return DSERR_INVALIDPARAM;
347 buf_size = desc->dwBufferBytes + format->nBlockAlign - 1;
348 buf_size -= buf_size%format->nBlockAlign;
349 if(buf_size < DSBSIZE_MIN) return DSERR_BUFFERTOOSMALL;
350 if(buf_size > DSBSIZE_MAX) return DSERR_INVALIDPARAM;
352 /* Generate a new buffer. Supporting the DSBCAPS_LOC* flags properly
353 * will need the EAX-RAM extension. Currently, we just tell the app it
354 * gets what it wanted. */
355 if(!HAS_EXTENSION(prim->share, SOFTX_MAP_BUFFER))
356 pBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pBuffer)+buf_size);
357 else
358 pBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pBuffer));
359 if(!pBuffer) return E_OUTOFMEMORY;
360 pBuffer->ref = 1;
361 pBuffer->primary = prim;
363 pBuffer->dsbflags = desc->dwFlags;
364 pBuffer->buf_size = buf_size;
366 if(format->wFormatTag == WAVE_FORMAT_PCM)
367 fmt_str = get_fmtstr_PCM(prim, format, &pBuffer->format);
368 else if(format->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
369 fmt_str = get_fmtstr_FLOAT(prim, format, &pBuffer->format);
370 else if(format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
372 const WAVEFORMATEXTENSIBLE *wfe;
374 if(format->cbSize != sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) &&
375 format->cbSize != sizeof(WAVEFORMATEXTENSIBLE))
376 goto fail;
378 wfe = CONTAINING_RECORD(format, const WAVEFORMATEXTENSIBLE, Format);
379 TRACE("Extensible values:\n"
380 " Samples = %d\n"
381 " ChannelMask = 0x%lx\n"
382 " SubFormat = %s\n",
383 wfe->Samples.wReserved, wfe->dwChannelMask,
384 debugstr_guid(&wfe->SubFormat));
386 fmt_str = get_fmtstr_EXT(prim, format, &pBuffer->format);
388 else
389 ERR("Unhandled formattag 0x%04x\n", format->wFormatTag);
390 if(!fmt_str) goto fail;
392 alGetError();
393 pBuffer->buf_format = alGetEnumValue(fmt_str);
394 if(alGetError() != AL_NO_ERROR || pBuffer->buf_format == 0 ||
395 pBuffer->buf_format == -1)
397 WARN("Could not get OpenAL format from %s\n", fmt_str);
398 goto fail;
401 hr = E_OUTOFMEMORY;
402 if(!HAS_EXTENSION(prim->share, SOFTX_MAP_BUFFER))
404 pBuffer->data = (BYTE*)(pBuffer+1);
406 alGenBuffers(1, &pBuffer->bid);
407 checkALError();
409 else
411 const ALbitfieldSOFT map_bits = AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT |
412 AL_MAP_PERSISTENT_BIT_SOFT;
413 alGenBuffers(1, &pBuffer->bid);
414 alBufferStorageSOFT(pBuffer->bid, pBuffer->buf_format, NULL, pBuffer->buf_size,
415 pBuffer->format.Format.nSamplesPerSec, map_bits);
416 pBuffer->data = alMapBufferSOFT(pBuffer->bid, 0, pBuffer->buf_size, map_bits);
417 checkALError();
419 if(!pBuffer->data) goto fail;
422 *ppv = pBuffer;
423 return S_OK;
425 fail:
426 DSData_Release(pBuffer);
427 return hr;
430 static void DSData_AddRef(DSData *data)
432 InterlockedIncrement(&data->ref);
435 /* This function is always called with the device lock held */
436 static void DSData_Release(DSData *This)
438 if(InterlockedDecrement(&This->ref)) return;
440 TRACE("Deleting %p\n", This);
441 if(This->bid)
443 DSPrimary *prim = This->primary;
444 if(HAS_EXTENSION(prim->share, SOFTX_MAP_BUFFER))
445 alUnmapBufferSOFT(This->bid);
446 alDeleteBuffers(1, &This->bid);
447 checkALError();
449 HeapFree(GetProcessHeap(), 0, This);
453 HRESULT DSBuffer_Create(DSBuffer **ppv, DSPrimary *prim, IDirectSoundBuffer *orig)
455 DSBuffer *This = NULL;
456 DWORD i;
458 *ppv = NULL;
459 EnterCriticalSection(&prim->share->crst);
460 for(i = 0;i < prim->NumBufferGroups;++i)
462 if(prim->BufferGroups[i].FreeBuffers)
464 int idx = CTZ64(prim->BufferGroups[i].FreeBuffers);
465 This = prim->BufferGroups[i].Buffers + idx;
466 memset(This, 0, sizeof(*This));
467 prim->BufferGroups[i].FreeBuffers &= ~(U64(1) << idx);
468 break;
471 if(!This)
473 struct DSBufferGroup *grp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
474 (prim->NumBufferGroups+1)*sizeof(prim->BufferGroups[0]));
475 if(grp)
477 for(i = 0;i < prim->NumBufferGroups;i++)
478 grp[i] = prim->BufferGroups[i];
479 grp[i].FreeBuffers = ~U64(0);
480 grp[i].Buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
481 64*sizeof(grp[0].Buffers[0]));
482 if(!grp[i].Buffers)
484 HeapFree(GetProcessHeap(), 0, grp);
485 grp = NULL;
487 else
489 HeapFree(GetProcessHeap(), 0, prim->BufferGroups);
490 prim->BufferGroups = grp;
491 prim->NumBufferGroups++;
493 This = prim->BufferGroups[i].Buffers + 0;
494 memset(This, 0, sizeof(*This));
495 prim->BufferGroups[i].FreeBuffers &= ~(U64(1) << 0);
499 LeaveCriticalSection(&prim->share->crst);
500 if(!This)
502 WARN("Out of memory allocating buffers\n");
503 return DSERR_OUTOFMEMORY;
506 This->IDirectSoundBuffer8_iface.lpVtbl = &DSBuffer_Vtbl;
507 This->IDirectSound3DBuffer_iface.lpVtbl = &DSBuffer3d_Vtbl;
508 This->IDirectSoundNotify_iface.lpVtbl = &DSBufferNot_Vtbl;
509 This->IKsPropertySet_iface.lpVtbl = &DSBufferProp_Vtbl;
511 This->share = prim->share;
512 This->primary = prim;
513 This->ctx = prim->ctx;
515 This->current.vol = 0;
516 This->current.pan = 0;
517 This->current.frequency = 0;
518 This->current.ds3d.dwSize = sizeof(This->current.ds3d);
519 This->current.ds3d.vPosition.x = 0.0f;
520 This->current.ds3d.vPosition.y = 0.0f;
521 This->current.ds3d.vPosition.z = 0.0f;
522 This->current.ds3d.vVelocity.x = 0.0f;
523 This->current.ds3d.vVelocity.y = 0.0f;
524 This->current.ds3d.vVelocity.z = 0.0f;
525 This->current.ds3d.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
526 This->current.ds3d.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
527 This->current.ds3d.vConeOrientation.x = 0.0f;
528 This->current.ds3d.vConeOrientation.y = 0.0f;
529 This->current.ds3d.vConeOrientation.z = 1.0f;
530 This->current.ds3d.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
531 This->current.ds3d.flMinDistance = DS3D_DEFAULTMINDISTANCE;
532 This->current.ds3d.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
533 This->current.ds3d.dwMode = DS3DMODE_NORMAL;
534 This->current.eax.lDirect = 0;
535 This->current.eax.lDirectHF = 0;
536 This->current.eax.lRoom = 0;
537 This->current.eax.lRoomHF = 0;
538 This->current.eax.lObstruction = 0;
539 This->current.eax.flObstructionLFRatio = 0.0f;
540 This->current.eax.lOcclusion = 0;
541 This->current.eax.flOcclusionLFRatio = 0.25f;
542 This->current.eax.flOcclusionRoomRatio = 1.5f;
543 This->current.eax.flOcclusionDirectRatio = 1.0f;
544 This->current.eax.lExclusion = 0;
545 This->current.eax.flExclusionLFRatio = 1.0f;
546 This->current.eax.lOutsideVolumeHF = 0;
547 This->current.eax.flDopplerFactor = 1.0f;
548 This->current.eax.flRolloffFactor = 0.0f;
549 This->current.eax.flRoomRolloffFactor = 0.0f;
550 This->current.eax.flAirAbsorptionFactor = 0.0f;
551 This->current.eax.dwFlags = EAXSOURCEFLAGS_DIRECTHFAUTO | EAXSOURCEFLAGS_ROOMAUTO |
552 EAXSOURCEFLAGS_ROOMHFAUTO;
553 This->current.fxslot_targets[0] = FXSLOT_TARGET_PRIMARY;
554 for(i = 1;i < EAX_MAX_ACTIVE_FXSLOTS;++i)
555 This->current.fxslot_targets[i] = FXSLOT_TARGET_NULL;
556 for(i = 0;i < EAX_MAX_FXSLOTS;++i)
558 This->current.send[i].lSend = 0;
559 This->current.send[i].lSendHF = 0;
560 This->current.send[i].lOcclusion = 0;
561 This->current.send[i].flOcclusionLFRatio = 0.25f;
562 This->current.send[i].flOcclusionRoomRatio = 1.5f;
563 This->current.send[i].flOcclusionDirectRatio = 1.0f;
564 This->current.send[i].lExclusion = 0;
565 This->current.send[i].flExclusionLFRatio = 1.0f;
567 This->current.eax1_reverbmix = 1.0f;
569 if(orig)
571 DSBuffer *org = impl_from_IDirectSoundBuffer(orig);
572 DSData *data = org->buffer;
574 if(org->bufferlost)
576 DSBuffer_Destroy(This);
577 return DSERR_BUFFERLOST;
579 DSData_AddRef(data);
580 This->buffer = data;
582 /* According to MSDN, volume isn't copied. */
583 if((data->dsbflags&DSBCAPS_CTRLPAN))
584 This->current.pan = org->current.pan;
585 if((data->dsbflags&DSBCAPS_CTRLFREQUENCY))
586 This->current.frequency = org->current.frequency;
587 if((data->dsbflags&DSBCAPS_CTRL3D))
588 This->current.ds3d = org->current.ds3d;
591 This->deferred.ds3d = This->current.ds3d;
592 This->deferred.eax = This->current.eax;
593 for(i = 0;i < EAX_MAX_ACTIVE_FXSLOTS;++i)
594 This->deferred.fxslot_targets[i] = This->current.fxslot_targets[i];
595 for(i = 0;i < EAX_MAX_FXSLOTS;++i)
596 This->deferred.send[i] = This->current.send[i];
597 This->deferred.eax1_reverbmix = This->current.eax1_reverbmix;
599 This->vm_voicepriority = (DWORD)-1;
601 *ppv = This;
602 return DS_OK;
605 void DSBuffer_Destroy(DSBuffer *This)
607 DSPrimary *prim = This->primary;
608 DWORD i;
610 if(!prim) return;
611 TRACE("Destroying %p\n", This);
613 EnterCriticalSection(&prim->share->crst);
614 /* Remove from list, if in list */
615 for(i = 0;i < prim->nnotifies;++i)
617 if(This == prim->notifies[i])
619 prim->notifies[i] = prim->notifies[--prim->nnotifies];
620 break;
624 setALContext(This->ctx);
625 if(This->source)
627 DeviceShare *share = This->share;
629 alSourceRewind(This->source);
630 alSourcei(This->source, AL_BUFFER, 0);
631 checkALError();
633 if(This->loc_status == DSBSTATUS_LOCHARDWARE)
634 share->sources.ids[share->sources.availhw_num++] = This->source;
635 else
637 DWORD base = share->sources.maxhw_alloc;
638 share->sources.ids[base + share->sources.availsw_num++] = This->source;
640 This->source = 0;
642 if(This->stream_bids[0])
643 alDeleteBuffers(QBUFFERS, This->stream_bids);
644 if(This->filter[0])
645 alDeleteFilters(1+EAX_MAX_FXSLOTS, This->filter);
647 if(This->buffer)
648 DSData_Release(This->buffer);
650 popALContext();
652 HeapFree(GetProcessHeap(), 0, This->notify);
654 for(i = 0;i < prim->NumBufferGroups;++i)
656 DWORD_PTR idx = This - prim->BufferGroups[i].Buffers;
657 if(idx < 64)
659 prim->BufferGroups[i].FreeBuffers |= U64(1) << idx;
660 This = NULL;
661 break;
664 LeaveCriticalSection(&prim->share->crst);
667 HRESULT DSBuffer_GetInterface(DSBuffer *buf, REFIID riid, void **ppv)
669 *ppv = NULL;
670 if(IsEqualIID(riid, &IID_IDirectSoundBuffer))
671 *ppv = &buf->IDirectSoundBuffer8_iface;
672 else if(IsEqualIID(riid, &IID_IDirectSoundBuffer8))
674 if(buf->primary->parent->is_8)
675 *ppv = &buf->IDirectSoundBuffer8_iface;
677 else if(IsEqualIID(riid, &IID_IDirectSound3DBuffer))
679 if((buf->buffer->dsbflags&DSBCAPS_CTRL3D))
680 *ppv = &buf->IDirectSound3DBuffer_iface;
682 else if(IsEqualIID(riid, &IID_IDirectSoundNotify))
684 if((buf->buffer->dsbflags&DSBCAPS_CTRLPOSITIONNOTIFY))
685 *ppv = &buf->IDirectSoundNotify_iface;
687 else if(IsEqualIID(riid, &IID_IKsPropertySet))
688 *ppv = &buf->IKsPropertySet_iface;
689 else if(IsEqualIID(riid, &IID_IUnknown))
690 *ppv = &buf->IDirectSoundBuffer8_iface;
691 else
692 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
694 if(*ppv)
696 IUnknown_AddRef((IUnknown*)*ppv);
697 return S_OK;
700 return E_NOINTERFACE;
703 static HRESULT DSBuffer_SetLoc(DSBuffer *buf, DWORD loc_status)
705 DeviceShare *share = buf->share;
706 DSData *data = buf->buffer;
707 ALsizei i;
709 if((loc_status && buf->loc_status == loc_status) || (!loc_status && buf->loc_status))
710 return DS_OK;
712 /* If we have a source, we're changing location, so return the source we
713 * have to get a new one.
715 if(buf->source)
717 alSourceRewind(buf->source);
718 alSourcei(buf->source, AL_BUFFER, 0);
719 checkALError();
721 if(buf->loc_status == DSBSTATUS_LOCHARDWARE)
722 share->sources.ids[share->sources.availhw_num++] = buf->source;
723 else
725 DWORD base = share->sources.maxhw_alloc;
726 share->sources.ids[base + share->sources.availsw_num++] = buf->source;
728 buf->source = 0;
730 buf->loc_status = 0;
732 if(!loc_status)
734 if(share->sources.availhw_num)
735 loc_status = DSBSTATUS_LOCHARDWARE;
736 else if(share->sources.availsw_num)
737 loc_status = DSBSTATUS_LOCSOFTWARE;
740 if((loc_status == DSBSTATUS_LOCHARDWARE && !share->sources.availhw_num) ||
741 (loc_status == DSBSTATUS_LOCSOFTWARE && !share->sources.availsw_num) ||
742 !loc_status)
744 ERR("Out of %s sources\n",
745 (loc_status == DSBSTATUS_LOCHARDWARE) ? "hardware" :
746 (loc_status == DSBSTATUS_LOCSOFTWARE) ? "software" : "any"
748 return DSERR_ALLOCATED;
751 if(loc_status == DSBSTATUS_LOCHARDWARE)
752 buf->source = share->sources.ids[--(share->sources.availhw_num)];
753 else
755 DWORD base = share->sources.maxhw_alloc;
756 buf->source = share->sources.ids[base + --(share->sources.availsw_num)];
758 alSourcef(buf->source, AL_GAIN, mB_to_gain((float)buf->current.vol));
759 alSourcef(buf->source, AL_PITCH,
760 buf->current.frequency ? (float)buf->current.frequency/data->format.Format.nSamplesPerSec
761 : 1.0f);
762 checkALError();
764 /* TODO: Don't set EAX parameters or connect to effect slots for software
765 * buffers. Need to check if EAX buffer properties are still tracked, or if
766 * they're lost/reset when leaving hardware.
768 * Alternatively, we can just allow it and say software processing supports
769 * EAX too. Depends if apps may get upset over that.
772 if((data->dsbflags&DSBCAPS_CTRL3D))
774 const DSPrimary *prim = buf->primary;
775 const ALuint source = buf->source;
776 const DS3DBUFFER *params = &buf->current.ds3d;
777 const EAXSOURCEPROPERTIES *eax_params = &buf->current.eax;
779 alSource3f(source, AL_POSITION, params->vPosition.x, params->vPosition.y,
780 -params->vPosition.z);
781 alSource3f(source, AL_VELOCITY, params->vVelocity.x, params->vVelocity.y,
782 -params->vVelocity.z);
783 alSourcei(source, AL_CONE_INNER_ANGLE, params->dwInsideConeAngle);
784 alSourcei(source, AL_CONE_OUTER_ANGLE, params->dwOutsideConeAngle);
785 alSource3f(source, AL_DIRECTION, params->vConeOrientation.x,
786 params->vConeOrientation.y,
787 -params->vConeOrientation.z);
788 alSourcef(source, AL_CONE_OUTER_GAIN, mB_to_gain((float)params->lConeOutsideVolume));
789 alSourcef(source, AL_REFERENCE_DISTANCE, params->flMinDistance);
790 alSourcef(source, AL_MAX_DISTANCE, params->flMaxDistance);
791 if(HAS_EXTENSION(share, SOFT_SOURCE_SPATIALIZE))
792 alSourcei(source, AL_SOURCE_SPATIALIZE_SOFT,
793 (params->dwMode==DS3DMODE_DISABLE) ? AL_FALSE : AL_TRUE
795 alSourcei(source, AL_SOURCE_RELATIVE,
796 (params->dwMode!=DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE
799 alSourcef(source, AL_ROLLOFF_FACTOR,
800 prim->current.ds3d.flRolloffFactor + eax_params->flRolloffFactor);
801 alSourcef(source, AL_DOPPLER_FACTOR, eax_params->flDopplerFactor);
802 if(HAS_EXTENSION(share, EXT_EFX))
804 alSourcei(source, AL_DIRECT_FILTER, buf->filter[0]);
805 for(i = 0;i < share->num_sends;++i)
807 DWORD target = buf->current.fxslot_targets[i];
808 ALuint filter=0, slot=0;
809 if(target < FXSLOT_TARGET_NULL)
811 ALint idx = (target == FXSLOT_TARGET_PRIMARY) ?
812 prim->primary_idx : (ALint)target;
813 if(idx >= 0)
815 slot = prim->auxslot[idx];
816 filter = buf->filter[1+idx];
819 alSource3i(source, AL_AUXILIARY_SEND_FILTER, slot, i, filter);
821 alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, eax_params->flRoomRolloffFactor);
822 alSourcef(source, AL_CONE_OUTER_GAINHF, mB_to_gain((float)eax_params->lOutsideVolumeHF));
823 alSourcef(source, AL_AIR_ABSORPTION_FACTOR,
824 clampF(prim->current.ctx.flAirAbsorptionHF / -5.0f *
825 eax_params->flAirAbsorptionFactor, 0.0f, 10.0f)
827 alSourcei(source, AL_DIRECT_FILTER_GAINHF_AUTO,
828 (eax_params->dwFlags&EAXSOURCEFLAGS_DIRECTHFAUTO) ? AL_TRUE : AL_FALSE);
829 alSourcei(source, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
830 (eax_params->dwFlags&EAXSOURCEFLAGS_ROOMAUTO) ? AL_TRUE : AL_FALSE);
831 alSourcei(source, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
832 (eax_params->dwFlags&EAXSOURCEFLAGS_ROOMHFAUTO) ? AL_TRUE : AL_FALSE);
834 checkALError();
836 else
838 const ALuint source = buf->source;
839 const ALfloat x = (ALfloat)(buf->current.pan-DSBPAN_LEFT)/(DSBPAN_RIGHT-DSBPAN_LEFT) -
840 0.5f;
842 alSource3f(source, AL_POSITION, x, 0.0f, -sqrtf(1.0f - x*x));
843 alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
844 alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
845 alSourcef(source, AL_CONE_OUTER_GAIN, 1.0f);
846 alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f);
847 alSourcef(source, AL_MAX_DISTANCE, 1000.0f);
848 alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f);
849 alSourcef(source, AL_DOPPLER_FACTOR, 0.0f);
850 alSourcei(source, AL_CONE_INNER_ANGLE, 360);
851 alSourcei(source, AL_CONE_OUTER_ANGLE, 360);
852 alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);
853 if(HAS_EXTENSION(share, EXT_EFX))
855 alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, 0.0f);
856 alSourcef(source, AL_CONE_OUTER_GAINHF, 1.0f);
857 alSourcef(source, AL_AIR_ABSORPTION_FACTOR, 0.0f);
858 alSourcei(source, AL_DIRECT_FILTER_GAINHF_AUTO, AL_TRUE);
859 alSourcei(source, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO, AL_TRUE);
860 alSourcei(source, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO, AL_TRUE);
861 alSourcei(source, AL_DIRECT_FILTER, AL_FILTER_NULL);
862 for(i = 0;i < share->num_sends;++i)
863 alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, i, AL_FILTER_NULL);
865 if(HAS_EXTENSION(share, SOFT_SOURCE_SPATIALIZE))
867 /* Set to auto so panning works for mono, and multi-channel works
868 * as expected.
870 alSourcei(source, AL_SOURCE_SPATIALIZE_SOFT, AL_AUTO_SOFT);
872 checkALError();
875 buf->loc_status = loc_status;
876 return DS_OK;
880 static HRESULT WINAPI DSBuffer_QueryInterface(IDirectSoundBuffer8 *iface, REFIID riid, void **ppv)
882 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
883 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
884 return DSBuffer_GetInterface(This, riid, ppv);
887 static ULONG WINAPI DSBuffer_AddRef(IDirectSoundBuffer8 *iface)
889 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
890 LONG ret;
892 InterlockedIncrement(&This->all_ref);
893 ret = InterlockedIncrement(&This->ref);
894 TRACE("(%p) ref %lu\n", iface, ret);
896 return ret;
899 static ULONG WINAPI DSBuffer_Release(IDirectSoundBuffer8 *iface)
901 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
902 LONG ret;
904 ret = InterlockedDecrement(&This->ref);
905 TRACE("(%p) ref %lu\n", iface, ret);
906 if(InterlockedDecrement(&This->all_ref) == 0)
907 DSBuffer_Destroy(This);
909 return ret;
912 static HRESULT WINAPI DSBuffer_GetCaps(IDirectSoundBuffer8 *iface, DSBCAPS *caps)
914 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
915 DSData *data;
917 TRACE("(%p)->(%p)\n", iface, caps);
919 if(!caps || caps->dwSize < sizeof(*caps))
921 WARN("Invalid DSBCAPS (%p, %lu)\n", caps, (caps ? caps->dwSize : 0));
922 return DSERR_INVALIDPARAM;
924 data = This->buffer;
926 caps->dwFlags = data->dsbflags;
927 if(!(data->dsbflags&DSBCAPS_LOCDEFER))
929 if(This->loc_status == DSBSTATUS_LOCHARDWARE)
930 caps->dwFlags |= DSBCAPS_LOCHARDWARE;
931 else if(This->loc_status == DSBSTATUS_LOCSOFTWARE)
932 caps->dwFlags |= DSBCAPS_LOCSOFTWARE;
934 caps->dwBufferBytes = data->buf_size;
935 caps->dwUnlockTransferRate = 4096;
936 caps->dwPlayCpuOverhead = 0;
938 return S_OK;
941 HRESULT WINAPI DSBuffer_GetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD *playpos, DWORD *curpos)
943 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
944 ALsizei writecursor, pos;
945 DSData *data;
947 TRACE("(%p)->(%p, %p)\n", iface, playpos, curpos);
949 data = This->buffer;
950 if(This->segsize != 0)
952 ALint queued = QBUFFERS;
953 ALint status = AL_INITIAL;
954 ALint ofs = 0;
956 EnterCriticalSection(&This->share->crst);
958 if(LIKELY(This->source))
960 setALContext(This->ctx);
961 alGetSourcei(This->source, AL_BUFFERS_QUEUED, &queued);
962 alGetSourcei(This->source, AL_BYTE_OFFSET, &ofs);
963 alGetSourcei(This->source, AL_SOURCE_STATE, &status);
964 checkALError();
965 popALContext();
968 if(status == AL_STOPPED)
969 pos = This->segsize*queued + This->queue_base;
970 else
971 pos = ofs + This->queue_base;
972 if(pos >= data->buf_size)
974 if(This->islooping)
975 pos %= data->buf_size;
976 else if(This->isplaying)
978 pos = data->buf_size;
979 alSourceStop(This->source);
980 alSourcei(This->source, AL_BUFFER, 0);
981 This->curidx = 0;
982 This->isplaying = FALSE;
985 if(This->isplaying)
986 writecursor = (This->segsize*QBUFFERS + pos) % data->buf_size;
987 else
988 writecursor = pos % data->buf_size;
990 LeaveCriticalSection(&This->share->crst);
992 else
994 const WAVEFORMATEX *format = &data->format.Format;
995 ALint status = AL_INITIAL;
996 ALint ofs = 0;
998 if(LIKELY(This->source))
1000 setALContext(This->ctx);
1001 alGetSourcei(This->source, AL_BYTE_OFFSET, &ofs);
1002 alGetSourcei(This->source, AL_SOURCE_STATE, &status);
1003 checkALError();
1004 popALContext();
1007 if(status == AL_PLAYING)
1009 pos = ofs;
1010 writecursor = format->nSamplesPerSec / This->primary->refresh;
1011 writecursor *= format->nBlockAlign;
1013 else
1015 /* AL_STOPPED means the source naturally reached its end, where
1016 * DirectSound's position should be at the end (OpenAL reports 0
1017 * for stopped sources). The Stop method correlates to pausing,
1018 * which would put the source into an AL_PAUSED state and correctly
1019 * hold its current position. AL_INITIAL means the buffer hasn't
1020 * been played since last changing location.
1022 switch(status)
1024 case AL_STOPPED: pos = data->buf_size; break;
1025 case AL_PAUSED: pos = ofs; break;
1026 case AL_INITIAL: pos = This->lastpos; break;
1027 default: pos = 0;
1029 writecursor = 0;
1031 writecursor = (writecursor + pos) % data->buf_size;
1033 TRACE("%p Play pos = %u, write pos = %u\n", This, pos, writecursor);
1035 if(pos > data->buf_size)
1037 ERR("playpos > buf_size\n");
1038 pos %= data->buf_size;
1040 if(writecursor >= data->buf_size)
1042 ERR("writepos >= buf_size\n");
1043 writecursor %= data->buf_size;
1046 if(playpos) *playpos = pos;
1047 if(curpos) *curpos = writecursor;
1049 return S_OK;
1052 static HRESULT WINAPI DSBuffer_GetFormat(IDirectSoundBuffer8 *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
1054 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1055 HRESULT hr = S_OK;
1056 UINT size;
1058 TRACE("(%p)->(%p, %lu, %p)\n", iface, wfx, allocated, written);
1060 if(!wfx && !written)
1062 WARN("Cannot report format or format size\n");
1063 return DSERR_INVALIDPARAM;
1066 size = sizeof(This->buffer->format.Format) + This->buffer->format.Format.cbSize;
1067 if(wfx)
1069 if(allocated < size)
1070 hr = DSERR_INVALIDPARAM;
1071 else
1072 memcpy(wfx, &This->buffer->format.Format, size);
1074 if(written)
1075 *written = size;
1077 return hr;
1080 static HRESULT WINAPI DSBuffer_GetVolume(IDirectSoundBuffer8 *iface, LONG *vol)
1082 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1083 HRESULT hr;
1085 TRACE("(%p)->(%p)\n", iface, vol);
1087 if(!vol)
1089 WARN("Invalid pointer\n");
1090 return DSERR_INVALIDPARAM;
1093 hr = DSERR_CONTROLUNAVAIL;
1094 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
1095 WARN("Volume control not set\n");
1096 else
1098 *vol = This->current.vol;
1099 hr = DS_OK;
1102 return hr;
1105 static HRESULT WINAPI DSBuffer_GetPan(IDirectSoundBuffer8 *iface, LONG *pan)
1107 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1108 HRESULT hr;
1110 TRACE("(%p)->(%p)\n", iface, pan);
1112 if(!pan)
1114 WARN("Invalid pointer\n");
1115 return DSERR_INVALIDPARAM;
1118 hr = DSERR_CONTROLUNAVAIL;
1119 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
1120 WARN("Panning control not set\n");
1121 else
1123 *pan = This->current.pan;
1124 hr = DS_OK;
1127 return hr;
1130 static HRESULT WINAPI DSBuffer_GetFrequency(IDirectSoundBuffer8 *iface, DWORD *freq)
1132 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1133 HRESULT hr;
1135 TRACE("(%p)->(%p)\n", iface, freq);
1137 if(!freq)
1139 WARN("Invalid pointer\n");
1140 return DSERR_INVALIDPARAM;
1143 hr = DSERR_CONTROLUNAVAIL;
1144 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
1145 WARN("Frequency control not set\n");
1146 else
1148 *freq = This->current.frequency;
1149 hr = DS_OK;
1152 return hr;
1155 HRESULT WINAPI DSBuffer_GetStatus(IDirectSoundBuffer8 *iface, DWORD *status)
1157 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1158 ALint state, looping;
1160 TRACE("(%p)->(%p)\n", iface, status);
1162 if(!status)
1164 WARN("Invalid pointer\n");
1165 return DSERR_INVALIDPARAM;
1167 *status = 0;
1169 if(This->segsize == 0)
1171 state = AL_INITIAL;
1172 looping = AL_FALSE;
1173 if(LIKELY(This->source))
1175 setALContext(This->ctx);
1176 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1177 alGetSourcei(This->source, AL_LOOPING, &looping);
1178 checkALError();
1179 popALContext();
1182 else
1184 EnterCriticalSection(&This->share->crst);
1185 state = This->isplaying ? AL_PLAYING : AL_PAUSED;
1186 looping = This->islooping;
1187 LeaveCriticalSection(&This->share->crst);
1190 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1191 *status |= This->loc_status;
1192 if(state == AL_PLAYING)
1193 *status |= DSBSTATUS_PLAYING | (looping ? DSBSTATUS_LOOPING : 0);
1195 TRACE("%p status = 0x%08lx\n", This, *status);
1196 return S_OK;
1199 HRESULT WINAPI DSBuffer_Initialize(IDirectSoundBuffer8 *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
1201 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1202 DSPrimary *prim;
1203 DSData *data;
1204 HRESULT hr;
1206 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
1208 EnterCriticalSection(&This->share->crst);
1209 setALContext(This->ctx);
1211 hr = DSERR_ALREADYINITIALIZED;
1212 if(This->init_done) goto out;
1214 prim = This->primary;
1215 if(!This->buffer)
1217 hr = DSERR_INVALIDPARAM;
1218 if(!desc)
1220 WARN("Missing DSound buffer description\n");
1221 goto out;
1223 if(!desc->lpwfxFormat)
1225 WARN("Missing buffer format (%p)\n", This);
1226 goto out;
1228 if((desc->dwFlags&DSBCAPS_CTRL3D) && desc->lpwfxFormat->nChannels != 1)
1230 if(prim->parent->is_8)
1232 /* DirectSoundBuffer8 objects aren't allowed non-mono 3D
1233 * buffers */
1234 WARN("Can't create multi-channel 3D buffers\n");
1235 goto out;
1237 else
1239 static int once = 0;
1240 if(!once++)
1241 ERR("Multi-channel 3D sounds are not spatialized\n");
1244 if((desc->dwFlags&DSBCAPS_CTRLPAN) && desc->lpwfxFormat->nChannels != 1)
1246 static int once = 0;
1247 if(!once++)
1248 ERR("Panning for multi-channel buffers is not supported\n");
1251 hr = DSData_Create(&This->buffer, desc, prim);
1252 if(FAILED(hr)) goto out;
1254 data = This->buffer;
1255 if(data->format.Format.wBitsPerSample == 8)
1256 memset(data->data, 0x80, data->buf_size);
1257 else
1258 memset(data->data, 0x00, data->buf_size);
1261 data = This->buffer;
1262 if(!(data->dsbflags&DSBCAPS_STATIC) && !HAS_EXTENSION(This->share, SOFTX_MAP_BUFFER))
1264 This->segsize = (data->format.Format.nAvgBytesPerSec+prim->refresh-1) / prim->refresh;
1265 This->segsize = clampI(This->segsize, data->format.Format.nBlockAlign, 2048);
1266 This->segsize += data->format.Format.nBlockAlign - 1;
1267 This->segsize -= This->segsize%data->format.Format.nBlockAlign;
1269 alGenBuffers(QBUFFERS, This->stream_bids);
1270 checkALError();
1272 if(!(data->dsbflags&DSBCAPS_CTRL3D))
1274 /* Non-3D sources aren't distance attenuated. */
1275 This->current.ds3d.dwMode = DS3DMODE_DISABLE;
1277 else
1279 if(HAS_EXTENSION(This->share, EXT_EFX))
1281 ALsizei i;
1283 alGenFilters(1+EAX_MAX_FXSLOTS, This->filter);
1284 alFilteri(This->filter[0], AL_FILTER_TYPE, AL_FILTER_LOWPASS);
1285 for(i = 0;i < EAX_MAX_FXSLOTS;++i)
1286 alFilteri(This->filter[1+i], AL_FILTER_TYPE, AL_FILTER_LOWPASS);
1287 if(UNLIKELY(alGetError() != AL_NO_ERROR))
1289 alDeleteFilters(1+EAX_MAX_FXSLOTS, This->filter);
1290 This->filter[0] = 0;
1291 for(i = 0;i < EAX_MAX_FXSLOTS;++i)
1292 This->filter[1+i] = 0;
1296 if(!This->current.frequency)
1297 This->current.frequency = data->format.Format.nSamplesPerSec;
1298 This->filter_mBLimit = prim->filter_mBLimit;
1300 hr = DS_OK;
1301 if(!(data->dsbflags&DSBCAPS_LOCDEFER))
1303 DWORD loc = 0;
1304 if((data->dsbflags&DSBCAPS_LOCHARDWARE)) loc = DSBSTATUS_LOCHARDWARE;
1305 else if((data->dsbflags&DSBCAPS_LOCSOFTWARE)) loc = DSBSTATUS_LOCSOFTWARE;
1306 hr = DSBuffer_SetLoc(This, loc);
1308 out:
1309 This->init_done = SUCCEEDED(hr);
1311 popALContext();
1312 LeaveCriticalSection(&This->share->crst);
1314 return hr;
1317 static HRESULT WINAPI DSBuffer_Lock(IDirectSoundBuffer8 *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
1319 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1320 DWORD remain;
1322 TRACE("(%p)->(%lu, %lu, %p, %p, %p, %p, 0x%lx)\n", This, ofs, bytes, ptr1, len1, ptr2, len2, flags);
1324 if(!ptr1 || !len1)
1326 WARN("Invalid pointer/len %p %p\n", ptr1, len1);
1327 return DSERR_INVALIDPARAM;
1330 *ptr1 = NULL;
1331 *len1 = 0;
1332 if(ptr2) *ptr2 = NULL;
1333 if(len2) *len2 = 0;
1335 if((flags&DSBLOCK_FROMWRITECURSOR))
1336 DSBuffer_GetCurrentPosition(iface, NULL, &ofs);
1337 else if(ofs >= (DWORD)This->buffer->buf_size)
1339 WARN("Invalid ofs %lu\n", ofs);
1340 return DSERR_INVALIDPARAM;
1342 if((flags&DSBLOCK_ENTIREBUFFER))
1343 bytes = This->buffer->buf_size;
1344 else if(bytes > (DWORD)This->buffer->buf_size)
1346 WARN("Invalid size %lu\n", bytes);
1347 return DSERR_INVALIDPARAM;
1350 if(InterlockedExchange(&This->buffer->locked, TRUE) == TRUE)
1352 WARN("Already locked\n");
1353 return DSERR_INVALIDPARAM;
1356 *ptr1 = This->buffer->data + ofs;
1357 if(bytes >= (DWORD)This->buffer->buf_size-ofs)
1359 *len1 = This->buffer->buf_size - ofs;
1360 remain = bytes - *len1;
1362 else
1364 *len1 = bytes;
1365 remain = 0;
1368 if(ptr2 && len2 && remain)
1370 *ptr2 = This->buffer->data;
1371 *len2 = remain;
1374 return DS_OK;
1377 static HRESULT WINAPI DSBuffer_Play(IDirectSoundBuffer8 *iface, DWORD res1, DWORD prio, DWORD flags)
1379 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1380 ALint state = AL_STOPPED;
1381 DSData *data;
1382 HRESULT hr;
1384 TRACE("(%p)->(%lu, %lu, %lu)\n", iface, res1, prio, flags);
1386 EnterCriticalSection(&This->share->crst);
1387 setALContext(This->ctx);
1389 hr = DSERR_BUFFERLOST;
1390 if(This->bufferlost)
1392 WARN("Buffer %p lost\n", This);
1393 goto out;
1396 data = This->buffer;
1397 if((data->dsbflags&DSBCAPS_LOCDEFER))
1399 DWORD loc = 0;
1401 hr = DSERR_INVALIDPARAM;
1402 if((flags&(DSBPLAY_LOCSOFTWARE|DSBPLAY_LOCHARDWARE)) == (DSBPLAY_LOCSOFTWARE|DSBPLAY_LOCHARDWARE))
1404 WARN("Both hardware and software specified\n");
1405 goto out;
1408 if((flags&DSBPLAY_LOCHARDWARE)) loc = DSBSTATUS_LOCHARDWARE;
1409 else if((flags&DSBPLAY_LOCSOFTWARE)) loc = DSBSTATUS_LOCSOFTWARE;
1411 if(loc && This->loc_status && loc != This->loc_status)
1413 if(This->segsize != 0)
1415 if(This->isplaying)
1416 state = AL_PLAYING;
1418 else
1420 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1421 checkALError();
1424 if(state == AL_PLAYING)
1426 ERR("Attemping to change location on playing buffer\n");
1427 goto out;
1431 hr = DSBuffer_SetLoc(This, loc);
1432 if(FAILED(hr)) goto out;
1434 else if(prio)
1436 ERR("Invalid priority set for non-deferred buffer %p, %lu!\n", This->buffer, prio);
1437 hr = DSERR_INVALIDPARAM;
1438 goto out;
1441 if(This->segsize != 0)
1443 This->islooping = !!(flags&DSBPLAY_LOOPING);
1444 if(This->isplaying) state = AL_PLAYING;
1446 else
1448 alSourcei(This->source, AL_LOOPING, (flags&DSBPLAY_LOOPING) ? AL_TRUE : AL_FALSE);
1449 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1450 checkALError();
1453 hr = S_OK;
1454 if(state == AL_PLAYING)
1455 goto out;
1457 if(This->segsize == 0)
1459 if(state == AL_INITIAL)
1461 alSourcei(This->source, AL_BUFFER, data->bid);
1462 alSourcei(This->source, AL_BYTE_OFFSET, This->lastpos % data->buf_size);
1464 alSourcePlay(This->source);
1466 else
1468 alSourceRewind(This->source);
1469 alSourcei(This->source, AL_BUFFER, 0);
1470 This->queue_base = This->data_offset % data->buf_size;
1471 This->curidx = 0;
1473 if(alGetError() != AL_NO_ERROR)
1475 ERR("Couldn't start source\n");
1476 hr = DSERR_GENERIC;
1477 goto out;
1479 This->isplaying = TRUE;
1481 if(This->nnotify)
1482 DSBuffer_addnotify(This);
1484 out:
1485 popALContext();
1486 LeaveCriticalSection(&This->share->crst);
1487 return hr;
1490 static HRESULT WINAPI DSBuffer_SetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD pos)
1492 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1493 DSData *data;
1495 TRACE("(%p)->(%lu)\n", iface, pos);
1497 data = This->buffer;
1498 if(pos >= (DWORD)data->buf_size)
1499 return DSERR_INVALIDPARAM;
1500 pos -= pos%data->format.Format.nBlockAlign;
1502 EnterCriticalSection(&This->share->crst);
1504 if(This->segsize != 0)
1506 if(This->isplaying)
1508 setALContext(This->ctx);
1509 /* Perform a flush, so the next timer update will restart at the
1510 * proper position */
1511 alSourceRewind(This->source);
1512 alSourcei(This->source, AL_BUFFER, 0);
1513 checkALError();
1514 popALContext();
1516 This->queue_base = This->data_offset = pos;
1517 This->curidx = 0;
1519 else
1521 if(LIKELY(This->source))
1523 setALContext(This->ctx);
1524 alSourcei(This->source, AL_BYTE_OFFSET, pos);
1525 checkALError();
1526 popALContext();
1529 This->lastpos = pos;
1531 LeaveCriticalSection(&This->share->crst);
1532 return DS_OK;
1535 static HRESULT WINAPI DSBuffer_SetFormat(IDirectSoundBuffer8 *iface, const WAVEFORMATEX *wfx)
1537 /* This call only works on primary buffers */
1538 WARN("(%p)->(%p)\n", iface, wfx);
1539 return DSERR_INVALIDCALL;
1542 static HRESULT WINAPI DSBuffer_SetVolume(IDirectSoundBuffer8 *iface, LONG vol)
1544 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1545 HRESULT hr = S_OK;
1547 TRACE("(%p)->(%ld)\n", iface, vol);
1549 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
1551 WARN("Invalid volume (%ld)\n", vol);
1552 return DSERR_INVALIDPARAM;
1555 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
1556 hr = DSERR_CONTROLUNAVAIL;
1557 else
1559 This->current.vol = vol;
1560 if(LIKELY(This->source))
1562 setALContext(This->ctx);
1563 alSourcef(This->source, AL_GAIN, mB_to_gain((float)vol));
1564 popALContext();
1568 return hr;
1571 static HRESULT WINAPI DSBuffer_SetPan(IDirectSoundBuffer8 *iface, LONG pan)
1573 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1574 HRESULT hr = S_OK;
1576 TRACE("(%p)->(%ld)\n", iface, pan);
1578 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
1580 WARN("invalid parameter: pan = %ld\n", pan);
1581 return DSERR_INVALIDPARAM;
1584 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
1585 hr = DSERR_CONTROLUNAVAIL;
1586 else
1588 This->current.pan = pan;
1589 if(LIKELY(This->source && !(This->buffer->dsbflags&DSBCAPS_CTRL3D)))
1591 ALfloat pos[3];
1592 pos[0] = (ALfloat)(pan-DSBPAN_LEFT)/(ALfloat)(DSBPAN_RIGHT-DSBPAN_LEFT) - 0.5f;
1593 pos[1] = 0.0f;
1594 /* NOTE: Strict movement along the X plane can cause the sound to
1595 * jump between left and right sharply. Using a curved path helps
1596 * smooth it out.
1598 pos[2] = -sqrtf(1.0f - pos[0]*pos[0]);
1600 setALContext(This->ctx);
1601 alSourcefv(This->source, AL_POSITION, pos);
1602 checkALError();
1603 popALContext();
1607 return hr;
1610 static HRESULT WINAPI DSBuffer_SetFrequency(IDirectSoundBuffer8 *iface, DWORD freq)
1612 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1613 DSData *data;
1614 HRESULT hr = S_OK;
1616 TRACE("(%p)->(%lu)\n", iface, freq);
1618 if(freq != 0 && (freq < DSBFREQUENCY_MIN || freq > DSBFREQUENCY_MAX))
1620 WARN("invalid parameter: freq = %lu\n", freq);
1621 return DSERR_INVALIDPARAM;
1624 data = This->buffer;
1625 if(!(data->dsbflags&DSBCAPS_CTRLFREQUENCY))
1626 hr = DSERR_CONTROLUNAVAIL;
1627 else
1629 This->current.frequency = freq ? freq : data->format.Format.nSamplesPerSec;
1630 if(LIKELY(This->source))
1632 setALContext(This->ctx);
1633 alSourcef(This->source, AL_PITCH,
1634 This->current.frequency / (ALfloat)data->format.Format.nSamplesPerSec
1636 checkALError();
1637 popALContext();
1641 return hr;
1644 static HRESULT WINAPI DSBuffer_Stop(IDirectSoundBuffer8 *iface)
1646 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1648 TRACE("(%p)->()\n", iface);
1650 EnterCriticalSection(&This->share->crst);
1651 if(LIKELY(This->source))
1653 const ALuint source = This->source;
1654 ALint state, ofs;
1656 setALContext(This->ctx);
1657 alSourcePause(source);
1658 alGetSourcei(source, AL_BYTE_OFFSET, &ofs);
1659 alGetSourcei(source, AL_SOURCE_STATE, &state);
1660 checkALError();
1662 This->isplaying = FALSE;
1663 if(This->nnotify)
1664 DSPrimary_triggernots(This->primary);
1665 /* Ensure the notification's last tracked position is updated, as well
1666 * as the queue offsets for streaming sources.
1668 if(This->segsize == 0)
1669 This->lastpos = (state == AL_STOPPED) ? This->buffer->buf_size : ofs;
1670 else
1672 DSData *data = This->buffer;
1673 ALint done = 0;
1675 alGetSourcei(This->source, AL_BUFFERS_PROCESSED, &done);
1676 This->queue_base += This->segsize*done + ofs;
1677 if(This->queue_base >= data->buf_size)
1679 if(This->islooping)
1680 This->queue_base %= data->buf_size;
1681 else
1682 This->queue_base = data->buf_size;
1684 This->lastpos = This->queue_base;
1686 alSourceRewind(This->source);
1687 alSourcei(This->source, AL_BUFFER, 0);
1688 checkALError();
1690 This->curidx = 0;
1691 This->data_offset = This->lastpos % data->buf_size;
1693 This->islooping = FALSE;
1694 popALContext();
1696 LeaveCriticalSection(&This->share->crst);
1698 return S_OK;
1701 static HRESULT WINAPI DSBuffer_Unlock(IDirectSoundBuffer8 *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
1703 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1704 DSData *buf = This->buffer;
1705 DWORD bufsize = buf->buf_size;
1706 DWORD_PTR ofs1, ofs2;
1707 DWORD_PTR boundary = (DWORD_PTR)buf->data;
1708 HRESULT hr;
1710 TRACE("(%p)->(%p, %lu, %p, %lu)\n", iface, ptr1, len1, ptr2, len2);
1712 if(InterlockedExchange(&buf->locked, FALSE) == FALSE)
1714 WARN("Not locked\n");
1715 return DSERR_INVALIDPARAM;
1718 hr = DSERR_INVALIDPARAM;
1719 /* Make sure offset is between boundary and boundary + bufsize */
1720 ofs1 = (DWORD_PTR)ptr1;
1721 ofs2 = (DWORD_PTR)ptr2;
1722 if(ofs1 < boundary || (ofs2 && ofs2 != boundary))
1723 goto out;
1724 ofs1 -= boundary;
1725 ofs2 = 0;
1726 if(bufsize-ofs1 < len1 || len2 > ofs1)
1727 goto out;
1728 if(!ptr2)
1729 len2 = 0;
1731 hr = DS_OK;
1732 if(!len1 && !len2)
1733 goto out;
1735 if(HAS_EXTENSION(This->share, SOFTX_MAP_BUFFER))
1737 setALContext(This->ctx);
1738 alFlushMappedBufferSOFT(buf->bid, 0, buf->buf_size);
1739 checkALError();
1740 popALContext();
1742 else if(This->segsize == 0)
1744 setALContext(This->ctx);
1745 alBufferData(buf->bid, buf->buf_format, buf->data, buf->buf_size,
1746 buf->format.Format.nSamplesPerSec);
1747 checkALError();
1748 popALContext();
1751 out:
1752 if(hr != S_OK)
1753 WARN("Invalid parameters (%p,%lu) (%p,%lu,%p,%lu)\n", (void*)boundary, bufsize,
1754 ptr1, len1, ptr2, len2);
1755 return hr;
1758 static HRESULT WINAPI DSBuffer_Restore(IDirectSoundBuffer8 *iface)
1760 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1761 HRESULT hr;
1763 TRACE("(%p)->()\n", iface);
1765 EnterCriticalSection(&This->share->crst);
1766 if(This->primary->parent->prio_level < DSSCL_WRITEPRIMARY ||
1767 (IDirectSoundBuffer*)&This->IDirectSoundBuffer8_iface == This->primary->write_emu)
1769 This->bufferlost = 0;
1770 hr = S_OK;
1772 else
1773 hr = DSERR_BUFFERLOST;
1774 LeaveCriticalSection(&This->share->crst);
1776 return hr;
1779 static HRESULT WINAPI DSBuffer_SetFX(IDirectSoundBuffer8 *iface, DWORD fxcount, DSEFFECTDESC *desc, DWORD *rescodes)
1781 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1782 ALenum state = AL_INITIAL;
1783 DSData *data;
1784 HRESULT hr;
1785 DWORD i;
1787 TRACE("(%p)->(%lu, %p, %p)\n", This, fxcount, desc, rescodes);
1789 data = This->buffer;
1790 if(!(data->dsbflags&DSBCAPS_CTRLFX))
1792 WARN("FX control not set\n");
1793 return DSERR_CONTROLUNAVAIL;
1796 if(data->locked)
1798 WARN("Buffer is locked\n");
1799 return DSERR_INVALIDCALL;
1802 EnterCriticalSection(&This->share->crst);
1804 setALContext(This->ctx);
1805 if(LIKELY(This->source))
1807 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1808 checkALError();
1810 popALContext();
1811 if(This->segsize != 0 && state != AL_PLAYING)
1812 state = This->isplaying ? AL_PLAYING : AL_PAUSED;
1813 if(state == AL_PLAYING)
1815 WARN("Buffer is playing\n");
1816 hr = DSERR_INVALIDCALL;
1817 goto done;
1820 hr = DSERR_INVALIDPARAM;
1821 if(fxcount == 0)
1823 if(desc || rescodes)
1825 WARN("Non-NULL desc and/or result pointer specified with no effects.\n");
1826 goto done;
1829 /* No effects; we can handle that */
1830 hr = DS_OK;
1831 goto done;
1834 if(!desc || !rescodes)
1836 WARN("NULL desc and/or result pointer specified.\n");
1837 goto done;
1840 /* We don't (currently) handle DSound effects */
1841 for(i = 0;i < fxcount;++i)
1843 FIXME("Cannot handle effect: %s\n", debugstr_guid(&desc[i].guidDSFXClass));
1844 rescodes[i] = DSFXR_FAILED;
1846 hr = DS_INCOMPLETE;
1848 done:
1849 LeaveCriticalSection(&This->share->crst);
1851 return hr;
1854 static HRESULT WINAPI DSBuffer_AcquireResources(IDirectSoundBuffer8 *iface, DWORD flags, DWORD fxcount, DWORD *rescodes)
1856 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1857 HRESULT hr;
1859 TRACE("(%p)->(%lu, %lu, %p)\n", This, flags, fxcount, rescodes);
1861 /* effects aren't supported at the moment.. */
1862 if(fxcount != 0 || rescodes)
1864 WARN("Non-zero effect count and/or result pointer specified with no effects.\n");
1865 return DSERR_INVALIDPARAM;
1868 EnterCriticalSection(&This->share->crst);
1869 setALContext(This->ctx);
1871 hr = DS_OK;
1872 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1874 DWORD loc = 0;
1876 hr = DSERR_INVALIDPARAM;
1877 if((flags&(DSBPLAY_LOCSOFTWARE|DSBPLAY_LOCHARDWARE)) == (DSBPLAY_LOCSOFTWARE|DSBPLAY_LOCHARDWARE))
1879 WARN("Both hardware and software specified\n");
1880 goto out;
1883 if((flags&DSBPLAY_LOCHARDWARE)) loc = DSBSTATUS_LOCHARDWARE;
1884 else if((flags&DSBPLAY_LOCSOFTWARE)) loc = DSBSTATUS_LOCSOFTWARE;
1886 if(loc && This->loc_status && loc != This->loc_status)
1888 ALint state = AL_INITIAL;
1890 if(This->segsize != 0)
1892 if(This->isplaying)
1893 state = AL_PLAYING;
1895 else
1897 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1898 checkALError();
1901 if(state == AL_PLAYING)
1903 ERR("Attemping to change location on playing buffer\n");
1904 goto out;
1908 hr = DSBuffer_SetLoc(This, loc);
1911 out:
1912 popALContext();
1913 LeaveCriticalSection(&This->share->crst);
1914 return hr;
1917 static HRESULT WINAPI DSBuffer_GetObjectInPath(IDirectSoundBuffer8 *iface, REFGUID guid, DWORD idx, REFGUID rguidiface, void **ppv)
1919 FIXME("(%p)->(%s, %lu, %s, %p) : stub!\n", iface, debugstr_guid(guid), idx, debugstr_guid(rguidiface), ppv);
1920 if(ppv) *ppv = NULL;
1921 return E_NOTIMPL;
1924 static IDirectSoundBuffer8Vtbl DSBuffer_Vtbl = {
1925 DSBuffer_QueryInterface,
1926 DSBuffer_AddRef,
1927 DSBuffer_Release,
1928 DSBuffer_GetCaps,
1929 DSBuffer_GetCurrentPosition,
1930 DSBuffer_GetFormat,
1931 DSBuffer_GetVolume,
1932 DSBuffer_GetPan,
1933 DSBuffer_GetFrequency,
1934 DSBuffer_GetStatus,
1935 DSBuffer_Initialize,
1936 DSBuffer_Lock,
1937 DSBuffer_Play,
1938 DSBuffer_SetCurrentPosition,
1939 DSBuffer_SetFormat,
1940 DSBuffer_SetVolume,
1941 DSBuffer_SetPan,
1942 DSBuffer_SetFrequency,
1943 DSBuffer_Stop,
1944 DSBuffer_Unlock,
1945 DSBuffer_Restore,
1946 DSBuffer_SetFX,
1947 DSBuffer_AcquireResources,
1948 DSBuffer_GetObjectInPath
1952 void DSBuffer_SetParams(DSBuffer *This, const DS3DBUFFER *params, LONG flags)
1954 DSPrimary *prim = This->primary;
1955 const ALuint source = This->source;
1956 union BufferParamFlags dirty = { flags };
1957 ALsizei i;
1959 /* Copy deferred parameters first. */
1960 if(dirty.bit.pos)
1961 This->current.ds3d.vPosition = params->vPosition;
1962 if(dirty.bit.vel)
1963 This->current.ds3d.vVelocity = params->vVelocity;
1964 if(dirty.bit.cone_angles)
1966 This->current.ds3d.dwInsideConeAngle = params->dwInsideConeAngle;
1967 This->current.ds3d.dwOutsideConeAngle = params->dwOutsideConeAngle;
1969 if(dirty.bit.cone_orient)
1970 This->current.ds3d.vConeOrientation = params->vConeOrientation;
1971 if(dirty.bit.cone_outsidevolume)
1972 This->current.ds3d.lConeOutsideVolume = params->lConeOutsideVolume;
1973 if(dirty.bit.min_distance)
1974 This->current.ds3d.flMinDistance = params->flMinDistance;
1975 if(dirty.bit.max_distance)
1976 This->current.ds3d.flMaxDistance = params->flMaxDistance;
1977 if(dirty.bit.mode)
1978 This->current.ds3d.dwMode = params->dwMode;
1979 /* Always copy EAX params (they're always set deferred first, then applied
1980 * when committing all params).
1982 This->current.eax = This->deferred.eax;
1983 for(i = 0;i < EAX_MAX_ACTIVE_FXSLOTS;++i)
1984 This->current.fxslot_targets[i] = This->deferred.fxslot_targets[i];
1985 for(i = 0;i < EAX_MAX_FXSLOTS;++i)
1986 This->current.send[i] = This->deferred.send[i];
1987 This->current.eax1_reverbmix = This->deferred.eax1_reverbmix;
1989 /* Now apply what's changed to OpenAL. */
1990 if(UNLIKELY(!source)) return;
1992 if(dirty.bit.pos)
1993 alSource3f(source, AL_POSITION, params->vPosition.x, params->vPosition.y,
1994 -params->vPosition.z);
1995 if(dirty.bit.vel)
1996 alSource3f(source, AL_VELOCITY, params->vVelocity.x, params->vVelocity.y,
1997 -params->vVelocity.z);
1998 if(dirty.bit.cone_angles)
2000 alSourcei(source, AL_CONE_INNER_ANGLE, params->dwInsideConeAngle);
2001 alSourcei(source, AL_CONE_OUTER_ANGLE, params->dwOutsideConeAngle);
2003 if(dirty.bit.cone_orient)
2004 alSource3f(source, AL_DIRECTION, params->vConeOrientation.x,
2005 params->vConeOrientation.y,
2006 -params->vConeOrientation.z);
2007 if(dirty.bit.cone_outsidevolume)
2008 alSourcef(source, AL_CONE_OUTER_GAIN, mB_to_gain((float)params->lConeOutsideVolume));
2009 if(dirty.bit.min_distance)
2010 alSourcef(source, AL_REFERENCE_DISTANCE, params->flMinDistance);
2011 if(dirty.bit.max_distance)
2012 alSourcef(source, AL_MAX_DISTANCE, params->flMaxDistance);
2013 if(dirty.bit.mode)
2015 if(HAS_EXTENSION(This->share, SOFT_SOURCE_SPATIALIZE))
2016 alSourcei(source, AL_SOURCE_SPATIALIZE_SOFT,
2017 (params->dwMode==DS3DMODE_DISABLE) ? AL_FALSE : AL_TRUE
2019 alSourcei(source, AL_SOURCE_RELATIVE,
2020 (params->dwMode!=DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE
2024 if(dirty.bit.dry_filter)
2025 alSourcei(source, AL_DIRECT_FILTER, This->filter[0]);
2026 if(dirty.bit.send_filters)
2028 for(i = 0;i < EAX_MAX_ACTIVE_FXSLOTS;++i)
2030 DWORD target = This->current.fxslot_targets[i];
2031 ALuint filter=0, slot=0;
2032 if(target < FXSLOT_TARGET_NULL)
2034 ALint idx = (target == FXSLOT_TARGET_PRIMARY) ?
2035 prim->primary_idx : (ALint)target;
2036 if(idx >= 0)
2038 slot = prim->auxslot[idx];
2039 filter = This->filter[1+idx];
2042 alSource3i(source, AL_AUXILIARY_SEND_FILTER, slot, i, filter);
2045 if(dirty.bit.doppler)
2046 alSourcef(source, AL_DOPPLER_FACTOR, This->current.eax.flDopplerFactor);
2047 if(dirty.bit.rolloff)
2048 alSourcef(source, AL_ROLLOFF_FACTOR, This->current.eax.flRolloffFactor +
2049 prim->current.ds3d.flRolloffFactor);
2050 if(dirty.bit.room_rolloff)
2051 alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, This->current.eax.flRoomRolloffFactor);
2052 if(dirty.bit.cone_outsidevolumehf)
2053 alSourcef(source, AL_CONE_OUTER_GAINHF, mB_to_gain((float)This->current.eax.lOutsideVolumeHF));
2054 if(dirty.bit.air_absorb)
2055 alSourcef(source, AL_AIR_ABSORPTION_FACTOR, This->current.eax.flAirAbsorptionFactor *
2056 prim->current.ctx.flAirAbsorptionHF / -5.0f);
2057 if(dirty.bit.flags)
2059 alSourcei(source, AL_DIRECT_FILTER_GAINHF_AUTO,
2060 (This->current.eax.dwFlags&EAXSOURCEFLAGS_DIRECTHFAUTO) ? AL_TRUE : AL_FALSE);
2061 alSourcei(source, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
2062 (This->current.eax.dwFlags&EAXSOURCEFLAGS_ROOMAUTO) ? AL_TRUE : AL_FALSE);
2063 alSourcei(source, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
2064 (This->current.eax.dwFlags&EAXSOURCEFLAGS_ROOMHFAUTO) ? AL_TRUE : AL_FALSE);
2068 static HRESULT WINAPI DSBuffer3D_QueryInterface(IDirectSound3DBuffer *iface, REFIID riid, void **ppv)
2070 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2071 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2072 return DSBuffer_GetInterface(This, riid, ppv);
2075 static ULONG WINAPI DSBuffer3D_AddRef(IDirectSound3DBuffer *iface)
2077 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2078 LONG ret;
2080 InterlockedIncrement(&This->all_ref);
2081 ret = InterlockedIncrement(&This->ds3d_ref);
2082 TRACE("(%p) ref %lu\n", iface, ret);
2084 return ret;
2087 static ULONG WINAPI DSBuffer3D_Release(IDirectSound3DBuffer *iface)
2089 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2090 LONG ret;
2092 ret = InterlockedDecrement(&This->ds3d_ref);
2093 TRACE("(%p) ref %lu\n", iface, ret);
2094 if(InterlockedDecrement(&This->all_ref) == 0)
2095 DSBuffer_Destroy(This);
2097 return ret;
2100 static HRESULT WINAPI DSBuffer3D_GetConeAngles(IDirectSound3DBuffer *iface, DWORD *pdwInsideConeAngle, DWORD *pdwOutsideConeAngle)
2102 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2104 TRACE("(%p)->(%p, %p)\n", This, pdwInsideConeAngle, pdwOutsideConeAngle);
2105 if(!pdwInsideConeAngle || !pdwOutsideConeAngle)
2107 WARN("Invalid pointers (%p, %p)\n", pdwInsideConeAngle, pdwOutsideConeAngle);
2108 return DSERR_INVALIDPARAM;
2111 EnterCriticalSection(&This->share->crst);
2112 *pdwInsideConeAngle = This->current.ds3d.dwInsideConeAngle;
2113 *pdwOutsideConeAngle = This->current.ds3d.dwOutsideConeAngle;
2114 LeaveCriticalSection(&This->share->crst);
2116 return S_OK;
2119 static HRESULT WINAPI DSBuffer3D_GetConeOrientation(IDirectSound3DBuffer *iface, D3DVECTOR *orient)
2121 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2123 TRACE("(%p)->(%p)\n", This, orient);
2124 if(!orient)
2126 WARN("Invalid pointer\n");
2127 return DSERR_INVALIDPARAM;
2130 EnterCriticalSection(&This->share->crst);
2131 *orient = This->current.ds3d.vConeOrientation;
2132 LeaveCriticalSection(&This->share->crst);
2134 return S_OK;
2137 static HRESULT WINAPI DSBuffer3D_GetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG *vol)
2139 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2141 TRACE("(%p)->(%p)\n", This, vol);
2142 if(!vol)
2144 WARN("Invalid pointer\n");
2145 return DSERR_INVALIDPARAM;
2148 *vol = This->current.ds3d.lConeOutsideVolume;
2149 return S_OK;
2152 static HRESULT WINAPI DSBuffer3D_GetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE *maxdist)
2154 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2156 TRACE("(%p)->(%p)\n", This, maxdist);
2157 if(!maxdist)
2159 WARN("Invalid pointer\n");
2160 return DSERR_INVALIDPARAM;
2163 *maxdist = This->current.ds3d.flMaxDistance;
2164 return S_OK;
2167 static HRESULT WINAPI DSBuffer3D_GetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE *mindist)
2169 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2171 TRACE("(%p)->(%p)\n", This, mindist);
2172 if(!mindist)
2174 WARN("Invalid pointer\n");
2175 return DSERR_INVALIDPARAM;
2178 *mindist = This->current.ds3d.flMinDistance;
2179 return S_OK;
2182 static HRESULT WINAPI DSBuffer3D_GetMode(IDirectSound3DBuffer *iface, DWORD *mode)
2184 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2186 TRACE("(%p)->(%p)\n", This, mode);
2187 if(!mode)
2189 WARN("Invalid pointer\n");
2190 return DSERR_INVALIDPARAM;
2193 *mode = This->current.ds3d.dwMode;
2194 return S_OK;
2197 static HRESULT WINAPI DSBuffer3D_GetPosition(IDirectSound3DBuffer *iface, D3DVECTOR *pos)
2199 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2201 TRACE("(%p)->(%p)\n", This, pos);
2202 if(!pos)
2204 WARN("Invalid pointer\n");
2205 return DSERR_INVALIDPARAM;
2208 EnterCriticalSection(&This->share->crst);
2209 *pos = This->current.ds3d.vPosition;
2210 LeaveCriticalSection(&This->share->crst);
2212 return S_OK;
2215 static HRESULT WINAPI DSBuffer3D_GetVelocity(IDirectSound3DBuffer *iface, D3DVECTOR *vel)
2217 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2219 TRACE("(%p)->(%p)\n", This, vel);
2220 if(!vel)
2222 WARN("Invalid pointer\n");
2223 return DSERR_INVALIDPARAM;
2226 EnterCriticalSection(&This->share->crst);
2227 *vel = This->current.ds3d.vVelocity;
2228 LeaveCriticalSection(&This->share->crst);
2230 return S_OK;
2233 static HRESULT WINAPI DSBuffer3D_GetAllParameters(IDirectSound3DBuffer *iface, DS3DBUFFER *ds3dbuffer)
2235 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2237 TRACE("(%p)->(%p)\n", iface, ds3dbuffer);
2239 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
2241 WARN("Invalid parameters %p %lu\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
2242 return DSERR_INVALIDPARAM;
2245 EnterCriticalSection(&This->share->crst);
2246 ds3dbuffer->vPosition = This->current.ds3d.vPosition;
2247 ds3dbuffer->vVelocity = This->current.ds3d.vVelocity;
2248 ds3dbuffer->dwInsideConeAngle = This->current.ds3d.dwInsideConeAngle;
2249 ds3dbuffer->dwOutsideConeAngle = This->current.ds3d.dwOutsideConeAngle;
2250 ds3dbuffer->vConeOrientation = This->current.ds3d.vConeOrientation;
2251 ds3dbuffer->lConeOutsideVolume = This->current.ds3d.lConeOutsideVolume;
2252 ds3dbuffer->flMinDistance = This->current.ds3d.flMinDistance;
2253 ds3dbuffer->flMaxDistance = This->current.ds3d.flMaxDistance;
2254 ds3dbuffer->dwMode = This->current.ds3d.dwMode;
2255 LeaveCriticalSection(&This->share->crst);
2257 return DS_OK;
2260 static HRESULT WINAPI DSBuffer3D_SetConeAngles(IDirectSound3DBuffer *iface, DWORD dwInsideConeAngle, DWORD dwOutsideConeAngle, DWORD apply)
2262 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2264 TRACE("(%p)->(%lu, %lu, %lu)\n", This, dwInsideConeAngle, dwOutsideConeAngle, apply);
2265 if(dwInsideConeAngle > DS3D_MAXCONEANGLE || dwOutsideConeAngle > DS3D_MAXCONEANGLE)
2267 WARN("Invalid cone angles (%lu, %lu)\n", dwInsideConeAngle, dwOutsideConeAngle);
2268 return DSERR_INVALIDPARAM;
2271 EnterCriticalSection(&This->share->crst);
2272 if(apply == DS3D_DEFERRED)
2274 This->deferred.ds3d.dwInsideConeAngle = dwInsideConeAngle;
2275 This->deferred.ds3d.dwOutsideConeAngle = dwOutsideConeAngle;
2276 This->dirty.bit.cone_angles = 1;
2278 else
2280 setALContext(This->ctx);
2281 This->current.ds3d.dwInsideConeAngle = dwInsideConeAngle;
2282 This->current.ds3d.dwOutsideConeAngle = dwOutsideConeAngle;
2283 if(LIKELY(This->source))
2285 alSourcei(This->source, AL_CONE_INNER_ANGLE, dwInsideConeAngle);
2286 alSourcei(This->source, AL_CONE_OUTER_ANGLE, dwOutsideConeAngle);
2287 checkALError();
2289 popALContext();
2291 LeaveCriticalSection(&This->share->crst);
2293 return S_OK;
2296 static HRESULT WINAPI DSBuffer3D_SetConeOrientation(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2298 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2300 TRACE("(%p)->(%f, %f, %f, %lu)\n", This, x, y, z, apply);
2302 EnterCriticalSection(&This->share->crst);
2303 if(apply == DS3D_DEFERRED)
2305 This->deferred.ds3d.vConeOrientation.x = x;
2306 This->deferred.ds3d.vConeOrientation.y = y;
2307 This->deferred.ds3d.vConeOrientation.z = z;
2308 This->dirty.bit.cone_orient = 1;
2310 else
2312 setALContext(This->ctx);
2313 This->current.ds3d.vConeOrientation.x = x;
2314 This->current.ds3d.vConeOrientation.y = y;
2315 This->current.ds3d.vConeOrientation.z = z;
2316 if(LIKELY(This->source))
2318 alSource3f(This->source, AL_DIRECTION, x, y, -z);
2319 checkALError();
2321 popALContext();
2323 LeaveCriticalSection(&This->share->crst);
2325 return S_OK;
2328 static HRESULT WINAPI DSBuffer3D_SetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG vol, DWORD apply)
2330 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2332 TRACE("(%p)->(%ld, %lu)\n", This, vol, apply);
2333 if(vol < DSBVOLUME_MIN || vol > DSBVOLUME_MAX)
2335 WARN("Invalid volume (%ld)\n", vol);
2336 return DSERR_INVALIDPARAM;
2339 EnterCriticalSection(&This->share->crst);
2340 if(apply == DS3D_DEFERRED)
2342 This->deferred.ds3d.lConeOutsideVolume = vol;
2343 This->dirty.bit.cone_outsidevolume = 1;
2345 else
2347 setALContext(This->ctx);
2348 This->current.ds3d.lConeOutsideVolume = vol;
2349 if(LIKELY(This->source))
2351 alSourcef(This->source, AL_CONE_OUTER_GAIN, mB_to_gain((float)vol));
2352 checkALError();
2354 popALContext();
2356 LeaveCriticalSection(&This->share->crst);
2358 return S_OK;
2361 static HRESULT WINAPI DSBuffer3D_SetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE maxdist, DWORD apply)
2363 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2365 TRACE("(%p)->(%f, %lu)\n", This, maxdist, apply);
2366 if(maxdist < 0.0f)
2368 WARN("Invalid max distance (%f)\n", maxdist);
2369 return DSERR_INVALIDPARAM;
2372 EnterCriticalSection(&This->share->crst);
2373 if(apply == DS3D_DEFERRED)
2375 This->deferred.ds3d.flMaxDistance = maxdist;
2376 This->dirty.bit.max_distance = 1;
2378 else
2380 setALContext(This->ctx);
2381 This->current.ds3d.flMaxDistance = maxdist;
2382 if(LIKELY(This->source))
2384 alSourcef(This->source, AL_MAX_DISTANCE, maxdist);
2385 checkALError();
2387 popALContext();
2389 LeaveCriticalSection(&This->share->crst);
2391 return S_OK;
2394 static HRESULT WINAPI DSBuffer3D_SetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE mindist, DWORD apply)
2396 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2398 TRACE("(%p)->(%f, %lu)\n", This, mindist, apply);
2399 if(mindist < 0.0f)
2401 WARN("Invalid min distance (%f)\n", mindist);
2402 return DSERR_INVALIDPARAM;
2405 EnterCriticalSection(&This->share->crst);
2406 if(apply == DS3D_DEFERRED)
2408 This->deferred.ds3d.flMinDistance = mindist;
2409 This->dirty.bit.min_distance = 1;
2411 else
2413 setALContext(This->ctx);
2414 This->current.ds3d.flMinDistance = mindist;
2415 if(LIKELY(This->source))
2417 alSourcef(This->source, AL_REFERENCE_DISTANCE, mindist);
2418 checkALError();
2420 popALContext();
2422 LeaveCriticalSection(&This->share->crst);
2424 return S_OK;
2427 static HRESULT WINAPI DSBuffer3D_SetMode(IDirectSound3DBuffer *iface, DWORD mode, DWORD apply)
2429 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2431 TRACE("(%p)->(%lu, %lu)\n", This, mode, apply);
2432 if(mode != DS3DMODE_NORMAL && mode != DS3DMODE_HEADRELATIVE &&
2433 mode != DS3DMODE_DISABLE)
2435 WARN("Invalid mode (%lu)\n", mode);
2436 return DSERR_INVALIDPARAM;
2439 EnterCriticalSection(&This->share->crst);
2440 if(apply == DS3D_DEFERRED)
2442 This->deferred.ds3d.dwMode = mode;
2443 This->dirty.bit.mode = 1;
2445 else
2447 setALContext(This->ctx);
2448 This->current.ds3d.dwMode = mode;
2449 if(LIKELY(This->source))
2451 if(HAS_EXTENSION(This->share, SOFT_SOURCE_SPATIALIZE))
2452 alSourcei(This->source, AL_SOURCE_SPATIALIZE_SOFT,
2453 (mode==DS3DMODE_DISABLE) ? AL_FALSE : AL_TRUE);
2454 alSourcei(This->source, AL_SOURCE_RELATIVE,
2455 (mode != DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE);
2456 checkALError();
2458 popALContext();
2460 LeaveCriticalSection(&This->share->crst);
2462 return S_OK;
2465 static HRESULT WINAPI DSBuffer3D_SetPosition(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2467 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2469 TRACE("(%p)->(%f, %f, %f, %lu)\n", This, x, y, z, apply);
2471 EnterCriticalSection(&This->share->crst);
2472 if(apply == DS3D_DEFERRED)
2474 This->deferred.ds3d.vPosition.x = x;
2475 This->deferred.ds3d.vPosition.y = y;
2476 This->deferred.ds3d.vPosition.z = z;
2477 This->dirty.bit.pos = 1;
2479 else
2481 setALContext(This->ctx);
2482 This->current.ds3d.vPosition.x = x;
2483 This->current.ds3d.vPosition.y = y;
2484 This->current.ds3d.vPosition.z = z;
2485 if(LIKELY(This->source))
2487 alSource3f(This->source, AL_POSITION, x, y, -z);
2488 checkALError();
2490 popALContext();
2492 LeaveCriticalSection(&This->share->crst);
2494 return S_OK;
2497 static HRESULT WINAPI DSBuffer3D_SetVelocity(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2499 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2501 TRACE("(%p)->(%f, %f, %f, %lu)\n", This, x, y, z, apply);
2503 EnterCriticalSection(&This->share->crst);
2504 if(apply == DS3D_DEFERRED)
2506 This->deferred.ds3d.vVelocity.x = x;
2507 This->deferred.ds3d.vVelocity.y = y;
2508 This->deferred.ds3d.vVelocity.z = z;
2509 This->dirty.bit.vel = 1;
2511 else
2513 setALContext(This->ctx);
2514 This->current.ds3d.vVelocity.x = x;
2515 This->current.ds3d.vVelocity.y = y;
2516 This->current.ds3d.vVelocity.z = z;
2517 if(LIKELY(This->source))
2519 alSource3f(This->source, AL_VELOCITY, x, y, -z);
2520 checkALError();
2522 popALContext();
2524 LeaveCriticalSection(&This->share->crst);
2526 return S_OK;
2529 static HRESULT WINAPI DSBuffer3D_SetAllParameters(IDirectSound3DBuffer *iface, const DS3DBUFFER *ds3dbuffer, DWORD apply)
2531 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2532 TRACE("(%p)->(%p, %lu)\n", This, ds3dbuffer, apply);
2534 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
2536 WARN("Invalid DS3DBUFFER (%p, %lu)\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
2537 return DSERR_INVALIDPARAM;
2540 if(ds3dbuffer->dwInsideConeAngle > DS3D_MAXCONEANGLE ||
2541 ds3dbuffer->dwOutsideConeAngle > DS3D_MAXCONEANGLE)
2543 WARN("Invalid cone angles (%lu, %lu)\n",
2544 ds3dbuffer->dwInsideConeAngle, ds3dbuffer->dwOutsideConeAngle);
2545 return DSERR_INVALIDPARAM;
2548 if(ds3dbuffer->lConeOutsideVolume > DSBVOLUME_MAX ||
2549 ds3dbuffer->lConeOutsideVolume < DSBVOLUME_MIN)
2551 WARN("Invalid cone outside volume (%ld)\n", ds3dbuffer->lConeOutsideVolume);
2552 return DSERR_INVALIDPARAM;
2555 if(ds3dbuffer->flMaxDistance < 0.0f)
2557 WARN("Invalid max distance (%f)\n", ds3dbuffer->flMaxDistance);
2558 return DSERR_INVALIDPARAM;
2561 if(ds3dbuffer->flMinDistance < 0.0f)
2563 WARN("Invalid min distance (%f)\n", ds3dbuffer->flMinDistance);
2564 return DSERR_INVALIDPARAM;
2567 if(ds3dbuffer->dwMode != DS3DMODE_NORMAL &&
2568 ds3dbuffer->dwMode != DS3DMODE_HEADRELATIVE &&
2569 ds3dbuffer->dwMode != DS3DMODE_DISABLE)
2571 WARN("Invalid mode (%lu)\n", ds3dbuffer->dwMode);
2572 return DSERR_INVALIDPARAM;
2575 if(apply == DS3D_DEFERRED)
2577 EnterCriticalSection(&This->share->crst);
2578 This->deferred.ds3d = *ds3dbuffer;
2579 This->deferred.ds3d.dwSize = sizeof(This->deferred.ds3d);
2580 This->dirty.bit.pos = 1;
2581 This->dirty.bit.vel = 1;
2582 This->dirty.bit.cone_angles = 1;
2583 This->dirty.bit.cone_orient = 1;
2584 This->dirty.bit.cone_outsidevolume = 1;
2585 This->dirty.bit.min_distance = 1;
2586 This->dirty.bit.max_distance = 1;
2587 This->dirty.bit.mode = 1;
2588 LeaveCriticalSection(&This->share->crst);
2590 else
2592 union BufferParamFlags dirty = { 0 };
2593 dirty.bit.pos = 1;
2594 dirty.bit.vel = 1;
2595 dirty.bit.cone_angles = 1;
2596 dirty.bit.cone_orient = 1;
2597 dirty.bit.cone_outsidevolume = 1;
2598 dirty.bit.min_distance = 1;
2599 dirty.bit.max_distance = 1;
2600 dirty.bit.mode = 1;
2602 EnterCriticalSection(&This->share->crst);
2603 setALContext(This->ctx);
2604 DSBuffer_SetParams(This, ds3dbuffer, dirty.flags);
2605 checkALError();
2606 popALContext();
2607 LeaveCriticalSection(&This->share->crst);
2610 return S_OK;
2613 static IDirectSound3DBufferVtbl DSBuffer3d_Vtbl =
2615 DSBuffer3D_QueryInterface,
2616 DSBuffer3D_AddRef,
2617 DSBuffer3D_Release,
2618 DSBuffer3D_GetAllParameters,
2619 DSBuffer3D_GetConeAngles,
2620 DSBuffer3D_GetConeOrientation,
2621 DSBuffer3D_GetConeOutsideVolume,
2622 DSBuffer3D_GetMaxDistance,
2623 DSBuffer3D_GetMinDistance,
2624 DSBuffer3D_GetMode,
2625 DSBuffer3D_GetPosition,
2626 DSBuffer3D_GetVelocity,
2627 DSBuffer3D_SetAllParameters,
2628 DSBuffer3D_SetConeAngles,
2629 DSBuffer3D_SetConeOrientation,
2630 DSBuffer3D_SetConeOutsideVolume,
2631 DSBuffer3D_SetMaxDistance,
2632 DSBuffer3D_SetMinDistance,
2633 DSBuffer3D_SetMode,
2634 DSBuffer3D_SetPosition,
2635 DSBuffer3D_SetVelocity
2639 static HRESULT WINAPI DSBufferNot_QueryInterface(IDirectSoundNotify *iface, REFIID riid, void **ppv)
2641 DSBuffer *This = impl_from_IDirectSoundNotify(iface);
2642 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2643 return DSBuffer_GetInterface(This, riid, ppv);
2646 static ULONG WINAPI DSBufferNot_AddRef(IDirectSoundNotify *iface)
2648 DSBuffer *This = impl_from_IDirectSoundNotify(iface);
2649 LONG ret;
2651 InterlockedIncrement(&This->all_ref);
2652 ret = InterlockedIncrement(&This->not_ref);
2653 TRACE("(%p) ref %lu\n", iface, ret);
2655 return ret;
2658 static ULONG WINAPI DSBufferNot_Release(IDirectSoundNotify *iface)
2660 DSBuffer *This = impl_from_IDirectSoundNotify(iface);
2661 LONG ret;
2663 ret = InterlockedDecrement(&This->not_ref);
2664 TRACE("(%p) ref %lu\n", iface, ret);
2665 if(InterlockedDecrement(&This->all_ref) == 0)
2666 DSBuffer_Destroy(This);
2668 return ret;
2671 static HRESULT WINAPI DSBufferNot_SetNotificationPositions(IDirectSoundNotify *iface, DWORD count, const DSBPOSITIONNOTIFY *notifications)
2673 DSBuffer *This = impl_from_IDirectSoundNotify(iface);
2674 DSBPOSITIONNOTIFY *nots;
2675 DWORD state;
2676 HRESULT hr;
2678 TRACE("(%p)->(%lu, %p))\n", iface, count, notifications);
2680 EnterCriticalSection(&This->share->crst);
2681 hr = DSERR_INVALIDPARAM;
2682 if(count && !notifications)
2683 goto out;
2685 hr = DSBuffer_GetStatus(&This->IDirectSoundBuffer8_iface, &state);
2686 if(FAILED(hr)) goto out;
2688 hr = DSERR_INVALIDCALL;
2689 if((state&DSBSTATUS_PLAYING))
2690 goto out;
2692 if(!count)
2694 HeapFree(GetProcessHeap(), 0, This->notify);
2695 This->notify = 0;
2696 This->nnotify = 0;
2697 hr = S_OK;
2699 else
2701 DWORD i;
2703 hr = DSERR_INVALIDPARAM;
2704 for(i = 0;i < count;++i)
2706 if(notifications[i].dwOffset >= (DWORD)This->buffer->buf_size &&
2707 notifications[i].dwOffset != (DWORD)DSBPN_OFFSETSTOP)
2708 goto out;
2711 hr = E_OUTOFMEMORY;
2712 nots = HeapAlloc(GetProcessHeap(), 0, count*sizeof(*nots));
2713 if(!nots) goto out;
2714 memcpy(nots, notifications, count*sizeof(*nots));
2716 HeapFree(GetProcessHeap(), 0, This->notify);
2717 This->notify = nots;
2718 This->nnotify = count;
2720 hr = S_OK;
2723 out:
2724 LeaveCriticalSection(&This->share->crst);
2725 return hr;
2728 static IDirectSoundNotifyVtbl DSBufferNot_Vtbl =
2730 DSBufferNot_QueryInterface,
2731 DSBufferNot_AddRef,
2732 DSBufferNot_Release,
2733 DSBufferNot_SetNotificationPositions
2737 static const char *debug_bufferprop(const GUID *guid)
2739 #define HANDLE_ID(id) if(IsEqualGUID(guid, &(id))) return #id
2740 HANDLE_ID(EAXPROPERTYID_EAX40_Source);
2741 HANDLE_ID(DSPROPSETID_EAX30_BufferProperties);
2742 HANDLE_ID(DSPROPSETID_EAX20_BufferProperties);
2743 HANDLE_ID(EAXPROPERTYID_EAX40_FXSlot0);
2744 HANDLE_ID(EAXPROPERTYID_EAX40_FXSlot1);
2745 HANDLE_ID(EAXPROPERTYID_EAX40_FXSlot2);
2746 HANDLE_ID(EAXPROPERTYID_EAX40_FXSlot3);
2747 HANDLE_ID(DSPROPSETID_EAX30_ListenerProperties);
2748 HANDLE_ID(DSPROPSETID_EAX20_ListenerProperties);
2749 HANDLE_ID(EAXPROPERTYID_EAX40_Context);
2750 HANDLE_ID(DSPROPSETID_EAX10_BufferProperties);
2751 HANDLE_ID(DSPROPSETID_EAX10_ListenerProperties);
2752 HANDLE_ID(DSPROPSETID_VoiceManager);
2753 HANDLE_ID(DSPROPSETID_ZOOMFX_BufferProperties);
2754 HANDLE_ID(DSPROPSETID_I3DL2_ListenerProperties);
2755 HANDLE_ID(DSPROPSETID_I3DL2_BufferProperties);
2756 #undef HANDLE_ID
2757 return debugstr_guid(guid);
2760 static HRESULT WINAPI DSBufferProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
2762 DSBuffer *This = impl_from_IKsPropertySet(iface);
2763 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2764 return DSBuffer_GetInterface(This, riid, ppv);
2767 static ULONG WINAPI DSBufferProp_AddRef(IKsPropertySet *iface)
2769 DSBuffer *This = impl_from_IKsPropertySet(iface);
2770 LONG ret;
2772 InterlockedIncrement(&This->all_ref);
2773 ret = InterlockedIncrement(&This->prop_ref);
2774 TRACE("(%p) ref %lu\n", iface, ret);
2776 return ret;
2779 static ULONG WINAPI DSBufferProp_Release(IKsPropertySet *iface)
2781 DSBuffer *This = impl_from_IKsPropertySet(iface);
2782 LONG ret;
2784 ret = InterlockedDecrement(&This->prop_ref);
2785 TRACE("(%p) ref %lu\n", iface, ret);
2786 if(InterlockedDecrement(&This->all_ref) == 0)
2787 DSBuffer_Destroy(This);
2789 return ret;
2792 /* NOTE: Due to some apparent quirks in DSound, the listener properties are
2793 handled through secondary buffers. */
2794 static HRESULT WINAPI DSBufferProp_Get(IKsPropertySet *iface,
2795 REFGUID guidPropSet, ULONG dwPropID,
2796 LPVOID pInstanceData, ULONG cbInstanceData,
2797 LPVOID pPropData, ULONG cbPropData,
2798 ULONG *pcbReturned)
2800 DSBuffer *This = impl_from_IKsPropertySet(iface);
2801 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2803 TRACE("(%p)->(%s, 0x%lx, %p, %lu, %p, %lu, %p)\n", iface, debug_bufferprop(guidPropSet),
2804 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData, pcbReturned);
2806 if(!pcbReturned)
2807 return E_POINTER;
2808 *pcbReturned = 0;
2810 if(cbPropData > 0 && !pPropData)
2812 WARN("pPropData is NULL with cbPropData > 0\n");
2813 return E_POINTER;
2816 EnterCriticalSection(&This->share->crst);
2817 if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_Source))
2818 hr = EAX4Source_Get(This, dwPropID, pPropData, cbPropData, pcbReturned);
2819 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX30_BufferProperties))
2820 hr = EAX3Buffer_Get(This, dwPropID, pPropData, cbPropData, pcbReturned);
2821 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2822 hr = EAX2Buffer_Get(This, dwPropID, pPropData, cbPropData, pcbReturned);
2823 else if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot0))
2824 hr = EAX4Slot_Get(This->primary, 0, dwPropID, pPropData, cbPropData, pcbReturned);
2825 else if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot1))
2826 hr = EAX4Slot_Get(This->primary, 1, dwPropID, pPropData, cbPropData, pcbReturned);
2827 else if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot2))
2828 hr = EAX4Slot_Get(This->primary, 2, dwPropID, pPropData, cbPropData, pcbReturned);
2829 else if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot3))
2830 hr = EAX4Slot_Get(This->primary, 3, dwPropID, pPropData, cbPropData, pcbReturned);
2831 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX30_ListenerProperties))
2832 hr = EAX3_Get(This->primary, dwPropID, pPropData, cbPropData, pcbReturned);
2833 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
2834 hr = EAX2_Get(This->primary, dwPropID, pPropData, cbPropData, pcbReturned);
2835 else if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_Context))
2836 hr = EAX4Context_Get(This->primary, dwPropID, pPropData, cbPropData, pcbReturned);
2837 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX10_BufferProperties))
2838 hr = EAX1Buffer_Get(This, dwPropID, pPropData, cbPropData, pcbReturned);
2839 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX10_ListenerProperties))
2840 hr = EAX1_Get(This->primary, dwPropID, pPropData, cbPropData, pcbReturned);
2841 else if(IsEqualIID(guidPropSet, &DSPROPSETID_VoiceManager))
2842 hr = VoiceMan_Get(This, dwPropID, pPropData, cbPropData, pcbReturned);
2843 else
2844 FIXME("Unhandled propset: %s\n", debug_bufferprop(guidPropSet));
2845 LeaveCriticalSection(&This->share->crst);
2847 return hr;
2850 static HRESULT WINAPI DSBufferProp_Set(IKsPropertySet *iface,
2851 REFGUID guidPropSet, ULONG dwPropID,
2852 LPVOID pInstanceData, ULONG cbInstanceData,
2853 LPVOID pPropData, ULONG cbPropData)
2855 DSBuffer *This = impl_from_IKsPropertySet(iface);
2856 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2857 LONG idx;
2859 TRACE("(%p)->(%s, 0x%lx, %p, %lu, %p, %lu)\n", iface, debug_bufferprop(guidPropSet),
2860 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData);
2862 if(cbPropData > 0 && !pPropData)
2864 WARN("pPropData is NULL with cbPropData > 0\n");
2865 return E_POINTER;
2868 EnterCriticalSection(&This->share->crst);
2869 if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_Source))
2871 DWORD propid = dwPropID & ~EAXSOURCE_PARAMETER_DEFERRED;
2872 BOOL immediate = !(dwPropID&EAXSOURCE_PARAMETER_DEFERRED);
2874 setALContext(This->ctx);
2875 hr = EAX4Source_Set(This, propid, pPropData, cbPropData);
2876 if(hr == DS_OK && immediate)
2878 DSPrimary *prim = This->primary;
2879 DSPrimary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
2881 popALContext();
2883 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX30_BufferProperties))
2885 DWORD propid = dwPropID & ~DSPROPERTY_EAX30BUFFER_DEFERRED;
2886 BOOL immediate = !(dwPropID&DSPROPERTY_EAX30BUFFER_DEFERRED);
2888 setALContext(This->ctx);
2889 hr = EAX3Buffer_Set(This, propid, pPropData, cbPropData);
2890 if(hr == DS_OK && immediate)
2892 DSPrimary *prim = This->primary;
2893 DSPrimary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
2895 popALContext();
2897 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2899 DWORD propid = dwPropID & ~DSPROPERTY_EAX20BUFFER_DEFERRED;
2900 BOOL immediate = !(dwPropID&DSPROPERTY_EAX20BUFFER_DEFERRED);
2902 setALContext(This->ctx);
2903 hr = EAX2Buffer_Set(This, propid, pPropData, cbPropData);
2904 if(hr == DS_OK && immediate)
2906 DSPrimary *prim = This->primary;
2907 DSPrimary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
2909 popALContext();
2911 else if(((idx=0),IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot0)) ||
2912 ((idx=1),IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot1)) ||
2913 ((idx=2),IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot2)) ||
2914 ((idx=3),IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot3)))
2916 DSPrimary *prim = This->primary;
2917 DWORD propid = dwPropID & ~EAXFXSLOT_PARAMETER_DEFERRED;
2918 BOOL immediate = !(dwPropID&EAXFXSLOT_PARAMETER_DEFERRED);
2920 setALContext(prim->ctx);
2921 hr = EAX4Slot_Set(prim, idx, propid, pPropData, cbPropData);
2922 if(hr == DS_OK && immediate)
2923 DSPrimary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
2924 popALContext();
2926 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX30_ListenerProperties))
2928 DSPrimary *prim = This->primary;
2929 DWORD propid = dwPropID & ~DSPROPERTY_EAX30LISTENER_DEFERRED;
2930 BOOL immediate = !(dwPropID&DSPROPERTY_EAX30LISTENER_DEFERRED);
2932 setALContext(prim->ctx);
2933 hr = EAX3_Set(prim, propid, pPropData, cbPropData);
2934 if(hr == DS_OK && immediate)
2935 DSPrimary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
2936 popALContext();
2938 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
2940 DSPrimary *prim = This->primary;
2941 DWORD propid = dwPropID & ~DSPROPERTY_EAX20LISTENER_DEFERRED;
2942 BOOL immediate = !(dwPropID&DSPROPERTY_EAX20LISTENER_DEFERRED);
2944 setALContext(prim->ctx);
2945 hr = EAX2_Set(prim, propid, pPropData, cbPropData);
2946 if(hr == DS_OK && immediate)
2947 DSPrimary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
2948 popALContext();
2950 else if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_Context))
2952 DSPrimary *prim = This->primary;
2953 DWORD propid = dwPropID & ~EAXCONTEXT_PARAMETER_DEFERRED;
2954 BOOL immediate = !(dwPropID&EAXCONTEXT_PARAMETER_DEFERRED);
2956 setALContext(prim->ctx);
2957 hr = EAX4Context_Set(prim, propid, pPropData, cbPropData);
2958 if(hr == DS_OK && immediate)
2959 DSPrimary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
2960 popALContext();
2962 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX10_BufferProperties))
2964 DWORD propid = dwPropID & ~DSPROPERTY_EAX20BUFFER_DEFERRED;
2965 BOOL immediate = !(dwPropID&DSPROPERTY_EAX20BUFFER_DEFERRED);
2967 setALContext(This->ctx);
2968 hr = EAX1Buffer_Set(This, propid, pPropData, cbPropData);
2969 if(hr == DS_OK && immediate)
2971 DSPrimary *prim = This->primary;
2972 DSPrimary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
2974 popALContext();
2976 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX10_ListenerProperties))
2978 DSPrimary *prim = This->primary;
2979 DWORD propid = dwPropID & ~DSPROPERTY_EAX20LISTENER_DEFERRED;
2980 BOOL immediate = !(dwPropID&DSPROPERTY_EAX20LISTENER_DEFERRED);
2982 setALContext(prim->ctx);
2983 hr = EAX1_Set(prim, propid, pPropData, cbPropData);
2984 if(hr == DS_OK && immediate)
2985 DSPrimary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
2986 popALContext();
2988 else if(IsEqualIID(guidPropSet, &DSPROPSETID_VoiceManager))
2990 hr = VoiceMan_Set(This, dwPropID, pPropData, cbPropData);
2992 else
2993 FIXME("Unhandled propset: %s\n", debug_bufferprop(guidPropSet));
2994 LeaveCriticalSection(&This->share->crst);
2996 return hr;
2999 static HRESULT WINAPI DSBufferProp_QuerySupport(IKsPropertySet *iface,
3000 REFGUID guidPropSet, ULONG dwPropID,
3001 ULONG *pTypeSupport)
3003 DSBuffer *This = impl_from_IKsPropertySet(iface);
3004 HRESULT hr = E_PROP_ID_UNSUPPORTED;
3006 TRACE("(%p)->(%s, 0x%lx, %p)\n", iface, debug_bufferprop(guidPropSet), dwPropID,
3007 pTypeSupport);
3009 if(!pTypeSupport)
3010 return E_POINTER;
3011 *pTypeSupport = 0;
3013 EnterCriticalSection(&This->share->crst);
3014 if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_Source))
3015 hr = EAX4Source_Query(This, dwPropID, pTypeSupport);
3016 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX30_BufferProperties))
3017 hr = EAX3Buffer_Query(This, dwPropID, pTypeSupport);
3018 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
3019 hr = EAX2Buffer_Query(This, dwPropID, pTypeSupport);
3020 else if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot0))
3021 hr = EAX4Slot_Query(This->primary, 0, dwPropID, pTypeSupport);
3022 else if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot1))
3023 hr = EAX4Slot_Query(This->primary, 1, dwPropID, pTypeSupport);
3024 else if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot2))
3025 hr = EAX4Slot_Query(This->primary, 2, dwPropID, pTypeSupport);
3026 else if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot3))
3027 hr = EAX4Slot_Query(This->primary, 3, dwPropID, pTypeSupport);
3028 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX30_ListenerProperties))
3029 hr = EAX3_Query(This->primary, dwPropID, pTypeSupport);
3030 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
3031 hr = EAX2_Query(This->primary, dwPropID, pTypeSupport);
3032 else if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_Context))
3033 hr = EAX4Context_Query(This->primary, dwPropID, pTypeSupport);
3034 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX10_ListenerProperties))
3035 hr = EAX1_Query(This->primary, dwPropID, pTypeSupport);
3036 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX10_BufferProperties))
3037 hr = EAX1Buffer_Query(This, dwPropID, pTypeSupport);
3038 else if(IsEqualIID(guidPropSet, &DSPROPSETID_VoiceManager))
3039 hr = VoiceMan_Query(This, dwPropID, pTypeSupport);
3040 else
3041 FIXME("Unhandled propset: %s (propid: %lu)\n", debug_bufferprop(guidPropSet), dwPropID);
3042 LeaveCriticalSection(&This->share->crst);
3044 return hr;
3047 static IKsPropertySetVtbl DSBufferProp_Vtbl =
3049 DSBufferProp_QueryInterface,
3050 DSBufferProp_AddRef,
3051 DSBufferProp_Release,
3052 DSBufferProp_Get,
3053 DSBufferProp_Set,
3054 DSBufferProp_QuerySupport