Protect the primary buffer when modifying it during secondary buffer destruction
[dsound-openal.git] / dsound8.c
blob8bb1bd6b91204a24bfee8d136dfce50af162d2d7
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 DS8Impl **devicelist;
60 static UINT devicelistsize;
62 static const IDirectSound8Vtbl DS8_Vtbl;
64 HRESULT DSOUND_Create(REFIID riid, LPVOID *ds)
66 HRESULT hr;
68 if(IsEqualIID(riid, &IID_IDirectSound8))
69 return E_NOINTERFACE;
70 hr = DSOUND_Create8(riid, ds);
71 if(hr == S_OK)
72 ((DS8Impl*)*ds)->is_8 = FALSE;
73 return hr;
76 static void DS8Impl_Destroy(DS8Impl *This);
78 static const WCHAR speakerconfigkey[] = {
79 'S','Y','S','T','E','M','\\',
80 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
81 'C','o','n','t','r','o','l','\\',
82 'M','e','d','i','a','R','e','s','o','u','r','c','e','s','\\',
83 'D','i','r','e','c','t','S','o','u','n','d','\\',
84 'S','p','e','a','k','e','r',' ','C','o','n','f','i','g','u','r','a','t','i','o','n',0
87 static const WCHAR speakerconfig[] = {
88 'S','p','e','a','k','e','r',' ','C','o','n','f','i','g','u','r','a','t','i','o','n',0
91 HRESULT DSOUND_Create8(REFIID riid, LPVOID *ds)
93 DS8Impl *This;
94 HKEY regkey;
95 HRESULT hr;
97 *ds = NULL;
98 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
99 if(!This)
100 return E_OUTOFMEMORY;
101 This->IDirectSound8_iface.lpVtbl = (IDirectSound8Vtbl*)&DS8_Vtbl;
103 This->is_8 = TRUE;
104 This->speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_5POINT1, DSSPEAKER_GEOMETRY_WIDE);
106 if(RegOpenKeyExW(HKEY_LOCAL_MACHINE, speakerconfigkey, 0, KEY_READ, &regkey) == ERROR_SUCCESS)
108 DWORD type, conf, confsize = sizeof(DWORD);
110 if(RegQueryValueExW(regkey, speakerconfig, NULL, &type, (BYTE*)&conf, &confsize) == ERROR_SUCCESS)
112 if(type == REG_DWORD)
113 This->speaker_config = conf;
116 RegCloseKey(regkey);
118 /*RegGetValueW(HKEY_LOCAL_MACHINE, speakerconfigkey, speakerconfig, RRF_RT_REG_DWORD, NULL, &This->speaker_config, NULL);*/
120 hr = IUnknown_QueryInterface(&This->IDirectSound8_iface, riid, ds);
121 if(FAILED(hr))
122 DS8Impl_Destroy(This);
123 else
125 void *temp;
127 EnterCriticalSection(&openal_crst);
128 if(devicelist)
129 temp = HeapReAlloc(GetProcessHeap(), 0, devicelist, sizeof(*devicelist)*(devicelistsize+1));
130 else
131 temp = HeapAlloc(GetProcessHeap(), 0, sizeof(*devicelist)*(devicelistsize+1));
132 if(temp)
134 devicelist = temp;
135 devicelist[devicelistsize++] = This;
137 LeaveCriticalSection(&openal_crst);
139 return hr;
142 static void DS8Impl_Destroy(DS8Impl *This)
144 UINT i;
146 EnterCriticalSection(&openal_crst);
147 for(i = 0;i < devicelistsize;i++)
149 if(devicelist[i] == This)
151 devicelist[i] = devicelist[--devicelistsize];
152 if(devicelistsize == 0)
154 HeapFree(GetProcessHeap(), 0, devicelist);
155 devicelist = NULL;
157 break;
160 LeaveCriticalSection(&openal_crst);
162 if(This->deviceref && InterlockedDecrement(This->deviceref) == 0)
164 if(This->primary)
165 DS8Primary_Destroy(This->primary);
166 if(This->device)
167 alcCloseDevice(This->device);
169 HeapFree(GetProcessHeap(), 0, This->deviceref);
171 else
173 EnterCriticalSection(&openal_crst);
174 if(This->primary && This->primary->parent == This)
176 /* If the primary is referencing this as its parent, update it to
177 * reference another handle for the device */
178 for(i = 0;i < devicelistsize;i++)
180 if(devicelist[i]->primary == This->primary)
182 This->primary->parent = devicelist[i];
183 break;
187 LeaveCriticalSection(&openal_crst);
190 HeapFree(GetProcessHeap(), 0, This);
193 static inline DS8Impl *impl_from_IDirectSound8(IDirectSound8 *iface)
195 return CONTAINING_RECORD(iface, DS8Impl, IDirectSound8_iface);
198 static HRESULT WINAPI DS8_QueryInterface(IDirectSound8 *iface, REFIID riid, LPVOID *ppv)
200 DS8Impl *This = impl_from_IDirectSound8(iface);
202 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
204 *ppv = NULL;
205 if(IsEqualIID(riid, &IID_IUnknown) ||
206 IsEqualIID(riid, &IID_IDirectSound))
207 *ppv = &This->IDirectSound8_iface;
208 else if((IsEqualIID(riid, &IID_IDirectSound8)))
210 if(This->is_8)
211 *ppv = &This->IDirectSound8_iface;
213 else
214 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
216 if(*ppv)
218 IUnknown_AddRef((IUnknown*)*ppv);
219 return S_OK;
222 return E_NOINTERFACE;
225 static ULONG WINAPI DS8_AddRef(IDirectSound8 *iface)
227 DS8Impl *This = impl_from_IDirectSound8(iface);
228 LONG ref;
230 ref = InterlockedIncrement(&This->ref);
231 TRACE("Reference count incremented to %d\n", ref);
233 return ref;
236 static ULONG WINAPI DS8_Release(IDirectSound8 *iface)
238 DS8Impl *This = impl_from_IDirectSound8(iface);
239 LONG ref;
241 ref = InterlockedDecrement(&This->ref);
242 TRACE("Reference count decremented to %d\n", ref);
243 if(ref == 0)
244 DS8Impl_Destroy(This);
246 return ref;
249 static HRESULT WINAPI DS8_CreateSoundBuffer(IDirectSound8 *iface, LPCDSBUFFERDESC desc, LPLPDIRECTSOUNDBUFFER buf, IUnknown *pUnkOuter)
251 DS8Impl *This = impl_from_IDirectSound8(iface);
252 HRESULT hr;
254 TRACE("(%p)->(%p, %p, %p)\n", iface, desc, buf, pUnkOuter);
256 if(!buf)
258 WARN("buf is null\n");
259 return DSERR_INVALIDPARAM;
261 *buf = NULL;
263 if(pUnkOuter)
265 WARN("Aggregation isn't supported\n");
266 return DSERR_NOAGGREGATION;
268 if(!desc || desc->dwSize < sizeof(DSBUFFERDESC1))
270 WARN("Invalid buffer %p/%u\n", desc, desc?desc->dwSize:0);
271 return DSERR_INVALIDPARAM;
274 TRACE("Requested buffer:\n"
275 " Size = %u\n"
276 " Flags = 0x%08x\n"
277 " BufferBytes = %u\n",
278 (UINT)desc->dwSize, (UINT)desc->dwFlags,
279 (UINT)desc->dwBufferBytes);
281 if(desc->dwSize >= sizeof(DSBUFFERDESC))
283 if(!(desc->dwFlags&DSBCAPS_CTRL3D))
285 if(!IsEqualGUID(&desc->guid3DAlgorithm, &GUID_NULL))
287 WARN("Invalid 3D algorithm GUID specified for non-3D buffer: %s\n", debugstr_guid(&desc->guid3DAlgorithm));
288 return DSERR_INVALIDPARAM;
291 else
292 TRACE("Requested 3D algorithm GUID: %s\n", debugstr_guid(&desc->guid3DAlgorithm));
295 /* OpenAL doesn't support playing with 3d and panning at same time.. */
296 if((desc->dwFlags&(DSBCAPS_CTRL3D|DSBCAPS_CTRLPAN)) == (DSBCAPS_CTRL3D|DSBCAPS_CTRLPAN))
298 if(!This->is_8)
299 ERR("Cannot create buffers with 3D and panning control\n");
300 else
301 WARN("Cannot create buffers with 3D and panning control\n");
302 return DSERR_INVALIDPARAM;
305 EnterCriticalSection(&openal_crst);
306 if(!This->device)
307 hr = DSERR_UNINITIALIZED;
308 else if((desc->dwFlags&DSBCAPS_PRIMARYBUFFER))
310 IDirectSoundBuffer *prim = &This->primary->IDirectSoundBuffer_iface;
312 hr = S_OK;
313 if(IDirectSoundBuffer_AddRef(prim) == 1)
315 hr = IDirectSoundBuffer_Initialize(prim, (IDirectSound*)&This->IDirectSound8_iface, desc);
316 if(FAILED(hr))
318 IDirectSoundBuffer_Release(prim);
319 prim = NULL;
322 *buf = prim;
324 else
326 DS8Buffer *dsb;
328 hr = DS8Buffer_Create(&dsb, This->primary, NULL);
329 if(SUCCEEDED(hr))
331 hr = IDirectSoundBuffer8_Initialize(&dsb->IDirectSoundBuffer8_iface, (IDirectSound*)&This->IDirectSound8_iface, desc);
332 if(FAILED(hr))
333 IDirectSoundBuffer8_Release(&dsb->IDirectSoundBuffer8_iface);
334 else
336 dsb->bufferlost = (This->prio_level == DSSCL_WRITEPRIMARY);
337 *buf = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
341 LeaveCriticalSection(&openal_crst);
343 TRACE("%08x\n", hr);
344 return hr;
347 static HRESULT WINAPI DS8_GetCaps(IDirectSound8 *iface, LPDSCAPS caps)
349 DS8Impl *This = impl_from_IDirectSound8(iface);
350 HRESULT hr = S_OK;
352 TRACE("(%p)->(%p)\n", iface, caps);
354 EnterCriticalSection(&openal_crst);
355 if(!This->device)
356 hr = DSERR_UNINITIALIZED;
357 else if(!caps || caps->dwSize < sizeof(*caps))
358 hr = DSERR_INVALIDPARAM;
359 else
361 LONG count = This->primary->max_sources;
363 setALContext(This->primary->ctx);
364 caps->dwFlags = DSCAPS_CONTINUOUSRATE |
365 DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYSTEREO |
366 DSCAPS_PRIMARY8BIT | DSCAPS_PRIMARYMONO |
367 DSCAPS_SECONDARY16BIT | DSCAPS_SECONDARY8BIT |
368 DSCAPS_SECONDARYMONO | DSCAPS_SECONDARYSTEREO;
369 caps->dwPrimaryBuffers = 1;
370 caps->dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
371 caps->dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
372 caps->dwMaxHwMixingAllBuffers =
373 caps->dwMaxHwMixingStaticBuffers =
374 caps->dwMaxHwMixingStreamingBuffers =
375 caps->dwMaxHw3DAllBuffers =
376 caps->dwMaxHw3DStaticBuffers =
377 caps->dwMaxHw3DStreamingBuffers = count;
378 count -= This->primary->nbuffers;
379 if(count < 0)
381 ERR("How did the count drop below 0?\n");
382 count = 0;
384 caps->dwFreeHwMixingAllBuffers =
385 caps->dwFreeHwMixingStaticBuffers =
386 caps->dwFreeHwMixingStreamingBuffers =
387 caps->dwFreeHw3DAllBuffers =
388 caps->dwFreeHw3DStaticBuffers =
389 caps->dwFreeHw3DStreamingBuffers = count;
390 caps->dwTotalHwMemBytes =
391 caps->dwFreeHwMemBytes = 64 * 1024 * 1024;
392 caps->dwMaxContigFreeHwMemBytes = caps->dwFreeHwMemBytes;
393 caps->dwUnlockTransferRateHwBuffers = 4096;
394 caps->dwPlayCpuOverheadSwBuffers = 0;
395 popALContext();
397 LeaveCriticalSection(&openal_crst);
399 return hr;
401 static HRESULT WINAPI DS8_DuplicateSoundBuffer(IDirectSound8 *iface, IDirectSoundBuffer *in, IDirectSoundBuffer **out)
403 DS8Impl *This = impl_from_IDirectSound8(iface);
404 HRESULT hr = S_OK;
406 TRACE("(%p)->(%p, %p)\n", iface, in, out);
408 EnterCriticalSection(&openal_crst);
409 if(!This->device)
410 hr = DSERR_UNINITIALIZED;
411 else if(!in || !out)
412 hr = DSERR_INVALIDPARAM;
413 else
415 DWORD i;
416 DSBCAPS caps;
417 DS8Buffer *buf;
419 *out = NULL;
421 for(i = 0; i < This->primary->nbuffers; ++i)
423 if(This->primary->buffers[i] == (DS8Buffer*)in)
424 break;
426 if(i == This->primary->nbuffers)
428 hr = DSERR_INVALIDPARAM;
429 WARN("Buffer %p not found\n", in);
430 goto out;
433 caps.dwSize = sizeof(caps);
434 hr = IDirectSoundBuffer_GetCaps(in, &caps);
435 if(SUCCEEDED(hr) && (caps.dwFlags&DSBCAPS_CTRLFX))
437 WARN("Cannot duplicate buffer %p, which has DSBCAPS_CTRLFX\n", in);
438 hr = DSERR_INVALIDPARAM;
440 if(SUCCEEDED(hr))
441 hr = DS8Buffer_Create(&buf, This->primary, (DS8Buffer*)in);
442 if(SUCCEEDED(hr))
444 *out = (IDirectSoundBuffer*)&buf->IDirectSoundBuffer8_iface;
445 hr = IDirectSoundBuffer_Initialize(*out, NULL, NULL);
447 if(SUCCEEDED(hr))
449 DWORD savelost = ((DS8Buffer*)in)->bufferlost;
450 ((DS8Buffer*)in)->bufferlost = 0;
451 /* According to MSDN volume isn't copied
453 if((caps.dwFlags&DSBCAPS_CTRLPAN))
455 LONG pan;
456 if(SUCCEEDED(IDirectSoundBuffer_GetPan(in, &pan)))
457 IDirectSoundBuffer_SetPan(*out, pan);
459 if((caps.dwFlags&DSBCAPS_CTRLFREQUENCY))
461 DWORD freq;
462 if(SUCCEEDED(IDirectSoundBuffer_GetFrequency(in, &freq)))
463 IDirectSoundBuffer_SetFrequency(*out, freq);
465 if((caps.dwFlags&DSBCAPS_CTRL3D))
467 IDirectSound3DBuffer *buf3d;
468 DS3DBUFFER DS3DBuffer;
469 HRESULT subhr;
471 subhr = IDirectSound_QueryInterface(in, &IID_IDirectSound3DBuffer, (void**)&buf3d);
472 if(SUCCEEDED(subhr))
474 DS3DBuffer.dwSize = sizeof(DS3DBuffer);
475 subhr = IDirectSound3DBuffer_GetAllParameters(buf3d, &DS3DBuffer);
476 IDirectSound3DBuffer_Release(buf3d);
478 if(SUCCEEDED(subhr))
479 subhr = IDirectSoundBuffer_QueryInterface(*out, &IID_IDirectSound3DBuffer, (void**)&buf3d);
480 if(SUCCEEDED(subhr))
482 subhr = IDirectSound3DBuffer_SetAllParameters(buf3d, &DS3DBuffer, DS3D_IMMEDIATE);
483 IDirectSound3DBuffer_Release(buf3d);
486 ((DS8Buffer*)in)->bufferlost = buf->bufferlost = savelost;
488 if(FAILED(hr))
490 if(*out)
491 IDirectSoundBuffer_Release(*out);
492 *out = NULL;
493 goto out;
496 out:
497 LeaveCriticalSection(&openal_crst);
498 return hr;
501 static HRESULT WINAPI DS8_SetCooperativeLevel(IDirectSound8 *iface, HWND hwnd, DWORD level)
503 DS8Impl *This = impl_from_IDirectSound8(iface);
504 HRESULT hr = S_OK;
506 TRACE("(%p)->(%p, %u)\n", iface, hwnd, level);
508 EnterCriticalSection(&openal_crst);
509 if(!This->device)
510 hr = DSERR_UNINITIALIZED;
511 else if(level > DSSCL_WRITEPRIMARY || level < DSSCL_NORMAL)
512 hr = E_INVALIDARG;
513 else if(level == DSSCL_WRITEPRIMARY && (This->prio_level != DSSCL_WRITEPRIMARY))
515 DWORD i, state;
517 for(i = 0; i < This->primary->nbuffers; ++i)
519 DS8Buffer *buf = This->primary->buffers[i];
520 if(FAILED(IDirectSoundBuffer_GetStatus(&buf->IDirectSoundBuffer8_iface, &state)) ||
521 (state&DSBSTATUS_PLAYING))
523 WARN("DSSCL_WRITEPRIMARY set with playing buffers!\n");
524 hr = DSERR_INVALIDCALL;
525 goto out;
527 /* Mark buffer as lost */
528 buf->bufferlost = 1;
530 if(This->primary->write_emu)
532 ERR("Why was there a write_emu?\n");
533 /* Delete it */
534 IDirectSoundBuffer8_Release(This->primary->write_emu);
535 This->primary->write_emu = NULL;
537 if(This->primary->flags)
539 /* Primary has open references.. create write_emu */
540 DSBUFFERDESC desc;
541 DS8Buffer *emu;
543 memset(&desc, 0, sizeof(desc));
544 desc.dwSize = sizeof(desc);
545 desc.dwFlags = DSBCAPS_LOCHARDWARE | (This->primary->flags&DSBCAPS_CTRLPAN);
546 desc.dwBufferBytes = This->primary->buf_size;
547 desc.lpwfxFormat = &This->primary->format.Format;
549 hr = DS8Buffer_Create(&emu, This->primary, NULL);
550 if(SUCCEEDED(hr))
552 This->primary->write_emu = &emu->IDirectSoundBuffer8_iface;
553 hr = IDirectSoundBuffer8_Initialize(This->primary->write_emu, (IDirectSound*)&This->IDirectSound8_iface, &desc);
554 if(FAILED(hr))
556 IDirectSoundBuffer8_Release(This->primary->write_emu);
557 This->primary->write_emu = NULL;
562 else if(This->prio_level == DSSCL_WRITEPRIMARY && level != DSSCL_WRITEPRIMARY && This->primary->write_emu)
564 TRACE("Nuking write_emu\n");
565 /* Delete it */
566 IDirectSoundBuffer8_Release(This->primary->write_emu);
567 This->primary->write_emu = NULL;
569 if(SUCCEEDED(hr))
570 This->prio_level = level;
571 out:
572 LeaveCriticalSection(&openal_crst);
574 return hr;
577 static HRESULT WINAPI DS8_Compact(IDirectSound8 *iface)
579 DS8Impl *This = impl_from_IDirectSound8(iface);
580 HRESULT hr = S_OK;
582 TRACE("(%p)->()\n", iface);
584 EnterCriticalSection(&openal_crst);
585 if(!This->device)
586 hr = DSERR_UNINITIALIZED;
587 else if(This->prio_level < DSSCL_PRIORITY)
588 hr = DSERR_PRIOLEVELNEEDED;
589 LeaveCriticalSection(&openal_crst);
591 return hr;
594 static HRESULT WINAPI DS8_GetSpeakerConfig(IDirectSound8 *iface, DWORD *config)
596 DS8Impl *This = impl_from_IDirectSound8(iface);
597 HRESULT hr = S_OK;
599 TRACE("(%p)->(%p)\n", iface, config);
601 if(!config)
602 return DSERR_INVALIDPARAM;
604 EnterCriticalSection(&openal_crst);
605 if(!This->device)
606 hr = DSERR_UNINITIALIZED;
607 else
608 *config = This->speaker_config;
609 LeaveCriticalSection(&openal_crst);
611 return hr;
614 static HRESULT WINAPI DS8_SetSpeakerConfig(IDirectSound8 *iface, DWORD config)
616 DS8Impl *This = impl_from_IDirectSound8(iface);
617 HRESULT hr;
619 TRACE("(%p)->(0x%08x)\n", iface, config);
621 EnterCriticalSection(&openal_crst);
622 if(!This->device)
623 hr = DSERR_UNINITIALIZED;
624 else
626 HKEY key;
627 DWORD geo, speaker;
629 geo = DSSPEAKER_GEOMETRY(config);
630 speaker = DSSPEAKER_CONFIG(config);
632 hr = DSERR_INVALIDPARAM;
633 if(geo && (geo < DSSPEAKER_GEOMETRY_MIN || geo > DSSPEAKER_GEOMETRY_MAX))
635 WARN("Invalid speaker angle %u\n", geo);
636 goto out;
638 if(speaker < DSSPEAKER_HEADPHONE || speaker > DSSPEAKER_7POINT1)
640 WARN("Invalid speaker config %u\n", speaker);
641 goto out;
644 hr = DSERR_GENERIC;
645 if(!RegCreateKeyExW(HKEY_LOCAL_MACHINE, speakerconfigkey, 0, NULL, 0, KEY_WRITE, NULL, &key, NULL))
647 RegSetValueExW(key, speakerconfig, 0, REG_DWORD, (const BYTE*)&config, sizeof(DWORD));
648 This->speaker_config = config;
649 RegCloseKey(key);
650 hr = S_OK;
653 out:
654 LeaveCriticalSection(&openal_crst);
656 return hr;
659 static HRESULT WINAPI DS8_Initialize(IDirectSound8 *iface, const GUID *devguid)
661 DS8Impl *This = impl_from_IDirectSound8(iface);
662 const ALCchar *drv_name;
663 HRESULT hr;
664 UINT n;
666 TRACE("(%p)->(%s)\n", iface, debugstr_guid(devguid));
668 if(!openal_loaded)
669 return DSERR_NODRIVER;
671 if(!devguid)
672 devguid = &DSDEVID_DefaultPlayback;
674 EnterCriticalSection(&openal_crst);
676 hr = DSERR_ALREADYINITIALIZED;
677 if(This->device)
678 goto out;
680 hr = GetDeviceID(devguid, &This->guid);
681 if(FAILED(hr))
682 goto out;
684 for(n = 0;n < devicelistsize;n++)
686 if(devicelist[n]->device && devicelist[n]->is_8 == This->is_8 &&
687 IsEqualGUID(&devicelist[n]->guid, &This->guid))
689 TRACE("Matched already open device %p\n", devicelist[n]);
691 This->device = devicelist[n]->device;
692 This->primary = devicelist[n]->primary;
693 This->deviceref = devicelist[n]->deviceref;
694 InterlockedIncrement(This->deviceref);
696 hr = DS_OK;
697 goto out;
701 if(!This->deviceref)
703 hr = DSERR_OUTOFMEMORY;
704 if(!(This->deviceref=HeapAlloc(GetProcessHeap(), 0, sizeof(LONG))))
705 goto out;
706 This->deviceref[0] = 1;
709 hr = DSERR_NODRIVER;
710 if(!(drv_name=DSOUND_getdevicestrings()) ||
711 memcmp(&This->guid, &DSOUND_renderer_guid, sizeof(GUID)-1) != 0)
713 WARN("No device found\n");
714 goto out;
717 n = This->guid.Data4[7];
718 while(*drv_name && n--)
719 drv_name += strlen(drv_name) + 1;
720 if(!*drv_name)
722 WARN("No device string found\n");
723 goto out;
726 This->device = alcOpenDevice(drv_name);
727 if(!This->device)
729 alcGetError(NULL);
730 WARN("Couldn't open device \"%s\"\n", drv_name);
731 goto out;
733 TRACE("Opened device: %s\n", alcGetString(This->device, ALC_DEVICE_SPECIFIER));
735 hr = DS8Primary_Create(&This->primary, This);
736 if(FAILED(hr))
738 alcCloseDevice(This->device);
739 This->device = NULL;
742 out:
743 LeaveCriticalSection(&openal_crst);
745 return hr;
748 /* I, Maarten Lankhorst, hereby declare this driver certified
749 * What this means.. ? An extra bit set
751 static HRESULT WINAPI DS8_VerifyCertification(IDirectSound8 *iface, DWORD *certified)
753 DS8Impl *This = impl_from_IDirectSound8(iface);
754 HRESULT hr;
756 TRACE("(%p)->(%p)\n", iface, certified);
758 if(!certified)
759 return DSERR_INVALIDPARAM;
761 EnterCriticalSection(&openal_crst);
762 hr = S_OK;
763 if(!This->device)
764 hr = DSERR_UNINITIALIZED;
765 else
766 *certified = DS_CERTIFIED;
767 LeaveCriticalSection(&openal_crst);
769 return hr;
772 static const IDirectSound8Vtbl DS8_Vtbl =
774 DS8_QueryInterface,
775 DS8_AddRef,
776 DS8_Release,
777 DS8_CreateSoundBuffer,
778 DS8_GetCaps,
779 DS8_DuplicateSoundBuffer,
780 DS8_SetCooperativeLevel,
781 DS8_Compact,
782 DS8_GetSpeakerConfig,
783 DS8_SetSpeakerConfig,
784 DS8_Initialize,
785 DS8_VerifyCertification