mmdevapi: Move test_connect handling into mmdevapi.
[wine.git] / dlls / winecoreaudio.drv / mmdevdrv.c
blob877c1f7c3bc49fe6d303eb224b7056396448062f
1 /*
2 * Copyright 2011 Andrew Eikum for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 #define COBJMACROS
20 #include <stdarg.h>
22 #include "windef.h"
23 #include "winbase.h"
24 #include "winternl.h"
25 #include "winnls.h"
26 #include "winreg.h"
27 #include "wine/debug.h"
28 #include "wine/heap.h"
29 #include "wine/list.h"
30 #include "wine/unixlib.h"
32 #include "ole2.h"
33 #include "mmdeviceapi.h"
34 #include "devpkey.h"
35 #include "dshow.h"
36 #include "dsound.h"
38 #include "initguid.h"
39 #include "endpointvolume.h"
40 #include "audioclient.h"
41 #include "audiopolicy.h"
42 #include "unixlib.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(coreaudio);
46 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
48 static const REFERENCE_TIME DefaultPeriod = 100000;
49 static const REFERENCE_TIME MinimumPeriod = 50000;
51 struct ACImpl;
52 typedef struct ACImpl ACImpl;
54 typedef struct _AudioSession {
55 GUID guid;
56 struct list clients;
58 IMMDevice *device;
60 float master_vol;
61 UINT32 channel_count;
62 float *channel_vols;
63 BOOL mute;
65 struct list entry;
66 } AudioSession;
68 typedef struct _AudioSessionWrapper {
69 IAudioSessionControl2 IAudioSessionControl2_iface;
70 IChannelAudioVolume IChannelAudioVolume_iface;
71 ISimpleAudioVolume ISimpleAudioVolume_iface;
73 LONG ref;
75 ACImpl *client;
76 AudioSession *session;
77 } AudioSessionWrapper;
79 struct ACImpl {
80 IAudioClient3 IAudioClient3_iface;
81 IAudioRenderClient IAudioRenderClient_iface;
82 IAudioCaptureClient IAudioCaptureClient_iface;
83 IAudioClock IAudioClock_iface;
84 IAudioClock2 IAudioClock2_iface;
85 IAudioStreamVolume IAudioStreamVolume_iface;
87 LONG ref;
89 IMMDevice *parent;
90 IUnknown *pUnkFTMarshal;
92 EDataFlow dataflow;
93 UINT32 channel_count, period_ms;
94 DWORD flags;
95 HANDLE event;
96 float *vols;
98 HANDLE timer;
100 AudioSession *session;
101 AudioSessionWrapper *session_wrapper;
103 stream_handle stream;
104 struct list entry;
106 char device_name[1];
109 static const IAudioClient3Vtbl AudioClient3_Vtbl;
110 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
111 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
112 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
113 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
114 static const IAudioClockVtbl AudioClock_Vtbl;
115 static const IAudioClock2Vtbl AudioClock2_Vtbl;
116 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
117 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
118 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl;
120 typedef struct _SessionMgr {
121 IAudioSessionManager2 IAudioSessionManager2_iface;
123 LONG ref;
125 IMMDevice *device;
126 } SessionMgr;
128 static const WCHAR *drv_key_devicesW = L"Software\\Wine\\Drivers\\winecoreaudio.drv\\devices";
130 static HANDLE g_timer_q;
132 static CRITICAL_SECTION g_sessions_lock;
133 static CRITICAL_SECTION_DEBUG g_sessions_lock_debug =
135 0, 0, &g_sessions_lock,
136 { &g_sessions_lock_debug.ProcessLocksList, &g_sessions_lock_debug.ProcessLocksList },
137 0, 0, { (DWORD_PTR)(__FILE__ ": g_sessions_lock") }
139 static CRITICAL_SECTION g_sessions_lock = { &g_sessions_lock_debug, -1, 0, 0, 0, 0 };
140 static struct list g_sessions = LIST_INIT(g_sessions);
142 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
144 static inline ACImpl *impl_from_IAudioClient3(IAudioClient3 *iface)
146 return CONTAINING_RECORD(iface, ACImpl, IAudioClient3_iface);
149 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
151 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
154 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
156 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
159 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
161 return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
164 static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
166 return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
169 static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
171 return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
174 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
176 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
179 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
181 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
184 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
186 return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
189 static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface)
191 return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface);
194 BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
196 switch (reason)
198 case DLL_PROCESS_ATTACH:
199 DisableThreadLibraryCalls(dll);
200 if (__wine_init_unix_call())
201 return FALSE;
202 g_timer_q = CreateTimerQueue();
203 if(!g_timer_q)
204 return FALSE;
205 break;
207 case DLL_PROCESS_DETACH:
208 if (reserved) break;
209 DeleteCriticalSection(&g_sessions_lock);
210 CloseHandle(g_timer_q);
211 break;
213 return TRUE;
216 static void set_device_guid(EDataFlow flow, HKEY drv_key, const WCHAR *key_name,
217 GUID *guid)
219 HKEY key;
220 BOOL opened = FALSE;
221 LONG lr;
223 if(!drv_key){
224 lr = RegCreateKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, NULL, 0, KEY_WRITE,
225 NULL, &drv_key, NULL);
226 if(lr != ERROR_SUCCESS){
227 ERR("RegCreateKeyEx(drv_key) failed: %lu\n", lr);
228 return;
230 opened = TRUE;
233 lr = RegCreateKeyExW(drv_key, key_name, 0, NULL, 0, KEY_WRITE,
234 NULL, &key, NULL);
235 if(lr != ERROR_SUCCESS){
236 ERR("RegCreateKeyEx(%s) failed: %lu\n", wine_dbgstr_w(key_name), lr);
237 goto exit;
240 lr = RegSetValueExW(key, L"guid", 0, REG_BINARY, (BYTE*)guid,
241 sizeof(GUID));
242 if(lr != ERROR_SUCCESS)
243 ERR("RegSetValueEx(%s\\guid) failed: %lu\n", wine_dbgstr_w(key_name), lr);
245 RegCloseKey(key);
246 exit:
247 if(opened)
248 RegCloseKey(drv_key);
251 static void get_device_guid(EDataFlow flow, const char *dev, GUID *guid)
253 HKEY key = NULL, dev_key;
254 DWORD type, size = sizeof(*guid);
255 WCHAR key_name[256];
257 if(flow == eCapture)
258 key_name[0] = '1';
259 else
260 key_name[0] = '0';
261 key_name[1] = ',';
263 MultiByteToWideChar(CP_UNIXCP, 0, dev, -1, key_name + 2, ARRAY_SIZE(key_name) - 2);
265 if(RegOpenKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, KEY_WRITE|KEY_READ, &key) == ERROR_SUCCESS){
266 if(RegOpenKeyExW(key, key_name, 0, KEY_READ, &dev_key) == ERROR_SUCCESS){
267 if(RegQueryValueExW(dev_key, L"guid", 0, &type,
268 (BYTE*)guid, &size) == ERROR_SUCCESS){
269 if(type == REG_BINARY){
270 RegCloseKey(dev_key);
271 RegCloseKey(key);
272 return;
274 ERR("Invalid type for device %s GUID: %lu; ignoring and overwriting\n",
275 wine_dbgstr_w(key_name), type);
277 RegCloseKey(dev_key);
281 CoCreateGuid(guid);
283 set_device_guid(flow, key, key_name, guid);
285 if(key)
286 RegCloseKey(key);
289 static void set_stream_volumes(ACImpl *This, int channel)
291 struct set_volumes_params params;
293 params.stream = This->stream;
294 params.master_volume = This->session->mute ? 0.0f : This->session->master_vol;
295 params.volumes = This->vols;
296 params.session_volumes = This->session->channel_vols;
297 params.channel = channel;
299 UNIX_CALL(set_volumes, &params);
302 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids_out,
303 GUID **guids_out, UINT *num, UINT *def_index)
305 struct get_endpoint_ids_params params;
306 unsigned int i;
307 GUID *guids = NULL;
308 WCHAR **ids = NULL;
310 TRACE("%d %p %p %p\n", flow, ids_out, num, def_index);
312 params.flow = flow;
313 params.size = 1000;
314 params.endpoints = NULL;
316 heap_free(params.endpoints);
317 params.endpoints = heap_alloc(params.size);
318 UNIX_CALL(get_endpoint_ids, &params);
319 }while(params.result == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
321 if(FAILED(params.result)) goto end;
323 ids = heap_alloc_zero(params.num * sizeof(*ids));
324 guids = heap_alloc(params.num * sizeof(*guids));
325 if(!ids || !guids){
326 params.result = E_OUTOFMEMORY;
327 goto end;
330 for(i = 0; i < params.num; i++){
331 const WCHAR *name = (WCHAR *)((char *)params.endpoints + params.endpoints[i].name);
332 const char *device = (char *)params.endpoints + params.endpoints[i].device;
333 const unsigned int size = (wcslen(name) + 1) * sizeof(WCHAR);
335 ids[i] = heap_alloc(size);
336 if(!ids[i]){
337 params.result = E_OUTOFMEMORY;
338 goto end;
340 memcpy(ids[i], name, size);
341 get_device_guid(flow, device, guids + i);
343 *def_index = params.default_idx;
345 end:
346 heap_free(params.endpoints);
347 if(FAILED(params.result)){
348 heap_free(guids);
349 if(ids){
350 for(i = 0; i < params.num; i++) heap_free(ids[i]);
351 heap_free(ids);
353 }else{
354 *ids_out = ids;
355 *guids_out = guids;
356 *num = params.num;
359 return params.result;
362 static BOOL get_device_name_by_guid(const GUID *guid, char *name, const SIZE_T name_size, EDataFlow *flow)
364 HKEY devices_key;
365 UINT i = 0;
366 WCHAR key_name[256];
367 DWORD key_name_size;
369 if(RegOpenKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, KEY_READ, &devices_key) != ERROR_SUCCESS){
370 ERR("No devices in registry?\n");
371 return FALSE;
374 while(1){
375 HKEY key;
376 DWORD size, type;
377 GUID reg_guid;
379 key_name_size = ARRAY_SIZE(key_name);
380 if(RegEnumKeyExW(devices_key, i++, key_name, &key_name_size, NULL,
381 NULL, NULL, NULL) != ERROR_SUCCESS)
382 break;
384 if(RegOpenKeyExW(devices_key, key_name, 0, KEY_READ, &key) != ERROR_SUCCESS){
385 WARN("Couldn't open key: %s\n", wine_dbgstr_w(key_name));
386 continue;
389 size = sizeof(reg_guid);
390 if(RegQueryValueExW(key, L"guid", 0, &type,
391 (BYTE*)&reg_guid, &size) == ERROR_SUCCESS){
392 if(IsEqualGUID(&reg_guid, guid)){
393 RegCloseKey(key);
394 RegCloseKey(devices_key);
396 TRACE("Found matching device key: %s\n", wine_dbgstr_w(key_name));
398 if(key_name[0] == '0')
399 *flow = eRender;
400 else if(key_name[0] == '1')
401 *flow = eCapture;
402 else{
403 ERR("Unknown device type: %c\n", key_name[0]);
404 return FALSE;
407 WideCharToMultiByte(CP_UNIXCP, 0, key_name + 2, -1, name, name_size, NULL, NULL);
409 return TRUE;
413 RegCloseKey(key);
416 RegCloseKey(devices_key);
418 WARN("No matching device in registry for GUID %s\n", debugstr_guid(guid));
420 return FALSE;
423 HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient **out)
425 ACImpl *This;
426 char name[256];
427 SIZE_T name_len;
428 EDataFlow dataflow;
429 HRESULT hr;
431 TRACE("%s %p %p\n", debugstr_guid(guid), dev, out);
433 if(!get_device_name_by_guid(guid, name, sizeof(name), &dataflow))
434 return AUDCLNT_E_DEVICE_INVALIDATED;
436 if(dataflow != eRender && dataflow != eCapture)
437 return E_INVALIDARG;
439 name_len = strlen(name);
440 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, offsetof(ACImpl, device_name[name_len + 1]));
441 if(!This)
442 return E_OUTOFMEMORY;
444 This->IAudioClient3_iface.lpVtbl = &AudioClient3_Vtbl;
445 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
446 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
447 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
448 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
449 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
451 This->dataflow = dataflow;
452 memcpy(This->device_name, name, name_len + 1);
454 hr = CoCreateFreeThreadedMarshaler((IUnknown *)&This->IAudioClient3_iface, &This->pUnkFTMarshal);
455 if (FAILED(hr)) {
456 HeapFree(GetProcessHeap(), 0, This);
457 return hr;
460 This->parent = dev;
461 IMMDevice_AddRef(This->parent);
463 *out = (IAudioClient *)&This->IAudioClient3_iface;
464 IAudioClient3_AddRef(&This->IAudioClient3_iface);
466 return S_OK;
469 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient3 *iface,
470 REFIID riid, void **ppv)
472 ACImpl *This = impl_from_IAudioClient3(iface);
473 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
475 if(!ppv)
476 return E_POINTER;
477 *ppv = NULL;
478 if(IsEqualIID(riid, &IID_IUnknown) ||
479 IsEqualIID(riid, &IID_IAudioClient) ||
480 IsEqualIID(riid, &IID_IAudioClient2) ||
481 IsEqualIID(riid, &IID_IAudioClient3))
482 *ppv = iface;
483 else if(IsEqualIID(riid, &IID_IMarshal))
484 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
486 if(*ppv){
487 IUnknown_AddRef((IUnknown*)*ppv);
488 return S_OK;
490 WARN("Unknown interface %s\n", debugstr_guid(riid));
491 return E_NOINTERFACE;
494 static ULONG WINAPI AudioClient_AddRef(IAudioClient3 *iface)
496 ACImpl *This = impl_from_IAudioClient3(iface);
497 ULONG ref;
498 ref = InterlockedIncrement(&This->ref);
499 TRACE("(%p) Refcount now %lu\n", This, ref);
500 return ref;
503 static ULONG WINAPI AudioClient_Release(IAudioClient3 *iface)
505 ACImpl *This = impl_from_IAudioClient3(iface);
506 struct release_stream_params params;
507 ULONG ref;
509 ref = InterlockedDecrement(&This->ref);
510 TRACE("(%p) Refcount now %lu\n", This, ref);
511 if(!ref){
512 if(This->timer){
513 HANDLE event;
514 BOOL wait;
515 event = CreateEventW(NULL, TRUE, FALSE, NULL);
516 wait = !DeleteTimerQueueTimer(g_timer_q, This->timer, event);
517 wait = wait && GetLastError() == ERROR_IO_PENDING;
518 if(event && wait)
519 WaitForSingleObject(event, INFINITE);
520 CloseHandle(event);
522 if(This->stream){
523 params.stream = This->stream;
524 params.timer_thread = NULL;
525 UNIX_CALL(release_stream, &params);
527 if(This->session){
528 EnterCriticalSection(&g_sessions_lock);
529 list_remove(&This->entry);
530 LeaveCriticalSection(&g_sessions_lock);
532 HeapFree(GetProcessHeap(), 0, This->vols);
533 IMMDevice_Release(This->parent);
534 IUnknown_Release(This->pUnkFTMarshal);
535 HeapFree(GetProcessHeap(), 0, This);
537 return ref;
540 static void dump_fmt(const WAVEFORMATEX *fmt)
542 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
543 switch(fmt->wFormatTag){
544 case WAVE_FORMAT_PCM:
545 TRACE("WAVE_FORMAT_PCM");
546 break;
547 case WAVE_FORMAT_IEEE_FLOAT:
548 TRACE("WAVE_FORMAT_IEEE_FLOAT");
549 break;
550 case WAVE_FORMAT_EXTENSIBLE:
551 TRACE("WAVE_FORMAT_EXTENSIBLE");
552 break;
553 default:
554 TRACE("Unknown");
555 break;
557 TRACE(")\n");
559 TRACE("nChannels: %u\n", fmt->nChannels);
560 TRACE("nSamplesPerSec: %lu\n", fmt->nSamplesPerSec);
561 TRACE("nAvgBytesPerSec: %lu\n", fmt->nAvgBytesPerSec);
562 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
563 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
564 TRACE("cbSize: %u\n", fmt->cbSize);
566 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
567 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
568 TRACE("dwChannelMask: %08lx\n", fmtex->dwChannelMask);
569 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
570 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
574 static void session_init_vols(AudioSession *session, UINT channels)
576 if(session->channel_count < channels){
577 UINT i;
579 if(session->channel_vols)
580 session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
581 session->channel_vols, sizeof(float) * channels);
582 else
583 session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
584 sizeof(float) * channels);
585 if(!session->channel_vols)
586 return;
588 for(i = session->channel_count; i < channels; ++i)
589 session->channel_vols[i] = 1.f;
591 session->channel_count = channels;
595 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
596 UINT num_channels)
598 AudioSession *ret;
600 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
601 if(!ret)
602 return NULL;
604 memcpy(&ret->guid, guid, sizeof(GUID));
606 ret->device = device;
608 list_init(&ret->clients);
610 list_add_head(&g_sessions, &ret->entry);
612 session_init_vols(ret, num_channels);
614 ret->master_vol = 1.f;
616 return ret;
619 /* if channels == 0, then this will return or create a session with
620 * matching dataflow and GUID. otherwise, channels must also match */
621 static HRESULT get_audio_session(const GUID *sessionguid,
622 IMMDevice *device, UINT channels, AudioSession **out)
624 AudioSession *session;
626 if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
627 *out = create_session(&GUID_NULL, device, channels);
628 if(!*out)
629 return E_OUTOFMEMORY;
631 return S_OK;
634 *out = NULL;
635 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
636 if(session->device == device &&
637 IsEqualGUID(sessionguid, &session->guid)){
638 session_init_vols(session, channels);
639 *out = session;
640 break;
644 if(!*out){
645 *out = create_session(sessionguid, device, channels);
646 if(!*out)
647 return E_OUTOFMEMORY;
650 return S_OK;
653 static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
654 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
655 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
656 const GUID *sessionguid)
658 ACImpl *This = impl_from_IAudioClient3(iface);
659 struct release_stream_params release_params;
660 struct create_stream_params params;
661 stream_handle stream;
662 UINT32 i;
664 TRACE("(%p)->(%x, %lx, %s, %s, %p, %s)\n", This, mode, flags,
665 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
667 if(!fmt)
668 return E_POINTER;
670 dump_fmt(fmt);
672 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
673 return E_INVALIDARG;
675 if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
676 AUDCLNT_STREAMFLAGS_LOOPBACK |
677 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
678 AUDCLNT_STREAMFLAGS_NOPERSIST |
679 AUDCLNT_STREAMFLAGS_RATEADJUST |
680 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
681 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
682 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED |
683 AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY |
684 AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM)){
685 FIXME("Unknown flags: %08lx\n", flags);
686 return E_INVALIDARG;
689 if(mode == AUDCLNT_SHAREMODE_SHARED){
690 period = DefaultPeriod;
691 if( duration < 3 * period)
692 duration = 3 * period;
693 }else{
694 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
695 if(((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask == 0 ||
696 ((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask & SPEAKER_RESERVED)
697 return AUDCLNT_E_UNSUPPORTED_FORMAT;
700 if(!period)
701 period = DefaultPeriod; /* not minimum */
702 if(period < MinimumPeriod || period > 5000000)
703 return AUDCLNT_E_INVALID_DEVICE_PERIOD;
704 if(duration > 20000000) /* the smaller the period, the lower this limit */
705 return AUDCLNT_E_BUFFER_SIZE_ERROR;
706 if(flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK){
707 if(duration != period)
708 return AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL;
709 FIXME("EXCLUSIVE mode with EVENTCALLBACK\n");
710 return AUDCLNT_E_DEVICE_IN_USE;
711 }else{
712 if( duration < 8 * period)
713 duration = 8 * period; /* may grow above 2s */
717 EnterCriticalSection(&g_sessions_lock);
719 if(This->stream){
720 LeaveCriticalSection(&g_sessions_lock);
721 return AUDCLNT_E_ALREADY_INITIALIZED;
724 params.name = NULL;
725 params.device = This->device_name;
726 params.flow = This->dataflow;
727 params.share = mode;
728 params.flags = flags;
729 params.duration = duration;
730 params.period = period;
731 params.fmt = fmt;
732 params.channel_count = NULL;
733 params.stream = &stream;
735 UNIX_CALL(create_stream, &params);
736 if(FAILED(params.result)){
737 LeaveCriticalSection(&g_sessions_lock);
738 return params.result;
741 This->flags = flags;
742 This->channel_count = fmt->nChannels;
743 This->period_ms = period / 10000;
745 This->vols = HeapAlloc(GetProcessHeap(), 0, This->channel_count * sizeof(float));
746 if(!This->vols){
747 params.result = E_OUTOFMEMORY;
748 goto end;
751 for(i = 0; i < This->channel_count; ++i)
752 This->vols[i] = 1.f;
754 params.result = get_audio_session(sessionguid, This->parent, fmt->nChannels, &This->session);
755 if(FAILED(params.result)) goto end;
757 list_add_tail(&This->session->clients, &This->entry);
759 end:
760 if(FAILED(params.result)){
761 release_params.stream = stream;
762 UNIX_CALL(release_stream, &release_params);
763 HeapFree(GetProcessHeap(), 0, This->vols);
764 This->vols = NULL;
765 }else{
766 This->stream = stream;
767 set_stream_volumes(This, -1);
770 LeaveCriticalSection(&g_sessions_lock);
772 return params.result;
775 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient3 *iface,
776 UINT32 *frames)
778 ACImpl *This = impl_from_IAudioClient3(iface);
779 struct get_buffer_size_params params;
781 TRACE("(%p)->(%p)\n", This, frames);
783 if(!frames)
784 return E_POINTER;
786 if(!This->stream)
787 return AUDCLNT_E_NOT_INITIALIZED;
789 params.stream = This->stream;
790 params.frames = frames;
791 UNIX_CALL(get_buffer_size, &params);
792 return params.result;
795 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient3 *iface,
796 REFERENCE_TIME *out)
798 ACImpl *This = impl_from_IAudioClient3(iface);
799 struct get_latency_params params;
801 TRACE("(%p)->(%p)\n", This, out);
803 if(!out)
804 return E_POINTER;
806 if(!This->stream)
807 return AUDCLNT_E_NOT_INITIALIZED;
809 params.stream = This->stream;
810 params.latency = out;
811 UNIX_CALL(get_latency, &params);
812 return params.result;
815 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient3 *iface,
816 UINT32 *numpad)
818 ACImpl *This = impl_from_IAudioClient3(iface);
819 struct get_current_padding_params params;
821 TRACE("(%p)->(%p)\n", This, numpad);
823 if(!numpad)
824 return E_POINTER;
826 if(!This->stream)
827 return AUDCLNT_E_NOT_INITIALIZED;
829 params.stream = This->stream;
830 params.padding = numpad;
831 UNIX_CALL(get_current_padding, &params);
832 return params.result;
835 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient3 *iface,
836 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
837 WAVEFORMATEX **outpwfx)
839 ACImpl *This = impl_from_IAudioClient3(iface);
840 struct is_format_supported_params params;
842 TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx);
843 if(pwfx) dump_fmt(pwfx);
845 params.device = This->device_name;
846 params.flow = This->dataflow;
847 params.share = mode;
848 params.fmt_in = pwfx;
849 params.fmt_out = NULL;
851 if(outpwfx){
852 *outpwfx = NULL;
853 if(mode == AUDCLNT_SHAREMODE_SHARED)
854 params.fmt_out = CoTaskMemAlloc(sizeof(*params.fmt_out));
856 UNIX_CALL(is_format_supported, &params);
858 if(params.result == S_FALSE)
859 *outpwfx = &params.fmt_out->Format;
860 else
861 CoTaskMemFree(params.fmt_out);
863 return params.result;
866 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface,
867 WAVEFORMATEX **pwfx)
869 ACImpl *This = impl_from_IAudioClient3(iface);
870 struct get_mix_format_params params;
872 TRACE("(%p)->(%p)\n", This, pwfx);
874 if(!pwfx)
875 return E_POINTER;
876 *pwfx = NULL;
878 params.device = This->device_name;
879 params.flow = This->dataflow;
880 params.fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
881 if(!params.fmt)
882 return E_OUTOFMEMORY;
884 UNIX_CALL(get_mix_format, &params);
886 if(SUCCEEDED(params.result)){
887 *pwfx = &params.fmt->Format;
888 dump_fmt(*pwfx);
889 }else
890 CoTaskMemFree(params.fmt);
892 return params.result;
895 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient3 *iface,
896 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
898 ACImpl *This = impl_from_IAudioClient3(iface);
900 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
902 if(!defperiod && !minperiod)
903 return E_POINTER;
905 if(defperiod)
906 *defperiod = DefaultPeriod;
907 if(minperiod)
908 *minperiod = MinimumPeriod;
910 return S_OK;
913 void CALLBACK ca_period_cb(void *user, BOOLEAN timer)
915 ACImpl *This = user;
917 if(This->event)
918 SetEvent(This->event);
921 static HRESULT WINAPI AudioClient_Start(IAudioClient3 *iface)
923 ACImpl *This = impl_from_IAudioClient3(iface);
924 struct start_params params;
926 TRACE("(%p)\n", This);
928 if(!This->stream)
929 return AUDCLNT_E_NOT_INITIALIZED;
931 if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event)
932 return AUDCLNT_E_EVENTHANDLE_NOT_SET;
934 params.stream = This->stream;
935 UNIX_CALL(start, &params);
937 if(SUCCEEDED(params.result)){
938 if(This->event && !This->timer){
939 if(!CreateTimerQueueTimer(&This->timer, g_timer_q, ca_period_cb, This, 0,
940 This->period_ms, WT_EXECUTEINTIMERTHREAD)){
941 This->timer = NULL;
942 IAudioClient3_Stop(iface);
943 WARN("Unable to create timer: %lu\n", GetLastError());
944 return E_OUTOFMEMORY;
948 return params.result;
951 static HRESULT WINAPI AudioClient_Stop(IAudioClient3 *iface)
953 ACImpl *This = impl_from_IAudioClient3(iface);
954 struct stop_params params;
956 TRACE("(%p)\n", This);
958 if(!This->stream)
959 return AUDCLNT_E_NOT_INITIALIZED;
961 params.stream = This->stream;
962 UNIX_CALL(stop, &params);
963 return params.result;
966 static HRESULT WINAPI AudioClient_Reset(IAudioClient3 *iface)
968 ACImpl *This = impl_from_IAudioClient3(iface);
969 struct reset_params params;
971 TRACE("(%p)\n", This);
973 if(!This->stream)
974 return AUDCLNT_E_NOT_INITIALIZED;
976 params.stream = This->stream;
977 UNIX_CALL(reset, &params);
978 return params.result;
981 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient3 *iface,
982 HANDLE event)
984 ACImpl *This = impl_from_IAudioClient3(iface);
985 HRESULT hr = S_OK;
987 TRACE("(%p)->(%p)\n", This, event);
989 if(!event)
990 return E_INVALIDARG;
992 if(!This->stream)
993 return AUDCLNT_E_NOT_INITIALIZED;
995 EnterCriticalSection(&g_sessions_lock);
997 if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK))
998 hr = AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
999 else if(This->event){
1000 FIXME("called twice\n");
1001 hr = HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
1002 }else
1003 This->event = event;
1005 LeaveCriticalSection(&g_sessions_lock);
1007 return hr;
1010 static HRESULT WINAPI AudioClient_GetService(IAudioClient3 *iface, REFIID riid,
1011 void **ppv)
1013 ACImpl *This = impl_from_IAudioClient3(iface);
1014 HRESULT hr;
1016 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1018 if(!ppv)
1019 return E_POINTER;
1020 *ppv = NULL;
1022 if(!This->stream)
1023 return AUDCLNT_E_NOT_INITIALIZED;
1025 EnterCriticalSection(&g_sessions_lock);
1027 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1028 if(This->dataflow != eRender){
1029 hr = AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1030 goto end;
1032 IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
1033 *ppv = &This->IAudioRenderClient_iface;
1034 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1035 if(This->dataflow != eCapture){
1036 hr = AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1037 goto end;
1039 IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
1040 *ppv = &This->IAudioCaptureClient_iface;
1041 }else if(IsEqualIID(riid, &IID_IAudioClock)){
1042 IAudioClock_AddRef(&This->IAudioClock_iface);
1043 *ppv = &This->IAudioClock_iface;
1044 }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1045 IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
1046 *ppv = &This->IAudioStreamVolume_iface;
1047 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1048 if(!This->session_wrapper){
1049 This->session_wrapper = AudioSessionWrapper_Create(This);
1050 if(!This->session_wrapper){
1051 hr = E_OUTOFMEMORY;
1052 goto end;
1054 }else
1055 IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
1057 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1058 }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1059 if(!This->session_wrapper){
1060 This->session_wrapper = AudioSessionWrapper_Create(This);
1061 if(!This->session_wrapper){
1062 hr = E_OUTOFMEMORY;
1063 goto end;
1065 }else
1066 IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
1068 *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1069 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1070 if(!This->session_wrapper){
1071 This->session_wrapper = AudioSessionWrapper_Create(This);
1072 if(!This->session_wrapper){
1073 hr = E_OUTOFMEMORY;
1074 goto end;
1076 }else
1077 ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
1079 *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1082 if(*ppv) hr = S_OK;
1083 else{
1084 FIXME("stub %s\n", debugstr_guid(riid));
1085 hr = E_NOINTERFACE;
1088 end:
1089 LeaveCriticalSection(&g_sessions_lock);
1090 return hr;
1093 static HRESULT WINAPI AudioClient_IsOffloadCapable(IAudioClient3 *iface,
1094 AUDIO_STREAM_CATEGORY category, BOOL *offload_capable)
1096 ACImpl *This = impl_from_IAudioClient3(iface);
1098 TRACE("(%p)->(0x%x, %p)\n", This, category, offload_capable);
1100 if(!offload_capable)
1101 return E_INVALIDARG;
1103 *offload_capable = FALSE;
1105 return S_OK;
1108 static HRESULT WINAPI AudioClient_SetClientProperties(IAudioClient3 *iface,
1109 const AudioClientProperties *prop)
1111 ACImpl *This = impl_from_IAudioClient3(iface);
1112 const Win8AudioClientProperties *legacy_prop = (const Win8AudioClientProperties *)prop;
1114 TRACE("(%p)->(%p)\n", This, prop);
1116 if(!legacy_prop)
1117 return E_POINTER;
1119 if(legacy_prop->cbSize == sizeof(AudioClientProperties)){
1120 TRACE("{ bIsOffload: %u, eCategory: 0x%x, Options: 0x%x }\n",
1121 legacy_prop->bIsOffload,
1122 legacy_prop->eCategory,
1123 prop->Options);
1124 }else if(legacy_prop->cbSize == sizeof(Win8AudioClientProperties)){
1125 TRACE("{ bIsOffload: %u, eCategory: 0x%x }\n",
1126 legacy_prop->bIsOffload,
1127 legacy_prop->eCategory);
1128 }else{
1129 WARN("Unsupported Size = %d\n", legacy_prop->cbSize);
1130 return E_INVALIDARG;
1134 if(legacy_prop->bIsOffload)
1135 return AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE;
1137 return S_OK;
1140 static HRESULT WINAPI AudioClient_GetBufferSizeLimits(IAudioClient3 *iface,
1141 const WAVEFORMATEX *format, BOOL event_driven, REFERENCE_TIME *min_duration,
1142 REFERENCE_TIME *max_duration)
1144 ACImpl *This = impl_from_IAudioClient3(iface);
1146 FIXME("(%p)->(%p, %u, %p, %p)\n", This, format, event_driven, min_duration, max_duration);
1148 return E_NOTIMPL;
1151 static HRESULT WINAPI AudioClient_GetSharedModeEnginePeriod(IAudioClient3 *iface,
1152 const WAVEFORMATEX *format, UINT32 *default_period_frames, UINT32 *unit_period_frames,
1153 UINT32 *min_period_frames, UINT32 *max_period_frames)
1155 ACImpl *This = impl_from_IAudioClient3(iface);
1157 FIXME("(%p)->(%p, %p, %p, %p, %p)\n", This, format, default_period_frames, unit_period_frames,
1158 min_period_frames, max_period_frames);
1160 return E_NOTIMPL;
1163 static HRESULT WINAPI AudioClient_GetCurrentSharedModeEnginePeriod(IAudioClient3 *iface,
1164 WAVEFORMATEX **cur_format, UINT32 *cur_period_frames)
1166 ACImpl *This = impl_from_IAudioClient3(iface);
1168 FIXME("(%p)->(%p, %p)\n", This, cur_format, cur_period_frames);
1170 return E_NOTIMPL;
1173 static HRESULT WINAPI AudioClient_InitializeSharedAudioStream(IAudioClient3 *iface,
1174 DWORD flags, UINT32 period_frames, const WAVEFORMATEX *format,
1175 const GUID *session_guid)
1177 ACImpl *This = impl_from_IAudioClient3(iface);
1179 FIXME("(%p)->(0x%lx, %u, %p, %s)\n", This, flags, period_frames, format, debugstr_guid(session_guid));
1181 return E_NOTIMPL;
1184 static const IAudioClient3Vtbl AudioClient3_Vtbl =
1186 AudioClient_QueryInterface,
1187 AudioClient_AddRef,
1188 AudioClient_Release,
1189 AudioClient_Initialize,
1190 AudioClient_GetBufferSize,
1191 AudioClient_GetStreamLatency,
1192 AudioClient_GetCurrentPadding,
1193 AudioClient_IsFormatSupported,
1194 AudioClient_GetMixFormat,
1195 AudioClient_GetDevicePeriod,
1196 AudioClient_Start,
1197 AudioClient_Stop,
1198 AudioClient_Reset,
1199 AudioClient_SetEventHandle,
1200 AudioClient_GetService,
1201 AudioClient_IsOffloadCapable,
1202 AudioClient_SetClientProperties,
1203 AudioClient_GetBufferSizeLimits,
1204 AudioClient_GetSharedModeEnginePeriod,
1205 AudioClient_GetCurrentSharedModeEnginePeriod,
1206 AudioClient_InitializeSharedAudioStream,
1209 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1210 IAudioRenderClient *iface, REFIID riid, void **ppv)
1212 ACImpl *This = impl_from_IAudioRenderClient(iface);
1213 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1215 if(!ppv)
1216 return E_POINTER;
1217 *ppv = NULL;
1219 if(IsEqualIID(riid, &IID_IUnknown) ||
1220 IsEqualIID(riid, &IID_IAudioRenderClient))
1221 *ppv = iface;
1222 else if(IsEqualIID(riid, &IID_IMarshal))
1223 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
1225 if(*ppv){
1226 IUnknown_AddRef((IUnknown*)*ppv);
1227 return S_OK;
1230 WARN("Unknown interface %s\n", debugstr_guid(riid));
1231 return E_NOINTERFACE;
1234 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1236 ACImpl *This = impl_from_IAudioRenderClient(iface);
1237 return AudioClient_AddRef(&This->IAudioClient3_iface);
1240 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1242 ACImpl *This = impl_from_IAudioRenderClient(iface);
1243 return AudioClient_Release(&This->IAudioClient3_iface);
1246 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1247 UINT32 frames, BYTE **data)
1249 ACImpl *This = impl_from_IAudioRenderClient(iface);
1250 struct get_render_buffer_params params;
1252 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1254 if(!data)
1255 return E_POINTER;
1256 *data = NULL;
1258 params.stream = This->stream;
1259 params.frames = frames;
1260 params.data = data;
1261 UNIX_CALL(get_render_buffer, &params);
1262 return params.result;
1265 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1266 IAudioRenderClient *iface, UINT32 frames, DWORD flags)
1268 ACImpl *This = impl_from_IAudioRenderClient(iface);
1269 struct release_render_buffer_params params;
1271 TRACE("(%p)->(%u, %lx)\n", This, frames, flags);
1273 params.stream = This->stream;
1274 params.written_frames = frames;
1275 params.flags = flags;
1276 UNIX_CALL(release_render_buffer, &params);
1277 return params.result;
1280 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1281 AudioRenderClient_QueryInterface,
1282 AudioRenderClient_AddRef,
1283 AudioRenderClient_Release,
1284 AudioRenderClient_GetBuffer,
1285 AudioRenderClient_ReleaseBuffer
1288 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1289 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1291 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1292 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1294 if(!ppv)
1295 return E_POINTER;
1296 *ppv = NULL;
1298 if(IsEqualIID(riid, &IID_IUnknown) ||
1299 IsEqualIID(riid, &IID_IAudioCaptureClient))
1300 *ppv = iface;
1301 else if(IsEqualIID(riid, &IID_IMarshal))
1302 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
1304 if(*ppv){
1305 IUnknown_AddRef((IUnknown*)*ppv);
1306 return S_OK;
1309 WARN("Unknown interface %s\n", debugstr_guid(riid));
1310 return E_NOINTERFACE;
1313 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1315 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1316 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1319 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1321 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1322 return IAudioClient3_Release(&This->IAudioClient3_iface);
1325 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1326 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1327 UINT64 *qpcpos)
1329 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1330 struct get_capture_buffer_params params;
1332 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1333 devpos, qpcpos);
1335 if(!data)
1336 return E_POINTER;
1338 *data = NULL;
1340 if(!frames || !flags)
1341 return E_POINTER;
1343 params.stream = This->stream;
1344 params.data = data;
1345 params.frames = frames;
1346 params.flags = (UINT *)flags;
1347 params.devpos = devpos;
1348 params.qpcpos = qpcpos;
1349 UNIX_CALL(get_capture_buffer, &params);
1350 return params.result;
1353 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1354 IAudioCaptureClient *iface, UINT32 done)
1356 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1357 struct release_capture_buffer_params params;
1359 TRACE("(%p)->(%u)\n", This, done);
1361 params.stream = This->stream;
1362 params.done = done;
1363 UNIX_CALL(release_capture_buffer, &params);
1364 return params.result;
1367 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1368 IAudioCaptureClient *iface, UINT32 *frames)
1370 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1371 struct get_next_packet_size_params params;
1373 TRACE("(%p)->(%p)\n", This, frames);
1375 if(!frames)
1376 return E_POINTER;
1378 params.stream = This->stream;
1379 params.frames = frames;
1380 UNIX_CALL(get_next_packet_size, &params);
1381 return params.result;
1384 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1386 AudioCaptureClient_QueryInterface,
1387 AudioCaptureClient_AddRef,
1388 AudioCaptureClient_Release,
1389 AudioCaptureClient_GetBuffer,
1390 AudioCaptureClient_ReleaseBuffer,
1391 AudioCaptureClient_GetNextPacketSize
1394 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1395 REFIID riid, void **ppv)
1397 ACImpl *This = impl_from_IAudioClock(iface);
1399 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1401 if(!ppv)
1402 return E_POINTER;
1403 *ppv = NULL;
1405 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
1406 *ppv = iface;
1407 else if(IsEqualIID(riid, &IID_IAudioClock2))
1408 *ppv = &This->IAudioClock2_iface;
1409 if(*ppv){
1410 IUnknown_AddRef((IUnknown*)*ppv);
1411 return S_OK;
1414 WARN("Unknown interface %s\n", debugstr_guid(riid));
1415 return E_NOINTERFACE;
1418 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
1420 ACImpl *This = impl_from_IAudioClock(iface);
1421 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1424 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
1426 ACImpl *This = impl_from_IAudioClock(iface);
1427 return IAudioClient3_Release(&This->IAudioClient3_iface);
1430 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
1432 ACImpl *This = impl_from_IAudioClock(iface);
1433 struct get_frequency_params params;
1435 TRACE("(%p)->(%p)\n", This, freq);
1437 params.stream = This->stream;
1438 params.freq = freq;
1439 UNIX_CALL(get_frequency, &params);
1440 return params.result;
1443 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
1444 UINT64 *qpctime)
1446 ACImpl *This = impl_from_IAudioClock(iface);
1447 struct get_position_params params;
1449 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
1451 if(!pos)
1452 return E_POINTER;
1454 params.stream = This->stream;
1455 params.pos = pos;
1456 params.qpctime = qpctime;
1457 UNIX_CALL(get_position, &params);
1458 return params.result;
1461 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
1462 DWORD *chars)
1464 ACImpl *This = impl_from_IAudioClock(iface);
1466 TRACE("(%p)->(%p)\n", This, chars);
1468 if(!chars)
1469 return E_POINTER;
1471 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
1473 return S_OK;
1476 static const IAudioClockVtbl AudioClock_Vtbl =
1478 AudioClock_QueryInterface,
1479 AudioClock_AddRef,
1480 AudioClock_Release,
1481 AudioClock_GetFrequency,
1482 AudioClock_GetPosition,
1483 AudioClock_GetCharacteristics
1486 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
1487 REFIID riid, void **ppv)
1489 ACImpl *This = impl_from_IAudioClock2(iface);
1490 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
1493 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
1495 ACImpl *This = impl_from_IAudioClock2(iface);
1496 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1499 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
1501 ACImpl *This = impl_from_IAudioClock2(iface);
1502 return IAudioClient3_Release(&This->IAudioClient3_iface);
1505 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
1506 UINT64 *pos, UINT64 *qpctime)
1508 ACImpl *This = impl_from_IAudioClock2(iface);
1510 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
1512 return E_NOTIMPL;
1515 static const IAudioClock2Vtbl AudioClock2_Vtbl =
1517 AudioClock2_QueryInterface,
1518 AudioClock2_AddRef,
1519 AudioClock2_Release,
1520 AudioClock2_GetDevicePosition
1523 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
1525 AudioSessionWrapper *ret;
1527 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1528 sizeof(AudioSessionWrapper));
1529 if(!ret)
1530 return NULL;
1532 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
1533 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
1534 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
1536 ret->ref = 1;
1538 ret->client = client;
1539 if(client){
1540 ret->session = client->session;
1541 IAudioClient3_AddRef(&client->IAudioClient3_iface);
1544 return ret;
1547 static HRESULT WINAPI AudioSessionControl_QueryInterface(
1548 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
1550 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1552 if(!ppv)
1553 return E_POINTER;
1554 *ppv = NULL;
1556 if(IsEqualIID(riid, &IID_IUnknown) ||
1557 IsEqualIID(riid, &IID_IAudioSessionControl) ||
1558 IsEqualIID(riid, &IID_IAudioSessionControl2))
1559 *ppv = iface;
1560 if(*ppv){
1561 IUnknown_AddRef((IUnknown*)*ppv);
1562 return S_OK;
1565 WARN("Unknown interface %s\n", debugstr_guid(riid));
1566 return E_NOINTERFACE;
1569 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
1571 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1572 ULONG ref;
1573 ref = InterlockedIncrement(&This->ref);
1574 TRACE("(%p) Refcount now %lu\n", This, ref);
1575 return ref;
1578 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
1580 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1581 ULONG ref;
1583 EnterCriticalSection(&g_sessions_lock);
1585 ref = InterlockedDecrement(&This->ref);
1586 TRACE("(%p) Refcount now %lu\n", This, ref);
1587 if(!ref){
1588 if(This->client){
1589 This->client->session_wrapper = NULL;
1590 AudioClient_Release(&This->client->IAudioClient3_iface);
1592 HeapFree(GetProcessHeap(), 0, This);
1595 LeaveCriticalSection(&g_sessions_lock);
1596 return ref;
1599 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
1600 AudioSessionState *state)
1602 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1603 struct is_started_params params;
1604 ACImpl *client;
1606 TRACE("(%p)->(%p)\n", This, state);
1608 if(!state)
1609 return NULL_PTR_ERR;
1611 EnterCriticalSection(&g_sessions_lock);
1613 if(list_empty(&This->session->clients)){
1614 *state = AudioSessionStateExpired;
1615 LeaveCriticalSection(&g_sessions_lock);
1616 return S_OK;
1619 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
1620 params.stream = client->stream;
1621 UNIX_CALL(is_started, &params);
1622 if(params.result == S_OK){
1623 *state = AudioSessionStateActive;
1624 LeaveCriticalSection(&g_sessions_lock);
1625 return S_OK;
1629 LeaveCriticalSection(&g_sessions_lock);
1631 *state = AudioSessionStateInactive;
1633 return S_OK;
1636 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
1637 IAudioSessionControl2 *iface, WCHAR **name)
1639 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1641 FIXME("(%p)->(%p) - stub\n", This, name);
1643 return E_NOTIMPL;
1646 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
1647 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
1649 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1651 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
1653 return E_NOTIMPL;
1656 static HRESULT WINAPI AudioSessionControl_GetIconPath(
1657 IAudioSessionControl2 *iface, WCHAR **path)
1659 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1661 FIXME("(%p)->(%p) - stub\n", This, path);
1663 return E_NOTIMPL;
1666 static HRESULT WINAPI AudioSessionControl_SetIconPath(
1667 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
1669 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1671 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
1673 return E_NOTIMPL;
1676 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
1677 IAudioSessionControl2 *iface, GUID *group)
1679 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1681 FIXME("(%p)->(%p) - stub\n", This, group);
1683 return E_NOTIMPL;
1686 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
1687 IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
1689 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1691 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
1692 debugstr_guid(session));
1694 return E_NOTIMPL;
1697 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
1698 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
1700 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1702 FIXME("(%p)->(%p) - stub\n", This, events);
1704 return S_OK;
1707 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
1708 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
1710 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1712 FIXME("(%p)->(%p) - stub\n", This, events);
1714 return S_OK;
1717 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
1718 IAudioSessionControl2 *iface, WCHAR **id)
1720 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1722 FIXME("(%p)->(%p) - stub\n", This, id);
1724 return E_NOTIMPL;
1727 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
1728 IAudioSessionControl2 *iface, WCHAR **id)
1730 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1732 FIXME("(%p)->(%p) - stub\n", This, id);
1734 return E_NOTIMPL;
1737 static HRESULT WINAPI AudioSessionControl_GetProcessId(
1738 IAudioSessionControl2 *iface, DWORD *pid)
1740 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1742 TRACE("(%p)->(%p)\n", This, pid);
1744 if(!pid)
1745 return E_POINTER;
1747 *pid = GetCurrentProcessId();
1749 return S_OK;
1752 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
1753 IAudioSessionControl2 *iface)
1755 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1757 TRACE("(%p)\n", This);
1759 return S_FALSE;
1762 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
1763 IAudioSessionControl2 *iface, BOOL optout)
1765 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1767 TRACE("(%p)->(%d)\n", This, optout);
1769 return S_OK;
1772 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
1774 AudioSessionControl_QueryInterface,
1775 AudioSessionControl_AddRef,
1776 AudioSessionControl_Release,
1777 AudioSessionControl_GetState,
1778 AudioSessionControl_GetDisplayName,
1779 AudioSessionControl_SetDisplayName,
1780 AudioSessionControl_GetIconPath,
1781 AudioSessionControl_SetIconPath,
1782 AudioSessionControl_GetGroupingParam,
1783 AudioSessionControl_SetGroupingParam,
1784 AudioSessionControl_RegisterAudioSessionNotification,
1785 AudioSessionControl_UnregisterAudioSessionNotification,
1786 AudioSessionControl_GetSessionIdentifier,
1787 AudioSessionControl_GetSessionInstanceIdentifier,
1788 AudioSessionControl_GetProcessId,
1789 AudioSessionControl_IsSystemSoundsSession,
1790 AudioSessionControl_SetDuckingPreference
1793 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
1794 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
1796 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1798 if(!ppv)
1799 return E_POINTER;
1800 *ppv = NULL;
1802 if(IsEqualIID(riid, &IID_IUnknown) ||
1803 IsEqualIID(riid, &IID_ISimpleAudioVolume))
1804 *ppv = iface;
1805 if(*ppv){
1806 IUnknown_AddRef((IUnknown*)*ppv);
1807 return S_OK;
1810 WARN("Unknown interface %s\n", debugstr_guid(riid));
1811 return E_NOINTERFACE;
1814 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
1816 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1817 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
1820 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
1822 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1823 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
1826 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
1827 ISimpleAudioVolume *iface, float level, const GUID *context)
1829 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1830 AudioSession *session = This->session;
1831 ACImpl *client;
1833 TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
1835 if(level < 0.f || level > 1.f)
1836 return E_INVALIDARG;
1838 if(context)
1839 FIXME("Notifications not supported yet\n");
1841 EnterCriticalSection(&g_sessions_lock);
1843 session->master_vol = level;
1845 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
1846 set_stream_volumes(client, -1);
1848 LeaveCriticalSection(&g_sessions_lock);
1850 return S_OK;
1853 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
1854 ISimpleAudioVolume *iface, float *level)
1856 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1857 AudioSession *session = This->session;
1859 TRACE("(%p)->(%p)\n", session, level);
1861 if(!level)
1862 return NULL_PTR_ERR;
1864 *level = session->master_vol;
1866 return S_OK;
1869 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
1870 BOOL mute, const GUID *context)
1872 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1873 AudioSession *session = This->session;
1874 ACImpl *client;
1876 TRACE("(%p)->(%u, %s)\n", session, mute, debugstr_guid(context));
1878 if(context)
1879 FIXME("Notifications not supported yet\n");
1881 EnterCriticalSection(&g_sessions_lock);
1883 session->mute = mute;
1885 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
1886 set_stream_volumes(client, -1);
1888 LeaveCriticalSection(&g_sessions_lock);
1890 return S_OK;
1893 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
1894 BOOL *mute)
1896 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1897 AudioSession *session = This->session;
1899 TRACE("(%p)->(%p)\n", session, mute);
1901 if(!mute)
1902 return NULL_PTR_ERR;
1904 *mute = session->mute;
1906 return S_OK;
1909 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
1911 SimpleAudioVolume_QueryInterface,
1912 SimpleAudioVolume_AddRef,
1913 SimpleAudioVolume_Release,
1914 SimpleAudioVolume_SetMasterVolume,
1915 SimpleAudioVolume_GetMasterVolume,
1916 SimpleAudioVolume_SetMute,
1917 SimpleAudioVolume_GetMute
1920 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
1921 IAudioStreamVolume *iface, REFIID riid, void **ppv)
1923 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1925 if(!ppv)
1926 return E_POINTER;
1927 *ppv = NULL;
1929 if(IsEqualIID(riid, &IID_IUnknown) ||
1930 IsEqualIID(riid, &IID_IAudioStreamVolume))
1931 *ppv = iface;
1932 if(*ppv){
1933 IUnknown_AddRef((IUnknown*)*ppv);
1934 return S_OK;
1937 WARN("Unknown interface %s\n", debugstr_guid(riid));
1938 return E_NOINTERFACE;
1941 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
1943 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1944 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1947 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
1949 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1950 return IAudioClient3_Release(&This->IAudioClient3_iface);
1953 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
1954 IAudioStreamVolume *iface, UINT32 *out)
1956 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1958 TRACE("(%p)->(%p)\n", This, out);
1960 if(!out)
1961 return E_POINTER;
1963 *out = This->channel_count;
1965 return S_OK;
1968 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
1969 IAudioStreamVolume *iface, UINT32 index, float level)
1971 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1973 TRACE("(%p)->(%d, %f)\n", This, index, level);
1975 if(level < 0.f || level > 1.f)
1976 return E_INVALIDARG;
1978 if(index >= This->channel_count)
1979 return E_INVALIDARG;
1981 EnterCriticalSection(&g_sessions_lock);
1983 This->vols[index] = level;
1985 WARN("CoreAudio doesn't support per-channel volume control\n");
1986 set_stream_volumes(This, index);
1988 LeaveCriticalSection(&g_sessions_lock);
1990 return S_OK;
1993 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
1994 IAudioStreamVolume *iface, UINT32 index, float *level)
1996 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1998 TRACE("(%p)->(%d, %p)\n", This, index, level);
2000 if(!level)
2001 return E_POINTER;
2003 if(index >= This->channel_count)
2004 return E_INVALIDARG;
2006 *level = This->vols[index];
2008 return S_OK;
2011 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2012 IAudioStreamVolume *iface, UINT32 count, const float *levels)
2014 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2015 UINT32 i;
2017 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2019 if(!levels)
2020 return E_POINTER;
2022 if(count != This->channel_count)
2023 return E_INVALIDARG;
2025 EnterCriticalSection(&g_sessions_lock);
2027 for(i = 0; i < count; ++i)
2028 This->vols[i] = levels[i];
2030 set_stream_volumes(This, -1);
2032 LeaveCriticalSection(&g_sessions_lock);
2034 return S_OK;
2037 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2038 IAudioStreamVolume *iface, UINT32 count, float *levels)
2040 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2041 UINT32 i;
2043 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2045 if(!levels)
2046 return E_POINTER;
2048 if(count != This->channel_count)
2049 return E_INVALIDARG;
2051 EnterCriticalSection(&g_sessions_lock);
2053 for(i = 0; i < count; ++i)
2054 levels[i] = This->vols[i];
2056 LeaveCriticalSection(&g_sessions_lock);
2058 return S_OK;
2061 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2063 AudioStreamVolume_QueryInterface,
2064 AudioStreamVolume_AddRef,
2065 AudioStreamVolume_Release,
2066 AudioStreamVolume_GetChannelCount,
2067 AudioStreamVolume_SetChannelVolume,
2068 AudioStreamVolume_GetChannelVolume,
2069 AudioStreamVolume_SetAllVolumes,
2070 AudioStreamVolume_GetAllVolumes
2073 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2074 IChannelAudioVolume *iface, REFIID riid, void **ppv)
2076 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2078 if(!ppv)
2079 return E_POINTER;
2080 *ppv = NULL;
2082 if(IsEqualIID(riid, &IID_IUnknown) ||
2083 IsEqualIID(riid, &IID_IChannelAudioVolume))
2084 *ppv = iface;
2085 if(*ppv){
2086 IUnknown_AddRef((IUnknown*)*ppv);
2087 return S_OK;
2090 WARN("Unknown interface %s\n", debugstr_guid(riid));
2091 return E_NOINTERFACE;
2094 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2096 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2097 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2100 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2102 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2103 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2106 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2107 IChannelAudioVolume *iface, UINT32 *out)
2109 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2110 AudioSession *session = This->session;
2112 TRACE("(%p)->(%p)\n", session, out);
2114 if(!out)
2115 return NULL_PTR_ERR;
2117 *out = session->channel_count;
2119 return S_OK;
2122 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2123 IChannelAudioVolume *iface, UINT32 index, float level,
2124 const GUID *context)
2126 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2127 AudioSession *session = This->session;
2128 ACImpl *client;
2130 TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2131 wine_dbgstr_guid(context));
2133 if(level < 0.f || level > 1.f)
2134 return E_INVALIDARG;
2136 if(index >= session->channel_count)
2137 return E_INVALIDARG;
2139 if(context)
2140 FIXME("Notifications not supported yet\n");
2142 EnterCriticalSection(&g_sessions_lock);
2144 session->channel_vols[index] = level;
2146 WARN("CoreAudio doesn't support per-channel volume control\n");
2147 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
2148 set_stream_volumes(client, index);
2150 LeaveCriticalSection(&g_sessions_lock);
2152 return S_OK;
2155 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2156 IChannelAudioVolume *iface, UINT32 index, float *level)
2158 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2159 AudioSession *session = This->session;
2161 TRACE("(%p)->(%d, %p)\n", session, index, level);
2163 if(!level)
2164 return NULL_PTR_ERR;
2166 if(index >= session->channel_count)
2167 return E_INVALIDARG;
2169 *level = session->channel_vols[index];
2171 return S_OK;
2174 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2175 IChannelAudioVolume *iface, UINT32 count, const float *levels,
2176 const GUID *context)
2178 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2179 AudioSession *session = This->session;
2180 ACImpl *client;
2181 UINT32 i;
2183 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2184 wine_dbgstr_guid(context));
2186 if(!levels)
2187 return NULL_PTR_ERR;
2189 if(count != session->channel_count)
2190 return E_INVALIDARG;
2192 if(context)
2193 FIXME("Notifications not supported yet\n");
2195 EnterCriticalSection(&g_sessions_lock);
2197 for(i = 0; i < count; ++i)
2198 session->channel_vols[i] = levels[i];
2200 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
2201 set_stream_volumes(client, -1);
2203 LeaveCriticalSection(&g_sessions_lock);
2205 return S_OK;
2208 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2209 IChannelAudioVolume *iface, UINT32 count, float *levels)
2211 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2212 AudioSession *session = This->session;
2213 int i;
2215 TRACE("(%p)->(%d, %p)\n", session, count, levels);
2217 if(!levels)
2218 return NULL_PTR_ERR;
2220 if(count != session->channel_count)
2221 return E_INVALIDARG;
2223 for(i = 0; i < count; ++i)
2224 levels[i] = session->channel_vols[i];
2226 return S_OK;
2229 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2231 ChannelAudioVolume_QueryInterface,
2232 ChannelAudioVolume_AddRef,
2233 ChannelAudioVolume_Release,
2234 ChannelAudioVolume_GetChannelCount,
2235 ChannelAudioVolume_SetChannelVolume,
2236 ChannelAudioVolume_GetChannelVolume,
2237 ChannelAudioVolume_SetAllVolumes,
2238 ChannelAudioVolume_GetAllVolumes
2241 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2242 REFIID riid, void **ppv)
2244 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2246 if(!ppv)
2247 return E_POINTER;
2248 *ppv = NULL;
2250 if(IsEqualIID(riid, &IID_IUnknown) ||
2251 IsEqualIID(riid, &IID_IAudioSessionManager) ||
2252 IsEqualIID(riid, &IID_IAudioSessionManager2))
2253 *ppv = iface;
2254 if(*ppv){
2255 IUnknown_AddRef((IUnknown*)*ppv);
2256 return S_OK;
2259 WARN("Unknown interface %s\n", debugstr_guid(riid));
2260 return E_NOINTERFACE;
2263 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2265 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2266 ULONG ref;
2267 ref = InterlockedIncrement(&This->ref);
2268 TRACE("(%p) Refcount now %lu\n", This, ref);
2269 return ref;
2272 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2274 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2275 ULONG ref;
2276 ref = InterlockedDecrement(&This->ref);
2277 TRACE("(%p) Refcount now %lu\n", This, ref);
2278 if(!ref)
2279 HeapFree(GetProcessHeap(), 0, This);
2280 return ref;
2283 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2284 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2285 IAudioSessionControl **out)
2287 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2288 AudioSession *session;
2289 AudioSessionWrapper *wrapper;
2290 HRESULT hr;
2292 TRACE("(%p)->(%s, %lx, %p)\n", This, debugstr_guid(session_guid),
2293 flags, out);
2295 hr = get_audio_session(session_guid, This->device, 0, &session);
2296 if(FAILED(hr))
2297 return hr;
2299 wrapper = AudioSessionWrapper_Create(NULL);
2300 if(!wrapper)
2301 return E_OUTOFMEMORY;
2303 wrapper->session = session;
2305 *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
2307 return S_OK;
2310 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
2311 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2312 ISimpleAudioVolume **out)
2314 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2315 AudioSession *session;
2316 AudioSessionWrapper *wrapper;
2317 HRESULT hr;
2319 TRACE("(%p)->(%s, %lx, %p)\n", This, debugstr_guid(session_guid),
2320 flags, out);
2322 hr = get_audio_session(session_guid, This->device, 0, &session);
2323 if(FAILED(hr))
2324 return hr;
2326 wrapper = AudioSessionWrapper_Create(NULL);
2327 if(!wrapper)
2328 return E_OUTOFMEMORY;
2330 wrapper->session = session;
2332 *out = &wrapper->ISimpleAudioVolume_iface;
2334 return S_OK;
2337 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
2338 IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
2340 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2341 FIXME("(%p)->(%p) - stub\n", This, out);
2342 return E_NOTIMPL;
2345 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
2346 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2348 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2349 FIXME("(%p)->(%p) - stub\n", This, notification);
2350 return E_NOTIMPL;
2353 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
2354 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2356 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2357 FIXME("(%p)->(%p) - stub\n", This, notification);
2358 return E_NOTIMPL;
2361 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
2362 IAudioSessionManager2 *iface, const WCHAR *session_id,
2363 IAudioVolumeDuckNotification *notification)
2365 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2366 FIXME("(%p)->(%p) - stub\n", This, notification);
2367 return E_NOTIMPL;
2370 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
2371 IAudioSessionManager2 *iface,
2372 IAudioVolumeDuckNotification *notification)
2374 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2375 FIXME("(%p)->(%p) - stub\n", This, notification);
2376 return E_NOTIMPL;
2379 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
2381 AudioSessionManager_QueryInterface,
2382 AudioSessionManager_AddRef,
2383 AudioSessionManager_Release,
2384 AudioSessionManager_GetAudioSessionControl,
2385 AudioSessionManager_GetSimpleAudioVolume,
2386 AudioSessionManager_GetSessionEnumerator,
2387 AudioSessionManager_RegisterSessionNotification,
2388 AudioSessionManager_UnregisterSessionNotification,
2389 AudioSessionManager_RegisterDuckNotification,
2390 AudioSessionManager_UnregisterDuckNotification
2393 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
2394 IAudioSessionManager2 **out)
2396 SessionMgr *This;
2398 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
2399 if(!This)
2400 return E_OUTOFMEMORY;
2402 This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
2403 This->device = device;
2404 This->ref = 1;
2406 *out = &This->IAudioSessionManager2_iface;
2408 return S_OK;