mmdevapi: Integrate wineoss's additions in unixlib.h.
[wine.git] / dlls / winealsa.drv / mmdevdrv.c
blobad322ccfa96c4d8c0a13e728a8e445bf96f33403
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>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winnls.h"
28 #include "winreg.h"
29 #include "winternl.h"
30 #include "propsys.h"
31 #include "initguid.h"
32 #include "ole2.h"
33 #include "propkey.h"
34 #include "mmdeviceapi.h"
35 #include "devpkey.h"
36 #include "mmsystem.h"
37 #include "dsound.h"
39 #include "endpointvolume.h"
40 #include "audioclient.h"
41 #include "audiopolicy.h"
43 #include "wine/debug.h"
44 #include "wine/list.h"
45 #include "wine/unixlib.h"
47 #include "unixlib.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(alsa);
51 unixlib_handle_t alsa_handle = 0;
53 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
55 static const REFERENCE_TIME DefaultPeriod = 100000;
56 static const REFERENCE_TIME MinimumPeriod = 50000;
58 struct ACImpl;
59 typedef struct ACImpl ACImpl;
61 typedef struct _AudioSession {
62 GUID guid;
63 struct list clients;
65 IMMDevice *device;
67 float master_vol;
68 UINT32 channel_count;
69 float *channel_vols;
70 BOOL mute;
72 struct list entry;
73 } AudioSession;
75 typedef struct _AudioSessionWrapper {
76 IAudioSessionControl2 IAudioSessionControl2_iface;
77 IChannelAudioVolume IChannelAudioVolume_iface;
78 ISimpleAudioVolume ISimpleAudioVolume_iface;
80 LONG ref;
82 ACImpl *client;
83 AudioSession *session;
84 } AudioSessionWrapper;
86 struct ACImpl {
87 IAudioClient3 IAudioClient3_iface;
88 IAudioRenderClient IAudioRenderClient_iface;
89 IAudioCaptureClient IAudioCaptureClient_iface;
90 IAudioClock IAudioClock_iface;
91 IAudioClock2 IAudioClock2_iface;
92 IAudioStreamVolume IAudioStreamVolume_iface;
94 LONG ref;
96 IMMDevice *parent;
97 IUnknown *pUnkFTMarshal;
99 EDataFlow dataflow;
100 float *vols;
101 UINT32 channel_count;
102 stream_handle stream;
104 HANDLE timer_thread;
106 AudioSession *session;
107 AudioSessionWrapper *session_wrapper;
109 struct list entry;
111 /* Keep at end */
112 char alsa_name[1];
115 typedef struct _SessionMgr {
116 IAudioSessionManager2 IAudioSessionManager2_iface;
118 LONG ref;
120 IMMDevice *device;
121 } SessionMgr;
123 static CRITICAL_SECTION g_sessions_lock;
124 static CRITICAL_SECTION_DEBUG g_sessions_lock_debug =
126 0, 0, &g_sessions_lock,
127 { &g_sessions_lock_debug.ProcessLocksList, &g_sessions_lock_debug.ProcessLocksList },
128 0, 0, { (DWORD_PTR)(__FILE__ ": g_sessions_lock") }
130 static CRITICAL_SECTION g_sessions_lock = { &g_sessions_lock_debug, -1, 0, 0, 0, 0 };
131 static struct list g_sessions = LIST_INIT(g_sessions);
133 static const WCHAR drv_key_devicesW[] = {'S','o','f','t','w','a','r','e','\\',
134 'W','i','n','e','\\','D','r','i','v','e','r','s','\\',
135 'w','i','n','e','a','l','s','a','.','d','r','v','\\','d','e','v','i','c','e','s',0};
136 static const WCHAR guidW[] = {'g','u','i','d',0};
138 static const IAudioClient3Vtbl AudioClient3_Vtbl;
139 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
140 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
141 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
142 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
143 static const IAudioClockVtbl AudioClock_Vtbl;
144 static const IAudioClock2Vtbl AudioClock2_Vtbl;
145 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
146 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
147 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl;
149 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
151 static inline ACImpl *impl_from_IAudioClient3(IAudioClient3 *iface)
153 return CONTAINING_RECORD(iface, ACImpl, IAudioClient3_iface);
156 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
158 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
161 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
163 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
166 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
168 return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
171 static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
173 return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
176 static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
178 return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
181 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
183 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
186 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
188 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
191 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
193 return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
196 static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface)
198 return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface);
201 BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
203 switch (reason)
205 case DLL_PROCESS_ATTACH:
206 if(NtQueryVirtualMemory(GetCurrentProcess(), dll, MemoryWineUnixFuncs,
207 &alsa_handle, sizeof(alsa_handle), NULL))
208 return FALSE;
209 break;
211 case DLL_PROCESS_DETACH:
212 if (reserved) break;
213 DeleteCriticalSection(&g_sessions_lock);
214 break;
216 return TRUE;
219 int WINAPI AUDDRV_GetPriority(void)
221 return Priority_Neutral;
224 static HRESULT alsa_stream_release(stream_handle stream, HANDLE timer_thread)
226 struct release_stream_params params;
228 params.stream = stream;
229 params.timer_thread = timer_thread;
231 ALSA_CALL(release_stream, &params);
233 return params.result;
236 static DWORD WINAPI alsa_timer_thread(void *user)
238 struct timer_loop_params params;
239 struct ACImpl *This = user;
241 params.stream = This->stream;
243 ALSA_CALL(timer_loop, &params);
245 return 0;
248 static void set_device_guid(EDataFlow flow, HKEY drv_key, const WCHAR *key_name,
249 GUID *guid)
251 HKEY key;
252 BOOL opened = FALSE;
253 LONG lr;
255 if(!drv_key){
256 lr = RegCreateKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, NULL, 0, KEY_WRITE,
257 NULL, &drv_key, NULL);
258 if(lr != ERROR_SUCCESS){
259 ERR("RegCreateKeyEx(drv_key) failed: %lu\n", lr);
260 return;
262 opened = TRUE;
265 lr = RegCreateKeyExW(drv_key, key_name, 0, NULL, 0, KEY_WRITE,
266 NULL, &key, NULL);
267 if(lr != ERROR_SUCCESS){
268 ERR("RegCreateKeyEx(%s) failed: %lu\n", wine_dbgstr_w(key_name), lr);
269 goto exit;
272 lr = RegSetValueExW(key, guidW, 0, REG_BINARY, (BYTE*)guid,
273 sizeof(GUID));
274 if(lr != ERROR_SUCCESS)
275 ERR("RegSetValueEx(%s\\guid) failed: %lu\n", wine_dbgstr_w(key_name), lr);
277 RegCloseKey(key);
278 exit:
279 if(opened)
280 RegCloseKey(drv_key);
283 static void get_device_guid(EDataFlow flow, const char *device, GUID *guid)
285 HKEY key = NULL, dev_key;
286 DWORD type, size = sizeof(*guid);
287 WCHAR key_name[256];
289 if(flow == eCapture)
290 key_name[0] = '1';
291 else
292 key_name[0] = '0';
293 key_name[1] = ',';
294 MultiByteToWideChar(CP_UNIXCP, 0, device, -1, key_name + 2, ARRAY_SIZE(key_name) - 2);
296 if(RegOpenKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, KEY_WRITE|KEY_READ, &key) == ERROR_SUCCESS){
297 if(RegOpenKeyExW(key, key_name, 0, KEY_READ, &dev_key) == ERROR_SUCCESS){
298 if(RegQueryValueExW(dev_key, guidW, 0, &type,
299 (BYTE*)guid, &size) == ERROR_SUCCESS){
300 if(type == REG_BINARY){
301 RegCloseKey(dev_key);
302 RegCloseKey(key);
303 return;
305 ERR("Invalid type for device %s GUID: %lu; ignoring and overwriting\n",
306 wine_dbgstr_w(key_name), type);
308 RegCloseKey(dev_key);
312 CoCreateGuid(guid);
314 set_device_guid(flow, key, key_name, guid);
316 if(key)
317 RegCloseKey(key);
320 static void set_stream_volumes(ACImpl *This)
322 struct set_volumes_params params;
324 params.stream = This->stream;
325 params.master_volume = (This->session->mute ? 0.0f : This->session->master_vol);
326 params.volumes = This->vols;
327 params.session_volumes = This->session->channel_vols;
329 ALSA_CALL(set_volumes, &params);
332 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids_out, GUID **guids_out,
333 UINT *num, UINT *def_index)
335 struct get_endpoint_ids_params params;
336 unsigned int i;
337 GUID *guids = NULL;
338 WCHAR **ids = NULL;
340 TRACE("%d %p %p %p %p\n", flow, ids, guids, num, def_index);
342 params.flow = flow;
343 params.size = 1000;
344 params.endpoints = NULL;
346 HeapFree(GetProcessHeap(), 0, params.endpoints);
347 params.endpoints = HeapAlloc(GetProcessHeap(), 0, params.size);
348 ALSA_CALL(get_endpoint_ids, &params);
349 }while(params.result == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
351 if(FAILED(params.result)) goto end;
353 ids = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, params.num * sizeof(*ids));
354 guids = HeapAlloc(GetProcessHeap(), 0, params.num * sizeof(*guids));
355 if(!ids || !guids){
356 params.result = E_OUTOFMEMORY;
357 goto end;
360 for(i = 0; i < params.num; i++){
361 WCHAR *name = (WCHAR *)((char *)params.endpoints + params.endpoints[i].name);
362 char *device = (char *)params.endpoints + params.endpoints[i].device;
363 unsigned int size = (wcslen(name) + 1) * sizeof(WCHAR);
365 ids[i] = HeapAlloc(GetProcessHeap(), 0, size);
366 if(!ids[i]){
367 params.result = E_OUTOFMEMORY;
368 goto end;
370 memcpy(ids[i], name, size);
371 get_device_guid(flow, device, guids + i);
373 *def_index = params.default_idx;
375 end:
376 HeapFree(GetProcessHeap(), 0, params.endpoints);
377 if(FAILED(params.result)){
378 HeapFree(GetProcessHeap(), 0, guids);
379 if(ids){
380 for(i = 0; i < params.num; i++)
381 HeapFree(GetProcessHeap(), 0, ids[i]);
382 HeapFree(GetProcessHeap(), 0, ids);
384 }else{
385 *ids_out = ids;
386 *guids_out = guids;
387 *num = params.num;
390 return params.result;
393 static BOOL get_alsa_name_by_guid(GUID *guid, char *name, DWORD name_size, EDataFlow *flow)
395 HKEY devices_key;
396 UINT i = 0;
397 WCHAR key_name[256];
398 DWORD key_name_size;
400 if(RegOpenKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, KEY_READ, &devices_key) != ERROR_SUCCESS){
401 ERR("No devices found in registry?\n");
402 return FALSE;
405 while(1){
406 HKEY key;
407 DWORD size, type;
408 GUID reg_guid;
410 key_name_size = ARRAY_SIZE(key_name);
411 if(RegEnumKeyExW(devices_key, i++, key_name, &key_name_size, NULL,
412 NULL, NULL, NULL) != ERROR_SUCCESS)
413 break;
415 if(RegOpenKeyExW(devices_key, key_name, 0, KEY_READ, &key) != ERROR_SUCCESS){
416 WARN("Couldn't open key: %s\n", wine_dbgstr_w(key_name));
417 continue;
420 size = sizeof(reg_guid);
421 if(RegQueryValueExW(key, guidW, 0, &type,
422 (BYTE*)&reg_guid, &size) == ERROR_SUCCESS){
423 if(IsEqualGUID(&reg_guid, guid)){
424 RegCloseKey(key);
425 RegCloseKey(devices_key);
427 TRACE("Found matching device key: %s\n", wine_dbgstr_w(key_name));
429 if(key_name[0] == '0')
430 *flow = eRender;
431 else if(key_name[0] == '1')
432 *flow = eCapture;
433 else{
434 ERR("Unknown device type: %c\n", key_name[0]);
435 return FALSE;
438 WideCharToMultiByte(CP_UNIXCP, 0, key_name + 2, -1, name, name_size, NULL, NULL);
440 return TRUE;
444 RegCloseKey(key);
447 RegCloseKey(devices_key);
449 WARN("No matching device in registry for GUID %s\n", debugstr_guid(guid));
451 return FALSE;
454 HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient **out)
456 ACImpl *This;
457 char alsa_name[256];
458 EDataFlow dataflow;
459 HRESULT hr;
460 int len;
462 TRACE("%s %p %p\n", debugstr_guid(guid), dev, out);
464 if(!get_alsa_name_by_guid(guid, alsa_name, sizeof(alsa_name), &dataflow))
465 return AUDCLNT_E_DEVICE_INVALIDATED;
467 if(dataflow != eRender && dataflow != eCapture)
468 return E_UNEXPECTED;
470 len = strlen(alsa_name);
471 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, offsetof(ACImpl, alsa_name[len + 1]));
472 if(!This)
473 return E_OUTOFMEMORY;
475 This->IAudioClient3_iface.lpVtbl = &AudioClient3_Vtbl;
476 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
477 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
478 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
479 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
480 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
482 hr = CoCreateFreeThreadedMarshaler((IUnknown *)&This->IAudioClient3_iface, &This->pUnkFTMarshal);
483 if (FAILED(hr)) {
484 HeapFree(GetProcessHeap(), 0, This);
485 return hr;
488 This->dataflow = dataflow;
489 memcpy(This->alsa_name, alsa_name, len + 1);
491 This->parent = dev;
492 IMMDevice_AddRef(This->parent);
494 *out = (IAudioClient *)&This->IAudioClient3_iface;
495 IAudioClient3_AddRef(&This->IAudioClient3_iface);
497 return S_OK;
500 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient3 *iface,
501 REFIID riid, void **ppv)
503 ACImpl *This = impl_from_IAudioClient3(iface);
504 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
506 if(!ppv)
507 return E_POINTER;
508 *ppv = NULL;
509 if(IsEqualIID(riid, &IID_IUnknown) ||
510 IsEqualIID(riid, &IID_IAudioClient) ||
511 IsEqualIID(riid, &IID_IAudioClient2) ||
512 IsEqualIID(riid, &IID_IAudioClient3))
513 *ppv = iface;
514 else if(IsEqualIID(riid, &IID_IMarshal))
515 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
517 if(*ppv){
518 IUnknown_AddRef((IUnknown*)*ppv);
519 return S_OK;
521 WARN("Unknown interface %s\n", debugstr_guid(riid));
522 return E_NOINTERFACE;
525 static ULONG WINAPI AudioClient_AddRef(IAudioClient3 *iface)
527 ACImpl *This = impl_from_IAudioClient3(iface);
528 ULONG ref;
529 ref = InterlockedIncrement(&This->ref);
530 TRACE("(%p) Refcount now %lu\n", This, ref);
531 return ref;
534 static ULONG WINAPI AudioClient_Release(IAudioClient3 *iface)
536 ACImpl *This = impl_from_IAudioClient3(iface);
537 ULONG ref;
539 ref = InterlockedDecrement(&This->ref);
540 TRACE("(%p) Refcount now %lu\n", This, ref);
541 if(!ref){
542 IAudioClient3_Stop(iface);
543 IMMDevice_Release(This->parent);
544 IUnknown_Release(This->pUnkFTMarshal);
545 if(This->session){
546 EnterCriticalSection(&g_sessions_lock);
547 list_remove(&This->entry);
548 LeaveCriticalSection(&g_sessions_lock);
550 HeapFree(GetProcessHeap(), 0, This->vols);
551 if (This->stream)
552 alsa_stream_release(This->stream, This->timer_thread);
553 HeapFree(GetProcessHeap(), 0, This);
555 return ref;
558 static void dump_fmt(const WAVEFORMATEX *fmt)
560 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
561 switch(fmt->wFormatTag){
562 case WAVE_FORMAT_PCM:
563 TRACE("WAVE_FORMAT_PCM");
564 break;
565 case WAVE_FORMAT_IEEE_FLOAT:
566 TRACE("WAVE_FORMAT_IEEE_FLOAT");
567 break;
568 case WAVE_FORMAT_EXTENSIBLE:
569 TRACE("WAVE_FORMAT_EXTENSIBLE");
570 break;
571 default:
572 TRACE("Unknown");
573 break;
575 TRACE(")\n");
577 TRACE("nChannels: %u\n", fmt->nChannels);
578 TRACE("nSamplesPerSec: %lu\n", fmt->nSamplesPerSec);
579 TRACE("nAvgBytesPerSec: %lu\n", fmt->nAvgBytesPerSec);
580 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
581 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
582 TRACE("cbSize: %u\n", fmt->cbSize);
584 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
585 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
586 TRACE("dwChannelMask: %08lx\n", fmtex->dwChannelMask);
587 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
588 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
592 static void session_init_vols(AudioSession *session, UINT channels)
594 if(session->channel_count < channels){
595 UINT i;
597 if(session->channel_vols)
598 session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
599 session->channel_vols, sizeof(float) * channels);
600 else
601 session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
602 sizeof(float) * channels);
603 if(!session->channel_vols)
604 return;
606 for(i = session->channel_count; i < channels; ++i)
607 session->channel_vols[i] = 1.f;
609 session->channel_count = channels;
613 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
614 UINT num_channels)
616 AudioSession *ret;
618 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
619 if(!ret)
620 return NULL;
622 memcpy(&ret->guid, guid, sizeof(GUID));
624 ret->device = device;
626 list_init(&ret->clients);
628 list_add_head(&g_sessions, &ret->entry);
630 session_init_vols(ret, num_channels);
632 ret->master_vol = 1.f;
634 return ret;
637 /* if channels == 0, then this will return or create a session with
638 * matching dataflow and GUID. otherwise, channels must also match */
639 static HRESULT get_audio_session(const GUID *sessionguid,
640 IMMDevice *device, UINT channels, AudioSession **out)
642 AudioSession *session;
644 if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
645 *out = create_session(&GUID_NULL, device, channels);
646 if(!*out)
647 return E_OUTOFMEMORY;
649 return S_OK;
652 *out = NULL;
653 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
654 if(session->device == device &&
655 IsEqualGUID(sessionguid, &session->guid)){
656 session_init_vols(session, channels);
657 *out = session;
658 break;
662 if(!*out){
663 *out = create_session(sessionguid, device, channels);
664 if(!*out)
665 return E_OUTOFMEMORY;
668 return S_OK;
671 static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
672 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
673 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
674 const GUID *sessionguid)
676 ACImpl *This = impl_from_IAudioClient3(iface);
677 struct create_stream_params params;
678 stream_handle stream;
679 unsigned int i;
681 TRACE("(%p)->(%x, %lx, %s, %s, %p, %s)\n", This, mode, flags,
682 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
684 if(!fmt)
685 return E_POINTER;
687 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
688 return E_INVALIDARG;
690 if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
691 AUDCLNT_STREAMFLAGS_LOOPBACK |
692 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
693 AUDCLNT_STREAMFLAGS_NOPERSIST |
694 AUDCLNT_STREAMFLAGS_RATEADJUST |
695 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
696 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
697 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED |
698 AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY |
699 AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM)){
700 FIXME("Unknown flags: %08lx\n", flags);
701 return E_INVALIDARG;
704 if(mode == AUDCLNT_SHAREMODE_SHARED){
705 period = DefaultPeriod;
706 if( duration < 3 * period)
707 duration = 3 * period;
708 }else{
709 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
710 if(((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask == 0 ||
711 ((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask & SPEAKER_RESERVED)
712 return AUDCLNT_E_UNSUPPORTED_FORMAT;
715 if(!period)
716 period = DefaultPeriod; /* not minimum */
717 if(period < MinimumPeriod || period > 5000000)
718 return AUDCLNT_E_INVALID_DEVICE_PERIOD;
719 if(duration > 20000000) /* the smaller the period, the lower this limit */
720 return AUDCLNT_E_BUFFER_SIZE_ERROR;
721 if(flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK){
722 if(duration != period)
723 return AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL;
724 FIXME("EXCLUSIVE mode with EVENTCALLBACK\n");
725 return AUDCLNT_E_DEVICE_IN_USE;
726 }else{
727 if( duration < 8 * period)
728 duration = 8 * period; /* may grow above 2s */
732 EnterCriticalSection(&g_sessions_lock);
734 if(This->stream){
735 LeaveCriticalSection(&g_sessions_lock);
736 return AUDCLNT_E_ALREADY_INITIALIZED;
739 dump_fmt(fmt);
741 params.name = NULL;
742 params.device = This->alsa_name;
743 params.flow = This->dataflow;
744 params.share = mode;
745 params.flags = flags;
746 params.duration = duration;
747 params.period = period;
748 params.fmt = fmt;
749 params.channel_count = NULL;
750 params.stream = &stream;
752 ALSA_CALL(create_stream, &params);
753 if(FAILED(params.result)){
754 LeaveCriticalSection(&g_sessions_lock);
755 return params.result;
758 This->channel_count = fmt->nChannels;
759 This->vols = HeapAlloc(GetProcessHeap(), 0, This->channel_count * sizeof(float));
760 if(!This->vols){
761 params.result = E_OUTOFMEMORY;
762 goto exit;
764 for(i = 0; i < This->channel_count; ++i)
765 This->vols[i] = 1.f;
767 params.result = get_audio_session(sessionguid, This->parent, This->channel_count,
768 &This->session);
769 if(FAILED(params.result))
770 goto exit;
772 list_add_tail(&This->session->clients, &This->entry);
774 exit:
775 if(FAILED(params.result)){
776 alsa_stream_release(stream, NULL);
777 HeapFree(GetProcessHeap(), 0, This->vols);
778 This->vols = NULL;
779 }else{
780 This->stream = stream;
781 set_stream_volumes(This);
784 LeaveCriticalSection(&g_sessions_lock);
786 return params.result;
789 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient3 *iface,
790 UINT32 *out)
792 ACImpl *This = impl_from_IAudioClient3(iface);
793 struct get_buffer_size_params params;
795 TRACE("(%p)->(%p)\n", This, out);
797 if(!out)
798 return E_POINTER;
800 if(!This->stream)
801 return AUDCLNT_E_NOT_INITIALIZED;
803 params.stream = This->stream;
804 params.size = out;
806 ALSA_CALL(get_buffer_size, &params);
808 return params.result;
811 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient3 *iface,
812 REFERENCE_TIME *latency)
814 ACImpl *This = impl_from_IAudioClient3(iface);
815 struct get_latency_params params;
817 TRACE("(%p)->(%p)\n", This, latency);
819 if(!latency)
820 return E_POINTER;
822 if(!This->stream)
823 return AUDCLNT_E_NOT_INITIALIZED;
825 params.stream = This->stream;
826 params.latency = latency;
828 ALSA_CALL(get_latency, &params);
830 return params.result;
833 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient3 *iface,
834 UINT32 *out)
836 ACImpl *This = impl_from_IAudioClient3(iface);
837 struct get_current_padding_params params;
839 TRACE("(%p)->(%p)\n", This, out);
841 if(!out)
842 return E_POINTER;
844 if(!This->stream)
845 return AUDCLNT_E_NOT_INITIALIZED;
847 params.stream = This->stream;
848 params.padding = out;
850 ALSA_CALL(get_current_padding, &params);
852 TRACE("pad: %u\n", *out);
854 return params.result;
857 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient3 *iface,
858 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *fmt,
859 WAVEFORMATEX **out)
861 ACImpl *This = impl_from_IAudioClient3(iface);
862 struct is_format_supported_params params;
864 TRACE("(%p)->(%x, %p, %p)\n", This, mode, fmt, out);
865 if(fmt) dump_fmt(fmt);
867 params.device = This->alsa_name;
868 params.flow = This->dataflow;
869 params.share = mode;
870 params.fmt_in = fmt;
871 params.fmt_out = NULL;
873 if(out){
874 *out = NULL;
875 if(mode == AUDCLNT_SHAREMODE_SHARED)
876 params.fmt_out = CoTaskMemAlloc(sizeof(*params.fmt_out));
878 ALSA_CALL(is_format_supported, &params);
880 if(params.result == S_FALSE)
881 *out = &params.fmt_out->Format;
882 else
883 CoTaskMemFree(params.fmt_out);
885 return params.result;
888 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface,
889 WAVEFORMATEX **pwfx)
891 ACImpl *This = impl_from_IAudioClient3(iface);
892 struct get_mix_format_params params;
894 TRACE("(%p)->(%p)\n", This, pwfx);
896 if(!pwfx)
897 return E_POINTER;
898 *pwfx = NULL;
900 params.device = This->alsa_name;
901 params.flow = This->dataflow;
902 params.fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
903 if(!params.fmt)
904 return E_OUTOFMEMORY;
906 ALSA_CALL(get_mix_format, &params);
908 if(SUCCEEDED(params.result)){
909 *pwfx = &params.fmt->Format;
910 dump_fmt(*pwfx);
911 } else
912 CoTaskMemFree(params.fmt);
914 return params.result;
917 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient3 *iface,
918 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
920 ACImpl *This = impl_from_IAudioClient3(iface);
922 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
924 if(!defperiod && !minperiod)
925 return E_POINTER;
927 if(defperiod)
928 *defperiod = DefaultPeriod;
929 if(minperiod)
930 *minperiod = DefaultPeriod;
932 return S_OK;
935 static HRESULT WINAPI AudioClient_Start(IAudioClient3 *iface)
937 ACImpl *This = impl_from_IAudioClient3(iface);
938 struct start_params params;
940 TRACE("(%p)\n", This);
942 EnterCriticalSection(&g_sessions_lock);
944 if(!This->stream){
945 LeaveCriticalSection(&g_sessions_lock);
946 return AUDCLNT_E_NOT_INITIALIZED;
949 params.stream = This->stream;
951 ALSA_CALL(start, &params);
953 if(SUCCEEDED(params.result) && !This->timer_thread){
954 This->timer_thread = CreateThread(NULL, 0, alsa_timer_thread, This, 0, NULL);
955 SetThreadPriority(This->timer_thread, THREAD_PRIORITY_TIME_CRITICAL);
958 LeaveCriticalSection(&g_sessions_lock);
960 return params.result;
963 static HRESULT WINAPI AudioClient_Stop(IAudioClient3 *iface)
965 ACImpl *This = impl_from_IAudioClient3(iface);
966 struct stop_params params;
968 TRACE("(%p)\n", This);
970 if(!This->stream)
971 return AUDCLNT_E_NOT_INITIALIZED;
973 params.stream = This->stream;
975 ALSA_CALL(stop, &params);
977 return params.result;
980 static HRESULT WINAPI AudioClient_Reset(IAudioClient3 *iface)
982 ACImpl *This = impl_from_IAudioClient3(iface);
983 struct reset_params params;
985 TRACE("(%p)\n", This);
987 if(!This->stream)
988 return AUDCLNT_E_NOT_INITIALIZED;
990 params.stream = This->stream;
992 ALSA_CALL(reset, &params);
994 return params.result;
997 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient3 *iface,
998 HANDLE event)
1000 ACImpl *This = impl_from_IAudioClient3(iface);
1001 struct set_event_handle_params params;
1003 TRACE("(%p)->(%p)\n", This, event);
1005 if(!event)
1006 return E_INVALIDARG;
1008 if(!This->stream)
1009 return AUDCLNT_E_NOT_INITIALIZED;
1011 params.stream = This->stream;
1012 params.event = event;
1014 ALSA_CALL(set_event_handle, &params);
1016 return params.result;
1019 static HRESULT WINAPI AudioClient_GetService(IAudioClient3 *iface, REFIID riid,
1020 void **ppv)
1022 ACImpl *This = impl_from_IAudioClient3(iface);
1024 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1026 if(!ppv)
1027 return E_POINTER;
1028 *ppv = NULL;
1030 EnterCriticalSection(&g_sessions_lock);
1032 if(!This->stream){
1033 LeaveCriticalSection(&g_sessions_lock);
1034 return AUDCLNT_E_NOT_INITIALIZED;
1037 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1038 if(This->dataflow != eRender){
1039 LeaveCriticalSection(&g_sessions_lock);
1040 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1042 IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
1043 *ppv = &This->IAudioRenderClient_iface;
1044 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1045 if(This->dataflow != eCapture){
1046 LeaveCriticalSection(&g_sessions_lock);
1047 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1049 IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
1050 *ppv = &This->IAudioCaptureClient_iface;
1051 }else if(IsEqualIID(riid, &IID_IAudioClock)){
1052 IAudioClock_AddRef(&This->IAudioClock_iface);
1053 *ppv = &This->IAudioClock_iface;
1054 }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1055 IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
1056 *ppv = &This->IAudioStreamVolume_iface;
1057 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1058 if(!This->session_wrapper){
1059 This->session_wrapper = AudioSessionWrapper_Create(This);
1060 if(!This->session_wrapper){
1061 LeaveCriticalSection(&g_sessions_lock);
1062 return E_OUTOFMEMORY;
1064 }else
1065 IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
1067 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1068 }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1069 if(!This->session_wrapper){
1070 This->session_wrapper = AudioSessionWrapper_Create(This);
1071 if(!This->session_wrapper){
1072 LeaveCriticalSection(&g_sessions_lock);
1073 return E_OUTOFMEMORY;
1075 }else
1076 IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
1078 *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1079 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1080 if(!This->session_wrapper){
1081 This->session_wrapper = AudioSessionWrapper_Create(This);
1082 if(!This->session_wrapper){
1083 LeaveCriticalSection(&g_sessions_lock);
1084 return E_OUTOFMEMORY;
1086 }else
1087 ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
1089 *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1092 if(*ppv){
1093 LeaveCriticalSection(&g_sessions_lock);
1094 return S_OK;
1097 LeaveCriticalSection(&g_sessions_lock);
1099 FIXME("stub %s\n", debugstr_guid(riid));
1100 return E_NOINTERFACE;
1103 static HRESULT WINAPI AudioClient_IsOffloadCapable(IAudioClient3 *iface,
1104 AUDIO_STREAM_CATEGORY category, BOOL *offload_capable)
1106 ACImpl *This = impl_from_IAudioClient3(iface);
1108 TRACE("(%p)->(0x%x, %p)\n", This, category, offload_capable);
1110 if(!offload_capable)
1111 return E_INVALIDARG;
1113 *offload_capable = FALSE;
1115 return S_OK;
1118 static HRESULT WINAPI AudioClient_SetClientProperties(IAudioClient3 *iface,
1119 const AudioClientProperties *prop)
1121 ACImpl *This = impl_from_IAudioClient3(iface);
1122 const Win8AudioClientProperties *legacy_prop = (const Win8AudioClientProperties *)prop;
1124 TRACE("(%p)->(%p)\n", This, prop);
1126 if(!legacy_prop)
1127 return E_POINTER;
1129 if(legacy_prop->cbSize == sizeof(AudioClientProperties)){
1130 TRACE("{ bIsOffload: %u, eCategory: 0x%x, Options: 0x%x }\n",
1131 legacy_prop->bIsOffload,
1132 legacy_prop->eCategory,
1133 prop->Options);
1134 }else if(legacy_prop->cbSize == sizeof(Win8AudioClientProperties)){
1135 TRACE("{ bIsOffload: %u, eCategory: 0x%x }\n",
1136 legacy_prop->bIsOffload,
1137 legacy_prop->eCategory);
1138 }else{
1139 WARN("Unsupported Size = %d\n", legacy_prop->cbSize);
1140 return E_INVALIDARG;
1144 if(legacy_prop->bIsOffload)
1145 return AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE;
1147 return S_OK;
1150 static HRESULT WINAPI AudioClient_GetBufferSizeLimits(IAudioClient3 *iface,
1151 const WAVEFORMATEX *format, BOOL event_driven, REFERENCE_TIME *min_duration,
1152 REFERENCE_TIME *max_duration)
1154 ACImpl *This = impl_from_IAudioClient3(iface);
1156 FIXME("(%p)->(%p, %u, %p, %p)\n", This, format, event_driven, min_duration, max_duration);
1158 return E_NOTIMPL;
1161 static HRESULT WINAPI AudioClient_GetSharedModeEnginePeriod(IAudioClient3 *iface,
1162 const WAVEFORMATEX *format, UINT32 *default_period_frames, UINT32 *unit_period_frames,
1163 UINT32 *min_period_frames, UINT32 *max_period_frames)
1165 ACImpl *This = impl_from_IAudioClient3(iface);
1167 FIXME("(%p)->(%p, %p, %p, %p, %p)\n", This, format, default_period_frames, unit_period_frames,
1168 min_period_frames, max_period_frames);
1170 return E_NOTIMPL;
1173 static HRESULT WINAPI AudioClient_GetCurrentSharedModeEnginePeriod(IAudioClient3 *iface,
1174 WAVEFORMATEX **cur_format, UINT32 *cur_period_frames)
1176 ACImpl *This = impl_from_IAudioClient3(iface);
1178 FIXME("(%p)->(%p, %p)\n", This, cur_format, cur_period_frames);
1180 return E_NOTIMPL;
1183 static HRESULT WINAPI AudioClient_InitializeSharedAudioStream(IAudioClient3 *iface,
1184 DWORD flags, UINT32 period_frames, const WAVEFORMATEX *format,
1185 const GUID *session_guid)
1187 ACImpl *This = impl_from_IAudioClient3(iface);
1189 FIXME("(%p)->(0x%lx, %u, %p, %s)\n", This, flags, period_frames, format, debugstr_guid(session_guid));
1191 return E_NOTIMPL;
1194 static const IAudioClient3Vtbl AudioClient3_Vtbl =
1196 AudioClient_QueryInterface,
1197 AudioClient_AddRef,
1198 AudioClient_Release,
1199 AudioClient_Initialize,
1200 AudioClient_GetBufferSize,
1201 AudioClient_GetStreamLatency,
1202 AudioClient_GetCurrentPadding,
1203 AudioClient_IsFormatSupported,
1204 AudioClient_GetMixFormat,
1205 AudioClient_GetDevicePeriod,
1206 AudioClient_Start,
1207 AudioClient_Stop,
1208 AudioClient_Reset,
1209 AudioClient_SetEventHandle,
1210 AudioClient_GetService,
1211 AudioClient_IsOffloadCapable,
1212 AudioClient_SetClientProperties,
1213 AudioClient_GetBufferSizeLimits,
1214 AudioClient_GetSharedModeEnginePeriod,
1215 AudioClient_GetCurrentSharedModeEnginePeriod,
1216 AudioClient_InitializeSharedAudioStream,
1219 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1220 IAudioRenderClient *iface, REFIID riid, void **ppv)
1222 ACImpl *This = impl_from_IAudioRenderClient(iface);
1223 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1225 if(!ppv)
1226 return E_POINTER;
1227 *ppv = NULL;
1229 if(IsEqualIID(riid, &IID_IUnknown) ||
1230 IsEqualIID(riid, &IID_IAudioRenderClient))
1231 *ppv = iface;
1232 else if(IsEqualIID(riid, &IID_IMarshal))
1233 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
1235 if(*ppv){
1236 IUnknown_AddRef((IUnknown*)*ppv);
1237 return S_OK;
1240 WARN("Unknown interface %s\n", debugstr_guid(riid));
1241 return E_NOINTERFACE;
1244 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1246 ACImpl *This = impl_from_IAudioRenderClient(iface);
1247 return AudioClient_AddRef(&This->IAudioClient3_iface);
1250 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1252 ACImpl *This = impl_from_IAudioRenderClient(iface);
1253 return AudioClient_Release(&This->IAudioClient3_iface);
1256 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1257 UINT32 frames, BYTE **data)
1259 ACImpl *This = impl_from_IAudioRenderClient(iface);
1260 struct get_render_buffer_params params;
1262 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1264 if(!data)
1265 return E_POINTER;
1266 *data = NULL;
1268 params.stream = This->stream;
1269 params.frames = frames;
1270 params.data = data;
1272 ALSA_CALL(get_render_buffer, &params);
1274 return params.result;
1277 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1278 IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
1280 ACImpl *This = impl_from_IAudioRenderClient(iface);
1281 struct release_render_buffer_params params;
1283 TRACE("(%p)->(%u, %lx)\n", This, written_frames, flags);
1285 params.stream = This->stream;
1286 params.written_frames = written_frames;
1287 params.flags = flags;
1289 ALSA_CALL(release_render_buffer, &params);
1291 return params.result;
1294 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1295 AudioRenderClient_QueryInterface,
1296 AudioRenderClient_AddRef,
1297 AudioRenderClient_Release,
1298 AudioRenderClient_GetBuffer,
1299 AudioRenderClient_ReleaseBuffer
1302 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1303 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1305 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1306 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1308 if(!ppv)
1309 return E_POINTER;
1310 *ppv = NULL;
1312 if(IsEqualIID(riid, &IID_IUnknown) ||
1313 IsEqualIID(riid, &IID_IAudioCaptureClient))
1314 *ppv = iface;
1315 else if(IsEqualIID(riid, &IID_IMarshal))
1316 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
1318 if(*ppv){
1319 IUnknown_AddRef((IUnknown*)*ppv);
1320 return S_OK;
1323 WARN("Unknown interface %s\n", debugstr_guid(riid));
1324 return E_NOINTERFACE;
1327 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1329 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1330 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1333 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1335 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1336 return IAudioClient3_Release(&This->IAudioClient3_iface);
1339 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1340 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1341 UINT64 *qpcpos)
1343 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1344 struct get_capture_buffer_params params;
1346 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1347 devpos, qpcpos);
1349 if(!data)
1350 return E_POINTER;
1352 *data = NULL;
1354 if(!frames || !flags)
1355 return E_POINTER;
1357 params.stream = This->stream;
1358 params.data = data;
1359 params.frames = frames;
1360 params.flags = (UINT*)flags;
1361 params.devpos = devpos;
1362 params.qpcpos = qpcpos;
1364 ALSA_CALL(get_capture_buffer, &params);
1366 return params.result;
1369 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1370 IAudioCaptureClient *iface, UINT32 done)
1372 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1373 struct release_capture_buffer_params params;
1375 TRACE("(%p)->(%u)\n", This, done);
1377 params.stream = This->stream;
1378 params.done = done;
1380 ALSA_CALL(release_capture_buffer, &params);
1382 return params.result;
1385 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1386 IAudioCaptureClient *iface, UINT32 *frames)
1388 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1389 struct get_next_packet_size_params params;
1391 TRACE("(%p)->(%p)\n", This, frames);
1393 if(!frames)
1394 return E_POINTER;
1396 params.stream = This->stream;
1397 params.frames = frames;
1399 ALSA_CALL(get_next_packet_size, &params);
1401 return params.result;
1404 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1406 AudioCaptureClient_QueryInterface,
1407 AudioCaptureClient_AddRef,
1408 AudioCaptureClient_Release,
1409 AudioCaptureClient_GetBuffer,
1410 AudioCaptureClient_ReleaseBuffer,
1411 AudioCaptureClient_GetNextPacketSize
1414 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1415 REFIID riid, void **ppv)
1417 ACImpl *This = impl_from_IAudioClock(iface);
1419 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1421 if(!ppv)
1422 return E_POINTER;
1423 *ppv = NULL;
1425 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
1426 *ppv = iface;
1427 else if(IsEqualIID(riid, &IID_IAudioClock2))
1428 *ppv = &This->IAudioClock2_iface;
1429 if(*ppv){
1430 IUnknown_AddRef((IUnknown*)*ppv);
1431 return S_OK;
1434 WARN("Unknown interface %s\n", debugstr_guid(riid));
1435 return E_NOINTERFACE;
1438 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
1440 ACImpl *This = impl_from_IAudioClock(iface);
1441 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1444 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
1446 ACImpl *This = impl_from_IAudioClock(iface);
1447 return IAudioClient3_Release(&This->IAudioClient3_iface);
1450 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
1452 ACImpl *This = impl_from_IAudioClock(iface);
1453 struct get_frequency_params params;
1455 TRACE("(%p)->(%p)\n", This, freq);
1457 params.stream = This->stream;
1458 params.freq = freq;
1460 ALSA_CALL(get_frequency, &params);
1462 return params.result;
1465 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
1466 UINT64 *qpctime)
1468 ACImpl *This = impl_from_IAudioClock(iface);
1469 struct get_position_params params;
1471 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
1473 if(!pos)
1474 return E_POINTER;
1476 params.stream = This->stream;
1477 params.device = FALSE;
1478 params.pos = pos;
1479 params.qpctime = qpctime;
1481 ALSA_CALL(get_position, &params);
1483 return params.result;
1486 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
1487 DWORD *chars)
1489 ACImpl *This = impl_from_IAudioClock(iface);
1491 TRACE("(%p)->(%p)\n", This, chars);
1493 if(!chars)
1494 return E_POINTER;
1496 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
1498 return S_OK;
1501 static const IAudioClockVtbl AudioClock_Vtbl =
1503 AudioClock_QueryInterface,
1504 AudioClock_AddRef,
1505 AudioClock_Release,
1506 AudioClock_GetFrequency,
1507 AudioClock_GetPosition,
1508 AudioClock_GetCharacteristics
1511 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
1512 REFIID riid, void **ppv)
1514 ACImpl *This = impl_from_IAudioClock2(iface);
1515 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
1518 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
1520 ACImpl *This = impl_from_IAudioClock2(iface);
1521 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1524 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
1526 ACImpl *This = impl_from_IAudioClock2(iface);
1527 return IAudioClient3_Release(&This->IAudioClient3_iface);
1530 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
1531 UINT64 *pos, UINT64 *qpctime)
1533 ACImpl *This = impl_from_IAudioClock2(iface);
1535 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
1537 return E_NOTIMPL;
1540 static const IAudioClock2Vtbl AudioClock2_Vtbl =
1542 AudioClock2_QueryInterface,
1543 AudioClock2_AddRef,
1544 AudioClock2_Release,
1545 AudioClock2_GetDevicePosition
1548 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
1550 AudioSessionWrapper *ret;
1552 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1553 sizeof(AudioSessionWrapper));
1554 if(!ret)
1555 return NULL;
1557 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
1558 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
1559 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
1561 ret->ref = 1;
1563 ret->client = client;
1564 if(client){
1565 ret->session = client->session;
1566 AudioClient_AddRef(&client->IAudioClient3_iface);
1569 return ret;
1572 static HRESULT WINAPI AudioSessionControl_QueryInterface(
1573 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
1575 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1577 if(!ppv)
1578 return E_POINTER;
1579 *ppv = NULL;
1581 if(IsEqualIID(riid, &IID_IUnknown) ||
1582 IsEqualIID(riid, &IID_IAudioSessionControl) ||
1583 IsEqualIID(riid, &IID_IAudioSessionControl2))
1584 *ppv = iface;
1585 if(*ppv){
1586 IUnknown_AddRef((IUnknown*)*ppv);
1587 return S_OK;
1590 WARN("Unknown interface %s\n", debugstr_guid(riid));
1591 return E_NOINTERFACE;
1594 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
1596 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1597 ULONG ref;
1598 ref = InterlockedIncrement(&This->ref);
1599 TRACE("(%p) Refcount now %lu\n", This, ref);
1600 return ref;
1603 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
1605 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1606 ULONG ref;
1607 ref = InterlockedDecrement(&This->ref);
1608 TRACE("(%p) Refcount now %lu\n", This, ref);
1609 if(!ref){
1610 if(This->client){
1611 EnterCriticalSection(&g_sessions_lock);
1612 This->client->session_wrapper = NULL;
1613 LeaveCriticalSection(&g_sessions_lock);
1614 AudioClient_Release(&This->client->IAudioClient3_iface);
1616 HeapFree(GetProcessHeap(), 0, This);
1618 return ref;
1621 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
1622 AudioSessionState *state)
1624 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1625 struct is_started_params params;
1626 ACImpl *client;
1628 TRACE("(%p)->(%p)\n", This, state);
1630 if(!state)
1631 return NULL_PTR_ERR;
1633 EnterCriticalSection(&g_sessions_lock);
1635 if(list_empty(&This->session->clients)){
1636 *state = AudioSessionStateExpired;
1637 LeaveCriticalSection(&g_sessions_lock);
1638 return S_OK;
1641 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
1642 params.stream = client->stream;
1643 ALSA_CALL(is_started, &params);
1644 if(params.result == S_OK){
1645 *state = AudioSessionStateActive;
1646 LeaveCriticalSection(&g_sessions_lock);
1647 return S_OK;
1651 LeaveCriticalSection(&g_sessions_lock);
1653 *state = AudioSessionStateInactive;
1655 return S_OK;
1658 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
1659 IAudioSessionControl2 *iface, WCHAR **name)
1661 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1663 FIXME("(%p)->(%p) - stub\n", This, name);
1665 return E_NOTIMPL;
1668 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
1669 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
1671 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1673 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
1675 return E_NOTIMPL;
1678 static HRESULT WINAPI AudioSessionControl_GetIconPath(
1679 IAudioSessionControl2 *iface, WCHAR **path)
1681 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1683 FIXME("(%p)->(%p) - stub\n", This, path);
1685 return E_NOTIMPL;
1688 static HRESULT WINAPI AudioSessionControl_SetIconPath(
1689 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
1691 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1693 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
1695 return E_NOTIMPL;
1698 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
1699 IAudioSessionControl2 *iface, GUID *group)
1701 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1703 FIXME("(%p)->(%p) - stub\n", This, group);
1705 return E_NOTIMPL;
1708 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
1709 IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
1711 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1713 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
1714 debugstr_guid(session));
1716 return E_NOTIMPL;
1719 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
1720 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
1722 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1724 FIXME("(%p)->(%p) - stub\n", This, events);
1726 return S_OK;
1729 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
1730 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
1732 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1734 FIXME("(%p)->(%p) - stub\n", This, events);
1736 return S_OK;
1739 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
1740 IAudioSessionControl2 *iface, WCHAR **id)
1742 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1744 FIXME("(%p)->(%p) - stub\n", This, id);
1746 return E_NOTIMPL;
1749 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
1750 IAudioSessionControl2 *iface, WCHAR **id)
1752 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1754 FIXME("(%p)->(%p) - stub\n", This, id);
1756 return E_NOTIMPL;
1759 static HRESULT WINAPI AudioSessionControl_GetProcessId(
1760 IAudioSessionControl2 *iface, DWORD *pid)
1762 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1764 TRACE("(%p)->(%p)\n", This, pid);
1766 if(!pid)
1767 return E_POINTER;
1769 *pid = GetCurrentProcessId();
1771 return S_OK;
1774 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
1775 IAudioSessionControl2 *iface)
1777 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1779 TRACE("(%p)\n", This);
1781 return S_FALSE;
1784 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
1785 IAudioSessionControl2 *iface, BOOL optout)
1787 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1789 TRACE("(%p)->(%d)\n", This, optout);
1791 return S_OK;
1794 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
1796 AudioSessionControl_QueryInterface,
1797 AudioSessionControl_AddRef,
1798 AudioSessionControl_Release,
1799 AudioSessionControl_GetState,
1800 AudioSessionControl_GetDisplayName,
1801 AudioSessionControl_SetDisplayName,
1802 AudioSessionControl_GetIconPath,
1803 AudioSessionControl_SetIconPath,
1804 AudioSessionControl_GetGroupingParam,
1805 AudioSessionControl_SetGroupingParam,
1806 AudioSessionControl_RegisterAudioSessionNotification,
1807 AudioSessionControl_UnregisterAudioSessionNotification,
1808 AudioSessionControl_GetSessionIdentifier,
1809 AudioSessionControl_GetSessionInstanceIdentifier,
1810 AudioSessionControl_GetProcessId,
1811 AudioSessionControl_IsSystemSoundsSession,
1812 AudioSessionControl_SetDuckingPreference
1815 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
1816 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
1818 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1820 if(!ppv)
1821 return E_POINTER;
1822 *ppv = NULL;
1824 if(IsEqualIID(riid, &IID_IUnknown) ||
1825 IsEqualIID(riid, &IID_ISimpleAudioVolume))
1826 *ppv = iface;
1827 if(*ppv){
1828 IUnknown_AddRef((IUnknown*)*ppv);
1829 return S_OK;
1832 WARN("Unknown interface %s\n", debugstr_guid(riid));
1833 return E_NOINTERFACE;
1836 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
1838 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1839 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
1842 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
1844 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1845 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
1848 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
1849 ISimpleAudioVolume *iface, float level, const GUID *context)
1851 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1852 AudioSession *session = This->session;
1853 ACImpl *client;
1855 TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
1857 if(level < 0.f || level > 1.f)
1858 return E_INVALIDARG;
1860 if(context)
1861 FIXME("Notifications not supported yet\n");
1863 TRACE("ALSA does not support volume control\n");
1865 EnterCriticalSection(&g_sessions_lock);
1867 session->master_vol = level;
1869 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
1870 set_stream_volumes(client);
1872 LeaveCriticalSection(&g_sessions_lock);
1874 return S_OK;
1877 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
1878 ISimpleAudioVolume *iface, float *level)
1880 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1881 AudioSession *session = This->session;
1883 TRACE("(%p)->(%p)\n", session, level);
1885 if(!level)
1886 return NULL_PTR_ERR;
1888 *level = session->master_vol;
1890 return S_OK;
1893 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
1894 BOOL mute, const GUID *context)
1896 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1897 AudioSession *session = This->session;
1898 ACImpl *client;
1900 TRACE("(%p)->(%u, %s)\n", session, mute, debugstr_guid(context));
1902 if(context)
1903 FIXME("Notifications not supported yet\n");
1905 EnterCriticalSection(&g_sessions_lock);
1907 session->mute = mute;
1908 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
1909 set_stream_volumes(client);
1911 LeaveCriticalSection(&g_sessions_lock);
1913 return S_OK;
1916 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
1917 BOOL *mute)
1919 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1920 AudioSession *session = This->session;
1922 TRACE("(%p)->(%p)\n", session, mute);
1924 if(!mute)
1925 return NULL_PTR_ERR;
1927 *mute = session->mute;
1929 return S_OK;
1932 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
1934 SimpleAudioVolume_QueryInterface,
1935 SimpleAudioVolume_AddRef,
1936 SimpleAudioVolume_Release,
1937 SimpleAudioVolume_SetMasterVolume,
1938 SimpleAudioVolume_GetMasterVolume,
1939 SimpleAudioVolume_SetMute,
1940 SimpleAudioVolume_GetMute
1943 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
1944 IAudioStreamVolume *iface, REFIID riid, void **ppv)
1946 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1948 if(!ppv)
1949 return E_POINTER;
1950 *ppv = NULL;
1952 if(IsEqualIID(riid, &IID_IUnknown) ||
1953 IsEqualIID(riid, &IID_IAudioStreamVolume))
1954 *ppv = iface;
1955 if(*ppv){
1956 IUnknown_AddRef((IUnknown*)*ppv);
1957 return S_OK;
1960 WARN("Unknown interface %s\n", debugstr_guid(riid));
1961 return E_NOINTERFACE;
1964 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
1966 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1967 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1970 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
1972 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1973 return IAudioClient3_Release(&This->IAudioClient3_iface);
1976 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
1977 IAudioStreamVolume *iface, UINT32 *out)
1979 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1981 TRACE("(%p)->(%p)\n", This, out);
1983 if(!out)
1984 return E_POINTER;
1986 *out = This->channel_count;
1988 return S_OK;
1991 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
1992 IAudioStreamVolume *iface, UINT32 index, float level)
1994 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1996 TRACE("(%p)->(%d, %f)\n", This, index, level);
1998 if(level < 0.f || level > 1.f)
1999 return E_INVALIDARG;
2001 if(index >= This->channel_count)
2002 return E_INVALIDARG;
2004 TRACE("ALSA does not support volume control\n");
2006 EnterCriticalSection(&g_sessions_lock);
2008 This->vols[index] = level;
2009 set_stream_volumes(This);
2011 LeaveCriticalSection(&g_sessions_lock);
2013 return S_OK;
2016 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2017 IAudioStreamVolume *iface, UINT32 index, float *level)
2019 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2021 TRACE("(%p)->(%d, %p)\n", This, index, level);
2023 if(!level)
2024 return E_POINTER;
2026 if(index >= This->channel_count)
2027 return E_INVALIDARG;
2029 *level = This->vols[index];
2031 return S_OK;
2034 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2035 IAudioStreamVolume *iface, UINT32 count, const float *levels)
2037 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2038 unsigned int i;
2040 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2042 if(!levels)
2043 return E_POINTER;
2045 if(count != This->channel_count)
2046 return E_INVALIDARG;
2048 TRACE("ALSA does not support volume control\n");
2050 EnterCriticalSection(&g_sessions_lock);
2052 for(i = 0; i < count; ++i)
2053 This->vols[i] = levels[i];
2054 set_stream_volumes(This);
2056 LeaveCriticalSection(&g_sessions_lock);
2058 return S_OK;
2061 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2062 IAudioStreamVolume *iface, UINT32 count, float *levels)
2064 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2065 unsigned int i;
2067 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2069 if(!levels)
2070 return E_POINTER;
2072 if(count != This->channel_count)
2073 return E_INVALIDARG;
2075 EnterCriticalSection(&g_sessions_lock);
2077 for(i = 0; i < count; ++i)
2078 levels[i] = This->vols[i];
2080 LeaveCriticalSection(&g_sessions_lock);
2082 return S_OK;
2085 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2087 AudioStreamVolume_QueryInterface,
2088 AudioStreamVolume_AddRef,
2089 AudioStreamVolume_Release,
2090 AudioStreamVolume_GetChannelCount,
2091 AudioStreamVolume_SetChannelVolume,
2092 AudioStreamVolume_GetChannelVolume,
2093 AudioStreamVolume_SetAllVolumes,
2094 AudioStreamVolume_GetAllVolumes
2097 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2098 IChannelAudioVolume *iface, REFIID riid, void **ppv)
2100 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2102 if(!ppv)
2103 return E_POINTER;
2104 *ppv = NULL;
2106 if(IsEqualIID(riid, &IID_IUnknown) ||
2107 IsEqualIID(riid, &IID_IChannelAudioVolume))
2108 *ppv = iface;
2109 if(*ppv){
2110 IUnknown_AddRef((IUnknown*)*ppv);
2111 return S_OK;
2114 WARN("Unknown interface %s\n", debugstr_guid(riid));
2115 return E_NOINTERFACE;
2118 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2120 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2121 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2124 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2126 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2127 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2130 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2131 IChannelAudioVolume *iface, UINT32 *out)
2133 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2134 AudioSession *session = This->session;
2136 TRACE("(%p)->(%p)\n", session, out);
2138 if(!out)
2139 return NULL_PTR_ERR;
2141 *out = session->channel_count;
2143 return S_OK;
2146 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2147 IChannelAudioVolume *iface, UINT32 index, float level,
2148 const GUID *context)
2150 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2151 AudioSession *session = This->session;
2152 ACImpl *client;
2154 TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2155 wine_dbgstr_guid(context));
2157 if(level < 0.f || level > 1.f)
2158 return E_INVALIDARG;
2160 if(index >= session->channel_count)
2161 return E_INVALIDARG;
2163 if(context)
2164 FIXME("Notifications not supported yet\n");
2166 TRACE("ALSA does not support volume control\n");
2168 EnterCriticalSection(&g_sessions_lock);
2170 session->channel_vols[index] = level;
2172 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
2173 set_stream_volumes(client);
2175 LeaveCriticalSection(&g_sessions_lock);
2177 return S_OK;
2180 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2181 IChannelAudioVolume *iface, UINT32 index, float *level)
2183 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2184 AudioSession *session = This->session;
2186 TRACE("(%p)->(%d, %p)\n", session, index, level);
2188 if(!level)
2189 return NULL_PTR_ERR;
2191 if(index >= session->channel_count)
2192 return E_INVALIDARG;
2194 *level = session->channel_vols[index];
2196 return S_OK;
2199 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2200 IChannelAudioVolume *iface, UINT32 count, const float *levels,
2201 const GUID *context)
2203 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2204 AudioSession *session = This->session;
2205 unsigned int i;
2206 ACImpl *client;
2208 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2209 wine_dbgstr_guid(context));
2211 if(!levels)
2212 return NULL_PTR_ERR;
2214 if(count != session->channel_count)
2215 return E_INVALIDARG;
2217 if(context)
2218 FIXME("Notifications not supported yet\n");
2220 TRACE("ALSA does not support volume control\n");
2222 EnterCriticalSection(&g_sessions_lock);
2224 for(i = 0; i < count; ++i)
2225 session->channel_vols[i] = levels[i];
2227 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
2228 set_stream_volumes(client);
2230 LeaveCriticalSection(&g_sessions_lock);
2232 return S_OK;
2235 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2236 IChannelAudioVolume *iface, UINT32 count, float *levels)
2238 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2239 AudioSession *session = This->session;
2240 unsigned int i;
2242 TRACE("(%p)->(%d, %p)\n", session, count, levels);
2244 if(!levels)
2245 return NULL_PTR_ERR;
2247 if(count != session->channel_count)
2248 return E_INVALIDARG;
2250 for(i = 0; i < count; ++i)
2251 levels[i] = session->channel_vols[i];
2253 return S_OK;
2256 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2258 ChannelAudioVolume_QueryInterface,
2259 ChannelAudioVolume_AddRef,
2260 ChannelAudioVolume_Release,
2261 ChannelAudioVolume_GetChannelCount,
2262 ChannelAudioVolume_SetChannelVolume,
2263 ChannelAudioVolume_GetChannelVolume,
2264 ChannelAudioVolume_SetAllVolumes,
2265 ChannelAudioVolume_GetAllVolumes
2268 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2269 REFIID riid, void **ppv)
2271 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2273 if(!ppv)
2274 return E_POINTER;
2275 *ppv = NULL;
2277 if(IsEqualIID(riid, &IID_IUnknown) ||
2278 IsEqualIID(riid, &IID_IAudioSessionManager) ||
2279 IsEqualIID(riid, &IID_IAudioSessionManager2))
2280 *ppv = iface;
2281 if(*ppv){
2282 IUnknown_AddRef((IUnknown*)*ppv);
2283 return S_OK;
2286 WARN("Unknown interface %s\n", debugstr_guid(riid));
2287 return E_NOINTERFACE;
2290 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2292 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2293 ULONG ref;
2294 ref = InterlockedIncrement(&This->ref);
2295 TRACE("(%p) Refcount now %lu\n", This, ref);
2296 return ref;
2299 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2301 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2302 ULONG ref;
2303 ref = InterlockedDecrement(&This->ref);
2304 TRACE("(%p) Refcount now %lu\n", This, ref);
2305 if(!ref)
2306 HeapFree(GetProcessHeap(), 0, This);
2307 return ref;
2310 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2311 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2312 IAudioSessionControl **out)
2314 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2315 AudioSession *session;
2316 AudioSessionWrapper *wrapper;
2317 HRESULT hr;
2319 TRACE("(%p)->(%s, %lx, %p)\n", This, debugstr_guid(session_guid),
2320 flags, out);
2322 hr = get_audio_session(session_guid, This->device, 0, &session);
2323 if(FAILED(hr))
2324 return hr;
2326 wrapper = AudioSessionWrapper_Create(NULL);
2327 if(!wrapper)
2328 return E_OUTOFMEMORY;
2330 wrapper->session = session;
2332 *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
2334 return S_OK;
2337 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
2338 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2339 ISimpleAudioVolume **out)
2341 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2342 AudioSession *session;
2343 AudioSessionWrapper *wrapper;
2344 HRESULT hr;
2346 TRACE("(%p)->(%s, %lx, %p)\n", This, debugstr_guid(session_guid),
2347 flags, out);
2349 hr = get_audio_session(session_guid, This->device, 0, &session);
2350 if(FAILED(hr))
2351 return hr;
2353 wrapper = AudioSessionWrapper_Create(NULL);
2354 if(!wrapper)
2355 return E_OUTOFMEMORY;
2357 wrapper->session = session;
2359 *out = &wrapper->ISimpleAudioVolume_iface;
2361 return S_OK;
2364 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
2365 IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
2367 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2368 FIXME("(%p)->(%p) - stub\n", This, out);
2369 return E_NOTIMPL;
2372 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
2373 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2375 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2376 FIXME("(%p)->(%p) - stub\n", This, notification);
2377 return E_NOTIMPL;
2380 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
2381 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2383 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2384 FIXME("(%p)->(%p) - stub\n", This, notification);
2385 return E_NOTIMPL;
2388 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
2389 IAudioSessionManager2 *iface, const WCHAR *session_id,
2390 IAudioVolumeDuckNotification *notification)
2392 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2393 FIXME("(%p)->(%p) - stub\n", This, notification);
2394 return E_NOTIMPL;
2397 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
2398 IAudioSessionManager2 *iface,
2399 IAudioVolumeDuckNotification *notification)
2401 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2402 FIXME("(%p)->(%p) - stub\n", This, notification);
2403 return E_NOTIMPL;
2406 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
2408 AudioSessionManager_QueryInterface,
2409 AudioSessionManager_AddRef,
2410 AudioSessionManager_Release,
2411 AudioSessionManager_GetAudioSessionControl,
2412 AudioSessionManager_GetSimpleAudioVolume,
2413 AudioSessionManager_GetSessionEnumerator,
2414 AudioSessionManager_RegisterSessionNotification,
2415 AudioSessionManager_UnregisterSessionNotification,
2416 AudioSessionManager_RegisterDuckNotification,
2417 AudioSessionManager_UnregisterDuckNotification
2420 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
2421 IAudioSessionManager2 **out)
2423 SessionMgr *This;
2425 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
2426 if(!This)
2427 return E_OUTOFMEMORY;
2429 This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
2430 This->device = device;
2431 This->ref = 1;
2433 *out = &This->IAudioSessionManager2_iface;
2435 return S_OK;
2438 HRESULT WINAPI AUDDRV_GetPropValue(GUID *guid, const PROPERTYKEY *prop, PROPVARIANT *out)
2440 struct get_prop_value_params params;
2441 char name[256];
2442 EDataFlow flow;
2443 unsigned int size = 0;
2445 TRACE("%s, (%s,%lu), %p\n", wine_dbgstr_guid(guid), wine_dbgstr_guid(&prop->fmtid), prop->pid, out);
2447 if(!get_alsa_name_by_guid(guid, name, sizeof(name), &flow))
2449 WARN("Unknown interface %s\n", debugstr_guid(guid));
2450 return E_NOINTERFACE;
2453 params.device = name;
2454 params.flow = flow;
2455 params.guid = guid;
2456 params.prop = prop;
2457 params.value = out;
2458 params.buffer = NULL;
2459 params.buffer_size = &size;
2461 while(1) {
2462 ALSA_CALL(get_prop_value, &params);
2464 if(params.result != E_NOT_SUFFICIENT_BUFFER)
2465 break;
2467 CoTaskMemFree(params.buffer);
2468 params.buffer = CoTaskMemAlloc(*params.buffer_size);
2469 if(!params.buffer)
2470 return E_OUTOFMEMORY;
2472 if(FAILED(params.result))
2473 CoTaskMemFree(params.buffer);
2475 return params.result;