dbghelp: Use RtlGetVersion() for system version detection instead.
[wine.git] / dlls / winecoreaudio.drv / mmdevdrv.c
blobda6c05bdc1f1e6d270ac42958c8f40ba16499ecb
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 unixlib_handle_t coreaudio_handle = 0;
48 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
50 static const REFERENCE_TIME DefaultPeriod = 100000;
51 static const REFERENCE_TIME MinimumPeriod = 50000;
53 struct ACImpl;
54 typedef struct ACImpl ACImpl;
56 typedef struct _AudioSession {
57 GUID guid;
58 struct list clients;
60 IMMDevice *device;
62 float master_vol;
63 UINT32 channel_count;
64 float *channel_vols;
65 BOOL mute;
67 struct list entry;
68 } AudioSession;
70 typedef struct _AudioSessionWrapper {
71 IAudioSessionControl2 IAudioSessionControl2_iface;
72 IChannelAudioVolume IChannelAudioVolume_iface;
73 ISimpleAudioVolume ISimpleAudioVolume_iface;
75 LONG ref;
77 ACImpl *client;
78 AudioSession *session;
79 } AudioSessionWrapper;
81 struct ACImpl {
82 IAudioClient3 IAudioClient3_iface;
83 IAudioRenderClient IAudioRenderClient_iface;
84 IAudioCaptureClient IAudioCaptureClient_iface;
85 IAudioClock IAudioClock_iface;
86 IAudioClock2 IAudioClock2_iface;
87 IAudioStreamVolume IAudioStreamVolume_iface;
89 LONG ref;
91 IMMDevice *parent;
92 IUnknown *pUnkFTMarshal;
94 EDataFlow dataflow;
95 UINT32 channel_count, period_ms;
96 DWORD flags;
97 HANDLE event;
98 float *vols;
100 DWORD dev_id;
101 HANDLE timer;
103 AudioSession *session;
104 AudioSessionWrapper *session_wrapper;
106 stream_handle stream;
107 struct list entry;
110 static const IAudioClient3Vtbl AudioClient3_Vtbl;
111 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
112 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
113 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
114 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
115 static const IAudioClockVtbl AudioClock_Vtbl;
116 static const IAudioClock2Vtbl AudioClock2_Vtbl;
117 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
118 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
119 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl;
121 typedef struct _SessionMgr {
122 IAudioSessionManager2 IAudioSessionManager2_iface;
124 LONG ref;
126 IMMDevice *device;
127 } SessionMgr;
129 static const WCHAR *drv_key_devicesW = L"Software\\Wine\\Drivers\\winecoreaudio.drv\\devices";
131 static HANDLE g_timer_q;
133 static CRITICAL_SECTION g_sessions_lock;
134 static CRITICAL_SECTION_DEBUG g_sessions_lock_debug =
136 0, 0, &g_sessions_lock,
137 { &g_sessions_lock_debug.ProcessLocksList, &g_sessions_lock_debug.ProcessLocksList },
138 0, 0, { (DWORD_PTR)(__FILE__ ": g_sessions_lock") }
140 static CRITICAL_SECTION g_sessions_lock = { &g_sessions_lock_debug, -1, 0, 0, 0, 0 };
141 static struct list g_sessions = LIST_INIT(g_sessions);
143 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
145 static inline ACImpl *impl_from_IAudioClient3(IAudioClient3 *iface)
147 return CONTAINING_RECORD(iface, ACImpl, IAudioClient3_iface);
150 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
152 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
155 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
157 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
160 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
162 return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
165 static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
167 return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
170 static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
172 return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
175 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
177 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
180 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
182 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
185 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
187 return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
190 static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface)
192 return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface);
195 BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
197 switch (reason)
199 case DLL_PROCESS_ATTACH:
200 if(NtQueryVirtualMemory(GetCurrentProcess(), dll, MemoryWineUnixFuncs,
201 &coreaudio_handle, sizeof(coreaudio_handle), NULL))
202 return FALSE;
203 g_timer_q = CreateTimerQueue();
204 if(!g_timer_q)
205 return FALSE;
206 break;
208 case DLL_PROCESS_DETACH:
209 if (reserved) break;
210 DeleteCriticalSection(&g_sessions_lock);
211 break;
213 return TRUE;
216 /* From <dlls/mmdevapi/mmdevapi.h> */
217 enum DriverPriority {
218 Priority_Unavailable = 0,
219 Priority_Low,
220 Priority_Neutral,
221 Priority_Preferred
224 int WINAPI AUDDRV_GetPriority(void)
226 return Priority_Neutral;
229 static void set_device_guid(EDataFlow flow, HKEY drv_key, const WCHAR *key_name,
230 GUID *guid)
232 HKEY key;
233 BOOL opened = FALSE;
234 LONG lr;
236 if(!drv_key){
237 lr = RegCreateKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, NULL, 0, KEY_WRITE,
238 NULL, &drv_key, NULL);
239 if(lr != ERROR_SUCCESS){
240 ERR("RegCreateKeyEx(drv_key) failed: %lu\n", lr);
241 return;
243 opened = TRUE;
246 lr = RegCreateKeyExW(drv_key, key_name, 0, NULL, 0, KEY_WRITE,
247 NULL, &key, NULL);
248 if(lr != ERROR_SUCCESS){
249 ERR("RegCreateKeyEx(%s) failed: %lu\n", wine_dbgstr_w(key_name), lr);
250 goto exit;
253 lr = RegSetValueExW(key, L"guid", 0, REG_BINARY, (BYTE*)guid,
254 sizeof(GUID));
255 if(lr != ERROR_SUCCESS)
256 ERR("RegSetValueEx(%s\\guid) failed: %lu\n", wine_dbgstr_w(key_name), lr);
258 RegCloseKey(key);
259 exit:
260 if(opened)
261 RegCloseKey(drv_key);
264 static void get_device_guid(EDataFlow flow, DWORD device_id, GUID *guid)
266 HKEY key = NULL, dev_key;
267 DWORD type, size = sizeof(*guid);
268 WCHAR key_name[256];
270 if(flow == eCapture)
271 key_name[0] = '1';
272 else
273 key_name[0] = '0';
274 key_name[1] = ',';
276 swprintf(key_name + 2, ARRAY_SIZE(key_name), L"%u", device_id);
278 if(RegOpenKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, KEY_WRITE|KEY_READ, &key) == ERROR_SUCCESS){
279 if(RegOpenKeyExW(key, key_name, 0, KEY_READ, &dev_key) == ERROR_SUCCESS){
280 if(RegQueryValueExW(dev_key, L"guid", 0, &type,
281 (BYTE*)guid, &size) == ERROR_SUCCESS){
282 if(type == REG_BINARY){
283 RegCloseKey(dev_key);
284 RegCloseKey(key);
285 return;
287 ERR("Invalid type for device %s GUID: %lu; ignoring and overwriting\n",
288 wine_dbgstr_w(key_name), type);
290 RegCloseKey(dev_key);
294 CoCreateGuid(guid);
296 set_device_guid(flow, key, key_name, guid);
298 if(key)
299 RegCloseKey(key);
302 static void set_stream_volumes(ACImpl *This, int channel)
304 struct set_volumes_params params;
306 params.stream = This->stream;
307 params.master_volume = This->session->mute ? 0.0f : This->session->master_vol;
308 params.volumes = This->vols;
309 params.session_volumes = This->session->channel_vols;
310 params.channel = channel;
312 UNIX_CALL(set_volumes, &params);
315 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids_out,
316 GUID **guids_out, UINT *num, UINT *def_index)
318 struct get_endpoint_ids_params params;
319 unsigned int i;
320 GUID *guids = NULL;
321 WCHAR **ids = NULL;
323 TRACE("%d %p %p %p\n", flow, ids_out, num, def_index);
325 params.flow = flow;
326 params.size = 1000;
327 params.endpoints = NULL;
329 heap_free(params.endpoints);
330 params.endpoints = heap_alloc(params.size);
331 UNIX_CALL(get_endpoint_ids, &params);
332 }while(params.result == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
334 if(FAILED(params.result)) goto end;
336 ids = heap_alloc_zero(params.num * sizeof(*ids));
337 guids = heap_alloc(params.num * sizeof(*guids));
338 if(!ids || !guids){
339 params.result = E_OUTOFMEMORY;
340 goto end;
343 for(i = 0; i < params.num; i++){
344 WCHAR *name = (WCHAR *)((char *)params.endpoints + params.endpoints[i].name);
345 int size = (wcslen(name) + 1) * sizeof(WCHAR);
347 ids[i] = heap_alloc(size);
348 if(!ids[i]){
349 params.result = E_OUTOFMEMORY;
350 goto end;
352 memcpy(ids[i], name, size);
353 get_device_guid(flow, params.endpoints[i].id, guids + i);
355 *def_index = params.default_idx;
357 end:
358 heap_free(params.endpoints);
359 if(FAILED(params.result)){
360 heap_free(guids);
361 if(ids){
362 for(i = 0; i < params.num; i++) heap_free(ids[i]);
363 heap_free(ids);
365 }else{
366 *ids_out = ids;
367 *guids_out = guids;
368 *num = params.num;
371 return params.result;
374 static BOOL get_deviceid_by_guid(GUID *guid, DWORD *id, EDataFlow *flow)
376 HKEY devices_key;
377 UINT i = 0;
378 WCHAR key_name[256];
379 DWORD key_name_size;
381 if(RegOpenKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, KEY_READ, &devices_key) != ERROR_SUCCESS){
382 ERR("No devices in registry?\n");
383 return FALSE;
386 while(1){
387 HKEY key;
388 DWORD size, type;
389 GUID reg_guid;
391 key_name_size = sizeof(key_name);
392 if(RegEnumKeyExW(devices_key, i++, key_name, &key_name_size, NULL,
393 NULL, NULL, NULL) != ERROR_SUCCESS)
394 break;
396 if(RegOpenKeyExW(devices_key, key_name, 0, KEY_READ, &key) != ERROR_SUCCESS){
397 WARN("Couldn't open key: %s\n", wine_dbgstr_w(key_name));
398 continue;
401 size = sizeof(reg_guid);
402 if(RegQueryValueExW(key, L"guid", 0, &type,
403 (BYTE*)&reg_guid, &size) == ERROR_SUCCESS){
404 if(IsEqualGUID(&reg_guid, guid)){
405 RegCloseKey(key);
406 RegCloseKey(devices_key);
408 TRACE("Found matching device key: %s\n", wine_dbgstr_w(key_name));
410 if(key_name[0] == '0')
411 *flow = eRender;
412 else if(key_name[0] == '1')
413 *flow = eCapture;
414 else{
415 ERR("Unknown device type: %c\n", key_name[0]);
416 return FALSE;
419 *id = wcstoul(key_name + 2, NULL, 10);
421 return TRUE;
425 RegCloseKey(key);
428 RegCloseKey(devices_key);
430 WARN("No matching device in registry for GUID %s\n", debugstr_guid(guid));
432 return FALSE;
435 HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient **out)
437 ACImpl *This;
438 DWORD dev_id;
439 EDataFlow dataflow;
440 HRESULT hr;
442 TRACE("%s %p %p\n", debugstr_guid(guid), dev, out);
444 if(!get_deviceid_by_guid(guid, &dev_id, &dataflow))
445 return AUDCLNT_E_DEVICE_INVALIDATED;
447 if(dataflow != eRender && dataflow != eCapture)
448 return E_INVALIDARG;
450 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACImpl));
451 if(!This)
452 return E_OUTOFMEMORY;
454 This->IAudioClient3_iface.lpVtbl = &AudioClient3_Vtbl;
455 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
456 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
457 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
458 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
459 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
461 This->dataflow = dataflow;
463 hr = CoCreateFreeThreadedMarshaler((IUnknown *)&This->IAudioClient3_iface, &This->pUnkFTMarshal);
464 if (FAILED(hr)) {
465 HeapFree(GetProcessHeap(), 0, This);
466 return hr;
469 This->parent = dev;
470 IMMDevice_AddRef(This->parent);
472 This->dev_id = dev_id;
474 *out = (IAudioClient *)&This->IAudioClient3_iface;
475 IAudioClient3_AddRef(&This->IAudioClient3_iface);
477 return S_OK;
480 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient3 *iface,
481 REFIID riid, void **ppv)
483 ACImpl *This = impl_from_IAudioClient3(iface);
484 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
486 if(!ppv)
487 return E_POINTER;
488 *ppv = NULL;
489 if(IsEqualIID(riid, &IID_IUnknown) ||
490 IsEqualIID(riid, &IID_IAudioClient) ||
491 IsEqualIID(riid, &IID_IAudioClient2) ||
492 IsEqualIID(riid, &IID_IAudioClient3))
493 *ppv = iface;
494 else if(IsEqualIID(riid, &IID_IMarshal))
495 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
497 if(*ppv){
498 IUnknown_AddRef((IUnknown*)*ppv);
499 return S_OK;
501 WARN("Unknown interface %s\n", debugstr_guid(riid));
502 return E_NOINTERFACE;
505 static ULONG WINAPI AudioClient_AddRef(IAudioClient3 *iface)
507 ACImpl *This = impl_from_IAudioClient3(iface);
508 ULONG ref;
509 ref = InterlockedIncrement(&This->ref);
510 TRACE("(%p) Refcount now %lu\n", This, ref);
511 return ref;
514 static ULONG WINAPI AudioClient_Release(IAudioClient3 *iface)
516 ACImpl *This = impl_from_IAudioClient3(iface);
517 struct release_stream_params params;
518 ULONG ref;
520 ref = InterlockedDecrement(&This->ref);
521 TRACE("(%p) Refcount now %lu\n", This, ref);
522 if(!ref){
523 if(This->timer){
524 HANDLE event;
525 BOOL wait;
526 event = CreateEventW(NULL, TRUE, FALSE, NULL);
527 wait = !DeleteTimerQueueTimer(g_timer_q, This->timer, event);
528 wait = wait && GetLastError() == ERROR_IO_PENDING;
529 if(event && wait)
530 WaitForSingleObject(event, INFINITE);
531 CloseHandle(event);
533 if(This->stream){
534 params.stream = This->stream;
535 UNIX_CALL(release_stream, &params);
537 if(This->session){
538 EnterCriticalSection(&g_sessions_lock);
539 list_remove(&This->entry);
540 LeaveCriticalSection(&g_sessions_lock);
542 HeapFree(GetProcessHeap(), 0, This->vols);
543 IMMDevice_Release(This->parent);
544 IUnknown_Release(This->pUnkFTMarshal);
545 HeapFree(GetProcessHeap(), 0, This);
547 return ref;
550 static void dump_fmt(const WAVEFORMATEX *fmt)
552 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
553 switch(fmt->wFormatTag){
554 case WAVE_FORMAT_PCM:
555 TRACE("WAVE_FORMAT_PCM");
556 break;
557 case WAVE_FORMAT_IEEE_FLOAT:
558 TRACE("WAVE_FORMAT_IEEE_FLOAT");
559 break;
560 case WAVE_FORMAT_EXTENSIBLE:
561 TRACE("WAVE_FORMAT_EXTENSIBLE");
562 break;
563 default:
564 TRACE("Unknown");
565 break;
567 TRACE(")\n");
569 TRACE("nChannels: %u\n", fmt->nChannels);
570 TRACE("nSamplesPerSec: %lu\n", fmt->nSamplesPerSec);
571 TRACE("nAvgBytesPerSec: %lu\n", fmt->nAvgBytesPerSec);
572 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
573 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
574 TRACE("cbSize: %u\n", fmt->cbSize);
576 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
577 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
578 TRACE("dwChannelMask: %08lx\n", fmtex->dwChannelMask);
579 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
580 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
584 static void session_init_vols(AudioSession *session, UINT channels)
586 if(session->channel_count < channels){
587 UINT i;
589 if(session->channel_vols)
590 session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
591 session->channel_vols, sizeof(float) * channels);
592 else
593 session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
594 sizeof(float) * channels);
595 if(!session->channel_vols)
596 return;
598 for(i = session->channel_count; i < channels; ++i)
599 session->channel_vols[i] = 1.f;
601 session->channel_count = channels;
605 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
606 UINT num_channels)
608 AudioSession *ret;
610 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
611 if(!ret)
612 return NULL;
614 memcpy(&ret->guid, guid, sizeof(GUID));
616 ret->device = device;
618 list_init(&ret->clients);
620 list_add_head(&g_sessions, &ret->entry);
622 session_init_vols(ret, num_channels);
624 ret->master_vol = 1.f;
626 return ret;
629 /* if channels == 0, then this will return or create a session with
630 * matching dataflow and GUID. otherwise, channels must also match */
631 static HRESULT get_audio_session(const GUID *sessionguid,
632 IMMDevice *device, UINT channels, AudioSession **out)
634 AudioSession *session;
636 if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
637 *out = create_session(&GUID_NULL, device, channels);
638 if(!*out)
639 return E_OUTOFMEMORY;
641 return S_OK;
644 *out = NULL;
645 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
646 if(session->device == device &&
647 IsEqualGUID(sessionguid, &session->guid)){
648 session_init_vols(session, channels);
649 *out = session;
650 break;
654 if(!*out){
655 *out = create_session(sessionguid, device, channels);
656 if(!*out)
657 return E_OUTOFMEMORY;
660 return S_OK;
663 static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
664 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
665 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
666 const GUID *sessionguid)
668 ACImpl *This = impl_from_IAudioClient3(iface);
669 struct release_stream_params release_params;
670 struct create_stream_params params;
671 stream_handle stream;
672 UINT32 i;
674 TRACE("(%p)->(%x, %lx, %s, %s, %p, %s)\n", This, mode, flags,
675 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
677 if(!fmt)
678 return E_POINTER;
680 dump_fmt(fmt);
682 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
683 return E_INVALIDARG;
685 if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
686 AUDCLNT_STREAMFLAGS_LOOPBACK |
687 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
688 AUDCLNT_STREAMFLAGS_NOPERSIST |
689 AUDCLNT_STREAMFLAGS_RATEADJUST |
690 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
691 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
692 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED |
693 AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY |
694 AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM)){
695 FIXME("Unknown flags: %08lx\n", flags);
696 return E_INVALIDARG;
699 if(mode == AUDCLNT_SHAREMODE_SHARED){
700 period = DefaultPeriod;
701 if( duration < 3 * period)
702 duration = 3 * period;
703 }else{
704 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
705 if(((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask == 0 ||
706 ((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask & SPEAKER_RESERVED)
707 return AUDCLNT_E_UNSUPPORTED_FORMAT;
710 if(!period)
711 period = DefaultPeriod; /* not minimum */
712 if(period < MinimumPeriod || period > 5000000)
713 return AUDCLNT_E_INVALID_DEVICE_PERIOD;
714 if(duration > 20000000) /* the smaller the period, the lower this limit */
715 return AUDCLNT_E_BUFFER_SIZE_ERROR;
716 if(flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK){
717 if(duration != period)
718 return AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL;
719 FIXME("EXCLUSIVE mode with EVENTCALLBACK\n");
720 return AUDCLNT_E_DEVICE_IN_USE;
721 }else{
722 if( duration < 8 * period)
723 duration = 8 * period; /* may grow above 2s */
727 EnterCriticalSection(&g_sessions_lock);
729 if(This->stream){
730 LeaveCriticalSection(&g_sessions_lock);
731 return AUDCLNT_E_ALREADY_INITIALIZED;
734 params.dev_id = This->dev_id;
735 params.flow = This->dataflow;
736 params.share = mode;
737 params.duration = duration;
738 params.period = period;
739 params.fmt = fmt;
740 params.stream = &stream;
742 UNIX_CALL(create_stream, &params);
743 if(FAILED(params.result)){
744 LeaveCriticalSection(&g_sessions_lock);
745 return params.result;
748 This->flags = flags;
749 This->channel_count = fmt->nChannels;
750 This->period_ms = period / 10000;
752 This->vols = HeapAlloc(GetProcessHeap(), 0, This->channel_count * sizeof(float));
753 if(!This->vols){
754 params.result = E_OUTOFMEMORY;
755 goto end;
758 for(i = 0; i < This->channel_count; ++i)
759 This->vols[i] = 1.f;
761 params.result = get_audio_session(sessionguid, This->parent, fmt->nChannels, &This->session);
762 if(FAILED(params.result)) goto end;
764 list_add_tail(&This->session->clients, &This->entry);
766 end:
767 if(FAILED(params.result)){
768 release_params.stream = stream;
769 UNIX_CALL(release_stream, &release_params);
770 HeapFree(GetProcessHeap(), 0, This->vols);
771 This->vols = NULL;
772 }else{
773 This->stream = stream;
774 set_stream_volumes(This, -1);
777 LeaveCriticalSection(&g_sessions_lock);
779 return params.result;
782 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient3 *iface,
783 UINT32 *frames)
785 ACImpl *This = impl_from_IAudioClient3(iface);
786 struct get_buffer_size_params params;
788 TRACE("(%p)->(%p)\n", This, frames);
790 if(!frames)
791 return E_POINTER;
793 if(!This->stream)
794 return AUDCLNT_E_NOT_INITIALIZED;
796 params.stream = This->stream;
797 params.frames = frames;
798 UNIX_CALL(get_buffer_size, &params);
799 return params.result;
802 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient3 *iface,
803 REFERENCE_TIME *out)
805 ACImpl *This = impl_from_IAudioClient3(iface);
806 struct get_latency_params params;
808 TRACE("(%p)->(%p)\n", This, out);
810 if(!out)
811 return E_POINTER;
813 if(!This->stream)
814 return AUDCLNT_E_NOT_INITIALIZED;
816 params.stream = This->stream;
817 params.latency = out;
818 UNIX_CALL(get_latency, &params);
819 return params.result;
822 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient3 *iface,
823 UINT32 *numpad)
825 ACImpl *This = impl_from_IAudioClient3(iface);
826 struct get_current_padding_params params;
828 TRACE("(%p)->(%p)\n", This, numpad);
830 if(!numpad)
831 return E_POINTER;
833 if(!This->stream)
834 return AUDCLNT_E_NOT_INITIALIZED;
836 params.stream = This->stream;
837 params.padding = numpad;
838 UNIX_CALL(get_current_padding, &params);
839 return params.result;
842 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient3 *iface,
843 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
844 WAVEFORMATEX **outpwfx)
846 ACImpl *This = impl_from_IAudioClient3(iface);
847 struct is_format_supported_params params;
849 TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx);
850 if(pwfx) dump_fmt(pwfx);
852 params.dev_id = This->dev_id;
853 params.flow = This->dataflow;
854 params.share = mode;
855 params.fmt_in = pwfx;
856 params.fmt_out = NULL;
858 if(outpwfx){
859 *outpwfx = NULL;
860 if(mode == AUDCLNT_SHAREMODE_SHARED)
861 params.fmt_out = CoTaskMemAlloc(sizeof(*params.fmt_out));
863 UNIX_CALL(is_format_supported, &params);
865 if(params.result == S_FALSE)
866 *outpwfx = &params.fmt_out->Format;
867 else
868 CoTaskMemFree(params.fmt_out);
870 return params.result;
873 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface,
874 WAVEFORMATEX **pwfx)
876 ACImpl *This = impl_from_IAudioClient3(iface);
877 struct get_mix_format_params params;
879 TRACE("(%p)->(%p)\n", This, pwfx);
881 if(!pwfx)
882 return E_POINTER;
883 *pwfx = NULL;
885 params.dev_id = This->dev_id;
886 params.flow = This->dataflow;
887 params.fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
888 if(!params.fmt)
889 return E_OUTOFMEMORY;
891 UNIX_CALL(get_mix_format, &params);
893 if(SUCCEEDED(params.result)){
894 *pwfx = &params.fmt->Format;
895 dump_fmt(*pwfx);
896 }else
897 CoTaskMemFree(params.fmt);
899 return params.result;
902 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient3 *iface,
903 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
905 ACImpl *This = impl_from_IAudioClient3(iface);
907 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
909 if(!defperiod && !minperiod)
910 return E_POINTER;
912 if(defperiod)
913 *defperiod = DefaultPeriod;
914 if(minperiod)
915 *minperiod = MinimumPeriod;
917 return S_OK;
920 void CALLBACK ca_period_cb(void *user, BOOLEAN timer)
922 ACImpl *This = user;
924 if(This->event)
925 SetEvent(This->event);
928 static HRESULT WINAPI AudioClient_Start(IAudioClient3 *iface)
930 ACImpl *This = impl_from_IAudioClient3(iface);
931 struct start_params params;
933 TRACE("(%p)\n", This);
935 if(!This->stream)
936 return AUDCLNT_E_NOT_INITIALIZED;
938 if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event)
939 return AUDCLNT_E_EVENTHANDLE_NOT_SET;
941 params.stream = This->stream;
942 UNIX_CALL(start, &params);
944 if(SUCCEEDED(params.result)){
945 if(This->event && !This->timer){
946 if(!CreateTimerQueueTimer(&This->timer, g_timer_q, ca_period_cb, This, 0,
947 This->period_ms, WT_EXECUTEINTIMERTHREAD)){
948 This->timer = NULL;
949 IAudioClient3_Stop(iface);
950 WARN("Unable to create timer: %lu\n", GetLastError());
951 return E_OUTOFMEMORY;
955 return params.result;
958 static HRESULT WINAPI AudioClient_Stop(IAudioClient3 *iface)
960 ACImpl *This = impl_from_IAudioClient3(iface);
961 struct stop_params params;
963 TRACE("(%p)\n", This);
965 if(!This->stream)
966 return AUDCLNT_E_NOT_INITIALIZED;
968 params.stream = This->stream;
969 UNIX_CALL(stop, &params);
970 return params.result;
973 static HRESULT WINAPI AudioClient_Reset(IAudioClient3 *iface)
975 ACImpl *This = impl_from_IAudioClient3(iface);
976 struct reset_params params;
978 TRACE("(%p)\n", This);
980 if(!This->stream)
981 return AUDCLNT_E_NOT_INITIALIZED;
983 params.stream = This->stream;
984 UNIX_CALL(reset, &params);
985 return params.result;
988 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient3 *iface,
989 HANDLE event)
991 ACImpl *This = impl_from_IAudioClient3(iface);
992 HRESULT hr = S_OK;
994 TRACE("(%p)->(%p)\n", This, event);
996 if(!event)
997 return E_INVALIDARG;
999 if(!This->stream)
1000 return AUDCLNT_E_NOT_INITIALIZED;
1002 EnterCriticalSection(&g_sessions_lock);
1004 if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK))
1005 hr = AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1006 else if(This->event){
1007 FIXME("called twice\n");
1008 hr = HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
1009 }else
1010 This->event = event;
1012 LeaveCriticalSection(&g_sessions_lock);
1014 return hr;
1017 static HRESULT WINAPI AudioClient_GetService(IAudioClient3 *iface, REFIID riid,
1018 void **ppv)
1020 ACImpl *This = impl_from_IAudioClient3(iface);
1021 HRESULT hr;
1023 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1025 if(!ppv)
1026 return E_POINTER;
1027 *ppv = NULL;
1029 if(!This->stream)
1030 return AUDCLNT_E_NOT_INITIALIZED;
1032 EnterCriticalSection(&g_sessions_lock);
1034 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1035 if(This->dataflow != eRender){
1036 hr = AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1037 goto end;
1039 IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
1040 *ppv = &This->IAudioRenderClient_iface;
1041 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1042 if(This->dataflow != eCapture){
1043 hr = AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1044 goto end;
1046 IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
1047 *ppv = &This->IAudioCaptureClient_iface;
1048 }else if(IsEqualIID(riid, &IID_IAudioClock)){
1049 IAudioClock_AddRef(&This->IAudioClock_iface);
1050 *ppv = &This->IAudioClock_iface;
1051 }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1052 IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
1053 *ppv = &This->IAudioStreamVolume_iface;
1054 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1055 if(!This->session_wrapper){
1056 This->session_wrapper = AudioSessionWrapper_Create(This);
1057 if(!This->session_wrapper){
1058 hr = E_OUTOFMEMORY;
1059 goto end;
1061 }else
1062 IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
1064 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1065 }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1066 if(!This->session_wrapper){
1067 This->session_wrapper = AudioSessionWrapper_Create(This);
1068 if(!This->session_wrapper){
1069 hr = E_OUTOFMEMORY;
1070 goto end;
1072 }else
1073 IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
1075 *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1076 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1077 if(!This->session_wrapper){
1078 This->session_wrapper = AudioSessionWrapper_Create(This);
1079 if(!This->session_wrapper){
1080 hr = E_OUTOFMEMORY;
1081 goto end;
1083 }else
1084 ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
1086 *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1089 if(*ppv) hr = S_OK;
1090 else{
1091 FIXME("stub %s\n", debugstr_guid(riid));
1092 hr = E_NOINTERFACE;
1095 end:
1096 LeaveCriticalSection(&g_sessions_lock);
1097 return hr;
1100 static HRESULT WINAPI AudioClient_IsOffloadCapable(IAudioClient3 *iface,
1101 AUDIO_STREAM_CATEGORY category, BOOL *offload_capable)
1103 ACImpl *This = impl_from_IAudioClient3(iface);
1105 TRACE("(%p)->(0x%x, %p)\n", This, category, offload_capable);
1107 if(!offload_capable)
1108 return E_INVALIDARG;
1110 *offload_capable = FALSE;
1112 return S_OK;
1115 static HRESULT WINAPI AudioClient_SetClientProperties(IAudioClient3 *iface,
1116 const AudioClientProperties *prop)
1118 ACImpl *This = impl_from_IAudioClient3(iface);
1119 const Win8AudioClientProperties *legacy_prop = (const Win8AudioClientProperties *)prop;
1121 TRACE("(%p)->(%p)\n", This, prop);
1123 if(!legacy_prop)
1124 return E_POINTER;
1126 if(legacy_prop->cbSize == sizeof(AudioClientProperties)){
1127 TRACE("{ bIsOffload: %u, eCategory: 0x%x, Options: 0x%x }\n",
1128 legacy_prop->bIsOffload,
1129 legacy_prop->eCategory,
1130 prop->Options);
1131 }else if(legacy_prop->cbSize == sizeof(Win8AudioClientProperties)){
1132 TRACE("{ bIsOffload: %u, eCategory: 0x%x }\n",
1133 legacy_prop->bIsOffload,
1134 legacy_prop->eCategory);
1135 }else{
1136 WARN("Unsupported Size = %d\n", legacy_prop->cbSize);
1137 return E_INVALIDARG;
1141 if(legacy_prop->bIsOffload)
1142 return AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE;
1144 return S_OK;
1147 static HRESULT WINAPI AudioClient_GetBufferSizeLimits(IAudioClient3 *iface,
1148 const WAVEFORMATEX *format, BOOL event_driven, REFERENCE_TIME *min_duration,
1149 REFERENCE_TIME *max_duration)
1151 ACImpl *This = impl_from_IAudioClient3(iface);
1153 FIXME("(%p)->(%p, %u, %p, %p)\n", This, format, event_driven, min_duration, max_duration);
1155 return E_NOTIMPL;
1158 static HRESULT WINAPI AudioClient_GetSharedModeEnginePeriod(IAudioClient3 *iface,
1159 const WAVEFORMATEX *format, UINT32 *default_period_frames, UINT32 *unit_period_frames,
1160 UINT32 *min_period_frames, UINT32 *max_period_frames)
1162 ACImpl *This = impl_from_IAudioClient3(iface);
1164 FIXME("(%p)->(%p, %p, %p, %p, %p)\n", This, format, default_period_frames, unit_period_frames,
1165 min_period_frames, max_period_frames);
1167 return E_NOTIMPL;
1170 static HRESULT WINAPI AudioClient_GetCurrentSharedModeEnginePeriod(IAudioClient3 *iface,
1171 WAVEFORMATEX **cur_format, UINT32 *cur_period_frames)
1173 ACImpl *This = impl_from_IAudioClient3(iface);
1175 FIXME("(%p)->(%p, %p)\n", This, cur_format, cur_period_frames);
1177 return E_NOTIMPL;
1180 static HRESULT WINAPI AudioClient_InitializeSharedAudioStream(IAudioClient3 *iface,
1181 DWORD flags, UINT32 period_frames, const WAVEFORMATEX *format,
1182 const GUID *session_guid)
1184 ACImpl *This = impl_from_IAudioClient3(iface);
1186 FIXME("(%p)->(0x%lx, %u, %p, %s)\n", This, flags, period_frames, format, debugstr_guid(session_guid));
1188 return E_NOTIMPL;
1191 static const IAudioClient3Vtbl AudioClient3_Vtbl =
1193 AudioClient_QueryInterface,
1194 AudioClient_AddRef,
1195 AudioClient_Release,
1196 AudioClient_Initialize,
1197 AudioClient_GetBufferSize,
1198 AudioClient_GetStreamLatency,
1199 AudioClient_GetCurrentPadding,
1200 AudioClient_IsFormatSupported,
1201 AudioClient_GetMixFormat,
1202 AudioClient_GetDevicePeriod,
1203 AudioClient_Start,
1204 AudioClient_Stop,
1205 AudioClient_Reset,
1206 AudioClient_SetEventHandle,
1207 AudioClient_GetService,
1208 AudioClient_IsOffloadCapable,
1209 AudioClient_SetClientProperties,
1210 AudioClient_GetBufferSizeLimits,
1211 AudioClient_GetSharedModeEnginePeriod,
1212 AudioClient_GetCurrentSharedModeEnginePeriod,
1213 AudioClient_InitializeSharedAudioStream,
1216 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1217 IAudioRenderClient *iface, REFIID riid, void **ppv)
1219 ACImpl *This = impl_from_IAudioRenderClient(iface);
1220 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1222 if(!ppv)
1223 return E_POINTER;
1224 *ppv = NULL;
1226 if(IsEqualIID(riid, &IID_IUnknown) ||
1227 IsEqualIID(riid, &IID_IAudioRenderClient))
1228 *ppv = iface;
1229 else if(IsEqualIID(riid, &IID_IMarshal))
1230 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
1232 if(*ppv){
1233 IUnknown_AddRef((IUnknown*)*ppv);
1234 return S_OK;
1237 WARN("Unknown interface %s\n", debugstr_guid(riid));
1238 return E_NOINTERFACE;
1241 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1243 ACImpl *This = impl_from_IAudioRenderClient(iface);
1244 return AudioClient_AddRef(&This->IAudioClient3_iface);
1247 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1249 ACImpl *This = impl_from_IAudioRenderClient(iface);
1250 return AudioClient_Release(&This->IAudioClient3_iface);
1253 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1254 UINT32 frames, BYTE **data)
1256 ACImpl *This = impl_from_IAudioRenderClient(iface);
1257 struct get_render_buffer_params params;
1259 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1261 if(!data)
1262 return E_POINTER;
1263 *data = NULL;
1265 params.stream = This->stream;
1266 params.frames = frames;
1267 params.data = data;
1268 UNIX_CALL(get_render_buffer, &params);
1269 return params.result;
1272 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1273 IAudioRenderClient *iface, UINT32 frames, DWORD flags)
1275 ACImpl *This = impl_from_IAudioRenderClient(iface);
1276 struct release_render_buffer_params params;
1278 TRACE("(%p)->(%u, %lx)\n", This, frames, flags);
1280 params.stream = This->stream;
1281 params.frames = frames;
1282 params.flags = flags;
1283 UNIX_CALL(release_render_buffer, &params);
1284 return params.result;
1287 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1288 AudioRenderClient_QueryInterface,
1289 AudioRenderClient_AddRef,
1290 AudioRenderClient_Release,
1291 AudioRenderClient_GetBuffer,
1292 AudioRenderClient_ReleaseBuffer
1295 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1296 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1298 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1299 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1301 if(!ppv)
1302 return E_POINTER;
1303 *ppv = NULL;
1305 if(IsEqualIID(riid, &IID_IUnknown) ||
1306 IsEqualIID(riid, &IID_IAudioCaptureClient))
1307 *ppv = iface;
1308 else if(IsEqualIID(riid, &IID_IMarshal))
1309 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
1311 if(*ppv){
1312 IUnknown_AddRef((IUnknown*)*ppv);
1313 return S_OK;
1316 WARN("Unknown interface %s\n", debugstr_guid(riid));
1317 return E_NOINTERFACE;
1320 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1322 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1323 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1326 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1328 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1329 return IAudioClient3_Release(&This->IAudioClient3_iface);
1332 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1333 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1334 UINT64 *qpcpos)
1336 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1337 struct get_capture_buffer_params params;
1339 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1340 devpos, qpcpos);
1342 if(!data)
1343 return E_POINTER;
1345 *data = NULL;
1347 if(!frames || !flags)
1348 return E_POINTER;
1350 params.stream = This->stream;
1351 params.data = data;
1352 params.frames = frames;
1353 params.flags = flags;
1354 params.devpos = devpos;
1355 params.qpcpos = qpcpos;
1356 UNIX_CALL(get_capture_buffer, &params);
1357 return params.result;
1360 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1361 IAudioCaptureClient *iface, UINT32 done)
1363 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1364 struct release_capture_buffer_params params;
1366 TRACE("(%p)->(%u)\n", This, done);
1368 params.stream = This->stream;
1369 params.done = done;
1370 UNIX_CALL(release_capture_buffer, &params);
1371 return params.result;
1374 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1375 IAudioCaptureClient *iface, UINT32 *frames)
1377 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1378 struct get_next_packet_size_params params;
1380 TRACE("(%p)->(%p)\n", This, frames);
1382 if(!frames)
1383 return E_POINTER;
1385 params.stream = This->stream;
1386 params.frames = frames;
1387 UNIX_CALL(get_next_packet_size, &params);
1388 return params.result;
1391 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1393 AudioCaptureClient_QueryInterface,
1394 AudioCaptureClient_AddRef,
1395 AudioCaptureClient_Release,
1396 AudioCaptureClient_GetBuffer,
1397 AudioCaptureClient_ReleaseBuffer,
1398 AudioCaptureClient_GetNextPacketSize
1401 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1402 REFIID riid, void **ppv)
1404 ACImpl *This = impl_from_IAudioClock(iface);
1406 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1408 if(!ppv)
1409 return E_POINTER;
1410 *ppv = NULL;
1412 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
1413 *ppv = iface;
1414 else if(IsEqualIID(riid, &IID_IAudioClock2))
1415 *ppv = &This->IAudioClock2_iface;
1416 if(*ppv){
1417 IUnknown_AddRef((IUnknown*)*ppv);
1418 return S_OK;
1421 WARN("Unknown interface %s\n", debugstr_guid(riid));
1422 return E_NOINTERFACE;
1425 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
1427 ACImpl *This = impl_from_IAudioClock(iface);
1428 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1431 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
1433 ACImpl *This = impl_from_IAudioClock(iface);
1434 return IAudioClient3_Release(&This->IAudioClient3_iface);
1437 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
1439 ACImpl *This = impl_from_IAudioClock(iface);
1440 struct get_frequency_params params;
1442 TRACE("(%p)->(%p)\n", This, freq);
1444 params.stream = This->stream;
1445 params.freq = freq;
1446 UNIX_CALL(get_frequency, &params);
1447 return params.result;
1450 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
1451 UINT64 *qpctime)
1453 ACImpl *This = impl_from_IAudioClock(iface);
1454 struct get_position_params params;
1456 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
1458 if(!pos)
1459 return E_POINTER;
1461 params.stream = This->stream;
1462 params.pos = pos;
1463 params.qpctime = qpctime;
1464 UNIX_CALL(get_position, &params);
1465 return params.result;
1468 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
1469 DWORD *chars)
1471 ACImpl *This = impl_from_IAudioClock(iface);
1473 TRACE("(%p)->(%p)\n", This, chars);
1475 if(!chars)
1476 return E_POINTER;
1478 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
1480 return S_OK;
1483 static const IAudioClockVtbl AudioClock_Vtbl =
1485 AudioClock_QueryInterface,
1486 AudioClock_AddRef,
1487 AudioClock_Release,
1488 AudioClock_GetFrequency,
1489 AudioClock_GetPosition,
1490 AudioClock_GetCharacteristics
1493 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
1494 REFIID riid, void **ppv)
1496 ACImpl *This = impl_from_IAudioClock2(iface);
1497 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
1500 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
1502 ACImpl *This = impl_from_IAudioClock2(iface);
1503 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1506 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
1508 ACImpl *This = impl_from_IAudioClock2(iface);
1509 return IAudioClient3_Release(&This->IAudioClient3_iface);
1512 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
1513 UINT64 *pos, UINT64 *qpctime)
1515 ACImpl *This = impl_from_IAudioClock2(iface);
1517 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
1519 return E_NOTIMPL;
1522 static const IAudioClock2Vtbl AudioClock2_Vtbl =
1524 AudioClock2_QueryInterface,
1525 AudioClock2_AddRef,
1526 AudioClock2_Release,
1527 AudioClock2_GetDevicePosition
1530 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
1532 AudioSessionWrapper *ret;
1534 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1535 sizeof(AudioSessionWrapper));
1536 if(!ret)
1537 return NULL;
1539 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
1540 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
1541 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
1543 ret->ref = 1;
1545 ret->client = client;
1546 if(client){
1547 ret->session = client->session;
1548 IAudioClient3_AddRef(&client->IAudioClient3_iface);
1551 return ret;
1554 static HRESULT WINAPI AudioSessionControl_QueryInterface(
1555 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
1557 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1559 if(!ppv)
1560 return E_POINTER;
1561 *ppv = NULL;
1563 if(IsEqualIID(riid, &IID_IUnknown) ||
1564 IsEqualIID(riid, &IID_IAudioSessionControl) ||
1565 IsEqualIID(riid, &IID_IAudioSessionControl2))
1566 *ppv = iface;
1567 if(*ppv){
1568 IUnknown_AddRef((IUnknown*)*ppv);
1569 return S_OK;
1572 WARN("Unknown interface %s\n", debugstr_guid(riid));
1573 return E_NOINTERFACE;
1576 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
1578 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1579 ULONG ref;
1580 ref = InterlockedIncrement(&This->ref);
1581 TRACE("(%p) Refcount now %lu\n", This, ref);
1582 return ref;
1585 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
1587 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1588 ULONG ref;
1590 EnterCriticalSection(&g_sessions_lock);
1592 ref = InterlockedDecrement(&This->ref);
1593 TRACE("(%p) Refcount now %lu\n", This, ref);
1594 if(!ref){
1595 if(This->client){
1596 This->client->session_wrapper = NULL;
1597 AudioClient_Release(&This->client->IAudioClient3_iface);
1599 HeapFree(GetProcessHeap(), 0, This);
1602 LeaveCriticalSection(&g_sessions_lock);
1603 return ref;
1606 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
1607 AudioSessionState *state)
1609 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1610 struct is_started_params params;
1611 ACImpl *client;
1613 TRACE("(%p)->(%p)\n", This, state);
1615 if(!state)
1616 return NULL_PTR_ERR;
1618 EnterCriticalSection(&g_sessions_lock);
1620 if(list_empty(&This->session->clients)){
1621 *state = AudioSessionStateExpired;
1622 LeaveCriticalSection(&g_sessions_lock);
1623 return S_OK;
1626 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
1627 params.stream = client->stream;
1628 UNIX_CALL(is_started, &params);
1629 if(params.result == S_OK){
1630 *state = AudioSessionStateActive;
1631 LeaveCriticalSection(&g_sessions_lock);
1632 return S_OK;
1636 LeaveCriticalSection(&g_sessions_lock);
1638 *state = AudioSessionStateInactive;
1640 return S_OK;
1643 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
1644 IAudioSessionControl2 *iface, WCHAR **name)
1646 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1648 FIXME("(%p)->(%p) - stub\n", This, name);
1650 return E_NOTIMPL;
1653 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
1654 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
1656 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1658 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
1660 return E_NOTIMPL;
1663 static HRESULT WINAPI AudioSessionControl_GetIconPath(
1664 IAudioSessionControl2 *iface, WCHAR **path)
1666 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1668 FIXME("(%p)->(%p) - stub\n", This, path);
1670 return E_NOTIMPL;
1673 static HRESULT WINAPI AudioSessionControl_SetIconPath(
1674 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
1676 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1678 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
1680 return E_NOTIMPL;
1683 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
1684 IAudioSessionControl2 *iface, GUID *group)
1686 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1688 FIXME("(%p)->(%p) - stub\n", This, group);
1690 return E_NOTIMPL;
1693 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
1694 IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
1696 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1698 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
1699 debugstr_guid(session));
1701 return E_NOTIMPL;
1704 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
1705 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
1707 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1709 FIXME("(%p)->(%p) - stub\n", This, events);
1711 return S_OK;
1714 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
1715 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
1717 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1719 FIXME("(%p)->(%p) - stub\n", This, events);
1721 return S_OK;
1724 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
1725 IAudioSessionControl2 *iface, WCHAR **id)
1727 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1729 FIXME("(%p)->(%p) - stub\n", This, id);
1731 return E_NOTIMPL;
1734 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
1735 IAudioSessionControl2 *iface, WCHAR **id)
1737 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1739 FIXME("(%p)->(%p) - stub\n", This, id);
1741 return E_NOTIMPL;
1744 static HRESULT WINAPI AudioSessionControl_GetProcessId(
1745 IAudioSessionControl2 *iface, DWORD *pid)
1747 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1749 TRACE("(%p)->(%p)\n", This, pid);
1751 if(!pid)
1752 return E_POINTER;
1754 *pid = GetCurrentProcessId();
1756 return S_OK;
1759 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
1760 IAudioSessionControl2 *iface)
1762 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1764 TRACE("(%p)\n", This);
1766 return S_FALSE;
1769 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
1770 IAudioSessionControl2 *iface, BOOL optout)
1772 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1774 TRACE("(%p)->(%d)\n", This, optout);
1776 return S_OK;
1779 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
1781 AudioSessionControl_QueryInterface,
1782 AudioSessionControl_AddRef,
1783 AudioSessionControl_Release,
1784 AudioSessionControl_GetState,
1785 AudioSessionControl_GetDisplayName,
1786 AudioSessionControl_SetDisplayName,
1787 AudioSessionControl_GetIconPath,
1788 AudioSessionControl_SetIconPath,
1789 AudioSessionControl_GetGroupingParam,
1790 AudioSessionControl_SetGroupingParam,
1791 AudioSessionControl_RegisterAudioSessionNotification,
1792 AudioSessionControl_UnregisterAudioSessionNotification,
1793 AudioSessionControl_GetSessionIdentifier,
1794 AudioSessionControl_GetSessionInstanceIdentifier,
1795 AudioSessionControl_GetProcessId,
1796 AudioSessionControl_IsSystemSoundsSession,
1797 AudioSessionControl_SetDuckingPreference
1800 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
1801 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
1803 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1805 if(!ppv)
1806 return E_POINTER;
1807 *ppv = NULL;
1809 if(IsEqualIID(riid, &IID_IUnknown) ||
1810 IsEqualIID(riid, &IID_ISimpleAudioVolume))
1811 *ppv = iface;
1812 if(*ppv){
1813 IUnknown_AddRef((IUnknown*)*ppv);
1814 return S_OK;
1817 WARN("Unknown interface %s\n", debugstr_guid(riid));
1818 return E_NOINTERFACE;
1821 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
1823 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1824 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
1827 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
1829 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1830 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
1833 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
1834 ISimpleAudioVolume *iface, float level, const GUID *context)
1836 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1837 AudioSession *session = This->session;
1838 ACImpl *client;
1840 TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
1842 if(level < 0.f || level > 1.f)
1843 return E_INVALIDARG;
1845 if(context)
1846 FIXME("Notifications not supported yet\n");
1848 EnterCriticalSection(&g_sessions_lock);
1850 session->master_vol = level;
1852 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
1853 set_stream_volumes(client, -1);
1855 LeaveCriticalSection(&g_sessions_lock);
1857 return S_OK;
1860 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
1861 ISimpleAudioVolume *iface, float *level)
1863 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1864 AudioSession *session = This->session;
1866 TRACE("(%p)->(%p)\n", session, level);
1868 if(!level)
1869 return NULL_PTR_ERR;
1871 *level = session->master_vol;
1873 return S_OK;
1876 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
1877 BOOL mute, const GUID *context)
1879 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1880 AudioSession *session = This->session;
1881 ACImpl *client;
1883 TRACE("(%p)->(%u, %s)\n", session, mute, debugstr_guid(context));
1885 if(context)
1886 FIXME("Notifications not supported yet\n");
1888 EnterCriticalSection(&g_sessions_lock);
1890 session->mute = mute;
1892 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
1893 set_stream_volumes(client, -1);
1895 LeaveCriticalSection(&g_sessions_lock);
1897 return S_OK;
1900 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
1901 BOOL *mute)
1903 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1904 AudioSession *session = This->session;
1906 TRACE("(%p)->(%p)\n", session, mute);
1908 if(!mute)
1909 return NULL_PTR_ERR;
1911 *mute = session->mute;
1913 return S_OK;
1916 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
1918 SimpleAudioVolume_QueryInterface,
1919 SimpleAudioVolume_AddRef,
1920 SimpleAudioVolume_Release,
1921 SimpleAudioVolume_SetMasterVolume,
1922 SimpleAudioVolume_GetMasterVolume,
1923 SimpleAudioVolume_SetMute,
1924 SimpleAudioVolume_GetMute
1927 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
1928 IAudioStreamVolume *iface, REFIID riid, void **ppv)
1930 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1932 if(!ppv)
1933 return E_POINTER;
1934 *ppv = NULL;
1936 if(IsEqualIID(riid, &IID_IUnknown) ||
1937 IsEqualIID(riid, &IID_IAudioStreamVolume))
1938 *ppv = iface;
1939 if(*ppv){
1940 IUnknown_AddRef((IUnknown*)*ppv);
1941 return S_OK;
1944 WARN("Unknown interface %s\n", debugstr_guid(riid));
1945 return E_NOINTERFACE;
1948 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
1950 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1951 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1954 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
1956 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1957 return IAudioClient3_Release(&This->IAudioClient3_iface);
1960 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
1961 IAudioStreamVolume *iface, UINT32 *out)
1963 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1965 TRACE("(%p)->(%p)\n", This, out);
1967 if(!out)
1968 return E_POINTER;
1970 *out = This->channel_count;
1972 return S_OK;
1975 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
1976 IAudioStreamVolume *iface, UINT32 index, float level)
1978 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1980 TRACE("(%p)->(%d, %f)\n", This, index, level);
1982 if(level < 0.f || level > 1.f)
1983 return E_INVALIDARG;
1985 if(index >= This->channel_count)
1986 return E_INVALIDARG;
1988 EnterCriticalSection(&g_sessions_lock);
1990 This->vols[index] = level;
1992 WARN("CoreAudio doesn't support per-channel volume control\n");
1993 set_stream_volumes(This, index);
1995 LeaveCriticalSection(&g_sessions_lock);
1997 return S_OK;
2000 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2001 IAudioStreamVolume *iface, UINT32 index, float *level)
2003 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2005 TRACE("(%p)->(%d, %p)\n", This, index, level);
2007 if(!level)
2008 return E_POINTER;
2010 if(index >= This->channel_count)
2011 return E_INVALIDARG;
2013 *level = This->vols[index];
2015 return S_OK;
2018 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2019 IAudioStreamVolume *iface, UINT32 count, const float *levels)
2021 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2022 UINT32 i;
2024 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2026 if(!levels)
2027 return E_POINTER;
2029 if(count != This->channel_count)
2030 return E_INVALIDARG;
2032 EnterCriticalSection(&g_sessions_lock);
2034 for(i = 0; i < count; ++i)
2035 This->vols[i] = levels[i];
2037 set_stream_volumes(This, -1);
2039 LeaveCriticalSection(&g_sessions_lock);
2041 return S_OK;
2044 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2045 IAudioStreamVolume *iface, UINT32 count, float *levels)
2047 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2048 UINT32 i;
2050 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2052 if(!levels)
2053 return E_POINTER;
2055 if(count != This->channel_count)
2056 return E_INVALIDARG;
2058 EnterCriticalSection(&g_sessions_lock);
2060 for(i = 0; i < count; ++i)
2061 levels[i] = This->vols[i];
2063 LeaveCriticalSection(&g_sessions_lock);
2065 return S_OK;
2068 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2070 AudioStreamVolume_QueryInterface,
2071 AudioStreamVolume_AddRef,
2072 AudioStreamVolume_Release,
2073 AudioStreamVolume_GetChannelCount,
2074 AudioStreamVolume_SetChannelVolume,
2075 AudioStreamVolume_GetChannelVolume,
2076 AudioStreamVolume_SetAllVolumes,
2077 AudioStreamVolume_GetAllVolumes
2080 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2081 IChannelAudioVolume *iface, REFIID riid, void **ppv)
2083 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2085 if(!ppv)
2086 return E_POINTER;
2087 *ppv = NULL;
2089 if(IsEqualIID(riid, &IID_IUnknown) ||
2090 IsEqualIID(riid, &IID_IChannelAudioVolume))
2091 *ppv = iface;
2092 if(*ppv){
2093 IUnknown_AddRef((IUnknown*)*ppv);
2094 return S_OK;
2097 WARN("Unknown interface %s\n", debugstr_guid(riid));
2098 return E_NOINTERFACE;
2101 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2103 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2104 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2107 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2109 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2110 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2113 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2114 IChannelAudioVolume *iface, UINT32 *out)
2116 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2117 AudioSession *session = This->session;
2119 TRACE("(%p)->(%p)\n", session, out);
2121 if(!out)
2122 return NULL_PTR_ERR;
2124 *out = session->channel_count;
2126 return S_OK;
2129 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2130 IChannelAudioVolume *iface, UINT32 index, float level,
2131 const GUID *context)
2133 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2134 AudioSession *session = This->session;
2135 ACImpl *client;
2137 TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2138 wine_dbgstr_guid(context));
2140 if(level < 0.f || level > 1.f)
2141 return E_INVALIDARG;
2143 if(index >= session->channel_count)
2144 return E_INVALIDARG;
2146 if(context)
2147 FIXME("Notifications not supported yet\n");
2149 EnterCriticalSection(&g_sessions_lock);
2151 session->channel_vols[index] = level;
2153 WARN("CoreAudio doesn't support per-channel volume control\n");
2154 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
2155 set_stream_volumes(client, index);
2157 LeaveCriticalSection(&g_sessions_lock);
2159 return S_OK;
2162 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2163 IChannelAudioVolume *iface, UINT32 index, float *level)
2165 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2166 AudioSession *session = This->session;
2168 TRACE("(%p)->(%d, %p)\n", session, index, level);
2170 if(!level)
2171 return NULL_PTR_ERR;
2173 if(index >= session->channel_count)
2174 return E_INVALIDARG;
2176 *level = session->channel_vols[index];
2178 return S_OK;
2181 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2182 IChannelAudioVolume *iface, UINT32 count, const float *levels,
2183 const GUID *context)
2185 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2186 AudioSession *session = This->session;
2187 ACImpl *client;
2188 UINT32 i;
2190 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2191 wine_dbgstr_guid(context));
2193 if(!levels)
2194 return NULL_PTR_ERR;
2196 if(count != session->channel_count)
2197 return E_INVALIDARG;
2199 if(context)
2200 FIXME("Notifications not supported yet\n");
2202 EnterCriticalSection(&g_sessions_lock);
2204 for(i = 0; i < count; ++i)
2205 session->channel_vols[i] = levels[i];
2207 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
2208 set_stream_volumes(client, -1);
2210 LeaveCriticalSection(&g_sessions_lock);
2212 return S_OK;
2215 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2216 IChannelAudioVolume *iface, UINT32 count, float *levels)
2218 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2219 AudioSession *session = This->session;
2220 int i;
2222 TRACE("(%p)->(%d, %p)\n", session, count, levels);
2224 if(!levels)
2225 return NULL_PTR_ERR;
2227 if(count != session->channel_count)
2228 return E_INVALIDARG;
2230 for(i = 0; i < count; ++i)
2231 levels[i] = session->channel_vols[i];
2233 return S_OK;
2236 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2238 ChannelAudioVolume_QueryInterface,
2239 ChannelAudioVolume_AddRef,
2240 ChannelAudioVolume_Release,
2241 ChannelAudioVolume_GetChannelCount,
2242 ChannelAudioVolume_SetChannelVolume,
2243 ChannelAudioVolume_GetChannelVolume,
2244 ChannelAudioVolume_SetAllVolumes,
2245 ChannelAudioVolume_GetAllVolumes
2248 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2249 REFIID riid, void **ppv)
2251 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2253 if(!ppv)
2254 return E_POINTER;
2255 *ppv = NULL;
2257 if(IsEqualIID(riid, &IID_IUnknown) ||
2258 IsEqualIID(riid, &IID_IAudioSessionManager) ||
2259 IsEqualIID(riid, &IID_IAudioSessionManager2))
2260 *ppv = iface;
2261 if(*ppv){
2262 IUnknown_AddRef((IUnknown*)*ppv);
2263 return S_OK;
2266 WARN("Unknown interface %s\n", debugstr_guid(riid));
2267 return E_NOINTERFACE;
2270 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2272 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2273 ULONG ref;
2274 ref = InterlockedIncrement(&This->ref);
2275 TRACE("(%p) Refcount now %lu\n", This, ref);
2276 return ref;
2279 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2281 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2282 ULONG ref;
2283 ref = InterlockedDecrement(&This->ref);
2284 TRACE("(%p) Refcount now %lu\n", This, ref);
2285 if(!ref)
2286 HeapFree(GetProcessHeap(), 0, This);
2287 return ref;
2290 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2291 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2292 IAudioSessionControl **out)
2294 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2295 AudioSession *session;
2296 AudioSessionWrapper *wrapper;
2297 HRESULT hr;
2299 TRACE("(%p)->(%s, %lx, %p)\n", This, debugstr_guid(session_guid),
2300 flags, out);
2302 hr = get_audio_session(session_guid, This->device, 0, &session);
2303 if(FAILED(hr))
2304 return hr;
2306 wrapper = AudioSessionWrapper_Create(NULL);
2307 if(!wrapper)
2308 return E_OUTOFMEMORY;
2310 wrapper->session = session;
2312 *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
2314 return S_OK;
2317 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
2318 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2319 ISimpleAudioVolume **out)
2321 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2322 AudioSession *session;
2323 AudioSessionWrapper *wrapper;
2324 HRESULT hr;
2326 TRACE("(%p)->(%s, %lx, %p)\n", This, debugstr_guid(session_guid),
2327 flags, out);
2329 hr = get_audio_session(session_guid, This->device, 0, &session);
2330 if(FAILED(hr))
2331 return hr;
2333 wrapper = AudioSessionWrapper_Create(NULL);
2334 if(!wrapper)
2335 return E_OUTOFMEMORY;
2337 wrapper->session = session;
2339 *out = &wrapper->ISimpleAudioVolume_iface;
2341 return S_OK;
2344 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
2345 IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
2347 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2348 FIXME("(%p)->(%p) - stub\n", This, out);
2349 return E_NOTIMPL;
2352 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
2353 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2355 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2356 FIXME("(%p)->(%p) - stub\n", This, notification);
2357 return E_NOTIMPL;
2360 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
2361 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2363 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2364 FIXME("(%p)->(%p) - stub\n", This, notification);
2365 return E_NOTIMPL;
2368 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
2369 IAudioSessionManager2 *iface, const WCHAR *session_id,
2370 IAudioVolumeDuckNotification *notification)
2372 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2373 FIXME("(%p)->(%p) - stub\n", This, notification);
2374 return E_NOTIMPL;
2377 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
2378 IAudioSessionManager2 *iface,
2379 IAudioVolumeDuckNotification *notification)
2381 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2382 FIXME("(%p)->(%p) - stub\n", This, notification);
2383 return E_NOTIMPL;
2386 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
2388 AudioSessionManager_QueryInterface,
2389 AudioSessionManager_AddRef,
2390 AudioSessionManager_Release,
2391 AudioSessionManager_GetAudioSessionControl,
2392 AudioSessionManager_GetSimpleAudioVolume,
2393 AudioSessionManager_GetSessionEnumerator,
2394 AudioSessionManager_RegisterSessionNotification,
2395 AudioSessionManager_UnregisterSessionNotification,
2396 AudioSessionManager_RegisterDuckNotification,
2397 AudioSessionManager_UnregisterDuckNotification
2400 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
2401 IAudioSessionManager2 **out)
2403 SessionMgr *This;
2405 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
2406 if(!This)
2407 return E_OUTOFMEMORY;
2409 This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
2410 This->device = device;
2411 This->ref = 1;
2413 *out = &This->IAudioSessionManager2_iface;
2415 return S_OK;