mmdevapi: Move test_connect handling into mmdevapi.
[wine.git] / dlls / wineoss.drv / mmdevdrv.c
blob6993fa88d0a948f229c1e2c0e613725aaadf9a72
1 /*
2 * Copyright 2011 Andrew Eikum for CodeWeavers
3 * 2022 Huw Davies
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #define COBJMACROS
21 #include <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winternl.h"
26 #include "winnls.h"
27 #include "winreg.h"
29 #include "ole2.h"
30 #include "mmdeviceapi.h"
31 #include "devpkey.h"
32 #include "dshow.h"
33 #include "dsound.h"
35 #include "initguid.h"
36 #include "endpointvolume.h"
37 #include "audiopolicy.h"
38 #include "audioclient.h"
40 #include "wine/debug.h"
41 #include "wine/list.h"
42 #include "wine/unixlib.h"
44 #include "unixlib.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(oss);
48 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
50 static const REFERENCE_TIME DefaultPeriod = 100000;
51 static const REFERENCE_TIME MinimumPeriod = 50000;
53 struct ACImpl;
54 typedef struct ACImpl ACImpl;
56 typedef struct _AudioSession {
57 GUID guid;
58 struct list clients;
60 IMMDevice *device;
62 float master_vol;
63 UINT32 channel_count;
64 float *channel_vols;
65 BOOL mute;
67 struct list entry;
68 } AudioSession;
70 typedef struct _AudioSessionWrapper {
71 IAudioSessionControl2 IAudioSessionControl2_iface;
72 IChannelAudioVolume IChannelAudioVolume_iface;
73 ISimpleAudioVolume ISimpleAudioVolume_iface;
75 LONG ref;
77 ACImpl *client;
78 AudioSession *session;
79 } AudioSessionWrapper;
81 struct ACImpl {
82 IAudioClient3 IAudioClient3_iface;
83 IAudioRenderClient IAudioRenderClient_iface;
84 IAudioCaptureClient IAudioCaptureClient_iface;
85 IAudioClock IAudioClock_iface;
86 IAudioClock2 IAudioClock2_iface;
87 IAudioStreamVolume IAudioStreamVolume_iface;
89 LONG ref;
91 IMMDevice *parent;
92 IUnknown *pUnkFTMarshal;
94 EDataFlow dataflow;
95 float *vols;
96 UINT32 channel_count;
97 stream_handle stream;
99 HANDLE timer_thread;
101 AudioSession *session;
102 AudioSessionWrapper *session_wrapper;
104 struct list entry;
106 /* Keep at end */
107 char devnode[0];
110 typedef struct _SessionMgr {
111 IAudioSessionManager2 IAudioSessionManager2_iface;
113 LONG ref;
115 IMMDevice *device;
116 } SessionMgr;
118 typedef struct _OSSDevice {
119 struct list entry;
120 EDataFlow flow;
121 GUID guid;
122 char devnode[0];
123 } OSSDevice;
125 static struct list g_devices = LIST_INIT(g_devices);
127 static const WCHAR drv_key_devicesW[] = {'S','o','f','t','w','a','r','e','\\',
128 'W','i','n','e','\\','D','r','i','v','e','r','s','\\',
129 'w','i','n','e','o','s','s','.','d','r','v','\\','d','e','v','i','c','e','s',0};
130 static const WCHAR guidW[] = {'g','u','i','d',0};
132 static CRITICAL_SECTION g_sessions_lock;
133 static CRITICAL_SECTION_DEBUG g_sessions_lock_debug =
135 0, 0, &g_sessions_lock,
136 { &g_sessions_lock_debug.ProcessLocksList, &g_sessions_lock_debug.ProcessLocksList },
137 0, 0, { (DWORD_PTR)(__FILE__ ": g_sessions_lock") }
139 static CRITICAL_SECTION g_sessions_lock = { &g_sessions_lock_debug, -1, 0, 0, 0, 0 };
140 static struct list g_sessions = LIST_INIT(g_sessions);
142 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
144 static const IAudioClient3Vtbl AudioClient3_Vtbl;
145 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
146 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
147 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
148 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
149 static const IAudioClockVtbl AudioClock_Vtbl;
150 static const IAudioClock2Vtbl AudioClock2_Vtbl;
151 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
152 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
153 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl;
155 static inline ACImpl *impl_from_IAudioClient3(IAudioClient3 *iface)
157 return CONTAINING_RECORD(iface, ACImpl, IAudioClient3_iface);
160 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
162 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
165 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
167 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
170 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
172 return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
175 static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
177 return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
180 static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
182 return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
185 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
187 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
190 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
192 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
195 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
197 return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
200 static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface)
202 return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface);
205 BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
207 switch (reason)
209 case DLL_PROCESS_ATTACH:
210 if(__wine_init_unix_call()) return FALSE;
211 break;
213 case DLL_PROCESS_DETACH:
214 if (!reserved)
216 OSSDevice *iter, *iter2;
218 DeleteCriticalSection(&g_sessions_lock);
220 LIST_FOR_EACH_ENTRY_SAFE(iter, iter2, &g_devices, OSSDevice, entry){
221 HeapFree(GetProcessHeap(), 0, iter);
224 break;
226 return TRUE;
229 static HRESULT stream_release(stream_handle stream, HANDLE timer_thread)
231 struct release_stream_params params;
233 params.stream = stream;
234 params.timer_thread = timer_thread;
235 OSS_CALL(release_stream, &params);
237 return params.result;
240 static DWORD WINAPI timer_thread(void *user)
242 struct timer_loop_params params;
243 struct ACImpl *This = user;
245 params.stream = This->stream;
246 OSS_CALL(timer_loop, &params);
248 return 0;
251 static void set_device_guid(EDataFlow flow, HKEY drv_key, const WCHAR *key_name,
252 GUID *guid)
254 HKEY key;
255 BOOL opened = FALSE;
256 LONG lr;
258 if(!drv_key){
259 lr = RegCreateKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, NULL, 0, KEY_WRITE,
260 NULL, &drv_key, NULL);
261 if(lr != ERROR_SUCCESS){
262 ERR("RegCreateKeyEx(drv_key) failed: %lu\n", lr);
263 return;
265 opened = TRUE;
268 lr = RegCreateKeyExW(drv_key, key_name, 0, NULL, 0, KEY_WRITE,
269 NULL, &key, NULL);
270 if(lr != ERROR_SUCCESS){
271 ERR("RegCreateKeyEx(%s) failed: %lu\n", wine_dbgstr_w(key_name), lr);
272 goto exit;
275 lr = RegSetValueExW(key, guidW, 0, REG_BINARY, (BYTE*)guid,
276 sizeof(GUID));
277 if(lr != ERROR_SUCCESS)
278 ERR("RegSetValueEx(%s\\guid) failed: %lu\n", wine_dbgstr_w(key_name), lr);
280 RegCloseKey(key);
281 exit:
282 if(opened)
283 RegCloseKey(drv_key);
286 static void get_device_guid(EDataFlow flow, const char *device, GUID *guid)
288 HKEY key = NULL, dev_key;
289 DWORD type, size = sizeof(*guid);
290 WCHAR key_name[256];
292 if(flow == eCapture)
293 key_name[0] = '1';
294 else
295 key_name[0] = '0';
296 key_name[1] = ',';
297 MultiByteToWideChar(CP_UNIXCP, 0, device, -1, key_name + 2, ARRAY_SIZE(key_name) - 2);
299 if(RegOpenKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, KEY_WRITE|KEY_READ, &key) == ERROR_SUCCESS){
300 if(RegOpenKeyExW(key, key_name, 0, KEY_READ, &dev_key) == ERROR_SUCCESS){
301 if(RegQueryValueExW(dev_key, guidW, 0, &type,
302 (BYTE*)guid, &size) == ERROR_SUCCESS){
303 if(type == REG_BINARY){
304 RegCloseKey(dev_key);
305 RegCloseKey(key);
306 return;
308 ERR("Invalid type for device %s GUID: %lu; ignoring and overwriting\n",
309 wine_dbgstr_w(key_name), type);
311 RegCloseKey(dev_key);
315 CoCreateGuid(guid);
317 set_device_guid(flow, key, key_name, guid);
319 if(key)
320 RegCloseKey(key);
323 static void set_stream_volumes(ACImpl *This)
325 struct set_volumes_params params;
327 params.stream = This->stream;
328 params.master_volume = (This->session->mute ? 0.0f : This->session->master_vol);
329 params.volumes = This->vols;
330 params.session_volumes = This->session->channel_vols;
331 params.channel = 0;
332 OSS_CALL(set_volumes, &params);
335 static const OSSDevice *get_ossdevice_from_guid(const GUID *guid)
337 OSSDevice *dev_item;
338 LIST_FOR_EACH_ENTRY(dev_item, &g_devices, OSSDevice, entry)
339 if(IsEqualGUID(guid, &dev_item->guid))
340 return dev_item;
341 return NULL;
344 static void device_add(OSSDevice *oss_dev)
346 if(get_ossdevice_from_guid(&oss_dev->guid)) /* already in list */
347 HeapFree(GetProcessHeap(), 0, oss_dev);
348 else
349 list_add_tail(&g_devices, &oss_dev->entry);
352 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids_out, GUID **guids_out,
353 UINT *num, UINT *def_index)
355 struct get_endpoint_ids_params params;
356 GUID *guids = NULL;
357 WCHAR **ids = NULL;
358 unsigned int i;
360 TRACE("%d %p %p %p %p\n", flow, ids, guids, num, def_index);
362 params.flow = flow;
363 params.size = 1000;
364 params.endpoints = NULL;
366 HeapFree(GetProcessHeap(), 0, params.endpoints);
367 params.endpoints = HeapAlloc(GetProcessHeap(), 0, params.size);
368 OSS_CALL(get_endpoint_ids, &params);
369 }while(params.result == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
371 if(FAILED(params.result)) goto end;
373 ids = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, params.num * sizeof(*ids));
374 guids = HeapAlloc(GetProcessHeap(), 0, params.num * sizeof(*guids));
375 if(!ids || !guids){
376 params.result = E_OUTOFMEMORY;
377 goto end;
380 for(i = 0; i < params.num; i++){
381 WCHAR *name = (WCHAR *)((char *)params.endpoints + params.endpoints[i].name);
382 char *device = (char *)params.endpoints + params.endpoints[i].device;
383 unsigned int name_size = (wcslen(name) + 1) * sizeof(WCHAR);
384 unsigned int dev_size = strlen(device) + 1;
385 OSSDevice *oss_dev;
387 ids[i] = HeapAlloc(GetProcessHeap(), 0, name_size);
388 oss_dev = HeapAlloc(GetProcessHeap(), 0, offsetof(OSSDevice, devnode[dev_size]));
389 if(!ids[i] || !oss_dev){
390 HeapFree(GetProcessHeap(), 0, oss_dev);
391 params.result = E_OUTOFMEMORY;
392 goto end;
394 memcpy(ids[i], name, name_size);
395 get_device_guid(flow, device, guids + i);
397 oss_dev->flow = flow;
398 oss_dev->guid = guids[i];
399 memcpy(oss_dev->devnode, device, dev_size);
400 device_add(oss_dev);
402 *def_index = params.default_idx;
404 end:
405 HeapFree(GetProcessHeap(), 0, params.endpoints);
406 if(FAILED(params.result)){
407 HeapFree(GetProcessHeap(), 0, guids);
408 if(ids){
409 for(i = 0; i < params.num; i++)
410 HeapFree(GetProcessHeap(), 0, ids[i]);
411 HeapFree(GetProcessHeap(), 0, ids);
413 }else{
414 *ids_out = ids;
415 *guids_out = guids;
416 *num = params.num;
419 return params.result;
422 HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev,
423 IAudioClient **out)
425 ACImpl *This;
426 const OSSDevice *oss_dev;
427 HRESULT hr;
428 int len;
430 TRACE("%s %p %p\n", debugstr_guid(guid), dev, out);
432 oss_dev = get_ossdevice_from_guid(guid);
433 if(!oss_dev){
434 WARN("Unknown GUID: %s\n", debugstr_guid(guid));
435 return AUDCLNT_E_DEVICE_INVALIDATED;
437 len = strlen(oss_dev->devnode);
438 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, offsetof(ACImpl, devnode[len + 1]));
439 if(!This)
440 return E_OUTOFMEMORY;
442 hr = CoCreateFreeThreadedMarshaler((IUnknown *)&This->IAudioClient3_iface, &This->pUnkFTMarshal);
443 if (FAILED(hr)) {
444 HeapFree(GetProcessHeap(), 0, This);
445 return hr;
448 This->dataflow = oss_dev->flow;
449 strcpy(This->devnode, oss_dev->devnode);
451 This->IAudioClient3_iface.lpVtbl = &AudioClient3_Vtbl;
452 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
453 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
454 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
455 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
456 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
458 This->parent = dev;
459 IMMDevice_AddRef(This->parent);
461 *out = (IAudioClient *)&This->IAudioClient3_iface;
462 IAudioClient3_AddRef(&This->IAudioClient3_iface);
464 return S_OK;
467 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient3 *iface,
468 REFIID riid, void **ppv)
470 ACImpl *This = impl_from_IAudioClient3(iface);
471 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
473 if(!ppv)
474 return E_POINTER;
475 *ppv = NULL;
476 if(IsEqualIID(riid, &IID_IUnknown) ||
477 IsEqualIID(riid, &IID_IAudioClient) ||
478 IsEqualIID(riid, &IID_IAudioClient2) ||
479 IsEqualIID(riid, &IID_IAudioClient3))
480 *ppv = iface;
481 else if(IsEqualIID(riid, &IID_IMarshal))
482 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
483 if(*ppv){
484 IUnknown_AddRef((IUnknown*)*ppv);
485 return S_OK;
487 WARN("Unknown interface %s\n", debugstr_guid(riid));
488 return E_NOINTERFACE;
491 static ULONG WINAPI AudioClient_AddRef(IAudioClient3 *iface)
493 ACImpl *This = impl_from_IAudioClient3(iface);
494 ULONG ref;
495 ref = InterlockedIncrement(&This->ref);
496 TRACE("(%p) Refcount now %lu\n", This, ref);
497 return ref;
500 static ULONG WINAPI AudioClient_Release(IAudioClient3 *iface)
502 ACImpl *This = impl_from_IAudioClient3(iface);
503 ULONG ref;
505 ref = InterlockedDecrement(&This->ref);
506 TRACE("(%p) Refcount now %lu\n", This, ref);
507 if(!ref){
508 IAudioClient3_Stop(iface);
509 IMMDevice_Release(This->parent);
510 IUnknown_Release(This->pUnkFTMarshal);
511 if(This->session){
512 EnterCriticalSection(&g_sessions_lock);
513 list_remove(&This->entry);
514 LeaveCriticalSection(&g_sessions_lock);
516 HeapFree(GetProcessHeap(), 0, This->vols);
517 if(This->stream)
518 stream_release(This->stream, This->timer_thread);
519 HeapFree(GetProcessHeap(), 0, This);
521 return ref;
524 static void dump_fmt(const WAVEFORMATEX *fmt)
526 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
527 switch(fmt->wFormatTag){
528 case WAVE_FORMAT_PCM:
529 TRACE("WAVE_FORMAT_PCM");
530 break;
531 case WAVE_FORMAT_IEEE_FLOAT:
532 TRACE("WAVE_FORMAT_IEEE_FLOAT");
533 break;
534 case WAVE_FORMAT_EXTENSIBLE:
535 TRACE("WAVE_FORMAT_EXTENSIBLE");
536 break;
537 default:
538 TRACE("Unknown");
539 break;
541 TRACE(")\n");
543 TRACE("nChannels: %u\n", fmt->nChannels);
544 TRACE("nSamplesPerSec: %lu\n", fmt->nSamplesPerSec);
545 TRACE("nAvgBytesPerSec: %lu\n", fmt->nAvgBytesPerSec);
546 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
547 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
548 TRACE("cbSize: %u\n", fmt->cbSize);
550 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
551 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
552 TRACE("dwChannelMask: %08lx\n", fmtex->dwChannelMask);
553 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
554 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
558 static void session_init_vols(AudioSession *session, UINT channels)
560 if(session->channel_count < channels){
561 UINT i;
563 if(session->channel_vols)
564 session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
565 session->channel_vols, sizeof(float) * channels);
566 else
567 session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
568 sizeof(float) * channels);
569 if(!session->channel_vols)
570 return;
572 for(i = session->channel_count; i < channels; ++i)
573 session->channel_vols[i] = 1.f;
575 session->channel_count = channels;
579 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
580 UINT num_channels)
582 AudioSession *ret;
584 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
585 if(!ret)
586 return NULL;
588 memcpy(&ret->guid, guid, sizeof(GUID));
590 ret->device = device;
592 list_init(&ret->clients);
594 list_add_head(&g_sessions, &ret->entry);
596 session_init_vols(ret, num_channels);
598 ret->master_vol = 1.f;
600 return ret;
603 /* if channels == 0, then this will return or create a session with
604 * matching dataflow and GUID. otherwise, channels must also match */
605 static HRESULT get_audio_session(const GUID *sessionguid,
606 IMMDevice *device, UINT channels, AudioSession **out)
608 AudioSession *session;
610 if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
611 *out = create_session(&GUID_NULL, device, channels);
612 if(!*out)
613 return E_OUTOFMEMORY;
615 return S_OK;
618 *out = NULL;
619 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
620 if(session->device == device &&
621 IsEqualGUID(sessionguid, &session->guid)){
622 session_init_vols(session, channels);
623 *out = session;
624 break;
628 if(!*out){
629 *out = create_session(sessionguid, device, channels);
630 if(!*out)
631 return E_OUTOFMEMORY;
634 return S_OK;
637 static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
638 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
639 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
640 const GUID *sessionguid)
642 ACImpl *This = impl_from_IAudioClient3(iface);
643 struct create_stream_params params;
644 stream_handle stream;
645 unsigned int i;
647 TRACE("(%p)->(%x, %lx, %s, %s, %p, %s)\n", This, mode, flags,
648 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
650 if(!fmt)
651 return E_POINTER;
653 dump_fmt(fmt);
655 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
656 return E_INVALIDARG;
658 if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
659 AUDCLNT_STREAMFLAGS_LOOPBACK |
660 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
661 AUDCLNT_STREAMFLAGS_NOPERSIST |
662 AUDCLNT_STREAMFLAGS_RATEADJUST |
663 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
664 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
665 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED |
666 AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY |
667 AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM)){
668 FIXME("Unknown flags: %08lx\n", flags);
669 return E_INVALIDARG;
672 if(mode == AUDCLNT_SHAREMODE_SHARED){
673 period = DefaultPeriod;
674 if( duration < 3 * period)
675 duration = 3 * period;
676 }else{
677 if(!period)
678 period = DefaultPeriod; /* not minimum */
679 if(period < MinimumPeriod || period > 5000000)
680 return AUDCLNT_E_INVALID_DEVICE_PERIOD;
681 if(duration > 20000000) /* the smaller the period, the lower this limit */
682 return AUDCLNT_E_BUFFER_SIZE_ERROR;
683 if(flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK){
684 if(duration != period)
685 return AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL;
686 FIXME("EXCLUSIVE mode with EVENTCALLBACK\n");
687 return AUDCLNT_E_DEVICE_IN_USE;
688 }else{
689 if( duration < 8 * period)
690 duration = 8 * period; /* may grow above 2s */
694 EnterCriticalSection(&g_sessions_lock);
696 if(This->stream){
697 LeaveCriticalSection(&g_sessions_lock);
698 return AUDCLNT_E_ALREADY_INITIALIZED;
701 params.name = NULL;
702 params.device = This->devnode;
703 params.flow = This->dataflow;
704 params.share = mode;
705 params.flags = flags;
706 params.duration = duration;
707 params.period = period;
708 params.fmt = fmt;
709 params.channel_count = NULL;
710 params.stream = &stream;
712 OSS_CALL(create_stream, &params);
713 if(FAILED(params.result)){
714 LeaveCriticalSection(&g_sessions_lock);
715 return params.result;
718 This->channel_count = fmt->nChannels;
719 This->vols = HeapAlloc(GetProcessHeap(), 0, This->channel_count * sizeof(float));
720 if(!This->vols){
721 params.result = E_OUTOFMEMORY;
722 goto exit;
724 for(i = 0; i < This->channel_count; ++i)
725 This->vols[i] = 1.f;
727 params.result = get_audio_session(sessionguid, This->parent, This->channel_count,
728 &This->session);
730 exit:
731 if(FAILED(params.result)){
732 stream_release(stream, NULL);
733 HeapFree(GetProcessHeap(), 0, This->vols);
734 This->vols = NULL;
735 } else {
736 list_add_tail(&This->session->clients, &This->entry);
737 This->stream = stream;
738 set_stream_volumes(This);
741 LeaveCriticalSection(&g_sessions_lock);
743 return params.result;
746 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient3 *iface,
747 UINT32 *frames)
749 ACImpl *This = impl_from_IAudioClient3(iface);
750 struct get_buffer_size_params params;
752 TRACE("(%p)->(%p)\n", This, frames);
754 if(!frames)
755 return E_POINTER;
757 if(!This->stream)
758 return AUDCLNT_E_NOT_INITIALIZED;
760 params.stream = This->stream;
761 params.frames = frames;
763 OSS_CALL(get_buffer_size, &params);
764 TRACE("buffer size: %u\n", *frames);
766 return params.result;
769 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient3 *iface,
770 REFERENCE_TIME *latency)
772 ACImpl *This = impl_from_IAudioClient3(iface);
773 struct get_latency_params params;
775 TRACE("(%p)->(%p)\n", This, latency);
777 if(!latency)
778 return E_POINTER;
780 if(!This->stream)
781 return AUDCLNT_E_NOT_INITIALIZED;
783 params.stream = This->stream;
784 params.latency = latency;
785 OSS_CALL(get_latency, &params);
787 return params.result;
790 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient3 *iface,
791 UINT32 *numpad)
793 ACImpl *This = impl_from_IAudioClient3(iface);
794 struct get_current_padding_params params;
796 TRACE("(%p)->(%p)\n", This, numpad);
798 if(!numpad)
799 return E_POINTER;
801 if(!This->stream)
802 return AUDCLNT_E_NOT_INITIALIZED;
804 params.stream = This->stream;
805 params.padding = numpad;
806 OSS_CALL(get_current_padding, &params);
807 TRACE("padding: %u\n", *numpad);
809 return params.result;
812 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient3 *iface,
813 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *fmt,
814 WAVEFORMATEX **out)
816 ACImpl *This = impl_from_IAudioClient3(iface);
817 struct is_format_supported_params params;
819 TRACE("(%p)->(%x, %p, %p)\n", This, mode, fmt, out);
820 if(fmt) dump_fmt(fmt);
822 params.device = This->devnode;
823 params.flow = This->dataflow;
824 params.share = mode;
825 params.fmt_in = fmt;
826 params.fmt_out = NULL;
828 if(out){
829 *out = NULL;
830 if(mode == AUDCLNT_SHAREMODE_SHARED)
831 params.fmt_out = CoTaskMemAlloc(sizeof(*params.fmt_out));
833 OSS_CALL(is_format_supported, &params);
835 if(params.result == S_FALSE)
836 *out = &params.fmt_out->Format;
837 else
838 CoTaskMemFree(params.fmt_out);
840 return params.result;
843 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface,
844 WAVEFORMATEX **pwfx)
846 ACImpl *This = impl_from_IAudioClient3(iface);
847 struct get_mix_format_params params;
849 TRACE("(%p)->(%p)\n", This, pwfx);
851 if(!pwfx)
852 return E_POINTER;
853 *pwfx = NULL;
855 params.device = This->devnode;
856 params.flow = This->dataflow;
857 params.fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
858 if(!params.fmt)
859 return E_OUTOFMEMORY;
861 OSS_CALL(get_mix_format, &params);
863 if(SUCCEEDED(params.result)){
864 *pwfx = &params.fmt->Format;
865 dump_fmt(*pwfx);
866 } else
867 CoTaskMemFree(params.fmt);
869 return params.result;
872 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient3 *iface,
873 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
875 ACImpl *This = impl_from_IAudioClient3(iface);
877 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
879 if(!defperiod && !minperiod)
880 return E_POINTER;
882 if(defperiod)
883 *defperiod = DefaultPeriod;
884 if(minperiod)
885 *minperiod = MinimumPeriod;
887 return S_OK;
890 static HRESULT WINAPI AudioClient_Start(IAudioClient3 *iface)
892 ACImpl *This = impl_from_IAudioClient3(iface);
893 struct start_params params;
895 TRACE("(%p)\n", This);
897 EnterCriticalSection(&g_sessions_lock);
899 if(!This->stream){
900 LeaveCriticalSection(&g_sessions_lock);
901 return AUDCLNT_E_NOT_INITIALIZED;
904 params.stream = This->stream;
905 OSS_CALL(start, &params);
907 if(SUCCEEDED(params.result) && !This->timer_thread){
908 This->timer_thread = CreateThread(NULL, 0, timer_thread, This, 0, NULL);
909 SetThreadPriority(This->timer_thread, THREAD_PRIORITY_TIME_CRITICAL);
912 LeaveCriticalSection(&g_sessions_lock);
914 return params.result;
917 static HRESULT WINAPI AudioClient_Stop(IAudioClient3 *iface)
919 ACImpl *This = impl_from_IAudioClient3(iface);
920 struct stop_params params;
922 TRACE("(%p)\n", This);
924 if(!This->stream)
925 return AUDCLNT_E_NOT_INITIALIZED;
927 params.stream = This->stream;
928 OSS_CALL(stop, &params);
930 return params.result;
933 static HRESULT WINAPI AudioClient_Reset(IAudioClient3 *iface)
935 ACImpl *This = impl_from_IAudioClient3(iface);
936 struct reset_params params;
938 TRACE("(%p)\n", This);
940 if(!This->stream)
941 return AUDCLNT_E_NOT_INITIALIZED;
943 params.stream = This->stream;
944 OSS_CALL(reset, &params);
946 return params.result;
949 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient3 *iface,
950 HANDLE event)
952 ACImpl *This = impl_from_IAudioClient3(iface);
953 struct set_event_handle_params params;
955 TRACE("(%p)->(%p)\n", This, event);
957 if(!event)
958 return E_INVALIDARG;
960 if(!This->stream)
961 return AUDCLNT_E_NOT_INITIALIZED;
963 params.stream = This->stream;
964 params.event = event;
965 OSS_CALL(set_event_handle, &params);
967 return params.result;
970 static HRESULT WINAPI AudioClient_GetService(IAudioClient3 *iface, REFIID riid,
971 void **ppv)
973 ACImpl *This = impl_from_IAudioClient3(iface);
975 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
977 if(!ppv)
978 return E_POINTER;
979 *ppv = NULL;
981 EnterCriticalSection(&g_sessions_lock);
983 if(!This->stream){
984 LeaveCriticalSection(&g_sessions_lock);
985 return AUDCLNT_E_NOT_INITIALIZED;
988 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
989 if(This->dataflow != eRender){
990 LeaveCriticalSection(&g_sessions_lock);
991 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
993 IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
994 *ppv = &This->IAudioRenderClient_iface;
995 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
996 if(This->dataflow != eCapture){
997 LeaveCriticalSection(&g_sessions_lock);
998 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1000 IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
1001 *ppv = &This->IAudioCaptureClient_iface;
1002 }else if(IsEqualIID(riid, &IID_IAudioClock)){
1003 IAudioClock_AddRef(&This->IAudioClock_iface);
1004 *ppv = &This->IAudioClock_iface;
1005 }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1006 IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
1007 *ppv = &This->IAudioStreamVolume_iface;
1008 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1009 if(!This->session_wrapper){
1010 This->session_wrapper = AudioSessionWrapper_Create(This);
1011 if(!This->session_wrapper){
1012 LeaveCriticalSection(&g_sessions_lock);
1013 return E_OUTOFMEMORY;
1015 }else
1016 IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
1018 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1019 }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1020 if(!This->session_wrapper){
1021 This->session_wrapper = AudioSessionWrapper_Create(This);
1022 if(!This->session_wrapper){
1023 LeaveCriticalSection(&g_sessions_lock);
1024 return E_OUTOFMEMORY;
1026 }else
1027 IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
1029 *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1030 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1031 if(!This->session_wrapper){
1032 This->session_wrapper = AudioSessionWrapper_Create(This);
1033 if(!This->session_wrapper){
1034 LeaveCriticalSection(&g_sessions_lock);
1035 return E_OUTOFMEMORY;
1037 }else
1038 ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
1040 *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1043 if(*ppv){
1044 LeaveCriticalSection(&g_sessions_lock);
1045 return S_OK;
1048 LeaveCriticalSection(&g_sessions_lock);
1050 FIXME("stub %s\n", debugstr_guid(riid));
1051 return E_NOINTERFACE;
1054 static HRESULT WINAPI AudioClient_IsOffloadCapable(IAudioClient3 *iface,
1055 AUDIO_STREAM_CATEGORY category, BOOL *offload_capable)
1057 ACImpl *This = impl_from_IAudioClient3(iface);
1059 TRACE("(%p)->(0x%x, %p)\n", This, category, offload_capable);
1061 if(!offload_capable)
1062 return E_INVALIDARG;
1064 *offload_capable = FALSE;
1066 return S_OK;
1069 static HRESULT WINAPI AudioClient_SetClientProperties(IAudioClient3 *iface,
1070 const AudioClientProperties *prop)
1072 ACImpl *This = impl_from_IAudioClient3(iface);
1073 const Win8AudioClientProperties *legacy_prop = (const Win8AudioClientProperties *)prop;
1075 TRACE("(%p)->(%p)\n", This, prop);
1077 if(!legacy_prop)
1078 return E_POINTER;
1080 if(legacy_prop->cbSize == sizeof(AudioClientProperties)){
1081 TRACE("{ bIsOffload: %u, eCategory: 0x%x, Options: 0x%x }\n",
1082 legacy_prop->bIsOffload,
1083 legacy_prop->eCategory,
1084 prop->Options);
1085 }else if(legacy_prop->cbSize == sizeof(Win8AudioClientProperties)){
1086 TRACE("{ bIsOffload: %u, eCategory: 0x%x }\n",
1087 legacy_prop->bIsOffload,
1088 legacy_prop->eCategory);
1089 }else{
1090 WARN("Unsupported Size = %d\n", legacy_prop->cbSize);
1091 return E_INVALIDARG;
1095 if(legacy_prop->bIsOffload)
1096 return AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE;
1098 return S_OK;
1101 static HRESULT WINAPI AudioClient_GetBufferSizeLimits(IAudioClient3 *iface,
1102 const WAVEFORMATEX *format, BOOL event_driven, REFERENCE_TIME *min_duration,
1103 REFERENCE_TIME *max_duration)
1105 ACImpl *This = impl_from_IAudioClient3(iface);
1107 FIXME("(%p)->(%p, %u, %p, %p)\n", This, format, event_driven, min_duration, max_duration);
1109 return E_NOTIMPL;
1112 static HRESULT WINAPI AudioClient_GetSharedModeEnginePeriod(IAudioClient3 *iface,
1113 const WAVEFORMATEX *format, UINT32 *default_period_frames, UINT32 *unit_period_frames,
1114 UINT32 *min_period_frames, UINT32 *max_period_frames)
1116 ACImpl *This = impl_from_IAudioClient3(iface);
1118 FIXME("(%p)->(%p, %p, %p, %p, %p)\n", This, format, default_period_frames, unit_period_frames,
1119 min_period_frames, max_period_frames);
1121 return E_NOTIMPL;
1124 static HRESULT WINAPI AudioClient_GetCurrentSharedModeEnginePeriod(IAudioClient3 *iface,
1125 WAVEFORMATEX **cur_format, UINT32 *cur_period_frames)
1127 ACImpl *This = impl_from_IAudioClient3(iface);
1129 FIXME("(%p)->(%p, %p)\n", This, cur_format, cur_period_frames);
1131 return E_NOTIMPL;
1134 static HRESULT WINAPI AudioClient_InitializeSharedAudioStream(IAudioClient3 *iface,
1135 DWORD flags, UINT32 period_frames, const WAVEFORMATEX *format,
1136 const GUID *session_guid)
1138 ACImpl *This = impl_from_IAudioClient3(iface);
1140 FIXME("(%p)->(0x%lx, %u, %p, %s)\n", This, flags, period_frames, format, debugstr_guid(session_guid));
1142 return E_NOTIMPL;
1145 static const IAudioClient3Vtbl AudioClient3_Vtbl =
1147 AudioClient_QueryInterface,
1148 AudioClient_AddRef,
1149 AudioClient_Release,
1150 AudioClient_Initialize,
1151 AudioClient_GetBufferSize,
1152 AudioClient_GetStreamLatency,
1153 AudioClient_GetCurrentPadding,
1154 AudioClient_IsFormatSupported,
1155 AudioClient_GetMixFormat,
1156 AudioClient_GetDevicePeriod,
1157 AudioClient_Start,
1158 AudioClient_Stop,
1159 AudioClient_Reset,
1160 AudioClient_SetEventHandle,
1161 AudioClient_GetService,
1162 AudioClient_IsOffloadCapable,
1163 AudioClient_SetClientProperties,
1164 AudioClient_GetBufferSizeLimits,
1165 AudioClient_GetSharedModeEnginePeriod,
1166 AudioClient_GetCurrentSharedModeEnginePeriod,
1167 AudioClient_InitializeSharedAudioStream,
1170 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1171 IAudioRenderClient *iface, REFIID riid, void **ppv)
1173 ACImpl *This = impl_from_IAudioRenderClient(iface);
1174 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1176 if(!ppv)
1177 return E_POINTER;
1178 *ppv = NULL;
1180 if(IsEqualIID(riid, &IID_IUnknown) ||
1181 IsEqualIID(riid, &IID_IAudioRenderClient))
1182 *ppv = iface;
1183 else if(IsEqualIID(riid, &IID_IMarshal))
1184 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
1185 if(*ppv){
1186 IUnknown_AddRef((IUnknown*)*ppv);
1187 return S_OK;
1190 WARN("Unknown interface %s\n", debugstr_guid(riid));
1191 return E_NOINTERFACE;
1194 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1196 ACImpl *This = impl_from_IAudioRenderClient(iface);
1197 return AudioClient_AddRef(&This->IAudioClient3_iface);
1200 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1202 ACImpl *This = impl_from_IAudioRenderClient(iface);
1203 return AudioClient_Release(&This->IAudioClient3_iface);
1206 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1207 UINT32 frames, BYTE **data)
1209 ACImpl *This = impl_from_IAudioRenderClient(iface);
1210 struct get_render_buffer_params params;
1212 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1214 if(!data)
1215 return E_POINTER;
1217 *data = NULL;
1219 params.stream = This->stream;
1220 params.frames = frames;
1221 params.data = data;
1222 OSS_CALL(get_render_buffer, &params);
1224 return params.result;
1227 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1228 IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
1230 ACImpl *This = impl_from_IAudioRenderClient(iface);
1231 struct release_render_buffer_params params;
1233 TRACE("(%p)->(%u, %lx)\n", This, written_frames, flags);
1235 params.stream = This->stream;
1236 params.written_frames = written_frames;
1237 params.flags = flags;
1238 OSS_CALL(release_render_buffer, &params);
1240 return params.result;
1243 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1244 AudioRenderClient_QueryInterface,
1245 AudioRenderClient_AddRef,
1246 AudioRenderClient_Release,
1247 AudioRenderClient_GetBuffer,
1248 AudioRenderClient_ReleaseBuffer
1251 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1252 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1254 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1255 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1257 if(!ppv)
1258 return E_POINTER;
1259 *ppv = NULL;
1261 if(IsEqualIID(riid, &IID_IUnknown) ||
1262 IsEqualIID(riid, &IID_IAudioCaptureClient))
1263 *ppv = iface;
1264 else if(IsEqualIID(riid, &IID_IMarshal))
1265 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
1266 if(*ppv){
1267 IUnknown_AddRef((IUnknown*)*ppv);
1268 return S_OK;
1271 WARN("Unknown interface %s\n", debugstr_guid(riid));
1272 return E_NOINTERFACE;
1275 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1277 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1278 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1281 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1283 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1284 return IAudioClient3_Release(&This->IAudioClient3_iface);
1287 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1288 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1289 UINT64 *qpcpos)
1291 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1292 struct get_capture_buffer_params params;
1294 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1295 devpos, qpcpos);
1297 if(!data)
1298 return E_POINTER;
1300 *data = NULL;
1302 if(!frames || !flags)
1303 return E_POINTER;
1305 params.stream = This->stream;
1306 params.data = data;
1307 params.frames = frames;
1308 params.flags = (UINT*)flags;
1309 params.devpos = devpos;
1310 params.qpcpos = qpcpos;
1311 OSS_CALL(get_capture_buffer, &params);
1313 return params.result;
1316 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1317 IAudioCaptureClient *iface, UINT32 done)
1319 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1320 struct release_capture_buffer_params params;
1322 TRACE("(%p)->(%u)\n", This, done);
1324 params.stream = This->stream;
1325 params.done = done;
1326 OSS_CALL(release_capture_buffer, &params);
1328 return params.result;
1331 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1332 IAudioCaptureClient *iface, UINT32 *frames)
1334 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1335 struct get_next_packet_size_params params;
1337 TRACE("(%p)->(%p)\n", This, frames);
1339 if(!frames)
1340 return E_POINTER;
1342 params.stream = This->stream;
1343 params.frames = frames;
1344 OSS_CALL(get_next_packet_size, &params);
1346 return params.result;
1349 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1351 AudioCaptureClient_QueryInterface,
1352 AudioCaptureClient_AddRef,
1353 AudioCaptureClient_Release,
1354 AudioCaptureClient_GetBuffer,
1355 AudioCaptureClient_ReleaseBuffer,
1356 AudioCaptureClient_GetNextPacketSize
1359 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1360 REFIID riid, void **ppv)
1362 ACImpl *This = impl_from_IAudioClock(iface);
1364 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1366 if(!ppv)
1367 return E_POINTER;
1368 *ppv = NULL;
1370 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
1371 *ppv = iface;
1372 else if(IsEqualIID(riid, &IID_IAudioClock2))
1373 *ppv = &This->IAudioClock2_iface;
1374 if(*ppv){
1375 IUnknown_AddRef((IUnknown*)*ppv);
1376 return S_OK;
1379 WARN("Unknown interface %s\n", debugstr_guid(riid));
1380 return E_NOINTERFACE;
1383 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
1385 ACImpl *This = impl_from_IAudioClock(iface);
1386 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1389 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
1391 ACImpl *This = impl_from_IAudioClock(iface);
1392 return IAudioClient3_Release(&This->IAudioClient3_iface);
1395 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
1397 ACImpl *This = impl_from_IAudioClock(iface);
1398 struct get_frequency_params params;
1400 TRACE("(%p)->(%p)\n", This, freq);
1402 params.stream = This->stream;
1403 params.freq = freq;
1404 OSS_CALL(get_frequency, &params);
1406 return params.result;
1409 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
1410 UINT64 *qpctime)
1412 ACImpl *This = impl_from_IAudioClock(iface);
1413 struct get_position_params params;
1415 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
1417 if(!pos)
1418 return E_POINTER;
1420 params.stream = This->stream;
1421 params.device = FALSE;
1422 params.pos = pos;
1423 params.qpctime = qpctime;
1424 OSS_CALL(get_position, &params);
1426 return params.result;
1429 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
1430 DWORD *chars)
1432 ACImpl *This = impl_from_IAudioClock(iface);
1434 TRACE("(%p)->(%p)\n", This, chars);
1436 if(!chars)
1437 return E_POINTER;
1439 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
1441 return S_OK;
1444 static const IAudioClockVtbl AudioClock_Vtbl =
1446 AudioClock_QueryInterface,
1447 AudioClock_AddRef,
1448 AudioClock_Release,
1449 AudioClock_GetFrequency,
1450 AudioClock_GetPosition,
1451 AudioClock_GetCharacteristics
1454 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
1455 REFIID riid, void **ppv)
1457 ACImpl *This = impl_from_IAudioClock2(iface);
1458 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
1461 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
1463 ACImpl *This = impl_from_IAudioClock2(iface);
1464 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1467 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
1469 ACImpl *This = impl_from_IAudioClock2(iface);
1470 return IAudioClient3_Release(&This->IAudioClient3_iface);
1473 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
1474 UINT64 *pos, UINT64 *qpctime)
1476 ACImpl *This = impl_from_IAudioClock2(iface);
1478 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
1480 return E_NOTIMPL;
1483 static const IAudioClock2Vtbl AudioClock2_Vtbl =
1485 AudioClock2_QueryInterface,
1486 AudioClock2_AddRef,
1487 AudioClock2_Release,
1488 AudioClock2_GetDevicePosition
1491 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
1493 AudioSessionWrapper *ret;
1495 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1496 sizeof(AudioSessionWrapper));
1497 if(!ret)
1498 return NULL;
1500 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
1501 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
1502 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
1504 ret->ref = 1;
1506 ret->client = client;
1507 if(client){
1508 ret->session = client->session;
1509 AudioClient_AddRef(&client->IAudioClient3_iface);
1512 return ret;
1515 static HRESULT WINAPI AudioSessionControl_QueryInterface(
1516 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
1518 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1520 if(!ppv)
1521 return E_POINTER;
1522 *ppv = NULL;
1524 if(IsEqualIID(riid, &IID_IUnknown) ||
1525 IsEqualIID(riid, &IID_IAudioSessionControl) ||
1526 IsEqualIID(riid, &IID_IAudioSessionControl2))
1527 *ppv = iface;
1528 if(*ppv){
1529 IUnknown_AddRef((IUnknown*)*ppv);
1530 return S_OK;
1533 WARN("Unknown interface %s\n", debugstr_guid(riid));
1534 return E_NOINTERFACE;
1537 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
1539 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1540 ULONG ref;
1541 ref = InterlockedIncrement(&This->ref);
1542 TRACE("(%p) Refcount now %lu\n", This, ref);
1543 return ref;
1546 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
1548 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1549 ULONG ref;
1550 ref = InterlockedDecrement(&This->ref);
1551 TRACE("(%p) Refcount now %lu\n", This, ref);
1552 if(!ref){
1553 if(This->client){
1554 EnterCriticalSection(&g_sessions_lock);
1555 This->client->session_wrapper = NULL;
1556 LeaveCriticalSection(&g_sessions_lock);
1557 AudioClient_Release(&This->client->IAudioClient3_iface);
1559 HeapFree(GetProcessHeap(), 0, This);
1561 return ref;
1564 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
1565 AudioSessionState *state)
1567 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1568 struct is_started_params params;
1569 ACImpl *client;
1571 TRACE("(%p)->(%p)\n", This, state);
1573 if(!state)
1574 return NULL_PTR_ERR;
1576 EnterCriticalSection(&g_sessions_lock);
1578 if(list_empty(&This->session->clients)){
1579 *state = AudioSessionStateExpired;
1580 LeaveCriticalSection(&g_sessions_lock);
1581 return S_OK;
1584 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
1585 params.stream = client->stream;
1586 OSS_CALL(is_started, &params);
1587 if(params.result == S_OK){
1588 *state = AudioSessionStateActive;
1589 LeaveCriticalSection(&g_sessions_lock);
1590 return S_OK;
1594 LeaveCriticalSection(&g_sessions_lock);
1596 *state = AudioSessionStateInactive;
1598 return S_OK;
1601 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
1602 IAudioSessionControl2 *iface, WCHAR **name)
1604 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1606 FIXME("(%p)->(%p) - stub\n", This, name);
1608 return E_NOTIMPL;
1611 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
1612 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
1614 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1616 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
1618 return E_NOTIMPL;
1621 static HRESULT WINAPI AudioSessionControl_GetIconPath(
1622 IAudioSessionControl2 *iface, WCHAR **path)
1624 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1626 FIXME("(%p)->(%p) - stub\n", This, path);
1628 return E_NOTIMPL;
1631 static HRESULT WINAPI AudioSessionControl_SetIconPath(
1632 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
1634 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1636 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
1638 return E_NOTIMPL;
1641 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
1642 IAudioSessionControl2 *iface, GUID *group)
1644 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1646 FIXME("(%p)->(%p) - stub\n", This, group);
1648 return E_NOTIMPL;
1651 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
1652 IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
1654 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1656 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
1657 debugstr_guid(session));
1659 return E_NOTIMPL;
1662 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
1663 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
1665 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1667 FIXME("(%p)->(%p) - stub\n", This, events);
1669 return S_OK;
1672 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
1673 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
1675 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1677 FIXME("(%p)->(%p) - stub\n", This, events);
1679 return S_OK;
1682 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
1683 IAudioSessionControl2 *iface, WCHAR **id)
1685 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1687 FIXME("(%p)->(%p) - stub\n", This, id);
1689 return E_NOTIMPL;
1692 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
1693 IAudioSessionControl2 *iface, WCHAR **id)
1695 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1697 FIXME("(%p)->(%p) - stub\n", This, id);
1699 return E_NOTIMPL;
1702 static HRESULT WINAPI AudioSessionControl_GetProcessId(
1703 IAudioSessionControl2 *iface, DWORD *pid)
1705 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1707 TRACE("(%p)->(%p)\n", This, pid);
1709 if(!pid)
1710 return E_POINTER;
1712 *pid = GetCurrentProcessId();
1714 return S_OK;
1717 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
1718 IAudioSessionControl2 *iface)
1720 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1722 TRACE("(%p)\n", This);
1724 return S_FALSE;
1727 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
1728 IAudioSessionControl2 *iface, BOOL optout)
1730 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1732 TRACE("(%p)->(%d)\n", This, optout);
1734 return S_OK;
1737 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
1739 AudioSessionControl_QueryInterface,
1740 AudioSessionControl_AddRef,
1741 AudioSessionControl_Release,
1742 AudioSessionControl_GetState,
1743 AudioSessionControl_GetDisplayName,
1744 AudioSessionControl_SetDisplayName,
1745 AudioSessionControl_GetIconPath,
1746 AudioSessionControl_SetIconPath,
1747 AudioSessionControl_GetGroupingParam,
1748 AudioSessionControl_SetGroupingParam,
1749 AudioSessionControl_RegisterAudioSessionNotification,
1750 AudioSessionControl_UnregisterAudioSessionNotification,
1751 AudioSessionControl_GetSessionIdentifier,
1752 AudioSessionControl_GetSessionInstanceIdentifier,
1753 AudioSessionControl_GetProcessId,
1754 AudioSessionControl_IsSystemSoundsSession,
1755 AudioSessionControl_SetDuckingPreference
1758 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
1759 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
1761 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1763 if(!ppv)
1764 return E_POINTER;
1765 *ppv = NULL;
1767 if(IsEqualIID(riid, &IID_IUnknown) ||
1768 IsEqualIID(riid, &IID_ISimpleAudioVolume))
1769 *ppv = iface;
1770 if(*ppv){
1771 IUnknown_AddRef((IUnknown*)*ppv);
1772 return S_OK;
1775 WARN("Unknown interface %s\n", debugstr_guid(riid));
1776 return E_NOINTERFACE;
1779 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
1781 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1782 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
1785 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
1787 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1788 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
1791 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
1792 ISimpleAudioVolume *iface, float level, const GUID *context)
1794 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1795 AudioSession *session = This->session;
1796 ACImpl *client;
1798 TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
1800 if(level < 0.f || level > 1.f)
1801 return E_INVALIDARG;
1803 if(context)
1804 FIXME("Notifications not supported yet\n");
1806 EnterCriticalSection(&g_sessions_lock);
1808 session->master_vol = level;
1810 TRACE("OSS doesn't support setting volume\n");
1811 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
1812 set_stream_volumes(client);
1814 LeaveCriticalSection(&g_sessions_lock);
1816 return S_OK;
1819 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
1820 ISimpleAudioVolume *iface, float *level)
1822 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1823 AudioSession *session = This->session;
1825 TRACE("(%p)->(%p)\n", session, level);
1827 if(!level)
1828 return NULL_PTR_ERR;
1830 *level = session->master_vol;
1832 return S_OK;
1835 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
1836 BOOL mute, const GUID *context)
1838 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1839 AudioSession *session = This->session;
1840 ACImpl *client;
1842 TRACE("(%p)->(%u, %s)\n", session, mute, debugstr_guid(context));
1844 EnterCriticalSection(&g_sessions_lock);
1846 session->mute = mute;
1848 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
1849 set_stream_volumes(client);
1851 LeaveCriticalSection(&g_sessions_lock);
1853 return S_OK;
1856 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
1857 BOOL *mute)
1859 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1860 AudioSession *session = This->session;
1862 TRACE("(%p)->(%p)\n", session, mute);
1864 if(!mute)
1865 return NULL_PTR_ERR;
1867 *mute = This->session->mute;
1869 return S_OK;
1872 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
1874 SimpleAudioVolume_QueryInterface,
1875 SimpleAudioVolume_AddRef,
1876 SimpleAudioVolume_Release,
1877 SimpleAudioVolume_SetMasterVolume,
1878 SimpleAudioVolume_GetMasterVolume,
1879 SimpleAudioVolume_SetMute,
1880 SimpleAudioVolume_GetMute
1883 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
1884 IAudioStreamVolume *iface, REFIID riid, void **ppv)
1886 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1888 if(!ppv)
1889 return E_POINTER;
1890 *ppv = NULL;
1892 if(IsEqualIID(riid, &IID_IUnknown) ||
1893 IsEqualIID(riid, &IID_IAudioStreamVolume))
1894 *ppv = iface;
1895 if(*ppv){
1896 IUnknown_AddRef((IUnknown*)*ppv);
1897 return S_OK;
1900 WARN("Unknown interface %s\n", debugstr_guid(riid));
1901 return E_NOINTERFACE;
1904 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
1906 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1907 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1910 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
1912 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1913 return IAudioClient3_Release(&This->IAudioClient3_iface);
1916 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
1917 IAudioStreamVolume *iface, UINT32 *out)
1919 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1921 TRACE("(%p)->(%p)\n", This, out);
1923 if(!out)
1924 return E_POINTER;
1926 *out = This->channel_count;
1928 return S_OK;
1931 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
1932 IAudioStreamVolume *iface, UINT32 index, float level)
1934 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1936 TRACE("(%p)->(%d, %f)\n", This, index, level);
1938 if(level < 0.f || level > 1.f)
1939 return E_INVALIDARG;
1941 if(index >= This->channel_count)
1942 return E_INVALIDARG;
1944 EnterCriticalSection(&g_sessions_lock);
1946 This->vols[index] = level;
1948 TRACE("OSS doesn't support setting volume\n");
1949 set_stream_volumes(This);
1951 LeaveCriticalSection(&g_sessions_lock);
1953 return S_OK;
1956 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
1957 IAudioStreamVolume *iface, UINT32 index, float *level)
1959 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1961 TRACE("(%p)->(%d, %p)\n", This, index, level);
1963 if(!level)
1964 return E_POINTER;
1966 if(index >= This->channel_count)
1967 return E_INVALIDARG;
1969 *level = This->vols[index];
1971 return S_OK;
1974 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
1975 IAudioStreamVolume *iface, UINT32 count, const float *levels)
1977 ACImpl *This = impl_from_IAudioStreamVolume(iface);
1978 int i;
1980 TRACE("(%p)->(%d, %p)\n", This, count, levels);
1982 if(!levels)
1983 return E_POINTER;
1985 if(count != This->channel_count)
1986 return E_INVALIDARG;
1988 EnterCriticalSection(&g_sessions_lock);
1990 for(i = 0; i < count; ++i)
1991 This->vols[i] = levels[i];
1993 TRACE("OSS doesn't support setting volume\n");
1994 set_stream_volumes(This);
1996 LeaveCriticalSection(&g_sessions_lock);
1998 return S_OK;
2001 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2002 IAudioStreamVolume *iface, UINT32 count, float *levels)
2004 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2005 int i;
2007 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2009 if(!levels)
2010 return E_POINTER;
2012 if(count != This->channel_count)
2013 return E_INVALIDARG;
2015 EnterCriticalSection(&g_sessions_lock);
2017 for(i = 0; i < count; ++i)
2018 levels[i] = This->vols[i];
2020 LeaveCriticalSection(&g_sessions_lock);
2022 return S_OK;
2025 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2027 AudioStreamVolume_QueryInterface,
2028 AudioStreamVolume_AddRef,
2029 AudioStreamVolume_Release,
2030 AudioStreamVolume_GetChannelCount,
2031 AudioStreamVolume_SetChannelVolume,
2032 AudioStreamVolume_GetChannelVolume,
2033 AudioStreamVolume_SetAllVolumes,
2034 AudioStreamVolume_GetAllVolumes
2037 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2038 IChannelAudioVolume *iface, REFIID riid, void **ppv)
2040 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2042 if(!ppv)
2043 return E_POINTER;
2044 *ppv = NULL;
2046 if(IsEqualIID(riid, &IID_IUnknown) ||
2047 IsEqualIID(riid, &IID_IChannelAudioVolume))
2048 *ppv = iface;
2049 if(*ppv){
2050 IUnknown_AddRef((IUnknown*)*ppv);
2051 return S_OK;
2054 WARN("Unknown interface %s\n", debugstr_guid(riid));
2055 return E_NOINTERFACE;
2058 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2060 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2061 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2064 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2066 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2067 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2070 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2071 IChannelAudioVolume *iface, UINT32 *out)
2073 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2074 AudioSession *session = This->session;
2076 TRACE("(%p)->(%p)\n", session, out);
2078 if(!out)
2079 return NULL_PTR_ERR;
2081 *out = session->channel_count;
2083 return S_OK;
2086 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2087 IChannelAudioVolume *iface, UINT32 index, float level,
2088 const GUID *context)
2090 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2091 AudioSession *session = This->session;
2092 ACImpl *client;
2094 TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2095 wine_dbgstr_guid(context));
2097 if(level < 0.f || level > 1.f)
2098 return E_INVALIDARG;
2100 if(index >= session->channel_count)
2101 return E_INVALIDARG;
2103 if(context)
2104 FIXME("Notifications not supported yet\n");
2106 EnterCriticalSection(&g_sessions_lock);
2108 session->channel_vols[index] = level;
2110 TRACE("OSS doesn't support setting volume\n");
2111 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
2112 set_stream_volumes(client);
2114 LeaveCriticalSection(&g_sessions_lock);
2116 return S_OK;
2119 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2120 IChannelAudioVolume *iface, UINT32 index, float *level)
2122 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2123 AudioSession *session = This->session;
2125 TRACE("(%p)->(%d, %p)\n", session, index, level);
2127 if(!level)
2128 return NULL_PTR_ERR;
2130 if(index >= session->channel_count)
2131 return E_INVALIDARG;
2133 *level = session->channel_vols[index];
2135 return S_OK;
2138 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2139 IChannelAudioVolume *iface, UINT32 count, const float *levels,
2140 const GUID *context)
2142 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2143 AudioSession *session = This->session;
2144 ACImpl *client;
2145 int i;
2147 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2148 wine_dbgstr_guid(context));
2150 if(!levels)
2151 return NULL_PTR_ERR;
2153 if(count != session->channel_count)
2154 return E_INVALIDARG;
2156 if(context)
2157 FIXME("Notifications not supported yet\n");
2159 EnterCriticalSection(&g_sessions_lock);
2161 for(i = 0; i < count; ++i)
2162 session->channel_vols[i] = levels[i];
2164 TRACE("OSS doesn't support setting volume\n");
2165 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry)
2166 set_stream_volumes(client);
2168 LeaveCriticalSection(&g_sessions_lock);
2170 return S_OK;
2173 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2174 IChannelAudioVolume *iface, UINT32 count, float *levels)
2176 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2177 AudioSession *session = This->session;
2178 int i;
2180 TRACE("(%p)->(%d, %p)\n", session, count, levels);
2182 if(!levels)
2183 return NULL_PTR_ERR;
2185 if(count != session->channel_count)
2186 return E_INVALIDARG;
2188 for(i = 0; i < count; ++i)
2189 levels[i] = session->channel_vols[i];
2191 return S_OK;
2194 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2196 ChannelAudioVolume_QueryInterface,
2197 ChannelAudioVolume_AddRef,
2198 ChannelAudioVolume_Release,
2199 ChannelAudioVolume_GetChannelCount,
2200 ChannelAudioVolume_SetChannelVolume,
2201 ChannelAudioVolume_GetChannelVolume,
2202 ChannelAudioVolume_SetAllVolumes,
2203 ChannelAudioVolume_GetAllVolumes
2206 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2207 REFIID riid, void **ppv)
2209 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2211 if(!ppv)
2212 return E_POINTER;
2213 *ppv = NULL;
2215 if(IsEqualIID(riid, &IID_IUnknown) ||
2216 IsEqualIID(riid, &IID_IAudioSessionManager) ||
2217 IsEqualIID(riid, &IID_IAudioSessionManager2))
2218 *ppv = iface;
2219 if(*ppv){
2220 IUnknown_AddRef((IUnknown*)*ppv);
2221 return S_OK;
2224 WARN("Unknown interface %s\n", debugstr_guid(riid));
2225 return E_NOINTERFACE;
2228 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2230 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2231 ULONG ref;
2232 ref = InterlockedIncrement(&This->ref);
2233 TRACE("(%p) Refcount now %lu\n", This, ref);
2234 return ref;
2237 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2239 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2240 ULONG ref;
2241 ref = InterlockedDecrement(&This->ref);
2242 TRACE("(%p) Refcount now %lu\n", This, ref);
2243 if(!ref)
2244 HeapFree(GetProcessHeap(), 0, This);
2245 return ref;
2248 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2249 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2250 IAudioSessionControl **out)
2252 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2253 AudioSession *session;
2254 AudioSessionWrapper *wrapper;
2255 HRESULT hr;
2257 TRACE("(%p)->(%s, %lx, %p)\n", This, debugstr_guid(session_guid),
2258 flags, out);
2260 hr = get_audio_session(session_guid, This->device, 0, &session);
2261 if(FAILED(hr))
2262 return hr;
2264 wrapper = AudioSessionWrapper_Create(NULL);
2265 if(!wrapper)
2266 return E_OUTOFMEMORY;
2268 wrapper->session = session;
2270 *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
2272 return S_OK;
2275 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
2276 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2277 ISimpleAudioVolume **out)
2279 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2280 AudioSession *session;
2281 AudioSessionWrapper *wrapper;
2282 HRESULT hr;
2284 TRACE("(%p)->(%s, %lx, %p)\n", This, debugstr_guid(session_guid),
2285 flags, out);
2287 hr = get_audio_session(session_guid, This->device, 0, &session);
2288 if(FAILED(hr))
2289 return hr;
2291 wrapper = AudioSessionWrapper_Create(NULL);
2292 if(!wrapper)
2293 return E_OUTOFMEMORY;
2295 wrapper->session = session;
2297 *out = &wrapper->ISimpleAudioVolume_iface;
2299 return S_OK;
2302 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
2303 IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
2305 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2306 FIXME("(%p)->(%p) - stub\n", This, out);
2307 return E_NOTIMPL;
2310 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
2311 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2313 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2314 FIXME("(%p)->(%p) - stub\n", This, notification);
2315 return E_NOTIMPL;
2318 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
2319 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2321 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2322 FIXME("(%p)->(%p) - stub\n", This, notification);
2323 return E_NOTIMPL;
2326 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
2327 IAudioSessionManager2 *iface, const WCHAR *session_id,
2328 IAudioVolumeDuckNotification *notification)
2330 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2331 FIXME("(%p)->(%p) - stub\n", This, notification);
2332 return E_NOTIMPL;
2335 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
2336 IAudioSessionManager2 *iface,
2337 IAudioVolumeDuckNotification *notification)
2339 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2340 FIXME("(%p)->(%p) - stub\n", This, notification);
2341 return E_NOTIMPL;
2344 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
2346 AudioSessionManager_QueryInterface,
2347 AudioSessionManager_AddRef,
2348 AudioSessionManager_Release,
2349 AudioSessionManager_GetAudioSessionControl,
2350 AudioSessionManager_GetSimpleAudioVolume,
2351 AudioSessionManager_GetSessionEnumerator,
2352 AudioSessionManager_RegisterSessionNotification,
2353 AudioSessionManager_UnregisterSessionNotification,
2354 AudioSessionManager_RegisterDuckNotification,
2355 AudioSessionManager_UnregisterDuckNotification
2358 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
2359 IAudioSessionManager2 **out)
2361 SessionMgr *This;
2363 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
2364 if(!This)
2365 return E_OUTOFMEMORY;
2367 This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
2368 This->device = device;
2369 This->ref = 1;
2371 *out = &This->IAudioSessionManager2_iface;
2373 return S_OK;