2 * Copyright (c) 2015 Mark Harmstone
3 * Copyright (c) 2015 Andrew Eikum for CodeWeavers
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define NONAMELESSUNION
27 #include "xaudio_private.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(xaudio2
);
38 static ALCdevice
*(ALC_APIENTRY
*palcLoopbackOpenDeviceSOFT
)(const ALCchar
*);
39 static void (ALC_APIENTRY
*palcRenderSamplesSOFT
)(ALCdevice
*, ALCvoid
*, ALCsizei
);
41 static HINSTANCE instance
;
43 #define COMPAT_E_INVALID_CALL(v) (v == 20) ? E_INVALIDARG : XAUDIO2_E_INVALID_CALL
44 #define COMPAT_E_DEVICE_INVALIDATED(v) (v == 20) ? XAUDIO20_E_DEVICE_INVALIDATED : XAUDIO2_E_DEVICE_INVALIDATED
46 static void dump_fmt(const WAVEFORMATEX
*fmt
)
48 TRACE("wFormatTag: 0x%x (", fmt
->wFormatTag
);
49 switch(fmt
->wFormatTag
){
50 #define DOCASE(x) case x: TRACE(#x); break;
51 DOCASE(WAVE_FORMAT_PCM
)
52 DOCASE(WAVE_FORMAT_IEEE_FLOAT
)
53 DOCASE(WAVE_FORMAT_EXTENSIBLE
)
61 TRACE("nChannels: %u\n", fmt
->nChannels
);
62 TRACE("nSamplesPerSec: %u\n", fmt
->nSamplesPerSec
);
63 TRACE("nAvgBytesPerSec: %u\n", fmt
->nAvgBytesPerSec
);
64 TRACE("nBlockAlign: %u\n", fmt
->nBlockAlign
);
65 TRACE("wBitsPerSample: %u\n", fmt
->wBitsPerSample
);
66 TRACE("cbSize: %u\n", fmt
->cbSize
);
68 if(fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
){
69 WAVEFORMATEXTENSIBLE
*fmtex
= (void*)fmt
;
70 TRACE("dwChannelMask: %08x\n", fmtex
->dwChannelMask
);
71 TRACE("Samples: %04x\n", fmtex
->Samples
.wReserved
);
72 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex
->SubFormat
));
73 }else if(fmt
->wFormatTag
== WAVE_FORMAT_ADPCM
){
74 ADPCMWAVEFORMAT
*fmtadpcm
= (void*)fmt
;
75 TRACE("wSamplesPerBlock: %u\n", fmtadpcm
->wSamplesPerBlock
);
79 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD reason
, void *pReserved
)
81 TRACE("(%p, %d, %p)\n", hinstDLL
, reason
, pReserved
);
85 case DLL_WINE_PREATTACH
:
86 return FALSE
; /* prefer native version */
87 case DLL_PROCESS_ATTACH
:
89 DisableThreadLibraryCalls( hinstDLL
);
91 if(!alcIsExtensionPresent(NULL
, "ALC_SOFT_loopback") ||
92 !(palcLoopbackOpenDeviceSOFT
= alcGetProcAddress(NULL
, "alcLoopbackOpenDeviceSOFT")) ||
93 !(palcRenderSamplesSOFT
= alcGetProcAddress(NULL
, "alcRenderSamplesSOFT"))){
94 ERR("XAudio2 requires the ALC_SOFT_loopback extension (OpenAL-Soft >= 1.14)\n");
103 HRESULT WINAPI
DllCanUnloadNow(void)
108 HRESULT WINAPI
DllRegisterServer(void)
111 return __wine_register_resources(instance
);
114 HRESULT WINAPI
DllUnregisterServer(void)
117 return __wine_unregister_resources(instance
);
120 static XA2SourceImpl
*impl_from_IXAudio2SourceVoice(IXAudio2SourceVoice
*iface
)
122 return CONTAINING_RECORD(iface
, XA2SourceImpl
, IXAudio2SourceVoice_iface
);
125 static XA2SubmixImpl
*impl_from_IXAudio2SubmixVoice(IXAudio2SubmixVoice
*iface
)
127 return CONTAINING_RECORD(iface
, XA2SubmixImpl
, IXAudio2SubmixVoice_iface
);
130 static inline IXAudio2Impl
*impl_from_IXAudio2(IXAudio2
*iface
)
132 return CONTAINING_RECORD(iface
, IXAudio2Impl
, IXAudio2_iface
);
135 static IXAudio2Impl
*impl_from_IXAudio2MasteringVoice(IXAudio2MasteringVoice
*iface
)
137 return CONTAINING_RECORD(iface
, IXAudio2Impl
, IXAudio2MasteringVoice_iface
);
140 static DWORD
get_channel_mask(unsigned int channels
)
146 return KSAUDIO_SPEAKER_MONO
;
148 return KSAUDIO_SPEAKER_STEREO
;
150 return KSAUDIO_SPEAKER_STEREO
| SPEAKER_LOW_FREQUENCY
;
152 return KSAUDIO_SPEAKER_QUAD
; /* not _SURROUND */
154 return KSAUDIO_SPEAKER_QUAD
| SPEAKER_LOW_FREQUENCY
;
156 return KSAUDIO_SPEAKER_5POINT1
; /* not 5POINT1_SURROUND */
158 return KSAUDIO_SPEAKER_5POINT1
| SPEAKER_BACK_CENTER
;
160 return KSAUDIO_SPEAKER_7POINT1_SURROUND
; /* Vista deprecates 7POINT1 */
162 FIXME("Unknown speaker configuration: %u\n", channels
);
166 static void WINAPI
XA2SRC_GetVoiceDetails(IXAudio2SourceVoice
*iface
,
167 XAUDIO2_VOICE_DETAILS
*pVoiceDetails
)
169 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
170 TRACE("%p, %p\n", This
, pVoiceDetails
);
173 static HRESULT WINAPI
XA2SRC_SetOutputVoices(IXAudio2SourceVoice
*iface
,
174 const XAUDIO2_VOICE_SENDS
*pSendList
)
176 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
178 XAUDIO2_VOICE_SENDS def_send
;
179 XAUDIO2_SEND_DESCRIPTOR def_desc
;
181 TRACE("%p, %p\n", This
, pSendList
);
185 def_desc
.pOutputVoice
= (IXAudio2Voice
*)&This
->xa2
->IXAudio2MasteringVoice_iface
;
187 def_send
.SendCount
= 1;
188 def_send
.pSends
= &def_desc
;
190 pSendList
= &def_send
;
193 if(TRACE_ON(xaudio2
)){
194 for(i
= 0; i
< pSendList
->SendCount
; ++i
){
195 XAUDIO2_SEND_DESCRIPTOR
*desc
= &pSendList
->pSends
[i
];
196 TRACE("Outputting to: 0x%x, %p\n", desc
->Flags
, desc
->pOutputVoice
);
200 if(This
->nsends
< pSendList
->SendCount
){
201 HeapFree(GetProcessHeap(), 0, This
->sends
);
202 This
->sends
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
->sends
) * pSendList
->SendCount
);
203 This
->nsends
= pSendList
->SendCount
;
205 memset(This
->sends
, 0, sizeof(*This
->sends
) * This
->nsends
);
207 memcpy(This
->sends
, pSendList
->pSends
, sizeof(*This
->sends
) * pSendList
->SendCount
);
212 static HRESULT WINAPI
XA2SRC_SetEffectChain(IXAudio2SourceVoice
*iface
,
213 const XAUDIO2_EFFECT_CHAIN
*pEffectChain
)
215 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
216 TRACE("%p, %p\n", This
, pEffectChain
);
220 static HRESULT WINAPI
XA2SRC_EnableEffect(IXAudio2SourceVoice
*iface
,
221 UINT32 EffectIndex
, UINT32 OperationSet
)
223 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
224 TRACE("%p, %u, 0x%x\n", This
, EffectIndex
, OperationSet
);
228 static HRESULT WINAPI
XA2SRC_DisableEffect(IXAudio2SourceVoice
*iface
,
229 UINT32 EffectIndex
, UINT32 OperationSet
)
231 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
232 TRACE("%p, %u, 0x%x\n", This
, EffectIndex
, OperationSet
);
236 static void WINAPI
XA2SRC_GetEffectState(IXAudio2SourceVoice
*iface
,
237 UINT32 EffectIndex
, BOOL
*pEnabled
)
239 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
240 TRACE("%p, %u, %p\n", This
, EffectIndex
, pEnabled
);
243 static HRESULT WINAPI
XA2SRC_SetEffectParameters(IXAudio2SourceVoice
*iface
,
244 UINT32 EffectIndex
, const void *pParameters
, UINT32 ParametersByteSize
,
247 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
248 TRACE("%p, %u, %p, 0x%x, 0x%x\n", This
, EffectIndex
, pParameters
,
249 ParametersByteSize
, OperationSet
);
253 static HRESULT WINAPI
XA2SRC_GetEffectParameters(IXAudio2SourceVoice
*iface
,
254 UINT32 EffectIndex
, void *pParameters
, UINT32 ParametersByteSize
)
256 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
257 TRACE("%p, %u, %p, 0x%x\n", This
, EffectIndex
, pParameters
,
262 static HRESULT WINAPI
XA2SRC_SetFilterParameters(IXAudio2SourceVoice
*iface
,
263 const XAUDIO2_FILTER_PARAMETERS
*pParameters
, UINT32 OperationSet
)
265 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
266 TRACE("%p, %p, 0x%x\n", This
, pParameters
, OperationSet
);
270 static void WINAPI
XA2SRC_GetFilterParameters(IXAudio2SourceVoice
*iface
,
271 XAUDIO2_FILTER_PARAMETERS
*pParameters
)
273 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
274 TRACE("%p, %p\n", This
, pParameters
);
277 static HRESULT WINAPI
XA2SRC_SetOutputFilterParameters(IXAudio2SourceVoice
*iface
,
278 IXAudio2Voice
*pDestinationVoice
,
279 const XAUDIO2_FILTER_PARAMETERS
*pParameters
, UINT32 OperationSet
)
281 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
282 TRACE("%p, %p, %p, 0x%x\n", This
, pDestinationVoice
, pParameters
, OperationSet
);
286 static void WINAPI
XA2SRC_GetOutputFilterParameters(IXAudio2SourceVoice
*iface
,
287 IXAudio2Voice
*pDestinationVoice
,
288 XAUDIO2_FILTER_PARAMETERS
*pParameters
)
290 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
291 TRACE("%p, %p, %p\n", This
, pDestinationVoice
, pParameters
);
294 static HRESULT WINAPI
XA2SRC_SetVolume(IXAudio2SourceVoice
*iface
, float Volume
,
297 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
300 TRACE("%p, %f, 0x%x\n", This
, Volume
, OperationSet
);
304 alSourcef(This
->al_src
, AL_GAIN
, al_gain
);
309 static void WINAPI
XA2SRC_GetVolume(IXAudio2SourceVoice
*iface
, float *pVolume
)
311 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
312 TRACE("%p, %p\n", This
, pVolume
);
315 static HRESULT WINAPI
XA2SRC_SetChannelVolumes(IXAudio2SourceVoice
*iface
,
316 UINT32 Channels
, const float *pVolumes
, UINT32 OperationSet
)
318 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
319 TRACE("%p, %u, %p, 0x%x\n", This
, Channels
, pVolumes
, OperationSet
);
323 static void WINAPI
XA2SRC_GetChannelVolumes(IXAudio2SourceVoice
*iface
,
324 UINT32 Channels
, float *pVolumes
)
326 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
327 TRACE("%p, %u, %p\n", This
, Channels
, pVolumes
);
330 static HRESULT WINAPI
XA2SRC_SetOutputMatrix(IXAudio2SourceVoice
*iface
,
331 IXAudio2Voice
*pDestinationVoice
, UINT32 SourceChannels
,
332 UINT32 DestinationChannels
, const float *pLevelMatrix
,
335 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
336 TRACE("%p, %p, %u, %u, %p, 0x%x\n", This
, pDestinationVoice
,
337 SourceChannels
, DestinationChannels
, pLevelMatrix
, OperationSet
);
341 static void WINAPI
XA2SRC_GetOutputMatrix(IXAudio2SourceVoice
*iface
,
342 IXAudio2Voice
*pDestinationVoice
, UINT32 SourceChannels
,
343 UINT32 DestinationChannels
, float *pLevelMatrix
)
345 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
346 TRACE("%p, %p, %u, %u, %p\n", This
, pDestinationVoice
,
347 SourceChannels
, DestinationChannels
, pLevelMatrix
);
350 static void WINAPI
XA2SRC_DestroyVoice(IXAudio2SourceVoice
*iface
)
352 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
357 EnterCriticalSection(&This
->lock
);
360 LeaveCriticalSection(&This
->lock
);
364 This
->in_use
= FALSE
;
366 This
->running
= FALSE
;
368 IXAudio2SourceVoice_Stop(iface
, 0, 0);
370 alSourceStop(This
->al_src
);
372 /* unqueue all buffers */
373 alSourcei(This
->al_src
, AL_BUFFER
, AL_NONE
);
375 alGetSourcei(This
->al_src
, AL_BUFFERS_PROCESSED
, &processed
);
378 ALuint al_buffers
[XAUDIO2_MAX_QUEUED_BUFFERS
];
380 alSourceUnqueueBuffers(This
->al_src
, processed
, al_buffers
);
383 HeapFree(GetProcessHeap(), 0, This
->fmt
);
385 alDeleteBuffers(XAUDIO2_MAX_QUEUED_BUFFERS
, This
->al_bufs
);
386 alDeleteSources(1, &This
->al_src
);
388 This
->in_al_bytes
= 0;
389 This
->al_bufs_used
= 0;
390 This
->played_frames
= 0;
395 LeaveCriticalSection(&This
->lock
);
398 static HRESULT WINAPI
XA2SRC_Start(IXAudio2SourceVoice
*iface
, UINT32 Flags
,
401 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
403 TRACE("%p, 0x%x, 0x%x\n", This
, Flags
, OperationSet
);
405 EnterCriticalSection(&This
->lock
);
407 This
->running
= TRUE
;
409 LeaveCriticalSection(&This
->lock
);
414 static HRESULT WINAPI
XA2SRC_Stop(IXAudio2SourceVoice
*iface
, UINT32 Flags
,
417 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
419 TRACE("%p, 0x%x, 0x%x\n", This
, Flags
, OperationSet
);
421 EnterCriticalSection(&This
->lock
);
423 This
->running
= FALSE
;
425 LeaveCriticalSection(&This
->lock
);
430 static ALenum
get_al_format(const WAVEFORMATEX
*fmt
)
432 WAVEFORMATEXTENSIBLE
*fmtex
= (WAVEFORMATEXTENSIBLE
*)fmt
;
433 if(fmt
->wFormatTag
== WAVE_FORMAT_PCM
||
434 (fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
&&
435 IsEqualGUID(&fmtex
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
))){
436 switch(fmt
->wBitsPerSample
){
438 switch(fmt
->nChannels
){
440 return AL_FORMAT_MONO8
;
442 return AL_FORMAT_STEREO8
;
444 return AL_FORMAT_QUAD8
;
446 return AL_FORMAT_51CHN8
;
448 return AL_FORMAT_61CHN8
;
450 return AL_FORMAT_71CHN8
;
453 switch(fmt
->nChannels
){
455 return AL_FORMAT_MONO16
;
457 return AL_FORMAT_STEREO16
;
459 return AL_FORMAT_QUAD16
;
461 return AL_FORMAT_51CHN16
;
463 return AL_FORMAT_61CHN16
;
465 return AL_FORMAT_71CHN16
;
468 }else if(fmt
->wFormatTag
== WAVE_FORMAT_IEEE_FLOAT
||
469 (fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
&&
470 IsEqualGUID(&fmtex
->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
))){
471 if(fmt
->wBitsPerSample
== 32){
472 switch(fmt
->nChannels
){
474 return AL_FORMAT_MONO_FLOAT32
;
476 return AL_FORMAT_STEREO_FLOAT32
;
483 static HRESULT WINAPI
XA2SRC_SubmitSourceBuffer(IXAudio2SourceVoice
*iface
,
484 const XAUDIO2_BUFFER
*pBuffer
, const XAUDIO2_BUFFER_WMA
*pBufferWMA
)
486 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
490 TRACE("%p, %p, %p\n", This
, pBuffer
, pBufferWMA
);
492 if(TRACE_ON(xaudio2
)){
493 TRACE("Flags: 0x%x\n", pBuffer
->Flags
);
494 TRACE("AudioBytes: %u\n", pBuffer
->AudioBytes
);
495 TRACE("pAudioData: %p\n", pBuffer
->pAudioData
);
496 TRACE("PlayBegin: %u\n", pBuffer
->PlayBegin
);
497 TRACE("PlayLength: %u\n", pBuffer
->PlayLength
);
498 TRACE("LoopBegin: %u\n", pBuffer
->LoopBegin
);
499 TRACE("LoopLength: %u\n", pBuffer
->LoopLength
);
500 TRACE("LoopCount: %u\n", pBuffer
->LoopCount
);
501 TRACE("pContext: %p\n", pBuffer
->pContext
);
504 EnterCriticalSection(&This
->lock
);
506 if(This
->nbufs
>= XAUDIO2_MAX_QUEUED_BUFFERS
){
507 TRACE("Too many buffers queued!\n");
508 LeaveCriticalSection(&This
->lock
);
509 return COMPAT_E_INVALID_CALL(This
->xa2
->version
);
512 buf_idx
= (This
->first_buf
+ This
->nbufs
) % XAUDIO2_MAX_QUEUED_BUFFERS
;
513 buf
= &This
->buffers
[buf_idx
];
514 memset(buf
, 0, sizeof(*buf
));
516 /* API contract: pAudioData must remain valid until this buffer is played,
517 * but pBuffer itself may be reused immediately */
518 memcpy(&buf
->xa2buffer
, pBuffer
, sizeof(*pBuffer
));
520 if(This
->xa2
->version
== 20){
521 if(buf
->xa2buffer
.LoopCount
== XAUDIO20_LOOP_INFINITE
)
522 buf
->xa2buffer
.LoopCount
= XAUDIO2_LOOP_INFINITE
;
525 /* convert samples offsets to bytes */
526 if(This
->fmt
->wFormatTag
== WAVE_FORMAT_ADPCM
){
527 /* ADPCM gives us a number of samples per block, so round down to
528 * nearest block and convert to bytes */
529 buf
->xa2buffer
.PlayBegin
= buf
->xa2buffer
.PlayBegin
/ ((ADPCMWAVEFORMAT
*)This
->fmt
)->wSamplesPerBlock
* This
->fmt
->nBlockAlign
;
530 buf
->xa2buffer
.PlayLength
= buf
->xa2buffer
.PlayLength
/ ((ADPCMWAVEFORMAT
*)This
->fmt
)->wSamplesPerBlock
* This
->fmt
->nBlockAlign
;
531 buf
->xa2buffer
.LoopBegin
= buf
->xa2buffer
.LoopBegin
/ ((ADPCMWAVEFORMAT
*)This
->fmt
)->wSamplesPerBlock
* This
->fmt
->nBlockAlign
;
532 buf
->xa2buffer
.LoopLength
= buf
->xa2buffer
.LoopLength
/ ((ADPCMWAVEFORMAT
*)This
->fmt
)->wSamplesPerBlock
* This
->fmt
->nBlockAlign
;
534 buf
->xa2buffer
.PlayBegin
*= This
->fmt
->nBlockAlign
;
535 buf
->xa2buffer
.PlayLength
*= This
->fmt
->nBlockAlign
;
536 buf
->xa2buffer
.LoopBegin
*= This
->fmt
->nBlockAlign
;
537 buf
->xa2buffer
.LoopLength
*= This
->fmt
->nBlockAlign
;
540 if(buf
->xa2buffer
.PlayLength
== 0)
541 /* set to end of buffer */
542 buf
->xa2buffer
.PlayLength
= buf
->xa2buffer
.AudioBytes
- buf
->xa2buffer
.PlayBegin
;
544 buf
->play_end_bytes
= buf
->xa2buffer
.PlayBegin
+ buf
->xa2buffer
.PlayLength
;
546 if(buf
->xa2buffer
.LoopCount
){
547 if(buf
->xa2buffer
.LoopLength
== 0)
548 /* set to end of play range */
549 buf
->xa2buffer
.LoopLength
= buf
->play_end_bytes
- buf
->xa2buffer
.LoopBegin
;
551 if(buf
->xa2buffer
.LoopBegin
>= buf
->play_end_bytes
){
552 /* this actually crashes on native xaudio 2.7 */
553 LeaveCriticalSection(&This
->lock
);
554 return COMPAT_E_INVALID_CALL(This
->xa2
->version
);
557 buf
->loop_end_bytes
= buf
->xa2buffer
.LoopBegin
+ buf
->xa2buffer
.LoopLength
;
559 /* xaudio 2.7 allows some invalid looping setups, but later versions
561 if(This
->xa2
->version
> 27){
562 if(buf
->loop_end_bytes
> buf
->play_end_bytes
){
563 LeaveCriticalSection(&This
->lock
);
564 return COMPAT_E_INVALID_CALL(This
->xa2
->version
);
567 if(buf
->loop_end_bytes
<= buf
->xa2buffer
.PlayBegin
){
568 LeaveCriticalSection(&This
->lock
);
569 return COMPAT_E_INVALID_CALL(This
->xa2
->version
);
572 if(buf
->loop_end_bytes
<= buf
->xa2buffer
.PlayBegin
){
573 buf
->xa2buffer
.LoopCount
= 0;
574 buf
->loop_end_bytes
= buf
->play_end_bytes
;
578 buf
->xa2buffer
.LoopLength
= buf
->xa2buffer
.PlayLength
;
579 buf
->xa2buffer
.LoopBegin
= buf
->xa2buffer
.PlayBegin
;
580 buf
->loop_end_bytes
= buf
->play_end_bytes
;
583 buf
->offs_bytes
= buf
->xa2buffer
.PlayBegin
;
584 buf
->cur_end_bytes
= buf
->loop_end_bytes
;
586 buf
->latest_al_buf
= -1;
590 TRACE("%p: queued buffer %u (%u bytes), now %u buffers held\n",
591 This
, buf_idx
, buf
->xa2buffer
.AudioBytes
, This
->nbufs
);
593 LeaveCriticalSection(&This
->lock
);
598 static HRESULT WINAPI
XA2SRC_FlushSourceBuffers(IXAudio2SourceVoice
*iface
)
600 UINT i
, first
, last
, to_flush
;
601 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
605 EnterCriticalSection(&This
->lock
);
607 if(This
->running
&& This
->nbufs
> 0){
608 /* when running, flush only completely unused buffers; the rest remain
610 last
= (This
->first_buf
+ This
->nbufs
) % XAUDIO2_MAX_QUEUED_BUFFERS
;
611 first
= (This
->cur_buf
+ 1) % XAUDIO2_MAX_QUEUED_BUFFERS
;
612 if(This
->cur_buf
== last
)
615 else if(last
>= first
)
616 to_flush
= last
- first
;
618 to_flush
= last
+ XAUDIO2_MAX_QUEUED_BUFFERS
- first
;
620 /* when stopped, flush all buffers */
621 first
= This
->first_buf
;
622 last
= (This
->first_buf
+ This
->nbufs
) % XAUDIO2_MAX_QUEUED_BUFFERS
;
623 to_flush
= This
->nbufs
;
628 i
< (first
+ to_flush
) % XAUDIO2_MAX_QUEUED_BUFFERS
;
629 i
= (i
+ 1) % XAUDIO2_MAX_QUEUED_BUFFERS
){
631 IXAudio2VoiceCallback_OnBufferEnd(This
->cb
,
632 This
->buffers
[i
].xa2buffer
.pContext
);
635 This
->nbufs
-= to_flush
;
637 LeaveCriticalSection(&This
->lock
);
642 static HRESULT WINAPI
XA2SRC_Discontinuity(IXAudio2SourceVoice
*iface
)
644 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
648 EnterCriticalSection(&This
->lock
);
651 DWORD last
= (This
->first_buf
+ This
->nbufs
- 1) % XAUDIO2_MAX_QUEUED_BUFFERS
;
652 This
->buffers
[last
].xa2buffer
.Flags
|= XAUDIO2_END_OF_STREAM
;
655 LeaveCriticalSection(&This
->lock
);
660 static HRESULT WINAPI
XA2SRC_ExitLoop(IXAudio2SourceVoice
*iface
, UINT32 OperationSet
)
662 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
664 TRACE("%p, 0x%x\n", This
, OperationSet
);
666 EnterCriticalSection(&This
->lock
);
668 This
->buffers
[This
->cur_buf
].looped
= XAUDIO2_LOOP_INFINITE
;
670 LeaveCriticalSection(&This
->lock
);
675 static void WINAPI
XA2SRC_GetState(IXAudio2SourceVoice
*iface
,
676 XAUDIO2_VOICE_STATE
*pVoiceState
, UINT32 Flags
)
678 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
680 TRACE("%p, %p, 0x%x\n", This
, pVoiceState
, Flags
);
682 EnterCriticalSection(&This
->lock
);
684 if(!(Flags
& XAUDIO2_VOICE_NOSAMPLESPLAYED
))
685 pVoiceState
->SamplesPlayed
= This
->played_frames
;
687 pVoiceState
->SamplesPlayed
= 0;
690 pVoiceState
->pCurrentBufferContext
= This
->buffers
[This
->first_buf
].xa2buffer
.pContext
;
692 pVoiceState
->pCurrentBufferContext
= NULL
;
694 pVoiceState
->BuffersQueued
= This
->nbufs
;
696 LeaveCriticalSection(&This
->lock
);
698 TRACE("returning %s, queued: %u\n", wine_dbgstr_longlong(pVoiceState
->SamplesPlayed
), This
->nbufs
);
701 static HRESULT WINAPI
XA2SRC_SetFrequencyRatio(IXAudio2SourceVoice
*iface
,
702 float Ratio
, UINT32 OperationSet
)
704 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
707 TRACE("%p, %f, 0x%x\n", This
, Ratio
, OperationSet
);
709 if(Ratio
< XAUDIO2_MIN_FREQ_RATIO
)
710 r
= XAUDIO2_MIN_FREQ_RATIO
;
711 else if (Ratio
> XAUDIO2_MAX_FREQ_RATIO
)
712 r
= XAUDIO2_MAX_FREQ_RATIO
;
716 alSourcef(This
->al_src
, AL_PITCH
, r
);
721 static void WINAPI
XA2SRC_GetFrequencyRatio(IXAudio2SourceVoice
*iface
, float *pRatio
)
724 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
726 TRACE("%p, %p\n", This
, pRatio
);
728 alGetSourcef(This
->al_src
, AL_PITCH
, &ratio
);
733 static HRESULT WINAPI
XA2SRC_SetSourceSampleRate(
734 IXAudio2SourceVoice
*iface
,
735 UINT32 NewSourceSampleRate
)
737 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
739 TRACE("%p, %u\n", This
, NewSourceSampleRate
);
741 EnterCriticalSection(&This
->lock
);
744 LeaveCriticalSection(&This
->lock
);
745 return COMPAT_E_INVALID_CALL(This
->xa2
->version
);
748 This
->fmt
->nSamplesPerSec
= NewSourceSampleRate
;
750 LeaveCriticalSection(&This
->lock
);
755 static const IXAudio2SourceVoiceVtbl XAudio2SourceVoice_Vtbl
= {
756 XA2SRC_GetVoiceDetails
,
757 XA2SRC_SetOutputVoices
,
758 XA2SRC_SetEffectChain
,
760 XA2SRC_DisableEffect
,
761 XA2SRC_GetEffectState
,
762 XA2SRC_SetEffectParameters
,
763 XA2SRC_GetEffectParameters
,
764 XA2SRC_SetFilterParameters
,
765 XA2SRC_GetFilterParameters
,
766 XA2SRC_SetOutputFilterParameters
,
767 XA2SRC_GetOutputFilterParameters
,
770 XA2SRC_SetChannelVolumes
,
771 XA2SRC_GetChannelVolumes
,
772 XA2SRC_SetOutputMatrix
,
773 XA2SRC_GetOutputMatrix
,
777 XA2SRC_SubmitSourceBuffer
,
778 XA2SRC_FlushSourceBuffers
,
779 XA2SRC_Discontinuity
,
782 XA2SRC_SetFrequencyRatio
,
783 XA2SRC_GetFrequencyRatio
,
784 XA2SRC_SetSourceSampleRate
787 static void WINAPI
XA2M_GetVoiceDetails(IXAudio2MasteringVoice
*iface
,
788 XAUDIO2_VOICE_DETAILS
*pVoiceDetails
)
790 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
791 TRACE("%p, %p\n", This
, pVoiceDetails
);
792 pVoiceDetails
->CreationFlags
= 0;
793 pVoiceDetails
->InputChannels
= This
->fmt
.Format
.nChannels
;
794 pVoiceDetails
->InputSampleRate
= This
->fmt
.Format
.nSamplesPerSec
;
797 static HRESULT WINAPI
XA2M_SetOutputVoices(IXAudio2MasteringVoice
*iface
,
798 const XAUDIO2_VOICE_SENDS
*pSendList
)
800 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
801 TRACE("%p, %p\n", This
, pSendList
);
805 static HRESULT WINAPI
XA2M_SetEffectChain(IXAudio2MasteringVoice
*iface
,
806 const XAUDIO2_EFFECT_CHAIN
*pEffectChain
)
808 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
809 TRACE("%p, %p\n", This
, pEffectChain
);
813 static HRESULT WINAPI
XA2M_EnableEffect(IXAudio2MasteringVoice
*iface
, UINT32 EffectIndex
,
816 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
817 TRACE("%p, %u, 0x%x\n", This
, EffectIndex
, OperationSet
);
821 static HRESULT WINAPI
XA2M_DisableEffect(IXAudio2MasteringVoice
*iface
, UINT32 EffectIndex
,
824 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
825 TRACE("%p, %u, 0x%x\n", This
, EffectIndex
, OperationSet
);
829 static void WINAPI
XA2M_GetEffectState(IXAudio2MasteringVoice
*iface
, UINT32 EffectIndex
,
832 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
833 TRACE("%p, %u, %p\n", This
, EffectIndex
, pEnabled
);
836 static HRESULT WINAPI
XA2M_SetEffectParameters(IXAudio2MasteringVoice
*iface
,
837 UINT32 EffectIndex
, const void *pParameters
, UINT32 ParametersByteSize
,
840 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
841 TRACE("%p, %u, %p, 0x%x, 0x%x\n", This
, EffectIndex
, pParameters
,
842 ParametersByteSize
, OperationSet
);
846 static HRESULT WINAPI
XA2M_GetEffectParameters(IXAudio2MasteringVoice
*iface
,
847 UINT32 EffectIndex
, void *pParameters
, UINT32 ParametersByteSize
)
849 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
850 TRACE("%p, %u, %p, 0x%x\n", This
, EffectIndex
, pParameters
,
855 static HRESULT WINAPI
XA2M_SetFilterParameters(IXAudio2MasteringVoice
*iface
,
856 const XAUDIO2_FILTER_PARAMETERS
*pParameters
, UINT32 OperationSet
)
858 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
859 TRACE("%p, %p, 0x%x\n", This
, pParameters
, OperationSet
);
863 static void WINAPI
XA2M_GetFilterParameters(IXAudio2MasteringVoice
*iface
,
864 XAUDIO2_FILTER_PARAMETERS
*pParameters
)
866 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
867 TRACE("%p, %p\n", This
, pParameters
);
870 static HRESULT WINAPI
XA2M_SetOutputFilterParameters(IXAudio2MasteringVoice
*iface
,
871 IXAudio2Voice
*pDestinationVoice
,
872 const XAUDIO2_FILTER_PARAMETERS
*pParameters
, UINT32 OperationSet
)
874 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
875 TRACE("%p, %p, %p, 0x%x\n", This
, pDestinationVoice
, pParameters
, OperationSet
);
879 static void WINAPI
XA2M_GetOutputFilterParameters(IXAudio2MasteringVoice
*iface
,
880 IXAudio2Voice
*pDestinationVoice
,
881 XAUDIO2_FILTER_PARAMETERS
*pParameters
)
883 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
884 TRACE("%p, %p, %p\n", This
, pDestinationVoice
, pParameters
);
887 static HRESULT WINAPI
XA2M_SetVolume(IXAudio2MasteringVoice
*iface
, float Volume
,
890 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
891 TRACE("%p, %f, 0x%x\n", This
, Volume
, OperationSet
);
895 static void WINAPI
XA2M_GetVolume(IXAudio2MasteringVoice
*iface
, float *pVolume
)
897 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
898 TRACE("%p, %p\n", This
, pVolume
);
901 static HRESULT WINAPI
XA2M_SetChannelVolumes(IXAudio2MasteringVoice
*iface
, UINT32 Channels
,
902 const float *pVolumes
, UINT32 OperationSet
)
904 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
905 TRACE("%p, %u, %p, 0x%x\n", This
, Channels
, pVolumes
, OperationSet
);
909 static void WINAPI
XA2M_GetChannelVolumes(IXAudio2MasteringVoice
*iface
, UINT32 Channels
,
912 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
913 TRACE("%p, %u, %p\n", This
, Channels
, pVolumes
);
916 static HRESULT WINAPI
XA2M_SetOutputMatrix(IXAudio2MasteringVoice
*iface
,
917 IXAudio2Voice
*pDestinationVoice
, UINT32 SourceChannels
,
918 UINT32 DestinationChannels
, const float *pLevelMatrix
,
921 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
922 TRACE("%p, %p, %u, %u, %p, 0x%x\n", This
, pDestinationVoice
,
923 SourceChannels
, DestinationChannels
, pLevelMatrix
, OperationSet
);
927 static void WINAPI
XA2M_GetOutputMatrix(IXAudio2MasteringVoice
*iface
,
928 IXAudio2Voice
*pDestinationVoice
, UINT32 SourceChannels
,
929 UINT32 DestinationChannels
, float *pLevelMatrix
)
931 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
932 TRACE("%p, %p, %u, %u, %p\n", This
, pDestinationVoice
,
933 SourceChannels
, DestinationChannels
, pLevelMatrix
);
936 static void WINAPI
XA2M_DestroyVoice(IXAudio2MasteringVoice
*iface
)
938 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
942 EnterCriticalSection(&This
->lock
);
945 LeaveCriticalSection(&This
->lock
);
949 This
->running
= FALSE
;
951 IAudioRenderClient_Release(This
->render
);
954 IAudioClient_Release(This
->aclient
);
955 This
->aclient
= NULL
;
957 alcCloseDevice(This
->al_device
);
958 This
->al_device
= NULL
;
960 alcDestroyContext(This
->al_ctx
);
963 LeaveCriticalSection(&This
->lock
);
966 /* not present in XAudio2 2.7 */
967 static void WINAPI
XA2M_GetChannelMask(IXAudio2MasteringVoice
*iface
,
970 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
972 TRACE("%p %p\n", This
, pChannelMask
);
974 *pChannelMask
= This
->fmt
.dwChannelMask
;
977 static const struct IXAudio2MasteringVoiceVtbl XAudio2MasteringVoice_Vtbl
= {
978 XA2M_GetVoiceDetails
,
979 XA2M_SetOutputVoices
,
984 XA2M_SetEffectParameters
,
985 XA2M_GetEffectParameters
,
986 XA2M_SetFilterParameters
,
987 XA2M_GetFilterParameters
,
988 XA2M_SetOutputFilterParameters
,
989 XA2M_GetOutputFilterParameters
,
992 XA2M_SetChannelVolumes
,
993 XA2M_GetChannelVolumes
,
994 XA2M_SetOutputMatrix
,
995 XA2M_GetOutputMatrix
,
1000 static void WINAPI
XA2SUB_GetVoiceDetails(IXAudio2SubmixVoice
*iface
,
1001 XAUDIO2_VOICE_DETAILS
*pVoiceDetails
)
1003 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1004 TRACE("%p, %p\n", This
, pVoiceDetails
);
1007 static HRESULT WINAPI
XA2SUB_SetOutputVoices(IXAudio2SubmixVoice
*iface
,
1008 const XAUDIO2_VOICE_SENDS
*pSendList
)
1010 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1011 TRACE("%p, %p\n", This
, pSendList
);
1015 static HRESULT WINAPI
XA2SUB_SetEffectChain(IXAudio2SubmixVoice
*iface
,
1016 const XAUDIO2_EFFECT_CHAIN
*pEffectChain
)
1018 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1019 TRACE("%p, %p\n", This
, pEffectChain
);
1023 static HRESULT WINAPI
XA2SUB_EnableEffect(IXAudio2SubmixVoice
*iface
, UINT32 EffectIndex
,
1024 UINT32 OperationSet
)
1026 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1027 TRACE("%p, %u, 0x%x\n", This
, EffectIndex
, OperationSet
);
1031 static HRESULT WINAPI
XA2SUB_DisableEffect(IXAudio2SubmixVoice
*iface
, UINT32 EffectIndex
,
1032 UINT32 OperationSet
)
1034 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1035 TRACE("%p, %u, 0x%x\n", This
, EffectIndex
, OperationSet
);
1039 static void WINAPI
XA2SUB_GetEffectState(IXAudio2SubmixVoice
*iface
, UINT32 EffectIndex
,
1042 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1043 TRACE("%p, %u, %p\n", This
, EffectIndex
, pEnabled
);
1046 static HRESULT WINAPI
XA2SUB_SetEffectParameters(IXAudio2SubmixVoice
*iface
,
1047 UINT32 EffectIndex
, const void *pParameters
, UINT32 ParametersByteSize
,
1048 UINT32 OperationSet
)
1050 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1051 TRACE("%p, %u, %p, 0x%x, 0x%x\n", This
, EffectIndex
, pParameters
,
1052 ParametersByteSize
, OperationSet
);
1056 static HRESULT WINAPI
XA2SUB_GetEffectParameters(IXAudio2SubmixVoice
*iface
,
1057 UINT32 EffectIndex
, void *pParameters
, UINT32 ParametersByteSize
)
1059 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1060 TRACE("%p, %u, %p, 0x%x\n", This
, EffectIndex
, pParameters
,
1061 ParametersByteSize
);
1065 static HRESULT WINAPI
XA2SUB_SetFilterParameters(IXAudio2SubmixVoice
*iface
,
1066 const XAUDIO2_FILTER_PARAMETERS
*pParameters
, UINT32 OperationSet
)
1068 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1069 TRACE("%p, %p, 0x%x\n", This
, pParameters
, OperationSet
);
1073 static void WINAPI
XA2SUB_GetFilterParameters(IXAudio2SubmixVoice
*iface
,
1074 XAUDIO2_FILTER_PARAMETERS
*pParameters
)
1076 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1077 TRACE("%p, %p\n", This
, pParameters
);
1080 static HRESULT WINAPI
XA2SUB_SetOutputFilterParameters(IXAudio2SubmixVoice
*iface
,
1081 IXAudio2Voice
*pDestinationVoice
,
1082 const XAUDIO2_FILTER_PARAMETERS
*pParameters
, UINT32 OperationSet
)
1084 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1085 TRACE("%p, %p, %p, 0x%x\n", This
, pDestinationVoice
, pParameters
, OperationSet
);
1089 static void WINAPI
XA2SUB_GetOutputFilterParameters(IXAudio2SubmixVoice
*iface
,
1090 IXAudio2Voice
*pDestinationVoice
,
1091 XAUDIO2_FILTER_PARAMETERS
*pParameters
)
1093 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1094 TRACE("%p, %p, %p\n", This
, pDestinationVoice
, pParameters
);
1097 static HRESULT WINAPI
XA2SUB_SetVolume(IXAudio2SubmixVoice
*iface
, float Volume
,
1098 UINT32 OperationSet
)
1100 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1101 TRACE("%p, %f, 0x%x\n", This
, Volume
, OperationSet
);
1105 static void WINAPI
XA2SUB_GetVolume(IXAudio2SubmixVoice
*iface
, float *pVolume
)
1107 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1108 TRACE("%p, %p\n", This
, pVolume
);
1111 static HRESULT WINAPI
XA2SUB_SetChannelVolumes(IXAudio2SubmixVoice
*iface
, UINT32 Channels
,
1112 const float *pVolumes
, UINT32 OperationSet
)
1114 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1115 TRACE("%p, %u, %p, 0x%x\n", This
, Channels
, pVolumes
, OperationSet
);
1119 static void WINAPI
XA2SUB_GetChannelVolumes(IXAudio2SubmixVoice
*iface
, UINT32 Channels
,
1122 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1123 TRACE("%p, %u, %p\n", This
, Channels
, pVolumes
);
1126 static HRESULT WINAPI
XA2SUB_SetOutputMatrix(IXAudio2SubmixVoice
*iface
,
1127 IXAudio2Voice
*pDestinationVoice
, UINT32 SourceChannels
,
1128 UINT32 DestinationChannels
, const float *pLevelMatrix
,
1129 UINT32 OperationSet
)
1131 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1132 TRACE("%p, %p, %u, %u, %p, 0x%x\n", This
, pDestinationVoice
,
1133 SourceChannels
, DestinationChannels
, pLevelMatrix
, OperationSet
);
1137 static void WINAPI
XA2SUB_GetOutputMatrix(IXAudio2SubmixVoice
*iface
,
1138 IXAudio2Voice
*pDestinationVoice
, UINT32 SourceChannels
,
1139 UINT32 DestinationChannels
, float *pLevelMatrix
)
1141 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1142 TRACE("%p, %p, %u, %u, %p\n", This
, pDestinationVoice
,
1143 SourceChannels
, DestinationChannels
, pLevelMatrix
);
1146 static void WINAPI
XA2SUB_DestroyVoice(IXAudio2SubmixVoice
*iface
)
1148 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1150 TRACE("%p\n", This
);
1152 EnterCriticalSection(&This
->lock
);
1154 This
->in_use
= FALSE
;
1156 LeaveCriticalSection(&This
->lock
);
1159 static const struct IXAudio2SubmixVoiceVtbl XAudio2SubmixVoice_Vtbl
= {
1160 XA2SUB_GetVoiceDetails
,
1161 XA2SUB_SetOutputVoices
,
1162 XA2SUB_SetEffectChain
,
1163 XA2SUB_EnableEffect
,
1164 XA2SUB_DisableEffect
,
1165 XA2SUB_GetEffectState
,
1166 XA2SUB_SetEffectParameters
,
1167 XA2SUB_GetEffectParameters
,
1168 XA2SUB_SetFilterParameters
,
1169 XA2SUB_GetFilterParameters
,
1170 XA2SUB_SetOutputFilterParameters
,
1171 XA2SUB_GetOutputFilterParameters
,
1174 XA2SUB_SetChannelVolumes
,
1175 XA2SUB_GetChannelVolumes
,
1176 XA2SUB_SetOutputMatrix
,
1177 XA2SUB_GetOutputMatrix
,
1181 static HRESULT WINAPI
IXAudio2Impl_QueryInterface(IXAudio2
*iface
, REFIID riid
,
1184 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1186 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), ppvObject
);
1188 if(IsEqualGUID(riid
, &IID_IUnknown
) ||
1189 IsEqualGUID(riid
, &IID_IXAudio2
))
1190 *ppvObject
= &This
->IXAudio2_iface
;
1191 else if(IsEqualGUID(riid
, &IID_IXAudio27
)){
1192 /* all xaudio versions before 28 share an IID */
1193 if(This
->version
== 20)
1194 *ppvObject
= &This
->IXAudio20_iface
;
1195 else if(This
->version
== 21 || This
->version
== 22)
1196 *ppvObject
= &This
->IXAudio22_iface
;
1198 *ppvObject
= &This
->IXAudio27_iface
;
1203 IUnknown_AddRef((IUnknown
*)*ppvObject
);
1207 FIXME("(%p)->(%s,%p), not found\n", This
,debugstr_guid(riid
), ppvObject
);
1209 return E_NOINTERFACE
;
1212 static ULONG WINAPI
IXAudio2Impl_AddRef(IXAudio2
*iface
)
1214 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1215 ULONG ref
= InterlockedIncrement(&This
->ref
);
1216 TRACE("(%p)->(): Refcount now %u\n", This
, ref
);
1220 static ULONG WINAPI
IXAudio2Impl_Release(IXAudio2
*iface
)
1222 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1223 ULONG ref
= InterlockedDecrement(&This
->ref
);
1225 TRACE("(%p)->(): Refcount now %u\n", This
, ref
);
1229 XA2SourceImpl
*src
, *src2
;
1230 XA2SubmixImpl
*sub
, *sub2
;
1233 This
->stop_engine
= TRUE
;
1234 SetEvent(This
->mmevt
);
1235 WaitForSingleObject(This
->engine
, INFINITE
);
1236 CloseHandle(This
->engine
);
1239 LIST_FOR_EACH_ENTRY_SAFE(src
, src2
, &This
->source_voices
, XA2SourceImpl
, entry
){
1240 HeapFree(GetProcessHeap(), 0, src
->sends
);
1241 IXAudio2SourceVoice_DestroyVoice(&src
->IXAudio2SourceVoice_iface
);
1242 DeleteCriticalSection(&src
->lock
);
1243 HeapFree(GetProcessHeap(), 0, src
);
1246 LIST_FOR_EACH_ENTRY_SAFE(sub
, sub2
, &This
->submix_voices
, XA2SubmixImpl
, entry
){
1247 IXAudio2SubmixVoice_DestroyVoice(&sub
->IXAudio2SubmixVoice_iface
);
1248 DeleteCriticalSection(&sub
->lock
);
1249 HeapFree(GetProcessHeap(), 0, sub
);
1252 IXAudio2MasteringVoice_DestroyVoice(&This
->IXAudio2MasteringVoice_iface
);
1255 IMMDeviceEnumerator_Release(This
->devenum
);
1256 for(i
= 0; i
< This
->ndevs
; ++i
)
1257 CoTaskMemFree(This
->devids
[i
]);
1258 HeapFree(GetProcessHeap(), 0, This
->devids
);
1259 HeapFree(GetProcessHeap(), 0, This
->cbs
);
1261 CloseHandle(This
->mmevt
);
1263 DeleteCriticalSection(&This
->lock
);
1265 HeapFree(GetProcessHeap(), 0, This
);
1270 static HRESULT WINAPI
IXAudio2Impl_RegisterForCallbacks(IXAudio2
*iface
,
1271 IXAudio2EngineCallback
*pCallback
)
1273 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1276 TRACE("(%p)->(%p)\n", This
, pCallback
);
1278 EnterCriticalSection(&This
->lock
);
1280 for(i
= 0; i
< This
->ncbs
; ++i
){
1281 if(!This
->cbs
[i
] || This
->cbs
[i
] == pCallback
){
1282 This
->cbs
[i
] = pCallback
;
1283 LeaveCriticalSection(&This
->lock
);
1289 This
->cbs
= HeapReAlloc(GetProcessHeap(), 0, This
->cbs
, This
->ncbs
* sizeof(*This
->cbs
));
1291 This
->cbs
[i
] = pCallback
;
1293 LeaveCriticalSection(&This
->lock
);
1298 static void WINAPI
IXAudio2Impl_UnregisterForCallbacks(IXAudio2
*iface
,
1299 IXAudio2EngineCallback
*pCallback
)
1301 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1304 TRACE("(%p)->(%p)\n", This
, pCallback
);
1306 EnterCriticalSection(&This
->lock
);
1308 for(i
= 0; i
< This
->ncbs
; ++i
){
1309 if(This
->cbs
[i
] == pCallback
)
1313 for(; i
< This
->ncbs
- 1 && This
->cbs
[i
+ 1]; ++i
)
1314 This
->cbs
[i
] = This
->cbs
[i
+ 1];
1317 This
->cbs
[i
] = NULL
;
1319 LeaveCriticalSection(&This
->lock
);
1322 static WAVEFORMATEX
*copy_waveformat(const WAVEFORMATEX
*wfex
)
1326 if(wfex
->wFormatTag
== WAVE_FORMAT_PCM
){
1327 pwfx
= HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEX
));
1328 CopyMemory(pwfx
, wfex
, sizeof(PCMWAVEFORMAT
));
1331 pwfx
= HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEX
) + wfex
->cbSize
);
1332 CopyMemory(pwfx
, wfex
, sizeof(WAVEFORMATEX
) + wfex
->cbSize
);
1338 static HRESULT WINAPI
IXAudio2Impl_CreateSourceVoice(IXAudio2
*iface
,
1339 IXAudio2SourceVoice
**ppSourceVoice
, const WAVEFORMATEX
*pSourceFormat
,
1340 UINT32 flags
, float maxFrequencyRatio
,
1341 IXAudio2VoiceCallback
*pCallback
, const XAUDIO2_VOICE_SENDS
*pSendList
,
1342 const XAUDIO2_EFFECT_CHAIN
*pEffectChain
)
1344 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1348 TRACE("(%p)->(%p, %p, 0x%x, %f, %p, %p, %p)\n", This
, ppSourceVoice
,
1349 pSourceFormat
, flags
, maxFrequencyRatio
, pCallback
, pSendList
,
1352 dump_fmt(pSourceFormat
);
1354 EnterCriticalSection(&This
->lock
);
1356 LIST_FOR_EACH_ENTRY(src
, &This
->source_voices
, XA2SourceImpl
, entry
){
1361 if(&src
->entry
== &This
->source_voices
){
1362 src
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*src
));
1364 LeaveCriticalSection(&This
->lock
);
1365 return E_OUTOFMEMORY
;
1368 list_add_head(&This
->source_voices
, &src
->entry
);
1370 src
->IXAudio20SourceVoice_iface
.lpVtbl
= &XAudio20SourceVoice_Vtbl
;
1371 src
->IXAudio23SourceVoice_iface
.lpVtbl
= &XAudio23SourceVoice_Vtbl
;
1372 src
->IXAudio27SourceVoice_iface
.lpVtbl
= &XAudio27SourceVoice_Vtbl
;
1373 src
->IXAudio2SourceVoice_iface
.lpVtbl
= &XAudio2SourceVoice_Vtbl
;
1375 InitializeCriticalSection(&src
->lock
);
1376 src
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": XA2SourceImpl.lock");
1382 src
->running
= FALSE
;
1384 LeaveCriticalSection(&This
->lock
);
1386 src
->cb
= pCallback
;
1388 src
->al_fmt
= get_al_format(pSourceFormat
);
1390 src
->in_use
= FALSE
;
1391 WARN("OpenAL can't convert this format!\n");
1392 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
1395 src
->submit_blocksize
= pSourceFormat
->nBlockAlign
;
1397 src
->fmt
= copy_waveformat(pSourceFormat
);
1399 hr
= XA2SRC_SetOutputVoices(&src
->IXAudio2SourceVoice_iface
, pSendList
);
1401 src
->in_use
= FALSE
;
1405 alGenSources(1, &src
->al_src
);
1406 alGenBuffers(XAUDIO2_MAX_QUEUED_BUFFERS
, src
->al_bufs
);
1408 alSourcePlay(src
->al_src
);
1410 if(This
->version
== 20)
1411 *ppSourceVoice
= (IXAudio2SourceVoice
*)&src
->IXAudio20SourceVoice_iface
;
1412 else if(This
->version
<= 23)
1413 *ppSourceVoice
= (IXAudio2SourceVoice
*)&src
->IXAudio23SourceVoice_iface
;
1414 else if(This
->version
<= 27)
1415 *ppSourceVoice
= (IXAudio2SourceVoice
*)&src
->IXAudio27SourceVoice_iface
;
1417 *ppSourceVoice
= &src
->IXAudio2SourceVoice_iface
;
1419 TRACE("Created source voice: %p\n", src
);
1424 static HRESULT WINAPI
IXAudio2Impl_CreateSubmixVoice(IXAudio2
*iface
,
1425 IXAudio2SubmixVoice
**ppSubmixVoice
, UINT32 inputChannels
,
1426 UINT32 inputSampleRate
, UINT32 flags
, UINT32 processingStage
,
1427 const XAUDIO2_VOICE_SENDS
*pSendList
,
1428 const XAUDIO2_EFFECT_CHAIN
*pEffectChain
)
1430 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1433 TRACE("(%p)->(%p, %u, %u, 0x%x, %u, %p, %p)\n", This
, ppSubmixVoice
,
1434 inputChannels
, inputSampleRate
, flags
, processingStage
, pSendList
,
1437 EnterCriticalSection(&This
->lock
);
1439 LIST_FOR_EACH_ENTRY(sub
, &This
->submix_voices
, XA2SubmixImpl
, entry
){
1444 if(&sub
->entry
== &This
->submix_voices
){
1445 sub
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*sub
));
1447 LeaveCriticalSection(&This
->lock
);
1448 return E_OUTOFMEMORY
;
1451 list_add_head(&This
->submix_voices
, &sub
->entry
);
1453 sub
->IXAudio20SubmixVoice_iface
.lpVtbl
= &XAudio20SubmixVoice_Vtbl
;
1454 sub
->IXAudio23SubmixVoice_iface
.lpVtbl
= &XAudio23SubmixVoice_Vtbl
;
1455 sub
->IXAudio2SubmixVoice_iface
.lpVtbl
= &XAudio2SubmixVoice_Vtbl
;
1457 InitializeCriticalSection(&sub
->lock
);
1458 sub
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": XA2SubmixImpl.lock");
1463 LeaveCriticalSection(&This
->lock
);
1465 if(This
->version
== 20)
1466 *ppSubmixVoice
= (IXAudio2SubmixVoice
*)&sub
->IXAudio20SubmixVoice_iface
;
1467 else if(This
->version
<= 23)
1468 *ppSubmixVoice
= (IXAudio2SubmixVoice
*)&sub
->IXAudio23SubmixVoice_iface
;
1470 *ppSubmixVoice
= &sub
->IXAudio2SubmixVoice_iface
;
1472 TRACE("Created submix voice: %p\n", sub
);
1477 static ALenum
al_get_loopback_format(const WAVEFORMATEXTENSIBLE
*fmt
)
1479 if(fmt
->Format
.wFormatTag
== WAVE_FORMAT_PCM
||
1480 (fmt
->Format
.wFormatTag
== WAVE_FORMAT_EXTENSIBLE
&&
1481 IsEqualGUID(&fmt
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
))){
1482 switch(fmt
->Format
.wBitsPerSample
){
1484 return ALC_UNSIGNED_BYTE_SOFT
;
1486 return ALC_SHORT_SOFT
;
1488 return ALC_INT_SOFT
;
1490 }else if(fmt
->Format
.wFormatTag
== WAVE_FORMAT_IEEE_FLOAT
||
1491 (fmt
->Format
.wFormatTag
== WAVE_FORMAT_EXTENSIBLE
&&
1492 IsEqualGUID(&fmt
->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
))){
1493 if(fmt
->Format
.wBitsPerSample
== 32)
1494 return ALC_FLOAT_SOFT
;
1499 static HRESULT WINAPI
IXAudio2Impl_CreateMasteringVoice(IXAudio2
*iface
,
1500 IXAudio2MasteringVoice
**ppMasteringVoice
, UINT32 inputChannels
,
1501 UINT32 inputSampleRate
, UINT32 flags
, const WCHAR
*deviceId
,
1502 const XAUDIO2_EFFECT_CHAIN
*pEffectChain
,
1503 AUDIO_STREAM_CATEGORY streamCategory
)
1505 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1510 REFERENCE_TIME period
, bufdur
;
1512 TRACE("(%p)->(%p, %u, %u, 0x%x, %s, %p, 0x%x)\n", This
,
1513 ppMasteringVoice
, inputChannels
, inputSampleRate
, flags
,
1514 wine_dbgstr_w(deviceId
), pEffectChain
, streamCategory
);
1517 WARN("Unknown flags set: 0x%x\n", flags
);
1520 WARN("Effect chain is unimplemented\n");
1522 EnterCriticalSection(&This
->lock
);
1524 /* there can only be one Mastering Voice, so just build it into XA2 */
1526 LeaveCriticalSection(&This
->lock
);
1527 return COMPAT_E_INVALID_CALL(This
->version
);
1531 if(This
->ndevs
== 0){
1532 LeaveCriticalSection(&This
->lock
);
1533 return ERROR_NOT_FOUND
;
1535 deviceId
= This
->devids
[0];
1538 hr
= IMMDeviceEnumerator_GetDevice(This
->devenum
, deviceId
, &dev
);
1540 WARN("GetDevice failed: %08x\n", hr
);
1541 hr
= COMPAT_E_DEVICE_INVALIDATED(This
->version
);
1545 hr
= IMMDevice_Activate(dev
, &IID_IAudioClient
,
1546 CLSCTX_INPROC_SERVER
, NULL
, (void**)&This
->aclient
);
1548 WARN("Activate(IAudioClient) failed: %08x\n", hr
);
1549 IMMDevice_Release(dev
);
1550 hr
= COMPAT_E_DEVICE_INVALIDATED(This
->version
);
1554 IMMDevice_Release(dev
);
1556 hr
= IAudioClient_GetMixFormat(This
->aclient
, &fmt
);
1558 WARN("GetMixFormat failed: %08x\n", hr
);
1559 hr
= COMPAT_E_DEVICE_INVALIDATED(This
->version
);
1563 if(sizeof(WAVEFORMATEX
) + fmt
->cbSize
> sizeof(WAVEFORMATEXTENSIBLE
)){
1564 FIXME("Mix format doesn't fit into WAVEFORMATEXTENSIBLE!\n");
1565 hr
= COMPAT_E_DEVICE_INVALIDATED(This
->version
);
1569 if(inputChannels
== XAUDIO2_DEFAULT_CHANNELS
)
1570 inputChannels
= fmt
->nChannels
;
1571 if(inputSampleRate
== XAUDIO2_DEFAULT_SAMPLERATE
)
1572 inputSampleRate
= fmt
->nSamplesPerSec
;
1574 memcpy(&This
->fmt
, fmt
, sizeof(WAVEFORMATEX
) + fmt
->cbSize
);
1575 This
->fmt
.Format
.nChannels
= inputChannels
;
1576 This
->fmt
.Format
.nSamplesPerSec
= inputSampleRate
;
1577 This
->fmt
.Format
.nBlockAlign
= This
->fmt
.Format
.nChannels
* This
->fmt
.Format
.wBitsPerSample
/ 8;
1578 This
->fmt
.Format
.nAvgBytesPerSec
= This
->fmt
.Format
.nSamplesPerSec
* This
->fmt
.Format
.nBlockAlign
;
1579 This
->fmt
.dwChannelMask
= get_channel_mask(This
->fmt
.Format
.nChannels
);
1584 hr
= IAudioClient_IsFormatSupported(This
->aclient
,
1585 AUDCLNT_SHAREMODE_SHARED
, &This
->fmt
.Format
, &fmt
);
1587 if(sizeof(WAVEFORMATEX
) + fmt
->cbSize
> sizeof(WAVEFORMATEXTENSIBLE
)){
1588 FIXME("Mix format doesn't fit into WAVEFORMATEXTENSIBLE!\n");
1589 hr
= COMPAT_E_DEVICE_INVALIDATED(This
->version
);
1592 memcpy(&This
->fmt
, fmt
, sizeof(WAVEFORMATEX
) + fmt
->cbSize
);
1597 hr
= IAudioClient_GetDevicePeriod(This
->aclient
, &period
, NULL
);
1599 WARN("GetDevicePeriod failed: %08x\n", hr
);
1600 hr
= COMPAT_E_DEVICE_INVALIDATED(This
->version
);
1604 /* 3 periods or 0.1 seconds */
1605 bufdur
= max(3 * period
, 1000000);
1607 hr
= IAudioClient_Initialize(This
->aclient
, AUDCLNT_SHAREMODE_SHARED
,
1608 AUDCLNT_STREAMFLAGS_EVENTCALLBACK
, bufdur
,
1609 0, &This
->fmt
.Format
, NULL
);
1611 WARN("Initialize failed: %08x\n", hr
);
1612 hr
= COMPAT_E_DEVICE_INVALIDATED(This
->version
);
1616 This
->period_frames
= MulDiv(period
, inputSampleRate
, 10000000);
1618 hr
= IAudioClient_SetEventHandle(This
->aclient
, This
->mmevt
);
1620 WARN("Initialize failed: %08x\n", hr
);
1621 hr
= COMPAT_E_DEVICE_INVALIDATED(This
->version
);
1625 hr
= IAudioClient_GetService(This
->aclient
, &IID_IAudioRenderClient
,
1626 (void**)&This
->render
);
1628 WARN("GetService(IAudioRenderClient) failed: %08x\n", hr
);
1629 hr
= COMPAT_E_DEVICE_INVALIDATED(This
->version
);
1633 /* setup openal context */
1634 attrs
[0] = ALC_FORMAT_CHANNELS_SOFT
;
1635 switch(inputChannels
){
1637 attrs
[1] = ALC_MONO_SOFT
;
1640 attrs
[1] = ALC_STEREO_SOFT
;
1643 attrs
[1] = ALC_QUAD_SOFT
;
1646 attrs
[1] = ALC_5POINT1_SOFT
;
1649 attrs
[1] = ALC_6POINT1_SOFT
;
1652 attrs
[1] = ALC_7POINT1_SOFT
;
1655 WARN("OpenAL doesn't support %u channels\n", inputChannels
);
1656 LeaveCriticalSection(&This
->lock
);
1657 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
1659 attrs
[2] = ALC_FREQUENCY
;
1660 attrs
[3] = inputSampleRate
;
1661 attrs
[4] = ALC_FORMAT_TYPE_SOFT
;
1662 attrs
[5] = al_get_loopback_format(&This
->fmt
);
1666 WARN("OpenAL can't output samples in this format\n");
1667 hr
= COMPAT_E_DEVICE_INVALIDATED(This
->version
);
1671 This
->al_device
= palcLoopbackOpenDeviceSOFT(NULL
);
1672 if(!This
->al_device
){
1673 WARN("alcLoopbackOpenDeviceSOFT failed\n");
1674 hr
= COMPAT_E_DEVICE_INVALIDATED(This
->version
);
1678 This
->al_ctx
= alcCreateContext(This
->al_device
, attrs
);
1680 WARN("alcCreateContext failed\n");
1681 hr
= COMPAT_E_DEVICE_INVALIDATED(This
->version
);
1685 if(alcMakeContextCurrent(This
->al_ctx
) == ALC_FALSE
){
1686 WARN("alcMakeContextCurrent failed\n");
1687 hr
= COMPAT_E_DEVICE_INVALIDATED(This
->version
);
1691 IAudioClient_Start(This
->aclient
);
1693 if(This
->version
<= 20)
1694 *ppMasteringVoice
= (IXAudio2MasteringVoice
*)&This
->IXAudio20MasteringVoice_iface
;
1695 else if(This
->version
<= 23)
1696 *ppMasteringVoice
= (IXAudio2MasteringVoice
*)&This
->IXAudio23MasteringVoice_iface
;
1698 *ppMasteringVoice
= &This
->IXAudio2MasteringVoice_iface
;
1703 IAudioRenderClient_Release(This
->render
);
1704 This
->render
= NULL
;
1707 IAudioClient_Release(This
->aclient
);
1708 This
->aclient
= NULL
;
1711 alcDestroyContext(This
->al_ctx
);
1712 This
->al_ctx
= NULL
;
1714 if(This
->al_device
){
1715 alcCloseDevice(This
->al_device
);
1716 This
->al_device
= NULL
;
1720 LeaveCriticalSection(&This
->lock
);
1725 static DWORD WINAPI
engine_threadproc(void *arg
);
1727 static HRESULT WINAPI
IXAudio2Impl_StartEngine(IXAudio2
*iface
)
1729 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1731 TRACE("(%p)->()\n", This
);
1733 This
->running
= TRUE
;
1736 This
->engine
= CreateThread(NULL
, 0, engine_threadproc
, This
, 0, NULL
);
1741 static void WINAPI
IXAudio2Impl_StopEngine(IXAudio2
*iface
)
1743 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1745 TRACE("(%p)->()\n", This
);
1747 This
->running
= FALSE
;
1750 static HRESULT WINAPI
IXAudio2Impl_CommitChanges(IXAudio2
*iface
,
1751 UINT32 operationSet
)
1753 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1755 TRACE("(%p)->(0x%x): stub!\n", This
, operationSet
);
1760 static void WINAPI
IXAudio2Impl_GetPerformanceData(IXAudio2
*iface
,
1761 XAUDIO2_PERFORMANCE_DATA
*pPerfData
)
1763 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1765 TRACE("(%p)->(%p): stub!\n", This
, pPerfData
);
1767 memset(pPerfData
, 0, sizeof(*pPerfData
));
1770 static void WINAPI
IXAudio2Impl_SetDebugConfiguration(IXAudio2
*iface
,
1771 const XAUDIO2_DEBUG_CONFIGURATION
*pDebugConfiguration
,
1774 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1776 FIXME("(%p)->(%p, %p): stub!\n", This
, pDebugConfiguration
, pReserved
);
1780 static const IXAudio2Vtbl XAudio2_Vtbl
=
1782 IXAudio2Impl_QueryInterface
,
1783 IXAudio2Impl_AddRef
,
1784 IXAudio2Impl_Release
,
1785 IXAudio2Impl_RegisterForCallbacks
,
1786 IXAudio2Impl_UnregisterForCallbacks
,
1787 IXAudio2Impl_CreateSourceVoice
,
1788 IXAudio2Impl_CreateSubmixVoice
,
1789 IXAudio2Impl_CreateMasteringVoice
,
1790 IXAudio2Impl_StartEngine
,
1791 IXAudio2Impl_StopEngine
,
1792 IXAudio2Impl_CommitChanges
,
1793 IXAudio2Impl_GetPerformanceData
,
1794 IXAudio2Impl_SetDebugConfiguration
1797 typedef struct _VUMeterImpl
{
1799 IXAPOParameters IXAPOParameters_iface
;
1806 static VUMeterImpl
*VUMeterImpl_from_IXAPO(IXAPO
*iface
)
1808 return CONTAINING_RECORD(iface
, VUMeterImpl
, IXAPO_iface
);
1811 static VUMeterImpl
*VUMeterImpl_from_IXAPOParameters(IXAPOParameters
*iface
)
1813 return CONTAINING_RECORD(iface
, VUMeterImpl
, IXAPOParameters_iface
);
1816 static HRESULT WINAPI
VUMXAPO_QueryInterface(IXAPO
*iface
, REFIID riid
,
1819 VUMeterImpl
*This
= VUMeterImpl_from_IXAPO(iface
);
1821 TRACE("%p, %s, %p\n", This
, wine_dbgstr_guid(riid
), ppvObject
);
1823 if(IsEqualGUID(riid
, &IID_IUnknown
) ||
1824 IsEqualGUID(riid
, &IID_IXAPO
) ||
1825 IsEqualGUID(riid
, &IID_IXAPO27
))
1826 *ppvObject
= &This
->IXAPO_iface
;
1827 else if(IsEqualGUID(riid
, &IID_IXAPOParameters
))
1828 *ppvObject
= &This
->IXAPOParameters_iface
;
1833 IUnknown_AddRef((IUnknown
*)*ppvObject
);
1837 return E_NOINTERFACE
;
1840 static ULONG WINAPI
VUMXAPO_AddRef(IXAPO
*iface
)
1842 VUMeterImpl
*This
= VUMeterImpl_from_IXAPO(iface
);
1843 ULONG ref
= InterlockedIncrement(&This
->ref
);
1844 TRACE("(%p)->(): Refcount now %u\n", This
, ref
);
1848 static ULONG WINAPI
VUMXAPO_Release(IXAPO
*iface
)
1850 VUMeterImpl
*This
= VUMeterImpl_from_IXAPO(iface
);
1851 ULONG ref
= InterlockedDecrement(&This
->ref
);
1853 TRACE("(%p)->(): Refcount now %u\n", This
, ref
);
1856 HeapFree(GetProcessHeap(), 0, This
);
1861 static HRESULT WINAPI
VUMXAPO_GetRegistrationProperties(IXAPO
*iface
,
1862 XAPO_REGISTRATION_PROPERTIES
**props
)
1864 VUMeterImpl
*This
= VUMeterImpl_from_IXAPO(iface
);
1865 TRACE("%p, %p\n", This
, props
);
1866 /* TODO: check for version == 20 and use XAPO20_REGISTRATION_PROPERTIES */
1870 static HRESULT WINAPI
VUMXAPO_IsInputFormatSupported(IXAPO
*iface
,
1871 const WAVEFORMATEX
*output_fmt
, const WAVEFORMATEX
*input_fmt
,
1872 WAVEFORMATEX
**supported_fmt
)
1874 VUMeterImpl
*This
= VUMeterImpl_from_IXAPO(iface
);
1875 TRACE("%p, %p, %p, %p\n", This
, output_fmt
, input_fmt
, supported_fmt
);
1879 static HRESULT WINAPI
VUMXAPO_IsOutputFormatSupported(IXAPO
*iface
,
1880 const WAVEFORMATEX
*input_fmt
, const WAVEFORMATEX
*output_fmt
,
1881 WAVEFORMATEX
**supported_fmt
)
1883 VUMeterImpl
*This
= VUMeterImpl_from_IXAPO(iface
);
1884 TRACE("%p, %p, %p, %p\n", This
, input_fmt
, output_fmt
, supported_fmt
);
1888 static HRESULT WINAPI
VUMXAPO_Initialize(IXAPO
*iface
, const void *data
,
1891 VUMeterImpl
*This
= VUMeterImpl_from_IXAPO(iface
);
1892 TRACE("%p, %p, %u\n", This
, data
, data_len
);
1896 static HRESULT WINAPI
VUMXAPO_Reset(IXAPO
*iface
)
1898 VUMeterImpl
*This
= VUMeterImpl_from_IXAPO(iface
);
1899 TRACE("%p\n", This
);
1903 static HRESULT WINAPI
VUMXAPO_LockForProcess(IXAPO
*iface
,
1904 UINT32 in_params_count
,
1905 const XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS
*in_params
,
1906 UINT32 out_params_count
,
1907 const XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS
*out_params
)
1909 VUMeterImpl
*This
= VUMeterImpl_from_IXAPO(iface
);
1910 TRACE("%p, %u, %p, %u, %p\n", This
, in_params_count
, in_params
,
1911 out_params_count
, out_params
);
1915 static void WINAPI
VUMXAPO_UnlockForProcess(IXAPO
*iface
)
1917 VUMeterImpl
*This
= VUMeterImpl_from_IXAPO(iface
);
1918 TRACE("%p\n", This
);
1921 static void WINAPI
VUMXAPO_Process(IXAPO
*iface
, UINT32 in_params_count
,
1922 const XAPO_PROCESS_BUFFER_PARAMETERS
*in_params
,
1923 UINT32 out_params_count
,
1924 const XAPO_PROCESS_BUFFER_PARAMETERS
*out_params
, BOOL enabled
)
1926 VUMeterImpl
*This
= VUMeterImpl_from_IXAPO(iface
);
1927 TRACE("%p, %u, %p, %u, %p, %u\n", This
, in_params_count
, in_params
,
1928 out_params_count
, out_params
, enabled
);
1931 static UINT32 WINAPI
VUMXAPO_CalcInputFrames(IXAPO
*iface
, UINT32 output_frames
)
1933 VUMeterImpl
*This
= VUMeterImpl_from_IXAPO(iface
);
1934 TRACE("%p, %u\n", This
, output_frames
);
1938 static UINT32 WINAPI
VUMXAPO_CalcOutputFrames(IXAPO
*iface
, UINT32 input_frames
)
1940 VUMeterImpl
*This
= VUMeterImpl_from_IXAPO(iface
);
1941 TRACE("%p, %u\n", This
, input_frames
);
1945 static const IXAPOVtbl VUMXAPO_Vtbl
= {
1946 VUMXAPO_QueryInterface
,
1949 VUMXAPO_GetRegistrationProperties
,
1950 VUMXAPO_IsInputFormatSupported
,
1951 VUMXAPO_IsOutputFormatSupported
,
1954 VUMXAPO_LockForProcess
,
1955 VUMXAPO_UnlockForProcess
,
1957 VUMXAPO_CalcInputFrames
,
1958 VUMXAPO_CalcOutputFrames
1961 static HRESULT WINAPI
VUMXAPOParams_QueryInterface(IXAPOParameters
*iface
,
1962 REFIID riid
, void **ppvObject
)
1964 VUMeterImpl
*This
= VUMeterImpl_from_IXAPOParameters(iface
);
1965 return VUMXAPO_QueryInterface(&This
->IXAPO_iface
, riid
, ppvObject
);
1968 static ULONG WINAPI
VUMXAPOParams_AddRef(IXAPOParameters
*iface
)
1970 VUMeterImpl
*This
= VUMeterImpl_from_IXAPOParameters(iface
);
1971 return VUMXAPO_AddRef(&This
->IXAPO_iface
);
1974 static ULONG WINAPI
VUMXAPOParams_Release(IXAPOParameters
*iface
)
1976 VUMeterImpl
*This
= VUMeterImpl_from_IXAPOParameters(iface
);
1977 return VUMXAPO_Release(&This
->IXAPO_iface
);
1980 static void WINAPI
VUMXAPOParams_SetParameters(IXAPOParameters
*iface
,
1981 const void *params
, UINT32 params_len
)
1983 VUMeterImpl
*This
= VUMeterImpl_from_IXAPOParameters(iface
);
1984 TRACE("%p, %p, %u\n", This
, params
, params_len
);
1987 static void WINAPI
VUMXAPOParams_GetParameters(IXAPOParameters
*iface
,
1988 void *params
, UINT32 params_len
)
1990 VUMeterImpl
*This
= VUMeterImpl_from_IXAPOParameters(iface
);
1991 TRACE("%p, %p, %u\n", This
, params
, params_len
);
1994 static const IXAPOParametersVtbl VUMXAPOParameters_Vtbl
= {
1995 VUMXAPOParams_QueryInterface
,
1996 VUMXAPOParams_AddRef
,
1997 VUMXAPOParams_Release
,
1998 VUMXAPOParams_SetParameters
,
1999 VUMXAPOParams_GetParameters
2002 typedef struct _ReverbImpl
{
2004 IXAPOParameters IXAPOParameters_iface
;
2011 static ReverbImpl
*ReverbImpl_from_IXAPO(IXAPO
*iface
)
2013 return CONTAINING_RECORD(iface
, ReverbImpl
, IXAPO_iface
);
2016 static ReverbImpl
*ReverbImpl_from_IXAPOParameters(IXAPOParameters
*iface
)
2018 return CONTAINING_RECORD(iface
, ReverbImpl
, IXAPOParameters_iface
);
2021 static HRESULT WINAPI
RVBXAPO_QueryInterface(IXAPO
*iface
, REFIID riid
, void **ppvObject
)
2023 ReverbImpl
*This
= ReverbImpl_from_IXAPO(iface
);
2025 TRACE("%p, %s, %p\n", This
, wine_dbgstr_guid(riid
), ppvObject
);
2027 if(IsEqualGUID(riid
, &IID_IUnknown
) ||
2028 IsEqualGUID(riid
, &IID_IXAPO
) ||
2029 IsEqualGUID(riid
, &IID_IXAPO27
))
2030 *ppvObject
= &This
->IXAPO_iface
;
2031 else if(IsEqualGUID(riid
, &IID_IXAPOParameters
))
2032 *ppvObject
= &This
->IXAPOParameters_iface
;
2037 IUnknown_AddRef((IUnknown
*)*ppvObject
);
2041 return E_NOINTERFACE
;
2044 static ULONG WINAPI
RVBXAPO_AddRef(IXAPO
*iface
)
2046 ReverbImpl
*This
= ReverbImpl_from_IXAPO(iface
);
2047 ULONG ref
= InterlockedIncrement(&This
->ref
);
2048 TRACE("(%p)->(): Refcount now %u\n", This
, ref
);
2052 static ULONG WINAPI
RVBXAPO_Release(IXAPO
*iface
)
2054 ReverbImpl
*This
= ReverbImpl_from_IXAPO(iface
);
2055 ULONG ref
= InterlockedDecrement(&This
->ref
);
2057 TRACE("(%p)->(): Refcount now %u\n", This
, ref
);
2060 HeapFree(GetProcessHeap(), 0, This
);
2065 static HRESULT WINAPI
RVBXAPO_GetRegistrationProperties(IXAPO
*iface
,
2066 XAPO_REGISTRATION_PROPERTIES
**props
)
2068 ReverbImpl
*This
= ReverbImpl_from_IXAPO(iface
);
2069 TRACE("%p, %p\n", This
, props
);
2070 /* TODO: check for version == 20 and use XAPO20_REGISTRATION_PROPERTIES */
2074 static HRESULT WINAPI
RVBXAPO_IsInputFormatSupported(IXAPO
*iface
,
2075 const WAVEFORMATEX
*output_fmt
, const WAVEFORMATEX
*input_fmt
,
2076 WAVEFORMATEX
**supported_fmt
)
2078 ReverbImpl
*This
= ReverbImpl_from_IXAPO(iface
);
2079 TRACE("%p, %p, %p, %p\n", This
, output_fmt
, input_fmt
, supported_fmt
);
2083 static HRESULT WINAPI
RVBXAPO_IsOutputFormatSupported(IXAPO
*iface
,
2084 const WAVEFORMATEX
*input_fmt
, const WAVEFORMATEX
*output_fmt
,
2085 WAVEFORMATEX
**supported_fmt
)
2087 ReverbImpl
*This
= ReverbImpl_from_IXAPO(iface
);
2088 TRACE("%p, %p, %p, %p\n", This
, input_fmt
, output_fmt
, supported_fmt
);
2092 static HRESULT WINAPI
RVBXAPO_Initialize(IXAPO
*iface
, const void *data
,
2095 ReverbImpl
*This
= ReverbImpl_from_IXAPO(iface
);
2096 TRACE("%p, %p, %u\n", This
, data
, data_len
);
2100 static HRESULT WINAPI
RVBXAPO_Reset(IXAPO
*iface
)
2102 ReverbImpl
*This
= ReverbImpl_from_IXAPO(iface
);
2103 TRACE("%p\n", This
);
2107 static HRESULT WINAPI
RVBXAPO_LockForProcess(IXAPO
*iface
, UINT32 in_params_count
,
2108 const XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS
*in_params
,
2109 UINT32 out_params_count
,
2110 const XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS
*out_params
)
2112 ReverbImpl
*This
= ReverbImpl_from_IXAPO(iface
);
2113 TRACE("%p, %u, %p, %u, %p\n", This
, in_params_count
, in_params
,
2114 out_params_count
, out_params
);
2118 static void WINAPI
RVBXAPO_UnlockForProcess(IXAPO
*iface
)
2120 ReverbImpl
*This
= ReverbImpl_from_IXAPO(iface
);
2121 TRACE("%p\n", This
);
2124 static void WINAPI
RVBXAPO_Process(IXAPO
*iface
, UINT32 in_params_count
,
2125 const XAPO_PROCESS_BUFFER_PARAMETERS
*in_params
,
2126 UINT32 out_params_count
,
2127 const XAPO_PROCESS_BUFFER_PARAMETERS
*out_params
, BOOL enabled
)
2129 ReverbImpl
*This
= ReverbImpl_from_IXAPO(iface
);
2130 TRACE("%p, %u, %p, %u, %p, %u\n", This
, in_params_count
, in_params
,
2131 out_params_count
, out_params
, enabled
);
2134 static UINT32 WINAPI
RVBXAPO_CalcInputFrames(IXAPO
*iface
, UINT32 output_frames
)
2136 ReverbImpl
*This
= ReverbImpl_from_IXAPO(iface
);
2137 TRACE("%p, %u\n", This
, output_frames
);
2141 static UINT32 WINAPI
RVBXAPO_CalcOutputFrames(IXAPO
*iface
, UINT32 input_frames
)
2143 ReverbImpl
*This
= ReverbImpl_from_IXAPO(iface
);
2144 TRACE("%p, %u\n", This
, input_frames
);
2148 static const IXAPOVtbl RVBXAPO_Vtbl
= {
2149 RVBXAPO_QueryInterface
,
2152 RVBXAPO_GetRegistrationProperties
,
2153 RVBXAPO_IsInputFormatSupported
,
2154 RVBXAPO_IsOutputFormatSupported
,
2157 RVBXAPO_LockForProcess
,
2158 RVBXAPO_UnlockForProcess
,
2160 RVBXAPO_CalcInputFrames
,
2161 RVBXAPO_CalcOutputFrames
2164 static HRESULT WINAPI
RVBXAPOParams_QueryInterface(IXAPOParameters
*iface
,
2165 REFIID riid
, void **ppvObject
)
2167 ReverbImpl
*This
= ReverbImpl_from_IXAPOParameters(iface
);
2168 return RVBXAPO_QueryInterface(&This
->IXAPO_iface
, riid
, ppvObject
);
2171 static ULONG WINAPI
RVBXAPOParams_AddRef(IXAPOParameters
*iface
)
2173 ReverbImpl
*This
= ReverbImpl_from_IXAPOParameters(iface
);
2174 return RVBXAPO_AddRef(&This
->IXAPO_iface
);
2177 static ULONG WINAPI
RVBXAPOParams_Release(IXAPOParameters
*iface
)
2179 ReverbImpl
*This
= ReverbImpl_from_IXAPOParameters(iface
);
2180 return RVBXAPO_Release(&This
->IXAPO_iface
);
2183 static void WINAPI
RVBXAPOParams_SetParameters(IXAPOParameters
*iface
,
2184 const void *params
, UINT32 params_len
)
2186 ReverbImpl
*This
= ReverbImpl_from_IXAPOParameters(iface
);
2187 TRACE("%p, %p, %u\n", This
, params
, params_len
);
2190 static void WINAPI
RVBXAPOParams_GetParameters(IXAPOParameters
*iface
, void *params
,
2193 ReverbImpl
*This
= ReverbImpl_from_IXAPOParameters(iface
);
2194 TRACE("%p, %p, %u\n", This
, params
, params_len
);
2197 static const IXAPOParametersVtbl RVBXAPOParameters_Vtbl
= {
2198 RVBXAPOParams_QueryInterface
,
2199 RVBXAPOParams_AddRef
,
2200 RVBXAPOParams_Release
,
2201 RVBXAPOParams_SetParameters
,
2202 RVBXAPOParams_GetParameters
2206 IClassFactory IClassFactory_iface
;
2211 struct xaudio2_cf
*impl_from_IClassFactory(IClassFactory
*iface
)
2213 return CONTAINING_RECORD(iface
, struct xaudio2_cf
, IClassFactory_iface
);
2216 static HRESULT WINAPI
XAudio2CF_QueryInterface(IClassFactory
*iface
, REFIID riid
, void **ppobj
)
2218 if(IsEqualGUID(riid
, &IID_IUnknown
)
2219 || IsEqualGUID(riid
, &IID_IClassFactory
))
2221 IClassFactory_AddRef(iface
);
2227 WARN("(%p)->(%s, %p): interface not found\n", iface
, debugstr_guid(riid
), ppobj
);
2228 return E_NOINTERFACE
;
2231 static ULONG WINAPI
XAudio2CF_AddRef(IClassFactory
*iface
)
2233 struct xaudio2_cf
*This
= impl_from_IClassFactory(iface
);
2234 ULONG ref
= InterlockedIncrement(&This
->ref
);
2235 TRACE("(%p)->(): Refcount now %u\n", This
, ref
);
2239 static ULONG WINAPI
XAudio2CF_Release(IClassFactory
*iface
)
2241 struct xaudio2_cf
*This
= impl_from_IClassFactory(iface
);
2242 ULONG ref
= InterlockedDecrement(&This
->ref
);
2243 TRACE("(%p)->(): Refcount now %u\n", This
, ref
);
2245 HeapFree(GetProcessHeap(), 0, This
);
2249 static HRESULT
initialize_mmdevices(IXAudio2Impl
*This
)
2251 IMMDeviceCollection
*devcoll
;
2256 hr
= CoCreateInstance(&CLSID_MMDeviceEnumerator
, NULL
,
2257 CLSCTX_INPROC_SERVER
, &IID_IMMDeviceEnumerator
, (void**)&This
->devenum
);
2262 hr
= IMMDeviceEnumerator_EnumAudioEndpoints(This
->devenum
, eRender
,
2263 DEVICE_STATE_ACTIVE
, &devcoll
);
2268 hr
= IMMDeviceCollection_GetCount(devcoll
, &devcount
);
2270 IMMDeviceCollection_Release(devcoll
);
2276 IMMDevice
*dev
, *def_dev
;
2278 /* make sure that device 0 is the default device */
2279 IMMDeviceEnumerator_GetDefaultAudioEndpoint(This
->devenum
, eRender
, eConsole
, &def_dev
);
2281 This
->devids
= HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR
*) * devcount
);
2283 for(i
= 0; i
< devcount
; ++i
){
2284 hr
= IMMDeviceCollection_Item(devcoll
, i
, &dev
);
2295 hr
= IMMDevice_GetId(dev
, &This
->devids
[idx
]);
2297 WARN("GetId failed: %08x\n", hr
);
2298 HeapFree(GetProcessHeap(), 0, This
->devids
);
2299 This
->devids
= NULL
;
2300 IMMDevice_Release(dev
);
2304 IMMDevice_Release(dev
);
2306 WARN("Item failed: %08x\n", hr
);
2307 HeapFree(GetProcessHeap(), 0, This
->devids
);
2308 This
->devids
= NULL
;
2309 IMMDeviceCollection_Release(devcoll
);
2315 IMMDeviceCollection_Release(devcoll
);
2317 This
->ndevs
= devcount
;
2322 static HRESULT WINAPI
XAudio2CF_CreateInstance(IClassFactory
*iface
, IUnknown
*pOuter
,
2323 REFIID riid
, void **ppobj
)
2325 struct xaudio2_cf
*This
= impl_from_IClassFactory(iface
);
2327 IXAudio2Impl
*object
;
2329 TRACE("(%p)->(%p,%s,%p)\n", This
, pOuter
, debugstr_guid(riid
), ppobj
);
2334 return CLASS_E_NOAGGREGATION
;
2336 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
2338 return E_OUTOFMEMORY
;
2340 object
->IXAudio20_iface
.lpVtbl
= &XAudio20_Vtbl
;
2341 object
->IXAudio22_iface
.lpVtbl
= &XAudio22_Vtbl
;
2342 object
->IXAudio27_iface
.lpVtbl
= &XAudio27_Vtbl
;
2343 object
->IXAudio2_iface
.lpVtbl
= &XAudio2_Vtbl
;
2344 object
->IXAudio20MasteringVoice_iface
.lpVtbl
= &XAudio20MasteringVoice_Vtbl
;
2345 object
->IXAudio23MasteringVoice_iface
.lpVtbl
= &XAudio23MasteringVoice_Vtbl
;
2346 object
->IXAudio2MasteringVoice_iface
.lpVtbl
= &XAudio2MasteringVoice_Vtbl
;
2348 if(IsEqualGUID(riid
, &IID_IXAudio27
))
2349 object
->version
= This
->version
;
2350 else /* only xaudio 2.8 has a different IID */
2351 object
->version
= 28;
2353 list_init(&object
->source_voices
);
2354 list_init(&object
->submix_voices
);
2356 object
->mmevt
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
2357 InitializeCriticalSection(&object
->lock
);
2358 object
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": IXAudio2Impl.lock");
2360 hr
= IXAudio2_QueryInterface(&object
->IXAudio2_iface
, riid
, ppobj
);
2362 HeapFree(GetProcessHeap(), 0, object
);
2366 hr
= initialize_mmdevices(object
);
2368 IUnknown_Release((IUnknown
*)*ppobj
);
2373 object
->cbs
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, object
->ncbs
* sizeof(*object
->cbs
));
2375 IXAudio2_StartEngine(&object
->IXAudio2_iface
);
2377 TRACE("Created XAudio version %u: %p\n", object
->version
, object
);
2383 IClassFactory IClassFactory_iface
;
2389 struct xapo_cf
*xapo_impl_from_IClassFactory(IClassFactory
*iface
)
2391 return CONTAINING_RECORD(iface
, struct xapo_cf
, IClassFactory_iface
);
2394 static ULONG WINAPI
xapo_AddRef(IClassFactory
*iface
)
2396 struct xapo_cf
*This
= xapo_impl_from_IClassFactory(iface
);
2397 ULONG ref
= InterlockedIncrement(&This
->ref
);
2398 TRACE("(%p)->(): Refcount now %u\n", This
, ref
);
2402 static ULONG WINAPI
xapo_Release(IClassFactory
*iface
)
2404 struct xapo_cf
*This
= xapo_impl_from_IClassFactory(iface
);
2405 ULONG ref
= InterlockedDecrement(&This
->ref
);
2406 TRACE("(%p)->(): Refcount now %u\n", This
, ref
);
2408 HeapFree(GetProcessHeap(), 0, This
);
2412 static HRESULT WINAPI
xapo_CreateInstance(IClassFactory
*iface
, IUnknown
*pOuter
,
2413 REFIID riid
, void **ppobj
)
2415 struct xapo_cf
*This
= xapo_impl_from_IClassFactory(iface
);
2418 TRACE("(%p)->(%p,%s,%p)\n", This
, pOuter
, debugstr_guid(riid
), ppobj
);
2423 return CLASS_E_NOAGGREGATION
;
2425 if(IsEqualGUID(This
->class, &CLSID_AudioVolumeMeter
)){
2426 VUMeterImpl
*object
;
2428 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
2430 return E_OUTOFMEMORY
;
2432 object
->IXAPO_iface
.lpVtbl
= &VUMXAPO_Vtbl
;
2433 object
->IXAPOParameters_iface
.lpVtbl
= &VUMXAPOParameters_Vtbl
;
2434 object
->version
= This
->version
;
2436 hr
= IXAPO_QueryInterface(&object
->IXAPO_iface
, riid
, ppobj
);
2438 HeapFree(GetProcessHeap(), 0, object
);
2441 }else if(IsEqualGUID(This
->class, &CLSID_AudioReverb
)){
2444 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
2446 return E_OUTOFMEMORY
;
2448 object
->IXAPO_iface
.lpVtbl
= &RVBXAPO_Vtbl
;
2449 object
->IXAPOParameters_iface
.lpVtbl
= &RVBXAPOParameters_Vtbl
;
2450 object
->version
= This
->version
;
2452 hr
= IXAPO_QueryInterface(&object
->IXAPO_iface
, riid
, ppobj
);
2454 HeapFree(GetProcessHeap(), 0, object
);
2458 return E_INVALIDARG
;
2463 static HRESULT WINAPI
XAudio2CF_LockServer(IClassFactory
*iface
, BOOL dolock
)
2465 FIXME("(static)->(%d): stub!\n", dolock
);
2469 static const IClassFactoryVtbl XAudio2CF_Vtbl
=
2471 XAudio2CF_QueryInterface
,
2474 XAudio2CF_CreateInstance
,
2475 XAudio2CF_LockServer
2478 static const IClassFactoryVtbl xapo_Vtbl
=
2480 XAudio2CF_QueryInterface
,
2483 xapo_CreateInstance
,
2484 XAudio2CF_LockServer
2487 static IClassFactory
*make_xaudio2_factory(DWORD version
)
2489 struct xapo_cf
*ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct xaudio2_cf
));
2490 ret
->IClassFactory_iface
.lpVtbl
= &XAudio2CF_Vtbl
;
2491 ret
->version
= version
;
2493 return &ret
->IClassFactory_iface
;
2496 static IClassFactory
*make_xapo_factory(REFCLSID clsid
, DWORD version
)
2498 struct xapo_cf
*ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct xaudio2_cf
));
2499 ret
->IClassFactory_iface
.lpVtbl
= &xapo_Vtbl
;
2500 ret
->version
= version
;
2503 return &ret
->IClassFactory_iface
;
2506 HRESULT WINAPI
DllGetClassObject(REFCLSID rclsid
, REFIID riid
, void **ppv
)
2508 IClassFactory
*factory
= NULL
;
2510 TRACE("(%s, %s, %p)\n", debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
2512 if(IsEqualGUID(rclsid
, &CLSID_XAudio20
)){
2513 factory
= make_xaudio2_factory(20);
2514 }else if(IsEqualGUID(rclsid
, &CLSID_XAudio21
)){
2515 factory
= make_xaudio2_factory(21);
2516 }else if(IsEqualGUID(rclsid
, &CLSID_XAudio22
)){
2517 factory
= make_xaudio2_factory(22);
2518 }else if(IsEqualGUID(rclsid
, &CLSID_XAudio23
)){
2519 factory
= make_xaudio2_factory(23);
2520 }else if(IsEqualGUID(rclsid
, &CLSID_XAudio24
)){
2521 factory
= make_xaudio2_factory(24);
2522 }else if(IsEqualGUID(rclsid
, &CLSID_XAudio25
)){
2523 factory
= make_xaudio2_factory(25);
2524 }else if(IsEqualGUID(rclsid
, &CLSID_XAudio26
)){
2525 factory
= make_xaudio2_factory(26);
2526 }else if(IsEqualGUID(rclsid
, &CLSID_XAudio2
)){
2527 factory
= make_xaudio2_factory(27);
2529 }else if(IsEqualGUID(rclsid
, &CLSID_AudioVolumeMeter20
)){
2530 factory
= make_xapo_factory(&CLSID_AudioVolumeMeter
, 20);
2531 }else if(IsEqualGUID(rclsid
, &CLSID_AudioVolumeMeter21
)){
2532 factory
= make_xapo_factory(&CLSID_AudioVolumeMeter
, 21);
2533 }else if(IsEqualGUID(rclsid
, &CLSID_AudioVolumeMeter22
)){
2534 factory
= make_xapo_factory(&CLSID_AudioVolumeMeter
, 22);
2535 }else if(IsEqualGUID(rclsid
, &CLSID_AudioVolumeMeter23
)){
2536 factory
= make_xapo_factory(&CLSID_AudioVolumeMeter
, 23);
2537 }else if(IsEqualGUID(rclsid
, &CLSID_AudioVolumeMeter24
)){
2538 factory
= make_xapo_factory(&CLSID_AudioVolumeMeter
, 24);
2539 }else if(IsEqualGUID(rclsid
, &CLSID_AudioVolumeMeter25
)){
2540 factory
= make_xapo_factory(&CLSID_AudioVolumeMeter
, 25);
2541 }else if(IsEqualGUID(rclsid
, &CLSID_AudioVolumeMeter26
)){
2542 factory
= make_xapo_factory(&CLSID_AudioVolumeMeter
, 26);
2543 }else if(IsEqualGUID(rclsid
, &CLSID_AudioVolumeMeter
)){
2544 factory
= make_xapo_factory(&CLSID_AudioVolumeMeter
, 27);
2546 }else if(IsEqualGUID(rclsid
, &CLSID_AudioReverb20
)){
2547 factory
= make_xapo_factory(&CLSID_AudioReverb
, 20);
2549 }else if(IsEqualGUID(rclsid
, &CLSID_AudioReverb21
) ||
2550 IsEqualGUID(rclsid
, &CLSID_WINE_FXReverb10
)){
2551 factory
= make_xapo_factory(&CLSID_AudioReverb
, 21);
2553 }else if(IsEqualGUID(rclsid
, &CLSID_AudioReverb22
) ||
2554 IsEqualGUID(rclsid
, &CLSID_WINE_FXReverb11
)){
2555 factory
= make_xapo_factory(&CLSID_AudioReverb
, 22);
2557 }else if(IsEqualGUID(rclsid
, &CLSID_AudioReverb23
) ||
2558 IsEqualGUID(rclsid
, &CLSID_WINE_FXReverb12
)){
2559 factory
= make_xapo_factory(&CLSID_AudioReverb
, 23);
2561 }else if(IsEqualGUID(rclsid
, &CLSID_AudioReverb24
) ||
2562 IsEqualGUID(rclsid
, &CLSID_WINE_FXReverb13
)){
2563 factory
= make_xapo_factory(&CLSID_AudioReverb
, 24);
2565 }else if(IsEqualGUID(rclsid
, &CLSID_AudioReverb25
)){
2566 factory
= make_xapo_factory(&CLSID_AudioReverb
, 25);
2568 }else if(IsEqualGUID(rclsid
, &CLSID_AudioReverb26
) ||
2569 IsEqualGUID(rclsid
, &CLSID_WINE_FXReverb14
)){
2570 factory
= make_xapo_factory(&CLSID_AudioReverb
, 26);
2572 }else if(IsEqualGUID(rclsid
, &CLSID_AudioReverb
) ||
2573 IsEqualGUID(rclsid
, &CLSID_WINE_FXReverb15
)){
2574 factory
= make_xapo_factory(&CLSID_AudioReverb
, 27);
2576 }else if(IsEqualGUID(rclsid
, &CLSID_WINE_FXReverb28
)){
2577 factory
= make_xapo_factory(&CLSID_AudioReverb
, 28);
2580 if(!factory
) return CLASS_E_CLASSNOTAVAILABLE
;
2582 return IClassFactory_QueryInterface(factory
, riid
, ppv
);
2585 /* returns TRUE if there is more data avilable in the buffer, FALSE if the
2586 * buffer's data has all been queued */
2587 static BOOL
xa2buffer_queue_period(XA2SourceImpl
*src
, XA2Buffer
*buf
, ALuint al_buf
)
2589 UINT32 submit_bytes
;
2590 const BYTE
*submit_buf
= NULL
;
2592 if(buf
->offs_bytes
>= buf
->cur_end_bytes
){
2593 WARN("Shouldn't happen: Trying to push frames from a spent buffer?\n");
2597 submit_bytes
= min(src
->xa2
->period_frames
* src
->submit_blocksize
, buf
->cur_end_bytes
- buf
->offs_bytes
);
2598 submit_buf
= buf
->xa2buffer
.pAudioData
+ buf
->offs_bytes
;
2599 buf
->offs_bytes
+= submit_bytes
;
2601 alBufferData(al_buf
, src
->al_fmt
, submit_buf
, submit_bytes
,
2602 src
->fmt
->nSamplesPerSec
);
2604 alSourceQueueBuffers(src
->al_src
, 1, &al_buf
);
2606 src
->in_al_bytes
+= submit_bytes
;
2607 src
->al_bufs_used
++;
2609 buf
->latest_al_buf
= al_buf
;
2611 TRACE("queueing %u bytes, now %u in AL\n", submit_bytes
, src
->in_al_bytes
);
2613 return buf
->offs_bytes
< buf
->cur_end_bytes
;
2618 * The looped section of a buffer is a subset of the play area which is looped
2622 * vvvvvvvvvvvvvvvvvv PlayLength
2624 * [-----PPPLLLLLLLLPPPPPPP------]
2626 * ^^^^^^^^ LoopLength
2629 * In the simple case, playback will start at PlayBegin. At LoopEnd, playback
2630 * will move to LoopBegin and repeat that loop LoopCount times. Then, playback
2631 * will cease at LoopEnd.
2633 * If PlayLength is zero, then PlayEnd is the end of the buffer.
2635 * If LoopLength is zero, then LoopEnd is PlayEnd.
2637 * For corner cases and version differences, see tests.
2639 static void update_source_state(XA2SourceImpl
*src
)
2645 alGetSourcei(src
->al_src
, AL_BUFFERS_PROCESSED
, &processed
);
2648 ALuint al_buffers
[XAUDIO2_MAX_QUEUED_BUFFERS
];
2650 alSourceUnqueueBuffers(src
->al_src
, processed
, al_buffers
);
2651 src
->first_al_buf
+= processed
;
2652 src
->first_al_buf
%= XAUDIO2_MAX_QUEUED_BUFFERS
;
2653 src
->al_bufs_used
-= processed
;
2655 for(i
= 0; i
< processed
; ++i
){
2658 alGetBufferi(al_buffers
[i
], AL_SIZE
, &bufsize
);
2660 src
->in_al_bytes
-= bufsize
;
2661 src
->played_frames
+= bufsize
/ src
->submit_blocksize
;
2663 if(al_buffers
[i
] == src
->buffers
[src
->first_buf
].latest_al_buf
){
2664 DWORD old_buf
= src
->first_buf
;
2667 src
->first_buf
%= XAUDIO2_MAX_QUEUED_BUFFERS
;
2670 TRACE("%p: done with buffer %u\n", src
, old_buf
);
2672 if(src
->buffers
[old_buf
].xa2buffer
.Flags
& XAUDIO2_END_OF_STREAM
)
2673 src
->played_frames
= 0;
2676 IXAudio2VoiceCallback_OnBufferEnd(src
->cb
,
2677 src
->buffers
[old_buf
].xa2buffer
.pContext
);
2678 if(src
->buffers
[old_buf
].xa2buffer
.Flags
& XAUDIO2_END_OF_STREAM
)
2679 IXAudio2VoiceCallback_OnStreamEnd(src
->cb
);
2682 IXAudio2VoiceCallback_OnBufferStart(src
->cb
,
2683 src
->buffers
[src
->first_buf
].xa2buffer
.pContext
);
2689 alGetSourcei(src
->al_src
, AL_BYTE_OFFSET
, &bufpos
);
2691 /* maintain 4 periods in AL */
2692 while(src
->cur_buf
!= (src
->first_buf
+ src
->nbufs
) % XAUDIO2_MAX_QUEUED_BUFFERS
&&
2693 src
->in_al_bytes
- bufpos
< 4 * src
->xa2
->period_frames
* src
->submit_blocksize
){
2694 TRACE("%p: going to queue a period from buffer %u\n", src
, src
->cur_buf
);
2696 /* starting from an empty buffer */
2697 if(src
->cb
&& src
->cur_buf
== src
->first_buf
&& src
->buffers
[src
->cur_buf
].offs_bytes
== 0 && !src
->buffers
[src
->cur_buf
].looped
)
2698 IXAudio2VoiceCallback_OnBufferStart(src
->cb
,
2699 src
->buffers
[src
->first_buf
].xa2buffer
.pContext
);
2701 if(!xa2buffer_queue_period(src
, &src
->buffers
[src
->cur_buf
],
2702 src
->al_bufs
[(src
->first_al_buf
+ src
->al_bufs_used
) % XAUDIO2_MAX_QUEUED_BUFFERS
])){
2703 XA2Buffer
*cur
= &src
->buffers
[src
->cur_buf
];
2705 if(cur
->looped
< cur
->xa2buffer
.LoopCount
){
2706 if(cur
->xa2buffer
.LoopCount
!= XAUDIO2_LOOP_INFINITE
)
2709 cur
->looped
= 1; /* indicate that we are executing a loop */
2711 cur
->offs_bytes
= cur
->xa2buffer
.LoopBegin
;
2712 if(cur
->looped
== cur
->xa2buffer
.LoopCount
)
2713 cur
->cur_end_bytes
= cur
->play_end_bytes
;
2715 cur
->cur_end_bytes
= cur
->loop_end_bytes
;
2718 IXAudio2VoiceCallback_OnLoopEnd(src
->cb
,
2719 src
->buffers
[src
->cur_buf
].xa2buffer
.pContext
);
2722 /* buffer is spent, move on */
2724 src
->cur_buf
%= XAUDIO2_MAX_QUEUED_BUFFERS
;
2730 static void do_engine_tick(IXAudio2Impl
*This
)
2735 UINT32 nframes
, i
, pad
;
2737 /* maintain up to 3 periods in mmdevapi */
2738 hr
= IAudioClient_GetCurrentPadding(This
->aclient
, &pad
);
2740 WARN("GetCurrentPadding failed: 0x%x\n", hr
);
2744 nframes
= This
->period_frames
* 3 - pad
;
2746 TRACE("frames available: %u\n", nframes
);
2748 if(nframes
< This
->period_frames
)
2754 for(i
= 0; i
< This
->ncbs
&& This
->cbs
[i
]; ++i
)
2755 IXAudio2EngineCallback_OnProcessingPassStart(This
->cbs
[i
]);
2757 LIST_FOR_EACH_ENTRY(src
, &This
->source_voices
, XA2SourceImpl
, entry
){
2760 EnterCriticalSection(&src
->lock
);
2762 if(!src
->in_use
|| !src
->running
){
2763 LeaveCriticalSection(&src
->lock
);
2768 if(This
->version
== 20)
2769 IXAudio20VoiceCallback_OnVoiceProcessingPassStart((IXAudio20VoiceCallback
*)src
->cb
);
2771 /* TODO: detect incoming underrun and inform callback */
2772 IXAudio2VoiceCallback_OnVoiceProcessingPassStart(src
->cb
, 0);
2775 update_source_state(src
);
2777 alGetSourcei(src
->al_src
, AL_SOURCE_STATE
, &st
);
2778 if(st
!= AL_PLAYING
)
2779 alSourcePlay(src
->al_src
);
2782 IXAudio2VoiceCallback_OnVoiceProcessingPassEnd(src
->cb
);
2784 LeaveCriticalSection(&src
->lock
);
2787 hr
= IAudioRenderClient_GetBuffer(This
->render
, nframes
, &buf
);
2789 WARN("GetBuffer failed: %08x\n", hr
);
2791 palcRenderSamplesSOFT(This
->al_device
, buf
, nframes
);
2793 hr
= IAudioRenderClient_ReleaseBuffer(This
->render
, nframes
, 0);
2795 WARN("ReleaseBuffer failed: %08x\n", hr
);
2797 for(i
= 0; i
< This
->ncbs
&& This
->cbs
[i
]; ++i
)
2798 IXAudio2EngineCallback_OnProcessingPassEnd(This
->cbs
[i
]);
2801 static DWORD WINAPI
engine_threadproc(void *arg
)
2803 IXAudio2Impl
*This
= arg
;
2805 WaitForSingleObject(This
->mmevt
, INFINITE
);
2807 if(This
->stop_engine
)
2810 EnterCriticalSection(&This
->lock
);
2812 if(!This
->running
|| !This
->aclient
){
2813 LeaveCriticalSection(&This
->lock
);
2817 do_engine_tick(This
);
2819 LeaveCriticalSection(&This
->lock
);