Use a separate thread to handle timer events
[wine/multimedia.git] / buffer.c
blobeda0436a09bc9a14d0e3103d3ceeee0f5689aada
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;
83 static void trigger_notifies(DS8Buffer *buf, DWORD lastpos, DWORD curpos)
85 DWORD i;
86 for(i = 0;i < buf->nnotify;++i)
88 DSBPOSITIONNOTIFY *not = &buf->notify[i];
89 HANDLE event = not->hEventNotify;
90 DWORD ofs = not->dwOffset;
92 if(ofs == (DWORD)DSBPN_OFFSETSTOP)
94 SetEvent(event);
95 continue;
98 /* Wraparound case */
99 if(curpos < lastpos)
101 if(ofs < curpos || ofs >= lastpos)
102 SetEvent(event);
103 continue;
106 /* Normal case */
107 if(ofs >= lastpos && ofs < curpos)
108 SetEvent(event);
112 static void CALLBACK DS8Buffer_timer(UINT timerID, UINT msg, DWORD_PTR dwUser,
113 DWORD_PTR dw1, DWORD_PTR dw2)
115 (void)timerID;
116 (void)msg;
117 (void)dw1;
118 (void)dw2;
119 PostThreadMessageA(dwUser, WM_USER, 0, 0);
122 static void DS8Buffer_starttimer(DS8Primary *prim)
124 DWORD triggertime, res = DS_TIME_RES;
125 ALint refresh = FAKE_REFRESH_COUNT;
126 TIMECAPS time;
128 if(prim->timer_id)
129 return;
131 timeGetDevCaps(&time, sizeof(TIMECAPS));
133 alcGetIntegerv(prim->parent->device, ALC_REFRESH, 1, &refresh);
134 getALCError(prim->parent->device);
136 triggertime = 1000 / refresh;
137 if(triggertime < time.wPeriodMin)
138 triggertime = time.wPeriodMin;
139 TRACE("Calling timer every %u ms for %i refreshes per second\n", triggertime, refresh);
141 if (res < time.wPeriodMin)
142 res = time.wPeriodMin;
143 if (timeBeginPeriod(res) == TIMERR_NOCANDO)
144 WARN("Could not set minimum resolution, don't expect sound\n");
146 prim->timer_res = res;
147 prim->timer_id = timeSetEvent(triggertime, res, DS8Buffer_timer, prim->thread_id, TIME_PERIODIC|TIME_KILL_SYNCHRONOUS);
150 /* Should be called with critsect held and context set.. */
151 static void DS8Buffer_addnotify(DS8Buffer *buf)
153 DS8Buffer **list;
154 DWORD i;
156 list = buf->primary->notifies;
157 for(i = 0; i < buf->primary->nnotifies; ++i)
159 if(buf == list[i])
161 ERR("Buffer %p already in notification list\n", buf);
162 return;
165 if(buf->primary->nnotifies == buf->primary->sizenotifies)
167 list = HeapReAlloc(GetProcessHeap(), 0, list, (buf->primary->nnotifies + 1) * sizeof(*list));
168 if(!list)
169 return;
170 buf->primary->sizenotifies++;
172 list[buf->primary->nnotifies++] = buf;
173 buf->primary->notifies = list;
176 static void DS8Buffer_removenotify(DS8Buffer *buf)
178 DWORD i;
179 for(i = 0; i < buf->primary->nnotifies; ++i)
181 if(buf == buf->primary->notifies[i])
183 buf->primary->notifies[i] =
184 buf->primary->notifies[--buf->primary->nnotifies];
185 return;
190 static const char *get_fmtstr_PCM(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out, ALenum *in_chans, ALenum *in_type)
192 out->Format = *format;
193 out->Format.cbSize = 0;
195 if(format->wBitsPerSample == 8)
197 *in_type = AL_UNSIGNED_BYTE;
198 switch(format->nChannels)
200 case 1: *in_chans = AL_MONO;
201 return "AL_FORMAT_MONO8";
202 case 2: *in_chans = AL_STEREO;
203 return "AL_FORMAT_STEREO8";
204 case 4: *in_chans = AL_QUAD;
205 return "AL_FORMAT_QUAD8";
206 case 6: *in_chans = AL_5POINT1;
207 return "AL_FORMAT_51CHN8";
208 case 7: *in_chans = AL_6POINT1;
209 return "AL_FORMAT_61CHN8";
210 case 8: *in_chans = AL_7POINT1;
211 return "AL_FORMAT_71CHN8";
212 default: break;
215 else if(format->wBitsPerSample == 16)
217 *in_type = AL_SHORT;
218 switch(format->nChannels)
220 case 1: *in_chans = AL_MONO;
221 return "AL_FORMAT_MONO16";
222 case 2: *in_chans = AL_STEREO;
223 return "AL_FORMAT_STEREO16";
224 case 4: *in_chans = AL_QUAD;
225 return "AL_FORMAT_QUAD16";
226 case 6: *in_chans = AL_5POINT1;
227 return "AL_FORMAT_51CHN16";
228 case 7: *in_chans = AL_6POINT1;
229 return "AL_FORMAT_61CHN16";
230 case 8: *in_chans = AL_7POINT1;
231 return "AL_FORMAT_71CHN16";
232 default: break;
235 #if 0 /* Will cause incorrect byte offsets */
236 else if(format->wBitsPerSample == 24 && prim->SupportedExt[SOFT_BUFFER_SAMPLES])
238 *in_type = AL_BYTE3;
239 switch(format->nChannels)
241 case 1: *in_chans = AL_MONO;
242 return "AL_MONO32F";
243 case 2: *in_chans = AL_STEREO;
244 return "AL_STEREO32F";
245 case 4: *in_chans = AL_QUAD;
246 return "AL_QUAD32F";
247 case 6: *in_chans = AL_5POINT1;
248 return "AL_5POINT1_32F";
249 case 7: *in_chans = AL_6POINT1;
250 return "AL_6POINT1_32F";
251 case 8: *in_chans = AL_7POINT1;
252 return "AL_7POINT1_32F";
253 default: break;
256 #endif
257 else if(format->wBitsPerSample == 32 && prim->SupportedExt[SOFT_BUFFER_SAMPLES])
259 *in_type = AL_INT;
260 switch(format->nChannels)
262 case 1: *in_chans = AL_MONO;
263 return "AL_MONO32F";
264 case 2: *in_chans = AL_STEREO;
265 return "AL_STEREO32F";
266 case 4: *in_chans = AL_QUAD;
267 return "AL_QUAD32F";
268 case 6: *in_chans = AL_5POINT1;
269 return "AL_5POINT1_32F";
270 case 7: *in_chans = AL_6POINT1;
271 return "AL_6POINT1_32F";
272 case 8: *in_chans = AL_7POINT1;
273 return "AL_7POINT1_32F";
274 default: break;
278 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
279 format->wBitsPerSample, format->nChannels);
280 return NULL;
283 static const char *get_fmtstr_FLOAT(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out, ALenum *in_chans, ALenum *in_type)
285 out->Format = *format;
286 out->Format.cbSize = 0;
288 if(format->wBitsPerSample == 32 &&
289 (prim->SupportedExt[EXT_FLOAT32] || prim->SupportedExt[SOFT_BUFFER_SAMPLES]))
291 *in_type = AL_FLOAT;
292 switch(format->nChannels)
294 case 1: *in_chans = AL_MONO;
295 return "AL_FORMAT_MONO_FLOAT32";
296 case 2: *in_chans = AL_STEREO;
297 return "AL_FORMAT_STEREO_FLOAT32";
298 case 4: *in_chans = AL_QUAD;
299 return "AL_FORMAT_QUAD32";
300 case 6: *in_chans = AL_5POINT1;
301 return "AL_FORMAT_51CHN32";
302 case 7: *in_chans = AL_6POINT1;
303 return "AL_FORMAT_61CHN32";
304 case 8: *in_chans = AL_7POINT1;
305 return "AL_FORMAT_71CHN32";
306 default: break;
309 #if 0 /* Will cause incorrect byte offsets */
310 else if(format->wBitsPerSample == 64 && prim->SupportedExt[SOFT_BUFFER_SAMPLES])
312 *in_type = AL_DOUBLE;
313 switch(format->nChannels)
315 case 1: *in_chans = AL_MONO;
316 return "AL_MONO32F";
317 case 2: *in_chans = AL_STEREO;
318 return "AL_STEREO32F";
319 case 4: *in_chans = AL_QUAD;
320 return "AL_QUAD32F";
321 case 6: *in_chans = AL_5POINT1;
322 return "AL_5POINT1_32F";
323 case 7: *in_chans = AL_6POINT1;
324 return "AL_6POINT1_32F";
325 case 8: *in_chans = AL_7POINT1;
326 return "AL_7POINT1_32F";
327 default: break;
330 #endif
332 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
333 format->wBitsPerSample, format->nChannels);
334 return NULL;
337 /* Speaker configs */
338 #define MONO SPEAKER_FRONT_CENTER
339 #define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)
340 #define REAR (SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
341 #define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
342 #define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
343 #define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
344 #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)
346 static const char *get_fmtstr_EXT(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out, ALenum *in_chans, ALenum *in_type)
348 *out = *(const WAVEFORMATEXTENSIBLE*)format;
349 out->Format.cbSize = sizeof(*out) - sizeof(out->Format);
351 if(!out->Samples.wValidBitsPerSample)
352 out->Samples.wValidBitsPerSample = out->Format.wBitsPerSample;
353 else if(out->Samples.wValidBitsPerSample != out->Format.wBitsPerSample)
355 FIXME("Padded samples not supported (%u of %u)\n", out->Samples.wValidBitsPerSample, out->Format.wBitsPerSample);
356 return NULL;
359 if(out->dwChannelMask != MONO && out->dwChannelMask != STEREO &&
360 !prim->SupportedExt[EXT_MCFORMATS] && !prim->SupportedExt[SOFT_BUFFER_SAMPLES])
362 WARN("Multi-channel not available\n");
363 return NULL;
366 if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
368 if(out->Samples.wValidBitsPerSample == 8)
370 *in_type = AL_UNSIGNED_BYTE;
371 switch(out->dwChannelMask)
373 case MONO: *in_chans = AL_MONO;
374 return "AL_FORMAT_MONO8";
375 case STEREO: *in_chans = AL_STEREO;
376 return "AL_FORMAT_STEREO8";
377 case REAR: *in_chans = AL_REAR;
378 return "AL_FORMAT_REAR8";
379 case QUAD: *in_chans = AL_QUAD;
380 return "AL_FORMAT_QUAD8";
381 case X5DOT1: *in_chans = AL_5POINT1;
382 return "AL_FORMAT_51CHN8";
383 case X6DOT1: *in_chans = AL_6POINT1;
384 return "AL_FORMAT_61CHN8";
385 case X7DOT1: *in_chans = AL_7POINT1;
386 return "AL_FORMAT_71CHN8";
387 default: break;
390 else if(out->Samples.wValidBitsPerSample == 16)
392 *in_type = AL_SHORT;
393 switch(out->dwChannelMask)
395 case MONO: *in_chans = AL_MONO;
396 return "AL_FORMAT_MONO16";
397 case STEREO: *in_chans = AL_STEREO;
398 return "AL_FORMAT_STEREO16";
399 case REAR: *in_chans = AL_REAR;
400 return "AL_FORMAT_REAR16";
401 case QUAD: *in_chans = AL_QUAD;
402 return "AL_FORMAT_QUAD16";
403 case X5DOT1: *in_chans = AL_5POINT1;
404 return "AL_FORMAT_51CHN16";
405 case X6DOT1: *in_chans = AL_6POINT1;
406 return "AL_FORMAT_61CHN16";
407 case X7DOT1: *in_chans = AL_7POINT1;
408 return "AL_FORMAT_71CHN16";
409 default: break;
412 #if 0
413 else if(out->Samples.wValidBitsPerSample == 24 &&
414 prim->SupportedExt[SOFT_BUFFER_SAMPLES])
416 *in_type = AL_BYTE3;
417 switch(out->dwChannelMask)
419 case MONO: *in_chans = AL_MONO;
420 return "AL_MONO32F";
421 case STEREO: *in_chans = AL_STEREO;
422 return "AL_STEREO32F";
423 case REAR: *in_chans = AL_REAR;
424 return "AL_REAR32F";
425 case QUAD: *in_chans = AL_QUAD;
426 return "AL_QUAD32F";
427 case X5DOT1: *in_chans = AL_5POINT1;
428 return "AL_5POINT1_32F";
429 case X6DOT1: *in_chans = AL_6POINT1;
430 return "AL_6POINT1_32F";
431 case X7DOT1: *in_chans = AL_7POINT1;
432 return "AL_7POINT1_32F";
433 default: break;
436 #endif
437 else if(out->Samples.wValidBitsPerSample == 32 &&
438 prim->SupportedExt[SOFT_BUFFER_SAMPLES])
440 *in_type = AL_INT;
441 switch(out->dwChannelMask)
443 case MONO: *in_chans = AL_MONO;
444 return "AL_MONO32F";
445 case STEREO: *in_chans = AL_STEREO;
446 return "AL_STEREO32F";
447 case REAR: *in_chans = AL_REAR;
448 return "AL_REAR32F";
449 case QUAD: *in_chans = AL_QUAD;
450 return "AL_QUAD32F";
451 case X5DOT1: *in_chans = AL_5POINT1;
452 return "AL_5POINT1_32F";
453 case X6DOT1: *in_chans = AL_6POINT1;
454 return "AL_6POINT1_32F";
455 case X7DOT1: *in_chans = AL_7POINT1;
456 return "AL_7POINT1_32F";
457 default: break;
461 FIXME("Could not get OpenAL PCM format (%d-bit, channelmask %#x)\n",
462 out->Samples.wValidBitsPerSample, out->dwChannelMask);
463 return NULL;
465 else if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) &&
466 (prim->SupportedExt[EXT_FLOAT32] || prim->SupportedExt[SOFT_BUFFER_SAMPLES]))
468 if(out->Samples.wValidBitsPerSample == 32)
470 *in_type = AL_FLOAT;
471 switch(out->dwChannelMask)
473 case MONO: *in_chans = AL_MONO;
474 return "AL_FORMAT_MONO_FLOAT32";
475 case STEREO: *in_chans = AL_STEREO;
476 return "AL_FORMAT_STEREO_FLOAT32";
477 case REAR: *in_chans = AL_REAR;
478 return "AL_FORMAT_REAR32";
479 case QUAD: *in_chans = AL_QUAD;
480 return "AL_FORMAT_QUAD32";
481 case X5DOT1: *in_chans = AL_5POINT1;
482 return "AL_FORMAT_51CHN32";
483 case X6DOT1: *in_chans = AL_6POINT1;
484 return "AL_FORMAT_61CHN32";
485 case X7DOT1: *in_chans = AL_7POINT1;
486 return "AL_FORMAT_71CHN32";
487 default: break;
490 #if 0
491 else if(out->Samples.wValidBitsPerSample == 64 &&
492 prim->SupportedExt[SOFT_BUFFER_SAMPLES])
494 *in_type = AL_DOUBLE;
495 switch(out->dwChannelMask)
497 case MONO: *in_chans = AL_MONO;
498 return "AL_MONO32F";
499 case STEREO: *in_chans = AL_STEREO;
500 return "AL_STEREO32F";
501 case REAR: *in_chans = AL_REAR;
502 return "AL_REAR32F";
503 case QUAD: *in_chans = AL_QUAD;
504 return "AL_QUAD32F";
505 case X5DOT1: *in_chans = AL_5POINT1;
506 return "AL_5POINT1_32F";
507 case X6DOT1: *in_chans = AL_6POINT1;
508 return "AL_6POINT1_32F";
509 case X7DOT1: *in_chans = AL_7POINT1;
510 return "AL_7POINT1_32F";
511 default: break;
514 #endif
515 else
517 WARN("Invalid float bits: %u\n", out->Samples.wValidBitsPerSample);
518 return NULL;
521 FIXME("Could not get OpenAL float format (%d-bit, channelmask %#x)\n",
522 out->Samples.wValidBitsPerSample, out->dwChannelMask);
523 return NULL;
525 else if(!IsEqualGUID(&out->SubFormat, &GUID_NULL))
526 ERR("Unhandled extensible format: %s\n", debugstr_guid(&out->SubFormat));
527 return NULL;
530 static void DS8Data_Release(DS8Data *This);
531 static HRESULT DS8Data_Create(DS8Data **ppv, const DSBUFFERDESC *desc, DS8Primary *prim)
533 HRESULT hr = DSERR_INVALIDPARAM;
534 const WAVEFORMATEX *format;
535 const char *fmt_str = NULL;
536 DS8Data *pBuffer;
538 format = desc->lpwfxFormat;
539 TRACE("Requested buffer format:\n"
540 " FormatTag = 0x%04x\n"
541 " Channels = %d\n"
542 " SamplesPerSec = %u\n"
543 " AvgBytesPerSec = %u\n"
544 " BlockAlign = %d\n"
545 " BitsPerSample = %d\n",
546 format->wFormatTag, format->nChannels,
547 format->nSamplesPerSec, format->nAvgBytesPerSec,
548 format->nBlockAlign, format->wBitsPerSample);
550 if(format->nBlockAlign == 0)
552 WARN("Invalid BlockAlign specified\n");
553 return DSERR_INVALIDPARAM;
556 /* Generate a new buffer. Supporting the DSBCAPS_LOC* flags properly
557 * will need the EAX-RAM extension. Currently, we just tell the app it
558 * gets what it wanted. */
559 pBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pBuffer));
560 if(!pBuffer)
561 return E_OUTOFMEMORY;
562 pBuffer->ref = 1;
564 pBuffer->dsbflags = desc->dwFlags;
565 if((pBuffer->dsbflags&(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE)) == (DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE))
567 WARN("Hardware and software location requested\n");
568 goto fail;
570 if(!(pBuffer->dsbflags&(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE|DSBCAPS_LOCDEFER)))
571 pBuffer->dsbflags |= DSBCAPS_LOCHARDWARE;
573 pBuffer->buf_size = desc->dwBufferBytes + format->nBlockAlign - 1;
574 pBuffer->buf_size -= pBuffer->buf_size%format->nBlockAlign;
576 hr = DSERR_BUFFERTOOSMALL;
577 if(pBuffer->buf_size < DSBSIZE_MIN)
578 goto fail;
580 hr = DSERR_INVALIDPARAM;
581 if(pBuffer->buf_size > DSBSIZE_MAX)
582 goto fail;
584 pBuffer->numsegs = 1;
585 pBuffer->segsize = pBuffer->buf_size;
586 pBuffer->lastsegsize = pBuffer->buf_size;
588 if(!(pBuffer->dsbflags&DSBCAPS_STATIC) && !prim->ExtAL.BufferSubData &&
589 !prim->ExtAL.BufferSamplesSOFT && !prim->ExtAL.BufferDataStatic)
591 ALCint refresh = FAKE_REFRESH_COUNT;
592 ALuint newSize;
594 alcGetIntegerv(prim->parent->device, ALC_REFRESH, 1, &refresh);
595 getALCError(prim->parent->device);
597 newSize = format->nAvgBytesPerSec/refresh + format->nBlockAlign - 1;
598 newSize -= newSize%format->nBlockAlign;
600 /* Make sure enough buffers are available */
601 if(newSize > pBuffer->buf_size/(QBUFFERS+2))
602 ERR("Buffer segments too large to stream (%u for %u)!\n",
603 newSize, pBuffer->buf_size);
604 else
606 pBuffer->numsegs = pBuffer->buf_size/newSize;
607 pBuffer->segsize = newSize;
608 pBuffer->lastsegsize = pBuffer->buf_size - (newSize*(pBuffer->numsegs-1));
609 TRACE("New streaming buffer (%u chunks, %u : %u sizes)\n",
610 pBuffer->numsegs, pBuffer->segsize, pBuffer->lastsegsize);
614 if(format->wFormatTag == WAVE_FORMAT_PCM)
615 fmt_str = get_fmtstr_PCM(prim, format, &pBuffer->format, &pBuffer->in_chans, &pBuffer->in_type);
616 else if(format->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
617 fmt_str = get_fmtstr_FLOAT(prim, format, &pBuffer->format, &pBuffer->in_chans, &pBuffer->in_type);
618 else if(format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
620 const WAVEFORMATEXTENSIBLE *wfe;
622 hr = DSERR_CONTROLUNAVAIL;
623 if(format->cbSize != sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) &&
624 format->cbSize != sizeof(WAVEFORMATEXTENSIBLE))
625 goto fail;
627 wfe = (const WAVEFORMATEXTENSIBLE*)format;
628 TRACE("Extensible values:\n"
629 " Samples = %d\n"
630 " ChannelMask = %#x\n"
631 " SubFormat = %s\n",
632 wfe->Samples.wReserved, wfe->dwChannelMask,
633 debugstr_guid(&wfe->SubFormat));
635 hr = DSERR_INVALIDCALL;
636 fmt_str = get_fmtstr_EXT(prim, format, &pBuffer->format, &pBuffer->in_chans, &pBuffer->in_type);
638 else
639 ERR("Unhandled formattag 0x%04x\n", format->wFormatTag);
641 if(!fmt_str)
642 goto fail;
644 pBuffer->buf_format = alGetEnumValue(fmt_str);
645 if(alGetError() != AL_NO_ERROR || pBuffer->buf_format == 0 ||
646 pBuffer->buf_format == -1)
648 WARN("Could not get OpenAL format from %s\n", fmt_str);
649 goto fail;
652 hr = E_OUTOFMEMORY;
653 pBuffer->buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pBuffer->buffers)*pBuffer->numsegs);
654 pBuffer->data = HeapAlloc(GetProcessHeap(), 0, pBuffer->buf_size);
655 if(!pBuffer->buffers || !pBuffer->data)
656 goto fail;
658 alGenBuffers(pBuffer->numsegs, pBuffer->buffers);
659 getALError();
661 *ppv = pBuffer;
662 return S_OK;
664 fail:
665 DS8Data_Release(pBuffer);
666 return hr;
669 static void DS8Data_AddRef(DS8Data *data)
671 InterlockedIncrement(&data->ref);
674 /* This function is always called with the device lock held */
675 static void DS8Data_Release(DS8Data *This)
677 if(InterlockedDecrement(&This->ref)) return;
679 TRACE("Deleting %p\n", This);
680 if (This->buffers && This->buffers[0])
682 alDeleteBuffers(This->numsegs, This->buffers);
683 getALError();
685 HeapFree(GetProcessHeap(), 0, This->buffers);
686 HeapFree(GetProcessHeap(), 0, This->data);
687 HeapFree(GetProcessHeap(), 0, This);
690 HRESULT DS8Buffer_Create(DS8Buffer **ppv, DS8Primary *parent, DS8Buffer *orig)
692 HRESULT hr = DSERR_OUTOFMEMORY;
693 DS8Buffer *This;
694 DS8Buffer **bufs;
696 *ppv = NULL;
697 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
698 if(!This) return hr;
700 This->IDirectSoundBuffer8_iface.lpVtbl = (IDirectSoundBuffer8Vtbl*)&DS8Buffer_Vtbl;
701 This->IDirectSound3DBuffer_iface.lpVtbl = (IDirectSound3DBufferVtbl*)&DS8Buffer3d_Vtbl;
702 This->IDirectSoundNotify_iface.lpVtbl = (IDirectSoundNotifyVtbl*)&DS8BufferNot_Vtbl;
703 This->IKsPropertySet_iface.lpVtbl = (IKsPropertySetVtbl*)&DS8BufferProp_Vtbl;
705 This->primary = parent;
706 This->ctx = parent->ctx;
707 This->ExtAL = &parent->ExtAL;
708 This->crst = &parent->crst;
709 This->ref = This->all_ref = 1;
711 if(orig)
713 This->buffer = orig->buffer;
714 DS8Data_AddRef(This->buffer);
717 /* Append to buffer list */
718 bufs = parent->buffers;
719 if(parent->nbuffers == parent->sizebuffers)
721 bufs = HeapReAlloc(GetProcessHeap(), 0, bufs, sizeof(*bufs)*(1+parent->nbuffers));
722 if(!bufs) goto fail;
723 parent->sizebuffers++;
725 parent->buffers = bufs;
726 bufs[parent->nbuffers++] = This;
728 /* Disable until initialized.. */
729 This->ds3dmode = DS3DMODE_DISABLE;
731 *ppv = This;
732 return S_OK;
734 fail:
735 DS8Buffer_Destroy(This);
736 return hr;
739 void DS8Buffer_Destroy(DS8Buffer *This)
741 DWORD idx;
742 TRACE("Destroying %p\n", This);
744 DS8Buffer_removenotify(This);
746 /* Remove from list, if in list */
747 for(idx = 0;idx < This->primary->nbuffers;++idx)
749 if(This->primary->buffers[idx] == This)
751 This->primary->buffers[idx] = This->primary->buffers[This->primary->nbuffers-1];
752 This->primary->nbuffers--;
753 break;
756 setALContext(This->ctx);
757 if(This->source)
759 ALuint *sources;
761 alSourceStop(This->source);
762 alSourcei(This->source, AL_BUFFER, 0);
763 getALError();
765 sources = This->primary->sources;
766 if(This->primary->nsources == This->primary->sizesources)
768 sources = HeapReAlloc(GetProcessHeap(), 0, sources, sizeof(*sources)*(1+This->primary->nsources));
769 if(!sources)
770 alDeleteSources(1, &This->source);
771 else
772 This->primary->sizesources++;
774 if(sources)
776 sources[This->primary->nsources++] = This->source;
777 This->primary->sources = sources;
780 HeapFree(GetProcessHeap(), 0, This->notify);
781 This->source = 0;
782 if(This->buffer)
783 DS8Data_Release(This->buffer);
784 popALContext();
785 HeapFree(GetProcessHeap(), 0, This);
788 static inline DS8Buffer *impl_from_IDirectSoundBuffer8(IDirectSoundBuffer8 *iface)
790 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSoundBuffer8_iface);
793 static HRESULT WINAPI DS8Buffer_QueryInterface(IDirectSoundBuffer8 *iface, REFIID riid, void **ppv)
795 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
797 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
799 *ppv = NULL;
800 if(IsEqualIID(riid, &IID_IUnknown) ||
801 IsEqualIID(riid, &IID_IDirectSoundBuffer))
802 *ppv = &This->IDirectSoundBuffer8_iface;
803 else if(IsEqualIID(riid, &IID_IDirectSoundBuffer8))
805 if(This->primary->parent->is_8)
806 *ppv = &This->IDirectSoundBuffer8_iface;
808 else if(IsEqualIID(riid, &IID_IDirectSound3DBuffer))
810 if((This->buffer->dsbflags&DSBCAPS_CTRL3D))
811 *ppv = &This->IDirectSound3DBuffer_iface;
813 else if(IsEqualIID(riid, &IID_IDirectSoundNotify))
815 if((This->buffer->dsbflags&DSBCAPS_CTRLPOSITIONNOTIFY))
816 *ppv = &This->IDirectSoundNotify_iface;
818 else if(IsEqualIID(riid, &IID_IKsPropertySet))
819 *ppv = &This->IKsPropertySet_iface;
820 else
821 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
823 if(*ppv)
825 IUnknown_AddRef((IUnknown*)*ppv);
826 return S_OK;
829 return E_NOINTERFACE;
832 static ULONG WINAPI DS8Buffer_AddRef(IDirectSoundBuffer8 *iface)
834 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
835 LONG ret;
837 InterlockedIncrement(&This->all_ref);
838 ret = InterlockedIncrement(&This->ref);
839 TRACE("new refcount %d\n", ret);
841 return ret;
844 static ULONG WINAPI DS8Buffer_Release(IDirectSoundBuffer8 *iface)
846 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
847 LONG ret;
849 ret = InterlockedDecrement(&This->ref);
850 TRACE("new refcount %d\n", ret);
851 if(InterlockedDecrement(&This->all_ref) == 0)
852 DS8Buffer_Destroy(This);
854 return ret;
857 static HRESULT WINAPI DS8Buffer_GetCaps(IDirectSoundBuffer8 *iface, DSBCAPS *caps)
859 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
861 TRACE("(%p)->(%p)\n", iface, caps);
863 if(!caps || caps->dwSize < sizeof(*caps))
865 WARN("Invalid DSBCAPS (%p, %u)\n", caps, (caps ? caps->dwSize : 0));
866 return DSERR_INVALIDPARAM;
869 caps->dwFlags = This->buffer->dsbflags;
870 caps->dwBufferBytes = This->buffer->buf_size;
871 caps->dwUnlockTransferRate = 4096;
872 caps->dwPlayCpuOverhead = 0;
873 return S_OK;
876 static HRESULT WINAPI DS8Buffer_GetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD *playpos, DWORD *curpos)
878 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
879 WAVEFORMATEX *format = &This->buffer->format.Format;
880 UINT writecursor, pos;
882 TRACE("(%p)->(%p, %p)\n", iface, playpos, curpos);
884 EnterCriticalSection(This->crst);
885 setALContext(This->ctx);
887 if(This->buffer->numsegs > 1)
889 ALint queued = QBUFFERS;
890 alGetSourcei(This->source, AL_BUFFERS_QUEUED, &queued);
891 getALError();
893 pos = (This->curidx+This->buffer->numsegs-queued)%This->buffer->numsegs;
894 pos *= This->buffer->segsize;
895 writecursor = This->curidx * This->buffer->segsize;
897 else if(This->ExtAL->BufferSubData || This->ExtAL->BufferSamplesSOFT)
899 ALint rwpos[2] = { 0, 0 };
901 alGetSourceiv(This->source, AL_BYTE_RW_OFFSETS_SOFT, rwpos);
902 getALError();
904 pos = rwpos[0];
905 writecursor = rwpos[1];
907 else
909 ALint status = 0;
910 ALint ofs = 0;
912 alGetSourcei(This->source, AL_BYTE_OFFSET, &ofs);
913 alGetSourcei(This->source, AL_SOURCE_STATE, &status);
914 getALError();
916 pos = ofs;
917 if(status == AL_PLAYING)
919 writecursor = format->nSamplesPerSec / 100;
920 writecursor *= format->nBlockAlign;
922 else
923 writecursor = 0;
924 writecursor = (writecursor + pos) % This->buffer->buf_size;
926 TRACE("%p Play pos = %u, write pos = %u\n", This, pos, writecursor);
927 if(pos >= This->buffer->buf_size)
929 ERR("playpos >= buf_size\n");
930 pos %= This->buffer->buf_size;
932 if(writecursor >= This->buffer->buf_size)
934 ERR("writepos >= buf_size\n");
935 writecursor %= This->buffer->buf_size;
938 if(playpos) *playpos = pos;
939 if(curpos) *curpos = writecursor;
941 popALContext();
942 LeaveCriticalSection(This->crst);
944 return S_OK;
947 static HRESULT WINAPI DS8Buffer_GetFormat(IDirectSoundBuffer8 *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
949 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
950 HRESULT hr = S_OK;
951 UINT size;
953 TRACE("(%p)->(%p, %u, %p)\n", iface, wfx, allocated, written);
955 if(!wfx && !written)
957 WARN("Cannot report format or format size\n");
958 return DSERR_INVALIDPARAM;
961 EnterCriticalSection(This->crst);
962 size = sizeof(This->buffer->format.Format) + This->buffer->format.Format.cbSize;
963 if(wfx)
965 if(allocated < size)
966 hr = DSERR_INVALIDPARAM;
967 else
968 memcpy(wfx, &This->buffer->format.Format, size);
970 if(written)
971 *written = size;
972 LeaveCriticalSection(This->crst);
974 return hr;
977 static HRESULT WINAPI DS8Buffer_GetVolume(IDirectSoundBuffer8 *iface, LONG *vol)
979 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
980 HRESULT hr;
982 TRACE("(%p)->(%p)\n", iface, vol);
984 if(!vol)
986 WARN("Invalid pointer\n");
987 return DSERR_INVALIDPARAM;
990 EnterCriticalSection(This->crst);
992 hr = DSERR_CONTROLUNAVAIL;
993 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
994 WARN("Volume control not set\n");
995 else
997 ALfloat gain = 1.0f;
999 setALContext(This->ctx);
1000 alGetSourcef(This->source, AL_GAIN, &gain);
1001 getALError();
1002 popALContext();
1004 *vol = gain_to_mB(gain);
1005 *vol = min(*vol, DSBVOLUME_MAX);
1006 *vol = max(*vol, DSBVOLUME_MIN);
1008 hr = DS_OK;
1011 LeaveCriticalSection(This->crst);
1012 return hr;
1015 static HRESULT WINAPI DS8Buffer_GetPan(IDirectSoundBuffer8 *iface, LONG *pan)
1017 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1018 HRESULT hr;
1020 TRACE("(%p)->(%p)\n", iface, pan);
1022 if(!pan)
1024 WARN("Invalid pointer\n");
1025 return DSERR_INVALIDPARAM;
1028 EnterCriticalSection(This->crst);
1030 hr = DSERR_CONTROLUNAVAIL;
1031 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
1032 WARN("Panning control not set\n");
1033 else
1035 ALfloat pos[3];
1037 setALContext(This->ctx);
1038 alGetSourcefv(This->source, AL_POSITION, pos);
1039 getALError();
1040 popALContext();
1042 *pan = (LONG)((pos[0]+1.0) * (DSBPAN_RIGHT-DSBPAN_LEFT) / 2.0 + 0.5) + DSBPAN_LEFT;
1043 *pan = min(*pan, DSBPAN_RIGHT);
1044 *pan = max(*pan, DSBPAN_LEFT);
1046 hr = DS_OK;
1049 LeaveCriticalSection(This->crst);
1050 return hr;
1053 static HRESULT WINAPI DS8Buffer_GetFrequency(IDirectSoundBuffer8 *iface, DWORD *freq)
1055 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1056 HRESULT hr;
1058 TRACE("(%p)->(%p)\n", iface, freq);
1060 if(!freq)
1062 WARN("Invalid pointer\n");
1063 return DSERR_INVALIDPARAM;
1066 EnterCriticalSection(This->crst);
1068 hr = DSERR_CONTROLUNAVAIL;
1069 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
1070 WARN("Frequency control not set\n");
1071 else
1073 ALfloat pitch = 1.0f;
1075 setALContext(This->ctx);
1076 alGetSourcefv(This->source, AL_PITCH, &pitch);
1077 getALError();
1078 popALContext();
1080 *freq = (DWORD)(This->buffer->format.Format.nSamplesPerSec * pitch);
1082 hr = DS_OK;
1085 LeaveCriticalSection(This->crst);
1086 return hr;
1089 static HRESULT WINAPI DS8Buffer_GetStatus(IDirectSoundBuffer8 *iface, DWORD *status)
1091 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1092 ALint state, looping;
1094 TRACE("(%p)->(%p)\n", iface, status);
1096 if(!status)
1098 WARN("Invalid pointer\n");
1099 return DSERR_INVALIDPARAM;
1102 EnterCriticalSection(This->crst);
1104 setALContext(This->ctx);
1105 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1106 looping = This->islooping;
1107 if(This->buffer->numsegs == 1)
1108 alGetSourcei(This->source, AL_LOOPING, &looping);
1109 else if(state != AL_PLAYING)
1110 state = This->isplaying ? AL_PLAYING : AL_PAUSED;
1111 getALError();
1112 popALContext();
1114 *status = 0;
1115 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1117 if((This->buffer->dsbflags&DSBCAPS_LOCSOFTWARE))
1118 *status |= DSBSTATUS_LOCSOFTWARE;
1119 else if((This->buffer->dsbflags&DSBCAPS_LOCHARDWARE))
1120 *status |= DSBSTATUS_LOCHARDWARE;
1122 if(state == AL_PLAYING)
1123 *status |= DSBSTATUS_PLAYING | (looping ? DSBSTATUS_LOOPING : 0);
1125 LeaveCriticalSection(This->crst);
1127 return S_OK;
1130 static HRESULT WINAPI DS8Buffer_Initialize(IDirectSoundBuffer8 *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
1132 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1133 DS3DBUFFER *ds3dbuffer;
1134 HRESULT hr;
1136 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
1138 EnterCriticalSection(This->crst);
1139 setALContext(This->ctx);
1141 hr = DSERR_ALREADYINITIALIZED;
1142 if(This->source)
1143 goto out;
1145 if(!This->buffer)
1147 hr = DSERR_INVALIDPARAM;
1148 if(!desc)
1150 WARN("Missing DSound buffer description\n");
1151 goto out;
1153 if(!desc->lpwfxFormat)
1155 WARN("Missing buffer format (%p)\n", This);
1156 goto out;
1158 if((desc->dwFlags&DSBCAPS_CTRL3D) && desc->lpwfxFormat->nChannels != 1)
1160 if(This->primary->parent->is_8)
1162 /* DirectSoundBuffer8 objects aren't allowed non-mono 3D
1163 * buffers */
1164 WARN("Can't create multi-channel 3D buffers\n");
1165 goto out;
1167 ERR("Multi-channel 3D sounds are not spatialized\n");
1170 hr = DS8Data_Create(&This->buffer, desc, This->primary);
1171 if(FAILED(hr))
1172 goto out;
1173 else
1175 DS8Data *buf = This->buffer;
1177 if(buf->in_type == AL_UNSIGNED_BYTE)
1178 memset(buf->data, 0x80, buf->buf_size);
1179 else
1180 memset(buf->data, 0x00, buf->buf_size);
1182 if(This->ExtAL->BufferDataStatic)
1183 This->ExtAL->BufferDataStatic(buf->buffers[0], buf->buf_format,
1184 buf->data, buf->buf_size,
1185 buf->format.Format.nSamplesPerSec);
1186 else if(This->ExtAL->BufferSamplesSOFT)
1187 This->ExtAL->BufferSamplesSOFT(buf->buffers[0],
1188 buf->format.Format.nSamplesPerSec, buf->buf_format,
1189 buf->buf_size/buf->format.Format.nBlockAlign,
1190 buf->in_chans, buf->in_type, buf->data);
1191 else if(This->ExtAL->BufferSubData)
1192 alBufferData(buf->buffers[0], buf->buf_format,
1193 buf->data, buf->buf_size,
1194 buf->format.Format.nSamplesPerSec);
1196 getALError();
1199 hr = DSERR_GENERIC;
1200 if(This->primary->nsources)
1202 This->source = This->primary->sources[--This->primary->nsources];
1203 alSourcef(This->source, AL_GAIN, 1.0f);
1204 alSourcef(This->source, AL_PITCH, 1.0f);
1205 getALError();
1207 else
1209 alGenSources(1, &This->source);
1210 if(alGetError() != AL_NO_ERROR)
1211 goto out;
1214 ds3dbuffer = &This->ds3dbuffer;
1215 ds3dbuffer->dwSize = sizeof(*ds3dbuffer);
1216 ds3dbuffer->vPosition.x = 0.0;
1217 ds3dbuffer->vPosition.y = 0.0;
1218 ds3dbuffer->vPosition.z = 0.0;
1219 ds3dbuffer->vVelocity.x = 0.0;
1220 ds3dbuffer->vVelocity.y = 0.0;
1221 ds3dbuffer->vVelocity.z = 0.0;
1222 ds3dbuffer->dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
1223 ds3dbuffer->dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
1224 ds3dbuffer->vConeOrientation.x = 0.0;
1225 ds3dbuffer->vConeOrientation.y = 0.0;
1226 ds3dbuffer->vConeOrientation.z = 1.0;
1227 ds3dbuffer->lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
1228 ds3dbuffer->flMinDistance = DS3D_DEFAULTMINDISTANCE;
1229 ds3dbuffer->flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
1230 ds3dbuffer->dwMode = DS3DMODE_NORMAL;
1232 if((This->buffer->dsbflags&DSBCAPS_CTRL3D))
1234 if(This->primary->auxslot != 0)
1236 alSource3i(This->source, AL_AUXILIARY_SEND_FILTER, This->primary->auxslot, 0, AL_FILTER_NULL);
1237 getALError();
1240 hr = IDirectSound3DBuffer_SetAllParameters(&This->IDirectSound3DBuffer_iface, ds3dbuffer, DS3D_IMMEDIATE);
1241 if(FAILED(hr))
1243 ERR("SetAllParameters failed\n");
1244 goto out;
1247 else
1249 ALuint source = This->source;
1251 if(This->primary->auxslot != 0)
1253 /* Simple hack to make reverb affect non-3D sounds too */
1254 alSource3i(source, AL_AUXILIARY_SEND_FILTER, This->primary->auxslot, 0, AL_FILTER_NULL);
1255 /*alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL);*/
1258 /* Non-3D sources aren't distance attenuated */
1259 This->ds3dmode = DS3DMODE_DISABLE;
1260 alSource3f(source, AL_POSITION, 0.0f, 1.0f, 0.0f);
1261 alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
1262 alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
1263 alSourcef(source, AL_CONE_OUTER_GAIN, 1.0f);
1264 alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f);
1265 alSourcef(source, AL_MAX_DISTANCE, 1000.0f);
1266 alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f);
1267 alSourcei(source, AL_CONE_INNER_ANGLE, 360);
1268 alSourcei(source, AL_CONE_OUTER_ANGLE, 360);
1269 alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);
1270 getALError();
1272 hr = S_OK;
1274 out:
1275 popALContext();
1276 LeaveCriticalSection(This->crst);
1278 return hr;
1281 static HRESULT WINAPI DS8Buffer_Lock(IDirectSoundBuffer8 *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
1283 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1284 HRESULT hr;
1285 DWORD remain;
1287 TRACE("(%p)->(%u, %u, %p, %p, %p, %p, 0x%x)\n", This, ofs, bytes, ptr1, len1, ptr2, len2, flags);
1289 if(!ptr1 || !len1)
1291 WARN("Invalid pointer/len %p %p\n", ptr1, len1);
1292 return DSERR_INVALIDPARAM;
1295 EnterCriticalSection(This->crst);
1296 setALContext(This->ctx);
1298 *ptr1 = NULL;
1299 *len1 = 0;
1300 if(ptr2) *ptr2 = NULL;
1301 if(len2) *len2 = 0;
1303 hr = DSERR_INVALIDPARAM;
1304 if((flags&DSBLOCK_FROMWRITECURSOR))
1305 DS8Buffer_GetCurrentPosition(iface, NULL, &ofs);
1306 else if(ofs >= This->buffer->buf_size)
1308 WARN("Invalid ofs %u\n", ofs);
1309 goto out;
1311 if((flags&DSBLOCK_ENTIREBUFFER))
1312 bytes = This->buffer->buf_size;
1313 else if(bytes > This->buffer->buf_size)
1315 WARN("Invalid size %u\n", bytes);
1316 goto out;
1319 *ptr1 = This->buffer->data + ofs;
1320 if(ofs+bytes >= This->buffer->buf_size)
1322 *len1 = This->buffer->buf_size - ofs;
1323 remain = bytes - *len1;
1325 else
1327 *len1 = bytes;
1328 remain = 0;
1331 This->buffer->locked = TRUE;
1333 if(ptr2 && len2 && remain)
1335 *ptr2 = This->buffer->data;
1336 *len2 = remain;
1338 hr = S_OK;
1340 out:
1341 popALContext();
1342 LeaveCriticalSection(This->crst);
1343 return hr;
1346 static HRESULT WINAPI DS8Buffer_Play(IDirectSoundBuffer8 *iface, DWORD res1, DWORD prio, DWORD flags)
1348 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1349 ALint type, state = AL_STOPPED;
1350 HRESULT hr;
1351 (void)res1;
1353 TRACE("%p\n", This);
1355 EnterCriticalSection(This->crst);
1356 setALContext(This->ctx);
1358 hr = DSERR_BUFFERLOST;
1359 if(This->bufferlost)
1361 WARN("Buffer %p lost\n", This);
1362 goto out;
1365 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1367 if(!(This->buffer->dsbflags&(DSBCAPS_LOCHARDWARE|DSBCAPS_LOCSOFTWARE)))
1369 if(flags & DSBPLAY_LOCSOFTWARE)
1370 This->buffer->dsbflags |= DSBCAPS_LOCSOFTWARE;
1371 else
1372 This->buffer->dsbflags |= DSBCAPS_LOCHARDWARE;
1375 else if(prio)
1377 ERR("Invalid priority set for non-deferred buffer %p, %u!\n", This->buffer, prio);
1378 hr = DSERR_INVALIDPARAM;
1379 goto out;
1382 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1383 if(This->buffer->numsegs > 1)
1385 This->islooping = !!(flags&DSBPLAY_LOOPING);
1386 if(state != AL_PLAYING && This->isplaying)
1387 state = AL_PLAYING;
1389 else
1391 alGetSourcei(This->source, AL_SOURCE_TYPE, &type);
1392 alSourcei(This->source, AL_LOOPING, (flags&DSBPLAY_LOOPING) ? AL_TRUE : AL_FALSE);
1394 getALError();
1396 hr = S_OK;
1397 if(state == AL_PLAYING)
1398 goto out;
1400 /* alSourceQueueBuffers will implicitly set type to streaming */
1401 if(This->buffer->numsegs == 1)
1403 if(type != AL_STATIC)
1404 alSourcei(This->source, AL_BUFFER, This->buffer->buffers[0]);
1405 alSourcePlay(This->source);
1407 if(alGetError() != AL_NO_ERROR)
1409 ERR("Couldn't start source\n");
1410 This->curidx = (This->buffer->numsegs-1+This->curidx)%This->buffer->numsegs;
1411 alSourcei(This->source, AL_BUFFER, 0);
1412 getALError();
1413 hr = DSERR_GENERIC;
1414 goto out;
1416 This->isplaying = TRUE;
1418 if(This->nnotify)
1420 DS8Buffer_addnotify(This);
1421 DS8Buffer_starttimer(This->primary);
1423 else if(This->buffer->numsegs > 1)
1424 DS8Buffer_starttimer(This->primary);
1426 out:
1427 popALContext();
1428 LeaveCriticalSection(This->crst);
1429 return hr;
1432 static HRESULT WINAPI DS8Buffer_SetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD pos)
1434 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1435 HRESULT hr;
1436 TRACE("%p\n", This);
1438 EnterCriticalSection(This->crst);
1439 setALContext(This->ctx);
1441 hr = DSERR_INVALIDPARAM;
1442 if(pos >= This->buffer->buf_size)
1443 goto out;
1445 if(This->buffer->numsegs > 1)
1447 DS8Data *buf = This->buffer;
1448 This->curidx = pos/buf->segsize;
1449 if(This->curidx >= buf->numsegs)
1450 This->curidx = buf->numsegs - 1;
1451 if(This->isplaying)
1453 alSourceStop(This->source);
1454 alSourcei(This->source, AL_BUFFER, 0);
1455 getALError();
1458 else
1459 alSourcei(This->source, AL_BYTE_OFFSET, pos);
1460 This->lastpos = pos;
1461 hr = S_OK;
1463 out:
1464 popALContext();
1465 LeaveCriticalSection(This->crst);
1466 return hr;
1469 static HRESULT WINAPI DS8Buffer_SetFormat(IDirectSoundBuffer8 *iface, const WAVEFORMATEX *wfx)
1471 /* This call only works on primary buffers */
1472 WARN("(%p)->(%p)\n", iface, wfx);
1473 return DSERR_INVALIDCALL;
1476 static HRESULT WINAPI DS8Buffer_SetVolume(IDirectSoundBuffer8 *iface, LONG vol)
1478 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1479 HRESULT hr = S_OK;
1481 TRACE("(%p)->(%d)\n", iface, vol);
1483 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
1485 WARN("Invalid volume (%d)\n", vol);
1486 return DSERR_INVALIDPARAM;
1489 EnterCriticalSection(This->crst);
1490 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
1491 hr = DSERR_CONTROLUNAVAIL;
1492 if(SUCCEEDED(hr))
1494 ALfloat fvol = mB_to_gain(vol);
1495 setALContext(This->ctx);
1496 alSourcef(This->source, AL_GAIN, fvol);
1497 popALContext();
1499 LeaveCriticalSection(This->crst);
1501 return hr;
1504 static HRESULT WINAPI DS8Buffer_SetPan(IDirectSoundBuffer8 *iface, LONG pan)
1506 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1507 HRESULT hr = S_OK;
1509 TRACE("(%p)->(%d)\n", iface, pan);
1511 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
1513 WARN("invalid parameter: pan = %d\n", pan);
1514 return DSERR_INVALIDPARAM;
1517 EnterCriticalSection(This->crst);
1518 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
1519 hr = DSERR_CONTROLUNAVAIL;
1520 else
1522 ALfloat pos[3];
1523 pos[0] = (pan-DSBPAN_LEFT) * 2.0 / (ALfloat)(DSBPAN_RIGHT-DSBPAN_LEFT) - 1.0;
1524 /* NOTE: Strict movement along the X plane can cause the sound to jump
1525 * between left and right sharply. Using a curved path helps smooth it
1526 * out */
1527 pos[1] = sqrt(1.0 - pos[0]*pos[0]);
1528 pos[2] = 0.0;
1530 setALContext(This->ctx);
1531 alSourcefv(This->source, AL_POSITION, pos);
1532 getALError();
1533 popALContext();
1535 if(pan != 0 && This->buffer->format.Format.nChannels > 1)
1536 FIXME("Panning for multi-channel buffers is not supported\n");
1538 LeaveCriticalSection(This->crst);
1540 return hr;
1543 static HRESULT WINAPI DS8Buffer_SetFrequency(IDirectSoundBuffer8 *iface, DWORD freq)
1545 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1546 HRESULT hr = S_OK;
1548 TRACE("(%p)->(%u)\n", iface, freq);
1550 if(freq < DSBFREQUENCY_MIN || freq > DSBFREQUENCY_MAX)
1552 WARN("invalid parameter: freq = %d\n", freq);
1553 return DSERR_INVALIDPARAM;
1556 EnterCriticalSection(This->crst);
1557 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
1558 hr = DSERR_CONTROLUNAVAIL;
1559 else
1561 ALfloat pitch = 1.0f;
1562 if(freq != DSBFREQUENCY_ORIGINAL)
1563 pitch = freq / (ALfloat)This->buffer->format.Format.nSamplesPerSec;
1565 setALContext(This->ctx);
1566 alSourcef(This->source, AL_PITCH, pitch);
1567 getALError();
1568 popALContext();
1570 LeaveCriticalSection(This->crst);
1571 return hr;
1574 static HRESULT WINAPI DS8Buffer_Stop(IDirectSoundBuffer8 *iface)
1576 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1577 ALint state;
1579 TRACE("(%p)->()\n", iface);
1581 EnterCriticalSection(This->crst);
1582 setALContext(This->ctx);
1584 alSourcePause(This->source);
1585 getALError();
1586 /* Mac OS X doesn't immediately report state change
1587 * if Play() is immediately called after Stop, this can be fatal,
1588 * the buffer would never be restarted
1590 do {
1591 state = AL_PAUSED;
1592 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1593 if(state != AL_PLAYING)
1594 break;
1595 Sleep(1);
1596 } while(1);
1598 /* Stopped, remove from notify list */
1599 if(This->nnotify)
1601 HRESULT hr;
1602 DWORD pos = This->lastpos;
1603 hr = IDirectSoundBuffer8_GetCurrentPosition(iface, &pos, NULL);
1604 if(FAILED(hr))
1605 ERR("Own getcurrentposition failed!\n");
1606 trigger_notifies(This, This->lastpos, pos);
1607 This->lastpos = pos;
1608 DS8Buffer_removenotify(This);
1611 This->isplaying = FALSE;
1613 popALContext();
1614 LeaveCriticalSection(This->crst);
1616 return S_OK;
1619 static HRESULT WINAPI DS8Buffer_Unlock(IDirectSoundBuffer8 *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
1621 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1622 DS8Data *buf = This->buffer;
1623 DWORD bufsize = buf->buf_size;
1624 DWORD_PTR ofs1, ofs2;
1625 DWORD_PTR boundary = (DWORD_PTR)buf->data;
1626 HRESULT hr;
1628 TRACE("(%p)->(%p, %u, %p, %u)\n", iface, ptr1, len1, ptr2, len2);
1630 EnterCriticalSection(This->crst);
1631 setALContext(This->ctx);
1633 This->buffer->locked = 0;
1634 hr = DSERR_INVALIDPARAM;
1636 /* Make sure offset is between boundary and boundary + bufsize */
1637 ofs1 = (DWORD_PTR)ptr1;
1638 ofs2 = (DWORD_PTR)ptr2;
1639 if(ofs1 < boundary)
1640 goto out;
1641 if(ofs2 && ofs2 != boundary)
1642 goto out;
1643 ofs1 -= boundary;
1644 ofs2 = 0;
1645 if(bufsize-ofs1 < len1 || len2 > ofs1)
1646 goto out;
1647 if(!ptr2)
1648 len2 = 0;
1650 hr = S_OK;
1651 if(!len1 && !len2)
1652 goto out;
1654 if(This->ExtAL->BufferDataStatic)
1655 goto out;
1657 if(This->ExtAL->BufferSubSamplesSOFT)
1659 WAVEFORMATEX *format = &buf->format.Format;
1661 ptr1 = (BYTE*)ptr1 - (ofs1%format->nBlockAlign);
1662 ofs1 /= format->nBlockAlign;
1663 len1 /= format->nBlockAlign;
1664 if(len1 > 0)
1665 This->ExtAL->BufferSubSamplesSOFT(buf->buffers[0], ofs1, len1,
1666 buf->in_chans, buf->in_type, ptr1);
1667 ptr2 = (BYTE*)ptr2 - (ofs2%format->nBlockAlign);
1668 ofs2 /= format->nBlockAlign;
1669 len2 /= format->nBlockAlign;
1670 if(len2 > 0)
1671 This->ExtAL->BufferSubSamplesSOFT(buf->buffers[0], ofs2, len2,
1672 buf->in_chans, buf->in_type, ptr2);
1673 getALError();
1675 else if(This->ExtAL->BufferSubData)
1677 WAVEFORMATEX *format = &buf->format.Format;
1679 len1 -= len1%format->nBlockAlign;
1680 if(len1 > 0)
1681 This->ExtAL->BufferSubData(buf->buffers[0], buf->buf_format, ptr1,
1682 ofs1, len1);
1683 len2 -= len2%format->nBlockAlign;
1684 if(len2 > 0)
1685 This->ExtAL->BufferSubData(buf->buffers[0], buf->buf_format, ptr2,
1686 ofs2, len2);
1687 getALError();
1689 else
1691 alBufferData(buf->buffers[0], buf->buf_format,
1692 buf->data, buf->buf_size,
1693 buf->format.Format.nSamplesPerSec);
1694 getALError();
1697 out:
1698 if(hr != S_OK)
1699 WARN("Invalid parameters (0x%lx,%u) (%p,%u,%p,%u)\n", boundary, bufsize, ptr1, len1, ptr2, len2);
1700 popALContext();
1701 LeaveCriticalSection(This->crst);
1702 return hr;
1705 static HRESULT WINAPI DS8Buffer_Restore(IDirectSoundBuffer8 *iface)
1707 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1708 HRESULT hr;
1710 TRACE("(%p)->()\n", iface);
1712 EnterCriticalSection(This->crst);
1713 if(This->primary->parent->prio_level < DSSCL_WRITEPRIMARY ||
1714 iface == This->primary->write_emu)
1716 This->bufferlost = 0;
1717 hr = S_OK;
1719 else
1720 hr = DSERR_BUFFERLOST;
1721 LeaveCriticalSection(This->crst);
1723 return hr;
1726 static HRESULT WINAPI DS8Buffer_SetFX(IDirectSoundBuffer8 *iface, DWORD fxcount, DSEFFECTDESC *desc, DWORD *rescodes)
1728 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1729 DWORD i;
1731 TRACE("(%p)->(%u, %p, %p)\n", This, fxcount, desc, rescodes);
1733 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFX))
1735 WARN("FX control not set\n");
1736 return DSERR_CONTROLUNAVAIL;
1739 if(fxcount == 0)
1741 if(desc || rescodes)
1743 WARN("Non-NULL desc and/or result pointer specified with no effects.\n");
1744 return DSERR_INVALIDPARAM;
1747 /* No effects; we can handle that */
1748 return DS_OK;
1751 if(!desc || !rescodes)
1753 WARN("NULL desc and/or result pointer specified.\n");
1754 return DSERR_INVALIDPARAM;
1757 /* We don't (currently) handle DSound effects */
1758 for(i = 0;i < fxcount;++i)
1760 FIXME("Cannot handle effect: %s\n", debugstr_guid(&desc[i].guidDSFXClass));
1761 rescodes[i] = DSFXR_FAILED;
1764 return DSERR_INVALIDPARAM;
1767 static HRESULT WINAPI DS8Buffer_AcquireResources(IDirectSoundBuffer8 *iface, DWORD flags, DWORD fxcount, DWORD *rescodes)
1769 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1771 TRACE("(%p)->(%u, %u, %p)\n", This, flags, fxcount, rescodes);
1773 /* effects aren't supported at the moment.. */
1774 if(fxcount != 0 || rescodes)
1776 WARN("Non-zero effect count and/or result pointer specified with no effects.\n");
1777 return DSERR_INVALIDPARAM;
1780 EnterCriticalSection(This->crst);
1781 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1783 This->buffer->dsbflags &= ~(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE);
1784 if((flags&DSBPLAY_LOCSOFTWARE))
1785 This->buffer->dsbflags |= DSBCAPS_LOCSOFTWARE;
1786 else
1787 This->buffer->dsbflags |= DSBCAPS_LOCHARDWARE;
1789 LeaveCriticalSection(This->crst);
1791 return S_OK;
1794 static HRESULT WINAPI DS8Buffer_GetObjectInPath(IDirectSoundBuffer8 *iface, REFGUID guid, DWORD idx, REFGUID rguidiface, void **ppv)
1796 FIXME("(%p)->(%s, %u, %s, %p) : stub!\n", iface, debugstr_guid(guid), idx, debugstr_guid(rguidiface), ppv);
1797 return E_NOTIMPL;
1800 static const IDirectSoundBuffer8Vtbl DS8Buffer_Vtbl =
1802 DS8Buffer_QueryInterface,
1803 DS8Buffer_AddRef,
1804 DS8Buffer_Release,
1805 DS8Buffer_GetCaps,
1806 DS8Buffer_GetCurrentPosition,
1807 DS8Buffer_GetFormat,
1808 DS8Buffer_GetVolume,
1809 DS8Buffer_GetPan,
1810 DS8Buffer_GetFrequency,
1811 DS8Buffer_GetStatus,
1812 DS8Buffer_Initialize,
1813 DS8Buffer_Lock,
1814 DS8Buffer_Play,
1815 DS8Buffer_SetCurrentPosition,
1816 DS8Buffer_SetFormat,
1817 DS8Buffer_SetVolume,
1818 DS8Buffer_SetPan,
1819 DS8Buffer_SetFrequency,
1820 DS8Buffer_Stop,
1821 DS8Buffer_Unlock,
1822 DS8Buffer_Restore,
1823 DS8Buffer_SetFX,
1824 DS8Buffer_AcquireResources,
1825 DS8Buffer_GetObjectInPath
1828 static inline DS8Buffer *impl_from_IDirectSound3DBuffer(IDirectSound3DBuffer *iface)
1830 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSound3DBuffer_iface);
1833 static HRESULT WINAPI DS8Buffer3D_QueryInterface(IDirectSound3DBuffer *iface, REFIID riid, void **ppv)
1835 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1836 return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
1839 static ULONG WINAPI DS8Buffer3D_AddRef(IDirectSound3DBuffer *iface)
1841 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1842 LONG ret;
1844 InterlockedIncrement(&This->all_ref);
1845 ret = InterlockedIncrement(&This->ds3d_ref);
1846 TRACE("new refcount %d\n", ret);
1848 return ret;
1851 static ULONG WINAPI DS8Buffer3D_Release(IDirectSound3DBuffer *iface)
1853 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1854 LONG ret;
1856 ret = InterlockedDecrement(&This->ds3d_ref);
1857 TRACE("new refcount %d\n", ret);
1858 if(InterlockedDecrement(&This->all_ref) == 0)
1859 DS8Buffer_Destroy(This);
1861 return ret;
1864 static HRESULT WINAPI DS8Buffer3D_GetAllParameters(IDirectSound3DBuffer *iface, DS3DBUFFER *ds3dbuffer)
1866 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1867 DS3DBUFFER ds3dbuf;
1868 HRESULT hr;
1870 TRACE("%p\n", This);
1872 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
1874 WARN("Invalid parameters %p %u\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
1875 return DSERR_INVALIDPARAM;
1877 ds3dbuf.dwSize = sizeof(ds3dbuf);
1879 EnterCriticalSection(This->crst);
1880 setALContext(This->ctx);
1882 hr = IDirectSound3DBuffer_GetPosition(iface, &ds3dbuf.vPosition);
1883 if(SUCCEEDED(hr))
1884 hr = IDirectSound3DBuffer_GetVelocity(iface, &ds3dbuf.vVelocity);
1885 if(SUCCEEDED(hr))
1886 hr = IDirectSound3DBuffer_GetConeAngles(iface, &ds3dbuf.dwInsideConeAngle, &ds3dbuf.dwOutsideConeAngle);
1887 if(SUCCEEDED(hr))
1888 hr = IDirectSound3DBuffer_GetConeOrientation(iface, &ds3dbuf.vConeOrientation);
1889 if(SUCCEEDED(hr))
1890 hr = IDirectSound3DBuffer_GetConeOutsideVolume(iface, &ds3dbuf.lConeOutsideVolume);
1891 if(SUCCEEDED(hr))
1892 hr = IDirectSound3DBuffer_GetMinDistance(iface, &ds3dbuf.flMinDistance);
1893 if(SUCCEEDED(hr))
1894 hr = IDirectSound3DBuffer_GetMaxDistance(iface, &ds3dbuf.flMaxDistance);
1895 if(SUCCEEDED(hr))
1896 hr = IDirectSound3DBuffer_GetMode(iface, &ds3dbuf.dwMode);
1897 if(SUCCEEDED(hr))
1898 memcpy(ds3dbuffer, &ds3dbuf, sizeof(ds3dbuf));
1900 popALContext();
1901 LeaveCriticalSection(This->crst);
1903 return hr;
1906 static HRESULT WINAPI DS8Buffer3D_GetConeAngles(IDirectSound3DBuffer *iface, DWORD *pdwInsideConeAngle, DWORD *pdwOutsideConeAngle)
1908 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1909 ALint inangle, outangle;
1911 TRACE("(%p)->(%p, %p)\n", This, pdwInsideConeAngle, pdwOutsideConeAngle);
1912 if(!pdwInsideConeAngle || !pdwOutsideConeAngle)
1914 WARN("Invalid pointers (%p, %p)\n", pdwInsideConeAngle, pdwOutsideConeAngle);
1915 return DSERR_INVALIDPARAM;
1918 EnterCriticalSection(This->crst);
1919 setALContext(This->ctx);
1921 alGetSourcei(This->source, AL_CONE_INNER_ANGLE, &inangle);
1922 alGetSourcei(This->source, AL_CONE_OUTER_ANGLE, &outangle);
1923 getALError();
1924 *pdwInsideConeAngle = inangle;
1925 *pdwOutsideConeAngle = outangle;
1927 popALContext();
1928 LeaveCriticalSection(This->crst);
1930 return S_OK;
1933 static HRESULT WINAPI DS8Buffer3D_GetConeOrientation(IDirectSound3DBuffer *iface, D3DVECTOR *orient)
1935 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1936 ALfloat dir[3];
1938 TRACE("(%p)->(%p)\n", This, orient);
1939 if(!orient)
1941 WARN("Invalid pointer\n");
1942 return DSERR_INVALIDPARAM;
1945 EnterCriticalSection(This->crst);
1946 setALContext(This->ctx);
1948 alGetSourcefv(This->source, AL_DIRECTION, dir);
1949 getALError();
1950 orient->x = dir[0];
1951 orient->y = dir[1];
1952 orient->z = -dir[2];
1954 popALContext();
1955 LeaveCriticalSection(This->crst);
1957 return S_OK;
1960 static HRESULT WINAPI DS8Buffer3D_GetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG *vol)
1962 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1963 ALfloat gain;
1965 TRACE("(%p)->(%p)\n", This, vol);
1966 if(!vol)
1968 WARN("Invalid pointer\n");
1969 return DSERR_INVALIDPARAM;
1972 EnterCriticalSection(This->crst);
1973 setALContext(This->ctx);
1975 alGetSourcef(This->source, AL_CONE_OUTER_GAIN, &gain);
1976 getALError();
1977 *vol = gain_to_mB(gain);
1978 *vol = max(*vol, DSBVOLUME_MIN);
1979 *vol = min(*vol, DSBVOLUME_MAX);
1981 popALContext();
1982 LeaveCriticalSection(This->crst);
1983 return S_OK;
1986 static HRESULT WINAPI DS8Buffer3D_GetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE *maxdist)
1988 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1989 ALfloat dist;
1991 TRACE("(%p)->(%p)\n", This, maxdist);
1992 if(!maxdist)
1994 WARN("Invalid pointer\n");
1995 return DSERR_INVALIDPARAM;
1998 EnterCriticalSection(This->crst);
1999 setALContext(This->ctx);
2001 alGetSourcef(This->source, AL_MAX_DISTANCE, &dist);
2002 getALError();
2003 *maxdist = dist;
2005 popALContext();
2006 LeaveCriticalSection(This->crst);
2008 return S_OK;
2011 static HRESULT WINAPI DS8Buffer3D_GetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE *mindist)
2013 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2014 ALfloat dist;
2016 TRACE("(%p)->(%p)\n", This, mindist);
2017 if(!mindist)
2019 WARN("Invalid pointer\n");
2020 return DSERR_INVALIDPARAM;
2023 EnterCriticalSection(This->crst);
2024 setALContext(This->ctx);
2026 alGetSourcef(This->source, AL_REFERENCE_DISTANCE, &dist);
2027 getALError();
2028 *mindist = dist;
2030 popALContext();
2031 LeaveCriticalSection(This->crst);
2033 return S_OK;
2036 static HRESULT WINAPI DS8Buffer3D_GetMode(IDirectSound3DBuffer *iface, DWORD *mode)
2038 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2040 TRACE("(%p)->(%p)\n", This, mode);
2041 if(!mode)
2043 WARN("Invalid pointer\n");
2044 return DSERR_INVALIDPARAM;
2047 EnterCriticalSection(This->crst);
2048 *mode = This->ds3dmode;
2049 LeaveCriticalSection(This->crst);
2051 return S_OK;
2054 static HRESULT WINAPI DS8Buffer3D_GetPosition(IDirectSound3DBuffer *iface, D3DVECTOR *pos)
2056 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2057 ALfloat alpos[3];
2059 TRACE("(%p)->(%p)\n", This, pos);
2060 if(!pos)
2062 WARN("Invalid pointer\n");
2063 return DSERR_INVALIDPARAM;
2066 EnterCriticalSection(This->crst);
2067 setALContext(This->ctx);
2069 alGetSourcefv(This->source, AL_POSITION, alpos);
2070 getALError();
2071 pos->x = alpos[0];
2072 pos->y = alpos[1];
2073 pos->z = -alpos[2];
2075 popALContext();
2076 LeaveCriticalSection(This->crst);
2078 return S_OK;
2081 static HRESULT WINAPI DS8Buffer3D_GetVelocity(IDirectSound3DBuffer *iface, D3DVECTOR *vel)
2083 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2084 ALfloat alvel[3];
2086 TRACE("(%p)->(%p)\n", This, vel);
2087 if(!vel)
2089 WARN("Invalid pointer\n");
2090 return DSERR_INVALIDPARAM;
2093 EnterCriticalSection(This->crst);
2094 setALContext(This->ctx);
2096 alGetSourcefv(This->source, AL_VELOCITY, alvel);
2097 getALError();
2098 vel->x = alvel[0];
2099 vel->y = alvel[1];
2100 vel->z = -alvel[2];
2102 popALContext();
2103 LeaveCriticalSection(This->crst);
2105 return S_OK;
2108 static HRESULT WINAPI DS8Buffer3D_SetAllParameters(IDirectSound3DBuffer *iface, const DS3DBUFFER *ds3dbuffer, DWORD apply)
2110 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2111 TRACE("(%p)->(%p, %u)\n", This, ds3dbuffer, apply);
2113 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
2115 WARN("Invalid DS3DBUFFER (%p, %u)\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
2116 return DSERR_INVALIDPARAM;
2119 if(ds3dbuffer->dwInsideConeAngle > DS3D_MAXCONEANGLE ||
2120 ds3dbuffer->dwOutsideConeAngle > DS3D_MAXCONEANGLE)
2122 WARN("Invalid cone angles (%u, %u)\n", ds3dbuffer->dwInsideConeAngle,
2123 ds3dbuffer->dwOutsideConeAngle);
2124 return DSERR_INVALIDPARAM;
2127 if(ds3dbuffer->lConeOutsideVolume > DSBVOLUME_MAX ||
2128 ds3dbuffer->lConeOutsideVolume < DSBVOLUME_MIN)
2130 WARN("Invalid cone outside volume (%d)\n", ds3dbuffer->lConeOutsideVolume);
2131 return DSERR_INVALIDPARAM;
2134 if(ds3dbuffer->flMaxDistance < 0.0f)
2136 WARN("Invalid max distance (%f)\n", ds3dbuffer->flMaxDistance);
2137 return DSERR_INVALIDPARAM;
2140 if(ds3dbuffer->flMinDistance < 0.0f)
2142 WARN("Invalid min distance (%f)\n", ds3dbuffer->flMinDistance);
2143 return DSERR_INVALIDPARAM;
2146 if(ds3dbuffer->dwMode != DS3DMODE_NORMAL &&
2147 ds3dbuffer->dwMode != DS3DMODE_HEADRELATIVE &&
2148 ds3dbuffer->dwMode != DS3DMODE_DISABLE)
2150 WARN("Invalid mode (%u)\n", ds3dbuffer->dwMode);
2151 return DSERR_INVALIDPARAM;
2154 EnterCriticalSection(This->crst);
2155 setALContext(This->ctx);
2156 IDirectSound3DBuffer_SetPosition(iface, ds3dbuffer->vPosition.x, ds3dbuffer->vPosition.y, ds3dbuffer->vPosition.z, apply);
2157 IDirectSound3DBuffer_SetVelocity(iface, ds3dbuffer->vVelocity.x, ds3dbuffer->vVelocity.y, ds3dbuffer->vVelocity.z, apply);
2158 IDirectSound3DBuffer_SetConeAngles(iface, ds3dbuffer->dwInsideConeAngle, ds3dbuffer->dwOutsideConeAngle, apply);
2159 IDirectSound3DBuffer_SetConeOrientation(iface, ds3dbuffer->vConeOrientation.x, ds3dbuffer->vConeOrientation.y, ds3dbuffer->vConeOrientation.z, apply);
2160 IDirectSound3DBuffer_SetConeOutsideVolume(iface, ds3dbuffer->lConeOutsideVolume, apply);
2161 IDirectSound3DBuffer_SetMinDistance(iface, ds3dbuffer->flMinDistance, apply);
2162 IDirectSound3DBuffer_SetMaxDistance(iface, ds3dbuffer->flMaxDistance, apply);
2163 IDirectSound3DBuffer_SetMode(iface, ds3dbuffer->dwMode, apply);
2164 popALContext();
2165 LeaveCriticalSection(This->crst);
2167 return S_OK;
2170 static HRESULT WINAPI DS8Buffer3D_SetConeAngles(IDirectSound3DBuffer *iface, DWORD dwInsideConeAngle, DWORD dwOutsideConeAngle, DWORD apply)
2172 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2174 TRACE("(%p)->(%u, %u, %u)\n", This, dwInsideConeAngle, dwOutsideConeAngle, apply);
2175 if(dwInsideConeAngle > DS3D_MAXCONEANGLE ||
2176 dwOutsideConeAngle > DS3D_MAXCONEANGLE)
2178 WARN("Invalid cone angles (%u, %u)\n", dwInsideConeAngle, dwOutsideConeAngle);
2179 return DSERR_INVALIDPARAM;
2182 EnterCriticalSection(This->crst);
2183 if(apply == DS3D_DEFERRED)
2185 This->ds3dbuffer.dwInsideConeAngle = dwInsideConeAngle;
2186 This->ds3dbuffer.dwOutsideConeAngle = dwOutsideConeAngle;
2187 This->dirty.bit.cone_angles = 1;
2189 else
2191 setALContext(This->ctx);
2192 alSourcei(This->source, AL_CONE_INNER_ANGLE, dwInsideConeAngle);
2193 alSourcei(This->source, AL_CONE_OUTER_ANGLE, dwOutsideConeAngle);
2194 getALError();
2195 popALContext();
2197 LeaveCriticalSection(This->crst);
2199 return S_OK;
2202 static HRESULT WINAPI DS8Buffer3D_SetConeOrientation(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2204 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2206 TRACE("(%p)->(%f, %f, %f, %u)\n", This, x, y, z, apply);
2208 EnterCriticalSection(This->crst);
2209 if(apply == DS3D_DEFERRED)
2211 This->ds3dbuffer.vConeOrientation.x = x;
2212 This->ds3dbuffer.vConeOrientation.y = y;
2213 This->ds3dbuffer.vConeOrientation.z = z;
2214 This->dirty.bit.cone_orient = 1;
2216 else
2218 setALContext(This->ctx);
2219 alSource3f(This->source, AL_DIRECTION, x, y, -z);
2220 getALError();
2221 popALContext();
2223 LeaveCriticalSection(This->crst);
2225 return S_OK;
2228 static HRESULT WINAPI DS8Buffer3D_SetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG vol, DWORD apply)
2230 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2232 TRACE("(%p)->(%u, %u)\n", This, vol, apply);
2233 if(vol < DSBVOLUME_MIN || vol > DSBVOLUME_MAX)
2235 WARN("Invalid volume (%u)\n", vol);
2236 return DSERR_INVALIDPARAM;
2239 EnterCriticalSection(This->crst);
2240 if(apply == DS3D_DEFERRED)
2242 This->ds3dbuffer.lConeOutsideVolume = vol;
2243 This->dirty.bit.cone_outsidevolume = 1;
2245 else
2247 setALContext(This->ctx);
2248 alSourcef(This->source, AL_CONE_OUTER_GAIN, mB_to_gain(vol));
2249 getALError();
2250 popALContext();
2252 LeaveCriticalSection(This->crst);
2254 return S_OK;
2257 static HRESULT WINAPI DS8Buffer3D_SetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE maxdist, DWORD apply)
2259 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2261 TRACE("(%p)->(%f, %u)\n", This, maxdist, apply);
2262 if(maxdist < 0.0f)
2264 WARN("Invalid max distance (%f)\n", maxdist);
2265 return DSERR_INVALIDPARAM;
2268 EnterCriticalSection(This->crst);
2269 if(apply == DS3D_DEFERRED)
2271 This->ds3dbuffer.flMaxDistance = maxdist;
2272 This->dirty.bit.max_distance = 1;
2274 else
2276 setALContext(This->ctx);
2277 alSourcef(This->source, AL_MAX_DISTANCE, maxdist);
2278 getALError();
2279 popALContext();
2281 LeaveCriticalSection(This->crst);
2283 return S_OK;
2286 static HRESULT WINAPI DS8Buffer3D_SetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE mindist, DWORD apply)
2288 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2290 TRACE("(%p)->(%f, %u)\n", This, mindist, apply);
2291 if(mindist < 0.0f)
2293 WARN("Invalid min distance (%f)\n", mindist);
2294 return DSERR_INVALIDPARAM;
2297 EnterCriticalSection(This->crst);
2298 if(apply == DS3D_DEFERRED)
2300 This->ds3dbuffer.flMinDistance = mindist;
2301 This->dirty.bit.min_distance = 1;
2303 else
2305 setALContext(This->ctx);
2306 alSourcef(This->source, AL_REFERENCE_DISTANCE, mindist);
2307 getALError();
2308 popALContext();
2310 LeaveCriticalSection(This->crst);
2312 return S_OK;
2315 static HRESULT WINAPI DS8Buffer3D_SetMode(IDirectSound3DBuffer *iface, DWORD mode, DWORD apply)
2317 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2319 TRACE("(%p)->(%u, %u)\n", This, mode, apply);
2320 if(mode != DS3DMODE_NORMAL && mode != DS3DMODE_HEADRELATIVE &&
2321 mode != DS3DMODE_DISABLE)
2323 WARN("Invalid mode (%u)\n", mode);
2324 return DSERR_INVALIDPARAM;
2327 EnterCriticalSection(This->crst);
2328 if(apply == DS3D_DEFERRED)
2330 This->ds3dbuffer.dwMode = mode;
2331 This->dirty.bit.mode = 1;
2333 else
2335 setALContext(This->ctx);
2336 alSourcei(This->source, AL_SOURCE_RELATIVE,
2337 (mode != DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE);
2338 alSourcef(This->source, AL_ROLLOFF_FACTOR,
2339 (mode == DS3DMODE_DISABLE) ? 0.0f : This->primary->rollofffactor);
2340 This->ds3dmode = mode;
2341 getALError();
2342 popALContext();
2344 LeaveCriticalSection(This->crst);
2346 return S_OK;
2349 static HRESULT WINAPI DS8Buffer3D_SetPosition(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2351 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2353 TRACE("(%p)->(%f, %f, %f, %u)\n", This, x, y, z, apply);
2355 EnterCriticalSection(This->crst);
2356 if(apply == DS3D_DEFERRED)
2358 This->ds3dbuffer.vPosition.x = x;
2359 This->ds3dbuffer.vPosition.y = y;
2360 This->ds3dbuffer.vPosition.z = z;
2361 This->dirty.bit.pos = 1;
2363 else
2365 setALContext(This->ctx);
2366 alSource3f(This->source, AL_POSITION, x, y, -z);
2367 getALError();
2368 popALContext();
2370 LeaveCriticalSection(This->crst);
2372 return S_OK;
2375 static HRESULT WINAPI DS8Buffer3D_SetVelocity(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2377 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2379 TRACE("(%p)->(%f, %f, %f, %u)\n", This, x, y, z, apply);
2381 EnterCriticalSection(This->crst);
2382 if(apply == DS3D_DEFERRED)
2384 This->ds3dbuffer.vVelocity.x = x;
2385 This->ds3dbuffer.vVelocity.y = y;
2386 This->ds3dbuffer.vVelocity.z = z;
2387 This->dirty.bit.vel = 1;
2389 else
2391 setALContext(This->ctx);
2392 alSource3f(This->source, AL_VELOCITY, x, y, -z);
2393 getALError();
2394 popALContext();
2396 LeaveCriticalSection(This->crst);
2398 return S_OK;
2401 static const IDirectSound3DBufferVtbl DS8Buffer3d_Vtbl =
2403 DS8Buffer3D_QueryInterface,
2404 DS8Buffer3D_AddRef,
2405 DS8Buffer3D_Release,
2406 DS8Buffer3D_GetAllParameters,
2407 DS8Buffer3D_GetConeAngles,
2408 DS8Buffer3D_GetConeOrientation,
2409 DS8Buffer3D_GetConeOutsideVolume,
2410 DS8Buffer3D_GetMaxDistance,
2411 DS8Buffer3D_GetMinDistance,
2412 DS8Buffer3D_GetMode,
2413 DS8Buffer3D_GetPosition,
2414 DS8Buffer3D_GetVelocity,
2415 DS8Buffer3D_SetAllParameters,
2416 DS8Buffer3D_SetConeAngles,
2417 DS8Buffer3D_SetConeOrientation,
2418 DS8Buffer3D_SetConeOutsideVolume,
2419 DS8Buffer3D_SetMaxDistance,
2420 DS8Buffer3D_SetMinDistance,
2421 DS8Buffer3D_SetMode,
2422 DS8Buffer3D_SetPosition,
2423 DS8Buffer3D_SetVelocity
2426 static inline DS8Buffer *impl_from_IDirectSoundNotify(IDirectSoundNotify *iface)
2428 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSoundNotify_iface);
2431 static HRESULT WINAPI DS8BufferNot_QueryInterface(IDirectSoundNotify *iface, REFIID riid, void **ppv)
2433 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2434 return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2437 static ULONG WINAPI DS8BufferNot_AddRef(IDirectSoundNotify *iface)
2439 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2440 LONG ret;
2442 InterlockedIncrement(&This->all_ref);
2443 ret = InterlockedIncrement(&This->not_ref);
2444 TRACE("new refcount %d\n", ret);
2446 return ret;
2449 static ULONG WINAPI DS8BufferNot_Release(IDirectSoundNotify *iface)
2451 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2452 LONG ret;
2454 ret = InterlockedDecrement(&This->not_ref);
2455 TRACE("new refcount %d\n", ret);
2456 if(InterlockedDecrement(&This->all_ref) == 0)
2457 DS8Buffer_Destroy(This);
2459 return ret;
2462 static HRESULT WINAPI DS8BufferNot_SetNotificationPositions(IDirectSoundNotify *iface, DWORD count, const DSBPOSITIONNOTIFY *notifications)
2464 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2465 DSBPOSITIONNOTIFY *nots;
2466 DWORD state;
2467 HRESULT hr;
2469 EnterCriticalSection(This->crst);
2470 hr = DSERR_INVALIDPARAM;
2471 if(count && !notifications)
2472 goto out;
2474 hr = IDirectSoundBuffer8_GetStatus(&This->IDirectSoundBuffer8_iface, &state);
2475 if(FAILED(hr))
2476 goto out;
2478 hr = DSERR_INVALIDCALL;
2479 if((state&DSBSTATUS_PLAYING))
2480 goto out;
2482 if(!count)
2484 HeapFree(GetProcessHeap(), 0, This->notify);
2485 This->notify = 0;
2486 This->nnotify = 0;
2487 hr = S_OK;
2489 else
2491 DWORD i;
2493 hr = DSERR_INVALIDPARAM;
2494 for(i = 0;i < count;++i)
2496 if(notifications[i].dwOffset >= This->buffer->buf_size &&
2497 notifications[i].dwOffset != (DWORD)DSBPN_OFFSETSTOP)
2498 goto out;
2501 hr = E_OUTOFMEMORY;
2502 nots = HeapAlloc(GetProcessHeap(), 0, count*sizeof(*nots));
2503 if(!nots)
2504 goto out;
2505 memcpy(nots, notifications, count*sizeof(*nots));
2507 HeapFree(GetProcessHeap(), 0, This->notify);
2508 This->notify = nots;
2509 This->nnotify = count;
2511 hr = S_OK;
2514 out:
2515 LeaveCriticalSection(This->crst);
2516 return hr;
2519 static const IDirectSoundNotifyVtbl DS8BufferNot_Vtbl =
2521 DS8BufferNot_QueryInterface,
2522 DS8BufferNot_AddRef,
2523 DS8BufferNot_Release,
2524 DS8BufferNot_SetNotificationPositions
2527 /* NOTE: Due to some apparent quirks in DSound, the listener properties are
2528 handled through secondary buffers. */
2529 static inline DS8Buffer *impl_from_IKsPropertySet(IKsPropertySet *iface)
2531 return CONTAINING_RECORD(iface, DS8Buffer, IKsPropertySet_iface);
2534 static HRESULT WINAPI DS8BufferProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
2536 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2537 return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2540 static ULONG WINAPI DS8BufferProp_AddRef(IKsPropertySet *iface)
2542 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2543 LONG ret;
2545 InterlockedIncrement(&This->all_ref);
2546 ret = InterlockedIncrement(&This->prop_ref);
2547 TRACE("new refcount %d\n", ret);
2549 return ret;
2552 static ULONG WINAPI DS8BufferProp_Release(IKsPropertySet *iface)
2554 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2555 LONG ret;
2557 ret = InterlockedDecrement(&This->prop_ref);
2558 TRACE("new refcount %d\n", ret);
2559 if(InterlockedDecrement(&This->all_ref) == 0)
2560 DS8Buffer_Destroy(This);
2562 return ret;
2565 static HRESULT WINAPI DS8BufferProp_Get(IKsPropertySet *iface,
2566 REFGUID guidPropSet, ULONG dwPropID,
2567 LPVOID pInstanceData, ULONG cbInstanceData,
2568 LPVOID pPropData, ULONG cbPropData,
2569 PULONG pcbReturned)
2571 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2572 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2574 TRACE("(%p)->(%s, %u, %p, %u, %p, %u, %p)\n", iface, debugstr_guid(guidPropSet),
2575 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData, pcbReturned);
2577 if(!pcbReturned)
2578 return E_POINTER;
2579 *pcbReturned = 0;
2581 #if 0
2582 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2585 else
2586 #endif
2588 /* Not a known buffer/source property. Pass it to the listener */
2589 hr = IKsPropertySet_Get(&This->primary->IKsPropertySet_iface, guidPropSet,
2590 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData,
2591 pcbReturned);
2594 return hr;
2597 static HRESULT WINAPI DS8BufferProp_Set(IKsPropertySet *iface,
2598 REFGUID guidPropSet, ULONG dwPropID,
2599 LPVOID pInstanceData, ULONG cbInstanceData,
2600 LPVOID pPropData, ULONG cbPropData)
2602 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2603 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2605 TRACE("(%p)->(%s, %u, %p, %u, %p, %u)\n", iface, debugstr_guid(guidPropSet),
2606 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData);
2608 #if 0
2609 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2612 else
2613 #endif
2615 /* Not a known buffer/source property. Pass it to the listener */
2616 hr = IKsPropertySet_Set(&This->primary->IKsPropertySet_iface, guidPropSet,
2617 dwPropID, pInstanceData, cbInstanceData, pPropData,
2618 cbPropData);
2621 return hr;
2624 static HRESULT WINAPI DS8BufferProp_QuerySupport(IKsPropertySet *iface,
2625 REFGUID guidPropSet, ULONG dwPropID,
2626 PULONG pTypeSupport)
2628 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2629 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2631 TRACE("(%p)->(%s, %u, %p)\n", iface, debugstr_guid(guidPropSet), dwPropID, pTypeSupport);
2633 if(!pTypeSupport)
2634 return E_POINTER;
2635 *pTypeSupport = 0;
2637 #if 0
2638 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2641 else
2642 #endif
2644 /* Not a known buffer/source property. Pass it to the listener */
2645 hr = IKsPropertySet_QuerySupport(&This->primary->IKsPropertySet_iface,
2646 guidPropSet, dwPropID, pTypeSupport);
2649 return hr;
2652 static const IKsPropertySetVtbl DS8BufferProp_Vtbl =
2654 DS8BufferProp_QueryInterface,
2655 DS8BufferProp_AddRef,
2656 DS8BufferProp_Release,
2657 DS8BufferProp_Get,
2658 DS8BufferProp_Set,
2659 DS8BufferProp_QuerySupport