winecoreaudio: Adapt "create_stream_params" struct to mmdevapi's.
[wine.git] / dlls / winecoreaudio.drv / mmdevdrv.c
blob79d617650f46941169f2ef880afe1b72a88e2f12
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 HANDLE timer;
102 AudioSession *session;
103 AudioSessionWrapper *session_wrapper;
105 stream_handle stream;
106 struct list entry;
108 char device_name[1];
111 static const IAudioClient3Vtbl AudioClient3_Vtbl;
112 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
113 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
114 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
115 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
116 static const IAudioClockVtbl AudioClock_Vtbl;
117 static const IAudioClock2Vtbl AudioClock2_Vtbl;
118 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
119 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
120 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl;
122 typedef struct _SessionMgr {
123 IAudioSessionManager2 IAudioSessionManager2_iface;
125 LONG ref;
127 IMMDevice *device;
128 } SessionMgr;
130 static const WCHAR *drv_key_devicesW = L"Software\\Wine\\Drivers\\winecoreaudio.drv\\devices";
132 static HANDLE g_timer_q;
134 static CRITICAL_SECTION g_sessions_lock;
135 static CRITICAL_SECTION_DEBUG g_sessions_lock_debug =
137 0, 0, &g_sessions_lock,
138 { &g_sessions_lock_debug.ProcessLocksList, &g_sessions_lock_debug.ProcessLocksList },
139 0, 0, { (DWORD_PTR)(__FILE__ ": g_sessions_lock") }
141 static CRITICAL_SECTION g_sessions_lock = { &g_sessions_lock_debug, -1, 0, 0, 0, 0 };
142 static struct list g_sessions = LIST_INIT(g_sessions);
144 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
146 static inline ACImpl *impl_from_IAudioClient3(IAudioClient3 *iface)
148 return CONTAINING_RECORD(iface, ACImpl, IAudioClient3_iface);
151 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
153 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
156 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
158 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
161 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
163 return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
166 static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
168 return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
171 static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
173 return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
176 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
178 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
181 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
183 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
186 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
188 return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
191 static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface)
193 return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface);
196 BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
198 switch (reason)
200 case DLL_PROCESS_ATTACH:
201 if(NtQueryVirtualMemory(GetCurrentProcess(), dll, MemoryWineUnixFuncs,
202 &coreaudio_handle, sizeof(coreaudio_handle), NULL))
203 return FALSE;
204 g_timer_q = CreateTimerQueue();
205 if(!g_timer_q)
206 return FALSE;
207 break;
209 case DLL_PROCESS_DETACH:
210 if (reserved) break;
211 DeleteCriticalSection(&g_sessions_lock);
212 break;
214 return TRUE;
217 /* From <dlls/mmdevapi/mmdevapi.h> */
218 enum DriverPriority {
219 Priority_Unavailable = 0,
220 Priority_Low,
221 Priority_Neutral,
222 Priority_Preferred
225 int WINAPI AUDDRV_GetPriority(void)
227 return Priority_Neutral;
230 static void set_device_guid(EDataFlow flow, HKEY drv_key, const WCHAR *key_name,
231 GUID *guid)
233 HKEY key;
234 BOOL opened = FALSE;
235 LONG lr;
237 if(!drv_key){
238 lr = RegCreateKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, NULL, 0, KEY_WRITE,
239 NULL, &drv_key, NULL);
240 if(lr != ERROR_SUCCESS){
241 ERR("RegCreateKeyEx(drv_key) failed: %lu\n", lr);
242 return;
244 opened = TRUE;
247 lr = RegCreateKeyExW(drv_key, key_name, 0, NULL, 0, KEY_WRITE,
248 NULL, &key, NULL);
249 if(lr != ERROR_SUCCESS){
250 ERR("RegCreateKeyEx(%s) failed: %lu\n", wine_dbgstr_w(key_name), lr);
251 goto exit;
254 lr = RegSetValueExW(key, L"guid", 0, REG_BINARY, (BYTE*)guid,
255 sizeof(GUID));
256 if(lr != ERROR_SUCCESS)
257 ERR("RegSetValueEx(%s\\guid) failed: %lu\n", wine_dbgstr_w(key_name), lr);
259 RegCloseKey(key);
260 exit:
261 if(opened)
262 RegCloseKey(drv_key);
265 static void get_device_guid(EDataFlow flow, const char *dev, GUID *guid)
267 HKEY key = NULL, dev_key;
268 DWORD type, size = sizeof(*guid);
269 WCHAR key_name[256];
271 if(flow == eCapture)
272 key_name[0] = '1';
273 else
274 key_name[0] = '0';
275 key_name[1] = ',';
277 MultiByteToWideChar(CP_UNIXCP, 0, dev, -1, key_name + 2, ARRAY_SIZE(key_name) - 2);
279 if(RegOpenKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, KEY_WRITE|KEY_READ, &key) == ERROR_SUCCESS){
280 if(RegOpenKeyExW(key, key_name, 0, KEY_READ, &dev_key) == ERROR_SUCCESS){
281 if(RegQueryValueExW(dev_key, L"guid", 0, &type,
282 (BYTE*)guid, &size) == ERROR_SUCCESS){
283 if(type == REG_BINARY){
284 RegCloseKey(dev_key);
285 RegCloseKey(key);
286 return;
288 ERR("Invalid type for device %s GUID: %lu; ignoring and overwriting\n",
289 wine_dbgstr_w(key_name), type);
291 RegCloseKey(dev_key);
295 CoCreateGuid(guid);
297 set_device_guid(flow, key, key_name, guid);
299 if(key)
300 RegCloseKey(key);
303 static void set_stream_volumes(ACImpl *This, int channel)
305 struct set_volumes_params params;
307 params.stream = This->stream;
308 params.master_volume = This->session->mute ? 0.0f : This->session->master_vol;
309 params.volumes = This->vols;
310 params.session_volumes = This->session->channel_vols;
311 params.channel = channel;
313 UNIX_CALL(set_volumes, &params);
316 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids_out,
317 GUID **guids_out, UINT *num, UINT *def_index)
319 struct get_endpoint_ids_params params;
320 unsigned int i;
321 GUID *guids = NULL;
322 WCHAR **ids = NULL;
324 TRACE("%d %p %p %p\n", flow, ids_out, num, def_index);
326 params.flow = flow;
327 params.size = 1000;
328 params.endpoints = NULL;
330 heap_free(params.endpoints);
331 params.endpoints = heap_alloc(params.size);
332 UNIX_CALL(get_endpoint_ids, &params);
333 }while(params.result == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
335 if(FAILED(params.result)) goto end;
337 ids = heap_alloc_zero(params.num * sizeof(*ids));
338 guids = heap_alloc(params.num * sizeof(*guids));
339 if(!ids || !guids){
340 params.result = E_OUTOFMEMORY;
341 goto end;
344 for(i = 0; i < params.num; i++){
345 const WCHAR *name = (WCHAR *)((char *)params.endpoints + params.endpoints[i].name);
346 const char *device = (char *)params.endpoints + params.endpoints[i].device;
347 const unsigned int size = (wcslen(name) + 1) * sizeof(WCHAR);
349 ids[i] = heap_alloc(size);
350 if(!ids[i]){
351 params.result = E_OUTOFMEMORY;
352 goto end;
354 memcpy(ids[i], name, size);
355 get_device_guid(flow, device, guids + i);
357 *def_index = params.default_idx;
359 end:
360 heap_free(params.endpoints);
361 if(FAILED(params.result)){
362 heap_free(guids);
363 if(ids){
364 for(i = 0; i < params.num; i++) heap_free(ids[i]);
365 heap_free(ids);
367 }else{
368 *ids_out = ids;
369 *guids_out = guids;
370 *num = params.num;
373 return params.result;
376 static BOOL get_device_name_by_guid(const GUID *guid, char *name, const SIZE_T name_size, EDataFlow *flow)
378 HKEY devices_key;
379 UINT i = 0;
380 WCHAR key_name[256];
381 DWORD key_name_size;
383 if(RegOpenKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, KEY_READ, &devices_key) != ERROR_SUCCESS){
384 ERR("No devices in registry?\n");
385 return FALSE;
388 while(1){
389 HKEY key;
390 DWORD size, type;
391 GUID reg_guid;
393 key_name_size = ARRAY_SIZE(key_name);
394 if(RegEnumKeyExW(devices_key, i++, key_name, &key_name_size, NULL,
395 NULL, NULL, NULL) != ERROR_SUCCESS)
396 break;
398 if(RegOpenKeyExW(devices_key, key_name, 0, KEY_READ, &key) != ERROR_SUCCESS){
399 WARN("Couldn't open key: %s\n", wine_dbgstr_w(key_name));
400 continue;
403 size = sizeof(reg_guid);
404 if(RegQueryValueExW(key, L"guid", 0, &type,
405 (BYTE*)&reg_guid, &size) == ERROR_SUCCESS){
406 if(IsEqualGUID(&reg_guid, guid)){
407 RegCloseKey(key);
408 RegCloseKey(devices_key);
410 TRACE("Found matching device key: %s\n", wine_dbgstr_w(key_name));
412 if(key_name[0] == '0')
413 *flow = eRender;
414 else if(key_name[0] == '1')
415 *flow = eCapture;
416 else{
417 ERR("Unknown device type: %c\n", key_name[0]);
418 return FALSE;
421 WideCharToMultiByte(CP_UNIXCP, 0, key_name + 2, -1, name, name_size, NULL, NULL);
423 return TRUE;
427 RegCloseKey(key);
430 RegCloseKey(devices_key);
432 WARN("No matching device in registry for GUID %s\n", debugstr_guid(guid));
434 return FALSE;
437 HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient **out)
439 ACImpl *This;
440 char name[256];
441 SIZE_T name_len;
442 EDataFlow dataflow;
443 HRESULT hr;
445 TRACE("%s %p %p\n", debugstr_guid(guid), dev, out);
447 if(!get_device_name_by_guid(guid, name, sizeof(name), &dataflow))
448 return AUDCLNT_E_DEVICE_INVALIDATED;
450 if(dataflow != eRender && dataflow != eCapture)
451 return E_INVALIDARG;
453 name_len = strlen(name);
454 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, offsetof(ACImpl, device_name[name_len + 1]));
455 if(!This)
456 return E_OUTOFMEMORY;
458 This->IAudioClient3_iface.lpVtbl = &AudioClient3_Vtbl;
459 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
460 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
461 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
462 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
463 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
465 This->dataflow = dataflow;
466 memcpy(This->device_name, name, name_len + 1);
468 hr = CoCreateFreeThreadedMarshaler((IUnknown *)&This->IAudioClient3_iface, &This->pUnkFTMarshal);
469 if (FAILED(hr)) {
470 HeapFree(GetProcessHeap(), 0, This);
471 return hr;
474 This->parent = dev;
475 IMMDevice_AddRef(This->parent);
477 *out = (IAudioClient *)&This->IAudioClient3_iface;
478 IAudioClient3_AddRef(&This->IAudioClient3_iface);
480 return S_OK;
483 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient3 *iface,
484 REFIID riid, void **ppv)
486 ACImpl *This = impl_from_IAudioClient3(iface);
487 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
489 if(!ppv)
490 return E_POINTER;
491 *ppv = NULL;
492 if(IsEqualIID(riid, &IID_IUnknown) ||
493 IsEqualIID(riid, &IID_IAudioClient) ||
494 IsEqualIID(riid, &IID_IAudioClient2) ||
495 IsEqualIID(riid, &IID_IAudioClient3))
496 *ppv = iface;
497 else if(IsEqualIID(riid, &IID_IMarshal))
498 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
500 if(*ppv){
501 IUnknown_AddRef((IUnknown*)*ppv);
502 return S_OK;
504 WARN("Unknown interface %s\n", debugstr_guid(riid));
505 return E_NOINTERFACE;
508 static ULONG WINAPI AudioClient_AddRef(IAudioClient3 *iface)
510 ACImpl *This = impl_from_IAudioClient3(iface);
511 ULONG ref;
512 ref = InterlockedIncrement(&This->ref);
513 TRACE("(%p) Refcount now %lu\n", This, ref);
514 return ref;
517 static ULONG WINAPI AudioClient_Release(IAudioClient3 *iface)
519 ACImpl *This = impl_from_IAudioClient3(iface);
520 struct release_stream_params params;
521 ULONG ref;
523 ref = InterlockedDecrement(&This->ref);
524 TRACE("(%p) Refcount now %lu\n", This, ref);
525 if(!ref){
526 if(This->timer){
527 HANDLE event;
528 BOOL wait;
529 event = CreateEventW(NULL, TRUE, FALSE, NULL);
530 wait = !DeleteTimerQueueTimer(g_timer_q, This->timer, event);
531 wait = wait && GetLastError() == ERROR_IO_PENDING;
532 if(event && wait)
533 WaitForSingleObject(event, INFINITE);
534 CloseHandle(event);
536 if(This->stream){
537 params.stream = This->stream;
538 UNIX_CALL(release_stream, &params);
540 if(This->session){
541 EnterCriticalSection(&g_sessions_lock);
542 list_remove(&This->entry);
543 LeaveCriticalSection(&g_sessions_lock);
545 HeapFree(GetProcessHeap(), 0, This->vols);
546 IMMDevice_Release(This->parent);
547 IUnknown_Release(This->pUnkFTMarshal);
548 HeapFree(GetProcessHeap(), 0, This);
550 return ref;
553 static void dump_fmt(const WAVEFORMATEX *fmt)
555 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
556 switch(fmt->wFormatTag){
557 case WAVE_FORMAT_PCM:
558 TRACE("WAVE_FORMAT_PCM");
559 break;
560 case WAVE_FORMAT_IEEE_FLOAT:
561 TRACE("WAVE_FORMAT_IEEE_FLOAT");
562 break;
563 case WAVE_FORMAT_EXTENSIBLE:
564 TRACE("WAVE_FORMAT_EXTENSIBLE");
565 break;
566 default:
567 TRACE("Unknown");
568 break;
570 TRACE(")\n");
572 TRACE("nChannels: %u\n", fmt->nChannels);
573 TRACE("nSamplesPerSec: %lu\n", fmt->nSamplesPerSec);
574 TRACE("nAvgBytesPerSec: %lu\n", fmt->nAvgBytesPerSec);
575 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
576 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
577 TRACE("cbSize: %u\n", fmt->cbSize);
579 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
580 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
581 TRACE("dwChannelMask: %08lx\n", fmtex->dwChannelMask);
582 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
583 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
587 static void session_init_vols(AudioSession *session, UINT channels)
589 if(session->channel_count < channels){
590 UINT i;
592 if(session->channel_vols)
593 session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
594 session->channel_vols, sizeof(float) * channels);
595 else
596 session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
597 sizeof(float) * channels);
598 if(!session->channel_vols)
599 return;
601 for(i = session->channel_count; i < channels; ++i)
602 session->channel_vols[i] = 1.f;
604 session->channel_count = channels;
608 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
609 UINT num_channels)
611 AudioSession *ret;
613 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
614 if(!ret)
615 return NULL;
617 memcpy(&ret->guid, guid, sizeof(GUID));
619 ret->device = device;
621 list_init(&ret->clients);
623 list_add_head(&g_sessions, &ret->entry);
625 session_init_vols(ret, num_channels);
627 ret->master_vol = 1.f;
629 return ret;
632 /* if channels == 0, then this will return or create a session with
633 * matching dataflow and GUID. otherwise, channels must also match */
634 static HRESULT get_audio_session(const GUID *sessionguid,
635 IMMDevice *device, UINT channels, AudioSession **out)
637 AudioSession *session;
639 if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
640 *out = create_session(&GUID_NULL, device, channels);
641 if(!*out)
642 return E_OUTOFMEMORY;
644 return S_OK;
647 *out = NULL;
648 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
649 if(session->device == device &&
650 IsEqualGUID(sessionguid, &session->guid)){
651 session_init_vols(session, channels);
652 *out = session;
653 break;
657 if(!*out){
658 *out = create_session(sessionguid, device, channels);
659 if(!*out)
660 return E_OUTOFMEMORY;
663 return S_OK;
666 static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
667 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
668 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
669 const GUID *sessionguid)
671 ACImpl *This = impl_from_IAudioClient3(iface);
672 struct release_stream_params release_params;
673 struct create_stream_params params;
674 stream_handle stream;
675 UINT32 i;
677 TRACE("(%p)->(%x, %lx, %s, %s, %p, %s)\n", This, mode, flags,
678 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
680 if(!fmt)
681 return E_POINTER;
683 dump_fmt(fmt);
685 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
686 return E_INVALIDARG;
688 if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
689 AUDCLNT_STREAMFLAGS_LOOPBACK |
690 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
691 AUDCLNT_STREAMFLAGS_NOPERSIST |
692 AUDCLNT_STREAMFLAGS_RATEADJUST |
693 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
694 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
695 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED |
696 AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY |
697 AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM)){
698 FIXME("Unknown flags: %08lx\n", flags);
699 return E_INVALIDARG;
702 if(mode == AUDCLNT_SHAREMODE_SHARED){
703 period = DefaultPeriod;
704 if( duration < 3 * period)
705 duration = 3 * period;
706 }else{
707 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
708 if(((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask == 0 ||
709 ((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask & SPEAKER_RESERVED)
710 return AUDCLNT_E_UNSUPPORTED_FORMAT;
713 if(!period)
714 period = DefaultPeriod; /* not minimum */
715 if(period < MinimumPeriod || period > 5000000)
716 return AUDCLNT_E_INVALID_DEVICE_PERIOD;
717 if(duration > 20000000) /* the smaller the period, the lower this limit */
718 return AUDCLNT_E_BUFFER_SIZE_ERROR;
719 if(flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK){
720 if(duration != period)
721 return AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL;
722 FIXME("EXCLUSIVE mode with EVENTCALLBACK\n");
723 return AUDCLNT_E_DEVICE_IN_USE;
724 }else{
725 if( duration < 8 * period)
726 duration = 8 * period; /* may grow above 2s */
730 EnterCriticalSection(&g_sessions_lock);
732 if(This->stream){
733 LeaveCriticalSection(&g_sessions_lock);
734 return AUDCLNT_E_ALREADY_INITIALIZED;
737 params.name = NULL;
738 params.device = This->device_name;
739 params.flow = This->dataflow;
740 params.share = mode;
741 params.flags = flags;
742 params.duration = duration;
743 params.period = period;
744 params.fmt = fmt;
745 params.channel_count = NULL;
746 params.stream = &stream;
748 UNIX_CALL(create_stream, &params);
749 if(FAILED(params.result)){
750 LeaveCriticalSection(&g_sessions_lock);
751 return params.result;
754 This->flags = flags;
755 This->channel_count = fmt->nChannels;
756 This->period_ms = period / 10000;
758 This->vols = HeapAlloc(GetProcessHeap(), 0, This->channel_count * sizeof(float));
759 if(!This->vols){
760 params.result = E_OUTOFMEMORY;
761 goto end;
764 for(i = 0; i < This->channel_count; ++i)
765 This->vols[i] = 1.f;
767 params.result = get_audio_session(sessionguid, This->parent, fmt->nChannels, &This->session);
768 if(FAILED(params.result)) goto end;
770 list_add_tail(&This->session->clients, &This->entry);
772 end:
773 if(FAILED(params.result)){
774 release_params.stream = stream;
775 UNIX_CALL(release_stream, &release_params);
776 HeapFree(GetProcessHeap(), 0, This->vols);
777 This->vols = NULL;
778 }else{
779 This->stream = stream;
780 set_stream_volumes(This, -1);
783 LeaveCriticalSection(&g_sessions_lock);
785 return params.result;
788 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient3 *iface,
789 UINT32 *frames)
791 ACImpl *This = impl_from_IAudioClient3(iface);
792 struct get_buffer_size_params params;
794 TRACE("(%p)->(%p)\n", This, frames);
796 if(!frames)
797 return E_POINTER;
799 if(!This->stream)
800 return AUDCLNT_E_NOT_INITIALIZED;
802 params.stream = This->stream;
803 params.frames = frames;
804 UNIX_CALL(get_buffer_size, &params);
805 return params.result;
808 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient3 *iface,
809 REFERENCE_TIME *out)
811 ACImpl *This = impl_from_IAudioClient3(iface);
812 struct get_latency_params params;
814 TRACE("(%p)->(%p)\n", This, out);
816 if(!out)
817 return E_POINTER;
819 if(!This->stream)
820 return AUDCLNT_E_NOT_INITIALIZED;
822 params.stream = This->stream;
823 params.latency = out;
824 UNIX_CALL(get_latency, &params);
825 return params.result;
828 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient3 *iface,
829 UINT32 *numpad)
831 ACImpl *This = impl_from_IAudioClient3(iface);
832 struct get_current_padding_params params;
834 TRACE("(%p)->(%p)\n", This, numpad);
836 if(!numpad)
837 return E_POINTER;
839 if(!This->stream)
840 return AUDCLNT_E_NOT_INITIALIZED;
842 params.stream = This->stream;
843 params.padding = numpad;
844 UNIX_CALL(get_current_padding, &params);
845 return params.result;
848 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient3 *iface,
849 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
850 WAVEFORMATEX **outpwfx)
852 ACImpl *This = impl_from_IAudioClient3(iface);
853 struct is_format_supported_params params;
855 TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx);
856 if(pwfx) dump_fmt(pwfx);
858 params.device = This->device_name;
859 params.flow = This->dataflow;
860 params.share = mode;
861 params.fmt_in = pwfx;
862 params.fmt_out = NULL;
864 if(outpwfx){
865 *outpwfx = NULL;
866 if(mode == AUDCLNT_SHAREMODE_SHARED)
867 params.fmt_out = CoTaskMemAlloc(sizeof(*params.fmt_out));
869 UNIX_CALL(is_format_supported, &params);
871 if(params.result == S_FALSE)
872 *outpwfx = &params.fmt_out->Format;
873 else
874 CoTaskMemFree(params.fmt_out);
876 return params.result;
879 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface,
880 WAVEFORMATEX **pwfx)
882 ACImpl *This = impl_from_IAudioClient3(iface);
883 struct get_mix_format_params params;
885 TRACE("(%p)->(%p)\n", This, pwfx);
887 if(!pwfx)
888 return E_POINTER;
889 *pwfx = NULL;
891 params.device = This->device_name;
892 params.flow = This->dataflow;
893 params.fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
894 if(!params.fmt)
895 return E_OUTOFMEMORY;
897 UNIX_CALL(get_mix_format, &params);
899 if(SUCCEEDED(params.result)){
900 *pwfx = &params.fmt->Format;
901 dump_fmt(*pwfx);
902 }else
903 CoTaskMemFree(params.fmt);
905 return params.result;
908 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient3 *iface,
909 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
911 ACImpl *This = impl_from_IAudioClient3(iface);
913 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
915 if(!defperiod && !minperiod)
916 return E_POINTER;
918 if(defperiod)
919 *defperiod = DefaultPeriod;
920 if(minperiod)
921 *minperiod = MinimumPeriod;
923 return S_OK;
926 void CALLBACK ca_period_cb(void *user, BOOLEAN timer)
928 ACImpl *This = user;
930 if(This->event)
931 SetEvent(This->event);
934 static HRESULT WINAPI AudioClient_Start(IAudioClient3 *iface)
936 ACImpl *This = impl_from_IAudioClient3(iface);
937 struct start_params params;
939 TRACE("(%p)\n", This);
941 if(!This->stream)
942 return AUDCLNT_E_NOT_INITIALIZED;
944 if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event)
945 return AUDCLNT_E_EVENTHANDLE_NOT_SET;
947 params.stream = This->stream;
948 UNIX_CALL(start, &params);
950 if(SUCCEEDED(params.result)){
951 if(This->event && !This->timer){
952 if(!CreateTimerQueueTimer(&This->timer, g_timer_q, ca_period_cb, This, 0,
953 This->period_ms, WT_EXECUTEINTIMERTHREAD)){
954 This->timer = NULL;
955 IAudioClient3_Stop(iface);
956 WARN("Unable to create timer: %lu\n", GetLastError());
957 return E_OUTOFMEMORY;
961 return params.result;
964 static HRESULT WINAPI AudioClient_Stop(IAudioClient3 *iface)
966 ACImpl *This = impl_from_IAudioClient3(iface);
967 struct stop_params params;
969 TRACE("(%p)\n", This);
971 if(!This->stream)
972 return AUDCLNT_E_NOT_INITIALIZED;
974 params.stream = This->stream;
975 UNIX_CALL(stop, &params);
976 return params.result;
979 static HRESULT WINAPI AudioClient_Reset(IAudioClient3 *iface)
981 ACImpl *This = impl_from_IAudioClient3(iface);
982 struct reset_params params;
984 TRACE("(%p)\n", This);
986 if(!This->stream)
987 return AUDCLNT_E_NOT_INITIALIZED;
989 params.stream = This->stream;
990 UNIX_CALL(reset, &params);
991 return params.result;
994 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient3 *iface,
995 HANDLE event)
997 ACImpl *This = impl_from_IAudioClient3(iface);
998 HRESULT hr = S_OK;
1000 TRACE("(%p)->(%p)\n", This, event);
1002 if(!event)
1003 return E_INVALIDARG;
1005 if(!This->stream)
1006 return AUDCLNT_E_NOT_INITIALIZED;
1008 EnterCriticalSection(&g_sessions_lock);
1010 if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK))
1011 hr = AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1012 else if(This->event){
1013 FIXME("called twice\n");
1014 hr = HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
1015 }else
1016 This->event = event;
1018 LeaveCriticalSection(&g_sessions_lock);
1020 return hr;
1023 static HRESULT WINAPI AudioClient_GetService(IAudioClient3 *iface, REFIID riid,
1024 void **ppv)
1026 ACImpl *This = impl_from_IAudioClient3(iface);
1027 HRESULT hr;
1029 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1031 if(!ppv)
1032 return E_POINTER;
1033 *ppv = NULL;
1035 if(!This->stream)
1036 return AUDCLNT_E_NOT_INITIALIZED;
1038 EnterCriticalSection(&g_sessions_lock);
1040 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1041 if(This->dataflow != eRender){
1042 hr = AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1043 goto end;
1045 IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
1046 *ppv = &This->IAudioRenderClient_iface;
1047 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1048 if(This->dataflow != eCapture){
1049 hr = AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1050 goto end;
1052 IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
1053 *ppv = &This->IAudioCaptureClient_iface;
1054 }else if(IsEqualIID(riid, &IID_IAudioClock)){
1055 IAudioClock_AddRef(&This->IAudioClock_iface);
1056 *ppv = &This->IAudioClock_iface;
1057 }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1058 IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
1059 *ppv = &This->IAudioStreamVolume_iface;
1060 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1061 if(!This->session_wrapper){
1062 This->session_wrapper = AudioSessionWrapper_Create(This);
1063 if(!This->session_wrapper){
1064 hr = E_OUTOFMEMORY;
1065 goto end;
1067 }else
1068 IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
1070 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1071 }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1072 if(!This->session_wrapper){
1073 This->session_wrapper = AudioSessionWrapper_Create(This);
1074 if(!This->session_wrapper){
1075 hr = E_OUTOFMEMORY;
1076 goto end;
1078 }else
1079 IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
1081 *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1082 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1083 if(!This->session_wrapper){
1084 This->session_wrapper = AudioSessionWrapper_Create(This);
1085 if(!This->session_wrapper){
1086 hr = E_OUTOFMEMORY;
1087 goto end;
1089 }else
1090 ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
1092 *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1095 if(*ppv) hr = S_OK;
1096 else{
1097 FIXME("stub %s\n", debugstr_guid(riid));
1098 hr = E_NOINTERFACE;
1101 end:
1102 LeaveCriticalSection(&g_sessions_lock);
1103 return hr;
1106 static HRESULT WINAPI AudioClient_IsOffloadCapable(IAudioClient3 *iface,
1107 AUDIO_STREAM_CATEGORY category, BOOL *offload_capable)
1109 ACImpl *This = impl_from_IAudioClient3(iface);
1111 TRACE("(%p)->(0x%x, %p)\n", This, category, offload_capable);
1113 if(!offload_capable)
1114 return E_INVALIDARG;
1116 *offload_capable = FALSE;
1118 return S_OK;
1121 static HRESULT WINAPI AudioClient_SetClientProperties(IAudioClient3 *iface,
1122 const AudioClientProperties *prop)
1124 ACImpl *This = impl_from_IAudioClient3(iface);
1125 const Win8AudioClientProperties *legacy_prop = (const Win8AudioClientProperties *)prop;
1127 TRACE("(%p)->(%p)\n", This, prop);
1129 if(!legacy_prop)
1130 return E_POINTER;
1132 if(legacy_prop->cbSize == sizeof(AudioClientProperties)){
1133 TRACE("{ bIsOffload: %u, eCategory: 0x%x, Options: 0x%x }\n",
1134 legacy_prop->bIsOffload,
1135 legacy_prop->eCategory,
1136 prop->Options);
1137 }else if(legacy_prop->cbSize == sizeof(Win8AudioClientProperties)){
1138 TRACE("{ bIsOffload: %u, eCategory: 0x%x }\n",
1139 legacy_prop->bIsOffload,
1140 legacy_prop->eCategory);
1141 }else{
1142 WARN("Unsupported Size = %d\n", legacy_prop->cbSize);
1143 return E_INVALIDARG;
1147 if(legacy_prop->bIsOffload)
1148 return AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE;
1150 return S_OK;
1153 static HRESULT WINAPI AudioClient_GetBufferSizeLimits(IAudioClient3 *iface,
1154 const WAVEFORMATEX *format, BOOL event_driven, REFERENCE_TIME *min_duration,
1155 REFERENCE_TIME *max_duration)
1157 ACImpl *This = impl_from_IAudioClient3(iface);
1159 FIXME("(%p)->(%p, %u, %p, %p)\n", This, format, event_driven, min_duration, max_duration);
1161 return E_NOTIMPL;
1164 static HRESULT WINAPI AudioClient_GetSharedModeEnginePeriod(IAudioClient3 *iface,
1165 const WAVEFORMATEX *format, UINT32 *default_period_frames, UINT32 *unit_period_frames,
1166 UINT32 *min_period_frames, UINT32 *max_period_frames)
1168 ACImpl *This = impl_from_IAudioClient3(iface);
1170 FIXME("(%p)->(%p, %p, %p, %p, %p)\n", This, format, default_period_frames, unit_period_frames,
1171 min_period_frames, max_period_frames);
1173 return E_NOTIMPL;
1176 static HRESULT WINAPI AudioClient_GetCurrentSharedModeEnginePeriod(IAudioClient3 *iface,
1177 WAVEFORMATEX **cur_format, UINT32 *cur_period_frames)
1179 ACImpl *This = impl_from_IAudioClient3(iface);
1181 FIXME("(%p)->(%p, %p)\n", This, cur_format, cur_period_frames);
1183 return E_NOTIMPL;
1186 static HRESULT WINAPI AudioClient_InitializeSharedAudioStream(IAudioClient3 *iface,
1187 DWORD flags, UINT32 period_frames, const WAVEFORMATEX *format,
1188 const GUID *session_guid)
1190 ACImpl *This = impl_from_IAudioClient3(iface);
1192 FIXME("(%p)->(0x%lx, %u, %p, %s)\n", This, flags, period_frames, format, debugstr_guid(session_guid));
1194 return E_NOTIMPL;
1197 static const IAudioClient3Vtbl AudioClient3_Vtbl =
1199 AudioClient_QueryInterface,
1200 AudioClient_AddRef,
1201 AudioClient_Release,
1202 AudioClient_Initialize,
1203 AudioClient_GetBufferSize,
1204 AudioClient_GetStreamLatency,
1205 AudioClient_GetCurrentPadding,
1206 AudioClient_IsFormatSupported,
1207 AudioClient_GetMixFormat,
1208 AudioClient_GetDevicePeriod,
1209 AudioClient_Start,
1210 AudioClient_Stop,
1211 AudioClient_Reset,
1212 AudioClient_SetEventHandle,
1213 AudioClient_GetService,
1214 AudioClient_IsOffloadCapable,
1215 AudioClient_SetClientProperties,
1216 AudioClient_GetBufferSizeLimits,
1217 AudioClient_GetSharedModeEnginePeriod,
1218 AudioClient_GetCurrentSharedModeEnginePeriod,
1219 AudioClient_InitializeSharedAudioStream,
1222 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1223 IAudioRenderClient *iface, REFIID riid, void **ppv)
1225 ACImpl *This = impl_from_IAudioRenderClient(iface);
1226 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1228 if(!ppv)
1229 return E_POINTER;
1230 *ppv = NULL;
1232 if(IsEqualIID(riid, &IID_IUnknown) ||
1233 IsEqualIID(riid, &IID_IAudioRenderClient))
1234 *ppv = iface;
1235 else if(IsEqualIID(riid, &IID_IMarshal))
1236 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
1238 if(*ppv){
1239 IUnknown_AddRef((IUnknown*)*ppv);
1240 return S_OK;
1243 WARN("Unknown interface %s\n", debugstr_guid(riid));
1244 return E_NOINTERFACE;
1247 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1249 ACImpl *This = impl_from_IAudioRenderClient(iface);
1250 return AudioClient_AddRef(&This->IAudioClient3_iface);
1253 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1255 ACImpl *This = impl_from_IAudioRenderClient(iface);
1256 return AudioClient_Release(&This->IAudioClient3_iface);
1259 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1260 UINT32 frames, BYTE **data)
1262 ACImpl *This = impl_from_IAudioRenderClient(iface);
1263 struct get_render_buffer_params params;
1265 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1267 if(!data)
1268 return E_POINTER;
1269 *data = NULL;
1271 params.stream = This->stream;
1272 params.frames = frames;
1273 params.data = data;
1274 UNIX_CALL(get_render_buffer, &params);
1275 return params.result;
1278 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1279 IAudioRenderClient *iface, UINT32 frames, DWORD flags)
1281 ACImpl *This = impl_from_IAudioRenderClient(iface);
1282 struct release_render_buffer_params params;
1284 TRACE("(%p)->(%u, %lx)\n", This, frames, flags);
1286 params.stream = This->stream;
1287 params.frames = frames;
1288 params.flags = flags;
1289 UNIX_CALL(release_render_buffer, &params);
1290 return params.result;
1293 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1294 AudioRenderClient_QueryInterface,
1295 AudioRenderClient_AddRef,
1296 AudioRenderClient_Release,
1297 AudioRenderClient_GetBuffer,
1298 AudioRenderClient_ReleaseBuffer
1301 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1302 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1304 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1305 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1307 if(!ppv)
1308 return E_POINTER;
1309 *ppv = NULL;
1311 if(IsEqualIID(riid, &IID_IUnknown) ||
1312 IsEqualIID(riid, &IID_IAudioCaptureClient))
1313 *ppv = iface;
1314 else if(IsEqualIID(riid, &IID_IMarshal))
1315 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
1317 if(*ppv){
1318 IUnknown_AddRef((IUnknown*)*ppv);
1319 return S_OK;
1322 WARN("Unknown interface %s\n", debugstr_guid(riid));
1323 return E_NOINTERFACE;
1326 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1328 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1329 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1332 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1334 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1335 return IAudioClient3_Release(&This->IAudioClient3_iface);
1338 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1339 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1340 UINT64 *qpcpos)
1342 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1343 struct get_capture_buffer_params params;
1345 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1346 devpos, qpcpos);
1348 if(!data)
1349 return E_POINTER;
1351 *data = NULL;
1353 if(!frames || !flags)
1354 return E_POINTER;
1356 params.stream = This->stream;
1357 params.data = data;
1358 params.frames = frames;
1359 params.flags = flags;
1360 params.devpos = devpos;
1361 params.qpcpos = qpcpos;
1362 UNIX_CALL(get_capture_buffer, &params);
1363 return params.result;
1366 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1367 IAudioCaptureClient *iface, UINT32 done)
1369 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1370 struct release_capture_buffer_params params;
1372 TRACE("(%p)->(%u)\n", This, done);
1374 params.stream = This->stream;
1375 params.done = done;
1376 UNIX_CALL(release_capture_buffer, &params);
1377 return params.result;
1380 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1381 IAudioCaptureClient *iface, UINT32 *frames)
1383 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1384 struct get_next_packet_size_params params;
1386 TRACE("(%p)->(%p)\n", This, frames);
1388 if(!frames)
1389 return E_POINTER;
1391 params.stream = This->stream;
1392 params.frames = frames;
1393 UNIX_CALL(get_next_packet_size, &params);
1394 return params.result;
1397 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1399 AudioCaptureClient_QueryInterface,
1400 AudioCaptureClient_AddRef,
1401 AudioCaptureClient_Release,
1402 AudioCaptureClient_GetBuffer,
1403 AudioCaptureClient_ReleaseBuffer,
1404 AudioCaptureClient_GetNextPacketSize
1407 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1408 REFIID riid, void **ppv)
1410 ACImpl *This = impl_from_IAudioClock(iface);
1412 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1414 if(!ppv)
1415 return E_POINTER;
1416 *ppv = NULL;
1418 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
1419 *ppv = iface;
1420 else if(IsEqualIID(riid, &IID_IAudioClock2))
1421 *ppv = &This->IAudioClock2_iface;
1422 if(*ppv){
1423 IUnknown_AddRef((IUnknown*)*ppv);
1424 return S_OK;
1427 WARN("Unknown interface %s\n", debugstr_guid(riid));
1428 return E_NOINTERFACE;
1431 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
1433 ACImpl *This = impl_from_IAudioClock(iface);
1434 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1437 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
1439 ACImpl *This = impl_from_IAudioClock(iface);
1440 return IAudioClient3_Release(&This->IAudioClient3_iface);
1443 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
1445 ACImpl *This = impl_from_IAudioClock(iface);
1446 struct get_frequency_params params;
1448 TRACE("(%p)->(%p)\n", This, freq);
1450 params.stream = This->stream;
1451 params.freq = freq;
1452 UNIX_CALL(get_frequency, &params);
1453 return params.result;
1456 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
1457 UINT64 *qpctime)
1459 ACImpl *This = impl_from_IAudioClock(iface);
1460 struct get_position_params params;
1462 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
1464 if(!pos)
1465 return E_POINTER;
1467 params.stream = This->stream;
1468 params.pos = pos;
1469 params.qpctime = qpctime;
1470 UNIX_CALL(get_position, &params);
1471 return params.result;
1474 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
1475 DWORD *chars)
1477 ACImpl *This = impl_from_IAudioClock(iface);
1479 TRACE("(%p)->(%p)\n", This, chars);
1481 if(!chars)
1482 return E_POINTER;
1484 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
1486 return S_OK;
1489 static const IAudioClockVtbl AudioClock_Vtbl =
1491 AudioClock_QueryInterface,
1492 AudioClock_AddRef,
1493 AudioClock_Release,
1494 AudioClock_GetFrequency,
1495 AudioClock_GetPosition,
1496 AudioClock_GetCharacteristics
1499 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
1500 REFIID riid, void **ppv)
1502 ACImpl *This = impl_from_IAudioClock2(iface);
1503 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
1506 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
1508 ACImpl *This = impl_from_IAudioClock2(iface);
1509 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1512 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
1514 ACImpl *This = impl_from_IAudioClock2(iface);
1515 return IAudioClient3_Release(&This->IAudioClient3_iface);
1518 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
1519 UINT64 *pos, UINT64 *qpctime)
1521 ACImpl *This = impl_from_IAudioClock2(iface);
1523 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
1525 return E_NOTIMPL;
1528 static const IAudioClock2Vtbl AudioClock2_Vtbl =
1530 AudioClock2_QueryInterface,
1531 AudioClock2_AddRef,
1532 AudioClock2_Release,
1533 AudioClock2_GetDevicePosition
1536 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
1538 AudioSessionWrapper *ret;
1540 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1541 sizeof(AudioSessionWrapper));
1542 if(!ret)
1543 return NULL;
1545 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
1546 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
1547 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
1549 ret->ref = 1;
1551 ret->client = client;
1552 if(client){
1553 ret->session = client->session;
1554 IAudioClient3_AddRef(&client->IAudioClient3_iface);
1557 return ret;
1560 static HRESULT WINAPI AudioSessionControl_QueryInterface(
1561 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
1563 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1565 if(!ppv)
1566 return E_POINTER;
1567 *ppv = NULL;
1569 if(IsEqualIID(riid, &IID_IUnknown) ||
1570 IsEqualIID(riid, &IID_IAudioSessionControl) ||
1571 IsEqualIID(riid, &IID_IAudioSessionControl2))
1572 *ppv = iface;
1573 if(*ppv){
1574 IUnknown_AddRef((IUnknown*)*ppv);
1575 return S_OK;
1578 WARN("Unknown interface %s\n", debugstr_guid(riid));
1579 return E_NOINTERFACE;
1582 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
1584 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1585 ULONG ref;
1586 ref = InterlockedIncrement(&This->ref);
1587 TRACE("(%p) Refcount now %lu\n", This, ref);
1588 return ref;
1591 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
1593 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1594 ULONG ref;
1596 EnterCriticalSection(&g_sessions_lock);
1598 ref = InterlockedDecrement(&This->ref);
1599 TRACE("(%p) Refcount now %lu\n", This, ref);
1600 if(!ref){
1601 if(This->client){
1602 This->client->session_wrapper = NULL;
1603 AudioClient_Release(&This->client->IAudioClient3_iface);
1605 HeapFree(GetProcessHeap(), 0, This);
1608 LeaveCriticalSection(&g_sessions_lock);
1609 return ref;
1612 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
1613 AudioSessionState *state)
1615 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1616 struct is_started_params params;
1617 ACImpl *client;
1619 TRACE("(%p)->(%p)\n", This, state);
1621 if(!state)
1622 return NULL_PTR_ERR;
1624 EnterCriticalSection(&g_sessions_lock);
1626 if(list_empty(&This->session->clients)){
1627 *state = AudioSessionStateExpired;
1628 LeaveCriticalSection(&g_sessions_lock);
1629 return S_OK;
1632 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
1633 params.stream = client->stream;
1634 UNIX_CALL(is_started, &params);
1635 if(params.result == S_OK){
1636 *state = AudioSessionStateActive;
1637 LeaveCriticalSection(&g_sessions_lock);
1638 return S_OK;
1642 LeaveCriticalSection(&g_sessions_lock);
1644 *state = AudioSessionStateInactive;
1646 return S_OK;
1649 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
1650 IAudioSessionControl2 *iface, WCHAR **name)
1652 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1654 FIXME("(%p)->(%p) - stub\n", This, name);
1656 return E_NOTIMPL;
1659 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
1660 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
1662 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1664 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
1666 return E_NOTIMPL;
1669 static HRESULT WINAPI AudioSessionControl_GetIconPath(
1670 IAudioSessionControl2 *iface, WCHAR **path)
1672 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1674 FIXME("(%p)->(%p) - stub\n", This, path);
1676 return E_NOTIMPL;
1679 static HRESULT WINAPI AudioSessionControl_SetIconPath(
1680 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
1682 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1684 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
1686 return E_NOTIMPL;
1689 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
1690 IAudioSessionControl2 *iface, GUID *group)
1692 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1694 FIXME("(%p)->(%p) - stub\n", This, group);
1696 return E_NOTIMPL;
1699 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
1700 IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
1702 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1704 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
1705 debugstr_guid(session));
1707 return E_NOTIMPL;
1710 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
1711 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
1713 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1715 FIXME("(%p)->(%p) - stub\n", This, events);
1717 return S_OK;
1720 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
1721 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
1723 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1725 FIXME("(%p)->(%p) - stub\n", This, events);
1727 return S_OK;
1730 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
1731 IAudioSessionControl2 *iface, WCHAR **id)
1733 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1735 FIXME("(%p)->(%p) - stub\n", This, id);
1737 return E_NOTIMPL;
1740 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
1741 IAudioSessionControl2 *iface, WCHAR **id)
1743 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1745 FIXME("(%p)->(%p) - stub\n", This, id);
1747 return E_NOTIMPL;
1750 static HRESULT WINAPI AudioSessionControl_GetProcessId(
1751 IAudioSessionControl2 *iface, DWORD *pid)
1753 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1755 TRACE("(%p)->(%p)\n", This, pid);
1757 if(!pid)
1758 return E_POINTER;
1760 *pid = GetCurrentProcessId();
1762 return S_OK;
1765 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
1766 IAudioSessionControl2 *iface)
1768 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1770 TRACE("(%p)\n", This);
1772 return S_FALSE;
1775 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
1776 IAudioSessionControl2 *iface, BOOL optout)
1778 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1780 TRACE("(%p)->(%d)\n", This, optout);
1782 return S_OK;
1785 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
1787 AudioSessionControl_QueryInterface,
1788 AudioSessionControl_AddRef,
1789 AudioSessionControl_Release,
1790 AudioSessionControl_GetState,
1791 AudioSessionControl_GetDisplayName,
1792 AudioSessionControl_SetDisplayName,
1793 AudioSessionControl_GetIconPath,
1794 AudioSessionControl_SetIconPath,
1795 AudioSessionControl_GetGroupingParam,
1796 AudioSessionControl_SetGroupingParam,
1797 AudioSessionControl_RegisterAudioSessionNotification,
1798 AudioSessionControl_UnregisterAudioSessionNotification,
1799 AudioSessionControl_GetSessionIdentifier,
1800 AudioSessionControl_GetSessionInstanceIdentifier,
1801 AudioSessionControl_GetProcessId,
1802 AudioSessionControl_IsSystemSoundsSession,
1803 AudioSessionControl_SetDuckingPreference
1806 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
1807 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
1809 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1811 if(!ppv)
1812 return E_POINTER;
1813 *ppv = NULL;
1815 if(IsEqualIID(riid, &IID_IUnknown) ||
1816 IsEqualIID(riid, &IID_ISimpleAudioVolume))
1817 *ppv = iface;
1818 if(*ppv){
1819 IUnknown_AddRef((IUnknown*)*ppv);
1820 return S_OK;
1823 WARN("Unknown interface %s\n", debugstr_guid(riid));
1824 return E_NOINTERFACE;
1827 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
1829 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1830 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
1833 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
1835 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1836 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
1839 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
1840 ISimpleAudioVolume *iface, float level, const GUID *context)
1842 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1843 AudioSession *session = This->session;
1844 ACImpl *client;
1846 TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
1848 if(level < 0.f || level > 1.f)
1849 return E_INVALIDARG;
1851 if(context)
1852 FIXME("Notifications not supported yet\n");
1854 EnterCriticalSection(&g_sessions_lock);
1856 session->master_vol = level;
1858 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
1859 set_stream_volumes(client, -1);
1861 LeaveCriticalSection(&g_sessions_lock);
1863 return S_OK;
1866 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
1867 ISimpleAudioVolume *iface, float *level)
1869 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1870 AudioSession *session = This->session;
1872 TRACE("(%p)->(%p)\n", session, level);
1874 if(!level)
1875 return NULL_PTR_ERR;
1877 *level = session->master_vol;
1879 return S_OK;
1882 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
1883 BOOL mute, const GUID *context)
1885 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1886 AudioSession *session = This->session;
1887 ACImpl *client;
1889 TRACE("(%p)->(%u, %s)\n", session, mute, debugstr_guid(context));
1891 if(context)
1892 FIXME("Notifications not supported yet\n");
1894 EnterCriticalSection(&g_sessions_lock);
1896 session->mute = mute;
1898 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
1899 set_stream_volumes(client, -1);
1901 LeaveCriticalSection(&g_sessions_lock);
1903 return S_OK;
1906 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
1907 BOOL *mute)
1909 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1910 AudioSession *session = This->session;
1912 TRACE("(%p)->(%p)\n", session, mute);
1914 if(!mute)
1915 return NULL_PTR_ERR;
1917 *mute = session->mute;
1919 return S_OK;
1922 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
1924 SimpleAudioVolume_QueryInterface,
1925 SimpleAudioVolume_AddRef,
1926 SimpleAudioVolume_Release,
1927 SimpleAudioVolume_SetMasterVolume,
1928 SimpleAudioVolume_GetMasterVolume,
1929 SimpleAudioVolume_SetMute,
1930 SimpleAudioVolume_GetMute
1933 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
1934 IAudioStreamVolume *iface, REFIID riid, void **ppv)
1936 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1938 if(!ppv)
1939 return E_POINTER;
1940 *ppv = NULL;
1942 if(IsEqualIID(riid, &IID_IUnknown) ||
1943 IsEqualIID(riid, &IID_IAudioStreamVolume))
1944 *ppv = iface;
1945 if(*ppv){
1946 IUnknown_AddRef((IUnknown*)*ppv);
1947 return S_OK;
1950 WARN("Unknown interface %s\n", debugstr_guid(riid));
1951 return E_NOINTERFACE;
1954 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
1956 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1957 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1960 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
1962 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1963 return IAudioClient3_Release(&This->IAudioClient3_iface);
1966 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
1967 IAudioStreamVolume *iface, UINT32 *out)
1969 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1971 TRACE("(%p)->(%p)\n", This, out);
1973 if(!out)
1974 return E_POINTER;
1976 *out = This->channel_count;
1978 return S_OK;
1981 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
1982 IAudioStreamVolume *iface, UINT32 index, float level)
1984 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1986 TRACE("(%p)->(%d, %f)\n", This, index, level);
1988 if(level < 0.f || level > 1.f)
1989 return E_INVALIDARG;
1991 if(index >= This->channel_count)
1992 return E_INVALIDARG;
1994 EnterCriticalSection(&g_sessions_lock);
1996 This->vols[index] = level;
1998 WARN("CoreAudio doesn't support per-channel volume control\n");
1999 set_stream_volumes(This, index);
2001 LeaveCriticalSection(&g_sessions_lock);
2003 return S_OK;
2006 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2007 IAudioStreamVolume *iface, UINT32 index, float *level)
2009 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2011 TRACE("(%p)->(%d, %p)\n", This, index, level);
2013 if(!level)
2014 return E_POINTER;
2016 if(index >= This->channel_count)
2017 return E_INVALIDARG;
2019 *level = This->vols[index];
2021 return S_OK;
2024 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2025 IAudioStreamVolume *iface, UINT32 count, const float *levels)
2027 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2028 UINT32 i;
2030 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2032 if(!levels)
2033 return E_POINTER;
2035 if(count != This->channel_count)
2036 return E_INVALIDARG;
2038 EnterCriticalSection(&g_sessions_lock);
2040 for(i = 0; i < count; ++i)
2041 This->vols[i] = levels[i];
2043 set_stream_volumes(This, -1);
2045 LeaveCriticalSection(&g_sessions_lock);
2047 return S_OK;
2050 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2051 IAudioStreamVolume *iface, UINT32 count, float *levels)
2053 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2054 UINT32 i;
2056 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2058 if(!levels)
2059 return E_POINTER;
2061 if(count != This->channel_count)
2062 return E_INVALIDARG;
2064 EnterCriticalSection(&g_sessions_lock);
2066 for(i = 0; i < count; ++i)
2067 levels[i] = This->vols[i];
2069 LeaveCriticalSection(&g_sessions_lock);
2071 return S_OK;
2074 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2076 AudioStreamVolume_QueryInterface,
2077 AudioStreamVolume_AddRef,
2078 AudioStreamVolume_Release,
2079 AudioStreamVolume_GetChannelCount,
2080 AudioStreamVolume_SetChannelVolume,
2081 AudioStreamVolume_GetChannelVolume,
2082 AudioStreamVolume_SetAllVolumes,
2083 AudioStreamVolume_GetAllVolumes
2086 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2087 IChannelAudioVolume *iface, REFIID riid, void **ppv)
2089 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2091 if(!ppv)
2092 return E_POINTER;
2093 *ppv = NULL;
2095 if(IsEqualIID(riid, &IID_IUnknown) ||
2096 IsEqualIID(riid, &IID_IChannelAudioVolume))
2097 *ppv = iface;
2098 if(*ppv){
2099 IUnknown_AddRef((IUnknown*)*ppv);
2100 return S_OK;
2103 WARN("Unknown interface %s\n", debugstr_guid(riid));
2104 return E_NOINTERFACE;
2107 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2109 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2110 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2113 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2115 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2116 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2119 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2120 IChannelAudioVolume *iface, UINT32 *out)
2122 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2123 AudioSession *session = This->session;
2125 TRACE("(%p)->(%p)\n", session, out);
2127 if(!out)
2128 return NULL_PTR_ERR;
2130 *out = session->channel_count;
2132 return S_OK;
2135 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2136 IChannelAudioVolume *iface, UINT32 index, float level,
2137 const GUID *context)
2139 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2140 AudioSession *session = This->session;
2141 ACImpl *client;
2143 TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2144 wine_dbgstr_guid(context));
2146 if(level < 0.f || level > 1.f)
2147 return E_INVALIDARG;
2149 if(index >= session->channel_count)
2150 return E_INVALIDARG;
2152 if(context)
2153 FIXME("Notifications not supported yet\n");
2155 EnterCriticalSection(&g_sessions_lock);
2157 session->channel_vols[index] = level;
2159 WARN("CoreAudio doesn't support per-channel volume control\n");
2160 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
2161 set_stream_volumes(client, index);
2163 LeaveCriticalSection(&g_sessions_lock);
2165 return S_OK;
2168 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2169 IChannelAudioVolume *iface, UINT32 index, float *level)
2171 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2172 AudioSession *session = This->session;
2174 TRACE("(%p)->(%d, %p)\n", session, index, level);
2176 if(!level)
2177 return NULL_PTR_ERR;
2179 if(index >= session->channel_count)
2180 return E_INVALIDARG;
2182 *level = session->channel_vols[index];
2184 return S_OK;
2187 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2188 IChannelAudioVolume *iface, UINT32 count, const float *levels,
2189 const GUID *context)
2191 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2192 AudioSession *session = This->session;
2193 ACImpl *client;
2194 UINT32 i;
2196 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2197 wine_dbgstr_guid(context));
2199 if(!levels)
2200 return NULL_PTR_ERR;
2202 if(count != session->channel_count)
2203 return E_INVALIDARG;
2205 if(context)
2206 FIXME("Notifications not supported yet\n");
2208 EnterCriticalSection(&g_sessions_lock);
2210 for(i = 0; i < count; ++i)
2211 session->channel_vols[i] = levels[i];
2213 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
2214 set_stream_volumes(client, -1);
2216 LeaveCriticalSection(&g_sessions_lock);
2218 return S_OK;
2221 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2222 IChannelAudioVolume *iface, UINT32 count, float *levels)
2224 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2225 AudioSession *session = This->session;
2226 int i;
2228 TRACE("(%p)->(%d, %p)\n", session, count, levels);
2230 if(!levels)
2231 return NULL_PTR_ERR;
2233 if(count != session->channel_count)
2234 return E_INVALIDARG;
2236 for(i = 0; i < count; ++i)
2237 levels[i] = session->channel_vols[i];
2239 return S_OK;
2242 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2244 ChannelAudioVolume_QueryInterface,
2245 ChannelAudioVolume_AddRef,
2246 ChannelAudioVolume_Release,
2247 ChannelAudioVolume_GetChannelCount,
2248 ChannelAudioVolume_SetChannelVolume,
2249 ChannelAudioVolume_GetChannelVolume,
2250 ChannelAudioVolume_SetAllVolumes,
2251 ChannelAudioVolume_GetAllVolumes
2254 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2255 REFIID riid, void **ppv)
2257 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2259 if(!ppv)
2260 return E_POINTER;
2261 *ppv = NULL;
2263 if(IsEqualIID(riid, &IID_IUnknown) ||
2264 IsEqualIID(riid, &IID_IAudioSessionManager) ||
2265 IsEqualIID(riid, &IID_IAudioSessionManager2))
2266 *ppv = iface;
2267 if(*ppv){
2268 IUnknown_AddRef((IUnknown*)*ppv);
2269 return S_OK;
2272 WARN("Unknown interface %s\n", debugstr_guid(riid));
2273 return E_NOINTERFACE;
2276 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2278 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2279 ULONG ref;
2280 ref = InterlockedIncrement(&This->ref);
2281 TRACE("(%p) Refcount now %lu\n", This, ref);
2282 return ref;
2285 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2287 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2288 ULONG ref;
2289 ref = InterlockedDecrement(&This->ref);
2290 TRACE("(%p) Refcount now %lu\n", This, ref);
2291 if(!ref)
2292 HeapFree(GetProcessHeap(), 0, This);
2293 return ref;
2296 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2297 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2298 IAudioSessionControl **out)
2300 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2301 AudioSession *session;
2302 AudioSessionWrapper *wrapper;
2303 HRESULT hr;
2305 TRACE("(%p)->(%s, %lx, %p)\n", This, debugstr_guid(session_guid),
2306 flags, out);
2308 hr = get_audio_session(session_guid, This->device, 0, &session);
2309 if(FAILED(hr))
2310 return hr;
2312 wrapper = AudioSessionWrapper_Create(NULL);
2313 if(!wrapper)
2314 return E_OUTOFMEMORY;
2316 wrapper->session = session;
2318 *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
2320 return S_OK;
2323 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
2324 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2325 ISimpleAudioVolume **out)
2327 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2328 AudioSession *session;
2329 AudioSessionWrapper *wrapper;
2330 HRESULT hr;
2332 TRACE("(%p)->(%s, %lx, %p)\n", This, debugstr_guid(session_guid),
2333 flags, out);
2335 hr = get_audio_session(session_guid, This->device, 0, &session);
2336 if(FAILED(hr))
2337 return hr;
2339 wrapper = AudioSessionWrapper_Create(NULL);
2340 if(!wrapper)
2341 return E_OUTOFMEMORY;
2343 wrapper->session = session;
2345 *out = &wrapper->ISimpleAudioVolume_iface;
2347 return S_OK;
2350 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
2351 IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
2353 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2354 FIXME("(%p)->(%p) - stub\n", This, out);
2355 return E_NOTIMPL;
2358 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
2359 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2361 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2362 FIXME("(%p)->(%p) - stub\n", This, notification);
2363 return E_NOTIMPL;
2366 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
2367 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2369 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2370 FIXME("(%p)->(%p) - stub\n", This, notification);
2371 return E_NOTIMPL;
2374 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
2375 IAudioSessionManager2 *iface, const WCHAR *session_id,
2376 IAudioVolumeDuckNotification *notification)
2378 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2379 FIXME("(%p)->(%p) - stub\n", This, notification);
2380 return E_NOTIMPL;
2383 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
2384 IAudioSessionManager2 *iface,
2385 IAudioVolumeDuckNotification *notification)
2387 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2388 FIXME("(%p)->(%p) - stub\n", This, notification);
2389 return E_NOTIMPL;
2392 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
2394 AudioSessionManager_QueryInterface,
2395 AudioSessionManager_AddRef,
2396 AudioSessionManager_Release,
2397 AudioSessionManager_GetAudioSessionControl,
2398 AudioSessionManager_GetSimpleAudioVolume,
2399 AudioSessionManager_GetSessionEnumerator,
2400 AudioSessionManager_RegisterSessionNotification,
2401 AudioSessionManager_UnregisterSessionNotification,
2402 AudioSessionManager_RegisterDuckNotification,
2403 AudioSessionManager_UnregisterDuckNotification
2406 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
2407 IAudioSessionManager2 **out)
2409 SessionMgr *This;
2411 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
2412 if(!This)
2413 return E_OUTOFMEMORY;
2415 This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
2416 This->device = device;
2417 This->ref = 1;
2419 *out = &This->IAudioSessionManager2_iface;
2421 return S_OK;