Release 2.9.
[wine.git] / dlls / xaudio2_7 / xaudio_dll.c
bloba09162934ef70b7f114cd427b36f7199c2129110
1 /*
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
20 #include <stdarg.h>
22 #define NONAMELESSUNION
23 #define COBJMACROS
25 #include "xaudio_private.h"
27 #include "ole2.h"
28 #include "rpcproxy.h"
30 #include "xapofx.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
45 #if XAUDIO2_VER == 0
46 #define COMPAT_E_INVALID_CALL E_INVALIDARG
47 #define COMPAT_E_DEVICE_INVALIDATED XAUDIO20_E_DEVICE_INVALIDATED
48 #else
49 #define COMPAT_E_INVALID_CALL XAUDIO2_E_INVALID_CALL
50 #define COMPAT_E_DEVICE_INVALIDATED XAUDIO2_E_DEVICE_INVALIDATED
51 #endif
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)
61 #undef DOCASE
62 default:
63 TRACE("Unknown");
64 break;
66 TRACE(")\n");
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);
90 switch (reason)
92 case DLL_WINE_PREATTACH:
93 return FALSE; /* prefer native version */
94 case DLL_PROCESS_ATTACH:
95 instance = hinstDLL;
96 DisableThreadLibraryCalls( hinstDLL );
98 if(!alcIsExtensionPresent(NULL, "ALC_SOFT_loopback") ||
99 !(palcLoopbackOpenDeviceSOFT = alcGetProcAddress(NULL, "alcLoopbackOpenDeviceSOFT")) ||
100 !(palcRenderSamplesSOFT = alcGetProcAddress(NULL, "alcRenderSamplesSOFT"))){
101 ERR("XAudio2 requires the ALC_SOFT_loopback extension (OpenAL-Soft >= 1.14)\n");
102 return FALSE;
105 if(!alcIsExtensionPresent(NULL, "ALC_EXT_thread_local_context") ||
106 !(palcSetThreadContext = alcGetProcAddress(NULL, "alcSetThreadContext"))){
107 ERR("XAudio2 requires the ALC_EXT_thread_local_context extension (OpenAL-Soft >= 1.12)\n");
108 return FALSE;
111 break;
113 return TRUE;
116 HRESULT WINAPI DllCanUnloadNow(void)
118 return S_FALSE;
121 HRESULT WINAPI DllRegisterServer(void)
123 TRACE("\n");
124 return __wine_register_resources(instance);
127 HRESULT WINAPI DllUnregisterServer(void)
129 TRACE("\n");
130 return __wine_unregister_resources(instance);
133 static XA2SourceImpl *impl_from_IXAudio2SourceVoice(IXAudio2SourceVoice *iface)
135 return CONTAINING_RECORD(iface, XA2SourceImpl, IXAudio2SourceVoice_iface);
138 static XA2SubmixImpl *impl_from_IXAudio2SubmixVoice(IXAudio2SubmixVoice *iface)
140 return CONTAINING_RECORD(iface, XA2SubmixImpl, IXAudio2SubmixVoice_iface);
143 static inline IXAudio2Impl *impl_from_IXAudio2(IXAudio2 *iface)
145 return CONTAINING_RECORD(iface, IXAudio2Impl, IXAudio2_iface);
148 static IXAudio2Impl *impl_from_IXAudio2MasteringVoice(IXAudio2MasteringVoice *iface)
150 return CONTAINING_RECORD(iface, IXAudio2Impl, IXAudio2MasteringVoice_iface);
153 static DWORD get_channel_mask(unsigned int channels)
155 switch(channels){
156 case 0:
157 return 0;
158 case 1:
159 return KSAUDIO_SPEAKER_MONO;
160 case 2:
161 return KSAUDIO_SPEAKER_STEREO;
162 case 3:
163 return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY;
164 case 4:
165 return KSAUDIO_SPEAKER_QUAD; /* not _SURROUND */
166 case 5:
167 return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY;
168 case 6:
169 return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */
170 case 7:
171 return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER;
172 case 8:
173 return KSAUDIO_SPEAKER_7POINT1_SURROUND; /* Vista deprecates 7POINT1 */
175 FIXME("Unknown speaker configuration: %u\n", channels);
176 return 0;
179 static void WINAPI XA2SRC_GetVoiceDetails(IXAudio2SourceVoice *iface,
180 XAUDIO2_VOICE_DETAILS *pVoiceDetails)
182 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
184 TRACE("%p, %p\n", This, pVoiceDetails);
186 pVoiceDetails->CreationFlags = 0;
187 pVoiceDetails->ActiveFlags = 0;
188 pVoiceDetails->InputChannels = This->fmt->nChannels;
189 pVoiceDetails->InputSampleRate = This->fmt->nSamplesPerSec;
192 static HRESULT WINAPI XA2SRC_SetOutputVoices(IXAudio2SourceVoice *iface,
193 const XAUDIO2_VOICE_SENDS *pSendList)
195 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
196 int i;
197 XAUDIO2_VOICE_SENDS def_send;
198 XAUDIO2_SEND_DESCRIPTOR def_desc;
200 TRACE("%p, %p\n", This, pSendList);
202 if(!pSendList){
203 def_desc.Flags = 0;
204 def_desc.pOutputVoice = (IXAudio2Voice*)&This->xa2->IXAudio2MasteringVoice_iface;
206 def_send.SendCount = 1;
207 def_send.pSends = &def_desc;
209 pSendList = &def_send;
212 if(TRACE_ON(xaudio2)){
213 for(i = 0; i < pSendList->SendCount; ++i){
214 XAUDIO2_SEND_DESCRIPTOR *desc = &pSendList->pSends[i];
215 TRACE("Outputting to: 0x%x, %p\n", desc->Flags, desc->pOutputVoice);
219 if(This->nsends < pSendList->SendCount){
220 HeapFree(GetProcessHeap(), 0, This->sends);
221 This->sends = HeapAlloc(GetProcessHeap(), 0, sizeof(*This->sends) * pSendList->SendCount);
222 This->nsends = pSendList->SendCount;
223 }else
224 memset(This->sends, 0, sizeof(*This->sends) * This->nsends);
226 memcpy(This->sends, pSendList->pSends, sizeof(*This->sends) * pSendList->SendCount);
228 return S_OK;
231 static HRESULT WINAPI XA2SRC_SetEffectChain(IXAudio2SourceVoice *iface,
232 const XAUDIO2_EFFECT_CHAIN *pEffectChain)
234 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
235 TRACE("%p, %p\n", This, pEffectChain);
236 return S_OK;
239 static HRESULT WINAPI XA2SRC_EnableEffect(IXAudio2SourceVoice *iface,
240 UINT32 EffectIndex, UINT32 OperationSet)
242 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
243 TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
244 return S_OK;
247 static HRESULT WINAPI XA2SRC_DisableEffect(IXAudio2SourceVoice *iface,
248 UINT32 EffectIndex, UINT32 OperationSet)
250 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
251 TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
252 return S_OK;
255 static void WINAPI XA2SRC_GetEffectState(IXAudio2SourceVoice *iface,
256 UINT32 EffectIndex, BOOL *pEnabled)
258 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
259 TRACE("%p, %u, %p\n", This, EffectIndex, pEnabled);
262 static HRESULT WINAPI XA2SRC_SetEffectParameters(IXAudio2SourceVoice *iface,
263 UINT32 EffectIndex, const void *pParameters, UINT32 ParametersByteSize,
264 UINT32 OperationSet)
266 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
267 TRACE("%p, %u, %p, 0x%x, 0x%x\n", This, EffectIndex, pParameters,
268 ParametersByteSize, OperationSet);
269 return S_OK;
272 static HRESULT WINAPI XA2SRC_GetEffectParameters(IXAudio2SourceVoice *iface,
273 UINT32 EffectIndex, void *pParameters, UINT32 ParametersByteSize)
275 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
276 TRACE("%p, %u, %p, 0x%x\n", This, EffectIndex, pParameters,
277 ParametersByteSize);
278 return S_OK;
281 static HRESULT WINAPI XA2SRC_SetFilterParameters(IXAudio2SourceVoice *iface,
282 const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
284 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
285 TRACE("%p, %p, 0x%x\n", This, pParameters, OperationSet);
286 return S_OK;
289 static void WINAPI XA2SRC_GetFilterParameters(IXAudio2SourceVoice *iface,
290 XAUDIO2_FILTER_PARAMETERS *pParameters)
292 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
293 TRACE("%p, %p\n", This, pParameters);
296 static HRESULT WINAPI XA2SRC_SetOutputFilterParameters(IXAudio2SourceVoice *iface,
297 IXAudio2Voice *pDestinationVoice,
298 const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
300 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
301 TRACE("%p, %p, %p, 0x%x\n", This, pDestinationVoice, pParameters, OperationSet);
302 return S_OK;
305 static void WINAPI XA2SRC_GetOutputFilterParameters(IXAudio2SourceVoice *iface,
306 IXAudio2Voice *pDestinationVoice,
307 XAUDIO2_FILTER_PARAMETERS *pParameters)
309 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
310 TRACE("%p, %p, %p\n", This, pDestinationVoice, pParameters);
313 static HRESULT WINAPI XA2SRC_SetVolume(IXAudio2SourceVoice *iface, float Volume,
314 UINT32 OperationSet)
316 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
317 ALfloat al_gain;
319 TRACE("%p, %f, 0x%x\n", This, Volume, OperationSet);
321 al_gain = Volume;
323 palcSetThreadContext(This->xa2->al_ctx);
325 alSourcef(This->al_src, AL_GAIN, al_gain);
327 return S_OK;
330 static void WINAPI XA2SRC_GetVolume(IXAudio2SourceVoice *iface, float *pVolume)
332 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
333 TRACE("%p, %p\n", This, pVolume);
336 static HRESULT WINAPI XA2SRC_SetChannelVolumes(IXAudio2SourceVoice *iface,
337 UINT32 Channels, const float *pVolumes, UINT32 OperationSet)
339 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
340 TRACE("%p, %u, %p, 0x%x\n", This, Channels, pVolumes, OperationSet);
341 return S_OK;
344 static void WINAPI XA2SRC_GetChannelVolumes(IXAudio2SourceVoice *iface,
345 UINT32 Channels, float *pVolumes)
347 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
348 TRACE("%p, %u, %p\n", This, Channels, pVolumes);
351 static HRESULT WINAPI XA2SRC_SetOutputMatrix(IXAudio2SourceVoice *iface,
352 IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
353 UINT32 DestinationChannels, const float *pLevelMatrix,
354 UINT32 OperationSet)
356 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
357 TRACE("%p, %p, %u, %u, %p, 0x%x\n", This, pDestinationVoice,
358 SourceChannels, DestinationChannels, pLevelMatrix, OperationSet);
359 return S_OK;
362 static void WINAPI XA2SRC_GetOutputMatrix(IXAudio2SourceVoice *iface,
363 IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
364 UINT32 DestinationChannels, float *pLevelMatrix)
366 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
367 TRACE("%p, %p, %u, %u, %p\n", This, pDestinationVoice,
368 SourceChannels, DestinationChannels, pLevelMatrix);
371 static void WINAPI XA2SRC_DestroyVoice(IXAudio2SourceVoice *iface)
373 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
374 ALint processed;
376 TRACE("%p\n", This);
378 palcSetThreadContext(This->xa2->al_ctx);
380 EnterCriticalSection(&This->lock);
382 if(!This->in_use){
383 LeaveCriticalSection(&This->lock);
384 return;
387 This->in_use = FALSE;
389 This->running = FALSE;
391 IXAudio2SourceVoice_Stop(iface, 0, 0);
393 alSourceStop(This->al_src);
395 /* unqueue all buffers */
396 alSourcei(This->al_src, AL_BUFFER, AL_NONE);
398 alGetSourcei(This->al_src, AL_BUFFERS_PROCESSED, &processed);
400 if(processed > 0){
401 ALuint al_buffers[XAUDIO2_MAX_QUEUED_BUFFERS];
403 alSourceUnqueueBuffers(This->al_src, processed, al_buffers);
406 HeapFree(GetProcessHeap(), 0, This->fmt);
408 alDeleteBuffers(XAUDIO2_MAX_QUEUED_BUFFERS, This->al_bufs);
409 alDeleteSources(1, &This->al_src);
411 This->in_al_bytes = 0;
412 This->al_bufs_used = 0;
413 This->played_frames = 0;
414 This->nbufs = 0;
415 This->first_buf = 0;
416 This->cur_buf = 0;
418 LeaveCriticalSection(&This->lock);
421 static HRESULT WINAPI XA2SRC_Start(IXAudio2SourceVoice *iface, UINT32 Flags,
422 UINT32 OperationSet)
424 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
426 TRACE("%p, 0x%x, 0x%x\n", This, Flags, OperationSet);
428 EnterCriticalSection(&This->lock);
430 This->running = TRUE;
432 LeaveCriticalSection(&This->lock);
434 return S_OK;
437 static HRESULT WINAPI XA2SRC_Stop(IXAudio2SourceVoice *iface, UINT32 Flags,
438 UINT32 OperationSet)
440 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
442 TRACE("%p, 0x%x, 0x%x\n", This, Flags, OperationSet);
444 EnterCriticalSection(&This->lock);
446 This->running = FALSE;
448 LeaveCriticalSection(&This->lock);
450 return S_OK;
453 static ALenum get_al_format(const WAVEFORMATEX *fmt)
455 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)fmt;
456 if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
457 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
458 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
459 switch(fmt->wBitsPerSample){
460 case 8:
461 switch(fmt->nChannels){
462 case 1:
463 return AL_FORMAT_MONO8;
464 case 2:
465 return AL_FORMAT_STEREO8;
466 case 4:
467 return AL_FORMAT_QUAD8;
468 case 6:
469 return AL_FORMAT_51CHN8;
470 case 7:
471 return AL_FORMAT_61CHN8;
472 case 8:
473 return AL_FORMAT_71CHN8;
475 break;
476 case 16:
477 switch(fmt->nChannels){
478 case 1:
479 return AL_FORMAT_MONO16;
480 case 2:
481 return AL_FORMAT_STEREO16;
482 case 4:
483 return AL_FORMAT_QUAD16;
484 case 6:
485 return AL_FORMAT_51CHN16;
486 case 7:
487 return AL_FORMAT_61CHN16;
488 case 8:
489 return AL_FORMAT_71CHN16;
491 break;
493 }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
494 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
495 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
496 if(fmt->wBitsPerSample == 32){
497 switch(fmt->nChannels){
498 case 1:
499 return AL_FORMAT_MONO_FLOAT32;
500 case 2:
501 return AL_FORMAT_STEREO_FLOAT32;
505 return 0;
508 static HRESULT WINAPI XA2SRC_SubmitSourceBuffer(IXAudio2SourceVoice *iface,
509 const XAUDIO2_BUFFER *pBuffer, const XAUDIO2_BUFFER_WMA *pBufferWMA)
511 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
512 XA2Buffer *buf;
513 UINT32 buf_idx;
515 TRACE("%p, %p, %p\n", This, pBuffer, pBufferWMA);
517 if(TRACE_ON(xaudio2)){
518 TRACE("Flags: 0x%x\n", pBuffer->Flags);
519 TRACE("AudioBytes: %u\n", pBuffer->AudioBytes);
520 TRACE("pAudioData: %p\n", pBuffer->pAudioData);
521 TRACE("PlayBegin: %u\n", pBuffer->PlayBegin);
522 TRACE("PlayLength: %u\n", pBuffer->PlayLength);
523 TRACE("LoopBegin: %u\n", pBuffer->LoopBegin);
524 TRACE("LoopLength: %u\n", pBuffer->LoopLength);
525 TRACE("LoopCount: %u\n", pBuffer->LoopCount);
526 TRACE("pContext: %p\n", pBuffer->pContext);
529 EnterCriticalSection(&This->lock);
531 if(This->nbufs >= XAUDIO2_MAX_QUEUED_BUFFERS){
532 TRACE("Too many buffers queued!\n");
533 LeaveCriticalSection(&This->lock);
534 return COMPAT_E_INVALID_CALL;
537 buf_idx = (This->first_buf + This->nbufs) % XAUDIO2_MAX_QUEUED_BUFFERS;
538 buf = &This->buffers[buf_idx];
539 memset(buf, 0, sizeof(*buf));
541 /* API contract: pAudioData must remain valid until this buffer is played,
542 * but pBuffer itself may be reused immediately */
543 memcpy(&buf->xa2buffer, pBuffer, sizeof(*pBuffer));
545 #if XAUDIO2_VER == 0
546 if(buf->xa2buffer.LoopCount == XAUDIO20_LOOP_INFINITE)
547 buf->xa2buffer.LoopCount = XAUDIO2_LOOP_INFINITE;
548 #endif
550 /* convert samples offsets to bytes */
551 if(This->fmt->wFormatTag == WAVE_FORMAT_ADPCM){
552 /* ADPCM gives us a number of samples per block, so round down to
553 * nearest block and convert to bytes */
554 buf->xa2buffer.PlayBegin = buf->xa2buffer.PlayBegin / ((ADPCMWAVEFORMAT*)This->fmt)->wSamplesPerBlock * This->fmt->nBlockAlign;
555 buf->xa2buffer.PlayLength = buf->xa2buffer.PlayLength / ((ADPCMWAVEFORMAT*)This->fmt)->wSamplesPerBlock * This->fmt->nBlockAlign;
556 buf->xa2buffer.LoopBegin = buf->xa2buffer.LoopBegin / ((ADPCMWAVEFORMAT*)This->fmt)->wSamplesPerBlock * This->fmt->nBlockAlign;
557 buf->xa2buffer.LoopLength = buf->xa2buffer.LoopLength / ((ADPCMWAVEFORMAT*)This->fmt)->wSamplesPerBlock * This->fmt->nBlockAlign;
558 }else{
559 buf->xa2buffer.PlayBegin *= This->fmt->nBlockAlign;
560 buf->xa2buffer.PlayLength *= This->fmt->nBlockAlign;
561 buf->xa2buffer.LoopBegin *= This->fmt->nBlockAlign;
562 buf->xa2buffer.LoopLength *= This->fmt->nBlockAlign;
565 if(buf->xa2buffer.PlayLength == 0)
566 /* set to end of buffer */
567 buf->xa2buffer.PlayLength = buf->xa2buffer.AudioBytes - buf->xa2buffer.PlayBegin;
569 buf->play_end_bytes = buf->xa2buffer.PlayBegin + buf->xa2buffer.PlayLength;
571 if(buf->xa2buffer.LoopCount){
572 if(buf->xa2buffer.LoopLength == 0)
573 /* set to end of play range */
574 buf->xa2buffer.LoopLength = buf->play_end_bytes - buf->xa2buffer.LoopBegin;
576 if(buf->xa2buffer.LoopBegin >= buf->play_end_bytes){
577 /* this actually crashes on native xaudio 2.7 */
578 LeaveCriticalSection(&This->lock);
579 return COMPAT_E_INVALID_CALL;
582 buf->loop_end_bytes = buf->xa2buffer.LoopBegin + buf->xa2buffer.LoopLength;
584 /* xaudio 2.7 allows some invalid looping setups, but later versions
585 * return an error */
586 #if XAUDIO2_VER > 7
587 if(buf->loop_end_bytes > buf->play_end_bytes){
588 LeaveCriticalSection(&This->lock);
589 return COMPAT_E_INVALID_CALL;
592 if(buf->loop_end_bytes <= buf->xa2buffer.PlayBegin){
593 LeaveCriticalSection(&This->lock);
594 return COMPAT_E_INVALID_CALL;
596 #else
597 if(buf->loop_end_bytes <= buf->xa2buffer.PlayBegin){
598 buf->xa2buffer.LoopCount = 0;
599 buf->loop_end_bytes = buf->play_end_bytes;
601 #endif
602 }else{
603 buf->xa2buffer.LoopLength = buf->xa2buffer.PlayLength;
604 buf->xa2buffer.LoopBegin = buf->xa2buffer.PlayBegin;
605 buf->loop_end_bytes = buf->play_end_bytes;
608 buf->offs_bytes = buf->xa2buffer.PlayBegin;
609 buf->cur_end_bytes = buf->loop_end_bytes;
611 buf->latest_al_buf = -1;
613 ++This->nbufs;
615 TRACE("%p: queued buffer %u (%u bytes), now %u buffers held\n",
616 This, buf_idx, buf->xa2buffer.AudioBytes, This->nbufs);
618 LeaveCriticalSection(&This->lock);
620 return S_OK;
623 static HRESULT WINAPI XA2SRC_FlushSourceBuffers(IXAudio2SourceVoice *iface)
625 UINT i, first, last, to_flush;
626 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
628 TRACE("%p\n", This);
630 EnterCriticalSection(&This->lock);
632 if(This->running && This->nbufs > 0){
633 /* when running, flush only completely unused buffers; the rest remain
634 * in queue */
635 last = (This->first_buf + This->nbufs) % XAUDIO2_MAX_QUEUED_BUFFERS;
636 first = (This->cur_buf + 1) % XAUDIO2_MAX_QUEUED_BUFFERS;
637 if(This->cur_buf == last)
638 /* nothing to do */
639 to_flush = 0;
640 else if(last >= first)
641 to_flush = last - first;
642 else
643 to_flush = last + XAUDIO2_MAX_QUEUED_BUFFERS - first;
644 }else{
645 /* when stopped, flush all buffers */
646 first = This->first_buf;
647 last = (This->first_buf + This->nbufs) % XAUDIO2_MAX_QUEUED_BUFFERS;
648 to_flush = This->nbufs;
652 for(i = first;
653 i < (first + to_flush) % XAUDIO2_MAX_QUEUED_BUFFERS;
654 i = (i + 1) % XAUDIO2_MAX_QUEUED_BUFFERS){
655 if(This->cb)
656 IXAudio2VoiceCallback_OnBufferEnd(This->cb,
657 This->buffers[i].xa2buffer.pContext);
660 This->nbufs -= to_flush;
661 This->cur_buf = (This->first_buf + This->nbufs) % XAUDIO2_MAX_QUEUED_BUFFERS;
663 LeaveCriticalSection(&This->lock);
665 return S_OK;
668 static HRESULT WINAPI XA2SRC_Discontinuity(IXAudio2SourceVoice *iface)
670 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
672 TRACE("%p\n", This);
674 EnterCriticalSection(&This->lock);
676 if(This->nbufs > 0){
677 DWORD last = (This->first_buf + This->nbufs - 1) % XAUDIO2_MAX_QUEUED_BUFFERS;
678 This->buffers[last].xa2buffer.Flags |= XAUDIO2_END_OF_STREAM;
681 LeaveCriticalSection(&This->lock);
683 return S_OK;
686 static HRESULT WINAPI XA2SRC_ExitLoop(IXAudio2SourceVoice *iface, UINT32 OperationSet)
688 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
690 TRACE("%p, 0x%x\n", This, OperationSet);
692 EnterCriticalSection(&This->lock);
694 This->buffers[This->cur_buf].looped = XAUDIO2_LOOP_INFINITE;
696 LeaveCriticalSection(&This->lock);
698 return S_OK;
701 static void WINAPI XA2SRC_GetState(IXAudio2SourceVoice *iface,
702 XAUDIO2_VOICE_STATE *pVoiceState, UINT32 Flags)
704 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
706 TRACE("%p, %p, 0x%x\n", This, pVoiceState, Flags);
708 EnterCriticalSection(&This->lock);
710 if(!(Flags & XAUDIO2_VOICE_NOSAMPLESPLAYED))
711 pVoiceState->SamplesPlayed = This->played_frames;
712 else
713 pVoiceState->SamplesPlayed = 0;
715 if(This->nbufs)
716 pVoiceState->pCurrentBufferContext = This->buffers[This->first_buf].xa2buffer.pContext;
717 else
718 pVoiceState->pCurrentBufferContext = NULL;
720 pVoiceState->BuffersQueued = This->nbufs;
722 LeaveCriticalSection(&This->lock);
724 TRACE("returning %s, queued: %u\n", wine_dbgstr_longlong(pVoiceState->SamplesPlayed), This->nbufs);
727 static HRESULT WINAPI XA2SRC_SetFrequencyRatio(IXAudio2SourceVoice *iface,
728 float Ratio, UINT32 OperationSet)
730 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
731 ALfloat r;
733 TRACE("%p, %f, 0x%x\n", This, Ratio, OperationSet);
735 if(Ratio < XAUDIO2_MIN_FREQ_RATIO)
736 r = XAUDIO2_MIN_FREQ_RATIO;
737 else if (Ratio > XAUDIO2_MAX_FREQ_RATIO)
738 r = XAUDIO2_MAX_FREQ_RATIO;
739 else
740 r = Ratio;
742 palcSetThreadContext(This->xa2->al_ctx);
744 alSourcef(This->al_src, AL_PITCH, r);
746 return S_OK;
749 static void WINAPI XA2SRC_GetFrequencyRatio(IXAudio2SourceVoice *iface, float *pRatio)
751 ALfloat ratio;
752 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
754 TRACE("%p, %p\n", This, pRatio);
756 palcSetThreadContext(This->xa2->al_ctx);
758 alGetSourcef(This->al_src, AL_PITCH, &ratio);
760 *pRatio = ratio;
763 static HRESULT WINAPI XA2SRC_SetSourceSampleRate(
764 IXAudio2SourceVoice *iface,
765 UINT32 NewSourceSampleRate)
767 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
769 TRACE("%p, %u\n", This, NewSourceSampleRate);
771 EnterCriticalSection(&This->lock);
773 if(This->nbufs){
774 LeaveCriticalSection(&This->lock);
775 return COMPAT_E_INVALID_CALL;
778 This->fmt->nSamplesPerSec = NewSourceSampleRate;
780 LeaveCriticalSection(&This->lock);
782 return S_OK;
785 static const IXAudio2SourceVoiceVtbl XAudio2SourceVoice_Vtbl = {
786 XA2SRC_GetVoiceDetails,
787 XA2SRC_SetOutputVoices,
788 XA2SRC_SetEffectChain,
789 XA2SRC_EnableEffect,
790 XA2SRC_DisableEffect,
791 XA2SRC_GetEffectState,
792 XA2SRC_SetEffectParameters,
793 XA2SRC_GetEffectParameters,
794 XA2SRC_SetFilterParameters,
795 XA2SRC_GetFilterParameters,
796 XA2SRC_SetOutputFilterParameters,
797 XA2SRC_GetOutputFilterParameters,
798 XA2SRC_SetVolume,
799 XA2SRC_GetVolume,
800 XA2SRC_SetChannelVolumes,
801 XA2SRC_GetChannelVolumes,
802 XA2SRC_SetOutputMatrix,
803 XA2SRC_GetOutputMatrix,
804 XA2SRC_DestroyVoice,
805 XA2SRC_Start,
806 XA2SRC_Stop,
807 XA2SRC_SubmitSourceBuffer,
808 XA2SRC_FlushSourceBuffers,
809 XA2SRC_Discontinuity,
810 XA2SRC_ExitLoop,
811 XA2SRC_GetState,
812 XA2SRC_SetFrequencyRatio,
813 XA2SRC_GetFrequencyRatio,
814 XA2SRC_SetSourceSampleRate
817 static void WINAPI XA2M_GetVoiceDetails(IXAudio2MasteringVoice *iface,
818 XAUDIO2_VOICE_DETAILS *pVoiceDetails)
820 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
821 TRACE("%p, %p\n", This, pVoiceDetails);
822 pVoiceDetails->CreationFlags = 0;
823 pVoiceDetails->ActiveFlags = 0;
824 pVoiceDetails->InputChannels = This->fmt.Format.nChannels;
825 pVoiceDetails->InputSampleRate = This->fmt.Format.nSamplesPerSec;
828 static HRESULT WINAPI XA2M_SetOutputVoices(IXAudio2MasteringVoice *iface,
829 const XAUDIO2_VOICE_SENDS *pSendList)
831 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
832 TRACE("%p, %p\n", This, pSendList);
833 return S_OK;
836 static HRESULT WINAPI XA2M_SetEffectChain(IXAudio2MasteringVoice *iface,
837 const XAUDIO2_EFFECT_CHAIN *pEffectChain)
839 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
840 TRACE("%p, %p\n", This, pEffectChain);
841 return S_OK;
844 static HRESULT WINAPI XA2M_EnableEffect(IXAudio2MasteringVoice *iface, UINT32 EffectIndex,
845 UINT32 OperationSet)
847 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
848 TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
849 return S_OK;
852 static HRESULT WINAPI XA2M_DisableEffect(IXAudio2MasteringVoice *iface, UINT32 EffectIndex,
853 UINT32 OperationSet)
855 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
856 TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
857 return S_OK;
860 static void WINAPI XA2M_GetEffectState(IXAudio2MasteringVoice *iface, UINT32 EffectIndex,
861 BOOL *pEnabled)
863 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
864 TRACE("%p, %u, %p\n", This, EffectIndex, pEnabled);
867 static HRESULT WINAPI XA2M_SetEffectParameters(IXAudio2MasteringVoice *iface,
868 UINT32 EffectIndex, const void *pParameters, UINT32 ParametersByteSize,
869 UINT32 OperationSet)
871 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
872 TRACE("%p, %u, %p, 0x%x, 0x%x\n", This, EffectIndex, pParameters,
873 ParametersByteSize, OperationSet);
874 return S_OK;
877 static HRESULT WINAPI XA2M_GetEffectParameters(IXAudio2MasteringVoice *iface,
878 UINT32 EffectIndex, void *pParameters, UINT32 ParametersByteSize)
880 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
881 TRACE("%p, %u, %p, 0x%x\n", This, EffectIndex, pParameters,
882 ParametersByteSize);
883 return S_OK;
886 static HRESULT WINAPI XA2M_SetFilterParameters(IXAudio2MasteringVoice *iface,
887 const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
889 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
890 TRACE("%p, %p, 0x%x\n", This, pParameters, OperationSet);
891 return S_OK;
894 static void WINAPI XA2M_GetFilterParameters(IXAudio2MasteringVoice *iface,
895 XAUDIO2_FILTER_PARAMETERS *pParameters)
897 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
898 TRACE("%p, %p\n", This, pParameters);
901 static HRESULT WINAPI XA2M_SetOutputFilterParameters(IXAudio2MasteringVoice *iface,
902 IXAudio2Voice *pDestinationVoice,
903 const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
905 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
906 TRACE("%p, %p, %p, 0x%x\n", This, pDestinationVoice, pParameters, OperationSet);
907 return S_OK;
910 static void WINAPI XA2M_GetOutputFilterParameters(IXAudio2MasteringVoice *iface,
911 IXAudio2Voice *pDestinationVoice,
912 XAUDIO2_FILTER_PARAMETERS *pParameters)
914 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
915 TRACE("%p, %p, %p\n", This, pDestinationVoice, pParameters);
918 static HRESULT WINAPI XA2M_SetVolume(IXAudio2MasteringVoice *iface, float Volume,
919 UINT32 OperationSet)
921 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
922 TRACE("%p, %f, 0x%x\n", This, Volume, OperationSet);
923 return S_OK;
926 static void WINAPI XA2M_GetVolume(IXAudio2MasteringVoice *iface, float *pVolume)
928 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
929 TRACE("%p, %p\n", This, pVolume);
932 static HRESULT WINAPI XA2M_SetChannelVolumes(IXAudio2MasteringVoice *iface, UINT32 Channels,
933 const float *pVolumes, UINT32 OperationSet)
935 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
936 TRACE("%p, %u, %p, 0x%x\n", This, Channels, pVolumes, OperationSet);
937 return S_OK;
940 static void WINAPI XA2M_GetChannelVolumes(IXAudio2MasteringVoice *iface, UINT32 Channels,
941 float *pVolumes)
943 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
944 TRACE("%p, %u, %p\n", This, Channels, pVolumes);
947 static HRESULT WINAPI XA2M_SetOutputMatrix(IXAudio2MasteringVoice *iface,
948 IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
949 UINT32 DestinationChannels, const float *pLevelMatrix,
950 UINT32 OperationSet)
952 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
953 TRACE("%p, %p, %u, %u, %p, 0x%x\n", This, pDestinationVoice,
954 SourceChannels, DestinationChannels, pLevelMatrix, OperationSet);
955 return S_OK;
958 static void WINAPI XA2M_GetOutputMatrix(IXAudio2MasteringVoice *iface,
959 IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
960 UINT32 DestinationChannels, float *pLevelMatrix)
962 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
963 TRACE("%p, %p, %u, %u, %p\n", This, pDestinationVoice,
964 SourceChannels, DestinationChannels, pLevelMatrix);
967 static void WINAPI XA2M_DestroyVoice(IXAudio2MasteringVoice *iface)
969 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
971 TRACE("%p\n", This);
973 EnterCriticalSection(&This->lock);
975 if(!This->aclient){
976 LeaveCriticalSection(&This->lock);
977 return;
980 This->running = FALSE;
982 IAudioRenderClient_Release(This->render);
983 This->render = NULL;
985 IAudioClient_Release(This->aclient);
986 This->aclient = NULL;
988 alcDestroyContext(This->al_ctx);
989 This->al_ctx = NULL;
991 alcCloseDevice(This->al_device);
992 This->al_device = NULL;
994 LeaveCriticalSection(&This->lock);
997 /* not present in XAudio2 2.7 */
998 static void WINAPI XA2M_GetChannelMask(IXAudio2MasteringVoice *iface,
999 DWORD *pChannelMask)
1001 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
1003 TRACE("%p %p\n", This, pChannelMask);
1005 *pChannelMask = This->fmt.dwChannelMask;
1008 static const struct IXAudio2MasteringVoiceVtbl XAudio2MasteringVoice_Vtbl = {
1009 XA2M_GetVoiceDetails,
1010 XA2M_SetOutputVoices,
1011 XA2M_SetEffectChain,
1012 XA2M_EnableEffect,
1013 XA2M_DisableEffect,
1014 XA2M_GetEffectState,
1015 XA2M_SetEffectParameters,
1016 XA2M_GetEffectParameters,
1017 XA2M_SetFilterParameters,
1018 XA2M_GetFilterParameters,
1019 XA2M_SetOutputFilterParameters,
1020 XA2M_GetOutputFilterParameters,
1021 XA2M_SetVolume,
1022 XA2M_GetVolume,
1023 XA2M_SetChannelVolumes,
1024 XA2M_GetChannelVolumes,
1025 XA2M_SetOutputMatrix,
1026 XA2M_GetOutputMatrix,
1027 XA2M_DestroyVoice,
1028 XA2M_GetChannelMask
1031 static void WINAPI XA2SUB_GetVoiceDetails(IXAudio2SubmixVoice *iface,
1032 XAUDIO2_VOICE_DETAILS *pVoiceDetails)
1034 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1036 TRACE("%p, %p\n", This, pVoiceDetails);
1038 *pVoiceDetails = This->details;
1041 static HRESULT WINAPI XA2SUB_SetOutputVoices(IXAudio2SubmixVoice *iface,
1042 const XAUDIO2_VOICE_SENDS *pSendList)
1044 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1045 TRACE("%p, %p\n", This, pSendList);
1046 return S_OK;
1049 static HRESULT WINAPI XA2SUB_SetEffectChain(IXAudio2SubmixVoice *iface,
1050 const XAUDIO2_EFFECT_CHAIN *pEffectChain)
1052 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1053 TRACE("%p, %p\n", This, pEffectChain);
1054 return S_OK;
1057 static HRESULT WINAPI XA2SUB_EnableEffect(IXAudio2SubmixVoice *iface, UINT32 EffectIndex,
1058 UINT32 OperationSet)
1060 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1061 TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
1062 return S_OK;
1065 static HRESULT WINAPI XA2SUB_DisableEffect(IXAudio2SubmixVoice *iface, UINT32 EffectIndex,
1066 UINT32 OperationSet)
1068 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1069 TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
1070 return S_OK;
1073 static void WINAPI XA2SUB_GetEffectState(IXAudio2SubmixVoice *iface, UINT32 EffectIndex,
1074 BOOL *pEnabled)
1076 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1077 TRACE("%p, %u, %p\n", This, EffectIndex, pEnabled);
1080 static HRESULT WINAPI XA2SUB_SetEffectParameters(IXAudio2SubmixVoice *iface,
1081 UINT32 EffectIndex, const void *pParameters, UINT32 ParametersByteSize,
1082 UINT32 OperationSet)
1084 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1085 TRACE("%p, %u, %p, 0x%x, 0x%x\n", This, EffectIndex, pParameters,
1086 ParametersByteSize, OperationSet);
1087 return S_OK;
1090 static HRESULT WINAPI XA2SUB_GetEffectParameters(IXAudio2SubmixVoice *iface,
1091 UINT32 EffectIndex, void *pParameters, UINT32 ParametersByteSize)
1093 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1094 TRACE("%p, %u, %p, 0x%x\n", This, EffectIndex, pParameters,
1095 ParametersByteSize);
1096 return S_OK;
1099 static HRESULT WINAPI XA2SUB_SetFilterParameters(IXAudio2SubmixVoice *iface,
1100 const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
1102 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1103 TRACE("%p, %p, 0x%x\n", This, pParameters, OperationSet);
1104 return S_OK;
1107 static void WINAPI XA2SUB_GetFilterParameters(IXAudio2SubmixVoice *iface,
1108 XAUDIO2_FILTER_PARAMETERS *pParameters)
1110 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1111 TRACE("%p, %p\n", This, pParameters);
1114 static HRESULT WINAPI XA2SUB_SetOutputFilterParameters(IXAudio2SubmixVoice *iface,
1115 IXAudio2Voice *pDestinationVoice,
1116 const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
1118 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1119 TRACE("%p, %p, %p, 0x%x\n", This, pDestinationVoice, pParameters, OperationSet);
1120 return S_OK;
1123 static void WINAPI XA2SUB_GetOutputFilterParameters(IXAudio2SubmixVoice *iface,
1124 IXAudio2Voice *pDestinationVoice,
1125 XAUDIO2_FILTER_PARAMETERS *pParameters)
1127 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1128 TRACE("%p, %p, %p\n", This, pDestinationVoice, pParameters);
1131 static HRESULT WINAPI XA2SUB_SetVolume(IXAudio2SubmixVoice *iface, float Volume,
1132 UINT32 OperationSet)
1134 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1135 TRACE("%p, %f, 0x%x\n", This, Volume, OperationSet);
1136 return S_OK;
1139 static void WINAPI XA2SUB_GetVolume(IXAudio2SubmixVoice *iface, float *pVolume)
1141 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1142 TRACE("%p, %p\n", This, pVolume);
1145 static HRESULT WINAPI XA2SUB_SetChannelVolumes(IXAudio2SubmixVoice *iface, UINT32 Channels,
1146 const float *pVolumes, UINT32 OperationSet)
1148 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1149 TRACE("%p, %u, %p, 0x%x\n", This, Channels, pVolumes, OperationSet);
1150 return S_OK;
1153 static void WINAPI XA2SUB_GetChannelVolumes(IXAudio2SubmixVoice *iface, UINT32 Channels,
1154 float *pVolumes)
1156 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1157 TRACE("%p, %u, %p\n", This, Channels, pVolumes);
1160 static HRESULT WINAPI XA2SUB_SetOutputMatrix(IXAudio2SubmixVoice *iface,
1161 IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
1162 UINT32 DestinationChannels, const float *pLevelMatrix,
1163 UINT32 OperationSet)
1165 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1166 TRACE("%p, %p, %u, %u, %p, 0x%x\n", This, pDestinationVoice,
1167 SourceChannels, DestinationChannels, pLevelMatrix, OperationSet);
1168 return S_OK;
1171 static void WINAPI XA2SUB_GetOutputMatrix(IXAudio2SubmixVoice *iface,
1172 IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
1173 UINT32 DestinationChannels, float *pLevelMatrix)
1175 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1176 TRACE("%p, %p, %u, %u, %p\n", This, pDestinationVoice,
1177 SourceChannels, DestinationChannels, pLevelMatrix);
1180 static void WINAPI XA2SUB_DestroyVoice(IXAudio2SubmixVoice *iface)
1182 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1184 TRACE("%p\n", This);
1186 EnterCriticalSection(&This->lock);
1188 This->in_use = FALSE;
1190 LeaveCriticalSection(&This->lock);
1193 static const struct IXAudio2SubmixVoiceVtbl XAudio2SubmixVoice_Vtbl = {
1194 XA2SUB_GetVoiceDetails,
1195 XA2SUB_SetOutputVoices,
1196 XA2SUB_SetEffectChain,
1197 XA2SUB_EnableEffect,
1198 XA2SUB_DisableEffect,
1199 XA2SUB_GetEffectState,
1200 XA2SUB_SetEffectParameters,
1201 XA2SUB_GetEffectParameters,
1202 XA2SUB_SetFilterParameters,
1203 XA2SUB_GetFilterParameters,
1204 XA2SUB_SetOutputFilterParameters,
1205 XA2SUB_GetOutputFilterParameters,
1206 XA2SUB_SetVolume,
1207 XA2SUB_GetVolume,
1208 XA2SUB_SetChannelVolumes,
1209 XA2SUB_GetChannelVolumes,
1210 XA2SUB_SetOutputMatrix,
1211 XA2SUB_GetOutputMatrix,
1212 XA2SUB_DestroyVoice
1215 static HRESULT WINAPI IXAudio2Impl_QueryInterface(IXAudio2 *iface, REFIID riid,
1216 void **ppvObject)
1218 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1220 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
1222 if(IsEqualGUID(riid, &IID_IUnknown) ||
1223 IsEqualGUID(riid, &IID_IXAudio28) ||
1224 IsEqualGUID(riid, &IID_IXAudio2))
1225 *ppvObject = &This->IXAudio2_iface;
1226 else if(IsEqualGUID(riid, &IID_IXAudio27)){
1227 /* all xaudio versions before 28 share an IID */
1228 #if XAUDIO2_VER == 0
1229 *ppvObject = &This->IXAudio20_iface;
1230 #elif XAUDIO2_VER <= 2
1231 *ppvObject = &This->IXAudio22_iface;
1232 #elif XAUDIO2_VER <= 7
1233 *ppvObject = &This->IXAudio27_iface;
1234 #else
1235 *ppvObject = NULL;
1236 #endif
1237 }else
1238 *ppvObject = NULL;
1240 if(*ppvObject){
1241 IUnknown_AddRef((IUnknown*)*ppvObject);
1242 return S_OK;
1245 FIXME("(%p)->(%s,%p), not found\n", This,debugstr_guid(riid), ppvObject);
1247 return E_NOINTERFACE;
1250 static ULONG WINAPI IXAudio2Impl_AddRef(IXAudio2 *iface)
1252 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1253 ULONG ref = InterlockedIncrement(&This->ref);
1254 TRACE("(%p)->(): Refcount now %u\n", This, ref);
1255 return ref;
1258 static ULONG WINAPI IXAudio2Impl_Release(IXAudio2 *iface)
1260 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1261 ULONG ref = InterlockedDecrement(&This->ref);
1263 TRACE("(%p)->(): Refcount now %u\n", This, ref);
1265 if (!ref) {
1266 int i;
1267 XA2SourceImpl *src, *src2;
1268 XA2SubmixImpl *sub, *sub2;
1270 if(This->engine){
1271 This->stop_engine = TRUE;
1272 SetEvent(This->mmevt);
1273 WaitForSingleObject(This->engine, INFINITE);
1274 CloseHandle(This->engine);
1277 LIST_FOR_EACH_ENTRY_SAFE(src, src2, &This->source_voices, XA2SourceImpl, entry){
1278 HeapFree(GetProcessHeap(), 0, src->sends);
1279 IXAudio2SourceVoice_DestroyVoice(&src->IXAudio2SourceVoice_iface);
1280 src->lock.DebugInfo->Spare[0] = 0;
1281 DeleteCriticalSection(&src->lock);
1282 HeapFree(GetProcessHeap(), 0, src);
1285 LIST_FOR_EACH_ENTRY_SAFE(sub, sub2, &This->submix_voices, XA2SubmixImpl, entry){
1286 IXAudio2SubmixVoice_DestroyVoice(&sub->IXAudio2SubmixVoice_iface);
1287 sub->lock.DebugInfo->Spare[0] = 0;
1288 DeleteCriticalSection(&sub->lock);
1289 HeapFree(GetProcessHeap(), 0, sub);
1292 IXAudio2MasteringVoice_DestroyVoice(&This->IXAudio2MasteringVoice_iface);
1294 if(This->devenum)
1295 IMMDeviceEnumerator_Release(This->devenum);
1296 for(i = 0; i < This->ndevs; ++i)
1297 CoTaskMemFree(This->devids[i]);
1298 HeapFree(GetProcessHeap(), 0, This->devids);
1299 HeapFree(GetProcessHeap(), 0, This->cbs);
1301 CloseHandle(This->mmevt);
1303 This->lock.DebugInfo->Spare[0] = 0;
1304 DeleteCriticalSection(&This->lock);
1306 HeapFree(GetProcessHeap(), 0, This);
1308 return ref;
1311 static HRESULT WINAPI IXAudio2Impl_RegisterForCallbacks(IXAudio2 *iface,
1312 IXAudio2EngineCallback *pCallback)
1314 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1315 int i;
1317 TRACE("(%p)->(%p)\n", This, pCallback);
1319 EnterCriticalSection(&This->lock);
1321 for(i = 0; i < This->ncbs; ++i){
1322 if(!This->cbs[i] || This->cbs[i] == pCallback){
1323 This->cbs[i] = pCallback;
1324 LeaveCriticalSection(&This->lock);
1325 return S_OK;
1329 This->ncbs *= 2;
1330 This->cbs = HeapReAlloc(GetProcessHeap(), 0, This->cbs, This->ncbs * sizeof(*This->cbs));
1332 This->cbs[i] = pCallback;
1334 LeaveCriticalSection(&This->lock);
1336 return S_OK;
1339 static void WINAPI IXAudio2Impl_UnregisterForCallbacks(IXAudio2 *iface,
1340 IXAudio2EngineCallback *pCallback)
1342 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1343 int i;
1345 TRACE("(%p)->(%p)\n", This, pCallback);
1347 EnterCriticalSection(&This->lock);
1349 for(i = 0; i < This->ncbs; ++i){
1350 if(This->cbs[i] == pCallback)
1351 break;
1354 for(; i < This->ncbs - 1 && This->cbs[i + 1]; ++i)
1355 This->cbs[i] = This->cbs[i + 1];
1357 if(i < This->ncbs)
1358 This->cbs[i] = NULL;
1360 LeaveCriticalSection(&This->lock);
1363 static WAVEFORMATEX *copy_waveformat(const WAVEFORMATEX *wfex)
1365 WAVEFORMATEX *pwfx;
1367 if(wfex->wFormatTag == WAVE_FORMAT_PCM){
1368 pwfx = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEX));
1369 CopyMemory(pwfx, wfex, sizeof(PCMWAVEFORMAT));
1370 pwfx->cbSize = 0;
1371 }else{
1372 pwfx = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEX) + wfex->cbSize);
1373 CopyMemory(pwfx, wfex, sizeof(WAVEFORMATEX) + wfex->cbSize);
1376 return pwfx;
1379 static HRESULT WINAPI IXAudio2Impl_CreateSourceVoice(IXAudio2 *iface,
1380 IXAudio2SourceVoice **ppSourceVoice, const WAVEFORMATEX *pSourceFormat,
1381 UINT32 flags, float maxFrequencyRatio,
1382 IXAudio2VoiceCallback *pCallback, const XAUDIO2_VOICE_SENDS *pSendList,
1383 const XAUDIO2_EFFECT_CHAIN *pEffectChain)
1385 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1386 XA2SourceImpl *src;
1387 HRESULT hr;
1389 TRACE("(%p)->(%p, %p, 0x%x, %f, %p, %p, %p)\n", This, ppSourceVoice,
1390 pSourceFormat, flags, maxFrequencyRatio, pCallback, pSendList,
1391 pEffectChain);
1393 dump_fmt(pSourceFormat);
1395 palcSetThreadContext(This->al_ctx);
1397 EnterCriticalSection(&This->lock);
1399 LIST_FOR_EACH_ENTRY(src, &This->source_voices, XA2SourceImpl, entry){
1400 EnterCriticalSection(&src->lock);
1401 if(!src->in_use)
1402 break;
1403 LeaveCriticalSection(&src->lock);
1406 if(&src->entry == &This->source_voices){
1407 src = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*src));
1408 if(!src){
1409 LeaveCriticalSection(&This->lock);
1410 return E_OUTOFMEMORY;
1413 list_add_head(&This->source_voices, &src->entry);
1415 src->IXAudio2SourceVoice_iface.lpVtbl = &XAudio2SourceVoice_Vtbl;
1417 #if XAUDIO2_VER == 0
1418 src->IXAudio20SourceVoice_iface.lpVtbl = &XAudio20SourceVoice_Vtbl;
1419 #elif XAUDIO2_VER <= 3
1420 src->IXAudio23SourceVoice_iface.lpVtbl = &XAudio23SourceVoice_Vtbl;
1421 #elif XAUDIO2_VER <= 7
1422 src->IXAudio27SourceVoice_iface.lpVtbl = &XAudio27SourceVoice_Vtbl;
1423 #endif
1425 InitializeCriticalSection(&src->lock);
1426 src->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": XA2SourceImpl.lock");
1428 src->xa2 = This;
1430 EnterCriticalSection(&src->lock);
1433 src->in_use = TRUE;
1434 src->running = FALSE;
1436 LeaveCriticalSection(&This->lock);
1438 src->cb = pCallback;
1440 src->al_fmt = get_al_format(pSourceFormat);
1441 if(!src->al_fmt){
1442 src->in_use = FALSE;
1443 LeaveCriticalSection(&src->lock);
1444 WARN("OpenAL can't convert this format!\n");
1445 return AUDCLNT_E_UNSUPPORTED_FORMAT;
1448 src->submit_blocksize = pSourceFormat->nBlockAlign;
1450 src->fmt = copy_waveformat(pSourceFormat);
1452 hr = XA2SRC_SetOutputVoices(&src->IXAudio2SourceVoice_iface, pSendList);
1453 if(FAILED(hr)){
1454 HeapFree(GetProcessHeap(), 0, src->fmt);
1455 src->in_use = FALSE;
1456 LeaveCriticalSection(&src->lock);
1457 return hr;
1460 alGenSources(1, &src->al_src);
1461 if(!src->al_src){
1462 static int once = 0;
1463 if(!once++)
1464 ERR_(winediag)("OpenAL ran out of sources, consider increasing its source limit.\n");
1465 HeapFree(GetProcessHeap(), 0, src->fmt);
1466 src->in_use = FALSE;
1467 LeaveCriticalSection(&src->lock);
1468 return E_OUTOFMEMORY;
1471 alGenBuffers(XAUDIO2_MAX_QUEUED_BUFFERS, src->al_bufs);
1473 alSourcePlay(src->al_src);
1475 LeaveCriticalSection(&src->lock);
1477 #if XAUDIO2_VER == 0
1478 *ppSourceVoice = (IXAudio2SourceVoice*)&src->IXAudio20SourceVoice_iface;
1479 #elif XAUDIO2_VER <= 3
1480 *ppSourceVoice = (IXAudio2SourceVoice*)&src->IXAudio23SourceVoice_iface;
1481 #elif XAUDIO2_VER <= 7
1482 *ppSourceVoice = (IXAudio2SourceVoice*)&src->IXAudio27SourceVoice_iface;
1483 #else
1484 *ppSourceVoice = &src->IXAudio2SourceVoice_iface;
1485 #endif
1487 TRACE("Created source voice: %p\n", src);
1489 return S_OK;
1492 static HRESULT WINAPI IXAudio2Impl_CreateSubmixVoice(IXAudio2 *iface,
1493 IXAudio2SubmixVoice **ppSubmixVoice, UINT32 inputChannels,
1494 UINT32 inputSampleRate, UINT32 flags, UINT32 processingStage,
1495 const XAUDIO2_VOICE_SENDS *pSendList,
1496 const XAUDIO2_EFFECT_CHAIN *pEffectChain)
1498 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1499 XA2SubmixImpl *sub;
1501 TRACE("(%p)->(%p, %u, %u, 0x%x, %u, %p, %p)\n", This, ppSubmixVoice,
1502 inputChannels, inputSampleRate, flags, processingStage, pSendList,
1503 pEffectChain);
1505 EnterCriticalSection(&This->lock);
1507 LIST_FOR_EACH_ENTRY(sub, &This->submix_voices, XA2SubmixImpl, entry){
1508 EnterCriticalSection(&sub->lock);
1509 if(!sub->in_use)
1510 break;
1511 LeaveCriticalSection(&sub->lock);
1514 if(&sub->entry == &This->submix_voices){
1515 sub = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*sub));
1516 if(!sub){
1517 LeaveCriticalSection(&This->lock);
1518 return E_OUTOFMEMORY;
1521 list_add_head(&This->submix_voices, &sub->entry);
1523 sub->IXAudio2SubmixVoice_iface.lpVtbl = &XAudio2SubmixVoice_Vtbl;
1525 #if XAUDIO2_VER == 0
1526 sub->IXAudio20SubmixVoice_iface.lpVtbl = &XAudio20SubmixVoice_Vtbl;
1527 #elif XAUDIO2_VER <= 3
1528 sub->IXAudio23SubmixVoice_iface.lpVtbl = &XAudio23SubmixVoice_Vtbl;
1529 #elif XAUDIO2_VER <= 7
1530 sub->IXAudio27SubmixVoice_iface.lpVtbl = &XAudio27SubmixVoice_Vtbl;
1531 #endif
1533 InitializeCriticalSection(&sub->lock);
1534 sub->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": XA2SubmixImpl.lock");
1536 EnterCriticalSection(&sub->lock);
1539 sub->in_use = TRUE;
1541 sub->details.CreationFlags = flags;
1542 sub->details.ActiveFlags = flags;
1543 sub->details.InputChannels = inputChannels;
1544 sub->details.InputSampleRate = inputSampleRate;
1546 LeaveCriticalSection(&This->lock);
1547 LeaveCriticalSection(&sub->lock);
1549 #if XAUDIO2_VER == 0
1550 *ppSubmixVoice = (IXAudio2SubmixVoice*)&sub->IXAudio20SubmixVoice_iface;
1551 #elif XAUDIO2_VER <= 3
1552 *ppSubmixVoice = (IXAudio2SubmixVoice*)&sub->IXAudio23SubmixVoice_iface;
1553 #elif XAUDIO2_VER <= 7
1554 *ppSubmixVoice = (IXAudio2SubmixVoice*)&sub->IXAudio27SubmixVoice_iface;
1555 #else
1556 *ppSubmixVoice = &sub->IXAudio2SubmixVoice_iface;
1557 #endif
1559 TRACE("Created submix voice: %p\n", sub);
1561 return S_OK;
1564 static ALenum al_get_loopback_format(const WAVEFORMATEXTENSIBLE *fmt)
1566 if(fmt->Format.wFormatTag == WAVE_FORMAT_PCM ||
1567 (fmt->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1568 IsEqualGUID(&fmt->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
1569 switch(fmt->Format.wBitsPerSample){
1570 case 8:
1571 return ALC_UNSIGNED_BYTE_SOFT;
1572 case 16:
1573 return ALC_SHORT_SOFT;
1574 case 32:
1575 return ALC_INT_SOFT;
1577 }else if(fmt->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
1578 (fmt->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1579 IsEqualGUID(&fmt->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
1580 if(fmt->Format.wBitsPerSample == 32)
1581 return ALC_FLOAT_SOFT;
1583 return 0;
1586 static HRESULT WINAPI IXAudio2Impl_CreateMasteringVoice(IXAudio2 *iface,
1587 IXAudio2MasteringVoice **ppMasteringVoice, UINT32 inputChannels,
1588 UINT32 inputSampleRate, UINT32 flags, const WCHAR *deviceId,
1589 const XAUDIO2_EFFECT_CHAIN *pEffectChain,
1590 AUDIO_STREAM_CATEGORY streamCategory)
1592 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1593 IMMDevice *dev;
1594 HRESULT hr;
1595 WAVEFORMATEX *fmt;
1596 ALCint attrs[11];
1597 REFERENCE_TIME period, bufdur;
1599 TRACE("(%p)->(%p, %u, %u, 0x%x, %s, %p, 0x%x)\n", This,
1600 ppMasteringVoice, inputChannels, inputSampleRate, flags,
1601 wine_dbgstr_w(deviceId), pEffectChain, streamCategory);
1603 if(flags != 0)
1604 WARN("Unknown flags set: 0x%x\n", flags);
1606 if(pEffectChain)
1607 WARN("Effect chain is unimplemented\n");
1609 EnterCriticalSection(&This->lock);
1611 /* there can only be one Mastering Voice, so just build it into XA2 */
1612 if(This->aclient){
1613 LeaveCriticalSection(&This->lock);
1614 return COMPAT_E_INVALID_CALL;
1617 if(!deviceId){
1618 if(This->ndevs == 0){
1619 LeaveCriticalSection(&This->lock);
1620 return E_NOTFOUND;
1622 deviceId = This->devids[0];
1625 hr = IMMDeviceEnumerator_GetDevice(This->devenum, deviceId, &dev);
1626 if(FAILED(hr)){
1627 WARN("GetDevice failed: %08x\n", hr);
1628 hr = COMPAT_E_DEVICE_INVALIDATED;
1629 goto exit;
1632 hr = IMMDevice_Activate(dev, &IID_IAudioClient,
1633 CLSCTX_INPROC_SERVER, NULL, (void**)&This->aclient);
1634 if(FAILED(hr)){
1635 WARN("Activate(IAudioClient) failed: %08x\n", hr);
1636 IMMDevice_Release(dev);
1637 hr = COMPAT_E_DEVICE_INVALIDATED;
1638 goto exit;
1641 IMMDevice_Release(dev);
1643 hr = IAudioClient_GetMixFormat(This->aclient, &fmt);
1644 if(FAILED(hr)){
1645 WARN("GetMixFormat failed: %08x\n", hr);
1646 hr = COMPAT_E_DEVICE_INVALIDATED;
1647 goto exit;
1650 if(sizeof(WAVEFORMATEX) + fmt->cbSize > sizeof(WAVEFORMATEXTENSIBLE)){
1651 FIXME("Mix format doesn't fit into WAVEFORMATEXTENSIBLE!\n");
1652 hr = COMPAT_E_DEVICE_INVALIDATED;
1653 goto exit;
1656 if(inputChannels == XAUDIO2_DEFAULT_CHANNELS)
1657 inputChannels = fmt->nChannels;
1658 if(inputSampleRate == XAUDIO2_DEFAULT_SAMPLERATE)
1659 inputSampleRate = fmt->nSamplesPerSec;
1661 memcpy(&This->fmt, fmt, sizeof(WAVEFORMATEX) + fmt->cbSize);
1662 This->fmt.Format.nChannels = inputChannels;
1663 This->fmt.Format.nSamplesPerSec = inputSampleRate;
1664 This->fmt.Format.nBlockAlign = This->fmt.Format.nChannels * This->fmt.Format.wBitsPerSample / 8;
1665 This->fmt.Format.nAvgBytesPerSec = This->fmt.Format.nSamplesPerSec * This->fmt.Format.nBlockAlign;
1666 This->fmt.dwChannelMask = get_channel_mask(This->fmt.Format.nChannels);
1668 CoTaskMemFree(fmt);
1669 fmt = NULL;
1671 hr = IAudioClient_IsFormatSupported(This->aclient,
1672 AUDCLNT_SHAREMODE_SHARED, &This->fmt.Format, &fmt);
1673 if(hr == S_FALSE){
1674 if(sizeof(WAVEFORMATEX) + fmt->cbSize > sizeof(WAVEFORMATEXTENSIBLE)){
1675 FIXME("Mix format doesn't fit into WAVEFORMATEXTENSIBLE!\n");
1676 hr = COMPAT_E_DEVICE_INVALIDATED;
1677 goto exit;
1679 memcpy(&This->fmt, fmt, sizeof(WAVEFORMATEX) + fmt->cbSize);
1682 CoTaskMemFree(fmt);
1684 hr = IAudioClient_GetDevicePeriod(This->aclient, &period, NULL);
1685 if(FAILED(hr)){
1686 WARN("GetDevicePeriod failed: %08x\n", hr);
1687 hr = COMPAT_E_DEVICE_INVALIDATED;
1688 goto exit;
1691 /* 3 periods or 0.1 seconds */
1692 bufdur = max(3 * period, 1000000);
1694 hr = IAudioClient_Initialize(This->aclient, AUDCLNT_SHAREMODE_SHARED,
1695 AUDCLNT_STREAMFLAGS_EVENTCALLBACK, bufdur,
1696 0, &This->fmt.Format, NULL);
1697 if(FAILED(hr)){
1698 WARN("Initialize failed: %08x\n", hr);
1699 hr = COMPAT_E_DEVICE_INVALIDATED;
1700 goto exit;
1703 This->period_frames = MulDiv(period, inputSampleRate, 10000000);
1705 hr = IAudioClient_SetEventHandle(This->aclient, This->mmevt);
1706 if(FAILED(hr)){
1707 WARN("Initialize failed: %08x\n", hr);
1708 hr = COMPAT_E_DEVICE_INVALIDATED;
1709 goto exit;
1712 hr = IAudioClient_GetService(This->aclient, &IID_IAudioRenderClient,
1713 (void**)&This->render);
1714 if(FAILED(hr)){
1715 WARN("GetService(IAudioRenderClient) failed: %08x\n", hr);
1716 hr = COMPAT_E_DEVICE_INVALIDATED;
1717 goto exit;
1720 /* setup openal context */
1721 attrs[0] = ALC_FORMAT_CHANNELS_SOFT;
1722 switch(inputChannels){
1723 case 1:
1724 attrs[1] = ALC_MONO_SOFT;
1725 break;
1726 case 2:
1727 attrs[1] = ALC_STEREO_SOFT;
1728 break;
1729 case 4:
1730 attrs[1] = ALC_QUAD_SOFT;
1731 break;
1732 case 6:
1733 attrs[1] = ALC_5POINT1_SOFT;
1734 break;
1735 case 7:
1736 attrs[1] = ALC_6POINT1_SOFT;
1737 break;
1738 case 8:
1739 attrs[1] = ALC_7POINT1_SOFT;
1740 break;
1741 default:
1742 WARN("OpenAL doesn't support %u channels\n", inputChannels);
1743 LeaveCriticalSection(&This->lock);
1744 return AUDCLNT_E_UNSUPPORTED_FORMAT;
1747 attrs[2] = ALC_FREQUENCY;
1748 attrs[3] = inputSampleRate;
1750 attrs[4] = ALC_FORMAT_TYPE_SOFT;
1751 attrs[5] = al_get_loopback_format(&This->fmt);
1753 /* some games create very many sources */
1754 attrs[6] = ALC_STEREO_SOURCES;
1755 attrs[7] = 1024;
1756 attrs[8] = ALC_MONO_SOURCES;
1757 attrs[9] = 1024;
1759 attrs[10] = 0;
1761 if(!attrs[5]){
1762 WARN("OpenAL can't output samples in this format\n");
1763 hr = COMPAT_E_DEVICE_INVALIDATED;
1764 goto exit;
1767 This->al_device = palcLoopbackOpenDeviceSOFT(NULL);
1768 if(!This->al_device){
1769 WARN("alcLoopbackOpenDeviceSOFT failed\n");
1770 hr = COMPAT_E_DEVICE_INVALIDATED;
1771 goto exit;
1774 This->al_ctx = alcCreateContext(This->al_device, attrs);
1775 if(!This->al_ctx){
1776 WARN("alcCreateContext failed\n");
1777 hr = COMPAT_E_DEVICE_INVALIDATED;
1778 goto exit;
1781 hr = IAudioClient_Start(This->aclient);
1782 if (FAILED(hr))
1784 WARN("Start(IAudioClient) failed: %08x\n", hr);
1785 hr = COMPAT_E_DEVICE_INVALIDATED;
1786 goto exit;
1789 #if XAUDIO2_VER == 0
1790 *ppMasteringVoice = (IXAudio2MasteringVoice*)&This->IXAudio20MasteringVoice_iface;
1791 #elif XAUDIO2_VER <= 3
1792 *ppMasteringVoice = (IXAudio2MasteringVoice*)&This->IXAudio23MasteringVoice_iface;
1793 #elif XAUDIO2_VER <= 7
1794 *ppMasteringVoice = (IXAudio2MasteringVoice*)&This->IXAudio27MasteringVoice_iface;
1795 #else
1796 *ppMasteringVoice = &This->IXAudio2MasteringVoice_iface;
1797 #endif
1799 exit:
1800 if(FAILED(hr)){
1801 if(This->render){
1802 IAudioRenderClient_Release(This->render);
1803 This->render = NULL;
1805 if(This->aclient){
1806 IAudioClient_Release(This->aclient);
1807 This->aclient = NULL;
1809 if(This->al_ctx){
1810 alcDestroyContext(This->al_ctx);
1811 This->al_ctx = NULL;
1813 if(This->al_device){
1814 alcCloseDevice(This->al_device);
1815 This->al_device = NULL;
1819 LeaveCriticalSection(&This->lock);
1821 return hr;
1824 static DWORD WINAPI engine_threadproc(void *arg);
1826 static HRESULT WINAPI IXAudio2Impl_StartEngine(IXAudio2 *iface)
1828 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1830 TRACE("(%p)->()\n", This);
1832 This->running = TRUE;
1834 if(!This->engine)
1835 This->engine = CreateThread(NULL, 0, engine_threadproc, This, 0, NULL);
1837 return S_OK;
1840 static void WINAPI IXAudio2Impl_StopEngine(IXAudio2 *iface)
1842 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1844 TRACE("(%p)->()\n", This);
1846 This->running = FALSE;
1849 static HRESULT WINAPI IXAudio2Impl_CommitChanges(IXAudio2 *iface,
1850 UINT32 operationSet)
1852 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1854 TRACE("(%p)->(0x%x): stub!\n", This, operationSet);
1856 return E_NOTIMPL;
1859 static void WINAPI IXAudio2Impl_GetPerformanceData(IXAudio2 *iface,
1860 XAUDIO2_PERFORMANCE_DATA *pPerfData)
1862 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1864 TRACE("(%p)->(%p): stub!\n", This, pPerfData);
1866 memset(pPerfData, 0, sizeof(*pPerfData));
1869 static void WINAPI IXAudio2Impl_SetDebugConfiguration(IXAudio2 *iface,
1870 const XAUDIO2_DEBUG_CONFIGURATION *pDebugConfiguration,
1871 void *pReserved)
1873 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1875 FIXME("(%p)->(%p, %p): stub!\n", This, pDebugConfiguration, pReserved);
1878 /* XAudio2 2.8 */
1879 static const IXAudio2Vtbl XAudio2_Vtbl =
1881 IXAudio2Impl_QueryInterface,
1882 IXAudio2Impl_AddRef,
1883 IXAudio2Impl_Release,
1884 IXAudio2Impl_RegisterForCallbacks,
1885 IXAudio2Impl_UnregisterForCallbacks,
1886 IXAudio2Impl_CreateSourceVoice,
1887 IXAudio2Impl_CreateSubmixVoice,
1888 IXAudio2Impl_CreateMasteringVoice,
1889 IXAudio2Impl_StartEngine,
1890 IXAudio2Impl_StopEngine,
1891 IXAudio2Impl_CommitChanges,
1892 IXAudio2Impl_GetPerformanceData,
1893 IXAudio2Impl_SetDebugConfiguration
1896 struct xaudio2_cf {
1897 IClassFactory IClassFactory_iface;
1898 LONG ref;
1901 static struct xaudio2_cf *impl_from_IClassFactory(IClassFactory *iface)
1903 return CONTAINING_RECORD(iface, struct xaudio2_cf, IClassFactory_iface);
1906 static HRESULT WINAPI XAudio2CF_QueryInterface(IClassFactory *iface, REFIID riid, void **ppobj)
1908 if(IsEqualGUID(riid, &IID_IUnknown)
1909 || IsEqualGUID(riid, &IID_IClassFactory))
1911 IClassFactory_AddRef(iface);
1912 *ppobj = iface;
1913 return S_OK;
1916 *ppobj = NULL;
1917 WARN("(%p)->(%s, %p): interface not found\n", iface, debugstr_guid(riid), ppobj);
1918 return E_NOINTERFACE;
1921 static ULONG WINAPI XAudio2CF_AddRef(IClassFactory *iface)
1923 struct xaudio2_cf *This = impl_from_IClassFactory(iface);
1924 ULONG ref = InterlockedIncrement(&This->ref);
1925 TRACE("(%p)->(): Refcount now %u\n", This, ref);
1926 return ref;
1929 static ULONG WINAPI XAudio2CF_Release(IClassFactory *iface)
1931 struct xaudio2_cf *This = impl_from_IClassFactory(iface);
1932 ULONG ref = InterlockedDecrement(&This->ref);
1933 TRACE("(%p)->(): Refcount now %u\n", This, ref);
1934 if (!ref)
1935 HeapFree(GetProcessHeap(), 0, This);
1936 return ref;
1939 static HRESULT initialize_mmdevices(IXAudio2Impl *This)
1941 IMMDeviceCollection *devcoll;
1942 UINT devcount;
1943 HRESULT hr;
1945 if(!This->devenum){
1946 hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL,
1947 CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void**)&This->devenum);
1948 if(FAILED(hr))
1949 return hr;
1952 hr = IMMDeviceEnumerator_EnumAudioEndpoints(This->devenum, eRender,
1953 DEVICE_STATE_ACTIVE, &devcoll);
1954 if(FAILED(hr)){
1955 return hr;
1958 hr = IMMDeviceCollection_GetCount(devcoll, &devcount);
1959 if(FAILED(hr)){
1960 IMMDeviceCollection_Release(devcoll);
1961 return hr;
1964 if(devcount > 0){
1965 UINT i, count = 1;
1966 IMMDevice *dev, *def_dev;
1968 /* make sure that device 0 is the default device */
1969 IMMDeviceEnumerator_GetDefaultAudioEndpoint(This->devenum, eRender, eConsole, &def_dev);
1971 This->devids = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *) * devcount);
1973 for(i = 0; i < devcount; ++i){
1974 hr = IMMDeviceCollection_Item(devcoll, i, &dev);
1975 if(SUCCEEDED(hr)){
1976 UINT idx;
1978 if(dev == def_dev)
1979 idx = 0;
1980 else{
1981 idx = count;
1982 ++count;
1985 hr = IMMDevice_GetId(dev, &This->devids[idx]);
1986 if(FAILED(hr)){
1987 WARN("GetId failed: %08x\n", hr);
1988 HeapFree(GetProcessHeap(), 0, This->devids);
1989 This->devids = NULL;
1990 IMMDevice_Release(dev);
1991 return hr;
1994 IMMDevice_Release(dev);
1995 }else{
1996 WARN("Item failed: %08x\n", hr);
1997 HeapFree(GetProcessHeap(), 0, This->devids);
1998 This->devids = NULL;
1999 IMMDeviceCollection_Release(devcoll);
2000 return hr;
2005 IMMDeviceCollection_Release(devcoll);
2007 This->ndevs = devcount;
2009 return S_OK;
2012 static HRESULT WINAPI XAudio2CF_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
2013 REFIID riid, void **ppobj)
2015 struct xaudio2_cf *This = impl_from_IClassFactory(iface);
2016 HRESULT hr;
2017 IXAudio2Impl *object;
2019 TRACE("(%p)->(%p,%s,%p)\n", This, pOuter, debugstr_guid(riid), ppobj);
2021 *ppobj = NULL;
2023 if(pOuter)
2024 return CLASS_E_NOAGGREGATION;
2026 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2027 if(!object)
2028 return E_OUTOFMEMORY;
2030 object->IXAudio2_iface.lpVtbl = &XAudio2_Vtbl;
2031 object->IXAudio2MasteringVoice_iface.lpVtbl = &XAudio2MasteringVoice_Vtbl;
2033 #if XAUDIO2_VER == 0
2034 object->IXAudio20_iface.lpVtbl = &XAudio20_Vtbl;
2035 #elif XAUDIO2_VER <= 2
2036 object->IXAudio22_iface.lpVtbl = &XAudio22_Vtbl;
2037 #elif XAUDIO2_VER <= 7
2038 object->IXAudio27_iface.lpVtbl = &XAudio27_Vtbl;
2039 #endif
2041 #if XAUDIO2_VER == 0
2042 object->IXAudio20MasteringVoice_iface.lpVtbl = &XAudio20MasteringVoice_Vtbl;
2043 #elif XAUDIO2_VER <= 3
2044 object->IXAudio23MasteringVoice_iface.lpVtbl = &XAudio23MasteringVoice_Vtbl;
2045 #elif XAUDIO2_VER <= 7
2046 object->IXAudio27MasteringVoice_iface.lpVtbl = &XAudio27MasteringVoice_Vtbl;
2047 #endif
2049 list_init(&object->source_voices);
2050 list_init(&object->submix_voices);
2052 object->mmevt = CreateEventW(NULL, FALSE, FALSE, NULL);
2053 InitializeCriticalSection(&object->lock);
2054 object->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IXAudio2Impl.lock");
2056 hr = IXAudio2_QueryInterface(&object->IXAudio2_iface, riid, ppobj);
2057 if(FAILED(hr)){
2058 HeapFree(GetProcessHeap(), 0, object);
2059 return hr;
2062 hr = initialize_mmdevices(object);
2063 if(FAILED(hr)){
2064 IUnknown_Release((IUnknown*)*ppobj);
2065 return hr;
2068 object->ncbs = 4;
2069 object->cbs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->ncbs * sizeof(*object->cbs));
2071 IXAudio2_StartEngine(&object->IXAudio2_iface);
2073 TRACE("Created XAudio version %u: %p\n", 20 + XAUDIO2_VER, object);
2075 return hr;
2078 static HRESULT WINAPI XAudio2CF_LockServer(IClassFactory *iface, BOOL dolock)
2080 FIXME("(static)->(%d): stub!\n", dolock);
2081 return S_OK;
2084 static const IClassFactoryVtbl XAudio2CF_Vtbl =
2086 XAudio2CF_QueryInterface,
2087 XAudio2CF_AddRef,
2088 XAudio2CF_Release,
2089 XAudio2CF_CreateInstance,
2090 XAudio2CF_LockServer
2093 static IClassFactory *make_xaudio2_factory(void)
2095 struct xaudio2_cf *ret = HeapAlloc(GetProcessHeap(), 0, sizeof(struct xaudio2_cf));
2096 ret->IClassFactory_iface.lpVtbl = &XAudio2CF_Vtbl;
2097 ret->ref = 0;
2098 return &ret->IClassFactory_iface;
2101 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
2103 IClassFactory *factory = NULL;
2105 TRACE("(%s, %s, %p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
2107 if(IsEqualGUID(rclsid, &CLSID_XAudio20) ||
2108 IsEqualGUID(rclsid, &CLSID_XAudio21) ||
2109 IsEqualGUID(rclsid, &CLSID_XAudio22) ||
2110 IsEqualGUID(rclsid, &CLSID_XAudio23) ||
2111 IsEqualGUID(rclsid, &CLSID_XAudio24) ||
2112 IsEqualGUID(rclsid, &CLSID_XAudio25) ||
2113 IsEqualGUID(rclsid, &CLSID_XAudio26) ||
2114 IsEqualGUID(rclsid, &CLSID_XAudio27)){
2115 factory = make_xaudio2_factory();
2117 }else if(IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter20) ||
2118 IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter21) ||
2119 IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter22) ||
2120 IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter23) ||
2121 IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter24) ||
2122 IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter25) ||
2123 IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter26) ||
2124 IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter27)){
2125 factory = make_xapo_factory(&CLSID_AudioVolumeMeter27);
2127 }else if(IsEqualGUID(rclsid, &CLSID_AudioReverb20) ||
2128 IsEqualGUID(rclsid, &CLSID_AudioReverb21) ||
2129 IsEqualGUID(rclsid, &CLSID_AudioReverb22) ||
2130 IsEqualGUID(rclsid, &CLSID_AudioReverb23) ||
2131 IsEqualGUID(rclsid, &CLSID_AudioReverb24) ||
2132 IsEqualGUID(rclsid, &CLSID_AudioReverb25) ||
2133 IsEqualGUID(rclsid, &CLSID_AudioReverb26) ||
2134 IsEqualGUID(rclsid, &CLSID_AudioReverb27)){
2135 factory = make_xapo_factory(&CLSID_FXReverb);
2138 if(!factory) return CLASS_E_CLASSNOTAVAILABLE;
2140 return IClassFactory_QueryInterface(factory, riid, ppv);
2143 HRESULT xaudio2_initialize(IXAudio2Impl *This, UINT32 flags, XAUDIO2_PROCESSOR proc)
2145 if(flags)
2146 FIXME("Unimplemented flags: 0x%x\n", flags);
2147 return S_OK;
2150 #if XAUDIO2_VER >= 8
2151 HRESULT WINAPI XAudio2Create(IXAudio2 **ppxa2, UINT32 flags, XAUDIO2_PROCESSOR proc)
2153 HRESULT hr;
2154 IXAudio2 *xa2;
2155 IClassFactory *cf;
2157 TRACE("%p 0x%x 0x%x\n", ppxa2, flags, proc);
2159 cf = make_xaudio2_factory();
2161 hr = IClassFactory_CreateInstance(cf, NULL, &IID_IXAudio2, (void**)&xa2);
2162 IClassFactory_Release(cf);
2163 if(FAILED(hr))
2164 return hr;
2166 hr = xaudio2_initialize(impl_from_IXAudio2(xa2), flags, proc);
2167 if(FAILED(hr)){
2168 IXAudio2_Release(xa2);
2169 return hr;
2172 *ppxa2 = xa2;
2174 return S_OK;
2176 #endif /* XAUDIO2_VER >= 8 */
2178 /* returns TRUE if there is more data available in the buffer, FALSE if the
2179 * buffer's data has all been queued */
2180 static BOOL xa2buffer_queue_period(XA2SourceImpl *src, XA2Buffer *buf, ALuint al_buf)
2182 UINT32 submit_bytes;
2183 const BYTE *submit_buf = NULL;
2185 if(buf->offs_bytes >= buf->cur_end_bytes){
2186 WARN("Shouldn't happen: Trying to push frames from a spent buffer?\n");
2187 return FALSE;
2190 submit_bytes = min(src->xa2->period_frames * src->submit_blocksize, buf->cur_end_bytes - buf->offs_bytes);
2191 submit_buf = buf->xa2buffer.pAudioData + buf->offs_bytes;
2192 buf->offs_bytes += submit_bytes;
2194 alBufferData(al_buf, src->al_fmt, submit_buf, submit_bytes,
2195 src->fmt->nSamplesPerSec);
2197 alSourceQueueBuffers(src->al_src, 1, &al_buf);
2199 src->in_al_bytes += submit_bytes;
2200 src->al_bufs_used++;
2202 buf->latest_al_buf = al_buf;
2204 TRACE("queueing %u bytes, now %u in AL\n", submit_bytes, src->in_al_bytes);
2206 return buf->offs_bytes < buf->cur_end_bytes;
2209 #if XAUDIO2_VER > 0
2210 static UINT32 get_underrun_warning(XA2SourceImpl *src)
2212 UINT32 period_bytes = src->xa2->period_frames * src->submit_blocksize;
2213 UINT32 total = 0, i;
2215 for(i = 0; i < src->nbufs && total < IN_AL_PERIODS * period_bytes; ++i){
2216 XA2Buffer *buf = &src->buffers[(src->first_buf + i) % XAUDIO2_MAX_QUEUED_BUFFERS];
2217 total += buf->cur_end_bytes - buf->offs_bytes;
2218 if(buf->xa2buffer.LoopCount == XAUDIO2_LOOP_INFINITE)
2219 return 0;
2220 if(buf->xa2buffer.LoopCount > 0){
2221 total += (buf->loop_end_bytes - buf->xa2buffer.LoopBegin) * (buf->xa2buffer.LoopCount - buf->looped);
2222 total += buf->play_end_bytes - buf->loop_end_bytes;
2226 if(total >= IN_AL_PERIODS * period_bytes)
2227 return 0;
2229 return ((IN_AL_PERIODS * period_bytes - total) / period_bytes + 1) * period_bytes;
2231 #endif
2233 /* Looping:
2235 * The looped section of a buffer is a subset of the play area which is looped
2236 * LoopCount times.
2238 * v PlayBegin
2239 * vvvvvvvvvvvvvvvvvv PlayLength
2240 * v (PlayEnd)
2241 * [-----PPPLLLLLLLLPPPPPPP------]
2242 * ^ LoopBegin
2243 * ^^^^^^^^ LoopLength
2244 * ^ (LoopEnd)
2246 * In the simple case, playback will start at PlayBegin. At LoopEnd, playback
2247 * will move to LoopBegin and repeat that loop LoopCount times. Then, playback
2248 * will cease at PlayEnd.
2250 * If PlayLength is zero, then PlayEnd is the end of the buffer.
2252 * If LoopLength is zero, then LoopEnd is PlayEnd.
2254 * For corner cases and version differences, see tests.
2256 static void update_source_state(XA2SourceImpl *src)
2258 int i;
2259 ALint processed;
2260 ALint bufpos;
2262 alGetSourcei(src->al_src, AL_BUFFERS_PROCESSED, &processed);
2264 if(processed > 0){
2265 ALuint al_buffers[XAUDIO2_MAX_QUEUED_BUFFERS];
2267 alSourceUnqueueBuffers(src->al_src, processed, al_buffers);
2268 src->first_al_buf += processed;
2269 src->first_al_buf %= XAUDIO2_MAX_QUEUED_BUFFERS;
2270 src->al_bufs_used -= processed;
2272 for(i = 0; i < processed; ++i){
2273 ALint bufsize;
2275 alGetBufferi(al_buffers[i], AL_SIZE, &bufsize);
2277 src->in_al_bytes -= bufsize;
2278 src->played_frames += bufsize / src->submit_blocksize;
2280 if(al_buffers[i] == src->buffers[src->first_buf].latest_al_buf){
2281 DWORD old_buf = src->first_buf;
2283 src->first_buf++;
2284 src->first_buf %= XAUDIO2_MAX_QUEUED_BUFFERS;
2285 src->nbufs--;
2287 TRACE("%p: done with buffer %u\n", src, old_buf);
2289 if(src->buffers[old_buf].xa2buffer.Flags & XAUDIO2_END_OF_STREAM)
2290 src->played_frames = 0;
2292 if(src->cb){
2293 IXAudio2VoiceCallback_OnBufferEnd(src->cb,
2294 src->buffers[old_buf].xa2buffer.pContext);
2295 if(src->buffers[old_buf].xa2buffer.Flags & XAUDIO2_END_OF_STREAM)
2296 IXAudio2VoiceCallback_OnStreamEnd(src->cb);
2298 if(src->nbufs > 0)
2299 IXAudio2VoiceCallback_OnBufferStart(src->cb,
2300 src->buffers[src->first_buf].xa2buffer.pContext);
2306 alGetSourcei(src->al_src, AL_BYTE_OFFSET, &bufpos);
2308 /* maintain IN_AL_PERIODS periods in AL */
2309 while(src->cur_buf != (src->first_buf + src->nbufs) % XAUDIO2_MAX_QUEUED_BUFFERS &&
2310 src->in_al_bytes - bufpos < IN_AL_PERIODS * src->xa2->period_frames * src->submit_blocksize){
2311 TRACE("%p: going to queue a period from buffer %u\n", src, src->cur_buf);
2313 /* starting from an empty buffer */
2314 if(src->cb && src->cur_buf == src->first_buf && src->buffers[src->cur_buf].offs_bytes == 0 && !src->buffers[src->cur_buf].looped)
2315 IXAudio2VoiceCallback_OnBufferStart(src->cb,
2316 src->buffers[src->first_buf].xa2buffer.pContext);
2318 if(!xa2buffer_queue_period(src, &src->buffers[src->cur_buf],
2319 src->al_bufs[(src->first_al_buf + src->al_bufs_used) % XAUDIO2_MAX_QUEUED_BUFFERS])){
2320 XA2Buffer *cur = &src->buffers[src->cur_buf];
2322 if(cur->looped < cur->xa2buffer.LoopCount){
2323 if(cur->xa2buffer.LoopCount != XAUDIO2_LOOP_INFINITE)
2324 ++cur->looped;
2325 else
2326 cur->looped = 1; /* indicate that we are executing a loop */
2328 cur->offs_bytes = cur->xa2buffer.LoopBegin;
2329 if(cur->looped == cur->xa2buffer.LoopCount)
2330 cur->cur_end_bytes = cur->play_end_bytes;
2331 else
2332 cur->cur_end_bytes = cur->loop_end_bytes;
2334 if(src->cb)
2335 IXAudio2VoiceCallback_OnLoopEnd(src->cb,
2336 src->buffers[src->cur_buf].xa2buffer.pContext);
2338 }else{
2339 /* buffer is spent, move on */
2340 src->cur_buf++;
2341 src->cur_buf %= XAUDIO2_MAX_QUEUED_BUFFERS;
2347 static void do_engine_tick(IXAudio2Impl *This)
2349 BYTE *buf;
2350 XA2SourceImpl *src;
2351 HRESULT hr;
2352 UINT32 nframes, i, pad;
2354 /* maintain up to 3 periods in mmdevapi */
2355 hr = IAudioClient_GetCurrentPadding(This->aclient, &pad);
2356 if(FAILED(hr)){
2357 WARN("GetCurrentPadding failed: 0x%x\n", hr);
2358 return;
2361 nframes = This->period_frames * 3 - pad;
2363 TRACE("frames available: %u\n", nframes);
2365 if(nframes < This->period_frames)
2366 return;
2368 if(!nframes)
2369 return;
2371 for(i = 0; i < This->ncbs && This->cbs[i]; ++i)
2372 IXAudio2EngineCallback_OnProcessingPassStart(This->cbs[i]);
2374 LIST_FOR_EACH_ENTRY(src, &This->source_voices, XA2SourceImpl, entry){
2375 ALint st = 0;
2377 EnterCriticalSection(&src->lock);
2379 if(!src->in_use || !src->running){
2380 LeaveCriticalSection(&src->lock);
2381 continue;
2384 if(src->cb){
2385 #if XAUDIO2_VER == 0
2386 IXAudio20VoiceCallback_OnVoiceProcessingPassStart((IXAudio20VoiceCallback*)src->cb);
2387 #else
2388 UINT32 underrun;
2389 underrun = get_underrun_warning(src);
2390 if(underrun > 0)
2391 TRACE("Calling OnVoiceProcessingPassStart with BytesRequired: %u\n", underrun);
2392 IXAudio2VoiceCallback_OnVoiceProcessingPassStart(src->cb, underrun);
2393 #endif
2396 update_source_state(src);
2398 alGetSourcei(src->al_src, AL_SOURCE_STATE, &st);
2399 if(st != AL_PLAYING)
2400 alSourcePlay(src->al_src);
2402 if(src->cb)
2403 IXAudio2VoiceCallback_OnVoiceProcessingPassEnd(src->cb);
2405 LeaveCriticalSection(&src->lock);
2408 hr = IAudioRenderClient_GetBuffer(This->render, nframes, &buf);
2409 if(FAILED(hr))
2410 WARN("GetBuffer failed: %08x\n", hr);
2412 palcRenderSamplesSOFT(This->al_device, buf, nframes);
2414 hr = IAudioRenderClient_ReleaseBuffer(This->render, nframes, 0);
2415 if(FAILED(hr))
2416 WARN("ReleaseBuffer failed: %08x\n", hr);
2418 for(i = 0; i < This->ncbs && This->cbs[i]; ++i)
2419 IXAudio2EngineCallback_OnProcessingPassEnd(This->cbs[i]);
2422 static DWORD WINAPI engine_threadproc(void *arg)
2424 IXAudio2Impl *This = arg;
2425 while(1){
2426 WaitForSingleObject(This->mmevt, INFINITE);
2428 if(This->stop_engine)
2429 break;
2431 EnterCriticalSection(&This->lock);
2433 if(!This->running || !This->aclient){
2434 LeaveCriticalSection(&This->lock);
2435 continue;
2438 palcSetThreadContext(This->al_ctx);
2440 do_engine_tick(This);
2442 LeaveCriticalSection(&This->lock);
2444 return 0;