mmdevapi: Move test_connect handling into mmdevapi.
[wine.git] / dlls / winealsa.drv / mmdevdrv.c
blobfb81faf9d00ac921f0b288147fe1f4fe3fb32d6b
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 "propkey.h"
32 #include "initguid.h"
33 #include "ole2.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 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
53 static const REFERENCE_TIME DefaultPeriod = 100000;
54 static const REFERENCE_TIME MinimumPeriod = 50000;
56 struct ACImpl;
57 typedef struct ACImpl ACImpl;
59 typedef struct _AudioSession {
60 GUID guid;
61 struct list clients;
63 IMMDevice *device;
65 float master_vol;
66 UINT32 channel_count;
67 float *channel_vols;
68 BOOL mute;
70 struct list entry;
71 } AudioSession;
73 typedef struct _AudioSessionWrapper {
74 IAudioSessionControl2 IAudioSessionControl2_iface;
75 IChannelAudioVolume IChannelAudioVolume_iface;
76 ISimpleAudioVolume ISimpleAudioVolume_iface;
78 LONG ref;
80 ACImpl *client;
81 AudioSession *session;
82 } AudioSessionWrapper;
84 struct ACImpl {
85 IAudioClient3 IAudioClient3_iface;
86 IAudioRenderClient IAudioRenderClient_iface;
87 IAudioCaptureClient IAudioCaptureClient_iface;
88 IAudioClock IAudioClock_iface;
89 IAudioClock2 IAudioClock2_iface;
90 IAudioStreamVolume IAudioStreamVolume_iface;
92 LONG ref;
94 IMMDevice *parent;
95 IUnknown *pUnkFTMarshal;
97 EDataFlow dataflow;
98 float *vols;
99 UINT32 channel_count;
100 stream_handle stream;
102 HANDLE timer_thread;
104 AudioSession *session;
105 AudioSessionWrapper *session_wrapper;
107 struct list entry;
109 /* Keep at end */
110 char alsa_name[1];
113 typedef struct _SessionMgr {
114 IAudioSessionManager2 IAudioSessionManager2_iface;
116 LONG ref;
118 IMMDevice *device;
119 } SessionMgr;
121 static CRITICAL_SECTION g_sessions_lock;
122 static CRITICAL_SECTION_DEBUG g_sessions_lock_debug =
124 0, 0, &g_sessions_lock,
125 { &g_sessions_lock_debug.ProcessLocksList, &g_sessions_lock_debug.ProcessLocksList },
126 0, 0, { (DWORD_PTR)(__FILE__ ": g_sessions_lock") }
128 static CRITICAL_SECTION g_sessions_lock = { &g_sessions_lock_debug, -1, 0, 0, 0, 0 };
129 static struct list g_sessions = LIST_INIT(g_sessions);
131 static const WCHAR drv_key_devicesW[] = {'S','o','f','t','w','a','r','e','\\',
132 'W','i','n','e','\\','D','r','i','v','e','r','s','\\',
133 'w','i','n','e','a','l','s','a','.','d','r','v','\\','d','e','v','i','c','e','s',0};
134 static const WCHAR guidW[] = {'g','u','i','d',0};
136 static const IAudioClient3Vtbl AudioClient3_Vtbl;
137 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
138 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
139 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
140 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
141 static const IAudioClockVtbl AudioClock_Vtbl;
142 static const IAudioClock2Vtbl AudioClock2_Vtbl;
143 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
144 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
145 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl;
147 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
149 static inline ACImpl *impl_from_IAudioClient3(IAudioClient3 *iface)
151 return CONTAINING_RECORD(iface, ACImpl, IAudioClient3_iface);
154 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
156 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
159 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
161 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
164 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
166 return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
169 static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
171 return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
174 static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
176 return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
179 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
181 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
184 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
186 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
189 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
191 return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
194 static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface)
196 return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface);
199 BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
201 switch (reason)
203 case DLL_PROCESS_ATTACH:
204 if(__wine_init_unix_call()) return FALSE;
205 break;
207 case DLL_PROCESS_DETACH:
208 if (reserved) break;
209 DeleteCriticalSection(&g_sessions_lock);
210 break;
212 return TRUE;
215 static HRESULT alsa_stream_release(stream_handle stream, HANDLE timer_thread)
217 struct release_stream_params params;
219 params.stream = stream;
220 params.timer_thread = timer_thread;
222 ALSA_CALL(release_stream, &params);
224 return params.result;
227 static DWORD WINAPI alsa_timer_thread(void *user)
229 struct timer_loop_params params;
230 struct ACImpl *This = user;
232 SetThreadDescription(GetCurrentThread(), L"winealsa_timer");
234 params.stream = This->stream;
236 ALSA_CALL(timer_loop, &params);
238 return 0;
241 static void set_device_guid(EDataFlow flow, HKEY drv_key, const WCHAR *key_name,
242 GUID *guid)
244 HKEY key;
245 BOOL opened = FALSE;
246 LONG lr;
248 if(!drv_key){
249 lr = RegCreateKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, NULL, 0, KEY_WRITE,
250 NULL, &drv_key, NULL);
251 if(lr != ERROR_SUCCESS){
252 ERR("RegCreateKeyEx(drv_key) failed: %lu\n", lr);
253 return;
255 opened = TRUE;
258 lr = RegCreateKeyExW(drv_key, key_name, 0, NULL, 0, KEY_WRITE,
259 NULL, &key, NULL);
260 if(lr != ERROR_SUCCESS){
261 ERR("RegCreateKeyEx(%s) failed: %lu\n", wine_dbgstr_w(key_name), lr);
262 goto exit;
265 lr = RegSetValueExW(key, guidW, 0, REG_BINARY, (BYTE*)guid,
266 sizeof(GUID));
267 if(lr != ERROR_SUCCESS)
268 ERR("RegSetValueEx(%s\\guid) failed: %lu\n", wine_dbgstr_w(key_name), lr);
270 RegCloseKey(key);
271 exit:
272 if(opened)
273 RegCloseKey(drv_key);
276 static void get_device_guid(EDataFlow flow, const char *device, GUID *guid)
278 HKEY key = NULL, dev_key;
279 DWORD type, size = sizeof(*guid);
280 WCHAR key_name[256];
282 if(flow == eCapture)
283 key_name[0] = '1';
284 else
285 key_name[0] = '0';
286 key_name[1] = ',';
287 MultiByteToWideChar(CP_UNIXCP, 0, device, -1, key_name + 2, ARRAY_SIZE(key_name) - 2);
289 if(RegOpenKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, KEY_WRITE|KEY_READ, &key) == ERROR_SUCCESS){
290 if(RegOpenKeyExW(key, key_name, 0, KEY_READ, &dev_key) == ERROR_SUCCESS){
291 if(RegQueryValueExW(dev_key, guidW, 0, &type,
292 (BYTE*)guid, &size) == ERROR_SUCCESS){
293 if(type == REG_BINARY){
294 RegCloseKey(dev_key);
295 RegCloseKey(key);
296 return;
298 ERR("Invalid type for device %s GUID: %lu; ignoring and overwriting\n",
299 wine_dbgstr_w(key_name), type);
301 RegCloseKey(dev_key);
305 CoCreateGuid(guid);
307 set_device_guid(flow, key, key_name, guid);
309 if(key)
310 RegCloseKey(key);
313 static void set_stream_volumes(ACImpl *This)
315 struct set_volumes_params params;
317 params.stream = This->stream;
318 params.master_volume = (This->session->mute ? 0.0f : This->session->master_vol);
319 params.volumes = This->vols;
320 params.session_volumes = This->session->channel_vols;
321 params.channel = 0;
323 ALSA_CALL(set_volumes, &params);
326 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids_out, GUID **guids_out,
327 UINT *num, UINT *def_index)
329 struct get_endpoint_ids_params params;
330 unsigned int i;
331 GUID *guids = NULL;
332 WCHAR **ids = NULL;
334 TRACE("%d %p %p %p %p\n", flow, ids, guids, num, def_index);
336 params.flow = flow;
337 params.size = 1000;
338 params.endpoints = NULL;
340 HeapFree(GetProcessHeap(), 0, params.endpoints);
341 params.endpoints = HeapAlloc(GetProcessHeap(), 0, params.size);
342 ALSA_CALL(get_endpoint_ids, &params);
343 }while(params.result == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
345 if(FAILED(params.result)) goto end;
347 ids = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, params.num * sizeof(*ids));
348 guids = HeapAlloc(GetProcessHeap(), 0, params.num * sizeof(*guids));
349 if(!ids || !guids){
350 params.result = E_OUTOFMEMORY;
351 goto end;
354 for(i = 0; i < params.num; i++){
355 WCHAR *name = (WCHAR *)((char *)params.endpoints + params.endpoints[i].name);
356 char *device = (char *)params.endpoints + params.endpoints[i].device;
357 unsigned int size = (wcslen(name) + 1) * sizeof(WCHAR);
359 ids[i] = HeapAlloc(GetProcessHeap(), 0, size);
360 if(!ids[i]){
361 params.result = E_OUTOFMEMORY;
362 goto end;
364 memcpy(ids[i], name, size);
365 get_device_guid(flow, device, guids + i);
367 *def_index = params.default_idx;
369 end:
370 HeapFree(GetProcessHeap(), 0, params.endpoints);
371 if(FAILED(params.result)){
372 HeapFree(GetProcessHeap(), 0, guids);
373 if(ids){
374 for(i = 0; i < params.num; i++)
375 HeapFree(GetProcessHeap(), 0, ids[i]);
376 HeapFree(GetProcessHeap(), 0, ids);
378 }else{
379 *ids_out = ids;
380 *guids_out = guids;
381 *num = params.num;
384 return params.result;
387 static BOOL get_alsa_name_by_guid(GUID *guid, char *name, DWORD name_size, EDataFlow *flow)
389 HKEY devices_key;
390 UINT i = 0;
391 WCHAR key_name[256];
392 DWORD key_name_size;
394 if(RegOpenKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, KEY_READ, &devices_key) != ERROR_SUCCESS){
395 ERR("No devices found in registry?\n");
396 return FALSE;
399 while(1){
400 HKEY key;
401 DWORD size, type;
402 GUID reg_guid;
404 key_name_size = ARRAY_SIZE(key_name);
405 if(RegEnumKeyExW(devices_key, i++, key_name, &key_name_size, NULL,
406 NULL, NULL, NULL) != ERROR_SUCCESS)
407 break;
409 if(RegOpenKeyExW(devices_key, key_name, 0, KEY_READ, &key) != ERROR_SUCCESS){
410 WARN("Couldn't open key: %s\n", wine_dbgstr_w(key_name));
411 continue;
414 size = sizeof(reg_guid);
415 if(RegQueryValueExW(key, guidW, 0, &type,
416 (BYTE*)&reg_guid, &size) == ERROR_SUCCESS){
417 if(IsEqualGUID(&reg_guid, guid)){
418 RegCloseKey(key);
419 RegCloseKey(devices_key);
421 TRACE("Found matching device key: %s\n", wine_dbgstr_w(key_name));
423 if(key_name[0] == '0')
424 *flow = eRender;
425 else if(key_name[0] == '1')
426 *flow = eCapture;
427 else{
428 ERR("Unknown device type: %c\n", key_name[0]);
429 return FALSE;
432 WideCharToMultiByte(CP_UNIXCP, 0, key_name + 2, -1, name, name_size, NULL, NULL);
434 return TRUE;
438 RegCloseKey(key);
441 RegCloseKey(devices_key);
443 WARN("No matching device in registry for GUID %s\n", debugstr_guid(guid));
445 return FALSE;
448 HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient **out)
450 ACImpl *This;
451 char alsa_name[256];
452 EDataFlow dataflow;
453 HRESULT hr;
454 int len;
456 TRACE("%s %p %p\n", debugstr_guid(guid), dev, out);
458 if(!get_alsa_name_by_guid(guid, alsa_name, sizeof(alsa_name), &dataflow))
459 return AUDCLNT_E_DEVICE_INVALIDATED;
461 if(dataflow != eRender && dataflow != eCapture)
462 return E_UNEXPECTED;
464 len = strlen(alsa_name);
465 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, offsetof(ACImpl, alsa_name[len + 1]));
466 if(!This)
467 return E_OUTOFMEMORY;
469 This->IAudioClient3_iface.lpVtbl = &AudioClient3_Vtbl;
470 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
471 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
472 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
473 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
474 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
476 hr = CoCreateFreeThreadedMarshaler((IUnknown *)&This->IAudioClient3_iface, &This->pUnkFTMarshal);
477 if (FAILED(hr)) {
478 HeapFree(GetProcessHeap(), 0, This);
479 return hr;
482 This->dataflow = dataflow;
483 memcpy(This->alsa_name, alsa_name, len + 1);
485 This->parent = dev;
486 IMMDevice_AddRef(This->parent);
488 *out = (IAudioClient *)&This->IAudioClient3_iface;
489 IAudioClient3_AddRef(&This->IAudioClient3_iface);
491 return S_OK;
494 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient3 *iface,
495 REFIID riid, void **ppv)
497 ACImpl *This = impl_from_IAudioClient3(iface);
498 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
500 if(!ppv)
501 return E_POINTER;
502 *ppv = NULL;
503 if(IsEqualIID(riid, &IID_IUnknown) ||
504 IsEqualIID(riid, &IID_IAudioClient) ||
505 IsEqualIID(riid, &IID_IAudioClient2) ||
506 IsEqualIID(riid, &IID_IAudioClient3))
507 *ppv = iface;
508 else if(IsEqualIID(riid, &IID_IMarshal))
509 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
511 if(*ppv){
512 IUnknown_AddRef((IUnknown*)*ppv);
513 return S_OK;
515 WARN("Unknown interface %s\n", debugstr_guid(riid));
516 return E_NOINTERFACE;
519 static ULONG WINAPI AudioClient_AddRef(IAudioClient3 *iface)
521 ACImpl *This = impl_from_IAudioClient3(iface);
522 ULONG ref;
523 ref = InterlockedIncrement(&This->ref);
524 TRACE("(%p) Refcount now %lu\n", This, ref);
525 return ref;
528 static ULONG WINAPI AudioClient_Release(IAudioClient3 *iface)
530 ACImpl *This = impl_from_IAudioClient3(iface);
531 ULONG ref;
533 ref = InterlockedDecrement(&This->ref);
534 TRACE("(%p) Refcount now %lu\n", This, ref);
535 if(!ref){
536 IAudioClient3_Stop(iface);
537 IMMDevice_Release(This->parent);
538 IUnknown_Release(This->pUnkFTMarshal);
539 if(This->session){
540 EnterCriticalSection(&g_sessions_lock);
541 list_remove(&This->entry);
542 LeaveCriticalSection(&g_sessions_lock);
544 HeapFree(GetProcessHeap(), 0, This->vols);
545 if (This->stream)
546 alsa_stream_release(This->stream, This->timer_thread);
547 HeapFree(GetProcessHeap(), 0, This);
549 return ref;
552 static void dump_fmt(const WAVEFORMATEX *fmt)
554 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
555 switch(fmt->wFormatTag){
556 case WAVE_FORMAT_PCM:
557 TRACE("WAVE_FORMAT_PCM");
558 break;
559 case WAVE_FORMAT_IEEE_FLOAT:
560 TRACE("WAVE_FORMAT_IEEE_FLOAT");
561 break;
562 case WAVE_FORMAT_EXTENSIBLE:
563 TRACE("WAVE_FORMAT_EXTENSIBLE");
564 break;
565 default:
566 TRACE("Unknown");
567 break;
569 TRACE(")\n");
571 TRACE("nChannels: %u\n", fmt->nChannels);
572 TRACE("nSamplesPerSec: %lu\n", fmt->nSamplesPerSec);
573 TRACE("nAvgBytesPerSec: %lu\n", fmt->nAvgBytesPerSec);
574 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
575 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
576 TRACE("cbSize: %u\n", fmt->cbSize);
578 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
579 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
580 TRACE("dwChannelMask: %08lx\n", fmtex->dwChannelMask);
581 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
582 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
586 static void session_init_vols(AudioSession *session, UINT channels)
588 if(session->channel_count < channels){
589 UINT i;
591 if(session->channel_vols)
592 session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
593 session->channel_vols, sizeof(float) * channels);
594 else
595 session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
596 sizeof(float) * channels);
597 if(!session->channel_vols)
598 return;
600 for(i = session->channel_count; i < channels; ++i)
601 session->channel_vols[i] = 1.f;
603 session->channel_count = channels;
607 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
608 UINT num_channels)
610 AudioSession *ret;
612 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
613 if(!ret)
614 return NULL;
616 memcpy(&ret->guid, guid, sizeof(GUID));
618 ret->device = device;
620 list_init(&ret->clients);
622 list_add_head(&g_sessions, &ret->entry);
624 session_init_vols(ret, num_channels);
626 ret->master_vol = 1.f;
628 return ret;
631 /* if channels == 0, then this will return or create a session with
632 * matching dataflow and GUID. otherwise, channels must also match */
633 static HRESULT get_audio_session(const GUID *sessionguid,
634 IMMDevice *device, UINT channels, AudioSession **out)
636 AudioSession *session;
638 if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
639 *out = create_session(&GUID_NULL, device, channels);
640 if(!*out)
641 return E_OUTOFMEMORY;
643 return S_OK;
646 *out = NULL;
647 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
648 if(session->device == device &&
649 IsEqualGUID(sessionguid, &session->guid)){
650 session_init_vols(session, channels);
651 *out = session;
652 break;
656 if(!*out){
657 *out = create_session(sessionguid, device, channels);
658 if(!*out)
659 return E_OUTOFMEMORY;
662 return S_OK;
665 static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
666 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
667 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
668 const GUID *sessionguid)
670 ACImpl *This = impl_from_IAudioClient3(iface);
671 struct create_stream_params params;
672 stream_handle stream;
673 unsigned int i;
675 TRACE("(%p)->(%x, %lx, %s, %s, %p, %s)\n", This, mode, flags,
676 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
678 if(!fmt)
679 return E_POINTER;
681 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
682 return E_INVALIDARG;
684 if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
685 AUDCLNT_STREAMFLAGS_LOOPBACK |
686 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
687 AUDCLNT_STREAMFLAGS_NOPERSIST |
688 AUDCLNT_STREAMFLAGS_RATEADJUST |
689 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
690 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
691 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED |
692 AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY |
693 AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM)){
694 FIXME("Unknown flags: %08lx\n", flags);
695 return E_INVALIDARG;
698 if(mode == AUDCLNT_SHAREMODE_SHARED){
699 period = DefaultPeriod;
700 if( duration < 3 * period)
701 duration = 3 * period;
702 }else{
703 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
704 if(((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask == 0 ||
705 ((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask & SPEAKER_RESERVED)
706 return AUDCLNT_E_UNSUPPORTED_FORMAT;
709 if(!period)
710 period = DefaultPeriod; /* not minimum */
711 if(period < MinimumPeriod || period > 5000000)
712 return AUDCLNT_E_INVALID_DEVICE_PERIOD;
713 if(duration > 20000000) /* the smaller the period, the lower this limit */
714 return AUDCLNT_E_BUFFER_SIZE_ERROR;
715 if(flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK){
716 if(duration != period)
717 return AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL;
718 FIXME("EXCLUSIVE mode with EVENTCALLBACK\n");
719 return AUDCLNT_E_DEVICE_IN_USE;
720 }else{
721 if( duration < 8 * period)
722 duration = 8 * period; /* may grow above 2s */
726 EnterCriticalSection(&g_sessions_lock);
728 if(This->stream){
729 LeaveCriticalSection(&g_sessions_lock);
730 return AUDCLNT_E_ALREADY_INITIALIZED;
733 dump_fmt(fmt);
735 params.name = NULL;
736 params.device = This->alsa_name;
737 params.flow = This->dataflow;
738 params.share = mode;
739 params.flags = flags;
740 params.duration = duration;
741 params.period = period;
742 params.fmt = fmt;
743 params.channel_count = NULL;
744 params.stream = &stream;
746 ALSA_CALL(create_stream, &params);
747 if(FAILED(params.result)){
748 LeaveCriticalSection(&g_sessions_lock);
749 return params.result;
752 This->channel_count = fmt->nChannels;
753 This->vols = HeapAlloc(GetProcessHeap(), 0, This->channel_count * sizeof(float));
754 if(!This->vols){
755 params.result = E_OUTOFMEMORY;
756 goto exit;
758 for(i = 0; i < This->channel_count; ++i)
759 This->vols[i] = 1.f;
761 params.result = get_audio_session(sessionguid, This->parent, This->channel_count,
762 &This->session);
763 if(FAILED(params.result))
764 goto exit;
766 list_add_tail(&This->session->clients, &This->entry);
768 exit:
769 if(FAILED(params.result)){
770 alsa_stream_release(stream, NULL);
771 HeapFree(GetProcessHeap(), 0, This->vols);
772 This->vols = NULL;
773 }else{
774 This->stream = stream;
775 set_stream_volumes(This);
778 LeaveCriticalSection(&g_sessions_lock);
780 return params.result;
783 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient3 *iface,
784 UINT32 *out)
786 ACImpl *This = impl_from_IAudioClient3(iface);
787 struct get_buffer_size_params params;
789 TRACE("(%p)->(%p)\n", This, out);
791 if(!out)
792 return E_POINTER;
794 if(!This->stream)
795 return AUDCLNT_E_NOT_INITIALIZED;
797 params.stream = This->stream;
798 params.frames = out;
800 ALSA_CALL(get_buffer_size, &params);
802 return params.result;
805 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient3 *iface,
806 REFERENCE_TIME *latency)
808 ACImpl *This = impl_from_IAudioClient3(iface);
809 struct get_latency_params params;
811 TRACE("(%p)->(%p)\n", This, latency);
813 if(!latency)
814 return E_POINTER;
816 if(!This->stream)
817 return AUDCLNT_E_NOT_INITIALIZED;
819 params.stream = This->stream;
820 params.latency = latency;
822 ALSA_CALL(get_latency, &params);
824 return params.result;
827 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient3 *iface,
828 UINT32 *out)
830 ACImpl *This = impl_from_IAudioClient3(iface);
831 struct get_current_padding_params params;
833 TRACE("(%p)->(%p)\n", This, out);
835 if(!out)
836 return E_POINTER;
838 if(!This->stream)
839 return AUDCLNT_E_NOT_INITIALIZED;
841 params.stream = This->stream;
842 params.padding = out;
844 ALSA_CALL(get_current_padding, &params);
846 TRACE("pad: %u\n", *out);
848 return params.result;
851 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient3 *iface,
852 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *fmt,
853 WAVEFORMATEX **out)
855 ACImpl *This = impl_from_IAudioClient3(iface);
856 struct is_format_supported_params params;
858 TRACE("(%p)->(%x, %p, %p)\n", This, mode, fmt, out);
859 if(fmt) dump_fmt(fmt);
861 params.device = This->alsa_name;
862 params.flow = This->dataflow;
863 params.share = mode;
864 params.fmt_in = fmt;
865 params.fmt_out = NULL;
867 if(out){
868 *out = NULL;
869 if(mode == AUDCLNT_SHAREMODE_SHARED)
870 params.fmt_out = CoTaskMemAlloc(sizeof(*params.fmt_out));
872 ALSA_CALL(is_format_supported, &params);
874 if(params.result == S_FALSE)
875 *out = &params.fmt_out->Format;
876 else
877 CoTaskMemFree(params.fmt_out);
879 return params.result;
882 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface,
883 WAVEFORMATEX **pwfx)
885 ACImpl *This = impl_from_IAudioClient3(iface);
886 struct get_mix_format_params params;
888 TRACE("(%p)->(%p)\n", This, pwfx);
890 if(!pwfx)
891 return E_POINTER;
892 *pwfx = NULL;
894 params.device = This->alsa_name;
895 params.flow = This->dataflow;
896 params.fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
897 if(!params.fmt)
898 return E_OUTOFMEMORY;
900 ALSA_CALL(get_mix_format, &params);
902 if(SUCCEEDED(params.result)){
903 *pwfx = &params.fmt->Format;
904 dump_fmt(*pwfx);
905 } else
906 CoTaskMemFree(params.fmt);
908 return params.result;
911 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient3 *iface,
912 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
914 ACImpl *This = impl_from_IAudioClient3(iface);
916 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
918 if(!defperiod && !minperiod)
919 return E_POINTER;
921 if(defperiod)
922 *defperiod = DefaultPeriod;
923 if(minperiod)
924 *minperiod = DefaultPeriod;
926 return S_OK;
929 static HRESULT WINAPI AudioClient_Start(IAudioClient3 *iface)
931 ACImpl *This = impl_from_IAudioClient3(iface);
932 struct start_params params;
934 TRACE("(%p)\n", This);
936 EnterCriticalSection(&g_sessions_lock);
938 if(!This->stream){
939 LeaveCriticalSection(&g_sessions_lock);
940 return AUDCLNT_E_NOT_INITIALIZED;
943 params.stream = This->stream;
945 ALSA_CALL(start, &params);
947 if(SUCCEEDED(params.result) && !This->timer_thread){
948 This->timer_thread = CreateThread(NULL, 0, alsa_timer_thread, This, 0, NULL);
949 SetThreadPriority(This->timer_thread, THREAD_PRIORITY_TIME_CRITICAL);
952 LeaveCriticalSection(&g_sessions_lock);
954 return params.result;
957 static HRESULT WINAPI AudioClient_Stop(IAudioClient3 *iface)
959 ACImpl *This = impl_from_IAudioClient3(iface);
960 struct stop_params params;
962 TRACE("(%p)\n", This);
964 if(!This->stream)
965 return AUDCLNT_E_NOT_INITIALIZED;
967 params.stream = This->stream;
969 ALSA_CALL(stop, &params);
971 return params.result;
974 static HRESULT WINAPI AudioClient_Reset(IAudioClient3 *iface)
976 ACImpl *This = impl_from_IAudioClient3(iface);
977 struct reset_params params;
979 TRACE("(%p)\n", This);
981 if(!This->stream)
982 return AUDCLNT_E_NOT_INITIALIZED;
984 params.stream = This->stream;
986 ALSA_CALL(reset, &params);
988 return params.result;
991 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient3 *iface,
992 HANDLE event)
994 ACImpl *This = impl_from_IAudioClient3(iface);
995 struct set_event_handle_params params;
997 TRACE("(%p)->(%p)\n", This, event);
999 if(!event)
1000 return E_INVALIDARG;
1002 if(!This->stream)
1003 return AUDCLNT_E_NOT_INITIALIZED;
1005 params.stream = This->stream;
1006 params.event = event;
1008 ALSA_CALL(set_event_handle, &params);
1010 return params.result;
1013 static HRESULT WINAPI AudioClient_GetService(IAudioClient3 *iface, REFIID riid,
1014 void **ppv)
1016 ACImpl *This = impl_from_IAudioClient3(iface);
1018 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1020 if(!ppv)
1021 return E_POINTER;
1022 *ppv = NULL;
1024 EnterCriticalSection(&g_sessions_lock);
1026 if(!This->stream){
1027 LeaveCriticalSection(&g_sessions_lock);
1028 return AUDCLNT_E_NOT_INITIALIZED;
1031 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1032 if(This->dataflow != eRender){
1033 LeaveCriticalSection(&g_sessions_lock);
1034 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1036 IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
1037 *ppv = &This->IAudioRenderClient_iface;
1038 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1039 if(This->dataflow != eCapture){
1040 LeaveCriticalSection(&g_sessions_lock);
1041 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1043 IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
1044 *ppv = &This->IAudioCaptureClient_iface;
1045 }else if(IsEqualIID(riid, &IID_IAudioClock)){
1046 IAudioClock_AddRef(&This->IAudioClock_iface);
1047 *ppv = &This->IAudioClock_iface;
1048 }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1049 IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
1050 *ppv = &This->IAudioStreamVolume_iface;
1051 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1052 if(!This->session_wrapper){
1053 This->session_wrapper = AudioSessionWrapper_Create(This);
1054 if(!This->session_wrapper){
1055 LeaveCriticalSection(&g_sessions_lock);
1056 return E_OUTOFMEMORY;
1058 }else
1059 IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
1061 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1062 }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1063 if(!This->session_wrapper){
1064 This->session_wrapper = AudioSessionWrapper_Create(This);
1065 if(!This->session_wrapper){
1066 LeaveCriticalSection(&g_sessions_lock);
1067 return E_OUTOFMEMORY;
1069 }else
1070 IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
1072 *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1073 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1074 if(!This->session_wrapper){
1075 This->session_wrapper = AudioSessionWrapper_Create(This);
1076 if(!This->session_wrapper){
1077 LeaveCriticalSection(&g_sessions_lock);
1078 return E_OUTOFMEMORY;
1080 }else
1081 ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
1083 *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1086 if(*ppv){
1087 LeaveCriticalSection(&g_sessions_lock);
1088 return S_OK;
1091 LeaveCriticalSection(&g_sessions_lock);
1093 FIXME("stub %s\n", debugstr_guid(riid));
1094 return E_NOINTERFACE;
1097 static HRESULT WINAPI AudioClient_IsOffloadCapable(IAudioClient3 *iface,
1098 AUDIO_STREAM_CATEGORY category, BOOL *offload_capable)
1100 ACImpl *This = impl_from_IAudioClient3(iface);
1102 TRACE("(%p)->(0x%x, %p)\n", This, category, offload_capable);
1104 if(!offload_capable)
1105 return E_INVALIDARG;
1107 *offload_capable = FALSE;
1109 return S_OK;
1112 static HRESULT WINAPI AudioClient_SetClientProperties(IAudioClient3 *iface,
1113 const AudioClientProperties *prop)
1115 ACImpl *This = impl_from_IAudioClient3(iface);
1116 const Win8AudioClientProperties *legacy_prop = (const Win8AudioClientProperties *)prop;
1118 TRACE("(%p)->(%p)\n", This, prop);
1120 if(!legacy_prop)
1121 return E_POINTER;
1123 if(legacy_prop->cbSize == sizeof(AudioClientProperties)){
1124 TRACE("{ bIsOffload: %u, eCategory: 0x%x, Options: 0x%x }\n",
1125 legacy_prop->bIsOffload,
1126 legacy_prop->eCategory,
1127 prop->Options);
1128 }else if(legacy_prop->cbSize == sizeof(Win8AudioClientProperties)){
1129 TRACE("{ bIsOffload: %u, eCategory: 0x%x }\n",
1130 legacy_prop->bIsOffload,
1131 legacy_prop->eCategory);
1132 }else{
1133 WARN("Unsupported Size = %d\n", legacy_prop->cbSize);
1134 return E_INVALIDARG;
1138 if(legacy_prop->bIsOffload)
1139 return AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE;
1141 return S_OK;
1144 static HRESULT WINAPI AudioClient_GetBufferSizeLimits(IAudioClient3 *iface,
1145 const WAVEFORMATEX *format, BOOL event_driven, REFERENCE_TIME *min_duration,
1146 REFERENCE_TIME *max_duration)
1148 ACImpl *This = impl_from_IAudioClient3(iface);
1150 FIXME("(%p)->(%p, %u, %p, %p)\n", This, format, event_driven, min_duration, max_duration);
1152 return E_NOTIMPL;
1155 static HRESULT WINAPI AudioClient_GetSharedModeEnginePeriod(IAudioClient3 *iface,
1156 const WAVEFORMATEX *format, UINT32 *default_period_frames, UINT32 *unit_period_frames,
1157 UINT32 *min_period_frames, UINT32 *max_period_frames)
1159 ACImpl *This = impl_from_IAudioClient3(iface);
1161 FIXME("(%p)->(%p, %p, %p, %p, %p)\n", This, format, default_period_frames, unit_period_frames,
1162 min_period_frames, max_period_frames);
1164 return E_NOTIMPL;
1167 static HRESULT WINAPI AudioClient_GetCurrentSharedModeEnginePeriod(IAudioClient3 *iface,
1168 WAVEFORMATEX **cur_format, UINT32 *cur_period_frames)
1170 ACImpl *This = impl_from_IAudioClient3(iface);
1172 FIXME("(%p)->(%p, %p)\n", This, cur_format, cur_period_frames);
1174 return E_NOTIMPL;
1177 static HRESULT WINAPI AudioClient_InitializeSharedAudioStream(IAudioClient3 *iface,
1178 DWORD flags, UINT32 period_frames, const WAVEFORMATEX *format,
1179 const GUID *session_guid)
1181 ACImpl *This = impl_from_IAudioClient3(iface);
1183 FIXME("(%p)->(0x%lx, %u, %p, %s)\n", This, flags, period_frames, format, debugstr_guid(session_guid));
1185 return E_NOTIMPL;
1188 static const IAudioClient3Vtbl AudioClient3_Vtbl =
1190 AudioClient_QueryInterface,
1191 AudioClient_AddRef,
1192 AudioClient_Release,
1193 AudioClient_Initialize,
1194 AudioClient_GetBufferSize,
1195 AudioClient_GetStreamLatency,
1196 AudioClient_GetCurrentPadding,
1197 AudioClient_IsFormatSupported,
1198 AudioClient_GetMixFormat,
1199 AudioClient_GetDevicePeriod,
1200 AudioClient_Start,
1201 AudioClient_Stop,
1202 AudioClient_Reset,
1203 AudioClient_SetEventHandle,
1204 AudioClient_GetService,
1205 AudioClient_IsOffloadCapable,
1206 AudioClient_SetClientProperties,
1207 AudioClient_GetBufferSizeLimits,
1208 AudioClient_GetSharedModeEnginePeriod,
1209 AudioClient_GetCurrentSharedModeEnginePeriod,
1210 AudioClient_InitializeSharedAudioStream,
1213 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1214 IAudioRenderClient *iface, REFIID riid, void **ppv)
1216 ACImpl *This = impl_from_IAudioRenderClient(iface);
1217 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1219 if(!ppv)
1220 return E_POINTER;
1221 *ppv = NULL;
1223 if(IsEqualIID(riid, &IID_IUnknown) ||
1224 IsEqualIID(riid, &IID_IAudioRenderClient))
1225 *ppv = iface;
1226 else if(IsEqualIID(riid, &IID_IMarshal))
1227 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
1229 if(*ppv){
1230 IUnknown_AddRef((IUnknown*)*ppv);
1231 return S_OK;
1234 WARN("Unknown interface %s\n", debugstr_guid(riid));
1235 return E_NOINTERFACE;
1238 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1240 ACImpl *This = impl_from_IAudioRenderClient(iface);
1241 return AudioClient_AddRef(&This->IAudioClient3_iface);
1244 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1246 ACImpl *This = impl_from_IAudioRenderClient(iface);
1247 return AudioClient_Release(&This->IAudioClient3_iface);
1250 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1251 UINT32 frames, BYTE **data)
1253 ACImpl *This = impl_from_IAudioRenderClient(iface);
1254 struct get_render_buffer_params params;
1256 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1258 if(!data)
1259 return E_POINTER;
1260 *data = NULL;
1262 params.stream = This->stream;
1263 params.frames = frames;
1264 params.data = data;
1266 ALSA_CALL(get_render_buffer, &params);
1268 return params.result;
1271 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1272 IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
1274 ACImpl *This = impl_from_IAudioRenderClient(iface);
1275 struct release_render_buffer_params params;
1277 TRACE("(%p)->(%u, %lx)\n", This, written_frames, flags);
1279 params.stream = This->stream;
1280 params.written_frames = written_frames;
1281 params.flags = flags;
1283 ALSA_CALL(release_render_buffer, &params);
1285 return params.result;
1288 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1289 AudioRenderClient_QueryInterface,
1290 AudioRenderClient_AddRef,
1291 AudioRenderClient_Release,
1292 AudioRenderClient_GetBuffer,
1293 AudioRenderClient_ReleaseBuffer
1296 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1297 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1299 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1300 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1302 if(!ppv)
1303 return E_POINTER;
1304 *ppv = NULL;
1306 if(IsEqualIID(riid, &IID_IUnknown) ||
1307 IsEqualIID(riid, &IID_IAudioCaptureClient))
1308 *ppv = iface;
1309 else if(IsEqualIID(riid, &IID_IMarshal))
1310 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
1312 if(*ppv){
1313 IUnknown_AddRef((IUnknown*)*ppv);
1314 return S_OK;
1317 WARN("Unknown interface %s\n", debugstr_guid(riid));
1318 return E_NOINTERFACE;
1321 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1323 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1324 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1327 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1329 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1330 return IAudioClient3_Release(&This->IAudioClient3_iface);
1333 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1334 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1335 UINT64 *qpcpos)
1337 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1338 struct get_capture_buffer_params params;
1340 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1341 devpos, qpcpos);
1343 if(!data)
1344 return E_POINTER;
1346 *data = NULL;
1348 if(!frames || !flags)
1349 return E_POINTER;
1351 params.stream = This->stream;
1352 params.data = data;
1353 params.frames = frames;
1354 params.flags = (UINT*)flags;
1355 params.devpos = devpos;
1356 params.qpcpos = qpcpos;
1358 ALSA_CALL(get_capture_buffer, &params);
1360 return params.result;
1363 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1364 IAudioCaptureClient *iface, UINT32 done)
1366 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1367 struct release_capture_buffer_params params;
1369 TRACE("(%p)->(%u)\n", This, done);
1371 params.stream = This->stream;
1372 params.done = done;
1374 ALSA_CALL(release_capture_buffer, &params);
1376 return params.result;
1379 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1380 IAudioCaptureClient *iface, UINT32 *frames)
1382 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1383 struct get_next_packet_size_params params;
1385 TRACE("(%p)->(%p)\n", This, frames);
1387 if(!frames)
1388 return E_POINTER;
1390 params.stream = This->stream;
1391 params.frames = frames;
1393 ALSA_CALL(get_next_packet_size, &params);
1395 return params.result;
1398 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1400 AudioCaptureClient_QueryInterface,
1401 AudioCaptureClient_AddRef,
1402 AudioCaptureClient_Release,
1403 AudioCaptureClient_GetBuffer,
1404 AudioCaptureClient_ReleaseBuffer,
1405 AudioCaptureClient_GetNextPacketSize
1408 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1409 REFIID riid, void **ppv)
1411 ACImpl *This = impl_from_IAudioClock(iface);
1413 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1415 if(!ppv)
1416 return E_POINTER;
1417 *ppv = NULL;
1419 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
1420 *ppv = iface;
1421 else if(IsEqualIID(riid, &IID_IAudioClock2))
1422 *ppv = &This->IAudioClock2_iface;
1423 if(*ppv){
1424 IUnknown_AddRef((IUnknown*)*ppv);
1425 return S_OK;
1428 WARN("Unknown interface %s\n", debugstr_guid(riid));
1429 return E_NOINTERFACE;
1432 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
1434 ACImpl *This = impl_from_IAudioClock(iface);
1435 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1438 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
1440 ACImpl *This = impl_from_IAudioClock(iface);
1441 return IAudioClient3_Release(&This->IAudioClient3_iface);
1444 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
1446 ACImpl *This = impl_from_IAudioClock(iface);
1447 struct get_frequency_params params;
1449 TRACE("(%p)->(%p)\n", This, freq);
1451 params.stream = This->stream;
1452 params.freq = freq;
1454 ALSA_CALL(get_frequency, &params);
1456 return params.result;
1459 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
1460 UINT64 *qpctime)
1462 ACImpl *This = impl_from_IAudioClock(iface);
1463 struct get_position_params params;
1465 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
1467 if(!pos)
1468 return E_POINTER;
1470 params.stream = This->stream;
1471 params.device = FALSE;
1472 params.pos = pos;
1473 params.qpctime = qpctime;
1475 ALSA_CALL(get_position, &params);
1477 return params.result;
1480 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
1481 DWORD *chars)
1483 ACImpl *This = impl_from_IAudioClock(iface);
1485 TRACE("(%p)->(%p)\n", This, chars);
1487 if(!chars)
1488 return E_POINTER;
1490 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
1492 return S_OK;
1495 static const IAudioClockVtbl AudioClock_Vtbl =
1497 AudioClock_QueryInterface,
1498 AudioClock_AddRef,
1499 AudioClock_Release,
1500 AudioClock_GetFrequency,
1501 AudioClock_GetPosition,
1502 AudioClock_GetCharacteristics
1505 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
1506 REFIID riid, void **ppv)
1508 ACImpl *This = impl_from_IAudioClock2(iface);
1509 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
1512 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
1514 ACImpl *This = impl_from_IAudioClock2(iface);
1515 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1518 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
1520 ACImpl *This = impl_from_IAudioClock2(iface);
1521 return IAudioClient3_Release(&This->IAudioClient3_iface);
1524 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
1525 UINT64 *pos, UINT64 *qpctime)
1527 ACImpl *This = impl_from_IAudioClock2(iface);
1529 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
1531 return E_NOTIMPL;
1534 static const IAudioClock2Vtbl AudioClock2_Vtbl =
1536 AudioClock2_QueryInterface,
1537 AudioClock2_AddRef,
1538 AudioClock2_Release,
1539 AudioClock2_GetDevicePosition
1542 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
1544 AudioSessionWrapper *ret;
1546 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1547 sizeof(AudioSessionWrapper));
1548 if(!ret)
1549 return NULL;
1551 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
1552 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
1553 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
1555 ret->ref = 1;
1557 ret->client = client;
1558 if(client){
1559 ret->session = client->session;
1560 AudioClient_AddRef(&client->IAudioClient3_iface);
1563 return ret;
1566 static HRESULT WINAPI AudioSessionControl_QueryInterface(
1567 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
1569 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1571 if(!ppv)
1572 return E_POINTER;
1573 *ppv = NULL;
1575 if(IsEqualIID(riid, &IID_IUnknown) ||
1576 IsEqualIID(riid, &IID_IAudioSessionControl) ||
1577 IsEqualIID(riid, &IID_IAudioSessionControl2))
1578 *ppv = iface;
1579 if(*ppv){
1580 IUnknown_AddRef((IUnknown*)*ppv);
1581 return S_OK;
1584 WARN("Unknown interface %s\n", debugstr_guid(riid));
1585 return E_NOINTERFACE;
1588 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
1590 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1591 ULONG ref;
1592 ref = InterlockedIncrement(&This->ref);
1593 TRACE("(%p) Refcount now %lu\n", This, ref);
1594 return ref;
1597 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
1599 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1600 ULONG ref;
1601 ref = InterlockedDecrement(&This->ref);
1602 TRACE("(%p) Refcount now %lu\n", This, ref);
1603 if(!ref){
1604 if(This->client){
1605 EnterCriticalSection(&g_sessions_lock);
1606 This->client->session_wrapper = NULL;
1607 LeaveCriticalSection(&g_sessions_lock);
1608 AudioClient_Release(&This->client->IAudioClient3_iface);
1610 HeapFree(GetProcessHeap(), 0, This);
1612 return ref;
1615 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
1616 AudioSessionState *state)
1618 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1619 struct is_started_params params;
1620 ACImpl *client;
1622 TRACE("(%p)->(%p)\n", This, state);
1624 if(!state)
1625 return NULL_PTR_ERR;
1627 EnterCriticalSection(&g_sessions_lock);
1629 if(list_empty(&This->session->clients)){
1630 *state = AudioSessionStateExpired;
1631 LeaveCriticalSection(&g_sessions_lock);
1632 return S_OK;
1635 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
1636 params.stream = client->stream;
1637 ALSA_CALL(is_started, &params);
1638 if(params.result == S_OK){
1639 *state = AudioSessionStateActive;
1640 LeaveCriticalSection(&g_sessions_lock);
1641 return S_OK;
1645 LeaveCriticalSection(&g_sessions_lock);
1647 *state = AudioSessionStateInactive;
1649 return S_OK;
1652 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
1653 IAudioSessionControl2 *iface, WCHAR **name)
1655 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1657 FIXME("(%p)->(%p) - stub\n", This, name);
1659 return E_NOTIMPL;
1662 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
1663 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
1665 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1667 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
1669 return E_NOTIMPL;
1672 static HRESULT WINAPI AudioSessionControl_GetIconPath(
1673 IAudioSessionControl2 *iface, WCHAR **path)
1675 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1677 FIXME("(%p)->(%p) - stub\n", This, path);
1679 return E_NOTIMPL;
1682 static HRESULT WINAPI AudioSessionControl_SetIconPath(
1683 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
1685 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1687 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
1689 return E_NOTIMPL;
1692 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
1693 IAudioSessionControl2 *iface, GUID *group)
1695 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1697 FIXME("(%p)->(%p) - stub\n", This, group);
1699 return E_NOTIMPL;
1702 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
1703 IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
1705 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1707 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
1708 debugstr_guid(session));
1710 return E_NOTIMPL;
1713 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
1714 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
1716 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1718 FIXME("(%p)->(%p) - stub\n", This, events);
1720 return S_OK;
1723 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
1724 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
1726 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1728 FIXME("(%p)->(%p) - stub\n", This, events);
1730 return S_OK;
1733 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
1734 IAudioSessionControl2 *iface, WCHAR **id)
1736 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1738 FIXME("(%p)->(%p) - stub\n", This, id);
1740 return E_NOTIMPL;
1743 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
1744 IAudioSessionControl2 *iface, WCHAR **id)
1746 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1748 FIXME("(%p)->(%p) - stub\n", This, id);
1750 return E_NOTIMPL;
1753 static HRESULT WINAPI AudioSessionControl_GetProcessId(
1754 IAudioSessionControl2 *iface, DWORD *pid)
1756 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1758 TRACE("(%p)->(%p)\n", This, pid);
1760 if(!pid)
1761 return E_POINTER;
1763 *pid = GetCurrentProcessId();
1765 return S_OK;
1768 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
1769 IAudioSessionControl2 *iface)
1771 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1773 TRACE("(%p)\n", This);
1775 return S_FALSE;
1778 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
1779 IAudioSessionControl2 *iface, BOOL optout)
1781 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1783 TRACE("(%p)->(%d)\n", This, optout);
1785 return S_OK;
1788 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
1790 AudioSessionControl_QueryInterface,
1791 AudioSessionControl_AddRef,
1792 AudioSessionControl_Release,
1793 AudioSessionControl_GetState,
1794 AudioSessionControl_GetDisplayName,
1795 AudioSessionControl_SetDisplayName,
1796 AudioSessionControl_GetIconPath,
1797 AudioSessionControl_SetIconPath,
1798 AudioSessionControl_GetGroupingParam,
1799 AudioSessionControl_SetGroupingParam,
1800 AudioSessionControl_RegisterAudioSessionNotification,
1801 AudioSessionControl_UnregisterAudioSessionNotification,
1802 AudioSessionControl_GetSessionIdentifier,
1803 AudioSessionControl_GetSessionInstanceIdentifier,
1804 AudioSessionControl_GetProcessId,
1805 AudioSessionControl_IsSystemSoundsSession,
1806 AudioSessionControl_SetDuckingPreference
1809 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
1810 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
1812 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1814 if(!ppv)
1815 return E_POINTER;
1816 *ppv = NULL;
1818 if(IsEqualIID(riid, &IID_IUnknown) ||
1819 IsEqualIID(riid, &IID_ISimpleAudioVolume))
1820 *ppv = iface;
1821 if(*ppv){
1822 IUnknown_AddRef((IUnknown*)*ppv);
1823 return S_OK;
1826 WARN("Unknown interface %s\n", debugstr_guid(riid));
1827 return E_NOINTERFACE;
1830 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
1832 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1833 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
1836 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
1838 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1839 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
1842 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
1843 ISimpleAudioVolume *iface, float level, const GUID *context)
1845 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1846 AudioSession *session = This->session;
1847 ACImpl *client;
1849 TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
1851 if(level < 0.f || level > 1.f)
1852 return E_INVALIDARG;
1854 if(context)
1855 FIXME("Notifications not supported yet\n");
1857 TRACE("ALSA does not support volume control\n");
1859 EnterCriticalSection(&g_sessions_lock);
1861 session->master_vol = level;
1863 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
1864 set_stream_volumes(client);
1866 LeaveCriticalSection(&g_sessions_lock);
1868 return S_OK;
1871 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
1872 ISimpleAudioVolume *iface, float *level)
1874 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1875 AudioSession *session = This->session;
1877 TRACE("(%p)->(%p)\n", session, level);
1879 if(!level)
1880 return NULL_PTR_ERR;
1882 *level = session->master_vol;
1884 return S_OK;
1887 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
1888 BOOL mute, const GUID *context)
1890 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1891 AudioSession *session = This->session;
1892 ACImpl *client;
1894 TRACE("(%p)->(%u, %s)\n", session, mute, debugstr_guid(context));
1896 if(context)
1897 FIXME("Notifications not supported yet\n");
1899 EnterCriticalSection(&g_sessions_lock);
1901 session->mute = mute;
1902 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
1903 set_stream_volumes(client);
1905 LeaveCriticalSection(&g_sessions_lock);
1907 return S_OK;
1910 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
1911 BOOL *mute)
1913 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1914 AudioSession *session = This->session;
1916 TRACE("(%p)->(%p)\n", session, mute);
1918 if(!mute)
1919 return NULL_PTR_ERR;
1921 *mute = session->mute;
1923 return S_OK;
1926 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
1928 SimpleAudioVolume_QueryInterface,
1929 SimpleAudioVolume_AddRef,
1930 SimpleAudioVolume_Release,
1931 SimpleAudioVolume_SetMasterVolume,
1932 SimpleAudioVolume_GetMasterVolume,
1933 SimpleAudioVolume_SetMute,
1934 SimpleAudioVolume_GetMute
1937 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
1938 IAudioStreamVolume *iface, REFIID riid, void **ppv)
1940 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1942 if(!ppv)
1943 return E_POINTER;
1944 *ppv = NULL;
1946 if(IsEqualIID(riid, &IID_IUnknown) ||
1947 IsEqualIID(riid, &IID_IAudioStreamVolume))
1948 *ppv = iface;
1949 if(*ppv){
1950 IUnknown_AddRef((IUnknown*)*ppv);
1951 return S_OK;
1954 WARN("Unknown interface %s\n", debugstr_guid(riid));
1955 return E_NOINTERFACE;
1958 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
1960 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1961 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1964 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
1966 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1967 return IAudioClient3_Release(&This->IAudioClient3_iface);
1970 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
1971 IAudioStreamVolume *iface, UINT32 *out)
1973 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1975 TRACE("(%p)->(%p)\n", This, out);
1977 if(!out)
1978 return E_POINTER;
1980 *out = This->channel_count;
1982 return S_OK;
1985 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
1986 IAudioStreamVolume *iface, UINT32 index, float level)
1988 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1990 TRACE("(%p)->(%d, %f)\n", This, index, level);
1992 if(level < 0.f || level > 1.f)
1993 return E_INVALIDARG;
1995 if(index >= This->channel_count)
1996 return E_INVALIDARG;
1998 TRACE("ALSA does not support volume control\n");
2000 EnterCriticalSection(&g_sessions_lock);
2002 This->vols[index] = level;
2003 set_stream_volumes(This);
2005 LeaveCriticalSection(&g_sessions_lock);
2007 return S_OK;
2010 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2011 IAudioStreamVolume *iface, UINT32 index, float *level)
2013 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2015 TRACE("(%p)->(%d, %p)\n", This, index, level);
2017 if(!level)
2018 return E_POINTER;
2020 if(index >= This->channel_count)
2021 return E_INVALIDARG;
2023 *level = This->vols[index];
2025 return S_OK;
2028 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2029 IAudioStreamVolume *iface, UINT32 count, const float *levels)
2031 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2032 unsigned int i;
2034 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2036 if(!levels)
2037 return E_POINTER;
2039 if(count != This->channel_count)
2040 return E_INVALIDARG;
2042 TRACE("ALSA does not support volume control\n");
2044 EnterCriticalSection(&g_sessions_lock);
2046 for(i = 0; i < count; ++i)
2047 This->vols[i] = levels[i];
2048 set_stream_volumes(This);
2050 LeaveCriticalSection(&g_sessions_lock);
2052 return S_OK;
2055 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2056 IAudioStreamVolume *iface, UINT32 count, float *levels)
2058 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2059 unsigned int i;
2061 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2063 if(!levels)
2064 return E_POINTER;
2066 if(count != This->channel_count)
2067 return E_INVALIDARG;
2069 EnterCriticalSection(&g_sessions_lock);
2071 for(i = 0; i < count; ++i)
2072 levels[i] = This->vols[i];
2074 LeaveCriticalSection(&g_sessions_lock);
2076 return S_OK;
2079 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2081 AudioStreamVolume_QueryInterface,
2082 AudioStreamVolume_AddRef,
2083 AudioStreamVolume_Release,
2084 AudioStreamVolume_GetChannelCount,
2085 AudioStreamVolume_SetChannelVolume,
2086 AudioStreamVolume_GetChannelVolume,
2087 AudioStreamVolume_SetAllVolumes,
2088 AudioStreamVolume_GetAllVolumes
2091 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2092 IChannelAudioVolume *iface, REFIID riid, void **ppv)
2094 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2096 if(!ppv)
2097 return E_POINTER;
2098 *ppv = NULL;
2100 if(IsEqualIID(riid, &IID_IUnknown) ||
2101 IsEqualIID(riid, &IID_IChannelAudioVolume))
2102 *ppv = iface;
2103 if(*ppv){
2104 IUnknown_AddRef((IUnknown*)*ppv);
2105 return S_OK;
2108 WARN("Unknown interface %s\n", debugstr_guid(riid));
2109 return E_NOINTERFACE;
2112 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2114 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2115 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2118 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2120 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2121 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2124 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2125 IChannelAudioVolume *iface, UINT32 *out)
2127 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2128 AudioSession *session = This->session;
2130 TRACE("(%p)->(%p)\n", session, out);
2132 if(!out)
2133 return NULL_PTR_ERR;
2135 *out = session->channel_count;
2137 return S_OK;
2140 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2141 IChannelAudioVolume *iface, UINT32 index, float level,
2142 const GUID *context)
2144 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2145 AudioSession *session = This->session;
2146 ACImpl *client;
2148 TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2149 wine_dbgstr_guid(context));
2151 if(level < 0.f || level > 1.f)
2152 return E_INVALIDARG;
2154 if(index >= session->channel_count)
2155 return E_INVALIDARG;
2157 if(context)
2158 FIXME("Notifications not supported yet\n");
2160 TRACE("ALSA does not support volume control\n");
2162 EnterCriticalSection(&g_sessions_lock);
2164 session->channel_vols[index] = level;
2166 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
2167 set_stream_volumes(client);
2169 LeaveCriticalSection(&g_sessions_lock);
2171 return S_OK;
2174 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2175 IChannelAudioVolume *iface, UINT32 index, float *level)
2177 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2178 AudioSession *session = This->session;
2180 TRACE("(%p)->(%d, %p)\n", session, index, level);
2182 if(!level)
2183 return NULL_PTR_ERR;
2185 if(index >= session->channel_count)
2186 return E_INVALIDARG;
2188 *level = session->channel_vols[index];
2190 return S_OK;
2193 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2194 IChannelAudioVolume *iface, UINT32 count, const float *levels,
2195 const GUID *context)
2197 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2198 AudioSession *session = This->session;
2199 unsigned int i;
2200 ACImpl *client;
2202 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2203 wine_dbgstr_guid(context));
2205 if(!levels)
2206 return NULL_PTR_ERR;
2208 if(count != session->channel_count)
2209 return E_INVALIDARG;
2211 if(context)
2212 FIXME("Notifications not supported yet\n");
2214 TRACE("ALSA does not support volume control\n");
2216 EnterCriticalSection(&g_sessions_lock);
2218 for(i = 0; i < count; ++i)
2219 session->channel_vols[i] = levels[i];
2221 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
2222 set_stream_volumes(client);
2224 LeaveCriticalSection(&g_sessions_lock);
2226 return S_OK;
2229 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2230 IChannelAudioVolume *iface, UINT32 count, float *levels)
2232 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2233 AudioSession *session = This->session;
2234 unsigned int i;
2236 TRACE("(%p)->(%d, %p)\n", session, count, levels);
2238 if(!levels)
2239 return NULL_PTR_ERR;
2241 if(count != session->channel_count)
2242 return E_INVALIDARG;
2244 for(i = 0; i < count; ++i)
2245 levels[i] = session->channel_vols[i];
2247 return S_OK;
2250 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2252 ChannelAudioVolume_QueryInterface,
2253 ChannelAudioVolume_AddRef,
2254 ChannelAudioVolume_Release,
2255 ChannelAudioVolume_GetChannelCount,
2256 ChannelAudioVolume_SetChannelVolume,
2257 ChannelAudioVolume_GetChannelVolume,
2258 ChannelAudioVolume_SetAllVolumes,
2259 ChannelAudioVolume_GetAllVolumes
2262 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2263 REFIID riid, void **ppv)
2265 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2267 if(!ppv)
2268 return E_POINTER;
2269 *ppv = NULL;
2271 if(IsEqualIID(riid, &IID_IUnknown) ||
2272 IsEqualIID(riid, &IID_IAudioSessionManager) ||
2273 IsEqualIID(riid, &IID_IAudioSessionManager2))
2274 *ppv = iface;
2275 if(*ppv){
2276 IUnknown_AddRef((IUnknown*)*ppv);
2277 return S_OK;
2280 WARN("Unknown interface %s\n", debugstr_guid(riid));
2281 return E_NOINTERFACE;
2284 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2286 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2287 ULONG ref;
2288 ref = InterlockedIncrement(&This->ref);
2289 TRACE("(%p) Refcount now %lu\n", This, ref);
2290 return ref;
2293 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2295 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2296 ULONG ref;
2297 ref = InterlockedDecrement(&This->ref);
2298 TRACE("(%p) Refcount now %lu\n", This, ref);
2299 if(!ref)
2300 HeapFree(GetProcessHeap(), 0, This);
2301 return ref;
2304 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2305 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2306 IAudioSessionControl **out)
2308 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2309 AudioSession *session;
2310 AudioSessionWrapper *wrapper;
2311 HRESULT hr;
2313 TRACE("(%p)->(%s, %lx, %p)\n", This, debugstr_guid(session_guid),
2314 flags, out);
2316 hr = get_audio_session(session_guid, This->device, 0, &session);
2317 if(FAILED(hr))
2318 return hr;
2320 wrapper = AudioSessionWrapper_Create(NULL);
2321 if(!wrapper)
2322 return E_OUTOFMEMORY;
2324 wrapper->session = session;
2326 *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
2328 return S_OK;
2331 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
2332 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2333 ISimpleAudioVolume **out)
2335 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2336 AudioSession *session;
2337 AudioSessionWrapper *wrapper;
2338 HRESULT hr;
2340 TRACE("(%p)->(%s, %lx, %p)\n", This, debugstr_guid(session_guid),
2341 flags, out);
2343 hr = get_audio_session(session_guid, This->device, 0, &session);
2344 if(FAILED(hr))
2345 return hr;
2347 wrapper = AudioSessionWrapper_Create(NULL);
2348 if(!wrapper)
2349 return E_OUTOFMEMORY;
2351 wrapper->session = session;
2353 *out = &wrapper->ISimpleAudioVolume_iface;
2355 return S_OK;
2358 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
2359 IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
2361 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2362 FIXME("(%p)->(%p) - stub\n", This, out);
2363 return E_NOTIMPL;
2366 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
2367 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2369 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2370 FIXME("(%p)->(%p) - stub\n", This, notification);
2371 return E_NOTIMPL;
2374 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
2375 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2377 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2378 FIXME("(%p)->(%p) - stub\n", This, notification);
2379 return E_NOTIMPL;
2382 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
2383 IAudioSessionManager2 *iface, const WCHAR *session_id,
2384 IAudioVolumeDuckNotification *notification)
2386 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2387 FIXME("(%p)->(%p) - stub\n", This, notification);
2388 return E_NOTIMPL;
2391 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
2392 IAudioSessionManager2 *iface,
2393 IAudioVolumeDuckNotification *notification)
2395 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2396 FIXME("(%p)->(%p) - stub\n", This, notification);
2397 return E_NOTIMPL;
2400 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
2402 AudioSessionManager_QueryInterface,
2403 AudioSessionManager_AddRef,
2404 AudioSessionManager_Release,
2405 AudioSessionManager_GetAudioSessionControl,
2406 AudioSessionManager_GetSimpleAudioVolume,
2407 AudioSessionManager_GetSessionEnumerator,
2408 AudioSessionManager_RegisterSessionNotification,
2409 AudioSessionManager_UnregisterSessionNotification,
2410 AudioSessionManager_RegisterDuckNotification,
2411 AudioSessionManager_UnregisterDuckNotification
2414 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
2415 IAudioSessionManager2 **out)
2417 SessionMgr *This;
2419 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
2420 if(!This)
2421 return E_OUTOFMEMORY;
2423 This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
2424 This->device = device;
2425 This->ref = 1;
2427 *out = &This->IAudioSessionManager2_iface;
2429 return S_OK;
2432 HRESULT WINAPI AUDDRV_GetPropValue(GUID *guid, const PROPERTYKEY *prop, PROPVARIANT *out)
2434 struct get_prop_value_params params;
2435 char name[256];
2436 EDataFlow flow;
2437 unsigned int size = 0;
2439 TRACE("%s, (%s,%lu), %p\n", wine_dbgstr_guid(guid), wine_dbgstr_guid(&prop->fmtid), prop->pid, out);
2441 if(!get_alsa_name_by_guid(guid, name, sizeof(name), &flow))
2443 WARN("Unknown interface %s\n", debugstr_guid(guid));
2444 return E_NOINTERFACE;
2447 params.device = name;
2448 params.flow = flow;
2449 params.guid = guid;
2450 params.prop = prop;
2451 params.value = out;
2452 params.buffer = NULL;
2453 params.buffer_size = &size;
2455 while(1) {
2456 ALSA_CALL(get_prop_value, &params);
2458 if(params.result != E_NOT_SUFFICIENT_BUFFER)
2459 break;
2461 CoTaskMemFree(params.buffer);
2462 params.buffer = CoTaskMemAlloc(*params.buffer_size);
2463 if(!params.buffer)
2464 return E_OUTOFMEMORY;
2466 if(FAILED(params.result))
2467 CoTaskMemFree(params.buffer);
2469 return params.result;