ntoskrnl.exe: Export InitSafeBootMode.
[wine/wine-gecko.git] / dlls / winecoreaudio.drv / mmdevdrv.c
blobe58cda1abfa68d58962d607f09d8df7dc168136d
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 <unistd.h>
41 #include <libkern/OSAtomic.h>
42 #include <CoreAudio/CoreAudio.h>
43 #include <AudioToolbox/AudioFormat.h>
44 #include <AudioToolbox/AudioConverter.h>
45 #include <AudioUnit/AudioUnit.h>
47 #undef LoadResource
48 #undef CompareString
49 #undef GetCurrentThread
50 #undef GetCurrentProcess
51 #undef _CDECL
52 #undef DPRINTF
54 #include "windef.h"
55 #include "winbase.h"
56 #include "winnls.h"
57 #include "winreg.h"
58 #include "wine/debug.h"
59 #include "wine/unicode.h"
60 #include "wine/list.h"
62 #include "ole2.h"
63 #include "mmdeviceapi.h"
64 #include "devpkey.h"
65 #include "dshow.h"
66 #include "dsound.h"
68 #include "initguid.h"
69 #include "endpointvolume.h"
70 #include "audioclient.h"
71 #include "audiopolicy.h"
73 WINE_DEFAULT_DEBUG_CHANNEL(coreaudio);
75 #ifndef HAVE_AUDIOUNIT_AUDIOCOMPONENT_H
76 /* Define new AudioComponent Manager functions for OSX 10.5 */
77 typedef Component AudioComponent;
78 typedef ComponentDescription AudioComponentDescription;
79 typedef ComponentInstance AudioComponentInstance;
81 static inline AudioComponent AudioComponentFindNext(AudioComponent ac, AudioComponentDescription *desc)
83 return FindNextComponent(ac, desc);
86 static inline OSStatus AudioComponentInstanceNew(AudioComponent ac, AudioComponentInstance *aci)
88 return OpenAComponent(ac, aci);
91 static inline OSStatus AudioComponentInstanceDispose(AudioComponentInstance aci)
93 return CloseComponent(aci);
95 #endif
97 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
99 static const REFERENCE_TIME DefaultPeriod = 100000;
100 static const REFERENCE_TIME MinimumPeriod = 50000;
102 struct ACImpl;
103 typedef struct ACImpl ACImpl;
105 typedef struct _AudioSession {
106 GUID guid;
107 struct list clients;
109 IMMDevice *device;
111 float master_vol;
112 UINT32 channel_count;
113 float *channel_vols;
114 BOOL mute;
116 CRITICAL_SECTION lock;
118 struct list entry;
119 } AudioSession;
121 typedef struct _AudioSessionWrapper {
122 IAudioSessionControl2 IAudioSessionControl2_iface;
123 IChannelAudioVolume IChannelAudioVolume_iface;
124 ISimpleAudioVolume ISimpleAudioVolume_iface;
126 LONG ref;
128 ACImpl *client;
129 AudioSession *session;
130 } AudioSessionWrapper;
132 struct ACImpl {
133 IAudioClient IAudioClient_iface;
134 IAudioRenderClient IAudioRenderClient_iface;
135 IAudioCaptureClient IAudioCaptureClient_iface;
136 IAudioClock IAudioClock_iface;
137 IAudioClock2 IAudioClock2_iface;
138 IAudioStreamVolume IAudioStreamVolume_iface;
140 LONG ref;
142 IMMDevice *parent;
143 IUnknown *pUnkFTMarshal;
145 WAVEFORMATEX *fmt;
147 EDataFlow dataflow;
148 DWORD flags;
149 AUDCLNT_SHAREMODE share;
150 HANDLE event;
151 float *vols;
153 BOOL initted;
154 AudioDeviceID adevid;
155 AudioObjectPropertyScope scope;
156 AudioConverterRef converter;
157 AudioComponentInstance unit;
158 AudioStreamBasicDescription dev_desc; /* audio unit format, not necessarily the same as fmt */
159 HANDLE timer;
160 UINT32 period_ms, bufsize_frames, period_frames;
161 UINT64 written_frames;
162 UINT32 lcl_offs_frames, wri_offs_frames, held_frames, tmp_buffer_frames;
163 UINT32 cap_bufsize_frames, cap_offs_frames, cap_held_frames, wrap_bufsize_frames, resamp_bufsize_frames;
164 INT32 getbuf_last;
165 BOOL playing;
166 BYTE *cap_buffer, *wrap_buffer, *resamp_buffer, *local_buffer, *tmp_buffer;
168 AudioSession *session;
169 AudioSessionWrapper *session_wrapper;
171 struct list entry;
173 OSSpinLock lock;
176 static const IAudioClientVtbl AudioClient_Vtbl;
177 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
178 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
179 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
180 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
181 static const IAudioClockVtbl AudioClock_Vtbl;
182 static const IAudioClock2Vtbl AudioClock2_Vtbl;
183 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
184 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
185 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl;
187 typedef struct _SessionMgr {
188 IAudioSessionManager2 IAudioSessionManager2_iface;
190 LONG ref;
192 IMMDevice *device;
193 } SessionMgr;
195 static const WCHAR drv_keyW[] = {'S','o','f','t','w','a','r','e','\\',
196 'W','i','n','e','\\','D','r','i','v','e','r','s','\\',
197 'w','i','n','e','c','o','r','e','a','u','d','i','o','.','d','r','v',0};
198 static const WCHAR drv_key_devicesW[] = {'S','o','f','t','w','a','r','e','\\',
199 'W','i','n','e','\\','D','r','i','v','e','r','s','\\',
200 'w','i','n','e','c','o','r','e','a','u','d','i','o','.','d','r','v','\\','d','e','v','i','c','e','s',0};
201 static const WCHAR guidW[] = {'g','u','i','d',0};
203 static HANDLE g_timer_q;
205 static CRITICAL_SECTION g_sessions_lock;
206 static CRITICAL_SECTION_DEBUG g_sessions_lock_debug =
208 0, 0, &g_sessions_lock,
209 { &g_sessions_lock_debug.ProcessLocksList, &g_sessions_lock_debug.ProcessLocksList },
210 0, 0, { (DWORD_PTR)(__FILE__ ": g_sessions_lock") }
212 static CRITICAL_SECTION g_sessions_lock = { &g_sessions_lock_debug, -1, 0, 0, 0, 0 };
213 static struct list g_sessions = LIST_INIT(g_sessions);
215 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
216 static HRESULT ca_setvol(ACImpl *This, UINT32 index);
218 static inline ACImpl *impl_from_IAudioClient(IAudioClient *iface)
220 return CONTAINING_RECORD(iface, ACImpl, IAudioClient_iface);
223 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
225 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
228 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
230 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
233 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
235 return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
238 static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
240 return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
243 static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
245 return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
248 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
250 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
253 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
255 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
258 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
260 return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
263 static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface)
265 return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface);
268 BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
270 switch (reason)
272 case DLL_PROCESS_ATTACH:
273 g_timer_q = CreateTimerQueue();
274 if(!g_timer_q)
275 return FALSE;
276 break;
278 case DLL_PROCESS_DETACH:
279 if (reserved) break;
280 DeleteCriticalSection(&g_sessions_lock);
281 break;
283 return TRUE;
286 /* From <dlls/mmdevapi/mmdevapi.h> */
287 enum DriverPriority {
288 Priority_Unavailable = 0,
289 Priority_Low,
290 Priority_Neutral,
291 Priority_Preferred
294 int WINAPI AUDDRV_GetPriority(void)
296 return Priority_Neutral;
299 static HRESULT osstatus_to_hresult(OSStatus sc)
301 switch(sc){
302 case kAudioFormatUnsupportedDataFormatError:
303 case kAudioFormatUnknownFormatError:
304 case kAudioDeviceUnsupportedFormatError:
305 return AUDCLNT_E_UNSUPPORTED_FORMAT;
306 case kAudioHardwareBadDeviceError:
307 return AUDCLNT_E_DEVICE_INVALIDATED;
309 return E_FAIL;
312 static void set_device_guid(EDataFlow flow, HKEY drv_key, const WCHAR *key_name,
313 GUID *guid)
315 HKEY key;
316 BOOL opened = FALSE;
317 LONG lr;
319 if(!drv_key){
320 lr = RegCreateKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, NULL, 0, KEY_WRITE,
321 NULL, &drv_key, NULL);
322 if(lr != ERROR_SUCCESS){
323 ERR("RegCreateKeyEx(drv_key) failed: %u\n", lr);
324 return;
326 opened = TRUE;
329 lr = RegCreateKeyExW(drv_key, key_name, 0, NULL, 0, KEY_WRITE,
330 NULL, &key, NULL);
331 if(lr != ERROR_SUCCESS){
332 ERR("RegCreateKeyEx(%s) failed: %u\n", wine_dbgstr_w(key_name), lr);
333 goto exit;
336 lr = RegSetValueExW(key, guidW, 0, REG_BINARY, (BYTE*)guid,
337 sizeof(GUID));
338 if(lr != ERROR_SUCCESS)
339 ERR("RegSetValueEx(%s\\guid) failed: %u\n", wine_dbgstr_w(key_name), lr);
341 RegCloseKey(key);
342 exit:
343 if(opened)
344 RegCloseKey(drv_key);
347 static void get_device_guid(EDataFlow flow, AudioDeviceID device, GUID *guid)
349 HKEY key = NULL, dev_key;
350 DWORD type, size = sizeof(*guid);
351 WCHAR key_name[256];
353 static const WCHAR key_fmt[] = {'%','u',0};
355 if(flow == eCapture)
356 key_name[0] = '1';
357 else
358 key_name[0] = '0';
359 key_name[1] = ',';
361 sprintfW(key_name + 2, key_fmt, device);
363 if(RegOpenKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, KEY_WRITE|KEY_READ, &key) == ERROR_SUCCESS){
364 if(RegOpenKeyExW(key, key_name, 0, KEY_READ, &dev_key) == ERROR_SUCCESS){
365 if(RegQueryValueExW(dev_key, guidW, 0, &type,
366 (BYTE*)guid, &size) == ERROR_SUCCESS){
367 if(type == REG_BINARY){
368 RegCloseKey(dev_key);
369 RegCloseKey(key);
370 return;
372 ERR("Invalid type for device %s GUID: %u; ignoring and overwriting\n",
373 wine_dbgstr_w(key_name), type);
375 RegCloseKey(dev_key);
379 CoCreateGuid(guid);
381 set_device_guid(flow, key, key_name, guid);
383 if(key)
384 RegCloseKey(key);
387 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids,
388 GUID **guids, UINT *num, UINT *def_index)
390 UInt32 devsize, size;
391 AudioDeviceID *devices;
392 AudioDeviceID default_id;
393 AudioObjectPropertyAddress addr;
394 OSStatus sc;
395 int i, ndevices;
397 TRACE("%d %p %p %p\n", flow, ids, num, def_index);
399 addr.mScope = kAudioObjectPropertyScopeGlobal;
400 addr.mElement = kAudioObjectPropertyElementMaster;
401 if(flow == eRender)
402 addr.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
403 else if(flow == eCapture)
404 addr.mSelector = kAudioHardwarePropertyDefaultInputDevice;
405 else
406 return E_INVALIDARG;
408 size = sizeof(default_id);
409 sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0,
410 NULL, &size, &default_id);
411 if(sc != noErr){
412 WARN("Getting _DefaultInputDevice property failed: %lx\n", sc);
413 default_id = -1;
416 addr.mSelector = kAudioHardwarePropertyDevices;
417 sc = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &addr, 0,
418 NULL, &devsize);
419 if(sc != noErr){
420 WARN("Getting _Devices property size failed: %lx\n", sc);
421 return osstatus_to_hresult(sc);
424 devices = HeapAlloc(GetProcessHeap(), 0, devsize);
425 if(!devices)
426 return E_OUTOFMEMORY;
428 sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0, NULL,
429 &devsize, devices);
430 if(sc != noErr){
431 WARN("Getting _Devices property failed: %lx\n", sc);
432 HeapFree(GetProcessHeap(), 0, devices);
433 return osstatus_to_hresult(sc);
436 ndevices = devsize / sizeof(AudioDeviceID);
438 *ids = HeapAlloc(GetProcessHeap(), 0, ndevices * sizeof(WCHAR *));
439 if(!*ids){
440 HeapFree(GetProcessHeap(), 0, devices);
441 return E_OUTOFMEMORY;
444 *guids = HeapAlloc(GetProcessHeap(), 0, ndevices * sizeof(GUID));
445 if(!*guids){
446 HeapFree(GetProcessHeap(), 0, *ids);
447 HeapFree(GetProcessHeap(), 0, devices);
448 return E_OUTOFMEMORY;
451 *num = 0;
452 *def_index = (UINT)-1;
453 for(i = 0; i < ndevices; ++i){
454 AudioBufferList *buffers;
455 CFStringRef name;
456 SIZE_T len;
457 int j;
459 addr.mSelector = kAudioDevicePropertyStreamConfiguration;
460 if(flow == eRender)
461 addr.mScope = kAudioDevicePropertyScopeOutput;
462 else
463 addr.mScope = kAudioDevicePropertyScopeInput;
464 addr.mElement = 0;
465 sc = AudioObjectGetPropertyDataSize(devices[i], &addr, 0, NULL, &size);
466 if(sc != noErr){
467 WARN("Unable to get _StreamConfiguration property size for "
468 "device %lu: %lx\n", devices[i], sc);
469 continue;
472 buffers = HeapAlloc(GetProcessHeap(), 0, size);
473 if(!buffers){
474 HeapFree(GetProcessHeap(), 0, devices);
475 for(j = 0; j < *num; ++j)
476 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
477 HeapFree(GetProcessHeap(), 0, *guids);
478 HeapFree(GetProcessHeap(), 0, *ids);
479 return E_OUTOFMEMORY;
482 sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL,
483 &size, buffers);
484 if(sc != noErr){
485 WARN("Unable to get _StreamConfiguration property for "
486 "device %lu: %lx\n", devices[i], sc);
487 HeapFree(GetProcessHeap(), 0, buffers);
488 continue;
491 /* check that there's at least one channel in this device before
492 * we claim it as usable */
493 for(j = 0; j < buffers->mNumberBuffers; ++j)
494 if(buffers->mBuffers[j].mNumberChannels > 0)
495 break;
496 if(j >= buffers->mNumberBuffers){
497 HeapFree(GetProcessHeap(), 0, buffers);
498 continue;
501 HeapFree(GetProcessHeap(), 0, buffers);
503 size = sizeof(name);
504 addr.mSelector = kAudioObjectPropertyName;
505 sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL,
506 &size, &name);
507 if(sc != noErr){
508 WARN("Unable to get _Name property for device %lu: %lx\n",
509 devices[i], sc);
510 continue;
513 len = CFStringGetLength(name) + 1;
514 (*ids)[*num] = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
515 if(!(*ids)[*num]){
516 CFRelease(name);
517 HeapFree(GetProcessHeap(), 0, devices);
518 for(j = 0; j < *num; ++j)
519 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
520 HeapFree(GetProcessHeap(), 0, *ids);
521 HeapFree(GetProcessHeap(), 0, *guids);
522 return E_OUTOFMEMORY;
524 CFStringGetCharacters(name, CFRangeMake(0, len - 1), (UniChar*)(*ids)[*num]);
525 ((*ids)[*num])[len - 1] = 0;
526 CFRelease(name);
528 get_device_guid(flow, devices[i], &(*guids)[*num]);
530 if(*def_index == (UINT)-1 && devices[i] == default_id)
531 *def_index = *num;
533 TRACE("device %u: id %s key %u%s\n", *num, debugstr_w((*ids)[*num]),
534 (unsigned int)devices[i], (*def_index == *num) ? " (default)" : "");
536 (*num)++;
539 if(*def_index == (UINT)-1)
540 *def_index = 0;
542 HeapFree(GetProcessHeap(), 0, devices);
544 return S_OK;
547 static BOOL get_deviceid_by_guid(GUID *guid, AudioDeviceID *id, EDataFlow *flow)
549 HKEY devices_key;
550 UINT i = 0;
551 WCHAR key_name[256];
552 DWORD key_name_size;
554 if(RegOpenKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, KEY_READ, &devices_key) != ERROR_SUCCESS){
555 ERR("No devices in registry?\n");
556 return FALSE;
559 while(1){
560 HKEY key;
561 DWORD size, type;
562 GUID reg_guid;
564 key_name_size = sizeof(key_name);
565 if(RegEnumKeyExW(devices_key, i, key_name, &key_name_size, NULL,
566 NULL, NULL, NULL) != ERROR_SUCCESS)
567 break;
569 if(RegOpenKeyExW(devices_key, key_name, 0, KEY_READ, &key) != ERROR_SUCCESS){
570 WARN("Couldn't open key: %s\n", wine_dbgstr_w(key_name));
571 continue;
574 size = sizeof(reg_guid);
575 if(RegQueryValueExW(key, guidW, 0, &type,
576 (BYTE*)&reg_guid, &size) == ERROR_SUCCESS){
577 if(IsEqualGUID(&reg_guid, guid)){
578 RegCloseKey(key);
579 RegCloseKey(devices_key);
581 TRACE("Found matching device key: %s\n", wine_dbgstr_w(key_name));
583 if(key_name[0] == '0')
584 *flow = eRender;
585 else if(key_name[0] == '1')
586 *flow = eCapture;
587 else{
588 ERR("Unknown device type: %c\n", key_name[0]);
589 return FALSE;
592 *id = strtoulW(key_name + 2, NULL, 10);
594 return TRUE;
598 RegCloseKey(key);
600 ++i;
603 RegCloseKey(devices_key);
605 WARN("No matching device in registry for GUID %s\n", debugstr_guid(guid));
607 return FALSE;
610 static AudioComponentInstance get_audiounit(EDataFlow dataflow, AudioDeviceID adevid)
612 AudioComponentInstance unit;
613 AudioComponent comp;
614 AudioComponentDescription desc;
615 OSStatus sc;
617 memset(&desc, 0, sizeof(desc));
618 desc.componentType = kAudioUnitType_Output;
619 desc.componentSubType = kAudioUnitSubType_HALOutput;
620 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
622 if(!(comp = AudioComponentFindNext(NULL, &desc))){
623 WARN("AudioComponentFindNext failed\n");
624 return NULL;
627 sc = AudioComponentInstanceNew(comp, &unit);
628 if(sc != noErr){
629 WARN("AudioComponentInstanceNew failed: %lx\n", sc);
630 return NULL;
633 if(dataflow == eCapture){
634 UInt32 enableio;
636 enableio = 1;
637 sc = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_EnableIO,
638 kAudioUnitScope_Input, 1, &enableio, sizeof(enableio));
639 if(sc != noErr){
640 WARN("Couldn't enable I/O on input element: %lx\n", sc);
641 AudioComponentInstanceDispose(unit);
642 return NULL;
645 enableio = 0;
646 sc = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_EnableIO,
647 kAudioUnitScope_Output, 0, &enableio, sizeof(enableio));
648 if(sc != noErr){
649 WARN("Couldn't disable I/O on output element: %lx\n", sc);
650 AudioComponentInstanceDispose(unit);
651 return NULL;
655 sc = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_CurrentDevice,
656 kAudioUnitScope_Global, 0, &adevid, sizeof(adevid));
657 if(sc != noErr){
658 WARN("Couldn't set audio unit device\n");
659 AudioComponentInstanceDispose(unit);
660 return NULL;
663 return unit;
666 HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient **out)
668 ACImpl *This;
669 AudioDeviceID adevid;
670 EDataFlow dataflow;
671 HRESULT hr;
673 TRACE("%s %p %p\n", debugstr_guid(guid), dev, out);
675 if(!get_deviceid_by_guid(guid, &adevid, &dataflow))
676 return AUDCLNT_E_DEVICE_INVALIDATED;
678 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACImpl));
679 if(!This)
680 return E_OUTOFMEMORY;
682 This->IAudioClient_iface.lpVtbl = &AudioClient_Vtbl;
683 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
684 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
685 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
686 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
687 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
689 This->dataflow = dataflow;
691 if(dataflow == eRender)
692 This->scope = kAudioDevicePropertyScopeOutput;
693 else if(dataflow == eCapture)
694 This->scope = kAudioDevicePropertyScopeInput;
695 else{
696 HeapFree(GetProcessHeap(), 0, This);
697 return E_INVALIDARG;
700 This->lock = 0;
702 hr = CoCreateFreeThreadedMarshaler((IUnknown *)&This->IAudioClient_iface,
703 (IUnknown **)&This->pUnkFTMarshal);
704 if (FAILED(hr)) {
705 HeapFree(GetProcessHeap(), 0, This);
706 return hr;
709 This->parent = dev;
710 IMMDevice_AddRef(This->parent);
712 This->adevid = adevid;
714 if(!(This->unit = get_audiounit(This->dataflow, This->adevid))){
715 HeapFree(GetProcessHeap(), 0, This);
716 return AUDCLNT_E_DEVICE_INVALIDATED;
719 *out = &This->IAudioClient_iface;
720 IAudioClient_AddRef(&This->IAudioClient_iface);
722 return S_OK;
725 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient *iface,
726 REFIID riid, void **ppv)
728 ACImpl *This = impl_from_IAudioClient(iface);
729 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
731 if(!ppv)
732 return E_POINTER;
733 *ppv = NULL;
734 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClient))
735 *ppv = iface;
736 else if(IsEqualIID(riid, &IID_IMarshal))
737 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
739 if(*ppv){
740 IUnknown_AddRef((IUnknown*)*ppv);
741 return S_OK;
743 WARN("Unknown interface %s\n", debugstr_guid(riid));
744 return E_NOINTERFACE;
747 static ULONG WINAPI AudioClient_AddRef(IAudioClient *iface)
749 ACImpl *This = impl_from_IAudioClient(iface);
750 ULONG ref;
751 ref = InterlockedIncrement(&This->ref);
752 TRACE("(%p) Refcount now %u\n", This, ref);
753 return ref;
756 static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
758 ACImpl *This = impl_from_IAudioClient(iface);
759 ULONG ref;
760 ref = InterlockedDecrement(&This->ref);
761 TRACE("(%p) Refcount now %u\n", This, ref);
762 if(!ref){
763 if(This->timer){
764 HANDLE event;
765 BOOL wait;
766 event = CreateEventW(NULL, TRUE, FALSE, NULL);
767 wait = !DeleteTimerQueueTimer(g_timer_q, This->timer, event);
768 wait = wait && GetLastError() == ERROR_IO_PENDING;
769 if(event && wait)
770 WaitForSingleObject(event, INFINITE);
771 CloseHandle(event);
773 AudioOutputUnitStop(This->unit);
774 AudioComponentInstanceDispose(This->unit);
775 if(This->converter)
776 AudioConverterDispose(This->converter);
777 if(This->session){
778 EnterCriticalSection(&g_sessions_lock);
779 list_remove(&This->entry);
780 LeaveCriticalSection(&g_sessions_lock);
782 HeapFree(GetProcessHeap(), 0, This->vols);
783 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
784 HeapFree(GetProcessHeap(), 0, This->cap_buffer);
785 HeapFree(GetProcessHeap(), 0, This->local_buffer);
786 free(This->wrap_buffer);
787 HeapFree(GetProcessHeap(), 0, This->resamp_buffer);
788 CoTaskMemFree(This->fmt);
789 IMMDevice_Release(This->parent);
790 IUnknown_Release(This->pUnkFTMarshal);
791 HeapFree(GetProcessHeap(), 0, This);
793 return ref;
796 static void dump_fmt(const WAVEFORMATEX *fmt)
798 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
799 switch(fmt->wFormatTag){
800 case WAVE_FORMAT_PCM:
801 TRACE("WAVE_FORMAT_PCM");
802 break;
803 case WAVE_FORMAT_IEEE_FLOAT:
804 TRACE("WAVE_FORMAT_IEEE_FLOAT");
805 break;
806 case WAVE_FORMAT_EXTENSIBLE:
807 TRACE("WAVE_FORMAT_EXTENSIBLE");
808 break;
809 default:
810 TRACE("Unknown");
811 break;
813 TRACE(")\n");
815 TRACE("nChannels: %u\n", fmt->nChannels);
816 TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
817 TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
818 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
819 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
820 TRACE("cbSize: %u\n", fmt->cbSize);
822 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
823 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
824 TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
825 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
826 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
830 static DWORD get_channel_mask(unsigned int channels)
832 switch(channels){
833 case 0:
834 return 0;
835 case 1:
836 return KSAUDIO_SPEAKER_MONO;
837 case 2:
838 return KSAUDIO_SPEAKER_STEREO;
839 case 3:
840 return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY;
841 case 4:
842 return KSAUDIO_SPEAKER_QUAD; /* not _SURROUND */
843 case 5:
844 return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY;
845 case 6:
846 return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */
847 case 7:
848 return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER;
849 case 8:
850 return KSAUDIO_SPEAKER_7POINT1_SURROUND; /* Vista deprecates 7POINT1 */
852 FIXME("Unknown speaker configuration: %u\n", channels);
853 return 0;
856 static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
858 WAVEFORMATEX *ret;
859 size_t size;
861 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
862 size = sizeof(WAVEFORMATEXTENSIBLE);
863 else
864 size = sizeof(WAVEFORMATEX);
866 ret = CoTaskMemAlloc(size);
867 if(!ret)
868 return NULL;
870 memcpy(ret, fmt, size);
872 ret->cbSize = size - sizeof(WAVEFORMATEX);
874 return ret;
877 static HRESULT ca_get_audiodesc(AudioStreamBasicDescription *desc,
878 const WAVEFORMATEX *fmt)
880 const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)fmt;
882 desc->mFormatFlags = 0;
884 if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
885 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
886 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
887 desc->mFormatID = kAudioFormatLinearPCM;
888 if(fmt->wBitsPerSample > 8)
889 desc->mFormatFlags = kAudioFormatFlagIsSignedInteger;
890 }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
891 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
892 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
893 desc->mFormatID = kAudioFormatLinearPCM;
894 desc->mFormatFlags = kAudioFormatFlagIsFloat;
895 }else if(fmt->wFormatTag == WAVE_FORMAT_MULAW ||
896 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
897 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_MULAW))){
898 desc->mFormatID = kAudioFormatULaw;
899 }else if(fmt->wFormatTag == WAVE_FORMAT_ALAW ||
900 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
901 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_ALAW))){
902 desc->mFormatID = kAudioFormatALaw;
903 }else
904 return AUDCLNT_E_UNSUPPORTED_FORMAT;
906 desc->mSampleRate = fmt->nSamplesPerSec;
907 desc->mBytesPerPacket = fmt->nBlockAlign;
908 desc->mFramesPerPacket = 1;
909 desc->mBytesPerFrame = fmt->nBlockAlign;
910 desc->mChannelsPerFrame = fmt->nChannels;
911 desc->mBitsPerChannel = fmt->wBitsPerSample;
912 desc->mReserved = 0;
914 return S_OK;
917 static void session_init_vols(AudioSession *session, UINT channels)
919 if(session->channel_count < channels){
920 UINT i;
922 if(session->channel_vols)
923 session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
924 session->channel_vols, sizeof(float) * channels);
925 else
926 session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
927 sizeof(float) * channels);
928 if(!session->channel_vols)
929 return;
931 for(i = session->channel_count; i < channels; ++i)
932 session->channel_vols[i] = 1.f;
934 session->channel_count = channels;
938 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
939 UINT num_channels)
941 AudioSession *ret;
943 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
944 if(!ret)
945 return NULL;
947 memcpy(&ret->guid, guid, sizeof(GUID));
949 ret->device = device;
951 list_init(&ret->clients);
953 list_add_head(&g_sessions, &ret->entry);
955 InitializeCriticalSection(&ret->lock);
956 ret->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": AudioSession.lock");
958 session_init_vols(ret, num_channels);
960 ret->master_vol = 1.f;
962 return ret;
965 /* if channels == 0, then this will return or create a session with
966 * matching dataflow and GUID. otherwise, channels must also match */
967 static HRESULT get_audio_session(const GUID *sessionguid,
968 IMMDevice *device, UINT channels, AudioSession **out)
970 AudioSession *session;
972 if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
973 *out = create_session(&GUID_NULL, device, channels);
974 if(!*out)
975 return E_OUTOFMEMORY;
977 return S_OK;
980 *out = NULL;
981 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
982 if(session->device == device &&
983 IsEqualGUID(sessionguid, &session->guid)){
984 session_init_vols(session, channels);
985 *out = session;
986 break;
990 if(!*out){
991 *out = create_session(sessionguid, device, channels);
992 if(!*out)
993 return E_OUTOFMEMORY;
996 return S_OK;
999 static void ca_wrap_buffer(BYTE *dst, UINT32 dst_offs, UINT32 dst_bytes,
1000 BYTE *src, UINT32 src_bytes)
1002 UINT32 chunk_bytes = dst_bytes - dst_offs;
1004 if(chunk_bytes < src_bytes){
1005 memcpy(dst + dst_offs, src, chunk_bytes);
1006 memcpy(dst, src + chunk_bytes, src_bytes - chunk_bytes);
1007 }else
1008 memcpy(dst + dst_offs, src, src_bytes);
1011 static void silence_buffer(ACImpl *This, BYTE *buffer, UINT32 frames)
1013 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)This->fmt;
1014 if((This->fmt->wFormatTag == WAVE_FORMAT_PCM ||
1015 (This->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1016 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) &&
1017 This->fmt->wBitsPerSample == 8)
1018 memset(buffer, 128, frames * This->fmt->nBlockAlign);
1019 else
1020 memset(buffer, 0, frames * This->fmt->nBlockAlign);
1023 /* CA is pulling data from us */
1024 static OSStatus ca_render_cb(void *user, AudioUnitRenderActionFlags *flags,
1025 const AudioTimeStamp *ts, UInt32 bus, UInt32 nframes,
1026 AudioBufferList *data)
1028 ACImpl *This = user;
1029 UINT32 to_copy_bytes, to_copy_frames, chunk_bytes, lcl_offs_bytes;
1031 OSSpinLockLock(&This->lock);
1033 if(This->playing){
1034 lcl_offs_bytes = This->lcl_offs_frames * This->fmt->nBlockAlign;
1035 to_copy_frames = min(nframes, This->held_frames);
1036 to_copy_bytes = to_copy_frames * This->fmt->nBlockAlign;
1038 chunk_bytes = (This->bufsize_frames - This->lcl_offs_frames) * This->fmt->nBlockAlign;
1040 if(to_copy_bytes > chunk_bytes){
1041 memcpy(data->mBuffers[0].mData, This->local_buffer + lcl_offs_bytes, chunk_bytes);
1042 memcpy(((BYTE *)data->mBuffers[0].mData) + chunk_bytes, This->local_buffer, to_copy_bytes - chunk_bytes);
1043 }else
1044 memcpy(data->mBuffers[0].mData, This->local_buffer + lcl_offs_bytes, to_copy_bytes);
1046 This->lcl_offs_frames += to_copy_frames;
1047 This->lcl_offs_frames %= This->bufsize_frames;
1048 This->held_frames -= to_copy_frames;
1049 }else
1050 to_copy_bytes = to_copy_frames = 0;
1052 if(nframes > to_copy_frames)
1053 silence_buffer(This, ((BYTE *)data->mBuffers[0].mData) + to_copy_bytes, nframes - to_copy_frames);
1055 OSSpinLockUnlock(&This->lock);
1057 return noErr;
1060 static UINT buf_ptr_diff(UINT left, UINT right, UINT bufsize)
1062 if(left <= right)
1063 return right - left;
1064 return bufsize - (left - right);
1067 /* place data from cap_buffer into provided AudioBufferList */
1068 static OSStatus feed_cb(AudioConverterRef converter, UInt32 *nframes, AudioBufferList *data,
1069 AudioStreamPacketDescription **packets, void *user)
1071 ACImpl *This = user;
1073 *nframes = min(*nframes, This->cap_held_frames);
1074 if(!*nframes){
1075 data->mBuffers[0].mData = NULL;
1076 data->mBuffers[0].mDataByteSize = 0;
1077 data->mBuffers[0].mNumberChannels = This->fmt->nChannels;
1078 return noErr;
1081 data->mBuffers[0].mDataByteSize = *nframes * This->fmt->nBlockAlign;
1082 data->mBuffers[0].mNumberChannels = This->fmt->nChannels;
1084 if(This->cap_offs_frames + *nframes > This->cap_bufsize_frames){
1085 UINT32 chunk_frames = This->cap_bufsize_frames - This->cap_offs_frames;
1087 if(This->wrap_bufsize_frames < *nframes){
1088 free(This->wrap_buffer);
1089 This->wrap_buffer = malloc(data->mBuffers[0].mDataByteSize);
1090 This->wrap_bufsize_frames = *nframes;
1093 memcpy(This->wrap_buffer, This->cap_buffer + This->cap_offs_frames * This->fmt->nBlockAlign,
1094 chunk_frames * This->fmt->nBlockAlign);
1095 memcpy(This->wrap_buffer + chunk_frames * This->fmt->nBlockAlign, This->cap_buffer,
1096 (*nframes - chunk_frames) * This->fmt->nBlockAlign);
1098 data->mBuffers[0].mData = This->wrap_buffer;
1099 }else
1100 data->mBuffers[0].mData = This->cap_buffer + This->cap_offs_frames * This->fmt->nBlockAlign;
1102 This->cap_offs_frames += *nframes;
1103 This->cap_offs_frames %= This->cap_bufsize_frames;
1104 This->cap_held_frames -= *nframes;
1106 if(packets)
1107 *packets = NULL;
1109 return noErr;
1112 static void capture_resample(ACImpl *This)
1114 UINT32 resamp_period_frames = MulDiv(This->period_frames, This->dev_desc.mSampleRate, This->fmt->nSamplesPerSec);
1115 OSStatus sc;
1117 /* the resampling process often needs more source frames than we'd
1118 * guess from a straight conversion using the sample rate ratio. so
1119 * only convert if we have extra source data. */
1120 while(This->cap_held_frames > resamp_period_frames * 2){
1121 AudioBufferList converted_list;
1122 UInt32 wanted_frames = This->period_frames;
1124 converted_list.mNumberBuffers = 1;
1125 converted_list.mBuffers[0].mNumberChannels = This->fmt->nChannels;
1126 converted_list.mBuffers[0].mDataByteSize = wanted_frames * This->fmt->nBlockAlign;
1128 if(This->resamp_bufsize_frames < wanted_frames){
1129 HeapFree(GetProcessHeap(), 0, This->resamp_buffer);
1130 This->resamp_buffer = HeapAlloc(GetProcessHeap(), 0, converted_list.mBuffers[0].mDataByteSize);
1131 This->resamp_bufsize_frames = wanted_frames;
1134 converted_list.mBuffers[0].mData = This->resamp_buffer;
1136 sc = AudioConverterFillComplexBuffer(This->converter, feed_cb,
1137 This, &wanted_frames, &converted_list, NULL);
1138 if(sc != noErr){
1139 WARN("AudioConverterFillComplexBuffer failed: %lx\n", sc);
1140 break;
1143 ca_wrap_buffer(This->local_buffer,
1144 This->wri_offs_frames * This->fmt->nBlockAlign,
1145 This->bufsize_frames * This->fmt->nBlockAlign,
1146 This->resamp_buffer, wanted_frames * This->fmt->nBlockAlign);
1148 This->wri_offs_frames += wanted_frames;
1149 This->wri_offs_frames %= This->bufsize_frames;
1150 if(This->held_frames + wanted_frames > This->bufsize_frames){
1151 This->lcl_offs_frames += buf_ptr_diff(This->lcl_offs_frames,
1152 This->wri_offs_frames, This->bufsize_frames);
1153 This->held_frames = This->bufsize_frames;
1154 }else
1155 This->held_frames += wanted_frames;
1159 /* we need to trigger CA to pull data from the device and give it to us
1161 * raw data from CA is stored in cap_buffer, possibly via wrap_buffer
1163 * raw data is resampled from cap_buffer into resamp_buffer in period-size
1164 * chunks and copied to local_buffer
1166 static OSStatus ca_capture_cb(void *user, AudioUnitRenderActionFlags *flags,
1167 const AudioTimeStamp *ts, UInt32 bus, UInt32 nframes,
1168 AudioBufferList *data)
1170 ACImpl *This = user;
1171 AudioBufferList list;
1172 OSStatus sc;
1173 UINT32 cap_wri_offs_frames;
1175 OSSpinLockLock(&This->lock);
1177 cap_wri_offs_frames = (This->cap_offs_frames + This->cap_held_frames) % This->cap_bufsize_frames;
1179 list.mNumberBuffers = 1;
1180 list.mBuffers[0].mNumberChannels = This->fmt->nChannels;
1181 list.mBuffers[0].mDataByteSize = nframes * This->fmt->nBlockAlign;
1183 if(!This->playing || cap_wri_offs_frames + nframes > This->cap_bufsize_frames){
1184 if(This->wrap_bufsize_frames < nframes){
1185 free(This->wrap_buffer);
1186 This->wrap_buffer = malloc(list.mBuffers[0].mDataByteSize);
1187 This->wrap_bufsize_frames = nframes;
1190 list.mBuffers[0].mData = This->wrap_buffer;
1191 }else
1192 list.mBuffers[0].mData = This->cap_buffer + cap_wri_offs_frames * This->fmt->nBlockAlign;
1194 sc = AudioUnitRender(This->unit, flags, ts, bus, nframes, &list);
1195 if(sc != noErr){
1196 OSSpinLockUnlock(&This->lock);
1197 return sc;
1200 if(This->playing){
1201 if(list.mBuffers[0].mData == This->wrap_buffer){
1202 ca_wrap_buffer(This->cap_buffer,
1203 cap_wri_offs_frames * This->fmt->nBlockAlign,
1204 This->cap_bufsize_frames * This->fmt->nBlockAlign,
1205 This->wrap_buffer, list.mBuffers[0].mDataByteSize);
1208 This->cap_held_frames += list.mBuffers[0].mDataByteSize / This->fmt->nBlockAlign;
1209 if(This->cap_held_frames > This->cap_bufsize_frames){
1210 This->cap_offs_frames += This->cap_held_frames % This->cap_bufsize_frames;
1211 This->cap_offs_frames %= This->cap_bufsize_frames;
1212 This->cap_held_frames = This->cap_bufsize_frames;
1216 OSSpinLockUnlock(&This->lock);
1217 return noErr;
1220 static void dump_adesc(const char *aux, AudioStreamBasicDescription *desc)
1222 TRACE("%s: mSampleRate: %f\n", aux, desc->mSampleRate);
1223 TRACE("%s: mBytesPerPacket: %ld\n", aux, desc->mBytesPerPacket);
1224 TRACE("%s: mFramesPerPacket: %ld\n", aux, desc->mFramesPerPacket);
1225 TRACE("%s: mBytesPerFrame: %ld\n", aux, desc->mBytesPerFrame);
1226 TRACE("%s: mChannelsPerFrame: %ld\n", aux, desc->mChannelsPerFrame);
1227 TRACE("%s: mBitsPerChannel: %ld\n", aux, desc->mBitsPerChannel);
1230 static HRESULT ca_setup_audiounit(EDataFlow dataflow, AudioComponentInstance unit,
1231 const WAVEFORMATEX *fmt, AudioStreamBasicDescription *dev_desc,
1232 AudioConverterRef *converter)
1234 OSStatus sc;
1235 HRESULT hr;
1237 if(dataflow == eCapture){
1238 AudioStreamBasicDescription desc;
1239 UInt32 size;
1240 Float64 rate;
1242 hr = ca_get_audiodesc(&desc, fmt);
1243 if(FAILED(hr))
1244 return hr;
1245 dump_adesc("requested", &desc);
1247 /* input-only units can't perform sample rate conversion, so we have to
1248 * set up our own AudioConverter to support arbitrary sample rates. */
1249 size = sizeof(*dev_desc);
1250 sc = AudioUnitGetProperty(unit, kAudioUnitProperty_StreamFormat,
1251 kAudioUnitScope_Input, 1, dev_desc, &size);
1252 if(sc != noErr){
1253 WARN("Couldn't get unit format: %lx\n", sc);
1254 return osstatus_to_hresult(sc);
1256 dump_adesc("hardware", dev_desc);
1258 rate = dev_desc->mSampleRate;
1259 *dev_desc = desc;
1260 dev_desc->mSampleRate = rate;
1262 dump_adesc("final", dev_desc);
1263 sc = AudioUnitSetProperty(unit, kAudioUnitProperty_StreamFormat,
1264 kAudioUnitScope_Output, 1, dev_desc, sizeof(*dev_desc));
1265 if(sc != noErr){
1266 WARN("Couldn't set unit format: %lx\n", sc);
1267 return osstatus_to_hresult(sc);
1270 sc = AudioConverterNew(dev_desc, &desc, converter);
1271 if(sc != noErr){
1272 WARN("Couldn't create audio converter: %lx\n", sc);
1273 return osstatus_to_hresult(sc);
1275 }else{
1276 hr = ca_get_audiodesc(dev_desc, fmt);
1277 if(FAILED(hr))
1278 return hr;
1280 dump_adesc("final", dev_desc);
1281 sc = AudioUnitSetProperty(unit, kAudioUnitProperty_StreamFormat,
1282 kAudioUnitScope_Input, 0, dev_desc, sizeof(*dev_desc));
1283 if(sc != noErr){
1284 WARN("Couldn't set format: %lx\n", sc);
1285 return osstatus_to_hresult(sc);
1289 return S_OK;
1292 static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
1293 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
1294 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
1295 const GUID *sessionguid)
1297 ACImpl *This = impl_from_IAudioClient(iface);
1298 HRESULT hr;
1299 OSStatus sc;
1300 int i;
1302 TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
1303 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
1305 if(!fmt)
1306 return E_POINTER;
1308 dump_fmt(fmt);
1310 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1311 return AUDCLNT_E_NOT_INITIALIZED;
1313 if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
1314 AUDCLNT_STREAMFLAGS_LOOPBACK |
1315 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
1316 AUDCLNT_STREAMFLAGS_NOPERSIST |
1317 AUDCLNT_STREAMFLAGS_RATEADJUST |
1318 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
1319 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
1320 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED)){
1321 TRACE("Unknown flags: %08x\n", flags);
1322 return E_INVALIDARG;
1325 if(mode == AUDCLNT_SHAREMODE_SHARED){
1326 period = DefaultPeriod;
1327 if( duration < 3 * period)
1328 duration = 3 * period;
1329 }else{
1330 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
1331 if(((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask == 0 ||
1332 ((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask & SPEAKER_RESERVED)
1333 return AUDCLNT_E_UNSUPPORTED_FORMAT;
1336 if(!period)
1337 period = DefaultPeriod; /* not minimum */
1338 if(period < MinimumPeriod || period > 5000000)
1339 return AUDCLNT_E_INVALID_DEVICE_PERIOD;
1340 if(duration > 20000000) /* the smaller the period, the lower this limit */
1341 return AUDCLNT_E_BUFFER_SIZE_ERROR;
1342 if(flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK){
1343 if(duration != period)
1344 return AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL;
1345 FIXME("EXCLUSIVE mode with EVENTCALLBACK\n");
1346 return AUDCLNT_E_DEVICE_IN_USE;
1347 }else{
1348 if( duration < 8 * period)
1349 duration = 8 * period; /* may grow above 2s */
1353 OSSpinLockLock(&This->lock);
1355 if(This->initted){
1356 OSSpinLockUnlock(&This->lock);
1357 return AUDCLNT_E_ALREADY_INITIALIZED;
1360 This->fmt = clone_format(fmt);
1361 if(!This->fmt){
1362 OSSpinLockUnlock(&This->lock);
1363 return E_OUTOFMEMORY;
1366 This->period_ms = period / 10000;
1367 This->period_frames = MulDiv(period, This->fmt->nSamplesPerSec, 10000000);
1369 This->bufsize_frames = MulDiv(duration, fmt->nSamplesPerSec, 10000000);
1370 if(mode == AUDCLNT_SHAREMODE_EXCLUSIVE)
1371 This->bufsize_frames -= This->bufsize_frames % This->period_frames;
1373 hr = ca_setup_audiounit(This->dataflow, This->unit, This->fmt, &This->dev_desc, &This->converter);
1374 if(FAILED(hr)){
1375 CoTaskMemFree(This->fmt);
1376 This->fmt = NULL;
1377 OSSpinLockUnlock(&This->lock);
1378 return hr;
1381 if(This->dataflow == eCapture){
1382 AURenderCallbackStruct input;
1384 memset(&input, 0, sizeof(input));
1385 input.inputProc = &ca_capture_cb;
1386 input.inputProcRefCon = This;
1388 sc = AudioUnitSetProperty(This->unit, kAudioOutputUnitProperty_SetInputCallback,
1389 kAudioUnitScope_Output, 1, &input, sizeof(input));
1390 if(sc != noErr){
1391 WARN("Couldn't set callback: %lx\n", sc);
1392 AudioConverterDispose(This->converter);
1393 This->converter = NULL;
1394 CoTaskMemFree(This->fmt);
1395 This->fmt = NULL;
1396 OSSpinLockUnlock(&This->lock);
1397 return osstatus_to_hresult(sc);
1399 }else{
1400 AURenderCallbackStruct input;
1402 memset(&input, 0, sizeof(input));
1403 input.inputProc = &ca_render_cb;
1404 input.inputProcRefCon = This;
1406 sc = AudioUnitSetProperty(This->unit, kAudioUnitProperty_SetRenderCallback,
1407 kAudioUnitScope_Input, 0, &input, sizeof(input));
1408 if(sc != noErr){
1409 WARN("Couldn't set callback: %lx\n", sc);
1410 CoTaskMemFree(This->fmt);
1411 This->fmt = NULL;
1412 OSSpinLockUnlock(&This->lock);
1413 return osstatus_to_hresult(sc);
1417 sc = AudioUnitInitialize(This->unit);
1418 if(sc != noErr){
1419 WARN("Couldn't initialize: %lx\n", sc);
1420 if(This->converter){
1421 AudioConverterDispose(This->converter);
1422 This->converter = NULL;
1424 CoTaskMemFree(This->fmt);
1425 This->fmt = NULL;
1426 OSSpinLockUnlock(&This->lock);
1427 return osstatus_to_hresult(sc);
1430 /* we play audio continuously because AudioOutputUnitStart sometimes takes
1431 * a while to return */
1432 sc = AudioOutputUnitStart(This->unit);
1433 if(sc != noErr){
1434 WARN("Unit failed to start: %lx\n", sc);
1435 if(This->converter){
1436 AudioConverterDispose(This->converter);
1437 This->converter = NULL;
1439 CoTaskMemFree(This->fmt);
1440 This->fmt = NULL;
1441 OSSpinLockUnlock(&This->lock);
1442 return osstatus_to_hresult(sc);
1445 This->local_buffer = HeapAlloc(GetProcessHeap(), 0, This->bufsize_frames * fmt->nBlockAlign);
1446 silence_buffer(This, This->local_buffer, This->bufsize_frames);
1448 if(This->dataflow == eCapture){
1449 This->cap_bufsize_frames = MulDiv(duration, This->dev_desc.mSampleRate, 10000000);
1450 This->cap_buffer = HeapAlloc(GetProcessHeap(), 0, This->cap_bufsize_frames * This->fmt->nBlockAlign);
1453 This->vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float));
1454 if(!This->vols){
1455 CoTaskMemFree(This->fmt);
1456 This->fmt = NULL;
1457 OSSpinLockUnlock(&This->lock);
1458 return E_OUTOFMEMORY;
1461 for(i = 0; i < fmt->nChannels; ++i)
1462 This->vols[i] = 1.f;
1464 This->share = mode;
1465 This->flags = flags;
1467 EnterCriticalSection(&g_sessions_lock);
1469 hr = get_audio_session(sessionguid, This->parent, fmt->nChannels,
1470 &This->session);
1471 if(FAILED(hr)){
1472 LeaveCriticalSection(&g_sessions_lock);
1473 CoTaskMemFree(This->fmt);
1474 This->fmt = NULL;
1475 HeapFree(GetProcessHeap(), 0, This->vols);
1476 This->vols = NULL;
1477 OSSpinLockUnlock(&This->lock);
1478 return E_INVALIDARG;
1481 list_add_tail(&This->session->clients, &This->entry);
1483 LeaveCriticalSection(&g_sessions_lock);
1485 ca_setvol(This, -1);
1487 This->initted = TRUE;
1489 OSSpinLockUnlock(&This->lock);
1491 return S_OK;
1494 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
1495 UINT32 *frames)
1497 ACImpl *This = impl_from_IAudioClient(iface);
1499 TRACE("(%p)->(%p)\n", This, frames);
1501 if(!frames)
1502 return E_POINTER;
1504 OSSpinLockLock(&This->lock);
1506 if(!This->initted){
1507 OSSpinLockUnlock(&This->lock);
1508 return AUDCLNT_E_NOT_INITIALIZED;
1511 *frames = This->bufsize_frames;
1513 OSSpinLockUnlock(&This->lock);
1515 return S_OK;
1518 static HRESULT ca_get_max_stream_latency(ACImpl *This, UInt32 *max)
1520 AudioObjectPropertyAddress addr;
1521 AudioStreamID *ids;
1522 UInt32 size;
1523 OSStatus sc;
1524 int nstreams, i;
1526 addr.mScope = This->scope;
1527 addr.mElement = 0;
1528 addr.mSelector = kAudioDevicePropertyStreams;
1530 sc = AudioObjectGetPropertyDataSize(This->adevid, &addr, 0, NULL,
1531 &size);
1532 if(sc != noErr){
1533 WARN("Unable to get size for _Streams property: %lx\n", sc);
1534 return osstatus_to_hresult(sc);
1537 ids = HeapAlloc(GetProcessHeap(), 0, size);
1538 if(!ids)
1539 return E_OUTOFMEMORY;
1541 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL, &size, ids);
1542 if(sc != noErr){
1543 WARN("Unable to get _Streams property: %lx\n", sc);
1544 HeapFree(GetProcessHeap(), 0, ids);
1545 return osstatus_to_hresult(sc);
1548 nstreams = size / sizeof(AudioStreamID);
1549 *max = 0;
1551 addr.mSelector = kAudioStreamPropertyLatency;
1552 for(i = 0; i < nstreams; ++i){
1553 UInt32 latency;
1555 size = sizeof(latency);
1556 sc = AudioObjectGetPropertyData(ids[i], &addr, 0, NULL,
1557 &size, &latency);
1558 if(sc != noErr){
1559 WARN("Unable to get _Latency property: %lx\n", sc);
1560 continue;
1563 if(latency > *max)
1564 *max = latency;
1567 HeapFree(GetProcessHeap(), 0, ids);
1569 return S_OK;
1572 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
1573 REFERENCE_TIME *out)
1575 ACImpl *This = impl_from_IAudioClient(iface);
1576 UInt32 latency, stream_latency, size;
1577 AudioObjectPropertyAddress addr;
1578 OSStatus sc;
1579 HRESULT hr;
1581 TRACE("(%p)->(%p)\n", This, out);
1583 if(!out)
1584 return E_POINTER;
1586 OSSpinLockLock(&This->lock);
1588 if(!This->initted){
1589 OSSpinLockUnlock(&This->lock);
1590 return AUDCLNT_E_NOT_INITIALIZED;
1593 addr.mScope = This->scope;
1594 addr.mSelector = kAudioDevicePropertyLatency;
1595 addr.mElement = 0;
1597 size = sizeof(latency);
1598 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL,
1599 &size, &latency);
1600 if(sc != noErr){
1601 WARN("Couldn't get _Latency property: %lx\n", sc);
1602 OSSpinLockUnlock(&This->lock);
1603 return osstatus_to_hresult(sc);
1606 hr = ca_get_max_stream_latency(This, &stream_latency);
1607 if(FAILED(hr)){
1608 OSSpinLockUnlock(&This->lock);
1609 return hr;
1612 latency += stream_latency;
1613 /* pretend we process audio in Period chunks, so max latency includes
1614 * the period time */
1615 *out = MulDiv(latency, 10000000, This->fmt->nSamplesPerSec)
1616 + This->period_ms * 10000;
1618 OSSpinLockUnlock(&This->lock);
1620 return S_OK;
1623 static HRESULT AudioClient_GetCurrentPadding_nolock(ACImpl *This,
1624 UINT32 *numpad)
1626 if(!This->initted)
1627 return AUDCLNT_E_NOT_INITIALIZED;
1629 if(This->dataflow == eCapture)
1630 capture_resample(This);
1632 *numpad = This->held_frames;
1634 return S_OK;
1637 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
1638 UINT32 *numpad)
1640 ACImpl *This = impl_from_IAudioClient(iface);
1641 HRESULT hr;
1643 TRACE("(%p)->(%p)\n", This, numpad);
1645 if(!numpad)
1646 return E_POINTER;
1648 OSSpinLockLock(&This->lock);
1650 hr = AudioClient_GetCurrentPadding_nolock(This, numpad);
1652 OSSpinLockUnlock(&This->lock);
1654 return hr;
1657 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
1658 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
1659 WAVEFORMATEX **outpwfx)
1661 ACImpl *This = impl_from_IAudioClient(iface);
1662 AudioStreamBasicDescription dev_desc;
1663 AudioConverterRef converter;
1664 AudioComponentInstance unit;
1665 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)pwfx;
1666 HRESULT hr;
1668 TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx);
1670 if(!pwfx || (mode == AUDCLNT_SHAREMODE_SHARED && !outpwfx))
1671 return E_POINTER;
1673 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1674 return E_INVALIDARG;
1676 if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1677 pwfx->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1678 return E_INVALIDARG;
1680 dump_fmt(pwfx);
1682 if(outpwfx){
1683 *outpwfx = NULL;
1684 if(mode != AUDCLNT_SHAREMODE_SHARED)
1685 outpwfx = NULL;
1688 if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
1689 if(pwfx->nAvgBytesPerSec == 0 ||
1690 pwfx->nBlockAlign == 0 ||
1691 fmtex->Samples.wValidBitsPerSample > pwfx->wBitsPerSample)
1692 return E_INVALIDARG;
1693 if(fmtex->Samples.wValidBitsPerSample < pwfx->wBitsPerSample)
1694 goto unsupported;
1695 if(mode == AUDCLNT_SHAREMODE_EXCLUSIVE){
1696 if(fmtex->dwChannelMask == 0 ||
1697 fmtex->dwChannelMask & SPEAKER_RESERVED)
1698 goto unsupported;
1702 if(pwfx->nBlockAlign != pwfx->nChannels * pwfx->wBitsPerSample / 8 ||
1703 pwfx->nAvgBytesPerSec != pwfx->nBlockAlign * pwfx->nSamplesPerSec)
1704 goto unsupported;
1706 if(pwfx->nChannels == 0)
1707 return AUDCLNT_E_UNSUPPORTED_FORMAT;
1709 unit = get_audiounit(This->dataflow, This->adevid);
1711 converter = NULL;
1712 hr = ca_setup_audiounit(This->dataflow, unit, pwfx, &dev_desc, &converter);
1713 AudioComponentInstanceDispose(unit);
1714 if(FAILED(hr))
1715 goto unsupported;
1717 if(converter)
1718 AudioConverterDispose(converter);
1720 return S_OK;
1722 unsupported:
1723 if(outpwfx){
1724 hr = IAudioClient_GetMixFormat(&This->IAudioClient_iface, outpwfx);
1725 if(FAILED(hr))
1726 return hr;
1727 return S_FALSE;
1730 return AUDCLNT_E_UNSUPPORTED_FORMAT;
1733 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
1734 WAVEFORMATEX **pwfx)
1736 ACImpl *This = impl_from_IAudioClient(iface);
1737 WAVEFORMATEXTENSIBLE *fmt;
1738 OSStatus sc;
1739 UInt32 size;
1740 Float64 rate;
1741 AudioBufferList *buffers;
1742 AudioObjectPropertyAddress addr;
1743 int i;
1745 TRACE("(%p)->(%p)\n", This, pwfx);
1747 if(!pwfx)
1748 return E_POINTER;
1749 *pwfx = NULL;
1751 fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
1752 if(!fmt)
1753 return E_OUTOFMEMORY;
1755 fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1757 addr.mScope = This->scope;
1758 addr.mElement = 0;
1759 addr.mSelector = kAudioDevicePropertyStreamConfiguration;
1761 sc = AudioObjectGetPropertyDataSize(This->adevid, &addr, 0, NULL, &size);
1762 if(sc != noErr){
1763 CoTaskMemFree(fmt);
1764 WARN("Unable to get size for _StreamConfiguration property: %lx\n", sc);
1765 return osstatus_to_hresult(sc);
1768 buffers = HeapAlloc(GetProcessHeap(), 0, size);
1769 if(!buffers){
1770 CoTaskMemFree(fmt);
1771 return E_OUTOFMEMORY;
1774 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL,
1775 &size, buffers);
1776 if(sc != noErr){
1777 CoTaskMemFree(fmt);
1778 HeapFree(GetProcessHeap(), 0, buffers);
1779 WARN("Unable to get _StreamConfiguration property: %lx\n", sc);
1780 return osstatus_to_hresult(sc);
1783 fmt->Format.nChannels = 0;
1784 for(i = 0; i < buffers->mNumberBuffers; ++i)
1785 fmt->Format.nChannels += buffers->mBuffers[i].mNumberChannels;
1787 HeapFree(GetProcessHeap(), 0, buffers);
1789 fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
1791 addr.mSelector = kAudioDevicePropertyNominalSampleRate;
1792 size = sizeof(Float64);
1793 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL, &size, &rate);
1794 if(sc != noErr){
1795 CoTaskMemFree(fmt);
1796 WARN("Unable to get _NominalSampleRate property: %lx\n", sc);
1797 return osstatus_to_hresult(sc);
1799 fmt->Format.nSamplesPerSec = rate;
1801 fmt->Format.wBitsPerSample = 32;
1802 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
1804 fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
1805 fmt->Format.nChannels) / 8;
1806 fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
1807 fmt->Format.nBlockAlign;
1809 fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
1810 fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1812 *pwfx = (WAVEFORMATEX*)fmt;
1813 dump_fmt(*pwfx);
1815 return S_OK;
1818 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
1819 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1821 ACImpl *This = impl_from_IAudioClient(iface);
1823 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
1825 if(!defperiod && !minperiod)
1826 return E_POINTER;
1828 if(defperiod)
1829 *defperiod = DefaultPeriod;
1830 if(minperiod)
1831 *minperiod = MinimumPeriod;
1833 return S_OK;
1836 void CALLBACK ca_period_cb(void *user, BOOLEAN timer)
1838 ACImpl *This = user;
1840 if(This->event)
1841 SetEvent(This->event);
1844 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
1846 ACImpl *This = impl_from_IAudioClient(iface);
1848 TRACE("(%p)\n", This);
1850 OSSpinLockLock(&This->lock);
1852 if(!This->initted){
1853 OSSpinLockUnlock(&This->lock);
1854 return AUDCLNT_E_NOT_INITIALIZED;
1857 if(This->playing){
1858 OSSpinLockUnlock(&This->lock);
1859 return AUDCLNT_E_NOT_STOPPED;
1862 if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
1863 OSSpinLockUnlock(&This->lock);
1864 return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1867 if(This->event && !This->timer)
1868 if(!CreateTimerQueueTimer(&This->timer, g_timer_q, ca_period_cb,
1869 This, 0, This->period_ms, WT_EXECUTEINTIMERTHREAD)){
1870 This->timer = NULL;
1871 OSSpinLockUnlock(&This->lock);
1872 WARN("Unable to create timer: %u\n", GetLastError());
1873 return E_OUTOFMEMORY;
1876 This->playing = TRUE;
1878 OSSpinLockUnlock(&This->lock);
1880 return S_OK;
1883 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
1885 ACImpl *This = impl_from_IAudioClient(iface);
1887 TRACE("(%p)\n", This);
1889 OSSpinLockLock(&This->lock);
1891 if(!This->initted){
1892 OSSpinLockUnlock(&This->lock);
1893 return AUDCLNT_E_NOT_INITIALIZED;
1896 if(!This->playing){
1897 OSSpinLockUnlock(&This->lock);
1898 return S_FALSE;
1901 This->playing = FALSE;
1903 OSSpinLockUnlock(&This->lock);
1905 return S_OK;
1908 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
1910 ACImpl *This = impl_from_IAudioClient(iface);
1912 TRACE("(%p)\n", This);
1914 OSSpinLockLock(&This->lock);
1916 if(!This->initted){
1917 OSSpinLockUnlock(&This->lock);
1918 return AUDCLNT_E_NOT_INITIALIZED;
1921 if(This->playing){
1922 OSSpinLockUnlock(&This->lock);
1923 return AUDCLNT_E_NOT_STOPPED;
1926 if(This->getbuf_last){
1927 OSSpinLockUnlock(&This->lock);
1928 return AUDCLNT_E_BUFFER_OPERATION_PENDING;
1931 if(This->dataflow == eRender){
1932 This->written_frames = 0;
1933 }else{
1934 This->written_frames += This->held_frames;
1937 This->held_frames = 0;
1938 This->lcl_offs_frames = 0;
1939 This->wri_offs_frames = 0;
1940 This->cap_offs_frames = 0;
1941 This->cap_held_frames = 0;
1943 OSSpinLockUnlock(&This->lock);
1945 return S_OK;
1948 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1949 HANDLE event)
1951 ACImpl *This = impl_from_IAudioClient(iface);
1953 TRACE("(%p)->(%p)\n", This, event);
1955 if(!event)
1956 return E_INVALIDARG;
1958 OSSpinLockLock(&This->lock);
1960 if(!This->initted){
1961 OSSpinLockUnlock(&This->lock);
1962 return AUDCLNT_E_NOT_INITIALIZED;
1965 if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
1966 OSSpinLockUnlock(&This->lock);
1967 return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1970 if (This->event){
1971 OSSpinLockUnlock(&This->lock);
1972 FIXME("called twice\n");
1973 return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
1976 This->event = event;
1978 OSSpinLockUnlock(&This->lock);
1980 return S_OK;
1983 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1984 void **ppv)
1986 ACImpl *This = impl_from_IAudioClient(iface);
1988 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1990 if(!ppv)
1991 return E_POINTER;
1992 *ppv = NULL;
1994 OSSpinLockLock(&This->lock);
1996 if(!This->initted){
1997 OSSpinLockUnlock(&This->lock);
1998 return AUDCLNT_E_NOT_INITIALIZED;
2001 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
2002 if(This->dataflow != eRender){
2003 OSSpinLockUnlock(&This->lock);
2004 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
2006 IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
2007 *ppv = &This->IAudioRenderClient_iface;
2008 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
2009 if(This->dataflow != eCapture){
2010 OSSpinLockUnlock(&This->lock);
2011 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
2013 IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
2014 *ppv = &This->IAudioCaptureClient_iface;
2015 }else if(IsEqualIID(riid, &IID_IAudioClock)){
2016 IAudioClock_AddRef(&This->IAudioClock_iface);
2017 *ppv = &This->IAudioClock_iface;
2018 }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
2019 IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
2020 *ppv = &This->IAudioStreamVolume_iface;
2021 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
2022 if(!This->session_wrapper){
2023 This->session_wrapper = AudioSessionWrapper_Create(This);
2024 if(!This->session_wrapper){
2025 OSSpinLockUnlock(&This->lock);
2026 return E_OUTOFMEMORY;
2028 }else
2029 IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
2031 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
2032 }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
2033 if(!This->session_wrapper){
2034 This->session_wrapper = AudioSessionWrapper_Create(This);
2035 if(!This->session_wrapper){
2036 OSSpinLockUnlock(&This->lock);
2037 return E_OUTOFMEMORY;
2039 }else
2040 IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
2042 *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
2043 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
2044 if(!This->session_wrapper){
2045 This->session_wrapper = AudioSessionWrapper_Create(This);
2046 if(!This->session_wrapper){
2047 OSSpinLockUnlock(&This->lock);
2048 return E_OUTOFMEMORY;
2050 }else
2051 ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
2053 *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
2056 if(*ppv){
2057 OSSpinLockUnlock(&This->lock);
2058 return S_OK;
2061 OSSpinLockUnlock(&This->lock);
2063 FIXME("stub %s\n", debugstr_guid(riid));
2064 return E_NOINTERFACE;
2067 static const IAudioClientVtbl AudioClient_Vtbl =
2069 AudioClient_QueryInterface,
2070 AudioClient_AddRef,
2071 AudioClient_Release,
2072 AudioClient_Initialize,
2073 AudioClient_GetBufferSize,
2074 AudioClient_GetStreamLatency,
2075 AudioClient_GetCurrentPadding,
2076 AudioClient_IsFormatSupported,
2077 AudioClient_GetMixFormat,
2078 AudioClient_GetDevicePeriod,
2079 AudioClient_Start,
2080 AudioClient_Stop,
2081 AudioClient_Reset,
2082 AudioClient_SetEventHandle,
2083 AudioClient_GetService
2086 static HRESULT WINAPI AudioRenderClient_QueryInterface(
2087 IAudioRenderClient *iface, REFIID riid, void **ppv)
2089 ACImpl *This = impl_from_IAudioRenderClient(iface);
2090 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2092 if(!ppv)
2093 return E_POINTER;
2094 *ppv = NULL;
2096 if(IsEqualIID(riid, &IID_IUnknown) ||
2097 IsEqualIID(riid, &IID_IAudioRenderClient))
2098 *ppv = iface;
2099 else if(IsEqualIID(riid, &IID_IMarshal))
2100 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
2102 if(*ppv){
2103 IUnknown_AddRef((IUnknown*)*ppv);
2104 return S_OK;
2107 WARN("Unknown interface %s\n", debugstr_guid(riid));
2108 return E_NOINTERFACE;
2111 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
2113 ACImpl *This = impl_from_IAudioRenderClient(iface);
2114 return AudioClient_AddRef(&This->IAudioClient_iface);
2117 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
2119 ACImpl *This = impl_from_IAudioRenderClient(iface);
2120 return AudioClient_Release(&This->IAudioClient_iface);
2123 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
2124 UINT32 frames, BYTE **data)
2126 ACImpl *This = impl_from_IAudioRenderClient(iface);
2127 UINT32 pad;
2128 HRESULT hr;
2130 TRACE("(%p)->(%u, %p)\n", This, frames, data);
2132 if(!data)
2133 return E_POINTER;
2134 *data = NULL;
2136 OSSpinLockLock(&This->lock);
2138 if(This->getbuf_last){
2139 OSSpinLockUnlock(&This->lock);
2140 return AUDCLNT_E_OUT_OF_ORDER;
2143 if(!frames){
2144 OSSpinLockUnlock(&This->lock);
2145 return S_OK;
2148 hr = AudioClient_GetCurrentPadding_nolock(This, &pad);
2149 if(FAILED(hr)){
2150 OSSpinLockUnlock(&This->lock);
2151 return hr;
2154 if(pad + frames > This->bufsize_frames){
2155 OSSpinLockUnlock(&This->lock);
2156 return AUDCLNT_E_BUFFER_TOO_LARGE;
2159 if(This->wri_offs_frames + frames > This->bufsize_frames){
2160 if(This->tmp_buffer_frames < frames){
2161 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
2162 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0, frames * This->fmt->nBlockAlign);
2163 if(!This->tmp_buffer){
2164 OSSpinLockUnlock(&This->lock);
2165 return E_OUTOFMEMORY;
2167 This->tmp_buffer_frames = frames;
2169 *data = This->tmp_buffer;
2170 This->getbuf_last = -frames;
2171 }else{
2172 *data = This->local_buffer + This->wri_offs_frames * This->fmt->nBlockAlign;
2173 This->getbuf_last = frames;
2176 silence_buffer(This, *data, frames);
2178 OSSpinLockUnlock(&This->lock);
2180 return S_OK;
2183 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
2184 IAudioRenderClient *iface, UINT32 frames, DWORD flags)
2186 ACImpl *This = impl_from_IAudioRenderClient(iface);
2187 BYTE *buffer;
2189 TRACE("(%p)->(%u, %x)\n", This, frames, flags);
2191 OSSpinLockLock(&This->lock);
2193 if(!frames){
2194 This->getbuf_last = 0;
2195 OSSpinLockUnlock(&This->lock);
2196 return S_OK;
2199 if(!This->getbuf_last){
2200 OSSpinLockUnlock(&This->lock);
2201 return AUDCLNT_E_OUT_OF_ORDER;
2204 if(frames > (This->getbuf_last >= 0 ? This->getbuf_last : -This->getbuf_last)){
2205 OSSpinLockUnlock(&This->lock);
2206 return AUDCLNT_E_INVALID_SIZE;
2209 if(This->getbuf_last >= 0)
2210 buffer = This->local_buffer + This->wri_offs_frames * This->fmt->nBlockAlign;
2211 else
2212 buffer = This->tmp_buffer;
2214 if(flags & AUDCLNT_BUFFERFLAGS_SILENT)
2215 silence_buffer(This, buffer, frames);
2217 if(This->getbuf_last < 0)
2218 ca_wrap_buffer(This->local_buffer,
2219 This->wri_offs_frames * This->fmt->nBlockAlign,
2220 This->bufsize_frames * This->fmt->nBlockAlign,
2221 buffer, frames * This->fmt->nBlockAlign);
2224 This->wri_offs_frames += frames;
2225 This->wri_offs_frames %= This->bufsize_frames;
2226 This->held_frames += frames;
2227 This->written_frames += frames;
2228 This->getbuf_last = 0;
2230 OSSpinLockUnlock(&This->lock);
2232 return S_OK;
2235 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
2236 AudioRenderClient_QueryInterface,
2237 AudioRenderClient_AddRef,
2238 AudioRenderClient_Release,
2239 AudioRenderClient_GetBuffer,
2240 AudioRenderClient_ReleaseBuffer
2243 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
2244 IAudioCaptureClient *iface, REFIID riid, void **ppv)
2246 ACImpl *This = impl_from_IAudioCaptureClient(iface);
2247 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2249 if(!ppv)
2250 return E_POINTER;
2251 *ppv = NULL;
2253 if(IsEqualIID(riid, &IID_IUnknown) ||
2254 IsEqualIID(riid, &IID_IAudioCaptureClient))
2255 *ppv = iface;
2256 else if(IsEqualIID(riid, &IID_IMarshal))
2257 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
2259 if(*ppv){
2260 IUnknown_AddRef((IUnknown*)*ppv);
2261 return S_OK;
2264 WARN("Unknown interface %s\n", debugstr_guid(riid));
2265 return E_NOINTERFACE;
2268 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
2270 ACImpl *This = impl_from_IAudioCaptureClient(iface);
2271 return IAudioClient_AddRef(&This->IAudioClient_iface);
2274 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
2276 ACImpl *This = impl_from_IAudioCaptureClient(iface);
2277 return IAudioClient_Release(&This->IAudioClient_iface);
2280 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
2281 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
2282 UINT64 *qpcpos)
2284 ACImpl *This = impl_from_IAudioCaptureClient(iface);
2285 UINT32 chunk_bytes, chunk_frames;
2287 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
2288 devpos, qpcpos);
2290 if(!data || !frames || !flags)
2291 return E_POINTER;
2293 OSSpinLockLock(&This->lock);
2295 if(This->getbuf_last){
2296 OSSpinLockUnlock(&This->lock);
2297 return AUDCLNT_E_OUT_OF_ORDER;
2300 capture_resample(This);
2302 if(This->held_frames < This->period_frames){
2303 *frames = 0;
2304 OSSpinLockUnlock(&This->lock);
2305 return AUDCLNT_S_BUFFER_EMPTY;
2308 *flags = 0;
2310 chunk_frames = This->bufsize_frames - This->lcl_offs_frames;
2311 if(chunk_frames < This->period_frames){
2312 chunk_bytes = chunk_frames * This->fmt->nBlockAlign;
2313 if(!This->tmp_buffer)
2314 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0, This->period_frames * This->fmt->nBlockAlign);
2315 *data = This->tmp_buffer;
2316 memcpy(*data, This->local_buffer + This->lcl_offs_frames * This->fmt->nBlockAlign, chunk_bytes);
2317 memcpy((*data) + chunk_bytes, This->local_buffer, This->period_frames * This->fmt->nBlockAlign - chunk_bytes);
2318 }else
2319 *data = This->local_buffer + This->lcl_offs_frames * This->fmt->nBlockAlign;
2321 This->getbuf_last = *frames = This->period_frames;
2323 if(devpos)
2324 *devpos = This->written_frames;
2325 if(qpcpos){ /* fixme: qpc of recording time */
2326 LARGE_INTEGER stamp, freq;
2327 QueryPerformanceCounter(&stamp);
2328 QueryPerformanceFrequency(&freq);
2329 *qpcpos = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
2332 OSSpinLockUnlock(&This->lock);
2334 return S_OK;
2337 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
2338 IAudioCaptureClient *iface, UINT32 done)
2340 ACImpl *This = impl_from_IAudioCaptureClient(iface);
2342 TRACE("(%p)->(%u)\n", This, done);
2344 OSSpinLockLock(&This->lock);
2346 if(!done){
2347 This->getbuf_last = 0;
2348 OSSpinLockUnlock(&This->lock);
2349 return S_OK;
2352 if(!This->getbuf_last){
2353 OSSpinLockUnlock(&This->lock);
2354 return AUDCLNT_E_OUT_OF_ORDER;
2357 if(This->getbuf_last != done){
2358 OSSpinLockUnlock(&This->lock);
2359 return AUDCLNT_E_INVALID_SIZE;
2362 This->written_frames += done;
2363 This->held_frames -= done;
2364 This->lcl_offs_frames += done;
2365 This->lcl_offs_frames %= This->bufsize_frames;
2366 This->getbuf_last = 0;
2368 OSSpinLockUnlock(&This->lock);
2370 return S_OK;
2373 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
2374 IAudioCaptureClient *iface, UINT32 *frames)
2376 ACImpl *This = impl_from_IAudioCaptureClient(iface);
2378 TRACE("(%p)->(%p)\n", This, frames);
2380 if(!frames)
2381 return E_POINTER;
2383 OSSpinLockLock(&This->lock);
2385 capture_resample(This);
2387 if(This->held_frames >= This->period_frames)
2388 *frames = This->period_frames;
2389 else
2390 *frames = 0;
2392 OSSpinLockUnlock(&This->lock);
2394 return S_OK;
2397 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
2399 AudioCaptureClient_QueryInterface,
2400 AudioCaptureClient_AddRef,
2401 AudioCaptureClient_Release,
2402 AudioCaptureClient_GetBuffer,
2403 AudioCaptureClient_ReleaseBuffer,
2404 AudioCaptureClient_GetNextPacketSize
2407 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
2408 REFIID riid, void **ppv)
2410 ACImpl *This = impl_from_IAudioClock(iface);
2412 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2414 if(!ppv)
2415 return E_POINTER;
2416 *ppv = NULL;
2418 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
2419 *ppv = iface;
2420 else if(IsEqualIID(riid, &IID_IAudioClock2))
2421 *ppv = &This->IAudioClock2_iface;
2422 if(*ppv){
2423 IUnknown_AddRef((IUnknown*)*ppv);
2424 return S_OK;
2427 WARN("Unknown interface %s\n", debugstr_guid(riid));
2428 return E_NOINTERFACE;
2431 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
2433 ACImpl *This = impl_from_IAudioClock(iface);
2434 return IAudioClient_AddRef(&This->IAudioClient_iface);
2437 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
2439 ACImpl *This = impl_from_IAudioClock(iface);
2440 return IAudioClient_Release(&This->IAudioClient_iface);
2443 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
2445 ACImpl *This = impl_from_IAudioClock(iface);
2447 TRACE("(%p)->(%p)\n", This, freq);
2449 if(This->share == AUDCLNT_SHAREMODE_SHARED)
2450 *freq = (UINT64)This->fmt->nSamplesPerSec * This->fmt->nBlockAlign;
2451 else
2452 *freq = This->fmt->nSamplesPerSec;
2454 return S_OK;
2457 static HRESULT AudioClock_GetPosition_nolock(ACImpl *This,
2458 UINT64 *pos, UINT64 *qpctime)
2460 *pos = This->written_frames - This->held_frames;
2462 if(This->share == AUDCLNT_SHAREMODE_SHARED)
2463 *pos *= This->fmt->nBlockAlign;
2465 if(qpctime){
2466 LARGE_INTEGER stamp, freq;
2467 QueryPerformanceCounter(&stamp);
2468 QueryPerformanceFrequency(&freq);
2469 *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
2472 return S_OK;
2475 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
2476 UINT64 *qpctime)
2478 ACImpl *This = impl_from_IAudioClock(iface);
2479 HRESULT hr;
2481 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
2483 if(!pos)
2484 return E_POINTER;
2486 OSSpinLockLock(&This->lock);
2488 hr = AudioClock_GetPosition_nolock(This, pos, qpctime);
2490 OSSpinLockUnlock(&This->lock);
2492 return hr;
2495 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
2496 DWORD *chars)
2498 ACImpl *This = impl_from_IAudioClock(iface);
2500 TRACE("(%p)->(%p)\n", This, chars);
2502 if(!chars)
2503 return E_POINTER;
2505 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
2507 return S_OK;
2510 static const IAudioClockVtbl AudioClock_Vtbl =
2512 AudioClock_QueryInterface,
2513 AudioClock_AddRef,
2514 AudioClock_Release,
2515 AudioClock_GetFrequency,
2516 AudioClock_GetPosition,
2517 AudioClock_GetCharacteristics
2520 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
2521 REFIID riid, void **ppv)
2523 ACImpl *This = impl_from_IAudioClock2(iface);
2524 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
2527 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
2529 ACImpl *This = impl_from_IAudioClock2(iface);
2530 return IAudioClient_AddRef(&This->IAudioClient_iface);
2533 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
2535 ACImpl *This = impl_from_IAudioClock2(iface);
2536 return IAudioClient_Release(&This->IAudioClient_iface);
2539 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
2540 UINT64 *pos, UINT64 *qpctime)
2542 ACImpl *This = impl_from_IAudioClock2(iface);
2544 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
2546 return E_NOTIMPL;
2549 static const IAudioClock2Vtbl AudioClock2_Vtbl =
2551 AudioClock2_QueryInterface,
2552 AudioClock2_AddRef,
2553 AudioClock2_Release,
2554 AudioClock2_GetDevicePosition
2557 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
2559 AudioSessionWrapper *ret;
2561 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2562 sizeof(AudioSessionWrapper));
2563 if(!ret)
2564 return NULL;
2566 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
2567 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
2568 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
2570 ret->ref = 1;
2572 ret->client = client;
2573 if(client){
2574 ret->session = client->session;
2575 AudioClient_AddRef(&client->IAudioClient_iface);
2578 return ret;
2581 static HRESULT WINAPI AudioSessionControl_QueryInterface(
2582 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
2584 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2586 if(!ppv)
2587 return E_POINTER;
2588 *ppv = NULL;
2590 if(IsEqualIID(riid, &IID_IUnknown) ||
2591 IsEqualIID(riid, &IID_IAudioSessionControl) ||
2592 IsEqualIID(riid, &IID_IAudioSessionControl2))
2593 *ppv = iface;
2594 if(*ppv){
2595 IUnknown_AddRef((IUnknown*)*ppv);
2596 return S_OK;
2599 WARN("Unknown interface %s\n", debugstr_guid(riid));
2600 return E_NOINTERFACE;
2603 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
2605 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2606 ULONG ref;
2607 ref = InterlockedIncrement(&This->ref);
2608 TRACE("(%p) Refcount now %u\n", This, ref);
2609 return ref;
2612 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
2614 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2615 ULONG ref;
2616 ref = InterlockedDecrement(&This->ref);
2617 TRACE("(%p) Refcount now %u\n", This, ref);
2618 if(!ref){
2619 if(This->client){
2620 OSSpinLockLock(&This->client->lock);
2621 This->client->session_wrapper = NULL;
2622 OSSpinLockUnlock(&This->client->lock);
2623 AudioClient_Release(&This->client->IAudioClient_iface);
2625 HeapFree(GetProcessHeap(), 0, This);
2627 return ref;
2630 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
2631 AudioSessionState *state)
2633 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2634 ACImpl *client;
2636 TRACE("(%p)->(%p)\n", This, state);
2638 if(!state)
2639 return NULL_PTR_ERR;
2641 EnterCriticalSection(&g_sessions_lock);
2643 if(list_empty(&This->session->clients)){
2644 *state = AudioSessionStateExpired;
2645 LeaveCriticalSection(&g_sessions_lock);
2646 return S_OK;
2649 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
2650 OSSpinLockLock(&client->lock);
2651 if(client->playing){
2652 *state = AudioSessionStateActive;
2653 OSSpinLockUnlock(&client->lock);
2654 LeaveCriticalSection(&g_sessions_lock);
2655 return S_OK;
2657 OSSpinLockUnlock(&client->lock);
2660 LeaveCriticalSection(&g_sessions_lock);
2662 *state = AudioSessionStateInactive;
2664 return S_OK;
2667 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
2668 IAudioSessionControl2 *iface, WCHAR **name)
2670 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2672 FIXME("(%p)->(%p) - stub\n", This, name);
2674 return E_NOTIMPL;
2677 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
2678 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
2680 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2682 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
2684 return E_NOTIMPL;
2687 static HRESULT WINAPI AudioSessionControl_GetIconPath(
2688 IAudioSessionControl2 *iface, WCHAR **path)
2690 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2692 FIXME("(%p)->(%p) - stub\n", This, path);
2694 return E_NOTIMPL;
2697 static HRESULT WINAPI AudioSessionControl_SetIconPath(
2698 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
2700 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2702 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
2704 return E_NOTIMPL;
2707 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
2708 IAudioSessionControl2 *iface, GUID *group)
2710 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2712 FIXME("(%p)->(%p) - stub\n", This, group);
2714 return E_NOTIMPL;
2717 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
2718 IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
2720 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2722 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
2723 debugstr_guid(session));
2725 return E_NOTIMPL;
2728 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
2729 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2731 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2733 FIXME("(%p)->(%p) - stub\n", This, events);
2735 return S_OK;
2738 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
2739 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2741 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2743 FIXME("(%p)->(%p) - stub\n", This, events);
2745 return S_OK;
2748 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
2749 IAudioSessionControl2 *iface, WCHAR **id)
2751 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2753 FIXME("(%p)->(%p) - stub\n", This, id);
2755 return E_NOTIMPL;
2758 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
2759 IAudioSessionControl2 *iface, WCHAR **id)
2761 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2763 FIXME("(%p)->(%p) - stub\n", This, id);
2765 return E_NOTIMPL;
2768 static HRESULT WINAPI AudioSessionControl_GetProcessId(
2769 IAudioSessionControl2 *iface, DWORD *pid)
2771 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2773 TRACE("(%p)->(%p)\n", This, pid);
2775 if(!pid)
2776 return E_POINTER;
2778 *pid = GetCurrentProcessId();
2780 return S_OK;
2783 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
2784 IAudioSessionControl2 *iface)
2786 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2788 TRACE("(%p)\n", This);
2790 return S_FALSE;
2793 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
2794 IAudioSessionControl2 *iface, BOOL optout)
2796 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2798 TRACE("(%p)->(%d)\n", This, optout);
2800 return S_OK;
2803 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
2805 AudioSessionControl_QueryInterface,
2806 AudioSessionControl_AddRef,
2807 AudioSessionControl_Release,
2808 AudioSessionControl_GetState,
2809 AudioSessionControl_GetDisplayName,
2810 AudioSessionControl_SetDisplayName,
2811 AudioSessionControl_GetIconPath,
2812 AudioSessionControl_SetIconPath,
2813 AudioSessionControl_GetGroupingParam,
2814 AudioSessionControl_SetGroupingParam,
2815 AudioSessionControl_RegisterAudioSessionNotification,
2816 AudioSessionControl_UnregisterAudioSessionNotification,
2817 AudioSessionControl_GetSessionIdentifier,
2818 AudioSessionControl_GetSessionInstanceIdentifier,
2819 AudioSessionControl_GetProcessId,
2820 AudioSessionControl_IsSystemSoundsSession,
2821 AudioSessionControl_SetDuckingPreference
2824 /* index == -1 means set all channels, otherwise sets only the given channel */
2825 static HRESULT ca_setvol(ACImpl *This, UINT32 index)
2827 Float32 level;
2828 OSStatus sc;
2830 if(This->session->mute)
2831 level = 0.;
2832 else{
2833 if(index == (UINT32)-1){
2834 UINT32 i;
2835 level = 1.;
2836 for(i = 0; i < This->fmt->nChannels; ++i){
2837 Float32 tmp;
2838 tmp = This->session->master_vol *
2839 This->session->channel_vols[i] * This->vols[i];
2840 level = tmp < level ? tmp : level;
2842 }else
2843 level = This->session->master_vol *
2844 This->session->channel_vols[index] * This->vols[index];
2847 sc = AudioUnitSetParameter(This->unit, kHALOutputParam_Volume,
2848 kAudioUnitScope_Global, 0, level, 0);
2849 if(sc != noErr)
2850 WARN("Couldn't set volume: %lx\n", sc);
2852 return S_OK;
2855 static HRESULT ca_session_setvol(AudioSession *session, UINT32 index)
2857 HRESULT ret = S_OK;
2858 ACImpl *client;
2860 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry){
2861 HRESULT hr;
2862 hr = ca_setvol(client, index);
2863 if(FAILED(hr))
2864 ret = hr;
2867 return ret;
2870 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
2871 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
2873 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2875 if(!ppv)
2876 return E_POINTER;
2877 *ppv = NULL;
2879 if(IsEqualIID(riid, &IID_IUnknown) ||
2880 IsEqualIID(riid, &IID_ISimpleAudioVolume))
2881 *ppv = iface;
2882 if(*ppv){
2883 IUnknown_AddRef((IUnknown*)*ppv);
2884 return S_OK;
2887 WARN("Unknown interface %s\n", debugstr_guid(riid));
2888 return E_NOINTERFACE;
2891 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
2893 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2894 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2897 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
2899 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2900 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2903 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
2904 ISimpleAudioVolume *iface, float level, const GUID *context)
2906 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2907 AudioSession *session = This->session;
2908 HRESULT ret;
2910 TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
2912 if(level < 0.f || level > 1.f)
2913 return E_INVALIDARG;
2915 if(context)
2916 FIXME("Notifications not supported yet\n");
2918 EnterCriticalSection(&session->lock);
2920 session->master_vol = level;
2922 ret = ca_session_setvol(session, -1);
2924 LeaveCriticalSection(&session->lock);
2926 return ret;
2929 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
2930 ISimpleAudioVolume *iface, float *level)
2932 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2933 AudioSession *session = This->session;
2935 TRACE("(%p)->(%p)\n", session, level);
2937 if(!level)
2938 return NULL_PTR_ERR;
2940 *level = session->master_vol;
2942 return S_OK;
2945 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
2946 BOOL mute, const GUID *context)
2948 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2949 AudioSession *session = This->session;
2951 TRACE("(%p)->(%u, %p)\n", session, mute, context);
2953 if(context)
2954 FIXME("Notifications not supported yet\n");
2956 EnterCriticalSection(&session->lock);
2958 session->mute = mute;
2960 ca_session_setvol(session, -1);
2962 LeaveCriticalSection(&session->lock);
2964 return S_OK;
2967 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
2968 BOOL *mute)
2970 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2971 AudioSession *session = This->session;
2973 TRACE("(%p)->(%p)\n", session, mute);
2975 if(!mute)
2976 return NULL_PTR_ERR;
2978 *mute = session->mute;
2980 return S_OK;
2983 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
2985 SimpleAudioVolume_QueryInterface,
2986 SimpleAudioVolume_AddRef,
2987 SimpleAudioVolume_Release,
2988 SimpleAudioVolume_SetMasterVolume,
2989 SimpleAudioVolume_GetMasterVolume,
2990 SimpleAudioVolume_SetMute,
2991 SimpleAudioVolume_GetMute
2994 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
2995 IAudioStreamVolume *iface, REFIID riid, void **ppv)
2997 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2999 if(!ppv)
3000 return E_POINTER;
3001 *ppv = NULL;
3003 if(IsEqualIID(riid, &IID_IUnknown) ||
3004 IsEqualIID(riid, &IID_IAudioStreamVolume))
3005 *ppv = iface;
3006 if(*ppv){
3007 IUnknown_AddRef((IUnknown*)*ppv);
3008 return S_OK;
3011 WARN("Unknown interface %s\n", debugstr_guid(riid));
3012 return E_NOINTERFACE;
3015 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
3017 ACImpl *This = impl_from_IAudioStreamVolume(iface);
3018 return IAudioClient_AddRef(&This->IAudioClient_iface);
3021 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
3023 ACImpl *This = impl_from_IAudioStreamVolume(iface);
3024 return IAudioClient_Release(&This->IAudioClient_iface);
3027 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
3028 IAudioStreamVolume *iface, UINT32 *out)
3030 ACImpl *This = impl_from_IAudioStreamVolume(iface);
3032 TRACE("(%p)->(%p)\n", This, out);
3034 if(!out)
3035 return E_POINTER;
3037 *out = This->fmt->nChannels;
3039 return S_OK;
3042 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
3043 IAudioStreamVolume *iface, UINT32 index, float level)
3045 ACImpl *This = impl_from_IAudioStreamVolume(iface);
3046 HRESULT ret;
3048 TRACE("(%p)->(%d, %f)\n", This, index, level);
3050 if(level < 0.f || level > 1.f)
3051 return E_INVALIDARG;
3053 if(index >= This->fmt->nChannels)
3054 return E_INVALIDARG;
3056 OSSpinLockLock(&This->lock);
3058 This->vols[index] = level;
3060 WARN("CoreAudio doesn't support per-channel volume control\n");
3061 ret = ca_setvol(This, index);
3063 OSSpinLockUnlock(&This->lock);
3065 return ret;
3068 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
3069 IAudioStreamVolume *iface, UINT32 index, float *level)
3071 ACImpl *This = impl_from_IAudioStreamVolume(iface);
3073 TRACE("(%p)->(%d, %p)\n", This, index, level);
3075 if(!level)
3076 return E_POINTER;
3078 if(index >= This->fmt->nChannels)
3079 return E_INVALIDARG;
3081 *level = This->vols[index];
3083 return S_OK;
3086 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
3087 IAudioStreamVolume *iface, UINT32 count, const float *levels)
3089 ACImpl *This = impl_from_IAudioStreamVolume(iface);
3090 int i;
3091 HRESULT ret;
3093 TRACE("(%p)->(%d, %p)\n", This, count, levels);
3095 if(!levels)
3096 return E_POINTER;
3098 if(count != This->fmt->nChannels)
3099 return E_INVALIDARG;
3101 OSSpinLockLock(&This->lock);
3103 for(i = 0; i < count; ++i)
3104 This->vols[i] = levels[i];
3106 ret = ca_setvol(This, -1);
3108 OSSpinLockUnlock(&This->lock);
3110 return ret;
3113 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
3114 IAudioStreamVolume *iface, UINT32 count, float *levels)
3116 ACImpl *This = impl_from_IAudioStreamVolume(iface);
3117 int i;
3119 TRACE("(%p)->(%d, %p)\n", This, count, levels);
3121 if(!levels)
3122 return E_POINTER;
3124 if(count != This->fmt->nChannels)
3125 return E_INVALIDARG;
3127 OSSpinLockLock(&This->lock);
3129 for(i = 0; i < count; ++i)
3130 levels[i] = This->vols[i];
3132 OSSpinLockUnlock(&This->lock);
3134 return S_OK;
3137 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
3139 AudioStreamVolume_QueryInterface,
3140 AudioStreamVolume_AddRef,
3141 AudioStreamVolume_Release,
3142 AudioStreamVolume_GetChannelCount,
3143 AudioStreamVolume_SetChannelVolume,
3144 AudioStreamVolume_GetChannelVolume,
3145 AudioStreamVolume_SetAllVolumes,
3146 AudioStreamVolume_GetAllVolumes
3149 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
3150 IChannelAudioVolume *iface, REFIID riid, void **ppv)
3152 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
3154 if(!ppv)
3155 return E_POINTER;
3156 *ppv = NULL;
3158 if(IsEqualIID(riid, &IID_IUnknown) ||
3159 IsEqualIID(riid, &IID_IChannelAudioVolume))
3160 *ppv = iface;
3161 if(*ppv){
3162 IUnknown_AddRef((IUnknown*)*ppv);
3163 return S_OK;
3166 WARN("Unknown interface %s\n", debugstr_guid(riid));
3167 return E_NOINTERFACE;
3170 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
3172 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
3173 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
3176 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
3178 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
3179 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
3182 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
3183 IChannelAudioVolume *iface, UINT32 *out)
3185 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
3186 AudioSession *session = This->session;
3188 TRACE("(%p)->(%p)\n", session, out);
3190 if(!out)
3191 return NULL_PTR_ERR;
3193 *out = session->channel_count;
3195 return S_OK;
3198 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
3199 IChannelAudioVolume *iface, UINT32 index, float level,
3200 const GUID *context)
3202 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
3203 AudioSession *session = This->session;
3204 HRESULT ret;
3206 TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
3207 wine_dbgstr_guid(context));
3209 if(level < 0.f || level > 1.f)
3210 return E_INVALIDARG;
3212 if(index >= session->channel_count)
3213 return E_INVALIDARG;
3215 if(context)
3216 FIXME("Notifications not supported yet\n");
3218 EnterCriticalSection(&session->lock);
3220 session->channel_vols[index] = level;
3222 WARN("CoreAudio doesn't support per-channel volume control\n");
3223 ret = ca_session_setvol(session, index);
3225 LeaveCriticalSection(&session->lock);
3227 return ret;
3230 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
3231 IChannelAudioVolume *iface, UINT32 index, float *level)
3233 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
3234 AudioSession *session = This->session;
3236 TRACE("(%p)->(%d, %p)\n", session, index, level);
3238 if(!level)
3239 return NULL_PTR_ERR;
3241 if(index >= session->channel_count)
3242 return E_INVALIDARG;
3244 *level = session->channel_vols[index];
3246 return S_OK;
3249 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
3250 IChannelAudioVolume *iface, UINT32 count, const float *levels,
3251 const GUID *context)
3253 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
3254 AudioSession *session = This->session;
3255 int i;
3256 HRESULT ret;
3258 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
3259 wine_dbgstr_guid(context));
3261 if(!levels)
3262 return NULL_PTR_ERR;
3264 if(count != session->channel_count)
3265 return E_INVALIDARG;
3267 if(context)
3268 FIXME("Notifications not supported yet\n");
3270 EnterCriticalSection(&session->lock);
3272 for(i = 0; i < count; ++i)
3273 session->channel_vols[i] = levels[i];
3275 ret = ca_session_setvol(session, -1);
3277 LeaveCriticalSection(&session->lock);
3279 return ret;
3282 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
3283 IChannelAudioVolume *iface, UINT32 count, float *levels)
3285 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
3286 AudioSession *session = This->session;
3287 int i;
3289 TRACE("(%p)->(%d, %p)\n", session, count, levels);
3291 if(!levels)
3292 return NULL_PTR_ERR;
3294 if(count != session->channel_count)
3295 return E_INVALIDARG;
3297 for(i = 0; i < count; ++i)
3298 levels[i] = session->channel_vols[i];
3300 return S_OK;
3303 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
3305 ChannelAudioVolume_QueryInterface,
3306 ChannelAudioVolume_AddRef,
3307 ChannelAudioVolume_Release,
3308 ChannelAudioVolume_GetChannelCount,
3309 ChannelAudioVolume_SetChannelVolume,
3310 ChannelAudioVolume_GetChannelVolume,
3311 ChannelAudioVolume_SetAllVolumes,
3312 ChannelAudioVolume_GetAllVolumes
3315 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
3316 REFIID riid, void **ppv)
3318 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
3320 if(!ppv)
3321 return E_POINTER;
3322 *ppv = NULL;
3324 if(IsEqualIID(riid, &IID_IUnknown) ||
3325 IsEqualIID(riid, &IID_IAudioSessionManager) ||
3326 IsEqualIID(riid, &IID_IAudioSessionManager2))
3327 *ppv = iface;
3328 if(*ppv){
3329 IUnknown_AddRef((IUnknown*)*ppv);
3330 return S_OK;
3333 WARN("Unknown interface %s\n", debugstr_guid(riid));
3334 return E_NOINTERFACE;
3337 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
3339 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3340 ULONG ref;
3341 ref = InterlockedIncrement(&This->ref);
3342 TRACE("(%p) Refcount now %u\n", This, ref);
3343 return ref;
3346 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
3348 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3349 ULONG ref;
3350 ref = InterlockedDecrement(&This->ref);
3351 TRACE("(%p) Refcount now %u\n", This, ref);
3352 if(!ref)
3353 HeapFree(GetProcessHeap(), 0, This);
3354 return ref;
3357 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
3358 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
3359 IAudioSessionControl **out)
3361 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3362 AudioSession *session;
3363 AudioSessionWrapper *wrapper;
3364 HRESULT hr;
3366 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
3367 flags, out);
3369 hr = get_audio_session(session_guid, This->device, 0, &session);
3370 if(FAILED(hr))
3371 return hr;
3373 wrapper = AudioSessionWrapper_Create(NULL);
3374 if(!wrapper)
3375 return E_OUTOFMEMORY;
3377 wrapper->session = session;
3379 *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
3381 return S_OK;
3384 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
3385 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
3386 ISimpleAudioVolume **out)
3388 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3389 AudioSession *session;
3390 AudioSessionWrapper *wrapper;
3391 HRESULT hr;
3393 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
3394 flags, out);
3396 hr = get_audio_session(session_guid, This->device, 0, &session);
3397 if(FAILED(hr))
3398 return hr;
3400 wrapper = AudioSessionWrapper_Create(NULL);
3401 if(!wrapper)
3402 return E_OUTOFMEMORY;
3404 wrapper->session = session;
3406 *out = &wrapper->ISimpleAudioVolume_iface;
3408 return S_OK;
3411 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
3412 IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
3414 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3415 FIXME("(%p)->(%p) - stub\n", This, out);
3416 return E_NOTIMPL;
3419 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
3420 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
3422 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3423 FIXME("(%p)->(%p) - stub\n", This, notification);
3424 return E_NOTIMPL;
3427 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
3428 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
3430 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3431 FIXME("(%p)->(%p) - stub\n", This, notification);
3432 return E_NOTIMPL;
3435 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
3436 IAudioSessionManager2 *iface, const WCHAR *session_id,
3437 IAudioVolumeDuckNotification *notification)
3439 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3440 FIXME("(%p)->(%p) - stub\n", This, notification);
3441 return E_NOTIMPL;
3444 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
3445 IAudioSessionManager2 *iface,
3446 IAudioVolumeDuckNotification *notification)
3448 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3449 FIXME("(%p)->(%p) - stub\n", This, notification);
3450 return E_NOTIMPL;
3453 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
3455 AudioSessionManager_QueryInterface,
3456 AudioSessionManager_AddRef,
3457 AudioSessionManager_Release,
3458 AudioSessionManager_GetAudioSessionControl,
3459 AudioSessionManager_GetSimpleAudioVolume,
3460 AudioSessionManager_GetSessionEnumerator,
3461 AudioSessionManager_RegisterSessionNotification,
3462 AudioSessionManager_UnregisterSessionNotification,
3463 AudioSessionManager_RegisterDuckNotification,
3464 AudioSessionManager_UnregisterDuckNotification
3467 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
3468 IAudioSessionManager2 **out)
3470 SessionMgr *This;
3472 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
3473 if(!This)
3474 return E_OUTOFMEMORY;
3476 This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
3477 This->device = device;
3478 This->ref = 1;
3480 *out = &This->IAudioSessionManager2_iface;
3482 return S_OK;