msvcrt: Don't include MSVC 10.0+ math functions in SOs for older DLLs.
[wine.git] / dlls / xaudio2_7 / xaudio_dll.c
blobbc5cf1cae9b11f86d531063c50d20b68e02f7cd5
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;
417 This->abandoned_albufs = 0;
419 LeaveCriticalSection(&This->lock);
422 static HRESULT WINAPI XA2SRC_Start(IXAudio2SourceVoice *iface, UINT32 Flags,
423 UINT32 OperationSet)
425 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
427 TRACE("%p, 0x%x, 0x%x\n", This, Flags, OperationSet);
429 EnterCriticalSection(&This->lock);
431 This->running = TRUE;
433 LeaveCriticalSection(&This->lock);
435 return S_OK;
438 static HRESULT WINAPI XA2SRC_Stop(IXAudio2SourceVoice *iface, UINT32 Flags,
439 UINT32 OperationSet)
441 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
442 ALint bufs;
444 TRACE("%p, 0x%x, 0x%x\n", This, Flags, OperationSet);
446 palcSetThreadContext(This->xa2->al_ctx);
448 EnterCriticalSection(&This->lock);
450 alGetSourcei(This->al_src, AL_BUFFERS_QUEUED, &bufs);
452 This->abandoned_albufs = bufs;
454 This->running = FALSE;
456 LeaveCriticalSection(&This->lock);
458 return S_OK;
461 static ALenum get_al_format(const WAVEFORMATEX *fmt)
463 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)fmt;
464 if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
465 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
466 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
467 switch(fmt->wBitsPerSample){
468 case 8:
469 switch(fmt->nChannels){
470 case 1:
471 return AL_FORMAT_MONO8;
472 case 2:
473 return AL_FORMAT_STEREO8;
474 case 4:
475 return AL_FORMAT_QUAD8;
476 case 6:
477 return AL_FORMAT_51CHN8;
478 case 7:
479 return AL_FORMAT_61CHN8;
480 case 8:
481 return AL_FORMAT_71CHN8;
483 break;
484 case 16:
485 switch(fmt->nChannels){
486 case 1:
487 return AL_FORMAT_MONO16;
488 case 2:
489 return AL_FORMAT_STEREO16;
490 case 4:
491 return AL_FORMAT_QUAD16;
492 case 6:
493 return AL_FORMAT_51CHN16;
494 case 7:
495 return AL_FORMAT_61CHN16;
496 case 8:
497 return AL_FORMAT_71CHN16;
499 break;
501 }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
502 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
503 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
504 if(fmt->wBitsPerSample == 32){
505 switch(fmt->nChannels){
506 case 1:
507 return AL_FORMAT_MONO_FLOAT32;
508 case 2:
509 return AL_FORMAT_STEREO_FLOAT32;
510 case 4:
511 return AL_FORMAT_QUAD32;
512 case 6:
513 return AL_FORMAT_51CHN32;
514 case 7:
515 return AL_FORMAT_61CHN32;
516 case 8:
517 return AL_FORMAT_71CHN32;
521 return 0;
524 static HRESULT WINAPI XA2SRC_SubmitSourceBuffer(IXAudio2SourceVoice *iface,
525 const XAUDIO2_BUFFER *pBuffer, const XAUDIO2_BUFFER_WMA *pBufferWMA)
527 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
528 XA2Buffer *buf;
529 UINT32 buf_idx;
531 TRACE("%p, %p, %p\n", This, pBuffer, pBufferWMA);
533 if(TRACE_ON(xaudio2)){
534 TRACE("Flags: 0x%x\n", pBuffer->Flags);
535 TRACE("AudioBytes: %u\n", pBuffer->AudioBytes);
536 TRACE("pAudioData: %p\n", pBuffer->pAudioData);
537 TRACE("PlayBegin: %u\n", pBuffer->PlayBegin);
538 TRACE("PlayLength: %u\n", pBuffer->PlayLength);
539 TRACE("LoopBegin: %u\n", pBuffer->LoopBegin);
540 TRACE("LoopLength: %u\n", pBuffer->LoopLength);
541 TRACE("LoopCount: %u\n", pBuffer->LoopCount);
542 TRACE("pContext: %p\n", pBuffer->pContext);
545 EnterCriticalSection(&This->lock);
547 if(This->nbufs >= XAUDIO2_MAX_QUEUED_BUFFERS){
548 TRACE("Too many buffers queued!\n");
549 LeaveCriticalSection(&This->lock);
550 return COMPAT_E_INVALID_CALL;
553 buf_idx = (This->first_buf + This->nbufs) % XAUDIO2_MAX_QUEUED_BUFFERS;
554 buf = &This->buffers[buf_idx];
555 memset(buf, 0, sizeof(*buf));
557 /* API contract: pAudioData must remain valid until this buffer is played,
558 * but pBuffer itself may be reused immediately */
559 memcpy(&buf->xa2buffer, pBuffer, sizeof(*pBuffer));
561 #if XAUDIO2_VER == 0
562 if(buf->xa2buffer.LoopCount == XAUDIO20_LOOP_INFINITE)
563 buf->xa2buffer.LoopCount = XAUDIO2_LOOP_INFINITE;
564 #endif
566 /* convert samples offsets to bytes */
567 if(This->fmt->wFormatTag == WAVE_FORMAT_ADPCM){
568 /* ADPCM gives us a number of samples per block, so round down to
569 * nearest block and convert to bytes */
570 buf->xa2buffer.PlayBegin = buf->xa2buffer.PlayBegin / ((ADPCMWAVEFORMAT*)This->fmt)->wSamplesPerBlock * This->fmt->nBlockAlign;
571 buf->xa2buffer.PlayLength = buf->xa2buffer.PlayLength / ((ADPCMWAVEFORMAT*)This->fmt)->wSamplesPerBlock * This->fmt->nBlockAlign;
572 buf->xa2buffer.LoopBegin = buf->xa2buffer.LoopBegin / ((ADPCMWAVEFORMAT*)This->fmt)->wSamplesPerBlock * This->fmt->nBlockAlign;
573 buf->xa2buffer.LoopLength = buf->xa2buffer.LoopLength / ((ADPCMWAVEFORMAT*)This->fmt)->wSamplesPerBlock * This->fmt->nBlockAlign;
574 }else{
575 buf->xa2buffer.PlayBegin *= This->fmt->nBlockAlign;
576 buf->xa2buffer.PlayLength *= This->fmt->nBlockAlign;
577 buf->xa2buffer.LoopBegin *= This->fmt->nBlockAlign;
578 buf->xa2buffer.LoopLength *= This->fmt->nBlockAlign;
581 if(buf->xa2buffer.PlayLength == 0)
582 /* set to end of buffer */
583 buf->xa2buffer.PlayLength = buf->xa2buffer.AudioBytes - buf->xa2buffer.PlayBegin;
585 buf->play_end_bytes = buf->xa2buffer.PlayBegin + buf->xa2buffer.PlayLength;
587 if(buf->xa2buffer.LoopCount){
588 if(buf->xa2buffer.LoopLength == 0)
589 /* set to end of play range */
590 buf->xa2buffer.LoopLength = buf->play_end_bytes - buf->xa2buffer.LoopBegin;
592 if(buf->xa2buffer.LoopBegin >= buf->play_end_bytes){
593 /* this actually crashes on native xaudio 2.7 */
594 LeaveCriticalSection(&This->lock);
595 return COMPAT_E_INVALID_CALL;
598 buf->loop_end_bytes = buf->xa2buffer.LoopBegin + buf->xa2buffer.LoopLength;
600 /* xaudio 2.7 allows some invalid looping setups, but later versions
601 * return an error */
602 #if XAUDIO2_VER > 7
603 if(buf->loop_end_bytes > buf->play_end_bytes){
604 LeaveCriticalSection(&This->lock);
605 return COMPAT_E_INVALID_CALL;
608 if(buf->loop_end_bytes <= buf->xa2buffer.PlayBegin){
609 LeaveCriticalSection(&This->lock);
610 return COMPAT_E_INVALID_CALL;
612 #else
613 if(buf->loop_end_bytes <= buf->xa2buffer.PlayBegin){
614 buf->xa2buffer.LoopCount = 0;
615 buf->loop_end_bytes = buf->play_end_bytes;
617 #endif
618 }else{
619 buf->xa2buffer.LoopLength = buf->xa2buffer.PlayLength;
620 buf->xa2buffer.LoopBegin = buf->xa2buffer.PlayBegin;
621 buf->loop_end_bytes = buf->play_end_bytes;
624 buf->offs_bytes = buf->xa2buffer.PlayBegin;
625 buf->cur_end_bytes = buf->loop_end_bytes;
627 buf->latest_al_buf = -1;
629 ++This->nbufs;
631 TRACE("%p: queued buffer %u (%u bytes), now %u buffers held\n",
632 This, buf_idx, buf->xa2buffer.AudioBytes, This->nbufs);
634 LeaveCriticalSection(&This->lock);
636 return S_OK;
639 static HRESULT WINAPI XA2SRC_FlushSourceBuffers(IXAudio2SourceVoice *iface)
641 UINT i, first, last, to_flush;
642 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
644 TRACE("%p\n", This);
646 EnterCriticalSection(&This->lock);
648 if(This->running && This->nbufs > 0){
649 /* when running, flush only completely unused buffers; the rest remain
650 * in queue */
651 last = (This->first_buf + This->nbufs) % XAUDIO2_MAX_QUEUED_BUFFERS;
652 first = (This->cur_buf + 1) % XAUDIO2_MAX_QUEUED_BUFFERS;
653 if(This->cur_buf == last)
654 /* nothing to do */
655 to_flush = 0;
656 else if(last >= first)
657 to_flush = last - first;
658 else
659 to_flush = last + XAUDIO2_MAX_QUEUED_BUFFERS - first;
660 }else{
661 /* when stopped, flush all buffers */
662 first = This->first_buf;
663 last = (This->first_buf + This->nbufs) % XAUDIO2_MAX_QUEUED_BUFFERS;
664 to_flush = This->nbufs;
668 for(i = first;
669 i < (first + to_flush) % XAUDIO2_MAX_QUEUED_BUFFERS;
670 i = (i + 1) % XAUDIO2_MAX_QUEUED_BUFFERS){
671 if(This->cb)
672 IXAudio2VoiceCallback_OnBufferEnd(This->cb,
673 This->buffers[i].xa2buffer.pContext);
676 This->nbufs -= to_flush;
677 This->cur_buf = (This->first_buf + This->nbufs) % XAUDIO2_MAX_QUEUED_BUFFERS;
679 LeaveCriticalSection(&This->lock);
681 return S_OK;
684 static HRESULT WINAPI XA2SRC_Discontinuity(IXAudio2SourceVoice *iface)
686 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
688 TRACE("%p\n", This);
690 EnterCriticalSection(&This->lock);
692 if(This->nbufs > 0){
693 DWORD last = (This->first_buf + This->nbufs - 1) % XAUDIO2_MAX_QUEUED_BUFFERS;
694 This->buffers[last].xa2buffer.Flags |= XAUDIO2_END_OF_STREAM;
697 LeaveCriticalSection(&This->lock);
699 return S_OK;
702 static HRESULT WINAPI XA2SRC_ExitLoop(IXAudio2SourceVoice *iface, UINT32 OperationSet)
704 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
706 TRACE("%p, 0x%x\n", This, OperationSet);
708 EnterCriticalSection(&This->lock);
710 This->buffers[This->cur_buf].looped = XAUDIO2_LOOP_INFINITE;
712 LeaveCriticalSection(&This->lock);
714 return S_OK;
717 static void WINAPI XA2SRC_GetState(IXAudio2SourceVoice *iface,
718 XAUDIO2_VOICE_STATE *pVoiceState, UINT32 Flags)
720 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
722 TRACE("%p, %p, 0x%x\n", This, pVoiceState, Flags);
724 EnterCriticalSection(&This->lock);
726 if(!(Flags & XAUDIO2_VOICE_NOSAMPLESPLAYED))
727 pVoiceState->SamplesPlayed = This->played_frames;
728 else
729 pVoiceState->SamplesPlayed = 0;
731 if(This->nbufs)
732 pVoiceState->pCurrentBufferContext = This->buffers[This->first_buf].xa2buffer.pContext;
733 else
734 pVoiceState->pCurrentBufferContext = NULL;
736 pVoiceState->BuffersQueued = This->nbufs;
738 LeaveCriticalSection(&This->lock);
740 TRACE("returning %s, queued: %u\n", wine_dbgstr_longlong(pVoiceState->SamplesPlayed), This->nbufs);
743 static HRESULT WINAPI XA2SRC_SetFrequencyRatio(IXAudio2SourceVoice *iface,
744 float Ratio, UINT32 OperationSet)
746 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
747 ALfloat r;
749 TRACE("%p, %f, 0x%x\n", This, Ratio, OperationSet);
751 if(Ratio < XAUDIO2_MIN_FREQ_RATIO)
752 r = XAUDIO2_MIN_FREQ_RATIO;
753 else if (Ratio > XAUDIO2_MAX_FREQ_RATIO)
754 r = XAUDIO2_MAX_FREQ_RATIO;
755 else
756 r = Ratio;
758 palcSetThreadContext(This->xa2->al_ctx);
760 alSourcef(This->al_src, AL_PITCH, r);
762 return S_OK;
765 static void WINAPI XA2SRC_GetFrequencyRatio(IXAudio2SourceVoice *iface, float *pRatio)
767 ALfloat ratio;
768 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
770 TRACE("%p, %p\n", This, pRatio);
772 palcSetThreadContext(This->xa2->al_ctx);
774 alGetSourcef(This->al_src, AL_PITCH, &ratio);
776 *pRatio = ratio;
779 static HRESULT WINAPI XA2SRC_SetSourceSampleRate(
780 IXAudio2SourceVoice *iface,
781 UINT32 NewSourceSampleRate)
783 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
785 TRACE("%p, %u\n", This, NewSourceSampleRate);
787 EnterCriticalSection(&This->lock);
789 if(This->nbufs){
790 LeaveCriticalSection(&This->lock);
791 return COMPAT_E_INVALID_CALL;
794 This->fmt->nSamplesPerSec = NewSourceSampleRate;
796 LeaveCriticalSection(&This->lock);
798 return S_OK;
801 static const IXAudio2SourceVoiceVtbl XAudio2SourceVoice_Vtbl = {
802 XA2SRC_GetVoiceDetails,
803 XA2SRC_SetOutputVoices,
804 XA2SRC_SetEffectChain,
805 XA2SRC_EnableEffect,
806 XA2SRC_DisableEffect,
807 XA2SRC_GetEffectState,
808 XA2SRC_SetEffectParameters,
809 XA2SRC_GetEffectParameters,
810 XA2SRC_SetFilterParameters,
811 XA2SRC_GetFilterParameters,
812 XA2SRC_SetOutputFilterParameters,
813 XA2SRC_GetOutputFilterParameters,
814 XA2SRC_SetVolume,
815 XA2SRC_GetVolume,
816 XA2SRC_SetChannelVolumes,
817 XA2SRC_GetChannelVolumes,
818 XA2SRC_SetOutputMatrix,
819 XA2SRC_GetOutputMatrix,
820 XA2SRC_DestroyVoice,
821 XA2SRC_Start,
822 XA2SRC_Stop,
823 XA2SRC_SubmitSourceBuffer,
824 XA2SRC_FlushSourceBuffers,
825 XA2SRC_Discontinuity,
826 XA2SRC_ExitLoop,
827 XA2SRC_GetState,
828 XA2SRC_SetFrequencyRatio,
829 XA2SRC_GetFrequencyRatio,
830 XA2SRC_SetSourceSampleRate
833 static void WINAPI XA2M_GetVoiceDetails(IXAudio2MasteringVoice *iface,
834 XAUDIO2_VOICE_DETAILS *pVoiceDetails)
836 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
837 TRACE("%p, %p\n", This, pVoiceDetails);
838 pVoiceDetails->CreationFlags = 0;
839 pVoiceDetails->ActiveFlags = 0;
840 pVoiceDetails->InputChannels = This->fmt.Format.nChannels;
841 pVoiceDetails->InputSampleRate = This->fmt.Format.nSamplesPerSec;
844 static HRESULT WINAPI XA2M_SetOutputVoices(IXAudio2MasteringVoice *iface,
845 const XAUDIO2_VOICE_SENDS *pSendList)
847 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
848 TRACE("%p, %p\n", This, pSendList);
849 return S_OK;
852 static HRESULT WINAPI XA2M_SetEffectChain(IXAudio2MasteringVoice *iface,
853 const XAUDIO2_EFFECT_CHAIN *pEffectChain)
855 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
856 TRACE("%p, %p\n", This, pEffectChain);
857 return S_OK;
860 static HRESULT WINAPI XA2M_EnableEffect(IXAudio2MasteringVoice *iface, UINT32 EffectIndex,
861 UINT32 OperationSet)
863 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
864 TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
865 return S_OK;
868 static HRESULT WINAPI XA2M_DisableEffect(IXAudio2MasteringVoice *iface, UINT32 EffectIndex,
869 UINT32 OperationSet)
871 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
872 TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
873 return S_OK;
876 static void WINAPI XA2M_GetEffectState(IXAudio2MasteringVoice *iface, UINT32 EffectIndex,
877 BOOL *pEnabled)
879 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
880 TRACE("%p, %u, %p\n", This, EffectIndex, pEnabled);
883 static HRESULT WINAPI XA2M_SetEffectParameters(IXAudio2MasteringVoice *iface,
884 UINT32 EffectIndex, const void *pParameters, UINT32 ParametersByteSize,
885 UINT32 OperationSet)
887 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
888 TRACE("%p, %u, %p, 0x%x, 0x%x\n", This, EffectIndex, pParameters,
889 ParametersByteSize, OperationSet);
890 return S_OK;
893 static HRESULT WINAPI XA2M_GetEffectParameters(IXAudio2MasteringVoice *iface,
894 UINT32 EffectIndex, void *pParameters, UINT32 ParametersByteSize)
896 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
897 TRACE("%p, %u, %p, 0x%x\n", This, EffectIndex, pParameters,
898 ParametersByteSize);
899 return S_OK;
902 static HRESULT WINAPI XA2M_SetFilterParameters(IXAudio2MasteringVoice *iface,
903 const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
905 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
906 TRACE("%p, %p, 0x%x\n", This, pParameters, OperationSet);
907 return S_OK;
910 static void WINAPI XA2M_GetFilterParameters(IXAudio2MasteringVoice *iface,
911 XAUDIO2_FILTER_PARAMETERS *pParameters)
913 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
914 TRACE("%p, %p\n", This, pParameters);
917 static HRESULT WINAPI XA2M_SetOutputFilterParameters(IXAudio2MasteringVoice *iface,
918 IXAudio2Voice *pDestinationVoice,
919 const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
921 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
922 TRACE("%p, %p, %p, 0x%x\n", This, pDestinationVoice, pParameters, OperationSet);
923 return S_OK;
926 static void WINAPI XA2M_GetOutputFilterParameters(IXAudio2MasteringVoice *iface,
927 IXAudio2Voice *pDestinationVoice,
928 XAUDIO2_FILTER_PARAMETERS *pParameters)
930 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
931 TRACE("%p, %p, %p\n", This, pDestinationVoice, pParameters);
934 static HRESULT WINAPI XA2M_SetVolume(IXAudio2MasteringVoice *iface, float Volume,
935 UINT32 OperationSet)
937 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
938 TRACE("%p, %f, 0x%x\n", This, Volume, OperationSet);
939 return S_OK;
942 static void WINAPI XA2M_GetVolume(IXAudio2MasteringVoice *iface, float *pVolume)
944 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
945 TRACE("%p, %p\n", This, pVolume);
948 static HRESULT WINAPI XA2M_SetChannelVolumes(IXAudio2MasteringVoice *iface, UINT32 Channels,
949 const float *pVolumes, UINT32 OperationSet)
951 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
952 TRACE("%p, %u, %p, 0x%x\n", This, Channels, pVolumes, OperationSet);
953 return S_OK;
956 static void WINAPI XA2M_GetChannelVolumes(IXAudio2MasteringVoice *iface, UINT32 Channels,
957 float *pVolumes)
959 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
960 TRACE("%p, %u, %p\n", This, Channels, pVolumes);
963 static HRESULT WINAPI XA2M_SetOutputMatrix(IXAudio2MasteringVoice *iface,
964 IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
965 UINT32 DestinationChannels, const float *pLevelMatrix,
966 UINT32 OperationSet)
968 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
969 TRACE("%p, %p, %u, %u, %p, 0x%x\n", This, pDestinationVoice,
970 SourceChannels, DestinationChannels, pLevelMatrix, OperationSet);
971 return S_OK;
974 static void WINAPI XA2M_GetOutputMatrix(IXAudio2MasteringVoice *iface,
975 IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
976 UINT32 DestinationChannels, float *pLevelMatrix)
978 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
979 TRACE("%p, %p, %u, %u, %p\n", This, pDestinationVoice,
980 SourceChannels, DestinationChannels, pLevelMatrix);
983 static void WINAPI XA2M_DestroyVoice(IXAudio2MasteringVoice *iface)
985 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
987 TRACE("%p\n", This);
989 EnterCriticalSection(&This->lock);
991 if(!This->aclient){
992 LeaveCriticalSection(&This->lock);
993 return;
996 This->running = FALSE;
998 IAudioRenderClient_Release(This->render);
999 This->render = NULL;
1001 IAudioClient_Release(This->aclient);
1002 This->aclient = NULL;
1004 alcDestroyContext(This->al_ctx);
1005 This->al_ctx = NULL;
1007 alcCloseDevice(This->al_device);
1008 This->al_device = NULL;
1010 LeaveCriticalSection(&This->lock);
1013 /* not present in XAudio2 2.7 */
1014 static void WINAPI XA2M_GetChannelMask(IXAudio2MasteringVoice *iface,
1015 DWORD *pChannelMask)
1017 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
1019 TRACE("%p %p\n", This, pChannelMask);
1021 *pChannelMask = This->fmt.dwChannelMask;
1024 static const struct IXAudio2MasteringVoiceVtbl XAudio2MasteringVoice_Vtbl = {
1025 XA2M_GetVoiceDetails,
1026 XA2M_SetOutputVoices,
1027 XA2M_SetEffectChain,
1028 XA2M_EnableEffect,
1029 XA2M_DisableEffect,
1030 XA2M_GetEffectState,
1031 XA2M_SetEffectParameters,
1032 XA2M_GetEffectParameters,
1033 XA2M_SetFilterParameters,
1034 XA2M_GetFilterParameters,
1035 XA2M_SetOutputFilterParameters,
1036 XA2M_GetOutputFilterParameters,
1037 XA2M_SetVolume,
1038 XA2M_GetVolume,
1039 XA2M_SetChannelVolumes,
1040 XA2M_GetChannelVolumes,
1041 XA2M_SetOutputMatrix,
1042 XA2M_GetOutputMatrix,
1043 XA2M_DestroyVoice,
1044 XA2M_GetChannelMask
1047 static void WINAPI XA2SUB_GetVoiceDetails(IXAudio2SubmixVoice *iface,
1048 XAUDIO2_VOICE_DETAILS *pVoiceDetails)
1050 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1052 TRACE("%p, %p\n", This, pVoiceDetails);
1054 *pVoiceDetails = This->details;
1057 static HRESULT WINAPI XA2SUB_SetOutputVoices(IXAudio2SubmixVoice *iface,
1058 const XAUDIO2_VOICE_SENDS *pSendList)
1060 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1061 TRACE("%p, %p\n", This, pSendList);
1062 return S_OK;
1065 static HRESULT WINAPI XA2SUB_SetEffectChain(IXAudio2SubmixVoice *iface,
1066 const XAUDIO2_EFFECT_CHAIN *pEffectChain)
1068 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1069 TRACE("%p, %p\n", This, pEffectChain);
1070 return S_OK;
1073 static HRESULT WINAPI XA2SUB_EnableEffect(IXAudio2SubmixVoice *iface, UINT32 EffectIndex,
1074 UINT32 OperationSet)
1076 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1077 TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
1078 return S_OK;
1081 static HRESULT WINAPI XA2SUB_DisableEffect(IXAudio2SubmixVoice *iface, UINT32 EffectIndex,
1082 UINT32 OperationSet)
1084 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1085 TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
1086 return S_OK;
1089 static void WINAPI XA2SUB_GetEffectState(IXAudio2SubmixVoice *iface, UINT32 EffectIndex,
1090 BOOL *pEnabled)
1092 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1093 TRACE("%p, %u, %p\n", This, EffectIndex, pEnabled);
1096 static HRESULT WINAPI XA2SUB_SetEffectParameters(IXAudio2SubmixVoice *iface,
1097 UINT32 EffectIndex, const void *pParameters, UINT32 ParametersByteSize,
1098 UINT32 OperationSet)
1100 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1101 TRACE("%p, %u, %p, 0x%x, 0x%x\n", This, EffectIndex, pParameters,
1102 ParametersByteSize, OperationSet);
1103 return S_OK;
1106 static HRESULT WINAPI XA2SUB_GetEffectParameters(IXAudio2SubmixVoice *iface,
1107 UINT32 EffectIndex, void *pParameters, UINT32 ParametersByteSize)
1109 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1110 TRACE("%p, %u, %p, 0x%x\n", This, EffectIndex, pParameters,
1111 ParametersByteSize);
1112 return S_OK;
1115 static HRESULT WINAPI XA2SUB_SetFilterParameters(IXAudio2SubmixVoice *iface,
1116 const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
1118 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1119 TRACE("%p, %p, 0x%x\n", This, pParameters, OperationSet);
1120 return S_OK;
1123 static void WINAPI XA2SUB_GetFilterParameters(IXAudio2SubmixVoice *iface,
1124 XAUDIO2_FILTER_PARAMETERS *pParameters)
1126 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1127 TRACE("%p, %p\n", This, pParameters);
1130 static HRESULT WINAPI XA2SUB_SetOutputFilterParameters(IXAudio2SubmixVoice *iface,
1131 IXAudio2Voice *pDestinationVoice,
1132 const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
1134 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1135 TRACE("%p, %p, %p, 0x%x\n", This, pDestinationVoice, pParameters, OperationSet);
1136 return S_OK;
1139 static void WINAPI XA2SUB_GetOutputFilterParameters(IXAudio2SubmixVoice *iface,
1140 IXAudio2Voice *pDestinationVoice,
1141 XAUDIO2_FILTER_PARAMETERS *pParameters)
1143 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1144 TRACE("%p, %p, %p\n", This, pDestinationVoice, pParameters);
1147 static HRESULT WINAPI XA2SUB_SetVolume(IXAudio2SubmixVoice *iface, float Volume,
1148 UINT32 OperationSet)
1150 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1151 TRACE("%p, %f, 0x%x\n", This, Volume, OperationSet);
1152 return S_OK;
1155 static void WINAPI XA2SUB_GetVolume(IXAudio2SubmixVoice *iface, float *pVolume)
1157 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1158 TRACE("%p, %p\n", This, pVolume);
1161 static HRESULT WINAPI XA2SUB_SetChannelVolumes(IXAudio2SubmixVoice *iface, UINT32 Channels,
1162 const float *pVolumes, UINT32 OperationSet)
1164 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1165 TRACE("%p, %u, %p, 0x%x\n", This, Channels, pVolumes, OperationSet);
1166 return S_OK;
1169 static void WINAPI XA2SUB_GetChannelVolumes(IXAudio2SubmixVoice *iface, UINT32 Channels,
1170 float *pVolumes)
1172 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1173 TRACE("%p, %u, %p\n", This, Channels, pVolumes);
1176 static HRESULT WINAPI XA2SUB_SetOutputMatrix(IXAudio2SubmixVoice *iface,
1177 IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
1178 UINT32 DestinationChannels, const float *pLevelMatrix,
1179 UINT32 OperationSet)
1181 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1182 TRACE("%p, %p, %u, %u, %p, 0x%x\n", This, pDestinationVoice,
1183 SourceChannels, DestinationChannels, pLevelMatrix, OperationSet);
1184 return S_OK;
1187 static void WINAPI XA2SUB_GetOutputMatrix(IXAudio2SubmixVoice *iface,
1188 IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
1189 UINT32 DestinationChannels, float *pLevelMatrix)
1191 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1192 TRACE("%p, %p, %u, %u, %p\n", This, pDestinationVoice,
1193 SourceChannels, DestinationChannels, pLevelMatrix);
1196 static void WINAPI XA2SUB_DestroyVoice(IXAudio2SubmixVoice *iface)
1198 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1200 TRACE("%p\n", This);
1202 EnterCriticalSection(&This->lock);
1204 This->in_use = FALSE;
1206 LeaveCriticalSection(&This->lock);
1209 static const struct IXAudio2SubmixVoiceVtbl XAudio2SubmixVoice_Vtbl = {
1210 XA2SUB_GetVoiceDetails,
1211 XA2SUB_SetOutputVoices,
1212 XA2SUB_SetEffectChain,
1213 XA2SUB_EnableEffect,
1214 XA2SUB_DisableEffect,
1215 XA2SUB_GetEffectState,
1216 XA2SUB_SetEffectParameters,
1217 XA2SUB_GetEffectParameters,
1218 XA2SUB_SetFilterParameters,
1219 XA2SUB_GetFilterParameters,
1220 XA2SUB_SetOutputFilterParameters,
1221 XA2SUB_GetOutputFilterParameters,
1222 XA2SUB_SetVolume,
1223 XA2SUB_GetVolume,
1224 XA2SUB_SetChannelVolumes,
1225 XA2SUB_GetChannelVolumes,
1226 XA2SUB_SetOutputMatrix,
1227 XA2SUB_GetOutputMatrix,
1228 XA2SUB_DestroyVoice
1231 static HRESULT WINAPI IXAudio2Impl_QueryInterface(IXAudio2 *iface, REFIID riid,
1232 void **ppvObject)
1234 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1236 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
1238 if(IsEqualGUID(riid, &IID_IUnknown) ||
1239 IsEqualGUID(riid, &IID_IXAudio28) ||
1240 IsEqualGUID(riid, &IID_IXAudio2))
1241 *ppvObject = &This->IXAudio2_iface;
1242 else if(IsEqualGUID(riid, &IID_IXAudio27)){
1243 /* all xaudio versions before 28 share an IID */
1244 #if XAUDIO2_VER == 0
1245 *ppvObject = &This->IXAudio20_iface;
1246 #elif XAUDIO2_VER <= 2
1247 *ppvObject = &This->IXAudio22_iface;
1248 #elif XAUDIO2_VER <= 7
1249 *ppvObject = &This->IXAudio27_iface;
1250 #else
1251 *ppvObject = NULL;
1252 #endif
1253 }else
1254 *ppvObject = NULL;
1256 if(*ppvObject){
1257 IUnknown_AddRef((IUnknown*)*ppvObject);
1258 return S_OK;
1261 FIXME("(%p)->(%s,%p), not found\n", This,debugstr_guid(riid), ppvObject);
1263 return E_NOINTERFACE;
1266 static ULONG WINAPI IXAudio2Impl_AddRef(IXAudio2 *iface)
1268 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1269 ULONG ref = InterlockedIncrement(&This->ref);
1270 TRACE("(%p)->(): Refcount now %u\n", This, ref);
1271 return ref;
1274 static ULONG WINAPI IXAudio2Impl_Release(IXAudio2 *iface)
1276 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1277 ULONG ref = InterlockedDecrement(&This->ref);
1279 TRACE("(%p)->(): Refcount now %u\n", This, ref);
1281 if (!ref) {
1282 int i;
1283 XA2SourceImpl *src, *src2;
1284 XA2SubmixImpl *sub, *sub2;
1286 if(This->engine){
1287 This->stop_engine = TRUE;
1288 SetEvent(This->mmevt);
1289 WaitForSingleObject(This->engine, INFINITE);
1290 CloseHandle(This->engine);
1293 LIST_FOR_EACH_ENTRY_SAFE(src, src2, &This->source_voices, XA2SourceImpl, entry){
1294 HeapFree(GetProcessHeap(), 0, src->sends);
1295 IXAudio2SourceVoice_DestroyVoice(&src->IXAudio2SourceVoice_iface);
1296 src->lock.DebugInfo->Spare[0] = 0;
1297 DeleteCriticalSection(&src->lock);
1298 HeapFree(GetProcessHeap(), 0, src);
1301 LIST_FOR_EACH_ENTRY_SAFE(sub, sub2, &This->submix_voices, XA2SubmixImpl, entry){
1302 IXAudio2SubmixVoice_DestroyVoice(&sub->IXAudio2SubmixVoice_iface);
1303 sub->lock.DebugInfo->Spare[0] = 0;
1304 DeleteCriticalSection(&sub->lock);
1305 HeapFree(GetProcessHeap(), 0, sub);
1308 IXAudio2MasteringVoice_DestroyVoice(&This->IXAudio2MasteringVoice_iface);
1310 if(This->devenum)
1311 IMMDeviceEnumerator_Release(This->devenum);
1312 for(i = 0; i < This->ndevs; ++i)
1313 CoTaskMemFree(This->devids[i]);
1314 HeapFree(GetProcessHeap(), 0, This->devids);
1315 HeapFree(GetProcessHeap(), 0, This->cbs);
1317 CloseHandle(This->mmevt);
1319 This->lock.DebugInfo->Spare[0] = 0;
1320 DeleteCriticalSection(&This->lock);
1322 HeapFree(GetProcessHeap(), 0, This);
1324 return ref;
1327 static HRESULT WINAPI IXAudio2Impl_RegisterForCallbacks(IXAudio2 *iface,
1328 IXAudio2EngineCallback *pCallback)
1330 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1331 int i;
1333 TRACE("(%p)->(%p)\n", This, pCallback);
1335 EnterCriticalSection(&This->lock);
1337 for(i = 0; i < This->ncbs; ++i){
1338 if(!This->cbs[i] || This->cbs[i] == pCallback){
1339 This->cbs[i] = pCallback;
1340 LeaveCriticalSection(&This->lock);
1341 return S_OK;
1345 This->ncbs *= 2;
1346 This->cbs = HeapReAlloc(GetProcessHeap(), 0, This->cbs, This->ncbs * sizeof(*This->cbs));
1348 This->cbs[i] = pCallback;
1350 LeaveCriticalSection(&This->lock);
1352 return S_OK;
1355 static void WINAPI IXAudio2Impl_UnregisterForCallbacks(IXAudio2 *iface,
1356 IXAudio2EngineCallback *pCallback)
1358 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1359 int i;
1361 TRACE("(%p)->(%p)\n", This, pCallback);
1363 EnterCriticalSection(&This->lock);
1365 for(i = 0; i < This->ncbs; ++i){
1366 if(This->cbs[i] == pCallback)
1367 break;
1370 for(; i < This->ncbs - 1 && This->cbs[i + 1]; ++i)
1371 This->cbs[i] = This->cbs[i + 1];
1373 if(i < This->ncbs)
1374 This->cbs[i] = NULL;
1376 LeaveCriticalSection(&This->lock);
1379 static WAVEFORMATEX *copy_waveformat(const WAVEFORMATEX *wfex)
1381 WAVEFORMATEX *pwfx;
1383 if(wfex->wFormatTag == WAVE_FORMAT_PCM){
1384 pwfx = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEX));
1385 CopyMemory(pwfx, wfex, sizeof(PCMWAVEFORMAT));
1386 pwfx->cbSize = 0;
1387 }else{
1388 pwfx = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEX) + wfex->cbSize);
1389 CopyMemory(pwfx, wfex, sizeof(WAVEFORMATEX) + wfex->cbSize);
1392 return pwfx;
1395 static HRESULT WINAPI IXAudio2Impl_CreateSourceVoice(IXAudio2 *iface,
1396 IXAudio2SourceVoice **ppSourceVoice, const WAVEFORMATEX *pSourceFormat,
1397 UINT32 flags, float maxFrequencyRatio,
1398 IXAudio2VoiceCallback *pCallback, const XAUDIO2_VOICE_SENDS *pSendList,
1399 const XAUDIO2_EFFECT_CHAIN *pEffectChain)
1401 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1402 XA2SourceImpl *src;
1403 HRESULT hr;
1405 TRACE("(%p)->(%p, %p, 0x%x, %f, %p, %p, %p)\n", This, ppSourceVoice,
1406 pSourceFormat, flags, maxFrequencyRatio, pCallback, pSendList,
1407 pEffectChain);
1409 dump_fmt(pSourceFormat);
1411 palcSetThreadContext(This->al_ctx);
1413 EnterCriticalSection(&This->lock);
1415 LIST_FOR_EACH_ENTRY(src, &This->source_voices, XA2SourceImpl, entry){
1416 EnterCriticalSection(&src->lock);
1417 if(!src->in_use)
1418 break;
1419 LeaveCriticalSection(&src->lock);
1422 if(&src->entry == &This->source_voices){
1423 src = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*src));
1424 if(!src){
1425 LeaveCriticalSection(&This->lock);
1426 return E_OUTOFMEMORY;
1429 list_add_head(&This->source_voices, &src->entry);
1431 src->IXAudio2SourceVoice_iface.lpVtbl = &XAudio2SourceVoice_Vtbl;
1433 #if XAUDIO2_VER == 0
1434 src->IXAudio20SourceVoice_iface.lpVtbl = &XAudio20SourceVoice_Vtbl;
1435 #elif XAUDIO2_VER <= 3
1436 src->IXAudio23SourceVoice_iface.lpVtbl = &XAudio23SourceVoice_Vtbl;
1437 #elif XAUDIO2_VER <= 7
1438 src->IXAudio27SourceVoice_iface.lpVtbl = &XAudio27SourceVoice_Vtbl;
1439 #endif
1441 InitializeCriticalSection(&src->lock);
1442 src->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": XA2SourceImpl.lock");
1444 src->xa2 = This;
1446 EnterCriticalSection(&src->lock);
1449 src->in_use = TRUE;
1450 src->running = FALSE;
1452 LeaveCriticalSection(&This->lock);
1454 src->cb = pCallback;
1456 src->al_fmt = get_al_format(pSourceFormat);
1457 if(!src->al_fmt){
1458 src->in_use = FALSE;
1459 LeaveCriticalSection(&src->lock);
1460 WARN("OpenAL can't convert this format!\n");
1461 return AUDCLNT_E_UNSUPPORTED_FORMAT;
1464 src->submit_blocksize = pSourceFormat->nBlockAlign;
1466 src->fmt = copy_waveformat(pSourceFormat);
1468 hr = XA2SRC_SetOutputVoices(&src->IXAudio2SourceVoice_iface, pSendList);
1469 if(FAILED(hr)){
1470 HeapFree(GetProcessHeap(), 0, src->fmt);
1471 src->in_use = FALSE;
1472 LeaveCriticalSection(&src->lock);
1473 return hr;
1476 alGenSources(1, &src->al_src);
1477 if(!src->al_src){
1478 static int once = 0;
1479 if(!once++)
1480 ERR_(winediag)("OpenAL ran out of sources, consider increasing its source limit.\n");
1481 HeapFree(GetProcessHeap(), 0, src->fmt);
1482 src->in_use = FALSE;
1483 LeaveCriticalSection(&src->lock);
1484 return E_OUTOFMEMORY;
1487 alGenBuffers(XAUDIO2_MAX_QUEUED_BUFFERS, src->al_bufs);
1489 alSourcePlay(src->al_src);
1491 LeaveCriticalSection(&src->lock);
1493 #if XAUDIO2_VER == 0
1494 *ppSourceVoice = (IXAudio2SourceVoice*)&src->IXAudio20SourceVoice_iface;
1495 #elif XAUDIO2_VER <= 3
1496 *ppSourceVoice = (IXAudio2SourceVoice*)&src->IXAudio23SourceVoice_iface;
1497 #elif XAUDIO2_VER <= 7
1498 *ppSourceVoice = (IXAudio2SourceVoice*)&src->IXAudio27SourceVoice_iface;
1499 #else
1500 *ppSourceVoice = &src->IXAudio2SourceVoice_iface;
1501 #endif
1503 TRACE("Created source voice: %p\n", src);
1505 return S_OK;
1508 static HRESULT WINAPI IXAudio2Impl_CreateSubmixVoice(IXAudio2 *iface,
1509 IXAudio2SubmixVoice **ppSubmixVoice, UINT32 inputChannels,
1510 UINT32 inputSampleRate, UINT32 flags, UINT32 processingStage,
1511 const XAUDIO2_VOICE_SENDS *pSendList,
1512 const XAUDIO2_EFFECT_CHAIN *pEffectChain)
1514 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1515 XA2SubmixImpl *sub;
1517 TRACE("(%p)->(%p, %u, %u, 0x%x, %u, %p, %p)\n", This, ppSubmixVoice,
1518 inputChannels, inputSampleRate, flags, processingStage, pSendList,
1519 pEffectChain);
1521 EnterCriticalSection(&This->lock);
1523 LIST_FOR_EACH_ENTRY(sub, &This->submix_voices, XA2SubmixImpl, entry){
1524 EnterCriticalSection(&sub->lock);
1525 if(!sub->in_use)
1526 break;
1527 LeaveCriticalSection(&sub->lock);
1530 if(&sub->entry == &This->submix_voices){
1531 sub = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*sub));
1532 if(!sub){
1533 LeaveCriticalSection(&This->lock);
1534 return E_OUTOFMEMORY;
1537 list_add_head(&This->submix_voices, &sub->entry);
1539 sub->IXAudio2SubmixVoice_iface.lpVtbl = &XAudio2SubmixVoice_Vtbl;
1541 #if XAUDIO2_VER == 0
1542 sub->IXAudio20SubmixVoice_iface.lpVtbl = &XAudio20SubmixVoice_Vtbl;
1543 #elif XAUDIO2_VER <= 3
1544 sub->IXAudio23SubmixVoice_iface.lpVtbl = &XAudio23SubmixVoice_Vtbl;
1545 #elif XAUDIO2_VER <= 7
1546 sub->IXAudio27SubmixVoice_iface.lpVtbl = &XAudio27SubmixVoice_Vtbl;
1547 #endif
1549 InitializeCriticalSection(&sub->lock);
1550 sub->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": XA2SubmixImpl.lock");
1552 EnterCriticalSection(&sub->lock);
1555 sub->in_use = TRUE;
1557 sub->details.CreationFlags = flags;
1558 sub->details.ActiveFlags = flags;
1559 sub->details.InputChannels = inputChannels;
1560 sub->details.InputSampleRate = inputSampleRate;
1562 LeaveCriticalSection(&This->lock);
1563 LeaveCriticalSection(&sub->lock);
1565 #if XAUDIO2_VER == 0
1566 *ppSubmixVoice = (IXAudio2SubmixVoice*)&sub->IXAudio20SubmixVoice_iface;
1567 #elif XAUDIO2_VER <= 3
1568 *ppSubmixVoice = (IXAudio2SubmixVoice*)&sub->IXAudio23SubmixVoice_iface;
1569 #elif XAUDIO2_VER <= 7
1570 *ppSubmixVoice = (IXAudio2SubmixVoice*)&sub->IXAudio27SubmixVoice_iface;
1571 #else
1572 *ppSubmixVoice = &sub->IXAudio2SubmixVoice_iface;
1573 #endif
1575 TRACE("Created submix voice: %p\n", sub);
1577 return S_OK;
1580 static ALenum al_get_loopback_format(const WAVEFORMATEXTENSIBLE *fmt)
1582 if(fmt->Format.wFormatTag == WAVE_FORMAT_PCM ||
1583 (fmt->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1584 IsEqualGUID(&fmt->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
1585 switch(fmt->Format.wBitsPerSample){
1586 case 8:
1587 return ALC_UNSIGNED_BYTE_SOFT;
1588 case 16:
1589 return ALC_SHORT_SOFT;
1590 case 32:
1591 return ALC_INT_SOFT;
1593 }else if(fmt->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
1594 (fmt->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1595 IsEqualGUID(&fmt->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
1596 if(fmt->Format.wBitsPerSample == 32)
1597 return ALC_FLOAT_SOFT;
1599 return 0;
1602 static HRESULT WINAPI IXAudio2Impl_CreateMasteringVoice(IXAudio2 *iface,
1603 IXAudio2MasteringVoice **ppMasteringVoice, UINT32 inputChannels,
1604 UINT32 inputSampleRate, UINT32 flags, const WCHAR *deviceId,
1605 const XAUDIO2_EFFECT_CHAIN *pEffectChain,
1606 AUDIO_STREAM_CATEGORY streamCategory)
1608 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1609 IMMDevice *dev;
1610 HRESULT hr;
1611 WAVEFORMATEX *fmt;
1612 ALCint attrs[11];
1613 REFERENCE_TIME period, bufdur;
1615 TRACE("(%p)->(%p, %u, %u, 0x%x, %s, %p, 0x%x)\n", This,
1616 ppMasteringVoice, inputChannels, inputSampleRate, flags,
1617 wine_dbgstr_w(deviceId), pEffectChain, streamCategory);
1619 if(flags != 0)
1620 WARN("Unknown flags set: 0x%x\n", flags);
1622 if(pEffectChain)
1623 WARN("Effect chain is unimplemented\n");
1625 EnterCriticalSection(&This->lock);
1627 /* there can only be one Mastering Voice, so just build it into XA2 */
1628 if(This->aclient){
1629 LeaveCriticalSection(&This->lock);
1630 return COMPAT_E_INVALID_CALL;
1633 if(!deviceId){
1634 if(This->ndevs == 0){
1635 LeaveCriticalSection(&This->lock);
1636 return E_NOTFOUND;
1638 deviceId = This->devids[0];
1641 hr = IMMDeviceEnumerator_GetDevice(This->devenum, deviceId, &dev);
1642 if(FAILED(hr)){
1643 WARN("GetDevice failed: %08x\n", hr);
1644 hr = COMPAT_E_DEVICE_INVALIDATED;
1645 goto exit;
1648 hr = IMMDevice_Activate(dev, &IID_IAudioClient,
1649 CLSCTX_INPROC_SERVER, NULL, (void**)&This->aclient);
1650 if(FAILED(hr)){
1651 WARN("Activate(IAudioClient) failed: %08x\n", hr);
1652 IMMDevice_Release(dev);
1653 hr = COMPAT_E_DEVICE_INVALIDATED;
1654 goto exit;
1657 IMMDevice_Release(dev);
1659 hr = IAudioClient_GetMixFormat(This->aclient, &fmt);
1660 if(FAILED(hr)){
1661 WARN("GetMixFormat failed: %08x\n", hr);
1662 hr = COMPAT_E_DEVICE_INVALIDATED;
1663 goto exit;
1666 if(sizeof(WAVEFORMATEX) + fmt->cbSize > sizeof(WAVEFORMATEXTENSIBLE)){
1667 FIXME("Mix format doesn't fit into WAVEFORMATEXTENSIBLE!\n");
1668 hr = COMPAT_E_DEVICE_INVALIDATED;
1669 goto exit;
1672 if(inputChannels == XAUDIO2_DEFAULT_CHANNELS)
1673 inputChannels = fmt->nChannels;
1674 if(inputSampleRate == XAUDIO2_DEFAULT_SAMPLERATE)
1675 inputSampleRate = fmt->nSamplesPerSec;
1677 memcpy(&This->fmt, fmt, sizeof(WAVEFORMATEX) + fmt->cbSize);
1678 This->fmt.Format.nChannels = inputChannels;
1679 This->fmt.Format.nSamplesPerSec = inputSampleRate;
1680 This->fmt.Format.nBlockAlign = This->fmt.Format.nChannels * This->fmt.Format.wBitsPerSample / 8;
1681 This->fmt.Format.nAvgBytesPerSec = This->fmt.Format.nSamplesPerSec * This->fmt.Format.nBlockAlign;
1682 This->fmt.dwChannelMask = get_channel_mask(This->fmt.Format.nChannels);
1684 CoTaskMemFree(fmt);
1685 fmt = NULL;
1687 hr = IAudioClient_IsFormatSupported(This->aclient,
1688 AUDCLNT_SHAREMODE_SHARED, &This->fmt.Format, &fmt);
1689 if(hr == S_FALSE){
1690 if(sizeof(WAVEFORMATEX) + fmt->cbSize > sizeof(WAVEFORMATEXTENSIBLE)){
1691 FIXME("Mix format doesn't fit into WAVEFORMATEXTENSIBLE!\n");
1692 hr = COMPAT_E_DEVICE_INVALIDATED;
1693 goto exit;
1695 memcpy(&This->fmt, fmt, sizeof(WAVEFORMATEX) + fmt->cbSize);
1698 CoTaskMemFree(fmt);
1700 hr = IAudioClient_GetDevicePeriod(This->aclient, &period, NULL);
1701 if(FAILED(hr)){
1702 WARN("GetDevicePeriod failed: %08x\n", hr);
1703 hr = COMPAT_E_DEVICE_INVALIDATED;
1704 goto exit;
1707 /* 3 periods or 0.1 seconds */
1708 bufdur = max(3 * period, 1000000);
1710 hr = IAudioClient_Initialize(This->aclient, AUDCLNT_SHAREMODE_SHARED,
1711 AUDCLNT_STREAMFLAGS_EVENTCALLBACK, bufdur,
1712 0, &This->fmt.Format, NULL);
1713 if(FAILED(hr)){
1714 WARN("Initialize failed: %08x\n", hr);
1715 hr = COMPAT_E_DEVICE_INVALIDATED;
1716 goto exit;
1719 This->period_frames = MulDiv(period, inputSampleRate, 10000000);
1721 hr = IAudioClient_SetEventHandle(This->aclient, This->mmevt);
1722 if(FAILED(hr)){
1723 WARN("Initialize failed: %08x\n", hr);
1724 hr = COMPAT_E_DEVICE_INVALIDATED;
1725 goto exit;
1728 hr = IAudioClient_GetService(This->aclient, &IID_IAudioRenderClient,
1729 (void**)&This->render);
1730 if(FAILED(hr)){
1731 WARN("GetService(IAudioRenderClient) failed: %08x\n", hr);
1732 hr = COMPAT_E_DEVICE_INVALIDATED;
1733 goto exit;
1736 /* setup openal context */
1737 attrs[0] = ALC_FORMAT_CHANNELS_SOFT;
1738 switch(inputChannels){
1739 case 1:
1740 attrs[1] = ALC_MONO_SOFT;
1741 break;
1742 case 2:
1743 attrs[1] = ALC_STEREO_SOFT;
1744 break;
1745 case 4:
1746 attrs[1] = ALC_QUAD_SOFT;
1747 break;
1748 case 6:
1749 attrs[1] = ALC_5POINT1_SOFT;
1750 break;
1751 case 7:
1752 attrs[1] = ALC_6POINT1_SOFT;
1753 break;
1754 case 8:
1755 attrs[1] = ALC_7POINT1_SOFT;
1756 break;
1757 default:
1758 WARN("OpenAL doesn't support %u channels\n", inputChannels);
1759 LeaveCriticalSection(&This->lock);
1760 return AUDCLNT_E_UNSUPPORTED_FORMAT;
1763 attrs[2] = ALC_FREQUENCY;
1764 attrs[3] = inputSampleRate;
1766 attrs[4] = ALC_FORMAT_TYPE_SOFT;
1767 attrs[5] = al_get_loopback_format(&This->fmt);
1769 /* some games create very many sources */
1770 attrs[6] = ALC_STEREO_SOURCES;
1771 attrs[7] = 1024;
1772 attrs[8] = ALC_MONO_SOURCES;
1773 attrs[9] = 1024;
1775 attrs[10] = 0;
1777 if(!attrs[5]){
1778 WARN("OpenAL can't output samples in this format\n");
1779 hr = COMPAT_E_DEVICE_INVALIDATED;
1780 goto exit;
1783 This->al_device = palcLoopbackOpenDeviceSOFT(NULL);
1784 if(!This->al_device){
1785 WARN("alcLoopbackOpenDeviceSOFT failed\n");
1786 hr = COMPAT_E_DEVICE_INVALIDATED;
1787 goto exit;
1790 This->al_ctx = alcCreateContext(This->al_device, attrs);
1791 if(!This->al_ctx){
1792 WARN("alcCreateContext failed\n");
1793 hr = COMPAT_E_DEVICE_INVALIDATED;
1794 goto exit;
1797 hr = IAudioClient_Start(This->aclient);
1798 if (FAILED(hr))
1800 WARN("Start(IAudioClient) failed: %08x\n", hr);
1801 hr = COMPAT_E_DEVICE_INVALIDATED;
1802 goto exit;
1805 #if XAUDIO2_VER == 0
1806 *ppMasteringVoice = (IXAudio2MasteringVoice*)&This->IXAudio20MasteringVoice_iface;
1807 #elif XAUDIO2_VER <= 3
1808 *ppMasteringVoice = (IXAudio2MasteringVoice*)&This->IXAudio23MasteringVoice_iface;
1809 #elif XAUDIO2_VER <= 7
1810 *ppMasteringVoice = (IXAudio2MasteringVoice*)&This->IXAudio27MasteringVoice_iface;
1811 #else
1812 *ppMasteringVoice = &This->IXAudio2MasteringVoice_iface;
1813 #endif
1815 exit:
1816 if(FAILED(hr)){
1817 if(This->render){
1818 IAudioRenderClient_Release(This->render);
1819 This->render = NULL;
1821 if(This->aclient){
1822 IAudioClient_Release(This->aclient);
1823 This->aclient = NULL;
1825 if(This->al_ctx){
1826 alcDestroyContext(This->al_ctx);
1827 This->al_ctx = NULL;
1829 if(This->al_device){
1830 alcCloseDevice(This->al_device);
1831 This->al_device = NULL;
1835 LeaveCriticalSection(&This->lock);
1837 return hr;
1840 static DWORD WINAPI engine_threadproc(void *arg);
1842 static HRESULT WINAPI IXAudio2Impl_StartEngine(IXAudio2 *iface)
1844 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1846 TRACE("(%p)->()\n", This);
1848 This->running = TRUE;
1850 if(!This->engine)
1851 This->engine = CreateThread(NULL, 0, engine_threadproc, This, 0, NULL);
1853 return S_OK;
1856 static void WINAPI IXAudio2Impl_StopEngine(IXAudio2 *iface)
1858 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1860 TRACE("(%p)->()\n", This);
1862 This->running = FALSE;
1865 static HRESULT WINAPI IXAudio2Impl_CommitChanges(IXAudio2 *iface,
1866 UINT32 operationSet)
1868 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1870 TRACE("(%p)->(0x%x): stub!\n", This, operationSet);
1872 return E_NOTIMPL;
1875 static void WINAPI IXAudio2Impl_GetPerformanceData(IXAudio2 *iface,
1876 XAUDIO2_PERFORMANCE_DATA *pPerfData)
1878 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1880 TRACE("(%p)->(%p): stub!\n", This, pPerfData);
1882 memset(pPerfData, 0, sizeof(*pPerfData));
1885 static void WINAPI IXAudio2Impl_SetDebugConfiguration(IXAudio2 *iface,
1886 const XAUDIO2_DEBUG_CONFIGURATION *pDebugConfiguration,
1887 void *pReserved)
1889 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1891 FIXME("(%p)->(%p, %p): stub!\n", This, pDebugConfiguration, pReserved);
1894 /* XAudio2 2.8 */
1895 static const IXAudio2Vtbl XAudio2_Vtbl =
1897 IXAudio2Impl_QueryInterface,
1898 IXAudio2Impl_AddRef,
1899 IXAudio2Impl_Release,
1900 IXAudio2Impl_RegisterForCallbacks,
1901 IXAudio2Impl_UnregisterForCallbacks,
1902 IXAudio2Impl_CreateSourceVoice,
1903 IXAudio2Impl_CreateSubmixVoice,
1904 IXAudio2Impl_CreateMasteringVoice,
1905 IXAudio2Impl_StartEngine,
1906 IXAudio2Impl_StopEngine,
1907 IXAudio2Impl_CommitChanges,
1908 IXAudio2Impl_GetPerformanceData,
1909 IXAudio2Impl_SetDebugConfiguration
1912 struct xaudio2_cf {
1913 IClassFactory IClassFactory_iface;
1914 LONG ref;
1917 static struct xaudio2_cf *impl_from_IClassFactory(IClassFactory *iface)
1919 return CONTAINING_RECORD(iface, struct xaudio2_cf, IClassFactory_iface);
1922 static HRESULT WINAPI XAudio2CF_QueryInterface(IClassFactory *iface, REFIID riid, void **ppobj)
1924 if(IsEqualGUID(riid, &IID_IUnknown)
1925 || IsEqualGUID(riid, &IID_IClassFactory))
1927 IClassFactory_AddRef(iface);
1928 *ppobj = iface;
1929 return S_OK;
1932 *ppobj = NULL;
1933 WARN("(%p)->(%s, %p): interface not found\n", iface, debugstr_guid(riid), ppobj);
1934 return E_NOINTERFACE;
1937 static ULONG WINAPI XAudio2CF_AddRef(IClassFactory *iface)
1939 struct xaudio2_cf *This = impl_from_IClassFactory(iface);
1940 ULONG ref = InterlockedIncrement(&This->ref);
1941 TRACE("(%p)->(): Refcount now %u\n", This, ref);
1942 return ref;
1945 static ULONG WINAPI XAudio2CF_Release(IClassFactory *iface)
1947 struct xaudio2_cf *This = impl_from_IClassFactory(iface);
1948 ULONG ref = InterlockedDecrement(&This->ref);
1949 TRACE("(%p)->(): Refcount now %u\n", This, ref);
1950 if (!ref)
1951 HeapFree(GetProcessHeap(), 0, This);
1952 return ref;
1955 static HRESULT initialize_mmdevices(IXAudio2Impl *This)
1957 IMMDeviceCollection *devcoll;
1958 UINT devcount;
1959 HRESULT hr;
1961 if(!This->devenum){
1962 hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL,
1963 CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void**)&This->devenum);
1964 if(FAILED(hr))
1965 return hr;
1968 hr = IMMDeviceEnumerator_EnumAudioEndpoints(This->devenum, eRender,
1969 DEVICE_STATE_ACTIVE, &devcoll);
1970 if(FAILED(hr)){
1971 return hr;
1974 hr = IMMDeviceCollection_GetCount(devcoll, &devcount);
1975 if(FAILED(hr)){
1976 IMMDeviceCollection_Release(devcoll);
1977 return hr;
1980 if(devcount > 0){
1981 UINT i, count = 1;
1982 IMMDevice *dev, *def_dev;
1984 /* make sure that device 0 is the default device */
1985 IMMDeviceEnumerator_GetDefaultAudioEndpoint(This->devenum, eRender, eConsole, &def_dev);
1987 This->devids = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *) * devcount);
1989 for(i = 0; i < devcount; ++i){
1990 hr = IMMDeviceCollection_Item(devcoll, i, &dev);
1991 if(SUCCEEDED(hr)){
1992 UINT idx;
1994 if(dev == def_dev)
1995 idx = 0;
1996 else{
1997 idx = count;
1998 ++count;
2001 hr = IMMDevice_GetId(dev, &This->devids[idx]);
2002 if(FAILED(hr)){
2003 WARN("GetId failed: %08x\n", hr);
2004 HeapFree(GetProcessHeap(), 0, This->devids);
2005 This->devids = NULL;
2006 IMMDevice_Release(dev);
2007 return hr;
2010 IMMDevice_Release(dev);
2011 }else{
2012 WARN("Item failed: %08x\n", hr);
2013 HeapFree(GetProcessHeap(), 0, This->devids);
2014 This->devids = NULL;
2015 IMMDeviceCollection_Release(devcoll);
2016 return hr;
2021 IMMDeviceCollection_Release(devcoll);
2023 This->ndevs = devcount;
2025 return S_OK;
2028 static HRESULT WINAPI XAudio2CF_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
2029 REFIID riid, void **ppobj)
2031 struct xaudio2_cf *This = impl_from_IClassFactory(iface);
2032 HRESULT hr;
2033 IXAudio2Impl *object;
2035 TRACE("(%p)->(%p,%s,%p)\n", This, pOuter, debugstr_guid(riid), ppobj);
2037 *ppobj = NULL;
2039 if(pOuter)
2040 return CLASS_E_NOAGGREGATION;
2042 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2043 if(!object)
2044 return E_OUTOFMEMORY;
2046 object->IXAudio2_iface.lpVtbl = &XAudio2_Vtbl;
2047 object->IXAudio2MasteringVoice_iface.lpVtbl = &XAudio2MasteringVoice_Vtbl;
2049 #if XAUDIO2_VER == 0
2050 object->IXAudio20_iface.lpVtbl = &XAudio20_Vtbl;
2051 #elif XAUDIO2_VER <= 2
2052 object->IXAudio22_iface.lpVtbl = &XAudio22_Vtbl;
2053 #elif XAUDIO2_VER <= 7
2054 object->IXAudio27_iface.lpVtbl = &XAudio27_Vtbl;
2055 #endif
2057 #if XAUDIO2_VER == 0
2058 object->IXAudio20MasteringVoice_iface.lpVtbl = &XAudio20MasteringVoice_Vtbl;
2059 #elif XAUDIO2_VER <= 3
2060 object->IXAudio23MasteringVoice_iface.lpVtbl = &XAudio23MasteringVoice_Vtbl;
2061 #elif XAUDIO2_VER <= 7
2062 object->IXAudio27MasteringVoice_iface.lpVtbl = &XAudio27MasteringVoice_Vtbl;
2063 #endif
2065 list_init(&object->source_voices);
2066 list_init(&object->submix_voices);
2068 object->mmevt = CreateEventW(NULL, FALSE, FALSE, NULL);
2069 InitializeCriticalSection(&object->lock);
2070 object->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IXAudio2Impl.lock");
2072 hr = IXAudio2_QueryInterface(&object->IXAudio2_iface, riid, ppobj);
2073 if(FAILED(hr)){
2074 HeapFree(GetProcessHeap(), 0, object);
2075 return hr;
2078 hr = initialize_mmdevices(object);
2079 if(FAILED(hr)){
2080 IUnknown_Release((IUnknown*)*ppobj);
2081 return hr;
2084 object->ncbs = 4;
2085 object->cbs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->ncbs * sizeof(*object->cbs));
2087 IXAudio2_StartEngine(&object->IXAudio2_iface);
2089 TRACE("Created XAudio version %u: %p\n", 20 + XAUDIO2_VER, object);
2091 return hr;
2094 static HRESULT WINAPI XAudio2CF_LockServer(IClassFactory *iface, BOOL dolock)
2096 FIXME("(static)->(%d): stub!\n", dolock);
2097 return S_OK;
2100 static const IClassFactoryVtbl XAudio2CF_Vtbl =
2102 XAudio2CF_QueryInterface,
2103 XAudio2CF_AddRef,
2104 XAudio2CF_Release,
2105 XAudio2CF_CreateInstance,
2106 XAudio2CF_LockServer
2109 static IClassFactory *make_xaudio2_factory(void)
2111 struct xaudio2_cf *ret = HeapAlloc(GetProcessHeap(), 0, sizeof(struct xaudio2_cf));
2112 ret->IClassFactory_iface.lpVtbl = &XAudio2CF_Vtbl;
2113 ret->ref = 0;
2114 return &ret->IClassFactory_iface;
2117 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
2119 IClassFactory *factory = NULL;
2121 TRACE("(%s, %s, %p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
2123 if(IsEqualGUID(rclsid, &CLSID_XAudio20) ||
2124 IsEqualGUID(rclsid, &CLSID_XAudio21) ||
2125 IsEqualGUID(rclsid, &CLSID_XAudio22) ||
2126 IsEqualGUID(rclsid, &CLSID_XAudio23) ||
2127 IsEqualGUID(rclsid, &CLSID_XAudio24) ||
2128 IsEqualGUID(rclsid, &CLSID_XAudio25) ||
2129 IsEqualGUID(rclsid, &CLSID_XAudio26) ||
2130 IsEqualGUID(rclsid, &CLSID_XAudio27)){
2131 factory = make_xaudio2_factory();
2133 }else if(IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter20) ||
2134 IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter21) ||
2135 IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter22) ||
2136 IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter23) ||
2137 IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter24) ||
2138 IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter25) ||
2139 IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter26) ||
2140 IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter27)){
2141 factory = make_xapo_factory(&CLSID_AudioVolumeMeter27);
2143 }else if(IsEqualGUID(rclsid, &CLSID_AudioReverb20) ||
2144 IsEqualGUID(rclsid, &CLSID_AudioReverb21) ||
2145 IsEqualGUID(rclsid, &CLSID_AudioReverb22) ||
2146 IsEqualGUID(rclsid, &CLSID_AudioReverb23) ||
2147 IsEqualGUID(rclsid, &CLSID_AudioReverb24) ||
2148 IsEqualGUID(rclsid, &CLSID_AudioReverb25) ||
2149 IsEqualGUID(rclsid, &CLSID_AudioReverb26) ||
2150 IsEqualGUID(rclsid, &CLSID_AudioReverb27)){
2151 factory = make_xapo_factory(&CLSID_FXReverb);
2154 if(!factory) return CLASS_E_CLASSNOTAVAILABLE;
2156 return IClassFactory_QueryInterface(factory, riid, ppv);
2159 HRESULT xaudio2_initialize(IXAudio2Impl *This, UINT32 flags, XAUDIO2_PROCESSOR proc)
2161 if(flags)
2162 FIXME("Unimplemented flags: 0x%x\n", flags);
2163 return S_OK;
2166 #if XAUDIO2_VER >= 8
2167 HRESULT WINAPI XAudio2Create(IXAudio2 **ppxa2, UINT32 flags, XAUDIO2_PROCESSOR proc)
2169 HRESULT hr;
2170 IXAudio2 *xa2;
2171 IClassFactory *cf;
2173 TRACE("%p 0x%x 0x%x\n", ppxa2, flags, proc);
2175 cf = make_xaudio2_factory();
2177 hr = IClassFactory_CreateInstance(cf, NULL, &IID_IXAudio2, (void**)&xa2);
2178 IClassFactory_Release(cf);
2179 if(FAILED(hr))
2180 return hr;
2182 hr = xaudio2_initialize(impl_from_IXAudio2(xa2), flags, proc);
2183 if(FAILED(hr)){
2184 IXAudio2_Release(xa2);
2185 return hr;
2188 *ppxa2 = xa2;
2190 return S_OK;
2192 #endif /* XAUDIO2_VER >= 8 */
2194 /* returns TRUE if there is more data available in the buffer, FALSE if the
2195 * buffer's data has all been queued */
2196 static BOOL xa2buffer_queue_period(XA2SourceImpl *src, XA2Buffer *buf, ALuint al_buf)
2198 UINT32 submit_bytes;
2199 const BYTE *submit_buf = NULL;
2201 if(buf->offs_bytes >= buf->cur_end_bytes){
2202 WARN("Shouldn't happen: Trying to push frames from a spent buffer?\n");
2203 return FALSE;
2206 submit_bytes = min(src->xa2->period_frames * src->submit_blocksize, buf->cur_end_bytes - buf->offs_bytes);
2207 submit_buf = buf->xa2buffer.pAudioData + buf->offs_bytes;
2208 buf->offs_bytes += submit_bytes;
2210 alBufferData(al_buf, src->al_fmt, submit_buf, submit_bytes,
2211 src->fmt->nSamplesPerSec);
2213 alSourceQueueBuffers(src->al_src, 1, &al_buf);
2215 src->in_al_bytes += submit_bytes;
2216 src->al_bufs_used++;
2218 buf->latest_al_buf = al_buf;
2220 TRACE("queueing %u bytes, now %u in AL\n", submit_bytes, src->in_al_bytes);
2222 return buf->offs_bytes < buf->cur_end_bytes;
2225 #if XAUDIO2_VER > 0
2226 static UINT32 get_underrun_warning(XA2SourceImpl *src)
2228 UINT32 period_bytes = src->xa2->period_frames * src->submit_blocksize;
2229 UINT32 total = 0, i;
2231 for(i = 0; i < src->nbufs && total < IN_AL_PERIODS * period_bytes; ++i){
2232 XA2Buffer *buf = &src->buffers[(src->first_buf + i) % XAUDIO2_MAX_QUEUED_BUFFERS];
2233 total += buf->cur_end_bytes - buf->offs_bytes;
2234 if(buf->xa2buffer.LoopCount == XAUDIO2_LOOP_INFINITE)
2235 return 0;
2236 if(buf->xa2buffer.LoopCount > 0){
2237 total += (buf->loop_end_bytes - buf->xa2buffer.LoopBegin) * (buf->xa2buffer.LoopCount - buf->looped);
2238 total += buf->play_end_bytes - buf->loop_end_bytes;
2242 if(total >= IN_AL_PERIODS * period_bytes)
2243 return 0;
2245 return ((IN_AL_PERIODS * period_bytes - total) / period_bytes + 1) * period_bytes;
2247 #endif
2249 /* Looping:
2251 * The looped section of a buffer is a subset of the play area which is looped
2252 * LoopCount times.
2254 * v PlayBegin
2255 * vvvvvvvvvvvvvvvvvv PlayLength
2256 * v (PlayEnd)
2257 * [-----PPPLLLLLLLLPPPPPPP------]
2258 * ^ LoopBegin
2259 * ^^^^^^^^ LoopLength
2260 * ^ (LoopEnd)
2262 * In the simple case, playback will start at PlayBegin. At LoopEnd, playback
2263 * will move to LoopBegin and repeat that loop LoopCount times. Then, playback
2264 * will cease at PlayEnd.
2266 * If PlayLength is zero, then PlayEnd is the end of the buffer.
2268 * If LoopLength is zero, then LoopEnd is PlayEnd.
2270 * For corner cases and version differences, see tests.
2272 static void update_source_state(XA2SourceImpl *src)
2274 int i;
2275 ALint processed;
2276 ALint bufpos;
2278 alGetSourcei(src->al_src, AL_BUFFERS_PROCESSED, &processed);
2280 if(processed > 0){
2281 ALuint al_buffers[XAUDIO2_MAX_QUEUED_BUFFERS];
2283 alSourceUnqueueBuffers(src->al_src, processed, al_buffers);
2285 src->first_al_buf += processed;
2286 src->first_al_buf %= XAUDIO2_MAX_QUEUED_BUFFERS;
2287 src->al_bufs_used -= processed;
2289 for(i = 0; i < processed; ++i){
2290 ALint bufsize;
2292 alGetBufferi(al_buffers[i], AL_SIZE, &bufsize);
2294 src->in_al_bytes -= bufsize;
2296 if(src->abandoned_albufs == 0){
2297 src->played_frames += bufsize / src->submit_blocksize;
2299 if(al_buffers[i] == src->buffers[src->first_buf].latest_al_buf){
2300 DWORD old_buf = src->first_buf;
2302 src->first_buf++;
2303 src->first_buf %= XAUDIO2_MAX_QUEUED_BUFFERS;
2304 src->nbufs--;
2306 TRACE("%p: done with buffer %u\n", src, old_buf);
2308 if(src->buffers[old_buf].xa2buffer.Flags & XAUDIO2_END_OF_STREAM)
2309 src->played_frames = 0;
2311 if(src->cb){
2312 IXAudio2VoiceCallback_OnBufferEnd(src->cb,
2313 src->buffers[old_buf].xa2buffer.pContext);
2314 if(src->buffers[old_buf].xa2buffer.Flags & XAUDIO2_END_OF_STREAM)
2315 IXAudio2VoiceCallback_OnStreamEnd(src->cb);
2317 if(src->nbufs > 0)
2318 IXAudio2VoiceCallback_OnBufferStart(src->cb,
2319 src->buffers[src->first_buf].xa2buffer.pContext);
2322 }else{
2323 src->abandoned_albufs--;
2328 if(!src->running)
2329 return;
2331 alGetSourcei(src->al_src, AL_BYTE_OFFSET, &bufpos);
2333 /* maintain IN_AL_PERIODS periods in AL */
2334 while(src->cur_buf != (src->first_buf + src->nbufs) % XAUDIO2_MAX_QUEUED_BUFFERS &&
2335 src->in_al_bytes - bufpos < IN_AL_PERIODS * src->xa2->period_frames * src->submit_blocksize){
2336 TRACE("%p: going to queue a period from buffer %u\n", src, src->cur_buf);
2338 /* starting from an empty buffer */
2339 if(src->cb && src->cur_buf == src->first_buf && src->buffers[src->cur_buf].offs_bytes == 0 && !src->buffers[src->cur_buf].looped)
2340 IXAudio2VoiceCallback_OnBufferStart(src->cb,
2341 src->buffers[src->first_buf].xa2buffer.pContext);
2343 if(!xa2buffer_queue_period(src, &src->buffers[src->cur_buf],
2344 src->al_bufs[(src->first_al_buf + src->al_bufs_used) % XAUDIO2_MAX_QUEUED_BUFFERS])){
2345 XA2Buffer *cur = &src->buffers[src->cur_buf];
2347 if(cur->looped < cur->xa2buffer.LoopCount){
2348 if(cur->xa2buffer.LoopCount != XAUDIO2_LOOP_INFINITE)
2349 ++cur->looped;
2350 else
2351 cur->looped = 1; /* indicate that we are executing a loop */
2353 cur->offs_bytes = cur->xa2buffer.LoopBegin;
2354 if(cur->looped == cur->xa2buffer.LoopCount)
2355 cur->cur_end_bytes = cur->play_end_bytes;
2356 else
2357 cur->cur_end_bytes = cur->loop_end_bytes;
2359 if(src->cb)
2360 IXAudio2VoiceCallback_OnLoopEnd(src->cb,
2361 src->buffers[src->cur_buf].xa2buffer.pContext);
2363 }else{
2364 /* buffer is spent, move on */
2365 src->cur_buf++;
2366 src->cur_buf %= XAUDIO2_MAX_QUEUED_BUFFERS;
2372 static void do_engine_tick(IXAudio2Impl *This)
2374 BYTE *buf;
2375 XA2SourceImpl *src;
2376 HRESULT hr;
2377 UINT32 nframes, i, pad;
2379 /* maintain up to 3 periods in mmdevapi */
2380 hr = IAudioClient_GetCurrentPadding(This->aclient, &pad);
2381 if(FAILED(hr)){
2382 WARN("GetCurrentPadding failed: 0x%x\n", hr);
2383 return;
2386 nframes = This->period_frames * 3 - pad;
2388 TRACE("frames available: %u\n", nframes);
2390 if(nframes < This->period_frames)
2391 return;
2393 if(!nframes)
2394 return;
2396 for(i = 0; i < This->ncbs && This->cbs[i]; ++i)
2397 IXAudio2EngineCallback_OnProcessingPassStart(This->cbs[i]);
2399 LIST_FOR_EACH_ENTRY(src, &This->source_voices, XA2SourceImpl, entry){
2400 ALint st = 0;
2402 EnterCriticalSection(&src->lock);
2404 if(!src->in_use){
2405 LeaveCriticalSection(&src->lock);
2406 continue;
2409 if(src->cb && This->running){
2410 #if XAUDIO2_VER == 0
2411 IXAudio20VoiceCallback_OnVoiceProcessingPassStart((IXAudio20VoiceCallback*)src->cb);
2412 #else
2413 UINT32 underrun;
2414 underrun = get_underrun_warning(src);
2415 if(underrun > 0)
2416 TRACE("Calling OnVoiceProcessingPassStart with BytesRequired: %u\n", underrun);
2417 IXAudio2VoiceCallback_OnVoiceProcessingPassStart(src->cb, underrun);
2418 #endif
2421 update_source_state(src);
2423 if(This->running){
2424 alGetSourcei(src->al_src, AL_SOURCE_STATE, &st);
2425 if(st != AL_PLAYING)
2426 alSourcePlay(src->al_src);
2428 if(src->cb)
2429 IXAudio2VoiceCallback_OnVoiceProcessingPassEnd(src->cb);
2432 LeaveCriticalSection(&src->lock);
2435 hr = IAudioRenderClient_GetBuffer(This->render, nframes, &buf);
2436 if(FAILED(hr))
2437 WARN("GetBuffer failed: %08x\n", hr);
2439 palcRenderSamplesSOFT(This->al_device, buf, nframes);
2441 hr = IAudioRenderClient_ReleaseBuffer(This->render, nframes, 0);
2442 if(FAILED(hr))
2443 WARN("ReleaseBuffer failed: %08x\n", hr);
2445 for(i = 0; i < This->ncbs && This->cbs[i]; ++i)
2446 IXAudio2EngineCallback_OnProcessingPassEnd(This->cbs[i]);
2449 static DWORD WINAPI engine_threadproc(void *arg)
2451 IXAudio2Impl *This = arg;
2452 while(1){
2453 WaitForSingleObject(This->mmevt, INFINITE);
2455 if(This->stop_engine)
2456 break;
2458 EnterCriticalSection(&This->lock);
2460 if(!This->running || !This->aclient){
2461 LeaveCriticalSection(&This->lock);
2462 continue;
2465 palcSetThreadContext(This->al_ctx);
2467 do_engine_tick(This);
2469 LeaveCriticalSection(&This->lock);
2471 return 0;