winebus.sys: Add missing keyboard free_device callback.
[wine.git] / dlls / winepulse.drv / mmdevdrv.c
blob67a42de97f96278b32988bdad5d168547edbe8f8
1 /*
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 COBJMACROS
23 #include <stdarg.h>
24 #include <assert.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winternl.h"
29 #include "wine/debug.h"
30 #include "wine/list.h"
32 #include "ole2.h"
33 #include "dshow.h"
34 #include "dsound.h"
35 #include "propsys.h"
37 #include "initguid.h"
38 #include "ks.h"
39 #include "ksmedia.h"
40 #include "propkey.h"
41 #include "mmdeviceapi.h"
42 #include "audioclient.h"
43 #include "endpointvolume.h"
44 #include "audiopolicy.h"
46 #include "unixlib.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(pulse);
50 static UINT64 pulse_handle;
52 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
54 /* From <dlls/mmdevapi/mmdevapi.h> */
55 enum DriverPriority {
56 Priority_Unavailable = 0,
57 Priority_Low,
58 Priority_Neutral,
59 Priority_Preferred
62 static struct pulse_config pulse_config;
64 static HANDLE pulse_thread;
65 static struct list g_sessions = LIST_INIT(g_sessions);
67 static GUID pulse_render_guid =
68 { 0xfd47d9cc, 0x4218, 0x4135, { 0x9c, 0xe2, 0x0c, 0x19, 0x5c, 0x87, 0x40, 0x5b } };
69 static GUID pulse_capture_guid =
70 { 0x25da76d0, 0x033c, 0x4235, { 0x90, 0x02, 0x19, 0xf4, 0x88, 0x94, 0xac, 0x6f } };
72 static CRITICAL_SECTION session_cs;
73 static CRITICAL_SECTION_DEBUG session_cs_debug = {
74 0, 0, &session_cs,
75 { &session_cs_debug.ProcessLocksList,
76 &session_cs_debug.ProcessLocksList },
77 0, 0, { (DWORD_PTR)(__FILE__ ": session_cs") }
79 static CRITICAL_SECTION session_cs = { &session_cs_debug, -1, 0, 0, 0, 0 };
81 BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
83 if (reason == DLL_PROCESS_ATTACH) {
84 DisableThreadLibraryCalls(dll);
85 if (__wine_init_unix_lib(dll, reason, NULL, &pulse_handle))
86 return FALSE;
87 } else if (reason == DLL_PROCESS_DETACH) {
88 __wine_init_unix_lib(dll, reason, NULL, NULL);
89 if (pulse_thread) {
90 WaitForSingleObject(pulse_thread, INFINITE);
91 CloseHandle(pulse_thread);
94 return TRUE;
97 typedef struct ACImpl ACImpl;
99 typedef struct _AudioSession {
100 GUID guid;
101 struct list clients;
103 IMMDevice *device;
105 float master_vol;
106 UINT32 channel_count;
107 float *channel_vols;
108 BOOL mute;
110 struct list entry;
111 } AudioSession;
113 typedef struct _AudioSessionWrapper {
114 IAudioSessionControl2 IAudioSessionControl2_iface;
115 IChannelAudioVolume IChannelAudioVolume_iface;
116 ISimpleAudioVolume ISimpleAudioVolume_iface;
118 LONG ref;
120 ACImpl *client;
121 AudioSession *session;
122 } AudioSessionWrapper;
124 struct ACImpl {
125 IAudioClient3 IAudioClient3_iface;
126 IAudioRenderClient IAudioRenderClient_iface;
127 IAudioCaptureClient IAudioCaptureClient_iface;
128 IAudioClock IAudioClock_iface;
129 IAudioClock2 IAudioClock2_iface;
130 IAudioStreamVolume IAudioStreamVolume_iface;
131 IUnknown *marshal;
132 IMMDevice *parent;
133 struct list entry;
134 float *vol;
136 LONG ref;
137 EDataFlow dataflow;
138 UINT32 channel_count;
139 HANDLE timer;
141 struct pulse_stream *pulse_stream;
143 AudioSession *session;
144 AudioSessionWrapper *session_wrapper;
147 static const WCHAR defaultW[] = L"Pulseaudio";
149 static const IAudioClient3Vtbl AudioClient3_Vtbl;
150 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
151 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
152 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
153 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
154 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
155 static const IAudioClockVtbl AudioClock_Vtbl;
156 static const IAudioClock2Vtbl AudioClock2_Vtbl;
157 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
159 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
161 static inline ACImpl *impl_from_IAudioClient3(IAudioClient3 *iface)
163 return CONTAINING_RECORD(iface, ACImpl, IAudioClient3_iface);
166 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
168 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
171 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
173 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
176 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
178 return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
181 static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
183 return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
186 static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
188 return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
191 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
193 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
196 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
198 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
201 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
203 return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
206 static void pulse_call(enum unix_funcs code, void *params)
208 NTSTATUS status;
209 status = __wine_unix_call(pulse_handle, code, params);
210 assert(!status);
213 static void pulse_release_stream(struct pulse_stream *stream, HANDLE timer)
215 struct release_stream_params params;
216 params.stream = stream;
217 params.timer = timer;
218 pulse_call(release_stream, &params);
221 static DWORD CALLBACK pulse_mainloop_thread(void *event)
223 struct main_loop_params params;
224 params.event = event;
225 pulse_call(main_loop, &params);
226 return 0;
229 static char *get_application_name(void)
231 WCHAR path[MAX_PATH], *name;
232 size_t len;
233 char *str;
235 GetModuleFileNameW(NULL, path, ARRAY_SIZE(path));
236 name = wcsrchr(path, '\\');
237 if (!name)
238 name = path;
239 else
240 name++;
241 len = WideCharToMultiByte(CP_UTF8, 0, name, -1, NULL, 0, NULL, NULL);
242 if (!(str = malloc(len)))
243 return NULL;
244 WideCharToMultiByte(CP_UNIXCP, 0, name, -1, str, len, NULL, NULL);
245 return str;
248 static DWORD WINAPI pulse_timer_cb(void *user)
250 struct timer_loop_params params;
251 ACImpl *This = user;
252 params.stream = This->pulse_stream;
253 pulse_call(timer_loop, &params);
254 return 0;
257 static void set_stream_volumes(ACImpl *This)
259 struct set_volumes_params params;
260 params.stream = This->pulse_stream;
261 params.master_volume = This->session->mute ? 0.0f : This->session->master_vol;
262 params.volumes = This->vol;
263 params.session_volumes = This->session->channel_vols;
264 pulse_call(set_volumes, &params);
267 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, const WCHAR ***ids, GUID **keys,
268 UINT *num, UINT *def_index)
270 WCHAR *id;
272 TRACE("%d %p %p %p\n", flow, ids, num, def_index);
274 *num = 1;
275 *def_index = 0;
277 *ids = HeapAlloc(GetProcessHeap(), 0, sizeof(**ids));
278 *keys = NULL;
279 if (!*ids)
280 return E_OUTOFMEMORY;
282 (*ids)[0] = id = HeapAlloc(GetProcessHeap(), 0, sizeof(defaultW));
283 *keys = HeapAlloc(GetProcessHeap(), 0, sizeof(**keys));
284 if (!*keys || !id) {
285 HeapFree(GetProcessHeap(), 0, id);
286 HeapFree(GetProcessHeap(), 0, *keys);
287 HeapFree(GetProcessHeap(), 0, *ids);
288 *ids = NULL;
289 *keys = NULL;
290 return E_OUTOFMEMORY;
292 memcpy(id, defaultW, sizeof(defaultW));
294 if (flow == eRender)
295 (*keys)[0] = pulse_render_guid;
296 else
297 (*keys)[0] = pulse_capture_guid;
299 return S_OK;
302 int WINAPI AUDDRV_GetPriority(void)
304 struct test_connect_params params;
305 char *name;
307 params.name = name = get_application_name();
308 params.config = &pulse_config;
309 pulse_call(test_connect, &params);
310 free(name);
311 return SUCCEEDED(params.result) ? Priority_Preferred : Priority_Unavailable;
314 HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient **out)
316 ACImpl *This;
317 EDataFlow dataflow;
318 HRESULT hr;
320 TRACE("%s %p %p\n", debugstr_guid(guid), dev, out);
321 if (IsEqualGUID(guid, &pulse_render_guid))
322 dataflow = eRender;
323 else if (IsEqualGUID(guid, &pulse_capture_guid))
324 dataflow = eCapture;
325 else
326 return E_UNEXPECTED;
328 *out = NULL;
330 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
331 if (!This)
332 return E_OUTOFMEMORY;
334 This->IAudioClient3_iface.lpVtbl = &AudioClient3_Vtbl;
335 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
336 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
337 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
338 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
339 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
340 This->dataflow = dataflow;
341 This->parent = dev;
343 hr = CoCreateFreeThreadedMarshaler((IUnknown*)&This->IAudioClient3_iface, &This->marshal);
344 if (hr) {
345 HeapFree(GetProcessHeap(), 0, This);
346 return hr;
348 IMMDevice_AddRef(This->parent);
350 *out = (IAudioClient *)&This->IAudioClient3_iface;
351 IAudioClient3_AddRef(&This->IAudioClient3_iface);
353 return S_OK;
356 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient3 *iface,
357 REFIID riid, void **ppv)
359 ACImpl *This = impl_from_IAudioClient3(iface);
361 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
363 if (!ppv)
364 return E_POINTER;
366 *ppv = NULL;
367 if (IsEqualIID(riid, &IID_IUnknown) ||
368 IsEqualIID(riid, &IID_IAudioClient) ||
369 IsEqualIID(riid, &IID_IAudioClient2) ||
370 IsEqualIID(riid, &IID_IAudioClient3))
371 *ppv = iface;
372 if (*ppv) {
373 IUnknown_AddRef((IUnknown*)*ppv);
374 return S_OK;
377 if (IsEqualIID(riid, &IID_IMarshal))
378 return IUnknown_QueryInterface(This->marshal, riid, ppv);
380 WARN("Unknown interface %s\n", debugstr_guid(riid));
381 return E_NOINTERFACE;
384 static ULONG WINAPI AudioClient_AddRef(IAudioClient3 *iface)
386 ACImpl *This = impl_from_IAudioClient3(iface);
387 ULONG ref;
388 ref = InterlockedIncrement(&This->ref);
389 TRACE("(%p) Refcount now %u\n", This, ref);
390 return ref;
393 static ULONG WINAPI AudioClient_Release(IAudioClient3 *iface)
395 ACImpl *This = impl_from_IAudioClient3(iface);
396 ULONG ref;
397 ref = InterlockedDecrement(&This->ref);
398 TRACE("(%p) Refcount now %u\n", This, ref);
399 if (!ref) {
400 if (This->pulse_stream) {
401 pulse_release_stream(This->pulse_stream, This->timer);
402 This->pulse_stream = NULL;
403 EnterCriticalSection(&session_cs);
404 list_remove(&This->entry);
405 LeaveCriticalSection(&session_cs);
407 IUnknown_Release(This->marshal);
408 IMMDevice_Release(This->parent);
409 HeapFree(GetProcessHeap(), 0, This);
411 return ref;
414 static void dump_fmt(const WAVEFORMATEX *fmt)
416 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
417 switch(fmt->wFormatTag) {
418 case WAVE_FORMAT_PCM:
419 TRACE("WAVE_FORMAT_PCM");
420 break;
421 case WAVE_FORMAT_IEEE_FLOAT:
422 TRACE("WAVE_FORMAT_IEEE_FLOAT");
423 break;
424 case WAVE_FORMAT_EXTENSIBLE:
425 TRACE("WAVE_FORMAT_EXTENSIBLE");
426 break;
427 default:
428 TRACE("Unknown");
429 break;
431 TRACE(")\n");
433 TRACE("nChannels: %u\n", fmt->nChannels);
434 TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
435 TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
436 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
437 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
438 TRACE("cbSize: %u\n", fmt->cbSize);
440 if (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
441 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
442 TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
443 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
444 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
448 static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
450 WAVEFORMATEX *ret;
451 size_t size;
453 if (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
454 size = sizeof(WAVEFORMATEXTENSIBLE);
455 else
456 size = sizeof(WAVEFORMATEX);
458 ret = CoTaskMemAlloc(size);
459 if (!ret)
460 return NULL;
462 memcpy(ret, fmt, size);
464 ret->cbSize = size - sizeof(WAVEFORMATEX);
466 return ret;
469 static void session_init_vols(AudioSession *session, UINT channels)
471 if (session->channel_count < channels) {
472 UINT i;
474 if (session->channel_vols)
475 session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
476 session->channel_vols, sizeof(float) * channels);
477 else
478 session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
479 sizeof(float) * channels);
480 if (!session->channel_vols)
481 return;
483 for(i = session->channel_count; i < channels; ++i)
484 session->channel_vols[i] = 1.f;
486 session->channel_count = channels;
490 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
491 UINT num_channels)
493 AudioSession *ret;
495 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
496 if (!ret)
497 return NULL;
499 memcpy(&ret->guid, guid, sizeof(GUID));
501 ret->device = device;
503 list_init(&ret->clients);
505 list_add_head(&g_sessions, &ret->entry);
507 session_init_vols(ret, num_channels);
509 ret->master_vol = 1.f;
511 return ret;
514 /* if channels == 0, then this will return or create a session with
515 * matching dataflow and GUID. otherwise, channels must also match */
516 static HRESULT get_audio_session(const GUID *sessionguid,
517 IMMDevice *device, UINT channels, AudioSession **out)
519 AudioSession *session;
521 if (!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)) {
522 *out = create_session(&GUID_NULL, device, channels);
523 if (!*out)
524 return E_OUTOFMEMORY;
526 return S_OK;
529 *out = NULL;
530 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry) {
531 if (session->device == device &&
532 IsEqualGUID(sessionguid, &session->guid)) {
533 session_init_vols(session, channels);
534 *out = session;
535 break;
539 if (!*out) {
540 *out = create_session(sessionguid, device, channels);
541 if (!*out)
542 return E_OUTOFMEMORY;
545 return S_OK;
548 static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
549 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
550 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
551 const GUID *sessionguid)
553 ACImpl *This = impl_from_IAudioClient3(iface);
554 struct create_stream_params params;
555 unsigned int i, channel_count;
556 struct pulse_stream *stream;
557 char *name;
558 HRESULT hr;
560 TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
561 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
563 if (!fmt)
564 return E_POINTER;
565 dump_fmt(fmt);
567 if (mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
568 return E_INVALIDARG;
569 if (mode == AUDCLNT_SHAREMODE_EXCLUSIVE)
570 return AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED;
572 if (flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
573 AUDCLNT_STREAMFLAGS_LOOPBACK |
574 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
575 AUDCLNT_STREAMFLAGS_NOPERSIST |
576 AUDCLNT_STREAMFLAGS_RATEADJUST |
577 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
578 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
579 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED |
580 AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY |
581 AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM)) {
582 FIXME("Unknown flags: %08x\n", flags);
583 return E_INVALIDARG;
586 EnterCriticalSection(&session_cs);
588 if (This->pulse_stream) {
589 LeaveCriticalSection(&session_cs);
590 return AUDCLNT_E_ALREADY_INITIALIZED;
593 if (!pulse_thread)
595 HANDLE event = CreateEventW(NULL, TRUE, FALSE, NULL);
596 if (!(pulse_thread = CreateThread(NULL, 0, pulse_mainloop_thread, event, 0, NULL)))
598 ERR("Failed to create mainloop thread.\n");
599 LeaveCriticalSection(&session_cs);
600 CloseHandle(event);
601 return E_FAIL;
603 SetThreadPriority(pulse_thread, THREAD_PRIORITY_TIME_CRITICAL);
604 WaitForSingleObject(event, INFINITE);
605 CloseHandle(event);
608 params.name = name = get_application_name();
609 params.dataflow = This->dataflow;
610 params.mode = mode;
611 params.flags = flags;
612 params.duration = duration;
613 params.fmt = fmt;
614 params.stream = &stream;
615 params.channel_count = &channel_count;
616 pulse_call(create_stream, &params);
617 free(name);
618 if (FAILED(hr = params.result))
620 LeaveCriticalSection(&session_cs);
621 return hr;
624 if (!(This->vol = malloc(channel_count * sizeof(*This->vol))))
626 pulse_release_stream(stream, NULL);
627 LeaveCriticalSection(&session_cs);
628 return E_OUTOFMEMORY;
630 for (i = 0; i < channel_count; i++)
631 This->vol[i] = 1.f;
633 hr = get_audio_session(sessionguid, This->parent, channel_count, &This->session);
634 if (FAILED(hr))
636 free(This->vol);
637 This->vol = NULL;
638 LeaveCriticalSection(&session_cs);
639 pulse_release_stream(stream, NULL);
640 return E_OUTOFMEMORY;
643 This->pulse_stream = stream;
644 This->channel_count = channel_count;
645 list_add_tail(&This->session->clients, &This->entry);
646 set_stream_volumes(This);
648 LeaveCriticalSection(&session_cs);
649 return S_OK;
652 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient3 *iface,
653 UINT32 *out)
655 ACImpl *This = impl_from_IAudioClient3(iface);
656 struct get_buffer_size_params params;
658 TRACE("(%p)->(%p)\n", This, out);
660 if (!out)
661 return E_POINTER;
662 if (!This->pulse_stream)
663 return AUDCLNT_E_NOT_INITIALIZED;
665 params.stream = This->pulse_stream;
666 params.size = out;
667 pulse_call(get_buffer_size, &params);
668 return params.result;
671 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient3 *iface,
672 REFERENCE_TIME *latency)
674 ACImpl *This = impl_from_IAudioClient3(iface);
675 struct get_latency_params params;
677 TRACE("(%p)->(%p)\n", This, latency);
679 if (!latency)
680 return E_POINTER;
681 if (!This->pulse_stream)
682 return AUDCLNT_E_NOT_INITIALIZED;
684 params.stream = This->pulse_stream;
685 params.latency = latency;
686 pulse_call(get_latency, &params);
687 return params.result;
690 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient3 *iface,
691 UINT32 *out)
693 ACImpl *This = impl_from_IAudioClient3(iface);
694 struct get_current_padding_params params;
696 TRACE("(%p)->(%p)\n", This, out);
698 if (!out)
699 return E_POINTER;
700 if (!This->pulse_stream)
701 return AUDCLNT_E_NOT_INITIALIZED;
703 params.stream = This->pulse_stream;
704 params.padding = out;
705 pulse_call(get_current_padding, &params);
706 return params.result;
709 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient3 *iface,
710 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *fmt,
711 WAVEFORMATEX **out)
713 ACImpl *This = impl_from_IAudioClient3(iface);
714 HRESULT hr = S_OK;
715 WAVEFORMATEX *closest = NULL;
716 BOOL exclusive;
718 TRACE("(%p)->(%x, %p, %p)\n", This, mode, fmt, out);
720 if (!fmt)
721 return E_POINTER;
723 if (out)
724 *out = NULL;
726 if (mode == AUDCLNT_SHAREMODE_EXCLUSIVE) {
727 exclusive = 1;
728 out = NULL;
729 } else if (mode == AUDCLNT_SHAREMODE_SHARED) {
730 exclusive = 0;
731 if (!out)
732 return E_POINTER;
733 } else
734 return E_INVALIDARG;
736 if (fmt->nChannels == 0)
737 return AUDCLNT_E_UNSUPPORTED_FORMAT;
739 closest = clone_format(fmt);
740 if (!closest)
741 return E_OUTOFMEMORY;
743 dump_fmt(fmt);
745 switch (fmt->wFormatTag) {
746 case WAVE_FORMAT_EXTENSIBLE: {
747 WAVEFORMATEXTENSIBLE *ext = (WAVEFORMATEXTENSIBLE*)closest;
749 if ((fmt->cbSize != sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) &&
750 fmt->cbSize != sizeof(WAVEFORMATEXTENSIBLE)) ||
751 fmt->nBlockAlign != fmt->wBitsPerSample / 8 * fmt->nChannels ||
752 ext->Samples.wValidBitsPerSample > fmt->wBitsPerSample ||
753 fmt->nAvgBytesPerSec != fmt->nBlockAlign * fmt->nSamplesPerSec) {
754 hr = E_INVALIDARG;
755 break;
758 if (exclusive) {
759 UINT32 mask = 0, i, channels = 0;
761 if (!(ext->dwChannelMask & (SPEAKER_ALL | SPEAKER_RESERVED))) {
762 for (i = 1; !(i & SPEAKER_RESERVED); i <<= 1) {
763 if (i & ext->dwChannelMask) {
764 mask |= i;
765 channels++;
769 if (channels != fmt->nChannels || (ext->dwChannelMask & ~mask)) {
770 hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
771 break;
773 } else {
774 hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
775 break;
779 if (IsEqualGUID(&ext->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) {
780 if (fmt->wBitsPerSample != 32) {
781 hr = E_INVALIDARG;
782 break;
785 if (ext->Samples.wValidBitsPerSample != fmt->wBitsPerSample) {
786 hr = S_FALSE;
787 ext->Samples.wValidBitsPerSample = fmt->wBitsPerSample;
789 } else if (IsEqualGUID(&ext->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) {
790 if (!fmt->wBitsPerSample || fmt->wBitsPerSample > 32 || fmt->wBitsPerSample % 8) {
791 hr = E_INVALIDARG;
792 break;
795 if (ext->Samples.wValidBitsPerSample != fmt->wBitsPerSample &&
796 !(fmt->wBitsPerSample == 32 &&
797 ext->Samples.wValidBitsPerSample == 24)) {
798 hr = S_FALSE;
799 ext->Samples.wValidBitsPerSample = fmt->wBitsPerSample;
800 break;
802 } else {
803 hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
804 break;
807 break;
810 case WAVE_FORMAT_ALAW:
811 case WAVE_FORMAT_MULAW:
812 if (fmt->wBitsPerSample != 8) {
813 hr = E_INVALIDARG;
814 break;
816 /* Fall-through */
817 case WAVE_FORMAT_IEEE_FLOAT:
818 if (fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT && fmt->wBitsPerSample != 32) {
819 hr = E_INVALIDARG;
820 break;
822 /* Fall-through */
823 case WAVE_FORMAT_PCM:
824 if (fmt->wFormatTag == WAVE_FORMAT_PCM &&
825 (!fmt->wBitsPerSample || fmt->wBitsPerSample > 32 || fmt->wBitsPerSample % 8)) {
826 hr = E_INVALIDARG;
827 break;
830 if (fmt->nChannels > 2) {
831 hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
832 break;
835 * fmt->cbSize, fmt->nBlockAlign and fmt->nAvgBytesPerSec seem to be
836 * ignored, invalid values are happily accepted.
838 break;
839 default:
840 hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
841 break;
844 if (exclusive && hr != S_OK) {
845 hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
846 CoTaskMemFree(closest);
847 } else if (hr != S_FALSE)
848 CoTaskMemFree(closest);
849 else
850 *out = closest;
852 /* Winepulse does not currently support exclusive mode, if you know of an
853 * application that uses it, I will correct this..
855 if (hr == S_OK && exclusive)
856 return This->dataflow == eCapture ? AUDCLNT_E_UNSUPPORTED_FORMAT : AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED;
858 TRACE("returning: %08x %p\n", hr, out ? *out : NULL);
859 return hr;
862 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface,
863 WAVEFORMATEX **pwfx)
865 ACImpl *This = impl_from_IAudioClient3(iface);
867 TRACE("(%p)->(%p)\n", This, pwfx);
869 if (!pwfx)
870 return E_POINTER;
872 *pwfx = clone_format(&pulse_config.modes[This->dataflow == eCapture].format.Format);
873 if (!*pwfx)
874 return E_OUTOFMEMORY;
875 dump_fmt(*pwfx);
876 return S_OK;
879 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient3 *iface,
880 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
882 ACImpl *This = impl_from_IAudioClient3(iface);
884 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
886 if (!defperiod && !minperiod)
887 return E_POINTER;
889 if (defperiod)
890 *defperiod = pulse_config.modes[This->dataflow == eCapture].def_period;
891 if (minperiod)
892 *minperiod = pulse_config.modes[This->dataflow == eCapture].min_period;
894 return S_OK;
897 static HRESULT WINAPI AudioClient_Start(IAudioClient3 *iface)
899 ACImpl *This = impl_from_IAudioClient3(iface);
900 struct start_params params;
901 HRESULT hr;
903 TRACE("(%p)\n", This);
905 if (!This->pulse_stream)
906 return AUDCLNT_E_NOT_INITIALIZED;
908 params.stream = This->pulse_stream;
909 pulse_call(start, &params);
910 if (FAILED(hr = params.result))
911 return hr;
913 if (!This->timer) {
914 This->timer = CreateThread(NULL, 0, pulse_timer_cb, This, 0, NULL);
915 SetThreadPriority(This->timer, THREAD_PRIORITY_TIME_CRITICAL);
918 return S_OK;
921 static HRESULT WINAPI AudioClient_Stop(IAudioClient3 *iface)
923 ACImpl *This = impl_from_IAudioClient3(iface);
924 struct stop_params params;
926 TRACE("(%p)\n", This);
928 if (!This->pulse_stream)
929 return AUDCLNT_E_NOT_INITIALIZED;
931 params.stream = This->pulse_stream;
932 pulse_call(stop, &params);
933 return params.result;
936 static HRESULT WINAPI AudioClient_Reset(IAudioClient3 *iface)
938 ACImpl *This = impl_from_IAudioClient3(iface);
939 struct reset_params params;
941 TRACE("(%p)\n", This);
943 if (!This->pulse_stream)
944 return AUDCLNT_E_NOT_INITIALIZED;
946 params.stream = This->pulse_stream;
947 pulse_call(reset, &params);
948 return params.result;
951 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient3 *iface,
952 HANDLE event)
954 ACImpl *This = impl_from_IAudioClient3(iface);
955 struct set_event_handle_params params;
957 TRACE("(%p)->(%p)\n", This, event);
959 if (!event)
960 return E_INVALIDARG;
961 if (!This->pulse_stream)
962 return AUDCLNT_E_NOT_INITIALIZED;
964 params.stream = This->pulse_stream;
965 params.event = event;
966 pulse_call(set_event_handle, &params);
967 return params.result;
970 static HRESULT WINAPI AudioClient_GetService(IAudioClient3 *iface, REFIID riid,
971 void **ppv)
973 ACImpl *This = impl_from_IAudioClient3(iface);
975 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
977 if (!ppv)
978 return E_POINTER;
979 *ppv = NULL;
981 if (!This->pulse_stream)
982 return AUDCLNT_E_NOT_INITIALIZED;
984 if (IsEqualIID(riid, &IID_IAudioRenderClient)) {
985 if (This->dataflow != eRender)
986 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
987 *ppv = &This->IAudioRenderClient_iface;
988 } else if (IsEqualIID(riid, &IID_IAudioCaptureClient)) {
989 if (This->dataflow != eCapture)
990 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
991 *ppv = &This->IAudioCaptureClient_iface;
992 } else if (IsEqualIID(riid, &IID_IAudioClock)) {
993 *ppv = &This->IAudioClock_iface;
994 } else if (IsEqualIID(riid, &IID_IAudioStreamVolume)) {
995 *ppv = &This->IAudioStreamVolume_iface;
996 } else if (IsEqualIID(riid, &IID_IAudioSessionControl) ||
997 IsEqualIID(riid, &IID_IChannelAudioVolume) ||
998 IsEqualIID(riid, &IID_ISimpleAudioVolume)) {
999 if (!This->session_wrapper) {
1000 This->session_wrapper = AudioSessionWrapper_Create(This);
1001 if (!This->session_wrapper)
1002 return E_OUTOFMEMORY;
1004 if (IsEqualIID(riid, &IID_IAudioSessionControl))
1005 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1006 else if (IsEqualIID(riid, &IID_IChannelAudioVolume))
1007 *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1008 else if (IsEqualIID(riid, &IID_ISimpleAudioVolume))
1009 *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1012 if (*ppv) {
1013 IUnknown_AddRef((IUnknown*)*ppv);
1014 return S_OK;
1017 FIXME("stub %s\n", debugstr_guid(riid));
1018 return E_NOINTERFACE;
1021 static HRESULT WINAPI AudioClient_IsOffloadCapable(IAudioClient3 *iface,
1022 AUDIO_STREAM_CATEGORY category, BOOL *offload_capable)
1024 ACImpl *This = impl_from_IAudioClient3(iface);
1026 TRACE("(%p)->(0x%x, %p)\n", This, category, offload_capable);
1028 if(!offload_capable)
1029 return E_INVALIDARG;
1031 *offload_capable = FALSE;
1033 return S_OK;
1036 static HRESULT WINAPI AudioClient_SetClientProperties(IAudioClient3 *iface,
1037 const AudioClientProperties *prop)
1039 ACImpl *This = impl_from_IAudioClient3(iface);
1040 const Win8AudioClientProperties *legacy_prop = (const Win8AudioClientProperties *)prop;
1042 TRACE("(%p)->(%p)\n", This, prop);
1044 if(!legacy_prop)
1045 return E_POINTER;
1047 if(legacy_prop->cbSize == sizeof(AudioClientProperties)){
1048 TRACE("{ bIsOffload: %u, eCategory: 0x%x, Options: 0x%x }\n",
1049 legacy_prop->bIsOffload,
1050 legacy_prop->eCategory,
1051 prop->Options);
1052 }else if(legacy_prop->cbSize == sizeof(Win8AudioClientProperties)){
1053 TRACE("{ bIsOffload: %u, eCategory: 0x%x }\n",
1054 legacy_prop->bIsOffload,
1055 legacy_prop->eCategory);
1056 }else{
1057 WARN("Unsupported Size = %d\n", legacy_prop->cbSize);
1058 return E_INVALIDARG;
1062 if(legacy_prop->bIsOffload)
1063 return AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE;
1065 return S_OK;
1068 static HRESULT WINAPI AudioClient_GetBufferSizeLimits(IAudioClient3 *iface,
1069 const WAVEFORMATEX *format, BOOL event_driven, REFERENCE_TIME *min_duration,
1070 REFERENCE_TIME *max_duration)
1072 ACImpl *This = impl_from_IAudioClient3(iface);
1074 FIXME("(%p)->(%p, %u, %p, %p)\n", This, format, event_driven, min_duration, max_duration);
1076 return E_NOTIMPL;
1079 static HRESULT WINAPI AudioClient_GetSharedModeEnginePeriod(IAudioClient3 *iface,
1080 const WAVEFORMATEX *format, UINT32 *default_period_frames, UINT32 *unit_period_frames,
1081 UINT32 *min_period_frames, UINT32 *max_period_frames)
1083 ACImpl *This = impl_from_IAudioClient3(iface);
1085 FIXME("(%p)->(%p, %p, %p, %p, %p)\n", This, format, default_period_frames, unit_period_frames,
1086 min_period_frames, max_period_frames);
1088 return E_NOTIMPL;
1091 static HRESULT WINAPI AudioClient_GetCurrentSharedModeEnginePeriod(IAudioClient3 *iface,
1092 WAVEFORMATEX **cur_format, UINT32 *cur_period_frames)
1094 ACImpl *This = impl_from_IAudioClient3(iface);
1096 FIXME("(%p)->(%p, %p)\n", This, cur_format, cur_period_frames);
1098 return E_NOTIMPL;
1101 static HRESULT WINAPI AudioClient_InitializeSharedAudioStream(IAudioClient3 *iface,
1102 DWORD flags, UINT32 period_frames, const WAVEFORMATEX *format,
1103 const GUID *session_guid)
1105 ACImpl *This = impl_from_IAudioClient3(iface);
1107 FIXME("(%p)->(0x%x, %u, %p, %s)\n", This, flags, period_frames, format, debugstr_guid(session_guid));
1109 return E_NOTIMPL;
1112 static const IAudioClient3Vtbl AudioClient3_Vtbl =
1114 AudioClient_QueryInterface,
1115 AudioClient_AddRef,
1116 AudioClient_Release,
1117 AudioClient_Initialize,
1118 AudioClient_GetBufferSize,
1119 AudioClient_GetStreamLatency,
1120 AudioClient_GetCurrentPadding,
1121 AudioClient_IsFormatSupported,
1122 AudioClient_GetMixFormat,
1123 AudioClient_GetDevicePeriod,
1124 AudioClient_Start,
1125 AudioClient_Stop,
1126 AudioClient_Reset,
1127 AudioClient_SetEventHandle,
1128 AudioClient_GetService,
1129 AudioClient_IsOffloadCapable,
1130 AudioClient_SetClientProperties,
1131 AudioClient_GetBufferSizeLimits,
1132 AudioClient_GetSharedModeEnginePeriod,
1133 AudioClient_GetCurrentSharedModeEnginePeriod,
1134 AudioClient_InitializeSharedAudioStream,
1137 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1138 IAudioRenderClient *iface, REFIID riid, void **ppv)
1140 ACImpl *This = impl_from_IAudioRenderClient(iface);
1141 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1143 if (!ppv)
1144 return E_POINTER;
1145 *ppv = NULL;
1147 if (IsEqualIID(riid, &IID_IUnknown) ||
1148 IsEqualIID(riid, &IID_IAudioRenderClient))
1149 *ppv = iface;
1150 if (*ppv) {
1151 IUnknown_AddRef((IUnknown*)*ppv);
1152 return S_OK;
1155 if (IsEqualIID(riid, &IID_IMarshal))
1156 return IUnknown_QueryInterface(This->marshal, riid, ppv);
1158 WARN("Unknown interface %s\n", debugstr_guid(riid));
1159 return E_NOINTERFACE;
1162 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1164 ACImpl *This = impl_from_IAudioRenderClient(iface);
1165 return AudioClient_AddRef(&This->IAudioClient3_iface);
1168 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1170 ACImpl *This = impl_from_IAudioRenderClient(iface);
1171 return AudioClient_Release(&This->IAudioClient3_iface);
1174 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1175 UINT32 frames, BYTE **data)
1177 ACImpl *This = impl_from_IAudioRenderClient(iface);
1178 struct get_render_buffer_params params;
1180 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1182 if (!data)
1183 return E_POINTER;
1184 if (!This->pulse_stream)
1185 return AUDCLNT_E_NOT_INITIALIZED;
1186 *data = NULL;
1188 params.stream = This->pulse_stream;
1189 params.frames = frames;
1190 params.data = data;
1191 pulse_call(get_render_buffer, &params);
1192 return params.result;
1195 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1196 IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
1198 ACImpl *This = impl_from_IAudioRenderClient(iface);
1199 struct release_render_buffer_params params;
1201 TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
1203 if (!This->pulse_stream)
1204 return AUDCLNT_E_NOT_INITIALIZED;
1206 params.stream = This->pulse_stream;
1207 params.written_frames = written_frames;
1208 params.flags = flags;
1209 pulse_call(release_render_buffer, &params);
1210 return params.result;
1213 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1214 AudioRenderClient_QueryInterface,
1215 AudioRenderClient_AddRef,
1216 AudioRenderClient_Release,
1217 AudioRenderClient_GetBuffer,
1218 AudioRenderClient_ReleaseBuffer
1221 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1222 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1224 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1225 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1227 if (!ppv)
1228 return E_POINTER;
1229 *ppv = NULL;
1231 if (IsEqualIID(riid, &IID_IUnknown) ||
1232 IsEqualIID(riid, &IID_IAudioCaptureClient))
1233 *ppv = iface;
1234 if (*ppv) {
1235 IUnknown_AddRef((IUnknown*)*ppv);
1236 return S_OK;
1239 if (IsEqualIID(riid, &IID_IMarshal))
1240 return IUnknown_QueryInterface(This->marshal, riid, ppv);
1242 WARN("Unknown interface %s\n", debugstr_guid(riid));
1243 return E_NOINTERFACE;
1246 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1248 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1249 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1252 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1254 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1255 return IAudioClient3_Release(&This->IAudioClient3_iface);
1258 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1259 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1260 UINT64 *qpcpos)
1262 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1263 struct get_capture_buffer_params params;
1265 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1266 devpos, qpcpos);
1268 if (!data)
1269 return E_POINTER;
1270 *data = NULL;
1271 if (!frames || !flags)
1272 return E_POINTER;
1273 if (!This->pulse_stream)
1274 return AUDCLNT_E_NOT_INITIALIZED;
1276 params.stream = This->pulse_stream;
1277 params.data = data;
1278 params.frames = frames;
1279 params.flags = flags;
1280 params.devpos = devpos;
1281 params.qpcpos = qpcpos;
1282 pulse_call(get_capture_buffer, &params);
1283 return params.result;
1286 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1287 IAudioCaptureClient *iface, UINT32 done)
1289 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1290 struct release_capture_buffer_params params;
1292 TRACE("(%p)->(%u)\n", This, done);
1294 if (!This->pulse_stream)
1295 return AUDCLNT_E_NOT_INITIALIZED;
1297 params.stream = This->pulse_stream;
1298 params.done = done;
1299 pulse_call(release_capture_buffer, &params);
1300 return params.result;
1303 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1304 IAudioCaptureClient *iface, UINT32 *frames)
1306 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1307 struct get_next_packet_size_params params;
1309 TRACE("(%p)->(%p)\n", This, frames);
1311 if (!frames)
1312 return E_POINTER;
1313 if (!This->pulse_stream)
1314 return AUDCLNT_E_NOT_INITIALIZED;
1316 params.stream = This->pulse_stream;
1317 params.frames = frames;
1318 pulse_call(get_next_packet_size, &params);
1319 return params.result;
1322 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1324 AudioCaptureClient_QueryInterface,
1325 AudioCaptureClient_AddRef,
1326 AudioCaptureClient_Release,
1327 AudioCaptureClient_GetBuffer,
1328 AudioCaptureClient_ReleaseBuffer,
1329 AudioCaptureClient_GetNextPacketSize
1332 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1333 REFIID riid, void **ppv)
1335 ACImpl *This = impl_from_IAudioClock(iface);
1337 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1339 if (!ppv)
1340 return E_POINTER;
1341 *ppv = NULL;
1343 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
1344 *ppv = iface;
1345 else if (IsEqualIID(riid, &IID_IAudioClock2))
1346 *ppv = &This->IAudioClock2_iface;
1347 if (*ppv) {
1348 IUnknown_AddRef((IUnknown*)*ppv);
1349 return S_OK;
1352 if (IsEqualIID(riid, &IID_IMarshal))
1353 return IUnknown_QueryInterface(This->marshal, riid, ppv);
1355 WARN("Unknown interface %s\n", debugstr_guid(riid));
1356 return E_NOINTERFACE;
1359 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
1361 ACImpl *This = impl_from_IAudioClock(iface);
1362 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1365 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
1367 ACImpl *This = impl_from_IAudioClock(iface);
1368 return IAudioClient3_Release(&This->IAudioClient3_iface);
1371 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
1373 ACImpl *This = impl_from_IAudioClock(iface);
1374 struct get_frequency_params params;
1376 TRACE("(%p)->(%p)\n", This, freq);
1378 if (!This->pulse_stream)
1379 return AUDCLNT_E_NOT_INITIALIZED;
1381 params.stream = This->pulse_stream;
1382 params.freq = freq;
1383 pulse_call(get_frequency, &params);
1384 return params.result;
1387 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
1388 UINT64 *qpctime)
1390 ACImpl *This = impl_from_IAudioClock(iface);
1391 struct get_position_params params;
1393 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
1395 if (!pos)
1396 return E_POINTER;
1397 if (!This->pulse_stream)
1398 return AUDCLNT_E_NOT_INITIALIZED;
1400 params.stream = This->pulse_stream;
1401 params.device = FALSE;
1402 params.pos = pos;
1403 params.qpctime = qpctime;
1404 pulse_call(get_position, &params);
1405 return params.result;
1408 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
1409 DWORD *chars)
1411 ACImpl *This = impl_from_IAudioClock(iface);
1413 TRACE("(%p)->(%p)\n", This, chars);
1415 if (!chars)
1416 return E_POINTER;
1418 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
1420 return S_OK;
1423 static const IAudioClockVtbl AudioClock_Vtbl =
1425 AudioClock_QueryInterface,
1426 AudioClock_AddRef,
1427 AudioClock_Release,
1428 AudioClock_GetFrequency,
1429 AudioClock_GetPosition,
1430 AudioClock_GetCharacteristics
1433 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
1434 REFIID riid, void **ppv)
1436 ACImpl *This = impl_from_IAudioClock2(iface);
1437 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
1440 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
1442 ACImpl *This = impl_from_IAudioClock2(iface);
1443 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1446 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
1448 ACImpl *This = impl_from_IAudioClock2(iface);
1449 return IAudioClient3_Release(&This->IAudioClient3_iface);
1452 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
1453 UINT64 *pos, UINT64 *qpctime)
1455 ACImpl *This = impl_from_IAudioClock2(iface);
1456 struct get_position_params params;
1458 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
1460 if (!pos)
1461 return E_POINTER;
1462 if (!This->pulse_stream)
1463 return AUDCLNT_E_NOT_INITIALIZED;
1465 params.stream = This->pulse_stream;
1466 params.device = TRUE;
1467 params.pos = pos;
1468 params.qpctime = qpctime;
1469 pulse_call(get_position, &params);
1470 return params.result;
1473 static const IAudioClock2Vtbl AudioClock2_Vtbl =
1475 AudioClock2_QueryInterface,
1476 AudioClock2_AddRef,
1477 AudioClock2_Release,
1478 AudioClock2_GetDevicePosition
1481 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
1482 IAudioStreamVolume *iface, REFIID riid, void **ppv)
1484 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1486 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1488 if (!ppv)
1489 return E_POINTER;
1490 *ppv = NULL;
1492 if (IsEqualIID(riid, &IID_IUnknown) ||
1493 IsEqualIID(riid, &IID_IAudioStreamVolume))
1494 *ppv = iface;
1495 if (*ppv) {
1496 IUnknown_AddRef((IUnknown*)*ppv);
1497 return S_OK;
1500 if (IsEqualIID(riid, &IID_IMarshal))
1501 return IUnknown_QueryInterface(This->marshal, riid, ppv);
1503 WARN("Unknown interface %s\n", debugstr_guid(riid));
1504 return E_NOINTERFACE;
1507 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
1509 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1510 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1513 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
1515 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1516 return IAudioClient3_Release(&This->IAudioClient3_iface);
1519 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
1520 IAudioStreamVolume *iface, UINT32 *out)
1522 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1524 TRACE("(%p)->(%p)\n", This, out);
1526 if (!out)
1527 return E_POINTER;
1529 *out = This->channel_count;
1531 return S_OK;
1534 struct pulse_info_cb_data {
1535 UINT32 n;
1536 float *levels;
1539 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
1540 IAudioStreamVolume *iface, UINT32 count, const float *levels)
1542 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1543 int i;
1545 TRACE("(%p)->(%d, %p)\n", This, count, levels);
1547 if (!levels)
1548 return E_POINTER;
1550 if (!This->pulse_stream)
1551 return AUDCLNT_E_NOT_INITIALIZED;
1552 if (count != This->channel_count)
1553 return E_INVALIDARG;
1555 EnterCriticalSection(&session_cs);
1556 for (i = 0; i < count; ++i)
1557 This->vol[i] = levels[i];
1559 set_stream_volumes(This);
1560 LeaveCriticalSection(&session_cs);
1561 return S_OK;
1564 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
1565 IAudioStreamVolume *iface, UINT32 count, float *levels)
1567 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1568 int i;
1570 TRACE("(%p)->(%d, %p)\n", This, count, levels);
1572 if (!levels)
1573 return E_POINTER;
1575 if (!This->pulse_stream)
1576 return AUDCLNT_E_NOT_INITIALIZED;
1577 if (count != This->channel_count)
1578 return E_INVALIDARG;
1580 EnterCriticalSection(&session_cs);
1581 for (i = 0; i < count; ++i)
1582 levels[i] = This->vol[i];
1583 LeaveCriticalSection(&session_cs);
1584 return S_OK;
1587 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
1588 IAudioStreamVolume *iface, UINT32 index, float level)
1590 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1592 TRACE("(%p)->(%d, %f)\n", This, index, level);
1594 if (level < 0.f || level > 1.f)
1595 return E_INVALIDARG;
1597 if (!This->pulse_stream)
1598 return AUDCLNT_E_NOT_INITIALIZED;
1599 if (index >= This->channel_count)
1600 return E_INVALIDARG;
1602 EnterCriticalSection(&session_cs);
1603 This->vol[index] = level;
1604 set_stream_volumes(This);
1605 LeaveCriticalSection(&session_cs);
1606 return S_OK;
1609 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
1610 IAudioStreamVolume *iface, UINT32 index, float *level)
1612 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1614 TRACE("(%p)->(%d, %p)\n", This, index, level);
1616 if (!level)
1617 return E_POINTER;
1619 if (!This->pulse_stream)
1620 return AUDCLNT_E_NOT_INITIALIZED;
1621 if (index >= This->channel_count)
1622 return E_INVALIDARG;
1624 EnterCriticalSection(&session_cs);
1625 *level = This->vol[index];
1626 LeaveCriticalSection(&session_cs);
1627 return S_OK;
1630 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
1632 AudioStreamVolume_QueryInterface,
1633 AudioStreamVolume_AddRef,
1634 AudioStreamVolume_Release,
1635 AudioStreamVolume_GetChannelCount,
1636 AudioStreamVolume_SetChannelVolume,
1637 AudioStreamVolume_GetChannelVolume,
1638 AudioStreamVolume_SetAllVolumes,
1639 AudioStreamVolume_GetAllVolumes
1642 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
1644 AudioSessionWrapper *ret;
1646 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1647 sizeof(AudioSessionWrapper));
1648 if (!ret)
1649 return NULL;
1651 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
1652 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
1653 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
1655 ret->ref = !client;
1657 ret->client = client;
1658 if (client) {
1659 ret->session = client->session;
1660 AudioClient_AddRef(&client->IAudioClient3_iface);
1663 return ret;
1666 static HRESULT WINAPI AudioSessionControl_QueryInterface(
1667 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
1669 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1671 if (!ppv)
1672 return E_POINTER;
1673 *ppv = NULL;
1675 if (IsEqualIID(riid, &IID_IUnknown) ||
1676 IsEqualIID(riid, &IID_IAudioSessionControl) ||
1677 IsEqualIID(riid, &IID_IAudioSessionControl2))
1678 *ppv = iface;
1679 if (*ppv) {
1680 IUnknown_AddRef((IUnknown*)*ppv);
1681 return S_OK;
1684 WARN("Unknown interface %s\n", debugstr_guid(riid));
1685 return E_NOINTERFACE;
1688 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
1690 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1691 ULONG ref;
1692 ref = InterlockedIncrement(&This->ref);
1693 TRACE("(%p) Refcount now %u\n", This, ref);
1694 return ref;
1697 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
1699 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1700 ULONG ref;
1701 ref = InterlockedDecrement(&This->ref);
1702 TRACE("(%p) Refcount now %u\n", This, ref);
1703 if (!ref) {
1704 if (This->client) {
1705 This->client->session_wrapper = NULL;
1706 AudioClient_Release(&This->client->IAudioClient3_iface);
1708 HeapFree(GetProcessHeap(), 0, This);
1710 return ref;
1713 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
1714 AudioSessionState *state)
1716 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1717 ACImpl *client;
1719 TRACE("(%p)->(%p)\n", This, state);
1721 if (!state)
1722 return NULL_PTR_ERR;
1724 EnterCriticalSection(&session_cs);
1725 if (list_empty(&This->session->clients)) {
1726 *state = AudioSessionStateExpired;
1727 goto out;
1729 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry) {
1730 struct is_started_params params;
1732 if (!client->pulse_stream)
1733 continue;
1735 params.stream = client->pulse_stream;
1736 pulse_call(is_started, &params);
1737 if (params.started) {
1738 *state = AudioSessionStateActive;
1739 goto out;
1742 *state = AudioSessionStateInactive;
1744 out:
1745 LeaveCriticalSection(&session_cs);
1746 return S_OK;
1749 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
1750 IAudioSessionControl2 *iface, WCHAR **name)
1752 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1754 FIXME("(%p)->(%p) - stub\n", This, name);
1756 return E_NOTIMPL;
1759 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
1760 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
1762 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1764 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
1766 return E_NOTIMPL;
1769 static HRESULT WINAPI AudioSessionControl_GetIconPath(
1770 IAudioSessionControl2 *iface, WCHAR **path)
1772 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1774 FIXME("(%p)->(%p) - stub\n", This, path);
1776 return E_NOTIMPL;
1779 static HRESULT WINAPI AudioSessionControl_SetIconPath(
1780 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
1782 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1784 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
1786 return E_NOTIMPL;
1789 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
1790 IAudioSessionControl2 *iface, GUID *group)
1792 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1794 FIXME("(%p)->(%p) - stub\n", This, group);
1796 return E_NOTIMPL;
1799 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
1800 IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
1802 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1804 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
1805 debugstr_guid(session));
1807 return E_NOTIMPL;
1810 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
1811 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
1813 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1815 FIXME("(%p)->(%p) - stub\n", This, events);
1817 return S_OK;
1820 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
1821 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
1823 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1825 FIXME("(%p)->(%p) - stub\n", This, events);
1827 return S_OK;
1830 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
1831 IAudioSessionControl2 *iface, WCHAR **id)
1833 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1835 FIXME("(%p)->(%p) - stub\n", This, id);
1837 return E_NOTIMPL;
1840 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
1841 IAudioSessionControl2 *iface, WCHAR **id)
1843 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1845 FIXME("(%p)->(%p) - stub\n", This, id);
1847 return E_NOTIMPL;
1850 static HRESULT WINAPI AudioSessionControl_GetProcessId(
1851 IAudioSessionControl2 *iface, DWORD *pid)
1853 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1855 TRACE("(%p)->(%p)\n", This, pid);
1857 if (!pid)
1858 return E_POINTER;
1860 *pid = GetCurrentProcessId();
1862 return S_OK;
1865 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
1866 IAudioSessionControl2 *iface)
1868 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1870 TRACE("(%p)\n", This);
1872 return S_FALSE;
1875 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
1876 IAudioSessionControl2 *iface, BOOL optout)
1878 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1880 TRACE("(%p)->(%d)\n", This, optout);
1882 return S_OK;
1885 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
1887 AudioSessionControl_QueryInterface,
1888 AudioSessionControl_AddRef,
1889 AudioSessionControl_Release,
1890 AudioSessionControl_GetState,
1891 AudioSessionControl_GetDisplayName,
1892 AudioSessionControl_SetDisplayName,
1893 AudioSessionControl_GetIconPath,
1894 AudioSessionControl_SetIconPath,
1895 AudioSessionControl_GetGroupingParam,
1896 AudioSessionControl_SetGroupingParam,
1897 AudioSessionControl_RegisterAudioSessionNotification,
1898 AudioSessionControl_UnregisterAudioSessionNotification,
1899 AudioSessionControl_GetSessionIdentifier,
1900 AudioSessionControl_GetSessionInstanceIdentifier,
1901 AudioSessionControl_GetProcessId,
1902 AudioSessionControl_IsSystemSoundsSession,
1903 AudioSessionControl_SetDuckingPreference
1906 typedef struct _SessionMgr {
1907 IAudioSessionManager2 IAudioSessionManager2_iface;
1909 LONG ref;
1911 IMMDevice *device;
1912 } SessionMgr;
1914 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
1915 REFIID riid, void **ppv)
1917 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1919 if (!ppv)
1920 return E_POINTER;
1921 *ppv = NULL;
1923 if (IsEqualIID(riid, &IID_IUnknown) ||
1924 IsEqualIID(riid, &IID_IAudioSessionManager) ||
1925 IsEqualIID(riid, &IID_IAudioSessionManager2))
1926 *ppv = iface;
1927 if (*ppv) {
1928 IUnknown_AddRef((IUnknown*)*ppv);
1929 return S_OK;
1932 WARN("Unknown interface %s\n", debugstr_guid(riid));
1933 return E_NOINTERFACE;
1936 static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface)
1938 return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface);
1941 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
1943 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
1944 ULONG ref;
1945 ref = InterlockedIncrement(&This->ref);
1946 TRACE("(%p) Refcount now %u\n", This, ref);
1947 return ref;
1950 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
1952 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
1953 ULONG ref;
1954 ref = InterlockedDecrement(&This->ref);
1955 TRACE("(%p) Refcount now %u\n", This, ref);
1956 if (!ref)
1957 HeapFree(GetProcessHeap(), 0, This);
1958 return ref;
1961 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
1962 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
1963 IAudioSessionControl **out)
1965 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
1966 AudioSession *session;
1967 AudioSessionWrapper *wrapper;
1968 HRESULT hr;
1970 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
1971 flags, out);
1973 hr = get_audio_session(session_guid, This->device, 0, &session);
1974 if (FAILED(hr))
1975 return hr;
1977 wrapper = AudioSessionWrapper_Create(NULL);
1978 if (!wrapper)
1979 return E_OUTOFMEMORY;
1981 wrapper->session = session;
1983 *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
1985 return S_OK;
1988 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
1989 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
1990 ISimpleAudioVolume **out)
1992 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
1993 AudioSession *session;
1994 AudioSessionWrapper *wrapper;
1995 HRESULT hr;
1997 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
1998 flags, out);
2000 hr = get_audio_session(session_guid, This->device, 0, &session);
2001 if (FAILED(hr))
2002 return hr;
2004 wrapper = AudioSessionWrapper_Create(NULL);
2005 if (!wrapper)
2006 return E_OUTOFMEMORY;
2008 wrapper->session = session;
2010 *out = &wrapper->ISimpleAudioVolume_iface;
2012 return S_OK;
2015 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
2016 IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
2018 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2019 FIXME("(%p)->(%p) - stub\n", This, out);
2020 return E_NOTIMPL;
2023 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
2024 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2026 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2027 FIXME("(%p)->(%p) - stub\n", This, notification);
2028 return E_NOTIMPL;
2031 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
2032 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2034 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2035 FIXME("(%p)->(%p) - stub\n", This, notification);
2036 return E_NOTIMPL;
2039 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
2040 IAudioSessionManager2 *iface, const WCHAR *session_id,
2041 IAudioVolumeDuckNotification *notification)
2043 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2044 FIXME("(%p)->(%p) - stub\n", This, notification);
2045 return E_NOTIMPL;
2048 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
2049 IAudioSessionManager2 *iface,
2050 IAudioVolumeDuckNotification *notification)
2052 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2053 FIXME("(%p)->(%p) - stub\n", This, notification);
2054 return E_NOTIMPL;
2057 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
2059 AudioSessionManager_QueryInterface,
2060 AudioSessionManager_AddRef,
2061 AudioSessionManager_Release,
2062 AudioSessionManager_GetAudioSessionControl,
2063 AudioSessionManager_GetSimpleAudioVolume,
2064 AudioSessionManager_GetSessionEnumerator,
2065 AudioSessionManager_RegisterSessionNotification,
2066 AudioSessionManager_UnregisterSessionNotification,
2067 AudioSessionManager_RegisterDuckNotification,
2068 AudioSessionManager_UnregisterDuckNotification
2071 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
2072 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
2074 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2076 if (!ppv)
2077 return E_POINTER;
2078 *ppv = NULL;
2080 if (IsEqualIID(riid, &IID_IUnknown) ||
2081 IsEqualIID(riid, &IID_ISimpleAudioVolume))
2082 *ppv = iface;
2083 if (*ppv) {
2084 IUnknown_AddRef((IUnknown*)*ppv);
2085 return S_OK;
2088 WARN("Unknown interface %s\n", debugstr_guid(riid));
2089 return E_NOINTERFACE;
2092 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
2094 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2095 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2098 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
2100 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2101 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2104 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
2105 ISimpleAudioVolume *iface, float level, const GUID *context)
2107 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2108 AudioSession *session = This->session;
2109 ACImpl *client;
2111 TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
2113 if (level < 0.f || level > 1.f)
2114 return E_INVALIDARG;
2116 if (context)
2117 FIXME("Notifications not supported yet\n");
2119 TRACE("PulseAudio does not support session volume control\n");
2121 EnterCriticalSection(&session_cs);
2122 session->master_vol = level;
2123 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry)
2124 set_stream_volumes(client);
2125 LeaveCriticalSection(&session_cs);
2127 return S_OK;
2130 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
2131 ISimpleAudioVolume *iface, float *level)
2133 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2134 AudioSession *session = This->session;
2136 TRACE("(%p)->(%p)\n", session, level);
2138 if (!level)
2139 return NULL_PTR_ERR;
2141 *level = session->master_vol;
2143 return S_OK;
2146 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
2147 BOOL mute, const GUID *context)
2149 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2150 AudioSession *session = This->session;
2151 ACImpl *client;
2153 TRACE("(%p)->(%u, %s)\n", session, mute, debugstr_guid(context));
2155 if (context)
2156 FIXME("Notifications not supported yet\n");
2158 EnterCriticalSection(&session_cs);
2159 session->mute = mute;
2160 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry)
2161 set_stream_volumes(client);
2162 LeaveCriticalSection(&session_cs);
2164 return S_OK;
2167 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
2168 BOOL *mute)
2170 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2171 AudioSession *session = This->session;
2173 TRACE("(%p)->(%p)\n", session, mute);
2175 if (!mute)
2176 return NULL_PTR_ERR;
2178 *mute = session->mute;
2180 return S_OK;
2183 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
2185 SimpleAudioVolume_QueryInterface,
2186 SimpleAudioVolume_AddRef,
2187 SimpleAudioVolume_Release,
2188 SimpleAudioVolume_SetMasterVolume,
2189 SimpleAudioVolume_GetMasterVolume,
2190 SimpleAudioVolume_SetMute,
2191 SimpleAudioVolume_GetMute
2194 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2195 IChannelAudioVolume *iface, REFIID riid, void **ppv)
2197 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2199 if (!ppv)
2200 return E_POINTER;
2201 *ppv = NULL;
2203 if (IsEqualIID(riid, &IID_IUnknown) ||
2204 IsEqualIID(riid, &IID_IChannelAudioVolume))
2205 *ppv = iface;
2206 if (*ppv) {
2207 IUnknown_AddRef((IUnknown*)*ppv);
2208 return S_OK;
2211 WARN("Unknown interface %s\n", debugstr_guid(riid));
2212 return E_NOINTERFACE;
2215 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2217 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2218 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2221 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2223 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2224 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2227 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2228 IChannelAudioVolume *iface, UINT32 *out)
2230 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2231 AudioSession *session = This->session;
2233 TRACE("(%p)->(%p)\n", session, out);
2235 if (!out)
2236 return NULL_PTR_ERR;
2238 *out = session->channel_count;
2240 return S_OK;
2243 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2244 IChannelAudioVolume *iface, UINT32 index, float level,
2245 const GUID *context)
2247 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2248 AudioSession *session = This->session;
2249 ACImpl *client;
2251 TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2252 wine_dbgstr_guid(context));
2254 if (level < 0.f || level > 1.f)
2255 return E_INVALIDARG;
2257 if (index >= session->channel_count)
2258 return E_INVALIDARG;
2260 if (context)
2261 FIXME("Notifications not supported yet\n");
2263 TRACE("PulseAudio does not support session volume control\n");
2265 EnterCriticalSection(&session_cs);
2266 session->channel_vols[index] = level;
2267 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry)
2268 set_stream_volumes(client);
2269 LeaveCriticalSection(&session_cs);
2271 return S_OK;
2274 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2275 IChannelAudioVolume *iface, UINT32 index, float *level)
2277 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2278 AudioSession *session = This->session;
2280 TRACE("(%p)->(%d, %p)\n", session, index, level);
2282 if (!level)
2283 return NULL_PTR_ERR;
2285 if (index >= session->channel_count)
2286 return E_INVALIDARG;
2288 *level = session->channel_vols[index];
2290 return S_OK;
2293 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2294 IChannelAudioVolume *iface, UINT32 count, const float *levels,
2295 const GUID *context)
2297 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2298 AudioSession *session = This->session;
2299 ACImpl *client;
2300 int i;
2302 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2303 wine_dbgstr_guid(context));
2305 if (!levels)
2306 return NULL_PTR_ERR;
2308 if (count != session->channel_count)
2309 return E_INVALIDARG;
2311 if (context)
2312 FIXME("Notifications not supported yet\n");
2314 TRACE("PulseAudio does not support session volume control\n");
2316 EnterCriticalSection(&session_cs);
2317 for(i = 0; i < count; ++i)
2318 session->channel_vols[i] = levels[i];
2319 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry)
2320 set_stream_volumes(client);
2321 LeaveCriticalSection(&session_cs);
2322 return S_OK;
2325 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2326 IChannelAudioVolume *iface, UINT32 count, float *levels)
2328 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2329 AudioSession *session = This->session;
2330 int i;
2332 TRACE("(%p)->(%d, %p)\n", session, count, levels);
2334 if (!levels)
2335 return NULL_PTR_ERR;
2337 if (count != session->channel_count)
2338 return E_INVALIDARG;
2340 for(i = 0; i < count; ++i)
2341 levels[i] = session->channel_vols[i];
2343 return S_OK;
2346 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2348 ChannelAudioVolume_QueryInterface,
2349 ChannelAudioVolume_AddRef,
2350 ChannelAudioVolume_Release,
2351 ChannelAudioVolume_GetChannelCount,
2352 ChannelAudioVolume_SetChannelVolume,
2353 ChannelAudioVolume_GetChannelVolume,
2354 ChannelAudioVolume_SetAllVolumes,
2355 ChannelAudioVolume_GetAllVolumes
2358 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
2359 IAudioSessionManager2 **out)
2361 SessionMgr *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
2362 *out = NULL;
2363 if (!This)
2364 return E_OUTOFMEMORY;
2365 This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
2366 This->device = device;
2367 This->ref = 1;
2368 *out = &This->IAudioSessionManager2_iface;
2369 return S_OK;
2372 HRESULT WINAPI AUDDRV_GetPropValue(GUID *guid, const PROPERTYKEY *prop, PROPVARIANT *out)
2374 TRACE("%s, (%s,%u), %p\n", wine_dbgstr_guid(guid), wine_dbgstr_guid(&prop->fmtid), prop->pid, out);
2376 if (IsEqualGUID(guid, &pulse_render_guid) && IsEqualPropertyKey(*prop, PKEY_AudioEndpoint_PhysicalSpeakers)) {
2377 out->vt = VT_UI4;
2378 out->ulVal = pulse_config.speakers_mask;
2380 return out->ulVal ? S_OK : E_FAIL;
2383 return E_NOTIMPL;