xaudio2: Implement CreateFX for legacy xaudio2 versions.
[wine.git] / dlls / xaudio2_7 / xaudio_dll.c
blobd55d39e8fdba031fe122d93d111ccf0d4e31a7f3
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 "initguid.h"
27 #include "xaudio_private.h"
29 #include "ole2.h"
30 #include "rpcproxy.h"
32 #include "xapofx.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(xaudio2);
38 static ALCdevice *(ALC_APIENTRY *palcLoopbackOpenDeviceSOFT)(const ALCchar*);
39 static void (ALC_APIENTRY *palcRenderSamplesSOFT)(ALCdevice*, ALCvoid*, ALCsizei);
41 static HINSTANCE instance;
43 #define COMPAT_E_INVALID_CALL(v) (v == 20) ? E_INVALIDARG : XAUDIO2_E_INVALID_CALL
44 #define COMPAT_E_DEVICE_INVALIDATED(v) (v == 20) ? XAUDIO20_E_DEVICE_INVALIDATED : XAUDIO2_E_DEVICE_INVALIDATED
46 static void dump_fmt(const WAVEFORMATEX *fmt)
48 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
49 switch(fmt->wFormatTag){
50 #define DOCASE(x) case x: TRACE(#x); break;
51 DOCASE(WAVE_FORMAT_PCM)
52 DOCASE(WAVE_FORMAT_IEEE_FLOAT)
53 DOCASE(WAVE_FORMAT_EXTENSIBLE)
54 #undef DOCASE
55 default:
56 TRACE("Unknown");
57 break;
59 TRACE(")\n");
61 TRACE("nChannels: %u\n", fmt->nChannels);
62 TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
63 TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
64 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
65 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
66 TRACE("cbSize: %u\n", fmt->cbSize);
68 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
69 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
70 TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
71 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
72 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
73 }else if(fmt->wFormatTag == WAVE_FORMAT_ADPCM){
74 ADPCMWAVEFORMAT *fmtadpcm = (void*)fmt;
75 TRACE("wSamplesPerBlock: %u\n", fmtadpcm->wSamplesPerBlock);
79 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, void *pReserved)
81 TRACE("(%p, %d, %p)\n", hinstDLL, reason, pReserved);
83 switch (reason)
85 case DLL_WINE_PREATTACH:
86 return FALSE; /* prefer native version */
87 case DLL_PROCESS_ATTACH:
88 instance = hinstDLL;
89 DisableThreadLibraryCalls( hinstDLL );
91 if(!alcIsExtensionPresent(NULL, "ALC_SOFT_loopback") ||
92 !(palcLoopbackOpenDeviceSOFT = alcGetProcAddress(NULL, "alcLoopbackOpenDeviceSOFT")) ||
93 !(palcRenderSamplesSOFT = alcGetProcAddress(NULL, "alcRenderSamplesSOFT"))){
94 ERR("XAudio2 requires the ALC_SOFT_loopback extension (OpenAL-Soft >= 1.14)\n");
95 return FALSE;
98 break;
100 return TRUE;
103 HRESULT WINAPI DllCanUnloadNow(void)
105 return S_FALSE;
108 HRESULT WINAPI DllRegisterServer(void)
110 TRACE("\n");
111 return __wine_register_resources(instance);
114 HRESULT WINAPI DllUnregisterServer(void)
116 TRACE("\n");
117 return __wine_unregister_resources(instance);
120 static XA2SourceImpl *impl_from_IXAudio2SourceVoice(IXAudio2SourceVoice *iface)
122 return CONTAINING_RECORD(iface, XA2SourceImpl, IXAudio2SourceVoice_iface);
125 static XA2SubmixImpl *impl_from_IXAudio2SubmixVoice(IXAudio2SubmixVoice *iface)
127 return CONTAINING_RECORD(iface, XA2SubmixImpl, IXAudio2SubmixVoice_iface);
130 static inline IXAudio2Impl *impl_from_IXAudio2(IXAudio2 *iface)
132 return CONTAINING_RECORD(iface, IXAudio2Impl, IXAudio2_iface);
135 static IXAudio2Impl *impl_from_IXAudio2MasteringVoice(IXAudio2MasteringVoice *iface)
137 return CONTAINING_RECORD(iface, IXAudio2Impl, IXAudio2MasteringVoice_iface);
140 static DWORD get_channel_mask(unsigned int channels)
142 switch(channels){
143 case 0:
144 return 0;
145 case 1:
146 return KSAUDIO_SPEAKER_MONO;
147 case 2:
148 return KSAUDIO_SPEAKER_STEREO;
149 case 3:
150 return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY;
151 case 4:
152 return KSAUDIO_SPEAKER_QUAD; /* not _SURROUND */
153 case 5:
154 return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY;
155 case 6:
156 return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */
157 case 7:
158 return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER;
159 case 8:
160 return KSAUDIO_SPEAKER_7POINT1_SURROUND; /* Vista deprecates 7POINT1 */
162 FIXME("Unknown speaker configuration: %u\n", channels);
163 return 0;
166 static void WINAPI XA2SRC_GetVoiceDetails(IXAudio2SourceVoice *iface,
167 XAUDIO2_VOICE_DETAILS *pVoiceDetails)
169 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
170 TRACE("%p, %p\n", This, pVoiceDetails);
173 static HRESULT WINAPI XA2SRC_SetOutputVoices(IXAudio2SourceVoice *iface,
174 const XAUDIO2_VOICE_SENDS *pSendList)
176 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
177 int i;
178 XAUDIO2_VOICE_SENDS def_send;
179 XAUDIO2_SEND_DESCRIPTOR def_desc;
181 TRACE("%p, %p\n", This, pSendList);
183 if(!pSendList){
184 def_desc.Flags = 0;
185 def_desc.pOutputVoice = (IXAudio2Voice*)&This->xa2->IXAudio2MasteringVoice_iface;
187 def_send.SendCount = 1;
188 def_send.pSends = &def_desc;
190 pSendList = &def_send;
193 if(TRACE_ON(xaudio2)){
194 for(i = 0; i < pSendList->SendCount; ++i){
195 XAUDIO2_SEND_DESCRIPTOR *desc = &pSendList->pSends[i];
196 TRACE("Outputting to: 0x%x, %p\n", desc->Flags, desc->pOutputVoice);
200 if(This->nsends < pSendList->SendCount){
201 HeapFree(GetProcessHeap(), 0, This->sends);
202 This->sends = HeapAlloc(GetProcessHeap(), 0, sizeof(*This->sends) * pSendList->SendCount);
203 This->nsends = pSendList->SendCount;
204 }else
205 memset(This->sends, 0, sizeof(*This->sends) * This->nsends);
207 memcpy(This->sends, pSendList->pSends, sizeof(*This->sends) * pSendList->SendCount);
209 return S_OK;
212 static HRESULT WINAPI XA2SRC_SetEffectChain(IXAudio2SourceVoice *iface,
213 const XAUDIO2_EFFECT_CHAIN *pEffectChain)
215 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
216 TRACE("%p, %p\n", This, pEffectChain);
217 return S_OK;
220 static HRESULT WINAPI XA2SRC_EnableEffect(IXAudio2SourceVoice *iface,
221 UINT32 EffectIndex, UINT32 OperationSet)
223 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
224 TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
225 return S_OK;
228 static HRESULT WINAPI XA2SRC_DisableEffect(IXAudio2SourceVoice *iface,
229 UINT32 EffectIndex, UINT32 OperationSet)
231 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
232 TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
233 return S_OK;
236 static void WINAPI XA2SRC_GetEffectState(IXAudio2SourceVoice *iface,
237 UINT32 EffectIndex, BOOL *pEnabled)
239 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
240 TRACE("%p, %u, %p\n", This, EffectIndex, pEnabled);
243 static HRESULT WINAPI XA2SRC_SetEffectParameters(IXAudio2SourceVoice *iface,
244 UINT32 EffectIndex, const void *pParameters, UINT32 ParametersByteSize,
245 UINT32 OperationSet)
247 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
248 TRACE("%p, %u, %p, 0x%x, 0x%x\n", This, EffectIndex, pParameters,
249 ParametersByteSize, OperationSet);
250 return S_OK;
253 static HRESULT WINAPI XA2SRC_GetEffectParameters(IXAudio2SourceVoice *iface,
254 UINT32 EffectIndex, void *pParameters, UINT32 ParametersByteSize)
256 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
257 TRACE("%p, %u, %p, 0x%x\n", This, EffectIndex, pParameters,
258 ParametersByteSize);
259 return S_OK;
262 static HRESULT WINAPI XA2SRC_SetFilterParameters(IXAudio2SourceVoice *iface,
263 const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
265 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
266 TRACE("%p, %p, 0x%x\n", This, pParameters, OperationSet);
267 return S_OK;
270 static void WINAPI XA2SRC_GetFilterParameters(IXAudio2SourceVoice *iface,
271 XAUDIO2_FILTER_PARAMETERS *pParameters)
273 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
274 TRACE("%p, %p\n", This, pParameters);
277 static HRESULT WINAPI XA2SRC_SetOutputFilterParameters(IXAudio2SourceVoice *iface,
278 IXAudio2Voice *pDestinationVoice,
279 const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
281 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
282 TRACE("%p, %p, %p, 0x%x\n", This, pDestinationVoice, pParameters, OperationSet);
283 return S_OK;
286 static void WINAPI XA2SRC_GetOutputFilterParameters(IXAudio2SourceVoice *iface,
287 IXAudio2Voice *pDestinationVoice,
288 XAUDIO2_FILTER_PARAMETERS *pParameters)
290 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
291 TRACE("%p, %p, %p\n", This, pDestinationVoice, pParameters);
294 static HRESULT WINAPI XA2SRC_SetVolume(IXAudio2SourceVoice *iface, float Volume,
295 UINT32 OperationSet)
297 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
298 ALfloat al_gain;
300 TRACE("%p, %f, 0x%x\n", This, Volume, OperationSet);
302 al_gain = Volume;
304 alSourcef(This->al_src, AL_GAIN, al_gain);
306 return S_OK;
309 static void WINAPI XA2SRC_GetVolume(IXAudio2SourceVoice *iface, float *pVolume)
311 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
312 TRACE("%p, %p\n", This, pVolume);
315 static HRESULT WINAPI XA2SRC_SetChannelVolumes(IXAudio2SourceVoice *iface,
316 UINT32 Channels, const float *pVolumes, UINT32 OperationSet)
318 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
319 TRACE("%p, %u, %p, 0x%x\n", This, Channels, pVolumes, OperationSet);
320 return S_OK;
323 static void WINAPI XA2SRC_GetChannelVolumes(IXAudio2SourceVoice *iface,
324 UINT32 Channels, float *pVolumes)
326 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
327 TRACE("%p, %u, %p\n", This, Channels, pVolumes);
330 static HRESULT WINAPI XA2SRC_SetOutputMatrix(IXAudio2SourceVoice *iface,
331 IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
332 UINT32 DestinationChannels, const float *pLevelMatrix,
333 UINT32 OperationSet)
335 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
336 TRACE("%p, %p, %u, %u, %p, 0x%x\n", This, pDestinationVoice,
337 SourceChannels, DestinationChannels, pLevelMatrix, OperationSet);
338 return S_OK;
341 static void WINAPI XA2SRC_GetOutputMatrix(IXAudio2SourceVoice *iface,
342 IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
343 UINT32 DestinationChannels, float *pLevelMatrix)
345 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
346 TRACE("%p, %p, %u, %u, %p\n", This, pDestinationVoice,
347 SourceChannels, DestinationChannels, pLevelMatrix);
350 static void WINAPI XA2SRC_DestroyVoice(IXAudio2SourceVoice *iface)
352 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
353 ALint processed;
355 TRACE("%p\n", This);
357 EnterCriticalSection(&This->lock);
359 if(!This->in_use){
360 LeaveCriticalSection(&This->lock);
361 return;
364 This->in_use = FALSE;
366 This->running = FALSE;
368 IXAudio2SourceVoice_Stop(iface, 0, 0);
370 alSourceStop(This->al_src);
372 /* unqueue all buffers */
373 alSourcei(This->al_src, AL_BUFFER, AL_NONE);
375 alGetSourcei(This->al_src, AL_BUFFERS_PROCESSED, &processed);
377 if(processed > 0){
378 ALuint al_buffers[XAUDIO2_MAX_QUEUED_BUFFERS];
380 alSourceUnqueueBuffers(This->al_src, processed, al_buffers);
383 HeapFree(GetProcessHeap(), 0, This->fmt);
385 alDeleteBuffers(XAUDIO2_MAX_QUEUED_BUFFERS, This->al_bufs);
386 alDeleteSources(1, &This->al_src);
388 This->in_al_bytes = 0;
389 This->al_bufs_used = 0;
390 This->played_frames = 0;
391 This->nbufs = 0;
392 This->first_buf = 0;
393 This->cur_buf = 0;
395 LeaveCriticalSection(&This->lock);
398 static HRESULT WINAPI XA2SRC_Start(IXAudio2SourceVoice *iface, UINT32 Flags,
399 UINT32 OperationSet)
401 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
403 TRACE("%p, 0x%x, 0x%x\n", This, Flags, OperationSet);
405 EnterCriticalSection(&This->lock);
407 This->running = TRUE;
409 LeaveCriticalSection(&This->lock);
411 return S_OK;
414 static HRESULT WINAPI XA2SRC_Stop(IXAudio2SourceVoice *iface, UINT32 Flags,
415 UINT32 OperationSet)
417 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
419 TRACE("%p, 0x%x, 0x%x\n", This, Flags, OperationSet);
421 EnterCriticalSection(&This->lock);
423 This->running = FALSE;
425 LeaveCriticalSection(&This->lock);
427 return S_OK;
430 static ALenum get_al_format(const WAVEFORMATEX *fmt)
432 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)fmt;
433 if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
434 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
435 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
436 switch(fmt->wBitsPerSample){
437 case 8:
438 switch(fmt->nChannels){
439 case 1:
440 return AL_FORMAT_MONO8;
441 case 2:
442 return AL_FORMAT_STEREO8;
443 case 4:
444 return AL_FORMAT_QUAD8;
445 case 6:
446 return AL_FORMAT_51CHN8;
447 case 7:
448 return AL_FORMAT_61CHN8;
449 case 8:
450 return AL_FORMAT_71CHN8;
452 case 16:
453 switch(fmt->nChannels){
454 case 1:
455 return AL_FORMAT_MONO16;
456 case 2:
457 return AL_FORMAT_STEREO16;
458 case 4:
459 return AL_FORMAT_QUAD16;
460 case 6:
461 return AL_FORMAT_51CHN16;
462 case 7:
463 return AL_FORMAT_61CHN16;
464 case 8:
465 return AL_FORMAT_71CHN16;
468 }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
469 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
470 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
471 if(fmt->wBitsPerSample == 32){
472 switch(fmt->nChannels){
473 case 1:
474 return AL_FORMAT_MONO_FLOAT32;
475 case 2:
476 return AL_FORMAT_STEREO_FLOAT32;
480 return 0;
483 static HRESULT WINAPI XA2SRC_SubmitSourceBuffer(IXAudio2SourceVoice *iface,
484 const XAUDIO2_BUFFER *pBuffer, const XAUDIO2_BUFFER_WMA *pBufferWMA)
486 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
487 XA2Buffer *buf;
488 UINT32 buf_idx;
490 TRACE("%p, %p, %p\n", This, pBuffer, pBufferWMA);
492 if(TRACE_ON(xaudio2)){
493 TRACE("Flags: 0x%x\n", pBuffer->Flags);
494 TRACE("AudioBytes: %u\n", pBuffer->AudioBytes);
495 TRACE("pAudioData: %p\n", pBuffer->pAudioData);
496 TRACE("PlayBegin: %u\n", pBuffer->PlayBegin);
497 TRACE("PlayLength: %u\n", pBuffer->PlayLength);
498 TRACE("LoopBegin: %u\n", pBuffer->LoopBegin);
499 TRACE("LoopLength: %u\n", pBuffer->LoopLength);
500 TRACE("LoopCount: %u\n", pBuffer->LoopCount);
501 TRACE("pContext: %p\n", pBuffer->pContext);
504 EnterCriticalSection(&This->lock);
506 if(This->nbufs >= XAUDIO2_MAX_QUEUED_BUFFERS){
507 TRACE("Too many buffers queued!\n");
508 LeaveCriticalSection(&This->lock);
509 return COMPAT_E_INVALID_CALL(This->xa2->version);
512 buf_idx = (This->first_buf + This->nbufs) % XAUDIO2_MAX_QUEUED_BUFFERS;
513 buf = &This->buffers[buf_idx];
514 memset(buf, 0, sizeof(*buf));
516 /* API contract: pAudioData must remain valid until this buffer is played,
517 * but pBuffer itself may be reused immediately */
518 memcpy(&buf->xa2buffer, pBuffer, sizeof(*pBuffer));
520 if(This->xa2->version == 20){
521 if(buf->xa2buffer.LoopCount == XAUDIO20_LOOP_INFINITE)
522 buf->xa2buffer.LoopCount = XAUDIO2_LOOP_INFINITE;
525 /* convert samples offsets to bytes */
526 if(This->fmt->wFormatTag == WAVE_FORMAT_ADPCM){
527 /* ADPCM gives us a number of samples per block, so round down to
528 * nearest block and convert to bytes */
529 buf->xa2buffer.PlayBegin = buf->xa2buffer.PlayBegin / ((ADPCMWAVEFORMAT*)This->fmt)->wSamplesPerBlock * This->fmt->nBlockAlign;
530 buf->xa2buffer.PlayLength = buf->xa2buffer.PlayLength / ((ADPCMWAVEFORMAT*)This->fmt)->wSamplesPerBlock * This->fmt->nBlockAlign;
531 buf->xa2buffer.LoopBegin = buf->xa2buffer.LoopBegin / ((ADPCMWAVEFORMAT*)This->fmt)->wSamplesPerBlock * This->fmt->nBlockAlign;
532 buf->xa2buffer.LoopLength = buf->xa2buffer.LoopLength / ((ADPCMWAVEFORMAT*)This->fmt)->wSamplesPerBlock * This->fmt->nBlockAlign;
533 }else{
534 buf->xa2buffer.PlayBegin *= This->fmt->nBlockAlign;
535 buf->xa2buffer.PlayLength *= This->fmt->nBlockAlign;
536 buf->xa2buffer.LoopBegin *= This->fmt->nBlockAlign;
537 buf->xa2buffer.LoopLength *= This->fmt->nBlockAlign;
540 if(buf->xa2buffer.PlayLength == 0)
541 /* set to end of buffer */
542 buf->xa2buffer.PlayLength = buf->xa2buffer.AudioBytes - buf->xa2buffer.PlayBegin;
544 buf->play_end_bytes = buf->xa2buffer.PlayBegin + buf->xa2buffer.PlayLength;
546 if(buf->xa2buffer.LoopCount){
547 if(buf->xa2buffer.LoopLength == 0)
548 /* set to end of play range */
549 buf->xa2buffer.LoopLength = buf->play_end_bytes - buf->xa2buffer.LoopBegin;
551 if(buf->xa2buffer.LoopBegin >= buf->play_end_bytes){
552 /* this actually crashes on native xaudio 2.7 */
553 LeaveCriticalSection(&This->lock);
554 return COMPAT_E_INVALID_CALL(This->xa2->version);
557 buf->loop_end_bytes = buf->xa2buffer.LoopBegin + buf->xa2buffer.LoopLength;
559 /* xaudio 2.7 allows some invalid looping setups, but later versions
560 * return an error */
561 if(This->xa2->version > 27){
562 if(buf->loop_end_bytes > buf->play_end_bytes){
563 LeaveCriticalSection(&This->lock);
564 return COMPAT_E_INVALID_CALL(This->xa2->version);
567 if(buf->loop_end_bytes <= buf->xa2buffer.PlayBegin){
568 LeaveCriticalSection(&This->lock);
569 return COMPAT_E_INVALID_CALL(This->xa2->version);
571 }else{
572 if(buf->loop_end_bytes <= buf->xa2buffer.PlayBegin){
573 buf->xa2buffer.LoopCount = 0;
574 buf->loop_end_bytes = buf->play_end_bytes;
577 }else{
578 buf->xa2buffer.LoopLength = buf->xa2buffer.PlayLength;
579 buf->xa2buffer.LoopBegin = buf->xa2buffer.PlayBegin;
580 buf->loop_end_bytes = buf->play_end_bytes;
583 buf->offs_bytes = buf->xa2buffer.PlayBegin;
584 buf->cur_end_bytes = buf->loop_end_bytes;
586 buf->latest_al_buf = -1;
588 ++This->nbufs;
590 TRACE("%p: queued buffer %u (%u bytes), now %u buffers held\n",
591 This, buf_idx, buf->xa2buffer.AudioBytes, This->nbufs);
593 LeaveCriticalSection(&This->lock);
595 return S_OK;
598 static HRESULT WINAPI XA2SRC_FlushSourceBuffers(IXAudio2SourceVoice *iface)
600 UINT i, first, last, to_flush;
601 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
603 TRACE("%p\n", This);
605 EnterCriticalSection(&This->lock);
607 if(This->running && This->nbufs > 0){
608 /* when running, flush only completely unused buffers; the rest remain
609 * in queue */
610 last = (This->first_buf + This->nbufs) % XAUDIO2_MAX_QUEUED_BUFFERS;
611 first = (This->cur_buf + 1) % XAUDIO2_MAX_QUEUED_BUFFERS;
612 if(This->cur_buf == last)
613 /* nothing to do */
614 to_flush = 0;
615 else if(last >= first)
616 to_flush = last - first;
617 else
618 to_flush = last + XAUDIO2_MAX_QUEUED_BUFFERS - first;
619 }else{
620 /* when stopped, flush all buffers */
621 first = This->first_buf;
622 last = (This->first_buf + This->nbufs) % XAUDIO2_MAX_QUEUED_BUFFERS;
623 to_flush = This->nbufs;
627 for(i = first;
628 i < (first + to_flush) % XAUDIO2_MAX_QUEUED_BUFFERS;
629 i = (i + 1) % XAUDIO2_MAX_QUEUED_BUFFERS){
630 if(This->cb)
631 IXAudio2VoiceCallback_OnBufferEnd(This->cb,
632 This->buffers[i].xa2buffer.pContext);
635 This->nbufs -= to_flush;
637 LeaveCriticalSection(&This->lock);
639 return S_OK;
642 static HRESULT WINAPI XA2SRC_Discontinuity(IXAudio2SourceVoice *iface)
644 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
646 TRACE("%p\n", This);
648 EnterCriticalSection(&This->lock);
650 if(This->nbufs > 0){
651 DWORD last = (This->first_buf + This->nbufs - 1) % XAUDIO2_MAX_QUEUED_BUFFERS;
652 This->buffers[last].xa2buffer.Flags |= XAUDIO2_END_OF_STREAM;
655 LeaveCriticalSection(&This->lock);
657 return S_OK;
660 static HRESULT WINAPI XA2SRC_ExitLoop(IXAudio2SourceVoice *iface, UINT32 OperationSet)
662 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
664 TRACE("%p, 0x%x\n", This, OperationSet);
666 EnterCriticalSection(&This->lock);
668 This->buffers[This->cur_buf].looped = XAUDIO2_LOOP_INFINITE;
670 LeaveCriticalSection(&This->lock);
672 return S_OK;
675 static void WINAPI XA2SRC_GetState(IXAudio2SourceVoice *iface,
676 XAUDIO2_VOICE_STATE *pVoiceState, UINT32 Flags)
678 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
680 TRACE("%p, %p, 0x%x\n", This, pVoiceState, Flags);
682 EnterCriticalSection(&This->lock);
684 if(!(Flags & XAUDIO2_VOICE_NOSAMPLESPLAYED))
685 pVoiceState->SamplesPlayed = This->played_frames;
686 else
687 pVoiceState->SamplesPlayed = 0;
689 if(This->nbufs)
690 pVoiceState->pCurrentBufferContext = This->buffers[This->first_buf].xa2buffer.pContext;
691 else
692 pVoiceState->pCurrentBufferContext = NULL;
694 pVoiceState->BuffersQueued = This->nbufs;
696 LeaveCriticalSection(&This->lock);
698 TRACE("returning %s, queued: %u\n", wine_dbgstr_longlong(pVoiceState->SamplesPlayed), This->nbufs);
701 static HRESULT WINAPI XA2SRC_SetFrequencyRatio(IXAudio2SourceVoice *iface,
702 float Ratio, UINT32 OperationSet)
704 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
705 ALfloat r;
707 TRACE("%p, %f, 0x%x\n", This, Ratio, OperationSet);
709 if(Ratio < XAUDIO2_MIN_FREQ_RATIO)
710 r = XAUDIO2_MIN_FREQ_RATIO;
711 else if (Ratio > XAUDIO2_MAX_FREQ_RATIO)
712 r = XAUDIO2_MAX_FREQ_RATIO;
713 else
714 r = Ratio;
716 alSourcef(This->al_src, AL_PITCH, r);
718 return S_OK;
721 static void WINAPI XA2SRC_GetFrequencyRatio(IXAudio2SourceVoice *iface, float *pRatio)
723 ALfloat ratio;
724 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
726 TRACE("%p, %p\n", This, pRatio);
728 alGetSourcef(This->al_src, AL_PITCH, &ratio);
730 *pRatio = ratio;
733 static HRESULT WINAPI XA2SRC_SetSourceSampleRate(
734 IXAudio2SourceVoice *iface,
735 UINT32 NewSourceSampleRate)
737 XA2SourceImpl *This = impl_from_IXAudio2SourceVoice(iface);
739 TRACE("%p, %u\n", This, NewSourceSampleRate);
741 EnterCriticalSection(&This->lock);
743 if(This->nbufs){
744 LeaveCriticalSection(&This->lock);
745 return COMPAT_E_INVALID_CALL(This->xa2->version);
748 This->fmt->nSamplesPerSec = NewSourceSampleRate;
750 LeaveCriticalSection(&This->lock);
752 return S_OK;
755 static const IXAudio2SourceVoiceVtbl XAudio2SourceVoice_Vtbl = {
756 XA2SRC_GetVoiceDetails,
757 XA2SRC_SetOutputVoices,
758 XA2SRC_SetEffectChain,
759 XA2SRC_EnableEffect,
760 XA2SRC_DisableEffect,
761 XA2SRC_GetEffectState,
762 XA2SRC_SetEffectParameters,
763 XA2SRC_GetEffectParameters,
764 XA2SRC_SetFilterParameters,
765 XA2SRC_GetFilterParameters,
766 XA2SRC_SetOutputFilterParameters,
767 XA2SRC_GetOutputFilterParameters,
768 XA2SRC_SetVolume,
769 XA2SRC_GetVolume,
770 XA2SRC_SetChannelVolumes,
771 XA2SRC_GetChannelVolumes,
772 XA2SRC_SetOutputMatrix,
773 XA2SRC_GetOutputMatrix,
774 XA2SRC_DestroyVoice,
775 XA2SRC_Start,
776 XA2SRC_Stop,
777 XA2SRC_SubmitSourceBuffer,
778 XA2SRC_FlushSourceBuffers,
779 XA2SRC_Discontinuity,
780 XA2SRC_ExitLoop,
781 XA2SRC_GetState,
782 XA2SRC_SetFrequencyRatio,
783 XA2SRC_GetFrequencyRatio,
784 XA2SRC_SetSourceSampleRate
787 static void WINAPI XA2M_GetVoiceDetails(IXAudio2MasteringVoice *iface,
788 XAUDIO2_VOICE_DETAILS *pVoiceDetails)
790 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
791 TRACE("%p, %p\n", This, pVoiceDetails);
792 pVoiceDetails->CreationFlags = 0;
793 pVoiceDetails->InputChannels = This->fmt.Format.nChannels;
794 pVoiceDetails->InputSampleRate = This->fmt.Format.nSamplesPerSec;
797 static HRESULT WINAPI XA2M_SetOutputVoices(IXAudio2MasteringVoice *iface,
798 const XAUDIO2_VOICE_SENDS *pSendList)
800 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
801 TRACE("%p, %p\n", This, pSendList);
802 return S_OK;
805 static HRESULT WINAPI XA2M_SetEffectChain(IXAudio2MasteringVoice *iface,
806 const XAUDIO2_EFFECT_CHAIN *pEffectChain)
808 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
809 TRACE("%p, %p\n", This, pEffectChain);
810 return S_OK;
813 static HRESULT WINAPI XA2M_EnableEffect(IXAudio2MasteringVoice *iface, UINT32 EffectIndex,
814 UINT32 OperationSet)
816 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
817 TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
818 return S_OK;
821 static HRESULT WINAPI XA2M_DisableEffect(IXAudio2MasteringVoice *iface, UINT32 EffectIndex,
822 UINT32 OperationSet)
824 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
825 TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
826 return S_OK;
829 static void WINAPI XA2M_GetEffectState(IXAudio2MasteringVoice *iface, UINT32 EffectIndex,
830 BOOL *pEnabled)
832 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
833 TRACE("%p, %u, %p\n", This, EffectIndex, pEnabled);
836 static HRESULT WINAPI XA2M_SetEffectParameters(IXAudio2MasteringVoice *iface,
837 UINT32 EffectIndex, const void *pParameters, UINT32 ParametersByteSize,
838 UINT32 OperationSet)
840 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
841 TRACE("%p, %u, %p, 0x%x, 0x%x\n", This, EffectIndex, pParameters,
842 ParametersByteSize, OperationSet);
843 return S_OK;
846 static HRESULT WINAPI XA2M_GetEffectParameters(IXAudio2MasteringVoice *iface,
847 UINT32 EffectIndex, void *pParameters, UINT32 ParametersByteSize)
849 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
850 TRACE("%p, %u, %p, 0x%x\n", This, EffectIndex, pParameters,
851 ParametersByteSize);
852 return S_OK;
855 static HRESULT WINAPI XA2M_SetFilterParameters(IXAudio2MasteringVoice *iface,
856 const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
858 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
859 TRACE("%p, %p, 0x%x\n", This, pParameters, OperationSet);
860 return S_OK;
863 static void WINAPI XA2M_GetFilterParameters(IXAudio2MasteringVoice *iface,
864 XAUDIO2_FILTER_PARAMETERS *pParameters)
866 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
867 TRACE("%p, %p\n", This, pParameters);
870 static HRESULT WINAPI XA2M_SetOutputFilterParameters(IXAudio2MasteringVoice *iface,
871 IXAudio2Voice *pDestinationVoice,
872 const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
874 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
875 TRACE("%p, %p, %p, 0x%x\n", This, pDestinationVoice, pParameters, OperationSet);
876 return S_OK;
879 static void WINAPI XA2M_GetOutputFilterParameters(IXAudio2MasteringVoice *iface,
880 IXAudio2Voice *pDestinationVoice,
881 XAUDIO2_FILTER_PARAMETERS *pParameters)
883 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
884 TRACE("%p, %p, %p\n", This, pDestinationVoice, pParameters);
887 static HRESULT WINAPI XA2M_SetVolume(IXAudio2MasteringVoice *iface, float Volume,
888 UINT32 OperationSet)
890 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
891 TRACE("%p, %f, 0x%x\n", This, Volume, OperationSet);
892 return S_OK;
895 static void WINAPI XA2M_GetVolume(IXAudio2MasteringVoice *iface, float *pVolume)
897 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
898 TRACE("%p, %p\n", This, pVolume);
901 static HRESULT WINAPI XA2M_SetChannelVolumes(IXAudio2MasteringVoice *iface, UINT32 Channels,
902 const float *pVolumes, UINT32 OperationSet)
904 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
905 TRACE("%p, %u, %p, 0x%x\n", This, Channels, pVolumes, OperationSet);
906 return S_OK;
909 static void WINAPI XA2M_GetChannelVolumes(IXAudio2MasteringVoice *iface, UINT32 Channels,
910 float *pVolumes)
912 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
913 TRACE("%p, %u, %p\n", This, Channels, pVolumes);
916 static HRESULT WINAPI XA2M_SetOutputMatrix(IXAudio2MasteringVoice *iface,
917 IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
918 UINT32 DestinationChannels, const float *pLevelMatrix,
919 UINT32 OperationSet)
921 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
922 TRACE("%p, %p, %u, %u, %p, 0x%x\n", This, pDestinationVoice,
923 SourceChannels, DestinationChannels, pLevelMatrix, OperationSet);
924 return S_OK;
927 static void WINAPI XA2M_GetOutputMatrix(IXAudio2MasteringVoice *iface,
928 IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
929 UINT32 DestinationChannels, float *pLevelMatrix)
931 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
932 TRACE("%p, %p, %u, %u, %p\n", This, pDestinationVoice,
933 SourceChannels, DestinationChannels, pLevelMatrix);
936 static void WINAPI XA2M_DestroyVoice(IXAudio2MasteringVoice *iface)
938 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
940 TRACE("%p\n", This);
942 EnterCriticalSection(&This->lock);
944 if(!This->aclient){
945 LeaveCriticalSection(&This->lock);
946 return;
949 This->running = FALSE;
951 IAudioRenderClient_Release(This->render);
952 This->render = NULL;
954 IAudioClient_Release(This->aclient);
955 This->aclient = NULL;
957 alcCloseDevice(This->al_device);
958 This->al_device = NULL;
960 alcDestroyContext(This->al_ctx);
961 This->al_ctx = NULL;
963 LeaveCriticalSection(&This->lock);
966 /* not present in XAudio2 2.7 */
967 static void WINAPI XA2M_GetChannelMask(IXAudio2MasteringVoice *iface,
968 DWORD *pChannelMask)
970 IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
972 TRACE("%p %p\n", This, pChannelMask);
974 *pChannelMask = This->fmt.dwChannelMask;
977 static const struct IXAudio2MasteringVoiceVtbl XAudio2MasteringVoice_Vtbl = {
978 XA2M_GetVoiceDetails,
979 XA2M_SetOutputVoices,
980 XA2M_SetEffectChain,
981 XA2M_EnableEffect,
982 XA2M_DisableEffect,
983 XA2M_GetEffectState,
984 XA2M_SetEffectParameters,
985 XA2M_GetEffectParameters,
986 XA2M_SetFilterParameters,
987 XA2M_GetFilterParameters,
988 XA2M_SetOutputFilterParameters,
989 XA2M_GetOutputFilterParameters,
990 XA2M_SetVolume,
991 XA2M_GetVolume,
992 XA2M_SetChannelVolumes,
993 XA2M_GetChannelVolumes,
994 XA2M_SetOutputMatrix,
995 XA2M_GetOutputMatrix,
996 XA2M_DestroyVoice,
997 XA2M_GetChannelMask
1000 static void WINAPI XA2SUB_GetVoiceDetails(IXAudio2SubmixVoice *iface,
1001 XAUDIO2_VOICE_DETAILS *pVoiceDetails)
1003 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1004 TRACE("%p, %p\n", This, pVoiceDetails);
1007 static HRESULT WINAPI XA2SUB_SetOutputVoices(IXAudio2SubmixVoice *iface,
1008 const XAUDIO2_VOICE_SENDS *pSendList)
1010 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1011 TRACE("%p, %p\n", This, pSendList);
1012 return S_OK;
1015 static HRESULT WINAPI XA2SUB_SetEffectChain(IXAudio2SubmixVoice *iface,
1016 const XAUDIO2_EFFECT_CHAIN *pEffectChain)
1018 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1019 TRACE("%p, %p\n", This, pEffectChain);
1020 return S_OK;
1023 static HRESULT WINAPI XA2SUB_EnableEffect(IXAudio2SubmixVoice *iface, UINT32 EffectIndex,
1024 UINT32 OperationSet)
1026 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1027 TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
1028 return S_OK;
1031 static HRESULT WINAPI XA2SUB_DisableEffect(IXAudio2SubmixVoice *iface, UINT32 EffectIndex,
1032 UINT32 OperationSet)
1034 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1035 TRACE("%p, %u, 0x%x\n", This, EffectIndex, OperationSet);
1036 return S_OK;
1039 static void WINAPI XA2SUB_GetEffectState(IXAudio2SubmixVoice *iface, UINT32 EffectIndex,
1040 BOOL *pEnabled)
1042 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1043 TRACE("%p, %u, %p\n", This, EffectIndex, pEnabled);
1046 static HRESULT WINAPI XA2SUB_SetEffectParameters(IXAudio2SubmixVoice *iface,
1047 UINT32 EffectIndex, const void *pParameters, UINT32 ParametersByteSize,
1048 UINT32 OperationSet)
1050 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1051 TRACE("%p, %u, %p, 0x%x, 0x%x\n", This, EffectIndex, pParameters,
1052 ParametersByteSize, OperationSet);
1053 return S_OK;
1056 static HRESULT WINAPI XA2SUB_GetEffectParameters(IXAudio2SubmixVoice *iface,
1057 UINT32 EffectIndex, void *pParameters, UINT32 ParametersByteSize)
1059 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1060 TRACE("%p, %u, %p, 0x%x\n", This, EffectIndex, pParameters,
1061 ParametersByteSize);
1062 return S_OK;
1065 static HRESULT WINAPI XA2SUB_SetFilterParameters(IXAudio2SubmixVoice *iface,
1066 const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
1068 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1069 TRACE("%p, %p, 0x%x\n", This, pParameters, OperationSet);
1070 return S_OK;
1073 static void WINAPI XA2SUB_GetFilterParameters(IXAudio2SubmixVoice *iface,
1074 XAUDIO2_FILTER_PARAMETERS *pParameters)
1076 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1077 TRACE("%p, %p\n", This, pParameters);
1080 static HRESULT WINAPI XA2SUB_SetOutputFilterParameters(IXAudio2SubmixVoice *iface,
1081 IXAudio2Voice *pDestinationVoice,
1082 const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
1084 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1085 TRACE("%p, %p, %p, 0x%x\n", This, pDestinationVoice, pParameters, OperationSet);
1086 return S_OK;
1089 static void WINAPI XA2SUB_GetOutputFilterParameters(IXAudio2SubmixVoice *iface,
1090 IXAudio2Voice *pDestinationVoice,
1091 XAUDIO2_FILTER_PARAMETERS *pParameters)
1093 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1094 TRACE("%p, %p, %p\n", This, pDestinationVoice, pParameters);
1097 static HRESULT WINAPI XA2SUB_SetVolume(IXAudio2SubmixVoice *iface, float Volume,
1098 UINT32 OperationSet)
1100 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1101 TRACE("%p, %f, 0x%x\n", This, Volume, OperationSet);
1102 return S_OK;
1105 static void WINAPI XA2SUB_GetVolume(IXAudio2SubmixVoice *iface, float *pVolume)
1107 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1108 TRACE("%p, %p\n", This, pVolume);
1111 static HRESULT WINAPI XA2SUB_SetChannelVolumes(IXAudio2SubmixVoice *iface, UINT32 Channels,
1112 const float *pVolumes, UINT32 OperationSet)
1114 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1115 TRACE("%p, %u, %p, 0x%x\n", This, Channels, pVolumes, OperationSet);
1116 return S_OK;
1119 static void WINAPI XA2SUB_GetChannelVolumes(IXAudio2SubmixVoice *iface, UINT32 Channels,
1120 float *pVolumes)
1122 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1123 TRACE("%p, %u, %p\n", This, Channels, pVolumes);
1126 static HRESULT WINAPI XA2SUB_SetOutputMatrix(IXAudio2SubmixVoice *iface,
1127 IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
1128 UINT32 DestinationChannels, const float *pLevelMatrix,
1129 UINT32 OperationSet)
1131 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1132 TRACE("%p, %p, %u, %u, %p, 0x%x\n", This, pDestinationVoice,
1133 SourceChannels, DestinationChannels, pLevelMatrix, OperationSet);
1134 return S_OK;
1137 static void WINAPI XA2SUB_GetOutputMatrix(IXAudio2SubmixVoice *iface,
1138 IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
1139 UINT32 DestinationChannels, float *pLevelMatrix)
1141 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1142 TRACE("%p, %p, %u, %u, %p\n", This, pDestinationVoice,
1143 SourceChannels, DestinationChannels, pLevelMatrix);
1146 static void WINAPI XA2SUB_DestroyVoice(IXAudio2SubmixVoice *iface)
1148 XA2SubmixImpl *This = impl_from_IXAudio2SubmixVoice(iface);
1150 TRACE("%p\n", This);
1152 EnterCriticalSection(&This->lock);
1154 This->in_use = FALSE;
1156 LeaveCriticalSection(&This->lock);
1159 static const struct IXAudio2SubmixVoiceVtbl XAudio2SubmixVoice_Vtbl = {
1160 XA2SUB_GetVoiceDetails,
1161 XA2SUB_SetOutputVoices,
1162 XA2SUB_SetEffectChain,
1163 XA2SUB_EnableEffect,
1164 XA2SUB_DisableEffect,
1165 XA2SUB_GetEffectState,
1166 XA2SUB_SetEffectParameters,
1167 XA2SUB_GetEffectParameters,
1168 XA2SUB_SetFilterParameters,
1169 XA2SUB_GetFilterParameters,
1170 XA2SUB_SetOutputFilterParameters,
1171 XA2SUB_GetOutputFilterParameters,
1172 XA2SUB_SetVolume,
1173 XA2SUB_GetVolume,
1174 XA2SUB_SetChannelVolumes,
1175 XA2SUB_GetChannelVolumes,
1176 XA2SUB_SetOutputMatrix,
1177 XA2SUB_GetOutputMatrix,
1178 XA2SUB_DestroyVoice
1181 static HRESULT WINAPI IXAudio2Impl_QueryInterface(IXAudio2 *iface, REFIID riid,
1182 void **ppvObject)
1184 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1186 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
1188 if(IsEqualGUID(riid, &IID_IUnknown) ||
1189 IsEqualGUID(riid, &IID_IXAudio2))
1190 *ppvObject = &This->IXAudio2_iface;
1191 else if(IsEqualGUID(riid, &IID_IXAudio27)){
1192 /* all xaudio versions before 28 share an IID */
1193 if(This->version == 20)
1194 *ppvObject = &This->IXAudio20_iface;
1195 else if(This->version == 21 || This->version == 22)
1196 *ppvObject = &This->IXAudio22_iface;
1197 else
1198 *ppvObject = &This->IXAudio27_iface;
1199 }else
1200 *ppvObject = NULL;
1202 if(*ppvObject){
1203 IUnknown_AddRef((IUnknown*)*ppvObject);
1204 return S_OK;
1207 FIXME("(%p)->(%s,%p), not found\n", This,debugstr_guid(riid), ppvObject);
1209 return E_NOINTERFACE;
1212 static ULONG WINAPI IXAudio2Impl_AddRef(IXAudio2 *iface)
1214 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1215 ULONG ref = InterlockedIncrement(&This->ref);
1216 TRACE("(%p)->(): Refcount now %u\n", This, ref);
1217 return ref;
1220 static ULONG WINAPI IXAudio2Impl_Release(IXAudio2 *iface)
1222 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1223 ULONG ref = InterlockedDecrement(&This->ref);
1225 TRACE("(%p)->(): Refcount now %u\n", This, ref);
1227 if (!ref) {
1228 int i;
1229 XA2SourceImpl *src, *src2;
1230 XA2SubmixImpl *sub, *sub2;
1232 if(This->engine){
1233 This->stop_engine = TRUE;
1234 SetEvent(This->mmevt);
1235 WaitForSingleObject(This->engine, INFINITE);
1236 CloseHandle(This->engine);
1239 LIST_FOR_EACH_ENTRY_SAFE(src, src2, &This->source_voices, XA2SourceImpl, entry){
1240 HeapFree(GetProcessHeap(), 0, src->sends);
1241 IXAudio2SourceVoice_DestroyVoice(&src->IXAudio2SourceVoice_iface);
1242 DeleteCriticalSection(&src->lock);
1243 HeapFree(GetProcessHeap(), 0, src);
1246 LIST_FOR_EACH_ENTRY_SAFE(sub, sub2, &This->submix_voices, XA2SubmixImpl, entry){
1247 IXAudio2SubmixVoice_DestroyVoice(&sub->IXAudio2SubmixVoice_iface);
1248 DeleteCriticalSection(&sub->lock);
1249 HeapFree(GetProcessHeap(), 0, sub);
1252 IXAudio2MasteringVoice_DestroyVoice(&This->IXAudio2MasteringVoice_iface);
1254 if(This->devenum)
1255 IMMDeviceEnumerator_Release(This->devenum);
1256 for(i = 0; i < This->ndevs; ++i)
1257 CoTaskMemFree(This->devids[i]);
1258 HeapFree(GetProcessHeap(), 0, This->devids);
1259 HeapFree(GetProcessHeap(), 0, This->cbs);
1261 CloseHandle(This->mmevt);
1263 DeleteCriticalSection(&This->lock);
1265 HeapFree(GetProcessHeap(), 0, This);
1267 return ref;
1270 static HRESULT WINAPI IXAudio2Impl_RegisterForCallbacks(IXAudio2 *iface,
1271 IXAudio2EngineCallback *pCallback)
1273 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1274 int i;
1276 TRACE("(%p)->(%p)\n", This, pCallback);
1278 EnterCriticalSection(&This->lock);
1280 for(i = 0; i < This->ncbs; ++i){
1281 if(!This->cbs[i] || This->cbs[i] == pCallback){
1282 This->cbs[i] = pCallback;
1283 LeaveCriticalSection(&This->lock);
1284 return S_OK;
1288 This->ncbs *= 2;
1289 This->cbs = HeapReAlloc(GetProcessHeap(), 0, This->cbs, This->ncbs * sizeof(*This->cbs));
1291 This->cbs[i] = pCallback;
1293 LeaveCriticalSection(&This->lock);
1295 return S_OK;
1298 static void WINAPI IXAudio2Impl_UnregisterForCallbacks(IXAudio2 *iface,
1299 IXAudio2EngineCallback *pCallback)
1301 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1302 int i;
1304 TRACE("(%p)->(%p)\n", This, pCallback);
1306 EnterCriticalSection(&This->lock);
1308 for(i = 0; i < This->ncbs; ++i){
1309 if(This->cbs[i] == pCallback)
1310 break;
1313 for(; i < This->ncbs - 1 && This->cbs[i + 1]; ++i)
1314 This->cbs[i] = This->cbs[i + 1];
1316 if(i < This->ncbs)
1317 This->cbs[i] = NULL;
1319 LeaveCriticalSection(&This->lock);
1322 static WAVEFORMATEX *copy_waveformat(const WAVEFORMATEX *wfex)
1324 WAVEFORMATEX *pwfx;
1326 if(wfex->wFormatTag == WAVE_FORMAT_PCM){
1327 pwfx = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEX));
1328 CopyMemory(pwfx, wfex, sizeof(PCMWAVEFORMAT));
1329 pwfx->cbSize = 0;
1330 }else{
1331 pwfx = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEX) + wfex->cbSize);
1332 CopyMemory(pwfx, wfex, sizeof(WAVEFORMATEX) + wfex->cbSize);
1335 return pwfx;
1338 static HRESULT WINAPI IXAudio2Impl_CreateSourceVoice(IXAudio2 *iface,
1339 IXAudio2SourceVoice **ppSourceVoice, const WAVEFORMATEX *pSourceFormat,
1340 UINT32 flags, float maxFrequencyRatio,
1341 IXAudio2VoiceCallback *pCallback, const XAUDIO2_VOICE_SENDS *pSendList,
1342 const XAUDIO2_EFFECT_CHAIN *pEffectChain)
1344 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1345 XA2SourceImpl *src;
1346 HRESULT hr;
1348 TRACE("(%p)->(%p, %p, 0x%x, %f, %p, %p, %p)\n", This, ppSourceVoice,
1349 pSourceFormat, flags, maxFrequencyRatio, pCallback, pSendList,
1350 pEffectChain);
1352 dump_fmt(pSourceFormat);
1354 EnterCriticalSection(&This->lock);
1356 LIST_FOR_EACH_ENTRY(src, &This->source_voices, XA2SourceImpl, entry){
1357 if(!src->in_use)
1358 break;
1361 if(&src->entry == &This->source_voices){
1362 src = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*src));
1363 if(!src){
1364 LeaveCriticalSection(&This->lock);
1365 return E_OUTOFMEMORY;
1368 list_add_head(&This->source_voices, &src->entry);
1370 src->IXAudio20SourceVoice_iface.lpVtbl = &XAudio20SourceVoice_Vtbl;
1371 src->IXAudio23SourceVoice_iface.lpVtbl = &XAudio23SourceVoice_Vtbl;
1372 src->IXAudio27SourceVoice_iface.lpVtbl = &XAudio27SourceVoice_Vtbl;
1373 src->IXAudio2SourceVoice_iface.lpVtbl = &XAudio2SourceVoice_Vtbl;
1375 InitializeCriticalSection(&src->lock);
1376 src->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": XA2SourceImpl.lock");
1378 src->xa2 = This;
1381 src->in_use = TRUE;
1382 src->running = FALSE;
1384 LeaveCriticalSection(&This->lock);
1386 src->cb = pCallback;
1388 src->al_fmt = get_al_format(pSourceFormat);
1389 if(!src->al_fmt){
1390 src->in_use = FALSE;
1391 WARN("OpenAL can't convert this format!\n");
1392 return AUDCLNT_E_UNSUPPORTED_FORMAT;
1395 src->submit_blocksize = pSourceFormat->nBlockAlign;
1397 src->fmt = copy_waveformat(pSourceFormat);
1399 hr = XA2SRC_SetOutputVoices(&src->IXAudio2SourceVoice_iface, pSendList);
1400 if(FAILED(hr)){
1401 src->in_use = FALSE;
1402 return hr;
1405 alGenSources(1, &src->al_src);
1406 alGenBuffers(XAUDIO2_MAX_QUEUED_BUFFERS, src->al_bufs);
1408 alSourcePlay(src->al_src);
1410 if(This->version == 20)
1411 *ppSourceVoice = (IXAudio2SourceVoice*)&src->IXAudio20SourceVoice_iface;
1412 else if(This->version <= 23)
1413 *ppSourceVoice = (IXAudio2SourceVoice*)&src->IXAudio23SourceVoice_iface;
1414 else if(This->version <= 27)
1415 *ppSourceVoice = (IXAudio2SourceVoice*)&src->IXAudio27SourceVoice_iface;
1416 else
1417 *ppSourceVoice = &src->IXAudio2SourceVoice_iface;
1419 TRACE("Created source voice: %p\n", src);
1421 return S_OK;
1424 static HRESULT WINAPI IXAudio2Impl_CreateSubmixVoice(IXAudio2 *iface,
1425 IXAudio2SubmixVoice **ppSubmixVoice, UINT32 inputChannels,
1426 UINT32 inputSampleRate, UINT32 flags, UINT32 processingStage,
1427 const XAUDIO2_VOICE_SENDS *pSendList,
1428 const XAUDIO2_EFFECT_CHAIN *pEffectChain)
1430 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1431 XA2SubmixImpl *sub;
1433 TRACE("(%p)->(%p, %u, %u, 0x%x, %u, %p, %p)\n", This, ppSubmixVoice,
1434 inputChannels, inputSampleRate, flags, processingStage, pSendList,
1435 pEffectChain);
1437 EnterCriticalSection(&This->lock);
1439 LIST_FOR_EACH_ENTRY(sub, &This->submix_voices, XA2SubmixImpl, entry){
1440 if(!sub->in_use)
1441 break;
1444 if(&sub->entry == &This->submix_voices){
1445 sub = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*sub));
1446 if(!sub){
1447 LeaveCriticalSection(&This->lock);
1448 return E_OUTOFMEMORY;
1451 list_add_head(&This->submix_voices, &sub->entry);
1453 sub->IXAudio20SubmixVoice_iface.lpVtbl = &XAudio20SubmixVoice_Vtbl;
1454 sub->IXAudio23SubmixVoice_iface.lpVtbl = &XAudio23SubmixVoice_Vtbl;
1455 sub->IXAudio2SubmixVoice_iface.lpVtbl = &XAudio2SubmixVoice_Vtbl;
1457 InitializeCriticalSection(&sub->lock);
1458 sub->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": XA2SubmixImpl.lock");
1461 sub->in_use = TRUE;
1463 LeaveCriticalSection(&This->lock);
1465 if(This->version == 20)
1466 *ppSubmixVoice = (IXAudio2SubmixVoice*)&sub->IXAudio20SubmixVoice_iface;
1467 else if(This->version <= 23)
1468 *ppSubmixVoice = (IXAudio2SubmixVoice*)&sub->IXAudio23SubmixVoice_iface;
1469 else
1470 *ppSubmixVoice = &sub->IXAudio2SubmixVoice_iface;
1472 TRACE("Created submix voice: %p\n", sub);
1474 return S_OK;
1477 static ALenum al_get_loopback_format(const WAVEFORMATEXTENSIBLE *fmt)
1479 if(fmt->Format.wFormatTag == WAVE_FORMAT_PCM ||
1480 (fmt->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1481 IsEqualGUID(&fmt->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
1482 switch(fmt->Format.wBitsPerSample){
1483 case 8:
1484 return ALC_UNSIGNED_BYTE_SOFT;
1485 case 16:
1486 return ALC_SHORT_SOFT;
1487 case 32:
1488 return ALC_INT_SOFT;
1490 }else if(fmt->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
1491 (fmt->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1492 IsEqualGUID(&fmt->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
1493 if(fmt->Format.wBitsPerSample == 32)
1494 return ALC_FLOAT_SOFT;
1496 return 0;
1499 static HRESULT WINAPI IXAudio2Impl_CreateMasteringVoice(IXAudio2 *iface,
1500 IXAudio2MasteringVoice **ppMasteringVoice, UINT32 inputChannels,
1501 UINT32 inputSampleRate, UINT32 flags, const WCHAR *deviceId,
1502 const XAUDIO2_EFFECT_CHAIN *pEffectChain,
1503 AUDIO_STREAM_CATEGORY streamCategory)
1505 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1506 IMMDevice *dev;
1507 HRESULT hr;
1508 WAVEFORMATEX *fmt;
1509 ALCint attrs[7];
1510 REFERENCE_TIME period, bufdur;
1512 TRACE("(%p)->(%p, %u, %u, 0x%x, %s, %p, 0x%x)\n", This,
1513 ppMasteringVoice, inputChannels, inputSampleRate, flags,
1514 wine_dbgstr_w(deviceId), pEffectChain, streamCategory);
1516 if(flags != 0)
1517 WARN("Unknown flags set: 0x%x\n", flags);
1519 if(pEffectChain)
1520 WARN("Effect chain is unimplemented\n");
1522 EnterCriticalSection(&This->lock);
1524 /* there can only be one Mastering Voice, so just build it into XA2 */
1525 if(This->aclient){
1526 LeaveCriticalSection(&This->lock);
1527 return COMPAT_E_INVALID_CALL(This->version);
1530 if(!deviceId){
1531 if(This->ndevs == 0){
1532 LeaveCriticalSection(&This->lock);
1533 return ERROR_NOT_FOUND;
1535 deviceId = This->devids[0];
1538 hr = IMMDeviceEnumerator_GetDevice(This->devenum, deviceId, &dev);
1539 if(FAILED(hr)){
1540 WARN("GetDevice failed: %08x\n", hr);
1541 hr = COMPAT_E_DEVICE_INVALIDATED(This->version);
1542 goto exit;
1545 hr = IMMDevice_Activate(dev, &IID_IAudioClient,
1546 CLSCTX_INPROC_SERVER, NULL, (void**)&This->aclient);
1547 if(FAILED(hr)){
1548 WARN("Activate(IAudioClient) failed: %08x\n", hr);
1549 IMMDevice_Release(dev);
1550 hr = COMPAT_E_DEVICE_INVALIDATED(This->version);
1551 goto exit;
1554 IMMDevice_Release(dev);
1556 hr = IAudioClient_GetMixFormat(This->aclient, &fmt);
1557 if(FAILED(hr)){
1558 WARN("GetMixFormat failed: %08x\n", hr);
1559 hr = COMPAT_E_DEVICE_INVALIDATED(This->version);
1560 goto exit;
1563 if(sizeof(WAVEFORMATEX) + fmt->cbSize > sizeof(WAVEFORMATEXTENSIBLE)){
1564 FIXME("Mix format doesn't fit into WAVEFORMATEXTENSIBLE!\n");
1565 hr = COMPAT_E_DEVICE_INVALIDATED(This->version);
1566 goto exit;
1569 if(inputChannels == XAUDIO2_DEFAULT_CHANNELS)
1570 inputChannels = fmt->nChannels;
1571 if(inputSampleRate == XAUDIO2_DEFAULT_SAMPLERATE)
1572 inputSampleRate = fmt->nSamplesPerSec;
1574 memcpy(&This->fmt, fmt, sizeof(WAVEFORMATEX) + fmt->cbSize);
1575 This->fmt.Format.nChannels = inputChannels;
1576 This->fmt.Format.nSamplesPerSec = inputSampleRate;
1577 This->fmt.Format.nBlockAlign = This->fmt.Format.nChannels * This->fmt.Format.wBitsPerSample / 8;
1578 This->fmt.Format.nAvgBytesPerSec = This->fmt.Format.nSamplesPerSec * This->fmt.Format.nBlockAlign;
1579 This->fmt.dwChannelMask = get_channel_mask(This->fmt.Format.nChannels);
1581 CoTaskMemFree(fmt);
1582 fmt = NULL;
1584 hr = IAudioClient_IsFormatSupported(This->aclient,
1585 AUDCLNT_SHAREMODE_SHARED, &This->fmt.Format, &fmt);
1586 if(hr == S_FALSE){
1587 if(sizeof(WAVEFORMATEX) + fmt->cbSize > sizeof(WAVEFORMATEXTENSIBLE)){
1588 FIXME("Mix format doesn't fit into WAVEFORMATEXTENSIBLE!\n");
1589 hr = COMPAT_E_DEVICE_INVALIDATED(This->version);
1590 goto exit;
1592 memcpy(&This->fmt, fmt, sizeof(WAVEFORMATEX) + fmt->cbSize);
1595 CoTaskMemFree(fmt);
1597 hr = IAudioClient_GetDevicePeriod(This->aclient, &period, NULL);
1598 if(FAILED(hr)){
1599 WARN("GetDevicePeriod failed: %08x\n", hr);
1600 hr = COMPAT_E_DEVICE_INVALIDATED(This->version);
1601 goto exit;
1604 /* 3 periods or 0.1 seconds */
1605 bufdur = max(3 * period, 1000000);
1607 hr = IAudioClient_Initialize(This->aclient, AUDCLNT_SHAREMODE_SHARED,
1608 AUDCLNT_STREAMFLAGS_EVENTCALLBACK, bufdur,
1609 0, &This->fmt.Format, NULL);
1610 if(FAILED(hr)){
1611 WARN("Initialize failed: %08x\n", hr);
1612 hr = COMPAT_E_DEVICE_INVALIDATED(This->version);
1613 goto exit;
1616 This->period_frames = MulDiv(period, inputSampleRate, 10000000);
1618 hr = IAudioClient_SetEventHandle(This->aclient, This->mmevt);
1619 if(FAILED(hr)){
1620 WARN("Initialize failed: %08x\n", hr);
1621 hr = COMPAT_E_DEVICE_INVALIDATED(This->version);
1622 goto exit;
1625 hr = IAudioClient_GetService(This->aclient, &IID_IAudioRenderClient,
1626 (void**)&This->render);
1627 if(FAILED(hr)){
1628 WARN("GetService(IAudioRenderClient) failed: %08x\n", hr);
1629 hr = COMPAT_E_DEVICE_INVALIDATED(This->version);
1630 goto exit;
1633 /* setup openal context */
1634 attrs[0] = ALC_FORMAT_CHANNELS_SOFT;
1635 switch(inputChannels){
1636 case 1:
1637 attrs[1] = ALC_MONO_SOFT;
1638 break;
1639 case 2:
1640 attrs[1] = ALC_STEREO_SOFT;
1641 break;
1642 case 4:
1643 attrs[1] = ALC_QUAD_SOFT;
1644 break;
1645 case 6:
1646 attrs[1] = ALC_5POINT1_SOFT;
1647 break;
1648 case 7:
1649 attrs[1] = ALC_6POINT1_SOFT;
1650 break;
1651 case 8:
1652 attrs[1] = ALC_7POINT1_SOFT;
1653 break;
1654 default:
1655 WARN("OpenAL doesn't support %u channels\n", inputChannels);
1656 LeaveCriticalSection(&This->lock);
1657 return AUDCLNT_E_UNSUPPORTED_FORMAT;
1659 attrs[2] = ALC_FREQUENCY;
1660 attrs[3] = inputSampleRate;
1661 attrs[4] = ALC_FORMAT_TYPE_SOFT;
1662 attrs[5] = al_get_loopback_format(&This->fmt);
1663 attrs[6] = 0;
1665 if(!attrs[5]){
1666 WARN("OpenAL can't output samples in this format\n");
1667 hr = COMPAT_E_DEVICE_INVALIDATED(This->version);
1668 goto exit;
1671 This->al_device = palcLoopbackOpenDeviceSOFT(NULL);
1672 if(!This->al_device){
1673 WARN("alcLoopbackOpenDeviceSOFT failed\n");
1674 hr = COMPAT_E_DEVICE_INVALIDATED(This->version);
1675 goto exit;
1678 This->al_ctx = alcCreateContext(This->al_device, attrs);
1679 if(!This->al_ctx){
1680 WARN("alcCreateContext failed\n");
1681 hr = COMPAT_E_DEVICE_INVALIDATED(This->version);
1682 goto exit;
1685 if(alcMakeContextCurrent(This->al_ctx) == ALC_FALSE){
1686 WARN("alcMakeContextCurrent failed\n");
1687 hr = COMPAT_E_DEVICE_INVALIDATED(This->version);
1688 goto exit;
1691 IAudioClient_Start(This->aclient);
1693 if(This->version <= 20)
1694 *ppMasteringVoice = (IXAudio2MasteringVoice*)&This->IXAudio20MasteringVoice_iface;
1695 else if(This->version <= 23)
1696 *ppMasteringVoice = (IXAudio2MasteringVoice*)&This->IXAudio23MasteringVoice_iface;
1697 else
1698 *ppMasteringVoice = &This->IXAudio2MasteringVoice_iface;
1700 exit:
1701 if(FAILED(hr)){
1702 if(This->render){
1703 IAudioRenderClient_Release(This->render);
1704 This->render = NULL;
1706 if(This->aclient){
1707 IAudioClient_Release(This->aclient);
1708 This->aclient = NULL;
1710 if(This->al_ctx){
1711 alcDestroyContext(This->al_ctx);
1712 This->al_ctx = NULL;
1714 if(This->al_device){
1715 alcCloseDevice(This->al_device);
1716 This->al_device = NULL;
1720 LeaveCriticalSection(&This->lock);
1722 return hr;
1725 static DWORD WINAPI engine_threadproc(void *arg);
1727 static HRESULT WINAPI IXAudio2Impl_StartEngine(IXAudio2 *iface)
1729 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1731 TRACE("(%p)->()\n", This);
1733 This->running = TRUE;
1735 if(!This->engine)
1736 This->engine = CreateThread(NULL, 0, engine_threadproc, This, 0, NULL);
1738 return S_OK;
1741 static void WINAPI IXAudio2Impl_StopEngine(IXAudio2 *iface)
1743 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1745 TRACE("(%p)->()\n", This);
1747 This->running = FALSE;
1750 static HRESULT WINAPI IXAudio2Impl_CommitChanges(IXAudio2 *iface,
1751 UINT32 operationSet)
1753 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1755 TRACE("(%p)->(0x%x): stub!\n", This, operationSet);
1757 return E_NOTIMPL;
1760 static void WINAPI IXAudio2Impl_GetPerformanceData(IXAudio2 *iface,
1761 XAUDIO2_PERFORMANCE_DATA *pPerfData)
1763 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1765 TRACE("(%p)->(%p): stub!\n", This, pPerfData);
1767 memset(pPerfData, 0, sizeof(*pPerfData));
1770 static void WINAPI IXAudio2Impl_SetDebugConfiguration(IXAudio2 *iface,
1771 const XAUDIO2_DEBUG_CONFIGURATION *pDebugConfiguration,
1772 void *pReserved)
1774 IXAudio2Impl *This = impl_from_IXAudio2(iface);
1776 FIXME("(%p)->(%p, %p): stub!\n", This, pDebugConfiguration, pReserved);
1779 /* XAudio2 2.8 */
1780 static const IXAudio2Vtbl XAudio2_Vtbl =
1782 IXAudio2Impl_QueryInterface,
1783 IXAudio2Impl_AddRef,
1784 IXAudio2Impl_Release,
1785 IXAudio2Impl_RegisterForCallbacks,
1786 IXAudio2Impl_UnregisterForCallbacks,
1787 IXAudio2Impl_CreateSourceVoice,
1788 IXAudio2Impl_CreateSubmixVoice,
1789 IXAudio2Impl_CreateMasteringVoice,
1790 IXAudio2Impl_StartEngine,
1791 IXAudio2Impl_StopEngine,
1792 IXAudio2Impl_CommitChanges,
1793 IXAudio2Impl_GetPerformanceData,
1794 IXAudio2Impl_SetDebugConfiguration
1797 typedef struct _VUMeterImpl {
1798 IXAPO IXAPO_iface;
1799 IXAPOParameters IXAPOParameters_iface;
1801 LONG ref;
1803 DWORD version;
1804 } VUMeterImpl;
1806 static VUMeterImpl *VUMeterImpl_from_IXAPO(IXAPO *iface)
1808 return CONTAINING_RECORD(iface, VUMeterImpl, IXAPO_iface);
1811 static VUMeterImpl *VUMeterImpl_from_IXAPOParameters(IXAPOParameters *iface)
1813 return CONTAINING_RECORD(iface, VUMeterImpl, IXAPOParameters_iface);
1816 static HRESULT WINAPI VUMXAPO_QueryInterface(IXAPO *iface, REFIID riid,
1817 void **ppvObject)
1819 VUMeterImpl *This = VUMeterImpl_from_IXAPO(iface);
1821 TRACE("%p, %s, %p\n", This, wine_dbgstr_guid(riid), ppvObject);
1823 if(IsEqualGUID(riid, &IID_IUnknown) ||
1824 IsEqualGUID(riid, &IID_IXAPO) ||
1825 IsEqualGUID(riid, &IID_IXAPO27))
1826 *ppvObject = &This->IXAPO_iface;
1827 else if(IsEqualGUID(riid, &IID_IXAPOParameters))
1828 *ppvObject = &This->IXAPOParameters_iface;
1829 else
1830 *ppvObject = NULL;
1832 if(*ppvObject){
1833 IUnknown_AddRef((IUnknown*)*ppvObject);
1834 return S_OK;
1837 return E_NOINTERFACE;
1840 static ULONG WINAPI VUMXAPO_AddRef(IXAPO *iface)
1842 VUMeterImpl *This = VUMeterImpl_from_IXAPO(iface);
1843 ULONG ref = InterlockedIncrement(&This->ref);
1844 TRACE("(%p)->(): Refcount now %u\n", This, ref);
1845 return ref;
1848 static ULONG WINAPI VUMXAPO_Release(IXAPO *iface)
1850 VUMeterImpl *This = VUMeterImpl_from_IXAPO(iface);
1851 ULONG ref = InterlockedDecrement(&This->ref);
1853 TRACE("(%p)->(): Refcount now %u\n", This, ref);
1855 if(!ref)
1856 HeapFree(GetProcessHeap(), 0, This);
1858 return ref;
1861 static HRESULT WINAPI VUMXAPO_GetRegistrationProperties(IXAPO *iface,
1862 XAPO_REGISTRATION_PROPERTIES **props)
1864 VUMeterImpl *This = VUMeterImpl_from_IXAPO(iface);
1865 TRACE("%p, %p\n", This, props);
1866 /* TODO: check for version == 20 and use XAPO20_REGISTRATION_PROPERTIES */
1867 return E_NOTIMPL;
1870 static HRESULT WINAPI VUMXAPO_IsInputFormatSupported(IXAPO *iface,
1871 const WAVEFORMATEX *output_fmt, const WAVEFORMATEX *input_fmt,
1872 WAVEFORMATEX **supported_fmt)
1874 VUMeterImpl *This = VUMeterImpl_from_IXAPO(iface);
1875 TRACE("%p, %p, %p, %p\n", This, output_fmt, input_fmt, supported_fmt);
1876 return E_NOTIMPL;
1879 static HRESULT WINAPI VUMXAPO_IsOutputFormatSupported(IXAPO *iface,
1880 const WAVEFORMATEX *input_fmt, const WAVEFORMATEX *output_fmt,
1881 WAVEFORMATEX **supported_fmt)
1883 VUMeterImpl *This = VUMeterImpl_from_IXAPO(iface);
1884 TRACE("%p, %p, %p, %p\n", This, input_fmt, output_fmt, supported_fmt);
1885 return E_NOTIMPL;
1888 static HRESULT WINAPI VUMXAPO_Initialize(IXAPO *iface, const void *data,
1889 UINT32 data_len)
1891 VUMeterImpl *This = VUMeterImpl_from_IXAPO(iface);
1892 TRACE("%p, %p, %u\n", This, data, data_len);
1893 return E_NOTIMPL;
1896 static HRESULT WINAPI VUMXAPO_Reset(IXAPO *iface)
1898 VUMeterImpl *This = VUMeterImpl_from_IXAPO(iface);
1899 TRACE("%p\n", This);
1900 return E_NOTIMPL;
1903 static HRESULT WINAPI VUMXAPO_LockForProcess(IXAPO *iface,
1904 UINT32 in_params_count,
1905 const XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS *in_params,
1906 UINT32 out_params_count,
1907 const XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS *out_params)
1909 VUMeterImpl *This = VUMeterImpl_from_IXAPO(iface);
1910 TRACE("%p, %u, %p, %u, %p\n", This, in_params_count, in_params,
1911 out_params_count, out_params);
1912 return E_NOTIMPL;
1915 static void WINAPI VUMXAPO_UnlockForProcess(IXAPO *iface)
1917 VUMeterImpl *This = VUMeterImpl_from_IXAPO(iface);
1918 TRACE("%p\n", This);
1921 static void WINAPI VUMXAPO_Process(IXAPO *iface, UINT32 in_params_count,
1922 const XAPO_PROCESS_BUFFER_PARAMETERS *in_params,
1923 UINT32 out_params_count,
1924 const XAPO_PROCESS_BUFFER_PARAMETERS *out_params, BOOL enabled)
1926 VUMeterImpl *This = VUMeterImpl_from_IXAPO(iface);
1927 TRACE("%p, %u, %p, %u, %p, %u\n", This, in_params_count, in_params,
1928 out_params_count, out_params, enabled);
1931 static UINT32 WINAPI VUMXAPO_CalcInputFrames(IXAPO *iface, UINT32 output_frames)
1933 VUMeterImpl *This = VUMeterImpl_from_IXAPO(iface);
1934 TRACE("%p, %u\n", This, output_frames);
1935 return 0;
1938 static UINT32 WINAPI VUMXAPO_CalcOutputFrames(IXAPO *iface, UINT32 input_frames)
1940 VUMeterImpl *This = VUMeterImpl_from_IXAPO(iface);
1941 TRACE("%p, %u\n", This, input_frames);
1942 return 0;
1945 static const IXAPOVtbl VUMXAPO_Vtbl = {
1946 VUMXAPO_QueryInterface,
1947 VUMXAPO_AddRef,
1948 VUMXAPO_Release,
1949 VUMXAPO_GetRegistrationProperties,
1950 VUMXAPO_IsInputFormatSupported,
1951 VUMXAPO_IsOutputFormatSupported,
1952 VUMXAPO_Initialize,
1953 VUMXAPO_Reset,
1954 VUMXAPO_LockForProcess,
1955 VUMXAPO_UnlockForProcess,
1956 VUMXAPO_Process,
1957 VUMXAPO_CalcInputFrames,
1958 VUMXAPO_CalcOutputFrames
1961 static HRESULT WINAPI VUMXAPOParams_QueryInterface(IXAPOParameters *iface,
1962 REFIID riid, void **ppvObject)
1964 VUMeterImpl *This = VUMeterImpl_from_IXAPOParameters(iface);
1965 return VUMXAPO_QueryInterface(&This->IXAPO_iface, riid, ppvObject);
1968 static ULONG WINAPI VUMXAPOParams_AddRef(IXAPOParameters *iface)
1970 VUMeterImpl *This = VUMeterImpl_from_IXAPOParameters(iface);
1971 return VUMXAPO_AddRef(&This->IXAPO_iface);
1974 static ULONG WINAPI VUMXAPOParams_Release(IXAPOParameters *iface)
1976 VUMeterImpl *This = VUMeterImpl_from_IXAPOParameters(iface);
1977 return VUMXAPO_Release(&This->IXAPO_iface);
1980 static void WINAPI VUMXAPOParams_SetParameters(IXAPOParameters *iface,
1981 const void *params, UINT32 params_len)
1983 VUMeterImpl *This = VUMeterImpl_from_IXAPOParameters(iface);
1984 TRACE("%p, %p, %u\n", This, params, params_len);
1987 static void WINAPI VUMXAPOParams_GetParameters(IXAPOParameters *iface,
1988 void *params, UINT32 params_len)
1990 VUMeterImpl *This = VUMeterImpl_from_IXAPOParameters(iface);
1991 TRACE("%p, %p, %u\n", This, params, params_len);
1994 static const IXAPOParametersVtbl VUMXAPOParameters_Vtbl = {
1995 VUMXAPOParams_QueryInterface,
1996 VUMXAPOParams_AddRef,
1997 VUMXAPOParams_Release,
1998 VUMXAPOParams_SetParameters,
1999 VUMXAPOParams_GetParameters
2002 typedef struct _ReverbImpl {
2003 IXAPO IXAPO_iface;
2004 IXAPOParameters IXAPOParameters_iface;
2006 LONG ref;
2008 DWORD version;
2009 } ReverbImpl;
2011 static ReverbImpl *ReverbImpl_from_IXAPO(IXAPO *iface)
2013 return CONTAINING_RECORD(iface, ReverbImpl, IXAPO_iface);
2016 static ReverbImpl *ReverbImpl_from_IXAPOParameters(IXAPOParameters *iface)
2018 return CONTAINING_RECORD(iface, ReverbImpl, IXAPOParameters_iface);
2021 static HRESULT WINAPI RVBXAPO_QueryInterface(IXAPO *iface, REFIID riid, void **ppvObject)
2023 ReverbImpl *This = ReverbImpl_from_IXAPO(iface);
2025 TRACE("%p, %s, %p\n", This, wine_dbgstr_guid(riid), ppvObject);
2027 if(IsEqualGUID(riid, &IID_IUnknown) ||
2028 IsEqualGUID(riid, &IID_IXAPO) ||
2029 IsEqualGUID(riid, &IID_IXAPO27))
2030 *ppvObject = &This->IXAPO_iface;
2031 else if(IsEqualGUID(riid, &IID_IXAPOParameters))
2032 *ppvObject = &This->IXAPOParameters_iface;
2033 else
2034 *ppvObject = NULL;
2036 if(*ppvObject){
2037 IUnknown_AddRef((IUnknown*)*ppvObject);
2038 return S_OK;
2041 return E_NOINTERFACE;
2044 static ULONG WINAPI RVBXAPO_AddRef(IXAPO *iface)
2046 ReverbImpl *This = ReverbImpl_from_IXAPO(iface);
2047 ULONG ref = InterlockedIncrement(&This->ref);
2048 TRACE("(%p)->(): Refcount now %u\n", This, ref);
2049 return ref;
2052 static ULONG WINAPI RVBXAPO_Release(IXAPO *iface)
2054 ReverbImpl *This = ReverbImpl_from_IXAPO(iface);
2055 ULONG ref = InterlockedDecrement(&This->ref);
2057 TRACE("(%p)->(): Refcount now %u\n", This, ref);
2059 if(!ref)
2060 HeapFree(GetProcessHeap(), 0, This);
2062 return ref;
2065 static HRESULT WINAPI RVBXAPO_GetRegistrationProperties(IXAPO *iface,
2066 XAPO_REGISTRATION_PROPERTIES **props)
2068 ReverbImpl *This = ReverbImpl_from_IXAPO(iface);
2069 TRACE("%p, %p\n", This, props);
2070 /* TODO: check for version == 20 and use XAPO20_REGISTRATION_PROPERTIES */
2071 return E_NOTIMPL;
2074 static HRESULT WINAPI RVBXAPO_IsInputFormatSupported(IXAPO *iface,
2075 const WAVEFORMATEX *output_fmt, const WAVEFORMATEX *input_fmt,
2076 WAVEFORMATEX **supported_fmt)
2078 ReverbImpl *This = ReverbImpl_from_IXAPO(iface);
2079 TRACE("%p, %p, %p, %p\n", This, output_fmt, input_fmt, supported_fmt);
2080 return E_NOTIMPL;
2083 static HRESULT WINAPI RVBXAPO_IsOutputFormatSupported(IXAPO *iface,
2084 const WAVEFORMATEX *input_fmt, const WAVEFORMATEX *output_fmt,
2085 WAVEFORMATEX **supported_fmt)
2087 ReverbImpl *This = ReverbImpl_from_IXAPO(iface);
2088 TRACE("%p, %p, %p, %p\n", This, input_fmt, output_fmt, supported_fmt);
2089 return E_NOTIMPL;
2092 static HRESULT WINAPI RVBXAPO_Initialize(IXAPO *iface, const void *data,
2093 UINT32 data_len)
2095 ReverbImpl *This = ReverbImpl_from_IXAPO(iface);
2096 TRACE("%p, %p, %u\n", This, data, data_len);
2097 return E_NOTIMPL;
2100 static HRESULT WINAPI RVBXAPO_Reset(IXAPO *iface)
2102 ReverbImpl *This = ReverbImpl_from_IXAPO(iface);
2103 TRACE("%p\n", This);
2104 return E_NOTIMPL;
2107 static HRESULT WINAPI RVBXAPO_LockForProcess(IXAPO *iface, UINT32 in_params_count,
2108 const XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS *in_params,
2109 UINT32 out_params_count,
2110 const XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS *out_params)
2112 ReverbImpl *This = ReverbImpl_from_IXAPO(iface);
2113 TRACE("%p, %u, %p, %u, %p\n", This, in_params_count, in_params,
2114 out_params_count, out_params);
2115 return E_NOTIMPL;
2118 static void WINAPI RVBXAPO_UnlockForProcess(IXAPO *iface)
2120 ReverbImpl *This = ReverbImpl_from_IXAPO(iface);
2121 TRACE("%p\n", This);
2124 static void WINAPI RVBXAPO_Process(IXAPO *iface, UINT32 in_params_count,
2125 const XAPO_PROCESS_BUFFER_PARAMETERS *in_params,
2126 UINT32 out_params_count,
2127 const XAPO_PROCESS_BUFFER_PARAMETERS *out_params, BOOL enabled)
2129 ReverbImpl *This = ReverbImpl_from_IXAPO(iface);
2130 TRACE("%p, %u, %p, %u, %p, %u\n", This, in_params_count, in_params,
2131 out_params_count, out_params, enabled);
2134 static UINT32 WINAPI RVBXAPO_CalcInputFrames(IXAPO *iface, UINT32 output_frames)
2136 ReverbImpl *This = ReverbImpl_from_IXAPO(iface);
2137 TRACE("%p, %u\n", This, output_frames);
2138 return 0;
2141 static UINT32 WINAPI RVBXAPO_CalcOutputFrames(IXAPO *iface, UINT32 input_frames)
2143 ReverbImpl *This = ReverbImpl_from_IXAPO(iface);
2144 TRACE("%p, %u\n", This, input_frames);
2145 return 0;
2148 static const IXAPOVtbl RVBXAPO_Vtbl = {
2149 RVBXAPO_QueryInterface,
2150 RVBXAPO_AddRef,
2151 RVBXAPO_Release,
2152 RVBXAPO_GetRegistrationProperties,
2153 RVBXAPO_IsInputFormatSupported,
2154 RVBXAPO_IsOutputFormatSupported,
2155 RVBXAPO_Initialize,
2156 RVBXAPO_Reset,
2157 RVBXAPO_LockForProcess,
2158 RVBXAPO_UnlockForProcess,
2159 RVBXAPO_Process,
2160 RVBXAPO_CalcInputFrames,
2161 RVBXAPO_CalcOutputFrames
2164 static HRESULT WINAPI RVBXAPOParams_QueryInterface(IXAPOParameters *iface,
2165 REFIID riid, void **ppvObject)
2167 ReverbImpl *This = ReverbImpl_from_IXAPOParameters(iface);
2168 return RVBXAPO_QueryInterface(&This->IXAPO_iface, riid, ppvObject);
2171 static ULONG WINAPI RVBXAPOParams_AddRef(IXAPOParameters *iface)
2173 ReverbImpl *This = ReverbImpl_from_IXAPOParameters(iface);
2174 return RVBXAPO_AddRef(&This->IXAPO_iface);
2177 static ULONG WINAPI RVBXAPOParams_Release(IXAPOParameters *iface)
2179 ReverbImpl *This = ReverbImpl_from_IXAPOParameters(iface);
2180 return RVBXAPO_Release(&This->IXAPO_iface);
2183 static void WINAPI RVBXAPOParams_SetParameters(IXAPOParameters *iface,
2184 const void *params, UINT32 params_len)
2186 ReverbImpl *This = ReverbImpl_from_IXAPOParameters(iface);
2187 TRACE("%p, %p, %u\n", This, params, params_len);
2190 static void WINAPI RVBXAPOParams_GetParameters(IXAPOParameters *iface, void *params,
2191 UINT32 params_len)
2193 ReverbImpl *This = ReverbImpl_from_IXAPOParameters(iface);
2194 TRACE("%p, %p, %u\n", This, params, params_len);
2197 static const IXAPOParametersVtbl RVBXAPOParameters_Vtbl = {
2198 RVBXAPOParams_QueryInterface,
2199 RVBXAPOParams_AddRef,
2200 RVBXAPOParams_Release,
2201 RVBXAPOParams_SetParameters,
2202 RVBXAPOParams_GetParameters
2205 struct xaudio2_cf {
2206 IClassFactory IClassFactory_iface;
2207 LONG ref;
2208 DWORD version;
2211 struct xaudio2_cf *impl_from_IClassFactory(IClassFactory *iface)
2213 return CONTAINING_RECORD(iface, struct xaudio2_cf, IClassFactory_iface);
2216 static HRESULT WINAPI XAudio2CF_QueryInterface(IClassFactory *iface, REFIID riid, void **ppobj)
2218 if(IsEqualGUID(riid, &IID_IUnknown)
2219 || IsEqualGUID(riid, &IID_IClassFactory))
2221 IClassFactory_AddRef(iface);
2222 *ppobj = iface;
2223 return S_OK;
2226 *ppobj = NULL;
2227 WARN("(%p)->(%s, %p): interface not found\n", iface, debugstr_guid(riid), ppobj);
2228 return E_NOINTERFACE;
2231 static ULONG WINAPI XAudio2CF_AddRef(IClassFactory *iface)
2233 struct xaudio2_cf *This = impl_from_IClassFactory(iface);
2234 ULONG ref = InterlockedIncrement(&This->ref);
2235 TRACE("(%p)->(): Refcount now %u\n", This, ref);
2236 return ref;
2239 static ULONG WINAPI XAudio2CF_Release(IClassFactory *iface)
2241 struct xaudio2_cf *This = impl_from_IClassFactory(iface);
2242 ULONG ref = InterlockedDecrement(&This->ref);
2243 TRACE("(%p)->(): Refcount now %u\n", This, ref);
2244 if (!ref)
2245 HeapFree(GetProcessHeap(), 0, This);
2246 return ref;
2249 static HRESULT initialize_mmdevices(IXAudio2Impl *This)
2251 IMMDeviceCollection *devcoll;
2252 UINT devcount;
2253 HRESULT hr;
2255 if(!This->devenum){
2256 hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL,
2257 CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void**)&This->devenum);
2258 if(FAILED(hr))
2259 return hr;
2262 hr = IMMDeviceEnumerator_EnumAudioEndpoints(This->devenum, eRender,
2263 DEVICE_STATE_ACTIVE, &devcoll);
2264 if(FAILED(hr)){
2265 return hr;
2268 hr = IMMDeviceCollection_GetCount(devcoll, &devcount);
2269 if(FAILED(hr)){
2270 IMMDeviceCollection_Release(devcoll);
2271 return hr;
2274 if(devcount > 0){
2275 UINT i, count = 1;
2276 IMMDevice *dev, *def_dev;
2278 /* make sure that device 0 is the default device */
2279 IMMDeviceEnumerator_GetDefaultAudioEndpoint(This->devenum, eRender, eConsole, &def_dev);
2281 This->devids = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *) * devcount);
2283 for(i = 0; i < devcount; ++i){
2284 hr = IMMDeviceCollection_Item(devcoll, i, &dev);
2285 if(SUCCEEDED(hr)){
2286 UINT idx;
2288 if(dev == def_dev)
2289 idx = 0;
2290 else{
2291 idx = count;
2292 ++count;
2295 hr = IMMDevice_GetId(dev, &This->devids[idx]);
2296 if(FAILED(hr)){
2297 WARN("GetId failed: %08x\n", hr);
2298 HeapFree(GetProcessHeap(), 0, This->devids);
2299 This->devids = NULL;
2300 IMMDevice_Release(dev);
2301 return hr;
2304 IMMDevice_Release(dev);
2305 }else{
2306 WARN("Item failed: %08x\n", hr);
2307 HeapFree(GetProcessHeap(), 0, This->devids);
2308 This->devids = NULL;
2309 IMMDeviceCollection_Release(devcoll);
2310 return hr;
2315 IMMDeviceCollection_Release(devcoll);
2317 This->ndevs = devcount;
2319 return S_OK;
2322 static HRESULT WINAPI XAudio2CF_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
2323 REFIID riid, void **ppobj)
2325 struct xaudio2_cf *This = impl_from_IClassFactory(iface);
2326 HRESULT hr;
2327 IXAudio2Impl *object;
2329 TRACE("(%p)->(%p,%s,%p)\n", This, pOuter, debugstr_guid(riid), ppobj);
2331 *ppobj = NULL;
2333 if(pOuter)
2334 return CLASS_E_NOAGGREGATION;
2336 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2337 if(!object)
2338 return E_OUTOFMEMORY;
2340 object->IXAudio20_iface.lpVtbl = &XAudio20_Vtbl;
2341 object->IXAudio22_iface.lpVtbl = &XAudio22_Vtbl;
2342 object->IXAudio27_iface.lpVtbl = &XAudio27_Vtbl;
2343 object->IXAudio2_iface.lpVtbl = &XAudio2_Vtbl;
2344 object->IXAudio20MasteringVoice_iface.lpVtbl = &XAudio20MasteringVoice_Vtbl;
2345 object->IXAudio23MasteringVoice_iface.lpVtbl = &XAudio23MasteringVoice_Vtbl;
2346 object->IXAudio2MasteringVoice_iface.lpVtbl = &XAudio2MasteringVoice_Vtbl;
2348 if(IsEqualGUID(riid, &IID_IXAudio27))
2349 object->version = This->version;
2350 else /* only xaudio 2.8 has a different IID */
2351 object->version = 28;
2353 list_init(&object->source_voices);
2354 list_init(&object->submix_voices);
2356 object->mmevt = CreateEventW(NULL, FALSE, FALSE, NULL);
2357 InitializeCriticalSection(&object->lock);
2358 object->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IXAudio2Impl.lock");
2360 hr = IXAudio2_QueryInterface(&object->IXAudio2_iface, riid, ppobj);
2361 if(FAILED(hr)){
2362 HeapFree(GetProcessHeap(), 0, object);
2363 return hr;
2366 hr = initialize_mmdevices(object);
2367 if(FAILED(hr)){
2368 IUnknown_Release((IUnknown*)*ppobj);
2369 return hr;
2372 object->ncbs = 4;
2373 object->cbs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->ncbs * sizeof(*object->cbs));
2375 IXAudio2_StartEngine(&object->IXAudio2_iface);
2377 TRACE("Created XAudio version %u: %p\n", object->version, object);
2379 return hr;
2382 struct xapo_cf {
2383 IClassFactory IClassFactory_iface;
2384 LONG ref;
2385 DWORD version;
2386 const CLSID *class;
2389 struct xapo_cf *xapo_impl_from_IClassFactory(IClassFactory *iface)
2391 return CONTAINING_RECORD(iface, struct xapo_cf, IClassFactory_iface);
2394 static ULONG WINAPI xapo_AddRef(IClassFactory *iface)
2396 struct xapo_cf *This = xapo_impl_from_IClassFactory(iface);
2397 ULONG ref = InterlockedIncrement(&This->ref);
2398 TRACE("(%p)->(): Refcount now %u\n", This, ref);
2399 return ref;
2402 static ULONG WINAPI xapo_Release(IClassFactory *iface)
2404 struct xapo_cf *This = xapo_impl_from_IClassFactory(iface);
2405 ULONG ref = InterlockedDecrement(&This->ref);
2406 TRACE("(%p)->(): Refcount now %u\n", This, ref);
2407 if (!ref)
2408 HeapFree(GetProcessHeap(), 0, This);
2409 return ref;
2412 static HRESULT WINAPI xapo_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
2413 REFIID riid, void **ppobj)
2415 struct xapo_cf *This = xapo_impl_from_IClassFactory(iface);
2416 HRESULT hr;
2418 TRACE("(%p)->(%p,%s,%p)\n", This, pOuter, debugstr_guid(riid), ppobj);
2420 *ppobj = NULL;
2422 if(pOuter)
2423 return CLASS_E_NOAGGREGATION;
2425 if(IsEqualGUID(This->class, &CLSID_AudioVolumeMeter)){
2426 VUMeterImpl *object;
2428 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2429 if(!object)
2430 return E_OUTOFMEMORY;
2432 object->IXAPO_iface.lpVtbl = &VUMXAPO_Vtbl;
2433 object->IXAPOParameters_iface.lpVtbl = &VUMXAPOParameters_Vtbl;
2434 object->version = This->version;
2436 hr = IXAPO_QueryInterface(&object->IXAPO_iface, riid, ppobj);
2437 if(FAILED(hr)){
2438 HeapFree(GetProcessHeap(), 0, object);
2439 return hr;
2441 }else if(IsEqualGUID(This->class, &CLSID_AudioReverb)){
2442 ReverbImpl *object;
2444 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2445 if(!object)
2446 return E_OUTOFMEMORY;
2448 object->IXAPO_iface.lpVtbl = &RVBXAPO_Vtbl;
2449 object->IXAPOParameters_iface.lpVtbl = &RVBXAPOParameters_Vtbl;
2450 object->version = This->version;
2452 hr = IXAPO_QueryInterface(&object->IXAPO_iface, riid, ppobj);
2453 if(FAILED(hr)){
2454 HeapFree(GetProcessHeap(), 0, object);
2455 return hr;
2457 }else
2458 return E_INVALIDARG;
2460 return S_OK;
2463 static HRESULT WINAPI XAudio2CF_LockServer(IClassFactory *iface, BOOL dolock)
2465 FIXME("(static)->(%d): stub!\n", dolock);
2466 return S_OK;
2469 static const IClassFactoryVtbl XAudio2CF_Vtbl =
2471 XAudio2CF_QueryInterface,
2472 XAudio2CF_AddRef,
2473 XAudio2CF_Release,
2474 XAudio2CF_CreateInstance,
2475 XAudio2CF_LockServer
2478 static const IClassFactoryVtbl xapo_Vtbl =
2480 XAudio2CF_QueryInterface,
2481 xapo_AddRef,
2482 xapo_Release,
2483 xapo_CreateInstance,
2484 XAudio2CF_LockServer
2487 static IClassFactory *make_xaudio2_factory(DWORD version)
2489 struct xapo_cf *ret = HeapAlloc(GetProcessHeap(), 0, sizeof(struct xaudio2_cf));
2490 ret->IClassFactory_iface.lpVtbl = &XAudio2CF_Vtbl;
2491 ret->version = version;
2492 ret->ref = 0;
2493 return &ret->IClassFactory_iface;
2496 static IClassFactory *make_xapo_factory(REFCLSID clsid, DWORD version)
2498 struct xapo_cf *ret = HeapAlloc(GetProcessHeap(), 0, sizeof(struct xaudio2_cf));
2499 ret->IClassFactory_iface.lpVtbl = &xapo_Vtbl;
2500 ret->version = version;
2501 ret->class = clsid;
2502 ret->ref = 0;
2503 return &ret->IClassFactory_iface;
2506 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
2508 IClassFactory *factory = NULL;
2510 TRACE("(%s, %s, %p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
2512 if(IsEqualGUID(rclsid, &CLSID_XAudio20)){
2513 factory = make_xaudio2_factory(20);
2514 }else if(IsEqualGUID(rclsid, &CLSID_XAudio21)){
2515 factory = make_xaudio2_factory(21);
2516 }else if(IsEqualGUID(rclsid, &CLSID_XAudio22)){
2517 factory = make_xaudio2_factory(22);
2518 }else if(IsEqualGUID(rclsid, &CLSID_XAudio23)){
2519 factory = make_xaudio2_factory(23);
2520 }else if(IsEqualGUID(rclsid, &CLSID_XAudio24)){
2521 factory = make_xaudio2_factory(24);
2522 }else if(IsEqualGUID(rclsid, &CLSID_XAudio25)){
2523 factory = make_xaudio2_factory(25);
2524 }else if(IsEqualGUID(rclsid, &CLSID_XAudio26)){
2525 factory = make_xaudio2_factory(26);
2526 }else if(IsEqualGUID(rclsid, &CLSID_XAudio2)){
2527 factory = make_xaudio2_factory(27);
2529 }else if(IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter20)){
2530 factory = make_xapo_factory(&CLSID_AudioVolumeMeter, 20);
2531 }else if(IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter21)){
2532 factory = make_xapo_factory(&CLSID_AudioVolumeMeter, 21);
2533 }else if(IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter22)){
2534 factory = make_xapo_factory(&CLSID_AudioVolumeMeter, 22);
2535 }else if(IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter23)){
2536 factory = make_xapo_factory(&CLSID_AudioVolumeMeter, 23);
2537 }else if(IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter24)){
2538 factory = make_xapo_factory(&CLSID_AudioVolumeMeter, 24);
2539 }else if(IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter25)){
2540 factory = make_xapo_factory(&CLSID_AudioVolumeMeter, 25);
2541 }else if(IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter26)){
2542 factory = make_xapo_factory(&CLSID_AudioVolumeMeter, 26);
2543 }else if(IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter)){
2544 factory = make_xapo_factory(&CLSID_AudioVolumeMeter, 27);
2546 }else if(IsEqualGUID(rclsid, &CLSID_AudioReverb20)){
2547 factory = make_xapo_factory(&CLSID_AudioReverb, 20);
2549 }else if(IsEqualGUID(rclsid, &CLSID_AudioReverb21) ||
2550 IsEqualGUID(rclsid, &CLSID_WINE_FXReverb10)){
2551 factory = make_xapo_factory(&CLSID_AudioReverb, 21);
2553 }else if(IsEqualGUID(rclsid, &CLSID_AudioReverb22) ||
2554 IsEqualGUID(rclsid, &CLSID_WINE_FXReverb11)){
2555 factory = make_xapo_factory(&CLSID_AudioReverb, 22);
2557 }else if(IsEqualGUID(rclsid, &CLSID_AudioReverb23) ||
2558 IsEqualGUID(rclsid, &CLSID_WINE_FXReverb12)){
2559 factory = make_xapo_factory(&CLSID_AudioReverb, 23);
2561 }else if(IsEqualGUID(rclsid, &CLSID_AudioReverb24) ||
2562 IsEqualGUID(rclsid, &CLSID_WINE_FXReverb13)){
2563 factory = make_xapo_factory(&CLSID_AudioReverb, 24);
2565 }else if(IsEqualGUID(rclsid, &CLSID_AudioReverb25)){
2566 factory = make_xapo_factory(&CLSID_AudioReverb, 25);
2568 }else if(IsEqualGUID(rclsid, &CLSID_AudioReverb26) ||
2569 IsEqualGUID(rclsid, &CLSID_WINE_FXReverb14)){
2570 factory = make_xapo_factory(&CLSID_AudioReverb, 26);
2572 }else if(IsEqualGUID(rclsid, &CLSID_AudioReverb) ||
2573 IsEqualGUID(rclsid, &CLSID_WINE_FXReverb15)){
2574 factory = make_xapo_factory(&CLSID_AudioReverb, 27);
2576 }else if(IsEqualGUID(rclsid, &CLSID_WINE_FXReverb28)){
2577 factory = make_xapo_factory(&CLSID_AudioReverb, 28);
2580 if(!factory) return CLASS_E_CLASSNOTAVAILABLE;
2582 return IClassFactory_QueryInterface(factory, riid, ppv);
2585 /* returns TRUE if there is more data avilable in the buffer, FALSE if the
2586 * buffer's data has all been queued */
2587 static BOOL xa2buffer_queue_period(XA2SourceImpl *src, XA2Buffer *buf, ALuint al_buf)
2589 UINT32 submit_bytes;
2590 const BYTE *submit_buf = NULL;
2592 if(buf->offs_bytes >= buf->cur_end_bytes){
2593 WARN("Shouldn't happen: Trying to push frames from a spent buffer?\n");
2594 return FALSE;
2597 submit_bytes = min(src->xa2->period_frames * src->submit_blocksize, buf->cur_end_bytes - buf->offs_bytes);
2598 submit_buf = buf->xa2buffer.pAudioData + buf->offs_bytes;
2599 buf->offs_bytes += submit_bytes;
2601 alBufferData(al_buf, src->al_fmt, submit_buf, submit_bytes,
2602 src->fmt->nSamplesPerSec);
2604 alSourceQueueBuffers(src->al_src, 1, &al_buf);
2606 src->in_al_bytes += submit_bytes;
2607 src->al_bufs_used++;
2609 buf->latest_al_buf = al_buf;
2611 TRACE("queueing %u bytes, now %u in AL\n", submit_bytes, src->in_al_bytes);
2613 return buf->offs_bytes < buf->cur_end_bytes;
2616 /* Looping:
2618 * The looped section of a buffer is a subset of the play area which is looped
2619 * LoopCount times.
2621 * v PlayBegin
2622 * vvvvvvvvvvvvvvvvvv PlayLength
2623 * v (PlayEnd)
2624 * [-----PPPLLLLLLLLPPPPPPP------]
2625 * ^ LoopBegin
2626 * ^^^^^^^^ LoopLength
2627 * ^ (LoopEnd)
2629 * In the simple case, playback will start at PlayBegin. At LoopEnd, playback
2630 * will move to LoopBegin and repeat that loop LoopCount times. Then, playback
2631 * will cease at LoopEnd.
2633 * If PlayLength is zero, then PlayEnd is the end of the buffer.
2635 * If LoopLength is zero, then LoopEnd is PlayEnd.
2637 * For corner cases and version differences, see tests.
2639 static void update_source_state(XA2SourceImpl *src)
2641 int i;
2642 ALint processed;
2643 ALint bufpos;
2645 alGetSourcei(src->al_src, AL_BUFFERS_PROCESSED, &processed);
2647 if(processed > 0){
2648 ALuint al_buffers[XAUDIO2_MAX_QUEUED_BUFFERS];
2650 alSourceUnqueueBuffers(src->al_src, processed, al_buffers);
2651 src->first_al_buf += processed;
2652 src->first_al_buf %= XAUDIO2_MAX_QUEUED_BUFFERS;
2653 src->al_bufs_used -= processed;
2655 for(i = 0; i < processed; ++i){
2656 ALint bufsize;
2658 alGetBufferi(al_buffers[i], AL_SIZE, &bufsize);
2660 src->in_al_bytes -= bufsize;
2661 src->played_frames += bufsize / src->submit_blocksize;
2663 if(al_buffers[i] == src->buffers[src->first_buf].latest_al_buf){
2664 DWORD old_buf = src->first_buf;
2666 src->first_buf++;
2667 src->first_buf %= XAUDIO2_MAX_QUEUED_BUFFERS;
2668 src->nbufs--;
2670 TRACE("%p: done with buffer %u\n", src, old_buf);
2672 if(src->buffers[old_buf].xa2buffer.Flags & XAUDIO2_END_OF_STREAM)
2673 src->played_frames = 0;
2675 if(src->cb){
2676 IXAudio2VoiceCallback_OnBufferEnd(src->cb,
2677 src->buffers[old_buf].xa2buffer.pContext);
2678 if(src->buffers[old_buf].xa2buffer.Flags & XAUDIO2_END_OF_STREAM)
2679 IXAudio2VoiceCallback_OnStreamEnd(src->cb);
2681 if(src->nbufs > 0)
2682 IXAudio2VoiceCallback_OnBufferStart(src->cb,
2683 src->buffers[src->first_buf].xa2buffer.pContext);
2689 alGetSourcei(src->al_src, AL_BYTE_OFFSET, &bufpos);
2691 /* maintain 4 periods in AL */
2692 while(src->cur_buf != (src->first_buf + src->nbufs) % XAUDIO2_MAX_QUEUED_BUFFERS &&
2693 src->in_al_bytes - bufpos < 4 * src->xa2->period_frames * src->submit_blocksize){
2694 TRACE("%p: going to queue a period from buffer %u\n", src, src->cur_buf);
2696 /* starting from an empty buffer */
2697 if(src->cb && src->cur_buf == src->first_buf && src->buffers[src->cur_buf].offs_bytes == 0 && !src->buffers[src->cur_buf].looped)
2698 IXAudio2VoiceCallback_OnBufferStart(src->cb,
2699 src->buffers[src->first_buf].xa2buffer.pContext);
2701 if(!xa2buffer_queue_period(src, &src->buffers[src->cur_buf],
2702 src->al_bufs[(src->first_al_buf + src->al_bufs_used) % XAUDIO2_MAX_QUEUED_BUFFERS])){
2703 XA2Buffer *cur = &src->buffers[src->cur_buf];
2705 if(cur->looped < cur->xa2buffer.LoopCount){
2706 if(cur->xa2buffer.LoopCount != XAUDIO2_LOOP_INFINITE)
2707 ++cur->looped;
2708 else
2709 cur->looped = 1; /* indicate that we are executing a loop */
2711 cur->offs_bytes = cur->xa2buffer.LoopBegin;
2712 if(cur->looped == cur->xa2buffer.LoopCount)
2713 cur->cur_end_bytes = cur->play_end_bytes;
2714 else
2715 cur->cur_end_bytes = cur->loop_end_bytes;
2717 if(src->cb)
2718 IXAudio2VoiceCallback_OnLoopEnd(src->cb,
2719 src->buffers[src->cur_buf].xa2buffer.pContext);
2721 }else{
2722 /* buffer is spent, move on */
2723 src->cur_buf++;
2724 src->cur_buf %= XAUDIO2_MAX_QUEUED_BUFFERS;
2730 static void do_engine_tick(IXAudio2Impl *This)
2732 BYTE *buf;
2733 XA2SourceImpl *src;
2734 HRESULT hr;
2735 UINT32 nframes, i, pad;
2737 /* maintain up to 3 periods in mmdevapi */
2738 hr = IAudioClient_GetCurrentPadding(This->aclient, &pad);
2739 if(FAILED(hr)){
2740 WARN("GetCurrentPadding failed: 0x%x\n", hr);
2741 return;
2744 nframes = This->period_frames * 3 - pad;
2746 TRACE("frames available: %u\n", nframes);
2748 if(nframes < This->period_frames)
2749 return;
2751 if(!nframes)
2752 return;
2754 for(i = 0; i < This->ncbs && This->cbs[i]; ++i)
2755 IXAudio2EngineCallback_OnProcessingPassStart(This->cbs[i]);
2757 LIST_FOR_EACH_ENTRY(src, &This->source_voices, XA2SourceImpl, entry){
2758 ALint st = 0;
2760 EnterCriticalSection(&src->lock);
2762 if(!src->in_use || !src->running){
2763 LeaveCriticalSection(&src->lock);
2764 continue;
2767 if(src->cb){
2768 if(This->version == 20)
2769 IXAudio20VoiceCallback_OnVoiceProcessingPassStart((IXAudio20VoiceCallback*)src->cb);
2770 else
2771 /* TODO: detect incoming underrun and inform callback */
2772 IXAudio2VoiceCallback_OnVoiceProcessingPassStart(src->cb, 0);
2775 update_source_state(src);
2777 alGetSourcei(src->al_src, AL_SOURCE_STATE, &st);
2778 if(st != AL_PLAYING)
2779 alSourcePlay(src->al_src);
2781 if(src->cb)
2782 IXAudio2VoiceCallback_OnVoiceProcessingPassEnd(src->cb);
2784 LeaveCriticalSection(&src->lock);
2787 hr = IAudioRenderClient_GetBuffer(This->render, nframes, &buf);
2788 if(FAILED(hr))
2789 WARN("GetBuffer failed: %08x\n", hr);
2791 palcRenderSamplesSOFT(This->al_device, buf, nframes);
2793 hr = IAudioRenderClient_ReleaseBuffer(This->render, nframes, 0);
2794 if(FAILED(hr))
2795 WARN("ReleaseBuffer failed: %08x\n", hr);
2797 for(i = 0; i < This->ncbs && This->cbs[i]; ++i)
2798 IXAudio2EngineCallback_OnProcessingPassEnd(This->cbs[i]);
2801 static DWORD WINAPI engine_threadproc(void *arg)
2803 IXAudio2Impl *This = arg;
2804 while(1){
2805 WaitForSingleObject(This->mmevt, INFINITE);
2807 if(This->stop_engine)
2808 break;
2810 EnterCriticalSection(&This->lock);
2812 if(!This->running || !This->aclient){
2813 LeaveCriticalSection(&This->lock);
2814 continue;
2817 do_engine_tick(This);
2819 LeaveCriticalSection(&This->lock);
2821 return 0;