2 * Copyright 2010 Maarten Lankhorst for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #define NONAMELESSUNION
27 #elif defined(HAVE_OPENAL_AL_H)
28 #include <OpenAL/al.h>
29 #include <OpenAL/alc.h>
36 #include "wine/debug.h"
37 #include "wine/unicode.h"
40 #include "mmdeviceapi.h"
43 #include "audioclient.h"
44 #include "endpointvolume.h"
45 #include "audiopolicy.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi
);
53 typedef struct ACRender ACRender
;
54 typedef struct ACCapture ACCapture
;
55 typedef struct ACSession ACSession
;
56 typedef struct ASVolume ASVolume
;
57 typedef struct AClock AClock
;
59 typedef struct ACImpl
{
60 const IAudioClientVtbl
*lpVtbl
;
65 CRITICAL_SECTION
*crst
;
67 DWORD locked
, flags
, bufsize
, pad
, padpartial
, ofs
, psize
, candisconnect
;
72 REFERENCE_TIME laststamp
;
85 const IAudioRenderClientVtbl
*lpVtbl
;
91 const IAudioCaptureClientVtbl
*lpVtbl
;
97 const IAudioSessionControl2Vtbl
*lpVtbl
;
103 const ISimpleAudioVolumeVtbl
*lpVtbl
;
109 const IAudioClockVtbl
*lpVtbl
;
110 const IAudioClock2Vtbl
*lp2Vtbl
;
115 static const IAudioClientVtbl ACImpl_Vtbl
;
116 static const IAudioRenderClientVtbl ACRender_Vtbl
;
117 static const IAudioCaptureClientVtbl ACCapture_Vtbl
;
118 static const IAudioSessionControl2Vtbl ACSession_Vtbl
;
119 static const ISimpleAudioVolumeVtbl ASVolume_Vtbl
;
120 static const IAudioClockVtbl AClock_Vtbl
;
121 static const IAudioClock2Vtbl AClock2_Vtbl
;
123 static HRESULT
AudioRenderClient_Create(ACImpl
*parent
, ACRender
**ppv
);
124 static void AudioRenderClient_Destroy(ACRender
*This
);
125 static HRESULT
AudioCaptureClient_Create(ACImpl
*parent
, ACCapture
**ppv
);
126 static void AudioCaptureClient_Destroy(ACCapture
*This
);
127 static HRESULT
AudioSessionControl_Create(ACImpl
*parent
, ACSession
**ppv
);
128 static void AudioSessionControl_Destroy(ACSession
*This
);
129 static HRESULT
AudioSimpleVolume_Create(ACImpl
*parent
, ASVolume
**ppv
);
130 static void AudioSimpleVolume_Destroy(ASVolume
*This
);
131 static HRESULT
AudioClock_Create(ACImpl
*parent
, AClock
**ppv
);
132 static void AudioClock_Destroy(AClock
*This
);
134 static int valid_dev(ACImpl
*This
)
138 if (This
->parent
->flow
== eRender
&& This
->dev
!= This
->parent
->device
)
143 static int get_format_PCM(WAVEFORMATEX
*format
)
145 if (format
->nChannels
> 2) {
146 FIXME("nChannels > 2 not documented for WAVE_FORMAT_PCM!\n");
152 if (format
->nBlockAlign
!= format
->wBitsPerSample
/8*format
->nChannels
) {
153 WARN("Invalid nBlockAlign %u, from %u %u\n",
154 format
->nBlockAlign
, format
->wBitsPerSample
, format
->nChannels
);
158 switch (format
->wBitsPerSample
) {
160 switch (format
->nChannels
) {
161 case 1: return AL_FORMAT_MONO8
;
162 case 2: return AL_FORMAT_STEREO8
;
166 switch (format
->nChannels
) {
167 case 1: return AL_FORMAT_MONO16
;
168 case 2: return AL_FORMAT_STEREO16
;
173 if (!(format
->wBitsPerSample
% 8))
174 WARN("Could not get OpenAL format (%d-bit, %d channels)\n",
175 format
->wBitsPerSample
, format
->nChannels
);
179 /* Speaker configs */
180 #define MONO SPEAKER_FRONT_CENTER
181 #define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)
182 #define REAR (SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
183 #define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
184 #define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
185 #define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
186 #define X7DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
188 static int get_format_EXT(WAVEFORMATEX
*format
)
190 WAVEFORMATEXTENSIBLE
*wfe
;
192 if(format
->cbSize
< sizeof(WAVEFORMATEXTENSIBLE
)-sizeof(WAVEFORMATEX
)) {
193 WARN("Invalid cbSize specified for WAVE_FORMAT_EXTENSIBLE (%d)\n", format
->cbSize
);
197 wfe
= (WAVEFORMATEXTENSIBLE
*)format
;
198 wfe
->Format
.cbSize
= sizeof(WAVEFORMATEXTENSIBLE
)-sizeof(WAVEFORMATEX
);
199 if (wfe
->Samples
.wValidBitsPerSample
&&
200 wfe
->Samples
.wValidBitsPerSample
!= format
->wBitsPerSample
) {
201 FIXME("wValidBitsPerSample(%u) != wBitsPerSample(%u) unsupported\n",
202 wfe
->Samples
.wValidBitsPerSample
, format
->wBitsPerSample
);
206 TRACE("Extensible values:\n"
208 " ChannelMask = 0x%08x\n"
210 wfe
->Samples
.wReserved
, wfe
->dwChannelMask
,
211 debugstr_guid(&wfe
->SubFormat
));
213 if (wfe
->dwChannelMask
!= MONO
214 && wfe
->dwChannelMask
!= STEREO
215 && !palIsExtensionPresent("AL_EXT_MCFORMATS")) {
216 /* QUAD PCM might still work, special case */
217 if (palIsExtensionPresent("AL_LOKI_quadriphonic")
218 && IsEqualGUID(&wfe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
)
219 && wfe
->dwChannelMask
== QUAD
) {
220 if (format
->wBitsPerSample
== 16)
221 return AL_FORMAT_QUAD16_LOKI
;
222 else if (format
->wBitsPerSample
== 8)
223 return AL_FORMAT_QUAD8_LOKI
;
225 WARN("Not all formats available\n");
229 if(IsEqualGUID(&wfe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
)) {
230 if (format
->wBitsPerSample
== 8) {
231 switch (wfe
->dwChannelMask
) {
232 case MONO
: return AL_FORMAT_MONO8
;
233 case STEREO
: return AL_FORMAT_STEREO8
;
234 case REAR
: return AL_FORMAT_REAR8
;
235 case QUAD
: return AL_FORMAT_QUAD8
;
236 case X5DOT1
: return AL_FORMAT_51CHN8
;
237 case X6DOT1
: return AL_FORMAT_61CHN8
;
238 case X7DOT1
: return AL_FORMAT_71CHN8
;
241 } else if (format
->wBitsPerSample
== 16) {
242 switch (wfe
->dwChannelMask
) {
243 case MONO
: return AL_FORMAT_MONO16
;
244 case STEREO
: return AL_FORMAT_STEREO16
;
245 case REAR
: return AL_FORMAT_REAR16
;
246 case QUAD
: return AL_FORMAT_QUAD16
;
247 case X5DOT1
: return AL_FORMAT_51CHN16
;
248 case X6DOT1
: return AL_FORMAT_61CHN16
;
249 case X7DOT1
: return AL_FORMAT_71CHN16
;
253 else if (!(format
->wBitsPerSample
% 8))
254 ERR("Could not get OpenAL PCM format (%d-bit, mask 0x%08x)\n",
255 format
->wBitsPerSample
, wfe
->dwChannelMask
);
258 else if(IsEqualGUID(&wfe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
)) {
259 if (format
->wBitsPerSample
!= 32) {
260 WARN("Invalid valid bits %u/32\n", format
->wBitsPerSample
);
263 switch (wfe
->dwChannelMask
) {
264 case MONO
: return AL_FORMAT_MONO_FLOAT32
;
265 case STEREO
: return AL_FORMAT_STEREO_FLOAT32
;
266 case REAR
: return AL_FORMAT_REAR32
;
267 case QUAD
: return AL_FORMAT_QUAD32
;
268 case X5DOT1
: return AL_FORMAT_51CHN32
;
269 case X6DOT1
: return AL_FORMAT_61CHN32
;
270 case X7DOT1
: return AL_FORMAT_71CHN32
;
272 ERR("Could not get OpenAL float format (%d-bit, mask 0x%08x)\n",
273 format
->wBitsPerSample
, wfe
->dwChannelMask
);
277 else if (!IsEqualGUID(&wfe
->SubFormat
, &GUID_NULL
))
278 ERR("Unhandled extensible format: %s\n", debugstr_guid(&wfe
->SubFormat
));
282 static ALint
get_format(WAVEFORMATEX
*in
)
285 if (in
->wFormatTag
== WAVE_FORMAT_PCM
)
286 ret
= get_format_PCM(in
);
287 else if (in
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
288 ret
= get_format_EXT(in
);
292 static REFERENCE_TIME
gettime(void) {
293 LARGE_INTEGER stamp
, freq
;
294 QueryPerformanceCounter(&stamp
);
295 QueryPerformanceFrequency(&freq
);
296 return (stamp
.QuadPart
* (INT64
)10000000) / freq
.QuadPart
;
299 HRESULT
AudioClient_Create(MMDevice
*parent
, IAudioClient
**ppv
)
301 ACImpl
*This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*This
));
302 *ppv
= (IAudioClient
*)This
;
304 return E_OUTOFMEMORY
;
305 This
->crst
= &parent
->crst
;
306 This
->lpVtbl
= &ACImpl_Vtbl
;
308 This
->parent
= parent
;
312 static void AudioClient_Destroy(ACImpl
*This
)
315 DeleteTimerQueueTimer(NULL
, This
->timer_id
, INVALID_HANDLE_VALUE
);
317 AudioRenderClient_Destroy(This
->render
);
319 AudioCaptureClient_Destroy(This
->capture
);
321 AudioSessionControl_Destroy(This
->session
);
323 AudioSimpleVolume_Destroy(This
->svolume
);
325 AudioClock_Destroy(This
->clock
);
326 if (!valid_dev(This
))
327 TRACE("Not destroying device since none exists\n");
328 else if (This
->parent
->flow
== eRender
) {
329 setALContext(This
->parent
->ctx
);
330 IAudioClient_Stop((IAudioClient
*)This
);
331 IAudioClient_Reset((IAudioClient
*)This
);
332 palDeleteSources(1, &This
->source
);
336 else if (This
->parent
->flow
== eCapture
)
337 palcCaptureCloseDevice(This
->dev
);
338 HeapFree(GetProcessHeap(), 0, This
->pwfx
);
339 HeapFree(GetProcessHeap(), 0, This
->buffer
);
340 HeapFree(GetProcessHeap(), 0, This
);
343 static void CALLBACK
AC_tick(void *data
, BOOLEAN fired
)
348 EnterCriticalSection(This
->crst
);
350 IAudioClient_GetCurrentPadding((IAudioClient
*)This
, &pad
);
351 LeaveCriticalSection(This
->crst
);
354 /* Open device and set/update internal mixing format based on information
355 * openal provides us. if the device cannot be opened, assume 48khz
356 * Guessing the frequency is harmless, since if GetMixFormat fails to open
357 * the device, then Initialize will likely fail as well
359 static HRESULT
AC_OpenRenderAL(ACImpl
*This
)
361 char alname
[MAX_PATH
];
362 MMDevice
*cur
= This
->parent
;
364 alname
[sizeof(alname
)-1] = 0;
366 return cur
->ctx
? S_OK
: AUDCLNT_E_SERVICE_NOT_RUNNING
;
368 WideCharToMultiByte(CP_UNIXCP
, 0, cur
->alname
, -1,
369 alname
, sizeof(alname
)/sizeof(*alname
)-1, NULL
, NULL
);
370 cur
->device
= palcOpenDevice(alname
);
372 ALCenum err
= palcGetError(NULL
);
373 WARN("Could not open device %s: 0x%04x\n", alname
, err
);
374 return AUDCLNT_E_DEVICE_IN_USE
;
376 cur
->ctx
= palcCreateContext(cur
->device
, NULL
);
378 ALCenum err
= palcGetError(cur
->device
);
379 ERR("Could not create context: 0x%04x\n", err
);
380 return AUDCLNT_E_SERVICE_NOT_RUNNING
;
383 return AUDCLNT_E_DEVICE_IN_USE
;
387 static HRESULT
AC_OpenCaptureAL(ACImpl
*This
)
389 char alname
[MAX_PATH
];
392 freq
= This
->pwfx
->nSamplesPerSec
;
393 size
= This
->bufsize
;
395 alname
[sizeof(alname
)-1] = 0;
397 FIXME("Attempting to open device while already open\n");
400 WideCharToMultiByte(CP_UNIXCP
, 0, This
->parent
->alname
, -1,
401 alname
, sizeof(alname
)/sizeof(*alname
)-1, NULL
, NULL
);
402 This
->dev
= palcCaptureOpenDevice(alname
, freq
, This
->format
, size
);
404 ALCenum err
= palcGetError(NULL
);
405 FIXME("Could not open device %s with buf size %u: 0x%04x\n",
406 alname
, This
->bufsize
, err
);
407 return AUDCLNT_E_DEVICE_IN_USE
;
412 static HRESULT WINAPI
AC_QueryInterface(IAudioClient
*iface
, REFIID riid
, void **ppv
)
414 TRACE("(%p)->(%s,%p)\n", iface
, debugstr_guid(riid
), ppv
);
419 if (IsEqualIID(riid
, &IID_IUnknown
)
420 || IsEqualIID(riid
, &IID_IAudioClient
))
423 IUnknown_AddRef((IUnknown
*)*ppv
);
426 WARN("Unknown interface %s\n", debugstr_guid(riid
));
427 return E_NOINTERFACE
;
430 static ULONG WINAPI
AC_AddRef(IAudioClient
*iface
)
432 ACImpl
*This
= (ACImpl
*)iface
;
434 ref
= InterlockedIncrement(&This
->ref
);
435 TRACE("Refcount now %i\n", ref
);
439 static ULONG WINAPI
AC_Release(IAudioClient
*iface
)
441 ACImpl
*This
= (ACImpl
*)iface
;
443 ref
= InterlockedDecrement(&This
->ref
);
444 TRACE("Refcount now %i\n", ref
);
446 AudioClient_Destroy(This
);
450 static HRESULT WINAPI
AC_Initialize(IAudioClient
*iface
, AUDCLNT_SHAREMODE mode
, DWORD flags
, REFERENCE_TIME duration
, REFERENCE_TIME period
, const WAVEFORMATEX
*pwfx
, const GUID
*sessionguid
)
452 ACImpl
*This
= (ACImpl
*)iface
;
455 REFERENCE_TIME time
, bufsize
;
457 TRACE("(%p)->(%x,%x,%u,%u,%p,%s)\n", This
, mode
, flags
, (int)duration
, (int)period
, pwfx
, debugstr_guid(sessionguid
));
459 return AUDCLNT_E_ALREADY_INITIALIZED
;
460 if (mode
!= AUDCLNT_SHAREMODE_SHARED
461 && mode
!= AUDCLNT_SHAREMODE_EXCLUSIVE
) {
462 WARN("Unknown mode %x\n", mode
);
463 return AUDCLNT_E_NOT_INITIALIZED
;
466 if (flags
& ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS
467 |AUDCLNT_STREAMFLAGS_LOOPBACK
468 |AUDCLNT_STREAMFLAGS_EVENTCALLBACK
469 |AUDCLNT_STREAMFLAGS_NOPERSIST
470 |AUDCLNT_STREAMFLAGS_RATEADJUST
471 |AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED
472 |AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE
473 |AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED
)) {
474 WARN("Unknown flags 0x%08x\n", flags
);
478 WARN("Flags 0x%08x ignored\n", flags
);
482 WARN("Session guid %s ignored\n", debugstr_guid(sessionguid
));
484 hr
= IAudioClient_IsFormatSupported(iface
, mode
, pwfx
, &pwfx2
);
485 CoTaskMemFree(pwfx2
);
486 if (FAILED(hr
) || pwfx2
) {
487 WARN("Format not supported, or had to be modified!\n");
488 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
490 EnterCriticalSection(This
->crst
);
491 HeapFree(GetProcessHeap(), 0, This
->pwfx
);
492 This
->pwfx
= HeapAlloc(GetProcessHeap(), 0, sizeof(*pwfx
) + pwfx
->cbSize
);
497 memcpy(This
->pwfx
, pwfx
, sizeof(*pwfx
) + pwfx
->cbSize
);
498 if (pwfx
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
) {
499 WAVEFORMATEXTENSIBLE
*wfe
= (WAVEFORMATEXTENSIBLE
*)This
->pwfx
;
500 switch (pwfx
->nChannels
) {
501 case 1: wfe
->dwChannelMask
= MONO
; break;
502 case 2: wfe
->dwChannelMask
= STEREO
; break;
503 case 4: wfe
->dwChannelMask
= QUAD
; break;
504 case 6: wfe
->dwChannelMask
= X5DOT1
; break;
505 case 7: wfe
->dwChannelMask
= X6DOT1
; break;
506 case 8: wfe
->dwChannelMask
= X7DOT1
; break;
508 ERR("How did we end up with %i channels?\n", pwfx
->nChannels
);
509 hr
= AUDCLNT_E_UNSUPPORTED_FORMAT
;
514 hr
= IAudioClient_GetDevicePeriod(iface
, &time
, NULL
);
518 This
->psize
= (DWORD64
)This
->pwfx
->nSamplesPerSec
* time
/ (DWORD64
)10000000;
519 if (duration
> 20000000)
522 bufsize
= duration
/ time
* This
->psize
;
524 bufsize
+= This
->psize
;
525 This
->bufsize
= bufsize
;
526 This
->psize
*= This
->pwfx
->nBlockAlign
;
527 bufsize
*= pwfx
->nBlockAlign
;
529 This
->format
= get_format(This
->pwfx
);
530 if (This
->parent
->flow
== eRender
) {
532 ALuint buf
= 0, towrite
;
534 hr
= AC_OpenRenderAL(This
);
535 This
->dev
= This
->parent
->device
;
539 /* Test the returned format */
540 towrite
= sizeof(silence
);
541 towrite
-= towrite
% This
->pwfx
->nBlockAlign
;
542 if (This
->pwfx
->wBitsPerSample
!= 8)
543 memset(silence
, 0, sizeof(silence
));
545 memset(silence
, 128, sizeof(silence
));
546 setALContext(This
->parent
->ctx
);
548 palGenBuffers(1, &buf
);
549 palBufferData(buf
, This
->format
, silence
, towrite
, This
->pwfx
->nSamplesPerSec
);
550 palDeleteBuffers(1, &buf
);
552 hr
= AUDCLNT_E_UNSUPPORTED_FORMAT
;
553 else if (!This
->source
) {
554 palGenSources(1, &This
->source
);
555 palSourcei(This
->source
, AL_LOOPING
, AL_FALSE
);
561 hr
= AC_OpenCaptureAL(This
);
566 This
->candisconnect
= palcIsExtensionPresent(This
->dev
, "ALC_EXT_disconnect");
567 This
->buffer
= HeapAlloc(GetProcessHeap(), 0, bufsize
);
574 This
->running
= FALSE
;
577 LeaveCriticalSection(This
->crst
);
581 static HRESULT WINAPI
AC_GetBufferSize(IAudioClient
*iface
, UINT32
*frames
)
583 ACImpl
*This
= (ACImpl
*)iface
;
584 TRACE("(%p)->(%p)\n", This
, frames
);
586 return AUDCLNT_E_NOT_INITIALIZED
;
589 *frames
= This
->bufsize
;
593 static HRESULT WINAPI
AC_GetStreamLatency(IAudioClient
*iface
, REFERENCE_TIME
*latency
)
595 ACImpl
*This
= (ACImpl
*)iface
;
596 TRACE("(%p)->(%p)\n", This
, latency
);
599 return AUDCLNT_E_NOT_INITIALIZED
;
609 static int disconnected(ACImpl
*This
)
611 if (!This
->candisconnect
)
613 if (This
->parent
->flow
== eRender
) {
614 if (This
->parent
->device
) {
616 palcGetIntegerv(This
->parent
->device
, ALC_CONNECTED
, 1, &con
);
617 palcGetError(This
->parent
->device
);
619 palcCloseDevice(This
->parent
->device
);
620 This
->parent
->device
= NULL
;
621 This
->parent
->ctx
= NULL
;
626 if (!This
->parent
->device
&& FAILED(AC_OpenRenderAL(This
))) {
627 This
->pad
-= This
->padpartial
;
628 This
->padpartial
= 0;
631 if (This
->parent
->device
!= This
->dev
) {
632 WARN("Emptying buffer after newly reconnected!\n");
633 This
->pad
-= This
->padpartial
;
634 This
->padpartial
= 0;
636 This
->dev
= This
->parent
->device
;
637 setALContext(This
->parent
->ctx
);
638 palGenSources(1, &This
->source
);
639 palSourcei(This
->source
, AL_LOOPING
, AL_FALSE
);
642 if (This
->render
&& !This
->locked
&& This
->pad
) {
643 UINT pad
= This
->pad
;
647 /* Probably will cause sound glitches, who cares? */
648 IAudioRenderClient_GetBuffer((IAudioRenderClient
*)This
->render
, pad
, &data
);
649 IAudioRenderClient_ReleaseBuffer((IAudioRenderClient
*)This
->render
, pad
, 0);
656 palcGetIntegerv(This
->dev
, ALC_CONNECTED
, 1, &con
);
657 palcGetError(This
->dev
);
659 palcCaptureCloseDevice(This
->dev
);
665 if (FAILED(AC_OpenCaptureAL(This
)))
668 WARN("Emptying buffer after newly reconnected!\n");
669 This
->pad
= This
->ofs
= 0;
671 palcCaptureStart(This
->dev
);
677 static HRESULT WINAPI
AC_GetCurrentPadding(IAudioClient
*iface
, UINT32
*numpad
)
679 ACImpl
*This
= (ACImpl
*)iface
;
682 TRACE("(%p)->(%p)\n", This
, numpad
);
684 return AUDCLNT_E_NOT_INITIALIZED
;
687 EnterCriticalSection(This
->crst
);
688 if (disconnected(This
)) {
689 REFERENCE_TIME time
= gettime(), period
;
691 WARN("No device found, faking increment\n");
692 IAudioClient_GetDevicePeriod(iface
, &period
, NULL
);
693 while (This
->running
&& time
- This
->laststamp
>= period
) {
694 This
->laststamp
+= period
;
696 if (This
->parent
->flow
== eCapture
) {
697 This
->pad
+= This
->psize
;
698 if (This
->pad
> This
->bufsize
)
699 This
->pad
= This
->bufsize
;
701 if (This
->pad
<= This
->psize
) {
705 This
->pad
-= This
->psize
;
709 if (This
->parent
->flow
== eCapture
)
710 *numpad
= This
->pad
>= This
->psize
? This
->psize
: 0;
713 } else if (This
->parent
->flow
== eRender
) {
715 ALint state
, padpart
;
716 setALContext(This
->parent
->ctx
);
718 palGetSourcei(This
->source
, AL_BYTE_OFFSET
, &padpart
);
719 palGetSourcei(This
->source
, AL_SOURCE_STATE
, &state
);
720 padpart
/= This
->pwfx
->nBlockAlign
;
721 if (state
== AL_STOPPED
&& This
->running
)
723 if (This
->running
&& This
->padpartial
!= padpart
) {
724 This
->padpartial
= padpart
;
725 This
->laststamp
= gettime();
726 #if 0 /* Manipulative lie */
727 } else if (This
->running
) {
728 ALint size
= This
->pad
- padpart
;
729 if (size
> This
->psize
)
731 played
= (gettime() - This
->laststamp
)*8;
732 played
= played
* This
->pwfx
->nSamplesPerSec
/ 10000000;
737 *numpad
= This
->pad
- This
->padpartial
- played
;
738 if (This
->handle
&& *numpad
+ This
->psize
<= This
->bufsize
)
739 SetEvent(This
->handle
);
743 DWORD block
= This
->pwfx
->nBlockAlign
;
744 DWORD psize
= This
->psize
/ block
;
745 palcGetIntegerv(This
->dev
, ALC_CAPTURE_SAMPLES
, 1, &avail
);
747 DWORD ofs
= This
->ofs
+ This
->pad
;
749 ofs
%= This
->bufsize
;
750 buf1
= This
->buffer
+ (ofs
* block
);
751 This
->laststamp
= gettime();
753 SetEvent(This
->handle
);
755 if (ofs
+ avail
<= This
->bufsize
)
756 palcCaptureSamples(This
->dev
, buf1
, avail
);
758 DWORD part1
= This
->bufsize
- ofs
;
759 palcCaptureSamples(This
->dev
, buf1
, part1
);
760 palcCaptureSamples(This
->dev
, This
->buffer
, avail
- part1
);
763 This
->frameswritten
+= avail
;
764 /* Increase ofs if the app forgets to read */
765 if (This
->pad
> This
->bufsize
) {
767 WARN("Overflowed! %u bytes\n", This
->pad
- This
->bufsize
);
768 This
->ofs
+= This
->pad
- This
->bufsize
;
769 rest
= This
->ofs
% psize
;
771 This
->ofs
+= psize
- rest
;
772 This
->ofs
%= This
->bufsize
;
773 This
->pad
= This
->bufsize
;
776 if (This
->pad
>= psize
)
781 LeaveCriticalSection(This
->crst
);
783 TRACE("%u queued\n", *numpad
);
787 static HRESULT WINAPI
AC_IsFormatSupported(IAudioClient
*iface
, AUDCLNT_SHAREMODE mode
, const WAVEFORMATEX
*pwfx
, WAVEFORMATEX
**outpwfx
)
789 ACImpl
*This
= (ACImpl
*)iface
;
793 TRACE("(%p)->(%x,%p,%p)\n", This
, mode
, pwfx
, outpwfx
);
797 if (mode
== AUDCLNT_SHAREMODE_SHARED
&& !outpwfx
)
799 if (mode
!= AUDCLNT_SHAREMODE_SHARED
800 && mode
!= AUDCLNT_SHAREMODE_EXCLUSIVE
) {
801 WARN("Unknown mode %x\n", mode
);
805 if (pwfx
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
806 size
= sizeof(WAVEFORMATEXTENSIBLE
);
807 else if (pwfx
->wFormatTag
== WAVE_FORMAT_PCM
)
808 size
= sizeof(WAVEFORMATEX
);
810 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
812 if (pwfx
->nSamplesPerSec
< 8000
813 || pwfx
->nSamplesPerSec
> 192000)
814 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
815 if (pwfx
->wFormatTag
!= WAVE_FORMAT_EXTENSIBLE
816 || !IsEqualIID(&((WAVEFORMATEXTENSIBLE
*)pwfx
)->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
)) {
817 if (pwfx
->wBitsPerSample
> 16)
818 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
821 switch (pwfx
->nChannels
) {
822 case 1: mask
= MONO
; break;
823 case 2: mask
= STEREO
; break;
824 case 4: mask
= QUAD
; break;
825 case 6: mask
= X5DOT1
; break;
826 case 7: mask
= X6DOT1
; break;
827 case 8: mask
= X7DOT1
; break;
829 TRACE("Unsupported channel count %i\n", pwfx
->nChannels
);
830 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
832 tmp
= CoTaskMemAlloc(size
);
836 return E_OUTOFMEMORY
;
838 memcpy(tmp
, pwfx
, size
);
839 tmp
->nBlockAlign
= tmp
->nChannels
* tmp
->wBitsPerSample
/ 8;
840 tmp
->nAvgBytesPerSec
= tmp
->nBlockAlign
* tmp
->nSamplesPerSec
;
841 tmp
->cbSize
= size
- sizeof(WAVEFORMATEX
);
842 if (tmp
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
) {
843 WAVEFORMATEXTENSIBLE
*ex
= (WAVEFORMATEXTENSIBLE
*)tmp
;
845 if (ex
->Samples
.wValidBitsPerSample
)
846 ex
->Samples
.wValidBitsPerSample
= ex
->Format
.wBitsPerSample
;
848 /* Rear is a special allowed case */
849 if (ex
->dwChannelMask
850 && !(ex
->Format
.nChannels
== 2 && ex
->dwChannelMask
== REAR
))
851 ex
->dwChannelMask
= mask
;
854 if (memcmp(pwfx
, tmp
, size
)) {
858 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
866 static HRESULT WINAPI
AC_GetMixFormat(IAudioClient
*iface
, WAVEFORMATEX
**pwfx
)
868 ACImpl
*This
= (ACImpl
*)iface
;
869 PROPVARIANT pv
= { VT_EMPTY
};
872 TRACE("(%p)->(%p)\n", This
, pwfx
);
876 hr
= MMDevice_GetPropValue(&This
->parent
->devguid
, This
->parent
->flow
,
877 &PKEY_AudioEngine_DeviceFormat
, &pv
);
878 *pwfx
= (WAVEFORMATEX
*)pv
.u
.blob
.pBlobData
;
879 if (SUCCEEDED(hr
) && pv
.vt
== VT_EMPTY
)
882 TRACE("Returning 0x%08x\n", hr
);
886 static HRESULT WINAPI
AC_GetDevicePeriod(IAudioClient
*iface
, REFERENCE_TIME
*defperiod
, REFERENCE_TIME
*minperiod
)
888 ACImpl
*This
= (ACImpl
*)iface
;
890 TRACE("(%p)->(%p)\n", This
, minperiod
);
891 if (!defperiod
&& !minperiod
)
901 static HRESULT WINAPI
AC_Start(IAudioClient
*iface
)
903 ACImpl
*This
= (ACImpl
*)iface
;
905 REFERENCE_TIME refresh
;
907 TRACE("(%p)\n", This
);
909 return AUDCLNT_E_NOT_INITIALIZED
;
910 if (This
->flags
& AUDCLNT_STREAMFLAGS_EVENTCALLBACK
) {
912 return AUDCLNT_E_EVENTHANDLE_NOT_SET
;
913 FIXME("Event handles not fully tested\n");
915 EnterCriticalSection(This
->crst
);
917 hr
= AUDCLNT_E_NOT_STOPPED
;
920 if (!valid_dev(This
))
921 WARN("No valid device\n");
922 else if (This
->parent
->flow
== eRender
) {
923 setALContext(This
->parent
->ctx
);
924 palSourcePlay(This
->source
);
929 palcCaptureStart(This
->dev
);
931 AC_GetDevicePeriod(iface
, &refresh
, NULL
);
932 if (!This
->timer_id
&& This
->handle
)
933 CreateTimerQueueTimer(&This
->timer_id
, NULL
, AC_tick
, This
,
934 refresh
/ 20000, refresh
/ 20000,
935 WT_EXECUTEINTIMERTHREAD
);
936 /* Set to 0, otherwise risk running the clock backwards
937 * This will cause AudioClock::GetPosition to return the maximum
938 * possible value for the current buffer
941 This
->running
= TRUE
;
944 LeaveCriticalSection(This
->crst
);
948 static HRESULT WINAPI
AC_Stop(IAudioClient
*iface
)
950 ACImpl
*This
= (ACImpl
*)iface
;
952 TRACE("(%p)\n", This
);
954 return AUDCLNT_E_NOT_INITIALIZED
;
957 EnterCriticalSection(This
->crst
);
958 if (!valid_dev(This
))
959 WARN("No valid device\n");
960 else if (This
->parent
->flow
== eRender
) {
962 setALContext(This
->parent
->ctx
);
963 palSourcePause(This
->source
);
966 palGetSourcei(This
->source
, AL_SOURCE_STATE
, &state
);
967 if (state
!= AL_PLAYING
)
975 palcCaptureStop(This
->dev
);
976 This
->running
= FALSE
;
977 timer_id
= This
->timer_id
;
979 LeaveCriticalSection(This
->crst
);
981 DeleteTimerQueueTimer(NULL
, timer_id
, INVALID_HANDLE_VALUE
);
985 static HRESULT WINAPI
AC_Reset(IAudioClient
*iface
)
987 ACImpl
*This
= (ACImpl
*)iface
;
989 TRACE("(%p)\n", This
);
991 return AUDCLNT_E_NOT_INITIALIZED
;
993 return AUDCLNT_E_NOT_STOPPED
;
994 EnterCriticalSection(This
->crst
);
996 hr
= AUDCLNT_E_BUFFER_OPERATION_PENDING
;
999 if (!valid_dev(This
))
1000 WARN("No valid device\n");
1001 else if (This
->parent
->flow
== eRender
) {
1004 setALContext(This
->parent
->ctx
);
1005 palSourceStop(This
->source
);
1006 palGetSourcei(This
->source
, AL_BUFFERS_PROCESSED
, &n
);
1008 palSourceUnqueueBuffers(This
->source
, 1, &buf
);
1009 palDeleteBuffers(1, &buf
);
1015 palcGetIntegerv(This
->dev
, ALC_CAPTURE_SAMPLES
, 1, &avail
);
1017 palcCaptureSamples(This
->dev
, This
->buffer
, avail
);
1019 This
->pad
= This
->padpartial
= 0;
1021 This
->frameswritten
= 0;
1023 LeaveCriticalSection(This
->crst
);
1027 static HRESULT WINAPI
AC_SetEventHandle(IAudioClient
*iface
, HANDLE handle
)
1029 ACImpl
*This
= (ACImpl
*)iface
;
1030 TRACE("(%p)\n", This
);
1032 return AUDCLNT_E_NOT_INITIALIZED
;
1034 return E_INVALIDARG
;
1035 if (!(This
->flags
& AUDCLNT_STREAMFLAGS_EVENTCALLBACK
))
1036 return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED
;
1037 This
->handle
= handle
;
1041 static HRESULT WINAPI
AC_GetService(IAudioClient
*iface
, REFIID riid
, void **ppv
)
1043 ACImpl
*This
= (ACImpl
*)iface
;
1045 TRACE("(%p)->(%s,%p)\n", This
, debugstr_guid(riid
), ppv
);
1047 return AUDCLNT_E_NOT_INITIALIZED
;
1052 if (IsEqualIID(riid
, &IID_IAudioRenderClient
)) {
1053 if (This
->parent
->flow
!= eRender
)
1054 return AUDCLNT_E_WRONG_ENDPOINT_TYPE
;
1056 hr
= AudioRenderClient_Create(This
, &This
->render
);
1057 *ppv
= This
->render
;
1058 } else if (IsEqualIID(riid
, &IID_IAudioCaptureClient
)) {
1059 if (This
->parent
->flow
!= eCapture
)
1060 return AUDCLNT_E_WRONG_ENDPOINT_TYPE
;
1062 hr
= AudioCaptureClient_Create(This
, &This
->capture
);
1063 *ppv
= This
->capture
;
1064 } else if (IsEqualIID(riid
, &IID_IAudioSessionControl
)) {
1066 hr
= AudioSessionControl_Create(This
, &This
->session
);
1067 *ppv
= This
->session
;
1068 } else if (IsEqualIID(riid
, &IID_ISimpleAudioVolume
)) {
1070 hr
= AudioSimpleVolume_Create(This
, &This
->svolume
);
1071 *ppv
= This
->svolume
;
1072 } else if (IsEqualIID(riid
, &IID_IAudioClock
)) {
1074 hr
= AudioClock_Create(This
, &This
->clock
);
1082 IUnknown_AddRef((IUnknown
*)*ppv
);
1086 FIXME("stub %s\n", debugstr_guid(riid
));
1087 return E_NOINTERFACE
;
1090 static const IAudioClientVtbl ACImpl_Vtbl
=
1097 AC_GetStreamLatency
,
1098 AC_GetCurrentPadding
,
1099 AC_IsFormatSupported
,
1109 static HRESULT
AudioRenderClient_Create(ACImpl
*parent
, ACRender
**ppv
)
1113 This
= *ppv
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
1115 return E_OUTOFMEMORY
;
1116 This
->lpVtbl
= &ACRender_Vtbl
;
1118 This
->parent
= parent
;
1122 static void AudioRenderClient_Destroy(ACRender
*This
)
1124 This
->parent
->render
= NULL
;
1125 HeapFree(GetProcessHeap(), 0, This
);
1128 static HRESULT WINAPI
ACR_QueryInterface(IAudioRenderClient
*iface
, REFIID riid
, void **ppv
)
1130 TRACE("(%p)->(%s,%p)\n", iface
, debugstr_guid(riid
), ppv
);
1135 if (IsEqualIID(riid
, &IID_IUnknown
)
1136 || IsEqualIID(riid
, &IID_IAudioRenderClient
))
1139 IUnknown_AddRef((IUnknown
*)*ppv
);
1142 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1143 return E_NOINTERFACE
;
1146 static ULONG WINAPI
ACR_AddRef(IAudioRenderClient
*iface
)
1148 ACRender
*This
= (ACRender
*)iface
;
1150 ref
= InterlockedIncrement(&This
->ref
);
1151 TRACE("Refcount now %i\n", ref
);
1155 static ULONG WINAPI
ACR_Release(IAudioRenderClient
*iface
)
1157 ACRender
*This
= (ACRender
*)iface
;
1159 ref
= InterlockedDecrement(&This
->ref
);
1160 TRACE("Refcount now %i\n", ref
);
1162 AudioRenderClient_Destroy(This
);
1166 static HRESULT WINAPI
ACR_GetBuffer(IAudioRenderClient
*iface
, UINT32 frames
, BYTE
**data
)
1168 ACRender
*This
= (ACRender
*)iface
;
1169 DWORD free
, framesize
;
1170 TRACE("(%p)->(%u,%p)\n", This
, frames
, data
);
1177 if (This
->parent
->locked
) {
1179 return AUDCLNT_E_OUT_OF_ORDER
;
1181 AC_GetCurrentPadding((IAudioClient
*)This
->parent
, &free
);
1182 if (This
->parent
->bufsize
-free
< frames
) {
1183 ERR("Too large: %u %u %u\n", This
->parent
->bufsize
, free
, frames
);
1184 return AUDCLNT_E_BUFFER_TOO_LARGE
;
1186 EnterCriticalSection(This
->parent
->crst
);
1187 This
->parent
->locked
= frames
;
1188 framesize
= This
->parent
->pwfx
->nBlockAlign
;
1190 /* Exact offset doesn't matter, offset could be 0 forever
1191 * but increasing it is easier to debug */
1192 if (This
->parent
->ofs
+ frames
> This
->parent
->bufsize
)
1193 This
->parent
->ofs
= 0;
1194 *data
= This
->parent
->buffer
+ This
->parent
->ofs
* framesize
;
1196 LeaveCriticalSection(This
->parent
->crst
);
1200 static HRESULT WINAPI
ACR_ReleaseBuffer(IAudioRenderClient
*iface
, UINT32 written
, DWORD flags
)
1202 ACRender
*This
= (ACRender
*)iface
;
1203 BYTE
*buf
= This
->parent
->buffer
;
1204 DWORD framesize
= This
->parent
->pwfx
->nBlockAlign
;
1205 DWORD ofs
= This
->parent
->ofs
;
1206 DWORD bufsize
= This
->parent
->bufsize
;
1207 DWORD freq
= This
->parent
->pwfx
->nSamplesPerSec
;
1208 DWORD bpp
= This
->parent
->pwfx
->wBitsPerSample
;
1211 TRACE("(%p)->(%u,%x)\n", This
, written
, flags
);
1213 if (This
->parent
->locked
< written
)
1214 return AUDCLNT_E_INVALID_SIZE
;
1216 if (flags
& ~AUDCLNT_BUFFERFLAGS_SILENT
)
1217 return E_INVALIDARG
;
1220 if (This
->parent
->locked
)
1221 FIXME("Handled right?\n");
1222 This
->parent
->locked
= 0;
1226 if (!This
->parent
->locked
)
1227 return AUDCLNT_E_OUT_OF_ORDER
;
1229 EnterCriticalSection(This
->parent
->crst
);
1231 This
->parent
->ofs
+= written
;
1232 This
->parent
->ofs
%= bufsize
;
1233 This
->parent
->pad
+= written
;
1234 This
->parent
->frameswritten
+= written
;
1235 This
->parent
->locked
= 0;
1238 written
*= framesize
;
1239 bufsize
*= framesize
;
1241 if (flags
& AUDCLNT_BUFFERFLAGS_SILENT
)
1242 memset(buf
+ofs
, bpp
!= 8 ? 0 : 128, written
);
1243 TRACE("buf: %p, ofs: %x, written %u, freq %u\n", buf
, ofs
, written
, freq
);
1244 if (!valid_dev(This
->parent
))
1247 setALContext(This
->parent
->parent
->ctx
);
1248 palGenBuffers(1, &albuf
);
1249 palBufferData(albuf
, This
->parent
->format
, buf
+ofs
, written
, freq
);
1250 palSourceQueueBuffers(This
->parent
->source
, 1, &albuf
);
1251 TRACE("Queued %u\n", albuf
);
1253 if (This
->parent
->running
) {
1254 ALint state
= AL_PLAYING
, done
= 0, padpart
= 0;
1256 palGetSourcei(This
->parent
->source
, AL_BUFFERS_PROCESSED
, &done
);
1257 palGetSourcei(This
->parent
->source
, AL_BYTE_OFFSET
, &padpart
);
1258 palGetSourcei(This
->parent
->source
, AL_SOURCE_STATE
, &state
);
1259 padpart
/= framesize
;
1261 if (state
== AL_STOPPED
) {
1262 padpart
= This
->parent
->pad
;
1263 /* Buffer might have been processed in the small window
1264 * between first and third call */
1265 palGetSourcei(This
->parent
->source
, AL_BUFFERS_PROCESSED
, &done
);
1267 if (done
|| This
->parent
->padpartial
!= padpart
)
1268 This
->parent
->laststamp
= gettime();
1269 This
->parent
->padpartial
= padpart
;
1272 ALint size
, bits
, chan
;
1275 palSourceUnqueueBuffers(This
->parent
->source
, 1, &which
);
1276 palGetBufferi(which
, AL_SIZE
, &size
);
1277 palGetBufferi(which
, AL_BITS
, &bits
);
1278 palGetBufferi(which
, AL_CHANNELS
, &chan
);
1279 size
/= bits
* chan
/ 8;
1280 if (size
> This
->parent
->pad
) {
1282 size
= This
->parent
->pad
;
1284 This
->parent
->pad
-= size
;
1285 This
->parent
->padpartial
-= size
;
1286 TRACE("Unqueued %u\n", which
);
1287 palDeleteBuffers(1, &which
);
1290 if (state
!= AL_PLAYING
) {
1291 ERR("Starting from %x\n", state
);
1292 palSourcePlay(This
->parent
->source
);
1299 LeaveCriticalSection(This
->parent
->crst
);
1304 static const IAudioRenderClientVtbl ACRender_Vtbl
= {
1312 static HRESULT
AudioCaptureClient_Create(ACImpl
*parent
, ACCapture
**ppv
)
1315 This
= *ppv
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
1317 return E_OUTOFMEMORY
;
1318 This
->lpVtbl
= &ACCapture_Vtbl
;
1320 This
->parent
= parent
;
1324 static void AudioCaptureClient_Destroy(ACCapture
*This
)
1326 This
->parent
->capture
= NULL
;
1327 HeapFree(GetProcessHeap(), 0, This
);
1330 static HRESULT WINAPI
ACC_QueryInterface(IAudioCaptureClient
*iface
, REFIID riid
, void **ppv
)
1332 TRACE("(%p)->(%s,%p)\n", iface
, debugstr_guid(riid
), ppv
);
1337 if (IsEqualIID(riid
, &IID_IUnknown
)
1338 || IsEqualIID(riid
, &IID_IAudioCaptureClient
))
1341 IUnknown_AddRef((IUnknown
*)*ppv
);
1344 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1345 return E_NOINTERFACE
;
1348 static ULONG WINAPI
ACC_AddRef(IAudioCaptureClient
*iface
)
1350 ACCapture
*This
= (ACCapture
*)iface
;
1352 ref
= InterlockedIncrement(&This
->ref
);
1353 TRACE("Refcount now %i\n", ref
);
1357 static ULONG WINAPI
ACC_Release(IAudioCaptureClient
*iface
)
1359 ACCapture
*This
= (ACCapture
*)iface
;
1361 ref
= InterlockedDecrement(&This
->ref
);
1362 TRACE("Refcount now %i\n", ref
);
1364 AudioCaptureClient_Destroy(This
);
1368 static HRESULT WINAPI
ACC_GetBuffer(IAudioCaptureClient
*iface
, BYTE
**data
, UINT32
*frames
, DWORD
*flags
, UINT64
*devpos
, UINT64
*qpcpos
)
1370 ACCapture
*This
= (ACCapture
*)iface
;
1372 DWORD block
= This
->parent
->pwfx
->nBlockAlign
;
1374 TRACE("(%p)->(%p,%p,%p,%p,%p)\n", This
, data
, frames
, flags
, devpos
, qpcpos
);
1381 FIXME("Flags can be null?\n");
1384 EnterCriticalSection(This
->parent
->crst
);
1385 hr
= AUDCLNT_E_OUT_OF_ORDER
;
1386 if (This
->parent
->locked
)
1388 IAudioCaptureClient_GetNextPacketSize(iface
, frames
);
1389 ofs
= This
->parent
->ofs
;
1390 if ( (ofs
*block
) % This
->parent
->psize
)
1391 ERR("Unaligned offset %u with %u\n", ofs
*block
, This
->parent
->psize
);
1392 *data
= This
->parent
->buffer
+ ofs
* block
;
1393 This
->parent
->locked
= *frames
;
1395 *devpos
= This
->parent
->frameswritten
- This
->parent
->pad
;
1397 *qpcpos
= This
->parent
->laststamp
;
1401 hr
= AUDCLNT_S_BUFFER_EMPTY
;
1403 LeaveCriticalSection(This
->parent
->crst
);
1404 TRACE("Returning %08x %i\n", hr
, *frames
);
1408 static HRESULT WINAPI
ACC_ReleaseBuffer(IAudioCaptureClient
*iface
, UINT32 written
)
1410 ACCapture
*This
= (ACCapture
*)iface
;
1412 EnterCriticalSection(This
->parent
->crst
);
1413 if (!written
|| written
== This
->parent
->locked
) {
1414 This
->parent
->locked
= 0;
1415 This
->parent
->ofs
+= written
;
1416 This
->parent
->ofs
%= This
->parent
->bufsize
;
1417 This
->parent
->pad
-= written
;
1418 } else if (!This
->parent
->locked
)
1419 hr
= AUDCLNT_E_OUT_OF_ORDER
;
1421 hr
= AUDCLNT_E_INVALID_SIZE
;
1422 LeaveCriticalSection(This
->parent
->crst
);
1426 static HRESULT WINAPI
ACC_GetNextPacketSize(IAudioCaptureClient
*iface
, UINT32
*frames
)
1428 ACCapture
*This
= (ACCapture
*)iface
;
1430 return AC_GetCurrentPadding((IAudioClient
*)This
->parent
, frames
);
1433 static const IAudioCaptureClientVtbl ACCapture_Vtbl
=
1440 ACC_GetNextPacketSize
1443 static HRESULT
AudioSessionControl_Create(ACImpl
*parent
, ACSession
**ppv
)
1446 This
= *ppv
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
1448 return E_OUTOFMEMORY
;
1449 This
->lpVtbl
= &ACSession_Vtbl
;
1451 This
->parent
= parent
;
1455 static void AudioSessionControl_Destroy(ACSession
*This
)
1457 This
->parent
->session
= NULL
;
1458 HeapFree(GetProcessHeap(), 0, This
);
1461 static HRESULT WINAPI
ACS_QueryInterface(IAudioSessionControl2
*iface
, REFIID riid
, void **ppv
)
1463 TRACE("(%p)->(%s,%p)\n", iface
, debugstr_guid(riid
), ppv
);
1468 if (IsEqualIID(riid
, &IID_IUnknown
)
1469 || IsEqualIID(riid
, &IID_IAudioSessionControl
)
1470 || IsEqualIID(riid
, &IID_IAudioSessionControl2
))
1473 IUnknown_AddRef((IUnknown
*)*ppv
);
1476 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1477 return E_NOINTERFACE
;
1480 static ULONG WINAPI
ACS_AddRef(IAudioSessionControl2
*iface
)
1482 ACSession
*This
= (ACSession
*)iface
;
1484 ref
= InterlockedIncrement(&This
->ref
);
1485 TRACE("Refcount now %i\n", ref
);
1489 static ULONG WINAPI
ACS_Release(IAudioSessionControl2
*iface
)
1491 ACSession
*This
= (ACSession
*)iface
;
1493 ref
= InterlockedDecrement(&This
->ref
);
1494 TRACE("Refcount now %i\n", ref
);
1496 AudioSessionControl_Destroy(This
);
1500 static HRESULT WINAPI
ACS_GetState(IAudioSessionControl2
*iface
, AudioSessionState
*state
)
1502 ACSession
*This
= (ACSession
*)iface
;
1503 TRACE("(%p)->(%p)\n", This
, state
);
1507 *state
= This
->parent
->parent
->state
;
1511 static HRESULT WINAPI
ACS_GetDisplayName(IAudioSessionControl2
*iface
, WCHAR
**name
)
1513 ACSession
*This
= (ACSession
*)iface
;
1514 TRACE("(%p)->(%p)\n", This
, name
);
1521 static HRESULT WINAPI
ACS_SetDisplayName(IAudioSessionControl2
*iface
, const WCHAR
*name
, const GUID
*session
)
1523 ACSession
*This
= (ACSession
*)iface
;
1524 TRACE("(%p)->(%p,%s)\n", This
, name
, debugstr_guid(session
));
1529 static HRESULT WINAPI
ACS_GetIconPath(IAudioSessionControl2
*iface
, WCHAR
**path
)
1531 ACSession
*This
= (ACSession
*)iface
;
1532 TRACE("(%p)->(%p)\n", This
, path
);
1539 static HRESULT WINAPI
ACS_SetIconPath(IAudioSessionControl2
*iface
, const WCHAR
*path
, const GUID
*session
)
1541 ACSession
*This
= (ACSession
*)iface
;
1542 TRACE("(%p)->(%p,%s)\n", This
, path
, debugstr_guid(session
));
1547 static HRESULT WINAPI
ACS_GetGroupingParam(IAudioSessionControl2
*iface
, GUID
*group
)
1549 ACSession
*This
= (ACSession
*)iface
;
1550 TRACE("(%p)->(%p)\n", This
, group
);
1557 static HRESULT WINAPI
ACS_SetGroupingParam(IAudioSessionControl2
*iface
, GUID
*group
, const GUID
*session
)
1559 ACSession
*This
= (ACSession
*)iface
;
1560 TRACE("(%p)->(%s,%s)\n", This
, debugstr_guid(group
), debugstr_guid(session
));
1565 static HRESULT WINAPI
ACS_RegisterAudioSessionNotification(IAudioSessionControl2
*iface
, IAudioSessionEvents
*events
)
1567 ACSession
*This
= (ACSession
*)iface
;
1568 TRACE("(%p)->(%p)\n", This
, events
);
1573 static HRESULT WINAPI
ACS_UnregisterAudioSessionNotification(IAudioSessionControl2
*iface
, IAudioSessionEvents
*events
)
1575 ACSession
*This
= (ACSession
*)iface
;
1576 TRACE("(%p)->(%p)\n", This
, events
);
1581 static HRESULT WINAPI
ACS_GetSessionIdentifier(IAudioSessionControl2
*iface
, WCHAR
**id
)
1583 ACSession
*This
= (ACSession
*)iface
;
1584 TRACE("(%p)->(%p)\n", This
, id
);
1591 static HRESULT WINAPI
ACS_GetSessionInstanceIdentifier(IAudioSessionControl2
*iface
, WCHAR
**id
)
1593 ACSession
*This
= (ACSession
*)iface
;
1594 TRACE("(%p)->(%p)\n", This
, id
);
1601 static HRESULT WINAPI
ACS_GetProcessId(IAudioSessionControl2
*iface
, DWORD
*pid
)
1603 ACSession
*This
= (ACSession
*)iface
;
1604 TRACE("(%p)->(%p)\n", This
, pid
);
1608 *pid
= GetCurrentProcessId();
1612 static HRESULT WINAPI
ACS_IsSystemSoundsSession(IAudioSessionControl2
*iface
)
1614 ACSession
*This
= (ACSession
*)iface
;
1615 TRACE("(%p)\n", This
);
1620 static HRESULT WINAPI
ACS_SetDuckingPreference(IAudioSessionControl2
*iface
, BOOL optout
)
1622 ACSession
*This
= (ACSession
*)iface
;
1623 TRACE("(%p)\n", This
);
1628 static const IAudioSessionControl2Vtbl ACSession_Vtbl
=
1638 ACS_GetGroupingParam
,
1639 ACS_SetGroupingParam
,
1640 ACS_RegisterAudioSessionNotification
,
1641 ACS_UnregisterAudioSessionNotification
,
1642 ACS_GetSessionIdentifier
,
1643 ACS_GetSessionInstanceIdentifier
,
1645 ACS_IsSystemSoundsSession
,
1646 ACS_SetDuckingPreference
1649 static HRESULT
AudioSimpleVolume_Create(ACImpl
*parent
, ASVolume
**ppv
)
1652 This
= *ppv
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
1654 return E_OUTOFMEMORY
;
1655 This
->lpVtbl
= &ASVolume_Vtbl
;
1657 This
->parent
= parent
;
1661 static void AudioSimpleVolume_Destroy(ASVolume
*This
)
1663 This
->parent
->svolume
= NULL
;
1664 HeapFree(GetProcessHeap(), 0, This
);
1667 static HRESULT WINAPI
ASV_QueryInterface(ISimpleAudioVolume
*iface
, REFIID riid
, void **ppv
)
1669 TRACE("(%p)->(%s,%p)\n", iface
, debugstr_guid(riid
), ppv
);
1674 if (IsEqualIID(riid
, &IID_IUnknown
)
1675 || IsEqualIID(riid
, &IID_ISimpleAudioVolume
))
1678 IUnknown_AddRef((IUnknown
*)*ppv
);
1681 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1682 return E_NOINTERFACE
;
1685 static ULONG WINAPI
ASV_AddRef(ISimpleAudioVolume
*iface
)
1687 ASVolume
*This
= (ASVolume
*)iface
;
1689 ref
= InterlockedIncrement(&This
->ref
);
1690 TRACE("Refcount now %i\n", ref
);
1694 static ULONG WINAPI
ASV_Release(ISimpleAudioVolume
*iface
)
1696 ASVolume
*This
= (ASVolume
*)iface
;
1698 ref
= InterlockedDecrement(&This
->ref
);
1699 TRACE("Refcount now %i\n", ref
);
1701 AudioSimpleVolume_Destroy(This
);
1705 static HRESULT WINAPI
ASV_SetMasterVolume(ISimpleAudioVolume
*iface
, float level
, const GUID
*context
)
1707 ASVolume
*This
= (ASVolume
*)iface
;
1708 TRACE("(%p)->(%f,%p)\n", This
, level
, context
);
1714 static HRESULT WINAPI
ASV_GetMasterVolume(ISimpleAudioVolume
*iface
, float *level
)
1716 ASVolume
*This
= (ASVolume
*)iface
;
1717 TRACE("(%p)->(%p)\n", This
, level
);
1724 static HRESULT WINAPI
ASV_SetMute(ISimpleAudioVolume
*iface
, BOOL mute
, const GUID
*context
)
1726 ASVolume
*This
= (ASVolume
*)iface
;
1727 TRACE("(%p)->(%u,%p)\n", This
, mute
, context
);
1733 static HRESULT WINAPI
ASV_GetMute(ISimpleAudioVolume
*iface
, BOOL
*mute
)
1735 ASVolume
*This
= (ASVolume
*)iface
;
1736 TRACE("(%p)->(%p)\n", This
, mute
);
1743 static const ISimpleAudioVolumeVtbl ASVolume_Vtbl
=
1748 ASV_SetMasterVolume
,
1749 ASV_GetMasterVolume
,
1754 static HRESULT
AudioClock_Create(ACImpl
*parent
, AClock
**ppv
)
1757 This
= *ppv
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
1759 return E_OUTOFMEMORY
;
1760 This
->lpVtbl
= &AClock_Vtbl
;
1761 This
->lp2Vtbl
= &AClock2_Vtbl
;
1763 This
->parent
= parent
;
1767 static void AudioClock_Destroy(AClock
*This
)
1769 This
->parent
->clock
= NULL
;
1770 HeapFree(GetProcessHeap(), 0, This
);
1773 static HRESULT WINAPI
AClock_QueryInterface(IAudioClock
*iface
, REFIID riid
, void **ppv
)
1775 AClock
*This
= (AClock
*)iface
;
1776 TRACE("(%p)->(%s,%p)\n", iface
, debugstr_guid(riid
), ppv
);
1781 if (IsEqualIID(riid
, &IID_IUnknown
)
1782 || IsEqualIID(riid
, &IID_IAudioClock
))
1784 else if (IsEqualIID(riid
, &IID_IAudioClock2
))
1785 *ppv
= &This
->lp2Vtbl
;
1787 IUnknown_AddRef((IUnknown
*)*ppv
);
1790 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1791 return E_NOINTERFACE
;
1794 static ULONG WINAPI
AClock_AddRef(IAudioClock
*iface
)
1796 AClock
*This
= (AClock
*)iface
;
1798 ref
= InterlockedIncrement(&This
->ref
);
1799 TRACE("Refcount now %i\n", ref
);
1803 static ULONG WINAPI
AClock_Release(IAudioClock
*iface
)
1805 AClock
*This
= (AClock
*)iface
;
1807 ref
= InterlockedDecrement(&This
->ref
);
1808 TRACE("Refcount now %i\n", ref
);
1810 AudioClock_Destroy(This
);
1814 static HRESULT WINAPI
AClock_GetFrequency(IAudioClock
*iface
, UINT64
*freq
)
1816 AClock
*This
= (AClock
*)iface
;
1817 TRACE("(%p)->(%p)\n", This
, freq
);
1819 *freq
= (UINT64
)This
->parent
->pwfx
->nSamplesPerSec
;
1823 static HRESULT WINAPI
AClock_GetPosition(IAudioClock
*iface
, UINT64
*pos
, UINT64
*qpctime
)
1825 AClock
*This
= (AClock
*)iface
;
1828 TRACE("(%p)->(%p,%p)\n", This
, pos
, qpctime
);
1833 EnterCriticalSection(This
->parent
->crst
);
1834 AC_GetCurrentPadding((IAudioClient
*)This
->parent
, &pad
);
1835 *pos
= This
->parent
->frameswritten
- pad
;
1837 *qpctime
= gettime();
1838 LeaveCriticalSection(This
->parent
->crst
);
1843 static HRESULT WINAPI
AClock_GetCharacteristics(IAudioClock
*iface
, DWORD
*chars
)
1845 AClock
*This
= (AClock
*)iface
;
1846 TRACE("(%p)->(%p)\n", This
, chars
);
1850 *chars
= AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ
;
1854 static const IAudioClockVtbl AClock_Vtbl
=
1856 AClock_QueryInterface
,
1859 AClock_GetFrequency
,
1861 AClock_GetCharacteristics
1864 static AClock
*get_clock_from_clock2(IAudioClock2
*iface
)
1866 return (AClock
*)((char*)iface
- offsetof(AClock
,lp2Vtbl
));
1869 static HRESULT WINAPI
AClock2_QueryInterface(IAudioClock2
*iface
, REFIID riid
, void **ppv
)
1871 AClock
*This
= get_clock_from_clock2(iface
);
1872 return IUnknown_QueryInterface((IUnknown
*)This
, riid
, ppv
);
1875 static ULONG WINAPI
AClock2_AddRef(IAudioClock2
*iface
)
1877 AClock
*This
= get_clock_from_clock2(iface
);
1878 return IUnknown_AddRef((IUnknown
*)This
);
1881 static ULONG WINAPI
AClock2_Release(IAudioClock2
*iface
)
1883 AClock
*This
= get_clock_from_clock2(iface
);
1884 return IUnknown_Release((IUnknown
*)This
);
1887 static HRESULT WINAPI
AClock2_GetPosition(IAudioClock2
*iface
, UINT64
*pos
, UINT64
*qpctime
)
1889 AClock
*This
= get_clock_from_clock2(iface
);
1890 return AClock_GetPosition((IAudioClock
*)This
, pos
, qpctime
);
1893 static const IAudioClock2Vtbl AClock2_Vtbl
=
1895 AClock2_QueryInterface
,