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
, candisconnect
;
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 valid_dev(ACImpl
*This
)
139 if (This
->parent
->flow
== eRender
&& This
->dev
!= This
->parent
->device
)
144 static int get_format_PCM(WAVEFORMATEX
*format
)
146 if (format
->nChannels
> 2) {
147 FIXME("nChannels > 2 not documented for WAVE_FORMAT_PCM!\n");
153 if (format
->nBlockAlign
!= format
->wBitsPerSample
/8*format
->nChannels
) {
154 WARN("Invalid nBlockAlign %u, from %u %u\n",
155 format
->nBlockAlign
, format
->wBitsPerSample
, format
->nChannels
);
159 switch (format
->wBitsPerSample
) {
161 switch (format
->nChannels
) {
162 case 1: return AL_FORMAT_MONO8
;
163 case 2: return AL_FORMAT_STEREO8
;
167 switch (format
->nChannels
) {
168 case 1: return AL_FORMAT_MONO16
;
169 case 2: return AL_FORMAT_STEREO16
;
174 if (!(format
->wBitsPerSample
% 8))
175 WARN("Could not get OpenAL format (%d-bit, %d channels)\n",
176 format
->wBitsPerSample
, format
->nChannels
);
180 /* Speaker configs */
181 #define MONO SPEAKER_FRONT_CENTER
182 #define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)
183 #define REAR (SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
184 #define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
185 #define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
186 #define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
187 #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)
189 static int get_format_EXT(WAVEFORMATEX
*format
)
191 WAVEFORMATEXTENSIBLE
*wfe
;
193 if(format
->cbSize
< sizeof(WAVEFORMATEXTENSIBLE
)-sizeof(WAVEFORMATEX
)) {
194 WARN("Invalid cbSize specified for WAVE_FORMAT_EXTENSIBLE (%d)\n", format
->cbSize
);
198 wfe
= (WAVEFORMATEXTENSIBLE
*)format
;
199 wfe
->Format
.cbSize
= sizeof(WAVEFORMATEXTENSIBLE
)-sizeof(WAVEFORMATEX
);
200 if (wfe
->Samples
.wValidBitsPerSample
&&
201 wfe
->Samples
.wValidBitsPerSample
!= format
->wBitsPerSample
) {
202 FIXME("wValidBitsPerSample(%u) != wBitsPerSample(%u) unsupported\n",
203 wfe
->Samples
.wValidBitsPerSample
, format
->wBitsPerSample
);
207 TRACE("Extensible values:\n"
209 " ChannelMask = 0x%08x\n"
211 wfe
->Samples
.wReserved
, wfe
->dwChannelMask
,
212 debugstr_guid(&wfe
->SubFormat
));
214 if (wfe
->dwChannelMask
!= MONO
215 && wfe
->dwChannelMask
!= STEREO
216 && !palIsExtensionPresent("AL_EXT_MCFORMATS")) {
217 /* QUAD PCM might still work, special case */
218 if (palIsExtensionPresent("AL_LOKI_quadriphonic")
219 && IsEqualGUID(&wfe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
)
220 && wfe
->dwChannelMask
== QUAD
) {
221 if (format
->wBitsPerSample
== 16)
222 return AL_FORMAT_QUAD16_LOKI
;
223 else if (format
->wBitsPerSample
== 8)
224 return AL_FORMAT_QUAD8_LOKI
;
226 WARN("Not all formats available\n");
230 if(IsEqualGUID(&wfe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
)) {
231 if (format
->wBitsPerSample
== 8) {
232 switch (wfe
->dwChannelMask
) {
233 case MONO
: return AL_FORMAT_MONO8
;
234 case STEREO
: return AL_FORMAT_STEREO8
;
235 case REAR
: return AL_FORMAT_REAR8
;
236 case QUAD
: return AL_FORMAT_QUAD8
;
237 case X5DOT1
: return AL_FORMAT_51CHN8
;
238 case X6DOT1
: return AL_FORMAT_61CHN8
;
239 case X7DOT1
: return AL_FORMAT_71CHN8
;
242 } else if (format
->wBitsPerSample
== 16) {
243 switch (wfe
->dwChannelMask
) {
244 case MONO
: return AL_FORMAT_MONO16
;
245 case STEREO
: return AL_FORMAT_STEREO16
;
246 case REAR
: return AL_FORMAT_REAR16
;
247 case QUAD
: return AL_FORMAT_QUAD16
;
248 case X5DOT1
: return AL_FORMAT_51CHN16
;
249 case X6DOT1
: return AL_FORMAT_61CHN16
;
250 case X7DOT1
: return AL_FORMAT_71CHN16
;
254 else if (!(format
->wBitsPerSample
% 8))
255 ERR("Could not get OpenAL PCM format (%d-bit, mask 0x%08x)\n",
256 format
->wBitsPerSample
, wfe
->dwChannelMask
);
259 else if(IsEqualGUID(&wfe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
)) {
260 if (format
->wBitsPerSample
!= 32) {
261 WARN("Invalid valid bits %u/32\n", format
->wBitsPerSample
);
264 switch (wfe
->dwChannelMask
) {
265 case MONO
: return AL_FORMAT_MONO_FLOAT32
;
266 case STEREO
: return AL_FORMAT_STEREO_FLOAT32
;
267 case REAR
: return AL_FORMAT_REAR32
;
268 case QUAD
: return AL_FORMAT_QUAD32
;
269 case X5DOT1
: return AL_FORMAT_51CHN32
;
270 case X6DOT1
: return AL_FORMAT_61CHN32
;
271 case X7DOT1
: return AL_FORMAT_71CHN32
;
273 ERR("Could not get OpenAL float format (%d-bit, mask 0x%08x)\n",
274 format
->wBitsPerSample
, wfe
->dwChannelMask
);
278 else if (!IsEqualGUID(&wfe
->SubFormat
, &GUID_NULL
))
279 ERR("Unhandled extensible format: %s\n", debugstr_guid(&wfe
->SubFormat
));
283 static ALint
get_format(WAVEFORMATEX
*in
)
286 if (in
->wFormatTag
== WAVE_FORMAT_PCM
)
287 ret
= get_format_PCM(in
);
288 else if (in
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
289 ret
= get_format_EXT(in
);
293 static REFERENCE_TIME
gettime(void) {
294 LARGE_INTEGER stamp
, freq
;
295 QueryPerformanceCounter(&stamp
);
296 QueryPerformanceFrequency(&freq
);
297 return (stamp
.QuadPart
* (INT64
)10000000) / freq
.QuadPart
;
300 HRESULT
AudioClient_Create(MMDevice
*parent
, IAudioClient
**ppv
)
302 ACImpl
*This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*This
));
303 *ppv
= (IAudioClient
*)This
;
305 return E_OUTOFMEMORY
;
306 This
->crst
= &parent
->crst
;
307 This
->lpVtbl
= &ACImpl_Vtbl
;
309 This
->parent
= parent
;
313 static void AudioClient_Destroy(ACImpl
*This
)
316 DeleteTimerQueueTimer(NULL
, This
->timer_id
, INVALID_HANDLE_VALUE
);
318 AudioRenderClient_Destroy(This
->render
);
320 AudioCaptureClient_Destroy(This
->capture
);
322 AudioSessionControl_Destroy(This
->session
);
324 AudioSimpleVolume_Destroy(This
->svolume
);
326 AudioClock_Destroy(This
->clock
);
327 if (!valid_dev(This
))
328 TRACE("Not destroying device since none exists\n");
329 else if (This
->parent
->flow
== eRender
) {
330 setALContext(This
->parent
->ctx
);
331 IAudioClient_Stop((IAudioClient
*)This
);
332 IAudioClient_Reset((IAudioClient
*)This
);
333 palDeleteSources(1, &This
->source
);
337 else if (This
->parent
->flow
== eCapture
)
338 palcCaptureCloseDevice(This
->dev
);
339 HeapFree(GetProcessHeap(), 0, This
->pwfx
);
340 HeapFree(GetProcessHeap(), 0, This
->buffer
);
341 HeapFree(GetProcessHeap(), 0, This
);
344 static void CALLBACK
AC_tick(void *data
, BOOLEAN fired
)
349 EnterCriticalSection(This
->crst
);
351 IAudioClient_GetCurrentPadding((IAudioClient
*)This
, &pad
);
352 LeaveCriticalSection(This
->crst
);
355 /* Open device and set/update internal mixing format based on information
356 * openal provides us. if the device cannot be opened, assume 48khz
357 * Guessing the frequency is harmless, since if GetMixFormat fails to open
358 * the device, then Initialize will likely fail as well
360 static HRESULT
AC_OpenRenderAL(ACImpl
*This
)
362 char alname
[MAX_PATH
];
363 MMDevice
*cur
= This
->parent
;
365 alname
[sizeof(alname
)-1] = 0;
367 return cur
->ctx
? S_OK
: AUDCLNT_E_SERVICE_NOT_RUNNING
;
369 WideCharToMultiByte(CP_UNIXCP
, 0, cur
->alname
, -1,
370 alname
, sizeof(alname
)/sizeof(*alname
)-1, NULL
, NULL
);
371 cur
->device
= palcOpenDevice(alname
);
373 ALCenum err
= palcGetError(NULL
);
374 WARN("Could not open device %s: 0x%04x\n", alname
, err
);
375 return AUDCLNT_E_DEVICE_IN_USE
;
377 cur
->ctx
= palcCreateContext(cur
->device
, NULL
);
379 ALCenum err
= palcGetError(cur
->device
);
380 ERR("Could not create context: 0x%04x\n", err
);
381 return AUDCLNT_E_SERVICE_NOT_RUNNING
;
384 return AUDCLNT_E_DEVICE_IN_USE
;
388 static HRESULT
AC_OpenCaptureAL(ACImpl
*This
)
390 char alname
[MAX_PATH
];
393 freq
= This
->pwfx
->nSamplesPerSec
;
394 size
= This
->bufsize
;
396 alname
[sizeof(alname
)-1] = 0;
398 FIXME("Attempting to open device while already open\n");
401 WideCharToMultiByte(CP_UNIXCP
, 0, This
->parent
->alname
, -1,
402 alname
, sizeof(alname
)/sizeof(*alname
)-1, NULL
, NULL
);
403 This
->dev
= palcCaptureOpenDevice(alname
, freq
, This
->format
, size
);
405 ALCenum err
= palcGetError(NULL
);
406 FIXME("Could not open device %s with buf size %u: 0x%04x\n",
407 alname
, This
->bufsize
, err
);
408 return AUDCLNT_E_DEVICE_IN_USE
;
413 static HRESULT WINAPI
AC_QueryInterface(IAudioClient
*iface
, REFIID riid
, void **ppv
)
415 TRACE("(%p)->(%s,%p)\n", iface
, debugstr_guid(riid
), ppv
);
420 if (IsEqualIID(riid
, &IID_IUnknown
)
421 || IsEqualIID(riid
, &IID_IAudioClient
))
424 IUnknown_AddRef((IUnknown
*)*ppv
);
427 WARN("Unknown interface %s\n", debugstr_guid(riid
));
428 return E_NOINTERFACE
;
431 static ULONG WINAPI
AC_AddRef(IAudioClient
*iface
)
433 ACImpl
*This
= (ACImpl
*)iface
;
435 ref
= InterlockedIncrement(&This
->ref
);
436 TRACE("Refcount now %i\n", ref
);
440 static ULONG WINAPI
AC_Release(IAudioClient
*iface
)
442 ACImpl
*This
= (ACImpl
*)iface
;
444 ref
= InterlockedDecrement(&This
->ref
);
445 TRACE("Refcount now %i\n", ref
);
447 AudioClient_Destroy(This
);
451 static HRESULT WINAPI
AC_Initialize(IAudioClient
*iface
, AUDCLNT_SHAREMODE mode
, DWORD flags
, REFERENCE_TIME duration
, REFERENCE_TIME period
, const WAVEFORMATEX
*pwfx
, const GUID
*sessionguid
)
453 ACImpl
*This
= (ACImpl
*)iface
;
456 REFERENCE_TIME time
, bufsize
;
458 TRACE("(%p)->(%x,%x,%u,%u,%p,%s)\n", This
, mode
, flags
, (int)duration
, (int)period
, pwfx
, debugstr_guid(sessionguid
));
460 return AUDCLNT_E_ALREADY_INITIALIZED
;
461 if (mode
!= AUDCLNT_SHAREMODE_SHARED
462 && mode
!= AUDCLNT_SHAREMODE_EXCLUSIVE
) {
463 WARN("Unknown mode %x\n", mode
);
464 return AUDCLNT_E_NOT_INITIALIZED
;
467 if (flags
& ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS
468 |AUDCLNT_STREAMFLAGS_LOOPBACK
469 |AUDCLNT_STREAMFLAGS_EVENTCALLBACK
470 |AUDCLNT_STREAMFLAGS_NOPERSIST
471 |AUDCLNT_STREAMFLAGS_RATEADJUST
472 |AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED
473 |AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE
474 |AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED
)) {
475 WARN("Unknown flags 0x%08x\n", flags
);
479 WARN("Flags 0x%08x ignored\n", flags
);
483 WARN("Session guid %s ignored\n", debugstr_guid(sessionguid
));
485 hr
= IAudioClient_IsFormatSupported(iface
, mode
, pwfx
, &pwfx2
);
486 CoTaskMemFree(pwfx2
);
487 if (FAILED(hr
) || pwfx2
) {
488 WARN("Format not supported, or had to be modified!\n");
489 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
491 EnterCriticalSection(This
->crst
);
492 HeapFree(GetProcessHeap(), 0, This
->pwfx
);
493 This
->pwfx
= HeapAlloc(GetProcessHeap(), 0, sizeof(*pwfx
) + pwfx
->cbSize
);
498 memcpy(This
->pwfx
, pwfx
, sizeof(*pwfx
) + pwfx
->cbSize
);
499 if (pwfx
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
) {
500 WAVEFORMATEXTENSIBLE
*wfe
= (WAVEFORMATEXTENSIBLE
*)This
->pwfx
;
501 switch (pwfx
->nChannels
) {
502 case 1: wfe
->dwChannelMask
= MONO
; break;
503 case 2: wfe
->dwChannelMask
= STEREO
; break;
504 case 4: wfe
->dwChannelMask
= QUAD
; break;
505 case 6: wfe
->dwChannelMask
= X5DOT1
; break;
506 case 7: wfe
->dwChannelMask
= X6DOT1
; break;
507 case 8: wfe
->dwChannelMask
= X7DOT1
; break;
509 ERR("How did we end up with %i channels?\n", pwfx
->nChannels
);
510 hr
= AUDCLNT_E_UNSUPPORTED_FORMAT
;
515 hr
= IAudioClient_GetDevicePeriod(iface
, &time
, NULL
);
519 This
->psize
= (DWORD64
)This
->pwfx
->nSamplesPerSec
* time
/ (DWORD64
)10000000;
520 if (duration
> 20000000)
523 bufsize
= duration
/ time
* This
->psize
;
525 bufsize
+= This
->psize
;
526 This
->bufsize
= bufsize
;
527 This
->psize
*= This
->pwfx
->nBlockAlign
;
528 bufsize
*= pwfx
->nBlockAlign
;
530 This
->format
= get_format(This
->pwfx
);
531 if (This
->parent
->flow
== eRender
) {
533 ALuint buf
= 0, towrite
;
535 hr
= AC_OpenRenderAL(This
);
536 This
->dev
= This
->parent
->device
;
540 /* Test the returned format */
541 towrite
= sizeof(silence
);
542 towrite
-= towrite
% This
->pwfx
->nBlockAlign
;
543 if (This
->pwfx
->wBitsPerSample
!= 8)
544 memset(silence
, 0, sizeof(silence
));
546 memset(silence
, 128, sizeof(silence
));
547 setALContext(This
->parent
->ctx
);
549 palGenBuffers(1, &buf
);
550 palBufferData(buf
, This
->format
, silence
, towrite
, This
->pwfx
->nSamplesPerSec
);
551 palDeleteBuffers(1, &buf
);
553 hr
= AUDCLNT_E_UNSUPPORTED_FORMAT
;
554 else if (!This
->source
) {
555 palGenSources(1, &This
->source
);
556 palSourcei(This
->source
, AL_LOOPING
, AL_FALSE
);
562 hr
= AC_OpenCaptureAL(This
);
567 This
->candisconnect
= palcIsExtensionPresent(This
->dev
, "ALC_EXT_disconnect");
568 This
->buffer
= HeapAlloc(GetProcessHeap(), 0, bufsize
);
575 This
->running
= FALSE
;
578 LeaveCriticalSection(This
->crst
);
582 static HRESULT WINAPI
AC_GetBufferSize(IAudioClient
*iface
, UINT32
*frames
)
584 ACImpl
*This
= (ACImpl
*)iface
;
585 TRACE("(%p)->(%p)\n", This
, frames
);
587 return AUDCLNT_E_NOT_INITIALIZED
;
590 *frames
= This
->bufsize
;
594 static HRESULT WINAPI
AC_GetStreamLatency(IAudioClient
*iface
, REFERENCE_TIME
*latency
)
596 ACImpl
*This
= (ACImpl
*)iface
;
597 TRACE("(%p)->(%p)\n", This
, latency
);
600 return AUDCLNT_E_NOT_INITIALIZED
;
610 static int disconnected(ACImpl
*This
)
612 if (!This
->candisconnect
)
614 if (This
->parent
->flow
== eRender
) {
615 if (This
->parent
->device
) {
617 palcGetIntegerv(This
->parent
->device
, ALC_CONNECTED
, 1, &con
);
618 palcGetError(This
->parent
->device
);
620 palcCloseDevice(This
->parent
->device
);
621 This
->parent
->device
= NULL
;
622 This
->parent
->ctx
= NULL
;
627 if (!This
->parent
->device
&& FAILED(AC_OpenRenderAL(This
))) {
628 This
->pad
-= This
->padpartial
;
629 This
->padpartial
= 0;
632 if (This
->parent
->device
!= This
->dev
) {
633 WARN("Emptying buffer after newly reconnected!\n");
634 This
->pad
-= This
->padpartial
;
635 This
->padpartial
= 0;
637 This
->dev
= This
->parent
->device
;
638 setALContext(This
->parent
->ctx
);
639 palGenSources(1, &This
->source
);
640 palSourcei(This
->source
, AL_LOOPING
, AL_FALSE
);
643 if (This
->render
&& !This
->locked
&& This
->pad
) {
644 UINT pad
= This
->pad
;
648 /* Probably will cause sound glitches, who cares? */
649 IAudioRenderClient_GetBuffer((IAudioRenderClient
*)This
->render
, pad
, &data
);
650 IAudioRenderClient_ReleaseBuffer((IAudioRenderClient
*)This
->render
, pad
, 0);
657 palcGetIntegerv(This
->dev
, ALC_CONNECTED
, 1, &con
);
658 palcGetError(This
->dev
);
660 palcCaptureCloseDevice(This
->dev
);
666 if (FAILED(AC_OpenCaptureAL(This
)))
669 WARN("Emptying buffer after newly reconnected!\n");
670 This
->pad
= This
->ofs
= 0;
672 palcCaptureStart(This
->dev
);
678 static HRESULT WINAPI
AC_GetCurrentPadding(IAudioClient
*iface
, UINT32
*numpad
)
680 ACImpl
*This
= (ACImpl
*)iface
;
683 TRACE("(%p)->(%p)\n", This
, numpad
);
685 return AUDCLNT_E_NOT_INITIALIZED
;
688 EnterCriticalSection(This
->crst
);
689 if (disconnected(This
)) {
690 REFERENCE_TIME time
= gettime(), period
;
692 WARN("No device found, faking increment\n");
693 IAudioClient_GetDevicePeriod(iface
, &period
, NULL
);
694 while (This
->running
&& time
- This
->laststamp
>= period
) {
695 This
->laststamp
+= period
;
697 if (This
->parent
->flow
== eCapture
) {
698 This
->pad
+= This
->psize
;
699 if (This
->pad
> This
->bufsize
)
700 This
->pad
= This
->bufsize
;
702 if (This
->pad
<= This
->psize
) {
706 This
->pad
-= This
->psize
;
710 if (This
->parent
->flow
== eCapture
)
711 *numpad
= This
->pad
>= This
->psize
? This
->psize
: 0;
714 } else if (This
->parent
->flow
== eRender
) {
716 ALint state
, padpart
;
717 setALContext(This
->parent
->ctx
);
719 palGetSourcei(This
->source
, AL_BYTE_OFFSET
, &padpart
);
720 palGetSourcei(This
->source
, AL_SOURCE_STATE
, &state
);
721 padpart
/= This
->pwfx
->nBlockAlign
;
722 if (state
== AL_STOPPED
&& This
->running
)
724 if (This
->running
&& This
->padpartial
!= padpart
) {
725 This
->padpartial
= padpart
;
726 This
->laststamp
= gettime();
727 #if 0 /* Manipulative lie */
728 } else if (This
->running
) {
729 ALint size
= This
->pad
- padpart
;
730 if (size
> This
->psize
)
732 played
= (gettime() - This
->laststamp
)*8;
733 played
= played
* This
->pwfx
->nSamplesPerSec
/ 10000000;
738 *numpad
= This
->pad
- This
->padpartial
- played
;
739 if (This
->handle
&& *numpad
+ This
->psize
<= This
->bufsize
)
740 SetEvent(This
->handle
);
744 DWORD block
= This
->pwfx
->nBlockAlign
;
745 DWORD psize
= This
->psize
/ block
;
746 palcGetIntegerv(This
->dev
, ALC_CAPTURE_SAMPLES
, 1, &avail
);
748 DWORD ofs
= This
->ofs
+ This
->pad
;
750 ofs
%= This
->bufsize
;
751 buf1
= This
->buffer
+ (ofs
* block
);
752 This
->laststamp
= gettime();
754 SetEvent(This
->handle
);
756 if (ofs
+ avail
<= This
->bufsize
)
757 palcCaptureSamples(This
->dev
, buf1
, avail
);
759 DWORD part1
= This
->bufsize
- ofs
;
760 palcCaptureSamples(This
->dev
, buf1
, part1
);
761 palcCaptureSamples(This
->dev
, This
->buffer
, avail
- part1
);
764 This
->frameswritten
+= avail
;
765 /* Increase ofs if the app forgets to read */
766 if (This
->pad
> This
->bufsize
) {
768 WARN("Overflowed! %u bytes\n", This
->pad
- This
->bufsize
);
769 This
->ofs
+= This
->pad
- This
->bufsize
;
770 rest
= This
->ofs
% psize
;
772 This
->ofs
+= psize
- rest
;
773 This
->ofs
%= This
->bufsize
;
774 This
->pad
= This
->bufsize
;
777 if (This
->pad
>= psize
)
782 LeaveCriticalSection(This
->crst
);
784 TRACE("%u queued\n", *numpad
);
788 static HRESULT WINAPI
AC_IsFormatSupported(IAudioClient
*iface
, AUDCLNT_SHAREMODE mode
, const WAVEFORMATEX
*pwfx
, WAVEFORMATEX
**outpwfx
)
790 ACImpl
*This
= (ACImpl
*)iface
;
794 TRACE("(%p)->(%x,%p,%p)\n", This
, mode
, pwfx
, outpwfx
);
798 if (mode
== AUDCLNT_SHAREMODE_SHARED
&& !outpwfx
)
800 if (mode
!= AUDCLNT_SHAREMODE_SHARED
801 && mode
!= AUDCLNT_SHAREMODE_EXCLUSIVE
) {
802 WARN("Unknown mode %x\n", mode
);
806 if (pwfx
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
807 size
= sizeof(WAVEFORMATEXTENSIBLE
);
808 else if (pwfx
->wFormatTag
== WAVE_FORMAT_PCM
)
809 size
= sizeof(WAVEFORMATEX
);
811 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
813 if (pwfx
->nSamplesPerSec
< 8000
814 || pwfx
->nSamplesPerSec
> 192000)
815 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
816 if (pwfx
->wFormatTag
!= WAVE_FORMAT_EXTENSIBLE
817 || !IsEqualIID(&((WAVEFORMATEXTENSIBLE
*)pwfx
)->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
)) {
818 if (pwfx
->wBitsPerSample
> 16)
819 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
822 switch (pwfx
->nChannels
) {
823 case 1: mask
= MONO
; break;
824 case 2: mask
= STEREO
; break;
825 case 4: mask
= QUAD
; break;
826 case 6: mask
= X5DOT1
; break;
827 case 7: mask
= X6DOT1
; break;
828 case 8: mask
= X7DOT1
; break;
830 TRACE("Unsupported channel count %i\n", pwfx
->nChannels
);
831 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
833 tmp
= CoTaskMemAlloc(size
);
837 return E_OUTOFMEMORY
;
839 memcpy(tmp
, pwfx
, size
);
840 tmp
->nBlockAlign
= tmp
->nChannels
* tmp
->wBitsPerSample
/ 8;
841 tmp
->nAvgBytesPerSec
= tmp
->nBlockAlign
* tmp
->nSamplesPerSec
;
842 tmp
->cbSize
= size
- sizeof(WAVEFORMATEX
);
843 if (tmp
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
) {
844 WAVEFORMATEXTENSIBLE
*ex
= (WAVEFORMATEXTENSIBLE
*)tmp
;
846 if (ex
->Samples
.wValidBitsPerSample
)
847 ex
->Samples
.wValidBitsPerSample
= ex
->Format
.wBitsPerSample
;
849 /* Rear is a special allowed case */
850 if (ex
->dwChannelMask
851 && !(ex
->Format
.nChannels
== 2 && ex
->dwChannelMask
== REAR
))
852 ex
->dwChannelMask
= mask
;
855 if (memcmp(pwfx
, tmp
, size
)) {
859 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
867 static HRESULT WINAPI
AC_GetMixFormat(IAudioClient
*iface
, WAVEFORMATEX
**pwfx
)
869 ACImpl
*This
= (ACImpl
*)iface
;
870 PROPVARIANT pv
= { VT_EMPTY
};
873 TRACE("(%p)->(%p)\n", This
, pwfx
);
877 hr
= MMDevice_GetPropValue(&This
->parent
->devguid
, This
->parent
->flow
,
878 &PKEY_AudioEngine_DeviceFormat
, &pv
);
879 *pwfx
= (WAVEFORMATEX
*)pv
.u
.blob
.pBlobData
;
880 if (SUCCEEDED(hr
) && pv
.vt
== VT_EMPTY
)
883 TRACE("Returning 0x%08x\n", hr
);
887 static HRESULT WINAPI
AC_GetDevicePeriod(IAudioClient
*iface
, REFERENCE_TIME
*defperiod
, REFERENCE_TIME
*minperiod
)
889 ACImpl
*This
= (ACImpl
*)iface
;
891 TRACE("(%p)->(%p)\n", This
, minperiod
);
892 if (!defperiod
&& !minperiod
)
902 static HRESULT WINAPI
AC_Start(IAudioClient
*iface
)
904 ACImpl
*This
= (ACImpl
*)iface
;
906 REFERENCE_TIME refresh
;
908 TRACE("(%p)\n", This
);
910 return AUDCLNT_E_NOT_INITIALIZED
;
911 if (This
->flags
& AUDCLNT_STREAMFLAGS_EVENTCALLBACK
) {
913 return AUDCLNT_E_EVENTHANDLE_NOT_SET
;
914 FIXME("Event handles not fully tested\n");
916 EnterCriticalSection(This
->crst
);
918 hr
= AUDCLNT_E_NOT_STOPPED
;
921 if (!valid_dev(This
))
922 WARN("No valid device\n");
923 else if (This
->parent
->flow
== eRender
) {
924 setALContext(This
->parent
->ctx
);
925 palSourcePlay(This
->source
);
930 palcCaptureStart(This
->dev
);
932 AC_GetDevicePeriod(iface
, &refresh
, NULL
);
933 if (!This
->timer_id
&& This
->handle
)
934 CreateTimerQueueTimer(&This
->timer_id
, NULL
, AC_tick
, This
,
935 refresh
/ 20000, refresh
/ 20000,
936 WT_EXECUTEINTIMERTHREAD
);
937 /* Set to 0, otherwise risk running the clock backwards
938 * This will cause AudioClock::GetPosition to return the maximum
939 * possible value for the current buffer
942 This
->running
= TRUE
;
945 LeaveCriticalSection(This
->crst
);
949 static HRESULT WINAPI
AC_Stop(IAudioClient
*iface
)
951 ACImpl
*This
= (ACImpl
*)iface
;
953 TRACE("(%p)\n", This
);
955 return AUDCLNT_E_NOT_INITIALIZED
;
958 EnterCriticalSection(This
->crst
);
959 if (!valid_dev(This
))
960 WARN("No valid device\n");
961 else if (This
->parent
->flow
== eRender
) {
963 setALContext(This
->parent
->ctx
);
964 palSourcePause(This
->source
);
967 palGetSourcei(This
->source
, AL_SOURCE_STATE
, &state
);
968 if (state
!= AL_PLAYING
)
976 palcCaptureStop(This
->dev
);
977 This
->running
= FALSE
;
978 timer_id
= This
->timer_id
;
980 LeaveCriticalSection(This
->crst
);
982 DeleteTimerQueueTimer(NULL
, timer_id
, INVALID_HANDLE_VALUE
);
986 static HRESULT WINAPI
AC_Reset(IAudioClient
*iface
)
988 ACImpl
*This
= (ACImpl
*)iface
;
990 TRACE("(%p)\n", This
);
992 return AUDCLNT_E_NOT_INITIALIZED
;
994 return AUDCLNT_E_NOT_STOPPED
;
995 EnterCriticalSection(This
->crst
);
997 hr
= AUDCLNT_E_BUFFER_OPERATION_PENDING
;
1000 if (!valid_dev(This
))
1001 WARN("No valid device\n");
1002 else if (This
->parent
->flow
== eRender
) {
1005 setALContext(This
->parent
->ctx
);
1006 palSourceStop(This
->source
);
1007 palGetSourcei(This
->source
, AL_BUFFERS_PROCESSED
, &n
);
1009 palSourceUnqueueBuffers(This
->source
, 1, &buf
);
1010 palDeleteBuffers(1, &buf
);
1016 palcGetIntegerv(This
->dev
, ALC_CAPTURE_SAMPLES
, 1, &avail
);
1018 palcCaptureSamples(This
->dev
, This
->buffer
, avail
);
1020 This
->pad
= This
->padpartial
= 0;
1022 This
->frameswritten
= 0;
1024 LeaveCriticalSection(This
->crst
);
1028 static HRESULT WINAPI
AC_SetEventHandle(IAudioClient
*iface
, HANDLE handle
)
1030 ACImpl
*This
= (ACImpl
*)iface
;
1031 TRACE("(%p)\n", This
);
1033 return AUDCLNT_E_NOT_INITIALIZED
;
1035 return E_INVALIDARG
;
1036 if (!(This
->flags
& AUDCLNT_STREAMFLAGS_EVENTCALLBACK
))
1037 return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED
;
1038 This
->handle
= handle
;
1042 static HRESULT WINAPI
AC_GetService(IAudioClient
*iface
, REFIID riid
, void **ppv
)
1044 ACImpl
*This
= (ACImpl
*)iface
;
1046 TRACE("(%p)->(%s,%p)\n", This
, debugstr_guid(riid
), ppv
);
1048 return AUDCLNT_E_NOT_INITIALIZED
;
1053 if (IsEqualIID(riid
, &IID_IAudioRenderClient
)) {
1054 if (This
->parent
->flow
!= eRender
)
1055 return AUDCLNT_E_WRONG_ENDPOINT_TYPE
;
1057 hr
= AudioRenderClient_Create(This
, &This
->render
);
1058 *ppv
= This
->render
;
1059 } else if (IsEqualIID(riid
, &IID_IAudioCaptureClient
)) {
1060 if (This
->parent
->flow
!= eCapture
)
1061 return AUDCLNT_E_WRONG_ENDPOINT_TYPE
;
1063 hr
= AudioCaptureClient_Create(This
, &This
->capture
);
1064 *ppv
= This
->capture
;
1065 } else if (IsEqualIID(riid
, &IID_IAudioSessionControl
)) {
1067 hr
= AudioSessionControl_Create(This
, &This
->session
);
1068 *ppv
= This
->session
;
1069 } else if (IsEqualIID(riid
, &IID_ISimpleAudioVolume
)) {
1071 hr
= AudioSimpleVolume_Create(This
, &This
->svolume
);
1072 *ppv
= This
->svolume
;
1073 } else if (IsEqualIID(riid
, &IID_IAudioClock
)) {
1075 hr
= AudioClock_Create(This
, &This
->clock
);
1083 IUnknown_AddRef((IUnknown
*)*ppv
);
1087 FIXME("stub %s\n", debugstr_guid(riid
));
1088 return E_NOINTERFACE
;
1091 static const IAudioClientVtbl ACImpl_Vtbl
=
1098 AC_GetStreamLatency
,
1099 AC_GetCurrentPadding
,
1100 AC_IsFormatSupported
,
1110 static HRESULT
AudioRenderClient_Create(ACImpl
*parent
, ACRender
**ppv
)
1114 This
= *ppv
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
1116 return E_OUTOFMEMORY
;
1117 This
->lpVtbl
= &ACRender_Vtbl
;
1119 This
->parent
= parent
;
1123 static void AudioRenderClient_Destroy(ACRender
*This
)
1125 This
->parent
->render
= NULL
;
1126 HeapFree(GetProcessHeap(), 0, This
);
1129 static HRESULT WINAPI
ACR_QueryInterface(IAudioRenderClient
*iface
, REFIID riid
, void **ppv
)
1131 TRACE("(%p)->(%s,%p)\n", iface
, debugstr_guid(riid
), ppv
);
1136 if (IsEqualIID(riid
, &IID_IUnknown
)
1137 || IsEqualIID(riid
, &IID_IAudioRenderClient
))
1140 IUnknown_AddRef((IUnknown
*)*ppv
);
1143 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1144 return E_NOINTERFACE
;
1147 static ULONG WINAPI
ACR_AddRef(IAudioRenderClient
*iface
)
1149 ACRender
*This
= (ACRender
*)iface
;
1151 ref
= InterlockedIncrement(&This
->ref
);
1152 TRACE("Refcount now %i\n", ref
);
1156 static ULONG WINAPI
ACR_Release(IAudioRenderClient
*iface
)
1158 ACRender
*This
= (ACRender
*)iface
;
1160 ref
= InterlockedDecrement(&This
->ref
);
1161 TRACE("Refcount now %i\n", ref
);
1163 AudioRenderClient_Destroy(This
);
1167 static HRESULT WINAPI
ACR_GetBuffer(IAudioRenderClient
*iface
, UINT32 frames
, BYTE
**data
)
1169 ACRender
*This
= (ACRender
*)iface
;
1170 DWORD free
, framesize
;
1171 TRACE("(%p)->(%u,%p)\n", This
, frames
, data
);
1178 if (This
->parent
->locked
) {
1180 return AUDCLNT_E_OUT_OF_ORDER
;
1182 AC_GetCurrentPadding((IAudioClient
*)This
->parent
, &free
);
1183 if (This
->parent
->bufsize
-free
< frames
) {
1184 ERR("Too large: %u %u %u\n", This
->parent
->bufsize
, free
, frames
);
1185 return AUDCLNT_E_BUFFER_TOO_LARGE
;
1187 EnterCriticalSection(This
->parent
->crst
);
1188 This
->parent
->locked
= frames
;
1189 framesize
= This
->parent
->pwfx
->nBlockAlign
;
1191 /* Exact offset doesn't matter, offset could be 0 forever
1192 * but increasing it is easier to debug */
1193 if (This
->parent
->ofs
+ frames
> This
->parent
->bufsize
)
1194 This
->parent
->ofs
= 0;
1195 *data
= This
->parent
->buffer
+ This
->parent
->ofs
* framesize
;
1197 LeaveCriticalSection(This
->parent
->crst
);
1201 static HRESULT WINAPI
ACR_ReleaseBuffer(IAudioRenderClient
*iface
, UINT32 written
, DWORD flags
)
1203 ACRender
*This
= (ACRender
*)iface
;
1204 BYTE
*buf
= This
->parent
->buffer
;
1205 DWORD framesize
= This
->parent
->pwfx
->nBlockAlign
;
1206 DWORD ofs
= This
->parent
->ofs
;
1207 DWORD bufsize
= This
->parent
->bufsize
;
1208 DWORD freq
= This
->parent
->pwfx
->nSamplesPerSec
;
1209 DWORD bpp
= This
->parent
->pwfx
->wBitsPerSample
;
1212 TRACE("(%p)->(%u,%x)\n", This
, written
, flags
);
1214 if (This
->parent
->locked
< written
)
1215 return AUDCLNT_E_INVALID_SIZE
;
1217 if (flags
& ~AUDCLNT_BUFFERFLAGS_SILENT
)
1218 return E_INVALIDARG
;
1221 if (This
->parent
->locked
)
1222 FIXME("Handled right?\n");
1223 This
->parent
->locked
= 0;
1227 if (!This
->parent
->locked
)
1228 return AUDCLNT_E_OUT_OF_ORDER
;
1230 EnterCriticalSection(This
->parent
->crst
);
1232 This
->parent
->ofs
+= written
;
1233 This
->parent
->ofs
%= bufsize
;
1234 This
->parent
->pad
+= written
;
1235 This
->parent
->frameswritten
+= written
;
1236 This
->parent
->locked
= 0;
1239 written
*= framesize
;
1240 bufsize
*= framesize
;
1242 if (flags
& AUDCLNT_BUFFERFLAGS_SILENT
)
1243 memset(buf
+ofs
, bpp
!= 8 ? 0 : 128, written
);
1244 TRACE("buf: %p, ofs: %x, written %u, freq %u\n", buf
, ofs
, written
, freq
);
1245 if (!valid_dev(This
->parent
))
1248 setALContext(This
->parent
->parent
->ctx
);
1249 palGenBuffers(1, &albuf
);
1250 palBufferData(albuf
, This
->parent
->format
, buf
+ofs
, written
, freq
);
1251 palSourceQueueBuffers(This
->parent
->source
, 1, &albuf
);
1252 TRACE("Queued %u\n", albuf
);
1254 if (This
->parent
->running
) {
1255 ALint state
= AL_PLAYING
, done
= 0, padpart
= 0;
1257 palGetSourcei(This
->parent
->source
, AL_BUFFERS_PROCESSED
, &done
);
1258 palGetSourcei(This
->parent
->source
, AL_BYTE_OFFSET
, &padpart
);
1259 palGetSourcei(This
->parent
->source
, AL_SOURCE_STATE
, &state
);
1260 padpart
/= framesize
;
1262 if (state
== AL_STOPPED
) {
1263 padpart
= This
->parent
->pad
;
1264 /* Buffer might have been processed in the small window
1265 * between first and third call */
1266 palGetSourcei(This
->parent
->source
, AL_BUFFERS_PROCESSED
, &done
);
1268 if (done
|| This
->parent
->padpartial
!= padpart
)
1269 This
->parent
->laststamp
= gettime();
1270 This
->parent
->padpartial
= padpart
;
1273 ALint size
, bits
, chan
;
1276 palSourceUnqueueBuffers(This
->parent
->source
, 1, &which
);
1277 palGetBufferi(which
, AL_SIZE
, &size
);
1278 palGetBufferi(which
, AL_BITS
, &bits
);
1279 palGetBufferi(which
, AL_CHANNELS
, &chan
);
1280 size
/= bits
* chan
/ 8;
1281 if (size
> This
->parent
->pad
) {
1283 size
= This
->parent
->pad
;
1285 This
->parent
->pad
-= size
;
1286 This
->parent
->padpartial
-= size
;
1287 TRACE("Unqueued %u\n", which
);
1288 palDeleteBuffers(1, &which
);
1291 if (state
!= AL_PLAYING
) {
1292 ERR("Starting from %x\n", state
);
1293 palSourcePlay(This
->parent
->source
);
1300 LeaveCriticalSection(This
->parent
->crst
);
1305 static const IAudioRenderClientVtbl ACRender_Vtbl
= {
1313 static HRESULT
AudioCaptureClient_Create(ACImpl
*parent
, ACCapture
**ppv
)
1316 This
= *ppv
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
1318 return E_OUTOFMEMORY
;
1319 This
->lpVtbl
= &ACCapture_Vtbl
;
1321 This
->parent
= parent
;
1325 static void AudioCaptureClient_Destroy(ACCapture
*This
)
1327 This
->parent
->capture
= NULL
;
1328 HeapFree(GetProcessHeap(), 0, This
);
1331 static HRESULT WINAPI
ACC_QueryInterface(IAudioCaptureClient
*iface
, REFIID riid
, void **ppv
)
1333 TRACE("(%p)->(%s,%p)\n", iface
, debugstr_guid(riid
), ppv
);
1338 if (IsEqualIID(riid
, &IID_IUnknown
)
1339 || IsEqualIID(riid
, &IID_IAudioCaptureClient
))
1342 IUnknown_AddRef((IUnknown
*)*ppv
);
1345 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1346 return E_NOINTERFACE
;
1349 static ULONG WINAPI
ACC_AddRef(IAudioCaptureClient
*iface
)
1351 ACCapture
*This
= (ACCapture
*)iface
;
1353 ref
= InterlockedIncrement(&This
->ref
);
1354 TRACE("Refcount now %i\n", ref
);
1358 static ULONG WINAPI
ACC_Release(IAudioCaptureClient
*iface
)
1360 ACCapture
*This
= (ACCapture
*)iface
;
1362 ref
= InterlockedDecrement(&This
->ref
);
1363 TRACE("Refcount now %i\n", ref
);
1365 AudioCaptureClient_Destroy(This
);
1369 static HRESULT WINAPI
ACC_GetBuffer(IAudioCaptureClient
*iface
, BYTE
**data
, UINT32
*frames
, DWORD
*flags
, UINT64
*devpos
, UINT64
*qpcpos
)
1371 ACCapture
*This
= (ACCapture
*)iface
;
1373 DWORD block
= This
->parent
->pwfx
->nBlockAlign
;
1375 TRACE("(%p)->(%p,%p,%p,%p,%p)\n", This
, data
, frames
, flags
, devpos
, qpcpos
);
1382 FIXME("Flags can be null?\n");
1385 EnterCriticalSection(This
->parent
->crst
);
1386 hr
= AUDCLNT_E_OUT_OF_ORDER
;
1387 if (This
->parent
->locked
)
1389 IAudioCaptureClient_GetNextPacketSize(iface
, frames
);
1390 ofs
= This
->parent
->ofs
;
1391 bufsize
= This
->parent
->bufsize
;
1392 if ( (ofs
*block
) % This
->parent
->psize
)
1393 ERR("Unaligned offset %u with %u\n", ofs
*block
, This
->parent
->psize
);
1394 *data
= This
->parent
->buffer
+ ofs
* block
;
1395 This
->parent
->locked
= *frames
;
1397 *devpos
= This
->parent
->frameswritten
- This
->parent
->pad
;
1399 *qpcpos
= This
->parent
->laststamp
;
1403 hr
= AUDCLNT_S_BUFFER_EMPTY
;
1405 LeaveCriticalSection(This
->parent
->crst
);
1406 TRACE("Returning %08x %i\n", hr
, *frames
);
1410 static HRESULT WINAPI
ACC_ReleaseBuffer(IAudioCaptureClient
*iface
, UINT32 written
)
1412 ACCapture
*This
= (ACCapture
*)iface
;
1414 EnterCriticalSection(This
->parent
->crst
);
1415 if (!written
|| written
== This
->parent
->locked
) {
1416 This
->parent
->locked
= 0;
1417 This
->parent
->ofs
+= written
;
1418 This
->parent
->ofs
%= This
->parent
->bufsize
;
1419 This
->parent
->pad
-= written
;
1420 } else if (!This
->parent
->locked
)
1421 hr
= AUDCLNT_E_OUT_OF_ORDER
;
1423 hr
= AUDCLNT_E_INVALID_SIZE
;
1424 LeaveCriticalSection(This
->parent
->crst
);
1428 static HRESULT WINAPI
ACC_GetNextPacketSize(IAudioCaptureClient
*iface
, UINT32
*frames
)
1430 ACCapture
*This
= (ACCapture
*)iface
;
1432 return AC_GetCurrentPadding((IAudioClient
*)This
->parent
, frames
);
1435 static const IAudioCaptureClientVtbl ACCapture_Vtbl
=
1442 ACC_GetNextPacketSize
1445 static HRESULT
AudioSessionControl_Create(ACImpl
*parent
, ACSession
**ppv
)
1448 This
= *ppv
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
1450 return E_OUTOFMEMORY
;
1451 This
->lpVtbl
= &ACSession_Vtbl
;
1453 This
->parent
= parent
;
1457 static void AudioSessionControl_Destroy(ACSession
*This
)
1459 This
->parent
->session
= NULL
;
1460 HeapFree(GetProcessHeap(), 0, This
);
1463 static HRESULT WINAPI
ACS_QueryInterface(IAudioSessionControl2
*iface
, REFIID riid
, void **ppv
)
1465 TRACE("(%p)->(%s,%p)\n", iface
, debugstr_guid(riid
), ppv
);
1470 if (IsEqualIID(riid
, &IID_IUnknown
)
1471 || IsEqualIID(riid
, &IID_IAudioSessionControl
)
1472 || IsEqualIID(riid
, &IID_IAudioSessionControl2
))
1475 IUnknown_AddRef((IUnknown
*)*ppv
);
1478 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1479 return E_NOINTERFACE
;
1482 static ULONG WINAPI
ACS_AddRef(IAudioSessionControl2
*iface
)
1484 ACSession
*This
= (ACSession
*)iface
;
1486 ref
= InterlockedIncrement(&This
->ref
);
1487 TRACE("Refcount now %i\n", ref
);
1491 static ULONG WINAPI
ACS_Release(IAudioSessionControl2
*iface
)
1493 ACSession
*This
= (ACSession
*)iface
;
1495 ref
= InterlockedDecrement(&This
->ref
);
1496 TRACE("Refcount now %i\n", ref
);
1498 AudioSessionControl_Destroy(This
);
1502 static HRESULT WINAPI
ACS_GetState(IAudioSessionControl2
*iface
, AudioSessionState
*state
)
1504 ACSession
*This
= (ACSession
*)iface
;
1505 TRACE("(%p)->(%p)\n", This
, state
);
1509 *state
= This
->parent
->parent
->state
;
1513 static HRESULT WINAPI
ACS_GetDisplayName(IAudioSessionControl2
*iface
, WCHAR
**name
)
1515 ACSession
*This
= (ACSession
*)iface
;
1516 TRACE("(%p)->(%p)\n", This
, name
);
1523 static HRESULT WINAPI
ACS_SetDisplayName(IAudioSessionControl2
*iface
, const WCHAR
*name
, const GUID
*session
)
1525 ACSession
*This
= (ACSession
*)iface
;
1526 TRACE("(%p)->(%p,%s)\n", This
, name
, debugstr_guid(session
));
1531 static HRESULT WINAPI
ACS_GetIconPath(IAudioSessionControl2
*iface
, WCHAR
**path
)
1533 ACSession
*This
= (ACSession
*)iface
;
1534 TRACE("(%p)->(%p)\n", This
, path
);
1541 static HRESULT WINAPI
ACS_SetIconPath(IAudioSessionControl2
*iface
, const WCHAR
*path
, const GUID
*session
)
1543 ACSession
*This
= (ACSession
*)iface
;
1544 TRACE("(%p)->(%p,%s)\n", This
, path
, debugstr_guid(session
));
1549 static HRESULT WINAPI
ACS_GetGroupingParam(IAudioSessionControl2
*iface
, GUID
*group
)
1551 ACSession
*This
= (ACSession
*)iface
;
1552 TRACE("(%p)->(%p)\n", This
, group
);
1559 static HRESULT WINAPI
ACS_SetGroupingParam(IAudioSessionControl2
*iface
, GUID
*group
, const GUID
*session
)
1561 ACSession
*This
= (ACSession
*)iface
;
1562 TRACE("(%p)->(%s,%s)\n", This
, debugstr_guid(group
), debugstr_guid(session
));
1567 static HRESULT WINAPI
ACS_RegisterAudioSessionNotification(IAudioSessionControl2
*iface
, IAudioSessionEvents
*events
)
1569 ACSession
*This
= (ACSession
*)iface
;
1570 TRACE("(%p)->(%p)\n", This
, events
);
1575 static HRESULT WINAPI
ACS_UnregisterAudioSessionNotification(IAudioSessionControl2
*iface
, IAudioSessionEvents
*events
)
1577 ACSession
*This
= (ACSession
*)iface
;
1578 TRACE("(%p)->(%p)\n", This
, events
);
1583 static HRESULT WINAPI
ACS_GetSessionIdentifier(IAudioSessionControl2
*iface
, WCHAR
**id
)
1585 ACSession
*This
= (ACSession
*)iface
;
1586 TRACE("(%p)->(%p)\n", This
, id
);
1593 static HRESULT WINAPI
ACS_GetSessionInstanceIdentifier(IAudioSessionControl2
*iface
, WCHAR
**id
)
1595 ACSession
*This
= (ACSession
*)iface
;
1596 TRACE("(%p)->(%p)\n", This
, id
);
1603 static HRESULT WINAPI
ACS_GetProcessId(IAudioSessionControl2
*iface
, DWORD
*pid
)
1605 ACSession
*This
= (ACSession
*)iface
;
1606 TRACE("(%p)->(%p)\n", This
, pid
);
1610 *pid
= GetCurrentProcessId();
1614 static HRESULT WINAPI
ACS_IsSystemSoundsSession(IAudioSessionControl2
*iface
)
1616 ACSession
*This
= (ACSession
*)iface
;
1617 TRACE("(%p)\n", This
);
1622 static HRESULT WINAPI
ACS_SetDuckingPreference(IAudioSessionControl2
*iface
, BOOL optout
)
1624 ACSession
*This
= (ACSession
*)iface
;
1625 TRACE("(%p)\n", This
);
1630 static const IAudioSessionControl2Vtbl ACSession_Vtbl
=
1640 ACS_GetGroupingParam
,
1641 ACS_SetGroupingParam
,
1642 ACS_RegisterAudioSessionNotification
,
1643 ACS_UnregisterAudioSessionNotification
,
1644 ACS_GetSessionIdentifier
,
1645 ACS_GetSessionInstanceIdentifier
,
1647 ACS_IsSystemSoundsSession
,
1648 ACS_SetDuckingPreference
1651 static HRESULT
AudioSimpleVolume_Create(ACImpl
*parent
, ASVolume
**ppv
)
1654 This
= *ppv
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
1656 return E_OUTOFMEMORY
;
1657 This
->lpVtbl
= &ASVolume_Vtbl
;
1659 This
->parent
= parent
;
1663 static void AudioSimpleVolume_Destroy(ASVolume
*This
)
1665 This
->parent
->svolume
= NULL
;
1666 HeapFree(GetProcessHeap(), 0, This
);
1669 static HRESULT WINAPI
ASV_QueryInterface(ISimpleAudioVolume
*iface
, REFIID riid
, void **ppv
)
1671 TRACE("(%p)->(%s,%p)\n", iface
, debugstr_guid(riid
), ppv
);
1676 if (IsEqualIID(riid
, &IID_IUnknown
)
1677 || IsEqualIID(riid
, &IID_ISimpleAudioVolume
))
1680 IUnknown_AddRef((IUnknown
*)*ppv
);
1683 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1684 return E_NOINTERFACE
;
1687 static ULONG WINAPI
ASV_AddRef(ISimpleAudioVolume
*iface
)
1689 ASVolume
*This
= (ASVolume
*)iface
;
1691 ref
= InterlockedIncrement(&This
->ref
);
1692 TRACE("Refcount now %i\n", ref
);
1696 static ULONG WINAPI
ASV_Release(ISimpleAudioVolume
*iface
)
1698 ASVolume
*This
= (ASVolume
*)iface
;
1700 ref
= InterlockedDecrement(&This
->ref
);
1701 TRACE("Refcount now %i\n", ref
);
1703 AudioSimpleVolume_Destroy(This
);
1707 static HRESULT WINAPI
ASV_SetMasterVolume(ISimpleAudioVolume
*iface
, float level
, const GUID
*context
)
1709 ASVolume
*This
= (ASVolume
*)iface
;
1710 TRACE("(%p)->(%f,%p)\n", This
, level
, context
);
1716 static HRESULT WINAPI
ASV_GetMasterVolume(ISimpleAudioVolume
*iface
, float *level
)
1718 ASVolume
*This
= (ASVolume
*)iface
;
1719 TRACE("(%p)->(%p)\n", This
, level
);
1726 static HRESULT WINAPI
ASV_SetMute(ISimpleAudioVolume
*iface
, BOOL mute
, const GUID
*context
)
1728 ASVolume
*This
= (ASVolume
*)iface
;
1729 TRACE("(%p)->(%u,%p)\n", This
, mute
, context
);
1735 static HRESULT WINAPI
ASV_GetMute(ISimpleAudioVolume
*iface
, BOOL
*mute
)
1737 ASVolume
*This
= (ASVolume
*)iface
;
1738 TRACE("(%p)->(%p)\n", This
, mute
);
1745 static const ISimpleAudioVolumeVtbl ASVolume_Vtbl
=
1750 ASV_SetMasterVolume
,
1751 ASV_GetMasterVolume
,
1756 static HRESULT
AudioClock_Create(ACImpl
*parent
, AClock
**ppv
)
1759 This
= *ppv
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
1761 return E_OUTOFMEMORY
;
1762 This
->lpVtbl
= &AClock_Vtbl
;
1763 This
->lp2Vtbl
= &AClock2_Vtbl
;
1765 This
->parent
= parent
;
1769 static void AudioClock_Destroy(AClock
*This
)
1771 This
->parent
->clock
= NULL
;
1772 HeapFree(GetProcessHeap(), 0, This
);
1775 static HRESULT WINAPI
AClock_QueryInterface(IAudioClock
*iface
, REFIID riid
, void **ppv
)
1777 AClock
*This
= (AClock
*)iface
;
1778 TRACE("(%p)->(%s,%p)\n", iface
, debugstr_guid(riid
), ppv
);
1783 if (IsEqualIID(riid
, &IID_IUnknown
)
1784 || IsEqualIID(riid
, &IID_IAudioClock
))
1786 else if (IsEqualIID(riid
, &IID_IAudioClock2
))
1787 *ppv
= &This
->lp2Vtbl
;
1789 IUnknown_AddRef((IUnknown
*)*ppv
);
1792 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1793 return E_NOINTERFACE
;
1796 static ULONG WINAPI
AClock_AddRef(IAudioClock
*iface
)
1798 AClock
*This
= (AClock
*)iface
;
1800 ref
= InterlockedIncrement(&This
->ref
);
1801 TRACE("Refcount now %i\n", ref
);
1805 static ULONG WINAPI
AClock_Release(IAudioClock
*iface
)
1807 AClock
*This
= (AClock
*)iface
;
1809 ref
= InterlockedDecrement(&This
->ref
);
1810 TRACE("Refcount now %i\n", ref
);
1812 AudioClock_Destroy(This
);
1816 static HRESULT WINAPI
AClock_GetFrequency(IAudioClock
*iface
, UINT64
*freq
)
1818 AClock
*This
= (AClock
*)iface
;
1819 TRACE("(%p)->(%p)\n", This
, freq
);
1821 *freq
= (UINT64
)This
->parent
->pwfx
->nSamplesPerSec
;
1825 static HRESULT WINAPI
AClock_GetPosition(IAudioClock
*iface
, UINT64
*pos
, UINT64
*qpctime
)
1827 AClock
*This
= (AClock
*)iface
;
1830 TRACE("(%p)->(%p,%p)\n", This
, pos
, qpctime
);
1835 EnterCriticalSection(This
->parent
->crst
);
1836 AC_GetCurrentPadding((IAudioClient
*)This
->parent
, &pad
);
1837 *pos
= This
->parent
->frameswritten
- pad
;
1839 *qpctime
= gettime();
1840 LeaveCriticalSection(This
->parent
->crst
);
1845 static HRESULT WINAPI
AClock_GetCharacteristics(IAudioClock
*iface
, DWORD
*chars
)
1847 AClock
*This
= (AClock
*)iface
;
1848 TRACE("(%p)->(%p)\n", This
, chars
);
1852 *chars
= AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ
;
1856 static const IAudioClockVtbl AClock_Vtbl
=
1858 AClock_QueryInterface
,
1861 AClock_GetFrequency
,
1863 AClock_GetCharacteristics
1866 static AClock
*get_clock_from_clock2(IAudioClock2
*iface
)
1868 return (AClock
*)((char*)iface
- offsetof(AClock
,lp2Vtbl
));
1871 static HRESULT WINAPI
AClock2_QueryInterface(IAudioClock2
*iface
, REFIID riid
, void **ppv
)
1873 AClock
*This
= get_clock_from_clock2(iface
);
1874 return IUnknown_QueryInterface((IUnknown
*)This
, riid
, ppv
);
1877 static ULONG WINAPI
AClock2_AddRef(IAudioClock2
*iface
)
1879 AClock
*This
= get_clock_from_clock2(iface
);
1880 return IUnknown_AddRef((IUnknown
*)This
);
1883 static ULONG WINAPI
AClock2_Release(IAudioClock2
*iface
)
1885 AClock
*This
= get_clock_from_clock2(iface
);
1886 return IUnknown_Release((IUnknown
*)This
);
1889 static HRESULT WINAPI
AClock2_GetPosition(IAudioClock2
*iface
, UINT64
*pos
, UINT64
*qpctime
)
1891 AClock
*This
= get_clock_from_clock2(iface
);
1892 return AClock_GetPosition((IAudioClock
*)This
, pos
, qpctime
);
1895 static const IAudioClock2Vtbl AClock2_Vtbl
=
1897 AClock2_QueryInterface
,