wineoss: Adapt "get_position_params" struct to mmdevapi's.
[wine.git] / dlls / wineoss.drv / mmdevdrv.c
blob1b081e171b3bf870a9e5731d2dacd467d303b8f8
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 unixlib_handle_t oss_handle = 0;
52 static const REFERENCE_TIME DefaultPeriod = 100000;
53 static const REFERENCE_TIME MinimumPeriod = 50000;
55 struct ACImpl;
56 typedef struct ACImpl ACImpl;
58 typedef struct _AudioSession {
59 GUID guid;
60 struct list clients;
62 IMMDevice *device;
64 float master_vol;
65 UINT32 channel_count;
66 float *channel_vols;
67 BOOL mute;
69 struct list entry;
70 } AudioSession;
72 typedef struct _AudioSessionWrapper {
73 IAudioSessionControl2 IAudioSessionControl2_iface;
74 IChannelAudioVolume IChannelAudioVolume_iface;
75 ISimpleAudioVolume ISimpleAudioVolume_iface;
77 LONG ref;
79 ACImpl *client;
80 AudioSession *session;
81 } AudioSessionWrapper;
83 struct ACImpl {
84 IAudioClient3 IAudioClient3_iface;
85 IAudioRenderClient IAudioRenderClient_iface;
86 IAudioCaptureClient IAudioCaptureClient_iface;
87 IAudioClock IAudioClock_iface;
88 IAudioClock2 IAudioClock2_iface;
89 IAudioStreamVolume IAudioStreamVolume_iface;
91 LONG ref;
93 IMMDevice *parent;
94 IUnknown *pUnkFTMarshal;
96 EDataFlow dataflow;
97 float *vols;
98 UINT32 channel_count;
99 stream_handle stream;
101 HANDLE timer_thread;
103 AudioSession *session;
104 AudioSessionWrapper *session_wrapper;
106 struct list entry;
108 /* Keep at end */
109 char devnode[0];
112 typedef struct _SessionMgr {
113 IAudioSessionManager2 IAudioSessionManager2_iface;
115 LONG ref;
117 IMMDevice *device;
118 } SessionMgr;
120 typedef struct _OSSDevice {
121 struct list entry;
122 EDataFlow flow;
123 GUID guid;
124 char devnode[0];
125 } OSSDevice;
127 static struct list g_devices = LIST_INIT(g_devices);
129 static const WCHAR drv_key_devicesW[] = {'S','o','f','t','w','a','r','e','\\',
130 'W','i','n','e','\\','D','r','i','v','e','r','s','\\',
131 'w','i','n','e','o','s','s','.','d','r','v','\\','d','e','v','i','c','e','s',0};
132 static const WCHAR guidW[] = {'g','u','i','d',0};
134 static CRITICAL_SECTION g_sessions_lock;
135 static CRITICAL_SECTION_DEBUG g_sessions_lock_debug =
137 0, 0, &g_sessions_lock,
138 { &g_sessions_lock_debug.ProcessLocksList, &g_sessions_lock_debug.ProcessLocksList },
139 0, 0, { (DWORD_PTR)(__FILE__ ": g_sessions_lock") }
141 static CRITICAL_SECTION g_sessions_lock = { &g_sessions_lock_debug, -1, 0, 0, 0, 0 };
142 static struct list g_sessions = LIST_INIT(g_sessions);
144 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
146 static const IAudioClient3Vtbl AudioClient3_Vtbl;
147 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
148 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
149 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
150 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
151 static const IAudioClockVtbl AudioClock_Vtbl;
152 static const IAudioClock2Vtbl AudioClock2_Vtbl;
153 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
154 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
155 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl;
157 static inline ACImpl *impl_from_IAudioClient3(IAudioClient3 *iface)
159 return CONTAINING_RECORD(iface, ACImpl, IAudioClient3_iface);
162 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
164 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
167 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
169 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
172 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
174 return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
177 static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
179 return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
182 static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
184 return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
187 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
189 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
192 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
194 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
197 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
199 return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
202 static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface)
204 return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface);
207 BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
209 switch (reason)
211 case DLL_PROCESS_ATTACH:
212 if(NtQueryVirtualMemory(GetCurrentProcess(), dll, MemoryWineUnixFuncs,
213 &oss_handle, sizeof(oss_handle), NULL))
214 return FALSE;
215 break;
217 case DLL_PROCESS_DETACH:
218 if (!reserved)
220 OSSDevice *iter, *iter2;
222 DeleteCriticalSection(&g_sessions_lock);
224 LIST_FOR_EACH_ENTRY_SAFE(iter, iter2, &g_devices, OSSDevice, entry){
225 HeapFree(GetProcessHeap(), 0, iter);
228 break;
230 return TRUE;
233 int WINAPI AUDDRV_GetPriority(void)
235 struct test_connect_params params;
237 params.name = NULL;
239 OSS_CALL(test_connect, &params);
241 return params.priority;
244 static HRESULT stream_release(stream_handle stream, HANDLE timer_thread)
246 struct release_stream_params params;
248 params.stream = stream;
249 params.timer_thread = timer_thread;
250 OSS_CALL(release_stream, &params);
252 return params.result;
255 static DWORD WINAPI timer_thread(void *user)
257 struct timer_loop_params params;
258 struct ACImpl *This = user;
260 params.stream = This->stream;
261 OSS_CALL(timer_loop, &params);
263 return 0;
266 static void set_device_guid(EDataFlow flow, HKEY drv_key, const WCHAR *key_name,
267 GUID *guid)
269 HKEY key;
270 BOOL opened = FALSE;
271 LONG lr;
273 if(!drv_key){
274 lr = RegCreateKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, NULL, 0, KEY_WRITE,
275 NULL, &drv_key, NULL);
276 if(lr != ERROR_SUCCESS){
277 ERR("RegCreateKeyEx(drv_key) failed: %lu\n", lr);
278 return;
280 opened = TRUE;
283 lr = RegCreateKeyExW(drv_key, key_name, 0, NULL, 0, KEY_WRITE,
284 NULL, &key, NULL);
285 if(lr != ERROR_SUCCESS){
286 ERR("RegCreateKeyEx(%s) failed: %lu\n", wine_dbgstr_w(key_name), lr);
287 goto exit;
290 lr = RegSetValueExW(key, guidW, 0, REG_BINARY, (BYTE*)guid,
291 sizeof(GUID));
292 if(lr != ERROR_SUCCESS)
293 ERR("RegSetValueEx(%s\\guid) failed: %lu\n", wine_dbgstr_w(key_name), lr);
295 RegCloseKey(key);
296 exit:
297 if(opened)
298 RegCloseKey(drv_key);
301 static void get_device_guid(EDataFlow flow, const char *device, GUID *guid)
303 HKEY key = NULL, dev_key;
304 DWORD type, size = sizeof(*guid);
305 WCHAR key_name[256];
307 if(flow == eCapture)
308 key_name[0] = '1';
309 else
310 key_name[0] = '0';
311 key_name[1] = ',';
312 MultiByteToWideChar(CP_UNIXCP, 0, device, -1, key_name + 2, ARRAY_SIZE(key_name) - 2);
314 if(RegOpenKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, KEY_WRITE|KEY_READ, &key) == ERROR_SUCCESS){
315 if(RegOpenKeyExW(key, key_name, 0, KEY_READ, &dev_key) == ERROR_SUCCESS){
316 if(RegQueryValueExW(dev_key, guidW, 0, &type,
317 (BYTE*)guid, &size) == ERROR_SUCCESS){
318 if(type == REG_BINARY){
319 RegCloseKey(dev_key);
320 RegCloseKey(key);
321 return;
323 ERR("Invalid type for device %s GUID: %lu; ignoring and overwriting\n",
324 wine_dbgstr_w(key_name), type);
326 RegCloseKey(dev_key);
330 CoCreateGuid(guid);
332 set_device_guid(flow, key, key_name, guid);
334 if(key)
335 RegCloseKey(key);
338 static void set_stream_volumes(ACImpl *This)
340 struct set_volumes_params params;
342 params.stream = This->stream;
343 params.master_volume = (This->session->mute ? 0.0f : This->session->master_vol);
344 params.volumes = This->vols;
345 params.session_volumes = This->session->channel_vols;
346 OSS_CALL(set_volumes, &params);
349 static const OSSDevice *get_ossdevice_from_guid(const GUID *guid)
351 OSSDevice *dev_item;
352 LIST_FOR_EACH_ENTRY(dev_item, &g_devices, OSSDevice, entry)
353 if(IsEqualGUID(guid, &dev_item->guid))
354 return dev_item;
355 return NULL;
358 static void device_add(OSSDevice *oss_dev)
360 if(get_ossdevice_from_guid(&oss_dev->guid)) /* already in list */
361 HeapFree(GetProcessHeap(), 0, oss_dev);
362 else
363 list_add_tail(&g_devices, &oss_dev->entry);
366 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids_out, GUID **guids_out,
367 UINT *num, UINT *def_index)
369 struct get_endpoint_ids_params params;
370 GUID *guids = NULL;
371 WCHAR **ids = NULL;
372 unsigned int i;
374 TRACE("%d %p %p %p %p\n", flow, ids, guids, num, def_index);
376 params.flow = flow;
377 params.size = 1000;
378 params.endpoints = NULL;
380 HeapFree(GetProcessHeap(), 0, params.endpoints);
381 params.endpoints = HeapAlloc(GetProcessHeap(), 0, params.size);
382 OSS_CALL(get_endpoint_ids, &params);
383 }while(params.result == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
385 if(FAILED(params.result)) goto end;
387 ids = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, params.num * sizeof(*ids));
388 guids = HeapAlloc(GetProcessHeap(), 0, params.num * sizeof(*guids));
389 if(!ids || !guids){
390 params.result = E_OUTOFMEMORY;
391 goto end;
394 for(i = 0; i < params.num; i++){
395 WCHAR *name = (WCHAR *)((char *)params.endpoints + params.endpoints[i].name);
396 char *device = (char *)params.endpoints + params.endpoints[i].device;
397 unsigned int name_size = (wcslen(name) + 1) * sizeof(WCHAR);
398 unsigned int dev_size = strlen(device) + 1;
399 OSSDevice *oss_dev;
401 ids[i] = HeapAlloc(GetProcessHeap(), 0, name_size);
402 oss_dev = HeapAlloc(GetProcessHeap(), 0, offsetof(OSSDevice, devnode[dev_size]));
403 if(!ids[i] || !oss_dev){
404 HeapFree(GetProcessHeap(), 0, oss_dev);
405 params.result = E_OUTOFMEMORY;
406 goto end;
408 memcpy(ids[i], name, name_size);
409 get_device_guid(flow, device, guids + i);
411 oss_dev->flow = flow;
412 oss_dev->guid = guids[i];
413 memcpy(oss_dev->devnode, device, dev_size);
414 device_add(oss_dev);
416 *def_index = params.default_idx;
418 end:
419 HeapFree(GetProcessHeap(), 0, params.endpoints);
420 if(FAILED(params.result)){
421 HeapFree(GetProcessHeap(), 0, guids);
422 if(ids){
423 for(i = 0; i < params.num; i++)
424 HeapFree(GetProcessHeap(), 0, ids[i]);
425 HeapFree(GetProcessHeap(), 0, ids);
427 }else{
428 *ids_out = ids;
429 *guids_out = guids;
430 *num = params.num;
433 return params.result;
436 HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev,
437 IAudioClient **out)
439 ACImpl *This;
440 const OSSDevice *oss_dev;
441 HRESULT hr;
442 int len;
444 TRACE("%s %p %p\n", debugstr_guid(guid), dev, out);
446 oss_dev = get_ossdevice_from_guid(guid);
447 if(!oss_dev){
448 WARN("Unknown GUID: %s\n", debugstr_guid(guid));
449 return AUDCLNT_E_DEVICE_INVALIDATED;
451 len = strlen(oss_dev->devnode);
452 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, offsetof(ACImpl, devnode[len + 1]));
453 if(!This)
454 return E_OUTOFMEMORY;
456 hr = CoCreateFreeThreadedMarshaler((IUnknown *)&This->IAudioClient3_iface, &This->pUnkFTMarshal);
457 if (FAILED(hr)) {
458 HeapFree(GetProcessHeap(), 0, This);
459 return hr;
462 This->dataflow = oss_dev->flow;
463 strcpy(This->devnode, oss_dev->devnode);
465 This->IAudioClient3_iface.lpVtbl = &AudioClient3_Vtbl;
466 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
467 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
468 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
469 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
470 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
472 This->parent = dev;
473 IMMDevice_AddRef(This->parent);
475 *out = (IAudioClient *)&This->IAudioClient3_iface;
476 IAudioClient3_AddRef(&This->IAudioClient3_iface);
478 return S_OK;
481 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient3 *iface,
482 REFIID riid, void **ppv)
484 ACImpl *This = impl_from_IAudioClient3(iface);
485 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
487 if(!ppv)
488 return E_POINTER;
489 *ppv = NULL;
490 if(IsEqualIID(riid, &IID_IUnknown) ||
491 IsEqualIID(riid, &IID_IAudioClient) ||
492 IsEqualIID(riid, &IID_IAudioClient2) ||
493 IsEqualIID(riid, &IID_IAudioClient3))
494 *ppv = iface;
495 else if(IsEqualIID(riid, &IID_IMarshal))
496 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
497 if(*ppv){
498 IUnknown_AddRef((IUnknown*)*ppv);
499 return S_OK;
501 WARN("Unknown interface %s\n", debugstr_guid(riid));
502 return E_NOINTERFACE;
505 static ULONG WINAPI AudioClient_AddRef(IAudioClient3 *iface)
507 ACImpl *This = impl_from_IAudioClient3(iface);
508 ULONG ref;
509 ref = InterlockedIncrement(&This->ref);
510 TRACE("(%p) Refcount now %lu\n", This, ref);
511 return ref;
514 static ULONG WINAPI AudioClient_Release(IAudioClient3 *iface)
516 ACImpl *This = impl_from_IAudioClient3(iface);
517 ULONG ref;
519 ref = InterlockedDecrement(&This->ref);
520 TRACE("(%p) Refcount now %lu\n", This, ref);
521 if(!ref){
522 IAudioClient3_Stop(iface);
523 IMMDevice_Release(This->parent);
524 IUnknown_Release(This->pUnkFTMarshal);
525 if(This->session){
526 EnterCriticalSection(&g_sessions_lock);
527 list_remove(&This->entry);
528 LeaveCriticalSection(&g_sessions_lock);
530 HeapFree(GetProcessHeap(), 0, This->vols);
531 if(This->stream)
532 stream_release(This->stream, This->timer_thread);
533 HeapFree(GetProcessHeap(), 0, This);
535 return ref;
538 static void dump_fmt(const WAVEFORMATEX *fmt)
540 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
541 switch(fmt->wFormatTag){
542 case WAVE_FORMAT_PCM:
543 TRACE("WAVE_FORMAT_PCM");
544 break;
545 case WAVE_FORMAT_IEEE_FLOAT:
546 TRACE("WAVE_FORMAT_IEEE_FLOAT");
547 break;
548 case WAVE_FORMAT_EXTENSIBLE:
549 TRACE("WAVE_FORMAT_EXTENSIBLE");
550 break;
551 default:
552 TRACE("Unknown");
553 break;
555 TRACE(")\n");
557 TRACE("nChannels: %u\n", fmt->nChannels);
558 TRACE("nSamplesPerSec: %lu\n", fmt->nSamplesPerSec);
559 TRACE("nAvgBytesPerSec: %lu\n", fmt->nAvgBytesPerSec);
560 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
561 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
562 TRACE("cbSize: %u\n", fmt->cbSize);
564 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
565 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
566 TRACE("dwChannelMask: %08lx\n", fmtex->dwChannelMask);
567 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
568 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
572 static void session_init_vols(AudioSession *session, UINT channels)
574 if(session->channel_count < channels){
575 UINT i;
577 if(session->channel_vols)
578 session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
579 session->channel_vols, sizeof(float) * channels);
580 else
581 session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
582 sizeof(float) * channels);
583 if(!session->channel_vols)
584 return;
586 for(i = session->channel_count; i < channels; ++i)
587 session->channel_vols[i] = 1.f;
589 session->channel_count = channels;
593 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
594 UINT num_channels)
596 AudioSession *ret;
598 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
599 if(!ret)
600 return NULL;
602 memcpy(&ret->guid, guid, sizeof(GUID));
604 ret->device = device;
606 list_init(&ret->clients);
608 list_add_head(&g_sessions, &ret->entry);
610 session_init_vols(ret, num_channels);
612 ret->master_vol = 1.f;
614 return ret;
617 /* if channels == 0, then this will return or create a session with
618 * matching dataflow and GUID. otherwise, channels must also match */
619 static HRESULT get_audio_session(const GUID *sessionguid,
620 IMMDevice *device, UINT channels, AudioSession **out)
622 AudioSession *session;
624 if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
625 *out = create_session(&GUID_NULL, device, channels);
626 if(!*out)
627 return E_OUTOFMEMORY;
629 return S_OK;
632 *out = NULL;
633 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
634 if(session->device == device &&
635 IsEqualGUID(sessionguid, &session->guid)){
636 session_init_vols(session, channels);
637 *out = session;
638 break;
642 if(!*out){
643 *out = create_session(sessionguid, device, channels);
644 if(!*out)
645 return E_OUTOFMEMORY;
648 return S_OK;
651 static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
652 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
653 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
654 const GUID *sessionguid)
656 ACImpl *This = impl_from_IAudioClient3(iface);
657 struct create_stream_params params;
658 stream_handle stream;
659 unsigned int i;
661 TRACE("(%p)->(%x, %lx, %s, %s, %p, %s)\n", This, mode, flags,
662 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
664 if(!fmt)
665 return E_POINTER;
667 dump_fmt(fmt);
669 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
670 return E_INVALIDARG;
672 if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
673 AUDCLNT_STREAMFLAGS_LOOPBACK |
674 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
675 AUDCLNT_STREAMFLAGS_NOPERSIST |
676 AUDCLNT_STREAMFLAGS_RATEADJUST |
677 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
678 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
679 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED |
680 AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY |
681 AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM)){
682 FIXME("Unknown flags: %08lx\n", flags);
683 return E_INVALIDARG;
686 if(mode == AUDCLNT_SHAREMODE_SHARED){
687 period = DefaultPeriod;
688 if( duration < 3 * period)
689 duration = 3 * period;
690 }else{
691 if(!period)
692 period = DefaultPeriod; /* not minimum */
693 if(period < MinimumPeriod || period > 5000000)
694 return AUDCLNT_E_INVALID_DEVICE_PERIOD;
695 if(duration > 20000000) /* the smaller the period, the lower this limit */
696 return AUDCLNT_E_BUFFER_SIZE_ERROR;
697 if(flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK){
698 if(duration != period)
699 return AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL;
700 FIXME("EXCLUSIVE mode with EVENTCALLBACK\n");
701 return AUDCLNT_E_DEVICE_IN_USE;
702 }else{
703 if( duration < 8 * period)
704 duration = 8 * period; /* may grow above 2s */
708 EnterCriticalSection(&g_sessions_lock);
710 if(This->stream){
711 LeaveCriticalSection(&g_sessions_lock);
712 return AUDCLNT_E_ALREADY_INITIALIZED;
715 params.name = NULL;
716 params.device = This->devnode;
717 params.flow = This->dataflow;
718 params.share = mode;
719 params.flags = flags;
720 params.duration = duration;
721 params.period = period;
722 params.fmt = fmt;
723 params.channel_count = NULL;
724 params.stream = &stream;
726 OSS_CALL(create_stream, &params);
727 if(FAILED(params.result)){
728 LeaveCriticalSection(&g_sessions_lock);
729 return params.result;
732 This->channel_count = fmt->nChannels;
733 This->vols = HeapAlloc(GetProcessHeap(), 0, This->channel_count * sizeof(float));
734 if(!This->vols){
735 params.result = E_OUTOFMEMORY;
736 goto exit;
738 for(i = 0; i < This->channel_count; ++i)
739 This->vols[i] = 1.f;
741 params.result = get_audio_session(sessionguid, This->parent, This->channel_count,
742 &This->session);
744 exit:
745 if(FAILED(params.result)){
746 stream_release(stream, NULL);
747 HeapFree(GetProcessHeap(), 0, This->vols);
748 This->vols = NULL;
749 } else {
750 list_add_tail(&This->session->clients, &This->entry);
751 This->stream = stream;
752 set_stream_volumes(This);
755 LeaveCriticalSection(&g_sessions_lock);
757 return params.result;
760 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient3 *iface,
761 UINT32 *frames)
763 ACImpl *This = impl_from_IAudioClient3(iface);
764 struct get_buffer_size_params params;
766 TRACE("(%p)->(%p)\n", This, frames);
768 if(!frames)
769 return E_POINTER;
771 if(!This->stream)
772 return AUDCLNT_E_NOT_INITIALIZED;
774 params.stream = This->stream;
775 params.size = frames;
777 OSS_CALL(get_buffer_size, &params);
778 TRACE("buffer size: %u\n", *frames);
780 return params.result;
783 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient3 *iface,
784 REFERENCE_TIME *latency)
786 ACImpl *This = impl_from_IAudioClient3(iface);
787 struct get_latency_params params;
789 TRACE("(%p)->(%p)\n", This, latency);
791 if(!latency)
792 return E_POINTER;
794 if(!This->stream)
795 return AUDCLNT_E_NOT_INITIALIZED;
797 params.stream = This->stream;
798 params.latency = latency;
799 OSS_CALL(get_latency, &params);
801 return params.result;
804 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient3 *iface,
805 UINT32 *numpad)
807 ACImpl *This = impl_from_IAudioClient3(iface);
808 struct get_current_padding_params params;
810 TRACE("(%p)->(%p)\n", This, numpad);
812 if(!numpad)
813 return E_POINTER;
815 if(!This->stream)
816 return AUDCLNT_E_NOT_INITIALIZED;
818 params.stream = This->stream;
819 params.padding = numpad;
820 OSS_CALL(get_current_padding, &params);
821 TRACE("padding: %u\n", *numpad);
823 return params.result;
826 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient3 *iface,
827 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *fmt,
828 WAVEFORMATEX **out)
830 ACImpl *This = impl_from_IAudioClient3(iface);
831 struct is_format_supported_params params;
833 TRACE("(%p)->(%x, %p, %p)\n", This, mode, fmt, out);
834 if(fmt) dump_fmt(fmt);
836 params.device = This->devnode;
837 params.flow = This->dataflow;
838 params.share = mode;
839 params.fmt_in = fmt;
840 params.fmt_out = NULL;
842 if(out){
843 *out = NULL;
844 if(mode == AUDCLNT_SHAREMODE_SHARED)
845 params.fmt_out = CoTaskMemAlloc(sizeof(*params.fmt_out));
847 OSS_CALL(is_format_supported, &params);
849 if(params.result == S_FALSE)
850 *out = &params.fmt_out->Format;
851 else
852 CoTaskMemFree(params.fmt_out);
854 return params.result;
857 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface,
858 WAVEFORMATEX **pwfx)
860 ACImpl *This = impl_from_IAudioClient3(iface);
861 struct get_mix_format_params params;
863 TRACE("(%p)->(%p)\n", This, pwfx);
865 if(!pwfx)
866 return E_POINTER;
867 *pwfx = NULL;
869 params.device = This->devnode;
870 params.flow = This->dataflow;
871 params.fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
872 if(!params.fmt)
873 return E_OUTOFMEMORY;
875 OSS_CALL(get_mix_format, &params);
877 if(SUCCEEDED(params.result)){
878 *pwfx = &params.fmt->Format;
879 dump_fmt(*pwfx);
880 } else
881 CoTaskMemFree(params.fmt);
883 return params.result;
886 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient3 *iface,
887 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
889 ACImpl *This = impl_from_IAudioClient3(iface);
891 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
893 if(!defperiod && !minperiod)
894 return E_POINTER;
896 if(defperiod)
897 *defperiod = DefaultPeriod;
898 if(minperiod)
899 *minperiod = MinimumPeriod;
901 return S_OK;
904 static HRESULT WINAPI AudioClient_Start(IAudioClient3 *iface)
906 ACImpl *This = impl_from_IAudioClient3(iface);
907 struct start_params params;
909 TRACE("(%p)\n", This);
911 EnterCriticalSection(&g_sessions_lock);
913 if(!This->stream){
914 LeaveCriticalSection(&g_sessions_lock);
915 return AUDCLNT_E_NOT_INITIALIZED;
918 params.stream = This->stream;
919 OSS_CALL(start, &params);
921 if(SUCCEEDED(params.result) && !This->timer_thread){
922 This->timer_thread = CreateThread(NULL, 0, timer_thread, This, 0, NULL);
923 SetThreadPriority(This->timer_thread, THREAD_PRIORITY_TIME_CRITICAL);
926 LeaveCriticalSection(&g_sessions_lock);
928 return params.result;
931 static HRESULT WINAPI AudioClient_Stop(IAudioClient3 *iface)
933 ACImpl *This = impl_from_IAudioClient3(iface);
934 struct stop_params params;
936 TRACE("(%p)\n", This);
938 if(!This->stream)
939 return AUDCLNT_E_NOT_INITIALIZED;
941 params.stream = This->stream;
942 OSS_CALL(stop, &params);
944 return params.result;
947 static HRESULT WINAPI AudioClient_Reset(IAudioClient3 *iface)
949 ACImpl *This = impl_from_IAudioClient3(iface);
950 struct reset_params params;
952 TRACE("(%p)\n", This);
954 if(!This->stream)
955 return AUDCLNT_E_NOT_INITIALIZED;
957 params.stream = This->stream;
958 OSS_CALL(reset, &params);
960 return params.result;
963 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient3 *iface,
964 HANDLE event)
966 ACImpl *This = impl_from_IAudioClient3(iface);
967 struct set_event_handle_params params;
969 TRACE("(%p)->(%p)\n", This, event);
971 if(!event)
972 return E_INVALIDARG;
974 if(!This->stream)
975 return AUDCLNT_E_NOT_INITIALIZED;
977 params.stream = This->stream;
978 params.event = event;
979 OSS_CALL(set_event_handle, &params);
981 return params.result;
984 static HRESULT WINAPI AudioClient_GetService(IAudioClient3 *iface, REFIID riid,
985 void **ppv)
987 ACImpl *This = impl_from_IAudioClient3(iface);
989 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
991 if(!ppv)
992 return E_POINTER;
993 *ppv = NULL;
995 EnterCriticalSection(&g_sessions_lock);
997 if(!This->stream){
998 LeaveCriticalSection(&g_sessions_lock);
999 return AUDCLNT_E_NOT_INITIALIZED;
1002 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1003 if(This->dataflow != eRender){
1004 LeaveCriticalSection(&g_sessions_lock);
1005 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1007 IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
1008 *ppv = &This->IAudioRenderClient_iface;
1009 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1010 if(This->dataflow != eCapture){
1011 LeaveCriticalSection(&g_sessions_lock);
1012 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1014 IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
1015 *ppv = &This->IAudioCaptureClient_iface;
1016 }else if(IsEqualIID(riid, &IID_IAudioClock)){
1017 IAudioClock_AddRef(&This->IAudioClock_iface);
1018 *ppv = &This->IAudioClock_iface;
1019 }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1020 IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
1021 *ppv = &This->IAudioStreamVolume_iface;
1022 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1023 if(!This->session_wrapper){
1024 This->session_wrapper = AudioSessionWrapper_Create(This);
1025 if(!This->session_wrapper){
1026 LeaveCriticalSection(&g_sessions_lock);
1027 return E_OUTOFMEMORY;
1029 }else
1030 IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
1032 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1033 }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1034 if(!This->session_wrapper){
1035 This->session_wrapper = AudioSessionWrapper_Create(This);
1036 if(!This->session_wrapper){
1037 LeaveCriticalSection(&g_sessions_lock);
1038 return E_OUTOFMEMORY;
1040 }else
1041 IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
1043 *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1044 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1045 if(!This->session_wrapper){
1046 This->session_wrapper = AudioSessionWrapper_Create(This);
1047 if(!This->session_wrapper){
1048 LeaveCriticalSection(&g_sessions_lock);
1049 return E_OUTOFMEMORY;
1051 }else
1052 ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
1054 *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1057 if(*ppv){
1058 LeaveCriticalSection(&g_sessions_lock);
1059 return S_OK;
1062 LeaveCriticalSection(&g_sessions_lock);
1064 FIXME("stub %s\n", debugstr_guid(riid));
1065 return E_NOINTERFACE;
1068 static HRESULT WINAPI AudioClient_IsOffloadCapable(IAudioClient3 *iface,
1069 AUDIO_STREAM_CATEGORY category, BOOL *offload_capable)
1071 ACImpl *This = impl_from_IAudioClient3(iface);
1073 TRACE("(%p)->(0x%x, %p)\n", This, category, offload_capable);
1075 if(!offload_capable)
1076 return E_INVALIDARG;
1078 *offload_capable = FALSE;
1080 return S_OK;
1083 static HRESULT WINAPI AudioClient_SetClientProperties(IAudioClient3 *iface,
1084 const AudioClientProperties *prop)
1086 ACImpl *This = impl_from_IAudioClient3(iface);
1087 const Win8AudioClientProperties *legacy_prop = (const Win8AudioClientProperties *)prop;
1089 TRACE("(%p)->(%p)\n", This, prop);
1091 if(!legacy_prop)
1092 return E_POINTER;
1094 if(legacy_prop->cbSize == sizeof(AudioClientProperties)){
1095 TRACE("{ bIsOffload: %u, eCategory: 0x%x, Options: 0x%x }\n",
1096 legacy_prop->bIsOffload,
1097 legacy_prop->eCategory,
1098 prop->Options);
1099 }else if(legacy_prop->cbSize == sizeof(Win8AudioClientProperties)){
1100 TRACE("{ bIsOffload: %u, eCategory: 0x%x }\n",
1101 legacy_prop->bIsOffload,
1102 legacy_prop->eCategory);
1103 }else{
1104 WARN("Unsupported Size = %d\n", legacy_prop->cbSize);
1105 return E_INVALIDARG;
1109 if(legacy_prop->bIsOffload)
1110 return AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE;
1112 return S_OK;
1115 static HRESULT WINAPI AudioClient_GetBufferSizeLimits(IAudioClient3 *iface,
1116 const WAVEFORMATEX *format, BOOL event_driven, REFERENCE_TIME *min_duration,
1117 REFERENCE_TIME *max_duration)
1119 ACImpl *This = impl_from_IAudioClient3(iface);
1121 FIXME("(%p)->(%p, %u, %p, %p)\n", This, format, event_driven, min_duration, max_duration);
1123 return E_NOTIMPL;
1126 static HRESULT WINAPI AudioClient_GetSharedModeEnginePeriod(IAudioClient3 *iface,
1127 const WAVEFORMATEX *format, UINT32 *default_period_frames, UINT32 *unit_period_frames,
1128 UINT32 *min_period_frames, UINT32 *max_period_frames)
1130 ACImpl *This = impl_from_IAudioClient3(iface);
1132 FIXME("(%p)->(%p, %p, %p, %p, %p)\n", This, format, default_period_frames, unit_period_frames,
1133 min_period_frames, max_period_frames);
1135 return E_NOTIMPL;
1138 static HRESULT WINAPI AudioClient_GetCurrentSharedModeEnginePeriod(IAudioClient3 *iface,
1139 WAVEFORMATEX **cur_format, UINT32 *cur_period_frames)
1141 ACImpl *This = impl_from_IAudioClient3(iface);
1143 FIXME("(%p)->(%p, %p)\n", This, cur_format, cur_period_frames);
1145 return E_NOTIMPL;
1148 static HRESULT WINAPI AudioClient_InitializeSharedAudioStream(IAudioClient3 *iface,
1149 DWORD flags, UINT32 period_frames, const WAVEFORMATEX *format,
1150 const GUID *session_guid)
1152 ACImpl *This = impl_from_IAudioClient3(iface);
1154 FIXME("(%p)->(0x%lx, %u, %p, %s)\n", This, flags, period_frames, format, debugstr_guid(session_guid));
1156 return E_NOTIMPL;
1159 static const IAudioClient3Vtbl AudioClient3_Vtbl =
1161 AudioClient_QueryInterface,
1162 AudioClient_AddRef,
1163 AudioClient_Release,
1164 AudioClient_Initialize,
1165 AudioClient_GetBufferSize,
1166 AudioClient_GetStreamLatency,
1167 AudioClient_GetCurrentPadding,
1168 AudioClient_IsFormatSupported,
1169 AudioClient_GetMixFormat,
1170 AudioClient_GetDevicePeriod,
1171 AudioClient_Start,
1172 AudioClient_Stop,
1173 AudioClient_Reset,
1174 AudioClient_SetEventHandle,
1175 AudioClient_GetService,
1176 AudioClient_IsOffloadCapable,
1177 AudioClient_SetClientProperties,
1178 AudioClient_GetBufferSizeLimits,
1179 AudioClient_GetSharedModeEnginePeriod,
1180 AudioClient_GetCurrentSharedModeEnginePeriod,
1181 AudioClient_InitializeSharedAudioStream,
1184 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1185 IAudioRenderClient *iface, REFIID riid, void **ppv)
1187 ACImpl *This = impl_from_IAudioRenderClient(iface);
1188 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1190 if(!ppv)
1191 return E_POINTER;
1192 *ppv = NULL;
1194 if(IsEqualIID(riid, &IID_IUnknown) ||
1195 IsEqualIID(riid, &IID_IAudioRenderClient))
1196 *ppv = iface;
1197 else if(IsEqualIID(riid, &IID_IMarshal))
1198 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
1199 if(*ppv){
1200 IUnknown_AddRef((IUnknown*)*ppv);
1201 return S_OK;
1204 WARN("Unknown interface %s\n", debugstr_guid(riid));
1205 return E_NOINTERFACE;
1208 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1210 ACImpl *This = impl_from_IAudioRenderClient(iface);
1211 return AudioClient_AddRef(&This->IAudioClient3_iface);
1214 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1216 ACImpl *This = impl_from_IAudioRenderClient(iface);
1217 return AudioClient_Release(&This->IAudioClient3_iface);
1220 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1221 UINT32 frames, BYTE **data)
1223 ACImpl *This = impl_from_IAudioRenderClient(iface);
1224 struct get_render_buffer_params params;
1226 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1228 if(!data)
1229 return E_POINTER;
1231 *data = NULL;
1233 params.stream = This->stream;
1234 params.frames = frames;
1235 params.data = data;
1236 OSS_CALL(get_render_buffer, &params);
1238 return params.result;
1241 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1242 IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
1244 ACImpl *This = impl_from_IAudioRenderClient(iface);
1245 struct release_render_buffer_params params;
1247 TRACE("(%p)->(%u, %lx)\n", This, written_frames, flags);
1249 params.stream = This->stream;
1250 params.written_frames = written_frames;
1251 params.flags = flags;
1252 OSS_CALL(release_render_buffer, &params);
1254 return params.result;
1257 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1258 AudioRenderClient_QueryInterface,
1259 AudioRenderClient_AddRef,
1260 AudioRenderClient_Release,
1261 AudioRenderClient_GetBuffer,
1262 AudioRenderClient_ReleaseBuffer
1265 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1266 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1268 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1269 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1271 if(!ppv)
1272 return E_POINTER;
1273 *ppv = NULL;
1275 if(IsEqualIID(riid, &IID_IUnknown) ||
1276 IsEqualIID(riid, &IID_IAudioCaptureClient))
1277 *ppv = iface;
1278 else if(IsEqualIID(riid, &IID_IMarshal))
1279 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
1280 if(*ppv){
1281 IUnknown_AddRef((IUnknown*)*ppv);
1282 return S_OK;
1285 WARN("Unknown interface %s\n", debugstr_guid(riid));
1286 return E_NOINTERFACE;
1289 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1291 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1292 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1295 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1297 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1298 return IAudioClient3_Release(&This->IAudioClient3_iface);
1301 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1302 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1303 UINT64 *qpcpos)
1305 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1306 struct get_capture_buffer_params params;
1308 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1309 devpos, qpcpos);
1311 if(!data)
1312 return E_POINTER;
1314 *data = NULL;
1316 if(!frames || !flags)
1317 return E_POINTER;
1319 params.stream = This->stream;
1320 params.data = data;
1321 params.frames = frames;
1322 params.flags = (UINT*)flags;
1323 params.devpos = devpos;
1324 params.qpcpos = qpcpos;
1325 OSS_CALL(get_capture_buffer, &params);
1327 return params.result;
1330 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1331 IAudioCaptureClient *iface, UINT32 done)
1333 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1334 struct release_capture_buffer_params params;
1336 TRACE("(%p)->(%u)\n", This, done);
1338 params.stream = This->stream;
1339 params.done = done;
1340 OSS_CALL(release_capture_buffer, &params);
1342 return params.result;
1345 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1346 IAudioCaptureClient *iface, UINT32 *frames)
1348 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1349 struct get_next_packet_size_params params;
1351 TRACE("(%p)->(%p)\n", This, frames);
1353 if(!frames)
1354 return E_POINTER;
1356 params.stream = This->stream;
1357 params.frames = frames;
1358 OSS_CALL(get_next_packet_size, &params);
1360 return params.result;
1363 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1365 AudioCaptureClient_QueryInterface,
1366 AudioCaptureClient_AddRef,
1367 AudioCaptureClient_Release,
1368 AudioCaptureClient_GetBuffer,
1369 AudioCaptureClient_ReleaseBuffer,
1370 AudioCaptureClient_GetNextPacketSize
1373 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1374 REFIID riid, void **ppv)
1376 ACImpl *This = impl_from_IAudioClock(iface);
1378 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1380 if(!ppv)
1381 return E_POINTER;
1382 *ppv = NULL;
1384 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
1385 *ppv = iface;
1386 else if(IsEqualIID(riid, &IID_IAudioClock2))
1387 *ppv = &This->IAudioClock2_iface;
1388 if(*ppv){
1389 IUnknown_AddRef((IUnknown*)*ppv);
1390 return S_OK;
1393 WARN("Unknown interface %s\n", debugstr_guid(riid));
1394 return E_NOINTERFACE;
1397 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
1399 ACImpl *This = impl_from_IAudioClock(iface);
1400 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1403 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
1405 ACImpl *This = impl_from_IAudioClock(iface);
1406 return IAudioClient3_Release(&This->IAudioClient3_iface);
1409 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
1411 ACImpl *This = impl_from_IAudioClock(iface);
1412 struct get_frequency_params params;
1414 TRACE("(%p)->(%p)\n", This, freq);
1416 params.stream = This->stream;
1417 params.freq = freq;
1418 OSS_CALL(get_frequency, &params);
1420 return params.result;
1423 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
1424 UINT64 *qpctime)
1426 ACImpl *This = impl_from_IAudioClock(iface);
1427 struct get_position_params params;
1429 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
1431 if(!pos)
1432 return E_POINTER;
1434 params.stream = This->stream;
1435 params.device = FALSE;
1436 params.pos = pos;
1437 params.qpctime = qpctime;
1438 OSS_CALL(get_position, &params);
1440 return params.result;
1443 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
1444 DWORD *chars)
1446 ACImpl *This = impl_from_IAudioClock(iface);
1448 TRACE("(%p)->(%p)\n", This, chars);
1450 if(!chars)
1451 return E_POINTER;
1453 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
1455 return S_OK;
1458 static const IAudioClockVtbl AudioClock_Vtbl =
1460 AudioClock_QueryInterface,
1461 AudioClock_AddRef,
1462 AudioClock_Release,
1463 AudioClock_GetFrequency,
1464 AudioClock_GetPosition,
1465 AudioClock_GetCharacteristics
1468 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
1469 REFIID riid, void **ppv)
1471 ACImpl *This = impl_from_IAudioClock2(iface);
1472 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
1475 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
1477 ACImpl *This = impl_from_IAudioClock2(iface);
1478 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1481 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
1483 ACImpl *This = impl_from_IAudioClock2(iface);
1484 return IAudioClient3_Release(&This->IAudioClient3_iface);
1487 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
1488 UINT64 *pos, UINT64 *qpctime)
1490 ACImpl *This = impl_from_IAudioClock2(iface);
1492 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
1494 return E_NOTIMPL;
1497 static const IAudioClock2Vtbl AudioClock2_Vtbl =
1499 AudioClock2_QueryInterface,
1500 AudioClock2_AddRef,
1501 AudioClock2_Release,
1502 AudioClock2_GetDevicePosition
1505 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
1507 AudioSessionWrapper *ret;
1509 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1510 sizeof(AudioSessionWrapper));
1511 if(!ret)
1512 return NULL;
1514 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
1515 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
1516 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
1518 ret->ref = 1;
1520 ret->client = client;
1521 if(client){
1522 ret->session = client->session;
1523 AudioClient_AddRef(&client->IAudioClient3_iface);
1526 return ret;
1529 static HRESULT WINAPI AudioSessionControl_QueryInterface(
1530 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
1532 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1534 if(!ppv)
1535 return E_POINTER;
1536 *ppv = NULL;
1538 if(IsEqualIID(riid, &IID_IUnknown) ||
1539 IsEqualIID(riid, &IID_IAudioSessionControl) ||
1540 IsEqualIID(riid, &IID_IAudioSessionControl2))
1541 *ppv = iface;
1542 if(*ppv){
1543 IUnknown_AddRef((IUnknown*)*ppv);
1544 return S_OK;
1547 WARN("Unknown interface %s\n", debugstr_guid(riid));
1548 return E_NOINTERFACE;
1551 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
1553 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1554 ULONG ref;
1555 ref = InterlockedIncrement(&This->ref);
1556 TRACE("(%p) Refcount now %lu\n", This, ref);
1557 return ref;
1560 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
1562 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1563 ULONG ref;
1564 ref = InterlockedDecrement(&This->ref);
1565 TRACE("(%p) Refcount now %lu\n", This, ref);
1566 if(!ref){
1567 if(This->client){
1568 EnterCriticalSection(&g_sessions_lock);
1569 This->client->session_wrapper = NULL;
1570 LeaveCriticalSection(&g_sessions_lock);
1571 AudioClient_Release(&This->client->IAudioClient3_iface);
1573 HeapFree(GetProcessHeap(), 0, This);
1575 return ref;
1578 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
1579 AudioSessionState *state)
1581 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1582 struct is_started_params params;
1583 ACImpl *client;
1585 TRACE("(%p)->(%p)\n", This, state);
1587 if(!state)
1588 return NULL_PTR_ERR;
1590 EnterCriticalSection(&g_sessions_lock);
1592 if(list_empty(&This->session->clients)){
1593 *state = AudioSessionStateExpired;
1594 LeaveCriticalSection(&g_sessions_lock);
1595 return S_OK;
1598 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
1599 params.stream = client->stream;
1600 OSS_CALL(is_started, &params);
1601 if(params.result == S_OK){
1602 *state = AudioSessionStateActive;
1603 LeaveCriticalSection(&g_sessions_lock);
1604 return S_OK;
1608 LeaveCriticalSection(&g_sessions_lock);
1610 *state = AudioSessionStateInactive;
1612 return S_OK;
1615 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
1616 IAudioSessionControl2 *iface, WCHAR **name)
1618 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1620 FIXME("(%p)->(%p) - stub\n", This, name);
1622 return E_NOTIMPL;
1625 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
1626 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
1628 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1630 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
1632 return E_NOTIMPL;
1635 static HRESULT WINAPI AudioSessionControl_GetIconPath(
1636 IAudioSessionControl2 *iface, WCHAR **path)
1638 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1640 FIXME("(%p)->(%p) - stub\n", This, path);
1642 return E_NOTIMPL;
1645 static HRESULT WINAPI AudioSessionControl_SetIconPath(
1646 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
1648 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1650 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
1652 return E_NOTIMPL;
1655 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
1656 IAudioSessionControl2 *iface, GUID *group)
1658 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1660 FIXME("(%p)->(%p) - stub\n", This, group);
1662 return E_NOTIMPL;
1665 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
1666 IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
1668 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1670 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
1671 debugstr_guid(session));
1673 return E_NOTIMPL;
1676 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
1677 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
1679 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1681 FIXME("(%p)->(%p) - stub\n", This, events);
1683 return S_OK;
1686 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
1687 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
1689 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1691 FIXME("(%p)->(%p) - stub\n", This, events);
1693 return S_OK;
1696 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
1697 IAudioSessionControl2 *iface, WCHAR **id)
1699 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1701 FIXME("(%p)->(%p) - stub\n", This, id);
1703 return E_NOTIMPL;
1706 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
1707 IAudioSessionControl2 *iface, WCHAR **id)
1709 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1711 FIXME("(%p)->(%p) - stub\n", This, id);
1713 return E_NOTIMPL;
1716 static HRESULT WINAPI AudioSessionControl_GetProcessId(
1717 IAudioSessionControl2 *iface, DWORD *pid)
1719 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1721 TRACE("(%p)->(%p)\n", This, pid);
1723 if(!pid)
1724 return E_POINTER;
1726 *pid = GetCurrentProcessId();
1728 return S_OK;
1731 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
1732 IAudioSessionControl2 *iface)
1734 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1736 TRACE("(%p)\n", This);
1738 return S_FALSE;
1741 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
1742 IAudioSessionControl2 *iface, BOOL optout)
1744 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1746 TRACE("(%p)->(%d)\n", This, optout);
1748 return S_OK;
1751 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
1753 AudioSessionControl_QueryInterface,
1754 AudioSessionControl_AddRef,
1755 AudioSessionControl_Release,
1756 AudioSessionControl_GetState,
1757 AudioSessionControl_GetDisplayName,
1758 AudioSessionControl_SetDisplayName,
1759 AudioSessionControl_GetIconPath,
1760 AudioSessionControl_SetIconPath,
1761 AudioSessionControl_GetGroupingParam,
1762 AudioSessionControl_SetGroupingParam,
1763 AudioSessionControl_RegisterAudioSessionNotification,
1764 AudioSessionControl_UnregisterAudioSessionNotification,
1765 AudioSessionControl_GetSessionIdentifier,
1766 AudioSessionControl_GetSessionInstanceIdentifier,
1767 AudioSessionControl_GetProcessId,
1768 AudioSessionControl_IsSystemSoundsSession,
1769 AudioSessionControl_SetDuckingPreference
1772 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
1773 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
1775 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1777 if(!ppv)
1778 return E_POINTER;
1779 *ppv = NULL;
1781 if(IsEqualIID(riid, &IID_IUnknown) ||
1782 IsEqualIID(riid, &IID_ISimpleAudioVolume))
1783 *ppv = iface;
1784 if(*ppv){
1785 IUnknown_AddRef((IUnknown*)*ppv);
1786 return S_OK;
1789 WARN("Unknown interface %s\n", debugstr_guid(riid));
1790 return E_NOINTERFACE;
1793 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
1795 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1796 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
1799 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
1801 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1802 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
1805 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
1806 ISimpleAudioVolume *iface, float level, const GUID *context)
1808 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1809 AudioSession *session = This->session;
1810 ACImpl *client;
1812 TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
1814 if(level < 0.f || level > 1.f)
1815 return E_INVALIDARG;
1817 if(context)
1818 FIXME("Notifications not supported yet\n");
1820 EnterCriticalSection(&g_sessions_lock);
1822 session->master_vol = level;
1824 TRACE("OSS doesn't support setting volume\n");
1825 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
1826 set_stream_volumes(client);
1828 LeaveCriticalSection(&g_sessions_lock);
1830 return S_OK;
1833 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
1834 ISimpleAudioVolume *iface, float *level)
1836 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1837 AudioSession *session = This->session;
1839 TRACE("(%p)->(%p)\n", session, level);
1841 if(!level)
1842 return NULL_PTR_ERR;
1844 *level = session->master_vol;
1846 return S_OK;
1849 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
1850 BOOL mute, const GUID *context)
1852 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1853 AudioSession *session = This->session;
1854 ACImpl *client;
1856 TRACE("(%p)->(%u, %s)\n", session, mute, debugstr_guid(context));
1858 EnterCriticalSection(&g_sessions_lock);
1860 session->mute = mute;
1862 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
1863 set_stream_volumes(client);
1865 LeaveCriticalSection(&g_sessions_lock);
1867 return S_OK;
1870 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
1871 BOOL *mute)
1873 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1874 AudioSession *session = This->session;
1876 TRACE("(%p)->(%p)\n", session, mute);
1878 if(!mute)
1879 return NULL_PTR_ERR;
1881 *mute = This->session->mute;
1883 return S_OK;
1886 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
1888 SimpleAudioVolume_QueryInterface,
1889 SimpleAudioVolume_AddRef,
1890 SimpleAudioVolume_Release,
1891 SimpleAudioVolume_SetMasterVolume,
1892 SimpleAudioVolume_GetMasterVolume,
1893 SimpleAudioVolume_SetMute,
1894 SimpleAudioVolume_GetMute
1897 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
1898 IAudioStreamVolume *iface, REFIID riid, void **ppv)
1900 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1902 if(!ppv)
1903 return E_POINTER;
1904 *ppv = NULL;
1906 if(IsEqualIID(riid, &IID_IUnknown) ||
1907 IsEqualIID(riid, &IID_IAudioStreamVolume))
1908 *ppv = iface;
1909 if(*ppv){
1910 IUnknown_AddRef((IUnknown*)*ppv);
1911 return S_OK;
1914 WARN("Unknown interface %s\n", debugstr_guid(riid));
1915 return E_NOINTERFACE;
1918 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
1920 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1921 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1924 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
1926 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1927 return IAudioClient3_Release(&This->IAudioClient3_iface);
1930 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
1931 IAudioStreamVolume *iface, UINT32 *out)
1933 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1935 TRACE("(%p)->(%p)\n", This, out);
1937 if(!out)
1938 return E_POINTER;
1940 *out = This->channel_count;
1942 return S_OK;
1945 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
1946 IAudioStreamVolume *iface, UINT32 index, float level)
1948 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1950 TRACE("(%p)->(%d, %f)\n", This, index, level);
1952 if(level < 0.f || level > 1.f)
1953 return E_INVALIDARG;
1955 if(index >= This->channel_count)
1956 return E_INVALIDARG;
1958 EnterCriticalSection(&g_sessions_lock);
1960 This->vols[index] = level;
1962 TRACE("OSS doesn't support setting volume\n");
1963 set_stream_volumes(This);
1965 LeaveCriticalSection(&g_sessions_lock);
1967 return S_OK;
1970 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
1971 IAudioStreamVolume *iface, UINT32 index, float *level)
1973 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1975 TRACE("(%p)->(%d, %p)\n", This, index, level);
1977 if(!level)
1978 return E_POINTER;
1980 if(index >= This->channel_count)
1981 return E_INVALIDARG;
1983 *level = This->vols[index];
1985 return S_OK;
1988 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
1989 IAudioStreamVolume *iface, UINT32 count, const float *levels)
1991 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1992 int i;
1994 TRACE("(%p)->(%d, %p)\n", This, count, levels);
1996 if(!levels)
1997 return E_POINTER;
1999 if(count != This->channel_count)
2000 return E_INVALIDARG;
2002 EnterCriticalSection(&g_sessions_lock);
2004 for(i = 0; i < count; ++i)
2005 This->vols[i] = levels[i];
2007 TRACE("OSS doesn't support setting volume\n");
2008 set_stream_volumes(This);
2010 LeaveCriticalSection(&g_sessions_lock);
2012 return S_OK;
2015 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2016 IAudioStreamVolume *iface, UINT32 count, float *levels)
2018 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2019 int i;
2021 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2023 if(!levels)
2024 return E_POINTER;
2026 if(count != This->channel_count)
2027 return E_INVALIDARG;
2029 EnterCriticalSection(&g_sessions_lock);
2031 for(i = 0; i < count; ++i)
2032 levels[i] = This->vols[i];
2034 LeaveCriticalSection(&g_sessions_lock);
2036 return S_OK;
2039 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2041 AudioStreamVolume_QueryInterface,
2042 AudioStreamVolume_AddRef,
2043 AudioStreamVolume_Release,
2044 AudioStreamVolume_GetChannelCount,
2045 AudioStreamVolume_SetChannelVolume,
2046 AudioStreamVolume_GetChannelVolume,
2047 AudioStreamVolume_SetAllVolumes,
2048 AudioStreamVolume_GetAllVolumes
2051 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2052 IChannelAudioVolume *iface, REFIID riid, void **ppv)
2054 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2056 if(!ppv)
2057 return E_POINTER;
2058 *ppv = NULL;
2060 if(IsEqualIID(riid, &IID_IUnknown) ||
2061 IsEqualIID(riid, &IID_IChannelAudioVolume))
2062 *ppv = iface;
2063 if(*ppv){
2064 IUnknown_AddRef((IUnknown*)*ppv);
2065 return S_OK;
2068 WARN("Unknown interface %s\n", debugstr_guid(riid));
2069 return E_NOINTERFACE;
2072 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2074 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2075 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2078 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2080 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2081 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2084 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2085 IChannelAudioVolume *iface, UINT32 *out)
2087 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2088 AudioSession *session = This->session;
2090 TRACE("(%p)->(%p)\n", session, out);
2092 if(!out)
2093 return NULL_PTR_ERR;
2095 *out = session->channel_count;
2097 return S_OK;
2100 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2101 IChannelAudioVolume *iface, UINT32 index, float level,
2102 const GUID *context)
2104 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2105 AudioSession *session = This->session;
2106 ACImpl *client;
2108 TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2109 wine_dbgstr_guid(context));
2111 if(level < 0.f || level > 1.f)
2112 return E_INVALIDARG;
2114 if(index >= session->channel_count)
2115 return E_INVALIDARG;
2117 if(context)
2118 FIXME("Notifications not supported yet\n");
2120 EnterCriticalSection(&g_sessions_lock);
2122 session->channel_vols[index] = level;
2124 TRACE("OSS doesn't support setting volume\n");
2125 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
2126 set_stream_volumes(client);
2128 LeaveCriticalSection(&g_sessions_lock);
2130 return S_OK;
2133 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2134 IChannelAudioVolume *iface, UINT32 index, float *level)
2136 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2137 AudioSession *session = This->session;
2139 TRACE("(%p)->(%d, %p)\n", session, index, level);
2141 if(!level)
2142 return NULL_PTR_ERR;
2144 if(index >= session->channel_count)
2145 return E_INVALIDARG;
2147 *level = session->channel_vols[index];
2149 return S_OK;
2152 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2153 IChannelAudioVolume *iface, UINT32 count, const float *levels,
2154 const GUID *context)
2156 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2157 AudioSession *session = This->session;
2158 ACImpl *client;
2159 int i;
2161 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2162 wine_dbgstr_guid(context));
2164 if(!levels)
2165 return NULL_PTR_ERR;
2167 if(count != session->channel_count)
2168 return E_INVALIDARG;
2170 if(context)
2171 FIXME("Notifications not supported yet\n");
2173 EnterCriticalSection(&g_sessions_lock);
2175 for(i = 0; i < count; ++i)
2176 session->channel_vols[i] = levels[i];
2178 TRACE("OSS doesn't support setting volume\n");
2179 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
2180 set_stream_volumes(client);
2182 LeaveCriticalSection(&g_sessions_lock);
2184 return S_OK;
2187 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2188 IChannelAudioVolume *iface, UINT32 count, float *levels)
2190 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2191 AudioSession *session = This->session;
2192 int i;
2194 TRACE("(%p)->(%d, %p)\n", session, count, levels);
2196 if(!levels)
2197 return NULL_PTR_ERR;
2199 if(count != session->channel_count)
2200 return E_INVALIDARG;
2202 for(i = 0; i < count; ++i)
2203 levels[i] = session->channel_vols[i];
2205 return S_OK;
2208 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2210 ChannelAudioVolume_QueryInterface,
2211 ChannelAudioVolume_AddRef,
2212 ChannelAudioVolume_Release,
2213 ChannelAudioVolume_GetChannelCount,
2214 ChannelAudioVolume_SetChannelVolume,
2215 ChannelAudioVolume_GetChannelVolume,
2216 ChannelAudioVolume_SetAllVolumes,
2217 ChannelAudioVolume_GetAllVolumes
2220 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2221 REFIID riid, void **ppv)
2223 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2225 if(!ppv)
2226 return E_POINTER;
2227 *ppv = NULL;
2229 if(IsEqualIID(riid, &IID_IUnknown) ||
2230 IsEqualIID(riid, &IID_IAudioSessionManager) ||
2231 IsEqualIID(riid, &IID_IAudioSessionManager2))
2232 *ppv = iface;
2233 if(*ppv){
2234 IUnknown_AddRef((IUnknown*)*ppv);
2235 return S_OK;
2238 WARN("Unknown interface %s\n", debugstr_guid(riid));
2239 return E_NOINTERFACE;
2242 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2244 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2245 ULONG ref;
2246 ref = InterlockedIncrement(&This->ref);
2247 TRACE("(%p) Refcount now %lu\n", This, ref);
2248 return ref;
2251 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2253 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2254 ULONG ref;
2255 ref = InterlockedDecrement(&This->ref);
2256 TRACE("(%p) Refcount now %lu\n", This, ref);
2257 if(!ref)
2258 HeapFree(GetProcessHeap(), 0, This);
2259 return ref;
2262 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2263 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2264 IAudioSessionControl **out)
2266 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2267 AudioSession *session;
2268 AudioSessionWrapper *wrapper;
2269 HRESULT hr;
2271 TRACE("(%p)->(%s, %lx, %p)\n", This, debugstr_guid(session_guid),
2272 flags, out);
2274 hr = get_audio_session(session_guid, This->device, 0, &session);
2275 if(FAILED(hr))
2276 return hr;
2278 wrapper = AudioSessionWrapper_Create(NULL);
2279 if(!wrapper)
2280 return E_OUTOFMEMORY;
2282 wrapper->session = session;
2284 *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
2286 return S_OK;
2289 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
2290 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2291 ISimpleAudioVolume **out)
2293 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2294 AudioSession *session;
2295 AudioSessionWrapper *wrapper;
2296 HRESULT hr;
2298 TRACE("(%p)->(%s, %lx, %p)\n", This, debugstr_guid(session_guid),
2299 flags, out);
2301 hr = get_audio_session(session_guid, This->device, 0, &session);
2302 if(FAILED(hr))
2303 return hr;
2305 wrapper = AudioSessionWrapper_Create(NULL);
2306 if(!wrapper)
2307 return E_OUTOFMEMORY;
2309 wrapper->session = session;
2311 *out = &wrapper->ISimpleAudioVolume_iface;
2313 return S_OK;
2316 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
2317 IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
2319 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2320 FIXME("(%p)->(%p) - stub\n", This, out);
2321 return E_NOTIMPL;
2324 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
2325 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2327 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2328 FIXME("(%p)->(%p) - stub\n", This, notification);
2329 return E_NOTIMPL;
2332 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
2333 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2335 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2336 FIXME("(%p)->(%p) - stub\n", This, notification);
2337 return E_NOTIMPL;
2340 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
2341 IAudioSessionManager2 *iface, const WCHAR *session_id,
2342 IAudioVolumeDuckNotification *notification)
2344 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2345 FIXME("(%p)->(%p) - stub\n", This, notification);
2346 return E_NOTIMPL;
2349 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
2350 IAudioSessionManager2 *iface,
2351 IAudioVolumeDuckNotification *notification)
2353 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2354 FIXME("(%p)->(%p) - stub\n", This, notification);
2355 return E_NOTIMPL;
2358 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
2360 AudioSessionManager_QueryInterface,
2361 AudioSessionManager_AddRef,
2362 AudioSessionManager_Release,
2363 AudioSessionManager_GetAudioSessionControl,
2364 AudioSessionManager_GetSimpleAudioVolume,
2365 AudioSessionManager_GetSessionEnumerator,
2366 AudioSessionManager_RegisterSessionNotification,
2367 AudioSessionManager_UnregisterSessionNotification,
2368 AudioSessionManager_RegisterDuckNotification,
2369 AudioSessionManager_UnregisterDuckNotification
2372 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
2373 IAudioSessionManager2 **out)
2375 SessionMgr *This;
2377 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
2378 if(!This)
2379 return E_OUTOFMEMORY;
2381 This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
2382 This->device = device;
2383 This->ref = 1;
2385 *out = &This->IAudioSessionManager2_iface;
2387 return S_OK;