vbscript: Fix memory leak in owned safearray iterator.
[wine.git] / dlls / wineoss.drv / mmdevdrv.c
blob7411f87a4d77c05db7e8a66607423668a4c77669
1 /*
2 * Copyright 2011 Andrew Eikum for CodeWeavers
3 * 2022 Huw Davies
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #define COBJMACROS
21 #include <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winternl.h"
26 #include "winnls.h"
27 #include "winreg.h"
29 #include "ole2.h"
30 #include "mmdeviceapi.h"
31 #include "devpkey.h"
32 #include "dshow.h"
33 #include "dsound.h"
35 #include "initguid.h"
36 #include "endpointvolume.h"
37 #include "audiopolicy.h"
38 #include "audioclient.h"
40 #include "wine/debug.h"
41 #include "wine/list.h"
42 #include "wine/unixlib.h"
44 #include "unixlib.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(oss);
48 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
50 static const REFERENCE_TIME DefaultPeriod = 100000;
51 static const REFERENCE_TIME MinimumPeriod = 50000;
53 struct ACImpl;
54 typedef struct ACImpl ACImpl;
56 typedef struct _AudioSession {
57 GUID guid;
58 struct list clients;
60 IMMDevice *device;
62 float master_vol;
63 UINT32 channel_count;
64 float *channel_vols;
65 BOOL mute;
67 struct list entry;
68 } AudioSession;
70 typedef struct _AudioSessionWrapper {
71 IAudioSessionControl2 IAudioSessionControl2_iface;
72 IChannelAudioVolume IChannelAudioVolume_iface;
73 ISimpleAudioVolume ISimpleAudioVolume_iface;
75 LONG ref;
77 ACImpl *client;
78 AudioSession *session;
79 } AudioSessionWrapper;
81 struct ACImpl {
82 IAudioClient3 IAudioClient3_iface;
83 IAudioRenderClient IAudioRenderClient_iface;
84 IAudioCaptureClient IAudioCaptureClient_iface;
85 IAudioClock IAudioClock_iface;
86 IAudioClock2 IAudioClock2_iface;
87 IAudioStreamVolume IAudioStreamVolume_iface;
89 LONG ref;
91 IMMDevice *parent;
92 IUnknown *pUnkFTMarshal;
94 EDataFlow dataflow;
95 float *vols;
96 UINT32 channel_count;
97 stream_handle stream;
99 HANDLE timer_thread;
101 AudioSession *session;
102 AudioSessionWrapper *session_wrapper;
104 struct list entry;
106 /* Keep at end */
107 char devnode[0];
110 typedef struct _SessionMgr {
111 IAudioSessionManager2 IAudioSessionManager2_iface;
113 LONG ref;
115 IMMDevice *device;
116 } SessionMgr;
118 typedef struct _OSSDevice {
119 struct list entry;
120 EDataFlow flow;
121 GUID guid;
122 char devnode[0];
123 } OSSDevice;
125 static struct list g_devices = LIST_INIT(g_devices);
127 static const WCHAR drv_key_devicesW[] = {'S','o','f','t','w','a','r','e','\\',
128 'W','i','n','e','\\','D','r','i','v','e','r','s','\\',
129 'w','i','n','e','o','s','s','.','d','r','v','\\','d','e','v','i','c','e','s',0};
130 static const WCHAR guidW[] = {'g','u','i','d',0};
132 static CRITICAL_SECTION g_sessions_lock;
133 static CRITICAL_SECTION_DEBUG g_sessions_lock_debug =
135 0, 0, &g_sessions_lock,
136 { &g_sessions_lock_debug.ProcessLocksList, &g_sessions_lock_debug.ProcessLocksList },
137 0, 0, { (DWORD_PTR)(__FILE__ ": g_sessions_lock") }
139 static CRITICAL_SECTION g_sessions_lock = { &g_sessions_lock_debug, -1, 0, 0, 0, 0 };
140 static struct list g_sessions = LIST_INIT(g_sessions);
142 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
144 static const IAudioClient3Vtbl AudioClient3_Vtbl;
145 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
146 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
147 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
148 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
149 static const IAudioClockVtbl AudioClock_Vtbl;
150 static const IAudioClock2Vtbl AudioClock2_Vtbl;
151 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
152 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
153 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl;
155 static inline ACImpl *impl_from_IAudioClient3(IAudioClient3 *iface)
157 return CONTAINING_RECORD(iface, ACImpl, IAudioClient3_iface);
160 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
162 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
165 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
167 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
170 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
172 return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
175 static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
177 return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
180 static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
182 return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
185 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
187 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
190 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
192 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
195 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
197 return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
200 static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface)
202 return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface);
205 BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
207 switch (reason)
209 case DLL_PROCESS_ATTACH:
210 if(__wine_init_unix_call()) return FALSE;
211 break;
213 case DLL_PROCESS_DETACH:
214 if (!reserved)
216 OSSDevice *iter, *iter2;
218 DeleteCriticalSection(&g_sessions_lock);
220 LIST_FOR_EACH_ENTRY_SAFE(iter, iter2, &g_devices, OSSDevice, entry){
221 HeapFree(GetProcessHeap(), 0, iter);
224 break;
226 return TRUE;
229 int WINAPI AUDDRV_GetPriority(void)
231 struct test_connect_params params;
233 params.name = NULL;
235 OSS_CALL(test_connect, &params);
237 return params.priority;
240 static HRESULT stream_release(stream_handle stream, HANDLE timer_thread)
242 struct release_stream_params params;
244 params.stream = stream;
245 params.timer_thread = timer_thread;
246 OSS_CALL(release_stream, &params);
248 return params.result;
251 static DWORD WINAPI timer_thread(void *user)
253 struct timer_loop_params params;
254 struct ACImpl *This = user;
256 params.stream = This->stream;
257 OSS_CALL(timer_loop, &params);
259 return 0;
262 static void set_device_guid(EDataFlow flow, HKEY drv_key, const WCHAR *key_name,
263 GUID *guid)
265 HKEY key;
266 BOOL opened = FALSE;
267 LONG lr;
269 if(!drv_key){
270 lr = RegCreateKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, NULL, 0, KEY_WRITE,
271 NULL, &drv_key, NULL);
272 if(lr != ERROR_SUCCESS){
273 ERR("RegCreateKeyEx(drv_key) failed: %lu\n", lr);
274 return;
276 opened = TRUE;
279 lr = RegCreateKeyExW(drv_key, key_name, 0, NULL, 0, KEY_WRITE,
280 NULL, &key, NULL);
281 if(lr != ERROR_SUCCESS){
282 ERR("RegCreateKeyEx(%s) failed: %lu\n", wine_dbgstr_w(key_name), lr);
283 goto exit;
286 lr = RegSetValueExW(key, guidW, 0, REG_BINARY, (BYTE*)guid,
287 sizeof(GUID));
288 if(lr != ERROR_SUCCESS)
289 ERR("RegSetValueEx(%s\\guid) failed: %lu\n", wine_dbgstr_w(key_name), lr);
291 RegCloseKey(key);
292 exit:
293 if(opened)
294 RegCloseKey(drv_key);
297 static void get_device_guid(EDataFlow flow, const char *device, GUID *guid)
299 HKEY key = NULL, dev_key;
300 DWORD type, size = sizeof(*guid);
301 WCHAR key_name[256];
303 if(flow == eCapture)
304 key_name[0] = '1';
305 else
306 key_name[0] = '0';
307 key_name[1] = ',';
308 MultiByteToWideChar(CP_UNIXCP, 0, device, -1, key_name + 2, ARRAY_SIZE(key_name) - 2);
310 if(RegOpenKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, KEY_WRITE|KEY_READ, &key) == ERROR_SUCCESS){
311 if(RegOpenKeyExW(key, key_name, 0, KEY_READ, &dev_key) == ERROR_SUCCESS){
312 if(RegQueryValueExW(dev_key, guidW, 0, &type,
313 (BYTE*)guid, &size) == ERROR_SUCCESS){
314 if(type == REG_BINARY){
315 RegCloseKey(dev_key);
316 RegCloseKey(key);
317 return;
319 ERR("Invalid type for device %s GUID: %lu; ignoring and overwriting\n",
320 wine_dbgstr_w(key_name), type);
322 RegCloseKey(dev_key);
326 CoCreateGuid(guid);
328 set_device_guid(flow, key, key_name, guid);
330 if(key)
331 RegCloseKey(key);
334 static void set_stream_volumes(ACImpl *This)
336 struct set_volumes_params params;
338 params.stream = This->stream;
339 params.master_volume = (This->session->mute ? 0.0f : This->session->master_vol);
340 params.volumes = This->vols;
341 params.session_volumes = This->session->channel_vols;
342 params.channel = 0;
343 OSS_CALL(set_volumes, &params);
346 static const OSSDevice *get_ossdevice_from_guid(const GUID *guid)
348 OSSDevice *dev_item;
349 LIST_FOR_EACH_ENTRY(dev_item, &g_devices, OSSDevice, entry)
350 if(IsEqualGUID(guid, &dev_item->guid))
351 return dev_item;
352 return NULL;
355 static void device_add(OSSDevice *oss_dev)
357 if(get_ossdevice_from_guid(&oss_dev->guid)) /* already in list */
358 HeapFree(GetProcessHeap(), 0, oss_dev);
359 else
360 list_add_tail(&g_devices, &oss_dev->entry);
363 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids_out, GUID **guids_out,
364 UINT *num, UINT *def_index)
366 struct get_endpoint_ids_params params;
367 GUID *guids = NULL;
368 WCHAR **ids = NULL;
369 unsigned int i;
371 TRACE("%d %p %p %p %p\n", flow, ids, guids, num, def_index);
373 params.flow = flow;
374 params.size = 1000;
375 params.endpoints = NULL;
377 HeapFree(GetProcessHeap(), 0, params.endpoints);
378 params.endpoints = HeapAlloc(GetProcessHeap(), 0, params.size);
379 OSS_CALL(get_endpoint_ids, &params);
380 }while(params.result == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
382 if(FAILED(params.result)) goto end;
384 ids = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, params.num * sizeof(*ids));
385 guids = HeapAlloc(GetProcessHeap(), 0, params.num * sizeof(*guids));
386 if(!ids || !guids){
387 params.result = E_OUTOFMEMORY;
388 goto end;
391 for(i = 0; i < params.num; i++){
392 WCHAR *name = (WCHAR *)((char *)params.endpoints + params.endpoints[i].name);
393 char *device = (char *)params.endpoints + params.endpoints[i].device;
394 unsigned int name_size = (wcslen(name) + 1) * sizeof(WCHAR);
395 unsigned int dev_size = strlen(device) + 1;
396 OSSDevice *oss_dev;
398 ids[i] = HeapAlloc(GetProcessHeap(), 0, name_size);
399 oss_dev = HeapAlloc(GetProcessHeap(), 0, offsetof(OSSDevice, devnode[dev_size]));
400 if(!ids[i] || !oss_dev){
401 HeapFree(GetProcessHeap(), 0, oss_dev);
402 params.result = E_OUTOFMEMORY;
403 goto end;
405 memcpy(ids[i], name, name_size);
406 get_device_guid(flow, device, guids + i);
408 oss_dev->flow = flow;
409 oss_dev->guid = guids[i];
410 memcpy(oss_dev->devnode, device, dev_size);
411 device_add(oss_dev);
413 *def_index = params.default_idx;
415 end:
416 HeapFree(GetProcessHeap(), 0, params.endpoints);
417 if(FAILED(params.result)){
418 HeapFree(GetProcessHeap(), 0, guids);
419 if(ids){
420 for(i = 0; i < params.num; i++)
421 HeapFree(GetProcessHeap(), 0, ids[i]);
422 HeapFree(GetProcessHeap(), 0, ids);
424 }else{
425 *ids_out = ids;
426 *guids_out = guids;
427 *num = params.num;
430 return params.result;
433 HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev,
434 IAudioClient **out)
436 ACImpl *This;
437 const OSSDevice *oss_dev;
438 HRESULT hr;
439 int len;
441 TRACE("%s %p %p\n", debugstr_guid(guid), dev, out);
443 oss_dev = get_ossdevice_from_guid(guid);
444 if(!oss_dev){
445 WARN("Unknown GUID: %s\n", debugstr_guid(guid));
446 return AUDCLNT_E_DEVICE_INVALIDATED;
448 len = strlen(oss_dev->devnode);
449 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, offsetof(ACImpl, devnode[len + 1]));
450 if(!This)
451 return E_OUTOFMEMORY;
453 hr = CoCreateFreeThreadedMarshaler((IUnknown *)&This->IAudioClient3_iface, &This->pUnkFTMarshal);
454 if (FAILED(hr)) {
455 HeapFree(GetProcessHeap(), 0, This);
456 return hr;
459 This->dataflow = oss_dev->flow;
460 strcpy(This->devnode, oss_dev->devnode);
462 This->IAudioClient3_iface.lpVtbl = &AudioClient3_Vtbl;
463 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
464 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
465 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
466 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
467 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
469 This->parent = dev;
470 IMMDevice_AddRef(This->parent);
472 *out = (IAudioClient *)&This->IAudioClient3_iface;
473 IAudioClient3_AddRef(&This->IAudioClient3_iface);
475 return S_OK;
478 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient3 *iface,
479 REFIID riid, void **ppv)
481 ACImpl *This = impl_from_IAudioClient3(iface);
482 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
484 if(!ppv)
485 return E_POINTER;
486 *ppv = NULL;
487 if(IsEqualIID(riid, &IID_IUnknown) ||
488 IsEqualIID(riid, &IID_IAudioClient) ||
489 IsEqualIID(riid, &IID_IAudioClient2) ||
490 IsEqualIID(riid, &IID_IAudioClient3))
491 *ppv = iface;
492 else if(IsEqualIID(riid, &IID_IMarshal))
493 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
494 if(*ppv){
495 IUnknown_AddRef((IUnknown*)*ppv);
496 return S_OK;
498 WARN("Unknown interface %s\n", debugstr_guid(riid));
499 return E_NOINTERFACE;
502 static ULONG WINAPI AudioClient_AddRef(IAudioClient3 *iface)
504 ACImpl *This = impl_from_IAudioClient3(iface);
505 ULONG ref;
506 ref = InterlockedIncrement(&This->ref);
507 TRACE("(%p) Refcount now %lu\n", This, ref);
508 return ref;
511 static ULONG WINAPI AudioClient_Release(IAudioClient3 *iface)
513 ACImpl *This = impl_from_IAudioClient3(iface);
514 ULONG ref;
516 ref = InterlockedDecrement(&This->ref);
517 TRACE("(%p) Refcount now %lu\n", This, ref);
518 if(!ref){
519 IAudioClient3_Stop(iface);
520 IMMDevice_Release(This->parent);
521 IUnknown_Release(This->pUnkFTMarshal);
522 if(This->session){
523 EnterCriticalSection(&g_sessions_lock);
524 list_remove(&This->entry);
525 LeaveCriticalSection(&g_sessions_lock);
527 HeapFree(GetProcessHeap(), 0, This->vols);
528 if(This->stream)
529 stream_release(This->stream, This->timer_thread);
530 HeapFree(GetProcessHeap(), 0, This);
532 return ref;
535 static void dump_fmt(const WAVEFORMATEX *fmt)
537 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
538 switch(fmt->wFormatTag){
539 case WAVE_FORMAT_PCM:
540 TRACE("WAVE_FORMAT_PCM");
541 break;
542 case WAVE_FORMAT_IEEE_FLOAT:
543 TRACE("WAVE_FORMAT_IEEE_FLOAT");
544 break;
545 case WAVE_FORMAT_EXTENSIBLE:
546 TRACE("WAVE_FORMAT_EXTENSIBLE");
547 break;
548 default:
549 TRACE("Unknown");
550 break;
552 TRACE(")\n");
554 TRACE("nChannels: %u\n", fmt->nChannels);
555 TRACE("nSamplesPerSec: %lu\n", fmt->nSamplesPerSec);
556 TRACE("nAvgBytesPerSec: %lu\n", fmt->nAvgBytesPerSec);
557 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
558 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
559 TRACE("cbSize: %u\n", fmt->cbSize);
561 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
562 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
563 TRACE("dwChannelMask: %08lx\n", fmtex->dwChannelMask);
564 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
565 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
569 static void session_init_vols(AudioSession *session, UINT channels)
571 if(session->channel_count < channels){
572 UINT i;
574 if(session->channel_vols)
575 session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
576 session->channel_vols, sizeof(float) * channels);
577 else
578 session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
579 sizeof(float) * channels);
580 if(!session->channel_vols)
581 return;
583 for(i = session->channel_count; i < channels; ++i)
584 session->channel_vols[i] = 1.f;
586 session->channel_count = channels;
590 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
591 UINT num_channels)
593 AudioSession *ret;
595 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
596 if(!ret)
597 return NULL;
599 memcpy(&ret->guid, guid, sizeof(GUID));
601 ret->device = device;
603 list_init(&ret->clients);
605 list_add_head(&g_sessions, &ret->entry);
607 session_init_vols(ret, num_channels);
609 ret->master_vol = 1.f;
611 return ret;
614 /* if channels == 0, then this will return or create a session with
615 * matching dataflow and GUID. otherwise, channels must also match */
616 static HRESULT get_audio_session(const GUID *sessionguid,
617 IMMDevice *device, UINT channels, AudioSession **out)
619 AudioSession *session;
621 if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
622 *out = create_session(&GUID_NULL, device, channels);
623 if(!*out)
624 return E_OUTOFMEMORY;
626 return S_OK;
629 *out = NULL;
630 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
631 if(session->device == device &&
632 IsEqualGUID(sessionguid, &session->guid)){
633 session_init_vols(session, channels);
634 *out = session;
635 break;
639 if(!*out){
640 *out = create_session(sessionguid, device, channels);
641 if(!*out)
642 return E_OUTOFMEMORY;
645 return S_OK;
648 static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
649 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
650 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
651 const GUID *sessionguid)
653 ACImpl *This = impl_from_IAudioClient3(iface);
654 struct create_stream_params params;
655 stream_handle stream;
656 unsigned int i;
658 TRACE("(%p)->(%x, %lx, %s, %s, %p, %s)\n", This, mode, flags,
659 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
661 if(!fmt)
662 return E_POINTER;
664 dump_fmt(fmt);
666 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
667 return E_INVALIDARG;
669 if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
670 AUDCLNT_STREAMFLAGS_LOOPBACK |
671 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
672 AUDCLNT_STREAMFLAGS_NOPERSIST |
673 AUDCLNT_STREAMFLAGS_RATEADJUST |
674 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
675 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
676 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED |
677 AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY |
678 AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM)){
679 FIXME("Unknown flags: %08lx\n", flags);
680 return E_INVALIDARG;
683 if(mode == AUDCLNT_SHAREMODE_SHARED){
684 period = DefaultPeriod;
685 if( duration < 3 * period)
686 duration = 3 * period;
687 }else{
688 if(!period)
689 period = DefaultPeriod; /* not minimum */
690 if(period < MinimumPeriod || period > 5000000)
691 return AUDCLNT_E_INVALID_DEVICE_PERIOD;
692 if(duration > 20000000) /* the smaller the period, the lower this limit */
693 return AUDCLNT_E_BUFFER_SIZE_ERROR;
694 if(flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK){
695 if(duration != period)
696 return AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL;
697 FIXME("EXCLUSIVE mode with EVENTCALLBACK\n");
698 return AUDCLNT_E_DEVICE_IN_USE;
699 }else{
700 if( duration < 8 * period)
701 duration = 8 * period; /* may grow above 2s */
705 EnterCriticalSection(&g_sessions_lock);
707 if(This->stream){
708 LeaveCriticalSection(&g_sessions_lock);
709 return AUDCLNT_E_ALREADY_INITIALIZED;
712 params.name = NULL;
713 params.device = This->devnode;
714 params.flow = This->dataflow;
715 params.share = mode;
716 params.flags = flags;
717 params.duration = duration;
718 params.period = period;
719 params.fmt = fmt;
720 params.channel_count = NULL;
721 params.stream = &stream;
723 OSS_CALL(create_stream, &params);
724 if(FAILED(params.result)){
725 LeaveCriticalSection(&g_sessions_lock);
726 return params.result;
729 This->channel_count = fmt->nChannels;
730 This->vols = HeapAlloc(GetProcessHeap(), 0, This->channel_count * sizeof(float));
731 if(!This->vols){
732 params.result = E_OUTOFMEMORY;
733 goto exit;
735 for(i = 0; i < This->channel_count; ++i)
736 This->vols[i] = 1.f;
738 params.result = get_audio_session(sessionguid, This->parent, This->channel_count,
739 &This->session);
741 exit:
742 if(FAILED(params.result)){
743 stream_release(stream, NULL);
744 HeapFree(GetProcessHeap(), 0, This->vols);
745 This->vols = NULL;
746 } else {
747 list_add_tail(&This->session->clients, &This->entry);
748 This->stream = stream;
749 set_stream_volumes(This);
752 LeaveCriticalSection(&g_sessions_lock);
754 return params.result;
757 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient3 *iface,
758 UINT32 *frames)
760 ACImpl *This = impl_from_IAudioClient3(iface);
761 struct get_buffer_size_params params;
763 TRACE("(%p)->(%p)\n", This, frames);
765 if(!frames)
766 return E_POINTER;
768 if(!This->stream)
769 return AUDCLNT_E_NOT_INITIALIZED;
771 params.stream = This->stream;
772 params.frames = frames;
774 OSS_CALL(get_buffer_size, &params);
775 TRACE("buffer size: %u\n", *frames);
777 return params.result;
780 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient3 *iface,
781 REFERENCE_TIME *latency)
783 ACImpl *This = impl_from_IAudioClient3(iface);
784 struct get_latency_params params;
786 TRACE("(%p)->(%p)\n", This, latency);
788 if(!latency)
789 return E_POINTER;
791 if(!This->stream)
792 return AUDCLNT_E_NOT_INITIALIZED;
794 params.stream = This->stream;
795 params.latency = latency;
796 OSS_CALL(get_latency, &params);
798 return params.result;
801 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient3 *iface,
802 UINT32 *numpad)
804 ACImpl *This = impl_from_IAudioClient3(iface);
805 struct get_current_padding_params params;
807 TRACE("(%p)->(%p)\n", This, numpad);
809 if(!numpad)
810 return E_POINTER;
812 if(!This->stream)
813 return AUDCLNT_E_NOT_INITIALIZED;
815 params.stream = This->stream;
816 params.padding = numpad;
817 OSS_CALL(get_current_padding, &params);
818 TRACE("padding: %u\n", *numpad);
820 return params.result;
823 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient3 *iface,
824 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *fmt,
825 WAVEFORMATEX **out)
827 ACImpl *This = impl_from_IAudioClient3(iface);
828 struct is_format_supported_params params;
830 TRACE("(%p)->(%x, %p, %p)\n", This, mode, fmt, out);
831 if(fmt) dump_fmt(fmt);
833 params.device = This->devnode;
834 params.flow = This->dataflow;
835 params.share = mode;
836 params.fmt_in = fmt;
837 params.fmt_out = NULL;
839 if(out){
840 *out = NULL;
841 if(mode == AUDCLNT_SHAREMODE_SHARED)
842 params.fmt_out = CoTaskMemAlloc(sizeof(*params.fmt_out));
844 OSS_CALL(is_format_supported, &params);
846 if(params.result == S_FALSE)
847 *out = &params.fmt_out->Format;
848 else
849 CoTaskMemFree(params.fmt_out);
851 return params.result;
854 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface,
855 WAVEFORMATEX **pwfx)
857 ACImpl *This = impl_from_IAudioClient3(iface);
858 struct get_mix_format_params params;
860 TRACE("(%p)->(%p)\n", This, pwfx);
862 if(!pwfx)
863 return E_POINTER;
864 *pwfx = NULL;
866 params.device = This->devnode;
867 params.flow = This->dataflow;
868 params.fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
869 if(!params.fmt)
870 return E_OUTOFMEMORY;
872 OSS_CALL(get_mix_format, &params);
874 if(SUCCEEDED(params.result)){
875 *pwfx = &params.fmt->Format;
876 dump_fmt(*pwfx);
877 } else
878 CoTaskMemFree(params.fmt);
880 return params.result;
883 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient3 *iface,
884 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
886 ACImpl *This = impl_from_IAudioClient3(iface);
888 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
890 if(!defperiod && !minperiod)
891 return E_POINTER;
893 if(defperiod)
894 *defperiod = DefaultPeriod;
895 if(minperiod)
896 *minperiod = MinimumPeriod;
898 return S_OK;
901 static HRESULT WINAPI AudioClient_Start(IAudioClient3 *iface)
903 ACImpl *This = impl_from_IAudioClient3(iface);
904 struct start_params params;
906 TRACE("(%p)\n", This);
908 EnterCriticalSection(&g_sessions_lock);
910 if(!This->stream){
911 LeaveCriticalSection(&g_sessions_lock);
912 return AUDCLNT_E_NOT_INITIALIZED;
915 params.stream = This->stream;
916 OSS_CALL(start, &params);
918 if(SUCCEEDED(params.result) && !This->timer_thread){
919 This->timer_thread = CreateThread(NULL, 0, timer_thread, This, 0, NULL);
920 SetThreadPriority(This->timer_thread, THREAD_PRIORITY_TIME_CRITICAL);
923 LeaveCriticalSection(&g_sessions_lock);
925 return params.result;
928 static HRESULT WINAPI AudioClient_Stop(IAudioClient3 *iface)
930 ACImpl *This = impl_from_IAudioClient3(iface);
931 struct stop_params params;
933 TRACE("(%p)\n", This);
935 if(!This->stream)
936 return AUDCLNT_E_NOT_INITIALIZED;
938 params.stream = This->stream;
939 OSS_CALL(stop, &params);
941 return params.result;
944 static HRESULT WINAPI AudioClient_Reset(IAudioClient3 *iface)
946 ACImpl *This = impl_from_IAudioClient3(iface);
947 struct reset_params params;
949 TRACE("(%p)\n", This);
951 if(!This->stream)
952 return AUDCLNT_E_NOT_INITIALIZED;
954 params.stream = This->stream;
955 OSS_CALL(reset, &params);
957 return params.result;
960 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient3 *iface,
961 HANDLE event)
963 ACImpl *This = impl_from_IAudioClient3(iface);
964 struct set_event_handle_params params;
966 TRACE("(%p)->(%p)\n", This, event);
968 if(!event)
969 return E_INVALIDARG;
971 if(!This->stream)
972 return AUDCLNT_E_NOT_INITIALIZED;
974 params.stream = This->stream;
975 params.event = event;
976 OSS_CALL(set_event_handle, &params);
978 return params.result;
981 static HRESULT WINAPI AudioClient_GetService(IAudioClient3 *iface, REFIID riid,
982 void **ppv)
984 ACImpl *This = impl_from_IAudioClient3(iface);
986 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
988 if(!ppv)
989 return E_POINTER;
990 *ppv = NULL;
992 EnterCriticalSection(&g_sessions_lock);
994 if(!This->stream){
995 LeaveCriticalSection(&g_sessions_lock);
996 return AUDCLNT_E_NOT_INITIALIZED;
999 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1000 if(This->dataflow != eRender){
1001 LeaveCriticalSection(&g_sessions_lock);
1002 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1004 IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
1005 *ppv = &This->IAudioRenderClient_iface;
1006 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1007 if(This->dataflow != eCapture){
1008 LeaveCriticalSection(&g_sessions_lock);
1009 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1011 IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
1012 *ppv = &This->IAudioCaptureClient_iface;
1013 }else if(IsEqualIID(riid, &IID_IAudioClock)){
1014 IAudioClock_AddRef(&This->IAudioClock_iface);
1015 *ppv = &This->IAudioClock_iface;
1016 }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1017 IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
1018 *ppv = &This->IAudioStreamVolume_iface;
1019 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1020 if(!This->session_wrapper){
1021 This->session_wrapper = AudioSessionWrapper_Create(This);
1022 if(!This->session_wrapper){
1023 LeaveCriticalSection(&g_sessions_lock);
1024 return E_OUTOFMEMORY;
1026 }else
1027 IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
1029 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1030 }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1031 if(!This->session_wrapper){
1032 This->session_wrapper = AudioSessionWrapper_Create(This);
1033 if(!This->session_wrapper){
1034 LeaveCriticalSection(&g_sessions_lock);
1035 return E_OUTOFMEMORY;
1037 }else
1038 IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
1040 *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1041 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1042 if(!This->session_wrapper){
1043 This->session_wrapper = AudioSessionWrapper_Create(This);
1044 if(!This->session_wrapper){
1045 LeaveCriticalSection(&g_sessions_lock);
1046 return E_OUTOFMEMORY;
1048 }else
1049 ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
1051 *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1054 if(*ppv){
1055 LeaveCriticalSection(&g_sessions_lock);
1056 return S_OK;
1059 LeaveCriticalSection(&g_sessions_lock);
1061 FIXME("stub %s\n", debugstr_guid(riid));
1062 return E_NOINTERFACE;
1065 static HRESULT WINAPI AudioClient_IsOffloadCapable(IAudioClient3 *iface,
1066 AUDIO_STREAM_CATEGORY category, BOOL *offload_capable)
1068 ACImpl *This = impl_from_IAudioClient3(iface);
1070 TRACE("(%p)->(0x%x, %p)\n", This, category, offload_capable);
1072 if(!offload_capable)
1073 return E_INVALIDARG;
1075 *offload_capable = FALSE;
1077 return S_OK;
1080 static HRESULT WINAPI AudioClient_SetClientProperties(IAudioClient3 *iface,
1081 const AudioClientProperties *prop)
1083 ACImpl *This = impl_from_IAudioClient3(iface);
1084 const Win8AudioClientProperties *legacy_prop = (const Win8AudioClientProperties *)prop;
1086 TRACE("(%p)->(%p)\n", This, prop);
1088 if(!legacy_prop)
1089 return E_POINTER;
1091 if(legacy_prop->cbSize == sizeof(AudioClientProperties)){
1092 TRACE("{ bIsOffload: %u, eCategory: 0x%x, Options: 0x%x }\n",
1093 legacy_prop->bIsOffload,
1094 legacy_prop->eCategory,
1095 prop->Options);
1096 }else if(legacy_prop->cbSize == sizeof(Win8AudioClientProperties)){
1097 TRACE("{ bIsOffload: %u, eCategory: 0x%x }\n",
1098 legacy_prop->bIsOffload,
1099 legacy_prop->eCategory);
1100 }else{
1101 WARN("Unsupported Size = %d\n", legacy_prop->cbSize);
1102 return E_INVALIDARG;
1106 if(legacy_prop->bIsOffload)
1107 return AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE;
1109 return S_OK;
1112 static HRESULT WINAPI AudioClient_GetBufferSizeLimits(IAudioClient3 *iface,
1113 const WAVEFORMATEX *format, BOOL event_driven, REFERENCE_TIME *min_duration,
1114 REFERENCE_TIME *max_duration)
1116 ACImpl *This = impl_from_IAudioClient3(iface);
1118 FIXME("(%p)->(%p, %u, %p, %p)\n", This, format, event_driven, min_duration, max_duration);
1120 return E_NOTIMPL;
1123 static HRESULT WINAPI AudioClient_GetSharedModeEnginePeriod(IAudioClient3 *iface,
1124 const WAVEFORMATEX *format, UINT32 *default_period_frames, UINT32 *unit_period_frames,
1125 UINT32 *min_period_frames, UINT32 *max_period_frames)
1127 ACImpl *This = impl_from_IAudioClient3(iface);
1129 FIXME("(%p)->(%p, %p, %p, %p, %p)\n", This, format, default_period_frames, unit_period_frames,
1130 min_period_frames, max_period_frames);
1132 return E_NOTIMPL;
1135 static HRESULT WINAPI AudioClient_GetCurrentSharedModeEnginePeriod(IAudioClient3 *iface,
1136 WAVEFORMATEX **cur_format, UINT32 *cur_period_frames)
1138 ACImpl *This = impl_from_IAudioClient3(iface);
1140 FIXME("(%p)->(%p, %p)\n", This, cur_format, cur_period_frames);
1142 return E_NOTIMPL;
1145 static HRESULT WINAPI AudioClient_InitializeSharedAudioStream(IAudioClient3 *iface,
1146 DWORD flags, UINT32 period_frames, const WAVEFORMATEX *format,
1147 const GUID *session_guid)
1149 ACImpl *This = impl_from_IAudioClient3(iface);
1151 FIXME("(%p)->(0x%lx, %u, %p, %s)\n", This, flags, period_frames, format, debugstr_guid(session_guid));
1153 return E_NOTIMPL;
1156 static const IAudioClient3Vtbl AudioClient3_Vtbl =
1158 AudioClient_QueryInterface,
1159 AudioClient_AddRef,
1160 AudioClient_Release,
1161 AudioClient_Initialize,
1162 AudioClient_GetBufferSize,
1163 AudioClient_GetStreamLatency,
1164 AudioClient_GetCurrentPadding,
1165 AudioClient_IsFormatSupported,
1166 AudioClient_GetMixFormat,
1167 AudioClient_GetDevicePeriod,
1168 AudioClient_Start,
1169 AudioClient_Stop,
1170 AudioClient_Reset,
1171 AudioClient_SetEventHandle,
1172 AudioClient_GetService,
1173 AudioClient_IsOffloadCapable,
1174 AudioClient_SetClientProperties,
1175 AudioClient_GetBufferSizeLimits,
1176 AudioClient_GetSharedModeEnginePeriod,
1177 AudioClient_GetCurrentSharedModeEnginePeriod,
1178 AudioClient_InitializeSharedAudioStream,
1181 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1182 IAudioRenderClient *iface, REFIID riid, void **ppv)
1184 ACImpl *This = impl_from_IAudioRenderClient(iface);
1185 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1187 if(!ppv)
1188 return E_POINTER;
1189 *ppv = NULL;
1191 if(IsEqualIID(riid, &IID_IUnknown) ||
1192 IsEqualIID(riid, &IID_IAudioRenderClient))
1193 *ppv = iface;
1194 else if(IsEqualIID(riid, &IID_IMarshal))
1195 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
1196 if(*ppv){
1197 IUnknown_AddRef((IUnknown*)*ppv);
1198 return S_OK;
1201 WARN("Unknown interface %s\n", debugstr_guid(riid));
1202 return E_NOINTERFACE;
1205 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1207 ACImpl *This = impl_from_IAudioRenderClient(iface);
1208 return AudioClient_AddRef(&This->IAudioClient3_iface);
1211 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1213 ACImpl *This = impl_from_IAudioRenderClient(iface);
1214 return AudioClient_Release(&This->IAudioClient3_iface);
1217 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1218 UINT32 frames, BYTE **data)
1220 ACImpl *This = impl_from_IAudioRenderClient(iface);
1221 struct get_render_buffer_params params;
1223 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1225 if(!data)
1226 return E_POINTER;
1228 *data = NULL;
1230 params.stream = This->stream;
1231 params.frames = frames;
1232 params.data = data;
1233 OSS_CALL(get_render_buffer, &params);
1235 return params.result;
1238 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1239 IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
1241 ACImpl *This = impl_from_IAudioRenderClient(iface);
1242 struct release_render_buffer_params params;
1244 TRACE("(%p)->(%u, %lx)\n", This, written_frames, flags);
1246 params.stream = This->stream;
1247 params.written_frames = written_frames;
1248 params.flags = flags;
1249 OSS_CALL(release_render_buffer, &params);
1251 return params.result;
1254 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1255 AudioRenderClient_QueryInterface,
1256 AudioRenderClient_AddRef,
1257 AudioRenderClient_Release,
1258 AudioRenderClient_GetBuffer,
1259 AudioRenderClient_ReleaseBuffer
1262 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1263 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1265 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1266 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1268 if(!ppv)
1269 return E_POINTER;
1270 *ppv = NULL;
1272 if(IsEqualIID(riid, &IID_IUnknown) ||
1273 IsEqualIID(riid, &IID_IAudioCaptureClient))
1274 *ppv = iface;
1275 else if(IsEqualIID(riid, &IID_IMarshal))
1276 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
1277 if(*ppv){
1278 IUnknown_AddRef((IUnknown*)*ppv);
1279 return S_OK;
1282 WARN("Unknown interface %s\n", debugstr_guid(riid));
1283 return E_NOINTERFACE;
1286 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1288 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1289 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1292 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1294 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1295 return IAudioClient3_Release(&This->IAudioClient3_iface);
1298 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1299 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1300 UINT64 *qpcpos)
1302 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1303 struct get_capture_buffer_params params;
1305 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1306 devpos, qpcpos);
1308 if(!data)
1309 return E_POINTER;
1311 *data = NULL;
1313 if(!frames || !flags)
1314 return E_POINTER;
1316 params.stream = This->stream;
1317 params.data = data;
1318 params.frames = frames;
1319 params.flags = (UINT*)flags;
1320 params.devpos = devpos;
1321 params.qpcpos = qpcpos;
1322 OSS_CALL(get_capture_buffer, &params);
1324 return params.result;
1327 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1328 IAudioCaptureClient *iface, UINT32 done)
1330 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1331 struct release_capture_buffer_params params;
1333 TRACE("(%p)->(%u)\n", This, done);
1335 params.stream = This->stream;
1336 params.done = done;
1337 OSS_CALL(release_capture_buffer, &params);
1339 return params.result;
1342 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1343 IAudioCaptureClient *iface, UINT32 *frames)
1345 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1346 struct get_next_packet_size_params params;
1348 TRACE("(%p)->(%p)\n", This, frames);
1350 if(!frames)
1351 return E_POINTER;
1353 params.stream = This->stream;
1354 params.frames = frames;
1355 OSS_CALL(get_next_packet_size, &params);
1357 return params.result;
1360 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1362 AudioCaptureClient_QueryInterface,
1363 AudioCaptureClient_AddRef,
1364 AudioCaptureClient_Release,
1365 AudioCaptureClient_GetBuffer,
1366 AudioCaptureClient_ReleaseBuffer,
1367 AudioCaptureClient_GetNextPacketSize
1370 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1371 REFIID riid, void **ppv)
1373 ACImpl *This = impl_from_IAudioClock(iface);
1375 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1377 if(!ppv)
1378 return E_POINTER;
1379 *ppv = NULL;
1381 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
1382 *ppv = iface;
1383 else if(IsEqualIID(riid, &IID_IAudioClock2))
1384 *ppv = &This->IAudioClock2_iface;
1385 if(*ppv){
1386 IUnknown_AddRef((IUnknown*)*ppv);
1387 return S_OK;
1390 WARN("Unknown interface %s\n", debugstr_guid(riid));
1391 return E_NOINTERFACE;
1394 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
1396 ACImpl *This = impl_from_IAudioClock(iface);
1397 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1400 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
1402 ACImpl *This = impl_from_IAudioClock(iface);
1403 return IAudioClient3_Release(&This->IAudioClient3_iface);
1406 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
1408 ACImpl *This = impl_from_IAudioClock(iface);
1409 struct get_frequency_params params;
1411 TRACE("(%p)->(%p)\n", This, freq);
1413 params.stream = This->stream;
1414 params.freq = freq;
1415 OSS_CALL(get_frequency, &params);
1417 return params.result;
1420 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
1421 UINT64 *qpctime)
1423 ACImpl *This = impl_from_IAudioClock(iface);
1424 struct get_position_params params;
1426 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
1428 if(!pos)
1429 return E_POINTER;
1431 params.stream = This->stream;
1432 params.device = FALSE;
1433 params.pos = pos;
1434 params.qpctime = qpctime;
1435 OSS_CALL(get_position, &params);
1437 return params.result;
1440 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
1441 DWORD *chars)
1443 ACImpl *This = impl_from_IAudioClock(iface);
1445 TRACE("(%p)->(%p)\n", This, chars);
1447 if(!chars)
1448 return E_POINTER;
1450 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
1452 return S_OK;
1455 static const IAudioClockVtbl AudioClock_Vtbl =
1457 AudioClock_QueryInterface,
1458 AudioClock_AddRef,
1459 AudioClock_Release,
1460 AudioClock_GetFrequency,
1461 AudioClock_GetPosition,
1462 AudioClock_GetCharacteristics
1465 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
1466 REFIID riid, void **ppv)
1468 ACImpl *This = impl_from_IAudioClock2(iface);
1469 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
1472 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
1474 ACImpl *This = impl_from_IAudioClock2(iface);
1475 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1478 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
1480 ACImpl *This = impl_from_IAudioClock2(iface);
1481 return IAudioClient3_Release(&This->IAudioClient3_iface);
1484 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
1485 UINT64 *pos, UINT64 *qpctime)
1487 ACImpl *This = impl_from_IAudioClock2(iface);
1489 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
1491 return E_NOTIMPL;
1494 static const IAudioClock2Vtbl AudioClock2_Vtbl =
1496 AudioClock2_QueryInterface,
1497 AudioClock2_AddRef,
1498 AudioClock2_Release,
1499 AudioClock2_GetDevicePosition
1502 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
1504 AudioSessionWrapper *ret;
1506 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1507 sizeof(AudioSessionWrapper));
1508 if(!ret)
1509 return NULL;
1511 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
1512 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
1513 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
1515 ret->ref = 1;
1517 ret->client = client;
1518 if(client){
1519 ret->session = client->session;
1520 AudioClient_AddRef(&client->IAudioClient3_iface);
1523 return ret;
1526 static HRESULT WINAPI AudioSessionControl_QueryInterface(
1527 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
1529 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1531 if(!ppv)
1532 return E_POINTER;
1533 *ppv = NULL;
1535 if(IsEqualIID(riid, &IID_IUnknown) ||
1536 IsEqualIID(riid, &IID_IAudioSessionControl) ||
1537 IsEqualIID(riid, &IID_IAudioSessionControl2))
1538 *ppv = iface;
1539 if(*ppv){
1540 IUnknown_AddRef((IUnknown*)*ppv);
1541 return S_OK;
1544 WARN("Unknown interface %s\n", debugstr_guid(riid));
1545 return E_NOINTERFACE;
1548 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
1550 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1551 ULONG ref;
1552 ref = InterlockedIncrement(&This->ref);
1553 TRACE("(%p) Refcount now %lu\n", This, ref);
1554 return ref;
1557 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
1559 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1560 ULONG ref;
1561 ref = InterlockedDecrement(&This->ref);
1562 TRACE("(%p) Refcount now %lu\n", This, ref);
1563 if(!ref){
1564 if(This->client){
1565 EnterCriticalSection(&g_sessions_lock);
1566 This->client->session_wrapper = NULL;
1567 LeaveCriticalSection(&g_sessions_lock);
1568 AudioClient_Release(&This->client->IAudioClient3_iface);
1570 HeapFree(GetProcessHeap(), 0, This);
1572 return ref;
1575 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
1576 AudioSessionState *state)
1578 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1579 struct is_started_params params;
1580 ACImpl *client;
1582 TRACE("(%p)->(%p)\n", This, state);
1584 if(!state)
1585 return NULL_PTR_ERR;
1587 EnterCriticalSection(&g_sessions_lock);
1589 if(list_empty(&This->session->clients)){
1590 *state = AudioSessionStateExpired;
1591 LeaveCriticalSection(&g_sessions_lock);
1592 return S_OK;
1595 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
1596 params.stream = client->stream;
1597 OSS_CALL(is_started, &params);
1598 if(params.result == S_OK){
1599 *state = AudioSessionStateActive;
1600 LeaveCriticalSection(&g_sessions_lock);
1601 return S_OK;
1605 LeaveCriticalSection(&g_sessions_lock);
1607 *state = AudioSessionStateInactive;
1609 return S_OK;
1612 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
1613 IAudioSessionControl2 *iface, WCHAR **name)
1615 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1617 FIXME("(%p)->(%p) - stub\n", This, name);
1619 return E_NOTIMPL;
1622 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
1623 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
1625 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1627 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
1629 return E_NOTIMPL;
1632 static HRESULT WINAPI AudioSessionControl_GetIconPath(
1633 IAudioSessionControl2 *iface, WCHAR **path)
1635 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1637 FIXME("(%p)->(%p) - stub\n", This, path);
1639 return E_NOTIMPL;
1642 static HRESULT WINAPI AudioSessionControl_SetIconPath(
1643 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
1645 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1647 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
1649 return E_NOTIMPL;
1652 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
1653 IAudioSessionControl2 *iface, GUID *group)
1655 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1657 FIXME("(%p)->(%p) - stub\n", This, group);
1659 return E_NOTIMPL;
1662 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
1663 IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
1665 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1667 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
1668 debugstr_guid(session));
1670 return E_NOTIMPL;
1673 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
1674 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
1676 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1678 FIXME("(%p)->(%p) - stub\n", This, events);
1680 return S_OK;
1683 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
1684 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
1686 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1688 FIXME("(%p)->(%p) - stub\n", This, events);
1690 return S_OK;
1693 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
1694 IAudioSessionControl2 *iface, WCHAR **id)
1696 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1698 FIXME("(%p)->(%p) - stub\n", This, id);
1700 return E_NOTIMPL;
1703 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
1704 IAudioSessionControl2 *iface, WCHAR **id)
1706 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1708 FIXME("(%p)->(%p) - stub\n", This, id);
1710 return E_NOTIMPL;
1713 static HRESULT WINAPI AudioSessionControl_GetProcessId(
1714 IAudioSessionControl2 *iface, DWORD *pid)
1716 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1718 TRACE("(%p)->(%p)\n", This, pid);
1720 if(!pid)
1721 return E_POINTER;
1723 *pid = GetCurrentProcessId();
1725 return S_OK;
1728 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
1729 IAudioSessionControl2 *iface)
1731 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1733 TRACE("(%p)\n", This);
1735 return S_FALSE;
1738 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
1739 IAudioSessionControl2 *iface, BOOL optout)
1741 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1743 TRACE("(%p)->(%d)\n", This, optout);
1745 return S_OK;
1748 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
1750 AudioSessionControl_QueryInterface,
1751 AudioSessionControl_AddRef,
1752 AudioSessionControl_Release,
1753 AudioSessionControl_GetState,
1754 AudioSessionControl_GetDisplayName,
1755 AudioSessionControl_SetDisplayName,
1756 AudioSessionControl_GetIconPath,
1757 AudioSessionControl_SetIconPath,
1758 AudioSessionControl_GetGroupingParam,
1759 AudioSessionControl_SetGroupingParam,
1760 AudioSessionControl_RegisterAudioSessionNotification,
1761 AudioSessionControl_UnregisterAudioSessionNotification,
1762 AudioSessionControl_GetSessionIdentifier,
1763 AudioSessionControl_GetSessionInstanceIdentifier,
1764 AudioSessionControl_GetProcessId,
1765 AudioSessionControl_IsSystemSoundsSession,
1766 AudioSessionControl_SetDuckingPreference
1769 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
1770 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
1772 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1774 if(!ppv)
1775 return E_POINTER;
1776 *ppv = NULL;
1778 if(IsEqualIID(riid, &IID_IUnknown) ||
1779 IsEqualIID(riid, &IID_ISimpleAudioVolume))
1780 *ppv = iface;
1781 if(*ppv){
1782 IUnknown_AddRef((IUnknown*)*ppv);
1783 return S_OK;
1786 WARN("Unknown interface %s\n", debugstr_guid(riid));
1787 return E_NOINTERFACE;
1790 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
1792 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1793 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
1796 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
1798 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1799 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
1802 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
1803 ISimpleAudioVolume *iface, float level, const GUID *context)
1805 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1806 AudioSession *session = This->session;
1807 ACImpl *client;
1809 TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
1811 if(level < 0.f || level > 1.f)
1812 return E_INVALIDARG;
1814 if(context)
1815 FIXME("Notifications not supported yet\n");
1817 EnterCriticalSection(&g_sessions_lock);
1819 session->master_vol = level;
1821 TRACE("OSS doesn't support setting volume\n");
1822 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
1823 set_stream_volumes(client);
1825 LeaveCriticalSection(&g_sessions_lock);
1827 return S_OK;
1830 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
1831 ISimpleAudioVolume *iface, float *level)
1833 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1834 AudioSession *session = This->session;
1836 TRACE("(%p)->(%p)\n", session, level);
1838 if(!level)
1839 return NULL_PTR_ERR;
1841 *level = session->master_vol;
1843 return S_OK;
1846 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
1847 BOOL mute, const GUID *context)
1849 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1850 AudioSession *session = This->session;
1851 ACImpl *client;
1853 TRACE("(%p)->(%u, %s)\n", session, mute, debugstr_guid(context));
1855 EnterCriticalSection(&g_sessions_lock);
1857 session->mute = mute;
1859 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
1860 set_stream_volumes(client);
1862 LeaveCriticalSection(&g_sessions_lock);
1864 return S_OK;
1867 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
1868 BOOL *mute)
1870 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1871 AudioSession *session = This->session;
1873 TRACE("(%p)->(%p)\n", session, mute);
1875 if(!mute)
1876 return NULL_PTR_ERR;
1878 *mute = This->session->mute;
1880 return S_OK;
1883 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
1885 SimpleAudioVolume_QueryInterface,
1886 SimpleAudioVolume_AddRef,
1887 SimpleAudioVolume_Release,
1888 SimpleAudioVolume_SetMasterVolume,
1889 SimpleAudioVolume_GetMasterVolume,
1890 SimpleAudioVolume_SetMute,
1891 SimpleAudioVolume_GetMute
1894 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
1895 IAudioStreamVolume *iface, REFIID riid, void **ppv)
1897 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1899 if(!ppv)
1900 return E_POINTER;
1901 *ppv = NULL;
1903 if(IsEqualIID(riid, &IID_IUnknown) ||
1904 IsEqualIID(riid, &IID_IAudioStreamVolume))
1905 *ppv = iface;
1906 if(*ppv){
1907 IUnknown_AddRef((IUnknown*)*ppv);
1908 return S_OK;
1911 WARN("Unknown interface %s\n", debugstr_guid(riid));
1912 return E_NOINTERFACE;
1915 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
1917 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1918 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1921 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
1923 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1924 return IAudioClient3_Release(&This->IAudioClient3_iface);
1927 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
1928 IAudioStreamVolume *iface, UINT32 *out)
1930 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1932 TRACE("(%p)->(%p)\n", This, out);
1934 if(!out)
1935 return E_POINTER;
1937 *out = This->channel_count;
1939 return S_OK;
1942 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
1943 IAudioStreamVolume *iface, UINT32 index, float level)
1945 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1947 TRACE("(%p)->(%d, %f)\n", This, index, level);
1949 if(level < 0.f || level > 1.f)
1950 return E_INVALIDARG;
1952 if(index >= This->channel_count)
1953 return E_INVALIDARG;
1955 EnterCriticalSection(&g_sessions_lock);
1957 This->vols[index] = level;
1959 TRACE("OSS doesn't support setting volume\n");
1960 set_stream_volumes(This);
1962 LeaveCriticalSection(&g_sessions_lock);
1964 return S_OK;
1967 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
1968 IAudioStreamVolume *iface, UINT32 index, float *level)
1970 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1972 TRACE("(%p)->(%d, %p)\n", This, index, level);
1974 if(!level)
1975 return E_POINTER;
1977 if(index >= This->channel_count)
1978 return E_INVALIDARG;
1980 *level = This->vols[index];
1982 return S_OK;
1985 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
1986 IAudioStreamVolume *iface, UINT32 count, const float *levels)
1988 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1989 int i;
1991 TRACE("(%p)->(%d, %p)\n", This, count, levels);
1993 if(!levels)
1994 return E_POINTER;
1996 if(count != This->channel_count)
1997 return E_INVALIDARG;
1999 EnterCriticalSection(&g_sessions_lock);
2001 for(i = 0; i < count; ++i)
2002 This->vols[i] = levels[i];
2004 TRACE("OSS doesn't support setting volume\n");
2005 set_stream_volumes(This);
2007 LeaveCriticalSection(&g_sessions_lock);
2009 return S_OK;
2012 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2013 IAudioStreamVolume *iface, UINT32 count, float *levels)
2015 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2016 int i;
2018 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2020 if(!levels)
2021 return E_POINTER;
2023 if(count != This->channel_count)
2024 return E_INVALIDARG;
2026 EnterCriticalSection(&g_sessions_lock);
2028 for(i = 0; i < count; ++i)
2029 levels[i] = This->vols[i];
2031 LeaveCriticalSection(&g_sessions_lock);
2033 return S_OK;
2036 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2038 AudioStreamVolume_QueryInterface,
2039 AudioStreamVolume_AddRef,
2040 AudioStreamVolume_Release,
2041 AudioStreamVolume_GetChannelCount,
2042 AudioStreamVolume_SetChannelVolume,
2043 AudioStreamVolume_GetChannelVolume,
2044 AudioStreamVolume_SetAllVolumes,
2045 AudioStreamVolume_GetAllVolumes
2048 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2049 IChannelAudioVolume *iface, REFIID riid, void **ppv)
2051 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2053 if(!ppv)
2054 return E_POINTER;
2055 *ppv = NULL;
2057 if(IsEqualIID(riid, &IID_IUnknown) ||
2058 IsEqualIID(riid, &IID_IChannelAudioVolume))
2059 *ppv = iface;
2060 if(*ppv){
2061 IUnknown_AddRef((IUnknown*)*ppv);
2062 return S_OK;
2065 WARN("Unknown interface %s\n", debugstr_guid(riid));
2066 return E_NOINTERFACE;
2069 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2071 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2072 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2075 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2077 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2078 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2081 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2082 IChannelAudioVolume *iface, UINT32 *out)
2084 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2085 AudioSession *session = This->session;
2087 TRACE("(%p)->(%p)\n", session, out);
2089 if(!out)
2090 return NULL_PTR_ERR;
2092 *out = session->channel_count;
2094 return S_OK;
2097 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2098 IChannelAudioVolume *iface, UINT32 index, float level,
2099 const GUID *context)
2101 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2102 AudioSession *session = This->session;
2103 ACImpl *client;
2105 TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2106 wine_dbgstr_guid(context));
2108 if(level < 0.f || level > 1.f)
2109 return E_INVALIDARG;
2111 if(index >= session->channel_count)
2112 return E_INVALIDARG;
2114 if(context)
2115 FIXME("Notifications not supported yet\n");
2117 EnterCriticalSection(&g_sessions_lock);
2119 session->channel_vols[index] = level;
2121 TRACE("OSS doesn't support setting volume\n");
2122 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
2123 set_stream_volumes(client);
2125 LeaveCriticalSection(&g_sessions_lock);
2127 return S_OK;
2130 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2131 IChannelAudioVolume *iface, UINT32 index, float *level)
2133 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2134 AudioSession *session = This->session;
2136 TRACE("(%p)->(%d, %p)\n", session, index, level);
2138 if(!level)
2139 return NULL_PTR_ERR;
2141 if(index >= session->channel_count)
2142 return E_INVALIDARG;
2144 *level = session->channel_vols[index];
2146 return S_OK;
2149 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2150 IChannelAudioVolume *iface, UINT32 count, const float *levels,
2151 const GUID *context)
2153 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2154 AudioSession *session = This->session;
2155 ACImpl *client;
2156 int i;
2158 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2159 wine_dbgstr_guid(context));
2161 if(!levels)
2162 return NULL_PTR_ERR;
2164 if(count != session->channel_count)
2165 return E_INVALIDARG;
2167 if(context)
2168 FIXME("Notifications not supported yet\n");
2170 EnterCriticalSection(&g_sessions_lock);
2172 for(i = 0; i < count; ++i)
2173 session->channel_vols[i] = levels[i];
2175 TRACE("OSS doesn't support setting volume\n");
2176 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
2177 set_stream_volumes(client);
2179 LeaveCriticalSection(&g_sessions_lock);
2181 return S_OK;
2184 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2185 IChannelAudioVolume *iface, UINT32 count, float *levels)
2187 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2188 AudioSession *session = This->session;
2189 int i;
2191 TRACE("(%p)->(%d, %p)\n", session, count, levels);
2193 if(!levels)
2194 return NULL_PTR_ERR;
2196 if(count != session->channel_count)
2197 return E_INVALIDARG;
2199 for(i = 0; i < count; ++i)
2200 levels[i] = session->channel_vols[i];
2202 return S_OK;
2205 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2207 ChannelAudioVolume_QueryInterface,
2208 ChannelAudioVolume_AddRef,
2209 ChannelAudioVolume_Release,
2210 ChannelAudioVolume_GetChannelCount,
2211 ChannelAudioVolume_SetChannelVolume,
2212 ChannelAudioVolume_GetChannelVolume,
2213 ChannelAudioVolume_SetAllVolumes,
2214 ChannelAudioVolume_GetAllVolumes
2217 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2218 REFIID riid, void **ppv)
2220 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2222 if(!ppv)
2223 return E_POINTER;
2224 *ppv = NULL;
2226 if(IsEqualIID(riid, &IID_IUnknown) ||
2227 IsEqualIID(riid, &IID_IAudioSessionManager) ||
2228 IsEqualIID(riid, &IID_IAudioSessionManager2))
2229 *ppv = iface;
2230 if(*ppv){
2231 IUnknown_AddRef((IUnknown*)*ppv);
2232 return S_OK;
2235 WARN("Unknown interface %s\n", debugstr_guid(riid));
2236 return E_NOINTERFACE;
2239 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2241 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2242 ULONG ref;
2243 ref = InterlockedIncrement(&This->ref);
2244 TRACE("(%p) Refcount now %lu\n", This, ref);
2245 return ref;
2248 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2250 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2251 ULONG ref;
2252 ref = InterlockedDecrement(&This->ref);
2253 TRACE("(%p) Refcount now %lu\n", This, ref);
2254 if(!ref)
2255 HeapFree(GetProcessHeap(), 0, This);
2256 return ref;
2259 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2260 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2261 IAudioSessionControl **out)
2263 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2264 AudioSession *session;
2265 AudioSessionWrapper *wrapper;
2266 HRESULT hr;
2268 TRACE("(%p)->(%s, %lx, %p)\n", This, debugstr_guid(session_guid),
2269 flags, out);
2271 hr = get_audio_session(session_guid, This->device, 0, &session);
2272 if(FAILED(hr))
2273 return hr;
2275 wrapper = AudioSessionWrapper_Create(NULL);
2276 if(!wrapper)
2277 return E_OUTOFMEMORY;
2279 wrapper->session = session;
2281 *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
2283 return S_OK;
2286 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
2287 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2288 ISimpleAudioVolume **out)
2290 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2291 AudioSession *session;
2292 AudioSessionWrapper *wrapper;
2293 HRESULT hr;
2295 TRACE("(%p)->(%s, %lx, %p)\n", This, debugstr_guid(session_guid),
2296 flags, out);
2298 hr = get_audio_session(session_guid, This->device, 0, &session);
2299 if(FAILED(hr))
2300 return hr;
2302 wrapper = AudioSessionWrapper_Create(NULL);
2303 if(!wrapper)
2304 return E_OUTOFMEMORY;
2306 wrapper->session = session;
2308 *out = &wrapper->ISimpleAudioVolume_iface;
2310 return S_OK;
2313 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
2314 IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
2316 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2317 FIXME("(%p)->(%p) - stub\n", This, out);
2318 return E_NOTIMPL;
2321 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
2322 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2324 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2325 FIXME("(%p)->(%p) - stub\n", This, notification);
2326 return E_NOTIMPL;
2329 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
2330 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2332 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2333 FIXME("(%p)->(%p) - stub\n", This, notification);
2334 return E_NOTIMPL;
2337 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
2338 IAudioSessionManager2 *iface, const WCHAR *session_id,
2339 IAudioVolumeDuckNotification *notification)
2341 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2342 FIXME("(%p)->(%p) - stub\n", This, notification);
2343 return E_NOTIMPL;
2346 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
2347 IAudioSessionManager2 *iface,
2348 IAudioVolumeDuckNotification *notification)
2350 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2351 FIXME("(%p)->(%p) - stub\n", This, notification);
2352 return E_NOTIMPL;
2355 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
2357 AudioSessionManager_QueryInterface,
2358 AudioSessionManager_AddRef,
2359 AudioSessionManager_Release,
2360 AudioSessionManager_GetAudioSessionControl,
2361 AudioSessionManager_GetSimpleAudioVolume,
2362 AudioSessionManager_GetSessionEnumerator,
2363 AudioSessionManager_RegisterSessionNotification,
2364 AudioSessionManager_UnregisterSessionNotification,
2365 AudioSessionManager_RegisterDuckNotification,
2366 AudioSessionManager_UnregisterDuckNotification
2369 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
2370 IAudioSessionManager2 **out)
2372 SessionMgr *This;
2374 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
2375 if(!This)
2376 return E_OUTOFMEMORY;
2378 This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
2379 This->device = device;
2380 This->ref = 1;
2382 *out = &This->IAudioSessionManager2_iface;
2384 return S_OK;