Add a LONGFMT macro to propery handle LONG-based types
[dsound-openal.git] / dsound8.c
blobfd1b932ccd0f5dbf02b9554917d1b468f316e6f1
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;
63 static const IDirectSoundVtbl DS_Vtbl;
65 static inline DS8Impl *impl_from_IDirectSound8(IDirectSound8 *iface)
67 return CONTAINING_RECORD(iface, DS8Impl, IDirectSound8_iface);
70 static inline DS8Impl *impl_from_IDirectSound(IDirectSound *iface)
72 return CONTAINING_RECORD(iface, DS8Impl, IDirectSound_iface);
75 HRESULT DSOUND_Create(REFIID riid, void **ds)
77 HRESULT hr;
79 if(IsEqualIID(riid, &IID_IDirectSound8))
80 return E_NOINTERFACE;
81 hr = DSOUND_Create8(&IID_IDirectSound8, ds);
82 if(hr == S_OK)
84 DS8Impl *impl = impl_from_IDirectSound8(*ds);
85 impl->is_8 = FALSE;
87 hr = IDirectSound8_QueryInterface(&impl->IDirectSound8_iface, riid, ds);
88 IDirectSound8_Release(&impl->IDirectSound8_iface);
90 return hr;
93 static void DS8Impl_Destroy(DS8Impl *This);
95 static const WCHAR speakerconfigkey[] = {
96 'S','Y','S','T','E','M','\\',
97 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
98 'C','o','n','t','r','o','l','\\',
99 'M','e','d','i','a','R','e','s','o','u','r','c','e','s','\\',
100 'D','i','r','e','c','t','S','o','u','n','d','\\',
101 'S','p','e','a','k','e','r',' ','C','o','n','f','i','g','u','r','a','t','i','o','n',0
104 static const WCHAR speakerconfig[] = {
105 'S','p','e','a','k','e','r',' ','C','o','n','f','i','g','u','r','a','t','i','o','n',0
108 HRESULT DSOUND_Create8(REFIID riid, LPVOID *ds)
110 DS8Impl *This;
111 HKEY regkey;
112 HRESULT hr;
114 *ds = NULL;
115 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
116 if(!This)
117 return E_OUTOFMEMORY;
118 This->IDirectSound8_iface.lpVtbl = (IDirectSound8Vtbl*)&DS8_Vtbl;
119 This->IDirectSound_iface.lpVtbl = (IDirectSoundVtbl*)&DS_Vtbl;
121 This->is_8 = TRUE;
122 This->speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_5POINT1, DSSPEAKER_GEOMETRY_WIDE);
124 if(RegOpenKeyExW(HKEY_LOCAL_MACHINE, speakerconfigkey, 0, KEY_READ, &regkey) == ERROR_SUCCESS)
126 DWORD type, conf, confsize = sizeof(DWORD);
128 if(RegQueryValueExW(regkey, speakerconfig, NULL, &type, (BYTE*)&conf, &confsize) == ERROR_SUCCESS)
130 if(type == REG_DWORD)
131 This->speaker_config = conf;
134 RegCloseKey(regkey);
136 /*RegGetValueW(HKEY_LOCAL_MACHINE, speakerconfigkey, speakerconfig, RRF_RT_REG_DWORD, NULL, &This->speaker_config, NULL);*/
138 hr = IDirectSound8_QueryInterface(&This->IDirectSound8_iface, riid, ds);
139 if(FAILED(hr))
140 DS8Impl_Destroy(This);
141 else
143 void *temp;
145 EnterCriticalSection(&openal_crst);
146 if(devicelist)
147 temp = HeapReAlloc(GetProcessHeap(), 0, devicelist, sizeof(*devicelist)*(devicelistsize+1));
148 else
149 temp = HeapAlloc(GetProcessHeap(), 0, sizeof(*devicelist)*(devicelistsize+1));
150 if(temp)
152 devicelist = temp;
153 devicelist[devicelistsize++] = This;
155 LeaveCriticalSection(&openal_crst);
157 return hr;
160 static void DS8Impl_Destroy(DS8Impl *This)
162 UINT i;
164 EnterCriticalSection(&openal_crst);
165 for(i = 0;i < devicelistsize;i++)
167 if(devicelist[i] == This)
169 devicelist[i] = devicelist[--devicelistsize];
170 if(devicelistsize == 0)
172 HeapFree(GetProcessHeap(), 0, devicelist);
173 devicelist = NULL;
175 break;
178 LeaveCriticalSection(&openal_crst);
180 if(This->deviceref && InterlockedDecrement(This->deviceref) == 0)
182 if(This->primary)
183 DS8Primary_Destroy(This->primary);
184 if(This->device)
185 alcCloseDevice(This->device);
187 HeapFree(GetProcessHeap(), 0, This->deviceref);
189 else
191 EnterCriticalSection(&openal_crst);
192 if(This->primary && This->primary->parent == This)
194 /* If the primary is referencing this as its parent, update it to
195 * reference another handle for the device */
196 for(i = 0;i < devicelistsize;i++)
198 if(devicelist[i]->primary == This->primary)
200 This->primary->parent = devicelist[i];
201 break;
205 LeaveCriticalSection(&openal_crst);
208 HeapFree(GetProcessHeap(), 0, This);
212 static HRESULT WINAPI DS8_QueryInterface(IDirectSound8 *iface, REFIID riid, LPVOID *ppv)
214 DS8Impl *This = impl_from_IDirectSound8(iface);
216 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
218 *ppv = NULL;
219 if(IsEqualIID(riid, &IID_IUnknown) ||
220 IsEqualIID(riid, &IID_IDirectSound))
221 *ppv = &This->IDirectSound8_iface;
222 else if((IsEqualIID(riid, &IID_IDirectSound8)))
224 if(This->is_8)
225 *ppv = &This->IDirectSound8_iface;
227 else
228 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
230 if(*ppv)
232 IUnknown_AddRef((IUnknown*)*ppv);
233 return S_OK;
236 return E_NOINTERFACE;
239 static ULONG WINAPI DS8_AddRef(IDirectSound8 *iface)
241 DS8Impl *This = impl_from_IDirectSound8(iface);
242 LONG ref;
244 ref = InterlockedIncrement(&This->ref);
245 TRACE("Reference count incremented to %"LONGFMT"d\n", ref);
247 return ref;
250 static ULONG WINAPI DS8_Release(IDirectSound8 *iface)
252 DS8Impl *This = impl_from_IDirectSound8(iface);
253 LONG ref;
255 ref = InterlockedDecrement(&This->ref);
256 TRACE("Reference count decremented to %"LONGFMT"d\n", ref);
257 if(ref == 0)
258 DS8Impl_Destroy(This);
260 return ref;
263 static HRESULT WINAPI DS8_CreateSoundBuffer(IDirectSound8 *iface, LPCDSBUFFERDESC desc, LPLPDIRECTSOUNDBUFFER buf, IUnknown *pUnkOuter)
265 DS8Impl *This = impl_from_IDirectSound8(iface);
266 HRESULT hr;
268 TRACE("(%p)->(%p, %p, %p)\n", iface, desc, buf, pUnkOuter);
270 if(!buf)
272 WARN("buf is null\n");
273 return DSERR_INVALIDPARAM;
275 *buf = NULL;
277 if(pUnkOuter)
279 WARN("Aggregation isn't supported\n");
280 return DSERR_NOAGGREGATION;
282 if(!desc || desc->dwSize < sizeof(DSBUFFERDESC1))
284 WARN("Invalid buffer %p/%"LONGFMT"u\n", desc, desc?desc->dwSize:0);
285 return DSERR_INVALIDPARAM;
288 if(!This->primary)
290 WARN("Device not initialized\n");
291 return DSERR_UNINITIALIZED;
294 TRACE("Requested buffer:\n"
295 " Size = %u\n"
296 " Flags = 0x%08x\n"
297 " BufferBytes = %u\n",
298 (UINT)desc->dwSize, (UINT)desc->dwFlags,
299 (UINT)desc->dwBufferBytes);
301 if(desc->dwSize >= sizeof(DSBUFFERDESC))
303 if(!(desc->dwFlags&DSBCAPS_CTRL3D))
305 if(!IsEqualGUID(&desc->guid3DAlgorithm, &GUID_NULL))
307 WARN("Invalid 3D algorithm GUID specified for non-3D buffer: %s\n", debugstr_guid(&desc->guid3DAlgorithm));
308 return DSERR_INVALIDPARAM;
311 else
312 TRACE("Requested 3D algorithm GUID: %s\n", debugstr_guid(&desc->guid3DAlgorithm));
315 /* OpenAL doesn't support playing with 3d and panning at same time.. */
316 if((desc->dwFlags&(DSBCAPS_CTRL3D|DSBCAPS_CTRLPAN)) == (DSBCAPS_CTRL3D|DSBCAPS_CTRLPAN))
318 if(!This->is_8)
319 ERR("Cannot create buffers with 3D and panning control\n");
320 else
321 WARN("Cannot create buffers with 3D and panning control\n");
322 return DSERR_INVALIDPARAM;
325 EnterCriticalSection(&This->primary->crst);
326 if((desc->dwFlags&DSBCAPS_PRIMARYBUFFER))
328 IDirectSoundBuffer *prim = &This->primary->IDirectSoundBuffer_iface;
330 hr = S_OK;
331 if(IDirectSoundBuffer_AddRef(prim) == 1)
333 hr = IDirectSoundBuffer_Initialize(prim, &This->IDirectSound_iface, desc);
334 if(FAILED(hr))
336 IDirectSoundBuffer_Release(prim);
337 prim = NULL;
340 *buf = prim;
342 else
344 DS8Buffer *dsb;
346 hr = DS8Buffer_Create(&dsb, This->primary, NULL);
347 if(SUCCEEDED(hr))
349 hr = IDirectSoundBuffer8_Initialize(&dsb->IDirectSoundBuffer8_iface, &This->IDirectSound_iface, desc);
350 if(FAILED(hr))
351 IDirectSoundBuffer8_Release(&dsb->IDirectSoundBuffer8_iface);
352 else
354 dsb->bufferlost = (This->prio_level == DSSCL_WRITEPRIMARY);
355 *buf = &dsb->IDirectSoundBuffer_iface;
359 LeaveCriticalSection(&This->primary->crst);
361 TRACE("%08"LONGFMT"x\n", hr);
362 return hr;
365 static HRESULT WINAPI DS8_GetCaps(IDirectSound8 *iface, LPDSCAPS caps)
367 DS8Impl *This = impl_from_IDirectSound8(iface);
368 LONG count;
370 TRACE("(%p)->(%p)\n", iface, caps);
372 if(!This->primary)
374 WARN("Device not initialized\n");
375 return DSERR_UNINITIALIZED;
378 if(!caps || caps->dwSize < sizeof(*caps))
380 WARN("Invalid DSCAPS (%p, %"LONGFMT"u)\n", caps, (caps?caps->dwSize:0));
381 return DSERR_INVALIDPARAM;
384 EnterCriticalSection(&This->primary->crst);
385 count = This->primary->max_sources;
387 setALContext(This->primary->ctx);
388 caps->dwFlags = DSCAPS_CONTINUOUSRATE |
389 DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYSTEREO |
390 DSCAPS_PRIMARY8BIT | DSCAPS_PRIMARYMONO |
391 DSCAPS_SECONDARY16BIT | DSCAPS_SECONDARY8BIT |
392 DSCAPS_SECONDARYMONO | DSCAPS_SECONDARYSTEREO;
393 caps->dwPrimaryBuffers = 1;
394 caps->dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
395 caps->dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
396 caps->dwMaxHwMixingAllBuffers =
397 caps->dwMaxHwMixingStaticBuffers =
398 caps->dwMaxHwMixingStreamingBuffers =
399 caps->dwMaxHw3DAllBuffers =
400 caps->dwMaxHw3DStaticBuffers =
401 caps->dwMaxHw3DStreamingBuffers = count;
402 count -= This->primary->nbuffers;
403 if(count < 0)
405 ERR("How did the count drop below 0?\n");
406 count = 0;
408 caps->dwFreeHwMixingAllBuffers =
409 caps->dwFreeHwMixingStaticBuffers =
410 caps->dwFreeHwMixingStreamingBuffers =
411 caps->dwFreeHw3DAllBuffers =
412 caps->dwFreeHw3DStaticBuffers =
413 caps->dwFreeHw3DStreamingBuffers = count;
414 caps->dwTotalHwMemBytes =
415 caps->dwFreeHwMemBytes = 64 * 1024 * 1024;
416 caps->dwMaxContigFreeHwMemBytes = caps->dwFreeHwMemBytes;
417 caps->dwUnlockTransferRateHwBuffers = 4096;
418 caps->dwPlayCpuOverheadSwBuffers = 0;
419 popALContext();
421 LeaveCriticalSection(&This->primary->crst);
423 return DS_OK;
425 static HRESULT WINAPI DS8_DuplicateSoundBuffer(IDirectSound8 *iface, IDirectSoundBuffer *in, IDirectSoundBuffer **out)
427 DS8Impl *This = impl_from_IDirectSound8(iface);
428 DS8Buffer *buf;
429 DSBCAPS caps;
430 HRESULT hr;
432 TRACE("(%p)->(%p, %p)\n", iface, in, out);
434 if(!This->primary)
436 WARN("Device not initialized\n");
437 return DSERR_UNINITIALIZED;
440 if(!in || !out)
442 WARN("Invalid pointer: int = %p, out = %p\n", in, out);
443 return DSERR_INVALIDPARAM;
445 *out = NULL;
447 EnterCriticalSection(&This->primary->crst);
449 caps.dwSize = sizeof(caps);
450 hr = IDirectSoundBuffer_GetCaps(in, &caps);
451 if(SUCCEEDED(hr) && (caps.dwFlags&DSBCAPS_PRIMARYBUFFER))
453 WARN("Cannot duplicate buffer %p, which has DSBCAPS_PRIMARYBUFFER\n", in);
454 hr = DSERR_INVALIDPARAM;
456 if(SUCCEEDED(hr) && (caps.dwFlags&DSBCAPS_CTRLFX))
458 WARN("Cannot duplicate buffer %p, which has DSBCAPS_CTRLFX\n", in);
459 hr = DSERR_INVALIDPARAM;
461 if(SUCCEEDED(hr))
462 hr = DS8Buffer_Create(&buf, This->primary, in);
463 if(SUCCEEDED(hr))
465 *out = &buf->IDirectSoundBuffer_iface;
466 hr = IDirectSoundBuffer_Initialize(*out, NULL, NULL);
468 if(SUCCEEDED(hr))
470 /* According to MSDN volume isn't copied */
471 if((caps.dwFlags&DSBCAPS_CTRLPAN))
473 LONG pan;
474 if(SUCCEEDED(IDirectSoundBuffer_GetPan(in, &pan)))
475 IDirectSoundBuffer_SetPan(*out, pan);
477 if((caps.dwFlags&DSBCAPS_CTRLFREQUENCY))
479 DWORD freq;
480 if(SUCCEEDED(IDirectSoundBuffer_GetFrequency(in, &freq)))
481 IDirectSoundBuffer_SetFrequency(*out, freq);
483 if((caps.dwFlags&DSBCAPS_CTRL3D))
485 IDirectSound3DBuffer *buf3d;
486 DS3DBUFFER DS3DBuffer;
487 HRESULT subhr;
489 subhr = IDirectSound_QueryInterface(in, &IID_IDirectSound3DBuffer, (void**)&buf3d);
490 if(SUCCEEDED(subhr))
492 DS3DBuffer.dwSize = sizeof(DS3DBuffer);
493 subhr = IDirectSound3DBuffer_GetAllParameters(buf3d, &DS3DBuffer);
494 IDirectSound3DBuffer_Release(buf3d);
496 if(SUCCEEDED(subhr))
497 subhr = IDirectSoundBuffer_QueryInterface(*out, &IID_IDirectSound3DBuffer, (void**)&buf3d);
498 if(SUCCEEDED(subhr))
500 subhr = IDirectSound3DBuffer_SetAllParameters(buf3d, &DS3DBuffer, DS3D_IMMEDIATE);
501 IDirectSound3DBuffer_Release(buf3d);
505 if(FAILED(hr))
507 if(*out)
508 IDirectSoundBuffer_Release(*out);
509 *out = NULL;
512 LeaveCriticalSection(&This->primary->crst);
513 return hr;
516 static HRESULT WINAPI DS8_SetCooperativeLevel(IDirectSound8 *iface, HWND hwnd, DWORD level)
518 DS8Impl *This = impl_from_IDirectSound8(iface);
519 HRESULT hr = S_OK;
521 TRACE("(%p)->(%p, %"LONGFMT"u)\n", iface, hwnd, level);
523 if(!This->primary)
525 WARN("Device not initialized\n");
526 return DSERR_UNINITIALIZED;
529 if(level > DSSCL_WRITEPRIMARY || level < DSSCL_NORMAL)
531 WARN("Invalid coop level: %"LONGFMT"u\n", level);
532 return DSERR_INVALIDPARAM;
535 EnterCriticalSection(&This->primary->crst);
536 if(level == DSSCL_WRITEPRIMARY && (This->prio_level != DSSCL_WRITEPRIMARY))
538 DWORD i, state;
540 for(i = 0; i < This->primary->nbuffers; ++i)
542 DS8Buffer *buf = This->primary->buffers[i];
543 if(FAILED(IDirectSoundBuffer_GetStatus(&buf->IDirectSoundBuffer8_iface, &state)) ||
544 (state&DSBSTATUS_PLAYING))
546 WARN("DSSCL_WRITEPRIMARY set with playing buffers!\n");
547 hr = DSERR_INVALIDCALL;
548 goto out;
550 /* Mark buffer as lost */
551 buf->bufferlost = 1;
553 if(This->primary->write_emu)
555 ERR("Why was there a write_emu?\n");
556 /* Delete it */
557 IDirectSoundBuffer8_Release(This->primary->write_emu);
558 This->primary->write_emu = NULL;
560 if(This->primary->flags)
562 /* Primary has open references.. create write_emu */
563 DSBUFFERDESC desc;
564 DS8Buffer *emu;
566 memset(&desc, 0, sizeof(desc));
567 desc.dwSize = sizeof(desc);
568 desc.dwFlags = DSBCAPS_LOCHARDWARE | (This->primary->flags&DSBCAPS_CTRLPAN);
569 desc.dwBufferBytes = This->primary->buf_size;
570 desc.lpwfxFormat = &This->primary->format.Format;
572 hr = DS8Buffer_Create(&emu, This->primary, NULL);
573 if(SUCCEEDED(hr))
575 This->primary->write_emu = &emu->IDirectSoundBuffer8_iface;
576 hr = IDirectSoundBuffer8_Initialize(This->primary->write_emu, &This->IDirectSound_iface, &desc);
577 if(FAILED(hr))
579 IDirectSoundBuffer8_Release(This->primary->write_emu);
580 This->primary->write_emu = NULL;
585 else if(This->prio_level == DSSCL_WRITEPRIMARY && level != DSSCL_WRITEPRIMARY && This->primary->write_emu)
587 TRACE("Nuking write_emu\n");
588 /* Delete it */
589 IDirectSoundBuffer8_Release(This->primary->write_emu);
590 This->primary->write_emu = NULL;
592 if(SUCCEEDED(hr))
593 This->prio_level = level;
594 out:
595 LeaveCriticalSection(&This->primary->crst);
597 return hr;
600 static HRESULT WINAPI DS8_Compact(IDirectSound8 *iface)
602 DS8Impl *This = impl_from_IDirectSound8(iface);
603 HRESULT hr = S_OK;
605 TRACE("(%p)->()\n", iface);
607 if(!This->primary)
609 WARN("Device not initialized\n");
610 return DSERR_UNINITIALIZED;
613 EnterCriticalSection(&This->primary->crst);
614 if(This->prio_level < DSSCL_PRIORITY)
616 WARN("Coop level not high enough (%"LONGFMT"u)\n", This->prio_level);
617 hr = DSERR_PRIOLEVELNEEDED;
619 LeaveCriticalSection(&This->primary->crst);
621 return hr;
624 static HRESULT WINAPI DS8_GetSpeakerConfig(IDirectSound8 *iface, DWORD *config)
626 DS8Impl *This = impl_from_IDirectSound8(iface);
627 HRESULT hr = S_OK;
629 TRACE("(%p)->(%p)\n", iface, config);
631 if(!config)
632 return DSERR_INVALIDPARAM;
633 *config = 0;
635 if(!This->primary)
637 WARN("Device not initialized\n");
638 return DSERR_UNINITIALIZED;
641 EnterCriticalSection(&This->primary->crst);
642 *config = This->speaker_config;
643 LeaveCriticalSection(&This->primary->crst);
645 return hr;
648 static HRESULT WINAPI DS8_SetSpeakerConfig(IDirectSound8 *iface, DWORD config)
650 DS8Impl *This = impl_from_IDirectSound8(iface);
651 DWORD geo, speaker;
652 HKEY key;
653 HRESULT hr;
655 TRACE("(%p)->(0x%08"LONGFMT"x)\n", iface, config);
657 if(!This->primary)
659 WARN("Device not initialized\n");
660 return DSERR_UNINITIALIZED;
663 EnterCriticalSection(&This->primary->crst);
665 geo = DSSPEAKER_GEOMETRY(config);
666 speaker = DSSPEAKER_CONFIG(config);
668 hr = DSERR_INVALIDPARAM;
669 if(geo && (geo < DSSPEAKER_GEOMETRY_MIN || geo > DSSPEAKER_GEOMETRY_MAX))
671 WARN("Invalid speaker angle %"LONGFMT"u\n", geo);
672 goto out;
674 if(speaker < DSSPEAKER_HEADPHONE || speaker > DSSPEAKER_7POINT1)
676 WARN("Invalid speaker config %"LONGFMT"u\n", speaker);
677 goto out;
680 hr = DSERR_GENERIC;
681 if(!RegCreateKeyExW(HKEY_LOCAL_MACHINE, speakerconfigkey, 0, NULL, 0, KEY_WRITE, NULL, &key, NULL))
683 RegSetValueExW(key, speakerconfig, 0, REG_DWORD, (const BYTE*)&config, sizeof(DWORD));
684 This->speaker_config = config;
685 RegCloseKey(key);
686 hr = S_OK;
688 out:
689 LeaveCriticalSection(&This->primary->crst);
691 return hr;
694 static HRESULT WINAPI DS8_Initialize(IDirectSound8 *iface, const GUID *devguid)
696 DS8Impl *This = impl_from_IDirectSound8(iface);
697 const ALCchar *drv_name;
698 HRESULT hr;
699 UINT n;
701 TRACE("(%p)->(%s)\n", iface, debugstr_guid(devguid));
703 if(!openal_loaded)
704 return DSERR_NODRIVER;
706 if(This->primary)
708 WARN("Device already initialized\n");
709 return DSERR_ALREADYINITIALIZED;
712 if(!devguid)
713 devguid = &DSDEVID_DefaultPlayback;
714 hr = GetDeviceID(devguid, &This->guid);
715 if(FAILED(hr))
716 return hr;
718 EnterCriticalSection(&openal_crst);
720 for(n = 0;n < devicelistsize;n++)
722 if(devicelist[n]->device && devicelist[n]->is_8 == This->is_8 &&
723 IsEqualGUID(&devicelist[n]->guid, &This->guid))
725 TRACE("Matched already open device %p\n", devicelist[n]);
727 This->device = devicelist[n]->device;
728 This->primary = devicelist[n]->primary;
729 This->deviceref = devicelist[n]->deviceref;
730 InterlockedIncrement(This->deviceref);
732 hr = DS_OK;
733 goto out;
737 if(!This->deviceref)
739 hr = DSERR_OUTOFMEMORY;
740 if(!(This->deviceref=HeapAlloc(GetProcessHeap(), 0, sizeof(LONG))))
741 goto out;
742 This->deviceref[0] = 1;
745 hr = DSERR_NODRIVER;
746 if(!(drv_name=DSOUND_getdevicestrings()) ||
747 memcmp(&This->guid, &DSOUND_renderer_guid, sizeof(GUID)-1) != 0)
749 WARN("No device found\n");
750 goto out;
753 n = This->guid.Data4[7];
754 while(*drv_name && n--)
755 drv_name += strlen(drv_name) + 1;
756 if(!*drv_name)
758 WARN("No device string found\n");
759 goto out;
762 This->device = alcOpenDevice(drv_name);
763 if(!This->device)
765 alcGetError(NULL);
766 WARN("Couldn't open device \"%s\"\n", drv_name);
767 goto out;
769 TRACE("Opened device: %s\n", alcGetString(This->device, ALC_DEVICE_SPECIFIER));
771 hr = DS8Primary_Create(&This->primary, This);
772 if(FAILED(hr))
774 alcCloseDevice(This->device);
775 This->device = NULL;
778 out:
779 LeaveCriticalSection(&openal_crst);
781 return hr;
784 /* I, Maarten Lankhorst, hereby declare this driver certified
785 * What this means.. ? An extra bit set
787 static HRESULT WINAPI DS8_VerifyCertification(IDirectSound8 *iface, DWORD *certified)
789 DS8Impl *This = impl_from_IDirectSound8(iface);
791 TRACE("(%p)->(%p)\n", iface, certified);
793 if(!certified)
794 return DSERR_INVALIDPARAM;
795 *certified = 0;
797 if(!This->primary)
799 WARN("Device not initialized\n");
800 return DSERR_UNINITIALIZED;
803 *certified = DS_CERTIFIED;
805 return DS_OK;
808 static const IDirectSound8Vtbl DS8_Vtbl = {
809 DS8_QueryInterface,
810 DS8_AddRef,
811 DS8_Release,
812 DS8_CreateSoundBuffer,
813 DS8_GetCaps,
814 DS8_DuplicateSoundBuffer,
815 DS8_SetCooperativeLevel,
816 DS8_Compact,
817 DS8_GetSpeakerConfig,
818 DS8_SetSpeakerConfig,
819 DS8_Initialize,
820 DS8_VerifyCertification
824 static HRESULT WINAPI DS_QueryInterface(IDirectSound *iface, REFIID riid, LPVOID *ppv)
826 DS8Impl *This = impl_from_IDirectSound(iface);
827 return DS8_QueryInterface(&This->IDirectSound8_iface, riid, ppv);
830 static ULONG WINAPI DS_AddRef(IDirectSound *iface)
832 DS8Impl *This = impl_from_IDirectSound(iface);
833 return DS8_AddRef(&This->IDirectSound8_iface);
836 static ULONG WINAPI DS_Release(IDirectSound *iface)
838 DS8Impl *This = impl_from_IDirectSound(iface);
839 return DS8_Release(&This->IDirectSound8_iface);
842 static HRESULT WINAPI DS_CreateSoundBuffer(IDirectSound *iface, LPCDSBUFFERDESC desc, LPLPDIRECTSOUNDBUFFER buf, IUnknown *pUnkOuter)
844 DS8Impl *This = impl_from_IDirectSound(iface);
845 return DS8_CreateSoundBuffer(&This->IDirectSound8_iface, desc, buf, pUnkOuter);
848 static HRESULT WINAPI DS_GetCaps(IDirectSound *iface, LPDSCAPS caps)
850 DS8Impl *This = impl_from_IDirectSound(iface);
851 return DS8_GetCaps(&This->IDirectSound8_iface, caps);
853 static HRESULT WINAPI DS_DuplicateSoundBuffer(IDirectSound *iface, IDirectSoundBuffer *in, IDirectSoundBuffer **out)
855 DS8Impl *This = impl_from_IDirectSound(iface);
856 return DS8_DuplicateSoundBuffer(&This->IDirectSound8_iface, in, out);
859 static HRESULT WINAPI DS_SetCooperativeLevel(IDirectSound *iface, HWND hwnd, DWORD level)
861 DS8Impl *This = impl_from_IDirectSound(iface);
862 return DS8_SetCooperativeLevel(&This->IDirectSound8_iface, hwnd, level);
865 static HRESULT WINAPI DS_Compact(IDirectSound *iface)
867 DS8Impl *This = impl_from_IDirectSound(iface);
868 return DS8_Compact(&This->IDirectSound8_iface);
871 static HRESULT WINAPI DS_GetSpeakerConfig(IDirectSound *iface, DWORD *config)
873 DS8Impl *This = impl_from_IDirectSound(iface);
874 return DS8_GetSpeakerConfig(&This->IDirectSound8_iface, config);
877 static HRESULT WINAPI DS_SetSpeakerConfig(IDirectSound *iface, DWORD config)
879 DS8Impl *This = impl_from_IDirectSound(iface);
880 return DS8_SetSpeakerConfig(&This->IDirectSound8_iface, config);
883 static HRESULT WINAPI DS_Initialize(IDirectSound *iface, const GUID *devguid)
885 DS8Impl *This = impl_from_IDirectSound(iface);
886 return DS8_Initialize(&This->IDirectSound8_iface, devguid);
889 static const IDirectSoundVtbl DS_Vtbl = {
890 DS_QueryInterface,
891 DS_AddRef,
892 DS_Release,
893 DS_CreateSoundBuffer,
894 DS_GetCaps,
895 DS_DuplicateSoundBuffer,
896 DS_SetCooperativeLevel,
897 DS_Compact,
898 DS_GetSpeakerConfig,
899 DS_SetSpeakerConfig,
900 DS_Initialize