winealsa: Use GetModuleFileName() instead of hardcoded module filename for registry...
[wine.git] / dlls / winealsa.drv / mmdevdrv.c
blob96a0a62d72ea381d3b86369bc8e8c0f300ff19a7
1 /*
2 * Copyright 2010 Maarten Lankhorst for CodeWeavers
3 * Copyright 2011 Andrew Eikum for CodeWeavers
4 * Copyright 2022 Huw Davies
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define COBJMACROS
23 #include <stdarg.h>
24 #include <wchar.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winnls.h"
29 #include "winreg.h"
30 #include "winternl.h"
31 #include "propsys.h"
32 #include "propkey.h"
33 #include "initguid.h"
34 #include "ole2.h"
35 #include "mmdeviceapi.h"
36 #include "devpkey.h"
37 #include "mmsystem.h"
38 #include "dsound.h"
40 #include "endpointvolume.h"
41 #include "audioclient.h"
42 #include "audiopolicy.h"
44 #include "wine/debug.h"
45 #include "wine/list.h"
46 #include "wine/unixlib.h"
48 #include "unixlib.h"
50 WINE_DEFAULT_DEBUG_CHANNEL(alsa);
52 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
54 static const REFERENCE_TIME DefaultPeriod = 100000;
55 static const REFERENCE_TIME MinimumPeriod = 50000;
57 struct ACImpl;
58 typedef struct ACImpl ACImpl;
60 typedef struct _AudioSession {
61 GUID guid;
62 struct list clients;
64 IMMDevice *device;
66 float master_vol;
67 UINT32 channel_count;
68 float *channel_vols;
69 BOOL mute;
71 struct list entry;
72 } AudioSession;
74 typedef struct _AudioSessionWrapper {
75 IAudioSessionControl2 IAudioSessionControl2_iface;
76 IChannelAudioVolume IChannelAudioVolume_iface;
77 ISimpleAudioVolume ISimpleAudioVolume_iface;
79 LONG ref;
81 ACImpl *client;
82 AudioSession *session;
83 } AudioSessionWrapper;
85 struct ACImpl {
86 IAudioClient3 IAudioClient3_iface;
87 IAudioRenderClient IAudioRenderClient_iface;
88 IAudioCaptureClient IAudioCaptureClient_iface;
89 IAudioClock IAudioClock_iface;
90 IAudioClock2 IAudioClock2_iface;
91 IAudioStreamVolume IAudioStreamVolume_iface;
93 LONG ref;
95 IMMDevice *parent;
96 IUnknown *pUnkFTMarshal;
98 EDataFlow dataflow;
99 float *vols;
100 UINT32 channel_count;
101 stream_handle stream;
103 HANDLE timer_thread;
105 AudioSession *session;
106 AudioSessionWrapper *session_wrapper;
108 struct list entry;
110 /* Keep at end */
111 char alsa_name[1];
114 typedef struct _SessionMgr {
115 IAudioSessionManager2 IAudioSessionManager2_iface;
117 LONG ref;
119 IMMDevice *device;
120 } SessionMgr;
122 static CRITICAL_SECTION g_sessions_lock;
123 static CRITICAL_SECTION_DEBUG g_sessions_lock_debug =
125 0, 0, &g_sessions_lock,
126 { &g_sessions_lock_debug.ProcessLocksList, &g_sessions_lock_debug.ProcessLocksList },
127 0, 0, { (DWORD_PTR)(__FILE__ ": g_sessions_lock") }
129 static CRITICAL_SECTION g_sessions_lock = { &g_sessions_lock_debug, -1, 0, 0, 0, 0 };
130 static struct list g_sessions = LIST_INIT(g_sessions);
132 static WCHAR drv_key_devicesW[256];
133 static const WCHAR guidW[] = {'g','u','i','d',0};
135 static const IAudioClient3Vtbl AudioClient3_Vtbl;
136 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
137 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
138 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
139 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
140 static const IAudioClockVtbl AudioClock_Vtbl;
141 static const IAudioClock2Vtbl AudioClock2_Vtbl;
142 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
143 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
144 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl;
146 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
148 static inline ACImpl *impl_from_IAudioClient3(IAudioClient3 *iface)
150 return CONTAINING_RECORD(iface, ACImpl, IAudioClient3_iface);
153 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
155 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
158 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
160 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
163 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
165 return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
168 static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
170 return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
173 static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
175 return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
178 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
180 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
183 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
185 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
188 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
190 return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
193 static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface)
195 return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface);
198 BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
200 switch (reason)
202 case DLL_PROCESS_ATTACH:
204 WCHAR buf[MAX_PATH];
205 WCHAR *filename;
207 if(__wine_init_unix_call()) return FALSE;
209 GetModuleFileNameW(dll, buf, ARRAY_SIZE(buf));
211 filename = wcsrchr(buf, '\\');
212 filename = filename ? filename + 1 : buf;
214 swprintf(drv_key_devicesW, ARRAY_SIZE(drv_key_devicesW),
215 L"Software\\Wine\\Drivers\\%s\\devices", filename);
217 break;
219 case DLL_PROCESS_DETACH:
220 if (reserved) break;
221 DeleteCriticalSection(&g_sessions_lock);
222 break;
224 return TRUE;
227 static HRESULT alsa_stream_release(stream_handle stream, HANDLE timer_thread)
229 struct release_stream_params params;
231 params.stream = stream;
232 params.timer_thread = timer_thread;
234 ALSA_CALL(release_stream, &params);
236 return params.result;
239 static DWORD WINAPI alsa_timer_thread(void *user)
241 struct timer_loop_params params;
242 struct ACImpl *This = user;
244 SetThreadDescription(GetCurrentThread(), L"winealsa_timer");
246 params.stream = This->stream;
248 ALSA_CALL(timer_loop, &params);
250 return 0;
253 static void set_device_guid(EDataFlow flow, HKEY drv_key, const WCHAR *key_name,
254 GUID *guid)
256 HKEY key;
257 BOOL opened = FALSE;
258 LONG lr;
260 if(!drv_key){
261 lr = RegCreateKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, NULL, 0, KEY_WRITE,
262 NULL, &drv_key, NULL);
263 if(lr != ERROR_SUCCESS){
264 ERR("RegCreateKeyEx(drv_key) failed: %lu\n", lr);
265 return;
267 opened = TRUE;
270 lr = RegCreateKeyExW(drv_key, key_name, 0, NULL, 0, KEY_WRITE,
271 NULL, &key, NULL);
272 if(lr != ERROR_SUCCESS){
273 ERR("RegCreateKeyEx(%s) failed: %lu\n", wine_dbgstr_w(key_name), lr);
274 goto exit;
277 lr = RegSetValueExW(key, guidW, 0, REG_BINARY, (BYTE*)guid,
278 sizeof(GUID));
279 if(lr != ERROR_SUCCESS)
280 ERR("RegSetValueEx(%s\\guid) failed: %lu\n", wine_dbgstr_w(key_name), lr);
282 RegCloseKey(key);
283 exit:
284 if(opened)
285 RegCloseKey(drv_key);
288 static void get_device_guid(EDataFlow flow, const char *device, GUID *guid)
290 HKEY key = NULL, dev_key;
291 DWORD type, size = sizeof(*guid);
292 WCHAR key_name[256];
294 if(flow == eCapture)
295 key_name[0] = '1';
296 else
297 key_name[0] = '0';
298 key_name[1] = ',';
299 MultiByteToWideChar(CP_UNIXCP, 0, device, -1, key_name + 2, ARRAY_SIZE(key_name) - 2);
301 if(RegOpenKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, KEY_WRITE|KEY_READ, &key) == ERROR_SUCCESS){
302 if(RegOpenKeyExW(key, key_name, 0, KEY_READ, &dev_key) == ERROR_SUCCESS){
303 if(RegQueryValueExW(dev_key, guidW, 0, &type,
304 (BYTE*)guid, &size) == ERROR_SUCCESS){
305 if(type == REG_BINARY){
306 RegCloseKey(dev_key);
307 RegCloseKey(key);
308 return;
310 ERR("Invalid type for device %s GUID: %lu; ignoring and overwriting\n",
311 wine_dbgstr_w(key_name), type);
313 RegCloseKey(dev_key);
317 CoCreateGuid(guid);
319 set_device_guid(flow, key, key_name, guid);
321 if(key)
322 RegCloseKey(key);
325 static void set_stream_volumes(ACImpl *This)
327 struct set_volumes_params params;
329 params.stream = This->stream;
330 params.master_volume = (This->session->mute ? 0.0f : This->session->master_vol);
331 params.volumes = This->vols;
332 params.session_volumes = This->session->channel_vols;
333 params.channel = 0;
335 ALSA_CALL(set_volumes, &params);
338 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids_out, GUID **guids_out,
339 UINT *num, UINT *def_index)
341 struct get_endpoint_ids_params params;
342 unsigned int i;
343 GUID *guids = NULL;
344 WCHAR **ids = NULL;
346 TRACE("%d %p %p %p %p\n", flow, ids, guids, num, def_index);
348 params.flow = flow;
349 params.size = 1000;
350 params.endpoints = NULL;
352 HeapFree(GetProcessHeap(), 0, params.endpoints);
353 params.endpoints = HeapAlloc(GetProcessHeap(), 0, params.size);
354 ALSA_CALL(get_endpoint_ids, &params);
355 }while(params.result == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
357 if(FAILED(params.result)) goto end;
359 ids = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, params.num * sizeof(*ids));
360 guids = HeapAlloc(GetProcessHeap(), 0, params.num * sizeof(*guids));
361 if(!ids || !guids){
362 params.result = E_OUTOFMEMORY;
363 goto end;
366 for(i = 0; i < params.num; i++){
367 WCHAR *name = (WCHAR *)((char *)params.endpoints + params.endpoints[i].name);
368 char *device = (char *)params.endpoints + params.endpoints[i].device;
369 unsigned int size = (wcslen(name) + 1) * sizeof(WCHAR);
371 ids[i] = HeapAlloc(GetProcessHeap(), 0, size);
372 if(!ids[i]){
373 params.result = E_OUTOFMEMORY;
374 goto end;
376 memcpy(ids[i], name, size);
377 get_device_guid(flow, device, guids + i);
379 *def_index = params.default_idx;
381 end:
382 HeapFree(GetProcessHeap(), 0, params.endpoints);
383 if(FAILED(params.result)){
384 HeapFree(GetProcessHeap(), 0, guids);
385 if(ids){
386 for(i = 0; i < params.num; i++)
387 HeapFree(GetProcessHeap(), 0, ids[i]);
388 HeapFree(GetProcessHeap(), 0, ids);
390 }else{
391 *ids_out = ids;
392 *guids_out = guids;
393 *num = params.num;
396 return params.result;
399 static BOOL get_alsa_name_by_guid(GUID *guid, char *name, DWORD name_size, EDataFlow *flow)
401 HKEY devices_key;
402 UINT i = 0;
403 WCHAR key_name[256];
404 DWORD key_name_size;
406 if(RegOpenKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, KEY_READ, &devices_key) != ERROR_SUCCESS){
407 ERR("No devices found in registry?\n");
408 return FALSE;
411 while(1){
412 HKEY key;
413 DWORD size, type;
414 GUID reg_guid;
416 key_name_size = ARRAY_SIZE(key_name);
417 if(RegEnumKeyExW(devices_key, i++, key_name, &key_name_size, NULL,
418 NULL, NULL, NULL) != ERROR_SUCCESS)
419 break;
421 if(RegOpenKeyExW(devices_key, key_name, 0, KEY_READ, &key) != ERROR_SUCCESS){
422 WARN("Couldn't open key: %s\n", wine_dbgstr_w(key_name));
423 continue;
426 size = sizeof(reg_guid);
427 if(RegQueryValueExW(key, guidW, 0, &type,
428 (BYTE*)&reg_guid, &size) == ERROR_SUCCESS){
429 if(IsEqualGUID(&reg_guid, guid)){
430 RegCloseKey(key);
431 RegCloseKey(devices_key);
433 TRACE("Found matching device key: %s\n", wine_dbgstr_w(key_name));
435 if(key_name[0] == '0')
436 *flow = eRender;
437 else if(key_name[0] == '1')
438 *flow = eCapture;
439 else{
440 ERR("Unknown device type: %c\n", key_name[0]);
441 return FALSE;
444 WideCharToMultiByte(CP_UNIXCP, 0, key_name + 2, -1, name, name_size, NULL, NULL);
446 return TRUE;
450 RegCloseKey(key);
453 RegCloseKey(devices_key);
455 WARN("No matching device in registry for GUID %s\n", debugstr_guid(guid));
457 return FALSE;
460 HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient **out)
462 ACImpl *This;
463 char alsa_name[256];
464 EDataFlow dataflow;
465 HRESULT hr;
466 int len;
468 TRACE("%s %p %p\n", debugstr_guid(guid), dev, out);
470 if(!get_alsa_name_by_guid(guid, alsa_name, sizeof(alsa_name), &dataflow))
471 return AUDCLNT_E_DEVICE_INVALIDATED;
473 if(dataflow != eRender && dataflow != eCapture)
474 return E_UNEXPECTED;
476 len = strlen(alsa_name);
477 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, offsetof(ACImpl, alsa_name[len + 1]));
478 if(!This)
479 return E_OUTOFMEMORY;
481 This->IAudioClient3_iface.lpVtbl = &AudioClient3_Vtbl;
482 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
483 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
484 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
485 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
486 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
488 hr = CoCreateFreeThreadedMarshaler((IUnknown *)&This->IAudioClient3_iface, &This->pUnkFTMarshal);
489 if (FAILED(hr)) {
490 HeapFree(GetProcessHeap(), 0, This);
491 return hr;
494 This->dataflow = dataflow;
495 memcpy(This->alsa_name, alsa_name, len + 1);
497 This->parent = dev;
498 IMMDevice_AddRef(This->parent);
500 *out = (IAudioClient *)&This->IAudioClient3_iface;
501 IAudioClient3_AddRef(&This->IAudioClient3_iface);
503 return S_OK;
506 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient3 *iface,
507 REFIID riid, void **ppv)
509 ACImpl *This = impl_from_IAudioClient3(iface);
510 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
512 if(!ppv)
513 return E_POINTER;
514 *ppv = NULL;
515 if(IsEqualIID(riid, &IID_IUnknown) ||
516 IsEqualIID(riid, &IID_IAudioClient) ||
517 IsEqualIID(riid, &IID_IAudioClient2) ||
518 IsEqualIID(riid, &IID_IAudioClient3))
519 *ppv = iface;
520 else if(IsEqualIID(riid, &IID_IMarshal))
521 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
523 if(*ppv){
524 IUnknown_AddRef((IUnknown*)*ppv);
525 return S_OK;
527 WARN("Unknown interface %s\n", debugstr_guid(riid));
528 return E_NOINTERFACE;
531 static ULONG WINAPI AudioClient_AddRef(IAudioClient3 *iface)
533 ACImpl *This = impl_from_IAudioClient3(iface);
534 ULONG ref;
535 ref = InterlockedIncrement(&This->ref);
536 TRACE("(%p) Refcount now %lu\n", This, ref);
537 return ref;
540 static ULONG WINAPI AudioClient_Release(IAudioClient3 *iface)
542 ACImpl *This = impl_from_IAudioClient3(iface);
543 ULONG ref;
545 ref = InterlockedDecrement(&This->ref);
546 TRACE("(%p) Refcount now %lu\n", This, ref);
547 if(!ref){
548 IAudioClient3_Stop(iface);
549 IMMDevice_Release(This->parent);
550 IUnknown_Release(This->pUnkFTMarshal);
551 if(This->session){
552 EnterCriticalSection(&g_sessions_lock);
553 list_remove(&This->entry);
554 LeaveCriticalSection(&g_sessions_lock);
556 HeapFree(GetProcessHeap(), 0, This->vols);
557 if (This->stream)
558 alsa_stream_release(This->stream, This->timer_thread);
559 HeapFree(GetProcessHeap(), 0, This);
561 return ref;
564 static void dump_fmt(const WAVEFORMATEX *fmt)
566 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
567 switch(fmt->wFormatTag){
568 case WAVE_FORMAT_PCM:
569 TRACE("WAVE_FORMAT_PCM");
570 break;
571 case WAVE_FORMAT_IEEE_FLOAT:
572 TRACE("WAVE_FORMAT_IEEE_FLOAT");
573 break;
574 case WAVE_FORMAT_EXTENSIBLE:
575 TRACE("WAVE_FORMAT_EXTENSIBLE");
576 break;
577 default:
578 TRACE("Unknown");
579 break;
581 TRACE(")\n");
583 TRACE("nChannels: %u\n", fmt->nChannels);
584 TRACE("nSamplesPerSec: %lu\n", fmt->nSamplesPerSec);
585 TRACE("nAvgBytesPerSec: %lu\n", fmt->nAvgBytesPerSec);
586 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
587 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
588 TRACE("cbSize: %u\n", fmt->cbSize);
590 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
591 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
592 TRACE("dwChannelMask: %08lx\n", fmtex->dwChannelMask);
593 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
594 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
598 static void session_init_vols(AudioSession *session, UINT channels)
600 if(session->channel_count < channels){
601 UINT i;
603 if(session->channel_vols)
604 session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
605 session->channel_vols, sizeof(float) * channels);
606 else
607 session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
608 sizeof(float) * channels);
609 if(!session->channel_vols)
610 return;
612 for(i = session->channel_count; i < channels; ++i)
613 session->channel_vols[i] = 1.f;
615 session->channel_count = channels;
619 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
620 UINT num_channels)
622 AudioSession *ret;
624 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
625 if(!ret)
626 return NULL;
628 memcpy(&ret->guid, guid, sizeof(GUID));
630 ret->device = device;
632 list_init(&ret->clients);
634 list_add_head(&g_sessions, &ret->entry);
636 session_init_vols(ret, num_channels);
638 ret->master_vol = 1.f;
640 return ret;
643 /* if channels == 0, then this will return or create a session with
644 * matching dataflow and GUID. otherwise, channels must also match */
645 static HRESULT get_audio_session(const GUID *sessionguid,
646 IMMDevice *device, UINT channels, AudioSession **out)
648 AudioSession *session;
650 if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
651 *out = create_session(&GUID_NULL, device, channels);
652 if(!*out)
653 return E_OUTOFMEMORY;
655 return S_OK;
658 *out = NULL;
659 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
660 if(session->device == device &&
661 IsEqualGUID(sessionguid, &session->guid)){
662 session_init_vols(session, channels);
663 *out = session;
664 break;
668 if(!*out){
669 *out = create_session(sessionguid, device, channels);
670 if(!*out)
671 return E_OUTOFMEMORY;
674 return S_OK;
677 static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
678 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
679 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
680 const GUID *sessionguid)
682 ACImpl *This = impl_from_IAudioClient3(iface);
683 struct create_stream_params params;
684 stream_handle stream;
685 unsigned int i;
687 TRACE("(%p)->(%x, %lx, %s, %s, %p, %s)\n", This, mode, flags,
688 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
690 if(!fmt)
691 return E_POINTER;
693 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
694 return E_INVALIDARG;
696 if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
697 AUDCLNT_STREAMFLAGS_LOOPBACK |
698 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
699 AUDCLNT_STREAMFLAGS_NOPERSIST |
700 AUDCLNT_STREAMFLAGS_RATEADJUST |
701 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
702 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
703 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED |
704 AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY |
705 AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM)){
706 FIXME("Unknown flags: %08lx\n", flags);
707 return E_INVALIDARG;
710 if(mode == AUDCLNT_SHAREMODE_SHARED){
711 period = DefaultPeriod;
712 if( duration < 3 * period)
713 duration = 3 * period;
714 }else{
715 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
716 if(((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask == 0 ||
717 ((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask & SPEAKER_RESERVED)
718 return AUDCLNT_E_UNSUPPORTED_FORMAT;
721 if(!period)
722 period = DefaultPeriod; /* not minimum */
723 if(period < MinimumPeriod || period > 5000000)
724 return AUDCLNT_E_INVALID_DEVICE_PERIOD;
725 if(duration > 20000000) /* the smaller the period, the lower this limit */
726 return AUDCLNT_E_BUFFER_SIZE_ERROR;
727 if(flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK){
728 if(duration != period)
729 return AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL;
730 FIXME("EXCLUSIVE mode with EVENTCALLBACK\n");
731 return AUDCLNT_E_DEVICE_IN_USE;
732 }else{
733 if( duration < 8 * period)
734 duration = 8 * period; /* may grow above 2s */
738 EnterCriticalSection(&g_sessions_lock);
740 if(This->stream){
741 LeaveCriticalSection(&g_sessions_lock);
742 return AUDCLNT_E_ALREADY_INITIALIZED;
745 dump_fmt(fmt);
747 params.name = NULL;
748 params.device = This->alsa_name;
749 params.flow = This->dataflow;
750 params.share = mode;
751 params.flags = flags;
752 params.duration = duration;
753 params.period = period;
754 params.fmt = fmt;
755 params.channel_count = NULL;
756 params.stream = &stream;
758 ALSA_CALL(create_stream, &params);
759 if(FAILED(params.result)){
760 LeaveCriticalSection(&g_sessions_lock);
761 return params.result;
764 This->channel_count = fmt->nChannels;
765 This->vols = HeapAlloc(GetProcessHeap(), 0, This->channel_count * sizeof(float));
766 if(!This->vols){
767 params.result = E_OUTOFMEMORY;
768 goto exit;
770 for(i = 0; i < This->channel_count; ++i)
771 This->vols[i] = 1.f;
773 params.result = get_audio_session(sessionguid, This->parent, This->channel_count,
774 &This->session);
775 if(FAILED(params.result))
776 goto exit;
778 list_add_tail(&This->session->clients, &This->entry);
780 exit:
781 if(FAILED(params.result)){
782 alsa_stream_release(stream, NULL);
783 HeapFree(GetProcessHeap(), 0, This->vols);
784 This->vols = NULL;
785 }else{
786 This->stream = stream;
787 set_stream_volumes(This);
790 LeaveCriticalSection(&g_sessions_lock);
792 return params.result;
795 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient3 *iface,
796 UINT32 *out)
798 ACImpl *This = impl_from_IAudioClient3(iface);
799 struct get_buffer_size_params params;
801 TRACE("(%p)->(%p)\n", This, out);
803 if(!out)
804 return E_POINTER;
806 if(!This->stream)
807 return AUDCLNT_E_NOT_INITIALIZED;
809 params.stream = This->stream;
810 params.frames = out;
812 ALSA_CALL(get_buffer_size, &params);
814 return params.result;
817 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient3 *iface,
818 REFERENCE_TIME *latency)
820 ACImpl *This = impl_from_IAudioClient3(iface);
821 struct get_latency_params params;
823 TRACE("(%p)->(%p)\n", This, latency);
825 if(!latency)
826 return E_POINTER;
828 if(!This->stream)
829 return AUDCLNT_E_NOT_INITIALIZED;
831 params.stream = This->stream;
832 params.latency = latency;
834 ALSA_CALL(get_latency, &params);
836 return params.result;
839 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient3 *iface,
840 UINT32 *out)
842 ACImpl *This = impl_from_IAudioClient3(iface);
843 struct get_current_padding_params params;
845 TRACE("(%p)->(%p)\n", This, out);
847 if(!out)
848 return E_POINTER;
850 if(!This->stream)
851 return AUDCLNT_E_NOT_INITIALIZED;
853 params.stream = This->stream;
854 params.padding = out;
856 ALSA_CALL(get_current_padding, &params);
858 TRACE("pad: %u\n", *out);
860 return params.result;
863 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient3 *iface,
864 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *fmt,
865 WAVEFORMATEX **out)
867 ACImpl *This = impl_from_IAudioClient3(iface);
868 struct is_format_supported_params params;
870 TRACE("(%p)->(%x, %p, %p)\n", This, mode, fmt, out);
871 if(fmt) dump_fmt(fmt);
873 params.device = This->alsa_name;
874 params.flow = This->dataflow;
875 params.share = mode;
876 params.fmt_in = fmt;
877 params.fmt_out = NULL;
879 if(out){
880 *out = NULL;
881 if(mode == AUDCLNT_SHAREMODE_SHARED)
882 params.fmt_out = CoTaskMemAlloc(sizeof(*params.fmt_out));
884 ALSA_CALL(is_format_supported, &params);
886 if(params.result == S_FALSE)
887 *out = &params.fmt_out->Format;
888 else
889 CoTaskMemFree(params.fmt_out);
891 return params.result;
894 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface,
895 WAVEFORMATEX **pwfx)
897 ACImpl *This = impl_from_IAudioClient3(iface);
898 struct get_mix_format_params params;
900 TRACE("(%p)->(%p)\n", This, pwfx);
902 if(!pwfx)
903 return E_POINTER;
904 *pwfx = NULL;
906 params.device = This->alsa_name;
907 params.flow = This->dataflow;
908 params.fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
909 if(!params.fmt)
910 return E_OUTOFMEMORY;
912 ALSA_CALL(get_mix_format, &params);
914 if(SUCCEEDED(params.result)){
915 *pwfx = &params.fmt->Format;
916 dump_fmt(*pwfx);
917 } else
918 CoTaskMemFree(params.fmt);
920 return params.result;
923 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient3 *iface,
924 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
926 ACImpl *This = impl_from_IAudioClient3(iface);
928 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
930 if(!defperiod && !minperiod)
931 return E_POINTER;
933 if(defperiod)
934 *defperiod = DefaultPeriod;
935 if(minperiod)
936 *minperiod = DefaultPeriod;
938 return S_OK;
941 static HRESULT WINAPI AudioClient_Start(IAudioClient3 *iface)
943 ACImpl *This = impl_from_IAudioClient3(iface);
944 struct start_params params;
946 TRACE("(%p)\n", This);
948 EnterCriticalSection(&g_sessions_lock);
950 if(!This->stream){
951 LeaveCriticalSection(&g_sessions_lock);
952 return AUDCLNT_E_NOT_INITIALIZED;
955 params.stream = This->stream;
957 ALSA_CALL(start, &params);
959 if(SUCCEEDED(params.result) && !This->timer_thread){
960 This->timer_thread = CreateThread(NULL, 0, alsa_timer_thread, This, 0, NULL);
961 SetThreadPriority(This->timer_thread, THREAD_PRIORITY_TIME_CRITICAL);
964 LeaveCriticalSection(&g_sessions_lock);
966 return params.result;
969 static HRESULT WINAPI AudioClient_Stop(IAudioClient3 *iface)
971 ACImpl *This = impl_from_IAudioClient3(iface);
972 struct stop_params params;
974 TRACE("(%p)\n", This);
976 if(!This->stream)
977 return AUDCLNT_E_NOT_INITIALIZED;
979 params.stream = This->stream;
981 ALSA_CALL(stop, &params);
983 return params.result;
986 static HRESULT WINAPI AudioClient_Reset(IAudioClient3 *iface)
988 ACImpl *This = impl_from_IAudioClient3(iface);
989 struct reset_params params;
991 TRACE("(%p)\n", This);
993 if(!This->stream)
994 return AUDCLNT_E_NOT_INITIALIZED;
996 params.stream = This->stream;
998 ALSA_CALL(reset, &params);
1000 return params.result;
1003 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient3 *iface,
1004 HANDLE event)
1006 ACImpl *This = impl_from_IAudioClient3(iface);
1007 struct set_event_handle_params params;
1009 TRACE("(%p)->(%p)\n", This, event);
1011 if(!event)
1012 return E_INVALIDARG;
1014 if(!This->stream)
1015 return AUDCLNT_E_NOT_INITIALIZED;
1017 params.stream = This->stream;
1018 params.event = event;
1020 ALSA_CALL(set_event_handle, &params);
1022 return params.result;
1025 static HRESULT WINAPI AudioClient_GetService(IAudioClient3 *iface, REFIID riid,
1026 void **ppv)
1028 ACImpl *This = impl_from_IAudioClient3(iface);
1030 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1032 if(!ppv)
1033 return E_POINTER;
1034 *ppv = NULL;
1036 EnterCriticalSection(&g_sessions_lock);
1038 if(!This->stream){
1039 LeaveCriticalSection(&g_sessions_lock);
1040 return AUDCLNT_E_NOT_INITIALIZED;
1043 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1044 if(This->dataflow != eRender){
1045 LeaveCriticalSection(&g_sessions_lock);
1046 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1048 IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
1049 *ppv = &This->IAudioRenderClient_iface;
1050 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1051 if(This->dataflow != eCapture){
1052 LeaveCriticalSection(&g_sessions_lock);
1053 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1055 IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
1056 *ppv = &This->IAudioCaptureClient_iface;
1057 }else if(IsEqualIID(riid, &IID_IAudioClock)){
1058 IAudioClock_AddRef(&This->IAudioClock_iface);
1059 *ppv = &This->IAudioClock_iface;
1060 }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1061 IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
1062 *ppv = &This->IAudioStreamVolume_iface;
1063 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1064 if(!This->session_wrapper){
1065 This->session_wrapper = AudioSessionWrapper_Create(This);
1066 if(!This->session_wrapper){
1067 LeaveCriticalSection(&g_sessions_lock);
1068 return E_OUTOFMEMORY;
1070 }else
1071 IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
1073 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1074 }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1075 if(!This->session_wrapper){
1076 This->session_wrapper = AudioSessionWrapper_Create(This);
1077 if(!This->session_wrapper){
1078 LeaveCriticalSection(&g_sessions_lock);
1079 return E_OUTOFMEMORY;
1081 }else
1082 IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
1084 *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1085 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1086 if(!This->session_wrapper){
1087 This->session_wrapper = AudioSessionWrapper_Create(This);
1088 if(!This->session_wrapper){
1089 LeaveCriticalSection(&g_sessions_lock);
1090 return E_OUTOFMEMORY;
1092 }else
1093 ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
1095 *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1098 if(*ppv){
1099 LeaveCriticalSection(&g_sessions_lock);
1100 return S_OK;
1103 LeaveCriticalSection(&g_sessions_lock);
1105 FIXME("stub %s\n", debugstr_guid(riid));
1106 return E_NOINTERFACE;
1109 static HRESULT WINAPI AudioClient_IsOffloadCapable(IAudioClient3 *iface,
1110 AUDIO_STREAM_CATEGORY category, BOOL *offload_capable)
1112 ACImpl *This = impl_from_IAudioClient3(iface);
1114 TRACE("(%p)->(0x%x, %p)\n", This, category, offload_capable);
1116 if(!offload_capable)
1117 return E_INVALIDARG;
1119 *offload_capable = FALSE;
1121 return S_OK;
1124 static HRESULT WINAPI AudioClient_SetClientProperties(IAudioClient3 *iface,
1125 const AudioClientProperties *prop)
1127 ACImpl *This = impl_from_IAudioClient3(iface);
1128 const Win8AudioClientProperties *legacy_prop = (const Win8AudioClientProperties *)prop;
1130 TRACE("(%p)->(%p)\n", This, prop);
1132 if(!legacy_prop)
1133 return E_POINTER;
1135 if(legacy_prop->cbSize == sizeof(AudioClientProperties)){
1136 TRACE("{ bIsOffload: %u, eCategory: 0x%x, Options: 0x%x }\n",
1137 legacy_prop->bIsOffload,
1138 legacy_prop->eCategory,
1139 prop->Options);
1140 }else if(legacy_prop->cbSize == sizeof(Win8AudioClientProperties)){
1141 TRACE("{ bIsOffload: %u, eCategory: 0x%x }\n",
1142 legacy_prop->bIsOffload,
1143 legacy_prop->eCategory);
1144 }else{
1145 WARN("Unsupported Size = %d\n", legacy_prop->cbSize);
1146 return E_INVALIDARG;
1150 if(legacy_prop->bIsOffload)
1151 return AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE;
1153 return S_OK;
1156 static HRESULT WINAPI AudioClient_GetBufferSizeLimits(IAudioClient3 *iface,
1157 const WAVEFORMATEX *format, BOOL event_driven, REFERENCE_TIME *min_duration,
1158 REFERENCE_TIME *max_duration)
1160 ACImpl *This = impl_from_IAudioClient3(iface);
1162 FIXME("(%p)->(%p, %u, %p, %p)\n", This, format, event_driven, min_duration, max_duration);
1164 return E_NOTIMPL;
1167 static HRESULT WINAPI AudioClient_GetSharedModeEnginePeriod(IAudioClient3 *iface,
1168 const WAVEFORMATEX *format, UINT32 *default_period_frames, UINT32 *unit_period_frames,
1169 UINT32 *min_period_frames, UINT32 *max_period_frames)
1171 ACImpl *This = impl_from_IAudioClient3(iface);
1173 FIXME("(%p)->(%p, %p, %p, %p, %p)\n", This, format, default_period_frames, unit_period_frames,
1174 min_period_frames, max_period_frames);
1176 return E_NOTIMPL;
1179 static HRESULT WINAPI AudioClient_GetCurrentSharedModeEnginePeriod(IAudioClient3 *iface,
1180 WAVEFORMATEX **cur_format, UINT32 *cur_period_frames)
1182 ACImpl *This = impl_from_IAudioClient3(iface);
1184 FIXME("(%p)->(%p, %p)\n", This, cur_format, cur_period_frames);
1186 return E_NOTIMPL;
1189 static HRESULT WINAPI AudioClient_InitializeSharedAudioStream(IAudioClient3 *iface,
1190 DWORD flags, UINT32 period_frames, const WAVEFORMATEX *format,
1191 const GUID *session_guid)
1193 ACImpl *This = impl_from_IAudioClient3(iface);
1195 FIXME("(%p)->(0x%lx, %u, %p, %s)\n", This, flags, period_frames, format, debugstr_guid(session_guid));
1197 return E_NOTIMPL;
1200 static const IAudioClient3Vtbl AudioClient3_Vtbl =
1202 AudioClient_QueryInterface,
1203 AudioClient_AddRef,
1204 AudioClient_Release,
1205 AudioClient_Initialize,
1206 AudioClient_GetBufferSize,
1207 AudioClient_GetStreamLatency,
1208 AudioClient_GetCurrentPadding,
1209 AudioClient_IsFormatSupported,
1210 AudioClient_GetMixFormat,
1211 AudioClient_GetDevicePeriod,
1212 AudioClient_Start,
1213 AudioClient_Stop,
1214 AudioClient_Reset,
1215 AudioClient_SetEventHandle,
1216 AudioClient_GetService,
1217 AudioClient_IsOffloadCapable,
1218 AudioClient_SetClientProperties,
1219 AudioClient_GetBufferSizeLimits,
1220 AudioClient_GetSharedModeEnginePeriod,
1221 AudioClient_GetCurrentSharedModeEnginePeriod,
1222 AudioClient_InitializeSharedAudioStream,
1225 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1226 IAudioRenderClient *iface, REFIID riid, void **ppv)
1228 ACImpl *This = impl_from_IAudioRenderClient(iface);
1229 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1231 if(!ppv)
1232 return E_POINTER;
1233 *ppv = NULL;
1235 if(IsEqualIID(riid, &IID_IUnknown) ||
1236 IsEqualIID(riid, &IID_IAudioRenderClient))
1237 *ppv = iface;
1238 else if(IsEqualIID(riid, &IID_IMarshal))
1239 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
1241 if(*ppv){
1242 IUnknown_AddRef((IUnknown*)*ppv);
1243 return S_OK;
1246 WARN("Unknown interface %s\n", debugstr_guid(riid));
1247 return E_NOINTERFACE;
1250 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1252 ACImpl *This = impl_from_IAudioRenderClient(iface);
1253 return AudioClient_AddRef(&This->IAudioClient3_iface);
1256 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1258 ACImpl *This = impl_from_IAudioRenderClient(iface);
1259 return AudioClient_Release(&This->IAudioClient3_iface);
1262 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1263 UINT32 frames, BYTE **data)
1265 ACImpl *This = impl_from_IAudioRenderClient(iface);
1266 struct get_render_buffer_params params;
1268 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1270 if(!data)
1271 return E_POINTER;
1272 *data = NULL;
1274 params.stream = This->stream;
1275 params.frames = frames;
1276 params.data = data;
1278 ALSA_CALL(get_render_buffer, &params);
1280 return params.result;
1283 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1284 IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
1286 ACImpl *This = impl_from_IAudioRenderClient(iface);
1287 struct release_render_buffer_params params;
1289 TRACE("(%p)->(%u, %lx)\n", This, written_frames, flags);
1291 params.stream = This->stream;
1292 params.written_frames = written_frames;
1293 params.flags = flags;
1295 ALSA_CALL(release_render_buffer, &params);
1297 return params.result;
1300 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1301 AudioRenderClient_QueryInterface,
1302 AudioRenderClient_AddRef,
1303 AudioRenderClient_Release,
1304 AudioRenderClient_GetBuffer,
1305 AudioRenderClient_ReleaseBuffer
1308 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1309 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1311 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1312 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1314 if(!ppv)
1315 return E_POINTER;
1316 *ppv = NULL;
1318 if(IsEqualIID(riid, &IID_IUnknown) ||
1319 IsEqualIID(riid, &IID_IAudioCaptureClient))
1320 *ppv = iface;
1321 else if(IsEqualIID(riid, &IID_IMarshal))
1322 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
1324 if(*ppv){
1325 IUnknown_AddRef((IUnknown*)*ppv);
1326 return S_OK;
1329 WARN("Unknown interface %s\n", debugstr_guid(riid));
1330 return E_NOINTERFACE;
1333 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1335 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1336 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1339 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1341 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1342 return IAudioClient3_Release(&This->IAudioClient3_iface);
1345 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1346 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1347 UINT64 *qpcpos)
1349 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1350 struct get_capture_buffer_params params;
1352 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1353 devpos, qpcpos);
1355 if(!data)
1356 return E_POINTER;
1358 *data = NULL;
1360 if(!frames || !flags)
1361 return E_POINTER;
1363 params.stream = This->stream;
1364 params.data = data;
1365 params.frames = frames;
1366 params.flags = (UINT*)flags;
1367 params.devpos = devpos;
1368 params.qpcpos = qpcpos;
1370 ALSA_CALL(get_capture_buffer, &params);
1372 return params.result;
1375 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1376 IAudioCaptureClient *iface, UINT32 done)
1378 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1379 struct release_capture_buffer_params params;
1381 TRACE("(%p)->(%u)\n", This, done);
1383 params.stream = This->stream;
1384 params.done = done;
1386 ALSA_CALL(release_capture_buffer, &params);
1388 return params.result;
1391 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1392 IAudioCaptureClient *iface, UINT32 *frames)
1394 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1395 struct get_next_packet_size_params params;
1397 TRACE("(%p)->(%p)\n", This, frames);
1399 if(!frames)
1400 return E_POINTER;
1402 params.stream = This->stream;
1403 params.frames = frames;
1405 ALSA_CALL(get_next_packet_size, &params);
1407 return params.result;
1410 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1412 AudioCaptureClient_QueryInterface,
1413 AudioCaptureClient_AddRef,
1414 AudioCaptureClient_Release,
1415 AudioCaptureClient_GetBuffer,
1416 AudioCaptureClient_ReleaseBuffer,
1417 AudioCaptureClient_GetNextPacketSize
1420 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1421 REFIID riid, void **ppv)
1423 ACImpl *This = impl_from_IAudioClock(iface);
1425 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1427 if(!ppv)
1428 return E_POINTER;
1429 *ppv = NULL;
1431 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
1432 *ppv = iface;
1433 else if(IsEqualIID(riid, &IID_IAudioClock2))
1434 *ppv = &This->IAudioClock2_iface;
1435 if(*ppv){
1436 IUnknown_AddRef((IUnknown*)*ppv);
1437 return S_OK;
1440 WARN("Unknown interface %s\n", debugstr_guid(riid));
1441 return E_NOINTERFACE;
1444 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
1446 ACImpl *This = impl_from_IAudioClock(iface);
1447 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1450 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
1452 ACImpl *This = impl_from_IAudioClock(iface);
1453 return IAudioClient3_Release(&This->IAudioClient3_iface);
1456 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
1458 ACImpl *This = impl_from_IAudioClock(iface);
1459 struct get_frequency_params params;
1461 TRACE("(%p)->(%p)\n", This, freq);
1463 params.stream = This->stream;
1464 params.freq = freq;
1466 ALSA_CALL(get_frequency, &params);
1468 return params.result;
1471 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
1472 UINT64 *qpctime)
1474 ACImpl *This = impl_from_IAudioClock(iface);
1475 struct get_position_params params;
1477 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
1479 if(!pos)
1480 return E_POINTER;
1482 params.stream = This->stream;
1483 params.device = FALSE;
1484 params.pos = pos;
1485 params.qpctime = qpctime;
1487 ALSA_CALL(get_position, &params);
1489 return params.result;
1492 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
1493 DWORD *chars)
1495 ACImpl *This = impl_from_IAudioClock(iface);
1497 TRACE("(%p)->(%p)\n", This, chars);
1499 if(!chars)
1500 return E_POINTER;
1502 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
1504 return S_OK;
1507 static const IAudioClockVtbl AudioClock_Vtbl =
1509 AudioClock_QueryInterface,
1510 AudioClock_AddRef,
1511 AudioClock_Release,
1512 AudioClock_GetFrequency,
1513 AudioClock_GetPosition,
1514 AudioClock_GetCharacteristics
1517 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
1518 REFIID riid, void **ppv)
1520 ACImpl *This = impl_from_IAudioClock2(iface);
1521 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
1524 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
1526 ACImpl *This = impl_from_IAudioClock2(iface);
1527 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1530 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
1532 ACImpl *This = impl_from_IAudioClock2(iface);
1533 return IAudioClient3_Release(&This->IAudioClient3_iface);
1536 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
1537 UINT64 *pos, UINT64 *qpctime)
1539 ACImpl *This = impl_from_IAudioClock2(iface);
1541 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
1543 return E_NOTIMPL;
1546 static const IAudioClock2Vtbl AudioClock2_Vtbl =
1548 AudioClock2_QueryInterface,
1549 AudioClock2_AddRef,
1550 AudioClock2_Release,
1551 AudioClock2_GetDevicePosition
1554 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
1556 AudioSessionWrapper *ret;
1558 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1559 sizeof(AudioSessionWrapper));
1560 if(!ret)
1561 return NULL;
1563 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
1564 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
1565 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
1567 ret->ref = 1;
1569 ret->client = client;
1570 if(client){
1571 ret->session = client->session;
1572 AudioClient_AddRef(&client->IAudioClient3_iface);
1575 return ret;
1578 static HRESULT WINAPI AudioSessionControl_QueryInterface(
1579 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
1581 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1583 if(!ppv)
1584 return E_POINTER;
1585 *ppv = NULL;
1587 if(IsEqualIID(riid, &IID_IUnknown) ||
1588 IsEqualIID(riid, &IID_IAudioSessionControl) ||
1589 IsEqualIID(riid, &IID_IAudioSessionControl2))
1590 *ppv = iface;
1591 if(*ppv){
1592 IUnknown_AddRef((IUnknown*)*ppv);
1593 return S_OK;
1596 WARN("Unknown interface %s\n", debugstr_guid(riid));
1597 return E_NOINTERFACE;
1600 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
1602 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1603 ULONG ref;
1604 ref = InterlockedIncrement(&This->ref);
1605 TRACE("(%p) Refcount now %lu\n", This, ref);
1606 return ref;
1609 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
1611 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1612 ULONG ref;
1613 ref = InterlockedDecrement(&This->ref);
1614 TRACE("(%p) Refcount now %lu\n", This, ref);
1615 if(!ref){
1616 if(This->client){
1617 EnterCriticalSection(&g_sessions_lock);
1618 This->client->session_wrapper = NULL;
1619 LeaveCriticalSection(&g_sessions_lock);
1620 AudioClient_Release(&This->client->IAudioClient3_iface);
1622 HeapFree(GetProcessHeap(), 0, This);
1624 return ref;
1627 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
1628 AudioSessionState *state)
1630 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1631 struct is_started_params params;
1632 ACImpl *client;
1634 TRACE("(%p)->(%p)\n", This, state);
1636 if(!state)
1637 return NULL_PTR_ERR;
1639 EnterCriticalSection(&g_sessions_lock);
1641 if(list_empty(&This->session->clients)){
1642 *state = AudioSessionStateExpired;
1643 LeaveCriticalSection(&g_sessions_lock);
1644 return S_OK;
1647 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
1648 params.stream = client->stream;
1649 ALSA_CALL(is_started, &params);
1650 if(params.result == S_OK){
1651 *state = AudioSessionStateActive;
1652 LeaveCriticalSection(&g_sessions_lock);
1653 return S_OK;
1657 LeaveCriticalSection(&g_sessions_lock);
1659 *state = AudioSessionStateInactive;
1661 return S_OK;
1664 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
1665 IAudioSessionControl2 *iface, WCHAR **name)
1667 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1669 FIXME("(%p)->(%p) - stub\n", This, name);
1671 return E_NOTIMPL;
1674 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
1675 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
1677 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1679 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
1681 return E_NOTIMPL;
1684 static HRESULT WINAPI AudioSessionControl_GetIconPath(
1685 IAudioSessionControl2 *iface, WCHAR **path)
1687 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1689 FIXME("(%p)->(%p) - stub\n", This, path);
1691 return E_NOTIMPL;
1694 static HRESULT WINAPI AudioSessionControl_SetIconPath(
1695 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
1697 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1699 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
1701 return E_NOTIMPL;
1704 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
1705 IAudioSessionControl2 *iface, GUID *group)
1707 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1709 FIXME("(%p)->(%p) - stub\n", This, group);
1711 return E_NOTIMPL;
1714 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
1715 IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
1717 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1719 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
1720 debugstr_guid(session));
1722 return E_NOTIMPL;
1725 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
1726 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
1728 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1730 FIXME("(%p)->(%p) - stub\n", This, events);
1732 return S_OK;
1735 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
1736 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
1738 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1740 FIXME("(%p)->(%p) - stub\n", This, events);
1742 return S_OK;
1745 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
1746 IAudioSessionControl2 *iface, WCHAR **id)
1748 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1750 FIXME("(%p)->(%p) - stub\n", This, id);
1752 return E_NOTIMPL;
1755 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
1756 IAudioSessionControl2 *iface, WCHAR **id)
1758 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1760 FIXME("(%p)->(%p) - stub\n", This, id);
1762 return E_NOTIMPL;
1765 static HRESULT WINAPI AudioSessionControl_GetProcessId(
1766 IAudioSessionControl2 *iface, DWORD *pid)
1768 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1770 TRACE("(%p)->(%p)\n", This, pid);
1772 if(!pid)
1773 return E_POINTER;
1775 *pid = GetCurrentProcessId();
1777 return S_OK;
1780 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
1781 IAudioSessionControl2 *iface)
1783 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1785 TRACE("(%p)\n", This);
1787 return S_FALSE;
1790 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
1791 IAudioSessionControl2 *iface, BOOL optout)
1793 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1795 TRACE("(%p)->(%d)\n", This, optout);
1797 return S_OK;
1800 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
1802 AudioSessionControl_QueryInterface,
1803 AudioSessionControl_AddRef,
1804 AudioSessionControl_Release,
1805 AudioSessionControl_GetState,
1806 AudioSessionControl_GetDisplayName,
1807 AudioSessionControl_SetDisplayName,
1808 AudioSessionControl_GetIconPath,
1809 AudioSessionControl_SetIconPath,
1810 AudioSessionControl_GetGroupingParam,
1811 AudioSessionControl_SetGroupingParam,
1812 AudioSessionControl_RegisterAudioSessionNotification,
1813 AudioSessionControl_UnregisterAudioSessionNotification,
1814 AudioSessionControl_GetSessionIdentifier,
1815 AudioSessionControl_GetSessionInstanceIdentifier,
1816 AudioSessionControl_GetProcessId,
1817 AudioSessionControl_IsSystemSoundsSession,
1818 AudioSessionControl_SetDuckingPreference
1821 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
1822 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
1824 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1826 if(!ppv)
1827 return E_POINTER;
1828 *ppv = NULL;
1830 if(IsEqualIID(riid, &IID_IUnknown) ||
1831 IsEqualIID(riid, &IID_ISimpleAudioVolume))
1832 *ppv = iface;
1833 if(*ppv){
1834 IUnknown_AddRef((IUnknown*)*ppv);
1835 return S_OK;
1838 WARN("Unknown interface %s\n", debugstr_guid(riid));
1839 return E_NOINTERFACE;
1842 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
1844 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1845 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
1848 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
1850 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1851 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
1854 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
1855 ISimpleAudioVolume *iface, float level, const GUID *context)
1857 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1858 AudioSession *session = This->session;
1859 ACImpl *client;
1861 TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
1863 if(level < 0.f || level > 1.f)
1864 return E_INVALIDARG;
1866 if(context)
1867 FIXME("Notifications not supported yet\n");
1869 TRACE("ALSA does not support volume control\n");
1871 EnterCriticalSection(&g_sessions_lock);
1873 session->master_vol = level;
1875 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
1876 set_stream_volumes(client);
1878 LeaveCriticalSection(&g_sessions_lock);
1880 return S_OK;
1883 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
1884 ISimpleAudioVolume *iface, float *level)
1886 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1887 AudioSession *session = This->session;
1889 TRACE("(%p)->(%p)\n", session, level);
1891 if(!level)
1892 return NULL_PTR_ERR;
1894 *level = session->master_vol;
1896 return S_OK;
1899 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
1900 BOOL mute, const GUID *context)
1902 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1903 AudioSession *session = This->session;
1904 ACImpl *client;
1906 TRACE("(%p)->(%u, %s)\n", session, mute, debugstr_guid(context));
1908 if(context)
1909 FIXME("Notifications not supported yet\n");
1911 EnterCriticalSection(&g_sessions_lock);
1913 session->mute = mute;
1914 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
1915 set_stream_volumes(client);
1917 LeaveCriticalSection(&g_sessions_lock);
1919 return S_OK;
1922 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
1923 BOOL *mute)
1925 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1926 AudioSession *session = This->session;
1928 TRACE("(%p)->(%p)\n", session, mute);
1930 if(!mute)
1931 return NULL_PTR_ERR;
1933 *mute = session->mute;
1935 return S_OK;
1938 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
1940 SimpleAudioVolume_QueryInterface,
1941 SimpleAudioVolume_AddRef,
1942 SimpleAudioVolume_Release,
1943 SimpleAudioVolume_SetMasterVolume,
1944 SimpleAudioVolume_GetMasterVolume,
1945 SimpleAudioVolume_SetMute,
1946 SimpleAudioVolume_GetMute
1949 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
1950 IAudioStreamVolume *iface, REFIID riid, void **ppv)
1952 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1954 if(!ppv)
1955 return E_POINTER;
1956 *ppv = NULL;
1958 if(IsEqualIID(riid, &IID_IUnknown) ||
1959 IsEqualIID(riid, &IID_IAudioStreamVolume))
1960 *ppv = iface;
1961 if(*ppv){
1962 IUnknown_AddRef((IUnknown*)*ppv);
1963 return S_OK;
1966 WARN("Unknown interface %s\n", debugstr_guid(riid));
1967 return E_NOINTERFACE;
1970 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
1972 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1973 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1976 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
1978 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1979 return IAudioClient3_Release(&This->IAudioClient3_iface);
1982 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
1983 IAudioStreamVolume *iface, UINT32 *out)
1985 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1987 TRACE("(%p)->(%p)\n", This, out);
1989 if(!out)
1990 return E_POINTER;
1992 *out = This->channel_count;
1994 return S_OK;
1997 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
1998 IAudioStreamVolume *iface, UINT32 index, float level)
2000 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2002 TRACE("(%p)->(%d, %f)\n", This, index, level);
2004 if(level < 0.f || level > 1.f)
2005 return E_INVALIDARG;
2007 if(index >= This->channel_count)
2008 return E_INVALIDARG;
2010 TRACE("ALSA does not support volume control\n");
2012 EnterCriticalSection(&g_sessions_lock);
2014 This->vols[index] = level;
2015 set_stream_volumes(This);
2017 LeaveCriticalSection(&g_sessions_lock);
2019 return S_OK;
2022 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2023 IAudioStreamVolume *iface, UINT32 index, float *level)
2025 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2027 TRACE("(%p)->(%d, %p)\n", This, index, level);
2029 if(!level)
2030 return E_POINTER;
2032 if(index >= This->channel_count)
2033 return E_INVALIDARG;
2035 *level = This->vols[index];
2037 return S_OK;
2040 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2041 IAudioStreamVolume *iface, UINT32 count, const float *levels)
2043 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2044 unsigned int i;
2046 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2048 if(!levels)
2049 return E_POINTER;
2051 if(count != This->channel_count)
2052 return E_INVALIDARG;
2054 TRACE("ALSA does not support volume control\n");
2056 EnterCriticalSection(&g_sessions_lock);
2058 for(i = 0; i < count; ++i)
2059 This->vols[i] = levels[i];
2060 set_stream_volumes(This);
2062 LeaveCriticalSection(&g_sessions_lock);
2064 return S_OK;
2067 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2068 IAudioStreamVolume *iface, UINT32 count, float *levels)
2070 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2071 unsigned int i;
2073 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2075 if(!levels)
2076 return E_POINTER;
2078 if(count != This->channel_count)
2079 return E_INVALIDARG;
2081 EnterCriticalSection(&g_sessions_lock);
2083 for(i = 0; i < count; ++i)
2084 levels[i] = This->vols[i];
2086 LeaveCriticalSection(&g_sessions_lock);
2088 return S_OK;
2091 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2093 AudioStreamVolume_QueryInterface,
2094 AudioStreamVolume_AddRef,
2095 AudioStreamVolume_Release,
2096 AudioStreamVolume_GetChannelCount,
2097 AudioStreamVolume_SetChannelVolume,
2098 AudioStreamVolume_GetChannelVolume,
2099 AudioStreamVolume_SetAllVolumes,
2100 AudioStreamVolume_GetAllVolumes
2103 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2104 IChannelAudioVolume *iface, REFIID riid, void **ppv)
2106 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2108 if(!ppv)
2109 return E_POINTER;
2110 *ppv = NULL;
2112 if(IsEqualIID(riid, &IID_IUnknown) ||
2113 IsEqualIID(riid, &IID_IChannelAudioVolume))
2114 *ppv = iface;
2115 if(*ppv){
2116 IUnknown_AddRef((IUnknown*)*ppv);
2117 return S_OK;
2120 WARN("Unknown interface %s\n", debugstr_guid(riid));
2121 return E_NOINTERFACE;
2124 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2126 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2127 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2130 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2132 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2133 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2136 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2137 IChannelAudioVolume *iface, UINT32 *out)
2139 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2140 AudioSession *session = This->session;
2142 TRACE("(%p)->(%p)\n", session, out);
2144 if(!out)
2145 return NULL_PTR_ERR;
2147 *out = session->channel_count;
2149 return S_OK;
2152 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2153 IChannelAudioVolume *iface, UINT32 index, float level,
2154 const GUID *context)
2156 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2157 AudioSession *session = This->session;
2158 ACImpl *client;
2160 TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2161 wine_dbgstr_guid(context));
2163 if(level < 0.f || level > 1.f)
2164 return E_INVALIDARG;
2166 if(index >= session->channel_count)
2167 return E_INVALIDARG;
2169 if(context)
2170 FIXME("Notifications not supported yet\n");
2172 TRACE("ALSA does not support volume control\n");
2174 EnterCriticalSection(&g_sessions_lock);
2176 session->channel_vols[index] = level;
2178 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
2179 set_stream_volumes(client);
2181 LeaveCriticalSection(&g_sessions_lock);
2183 return S_OK;
2186 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2187 IChannelAudioVolume *iface, UINT32 index, float *level)
2189 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2190 AudioSession *session = This->session;
2192 TRACE("(%p)->(%d, %p)\n", session, index, level);
2194 if(!level)
2195 return NULL_PTR_ERR;
2197 if(index >= session->channel_count)
2198 return E_INVALIDARG;
2200 *level = session->channel_vols[index];
2202 return S_OK;
2205 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2206 IChannelAudioVolume *iface, UINT32 count, const float *levels,
2207 const GUID *context)
2209 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2210 AudioSession *session = This->session;
2211 unsigned int i;
2212 ACImpl *client;
2214 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2215 wine_dbgstr_guid(context));
2217 if(!levels)
2218 return NULL_PTR_ERR;
2220 if(count != session->channel_count)
2221 return E_INVALIDARG;
2223 if(context)
2224 FIXME("Notifications not supported yet\n");
2226 TRACE("ALSA does not support volume control\n");
2228 EnterCriticalSection(&g_sessions_lock);
2230 for(i = 0; i < count; ++i)
2231 session->channel_vols[i] = levels[i];
2233 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
2234 set_stream_volumes(client);
2236 LeaveCriticalSection(&g_sessions_lock);
2238 return S_OK;
2241 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2242 IChannelAudioVolume *iface, UINT32 count, float *levels)
2244 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2245 AudioSession *session = This->session;
2246 unsigned int i;
2248 TRACE("(%p)->(%d, %p)\n", session, count, levels);
2250 if(!levels)
2251 return NULL_PTR_ERR;
2253 if(count != session->channel_count)
2254 return E_INVALIDARG;
2256 for(i = 0; i < count; ++i)
2257 levels[i] = session->channel_vols[i];
2259 return S_OK;
2262 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2264 ChannelAudioVolume_QueryInterface,
2265 ChannelAudioVolume_AddRef,
2266 ChannelAudioVolume_Release,
2267 ChannelAudioVolume_GetChannelCount,
2268 ChannelAudioVolume_SetChannelVolume,
2269 ChannelAudioVolume_GetChannelVolume,
2270 ChannelAudioVolume_SetAllVolumes,
2271 ChannelAudioVolume_GetAllVolumes
2274 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2275 REFIID riid, void **ppv)
2277 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2279 if(!ppv)
2280 return E_POINTER;
2281 *ppv = NULL;
2283 if(IsEqualIID(riid, &IID_IUnknown) ||
2284 IsEqualIID(riid, &IID_IAudioSessionManager) ||
2285 IsEqualIID(riid, &IID_IAudioSessionManager2))
2286 *ppv = iface;
2287 if(*ppv){
2288 IUnknown_AddRef((IUnknown*)*ppv);
2289 return S_OK;
2292 WARN("Unknown interface %s\n", debugstr_guid(riid));
2293 return E_NOINTERFACE;
2296 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2298 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2299 ULONG ref;
2300 ref = InterlockedIncrement(&This->ref);
2301 TRACE("(%p) Refcount now %lu\n", This, ref);
2302 return ref;
2305 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2307 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2308 ULONG ref;
2309 ref = InterlockedDecrement(&This->ref);
2310 TRACE("(%p) Refcount now %lu\n", This, ref);
2311 if(!ref)
2312 HeapFree(GetProcessHeap(), 0, This);
2313 return ref;
2316 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2317 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2318 IAudioSessionControl **out)
2320 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2321 AudioSession *session;
2322 AudioSessionWrapper *wrapper;
2323 HRESULT hr;
2325 TRACE("(%p)->(%s, %lx, %p)\n", This, debugstr_guid(session_guid),
2326 flags, out);
2328 hr = get_audio_session(session_guid, This->device, 0, &session);
2329 if(FAILED(hr))
2330 return hr;
2332 wrapper = AudioSessionWrapper_Create(NULL);
2333 if(!wrapper)
2334 return E_OUTOFMEMORY;
2336 wrapper->session = session;
2338 *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
2340 return S_OK;
2343 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
2344 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2345 ISimpleAudioVolume **out)
2347 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2348 AudioSession *session;
2349 AudioSessionWrapper *wrapper;
2350 HRESULT hr;
2352 TRACE("(%p)->(%s, %lx, %p)\n", This, debugstr_guid(session_guid),
2353 flags, out);
2355 hr = get_audio_session(session_guid, This->device, 0, &session);
2356 if(FAILED(hr))
2357 return hr;
2359 wrapper = AudioSessionWrapper_Create(NULL);
2360 if(!wrapper)
2361 return E_OUTOFMEMORY;
2363 wrapper->session = session;
2365 *out = &wrapper->ISimpleAudioVolume_iface;
2367 return S_OK;
2370 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
2371 IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
2373 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2374 FIXME("(%p)->(%p) - stub\n", This, out);
2375 return E_NOTIMPL;
2378 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
2379 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2381 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2382 FIXME("(%p)->(%p) - stub\n", This, notification);
2383 return E_NOTIMPL;
2386 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
2387 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2389 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2390 FIXME("(%p)->(%p) - stub\n", This, notification);
2391 return E_NOTIMPL;
2394 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
2395 IAudioSessionManager2 *iface, const WCHAR *session_id,
2396 IAudioVolumeDuckNotification *notification)
2398 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2399 FIXME("(%p)->(%p) - stub\n", This, notification);
2400 return E_NOTIMPL;
2403 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
2404 IAudioSessionManager2 *iface,
2405 IAudioVolumeDuckNotification *notification)
2407 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2408 FIXME("(%p)->(%p) - stub\n", This, notification);
2409 return E_NOTIMPL;
2412 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
2414 AudioSessionManager_QueryInterface,
2415 AudioSessionManager_AddRef,
2416 AudioSessionManager_Release,
2417 AudioSessionManager_GetAudioSessionControl,
2418 AudioSessionManager_GetSimpleAudioVolume,
2419 AudioSessionManager_GetSessionEnumerator,
2420 AudioSessionManager_RegisterSessionNotification,
2421 AudioSessionManager_UnregisterSessionNotification,
2422 AudioSessionManager_RegisterDuckNotification,
2423 AudioSessionManager_UnregisterDuckNotification
2426 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
2427 IAudioSessionManager2 **out)
2429 SessionMgr *This;
2431 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
2432 if(!This)
2433 return E_OUTOFMEMORY;
2435 This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
2436 This->device = device;
2437 This->ref = 1;
2439 *out = &This->IAudioSessionManager2_iface;
2441 return S_OK;
2444 HRESULT WINAPI AUDDRV_GetPropValue(GUID *guid, const PROPERTYKEY *prop, PROPVARIANT *out)
2446 struct get_prop_value_params params;
2447 char name[256];
2448 EDataFlow flow;
2449 unsigned int size = 0;
2451 TRACE("%s, (%s,%lu), %p\n", wine_dbgstr_guid(guid), wine_dbgstr_guid(&prop->fmtid), prop->pid, out);
2453 if(!get_alsa_name_by_guid(guid, name, sizeof(name), &flow))
2455 WARN("Unknown interface %s\n", debugstr_guid(guid));
2456 return E_NOINTERFACE;
2459 params.device = name;
2460 params.flow = flow;
2461 params.guid = guid;
2462 params.prop = prop;
2463 params.value = out;
2464 params.buffer = NULL;
2465 params.buffer_size = &size;
2467 while(1) {
2468 ALSA_CALL(get_prop_value, &params);
2470 if(params.result != E_NOT_SUFFICIENT_BUFFER)
2471 break;
2473 CoTaskMemFree(params.buffer);
2474 params.buffer = CoTaskMemAlloc(*params.buffer_size);
2475 if(!params.buffer)
2476 return E_OUTOFMEMORY;
2478 if(FAILED(params.result))
2479 CoTaskMemFree(params.buffer);
2481 return params.result;