Use a separate object for shared device resources
[wine/multimedia.git] / dsound8.c
blob324cefdf45a63466f03b7b7e1f4d6fe33284a63d
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 if(This->primary)
367 DS8Primary_Destroy(This->primary);
368 This->primary = NULL;
369 if(This->share)
370 DSShare_Release(This->share);
371 This->share = NULL;
373 HeapFree(GetProcessHeap(), 0, This);
377 static HRESULT WINAPI DS8_QueryInterface(IDirectSound8 *iface, REFIID riid, LPVOID *ppv)
379 DS8Impl *This = impl_from_IDirectSound8(iface);
381 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
383 *ppv = NULL;
384 if(IsEqualIID(riid, &IID_IUnknown) ||
385 IsEqualIID(riid, &IID_IDirectSound))
386 *ppv = &This->IDirectSound8_iface;
387 else if((IsEqualIID(riid, &IID_IDirectSound8)))
389 if(This->is_8)
390 *ppv = &This->IDirectSound8_iface;
392 else
393 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
395 if(*ppv)
397 IUnknown_AddRef((IUnknown*)*ppv);
398 return S_OK;
401 return E_NOINTERFACE;
404 static ULONG WINAPI DS8_AddRef(IDirectSound8 *iface)
406 DS8Impl *This = impl_from_IDirectSound8(iface);
407 LONG ref;
409 ref = InterlockedIncrement(&This->ref);
410 TRACE("Reference count incremented to %"LONGFMT"d\n", ref);
412 return ref;
415 static ULONG WINAPI DS8_Release(IDirectSound8 *iface)
417 DS8Impl *This = impl_from_IDirectSound8(iface);
418 LONG ref;
420 ref = InterlockedDecrement(&This->ref);
421 TRACE("Reference count decremented to %"LONGFMT"d\n", ref);
422 if(ref == 0)
423 DS8Impl_Destroy(This);
425 return ref;
428 static HRESULT WINAPI DS8_CreateSoundBuffer(IDirectSound8 *iface, LPCDSBUFFERDESC desc, LPLPDIRECTSOUNDBUFFER buf, IUnknown *pUnkOuter)
430 DS8Impl *This = impl_from_IDirectSound8(iface);
431 HRESULT hr;
433 TRACE("(%p)->(%p, %p, %p)\n", iface, desc, buf, pUnkOuter);
435 if(!buf)
437 WARN("buf is null\n");
438 return DSERR_INVALIDPARAM;
440 *buf = NULL;
442 if(pUnkOuter)
444 WARN("Aggregation isn't supported\n");
445 return DSERR_NOAGGREGATION;
447 if(!desc || desc->dwSize < sizeof(DSBUFFERDESC1))
449 WARN("Invalid buffer %p/%"LONGFMT"u\n", desc, desc?desc->dwSize:0);
450 return DSERR_INVALIDPARAM;
453 if(!This->primary)
455 WARN("Device not initialized\n");
456 return DSERR_UNINITIALIZED;
459 TRACE("Requested buffer:\n"
460 " Size = %"LONGFMT"u\n"
461 " Flags = 0x%08"LONGFMT"x\n"
462 " BufferBytes = %"LONGFMT"u\n",
463 desc->dwSize, desc->dwFlags, desc->dwBufferBytes);
465 if(desc->dwSize >= sizeof(DSBUFFERDESC))
467 if(!(desc->dwFlags&DSBCAPS_CTRL3D))
469 if(!IsEqualGUID(&desc->guid3DAlgorithm, &GUID_NULL))
471 WARN("Invalid 3D algorithm GUID specified for non-3D buffer: %s\n", debugstr_guid(&desc->guid3DAlgorithm));
472 return DSERR_INVALIDPARAM;
475 else
476 TRACE("Requested 3D algorithm GUID: %s\n", debugstr_guid(&desc->guid3DAlgorithm));
479 /* OpenAL doesn't support playing with 3d and panning at same time.. */
480 if((desc->dwFlags&(DSBCAPS_CTRL3D|DSBCAPS_CTRLPAN)) == (DSBCAPS_CTRL3D|DSBCAPS_CTRLPAN))
482 if(!This->is_8)
483 ERR("Cannot create buffers with 3D and panning control\n");
484 else
485 WARN("Cannot create buffers with 3D and panning control\n");
486 return DSERR_INVALIDPARAM;
489 EnterCriticalSection(This->primary->crst);
490 if((desc->dwFlags&DSBCAPS_PRIMARYBUFFER))
492 IDirectSoundBuffer *prim = &This->primary->IDirectSoundBuffer_iface;
494 hr = S_OK;
495 if(IDirectSoundBuffer_AddRef(prim) == 1)
497 hr = IDirectSoundBuffer_Initialize(prim, &This->IDirectSound_iface, desc);
498 if(FAILED(hr))
500 IDirectSoundBuffer_Release(prim);
501 prim = NULL;
504 *buf = prim;
506 else
508 DS8Buffer *dsb;
510 hr = DS8Buffer_Create(&dsb, This->primary, NULL);
511 if(SUCCEEDED(hr))
513 hr = IDirectSoundBuffer8_Initialize(&dsb->IDirectSoundBuffer8_iface, &This->IDirectSound_iface, desc);
514 if(FAILED(hr))
515 IDirectSoundBuffer8_Release(&dsb->IDirectSoundBuffer8_iface);
516 else
518 dsb->bufferlost = (This->prio_level == DSSCL_WRITEPRIMARY);
519 *buf = &dsb->IDirectSoundBuffer_iface;
523 LeaveCriticalSection(This->primary->crst);
525 TRACE("%08"LONGFMT"x\n", hr);
526 return hr;
529 static HRESULT WINAPI DS8_GetCaps(IDirectSound8 *iface, LPDSCAPS caps)
531 DS8Impl *This = impl_from_IDirectSound8(iface);
533 TRACE("(%p)->(%p)\n", iface, caps);
535 if(!This->primary)
537 WARN("Device not initialized\n");
538 return DSERR_UNINITIALIZED;
541 if(!caps || caps->dwSize < sizeof(*caps))
543 WARN("Invalid DSCAPS (%p, %"LONGFMT"u)\n", caps, (caps?caps->dwSize:0));
544 return DSERR_INVALIDPARAM;
547 EnterCriticalSection(&This->share->crst);
549 caps->dwFlags = DSCAPS_CONTINUOUSRATE |
550 DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYSTEREO |
551 DSCAPS_PRIMARY8BIT | DSCAPS_PRIMARYMONO |
552 DSCAPS_SECONDARY16BIT | DSCAPS_SECONDARY8BIT |
553 DSCAPS_SECONDARYMONO | DSCAPS_SECONDARYSTEREO;
554 caps->dwPrimaryBuffers = 1;
555 caps->dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
556 caps->dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
557 caps->dwMaxHwMixingAllBuffers =
558 caps->dwMaxHwMixingStaticBuffers =
559 caps->dwMaxHwMixingStreamingBuffers =
560 caps->dwMaxHw3DAllBuffers =
561 caps->dwMaxHw3DStaticBuffers =
562 caps->dwMaxHw3DStreamingBuffers = This->share->max_sources;
563 caps->dwFreeHwMixingAllBuffers =
564 caps->dwFreeHwMixingStaticBuffers =
565 caps->dwFreeHwMixingStreamingBuffers =
566 caps->dwFreeHw3DAllBuffers =
567 caps->dwFreeHw3DStaticBuffers =
568 caps->dwFreeHw3DStreamingBuffers = This->share->nsources;
569 caps->dwTotalHwMemBytes =
570 caps->dwFreeHwMemBytes = 64 * 1024 * 1024;
571 caps->dwMaxContigFreeHwMemBytes = caps->dwFreeHwMemBytes;
572 caps->dwUnlockTransferRateHwBuffers = 4096;
573 caps->dwPlayCpuOverheadSwBuffers = 0;
575 LeaveCriticalSection(&This->share->crst);
577 return DS_OK;
579 static HRESULT WINAPI DS8_DuplicateSoundBuffer(IDirectSound8 *iface, IDirectSoundBuffer *in, IDirectSoundBuffer **out)
581 DS8Impl *This = impl_from_IDirectSound8(iface);
582 DS8Buffer *buf;
583 DSBCAPS caps;
584 HRESULT hr;
586 TRACE("(%p)->(%p, %p)\n", iface, in, out);
588 if(!This->share)
590 WARN("Device not initialized\n");
591 return DSERR_UNINITIALIZED;
594 if(!in || !out)
596 WARN("Invalid pointer: int = %p, out = %p\n", in, out);
597 return DSERR_INVALIDPARAM;
599 *out = NULL;
601 caps.dwSize = sizeof(caps);
602 hr = IDirectSoundBuffer_GetCaps(in, &caps);
603 if(SUCCEEDED(hr) && (caps.dwFlags&DSBCAPS_PRIMARYBUFFER))
605 WARN("Cannot duplicate buffer %p, which has DSBCAPS_PRIMARYBUFFER\n", in);
606 hr = DSERR_INVALIDPARAM;
608 if(SUCCEEDED(hr) && (caps.dwFlags&DSBCAPS_CTRLFX))
610 WARN("Cannot duplicate buffer %p, which has DSBCAPS_CTRLFX\n", in);
611 hr = DSERR_INVALIDPARAM;
613 if(SUCCEEDED(hr))
614 hr = DS8Buffer_Create(&buf, This->primary, in);
615 if(SUCCEEDED(hr))
617 *out = &buf->IDirectSoundBuffer_iface;
618 hr = IDirectSoundBuffer_Initialize(*out, NULL, NULL);
620 if(SUCCEEDED(hr))
622 /* According to MSDN volume isn't copied */
623 if((caps.dwFlags&DSBCAPS_CTRLPAN))
625 LONG pan;
626 if(SUCCEEDED(IDirectSoundBuffer_GetPan(in, &pan)))
627 IDirectSoundBuffer_SetPan(*out, pan);
629 if((caps.dwFlags&DSBCAPS_CTRLFREQUENCY))
631 DWORD freq;
632 if(SUCCEEDED(IDirectSoundBuffer_GetFrequency(in, &freq)))
633 IDirectSoundBuffer_SetFrequency(*out, freq);
635 if((caps.dwFlags&DSBCAPS_CTRL3D))
637 IDirectSound3DBuffer *buf3d;
638 DS3DBUFFER DS3DBuffer;
639 HRESULT subhr;
641 subhr = IDirectSound_QueryInterface(in, &IID_IDirectSound3DBuffer, (void**)&buf3d);
642 if(SUCCEEDED(subhr))
644 DS3DBuffer.dwSize = sizeof(DS3DBuffer);
645 subhr = IDirectSound3DBuffer_GetAllParameters(buf3d, &DS3DBuffer);
646 IDirectSound3DBuffer_Release(buf3d);
648 if(SUCCEEDED(subhr))
649 subhr = IDirectSoundBuffer_QueryInterface(*out, &IID_IDirectSound3DBuffer, (void**)&buf3d);
650 if(SUCCEEDED(subhr))
652 subhr = IDirectSound3DBuffer_SetAllParameters(buf3d, &DS3DBuffer, DS3D_IMMEDIATE);
653 IDirectSound3DBuffer_Release(buf3d);
657 if(FAILED(hr))
659 if(*out)
660 IDirectSoundBuffer_Release(*out);
661 *out = NULL;
664 return hr;
667 static HRESULT WINAPI DS8_SetCooperativeLevel(IDirectSound8 *iface, HWND hwnd, DWORD level)
669 DS8Impl *This = impl_from_IDirectSound8(iface);
670 HRESULT hr = S_OK;
672 TRACE("(%p)->(%p, %"LONGFMT"u)\n", iface, hwnd, level);
674 if(!This->share)
676 WARN("Device not initialized\n");
677 return DSERR_UNINITIALIZED;
680 if(level > DSSCL_WRITEPRIMARY || level < DSSCL_NORMAL)
682 WARN("Invalid coop level: %"LONGFMT"u\n", level);
683 return DSERR_INVALIDPARAM;
686 EnterCriticalSection(This->primary->crst);
687 if(level == DSSCL_WRITEPRIMARY && (This->prio_level != DSSCL_WRITEPRIMARY))
689 DWORD i, state;
691 for(i = 0; i < This->primary->nbuffers; ++i)
693 DS8Buffer *buf = This->primary->buffers[i];
694 if(FAILED(IDirectSoundBuffer_GetStatus(&buf->IDirectSoundBuffer8_iface, &state)) ||
695 (state&DSBSTATUS_PLAYING))
697 WARN("DSSCL_WRITEPRIMARY set with playing buffers!\n");
698 hr = DSERR_INVALIDCALL;
699 goto out;
701 /* Mark buffer as lost */
702 buf->bufferlost = 1;
704 if(This->primary->write_emu)
706 ERR("Why was there a write_emu?\n");
707 /* Delete it */
708 IDirectSoundBuffer8_Release(This->primary->write_emu);
709 This->primary->write_emu = NULL;
711 if(This->primary->flags)
713 /* Primary has open references.. create write_emu */
714 DSBUFFERDESC desc;
715 DS8Buffer *emu;
717 memset(&desc, 0, sizeof(desc));
718 desc.dwSize = sizeof(desc);
719 desc.dwFlags = DSBCAPS_LOCHARDWARE | (This->primary->flags&DSBCAPS_CTRLPAN);
720 desc.dwBufferBytes = This->primary->buf_size;
721 desc.lpwfxFormat = &This->primary->format.Format;
723 hr = DS8Buffer_Create(&emu, This->primary, NULL);
724 if(SUCCEEDED(hr))
726 This->primary->write_emu = &emu->IDirectSoundBuffer8_iface;
727 hr = IDirectSoundBuffer8_Initialize(This->primary->write_emu, &This->IDirectSound_iface, &desc);
728 if(FAILED(hr))
730 IDirectSoundBuffer8_Release(This->primary->write_emu);
731 This->primary->write_emu = NULL;
736 else if(This->prio_level == DSSCL_WRITEPRIMARY && level != DSSCL_WRITEPRIMARY && This->primary->write_emu)
738 TRACE("Nuking write_emu\n");
739 /* Delete it */
740 IDirectSoundBuffer8_Release(This->primary->write_emu);
741 This->primary->write_emu = NULL;
743 if(SUCCEEDED(hr))
744 This->prio_level = level;
745 out:
746 LeaveCriticalSection(This->primary->crst);
748 return hr;
751 static HRESULT WINAPI DS8_Compact(IDirectSound8 *iface)
753 DS8Impl *This = impl_from_IDirectSound8(iface);
754 HRESULT hr = S_OK;
756 TRACE("(%p)->()\n", iface);
758 if(!This->share)
760 WARN("Device not initialized\n");
761 return DSERR_UNINITIALIZED;
764 EnterCriticalSection(&This->share->crst);
765 if(This->prio_level < DSSCL_PRIORITY)
767 WARN("Coop level not high enough (%"LONGFMT"u)\n", This->prio_level);
768 hr = DSERR_PRIOLEVELNEEDED;
770 LeaveCriticalSection(&This->share->crst);
772 return hr;
775 static HRESULT WINAPI DS8_GetSpeakerConfig(IDirectSound8 *iface, DWORD *config)
777 DS8Impl *This = impl_from_IDirectSound8(iface);
778 HRESULT hr = S_OK;
780 TRACE("(%p)->(%p)\n", iface, config);
782 if(!config)
783 return DSERR_INVALIDPARAM;
784 *config = 0;
786 if(!This->primary)
788 WARN("Device not initialized\n");
789 return DSERR_UNINITIALIZED;
792 EnterCriticalSection(&This->share->crst);
793 *config = This->speaker_config;
794 LeaveCriticalSection(&This->share->crst);
796 return hr;
799 static HRESULT WINAPI DS8_SetSpeakerConfig(IDirectSound8 *iface, DWORD config)
801 DS8Impl *This = impl_from_IDirectSound8(iface);
802 DWORD geo, speaker;
803 HKEY key;
804 HRESULT hr;
806 TRACE("(%p)->(0x%08"LONGFMT"x)\n", iface, config);
808 if(!This->share)
810 WARN("Device not initialized\n");
811 return DSERR_UNINITIALIZED;
814 geo = DSSPEAKER_GEOMETRY(config);
815 speaker = DSSPEAKER_CONFIG(config);
817 if(geo && (geo < DSSPEAKER_GEOMETRY_MIN || geo > DSSPEAKER_GEOMETRY_MAX))
819 WARN("Invalid speaker angle %"LONGFMT"u\n", geo);
820 return DSERR_INVALIDPARAM;
822 if(speaker < DSSPEAKER_HEADPHONE || speaker > DSSPEAKER_7POINT1)
824 WARN("Invalid speaker config %"LONGFMT"u\n", speaker);
825 return DSERR_INVALIDPARAM;
828 EnterCriticalSection(&This->share->crst);
830 hr = DSERR_GENERIC;
831 if(!RegCreateKeyExW(HKEY_LOCAL_MACHINE, speakerconfigkey, 0, NULL, 0, KEY_WRITE, NULL, &key, NULL))
833 RegSetValueExW(key, speakerconfig, 0, REG_DWORD, (const BYTE*)&config, sizeof(DWORD));
834 This->speaker_config = config;
835 RegCloseKey(key);
836 hr = S_OK;
839 LeaveCriticalSection(&This->share->crst);
840 return hr;
843 static HRESULT WINAPI DS8_Initialize(IDirectSound8 *iface, const GUID *devguid)
845 DS8Impl *This = impl_from_IDirectSound8(iface);
846 HRESULT hr;
847 GUID guid;
848 UINT n;
850 TRACE("(%p)->(%s)\n", iface, debugstr_guid(devguid));
852 if(!openal_loaded)
853 return DSERR_NODRIVER;
855 if(This->primary)
857 WARN("Device already initialized\n");
858 return DSERR_ALREADYINITIALIZED;
861 if(!devguid)
862 devguid = &DSDEVID_DefaultPlayback;
863 hr = GetDeviceID(devguid, &guid);
864 if(FAILED(hr))
865 return hr;
867 EnterCriticalSection(&openal_crst);
869 for(n = 0;n < sharelistsize;n++)
871 if(IsEqualGUID(&sharelist[n]->guid, &guid))
873 TRACE("Matched already open device %p\n", sharelist[n]->device);
875 This->share = sharelist[n];
876 DSShare_AddRef(This->share);
877 break;
881 if(!This->share)
882 hr = DSShare_Create(&guid, &This->share);
883 if(SUCCEEDED(hr))
885 This->device = This->share->device;
886 hr = DS8Primary_Create(&This->primary, This);
889 if(FAILED(hr))
891 if(This->share)
892 DSShare_Release(This->share);
893 This->share = NULL;
896 LeaveCriticalSection(&openal_crst);
897 return hr;
900 /* I, Maarten Lankhorst, hereby declare this driver certified
901 * What this means.. ? An extra bit set
903 static HRESULT WINAPI DS8_VerifyCertification(IDirectSound8 *iface, DWORD *certified)
905 DS8Impl *This = impl_from_IDirectSound8(iface);
907 TRACE("(%p)->(%p)\n", iface, certified);
909 if(!certified)
910 return DSERR_INVALIDPARAM;
911 *certified = 0;
913 if(!This->primary)
915 WARN("Device not initialized\n");
916 return DSERR_UNINITIALIZED;
919 *certified = DS_CERTIFIED;
921 return DS_OK;
924 static const IDirectSound8Vtbl DS8_Vtbl = {
925 DS8_QueryInterface,
926 DS8_AddRef,
927 DS8_Release,
928 DS8_CreateSoundBuffer,
929 DS8_GetCaps,
930 DS8_DuplicateSoundBuffer,
931 DS8_SetCooperativeLevel,
932 DS8_Compact,
933 DS8_GetSpeakerConfig,
934 DS8_SetSpeakerConfig,
935 DS8_Initialize,
936 DS8_VerifyCertification
940 static HRESULT WINAPI DS_QueryInterface(IDirectSound *iface, REFIID riid, LPVOID *ppv)
942 DS8Impl *This = impl_from_IDirectSound(iface);
943 return DS8_QueryInterface(&This->IDirectSound8_iface, riid, ppv);
946 static ULONG WINAPI DS_AddRef(IDirectSound *iface)
948 DS8Impl *This = impl_from_IDirectSound(iface);
949 return DS8_AddRef(&This->IDirectSound8_iface);
952 static ULONG WINAPI DS_Release(IDirectSound *iface)
954 DS8Impl *This = impl_from_IDirectSound(iface);
955 return DS8_Release(&This->IDirectSound8_iface);
958 static HRESULT WINAPI DS_CreateSoundBuffer(IDirectSound *iface, LPCDSBUFFERDESC desc, LPLPDIRECTSOUNDBUFFER buf, IUnknown *pUnkOuter)
960 DS8Impl *This = impl_from_IDirectSound(iface);
961 return DS8_CreateSoundBuffer(&This->IDirectSound8_iface, desc, buf, pUnkOuter);
964 static HRESULT WINAPI DS_GetCaps(IDirectSound *iface, LPDSCAPS caps)
966 DS8Impl *This = impl_from_IDirectSound(iface);
967 return DS8_GetCaps(&This->IDirectSound8_iface, caps);
969 static HRESULT WINAPI DS_DuplicateSoundBuffer(IDirectSound *iface, IDirectSoundBuffer *in, IDirectSoundBuffer **out)
971 DS8Impl *This = impl_from_IDirectSound(iface);
972 return DS8_DuplicateSoundBuffer(&This->IDirectSound8_iface, in, out);
975 static HRESULT WINAPI DS_SetCooperativeLevel(IDirectSound *iface, HWND hwnd, DWORD level)
977 DS8Impl *This = impl_from_IDirectSound(iface);
978 return DS8_SetCooperativeLevel(&This->IDirectSound8_iface, hwnd, level);
981 static HRESULT WINAPI DS_Compact(IDirectSound *iface)
983 DS8Impl *This = impl_from_IDirectSound(iface);
984 return DS8_Compact(&This->IDirectSound8_iface);
987 static HRESULT WINAPI DS_GetSpeakerConfig(IDirectSound *iface, DWORD *config)
989 DS8Impl *This = impl_from_IDirectSound(iface);
990 return DS8_GetSpeakerConfig(&This->IDirectSound8_iface, config);
993 static HRESULT WINAPI DS_SetSpeakerConfig(IDirectSound *iface, DWORD config)
995 DS8Impl *This = impl_from_IDirectSound(iface);
996 return DS8_SetSpeakerConfig(&This->IDirectSound8_iface, config);
999 static HRESULT WINAPI DS_Initialize(IDirectSound *iface, const GUID *devguid)
1001 DS8Impl *This = impl_from_IDirectSound(iface);
1002 return DS8_Initialize(&This->IDirectSound8_iface, devguid);
1005 static const IDirectSoundVtbl DS_Vtbl = {
1006 DS_QueryInterface,
1007 DS_AddRef,
1008 DS_Release,
1009 DS_CreateSoundBuffer,
1010 DS_GetCaps,
1011 DS_DuplicateSoundBuffer,
1012 DS_SetCooperativeLevel,
1013 DS_Compact,
1014 DS_GetSpeakerConfig,
1015 DS_SetSpeakerConfig,
1016 DS_Initialize