Don't allow duplicating lost buffers
[dsound-openal.git] / buffer.c
blob518527c83d3713d1b66494ea7205094169c4c493
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 #include <stdarg.h>
25 #ifdef __WINESRC__
27 #define COBJMACROS
28 #define NONAMELESSSTRUCT
29 #define NONAMELESSUNION
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winuser.h"
33 #include "winnls.h"
34 #include "winreg.h"
35 #include "vfwmsgs.h"
36 #include "mmsystem.h"
37 #include "winternl.h"
38 #include "mmddk.h"
39 #include "wine/debug.h"
40 #include "dsound.h"
42 #include "dsound_private.h"
44 #include "ks.h"
45 #include "ksmedia.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
49 #else
51 #define WINVER 0x0600
52 #define INITGUID
53 #include <windows.h>
54 #include <dsound.h>
56 #include "dsound_private.h"
58 DEFINE_GUID(CLSID_DirectSoundPrivate,0x11ab3ec0,0x25ec,0x11d1,0xa4,0xd8,0x00,0xc0,0x4f,0xc2,0x8a,0xca);
60 DEFINE_GUID(DSPROPSETID_DirectSoundDevice,0x84624f82,0x25ec,0x11d1,0xa4,0xd8,0x00,0xc0,0x4f,0xc2,0x8a,0xca);
62 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
63 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
65 #ifndef E_PROP_ID_UNSUPPORTED
66 #define E_PROP_ID_UNSUPPORTED ((HRESULT)0x80070490)
67 #endif
69 #endif
71 #ifndef WAVE_FORMAT_IEEE_FLOAT
72 #define WAVE_FORMAT_IEEE_FLOAT 3
73 #endif
75 /* TODO: when bufferlost is set, return from all calls except initialize with
76 * DSERR_BUFFERLOST
78 static const IDirectSoundBuffer8Vtbl DS8Buffer_Vtbl;
79 static const IDirectSound3DBufferVtbl DS8Buffer3d_Vtbl;
80 static const IDirectSoundNotifyVtbl DS8BufferNot_Vtbl;
81 static const IKsPropertySetVtbl DS8BufferProp_Vtbl;
84 static inline DS8Buffer *impl_from_IDirectSoundBuffer8(IDirectSoundBuffer8 *iface)
86 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSoundBuffer8_iface);
88 /* Shares the same vtable */
89 static inline DS8Buffer *impl_from_IDirectSoundBuffer(IDirectSoundBuffer *iface)
91 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSoundBuffer8_iface);
94 static inline DS8Buffer *impl_from_IDirectSound3DBuffer(IDirectSound3DBuffer *iface)
96 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSound3DBuffer_iface);
99 static inline DS8Buffer *impl_from_IDirectSoundNotify(IDirectSoundNotify *iface)
101 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSoundNotify_iface);
104 static inline DS8Buffer *impl_from_IKsPropertySet(IKsPropertySet *iface)
106 return CONTAINING_RECORD(iface, DS8Buffer, IKsPropertySet_iface);
110 static void CALLBACK DS8Buffer_timer(UINT timerID, UINT msg, DWORD_PTR dwUser,
111 DWORD_PTR dw1, DWORD_PTR dw2)
113 (void)timerID;
114 (void)msg;
115 (void)dw1;
116 (void)dw2;
117 PostThreadMessageA(dwUser, WM_USER, 0, 0);
120 static void DS8Buffer_starttimer(DS8Primary *prim)
122 DWORD triggertime, res = DS_TIME_RES;
123 ALint refresh = FAKE_REFRESH_COUNT;
124 TIMECAPS time;
126 if(prim->timer_id)
127 return;
129 timeGetDevCaps(&time, sizeof(TIMECAPS));
131 alcGetIntegerv(prim->parent->device, ALC_REFRESH, 1, &refresh);
132 getALCError(prim->parent->device);
134 triggertime = 1000 / refresh / 2;
135 if(triggertime < time.wPeriodMin)
136 triggertime = time.wPeriodMin;
137 TRACE("Calling timer every %u ms for %i refreshes per second\n", triggertime, refresh);
139 if (res < time.wPeriodMin)
140 res = time.wPeriodMin;
141 if (timeBeginPeriod(res) == TIMERR_NOCANDO)
142 WARN("Could not set minimum resolution, don't expect sound\n");
144 prim->timer_res = res;
145 prim->timer_id = timeSetEvent(triggertime, res, DS8Buffer_timer, prim->thread_id, TIME_PERIODIC|TIME_KILL_SYNCHRONOUS);
148 /* Should be called with critsect held and context set.. */
149 static void DS8Buffer_addnotify(DS8Buffer *buf)
151 DS8Buffer **list;
152 DWORD i;
154 list = buf->primary->notifies;
155 for(i = 0; i < buf->primary->nnotifies; ++i)
157 if(buf == list[i])
159 ERR("Buffer %p already in notification list\n", buf);
160 return;
163 if(buf->primary->nnotifies == buf->primary->sizenotifies)
165 list = HeapReAlloc(GetProcessHeap(), 0, list, (buf->primary->nnotifies + 1) * sizeof(*list));
166 if(!list)
167 return;
168 buf->primary->sizenotifies++;
170 list[buf->primary->nnotifies++] = buf;
171 buf->primary->notifies = list;
175 static const char *get_fmtstr_PCM(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out, ALenum *in_chans, ALenum *in_type)
177 out->Format = *format;
178 out->Format.cbSize = 0;
180 if(format->wBitsPerSample == 8)
182 *in_type = AL_UNSIGNED_BYTE;
183 switch(format->nChannels)
185 case 1: *in_chans = AL_MONO;
186 return "AL_FORMAT_MONO8";
187 case 2: *in_chans = AL_STEREO;
188 return "AL_FORMAT_STEREO8";
189 case 4: *in_chans = AL_QUAD;
190 return "AL_FORMAT_QUAD8";
191 case 6: *in_chans = AL_5POINT1;
192 return "AL_FORMAT_51CHN8";
193 case 7: *in_chans = AL_6POINT1;
194 return "AL_FORMAT_61CHN8";
195 case 8: *in_chans = AL_7POINT1;
196 return "AL_FORMAT_71CHN8";
197 default: break;
200 else if(format->wBitsPerSample == 16)
202 *in_type = AL_SHORT;
203 switch(format->nChannels)
205 case 1: *in_chans = AL_MONO;
206 return "AL_FORMAT_MONO16";
207 case 2: *in_chans = AL_STEREO;
208 return "AL_FORMAT_STEREO16";
209 case 4: *in_chans = AL_QUAD;
210 return "AL_FORMAT_QUAD16";
211 case 6: *in_chans = AL_5POINT1;
212 return "AL_FORMAT_51CHN16";
213 case 7: *in_chans = AL_6POINT1;
214 return "AL_FORMAT_61CHN16";
215 case 8: *in_chans = AL_7POINT1;
216 return "AL_FORMAT_71CHN16";
217 default: break;
220 #if 0 /* Will cause incorrect byte offsets */
221 else if(format->wBitsPerSample == 24 && prim->SupportedExt[SOFT_BUFFER_SAMPLES])
223 *in_type = AL_BYTE3;
224 switch(format->nChannels)
226 case 1: *in_chans = AL_MONO;
227 return "AL_MONO32F";
228 case 2: *in_chans = AL_STEREO;
229 return "AL_STEREO32F";
230 case 4: *in_chans = AL_QUAD;
231 return "AL_QUAD32F";
232 case 6: *in_chans = AL_5POINT1;
233 return "AL_5POINT1_32F";
234 case 7: *in_chans = AL_6POINT1;
235 return "AL_6POINT1_32F";
236 case 8: *in_chans = AL_7POINT1;
237 return "AL_7POINT1_32F";
238 default: break;
241 #endif
242 else if(format->wBitsPerSample == 32 && prim->SupportedExt[SOFT_BUFFER_SAMPLES])
244 *in_type = AL_INT;
245 switch(format->nChannels)
247 case 1: *in_chans = AL_MONO;
248 return "AL_MONO32F";
249 case 2: *in_chans = AL_STEREO;
250 return "AL_STEREO32F";
251 case 4: *in_chans = AL_QUAD;
252 return "AL_QUAD32F";
253 case 6: *in_chans = AL_5POINT1;
254 return "AL_5POINT1_32F";
255 case 7: *in_chans = AL_6POINT1;
256 return "AL_6POINT1_32F";
257 case 8: *in_chans = AL_7POINT1;
258 return "AL_7POINT1_32F";
259 default: break;
263 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
264 format->wBitsPerSample, format->nChannels);
265 return NULL;
268 static const char *get_fmtstr_FLOAT(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out, ALenum *in_chans, ALenum *in_type)
270 out->Format = *format;
271 out->Format.cbSize = 0;
273 if(format->wBitsPerSample == 32 &&
274 (prim->SupportedExt[EXT_FLOAT32] || prim->SupportedExt[SOFT_BUFFER_SAMPLES]))
276 *in_type = AL_FLOAT;
277 switch(format->nChannels)
279 case 1: *in_chans = AL_MONO;
280 return "AL_FORMAT_MONO_FLOAT32";
281 case 2: *in_chans = AL_STEREO;
282 return "AL_FORMAT_STEREO_FLOAT32";
283 case 4: *in_chans = AL_QUAD;
284 return "AL_FORMAT_QUAD32";
285 case 6: *in_chans = AL_5POINT1;
286 return "AL_FORMAT_51CHN32";
287 case 7: *in_chans = AL_6POINT1;
288 return "AL_FORMAT_61CHN32";
289 case 8: *in_chans = AL_7POINT1;
290 return "AL_FORMAT_71CHN32";
291 default: break;
294 #if 0 /* Will cause incorrect byte offsets */
295 else if(format->wBitsPerSample == 64 && prim->SupportedExt[SOFT_BUFFER_SAMPLES])
297 *in_type = AL_DOUBLE;
298 switch(format->nChannels)
300 case 1: *in_chans = AL_MONO;
301 return "AL_MONO32F";
302 case 2: *in_chans = AL_STEREO;
303 return "AL_STEREO32F";
304 case 4: *in_chans = AL_QUAD;
305 return "AL_QUAD32F";
306 case 6: *in_chans = AL_5POINT1;
307 return "AL_5POINT1_32F";
308 case 7: *in_chans = AL_6POINT1;
309 return "AL_6POINT1_32F";
310 case 8: *in_chans = AL_7POINT1;
311 return "AL_7POINT1_32F";
312 default: break;
315 #endif
317 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
318 format->wBitsPerSample, format->nChannels);
319 return NULL;
322 /* Speaker configs */
323 #define MONO SPEAKER_FRONT_CENTER
324 #define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)
325 #define REAR (SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
326 #define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
327 #define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
328 #define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
329 #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)
331 static const char *get_fmtstr_EXT(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out, ALenum *in_chans, ALenum *in_type)
333 *out = *(const WAVEFORMATEXTENSIBLE*)format;
334 out->Format.cbSize = sizeof(*out) - sizeof(out->Format);
336 if(!out->Samples.wValidBitsPerSample)
337 out->Samples.wValidBitsPerSample = out->Format.wBitsPerSample;
338 else if(out->Samples.wValidBitsPerSample != out->Format.wBitsPerSample)
340 FIXME("Padded samples not supported (%u of %u)\n", out->Samples.wValidBitsPerSample, out->Format.wBitsPerSample);
341 return NULL;
344 if(out->dwChannelMask != MONO && out->dwChannelMask != STEREO &&
345 !prim->SupportedExt[EXT_MCFORMATS] && !prim->SupportedExt[SOFT_BUFFER_SAMPLES])
347 WARN("Multi-channel not available\n");
348 return NULL;
351 if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
353 if(out->Samples.wValidBitsPerSample == 8)
355 *in_type = AL_UNSIGNED_BYTE;
356 switch(out->dwChannelMask)
358 case MONO: *in_chans = AL_MONO;
359 return "AL_FORMAT_MONO8";
360 case STEREO: *in_chans = AL_STEREO;
361 return "AL_FORMAT_STEREO8";
362 case REAR: *in_chans = AL_REAR;
363 return "AL_FORMAT_REAR8";
364 case QUAD: *in_chans = AL_QUAD;
365 return "AL_FORMAT_QUAD8";
366 case X5DOT1: *in_chans = AL_5POINT1;
367 return "AL_FORMAT_51CHN8";
368 case X6DOT1: *in_chans = AL_6POINT1;
369 return "AL_FORMAT_61CHN8";
370 case X7DOT1: *in_chans = AL_7POINT1;
371 return "AL_FORMAT_71CHN8";
372 default: break;
375 else if(out->Samples.wValidBitsPerSample == 16)
377 *in_type = AL_SHORT;
378 switch(out->dwChannelMask)
380 case MONO: *in_chans = AL_MONO;
381 return "AL_FORMAT_MONO16";
382 case STEREO: *in_chans = AL_STEREO;
383 return "AL_FORMAT_STEREO16";
384 case REAR: *in_chans = AL_REAR;
385 return "AL_FORMAT_REAR16";
386 case QUAD: *in_chans = AL_QUAD;
387 return "AL_FORMAT_QUAD16";
388 case X5DOT1: *in_chans = AL_5POINT1;
389 return "AL_FORMAT_51CHN16";
390 case X6DOT1: *in_chans = AL_6POINT1;
391 return "AL_FORMAT_61CHN16";
392 case X7DOT1: *in_chans = AL_7POINT1;
393 return "AL_FORMAT_71CHN16";
394 default: break;
397 #if 0
398 else if(out->Samples.wValidBitsPerSample == 24 &&
399 prim->SupportedExt[SOFT_BUFFER_SAMPLES])
401 *in_type = AL_BYTE3;
402 switch(out->dwChannelMask)
404 case MONO: *in_chans = AL_MONO;
405 return "AL_MONO32F";
406 case STEREO: *in_chans = AL_STEREO;
407 return "AL_STEREO32F";
408 case REAR: *in_chans = AL_REAR;
409 return "AL_REAR32F";
410 case QUAD: *in_chans = AL_QUAD;
411 return "AL_QUAD32F";
412 case X5DOT1: *in_chans = AL_5POINT1;
413 return "AL_5POINT1_32F";
414 case X6DOT1: *in_chans = AL_6POINT1;
415 return "AL_6POINT1_32F";
416 case X7DOT1: *in_chans = AL_7POINT1;
417 return "AL_7POINT1_32F";
418 default: break;
421 #endif
422 else if(out->Samples.wValidBitsPerSample == 32 &&
423 prim->SupportedExt[SOFT_BUFFER_SAMPLES])
425 *in_type = AL_INT;
426 switch(out->dwChannelMask)
428 case MONO: *in_chans = AL_MONO;
429 return "AL_MONO32F";
430 case STEREO: *in_chans = AL_STEREO;
431 return "AL_STEREO32F";
432 case REAR: *in_chans = AL_REAR;
433 return "AL_REAR32F";
434 case QUAD: *in_chans = AL_QUAD;
435 return "AL_QUAD32F";
436 case X5DOT1: *in_chans = AL_5POINT1;
437 return "AL_5POINT1_32F";
438 case X6DOT1: *in_chans = AL_6POINT1;
439 return "AL_6POINT1_32F";
440 case X7DOT1: *in_chans = AL_7POINT1;
441 return "AL_7POINT1_32F";
442 default: break;
446 FIXME("Could not get OpenAL PCM format (%d-bit, channelmask %#x)\n",
447 out->Samples.wValidBitsPerSample, out->dwChannelMask);
448 return NULL;
450 else if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) &&
451 (prim->SupportedExt[EXT_FLOAT32] || prim->SupportedExt[SOFT_BUFFER_SAMPLES]))
453 if(out->Samples.wValidBitsPerSample == 32)
455 *in_type = AL_FLOAT;
456 switch(out->dwChannelMask)
458 case MONO: *in_chans = AL_MONO;
459 return "AL_FORMAT_MONO_FLOAT32";
460 case STEREO: *in_chans = AL_STEREO;
461 return "AL_FORMAT_STEREO_FLOAT32";
462 case REAR: *in_chans = AL_REAR;
463 return "AL_FORMAT_REAR32";
464 case QUAD: *in_chans = AL_QUAD;
465 return "AL_FORMAT_QUAD32";
466 case X5DOT1: *in_chans = AL_5POINT1;
467 return "AL_FORMAT_51CHN32";
468 case X6DOT1: *in_chans = AL_6POINT1;
469 return "AL_FORMAT_61CHN32";
470 case X7DOT1: *in_chans = AL_7POINT1;
471 return "AL_FORMAT_71CHN32";
472 default: break;
475 #if 0
476 else if(out->Samples.wValidBitsPerSample == 64 &&
477 prim->SupportedExt[SOFT_BUFFER_SAMPLES])
479 *in_type = AL_DOUBLE;
480 switch(out->dwChannelMask)
482 case MONO: *in_chans = AL_MONO;
483 return "AL_MONO32F";
484 case STEREO: *in_chans = AL_STEREO;
485 return "AL_STEREO32F";
486 case REAR: *in_chans = AL_REAR;
487 return "AL_REAR32F";
488 case QUAD: *in_chans = AL_QUAD;
489 return "AL_QUAD32F";
490 case X5DOT1: *in_chans = AL_5POINT1;
491 return "AL_5POINT1_32F";
492 case X6DOT1: *in_chans = AL_6POINT1;
493 return "AL_6POINT1_32F";
494 case X7DOT1: *in_chans = AL_7POINT1;
495 return "AL_7POINT1_32F";
496 default: break;
499 #endif
500 else
502 WARN("Invalid float bits: %u\n", out->Samples.wValidBitsPerSample);
503 return NULL;
506 FIXME("Could not get OpenAL float format (%d-bit, channelmask %#x)\n",
507 out->Samples.wValidBitsPerSample, out->dwChannelMask);
508 return NULL;
510 else if(!IsEqualGUID(&out->SubFormat, &GUID_NULL))
511 ERR("Unhandled extensible format: %s\n", debugstr_guid(&out->SubFormat));
512 return NULL;
515 static void DS8Data_Release(DS8Data *This);
516 static HRESULT DS8Data_Create(DS8Data **ppv, const DSBUFFERDESC *desc, DS8Primary *prim)
518 HRESULT hr = DSERR_INVALIDPARAM;
519 const WAVEFORMATEX *format;
520 const char *fmt_str = NULL;
521 DS8Data *pBuffer;
523 format = desc->lpwfxFormat;
524 TRACE("Requested buffer format:\n"
525 " FormatTag = 0x%04x\n"
526 " Channels = %d\n"
527 " SamplesPerSec = %u\n"
528 " AvgBytesPerSec = %u\n"
529 " BlockAlign = %d\n"
530 " BitsPerSample = %d\n",
531 format->wFormatTag, format->nChannels,
532 format->nSamplesPerSec, format->nAvgBytesPerSec,
533 format->nBlockAlign, format->wBitsPerSample);
535 if(format->nBlockAlign == 0)
537 WARN("Invalid BlockAlign specified\n");
538 return DSERR_INVALIDPARAM;
541 /* Generate a new buffer. Supporting the DSBCAPS_LOC* flags properly
542 * will need the EAX-RAM extension. Currently, we just tell the app it
543 * gets what it wanted. */
544 pBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pBuffer));
545 if(!pBuffer)
546 return E_OUTOFMEMORY;
547 pBuffer->ref = 1;
549 pBuffer->dsbflags = desc->dwFlags;
550 if((pBuffer->dsbflags&(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE)) == (DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE))
552 WARN("Hardware and software location requested\n");
553 goto fail;
555 if(!(pBuffer->dsbflags&(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE|DSBCAPS_LOCDEFER)))
556 pBuffer->dsbflags |= DSBCAPS_LOCHARDWARE;
558 pBuffer->buf_size = desc->dwBufferBytes + format->nBlockAlign - 1;
559 pBuffer->buf_size -= pBuffer->buf_size%format->nBlockAlign;
561 hr = DSERR_BUFFERTOOSMALL;
562 if(pBuffer->buf_size < DSBSIZE_MIN)
563 goto fail;
565 hr = DSERR_INVALIDPARAM;
566 if(pBuffer->buf_size > DSBSIZE_MAX)
567 goto fail;
569 pBuffer->numsegs = 1;
570 pBuffer->segsize = pBuffer->buf_size;
571 pBuffer->lastsegsize = pBuffer->buf_size;
573 if(!(pBuffer->dsbflags&DSBCAPS_STATIC) && !prim->ExtAL.BufferSubData &&
574 !prim->ExtAL.BufferSamplesSOFT && !prim->ExtAL.BufferDataStatic)
576 ALCint refresh = FAKE_REFRESH_COUNT;
577 ALuint newSize;
579 alcGetIntegerv(prim->parent->device, ALC_REFRESH, 1, &refresh);
580 getALCError(prim->parent->device);
582 newSize = format->nAvgBytesPerSec/refresh + format->nBlockAlign - 1;
583 newSize -= newSize%format->nBlockAlign;
585 /* Make sure enough buffers are available */
586 if(newSize > pBuffer->buf_size/(QBUFFERS+2))
587 ERR("Buffer segments too large to stream (%u for %u)!\n",
588 newSize, pBuffer->buf_size);
589 else
591 pBuffer->numsegs = pBuffer->buf_size/newSize;
592 pBuffer->segsize = newSize;
593 pBuffer->lastsegsize = pBuffer->buf_size - (newSize*(pBuffer->numsegs-1));
594 TRACE("New streaming buffer (%u chunks, %u : %u sizes)\n",
595 pBuffer->numsegs, pBuffer->segsize, pBuffer->lastsegsize);
599 if(format->wFormatTag == WAVE_FORMAT_PCM)
600 fmt_str = get_fmtstr_PCM(prim, format, &pBuffer->format, &pBuffer->in_chans, &pBuffer->in_type);
601 else if(format->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
602 fmt_str = get_fmtstr_FLOAT(prim, format, &pBuffer->format, &pBuffer->in_chans, &pBuffer->in_type);
603 else if(format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
605 const WAVEFORMATEXTENSIBLE *wfe;
607 hr = DSERR_CONTROLUNAVAIL;
608 if(format->cbSize != sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) &&
609 format->cbSize != sizeof(WAVEFORMATEXTENSIBLE))
610 goto fail;
612 wfe = (const WAVEFORMATEXTENSIBLE*)format;
613 TRACE("Extensible values:\n"
614 " Samples = %d\n"
615 " ChannelMask = %#x\n"
616 " SubFormat = %s\n",
617 wfe->Samples.wReserved, wfe->dwChannelMask,
618 debugstr_guid(&wfe->SubFormat));
620 hr = DSERR_INVALIDCALL;
621 fmt_str = get_fmtstr_EXT(prim, format, &pBuffer->format, &pBuffer->in_chans, &pBuffer->in_type);
623 else
624 ERR("Unhandled formattag 0x%04x\n", format->wFormatTag);
626 if(!fmt_str)
627 goto fail;
629 pBuffer->buf_format = alGetEnumValue(fmt_str);
630 if(alGetError() != AL_NO_ERROR || pBuffer->buf_format == 0 ||
631 pBuffer->buf_format == -1)
633 WARN("Could not get OpenAL format from %s\n", fmt_str);
634 goto fail;
637 hr = E_OUTOFMEMORY;
638 pBuffer->buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pBuffer->buffers)*pBuffer->numsegs);
639 pBuffer->data = HeapAlloc(GetProcessHeap(), 0, pBuffer->buf_size);
640 if(!pBuffer->buffers || !pBuffer->data)
641 goto fail;
643 alGenBuffers(pBuffer->numsegs, pBuffer->buffers);
644 getALError();
646 *ppv = pBuffer;
647 return S_OK;
649 fail:
650 DS8Data_Release(pBuffer);
651 return hr;
654 static void DS8Data_AddRef(DS8Data *data)
656 InterlockedIncrement(&data->ref);
659 /* This function is always called with the device lock held */
660 static void DS8Data_Release(DS8Data *This)
662 if(InterlockedDecrement(&This->ref)) return;
664 TRACE("Deleting %p\n", This);
665 if (This->buffers && This->buffers[0])
667 alDeleteBuffers(This->numsegs, This->buffers);
668 getALError();
670 HeapFree(GetProcessHeap(), 0, This->buffers);
671 HeapFree(GetProcessHeap(), 0, This->data);
672 HeapFree(GetProcessHeap(), 0, This);
675 HRESULT DS8Buffer_Create(DS8Buffer **ppv, DS8Primary *parent, IDirectSoundBuffer *orig)
677 HRESULT hr = DSERR_OUTOFMEMORY;
678 DS8Buffer *This;
679 DS8Buffer **bufs;
681 *ppv = NULL;
682 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
683 if(!This) return hr;
685 This->IDirectSoundBuffer8_iface.lpVtbl = (IDirectSoundBuffer8Vtbl*)&DS8Buffer_Vtbl;
686 This->IDirectSound3DBuffer_iface.lpVtbl = (IDirectSound3DBufferVtbl*)&DS8Buffer3d_Vtbl;
687 This->IDirectSoundNotify_iface.lpVtbl = (IDirectSoundNotifyVtbl*)&DS8BufferNot_Vtbl;
688 This->IKsPropertySet_iface.lpVtbl = (IKsPropertySetVtbl*)&DS8BufferProp_Vtbl;
690 This->primary = parent;
691 This->ctx = parent->ctx;
692 This->ExtAL = &parent->ExtAL;
693 This->crst = &parent->crst;
694 This->ref = This->all_ref = 1;
696 if(orig)
698 DS8Buffer *org = impl_from_IDirectSoundBuffer(orig);
699 hr = DSERR_BUFFERLOST;
700 if(org->bufferlost)
701 goto fail;
702 DS8Data_AddRef(org->buffer);
703 This->buffer = org->buffer;
706 /* Append to buffer list */
707 bufs = parent->buffers;
708 if(parent->nbuffers == parent->sizebuffers)
710 bufs = HeapReAlloc(GetProcessHeap(), 0, bufs, sizeof(*bufs)*(1+parent->nbuffers));
711 hr = DSERR_OUTOFMEMORY;
712 if(!bufs) goto fail;
713 parent->sizebuffers++;
715 parent->buffers = bufs;
716 bufs[parent->nbuffers++] = This;
718 /* Disable until initialized.. */
719 This->ds3dmode = DS3DMODE_DISABLE;
721 *ppv = This;
722 return S_OK;
724 fail:
725 DS8Buffer_Destroy(This);
726 return hr;
729 void DS8Buffer_Destroy(DS8Buffer *This)
731 DS8Primary *prim = This->primary;
732 DWORD idx;
734 TRACE("Destroying %p\n", This);
736 EnterCriticalSection(&prim->crst);
737 /* Remove from list, if in list */
738 for(idx = 0;idx < prim->nnotifies;++idx)
740 if(This == prim->notifies[idx])
742 prim->notifies[idx] = prim->notifies[--prim->nnotifies];
743 break;
746 for(idx = 0;idx < prim->nbuffers;++idx)
748 if(prim->buffers[idx] == This)
750 prim->buffers[idx] = prim->buffers[--prim->nbuffers];
751 break;
755 setALContext(This->ctx);
756 if(This->source)
758 ALuint *sources;
760 alSourceStop(This->source);
761 alSourcei(This->source, AL_BUFFER, 0);
762 getALError();
764 sources = prim->sources;
765 if(prim->nsources == prim->sizesources)
767 sources = HeapReAlloc(GetProcessHeap(), 0, sources, sizeof(*sources)*(prim->nsources+1));
768 if(!sources)
769 alDeleteSources(1, &This->source);
770 else
771 prim->sizesources++;
773 if(sources)
775 sources[prim->nsources++] = This->source;
776 prim->sources = sources;
778 This->source = 0;
780 LeaveCriticalSection(&prim->crst);
782 if(This->buffer)
783 DS8Data_Release(This->buffer);
785 popALContext();
787 HeapFree(GetProcessHeap(), 0, This->notify);
788 HeapFree(GetProcessHeap(), 0, This);
792 static HRESULT WINAPI DS8Buffer_QueryInterface(IDirectSoundBuffer8 *iface, REFIID riid, void **ppv)
794 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
796 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
798 *ppv = NULL;
799 if(IsEqualIID(riid, &IID_IUnknown) ||
800 IsEqualIID(riid, &IID_IDirectSoundBuffer))
801 *ppv = &This->IDirectSoundBuffer8_iface;
802 else if(IsEqualIID(riid, &IID_IDirectSoundBuffer8))
804 if(This->primary->parent->is_8)
805 *ppv = &This->IDirectSoundBuffer8_iface;
807 else if(IsEqualIID(riid, &IID_IDirectSound3DBuffer))
809 if((This->buffer->dsbflags&DSBCAPS_CTRL3D))
810 *ppv = &This->IDirectSound3DBuffer_iface;
812 else if(IsEqualIID(riid, &IID_IDirectSoundNotify))
814 if((This->buffer->dsbflags&DSBCAPS_CTRLPOSITIONNOTIFY))
815 *ppv = &This->IDirectSoundNotify_iface;
817 else if(IsEqualIID(riid, &IID_IKsPropertySet))
818 *ppv = &This->IKsPropertySet_iface;
819 else
820 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
822 if(*ppv)
824 IUnknown_AddRef((IUnknown*)*ppv);
825 return S_OK;
828 return E_NOINTERFACE;
831 static ULONG WINAPI DS8Buffer_AddRef(IDirectSoundBuffer8 *iface)
833 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
834 LONG ret;
836 InterlockedIncrement(&This->all_ref);
837 ret = InterlockedIncrement(&This->ref);
838 TRACE("new refcount %d\n", ret);
840 return ret;
843 static ULONG WINAPI DS8Buffer_Release(IDirectSoundBuffer8 *iface)
845 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
846 LONG ret;
848 ret = InterlockedDecrement(&This->ref);
849 TRACE("new refcount %d\n", ret);
850 if(InterlockedDecrement(&This->all_ref) == 0)
851 DS8Buffer_Destroy(This);
853 return ret;
856 static HRESULT WINAPI DS8Buffer_GetCaps(IDirectSoundBuffer8 *iface, DSBCAPS *caps)
858 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
860 TRACE("(%p)->(%p)\n", iface, caps);
862 if(!caps || caps->dwSize < sizeof(*caps))
864 WARN("Invalid DSBCAPS (%p, %u)\n", caps, (caps ? caps->dwSize : 0));
865 return DSERR_INVALIDPARAM;
868 caps->dwFlags = This->buffer->dsbflags;
869 caps->dwBufferBytes = This->buffer->buf_size;
870 caps->dwUnlockTransferRate = 4096;
871 caps->dwPlayCpuOverhead = 0;
872 return S_OK;
875 static HRESULT WINAPI DS8Buffer_GetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD *playpos, DWORD *curpos)
877 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
878 WAVEFORMATEX *format = &This->buffer->format.Format;
879 UINT writecursor, pos;
881 TRACE("(%p)->(%p, %p)\n", iface, playpos, curpos);
883 EnterCriticalSection(This->crst);
884 setALContext(This->ctx);
886 if(This->buffer->numsegs > 1)
888 ALint queued = QBUFFERS;
889 alGetSourcei(This->source, AL_BUFFERS_QUEUED, &queued);
890 getALError();
892 pos = (This->curidx+This->buffer->numsegs-queued)%This->buffer->numsegs;
893 pos *= This->buffer->segsize;
894 writecursor = This->curidx * This->buffer->segsize;
896 else if(This->ExtAL->BufferSubData || This->ExtAL->BufferSamplesSOFT)
898 ALint rwpos[2] = { 0, 0 };
900 alGetSourceiv(This->source, AL_BYTE_RW_OFFSETS_SOFT, rwpos);
901 getALError();
903 pos = rwpos[0];
904 writecursor = rwpos[1];
906 else
908 ALint status = 0;
909 ALint ofs = 0;
911 alGetSourcei(This->source, AL_BYTE_OFFSET, &ofs);
912 alGetSourcei(This->source, AL_SOURCE_STATE, &status);
913 getALError();
915 pos = ofs;
916 if(status == AL_PLAYING)
918 writecursor = format->nSamplesPerSec / 100;
919 writecursor *= format->nBlockAlign;
921 else
922 writecursor = 0;
923 writecursor = (writecursor + pos) % This->buffer->buf_size;
925 TRACE("%p Play pos = %u, write pos = %u\n", This, pos, writecursor);
926 if(pos >= This->buffer->buf_size)
928 ERR("playpos >= buf_size\n");
929 pos %= This->buffer->buf_size;
931 if(writecursor >= This->buffer->buf_size)
933 ERR("writepos >= buf_size\n");
934 writecursor %= This->buffer->buf_size;
937 if(playpos) *playpos = pos;
938 if(curpos) *curpos = writecursor;
940 popALContext();
941 LeaveCriticalSection(This->crst);
943 return S_OK;
946 static HRESULT WINAPI DS8Buffer_GetFormat(IDirectSoundBuffer8 *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
948 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
949 HRESULT hr = S_OK;
950 UINT size;
952 TRACE("(%p)->(%p, %u, %p)\n", iface, wfx, allocated, written);
954 if(!wfx && !written)
956 WARN("Cannot report format or format size\n");
957 return DSERR_INVALIDPARAM;
960 EnterCriticalSection(This->crst);
961 size = sizeof(This->buffer->format.Format) + This->buffer->format.Format.cbSize;
962 if(wfx)
964 if(allocated < size)
965 hr = DSERR_INVALIDPARAM;
966 else
967 memcpy(wfx, &This->buffer->format.Format, size);
969 if(written)
970 *written = size;
971 LeaveCriticalSection(This->crst);
973 return hr;
976 static HRESULT WINAPI DS8Buffer_GetVolume(IDirectSoundBuffer8 *iface, LONG *vol)
978 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
979 HRESULT hr;
981 TRACE("(%p)->(%p)\n", iface, vol);
983 if(!vol)
985 WARN("Invalid pointer\n");
986 return DSERR_INVALIDPARAM;
989 EnterCriticalSection(This->crst);
991 hr = DSERR_CONTROLUNAVAIL;
992 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
993 WARN("Volume control not set\n");
994 else
996 ALfloat gain = 1.0f;
998 setALContext(This->ctx);
999 alGetSourcef(This->source, AL_GAIN, &gain);
1000 getALError();
1001 popALContext();
1003 *vol = gain_to_mB(gain);
1004 *vol = min(*vol, DSBVOLUME_MAX);
1005 *vol = max(*vol, DSBVOLUME_MIN);
1007 hr = DS_OK;
1010 LeaveCriticalSection(This->crst);
1011 return hr;
1014 static HRESULT WINAPI DS8Buffer_GetPan(IDirectSoundBuffer8 *iface, LONG *pan)
1016 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1017 HRESULT hr;
1019 TRACE("(%p)->(%p)\n", iface, pan);
1021 if(!pan)
1023 WARN("Invalid pointer\n");
1024 return DSERR_INVALIDPARAM;
1027 EnterCriticalSection(This->crst);
1029 hr = DSERR_CONTROLUNAVAIL;
1030 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
1031 WARN("Panning control not set\n");
1032 else
1034 ALfloat pos[3];
1036 setALContext(This->ctx);
1037 alGetSourcefv(This->source, AL_POSITION, pos);
1038 getALError();
1039 popALContext();
1041 *pan = (LONG)((pos[0]+1.0) * (DSBPAN_RIGHT-DSBPAN_LEFT) / 2.0 + 0.5) + DSBPAN_LEFT;
1042 *pan = min(*pan, DSBPAN_RIGHT);
1043 *pan = max(*pan, DSBPAN_LEFT);
1045 hr = DS_OK;
1048 LeaveCriticalSection(This->crst);
1049 return hr;
1052 static HRESULT WINAPI DS8Buffer_GetFrequency(IDirectSoundBuffer8 *iface, DWORD *freq)
1054 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1055 HRESULT hr;
1057 TRACE("(%p)->(%p)\n", iface, freq);
1059 if(!freq)
1061 WARN("Invalid pointer\n");
1062 return DSERR_INVALIDPARAM;
1065 EnterCriticalSection(This->crst);
1067 hr = DSERR_CONTROLUNAVAIL;
1068 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
1069 WARN("Frequency control not set\n");
1070 else
1072 ALfloat pitch = 1.0f;
1074 setALContext(This->ctx);
1075 alGetSourcefv(This->source, AL_PITCH, &pitch);
1076 getALError();
1077 popALContext();
1079 *freq = (DWORD)(This->buffer->format.Format.nSamplesPerSec * pitch);
1081 hr = DS_OK;
1084 LeaveCriticalSection(This->crst);
1085 return hr;
1088 static HRESULT WINAPI DS8Buffer_GetStatus(IDirectSoundBuffer8 *iface, DWORD *status)
1090 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1091 ALint state, looping;
1093 TRACE("(%p)->(%p)\n", iface, status);
1095 if(!status)
1097 WARN("Invalid pointer\n");
1098 return DSERR_INVALIDPARAM;
1101 EnterCriticalSection(This->crst);
1103 setALContext(This->ctx);
1104 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1105 looping = This->islooping;
1106 if(This->buffer->numsegs == 1)
1107 alGetSourcei(This->source, AL_LOOPING, &looping);
1108 else if(state != AL_PLAYING)
1109 state = This->isplaying ? AL_PLAYING : AL_PAUSED;
1110 getALError();
1111 popALContext();
1113 *status = 0;
1114 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1116 if((This->buffer->dsbflags&DSBCAPS_LOCSOFTWARE))
1117 *status |= DSBSTATUS_LOCSOFTWARE;
1118 else if((This->buffer->dsbflags&DSBCAPS_LOCHARDWARE))
1119 *status |= DSBSTATUS_LOCHARDWARE;
1121 if(state == AL_PLAYING)
1122 *status |= DSBSTATUS_PLAYING | (looping ? DSBSTATUS_LOOPING : 0);
1124 LeaveCriticalSection(This->crst);
1126 return S_OK;
1129 static HRESULT WINAPI DS8Buffer_Initialize(IDirectSoundBuffer8 *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
1131 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1132 DS3DBUFFER *ds3dbuffer;
1133 HRESULT hr;
1135 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
1137 EnterCriticalSection(This->crst);
1138 setALContext(This->ctx);
1140 hr = DSERR_ALREADYINITIALIZED;
1141 if(This->source)
1142 goto out;
1144 if(!This->buffer)
1146 hr = DSERR_INVALIDPARAM;
1147 if(!desc)
1149 WARN("Missing DSound buffer description\n");
1150 goto out;
1152 if(!desc->lpwfxFormat)
1154 WARN("Missing buffer format (%p)\n", This);
1155 goto out;
1157 if((desc->dwFlags&DSBCAPS_CTRL3D) && desc->lpwfxFormat->nChannels != 1)
1159 if(This->primary->parent->is_8)
1161 /* DirectSoundBuffer8 objects aren't allowed non-mono 3D
1162 * buffers */
1163 WARN("Can't create multi-channel 3D buffers\n");
1164 goto out;
1166 ERR("Multi-channel 3D sounds are not spatialized\n");
1169 hr = DS8Data_Create(&This->buffer, desc, This->primary);
1170 if(FAILED(hr))
1171 goto out;
1172 else
1174 DS8Data *buf = This->buffer;
1176 if(buf->in_type == AL_UNSIGNED_BYTE)
1177 memset(buf->data, 0x80, buf->buf_size);
1178 else
1179 memset(buf->data, 0x00, buf->buf_size);
1181 if(This->ExtAL->BufferDataStatic)
1182 This->ExtAL->BufferDataStatic(buf->buffers[0], buf->buf_format,
1183 buf->data, buf->buf_size,
1184 buf->format.Format.nSamplesPerSec);
1185 else if(This->ExtAL->BufferSamplesSOFT)
1186 This->ExtAL->BufferSamplesSOFT(buf->buffers[0],
1187 buf->format.Format.nSamplesPerSec, buf->buf_format,
1188 buf->buf_size/buf->format.Format.nBlockAlign,
1189 buf->in_chans, buf->in_type, buf->data);
1190 else if(This->ExtAL->BufferSubData)
1191 alBufferData(buf->buffers[0], buf->buf_format,
1192 buf->data, buf->buf_size,
1193 buf->format.Format.nSamplesPerSec);
1195 getALError();
1198 hr = DSERR_GENERIC;
1199 if(This->primary->nsources)
1201 This->source = This->primary->sources[--This->primary->nsources];
1202 alSourcef(This->source, AL_GAIN, 1.0f);
1203 alSourcef(This->source, AL_PITCH, 1.0f);
1204 getALError();
1206 else
1208 alGenSources(1, &This->source);
1209 if(alGetError() != AL_NO_ERROR)
1210 goto out;
1213 ds3dbuffer = &This->ds3dbuffer;
1214 ds3dbuffer->dwSize = sizeof(*ds3dbuffer);
1215 ds3dbuffer->vPosition.x = 0.0;
1216 ds3dbuffer->vPosition.y = 0.0;
1217 ds3dbuffer->vPosition.z = 0.0;
1218 ds3dbuffer->vVelocity.x = 0.0;
1219 ds3dbuffer->vVelocity.y = 0.0;
1220 ds3dbuffer->vVelocity.z = 0.0;
1221 ds3dbuffer->dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
1222 ds3dbuffer->dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
1223 ds3dbuffer->vConeOrientation.x = 0.0;
1224 ds3dbuffer->vConeOrientation.y = 0.0;
1225 ds3dbuffer->vConeOrientation.z = 1.0;
1226 ds3dbuffer->lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
1227 ds3dbuffer->flMinDistance = DS3D_DEFAULTMINDISTANCE;
1228 ds3dbuffer->flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
1229 ds3dbuffer->dwMode = DS3DMODE_NORMAL;
1231 if((This->buffer->dsbflags&DSBCAPS_CTRL3D))
1233 if(This->primary->auxslot != 0)
1235 alSource3i(This->source, AL_AUXILIARY_SEND_FILTER, This->primary->auxslot, 0, AL_FILTER_NULL);
1236 getALError();
1239 hr = IDirectSound3DBuffer_SetAllParameters(&This->IDirectSound3DBuffer_iface, ds3dbuffer, DS3D_IMMEDIATE);
1240 if(FAILED(hr))
1242 ERR("SetAllParameters failed\n");
1243 goto out;
1246 else
1248 ALuint source = This->source;
1250 if(This->primary->auxslot != 0)
1252 /* Simple hack to make reverb affect non-3D sounds too */
1253 alSource3i(source, AL_AUXILIARY_SEND_FILTER, This->primary->auxslot, 0, AL_FILTER_NULL);
1254 /*alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL);*/
1257 /* Non-3D sources aren't distance attenuated */
1258 This->ds3dmode = DS3DMODE_DISABLE;
1259 alSource3f(source, AL_POSITION, 0.0f, 1.0f, 0.0f);
1260 alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
1261 alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
1262 alSourcef(source, AL_CONE_OUTER_GAIN, 1.0f);
1263 alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f);
1264 alSourcef(source, AL_MAX_DISTANCE, 1000.0f);
1265 alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f);
1266 alSourcei(source, AL_CONE_INNER_ANGLE, 360);
1267 alSourcei(source, AL_CONE_OUTER_ANGLE, 360);
1268 alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);
1269 getALError();
1271 hr = S_OK;
1273 out:
1274 popALContext();
1275 LeaveCriticalSection(This->crst);
1277 return hr;
1280 static HRESULT WINAPI DS8Buffer_Lock(IDirectSoundBuffer8 *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
1282 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1283 HRESULT hr;
1284 DWORD remain;
1286 TRACE("(%p)->(%u, %u, %p, %p, %p, %p, 0x%x)\n", This, ofs, bytes, ptr1, len1, ptr2, len2, flags);
1288 if(!ptr1 || !len1)
1290 WARN("Invalid pointer/len %p %p\n", ptr1, len1);
1291 return DSERR_INVALIDPARAM;
1294 EnterCriticalSection(This->crst);
1295 setALContext(This->ctx);
1297 *ptr1 = NULL;
1298 *len1 = 0;
1299 if(ptr2) *ptr2 = NULL;
1300 if(len2) *len2 = 0;
1302 hr = DSERR_INVALIDPARAM;
1303 if((flags&DSBLOCK_FROMWRITECURSOR))
1304 DS8Buffer_GetCurrentPosition(iface, NULL, &ofs);
1305 else if(ofs >= This->buffer->buf_size)
1307 WARN("Invalid ofs %u\n", ofs);
1308 goto out;
1310 if((flags&DSBLOCK_ENTIREBUFFER))
1311 bytes = This->buffer->buf_size;
1312 else if(bytes > This->buffer->buf_size)
1314 WARN("Invalid size %u\n", bytes);
1315 goto out;
1318 *ptr1 = This->buffer->data + ofs;
1319 if(ofs+bytes >= This->buffer->buf_size)
1321 *len1 = This->buffer->buf_size - ofs;
1322 remain = bytes - *len1;
1324 else
1326 *len1 = bytes;
1327 remain = 0;
1330 This->buffer->locked = TRUE;
1332 if(ptr2 && len2 && remain)
1334 *ptr2 = This->buffer->data;
1335 *len2 = remain;
1337 hr = S_OK;
1339 out:
1340 popALContext();
1341 LeaveCriticalSection(This->crst);
1342 return hr;
1345 static HRESULT WINAPI DS8Buffer_Play(IDirectSoundBuffer8 *iface, DWORD res1, DWORD prio, DWORD flags)
1347 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1348 ALint type, state = AL_STOPPED;
1349 HRESULT hr;
1350 (void)res1;
1352 TRACE("%p\n", This);
1354 EnterCriticalSection(This->crst);
1355 setALContext(This->ctx);
1357 hr = DSERR_BUFFERLOST;
1358 if(This->bufferlost)
1360 WARN("Buffer %p lost\n", This);
1361 goto out;
1364 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1366 if(!(This->buffer->dsbflags&(DSBCAPS_LOCHARDWARE|DSBCAPS_LOCSOFTWARE)))
1368 if(flags & DSBPLAY_LOCSOFTWARE)
1369 This->buffer->dsbflags |= DSBCAPS_LOCSOFTWARE;
1370 else
1371 This->buffer->dsbflags |= DSBCAPS_LOCHARDWARE;
1374 else if(prio)
1376 ERR("Invalid priority set for non-deferred buffer %p, %u!\n", This->buffer, prio);
1377 hr = DSERR_INVALIDPARAM;
1378 goto out;
1381 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1382 if(This->buffer->numsegs > 1)
1384 This->islooping = !!(flags&DSBPLAY_LOOPING);
1385 if(state != AL_PLAYING && This->isplaying)
1386 state = AL_PLAYING;
1388 else
1390 alGetSourcei(This->source, AL_SOURCE_TYPE, &type);
1391 alSourcei(This->source, AL_LOOPING, (flags&DSBPLAY_LOOPING) ? AL_TRUE : AL_FALSE);
1393 getALError();
1395 hr = S_OK;
1396 if(state == AL_PLAYING)
1397 goto out;
1399 /* alSourceQueueBuffers will implicitly set type to streaming */
1400 if(This->buffer->numsegs == 1)
1402 if(type != AL_STATIC)
1403 alSourcei(This->source, AL_BUFFER, This->buffer->buffers[0]);
1404 alSourcePlay(This->source);
1406 if(alGetError() != AL_NO_ERROR)
1408 ERR("Couldn't start source\n");
1409 This->curidx = (This->buffer->numsegs-1+This->curidx)%This->buffer->numsegs;
1410 alSourcei(This->source, AL_BUFFER, 0);
1411 getALError();
1412 hr = DSERR_GENERIC;
1413 goto out;
1415 This->isplaying = TRUE;
1417 if(This->nnotify)
1419 DS8Buffer_addnotify(This);
1420 DS8Buffer_starttimer(This->primary);
1422 else if(This->buffer->numsegs > 1)
1423 DS8Buffer_starttimer(This->primary);
1425 out:
1426 popALContext();
1427 LeaveCriticalSection(This->crst);
1428 return hr;
1431 static HRESULT WINAPI DS8Buffer_SetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD pos)
1433 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1434 HRESULT hr;
1435 TRACE("%p\n", This);
1437 EnterCriticalSection(This->crst);
1438 setALContext(This->ctx);
1440 hr = DSERR_INVALIDPARAM;
1441 if(pos >= This->buffer->buf_size)
1442 goto out;
1444 if(This->buffer->numsegs > 1)
1446 DS8Data *buf = This->buffer;
1447 This->curidx = pos/buf->segsize;
1448 if(This->curidx >= buf->numsegs)
1449 This->curidx = buf->numsegs - 1;
1450 if(This->isplaying)
1452 alSourceStop(This->source);
1453 alSourcei(This->source, AL_BUFFER, 0);
1454 getALError();
1457 else
1458 alSourcei(This->source, AL_BYTE_OFFSET, pos);
1459 This->lastpos = pos;
1460 hr = S_OK;
1462 out:
1463 popALContext();
1464 LeaveCriticalSection(This->crst);
1465 return hr;
1468 static HRESULT WINAPI DS8Buffer_SetFormat(IDirectSoundBuffer8 *iface, const WAVEFORMATEX *wfx)
1470 /* This call only works on primary buffers */
1471 WARN("(%p)->(%p)\n", iface, wfx);
1472 return DSERR_INVALIDCALL;
1475 static HRESULT WINAPI DS8Buffer_SetVolume(IDirectSoundBuffer8 *iface, LONG vol)
1477 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1478 HRESULT hr = S_OK;
1480 TRACE("(%p)->(%d)\n", iface, vol);
1482 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
1484 WARN("Invalid volume (%d)\n", vol);
1485 return DSERR_INVALIDPARAM;
1488 EnterCriticalSection(This->crst);
1489 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
1490 hr = DSERR_CONTROLUNAVAIL;
1491 if(SUCCEEDED(hr))
1493 ALfloat fvol = mB_to_gain(vol);
1494 setALContext(This->ctx);
1495 alSourcef(This->source, AL_GAIN, fvol);
1496 popALContext();
1498 LeaveCriticalSection(This->crst);
1500 return hr;
1503 static HRESULT WINAPI DS8Buffer_SetPan(IDirectSoundBuffer8 *iface, LONG pan)
1505 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1506 HRESULT hr = S_OK;
1508 TRACE("(%p)->(%d)\n", iface, pan);
1510 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
1512 WARN("invalid parameter: pan = %d\n", pan);
1513 return DSERR_INVALIDPARAM;
1516 EnterCriticalSection(This->crst);
1517 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
1518 hr = DSERR_CONTROLUNAVAIL;
1519 else
1521 ALfloat pos[3];
1522 pos[0] = (pan-DSBPAN_LEFT) * 2.0 / (ALfloat)(DSBPAN_RIGHT-DSBPAN_LEFT) - 1.0;
1523 /* NOTE: Strict movement along the X plane can cause the sound to jump
1524 * between left and right sharply. Using a curved path helps smooth it
1525 * out */
1526 pos[1] = sqrt(1.0 - pos[0]*pos[0]);
1527 pos[2] = 0.0;
1529 setALContext(This->ctx);
1530 alSourcefv(This->source, AL_POSITION, pos);
1531 getALError();
1532 popALContext();
1534 if(pan != 0 && This->buffer->format.Format.nChannels > 1)
1535 FIXME("Panning for multi-channel buffers is not supported\n");
1537 LeaveCriticalSection(This->crst);
1539 return hr;
1542 static HRESULT WINAPI DS8Buffer_SetFrequency(IDirectSoundBuffer8 *iface, DWORD freq)
1544 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1545 HRESULT hr = S_OK;
1547 TRACE("(%p)->(%u)\n", iface, freq);
1549 if(freq < DSBFREQUENCY_MIN || freq > DSBFREQUENCY_MAX)
1551 WARN("invalid parameter: freq = %d\n", freq);
1552 return DSERR_INVALIDPARAM;
1555 EnterCriticalSection(This->crst);
1556 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
1557 hr = DSERR_CONTROLUNAVAIL;
1558 else
1560 ALfloat pitch = 1.0f;
1561 if(freq != DSBFREQUENCY_ORIGINAL)
1562 pitch = freq / (ALfloat)This->buffer->format.Format.nSamplesPerSec;
1564 setALContext(This->ctx);
1565 alSourcef(This->source, AL_PITCH, pitch);
1566 getALError();
1567 popALContext();
1569 LeaveCriticalSection(This->crst);
1570 return hr;
1573 static HRESULT WINAPI DS8Buffer_Stop(IDirectSoundBuffer8 *iface)
1575 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1576 ALint state;
1578 TRACE("(%p)->()\n", iface);
1580 EnterCriticalSection(This->crst);
1581 setALContext(This->ctx);
1583 alSourcePause(This->source);
1584 getALError();
1585 /* Mac OS X doesn't immediately report state change
1586 * if Play() is immediately called after Stop, this can be fatal,
1587 * the buffer would never be restarted
1589 do {
1590 state = AL_PAUSED;
1591 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1592 if(state != AL_PLAYING)
1593 break;
1594 Sleep(1);
1595 } while(1);
1597 This->isplaying = FALSE;
1599 popALContext();
1600 LeaveCriticalSection(This->crst);
1602 return S_OK;
1605 static HRESULT WINAPI DS8Buffer_Unlock(IDirectSoundBuffer8 *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
1607 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1608 DS8Data *buf = This->buffer;
1609 DWORD bufsize = buf->buf_size;
1610 DWORD_PTR ofs1, ofs2;
1611 DWORD_PTR boundary = (DWORD_PTR)buf->data;
1612 HRESULT hr;
1614 TRACE("(%p)->(%p, %u, %p, %u)\n", iface, ptr1, len1, ptr2, len2);
1616 EnterCriticalSection(This->crst);
1617 setALContext(This->ctx);
1619 This->buffer->locked = 0;
1620 hr = DSERR_INVALIDPARAM;
1622 /* Make sure offset is between boundary and boundary + bufsize */
1623 ofs1 = (DWORD_PTR)ptr1;
1624 ofs2 = (DWORD_PTR)ptr2;
1625 if(ofs1 < boundary)
1626 goto out;
1627 if(ofs2 && ofs2 != boundary)
1628 goto out;
1629 ofs1 -= boundary;
1630 ofs2 = 0;
1631 if(bufsize-ofs1 < len1 || len2 > ofs1)
1632 goto out;
1633 if(!ptr2)
1634 len2 = 0;
1636 hr = S_OK;
1637 if(!len1 && !len2)
1638 goto out;
1640 if(This->ExtAL->BufferDataStatic)
1641 goto out;
1643 if(This->ExtAL->BufferSubSamplesSOFT)
1645 WAVEFORMATEX *format = &buf->format.Format;
1647 ptr1 = (BYTE*)ptr1 - (ofs1%format->nBlockAlign);
1648 ofs1 /= format->nBlockAlign;
1649 len1 /= format->nBlockAlign;
1650 if(len1 > 0)
1651 This->ExtAL->BufferSubSamplesSOFT(buf->buffers[0], ofs1, len1,
1652 buf->in_chans, buf->in_type, ptr1);
1653 ptr2 = (BYTE*)ptr2 - (ofs2%format->nBlockAlign);
1654 ofs2 /= format->nBlockAlign;
1655 len2 /= format->nBlockAlign;
1656 if(len2 > 0)
1657 This->ExtAL->BufferSubSamplesSOFT(buf->buffers[0], ofs2, len2,
1658 buf->in_chans, buf->in_type, ptr2);
1659 getALError();
1661 else if(This->ExtAL->BufferSubData)
1663 WAVEFORMATEX *format = &buf->format.Format;
1665 len1 -= len1%format->nBlockAlign;
1666 if(len1 > 0)
1667 This->ExtAL->BufferSubData(buf->buffers[0], buf->buf_format, ptr1,
1668 ofs1, len1);
1669 len2 -= len2%format->nBlockAlign;
1670 if(len2 > 0)
1671 This->ExtAL->BufferSubData(buf->buffers[0], buf->buf_format, ptr2,
1672 ofs2, len2);
1673 getALError();
1675 else
1677 alBufferData(buf->buffers[0], buf->buf_format,
1678 buf->data, buf->buf_size,
1679 buf->format.Format.nSamplesPerSec);
1680 getALError();
1683 out:
1684 if(hr != S_OK)
1685 WARN("Invalid parameters (0x%lx,%u) (%p,%u,%p,%u)\n", boundary, bufsize, ptr1, len1, ptr2, len2);
1686 popALContext();
1687 LeaveCriticalSection(This->crst);
1688 return hr;
1691 static HRESULT WINAPI DS8Buffer_Restore(IDirectSoundBuffer8 *iface)
1693 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1694 HRESULT hr;
1696 TRACE("(%p)->()\n", iface);
1698 EnterCriticalSection(This->crst);
1699 if(This->primary->parent->prio_level < DSSCL_WRITEPRIMARY ||
1700 iface == This->primary->write_emu)
1702 This->bufferlost = 0;
1703 hr = S_OK;
1705 else
1706 hr = DSERR_BUFFERLOST;
1707 LeaveCriticalSection(This->crst);
1709 return hr;
1712 static HRESULT WINAPI DS8Buffer_SetFX(IDirectSoundBuffer8 *iface, DWORD fxcount, DSEFFECTDESC *desc, DWORD *rescodes)
1714 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1715 DWORD i;
1717 TRACE("(%p)->(%u, %p, %p)\n", This, fxcount, desc, rescodes);
1719 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFX))
1721 WARN("FX control not set\n");
1722 return DSERR_CONTROLUNAVAIL;
1725 if(fxcount == 0)
1727 if(desc || rescodes)
1729 WARN("Non-NULL desc and/or result pointer specified with no effects.\n");
1730 return DSERR_INVALIDPARAM;
1733 /* No effects; we can handle that */
1734 return DS_OK;
1737 if(!desc || !rescodes)
1739 WARN("NULL desc and/or result pointer specified.\n");
1740 return DSERR_INVALIDPARAM;
1743 /* We don't (currently) handle DSound effects */
1744 for(i = 0;i < fxcount;++i)
1746 FIXME("Cannot handle effect: %s\n", debugstr_guid(&desc[i].guidDSFXClass));
1747 rescodes[i] = DSFXR_FAILED;
1750 return DSERR_INVALIDPARAM;
1753 static HRESULT WINAPI DS8Buffer_AcquireResources(IDirectSoundBuffer8 *iface, DWORD flags, DWORD fxcount, DWORD *rescodes)
1755 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1757 TRACE("(%p)->(%u, %u, %p)\n", This, flags, fxcount, rescodes);
1759 /* effects aren't supported at the moment.. */
1760 if(fxcount != 0 || rescodes)
1762 WARN("Non-zero effect count and/or result pointer specified with no effects.\n");
1763 return DSERR_INVALIDPARAM;
1766 EnterCriticalSection(This->crst);
1767 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1769 This->buffer->dsbflags &= ~(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE);
1770 if((flags&DSBPLAY_LOCSOFTWARE))
1771 This->buffer->dsbflags |= DSBCAPS_LOCSOFTWARE;
1772 else
1773 This->buffer->dsbflags |= DSBCAPS_LOCHARDWARE;
1775 LeaveCriticalSection(This->crst);
1777 return S_OK;
1780 static HRESULT WINAPI DS8Buffer_GetObjectInPath(IDirectSoundBuffer8 *iface, REFGUID guid, DWORD idx, REFGUID rguidiface, void **ppv)
1782 FIXME("(%p)->(%s, %u, %s, %p) : stub!\n", iface, debugstr_guid(guid), idx, debugstr_guid(rguidiface), ppv);
1783 return E_NOTIMPL;
1786 static const IDirectSoundBuffer8Vtbl DS8Buffer_Vtbl =
1788 DS8Buffer_QueryInterface,
1789 DS8Buffer_AddRef,
1790 DS8Buffer_Release,
1791 DS8Buffer_GetCaps,
1792 DS8Buffer_GetCurrentPosition,
1793 DS8Buffer_GetFormat,
1794 DS8Buffer_GetVolume,
1795 DS8Buffer_GetPan,
1796 DS8Buffer_GetFrequency,
1797 DS8Buffer_GetStatus,
1798 DS8Buffer_Initialize,
1799 DS8Buffer_Lock,
1800 DS8Buffer_Play,
1801 DS8Buffer_SetCurrentPosition,
1802 DS8Buffer_SetFormat,
1803 DS8Buffer_SetVolume,
1804 DS8Buffer_SetPan,
1805 DS8Buffer_SetFrequency,
1806 DS8Buffer_Stop,
1807 DS8Buffer_Unlock,
1808 DS8Buffer_Restore,
1809 DS8Buffer_SetFX,
1810 DS8Buffer_AcquireResources,
1811 DS8Buffer_GetObjectInPath
1815 static HRESULT WINAPI DS8Buffer3D_QueryInterface(IDirectSound3DBuffer *iface, REFIID riid, void **ppv)
1817 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1818 return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
1821 static ULONG WINAPI DS8Buffer3D_AddRef(IDirectSound3DBuffer *iface)
1823 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1824 LONG ret;
1826 InterlockedIncrement(&This->all_ref);
1827 ret = InterlockedIncrement(&This->ds3d_ref);
1828 TRACE("new refcount %d\n", ret);
1830 return ret;
1833 static ULONG WINAPI DS8Buffer3D_Release(IDirectSound3DBuffer *iface)
1835 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1836 LONG ret;
1838 ret = InterlockedDecrement(&This->ds3d_ref);
1839 TRACE("new refcount %d\n", ret);
1840 if(InterlockedDecrement(&This->all_ref) == 0)
1841 DS8Buffer_Destroy(This);
1843 return ret;
1846 static HRESULT WINAPI DS8Buffer3D_GetAllParameters(IDirectSound3DBuffer *iface, DS3DBUFFER *ds3dbuffer)
1848 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1849 DS3DBUFFER ds3dbuf;
1850 HRESULT hr;
1852 TRACE("%p\n", This);
1854 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
1856 WARN("Invalid parameters %p %u\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
1857 return DSERR_INVALIDPARAM;
1859 ds3dbuf.dwSize = sizeof(ds3dbuf);
1861 EnterCriticalSection(This->crst);
1862 setALContext(This->ctx);
1864 hr = IDirectSound3DBuffer_GetPosition(iface, &ds3dbuf.vPosition);
1865 if(SUCCEEDED(hr))
1866 hr = IDirectSound3DBuffer_GetVelocity(iface, &ds3dbuf.vVelocity);
1867 if(SUCCEEDED(hr))
1868 hr = IDirectSound3DBuffer_GetConeAngles(iface, &ds3dbuf.dwInsideConeAngle, &ds3dbuf.dwOutsideConeAngle);
1869 if(SUCCEEDED(hr))
1870 hr = IDirectSound3DBuffer_GetConeOrientation(iface, &ds3dbuf.vConeOrientation);
1871 if(SUCCEEDED(hr))
1872 hr = IDirectSound3DBuffer_GetConeOutsideVolume(iface, &ds3dbuf.lConeOutsideVolume);
1873 if(SUCCEEDED(hr))
1874 hr = IDirectSound3DBuffer_GetMinDistance(iface, &ds3dbuf.flMinDistance);
1875 if(SUCCEEDED(hr))
1876 hr = IDirectSound3DBuffer_GetMaxDistance(iface, &ds3dbuf.flMaxDistance);
1877 if(SUCCEEDED(hr))
1878 hr = IDirectSound3DBuffer_GetMode(iface, &ds3dbuf.dwMode);
1879 if(SUCCEEDED(hr))
1880 memcpy(ds3dbuffer, &ds3dbuf, sizeof(ds3dbuf));
1882 popALContext();
1883 LeaveCriticalSection(This->crst);
1885 return hr;
1888 static HRESULT WINAPI DS8Buffer3D_GetConeAngles(IDirectSound3DBuffer *iface, DWORD *pdwInsideConeAngle, DWORD *pdwOutsideConeAngle)
1890 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1891 ALint inangle, outangle;
1893 TRACE("(%p)->(%p, %p)\n", This, pdwInsideConeAngle, pdwOutsideConeAngle);
1894 if(!pdwInsideConeAngle || !pdwOutsideConeAngle)
1896 WARN("Invalid pointers (%p, %p)\n", pdwInsideConeAngle, pdwOutsideConeAngle);
1897 return DSERR_INVALIDPARAM;
1900 EnterCriticalSection(This->crst);
1901 setALContext(This->ctx);
1903 alGetSourcei(This->source, AL_CONE_INNER_ANGLE, &inangle);
1904 alGetSourcei(This->source, AL_CONE_OUTER_ANGLE, &outangle);
1905 getALError();
1906 *pdwInsideConeAngle = inangle;
1907 *pdwOutsideConeAngle = outangle;
1909 popALContext();
1910 LeaveCriticalSection(This->crst);
1912 return S_OK;
1915 static HRESULT WINAPI DS8Buffer3D_GetConeOrientation(IDirectSound3DBuffer *iface, D3DVECTOR *orient)
1917 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1918 ALfloat dir[3];
1920 TRACE("(%p)->(%p)\n", This, orient);
1921 if(!orient)
1923 WARN("Invalid pointer\n");
1924 return DSERR_INVALIDPARAM;
1927 EnterCriticalSection(This->crst);
1928 setALContext(This->ctx);
1930 alGetSourcefv(This->source, AL_DIRECTION, dir);
1931 getALError();
1932 orient->x = dir[0];
1933 orient->y = dir[1];
1934 orient->z = -dir[2];
1936 popALContext();
1937 LeaveCriticalSection(This->crst);
1939 return S_OK;
1942 static HRESULT WINAPI DS8Buffer3D_GetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG *vol)
1944 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1945 ALfloat gain;
1947 TRACE("(%p)->(%p)\n", This, vol);
1948 if(!vol)
1950 WARN("Invalid pointer\n");
1951 return DSERR_INVALIDPARAM;
1954 EnterCriticalSection(This->crst);
1955 setALContext(This->ctx);
1957 alGetSourcef(This->source, AL_CONE_OUTER_GAIN, &gain);
1958 getALError();
1959 *vol = gain_to_mB(gain);
1960 *vol = max(*vol, DSBVOLUME_MIN);
1961 *vol = min(*vol, DSBVOLUME_MAX);
1963 popALContext();
1964 LeaveCriticalSection(This->crst);
1965 return S_OK;
1968 static HRESULT WINAPI DS8Buffer3D_GetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE *maxdist)
1970 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1971 ALfloat dist;
1973 TRACE("(%p)->(%p)\n", This, maxdist);
1974 if(!maxdist)
1976 WARN("Invalid pointer\n");
1977 return DSERR_INVALIDPARAM;
1980 EnterCriticalSection(This->crst);
1981 setALContext(This->ctx);
1983 alGetSourcef(This->source, AL_MAX_DISTANCE, &dist);
1984 getALError();
1985 *maxdist = dist;
1987 popALContext();
1988 LeaveCriticalSection(This->crst);
1990 return S_OK;
1993 static HRESULT WINAPI DS8Buffer3D_GetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE *mindist)
1995 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1996 ALfloat dist;
1998 TRACE("(%p)->(%p)\n", This, mindist);
1999 if(!mindist)
2001 WARN("Invalid pointer\n");
2002 return DSERR_INVALIDPARAM;
2005 EnterCriticalSection(This->crst);
2006 setALContext(This->ctx);
2008 alGetSourcef(This->source, AL_REFERENCE_DISTANCE, &dist);
2009 getALError();
2010 *mindist = dist;
2012 popALContext();
2013 LeaveCriticalSection(This->crst);
2015 return S_OK;
2018 static HRESULT WINAPI DS8Buffer3D_GetMode(IDirectSound3DBuffer *iface, DWORD *mode)
2020 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2022 TRACE("(%p)->(%p)\n", This, mode);
2023 if(!mode)
2025 WARN("Invalid pointer\n");
2026 return DSERR_INVALIDPARAM;
2029 EnterCriticalSection(This->crst);
2030 *mode = This->ds3dmode;
2031 LeaveCriticalSection(This->crst);
2033 return S_OK;
2036 static HRESULT WINAPI DS8Buffer3D_GetPosition(IDirectSound3DBuffer *iface, D3DVECTOR *pos)
2038 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2039 ALfloat alpos[3];
2041 TRACE("(%p)->(%p)\n", This, pos);
2042 if(!pos)
2044 WARN("Invalid pointer\n");
2045 return DSERR_INVALIDPARAM;
2048 EnterCriticalSection(This->crst);
2049 setALContext(This->ctx);
2051 alGetSourcefv(This->source, AL_POSITION, alpos);
2052 getALError();
2053 pos->x = alpos[0];
2054 pos->y = alpos[1];
2055 pos->z = -alpos[2];
2057 popALContext();
2058 LeaveCriticalSection(This->crst);
2060 return S_OK;
2063 static HRESULT WINAPI DS8Buffer3D_GetVelocity(IDirectSound3DBuffer *iface, D3DVECTOR *vel)
2065 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2066 ALfloat alvel[3];
2068 TRACE("(%p)->(%p)\n", This, vel);
2069 if(!vel)
2071 WARN("Invalid pointer\n");
2072 return DSERR_INVALIDPARAM;
2075 EnterCriticalSection(This->crst);
2076 setALContext(This->ctx);
2078 alGetSourcefv(This->source, AL_VELOCITY, alvel);
2079 getALError();
2080 vel->x = alvel[0];
2081 vel->y = alvel[1];
2082 vel->z = -alvel[2];
2084 popALContext();
2085 LeaveCriticalSection(This->crst);
2087 return S_OK;
2090 static HRESULT WINAPI DS8Buffer3D_SetAllParameters(IDirectSound3DBuffer *iface, const DS3DBUFFER *ds3dbuffer, DWORD apply)
2092 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2093 TRACE("(%p)->(%p, %u)\n", This, ds3dbuffer, apply);
2095 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
2097 WARN("Invalid DS3DBUFFER (%p, %u)\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
2098 return DSERR_INVALIDPARAM;
2101 if(ds3dbuffer->dwInsideConeAngle > DS3D_MAXCONEANGLE ||
2102 ds3dbuffer->dwOutsideConeAngle > DS3D_MAXCONEANGLE)
2104 WARN("Invalid cone angles (%u, %u)\n", ds3dbuffer->dwInsideConeAngle,
2105 ds3dbuffer->dwOutsideConeAngle);
2106 return DSERR_INVALIDPARAM;
2109 if(ds3dbuffer->lConeOutsideVolume > DSBVOLUME_MAX ||
2110 ds3dbuffer->lConeOutsideVolume < DSBVOLUME_MIN)
2112 WARN("Invalid cone outside volume (%d)\n", ds3dbuffer->lConeOutsideVolume);
2113 return DSERR_INVALIDPARAM;
2116 if(ds3dbuffer->flMaxDistance < 0.0f)
2118 WARN("Invalid max distance (%f)\n", ds3dbuffer->flMaxDistance);
2119 return DSERR_INVALIDPARAM;
2122 if(ds3dbuffer->flMinDistance < 0.0f)
2124 WARN("Invalid min distance (%f)\n", ds3dbuffer->flMinDistance);
2125 return DSERR_INVALIDPARAM;
2128 if(ds3dbuffer->dwMode != DS3DMODE_NORMAL &&
2129 ds3dbuffer->dwMode != DS3DMODE_HEADRELATIVE &&
2130 ds3dbuffer->dwMode != DS3DMODE_DISABLE)
2132 WARN("Invalid mode (%u)\n", ds3dbuffer->dwMode);
2133 return DSERR_INVALIDPARAM;
2136 EnterCriticalSection(This->crst);
2137 setALContext(This->ctx);
2138 IDirectSound3DBuffer_SetPosition(iface, ds3dbuffer->vPosition.x, ds3dbuffer->vPosition.y, ds3dbuffer->vPosition.z, apply);
2139 IDirectSound3DBuffer_SetVelocity(iface, ds3dbuffer->vVelocity.x, ds3dbuffer->vVelocity.y, ds3dbuffer->vVelocity.z, apply);
2140 IDirectSound3DBuffer_SetConeAngles(iface, ds3dbuffer->dwInsideConeAngle, ds3dbuffer->dwOutsideConeAngle, apply);
2141 IDirectSound3DBuffer_SetConeOrientation(iface, ds3dbuffer->vConeOrientation.x, ds3dbuffer->vConeOrientation.y, ds3dbuffer->vConeOrientation.z, apply);
2142 IDirectSound3DBuffer_SetConeOutsideVolume(iface, ds3dbuffer->lConeOutsideVolume, apply);
2143 IDirectSound3DBuffer_SetMinDistance(iface, ds3dbuffer->flMinDistance, apply);
2144 IDirectSound3DBuffer_SetMaxDistance(iface, ds3dbuffer->flMaxDistance, apply);
2145 IDirectSound3DBuffer_SetMode(iface, ds3dbuffer->dwMode, apply);
2146 popALContext();
2147 LeaveCriticalSection(This->crst);
2149 return S_OK;
2152 static HRESULT WINAPI DS8Buffer3D_SetConeAngles(IDirectSound3DBuffer *iface, DWORD dwInsideConeAngle, DWORD dwOutsideConeAngle, DWORD apply)
2154 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2156 TRACE("(%p)->(%u, %u, %u)\n", This, dwInsideConeAngle, dwOutsideConeAngle, apply);
2157 if(dwInsideConeAngle > DS3D_MAXCONEANGLE ||
2158 dwOutsideConeAngle > DS3D_MAXCONEANGLE)
2160 WARN("Invalid cone angles (%u, %u)\n", dwInsideConeAngle, dwOutsideConeAngle);
2161 return DSERR_INVALIDPARAM;
2164 EnterCriticalSection(This->crst);
2165 if(apply == DS3D_DEFERRED)
2167 This->ds3dbuffer.dwInsideConeAngle = dwInsideConeAngle;
2168 This->ds3dbuffer.dwOutsideConeAngle = dwOutsideConeAngle;
2169 This->dirty.bit.cone_angles = 1;
2171 else
2173 setALContext(This->ctx);
2174 alSourcei(This->source, AL_CONE_INNER_ANGLE, dwInsideConeAngle);
2175 alSourcei(This->source, AL_CONE_OUTER_ANGLE, dwOutsideConeAngle);
2176 getALError();
2177 popALContext();
2179 LeaveCriticalSection(This->crst);
2181 return S_OK;
2184 static HRESULT WINAPI DS8Buffer3D_SetConeOrientation(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2186 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2188 TRACE("(%p)->(%f, %f, %f, %u)\n", This, x, y, z, apply);
2190 EnterCriticalSection(This->crst);
2191 if(apply == DS3D_DEFERRED)
2193 This->ds3dbuffer.vConeOrientation.x = x;
2194 This->ds3dbuffer.vConeOrientation.y = y;
2195 This->ds3dbuffer.vConeOrientation.z = z;
2196 This->dirty.bit.cone_orient = 1;
2198 else
2200 setALContext(This->ctx);
2201 alSource3f(This->source, AL_DIRECTION, x, y, -z);
2202 getALError();
2203 popALContext();
2205 LeaveCriticalSection(This->crst);
2207 return S_OK;
2210 static HRESULT WINAPI DS8Buffer3D_SetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG vol, DWORD apply)
2212 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2214 TRACE("(%p)->(%u, %u)\n", This, vol, apply);
2215 if(vol < DSBVOLUME_MIN || vol > DSBVOLUME_MAX)
2217 WARN("Invalid volume (%u)\n", vol);
2218 return DSERR_INVALIDPARAM;
2221 EnterCriticalSection(This->crst);
2222 if(apply == DS3D_DEFERRED)
2224 This->ds3dbuffer.lConeOutsideVolume = vol;
2225 This->dirty.bit.cone_outsidevolume = 1;
2227 else
2229 setALContext(This->ctx);
2230 alSourcef(This->source, AL_CONE_OUTER_GAIN, mB_to_gain(vol));
2231 getALError();
2232 popALContext();
2234 LeaveCriticalSection(This->crst);
2236 return S_OK;
2239 static HRESULT WINAPI DS8Buffer3D_SetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE maxdist, DWORD apply)
2241 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2243 TRACE("(%p)->(%f, %u)\n", This, maxdist, apply);
2244 if(maxdist < 0.0f)
2246 WARN("Invalid max distance (%f)\n", maxdist);
2247 return DSERR_INVALIDPARAM;
2250 EnterCriticalSection(This->crst);
2251 if(apply == DS3D_DEFERRED)
2253 This->ds3dbuffer.flMaxDistance = maxdist;
2254 This->dirty.bit.max_distance = 1;
2256 else
2258 setALContext(This->ctx);
2259 alSourcef(This->source, AL_MAX_DISTANCE, maxdist);
2260 getALError();
2261 popALContext();
2263 LeaveCriticalSection(This->crst);
2265 return S_OK;
2268 static HRESULT WINAPI DS8Buffer3D_SetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE mindist, DWORD apply)
2270 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2272 TRACE("(%p)->(%f, %u)\n", This, mindist, apply);
2273 if(mindist < 0.0f)
2275 WARN("Invalid min distance (%f)\n", mindist);
2276 return DSERR_INVALIDPARAM;
2279 EnterCriticalSection(This->crst);
2280 if(apply == DS3D_DEFERRED)
2282 This->ds3dbuffer.flMinDistance = mindist;
2283 This->dirty.bit.min_distance = 1;
2285 else
2287 setALContext(This->ctx);
2288 alSourcef(This->source, AL_REFERENCE_DISTANCE, mindist);
2289 getALError();
2290 popALContext();
2292 LeaveCriticalSection(This->crst);
2294 return S_OK;
2297 static HRESULT WINAPI DS8Buffer3D_SetMode(IDirectSound3DBuffer *iface, DWORD mode, DWORD apply)
2299 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2301 TRACE("(%p)->(%u, %u)\n", This, mode, apply);
2302 if(mode != DS3DMODE_NORMAL && mode != DS3DMODE_HEADRELATIVE &&
2303 mode != DS3DMODE_DISABLE)
2305 WARN("Invalid mode (%u)\n", mode);
2306 return DSERR_INVALIDPARAM;
2309 EnterCriticalSection(This->crst);
2310 if(apply == DS3D_DEFERRED)
2312 This->ds3dbuffer.dwMode = mode;
2313 This->dirty.bit.mode = 1;
2315 else
2317 setALContext(This->ctx);
2318 alSourcei(This->source, AL_SOURCE_RELATIVE,
2319 (mode != DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE);
2320 alSourcef(This->source, AL_ROLLOFF_FACTOR,
2321 (mode == DS3DMODE_DISABLE) ? 0.0f : This->primary->rollofffactor);
2322 This->ds3dmode = mode;
2323 getALError();
2324 popALContext();
2326 LeaveCriticalSection(This->crst);
2328 return S_OK;
2331 static HRESULT WINAPI DS8Buffer3D_SetPosition(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2333 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2335 TRACE("(%p)->(%f, %f, %f, %u)\n", This, x, y, z, apply);
2337 EnterCriticalSection(This->crst);
2338 if(apply == DS3D_DEFERRED)
2340 This->ds3dbuffer.vPosition.x = x;
2341 This->ds3dbuffer.vPosition.y = y;
2342 This->ds3dbuffer.vPosition.z = z;
2343 This->dirty.bit.pos = 1;
2345 else
2347 setALContext(This->ctx);
2348 alSource3f(This->source, AL_POSITION, x, y, -z);
2349 getALError();
2350 popALContext();
2352 LeaveCriticalSection(This->crst);
2354 return S_OK;
2357 static HRESULT WINAPI DS8Buffer3D_SetVelocity(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2359 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2361 TRACE("(%p)->(%f, %f, %f, %u)\n", This, x, y, z, apply);
2363 EnterCriticalSection(This->crst);
2364 if(apply == DS3D_DEFERRED)
2366 This->ds3dbuffer.vVelocity.x = x;
2367 This->ds3dbuffer.vVelocity.y = y;
2368 This->ds3dbuffer.vVelocity.z = z;
2369 This->dirty.bit.vel = 1;
2371 else
2373 setALContext(This->ctx);
2374 alSource3f(This->source, AL_VELOCITY, x, y, -z);
2375 getALError();
2376 popALContext();
2378 LeaveCriticalSection(This->crst);
2380 return S_OK;
2383 static const IDirectSound3DBufferVtbl DS8Buffer3d_Vtbl =
2385 DS8Buffer3D_QueryInterface,
2386 DS8Buffer3D_AddRef,
2387 DS8Buffer3D_Release,
2388 DS8Buffer3D_GetAllParameters,
2389 DS8Buffer3D_GetConeAngles,
2390 DS8Buffer3D_GetConeOrientation,
2391 DS8Buffer3D_GetConeOutsideVolume,
2392 DS8Buffer3D_GetMaxDistance,
2393 DS8Buffer3D_GetMinDistance,
2394 DS8Buffer3D_GetMode,
2395 DS8Buffer3D_GetPosition,
2396 DS8Buffer3D_GetVelocity,
2397 DS8Buffer3D_SetAllParameters,
2398 DS8Buffer3D_SetConeAngles,
2399 DS8Buffer3D_SetConeOrientation,
2400 DS8Buffer3D_SetConeOutsideVolume,
2401 DS8Buffer3D_SetMaxDistance,
2402 DS8Buffer3D_SetMinDistance,
2403 DS8Buffer3D_SetMode,
2404 DS8Buffer3D_SetPosition,
2405 DS8Buffer3D_SetVelocity
2409 static HRESULT WINAPI DS8BufferNot_QueryInterface(IDirectSoundNotify *iface, REFIID riid, void **ppv)
2411 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2412 return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2415 static ULONG WINAPI DS8BufferNot_AddRef(IDirectSoundNotify *iface)
2417 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2418 LONG ret;
2420 InterlockedIncrement(&This->all_ref);
2421 ret = InterlockedIncrement(&This->not_ref);
2422 TRACE("new refcount %d\n", ret);
2424 return ret;
2427 static ULONG WINAPI DS8BufferNot_Release(IDirectSoundNotify *iface)
2429 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2430 LONG ret;
2432 ret = InterlockedDecrement(&This->not_ref);
2433 TRACE("new refcount %d\n", ret);
2434 if(InterlockedDecrement(&This->all_ref) == 0)
2435 DS8Buffer_Destroy(This);
2437 return ret;
2440 static HRESULT WINAPI DS8BufferNot_SetNotificationPositions(IDirectSoundNotify *iface, DWORD count, const DSBPOSITIONNOTIFY *notifications)
2442 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2443 DSBPOSITIONNOTIFY *nots;
2444 DWORD state;
2445 HRESULT hr;
2447 EnterCriticalSection(This->crst);
2448 hr = DSERR_INVALIDPARAM;
2449 if(count && !notifications)
2450 goto out;
2452 hr = IDirectSoundBuffer8_GetStatus(&This->IDirectSoundBuffer8_iface, &state);
2453 if(FAILED(hr))
2454 goto out;
2456 hr = DSERR_INVALIDCALL;
2457 if((state&DSBSTATUS_PLAYING))
2458 goto out;
2460 if(!count)
2462 HeapFree(GetProcessHeap(), 0, This->notify);
2463 This->notify = 0;
2464 This->nnotify = 0;
2465 hr = S_OK;
2467 else
2469 DWORD i;
2471 hr = DSERR_INVALIDPARAM;
2472 for(i = 0;i < count;++i)
2474 if(notifications[i].dwOffset >= This->buffer->buf_size &&
2475 notifications[i].dwOffset != (DWORD)DSBPN_OFFSETSTOP)
2476 goto out;
2479 hr = E_OUTOFMEMORY;
2480 nots = HeapAlloc(GetProcessHeap(), 0, count*sizeof(*nots));
2481 if(!nots)
2482 goto out;
2483 memcpy(nots, notifications, count*sizeof(*nots));
2485 HeapFree(GetProcessHeap(), 0, This->notify);
2486 This->notify = nots;
2487 This->nnotify = count;
2489 hr = S_OK;
2492 out:
2493 LeaveCriticalSection(This->crst);
2494 return hr;
2497 static const IDirectSoundNotifyVtbl DS8BufferNot_Vtbl =
2499 DS8BufferNot_QueryInterface,
2500 DS8BufferNot_AddRef,
2501 DS8BufferNot_Release,
2502 DS8BufferNot_SetNotificationPositions
2506 static HRESULT WINAPI DS8BufferProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
2508 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2509 return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2512 static ULONG WINAPI DS8BufferProp_AddRef(IKsPropertySet *iface)
2514 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2515 LONG ret;
2517 InterlockedIncrement(&This->all_ref);
2518 ret = InterlockedIncrement(&This->prop_ref);
2519 TRACE("new refcount %d\n", ret);
2521 return ret;
2524 static ULONG WINAPI DS8BufferProp_Release(IKsPropertySet *iface)
2526 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2527 LONG ret;
2529 ret = InterlockedDecrement(&This->prop_ref);
2530 TRACE("new refcount %d\n", ret);
2531 if(InterlockedDecrement(&This->all_ref) == 0)
2532 DS8Buffer_Destroy(This);
2534 return ret;
2537 /* NOTE: Due to some apparent quirks in DSound, the listener properties are
2538 handled through secondary buffers. */
2539 static HRESULT WINAPI DS8BufferProp_Get(IKsPropertySet *iface,
2540 REFGUID guidPropSet, ULONG dwPropID,
2541 LPVOID pInstanceData, ULONG cbInstanceData,
2542 LPVOID pPropData, ULONG cbPropData,
2543 PULONG pcbReturned)
2545 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2546 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2548 TRACE("(%p)->(%s, %u, %p, %u, %p, %u, %p)\n", iface, debugstr_guid(guidPropSet),
2549 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData, pcbReturned);
2551 if(!pcbReturned)
2552 return E_POINTER;
2553 *pcbReturned = 0;
2555 #if 0
2556 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2559 else
2560 #endif
2562 /* Not a known buffer/source property. Pass it to the listener */
2563 hr = IKsPropertySet_Get(&This->primary->IKsPropertySet_iface, guidPropSet,
2564 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData,
2565 pcbReturned);
2568 return hr;
2571 static HRESULT WINAPI DS8BufferProp_Set(IKsPropertySet *iface,
2572 REFGUID guidPropSet, ULONG dwPropID,
2573 LPVOID pInstanceData, ULONG cbInstanceData,
2574 LPVOID pPropData, ULONG cbPropData)
2576 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2577 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2579 TRACE("(%p)->(%s, %u, %p, %u, %p, %u)\n", iface, debugstr_guid(guidPropSet),
2580 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData);
2582 #if 0
2583 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2586 else
2587 #endif
2589 /* Not a known buffer/source property. Pass it to the listener */
2590 hr = IKsPropertySet_Set(&This->primary->IKsPropertySet_iface, guidPropSet,
2591 dwPropID, pInstanceData, cbInstanceData, pPropData,
2592 cbPropData);
2595 return hr;
2598 static HRESULT WINAPI DS8BufferProp_QuerySupport(IKsPropertySet *iface,
2599 REFGUID guidPropSet, ULONG dwPropID,
2600 PULONG pTypeSupport)
2602 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2603 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2605 TRACE("(%p)->(%s, %u, %p)\n", iface, debugstr_guid(guidPropSet), dwPropID, pTypeSupport);
2607 if(!pTypeSupport)
2608 return E_POINTER;
2609 *pTypeSupport = 0;
2611 #if 0
2612 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2615 else
2616 #endif
2618 /* Not a known buffer/source property. Pass it to the listener */
2619 hr = IKsPropertySet_QuerySupport(&This->primary->IKsPropertySet_iface,
2620 guidPropSet, dwPropID, pTypeSupport);
2623 return hr;
2626 static const IKsPropertySetVtbl DS8BufferProp_Vtbl =
2628 DS8BufferProp_QueryInterface,
2629 DS8BufferProp_AddRef,
2630 DS8BufferProp_Release,
2631 DS8BufferProp_Get,
2632 DS8BufferProp_Set,
2633 DS8BufferProp_QuerySupport