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
28 #elif defined(HAVE_OPENAL_AL_H)
29 #include <OpenAL/al.h>
30 #include <OpenAL/alc.h>
37 #include "wine/debug.h"
38 #include "wine/unicode.h"
41 #include "mmdeviceapi.h"
44 #include "audioclient.h"
45 #include "endpointvolume.h"
46 #include "audiopolicy.h"
50 WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi
);
54 typedef struct ACRender ACRender
;
55 typedef struct ACCapture ACCapture
;
56 typedef struct ACSession ACSession
;
57 typedef struct ASVolume ASVolume
;
58 typedef struct AClock AClock
;
60 typedef struct ACImpl
{
61 const IAudioClientVtbl
*lpVtbl
;
66 CRITICAL_SECTION
*crst
;
68 DWORD locked
, flags
, bufsize
, pad
, padpartial
, ofs
, psize
;
73 REFERENCE_TIME laststamp
;
86 const IAudioRenderClientVtbl
*lpVtbl
;
92 const IAudioCaptureClientVtbl
*lpVtbl
;
98 const IAudioSessionControl2Vtbl
*lpVtbl
;
104 const ISimpleAudioVolumeVtbl
*lpVtbl
;
110 const IAudioClockVtbl
*lpVtbl
;
111 const IAudioClock2Vtbl
*lp2Vtbl
;
116 static const IAudioClientVtbl ACImpl_Vtbl
;
117 static const IAudioRenderClientVtbl ACRender_Vtbl
;
118 static const IAudioCaptureClientVtbl ACCapture_Vtbl
;
119 static const IAudioSessionControl2Vtbl ACSession_Vtbl
;
120 static const ISimpleAudioVolumeVtbl ASVolume_Vtbl
;
121 static const IAudioClockVtbl AClock_Vtbl
;
122 static const IAudioClock2Vtbl AClock2_Vtbl
;
124 static HRESULT
AudioRenderClient_Create(ACImpl
*parent
, ACRender
**ppv
);
125 static void AudioRenderClient_Destroy(ACRender
*This
);
126 static HRESULT
AudioCaptureClient_Create(ACImpl
*parent
, ACCapture
**ppv
);
127 static void AudioCaptureClient_Destroy(ACCapture
*This
);
128 static HRESULT
AudioSessionControl_Create(ACImpl
*parent
, ACSession
**ppv
);
129 static void AudioSessionControl_Destroy(ACSession
*This
);
130 static HRESULT
AudioSimpleVolume_Create(ACImpl
*parent
, ASVolume
**ppv
);
131 static void AudioSimpleVolume_Destroy(ASVolume
*This
);
132 static HRESULT
AudioClock_Create(ACImpl
*parent
, AClock
**ppv
);
133 static void AudioClock_Destroy(AClock
*This
);
135 static int get_format_PCM(WAVEFORMATEX
*format
)
137 if (format
->nChannels
> 2) {
138 FIXME("nChannels > 2 not documented for WAVE_FORMAT_PCM!\n");
144 if (format
->nBlockAlign
!= format
->wBitsPerSample
/8*format
->nChannels
) {
145 WARN("Invalid nBlockAlign %u, from %u %u\n",
146 format
->nBlockAlign
, format
->wBitsPerSample
, format
->nChannels
);
150 switch (format
->wBitsPerSample
) {
152 switch (format
->nChannels
) {
153 case 1: return AL_FORMAT_MONO8
;
154 case 2: return AL_FORMAT_STEREO8
;
158 switch (format
->nChannels
) {
159 case 1: return AL_FORMAT_MONO16
;
160 case 2: return AL_FORMAT_STEREO16
;
165 if (!(format
->wBitsPerSample
% 8))
166 WARN("Could not get OpenAL format (%d-bit, %d channels)\n",
167 format
->wBitsPerSample
, format
->nChannels
);
171 /* Speaker configs */
172 #define MONO SPEAKER_FRONT_CENTER
173 #define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)
174 #define REAR (SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
175 #define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
176 #define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
177 #define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
178 #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)
180 static int get_format_EXT(WAVEFORMATEX
*format
)
182 WAVEFORMATEXTENSIBLE
*wfe
;
184 if(format
->cbSize
< sizeof(WAVEFORMATEXTENSIBLE
)-sizeof(WAVEFORMATEX
)) {
185 WARN("Invalid cbSize specified for WAVE_FORMAT_EXTENSIBLE (%d)\n", format
->cbSize
);
189 wfe
= (WAVEFORMATEXTENSIBLE
*)format
;
190 wfe
->Format
.cbSize
= sizeof(WAVEFORMATEXTENSIBLE
)-sizeof(WAVEFORMATEX
);
191 if (wfe
->Samples
.wValidBitsPerSample
&&
192 wfe
->Samples
.wValidBitsPerSample
!= format
->wBitsPerSample
) {
193 FIXME("wValidBitsPerSample(%u) != wBitsPerSample(%u) unsupported\n",
194 wfe
->Samples
.wValidBitsPerSample
, format
->wBitsPerSample
);
198 TRACE("Extensible values:\n"
200 " ChannelMask = 0x%08x\n"
202 wfe
->Samples
.wReserved
, wfe
->dwChannelMask
,
203 debugstr_guid(&wfe
->SubFormat
));
205 if (wfe
->dwChannelMask
!= MONO
206 && wfe
->dwChannelMask
!= STEREO
207 && !palIsExtensionPresent("AL_EXT_MCFORMATS")) {
208 /* QUAD PCM might still work, special case */
209 if (palIsExtensionPresent("AL_LOKI_quadriphonic")
210 && IsEqualGUID(&wfe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
)
211 && wfe
->dwChannelMask
== QUAD
) {
212 if (format
->wBitsPerSample
== 16)
213 return AL_FORMAT_QUAD16_LOKI
;
214 else if (format
->wBitsPerSample
== 8)
215 return AL_FORMAT_QUAD8_LOKI
;
217 WARN("Not all formats available\n");
221 if(IsEqualGUID(&wfe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
)) {
222 if (format
->wBitsPerSample
== 8) {
223 switch (wfe
->dwChannelMask
) {
224 case MONO
: return AL_FORMAT_MONO8
;
225 case STEREO
: return AL_FORMAT_STEREO8
;
226 case REAR
: return AL_FORMAT_REAR8
;
227 case QUAD
: return AL_FORMAT_QUAD8
;
228 case X5DOT1
: return AL_FORMAT_51CHN8
;
229 case X6DOT1
: return AL_FORMAT_61CHN8
;
230 case X7DOT1
: return AL_FORMAT_71CHN8
;
233 } else if (format
->wBitsPerSample
== 16) {
234 switch (wfe
->dwChannelMask
) {
235 case MONO
: return AL_FORMAT_MONO16
;
236 case STEREO
: return AL_FORMAT_STEREO16
;
237 case REAR
: return AL_FORMAT_REAR16
;
238 case QUAD
: return AL_FORMAT_QUAD16
;
239 case X5DOT1
: return AL_FORMAT_51CHN16
;
240 case X6DOT1
: return AL_FORMAT_61CHN16
;
241 case X7DOT1
: return AL_FORMAT_71CHN16
;
245 else if (!(format
->wBitsPerSample
% 8))
246 ERR("Could not get OpenAL PCM format (%d-bit, mask 0x%08x)\n",
247 format
->wBitsPerSample
, wfe
->dwChannelMask
);
250 else if(IsEqualGUID(&wfe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
)) {
251 if (format
->wBitsPerSample
!= 32) {
252 WARN("Invalid valid bits %u/32\n", format
->wBitsPerSample
);
255 switch (wfe
->dwChannelMask
) {
256 case MONO
: return AL_FORMAT_MONO_FLOAT32
;
257 case STEREO
: return AL_FORMAT_STEREO_FLOAT32
;
258 case REAR
: return AL_FORMAT_REAR32
;
259 case QUAD
: return AL_FORMAT_QUAD32
;
260 case X5DOT1
: return AL_FORMAT_51CHN32
;
261 case X6DOT1
: return AL_FORMAT_61CHN32
;
262 case X7DOT1
: return AL_FORMAT_71CHN32
;
264 ERR("Could not get OpenAL float format (%d-bit, mask 0x%08x)\n",
265 format
->wBitsPerSample
, wfe
->dwChannelMask
);
269 else if (!IsEqualGUID(&wfe
->SubFormat
, &GUID_NULL
))
270 ERR("Unhandled extensible format: %s\n", debugstr_guid(&wfe
->SubFormat
));
274 static ALint
get_format(WAVEFORMATEX
*in
)
277 if (in
->wFormatTag
== WAVE_FORMAT_PCM
)
278 ret
= get_format_PCM(in
);
279 else if (in
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
280 ret
= get_format_EXT(in
);
284 static REFERENCE_TIME
gettime(void) {
285 LARGE_INTEGER stamp
, freq
;
286 QueryPerformanceCounter(&stamp
);
287 QueryPerformanceFrequency(&freq
);
288 return (stamp
.QuadPart
* (INT64
)10000000) / freq
.QuadPart
;
291 HRESULT
AudioClient_Create(MMDevice
*parent
, IAudioClient
**ppv
)
293 ACImpl
*This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*This
));
294 *ppv
= (IAudioClient
*)This
;
296 return E_OUTOFMEMORY
;
297 This
->crst
= &parent
->crst
;
298 This
->lpVtbl
= &ACImpl_Vtbl
;
300 This
->parent
= parent
;
304 static void AudioClient_Destroy(ACImpl
*This
)
307 DeleteTimerQueueTimer(NULL
, This
->timer_id
, INVALID_HANDLE_VALUE
);
309 AudioRenderClient_Destroy(This
->render
);
311 AudioCaptureClient_Destroy(This
->capture
);
313 AudioSessionControl_Destroy(This
->session
);
315 AudioSimpleVolume_Destroy(This
->svolume
);
317 AudioClock_Destroy(This
->clock
);
318 if (This
->parent
->flow
== eRender
&& This
->init
) {
319 setALContext(This
->parent
->ctx
);
320 IAudioClient_Stop((IAudioClient
*)This
);
321 IAudioClient_Reset((IAudioClient
*)This
);
322 palDeleteSources(1, &This
->source
);
327 palcCaptureCloseDevice(This
->capdev
);
328 HeapFree(GetProcessHeap(), 0, This
->pwfx
);
329 HeapFree(GetProcessHeap(), 0, This
->buffer
);
330 HeapFree(GetProcessHeap(), 0, This
);
333 static void CALLBACK
AC_tick(void *data
, BOOLEAN fired
)
338 EnterCriticalSection(This
->crst
);
340 IAudioClient_GetCurrentPadding((IAudioClient
*)This
, &pad
);
341 LeaveCriticalSection(This
->crst
);
344 /* Open device and set/update internal mixing format based on information
345 * openal provides us. if the device cannot be opened, assume 48khz
346 * Guessing the frequency is harmless, since if GetMixFormat fails to open
347 * the device, then Initialize will likely fail as well
349 static HRESULT
AC_OpenRenderAL(ACImpl
*This
)
351 char alname
[MAX_PATH
];
352 MMDevice
*cur
= This
->parent
;
354 alname
[sizeof(alname
)-1] = 0;
356 return cur
->ctx
? S_OK
: AUDCLNT_E_SERVICE_NOT_RUNNING
;
358 WideCharToMultiByte(CP_UNIXCP
, 0, cur
->alname
, -1,
359 alname
, sizeof(alname
)/sizeof(*alname
)-1, NULL
, NULL
);
360 cur
->device
= palcOpenDevice(alname
);
362 ALCenum err
= palcGetError(NULL
);
363 FIXME("Could not open device %s: 0x%04x\n", alname
, err
);
364 return AUDCLNT_E_DEVICE_IN_USE
;
366 cur
->ctx
= palcCreateContext(cur
->device
, NULL
);
368 ALCenum err
= palcGetError(cur
->device
);
369 FIXME("Could not create context: 0x%04x\n", err
);
370 return AUDCLNT_E_SERVICE_NOT_RUNNING
;
373 return AUDCLNT_E_DEVICE_IN_USE
;
377 static HRESULT
AC_OpenCaptureAL(ACImpl
*This
)
379 char alname
[MAX_PATH
];
382 freq
= This
->pwfx
->nSamplesPerSec
;
383 size
= This
->bufsize
;
385 alname
[sizeof(alname
)-1] = 0;
387 FIXME("Attempting to open device while already open\n");
390 WideCharToMultiByte(CP_UNIXCP
, 0, This
->parent
->alname
, -1,
391 alname
, sizeof(alname
)/sizeof(*alname
)-1, NULL
, NULL
);
392 This
->capdev
= palcCaptureOpenDevice(alname
, freq
, This
->format
, size
);
394 ALCenum err
= palcGetError(NULL
);
395 FIXME("Could not open device %s with buf size %u: 0x%04x\n",
396 alname
, This
->bufsize
, err
);
397 return AUDCLNT_E_DEVICE_IN_USE
;
402 static HRESULT WINAPI
AC_QueryInterface(IAudioClient
*iface
, REFIID riid
, void **ppv
)
404 TRACE("(%p)->(%s,%p)\n", iface
, debugstr_guid(riid
), ppv
);
409 if (IsEqualIID(riid
, &IID_IUnknown
)
410 || IsEqualIID(riid
, &IID_IAudioClient
))
413 IUnknown_AddRef((IUnknown
*)*ppv
);
416 WARN("Unknown interface %s\n", debugstr_guid(riid
));
417 return E_NOINTERFACE
;
420 static ULONG WINAPI
AC_AddRef(IAudioClient
*iface
)
422 ACImpl
*This
= (ACImpl
*)iface
;
424 ref
= InterlockedIncrement(&This
->ref
);
425 TRACE("Refcount now %i\n", ref
);
429 static ULONG WINAPI
AC_Release(IAudioClient
*iface
)
431 ACImpl
*This
= (ACImpl
*)iface
;
433 ref
= InterlockedDecrement(&This
->ref
);
434 TRACE("Refcount now %i\n", ref
);
436 AudioClient_Destroy(This
);
440 static HRESULT WINAPI
AC_Initialize(IAudioClient
*iface
, AUDCLNT_SHAREMODE mode
, DWORD flags
, REFERENCE_TIME duration
, REFERENCE_TIME period
, const WAVEFORMATEX
*pwfx
, const GUID
*sessionguid
)
442 ACImpl
*This
= (ACImpl
*)iface
;
445 REFERENCE_TIME time
, bufsize
;
447 TRACE("(%p)->(%x,%x,%u,%u,%p,%s)\n", This
, mode
, flags
, (int)duration
, (int)period
, pwfx
, debugstr_guid(sessionguid
));
449 return AUDCLNT_E_ALREADY_INITIALIZED
;
450 if (mode
!= AUDCLNT_SHAREMODE_SHARED
451 && mode
!= AUDCLNT_SHAREMODE_EXCLUSIVE
) {
452 WARN("Unknown mode %x\n", mode
);
453 return AUDCLNT_E_NOT_INITIALIZED
;
456 if (flags
& ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS
457 |AUDCLNT_STREAMFLAGS_LOOPBACK
458 |AUDCLNT_STREAMFLAGS_EVENTCALLBACK
459 |AUDCLNT_STREAMFLAGS_NOPERSIST
460 |AUDCLNT_STREAMFLAGS_RATEADJUST
461 |AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED
462 |AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE
463 |AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED
)) {
464 WARN("Unknown flags 0x%08x\n", flags
);
468 WARN("Flags 0x%08x ignored\n", flags
);
472 WARN("Session guid %s ignored\n", debugstr_guid(sessionguid
));
474 hr
= IAudioClient_IsFormatSupported(iface
, mode
, pwfx
, &pwfx2
);
475 CoTaskMemFree(pwfx2
);
476 if (FAILED(hr
) || pwfx2
)
477 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
478 EnterCriticalSection(This
->crst
);
479 HeapFree(GetProcessHeap(), 0, This
->pwfx
);
480 This
->pwfx
= HeapAlloc(GetProcessHeap(), 0, sizeof(*pwfx
) + pwfx
->cbSize
);
485 memcpy(This
->pwfx
, pwfx
, sizeof(*pwfx
) + pwfx
->cbSize
);
487 hr
= IAudioClient_GetDevicePeriod(iface
, &time
, NULL
);
491 This
->psize
= (DWORD64
)This
->pwfx
->nSamplesPerSec
* time
/ (DWORD64
)10000000;
492 if (duration
> 20000000)
495 bufsize
= duration
/ time
* This
->psize
;
497 bufsize
+= This
->psize
;
498 This
->bufsize
= bufsize
;
499 This
->psize
*= This
->pwfx
->nBlockAlign
;
500 bufsize
*= pwfx
->nBlockAlign
;
502 This
->format
= get_format(This
->pwfx
);
503 if (This
->parent
->flow
== eRender
) {
505 ALuint buf
= 0, towrite
;
507 hr
= AC_OpenRenderAL(This
);
511 /* Test the returned format */
512 towrite
= sizeof(silence
);
513 towrite
-= towrite
% This
->pwfx
->nBlockAlign
;
514 if (This
->pwfx
->wBitsPerSample
!= 8)
515 memset(silence
, 0, sizeof(silence
));
517 memset(silence
, 128, sizeof(silence
));
518 setALContext(This
->parent
->ctx
);
520 palGenBuffers(1, &buf
);
521 palBufferData(buf
, This
->format
, silence
, towrite
, This
->pwfx
->nSamplesPerSec
);
522 palDeleteBuffers(1, &buf
);
524 hr
= AUDCLNT_E_UNSUPPORTED_FORMAT
;
525 else if (!This
->source
) {
526 palGenSources(1, &This
->source
);
527 palSourcei(This
->source
, AL_LOOPING
, AL_FALSE
);
533 hr
= AC_OpenCaptureAL(This
);
538 This
->buffer
= HeapAlloc(GetProcessHeap(), 0, bufsize
);
545 This
->running
= FALSE
;
548 LeaveCriticalSection(This
->crst
);
552 static HRESULT WINAPI
AC_GetBufferSize(IAudioClient
*iface
, UINT32
*frames
)
554 ACImpl
*This
= (ACImpl
*)iface
;
555 TRACE("(%p)->(%p)\n", This
, frames
);
557 return AUDCLNT_E_NOT_INITIALIZED
;
560 *frames
= This
->bufsize
;
564 static HRESULT WINAPI
AC_GetStreamLatency(IAudioClient
*iface
, REFERENCE_TIME
*latency
)
566 ACImpl
*This
= (ACImpl
*)iface
;
567 TRACE("(%p)->(%p)\n", This
, latency
);
570 return AUDCLNT_E_NOT_INITIALIZED
;
580 static HRESULT WINAPI
AC_GetCurrentPadding(IAudioClient
*iface
, UINT32
*numpad
)
582 ACImpl
*This
= (ACImpl
*)iface
;
585 TRACE("(%p)->(%p)\n", This
, numpad
);
587 return AUDCLNT_E_NOT_INITIALIZED
;
590 EnterCriticalSection(This
->crst
);
591 if (This
->parent
->flow
== eRender
) {
593 ALint state
, padpart
;
594 setALContext(This
->parent
->ctx
);
596 palGetSourcei(This
->source
, AL_BYTE_OFFSET
, &padpart
);
597 palGetSourcei(This
->source
, AL_SOURCE_STATE
, &state
);
598 padpart
/= This
->pwfx
->nBlockAlign
;
599 if (state
== AL_STOPPED
&& This
->running
)
601 if (This
->running
&& This
->padpartial
!= padpart
) {
602 This
->padpartial
= padpart
;
603 This
->laststamp
= gettime();
604 #if 0 /* Manipulative lie */
605 } else if (This
->running
) {
606 ALint size
= This
->pad
- padpart
;
607 if (size
> This
->psize
)
609 played
= (gettime() - This
->laststamp
)*8;
610 played
= played
* This
->pwfx
->nSamplesPerSec
/ 10000000;
615 *numpad
= This
->pad
- This
->padpartial
- played
;
616 if (This
->handle
&& *numpad
+ This
->psize
<= This
->bufsize
)
617 SetEvent(This
->handle
);
621 DWORD block
= This
->pwfx
->nBlockAlign
;
622 DWORD psize
= This
->psize
/ block
;
623 palcGetIntegerv(This
->capdev
, ALC_CAPTURE_SAMPLES
, 1, &avail
);
625 DWORD ofs
= This
->ofs
+ This
->pad
;
627 ofs
%= This
->bufsize
;
628 buf1
= This
->buffer
+ (ofs
* block
);
629 This
->laststamp
= gettime();
631 SetEvent(This
->handle
);
633 if (ofs
+ avail
<= This
->bufsize
)
634 palcCaptureSamples(This
->capdev
, buf1
, avail
);
636 DWORD part1
= This
->bufsize
- This
->ofs
;
637 palcCaptureSamples(This
->capdev
, buf1
, part1
);
638 palcCaptureSamples(This
->capdev
, This
->buffer
, avail
- part1
);
641 This
->frameswritten
+= avail
;
642 /* Increase ofs if the app forgets to read */
643 if (This
->pad
> This
->bufsize
) {
645 WARN("Overflowed! %u bytes\n", This
->pad
- This
->bufsize
);
646 This
->ofs
+= This
->pad
- This
->bufsize
;
647 rest
= This
->ofs
% psize
;
649 This
->ofs
+= psize
- rest
;
650 This
->ofs
%= This
->bufsize
;
651 This
->pad
= This
->bufsize
- rest
;
654 if (This
->pad
>= psize
)
659 LeaveCriticalSection(This
->crst
);
661 TRACE("%u queued\n", *numpad
);
665 static HRESULT WINAPI
AC_IsFormatSupported(IAudioClient
*iface
, AUDCLNT_SHAREMODE mode
, const WAVEFORMATEX
*pwfx
, WAVEFORMATEX
**outpwfx
)
667 ACImpl
*This
= (ACImpl
*)iface
;
668 TRACE("(%p)->(%x,%p,%p)\n", This
, mode
, pwfx
, outpwfx
);
672 if (mode
== AUDCLNT_SHAREMODE_SHARED
&& !outpwfx
)
674 if (mode
!= AUDCLNT_SHAREMODE_SHARED
675 && mode
!= AUDCLNT_SHAREMODE_EXCLUSIVE
) {
676 WARN("Unknown mode %x\n", mode
);
679 if (pwfx
->wFormatTag
!= WAVE_FORMAT_EXTENSIBLE
680 && pwfx
->wFormatTag
!= WAVE_FORMAT_PCM
)
681 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
682 if (pwfx
->nSamplesPerSec
< 8000
683 || pwfx
->nSamplesPerSec
> 192000)
684 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
685 if (pwfx
->wFormatTag
!= WAVE_FORMAT_EXTENSIBLE
686 || !IsEqualIID(&((WAVEFORMATEXTENSIBLE
*)pwfx
)->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
)) {
687 if (pwfx
->wBitsPerSample
> 16)
688 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
695 static HRESULT WINAPI
AC_GetMixFormat(IAudioClient
*iface
, WAVEFORMATEX
**pwfx
)
697 ACImpl
*This
= (ACImpl
*)iface
;
698 PROPVARIANT pv
= { VT_EMPTY
};
701 TRACE("(%p)->(%p)\n", This
, pwfx
);
705 hr
= MMDevice_GetPropValue(&This
->parent
->devguid
, This
->parent
->flow
,
706 &PKEY_AudioEngine_DeviceFormat
, &pv
);
707 *pwfx
= (WAVEFORMATEX
*)pv
.u
.blob
.pBlobData
;
708 if (SUCCEEDED(hr
) && pv
.vt
== VT_EMPTY
)
711 TRACE("Returning 0x%08x\n", hr
);
715 static HRESULT WINAPI
AC_GetDevicePeriod(IAudioClient
*iface
, REFERENCE_TIME
*defperiod
, REFERENCE_TIME
*minperiod
)
717 ACImpl
*This
= (ACImpl
*)iface
;
719 TRACE("(%p)->(%p)\n", This
, minperiod
);
720 if (!defperiod
&& !minperiod
)
730 static HRESULT WINAPI
AC_Start(IAudioClient
*iface
)
732 ACImpl
*This
= (ACImpl
*)iface
;
734 REFERENCE_TIME refresh
;
736 TRACE("(%p)\n", This
);
738 return AUDCLNT_E_NOT_INITIALIZED
;
739 if (This
->flags
& AUDCLNT_STREAMFLAGS_EVENTCALLBACK
) {
741 return AUDCLNT_E_EVENTHANDLE_NOT_SET
;
742 FIXME("Event handles not fully tested\n");
744 EnterCriticalSection(This
->crst
);
746 hr
= AUDCLNT_E_NOT_STOPPED
;
749 if (This
->parent
->flow
== eRender
) {
750 setALContext(This
->parent
->ctx
);
751 palSourcePlay(This
->source
);
756 palcCaptureStart(This
->capdev
);
758 AC_GetDevicePeriod(iface
, &refresh
, NULL
);
759 if (!This
->timer_id
&& This
->handle
)
760 CreateTimerQueueTimer(&This
->timer_id
, NULL
, AC_tick
, This
,
761 refresh
/ 20000, refresh
/ 20000,
762 WT_EXECUTEINTIMERTHREAD
);
763 /* Set to 0, otherwise risk running the clock backwards
764 * This will cause AudioClock::GetPosition to return the maximum
765 * possible value for the current buffer
768 This
->running
= TRUE
;
771 LeaveCriticalSection(This
->crst
);
775 static HRESULT WINAPI
AC_Stop(IAudioClient
*iface
)
777 ACImpl
*This
= (ACImpl
*)iface
;
779 TRACE("(%p)\n", This
);
781 return AUDCLNT_E_NOT_INITIALIZED
;
784 EnterCriticalSection(This
->crst
);
785 if (This
->parent
->flow
== eRender
) {
787 setALContext(This
->parent
->ctx
);
788 This
->running
= FALSE
;
789 palSourcePause(This
->source
);
792 palGetSourcei(This
->source
, AL_SOURCE_STATE
, &state
);
793 if (state
!= AL_PLAYING
)
801 palcCaptureStop(This
->capdev
);
802 timer_id
= This
->timer_id
;
804 LeaveCriticalSection(This
->crst
);
806 DeleteTimerQueueTimer(NULL
, timer_id
, INVALID_HANDLE_VALUE
);
810 static HRESULT WINAPI
AC_Reset(IAudioClient
*iface
)
812 ACImpl
*This
= (ACImpl
*)iface
;
814 TRACE("(%p)\n", This
);
816 return AUDCLNT_E_NOT_INITIALIZED
;
818 return AUDCLNT_E_NOT_STOPPED
;
819 EnterCriticalSection(This
->crst
);
821 hr
= AUDCLNT_E_BUFFER_OPERATION_PENDING
;
824 if (This
->parent
->flow
== eRender
) {
827 setALContext(This
->parent
->ctx
);
828 palSourceStop(This
->source
);
829 palGetSourcei(This
->source
, AL_BUFFERS_PROCESSED
, &n
);
831 palSourceUnqueueBuffers(This
->source
, 1, &buf
);
832 palDeleteBuffers(1, &buf
);
838 palcGetIntegerv(This
->capdev
, ALC_CAPTURE_SAMPLES
, 1, &avail
);
840 palcCaptureSamples(This
->capdev
, This
->buffer
, avail
);
842 This
->pad
= This
->padpartial
= 0;
844 This
->frameswritten
= 0;
846 LeaveCriticalSection(This
->crst
);
850 static HRESULT WINAPI
AC_SetEventHandle(IAudioClient
*iface
, HANDLE handle
)
852 ACImpl
*This
= (ACImpl
*)iface
;
853 TRACE("(%p)\n", This
);
855 return AUDCLNT_E_NOT_INITIALIZED
;
858 if (!(This
->flags
& AUDCLNT_STREAMFLAGS_EVENTCALLBACK
))
859 return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED
;
860 This
->handle
= handle
;
864 static HRESULT WINAPI
AC_GetService(IAudioClient
*iface
, REFIID riid
, void **ppv
)
866 ACImpl
*This
= (ACImpl
*)iface
;
868 TRACE("(%p)->(%s,%p)\n", This
, debugstr_guid(riid
), ppv
);
870 return AUDCLNT_E_NOT_INITIALIZED
;
875 if (IsEqualIID(riid
, &IID_IAudioRenderClient
)) {
876 if (This
->parent
->flow
!= eRender
)
877 return AUDCLNT_E_WRONG_ENDPOINT_TYPE
;
879 hr
= AudioRenderClient_Create(This
, &This
->render
);
881 } else if (IsEqualIID(riid
, &IID_IAudioCaptureClient
)) {
882 if (This
->parent
->flow
!= eCapture
)
883 return AUDCLNT_E_WRONG_ENDPOINT_TYPE
;
885 hr
= AudioCaptureClient_Create(This
, &This
->capture
);
886 *ppv
= This
->capture
;
887 } else if (IsEqualIID(riid
, &IID_IAudioSessionControl
)) {
889 hr
= AudioSessionControl_Create(This
, &This
->session
);
890 *ppv
= This
->session
;
891 } else if (IsEqualIID(riid
, &IID_ISimpleAudioVolume
)) {
893 hr
= AudioSimpleVolume_Create(This
, &This
->svolume
);
894 *ppv
= This
->svolume
;
895 } else if (IsEqualIID(riid
, &IID_IAudioClock
)) {
897 hr
= AudioClock_Create(This
, &This
->clock
);
905 IUnknown_AddRef((IUnknown
*)*ppv
);
909 FIXME("stub %s\n", debugstr_guid(riid
));
910 return E_NOINTERFACE
;
913 static const IAudioClientVtbl ACImpl_Vtbl
=
921 AC_GetCurrentPadding
,
922 AC_IsFormatSupported
,
932 static HRESULT
AudioRenderClient_Create(ACImpl
*parent
, ACRender
**ppv
)
936 This
= *ppv
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
938 return E_OUTOFMEMORY
;
939 This
->lpVtbl
= &ACRender_Vtbl
;
941 This
->parent
= parent
;
945 static void AudioRenderClient_Destroy(ACRender
*This
)
947 This
->parent
->render
= NULL
;
948 HeapFree(GetProcessHeap(), 0, This
);
951 static HRESULT WINAPI
ACR_QueryInterface(IAudioRenderClient
*iface
, REFIID riid
, void **ppv
)
953 TRACE("(%p)->(%s,%p)\n", iface
, debugstr_guid(riid
), ppv
);
958 if (IsEqualIID(riid
, &IID_IUnknown
)
959 || IsEqualIID(riid
, &IID_IAudioRenderClient
))
962 IUnknown_AddRef((IUnknown
*)*ppv
);
965 WARN("Unknown interface %s\n", debugstr_guid(riid
));
966 return E_NOINTERFACE
;
969 static ULONG WINAPI
ACR_AddRef(IAudioRenderClient
*iface
)
971 ACRender
*This
= (ACRender
*)iface
;
973 ref
= InterlockedIncrement(&This
->ref
);
974 TRACE("Refcount now %i\n", ref
);
978 static ULONG WINAPI
ACR_Release(IAudioRenderClient
*iface
)
980 ACRender
*This
= (ACRender
*)iface
;
982 ref
= InterlockedDecrement(&This
->ref
);
983 TRACE("Refcount now %i\n", ref
);
985 AudioRenderClient_Destroy(This
);
989 static HRESULT WINAPI
ACR_GetBuffer(IAudioRenderClient
*iface
, UINT32 frames
, BYTE
**data
)
991 ACRender
*This
= (ACRender
*)iface
;
992 DWORD free
, framesize
;
993 TRACE("(%p)->(%u,%p)\n", This
, frames
, data
);
1000 if (This
->parent
->locked
) {
1002 return AUDCLNT_E_OUT_OF_ORDER
;
1004 AC_GetCurrentPadding((IAudioClient
*)This
->parent
, &free
);
1005 if (This
->parent
->bufsize
-free
< frames
) {
1006 ERR("Too large: %u %u %u\n", This
->parent
->bufsize
, free
, frames
);
1007 return AUDCLNT_E_BUFFER_TOO_LARGE
;
1009 EnterCriticalSection(This
->parent
->crst
);
1010 This
->parent
->locked
= frames
;
1011 framesize
= This
->parent
->pwfx
->nBlockAlign
;
1013 /* Exact offset doesn't matter, offset could be 0 forever
1014 * but increasing it is easier to debug */
1015 if (This
->parent
->ofs
+ frames
> This
->parent
->bufsize
)
1016 This
->parent
->ofs
= 0;
1017 *data
= This
->parent
->buffer
+ This
->parent
->ofs
* framesize
;
1019 LeaveCriticalSection(This
->parent
->crst
);
1023 static HRESULT WINAPI
ACR_ReleaseBuffer(IAudioRenderClient
*iface
, UINT32 written
, DWORD flags
)
1025 ACRender
*This
= (ACRender
*)iface
;
1026 BYTE
*buf
= This
->parent
->buffer
;
1027 DWORD framesize
= This
->parent
->pwfx
->nBlockAlign
;
1028 DWORD ofs
= This
->parent
->ofs
;
1029 DWORD bufsize
= This
->parent
->bufsize
;
1030 DWORD locked
= This
->parent
->locked
;
1031 DWORD freq
= This
->parent
->pwfx
->nSamplesPerSec
;
1032 DWORD bpp
= This
->parent
->pwfx
->wBitsPerSample
;
1035 TRACE("(%p)->(%u,%x)\n", This
, written
, flags
);
1037 if (locked
< written
)
1038 return AUDCLNT_E_INVALID_SIZE
;
1040 if (flags
& ~AUDCLNT_BUFFERFLAGS_SILENT
)
1041 return E_INVALIDARG
;
1044 FIXME("Handled right?\n");
1045 This
->parent
->locked
= 0;
1049 if (!This
->parent
->locked
)
1050 return AUDCLNT_E_OUT_OF_ORDER
;
1052 EnterCriticalSection(This
->parent
->crst
);
1053 setALContext(This
->parent
->parent
->ctx
);
1055 This
->parent
->ofs
+= written
;
1056 This
->parent
->ofs
%= bufsize
;
1057 This
->parent
->pad
+= written
;
1058 This
->parent
->frameswritten
+= written
;
1061 written
*= framesize
;
1062 bufsize
*= framesize
;
1063 locked
*= framesize
;
1065 if (flags
& AUDCLNT_BUFFERFLAGS_SILENT
)
1066 memset(buf
+ofs
, bpp
!= 8 ? 0 : 128, written
);
1067 TRACE("buf: %p, ofs: %x, written %u, freq %u\n", buf
, ofs
, written
, freq
);
1069 palGenBuffers(1, &albuf
);
1070 palBufferData(albuf
, This
->parent
->format
, buf
+ofs
, written
, freq
);
1071 palSourceQueueBuffers(This
->parent
->source
, 1, &albuf
);
1072 TRACE("Queued %u\n", albuf
);
1074 if (This
->parent
->running
) {
1075 ALint state
= AL_PLAYING
, done
= 0, padpart
= 0;
1077 palGetSourcei(This
->parent
->source
, AL_BUFFERS_PROCESSED
, &done
);
1078 palGetSourcei(This
->parent
->source
, AL_BYTE_OFFSET
, &padpart
);
1079 palGetSourcei(This
->parent
->source
, AL_SOURCE_STATE
, &state
);
1080 padpart
/= framesize
;
1082 if (state
== AL_STOPPED
) {
1083 padpart
= This
->parent
->pad
;
1084 /* Buffer might have been processed in the small window
1085 * between first and third call */
1086 palGetSourcei(This
->parent
->source
, AL_BUFFERS_PROCESSED
, &done
);
1088 if (done
|| This
->parent
->padpartial
!= padpart
)
1089 This
->parent
->laststamp
= gettime();
1090 This
->parent
->padpartial
= padpart
;
1093 ALint size
, bits
, chan
;
1096 palSourceUnqueueBuffers(This
->parent
->source
, 1, &which
);
1097 palGetBufferi(which
, AL_SIZE
, &size
);
1098 palGetBufferi(which
, AL_BITS
, &bits
);
1099 palGetBufferi(which
, AL_CHANNELS
, &chan
);
1100 size
/= bits
* chan
/ 8;
1101 if (size
> This
->parent
->pad
) {
1103 size
= This
->parent
->pad
;
1105 This
->parent
->pad
-= size
;
1106 This
->parent
->padpartial
-= size
;
1107 TRACE("Unqueued %u\n", which
);
1108 palDeleteBuffers(1, &which
);
1111 if (state
!= AL_PLAYING
) {
1112 ERR("Starting from %x\n", state
);
1113 palSourcePlay(This
->parent
->source
);
1117 This
->parent
->locked
= 0;
1121 LeaveCriticalSection(This
->parent
->crst
);
1126 static const IAudioRenderClientVtbl ACRender_Vtbl
= {
1134 static HRESULT
AudioCaptureClient_Create(ACImpl
*parent
, ACCapture
**ppv
)
1137 This
= *ppv
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
1139 return E_OUTOFMEMORY
;
1140 This
->lpVtbl
= &ACCapture_Vtbl
;
1142 This
->parent
= parent
;
1146 static void AudioCaptureClient_Destroy(ACCapture
*This
)
1148 This
->parent
->capture
= NULL
;
1149 HeapFree(GetProcessHeap(), 0, This
);
1152 static HRESULT WINAPI
ACC_QueryInterface(IAudioCaptureClient
*iface
, REFIID riid
, void **ppv
)
1154 TRACE("(%p)->(%s,%p)\n", iface
, debugstr_guid(riid
), ppv
);
1159 if (IsEqualIID(riid
, &IID_IUnknown
)
1160 || IsEqualIID(riid
, &IID_IAudioCaptureClient
))
1163 IUnknown_AddRef((IUnknown
*)*ppv
);
1166 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1167 return E_NOINTERFACE
;
1170 static ULONG WINAPI
ACC_AddRef(IAudioCaptureClient
*iface
)
1172 ACCapture
*This
= (ACCapture
*)iface
;
1174 ref
= InterlockedIncrement(&This
->ref
);
1175 TRACE("Refcount now %i\n", ref
);
1179 static ULONG WINAPI
ACC_Release(IAudioCaptureClient
*iface
)
1181 ACCapture
*This
= (ACCapture
*)iface
;
1183 ref
= InterlockedDecrement(&This
->ref
);
1184 TRACE("Refcount now %i\n", ref
);
1186 AudioCaptureClient_Destroy(This
);
1190 static HRESULT WINAPI
ACC_GetBuffer(IAudioCaptureClient
*iface
, BYTE
**data
, UINT32
*frames
, DWORD
*flags
, UINT64
*devpos
, UINT64
*qpcpos
)
1192 ACCapture
*This
= (ACCapture
*)iface
;
1194 DWORD block
= This
->parent
->pwfx
->nBlockAlign
;
1196 TRACE("(%p)->(%p,%p,%p,%p,%p)\n", This
, data
, frames
, flags
, devpos
, qpcpos
);
1203 FIXME("Flags can be null?\n");
1206 EnterCriticalSection(This
->parent
->crst
);
1207 hr
= AUDCLNT_E_OUT_OF_ORDER
;
1208 if (This
->parent
->locked
)
1210 IAudioCaptureClient_GetNextPacketSize(iface
, frames
);
1211 ofs
= This
->parent
->ofs
;
1212 bufsize
= This
->parent
->bufsize
;
1213 if ( (ofs
*block
) % This
->parent
->psize
)
1214 ERR("Unaligned offset %u with %u\n", ofs
*block
, This
->parent
->psize
);
1215 *data
= This
->parent
->buffer
+ ofs
* block
;
1216 This
->parent
->locked
= *frames
;
1218 *devpos
= This
->parent
->frameswritten
- This
->parent
->pad
;
1220 *qpcpos
= This
->parent
->laststamp
;
1224 hr
= AUDCLNT_S_BUFFER_EMPTY
;
1226 LeaveCriticalSection(This
->parent
->crst
);
1230 static HRESULT WINAPI
ACC_ReleaseBuffer(IAudioCaptureClient
*iface
, UINT32 written
)
1232 ACCapture
*This
= (ACCapture
*)iface
;
1234 EnterCriticalSection(This
->parent
->crst
);
1235 if (!written
|| written
== This
->parent
->locked
)
1236 This
->parent
->locked
= 0;
1237 else if (!This
->parent
->locked
)
1238 hr
= AUDCLNT_E_OUT_OF_ORDER
;
1240 hr
= AUDCLNT_E_INVALID_SIZE
;
1241 This
->parent
->ofs
+= written
;
1242 This
->parent
->ofs
%= This
->parent
->bufsize
;
1243 This
->parent
->pad
-= written
;
1244 LeaveCriticalSection(This
->parent
->crst
);
1248 static HRESULT WINAPI
ACC_GetNextPacketSize(IAudioCaptureClient
*iface
, UINT32
*frames
)
1250 ACCapture
*This
= (ACCapture
*)iface
;
1252 return AC_GetCurrentPadding((IAudioClient
*)This
->parent
, frames
);
1255 static const IAudioCaptureClientVtbl ACCapture_Vtbl
=
1262 ACC_GetNextPacketSize
1265 static HRESULT
AudioSessionControl_Create(ACImpl
*parent
, ACSession
**ppv
)
1268 This
= *ppv
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
1270 return E_OUTOFMEMORY
;
1271 This
->lpVtbl
= &ACSession_Vtbl
;
1273 This
->parent
= parent
;
1277 static void AudioSessionControl_Destroy(ACSession
*This
)
1279 This
->parent
->session
= NULL
;
1280 HeapFree(GetProcessHeap(), 0, This
);
1283 static HRESULT WINAPI
ACS_QueryInterface(IAudioSessionControl2
*iface
, REFIID riid
, void **ppv
)
1285 TRACE("(%p)->(%s,%p)\n", iface
, debugstr_guid(riid
), ppv
);
1290 if (IsEqualIID(riid
, &IID_IUnknown
)
1291 || IsEqualIID(riid
, &IID_IAudioSessionControl
)
1292 || IsEqualIID(riid
, &IID_IAudioSessionControl2
))
1295 IUnknown_AddRef((IUnknown
*)*ppv
);
1298 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1299 return E_NOINTERFACE
;
1302 static ULONG WINAPI
ACS_AddRef(IAudioSessionControl2
*iface
)
1304 ACSession
*This
= (ACSession
*)iface
;
1306 ref
= InterlockedIncrement(&This
->ref
);
1307 TRACE("Refcount now %i\n", ref
);
1311 static ULONG WINAPI
ACS_Release(IAudioSessionControl2
*iface
)
1313 ACSession
*This
= (ACSession
*)iface
;
1315 ref
= InterlockedDecrement(&This
->ref
);
1316 TRACE("Refcount now %i\n", ref
);
1318 AudioSessionControl_Destroy(This
);
1322 static HRESULT WINAPI
ACS_GetState(IAudioSessionControl2
*iface
, AudioSessionState
*state
)
1324 ACSession
*This
= (ACSession
*)iface
;
1325 TRACE("(%p)->(%p)\n", This
, state
);
1329 *state
= This
->parent
->parent
->state
;
1333 static HRESULT WINAPI
ACS_GetDisplayName(IAudioSessionControl2
*iface
, WCHAR
**name
)
1335 ACSession
*This
= (ACSession
*)iface
;
1336 TRACE("(%p)->(%p)\n", This
, name
);
1343 static HRESULT WINAPI
ACS_SetDisplayName(IAudioSessionControl2
*iface
, const WCHAR
*name
, const GUID
*session
)
1345 ACSession
*This
= (ACSession
*)iface
;
1346 TRACE("(%p)->(%p,%s)\n", This
, name
, debugstr_guid(session
));
1351 static HRESULT WINAPI
ACS_GetIconPath(IAudioSessionControl2
*iface
, WCHAR
**path
)
1353 ACSession
*This
= (ACSession
*)iface
;
1354 TRACE("(%p)->(%p)\n", This
, path
);
1361 static HRESULT WINAPI
ACS_SetIconPath(IAudioSessionControl2
*iface
, const WCHAR
*path
, const GUID
*session
)
1363 ACSession
*This
= (ACSession
*)iface
;
1364 TRACE("(%p)->(%p,%s)\n", This
, path
, debugstr_guid(session
));
1369 static HRESULT WINAPI
ACS_GetGroupingParam(IAudioSessionControl2
*iface
, GUID
*group
)
1371 ACSession
*This
= (ACSession
*)iface
;
1372 TRACE("(%p)->(%p)\n", This
, group
);
1379 static HRESULT WINAPI
ACS_SetGroupingParam(IAudioSessionControl2
*iface
, GUID
*group
, const GUID
*session
)
1381 ACSession
*This
= (ACSession
*)iface
;
1382 TRACE("(%p)->(%s,%s)\n", This
, debugstr_guid(group
), debugstr_guid(session
));
1387 static HRESULT WINAPI
ACS_RegisterAudioSessionNotification(IAudioSessionControl2
*iface
, IAudioSessionEvents
*events
)
1389 ACSession
*This
= (ACSession
*)iface
;
1390 TRACE("(%p)->(%p)\n", This
, events
);
1395 static HRESULT WINAPI
ACS_UnregisterAudioSessionNotification(IAudioSessionControl2
*iface
, IAudioSessionEvents
*events
)
1397 ACSession
*This
= (ACSession
*)iface
;
1398 TRACE("(%p)->(%p)\n", This
, events
);
1403 static HRESULT WINAPI
ACS_GetSessionIdentifier(IAudioSessionControl2
*iface
, WCHAR
**id
)
1405 ACSession
*This
= (ACSession
*)iface
;
1406 TRACE("(%p)->(%p)\n", This
, id
);
1413 static HRESULT WINAPI
ACS_GetSessionInstanceIdentifier(IAudioSessionControl2
*iface
, WCHAR
**id
)
1415 ACSession
*This
= (ACSession
*)iface
;
1416 TRACE("(%p)->(%p)\n", This
, id
);
1423 static HRESULT WINAPI
ACS_GetProcessId(IAudioSessionControl2
*iface
, DWORD
*pid
)
1425 ACSession
*This
= (ACSession
*)iface
;
1426 TRACE("(%p)->(%p)\n", This
, pid
);
1430 *pid
= GetCurrentProcessId();
1434 static HRESULT WINAPI
ACS_IsSystemSoundsSession(IAudioSessionControl2
*iface
)
1436 ACSession
*This
= (ACSession
*)iface
;
1437 TRACE("(%p)\n", This
);
1442 static HRESULT WINAPI
ACS_SetDuckingPreference(IAudioSessionControl2
*iface
, BOOL optout
)
1444 ACSession
*This
= (ACSession
*)iface
;
1445 TRACE("(%p)\n", This
);
1450 static const IAudioSessionControl2Vtbl ACSession_Vtbl
=
1460 ACS_GetGroupingParam
,
1461 ACS_SetGroupingParam
,
1462 ACS_RegisterAudioSessionNotification
,
1463 ACS_UnregisterAudioSessionNotification
,
1464 ACS_GetSessionIdentifier
,
1465 ACS_GetSessionInstanceIdentifier
,
1467 ACS_IsSystemSoundsSession
,
1468 ACS_SetDuckingPreference
1471 static HRESULT
AudioSimpleVolume_Create(ACImpl
*parent
, ASVolume
**ppv
)
1474 This
= *ppv
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
1476 return E_OUTOFMEMORY
;
1477 This
->lpVtbl
= &ASVolume_Vtbl
;
1479 This
->parent
= parent
;
1483 static void AudioSimpleVolume_Destroy(ASVolume
*This
)
1485 This
->parent
->svolume
= NULL
;
1486 HeapFree(GetProcessHeap(), 0, This
);
1489 static HRESULT WINAPI
ASV_QueryInterface(ISimpleAudioVolume
*iface
, REFIID riid
, void **ppv
)
1491 TRACE("(%p)->(%s,%p)\n", iface
, debugstr_guid(riid
), ppv
);
1496 if (IsEqualIID(riid
, &IID_IUnknown
)
1497 || IsEqualIID(riid
, &IID_ISimpleAudioVolume
))
1500 IUnknown_AddRef((IUnknown
*)*ppv
);
1503 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1504 return E_NOINTERFACE
;
1507 static ULONG WINAPI
ASV_AddRef(ISimpleAudioVolume
*iface
)
1509 ASVolume
*This
= (ASVolume
*)iface
;
1511 ref
= InterlockedIncrement(&This
->ref
);
1512 TRACE("Refcount now %i\n", ref
);
1516 static ULONG WINAPI
ASV_Release(ISimpleAudioVolume
*iface
)
1518 ASVolume
*This
= (ASVolume
*)iface
;
1520 ref
= InterlockedDecrement(&This
->ref
);
1521 TRACE("Refcount now %i\n", ref
);
1523 AudioSimpleVolume_Destroy(This
);
1527 static HRESULT WINAPI
ASV_SetMasterVolume(ISimpleAudioVolume
*iface
, float level
, const GUID
*context
)
1529 ASVolume
*This
= (ASVolume
*)iface
;
1530 TRACE("(%p)->(%f,%p)\n", This
, level
, context
);
1536 static HRESULT WINAPI
ASV_GetMasterVolume(ISimpleAudioVolume
*iface
, float *level
)
1538 ASVolume
*This
= (ASVolume
*)iface
;
1539 TRACE("(%p)->(%p)\n", This
, level
);
1546 static HRESULT WINAPI
ASV_SetMute(ISimpleAudioVolume
*iface
, BOOL mute
, const GUID
*context
)
1548 ASVolume
*This
= (ASVolume
*)iface
;
1549 TRACE("(%p)->(%u,%p)\n", This
, mute
, context
);
1555 static HRESULT WINAPI
ASV_GetMute(ISimpleAudioVolume
*iface
, BOOL
*mute
)
1557 ASVolume
*This
= (ASVolume
*)iface
;
1558 TRACE("(%p)->(%p)\n", This
, mute
);
1565 static const ISimpleAudioVolumeVtbl ASVolume_Vtbl
=
1570 ASV_SetMasterVolume
,
1571 ASV_GetMasterVolume
,
1576 static HRESULT
AudioClock_Create(ACImpl
*parent
, AClock
**ppv
)
1579 This
= *ppv
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
1581 return E_OUTOFMEMORY
;
1582 This
->lpVtbl
= &AClock_Vtbl
;
1583 This
->lp2Vtbl
= &AClock2_Vtbl
;
1585 This
->parent
= parent
;
1589 static void AudioClock_Destroy(AClock
*This
)
1591 This
->parent
->clock
= NULL
;
1592 HeapFree(GetProcessHeap(), 0, This
);
1595 static HRESULT WINAPI
AClock_QueryInterface(IAudioClock
*iface
, REFIID riid
, void **ppv
)
1597 AClock
*This
= (AClock
*)iface
;
1598 TRACE("(%p)->(%s,%p)\n", iface
, debugstr_guid(riid
), ppv
);
1603 if (IsEqualIID(riid
, &IID_IUnknown
)
1604 || IsEqualIID(riid
, &IID_IAudioClock
))
1606 else if (IsEqualIID(riid
, &IID_IAudioClock2
))
1607 *ppv
= &This
->lp2Vtbl
;
1609 IUnknown_AddRef((IUnknown
*)*ppv
);
1612 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1613 return E_NOINTERFACE
;
1616 static ULONG WINAPI
AClock_AddRef(IAudioClock
*iface
)
1618 AClock
*This
= (AClock
*)iface
;
1620 ref
= InterlockedIncrement(&This
->ref
);
1621 TRACE("Refcount now %i\n", ref
);
1625 static ULONG WINAPI
AClock_Release(IAudioClock
*iface
)
1627 AClock
*This
= (AClock
*)iface
;
1629 ref
= InterlockedDecrement(&This
->ref
);
1630 TRACE("Refcount now %i\n", ref
);
1632 AudioClock_Destroy(This
);
1636 static HRESULT WINAPI
AClock_GetFrequency(IAudioClock
*iface
, UINT64
*freq
)
1638 AClock
*This
= (AClock
*)iface
;
1639 TRACE("(%p)->(%p)\n", This
, freq
);
1641 *freq
= (UINT64
)This
->parent
->pwfx
->nSamplesPerSec
;
1645 static HRESULT WINAPI
AClock_GetPosition(IAudioClock
*iface
, UINT64
*pos
, UINT64
*qpctime
)
1647 AClock
*This
= (AClock
*)iface
;
1650 TRACE("(%p)->(%p,%p)\n", This
, pos
, qpctime
);
1655 EnterCriticalSection(This
->parent
->crst
);
1656 AC_GetCurrentPadding((IAudioClient
*)This
->parent
, &pad
);
1657 *pos
= This
->parent
->frameswritten
- pad
;
1659 *qpctime
= gettime();
1660 LeaveCriticalSection(This
->parent
->crst
);
1665 static HRESULT WINAPI
AClock_GetCharacteristics(IAudioClock
*iface
, DWORD
*chars
)
1667 AClock
*This
= (AClock
*)iface
;
1668 TRACE("(%p)->(%p)\n", This
, chars
);
1672 *chars
= AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ
;
1676 static const IAudioClockVtbl AClock_Vtbl
=
1678 AClock_QueryInterface
,
1681 AClock_GetFrequency
,
1683 AClock_GetCharacteristics
1686 static AClock
*get_clock_from_clock2(IAudioClock2
*iface
)
1688 return (AClock
*)((char*)iface
- offsetof(AClock
,lp2Vtbl
));
1691 static HRESULT WINAPI
AClock2_QueryInterface(IAudioClock2
*iface
, REFIID riid
, void **ppv
)
1693 AClock
*This
= get_clock_from_clock2(iface
);
1694 return IUnknown_QueryInterface((IUnknown
*)This
, riid
, ppv
);
1697 static ULONG WINAPI
AClock2_AddRef(IAudioClock2
*iface
)
1699 AClock
*This
= get_clock_from_clock2(iface
);
1700 return IUnknown_AddRef((IUnknown
*)This
);
1703 static ULONG WINAPI
AClock2_Release(IAudioClock2
*iface
)
1705 AClock
*This
= get_clock_from_clock2(iface
);
1706 return IUnknown_Release((IUnknown
*)This
);
1709 static HRESULT WINAPI
AClock2_GetPosition(IAudioClock2
*iface
, UINT64
*pos
, UINT64
*qpctime
)
1711 AClock
*This
= get_clock_from_clock2(iface
);
1712 return AClock_GetPosition((IAudioClock
*)This
, pos
, qpctime
);
1715 static const IAudioClock2Vtbl AClock2_Vtbl
=
1717 AClock2_QueryInterface
,