2 * Copyright 2011-2012 Maarten Lankhorst
3 * Copyright 2010-2011 Maarten Lankhorst for CodeWeavers
4 * Copyright 2011 Andrew Eikum for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define NONAMELESSUNION
33 #include <pulse/pulseaudio.h>
40 #include "wine/debug.h"
41 #include "wine/unicode.h"
42 #include "wine/list.h"
53 #include "mmdeviceapi.h"
54 #include "audioclient.h"
55 #include "endpointvolume.h"
56 #include "audiopolicy.h"
60 WINE_DEFAULT_DEBUG_CHANNEL(pulse
);
62 static const struct unix_funcs
*pulse
;
64 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
66 /* From <dlls/mmdevapi/mmdevapi.h> */
68 Priority_Unavailable
= 0,
74 static struct pulse_config pulse_config
;
76 static HANDLE pulse_thread
;
77 static struct list g_sessions
= LIST_INIT(g_sessions
);
79 static GUID pulse_render_guid
=
80 { 0xfd47d9cc, 0x4218, 0x4135, { 0x9c, 0xe2, 0x0c, 0x19, 0x5c, 0x87, 0x40, 0x5b } };
81 static GUID pulse_capture_guid
=
82 { 0x25da76d0, 0x033c, 0x4235, { 0x90, 0x02, 0x19, 0xf4, 0x88, 0x94, 0xac, 0x6f } };
84 BOOL WINAPI
DllMain(HINSTANCE dll
, DWORD reason
, void *reserved
)
86 if (reason
== DLL_PROCESS_ATTACH
) {
87 DisableThreadLibraryCalls(dll
);
88 if (__wine_init_unix_lib(dll
, reason
, NULL
, &pulse
))
90 } else if (reason
== DLL_PROCESS_DETACH
) {
91 __wine_init_unix_lib(dll
, reason
, NULL
, NULL
);
93 WaitForSingleObject(pulse_thread
, INFINITE
);
94 CloseHandle(pulse_thread
);
100 typedef struct ACImpl ACImpl
;
102 typedef struct _AudioSession
{
109 UINT32 channel_count
;
116 typedef struct _AudioSessionWrapper
{
117 IAudioSessionControl2 IAudioSessionControl2_iface
;
118 IChannelAudioVolume IChannelAudioVolume_iface
;
119 ISimpleAudioVolume ISimpleAudioVolume_iface
;
124 AudioSession
*session
;
125 } AudioSessionWrapper
;
128 IAudioClient3 IAudioClient3_iface
;
129 IAudioRenderClient IAudioRenderClient_iface
;
130 IAudioCaptureClient IAudioCaptureClient_iface
;
131 IAudioClock IAudioClock_iface
;
132 IAudioClock2 IAudioClock2_iface
;
133 IAudioStreamVolume IAudioStreamVolume_iface
;
137 float vol
[PA_CHANNELS_MAX
];
141 UINT32 channel_count
;
144 struct pulse_stream
*pulse_stream
;
146 AudioSession
*session
;
147 AudioSessionWrapper
*session_wrapper
;
150 static const WCHAR defaultW
[] = {'P','u','l','s','e','a','u','d','i','o',0};
152 static const IAudioClient3Vtbl AudioClient3_Vtbl
;
153 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl
;
154 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl
;
155 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl
;
156 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl
;
157 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl
;
158 static const IAudioClockVtbl AudioClock_Vtbl
;
159 static const IAudioClock2Vtbl AudioClock2_Vtbl
;
160 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl
;
162 static AudioSessionWrapper
*AudioSessionWrapper_Create(ACImpl
*client
);
164 static inline ACImpl
*impl_from_IAudioClient3(IAudioClient3
*iface
)
166 return CONTAINING_RECORD(iface
, ACImpl
, IAudioClient3_iface
);
169 static inline ACImpl
*impl_from_IAudioRenderClient(IAudioRenderClient
*iface
)
171 return CONTAINING_RECORD(iface
, ACImpl
, IAudioRenderClient_iface
);
174 static inline ACImpl
*impl_from_IAudioCaptureClient(IAudioCaptureClient
*iface
)
176 return CONTAINING_RECORD(iface
, ACImpl
, IAudioCaptureClient_iface
);
179 static inline AudioSessionWrapper
*impl_from_IAudioSessionControl2(IAudioSessionControl2
*iface
)
181 return CONTAINING_RECORD(iface
, AudioSessionWrapper
, IAudioSessionControl2_iface
);
184 static inline AudioSessionWrapper
*impl_from_ISimpleAudioVolume(ISimpleAudioVolume
*iface
)
186 return CONTAINING_RECORD(iface
, AudioSessionWrapper
, ISimpleAudioVolume_iface
);
189 static inline AudioSessionWrapper
*impl_from_IChannelAudioVolume(IChannelAudioVolume
*iface
)
191 return CONTAINING_RECORD(iface
, AudioSessionWrapper
, IChannelAudioVolume_iface
);
194 static inline ACImpl
*impl_from_IAudioClock(IAudioClock
*iface
)
196 return CONTAINING_RECORD(iface
, ACImpl
, IAudioClock_iface
);
199 static inline ACImpl
*impl_from_IAudioClock2(IAudioClock2
*iface
)
201 return CONTAINING_RECORD(iface
, ACImpl
, IAudioClock2_iface
);
204 static inline ACImpl
*impl_from_IAudioStreamVolume(IAudioStreamVolume
*iface
)
206 return CONTAINING_RECORD(iface
, ACImpl
, IAudioStreamVolume_iface
);
209 static DWORD CALLBACK
pulse_mainloop_thread(void *tmp
) {
214 static char *get_application_name(void)
216 WCHAR path
[MAX_PATH
], *name
;
220 GetModuleFileNameW(NULL
, path
, ARRAY_SIZE(path
));
221 name
= strrchrW(path
, '\\');
226 len
= WideCharToMultiByte(CP_UTF8
, 0, name
, -1, NULL
, 0, NULL
, NULL
);
227 if (!(str
= malloc(len
)))
229 WideCharToMultiByte(CP_UNIXCP
, 0, name
, -1, str
, len
, NULL
, NULL
);
233 static HRESULT
pulse_stream_valid(ACImpl
*This
) {
234 if (!This
->pulse_stream
)
235 return AUDCLNT_E_NOT_INITIALIZED
;
236 if (pa_stream_get_state(This
->pulse_stream
->stream
) != PA_STREAM_READY
)
237 return AUDCLNT_E_DEVICE_INVALIDATED
;
241 static void silence_buffer(pa_sample_format_t format
, BYTE
*buffer
, UINT32 bytes
)
243 memset(buffer
, format
== PA_SAMPLE_U8
? 0x80 : 0, bytes
);
246 static void pulse_op_cb(pa_stream
*s
, int success
, void *user
) {
247 TRACE("Success: %i\n", success
);
248 *(int*)user
= success
;
252 static DWORD WINAPI
pulse_timer_cb(void *user
)
255 pulse
->timer_loop(This
->pulse_stream
);
259 static void set_stream_volumes(ACImpl
*This
)
261 float master_vol
= This
->session
->mute
? 0.0f
: This
->session
->master_vol
;
262 pulse
->set_volumes(This
->pulse_stream
, master_vol
, This
->vol
,
263 This
->session
->channel_vols
);
266 HRESULT WINAPI
AUDDRV_GetEndpointIDs(EDataFlow flow
, const WCHAR
***ids
, GUID
**keys
,
267 UINT
*num
, UINT
*def_index
)
271 TRACE("%d %p %p %p\n", flow
, ids
, num
, def_index
);
276 *ids
= HeapAlloc(GetProcessHeap(), 0, sizeof(**ids
));
279 return E_OUTOFMEMORY
;
281 (*ids
)[0] = id
= HeapAlloc(GetProcessHeap(), 0, sizeof(defaultW
));
282 *keys
= HeapAlloc(GetProcessHeap(), 0, sizeof(**keys
));
284 HeapFree(GetProcessHeap(), 0, id
);
285 HeapFree(GetProcessHeap(), 0, *keys
);
286 HeapFree(GetProcessHeap(), 0, *ids
);
289 return E_OUTOFMEMORY
;
291 memcpy(id
, defaultW
, sizeof(defaultW
));
294 (*keys
)[0] = pulse_render_guid
;
296 (*keys
)[0] = pulse_capture_guid
;
301 int WINAPI
AUDDRV_GetPriority(void)
306 name
= get_application_name();
307 hr
= pulse
->test_connect(name
, &pulse_config
);
309 return SUCCEEDED(hr
) ? Priority_Preferred
: Priority_Unavailable
;
312 HRESULT WINAPI
AUDDRV_GetAudioEndpoint(GUID
*guid
, IMMDevice
*dev
, IAudioClient
**out
)
319 TRACE("%s %p %p\n", debugstr_guid(guid
), dev
, out
);
320 if (IsEqualGUID(guid
, &pulse_render_guid
))
322 else if (IsEqualGUID(guid
, &pulse_capture_guid
))
329 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*This
));
331 return E_OUTOFMEMORY
;
333 This
->IAudioClient3_iface
.lpVtbl
= &AudioClient3_Vtbl
;
334 This
->IAudioRenderClient_iface
.lpVtbl
= &AudioRenderClient_Vtbl
;
335 This
->IAudioCaptureClient_iface
.lpVtbl
= &AudioCaptureClient_Vtbl
;
336 This
->IAudioClock_iface
.lpVtbl
= &AudioClock_Vtbl
;
337 This
->IAudioClock2_iface
.lpVtbl
= &AudioClock2_Vtbl
;
338 This
->IAudioStreamVolume_iface
.lpVtbl
= &AudioStreamVolume_Vtbl
;
339 This
->dataflow
= dataflow
;
341 for (i
= 0; i
< PA_CHANNELS_MAX
; ++i
)
344 hr
= CoCreateFreeThreadedMarshaler((IUnknown
*)&This
->IAudioClient3_iface
, &This
->marshal
);
346 HeapFree(GetProcessHeap(), 0, This
);
349 IMMDevice_AddRef(This
->parent
);
351 *out
= (IAudioClient
*)&This
->IAudioClient3_iface
;
352 IAudioClient3_AddRef(&This
->IAudioClient3_iface
);
357 static HRESULT WINAPI
AudioClient_QueryInterface(IAudioClient3
*iface
,
358 REFIID riid
, void **ppv
)
360 ACImpl
*This
= impl_from_IAudioClient3(iface
);
362 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
368 if (IsEqualIID(riid
, &IID_IUnknown
) ||
369 IsEqualIID(riid
, &IID_IAudioClient
) ||
370 IsEqualIID(riid
, &IID_IAudioClient2
) ||
371 IsEqualIID(riid
, &IID_IAudioClient3
))
374 IUnknown_AddRef((IUnknown
*)*ppv
);
378 if (IsEqualIID(riid
, &IID_IMarshal
))
379 return IUnknown_QueryInterface(This
->marshal
, riid
, ppv
);
381 WARN("Unknown interface %s\n", debugstr_guid(riid
));
382 return E_NOINTERFACE
;
385 static ULONG WINAPI
AudioClient_AddRef(IAudioClient3
*iface
)
387 ACImpl
*This
= impl_from_IAudioClient3(iface
);
389 ref
= InterlockedIncrement(&This
->ref
);
390 TRACE("(%p) Refcount now %u\n", This
, ref
);
394 static ULONG WINAPI
AudioClient_Release(IAudioClient3
*iface
)
396 ACImpl
*This
= impl_from_IAudioClient3(iface
);
398 ref
= InterlockedDecrement(&This
->ref
);
399 TRACE("(%p) Refcount now %u\n", This
, ref
);
401 if (This
->pulse_stream
) {
402 pulse
->release_stream(This
->pulse_stream
, This
->timer
);
403 This
->pulse_stream
= NULL
;
405 list_remove(&This
->entry
);
408 IUnknown_Release(This
->marshal
);
409 IMMDevice_Release(This
->parent
);
410 HeapFree(GetProcessHeap(), 0, This
);
415 static void dump_fmt(const WAVEFORMATEX
*fmt
)
417 TRACE("wFormatTag: 0x%x (", fmt
->wFormatTag
);
418 switch(fmt
->wFormatTag
) {
419 case WAVE_FORMAT_PCM
:
420 TRACE("WAVE_FORMAT_PCM");
422 case WAVE_FORMAT_IEEE_FLOAT
:
423 TRACE("WAVE_FORMAT_IEEE_FLOAT");
425 case WAVE_FORMAT_EXTENSIBLE
:
426 TRACE("WAVE_FORMAT_EXTENSIBLE");
434 TRACE("nChannels: %u\n", fmt
->nChannels
);
435 TRACE("nSamplesPerSec: %u\n", fmt
->nSamplesPerSec
);
436 TRACE("nAvgBytesPerSec: %u\n", fmt
->nAvgBytesPerSec
);
437 TRACE("nBlockAlign: %u\n", fmt
->nBlockAlign
);
438 TRACE("wBitsPerSample: %u\n", fmt
->wBitsPerSample
);
439 TRACE("cbSize: %u\n", fmt
->cbSize
);
441 if (fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
) {
442 WAVEFORMATEXTENSIBLE
*fmtex
= (void*)fmt
;
443 TRACE("dwChannelMask: %08x\n", fmtex
->dwChannelMask
);
444 TRACE("Samples: %04x\n", fmtex
->Samples
.wReserved
);
445 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex
->SubFormat
));
449 static WAVEFORMATEX
*clone_format(const WAVEFORMATEX
*fmt
)
454 if (fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
455 size
= sizeof(WAVEFORMATEXTENSIBLE
);
457 size
= sizeof(WAVEFORMATEX
);
459 ret
= CoTaskMemAlloc(size
);
463 memcpy(ret
, fmt
, size
);
465 ret
->cbSize
= size
- sizeof(WAVEFORMATEX
);
470 static void session_init_vols(AudioSession
*session
, UINT channels
)
472 if (session
->channel_count
< channels
) {
475 if (session
->channel_vols
)
476 session
->channel_vols
= HeapReAlloc(GetProcessHeap(), 0,
477 session
->channel_vols
, sizeof(float) * channels
);
479 session
->channel_vols
= HeapAlloc(GetProcessHeap(), 0,
480 sizeof(float) * channels
);
481 if (!session
->channel_vols
)
484 for(i
= session
->channel_count
; i
< channels
; ++i
)
485 session
->channel_vols
[i
] = 1.f
;
487 session
->channel_count
= channels
;
491 static AudioSession
*create_session(const GUID
*guid
, IMMDevice
*device
,
496 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(AudioSession
));
500 memcpy(&ret
->guid
, guid
, sizeof(GUID
));
502 ret
->device
= device
;
504 list_init(&ret
->clients
);
506 list_add_head(&g_sessions
, &ret
->entry
);
508 session_init_vols(ret
, num_channels
);
510 ret
->master_vol
= 1.f
;
515 /* if channels == 0, then this will return or create a session with
516 * matching dataflow and GUID. otherwise, channels must also match */
517 static HRESULT
get_audio_session(const GUID
*sessionguid
,
518 IMMDevice
*device
, UINT channels
, AudioSession
**out
)
520 AudioSession
*session
;
522 if (!sessionguid
|| IsEqualGUID(sessionguid
, &GUID_NULL
)) {
523 *out
= create_session(&GUID_NULL
, device
, channels
);
525 return E_OUTOFMEMORY
;
531 LIST_FOR_EACH_ENTRY(session
, &g_sessions
, AudioSession
, entry
) {
532 if (session
->device
== device
&&
533 IsEqualGUID(sessionguid
, &session
->guid
)) {
534 session_init_vols(session
, channels
);
541 *out
= create_session(sessionguid
, device
, channels
);
543 return E_OUTOFMEMORY
;
549 static HRESULT WINAPI
AudioClient_Initialize(IAudioClient3
*iface
,
550 AUDCLNT_SHAREMODE mode
, DWORD flags
, REFERENCE_TIME duration
,
551 REFERENCE_TIME period
, const WAVEFORMATEX
*fmt
,
552 const GUID
*sessionguid
)
554 ACImpl
*This
= impl_from_IAudioClient3(iface
);
558 TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This
, mode
, flags
,
559 wine_dbgstr_longlong(duration
), wine_dbgstr_longlong(period
), fmt
, debugstr_guid(sessionguid
));
565 if (mode
!= AUDCLNT_SHAREMODE_SHARED
&& mode
!= AUDCLNT_SHAREMODE_EXCLUSIVE
)
567 if (mode
== AUDCLNT_SHAREMODE_EXCLUSIVE
)
568 return AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED
;
570 if (flags
& ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS
|
571 AUDCLNT_STREAMFLAGS_LOOPBACK
|
572 AUDCLNT_STREAMFLAGS_EVENTCALLBACK
|
573 AUDCLNT_STREAMFLAGS_NOPERSIST
|
574 AUDCLNT_STREAMFLAGS_RATEADJUST
|
575 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED
|
576 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE
|
577 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED
|
578 AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY
|
579 AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM
)) {
580 FIXME("Unknown flags: %08x\n", flags
);
586 if (This
->pulse_stream
) {
588 return AUDCLNT_E_ALREADY_INITIALIZED
;
593 if (!(pulse_thread
= CreateThread(NULL
, 0, pulse_mainloop_thread
, NULL
, 0, NULL
)))
595 ERR("Failed to create mainloop thread.\n");
599 SetThreadPriority(pulse_thread
, THREAD_PRIORITY_TIME_CRITICAL
);
603 name
= get_application_name();
604 hr
= pulse
->create_stream(name
, This
->dataflow
, mode
, flags
, duration
, period
, fmt
,
605 &This
->channel_count
, &This
->pulse_stream
);
608 hr
= get_audio_session(sessionguid
, This
->parent
, This
->channel_count
, &This
->session
);
610 set_stream_volumes(This
);
611 list_add_tail(&This
->session
->clients
, &This
->entry
);
613 pulse
->release_stream(This
->pulse_stream
, NULL
);
614 This
->pulse_stream
= NULL
;
622 static HRESULT WINAPI
AudioClient_GetBufferSize(IAudioClient3
*iface
,
625 ACImpl
*This
= impl_from_IAudioClient3(iface
);
628 TRACE("(%p)->(%p)\n", This
, out
);
634 hr
= pulse_stream_valid(This
);
636 *out
= This
->pulse_stream
->bufsize_frames
;
642 static HRESULT WINAPI
AudioClient_GetStreamLatency(IAudioClient3
*iface
,
643 REFERENCE_TIME
*latency
)
645 ACImpl
*This
= impl_from_IAudioClient3(iface
);
646 const pa_buffer_attr
*attr
;
650 TRACE("(%p)->(%p)\n", This
, latency
);
656 hr
= pulse_stream_valid(This
);
661 attr
= pa_stream_get_buffer_attr(This
->pulse_stream
->stream
);
662 if (This
->dataflow
== eRender
){
663 lat
= attr
->minreq
/ pa_frame_size(&This
->pulse_stream
->ss
);
665 lat
= attr
->fragsize
/ pa_frame_size(&This
->pulse_stream
->ss
);
668 *latency
/= This
->pulse_stream
->ss
.rate
;
669 *latency
+= pulse_config
.modes
[0].def_period
;
671 TRACE("Latency: %u ms\n", (DWORD
)(*latency
/ 10000));
675 static void ACImpl_GetRenderPad(ACImpl
*This
, UINT32
*out
)
677 *out
= This
->pulse_stream
->held_bytes
/ pa_frame_size(&This
->pulse_stream
->ss
);
680 static void ACImpl_GetCapturePad(ACImpl
*This
, UINT32
*out
)
682 ACPacket
*packet
= This
->pulse_stream
->locked_ptr
;
683 if (!packet
&& !list_empty(&This
->pulse_stream
->packet_filled_head
)) {
684 packet
= (ACPacket
*)list_head(&This
->pulse_stream
->packet_filled_head
);
685 This
->pulse_stream
->locked_ptr
= packet
;
686 list_remove(&packet
->entry
);
689 *out
= This
->pulse_stream
->held_bytes
/ pa_frame_size(&This
->pulse_stream
->ss
);
692 static HRESULT WINAPI
AudioClient_GetCurrentPadding(IAudioClient3
*iface
,
695 ACImpl
*This
= impl_from_IAudioClient3(iface
);
698 TRACE("(%p)->(%p)\n", This
, out
);
704 hr
= pulse_stream_valid(This
);
710 if (This
->dataflow
== eRender
)
711 ACImpl_GetRenderPad(This
, out
);
713 ACImpl_GetCapturePad(This
, out
);
716 TRACE("%p Pad: %u ms (%u)\n", This
, MulDiv(*out
, 1000, This
->pulse_stream
->ss
.rate
), *out
);
720 static HRESULT WINAPI
AudioClient_IsFormatSupported(IAudioClient3
*iface
,
721 AUDCLNT_SHAREMODE mode
, const WAVEFORMATEX
*fmt
,
724 ACImpl
*This
= impl_from_IAudioClient3(iface
);
726 WAVEFORMATEX
*closest
= NULL
;
729 TRACE("(%p)->(%x, %p, %p)\n", This
, mode
, fmt
, out
);
737 if (mode
== AUDCLNT_SHAREMODE_EXCLUSIVE
) {
740 } else if (mode
== AUDCLNT_SHAREMODE_SHARED
) {
747 if (fmt
->nChannels
== 0)
748 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
750 closest
= clone_format(fmt
);
752 return E_OUTOFMEMORY
;
756 switch (fmt
->wFormatTag
) {
757 case WAVE_FORMAT_EXTENSIBLE
: {
758 WAVEFORMATEXTENSIBLE
*ext
= (WAVEFORMATEXTENSIBLE
*)closest
;
760 if ((fmt
->cbSize
!= sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
) &&
761 fmt
->cbSize
!= sizeof(WAVEFORMATEXTENSIBLE
)) ||
762 fmt
->nBlockAlign
!= fmt
->wBitsPerSample
/ 8 * fmt
->nChannels
||
763 ext
->Samples
.wValidBitsPerSample
> fmt
->wBitsPerSample
||
764 fmt
->nAvgBytesPerSec
!= fmt
->nBlockAlign
* fmt
->nSamplesPerSec
) {
770 UINT32 mask
= 0, i
, channels
= 0;
772 if (!(ext
->dwChannelMask
& (SPEAKER_ALL
| SPEAKER_RESERVED
))) {
773 for (i
= 1; !(i
& SPEAKER_RESERVED
); i
<<= 1) {
774 if (i
& ext
->dwChannelMask
) {
780 if (channels
!= fmt
->nChannels
|| (ext
->dwChannelMask
& ~mask
)) {
781 hr
= AUDCLNT_E_UNSUPPORTED_FORMAT
;
785 hr
= AUDCLNT_E_UNSUPPORTED_FORMAT
;
790 if (IsEqualGUID(&ext
->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
)) {
791 if (fmt
->wBitsPerSample
!= 32) {
796 if (ext
->Samples
.wValidBitsPerSample
!= fmt
->wBitsPerSample
) {
798 ext
->Samples
.wValidBitsPerSample
= fmt
->wBitsPerSample
;
800 } else if (IsEqualGUID(&ext
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
)) {
801 if (!fmt
->wBitsPerSample
|| fmt
->wBitsPerSample
> 32 || fmt
->wBitsPerSample
% 8) {
806 if (ext
->Samples
.wValidBitsPerSample
!= fmt
->wBitsPerSample
&&
807 !(fmt
->wBitsPerSample
== 32 &&
808 ext
->Samples
.wValidBitsPerSample
== 24)) {
810 ext
->Samples
.wValidBitsPerSample
= fmt
->wBitsPerSample
;
814 hr
= AUDCLNT_E_UNSUPPORTED_FORMAT
;
821 case WAVE_FORMAT_ALAW
:
822 case WAVE_FORMAT_MULAW
:
823 if (fmt
->wBitsPerSample
!= 8) {
828 case WAVE_FORMAT_IEEE_FLOAT
:
829 if (fmt
->wFormatTag
== WAVE_FORMAT_IEEE_FLOAT
&& fmt
->wBitsPerSample
!= 32) {
834 case WAVE_FORMAT_PCM
:
835 if (fmt
->wFormatTag
== WAVE_FORMAT_PCM
&&
836 (!fmt
->wBitsPerSample
|| fmt
->wBitsPerSample
> 32 || fmt
->wBitsPerSample
% 8)) {
841 if (fmt
->nChannels
> 2) {
842 hr
= AUDCLNT_E_UNSUPPORTED_FORMAT
;
846 * fmt->cbSize, fmt->nBlockAlign and fmt->nAvgBytesPerSec seem to be
847 * ignored, invalid values are happily accepted.
851 hr
= AUDCLNT_E_UNSUPPORTED_FORMAT
;
855 if (exclusive
&& hr
!= S_OK
) {
856 hr
= AUDCLNT_E_UNSUPPORTED_FORMAT
;
857 CoTaskMemFree(closest
);
858 } else if (hr
!= S_FALSE
)
859 CoTaskMemFree(closest
);
863 /* Winepulse does not currently support exclusive mode, if you know of an
864 * application that uses it, I will correct this..
866 if (hr
== S_OK
&& exclusive
)
867 return This
->dataflow
== eCapture
? AUDCLNT_E_UNSUPPORTED_FORMAT
: AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED
;
869 TRACE("returning: %08x %p\n", hr
, out
? *out
: NULL
);
873 static HRESULT WINAPI
AudioClient_GetMixFormat(IAudioClient3
*iface
,
876 ACImpl
*This
= impl_from_IAudioClient3(iface
);
878 TRACE("(%p)->(%p)\n", This
, pwfx
);
883 *pwfx
= clone_format(&pulse_config
.modes
[This
->dataflow
== eCapture
].format
.Format
);
885 return E_OUTOFMEMORY
;
890 static HRESULT WINAPI
AudioClient_GetDevicePeriod(IAudioClient3
*iface
,
891 REFERENCE_TIME
*defperiod
, REFERENCE_TIME
*minperiod
)
893 ACImpl
*This
= impl_from_IAudioClient3(iface
);
895 TRACE("(%p)->(%p, %p)\n", This
, defperiod
, minperiod
);
897 if (!defperiod
&& !minperiod
)
901 *defperiod
= pulse_config
.modes
[This
->dataflow
== eCapture
].def_period
;
903 *minperiod
= pulse_config
.modes
[This
->dataflow
== eCapture
].min_period
;
908 static HRESULT WINAPI
AudioClient_Start(IAudioClient3
*iface
)
910 ACImpl
*This
= impl_from_IAudioClient3(iface
);
913 TRACE("(%p)\n", This
);
915 if (!This
->pulse_stream
)
916 return AUDCLNT_E_NOT_INITIALIZED
;
918 hr
= pulse
->start(This
->pulse_stream
);
923 This
->timer
= CreateThread(NULL
, 0, pulse_timer_cb
, This
, 0, NULL
);
924 SetThreadPriority(This
->timer
, THREAD_PRIORITY_TIME_CRITICAL
);
930 static HRESULT WINAPI
AudioClient_Stop(IAudioClient3
*iface
)
932 ACImpl
*This
= impl_from_IAudioClient3(iface
);
933 TRACE("(%p)\n", This
);
935 if (!This
->pulse_stream
)
936 return AUDCLNT_E_NOT_INITIALIZED
;
938 return pulse
->stop(This
->pulse_stream
);
941 static HRESULT WINAPI
AudioClient_Reset(IAudioClient3
*iface
)
943 ACImpl
*This
= impl_from_IAudioClient3(iface
);
946 TRACE("(%p)\n", This
);
949 hr
= pulse_stream_valid(This
);
955 if (This
->pulse_stream
->started
) {
957 return AUDCLNT_E_NOT_STOPPED
;
960 if (This
->pulse_stream
->locked
) {
962 return AUDCLNT_E_BUFFER_OPERATION_PENDING
;
965 if (This
->dataflow
== eRender
) {
966 /* If there is still data in the render buffer it needs to be removed from the server */
968 if (This
->pulse_stream
->held_bytes
) {
969 pa_operation
*o
= pa_stream_flush(This
->pulse_stream
->stream
, pulse_op_cb
, &success
);
971 while(pa_operation_get_state(o
) == PA_OPERATION_RUNNING
)
973 pa_operation_unref(o
);
976 if (success
|| !This
->pulse_stream
->held_bytes
){
977 This
->pulse_stream
->clock_lastpos
= This
->pulse_stream
->clock_written
= 0;
978 This
->pulse_stream
->pa_offs_bytes
= This
->pulse_stream
->lcl_offs_bytes
= This
->pulse_stream
->held_bytes
= This
->pulse_stream
->pa_held_bytes
= 0;
982 This
->pulse_stream
->clock_written
+= This
->pulse_stream
->held_bytes
;
983 This
->pulse_stream
->held_bytes
= 0;
985 if ((p
= This
->pulse_stream
->locked_ptr
)) {
986 This
->pulse_stream
->locked_ptr
= NULL
;
987 list_add_tail(&This
->pulse_stream
->packet_free_head
, &p
->entry
);
989 list_move_tail(&This
->pulse_stream
->packet_free_head
, &This
->pulse_stream
->packet_filled_head
);
996 static HRESULT WINAPI
AudioClient_SetEventHandle(IAudioClient3
*iface
,
999 ACImpl
*This
= impl_from_IAudioClient3(iface
);
1002 TRACE("(%p)->(%p)\n", This
, event
);
1005 return E_INVALIDARG
;
1008 hr
= pulse_stream_valid(This
);
1014 if (!(This
->pulse_stream
->flags
& AUDCLNT_STREAMFLAGS_EVENTCALLBACK
))
1015 hr
= AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED
;
1016 else if (This
->pulse_stream
->event
)
1017 hr
= HRESULT_FROM_WIN32(ERROR_INVALID_NAME
);
1019 This
->pulse_stream
->event
= event
;
1024 static HRESULT WINAPI
AudioClient_GetService(IAudioClient3
*iface
, REFIID riid
,
1027 ACImpl
*This
= impl_from_IAudioClient3(iface
);
1030 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), ppv
);
1037 hr
= pulse_stream_valid(This
);
1042 if (IsEqualIID(riid
, &IID_IAudioRenderClient
)) {
1043 if (This
->dataflow
!= eRender
)
1044 return AUDCLNT_E_WRONG_ENDPOINT_TYPE
;
1045 *ppv
= &This
->IAudioRenderClient_iface
;
1046 } else if (IsEqualIID(riid
, &IID_IAudioCaptureClient
)) {
1047 if (This
->dataflow
!= eCapture
)
1048 return AUDCLNT_E_WRONG_ENDPOINT_TYPE
;
1049 *ppv
= &This
->IAudioCaptureClient_iface
;
1050 } else if (IsEqualIID(riid
, &IID_IAudioClock
)) {
1051 *ppv
= &This
->IAudioClock_iface
;
1052 } else if (IsEqualIID(riid
, &IID_IAudioStreamVolume
)) {
1053 *ppv
= &This
->IAudioStreamVolume_iface
;
1054 } else if (IsEqualIID(riid
, &IID_IAudioSessionControl
) ||
1055 IsEqualIID(riid
, &IID_IChannelAudioVolume
) ||
1056 IsEqualIID(riid
, &IID_ISimpleAudioVolume
)) {
1057 if (!This
->session_wrapper
) {
1058 This
->session_wrapper
= AudioSessionWrapper_Create(This
);
1059 if (!This
->session_wrapper
)
1060 return E_OUTOFMEMORY
;
1062 if (IsEqualIID(riid
, &IID_IAudioSessionControl
))
1063 *ppv
= &This
->session_wrapper
->IAudioSessionControl2_iface
;
1064 else if (IsEqualIID(riid
, &IID_IChannelAudioVolume
))
1065 *ppv
= &This
->session_wrapper
->IChannelAudioVolume_iface
;
1066 else if (IsEqualIID(riid
, &IID_ISimpleAudioVolume
))
1067 *ppv
= &This
->session_wrapper
->ISimpleAudioVolume_iface
;
1071 IUnknown_AddRef((IUnknown
*)*ppv
);
1075 FIXME("stub %s\n", debugstr_guid(riid
));
1076 return E_NOINTERFACE
;
1079 static HRESULT WINAPI
AudioClient_IsOffloadCapable(IAudioClient3
*iface
,
1080 AUDIO_STREAM_CATEGORY category
, BOOL
*offload_capable
)
1082 ACImpl
*This
= impl_from_IAudioClient3(iface
);
1084 TRACE("(%p)->(0x%x, %p)\n", This
, category
, offload_capable
);
1086 if(!offload_capable
)
1087 return E_INVALIDARG
;
1089 *offload_capable
= FALSE
;
1094 static HRESULT WINAPI
AudioClient_SetClientProperties(IAudioClient3
*iface
,
1095 const AudioClientProperties
*prop
)
1097 ACImpl
*This
= impl_from_IAudioClient3(iface
);
1098 const Win8AudioClientProperties
*legacy_prop
= (const Win8AudioClientProperties
*)prop
;
1100 TRACE("(%p)->(%p)\n", This
, prop
);
1105 if(legacy_prop
->cbSize
== sizeof(AudioClientProperties
)){
1106 TRACE("{ bIsOffload: %u, eCategory: 0x%x, Options: 0x%x }\n",
1107 legacy_prop
->bIsOffload
,
1108 legacy_prop
->eCategory
,
1110 }else if(legacy_prop
->cbSize
== sizeof(Win8AudioClientProperties
)){
1111 TRACE("{ bIsOffload: %u, eCategory: 0x%x }\n",
1112 legacy_prop
->bIsOffload
,
1113 legacy_prop
->eCategory
);
1115 WARN("Unsupported Size = %d\n", legacy_prop
->cbSize
);
1116 return E_INVALIDARG
;
1120 if(legacy_prop
->bIsOffload
)
1121 return AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE
;
1126 static HRESULT WINAPI
AudioClient_GetBufferSizeLimits(IAudioClient3
*iface
,
1127 const WAVEFORMATEX
*format
, BOOL event_driven
, REFERENCE_TIME
*min_duration
,
1128 REFERENCE_TIME
*max_duration
)
1130 ACImpl
*This
= impl_from_IAudioClient3(iface
);
1132 FIXME("(%p)->(%p, %u, %p, %p)\n", This
, format
, event_driven
, min_duration
, max_duration
);
1137 static HRESULT WINAPI
AudioClient_GetSharedModeEnginePeriod(IAudioClient3
*iface
,
1138 const WAVEFORMATEX
*format
, UINT32
*default_period_frames
, UINT32
*unit_period_frames
,
1139 UINT32
*min_period_frames
, UINT32
*max_period_frames
)
1141 ACImpl
*This
= impl_from_IAudioClient3(iface
);
1143 FIXME("(%p)->(%p, %p, %p, %p, %p)\n", This
, format
, default_period_frames
, unit_period_frames
,
1144 min_period_frames
, max_period_frames
);
1149 static HRESULT WINAPI
AudioClient_GetCurrentSharedModeEnginePeriod(IAudioClient3
*iface
,
1150 WAVEFORMATEX
**cur_format
, UINT32
*cur_period_frames
)
1152 ACImpl
*This
= impl_from_IAudioClient3(iface
);
1154 FIXME("(%p)->(%p, %p)\n", This
, cur_format
, cur_period_frames
);
1159 static HRESULT WINAPI
AudioClient_InitializeSharedAudioStream(IAudioClient3
*iface
,
1160 DWORD flags
, UINT32 period_frames
, const WAVEFORMATEX
*format
,
1161 const GUID
*session_guid
)
1163 ACImpl
*This
= impl_from_IAudioClient3(iface
);
1165 FIXME("(%p)->(0x%x, %u, %p, %s)\n", This
, flags
, period_frames
, format
, debugstr_guid(session_guid
));
1170 static const IAudioClient3Vtbl AudioClient3_Vtbl
=
1172 AudioClient_QueryInterface
,
1174 AudioClient_Release
,
1175 AudioClient_Initialize
,
1176 AudioClient_GetBufferSize
,
1177 AudioClient_GetStreamLatency
,
1178 AudioClient_GetCurrentPadding
,
1179 AudioClient_IsFormatSupported
,
1180 AudioClient_GetMixFormat
,
1181 AudioClient_GetDevicePeriod
,
1185 AudioClient_SetEventHandle
,
1186 AudioClient_GetService
,
1187 AudioClient_IsOffloadCapable
,
1188 AudioClient_SetClientProperties
,
1189 AudioClient_GetBufferSizeLimits
,
1190 AudioClient_GetSharedModeEnginePeriod
,
1191 AudioClient_GetCurrentSharedModeEnginePeriod
,
1192 AudioClient_InitializeSharedAudioStream
,
1195 static HRESULT WINAPI
AudioRenderClient_QueryInterface(
1196 IAudioRenderClient
*iface
, REFIID riid
, void **ppv
)
1198 ACImpl
*This
= impl_from_IAudioRenderClient(iface
);
1199 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
1205 if (IsEqualIID(riid
, &IID_IUnknown
) ||
1206 IsEqualIID(riid
, &IID_IAudioRenderClient
))
1209 IUnknown_AddRef((IUnknown
*)*ppv
);
1213 if (IsEqualIID(riid
, &IID_IMarshal
))
1214 return IUnknown_QueryInterface(This
->marshal
, riid
, ppv
);
1216 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1217 return E_NOINTERFACE
;
1220 static ULONG WINAPI
AudioRenderClient_AddRef(IAudioRenderClient
*iface
)
1222 ACImpl
*This
= impl_from_IAudioRenderClient(iface
);
1223 return AudioClient_AddRef(&This
->IAudioClient3_iface
);
1226 static ULONG WINAPI
AudioRenderClient_Release(IAudioRenderClient
*iface
)
1228 ACImpl
*This
= impl_from_IAudioRenderClient(iface
);
1229 return AudioClient_Release(&This
->IAudioClient3_iface
);
1232 static void alloc_tmp_buffer(ACImpl
*This
, UINT32 bytes
)
1234 if(This
->pulse_stream
->tmp_buffer_bytes
>= bytes
)
1237 HeapFree(GetProcessHeap(), 0, This
->pulse_stream
->tmp_buffer
);
1238 This
->pulse_stream
->tmp_buffer
= HeapAlloc(GetProcessHeap(), 0, bytes
);
1239 This
->pulse_stream
->tmp_buffer_bytes
= bytes
;
1242 static HRESULT WINAPI
AudioRenderClient_GetBuffer(IAudioRenderClient
*iface
,
1243 UINT32 frames
, BYTE
**data
)
1245 ACImpl
*This
= impl_from_IAudioRenderClient(iface
);
1246 size_t bytes
= frames
* pa_frame_size(&This
->pulse_stream
->ss
);
1248 UINT32 wri_offs_bytes
;
1250 TRACE("(%p)->(%u, %p)\n", This
, frames
, data
);
1257 hr
= pulse_stream_valid(This
);
1258 if (FAILED(hr
) || This
->pulse_stream
->locked
) {
1260 return FAILED(hr
) ? hr
: AUDCLNT_E_OUT_OF_ORDER
;
1267 if(This
->pulse_stream
->held_bytes
/ pa_frame_size(&This
->pulse_stream
->ss
) + frames
> This
->pulse_stream
->bufsize_frames
){
1269 return AUDCLNT_E_BUFFER_TOO_LARGE
;
1272 wri_offs_bytes
= (This
->pulse_stream
->lcl_offs_bytes
+ This
->pulse_stream
->held_bytes
) % This
->pulse_stream
->real_bufsize_bytes
;
1273 if(wri_offs_bytes
+ bytes
> This
->pulse_stream
->real_bufsize_bytes
){
1274 alloc_tmp_buffer(This
, bytes
);
1275 *data
= This
->pulse_stream
->tmp_buffer
;
1276 This
->pulse_stream
->locked
= -bytes
;
1278 *data
= This
->pulse_stream
->local_buffer
+ wri_offs_bytes
;
1279 This
->pulse_stream
->locked
= bytes
;
1282 silence_buffer(This
->pulse_stream
->ss
.format
, *data
, bytes
);
1289 static void pulse_wrap_buffer(ACImpl
*This
, BYTE
*buffer
, UINT32 written_bytes
)
1291 UINT32 wri_offs_bytes
= (This
->pulse_stream
->lcl_offs_bytes
+ This
->pulse_stream
->held_bytes
) % This
->pulse_stream
->real_bufsize_bytes
;
1292 UINT32 chunk_bytes
= This
->pulse_stream
->real_bufsize_bytes
- wri_offs_bytes
;
1294 if(written_bytes
<= chunk_bytes
){
1295 memcpy(This
->pulse_stream
->local_buffer
+ wri_offs_bytes
, buffer
, written_bytes
);
1297 memcpy(This
->pulse_stream
->local_buffer
+ wri_offs_bytes
, buffer
, chunk_bytes
);
1298 memcpy(This
->pulse_stream
->local_buffer
, buffer
+ chunk_bytes
,
1299 written_bytes
- chunk_bytes
);
1303 static HRESULT WINAPI
AudioRenderClient_ReleaseBuffer(
1304 IAudioRenderClient
*iface
, UINT32 written_frames
, DWORD flags
)
1306 ACImpl
*This
= impl_from_IAudioRenderClient(iface
);
1307 UINT32 written_bytes
= written_frames
* pa_frame_size(&This
->pulse_stream
->ss
);
1310 TRACE("(%p)->(%u, %x)\n", This
, written_frames
, flags
);
1313 if (!This
->pulse_stream
->locked
|| !written_frames
) {
1314 This
->pulse_stream
->locked
= 0;
1316 return written_frames
? AUDCLNT_E_OUT_OF_ORDER
: S_OK
;
1319 if(written_frames
* pa_frame_size(&This
->pulse_stream
->ss
) > (This
->pulse_stream
->locked
>= 0 ? This
->pulse_stream
->locked
: -This
->pulse_stream
->locked
)){
1321 return AUDCLNT_E_INVALID_SIZE
;
1324 if(This
->pulse_stream
->locked
>= 0)
1325 buffer
= This
->pulse_stream
->local_buffer
+ (This
->pulse_stream
->lcl_offs_bytes
+ This
->pulse_stream
->held_bytes
) % This
->pulse_stream
->real_bufsize_bytes
;
1327 buffer
= This
->pulse_stream
->tmp_buffer
;
1329 if(flags
& AUDCLNT_BUFFERFLAGS_SILENT
)
1330 silence_buffer(This
->pulse_stream
->ss
.format
, buffer
, written_bytes
);
1332 if(This
->pulse_stream
->locked
< 0)
1333 pulse_wrap_buffer(This
, buffer
, written_bytes
);
1335 This
->pulse_stream
->held_bytes
+= written_bytes
;
1336 This
->pulse_stream
->pa_held_bytes
+= written_bytes
;
1337 if(This
->pulse_stream
->pa_held_bytes
> This
->pulse_stream
->real_bufsize_bytes
){
1338 This
->pulse_stream
->pa_offs_bytes
+= This
->pulse_stream
->pa_held_bytes
- This
->pulse_stream
->real_bufsize_bytes
;
1339 This
->pulse_stream
->pa_offs_bytes
%= This
->pulse_stream
->real_bufsize_bytes
;
1340 This
->pulse_stream
->pa_held_bytes
= This
->pulse_stream
->real_bufsize_bytes
;
1342 This
->pulse_stream
->clock_written
+= written_bytes
;
1343 This
->pulse_stream
->locked
= 0;
1345 TRACE("Released %u, held %zu\n", written_frames
, This
->pulse_stream
->held_bytes
/ pa_frame_size(&This
->pulse_stream
->ss
));
1352 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl
= {
1353 AudioRenderClient_QueryInterface
,
1354 AudioRenderClient_AddRef
,
1355 AudioRenderClient_Release
,
1356 AudioRenderClient_GetBuffer
,
1357 AudioRenderClient_ReleaseBuffer
1360 static HRESULT WINAPI
AudioCaptureClient_QueryInterface(
1361 IAudioCaptureClient
*iface
, REFIID riid
, void **ppv
)
1363 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1364 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
1370 if (IsEqualIID(riid
, &IID_IUnknown
) ||
1371 IsEqualIID(riid
, &IID_IAudioCaptureClient
))
1374 IUnknown_AddRef((IUnknown
*)*ppv
);
1378 if (IsEqualIID(riid
, &IID_IMarshal
))
1379 return IUnknown_QueryInterface(This
->marshal
, riid
, ppv
);
1381 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1382 return E_NOINTERFACE
;
1385 static ULONG WINAPI
AudioCaptureClient_AddRef(IAudioCaptureClient
*iface
)
1387 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1388 return IAudioClient3_AddRef(&This
->IAudioClient3_iface
);
1391 static ULONG WINAPI
AudioCaptureClient_Release(IAudioCaptureClient
*iface
)
1393 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1394 return IAudioClient3_Release(&This
->IAudioClient3_iface
);
1397 static HRESULT WINAPI
AudioCaptureClient_GetBuffer(IAudioCaptureClient
*iface
,
1398 BYTE
**data
, UINT32
*frames
, DWORD
*flags
, UINT64
*devpos
,
1401 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1405 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This
, data
, frames
, flags
,
1413 if (!frames
|| !flags
)
1417 hr
= pulse_stream_valid(This
);
1418 if (FAILED(hr
) || This
->pulse_stream
->locked
) {
1420 return FAILED(hr
) ? hr
: AUDCLNT_E_OUT_OF_ORDER
;
1423 ACImpl_GetCapturePad(This
, NULL
);
1424 if ((packet
= This
->pulse_stream
->locked_ptr
)) {
1425 *frames
= This
->pulse_stream
->period_bytes
/ pa_frame_size(&This
->pulse_stream
->ss
);
1427 if (packet
->discont
)
1428 *flags
|= AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY
;
1430 if (packet
->discont
)
1431 *devpos
= (This
->pulse_stream
->clock_written
+ This
->pulse_stream
->period_bytes
) / pa_frame_size(&This
->pulse_stream
->ss
);
1433 *devpos
= This
->pulse_stream
->clock_written
/ pa_frame_size(&This
->pulse_stream
->ss
);
1436 *qpcpos
= packet
->qpcpos
;
1437 *data
= packet
->data
;
1441 This
->pulse_stream
->locked
= *frames
;
1443 return *frames
? S_OK
: AUDCLNT_S_BUFFER_EMPTY
;
1446 static HRESULT WINAPI
AudioCaptureClient_ReleaseBuffer(
1447 IAudioCaptureClient
*iface
, UINT32 done
)
1449 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1451 TRACE("(%p)->(%u)\n", This
, done
);
1454 if (!This
->pulse_stream
->locked
&& done
) {
1456 return AUDCLNT_E_OUT_OF_ORDER
;
1458 if (done
&& This
->pulse_stream
->locked
!= done
) {
1460 return AUDCLNT_E_INVALID_SIZE
;
1463 ACPacket
*packet
= This
->pulse_stream
->locked_ptr
;
1464 This
->pulse_stream
->locked_ptr
= NULL
;
1465 This
->pulse_stream
->held_bytes
-= This
->pulse_stream
->period_bytes
;
1466 if (packet
->discont
)
1467 This
->pulse_stream
->clock_written
+= 2 * This
->pulse_stream
->period_bytes
;
1469 This
->pulse_stream
->clock_written
+= This
->pulse_stream
->period_bytes
;
1470 list_add_tail(&This
->pulse_stream
->packet_free_head
, &packet
->entry
);
1472 This
->pulse_stream
->locked
= 0;
1477 static HRESULT WINAPI
AudioCaptureClient_GetNextPacketSize(
1478 IAudioCaptureClient
*iface
, UINT32
*frames
)
1480 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1482 TRACE("(%p)->(%p)\n", This
, frames
);
1487 ACImpl_GetCapturePad(This
, NULL
);
1488 if (This
->pulse_stream
->locked_ptr
)
1489 *frames
= This
->pulse_stream
->period_bytes
/ pa_frame_size(&This
->pulse_stream
->ss
);
1496 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl
=
1498 AudioCaptureClient_QueryInterface
,
1499 AudioCaptureClient_AddRef
,
1500 AudioCaptureClient_Release
,
1501 AudioCaptureClient_GetBuffer
,
1502 AudioCaptureClient_ReleaseBuffer
,
1503 AudioCaptureClient_GetNextPacketSize
1506 static HRESULT WINAPI
AudioClock_QueryInterface(IAudioClock
*iface
,
1507 REFIID riid
, void **ppv
)
1509 ACImpl
*This
= impl_from_IAudioClock(iface
);
1511 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
1517 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IAudioClock
))
1519 else if (IsEqualIID(riid
, &IID_IAudioClock2
))
1520 *ppv
= &This
->IAudioClock2_iface
;
1522 IUnknown_AddRef((IUnknown
*)*ppv
);
1526 if (IsEqualIID(riid
, &IID_IMarshal
))
1527 return IUnknown_QueryInterface(This
->marshal
, riid
, ppv
);
1529 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1530 return E_NOINTERFACE
;
1533 static ULONG WINAPI
AudioClock_AddRef(IAudioClock
*iface
)
1535 ACImpl
*This
= impl_from_IAudioClock(iface
);
1536 return IAudioClient3_AddRef(&This
->IAudioClient3_iface
);
1539 static ULONG WINAPI
AudioClock_Release(IAudioClock
*iface
)
1541 ACImpl
*This
= impl_from_IAudioClock(iface
);
1542 return IAudioClient3_Release(&This
->IAudioClient3_iface
);
1545 static HRESULT WINAPI
AudioClock_GetFrequency(IAudioClock
*iface
, UINT64
*freq
)
1547 ACImpl
*This
= impl_from_IAudioClock(iface
);
1550 TRACE("(%p)->(%p)\n", This
, freq
);
1553 hr
= pulse_stream_valid(This
);
1554 if (SUCCEEDED(hr
)) {
1555 *freq
= This
->pulse_stream
->ss
.rate
;
1556 if (This
->pulse_stream
->share
== AUDCLNT_SHAREMODE_SHARED
)
1557 *freq
*= pa_frame_size(&This
->pulse_stream
->ss
);
1563 static HRESULT WINAPI
AudioClock_GetPosition(IAudioClock
*iface
, UINT64
*pos
,
1566 ACImpl
*This
= impl_from_IAudioClock(iface
);
1569 TRACE("(%p)->(%p, %p)\n", This
, pos
, qpctime
);
1575 hr
= pulse_stream_valid(This
);
1581 *pos
= This
->pulse_stream
->clock_written
- This
->pulse_stream
->held_bytes
;
1583 if (This
->pulse_stream
->share
== AUDCLNT_SHAREMODE_EXCLUSIVE
)
1584 *pos
/= pa_frame_size(&This
->pulse_stream
->ss
);
1586 /* Make time never go backwards */
1587 if (*pos
< This
->pulse_stream
->clock_lastpos
)
1588 *pos
= This
->pulse_stream
->clock_lastpos
;
1590 This
->pulse_stream
->clock_lastpos
= *pos
;
1593 TRACE("%p Position: %u\n", This
, (unsigned)*pos
);
1596 LARGE_INTEGER stamp
, freq
;
1597 QueryPerformanceCounter(&stamp
);
1598 QueryPerformanceFrequency(&freq
);
1599 *qpctime
= (stamp
.QuadPart
* (INT64
)10000000) / freq
.QuadPart
;
1605 static HRESULT WINAPI
AudioClock_GetCharacteristics(IAudioClock
*iface
,
1608 ACImpl
*This
= impl_from_IAudioClock(iface
);
1610 TRACE("(%p)->(%p)\n", This
, chars
);
1615 *chars
= AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ
;
1620 static const IAudioClockVtbl AudioClock_Vtbl
=
1622 AudioClock_QueryInterface
,
1625 AudioClock_GetFrequency
,
1626 AudioClock_GetPosition
,
1627 AudioClock_GetCharacteristics
1630 static HRESULT WINAPI
AudioClock2_QueryInterface(IAudioClock2
*iface
,
1631 REFIID riid
, void **ppv
)
1633 ACImpl
*This
= impl_from_IAudioClock2(iface
);
1634 return IAudioClock_QueryInterface(&This
->IAudioClock_iface
, riid
, ppv
);
1637 static ULONG WINAPI
AudioClock2_AddRef(IAudioClock2
*iface
)
1639 ACImpl
*This
= impl_from_IAudioClock2(iface
);
1640 return IAudioClient3_AddRef(&This
->IAudioClient3_iface
);
1643 static ULONG WINAPI
AudioClock2_Release(IAudioClock2
*iface
)
1645 ACImpl
*This
= impl_from_IAudioClock2(iface
);
1646 return IAudioClient3_Release(&This
->IAudioClient3_iface
);
1649 static HRESULT WINAPI
AudioClock2_GetDevicePosition(IAudioClock2
*iface
,
1650 UINT64
*pos
, UINT64
*qpctime
)
1652 ACImpl
*This
= impl_from_IAudioClock2(iface
);
1653 HRESULT hr
= AudioClock_GetPosition(&This
->IAudioClock_iface
, pos
, qpctime
);
1654 if (SUCCEEDED(hr
) && This
->pulse_stream
->share
== AUDCLNT_SHAREMODE_SHARED
)
1655 *pos
/= pa_frame_size(&This
->pulse_stream
->ss
);
1659 static const IAudioClock2Vtbl AudioClock2_Vtbl
=
1661 AudioClock2_QueryInterface
,
1663 AudioClock2_Release
,
1664 AudioClock2_GetDevicePosition
1667 static HRESULT WINAPI
AudioStreamVolume_QueryInterface(
1668 IAudioStreamVolume
*iface
, REFIID riid
, void **ppv
)
1670 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
1672 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
1678 if (IsEqualIID(riid
, &IID_IUnknown
) ||
1679 IsEqualIID(riid
, &IID_IAudioStreamVolume
))
1682 IUnknown_AddRef((IUnknown
*)*ppv
);
1686 if (IsEqualIID(riid
, &IID_IMarshal
))
1687 return IUnknown_QueryInterface(This
->marshal
, riid
, ppv
);
1689 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1690 return E_NOINTERFACE
;
1693 static ULONG WINAPI
AudioStreamVolume_AddRef(IAudioStreamVolume
*iface
)
1695 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
1696 return IAudioClient3_AddRef(&This
->IAudioClient3_iface
);
1699 static ULONG WINAPI
AudioStreamVolume_Release(IAudioStreamVolume
*iface
)
1701 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
1702 return IAudioClient3_Release(&This
->IAudioClient3_iface
);
1705 static HRESULT WINAPI
AudioStreamVolume_GetChannelCount(
1706 IAudioStreamVolume
*iface
, UINT32
*out
)
1708 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
1710 TRACE("(%p)->(%p)\n", This
, out
);
1715 *out
= This
->channel_count
;
1720 struct pulse_info_cb_data
{
1725 static HRESULT WINAPI
AudioStreamVolume_SetAllVolumes(
1726 IAudioStreamVolume
*iface
, UINT32 count
, const float *levels
)
1728 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
1732 TRACE("(%p)->(%d, %p)\n", This
, count
, levels
);
1737 if (count
!= This
->channel_count
)
1738 return E_INVALIDARG
;
1741 hr
= pulse_stream_valid(This
);
1745 for (i
= 0; i
< count
; ++i
)
1746 This
->vol
[i
] = levels
[i
];
1748 set_stream_volumes(This
);
1754 static HRESULT WINAPI
AudioStreamVolume_GetAllVolumes(
1755 IAudioStreamVolume
*iface
, UINT32 count
, float *levels
)
1757 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
1761 TRACE("(%p)->(%d, %p)\n", This
, count
, levels
);
1766 if (count
!= This
->channel_count
)
1767 return E_INVALIDARG
;
1770 hr
= pulse_stream_valid(This
);
1774 for (i
= 0; i
< count
; ++i
)
1775 levels
[i
] = This
->vol
[i
];
1782 static HRESULT WINAPI
AudioStreamVolume_SetChannelVolume(
1783 IAudioStreamVolume
*iface
, UINT32 index
, float level
)
1785 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
1787 float volumes
[PA_CHANNELS_MAX
];
1789 TRACE("(%p)->(%d, %f)\n", This
, index
, level
);
1791 if (level
< 0.f
|| level
> 1.f
)
1792 return E_INVALIDARG
;
1794 if (index
>= This
->channel_count
)
1795 return E_INVALIDARG
;
1797 hr
= AudioStreamVolume_GetAllVolumes(iface
, This
->channel_count
, volumes
);
1798 volumes
[index
] = level
;
1800 hr
= AudioStreamVolume_SetAllVolumes(iface
, This
->channel_count
, volumes
);
1804 static HRESULT WINAPI
AudioStreamVolume_GetChannelVolume(
1805 IAudioStreamVolume
*iface
, UINT32 index
, float *level
)
1807 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
1808 float volumes
[PA_CHANNELS_MAX
];
1811 TRACE("(%p)->(%d, %p)\n", This
, index
, level
);
1816 if (index
>= This
->channel_count
)
1817 return E_INVALIDARG
;
1819 hr
= AudioStreamVolume_GetAllVolumes(iface
, This
->channel_count
, volumes
);
1821 *level
= volumes
[index
];
1825 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl
=
1827 AudioStreamVolume_QueryInterface
,
1828 AudioStreamVolume_AddRef
,
1829 AudioStreamVolume_Release
,
1830 AudioStreamVolume_GetChannelCount
,
1831 AudioStreamVolume_SetChannelVolume
,
1832 AudioStreamVolume_GetChannelVolume
,
1833 AudioStreamVolume_SetAllVolumes
,
1834 AudioStreamVolume_GetAllVolumes
1837 static AudioSessionWrapper
*AudioSessionWrapper_Create(ACImpl
*client
)
1839 AudioSessionWrapper
*ret
;
1841 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
1842 sizeof(AudioSessionWrapper
));
1846 ret
->IAudioSessionControl2_iface
.lpVtbl
= &AudioSessionControl2_Vtbl
;
1847 ret
->ISimpleAudioVolume_iface
.lpVtbl
= &SimpleAudioVolume_Vtbl
;
1848 ret
->IChannelAudioVolume_iface
.lpVtbl
= &ChannelAudioVolume_Vtbl
;
1852 ret
->client
= client
;
1854 ret
->session
= client
->session
;
1855 AudioClient_AddRef(&client
->IAudioClient3_iface
);
1861 static HRESULT WINAPI
AudioSessionControl_QueryInterface(
1862 IAudioSessionControl2
*iface
, REFIID riid
, void **ppv
)
1864 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
1870 if (IsEqualIID(riid
, &IID_IUnknown
) ||
1871 IsEqualIID(riid
, &IID_IAudioSessionControl
) ||
1872 IsEqualIID(riid
, &IID_IAudioSessionControl2
))
1875 IUnknown_AddRef((IUnknown
*)*ppv
);
1879 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1880 return E_NOINTERFACE
;
1883 static ULONG WINAPI
AudioSessionControl_AddRef(IAudioSessionControl2
*iface
)
1885 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
1887 ref
= InterlockedIncrement(&This
->ref
);
1888 TRACE("(%p) Refcount now %u\n", This
, ref
);
1892 static ULONG WINAPI
AudioSessionControl_Release(IAudioSessionControl2
*iface
)
1894 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
1896 ref
= InterlockedDecrement(&This
->ref
);
1897 TRACE("(%p) Refcount now %u\n", This
, ref
);
1900 This
->client
->session_wrapper
= NULL
;
1901 AudioClient_Release(&This
->client
->IAudioClient3_iface
);
1903 HeapFree(GetProcessHeap(), 0, This
);
1908 static HRESULT WINAPI
AudioSessionControl_GetState(IAudioSessionControl2
*iface
,
1909 AudioSessionState
*state
)
1911 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
1914 TRACE("(%p)->(%p)\n", This
, state
);
1917 return NULL_PTR_ERR
;
1920 if (list_empty(&This
->session
->clients
)) {
1921 *state
= AudioSessionStateExpired
;
1924 LIST_FOR_EACH_ENTRY(client
, &This
->session
->clients
, ACImpl
, entry
) {
1925 if (client
->pulse_stream
->started
) {
1926 *state
= AudioSessionStateActive
;
1930 *state
= AudioSessionStateInactive
;
1937 static HRESULT WINAPI
AudioSessionControl_GetDisplayName(
1938 IAudioSessionControl2
*iface
, WCHAR
**name
)
1940 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
1942 FIXME("(%p)->(%p) - stub\n", This
, name
);
1947 static HRESULT WINAPI
AudioSessionControl_SetDisplayName(
1948 IAudioSessionControl2
*iface
, const WCHAR
*name
, const GUID
*session
)
1950 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
1952 FIXME("(%p)->(%p, %s) - stub\n", This
, name
, debugstr_guid(session
));
1957 static HRESULT WINAPI
AudioSessionControl_GetIconPath(
1958 IAudioSessionControl2
*iface
, WCHAR
**path
)
1960 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
1962 FIXME("(%p)->(%p) - stub\n", This
, path
);
1967 static HRESULT WINAPI
AudioSessionControl_SetIconPath(
1968 IAudioSessionControl2
*iface
, const WCHAR
*path
, const GUID
*session
)
1970 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
1972 FIXME("(%p)->(%p, %s) - stub\n", This
, path
, debugstr_guid(session
));
1977 static HRESULT WINAPI
AudioSessionControl_GetGroupingParam(
1978 IAudioSessionControl2
*iface
, GUID
*group
)
1980 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
1982 FIXME("(%p)->(%p) - stub\n", This
, group
);
1987 static HRESULT WINAPI
AudioSessionControl_SetGroupingParam(
1988 IAudioSessionControl2
*iface
, const GUID
*group
, const GUID
*session
)
1990 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
1992 FIXME("(%p)->(%s, %s) - stub\n", This
, debugstr_guid(group
),
1993 debugstr_guid(session
));
1998 static HRESULT WINAPI
AudioSessionControl_RegisterAudioSessionNotification(
1999 IAudioSessionControl2
*iface
, IAudioSessionEvents
*events
)
2001 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2003 FIXME("(%p)->(%p) - stub\n", This
, events
);
2008 static HRESULT WINAPI
AudioSessionControl_UnregisterAudioSessionNotification(
2009 IAudioSessionControl2
*iface
, IAudioSessionEvents
*events
)
2011 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2013 FIXME("(%p)->(%p) - stub\n", This
, events
);
2018 static HRESULT WINAPI
AudioSessionControl_GetSessionIdentifier(
2019 IAudioSessionControl2
*iface
, WCHAR
**id
)
2021 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2023 FIXME("(%p)->(%p) - stub\n", This
, id
);
2028 static HRESULT WINAPI
AudioSessionControl_GetSessionInstanceIdentifier(
2029 IAudioSessionControl2
*iface
, WCHAR
**id
)
2031 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2033 FIXME("(%p)->(%p) - stub\n", This
, id
);
2038 static HRESULT WINAPI
AudioSessionControl_GetProcessId(
2039 IAudioSessionControl2
*iface
, DWORD
*pid
)
2041 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2043 TRACE("(%p)->(%p)\n", This
, pid
);
2048 *pid
= GetCurrentProcessId();
2053 static HRESULT WINAPI
AudioSessionControl_IsSystemSoundsSession(
2054 IAudioSessionControl2
*iface
)
2056 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2058 TRACE("(%p)\n", This
);
2063 static HRESULT WINAPI
AudioSessionControl_SetDuckingPreference(
2064 IAudioSessionControl2
*iface
, BOOL optout
)
2066 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2068 TRACE("(%p)->(%d)\n", This
, optout
);
2073 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl
=
2075 AudioSessionControl_QueryInterface
,
2076 AudioSessionControl_AddRef
,
2077 AudioSessionControl_Release
,
2078 AudioSessionControl_GetState
,
2079 AudioSessionControl_GetDisplayName
,
2080 AudioSessionControl_SetDisplayName
,
2081 AudioSessionControl_GetIconPath
,
2082 AudioSessionControl_SetIconPath
,
2083 AudioSessionControl_GetGroupingParam
,
2084 AudioSessionControl_SetGroupingParam
,
2085 AudioSessionControl_RegisterAudioSessionNotification
,
2086 AudioSessionControl_UnregisterAudioSessionNotification
,
2087 AudioSessionControl_GetSessionIdentifier
,
2088 AudioSessionControl_GetSessionInstanceIdentifier
,
2089 AudioSessionControl_GetProcessId
,
2090 AudioSessionControl_IsSystemSoundsSession
,
2091 AudioSessionControl_SetDuckingPreference
2094 typedef struct _SessionMgr
{
2095 IAudioSessionManager2 IAudioSessionManager2_iface
;
2102 static HRESULT WINAPI
AudioSessionManager_QueryInterface(IAudioSessionManager2
*iface
,
2103 REFIID riid
, void **ppv
)
2105 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
2111 if (IsEqualIID(riid
, &IID_IUnknown
) ||
2112 IsEqualIID(riid
, &IID_IAudioSessionManager
) ||
2113 IsEqualIID(riid
, &IID_IAudioSessionManager2
))
2116 IUnknown_AddRef((IUnknown
*)*ppv
);
2120 WARN("Unknown interface %s\n", debugstr_guid(riid
));
2121 return E_NOINTERFACE
;
2124 static inline SessionMgr
*impl_from_IAudioSessionManager2(IAudioSessionManager2
*iface
)
2126 return CONTAINING_RECORD(iface
, SessionMgr
, IAudioSessionManager2_iface
);
2129 static ULONG WINAPI
AudioSessionManager_AddRef(IAudioSessionManager2
*iface
)
2131 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
2133 ref
= InterlockedIncrement(&This
->ref
);
2134 TRACE("(%p) Refcount now %u\n", This
, ref
);
2138 static ULONG WINAPI
AudioSessionManager_Release(IAudioSessionManager2
*iface
)
2140 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
2142 ref
= InterlockedDecrement(&This
->ref
);
2143 TRACE("(%p) Refcount now %u\n", This
, ref
);
2145 HeapFree(GetProcessHeap(), 0, This
);
2149 static HRESULT WINAPI
AudioSessionManager_GetAudioSessionControl(
2150 IAudioSessionManager2
*iface
, const GUID
*session_guid
, DWORD flags
,
2151 IAudioSessionControl
**out
)
2153 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
2154 AudioSession
*session
;
2155 AudioSessionWrapper
*wrapper
;
2158 TRACE("(%p)->(%s, %x, %p)\n", This
, debugstr_guid(session_guid
),
2161 hr
= get_audio_session(session_guid
, This
->device
, 0, &session
);
2165 wrapper
= AudioSessionWrapper_Create(NULL
);
2167 return E_OUTOFMEMORY
;
2169 wrapper
->session
= session
;
2171 *out
= (IAudioSessionControl
*)&wrapper
->IAudioSessionControl2_iface
;
2176 static HRESULT WINAPI
AudioSessionManager_GetSimpleAudioVolume(
2177 IAudioSessionManager2
*iface
, const GUID
*session_guid
, DWORD flags
,
2178 ISimpleAudioVolume
**out
)
2180 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
2181 AudioSession
*session
;
2182 AudioSessionWrapper
*wrapper
;
2185 TRACE("(%p)->(%s, %x, %p)\n", This
, debugstr_guid(session_guid
),
2188 hr
= get_audio_session(session_guid
, This
->device
, 0, &session
);
2192 wrapper
= AudioSessionWrapper_Create(NULL
);
2194 return E_OUTOFMEMORY
;
2196 wrapper
->session
= session
;
2198 *out
= &wrapper
->ISimpleAudioVolume_iface
;
2203 static HRESULT WINAPI
AudioSessionManager_GetSessionEnumerator(
2204 IAudioSessionManager2
*iface
, IAudioSessionEnumerator
**out
)
2206 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
2207 FIXME("(%p)->(%p) - stub\n", This
, out
);
2211 static HRESULT WINAPI
AudioSessionManager_RegisterSessionNotification(
2212 IAudioSessionManager2
*iface
, IAudioSessionNotification
*notification
)
2214 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
2215 FIXME("(%p)->(%p) - stub\n", This
, notification
);
2219 static HRESULT WINAPI
AudioSessionManager_UnregisterSessionNotification(
2220 IAudioSessionManager2
*iface
, IAudioSessionNotification
*notification
)
2222 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
2223 FIXME("(%p)->(%p) - stub\n", This
, notification
);
2227 static HRESULT WINAPI
AudioSessionManager_RegisterDuckNotification(
2228 IAudioSessionManager2
*iface
, const WCHAR
*session_id
,
2229 IAudioVolumeDuckNotification
*notification
)
2231 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
2232 FIXME("(%p)->(%p) - stub\n", This
, notification
);
2236 static HRESULT WINAPI
AudioSessionManager_UnregisterDuckNotification(
2237 IAudioSessionManager2
*iface
,
2238 IAudioVolumeDuckNotification
*notification
)
2240 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
2241 FIXME("(%p)->(%p) - stub\n", This
, notification
);
2245 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl
=
2247 AudioSessionManager_QueryInterface
,
2248 AudioSessionManager_AddRef
,
2249 AudioSessionManager_Release
,
2250 AudioSessionManager_GetAudioSessionControl
,
2251 AudioSessionManager_GetSimpleAudioVolume
,
2252 AudioSessionManager_GetSessionEnumerator
,
2253 AudioSessionManager_RegisterSessionNotification
,
2254 AudioSessionManager_UnregisterSessionNotification
,
2255 AudioSessionManager_RegisterDuckNotification
,
2256 AudioSessionManager_UnregisterDuckNotification
2259 static HRESULT WINAPI
SimpleAudioVolume_QueryInterface(
2260 ISimpleAudioVolume
*iface
, REFIID riid
, void **ppv
)
2262 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
2268 if (IsEqualIID(riid
, &IID_IUnknown
) ||
2269 IsEqualIID(riid
, &IID_ISimpleAudioVolume
))
2272 IUnknown_AddRef((IUnknown
*)*ppv
);
2276 WARN("Unknown interface %s\n", debugstr_guid(riid
));
2277 return E_NOINTERFACE
;
2280 static ULONG WINAPI
SimpleAudioVolume_AddRef(ISimpleAudioVolume
*iface
)
2282 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2283 return AudioSessionControl_AddRef(&This
->IAudioSessionControl2_iface
);
2286 static ULONG WINAPI
SimpleAudioVolume_Release(ISimpleAudioVolume
*iface
)
2288 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2289 return AudioSessionControl_Release(&This
->IAudioSessionControl2_iface
);
2292 static HRESULT WINAPI
SimpleAudioVolume_SetMasterVolume(
2293 ISimpleAudioVolume
*iface
, float level
, const GUID
*context
)
2295 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2296 AudioSession
*session
= This
->session
;
2299 TRACE("(%p)->(%f, %s)\n", session
, level
, wine_dbgstr_guid(context
));
2301 if (level
< 0.f
|| level
> 1.f
)
2302 return E_INVALIDARG
;
2305 FIXME("Notifications not supported yet\n");
2307 TRACE("PulseAudio does not support session volume control\n");
2310 session
->master_vol
= level
;
2311 LIST_FOR_EACH_ENTRY(client
, &This
->session
->clients
, ACImpl
, entry
)
2312 set_stream_volumes(client
);
2318 static HRESULT WINAPI
SimpleAudioVolume_GetMasterVolume(
2319 ISimpleAudioVolume
*iface
, float *level
)
2321 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2322 AudioSession
*session
= This
->session
;
2324 TRACE("(%p)->(%p)\n", session
, level
);
2327 return NULL_PTR_ERR
;
2329 *level
= session
->master_vol
;
2334 static HRESULT WINAPI
SimpleAudioVolume_SetMute(ISimpleAudioVolume
*iface
,
2335 BOOL mute
, const GUID
*context
)
2337 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2338 AudioSession
*session
= This
->session
;
2341 TRACE("(%p)->(%u, %s)\n", session
, mute
, debugstr_guid(context
));
2344 FIXME("Notifications not supported yet\n");
2347 session
->mute
= mute
;
2348 LIST_FOR_EACH_ENTRY(client
, &This
->session
->clients
, ACImpl
, entry
)
2349 set_stream_volumes(client
);
2355 static HRESULT WINAPI
SimpleAudioVolume_GetMute(ISimpleAudioVolume
*iface
,
2358 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2359 AudioSession
*session
= This
->session
;
2361 TRACE("(%p)->(%p)\n", session
, mute
);
2364 return NULL_PTR_ERR
;
2366 *mute
= session
->mute
;
2371 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl
=
2373 SimpleAudioVolume_QueryInterface
,
2374 SimpleAudioVolume_AddRef
,
2375 SimpleAudioVolume_Release
,
2376 SimpleAudioVolume_SetMasterVolume
,
2377 SimpleAudioVolume_GetMasterVolume
,
2378 SimpleAudioVolume_SetMute
,
2379 SimpleAudioVolume_GetMute
2382 static HRESULT WINAPI
ChannelAudioVolume_QueryInterface(
2383 IChannelAudioVolume
*iface
, REFIID riid
, void **ppv
)
2385 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
2391 if (IsEqualIID(riid
, &IID_IUnknown
) ||
2392 IsEqualIID(riid
, &IID_IChannelAudioVolume
))
2395 IUnknown_AddRef((IUnknown
*)*ppv
);
2399 WARN("Unknown interface %s\n", debugstr_guid(riid
));
2400 return E_NOINTERFACE
;
2403 static ULONG WINAPI
ChannelAudioVolume_AddRef(IChannelAudioVolume
*iface
)
2405 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2406 return AudioSessionControl_AddRef(&This
->IAudioSessionControl2_iface
);
2409 static ULONG WINAPI
ChannelAudioVolume_Release(IChannelAudioVolume
*iface
)
2411 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2412 return AudioSessionControl_Release(&This
->IAudioSessionControl2_iface
);
2415 static HRESULT WINAPI
ChannelAudioVolume_GetChannelCount(
2416 IChannelAudioVolume
*iface
, UINT32
*out
)
2418 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2419 AudioSession
*session
= This
->session
;
2421 TRACE("(%p)->(%p)\n", session
, out
);
2424 return NULL_PTR_ERR
;
2426 *out
= session
->channel_count
;
2431 static HRESULT WINAPI
ChannelAudioVolume_SetChannelVolume(
2432 IChannelAudioVolume
*iface
, UINT32 index
, float level
,
2433 const GUID
*context
)
2435 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2436 AudioSession
*session
= This
->session
;
2439 TRACE("(%p)->(%d, %f, %s)\n", session
, index
, level
,
2440 wine_dbgstr_guid(context
));
2442 if (level
< 0.f
|| level
> 1.f
)
2443 return E_INVALIDARG
;
2445 if (index
>= session
->channel_count
)
2446 return E_INVALIDARG
;
2449 FIXME("Notifications not supported yet\n");
2451 TRACE("PulseAudio does not support session volume control\n");
2454 session
->channel_vols
[index
] = level
;
2455 LIST_FOR_EACH_ENTRY(client
, &This
->session
->clients
, ACImpl
, entry
)
2456 set_stream_volumes(client
);
2462 static HRESULT WINAPI
ChannelAudioVolume_GetChannelVolume(
2463 IChannelAudioVolume
*iface
, UINT32 index
, float *level
)
2465 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2466 AudioSession
*session
= This
->session
;
2468 TRACE("(%p)->(%d, %p)\n", session
, index
, level
);
2471 return NULL_PTR_ERR
;
2473 if (index
>= session
->channel_count
)
2474 return E_INVALIDARG
;
2476 *level
= session
->channel_vols
[index
];
2481 static HRESULT WINAPI
ChannelAudioVolume_SetAllVolumes(
2482 IChannelAudioVolume
*iface
, UINT32 count
, const float *levels
,
2483 const GUID
*context
)
2485 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2486 AudioSession
*session
= This
->session
;
2490 TRACE("(%p)->(%d, %p, %s)\n", session
, count
, levels
,
2491 wine_dbgstr_guid(context
));
2494 return NULL_PTR_ERR
;
2496 if (count
!= session
->channel_count
)
2497 return E_INVALIDARG
;
2500 FIXME("Notifications not supported yet\n");
2502 TRACE("PulseAudio does not support session volume control\n");
2505 for(i
= 0; i
< count
; ++i
)
2506 session
->channel_vols
[i
] = levels
[i
];
2507 LIST_FOR_EACH_ENTRY(client
, &This
->session
->clients
, ACImpl
, entry
)
2508 set_stream_volumes(client
);
2513 static HRESULT WINAPI
ChannelAudioVolume_GetAllVolumes(
2514 IChannelAudioVolume
*iface
, UINT32 count
, float *levels
)
2516 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2517 AudioSession
*session
= This
->session
;
2520 TRACE("(%p)->(%d, %p)\n", session
, count
, levels
);
2523 return NULL_PTR_ERR
;
2525 if (count
!= session
->channel_count
)
2526 return E_INVALIDARG
;
2528 for(i
= 0; i
< count
; ++i
)
2529 levels
[i
] = session
->channel_vols
[i
];
2534 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl
=
2536 ChannelAudioVolume_QueryInterface
,
2537 ChannelAudioVolume_AddRef
,
2538 ChannelAudioVolume_Release
,
2539 ChannelAudioVolume_GetChannelCount
,
2540 ChannelAudioVolume_SetChannelVolume
,
2541 ChannelAudioVolume_GetChannelVolume
,
2542 ChannelAudioVolume_SetAllVolumes
,
2543 ChannelAudioVolume_GetAllVolumes
2546 HRESULT WINAPI
AUDDRV_GetAudioSessionManager(IMMDevice
*device
,
2547 IAudioSessionManager2
**out
)
2549 SessionMgr
*This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(SessionMgr
));
2552 return E_OUTOFMEMORY
;
2553 This
->IAudioSessionManager2_iface
.lpVtbl
= &AudioSessionManager2_Vtbl
;
2554 This
->device
= device
;
2556 *out
= &This
->IAudioSessionManager2_iface
;
2560 HRESULT WINAPI
AUDDRV_GetPropValue(GUID
*guid
, const PROPERTYKEY
*prop
, PROPVARIANT
*out
)
2562 TRACE("%s, (%s,%u), %p\n", wine_dbgstr_guid(guid
), wine_dbgstr_guid(&prop
->fmtid
), prop
->pid
, out
);
2564 if (IsEqualGUID(guid
, &pulse_render_guid
) && IsEqualPropertyKey(*prop
, PKEY_AudioEndpoint_PhysicalSpeakers
)) {
2566 out
->ulVal
= pulse_config
.speakers_mask
;
2568 return out
->ulVal
? S_OK
: E_FAIL
;