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"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(xaudio2
);
36 static ALCdevice
*(ALC_APIENTRY
*palcLoopbackOpenDeviceSOFT
)(const ALCchar
*);
37 static void (ALC_APIENTRY
*palcRenderSamplesSOFT
)(ALCdevice
*, ALCvoid
*, ALCsizei
);
39 static HINSTANCE instance
;
41 #define COMPAT_E_INVALID_CALL(v) (v == 20) ? E_INVALIDARG : XAUDIO2_E_INVALID_CALL
42 #define COMPAT_E_DEVICE_INVALIDATED(v) (v == 20) ? XAUDIO20_E_DEVICE_INVALIDATED : XAUDIO2_E_DEVICE_INVALIDATED
44 static void dump_fmt(const WAVEFORMATEX
*fmt
)
46 TRACE("wFormatTag: 0x%x (", fmt
->wFormatTag
);
47 switch(fmt
->wFormatTag
){
48 #define DOCASE(x) case x: TRACE(#x); break;
49 DOCASE(WAVE_FORMAT_PCM
)
50 DOCASE(WAVE_FORMAT_IEEE_FLOAT
)
51 DOCASE(WAVE_FORMAT_EXTENSIBLE
)
59 TRACE("nChannels: %u\n", fmt
->nChannels
);
60 TRACE("nSamplesPerSec: %u\n", fmt
->nSamplesPerSec
);
61 TRACE("nAvgBytesPerSec: %u\n", fmt
->nAvgBytesPerSec
);
62 TRACE("nBlockAlign: %u\n", fmt
->nBlockAlign
);
63 TRACE("wBitsPerSample: %u\n", fmt
->wBitsPerSample
);
64 TRACE("cbSize: %u\n", fmt
->cbSize
);
66 if(fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
){
67 WAVEFORMATEXTENSIBLE
*fmtex
= (void*)fmt
;
68 TRACE("dwChannelMask: %08x\n", fmtex
->dwChannelMask
);
69 TRACE("Samples: %04x\n", fmtex
->Samples
.wReserved
);
70 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex
->SubFormat
));
71 }else if(fmt
->wFormatTag
== WAVE_FORMAT_ADPCM
){
72 ADPCMWAVEFORMAT
*fmtadpcm
= (void*)fmt
;
73 TRACE("wSamplesPerBlock: %u\n", fmtadpcm
->wSamplesPerBlock
);
77 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD reason
, void *pReserved
)
79 TRACE("(%p, %d, %p)\n", hinstDLL
, reason
, pReserved
);
83 case DLL_WINE_PREATTACH
:
84 return FALSE
; /* prefer native version */
85 case DLL_PROCESS_ATTACH
:
87 DisableThreadLibraryCalls( hinstDLL
);
89 if(!alcIsExtensionPresent(NULL
, "ALC_SOFT_loopback") ||
90 !(palcLoopbackOpenDeviceSOFT
= alcGetProcAddress(NULL
, "alcLoopbackOpenDeviceSOFT")) ||
91 !(palcRenderSamplesSOFT
= alcGetProcAddress(NULL
, "alcRenderSamplesSOFT"))){
92 ERR("XAudio2 requires the ALC_SOFT_loopback extension (OpenAL-Soft >= 1.14)\n");
101 HRESULT WINAPI
DllCanUnloadNow(void)
106 HRESULT WINAPI
DllRegisterServer(void)
109 return __wine_register_resources(instance
);
112 HRESULT WINAPI
DllUnregisterServer(void)
115 return __wine_unregister_resources(instance
);
118 static XA2SourceImpl
*impl_from_IXAudio2SourceVoice(IXAudio2SourceVoice
*iface
)
120 return CONTAINING_RECORD(iface
, XA2SourceImpl
, IXAudio2SourceVoice_iface
);
123 static XA2SubmixImpl
*impl_from_IXAudio2SubmixVoice(IXAudio2SubmixVoice
*iface
)
125 return CONTAINING_RECORD(iface
, XA2SubmixImpl
, IXAudio2SubmixVoice_iface
);
128 static inline IXAudio2Impl
*impl_from_IXAudio2(IXAudio2
*iface
)
130 return CONTAINING_RECORD(iface
, IXAudio2Impl
, IXAudio2_iface
);
133 static IXAudio2Impl
*impl_from_IXAudio2MasteringVoice(IXAudio2MasteringVoice
*iface
)
135 return CONTAINING_RECORD(iface
, IXAudio2Impl
, IXAudio2MasteringVoice_iface
);
138 static DWORD
get_channel_mask(unsigned int channels
)
144 return KSAUDIO_SPEAKER_MONO
;
146 return KSAUDIO_SPEAKER_STEREO
;
148 return KSAUDIO_SPEAKER_STEREO
| SPEAKER_LOW_FREQUENCY
;
150 return KSAUDIO_SPEAKER_QUAD
; /* not _SURROUND */
152 return KSAUDIO_SPEAKER_QUAD
| SPEAKER_LOW_FREQUENCY
;
154 return KSAUDIO_SPEAKER_5POINT1
; /* not 5POINT1_SURROUND */
156 return KSAUDIO_SPEAKER_5POINT1
| SPEAKER_BACK_CENTER
;
158 return KSAUDIO_SPEAKER_7POINT1_SURROUND
; /* Vista deprecates 7POINT1 */
160 FIXME("Unknown speaker configuration: %u\n", channels
);
164 static void WINAPI
XA2SRC_GetVoiceDetails(IXAudio2SourceVoice
*iface
,
165 XAUDIO2_VOICE_DETAILS
*pVoiceDetails
)
167 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
168 TRACE("%p, %p\n", This
, pVoiceDetails
);
171 static HRESULT WINAPI
XA2SRC_SetOutputVoices(IXAudio2SourceVoice
*iface
,
172 const XAUDIO2_VOICE_SENDS
*pSendList
)
174 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
176 XAUDIO2_VOICE_SENDS def_send
;
177 XAUDIO2_SEND_DESCRIPTOR def_desc
;
179 TRACE("%p, %p\n", This
, pSendList
);
183 def_desc
.pOutputVoice
= (IXAudio2Voice
*)&This
->xa2
->IXAudio2MasteringVoice_iface
;
185 def_send
.SendCount
= 1;
186 def_send
.pSends
= &def_desc
;
188 pSendList
= &def_send
;
191 if(TRACE_ON(xaudio2
)){
192 for(i
= 0; i
< pSendList
->SendCount
; ++i
){
193 XAUDIO2_SEND_DESCRIPTOR
*desc
= &pSendList
->pSends
[i
];
194 TRACE("Outputting to: 0x%x, %p\n", desc
->Flags
, desc
->pOutputVoice
);
198 if(This
->nsends
< pSendList
->SendCount
){
199 HeapFree(GetProcessHeap(), 0, This
->sends
);
200 This
->sends
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
->sends
) * pSendList
->SendCount
);
201 This
->nsends
= pSendList
->SendCount
;
203 memset(This
->sends
, 0, sizeof(*This
->sends
) * This
->nsends
);
205 memcpy(This
->sends
, pSendList
->pSends
, sizeof(*This
->sends
) * pSendList
->SendCount
);
210 static HRESULT WINAPI
XA2SRC_SetEffectChain(IXAudio2SourceVoice
*iface
,
211 const XAUDIO2_EFFECT_CHAIN
*pEffectChain
)
213 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
214 TRACE("%p, %p\n", This
, pEffectChain
);
218 static HRESULT WINAPI
XA2SRC_EnableEffect(IXAudio2SourceVoice
*iface
,
219 UINT32 EffectIndex
, UINT32 OperationSet
)
221 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
222 TRACE("%p, %u, 0x%x\n", This
, EffectIndex
, OperationSet
);
226 static HRESULT WINAPI
XA2SRC_DisableEffect(IXAudio2SourceVoice
*iface
,
227 UINT32 EffectIndex
, UINT32 OperationSet
)
229 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
230 TRACE("%p, %u, 0x%x\n", This
, EffectIndex
, OperationSet
);
234 static void WINAPI
XA2SRC_GetEffectState(IXAudio2SourceVoice
*iface
,
235 UINT32 EffectIndex
, BOOL
*pEnabled
)
237 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
238 TRACE("%p, %u, %p\n", This
, EffectIndex
, pEnabled
);
241 static HRESULT WINAPI
XA2SRC_SetEffectParameters(IXAudio2SourceVoice
*iface
,
242 UINT32 EffectIndex
, const void *pParameters
, UINT32 ParametersByteSize
,
245 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
246 TRACE("%p, %u, %p, 0x%x, 0x%x\n", This
, EffectIndex
, pParameters
,
247 ParametersByteSize
, OperationSet
);
251 static HRESULT WINAPI
XA2SRC_GetEffectParameters(IXAudio2SourceVoice
*iface
,
252 UINT32 EffectIndex
, void *pParameters
, UINT32 ParametersByteSize
)
254 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
255 TRACE("%p, %u, %p, 0x%x\n", This
, EffectIndex
, pParameters
,
260 static HRESULT WINAPI
XA2SRC_SetFilterParameters(IXAudio2SourceVoice
*iface
,
261 const XAUDIO2_FILTER_PARAMETERS
*pParameters
, UINT32 OperationSet
)
263 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
264 TRACE("%p, %p, 0x%x\n", This
, pParameters
, OperationSet
);
268 static void WINAPI
XA2SRC_GetFilterParameters(IXAudio2SourceVoice
*iface
,
269 XAUDIO2_FILTER_PARAMETERS
*pParameters
)
271 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
272 TRACE("%p, %p\n", This
, pParameters
);
275 static HRESULT WINAPI
XA2SRC_SetOutputFilterParameters(IXAudio2SourceVoice
*iface
,
276 IXAudio2Voice
*pDestinationVoice
,
277 const XAUDIO2_FILTER_PARAMETERS
*pParameters
, UINT32 OperationSet
)
279 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
280 TRACE("%p, %p, %p, 0x%x\n", This
, pDestinationVoice
, pParameters
, OperationSet
);
284 static void WINAPI
XA2SRC_GetOutputFilterParameters(IXAudio2SourceVoice
*iface
,
285 IXAudio2Voice
*pDestinationVoice
,
286 XAUDIO2_FILTER_PARAMETERS
*pParameters
)
288 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
289 TRACE("%p, %p, %p\n", This
, pDestinationVoice
, pParameters
);
292 static HRESULT WINAPI
XA2SRC_SetVolume(IXAudio2SourceVoice
*iface
, float Volume
,
295 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
298 TRACE("%p, %f, 0x%x\n", This
, Volume
, OperationSet
);
302 alSourcef(This
->al_src
, AL_GAIN
, al_gain
);
307 static void WINAPI
XA2SRC_GetVolume(IXAudio2SourceVoice
*iface
, float *pVolume
)
309 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
310 TRACE("%p, %p\n", This
, pVolume
);
313 static HRESULT WINAPI
XA2SRC_SetChannelVolumes(IXAudio2SourceVoice
*iface
,
314 UINT32 Channels
, const float *pVolumes
, UINT32 OperationSet
)
316 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
317 TRACE("%p, %u, %p, 0x%x\n", This
, Channels
, pVolumes
, OperationSet
);
321 static void WINAPI
XA2SRC_GetChannelVolumes(IXAudio2SourceVoice
*iface
,
322 UINT32 Channels
, float *pVolumes
)
324 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
325 TRACE("%p, %u, %p\n", This
, Channels
, pVolumes
);
328 static HRESULT WINAPI
XA2SRC_SetOutputMatrix(IXAudio2SourceVoice
*iface
,
329 IXAudio2Voice
*pDestinationVoice
, UINT32 SourceChannels
,
330 UINT32 DestinationChannels
, const float *pLevelMatrix
,
333 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
334 TRACE("%p, %p, %u, %u, %p, 0x%x\n", This
, pDestinationVoice
,
335 SourceChannels
, DestinationChannels
, pLevelMatrix
, OperationSet
);
339 static void WINAPI
XA2SRC_GetOutputMatrix(IXAudio2SourceVoice
*iface
,
340 IXAudio2Voice
*pDestinationVoice
, UINT32 SourceChannels
,
341 UINT32 DestinationChannels
, float *pLevelMatrix
)
343 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
344 TRACE("%p, %p, %u, %u, %p\n", This
, pDestinationVoice
,
345 SourceChannels
, DestinationChannels
, pLevelMatrix
);
348 static void WINAPI
XA2SRC_DestroyVoice(IXAudio2SourceVoice
*iface
)
350 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
355 EnterCriticalSection(&This
->lock
);
358 LeaveCriticalSection(&This
->lock
);
362 This
->in_use
= FALSE
;
364 This
->running
= FALSE
;
366 IXAudio2SourceVoice_Stop(iface
, 0, 0);
368 alSourceStop(This
->al_src
);
370 /* unqueue all buffers */
371 alSourcei(This
->al_src
, AL_BUFFER
, AL_NONE
);
373 alGetSourcei(This
->al_src
, AL_BUFFERS_PROCESSED
, &processed
);
376 ALuint al_buffers
[XAUDIO2_MAX_QUEUED_BUFFERS
];
378 alSourceUnqueueBuffers(This
->al_src
, processed
, al_buffers
);
381 HeapFree(GetProcessHeap(), 0, This
->fmt
);
383 alDeleteBuffers(XAUDIO2_MAX_QUEUED_BUFFERS
, This
->al_bufs
);
384 alDeleteSources(1, &This
->al_src
);
386 This
->in_al_bytes
= 0;
387 This
->al_bufs_used
= 0;
388 This
->played_frames
= 0;
393 LeaveCriticalSection(&This
->lock
);
396 static HRESULT WINAPI
XA2SRC_Start(IXAudio2SourceVoice
*iface
, UINT32 Flags
,
399 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
401 TRACE("%p, 0x%x, 0x%x\n", This
, Flags
, OperationSet
);
403 EnterCriticalSection(&This
->lock
);
405 This
->running
= TRUE
;
407 LeaveCriticalSection(&This
->lock
);
412 static HRESULT WINAPI
XA2SRC_Stop(IXAudio2SourceVoice
*iface
, UINT32 Flags
,
415 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
417 TRACE("%p, 0x%x, 0x%x\n", This
, Flags
, OperationSet
);
419 EnterCriticalSection(&This
->lock
);
421 This
->running
= FALSE
;
423 LeaveCriticalSection(&This
->lock
);
428 static ALenum
get_al_format(const WAVEFORMATEX
*fmt
)
430 WAVEFORMATEXTENSIBLE
*fmtex
= (WAVEFORMATEXTENSIBLE
*)fmt
;
431 if(fmt
->wFormatTag
== WAVE_FORMAT_PCM
||
432 (fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
&&
433 IsEqualGUID(&fmtex
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
))){
434 switch(fmt
->wBitsPerSample
){
436 switch(fmt
->nChannels
){
438 return AL_FORMAT_MONO8
;
440 return AL_FORMAT_STEREO8
;
442 return AL_FORMAT_QUAD8
;
444 return AL_FORMAT_51CHN8
;
446 return AL_FORMAT_61CHN8
;
448 return AL_FORMAT_71CHN8
;
451 switch(fmt
->nChannels
){
453 return AL_FORMAT_MONO16
;
455 return AL_FORMAT_STEREO16
;
457 return AL_FORMAT_QUAD16
;
459 return AL_FORMAT_51CHN16
;
461 return AL_FORMAT_61CHN16
;
463 return AL_FORMAT_71CHN16
;
466 }else if(fmt
->wFormatTag
== WAVE_FORMAT_IEEE_FLOAT
||
467 (fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
&&
468 IsEqualGUID(&fmtex
->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
))){
469 if(fmt
->wBitsPerSample
== 32){
470 switch(fmt
->nChannels
){
472 return AL_FORMAT_MONO_FLOAT32
;
474 return AL_FORMAT_STEREO_FLOAT32
;
481 static HRESULT WINAPI
XA2SRC_SubmitSourceBuffer(IXAudio2SourceVoice
*iface
,
482 const XAUDIO2_BUFFER
*pBuffer
, const XAUDIO2_BUFFER_WMA
*pBufferWMA
)
484 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
488 TRACE("%p, %p, %p\n", This
, pBuffer
, pBufferWMA
);
490 if(TRACE_ON(xaudio2
)){
491 TRACE("Flags: 0x%x\n", pBuffer
->Flags
);
492 TRACE("AudioBytes: %u\n", pBuffer
->AudioBytes
);
493 TRACE("pAudioData: %p\n", pBuffer
->pAudioData
);
494 TRACE("PlayBegin: %u\n", pBuffer
->PlayBegin
);
495 TRACE("PlayLength: %u\n", pBuffer
->PlayLength
);
496 TRACE("LoopBegin: %u\n", pBuffer
->LoopBegin
);
497 TRACE("LoopLength: %u\n", pBuffer
->LoopLength
);
498 TRACE("LoopCount: %u\n", pBuffer
->LoopCount
);
499 TRACE("pContext: %p\n", pBuffer
->pContext
);
502 EnterCriticalSection(&This
->lock
);
504 if(This
->nbufs
>= XAUDIO2_MAX_QUEUED_BUFFERS
){
505 TRACE("Too many buffers queued!\n");
506 LeaveCriticalSection(&This
->lock
);
507 return COMPAT_E_INVALID_CALL(This
->xa2
->version
);
510 buf_idx
= (This
->first_buf
+ This
->nbufs
) % XAUDIO2_MAX_QUEUED_BUFFERS
;
511 buf
= &This
->buffers
[buf_idx
];
512 memset(buf
, 0, sizeof(*buf
));
514 /* API contract: pAudioData must remain valid until this buffer is played,
515 * but pBuffer itself may be reused immediately */
516 memcpy(&buf
->xa2buffer
, pBuffer
, sizeof(*pBuffer
));
518 if(This
->xa2
->version
== 20){
519 if(buf
->xa2buffer
.LoopCount
== XAUDIO20_LOOP_INFINITE
)
520 buf
->xa2buffer
.LoopCount
= XAUDIO2_LOOP_INFINITE
;
523 /* convert samples offsets to bytes */
524 if(This
->fmt
->wFormatTag
== WAVE_FORMAT_ADPCM
){
525 /* ADPCM gives us a number of samples per block, so round down to
526 * nearest block and convert to bytes */
527 buf
->xa2buffer
.PlayBegin
= buf
->xa2buffer
.PlayBegin
/ ((ADPCMWAVEFORMAT
*)This
->fmt
)->wSamplesPerBlock
* This
->fmt
->nBlockAlign
;
528 buf
->xa2buffer
.PlayLength
= buf
->xa2buffer
.PlayLength
/ ((ADPCMWAVEFORMAT
*)This
->fmt
)->wSamplesPerBlock
* This
->fmt
->nBlockAlign
;
529 buf
->xa2buffer
.LoopBegin
= buf
->xa2buffer
.LoopBegin
/ ((ADPCMWAVEFORMAT
*)This
->fmt
)->wSamplesPerBlock
* This
->fmt
->nBlockAlign
;
530 buf
->xa2buffer
.LoopLength
= buf
->xa2buffer
.LoopLength
/ ((ADPCMWAVEFORMAT
*)This
->fmt
)->wSamplesPerBlock
* This
->fmt
->nBlockAlign
;
532 buf
->xa2buffer
.PlayBegin
*= This
->fmt
->nBlockAlign
;
533 buf
->xa2buffer
.PlayLength
*= This
->fmt
->nBlockAlign
;
534 buf
->xa2buffer
.LoopBegin
*= This
->fmt
->nBlockAlign
;
535 buf
->xa2buffer
.LoopLength
*= This
->fmt
->nBlockAlign
;
538 if(buf
->xa2buffer
.PlayLength
== 0)
539 /* set to end of buffer */
540 buf
->xa2buffer
.PlayLength
= buf
->xa2buffer
.AudioBytes
- buf
->xa2buffer
.PlayBegin
;
542 buf
->play_end_bytes
= buf
->xa2buffer
.PlayBegin
+ buf
->xa2buffer
.PlayLength
;
544 if(buf
->xa2buffer
.LoopCount
){
545 if(buf
->xa2buffer
.LoopLength
== 0)
546 /* set to end of play range */
547 buf
->xa2buffer
.LoopLength
= buf
->play_end_bytes
- buf
->xa2buffer
.LoopBegin
;
549 if(buf
->xa2buffer
.LoopBegin
>= buf
->play_end_bytes
){
550 /* this actually crashes on native xaudio 2.7 */
551 LeaveCriticalSection(&This
->lock
);
552 return COMPAT_E_INVALID_CALL(This
->xa2
->version
);
555 buf
->loop_end_bytes
= buf
->xa2buffer
.LoopBegin
+ buf
->xa2buffer
.LoopLength
;
557 /* xaudio 2.7 allows some invalid looping setups, but later versions
559 if(This
->xa2
->version
> 27){
560 if(buf
->loop_end_bytes
> buf
->play_end_bytes
){
561 LeaveCriticalSection(&This
->lock
);
562 return COMPAT_E_INVALID_CALL(This
->xa2
->version
);
565 if(buf
->loop_end_bytes
<= buf
->xa2buffer
.PlayBegin
){
566 LeaveCriticalSection(&This
->lock
);
567 return COMPAT_E_INVALID_CALL(This
->xa2
->version
);
570 if(buf
->loop_end_bytes
<= buf
->xa2buffer
.PlayBegin
){
571 buf
->xa2buffer
.LoopCount
= 0;
572 buf
->loop_end_bytes
= buf
->play_end_bytes
;
576 buf
->xa2buffer
.LoopLength
= buf
->xa2buffer
.PlayLength
;
577 buf
->xa2buffer
.LoopBegin
= buf
->xa2buffer
.PlayBegin
;
578 buf
->loop_end_bytes
= buf
->play_end_bytes
;
581 buf
->offs_bytes
= buf
->xa2buffer
.PlayBegin
;
582 buf
->cur_end_bytes
= buf
->loop_end_bytes
;
584 buf
->latest_al_buf
= -1;
588 TRACE("%p: queued buffer %u (%u bytes), now %u buffers held\n",
589 This
, buf_idx
, buf
->xa2buffer
.AudioBytes
, This
->nbufs
);
591 LeaveCriticalSection(&This
->lock
);
596 static HRESULT WINAPI
XA2SRC_FlushSourceBuffers(IXAudio2SourceVoice
*iface
)
598 UINT i
, first
, last
, to_flush
;
599 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
603 EnterCriticalSection(&This
->lock
);
605 if(This
->running
&& This
->nbufs
> 0){
606 /* when running, flush only completely unused buffers; the rest remain
608 last
= (This
->first_buf
+ This
->nbufs
) % XAUDIO2_MAX_QUEUED_BUFFERS
;
609 first
= (This
->cur_buf
+ 1) % XAUDIO2_MAX_QUEUED_BUFFERS
;
610 if(This
->cur_buf
== last
)
613 else if(last
>= first
)
614 to_flush
= last
- first
;
616 to_flush
= last
+ XAUDIO2_MAX_QUEUED_BUFFERS
- first
;
618 /* when stopped, flush all buffers */
619 first
= This
->first_buf
;
620 last
= (This
->first_buf
+ This
->nbufs
) % XAUDIO2_MAX_QUEUED_BUFFERS
;
621 to_flush
= This
->nbufs
;
626 i
< (first
+ to_flush
) % XAUDIO2_MAX_QUEUED_BUFFERS
;
627 i
= (i
+ 1) % XAUDIO2_MAX_QUEUED_BUFFERS
){
629 IXAudio2VoiceCallback_OnBufferEnd(This
->cb
,
630 This
->buffers
[i
].xa2buffer
.pContext
);
633 This
->nbufs
-= to_flush
;
635 LeaveCriticalSection(&This
->lock
);
640 static HRESULT WINAPI
XA2SRC_Discontinuity(IXAudio2SourceVoice
*iface
)
642 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
646 EnterCriticalSection(&This
->lock
);
649 DWORD last
= (This
->first_buf
+ This
->nbufs
- 1) % XAUDIO2_MAX_QUEUED_BUFFERS
;
650 This
->buffers
[last
].xa2buffer
.Flags
|= XAUDIO2_END_OF_STREAM
;
653 LeaveCriticalSection(&This
->lock
);
658 static HRESULT WINAPI
XA2SRC_ExitLoop(IXAudio2SourceVoice
*iface
, UINT32 OperationSet
)
660 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
662 TRACE("%p, 0x%x\n", This
, OperationSet
);
664 EnterCriticalSection(&This
->lock
);
666 This
->buffers
[This
->cur_buf
].looped
= XAUDIO2_LOOP_INFINITE
;
668 LeaveCriticalSection(&This
->lock
);
673 static void WINAPI
XA2SRC_GetState(IXAudio2SourceVoice
*iface
,
674 XAUDIO2_VOICE_STATE
*pVoiceState
, UINT32 Flags
)
676 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
678 TRACE("%p, %p, 0x%x\n", This
, pVoiceState
, Flags
);
680 EnterCriticalSection(&This
->lock
);
682 if(!(Flags
& XAUDIO2_VOICE_NOSAMPLESPLAYED
))
683 pVoiceState
->SamplesPlayed
= This
->played_frames
;
685 pVoiceState
->SamplesPlayed
= 0;
688 pVoiceState
->pCurrentBufferContext
= This
->buffers
[This
->first_buf
].xa2buffer
.pContext
;
690 pVoiceState
->pCurrentBufferContext
= NULL
;
692 pVoiceState
->BuffersQueued
= This
->nbufs
;
694 LeaveCriticalSection(&This
->lock
);
696 TRACE("returning %s, queued: %u\n", wine_dbgstr_longlong(pVoiceState
->SamplesPlayed
), This
->nbufs
);
699 static HRESULT WINAPI
XA2SRC_SetFrequencyRatio(IXAudio2SourceVoice
*iface
,
700 float Ratio
, UINT32 OperationSet
)
702 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
705 TRACE("%p, %f, 0x%x\n", This
, Ratio
, OperationSet
);
707 if(Ratio
< XAUDIO2_MIN_FREQ_RATIO
)
708 r
= XAUDIO2_MIN_FREQ_RATIO
;
709 else if (Ratio
> XAUDIO2_MAX_FREQ_RATIO
)
710 r
= XAUDIO2_MAX_FREQ_RATIO
;
714 alSourcef(This
->al_src
, AL_PITCH
, r
);
719 static void WINAPI
XA2SRC_GetFrequencyRatio(IXAudio2SourceVoice
*iface
, float *pRatio
)
722 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
724 TRACE("%p, %p\n", This
, pRatio
);
726 alGetSourcef(This
->al_src
, AL_PITCH
, &ratio
);
731 static HRESULT WINAPI
XA2SRC_SetSourceSampleRate(
732 IXAudio2SourceVoice
*iface
,
733 UINT32 NewSourceSampleRate
)
735 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
737 TRACE("%p, %u\n", This
, NewSourceSampleRate
);
739 EnterCriticalSection(&This
->lock
);
742 LeaveCriticalSection(&This
->lock
);
743 return COMPAT_E_INVALID_CALL(This
->xa2
->version
);
746 This
->fmt
->nSamplesPerSec
= NewSourceSampleRate
;
748 LeaveCriticalSection(&This
->lock
);
753 static const IXAudio2SourceVoiceVtbl XAudio2SourceVoice_Vtbl
= {
754 XA2SRC_GetVoiceDetails
,
755 XA2SRC_SetOutputVoices
,
756 XA2SRC_SetEffectChain
,
758 XA2SRC_DisableEffect
,
759 XA2SRC_GetEffectState
,
760 XA2SRC_SetEffectParameters
,
761 XA2SRC_GetEffectParameters
,
762 XA2SRC_SetFilterParameters
,
763 XA2SRC_GetFilterParameters
,
764 XA2SRC_SetOutputFilterParameters
,
765 XA2SRC_GetOutputFilterParameters
,
768 XA2SRC_SetChannelVolumes
,
769 XA2SRC_GetChannelVolumes
,
770 XA2SRC_SetOutputMatrix
,
771 XA2SRC_GetOutputMatrix
,
775 XA2SRC_SubmitSourceBuffer
,
776 XA2SRC_FlushSourceBuffers
,
777 XA2SRC_Discontinuity
,
780 XA2SRC_SetFrequencyRatio
,
781 XA2SRC_GetFrequencyRatio
,
782 XA2SRC_SetSourceSampleRate
785 static void WINAPI
XA2M_GetVoiceDetails(IXAudio2MasteringVoice
*iface
,
786 XAUDIO2_VOICE_DETAILS
*pVoiceDetails
)
788 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
789 TRACE("%p, %p\n", This
, pVoiceDetails
);
790 pVoiceDetails
->CreationFlags
= 0;
791 pVoiceDetails
->InputChannels
= This
->fmt
.Format
.nChannels
;
792 pVoiceDetails
->InputSampleRate
= This
->fmt
.Format
.nSamplesPerSec
;
795 static HRESULT WINAPI
XA2M_SetOutputVoices(IXAudio2MasteringVoice
*iface
,
796 const XAUDIO2_VOICE_SENDS
*pSendList
)
798 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
799 TRACE("%p, %p\n", This
, pSendList
);
803 static HRESULT WINAPI
XA2M_SetEffectChain(IXAudio2MasteringVoice
*iface
,
804 const XAUDIO2_EFFECT_CHAIN
*pEffectChain
)
806 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
807 TRACE("%p, %p\n", This
, pEffectChain
);
811 static HRESULT WINAPI
XA2M_EnableEffect(IXAudio2MasteringVoice
*iface
, UINT32 EffectIndex
,
814 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
815 TRACE("%p, %u, 0x%x\n", This
, EffectIndex
, OperationSet
);
819 static HRESULT WINAPI
XA2M_DisableEffect(IXAudio2MasteringVoice
*iface
, UINT32 EffectIndex
,
822 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
823 TRACE("%p, %u, 0x%x\n", This
, EffectIndex
, OperationSet
);
827 static void WINAPI
XA2M_GetEffectState(IXAudio2MasteringVoice
*iface
, UINT32 EffectIndex
,
830 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
831 TRACE("%p, %u, %p\n", This
, EffectIndex
, pEnabled
);
834 static HRESULT WINAPI
XA2M_SetEffectParameters(IXAudio2MasteringVoice
*iface
,
835 UINT32 EffectIndex
, const void *pParameters
, UINT32 ParametersByteSize
,
838 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
839 TRACE("%p, %u, %p, 0x%x, 0x%x\n", This
, EffectIndex
, pParameters
,
840 ParametersByteSize
, OperationSet
);
844 static HRESULT WINAPI
XA2M_GetEffectParameters(IXAudio2MasteringVoice
*iface
,
845 UINT32 EffectIndex
, void *pParameters
, UINT32 ParametersByteSize
)
847 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
848 TRACE("%p, %u, %p, 0x%x\n", This
, EffectIndex
, pParameters
,
853 static HRESULT WINAPI
XA2M_SetFilterParameters(IXAudio2MasteringVoice
*iface
,
854 const XAUDIO2_FILTER_PARAMETERS
*pParameters
, UINT32 OperationSet
)
856 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
857 TRACE("%p, %p, 0x%x\n", This
, pParameters
, OperationSet
);
861 static void WINAPI
XA2M_GetFilterParameters(IXAudio2MasteringVoice
*iface
,
862 XAUDIO2_FILTER_PARAMETERS
*pParameters
)
864 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
865 TRACE("%p, %p\n", This
, pParameters
);
868 static HRESULT WINAPI
XA2M_SetOutputFilterParameters(IXAudio2MasteringVoice
*iface
,
869 IXAudio2Voice
*pDestinationVoice
,
870 const XAUDIO2_FILTER_PARAMETERS
*pParameters
, UINT32 OperationSet
)
872 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
873 TRACE("%p, %p, %p, 0x%x\n", This
, pDestinationVoice
, pParameters
, OperationSet
);
877 static void WINAPI
XA2M_GetOutputFilterParameters(IXAudio2MasteringVoice
*iface
,
878 IXAudio2Voice
*pDestinationVoice
,
879 XAUDIO2_FILTER_PARAMETERS
*pParameters
)
881 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
882 TRACE("%p, %p, %p\n", This
, pDestinationVoice
, pParameters
);
885 static HRESULT WINAPI
XA2M_SetVolume(IXAudio2MasteringVoice
*iface
, float Volume
,
888 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
889 TRACE("%p, %f, 0x%x\n", This
, Volume
, OperationSet
);
893 static void WINAPI
XA2M_GetVolume(IXAudio2MasteringVoice
*iface
, float *pVolume
)
895 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
896 TRACE("%p, %p\n", This
, pVolume
);
899 static HRESULT WINAPI
XA2M_SetChannelVolumes(IXAudio2MasteringVoice
*iface
, UINT32 Channels
,
900 const float *pVolumes
, UINT32 OperationSet
)
902 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
903 TRACE("%p, %u, %p, 0x%x\n", This
, Channels
, pVolumes
, OperationSet
);
907 static void WINAPI
XA2M_GetChannelVolumes(IXAudio2MasteringVoice
*iface
, UINT32 Channels
,
910 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
911 TRACE("%p, %u, %p\n", This
, Channels
, pVolumes
);
914 static HRESULT WINAPI
XA2M_SetOutputMatrix(IXAudio2MasteringVoice
*iface
,
915 IXAudio2Voice
*pDestinationVoice
, UINT32 SourceChannels
,
916 UINT32 DestinationChannels
, const float *pLevelMatrix
,
919 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
920 TRACE("%p, %p, %u, %u, %p, 0x%x\n", This
, pDestinationVoice
,
921 SourceChannels
, DestinationChannels
, pLevelMatrix
, OperationSet
);
925 static void WINAPI
XA2M_GetOutputMatrix(IXAudio2MasteringVoice
*iface
,
926 IXAudio2Voice
*pDestinationVoice
, UINT32 SourceChannels
,
927 UINT32 DestinationChannels
, float *pLevelMatrix
)
929 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
930 TRACE("%p, %p, %u, %u, %p\n", This
, pDestinationVoice
,
931 SourceChannels
, DestinationChannels
, pLevelMatrix
);
934 static void WINAPI
XA2M_DestroyVoice(IXAudio2MasteringVoice
*iface
)
936 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
940 EnterCriticalSection(&This
->lock
);
943 LeaveCriticalSection(&This
->lock
);
947 This
->running
= FALSE
;
949 IAudioRenderClient_Release(This
->render
);
952 IAudioClient_Release(This
->aclient
);
953 This
->aclient
= NULL
;
955 alcCloseDevice(This
->al_device
);
956 This
->al_device
= NULL
;
958 alcDestroyContext(This
->al_ctx
);
961 LeaveCriticalSection(&This
->lock
);
964 /* not present in XAudio2 2.7 */
965 static void WINAPI
XA2M_GetChannelMask(IXAudio2MasteringVoice
*iface
,
968 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
970 TRACE("%p %p\n", This
, pChannelMask
);
972 *pChannelMask
= This
->fmt
.dwChannelMask
;
975 static const struct IXAudio2MasteringVoiceVtbl XAudio2MasteringVoice_Vtbl
= {
976 XA2M_GetVoiceDetails
,
977 XA2M_SetOutputVoices
,
982 XA2M_SetEffectParameters
,
983 XA2M_GetEffectParameters
,
984 XA2M_SetFilterParameters
,
985 XA2M_GetFilterParameters
,
986 XA2M_SetOutputFilterParameters
,
987 XA2M_GetOutputFilterParameters
,
990 XA2M_SetChannelVolumes
,
991 XA2M_GetChannelVolumes
,
992 XA2M_SetOutputMatrix
,
993 XA2M_GetOutputMatrix
,
998 static void WINAPI
XA2SUB_GetVoiceDetails(IXAudio2SubmixVoice
*iface
,
999 XAUDIO2_VOICE_DETAILS
*pVoiceDetails
)
1001 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1002 TRACE("%p, %p\n", This
, pVoiceDetails
);
1005 static HRESULT WINAPI
XA2SUB_SetOutputVoices(IXAudio2SubmixVoice
*iface
,
1006 const XAUDIO2_VOICE_SENDS
*pSendList
)
1008 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1009 TRACE("%p, %p\n", This
, pSendList
);
1013 static HRESULT WINAPI
XA2SUB_SetEffectChain(IXAudio2SubmixVoice
*iface
,
1014 const XAUDIO2_EFFECT_CHAIN
*pEffectChain
)
1016 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1017 TRACE("%p, %p\n", This
, pEffectChain
);
1021 static HRESULT WINAPI
XA2SUB_EnableEffect(IXAudio2SubmixVoice
*iface
, UINT32 EffectIndex
,
1022 UINT32 OperationSet
)
1024 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1025 TRACE("%p, %u, 0x%x\n", This
, EffectIndex
, OperationSet
);
1029 static HRESULT WINAPI
XA2SUB_DisableEffect(IXAudio2SubmixVoice
*iface
, UINT32 EffectIndex
,
1030 UINT32 OperationSet
)
1032 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1033 TRACE("%p, %u, 0x%x\n", This
, EffectIndex
, OperationSet
);
1037 static void WINAPI
XA2SUB_GetEffectState(IXAudio2SubmixVoice
*iface
, UINT32 EffectIndex
,
1040 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1041 TRACE("%p, %u, %p\n", This
, EffectIndex
, pEnabled
);
1044 static HRESULT WINAPI
XA2SUB_SetEffectParameters(IXAudio2SubmixVoice
*iface
,
1045 UINT32 EffectIndex
, const void *pParameters
, UINT32 ParametersByteSize
,
1046 UINT32 OperationSet
)
1048 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1049 TRACE("%p, %u, %p, 0x%x, 0x%x\n", This
, EffectIndex
, pParameters
,
1050 ParametersByteSize
, OperationSet
);
1054 static HRESULT WINAPI
XA2SUB_GetEffectParameters(IXAudio2SubmixVoice
*iface
,
1055 UINT32 EffectIndex
, void *pParameters
, UINT32 ParametersByteSize
)
1057 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1058 TRACE("%p, %u, %p, 0x%x\n", This
, EffectIndex
, pParameters
,
1059 ParametersByteSize
);
1063 static HRESULT WINAPI
XA2SUB_SetFilterParameters(IXAudio2SubmixVoice
*iface
,
1064 const XAUDIO2_FILTER_PARAMETERS
*pParameters
, UINT32 OperationSet
)
1066 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1067 TRACE("%p, %p, 0x%x\n", This
, pParameters
, OperationSet
);
1071 static void WINAPI
XA2SUB_GetFilterParameters(IXAudio2SubmixVoice
*iface
,
1072 XAUDIO2_FILTER_PARAMETERS
*pParameters
)
1074 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1075 TRACE("%p, %p\n", This
, pParameters
);
1078 static HRESULT WINAPI
XA2SUB_SetOutputFilterParameters(IXAudio2SubmixVoice
*iface
,
1079 IXAudio2Voice
*pDestinationVoice
,
1080 const XAUDIO2_FILTER_PARAMETERS
*pParameters
, UINT32 OperationSet
)
1082 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1083 TRACE("%p, %p, %p, 0x%x\n", This
, pDestinationVoice
, pParameters
, OperationSet
);
1087 static void WINAPI
XA2SUB_GetOutputFilterParameters(IXAudio2SubmixVoice
*iface
,
1088 IXAudio2Voice
*pDestinationVoice
,
1089 XAUDIO2_FILTER_PARAMETERS
*pParameters
)
1091 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1092 TRACE("%p, %p, %p\n", This
, pDestinationVoice
, pParameters
);
1095 static HRESULT WINAPI
XA2SUB_SetVolume(IXAudio2SubmixVoice
*iface
, float Volume
,
1096 UINT32 OperationSet
)
1098 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1099 TRACE("%p, %f, 0x%x\n", This
, Volume
, OperationSet
);
1103 static void WINAPI
XA2SUB_GetVolume(IXAudio2SubmixVoice
*iface
, float *pVolume
)
1105 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1106 TRACE("%p, %p\n", This
, pVolume
);
1109 static HRESULT WINAPI
XA2SUB_SetChannelVolumes(IXAudio2SubmixVoice
*iface
, UINT32 Channels
,
1110 const float *pVolumes
, UINT32 OperationSet
)
1112 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1113 TRACE("%p, %u, %p, 0x%x\n", This
, Channels
, pVolumes
, OperationSet
);
1117 static void WINAPI
XA2SUB_GetChannelVolumes(IXAudio2SubmixVoice
*iface
, UINT32 Channels
,
1120 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1121 TRACE("%p, %u, %p\n", This
, Channels
, pVolumes
);
1124 static HRESULT WINAPI
XA2SUB_SetOutputMatrix(IXAudio2SubmixVoice
*iface
,
1125 IXAudio2Voice
*pDestinationVoice
, UINT32 SourceChannels
,
1126 UINT32 DestinationChannels
, const float *pLevelMatrix
,
1127 UINT32 OperationSet
)
1129 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1130 TRACE("%p, %p, %u, %u, %p, 0x%x\n", This
, pDestinationVoice
,
1131 SourceChannels
, DestinationChannels
, pLevelMatrix
, OperationSet
);
1135 static void WINAPI
XA2SUB_GetOutputMatrix(IXAudio2SubmixVoice
*iface
,
1136 IXAudio2Voice
*pDestinationVoice
, UINT32 SourceChannels
,
1137 UINT32 DestinationChannels
, float *pLevelMatrix
)
1139 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1140 TRACE("%p, %p, %u, %u, %p\n", This
, pDestinationVoice
,
1141 SourceChannels
, DestinationChannels
, pLevelMatrix
);
1144 static void WINAPI
XA2SUB_DestroyVoice(IXAudio2SubmixVoice
*iface
)
1146 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1148 TRACE("%p\n", This
);
1150 EnterCriticalSection(&This
->lock
);
1152 This
->in_use
= FALSE
;
1154 LeaveCriticalSection(&This
->lock
);
1157 static const struct IXAudio2SubmixVoiceVtbl XAudio2SubmixVoice_Vtbl
= {
1158 XA2SUB_GetVoiceDetails
,
1159 XA2SUB_SetOutputVoices
,
1160 XA2SUB_SetEffectChain
,
1161 XA2SUB_EnableEffect
,
1162 XA2SUB_DisableEffect
,
1163 XA2SUB_GetEffectState
,
1164 XA2SUB_SetEffectParameters
,
1165 XA2SUB_GetEffectParameters
,
1166 XA2SUB_SetFilterParameters
,
1167 XA2SUB_GetFilterParameters
,
1168 XA2SUB_SetOutputFilterParameters
,
1169 XA2SUB_GetOutputFilterParameters
,
1172 XA2SUB_SetChannelVolumes
,
1173 XA2SUB_GetChannelVolumes
,
1174 XA2SUB_SetOutputMatrix
,
1175 XA2SUB_GetOutputMatrix
,
1179 static HRESULT WINAPI
IXAudio2Impl_QueryInterface(IXAudio2
*iface
, REFIID riid
,
1182 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1184 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), ppvObject
);
1186 if(IsEqualGUID(riid
, &IID_IUnknown
) ||
1187 IsEqualGUID(riid
, &IID_IXAudio2
))
1188 *ppvObject
= &This
->IXAudio2_iface
;
1189 else if(IsEqualGUID(riid
, &IID_IXAudio27
)){
1190 /* all xaudio versions before 28 share an IID */
1191 if(This
->version
== 20)
1192 *ppvObject
= &This
->IXAudio20_iface
;
1193 else if(This
->version
== 21 || This
->version
== 22)
1194 *ppvObject
= &This
->IXAudio22_iface
;
1196 *ppvObject
= &This
->IXAudio27_iface
;
1201 IUnknown_AddRef((IUnknown
*)*ppvObject
);
1205 FIXME("(%p)->(%s,%p), not found\n", This
,debugstr_guid(riid
), ppvObject
);
1207 return E_NOINTERFACE
;
1210 static ULONG WINAPI
IXAudio2Impl_AddRef(IXAudio2
*iface
)
1212 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1213 ULONG ref
= InterlockedIncrement(&This
->ref
);
1214 TRACE("(%p)->(): Refcount now %u\n", This
, ref
);
1218 static ULONG WINAPI
IXAudio2Impl_Release(IXAudio2
*iface
)
1220 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1221 ULONG ref
= InterlockedDecrement(&This
->ref
);
1223 TRACE("(%p)->(): Refcount now %u\n", This
, ref
);
1227 XA2SourceImpl
*src
, *src2
;
1228 XA2SubmixImpl
*sub
, *sub2
;
1231 This
->stop_engine
= TRUE
;
1232 SetEvent(This
->mmevt
);
1233 WaitForSingleObject(This
->engine
, INFINITE
);
1234 CloseHandle(This
->engine
);
1237 LIST_FOR_EACH_ENTRY_SAFE(src
, src2
, &This
->source_voices
, XA2SourceImpl
, entry
){
1238 HeapFree(GetProcessHeap(), 0, src
->sends
);
1239 IXAudio2SourceVoice_DestroyVoice(&src
->IXAudio2SourceVoice_iface
);
1240 DeleteCriticalSection(&src
->lock
);
1241 HeapFree(GetProcessHeap(), 0, src
);
1244 LIST_FOR_EACH_ENTRY_SAFE(sub
, sub2
, &This
->submix_voices
, XA2SubmixImpl
, entry
){
1245 IXAudio2SubmixVoice_DestroyVoice(&sub
->IXAudio2SubmixVoice_iface
);
1246 DeleteCriticalSection(&sub
->lock
);
1247 HeapFree(GetProcessHeap(), 0, sub
);
1250 IXAudio2MasteringVoice_DestroyVoice(&This
->IXAudio2MasteringVoice_iface
);
1253 IMMDeviceEnumerator_Release(This
->devenum
);
1254 for(i
= 0; i
< This
->ndevs
; ++i
)
1255 CoTaskMemFree(This
->devids
[i
]);
1256 HeapFree(GetProcessHeap(), 0, This
->devids
);
1257 HeapFree(GetProcessHeap(), 0, This
->cbs
);
1259 CloseHandle(This
->mmevt
);
1261 DeleteCriticalSection(&This
->lock
);
1263 HeapFree(GetProcessHeap(), 0, This
);
1268 static HRESULT WINAPI
IXAudio2Impl_RegisterForCallbacks(IXAudio2
*iface
,
1269 IXAudio2EngineCallback
*pCallback
)
1271 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1274 TRACE("(%p)->(%p)\n", This
, pCallback
);
1276 EnterCriticalSection(&This
->lock
);
1278 for(i
= 0; i
< This
->ncbs
; ++i
){
1279 if(!This
->cbs
[i
] || This
->cbs
[i
] == pCallback
){
1280 This
->cbs
[i
] = pCallback
;
1281 LeaveCriticalSection(&This
->lock
);
1287 This
->cbs
= HeapReAlloc(GetProcessHeap(), 0, This
->cbs
, This
->ncbs
* sizeof(*This
->cbs
));
1289 This
->cbs
[i
] = pCallback
;
1291 LeaveCriticalSection(&This
->lock
);
1296 static void WINAPI
IXAudio2Impl_UnregisterForCallbacks(IXAudio2
*iface
,
1297 IXAudio2EngineCallback
*pCallback
)
1299 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1302 TRACE("(%p)->(%p)\n", This
, pCallback
);
1304 EnterCriticalSection(&This
->lock
);
1306 for(i
= 0; i
< This
->ncbs
; ++i
){
1307 if(This
->cbs
[i
] == pCallback
)
1311 for(; i
< This
->ncbs
- 1 && This
->cbs
[i
+ 1]; ++i
)
1312 This
->cbs
[i
] = This
->cbs
[i
+ 1];
1315 This
->cbs
[i
] = NULL
;
1317 LeaveCriticalSection(&This
->lock
);
1320 static WAVEFORMATEX
*copy_waveformat(const WAVEFORMATEX
*wfex
)
1324 if(wfex
->wFormatTag
== WAVE_FORMAT_PCM
){
1325 pwfx
= HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEX
));
1326 CopyMemory(pwfx
, wfex
, sizeof(PCMWAVEFORMAT
));
1329 pwfx
= HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEX
) + wfex
->cbSize
);
1330 CopyMemory(pwfx
, wfex
, sizeof(WAVEFORMATEX
) + wfex
->cbSize
);
1336 static HRESULT WINAPI
IXAudio2Impl_CreateSourceVoice(IXAudio2
*iface
,
1337 IXAudio2SourceVoice
**ppSourceVoice
, const WAVEFORMATEX
*pSourceFormat
,
1338 UINT32 flags
, float maxFrequencyRatio
,
1339 IXAudio2VoiceCallback
*pCallback
, const XAUDIO2_VOICE_SENDS
*pSendList
,
1340 const XAUDIO2_EFFECT_CHAIN
*pEffectChain
)
1342 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1346 TRACE("(%p)->(%p, %p, 0x%x, %f, %p, %p, %p)\n", This
, ppSourceVoice
,
1347 pSourceFormat
, flags
, maxFrequencyRatio
, pCallback
, pSendList
,
1350 dump_fmt(pSourceFormat
);
1352 EnterCriticalSection(&This
->lock
);
1354 LIST_FOR_EACH_ENTRY(src
, &This
->source_voices
, XA2SourceImpl
, entry
){
1359 if(&src
->entry
== &This
->source_voices
){
1360 src
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*src
));
1362 LeaveCriticalSection(&This
->lock
);
1363 return E_OUTOFMEMORY
;
1366 list_add_head(&This
->source_voices
, &src
->entry
);
1368 src
->IXAudio20SourceVoice_iface
.lpVtbl
= &XAudio20SourceVoice_Vtbl
;
1369 src
->IXAudio23SourceVoice_iface
.lpVtbl
= &XAudio23SourceVoice_Vtbl
;
1370 src
->IXAudio27SourceVoice_iface
.lpVtbl
= &XAudio27SourceVoice_Vtbl
;
1371 src
->IXAudio2SourceVoice_iface
.lpVtbl
= &XAudio2SourceVoice_Vtbl
;
1373 InitializeCriticalSection(&src
->lock
);
1374 src
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": XA2SourceImpl.lock");
1380 src
->running
= FALSE
;
1382 LeaveCriticalSection(&This
->lock
);
1384 src
->cb
= pCallback
;
1386 src
->al_fmt
= get_al_format(pSourceFormat
);
1388 src
->in_use
= FALSE
;
1389 WARN("OpenAL can't convert this format!\n");
1390 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
1393 src
->submit_blocksize
= pSourceFormat
->nBlockAlign
;
1395 src
->fmt
= copy_waveformat(pSourceFormat
);
1397 hr
= XA2SRC_SetOutputVoices(&src
->IXAudio2SourceVoice_iface
, pSendList
);
1399 src
->in_use
= FALSE
;
1403 alGenSources(1, &src
->al_src
);
1404 alGenBuffers(XAUDIO2_MAX_QUEUED_BUFFERS
, src
->al_bufs
);
1406 alSourcePlay(src
->al_src
);
1408 if(This
->version
== 20)
1409 *ppSourceVoice
= (IXAudio2SourceVoice
*)&src
->IXAudio20SourceVoice_iface
;
1410 else if(This
->version
<= 23)
1411 *ppSourceVoice
= (IXAudio2SourceVoice
*)&src
->IXAudio23SourceVoice_iface
;
1412 else if(This
->version
<= 27)
1413 *ppSourceVoice
= (IXAudio2SourceVoice
*)&src
->IXAudio27SourceVoice_iface
;
1415 *ppSourceVoice
= &src
->IXAudio2SourceVoice_iface
;
1417 TRACE("Created source voice: %p\n", src
);
1422 static HRESULT WINAPI
IXAudio2Impl_CreateSubmixVoice(IXAudio2
*iface
,
1423 IXAudio2SubmixVoice
**ppSubmixVoice
, UINT32 inputChannels
,
1424 UINT32 inputSampleRate
, UINT32 flags
, UINT32 processingStage
,
1425 const XAUDIO2_VOICE_SENDS
*pSendList
,
1426 const XAUDIO2_EFFECT_CHAIN
*pEffectChain
)
1428 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1431 TRACE("(%p)->(%p, %u, %u, 0x%x, %u, %p, %p)\n", This
, ppSubmixVoice
,
1432 inputChannels
, inputSampleRate
, flags
, processingStage
, pSendList
,
1435 EnterCriticalSection(&This
->lock
);
1437 LIST_FOR_EACH_ENTRY(sub
, &This
->submix_voices
, XA2SubmixImpl
, entry
){
1442 if(&sub
->entry
== &This
->submix_voices
){
1443 sub
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*sub
));
1445 LeaveCriticalSection(&This
->lock
);
1446 return E_OUTOFMEMORY
;
1449 list_add_head(&This
->submix_voices
, &sub
->entry
);
1451 sub
->IXAudio20SubmixVoice_iface
.lpVtbl
= &XAudio20SubmixVoice_Vtbl
;
1452 sub
->IXAudio23SubmixVoice_iface
.lpVtbl
= &XAudio23SubmixVoice_Vtbl
;
1453 sub
->IXAudio2SubmixVoice_iface
.lpVtbl
= &XAudio2SubmixVoice_Vtbl
;
1455 InitializeCriticalSection(&sub
->lock
);
1456 sub
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": XA2SubmixImpl.lock");
1461 LeaveCriticalSection(&This
->lock
);
1463 if(This
->version
== 20)
1464 *ppSubmixVoice
= (IXAudio2SubmixVoice
*)&sub
->IXAudio20SubmixVoice_iface
;
1465 else if(This
->version
<= 23)
1466 *ppSubmixVoice
= (IXAudio2SubmixVoice
*)&sub
->IXAudio23SubmixVoice_iface
;
1468 *ppSubmixVoice
= &sub
->IXAudio2SubmixVoice_iface
;
1470 TRACE("Created submix voice: %p\n", sub
);
1475 static ALenum
al_get_loopback_format(const WAVEFORMATEXTENSIBLE
*fmt
)
1477 if(fmt
->Format
.wFormatTag
== WAVE_FORMAT_PCM
||
1478 (fmt
->Format
.wFormatTag
== WAVE_FORMAT_EXTENSIBLE
&&
1479 IsEqualGUID(&fmt
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
))){
1480 switch(fmt
->Format
.wBitsPerSample
){
1482 return ALC_UNSIGNED_BYTE_SOFT
;
1484 return ALC_SHORT_SOFT
;
1486 return ALC_INT_SOFT
;
1488 }else if(fmt
->Format
.wFormatTag
== WAVE_FORMAT_IEEE_FLOAT
||
1489 (fmt
->Format
.wFormatTag
== WAVE_FORMAT_EXTENSIBLE
&&
1490 IsEqualGUID(&fmt
->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
))){
1491 if(fmt
->Format
.wBitsPerSample
== 32)
1492 return ALC_FLOAT_SOFT
;
1497 static HRESULT WINAPI
IXAudio2Impl_CreateMasteringVoice(IXAudio2
*iface
,
1498 IXAudio2MasteringVoice
**ppMasteringVoice
, UINT32 inputChannels
,
1499 UINT32 inputSampleRate
, UINT32 flags
, const WCHAR
*deviceId
,
1500 const XAUDIO2_EFFECT_CHAIN
*pEffectChain
,
1501 AUDIO_STREAM_CATEGORY streamCategory
)
1503 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1508 REFERENCE_TIME period
, bufdur
;
1510 TRACE("(%p)->(%p, %u, %u, 0x%x, %s, %p, 0x%x)\n", This
,
1511 ppMasteringVoice
, inputChannels
, inputSampleRate
, flags
,
1512 wine_dbgstr_w(deviceId
), pEffectChain
, streamCategory
);
1515 WARN("Unknown flags set: 0x%x\n", flags
);
1518 WARN("Effect chain is unimplemented\n");
1520 EnterCriticalSection(&This
->lock
);
1522 /* there can only be one Mastering Voice, so just build it into XA2 */
1524 LeaveCriticalSection(&This
->lock
);
1525 return COMPAT_E_INVALID_CALL(This
->version
);
1529 if(This
->ndevs
== 0){
1530 LeaveCriticalSection(&This
->lock
);
1531 return ERROR_NOT_FOUND
;
1533 deviceId
= This
->devids
[0];
1536 hr
= IMMDeviceEnumerator_GetDevice(This
->devenum
, deviceId
, &dev
);
1538 WARN("GetDevice failed: %08x\n", hr
);
1539 hr
= COMPAT_E_DEVICE_INVALIDATED(This
->version
);
1543 hr
= IMMDevice_Activate(dev
, &IID_IAudioClient
,
1544 CLSCTX_INPROC_SERVER
, NULL
, (void**)&This
->aclient
);
1546 WARN("Activate(IAudioClient) failed: %08x\n", hr
);
1547 IMMDevice_Release(dev
);
1548 hr
= COMPAT_E_DEVICE_INVALIDATED(This
->version
);
1552 IMMDevice_Release(dev
);
1554 hr
= IAudioClient_GetMixFormat(This
->aclient
, &fmt
);
1556 WARN("GetMixFormat failed: %08x\n", hr
);
1557 hr
= COMPAT_E_DEVICE_INVALIDATED(This
->version
);
1561 if(sizeof(WAVEFORMATEX
) + fmt
->cbSize
> sizeof(WAVEFORMATEXTENSIBLE
)){
1562 FIXME("Mix format doesn't fit into WAVEFORMATEXTENSIBLE!\n");
1563 hr
= COMPAT_E_DEVICE_INVALIDATED(This
->version
);
1567 if(inputChannels
== XAUDIO2_DEFAULT_CHANNELS
)
1568 inputChannels
= fmt
->nChannels
;
1569 if(inputSampleRate
== XAUDIO2_DEFAULT_SAMPLERATE
)
1570 inputSampleRate
= fmt
->nSamplesPerSec
;
1572 memcpy(&This
->fmt
, fmt
, sizeof(WAVEFORMATEX
) + fmt
->cbSize
);
1573 This
->fmt
.Format
.nChannels
= inputChannels
;
1574 This
->fmt
.Format
.nSamplesPerSec
= inputSampleRate
;
1575 This
->fmt
.Format
.nBlockAlign
= This
->fmt
.Format
.nChannels
* This
->fmt
.Format
.wBitsPerSample
/ 8;
1576 This
->fmt
.Format
.nAvgBytesPerSec
= This
->fmt
.Format
.nSamplesPerSec
* This
->fmt
.Format
.nBlockAlign
;
1577 This
->fmt
.dwChannelMask
= get_channel_mask(This
->fmt
.Format
.nChannels
);
1582 hr
= IAudioClient_IsFormatSupported(This
->aclient
,
1583 AUDCLNT_SHAREMODE_SHARED
, &This
->fmt
.Format
, &fmt
);
1585 if(sizeof(WAVEFORMATEX
) + fmt
->cbSize
> sizeof(WAVEFORMATEXTENSIBLE
)){
1586 FIXME("Mix format doesn't fit into WAVEFORMATEXTENSIBLE!\n");
1587 hr
= COMPAT_E_DEVICE_INVALIDATED(This
->version
);
1590 memcpy(&This
->fmt
, fmt
, sizeof(WAVEFORMATEX
) + fmt
->cbSize
);
1595 hr
= IAudioClient_GetDevicePeriod(This
->aclient
, &period
, NULL
);
1597 WARN("GetDevicePeriod failed: %08x\n", hr
);
1598 hr
= COMPAT_E_DEVICE_INVALIDATED(This
->version
);
1602 /* 3 periods or 0.1 seconds */
1603 bufdur
= max(3 * period
, 1000000);
1605 hr
= IAudioClient_Initialize(This
->aclient
, AUDCLNT_SHAREMODE_SHARED
,
1606 AUDCLNT_STREAMFLAGS_EVENTCALLBACK
, bufdur
,
1607 0, &This
->fmt
.Format
, NULL
);
1609 WARN("Initialize failed: %08x\n", hr
);
1610 hr
= COMPAT_E_DEVICE_INVALIDATED(This
->version
);
1614 This
->period_frames
= MulDiv(period
, inputSampleRate
, 10000000);
1616 hr
= IAudioClient_SetEventHandle(This
->aclient
, This
->mmevt
);
1618 WARN("Initialize failed: %08x\n", hr
);
1619 hr
= COMPAT_E_DEVICE_INVALIDATED(This
->version
);
1623 hr
= IAudioClient_GetService(This
->aclient
, &IID_IAudioRenderClient
,
1624 (void**)&This
->render
);
1626 WARN("GetService(IAudioRenderClient) failed: %08x\n", hr
);
1627 hr
= COMPAT_E_DEVICE_INVALIDATED(This
->version
);
1631 /* setup openal context */
1632 attrs
[0] = ALC_FORMAT_CHANNELS_SOFT
;
1633 switch(inputChannels
){
1635 attrs
[1] = ALC_MONO_SOFT
;
1638 attrs
[1] = ALC_STEREO_SOFT
;
1641 attrs
[1] = ALC_QUAD_SOFT
;
1644 attrs
[1] = ALC_5POINT1_SOFT
;
1647 attrs
[1] = ALC_6POINT1_SOFT
;
1650 attrs
[1] = ALC_7POINT1_SOFT
;
1653 WARN("OpenAL doesn't support %u channels\n", inputChannels
);
1654 LeaveCriticalSection(&This
->lock
);
1655 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
1657 attrs
[2] = ALC_FREQUENCY
;
1658 attrs
[3] = inputSampleRate
;
1659 attrs
[4] = ALC_FORMAT_TYPE_SOFT
;
1660 attrs
[5] = al_get_loopback_format(&This
->fmt
);
1664 WARN("OpenAL can't output samples in this format\n");
1665 hr
= COMPAT_E_DEVICE_INVALIDATED(This
->version
);
1669 This
->al_device
= palcLoopbackOpenDeviceSOFT(NULL
);
1670 if(!This
->al_device
){
1671 WARN("alcLoopbackOpenDeviceSOFT failed\n");
1672 hr
= COMPAT_E_DEVICE_INVALIDATED(This
->version
);
1676 This
->al_ctx
= alcCreateContext(This
->al_device
, attrs
);
1678 WARN("alcCreateContext failed\n");
1679 hr
= COMPAT_E_DEVICE_INVALIDATED(This
->version
);
1683 if(alcMakeContextCurrent(This
->al_ctx
) == ALC_FALSE
){
1684 WARN("alcMakeContextCurrent failed\n");
1685 hr
= COMPAT_E_DEVICE_INVALIDATED(This
->version
);
1689 IAudioClient_Start(This
->aclient
);
1691 if(This
->version
<= 20)
1692 *ppMasteringVoice
= (IXAudio2MasteringVoice
*)&This
->IXAudio20MasteringVoice_iface
;
1693 else if(This
->version
<= 23)
1694 *ppMasteringVoice
= (IXAudio2MasteringVoice
*)&This
->IXAudio23MasteringVoice_iface
;
1696 *ppMasteringVoice
= &This
->IXAudio2MasteringVoice_iface
;
1701 IAudioRenderClient_Release(This
->render
);
1702 This
->render
= NULL
;
1705 IAudioClient_Release(This
->aclient
);
1706 This
->aclient
= NULL
;
1709 alcDestroyContext(This
->al_ctx
);
1710 This
->al_ctx
= NULL
;
1712 if(This
->al_device
){
1713 alcCloseDevice(This
->al_device
);
1714 This
->al_device
= NULL
;
1718 LeaveCriticalSection(&This
->lock
);
1723 static DWORD WINAPI
engine_threadproc(void *arg
);
1725 static HRESULT WINAPI
IXAudio2Impl_StartEngine(IXAudio2
*iface
)
1727 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1729 TRACE("(%p)->()\n", This
);
1731 This
->running
= TRUE
;
1734 This
->engine
= CreateThread(NULL
, 0, engine_threadproc
, This
, 0, NULL
);
1739 static void WINAPI
IXAudio2Impl_StopEngine(IXAudio2
*iface
)
1741 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1743 TRACE("(%p)->()\n", This
);
1745 This
->running
= FALSE
;
1748 static HRESULT WINAPI
IXAudio2Impl_CommitChanges(IXAudio2
*iface
,
1749 UINT32 operationSet
)
1751 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1753 TRACE("(%p)->(0x%x): stub!\n", This
, operationSet
);
1758 static void WINAPI
IXAudio2Impl_GetPerformanceData(IXAudio2
*iface
,
1759 XAUDIO2_PERFORMANCE_DATA
*pPerfData
)
1761 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1763 TRACE("(%p)->(%p): stub!\n", This
, pPerfData
);
1765 memset(pPerfData
, 0, sizeof(*pPerfData
));
1768 static void WINAPI
IXAudio2Impl_SetDebugConfiguration(IXAudio2
*iface
,
1769 const XAUDIO2_DEBUG_CONFIGURATION
*pDebugConfiguration
,
1772 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1774 FIXME("(%p)->(%p, %p): stub!\n", This
, pDebugConfiguration
, pReserved
);
1778 static const IXAudio2Vtbl XAudio2_Vtbl
=
1780 IXAudio2Impl_QueryInterface
,
1781 IXAudio2Impl_AddRef
,
1782 IXAudio2Impl_Release
,
1783 IXAudio2Impl_RegisterForCallbacks
,
1784 IXAudio2Impl_UnregisterForCallbacks
,
1785 IXAudio2Impl_CreateSourceVoice
,
1786 IXAudio2Impl_CreateSubmixVoice
,
1787 IXAudio2Impl_CreateMasteringVoice
,
1788 IXAudio2Impl_StartEngine
,
1789 IXAudio2Impl_StopEngine
,
1790 IXAudio2Impl_CommitChanges
,
1791 IXAudio2Impl_GetPerformanceData
,
1792 IXAudio2Impl_SetDebugConfiguration
1795 typedef struct _VUMeterImpl
{
1797 IXAPOParameters IXAPOParameters_iface
;
1804 static VUMeterImpl
*VUMeterImpl_from_IXAPO(IXAPO
*iface
)
1806 return CONTAINING_RECORD(iface
, VUMeterImpl
, IXAPO_iface
);
1809 static VUMeterImpl
*VUMeterImpl_from_IXAPOParameters(IXAPOParameters
*iface
)
1811 return CONTAINING_RECORD(iface
, VUMeterImpl
, IXAPOParameters_iface
);
1814 static HRESULT WINAPI
VUMXAPO_QueryInterface(IXAPO
*iface
, REFIID riid
,
1817 VUMeterImpl
*This
= VUMeterImpl_from_IXAPO(iface
);
1819 TRACE("%p, %s, %p\n", This
, wine_dbgstr_guid(riid
), ppvObject
);
1821 if(IsEqualGUID(riid
, &IID_IUnknown
) ||
1822 IsEqualGUID(riid
, &IID_IXAPO
) ||
1823 IsEqualGUID(riid
, &IID_IXAPO27
))
1824 *ppvObject
= &This
->IXAPO_iface
;
1825 else if(IsEqualGUID(riid
, &IID_IXAPOParameters
))
1826 *ppvObject
= &This
->IXAPOParameters_iface
;
1831 IUnknown_AddRef((IUnknown
*)*ppvObject
);
1835 return E_NOINTERFACE
;
1838 static ULONG WINAPI
VUMXAPO_AddRef(IXAPO
*iface
)
1840 VUMeterImpl
*This
= VUMeterImpl_from_IXAPO(iface
);
1841 ULONG ref
= InterlockedIncrement(&This
->ref
);
1842 TRACE("(%p)->(): Refcount now %u\n", This
, ref
);
1846 static ULONG WINAPI
VUMXAPO_Release(IXAPO
*iface
)
1848 VUMeterImpl
*This
= VUMeterImpl_from_IXAPO(iface
);
1849 ULONG ref
= InterlockedDecrement(&This
->ref
);
1851 TRACE("(%p)->(): Refcount now %u\n", This
, ref
);
1854 HeapFree(GetProcessHeap(), 0, This
);
1859 static HRESULT WINAPI
VUMXAPO_GetRegistrationProperties(IXAPO
*iface
,
1860 XAPO_REGISTRATION_PROPERTIES
**props
)
1862 VUMeterImpl
*This
= VUMeterImpl_from_IXAPO(iface
);
1863 TRACE("%p, %p\n", This
, props
);
1864 /* TODO: check for version == 20 and use XAPO20_REGISTRATION_PROPERTIES */
1868 static HRESULT WINAPI
VUMXAPO_IsInputFormatSupported(IXAPO
*iface
,
1869 const WAVEFORMATEX
*output_fmt
, const WAVEFORMATEX
*input_fmt
,
1870 WAVEFORMATEX
**supported_fmt
)
1872 VUMeterImpl
*This
= VUMeterImpl_from_IXAPO(iface
);
1873 TRACE("%p, %p, %p, %p\n", This
, output_fmt
, input_fmt
, supported_fmt
);
1877 static HRESULT WINAPI
VUMXAPO_IsOutputFormatSupported(IXAPO
*iface
,
1878 const WAVEFORMATEX
*input_fmt
, const WAVEFORMATEX
*output_fmt
,
1879 WAVEFORMATEX
**supported_fmt
)
1881 VUMeterImpl
*This
= VUMeterImpl_from_IXAPO(iface
);
1882 TRACE("%p, %p, %p, %p\n", This
, input_fmt
, output_fmt
, supported_fmt
);
1886 static HRESULT WINAPI
VUMXAPO_Initialize(IXAPO
*iface
, const void *data
,
1889 VUMeterImpl
*This
= VUMeterImpl_from_IXAPO(iface
);
1890 TRACE("%p, %p, %u\n", This
, data
, data_len
);
1894 static HRESULT WINAPI
VUMXAPO_Reset(IXAPO
*iface
)
1896 VUMeterImpl
*This
= VUMeterImpl_from_IXAPO(iface
);
1897 TRACE("%p\n", This
);
1901 static HRESULT WINAPI
VUMXAPO_LockForProcess(IXAPO
*iface
,
1902 UINT32 in_params_count
,
1903 const XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS
*in_params
,
1904 UINT32 out_params_count
,
1905 const XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS
*out_params
)
1907 VUMeterImpl
*This
= VUMeterImpl_from_IXAPO(iface
);
1908 TRACE("%p, %u, %p, %u, %p\n", This
, in_params_count
, in_params
,
1909 out_params_count
, out_params
);
1913 static void WINAPI
VUMXAPO_UnlockForProcess(IXAPO
*iface
)
1915 VUMeterImpl
*This
= VUMeterImpl_from_IXAPO(iface
);
1916 TRACE("%p\n", This
);
1919 static void WINAPI
VUMXAPO_Process(IXAPO
*iface
, UINT32 in_params_count
,
1920 const XAPO_PROCESS_BUFFER_PARAMETERS
*in_params
,
1921 UINT32 out_params_count
,
1922 const XAPO_PROCESS_BUFFER_PARAMETERS
*out_params
, BOOL enabled
)
1924 VUMeterImpl
*This
= VUMeterImpl_from_IXAPO(iface
);
1925 TRACE("%p, %u, %p, %u, %p, %u\n", This
, in_params_count
, in_params
,
1926 out_params_count
, out_params
, enabled
);
1929 static UINT32 WINAPI
VUMXAPO_CalcInputFrames(IXAPO
*iface
, UINT32 output_frames
)
1931 VUMeterImpl
*This
= VUMeterImpl_from_IXAPO(iface
);
1932 TRACE("%p, %u\n", This
, output_frames
);
1936 static UINT32 WINAPI
VUMXAPO_CalcOutputFrames(IXAPO
*iface
, UINT32 input_frames
)
1938 VUMeterImpl
*This
= VUMeterImpl_from_IXAPO(iface
);
1939 TRACE("%p, %u\n", This
, input_frames
);
1943 static const IXAPOVtbl VUMXAPO_Vtbl
= {
1944 VUMXAPO_QueryInterface
,
1947 VUMXAPO_GetRegistrationProperties
,
1948 VUMXAPO_IsInputFormatSupported
,
1949 VUMXAPO_IsOutputFormatSupported
,
1952 VUMXAPO_LockForProcess
,
1953 VUMXAPO_UnlockForProcess
,
1955 VUMXAPO_CalcInputFrames
,
1956 VUMXAPO_CalcOutputFrames
1959 static HRESULT WINAPI
VUMXAPOParams_QueryInterface(IXAPOParameters
*iface
,
1960 REFIID riid
, void **ppvObject
)
1962 VUMeterImpl
*This
= VUMeterImpl_from_IXAPOParameters(iface
);
1963 return VUMXAPO_QueryInterface(&This
->IXAPO_iface
, riid
, ppvObject
);
1966 static ULONG WINAPI
VUMXAPOParams_AddRef(IXAPOParameters
*iface
)
1968 VUMeterImpl
*This
= VUMeterImpl_from_IXAPOParameters(iface
);
1969 return VUMXAPO_AddRef(&This
->IXAPO_iface
);
1972 static ULONG WINAPI
VUMXAPOParams_Release(IXAPOParameters
*iface
)
1974 VUMeterImpl
*This
= VUMeterImpl_from_IXAPOParameters(iface
);
1975 return VUMXAPO_Release(&This
->IXAPO_iface
);
1978 static void WINAPI
VUMXAPOParams_SetParameters(IXAPOParameters
*iface
,
1979 const void *params
, UINT32 params_len
)
1981 VUMeterImpl
*This
= VUMeterImpl_from_IXAPOParameters(iface
);
1982 TRACE("%p, %p, %u\n", This
, params
, params_len
);
1985 static void WINAPI
VUMXAPOParams_GetParameters(IXAPOParameters
*iface
,
1986 void *params
, UINT32 params_len
)
1988 VUMeterImpl
*This
= VUMeterImpl_from_IXAPOParameters(iface
);
1989 TRACE("%p, %p, %u\n", This
, params
, params_len
);
1992 static const IXAPOParametersVtbl VUMXAPOParameters_Vtbl
= {
1993 VUMXAPOParams_QueryInterface
,
1994 VUMXAPOParams_AddRef
,
1995 VUMXAPOParams_Release
,
1996 VUMXAPOParams_SetParameters
,
1997 VUMXAPOParams_GetParameters
2000 typedef struct _ReverbImpl
{
2002 IXAPOParameters IXAPOParameters_iface
;
2009 static ReverbImpl
*ReverbImpl_from_IXAPO(IXAPO
*iface
)
2011 return CONTAINING_RECORD(iface
, ReverbImpl
, IXAPO_iface
);
2014 static ReverbImpl
*ReverbImpl_from_IXAPOParameters(IXAPOParameters
*iface
)
2016 return CONTAINING_RECORD(iface
, ReverbImpl
, IXAPOParameters_iface
);
2019 static HRESULT WINAPI
RVBXAPO_QueryInterface(IXAPO
*iface
, REFIID riid
, void **ppvObject
)
2021 ReverbImpl
*This
= ReverbImpl_from_IXAPO(iface
);
2023 TRACE("%p, %s, %p\n", This
, wine_dbgstr_guid(riid
), ppvObject
);
2025 if(IsEqualGUID(riid
, &IID_IUnknown
) ||
2026 IsEqualGUID(riid
, &IID_IXAPO
) ||
2027 IsEqualGUID(riid
, &IID_IXAPO27
))
2028 *ppvObject
= &This
->IXAPO_iface
;
2029 else if(IsEqualGUID(riid
, &IID_IXAPOParameters
))
2030 *ppvObject
= &This
->IXAPOParameters_iface
;
2035 IUnknown_AddRef((IUnknown
*)*ppvObject
);
2039 return E_NOINTERFACE
;
2042 static ULONG WINAPI
RVBXAPO_AddRef(IXAPO
*iface
)
2044 ReverbImpl
*This
= ReverbImpl_from_IXAPO(iface
);
2045 ULONG ref
= InterlockedIncrement(&This
->ref
);
2046 TRACE("(%p)->(): Refcount now %u\n", This
, ref
);
2050 static ULONG WINAPI
RVBXAPO_Release(IXAPO
*iface
)
2052 ReverbImpl
*This
= ReverbImpl_from_IXAPO(iface
);
2053 ULONG ref
= InterlockedDecrement(&This
->ref
);
2055 TRACE("(%p)->(): Refcount now %u\n", This
, ref
);
2058 HeapFree(GetProcessHeap(), 0, This
);
2063 static HRESULT WINAPI
RVBXAPO_GetRegistrationProperties(IXAPO
*iface
,
2064 XAPO_REGISTRATION_PROPERTIES
**props
)
2066 ReverbImpl
*This
= ReverbImpl_from_IXAPO(iface
);
2067 TRACE("%p, %p\n", This
, props
);
2068 /* TODO: check for version == 20 and use XAPO20_REGISTRATION_PROPERTIES */
2072 static HRESULT WINAPI
RVBXAPO_IsInputFormatSupported(IXAPO
*iface
,
2073 const WAVEFORMATEX
*output_fmt
, const WAVEFORMATEX
*input_fmt
,
2074 WAVEFORMATEX
**supported_fmt
)
2076 ReverbImpl
*This
= ReverbImpl_from_IXAPO(iface
);
2077 TRACE("%p, %p, %p, %p\n", This
, output_fmt
, input_fmt
, supported_fmt
);
2081 static HRESULT WINAPI
RVBXAPO_IsOutputFormatSupported(IXAPO
*iface
,
2082 const WAVEFORMATEX
*input_fmt
, const WAVEFORMATEX
*output_fmt
,
2083 WAVEFORMATEX
**supported_fmt
)
2085 ReverbImpl
*This
= ReverbImpl_from_IXAPO(iface
);
2086 TRACE("%p, %p, %p, %p\n", This
, input_fmt
, output_fmt
, supported_fmt
);
2090 static HRESULT WINAPI
RVBXAPO_Initialize(IXAPO
*iface
, const void *data
,
2093 ReverbImpl
*This
= ReverbImpl_from_IXAPO(iface
);
2094 TRACE("%p, %p, %u\n", This
, data
, data_len
);
2098 static HRESULT WINAPI
RVBXAPO_Reset(IXAPO
*iface
)
2100 ReverbImpl
*This
= ReverbImpl_from_IXAPO(iface
);
2101 TRACE("%p\n", This
);
2105 static HRESULT WINAPI
RVBXAPO_LockForProcess(IXAPO
*iface
, UINT32 in_params_count
,
2106 const XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS
*in_params
,
2107 UINT32 out_params_count
,
2108 const XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS
*out_params
)
2110 ReverbImpl
*This
= ReverbImpl_from_IXAPO(iface
);
2111 TRACE("%p, %u, %p, %u, %p\n", This
, in_params_count
, in_params
,
2112 out_params_count
, out_params
);
2116 static void WINAPI
RVBXAPO_UnlockForProcess(IXAPO
*iface
)
2118 ReverbImpl
*This
= ReverbImpl_from_IXAPO(iface
);
2119 TRACE("%p\n", This
);
2122 static void WINAPI
RVBXAPO_Process(IXAPO
*iface
, UINT32 in_params_count
,
2123 const XAPO_PROCESS_BUFFER_PARAMETERS
*in_params
,
2124 UINT32 out_params_count
,
2125 const XAPO_PROCESS_BUFFER_PARAMETERS
*out_params
, BOOL enabled
)
2127 ReverbImpl
*This
= ReverbImpl_from_IXAPO(iface
);
2128 TRACE("%p, %u, %p, %u, %p, %u\n", This
, in_params_count
, in_params
,
2129 out_params_count
, out_params
, enabled
);
2132 static UINT32 WINAPI
RVBXAPO_CalcInputFrames(IXAPO
*iface
, UINT32 output_frames
)
2134 ReverbImpl
*This
= ReverbImpl_from_IXAPO(iface
);
2135 TRACE("%p, %u\n", This
, output_frames
);
2139 static UINT32 WINAPI
RVBXAPO_CalcOutputFrames(IXAPO
*iface
, UINT32 input_frames
)
2141 ReverbImpl
*This
= ReverbImpl_from_IXAPO(iface
);
2142 TRACE("%p, %u\n", This
, input_frames
);
2146 static const IXAPOVtbl RVBXAPO_Vtbl
= {
2147 RVBXAPO_QueryInterface
,
2150 RVBXAPO_GetRegistrationProperties
,
2151 RVBXAPO_IsInputFormatSupported
,
2152 RVBXAPO_IsOutputFormatSupported
,
2155 RVBXAPO_LockForProcess
,
2156 RVBXAPO_UnlockForProcess
,
2158 RVBXAPO_CalcInputFrames
,
2159 RVBXAPO_CalcOutputFrames
2162 static HRESULT WINAPI
RVBXAPOParams_QueryInterface(IXAPOParameters
*iface
,
2163 REFIID riid
, void **ppvObject
)
2165 ReverbImpl
*This
= ReverbImpl_from_IXAPOParameters(iface
);
2166 return RVBXAPO_QueryInterface(&This
->IXAPO_iface
, riid
, ppvObject
);
2169 static ULONG WINAPI
RVBXAPOParams_AddRef(IXAPOParameters
*iface
)
2171 ReverbImpl
*This
= ReverbImpl_from_IXAPOParameters(iface
);
2172 return RVBXAPO_AddRef(&This
->IXAPO_iface
);
2175 static ULONG WINAPI
RVBXAPOParams_Release(IXAPOParameters
*iface
)
2177 ReverbImpl
*This
= ReverbImpl_from_IXAPOParameters(iface
);
2178 return RVBXAPO_Release(&This
->IXAPO_iface
);
2181 static void WINAPI
RVBXAPOParams_SetParameters(IXAPOParameters
*iface
,
2182 const void *params
, UINT32 params_len
)
2184 ReverbImpl
*This
= ReverbImpl_from_IXAPOParameters(iface
);
2185 TRACE("%p, %p, %u\n", This
, params
, params_len
);
2188 static void WINAPI
RVBXAPOParams_GetParameters(IXAPOParameters
*iface
, void *params
,
2191 ReverbImpl
*This
= ReverbImpl_from_IXAPOParameters(iface
);
2192 TRACE("%p, %p, %u\n", This
, params
, params_len
);
2195 static const IXAPOParametersVtbl RVBXAPOParameters_Vtbl
= {
2196 RVBXAPOParams_QueryInterface
,
2197 RVBXAPOParams_AddRef
,
2198 RVBXAPOParams_Release
,
2199 RVBXAPOParams_SetParameters
,
2200 RVBXAPOParams_GetParameters
2204 IClassFactory IClassFactory_iface
;
2209 struct xaudio2_cf
*impl_from_IClassFactory(IClassFactory
*iface
)
2211 return CONTAINING_RECORD(iface
, struct xaudio2_cf
, IClassFactory_iface
);
2214 static HRESULT WINAPI
XAudio2CF_QueryInterface(IClassFactory
*iface
, REFIID riid
, void **ppobj
)
2216 if(IsEqualGUID(riid
, &IID_IUnknown
)
2217 || IsEqualGUID(riid
, &IID_IClassFactory
))
2219 IClassFactory_AddRef(iface
);
2225 WARN("(%p)->(%s, %p): interface not found\n", iface
, debugstr_guid(riid
), ppobj
);
2226 return E_NOINTERFACE
;
2229 static ULONG WINAPI
XAudio2CF_AddRef(IClassFactory
*iface
)
2231 struct xaudio2_cf
*This
= impl_from_IClassFactory(iface
);
2232 ULONG ref
= InterlockedIncrement(&This
->ref
);
2233 TRACE("(%p)->(): Refcount now %u\n", This
, ref
);
2237 static ULONG WINAPI
XAudio2CF_Release(IClassFactory
*iface
)
2239 struct xaudio2_cf
*This
= impl_from_IClassFactory(iface
);
2240 ULONG ref
= InterlockedDecrement(&This
->ref
);
2241 TRACE("(%p)->(): Refcount now %u\n", This
, ref
);
2243 HeapFree(GetProcessHeap(), 0, This
);
2247 static HRESULT
initialize_mmdevices(IXAudio2Impl
*This
)
2249 IMMDeviceCollection
*devcoll
;
2254 hr
= CoCreateInstance(&CLSID_MMDeviceEnumerator
, NULL
,
2255 CLSCTX_INPROC_SERVER
, &IID_IMMDeviceEnumerator
, (void**)&This
->devenum
);
2260 hr
= IMMDeviceEnumerator_EnumAudioEndpoints(This
->devenum
, eRender
,
2261 DEVICE_STATE_ACTIVE
, &devcoll
);
2266 hr
= IMMDeviceCollection_GetCount(devcoll
, &devcount
);
2268 IMMDeviceCollection_Release(devcoll
);
2274 IMMDevice
*dev
, *def_dev
;
2276 /* make sure that device 0 is the default device */
2277 IMMDeviceEnumerator_GetDefaultAudioEndpoint(This
->devenum
, eRender
, eConsole
, &def_dev
);
2279 This
->devids
= HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR
*) * devcount
);
2281 for(i
= 0; i
< devcount
; ++i
){
2282 hr
= IMMDeviceCollection_Item(devcoll
, i
, &dev
);
2293 hr
= IMMDevice_GetId(dev
, &This
->devids
[idx
]);
2295 WARN("GetId failed: %08x\n", hr
);
2296 HeapFree(GetProcessHeap(), 0, This
->devids
);
2297 This
->devids
= NULL
;
2298 IMMDevice_Release(dev
);
2302 IMMDevice_Release(dev
);
2304 WARN("Item failed: %08x\n", hr
);
2305 HeapFree(GetProcessHeap(), 0, This
->devids
);
2306 This
->devids
= NULL
;
2307 IMMDeviceCollection_Release(devcoll
);
2313 IMMDeviceCollection_Release(devcoll
);
2315 This
->ndevs
= devcount
;
2320 static HRESULT WINAPI
XAudio2CF_CreateInstance(IClassFactory
*iface
, IUnknown
*pOuter
,
2321 REFIID riid
, void **ppobj
)
2323 struct xaudio2_cf
*This
= impl_from_IClassFactory(iface
);
2325 IXAudio2Impl
*object
;
2327 TRACE("(%p)->(%p,%s,%p)\n", This
, pOuter
, debugstr_guid(riid
), ppobj
);
2332 return CLASS_E_NOAGGREGATION
;
2334 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
2336 return E_OUTOFMEMORY
;
2338 object
->IXAudio20_iface
.lpVtbl
= &XAudio20_Vtbl
;
2339 object
->IXAudio22_iface
.lpVtbl
= &XAudio22_Vtbl
;
2340 object
->IXAudio27_iface
.lpVtbl
= &XAudio27_Vtbl
;
2341 object
->IXAudio2_iface
.lpVtbl
= &XAudio2_Vtbl
;
2342 object
->IXAudio20MasteringVoice_iface
.lpVtbl
= &XAudio20MasteringVoice_Vtbl
;
2343 object
->IXAudio23MasteringVoice_iface
.lpVtbl
= &XAudio23MasteringVoice_Vtbl
;
2344 object
->IXAudio2MasteringVoice_iface
.lpVtbl
= &XAudio2MasteringVoice_Vtbl
;
2346 if(IsEqualGUID(riid
, &IID_IXAudio27
))
2347 object
->version
= This
->version
;
2348 else /* only xaudio 2.8 has a different IID */
2349 object
->version
= 28;
2351 list_init(&object
->source_voices
);
2352 list_init(&object
->submix_voices
);
2354 object
->mmevt
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
2355 InitializeCriticalSection(&object
->lock
);
2356 object
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": IXAudio2Impl.lock");
2358 hr
= IXAudio2_QueryInterface(&object
->IXAudio2_iface
, riid
, ppobj
);
2360 HeapFree(GetProcessHeap(), 0, object
);
2364 hr
= initialize_mmdevices(object
);
2366 IUnknown_Release((IUnknown
*)*ppobj
);
2371 object
->cbs
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, object
->ncbs
* sizeof(*object
->cbs
));
2373 IXAudio2_StartEngine(&object
->IXAudio2_iface
);
2375 TRACE("Created XAudio version %u: %p\n", object
->version
, object
);
2381 IClassFactory IClassFactory_iface
;
2387 struct xapo_cf
*xapo_impl_from_IClassFactory(IClassFactory
*iface
)
2389 return CONTAINING_RECORD(iface
, struct xapo_cf
, IClassFactory_iface
);
2392 static ULONG WINAPI
xapo_AddRef(IClassFactory
*iface
)
2394 struct xapo_cf
*This
= xapo_impl_from_IClassFactory(iface
);
2395 ULONG ref
= InterlockedIncrement(&This
->ref
);
2396 TRACE("(%p)->(): Refcount now %u\n", This
, ref
);
2400 static ULONG WINAPI
xapo_Release(IClassFactory
*iface
)
2402 struct xapo_cf
*This
= xapo_impl_from_IClassFactory(iface
);
2403 ULONG ref
= InterlockedDecrement(&This
->ref
);
2404 TRACE("(%p)->(): Refcount now %u\n", This
, ref
);
2406 HeapFree(GetProcessHeap(), 0, This
);
2410 static HRESULT WINAPI
xapo_CreateInstance(IClassFactory
*iface
, IUnknown
*pOuter
,
2411 REFIID riid
, void **ppobj
)
2413 struct xapo_cf
*This
= xapo_impl_from_IClassFactory(iface
);
2416 TRACE("(%p)->(%p,%s,%p)\n", This
, pOuter
, debugstr_guid(riid
), ppobj
);
2421 return CLASS_E_NOAGGREGATION
;
2423 if(IsEqualGUID(This
->class, &CLSID_AudioVolumeMeter
)){
2424 VUMeterImpl
*object
;
2426 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
2428 return E_OUTOFMEMORY
;
2430 object
->IXAPO_iface
.lpVtbl
= &VUMXAPO_Vtbl
;
2431 object
->IXAPOParameters_iface
.lpVtbl
= &VUMXAPOParameters_Vtbl
;
2432 object
->version
= This
->version
;
2434 hr
= IXAPO_QueryInterface(&object
->IXAPO_iface
, riid
, ppobj
);
2436 HeapFree(GetProcessHeap(), 0, object
);
2439 }else if(IsEqualGUID(This
->class, &CLSID_AudioReverb
)){
2442 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
2444 return E_OUTOFMEMORY
;
2446 object
->IXAPO_iface
.lpVtbl
= &RVBXAPO_Vtbl
;
2447 object
->IXAPOParameters_iface
.lpVtbl
= &RVBXAPOParameters_Vtbl
;
2448 object
->version
= This
->version
;
2450 hr
= IXAPO_QueryInterface(&object
->IXAPO_iface
, riid
, ppobj
);
2452 HeapFree(GetProcessHeap(), 0, object
);
2456 return E_INVALIDARG
;
2461 static HRESULT WINAPI
XAudio2CF_LockServer(IClassFactory
*iface
, BOOL dolock
)
2463 FIXME("(static)->(%d): stub!\n", dolock
);
2467 static const IClassFactoryVtbl XAudio2CF_Vtbl
=
2469 XAudio2CF_QueryInterface
,
2472 XAudio2CF_CreateInstance
,
2473 XAudio2CF_LockServer
2476 static const IClassFactoryVtbl xapo_Vtbl
=
2478 XAudio2CF_QueryInterface
,
2481 xapo_CreateInstance
,
2482 XAudio2CF_LockServer
2485 static IClassFactory
*make_xaudio2_factory(DWORD version
)
2487 struct xapo_cf
*ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct xaudio2_cf
));
2488 ret
->IClassFactory_iface
.lpVtbl
= &XAudio2CF_Vtbl
;
2489 ret
->version
= version
;
2491 return &ret
->IClassFactory_iface
;
2494 static IClassFactory
*make_xapo_factory(REFCLSID clsid
, DWORD version
)
2496 struct xapo_cf
*ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct xaudio2_cf
));
2497 ret
->IClassFactory_iface
.lpVtbl
= &xapo_Vtbl
;
2498 ret
->version
= version
;
2501 return &ret
->IClassFactory_iface
;
2504 HRESULT WINAPI
DllGetClassObject(REFCLSID rclsid
, REFIID riid
, void **ppv
)
2506 IClassFactory
*factory
= NULL
;
2508 TRACE("(%s, %s, %p)\n", debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
2510 if IsEqualGUID(rclsid
, &CLSID_XAudio20
){
2511 factory
= make_xaudio2_factory(20);
2512 }else if IsEqualGUID(rclsid
, &CLSID_XAudio21
){
2513 factory
= make_xaudio2_factory(21);
2514 }else if IsEqualGUID(rclsid
, &CLSID_XAudio22
){
2515 factory
= make_xaudio2_factory(22);
2516 }else if IsEqualGUID(rclsid
, &CLSID_XAudio23
){
2517 factory
= make_xaudio2_factory(23);
2518 }else if(IsEqualGUID(rclsid
, &CLSID_XAudio24
)){
2519 factory
= make_xaudio2_factory(24);
2520 }else if(IsEqualGUID(rclsid
, &CLSID_XAudio25
)){
2521 factory
= make_xaudio2_factory(25);
2522 }else if(IsEqualGUID(rclsid
, &CLSID_XAudio26
)){
2523 factory
= make_xaudio2_factory(26);
2524 }else if(IsEqualGUID(rclsid
, &CLSID_XAudio2
)){
2525 factory
= make_xaudio2_factory(27);
2527 }else if IsEqualGUID(rclsid
, &CLSID_AudioVolumeMeter20
){
2528 factory
= make_xapo_factory(&CLSID_AudioVolumeMeter
, 20);
2529 }else if IsEqualGUID(rclsid
, &CLSID_AudioVolumeMeter21
){
2530 factory
= make_xapo_factory(&CLSID_AudioVolumeMeter
, 21);
2531 }else if IsEqualGUID(rclsid
, &CLSID_AudioVolumeMeter22
){
2532 factory
= make_xapo_factory(&CLSID_AudioVolumeMeter
, 22);
2533 }else if IsEqualGUID(rclsid
, &CLSID_AudioVolumeMeter23
){
2534 factory
= make_xapo_factory(&CLSID_AudioVolumeMeter
, 23);
2535 }else if(IsEqualGUID(rclsid
, &CLSID_AudioVolumeMeter24
)){
2536 factory
= make_xapo_factory(&CLSID_AudioVolumeMeter
, 24);
2537 }else if(IsEqualGUID(rclsid
, &CLSID_AudioVolumeMeter25
)){
2538 factory
= make_xapo_factory(&CLSID_AudioVolumeMeter
, 25);
2539 }else if(IsEqualGUID(rclsid
, &CLSID_AudioVolumeMeter26
)){
2540 factory
= make_xapo_factory(&CLSID_AudioVolumeMeter
, 26);
2541 }else if(IsEqualGUID(rclsid
, &CLSID_AudioVolumeMeter
)){
2542 factory
= make_xapo_factory(&CLSID_AudioVolumeMeter
, 27);
2544 }else if IsEqualGUID(rclsid
, &CLSID_AudioReverb20
){
2545 factory
= make_xapo_factory(&CLSID_AudioReverb
, 20);
2546 }else if IsEqualGUID(rclsid
, &CLSID_AudioReverb21
){
2547 factory
= make_xapo_factory(&CLSID_AudioReverb
, 21);
2548 }else if IsEqualGUID(rclsid
, &CLSID_AudioReverb22
){
2549 factory
= make_xapo_factory(&CLSID_AudioReverb
, 22);
2550 }else if IsEqualGUID(rclsid
, &CLSID_AudioReverb23
){
2551 factory
= make_xapo_factory(&CLSID_AudioReverb
, 23);
2552 }else if(IsEqualGUID(rclsid
, &CLSID_AudioReverb24
)){
2553 factory
= make_xapo_factory(&CLSID_AudioReverb
, 24);
2554 }else if(IsEqualGUID(rclsid
, &CLSID_AudioReverb25
)){
2555 factory
= make_xapo_factory(&CLSID_AudioReverb
, 25);
2556 }else if(IsEqualGUID(rclsid
, &CLSID_AudioReverb26
)){
2557 factory
= make_xapo_factory(&CLSID_AudioReverb
, 26);
2558 }else if(IsEqualGUID(rclsid
, &CLSID_AudioReverb
)){
2559 factory
= make_xapo_factory(&CLSID_AudioReverb
, 27);
2561 if(!factory
) return CLASS_E_CLASSNOTAVAILABLE
;
2563 return IClassFactory_QueryInterface(factory
, riid
, ppv
);
2566 /* returns TRUE if there is more data avilable in the buffer, FALSE if the
2567 * buffer's data has all been queued */
2568 static BOOL
xa2buffer_queue_period(XA2SourceImpl
*src
, XA2Buffer
*buf
, ALuint al_buf
)
2570 UINT32 submit_bytes
;
2571 const BYTE
*submit_buf
= NULL
;
2573 if(buf
->offs_bytes
>= buf
->cur_end_bytes
){
2574 WARN("Shouldn't happen: Trying to push frames from a spent buffer?\n");
2578 submit_bytes
= min(src
->xa2
->period_frames
* src
->submit_blocksize
, buf
->cur_end_bytes
- buf
->offs_bytes
);
2579 submit_buf
= buf
->xa2buffer
.pAudioData
+ buf
->offs_bytes
;
2580 buf
->offs_bytes
+= submit_bytes
;
2582 alBufferData(al_buf
, src
->al_fmt
, submit_buf
, submit_bytes
,
2583 src
->fmt
->nSamplesPerSec
);
2585 alSourceQueueBuffers(src
->al_src
, 1, &al_buf
);
2587 src
->in_al_bytes
+= submit_bytes
;
2588 src
->al_bufs_used
++;
2590 buf
->latest_al_buf
= al_buf
;
2592 TRACE("queueing %u bytes, now %u in AL\n", submit_bytes
, src
->in_al_bytes
);
2594 return buf
->offs_bytes
< buf
->cur_end_bytes
;
2599 * The looped section of a buffer is a subset of the play area which is looped
2603 * vvvvvvvvvvvvvvvvvv PlayLength
2605 * [-----PPPLLLLLLLLPPPPPPP------]
2607 * ^^^^^^^^ LoopLength
2610 * In the simple case, playback will start at PlayBegin. At LoopEnd, playback
2611 * will move to LoopBegin and repeat that loop LoopCount times. Then, playback
2612 * will cease at LoopEnd.
2614 * If PlayLength is zero, then PlayEnd is the end of the buffer.
2616 * If LoopLength is zero, then LoopEnd is PlayEnd.
2618 * For corner cases and version differences, see tests.
2620 static void update_source_state(XA2SourceImpl
*src
)
2626 alGetSourcei(src
->al_src
, AL_BUFFERS_PROCESSED
, &processed
);
2629 ALuint al_buffers
[XAUDIO2_MAX_QUEUED_BUFFERS
];
2631 alSourceUnqueueBuffers(src
->al_src
, processed
, al_buffers
);
2632 src
->first_al_buf
+= processed
;
2633 src
->first_al_buf
%= XAUDIO2_MAX_QUEUED_BUFFERS
;
2634 src
->al_bufs_used
-= processed
;
2636 for(i
= 0; i
< processed
; ++i
){
2639 alGetBufferi(al_buffers
[i
], AL_SIZE
, &bufsize
);
2641 src
->in_al_bytes
-= bufsize
;
2642 src
->played_frames
+= bufsize
/ src
->submit_blocksize
;
2644 if(al_buffers
[i
] == src
->buffers
[src
->first_buf
].latest_al_buf
){
2645 DWORD old_buf
= src
->first_buf
;
2648 src
->first_buf
%= XAUDIO2_MAX_QUEUED_BUFFERS
;
2651 TRACE("%p: done with buffer %u\n", src
, old_buf
);
2653 if(src
->buffers
[old_buf
].xa2buffer
.Flags
& XAUDIO2_END_OF_STREAM
)
2654 src
->played_frames
= 0;
2657 IXAudio2VoiceCallback_OnBufferEnd(src
->cb
,
2658 src
->buffers
[old_buf
].xa2buffer
.pContext
);
2659 if(src
->buffers
[old_buf
].xa2buffer
.Flags
& XAUDIO2_END_OF_STREAM
)
2660 IXAudio2VoiceCallback_OnStreamEnd(src
->cb
);
2663 IXAudio2VoiceCallback_OnBufferStart(src
->cb
,
2664 src
->buffers
[src
->first_buf
].xa2buffer
.pContext
);
2670 alGetSourcei(src
->al_src
, AL_BYTE_OFFSET
, &bufpos
);
2672 /* maintain 4 periods in AL */
2673 while(src
->cur_buf
!= (src
->first_buf
+ src
->nbufs
) % XAUDIO2_MAX_QUEUED_BUFFERS
&&
2674 src
->in_al_bytes
- bufpos
< 4 * src
->xa2
->period_frames
* src
->submit_blocksize
){
2675 TRACE("%p: going to queue a period from buffer %u\n", src
, src
->cur_buf
);
2677 /* starting from an empty buffer */
2678 if(src
->cb
&& src
->cur_buf
== src
->first_buf
&& src
->buffers
[src
->cur_buf
].offs_bytes
== 0 && !src
->buffers
[src
->cur_buf
].looped
)
2679 IXAudio2VoiceCallback_OnBufferStart(src
->cb
,
2680 src
->buffers
[src
->first_buf
].xa2buffer
.pContext
);
2682 if(!xa2buffer_queue_period(src
, &src
->buffers
[src
->cur_buf
],
2683 src
->al_bufs
[(src
->first_al_buf
+ src
->al_bufs_used
) % XAUDIO2_MAX_QUEUED_BUFFERS
])){
2684 XA2Buffer
*cur
= &src
->buffers
[src
->cur_buf
];
2686 if(cur
->looped
< cur
->xa2buffer
.LoopCount
){
2687 if(cur
->xa2buffer
.LoopCount
!= XAUDIO2_LOOP_INFINITE
)
2690 cur
->looped
= 1; /* indicate that we are executing a loop */
2692 cur
->offs_bytes
= cur
->xa2buffer
.LoopBegin
;
2693 if(cur
->looped
== cur
->xa2buffer
.LoopCount
)
2694 cur
->cur_end_bytes
= cur
->play_end_bytes
;
2696 cur
->cur_end_bytes
= cur
->loop_end_bytes
;
2699 IXAudio2VoiceCallback_OnLoopEnd(src
->cb
,
2700 src
->buffers
[src
->cur_buf
].xa2buffer
.pContext
);
2703 /* buffer is spent, move on */
2705 src
->cur_buf
%= XAUDIO2_MAX_QUEUED_BUFFERS
;
2711 static void do_engine_tick(IXAudio2Impl
*This
)
2716 UINT32 nframes
, i
, pad
;
2718 /* maintain up to 3 periods in mmdevapi */
2719 hr
= IAudioClient_GetCurrentPadding(This
->aclient
, &pad
);
2721 WARN("GetCurrentPadding failed: 0x%x\n", hr
);
2725 nframes
= This
->period_frames
* 3 - pad
;
2726 TRACE("going to render %u frames\n", nframes
);
2731 for(i
= 0; i
< This
->ncbs
&& This
->cbs
[i
]; ++i
)
2732 IXAudio2EngineCallback_OnProcessingPassStart(This
->cbs
[i
]);
2734 LIST_FOR_EACH_ENTRY(src
, &This
->source_voices
, XA2SourceImpl
, entry
){
2737 EnterCriticalSection(&src
->lock
);
2739 if(!src
->in_use
|| !src
->running
){
2740 LeaveCriticalSection(&src
->lock
);
2745 if(This
->version
== 20)
2746 IXAudio20VoiceCallback_OnVoiceProcessingPassStart((IXAudio20VoiceCallback
*)src
->cb
);
2748 /* TODO: detect incoming underrun and inform callback */
2749 IXAudio2VoiceCallback_OnVoiceProcessingPassStart(src
->cb
, 0);
2752 update_source_state(src
);
2754 alGetSourcei(src
->al_src
, AL_SOURCE_STATE
, &st
);
2755 if(st
!= AL_PLAYING
)
2756 alSourcePlay(src
->al_src
);
2759 IXAudio2VoiceCallback_OnVoiceProcessingPassEnd(src
->cb
);
2761 LeaveCriticalSection(&src
->lock
);
2764 hr
= IAudioRenderClient_GetBuffer(This
->render
, nframes
, &buf
);
2766 WARN("GetBuffer failed: %08x\n", hr
);
2768 palcRenderSamplesSOFT(This
->al_device
, buf
, nframes
);
2770 hr
= IAudioRenderClient_ReleaseBuffer(This
->render
, nframes
, 0);
2772 WARN("ReleaseBuffer failed: %08x\n", hr
);
2774 for(i
= 0; i
< This
->ncbs
&& This
->cbs
[i
]; ++i
)
2775 IXAudio2EngineCallback_OnProcessingPassEnd(This
->cbs
[i
]);
2778 static DWORD WINAPI
engine_threadproc(void *arg
)
2780 IXAudio2Impl
*This
= arg
;
2782 WaitForSingleObject(This
->mmevt
, INFINITE
);
2784 if(This
->stop_engine
)
2787 EnterCriticalSection(&This
->lock
);
2789 if(!This
->running
|| !This
->aclient
){
2790 LeaveCriticalSection(&This
->lock
);
2794 do_engine_tick(This
);
2796 LeaveCriticalSection(&This
->lock
);