wined3d: Clear the renderbuffer IDs on unload.
[wine.git] / dlls / xaudio2_7 / xaudio_dll.c
blob13935994b72dff6a4a37a2c64834400fbb9269a0
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);
40 static HINSTANCE instance;
42 #define IN_AL_PERIODS 4
44 #if XAUDIO2_VER == 0
45 #define COMPAT_E_INVALID_CALL E_INVALIDARG
46 #define COMPAT_E_DEVICE_INVALIDATED XAUDIO20_E_DEVICE_INVALIDATED
47 #else
48 #define COMPAT_E_INVALID_CALL XAUDIO2_E_INVALID_CALL
49 #define COMPAT_E_DEVICE_INVALIDATED XAUDIO2_E_DEVICE_INVALIDATED
50 #endif
52 static void dump_fmt(const WAVEFORMATEX *fmt)
54 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
55 switch(fmt->wFormatTag){
56 #define DOCASE(x) case x: TRACE(#x); break;
57 DOCASE(WAVE_FORMAT_PCM)
58 DOCASE(WAVE_FORMAT_IEEE_FLOAT)
59 DOCASE(WAVE_FORMAT_EXTENSIBLE)
60 #undef DOCASE
61 default:
62 TRACE("Unknown");
63 break;
65 TRACE(")\n");
67 TRACE("nChannels: %u\n", fmt->nChannels);
68 TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
69 TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
70 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
71 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
72 TRACE("cbSize: %u\n", fmt->cbSize);
74 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
75 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
76 TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
77 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
78 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
79 }else if(fmt->wFormatTag == WAVE_FORMAT_ADPCM){
80 ADPCMWAVEFORMAT *fmtadpcm = (void*)fmt;
81 TRACE("wSamplesPerBlock: %u\n", fmtadpcm->wSamplesPerBlock);
85 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, void *pReserved)
87 TRACE("(%p, %d, %p)\n", hinstDLL, reason, pReserved);
89 switch (reason)
91 case DLL_WINE_PREATTACH:
92 return FALSE; /* prefer native version */
93 case DLL_PROCESS_ATTACH:
94 instance = hinstDLL;
95 DisableThreadLibraryCalls( hinstDLL );
97 if(!alcIsExtensionPresent(NULL, "ALC_SOFT_loopback") ||
98 !(palcLoopbackOpenDeviceSOFT = alcGetProcAddress(NULL, "alcLoopbackOpenDeviceSOFT")) ||
99 !(palcRenderSamplesSOFT = alcGetProcAddress(NULL, "alcRenderSamplesSOFT"))){
100 ERR("XAudio2 requires the ALC_SOFT_loopback extension (OpenAL-Soft >= 1.14)\n");
101 return FALSE;
104 break;
106 return TRUE;
109 HRESULT WINAPI DllCanUnloadNow(void)
111 return S_FALSE;
114 HRESULT WINAPI DllRegisterServer(void)
116 TRACE("\n");
117 return __wine_register_resources(instance);
120 HRESULT WINAPI DllUnregisterServer(void)
122 TRACE("\n");
123 return __wine_unregister_resources(instance);
126 static XA2SourceImpl *impl_from_IXAudio2SourceVoice(IXAudio2SourceVoice *iface)
128 return CONTAINING_RECORD(iface, XA2SourceImpl, IXAudio2SourceVoice_iface);
131 static XA2SubmixImpl *impl_from_IXAudio2SubmixVoice(IXAudio2SubmixVoice *iface)
133 return CONTAINING_RECORD(iface, XA2SubmixImpl, IXAudio2SubmixVoice_iface);
136 static inline IXAudio2Impl *impl_from_IXAudio2(IXAudio2 *iface)
138 return CONTAINING_RECORD(iface, IXAudio2Impl, IXAudio2_iface);
141 static IXAudio2Impl *impl_from_IXAudio2MasteringVoice(IXAudio2MasteringVoice *iface)
143 return CONTAINING_RECORD(iface, IXAudio2Impl, IXAudio2MasteringVoice_iface);
146 static DWORD get_channel_mask(unsigned int channels)
148 switch(channels){
149 case 0:
150 return 0;
151 case 1:
152 return KSAUDIO_SPEAKER_MONO;
153 case 2:
154 return KSAUDIO_SPEAKER_STEREO;
155 case 3:
156 return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY;
157 case 4:
158 return KSAUDIO_SPEAKER_QUAD; /* not _SURROUND */
159 case 5:
160 return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY;
161 case 6:
162 return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */
163 case 7:
164 return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER;
165 case 8:
166 return KSAUDIO_SPEAKER_7POINT1_SURROUND; /* Vista deprecates 7POINT1 */
168 FIXME("Unknown speaker configuration: %u\n", channels);
169 return 0;
172 static void WINAPI XA2SRC_GetVoiceDetails(IXAudio2SourceVoice *iface,
173 XAUDIO2_VOICE_DETAILS *pVoiceDetails)
175 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
176 TRACE("%p, %p\n", This, pVoiceDetails);
179 static HRESULT WINAPI XA2SRC_SetOutputVoices(IXAudio2SourceVoice *iface,
180 const XAUDIO2_VOICE_SENDS *pSendList)
182 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
183 int i;
184 XAUDIO2_VOICE_SENDS def_send;
185 XAUDIO2_SEND_DESCRIPTOR def_desc;
187 TRACE("%p, %p\n", This, pSendList);
189 if(!pSendList){
190 def_desc.Flags = 0;
191 def_desc.pOutputVoice = (IXAudio2Voice*)&This->xa2->IXAudio2MasteringVoice_iface;
193 def_send.SendCount = 1;
194 def_send.pSends = &def_desc;
196 pSendList = &def_send;
199 if(TRACE_ON(xaudio2)){
200 for(i = 0; i < pSendList->SendCount; ++i){
201 XAUDIO2_SEND_DESCRIPTOR *desc = &pSendList->pSends[i];
202 TRACE("Outputting to: 0x%x, %p\n", desc->Flags, desc->pOutputVoice);
206 if(This->nsends < pSendList->SendCount){
207 HeapFree(GetProcessHeap(), 0, This->sends);
208 This->sends = HeapAlloc(GetProcessHeap(), 0, sizeof(*This->sends) * pSendList->SendCount);
209 This->nsends = pSendList->SendCount;
210 }else
211 memset(This->sends, 0, sizeof(*This->sends) * This->nsends);
213 memcpy(This->sends, pSendList->pSends, sizeof(*This->sends) * pSendList->SendCount);
215 return S_OK;
218 static HRESULT WINAPI XA2SRC_SetEffectChain(IXAudio2SourceVoice *iface,
219 const XAUDIO2_EFFECT_CHAIN *pEffectChain)
221 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
222 TRACE("%p, %p\n", This, pEffectChain);
223 return S_OK;
226 static HRESULT WINAPI XA2SRC_EnableEffect(IXAudio2SourceVoice *iface,
227 UINT32 EffectIndex, UINT32 OperationSet)
229 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
230 TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
231 return S_OK;
234 static HRESULT WINAPI XA2SRC_DisableEffect(IXAudio2SourceVoice *iface,
235 UINT32 EffectIndex, UINT32 OperationSet)
237 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
238 TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
239 return S_OK;
242 static void WINAPI XA2SRC_GetEffectState(IXAudio2SourceVoice *iface,
243 UINT32 EffectIndex, BOOL *pEnabled)
245 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
246 TRACE("%p, %u, %p\n", This, EffectIndex, pEnabled);
249 static HRESULT WINAPI XA2SRC_SetEffectParameters(IXAudio2SourceVoice *iface,
250 UINT32 EffectIndex, const void *pParameters, UINT32 ParametersByteSize,
251 UINT32 OperationSet)
253 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
254 TRACE("%p, %u, %p, 0x%x, 0x%x\n", This, EffectIndex, pParameters,
255 ParametersByteSize, OperationSet);
256 return S_OK;
259 static HRESULT WINAPI XA2SRC_GetEffectParameters(IXAudio2SourceVoice *iface,
260 UINT32 EffectIndex, void *pParameters, UINT32 ParametersByteSize)
262 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
263 TRACE("%p, %u, %p, 0x%x\n", This, EffectIndex, pParameters,
264 ParametersByteSize);
265 return S_OK;
268 static HRESULT WINAPI XA2SRC_SetFilterParameters(IXAudio2SourceVoice *iface,
269 const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
271 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
272 TRACE("%p, %p, 0x%x\n", This, pParameters, OperationSet);
273 return S_OK;
276 static void WINAPI XA2SRC_GetFilterParameters(IXAudio2SourceVoice *iface,
277 XAUDIO2_FILTER_PARAMETERS *pParameters)
279 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
280 TRACE("%p, %p\n", This, pParameters);
283 static HRESULT WINAPI XA2SRC_SetOutputFilterParameters(IXAudio2SourceVoice *iface,
284 IXAudio2Voice *pDestinationVoice,
285 const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
287 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
288 TRACE("%p, %p, %p, 0x%x\n", This, pDestinationVoice, pParameters, OperationSet);
289 return S_OK;
292 static void WINAPI XA2SRC_GetOutputFilterParameters(IXAudio2SourceVoice *iface,
293 IXAudio2Voice *pDestinationVoice,
294 XAUDIO2_FILTER_PARAMETERS *pParameters)
296 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
297 TRACE("%p, %p, %p\n", This, pDestinationVoice, pParameters);
300 static HRESULT WINAPI XA2SRC_SetVolume(IXAudio2SourceVoice *iface, float Volume,
301 UINT32 OperationSet)
303 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
304 ALfloat al_gain;
306 TRACE("%p, %f, 0x%x\n", This, Volume, OperationSet);
308 al_gain = Volume;
310 alSourcef(This->al_src, AL_GAIN, al_gain);
312 return S_OK;
315 static void WINAPI XA2SRC_GetVolume(IXAudio2SourceVoice *iface, float *pVolume)
317 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
318 TRACE("%p, %p\n", This, pVolume);
321 static HRESULT WINAPI XA2SRC_SetChannelVolumes(IXAudio2SourceVoice *iface,
322 UINT32 Channels, const float *pVolumes, UINT32 OperationSet)
324 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
325 TRACE("%p, %u, %p, 0x%x\n", This, Channels, pVolumes, OperationSet);
326 return S_OK;
329 static void WINAPI XA2SRC_GetChannelVolumes(IXAudio2SourceVoice *iface,
330 UINT32 Channels, float *pVolumes)
332 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
333 TRACE("%p, %u, %p\n", This, Channels, pVolumes);
336 static HRESULT WINAPI XA2SRC_SetOutputMatrix(IXAudio2SourceVoice *iface,
337 IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
338 UINT32 DestinationChannels, const float *pLevelMatrix,
339 UINT32 OperationSet)
341 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
342 TRACE("%p, %p, %u, %u, %p, 0x%x\n", This, pDestinationVoice,
343 SourceChannels, DestinationChannels, pLevelMatrix, OperationSet);
344 return S_OK;
347 static void WINAPI XA2SRC_GetOutputMatrix(IXAudio2SourceVoice *iface,
348 IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
349 UINT32 DestinationChannels, float *pLevelMatrix)
351 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
352 TRACE("%p, %p, %u, %u, %p\n", This, pDestinationVoice,
353 SourceChannels, DestinationChannels, pLevelMatrix);
356 static void WINAPI XA2SRC_DestroyVoice(IXAudio2SourceVoice *iface)
358 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
359 ALint processed;
361 TRACE("%p\n", This);
363 EnterCriticalSection(&This->lock);
365 if(!This->in_use){
366 LeaveCriticalSection(&This->lock);
367 return;
370 This->in_use = FALSE;
372 This->running = FALSE;
374 IXAudio2SourceVoice_Stop(iface, 0, 0);
376 alSourceStop(This->al_src);
378 /* unqueue all buffers */
379 alSourcei(This->al_src, AL_BUFFER, AL_NONE);
381 alGetSourcei(This->al_src, AL_BUFFERS_PROCESSED, &processed);
383 if(processed > 0){
384 ALuint al_buffers[XAUDIO2_MAX_QUEUED_BUFFERS];
386 alSourceUnqueueBuffers(This->al_src, processed, al_buffers);
389 HeapFree(GetProcessHeap(), 0, This->fmt);
391 alDeleteBuffers(XAUDIO2_MAX_QUEUED_BUFFERS, This->al_bufs);
392 alDeleteSources(1, &This->al_src);
394 This->in_al_bytes = 0;
395 This->al_bufs_used = 0;
396 This->played_frames = 0;
397 This->nbufs = 0;
398 This->first_buf = 0;
399 This->cur_buf = 0;
401 LeaveCriticalSection(&This->lock);
404 static HRESULT WINAPI XA2SRC_Start(IXAudio2SourceVoice *iface, UINT32 Flags,
405 UINT32 OperationSet)
407 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
409 TRACE("%p, 0x%x, 0x%x\n", This, Flags, OperationSet);
411 EnterCriticalSection(&This->lock);
413 This->running = TRUE;
415 LeaveCriticalSection(&This->lock);
417 return S_OK;
420 static HRESULT WINAPI XA2SRC_Stop(IXAudio2SourceVoice *iface, UINT32 Flags,
421 UINT32 OperationSet)
423 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
425 TRACE("%p, 0x%x, 0x%x\n", This, Flags, OperationSet);
427 EnterCriticalSection(&This->lock);
429 This->running = FALSE;
431 LeaveCriticalSection(&This->lock);
433 return S_OK;
436 static ALenum get_al_format(const WAVEFORMATEX *fmt)
438 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)fmt;
439 if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
440 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
441 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
442 switch(fmt->wBitsPerSample){
443 case 8:
444 switch(fmt->nChannels){
445 case 1:
446 return AL_FORMAT_MONO8;
447 case 2:
448 return AL_FORMAT_STEREO8;
449 case 4:
450 return AL_FORMAT_QUAD8;
451 case 6:
452 return AL_FORMAT_51CHN8;
453 case 7:
454 return AL_FORMAT_61CHN8;
455 case 8:
456 return AL_FORMAT_71CHN8;
458 break;
459 case 16:
460 switch(fmt->nChannels){
461 case 1:
462 return AL_FORMAT_MONO16;
463 case 2:
464 return AL_FORMAT_STEREO16;
465 case 4:
466 return AL_FORMAT_QUAD16;
467 case 6:
468 return AL_FORMAT_51CHN16;
469 case 7:
470 return AL_FORMAT_61CHN16;
471 case 8:
472 return AL_FORMAT_71CHN16;
474 break;
476 }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
477 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
478 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
479 if(fmt->wBitsPerSample == 32){
480 switch(fmt->nChannels){
481 case 1:
482 return AL_FORMAT_MONO_FLOAT32;
483 case 2:
484 return AL_FORMAT_STEREO_FLOAT32;
488 return 0;
491 static HRESULT WINAPI XA2SRC_SubmitSourceBuffer(IXAudio2SourceVoice *iface,
492 const XAUDIO2_BUFFER *pBuffer, const XAUDIO2_BUFFER_WMA *pBufferWMA)
494 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
495 XA2Buffer *buf;
496 UINT32 buf_idx;
498 TRACE("%p, %p, %p\n", This, pBuffer, pBufferWMA);
500 if(TRACE_ON(xaudio2)){
501 TRACE("Flags: 0x%x\n", pBuffer->Flags);
502 TRACE("AudioBytes: %u\n", pBuffer->AudioBytes);
503 TRACE("pAudioData: %p\n", pBuffer->pAudioData);
504 TRACE("PlayBegin: %u\n", pBuffer->PlayBegin);
505 TRACE("PlayLength: %u\n", pBuffer->PlayLength);
506 TRACE("LoopBegin: %u\n", pBuffer->LoopBegin);
507 TRACE("LoopLength: %u\n", pBuffer->LoopLength);
508 TRACE("LoopCount: %u\n", pBuffer->LoopCount);
509 TRACE("pContext: %p\n", pBuffer->pContext);
512 EnterCriticalSection(&This->lock);
514 if(This->nbufs >= XAUDIO2_MAX_QUEUED_BUFFERS){
515 TRACE("Too many buffers queued!\n");
516 LeaveCriticalSection(&This->lock);
517 return COMPAT_E_INVALID_CALL;
520 buf_idx = (This->first_buf + This->nbufs) % XAUDIO2_MAX_QUEUED_BUFFERS;
521 buf = &This->buffers[buf_idx];
522 memset(buf, 0, sizeof(*buf));
524 /* API contract: pAudioData must remain valid until this buffer is played,
525 * but pBuffer itself may be reused immediately */
526 memcpy(&buf->xa2buffer, pBuffer, sizeof(*pBuffer));
528 #if XAUDIO2_VER == 0
529 if(buf->xa2buffer.LoopCount == XAUDIO20_LOOP_INFINITE)
530 buf->xa2buffer.LoopCount = XAUDIO2_LOOP_INFINITE;
531 #endif
533 /* convert samples offsets to bytes */
534 if(This->fmt->wFormatTag == WAVE_FORMAT_ADPCM){
535 /* ADPCM gives us a number of samples per block, so round down to
536 * nearest block and convert to bytes */
537 buf->xa2buffer.PlayBegin = buf->xa2buffer.PlayBegin / ((ADPCMWAVEFORMAT*)This->fmt)->wSamplesPerBlock * This->fmt->nBlockAlign;
538 buf->xa2buffer.PlayLength = buf->xa2buffer.PlayLength / ((ADPCMWAVEFORMAT*)This->fmt)->wSamplesPerBlock * This->fmt->nBlockAlign;
539 buf->xa2buffer.LoopBegin = buf->xa2buffer.LoopBegin / ((ADPCMWAVEFORMAT*)This->fmt)->wSamplesPerBlock * This->fmt->nBlockAlign;
540 buf->xa2buffer.LoopLength = buf->xa2buffer.LoopLength / ((ADPCMWAVEFORMAT*)This->fmt)->wSamplesPerBlock * This->fmt->nBlockAlign;
541 }else{
542 buf->xa2buffer.PlayBegin *= This->fmt->nBlockAlign;
543 buf->xa2buffer.PlayLength *= This->fmt->nBlockAlign;
544 buf->xa2buffer.LoopBegin *= This->fmt->nBlockAlign;
545 buf->xa2buffer.LoopLength *= This->fmt->nBlockAlign;
548 if(buf->xa2buffer.PlayLength == 0)
549 /* set to end of buffer */
550 buf->xa2buffer.PlayLength = buf->xa2buffer.AudioBytes - buf->xa2buffer.PlayBegin;
552 buf->play_end_bytes = buf->xa2buffer.PlayBegin + buf->xa2buffer.PlayLength;
554 if(buf->xa2buffer.LoopCount){
555 if(buf->xa2buffer.LoopLength == 0)
556 /* set to end of play range */
557 buf->xa2buffer.LoopLength = buf->play_end_bytes - buf->xa2buffer.LoopBegin;
559 if(buf->xa2buffer.LoopBegin >= buf->play_end_bytes){
560 /* this actually crashes on native xaudio 2.7 */
561 LeaveCriticalSection(&This->lock);
562 return COMPAT_E_INVALID_CALL;
565 buf->loop_end_bytes = buf->xa2buffer.LoopBegin + buf->xa2buffer.LoopLength;
567 /* xaudio 2.7 allows some invalid looping setups, but later versions
568 * return an error */
569 #if XAUDIO2_VER > 7
570 if(buf->loop_end_bytes > buf->play_end_bytes){
571 LeaveCriticalSection(&This->lock);
572 return COMPAT_E_INVALID_CALL;
575 if(buf->loop_end_bytes <= buf->xa2buffer.PlayBegin){
576 LeaveCriticalSection(&This->lock);
577 return COMPAT_E_INVALID_CALL;
579 #else
580 if(buf->loop_end_bytes <= buf->xa2buffer.PlayBegin){
581 buf->xa2buffer.LoopCount = 0;
582 buf->loop_end_bytes = buf->play_end_bytes;
584 #endif
585 }else{
586 buf->xa2buffer.LoopLength = buf->xa2buffer.PlayLength;
587 buf->xa2buffer.LoopBegin = buf->xa2buffer.PlayBegin;
588 buf->loop_end_bytes = buf->play_end_bytes;
591 buf->offs_bytes = buf->xa2buffer.PlayBegin;
592 buf->cur_end_bytes = buf->loop_end_bytes;
594 buf->latest_al_buf = -1;
596 ++This->nbufs;
598 TRACE("%p: queued buffer %u (%u bytes), now %u buffers held\n",
599 This, buf_idx, buf->xa2buffer.AudioBytes, This->nbufs);
601 LeaveCriticalSection(&This->lock);
603 return S_OK;
606 static HRESULT WINAPI XA2SRC_FlushSourceBuffers(IXAudio2SourceVoice *iface)
608 UINT i, first, last, to_flush;
609 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
611 TRACE("%p\n", This);
613 EnterCriticalSection(&This->lock);
615 if(This->running && This->nbufs > 0){
616 /* when running, flush only completely unused buffers; the rest remain
617 * in queue */
618 last = (This->first_buf + This->nbufs) % XAUDIO2_MAX_QUEUED_BUFFERS;
619 first = (This->cur_buf + 1) % XAUDIO2_MAX_QUEUED_BUFFERS;
620 if(This->cur_buf == last)
621 /* nothing to do */
622 to_flush = 0;
623 else if(last >= first)
624 to_flush = last - first;
625 else
626 to_flush = last + XAUDIO2_MAX_QUEUED_BUFFERS - first;
627 }else{
628 /* when stopped, flush all buffers */
629 first = This->first_buf;
630 last = (This->first_buf + This->nbufs) % XAUDIO2_MAX_QUEUED_BUFFERS;
631 to_flush = This->nbufs;
635 for(i = first;
636 i < (first + to_flush) % XAUDIO2_MAX_QUEUED_BUFFERS;
637 i = (i + 1) % XAUDIO2_MAX_QUEUED_BUFFERS){
638 if(This->cb)
639 IXAudio2VoiceCallback_OnBufferEnd(This->cb,
640 This->buffers[i].xa2buffer.pContext);
643 This->nbufs -= to_flush;
644 This->cur_buf = (This->first_buf + This->nbufs) % XAUDIO2_MAX_QUEUED_BUFFERS;
646 LeaveCriticalSection(&This->lock);
648 return S_OK;
651 static HRESULT WINAPI XA2SRC_Discontinuity(IXAudio2SourceVoice *iface)
653 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
655 TRACE("%p\n", This);
657 EnterCriticalSection(&This->lock);
659 if(This->nbufs > 0){
660 DWORD last = (This->first_buf + This->nbufs - 1) % XAUDIO2_MAX_QUEUED_BUFFERS;
661 This->buffers[last].xa2buffer.Flags |= XAUDIO2_END_OF_STREAM;
664 LeaveCriticalSection(&This->lock);
666 return S_OK;
669 static HRESULT WINAPI XA2SRC_ExitLoop(IXAudio2SourceVoice *iface, UINT32 OperationSet)
671 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
673 TRACE("%p, 0x%x\n", This, OperationSet);
675 EnterCriticalSection(&This->lock);
677 This->buffers[This->cur_buf].looped = XAUDIO2_LOOP_INFINITE;
679 LeaveCriticalSection(&This->lock);
681 return S_OK;
684 static void WINAPI XA2SRC_GetState(IXAudio2SourceVoice *iface,
685 XAUDIO2_VOICE_STATE *pVoiceState, UINT32 Flags)
687 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
689 TRACE("%p, %p, 0x%x\n", This, pVoiceState, Flags);
691 EnterCriticalSection(&This->lock);
693 if(!(Flags & XAUDIO2_VOICE_NOSAMPLESPLAYED))
694 pVoiceState->SamplesPlayed = This->played_frames;
695 else
696 pVoiceState->SamplesPlayed = 0;
698 if(This->nbufs)
699 pVoiceState->pCurrentBufferContext = This->buffers[This->first_buf].xa2buffer.pContext;
700 else
701 pVoiceState->pCurrentBufferContext = NULL;
703 pVoiceState->BuffersQueued = This->nbufs;
705 LeaveCriticalSection(&This->lock);
707 TRACE("returning %s, queued: %u\n", wine_dbgstr_longlong(pVoiceState->SamplesPlayed), This->nbufs);
710 static HRESULT WINAPI XA2SRC_SetFrequencyRatio(IXAudio2SourceVoice *iface,
711 float Ratio, UINT32 OperationSet)
713 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
714 ALfloat r;
716 TRACE("%p, %f, 0x%x\n", This, Ratio, OperationSet);
718 if(Ratio < XAUDIO2_MIN_FREQ_RATIO)
719 r = XAUDIO2_MIN_FREQ_RATIO;
720 else if (Ratio > XAUDIO2_MAX_FREQ_RATIO)
721 r = XAUDIO2_MAX_FREQ_RATIO;
722 else
723 r = Ratio;
725 alSourcef(This->al_src, AL_PITCH, r);
727 return S_OK;
730 static void WINAPI XA2SRC_GetFrequencyRatio(IXAudio2SourceVoice *iface, float *pRatio)
732 ALfloat ratio;
733 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
735 TRACE("%p, %p\n", This, pRatio);
737 alGetSourcef(This->al_src, AL_PITCH, &ratio);
739 *pRatio = ratio;
742 static HRESULT WINAPI XA2SRC_SetSourceSampleRate(
743 IXAudio2SourceVoice *iface,
744 UINT32 NewSourceSampleRate)
746 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
748 TRACE("%p, %u\n", This, NewSourceSampleRate);
750 EnterCriticalSection(&This->lock);
752 if(This->nbufs){
753 LeaveCriticalSection(&This->lock);
754 return COMPAT_E_INVALID_CALL;
757 This->fmt->nSamplesPerSec = NewSourceSampleRate;
759 LeaveCriticalSection(&This->lock);
761 return S_OK;
764 static const IXAudio2SourceVoiceVtbl XAudio2SourceVoice_Vtbl = {
765 XA2SRC_GetVoiceDetails,
766 XA2SRC_SetOutputVoices,
767 XA2SRC_SetEffectChain,
768 XA2SRC_EnableEffect,
769 XA2SRC_DisableEffect,
770 XA2SRC_GetEffectState,
771 XA2SRC_SetEffectParameters,
772 XA2SRC_GetEffectParameters,
773 XA2SRC_SetFilterParameters,
774 XA2SRC_GetFilterParameters,
775 XA2SRC_SetOutputFilterParameters,
776 XA2SRC_GetOutputFilterParameters,
777 XA2SRC_SetVolume,
778 XA2SRC_GetVolume,
779 XA2SRC_SetChannelVolumes,
780 XA2SRC_GetChannelVolumes,
781 XA2SRC_SetOutputMatrix,
782 XA2SRC_GetOutputMatrix,
783 XA2SRC_DestroyVoice,
784 XA2SRC_Start,
785 XA2SRC_Stop,
786 XA2SRC_SubmitSourceBuffer,
787 XA2SRC_FlushSourceBuffers,
788 XA2SRC_Discontinuity,
789 XA2SRC_ExitLoop,
790 XA2SRC_GetState,
791 XA2SRC_SetFrequencyRatio,
792 XA2SRC_GetFrequencyRatio,
793 XA2SRC_SetSourceSampleRate
796 static void WINAPI XA2M_GetVoiceDetails(IXAudio2MasteringVoice *iface,
797 XAUDIO2_VOICE_DETAILS *pVoiceDetails)
799 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
800 TRACE("%p, %p\n", This, pVoiceDetails);
801 pVoiceDetails->CreationFlags = 0;
802 pVoiceDetails->InputChannels = This->fmt.Format.nChannels;
803 pVoiceDetails->InputSampleRate = This->fmt.Format.nSamplesPerSec;
806 static HRESULT WINAPI XA2M_SetOutputVoices(IXAudio2MasteringVoice *iface,
807 const XAUDIO2_VOICE_SENDS *pSendList)
809 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
810 TRACE("%p, %p\n", This, pSendList);
811 return S_OK;
814 static HRESULT WINAPI XA2M_SetEffectChain(IXAudio2MasteringVoice *iface,
815 const XAUDIO2_EFFECT_CHAIN *pEffectChain)
817 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
818 TRACE("%p, %p\n", This, pEffectChain);
819 return S_OK;
822 static HRESULT WINAPI XA2M_EnableEffect(IXAudio2MasteringVoice *iface, UINT32 EffectIndex,
823 UINT32 OperationSet)
825 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
826 TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
827 return S_OK;
830 static HRESULT WINAPI XA2M_DisableEffect(IXAudio2MasteringVoice *iface, UINT32 EffectIndex,
831 UINT32 OperationSet)
833 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
834 TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
835 return S_OK;
838 static void WINAPI XA2M_GetEffectState(IXAudio2MasteringVoice *iface, UINT32 EffectIndex,
839 BOOL *pEnabled)
841 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
842 TRACE("%p, %u, %p\n", This, EffectIndex, pEnabled);
845 static HRESULT WINAPI XA2M_SetEffectParameters(IXAudio2MasteringVoice *iface,
846 UINT32 EffectIndex, const void *pParameters, UINT32 ParametersByteSize,
847 UINT32 OperationSet)
849 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
850 TRACE("%p, %u, %p, 0x%x, 0x%x\n", This, EffectIndex, pParameters,
851 ParametersByteSize, OperationSet);
852 return S_OK;
855 static HRESULT WINAPI XA2M_GetEffectParameters(IXAudio2MasteringVoice *iface,
856 UINT32 EffectIndex, void *pParameters, UINT32 ParametersByteSize)
858 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
859 TRACE("%p, %u, %p, 0x%x\n", This, EffectIndex, pParameters,
860 ParametersByteSize);
861 return S_OK;
864 static HRESULT WINAPI XA2M_SetFilterParameters(IXAudio2MasteringVoice *iface,
865 const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
867 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
868 TRACE("%p, %p, 0x%x\n", This, pParameters, OperationSet);
869 return S_OK;
872 static void WINAPI XA2M_GetFilterParameters(IXAudio2MasteringVoice *iface,
873 XAUDIO2_FILTER_PARAMETERS *pParameters)
875 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
876 TRACE("%p, %p\n", This, pParameters);
879 static HRESULT WINAPI XA2M_SetOutputFilterParameters(IXAudio2MasteringVoice *iface,
880 IXAudio2Voice *pDestinationVoice,
881 const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
883 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
884 TRACE("%p, %p, %p, 0x%x\n", This, pDestinationVoice, pParameters, OperationSet);
885 return S_OK;
888 static void WINAPI XA2M_GetOutputFilterParameters(IXAudio2MasteringVoice *iface,
889 IXAudio2Voice *pDestinationVoice,
890 XAUDIO2_FILTER_PARAMETERS *pParameters)
892 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
893 TRACE("%p, %p, %p\n", This, pDestinationVoice, pParameters);
896 static HRESULT WINAPI XA2M_SetVolume(IXAudio2MasteringVoice *iface, float Volume,
897 UINT32 OperationSet)
899 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
900 TRACE("%p, %f, 0x%x\n", This, Volume, OperationSet);
901 return S_OK;
904 static void WINAPI XA2M_GetVolume(IXAudio2MasteringVoice *iface, float *pVolume)
906 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
907 TRACE("%p, %p\n", This, pVolume);
910 static HRESULT WINAPI XA2M_SetChannelVolumes(IXAudio2MasteringVoice *iface, UINT32 Channels,
911 const float *pVolumes, UINT32 OperationSet)
913 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
914 TRACE("%p, %u, %p, 0x%x\n", This, Channels, pVolumes, OperationSet);
915 return S_OK;
918 static void WINAPI XA2M_GetChannelVolumes(IXAudio2MasteringVoice *iface, UINT32 Channels,
919 float *pVolumes)
921 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
922 TRACE("%p, %u, %p\n", This, Channels, pVolumes);
925 static HRESULT WINAPI XA2M_SetOutputMatrix(IXAudio2MasteringVoice *iface,
926 IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
927 UINT32 DestinationChannels, const float *pLevelMatrix,
928 UINT32 OperationSet)
930 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
931 TRACE("%p, %p, %u, %u, %p, 0x%x\n", This, pDestinationVoice,
932 SourceChannels, DestinationChannels, pLevelMatrix, OperationSet);
933 return S_OK;
936 static void WINAPI XA2M_GetOutputMatrix(IXAudio2MasteringVoice *iface,
937 IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
938 UINT32 DestinationChannels, float *pLevelMatrix)
940 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
941 TRACE("%p, %p, %u, %u, %p\n", This, pDestinationVoice,
942 SourceChannels, DestinationChannels, pLevelMatrix);
945 static void WINAPI XA2M_DestroyVoice(IXAudio2MasteringVoice *iface)
947 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
949 TRACE("%p\n", This);
951 EnterCriticalSection(&This->lock);
953 if(!This->aclient){
954 LeaveCriticalSection(&This->lock);
955 return;
958 This->running = FALSE;
960 IAudioRenderClient_Release(This->render);
961 This->render = NULL;
963 IAudioClient_Release(This->aclient);
964 This->aclient = NULL;
966 alcCloseDevice(This->al_device);
967 This->al_device = NULL;
969 alcDestroyContext(This->al_ctx);
970 This->al_ctx = NULL;
972 LeaveCriticalSection(&This->lock);
975 /* not present in XAudio2 2.7 */
976 static void WINAPI XA2M_GetChannelMask(IXAudio2MasteringVoice *iface,
977 DWORD *pChannelMask)
979 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
981 TRACE("%p %p\n", This, pChannelMask);
983 *pChannelMask = This->fmt.dwChannelMask;
986 static const struct IXAudio2MasteringVoiceVtbl XAudio2MasteringVoice_Vtbl = {
987 XA2M_GetVoiceDetails,
988 XA2M_SetOutputVoices,
989 XA2M_SetEffectChain,
990 XA2M_EnableEffect,
991 XA2M_DisableEffect,
992 XA2M_GetEffectState,
993 XA2M_SetEffectParameters,
994 XA2M_GetEffectParameters,
995 XA2M_SetFilterParameters,
996 XA2M_GetFilterParameters,
997 XA2M_SetOutputFilterParameters,
998 XA2M_GetOutputFilterParameters,
999 XA2M_SetVolume,
1000 XA2M_GetVolume,
1001 XA2M_SetChannelVolumes,
1002 XA2M_GetChannelVolumes,
1003 XA2M_SetOutputMatrix,
1004 XA2M_GetOutputMatrix,
1005 XA2M_DestroyVoice,
1006 XA2M_GetChannelMask
1009 static void WINAPI XA2SUB_GetVoiceDetails(IXAudio2SubmixVoice *iface,
1010 XAUDIO2_VOICE_DETAILS *pVoiceDetails)
1012 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1013 TRACE("%p, %p\n", This, pVoiceDetails);
1016 static HRESULT WINAPI XA2SUB_SetOutputVoices(IXAudio2SubmixVoice *iface,
1017 const XAUDIO2_VOICE_SENDS *pSendList)
1019 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1020 TRACE("%p, %p\n", This, pSendList);
1021 return S_OK;
1024 static HRESULT WINAPI XA2SUB_SetEffectChain(IXAudio2SubmixVoice *iface,
1025 const XAUDIO2_EFFECT_CHAIN *pEffectChain)
1027 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1028 TRACE("%p, %p\n", This, pEffectChain);
1029 return S_OK;
1032 static HRESULT WINAPI XA2SUB_EnableEffect(IXAudio2SubmixVoice *iface, UINT32 EffectIndex,
1033 UINT32 OperationSet)
1035 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1036 TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
1037 return S_OK;
1040 static HRESULT WINAPI XA2SUB_DisableEffect(IXAudio2SubmixVoice *iface, UINT32 EffectIndex,
1041 UINT32 OperationSet)
1043 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1044 TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
1045 return S_OK;
1048 static void WINAPI XA2SUB_GetEffectState(IXAudio2SubmixVoice *iface, UINT32 EffectIndex,
1049 BOOL *pEnabled)
1051 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1052 TRACE("%p, %u, %p\n", This, EffectIndex, pEnabled);
1055 static HRESULT WINAPI XA2SUB_SetEffectParameters(IXAudio2SubmixVoice *iface,
1056 UINT32 EffectIndex, const void *pParameters, UINT32 ParametersByteSize,
1057 UINT32 OperationSet)
1059 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1060 TRACE("%p, %u, %p, 0x%x, 0x%x\n", This, EffectIndex, pParameters,
1061 ParametersByteSize, OperationSet);
1062 return S_OK;
1065 static HRESULT WINAPI XA2SUB_GetEffectParameters(IXAudio2SubmixVoice *iface,
1066 UINT32 EffectIndex, void *pParameters, UINT32 ParametersByteSize)
1068 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1069 TRACE("%p, %u, %p, 0x%x\n", This, EffectIndex, pParameters,
1070 ParametersByteSize);
1071 return S_OK;
1074 static HRESULT WINAPI XA2SUB_SetFilterParameters(IXAudio2SubmixVoice *iface,
1075 const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
1077 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1078 TRACE("%p, %p, 0x%x\n", This, pParameters, OperationSet);
1079 return S_OK;
1082 static void WINAPI XA2SUB_GetFilterParameters(IXAudio2SubmixVoice *iface,
1083 XAUDIO2_FILTER_PARAMETERS *pParameters)
1085 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1086 TRACE("%p, %p\n", This, pParameters);
1089 static HRESULT WINAPI XA2SUB_SetOutputFilterParameters(IXAudio2SubmixVoice *iface,
1090 IXAudio2Voice *pDestinationVoice,
1091 const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
1093 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1094 TRACE("%p, %p, %p, 0x%x\n", This, pDestinationVoice, pParameters, OperationSet);
1095 return S_OK;
1098 static void WINAPI XA2SUB_GetOutputFilterParameters(IXAudio2SubmixVoice *iface,
1099 IXAudio2Voice *pDestinationVoice,
1100 XAUDIO2_FILTER_PARAMETERS *pParameters)
1102 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1103 TRACE("%p, %p, %p\n", This, pDestinationVoice, pParameters);
1106 static HRESULT WINAPI XA2SUB_SetVolume(IXAudio2SubmixVoice *iface, float Volume,
1107 UINT32 OperationSet)
1109 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1110 TRACE("%p, %f, 0x%x\n", This, Volume, OperationSet);
1111 return S_OK;
1114 static void WINAPI XA2SUB_GetVolume(IXAudio2SubmixVoice *iface, float *pVolume)
1116 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1117 TRACE("%p, %p\n", This, pVolume);
1120 static HRESULT WINAPI XA2SUB_SetChannelVolumes(IXAudio2SubmixVoice *iface, UINT32 Channels,
1121 const float *pVolumes, UINT32 OperationSet)
1123 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1124 TRACE("%p, %u, %p, 0x%x\n", This, Channels, pVolumes, OperationSet);
1125 return S_OK;
1128 static void WINAPI XA2SUB_GetChannelVolumes(IXAudio2SubmixVoice *iface, UINT32 Channels,
1129 float *pVolumes)
1131 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1132 TRACE("%p, %u, %p\n", This, Channels, pVolumes);
1135 static HRESULT WINAPI XA2SUB_SetOutputMatrix(IXAudio2SubmixVoice *iface,
1136 IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
1137 UINT32 DestinationChannels, const float *pLevelMatrix,
1138 UINT32 OperationSet)
1140 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1141 TRACE("%p, %p, %u, %u, %p, 0x%x\n", This, pDestinationVoice,
1142 SourceChannels, DestinationChannels, pLevelMatrix, OperationSet);
1143 return S_OK;
1146 static void WINAPI XA2SUB_GetOutputMatrix(IXAudio2SubmixVoice *iface,
1147 IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
1148 UINT32 DestinationChannels, float *pLevelMatrix)
1150 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1151 TRACE("%p, %p, %u, %u, %p\n", This, pDestinationVoice,
1152 SourceChannels, DestinationChannels, pLevelMatrix);
1155 static void WINAPI XA2SUB_DestroyVoice(IXAudio2SubmixVoice *iface)
1157 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1159 TRACE("%p\n", This);
1161 EnterCriticalSection(&This->lock);
1163 This->in_use = FALSE;
1165 LeaveCriticalSection(&This->lock);
1168 static const struct IXAudio2SubmixVoiceVtbl XAudio2SubmixVoice_Vtbl = {
1169 XA2SUB_GetVoiceDetails,
1170 XA2SUB_SetOutputVoices,
1171 XA2SUB_SetEffectChain,
1172 XA2SUB_EnableEffect,
1173 XA2SUB_DisableEffect,
1174 XA2SUB_GetEffectState,
1175 XA2SUB_SetEffectParameters,
1176 XA2SUB_GetEffectParameters,
1177 XA2SUB_SetFilterParameters,
1178 XA2SUB_GetFilterParameters,
1179 XA2SUB_SetOutputFilterParameters,
1180 XA2SUB_GetOutputFilterParameters,
1181 XA2SUB_SetVolume,
1182 XA2SUB_GetVolume,
1183 XA2SUB_SetChannelVolumes,
1184 XA2SUB_GetChannelVolumes,
1185 XA2SUB_SetOutputMatrix,
1186 XA2SUB_GetOutputMatrix,
1187 XA2SUB_DestroyVoice
1190 static HRESULT WINAPI IXAudio2Impl_QueryInterface(IXAudio2 *iface, REFIID riid,
1191 void **ppvObject)
1193 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1195 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
1197 if(IsEqualGUID(riid, &IID_IUnknown) ||
1198 IsEqualGUID(riid, &IID_IXAudio28) ||
1199 IsEqualGUID(riid, &IID_IXAudio2))
1200 *ppvObject = &This->IXAudio2_iface;
1201 else if(IsEqualGUID(riid, &IID_IXAudio27)){
1202 /* all xaudio versions before 28 share an IID */
1203 #if XAUDIO2_VER == 0
1204 *ppvObject = &This->IXAudio20_iface;
1205 #elif XAUDIO2_VER <= 2
1206 *ppvObject = &This->IXAudio22_iface;
1207 #elif XAUDIO2_VER <= 7
1208 *ppvObject = &This->IXAudio27_iface;
1209 #else
1210 *ppvObject = NULL;
1211 #endif
1212 }else
1213 *ppvObject = NULL;
1215 if(*ppvObject){
1216 IUnknown_AddRef((IUnknown*)*ppvObject);
1217 return S_OK;
1220 FIXME("(%p)->(%s,%p), not found\n", This,debugstr_guid(riid), ppvObject);
1222 return E_NOINTERFACE;
1225 static ULONG WINAPI IXAudio2Impl_AddRef(IXAudio2 *iface)
1227 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1228 ULONG ref = InterlockedIncrement(&This->ref);
1229 TRACE("(%p)->(): Refcount now %u\n", This, ref);
1230 return ref;
1233 static ULONG WINAPI IXAudio2Impl_Release(IXAudio2 *iface)
1235 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1236 ULONG ref = InterlockedDecrement(&This->ref);
1238 TRACE("(%p)->(): Refcount now %u\n", This, ref);
1240 if (!ref) {
1241 int i;
1242 XA2SourceImpl *src, *src2;
1243 XA2SubmixImpl *sub, *sub2;
1245 if(This->engine){
1246 This->stop_engine = TRUE;
1247 SetEvent(This->mmevt);
1248 WaitForSingleObject(This->engine, INFINITE);
1249 CloseHandle(This->engine);
1252 LIST_FOR_EACH_ENTRY_SAFE(src, src2, &This->source_voices, XA2SourceImpl, entry){
1253 HeapFree(GetProcessHeap(), 0, src->sends);
1254 IXAudio2SourceVoice_DestroyVoice(&src->IXAudio2SourceVoice_iface);
1255 src->lock.DebugInfo->Spare[0] = 0;
1256 DeleteCriticalSection(&src->lock);
1257 HeapFree(GetProcessHeap(), 0, src);
1260 LIST_FOR_EACH_ENTRY_SAFE(sub, sub2, &This->submix_voices, XA2SubmixImpl, entry){
1261 IXAudio2SubmixVoice_DestroyVoice(&sub->IXAudio2SubmixVoice_iface);
1262 sub->lock.DebugInfo->Spare[0] = 0;
1263 DeleteCriticalSection(&sub->lock);
1264 HeapFree(GetProcessHeap(), 0, sub);
1267 IXAudio2MasteringVoice_DestroyVoice(&This->IXAudio2MasteringVoice_iface);
1269 if(This->devenum)
1270 IMMDeviceEnumerator_Release(This->devenum);
1271 for(i = 0; i < This->ndevs; ++i)
1272 CoTaskMemFree(This->devids[i]);
1273 HeapFree(GetProcessHeap(), 0, This->devids);
1274 HeapFree(GetProcessHeap(), 0, This->cbs);
1276 CloseHandle(This->mmevt);
1278 This->lock.DebugInfo->Spare[0] = 0;
1279 DeleteCriticalSection(&This->lock);
1281 HeapFree(GetProcessHeap(), 0, This);
1283 return ref;
1286 static HRESULT WINAPI IXAudio2Impl_RegisterForCallbacks(IXAudio2 *iface,
1287 IXAudio2EngineCallback *pCallback)
1289 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1290 int i;
1292 TRACE("(%p)->(%p)\n", This, pCallback);
1294 EnterCriticalSection(&This->lock);
1296 for(i = 0; i < This->ncbs; ++i){
1297 if(!This->cbs[i] || This->cbs[i] == pCallback){
1298 This->cbs[i] = pCallback;
1299 LeaveCriticalSection(&This->lock);
1300 return S_OK;
1304 This->ncbs *= 2;
1305 This->cbs = HeapReAlloc(GetProcessHeap(), 0, This->cbs, This->ncbs * sizeof(*This->cbs));
1307 This->cbs[i] = pCallback;
1309 LeaveCriticalSection(&This->lock);
1311 return S_OK;
1314 static void WINAPI IXAudio2Impl_UnregisterForCallbacks(IXAudio2 *iface,
1315 IXAudio2EngineCallback *pCallback)
1317 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1318 int i;
1320 TRACE("(%p)->(%p)\n", This, pCallback);
1322 EnterCriticalSection(&This->lock);
1324 for(i = 0; i < This->ncbs; ++i){
1325 if(This->cbs[i] == pCallback)
1326 break;
1329 for(; i < This->ncbs - 1 && This->cbs[i + 1]; ++i)
1330 This->cbs[i] = This->cbs[i + 1];
1332 if(i < This->ncbs)
1333 This->cbs[i] = NULL;
1335 LeaveCriticalSection(&This->lock);
1338 static WAVEFORMATEX *copy_waveformat(const WAVEFORMATEX *wfex)
1340 WAVEFORMATEX *pwfx;
1342 if(wfex->wFormatTag == WAVE_FORMAT_PCM){
1343 pwfx = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEX));
1344 CopyMemory(pwfx, wfex, sizeof(PCMWAVEFORMAT));
1345 pwfx->cbSize = 0;
1346 }else{
1347 pwfx = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEX) + wfex->cbSize);
1348 CopyMemory(pwfx, wfex, sizeof(WAVEFORMATEX) + wfex->cbSize);
1351 return pwfx;
1354 static HRESULT WINAPI IXAudio2Impl_CreateSourceVoice(IXAudio2 *iface,
1355 IXAudio2SourceVoice **ppSourceVoice, const WAVEFORMATEX *pSourceFormat,
1356 UINT32 flags, float maxFrequencyRatio,
1357 IXAudio2VoiceCallback *pCallback, const XAUDIO2_VOICE_SENDS *pSendList,
1358 const XAUDIO2_EFFECT_CHAIN *pEffectChain)
1360 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1361 XA2SourceImpl *src;
1362 HRESULT hr;
1364 TRACE("(%p)->(%p, %p, 0x%x, %f, %p, %p, %p)\n", This, ppSourceVoice,
1365 pSourceFormat, flags, maxFrequencyRatio, pCallback, pSendList,
1366 pEffectChain);
1368 dump_fmt(pSourceFormat);
1370 EnterCriticalSection(&This->lock);
1372 LIST_FOR_EACH_ENTRY(src, &This->source_voices, XA2SourceImpl, entry){
1373 EnterCriticalSection(&src->lock);
1374 if(!src->in_use)
1375 break;
1376 LeaveCriticalSection(&src->lock);
1379 if(&src->entry == &This->source_voices){
1380 src = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*src));
1381 if(!src){
1382 LeaveCriticalSection(&This->lock);
1383 return E_OUTOFMEMORY;
1386 list_add_head(&This->source_voices, &src->entry);
1388 src->IXAudio2SourceVoice_iface.lpVtbl = &XAudio2SourceVoice_Vtbl;
1390 #if XAUDIO2_VER == 0
1391 src->IXAudio20SourceVoice_iface.lpVtbl = &XAudio20SourceVoice_Vtbl;
1392 #elif XAUDIO2_VER <= 3
1393 src->IXAudio23SourceVoice_iface.lpVtbl = &XAudio23SourceVoice_Vtbl;
1394 #elif XAUDIO2_VER <= 7
1395 src->IXAudio27SourceVoice_iface.lpVtbl = &XAudio27SourceVoice_Vtbl;
1396 #endif
1398 InitializeCriticalSection(&src->lock);
1399 src->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": XA2SourceImpl.lock");
1401 src->xa2 = This;
1403 EnterCriticalSection(&src->lock);
1406 src->in_use = TRUE;
1407 src->running = FALSE;
1409 LeaveCriticalSection(&This->lock);
1411 src->cb = pCallback;
1413 src->al_fmt = get_al_format(pSourceFormat);
1414 if(!src->al_fmt){
1415 src->in_use = FALSE;
1416 LeaveCriticalSection(&src->lock);
1417 WARN("OpenAL can't convert this format!\n");
1418 return AUDCLNT_E_UNSUPPORTED_FORMAT;
1421 src->submit_blocksize = pSourceFormat->nBlockAlign;
1423 src->fmt = copy_waveformat(pSourceFormat);
1425 hr = XA2SRC_SetOutputVoices(&src->IXAudio2SourceVoice_iface, pSendList);
1426 if(FAILED(hr)){
1427 HeapFree(GetProcessHeap(), 0, src->fmt);
1428 src->in_use = FALSE;
1429 LeaveCriticalSection(&src->lock);
1430 return hr;
1433 alGenSources(1, &src->al_src);
1434 if(!src->al_src){
1435 static int once = 0;
1436 if(!once++)
1437 ERR_(winediag)("OpenAL ran out of sources, consider increasing its source limit.\n");
1438 HeapFree(GetProcessHeap(), 0, src->fmt);
1439 src->in_use = FALSE;
1440 LeaveCriticalSection(&src->lock);
1441 return E_OUTOFMEMORY;
1444 alGenBuffers(XAUDIO2_MAX_QUEUED_BUFFERS, src->al_bufs);
1446 alSourcePlay(src->al_src);
1448 LeaveCriticalSection(&src->lock);
1450 #if XAUDIO2_VER == 0
1451 *ppSourceVoice = (IXAudio2SourceVoice*)&src->IXAudio20SourceVoice_iface;
1452 #elif XAUDIO2_VER <= 3
1453 *ppSourceVoice = (IXAudio2SourceVoice*)&src->IXAudio23SourceVoice_iface;
1454 #elif XAUDIO2_VER <= 7
1455 *ppSourceVoice = (IXAudio2SourceVoice*)&src->IXAudio27SourceVoice_iface;
1456 #else
1457 *ppSourceVoice = &src->IXAudio2SourceVoice_iface;
1458 #endif
1460 TRACE("Created source voice: %p\n", src);
1462 return S_OK;
1465 static HRESULT WINAPI IXAudio2Impl_CreateSubmixVoice(IXAudio2 *iface,
1466 IXAudio2SubmixVoice **ppSubmixVoice, UINT32 inputChannels,
1467 UINT32 inputSampleRate, UINT32 flags, UINT32 processingStage,
1468 const XAUDIO2_VOICE_SENDS *pSendList,
1469 const XAUDIO2_EFFECT_CHAIN *pEffectChain)
1471 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1472 XA2SubmixImpl *sub;
1474 TRACE("(%p)->(%p, %u, %u, 0x%x, %u, %p, %p)\n", This, ppSubmixVoice,
1475 inputChannels, inputSampleRate, flags, processingStage, pSendList,
1476 pEffectChain);
1478 EnterCriticalSection(&This->lock);
1480 LIST_FOR_EACH_ENTRY(sub, &This->submix_voices, XA2SubmixImpl, entry){
1481 EnterCriticalSection(&sub->lock);
1482 if(!sub->in_use)
1483 break;
1484 LeaveCriticalSection(&sub->lock);
1487 if(&sub->entry == &This->submix_voices){
1488 sub = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*sub));
1489 if(!sub){
1490 LeaveCriticalSection(&This->lock);
1491 return E_OUTOFMEMORY;
1494 list_add_head(&This->submix_voices, &sub->entry);
1496 sub->IXAudio2SubmixVoice_iface.lpVtbl = &XAudio2SubmixVoice_Vtbl;
1498 #if XAUDIO2_VER == 0
1499 sub->IXAudio20SubmixVoice_iface.lpVtbl = &XAudio20SubmixVoice_Vtbl;
1500 #elif XAUDIO2_VER <= 3
1501 sub->IXAudio23SubmixVoice_iface.lpVtbl = &XAudio23SubmixVoice_Vtbl;
1502 #endif
1504 InitializeCriticalSection(&sub->lock);
1505 sub->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": XA2SubmixImpl.lock");
1507 EnterCriticalSection(&sub->lock);
1510 sub->in_use = TRUE;
1512 LeaveCriticalSection(&This->lock);
1513 LeaveCriticalSection(&sub->lock);
1515 #if XAUDIO2_VER == 0
1516 *ppSubmixVoice = (IXAudio2SubmixVoice*)&sub->IXAudio20SubmixVoice_iface;
1517 #elif XAUDIO2_VER <= 3
1518 *ppSubmixVoice = (IXAudio2SubmixVoice*)&sub->IXAudio23SubmixVoice_iface;
1519 #else
1520 *ppSubmixVoice = &sub->IXAudio2SubmixVoice_iface;
1521 #endif
1523 TRACE("Created submix voice: %p\n", sub);
1525 return S_OK;
1528 static ALenum al_get_loopback_format(const WAVEFORMATEXTENSIBLE *fmt)
1530 if(fmt->Format.wFormatTag == WAVE_FORMAT_PCM ||
1531 (fmt->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1532 IsEqualGUID(&fmt->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
1533 switch(fmt->Format.wBitsPerSample){
1534 case 8:
1535 return ALC_UNSIGNED_BYTE_SOFT;
1536 case 16:
1537 return ALC_SHORT_SOFT;
1538 case 32:
1539 return ALC_INT_SOFT;
1541 }else if(fmt->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
1542 (fmt->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1543 IsEqualGUID(&fmt->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
1544 if(fmt->Format.wBitsPerSample == 32)
1545 return ALC_FLOAT_SOFT;
1547 return 0;
1550 static HRESULT WINAPI IXAudio2Impl_CreateMasteringVoice(IXAudio2 *iface,
1551 IXAudio2MasteringVoice **ppMasteringVoice, UINT32 inputChannels,
1552 UINT32 inputSampleRate, UINT32 flags, const WCHAR *deviceId,
1553 const XAUDIO2_EFFECT_CHAIN *pEffectChain,
1554 AUDIO_STREAM_CATEGORY streamCategory)
1556 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1557 IMMDevice *dev;
1558 HRESULT hr;
1559 WAVEFORMATEX *fmt;
1560 ALCint attrs[7];
1561 REFERENCE_TIME period, bufdur;
1563 TRACE("(%p)->(%p, %u, %u, 0x%x, %s, %p, 0x%x)\n", This,
1564 ppMasteringVoice, inputChannels, inputSampleRate, flags,
1565 wine_dbgstr_w(deviceId), pEffectChain, streamCategory);
1567 if(flags != 0)
1568 WARN("Unknown flags set: 0x%x\n", flags);
1570 if(pEffectChain)
1571 WARN("Effect chain is unimplemented\n");
1573 EnterCriticalSection(&This->lock);
1575 /* there can only be one Mastering Voice, so just build it into XA2 */
1576 if(This->aclient){
1577 LeaveCriticalSection(&This->lock);
1578 return COMPAT_E_INVALID_CALL;
1581 if(!deviceId){
1582 if(This->ndevs == 0){
1583 LeaveCriticalSection(&This->lock);
1584 return E_NOTFOUND;
1586 deviceId = This->devids[0];
1589 hr = IMMDeviceEnumerator_GetDevice(This->devenum, deviceId, &dev);
1590 if(FAILED(hr)){
1591 WARN("GetDevice failed: %08x\n", hr);
1592 hr = COMPAT_E_DEVICE_INVALIDATED;
1593 goto exit;
1596 hr = IMMDevice_Activate(dev, &IID_IAudioClient,
1597 CLSCTX_INPROC_SERVER, NULL, (void**)&This->aclient);
1598 if(FAILED(hr)){
1599 WARN("Activate(IAudioClient) failed: %08x\n", hr);
1600 IMMDevice_Release(dev);
1601 hr = COMPAT_E_DEVICE_INVALIDATED;
1602 goto exit;
1605 IMMDevice_Release(dev);
1607 hr = IAudioClient_GetMixFormat(This->aclient, &fmt);
1608 if(FAILED(hr)){
1609 WARN("GetMixFormat failed: %08x\n", hr);
1610 hr = COMPAT_E_DEVICE_INVALIDATED;
1611 goto exit;
1614 if(sizeof(WAVEFORMATEX) + fmt->cbSize > sizeof(WAVEFORMATEXTENSIBLE)){
1615 FIXME("Mix format doesn't fit into WAVEFORMATEXTENSIBLE!\n");
1616 hr = COMPAT_E_DEVICE_INVALIDATED;
1617 goto exit;
1620 if(inputChannels == XAUDIO2_DEFAULT_CHANNELS)
1621 inputChannels = fmt->nChannels;
1622 if(inputSampleRate == XAUDIO2_DEFAULT_SAMPLERATE)
1623 inputSampleRate = fmt->nSamplesPerSec;
1625 memcpy(&This->fmt, fmt, sizeof(WAVEFORMATEX) + fmt->cbSize);
1626 This->fmt.Format.nChannels = inputChannels;
1627 This->fmt.Format.nSamplesPerSec = inputSampleRate;
1628 This->fmt.Format.nBlockAlign = This->fmt.Format.nChannels * This->fmt.Format.wBitsPerSample / 8;
1629 This->fmt.Format.nAvgBytesPerSec = This->fmt.Format.nSamplesPerSec * This->fmt.Format.nBlockAlign;
1630 This->fmt.dwChannelMask = get_channel_mask(This->fmt.Format.nChannels);
1632 CoTaskMemFree(fmt);
1633 fmt = NULL;
1635 hr = IAudioClient_IsFormatSupported(This->aclient,
1636 AUDCLNT_SHAREMODE_SHARED, &This->fmt.Format, &fmt);
1637 if(hr == S_FALSE){
1638 if(sizeof(WAVEFORMATEX) + fmt->cbSize > sizeof(WAVEFORMATEXTENSIBLE)){
1639 FIXME("Mix format doesn't fit into WAVEFORMATEXTENSIBLE!\n");
1640 hr = COMPAT_E_DEVICE_INVALIDATED;
1641 goto exit;
1643 memcpy(&This->fmt, fmt, sizeof(WAVEFORMATEX) + fmt->cbSize);
1646 CoTaskMemFree(fmt);
1648 hr = IAudioClient_GetDevicePeriod(This->aclient, &period, NULL);
1649 if(FAILED(hr)){
1650 WARN("GetDevicePeriod failed: %08x\n", hr);
1651 hr = COMPAT_E_DEVICE_INVALIDATED;
1652 goto exit;
1655 /* 3 periods or 0.1 seconds */
1656 bufdur = max(3 * period, 1000000);
1658 hr = IAudioClient_Initialize(This->aclient, AUDCLNT_SHAREMODE_SHARED,
1659 AUDCLNT_STREAMFLAGS_EVENTCALLBACK, bufdur,
1660 0, &This->fmt.Format, NULL);
1661 if(FAILED(hr)){
1662 WARN("Initialize failed: %08x\n", hr);
1663 hr = COMPAT_E_DEVICE_INVALIDATED;
1664 goto exit;
1667 This->period_frames = MulDiv(period, inputSampleRate, 10000000);
1669 hr = IAudioClient_SetEventHandle(This->aclient, This->mmevt);
1670 if(FAILED(hr)){
1671 WARN("Initialize failed: %08x\n", hr);
1672 hr = COMPAT_E_DEVICE_INVALIDATED;
1673 goto exit;
1676 hr = IAudioClient_GetService(This->aclient, &IID_IAudioRenderClient,
1677 (void**)&This->render);
1678 if(FAILED(hr)){
1679 WARN("GetService(IAudioRenderClient) failed: %08x\n", hr);
1680 hr = COMPAT_E_DEVICE_INVALIDATED;
1681 goto exit;
1684 /* setup openal context */
1685 attrs[0] = ALC_FORMAT_CHANNELS_SOFT;
1686 switch(inputChannels){
1687 case 1:
1688 attrs[1] = ALC_MONO_SOFT;
1689 break;
1690 case 2:
1691 attrs[1] = ALC_STEREO_SOFT;
1692 break;
1693 case 4:
1694 attrs[1] = ALC_QUAD_SOFT;
1695 break;
1696 case 6:
1697 attrs[1] = ALC_5POINT1_SOFT;
1698 break;
1699 case 7:
1700 attrs[1] = ALC_6POINT1_SOFT;
1701 break;
1702 case 8:
1703 attrs[1] = ALC_7POINT1_SOFT;
1704 break;
1705 default:
1706 WARN("OpenAL doesn't support %u channels\n", inputChannels);
1707 LeaveCriticalSection(&This->lock);
1708 return AUDCLNT_E_UNSUPPORTED_FORMAT;
1710 attrs[2] = ALC_FREQUENCY;
1711 attrs[3] = inputSampleRate;
1712 attrs[4] = ALC_FORMAT_TYPE_SOFT;
1713 attrs[5] = al_get_loopback_format(&This->fmt);
1714 attrs[6] = 0;
1716 if(!attrs[5]){
1717 WARN("OpenAL can't output samples in this format\n");
1718 hr = COMPAT_E_DEVICE_INVALIDATED;
1719 goto exit;
1722 This->al_device = palcLoopbackOpenDeviceSOFT(NULL);
1723 if(!This->al_device){
1724 WARN("alcLoopbackOpenDeviceSOFT failed\n");
1725 hr = COMPAT_E_DEVICE_INVALIDATED;
1726 goto exit;
1729 This->al_ctx = alcCreateContext(This->al_device, attrs);
1730 if(!This->al_ctx){
1731 WARN("alcCreateContext failed\n");
1732 hr = COMPAT_E_DEVICE_INVALIDATED;
1733 goto exit;
1736 if(alcMakeContextCurrent(This->al_ctx) == ALC_FALSE){
1737 WARN("alcMakeContextCurrent failed\n");
1738 hr = COMPAT_E_DEVICE_INVALIDATED;
1739 goto exit;
1742 hr = IAudioClient_Start(This->aclient);
1743 if (FAILED(hr))
1745 WARN("Start(IAudioClient) failed: %08x\n", hr);
1746 hr = COMPAT_E_DEVICE_INVALIDATED;
1747 goto exit;
1750 #if XAUDIO2_VER == 0
1751 *ppMasteringVoice = (IXAudio2MasteringVoice*)&This->IXAudio20MasteringVoice_iface;
1752 #elif XAUDIO2_VER <= 3
1753 *ppMasteringVoice = (IXAudio2MasteringVoice*)&This->IXAudio23MasteringVoice_iface;
1754 #else
1755 *ppMasteringVoice = &This->IXAudio2MasteringVoice_iface;
1756 #endif
1758 exit:
1759 if(FAILED(hr)){
1760 if(This->render){
1761 IAudioRenderClient_Release(This->render);
1762 This->render = NULL;
1764 if(This->aclient){
1765 IAudioClient_Release(This->aclient);
1766 This->aclient = NULL;
1768 if(This->al_ctx){
1769 alcDestroyContext(This->al_ctx);
1770 This->al_ctx = NULL;
1772 if(This->al_device){
1773 alcCloseDevice(This->al_device);
1774 This->al_device = NULL;
1778 LeaveCriticalSection(&This->lock);
1780 return hr;
1783 static DWORD WINAPI engine_threadproc(void *arg);
1785 static HRESULT WINAPI IXAudio2Impl_StartEngine(IXAudio2 *iface)
1787 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1789 TRACE("(%p)->()\n", This);
1791 This->running = TRUE;
1793 if(!This->engine)
1794 This->engine = CreateThread(NULL, 0, engine_threadproc, This, 0, NULL);
1796 return S_OK;
1799 static void WINAPI IXAudio2Impl_StopEngine(IXAudio2 *iface)
1801 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1803 TRACE("(%p)->()\n", This);
1805 This->running = FALSE;
1808 static HRESULT WINAPI IXAudio2Impl_CommitChanges(IXAudio2 *iface,
1809 UINT32 operationSet)
1811 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1813 TRACE("(%p)->(0x%x): stub!\n", This, operationSet);
1815 return E_NOTIMPL;
1818 static void WINAPI IXAudio2Impl_GetPerformanceData(IXAudio2 *iface,
1819 XAUDIO2_PERFORMANCE_DATA *pPerfData)
1821 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1823 TRACE("(%p)->(%p): stub!\n", This, pPerfData);
1825 memset(pPerfData, 0, sizeof(*pPerfData));
1828 static void WINAPI IXAudio2Impl_SetDebugConfiguration(IXAudio2 *iface,
1829 const XAUDIO2_DEBUG_CONFIGURATION *pDebugConfiguration,
1830 void *pReserved)
1832 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1834 FIXME("(%p)->(%p, %p): stub!\n", This, pDebugConfiguration, pReserved);
1837 /* XAudio2 2.8 */
1838 static const IXAudio2Vtbl XAudio2_Vtbl =
1840 IXAudio2Impl_QueryInterface,
1841 IXAudio2Impl_AddRef,
1842 IXAudio2Impl_Release,
1843 IXAudio2Impl_RegisterForCallbacks,
1844 IXAudio2Impl_UnregisterForCallbacks,
1845 IXAudio2Impl_CreateSourceVoice,
1846 IXAudio2Impl_CreateSubmixVoice,
1847 IXAudio2Impl_CreateMasteringVoice,
1848 IXAudio2Impl_StartEngine,
1849 IXAudio2Impl_StopEngine,
1850 IXAudio2Impl_CommitChanges,
1851 IXAudio2Impl_GetPerformanceData,
1852 IXAudio2Impl_SetDebugConfiguration
1855 struct xaudio2_cf {
1856 IClassFactory IClassFactory_iface;
1857 LONG ref;
1860 static struct xaudio2_cf *impl_from_IClassFactory(IClassFactory *iface)
1862 return CONTAINING_RECORD(iface, struct xaudio2_cf, IClassFactory_iface);
1865 static HRESULT WINAPI XAudio2CF_QueryInterface(IClassFactory *iface, REFIID riid, void **ppobj)
1867 if(IsEqualGUID(riid, &IID_IUnknown)
1868 || IsEqualGUID(riid, &IID_IClassFactory))
1870 IClassFactory_AddRef(iface);
1871 *ppobj = iface;
1872 return S_OK;
1875 *ppobj = NULL;
1876 WARN("(%p)->(%s, %p): interface not found\n", iface, debugstr_guid(riid), ppobj);
1877 return E_NOINTERFACE;
1880 static ULONG WINAPI XAudio2CF_AddRef(IClassFactory *iface)
1882 struct xaudio2_cf *This = impl_from_IClassFactory(iface);
1883 ULONG ref = InterlockedIncrement(&This->ref);
1884 TRACE("(%p)->(): Refcount now %u\n", This, ref);
1885 return ref;
1888 static ULONG WINAPI XAudio2CF_Release(IClassFactory *iface)
1890 struct xaudio2_cf *This = impl_from_IClassFactory(iface);
1891 ULONG ref = InterlockedDecrement(&This->ref);
1892 TRACE("(%p)->(): Refcount now %u\n", This, ref);
1893 if (!ref)
1894 HeapFree(GetProcessHeap(), 0, This);
1895 return ref;
1898 static HRESULT initialize_mmdevices(IXAudio2Impl *This)
1900 IMMDeviceCollection *devcoll;
1901 UINT devcount;
1902 HRESULT hr;
1904 if(!This->devenum){
1905 hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL,
1906 CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void**)&This->devenum);
1907 if(FAILED(hr))
1908 return hr;
1911 hr = IMMDeviceEnumerator_EnumAudioEndpoints(This->devenum, eRender,
1912 DEVICE_STATE_ACTIVE, &devcoll);
1913 if(FAILED(hr)){
1914 return hr;
1917 hr = IMMDeviceCollection_GetCount(devcoll, &devcount);
1918 if(FAILED(hr)){
1919 IMMDeviceCollection_Release(devcoll);
1920 return hr;
1923 if(devcount > 0){
1924 UINT i, count = 1;
1925 IMMDevice *dev, *def_dev;
1927 /* make sure that device 0 is the default device */
1928 IMMDeviceEnumerator_GetDefaultAudioEndpoint(This->devenum, eRender, eConsole, &def_dev);
1930 This->devids = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *) * devcount);
1932 for(i = 0; i < devcount; ++i){
1933 hr = IMMDeviceCollection_Item(devcoll, i, &dev);
1934 if(SUCCEEDED(hr)){
1935 UINT idx;
1937 if(dev == def_dev)
1938 idx = 0;
1939 else{
1940 idx = count;
1941 ++count;
1944 hr = IMMDevice_GetId(dev, &This->devids[idx]);
1945 if(FAILED(hr)){
1946 WARN("GetId failed: %08x\n", hr);
1947 HeapFree(GetProcessHeap(), 0, This->devids);
1948 This->devids = NULL;
1949 IMMDevice_Release(dev);
1950 return hr;
1953 IMMDevice_Release(dev);
1954 }else{
1955 WARN("Item failed: %08x\n", hr);
1956 HeapFree(GetProcessHeap(), 0, This->devids);
1957 This->devids = NULL;
1958 IMMDeviceCollection_Release(devcoll);
1959 return hr;
1964 IMMDeviceCollection_Release(devcoll);
1966 This->ndevs = devcount;
1968 return S_OK;
1971 static HRESULT WINAPI XAudio2CF_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
1972 REFIID riid, void **ppobj)
1974 struct xaudio2_cf *This = impl_from_IClassFactory(iface);
1975 HRESULT hr;
1976 IXAudio2Impl *object;
1978 TRACE("(%p)->(%p,%s,%p)\n", This, pOuter, debugstr_guid(riid), ppobj);
1980 *ppobj = NULL;
1982 if(pOuter)
1983 return CLASS_E_NOAGGREGATION;
1985 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1986 if(!object)
1987 return E_OUTOFMEMORY;
1989 object->IXAudio2_iface.lpVtbl = &XAudio2_Vtbl;
1990 object->IXAudio2MasteringVoice_iface.lpVtbl = &XAudio2MasteringVoice_Vtbl;
1992 #if XAUDIO2_VER == 0
1993 object->IXAudio20_iface.lpVtbl = &XAudio20_Vtbl;
1994 #elif XAUDIO2_VER <= 2
1995 object->IXAudio22_iface.lpVtbl = &XAudio22_Vtbl;
1996 #elif XAUDIO2_VER <= 7
1997 object->IXAudio27_iface.lpVtbl = &XAudio27_Vtbl;
1998 #endif
2000 #if XAUDIO2_VER == 0
2001 object->IXAudio20MasteringVoice_iface.lpVtbl = &XAudio20MasteringVoice_Vtbl;
2002 #elif XAUDIO2_VER <= 3
2003 object->IXAudio23MasteringVoice_iface.lpVtbl = &XAudio23MasteringVoice_Vtbl;
2004 #endif
2006 list_init(&object->source_voices);
2007 list_init(&object->submix_voices);
2009 object->mmevt = CreateEventW(NULL, FALSE, FALSE, NULL);
2010 InitializeCriticalSection(&object->lock);
2011 object->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IXAudio2Impl.lock");
2013 hr = IXAudio2_QueryInterface(&object->IXAudio2_iface, riid, ppobj);
2014 if(FAILED(hr)){
2015 HeapFree(GetProcessHeap(), 0, object);
2016 return hr;
2019 hr = initialize_mmdevices(object);
2020 if(FAILED(hr)){
2021 IUnknown_Release((IUnknown*)*ppobj);
2022 return hr;
2025 object->ncbs = 4;
2026 object->cbs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->ncbs * sizeof(*object->cbs));
2028 IXAudio2_StartEngine(&object->IXAudio2_iface);
2030 TRACE("Created XAudio version %u: %p\n", 20 + XAUDIO2_VER, object);
2032 return hr;
2035 static HRESULT WINAPI XAudio2CF_LockServer(IClassFactory *iface, BOOL dolock)
2037 FIXME("(static)->(%d): stub!\n", dolock);
2038 return S_OK;
2041 static const IClassFactoryVtbl XAudio2CF_Vtbl =
2043 XAudio2CF_QueryInterface,
2044 XAudio2CF_AddRef,
2045 XAudio2CF_Release,
2046 XAudio2CF_CreateInstance,
2047 XAudio2CF_LockServer
2050 static IClassFactory *make_xaudio2_factory(void)
2052 struct xaudio2_cf *ret = HeapAlloc(GetProcessHeap(), 0, sizeof(struct xaudio2_cf));
2053 ret->IClassFactory_iface.lpVtbl = &XAudio2CF_Vtbl;
2054 ret->ref = 0;
2055 return &ret->IClassFactory_iface;
2058 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
2060 IClassFactory *factory = NULL;
2062 TRACE("(%s, %s, %p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
2064 if(IsEqualGUID(rclsid, &CLSID_XAudio20) ||
2065 IsEqualGUID(rclsid, &CLSID_XAudio21) ||
2066 IsEqualGUID(rclsid, &CLSID_XAudio22) ||
2067 IsEqualGUID(rclsid, &CLSID_XAudio23) ||
2068 IsEqualGUID(rclsid, &CLSID_XAudio24) ||
2069 IsEqualGUID(rclsid, &CLSID_XAudio25) ||
2070 IsEqualGUID(rclsid, &CLSID_XAudio26) ||
2071 IsEqualGUID(rclsid, &CLSID_XAudio27)){
2072 factory = make_xaudio2_factory();
2074 }else if(IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter20) ||
2075 IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter21) ||
2076 IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter22) ||
2077 IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter23) ||
2078 IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter24) ||
2079 IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter25) ||
2080 IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter26) ||
2081 IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter27)){
2082 factory = make_xapo_factory(&CLSID_AudioVolumeMeter27);
2084 }else if(IsEqualGUID(rclsid, &CLSID_AudioReverb20) ||
2085 IsEqualGUID(rclsid, &CLSID_AudioReverb21) ||
2086 IsEqualGUID(rclsid, &CLSID_AudioReverb22) ||
2087 IsEqualGUID(rclsid, &CLSID_AudioReverb23) ||
2088 IsEqualGUID(rclsid, &CLSID_AudioReverb24) ||
2089 IsEqualGUID(rclsid, &CLSID_AudioReverb25) ||
2090 IsEqualGUID(rclsid, &CLSID_AudioReverb26) ||
2091 IsEqualGUID(rclsid, &CLSID_AudioReverb27)){
2092 factory = make_xapo_factory(&CLSID_FXReverb);
2095 if(!factory) return CLASS_E_CLASSNOTAVAILABLE;
2097 return IClassFactory_QueryInterface(factory, riid, ppv);
2100 HRESULT xaudio2_initialize(IXAudio2Impl *This, UINT32 flags, XAUDIO2_PROCESSOR proc)
2102 if(flags)
2103 FIXME("Unimplemented flags: 0x%x\n", flags);
2104 return S_OK;
2107 #if XAUDIO2_VER >= 8
2108 HRESULT WINAPI XAudio2Create(IXAudio2 **ppxa2, UINT32 flags, XAUDIO2_PROCESSOR proc)
2110 HRESULT hr;
2111 IXAudio2 *xa2;
2112 IClassFactory *cf;
2114 TRACE("%p 0x%x 0x%x\n", ppxa2, flags, proc);
2116 cf = make_xaudio2_factory();
2118 hr = IClassFactory_CreateInstance(cf, NULL, &IID_IXAudio2, (void**)&xa2);
2119 IClassFactory_Release(cf);
2120 if(FAILED(hr))
2121 return hr;
2123 hr = xaudio2_initialize(impl_from_IXAudio2(xa2), flags, proc);
2124 if(FAILED(hr)){
2125 IXAudio2_Release(xa2);
2126 return hr;
2129 *ppxa2 = xa2;
2131 return S_OK;
2133 #endif /* XAUDIO2_VER >= 8 */
2135 /* returns TRUE if there is more data available in the buffer, FALSE if the
2136 * buffer's data has all been queued */
2137 static BOOL xa2buffer_queue_period(XA2SourceImpl *src, XA2Buffer *buf, ALuint al_buf)
2139 UINT32 submit_bytes;
2140 const BYTE *submit_buf = NULL;
2142 if(buf->offs_bytes >= buf->cur_end_bytes){
2143 WARN("Shouldn't happen: Trying to push frames from a spent buffer?\n");
2144 return FALSE;
2147 submit_bytes = min(src->xa2->period_frames * src->submit_blocksize, buf->cur_end_bytes - buf->offs_bytes);
2148 submit_buf = buf->xa2buffer.pAudioData + buf->offs_bytes;
2149 buf->offs_bytes += submit_bytes;
2151 alBufferData(al_buf, src->al_fmt, submit_buf, submit_bytes,
2152 src->fmt->nSamplesPerSec);
2154 alSourceQueueBuffers(src->al_src, 1, &al_buf);
2156 src->in_al_bytes += submit_bytes;
2157 src->al_bufs_used++;
2159 buf->latest_al_buf = al_buf;
2161 TRACE("queueing %u bytes, now %u in AL\n", submit_bytes, src->in_al_bytes);
2163 return buf->offs_bytes < buf->cur_end_bytes;
2166 #if XAUDIO2_VER > 0
2167 static UINT32 get_underrun_warning(XA2SourceImpl *src)
2169 UINT32 period_bytes = src->xa2->period_frames * src->submit_blocksize;
2170 UINT32 total = 0, i;
2172 for(i = 0; i < src->nbufs && total < IN_AL_PERIODS * period_bytes; ++i){
2173 XA2Buffer *buf = &src->buffers[(src->first_buf + i) % XAUDIO2_MAX_QUEUED_BUFFERS];
2174 total += buf->cur_end_bytes - buf->offs_bytes;
2175 if(buf->xa2buffer.LoopCount == XAUDIO2_LOOP_INFINITE)
2176 return 0;
2177 if(buf->xa2buffer.LoopCount > 0){
2178 total += (buf->loop_end_bytes - buf->xa2buffer.LoopBegin) * (buf->xa2buffer.LoopCount - buf->looped);
2179 total += buf->play_end_bytes - buf->loop_end_bytes;
2183 if(total >= IN_AL_PERIODS * period_bytes)
2184 return 0;
2186 return ((IN_AL_PERIODS * period_bytes - total) / period_bytes + 1) * period_bytes;
2188 #endif
2190 /* Looping:
2192 * The looped section of a buffer is a subset of the play area which is looped
2193 * LoopCount times.
2195 * v PlayBegin
2196 * vvvvvvvvvvvvvvvvvv PlayLength
2197 * v (PlayEnd)
2198 * [-----PPPLLLLLLLLPPPPPPP------]
2199 * ^ LoopBegin
2200 * ^^^^^^^^ LoopLength
2201 * ^ (LoopEnd)
2203 * In the simple case, playback will start at PlayBegin. At LoopEnd, playback
2204 * will move to LoopBegin and repeat that loop LoopCount times. Then, playback
2205 * will cease at PlayEnd.
2207 * If PlayLength is zero, then PlayEnd is the end of the buffer.
2209 * If LoopLength is zero, then LoopEnd is PlayEnd.
2211 * For corner cases and version differences, see tests.
2213 static void update_source_state(XA2SourceImpl *src)
2215 int i;
2216 ALint processed;
2217 ALint bufpos;
2219 alGetSourcei(src->al_src, AL_BUFFERS_PROCESSED, &processed);
2221 if(processed > 0){
2222 ALuint al_buffers[XAUDIO2_MAX_QUEUED_BUFFERS];
2224 alSourceUnqueueBuffers(src->al_src, processed, al_buffers);
2225 src->first_al_buf += processed;
2226 src->first_al_buf %= XAUDIO2_MAX_QUEUED_BUFFERS;
2227 src->al_bufs_used -= processed;
2229 for(i = 0; i < processed; ++i){
2230 ALint bufsize;
2232 alGetBufferi(al_buffers[i], AL_SIZE, &bufsize);
2234 src->in_al_bytes -= bufsize;
2235 src->played_frames += bufsize / src->submit_blocksize;
2237 if(al_buffers[i] == src->buffers[src->first_buf].latest_al_buf){
2238 DWORD old_buf = src->first_buf;
2240 src->first_buf++;
2241 src->first_buf %= XAUDIO2_MAX_QUEUED_BUFFERS;
2242 src->nbufs--;
2244 TRACE("%p: done with buffer %u\n", src, old_buf);
2246 if(src->buffers[old_buf].xa2buffer.Flags & XAUDIO2_END_OF_STREAM)
2247 src->played_frames = 0;
2249 if(src->cb){
2250 IXAudio2VoiceCallback_OnBufferEnd(src->cb,
2251 src->buffers[old_buf].xa2buffer.pContext);
2252 if(src->buffers[old_buf].xa2buffer.Flags & XAUDIO2_END_OF_STREAM)
2253 IXAudio2VoiceCallback_OnStreamEnd(src->cb);
2255 if(src->nbufs > 0)
2256 IXAudio2VoiceCallback_OnBufferStart(src->cb,
2257 src->buffers[src->first_buf].xa2buffer.pContext);
2263 alGetSourcei(src->al_src, AL_BYTE_OFFSET, &bufpos);
2265 /* maintain IN_AL_PERIODS periods in AL */
2266 while(src->cur_buf != (src->first_buf + src->nbufs) % XAUDIO2_MAX_QUEUED_BUFFERS &&
2267 src->in_al_bytes - bufpos < IN_AL_PERIODS * src->xa2->period_frames * src->submit_blocksize){
2268 TRACE("%p: going to queue a period from buffer %u\n", src, src->cur_buf);
2270 /* starting from an empty buffer */
2271 if(src->cb && src->cur_buf == src->first_buf && src->buffers[src->cur_buf].offs_bytes == 0 && !src->buffers[src->cur_buf].looped)
2272 IXAudio2VoiceCallback_OnBufferStart(src->cb,
2273 src->buffers[src->first_buf].xa2buffer.pContext);
2275 if(!xa2buffer_queue_period(src, &src->buffers[src->cur_buf],
2276 src->al_bufs[(src->first_al_buf + src->al_bufs_used) % XAUDIO2_MAX_QUEUED_BUFFERS])){
2277 XA2Buffer *cur = &src->buffers[src->cur_buf];
2279 if(cur->looped < cur->xa2buffer.LoopCount){
2280 if(cur->xa2buffer.LoopCount != XAUDIO2_LOOP_INFINITE)
2281 ++cur->looped;
2282 else
2283 cur->looped = 1; /* indicate that we are executing a loop */
2285 cur->offs_bytes = cur->xa2buffer.LoopBegin;
2286 if(cur->looped == cur->xa2buffer.LoopCount)
2287 cur->cur_end_bytes = cur->play_end_bytes;
2288 else
2289 cur->cur_end_bytes = cur->loop_end_bytes;
2291 if(src->cb)
2292 IXAudio2VoiceCallback_OnLoopEnd(src->cb,
2293 src->buffers[src->cur_buf].xa2buffer.pContext);
2295 }else{
2296 /* buffer is spent, move on */
2297 src->cur_buf++;
2298 src->cur_buf %= XAUDIO2_MAX_QUEUED_BUFFERS;
2304 static void do_engine_tick(IXAudio2Impl *This)
2306 BYTE *buf;
2307 XA2SourceImpl *src;
2308 HRESULT hr;
2309 UINT32 nframes, i, pad;
2311 /* maintain up to 3 periods in mmdevapi */
2312 hr = IAudioClient_GetCurrentPadding(This->aclient, &pad);
2313 if(FAILED(hr)){
2314 WARN("GetCurrentPadding failed: 0x%x\n", hr);
2315 return;
2318 nframes = This->period_frames * 3 - pad;
2320 TRACE("frames available: %u\n", nframes);
2322 if(nframes < This->period_frames)
2323 return;
2325 if(!nframes)
2326 return;
2328 for(i = 0; i < This->ncbs && This->cbs[i]; ++i)
2329 IXAudio2EngineCallback_OnProcessingPassStart(This->cbs[i]);
2331 LIST_FOR_EACH_ENTRY(src, &This->source_voices, XA2SourceImpl, entry){
2332 ALint st = 0;
2334 EnterCriticalSection(&src->lock);
2336 if(!src->in_use || !src->running){
2337 LeaveCriticalSection(&src->lock);
2338 continue;
2341 if(src->cb){
2342 #if XAUDIO2_VER == 0
2343 IXAudio20VoiceCallback_OnVoiceProcessingPassStart((IXAudio20VoiceCallback*)src->cb);
2344 #else
2345 UINT32 underrun;
2346 underrun = get_underrun_warning(src);
2347 if(underrun > 0)
2348 TRACE("Calling OnVoiceProcessingPassStart with BytesRequired: %u\n", underrun);
2349 IXAudio2VoiceCallback_OnVoiceProcessingPassStart(src->cb, underrun);
2350 #endif
2353 update_source_state(src);
2355 alGetSourcei(src->al_src, AL_SOURCE_STATE, &st);
2356 if(st != AL_PLAYING)
2357 alSourcePlay(src->al_src);
2359 if(src->cb)
2360 IXAudio2VoiceCallback_OnVoiceProcessingPassEnd(src->cb);
2362 LeaveCriticalSection(&src->lock);
2365 hr = IAudioRenderClient_GetBuffer(This->render, nframes, &buf);
2366 if(FAILED(hr))
2367 WARN("GetBuffer failed: %08x\n", hr);
2369 palcRenderSamplesSOFT(This->al_device, buf, nframes);
2371 hr = IAudioRenderClient_ReleaseBuffer(This->render, nframes, 0);
2372 if(FAILED(hr))
2373 WARN("ReleaseBuffer failed: %08x\n", hr);
2375 for(i = 0; i < This->ncbs && This->cbs[i]; ++i)
2376 IXAudio2EngineCallback_OnProcessingPassEnd(This->cbs[i]);
2379 static DWORD WINAPI engine_threadproc(void *arg)
2381 IXAudio2Impl *This = arg;
2382 while(1){
2383 WaitForSingleObject(This->mmevt, INFINITE);
2385 if(This->stop_engine)
2386 break;
2388 EnterCriticalSection(&This->lock);
2390 if(!This->running || !This->aclient){
2391 LeaveCriticalSection(&This->lock);
2392 continue;
2395 do_engine_tick(This);
2397 LeaveCriticalSection(&This->lock);
2399 return 0;