winecoreaudio: Move is_started to the unixlib.
[wine.git] / dlls / winecoreaudio.drv / mmdevdrv.c
blob07260c16ff0b36a2d2726017493385e42f23b398
1 /*
2 * Copyright 2011 Andrew Eikum for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #define NONAMELESSUNION
20 #define COBJMACROS
21 #include "config.h"
23 #define LoadResource __carbon_LoadResource
24 #define CompareString __carbon_CompareString
25 #define GetCurrentThread __carbon_GetCurrentThread
26 #define GetCurrentProcess __carbon_GetCurrentProcess
28 #include <stdarg.h>
30 #include <errno.h>
31 #include <limits.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <sys/ioctl.h>
38 #include <fcntl.h>
39 #include <fenv.h>
40 #include <unistd.h>
42 #include <libkern/OSAtomic.h>
43 #include <CoreAudio/CoreAudio.h>
44 #include <AudioToolbox/AudioFormat.h>
45 #include <AudioToolbox/AudioConverter.h>
46 #include <AudioUnit/AudioUnit.h>
48 #undef LoadResource
49 #undef CompareString
50 #undef GetCurrentThread
51 #undef GetCurrentProcess
52 #undef _CDECL
54 #include "windef.h"
55 #include "winbase.h"
56 #include "winnls.h"
57 #include "winreg.h"
58 #include "wine/debug.h"
59 #include "wine/heap.h"
60 #include "wine/unicode.h"
61 #include "wine/list.h"
62 #include "wine/unixlib.h"
64 #include "ole2.h"
65 #include "mmdeviceapi.h"
66 #include "devpkey.h"
67 #include "dshow.h"
68 #include "dsound.h"
70 #include "initguid.h"
71 #include "endpointvolume.h"
72 #include "audioclient.h"
73 #include "audiopolicy.h"
74 #include "unixlib.h"
76 WINE_DEFAULT_DEBUG_CHANNEL(coreaudio);
78 unixlib_handle_t coreaudio_handle = 0;
80 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
82 static const REFERENCE_TIME DefaultPeriod = 100000;
83 static const REFERENCE_TIME MinimumPeriod = 50000;
85 struct ACImpl;
86 typedef struct ACImpl ACImpl;
88 typedef struct _AudioSession {
89 GUID guid;
90 struct list clients;
92 IMMDevice *device;
94 float master_vol;
95 UINT32 channel_count;
96 float *channel_vols;
97 BOOL mute;
99 struct list entry;
100 } AudioSession;
102 typedef struct _AudioSessionWrapper {
103 IAudioSessionControl2 IAudioSessionControl2_iface;
104 IChannelAudioVolume IChannelAudioVolume_iface;
105 ISimpleAudioVolume ISimpleAudioVolume_iface;
107 LONG ref;
109 ACImpl *client;
110 AudioSession *session;
111 } AudioSessionWrapper;
113 struct ACImpl {
114 IAudioClient3 IAudioClient3_iface;
115 IAudioRenderClient IAudioRenderClient_iface;
116 IAudioCaptureClient IAudioCaptureClient_iface;
117 IAudioClock IAudioClock_iface;
118 IAudioClock2 IAudioClock2_iface;
119 IAudioStreamVolume IAudioStreamVolume_iface;
121 LONG ref;
123 IMMDevice *parent;
124 IUnknown *pUnkFTMarshal;
126 EDataFlow dataflow;
127 UINT32 channel_count, period_ms;
128 DWORD flags;
129 HANDLE event;
130 float *vols;
132 AudioDeviceID adevid;
133 HANDLE timer;
135 AudioSession *session;
136 AudioSessionWrapper *session_wrapper;
138 struct coreaudio_stream *stream;
139 struct list entry;
142 static const IAudioClient3Vtbl AudioClient3_Vtbl;
143 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
144 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
145 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
146 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
147 static const IAudioClockVtbl AudioClock_Vtbl;
148 static const IAudioClock2Vtbl AudioClock2_Vtbl;
149 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
150 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
151 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl;
153 typedef struct _SessionMgr {
154 IAudioSessionManager2 IAudioSessionManager2_iface;
156 LONG ref;
158 IMMDevice *device;
159 } SessionMgr;
161 static const WCHAR drv_key_devicesW[] = {'S','o','f','t','w','a','r','e','\\',
162 'W','i','n','e','\\','D','r','i','v','e','r','s','\\',
163 'w','i','n','e','c','o','r','e','a','u','d','i','o','.','d','r','v','\\','d','e','v','i','c','e','s',0};
164 static const WCHAR guidW[] = {'g','u','i','d',0};
166 static HANDLE g_timer_q;
168 static CRITICAL_SECTION g_sessions_lock;
169 static CRITICAL_SECTION_DEBUG g_sessions_lock_debug =
171 0, 0, &g_sessions_lock,
172 { &g_sessions_lock_debug.ProcessLocksList, &g_sessions_lock_debug.ProcessLocksList },
173 0, 0, { (DWORD_PTR)(__FILE__ ": g_sessions_lock") }
175 static CRITICAL_SECTION g_sessions_lock = { &g_sessions_lock_debug, -1, 0, 0, 0, 0 };
176 static struct list g_sessions = LIST_INIT(g_sessions);
178 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
179 static HRESULT ca_setvol(ACImpl *This, struct coreaudio_stream *stream, UINT32 index);
181 static inline ACImpl *impl_from_IAudioClient3(IAudioClient3 *iface)
183 return CONTAINING_RECORD(iface, ACImpl, IAudioClient3_iface);
186 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
188 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
191 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
193 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
196 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
198 return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
201 static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
203 return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
206 static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
208 return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
211 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
213 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
216 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
218 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
221 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
223 return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
226 static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface)
228 return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface);
231 BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
233 switch (reason)
235 case DLL_PROCESS_ATTACH:
236 if(NtQueryVirtualMemory(GetCurrentProcess(), dll, MemoryWineUnixFuncs,
237 &coreaudio_handle, sizeof(coreaudio_handle), NULL))
238 return FALSE;
239 g_timer_q = CreateTimerQueue();
240 if(!g_timer_q)
241 return FALSE;
242 break;
244 case DLL_PROCESS_DETACH:
245 if (reserved) break;
246 DeleteCriticalSection(&g_sessions_lock);
247 break;
249 return TRUE;
252 /* From <dlls/mmdevapi/mmdevapi.h> */
253 enum DriverPriority {
254 Priority_Unavailable = 0,
255 Priority_Low,
256 Priority_Neutral,
257 Priority_Preferred
260 int WINAPI AUDDRV_GetPriority(void)
262 return Priority_Neutral;
265 static void set_device_guid(EDataFlow flow, HKEY drv_key, const WCHAR *key_name,
266 GUID *guid)
268 HKEY key;
269 BOOL opened = FALSE;
270 LONG lr;
272 if(!drv_key){
273 lr = RegCreateKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, NULL, 0, KEY_WRITE,
274 NULL, &drv_key, NULL);
275 if(lr != ERROR_SUCCESS){
276 ERR("RegCreateKeyEx(drv_key) failed: %u\n", lr);
277 return;
279 opened = TRUE;
282 lr = RegCreateKeyExW(drv_key, key_name, 0, NULL, 0, KEY_WRITE,
283 NULL, &key, NULL);
284 if(lr != ERROR_SUCCESS){
285 ERR("RegCreateKeyEx(%s) failed: %u\n", wine_dbgstr_w(key_name), lr);
286 goto exit;
289 lr = RegSetValueExW(key, guidW, 0, REG_BINARY, (BYTE*)guid,
290 sizeof(GUID));
291 if(lr != ERROR_SUCCESS)
292 ERR("RegSetValueEx(%s\\guid) failed: %u\n", wine_dbgstr_w(key_name), lr);
294 RegCloseKey(key);
295 exit:
296 if(opened)
297 RegCloseKey(drv_key);
300 static void get_device_guid(EDataFlow flow, DWORD device_id, GUID *guid)
302 HKEY key = NULL, dev_key;
303 DWORD type, size = sizeof(*guid);
304 WCHAR key_name[256];
306 static const WCHAR key_fmt[] = {'%','u',0};
308 if(flow == eCapture)
309 key_name[0] = '1';
310 else
311 key_name[0] = '0';
312 key_name[1] = ',';
314 sprintfW(key_name + 2, key_fmt, device_id);
316 if(RegOpenKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, KEY_WRITE|KEY_READ, &key) == ERROR_SUCCESS){
317 if(RegOpenKeyExW(key, key_name, 0, KEY_READ, &dev_key) == ERROR_SUCCESS){
318 if(RegQueryValueExW(dev_key, guidW, 0, &type,
319 (BYTE*)guid, &size) == ERROR_SUCCESS){
320 if(type == REG_BINARY){
321 RegCloseKey(dev_key);
322 RegCloseKey(key);
323 return;
325 ERR("Invalid type for device %s GUID: %u; ignoring and overwriting\n",
326 wine_dbgstr_w(key_name), type);
328 RegCloseKey(dev_key);
332 CoCreateGuid(guid);
334 set_device_guid(flow, key, key_name, guid);
336 if(key)
337 RegCloseKey(key);
340 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids_out,
341 GUID **guids_out, UINT *num, UINT *def_index)
343 struct get_endpoint_ids_params params;
344 unsigned int i;
345 GUID *guids;
346 WCHAR **ids;
348 TRACE("%d %p %p %p\n", flow, ids_out, num, def_index);
350 params.flow = flow;
351 params.size = 1000;
352 params.endpoints = NULL;
354 heap_free(params.endpoints);
355 params.endpoints = heap_alloc(params.size);
356 UNIX_CALL(get_endpoint_ids, &params);
357 }while(params.result == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
359 if(FAILED(params.result)) goto end;
361 ids = heap_alloc_zero(params.num * sizeof(*ids));
362 guids = heap_alloc(params.num * sizeof(*guids));
363 if(!ids || !guids){
364 params.result = E_OUTOFMEMORY;
365 goto end;
368 for(i = 0; i < params.num; i++){
369 int size = (strlenW(params.endpoints[i].name) + 1) * sizeof(WCHAR);
370 ids[i] = heap_alloc(size);
371 if(!ids[i]){
372 params.result = E_OUTOFMEMORY;
373 goto end;
375 memcpy(ids[i], params.endpoints[i].name, size);
376 get_device_guid(flow, params.endpoints[i].id, guids + i);
378 *def_index = params.default_idx;
380 end:
381 heap_free(params.endpoints);
382 if(FAILED(params.result)){
383 heap_free(guids);
384 if(ids){
385 for(i = 0; i < params.num; i++) heap_free(ids[i]);
386 heap_free(ids);
388 }else{
389 *ids_out = ids;
390 *guids_out = guids;
391 *num = params.num;
394 return params.result;
397 static BOOL get_deviceid_by_guid(GUID *guid, AudioDeviceID *id, EDataFlow *flow)
399 HKEY devices_key;
400 UINT i = 0;
401 WCHAR key_name[256];
402 DWORD key_name_size;
404 if(RegOpenKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, KEY_READ, &devices_key) != ERROR_SUCCESS){
405 ERR("No devices in registry?\n");
406 return FALSE;
409 while(1){
410 HKEY key;
411 DWORD size, type;
412 GUID reg_guid;
414 key_name_size = sizeof(key_name);
415 if(RegEnumKeyExW(devices_key, i++, key_name, &key_name_size, NULL,
416 NULL, NULL, NULL) != ERROR_SUCCESS)
417 break;
419 if(RegOpenKeyExW(devices_key, key_name, 0, KEY_READ, &key) != ERROR_SUCCESS){
420 WARN("Couldn't open key: %s\n", wine_dbgstr_w(key_name));
421 continue;
424 size = sizeof(reg_guid);
425 if(RegQueryValueExW(key, guidW, 0, &type,
426 (BYTE*)&reg_guid, &size) == ERROR_SUCCESS){
427 if(IsEqualGUID(&reg_guid, guid)){
428 RegCloseKey(key);
429 RegCloseKey(devices_key);
431 TRACE("Found matching device key: %s\n", wine_dbgstr_w(key_name));
433 if(key_name[0] == '0')
434 *flow = eRender;
435 else if(key_name[0] == '1')
436 *flow = eCapture;
437 else{
438 ERR("Unknown device type: %c\n", key_name[0]);
439 return FALSE;
442 *id = strtoulW(key_name + 2, NULL, 10);
444 return TRUE;
448 RegCloseKey(key);
451 RegCloseKey(devices_key);
453 WARN("No matching device in registry for GUID %s\n", debugstr_guid(guid));
455 return FALSE;
458 HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient **out)
460 ACImpl *This;
461 AudioDeviceID adevid;
462 EDataFlow dataflow;
463 HRESULT hr;
465 TRACE("%s %p %p\n", debugstr_guid(guid), dev, out);
467 if(!get_deviceid_by_guid(guid, &adevid, &dataflow))
468 return AUDCLNT_E_DEVICE_INVALIDATED;
470 if(dataflow != eRender && dataflow != eCapture)
471 return E_INVALIDARG;
473 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACImpl));
474 if(!This)
475 return E_OUTOFMEMORY;
477 This->IAudioClient3_iface.lpVtbl = &AudioClient3_Vtbl;
478 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
479 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
480 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
481 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
482 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
484 This->dataflow = dataflow;
486 hr = CoCreateFreeThreadedMarshaler((IUnknown *)&This->IAudioClient3_iface, &This->pUnkFTMarshal);
487 if (FAILED(hr)) {
488 HeapFree(GetProcessHeap(), 0, This);
489 return hr;
492 This->parent = dev;
493 IMMDevice_AddRef(This->parent);
495 This->adevid = adevid;
497 *out = (IAudioClient *)&This->IAudioClient3_iface;
498 IAudioClient3_AddRef(&This->IAudioClient3_iface);
500 return S_OK;
503 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient3 *iface,
504 REFIID riid, void **ppv)
506 ACImpl *This = impl_from_IAudioClient3(iface);
507 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
509 if(!ppv)
510 return E_POINTER;
511 *ppv = NULL;
512 if(IsEqualIID(riid, &IID_IUnknown) ||
513 IsEqualIID(riid, &IID_IAudioClient) ||
514 IsEqualIID(riid, &IID_IAudioClient2) ||
515 IsEqualIID(riid, &IID_IAudioClient3))
516 *ppv = iface;
517 else if(IsEqualIID(riid, &IID_IMarshal))
518 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
520 if(*ppv){
521 IUnknown_AddRef((IUnknown*)*ppv);
522 return S_OK;
524 WARN("Unknown interface %s\n", debugstr_guid(riid));
525 return E_NOINTERFACE;
528 static ULONG WINAPI AudioClient_AddRef(IAudioClient3 *iface)
530 ACImpl *This = impl_from_IAudioClient3(iface);
531 ULONG ref;
532 ref = InterlockedIncrement(&This->ref);
533 TRACE("(%p) Refcount now %u\n", This, ref);
534 return ref;
537 static ULONG WINAPI AudioClient_Release(IAudioClient3 *iface)
539 ACImpl *This = impl_from_IAudioClient3(iface);
540 struct release_stream_params params;
541 ULONG ref;
543 ref = InterlockedDecrement(&This->ref);
544 TRACE("(%p) Refcount now %u\n", This, ref);
545 if(!ref){
546 if(This->timer){
547 HANDLE event;
548 BOOL wait;
549 event = CreateEventW(NULL, TRUE, FALSE, NULL);
550 wait = !DeleteTimerQueueTimer(g_timer_q, This->timer, event);
551 wait = wait && GetLastError() == ERROR_IO_PENDING;
552 if(event && wait)
553 WaitForSingleObject(event, INFINITE);
554 CloseHandle(event);
556 if(This->stream){
557 params.stream = This->stream;
558 UNIX_CALL(release_stream, &params);
560 if(This->session){
561 EnterCriticalSection(&g_sessions_lock);
562 list_remove(&This->entry);
563 LeaveCriticalSection(&g_sessions_lock);
565 HeapFree(GetProcessHeap(), 0, This->vols);
566 IMMDevice_Release(This->parent);
567 IUnknown_Release(This->pUnkFTMarshal);
568 HeapFree(GetProcessHeap(), 0, This);
570 return ref;
573 static void dump_fmt(const WAVEFORMATEX *fmt)
575 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
576 switch(fmt->wFormatTag){
577 case WAVE_FORMAT_PCM:
578 TRACE("WAVE_FORMAT_PCM");
579 break;
580 case WAVE_FORMAT_IEEE_FLOAT:
581 TRACE("WAVE_FORMAT_IEEE_FLOAT");
582 break;
583 case WAVE_FORMAT_EXTENSIBLE:
584 TRACE("WAVE_FORMAT_EXTENSIBLE");
585 break;
586 default:
587 TRACE("Unknown");
588 break;
590 TRACE(")\n");
592 TRACE("nChannels: %u\n", fmt->nChannels);
593 TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
594 TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
595 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
596 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
597 TRACE("cbSize: %u\n", fmt->cbSize);
599 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
600 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
601 TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
602 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
603 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
607 static void session_init_vols(AudioSession *session, UINT channels)
609 if(session->channel_count < channels){
610 UINT i;
612 if(session->channel_vols)
613 session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
614 session->channel_vols, sizeof(float) * channels);
615 else
616 session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
617 sizeof(float) * channels);
618 if(!session->channel_vols)
619 return;
621 for(i = session->channel_count; i < channels; ++i)
622 session->channel_vols[i] = 1.f;
624 session->channel_count = channels;
628 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
629 UINT num_channels)
631 AudioSession *ret;
633 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
634 if(!ret)
635 return NULL;
637 memcpy(&ret->guid, guid, sizeof(GUID));
639 ret->device = device;
641 list_init(&ret->clients);
643 list_add_head(&g_sessions, &ret->entry);
645 session_init_vols(ret, num_channels);
647 ret->master_vol = 1.f;
649 return ret;
652 /* if channels == 0, then this will return or create a session with
653 * matching dataflow and GUID. otherwise, channels must also match */
654 static HRESULT get_audio_session(const GUID *sessionguid,
655 IMMDevice *device, UINT channels, AudioSession **out)
657 AudioSession *session;
659 if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
660 *out = create_session(&GUID_NULL, device, channels);
661 if(!*out)
662 return E_OUTOFMEMORY;
664 return S_OK;
667 *out = NULL;
668 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
669 if(session->device == device &&
670 IsEqualGUID(sessionguid, &session->guid)){
671 session_init_vols(session, channels);
672 *out = session;
673 break;
677 if(!*out){
678 *out = create_session(sessionguid, device, channels);
679 if(!*out)
680 return E_OUTOFMEMORY;
683 return S_OK;
686 static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
687 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
688 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
689 const GUID *sessionguid)
691 ACImpl *This = impl_from_IAudioClient3(iface);
692 struct release_stream_params release_params;
693 struct create_stream_params params;
694 UINT32 i;
696 TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
697 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
699 if(!fmt)
700 return E_POINTER;
702 dump_fmt(fmt);
704 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
705 return E_INVALIDARG;
707 if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
708 AUDCLNT_STREAMFLAGS_LOOPBACK |
709 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
710 AUDCLNT_STREAMFLAGS_NOPERSIST |
711 AUDCLNT_STREAMFLAGS_RATEADJUST |
712 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
713 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
714 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED |
715 AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY |
716 AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM)){
717 FIXME("Unknown flags: %08x\n", flags);
718 return E_INVALIDARG;
721 if(mode == AUDCLNT_SHAREMODE_SHARED){
722 period = DefaultPeriod;
723 if( duration < 3 * period)
724 duration = 3 * period;
725 }else{
726 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
727 if(((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask == 0 ||
728 ((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask & SPEAKER_RESERVED)
729 return AUDCLNT_E_UNSUPPORTED_FORMAT;
732 if(!period)
733 period = DefaultPeriod; /* not minimum */
734 if(period < MinimumPeriod || period > 5000000)
735 return AUDCLNT_E_INVALID_DEVICE_PERIOD;
736 if(duration > 20000000) /* the smaller the period, the lower this limit */
737 return AUDCLNT_E_BUFFER_SIZE_ERROR;
738 if(flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK){
739 if(duration != period)
740 return AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL;
741 FIXME("EXCLUSIVE mode with EVENTCALLBACK\n");
742 return AUDCLNT_E_DEVICE_IN_USE;
743 }else{
744 if( duration < 8 * period)
745 duration = 8 * period; /* may grow above 2s */
749 EnterCriticalSection(&g_sessions_lock);
751 if(This->stream){
752 LeaveCriticalSection(&g_sessions_lock);
753 return AUDCLNT_E_ALREADY_INITIALIZED;
756 params.dev_id = This->adevid;
757 params.flow = This->dataflow;
758 params.share = mode;
759 params.duration = duration;
760 params.period = period;
761 params.fmt = fmt;
762 params.stream = NULL;
764 UNIX_CALL(create_stream, &params);
765 if(FAILED(params.result)) goto end;
767 This->flags = flags;
768 This->channel_count = fmt->nChannels;
769 This->period_ms = period / 10000;
771 This->vols = HeapAlloc(GetProcessHeap(), 0, This->channel_count * sizeof(float));
772 if(!This->vols){
773 params.result = E_OUTOFMEMORY;
774 goto end;
777 for(i = 0; i < This->channel_count; ++i)
778 This->vols[i] = 1.f;
780 params.result = get_audio_session(sessionguid, This->parent, fmt->nChannels, &This->session);
781 if(FAILED(params.result)) goto end;
783 list_add_tail(&This->session->clients, &This->entry);
785 ca_setvol(This, params.stream, -1);
787 end:
788 if(FAILED(params.result)){
789 if(params.stream){
790 release_params.stream = params.stream;
791 UNIX_CALL(release_stream, &release_params);
793 HeapFree(GetProcessHeap(), 0, This->vols);
794 This->vols = NULL;
795 }else
796 This->stream = params.stream;
798 LeaveCriticalSection(&g_sessions_lock);
800 return params.result;
803 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient3 *iface,
804 UINT32 *frames)
806 ACImpl *This = impl_from_IAudioClient3(iface);
807 struct get_buffer_size_params params;
809 TRACE("(%p)->(%p)\n", This, frames);
811 if(!frames)
812 return E_POINTER;
814 if(!This->stream)
815 return AUDCLNT_E_NOT_INITIALIZED;
817 params.stream = This->stream;
818 params.frames = frames;
819 UNIX_CALL(get_buffer_size, &params);
820 return params.result;
823 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient3 *iface,
824 REFERENCE_TIME *out)
826 ACImpl *This = impl_from_IAudioClient3(iface);
827 struct get_latency_params params;
829 TRACE("(%p)->(%p)\n", This, out);
831 if(!out)
832 return E_POINTER;
834 if(!This->stream)
835 return AUDCLNT_E_NOT_INITIALIZED;
837 params.stream = This->stream;
838 params.latency = out;
839 UNIX_CALL(get_latency, &params);
840 return params.result;
843 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient3 *iface,
844 UINT32 *numpad)
846 ACImpl *This = impl_from_IAudioClient3(iface);
847 struct get_current_padding_params params;
849 TRACE("(%p)->(%p)\n", This, numpad);
851 if(!numpad)
852 return E_POINTER;
854 if(!This->stream)
855 return AUDCLNT_E_NOT_INITIALIZED;
857 params.stream = This->stream;
858 params.padding = numpad;
859 UNIX_CALL(get_current_padding, &params);
860 return params.result;
863 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient3 *iface,
864 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
865 WAVEFORMATEX **outpwfx)
867 ACImpl *This = impl_from_IAudioClient3(iface);
868 struct is_format_supported_params params;
870 TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx);
871 if(pwfx) dump_fmt(pwfx);
873 params.dev_id = This->adevid;
874 params.flow = This->dataflow;
875 params.share = mode;
876 params.fmt_in = pwfx;
877 params.fmt_out = NULL;
879 if(outpwfx){
880 *outpwfx = NULL;
881 if(mode == AUDCLNT_SHAREMODE_SHARED)
882 params.fmt_out = CoTaskMemAlloc(sizeof(*params.fmt_out));
884 UNIX_CALL(is_format_supported, &params);
886 if(params.result == S_FALSE)
887 *outpwfx = &params.fmt_out->Format;
888 else
889 CoTaskMemFree(params.fmt_out);
891 return params.result;
894 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface,
895 WAVEFORMATEX **pwfx)
897 ACImpl *This = impl_from_IAudioClient3(iface);
898 struct get_mix_format_params params;
900 TRACE("(%p)->(%p)\n", This, pwfx);
902 if(!pwfx)
903 return E_POINTER;
904 *pwfx = NULL;
906 params.dev_id = This->adevid;
907 params.flow = This->dataflow;
908 params.fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
909 if(!params.fmt)
910 return E_OUTOFMEMORY;
912 UNIX_CALL(get_mix_format, &params);
914 if(SUCCEEDED(params.result)){
915 *pwfx = &params.fmt->Format;
916 dump_fmt(*pwfx);
917 }else
918 CoTaskMemFree(params.fmt);
920 return params.result;
923 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient3 *iface,
924 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
926 ACImpl *This = impl_from_IAudioClient3(iface);
928 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
930 if(!defperiod && !minperiod)
931 return E_POINTER;
933 if(defperiod)
934 *defperiod = DefaultPeriod;
935 if(minperiod)
936 *minperiod = MinimumPeriod;
938 return S_OK;
941 void CALLBACK ca_period_cb(void *user, BOOLEAN timer)
943 ACImpl *This = user;
945 if(This->event)
946 SetEvent(This->event);
949 static HRESULT WINAPI AudioClient_Start(IAudioClient3 *iface)
951 ACImpl *This = impl_from_IAudioClient3(iface);
952 struct start_params params;
954 TRACE("(%p)\n", This);
956 if(!This->stream)
957 return AUDCLNT_E_NOT_INITIALIZED;
959 if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event)
960 return AUDCLNT_E_EVENTHANDLE_NOT_SET;
962 params.stream = This->stream;
963 UNIX_CALL(start, &params);
965 if(SUCCEEDED(params.result)){
966 if(This->event && !This->timer){
967 if(!CreateTimerQueueTimer(&This->timer, g_timer_q, ca_period_cb, This, 0,
968 This->period_ms, WT_EXECUTEINTIMERTHREAD)){
969 This->timer = NULL;
970 IAudioClient3_Stop(iface);
971 WARN("Unable to create timer: %u\n", GetLastError());
972 return E_OUTOFMEMORY;
976 return params.result;
979 static HRESULT WINAPI AudioClient_Stop(IAudioClient3 *iface)
981 ACImpl *This = impl_from_IAudioClient3(iface);
982 struct stop_params params;
984 TRACE("(%p)\n", This);
986 if(!This->stream)
987 return AUDCLNT_E_NOT_INITIALIZED;
989 params.stream = This->stream;
990 UNIX_CALL(stop, &params);
991 return params.result;
994 static HRESULT WINAPI AudioClient_Reset(IAudioClient3 *iface)
996 ACImpl *This = impl_from_IAudioClient3(iface);
997 struct reset_params params;
999 TRACE("(%p)\n", This);
1001 if(!This->stream)
1002 return AUDCLNT_E_NOT_INITIALIZED;
1004 params.stream = This->stream;
1005 UNIX_CALL(reset, &params);
1006 return params.result;
1009 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient3 *iface,
1010 HANDLE event)
1012 ACImpl *This = impl_from_IAudioClient3(iface);
1013 HRESULT hr = S_OK;
1015 TRACE("(%p)->(%p)\n", This, event);
1017 if(!event)
1018 return E_INVALIDARG;
1020 if(!This->stream)
1021 return AUDCLNT_E_NOT_INITIALIZED;
1023 EnterCriticalSection(&g_sessions_lock);
1025 if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK))
1026 hr = AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1027 else if(This->event){
1028 FIXME("called twice\n");
1029 hr = HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
1030 }else
1031 This->event = event;
1033 LeaveCriticalSection(&g_sessions_lock);
1035 return hr;
1038 static HRESULT WINAPI AudioClient_GetService(IAudioClient3 *iface, REFIID riid,
1039 void **ppv)
1041 ACImpl *This = impl_from_IAudioClient3(iface);
1042 HRESULT hr;
1044 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1046 if(!ppv)
1047 return E_POINTER;
1048 *ppv = NULL;
1050 if(!This->stream)
1051 return AUDCLNT_E_NOT_INITIALIZED;
1053 EnterCriticalSection(&g_sessions_lock);
1055 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1056 if(This->dataflow != eRender){
1057 hr = AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1058 goto end;
1060 IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
1061 *ppv = &This->IAudioRenderClient_iface;
1062 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1063 if(This->dataflow != eCapture){
1064 hr = AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1065 goto end;
1067 IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
1068 *ppv = &This->IAudioCaptureClient_iface;
1069 }else if(IsEqualIID(riid, &IID_IAudioClock)){
1070 IAudioClock_AddRef(&This->IAudioClock_iface);
1071 *ppv = &This->IAudioClock_iface;
1072 }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1073 IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
1074 *ppv = &This->IAudioStreamVolume_iface;
1075 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1076 if(!This->session_wrapper){
1077 This->session_wrapper = AudioSessionWrapper_Create(This);
1078 if(!This->session_wrapper){
1079 hr = E_OUTOFMEMORY;
1080 goto end;
1082 }else
1083 IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
1085 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1086 }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1087 if(!This->session_wrapper){
1088 This->session_wrapper = AudioSessionWrapper_Create(This);
1089 if(!This->session_wrapper){
1090 hr = E_OUTOFMEMORY;
1091 goto end;
1093 }else
1094 IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
1096 *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1097 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1098 if(!This->session_wrapper){
1099 This->session_wrapper = AudioSessionWrapper_Create(This);
1100 if(!This->session_wrapper){
1101 hr = E_OUTOFMEMORY;
1102 goto end;
1104 }else
1105 ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
1107 *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1110 if(*ppv) hr = S_OK;
1111 else{
1112 FIXME("stub %s\n", debugstr_guid(riid));
1113 hr = E_NOINTERFACE;
1116 end:
1117 LeaveCriticalSection(&g_sessions_lock);
1118 return hr;
1121 static HRESULT WINAPI AudioClient_IsOffloadCapable(IAudioClient3 *iface,
1122 AUDIO_STREAM_CATEGORY category, BOOL *offload_capable)
1124 ACImpl *This = impl_from_IAudioClient3(iface);
1126 TRACE("(%p)->(0x%x, %p)\n", This, category, offload_capable);
1128 if(!offload_capable)
1129 return E_INVALIDARG;
1131 *offload_capable = FALSE;
1133 return S_OK;
1136 static HRESULT WINAPI AudioClient_SetClientProperties(IAudioClient3 *iface,
1137 const AudioClientProperties *prop)
1139 ACImpl *This = impl_from_IAudioClient3(iface);
1140 const Win8AudioClientProperties *legacy_prop = (const Win8AudioClientProperties *)prop;
1142 TRACE("(%p)->(%p)\n", This, prop);
1144 if(!legacy_prop)
1145 return E_POINTER;
1147 if(legacy_prop->cbSize == sizeof(AudioClientProperties)){
1148 TRACE("{ bIsOffload: %u, eCategory: 0x%x, Options: 0x%x }\n",
1149 legacy_prop->bIsOffload,
1150 legacy_prop->eCategory,
1151 prop->Options);
1152 }else if(legacy_prop->cbSize == sizeof(Win8AudioClientProperties)){
1153 TRACE("{ bIsOffload: %u, eCategory: 0x%x }\n",
1154 legacy_prop->bIsOffload,
1155 legacy_prop->eCategory);
1156 }else{
1157 WARN("Unsupported Size = %d\n", legacy_prop->cbSize);
1158 return E_INVALIDARG;
1162 if(legacy_prop->bIsOffload)
1163 return AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE;
1165 return S_OK;
1168 static HRESULT WINAPI AudioClient_GetBufferSizeLimits(IAudioClient3 *iface,
1169 const WAVEFORMATEX *format, BOOL event_driven, REFERENCE_TIME *min_duration,
1170 REFERENCE_TIME *max_duration)
1172 ACImpl *This = impl_from_IAudioClient3(iface);
1174 FIXME("(%p)->(%p, %u, %p, %p)\n", This, format, event_driven, min_duration, max_duration);
1176 return E_NOTIMPL;
1179 static HRESULT WINAPI AudioClient_GetSharedModeEnginePeriod(IAudioClient3 *iface,
1180 const WAVEFORMATEX *format, UINT32 *default_period_frames, UINT32 *unit_period_frames,
1181 UINT32 *min_period_frames, UINT32 *max_period_frames)
1183 ACImpl *This = impl_from_IAudioClient3(iface);
1185 FIXME("(%p)->(%p, %p, %p, %p, %p)\n", This, format, default_period_frames, unit_period_frames,
1186 min_period_frames, max_period_frames);
1188 return E_NOTIMPL;
1191 static HRESULT WINAPI AudioClient_GetCurrentSharedModeEnginePeriod(IAudioClient3 *iface,
1192 WAVEFORMATEX **cur_format, UINT32 *cur_period_frames)
1194 ACImpl *This = impl_from_IAudioClient3(iface);
1196 FIXME("(%p)->(%p, %p)\n", This, cur_format, cur_period_frames);
1198 return E_NOTIMPL;
1201 static HRESULT WINAPI AudioClient_InitializeSharedAudioStream(IAudioClient3 *iface,
1202 DWORD flags, UINT32 period_frames, const WAVEFORMATEX *format,
1203 const GUID *session_guid)
1205 ACImpl *This = impl_from_IAudioClient3(iface);
1207 FIXME("(%p)->(0x%x, %u, %p, %s)\n", This, flags, period_frames, format, debugstr_guid(session_guid));
1209 return E_NOTIMPL;
1212 static const IAudioClient3Vtbl AudioClient3_Vtbl =
1214 AudioClient_QueryInterface,
1215 AudioClient_AddRef,
1216 AudioClient_Release,
1217 AudioClient_Initialize,
1218 AudioClient_GetBufferSize,
1219 AudioClient_GetStreamLatency,
1220 AudioClient_GetCurrentPadding,
1221 AudioClient_IsFormatSupported,
1222 AudioClient_GetMixFormat,
1223 AudioClient_GetDevicePeriod,
1224 AudioClient_Start,
1225 AudioClient_Stop,
1226 AudioClient_Reset,
1227 AudioClient_SetEventHandle,
1228 AudioClient_GetService,
1229 AudioClient_IsOffloadCapable,
1230 AudioClient_SetClientProperties,
1231 AudioClient_GetBufferSizeLimits,
1232 AudioClient_GetSharedModeEnginePeriod,
1233 AudioClient_GetCurrentSharedModeEnginePeriod,
1234 AudioClient_InitializeSharedAudioStream,
1237 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1238 IAudioRenderClient *iface, REFIID riid, void **ppv)
1240 ACImpl *This = impl_from_IAudioRenderClient(iface);
1241 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1243 if(!ppv)
1244 return E_POINTER;
1245 *ppv = NULL;
1247 if(IsEqualIID(riid, &IID_IUnknown) ||
1248 IsEqualIID(riid, &IID_IAudioRenderClient))
1249 *ppv = iface;
1250 else if(IsEqualIID(riid, &IID_IMarshal))
1251 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
1253 if(*ppv){
1254 IUnknown_AddRef((IUnknown*)*ppv);
1255 return S_OK;
1258 WARN("Unknown interface %s\n", debugstr_guid(riid));
1259 return E_NOINTERFACE;
1262 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1264 ACImpl *This = impl_from_IAudioRenderClient(iface);
1265 return AudioClient_AddRef(&This->IAudioClient3_iface);
1268 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1270 ACImpl *This = impl_from_IAudioRenderClient(iface);
1271 return AudioClient_Release(&This->IAudioClient3_iface);
1274 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1275 UINT32 frames, BYTE **data)
1277 ACImpl *This = impl_from_IAudioRenderClient(iface);
1278 struct get_render_buffer_params params;
1280 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1282 if(!data)
1283 return E_POINTER;
1284 *data = NULL;
1286 params.stream = This->stream;
1287 params.frames = frames;
1288 params.data = data;
1289 UNIX_CALL(get_render_buffer, &params);
1290 return params.result;
1293 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1294 IAudioRenderClient *iface, UINT32 frames, DWORD flags)
1296 ACImpl *This = impl_from_IAudioRenderClient(iface);
1297 struct release_render_buffer_params params;
1299 TRACE("(%p)->(%u, %x)\n", This, frames, flags);
1301 params.stream = This->stream;
1302 params.frames = frames;
1303 params.flags = flags;
1304 UNIX_CALL(release_render_buffer, &params);
1305 return params.result;
1308 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1309 AudioRenderClient_QueryInterface,
1310 AudioRenderClient_AddRef,
1311 AudioRenderClient_Release,
1312 AudioRenderClient_GetBuffer,
1313 AudioRenderClient_ReleaseBuffer
1316 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1317 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1319 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1320 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1322 if(!ppv)
1323 return E_POINTER;
1324 *ppv = NULL;
1326 if(IsEqualIID(riid, &IID_IUnknown) ||
1327 IsEqualIID(riid, &IID_IAudioCaptureClient))
1328 *ppv = iface;
1329 else if(IsEqualIID(riid, &IID_IMarshal))
1330 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
1332 if(*ppv){
1333 IUnknown_AddRef((IUnknown*)*ppv);
1334 return S_OK;
1337 WARN("Unknown interface %s\n", debugstr_guid(riid));
1338 return E_NOINTERFACE;
1341 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1343 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1344 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1347 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1349 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1350 return IAudioClient3_Release(&This->IAudioClient3_iface);
1353 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1354 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1355 UINT64 *qpcpos)
1357 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1358 struct get_capture_buffer_params params;
1360 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1361 devpos, qpcpos);
1363 if(!data)
1364 return E_POINTER;
1366 *data = NULL;
1368 if(!frames || !flags)
1369 return E_POINTER;
1371 params.stream = This->stream;
1372 params.data = data;
1373 params.frames = frames;
1374 params.flags = flags;
1375 params.devpos = devpos;
1376 params.qpcpos = qpcpos;
1377 UNIX_CALL(get_capture_buffer, &params);
1378 return params.result;
1381 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1382 IAudioCaptureClient *iface, UINT32 done)
1384 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1385 struct release_capture_buffer_params params;
1387 TRACE("(%p)->(%u)\n", This, done);
1389 params.stream = This->stream;
1390 params.done = done;
1391 UNIX_CALL(release_capture_buffer, &params);
1392 return params.result;
1395 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1396 IAudioCaptureClient *iface, UINT32 *frames)
1398 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1399 struct get_next_packet_size_params params;
1401 TRACE("(%p)->(%p)\n", This, frames);
1403 if(!frames)
1404 return E_POINTER;
1406 params.stream = This->stream;
1407 params.frames = frames;
1408 UNIX_CALL(get_next_packet_size, &params);
1409 return params.result;
1412 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1414 AudioCaptureClient_QueryInterface,
1415 AudioCaptureClient_AddRef,
1416 AudioCaptureClient_Release,
1417 AudioCaptureClient_GetBuffer,
1418 AudioCaptureClient_ReleaseBuffer,
1419 AudioCaptureClient_GetNextPacketSize
1422 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1423 REFIID riid, void **ppv)
1425 ACImpl *This = impl_from_IAudioClock(iface);
1427 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1429 if(!ppv)
1430 return E_POINTER;
1431 *ppv = NULL;
1433 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
1434 *ppv = iface;
1435 else if(IsEqualIID(riid, &IID_IAudioClock2))
1436 *ppv = &This->IAudioClock2_iface;
1437 if(*ppv){
1438 IUnknown_AddRef((IUnknown*)*ppv);
1439 return S_OK;
1442 WARN("Unknown interface %s\n", debugstr_guid(riid));
1443 return E_NOINTERFACE;
1446 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
1448 ACImpl *This = impl_from_IAudioClock(iface);
1449 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1452 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
1454 ACImpl *This = impl_from_IAudioClock(iface);
1455 return IAudioClient3_Release(&This->IAudioClient3_iface);
1458 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
1460 ACImpl *This = impl_from_IAudioClock(iface);
1461 struct get_frequency_params params;
1463 TRACE("(%p)->(%p)\n", This, freq);
1465 params.stream = This->stream;
1466 params.freq = freq;
1467 UNIX_CALL(get_frequency, &params);
1468 return params.result;
1471 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
1472 UINT64 *qpctime)
1474 ACImpl *This = impl_from_IAudioClock(iface);
1475 struct get_position_params params;
1477 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
1479 if(!pos)
1480 return E_POINTER;
1482 params.stream = This->stream;
1483 params.pos = pos;
1484 params.qpctime = qpctime;
1485 UNIX_CALL(get_position, &params);
1486 return params.result;
1489 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
1490 DWORD *chars)
1492 ACImpl *This = impl_from_IAudioClock(iface);
1494 TRACE("(%p)->(%p)\n", This, chars);
1496 if(!chars)
1497 return E_POINTER;
1499 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
1501 return S_OK;
1504 static const IAudioClockVtbl AudioClock_Vtbl =
1506 AudioClock_QueryInterface,
1507 AudioClock_AddRef,
1508 AudioClock_Release,
1509 AudioClock_GetFrequency,
1510 AudioClock_GetPosition,
1511 AudioClock_GetCharacteristics
1514 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
1515 REFIID riid, void **ppv)
1517 ACImpl *This = impl_from_IAudioClock2(iface);
1518 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
1521 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
1523 ACImpl *This = impl_from_IAudioClock2(iface);
1524 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1527 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
1529 ACImpl *This = impl_from_IAudioClock2(iface);
1530 return IAudioClient3_Release(&This->IAudioClient3_iface);
1533 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
1534 UINT64 *pos, UINT64 *qpctime)
1536 ACImpl *This = impl_from_IAudioClock2(iface);
1538 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
1540 return E_NOTIMPL;
1543 static const IAudioClock2Vtbl AudioClock2_Vtbl =
1545 AudioClock2_QueryInterface,
1546 AudioClock2_AddRef,
1547 AudioClock2_Release,
1548 AudioClock2_GetDevicePosition
1551 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
1553 AudioSessionWrapper *ret;
1555 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1556 sizeof(AudioSessionWrapper));
1557 if(!ret)
1558 return NULL;
1560 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
1561 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
1562 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
1564 ret->ref = 1;
1566 ret->client = client;
1567 if(client){
1568 ret->session = client->session;
1569 IAudioClient3_AddRef(&client->IAudioClient3_iface);
1572 return ret;
1575 static HRESULT WINAPI AudioSessionControl_QueryInterface(
1576 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
1578 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1580 if(!ppv)
1581 return E_POINTER;
1582 *ppv = NULL;
1584 if(IsEqualIID(riid, &IID_IUnknown) ||
1585 IsEqualIID(riid, &IID_IAudioSessionControl) ||
1586 IsEqualIID(riid, &IID_IAudioSessionControl2))
1587 *ppv = iface;
1588 if(*ppv){
1589 IUnknown_AddRef((IUnknown*)*ppv);
1590 return S_OK;
1593 WARN("Unknown interface %s\n", debugstr_guid(riid));
1594 return E_NOINTERFACE;
1597 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
1599 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1600 ULONG ref;
1601 ref = InterlockedIncrement(&This->ref);
1602 TRACE("(%p) Refcount now %u\n", This, ref);
1603 return ref;
1606 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
1608 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1609 ULONG ref;
1611 EnterCriticalSection(&g_sessions_lock);
1613 ref = InterlockedDecrement(&This->ref);
1614 TRACE("(%p) Refcount now %u\n", This, ref);
1615 if(!ref){
1616 if(This->client){
1617 This->client->session_wrapper = NULL;
1618 AudioClient_Release(&This->client->IAudioClient3_iface);
1620 HeapFree(GetProcessHeap(), 0, This);
1623 LeaveCriticalSection(&g_sessions_lock);
1624 return ref;
1627 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
1628 AudioSessionState *state)
1630 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1631 struct is_started_params params;
1632 ACImpl *client;
1634 TRACE("(%p)->(%p)\n", This, state);
1636 if(!state)
1637 return NULL_PTR_ERR;
1639 EnterCriticalSection(&g_sessions_lock);
1641 if(list_empty(&This->session->clients)){
1642 *state = AudioSessionStateExpired;
1643 LeaveCriticalSection(&g_sessions_lock);
1644 return S_OK;
1647 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
1648 params.stream = client->stream;
1649 UNIX_CALL(is_started, &params);
1650 if(params.result == S_OK){
1651 *state = AudioSessionStateActive;
1652 LeaveCriticalSection(&g_sessions_lock);
1653 return S_OK;
1657 LeaveCriticalSection(&g_sessions_lock);
1659 *state = AudioSessionStateInactive;
1661 return S_OK;
1664 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
1665 IAudioSessionControl2 *iface, WCHAR **name)
1667 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1669 FIXME("(%p)->(%p) - stub\n", This, name);
1671 return E_NOTIMPL;
1674 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
1675 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
1677 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1679 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
1681 return E_NOTIMPL;
1684 static HRESULT WINAPI AudioSessionControl_GetIconPath(
1685 IAudioSessionControl2 *iface, WCHAR **path)
1687 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1689 FIXME("(%p)->(%p) - stub\n", This, path);
1691 return E_NOTIMPL;
1694 static HRESULT WINAPI AudioSessionControl_SetIconPath(
1695 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
1697 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1699 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
1701 return E_NOTIMPL;
1704 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
1705 IAudioSessionControl2 *iface, GUID *group)
1707 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1709 FIXME("(%p)->(%p) - stub\n", This, group);
1711 return E_NOTIMPL;
1714 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
1715 IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
1717 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1719 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
1720 debugstr_guid(session));
1722 return E_NOTIMPL;
1725 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
1726 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
1728 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1730 FIXME("(%p)->(%p) - stub\n", This, events);
1732 return S_OK;
1735 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
1736 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
1738 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1740 FIXME("(%p)->(%p) - stub\n", This, events);
1742 return S_OK;
1745 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
1746 IAudioSessionControl2 *iface, WCHAR **id)
1748 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1750 FIXME("(%p)->(%p) - stub\n", This, id);
1752 return E_NOTIMPL;
1755 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
1756 IAudioSessionControl2 *iface, WCHAR **id)
1758 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1760 FIXME("(%p)->(%p) - stub\n", This, id);
1762 return E_NOTIMPL;
1765 static HRESULT WINAPI AudioSessionControl_GetProcessId(
1766 IAudioSessionControl2 *iface, DWORD *pid)
1768 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1770 TRACE("(%p)->(%p)\n", This, pid);
1772 if(!pid)
1773 return E_POINTER;
1775 *pid = GetCurrentProcessId();
1777 return S_OK;
1780 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
1781 IAudioSessionControl2 *iface)
1783 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1785 TRACE("(%p)\n", This);
1787 return S_FALSE;
1790 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
1791 IAudioSessionControl2 *iface, BOOL optout)
1793 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1795 TRACE("(%p)->(%d)\n", This, optout);
1797 return S_OK;
1800 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
1802 AudioSessionControl_QueryInterface,
1803 AudioSessionControl_AddRef,
1804 AudioSessionControl_Release,
1805 AudioSessionControl_GetState,
1806 AudioSessionControl_GetDisplayName,
1807 AudioSessionControl_SetDisplayName,
1808 AudioSessionControl_GetIconPath,
1809 AudioSessionControl_SetIconPath,
1810 AudioSessionControl_GetGroupingParam,
1811 AudioSessionControl_SetGroupingParam,
1812 AudioSessionControl_RegisterAudioSessionNotification,
1813 AudioSessionControl_UnregisterAudioSessionNotification,
1814 AudioSessionControl_GetSessionIdentifier,
1815 AudioSessionControl_GetSessionInstanceIdentifier,
1816 AudioSessionControl_GetProcessId,
1817 AudioSessionControl_IsSystemSoundsSession,
1818 AudioSessionControl_SetDuckingPreference
1821 /* index == -1 means set all channels, otherwise sets only the given channel */
1822 static HRESULT ca_setvol(ACImpl *This, struct coreaudio_stream *stream, UINT32 index)
1824 Float32 level;
1825 OSStatus sc;
1827 if(This->session->mute)
1828 level = 0.;
1829 else{
1830 if(index == (UINT32)-1){
1831 UINT32 i;
1832 level = 1.;
1833 for(i = 0; i < stream->fmt->nChannels; ++i){
1834 Float32 tmp;
1835 tmp = This->session->master_vol *
1836 This->session->channel_vols[i] * This->vols[i];
1837 level = tmp < level ? tmp : level;
1839 }else
1840 level = This->session->master_vol *
1841 This->session->channel_vols[index] * This->vols[index];
1844 sc = AudioUnitSetParameter(stream->unit, kHALOutputParam_Volume,
1845 kAudioUnitScope_Global, 0, level, 0);
1846 if(sc != noErr)
1847 WARN("Couldn't set volume: %x\n", (int)sc);
1849 return S_OK;
1852 static HRESULT ca_session_setvol(AudioSession *session, UINT32 index)
1854 HRESULT ret = S_OK;
1855 ACImpl *client;
1857 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry){
1858 HRESULT hr;
1859 hr = ca_setvol(client, client->stream, index);
1860 if(FAILED(hr))
1861 ret = hr;
1864 return ret;
1867 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
1868 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
1870 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1872 if(!ppv)
1873 return E_POINTER;
1874 *ppv = NULL;
1876 if(IsEqualIID(riid, &IID_IUnknown) ||
1877 IsEqualIID(riid, &IID_ISimpleAudioVolume))
1878 *ppv = iface;
1879 if(*ppv){
1880 IUnknown_AddRef((IUnknown*)*ppv);
1881 return S_OK;
1884 WARN("Unknown interface %s\n", debugstr_guid(riid));
1885 return E_NOINTERFACE;
1888 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
1890 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1891 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
1894 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
1896 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1897 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
1900 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
1901 ISimpleAudioVolume *iface, float level, const GUID *context)
1903 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1904 AudioSession *session = This->session;
1905 HRESULT ret;
1907 TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
1909 if(level < 0.f || level > 1.f)
1910 return E_INVALIDARG;
1912 if(context)
1913 FIXME("Notifications not supported yet\n");
1915 EnterCriticalSection(&g_sessions_lock);
1917 session->master_vol = level;
1919 ret = ca_session_setvol(session, -1);
1921 LeaveCriticalSection(&g_sessions_lock);
1923 return ret;
1926 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
1927 ISimpleAudioVolume *iface, float *level)
1929 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1930 AudioSession *session = This->session;
1932 TRACE("(%p)->(%p)\n", session, level);
1934 if(!level)
1935 return NULL_PTR_ERR;
1937 *level = session->master_vol;
1939 return S_OK;
1942 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
1943 BOOL mute, const GUID *context)
1945 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1946 AudioSession *session = This->session;
1948 TRACE("(%p)->(%u, %s)\n", session, mute, debugstr_guid(context));
1950 if(context)
1951 FIXME("Notifications not supported yet\n");
1953 EnterCriticalSection(&g_sessions_lock);
1955 session->mute = mute;
1957 ca_session_setvol(session, -1);
1959 LeaveCriticalSection(&g_sessions_lock);
1961 return S_OK;
1964 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
1965 BOOL *mute)
1967 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
1968 AudioSession *session = This->session;
1970 TRACE("(%p)->(%p)\n", session, mute);
1972 if(!mute)
1973 return NULL_PTR_ERR;
1975 *mute = session->mute;
1977 return S_OK;
1980 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
1982 SimpleAudioVolume_QueryInterface,
1983 SimpleAudioVolume_AddRef,
1984 SimpleAudioVolume_Release,
1985 SimpleAudioVolume_SetMasterVolume,
1986 SimpleAudioVolume_GetMasterVolume,
1987 SimpleAudioVolume_SetMute,
1988 SimpleAudioVolume_GetMute
1991 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
1992 IAudioStreamVolume *iface, REFIID riid, void **ppv)
1994 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1996 if(!ppv)
1997 return E_POINTER;
1998 *ppv = NULL;
2000 if(IsEqualIID(riid, &IID_IUnknown) ||
2001 IsEqualIID(riid, &IID_IAudioStreamVolume))
2002 *ppv = iface;
2003 if(*ppv){
2004 IUnknown_AddRef((IUnknown*)*ppv);
2005 return S_OK;
2008 WARN("Unknown interface %s\n", debugstr_guid(riid));
2009 return E_NOINTERFACE;
2012 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
2014 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2015 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
2018 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
2020 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2021 return IAudioClient3_Release(&This->IAudioClient3_iface);
2024 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
2025 IAudioStreamVolume *iface, UINT32 *out)
2027 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2029 TRACE("(%p)->(%p)\n", This, out);
2031 if(!out)
2032 return E_POINTER;
2034 *out = This->channel_count;
2036 return S_OK;
2039 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
2040 IAudioStreamVolume *iface, UINT32 index, float level)
2042 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2043 HRESULT ret;
2045 TRACE("(%p)->(%d, %f)\n", This, index, level);
2047 if(level < 0.f || level > 1.f)
2048 return E_INVALIDARG;
2050 if(index >= This->channel_count)
2051 return E_INVALIDARG;
2053 EnterCriticalSection(&g_sessions_lock);
2055 This->vols[index] = level;
2057 WARN("CoreAudio doesn't support per-channel volume control\n");
2058 ret = ca_setvol(This, This->stream, index);
2060 LeaveCriticalSection(&g_sessions_lock);
2062 return ret;
2065 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2066 IAudioStreamVolume *iface, UINT32 index, float *level)
2068 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2070 TRACE("(%p)->(%d, %p)\n", This, index, level);
2072 if(!level)
2073 return E_POINTER;
2075 if(index >= This->channel_count)
2076 return E_INVALIDARG;
2078 *level = This->vols[index];
2080 return S_OK;
2083 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2084 IAudioStreamVolume *iface, UINT32 count, const float *levels)
2086 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2087 UINT32 i;
2088 HRESULT ret;
2090 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2092 if(!levels)
2093 return E_POINTER;
2095 if(count != This->channel_count)
2096 return E_INVALIDARG;
2098 EnterCriticalSection(&g_sessions_lock);
2100 for(i = 0; i < count; ++i)
2101 This->vols[i] = levels[i];
2103 ret = ca_setvol(This, This->stream, -1);
2105 LeaveCriticalSection(&g_sessions_lock);
2107 return ret;
2110 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2111 IAudioStreamVolume *iface, UINT32 count, float *levels)
2113 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2114 UINT32 i;
2116 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2118 if(!levels)
2119 return E_POINTER;
2121 if(count != This->channel_count)
2122 return E_INVALIDARG;
2124 EnterCriticalSection(&g_sessions_lock);
2126 for(i = 0; i < count; ++i)
2127 levels[i] = This->vols[i];
2129 LeaveCriticalSection(&g_sessions_lock);
2131 return S_OK;
2134 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2136 AudioStreamVolume_QueryInterface,
2137 AudioStreamVolume_AddRef,
2138 AudioStreamVolume_Release,
2139 AudioStreamVolume_GetChannelCount,
2140 AudioStreamVolume_SetChannelVolume,
2141 AudioStreamVolume_GetChannelVolume,
2142 AudioStreamVolume_SetAllVolumes,
2143 AudioStreamVolume_GetAllVolumes
2146 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2147 IChannelAudioVolume *iface, REFIID riid, void **ppv)
2149 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2151 if(!ppv)
2152 return E_POINTER;
2153 *ppv = NULL;
2155 if(IsEqualIID(riid, &IID_IUnknown) ||
2156 IsEqualIID(riid, &IID_IChannelAudioVolume))
2157 *ppv = iface;
2158 if(*ppv){
2159 IUnknown_AddRef((IUnknown*)*ppv);
2160 return S_OK;
2163 WARN("Unknown interface %s\n", debugstr_guid(riid));
2164 return E_NOINTERFACE;
2167 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2169 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2170 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2173 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2175 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2176 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2179 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2180 IChannelAudioVolume *iface, UINT32 *out)
2182 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2183 AudioSession *session = This->session;
2185 TRACE("(%p)->(%p)\n", session, out);
2187 if(!out)
2188 return NULL_PTR_ERR;
2190 *out = session->channel_count;
2192 return S_OK;
2195 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2196 IChannelAudioVolume *iface, UINT32 index, float level,
2197 const GUID *context)
2199 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2200 AudioSession *session = This->session;
2201 HRESULT ret;
2203 TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2204 wine_dbgstr_guid(context));
2206 if(level < 0.f || level > 1.f)
2207 return E_INVALIDARG;
2209 if(index >= session->channel_count)
2210 return E_INVALIDARG;
2212 if(context)
2213 FIXME("Notifications not supported yet\n");
2215 EnterCriticalSection(&g_sessions_lock);
2217 session->channel_vols[index] = level;
2219 WARN("CoreAudio doesn't support per-channel volume control\n");
2220 ret = ca_session_setvol(session, index);
2222 LeaveCriticalSection(&g_sessions_lock);
2224 return ret;
2227 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2228 IChannelAudioVolume *iface, UINT32 index, float *level)
2230 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2231 AudioSession *session = This->session;
2233 TRACE("(%p)->(%d, %p)\n", session, index, level);
2235 if(!level)
2236 return NULL_PTR_ERR;
2238 if(index >= session->channel_count)
2239 return E_INVALIDARG;
2241 *level = session->channel_vols[index];
2243 return S_OK;
2246 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2247 IChannelAudioVolume *iface, UINT32 count, const float *levels,
2248 const GUID *context)
2250 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2251 AudioSession *session = This->session;
2252 int i;
2253 HRESULT ret;
2255 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2256 wine_dbgstr_guid(context));
2258 if(!levels)
2259 return NULL_PTR_ERR;
2261 if(count != session->channel_count)
2262 return E_INVALIDARG;
2264 if(context)
2265 FIXME("Notifications not supported yet\n");
2267 EnterCriticalSection(&g_sessions_lock);
2269 for(i = 0; i < count; ++i)
2270 session->channel_vols[i] = levels[i];
2272 ret = ca_session_setvol(session, -1);
2274 LeaveCriticalSection(&g_sessions_lock);
2276 return ret;
2279 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2280 IChannelAudioVolume *iface, UINT32 count, float *levels)
2282 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2283 AudioSession *session = This->session;
2284 int i;
2286 TRACE("(%p)->(%d, %p)\n", session, count, levels);
2288 if(!levels)
2289 return NULL_PTR_ERR;
2291 if(count != session->channel_count)
2292 return E_INVALIDARG;
2294 for(i = 0; i < count; ++i)
2295 levels[i] = session->channel_vols[i];
2297 return S_OK;
2300 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2302 ChannelAudioVolume_QueryInterface,
2303 ChannelAudioVolume_AddRef,
2304 ChannelAudioVolume_Release,
2305 ChannelAudioVolume_GetChannelCount,
2306 ChannelAudioVolume_SetChannelVolume,
2307 ChannelAudioVolume_GetChannelVolume,
2308 ChannelAudioVolume_SetAllVolumes,
2309 ChannelAudioVolume_GetAllVolumes
2312 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2313 REFIID riid, void **ppv)
2315 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2317 if(!ppv)
2318 return E_POINTER;
2319 *ppv = NULL;
2321 if(IsEqualIID(riid, &IID_IUnknown) ||
2322 IsEqualIID(riid, &IID_IAudioSessionManager) ||
2323 IsEqualIID(riid, &IID_IAudioSessionManager2))
2324 *ppv = iface;
2325 if(*ppv){
2326 IUnknown_AddRef((IUnknown*)*ppv);
2327 return S_OK;
2330 WARN("Unknown interface %s\n", debugstr_guid(riid));
2331 return E_NOINTERFACE;
2334 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2336 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2337 ULONG ref;
2338 ref = InterlockedIncrement(&This->ref);
2339 TRACE("(%p) Refcount now %u\n", This, ref);
2340 return ref;
2343 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2345 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2346 ULONG ref;
2347 ref = InterlockedDecrement(&This->ref);
2348 TRACE("(%p) Refcount now %u\n", This, ref);
2349 if(!ref)
2350 HeapFree(GetProcessHeap(), 0, This);
2351 return ref;
2354 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2355 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2356 IAudioSessionControl **out)
2358 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2359 AudioSession *session;
2360 AudioSessionWrapper *wrapper;
2361 HRESULT hr;
2363 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2364 flags, out);
2366 hr = get_audio_session(session_guid, This->device, 0, &session);
2367 if(FAILED(hr))
2368 return hr;
2370 wrapper = AudioSessionWrapper_Create(NULL);
2371 if(!wrapper)
2372 return E_OUTOFMEMORY;
2374 wrapper->session = session;
2376 *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
2378 return S_OK;
2381 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
2382 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2383 ISimpleAudioVolume **out)
2385 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2386 AudioSession *session;
2387 AudioSessionWrapper *wrapper;
2388 HRESULT hr;
2390 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2391 flags, out);
2393 hr = get_audio_session(session_guid, This->device, 0, &session);
2394 if(FAILED(hr))
2395 return hr;
2397 wrapper = AudioSessionWrapper_Create(NULL);
2398 if(!wrapper)
2399 return E_OUTOFMEMORY;
2401 wrapper->session = session;
2403 *out = &wrapper->ISimpleAudioVolume_iface;
2405 return S_OK;
2408 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
2409 IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
2411 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2412 FIXME("(%p)->(%p) - stub\n", This, out);
2413 return E_NOTIMPL;
2416 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
2417 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2419 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2420 FIXME("(%p)->(%p) - stub\n", This, notification);
2421 return E_NOTIMPL;
2424 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
2425 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2427 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2428 FIXME("(%p)->(%p) - stub\n", This, notification);
2429 return E_NOTIMPL;
2432 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
2433 IAudioSessionManager2 *iface, const WCHAR *session_id,
2434 IAudioVolumeDuckNotification *notification)
2436 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2437 FIXME("(%p)->(%p) - stub\n", This, notification);
2438 return E_NOTIMPL;
2441 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
2442 IAudioSessionManager2 *iface,
2443 IAudioVolumeDuckNotification *notification)
2445 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2446 FIXME("(%p)->(%p) - stub\n", This, notification);
2447 return E_NOTIMPL;
2450 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
2452 AudioSessionManager_QueryInterface,
2453 AudioSessionManager_AddRef,
2454 AudioSessionManager_Release,
2455 AudioSessionManager_GetAudioSessionControl,
2456 AudioSessionManager_GetSimpleAudioVolume,
2457 AudioSessionManager_GetSessionEnumerator,
2458 AudioSessionManager_RegisterSessionNotification,
2459 AudioSessionManager_UnregisterSessionNotification,
2460 AudioSessionManager_RegisterDuckNotification,
2461 AudioSessionManager_UnregisterDuckNotification
2464 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
2465 IAudioSessionManager2 **out)
2467 SessionMgr *This;
2469 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
2470 if(!This)
2471 return E_OUTOFMEMORY;
2473 This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
2474 This->device = device;
2475 This->ref = 1;
2477 *out = &This->IAudioSessionManager2_iface;
2479 return S_OK;