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 WARN("Format not supported, or had to be modified!\n");
478 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
480 EnterCriticalSection(This
->crst
);
481 HeapFree(GetProcessHeap(), 0, This
->pwfx
);
482 This
->pwfx
= HeapAlloc(GetProcessHeap(), 0, sizeof(*pwfx
) + pwfx
->cbSize
);
487 memcpy(This
->pwfx
, pwfx
, sizeof(*pwfx
) + pwfx
->cbSize
);
488 if (pwfx
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
) {
489 WAVEFORMATEXTENSIBLE
*wfe
= (WAVEFORMATEXTENSIBLE
*)This
->pwfx
;
490 switch (pwfx
->nChannels
) {
491 case 1: wfe
->dwChannelMask
= MONO
; break;
492 case 2: wfe
->dwChannelMask
= STEREO
; break;
493 case 4: wfe
->dwChannelMask
= QUAD
; break;
494 case 6: wfe
->dwChannelMask
= X5DOT1
; break;
495 case 7: wfe
->dwChannelMask
= X6DOT1
; break;
496 case 8: wfe
->dwChannelMask
= X7DOT1
; break;
498 ERR("How did we end up with %i channels?\n", pwfx
->nChannels
);
499 hr
= AUDCLNT_E_UNSUPPORTED_FORMAT
;
504 hr
= IAudioClient_GetDevicePeriod(iface
, &time
, NULL
);
508 This
->psize
= (DWORD64
)This
->pwfx
->nSamplesPerSec
* time
/ (DWORD64
)10000000;
509 if (duration
> 20000000)
512 bufsize
= duration
/ time
* This
->psize
;
514 bufsize
+= This
->psize
;
515 This
->bufsize
= bufsize
;
516 This
->psize
*= This
->pwfx
->nBlockAlign
;
517 bufsize
*= pwfx
->nBlockAlign
;
519 This
->format
= get_format(This
->pwfx
);
520 if (This
->parent
->flow
== eRender
) {
522 ALuint buf
= 0, towrite
;
524 hr
= AC_OpenRenderAL(This
);
528 /* Test the returned format */
529 towrite
= sizeof(silence
);
530 towrite
-= towrite
% This
->pwfx
->nBlockAlign
;
531 if (This
->pwfx
->wBitsPerSample
!= 8)
532 memset(silence
, 0, sizeof(silence
));
534 memset(silence
, 128, sizeof(silence
));
535 setALContext(This
->parent
->ctx
);
537 palGenBuffers(1, &buf
);
538 palBufferData(buf
, This
->format
, silence
, towrite
, This
->pwfx
->nSamplesPerSec
);
539 palDeleteBuffers(1, &buf
);
541 hr
= AUDCLNT_E_UNSUPPORTED_FORMAT
;
542 else if (!This
->source
) {
543 palGenSources(1, &This
->source
);
544 palSourcei(This
->source
, AL_LOOPING
, AL_FALSE
);
550 hr
= AC_OpenCaptureAL(This
);
555 This
->buffer
= HeapAlloc(GetProcessHeap(), 0, bufsize
);
562 This
->running
= FALSE
;
565 LeaveCriticalSection(This
->crst
);
569 static HRESULT WINAPI
AC_GetBufferSize(IAudioClient
*iface
, UINT32
*frames
)
571 ACImpl
*This
= (ACImpl
*)iface
;
572 TRACE("(%p)->(%p)\n", This
, frames
);
574 return AUDCLNT_E_NOT_INITIALIZED
;
577 *frames
= This
->bufsize
;
581 static HRESULT WINAPI
AC_GetStreamLatency(IAudioClient
*iface
, REFERENCE_TIME
*latency
)
583 ACImpl
*This
= (ACImpl
*)iface
;
584 TRACE("(%p)->(%p)\n", This
, latency
);
587 return AUDCLNT_E_NOT_INITIALIZED
;
597 static HRESULT WINAPI
AC_GetCurrentPadding(IAudioClient
*iface
, UINT32
*numpad
)
599 ACImpl
*This
= (ACImpl
*)iface
;
602 TRACE("(%p)->(%p)\n", This
, numpad
);
604 return AUDCLNT_E_NOT_INITIALIZED
;
607 EnterCriticalSection(This
->crst
);
608 if (This
->parent
->flow
== eRender
) {
610 ALint state
, padpart
;
611 setALContext(This
->parent
->ctx
);
613 palGetSourcei(This
->source
, AL_BYTE_OFFSET
, &padpart
);
614 palGetSourcei(This
->source
, AL_SOURCE_STATE
, &state
);
615 padpart
/= This
->pwfx
->nBlockAlign
;
616 if (state
== AL_STOPPED
&& This
->running
)
618 if (This
->running
&& This
->padpartial
!= padpart
) {
619 This
->padpartial
= padpart
;
620 This
->laststamp
= gettime();
621 #if 0 /* Manipulative lie */
622 } else if (This
->running
) {
623 ALint size
= This
->pad
- padpart
;
624 if (size
> This
->psize
)
626 played
= (gettime() - This
->laststamp
)*8;
627 played
= played
* This
->pwfx
->nSamplesPerSec
/ 10000000;
632 *numpad
= This
->pad
- This
->padpartial
- played
;
633 if (This
->handle
&& *numpad
+ This
->psize
<= This
->bufsize
)
634 SetEvent(This
->handle
);
638 DWORD block
= This
->pwfx
->nBlockAlign
;
639 DWORD psize
= This
->psize
/ block
;
640 palcGetIntegerv(This
->capdev
, ALC_CAPTURE_SAMPLES
, 1, &avail
);
642 DWORD ofs
= This
->ofs
+ This
->pad
;
644 ofs
%= This
->bufsize
;
645 buf1
= This
->buffer
+ (ofs
* block
);
646 This
->laststamp
= gettime();
648 SetEvent(This
->handle
);
650 if (ofs
+ avail
<= This
->bufsize
)
651 palcCaptureSamples(This
->capdev
, buf1
, avail
);
653 DWORD part1
= This
->bufsize
- ofs
;
654 palcCaptureSamples(This
->capdev
, buf1
, part1
);
655 palcCaptureSamples(This
->capdev
, This
->buffer
, avail
- part1
);
658 This
->frameswritten
+= avail
;
659 /* Increase ofs if the app forgets to read */
660 if (This
->pad
> This
->bufsize
) {
662 WARN("Overflowed! %u bytes\n", This
->pad
- This
->bufsize
);
663 This
->ofs
+= This
->pad
- This
->bufsize
;
664 rest
= This
->ofs
% psize
;
666 This
->ofs
+= psize
- rest
;
667 This
->ofs
%= This
->bufsize
;
668 This
->pad
= This
->bufsize
;
671 if (This
->pad
>= psize
)
676 LeaveCriticalSection(This
->crst
);
678 TRACE("%u queued\n", *numpad
);
682 static HRESULT WINAPI
AC_IsFormatSupported(IAudioClient
*iface
, AUDCLNT_SHAREMODE mode
, const WAVEFORMATEX
*pwfx
, WAVEFORMATEX
**outpwfx
)
684 ACImpl
*This
= (ACImpl
*)iface
;
688 TRACE("(%p)->(%x,%p,%p)\n", This
, mode
, pwfx
, outpwfx
);
692 if (mode
== AUDCLNT_SHAREMODE_SHARED
&& !outpwfx
)
694 if (mode
!= AUDCLNT_SHAREMODE_SHARED
695 && mode
!= AUDCLNT_SHAREMODE_EXCLUSIVE
) {
696 WARN("Unknown mode %x\n", mode
);
700 if (pwfx
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
701 size
= sizeof(WAVEFORMATEXTENSIBLE
);
702 else if (pwfx
->wFormatTag
== WAVE_FORMAT_PCM
)
703 size
= sizeof(WAVEFORMATEX
);
705 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
707 if (pwfx
->nSamplesPerSec
< 8000
708 || pwfx
->nSamplesPerSec
> 192000)
709 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
710 if (pwfx
->wFormatTag
!= WAVE_FORMAT_EXTENSIBLE
711 || !IsEqualIID(&((WAVEFORMATEXTENSIBLE
*)pwfx
)->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
)) {
712 if (pwfx
->wBitsPerSample
> 16)
713 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
716 switch (pwfx
->nChannels
) {
717 case 1: mask
= MONO
; break;
718 case 2: mask
= STEREO
; break;
719 case 4: mask
= QUAD
; break;
720 case 6: mask
= X5DOT1
; break;
721 case 7: mask
= X6DOT1
; break;
722 case 8: mask
= X7DOT1
; break;
724 TRACE("Unsupported channel count %i\n", pwfx
->nChannels
);
725 return AUDCLNT_E_UNSUPPORTED_FORMAT
;;
727 tmp
= CoTaskMemAlloc(size
);
731 return E_OUTOFMEMORY
;
733 memcpy(tmp
, pwfx
, size
);
734 tmp
->nBlockAlign
= tmp
->nChannels
* tmp
->wBitsPerSample
/ 8;
735 tmp
->nAvgBytesPerSec
= tmp
->nBlockAlign
* tmp
->nSamplesPerSec
;
736 tmp
->cbSize
= size
- sizeof(WAVEFORMATEX
);
737 if (tmp
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
) {
738 WAVEFORMATEXTENSIBLE
*ex
= (WAVEFORMATEXTENSIBLE
*)tmp
;
740 if (ex
->Samples
.wValidBitsPerSample
)
741 ex
->Samples
.wValidBitsPerSample
= ex
->Format
.wBitsPerSample
;
743 /* Rear is a special allowed case */
744 if (ex
->dwChannelMask
745 && !(ex
->Format
.nChannels
== 2 && ex
->dwChannelMask
== REAR
))
746 ex
->dwChannelMask
= mask
;
749 if (memcmp(pwfx
, tmp
, size
)) {
753 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
761 static HRESULT WINAPI
AC_GetMixFormat(IAudioClient
*iface
, WAVEFORMATEX
**pwfx
)
763 ACImpl
*This
= (ACImpl
*)iface
;
764 PROPVARIANT pv
= { VT_EMPTY
};
767 TRACE("(%p)->(%p)\n", This
, pwfx
);
771 hr
= MMDevice_GetPropValue(&This
->parent
->devguid
, This
->parent
->flow
,
772 &PKEY_AudioEngine_DeviceFormat
, &pv
);
773 *pwfx
= (WAVEFORMATEX
*)pv
.u
.blob
.pBlobData
;
774 if (SUCCEEDED(hr
) && pv
.vt
== VT_EMPTY
)
777 TRACE("Returning 0x%08x\n", hr
);
781 static HRESULT WINAPI
AC_GetDevicePeriod(IAudioClient
*iface
, REFERENCE_TIME
*defperiod
, REFERENCE_TIME
*minperiod
)
783 ACImpl
*This
= (ACImpl
*)iface
;
785 TRACE("(%p)->(%p)\n", This
, minperiod
);
786 if (!defperiod
&& !minperiod
)
796 static HRESULT WINAPI
AC_Start(IAudioClient
*iface
)
798 ACImpl
*This
= (ACImpl
*)iface
;
800 REFERENCE_TIME refresh
;
802 TRACE("(%p)\n", This
);
804 return AUDCLNT_E_NOT_INITIALIZED
;
805 if (This
->flags
& AUDCLNT_STREAMFLAGS_EVENTCALLBACK
) {
807 return AUDCLNT_E_EVENTHANDLE_NOT_SET
;
808 FIXME("Event handles not fully tested\n");
810 EnterCriticalSection(This
->crst
);
812 hr
= AUDCLNT_E_NOT_STOPPED
;
815 if (This
->parent
->flow
== eRender
) {
816 setALContext(This
->parent
->ctx
);
817 palSourcePlay(This
->source
);
822 palcCaptureStart(This
->capdev
);
824 AC_GetDevicePeriod(iface
, &refresh
, NULL
);
825 if (!This
->timer_id
&& This
->handle
)
826 CreateTimerQueueTimer(&This
->timer_id
, NULL
, AC_tick
, This
,
827 refresh
/ 20000, refresh
/ 20000,
828 WT_EXECUTEINTIMERTHREAD
);
829 /* Set to 0, otherwise risk running the clock backwards
830 * This will cause AudioClock::GetPosition to return the maximum
831 * possible value for the current buffer
834 This
->running
= TRUE
;
837 LeaveCriticalSection(This
->crst
);
841 static HRESULT WINAPI
AC_Stop(IAudioClient
*iface
)
843 ACImpl
*This
= (ACImpl
*)iface
;
845 TRACE("(%p)\n", This
);
847 return AUDCLNT_E_NOT_INITIALIZED
;
850 EnterCriticalSection(This
->crst
);
851 if (This
->parent
->flow
== eRender
) {
853 setALContext(This
->parent
->ctx
);
854 This
->running
= FALSE
;
855 palSourcePause(This
->source
);
858 palGetSourcei(This
->source
, AL_SOURCE_STATE
, &state
);
859 if (state
!= AL_PLAYING
)
867 palcCaptureStop(This
->capdev
);
868 timer_id
= This
->timer_id
;
870 LeaveCriticalSection(This
->crst
);
872 DeleteTimerQueueTimer(NULL
, timer_id
, INVALID_HANDLE_VALUE
);
876 static HRESULT WINAPI
AC_Reset(IAudioClient
*iface
)
878 ACImpl
*This
= (ACImpl
*)iface
;
880 TRACE("(%p)\n", This
);
882 return AUDCLNT_E_NOT_INITIALIZED
;
884 return AUDCLNT_E_NOT_STOPPED
;
885 EnterCriticalSection(This
->crst
);
887 hr
= AUDCLNT_E_BUFFER_OPERATION_PENDING
;
890 if (This
->parent
->flow
== eRender
) {
893 setALContext(This
->parent
->ctx
);
894 palSourceStop(This
->source
);
895 palGetSourcei(This
->source
, AL_BUFFERS_PROCESSED
, &n
);
897 palSourceUnqueueBuffers(This
->source
, 1, &buf
);
898 palDeleteBuffers(1, &buf
);
904 palcGetIntegerv(This
->capdev
, ALC_CAPTURE_SAMPLES
, 1, &avail
);
906 palcCaptureSamples(This
->capdev
, This
->buffer
, avail
);
908 This
->pad
= This
->padpartial
= 0;
910 This
->frameswritten
= 0;
912 LeaveCriticalSection(This
->crst
);
916 static HRESULT WINAPI
AC_SetEventHandle(IAudioClient
*iface
, HANDLE handle
)
918 ACImpl
*This
= (ACImpl
*)iface
;
919 TRACE("(%p)\n", This
);
921 return AUDCLNT_E_NOT_INITIALIZED
;
924 if (!(This
->flags
& AUDCLNT_STREAMFLAGS_EVENTCALLBACK
))
925 return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED
;
926 This
->handle
= handle
;
930 static HRESULT WINAPI
AC_GetService(IAudioClient
*iface
, REFIID riid
, void **ppv
)
932 ACImpl
*This
= (ACImpl
*)iface
;
934 TRACE("(%p)->(%s,%p)\n", This
, debugstr_guid(riid
), ppv
);
936 return AUDCLNT_E_NOT_INITIALIZED
;
941 if (IsEqualIID(riid
, &IID_IAudioRenderClient
)) {
942 if (This
->parent
->flow
!= eRender
)
943 return AUDCLNT_E_WRONG_ENDPOINT_TYPE
;
945 hr
= AudioRenderClient_Create(This
, &This
->render
);
947 } else if (IsEqualIID(riid
, &IID_IAudioCaptureClient
)) {
948 if (This
->parent
->flow
!= eCapture
)
949 return AUDCLNT_E_WRONG_ENDPOINT_TYPE
;
951 hr
= AudioCaptureClient_Create(This
, &This
->capture
);
952 *ppv
= This
->capture
;
953 } else if (IsEqualIID(riid
, &IID_IAudioSessionControl
)) {
955 hr
= AudioSessionControl_Create(This
, &This
->session
);
956 *ppv
= This
->session
;
957 } else if (IsEqualIID(riid
, &IID_ISimpleAudioVolume
)) {
959 hr
= AudioSimpleVolume_Create(This
, &This
->svolume
);
960 *ppv
= This
->svolume
;
961 } else if (IsEqualIID(riid
, &IID_IAudioClock
)) {
963 hr
= AudioClock_Create(This
, &This
->clock
);
971 IUnknown_AddRef((IUnknown
*)*ppv
);
975 FIXME("stub %s\n", debugstr_guid(riid
));
976 return E_NOINTERFACE
;
979 static const IAudioClientVtbl ACImpl_Vtbl
=
987 AC_GetCurrentPadding
,
988 AC_IsFormatSupported
,
998 static HRESULT
AudioRenderClient_Create(ACImpl
*parent
, ACRender
**ppv
)
1002 This
= *ppv
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
1004 return E_OUTOFMEMORY
;
1005 This
->lpVtbl
= &ACRender_Vtbl
;
1007 This
->parent
= parent
;
1011 static void AudioRenderClient_Destroy(ACRender
*This
)
1013 This
->parent
->render
= NULL
;
1014 HeapFree(GetProcessHeap(), 0, This
);
1017 static HRESULT WINAPI
ACR_QueryInterface(IAudioRenderClient
*iface
, REFIID riid
, void **ppv
)
1019 TRACE("(%p)->(%s,%p)\n", iface
, debugstr_guid(riid
), ppv
);
1024 if (IsEqualIID(riid
, &IID_IUnknown
)
1025 || IsEqualIID(riid
, &IID_IAudioRenderClient
))
1028 IUnknown_AddRef((IUnknown
*)*ppv
);
1031 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1032 return E_NOINTERFACE
;
1035 static ULONG WINAPI
ACR_AddRef(IAudioRenderClient
*iface
)
1037 ACRender
*This
= (ACRender
*)iface
;
1039 ref
= InterlockedIncrement(&This
->ref
);
1040 TRACE("Refcount now %i\n", ref
);
1044 static ULONG WINAPI
ACR_Release(IAudioRenderClient
*iface
)
1046 ACRender
*This
= (ACRender
*)iface
;
1048 ref
= InterlockedDecrement(&This
->ref
);
1049 TRACE("Refcount now %i\n", ref
);
1051 AudioRenderClient_Destroy(This
);
1055 static HRESULT WINAPI
ACR_GetBuffer(IAudioRenderClient
*iface
, UINT32 frames
, BYTE
**data
)
1057 ACRender
*This
= (ACRender
*)iface
;
1058 DWORD free
, framesize
;
1059 TRACE("(%p)->(%u,%p)\n", This
, frames
, data
);
1066 if (This
->parent
->locked
) {
1068 return AUDCLNT_E_OUT_OF_ORDER
;
1070 AC_GetCurrentPadding((IAudioClient
*)This
->parent
, &free
);
1071 if (This
->parent
->bufsize
-free
< frames
) {
1072 ERR("Too large: %u %u %u\n", This
->parent
->bufsize
, free
, frames
);
1073 return AUDCLNT_E_BUFFER_TOO_LARGE
;
1075 EnterCriticalSection(This
->parent
->crst
);
1076 This
->parent
->locked
= frames
;
1077 framesize
= This
->parent
->pwfx
->nBlockAlign
;
1079 /* Exact offset doesn't matter, offset could be 0 forever
1080 * but increasing it is easier to debug */
1081 if (This
->parent
->ofs
+ frames
> This
->parent
->bufsize
)
1082 This
->parent
->ofs
= 0;
1083 *data
= This
->parent
->buffer
+ This
->parent
->ofs
* framesize
;
1085 LeaveCriticalSection(This
->parent
->crst
);
1089 static HRESULT WINAPI
ACR_ReleaseBuffer(IAudioRenderClient
*iface
, UINT32 written
, DWORD flags
)
1091 ACRender
*This
= (ACRender
*)iface
;
1092 BYTE
*buf
= This
->parent
->buffer
;
1093 DWORD framesize
= This
->parent
->pwfx
->nBlockAlign
;
1094 DWORD ofs
= This
->parent
->ofs
;
1095 DWORD bufsize
= This
->parent
->bufsize
;
1096 DWORD locked
= This
->parent
->locked
;
1097 DWORD freq
= This
->parent
->pwfx
->nSamplesPerSec
;
1098 DWORD bpp
= This
->parent
->pwfx
->wBitsPerSample
;
1101 TRACE("(%p)->(%u,%x)\n", This
, written
, flags
);
1103 if (locked
< written
)
1104 return AUDCLNT_E_INVALID_SIZE
;
1106 if (flags
& ~AUDCLNT_BUFFERFLAGS_SILENT
)
1107 return E_INVALIDARG
;
1110 if (This
->parent
->locked
)
1111 FIXME("Handled right?\n");
1112 This
->parent
->locked
= 0;
1116 if (!This
->parent
->locked
)
1117 return AUDCLNT_E_OUT_OF_ORDER
;
1119 EnterCriticalSection(This
->parent
->crst
);
1120 setALContext(This
->parent
->parent
->ctx
);
1122 This
->parent
->ofs
+= written
;
1123 This
->parent
->ofs
%= bufsize
;
1124 This
->parent
->pad
+= written
;
1125 This
->parent
->frameswritten
+= written
;
1128 written
*= framesize
;
1129 bufsize
*= framesize
;
1130 locked
*= framesize
;
1132 if (flags
& AUDCLNT_BUFFERFLAGS_SILENT
)
1133 memset(buf
+ofs
, bpp
!= 8 ? 0 : 128, written
);
1134 TRACE("buf: %p, ofs: %x, written %u, freq %u\n", buf
, ofs
, written
, freq
);
1136 palGenBuffers(1, &albuf
);
1137 palBufferData(albuf
, This
->parent
->format
, buf
+ofs
, written
, freq
);
1138 palSourceQueueBuffers(This
->parent
->source
, 1, &albuf
);
1139 TRACE("Queued %u\n", albuf
);
1141 if (This
->parent
->running
) {
1142 ALint state
= AL_PLAYING
, done
= 0, padpart
= 0;
1144 palGetSourcei(This
->parent
->source
, AL_BUFFERS_PROCESSED
, &done
);
1145 palGetSourcei(This
->parent
->source
, AL_BYTE_OFFSET
, &padpart
);
1146 palGetSourcei(This
->parent
->source
, AL_SOURCE_STATE
, &state
);
1147 padpart
/= framesize
;
1149 if (state
== AL_STOPPED
) {
1150 padpart
= This
->parent
->pad
;
1151 /* Buffer might have been processed in the small window
1152 * between first and third call */
1153 palGetSourcei(This
->parent
->source
, AL_BUFFERS_PROCESSED
, &done
);
1155 if (done
|| This
->parent
->padpartial
!= padpart
)
1156 This
->parent
->laststamp
= gettime();
1157 This
->parent
->padpartial
= padpart
;
1160 ALint size
, bits
, chan
;
1163 palSourceUnqueueBuffers(This
->parent
->source
, 1, &which
);
1164 palGetBufferi(which
, AL_SIZE
, &size
);
1165 palGetBufferi(which
, AL_BITS
, &bits
);
1166 palGetBufferi(which
, AL_CHANNELS
, &chan
);
1167 size
/= bits
* chan
/ 8;
1168 if (size
> This
->parent
->pad
) {
1170 size
= This
->parent
->pad
;
1172 This
->parent
->pad
-= size
;
1173 This
->parent
->padpartial
-= size
;
1174 TRACE("Unqueued %u\n", which
);
1175 palDeleteBuffers(1, &which
);
1178 if (state
!= AL_PLAYING
) {
1179 ERR("Starting from %x\n", state
);
1180 palSourcePlay(This
->parent
->source
);
1184 This
->parent
->locked
= 0;
1188 LeaveCriticalSection(This
->parent
->crst
);
1193 static const IAudioRenderClientVtbl ACRender_Vtbl
= {
1201 static HRESULT
AudioCaptureClient_Create(ACImpl
*parent
, ACCapture
**ppv
)
1204 This
= *ppv
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
1206 return E_OUTOFMEMORY
;
1207 This
->lpVtbl
= &ACCapture_Vtbl
;
1209 This
->parent
= parent
;
1213 static void AudioCaptureClient_Destroy(ACCapture
*This
)
1215 This
->parent
->capture
= NULL
;
1216 HeapFree(GetProcessHeap(), 0, This
);
1219 static HRESULT WINAPI
ACC_QueryInterface(IAudioCaptureClient
*iface
, REFIID riid
, void **ppv
)
1221 TRACE("(%p)->(%s,%p)\n", iface
, debugstr_guid(riid
), ppv
);
1226 if (IsEqualIID(riid
, &IID_IUnknown
)
1227 || IsEqualIID(riid
, &IID_IAudioCaptureClient
))
1230 IUnknown_AddRef((IUnknown
*)*ppv
);
1233 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1234 return E_NOINTERFACE
;
1237 static ULONG WINAPI
ACC_AddRef(IAudioCaptureClient
*iface
)
1239 ACCapture
*This
= (ACCapture
*)iface
;
1241 ref
= InterlockedIncrement(&This
->ref
);
1242 TRACE("Refcount now %i\n", ref
);
1246 static ULONG WINAPI
ACC_Release(IAudioCaptureClient
*iface
)
1248 ACCapture
*This
= (ACCapture
*)iface
;
1250 ref
= InterlockedDecrement(&This
->ref
);
1251 TRACE("Refcount now %i\n", ref
);
1253 AudioCaptureClient_Destroy(This
);
1257 static HRESULT WINAPI
ACC_GetBuffer(IAudioCaptureClient
*iface
, BYTE
**data
, UINT32
*frames
, DWORD
*flags
, UINT64
*devpos
, UINT64
*qpcpos
)
1259 ACCapture
*This
= (ACCapture
*)iface
;
1261 DWORD block
= This
->parent
->pwfx
->nBlockAlign
;
1263 TRACE("(%p)->(%p,%p,%p,%p,%p)\n", This
, data
, frames
, flags
, devpos
, qpcpos
);
1270 FIXME("Flags can be null?\n");
1273 EnterCriticalSection(This
->parent
->crst
);
1274 hr
= AUDCLNT_E_OUT_OF_ORDER
;
1275 if (This
->parent
->locked
)
1277 IAudioCaptureClient_GetNextPacketSize(iface
, frames
);
1278 ofs
= This
->parent
->ofs
;
1279 bufsize
= This
->parent
->bufsize
;
1280 if ( (ofs
*block
) % This
->parent
->psize
)
1281 ERR("Unaligned offset %u with %u\n", ofs
*block
, This
->parent
->psize
);
1282 *data
= This
->parent
->buffer
+ ofs
* block
;
1283 This
->parent
->locked
= *frames
;
1285 *devpos
= This
->parent
->frameswritten
- This
->parent
->pad
;
1287 *qpcpos
= This
->parent
->laststamp
;
1291 hr
= AUDCLNT_S_BUFFER_EMPTY
;
1293 LeaveCriticalSection(This
->parent
->crst
);
1294 TRACE("Returning %08x %i\n", hr
, *frames
);
1298 static HRESULT WINAPI
ACC_ReleaseBuffer(IAudioCaptureClient
*iface
, UINT32 written
)
1300 ACCapture
*This
= (ACCapture
*)iface
;
1302 EnterCriticalSection(This
->parent
->crst
);
1303 if (!written
|| written
== This
->parent
->locked
) {
1304 This
->parent
->locked
= 0;
1305 This
->parent
->ofs
+= written
;
1306 This
->parent
->ofs
%= This
->parent
->bufsize
;
1307 This
->parent
->pad
-= written
;
1308 } else if (!This
->parent
->locked
)
1309 hr
= AUDCLNT_E_OUT_OF_ORDER
;
1311 hr
= AUDCLNT_E_INVALID_SIZE
;
1312 LeaveCriticalSection(This
->parent
->crst
);
1316 static HRESULT WINAPI
ACC_GetNextPacketSize(IAudioCaptureClient
*iface
, UINT32
*frames
)
1318 ACCapture
*This
= (ACCapture
*)iface
;
1320 return AC_GetCurrentPadding((IAudioClient
*)This
->parent
, frames
);
1323 static const IAudioCaptureClientVtbl ACCapture_Vtbl
=
1330 ACC_GetNextPacketSize
1333 static HRESULT
AudioSessionControl_Create(ACImpl
*parent
, ACSession
**ppv
)
1336 This
= *ppv
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
1338 return E_OUTOFMEMORY
;
1339 This
->lpVtbl
= &ACSession_Vtbl
;
1341 This
->parent
= parent
;
1345 static void AudioSessionControl_Destroy(ACSession
*This
)
1347 This
->parent
->session
= NULL
;
1348 HeapFree(GetProcessHeap(), 0, This
);
1351 static HRESULT WINAPI
ACS_QueryInterface(IAudioSessionControl2
*iface
, REFIID riid
, void **ppv
)
1353 TRACE("(%p)->(%s,%p)\n", iface
, debugstr_guid(riid
), ppv
);
1358 if (IsEqualIID(riid
, &IID_IUnknown
)
1359 || IsEqualIID(riid
, &IID_IAudioSessionControl
)
1360 || IsEqualIID(riid
, &IID_IAudioSessionControl2
))
1363 IUnknown_AddRef((IUnknown
*)*ppv
);
1366 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1367 return E_NOINTERFACE
;
1370 static ULONG WINAPI
ACS_AddRef(IAudioSessionControl2
*iface
)
1372 ACSession
*This
= (ACSession
*)iface
;
1374 ref
= InterlockedIncrement(&This
->ref
);
1375 TRACE("Refcount now %i\n", ref
);
1379 static ULONG WINAPI
ACS_Release(IAudioSessionControl2
*iface
)
1381 ACSession
*This
= (ACSession
*)iface
;
1383 ref
= InterlockedDecrement(&This
->ref
);
1384 TRACE("Refcount now %i\n", ref
);
1386 AudioSessionControl_Destroy(This
);
1390 static HRESULT WINAPI
ACS_GetState(IAudioSessionControl2
*iface
, AudioSessionState
*state
)
1392 ACSession
*This
= (ACSession
*)iface
;
1393 TRACE("(%p)->(%p)\n", This
, state
);
1397 *state
= This
->parent
->parent
->state
;
1401 static HRESULT WINAPI
ACS_GetDisplayName(IAudioSessionControl2
*iface
, WCHAR
**name
)
1403 ACSession
*This
= (ACSession
*)iface
;
1404 TRACE("(%p)->(%p)\n", This
, name
);
1411 static HRESULT WINAPI
ACS_SetDisplayName(IAudioSessionControl2
*iface
, const WCHAR
*name
, const GUID
*session
)
1413 ACSession
*This
= (ACSession
*)iface
;
1414 TRACE("(%p)->(%p,%s)\n", This
, name
, debugstr_guid(session
));
1419 static HRESULT WINAPI
ACS_GetIconPath(IAudioSessionControl2
*iface
, WCHAR
**path
)
1421 ACSession
*This
= (ACSession
*)iface
;
1422 TRACE("(%p)->(%p)\n", This
, path
);
1429 static HRESULT WINAPI
ACS_SetIconPath(IAudioSessionControl2
*iface
, const WCHAR
*path
, const GUID
*session
)
1431 ACSession
*This
= (ACSession
*)iface
;
1432 TRACE("(%p)->(%p,%s)\n", This
, path
, debugstr_guid(session
));
1437 static HRESULT WINAPI
ACS_GetGroupingParam(IAudioSessionControl2
*iface
, GUID
*group
)
1439 ACSession
*This
= (ACSession
*)iface
;
1440 TRACE("(%p)->(%p)\n", This
, group
);
1447 static HRESULT WINAPI
ACS_SetGroupingParam(IAudioSessionControl2
*iface
, GUID
*group
, const GUID
*session
)
1449 ACSession
*This
= (ACSession
*)iface
;
1450 TRACE("(%p)->(%s,%s)\n", This
, debugstr_guid(group
), debugstr_guid(session
));
1455 static HRESULT WINAPI
ACS_RegisterAudioSessionNotification(IAudioSessionControl2
*iface
, IAudioSessionEvents
*events
)
1457 ACSession
*This
= (ACSession
*)iface
;
1458 TRACE("(%p)->(%p)\n", This
, events
);
1463 static HRESULT WINAPI
ACS_UnregisterAudioSessionNotification(IAudioSessionControl2
*iface
, IAudioSessionEvents
*events
)
1465 ACSession
*This
= (ACSession
*)iface
;
1466 TRACE("(%p)->(%p)\n", This
, events
);
1471 static HRESULT WINAPI
ACS_GetSessionIdentifier(IAudioSessionControl2
*iface
, WCHAR
**id
)
1473 ACSession
*This
= (ACSession
*)iface
;
1474 TRACE("(%p)->(%p)\n", This
, id
);
1481 static HRESULT WINAPI
ACS_GetSessionInstanceIdentifier(IAudioSessionControl2
*iface
, WCHAR
**id
)
1483 ACSession
*This
= (ACSession
*)iface
;
1484 TRACE("(%p)->(%p)\n", This
, id
);
1491 static HRESULT WINAPI
ACS_GetProcessId(IAudioSessionControl2
*iface
, DWORD
*pid
)
1493 ACSession
*This
= (ACSession
*)iface
;
1494 TRACE("(%p)->(%p)\n", This
, pid
);
1498 *pid
= GetCurrentProcessId();
1502 static HRESULT WINAPI
ACS_IsSystemSoundsSession(IAudioSessionControl2
*iface
)
1504 ACSession
*This
= (ACSession
*)iface
;
1505 TRACE("(%p)\n", This
);
1510 static HRESULT WINAPI
ACS_SetDuckingPreference(IAudioSessionControl2
*iface
, BOOL optout
)
1512 ACSession
*This
= (ACSession
*)iface
;
1513 TRACE("(%p)\n", This
);
1518 static const IAudioSessionControl2Vtbl ACSession_Vtbl
=
1528 ACS_GetGroupingParam
,
1529 ACS_SetGroupingParam
,
1530 ACS_RegisterAudioSessionNotification
,
1531 ACS_UnregisterAudioSessionNotification
,
1532 ACS_GetSessionIdentifier
,
1533 ACS_GetSessionInstanceIdentifier
,
1535 ACS_IsSystemSoundsSession
,
1536 ACS_SetDuckingPreference
1539 static HRESULT
AudioSimpleVolume_Create(ACImpl
*parent
, ASVolume
**ppv
)
1542 This
= *ppv
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
1544 return E_OUTOFMEMORY
;
1545 This
->lpVtbl
= &ASVolume_Vtbl
;
1547 This
->parent
= parent
;
1551 static void AudioSimpleVolume_Destroy(ASVolume
*This
)
1553 This
->parent
->svolume
= NULL
;
1554 HeapFree(GetProcessHeap(), 0, This
);
1557 static HRESULT WINAPI
ASV_QueryInterface(ISimpleAudioVolume
*iface
, REFIID riid
, void **ppv
)
1559 TRACE("(%p)->(%s,%p)\n", iface
, debugstr_guid(riid
), ppv
);
1564 if (IsEqualIID(riid
, &IID_IUnknown
)
1565 || IsEqualIID(riid
, &IID_ISimpleAudioVolume
))
1568 IUnknown_AddRef((IUnknown
*)*ppv
);
1571 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1572 return E_NOINTERFACE
;
1575 static ULONG WINAPI
ASV_AddRef(ISimpleAudioVolume
*iface
)
1577 ASVolume
*This
= (ASVolume
*)iface
;
1579 ref
= InterlockedIncrement(&This
->ref
);
1580 TRACE("Refcount now %i\n", ref
);
1584 static ULONG WINAPI
ASV_Release(ISimpleAudioVolume
*iface
)
1586 ASVolume
*This
= (ASVolume
*)iface
;
1588 ref
= InterlockedDecrement(&This
->ref
);
1589 TRACE("Refcount now %i\n", ref
);
1591 AudioSimpleVolume_Destroy(This
);
1595 static HRESULT WINAPI
ASV_SetMasterVolume(ISimpleAudioVolume
*iface
, float level
, const GUID
*context
)
1597 ASVolume
*This
= (ASVolume
*)iface
;
1598 TRACE("(%p)->(%f,%p)\n", This
, level
, context
);
1604 static HRESULT WINAPI
ASV_GetMasterVolume(ISimpleAudioVolume
*iface
, float *level
)
1606 ASVolume
*This
= (ASVolume
*)iface
;
1607 TRACE("(%p)->(%p)\n", This
, level
);
1614 static HRESULT WINAPI
ASV_SetMute(ISimpleAudioVolume
*iface
, BOOL mute
, const GUID
*context
)
1616 ASVolume
*This
= (ASVolume
*)iface
;
1617 TRACE("(%p)->(%u,%p)\n", This
, mute
, context
);
1623 static HRESULT WINAPI
ASV_GetMute(ISimpleAudioVolume
*iface
, BOOL
*mute
)
1625 ASVolume
*This
= (ASVolume
*)iface
;
1626 TRACE("(%p)->(%p)\n", This
, mute
);
1633 static const ISimpleAudioVolumeVtbl ASVolume_Vtbl
=
1638 ASV_SetMasterVolume
,
1639 ASV_GetMasterVolume
,
1644 static HRESULT
AudioClock_Create(ACImpl
*parent
, AClock
**ppv
)
1647 This
= *ppv
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
1649 return E_OUTOFMEMORY
;
1650 This
->lpVtbl
= &AClock_Vtbl
;
1651 This
->lp2Vtbl
= &AClock2_Vtbl
;
1653 This
->parent
= parent
;
1657 static void AudioClock_Destroy(AClock
*This
)
1659 This
->parent
->clock
= NULL
;
1660 HeapFree(GetProcessHeap(), 0, This
);
1663 static HRESULT WINAPI
AClock_QueryInterface(IAudioClock
*iface
, REFIID riid
, void **ppv
)
1665 AClock
*This
= (AClock
*)iface
;
1666 TRACE("(%p)->(%s,%p)\n", iface
, debugstr_guid(riid
), ppv
);
1671 if (IsEqualIID(riid
, &IID_IUnknown
)
1672 || IsEqualIID(riid
, &IID_IAudioClock
))
1674 else if (IsEqualIID(riid
, &IID_IAudioClock2
))
1675 *ppv
= &This
->lp2Vtbl
;
1677 IUnknown_AddRef((IUnknown
*)*ppv
);
1680 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1681 return E_NOINTERFACE
;
1684 static ULONG WINAPI
AClock_AddRef(IAudioClock
*iface
)
1686 AClock
*This
= (AClock
*)iface
;
1688 ref
= InterlockedIncrement(&This
->ref
);
1689 TRACE("Refcount now %i\n", ref
);
1693 static ULONG WINAPI
AClock_Release(IAudioClock
*iface
)
1695 AClock
*This
= (AClock
*)iface
;
1697 ref
= InterlockedDecrement(&This
->ref
);
1698 TRACE("Refcount now %i\n", ref
);
1700 AudioClock_Destroy(This
);
1704 static HRESULT WINAPI
AClock_GetFrequency(IAudioClock
*iface
, UINT64
*freq
)
1706 AClock
*This
= (AClock
*)iface
;
1707 TRACE("(%p)->(%p)\n", This
, freq
);
1709 *freq
= (UINT64
)This
->parent
->pwfx
->nSamplesPerSec
;
1713 static HRESULT WINAPI
AClock_GetPosition(IAudioClock
*iface
, UINT64
*pos
, UINT64
*qpctime
)
1715 AClock
*This
= (AClock
*)iface
;
1718 TRACE("(%p)->(%p,%p)\n", This
, pos
, qpctime
);
1723 EnterCriticalSection(This
->parent
->crst
);
1724 AC_GetCurrentPadding((IAudioClient
*)This
->parent
, &pad
);
1725 *pos
= This
->parent
->frameswritten
- pad
;
1727 *qpctime
= gettime();
1728 LeaveCriticalSection(This
->parent
->crst
);
1733 static HRESULT WINAPI
AClock_GetCharacteristics(IAudioClock
*iface
, DWORD
*chars
)
1735 AClock
*This
= (AClock
*)iface
;
1736 TRACE("(%p)->(%p)\n", This
, chars
);
1740 *chars
= AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ
;
1744 static const IAudioClockVtbl AClock_Vtbl
=
1746 AClock_QueryInterface
,
1749 AClock_GetFrequency
,
1751 AClock_GetCharacteristics
1754 static AClock
*get_clock_from_clock2(IAudioClock2
*iface
)
1756 return (AClock
*)((char*)iface
- offsetof(AClock
,lp2Vtbl
));
1759 static HRESULT WINAPI
AClock2_QueryInterface(IAudioClock2
*iface
, REFIID riid
, void **ppv
)
1761 AClock
*This
= get_clock_from_clock2(iface
);
1762 return IUnknown_QueryInterface((IUnknown
*)This
, riid
, ppv
);
1765 static ULONG WINAPI
AClock2_AddRef(IAudioClock2
*iface
)
1767 AClock
*This
= get_clock_from_clock2(iface
);
1768 return IUnknown_AddRef((IUnknown
*)This
);
1771 static ULONG WINAPI
AClock2_Release(IAudioClock2
*iface
)
1773 AClock
*This
= get_clock_from_clock2(iface
);
1774 return IUnknown_Release((IUnknown
*)This
);
1777 static HRESULT WINAPI
AClock2_GetPosition(IAudioClock2
*iface
, UINT64
*pos
, UINT64
*qpctime
)
1779 AClock
*This
= get_clock_from_clock2(iface
);
1780 return AClock_GetPosition((IAudioClock
*)This
, pos
, qpctime
);
1783 static const IAudioClock2Vtbl AClock2_Vtbl
=
1785 AClock2_QueryInterface
,