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
28 #define NONAMELESSSTRUCT
29 #define NONAMELESSUNION
38 #include "wine/debug.h"
41 #include "dsound_private.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(dsound
);
51 #include "dsound_private.h"
53 #ifndef DSSPEAKER_7POINT1
54 #define DSSPEAKER_7POINT1 7
59 static DeviceShare
**sharelist
;
60 static UINT sharelistsize
;
62 static void DSShare_Destroy(DeviceShare
*share
)
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
);
80 LeaveCriticalSection(&openal_crst
);
84 /* Calling setALContext is not appropriate here,
85 * since we *have* to unset the context before destroying it
89 EnterCriticalSection(&openal_crst
);
90 old_ctx
= get_context();
91 if(old_ctx
!= share
->ctx
)
92 set_context(share
->ctx
);
97 alDeleteSources(share
->nsources
, share
->sources
);
100 share
->ExtAL
.DeleteEffects(1, &share
->effect
);
102 share
->ExtAL
.DeleteAuxiliaryEffectSlots(1, &share
->auxslot
);
104 set_context(old_ctx
);
105 alcDestroyContext(share
->ctx
);
106 LeaveCriticalSection(&openal_crst
);
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
;
127 share
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*share
));
128 if(!share
) return DSERR_OUTOFMEMORY
;
131 InitializeCriticalSection(&share
->crst
);
132 share
->crst
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": Device.crst");
135 if(!(drv_name
=DSOUND_getdevicestrings()) ||
136 memcmp(guid
, &DSOUND_renderer_guid
, sizeof(GUID
)-1) != 0)
138 WARN("No device found\n");
143 while(*drv_name
&& n
--)
144 drv_name
+= strlen(drv_name
) + 1;
147 WARN("No device string found\n");
150 memcpy(&share
->guid
, guid
, sizeof(GUID
));
152 share
->device
= alcOpenDevice(drv_name
);
156 WARN("Couldn't open device \"%s\"\n", drv_name
);
159 TRACE("Opened device: %s\n", alcGetString(share
->device
, ALC_DEVICE_SPECIFIER
));
162 share
->ctx
= alcCreateContext(share
->device
, NULL
);
165 ALCenum err
= alcGetError(share
->device
);
166 ERR("Could not create context (0x%x)!\n", err
);
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
);
218 LOAD_FUNC(GenAuxiliaryEffectSlots
);
219 LOAD_FUNC(DeleteAuxiliaryEffectSlots
);
220 LOAD_FUNC(AuxiliaryEffectSloti
);
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
)
245 share
->max_sources
++;
247 share
->nsources
= share
->max_sources
;
251 temp
= HeapReAlloc(GetProcessHeap(), 0, sharelist
, sizeof(*sharelist
)*(sharelistsize
+1));
253 temp
= HeapAlloc(GetProcessHeap(), 0, sizeof(*sharelist
)*(sharelistsize
+1));
257 sharelist
[sharelistsize
++] = share
;
264 DSShare_Destroy(share
);
268 static ULONG
DSShare_AddRef(DeviceShare
*share
)
270 ULONG ref
= InterlockedIncrement(&share
->ref
);
274 static ULONG
DSShare_Release(DeviceShare
*share
)
276 ULONG ref
= InterlockedDecrement(&share
->ref
);
277 if(ref
== 0) DSShare_Destroy(share
);
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
)
299 if(IsEqualIID(riid
, &IID_IDirectSound8
))
300 return E_NOINTERFACE
;
301 hr
= DSOUND_Create8(&IID_IDirectSound8
, ds
);
304 DS8Impl
*impl
= impl_from_IDirectSound8(*ds
);
307 hr
= IDirectSound8_QueryInterface(&impl
->IDirectSound8_iface
, riid
, ds
);
308 IDirectSound8_Release(&impl
->IDirectSound8_iface
);
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
)
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
;
342 This
->speaker_config
= DSSPEAKER_COMBINED(DSSPEAKER_5POINT1
, DSSPEAKER_GEOMETRY_WIDE
);
344 if(RegOpenKeyExW(HKEY_LOCAL_MACHINE
, speakerconfigkey
, 0, KEY_READ
, ®key
) == 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
;
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
);
360 DS8Impl_Destroy(This
);
364 static void DS8Impl_Destroy(DS8Impl
*This
)
367 DS8Primary_Destroy(This
->primary
);
368 This
->primary
= NULL
;
370 DSShare_Release(This
->share
);
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
);
384 if(IsEqualIID(riid
, &IID_IUnknown
) ||
385 IsEqualIID(riid
, &IID_IDirectSound
))
386 *ppv
= &This
->IDirectSound8_iface
;
387 else if((IsEqualIID(riid
, &IID_IDirectSound8
)))
390 *ppv
= &This
->IDirectSound8_iface
;
393 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid
));
397 IUnknown_AddRef((IUnknown
*)*ppv
);
401 return E_NOINTERFACE
;
404 static ULONG WINAPI
DS8_AddRef(IDirectSound8
*iface
)
406 DS8Impl
*This
= impl_from_IDirectSound8(iface
);
409 ref
= InterlockedIncrement(&This
->ref
);
410 TRACE("Reference count incremented to %"LONGFMT
"d\n", ref
);
415 static ULONG WINAPI
DS8_Release(IDirectSound8
*iface
)
417 DS8Impl
*This
= impl_from_IDirectSound8(iface
);
420 ref
= InterlockedDecrement(&This
->ref
);
421 TRACE("Reference count decremented to %"LONGFMT
"d\n", ref
);
423 DS8Impl_Destroy(This
);
428 static HRESULT WINAPI
DS8_CreateSoundBuffer(IDirectSound8
*iface
, LPCDSBUFFERDESC desc
, LPLPDIRECTSOUNDBUFFER buf
, IUnknown
*pUnkOuter
)
430 DS8Impl
*This
= impl_from_IDirectSound8(iface
);
433 TRACE("(%p)->(%p, %p, %p)\n", iface
, desc
, buf
, pUnkOuter
);
437 WARN("buf is null\n");
438 return DSERR_INVALIDPARAM
;
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
;
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
;
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
))
483 ERR("Cannot create buffers with 3D and panning control\n");
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
;
495 if(IDirectSoundBuffer_AddRef(prim
) == 1)
497 hr
= IDirectSoundBuffer_Initialize(prim
, &This
->IDirectSound_iface
, desc
);
500 IDirectSoundBuffer_Release(prim
);
510 hr
= DS8Buffer_Create(&dsb
, This
->primary
, NULL
);
513 hr
= IDirectSoundBuffer8_Initialize(&dsb
->IDirectSoundBuffer8_iface
, &This
->IDirectSound_iface
, desc
);
515 IDirectSoundBuffer8_Release(&dsb
->IDirectSoundBuffer8_iface
);
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
);
529 static HRESULT WINAPI
DS8_GetCaps(IDirectSound8
*iface
, LPDSCAPS caps
)
531 DS8Impl
*This
= impl_from_IDirectSound8(iface
);
533 TRACE("(%p)->(%p)\n", iface
, caps
);
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
);
579 static HRESULT WINAPI
DS8_DuplicateSoundBuffer(IDirectSound8
*iface
, IDirectSoundBuffer
*in
, IDirectSoundBuffer
**out
)
581 DS8Impl
*This
= impl_from_IDirectSound8(iface
);
586 TRACE("(%p)->(%p, %p)\n", iface
, in
, out
);
590 WARN("Device not initialized\n");
591 return DSERR_UNINITIALIZED
;
596 WARN("Invalid pointer: int = %p, out = %p\n", in
, out
);
597 return DSERR_INVALIDPARAM
;
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
;
614 hr
= DS8Buffer_Create(&buf
, This
->primary
, in
);
617 *out
= &buf
->IDirectSoundBuffer_iface
;
618 hr
= IDirectSoundBuffer_Initialize(*out
, NULL
, NULL
);
622 /* According to MSDN volume isn't copied */
623 if((caps
.dwFlags
&DSBCAPS_CTRLPAN
))
626 if(SUCCEEDED(IDirectSoundBuffer_GetPan(in
, &pan
)))
627 IDirectSoundBuffer_SetPan(*out
, pan
);
629 if((caps
.dwFlags
&DSBCAPS_CTRLFREQUENCY
))
632 if(SUCCEEDED(IDirectSoundBuffer_GetFrequency(in
, &freq
)))
633 IDirectSoundBuffer_SetFrequency(*out
, freq
);
635 if((caps
.dwFlags
&DSBCAPS_CTRL3D
))
637 IDirectSound3DBuffer
*buf3d
;
638 DS3DBUFFER DS3DBuffer
;
641 subhr
= IDirectSound_QueryInterface(in
, &IID_IDirectSound3DBuffer
, (void**)&buf3d
);
644 DS3DBuffer
.dwSize
= sizeof(DS3DBuffer
);
645 subhr
= IDirectSound3DBuffer_GetAllParameters(buf3d
, &DS3DBuffer
);
646 IDirectSound3DBuffer_Release(buf3d
);
649 subhr
= IDirectSoundBuffer_QueryInterface(*out
, &IID_IDirectSound3DBuffer
, (void**)&buf3d
);
652 subhr
= IDirectSound3DBuffer_SetAllParameters(buf3d
, &DS3DBuffer
, DS3D_IMMEDIATE
);
653 IDirectSound3DBuffer_Release(buf3d
);
660 IDirectSoundBuffer_Release(*out
);
667 static HRESULT WINAPI
DS8_SetCooperativeLevel(IDirectSound8
*iface
, HWND hwnd
, DWORD level
)
669 DS8Impl
*This
= impl_from_IDirectSound8(iface
);
672 TRACE("(%p)->(%p, %"LONGFMT
"u)\n", iface
, hwnd
, level
);
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
))
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
;
701 /* Mark buffer as lost */
704 if(This
->primary
->write_emu
)
706 ERR("Why was there a write_emu?\n");
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 */
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
);
726 This
->primary
->write_emu
= &emu
->IDirectSoundBuffer8_iface
;
727 hr
= IDirectSoundBuffer8_Initialize(This
->primary
->write_emu
, &This
->IDirectSound_iface
, &desc
);
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");
740 IDirectSoundBuffer8_Release(This
->primary
->write_emu
);
741 This
->primary
->write_emu
= NULL
;
744 This
->prio_level
= level
;
746 LeaveCriticalSection(This
->primary
->crst
);
751 static HRESULT WINAPI
DS8_Compact(IDirectSound8
*iface
)
753 DS8Impl
*This
= impl_from_IDirectSound8(iface
);
756 TRACE("(%p)->()\n", iface
);
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
);
775 static HRESULT WINAPI
DS8_GetSpeakerConfig(IDirectSound8
*iface
, DWORD
*config
)
777 DS8Impl
*This
= impl_from_IDirectSound8(iface
);
780 TRACE("(%p)->(%p)\n", iface
, config
);
783 return DSERR_INVALIDPARAM
;
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
);
799 static HRESULT WINAPI
DS8_SetSpeakerConfig(IDirectSound8
*iface
, DWORD config
)
801 DS8Impl
*This
= impl_from_IDirectSound8(iface
);
806 TRACE("(%p)->(0x%08"LONGFMT
"x)\n", iface
, config
);
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
);
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
;
839 LeaveCriticalSection(&This
->share
->crst
);
843 static HRESULT WINAPI
DS8_Initialize(IDirectSound8
*iface
, const GUID
*devguid
)
845 DS8Impl
*This
= impl_from_IDirectSound8(iface
);
850 TRACE("(%p)->(%s)\n", iface
, debugstr_guid(devguid
));
853 return DSERR_NODRIVER
;
857 WARN("Device already initialized\n");
858 return DSERR_ALREADYINITIALIZED
;
862 devguid
= &DSDEVID_DefaultPlayback
;
863 hr
= GetDeviceID(devguid
, &guid
);
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
);
882 hr
= DSShare_Create(&guid
, &This
->share
);
885 This
->device
= This
->share
->device
;
886 hr
= DS8Primary_Create(&This
->primary
, This
);
892 DSShare_Release(This
->share
);
896 LeaveCriticalSection(&openal_crst
);
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
);
910 return DSERR_INVALIDPARAM
;
915 WARN("Device not initialized\n");
916 return DSERR_UNINITIALIZED
;
919 *certified
= DS_CERTIFIED
;
924 static const IDirectSound8Vtbl DS8_Vtbl
= {
928 DS8_CreateSoundBuffer
,
930 DS8_DuplicateSoundBuffer
,
931 DS8_SetCooperativeLevel
,
933 DS8_GetSpeakerConfig
,
934 DS8_SetSpeakerConfig
,
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
= {
1009 DS_CreateSoundBuffer
,
1011 DS_DuplicateSoundBuffer
,
1012 DS_SetCooperativeLevel
,
1014 DS_GetSpeakerConfig
,
1015 DS_SetSpeakerConfig
,