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
25 #include "xaudio_private.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(xaudio2
);
35 WINE_DECLARE_DEBUG_CHANNEL(winediag
);
37 static ALCdevice
*(ALC_APIENTRY
*palcLoopbackOpenDeviceSOFT
)(const ALCchar
*);
38 static void (ALC_APIENTRY
*palcRenderSamplesSOFT
)(ALCdevice
*, ALCvoid
*, ALCsizei
);
39 static ALCboolean (ALC_APIENTRY
*palcSetThreadContext
)(ALCcontext
*);
41 static HINSTANCE instance
;
43 #define IN_AL_PERIODS 4
46 #define COMPAT_E_INVALID_CALL E_INVALIDARG
47 #define COMPAT_E_DEVICE_INVALIDATED XAUDIO20_E_DEVICE_INVALIDATED
49 #define COMPAT_E_INVALID_CALL XAUDIO2_E_INVALID_CALL
50 #define COMPAT_E_DEVICE_INVALIDATED XAUDIO2_E_DEVICE_INVALIDATED
53 static void dump_fmt(const WAVEFORMATEX
*fmt
)
55 TRACE("wFormatTag: 0x%x (", fmt
->wFormatTag
);
56 switch(fmt
->wFormatTag
){
57 #define DOCASE(x) case x: TRACE(#x); break;
58 DOCASE(WAVE_FORMAT_PCM
)
59 DOCASE(WAVE_FORMAT_IEEE_FLOAT
)
60 DOCASE(WAVE_FORMAT_EXTENSIBLE
)
68 TRACE("nChannels: %u\n", fmt
->nChannels
);
69 TRACE("nSamplesPerSec: %u\n", fmt
->nSamplesPerSec
);
70 TRACE("nAvgBytesPerSec: %u\n", fmt
->nAvgBytesPerSec
);
71 TRACE("nBlockAlign: %u\n", fmt
->nBlockAlign
);
72 TRACE("wBitsPerSample: %u\n", fmt
->wBitsPerSample
);
73 TRACE("cbSize: %u\n", fmt
->cbSize
);
75 if(fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
){
76 WAVEFORMATEXTENSIBLE
*fmtex
= (void*)fmt
;
77 TRACE("dwChannelMask: %08x\n", fmtex
->dwChannelMask
);
78 TRACE("Samples: %04x\n", fmtex
->Samples
.wReserved
);
79 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex
->SubFormat
));
80 }else if(fmt
->wFormatTag
== WAVE_FORMAT_ADPCM
){
81 ADPCMWAVEFORMAT
*fmtadpcm
= (void*)fmt
;
82 TRACE("wSamplesPerBlock: %u\n", fmtadpcm
->wSamplesPerBlock
);
86 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD reason
, void *pReserved
)
88 TRACE("(%p, %d, %p)\n", hinstDLL
, reason
, pReserved
);
92 case DLL_PROCESS_ATTACH
:
94 DisableThreadLibraryCalls( hinstDLL
);
96 if(!alcIsExtensionPresent(NULL
, "ALC_SOFT_loopback") ||
97 !(palcLoopbackOpenDeviceSOFT
= alcGetProcAddress(NULL
, "alcLoopbackOpenDeviceSOFT")) ||
98 !(palcRenderSamplesSOFT
= alcGetProcAddress(NULL
, "alcRenderSamplesSOFT"))){
99 ERR("XAudio2 requires the ALC_SOFT_loopback extension (OpenAL-Soft >= 1.14)\n");
103 if(!alcIsExtensionPresent(NULL
, "ALC_EXT_thread_local_context") ||
104 !(palcSetThreadContext
= alcGetProcAddress(NULL
, "alcSetThreadContext"))){
105 ERR("XAudio2 requires the ALC_EXT_thread_local_context extension (OpenAL-Soft >= 1.12)\n");
114 HRESULT WINAPI
DllCanUnloadNow(void)
119 HRESULT WINAPI
DllRegisterServer(void)
122 return __wine_register_resources(instance
);
125 HRESULT WINAPI
DllUnregisterServer(void)
128 return __wine_unregister_resources(instance
);
131 static XA2SourceImpl
*impl_from_IXAudio2SourceVoice(IXAudio2SourceVoice
*iface
)
133 return CONTAINING_RECORD(iface
, XA2SourceImpl
, IXAudio2SourceVoice_iface
);
136 static XA2SubmixImpl
*impl_from_IXAudio2SubmixVoice(IXAudio2SubmixVoice
*iface
)
138 return CONTAINING_RECORD(iface
, XA2SubmixImpl
, IXAudio2SubmixVoice_iface
);
141 static inline IXAudio2Impl
*impl_from_IXAudio2(IXAudio2
*iface
)
143 return CONTAINING_RECORD(iface
, IXAudio2Impl
, IXAudio2_iface
);
146 static IXAudio2Impl
*impl_from_IXAudio2MasteringVoice(IXAudio2MasteringVoice
*iface
)
148 return CONTAINING_RECORD(iface
, IXAudio2Impl
, IXAudio2MasteringVoice_iface
);
151 static DWORD
get_channel_mask(unsigned int channels
)
157 return KSAUDIO_SPEAKER_MONO
;
159 return KSAUDIO_SPEAKER_STEREO
;
161 return KSAUDIO_SPEAKER_STEREO
| SPEAKER_LOW_FREQUENCY
;
163 return KSAUDIO_SPEAKER_QUAD
; /* not _SURROUND */
165 return KSAUDIO_SPEAKER_QUAD
| SPEAKER_LOW_FREQUENCY
;
167 return KSAUDIO_SPEAKER_5POINT1
; /* not 5POINT1_SURROUND */
169 return KSAUDIO_SPEAKER_5POINT1
| SPEAKER_BACK_CENTER
;
171 return KSAUDIO_SPEAKER_7POINT1_SURROUND
; /* Vista deprecates 7POINT1 */
173 FIXME("Unknown speaker configuration: %u\n", channels
);
177 static void WINAPI
XA2SRC_GetVoiceDetails(IXAudio2SourceVoice
*iface
,
178 XAUDIO2_VOICE_DETAILS
*pVoiceDetails
)
180 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
182 TRACE("%p, %p\n", This
, pVoiceDetails
);
184 pVoiceDetails
->CreationFlags
= 0;
185 pVoiceDetails
->ActiveFlags
= 0;
186 pVoiceDetails
->InputChannels
= This
->fmt
->nChannels
;
187 pVoiceDetails
->InputSampleRate
= This
->fmt
->nSamplesPerSec
;
190 static HRESULT WINAPI
XA2SRC_SetOutputVoices(IXAudio2SourceVoice
*iface
,
191 const XAUDIO2_VOICE_SENDS
*pSendList
)
193 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
195 XAUDIO2_VOICE_SENDS def_send
;
196 XAUDIO2_SEND_DESCRIPTOR def_desc
;
198 TRACE("%p, %p\n", This
, pSendList
);
202 def_desc
.pOutputVoice
= (IXAudio2Voice
*)&This
->xa2
->IXAudio2MasteringVoice_iface
;
204 def_send
.SendCount
= 1;
205 def_send
.pSends
= &def_desc
;
207 pSendList
= &def_send
;
210 if(TRACE_ON(xaudio2
)){
211 for(i
= 0; i
< pSendList
->SendCount
; ++i
){
212 XAUDIO2_SEND_DESCRIPTOR
*desc
= &pSendList
->pSends
[i
];
213 TRACE("Outputting to: 0x%x, %p\n", desc
->Flags
, desc
->pOutputVoice
);
217 if(This
->nsends
< pSendList
->SendCount
){
218 HeapFree(GetProcessHeap(), 0, This
->sends
);
219 This
->sends
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
->sends
) * pSendList
->SendCount
);
220 This
->nsends
= pSendList
->SendCount
;
222 memset(This
->sends
, 0, sizeof(*This
->sends
) * This
->nsends
);
224 memcpy(This
->sends
, pSendList
->pSends
, sizeof(*This
->sends
) * pSendList
->SendCount
);
229 static HRESULT WINAPI
XA2SRC_SetEffectChain(IXAudio2SourceVoice
*iface
,
230 const XAUDIO2_EFFECT_CHAIN
*pEffectChain
)
232 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
233 TRACE("%p, %p\n", This
, pEffectChain
);
237 static HRESULT WINAPI
XA2SRC_EnableEffect(IXAudio2SourceVoice
*iface
,
238 UINT32 EffectIndex
, UINT32 OperationSet
)
240 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
241 TRACE("%p, %u, 0x%x\n", This
, EffectIndex
, OperationSet
);
245 static HRESULT WINAPI
XA2SRC_DisableEffect(IXAudio2SourceVoice
*iface
,
246 UINT32 EffectIndex
, UINT32 OperationSet
)
248 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
249 TRACE("%p, %u, 0x%x\n", This
, EffectIndex
, OperationSet
);
253 static void WINAPI
XA2SRC_GetEffectState(IXAudio2SourceVoice
*iface
,
254 UINT32 EffectIndex
, BOOL
*pEnabled
)
256 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
257 TRACE("%p, %u, %p\n", This
, EffectIndex
, pEnabled
);
260 static HRESULT WINAPI
XA2SRC_SetEffectParameters(IXAudio2SourceVoice
*iface
,
261 UINT32 EffectIndex
, const void *pParameters
, UINT32 ParametersByteSize
,
264 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
265 TRACE("%p, %u, %p, 0x%x, 0x%x\n", This
, EffectIndex
, pParameters
,
266 ParametersByteSize
, OperationSet
);
270 static HRESULT WINAPI
XA2SRC_GetEffectParameters(IXAudio2SourceVoice
*iface
,
271 UINT32 EffectIndex
, void *pParameters
, UINT32 ParametersByteSize
)
273 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
274 TRACE("%p, %u, %p, 0x%x\n", This
, EffectIndex
, pParameters
,
279 static HRESULT WINAPI
XA2SRC_SetFilterParameters(IXAudio2SourceVoice
*iface
,
280 const XAUDIO2_FILTER_PARAMETERS
*pParameters
, UINT32 OperationSet
)
282 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
283 TRACE("%p, %p, 0x%x\n", This
, pParameters
, OperationSet
);
287 static void WINAPI
XA2SRC_GetFilterParameters(IXAudio2SourceVoice
*iface
,
288 XAUDIO2_FILTER_PARAMETERS
*pParameters
)
290 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
291 TRACE("%p, %p\n", This
, pParameters
);
294 static HRESULT WINAPI
XA2SRC_SetOutputFilterParameters(IXAudio2SourceVoice
*iface
,
295 IXAudio2Voice
*pDestinationVoice
,
296 const XAUDIO2_FILTER_PARAMETERS
*pParameters
, UINT32 OperationSet
)
298 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
299 TRACE("%p, %p, %p, 0x%x\n", This
, pDestinationVoice
, pParameters
, OperationSet
);
303 static void WINAPI
XA2SRC_GetOutputFilterParameters(IXAudio2SourceVoice
*iface
,
304 IXAudio2Voice
*pDestinationVoice
,
305 XAUDIO2_FILTER_PARAMETERS
*pParameters
)
307 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
308 TRACE("%p, %p, %p\n", This
, pDestinationVoice
, pParameters
);
311 static HRESULT WINAPI
XA2SRC_SetVolume(IXAudio2SourceVoice
*iface
, float Volume
,
314 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
317 TRACE("%p, %f, 0x%x\n", This
, Volume
, OperationSet
);
321 palcSetThreadContext(This
->xa2
->al_ctx
);
323 alSourcef(This
->al_src
, AL_GAIN
, al_gain
);
328 static void WINAPI
XA2SRC_GetVolume(IXAudio2SourceVoice
*iface
, float *pVolume
)
330 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
331 TRACE("%p, %p\n", This
, pVolume
);
334 static HRESULT WINAPI
XA2SRC_SetChannelVolumes(IXAudio2SourceVoice
*iface
,
335 UINT32 Channels
, const float *pVolumes
, UINT32 OperationSet
)
337 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
340 BOOL same_volumes_given
= TRUE
;
342 TRACE("%p, %u, %p, 0x%x\n", This
, Channels
, pVolumes
, OperationSet
);
345 if(Channels
!= This
->fmt
->nChannels
|| !pVolumes
)
346 return COMPAT_E_INVALID_CALL
;
351 /* check whether all volumes are the same */
352 for(i
= 1; i
< Channels
; ++i
){
353 if(al_gain
!= *(pVolumes
+ i
)){
354 same_volumes_given
= FALSE
;
358 if(!same_volumes_given
){
359 WARN("Different volumes for channels unsupported, setting the highest volume.\n");
360 for(; i
< Channels
; ++i
)
361 al_gain
= max(al_gain
, *(pVolumes
+ i
));
364 palcSetThreadContext(This
->xa2
->al_ctx
);
365 alSourcef(This
->al_src
, AL_GAIN
, al_gain
);
370 static void WINAPI
XA2SRC_GetChannelVolumes(IXAudio2SourceVoice
*iface
,
371 UINT32 Channels
, float *pVolumes
)
373 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
374 TRACE("%p, %u, %p\n", This
, Channels
, pVolumes
);
377 static HRESULT WINAPI
XA2SRC_SetOutputMatrix(IXAudio2SourceVoice
*iface
,
378 IXAudio2Voice
*pDestinationVoice
, UINT32 SourceChannels
,
379 UINT32 DestinationChannels
, const float *pLevelMatrix
,
382 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
383 TRACE("%p, %p, %u, %u, %p, 0x%x\n", This
, pDestinationVoice
,
384 SourceChannels
, DestinationChannels
, pLevelMatrix
, OperationSet
);
388 static void WINAPI
XA2SRC_GetOutputMatrix(IXAudio2SourceVoice
*iface
,
389 IXAudio2Voice
*pDestinationVoice
, UINT32 SourceChannels
,
390 UINT32 DestinationChannels
, float *pLevelMatrix
)
392 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
393 TRACE("%p, %p, %u, %u, %p\n", This
, pDestinationVoice
,
394 SourceChannels
, DestinationChannels
, pLevelMatrix
);
397 static void WINAPI
XA2SRC_DestroyVoice(IXAudio2SourceVoice
*iface
)
399 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
404 palcSetThreadContext(This
->xa2
->al_ctx
);
406 EnterCriticalSection(&This
->lock
);
409 LeaveCriticalSection(&This
->lock
);
413 This
->in_use
= FALSE
;
415 This
->running
= FALSE
;
417 IXAudio2SourceVoice_Stop(iface
, 0, 0);
419 alSourceStop(This
->al_src
);
421 /* unqueue all buffers */
422 alSourcei(This
->al_src
, AL_BUFFER
, AL_NONE
);
424 alGetSourcei(This
->al_src
, AL_BUFFERS_PROCESSED
, &processed
);
427 ALuint al_buffers
[XAUDIO2_MAX_QUEUED_BUFFERS
];
429 alSourceUnqueueBuffers(This
->al_src
, processed
, al_buffers
);
432 HeapFree(GetProcessHeap(), 0, This
->fmt
);
434 alDeleteBuffers(XAUDIO2_MAX_QUEUED_BUFFERS
, This
->al_bufs
);
435 alDeleteSources(1, &This
->al_src
);
437 This
->in_al_bytes
= 0;
438 This
->al_bufs_used
= 0;
439 This
->played_frames
= 0;
443 This
->abandoned_albufs
= 0;
445 LeaveCriticalSection(&This
->lock
);
448 static HRESULT WINAPI
XA2SRC_Start(IXAudio2SourceVoice
*iface
, UINT32 Flags
,
451 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
453 TRACE("%p, 0x%x, 0x%x\n", This
, Flags
, OperationSet
);
455 EnterCriticalSection(&This
->lock
);
457 This
->running
= TRUE
;
459 LeaveCriticalSection(&This
->lock
);
464 static HRESULT WINAPI
XA2SRC_Stop(IXAudio2SourceVoice
*iface
, UINT32 Flags
,
467 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
470 TRACE("%p, 0x%x, 0x%x\n", This
, Flags
, OperationSet
);
472 palcSetThreadContext(This
->xa2
->al_ctx
);
474 EnterCriticalSection(&This
->lock
);
476 alGetSourcei(This
->al_src
, AL_BUFFERS_QUEUED
, &bufs
);
478 This
->abandoned_albufs
= bufs
;
480 This
->running
= FALSE
;
482 LeaveCriticalSection(&This
->lock
);
487 static ALenum
get_al_format(const WAVEFORMATEX
*fmt
)
489 WAVEFORMATEXTENSIBLE
*fmtex
= (WAVEFORMATEXTENSIBLE
*)fmt
;
490 if(fmt
->wFormatTag
== WAVE_FORMAT_PCM
||
491 (fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
&&
492 IsEqualGUID(&fmtex
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
))){
493 switch(fmt
->wBitsPerSample
){
495 switch(fmt
->nChannels
){
497 return AL_FORMAT_MONO8
;
499 return AL_FORMAT_STEREO8
;
501 return AL_FORMAT_QUAD8
;
503 return AL_FORMAT_51CHN8
;
505 return AL_FORMAT_61CHN8
;
507 return AL_FORMAT_71CHN8
;
511 switch(fmt
->nChannels
){
513 return AL_FORMAT_MONO16
;
515 return AL_FORMAT_STEREO16
;
517 return AL_FORMAT_QUAD16
;
519 return AL_FORMAT_51CHN16
;
521 return AL_FORMAT_61CHN16
;
523 return AL_FORMAT_71CHN16
;
527 }else if(fmt
->wFormatTag
== WAVE_FORMAT_IEEE_FLOAT
||
528 (fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
&&
529 IsEqualGUID(&fmtex
->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
))){
530 if(fmt
->wBitsPerSample
== 32){
531 switch(fmt
->nChannels
){
533 return AL_FORMAT_MONO_FLOAT32
;
535 return AL_FORMAT_STEREO_FLOAT32
;
537 return AL_FORMAT_QUAD32
;
539 return AL_FORMAT_51CHN32
;
541 return AL_FORMAT_61CHN32
;
543 return AL_FORMAT_71CHN32
;
550 static HRESULT WINAPI
XA2SRC_SubmitSourceBuffer(IXAudio2SourceVoice
*iface
,
551 const XAUDIO2_BUFFER
*pBuffer
, const XAUDIO2_BUFFER_WMA
*pBufferWMA
)
553 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
557 TRACE("%p, %p, %p\n", This
, pBuffer
, pBufferWMA
);
559 if(TRACE_ON(xaudio2
)){
560 TRACE("Flags: 0x%x\n", pBuffer
->Flags
);
561 TRACE("AudioBytes: %u\n", pBuffer
->AudioBytes
);
562 TRACE("pAudioData: %p\n", pBuffer
->pAudioData
);
563 TRACE("PlayBegin: %u\n", pBuffer
->PlayBegin
);
564 TRACE("PlayLength: %u\n", pBuffer
->PlayLength
);
565 TRACE("LoopBegin: %u\n", pBuffer
->LoopBegin
);
566 TRACE("LoopLength: %u\n", pBuffer
->LoopLength
);
567 TRACE("LoopCount: %u\n", pBuffer
->LoopCount
);
568 TRACE("pContext: %p\n", pBuffer
->pContext
);
571 EnterCriticalSection(&This
->lock
);
573 if(This
->nbufs
>= XAUDIO2_MAX_QUEUED_BUFFERS
){
574 TRACE("Too many buffers queued!\n");
575 LeaveCriticalSection(&This
->lock
);
576 return COMPAT_E_INVALID_CALL
;
579 buf_idx
= (This
->first_buf
+ This
->nbufs
) % XAUDIO2_MAX_QUEUED_BUFFERS
;
580 buf
= &This
->buffers
[buf_idx
];
581 memset(buf
, 0, sizeof(*buf
));
583 /* API contract: pAudioData must remain valid until this buffer is played,
584 * but pBuffer itself may be reused immediately */
585 memcpy(&buf
->xa2buffer
, pBuffer
, sizeof(*pBuffer
));
588 if(buf
->xa2buffer
.LoopCount
== XAUDIO20_LOOP_INFINITE
)
589 buf
->xa2buffer
.LoopCount
= XAUDIO2_LOOP_INFINITE
;
592 /* convert samples offsets to bytes */
593 if(This
->fmt
->wFormatTag
== WAVE_FORMAT_ADPCM
){
594 /* ADPCM gives us a number of samples per block, so round down to
595 * nearest block and convert to bytes */
596 buf
->xa2buffer
.PlayBegin
= buf
->xa2buffer
.PlayBegin
/ ((ADPCMWAVEFORMAT
*)This
->fmt
)->wSamplesPerBlock
* This
->fmt
->nBlockAlign
;
597 buf
->xa2buffer
.PlayLength
= buf
->xa2buffer
.PlayLength
/ ((ADPCMWAVEFORMAT
*)This
->fmt
)->wSamplesPerBlock
* This
->fmt
->nBlockAlign
;
598 buf
->xa2buffer
.LoopBegin
= buf
->xa2buffer
.LoopBegin
/ ((ADPCMWAVEFORMAT
*)This
->fmt
)->wSamplesPerBlock
* This
->fmt
->nBlockAlign
;
599 buf
->xa2buffer
.LoopLength
= buf
->xa2buffer
.LoopLength
/ ((ADPCMWAVEFORMAT
*)This
->fmt
)->wSamplesPerBlock
* This
->fmt
->nBlockAlign
;
601 buf
->xa2buffer
.PlayBegin
*= This
->fmt
->nBlockAlign
;
602 buf
->xa2buffer
.PlayLength
*= This
->fmt
->nBlockAlign
;
603 buf
->xa2buffer
.LoopBegin
*= This
->fmt
->nBlockAlign
;
604 buf
->xa2buffer
.LoopLength
*= This
->fmt
->nBlockAlign
;
607 if(buf
->xa2buffer
.PlayLength
== 0)
608 /* set to end of buffer */
609 buf
->xa2buffer
.PlayLength
= buf
->xa2buffer
.AudioBytes
- buf
->xa2buffer
.PlayBegin
;
611 buf
->play_end_bytes
= buf
->xa2buffer
.PlayBegin
+ buf
->xa2buffer
.PlayLength
;
613 if(buf
->xa2buffer
.LoopCount
){
614 if(buf
->xa2buffer
.LoopLength
== 0)
615 /* set to end of play range */
616 buf
->xa2buffer
.LoopLength
= buf
->play_end_bytes
- buf
->xa2buffer
.LoopBegin
;
618 if(buf
->xa2buffer
.LoopBegin
>= buf
->play_end_bytes
){
619 /* this actually crashes on native xaudio 2.7 */
620 LeaveCriticalSection(&This
->lock
);
621 return COMPAT_E_INVALID_CALL
;
624 buf
->loop_end_bytes
= buf
->xa2buffer
.LoopBegin
+ buf
->xa2buffer
.LoopLength
;
626 /* xaudio 2.7 allows some invalid looping setups, but later versions
629 if(buf
->loop_end_bytes
> buf
->play_end_bytes
){
630 LeaveCriticalSection(&This
->lock
);
631 return COMPAT_E_INVALID_CALL
;
634 if(buf
->loop_end_bytes
<= buf
->xa2buffer
.PlayBegin
){
635 LeaveCriticalSection(&This
->lock
);
636 return COMPAT_E_INVALID_CALL
;
639 if(buf
->loop_end_bytes
<= buf
->xa2buffer
.PlayBegin
){
640 buf
->xa2buffer
.LoopCount
= 0;
641 buf
->loop_end_bytes
= buf
->play_end_bytes
;
645 buf
->xa2buffer
.LoopLength
= buf
->xa2buffer
.PlayLength
;
646 buf
->xa2buffer
.LoopBegin
= buf
->xa2buffer
.PlayBegin
;
647 buf
->loop_end_bytes
= buf
->play_end_bytes
;
650 buf
->offs_bytes
= buf
->xa2buffer
.PlayBegin
;
651 buf
->cur_end_bytes
= buf
->loop_end_bytes
;
653 buf
->latest_al_buf
= -1;
657 TRACE("%p: queued buffer %u (%u bytes), now %u buffers held\n",
658 This
, buf_idx
, buf
->xa2buffer
.AudioBytes
, This
->nbufs
);
660 LeaveCriticalSection(&This
->lock
);
665 static HRESULT WINAPI
XA2SRC_FlushSourceBuffers(IXAudio2SourceVoice
*iface
)
667 UINT i
, first
, last
, to_flush
;
668 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
672 EnterCriticalSection(&This
->lock
);
674 if(This
->running
&& This
->nbufs
> 0){
675 /* when running, flush only completely unused buffers; the rest remain
677 last
= (This
->first_buf
+ This
->nbufs
) % XAUDIO2_MAX_QUEUED_BUFFERS
;
678 first
= (This
->cur_buf
+ 1) % XAUDIO2_MAX_QUEUED_BUFFERS
;
679 if(This
->cur_buf
== last
)
682 else if(last
>= first
)
683 to_flush
= last
- first
;
685 to_flush
= last
+ XAUDIO2_MAX_QUEUED_BUFFERS
- first
;
687 /* when stopped, flush all buffers */
688 first
= This
->first_buf
;
689 last
= (This
->first_buf
+ This
->nbufs
) % XAUDIO2_MAX_QUEUED_BUFFERS
;
690 to_flush
= This
->nbufs
;
695 i
< (first
+ to_flush
) % XAUDIO2_MAX_QUEUED_BUFFERS
;
696 i
= (i
+ 1) % XAUDIO2_MAX_QUEUED_BUFFERS
){
698 IXAudio2VoiceCallback_OnBufferEnd(This
->cb
,
699 This
->buffers
[i
].xa2buffer
.pContext
);
702 This
->nbufs
-= to_flush
;
703 This
->cur_buf
= (This
->first_buf
+ This
->nbufs
) % XAUDIO2_MAX_QUEUED_BUFFERS
;
705 LeaveCriticalSection(&This
->lock
);
710 static HRESULT WINAPI
XA2SRC_Discontinuity(IXAudio2SourceVoice
*iface
)
712 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
716 EnterCriticalSection(&This
->lock
);
719 DWORD last
= (This
->first_buf
+ This
->nbufs
- 1) % XAUDIO2_MAX_QUEUED_BUFFERS
;
720 This
->buffers
[last
].xa2buffer
.Flags
|= XAUDIO2_END_OF_STREAM
;
723 LeaveCriticalSection(&This
->lock
);
728 static HRESULT WINAPI
XA2SRC_ExitLoop(IXAudio2SourceVoice
*iface
, UINT32 OperationSet
)
730 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
732 TRACE("%p, 0x%x\n", This
, OperationSet
);
734 EnterCriticalSection(&This
->lock
);
736 This
->buffers
[This
->cur_buf
].looped
= XAUDIO2_LOOP_INFINITE
;
738 LeaveCriticalSection(&This
->lock
);
743 static void WINAPI
XA2SRC_GetState(IXAudio2SourceVoice
*iface
,
744 XAUDIO2_VOICE_STATE
*pVoiceState
, UINT32 Flags
)
746 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
748 TRACE("%p, %p, 0x%x\n", This
, pVoiceState
, Flags
);
750 EnterCriticalSection(&This
->lock
);
752 if(!(Flags
& XAUDIO2_VOICE_NOSAMPLESPLAYED
))
753 pVoiceState
->SamplesPlayed
= This
->played_frames
;
755 pVoiceState
->SamplesPlayed
= 0;
758 pVoiceState
->pCurrentBufferContext
= This
->buffers
[This
->first_buf
].xa2buffer
.pContext
;
760 pVoiceState
->pCurrentBufferContext
= NULL
;
762 pVoiceState
->BuffersQueued
= This
->nbufs
;
764 LeaveCriticalSection(&This
->lock
);
766 TRACE("returning %s, queued: %u\n", wine_dbgstr_longlong(pVoiceState
->SamplesPlayed
), This
->nbufs
);
769 static HRESULT WINAPI
XA2SRC_SetFrequencyRatio(IXAudio2SourceVoice
*iface
,
770 float Ratio
, UINT32 OperationSet
)
772 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
775 TRACE("%p, %f, 0x%x\n", This
, Ratio
, OperationSet
);
777 if(Ratio
< XAUDIO2_MIN_FREQ_RATIO
)
778 r
= XAUDIO2_MIN_FREQ_RATIO
;
779 else if (Ratio
> XAUDIO2_MAX_FREQ_RATIO
)
780 r
= XAUDIO2_MAX_FREQ_RATIO
;
784 palcSetThreadContext(This
->xa2
->al_ctx
);
786 alSourcef(This
->al_src
, AL_PITCH
, r
);
791 static void WINAPI
XA2SRC_GetFrequencyRatio(IXAudio2SourceVoice
*iface
, float *pRatio
)
794 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
796 TRACE("%p, %p\n", This
, pRatio
);
798 palcSetThreadContext(This
->xa2
->al_ctx
);
800 alGetSourcef(This
->al_src
, AL_PITCH
, &ratio
);
805 static HRESULT WINAPI
XA2SRC_SetSourceSampleRate(
806 IXAudio2SourceVoice
*iface
,
807 UINT32 NewSourceSampleRate
)
809 XA2SourceImpl
*This
= impl_from_IXAudio2SourceVoice(iface
);
811 TRACE("%p, %u\n", This
, NewSourceSampleRate
);
813 EnterCriticalSection(&This
->lock
);
816 LeaveCriticalSection(&This
->lock
);
817 return COMPAT_E_INVALID_CALL
;
820 This
->fmt
->nSamplesPerSec
= NewSourceSampleRate
;
822 LeaveCriticalSection(&This
->lock
);
827 static const IXAudio2SourceVoiceVtbl XAudio2SourceVoice_Vtbl
= {
828 XA2SRC_GetVoiceDetails
,
829 XA2SRC_SetOutputVoices
,
830 XA2SRC_SetEffectChain
,
832 XA2SRC_DisableEffect
,
833 XA2SRC_GetEffectState
,
834 XA2SRC_SetEffectParameters
,
835 XA2SRC_GetEffectParameters
,
836 XA2SRC_SetFilterParameters
,
837 XA2SRC_GetFilterParameters
,
838 XA2SRC_SetOutputFilterParameters
,
839 XA2SRC_GetOutputFilterParameters
,
842 XA2SRC_SetChannelVolumes
,
843 XA2SRC_GetChannelVolumes
,
844 XA2SRC_SetOutputMatrix
,
845 XA2SRC_GetOutputMatrix
,
849 XA2SRC_SubmitSourceBuffer
,
850 XA2SRC_FlushSourceBuffers
,
851 XA2SRC_Discontinuity
,
854 XA2SRC_SetFrequencyRatio
,
855 XA2SRC_GetFrequencyRatio
,
856 XA2SRC_SetSourceSampleRate
859 static void WINAPI
XA2M_GetVoiceDetails(IXAudio2MasteringVoice
*iface
,
860 XAUDIO2_VOICE_DETAILS
*pVoiceDetails
)
862 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
863 TRACE("%p, %p\n", This
, pVoiceDetails
);
864 pVoiceDetails
->CreationFlags
= 0;
865 pVoiceDetails
->ActiveFlags
= 0;
866 pVoiceDetails
->InputChannels
= This
->fmt
.Format
.nChannels
;
867 pVoiceDetails
->InputSampleRate
= This
->fmt
.Format
.nSamplesPerSec
;
870 static HRESULT WINAPI
XA2M_SetOutputVoices(IXAudio2MasteringVoice
*iface
,
871 const XAUDIO2_VOICE_SENDS
*pSendList
)
873 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
874 TRACE("%p, %p\n", This
, pSendList
);
878 static HRESULT WINAPI
XA2M_SetEffectChain(IXAudio2MasteringVoice
*iface
,
879 const XAUDIO2_EFFECT_CHAIN
*pEffectChain
)
881 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
882 TRACE("%p, %p\n", This
, pEffectChain
);
886 static HRESULT WINAPI
XA2M_EnableEffect(IXAudio2MasteringVoice
*iface
, UINT32 EffectIndex
,
889 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
890 TRACE("%p, %u, 0x%x\n", This
, EffectIndex
, OperationSet
);
894 static HRESULT WINAPI
XA2M_DisableEffect(IXAudio2MasteringVoice
*iface
, UINT32 EffectIndex
,
897 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
898 TRACE("%p, %u, 0x%x\n", This
, EffectIndex
, OperationSet
);
902 static void WINAPI
XA2M_GetEffectState(IXAudio2MasteringVoice
*iface
, UINT32 EffectIndex
,
905 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
906 TRACE("%p, %u, %p\n", This
, EffectIndex
, pEnabled
);
909 static HRESULT WINAPI
XA2M_SetEffectParameters(IXAudio2MasteringVoice
*iface
,
910 UINT32 EffectIndex
, const void *pParameters
, UINT32 ParametersByteSize
,
913 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
914 TRACE("%p, %u, %p, 0x%x, 0x%x\n", This
, EffectIndex
, pParameters
,
915 ParametersByteSize
, OperationSet
);
919 static HRESULT WINAPI
XA2M_GetEffectParameters(IXAudio2MasteringVoice
*iface
,
920 UINT32 EffectIndex
, void *pParameters
, UINT32 ParametersByteSize
)
922 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
923 TRACE("%p, %u, %p, 0x%x\n", This
, EffectIndex
, pParameters
,
928 static HRESULT WINAPI
XA2M_SetFilterParameters(IXAudio2MasteringVoice
*iface
,
929 const XAUDIO2_FILTER_PARAMETERS
*pParameters
, UINT32 OperationSet
)
931 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
932 TRACE("%p, %p, 0x%x\n", This
, pParameters
, OperationSet
);
936 static void WINAPI
XA2M_GetFilterParameters(IXAudio2MasteringVoice
*iface
,
937 XAUDIO2_FILTER_PARAMETERS
*pParameters
)
939 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
940 TRACE("%p, %p\n", This
, pParameters
);
943 static HRESULT WINAPI
XA2M_SetOutputFilterParameters(IXAudio2MasteringVoice
*iface
,
944 IXAudio2Voice
*pDestinationVoice
,
945 const XAUDIO2_FILTER_PARAMETERS
*pParameters
, UINT32 OperationSet
)
947 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
948 TRACE("%p, %p, %p, 0x%x\n", This
, pDestinationVoice
, pParameters
, OperationSet
);
952 static void WINAPI
XA2M_GetOutputFilterParameters(IXAudio2MasteringVoice
*iface
,
953 IXAudio2Voice
*pDestinationVoice
,
954 XAUDIO2_FILTER_PARAMETERS
*pParameters
)
956 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
957 TRACE("%p, %p, %p\n", This
, pDestinationVoice
, pParameters
);
960 static HRESULT WINAPI
XA2M_SetVolume(IXAudio2MasteringVoice
*iface
, float Volume
,
963 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
964 TRACE("%p, %f, 0x%x\n", This
, Volume
, OperationSet
);
968 static void WINAPI
XA2M_GetVolume(IXAudio2MasteringVoice
*iface
, float *pVolume
)
970 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
971 TRACE("%p, %p\n", This
, pVolume
);
974 static HRESULT WINAPI
XA2M_SetChannelVolumes(IXAudio2MasteringVoice
*iface
, UINT32 Channels
,
975 const float *pVolumes
, UINT32 OperationSet
)
977 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
978 TRACE("%p, %u, %p, 0x%x\n", This
, Channels
, pVolumes
, OperationSet
);
982 static void WINAPI
XA2M_GetChannelVolumes(IXAudio2MasteringVoice
*iface
, UINT32 Channels
,
985 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
986 TRACE("%p, %u, %p\n", This
, Channels
, pVolumes
);
989 static HRESULT WINAPI
XA2M_SetOutputMatrix(IXAudio2MasteringVoice
*iface
,
990 IXAudio2Voice
*pDestinationVoice
, UINT32 SourceChannels
,
991 UINT32 DestinationChannels
, const float *pLevelMatrix
,
994 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
995 TRACE("%p, %p, %u, %u, %p, 0x%x\n", This
, pDestinationVoice
,
996 SourceChannels
, DestinationChannels
, pLevelMatrix
, OperationSet
);
1000 static void WINAPI
XA2M_GetOutputMatrix(IXAudio2MasteringVoice
*iface
,
1001 IXAudio2Voice
*pDestinationVoice
, UINT32 SourceChannels
,
1002 UINT32 DestinationChannels
, float *pLevelMatrix
)
1004 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
1005 TRACE("%p, %p, %u, %u, %p\n", This
, pDestinationVoice
,
1006 SourceChannels
, DestinationChannels
, pLevelMatrix
);
1009 static void WINAPI
XA2M_DestroyVoice(IXAudio2MasteringVoice
*iface
)
1011 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
1013 TRACE("%p\n", This
);
1015 EnterCriticalSection(&This
->lock
);
1018 LeaveCriticalSection(&This
->lock
);
1022 This
->running
= FALSE
;
1024 IAudioRenderClient_Release(This
->render
);
1025 This
->render
= NULL
;
1027 IAudioClient_Release(This
->aclient
);
1028 This
->aclient
= NULL
;
1030 alcDestroyContext(This
->al_ctx
);
1031 This
->al_ctx
= NULL
;
1033 alcCloseDevice(This
->al_device
);
1034 This
->al_device
= NULL
;
1036 LeaveCriticalSection(&This
->lock
);
1039 /* not present in XAudio2 2.7 */
1040 static void WINAPI
XA2M_GetChannelMask(IXAudio2MasteringVoice
*iface
,
1041 DWORD
*pChannelMask
)
1043 IXAudio2Impl
*This
= impl_from_IXAudio2MasteringVoice(iface
);
1045 TRACE("%p %p\n", This
, pChannelMask
);
1047 *pChannelMask
= This
->fmt
.dwChannelMask
;
1050 static const struct IXAudio2MasteringVoiceVtbl XAudio2MasteringVoice_Vtbl
= {
1051 XA2M_GetVoiceDetails
,
1052 XA2M_SetOutputVoices
,
1053 XA2M_SetEffectChain
,
1056 XA2M_GetEffectState
,
1057 XA2M_SetEffectParameters
,
1058 XA2M_GetEffectParameters
,
1059 XA2M_SetFilterParameters
,
1060 XA2M_GetFilterParameters
,
1061 XA2M_SetOutputFilterParameters
,
1062 XA2M_GetOutputFilterParameters
,
1065 XA2M_SetChannelVolumes
,
1066 XA2M_GetChannelVolumes
,
1067 XA2M_SetOutputMatrix
,
1068 XA2M_GetOutputMatrix
,
1073 static void WINAPI
XA2SUB_GetVoiceDetails(IXAudio2SubmixVoice
*iface
,
1074 XAUDIO2_VOICE_DETAILS
*pVoiceDetails
)
1076 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1078 TRACE("%p, %p\n", This
, pVoiceDetails
);
1080 *pVoiceDetails
= This
->details
;
1083 static HRESULT WINAPI
XA2SUB_SetOutputVoices(IXAudio2SubmixVoice
*iface
,
1084 const XAUDIO2_VOICE_SENDS
*pSendList
)
1086 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1087 TRACE("%p, %p\n", This
, pSendList
);
1091 static HRESULT WINAPI
XA2SUB_SetEffectChain(IXAudio2SubmixVoice
*iface
,
1092 const XAUDIO2_EFFECT_CHAIN
*pEffectChain
)
1094 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1095 TRACE("%p, %p\n", This
, pEffectChain
);
1099 static HRESULT WINAPI
XA2SUB_EnableEffect(IXAudio2SubmixVoice
*iface
, UINT32 EffectIndex
,
1100 UINT32 OperationSet
)
1102 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1103 TRACE("%p, %u, 0x%x\n", This
, EffectIndex
, OperationSet
);
1107 static HRESULT WINAPI
XA2SUB_DisableEffect(IXAudio2SubmixVoice
*iface
, UINT32 EffectIndex
,
1108 UINT32 OperationSet
)
1110 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1111 TRACE("%p, %u, 0x%x\n", This
, EffectIndex
, OperationSet
);
1115 static void WINAPI
XA2SUB_GetEffectState(IXAudio2SubmixVoice
*iface
, UINT32 EffectIndex
,
1118 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1119 TRACE("%p, %u, %p\n", This
, EffectIndex
, pEnabled
);
1122 static HRESULT WINAPI
XA2SUB_SetEffectParameters(IXAudio2SubmixVoice
*iface
,
1123 UINT32 EffectIndex
, const void *pParameters
, UINT32 ParametersByteSize
,
1124 UINT32 OperationSet
)
1126 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1127 TRACE("%p, %u, %p, 0x%x, 0x%x\n", This
, EffectIndex
, pParameters
,
1128 ParametersByteSize
, OperationSet
);
1132 static HRESULT WINAPI
XA2SUB_GetEffectParameters(IXAudio2SubmixVoice
*iface
,
1133 UINT32 EffectIndex
, void *pParameters
, UINT32 ParametersByteSize
)
1135 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1136 TRACE("%p, %u, %p, 0x%x\n", This
, EffectIndex
, pParameters
,
1137 ParametersByteSize
);
1141 static HRESULT WINAPI
XA2SUB_SetFilterParameters(IXAudio2SubmixVoice
*iface
,
1142 const XAUDIO2_FILTER_PARAMETERS
*pParameters
, UINT32 OperationSet
)
1144 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1145 TRACE("%p, %p, 0x%x\n", This
, pParameters
, OperationSet
);
1149 static void WINAPI
XA2SUB_GetFilterParameters(IXAudio2SubmixVoice
*iface
,
1150 XAUDIO2_FILTER_PARAMETERS
*pParameters
)
1152 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1153 TRACE("%p, %p\n", This
, pParameters
);
1156 static HRESULT WINAPI
XA2SUB_SetOutputFilterParameters(IXAudio2SubmixVoice
*iface
,
1157 IXAudio2Voice
*pDestinationVoice
,
1158 const XAUDIO2_FILTER_PARAMETERS
*pParameters
, UINT32 OperationSet
)
1160 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1161 TRACE("%p, %p, %p, 0x%x\n", This
, pDestinationVoice
, pParameters
, OperationSet
);
1165 static void WINAPI
XA2SUB_GetOutputFilterParameters(IXAudio2SubmixVoice
*iface
,
1166 IXAudio2Voice
*pDestinationVoice
,
1167 XAUDIO2_FILTER_PARAMETERS
*pParameters
)
1169 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1170 TRACE("%p, %p, %p\n", This
, pDestinationVoice
, pParameters
);
1173 static HRESULT WINAPI
XA2SUB_SetVolume(IXAudio2SubmixVoice
*iface
, float Volume
,
1174 UINT32 OperationSet
)
1176 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1177 TRACE("%p, %f, 0x%x\n", This
, Volume
, OperationSet
);
1181 static void WINAPI
XA2SUB_GetVolume(IXAudio2SubmixVoice
*iface
, float *pVolume
)
1183 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1184 TRACE("%p, %p\n", This
, pVolume
);
1187 static HRESULT WINAPI
XA2SUB_SetChannelVolumes(IXAudio2SubmixVoice
*iface
, UINT32 Channels
,
1188 const float *pVolumes
, UINT32 OperationSet
)
1190 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1191 TRACE("%p, %u, %p, 0x%x\n", This
, Channels
, pVolumes
, OperationSet
);
1195 static void WINAPI
XA2SUB_GetChannelVolumes(IXAudio2SubmixVoice
*iface
, UINT32 Channels
,
1198 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1199 TRACE("%p, %u, %p\n", This
, Channels
, pVolumes
);
1202 static HRESULT WINAPI
XA2SUB_SetOutputMatrix(IXAudio2SubmixVoice
*iface
,
1203 IXAudio2Voice
*pDestinationVoice
, UINT32 SourceChannels
,
1204 UINT32 DestinationChannels
, const float *pLevelMatrix
,
1205 UINT32 OperationSet
)
1207 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1208 TRACE("%p, %p, %u, %u, %p, 0x%x\n", This
, pDestinationVoice
,
1209 SourceChannels
, DestinationChannels
, pLevelMatrix
, OperationSet
);
1213 static void WINAPI
XA2SUB_GetOutputMatrix(IXAudio2SubmixVoice
*iface
,
1214 IXAudio2Voice
*pDestinationVoice
, UINT32 SourceChannels
,
1215 UINT32 DestinationChannels
, float *pLevelMatrix
)
1217 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1218 TRACE("%p, %p, %u, %u, %p\n", This
, pDestinationVoice
,
1219 SourceChannels
, DestinationChannels
, pLevelMatrix
);
1222 static void WINAPI
XA2SUB_DestroyVoice(IXAudio2SubmixVoice
*iface
)
1224 XA2SubmixImpl
*This
= impl_from_IXAudio2SubmixVoice(iface
);
1226 TRACE("%p\n", This
);
1228 EnterCriticalSection(&This
->lock
);
1230 This
->in_use
= FALSE
;
1232 LeaveCriticalSection(&This
->lock
);
1235 static const struct IXAudio2SubmixVoiceVtbl XAudio2SubmixVoice_Vtbl
= {
1236 XA2SUB_GetVoiceDetails
,
1237 XA2SUB_SetOutputVoices
,
1238 XA2SUB_SetEffectChain
,
1239 XA2SUB_EnableEffect
,
1240 XA2SUB_DisableEffect
,
1241 XA2SUB_GetEffectState
,
1242 XA2SUB_SetEffectParameters
,
1243 XA2SUB_GetEffectParameters
,
1244 XA2SUB_SetFilterParameters
,
1245 XA2SUB_GetFilterParameters
,
1246 XA2SUB_SetOutputFilterParameters
,
1247 XA2SUB_GetOutputFilterParameters
,
1250 XA2SUB_SetChannelVolumes
,
1251 XA2SUB_GetChannelVolumes
,
1252 XA2SUB_SetOutputMatrix
,
1253 XA2SUB_GetOutputMatrix
,
1257 static HRESULT WINAPI
IXAudio2Impl_QueryInterface(IXAudio2
*iface
, REFIID riid
,
1260 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1262 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), ppvObject
);
1264 if(IsEqualGUID(riid
, &IID_IUnknown
) ||
1265 IsEqualGUID(riid
, &IID_IXAudio28
) ||
1266 IsEqualGUID(riid
, &IID_IXAudio2
))
1267 *ppvObject
= &This
->IXAudio2_iface
;
1268 else if(IsEqualGUID(riid
, &IID_IXAudio27
)){
1269 /* all xaudio versions before 28 share an IID */
1270 #if XAUDIO2_VER == 0
1271 *ppvObject
= &This
->IXAudio20_iface
;
1272 #elif XAUDIO2_VER <= 2
1273 *ppvObject
= &This
->IXAudio22_iface
;
1274 #elif XAUDIO2_VER <= 7
1275 *ppvObject
= &This
->IXAudio27_iface
;
1283 IUnknown_AddRef((IUnknown
*)*ppvObject
);
1287 FIXME("(%p)->(%s,%p), not found\n", This
,debugstr_guid(riid
), ppvObject
);
1289 return E_NOINTERFACE
;
1292 static ULONG WINAPI
IXAudio2Impl_AddRef(IXAudio2
*iface
)
1294 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1295 ULONG ref
= InterlockedIncrement(&This
->ref
);
1296 TRACE("(%p)->(): Refcount now %u\n", This
, ref
);
1300 static ULONG WINAPI
IXAudio2Impl_Release(IXAudio2
*iface
)
1302 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1303 ULONG ref
= InterlockedDecrement(&This
->ref
);
1305 TRACE("(%p)->(): Refcount now %u\n", This
, ref
);
1309 XA2SourceImpl
*src
, *src2
;
1310 XA2SubmixImpl
*sub
, *sub2
;
1313 This
->stop_engine
= TRUE
;
1314 SetEvent(This
->mmevt
);
1315 WaitForSingleObject(This
->engine
, INFINITE
);
1316 CloseHandle(This
->engine
);
1319 LIST_FOR_EACH_ENTRY_SAFE(src
, src2
, &This
->source_voices
, XA2SourceImpl
, entry
){
1320 HeapFree(GetProcessHeap(), 0, src
->sends
);
1321 IXAudio2SourceVoice_DestroyVoice(&src
->IXAudio2SourceVoice_iface
);
1322 src
->lock
.DebugInfo
->Spare
[0] = 0;
1323 DeleteCriticalSection(&src
->lock
);
1324 HeapFree(GetProcessHeap(), 0, src
);
1327 LIST_FOR_EACH_ENTRY_SAFE(sub
, sub2
, &This
->submix_voices
, XA2SubmixImpl
, entry
){
1328 IXAudio2SubmixVoice_DestroyVoice(&sub
->IXAudio2SubmixVoice_iface
);
1329 sub
->lock
.DebugInfo
->Spare
[0] = 0;
1330 DeleteCriticalSection(&sub
->lock
);
1331 HeapFree(GetProcessHeap(), 0, sub
);
1334 IXAudio2MasteringVoice_DestroyVoice(&This
->IXAudio2MasteringVoice_iface
);
1337 IMMDeviceEnumerator_Release(This
->devenum
);
1338 for(i
= 0; i
< This
->ndevs
; ++i
)
1339 CoTaskMemFree(This
->devids
[i
]);
1340 HeapFree(GetProcessHeap(), 0, This
->devids
);
1341 HeapFree(GetProcessHeap(), 0, This
->cbs
);
1343 CloseHandle(This
->mmevt
);
1345 This
->lock
.DebugInfo
->Spare
[0] = 0;
1346 DeleteCriticalSection(&This
->lock
);
1348 HeapFree(GetProcessHeap(), 0, This
);
1353 static HRESULT WINAPI
IXAudio2Impl_RegisterForCallbacks(IXAudio2
*iface
,
1354 IXAudio2EngineCallback
*pCallback
)
1356 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1359 TRACE("(%p)->(%p)\n", This
, pCallback
);
1361 EnterCriticalSection(&This
->lock
);
1363 for(i
= 0; i
< This
->ncbs
; ++i
){
1364 if(!This
->cbs
[i
] || This
->cbs
[i
] == pCallback
){
1365 This
->cbs
[i
] = pCallback
;
1366 LeaveCriticalSection(&This
->lock
);
1372 This
->cbs
= HeapReAlloc(GetProcessHeap(), 0, This
->cbs
, This
->ncbs
* sizeof(*This
->cbs
));
1374 This
->cbs
[i
] = pCallback
;
1376 LeaveCriticalSection(&This
->lock
);
1381 static void WINAPI
IXAudio2Impl_UnregisterForCallbacks(IXAudio2
*iface
,
1382 IXAudio2EngineCallback
*pCallback
)
1384 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1387 TRACE("(%p)->(%p)\n", This
, pCallback
);
1389 EnterCriticalSection(&This
->lock
);
1391 for(i
= 0; i
< This
->ncbs
; ++i
){
1392 if(This
->cbs
[i
] == pCallback
)
1396 for(; i
< This
->ncbs
- 1 && This
->cbs
[i
+ 1]; ++i
)
1397 This
->cbs
[i
] = This
->cbs
[i
+ 1];
1400 This
->cbs
[i
] = NULL
;
1402 LeaveCriticalSection(&This
->lock
);
1405 static WAVEFORMATEX
*copy_waveformat(const WAVEFORMATEX
*wfex
)
1409 if(wfex
->wFormatTag
== WAVE_FORMAT_PCM
){
1410 pwfx
= HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEX
));
1411 CopyMemory(pwfx
, wfex
, sizeof(PCMWAVEFORMAT
));
1414 pwfx
= HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEX
) + wfex
->cbSize
);
1415 CopyMemory(pwfx
, wfex
, sizeof(WAVEFORMATEX
) + wfex
->cbSize
);
1421 static HRESULT WINAPI
IXAudio2Impl_CreateSourceVoice(IXAudio2
*iface
,
1422 IXAudio2SourceVoice
**ppSourceVoice
, const WAVEFORMATEX
*pSourceFormat
,
1423 UINT32 flags
, float maxFrequencyRatio
,
1424 IXAudio2VoiceCallback
*pCallback
, const XAUDIO2_VOICE_SENDS
*pSendList
,
1425 const XAUDIO2_EFFECT_CHAIN
*pEffectChain
)
1427 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1431 TRACE("(%p)->(%p, %p, 0x%x, %f, %p, %p, %p)\n", This
, ppSourceVoice
,
1432 pSourceFormat
, flags
, maxFrequencyRatio
, pCallback
, pSendList
,
1435 dump_fmt(pSourceFormat
);
1437 palcSetThreadContext(This
->al_ctx
);
1439 EnterCriticalSection(&This
->lock
);
1441 LIST_FOR_EACH_ENTRY(src
, &This
->source_voices
, XA2SourceImpl
, entry
){
1442 EnterCriticalSection(&src
->lock
);
1445 LeaveCriticalSection(&src
->lock
);
1448 if(&src
->entry
== &This
->source_voices
){
1449 src
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*src
));
1451 LeaveCriticalSection(&This
->lock
);
1452 return E_OUTOFMEMORY
;
1455 list_add_head(&This
->source_voices
, &src
->entry
);
1457 src
->IXAudio2SourceVoice_iface
.lpVtbl
= &XAudio2SourceVoice_Vtbl
;
1459 #if XAUDIO2_VER == 0
1460 src
->IXAudio20SourceVoice_iface
.lpVtbl
= &XAudio20SourceVoice_Vtbl
;
1461 #elif XAUDIO2_VER <= 3
1462 src
->IXAudio23SourceVoice_iface
.lpVtbl
= &XAudio23SourceVoice_Vtbl
;
1463 #elif XAUDIO2_VER <= 7
1464 src
->IXAudio27SourceVoice_iface
.lpVtbl
= &XAudio27SourceVoice_Vtbl
;
1467 InitializeCriticalSection(&src
->lock
);
1468 src
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": XA2SourceImpl.lock");
1472 EnterCriticalSection(&src
->lock
);
1476 src
->running
= FALSE
;
1478 LeaveCriticalSection(&This
->lock
);
1480 src
->cb
= pCallback
;
1482 src
->al_fmt
= get_al_format(pSourceFormat
);
1484 src
->in_use
= FALSE
;
1485 LeaveCriticalSection(&src
->lock
);
1486 WARN("OpenAL can't convert this format!\n");
1487 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
1490 src
->submit_blocksize
= pSourceFormat
->nBlockAlign
;
1492 src
->fmt
= copy_waveformat(pSourceFormat
);
1494 hr
= XA2SRC_SetOutputVoices(&src
->IXAudio2SourceVoice_iface
, pSendList
);
1496 HeapFree(GetProcessHeap(), 0, src
->fmt
);
1497 src
->in_use
= FALSE
;
1498 LeaveCriticalSection(&src
->lock
);
1502 alGenSources(1, &src
->al_src
);
1504 static int once
= 0;
1506 ERR_(winediag
)("OpenAL ran out of sources, consider increasing its source limit.\n");
1507 HeapFree(GetProcessHeap(), 0, src
->fmt
);
1508 src
->in_use
= FALSE
;
1509 LeaveCriticalSection(&src
->lock
);
1510 return E_OUTOFMEMORY
;
1513 alGenBuffers(XAUDIO2_MAX_QUEUED_BUFFERS
, src
->al_bufs
);
1515 alSourcePlay(src
->al_src
);
1517 LeaveCriticalSection(&src
->lock
);
1519 #if XAUDIO2_VER == 0
1520 *ppSourceVoice
= (IXAudio2SourceVoice
*)&src
->IXAudio20SourceVoice_iface
;
1521 #elif XAUDIO2_VER <= 3
1522 *ppSourceVoice
= (IXAudio2SourceVoice
*)&src
->IXAudio23SourceVoice_iface
;
1523 #elif XAUDIO2_VER <= 7
1524 *ppSourceVoice
= (IXAudio2SourceVoice
*)&src
->IXAudio27SourceVoice_iface
;
1526 *ppSourceVoice
= &src
->IXAudio2SourceVoice_iface
;
1529 TRACE("Created source voice: %p\n", src
);
1534 static HRESULT WINAPI
IXAudio2Impl_CreateSubmixVoice(IXAudio2
*iface
,
1535 IXAudio2SubmixVoice
**ppSubmixVoice
, UINT32 inputChannels
,
1536 UINT32 inputSampleRate
, UINT32 flags
, UINT32 processingStage
,
1537 const XAUDIO2_VOICE_SENDS
*pSendList
,
1538 const XAUDIO2_EFFECT_CHAIN
*pEffectChain
)
1540 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1543 TRACE("(%p)->(%p, %u, %u, 0x%x, %u, %p, %p)\n", This
, ppSubmixVoice
,
1544 inputChannels
, inputSampleRate
, flags
, processingStage
, pSendList
,
1547 EnterCriticalSection(&This
->lock
);
1549 LIST_FOR_EACH_ENTRY(sub
, &This
->submix_voices
, XA2SubmixImpl
, entry
){
1550 EnterCriticalSection(&sub
->lock
);
1553 LeaveCriticalSection(&sub
->lock
);
1556 if(&sub
->entry
== &This
->submix_voices
){
1557 sub
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*sub
));
1559 LeaveCriticalSection(&This
->lock
);
1560 return E_OUTOFMEMORY
;
1563 list_add_head(&This
->submix_voices
, &sub
->entry
);
1565 sub
->IXAudio2SubmixVoice_iface
.lpVtbl
= &XAudio2SubmixVoice_Vtbl
;
1567 #if XAUDIO2_VER == 0
1568 sub
->IXAudio20SubmixVoice_iface
.lpVtbl
= &XAudio20SubmixVoice_Vtbl
;
1569 #elif XAUDIO2_VER <= 3
1570 sub
->IXAudio23SubmixVoice_iface
.lpVtbl
= &XAudio23SubmixVoice_Vtbl
;
1571 #elif XAUDIO2_VER <= 7
1572 sub
->IXAudio27SubmixVoice_iface
.lpVtbl
= &XAudio27SubmixVoice_Vtbl
;
1575 InitializeCriticalSection(&sub
->lock
);
1576 sub
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": XA2SubmixImpl.lock");
1578 EnterCriticalSection(&sub
->lock
);
1583 sub
->details
.CreationFlags
= flags
;
1584 sub
->details
.ActiveFlags
= flags
;
1585 sub
->details
.InputChannels
= inputChannels
;
1586 sub
->details
.InputSampleRate
= inputSampleRate
;
1588 LeaveCriticalSection(&This
->lock
);
1589 LeaveCriticalSection(&sub
->lock
);
1591 #if XAUDIO2_VER == 0
1592 *ppSubmixVoice
= (IXAudio2SubmixVoice
*)&sub
->IXAudio20SubmixVoice_iface
;
1593 #elif XAUDIO2_VER <= 3
1594 *ppSubmixVoice
= (IXAudio2SubmixVoice
*)&sub
->IXAudio23SubmixVoice_iface
;
1595 #elif XAUDIO2_VER <= 7
1596 *ppSubmixVoice
= (IXAudio2SubmixVoice
*)&sub
->IXAudio27SubmixVoice_iface
;
1598 *ppSubmixVoice
= &sub
->IXAudio2SubmixVoice_iface
;
1601 TRACE("Created submix voice: %p\n", sub
);
1606 static ALenum
al_get_loopback_format(const WAVEFORMATEXTENSIBLE
*fmt
)
1608 if(fmt
->Format
.wFormatTag
== WAVE_FORMAT_PCM
||
1609 (fmt
->Format
.wFormatTag
== WAVE_FORMAT_EXTENSIBLE
&&
1610 IsEqualGUID(&fmt
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
))){
1611 switch(fmt
->Format
.wBitsPerSample
){
1613 return ALC_UNSIGNED_BYTE_SOFT
;
1615 return ALC_SHORT_SOFT
;
1617 return ALC_INT_SOFT
;
1619 }else if(fmt
->Format
.wFormatTag
== WAVE_FORMAT_IEEE_FLOAT
||
1620 (fmt
->Format
.wFormatTag
== WAVE_FORMAT_EXTENSIBLE
&&
1621 IsEqualGUID(&fmt
->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
))){
1622 if(fmt
->Format
.wBitsPerSample
== 32)
1623 return ALC_FLOAT_SOFT
;
1628 static HRESULT WINAPI
IXAudio2Impl_CreateMasteringVoice(IXAudio2
*iface
,
1629 IXAudio2MasteringVoice
**ppMasteringVoice
, UINT32 inputChannels
,
1630 UINT32 inputSampleRate
, UINT32 flags
, const WCHAR
*deviceId
,
1631 const XAUDIO2_EFFECT_CHAIN
*pEffectChain
,
1632 AUDIO_STREAM_CATEGORY streamCategory
)
1634 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1639 REFERENCE_TIME period
, bufdur
;
1641 TRACE("(%p)->(%p, %u, %u, 0x%x, %s, %p, 0x%x)\n", This
,
1642 ppMasteringVoice
, inputChannels
, inputSampleRate
, flags
,
1643 wine_dbgstr_w(deviceId
), pEffectChain
, streamCategory
);
1646 WARN("Unknown flags set: 0x%x\n", flags
);
1649 WARN("Effect chain is unimplemented\n");
1651 EnterCriticalSection(&This
->lock
);
1653 /* there can only be one Mastering Voice, so just build it into XA2 */
1655 LeaveCriticalSection(&This
->lock
);
1656 return COMPAT_E_INVALID_CALL
;
1660 if(This
->ndevs
== 0){
1661 LeaveCriticalSection(&This
->lock
);
1664 deviceId
= This
->devids
[0];
1667 hr
= IMMDeviceEnumerator_GetDevice(This
->devenum
, deviceId
, &dev
);
1669 WARN("GetDevice failed: %08x\n", hr
);
1670 hr
= COMPAT_E_DEVICE_INVALIDATED
;
1674 hr
= IMMDevice_Activate(dev
, &IID_IAudioClient
,
1675 CLSCTX_INPROC_SERVER
, NULL
, (void**)&This
->aclient
);
1677 WARN("Activate(IAudioClient) failed: %08x\n", hr
);
1678 IMMDevice_Release(dev
);
1679 hr
= COMPAT_E_DEVICE_INVALIDATED
;
1683 IMMDevice_Release(dev
);
1685 hr
= IAudioClient_GetMixFormat(This
->aclient
, &fmt
);
1687 WARN("GetMixFormat failed: %08x\n", hr
);
1688 hr
= COMPAT_E_DEVICE_INVALIDATED
;
1692 if(sizeof(WAVEFORMATEX
) + fmt
->cbSize
> sizeof(WAVEFORMATEXTENSIBLE
)){
1693 FIXME("Mix format doesn't fit into WAVEFORMATEXTENSIBLE!\n");
1694 hr
= COMPAT_E_DEVICE_INVALIDATED
;
1698 if(inputChannels
== XAUDIO2_DEFAULT_CHANNELS
)
1699 inputChannels
= fmt
->nChannels
;
1700 if(inputSampleRate
== XAUDIO2_DEFAULT_SAMPLERATE
)
1701 inputSampleRate
= fmt
->nSamplesPerSec
;
1703 memcpy(&This
->fmt
, fmt
, sizeof(WAVEFORMATEX
) + fmt
->cbSize
);
1704 This
->fmt
.Format
.nChannels
= inputChannels
;
1705 This
->fmt
.Format
.nSamplesPerSec
= inputSampleRate
;
1706 This
->fmt
.Format
.nBlockAlign
= This
->fmt
.Format
.nChannels
* This
->fmt
.Format
.wBitsPerSample
/ 8;
1707 This
->fmt
.Format
.nAvgBytesPerSec
= This
->fmt
.Format
.nSamplesPerSec
* This
->fmt
.Format
.nBlockAlign
;
1708 This
->fmt
.dwChannelMask
= get_channel_mask(This
->fmt
.Format
.nChannels
);
1713 hr
= IAudioClient_IsFormatSupported(This
->aclient
,
1714 AUDCLNT_SHAREMODE_SHARED
, &This
->fmt
.Format
, &fmt
);
1716 if(sizeof(WAVEFORMATEX
) + fmt
->cbSize
> sizeof(WAVEFORMATEXTENSIBLE
)){
1717 FIXME("Mix format doesn't fit into WAVEFORMATEXTENSIBLE!\n");
1718 hr
= COMPAT_E_DEVICE_INVALIDATED
;
1721 memcpy(&This
->fmt
, fmt
, sizeof(WAVEFORMATEX
) + fmt
->cbSize
);
1726 hr
= IAudioClient_GetDevicePeriod(This
->aclient
, &period
, NULL
);
1728 WARN("GetDevicePeriod failed: %08x\n", hr
);
1729 hr
= COMPAT_E_DEVICE_INVALIDATED
;
1733 /* 3 periods or 0.1 seconds */
1734 bufdur
= max(3 * period
, 1000000);
1736 hr
= IAudioClient_Initialize(This
->aclient
, AUDCLNT_SHAREMODE_SHARED
,
1737 AUDCLNT_STREAMFLAGS_EVENTCALLBACK
, bufdur
,
1738 0, &This
->fmt
.Format
, NULL
);
1740 WARN("Initialize failed: %08x\n", hr
);
1741 hr
= COMPAT_E_DEVICE_INVALIDATED
;
1745 This
->period_frames
= MulDiv(period
, inputSampleRate
, 10000000);
1747 hr
= IAudioClient_SetEventHandle(This
->aclient
, This
->mmevt
);
1749 WARN("Initialize failed: %08x\n", hr
);
1750 hr
= COMPAT_E_DEVICE_INVALIDATED
;
1754 hr
= IAudioClient_GetService(This
->aclient
, &IID_IAudioRenderClient
,
1755 (void**)&This
->render
);
1757 WARN("GetService(IAudioRenderClient) failed: %08x\n", hr
);
1758 hr
= COMPAT_E_DEVICE_INVALIDATED
;
1762 /* setup openal context */
1763 attrs
[0] = ALC_FORMAT_CHANNELS_SOFT
;
1764 switch(inputChannels
){
1766 attrs
[1] = ALC_MONO_SOFT
;
1769 attrs
[1] = ALC_STEREO_SOFT
;
1772 attrs
[1] = ALC_QUAD_SOFT
;
1775 attrs
[1] = ALC_5POINT1_SOFT
;
1778 attrs
[1] = ALC_6POINT1_SOFT
;
1781 attrs
[1] = ALC_7POINT1_SOFT
;
1784 WARN("OpenAL doesn't support %u channels\n", inputChannels
);
1785 LeaveCriticalSection(&This
->lock
);
1786 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
1789 attrs
[2] = ALC_FREQUENCY
;
1790 attrs
[3] = inputSampleRate
;
1792 attrs
[4] = ALC_FORMAT_TYPE_SOFT
;
1793 attrs
[5] = al_get_loopback_format(&This
->fmt
);
1795 /* some games create very many sources */
1796 attrs
[6] = ALC_STEREO_SOURCES
;
1798 attrs
[8] = ALC_MONO_SOURCES
;
1804 WARN("OpenAL can't output samples in this format\n");
1805 hr
= COMPAT_E_DEVICE_INVALIDATED
;
1809 This
->al_device
= palcLoopbackOpenDeviceSOFT(NULL
);
1810 if(!This
->al_device
){
1811 WARN("alcLoopbackOpenDeviceSOFT failed\n");
1812 hr
= COMPAT_E_DEVICE_INVALIDATED
;
1816 This
->al_ctx
= alcCreateContext(This
->al_device
, attrs
);
1818 WARN("alcCreateContext failed\n");
1819 hr
= COMPAT_E_DEVICE_INVALIDATED
;
1823 hr
= IAudioClient_Start(This
->aclient
);
1826 WARN("Start(IAudioClient) failed: %08x\n", hr
);
1827 hr
= COMPAT_E_DEVICE_INVALIDATED
;
1831 #if XAUDIO2_VER == 0
1832 *ppMasteringVoice
= (IXAudio2MasteringVoice
*)&This
->IXAudio20MasteringVoice_iface
;
1833 #elif XAUDIO2_VER <= 3
1834 *ppMasteringVoice
= (IXAudio2MasteringVoice
*)&This
->IXAudio23MasteringVoice_iface
;
1835 #elif XAUDIO2_VER <= 7
1836 *ppMasteringVoice
= (IXAudio2MasteringVoice
*)&This
->IXAudio27MasteringVoice_iface
;
1838 *ppMasteringVoice
= &This
->IXAudio2MasteringVoice_iface
;
1844 IAudioRenderClient_Release(This
->render
);
1845 This
->render
= NULL
;
1848 IAudioClient_Release(This
->aclient
);
1849 This
->aclient
= NULL
;
1852 alcDestroyContext(This
->al_ctx
);
1853 This
->al_ctx
= NULL
;
1855 if(This
->al_device
){
1856 alcCloseDevice(This
->al_device
);
1857 This
->al_device
= NULL
;
1861 LeaveCriticalSection(&This
->lock
);
1866 static DWORD WINAPI
engine_threadproc(void *arg
);
1868 static HRESULT WINAPI
IXAudio2Impl_StartEngine(IXAudio2
*iface
)
1870 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1872 TRACE("(%p)->()\n", This
);
1874 This
->running
= TRUE
;
1877 This
->engine
= CreateThread(NULL
, 0, engine_threadproc
, This
, 0, NULL
);
1882 static void WINAPI
IXAudio2Impl_StopEngine(IXAudio2
*iface
)
1884 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1886 TRACE("(%p)->()\n", This
);
1888 This
->running
= FALSE
;
1891 static HRESULT WINAPI
IXAudio2Impl_CommitChanges(IXAudio2
*iface
,
1892 UINT32 operationSet
)
1894 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1896 TRACE("(%p)->(0x%x): stub!\n", This
, operationSet
);
1901 static void WINAPI
IXAudio2Impl_GetPerformanceData(IXAudio2
*iface
,
1902 XAUDIO2_PERFORMANCE_DATA
*pPerfData
)
1904 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1906 TRACE("(%p)->(%p): stub!\n", This
, pPerfData
);
1908 memset(pPerfData
, 0, sizeof(*pPerfData
));
1911 static void WINAPI
IXAudio2Impl_SetDebugConfiguration(IXAudio2
*iface
,
1912 const XAUDIO2_DEBUG_CONFIGURATION
*pDebugConfiguration
,
1915 IXAudio2Impl
*This
= impl_from_IXAudio2(iface
);
1917 FIXME("(%p)->(%p, %p): stub!\n", This
, pDebugConfiguration
, pReserved
);
1921 static const IXAudio2Vtbl XAudio2_Vtbl
=
1923 IXAudio2Impl_QueryInterface
,
1924 IXAudio2Impl_AddRef
,
1925 IXAudio2Impl_Release
,
1926 IXAudio2Impl_RegisterForCallbacks
,
1927 IXAudio2Impl_UnregisterForCallbacks
,
1928 IXAudio2Impl_CreateSourceVoice
,
1929 IXAudio2Impl_CreateSubmixVoice
,
1930 IXAudio2Impl_CreateMasteringVoice
,
1931 IXAudio2Impl_StartEngine
,
1932 IXAudio2Impl_StopEngine
,
1933 IXAudio2Impl_CommitChanges
,
1934 IXAudio2Impl_GetPerformanceData
,
1935 IXAudio2Impl_SetDebugConfiguration
1939 IClassFactory IClassFactory_iface
;
1943 static struct xaudio2_cf
*impl_from_IClassFactory(IClassFactory
*iface
)
1945 return CONTAINING_RECORD(iface
, struct xaudio2_cf
, IClassFactory_iface
);
1948 static HRESULT WINAPI
XAudio2CF_QueryInterface(IClassFactory
*iface
, REFIID riid
, void **ppobj
)
1950 if(IsEqualGUID(riid
, &IID_IUnknown
)
1951 || IsEqualGUID(riid
, &IID_IClassFactory
))
1953 IClassFactory_AddRef(iface
);
1959 WARN("(%p)->(%s, %p): interface not found\n", iface
, debugstr_guid(riid
), ppobj
);
1960 return E_NOINTERFACE
;
1963 static ULONG WINAPI
XAudio2CF_AddRef(IClassFactory
*iface
)
1965 struct xaudio2_cf
*This
= impl_from_IClassFactory(iface
);
1966 ULONG ref
= InterlockedIncrement(&This
->ref
);
1967 TRACE("(%p)->(): Refcount now %u\n", This
, ref
);
1971 static ULONG WINAPI
XAudio2CF_Release(IClassFactory
*iface
)
1973 struct xaudio2_cf
*This
= impl_from_IClassFactory(iface
);
1974 ULONG ref
= InterlockedDecrement(&This
->ref
);
1975 TRACE("(%p)->(): Refcount now %u\n", This
, ref
);
1977 HeapFree(GetProcessHeap(), 0, This
);
1981 static HRESULT
initialize_mmdevices(IXAudio2Impl
*This
)
1983 IMMDeviceCollection
*devcoll
;
1988 hr
= CoCreateInstance(&CLSID_MMDeviceEnumerator
, NULL
,
1989 CLSCTX_INPROC_SERVER
, &IID_IMMDeviceEnumerator
, (void**)&This
->devenum
);
1994 hr
= IMMDeviceEnumerator_EnumAudioEndpoints(This
->devenum
, eRender
,
1995 DEVICE_STATE_ACTIVE
, &devcoll
);
2000 hr
= IMMDeviceCollection_GetCount(devcoll
, &devcount
);
2002 IMMDeviceCollection_Release(devcoll
);
2008 IMMDevice
*dev
, *def_dev
;
2010 /* make sure that device 0 is the default device */
2011 IMMDeviceEnumerator_GetDefaultAudioEndpoint(This
->devenum
, eRender
, eConsole
, &def_dev
);
2013 This
->devids
= HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR
*) * devcount
);
2015 for(i
= 0; i
< devcount
; ++i
){
2016 hr
= IMMDeviceCollection_Item(devcoll
, i
, &dev
);
2027 hr
= IMMDevice_GetId(dev
, &This
->devids
[idx
]);
2029 WARN("GetId failed: %08x\n", hr
);
2030 HeapFree(GetProcessHeap(), 0, This
->devids
);
2031 This
->devids
= NULL
;
2032 IMMDevice_Release(dev
);
2036 IMMDevice_Release(dev
);
2038 WARN("Item failed: %08x\n", hr
);
2039 HeapFree(GetProcessHeap(), 0, This
->devids
);
2040 This
->devids
= NULL
;
2041 IMMDeviceCollection_Release(devcoll
);
2047 IMMDeviceCollection_Release(devcoll
);
2049 This
->ndevs
= devcount
;
2054 static HRESULT WINAPI
XAudio2CF_CreateInstance(IClassFactory
*iface
, IUnknown
*pOuter
,
2055 REFIID riid
, void **ppobj
)
2057 struct xaudio2_cf
*This
= impl_from_IClassFactory(iface
);
2059 IXAudio2Impl
*object
;
2061 TRACE("(%p)->(%p,%s,%p)\n", This
, pOuter
, debugstr_guid(riid
), ppobj
);
2066 return CLASS_E_NOAGGREGATION
;
2068 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
2070 return E_OUTOFMEMORY
;
2072 object
->IXAudio2_iface
.lpVtbl
= &XAudio2_Vtbl
;
2073 object
->IXAudio2MasteringVoice_iface
.lpVtbl
= &XAudio2MasteringVoice_Vtbl
;
2075 #if XAUDIO2_VER == 0
2076 object
->IXAudio20_iface
.lpVtbl
= &XAudio20_Vtbl
;
2077 #elif XAUDIO2_VER <= 2
2078 object
->IXAudio22_iface
.lpVtbl
= &XAudio22_Vtbl
;
2079 #elif XAUDIO2_VER <= 7
2080 object
->IXAudio27_iface
.lpVtbl
= &XAudio27_Vtbl
;
2083 #if XAUDIO2_VER == 0
2084 object
->IXAudio20MasteringVoice_iface
.lpVtbl
= &XAudio20MasteringVoice_Vtbl
;
2085 #elif XAUDIO2_VER <= 3
2086 object
->IXAudio23MasteringVoice_iface
.lpVtbl
= &XAudio23MasteringVoice_Vtbl
;
2087 #elif XAUDIO2_VER <= 7
2088 object
->IXAudio27MasteringVoice_iface
.lpVtbl
= &XAudio27MasteringVoice_Vtbl
;
2091 list_init(&object
->source_voices
);
2092 list_init(&object
->submix_voices
);
2094 object
->mmevt
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
2095 InitializeCriticalSection(&object
->lock
);
2096 object
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": IXAudio2Impl.lock");
2098 hr
= IXAudio2_QueryInterface(&object
->IXAudio2_iface
, riid
, ppobj
);
2100 HeapFree(GetProcessHeap(), 0, object
);
2104 hr
= initialize_mmdevices(object
);
2106 IUnknown_Release((IUnknown
*)*ppobj
);
2111 object
->cbs
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, object
->ncbs
* sizeof(*object
->cbs
));
2113 IXAudio2_StartEngine(&object
->IXAudio2_iface
);
2115 TRACE("Created XAudio version %u: %p\n", 20 + XAUDIO2_VER
, object
);
2120 static HRESULT WINAPI
XAudio2CF_LockServer(IClassFactory
*iface
, BOOL dolock
)
2122 struct xaudio2_cf
*This
= impl_from_IClassFactory(iface
);
2123 FIXME("(%p)->(%d): stub!\n", This
, dolock
);
2127 static const IClassFactoryVtbl XAudio2CF_Vtbl
=
2129 XAudio2CF_QueryInterface
,
2132 XAudio2CF_CreateInstance
,
2133 XAudio2CF_LockServer
2136 static HRESULT
make_xaudio2_factory(REFIID riid
, void **ppv
)
2139 struct xaudio2_cf
*ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct xaudio2_cf
));
2140 ret
->IClassFactory_iface
.lpVtbl
= &XAudio2CF_Vtbl
;
2142 hr
= IClassFactory_QueryInterface(&ret
->IClassFactory_iface
, riid
, ppv
);
2144 HeapFree(GetProcessHeap(), 0, ret
);
2148 HRESULT WINAPI
DllGetClassObject(REFCLSID rclsid
, REFIID riid
, void **ppv
)
2150 TRACE("(%s, %s, %p)\n", debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
2152 if(IsEqualGUID(rclsid
, &CLSID_XAudio20
) ||
2153 IsEqualGUID(rclsid
, &CLSID_XAudio21
) ||
2154 IsEqualGUID(rclsid
, &CLSID_XAudio22
) ||
2155 IsEqualGUID(rclsid
, &CLSID_XAudio23
) ||
2156 IsEqualGUID(rclsid
, &CLSID_XAudio24
) ||
2157 IsEqualGUID(rclsid
, &CLSID_XAudio25
) ||
2158 IsEqualGUID(rclsid
, &CLSID_XAudio26
) ||
2159 IsEqualGUID(rclsid
, &CLSID_XAudio27
))
2160 return make_xaudio2_factory(riid
, ppv
);
2162 if(IsEqualGUID(rclsid
, &CLSID_AudioVolumeMeter20
) ||
2163 IsEqualGUID(rclsid
, &CLSID_AudioVolumeMeter21
) ||
2164 IsEqualGUID(rclsid
, &CLSID_AudioVolumeMeter22
) ||
2165 IsEqualGUID(rclsid
, &CLSID_AudioVolumeMeter23
) ||
2166 IsEqualGUID(rclsid
, &CLSID_AudioVolumeMeter24
) ||
2167 IsEqualGUID(rclsid
, &CLSID_AudioVolumeMeter25
) ||
2168 IsEqualGUID(rclsid
, &CLSID_AudioVolumeMeter26
) ||
2169 IsEqualGUID(rclsid
, &CLSID_AudioVolumeMeter27
))
2170 return make_xapo_factory(&CLSID_AudioVolumeMeter27
, riid
, ppv
);
2172 if(IsEqualGUID(rclsid
, &CLSID_AudioReverb20
) ||
2173 IsEqualGUID(rclsid
, &CLSID_AudioReverb21
) ||
2174 IsEqualGUID(rclsid
, &CLSID_AudioReverb22
) ||
2175 IsEqualGUID(rclsid
, &CLSID_AudioReverb23
) ||
2176 IsEqualGUID(rclsid
, &CLSID_AudioReverb24
) ||
2177 IsEqualGUID(rclsid
, &CLSID_AudioReverb25
) ||
2178 IsEqualGUID(rclsid
, &CLSID_AudioReverb26
) ||
2179 IsEqualGUID(rclsid
, &CLSID_AudioReverb27
))
2180 return make_xapo_factory(&CLSID_FXReverb
, riid
, ppv
);
2182 return CLASS_E_CLASSNOTAVAILABLE
;
2185 HRESULT
xaudio2_initialize(IXAudio2Impl
*This
, UINT32 flags
, XAUDIO2_PROCESSOR proc
)
2188 FIXME("Unimplemented flags: 0x%x\n", flags
);
2192 #if XAUDIO2_VER >= 8
2193 HRESULT WINAPI
XAudio2Create(IXAudio2
**ppxa2
, UINT32 flags
, XAUDIO2_PROCESSOR proc
)
2199 TRACE("%p 0x%x 0x%x\n", ppxa2
, flags
, proc
);
2201 hr
= make_xaudio2_factory(&IID_IClassFactory
, (void**)&cf
);
2205 hr
= IClassFactory_CreateInstance(cf
, NULL
, &IID_IXAudio2
, (void**)&xa2
);
2206 IClassFactory_Release(cf
);
2210 hr
= xaudio2_initialize(impl_from_IXAudio2(xa2
), flags
, proc
);
2212 IXAudio2_Release(xa2
);
2220 #endif /* XAUDIO2_VER >= 8 */
2222 /* returns TRUE if there is more data available in the buffer, FALSE if the
2223 * buffer's data has all been queued */
2224 static BOOL
xa2buffer_queue_period(XA2SourceImpl
*src
, XA2Buffer
*buf
, ALuint al_buf
)
2226 UINT32 submit_bytes
;
2227 const BYTE
*submit_buf
= NULL
;
2229 if(buf
->offs_bytes
>= buf
->cur_end_bytes
){
2230 WARN("Shouldn't happen: Trying to push frames from a spent buffer?\n");
2234 submit_bytes
= min(src
->xa2
->period_frames
* src
->submit_blocksize
, buf
->cur_end_bytes
- buf
->offs_bytes
);
2235 submit_buf
= buf
->xa2buffer
.pAudioData
+ buf
->offs_bytes
;
2236 buf
->offs_bytes
+= submit_bytes
;
2238 alBufferData(al_buf
, src
->al_fmt
, submit_buf
, submit_bytes
,
2239 src
->fmt
->nSamplesPerSec
);
2241 alSourceQueueBuffers(src
->al_src
, 1, &al_buf
);
2243 src
->in_al_bytes
+= submit_bytes
;
2244 src
->al_bufs_used
++;
2246 buf
->latest_al_buf
= al_buf
;
2248 TRACE("queueing %u bytes, now %u in AL\n", submit_bytes
, src
->in_al_bytes
);
2250 return buf
->offs_bytes
< buf
->cur_end_bytes
;
2254 static UINT32
get_underrun_warning(XA2SourceImpl
*src
)
2256 UINT32 period_bytes
= src
->xa2
->period_frames
* src
->submit_blocksize
;
2257 UINT32 total
= 0, i
;
2259 for(i
= 0; i
< src
->nbufs
&& total
< IN_AL_PERIODS
* period_bytes
; ++i
){
2260 XA2Buffer
*buf
= &src
->buffers
[(src
->first_buf
+ i
) % XAUDIO2_MAX_QUEUED_BUFFERS
];
2261 total
+= buf
->cur_end_bytes
- buf
->offs_bytes
;
2262 if(buf
->xa2buffer
.LoopCount
== XAUDIO2_LOOP_INFINITE
)
2264 if(buf
->xa2buffer
.LoopCount
> 0){
2265 total
+= (buf
->loop_end_bytes
- buf
->xa2buffer
.LoopBegin
) * (buf
->xa2buffer
.LoopCount
- buf
->looped
);
2266 total
+= buf
->play_end_bytes
- buf
->loop_end_bytes
;
2270 if(total
>= IN_AL_PERIODS
* period_bytes
)
2273 return ((IN_AL_PERIODS
* period_bytes
- total
) / period_bytes
+ 1) * period_bytes
;
2279 * The looped section of a buffer is a subset of the play area which is looped
2283 * vvvvvvvvvvvvvvvvvv PlayLength
2285 * [-----PPPLLLLLLLLPPPPPPP------]
2287 * ^^^^^^^^ LoopLength
2290 * In the simple case, playback will start at PlayBegin. At LoopEnd, playback
2291 * will move to LoopBegin and repeat that loop LoopCount times. Then, playback
2292 * will cease at PlayEnd.
2294 * If PlayLength is zero, then PlayEnd is the end of the buffer.
2296 * If LoopLength is zero, then LoopEnd is PlayEnd.
2298 * For corner cases and version differences, see tests.
2300 static void update_source_state(XA2SourceImpl
*src
)
2306 alGetSourcei(src
->al_src
, AL_BUFFERS_PROCESSED
, &processed
);
2309 ALuint al_buffers
[XAUDIO2_MAX_QUEUED_BUFFERS
];
2311 alSourceUnqueueBuffers(src
->al_src
, processed
, al_buffers
);
2313 src
->first_al_buf
+= processed
;
2314 src
->first_al_buf
%= XAUDIO2_MAX_QUEUED_BUFFERS
;
2315 src
->al_bufs_used
-= processed
;
2317 for(i
= 0; i
< processed
; ++i
){
2320 alGetBufferi(al_buffers
[i
], AL_SIZE
, &bufsize
);
2322 src
->in_al_bytes
-= bufsize
;
2324 if(src
->abandoned_albufs
== 0){
2325 src
->played_frames
+= bufsize
/ src
->submit_blocksize
;
2327 if(al_buffers
[i
] == src
->buffers
[src
->first_buf
].latest_al_buf
){
2328 DWORD old_buf
= src
->first_buf
;
2331 src
->first_buf
%= XAUDIO2_MAX_QUEUED_BUFFERS
;
2334 TRACE("%p: done with buffer %u\n", src
, old_buf
);
2336 if(src
->buffers
[old_buf
].xa2buffer
.Flags
& XAUDIO2_END_OF_STREAM
)
2337 src
->played_frames
= 0;
2340 IXAudio2VoiceCallback_OnBufferEnd(src
->cb
,
2341 src
->buffers
[old_buf
].xa2buffer
.pContext
);
2342 if(src
->buffers
[old_buf
].xa2buffer
.Flags
& XAUDIO2_END_OF_STREAM
)
2343 IXAudio2VoiceCallback_OnStreamEnd(src
->cb
);
2346 IXAudio2VoiceCallback_OnBufferStart(src
->cb
,
2347 src
->buffers
[src
->first_buf
].xa2buffer
.pContext
);
2351 src
->abandoned_albufs
--;
2359 alGetSourcei(src
->al_src
, AL_BYTE_OFFSET
, &bufpos
);
2361 /* maintain IN_AL_PERIODS periods in AL */
2362 while(src
->cur_buf
!= (src
->first_buf
+ src
->nbufs
) % XAUDIO2_MAX_QUEUED_BUFFERS
&&
2363 src
->in_al_bytes
- bufpos
< IN_AL_PERIODS
* src
->xa2
->period_frames
* src
->submit_blocksize
){
2364 TRACE("%p: going to queue a period from buffer %u\n", src
, src
->cur_buf
);
2366 /* starting from an empty buffer */
2367 if(src
->cb
&& src
->cur_buf
== src
->first_buf
&& src
->buffers
[src
->cur_buf
].offs_bytes
== 0 && !src
->buffers
[src
->cur_buf
].looped
)
2368 IXAudio2VoiceCallback_OnBufferStart(src
->cb
,
2369 src
->buffers
[src
->first_buf
].xa2buffer
.pContext
);
2371 if(!xa2buffer_queue_period(src
, &src
->buffers
[src
->cur_buf
],
2372 src
->al_bufs
[(src
->first_al_buf
+ src
->al_bufs_used
) % XAUDIO2_MAX_QUEUED_BUFFERS
])){
2373 XA2Buffer
*cur
= &src
->buffers
[src
->cur_buf
];
2375 if(cur
->looped
< cur
->xa2buffer
.LoopCount
){
2376 if(cur
->xa2buffer
.LoopCount
!= XAUDIO2_LOOP_INFINITE
)
2379 cur
->looped
= 1; /* indicate that we are executing a loop */
2381 cur
->offs_bytes
= cur
->xa2buffer
.LoopBegin
;
2382 if(cur
->looped
== cur
->xa2buffer
.LoopCount
)
2383 cur
->cur_end_bytes
= cur
->play_end_bytes
;
2385 cur
->cur_end_bytes
= cur
->loop_end_bytes
;
2388 IXAudio2VoiceCallback_OnLoopEnd(src
->cb
,
2389 src
->buffers
[src
->cur_buf
].xa2buffer
.pContext
);
2392 /* buffer is spent, move on */
2394 src
->cur_buf
%= XAUDIO2_MAX_QUEUED_BUFFERS
;
2400 static void do_engine_tick(IXAudio2Impl
*This
)
2405 UINT32 nframes
, i
, pad
;
2407 /* maintain up to 3 periods in mmdevapi */
2408 hr
= IAudioClient_GetCurrentPadding(This
->aclient
, &pad
);
2410 WARN("GetCurrentPadding failed: 0x%x\n", hr
);
2414 nframes
= This
->period_frames
* 3 - pad
;
2416 TRACE("frames available: %u\n", nframes
);
2418 if(nframes
< This
->period_frames
)
2424 for(i
= 0; i
< This
->ncbs
&& This
->cbs
[i
]; ++i
)
2425 IXAudio2EngineCallback_OnProcessingPassStart(This
->cbs
[i
]);
2427 LIST_FOR_EACH_ENTRY(src
, &This
->source_voices
, XA2SourceImpl
, entry
){
2430 EnterCriticalSection(&src
->lock
);
2433 LeaveCriticalSection(&src
->lock
);
2437 if(src
->cb
&& This
->running
){
2438 #if XAUDIO2_VER == 0
2439 IXAudio20VoiceCallback_OnVoiceProcessingPassStart((IXAudio20VoiceCallback
*)src
->cb
);
2442 underrun
= get_underrun_warning(src
);
2444 TRACE("Calling OnVoiceProcessingPassStart with BytesRequired: %u\n", underrun
);
2445 IXAudio2VoiceCallback_OnVoiceProcessingPassStart(src
->cb
, underrun
);
2449 update_source_state(src
);
2452 alGetSourcei(src
->al_src
, AL_SOURCE_STATE
, &st
);
2453 if(st
!= AL_PLAYING
)
2454 alSourcePlay(src
->al_src
);
2457 IXAudio2VoiceCallback_OnVoiceProcessingPassEnd(src
->cb
);
2460 LeaveCriticalSection(&src
->lock
);
2463 hr
= IAudioRenderClient_GetBuffer(This
->render
, nframes
, &buf
);
2465 WARN("GetBuffer failed: %08x\n", hr
);
2467 palcRenderSamplesSOFT(This
->al_device
, buf
, nframes
);
2469 hr
= IAudioRenderClient_ReleaseBuffer(This
->render
, nframes
, 0);
2471 WARN("ReleaseBuffer failed: %08x\n", hr
);
2473 for(i
= 0; i
< This
->ncbs
&& This
->cbs
[i
]; ++i
)
2474 IXAudio2EngineCallback_OnProcessingPassEnd(This
->cbs
[i
]);
2477 static DWORD WINAPI
engine_threadproc(void *arg
)
2479 IXAudio2Impl
*This
= arg
;
2481 WaitForSingleObject(This
->mmevt
, INFINITE
);
2483 if(This
->stop_engine
)
2486 EnterCriticalSection(&This
->lock
);
2488 if(!This
->running
|| !This
->aclient
){
2489 LeaveCriticalSection(&This
->lock
);
2493 palcSetThreadContext(This
->al_ctx
);
2495 do_engine_tick(This
);
2497 LeaveCriticalSection(&This
->lock
);