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
29 #include "wine/debug.h"
30 #include "wine/unicode.h"
31 #include "wine/list.h"
34 #include "mmdeviceapi.h"
38 #include "endpointvolume.h"
41 #include "audioclient.h"
42 #include "audiopolicy.h"
49 #include <sys/types.h>
51 #include <sys/ioctl.h>
55 #include <libkern/OSAtomic.h>
56 #include <CoreAudio/CoreAudio.h>
57 #include <AudioToolbox/AudioQueue.h>
59 WINE_DEFAULT_DEBUG_CHANNEL(coreaudio);
61 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
63 #define CAPTURE_BUFFERS 5
65 static const REFERENCE_TIME DefaultPeriod = 200000;
66 static const REFERENCE_TIME MinimumPeriod = 100000;
68 typedef struct _AQBuffer {
69 AudioQueueBufferRef buf;
74 typedef struct ACImpl ACImpl;
76 typedef struct _AudioSession {
87 CRITICAL_SECTION lock;
92 typedef struct _AudioSessionWrapper {
93 IAudioSessionControl2 IAudioSessionControl2_iface;
94 IChannelAudioVolume IChannelAudioVolume_iface;
95 ISimpleAudioVolume ISimpleAudioVolume_iface;
100 AudioSession *session;
101 } AudioSessionWrapper;
104 IAudioClient IAudioClient_iface;
105 IAudioRenderClient IAudioRenderClient_iface;
106 IAudioCaptureClient IAudioCaptureClient_iface;
107 IAudioClock IAudioClock_iface;
108 IAudioClock2 IAudioClock2_iface;
109 IAudioStreamVolume IAudioStreamVolume_iface;
119 AUDCLNT_SHAREMODE share;
123 AudioDeviceID adevid;
124 AudioQueueRef aqueue;
125 AudioObjectPropertyScope scope;
127 UINT32 period_ms, bufsize_frames, inbuf_frames;
128 UINT64 last_time, written_frames;
129 AudioQueueBufferRef public_buffer;
133 AudioSession *session;
134 AudioSessionWrapper *session_wrapper;
138 struct list avail_buffers;
140 /* We can't use debug printing or {Enter,Leave}CriticalSection from
141 * OSX callback threads, so we use OSX's OSSpinLock for synchronization
142 * instead. OSSpinLock is not a recursive lock, so don't call
143 * synchronized functions while holding the lock. */
153 static const IAudioClientVtbl AudioClient_Vtbl;
154 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
155 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
156 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
157 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
158 static const IAudioClockVtbl AudioClock_Vtbl;
159 static const IAudioClock2Vtbl AudioClock2_Vtbl;
160 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
161 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
162 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl;
164 typedef struct _SessionMgr {
165 IAudioSessionManager2 IAudioSessionManager2_iface;
172 static HANDLE g_timer_q;
174 static CRITICAL_SECTION g_sessions_lock;
175 static struct list g_sessions = LIST_INIT(g_sessions);
177 static HRESULT AudioClock_GetPosition_nolock(ACImpl *This, UINT64 *pos,
178 UINT64 *qpctime, BOOL raw);
179 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
180 static HRESULT ca_setvol(ACImpl *This, UINT32 index);
182 static inline ACImpl *impl_from_IAudioClient(IAudioClient *iface)
184 return CONTAINING_RECORD(iface, ACImpl, IAudioClient_iface);
187 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
189 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
192 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
194 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
197 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
199 return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
202 static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
204 return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
207 static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
209 return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
212 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
214 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
217 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
219 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
222 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
224 return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
227 static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface)
229 return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface);
232 BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
234 if(reason == DLL_PROCESS_ATTACH){
235 g_timer_q = CreateTimerQueue();
239 InitializeCriticalSection(&g_sessions_lock);
245 /* From <dlls/mmdevapi/mmdevapi.h> */
246 enum DriverPriority {
247 Priority_Unavailable = 0,
253 int WINAPI AUDDRV_GetPriority(void)
255 return Priority_Neutral;
258 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids,
259 AudioDeviceID ***keys, UINT *num, UINT *def_index)
261 UInt32 devsize, size;
262 AudioDeviceID *devices;
263 AudioDeviceID default_id;
264 AudioObjectPropertyAddress addr;
268 TRACE("%d %p %p %p\n", flow, ids, num, def_index);
270 addr.mScope = kAudioObjectPropertyScopeGlobal;
271 addr.mElement = kAudioObjectPropertyElementMaster;
273 addr.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
274 else if(flow == eCapture)
275 addr.mSelector = kAudioHardwarePropertyDefaultInputDevice;
279 size = sizeof(default_id);
280 sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0,
281 NULL, &size, &default_id);
283 WARN("Getting _DefaultInputDevice property failed: %lx\n", sc);
287 addr.mSelector = kAudioHardwarePropertyDevices;
288 sc = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &addr, 0,
291 WARN("Getting _Devices property size failed: %lx\n", sc);
295 devices = HeapAlloc(GetProcessHeap(), 0, devsize);
297 return E_OUTOFMEMORY;
299 sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0, NULL,
302 WARN("Getting _Devices property failed: %lx\n", sc);
303 HeapFree(GetProcessHeap(), 0, devices);
307 ndevices = devsize / sizeof(AudioDeviceID);
309 *ids = HeapAlloc(GetProcessHeap(), 0, ndevices * sizeof(WCHAR *));
311 HeapFree(GetProcessHeap(), 0, devices);
312 return E_OUTOFMEMORY;
315 *keys = HeapAlloc(GetProcessHeap(), 0, ndevices * sizeof(AudioDeviceID *));
317 HeapFree(GetProcessHeap(), 0, *ids);
318 HeapFree(GetProcessHeap(), 0, devices);
319 return E_OUTOFMEMORY;
323 *def_index = (UINT)-1;
324 for(i = 0; i < ndevices; ++i){
325 AudioBufferList *buffers;
331 addr.mSelector = kAudioDevicePropertyStreamConfiguration;
333 addr.mScope = kAudioDevicePropertyScopeOutput;
335 addr.mScope = kAudioDevicePropertyScopeInput;
337 sc = AudioObjectGetPropertyDataSize(devices[i], &addr, 0, NULL, &size);
339 WARN("Unable to get _StreamConfiguration property size for "
340 "device %lu: %lx\n", devices[i], sc);
344 buffers = HeapAlloc(GetProcessHeap(), 0, size);
346 HeapFree(GetProcessHeap(), 0, devices);
347 for(j = 0; j < *num; ++j)
348 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
349 HeapFree(GetProcessHeap(), 0, *keys);
350 HeapFree(GetProcessHeap(), 0, *ids);
351 return E_OUTOFMEMORY;
354 sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL,
357 WARN("Unable to get _StreamConfiguration property for "
358 "device %lu: %lx\n", devices[i], sc);
359 HeapFree(GetProcessHeap(), 0, buffers);
363 /* check that there's at least one channel in this device before
364 * we claim it as usable */
365 for(j = 0; j < buffers->mNumberBuffers; ++j)
366 if(buffers->mBuffers[j].mNumberChannels > 0)
368 if(j >= buffers->mNumberBuffers){
369 HeapFree(GetProcessHeap(), 0, buffers);
373 HeapFree(GetProcessHeap(), 0, buffers);
376 addr.mSelector = kAudioObjectPropertyName;
377 sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL,
380 WARN("Unable to get _Name property for device %lu: %lx\n",
385 if(!CFStringGetCString(name, nameA, sizeof(nameA),
386 kCFStringEncodingUTF8)){
387 WARN("Error converting string to UTF8\n");
394 len = MultiByteToWideChar(CP_UNIXCP, 0, nameA, -1, NULL, 0);
395 (*ids)[*num] = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
397 HeapFree(GetProcessHeap(), 0, devices);
398 for(j = 0; j < *num; ++j){
399 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
400 HeapFree(GetProcessHeap(), 0, (*keys)[j]);
402 HeapFree(GetProcessHeap(), 0, *ids);
403 HeapFree(GetProcessHeap(), 0, *keys);
404 return E_OUTOFMEMORY;
406 MultiByteToWideChar(CP_UNIXCP, 0, nameA, -1, (*ids)[*num], len);
408 (*keys)[*num] = HeapAlloc(GetProcessHeap(), 0, sizeof(AudioDeviceID));
410 HeapFree(GetProcessHeap(), 0, devices);
411 HeapFree(GetProcessHeap(), 0, (*ids)[*num]);
412 for(j = 0; j < *num; ++j){
413 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
414 HeapFree(GetProcessHeap(), 0, (*keys)[j]);
416 HeapFree(GetProcessHeap(), 0, *ids);
417 HeapFree(GetProcessHeap(), 0, *keys);
418 return E_OUTOFMEMORY;
420 *(*keys)[*num] = devices[i];
422 if(*def_index == (UINT)-1 && devices[i] == default_id)
428 if(*def_index == (UINT)-1)
431 HeapFree(GetProcessHeap(), 0, devices);
436 HRESULT WINAPI AUDDRV_GetAudioEndpoint(AudioDeviceID *adevid, IMMDevice *dev,
437 EDataFlow dataflow, IAudioClient **out)
441 TRACE("%p %d %p\n", dev, dataflow, out);
443 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACImpl));
445 return E_OUTOFMEMORY;
447 This->IAudioClient_iface.lpVtbl = &AudioClient_Vtbl;
448 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
449 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
450 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
451 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
452 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
454 This->dataflow = dataflow;
456 if(dataflow == eRender)
457 This->scope = kAudioDevicePropertyScopeOutput;
458 else if(dataflow == eCapture)
459 This->scope = kAudioDevicePropertyScopeInput;
461 HeapFree(GetProcessHeap(), 0, This);
468 IMMDevice_AddRef(This->parent);
470 list_init(&This->avail_buffers);
472 This->adevid = *adevid;
474 *out = &This->IAudioClient_iface;
475 IAudioClient_AddRef(&This->IAudioClient_iface);
480 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient *iface,
481 REFIID riid, void **ppv)
483 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
488 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClient))
491 IUnknown_AddRef((IUnknown*)*ppv);
494 WARN("Unknown interface %s\n", debugstr_guid(riid));
495 return E_NOINTERFACE;
498 static ULONG WINAPI AudioClient_AddRef(IAudioClient *iface)
500 ACImpl *This = impl_from_IAudioClient(iface);
502 ref = InterlockedIncrement(&This->ref);
503 TRACE("(%p) Refcount now %u\n", This, ref);
507 static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
509 ACImpl *This = impl_from_IAudioClient(iface);
511 ref = InterlockedDecrement(&This->ref);
512 TRACE("(%p) Refcount now %u\n", This, ref);
514 IAudioClient_Stop(iface);
516 AudioQueueDispose(This->aqueue, 1);
518 EnterCriticalSection(&g_sessions_lock);
519 list_remove(&This->entry);
520 LeaveCriticalSection(&g_sessions_lock);
522 HeapFree(GetProcessHeap(), 0, This->vols);
523 HeapFree(GetProcessHeap(), 0, This->public_buffer);
524 CoTaskMemFree(This->fmt);
525 IMMDevice_Release(This->parent);
526 HeapFree(GetProcessHeap(), 0, This);
531 static void dump_fmt(const WAVEFORMATEX *fmt)
533 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
534 switch(fmt->wFormatTag){
535 case WAVE_FORMAT_PCM:
536 TRACE("WAVE_FORMAT_PCM");
538 case WAVE_FORMAT_IEEE_FLOAT:
539 TRACE("WAVE_FORMAT_IEEE_FLOAT");
541 case WAVE_FORMAT_EXTENSIBLE:
542 TRACE("WAVE_FORMAT_EXTENSIBLE");
550 TRACE("nChannels: %u\n", fmt->nChannels);
551 TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
552 TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
553 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
554 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
555 TRACE("cbSize: %u\n", fmt->cbSize);
557 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
558 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
559 TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
560 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
561 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
565 static DWORD get_channel_mask(unsigned int channels)
571 return KSAUDIO_SPEAKER_MONO;
573 return KSAUDIO_SPEAKER_STEREO;
575 return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY;
577 return KSAUDIO_SPEAKER_QUAD; /* not _SURROUND */
579 return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY;
581 return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */
583 return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER;
585 return KSAUDIO_SPEAKER_7POINT1; /* not 7POINT1_SURROUND */
587 FIXME("Unknown speaker configuration: %u\n", channels);
591 static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
596 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
597 size = sizeof(WAVEFORMATEXTENSIBLE);
599 size = sizeof(WAVEFORMATEX);
601 ret = CoTaskMemAlloc(size);
605 memcpy(ret, fmt, size);
607 ret->cbSize = size - sizeof(WAVEFORMATEX);
612 static HRESULT ca_get_audiodesc(AudioStreamBasicDescription *desc,
613 const WAVEFORMATEX *fmt)
615 const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)fmt;
617 desc->mFormatFlags = 0;
619 if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
620 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
621 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
622 desc->mFormatID = kAudioFormatLinearPCM;
623 if(fmt->wBitsPerSample > 8)
624 desc->mFormatFlags = kAudioFormatFlagIsSignedInteger;
625 }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
626 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
627 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
628 desc->mFormatID = kAudioFormatLinearPCM;
629 desc->mFormatFlags = kAudioFormatFlagIsFloat;
630 }else if(fmt->wFormatTag == WAVE_FORMAT_MULAW ||
631 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
632 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_MULAW))){
633 desc->mFormatID = kAudioFormatULaw;
634 }else if(fmt->wFormatTag == WAVE_FORMAT_ALAW ||
635 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
636 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_ALAW))){
637 desc->mFormatID = kAudioFormatALaw;
639 return AUDCLNT_E_UNSUPPORTED_FORMAT;
641 desc->mSampleRate = fmt->nSamplesPerSec;
642 desc->mBytesPerPacket = fmt->nBlockAlign;
643 desc->mFramesPerPacket = 1;
644 desc->mBytesPerFrame = fmt->nBlockAlign;
645 desc->mChannelsPerFrame = fmt->nChannels;
646 desc->mBitsPerChannel = fmt->wBitsPerSample;
652 static void ca_out_buffer_cb(void *user, AudioQueueRef aqueue,
653 AudioQueueBufferRef buffer)
656 AQBuffer *buf = buffer->mUserData;
658 OSSpinLockLock(&This->lock);
659 list_add_tail(&This->avail_buffers, &buf->entry);
660 This->inbuf_frames -= buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
661 OSSpinLockUnlock(&This->lock);
664 static void ca_in_buffer_cb(void *user, AudioQueueRef aqueue,
665 AudioQueueBufferRef buffer, const AudioTimeStamp *start,
666 UInt32 ndesc, const AudioStreamPacketDescription *descs)
669 AQBuffer *buf = buffer->mUserData;
671 OSSpinLockLock(&This->lock);
672 list_add_tail(&This->avail_buffers, &buf->entry);
673 This->inbuf_frames += buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
674 OSSpinLockUnlock(&This->lock);
677 static HRESULT ca_setup_aqueue(AudioDeviceID did, EDataFlow flow,
678 const WAVEFORMATEX *fmt, void *user, AudioQueueRef *aqueue)
680 AudioStreamBasicDescription desc;
681 AudioObjectPropertyAddress addr;
687 addr.mScope = kAudioObjectPropertyScopeGlobal;
689 addr.mSelector = kAudioDevicePropertyDeviceUID;
692 sc = AudioObjectGetPropertyData(did, &addr, 0, NULL, &size, &uid);
694 WARN("Unable to get _DeviceUID property: %lx\n", sc);
698 hr = ca_get_audiodesc(&desc, fmt);
705 sc = AudioQueueNewOutput(&desc, ca_out_buffer_cb, user, NULL, NULL, 0,
707 else if(flow == eCapture)
708 sc = AudioQueueNewInput(&desc, ca_in_buffer_cb, user, NULL, NULL, 0,
715 WARN("Unable to create AudioQueue: %lx\n", sc);
720 sc = AudioQueueSetProperty(*aqueue, kAudioQueueProperty_CurrentDevice,
732 static void session_init_vols(AudioSession *session, UINT channels)
734 if(session->channel_count < channels){
737 if(session->channel_vols)
738 session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
739 session->channel_vols, sizeof(float) * channels);
741 session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
742 sizeof(float) * channels);
743 if(!session->channel_vols)
746 for(i = session->channel_count; i < channels; ++i)
747 session->channel_vols[i] = 1.f;
749 session->channel_count = channels;
753 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
758 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
762 memcpy(&ret->guid, guid, sizeof(GUID));
764 ret->device = device;
766 list_init(&ret->clients);
768 list_add_head(&g_sessions, &ret->entry);
770 InitializeCriticalSection(&ret->lock);
772 session_init_vols(ret, num_channels);
774 ret->master_vol = 1.f;
779 /* if channels == 0, then this will return or create a session with
780 * matching dataflow and GUID. otherwise, channels must also match */
781 static HRESULT get_audio_session(const GUID *sessionguid,
782 IMMDevice *device, UINT channels, AudioSession **out)
784 AudioSession *session;
786 if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
787 *out = create_session(&GUID_NULL, device, channels);
789 return E_OUTOFMEMORY;
795 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
796 if(session->device == device &&
797 IsEqualGUID(sessionguid, &session->guid)){
798 session_init_vols(session, channels);
805 *out = create_session(sessionguid, device, channels);
807 return E_OUTOFMEMORY;
813 static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
814 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
815 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
816 const GUID *sessionguid)
818 ACImpl *This = impl_from_IAudioClient(iface);
823 TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
824 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
831 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
832 return AUDCLNT_E_NOT_INITIALIZED;
834 if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
835 AUDCLNT_STREAMFLAGS_LOOPBACK |
836 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
837 AUDCLNT_STREAMFLAGS_NOPERSIST |
838 AUDCLNT_STREAMFLAGS_RATEADJUST |
839 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
840 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
841 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED)){
842 TRACE("Unknown flags: %08x\n", flags);
846 OSSpinLockLock(&This->lock);
849 OSSpinLockUnlock(&This->lock);
850 return AUDCLNT_E_ALREADY_INITIALIZED;
853 hr = ca_setup_aqueue(This->adevid, This->dataflow, fmt, This, &This->aqueue);
855 OSSpinLockUnlock(&This->lock);
859 This->fmt = clone_format(fmt);
861 AudioQueueDispose(This->aqueue, 1);
863 OSSpinLockUnlock(&This->lock);
864 return E_OUTOFMEMORY;
868 This->period_ms = period / 10000;
869 if(This->period_ms == 0)
872 This->period_ms = MinimumPeriod / 10000;
875 duration = 300000; /* 0.03s */
876 This->bufsize_frames = ceil(fmt->nSamplesPerSec * (duration / 10000000.));
878 if(This->dataflow == eCapture){
880 UInt32 bsize = ceil((This->bufsize_frames / (double)CAPTURE_BUFFERS) *
881 This->fmt->nBlockAlign);
882 for(i = 0; i < CAPTURE_BUFFERS; ++i){
885 buf = HeapAlloc(GetProcessHeap(), 0, sizeof(AQBuffer));
887 AudioQueueDispose(This->aqueue, 1);
889 CoTaskMemFree(This->fmt);
891 OSSpinLockUnlock(&This->lock);
892 return E_OUTOFMEMORY;
895 sc = AudioQueueAllocateBuffer(This->aqueue, bsize, &buf->buf);
897 AudioQueueDispose(This->aqueue, 1);
899 CoTaskMemFree(This->fmt);
901 OSSpinLockUnlock(&This->lock);
902 WARN("Couldn't allocate buffer: %lx\n", sc);
906 buf->buf->mUserData = buf;
908 sc = AudioQueueEnqueueBuffer(This->aqueue, buf->buf, 0, NULL);
910 ERR("Couldn't enqueue buffer: %lx\n", sc);
916 This->vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float));
918 AudioQueueDispose(This->aqueue, 1);
920 CoTaskMemFree(This->fmt);
922 OSSpinLockUnlock(&This->lock);
923 return E_OUTOFMEMORY;
926 for(i = 0; i < fmt->nChannels; ++i)
932 EnterCriticalSection(&g_sessions_lock);
934 hr = get_audio_session(sessionguid, This->parent, fmt->nChannels,
937 LeaveCriticalSection(&g_sessions_lock);
938 AudioQueueDispose(This->aqueue, 1);
940 CoTaskMemFree(This->fmt);
942 HeapFree(GetProcessHeap(), 0, This->vols);
944 OSSpinLockUnlock(&This->lock);
948 list_add_tail(&This->session->clients, &This->entry);
950 LeaveCriticalSection(&g_sessions_lock);
954 OSSpinLockUnlock(&This->lock);
959 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
962 ACImpl *This = impl_from_IAudioClient(iface);
964 TRACE("(%p)->(%p)\n", This, frames);
969 OSSpinLockLock(&This->lock);
972 OSSpinLockUnlock(&This->lock);
973 return AUDCLNT_E_NOT_INITIALIZED;
976 *frames = This->bufsize_frames;
978 OSSpinLockUnlock(&This->lock);
983 static HRESULT ca_get_max_stream_latency(ACImpl *This, UInt32 *max)
985 AudioObjectPropertyAddress addr;
991 addr.mScope = This->scope;
993 addr.mSelector = kAudioDevicePropertyStreams;
995 sc = AudioObjectGetPropertyDataSize(This->adevid, &addr, 0, NULL,
998 WARN("Unable to get size for _Streams property: %lx\n", sc);
1002 ids = HeapAlloc(GetProcessHeap(), 0, size);
1004 return E_OUTOFMEMORY;
1006 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL, &size, ids);
1008 WARN("Unable to get _Streams property: %lx\n", sc);
1009 HeapFree(GetProcessHeap(), 0, ids);
1013 nstreams = size / sizeof(AudioStreamID);
1016 addr.mSelector = kAudioStreamPropertyLatency;
1017 for(i = 0; i < nstreams; ++i){
1020 size = sizeof(latency);
1021 sc = AudioObjectGetPropertyData(ids[i], &addr, 0, NULL,
1024 WARN("Unable to get _Latency property: %lx\n", sc);
1032 HeapFree(GetProcessHeap(), 0, ids);
1037 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
1038 REFERENCE_TIME *out)
1040 ACImpl *This = impl_from_IAudioClient(iface);
1041 UInt32 latency, stream_latency, size;
1042 AudioObjectPropertyAddress addr;
1046 TRACE("(%p)->(%p)\n", This, out);
1051 OSSpinLockLock(&This->lock);
1054 OSSpinLockUnlock(&This->lock);
1055 return AUDCLNT_E_NOT_INITIALIZED;
1058 addr.mScope = This->scope;
1059 addr.mSelector = kAudioDevicePropertyLatency;
1062 size = sizeof(latency);
1063 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL,
1066 WARN("Couldn't get _Latency property: %lx\n", sc);
1067 OSSpinLockUnlock(&This->lock);
1071 hr = ca_get_max_stream_latency(This, &stream_latency);
1073 OSSpinLockUnlock(&This->lock);
1077 latency += stream_latency;
1078 *out = (latency / (double)This->fmt->nSamplesPerSec) * 10000000;
1080 OSSpinLockUnlock(&This->lock);
1085 static HRESULT AudioClient_GetCurrentPadding_nolock(ACImpl *This,
1089 return AUDCLNT_E_NOT_INITIALIZED;
1091 *numpad = This->inbuf_frames;
1096 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
1099 ACImpl *This = impl_from_IAudioClient(iface);
1102 TRACE("(%p)->(%p)\n", This, numpad);
1107 OSSpinLockLock(&This->lock);
1109 hr = AudioClient_GetCurrentPadding_nolock(This, numpad);
1111 OSSpinLockUnlock(&This->lock);
1116 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
1117 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
1118 WAVEFORMATEX **outpwfx)
1120 ACImpl *This = impl_from_IAudioClient(iface);
1121 AudioQueueRef aqueue;
1124 TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx);
1126 if(!pwfx || (mode == AUDCLNT_SHAREMODE_SHARED && !outpwfx))
1129 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1130 return E_INVALIDARG;
1132 if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1133 pwfx->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1134 return E_INVALIDARG;
1138 OSSpinLockLock(&This->lock);
1140 hr = ca_setup_aqueue(This->adevid, This->dataflow, pwfx, NULL, &aqueue);
1142 AudioQueueDispose(aqueue, 1);
1143 OSSpinLockUnlock(&This->lock);
1146 TRACE("returning %08x\n", S_OK);
1150 OSSpinLockUnlock(&This->lock);
1155 TRACE("returning %08x\n", AUDCLNT_E_UNSUPPORTED_FORMAT);
1156 return AUDCLNT_E_UNSUPPORTED_FORMAT;
1159 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
1160 WAVEFORMATEX **pwfx)
1162 ACImpl *This = impl_from_IAudioClient(iface);
1163 WAVEFORMATEXTENSIBLE *fmt;
1167 AudioBufferList *buffers;
1168 AudioObjectPropertyAddress addr;
1171 TRACE("(%p)->(%p)\n", This, pwfx);
1177 fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
1179 return E_OUTOFMEMORY;
1181 fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1183 addr.mScope = This->scope;
1185 addr.mSelector = kAudioDevicePropertyStreamConfiguration;
1187 sc = AudioObjectGetPropertyDataSize(This->adevid, &addr, 0, NULL, &size);
1190 WARN("Unable to get size for _StreamConfiguration property: %lx\n", sc);
1194 buffers = HeapAlloc(GetProcessHeap(), 0, size);
1197 return E_OUTOFMEMORY;
1200 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL,
1204 HeapFree(GetProcessHeap(), 0, buffers);
1205 WARN("Unable to get _StreamConfiguration property: %lx\n", sc);
1209 fmt->Format.nChannels = 0;
1210 for(i = 0; i < buffers->mNumberBuffers; ++i)
1211 fmt->Format.nChannels += buffers->mBuffers[i].mNumberChannels;
1213 HeapFree(GetProcessHeap(), 0, buffers);
1215 fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
1217 addr.mSelector = kAudioDevicePropertyNominalSampleRate;
1218 size = sizeof(Float64);
1219 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL, &size, &rate);
1222 WARN("Unable to get _NominalSampleRate property: %lx\n", sc);
1225 fmt->Format.nSamplesPerSec = rate;
1227 fmt->Format.wBitsPerSample = 32;
1228 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
1230 fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
1231 fmt->Format.nChannels) / 8;
1232 fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
1233 fmt->Format.nBlockAlign;
1235 fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
1236 fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1238 *pwfx = (WAVEFORMATEX*)fmt;
1244 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
1245 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1247 ACImpl *This = impl_from_IAudioClient(iface);
1249 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
1251 if(!defperiod && !minperiod)
1254 OSSpinLockLock(&This->lock);
1256 if(This->period_ms){
1258 *defperiod = This->period_ms * 10000;
1260 *minperiod = This->period_ms * 10000;
1263 *defperiod = DefaultPeriod;
1265 *minperiod = MinimumPeriod;
1268 OSSpinLockUnlock(&This->lock);
1273 void CALLBACK ca_period_cb(void *user, BOOLEAN timer)
1275 ACImpl *This = user;
1277 OSSpinLockLock(&This->lock);
1279 SetEvent(This->event);
1280 OSSpinLockUnlock(&This->lock);
1283 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
1285 ACImpl *This = impl_from_IAudioClient(iface);
1288 TRACE("(%p)\n", This);
1290 OSSpinLockLock(&This->lock);
1293 OSSpinLockUnlock(&This->lock);
1294 return AUDCLNT_E_NOT_INITIALIZED;
1297 if(This->playing != StateStopped){
1298 OSSpinLockUnlock(&This->lock);
1299 return AUDCLNT_E_NOT_STOPPED;
1302 if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
1303 OSSpinLockUnlock(&This->lock);
1304 return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1308 if(!CreateTimerQueueTimer(&This->timer, g_timer_q,
1309 ca_period_cb, This, 0, This->period_ms, 0))
1310 ERR("Unable to create timer: %u\n", GetLastError());
1312 This->playing = StateInTransition;
1314 OSSpinLockUnlock(&This->lock);
1316 sc = AudioQueueStart(This->aqueue, NULL);
1318 WARN("Unable to start audio queue: %lx\n", sc);
1322 OSSpinLockLock(&This->lock);
1324 This->playing = StatePlaying;
1326 OSSpinLockUnlock(&This->lock);
1331 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
1333 ACImpl *This = impl_from_IAudioClient(iface);
1336 TRACE("(%p)\n", This);
1338 OSSpinLockLock(&This->lock);
1341 OSSpinLockUnlock(&This->lock);
1342 return AUDCLNT_E_NOT_INITIALIZED;
1345 if(This->playing == StateStopped){
1346 OSSpinLockUnlock(&This->lock);
1350 if(This->playing == StateInTransition){
1351 OSSpinLockUnlock(&This->lock);
1355 if(This->timer && This->timer != INVALID_HANDLE_VALUE){
1356 DeleteTimerQueueTimer(g_timer_q, This->timer, INVALID_HANDLE_VALUE);
1360 This->playing = StateInTransition;
1362 OSSpinLockUnlock(&This->lock);
1364 sc = AudioQueueFlush(This->aqueue);
1366 WARN("Unable to flush audio queue: %lx\n", sc);
1368 sc = AudioQueuePause(This->aqueue);
1370 WARN("Unable to pause audio queue: %lx\n", sc);
1374 OSSpinLockLock(&This->lock);
1376 This->playing = StateStopped;
1378 OSSpinLockUnlock(&This->lock);
1383 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
1385 ACImpl *This = impl_from_IAudioClient(iface);
1389 TRACE("(%p)\n", This);
1391 OSSpinLockLock(&This->lock);
1394 OSSpinLockUnlock(&This->lock);
1395 return AUDCLNT_E_NOT_INITIALIZED;
1398 if(This->playing != StateStopped){
1399 OSSpinLockUnlock(&This->lock);
1400 return AUDCLNT_E_NOT_STOPPED;
1403 if(This->getbuf_last){
1404 OSSpinLockUnlock(&This->lock);
1405 return AUDCLNT_E_BUFFER_OPERATION_PENDING;
1408 This->written_frames = 0;
1410 hr = AudioClock_GetPosition_nolock(This, &This->last_time, NULL, TRUE);
1412 OSSpinLockUnlock(&This->lock);
1416 OSSpinLockUnlock(&This->lock);
1418 sc = AudioQueueReset(This->aqueue);
1420 WARN("Unable to reset audio queue: %lx\n", sc);
1427 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1430 ACImpl *This = impl_from_IAudioClient(iface);
1432 TRACE("(%p)->(%p)\n", This, event);
1435 return E_INVALIDARG;
1437 OSSpinLockLock(&This->lock);
1440 OSSpinLockUnlock(&This->lock);
1441 return AUDCLNT_E_NOT_INITIALIZED;
1444 if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
1445 OSSpinLockUnlock(&This->lock);
1446 return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1449 This->event = event;
1451 OSSpinLockUnlock(&This->lock);
1456 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1459 ACImpl *This = impl_from_IAudioClient(iface);
1461 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1467 OSSpinLockLock(&This->lock);
1470 OSSpinLockUnlock(&This->lock);
1471 return AUDCLNT_E_NOT_INITIALIZED;
1474 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1475 if(This->dataflow != eRender){
1476 OSSpinLockUnlock(&This->lock);
1477 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1479 IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
1480 *ppv = &This->IAudioRenderClient_iface;
1481 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1482 if(This->dataflow != eCapture){
1483 OSSpinLockUnlock(&This->lock);
1484 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1486 IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
1487 *ppv = &This->IAudioCaptureClient_iface;
1488 }else if(IsEqualIID(riid, &IID_IAudioClock)){
1489 IAudioClock_AddRef(&This->IAudioClock_iface);
1490 *ppv = &This->IAudioClock_iface;
1491 }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1492 IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
1493 *ppv = &This->IAudioStreamVolume_iface;
1494 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1495 if(!This->session_wrapper){
1496 This->session_wrapper = AudioSessionWrapper_Create(This);
1497 if(!This->session_wrapper){
1498 OSSpinLockUnlock(&This->lock);
1499 return E_OUTOFMEMORY;
1502 IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
1504 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1505 }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1506 if(!This->session_wrapper){
1507 This->session_wrapper = AudioSessionWrapper_Create(This);
1508 if(!This->session_wrapper){
1509 OSSpinLockUnlock(&This->lock);
1510 return E_OUTOFMEMORY;
1513 IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
1515 *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1516 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1517 if(!This->session_wrapper){
1518 This->session_wrapper = AudioSessionWrapper_Create(This);
1519 if(!This->session_wrapper){
1520 OSSpinLockUnlock(&This->lock);
1521 return E_OUTOFMEMORY;
1524 ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
1526 *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1530 OSSpinLockUnlock(&This->lock);
1534 OSSpinLockUnlock(&This->lock);
1536 FIXME("stub %s\n", debugstr_guid(riid));
1537 return E_NOINTERFACE;
1540 static const IAudioClientVtbl AudioClient_Vtbl =
1542 AudioClient_QueryInterface,
1544 AudioClient_Release,
1545 AudioClient_Initialize,
1546 AudioClient_GetBufferSize,
1547 AudioClient_GetStreamLatency,
1548 AudioClient_GetCurrentPadding,
1549 AudioClient_IsFormatSupported,
1550 AudioClient_GetMixFormat,
1551 AudioClient_GetDevicePeriod,
1555 AudioClient_SetEventHandle,
1556 AudioClient_GetService
1559 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1560 IAudioRenderClient *iface, REFIID riid, void **ppv)
1562 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1568 if(IsEqualIID(riid, &IID_IUnknown) ||
1569 IsEqualIID(riid, &IID_IAudioRenderClient))
1572 IUnknown_AddRef((IUnknown*)*ppv);
1576 WARN("Unknown interface %s\n", debugstr_guid(riid));
1577 return E_NOINTERFACE;
1580 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1582 ACImpl *This = impl_from_IAudioRenderClient(iface);
1583 return AudioClient_AddRef(&This->IAudioClient_iface);
1586 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1588 ACImpl *This = impl_from_IAudioRenderClient(iface);
1589 return AudioClient_Release(&This->IAudioClient_iface);
1592 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1593 UINT32 frames, BYTE **data)
1595 ACImpl *This = impl_from_IAudioRenderClient(iface);
1597 UINT32 pad, bytes = frames * This->fmt->nBlockAlign;
1601 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1607 OSSpinLockLock(&This->lock);
1609 if(This->getbuf_last){
1610 OSSpinLockUnlock(&This->lock);
1611 return AUDCLNT_E_OUT_OF_ORDER;
1615 OSSpinLockUnlock(&This->lock);
1619 hr = AudioClient_GetCurrentPadding_nolock(This, &pad);
1621 OSSpinLockUnlock(&This->lock);
1625 if(pad + frames > This->bufsize_frames){
1626 OSSpinLockUnlock(&This->lock);
1627 return AUDCLNT_E_BUFFER_TOO_LARGE;
1630 LIST_FOR_EACH_ENTRY(buf, &This->avail_buffers, AQBuffer, entry){
1631 if(buf->buf->mAudioDataBytesCapacity >= bytes){
1632 This->public_buffer = buf->buf;
1633 list_remove(&buf->entry);
1638 if(&buf->entry == &This->avail_buffers){
1639 sc = AudioQueueAllocateBuffer(This->aqueue, bytes,
1640 &This->public_buffer);
1642 OSSpinLockUnlock(&This->lock);
1643 WARN("Unable to allocate buffer: %lx\n", sc);
1646 buf = HeapAlloc(GetProcessHeap(), 0, sizeof(AQBuffer));
1648 AudioQueueFreeBuffer(This->aqueue, This->public_buffer);
1649 This->public_buffer = NULL;
1650 OSSpinLockUnlock(&This->lock);
1651 return E_OUTOFMEMORY;
1653 buf->buf = This->public_buffer;
1654 This->public_buffer->mUserData = buf;
1657 *data = This->public_buffer->mAudioData;
1659 This->getbuf_last = frames;
1661 OSSpinLockUnlock(&This->lock);
1666 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1667 IAudioRenderClient *iface, UINT32 frames, DWORD flags)
1669 ACImpl *This = impl_from_IAudioRenderClient(iface);
1672 TRACE("(%p)->(%u, %x)\n", This, frames, flags);
1674 OSSpinLockLock(&This->lock);
1677 This->getbuf_last = 0;
1678 if(This->public_buffer){
1679 AQBuffer *buf = This->public_buffer->mUserData;
1680 list_add_tail(&This->avail_buffers, &buf->entry);
1681 This->public_buffer = NULL;
1683 OSSpinLockUnlock(&This->lock);
1687 if(!This->getbuf_last){
1688 OSSpinLockUnlock(&This->lock);
1689 return AUDCLNT_E_OUT_OF_ORDER;
1692 if(frames > This->getbuf_last){
1693 OSSpinLockUnlock(&This->lock);
1694 return AUDCLNT_E_INVALID_SIZE;
1697 if(flags & AUDCLNT_BUFFERFLAGS_SILENT){
1698 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)This->fmt;
1699 if((This->fmt->wFormatTag == WAVE_FORMAT_PCM ||
1700 (This->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1701 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) &&
1702 This->fmt->wBitsPerSample == 8)
1703 memset(This->public_buffer->mAudioData, 128,
1704 frames * This->fmt->nBlockAlign);
1706 memset(This->public_buffer->mAudioData, 0,
1707 frames * This->fmt->nBlockAlign);
1710 This->public_buffer->mAudioDataByteSize = frames * This->fmt->nBlockAlign;
1712 sc = AudioQueueEnqueueBuffer(This->aqueue, This->public_buffer, 0, NULL);
1714 OSSpinLockUnlock(&This->lock);
1715 WARN("Unable to enqueue buffer: %lx\n", sc);
1719 if(This->playing == StateStopped)
1720 AudioQueuePrime(This->aqueue, 0, NULL);
1722 This->public_buffer = NULL;
1723 This->getbuf_last = 0;
1724 This->written_frames += frames;
1725 This->inbuf_frames += frames;
1727 OSSpinLockUnlock(&This->lock);
1732 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1733 AudioRenderClient_QueryInterface,
1734 AudioRenderClient_AddRef,
1735 AudioRenderClient_Release,
1736 AudioRenderClient_GetBuffer,
1737 AudioRenderClient_ReleaseBuffer
1740 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1741 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1743 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1749 if(IsEqualIID(riid, &IID_IUnknown) ||
1750 IsEqualIID(riid, &IID_IAudioCaptureClient))
1753 IUnknown_AddRef((IUnknown*)*ppv);
1757 WARN("Unknown interface %s\n", debugstr_guid(riid));
1758 return E_NOINTERFACE;
1761 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1763 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1764 return IAudioClient_AddRef(&This->IAudioClient_iface);
1767 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1769 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1770 return IAudioClient_Release(&This->IAudioClient_iface);
1773 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1774 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1777 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1779 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1782 if(!data || !frames || !flags)
1785 OSSpinLockLock(&This->lock);
1787 if(This->getbuf_last){
1788 OSSpinLockUnlock(&This->lock);
1789 return AUDCLNT_E_OUT_OF_ORDER;
1792 if(This->public_buffer){
1793 *data = This->public_buffer->mAudioData;
1795 This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
1797 struct list *head = list_head(&This->avail_buffers);
1802 AQBuffer *buf = LIST_ENTRY(head, AQBuffer, entry);
1803 This->public_buffer = buf->buf;
1804 *data = This->public_buffer->mAudioData;
1806 This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
1807 list_remove(&buf->entry);
1812 This->written_frames += *frames;
1813 This->inbuf_frames -= *frames;
1814 This->getbuf_last = 1;
1816 if(devpos || qpcpos)
1817 AudioClock_GetPosition_nolock(This, devpos, qpcpos, FALSE);
1819 OSSpinLockUnlock(&This->lock);
1821 return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
1824 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1825 IAudioCaptureClient *iface, UINT32 done)
1827 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1831 TRACE("(%p)->(%u)\n", This, done);
1833 OSSpinLockLock(&This->lock);
1835 if(!This->getbuf_last){
1836 OSSpinLockUnlock(&This->lock);
1837 return AUDCLNT_E_OUT_OF_ORDER;
1840 pbuf_frames = This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
1841 if(done != 0 && done != pbuf_frames){
1842 OSSpinLockUnlock(&This->lock);
1843 return AUDCLNT_E_INVALID_SIZE;
1847 sc = AudioQueueEnqueueBuffer(This->aqueue, This->public_buffer,
1850 WARN("Unable to enqueue buffer: %lx\n", sc);
1851 This->public_buffer = NULL;
1854 This->getbuf_last = 0;
1856 OSSpinLockUnlock(&This->lock);
1861 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1862 IAudioCaptureClient *iface, UINT32 *frames)
1864 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1868 TRACE("(%p)->(%p)\n", This, frames);
1873 OSSpinLockLock(&This->lock);
1875 head = list_head(&This->avail_buffers);
1878 *frames = This->bufsize_frames / CAPTURE_BUFFERS;
1879 OSSpinLockUnlock(&This->lock);
1883 buf = LIST_ENTRY(head, AQBuffer, entry);
1884 *frames = buf->buf->mAudioDataByteSize / This->fmt->nBlockAlign;
1886 OSSpinLockUnlock(&This->lock);
1891 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1893 AudioCaptureClient_QueryInterface,
1894 AudioCaptureClient_AddRef,
1895 AudioCaptureClient_Release,
1896 AudioCaptureClient_GetBuffer,
1897 AudioCaptureClient_ReleaseBuffer,
1898 AudioCaptureClient_GetNextPacketSize
1901 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1902 REFIID riid, void **ppv)
1904 ACImpl *This = impl_from_IAudioClock(iface);
1906 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1912 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
1914 else if(IsEqualIID(riid, &IID_IAudioClock2))
1915 *ppv = &This->IAudioClock2_iface;
1917 IUnknown_AddRef((IUnknown*)*ppv);
1921 WARN("Unknown interface %s\n", debugstr_guid(riid));
1922 return E_NOINTERFACE;
1925 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
1927 ACImpl *This = impl_from_IAudioClock(iface);
1928 return IAudioClient_AddRef(&This->IAudioClient_iface);
1931 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
1933 ACImpl *This = impl_from_IAudioClock(iface);
1934 return IAudioClient_Release(&This->IAudioClient_iface);
1937 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
1939 ACImpl *This = impl_from_IAudioClock(iface);
1941 TRACE("(%p)->(%p)\n", This, freq);
1943 *freq = This->fmt->nSamplesPerSec;
1948 static HRESULT AudioClock_GetPosition_nolock(ACImpl *This,
1949 UINT64 *pos, UINT64 *qpctime, BOOL raw)
1951 AudioTimeStamp time;
1954 sc = AudioQueueGetCurrentTime(This->aqueue, NULL, &time, NULL);
1955 if(sc == kAudioQueueErr_InvalidRunState){
1957 }else if(sc == noErr){
1958 if(!(time.mFlags & kAudioTimeStampSampleTimeValid)){
1959 FIXME("Sample time not valid, should calculate from something else\n");
1964 *pos = time.mSampleTime;
1966 *pos = time.mSampleTime - This->last_time;
1968 WARN("Unable to get current time: %lx\n", sc);
1973 LARGE_INTEGER stamp, freq;
1974 QueryPerformanceCounter(&stamp);
1975 QueryPerformanceFrequency(&freq);
1976 *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
1982 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
1985 ACImpl *This = impl_from_IAudioClock(iface);
1988 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
1993 OSSpinLockLock(&This->lock);
1995 hr = AudioClock_GetPosition_nolock(This, pos, qpctime, FALSE);
1997 OSSpinLockUnlock(&This->lock);
2002 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
2005 ACImpl *This = impl_from_IAudioClock(iface);
2007 TRACE("(%p)->(%p)\n", This, chars);
2012 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
2017 static const IAudioClockVtbl AudioClock_Vtbl =
2019 AudioClock_QueryInterface,
2022 AudioClock_GetFrequency,
2023 AudioClock_GetPosition,
2024 AudioClock_GetCharacteristics
2027 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
2028 REFIID riid, void **ppv)
2030 ACImpl *This = impl_from_IAudioClock2(iface);
2031 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
2034 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
2036 ACImpl *This = impl_from_IAudioClock2(iface);
2037 return IAudioClient_AddRef(&This->IAudioClient_iface);
2040 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
2042 ACImpl *This = impl_from_IAudioClock2(iface);
2043 return IAudioClient_Release(&This->IAudioClient_iface);
2046 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
2047 UINT64 *pos, UINT64 *qpctime)
2049 ACImpl *This = impl_from_IAudioClock2(iface);
2051 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
2056 static const IAudioClock2Vtbl AudioClock2_Vtbl =
2058 AudioClock2_QueryInterface,
2060 AudioClock2_Release,
2061 AudioClock2_GetDevicePosition
2064 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
2066 AudioSessionWrapper *ret;
2068 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2069 sizeof(AudioSessionWrapper));
2073 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
2074 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
2075 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
2079 ret->client = client;
2081 ret->session = client->session;
2082 AudioClient_AddRef(&client->IAudioClient_iface);
2088 static HRESULT WINAPI AudioSessionControl_QueryInterface(
2089 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
2091 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2097 if(IsEqualIID(riid, &IID_IUnknown) ||
2098 IsEqualIID(riid, &IID_IAudioSessionControl) ||
2099 IsEqualIID(riid, &IID_IAudioSessionControl2))
2102 IUnknown_AddRef((IUnknown*)*ppv);
2106 WARN("Unknown interface %s\n", debugstr_guid(riid));
2107 return E_NOINTERFACE;
2110 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
2112 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2114 ref = InterlockedIncrement(&This->ref);
2115 TRACE("(%p) Refcount now %u\n", This, ref);
2119 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
2121 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2123 ref = InterlockedDecrement(&This->ref);
2124 TRACE("(%p) Refcount now %u\n", This, ref);
2127 OSSpinLockLock(&This->client->lock);
2128 This->client->session_wrapper = NULL;
2129 OSSpinLockUnlock(&This->client->lock);
2130 AudioClient_Release(&This->client->IAudioClient_iface);
2132 HeapFree(GetProcessHeap(), 0, This);
2137 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
2138 AudioSessionState *state)
2140 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2143 TRACE("(%p)->(%p)\n", This, state);
2146 return NULL_PTR_ERR;
2148 EnterCriticalSection(&g_sessions_lock);
2150 if(list_empty(&This->session->clients)){
2151 *state = AudioSessionStateExpired;
2152 LeaveCriticalSection(&g_sessions_lock);
2156 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
2157 OSSpinLockLock(&client->lock);
2158 if(client->playing == StatePlaying ||
2159 client->playing == StateInTransition){
2160 *state = AudioSessionStateActive;
2161 OSSpinLockUnlock(&client->lock);
2162 LeaveCriticalSection(&g_sessions_lock);
2165 OSSpinLockUnlock(&client->lock);
2168 LeaveCriticalSection(&g_sessions_lock);
2170 *state = AudioSessionStateInactive;
2175 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
2176 IAudioSessionControl2 *iface, WCHAR **name)
2178 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2180 FIXME("(%p)->(%p) - stub\n", This, name);
2185 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
2186 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
2188 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2190 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
2195 static HRESULT WINAPI AudioSessionControl_GetIconPath(
2196 IAudioSessionControl2 *iface, WCHAR **path)
2198 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2200 FIXME("(%p)->(%p) - stub\n", This, path);
2205 static HRESULT WINAPI AudioSessionControl_SetIconPath(
2206 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
2208 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2210 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
2215 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
2216 IAudioSessionControl2 *iface, GUID *group)
2218 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2220 FIXME("(%p)->(%p) - stub\n", This, group);
2225 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
2226 IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
2228 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2230 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
2231 debugstr_guid(session));
2236 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
2237 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2239 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2241 FIXME("(%p)->(%p) - stub\n", This, events);
2246 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
2247 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2249 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2251 FIXME("(%p)->(%p) - stub\n", This, events);
2256 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
2257 IAudioSessionControl2 *iface, WCHAR **id)
2259 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2261 FIXME("(%p)->(%p) - stub\n", This, id);
2266 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
2267 IAudioSessionControl2 *iface, WCHAR **id)
2269 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2271 FIXME("(%p)->(%p) - stub\n", This, id);
2276 static HRESULT WINAPI AudioSessionControl_GetProcessId(
2277 IAudioSessionControl2 *iface, DWORD *pid)
2279 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2281 TRACE("(%p)->(%p)\n", This, pid);
2286 *pid = GetCurrentProcessId();
2291 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
2292 IAudioSessionControl2 *iface)
2294 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2296 TRACE("(%p)\n", This);
2301 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
2302 IAudioSessionControl2 *iface, BOOL optout)
2304 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2306 TRACE("(%p)->(%d)\n", This, optout);
2311 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
2313 AudioSessionControl_QueryInterface,
2314 AudioSessionControl_AddRef,
2315 AudioSessionControl_Release,
2316 AudioSessionControl_GetState,
2317 AudioSessionControl_GetDisplayName,
2318 AudioSessionControl_SetDisplayName,
2319 AudioSessionControl_GetIconPath,
2320 AudioSessionControl_SetIconPath,
2321 AudioSessionControl_GetGroupingParam,
2322 AudioSessionControl_SetGroupingParam,
2323 AudioSessionControl_RegisterAudioSessionNotification,
2324 AudioSessionControl_UnregisterAudioSessionNotification,
2325 AudioSessionControl_GetSessionIdentifier,
2326 AudioSessionControl_GetSessionInstanceIdentifier,
2327 AudioSessionControl_GetProcessId,
2328 AudioSessionControl_IsSystemSoundsSession,
2329 AudioSessionControl_SetDuckingPreference
2332 /* index == -1 means set all channels, otherwise sets only the given channel */
2333 static HRESULT ca_setvol(ACImpl *This, UINT32 index)
2338 if(index == (UINT32)-1){
2341 for(i = 0; i < This->fmt->nChannels; ++i){
2343 hr = ca_setvol(This, i);
2350 if(This->session->mute)
2353 level = This->session->master_vol *
2354 This->session->channel_vols[index] * This->vols[index];
2356 sc = AudioQueueSetParameter(This->aqueue, kAudioQueueParam_Volume, level);
2358 WARN("Setting _Volume property failed: %lx\n", sc);
2365 static HRESULT ca_session_setvol(AudioSession *session, UINT32 index)
2370 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry){
2372 hr = ca_setvol(client, index);
2380 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
2381 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
2383 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2389 if(IsEqualIID(riid, &IID_IUnknown) ||
2390 IsEqualIID(riid, &IID_ISimpleAudioVolume))
2393 IUnknown_AddRef((IUnknown*)*ppv);
2397 WARN("Unknown interface %s\n", debugstr_guid(riid));
2398 return E_NOINTERFACE;
2401 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
2403 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2404 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2407 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
2409 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2410 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2413 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
2414 ISimpleAudioVolume *iface, float level, const GUID *context)
2416 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2417 AudioSession *session = This->session;
2420 TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
2422 if(level < 0.f || level > 1.f)
2423 return E_INVALIDARG;
2426 FIXME("Notifications not supported yet\n");
2428 EnterCriticalSection(&session->lock);
2430 session->master_vol = level;
2432 ret = ca_session_setvol(session, -1);
2434 LeaveCriticalSection(&session->lock);
2439 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
2440 ISimpleAudioVolume *iface, float *level)
2442 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2443 AudioSession *session = This->session;
2445 TRACE("(%p)->(%p)\n", session, level);
2448 return NULL_PTR_ERR;
2450 *level = session->master_vol;
2455 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
2456 BOOL mute, const GUID *context)
2458 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2459 AudioSession *session = This->session;
2461 TRACE("(%p)->(%u, %p)\n", session, mute, context);
2464 FIXME("Notifications not supported yet\n");
2466 EnterCriticalSection(&session->lock);
2468 session->mute = mute;
2470 ca_session_setvol(session, -1);
2472 LeaveCriticalSection(&session->lock);
2477 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
2480 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2481 AudioSession *session = This->session;
2483 TRACE("(%p)->(%p)\n", session, mute);
2486 return NULL_PTR_ERR;
2488 *mute = session->mute;
2493 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
2495 SimpleAudioVolume_QueryInterface,
2496 SimpleAudioVolume_AddRef,
2497 SimpleAudioVolume_Release,
2498 SimpleAudioVolume_SetMasterVolume,
2499 SimpleAudioVolume_GetMasterVolume,
2500 SimpleAudioVolume_SetMute,
2501 SimpleAudioVolume_GetMute
2504 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
2505 IAudioStreamVolume *iface, REFIID riid, void **ppv)
2507 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2513 if(IsEqualIID(riid, &IID_IUnknown) ||
2514 IsEqualIID(riid, &IID_IAudioStreamVolume))
2517 IUnknown_AddRef((IUnknown*)*ppv);
2521 WARN("Unknown interface %s\n", debugstr_guid(riid));
2522 return E_NOINTERFACE;
2525 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
2527 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2528 return IAudioClient_AddRef(&This->IAudioClient_iface);
2531 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
2533 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2534 return IAudioClient_Release(&This->IAudioClient_iface);
2537 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
2538 IAudioStreamVolume *iface, UINT32 *out)
2540 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2542 TRACE("(%p)->(%p)\n", This, out);
2547 *out = This->fmt->nChannels;
2552 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
2553 IAudioStreamVolume *iface, UINT32 index, float level)
2555 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2558 TRACE("(%p)->(%d, %f)\n", This, index, level);
2560 if(level < 0.f || level > 1.f)
2561 return E_INVALIDARG;
2563 if(index >= This->fmt->nChannels)
2564 return E_INVALIDARG;
2566 OSSpinLockLock(&This->lock);
2568 This->vols[index] = level;
2570 WARN("AudioQueue doesn't support per-channel volume control\n");
2571 ret = ca_setvol(This, index);
2573 OSSpinLockUnlock(&This->lock);
2578 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2579 IAudioStreamVolume *iface, UINT32 index, float *level)
2581 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2583 TRACE("(%p)->(%d, %p)\n", This, index, level);
2588 if(index >= This->fmt->nChannels)
2589 return E_INVALIDARG;
2591 *level = This->vols[index];
2596 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2597 IAudioStreamVolume *iface, UINT32 count, const float *levels)
2599 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2603 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2608 if(count != This->fmt->nChannels)
2609 return E_INVALIDARG;
2611 OSSpinLockLock(&This->lock);
2613 for(i = 0; i < count; ++i)
2614 This->vols[i] = levels[i];
2616 ret = ca_setvol(This, -1);
2618 OSSpinLockUnlock(&This->lock);
2623 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2624 IAudioStreamVolume *iface, UINT32 count, float *levels)
2626 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2629 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2634 if(count != This->fmt->nChannels)
2635 return E_INVALIDARG;
2637 OSSpinLockLock(&This->lock);
2639 for(i = 0; i < count; ++i)
2640 levels[i] = This->vols[i];
2642 OSSpinLockUnlock(&This->lock);
2647 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2649 AudioStreamVolume_QueryInterface,
2650 AudioStreamVolume_AddRef,
2651 AudioStreamVolume_Release,
2652 AudioStreamVolume_GetChannelCount,
2653 AudioStreamVolume_SetChannelVolume,
2654 AudioStreamVolume_GetChannelVolume,
2655 AudioStreamVolume_SetAllVolumes,
2656 AudioStreamVolume_GetAllVolumes
2659 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2660 IChannelAudioVolume *iface, REFIID riid, void **ppv)
2662 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2668 if(IsEqualIID(riid, &IID_IUnknown) ||
2669 IsEqualIID(riid, &IID_IChannelAudioVolume))
2672 IUnknown_AddRef((IUnknown*)*ppv);
2676 WARN("Unknown interface %s\n", debugstr_guid(riid));
2677 return E_NOINTERFACE;
2680 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2682 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2683 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2686 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2688 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2689 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2692 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2693 IChannelAudioVolume *iface, UINT32 *out)
2695 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2696 AudioSession *session = This->session;
2698 TRACE("(%p)->(%p)\n", session, out);
2701 return NULL_PTR_ERR;
2703 *out = session->channel_count;
2708 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2709 IChannelAudioVolume *iface, UINT32 index, float level,
2710 const GUID *context)
2712 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2713 AudioSession *session = This->session;
2716 TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2717 wine_dbgstr_guid(context));
2719 if(level < 0.f || level > 1.f)
2720 return E_INVALIDARG;
2722 if(index >= session->channel_count)
2723 return E_INVALIDARG;
2726 FIXME("Notifications not supported yet\n");
2728 EnterCriticalSection(&session->lock);
2730 session->channel_vols[index] = level;
2732 WARN("AudioQueue doesn't support per-channel volume control\n");
2733 ret = ca_session_setvol(session, index);
2735 LeaveCriticalSection(&session->lock);
2740 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2741 IChannelAudioVolume *iface, UINT32 index, float *level)
2743 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2744 AudioSession *session = This->session;
2746 TRACE("(%p)->(%d, %p)\n", session, index, level);
2749 return NULL_PTR_ERR;
2751 if(index >= session->channel_count)
2752 return E_INVALIDARG;
2754 *level = session->channel_vols[index];
2759 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2760 IChannelAudioVolume *iface, UINT32 count, const float *levels,
2761 const GUID *context)
2763 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2764 AudioSession *session = This->session;
2768 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2769 wine_dbgstr_guid(context));
2772 return NULL_PTR_ERR;
2774 if(count != session->channel_count)
2775 return E_INVALIDARG;
2778 FIXME("Notifications not supported yet\n");
2780 EnterCriticalSection(&session->lock);
2782 for(i = 0; i < count; ++i)
2783 session->channel_vols[i] = levels[i];
2785 ret = ca_session_setvol(session, -1);
2787 LeaveCriticalSection(&session->lock);
2792 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2793 IChannelAudioVolume *iface, UINT32 count, float *levels)
2795 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2796 AudioSession *session = This->session;
2799 TRACE("(%p)->(%d, %p)\n", session, count, levels);
2802 return NULL_PTR_ERR;
2804 if(count != session->channel_count)
2805 return E_INVALIDARG;
2807 for(i = 0; i < count; ++i)
2808 levels[i] = session->channel_vols[i];
2813 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2815 ChannelAudioVolume_QueryInterface,
2816 ChannelAudioVolume_AddRef,
2817 ChannelAudioVolume_Release,
2818 ChannelAudioVolume_GetChannelCount,
2819 ChannelAudioVolume_SetChannelVolume,
2820 ChannelAudioVolume_GetChannelVolume,
2821 ChannelAudioVolume_SetAllVolumes,
2822 ChannelAudioVolume_GetAllVolumes
2825 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2826 REFIID riid, void **ppv)
2828 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2834 if(IsEqualIID(riid, &IID_IUnknown) ||
2835 IsEqualIID(riid, &IID_IAudioSessionManager) ||
2836 IsEqualIID(riid, &IID_IAudioSessionManager2))
2839 IUnknown_AddRef((IUnknown*)*ppv);
2843 WARN("Unknown interface %s\n", debugstr_guid(riid));
2844 return E_NOINTERFACE;
2847 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2849 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2851 ref = InterlockedIncrement(&This->ref);
2852 TRACE("(%p) Refcount now %u\n", This, ref);
2856 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2858 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2860 ref = InterlockedDecrement(&This->ref);
2861 TRACE("(%p) Refcount now %u\n", This, ref);
2863 HeapFree(GetProcessHeap(), 0, This);
2867 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2868 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2869 IAudioSessionControl **out)
2871 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2872 AudioSession *session;
2873 AudioSessionWrapper *wrapper;
2876 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2879 hr = get_audio_session(session_guid, This->device, 0, &session);
2883 wrapper = AudioSessionWrapper_Create(NULL);
2885 return E_OUTOFMEMORY;
2887 wrapper->session = session;
2889 *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
2894 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
2895 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2896 ISimpleAudioVolume **out)
2898 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2899 AudioSession *session;
2900 AudioSessionWrapper *wrapper;
2903 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2906 hr = get_audio_session(session_guid, This->device, 0, &session);
2910 wrapper = AudioSessionWrapper_Create(NULL);
2912 return E_OUTOFMEMORY;
2914 wrapper->session = session;
2916 *out = &wrapper->ISimpleAudioVolume_iface;
2921 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
2922 IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
2924 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2925 FIXME("(%p)->(%p) - stub\n", This, out);
2929 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
2930 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2932 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2933 FIXME("(%p)->(%p) - stub\n", This, notification);
2937 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
2938 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2940 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2941 FIXME("(%p)->(%p) - stub\n", This, notification);
2945 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
2946 IAudioSessionManager2 *iface, const WCHAR *session_id,
2947 IAudioVolumeDuckNotification *notification)
2949 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2950 FIXME("(%p)->(%p) - stub\n", This, notification);
2954 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
2955 IAudioSessionManager2 *iface,
2956 IAudioVolumeDuckNotification *notification)
2958 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2959 FIXME("(%p)->(%p) - stub\n", This, notification);
2963 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
2965 AudioSessionManager_QueryInterface,
2966 AudioSessionManager_AddRef,
2967 AudioSessionManager_Release,
2968 AudioSessionManager_GetAudioSessionControl,
2969 AudioSessionManager_GetSimpleAudioVolume,
2970 AudioSessionManager_GetSessionEnumerator,
2971 AudioSessionManager_RegisterSessionNotification,
2972 AudioSessionManager_UnregisterSessionNotification,
2973 AudioSessionManager_RegisterDuckNotification,
2974 AudioSessionManager_UnregisterDuckNotification
2977 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
2978 IAudioSessionManager2 **out)
2982 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
2984 return E_OUTOFMEMORY;
2986 This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
2987 This->device = device;
2990 *out = &This->IAudioSessionManager2_iface;