Protect the primary buffer when modifying it during secondary buffer destruction
[dsound-openal.git] / buffer.c
blob26e97f8374f196bc3d28c33f07d36b8b7f8ad65e
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 void CALLBACK DS8Buffer_timer(UINT timerID, UINT msg, DWORD_PTR dwUser,
85 DWORD_PTR dw1, DWORD_PTR dw2)
87 (void)timerID;
88 (void)msg;
89 (void)dw1;
90 (void)dw2;
91 PostThreadMessageA(dwUser, WM_USER, 0, 0);
94 static void DS8Buffer_starttimer(DS8Primary *prim)
96 DWORD triggertime, res = DS_TIME_RES;
97 ALint refresh = FAKE_REFRESH_COUNT;
98 TIMECAPS time;
100 if(prim->timer_id)
101 return;
103 timeGetDevCaps(&time, sizeof(TIMECAPS));
105 alcGetIntegerv(prim->parent->device, ALC_REFRESH, 1, &refresh);
106 getALCError(prim->parent->device);
108 triggertime = 1000 / refresh / 2;
109 if(triggertime < time.wPeriodMin)
110 triggertime = time.wPeriodMin;
111 TRACE("Calling timer every %u ms for %i refreshes per second\n", triggertime, refresh);
113 if (res < time.wPeriodMin)
114 res = time.wPeriodMin;
115 if (timeBeginPeriod(res) == TIMERR_NOCANDO)
116 WARN("Could not set minimum resolution, don't expect sound\n");
118 prim->timer_res = res;
119 prim->timer_id = timeSetEvent(triggertime, res, DS8Buffer_timer, prim->thread_id, TIME_PERIODIC|TIME_KILL_SYNCHRONOUS);
122 /* Should be called with critsect held and context set.. */
123 static void DS8Buffer_addnotify(DS8Buffer *buf)
125 DS8Buffer **list;
126 DWORD i;
128 list = buf->primary->notifies;
129 for(i = 0; i < buf->primary->nnotifies; ++i)
131 if(buf == list[i])
133 ERR("Buffer %p already in notification list\n", buf);
134 return;
137 if(buf->primary->nnotifies == buf->primary->sizenotifies)
139 list = HeapReAlloc(GetProcessHeap(), 0, list, (buf->primary->nnotifies + 1) * sizeof(*list));
140 if(!list)
141 return;
142 buf->primary->sizenotifies++;
144 list[buf->primary->nnotifies++] = buf;
145 buf->primary->notifies = list;
149 static const char *get_fmtstr_PCM(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out, ALenum *in_chans, ALenum *in_type)
151 out->Format = *format;
152 out->Format.cbSize = 0;
154 if(format->wBitsPerSample == 8)
156 *in_type = AL_UNSIGNED_BYTE;
157 switch(format->nChannels)
159 case 1: *in_chans = AL_MONO;
160 return "AL_FORMAT_MONO8";
161 case 2: *in_chans = AL_STEREO;
162 return "AL_FORMAT_STEREO8";
163 case 4: *in_chans = AL_QUAD;
164 return "AL_FORMAT_QUAD8";
165 case 6: *in_chans = AL_5POINT1;
166 return "AL_FORMAT_51CHN8";
167 case 7: *in_chans = AL_6POINT1;
168 return "AL_FORMAT_61CHN8";
169 case 8: *in_chans = AL_7POINT1;
170 return "AL_FORMAT_71CHN8";
171 default: break;
174 else if(format->wBitsPerSample == 16)
176 *in_type = AL_SHORT;
177 switch(format->nChannels)
179 case 1: *in_chans = AL_MONO;
180 return "AL_FORMAT_MONO16";
181 case 2: *in_chans = AL_STEREO;
182 return "AL_FORMAT_STEREO16";
183 case 4: *in_chans = AL_QUAD;
184 return "AL_FORMAT_QUAD16";
185 case 6: *in_chans = AL_5POINT1;
186 return "AL_FORMAT_51CHN16";
187 case 7: *in_chans = AL_6POINT1;
188 return "AL_FORMAT_61CHN16";
189 case 8: *in_chans = AL_7POINT1;
190 return "AL_FORMAT_71CHN16";
191 default: break;
194 #if 0 /* Will cause incorrect byte offsets */
195 else if(format->wBitsPerSample == 24 && prim->SupportedExt[SOFT_BUFFER_SAMPLES])
197 *in_type = AL_BYTE3;
198 switch(format->nChannels)
200 case 1: *in_chans = AL_MONO;
201 return "AL_MONO32F";
202 case 2: *in_chans = AL_STEREO;
203 return "AL_STEREO32F";
204 case 4: *in_chans = AL_QUAD;
205 return "AL_QUAD32F";
206 case 6: *in_chans = AL_5POINT1;
207 return "AL_5POINT1_32F";
208 case 7: *in_chans = AL_6POINT1;
209 return "AL_6POINT1_32F";
210 case 8: *in_chans = AL_7POINT1;
211 return "AL_7POINT1_32F";
212 default: break;
215 #endif
216 else if(format->wBitsPerSample == 32 && prim->SupportedExt[SOFT_BUFFER_SAMPLES])
218 *in_type = AL_INT;
219 switch(format->nChannels)
221 case 1: *in_chans = AL_MONO;
222 return "AL_MONO32F";
223 case 2: *in_chans = AL_STEREO;
224 return "AL_STEREO32F";
225 case 4: *in_chans = AL_QUAD;
226 return "AL_QUAD32F";
227 case 6: *in_chans = AL_5POINT1;
228 return "AL_5POINT1_32F";
229 case 7: *in_chans = AL_6POINT1;
230 return "AL_6POINT1_32F";
231 case 8: *in_chans = AL_7POINT1;
232 return "AL_7POINT1_32F";
233 default: break;
237 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
238 format->wBitsPerSample, format->nChannels);
239 return NULL;
242 static const char *get_fmtstr_FLOAT(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out, ALenum *in_chans, ALenum *in_type)
244 out->Format = *format;
245 out->Format.cbSize = 0;
247 if(format->wBitsPerSample == 32 &&
248 (prim->SupportedExt[EXT_FLOAT32] || prim->SupportedExt[SOFT_BUFFER_SAMPLES]))
250 *in_type = AL_FLOAT;
251 switch(format->nChannels)
253 case 1: *in_chans = AL_MONO;
254 return "AL_FORMAT_MONO_FLOAT32";
255 case 2: *in_chans = AL_STEREO;
256 return "AL_FORMAT_STEREO_FLOAT32";
257 case 4: *in_chans = AL_QUAD;
258 return "AL_FORMAT_QUAD32";
259 case 6: *in_chans = AL_5POINT1;
260 return "AL_FORMAT_51CHN32";
261 case 7: *in_chans = AL_6POINT1;
262 return "AL_FORMAT_61CHN32";
263 case 8: *in_chans = AL_7POINT1;
264 return "AL_FORMAT_71CHN32";
265 default: break;
268 #if 0 /* Will cause incorrect byte offsets */
269 else if(format->wBitsPerSample == 64 && prim->SupportedExt[SOFT_BUFFER_SAMPLES])
271 *in_type = AL_DOUBLE;
272 switch(format->nChannels)
274 case 1: *in_chans = AL_MONO;
275 return "AL_MONO32F";
276 case 2: *in_chans = AL_STEREO;
277 return "AL_STEREO32F";
278 case 4: *in_chans = AL_QUAD;
279 return "AL_QUAD32F";
280 case 6: *in_chans = AL_5POINT1;
281 return "AL_5POINT1_32F";
282 case 7: *in_chans = AL_6POINT1;
283 return "AL_6POINT1_32F";
284 case 8: *in_chans = AL_7POINT1;
285 return "AL_7POINT1_32F";
286 default: break;
289 #endif
291 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
292 format->wBitsPerSample, format->nChannels);
293 return NULL;
296 /* Speaker configs */
297 #define MONO SPEAKER_FRONT_CENTER
298 #define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)
299 #define REAR (SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
300 #define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
301 #define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
302 #define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
303 #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)
305 static const char *get_fmtstr_EXT(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out, ALenum *in_chans, ALenum *in_type)
307 *out = *(const WAVEFORMATEXTENSIBLE*)format;
308 out->Format.cbSize = sizeof(*out) - sizeof(out->Format);
310 if(!out->Samples.wValidBitsPerSample)
311 out->Samples.wValidBitsPerSample = out->Format.wBitsPerSample;
312 else if(out->Samples.wValidBitsPerSample != out->Format.wBitsPerSample)
314 FIXME("Padded samples not supported (%u of %u)\n", out->Samples.wValidBitsPerSample, out->Format.wBitsPerSample);
315 return NULL;
318 if(out->dwChannelMask != MONO && out->dwChannelMask != STEREO &&
319 !prim->SupportedExt[EXT_MCFORMATS] && !prim->SupportedExt[SOFT_BUFFER_SAMPLES])
321 WARN("Multi-channel not available\n");
322 return NULL;
325 if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
327 if(out->Samples.wValidBitsPerSample == 8)
329 *in_type = AL_UNSIGNED_BYTE;
330 switch(out->dwChannelMask)
332 case MONO: *in_chans = AL_MONO;
333 return "AL_FORMAT_MONO8";
334 case STEREO: *in_chans = AL_STEREO;
335 return "AL_FORMAT_STEREO8";
336 case REAR: *in_chans = AL_REAR;
337 return "AL_FORMAT_REAR8";
338 case QUAD: *in_chans = AL_QUAD;
339 return "AL_FORMAT_QUAD8";
340 case X5DOT1: *in_chans = AL_5POINT1;
341 return "AL_FORMAT_51CHN8";
342 case X6DOT1: *in_chans = AL_6POINT1;
343 return "AL_FORMAT_61CHN8";
344 case X7DOT1: *in_chans = AL_7POINT1;
345 return "AL_FORMAT_71CHN8";
346 default: break;
349 else if(out->Samples.wValidBitsPerSample == 16)
351 *in_type = AL_SHORT;
352 switch(out->dwChannelMask)
354 case MONO: *in_chans = AL_MONO;
355 return "AL_FORMAT_MONO16";
356 case STEREO: *in_chans = AL_STEREO;
357 return "AL_FORMAT_STEREO16";
358 case REAR: *in_chans = AL_REAR;
359 return "AL_FORMAT_REAR16";
360 case QUAD: *in_chans = AL_QUAD;
361 return "AL_FORMAT_QUAD16";
362 case X5DOT1: *in_chans = AL_5POINT1;
363 return "AL_FORMAT_51CHN16";
364 case X6DOT1: *in_chans = AL_6POINT1;
365 return "AL_FORMAT_61CHN16";
366 case X7DOT1: *in_chans = AL_7POINT1;
367 return "AL_FORMAT_71CHN16";
368 default: break;
371 #if 0
372 else if(out->Samples.wValidBitsPerSample == 24 &&
373 prim->SupportedExt[SOFT_BUFFER_SAMPLES])
375 *in_type = AL_BYTE3;
376 switch(out->dwChannelMask)
378 case MONO: *in_chans = AL_MONO;
379 return "AL_MONO32F";
380 case STEREO: *in_chans = AL_STEREO;
381 return "AL_STEREO32F";
382 case REAR: *in_chans = AL_REAR;
383 return "AL_REAR32F";
384 case QUAD: *in_chans = AL_QUAD;
385 return "AL_QUAD32F";
386 case X5DOT1: *in_chans = AL_5POINT1;
387 return "AL_5POINT1_32F";
388 case X6DOT1: *in_chans = AL_6POINT1;
389 return "AL_6POINT1_32F";
390 case X7DOT1: *in_chans = AL_7POINT1;
391 return "AL_7POINT1_32F";
392 default: break;
395 #endif
396 else if(out->Samples.wValidBitsPerSample == 32 &&
397 prim->SupportedExt[SOFT_BUFFER_SAMPLES])
399 *in_type = AL_INT;
400 switch(out->dwChannelMask)
402 case MONO: *in_chans = AL_MONO;
403 return "AL_MONO32F";
404 case STEREO: *in_chans = AL_STEREO;
405 return "AL_STEREO32F";
406 case REAR: *in_chans = AL_REAR;
407 return "AL_REAR32F";
408 case QUAD: *in_chans = AL_QUAD;
409 return "AL_QUAD32F";
410 case X5DOT1: *in_chans = AL_5POINT1;
411 return "AL_5POINT1_32F";
412 case X6DOT1: *in_chans = AL_6POINT1;
413 return "AL_6POINT1_32F";
414 case X7DOT1: *in_chans = AL_7POINT1;
415 return "AL_7POINT1_32F";
416 default: break;
420 FIXME("Could not get OpenAL PCM format (%d-bit, channelmask %#x)\n",
421 out->Samples.wValidBitsPerSample, out->dwChannelMask);
422 return NULL;
424 else if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) &&
425 (prim->SupportedExt[EXT_FLOAT32] || prim->SupportedExt[SOFT_BUFFER_SAMPLES]))
427 if(out->Samples.wValidBitsPerSample == 32)
429 *in_type = AL_FLOAT;
430 switch(out->dwChannelMask)
432 case MONO: *in_chans = AL_MONO;
433 return "AL_FORMAT_MONO_FLOAT32";
434 case STEREO: *in_chans = AL_STEREO;
435 return "AL_FORMAT_STEREO_FLOAT32";
436 case REAR: *in_chans = AL_REAR;
437 return "AL_FORMAT_REAR32";
438 case QUAD: *in_chans = AL_QUAD;
439 return "AL_FORMAT_QUAD32";
440 case X5DOT1: *in_chans = AL_5POINT1;
441 return "AL_FORMAT_51CHN32";
442 case X6DOT1: *in_chans = AL_6POINT1;
443 return "AL_FORMAT_61CHN32";
444 case X7DOT1: *in_chans = AL_7POINT1;
445 return "AL_FORMAT_71CHN32";
446 default: break;
449 #if 0
450 else if(out->Samples.wValidBitsPerSample == 64 &&
451 prim->SupportedExt[SOFT_BUFFER_SAMPLES])
453 *in_type = AL_DOUBLE;
454 switch(out->dwChannelMask)
456 case MONO: *in_chans = AL_MONO;
457 return "AL_MONO32F";
458 case STEREO: *in_chans = AL_STEREO;
459 return "AL_STEREO32F";
460 case REAR: *in_chans = AL_REAR;
461 return "AL_REAR32F";
462 case QUAD: *in_chans = AL_QUAD;
463 return "AL_QUAD32F";
464 case X5DOT1: *in_chans = AL_5POINT1;
465 return "AL_5POINT1_32F";
466 case X6DOT1: *in_chans = AL_6POINT1;
467 return "AL_6POINT1_32F";
468 case X7DOT1: *in_chans = AL_7POINT1;
469 return "AL_7POINT1_32F";
470 default: break;
473 #endif
474 else
476 WARN("Invalid float bits: %u\n", out->Samples.wValidBitsPerSample);
477 return NULL;
480 FIXME("Could not get OpenAL float format (%d-bit, channelmask %#x)\n",
481 out->Samples.wValidBitsPerSample, out->dwChannelMask);
482 return NULL;
484 else if(!IsEqualGUID(&out->SubFormat, &GUID_NULL))
485 ERR("Unhandled extensible format: %s\n", debugstr_guid(&out->SubFormat));
486 return NULL;
489 static void DS8Data_Release(DS8Data *This);
490 static HRESULT DS8Data_Create(DS8Data **ppv, const DSBUFFERDESC *desc, DS8Primary *prim)
492 HRESULT hr = DSERR_INVALIDPARAM;
493 const WAVEFORMATEX *format;
494 const char *fmt_str = NULL;
495 DS8Data *pBuffer;
497 format = desc->lpwfxFormat;
498 TRACE("Requested buffer format:\n"
499 " FormatTag = 0x%04x\n"
500 " Channels = %d\n"
501 " SamplesPerSec = %u\n"
502 " AvgBytesPerSec = %u\n"
503 " BlockAlign = %d\n"
504 " BitsPerSample = %d\n",
505 format->wFormatTag, format->nChannels,
506 format->nSamplesPerSec, format->nAvgBytesPerSec,
507 format->nBlockAlign, format->wBitsPerSample);
509 if(format->nBlockAlign == 0)
511 WARN("Invalid BlockAlign specified\n");
512 return DSERR_INVALIDPARAM;
515 /* Generate a new buffer. Supporting the DSBCAPS_LOC* flags properly
516 * will need the EAX-RAM extension. Currently, we just tell the app it
517 * gets what it wanted. */
518 pBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pBuffer));
519 if(!pBuffer)
520 return E_OUTOFMEMORY;
521 pBuffer->ref = 1;
523 pBuffer->dsbflags = desc->dwFlags;
524 if((pBuffer->dsbflags&(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE)) == (DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE))
526 WARN("Hardware and software location requested\n");
527 goto fail;
529 if(!(pBuffer->dsbflags&(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE|DSBCAPS_LOCDEFER)))
530 pBuffer->dsbflags |= DSBCAPS_LOCHARDWARE;
532 pBuffer->buf_size = desc->dwBufferBytes + format->nBlockAlign - 1;
533 pBuffer->buf_size -= pBuffer->buf_size%format->nBlockAlign;
535 hr = DSERR_BUFFERTOOSMALL;
536 if(pBuffer->buf_size < DSBSIZE_MIN)
537 goto fail;
539 hr = DSERR_INVALIDPARAM;
540 if(pBuffer->buf_size > DSBSIZE_MAX)
541 goto fail;
543 pBuffer->numsegs = 1;
544 pBuffer->segsize = pBuffer->buf_size;
545 pBuffer->lastsegsize = pBuffer->buf_size;
547 if(!(pBuffer->dsbflags&DSBCAPS_STATIC) && !prim->ExtAL.BufferSubData &&
548 !prim->ExtAL.BufferSamplesSOFT && !prim->ExtAL.BufferDataStatic)
550 ALCint refresh = FAKE_REFRESH_COUNT;
551 ALuint newSize;
553 alcGetIntegerv(prim->parent->device, ALC_REFRESH, 1, &refresh);
554 getALCError(prim->parent->device);
556 newSize = format->nAvgBytesPerSec/refresh + format->nBlockAlign - 1;
557 newSize -= newSize%format->nBlockAlign;
559 /* Make sure enough buffers are available */
560 if(newSize > pBuffer->buf_size/(QBUFFERS+2))
561 ERR("Buffer segments too large to stream (%u for %u)!\n",
562 newSize, pBuffer->buf_size);
563 else
565 pBuffer->numsegs = pBuffer->buf_size/newSize;
566 pBuffer->segsize = newSize;
567 pBuffer->lastsegsize = pBuffer->buf_size - (newSize*(pBuffer->numsegs-1));
568 TRACE("New streaming buffer (%u chunks, %u : %u sizes)\n",
569 pBuffer->numsegs, pBuffer->segsize, pBuffer->lastsegsize);
573 if(format->wFormatTag == WAVE_FORMAT_PCM)
574 fmt_str = get_fmtstr_PCM(prim, format, &pBuffer->format, &pBuffer->in_chans, &pBuffer->in_type);
575 else if(format->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
576 fmt_str = get_fmtstr_FLOAT(prim, format, &pBuffer->format, &pBuffer->in_chans, &pBuffer->in_type);
577 else if(format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
579 const WAVEFORMATEXTENSIBLE *wfe;
581 hr = DSERR_CONTROLUNAVAIL;
582 if(format->cbSize != sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) &&
583 format->cbSize != sizeof(WAVEFORMATEXTENSIBLE))
584 goto fail;
586 wfe = (const WAVEFORMATEXTENSIBLE*)format;
587 TRACE("Extensible values:\n"
588 " Samples = %d\n"
589 " ChannelMask = %#x\n"
590 " SubFormat = %s\n",
591 wfe->Samples.wReserved, wfe->dwChannelMask,
592 debugstr_guid(&wfe->SubFormat));
594 hr = DSERR_INVALIDCALL;
595 fmt_str = get_fmtstr_EXT(prim, format, &pBuffer->format, &pBuffer->in_chans, &pBuffer->in_type);
597 else
598 ERR("Unhandled formattag 0x%04x\n", format->wFormatTag);
600 if(!fmt_str)
601 goto fail;
603 pBuffer->buf_format = alGetEnumValue(fmt_str);
604 if(alGetError() != AL_NO_ERROR || pBuffer->buf_format == 0 ||
605 pBuffer->buf_format == -1)
607 WARN("Could not get OpenAL format from %s\n", fmt_str);
608 goto fail;
611 hr = E_OUTOFMEMORY;
612 pBuffer->buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pBuffer->buffers)*pBuffer->numsegs);
613 pBuffer->data = HeapAlloc(GetProcessHeap(), 0, pBuffer->buf_size);
614 if(!pBuffer->buffers || !pBuffer->data)
615 goto fail;
617 alGenBuffers(pBuffer->numsegs, pBuffer->buffers);
618 getALError();
620 *ppv = pBuffer;
621 return S_OK;
623 fail:
624 DS8Data_Release(pBuffer);
625 return hr;
628 static void DS8Data_AddRef(DS8Data *data)
630 InterlockedIncrement(&data->ref);
633 /* This function is always called with the device lock held */
634 static void DS8Data_Release(DS8Data *This)
636 if(InterlockedDecrement(&This->ref)) return;
638 TRACE("Deleting %p\n", This);
639 if (This->buffers && This->buffers[0])
641 alDeleteBuffers(This->numsegs, This->buffers);
642 getALError();
644 HeapFree(GetProcessHeap(), 0, This->buffers);
645 HeapFree(GetProcessHeap(), 0, This->data);
646 HeapFree(GetProcessHeap(), 0, This);
649 HRESULT DS8Buffer_Create(DS8Buffer **ppv, DS8Primary *parent, DS8Buffer *orig)
651 HRESULT hr = DSERR_OUTOFMEMORY;
652 DS8Buffer *This;
653 DS8Buffer **bufs;
655 *ppv = NULL;
656 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
657 if(!This) return hr;
659 This->IDirectSoundBuffer8_iface.lpVtbl = (IDirectSoundBuffer8Vtbl*)&DS8Buffer_Vtbl;
660 This->IDirectSound3DBuffer_iface.lpVtbl = (IDirectSound3DBufferVtbl*)&DS8Buffer3d_Vtbl;
661 This->IDirectSoundNotify_iface.lpVtbl = (IDirectSoundNotifyVtbl*)&DS8BufferNot_Vtbl;
662 This->IKsPropertySet_iface.lpVtbl = (IKsPropertySetVtbl*)&DS8BufferProp_Vtbl;
664 This->primary = parent;
665 This->ctx = parent->ctx;
666 This->ExtAL = &parent->ExtAL;
667 This->crst = &parent->crst;
668 This->ref = This->all_ref = 1;
670 if(orig)
672 This->buffer = orig->buffer;
673 DS8Data_AddRef(This->buffer);
676 /* Append to buffer list */
677 bufs = parent->buffers;
678 if(parent->nbuffers == parent->sizebuffers)
680 bufs = HeapReAlloc(GetProcessHeap(), 0, bufs, sizeof(*bufs)*(1+parent->nbuffers));
681 if(!bufs) goto fail;
682 parent->sizebuffers++;
684 parent->buffers = bufs;
685 bufs[parent->nbuffers++] = This;
687 /* Disable until initialized.. */
688 This->ds3dmode = DS3DMODE_DISABLE;
690 *ppv = This;
691 return S_OK;
693 fail:
694 DS8Buffer_Destroy(This);
695 return hr;
698 void DS8Buffer_Destroy(DS8Buffer *This)
700 DS8Primary *prim = This->primary;
701 DWORD idx;
703 TRACE("Destroying %p\n", This);
705 EnterCriticalSection(&prim->crst);
706 /* Remove from list, if in list */
707 for(idx = 0;idx < prim->nnotifies;++idx)
709 if(This == prim->notifies[idx])
711 prim->notifies[idx] = prim->notifies[--prim->nnotifies];
712 break;
715 for(idx = 0;idx < prim->nbuffers;++idx)
717 if(prim->buffers[idx] == This)
719 prim->buffers[idx] = prim->buffers[--prim->nbuffers];
720 break;
724 setALContext(This->ctx);
725 if(This->source)
727 ALuint *sources;
729 alSourceStop(This->source);
730 alSourcei(This->source, AL_BUFFER, 0);
731 getALError();
733 sources = prim->sources;
734 if(prim->nsources == prim->sizesources)
736 sources = HeapReAlloc(GetProcessHeap(), 0, sources, sizeof(*sources)*(prim->nsources+1));
737 if(!sources)
738 alDeleteSources(1, &This->source);
739 else
740 prim->sizesources++;
742 if(sources)
744 sources[prim->nsources++] = This->source;
745 prim->sources = sources;
747 This->source = 0;
749 LeaveCriticalSection(&prim->crst);
751 if(This->buffer)
752 DS8Data_Release(This->buffer);
754 popALContext();
756 HeapFree(GetProcessHeap(), 0, This->notify);
757 HeapFree(GetProcessHeap(), 0, This);
760 static inline DS8Buffer *impl_from_IDirectSoundBuffer8(IDirectSoundBuffer8 *iface)
762 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSoundBuffer8_iface);
765 static HRESULT WINAPI DS8Buffer_QueryInterface(IDirectSoundBuffer8 *iface, REFIID riid, void **ppv)
767 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
769 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
771 *ppv = NULL;
772 if(IsEqualIID(riid, &IID_IUnknown) ||
773 IsEqualIID(riid, &IID_IDirectSoundBuffer))
774 *ppv = &This->IDirectSoundBuffer8_iface;
775 else if(IsEqualIID(riid, &IID_IDirectSoundBuffer8))
777 if(This->primary->parent->is_8)
778 *ppv = &This->IDirectSoundBuffer8_iface;
780 else if(IsEqualIID(riid, &IID_IDirectSound3DBuffer))
782 if((This->buffer->dsbflags&DSBCAPS_CTRL3D))
783 *ppv = &This->IDirectSound3DBuffer_iface;
785 else if(IsEqualIID(riid, &IID_IDirectSoundNotify))
787 if((This->buffer->dsbflags&DSBCAPS_CTRLPOSITIONNOTIFY))
788 *ppv = &This->IDirectSoundNotify_iface;
790 else if(IsEqualIID(riid, &IID_IKsPropertySet))
791 *ppv = &This->IKsPropertySet_iface;
792 else
793 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
795 if(*ppv)
797 IUnknown_AddRef((IUnknown*)*ppv);
798 return S_OK;
801 return E_NOINTERFACE;
804 static ULONG WINAPI DS8Buffer_AddRef(IDirectSoundBuffer8 *iface)
806 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
807 LONG ret;
809 InterlockedIncrement(&This->all_ref);
810 ret = InterlockedIncrement(&This->ref);
811 TRACE("new refcount %d\n", ret);
813 return ret;
816 static ULONG WINAPI DS8Buffer_Release(IDirectSoundBuffer8 *iface)
818 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
819 LONG ret;
821 ret = InterlockedDecrement(&This->ref);
822 TRACE("new refcount %d\n", ret);
823 if(InterlockedDecrement(&This->all_ref) == 0)
824 DS8Buffer_Destroy(This);
826 return ret;
829 static HRESULT WINAPI DS8Buffer_GetCaps(IDirectSoundBuffer8 *iface, DSBCAPS *caps)
831 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
833 TRACE("(%p)->(%p)\n", iface, caps);
835 if(!caps || caps->dwSize < sizeof(*caps))
837 WARN("Invalid DSBCAPS (%p, %u)\n", caps, (caps ? caps->dwSize : 0));
838 return DSERR_INVALIDPARAM;
841 caps->dwFlags = This->buffer->dsbflags;
842 caps->dwBufferBytes = This->buffer->buf_size;
843 caps->dwUnlockTransferRate = 4096;
844 caps->dwPlayCpuOverhead = 0;
845 return S_OK;
848 static HRESULT WINAPI DS8Buffer_GetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD *playpos, DWORD *curpos)
850 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
851 WAVEFORMATEX *format = &This->buffer->format.Format;
852 UINT writecursor, pos;
854 TRACE("(%p)->(%p, %p)\n", iface, playpos, curpos);
856 EnterCriticalSection(This->crst);
857 setALContext(This->ctx);
859 if(This->buffer->numsegs > 1)
861 ALint queued = QBUFFERS;
862 alGetSourcei(This->source, AL_BUFFERS_QUEUED, &queued);
863 getALError();
865 pos = (This->curidx+This->buffer->numsegs-queued)%This->buffer->numsegs;
866 pos *= This->buffer->segsize;
867 writecursor = This->curidx * This->buffer->segsize;
869 else if(This->ExtAL->BufferSubData || This->ExtAL->BufferSamplesSOFT)
871 ALint rwpos[2] = { 0, 0 };
873 alGetSourceiv(This->source, AL_BYTE_RW_OFFSETS_SOFT, rwpos);
874 getALError();
876 pos = rwpos[0];
877 writecursor = rwpos[1];
879 else
881 ALint status = 0;
882 ALint ofs = 0;
884 alGetSourcei(This->source, AL_BYTE_OFFSET, &ofs);
885 alGetSourcei(This->source, AL_SOURCE_STATE, &status);
886 getALError();
888 pos = ofs;
889 if(status == AL_PLAYING)
891 writecursor = format->nSamplesPerSec / 100;
892 writecursor *= format->nBlockAlign;
894 else
895 writecursor = 0;
896 writecursor = (writecursor + pos) % This->buffer->buf_size;
898 TRACE("%p Play pos = %u, write pos = %u\n", This, pos, writecursor);
899 if(pos >= This->buffer->buf_size)
901 ERR("playpos >= buf_size\n");
902 pos %= This->buffer->buf_size;
904 if(writecursor >= This->buffer->buf_size)
906 ERR("writepos >= buf_size\n");
907 writecursor %= This->buffer->buf_size;
910 if(playpos) *playpos = pos;
911 if(curpos) *curpos = writecursor;
913 popALContext();
914 LeaveCriticalSection(This->crst);
916 return S_OK;
919 static HRESULT WINAPI DS8Buffer_GetFormat(IDirectSoundBuffer8 *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
921 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
922 HRESULT hr = S_OK;
923 UINT size;
925 TRACE("(%p)->(%p, %u, %p)\n", iface, wfx, allocated, written);
927 if(!wfx && !written)
929 WARN("Cannot report format or format size\n");
930 return DSERR_INVALIDPARAM;
933 EnterCriticalSection(This->crst);
934 size = sizeof(This->buffer->format.Format) + This->buffer->format.Format.cbSize;
935 if(wfx)
937 if(allocated < size)
938 hr = DSERR_INVALIDPARAM;
939 else
940 memcpy(wfx, &This->buffer->format.Format, size);
942 if(written)
943 *written = size;
944 LeaveCriticalSection(This->crst);
946 return hr;
949 static HRESULT WINAPI DS8Buffer_GetVolume(IDirectSoundBuffer8 *iface, LONG *vol)
951 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
952 HRESULT hr;
954 TRACE("(%p)->(%p)\n", iface, vol);
956 if(!vol)
958 WARN("Invalid pointer\n");
959 return DSERR_INVALIDPARAM;
962 EnterCriticalSection(This->crst);
964 hr = DSERR_CONTROLUNAVAIL;
965 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
966 WARN("Volume control not set\n");
967 else
969 ALfloat gain = 1.0f;
971 setALContext(This->ctx);
972 alGetSourcef(This->source, AL_GAIN, &gain);
973 getALError();
974 popALContext();
976 *vol = gain_to_mB(gain);
977 *vol = min(*vol, DSBVOLUME_MAX);
978 *vol = max(*vol, DSBVOLUME_MIN);
980 hr = DS_OK;
983 LeaveCriticalSection(This->crst);
984 return hr;
987 static HRESULT WINAPI DS8Buffer_GetPan(IDirectSoundBuffer8 *iface, LONG *pan)
989 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
990 HRESULT hr;
992 TRACE("(%p)->(%p)\n", iface, pan);
994 if(!pan)
996 WARN("Invalid pointer\n");
997 return DSERR_INVALIDPARAM;
1000 EnterCriticalSection(This->crst);
1002 hr = DSERR_CONTROLUNAVAIL;
1003 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
1004 WARN("Panning control not set\n");
1005 else
1007 ALfloat pos[3];
1009 setALContext(This->ctx);
1010 alGetSourcefv(This->source, AL_POSITION, pos);
1011 getALError();
1012 popALContext();
1014 *pan = (LONG)((pos[0]+1.0) * (DSBPAN_RIGHT-DSBPAN_LEFT) / 2.0 + 0.5) + DSBPAN_LEFT;
1015 *pan = min(*pan, DSBPAN_RIGHT);
1016 *pan = max(*pan, DSBPAN_LEFT);
1018 hr = DS_OK;
1021 LeaveCriticalSection(This->crst);
1022 return hr;
1025 static HRESULT WINAPI DS8Buffer_GetFrequency(IDirectSoundBuffer8 *iface, DWORD *freq)
1027 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1028 HRESULT hr;
1030 TRACE("(%p)->(%p)\n", iface, freq);
1032 if(!freq)
1034 WARN("Invalid pointer\n");
1035 return DSERR_INVALIDPARAM;
1038 EnterCriticalSection(This->crst);
1040 hr = DSERR_CONTROLUNAVAIL;
1041 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
1042 WARN("Frequency control not set\n");
1043 else
1045 ALfloat pitch = 1.0f;
1047 setALContext(This->ctx);
1048 alGetSourcefv(This->source, AL_PITCH, &pitch);
1049 getALError();
1050 popALContext();
1052 *freq = (DWORD)(This->buffer->format.Format.nSamplesPerSec * pitch);
1054 hr = DS_OK;
1057 LeaveCriticalSection(This->crst);
1058 return hr;
1061 static HRESULT WINAPI DS8Buffer_GetStatus(IDirectSoundBuffer8 *iface, DWORD *status)
1063 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1064 ALint state, looping;
1066 TRACE("(%p)->(%p)\n", iface, status);
1068 if(!status)
1070 WARN("Invalid pointer\n");
1071 return DSERR_INVALIDPARAM;
1074 EnterCriticalSection(This->crst);
1076 setALContext(This->ctx);
1077 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1078 looping = This->islooping;
1079 if(This->buffer->numsegs == 1)
1080 alGetSourcei(This->source, AL_LOOPING, &looping);
1081 else if(state != AL_PLAYING)
1082 state = This->isplaying ? AL_PLAYING : AL_PAUSED;
1083 getALError();
1084 popALContext();
1086 *status = 0;
1087 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1089 if((This->buffer->dsbflags&DSBCAPS_LOCSOFTWARE))
1090 *status |= DSBSTATUS_LOCSOFTWARE;
1091 else if((This->buffer->dsbflags&DSBCAPS_LOCHARDWARE))
1092 *status |= DSBSTATUS_LOCHARDWARE;
1094 if(state == AL_PLAYING)
1095 *status |= DSBSTATUS_PLAYING | (looping ? DSBSTATUS_LOOPING : 0);
1097 LeaveCriticalSection(This->crst);
1099 return S_OK;
1102 static HRESULT WINAPI DS8Buffer_Initialize(IDirectSoundBuffer8 *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
1104 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1105 DS3DBUFFER *ds3dbuffer;
1106 HRESULT hr;
1108 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
1110 EnterCriticalSection(This->crst);
1111 setALContext(This->ctx);
1113 hr = DSERR_ALREADYINITIALIZED;
1114 if(This->source)
1115 goto out;
1117 if(!This->buffer)
1119 hr = DSERR_INVALIDPARAM;
1120 if(!desc)
1122 WARN("Missing DSound buffer description\n");
1123 goto out;
1125 if(!desc->lpwfxFormat)
1127 WARN("Missing buffer format (%p)\n", This);
1128 goto out;
1130 if((desc->dwFlags&DSBCAPS_CTRL3D) && desc->lpwfxFormat->nChannels != 1)
1132 if(This->primary->parent->is_8)
1134 /* DirectSoundBuffer8 objects aren't allowed non-mono 3D
1135 * buffers */
1136 WARN("Can't create multi-channel 3D buffers\n");
1137 goto out;
1139 ERR("Multi-channel 3D sounds are not spatialized\n");
1142 hr = DS8Data_Create(&This->buffer, desc, This->primary);
1143 if(FAILED(hr))
1144 goto out;
1145 else
1147 DS8Data *buf = This->buffer;
1149 if(buf->in_type == AL_UNSIGNED_BYTE)
1150 memset(buf->data, 0x80, buf->buf_size);
1151 else
1152 memset(buf->data, 0x00, buf->buf_size);
1154 if(This->ExtAL->BufferDataStatic)
1155 This->ExtAL->BufferDataStatic(buf->buffers[0], buf->buf_format,
1156 buf->data, buf->buf_size,
1157 buf->format.Format.nSamplesPerSec);
1158 else if(This->ExtAL->BufferSamplesSOFT)
1159 This->ExtAL->BufferSamplesSOFT(buf->buffers[0],
1160 buf->format.Format.nSamplesPerSec, buf->buf_format,
1161 buf->buf_size/buf->format.Format.nBlockAlign,
1162 buf->in_chans, buf->in_type, buf->data);
1163 else if(This->ExtAL->BufferSubData)
1164 alBufferData(buf->buffers[0], buf->buf_format,
1165 buf->data, buf->buf_size,
1166 buf->format.Format.nSamplesPerSec);
1168 getALError();
1171 hr = DSERR_GENERIC;
1172 if(This->primary->nsources)
1174 This->source = This->primary->sources[--This->primary->nsources];
1175 alSourcef(This->source, AL_GAIN, 1.0f);
1176 alSourcef(This->source, AL_PITCH, 1.0f);
1177 getALError();
1179 else
1181 alGenSources(1, &This->source);
1182 if(alGetError() != AL_NO_ERROR)
1183 goto out;
1186 ds3dbuffer = &This->ds3dbuffer;
1187 ds3dbuffer->dwSize = sizeof(*ds3dbuffer);
1188 ds3dbuffer->vPosition.x = 0.0;
1189 ds3dbuffer->vPosition.y = 0.0;
1190 ds3dbuffer->vPosition.z = 0.0;
1191 ds3dbuffer->vVelocity.x = 0.0;
1192 ds3dbuffer->vVelocity.y = 0.0;
1193 ds3dbuffer->vVelocity.z = 0.0;
1194 ds3dbuffer->dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
1195 ds3dbuffer->dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
1196 ds3dbuffer->vConeOrientation.x = 0.0;
1197 ds3dbuffer->vConeOrientation.y = 0.0;
1198 ds3dbuffer->vConeOrientation.z = 1.0;
1199 ds3dbuffer->lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
1200 ds3dbuffer->flMinDistance = DS3D_DEFAULTMINDISTANCE;
1201 ds3dbuffer->flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
1202 ds3dbuffer->dwMode = DS3DMODE_NORMAL;
1204 if((This->buffer->dsbflags&DSBCAPS_CTRL3D))
1206 if(This->primary->auxslot != 0)
1208 alSource3i(This->source, AL_AUXILIARY_SEND_FILTER, This->primary->auxslot, 0, AL_FILTER_NULL);
1209 getALError();
1212 hr = IDirectSound3DBuffer_SetAllParameters(&This->IDirectSound3DBuffer_iface, ds3dbuffer, DS3D_IMMEDIATE);
1213 if(FAILED(hr))
1215 ERR("SetAllParameters failed\n");
1216 goto out;
1219 else
1221 ALuint source = This->source;
1223 if(This->primary->auxslot != 0)
1225 /* Simple hack to make reverb affect non-3D sounds too */
1226 alSource3i(source, AL_AUXILIARY_SEND_FILTER, This->primary->auxslot, 0, AL_FILTER_NULL);
1227 /*alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL);*/
1230 /* Non-3D sources aren't distance attenuated */
1231 This->ds3dmode = DS3DMODE_DISABLE;
1232 alSource3f(source, AL_POSITION, 0.0f, 1.0f, 0.0f);
1233 alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
1234 alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
1235 alSourcef(source, AL_CONE_OUTER_GAIN, 1.0f);
1236 alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f);
1237 alSourcef(source, AL_MAX_DISTANCE, 1000.0f);
1238 alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f);
1239 alSourcei(source, AL_CONE_INNER_ANGLE, 360);
1240 alSourcei(source, AL_CONE_OUTER_ANGLE, 360);
1241 alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);
1242 getALError();
1244 hr = S_OK;
1246 out:
1247 popALContext();
1248 LeaveCriticalSection(This->crst);
1250 return hr;
1253 static HRESULT WINAPI DS8Buffer_Lock(IDirectSoundBuffer8 *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
1255 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1256 HRESULT hr;
1257 DWORD remain;
1259 TRACE("(%p)->(%u, %u, %p, %p, %p, %p, 0x%x)\n", This, ofs, bytes, ptr1, len1, ptr2, len2, flags);
1261 if(!ptr1 || !len1)
1263 WARN("Invalid pointer/len %p %p\n", ptr1, len1);
1264 return DSERR_INVALIDPARAM;
1267 EnterCriticalSection(This->crst);
1268 setALContext(This->ctx);
1270 *ptr1 = NULL;
1271 *len1 = 0;
1272 if(ptr2) *ptr2 = NULL;
1273 if(len2) *len2 = 0;
1275 hr = DSERR_INVALIDPARAM;
1276 if((flags&DSBLOCK_FROMWRITECURSOR))
1277 DS8Buffer_GetCurrentPosition(iface, NULL, &ofs);
1278 else if(ofs >= This->buffer->buf_size)
1280 WARN("Invalid ofs %u\n", ofs);
1281 goto out;
1283 if((flags&DSBLOCK_ENTIREBUFFER))
1284 bytes = This->buffer->buf_size;
1285 else if(bytes > This->buffer->buf_size)
1287 WARN("Invalid size %u\n", bytes);
1288 goto out;
1291 *ptr1 = This->buffer->data + ofs;
1292 if(ofs+bytes >= This->buffer->buf_size)
1294 *len1 = This->buffer->buf_size - ofs;
1295 remain = bytes - *len1;
1297 else
1299 *len1 = bytes;
1300 remain = 0;
1303 This->buffer->locked = TRUE;
1305 if(ptr2 && len2 && remain)
1307 *ptr2 = This->buffer->data;
1308 *len2 = remain;
1310 hr = S_OK;
1312 out:
1313 popALContext();
1314 LeaveCriticalSection(This->crst);
1315 return hr;
1318 static HRESULT WINAPI DS8Buffer_Play(IDirectSoundBuffer8 *iface, DWORD res1, DWORD prio, DWORD flags)
1320 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1321 ALint type, state = AL_STOPPED;
1322 HRESULT hr;
1323 (void)res1;
1325 TRACE("%p\n", This);
1327 EnterCriticalSection(This->crst);
1328 setALContext(This->ctx);
1330 hr = DSERR_BUFFERLOST;
1331 if(This->bufferlost)
1333 WARN("Buffer %p lost\n", This);
1334 goto out;
1337 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1339 if(!(This->buffer->dsbflags&(DSBCAPS_LOCHARDWARE|DSBCAPS_LOCSOFTWARE)))
1341 if(flags & DSBPLAY_LOCSOFTWARE)
1342 This->buffer->dsbflags |= DSBCAPS_LOCSOFTWARE;
1343 else
1344 This->buffer->dsbflags |= DSBCAPS_LOCHARDWARE;
1347 else if(prio)
1349 ERR("Invalid priority set for non-deferred buffer %p, %u!\n", This->buffer, prio);
1350 hr = DSERR_INVALIDPARAM;
1351 goto out;
1354 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1355 if(This->buffer->numsegs > 1)
1357 This->islooping = !!(flags&DSBPLAY_LOOPING);
1358 if(state != AL_PLAYING && This->isplaying)
1359 state = AL_PLAYING;
1361 else
1363 alGetSourcei(This->source, AL_SOURCE_TYPE, &type);
1364 alSourcei(This->source, AL_LOOPING, (flags&DSBPLAY_LOOPING) ? AL_TRUE : AL_FALSE);
1366 getALError();
1368 hr = S_OK;
1369 if(state == AL_PLAYING)
1370 goto out;
1372 /* alSourceQueueBuffers will implicitly set type to streaming */
1373 if(This->buffer->numsegs == 1)
1375 if(type != AL_STATIC)
1376 alSourcei(This->source, AL_BUFFER, This->buffer->buffers[0]);
1377 alSourcePlay(This->source);
1379 if(alGetError() != AL_NO_ERROR)
1381 ERR("Couldn't start source\n");
1382 This->curidx = (This->buffer->numsegs-1+This->curidx)%This->buffer->numsegs;
1383 alSourcei(This->source, AL_BUFFER, 0);
1384 getALError();
1385 hr = DSERR_GENERIC;
1386 goto out;
1388 This->isplaying = TRUE;
1390 if(This->nnotify)
1392 DS8Buffer_addnotify(This);
1393 DS8Buffer_starttimer(This->primary);
1395 else if(This->buffer->numsegs > 1)
1396 DS8Buffer_starttimer(This->primary);
1398 out:
1399 popALContext();
1400 LeaveCriticalSection(This->crst);
1401 return hr;
1404 static HRESULT WINAPI DS8Buffer_SetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD pos)
1406 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1407 HRESULT hr;
1408 TRACE("%p\n", This);
1410 EnterCriticalSection(This->crst);
1411 setALContext(This->ctx);
1413 hr = DSERR_INVALIDPARAM;
1414 if(pos >= This->buffer->buf_size)
1415 goto out;
1417 if(This->buffer->numsegs > 1)
1419 DS8Data *buf = This->buffer;
1420 This->curidx = pos/buf->segsize;
1421 if(This->curidx >= buf->numsegs)
1422 This->curidx = buf->numsegs - 1;
1423 if(This->isplaying)
1425 alSourceStop(This->source);
1426 alSourcei(This->source, AL_BUFFER, 0);
1427 getALError();
1430 else
1431 alSourcei(This->source, AL_BYTE_OFFSET, pos);
1432 This->lastpos = pos;
1433 hr = S_OK;
1435 out:
1436 popALContext();
1437 LeaveCriticalSection(This->crst);
1438 return hr;
1441 static HRESULT WINAPI DS8Buffer_SetFormat(IDirectSoundBuffer8 *iface, const WAVEFORMATEX *wfx)
1443 /* This call only works on primary buffers */
1444 WARN("(%p)->(%p)\n", iface, wfx);
1445 return DSERR_INVALIDCALL;
1448 static HRESULT WINAPI DS8Buffer_SetVolume(IDirectSoundBuffer8 *iface, LONG vol)
1450 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1451 HRESULT hr = S_OK;
1453 TRACE("(%p)->(%d)\n", iface, vol);
1455 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
1457 WARN("Invalid volume (%d)\n", vol);
1458 return DSERR_INVALIDPARAM;
1461 EnterCriticalSection(This->crst);
1462 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
1463 hr = DSERR_CONTROLUNAVAIL;
1464 if(SUCCEEDED(hr))
1466 ALfloat fvol = mB_to_gain(vol);
1467 setALContext(This->ctx);
1468 alSourcef(This->source, AL_GAIN, fvol);
1469 popALContext();
1471 LeaveCriticalSection(This->crst);
1473 return hr;
1476 static HRESULT WINAPI DS8Buffer_SetPan(IDirectSoundBuffer8 *iface, LONG pan)
1478 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1479 HRESULT hr = S_OK;
1481 TRACE("(%p)->(%d)\n", iface, pan);
1483 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
1485 WARN("invalid parameter: pan = %d\n", pan);
1486 return DSERR_INVALIDPARAM;
1489 EnterCriticalSection(This->crst);
1490 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
1491 hr = DSERR_CONTROLUNAVAIL;
1492 else
1494 ALfloat pos[3];
1495 pos[0] = (pan-DSBPAN_LEFT) * 2.0 / (ALfloat)(DSBPAN_RIGHT-DSBPAN_LEFT) - 1.0;
1496 /* NOTE: Strict movement along the X plane can cause the sound to jump
1497 * between left and right sharply. Using a curved path helps smooth it
1498 * out */
1499 pos[1] = sqrt(1.0 - pos[0]*pos[0]);
1500 pos[2] = 0.0;
1502 setALContext(This->ctx);
1503 alSourcefv(This->source, AL_POSITION, pos);
1504 getALError();
1505 popALContext();
1507 if(pan != 0 && This->buffer->format.Format.nChannels > 1)
1508 FIXME("Panning for multi-channel buffers is not supported\n");
1510 LeaveCriticalSection(This->crst);
1512 return hr;
1515 static HRESULT WINAPI DS8Buffer_SetFrequency(IDirectSoundBuffer8 *iface, DWORD freq)
1517 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1518 HRESULT hr = S_OK;
1520 TRACE("(%p)->(%u)\n", iface, freq);
1522 if(freq < DSBFREQUENCY_MIN || freq > DSBFREQUENCY_MAX)
1524 WARN("invalid parameter: freq = %d\n", freq);
1525 return DSERR_INVALIDPARAM;
1528 EnterCriticalSection(This->crst);
1529 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
1530 hr = DSERR_CONTROLUNAVAIL;
1531 else
1533 ALfloat pitch = 1.0f;
1534 if(freq != DSBFREQUENCY_ORIGINAL)
1535 pitch = freq / (ALfloat)This->buffer->format.Format.nSamplesPerSec;
1537 setALContext(This->ctx);
1538 alSourcef(This->source, AL_PITCH, pitch);
1539 getALError();
1540 popALContext();
1542 LeaveCriticalSection(This->crst);
1543 return hr;
1546 static HRESULT WINAPI DS8Buffer_Stop(IDirectSoundBuffer8 *iface)
1548 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1549 ALint state;
1551 TRACE("(%p)->()\n", iface);
1553 EnterCriticalSection(This->crst);
1554 setALContext(This->ctx);
1556 alSourcePause(This->source);
1557 getALError();
1558 /* Mac OS X doesn't immediately report state change
1559 * if Play() is immediately called after Stop, this can be fatal,
1560 * the buffer would never be restarted
1562 do {
1563 state = AL_PAUSED;
1564 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1565 if(state != AL_PLAYING)
1566 break;
1567 Sleep(1);
1568 } while(1);
1570 This->isplaying = FALSE;
1572 popALContext();
1573 LeaveCriticalSection(This->crst);
1575 return S_OK;
1578 static HRESULT WINAPI DS8Buffer_Unlock(IDirectSoundBuffer8 *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
1580 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1581 DS8Data *buf = This->buffer;
1582 DWORD bufsize = buf->buf_size;
1583 DWORD_PTR ofs1, ofs2;
1584 DWORD_PTR boundary = (DWORD_PTR)buf->data;
1585 HRESULT hr;
1587 TRACE("(%p)->(%p, %u, %p, %u)\n", iface, ptr1, len1, ptr2, len2);
1589 EnterCriticalSection(This->crst);
1590 setALContext(This->ctx);
1592 This->buffer->locked = 0;
1593 hr = DSERR_INVALIDPARAM;
1595 /* Make sure offset is between boundary and boundary + bufsize */
1596 ofs1 = (DWORD_PTR)ptr1;
1597 ofs2 = (DWORD_PTR)ptr2;
1598 if(ofs1 < boundary)
1599 goto out;
1600 if(ofs2 && ofs2 != boundary)
1601 goto out;
1602 ofs1 -= boundary;
1603 ofs2 = 0;
1604 if(bufsize-ofs1 < len1 || len2 > ofs1)
1605 goto out;
1606 if(!ptr2)
1607 len2 = 0;
1609 hr = S_OK;
1610 if(!len1 && !len2)
1611 goto out;
1613 if(This->ExtAL->BufferDataStatic)
1614 goto out;
1616 if(This->ExtAL->BufferSubSamplesSOFT)
1618 WAVEFORMATEX *format = &buf->format.Format;
1620 ptr1 = (BYTE*)ptr1 - (ofs1%format->nBlockAlign);
1621 ofs1 /= format->nBlockAlign;
1622 len1 /= format->nBlockAlign;
1623 if(len1 > 0)
1624 This->ExtAL->BufferSubSamplesSOFT(buf->buffers[0], ofs1, len1,
1625 buf->in_chans, buf->in_type, ptr1);
1626 ptr2 = (BYTE*)ptr2 - (ofs2%format->nBlockAlign);
1627 ofs2 /= format->nBlockAlign;
1628 len2 /= format->nBlockAlign;
1629 if(len2 > 0)
1630 This->ExtAL->BufferSubSamplesSOFT(buf->buffers[0], ofs2, len2,
1631 buf->in_chans, buf->in_type, ptr2);
1632 getALError();
1634 else if(This->ExtAL->BufferSubData)
1636 WAVEFORMATEX *format = &buf->format.Format;
1638 len1 -= len1%format->nBlockAlign;
1639 if(len1 > 0)
1640 This->ExtAL->BufferSubData(buf->buffers[0], buf->buf_format, ptr1,
1641 ofs1, len1);
1642 len2 -= len2%format->nBlockAlign;
1643 if(len2 > 0)
1644 This->ExtAL->BufferSubData(buf->buffers[0], buf->buf_format, ptr2,
1645 ofs2, len2);
1646 getALError();
1648 else
1650 alBufferData(buf->buffers[0], buf->buf_format,
1651 buf->data, buf->buf_size,
1652 buf->format.Format.nSamplesPerSec);
1653 getALError();
1656 out:
1657 if(hr != S_OK)
1658 WARN("Invalid parameters (0x%lx,%u) (%p,%u,%p,%u)\n", boundary, bufsize, ptr1, len1, ptr2, len2);
1659 popALContext();
1660 LeaveCriticalSection(This->crst);
1661 return hr;
1664 static HRESULT WINAPI DS8Buffer_Restore(IDirectSoundBuffer8 *iface)
1666 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1667 HRESULT hr;
1669 TRACE("(%p)->()\n", iface);
1671 EnterCriticalSection(This->crst);
1672 if(This->primary->parent->prio_level < DSSCL_WRITEPRIMARY ||
1673 iface == This->primary->write_emu)
1675 This->bufferlost = 0;
1676 hr = S_OK;
1678 else
1679 hr = DSERR_BUFFERLOST;
1680 LeaveCriticalSection(This->crst);
1682 return hr;
1685 static HRESULT WINAPI DS8Buffer_SetFX(IDirectSoundBuffer8 *iface, DWORD fxcount, DSEFFECTDESC *desc, DWORD *rescodes)
1687 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1688 DWORD i;
1690 TRACE("(%p)->(%u, %p, %p)\n", This, fxcount, desc, rescodes);
1692 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFX))
1694 WARN("FX control not set\n");
1695 return DSERR_CONTROLUNAVAIL;
1698 if(fxcount == 0)
1700 if(desc || rescodes)
1702 WARN("Non-NULL desc and/or result pointer specified with no effects.\n");
1703 return DSERR_INVALIDPARAM;
1706 /* No effects; we can handle that */
1707 return DS_OK;
1710 if(!desc || !rescodes)
1712 WARN("NULL desc and/or result pointer specified.\n");
1713 return DSERR_INVALIDPARAM;
1716 /* We don't (currently) handle DSound effects */
1717 for(i = 0;i < fxcount;++i)
1719 FIXME("Cannot handle effect: %s\n", debugstr_guid(&desc[i].guidDSFXClass));
1720 rescodes[i] = DSFXR_FAILED;
1723 return DSERR_INVALIDPARAM;
1726 static HRESULT WINAPI DS8Buffer_AcquireResources(IDirectSoundBuffer8 *iface, DWORD flags, DWORD fxcount, DWORD *rescodes)
1728 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1730 TRACE("(%p)->(%u, %u, %p)\n", This, flags, fxcount, rescodes);
1732 /* effects aren't supported at the moment.. */
1733 if(fxcount != 0 || rescodes)
1735 WARN("Non-zero effect count and/or result pointer specified with no effects.\n");
1736 return DSERR_INVALIDPARAM;
1739 EnterCriticalSection(This->crst);
1740 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1742 This->buffer->dsbflags &= ~(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE);
1743 if((flags&DSBPLAY_LOCSOFTWARE))
1744 This->buffer->dsbflags |= DSBCAPS_LOCSOFTWARE;
1745 else
1746 This->buffer->dsbflags |= DSBCAPS_LOCHARDWARE;
1748 LeaveCriticalSection(This->crst);
1750 return S_OK;
1753 static HRESULT WINAPI DS8Buffer_GetObjectInPath(IDirectSoundBuffer8 *iface, REFGUID guid, DWORD idx, REFGUID rguidiface, void **ppv)
1755 FIXME("(%p)->(%s, %u, %s, %p) : stub!\n", iface, debugstr_guid(guid), idx, debugstr_guid(rguidiface), ppv);
1756 return E_NOTIMPL;
1759 static const IDirectSoundBuffer8Vtbl DS8Buffer_Vtbl =
1761 DS8Buffer_QueryInterface,
1762 DS8Buffer_AddRef,
1763 DS8Buffer_Release,
1764 DS8Buffer_GetCaps,
1765 DS8Buffer_GetCurrentPosition,
1766 DS8Buffer_GetFormat,
1767 DS8Buffer_GetVolume,
1768 DS8Buffer_GetPan,
1769 DS8Buffer_GetFrequency,
1770 DS8Buffer_GetStatus,
1771 DS8Buffer_Initialize,
1772 DS8Buffer_Lock,
1773 DS8Buffer_Play,
1774 DS8Buffer_SetCurrentPosition,
1775 DS8Buffer_SetFormat,
1776 DS8Buffer_SetVolume,
1777 DS8Buffer_SetPan,
1778 DS8Buffer_SetFrequency,
1779 DS8Buffer_Stop,
1780 DS8Buffer_Unlock,
1781 DS8Buffer_Restore,
1782 DS8Buffer_SetFX,
1783 DS8Buffer_AcquireResources,
1784 DS8Buffer_GetObjectInPath
1787 static inline DS8Buffer *impl_from_IDirectSound3DBuffer(IDirectSound3DBuffer *iface)
1789 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSound3DBuffer_iface);
1792 static HRESULT WINAPI DS8Buffer3D_QueryInterface(IDirectSound3DBuffer *iface, REFIID riid, void **ppv)
1794 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1795 return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
1798 static ULONG WINAPI DS8Buffer3D_AddRef(IDirectSound3DBuffer *iface)
1800 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1801 LONG ret;
1803 InterlockedIncrement(&This->all_ref);
1804 ret = InterlockedIncrement(&This->ds3d_ref);
1805 TRACE("new refcount %d\n", ret);
1807 return ret;
1810 static ULONG WINAPI DS8Buffer3D_Release(IDirectSound3DBuffer *iface)
1812 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1813 LONG ret;
1815 ret = InterlockedDecrement(&This->ds3d_ref);
1816 TRACE("new refcount %d\n", ret);
1817 if(InterlockedDecrement(&This->all_ref) == 0)
1818 DS8Buffer_Destroy(This);
1820 return ret;
1823 static HRESULT WINAPI DS8Buffer3D_GetAllParameters(IDirectSound3DBuffer *iface, DS3DBUFFER *ds3dbuffer)
1825 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1826 DS3DBUFFER ds3dbuf;
1827 HRESULT hr;
1829 TRACE("%p\n", This);
1831 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
1833 WARN("Invalid parameters %p %u\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
1834 return DSERR_INVALIDPARAM;
1836 ds3dbuf.dwSize = sizeof(ds3dbuf);
1838 EnterCriticalSection(This->crst);
1839 setALContext(This->ctx);
1841 hr = IDirectSound3DBuffer_GetPosition(iface, &ds3dbuf.vPosition);
1842 if(SUCCEEDED(hr))
1843 hr = IDirectSound3DBuffer_GetVelocity(iface, &ds3dbuf.vVelocity);
1844 if(SUCCEEDED(hr))
1845 hr = IDirectSound3DBuffer_GetConeAngles(iface, &ds3dbuf.dwInsideConeAngle, &ds3dbuf.dwOutsideConeAngle);
1846 if(SUCCEEDED(hr))
1847 hr = IDirectSound3DBuffer_GetConeOrientation(iface, &ds3dbuf.vConeOrientation);
1848 if(SUCCEEDED(hr))
1849 hr = IDirectSound3DBuffer_GetConeOutsideVolume(iface, &ds3dbuf.lConeOutsideVolume);
1850 if(SUCCEEDED(hr))
1851 hr = IDirectSound3DBuffer_GetMinDistance(iface, &ds3dbuf.flMinDistance);
1852 if(SUCCEEDED(hr))
1853 hr = IDirectSound3DBuffer_GetMaxDistance(iface, &ds3dbuf.flMaxDistance);
1854 if(SUCCEEDED(hr))
1855 hr = IDirectSound3DBuffer_GetMode(iface, &ds3dbuf.dwMode);
1856 if(SUCCEEDED(hr))
1857 memcpy(ds3dbuffer, &ds3dbuf, sizeof(ds3dbuf));
1859 popALContext();
1860 LeaveCriticalSection(This->crst);
1862 return hr;
1865 static HRESULT WINAPI DS8Buffer3D_GetConeAngles(IDirectSound3DBuffer *iface, DWORD *pdwInsideConeAngle, DWORD *pdwOutsideConeAngle)
1867 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1868 ALint inangle, outangle;
1870 TRACE("(%p)->(%p, %p)\n", This, pdwInsideConeAngle, pdwOutsideConeAngle);
1871 if(!pdwInsideConeAngle || !pdwOutsideConeAngle)
1873 WARN("Invalid pointers (%p, %p)\n", pdwInsideConeAngle, pdwOutsideConeAngle);
1874 return DSERR_INVALIDPARAM;
1877 EnterCriticalSection(This->crst);
1878 setALContext(This->ctx);
1880 alGetSourcei(This->source, AL_CONE_INNER_ANGLE, &inangle);
1881 alGetSourcei(This->source, AL_CONE_OUTER_ANGLE, &outangle);
1882 getALError();
1883 *pdwInsideConeAngle = inangle;
1884 *pdwOutsideConeAngle = outangle;
1886 popALContext();
1887 LeaveCriticalSection(This->crst);
1889 return S_OK;
1892 static HRESULT WINAPI DS8Buffer3D_GetConeOrientation(IDirectSound3DBuffer *iface, D3DVECTOR *orient)
1894 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1895 ALfloat dir[3];
1897 TRACE("(%p)->(%p)\n", This, orient);
1898 if(!orient)
1900 WARN("Invalid pointer\n");
1901 return DSERR_INVALIDPARAM;
1904 EnterCriticalSection(This->crst);
1905 setALContext(This->ctx);
1907 alGetSourcefv(This->source, AL_DIRECTION, dir);
1908 getALError();
1909 orient->x = dir[0];
1910 orient->y = dir[1];
1911 orient->z = -dir[2];
1913 popALContext();
1914 LeaveCriticalSection(This->crst);
1916 return S_OK;
1919 static HRESULT WINAPI DS8Buffer3D_GetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG *vol)
1921 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1922 ALfloat gain;
1924 TRACE("(%p)->(%p)\n", This, vol);
1925 if(!vol)
1927 WARN("Invalid pointer\n");
1928 return DSERR_INVALIDPARAM;
1931 EnterCriticalSection(This->crst);
1932 setALContext(This->ctx);
1934 alGetSourcef(This->source, AL_CONE_OUTER_GAIN, &gain);
1935 getALError();
1936 *vol = gain_to_mB(gain);
1937 *vol = max(*vol, DSBVOLUME_MIN);
1938 *vol = min(*vol, DSBVOLUME_MAX);
1940 popALContext();
1941 LeaveCriticalSection(This->crst);
1942 return S_OK;
1945 static HRESULT WINAPI DS8Buffer3D_GetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE *maxdist)
1947 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1948 ALfloat dist;
1950 TRACE("(%p)->(%p)\n", This, maxdist);
1951 if(!maxdist)
1953 WARN("Invalid pointer\n");
1954 return DSERR_INVALIDPARAM;
1957 EnterCriticalSection(This->crst);
1958 setALContext(This->ctx);
1960 alGetSourcef(This->source, AL_MAX_DISTANCE, &dist);
1961 getALError();
1962 *maxdist = dist;
1964 popALContext();
1965 LeaveCriticalSection(This->crst);
1967 return S_OK;
1970 static HRESULT WINAPI DS8Buffer3D_GetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE *mindist)
1972 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1973 ALfloat dist;
1975 TRACE("(%p)->(%p)\n", This, mindist);
1976 if(!mindist)
1978 WARN("Invalid pointer\n");
1979 return DSERR_INVALIDPARAM;
1982 EnterCriticalSection(This->crst);
1983 setALContext(This->ctx);
1985 alGetSourcef(This->source, AL_REFERENCE_DISTANCE, &dist);
1986 getALError();
1987 *mindist = dist;
1989 popALContext();
1990 LeaveCriticalSection(This->crst);
1992 return S_OK;
1995 static HRESULT WINAPI DS8Buffer3D_GetMode(IDirectSound3DBuffer *iface, DWORD *mode)
1997 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1999 TRACE("(%p)->(%p)\n", This, mode);
2000 if(!mode)
2002 WARN("Invalid pointer\n");
2003 return DSERR_INVALIDPARAM;
2006 EnterCriticalSection(This->crst);
2007 *mode = This->ds3dmode;
2008 LeaveCriticalSection(This->crst);
2010 return S_OK;
2013 static HRESULT WINAPI DS8Buffer3D_GetPosition(IDirectSound3DBuffer *iface, D3DVECTOR *pos)
2015 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2016 ALfloat alpos[3];
2018 TRACE("(%p)->(%p)\n", This, pos);
2019 if(!pos)
2021 WARN("Invalid pointer\n");
2022 return DSERR_INVALIDPARAM;
2025 EnterCriticalSection(This->crst);
2026 setALContext(This->ctx);
2028 alGetSourcefv(This->source, AL_POSITION, alpos);
2029 getALError();
2030 pos->x = alpos[0];
2031 pos->y = alpos[1];
2032 pos->z = -alpos[2];
2034 popALContext();
2035 LeaveCriticalSection(This->crst);
2037 return S_OK;
2040 static HRESULT WINAPI DS8Buffer3D_GetVelocity(IDirectSound3DBuffer *iface, D3DVECTOR *vel)
2042 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2043 ALfloat alvel[3];
2045 TRACE("(%p)->(%p)\n", This, vel);
2046 if(!vel)
2048 WARN("Invalid pointer\n");
2049 return DSERR_INVALIDPARAM;
2052 EnterCriticalSection(This->crst);
2053 setALContext(This->ctx);
2055 alGetSourcefv(This->source, AL_VELOCITY, alvel);
2056 getALError();
2057 vel->x = alvel[0];
2058 vel->y = alvel[1];
2059 vel->z = -alvel[2];
2061 popALContext();
2062 LeaveCriticalSection(This->crst);
2064 return S_OK;
2067 static HRESULT WINAPI DS8Buffer3D_SetAllParameters(IDirectSound3DBuffer *iface, const DS3DBUFFER *ds3dbuffer, DWORD apply)
2069 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2070 TRACE("(%p)->(%p, %u)\n", This, ds3dbuffer, apply);
2072 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
2074 WARN("Invalid DS3DBUFFER (%p, %u)\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
2075 return DSERR_INVALIDPARAM;
2078 if(ds3dbuffer->dwInsideConeAngle > DS3D_MAXCONEANGLE ||
2079 ds3dbuffer->dwOutsideConeAngle > DS3D_MAXCONEANGLE)
2081 WARN("Invalid cone angles (%u, %u)\n", ds3dbuffer->dwInsideConeAngle,
2082 ds3dbuffer->dwOutsideConeAngle);
2083 return DSERR_INVALIDPARAM;
2086 if(ds3dbuffer->lConeOutsideVolume > DSBVOLUME_MAX ||
2087 ds3dbuffer->lConeOutsideVolume < DSBVOLUME_MIN)
2089 WARN("Invalid cone outside volume (%d)\n", ds3dbuffer->lConeOutsideVolume);
2090 return DSERR_INVALIDPARAM;
2093 if(ds3dbuffer->flMaxDistance < 0.0f)
2095 WARN("Invalid max distance (%f)\n", ds3dbuffer->flMaxDistance);
2096 return DSERR_INVALIDPARAM;
2099 if(ds3dbuffer->flMinDistance < 0.0f)
2101 WARN("Invalid min distance (%f)\n", ds3dbuffer->flMinDistance);
2102 return DSERR_INVALIDPARAM;
2105 if(ds3dbuffer->dwMode != DS3DMODE_NORMAL &&
2106 ds3dbuffer->dwMode != DS3DMODE_HEADRELATIVE &&
2107 ds3dbuffer->dwMode != DS3DMODE_DISABLE)
2109 WARN("Invalid mode (%u)\n", ds3dbuffer->dwMode);
2110 return DSERR_INVALIDPARAM;
2113 EnterCriticalSection(This->crst);
2114 setALContext(This->ctx);
2115 IDirectSound3DBuffer_SetPosition(iface, ds3dbuffer->vPosition.x, ds3dbuffer->vPosition.y, ds3dbuffer->vPosition.z, apply);
2116 IDirectSound3DBuffer_SetVelocity(iface, ds3dbuffer->vVelocity.x, ds3dbuffer->vVelocity.y, ds3dbuffer->vVelocity.z, apply);
2117 IDirectSound3DBuffer_SetConeAngles(iface, ds3dbuffer->dwInsideConeAngle, ds3dbuffer->dwOutsideConeAngle, apply);
2118 IDirectSound3DBuffer_SetConeOrientation(iface, ds3dbuffer->vConeOrientation.x, ds3dbuffer->vConeOrientation.y, ds3dbuffer->vConeOrientation.z, apply);
2119 IDirectSound3DBuffer_SetConeOutsideVolume(iface, ds3dbuffer->lConeOutsideVolume, apply);
2120 IDirectSound3DBuffer_SetMinDistance(iface, ds3dbuffer->flMinDistance, apply);
2121 IDirectSound3DBuffer_SetMaxDistance(iface, ds3dbuffer->flMaxDistance, apply);
2122 IDirectSound3DBuffer_SetMode(iface, ds3dbuffer->dwMode, apply);
2123 popALContext();
2124 LeaveCriticalSection(This->crst);
2126 return S_OK;
2129 static HRESULT WINAPI DS8Buffer3D_SetConeAngles(IDirectSound3DBuffer *iface, DWORD dwInsideConeAngle, DWORD dwOutsideConeAngle, DWORD apply)
2131 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2133 TRACE("(%p)->(%u, %u, %u)\n", This, dwInsideConeAngle, dwOutsideConeAngle, apply);
2134 if(dwInsideConeAngle > DS3D_MAXCONEANGLE ||
2135 dwOutsideConeAngle > DS3D_MAXCONEANGLE)
2137 WARN("Invalid cone angles (%u, %u)\n", dwInsideConeAngle, dwOutsideConeAngle);
2138 return DSERR_INVALIDPARAM;
2141 EnterCriticalSection(This->crst);
2142 if(apply == DS3D_DEFERRED)
2144 This->ds3dbuffer.dwInsideConeAngle = dwInsideConeAngle;
2145 This->ds3dbuffer.dwOutsideConeAngle = dwOutsideConeAngle;
2146 This->dirty.bit.cone_angles = 1;
2148 else
2150 setALContext(This->ctx);
2151 alSourcei(This->source, AL_CONE_INNER_ANGLE, dwInsideConeAngle);
2152 alSourcei(This->source, AL_CONE_OUTER_ANGLE, dwOutsideConeAngle);
2153 getALError();
2154 popALContext();
2156 LeaveCriticalSection(This->crst);
2158 return S_OK;
2161 static HRESULT WINAPI DS8Buffer3D_SetConeOrientation(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2163 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2165 TRACE("(%p)->(%f, %f, %f, %u)\n", This, x, y, z, apply);
2167 EnterCriticalSection(This->crst);
2168 if(apply == DS3D_DEFERRED)
2170 This->ds3dbuffer.vConeOrientation.x = x;
2171 This->ds3dbuffer.vConeOrientation.y = y;
2172 This->ds3dbuffer.vConeOrientation.z = z;
2173 This->dirty.bit.cone_orient = 1;
2175 else
2177 setALContext(This->ctx);
2178 alSource3f(This->source, AL_DIRECTION, x, y, -z);
2179 getALError();
2180 popALContext();
2182 LeaveCriticalSection(This->crst);
2184 return S_OK;
2187 static HRESULT WINAPI DS8Buffer3D_SetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG vol, DWORD apply)
2189 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2191 TRACE("(%p)->(%u, %u)\n", This, vol, apply);
2192 if(vol < DSBVOLUME_MIN || vol > DSBVOLUME_MAX)
2194 WARN("Invalid volume (%u)\n", vol);
2195 return DSERR_INVALIDPARAM;
2198 EnterCriticalSection(This->crst);
2199 if(apply == DS3D_DEFERRED)
2201 This->ds3dbuffer.lConeOutsideVolume = vol;
2202 This->dirty.bit.cone_outsidevolume = 1;
2204 else
2206 setALContext(This->ctx);
2207 alSourcef(This->source, AL_CONE_OUTER_GAIN, mB_to_gain(vol));
2208 getALError();
2209 popALContext();
2211 LeaveCriticalSection(This->crst);
2213 return S_OK;
2216 static HRESULT WINAPI DS8Buffer3D_SetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE maxdist, DWORD apply)
2218 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2220 TRACE("(%p)->(%f, %u)\n", This, maxdist, apply);
2221 if(maxdist < 0.0f)
2223 WARN("Invalid max distance (%f)\n", maxdist);
2224 return DSERR_INVALIDPARAM;
2227 EnterCriticalSection(This->crst);
2228 if(apply == DS3D_DEFERRED)
2230 This->ds3dbuffer.flMaxDistance = maxdist;
2231 This->dirty.bit.max_distance = 1;
2233 else
2235 setALContext(This->ctx);
2236 alSourcef(This->source, AL_MAX_DISTANCE, maxdist);
2237 getALError();
2238 popALContext();
2240 LeaveCriticalSection(This->crst);
2242 return S_OK;
2245 static HRESULT WINAPI DS8Buffer3D_SetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE mindist, DWORD apply)
2247 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2249 TRACE("(%p)->(%f, %u)\n", This, mindist, apply);
2250 if(mindist < 0.0f)
2252 WARN("Invalid min distance (%f)\n", mindist);
2253 return DSERR_INVALIDPARAM;
2256 EnterCriticalSection(This->crst);
2257 if(apply == DS3D_DEFERRED)
2259 This->ds3dbuffer.flMinDistance = mindist;
2260 This->dirty.bit.min_distance = 1;
2262 else
2264 setALContext(This->ctx);
2265 alSourcef(This->source, AL_REFERENCE_DISTANCE, mindist);
2266 getALError();
2267 popALContext();
2269 LeaveCriticalSection(This->crst);
2271 return S_OK;
2274 static HRESULT WINAPI DS8Buffer3D_SetMode(IDirectSound3DBuffer *iface, DWORD mode, DWORD apply)
2276 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2278 TRACE("(%p)->(%u, %u)\n", This, mode, apply);
2279 if(mode != DS3DMODE_NORMAL && mode != DS3DMODE_HEADRELATIVE &&
2280 mode != DS3DMODE_DISABLE)
2282 WARN("Invalid mode (%u)\n", mode);
2283 return DSERR_INVALIDPARAM;
2286 EnterCriticalSection(This->crst);
2287 if(apply == DS3D_DEFERRED)
2289 This->ds3dbuffer.dwMode = mode;
2290 This->dirty.bit.mode = 1;
2292 else
2294 setALContext(This->ctx);
2295 alSourcei(This->source, AL_SOURCE_RELATIVE,
2296 (mode != DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE);
2297 alSourcef(This->source, AL_ROLLOFF_FACTOR,
2298 (mode == DS3DMODE_DISABLE) ? 0.0f : This->primary->rollofffactor);
2299 This->ds3dmode = mode;
2300 getALError();
2301 popALContext();
2303 LeaveCriticalSection(This->crst);
2305 return S_OK;
2308 static HRESULT WINAPI DS8Buffer3D_SetPosition(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2310 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2312 TRACE("(%p)->(%f, %f, %f, %u)\n", This, x, y, z, apply);
2314 EnterCriticalSection(This->crst);
2315 if(apply == DS3D_DEFERRED)
2317 This->ds3dbuffer.vPosition.x = x;
2318 This->ds3dbuffer.vPosition.y = y;
2319 This->ds3dbuffer.vPosition.z = z;
2320 This->dirty.bit.pos = 1;
2322 else
2324 setALContext(This->ctx);
2325 alSource3f(This->source, AL_POSITION, x, y, -z);
2326 getALError();
2327 popALContext();
2329 LeaveCriticalSection(This->crst);
2331 return S_OK;
2334 static HRESULT WINAPI DS8Buffer3D_SetVelocity(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2336 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2338 TRACE("(%p)->(%f, %f, %f, %u)\n", This, x, y, z, apply);
2340 EnterCriticalSection(This->crst);
2341 if(apply == DS3D_DEFERRED)
2343 This->ds3dbuffer.vVelocity.x = x;
2344 This->ds3dbuffer.vVelocity.y = y;
2345 This->ds3dbuffer.vVelocity.z = z;
2346 This->dirty.bit.vel = 1;
2348 else
2350 setALContext(This->ctx);
2351 alSource3f(This->source, AL_VELOCITY, x, y, -z);
2352 getALError();
2353 popALContext();
2355 LeaveCriticalSection(This->crst);
2357 return S_OK;
2360 static const IDirectSound3DBufferVtbl DS8Buffer3d_Vtbl =
2362 DS8Buffer3D_QueryInterface,
2363 DS8Buffer3D_AddRef,
2364 DS8Buffer3D_Release,
2365 DS8Buffer3D_GetAllParameters,
2366 DS8Buffer3D_GetConeAngles,
2367 DS8Buffer3D_GetConeOrientation,
2368 DS8Buffer3D_GetConeOutsideVolume,
2369 DS8Buffer3D_GetMaxDistance,
2370 DS8Buffer3D_GetMinDistance,
2371 DS8Buffer3D_GetMode,
2372 DS8Buffer3D_GetPosition,
2373 DS8Buffer3D_GetVelocity,
2374 DS8Buffer3D_SetAllParameters,
2375 DS8Buffer3D_SetConeAngles,
2376 DS8Buffer3D_SetConeOrientation,
2377 DS8Buffer3D_SetConeOutsideVolume,
2378 DS8Buffer3D_SetMaxDistance,
2379 DS8Buffer3D_SetMinDistance,
2380 DS8Buffer3D_SetMode,
2381 DS8Buffer3D_SetPosition,
2382 DS8Buffer3D_SetVelocity
2385 static inline DS8Buffer *impl_from_IDirectSoundNotify(IDirectSoundNotify *iface)
2387 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSoundNotify_iface);
2390 static HRESULT WINAPI DS8BufferNot_QueryInterface(IDirectSoundNotify *iface, REFIID riid, void **ppv)
2392 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2393 return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2396 static ULONG WINAPI DS8BufferNot_AddRef(IDirectSoundNotify *iface)
2398 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2399 LONG ret;
2401 InterlockedIncrement(&This->all_ref);
2402 ret = InterlockedIncrement(&This->not_ref);
2403 TRACE("new refcount %d\n", ret);
2405 return ret;
2408 static ULONG WINAPI DS8BufferNot_Release(IDirectSoundNotify *iface)
2410 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2411 LONG ret;
2413 ret = InterlockedDecrement(&This->not_ref);
2414 TRACE("new refcount %d\n", ret);
2415 if(InterlockedDecrement(&This->all_ref) == 0)
2416 DS8Buffer_Destroy(This);
2418 return ret;
2421 static HRESULT WINAPI DS8BufferNot_SetNotificationPositions(IDirectSoundNotify *iface, DWORD count, const DSBPOSITIONNOTIFY *notifications)
2423 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2424 DSBPOSITIONNOTIFY *nots;
2425 DWORD state;
2426 HRESULT hr;
2428 EnterCriticalSection(This->crst);
2429 hr = DSERR_INVALIDPARAM;
2430 if(count && !notifications)
2431 goto out;
2433 hr = IDirectSoundBuffer8_GetStatus(&This->IDirectSoundBuffer8_iface, &state);
2434 if(FAILED(hr))
2435 goto out;
2437 hr = DSERR_INVALIDCALL;
2438 if((state&DSBSTATUS_PLAYING))
2439 goto out;
2441 if(!count)
2443 HeapFree(GetProcessHeap(), 0, This->notify);
2444 This->notify = 0;
2445 This->nnotify = 0;
2446 hr = S_OK;
2448 else
2450 DWORD i;
2452 hr = DSERR_INVALIDPARAM;
2453 for(i = 0;i < count;++i)
2455 if(notifications[i].dwOffset >= This->buffer->buf_size &&
2456 notifications[i].dwOffset != (DWORD)DSBPN_OFFSETSTOP)
2457 goto out;
2460 hr = E_OUTOFMEMORY;
2461 nots = HeapAlloc(GetProcessHeap(), 0, count*sizeof(*nots));
2462 if(!nots)
2463 goto out;
2464 memcpy(nots, notifications, count*sizeof(*nots));
2466 HeapFree(GetProcessHeap(), 0, This->notify);
2467 This->notify = nots;
2468 This->nnotify = count;
2470 hr = S_OK;
2473 out:
2474 LeaveCriticalSection(This->crst);
2475 return hr;
2478 static const IDirectSoundNotifyVtbl DS8BufferNot_Vtbl =
2480 DS8BufferNot_QueryInterface,
2481 DS8BufferNot_AddRef,
2482 DS8BufferNot_Release,
2483 DS8BufferNot_SetNotificationPositions
2486 /* NOTE: Due to some apparent quirks in DSound, the listener properties are
2487 handled through secondary buffers. */
2488 static inline DS8Buffer *impl_from_IKsPropertySet(IKsPropertySet *iface)
2490 return CONTAINING_RECORD(iface, DS8Buffer, IKsPropertySet_iface);
2493 static HRESULT WINAPI DS8BufferProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
2495 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2496 return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2499 static ULONG WINAPI DS8BufferProp_AddRef(IKsPropertySet *iface)
2501 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2502 LONG ret;
2504 InterlockedIncrement(&This->all_ref);
2505 ret = InterlockedIncrement(&This->prop_ref);
2506 TRACE("new refcount %d\n", ret);
2508 return ret;
2511 static ULONG WINAPI DS8BufferProp_Release(IKsPropertySet *iface)
2513 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2514 LONG ret;
2516 ret = InterlockedDecrement(&This->prop_ref);
2517 TRACE("new refcount %d\n", ret);
2518 if(InterlockedDecrement(&This->all_ref) == 0)
2519 DS8Buffer_Destroy(This);
2521 return ret;
2524 static HRESULT WINAPI DS8BufferProp_Get(IKsPropertySet *iface,
2525 REFGUID guidPropSet, ULONG dwPropID,
2526 LPVOID pInstanceData, ULONG cbInstanceData,
2527 LPVOID pPropData, ULONG cbPropData,
2528 PULONG pcbReturned)
2530 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2531 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2533 TRACE("(%p)->(%s, %u, %p, %u, %p, %u, %p)\n", iface, debugstr_guid(guidPropSet),
2534 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData, pcbReturned);
2536 if(!pcbReturned)
2537 return E_POINTER;
2538 *pcbReturned = 0;
2540 #if 0
2541 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2544 else
2545 #endif
2547 /* Not a known buffer/source property. Pass it to the listener */
2548 hr = IKsPropertySet_Get(&This->primary->IKsPropertySet_iface, guidPropSet,
2549 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData,
2550 pcbReturned);
2553 return hr;
2556 static HRESULT WINAPI DS8BufferProp_Set(IKsPropertySet *iface,
2557 REFGUID guidPropSet, ULONG dwPropID,
2558 LPVOID pInstanceData, ULONG cbInstanceData,
2559 LPVOID pPropData, ULONG cbPropData)
2561 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2562 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2564 TRACE("(%p)->(%s, %u, %p, %u, %p, %u)\n", iface, debugstr_guid(guidPropSet),
2565 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData);
2567 #if 0
2568 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2571 else
2572 #endif
2574 /* Not a known buffer/source property. Pass it to the listener */
2575 hr = IKsPropertySet_Set(&This->primary->IKsPropertySet_iface, guidPropSet,
2576 dwPropID, pInstanceData, cbInstanceData, pPropData,
2577 cbPropData);
2580 return hr;
2583 static HRESULT WINAPI DS8BufferProp_QuerySupport(IKsPropertySet *iface,
2584 REFGUID guidPropSet, ULONG dwPropID,
2585 PULONG pTypeSupport)
2587 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2588 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2590 TRACE("(%p)->(%s, %u, %p)\n", iface, debugstr_guid(guidPropSet), dwPropID, pTypeSupport);
2592 if(!pTypeSupport)
2593 return E_POINTER;
2594 *pTypeSupport = 0;
2596 #if 0
2597 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2600 else
2601 #endif
2603 /* Not a known buffer/source property. Pass it to the listener */
2604 hr = IKsPropertySet_QuerySupport(&This->primary->IKsPropertySet_iface,
2605 guidPropSet, dwPropID, pTypeSupport);
2608 return hr;
2611 static const IKsPropertySetVtbl DS8BufferProp_Vtbl =
2613 DS8BufferProp_QueryInterface,
2614 DS8BufferProp_AddRef,
2615 DS8BufferProp_Release,
2616 DS8BufferProp_Get,
2617 DS8BufferProp_Set,
2618 DS8BufferProp_QuerySupport