Make the primary buffer a non-pointer member of the device
[wine/multimedia.git] / dsound8.c
blob52768839862e673fd69cae8933029f88f7c2ca5d
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 "mmsystem.h"
36 #include "winternl.h"
37 #include "mmddk.h"
38 #include "wine/debug.h"
39 #include "dsound.h"
41 #include "dsound_private.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
45 #else
47 #define WINVER 0x0600
48 #include <windows.h>
49 #include <dsound.h>
51 #include "dsound_private.h"
53 #ifndef DSSPEAKER_7POINT1
54 #define DSSPEAKER_7POINT1 7
55 #endif
57 #endif
59 static DeviceShare **sharelist;
60 static UINT sharelistsize;
62 static void DSShare_Destroy(DeviceShare *share)
64 UINT i;
66 EnterCriticalSection(&openal_crst);
67 for(i = 0;i < sharelistsize;i++)
69 if(sharelist[i] == share)
71 sharelist[i] = sharelist[--sharelistsize];
72 if(sharelistsize == 0)
74 HeapFree(GetProcessHeap(), 0, sharelist);
75 sharelist = NULL;
77 break;
80 LeaveCriticalSection(&openal_crst);
82 if(share->ctx)
84 /* Calling setALContext is not appropriate here,
85 * since we *have* to unset the context before destroying it
87 ALCcontext *old_ctx;
89 EnterCriticalSection(&openal_crst);
90 old_ctx = get_context();
91 if(old_ctx != share->ctx)
92 set_context(share->ctx);
93 else
94 old_ctx = NULL;
96 if(share->nsources)
97 alDeleteSources(share->nsources, share->sources);
99 if(share->effect)
100 share->ExtAL.DeleteEffects(1, &share->effect);
101 if(share->auxslot)
102 share->ExtAL.DeleteAuxiliaryEffectSlots(1, &share->auxslot);
104 set_context(old_ctx);
105 alcDestroyContext(share->ctx);
106 LeaveCriticalSection(&openal_crst);
109 if(share->device)
110 alcCloseDevice(share->device);
111 share->device = NULL;
113 share->crst.DebugInfo->Spare[0] = 0;
114 DeleteCriticalSection(&share->crst);
116 HeapFree(GetProcessHeap(), 0, share);
119 static HRESULT DSShare_Create(REFIID guid, DeviceShare **out)
121 const ALCchar *drv_name;
122 DeviceShare *share;
123 void *temp;
124 HRESULT hr;
125 DWORD n;
127 share = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*share));
128 if(!share) return DSERR_OUTOFMEMORY;
129 share->ref = 1;
131 InitializeCriticalSection(&share->crst);
132 share->crst.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": Device.crst");
134 hr = DSERR_NODRIVER;
135 if(!(drv_name=DSOUND_getdevicestrings()) ||
136 memcmp(guid, &DSOUND_renderer_guid, sizeof(GUID)-1) != 0)
138 WARN("No device found\n");
139 goto fail;
142 n = guid->Data4[7];
143 while(*drv_name && n--)
144 drv_name += strlen(drv_name) + 1;
145 if(!*drv_name)
147 WARN("No device string found\n");
148 goto fail;
150 memcpy(&share->guid, guid, sizeof(GUID));
152 share->device = alcOpenDevice(drv_name);
153 if(!share->device)
155 alcGetError(NULL);
156 WARN("Couldn't open device \"%s\"\n", drv_name);
157 goto fail;
159 TRACE("Opened device: %s\n", alcGetString(share->device, ALC_DEVICE_SPECIFIER));
161 hr = DSERR_NODRIVER;
162 share->ctx = alcCreateContext(share->device, NULL);
163 if(!share->ctx)
165 ALCenum err = alcGetError(share->device);
166 ERR("Could not create context (0x%x)!\n", err);
167 goto fail;
170 setALContext(share->ctx);
171 if(alIsExtensionPresent("AL_EXT_FLOAT32"))
173 TRACE("Found AL_EXT_FLOAT32\n");
174 share->SupportedExt[EXT_FLOAT32] = AL_TRUE;
176 if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
178 TRACE("Found AL_EXT_MCFORMATS\n");
179 share->SupportedExt[EXT_MCFORMATS] = AL_TRUE;
181 if(alIsExtensionPresent("AL_EXT_STATIC_BUFFER"))
183 TRACE("Found AL_EXT_STATIC_BUFFER\n");
184 share->ExtAL.BufferDataStatic = alGetProcAddress("alBufferDataStatic");
185 share->SupportedExt[EXT_STATIC_BUFFER] = AL_TRUE;
187 if(alIsExtensionPresent("AL_SOFTX_buffer_samples"))
189 TRACE("Found AL_SOFTX_buffer_samples\n");
190 share->ExtAL.BufferSamplesSOFT = alGetProcAddress("alBufferSamplesSOFT");
191 share->ExtAL.BufferSubSamplesSOFT = alGetProcAddress("alBufferSubSamplesSOFT");
192 share->ExtAL.GetBufferSamplesSOFT = alGetProcAddress("alGetBufferSamplesSOFT");
193 share->ExtAL.IsBufferFormatSupportedSOFT = alGetProcAddress("alIsBufferFormatSupportedSOFT");
194 share->SupportedExt[SOFT_BUFFER_SAMPLES] = AL_TRUE;
196 if(alIsExtensionPresent("AL_SOFT_buffer_sub_data"))
198 TRACE("Found AL_SOFT_buffer_sub_data\n");
199 share->ExtAL.BufferSubData = alGetProcAddress("alBufferSubDataSOFT");
200 share->SupportedExt[SOFT_BUFFER_SUB_DATA] = AL_TRUE;
202 if(alIsExtensionPresent("AL_SOFTX_deferred_updates"))
204 TRACE("Found AL_SOFTX_deferred_updates\n");
205 share->ExtAL.DeferUpdatesSOFT = alGetProcAddress("alDeferUpdatesSOFT");
206 share->ExtAL.ProcessUpdatesSOFT = alGetProcAddress("alProcessUpdatesSOFT");
207 share->SupportedExt[SOFT_DEFERRED_UPDATES] = AL_TRUE;
210 if(alcIsExtensionPresent(share->device, "ALC_EXT_EFX"))
212 #define LOAD_FUNC(x) (share->ExtAL.x = alGetProcAddress("al"#x))
213 LOAD_FUNC(GenEffects);
214 LOAD_FUNC(DeleteEffects);
215 LOAD_FUNC(Effecti);
216 LOAD_FUNC(Effectf);
218 LOAD_FUNC(GenAuxiliaryEffectSlots);
219 LOAD_FUNC(DeleteAuxiliaryEffectSlots);
220 LOAD_FUNC(AuxiliaryEffectSloti);
221 #undef LOAD_FUNC
222 share->SupportedExt[EXT_EFX] = AL_TRUE;
224 share->ExtAL.GenEffects(1, &share->effect);
225 share->ExtAL.Effecti(share->effect, AL_EFFECT_TYPE, AL_EFFECT_REVERB);
227 share->ExtAL.GenAuxiliaryEffectSlots(1, &share->auxslot);
230 if(!share->SupportedExt[SOFT_BUFFER_SUB_DATA] &&
231 !share->SupportedExt[SOFT_BUFFER_SAMPLES] &&
232 !share->SupportedExt[EXT_STATIC_BUFFER])
234 ERR("Missing alBufferSubDataSOFT, alBufferSamplesSOFT , and alBufferDataStatic on device '%s', sound playback quality may be degraded\n",
235 alcGetString(share->device, ALC_DEVICE_SPECIFIER));
236 ERR("Please consider using OpenAL-Soft\n");
239 share->max_sources = 0;
240 while(share->max_sources < MAX_SOURCES)
242 alGenSources(1, &share->sources[share->max_sources]);
243 if(alGetError() != AL_NO_ERROR)
244 break;
245 share->max_sources++;
247 share->nsources = share->max_sources;
248 popALContext();
250 if(sharelist)
251 temp = HeapReAlloc(GetProcessHeap(), 0, sharelist, sizeof(*sharelist)*(sharelistsize+1));
252 else
253 temp = HeapAlloc(GetProcessHeap(), 0, sizeof(*sharelist)*(sharelistsize+1));
254 if(temp)
256 sharelist = temp;
257 sharelist[sharelistsize++] = share;
260 *out = share;
261 return DS_OK;
263 fail:
264 DSShare_Destroy(share);
265 return hr;
268 static ULONG DSShare_AddRef(DeviceShare *share)
270 ULONG ref = InterlockedIncrement(&share->ref);
271 return ref;
274 static ULONG DSShare_Release(DeviceShare *share)
276 ULONG ref = InterlockedDecrement(&share->ref);
277 if(ref == 0) DSShare_Destroy(share);
278 return ref;
282 static const IDirectSound8Vtbl DS8_Vtbl;
283 static const IDirectSoundVtbl DS_Vtbl;
285 static inline DS8Impl *impl_from_IDirectSound8(IDirectSound8 *iface)
287 return CONTAINING_RECORD(iface, DS8Impl, IDirectSound8_iface);
290 static inline DS8Impl *impl_from_IDirectSound(IDirectSound *iface)
292 return CONTAINING_RECORD(iface, DS8Impl, IDirectSound_iface);
295 HRESULT DSOUND_Create(REFIID riid, void **ds)
297 HRESULT hr;
299 if(IsEqualIID(riid, &IID_IDirectSound8))
300 return E_NOINTERFACE;
301 hr = DSOUND_Create8(&IID_IDirectSound8, ds);
302 if(hr == S_OK)
304 DS8Impl *impl = impl_from_IDirectSound8(*ds);
305 impl->is_8 = FALSE;
307 hr = IDirectSound8_QueryInterface(&impl->IDirectSound8_iface, riid, ds);
308 IDirectSound8_Release(&impl->IDirectSound8_iface);
310 return hr;
313 static void DS8Impl_Destroy(DS8Impl *This);
315 static const WCHAR speakerconfigkey[] = {
316 'S','Y','S','T','E','M','\\',
317 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
318 'C','o','n','t','r','o','l','\\',
319 'M','e','d','i','a','R','e','s','o','u','r','c','e','s','\\',
320 'D','i','r','e','c','t','S','o','u','n','d','\\',
321 'S','p','e','a','k','e','r',' ','C','o','n','f','i','g','u','r','a','t','i','o','n',0
324 static const WCHAR speakerconfig[] = {
325 'S','p','e','a','k','e','r',' ','C','o','n','f','i','g','u','r','a','t','i','o','n',0
328 HRESULT DSOUND_Create8(REFIID riid, LPVOID *ds)
330 DS8Impl *This;
331 HKEY regkey;
332 HRESULT hr;
334 *ds = NULL;
335 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
336 if(!This) return DSERR_OUTOFMEMORY;
338 This->IDirectSound8_iface.lpVtbl = (IDirectSound8Vtbl*)&DS8_Vtbl;
339 This->IDirectSound_iface.lpVtbl = (IDirectSoundVtbl*)&DS_Vtbl;
341 This->is_8 = TRUE;
342 This->speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_5POINT1, DSSPEAKER_GEOMETRY_WIDE);
344 if(RegOpenKeyExW(HKEY_LOCAL_MACHINE, speakerconfigkey, 0, KEY_READ, &regkey) == ERROR_SUCCESS)
346 DWORD type, conf, confsize = sizeof(DWORD);
348 if(RegQueryValueExW(regkey, speakerconfig, NULL, &type, (BYTE*)&conf, &confsize) == ERROR_SUCCESS)
350 if(type == REG_DWORD)
351 This->speaker_config = conf;
354 RegCloseKey(regkey);
356 /*RegGetValueW(HKEY_LOCAL_MACHINE, speakerconfigkey, speakerconfig, RRF_RT_REG_DWORD, NULL, &This->speaker_config, NULL);*/
358 hr = IDirectSound8_QueryInterface(&This->IDirectSound8_iface, riid, ds);
359 if(FAILED(hr))
360 DS8Impl_Destroy(This);
361 return hr;
364 static void DS8Impl_Destroy(DS8Impl *This)
366 DS8Primary_Destroy(&This->primary);
367 if(This->share)
368 DSShare_Release(This->share);
369 This->share = NULL;
371 HeapFree(GetProcessHeap(), 0, This);
375 static HRESULT WINAPI DS8_QueryInterface(IDirectSound8 *iface, REFIID riid, LPVOID *ppv)
377 DS8Impl *This = impl_from_IDirectSound8(iface);
379 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
381 *ppv = NULL;
382 if(IsEqualIID(riid, &IID_IUnknown) ||
383 IsEqualIID(riid, &IID_IDirectSound))
384 *ppv = &This->IDirectSound8_iface;
385 else if((IsEqualIID(riid, &IID_IDirectSound8)))
387 if(This->is_8)
388 *ppv = &This->IDirectSound8_iface;
390 else
391 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
393 if(*ppv)
395 IUnknown_AddRef((IUnknown*)*ppv);
396 return S_OK;
399 return E_NOINTERFACE;
402 static ULONG WINAPI DS8_AddRef(IDirectSound8 *iface)
404 DS8Impl *This = impl_from_IDirectSound8(iface);
405 LONG ref;
407 ref = InterlockedIncrement(&This->ref);
408 TRACE("Reference count incremented to %"LONGFMT"d\n", ref);
410 return ref;
413 static ULONG WINAPI DS8_Release(IDirectSound8 *iface)
415 DS8Impl *This = impl_from_IDirectSound8(iface);
416 LONG ref;
418 ref = InterlockedDecrement(&This->ref);
419 TRACE("Reference count decremented to %"LONGFMT"d\n", ref);
420 if(ref == 0)
421 DS8Impl_Destroy(This);
423 return ref;
426 static HRESULT WINAPI DS8_CreateSoundBuffer(IDirectSound8 *iface, LPCDSBUFFERDESC desc, LPLPDIRECTSOUNDBUFFER buf, IUnknown *pUnkOuter)
428 DS8Impl *This = impl_from_IDirectSound8(iface);
429 HRESULT hr;
431 TRACE("(%p)->(%p, %p, %p)\n", iface, desc, buf, pUnkOuter);
433 if(!buf)
435 WARN("buf is null\n");
436 return DSERR_INVALIDPARAM;
438 *buf = NULL;
440 if(pUnkOuter)
442 WARN("Aggregation isn't supported\n");
443 return DSERR_NOAGGREGATION;
445 if(!desc || desc->dwSize < sizeof(DSBUFFERDESC1))
447 WARN("Invalid buffer %p/%"LONGFMT"u\n", desc, desc?desc->dwSize:0);
448 return DSERR_INVALIDPARAM;
451 if(!This->share)
453 WARN("Device not initialized\n");
454 return DSERR_UNINITIALIZED;
457 TRACE("Requested buffer:\n"
458 " Size = %"LONGFMT"u\n"
459 " Flags = 0x%08"LONGFMT"x\n"
460 " BufferBytes = %"LONGFMT"u\n",
461 desc->dwSize, desc->dwFlags, desc->dwBufferBytes);
463 if(desc->dwSize >= sizeof(DSBUFFERDESC))
465 if(!(desc->dwFlags&DSBCAPS_CTRL3D))
467 if(!IsEqualGUID(&desc->guid3DAlgorithm, &GUID_NULL))
469 WARN("Invalid 3D algorithm GUID specified for non-3D buffer: %s\n", debugstr_guid(&desc->guid3DAlgorithm));
470 return DSERR_INVALIDPARAM;
473 else
474 TRACE("Requested 3D algorithm GUID: %s\n", debugstr_guid(&desc->guid3DAlgorithm));
477 /* OpenAL doesn't support playing with 3d and panning at same time.. */
478 if((desc->dwFlags&(DSBCAPS_CTRL3D|DSBCAPS_CTRLPAN)) == (DSBCAPS_CTRL3D|DSBCAPS_CTRLPAN))
480 if(!This->is_8)
481 ERR("Cannot create buffers with 3D and panning control\n");
482 else
483 WARN("Cannot create buffers with 3D and panning control\n");
484 return DSERR_INVALIDPARAM;
487 EnterCriticalSection(This->primary.crst);
488 if((desc->dwFlags&DSBCAPS_PRIMARYBUFFER))
490 IDirectSoundBuffer *prim = &This->primary.IDirectSoundBuffer_iface;
492 hr = S_OK;
493 if(IDirectSoundBuffer_AddRef(prim) == 1)
495 hr = IDirectSoundBuffer_Initialize(prim, &This->IDirectSound_iface, desc);
496 if(FAILED(hr))
498 IDirectSoundBuffer_Release(prim);
499 prim = NULL;
502 *buf = prim;
504 else
506 DS8Buffer *dsb;
508 hr = DS8Buffer_Create(&dsb, &This->primary, NULL);
509 if(SUCCEEDED(hr))
511 hr = IDirectSoundBuffer8_Initialize(&dsb->IDirectSoundBuffer8_iface, &This->IDirectSound_iface, desc);
512 if(FAILED(hr))
513 IDirectSoundBuffer8_Release(&dsb->IDirectSoundBuffer8_iface);
514 else
516 dsb->bufferlost = (This->prio_level == DSSCL_WRITEPRIMARY);
517 *buf = &dsb->IDirectSoundBuffer_iface;
521 LeaveCriticalSection(This->primary.crst);
523 TRACE("%08"LONGFMT"x\n", hr);
524 return hr;
527 static HRESULT WINAPI DS8_GetCaps(IDirectSound8 *iface, LPDSCAPS caps)
529 DS8Impl *This = impl_from_IDirectSound8(iface);
531 TRACE("(%p)->(%p)\n", iface, caps);
533 if(!This->share)
535 WARN("Device not initialized\n");
536 return DSERR_UNINITIALIZED;
539 if(!caps || caps->dwSize < sizeof(*caps))
541 WARN("Invalid DSCAPS (%p, %"LONGFMT"u)\n", caps, (caps?caps->dwSize:0));
542 return DSERR_INVALIDPARAM;
545 EnterCriticalSection(&This->share->crst);
547 caps->dwFlags = DSCAPS_CONTINUOUSRATE |
548 DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYSTEREO |
549 DSCAPS_PRIMARY8BIT | DSCAPS_PRIMARYMONO |
550 DSCAPS_SECONDARY16BIT | DSCAPS_SECONDARY8BIT |
551 DSCAPS_SECONDARYMONO | DSCAPS_SECONDARYSTEREO;
552 caps->dwPrimaryBuffers = 1;
553 caps->dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
554 caps->dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
555 caps->dwMaxHwMixingAllBuffers =
556 caps->dwMaxHwMixingStaticBuffers =
557 caps->dwMaxHwMixingStreamingBuffers =
558 caps->dwMaxHw3DAllBuffers =
559 caps->dwMaxHw3DStaticBuffers =
560 caps->dwMaxHw3DStreamingBuffers = This->share->max_sources;
561 caps->dwFreeHwMixingAllBuffers =
562 caps->dwFreeHwMixingStaticBuffers =
563 caps->dwFreeHwMixingStreamingBuffers =
564 caps->dwFreeHw3DAllBuffers =
565 caps->dwFreeHw3DStaticBuffers =
566 caps->dwFreeHw3DStreamingBuffers = This->share->nsources;
567 caps->dwTotalHwMemBytes =
568 caps->dwFreeHwMemBytes = 64 * 1024 * 1024;
569 caps->dwMaxContigFreeHwMemBytes = caps->dwFreeHwMemBytes;
570 caps->dwUnlockTransferRateHwBuffers = 4096;
571 caps->dwPlayCpuOverheadSwBuffers = 0;
573 LeaveCriticalSection(&This->share->crst);
575 return DS_OK;
577 static HRESULT WINAPI DS8_DuplicateSoundBuffer(IDirectSound8 *iface, IDirectSoundBuffer *in, IDirectSoundBuffer **out)
579 DS8Impl *This = impl_from_IDirectSound8(iface);
580 DS8Buffer *buf;
581 DSBCAPS caps;
582 HRESULT hr;
584 TRACE("(%p)->(%p, %p)\n", iface, in, out);
586 if(!This->share)
588 WARN("Device not initialized\n");
589 return DSERR_UNINITIALIZED;
592 if(!in || !out)
594 WARN("Invalid pointer: int = %p, out = %p\n", in, out);
595 return DSERR_INVALIDPARAM;
597 *out = NULL;
599 caps.dwSize = sizeof(caps);
600 hr = IDirectSoundBuffer_GetCaps(in, &caps);
601 if(SUCCEEDED(hr) && (caps.dwFlags&DSBCAPS_PRIMARYBUFFER))
603 WARN("Cannot duplicate buffer %p, which has DSBCAPS_PRIMARYBUFFER\n", in);
604 hr = DSERR_INVALIDPARAM;
606 if(SUCCEEDED(hr) && (caps.dwFlags&DSBCAPS_CTRLFX))
608 WARN("Cannot duplicate buffer %p, which has DSBCAPS_CTRLFX\n", in);
609 hr = DSERR_INVALIDPARAM;
611 if(SUCCEEDED(hr))
612 hr = DS8Buffer_Create(&buf, &This->primary, in);
613 if(SUCCEEDED(hr))
615 *out = &buf->IDirectSoundBuffer_iface;
616 hr = IDirectSoundBuffer_Initialize(*out, NULL, NULL);
618 if(SUCCEEDED(hr))
620 /* According to MSDN volume isn't copied */
621 if((caps.dwFlags&DSBCAPS_CTRLPAN))
623 LONG pan;
624 if(SUCCEEDED(IDirectSoundBuffer_GetPan(in, &pan)))
625 IDirectSoundBuffer_SetPan(*out, pan);
627 if((caps.dwFlags&DSBCAPS_CTRLFREQUENCY))
629 DWORD freq;
630 if(SUCCEEDED(IDirectSoundBuffer_GetFrequency(in, &freq)))
631 IDirectSoundBuffer_SetFrequency(*out, freq);
633 if((caps.dwFlags&DSBCAPS_CTRL3D))
635 IDirectSound3DBuffer *buf3d;
636 DS3DBUFFER DS3DBuffer;
637 HRESULT subhr;
639 subhr = IDirectSound_QueryInterface(in, &IID_IDirectSound3DBuffer, (void**)&buf3d);
640 if(SUCCEEDED(subhr))
642 DS3DBuffer.dwSize = sizeof(DS3DBuffer);
643 subhr = IDirectSound3DBuffer_GetAllParameters(buf3d, &DS3DBuffer);
644 IDirectSound3DBuffer_Release(buf3d);
646 if(SUCCEEDED(subhr))
647 subhr = IDirectSoundBuffer_QueryInterface(*out, &IID_IDirectSound3DBuffer, (void**)&buf3d);
648 if(SUCCEEDED(subhr))
650 subhr = IDirectSound3DBuffer_SetAllParameters(buf3d, &DS3DBuffer, DS3D_IMMEDIATE);
651 IDirectSound3DBuffer_Release(buf3d);
655 if(FAILED(hr))
657 if(*out)
658 IDirectSoundBuffer_Release(*out);
659 *out = NULL;
662 return hr;
665 static HRESULT WINAPI DS8_SetCooperativeLevel(IDirectSound8 *iface, HWND hwnd, DWORD level)
667 DS8Impl *This = impl_from_IDirectSound8(iface);
668 HRESULT hr = S_OK;
670 TRACE("(%p)->(%p, %"LONGFMT"u)\n", iface, hwnd, level);
672 if(!This->share)
674 WARN("Device not initialized\n");
675 return DSERR_UNINITIALIZED;
678 if(level > DSSCL_WRITEPRIMARY || level < DSSCL_NORMAL)
680 WARN("Invalid coop level: %"LONGFMT"u\n", level);
681 return DSERR_INVALIDPARAM;
684 EnterCriticalSection(This->primary.crst);
685 if(level == DSSCL_WRITEPRIMARY && (This->prio_level != DSSCL_WRITEPRIMARY))
687 DWORD i, state;
689 for(i = 0; i < This->primary.nbuffers; ++i)
691 DS8Buffer *buf = This->primary.buffers[i];
692 if(FAILED(IDirectSoundBuffer_GetStatus(&buf->IDirectSoundBuffer8_iface, &state)) ||
693 (state&DSBSTATUS_PLAYING))
695 WARN("DSSCL_WRITEPRIMARY set with playing buffers!\n");
696 hr = DSERR_INVALIDCALL;
697 goto out;
699 /* Mark buffer as lost */
700 buf->bufferlost = 1;
702 if(This->primary.write_emu)
704 ERR("Why was there a write_emu?\n");
705 /* Delete it */
706 IDirectSoundBuffer8_Release(This->primary.write_emu);
707 This->primary.write_emu = NULL;
709 if(This->primary.flags)
711 /* Primary has open references.. create write_emu */
712 DSBUFFERDESC desc;
713 DS8Buffer *emu;
715 memset(&desc, 0, sizeof(desc));
716 desc.dwSize = sizeof(desc);
717 desc.dwFlags = DSBCAPS_LOCHARDWARE | (This->primary.flags&DSBCAPS_CTRLPAN);
718 desc.dwBufferBytes = This->primary.buf_size;
719 desc.lpwfxFormat = &This->primary.format.Format;
721 hr = DS8Buffer_Create(&emu, &This->primary, NULL);
722 if(SUCCEEDED(hr))
724 This->primary.write_emu = &emu->IDirectSoundBuffer8_iface;
725 hr = IDirectSoundBuffer8_Initialize(This->primary.write_emu, &This->IDirectSound_iface, &desc);
726 if(FAILED(hr))
728 IDirectSoundBuffer8_Release(This->primary.write_emu);
729 This->primary.write_emu = NULL;
734 else if(This->prio_level == DSSCL_WRITEPRIMARY && level != DSSCL_WRITEPRIMARY && This->primary.write_emu)
736 TRACE("Nuking write_emu\n");
737 /* Delete it */
738 IDirectSoundBuffer8_Release(This->primary.write_emu);
739 This->primary.write_emu = NULL;
741 if(SUCCEEDED(hr))
742 This->prio_level = level;
743 out:
744 LeaveCriticalSection(This->primary.crst);
746 return hr;
749 static HRESULT WINAPI DS8_Compact(IDirectSound8 *iface)
751 DS8Impl *This = impl_from_IDirectSound8(iface);
752 HRESULT hr = S_OK;
754 TRACE("(%p)->()\n", iface);
756 if(!This->share)
758 WARN("Device not initialized\n");
759 return DSERR_UNINITIALIZED;
762 EnterCriticalSection(&This->share->crst);
763 if(This->prio_level < DSSCL_PRIORITY)
765 WARN("Coop level not high enough (%"LONGFMT"u)\n", This->prio_level);
766 hr = DSERR_PRIOLEVELNEEDED;
768 LeaveCriticalSection(&This->share->crst);
770 return hr;
773 static HRESULT WINAPI DS8_GetSpeakerConfig(IDirectSound8 *iface, DWORD *config)
775 DS8Impl *This = impl_from_IDirectSound8(iface);
776 HRESULT hr = S_OK;
778 TRACE("(%p)->(%p)\n", iface, config);
780 if(!config)
781 return DSERR_INVALIDPARAM;
782 *config = 0;
784 if(!This->share)
786 WARN("Device not initialized\n");
787 return DSERR_UNINITIALIZED;
790 EnterCriticalSection(&This->share->crst);
791 *config = This->speaker_config;
792 LeaveCriticalSection(&This->share->crst);
794 return hr;
797 static HRESULT WINAPI DS8_SetSpeakerConfig(IDirectSound8 *iface, DWORD config)
799 DS8Impl *This = impl_from_IDirectSound8(iface);
800 DWORD geo, speaker;
801 HKEY key;
802 HRESULT hr;
804 TRACE("(%p)->(0x%08"LONGFMT"x)\n", iface, config);
806 if(!This->share)
808 WARN("Device not initialized\n");
809 return DSERR_UNINITIALIZED;
812 geo = DSSPEAKER_GEOMETRY(config);
813 speaker = DSSPEAKER_CONFIG(config);
815 if(geo && (geo < DSSPEAKER_GEOMETRY_MIN || geo > DSSPEAKER_GEOMETRY_MAX))
817 WARN("Invalid speaker angle %"LONGFMT"u\n", geo);
818 return DSERR_INVALIDPARAM;
820 if(speaker < DSSPEAKER_HEADPHONE || speaker > DSSPEAKER_7POINT1)
822 WARN("Invalid speaker config %"LONGFMT"u\n", speaker);
823 return DSERR_INVALIDPARAM;
826 EnterCriticalSection(&This->share->crst);
828 hr = DSERR_GENERIC;
829 if(!RegCreateKeyExW(HKEY_LOCAL_MACHINE, speakerconfigkey, 0, NULL, 0, KEY_WRITE, NULL, &key, NULL))
831 RegSetValueExW(key, speakerconfig, 0, REG_DWORD, (const BYTE*)&config, sizeof(DWORD));
832 This->speaker_config = config;
833 RegCloseKey(key);
834 hr = S_OK;
837 LeaveCriticalSection(&This->share->crst);
838 return hr;
841 static HRESULT WINAPI DS8_Initialize(IDirectSound8 *iface, const GUID *devguid)
843 DS8Impl *This = impl_from_IDirectSound8(iface);
844 HRESULT hr;
845 GUID guid;
846 UINT n;
848 TRACE("(%p)->(%s)\n", iface, debugstr_guid(devguid));
850 if(!openal_loaded)
851 return DSERR_NODRIVER;
853 if(This->share)
855 WARN("Device already initialized\n");
856 return DSERR_ALREADYINITIALIZED;
859 if(!devguid)
860 devguid = &DSDEVID_DefaultPlayback;
861 hr = GetDeviceID(devguid, &guid);
862 if(FAILED(hr))
863 return hr;
865 EnterCriticalSection(&openal_crst);
867 for(n = 0;n < sharelistsize;n++)
869 if(IsEqualGUID(&sharelist[n]->guid, &guid))
871 TRACE("Matched already open device %p\n", sharelist[n]->device);
873 This->share = sharelist[n];
874 DSShare_AddRef(This->share);
875 break;
879 if(!This->share)
880 hr = DSShare_Create(&guid, &This->share);
881 if(SUCCEEDED(hr))
883 This->device = This->share->device;
884 hr = DS8Primary_Create(&This->primary, This);
887 if(FAILED(hr))
889 if(This->share)
890 DSShare_Release(This->share);
891 This->share = NULL;
894 LeaveCriticalSection(&openal_crst);
895 return hr;
898 /* I, Maarten Lankhorst, hereby declare this driver certified
899 * What this means.. ? An extra bit set
901 static HRESULT WINAPI DS8_VerifyCertification(IDirectSound8 *iface, DWORD *certified)
903 DS8Impl *This = impl_from_IDirectSound8(iface);
905 TRACE("(%p)->(%p)\n", iface, certified);
907 if(!certified)
908 return DSERR_INVALIDPARAM;
909 *certified = 0;
911 if(!This->share)
913 WARN("Device not initialized\n");
914 return DSERR_UNINITIALIZED;
917 *certified = DS_CERTIFIED;
919 return DS_OK;
922 static const IDirectSound8Vtbl DS8_Vtbl = {
923 DS8_QueryInterface,
924 DS8_AddRef,
925 DS8_Release,
926 DS8_CreateSoundBuffer,
927 DS8_GetCaps,
928 DS8_DuplicateSoundBuffer,
929 DS8_SetCooperativeLevel,
930 DS8_Compact,
931 DS8_GetSpeakerConfig,
932 DS8_SetSpeakerConfig,
933 DS8_Initialize,
934 DS8_VerifyCertification
938 static HRESULT WINAPI DS_QueryInterface(IDirectSound *iface, REFIID riid, LPVOID *ppv)
940 DS8Impl *This = impl_from_IDirectSound(iface);
941 return DS8_QueryInterface(&This->IDirectSound8_iface, riid, ppv);
944 static ULONG WINAPI DS_AddRef(IDirectSound *iface)
946 DS8Impl *This = impl_from_IDirectSound(iface);
947 return DS8_AddRef(&This->IDirectSound8_iface);
950 static ULONG WINAPI DS_Release(IDirectSound *iface)
952 DS8Impl *This = impl_from_IDirectSound(iface);
953 return DS8_Release(&This->IDirectSound8_iface);
956 static HRESULT WINAPI DS_CreateSoundBuffer(IDirectSound *iface, LPCDSBUFFERDESC desc, LPLPDIRECTSOUNDBUFFER buf, IUnknown *pUnkOuter)
958 DS8Impl *This = impl_from_IDirectSound(iface);
959 return DS8_CreateSoundBuffer(&This->IDirectSound8_iface, desc, buf, pUnkOuter);
962 static HRESULT WINAPI DS_GetCaps(IDirectSound *iface, LPDSCAPS caps)
964 DS8Impl *This = impl_from_IDirectSound(iface);
965 return DS8_GetCaps(&This->IDirectSound8_iface, caps);
967 static HRESULT WINAPI DS_DuplicateSoundBuffer(IDirectSound *iface, IDirectSoundBuffer *in, IDirectSoundBuffer **out)
969 DS8Impl *This = impl_from_IDirectSound(iface);
970 return DS8_DuplicateSoundBuffer(&This->IDirectSound8_iface, in, out);
973 static HRESULT WINAPI DS_SetCooperativeLevel(IDirectSound *iface, HWND hwnd, DWORD level)
975 DS8Impl *This = impl_from_IDirectSound(iface);
976 return DS8_SetCooperativeLevel(&This->IDirectSound8_iface, hwnd, level);
979 static HRESULT WINAPI DS_Compact(IDirectSound *iface)
981 DS8Impl *This = impl_from_IDirectSound(iface);
982 return DS8_Compact(&This->IDirectSound8_iface);
985 static HRESULT WINAPI DS_GetSpeakerConfig(IDirectSound *iface, DWORD *config)
987 DS8Impl *This = impl_from_IDirectSound(iface);
988 return DS8_GetSpeakerConfig(&This->IDirectSound8_iface, config);
991 static HRESULT WINAPI DS_SetSpeakerConfig(IDirectSound *iface, DWORD config)
993 DS8Impl *This = impl_from_IDirectSound(iface);
994 return DS8_SetSpeakerConfig(&This->IDirectSound8_iface, config);
997 static HRESULT WINAPI DS_Initialize(IDirectSound *iface, const GUID *devguid)
999 DS8Impl *This = impl_from_IDirectSound(iface);
1000 return DS8_Initialize(&This->IDirectSound8_iface, devguid);
1003 static const IDirectSoundVtbl DS_Vtbl = {
1004 DS_QueryInterface,
1005 DS_AddRef,
1006 DS_Release,
1007 DS_CreateSoundBuffer,
1008 DS_GetCaps,
1009 DS_DuplicateSoundBuffer,
1010 DS_SetCooperativeLevel,
1011 DS_Compact,
1012 DS_GetSpeakerConfig,
1013 DS_SetSpeakerConfig,
1014 DS_Initialize