wineoss: Use mmdevapi's AudioStreamVolume.
[wine.git] / dlls / wineoss.drv / mmdevdrv.c
blob1940750d4846e78d1502d95bbec2eede91d5647b
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>
22 #include <wchar.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winternl.h"
27 #include "winnls.h"
28 #include "winreg.h"
30 #include "ole2.h"
31 #include "mmdeviceapi.h"
32 #include "devpkey.h"
33 #include "dshow.h"
34 #include "dsound.h"
36 #include "initguid.h"
37 #include "endpointvolume.h"
38 #include "audiopolicy.h"
39 #include "audioclient.h"
41 #include "wine/debug.h"
42 #include "wine/list.h"
43 #include "wine/unixlib.h"
45 #include "unixlib.h"
47 #include "../mmdevapi/mmdevdrv.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(oss);
51 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
53 static const REFERENCE_TIME DefaultPeriod = 100000;
54 static const REFERENCE_TIME MinimumPeriod = 50000;
56 typedef struct _OSSDevice {
57 struct list entry;
58 EDataFlow flow;
59 GUID guid;
60 char devnode[0];
61 } OSSDevice;
63 static struct list g_devices = LIST_INIT(g_devices);
65 static WCHAR drv_key_devicesW[256];
66 static const WCHAR guidW[] = {'g','u','i','d',0};
68 static CRITICAL_SECTION g_sessions_lock;
69 static CRITICAL_SECTION_DEBUG g_sessions_lock_debug =
71 0, 0, &g_sessions_lock,
72 { &g_sessions_lock_debug.ProcessLocksList, &g_sessions_lock_debug.ProcessLocksList },
73 0, 0, { (DWORD_PTR)(__FILE__ ": g_sessions_lock") }
75 static CRITICAL_SECTION g_sessions_lock = { &g_sessions_lock_debug, -1, 0, 0, 0, 0 };
76 static struct list g_sessions = LIST_INIT(g_sessions);
78 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
80 static const IAudioClient3Vtbl AudioClient3_Vtbl;
81 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
82 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
83 extern const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
84 extern const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
85 static const IAudioClockVtbl AudioClock_Vtbl;
86 static const IAudioClock2Vtbl AudioClock2_Vtbl;
87 extern const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
88 extern const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
90 void DECLSPEC_HIDDEN sessions_lock(void)
92 EnterCriticalSection(&g_sessions_lock);
95 void DECLSPEC_HIDDEN sessions_unlock(void)
97 LeaveCriticalSection(&g_sessions_lock);
100 static inline ACImpl *impl_from_IAudioClient3(IAudioClient3 *iface)
102 return CONTAINING_RECORD(iface, ACImpl, IAudioClient3_iface);
105 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
107 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
110 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
112 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
115 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
117 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
120 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
122 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
125 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
127 return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
130 BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
132 switch (reason)
134 case DLL_PROCESS_ATTACH:
136 WCHAR buf[MAX_PATH];
137 WCHAR *filename;
139 if(__wine_init_unix_call()) return FALSE;
141 GetModuleFileNameW(dll, buf, ARRAY_SIZE(buf));
143 filename = wcsrchr(buf, '\\');
144 filename = filename ? filename + 1 : buf;
146 swprintf(drv_key_devicesW, ARRAY_SIZE(drv_key_devicesW),
147 L"Software\\Wine\\Drivers\\%s\\devices", filename);
149 break;
151 case DLL_PROCESS_DETACH:
152 if (!reserved)
154 OSSDevice *iter, *iter2;
156 DeleteCriticalSection(&g_sessions_lock);
158 LIST_FOR_EACH_ENTRY_SAFE(iter, iter2, &g_devices, OSSDevice, entry){
159 HeapFree(GetProcessHeap(), 0, iter);
162 break;
164 return TRUE;
167 static HRESULT stream_release(stream_handle stream, HANDLE timer_thread)
169 struct release_stream_params params;
171 params.stream = stream;
172 params.timer_thread = timer_thread;
173 OSS_CALL(release_stream, &params);
175 return params.result;
178 static DWORD WINAPI timer_thread(void *user)
180 struct timer_loop_params params;
181 ACImpl *This = user;
183 params.stream = This->stream;
184 OSS_CALL(timer_loop, &params);
186 return 0;
189 static void set_device_guid(EDataFlow flow, HKEY drv_key, const WCHAR *key_name,
190 GUID *guid)
192 HKEY key;
193 BOOL opened = FALSE;
194 LONG lr;
196 if(!drv_key){
197 lr = RegCreateKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, NULL, 0, KEY_WRITE,
198 NULL, &drv_key, NULL);
199 if(lr != ERROR_SUCCESS){
200 ERR("RegCreateKeyEx(drv_key) failed: %lu\n", lr);
201 return;
203 opened = TRUE;
206 lr = RegCreateKeyExW(drv_key, key_name, 0, NULL, 0, KEY_WRITE,
207 NULL, &key, NULL);
208 if(lr != ERROR_SUCCESS){
209 ERR("RegCreateKeyEx(%s) failed: %lu\n", wine_dbgstr_w(key_name), lr);
210 goto exit;
213 lr = RegSetValueExW(key, guidW, 0, REG_BINARY, (BYTE*)guid,
214 sizeof(GUID));
215 if(lr != ERROR_SUCCESS)
216 ERR("RegSetValueEx(%s\\guid) failed: %lu\n", wine_dbgstr_w(key_name), lr);
218 RegCloseKey(key);
219 exit:
220 if(opened)
221 RegCloseKey(drv_key);
224 static void get_device_guid(EDataFlow flow, const char *device, GUID *guid)
226 HKEY key = NULL, dev_key;
227 DWORD type, size = sizeof(*guid);
228 WCHAR key_name[256];
230 if(flow == eCapture)
231 key_name[0] = '1';
232 else
233 key_name[0] = '0';
234 key_name[1] = ',';
235 MultiByteToWideChar(CP_UNIXCP, 0, device, -1, key_name + 2, ARRAY_SIZE(key_name) - 2);
237 if(RegOpenKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, KEY_WRITE|KEY_READ, &key) == ERROR_SUCCESS){
238 if(RegOpenKeyExW(key, key_name, 0, KEY_READ, &dev_key) == ERROR_SUCCESS){
239 if(RegQueryValueExW(dev_key, guidW, 0, &type,
240 (BYTE*)guid, &size) == ERROR_SUCCESS){
241 if(type == REG_BINARY){
242 RegCloseKey(dev_key);
243 RegCloseKey(key);
244 return;
246 ERR("Invalid type for device %s GUID: %lu; ignoring and overwriting\n",
247 wine_dbgstr_w(key_name), type);
249 RegCloseKey(dev_key);
253 CoCreateGuid(guid);
255 set_device_guid(flow, key, key_name, guid);
257 if(key)
258 RegCloseKey(key);
261 static void set_stream_volumes(ACImpl *This)
263 struct set_volumes_params params;
265 params.stream = This->stream;
266 params.master_volume = (This->session->mute ? 0.0f : This->session->master_vol);
267 params.volumes = This->vols;
268 params.session_volumes = This->session->channel_vols;
269 OSS_CALL(set_volumes, &params);
272 static const OSSDevice *get_ossdevice_from_guid(const GUID *guid)
274 OSSDevice *dev_item;
275 LIST_FOR_EACH_ENTRY(dev_item, &g_devices, OSSDevice, entry)
276 if(IsEqualGUID(guid, &dev_item->guid))
277 return dev_item;
278 return NULL;
281 static void device_add(OSSDevice *oss_dev)
283 if(get_ossdevice_from_guid(&oss_dev->guid)) /* already in list */
284 HeapFree(GetProcessHeap(), 0, oss_dev);
285 else
286 list_add_tail(&g_devices, &oss_dev->entry);
289 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids_out, GUID **guids_out,
290 UINT *num, UINT *def_index)
292 struct get_endpoint_ids_params params;
293 GUID *guids = NULL;
294 WCHAR **ids = NULL;
295 unsigned int i;
297 TRACE("%d %p %p %p %p\n", flow, ids, guids, num, def_index);
299 params.flow = flow;
300 params.size = 1000;
301 params.endpoints = NULL;
303 HeapFree(GetProcessHeap(), 0, params.endpoints);
304 params.endpoints = HeapAlloc(GetProcessHeap(), 0, params.size);
305 OSS_CALL(get_endpoint_ids, &params);
306 }while(params.result == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
308 if(FAILED(params.result)) goto end;
310 ids = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, params.num * sizeof(*ids));
311 guids = HeapAlloc(GetProcessHeap(), 0, params.num * sizeof(*guids));
312 if(!ids || !guids){
313 params.result = E_OUTOFMEMORY;
314 goto end;
317 for(i = 0; i < params.num; i++){
318 WCHAR *name = (WCHAR *)((char *)params.endpoints + params.endpoints[i].name);
319 char *device = (char *)params.endpoints + params.endpoints[i].device;
320 unsigned int name_size = (wcslen(name) + 1) * sizeof(WCHAR);
321 unsigned int dev_size = strlen(device) + 1;
322 OSSDevice *oss_dev;
324 ids[i] = HeapAlloc(GetProcessHeap(), 0, name_size);
325 oss_dev = HeapAlloc(GetProcessHeap(), 0, offsetof(OSSDevice, devnode[dev_size]));
326 if(!ids[i] || !oss_dev){
327 HeapFree(GetProcessHeap(), 0, oss_dev);
328 params.result = E_OUTOFMEMORY;
329 goto end;
331 memcpy(ids[i], name, name_size);
332 get_device_guid(flow, device, guids + i);
334 oss_dev->flow = flow;
335 oss_dev->guid = guids[i];
336 memcpy(oss_dev->devnode, device, dev_size);
337 device_add(oss_dev);
339 *def_index = params.default_idx;
341 end:
342 HeapFree(GetProcessHeap(), 0, params.endpoints);
343 if(FAILED(params.result)){
344 HeapFree(GetProcessHeap(), 0, guids);
345 if(ids){
346 for(i = 0; i < params.num; i++)
347 HeapFree(GetProcessHeap(), 0, ids[i]);
348 HeapFree(GetProcessHeap(), 0, ids);
350 }else{
351 *ids_out = ids;
352 *guids_out = guids;
353 *num = params.num;
356 return params.result;
359 HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev,
360 IAudioClient **out)
362 ACImpl *This;
363 const OSSDevice *oss_dev;
364 HRESULT hr;
365 int len;
367 TRACE("%s %p %p\n", debugstr_guid(guid), dev, out);
369 oss_dev = get_ossdevice_from_guid(guid);
370 if(!oss_dev){
371 WARN("Unknown GUID: %s\n", debugstr_guid(guid));
372 return AUDCLNT_E_DEVICE_INVALIDATED;
374 len = strlen(oss_dev->devnode);
375 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, offsetof(ACImpl, device_name[len + 1]));
376 if(!This)
377 return E_OUTOFMEMORY;
379 hr = CoCreateFreeThreadedMarshaler((IUnknown *)&This->IAudioClient3_iface, &This->marshal);
380 if (FAILED(hr)) {
381 HeapFree(GetProcessHeap(), 0, This);
382 return hr;
385 This->dataflow = oss_dev->flow;
386 strcpy(This->device_name, oss_dev->devnode);
388 This->IAudioClient3_iface.lpVtbl = &AudioClient3_Vtbl;
389 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
390 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
391 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
392 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
393 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
395 This->parent = dev;
396 IMMDevice_AddRef(This->parent);
398 *out = (IAudioClient *)&This->IAudioClient3_iface;
399 IAudioClient3_AddRef(&This->IAudioClient3_iface);
401 return S_OK;
404 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient3 *iface,
405 REFIID riid, void **ppv)
407 ACImpl *This = impl_from_IAudioClient3(iface);
408 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
410 if(!ppv)
411 return E_POINTER;
412 *ppv = NULL;
413 if(IsEqualIID(riid, &IID_IUnknown) ||
414 IsEqualIID(riid, &IID_IAudioClient) ||
415 IsEqualIID(riid, &IID_IAudioClient2) ||
416 IsEqualIID(riid, &IID_IAudioClient3))
417 *ppv = iface;
418 else if(IsEqualIID(riid, &IID_IMarshal))
419 return IUnknown_QueryInterface(This->marshal, riid, ppv);
420 if(*ppv){
421 IUnknown_AddRef((IUnknown*)*ppv);
422 return S_OK;
424 WARN("Unknown interface %s\n", debugstr_guid(riid));
425 return E_NOINTERFACE;
428 static ULONG WINAPI AudioClient_AddRef(IAudioClient3 *iface)
430 ACImpl *This = impl_from_IAudioClient3(iface);
431 ULONG ref;
432 ref = InterlockedIncrement(&This->ref);
433 TRACE("(%p) Refcount now %lu\n", This, ref);
434 return ref;
437 static ULONG WINAPI AudioClient_Release(IAudioClient3 *iface)
439 ACImpl *This = impl_from_IAudioClient3(iface);
440 ULONG ref;
442 ref = InterlockedDecrement(&This->ref);
443 TRACE("(%p) Refcount now %lu\n", This, ref);
444 if(!ref){
445 IAudioClient3_Stop(iface);
446 IMMDevice_Release(This->parent);
447 IUnknown_Release(This->marshal);
448 if(This->session){
449 sessions_lock();
450 list_remove(&This->entry);
451 sessions_unlock();
453 HeapFree(GetProcessHeap(), 0, This->vols);
454 if(This->stream)
455 stream_release(This->stream, This->timer_thread);
456 HeapFree(GetProcessHeap(), 0, This);
458 return ref;
461 static void dump_fmt(const WAVEFORMATEX *fmt)
463 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
464 switch(fmt->wFormatTag){
465 case WAVE_FORMAT_PCM:
466 TRACE("WAVE_FORMAT_PCM");
467 break;
468 case WAVE_FORMAT_IEEE_FLOAT:
469 TRACE("WAVE_FORMAT_IEEE_FLOAT");
470 break;
471 case WAVE_FORMAT_EXTENSIBLE:
472 TRACE("WAVE_FORMAT_EXTENSIBLE");
473 break;
474 default:
475 TRACE("Unknown");
476 break;
478 TRACE(")\n");
480 TRACE("nChannels: %u\n", fmt->nChannels);
481 TRACE("nSamplesPerSec: %lu\n", fmt->nSamplesPerSec);
482 TRACE("nAvgBytesPerSec: %lu\n", fmt->nAvgBytesPerSec);
483 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
484 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
485 TRACE("cbSize: %u\n", fmt->cbSize);
487 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
488 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
489 TRACE("dwChannelMask: %08lx\n", fmtex->dwChannelMask);
490 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
491 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
495 static void session_init_vols(AudioSession *session, UINT channels)
497 if(session->channel_count < channels){
498 UINT i;
500 if(session->channel_vols)
501 session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
502 session->channel_vols, sizeof(float) * channels);
503 else
504 session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
505 sizeof(float) * channels);
506 if(!session->channel_vols)
507 return;
509 for(i = session->channel_count; i < channels; ++i)
510 session->channel_vols[i] = 1.f;
512 session->channel_count = channels;
516 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
517 UINT num_channels)
519 AudioSession *ret;
521 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
522 if(!ret)
523 return NULL;
525 memcpy(&ret->guid, guid, sizeof(GUID));
527 ret->device = device;
529 list_init(&ret->clients);
531 list_add_head(&g_sessions, &ret->entry);
533 session_init_vols(ret, num_channels);
535 ret->master_vol = 1.f;
537 return ret;
540 /* if channels == 0, then this will return or create a session with
541 * matching dataflow and GUID. otherwise, channels must also match */
542 static HRESULT get_audio_session(const GUID *sessionguid,
543 IMMDevice *device, UINT channels, AudioSession **out)
545 AudioSession *session;
547 if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
548 *out = create_session(&GUID_NULL, device, channels);
549 if(!*out)
550 return E_OUTOFMEMORY;
552 return S_OK;
555 *out = NULL;
556 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
557 if(session->device == device &&
558 IsEqualGUID(sessionguid, &session->guid)){
559 session_init_vols(session, channels);
560 *out = session;
561 break;
565 if(!*out){
566 *out = create_session(sessionguid, device, channels);
567 if(!*out)
568 return E_OUTOFMEMORY;
571 return S_OK;
574 static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
575 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
576 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
577 const GUID *sessionguid)
579 ACImpl *This = impl_from_IAudioClient3(iface);
580 struct create_stream_params params;
581 stream_handle stream;
582 unsigned int i;
584 TRACE("(%p)->(%x, %lx, %s, %s, %p, %s)\n", This, mode, flags,
585 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
587 if(!fmt)
588 return E_POINTER;
590 dump_fmt(fmt);
592 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
593 return E_INVALIDARG;
595 if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
596 AUDCLNT_STREAMFLAGS_LOOPBACK |
597 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
598 AUDCLNT_STREAMFLAGS_NOPERSIST |
599 AUDCLNT_STREAMFLAGS_RATEADJUST |
600 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
601 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
602 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED |
603 AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY |
604 AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM)){
605 FIXME("Unknown flags: %08lx\n", flags);
606 return E_INVALIDARG;
609 if(mode == AUDCLNT_SHAREMODE_SHARED){
610 period = DefaultPeriod;
611 if( duration < 3 * period)
612 duration = 3 * period;
613 }else{
614 if(!period)
615 period = DefaultPeriod; /* not minimum */
616 if(period < MinimumPeriod || period > 5000000)
617 return AUDCLNT_E_INVALID_DEVICE_PERIOD;
618 if(duration > 20000000) /* the smaller the period, the lower this limit */
619 return AUDCLNT_E_BUFFER_SIZE_ERROR;
620 if(flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK){
621 if(duration != period)
622 return AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL;
623 FIXME("EXCLUSIVE mode with EVENTCALLBACK\n");
624 return AUDCLNT_E_DEVICE_IN_USE;
625 }else{
626 if( duration < 8 * period)
627 duration = 8 * period; /* may grow above 2s */
631 sessions_lock();
633 if(This->stream){
634 sessions_unlock();
635 return AUDCLNT_E_ALREADY_INITIALIZED;
638 params.name = NULL;
639 params.device = This->device_name;
640 params.flow = This->dataflow;
641 params.share = mode;
642 params.flags = flags;
643 params.duration = duration;
644 params.period = period;
645 params.fmt = fmt;
646 params.channel_count = NULL;
647 params.stream = &stream;
649 OSS_CALL(create_stream, &params);
650 if(FAILED(params.result)){
651 sessions_unlock();
652 return params.result;
655 This->channel_count = fmt->nChannels;
656 This->vols = HeapAlloc(GetProcessHeap(), 0, This->channel_count * sizeof(float));
657 if(!This->vols){
658 params.result = E_OUTOFMEMORY;
659 goto exit;
661 for(i = 0; i < This->channel_count; ++i)
662 This->vols[i] = 1.f;
664 params.result = get_audio_session(sessionguid, This->parent, This->channel_count,
665 &This->session);
667 exit:
668 if(FAILED(params.result)){
669 stream_release(stream, NULL);
670 HeapFree(GetProcessHeap(), 0, This->vols);
671 This->vols = NULL;
672 } else {
673 list_add_tail(&This->session->clients, &This->entry);
674 This->stream = stream;
675 set_stream_volumes(This);
678 sessions_unlock();
680 return params.result;
683 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient3 *iface,
684 UINT32 *frames)
686 ACImpl *This = impl_from_IAudioClient3(iface);
687 struct get_buffer_size_params params;
689 TRACE("(%p)->(%p)\n", This, frames);
691 if(!frames)
692 return E_POINTER;
694 if(!This->stream)
695 return AUDCLNT_E_NOT_INITIALIZED;
697 params.stream = This->stream;
698 params.frames = frames;
700 OSS_CALL(get_buffer_size, &params);
701 TRACE("buffer size: %u\n", *frames);
703 return params.result;
706 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient3 *iface,
707 REFERENCE_TIME *latency)
709 ACImpl *This = impl_from_IAudioClient3(iface);
710 struct get_latency_params params;
712 TRACE("(%p)->(%p)\n", This, latency);
714 if(!latency)
715 return E_POINTER;
717 if(!This->stream)
718 return AUDCLNT_E_NOT_INITIALIZED;
720 params.stream = This->stream;
721 params.latency = latency;
722 OSS_CALL(get_latency, &params);
724 return params.result;
727 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient3 *iface,
728 UINT32 *numpad)
730 ACImpl *This = impl_from_IAudioClient3(iface);
731 struct get_current_padding_params params;
733 TRACE("(%p)->(%p)\n", This, numpad);
735 if(!numpad)
736 return E_POINTER;
738 if(!This->stream)
739 return AUDCLNT_E_NOT_INITIALIZED;
741 params.stream = This->stream;
742 params.padding = numpad;
743 OSS_CALL(get_current_padding, &params);
744 TRACE("padding: %u\n", *numpad);
746 return params.result;
749 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient3 *iface,
750 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *fmt,
751 WAVEFORMATEX **out)
753 ACImpl *This = impl_from_IAudioClient3(iface);
754 struct is_format_supported_params params;
756 TRACE("(%p)->(%x, %p, %p)\n", This, mode, fmt, out);
757 if(fmt) dump_fmt(fmt);
759 params.device = This->device_name;
760 params.flow = This->dataflow;
761 params.share = mode;
762 params.fmt_in = fmt;
763 params.fmt_out = NULL;
765 if(out){
766 *out = NULL;
767 if(mode == AUDCLNT_SHAREMODE_SHARED)
768 params.fmt_out = CoTaskMemAlloc(sizeof(*params.fmt_out));
770 OSS_CALL(is_format_supported, &params);
772 if(params.result == S_FALSE)
773 *out = &params.fmt_out->Format;
774 else
775 CoTaskMemFree(params.fmt_out);
777 return params.result;
780 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface,
781 WAVEFORMATEX **pwfx)
783 ACImpl *This = impl_from_IAudioClient3(iface);
784 struct get_mix_format_params params;
786 TRACE("(%p)->(%p)\n", This, pwfx);
788 if(!pwfx)
789 return E_POINTER;
790 *pwfx = NULL;
792 params.device = This->device_name;
793 params.flow = This->dataflow;
794 params.fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
795 if(!params.fmt)
796 return E_OUTOFMEMORY;
798 OSS_CALL(get_mix_format, &params);
800 if(SUCCEEDED(params.result)){
801 *pwfx = &params.fmt->Format;
802 dump_fmt(*pwfx);
803 } else
804 CoTaskMemFree(params.fmt);
806 return params.result;
809 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient3 *iface,
810 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
812 ACImpl *This = impl_from_IAudioClient3(iface);
814 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
816 if(!defperiod && !minperiod)
817 return E_POINTER;
819 if(defperiod)
820 *defperiod = DefaultPeriod;
821 if(minperiod)
822 *minperiod = MinimumPeriod;
824 return S_OK;
827 static HRESULT WINAPI AudioClient_Start(IAudioClient3 *iface)
829 ACImpl *This = impl_from_IAudioClient3(iface);
830 struct start_params params;
832 TRACE("(%p)\n", This);
834 sessions_lock();
836 if(!This->stream){
837 sessions_unlock();
838 return AUDCLNT_E_NOT_INITIALIZED;
841 params.stream = This->stream;
842 OSS_CALL(start, &params);
844 if(SUCCEEDED(params.result) && !This->timer_thread){
845 This->timer_thread = CreateThread(NULL, 0, timer_thread, This, 0, NULL);
846 SetThreadPriority(This->timer_thread, THREAD_PRIORITY_TIME_CRITICAL);
849 sessions_unlock();
851 return params.result;
854 static HRESULT WINAPI AudioClient_Stop(IAudioClient3 *iface)
856 ACImpl *This = impl_from_IAudioClient3(iface);
857 struct stop_params params;
859 TRACE("(%p)\n", This);
861 if(!This->stream)
862 return AUDCLNT_E_NOT_INITIALIZED;
864 params.stream = This->stream;
865 OSS_CALL(stop, &params);
867 return params.result;
870 static HRESULT WINAPI AudioClient_Reset(IAudioClient3 *iface)
872 ACImpl *This = impl_from_IAudioClient3(iface);
873 struct reset_params params;
875 TRACE("(%p)\n", This);
877 if(!This->stream)
878 return AUDCLNT_E_NOT_INITIALIZED;
880 params.stream = This->stream;
881 OSS_CALL(reset, &params);
883 return params.result;
886 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient3 *iface,
887 HANDLE event)
889 ACImpl *This = impl_from_IAudioClient3(iface);
890 struct set_event_handle_params params;
892 TRACE("(%p)->(%p)\n", This, event);
894 if(!event)
895 return E_INVALIDARG;
897 if(!This->stream)
898 return AUDCLNT_E_NOT_INITIALIZED;
900 params.stream = This->stream;
901 params.event = event;
902 OSS_CALL(set_event_handle, &params);
904 return params.result;
907 static HRESULT WINAPI AudioClient_GetService(IAudioClient3 *iface, REFIID riid,
908 void **ppv)
910 ACImpl *This = impl_from_IAudioClient3(iface);
912 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
914 if(!ppv)
915 return E_POINTER;
916 *ppv = NULL;
918 sessions_lock();
920 if(!This->stream){
921 sessions_unlock();
922 return AUDCLNT_E_NOT_INITIALIZED;
925 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
926 if(This->dataflow != eRender){
927 sessions_unlock();
928 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
930 IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
931 *ppv = &This->IAudioRenderClient_iface;
932 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
933 if(This->dataflow != eCapture){
934 sessions_unlock();
935 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
937 IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
938 *ppv = &This->IAudioCaptureClient_iface;
939 }else if(IsEqualIID(riid, &IID_IAudioClock)){
940 IAudioClock_AddRef(&This->IAudioClock_iface);
941 *ppv = &This->IAudioClock_iface;
942 }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
943 IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
944 *ppv = &This->IAudioStreamVolume_iface;
945 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
946 if(!This->session_wrapper){
947 This->session_wrapper = AudioSessionWrapper_Create(This);
948 if(!This->session_wrapper){
949 sessions_unlock();
950 return E_OUTOFMEMORY;
952 }else
953 IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
955 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
956 }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
957 if(!This->session_wrapper){
958 This->session_wrapper = AudioSessionWrapper_Create(This);
959 if(!This->session_wrapper){
960 sessions_unlock();
961 return E_OUTOFMEMORY;
963 }else
964 IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
966 *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
967 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
968 if(!This->session_wrapper){
969 This->session_wrapper = AudioSessionWrapper_Create(This);
970 if(!This->session_wrapper){
971 sessions_unlock();
972 return E_OUTOFMEMORY;
974 }else
975 ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
977 *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
980 if(*ppv){
981 sessions_unlock();
982 return S_OK;
985 sessions_unlock();
987 FIXME("stub %s\n", debugstr_guid(riid));
988 return E_NOINTERFACE;
991 static HRESULT WINAPI AudioClient_IsOffloadCapable(IAudioClient3 *iface,
992 AUDIO_STREAM_CATEGORY category, BOOL *offload_capable)
994 ACImpl *This = impl_from_IAudioClient3(iface);
996 TRACE("(%p)->(0x%x, %p)\n", This, category, offload_capable);
998 if(!offload_capable)
999 return E_INVALIDARG;
1001 *offload_capable = FALSE;
1003 return S_OK;
1006 static HRESULT WINAPI AudioClient_SetClientProperties(IAudioClient3 *iface,
1007 const AudioClientProperties *prop)
1009 ACImpl *This = impl_from_IAudioClient3(iface);
1010 const Win8AudioClientProperties *legacy_prop = (const Win8AudioClientProperties *)prop;
1012 TRACE("(%p)->(%p)\n", This, prop);
1014 if(!legacy_prop)
1015 return E_POINTER;
1017 if(legacy_prop->cbSize == sizeof(AudioClientProperties)){
1018 TRACE("{ bIsOffload: %u, eCategory: 0x%x, Options: 0x%x }\n",
1019 legacy_prop->bIsOffload,
1020 legacy_prop->eCategory,
1021 prop->Options);
1022 }else if(legacy_prop->cbSize == sizeof(Win8AudioClientProperties)){
1023 TRACE("{ bIsOffload: %u, eCategory: 0x%x }\n",
1024 legacy_prop->bIsOffload,
1025 legacy_prop->eCategory);
1026 }else{
1027 WARN("Unsupported Size = %d\n", legacy_prop->cbSize);
1028 return E_INVALIDARG;
1032 if(legacy_prop->bIsOffload)
1033 return AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE;
1035 return S_OK;
1038 static HRESULT WINAPI AudioClient_GetBufferSizeLimits(IAudioClient3 *iface,
1039 const WAVEFORMATEX *format, BOOL event_driven, REFERENCE_TIME *min_duration,
1040 REFERENCE_TIME *max_duration)
1042 ACImpl *This = impl_from_IAudioClient3(iface);
1044 FIXME("(%p)->(%p, %u, %p, %p)\n", This, format, event_driven, min_duration, max_duration);
1046 return E_NOTIMPL;
1049 static HRESULT WINAPI AudioClient_GetSharedModeEnginePeriod(IAudioClient3 *iface,
1050 const WAVEFORMATEX *format, UINT32 *default_period_frames, UINT32 *unit_period_frames,
1051 UINT32 *min_period_frames, UINT32 *max_period_frames)
1053 ACImpl *This = impl_from_IAudioClient3(iface);
1055 FIXME("(%p)->(%p, %p, %p, %p, %p)\n", This, format, default_period_frames, unit_period_frames,
1056 min_period_frames, max_period_frames);
1058 return E_NOTIMPL;
1061 static HRESULT WINAPI AudioClient_GetCurrentSharedModeEnginePeriod(IAudioClient3 *iface,
1062 WAVEFORMATEX **cur_format, UINT32 *cur_period_frames)
1064 ACImpl *This = impl_from_IAudioClient3(iface);
1066 FIXME("(%p)->(%p, %p)\n", This, cur_format, cur_period_frames);
1068 return E_NOTIMPL;
1071 static HRESULT WINAPI AudioClient_InitializeSharedAudioStream(IAudioClient3 *iface,
1072 DWORD flags, UINT32 period_frames, const WAVEFORMATEX *format,
1073 const GUID *session_guid)
1075 ACImpl *This = impl_from_IAudioClient3(iface);
1077 FIXME("(%p)->(0x%lx, %u, %p, %s)\n", This, flags, period_frames, format, debugstr_guid(session_guid));
1079 return E_NOTIMPL;
1082 static const IAudioClient3Vtbl AudioClient3_Vtbl =
1084 AudioClient_QueryInterface,
1085 AudioClient_AddRef,
1086 AudioClient_Release,
1087 AudioClient_Initialize,
1088 AudioClient_GetBufferSize,
1089 AudioClient_GetStreamLatency,
1090 AudioClient_GetCurrentPadding,
1091 AudioClient_IsFormatSupported,
1092 AudioClient_GetMixFormat,
1093 AudioClient_GetDevicePeriod,
1094 AudioClient_Start,
1095 AudioClient_Stop,
1096 AudioClient_Reset,
1097 AudioClient_SetEventHandle,
1098 AudioClient_GetService,
1099 AudioClient_IsOffloadCapable,
1100 AudioClient_SetClientProperties,
1101 AudioClient_GetBufferSizeLimits,
1102 AudioClient_GetSharedModeEnginePeriod,
1103 AudioClient_GetCurrentSharedModeEnginePeriod,
1104 AudioClient_InitializeSharedAudioStream,
1107 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1108 IAudioRenderClient *iface, REFIID riid, void **ppv)
1110 ACImpl *This = impl_from_IAudioRenderClient(iface);
1111 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1113 if(!ppv)
1114 return E_POINTER;
1115 *ppv = NULL;
1117 if(IsEqualIID(riid, &IID_IUnknown) ||
1118 IsEqualIID(riid, &IID_IAudioRenderClient))
1119 *ppv = iface;
1120 else if(IsEqualIID(riid, &IID_IMarshal))
1121 return IUnknown_QueryInterface(This->marshal, riid, ppv);
1122 if(*ppv){
1123 IUnknown_AddRef((IUnknown*)*ppv);
1124 return S_OK;
1127 WARN("Unknown interface %s\n", debugstr_guid(riid));
1128 return E_NOINTERFACE;
1131 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1133 ACImpl *This = impl_from_IAudioRenderClient(iface);
1134 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1137 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1139 ACImpl *This = impl_from_IAudioRenderClient(iface);
1140 return IAudioClient3_Release(&This->IAudioClient3_iface);
1143 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1144 UINT32 frames, BYTE **data)
1146 ACImpl *This = impl_from_IAudioRenderClient(iface);
1147 struct get_render_buffer_params params;
1149 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1151 if(!data)
1152 return E_POINTER;
1154 *data = NULL;
1156 params.stream = This->stream;
1157 params.frames = frames;
1158 params.data = data;
1159 OSS_CALL(get_render_buffer, &params);
1161 return params.result;
1164 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1165 IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
1167 ACImpl *This = impl_from_IAudioRenderClient(iface);
1168 struct release_render_buffer_params params;
1170 TRACE("(%p)->(%u, %lx)\n", This, written_frames, flags);
1172 params.stream = This->stream;
1173 params.written_frames = written_frames;
1174 params.flags = flags;
1175 OSS_CALL(release_render_buffer, &params);
1177 return params.result;
1180 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1181 AudioRenderClient_QueryInterface,
1182 AudioRenderClient_AddRef,
1183 AudioRenderClient_Release,
1184 AudioRenderClient_GetBuffer,
1185 AudioRenderClient_ReleaseBuffer
1188 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1189 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1191 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1192 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1194 if(!ppv)
1195 return E_POINTER;
1196 *ppv = NULL;
1198 if(IsEqualIID(riid, &IID_IUnknown) ||
1199 IsEqualIID(riid, &IID_IAudioCaptureClient))
1200 *ppv = iface;
1201 else if(IsEqualIID(riid, &IID_IMarshal))
1202 return IUnknown_QueryInterface(This->marshal, riid, ppv);
1203 if(*ppv){
1204 IUnknown_AddRef((IUnknown*)*ppv);
1205 return S_OK;
1208 WARN("Unknown interface %s\n", debugstr_guid(riid));
1209 return E_NOINTERFACE;
1212 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1214 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1215 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1218 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1220 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1221 return IAudioClient3_Release(&This->IAudioClient3_iface);
1224 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1225 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1226 UINT64 *qpcpos)
1228 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1229 struct get_capture_buffer_params params;
1231 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1232 devpos, qpcpos);
1234 if(!data)
1235 return E_POINTER;
1237 *data = NULL;
1239 if(!frames || !flags)
1240 return E_POINTER;
1242 params.stream = This->stream;
1243 params.data = data;
1244 params.frames = frames;
1245 params.flags = (UINT*)flags;
1246 params.devpos = devpos;
1247 params.qpcpos = qpcpos;
1248 OSS_CALL(get_capture_buffer, &params);
1250 return params.result;
1253 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1254 IAudioCaptureClient *iface, UINT32 done)
1256 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1257 struct release_capture_buffer_params params;
1259 TRACE("(%p)->(%u)\n", This, done);
1261 params.stream = This->stream;
1262 params.done = done;
1263 OSS_CALL(release_capture_buffer, &params);
1265 return params.result;
1268 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1269 IAudioCaptureClient *iface, UINT32 *frames)
1271 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1272 struct get_next_packet_size_params params;
1274 TRACE("(%p)->(%p)\n", This, frames);
1276 if(!frames)
1277 return E_POINTER;
1279 params.stream = This->stream;
1280 params.frames = frames;
1281 OSS_CALL(get_next_packet_size, &params);
1283 return params.result;
1286 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1288 AudioCaptureClient_QueryInterface,
1289 AudioCaptureClient_AddRef,
1290 AudioCaptureClient_Release,
1291 AudioCaptureClient_GetBuffer,
1292 AudioCaptureClient_ReleaseBuffer,
1293 AudioCaptureClient_GetNextPacketSize
1296 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1297 REFIID riid, void **ppv)
1299 ACImpl *This = impl_from_IAudioClock(iface);
1301 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1303 if(!ppv)
1304 return E_POINTER;
1305 *ppv = NULL;
1307 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
1308 *ppv = iface;
1309 else if(IsEqualIID(riid, &IID_IAudioClock2))
1310 *ppv = &This->IAudioClock2_iface;
1311 if(*ppv){
1312 IUnknown_AddRef((IUnknown*)*ppv);
1313 return S_OK;
1316 WARN("Unknown interface %s\n", debugstr_guid(riid));
1317 return E_NOINTERFACE;
1320 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
1322 ACImpl *This = impl_from_IAudioClock(iface);
1323 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1326 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
1328 ACImpl *This = impl_from_IAudioClock(iface);
1329 return IAudioClient3_Release(&This->IAudioClient3_iface);
1332 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
1334 ACImpl *This = impl_from_IAudioClock(iface);
1335 struct get_frequency_params params;
1337 TRACE("(%p)->(%p)\n", This, freq);
1339 params.stream = This->stream;
1340 params.freq = freq;
1341 OSS_CALL(get_frequency, &params);
1343 return params.result;
1346 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
1347 UINT64 *qpctime)
1349 ACImpl *This = impl_from_IAudioClock(iface);
1350 struct get_position_params params;
1352 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
1354 if(!pos)
1355 return E_POINTER;
1357 params.stream = This->stream;
1358 params.device = FALSE;
1359 params.pos = pos;
1360 params.qpctime = qpctime;
1361 OSS_CALL(get_position, &params);
1363 return params.result;
1366 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
1367 DWORD *chars)
1369 ACImpl *This = impl_from_IAudioClock(iface);
1371 TRACE("(%p)->(%p)\n", This, chars);
1373 if(!chars)
1374 return E_POINTER;
1376 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
1378 return S_OK;
1381 static const IAudioClockVtbl AudioClock_Vtbl =
1383 AudioClock_QueryInterface,
1384 AudioClock_AddRef,
1385 AudioClock_Release,
1386 AudioClock_GetFrequency,
1387 AudioClock_GetPosition,
1388 AudioClock_GetCharacteristics
1391 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
1392 REFIID riid, void **ppv)
1394 ACImpl *This = impl_from_IAudioClock2(iface);
1395 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
1398 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
1400 ACImpl *This = impl_from_IAudioClock2(iface);
1401 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1404 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
1406 ACImpl *This = impl_from_IAudioClock2(iface);
1407 return IAudioClient3_Release(&This->IAudioClient3_iface);
1410 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
1411 UINT64 *pos, UINT64 *qpctime)
1413 ACImpl *This = impl_from_IAudioClock2(iface);
1415 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
1417 return E_NOTIMPL;
1420 static const IAudioClock2Vtbl AudioClock2_Vtbl =
1422 AudioClock2_QueryInterface,
1423 AudioClock2_AddRef,
1424 AudioClock2_Release,
1425 AudioClock2_GetDevicePosition
1428 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
1430 AudioSessionWrapper *ret;
1432 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1433 sizeof(AudioSessionWrapper));
1434 if(!ret)
1435 return NULL;
1437 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
1438 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
1439 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
1441 ret->ref = 1;
1443 ret->client = client;
1444 if(client){
1445 ret->session = client->session;
1446 IAudioClient3_AddRef(&client->IAudioClient3_iface);
1449 return ret;
1452 HRESULT WINAPI AUDDRV_GetAudioSessionWrapper(const GUID *guid, IMMDevice *device,
1453 AudioSessionWrapper **out)
1455 AudioSession *session;
1457 HRESULT hr = get_audio_session(guid, device, 0, &session);
1458 if(FAILED(hr))
1459 return hr;
1461 *out = AudioSessionWrapper_Create(NULL);
1462 if(!*out)
1463 return E_OUTOFMEMORY;
1465 (*out)->session = session;
1467 return S_OK;