Rename a couple primary and secondary buffer fields
[dsound-openal.git] / dsound8.c
blobe40f65edc95bc0de6a632cf49515bb47e93ea247
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->auxslot)
100 share->ExtAL.DeleteAuxiliaryEffectSlots(1, &share->auxslot);
102 set_context(old_ctx);
103 alcDestroyContext(share->ctx);
104 LeaveCriticalSection(&openal_crst);
107 if(share->device)
108 alcCloseDevice(share->device);
109 share->device = NULL;
111 share->crst.DebugInfo->Spare[0] = 0;
112 DeleteCriticalSection(&share->crst);
114 HeapFree(GetProcessHeap(), 0, share);
117 static HRESULT DSShare_Create(REFIID guid, DeviceShare **out)
119 const ALCchar *drv_name;
120 DeviceShare *share;
121 void *temp;
122 HRESULT hr;
123 DWORD n;
125 share = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*share));
126 if(!share) return DSERR_OUTOFMEMORY;
127 share->ref = 1;
129 InitializeCriticalSection(&share->crst);
130 share->crst.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": Device.crst");
132 hr = DSERR_NODRIVER;
133 if(!(drv_name=DSOUND_getdevicestrings()) ||
134 memcmp(guid, &DSOUND_renderer_guid, sizeof(GUID)-1) != 0)
136 WARN("No device found\n");
137 goto fail;
140 n = guid->Data4[7];
141 while(*drv_name && n--)
142 drv_name += strlen(drv_name) + 1;
143 if(!*drv_name)
145 WARN("No device string found\n");
146 goto fail;
148 memcpy(&share->guid, guid, sizeof(GUID));
150 share->device = alcOpenDevice(drv_name);
151 if(!share->device)
153 alcGetError(NULL);
154 WARN("Couldn't open device \"%s\"\n", drv_name);
155 goto fail;
157 TRACE("Opened device: %s\n", alcGetString(share->device, ALC_DEVICE_SPECIFIER));
159 hr = DSERR_NODRIVER;
160 share->ctx = alcCreateContext(share->device, NULL);
161 if(!share->ctx)
163 ALCenum err = alcGetError(share->device);
164 ERR("Could not create context (0x%x)!\n", err);
165 goto fail;
168 setALContext(share->ctx);
169 if(alIsExtensionPresent("AL_EXT_FLOAT32"))
171 TRACE("Found AL_EXT_FLOAT32\n");
172 share->SupportedExt[EXT_FLOAT32] = AL_TRUE;
174 if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
176 TRACE("Found AL_EXT_MCFORMATS\n");
177 share->SupportedExt[EXT_MCFORMATS] = AL_TRUE;
179 if(alIsExtensionPresent("AL_EXT_STATIC_BUFFER"))
181 TRACE("Found AL_EXT_STATIC_BUFFER\n");
182 share->ExtAL.BufferDataStatic = alGetProcAddress("alBufferDataStatic");
183 share->SupportedExt[EXT_STATIC_BUFFER] = AL_TRUE;
185 if(alIsExtensionPresent("AL_SOFTX_buffer_samples"))
187 TRACE("Found AL_SOFTX_buffer_samples\n");
188 share->ExtAL.BufferSamplesSOFT = alGetProcAddress("alBufferSamplesSOFT");
189 share->ExtAL.BufferSubSamplesSOFT = alGetProcAddress("alBufferSubSamplesSOFT");
190 share->ExtAL.GetBufferSamplesSOFT = alGetProcAddress("alGetBufferSamplesSOFT");
191 share->ExtAL.IsBufferFormatSupportedSOFT = alGetProcAddress("alIsBufferFormatSupportedSOFT");
192 share->SupportedExt[SOFT_BUFFER_SAMPLES] = AL_TRUE;
194 if(alIsExtensionPresent("AL_SOFT_buffer_sub_data"))
196 TRACE("Found AL_SOFT_buffer_sub_data\n");
197 share->ExtAL.BufferSubData = alGetProcAddress("alBufferSubDataSOFT");
198 share->SupportedExt[SOFT_BUFFER_SUB_DATA] = AL_TRUE;
200 if(alIsExtensionPresent("AL_SOFTX_deferred_updates"))
202 TRACE("Found AL_SOFTX_deferred_updates\n");
203 share->ExtAL.DeferUpdatesSOFT = alGetProcAddress("alDeferUpdatesSOFT");
204 share->ExtAL.ProcessUpdatesSOFT = alGetProcAddress("alProcessUpdatesSOFT");
205 share->SupportedExt[SOFT_DEFERRED_UPDATES] = AL_TRUE;
208 if(alcIsExtensionPresent(share->device, "ALC_EXT_EFX"))
210 #define LOAD_FUNC(x) (share->ExtAL.x = alGetProcAddress("al"#x))
211 LOAD_FUNC(GenEffects);
212 LOAD_FUNC(DeleteEffects);
213 LOAD_FUNC(Effecti);
214 LOAD_FUNC(Effectf);
216 LOAD_FUNC(GenAuxiliaryEffectSlots);
217 LOAD_FUNC(DeleteAuxiliaryEffectSlots);
218 LOAD_FUNC(AuxiliaryEffectSloti);
219 #undef LOAD_FUNC
220 share->SupportedExt[EXT_EFX] = AL_TRUE;
222 share->ExtAL.GenAuxiliaryEffectSlots(1, &share->auxslot);
225 if(!share->SupportedExt[SOFT_BUFFER_SUB_DATA] &&
226 !share->SupportedExt[SOFT_BUFFER_SAMPLES] &&
227 !share->SupportedExt[EXT_STATIC_BUFFER])
229 ERR("Missing alBufferSubDataSOFT, alBufferSamplesSOFT , and alBufferDataStatic on device '%s', sound playback quality may be degraded\n",
230 alcGetString(share->device, ALC_DEVICE_SPECIFIER));
231 ERR("Please consider using OpenAL-Soft\n");
234 share->max_sources = 0;
235 while(share->max_sources < MAX_SOURCES)
237 alGenSources(1, &share->sources[share->max_sources]);
238 if(alGetError() != AL_NO_ERROR)
239 break;
240 share->max_sources++;
242 share->nsources = share->max_sources;
243 popALContext();
245 if(sharelist)
246 temp = HeapReAlloc(GetProcessHeap(), 0, sharelist, sizeof(*sharelist)*(sharelistsize+1));
247 else
248 temp = HeapAlloc(GetProcessHeap(), 0, sizeof(*sharelist)*(sharelistsize+1));
249 if(temp)
251 sharelist = temp;
252 sharelist[sharelistsize++] = share;
255 *out = share;
256 return DS_OK;
258 fail:
259 DSShare_Destroy(share);
260 return hr;
263 static ULONG DSShare_AddRef(DeviceShare *share)
265 ULONG ref = InterlockedIncrement(&share->ref);
266 return ref;
269 static ULONG DSShare_Release(DeviceShare *share)
271 ULONG ref = InterlockedDecrement(&share->ref);
272 if(ref == 0) DSShare_Destroy(share);
273 return ref;
277 static const IDirectSound8Vtbl DS8_Vtbl;
278 static const IDirectSoundVtbl DS_Vtbl;
280 static inline DS8Impl *impl_from_IDirectSound8(IDirectSound8 *iface)
282 return CONTAINING_RECORD(iface, DS8Impl, IDirectSound8_iface);
285 static inline DS8Impl *impl_from_IDirectSound(IDirectSound *iface)
287 return CONTAINING_RECORD(iface, DS8Impl, IDirectSound_iface);
290 HRESULT DSOUND_Create(REFIID riid, void **ds)
292 HRESULT hr;
294 hr = DSOUND_Create8(&IID_IDirectSound, ds);
295 if(SUCCEEDED(hr))
297 DS8Impl *impl = impl_from_IDirectSound(*ds);
298 impl->is_8 = FALSE;
300 if(!IsEqualIID(riid, &IID_IDirectSound))
302 hr = IDirectSound_QueryInterface(&impl->IDirectSound_iface, riid, ds);
303 IDirectSound_Release(&impl->IDirectSound_iface);
306 return hr;
309 static void DS8Impl_Destroy(DS8Impl *This);
311 static const WCHAR speakerconfigkey[] = {
312 'S','Y','S','T','E','M','\\',
313 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
314 'C','o','n','t','r','o','l','\\',
315 'M','e','d','i','a','R','e','s','o','u','r','c','e','s','\\',
316 'D','i','r','e','c','t','S','o','u','n','d','\\',
317 'S','p','e','a','k','e','r',' ','C','o','n','f','i','g','u','r','a','t','i','o','n',0
320 static const WCHAR speakerconfig[] = {
321 'S','p','e','a','k','e','r',' ','C','o','n','f','i','g','u','r','a','t','i','o','n',0
324 HRESULT DSOUND_Create8(REFIID riid, LPVOID *ds)
326 DS8Impl *This;
327 HKEY regkey;
328 HRESULT hr;
330 *ds = NULL;
331 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
332 if(!This) return DSERR_OUTOFMEMORY;
334 This->IDirectSound8_iface.lpVtbl = (IDirectSound8Vtbl*)&DS8_Vtbl;
335 This->IDirectSound_iface.lpVtbl = (IDirectSoundVtbl*)&DS_Vtbl;
337 This->is_8 = TRUE;
338 This->speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_5POINT1, DSSPEAKER_GEOMETRY_WIDE);
340 if(RegOpenKeyExW(HKEY_LOCAL_MACHINE, speakerconfigkey, 0, KEY_READ, &regkey) == ERROR_SUCCESS)
342 DWORD type, conf, confsize = sizeof(DWORD);
344 if(RegQueryValueExW(regkey, speakerconfig, NULL, &type, (BYTE*)&conf, &confsize) == ERROR_SUCCESS)
346 if(type == REG_DWORD)
347 This->speaker_config = conf;
350 RegCloseKey(regkey);
352 /*RegGetValueW(HKEY_LOCAL_MACHINE, speakerconfigkey, speakerconfig, RRF_RT_REG_DWORD, NULL, &This->speaker_config, NULL);*/
354 hr = IDirectSound8_QueryInterface(&This->IDirectSound8_iface, riid, ds);
355 if(FAILED(hr))
356 DS8Impl_Destroy(This);
357 return hr;
360 static void DS8Impl_Destroy(DS8Impl *This)
362 DS8Primary_Clear(&This->primary);
363 if(This->share)
364 DSShare_Release(This->share);
365 This->share = NULL;
367 HeapFree(GetProcessHeap(), 0, This);
371 static HRESULT WINAPI DS8_QueryInterface(IDirectSound8 *iface, REFIID riid, LPVOID *ppv)
373 DS8Impl *This = impl_from_IDirectSound8(iface);
375 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
377 *ppv = NULL;
378 if(IsEqualIID(riid, &IID_IUnknown))
379 *ppv = &This->IDirectSound8_iface;
380 else if(IsEqualIID(riid, &IID_IDirectSound8))
382 if(This->is_8)
383 *ppv = &This->IDirectSound8_iface;
385 else if(IsEqualIID(riid, &IID_IDirectSound))
386 *ppv = &This->IDirectSound_iface;
387 else
388 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
390 if(*ppv)
392 IUnknown_AddRef((IUnknown*)*ppv);
393 return S_OK;
396 return E_NOINTERFACE;
399 static ULONG WINAPI DS8_AddRef(IDirectSound8 *iface)
401 DS8Impl *This = impl_from_IDirectSound8(iface);
402 LONG ref;
404 ref = InterlockedIncrement(&This->ref);
405 TRACE("Reference count incremented to %"LONGFMT"d\n", ref);
407 return ref;
410 static ULONG WINAPI DS8_Release(IDirectSound8 *iface)
412 DS8Impl *This = impl_from_IDirectSound8(iface);
413 LONG ref;
415 ref = InterlockedDecrement(&This->ref);
416 TRACE("Reference count decremented to %"LONGFMT"d\n", ref);
417 if(ref == 0)
418 DS8Impl_Destroy(This);
420 return ref;
423 static HRESULT WINAPI DS8_CreateSoundBuffer(IDirectSound8 *iface, LPCDSBUFFERDESC desc, LPLPDIRECTSOUNDBUFFER buf, IUnknown *pUnkOuter)
425 DS8Impl *This = impl_from_IDirectSound8(iface);
426 HRESULT hr;
428 TRACE("(%p)->(%p, %p, %p)\n", iface, desc, buf, pUnkOuter);
430 if(!buf)
432 WARN("buf is null\n");
433 return DSERR_INVALIDPARAM;
435 *buf = NULL;
437 if(pUnkOuter)
439 WARN("Aggregation isn't supported\n");
440 return DSERR_NOAGGREGATION;
442 if(!desc || desc->dwSize < sizeof(DSBUFFERDESC1))
444 WARN("Invalid buffer %p/%"LONGFMT"u\n", desc, desc?desc->dwSize:0);
445 return DSERR_INVALIDPARAM;
448 if(!This->share)
450 WARN("Device not initialized\n");
451 return DSERR_UNINITIALIZED;
454 TRACE("Requested buffer:\n"
455 " Size = %"LONGFMT"u\n"
456 " Flags = 0x%08"LONGFMT"x\n"
457 " BufferBytes = %"LONGFMT"u\n",
458 desc->dwSize, desc->dwFlags, desc->dwBufferBytes);
460 if(desc->dwSize >= sizeof(DSBUFFERDESC))
462 if(!(desc->dwFlags&DSBCAPS_CTRL3D))
464 if(!IsEqualGUID(&desc->guid3DAlgorithm, &GUID_NULL))
466 WARN("Invalid 3D algorithm GUID specified for non-3D buffer: %s\n", debugstr_guid(&desc->guid3DAlgorithm));
467 return DSERR_INVALIDPARAM;
470 else
471 TRACE("Requested 3D algorithm GUID: %s\n", debugstr_guid(&desc->guid3DAlgorithm));
474 /* OpenAL doesn't support playing with 3d and panning at same time.. */
475 if((desc->dwFlags&(DSBCAPS_CTRL3D|DSBCAPS_CTRLPAN)) == (DSBCAPS_CTRL3D|DSBCAPS_CTRLPAN))
477 if(!This->is_8)
478 ERR("Cannot create buffers with 3D and panning control\n");
479 else
480 WARN("Cannot create buffers with 3D and panning control\n");
481 return DSERR_INVALIDPARAM;
484 EnterCriticalSection(This->primary.crst);
485 if((desc->dwFlags&DSBCAPS_PRIMARYBUFFER))
487 IDirectSoundBuffer *prim = &This->primary.IDirectSoundBuffer_iface;
489 hr = S_OK;
490 if(IDirectSoundBuffer_AddRef(prim) == 1)
492 hr = IDirectSoundBuffer_Initialize(prim, &This->IDirectSound_iface, desc);
493 if(FAILED(hr))
495 IDirectSoundBuffer_Release(prim);
496 prim = NULL;
499 *buf = prim;
501 else
503 DS8Buffer *dsb;
505 hr = DS8Buffer_Create(&dsb, &This->primary, NULL);
506 if(SUCCEEDED(hr))
508 hr = IDirectSoundBuffer8_Initialize(&dsb->IDirectSoundBuffer8_iface, &This->IDirectSound_iface, desc);
509 if(FAILED(hr))
510 IDirectSoundBuffer8_Release(&dsb->IDirectSoundBuffer8_iface);
511 else
513 dsb->bufferlost = (This->prio_level == DSSCL_WRITEPRIMARY);
514 *buf = &dsb->IDirectSoundBuffer_iface;
518 LeaveCriticalSection(This->primary.crst);
520 TRACE("%08"LONGFMT"x\n", hr);
521 return hr;
524 static HRESULT WINAPI DS8_GetCaps(IDirectSound8 *iface, LPDSCAPS caps)
526 DS8Impl *This = impl_from_IDirectSound8(iface);
528 TRACE("(%p)->(%p)\n", iface, caps);
530 if(!This->share)
532 WARN("Device not initialized\n");
533 return DSERR_UNINITIALIZED;
536 if(!caps || caps->dwSize < sizeof(*caps))
538 WARN("Invalid DSCAPS (%p, %"LONGFMT"u)\n", caps, (caps?caps->dwSize:0));
539 return DSERR_INVALIDPARAM;
542 EnterCriticalSection(&This->share->crst);
544 caps->dwFlags = DSCAPS_CONTINUOUSRATE |
545 DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYSTEREO |
546 DSCAPS_PRIMARY8BIT | DSCAPS_PRIMARYMONO |
547 DSCAPS_SECONDARY16BIT | DSCAPS_SECONDARY8BIT |
548 DSCAPS_SECONDARYMONO | DSCAPS_SECONDARYSTEREO;
549 caps->dwPrimaryBuffers = 1;
550 caps->dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
551 caps->dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
552 caps->dwMaxHwMixingAllBuffers =
553 caps->dwMaxHwMixingStaticBuffers =
554 caps->dwMaxHwMixingStreamingBuffers =
555 caps->dwMaxHw3DAllBuffers =
556 caps->dwMaxHw3DStaticBuffers =
557 caps->dwMaxHw3DStreamingBuffers = This->share->max_sources;
558 caps->dwFreeHwMixingAllBuffers =
559 caps->dwFreeHwMixingStaticBuffers =
560 caps->dwFreeHwMixingStreamingBuffers =
561 caps->dwFreeHw3DAllBuffers =
562 caps->dwFreeHw3DStaticBuffers =
563 caps->dwFreeHw3DStreamingBuffers = This->share->nsources;
564 caps->dwTotalHwMemBytes =
565 caps->dwFreeHwMemBytes = 64 * 1024 * 1024;
566 caps->dwMaxContigFreeHwMemBytes = caps->dwFreeHwMemBytes;
567 caps->dwUnlockTransferRateHwBuffers = 4096;
568 caps->dwPlayCpuOverheadSwBuffers = 0;
570 LeaveCriticalSection(&This->share->crst);
572 return DS_OK;
574 static HRESULT WINAPI DS8_DuplicateSoundBuffer(IDirectSound8 *iface, IDirectSoundBuffer *in, IDirectSoundBuffer **out)
576 DS8Impl *This = impl_from_IDirectSound8(iface);
577 DS8Buffer *buf;
578 DSBCAPS caps;
579 HRESULT hr;
581 TRACE("(%p)->(%p, %p)\n", iface, in, out);
583 if(!This->share)
585 WARN("Device not initialized\n");
586 return DSERR_UNINITIALIZED;
589 if(!in || !out)
591 WARN("Invalid pointer: int = %p, out = %p\n", in, out);
592 return DSERR_INVALIDPARAM;
594 *out = NULL;
596 caps.dwSize = sizeof(caps);
597 hr = IDirectSoundBuffer_GetCaps(in, &caps);
598 if(SUCCEEDED(hr) && (caps.dwFlags&DSBCAPS_PRIMARYBUFFER))
600 WARN("Cannot duplicate buffer %p, which has DSBCAPS_PRIMARYBUFFER\n", in);
601 hr = DSERR_INVALIDPARAM;
603 if(SUCCEEDED(hr) && (caps.dwFlags&DSBCAPS_CTRLFX))
605 WARN("Cannot duplicate buffer %p, which has DSBCAPS_CTRLFX\n", in);
606 hr = DSERR_INVALIDPARAM;
608 if(SUCCEEDED(hr))
609 hr = DS8Buffer_Create(&buf, &This->primary, in);
610 if(SUCCEEDED(hr))
612 *out = &buf->IDirectSoundBuffer_iface;
613 hr = IDirectSoundBuffer_Initialize(*out, NULL, NULL);
615 if(SUCCEEDED(hr))
617 /* According to MSDN volume isn't copied */
618 if((caps.dwFlags&DSBCAPS_CTRLPAN))
620 LONG pan;
621 if(SUCCEEDED(IDirectSoundBuffer_GetPan(in, &pan)))
622 IDirectSoundBuffer_SetPan(*out, pan);
624 if((caps.dwFlags&DSBCAPS_CTRLFREQUENCY))
626 DWORD freq;
627 if(SUCCEEDED(IDirectSoundBuffer_GetFrequency(in, &freq)))
628 IDirectSoundBuffer_SetFrequency(*out, freq);
630 if((caps.dwFlags&DSBCAPS_CTRL3D))
632 IDirectSound3DBuffer *buf3d;
633 DS3DBUFFER DS3DBuffer;
634 HRESULT subhr;
636 subhr = IDirectSound_QueryInterface(in, &IID_IDirectSound3DBuffer, (void**)&buf3d);
637 if(SUCCEEDED(subhr))
639 DS3DBuffer.dwSize = sizeof(DS3DBuffer);
640 subhr = IDirectSound3DBuffer_GetAllParameters(buf3d, &DS3DBuffer);
641 IDirectSound3DBuffer_Release(buf3d);
643 if(SUCCEEDED(subhr))
644 subhr = IDirectSoundBuffer_QueryInterface(*out, &IID_IDirectSound3DBuffer, (void**)&buf3d);
645 if(SUCCEEDED(subhr))
647 subhr = IDirectSound3DBuffer_SetAllParameters(buf3d, &DS3DBuffer, DS3D_IMMEDIATE);
648 IDirectSound3DBuffer_Release(buf3d);
652 if(FAILED(hr))
654 if(*out)
655 IDirectSoundBuffer_Release(*out);
656 *out = NULL;
659 return hr;
662 static HRESULT WINAPI DS8_SetCooperativeLevel(IDirectSound8 *iface, HWND hwnd, DWORD level)
664 DS8Impl *This = impl_from_IDirectSound8(iface);
665 HRESULT hr = S_OK;
667 TRACE("(%p)->(%p, %"LONGFMT"u)\n", iface, hwnd, level);
669 if(!This->share)
671 WARN("Device not initialized\n");
672 return DSERR_UNINITIALIZED;
675 if(level > DSSCL_WRITEPRIMARY || level < DSSCL_NORMAL)
677 WARN("Invalid coop level: %"LONGFMT"u\n", level);
678 return DSERR_INVALIDPARAM;
681 EnterCriticalSection(This->primary.crst);
682 if(level == DSSCL_WRITEPRIMARY && (This->prio_level != DSSCL_WRITEPRIMARY))
684 DWORD i, state;
686 for(i = 0; i < This->primary.nbuffers; ++i)
688 DS8Buffer *buf = This->primary.buffers[i];
689 if(FAILED(IDirectSoundBuffer_GetStatus(&buf->IDirectSoundBuffer8_iface, &state)) ||
690 (state&DSBSTATUS_PLAYING))
692 WARN("DSSCL_WRITEPRIMARY set with playing buffers!\n");
693 hr = DSERR_INVALIDCALL;
694 goto out;
696 /* Mark buffer as lost */
697 buf->bufferlost = 1;
699 if(This->primary.write_emu)
701 ERR("Why was there a write_emu?\n");
702 /* Delete it */
703 IDirectSoundBuffer8_Release(This->primary.write_emu);
704 This->primary.write_emu = NULL;
706 if(This->primary.flags)
708 /* Primary has open references.. create write_emu */
709 DSBUFFERDESC desc;
710 DS8Buffer *emu;
712 memset(&desc, 0, sizeof(desc));
713 desc.dwSize = sizeof(desc);
714 desc.dwFlags = DSBCAPS_LOCHARDWARE | (This->primary.flags&DSBCAPS_CTRLPAN);
715 desc.dwBufferBytes = This->primary.buf_size;
716 desc.lpwfxFormat = &This->primary.format.Format;
718 hr = DS8Buffer_Create(&emu, &This->primary, NULL);
719 if(SUCCEEDED(hr))
721 This->primary.write_emu = &emu->IDirectSoundBuffer8_iface;
722 hr = IDirectSoundBuffer8_Initialize(This->primary.write_emu, &This->IDirectSound_iface, &desc);
723 if(FAILED(hr))
725 IDirectSoundBuffer8_Release(This->primary.write_emu);
726 This->primary.write_emu = NULL;
731 else if(This->prio_level == DSSCL_WRITEPRIMARY && level != DSSCL_WRITEPRIMARY && This->primary.write_emu)
733 TRACE("Nuking write_emu\n");
734 /* Delete it */
735 IDirectSoundBuffer8_Release(This->primary.write_emu);
736 This->primary.write_emu = NULL;
738 if(SUCCEEDED(hr))
739 This->prio_level = level;
740 out:
741 LeaveCriticalSection(This->primary.crst);
743 return hr;
746 static HRESULT WINAPI DS8_Compact(IDirectSound8 *iface)
748 DS8Impl *This = impl_from_IDirectSound8(iface);
749 HRESULT hr = S_OK;
751 TRACE("(%p)->()\n", iface);
753 if(!This->share)
755 WARN("Device not initialized\n");
756 return DSERR_UNINITIALIZED;
759 EnterCriticalSection(&This->share->crst);
760 if(This->prio_level < DSSCL_PRIORITY)
762 WARN("Coop level not high enough (%"LONGFMT"u)\n", This->prio_level);
763 hr = DSERR_PRIOLEVELNEEDED;
765 LeaveCriticalSection(&This->share->crst);
767 return hr;
770 static HRESULT WINAPI DS8_GetSpeakerConfig(IDirectSound8 *iface, DWORD *config)
772 DS8Impl *This = impl_from_IDirectSound8(iface);
773 HRESULT hr = S_OK;
775 TRACE("(%p)->(%p)\n", iface, config);
777 if(!config)
778 return DSERR_INVALIDPARAM;
779 *config = 0;
781 if(!This->share)
783 WARN("Device not initialized\n");
784 return DSERR_UNINITIALIZED;
787 EnterCriticalSection(&This->share->crst);
788 *config = This->speaker_config;
789 LeaveCriticalSection(&This->share->crst);
791 return hr;
794 static HRESULT WINAPI DS8_SetSpeakerConfig(IDirectSound8 *iface, DWORD config)
796 DS8Impl *This = impl_from_IDirectSound8(iface);
797 DWORD geo, speaker;
798 HKEY key;
799 HRESULT hr;
801 TRACE("(%p)->(0x%08"LONGFMT"x)\n", iface, config);
803 if(!This->share)
805 WARN("Device not initialized\n");
806 return DSERR_UNINITIALIZED;
809 geo = DSSPEAKER_GEOMETRY(config);
810 speaker = DSSPEAKER_CONFIG(config);
812 if(geo && (geo < DSSPEAKER_GEOMETRY_MIN || geo > DSSPEAKER_GEOMETRY_MAX))
814 WARN("Invalid speaker angle %"LONGFMT"u\n", geo);
815 return DSERR_INVALIDPARAM;
817 if(speaker < DSSPEAKER_HEADPHONE || speaker > DSSPEAKER_7POINT1)
819 WARN("Invalid speaker config %"LONGFMT"u\n", speaker);
820 return DSERR_INVALIDPARAM;
823 EnterCriticalSection(&This->share->crst);
825 hr = DSERR_GENERIC;
826 if(!RegCreateKeyExW(HKEY_LOCAL_MACHINE, speakerconfigkey, 0, NULL, 0, KEY_WRITE, NULL, &key, NULL))
828 RegSetValueExW(key, speakerconfig, 0, REG_DWORD, (const BYTE*)&config, sizeof(DWORD));
829 This->speaker_config = config;
830 RegCloseKey(key);
831 hr = S_OK;
834 LeaveCriticalSection(&This->share->crst);
835 return hr;
838 static HRESULT WINAPI DS8_Initialize(IDirectSound8 *iface, const GUID *devguid)
840 DS8Impl *This = impl_from_IDirectSound8(iface);
841 HRESULT hr;
842 GUID guid;
843 UINT n;
845 TRACE("(%p)->(%s)\n", iface, debugstr_guid(devguid));
847 if(!openal_loaded)
848 return DSERR_NODRIVER;
850 if(This->share)
852 WARN("Device already initialized\n");
853 return DSERR_ALREADYINITIALIZED;
856 if(!devguid)
857 devguid = &DSDEVID_DefaultPlayback;
858 hr = GetDeviceID(devguid, &guid);
859 if(FAILED(hr))
860 return hr;
862 EnterCriticalSection(&openal_crst);
864 for(n = 0;n < sharelistsize;n++)
866 if(IsEqualGUID(&sharelist[n]->guid, &guid))
868 TRACE("Matched already open device %p\n", sharelist[n]->device);
870 This->share = sharelist[n];
871 DSShare_AddRef(This->share);
872 break;
876 if(!This->share)
877 hr = DSShare_Create(&guid, &This->share);
878 if(SUCCEEDED(hr))
880 This->device = This->share->device;
881 hr = DS8Primary_PreInit(&This->primary, This);
884 if(FAILED(hr))
886 if(This->share)
887 DSShare_Release(This->share);
888 This->share = NULL;
891 LeaveCriticalSection(&openal_crst);
892 return hr;
895 /* I, Maarten Lankhorst, hereby declare this driver certified
896 * What this means.. ? An extra bit set
898 static HRESULT WINAPI DS8_VerifyCertification(IDirectSound8 *iface, DWORD *certified)
900 DS8Impl *This = impl_from_IDirectSound8(iface);
902 TRACE("(%p)->(%p)\n", iface, certified);
904 if(!certified)
905 return DSERR_INVALIDPARAM;
906 *certified = 0;
908 if(!This->share)
910 WARN("Device not initialized\n");
911 return DSERR_UNINITIALIZED;
914 *certified = DS_CERTIFIED;
916 return DS_OK;
919 static const IDirectSound8Vtbl DS8_Vtbl = {
920 DS8_QueryInterface,
921 DS8_AddRef,
922 DS8_Release,
923 DS8_CreateSoundBuffer,
924 DS8_GetCaps,
925 DS8_DuplicateSoundBuffer,
926 DS8_SetCooperativeLevel,
927 DS8_Compact,
928 DS8_GetSpeakerConfig,
929 DS8_SetSpeakerConfig,
930 DS8_Initialize,
931 DS8_VerifyCertification
935 static HRESULT WINAPI DS_QueryInterface(IDirectSound *iface, REFIID riid, LPVOID *ppv)
937 DS8Impl *This = impl_from_IDirectSound(iface);
938 return DS8_QueryInterface(&This->IDirectSound8_iface, riid, ppv);
941 static ULONG WINAPI DS_AddRef(IDirectSound *iface)
943 DS8Impl *This = impl_from_IDirectSound(iface);
944 return DS8_AddRef(&This->IDirectSound8_iface);
947 static ULONG WINAPI DS_Release(IDirectSound *iface)
949 DS8Impl *This = impl_from_IDirectSound(iface);
950 return DS8_Release(&This->IDirectSound8_iface);
953 static HRESULT WINAPI DS_CreateSoundBuffer(IDirectSound *iface, LPCDSBUFFERDESC desc, LPLPDIRECTSOUNDBUFFER buf, IUnknown *pUnkOuter)
955 DS8Impl *This = impl_from_IDirectSound(iface);
956 return DS8_CreateSoundBuffer(&This->IDirectSound8_iface, desc, buf, pUnkOuter);
959 static HRESULT WINAPI DS_GetCaps(IDirectSound *iface, LPDSCAPS caps)
961 DS8Impl *This = impl_from_IDirectSound(iface);
962 return DS8_GetCaps(&This->IDirectSound8_iface, caps);
964 static HRESULT WINAPI DS_DuplicateSoundBuffer(IDirectSound *iface, IDirectSoundBuffer *in, IDirectSoundBuffer **out)
966 DS8Impl *This = impl_from_IDirectSound(iface);
967 return DS8_DuplicateSoundBuffer(&This->IDirectSound8_iface, in, out);
970 static HRESULT WINAPI DS_SetCooperativeLevel(IDirectSound *iface, HWND hwnd, DWORD level)
972 DS8Impl *This = impl_from_IDirectSound(iface);
973 return DS8_SetCooperativeLevel(&This->IDirectSound8_iface, hwnd, level);
976 static HRESULT WINAPI DS_Compact(IDirectSound *iface)
978 DS8Impl *This = impl_from_IDirectSound(iface);
979 return DS8_Compact(&This->IDirectSound8_iface);
982 static HRESULT WINAPI DS_GetSpeakerConfig(IDirectSound *iface, DWORD *config)
984 DS8Impl *This = impl_from_IDirectSound(iface);
985 return DS8_GetSpeakerConfig(&This->IDirectSound8_iface, config);
988 static HRESULT WINAPI DS_SetSpeakerConfig(IDirectSound *iface, DWORD config)
990 DS8Impl *This = impl_from_IDirectSound(iface);
991 return DS8_SetSpeakerConfig(&This->IDirectSound8_iface, config);
994 static HRESULT WINAPI DS_Initialize(IDirectSound *iface, const GUID *devguid)
996 DS8Impl *This = impl_from_IDirectSound(iface);
997 return DS8_Initialize(&This->IDirectSound8_iface, devguid);
1000 static const IDirectSoundVtbl DS_Vtbl = {
1001 DS_QueryInterface,
1002 DS_AddRef,
1003 DS_Release,
1004 DS_CreateSoundBuffer,
1005 DS_GetCaps,
1006 DS_DuplicateSoundBuffer,
1007 DS_SetCooperativeLevel,
1008 DS_Compact,
1009 DS_GetSpeakerConfig,
1010 DS_SetSpeakerConfig,
1011 DS_Initialize