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 {
86 CRITICAL_SECTION lock;
91 typedef struct _AudioSessionWrapper {
92 IAudioSessionControl2 IAudioSessionControl2_iface;
93 IChannelAudioVolume IChannelAudioVolume_iface;
94 ISimpleAudioVolume ISimpleAudioVolume_iface;
99 AudioSession *session;
100 } AudioSessionWrapper;
103 IAudioClient IAudioClient_iface;
104 IAudioRenderClient IAudioRenderClient_iface;
105 IAudioCaptureClient IAudioCaptureClient_iface;
106 IAudioClock IAudioClock_iface;
107 IAudioClock2 IAudioClock2_iface;
108 IAudioStreamVolume IAudioStreamVolume_iface;
118 AUDCLNT_SHAREMODE share;
122 AudioDeviceID adevid;
123 AudioQueueRef aqueue;
124 AudioObjectPropertyScope scope;
126 UINT32 period_ms, bufsize_frames, inbuf_frames, written_frames;
128 AudioQueueBufferRef public_buffer;
132 AudioSession *session;
133 AudioSessionWrapper *session_wrapper;
137 struct list avail_buffers;
139 /* We can't use debug printing or {Enter,Leave}CriticalSection from
140 * OSX callback threads, so we use OSX's OSSpinLock for synchronization
141 * instead. OSSpinLock is not a recursive lock, so don't call
142 * synchronized functions while holding the lock. */
152 static const IAudioClientVtbl AudioClient_Vtbl;
153 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
154 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
155 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
156 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
157 static const IAudioClockVtbl AudioClock_Vtbl;
158 static const IAudioClock2Vtbl AudioClock2_Vtbl;
159 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
160 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
162 static HANDLE g_timer_q;
164 static CRITICAL_SECTION g_sessions_lock;
165 static struct list g_sessions = LIST_INIT(g_sessions);
167 static HRESULT AudioClock_GetPosition_nolock(ACImpl *This, UINT64 *pos,
168 UINT64 *qpctime, BOOL raw);
169 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
170 static HRESULT ca_setvol(ACImpl *This, UINT32 index);
172 static inline ACImpl *impl_from_IAudioClient(IAudioClient *iface)
174 return CONTAINING_RECORD(iface, ACImpl, IAudioClient_iface);
177 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
179 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
182 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
184 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
187 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
189 return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
192 static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
194 return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
197 static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
199 return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
202 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
204 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
207 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
209 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
212 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
214 return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
217 BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
219 if(reason == DLL_PROCESS_ATTACH){
220 g_timer_q = CreateTimerQueue();
224 InitializeCriticalSection(&g_sessions_lock);
230 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids,
231 AudioDeviceID ***keys, UINT *num, UINT *def_index)
233 UInt32 devsize, size;
234 AudioDeviceID *devices;
235 AudioDeviceID default_id;
236 AudioObjectPropertyAddress addr;
240 TRACE("%d %p %p %p\n", flow, ids, num, def_index);
242 addr.mScope = kAudioObjectPropertyScopeGlobal;
243 addr.mElement = kAudioObjectPropertyElementMaster;
245 addr.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
246 else if(flow == eCapture)
247 addr.mSelector = kAudioHardwarePropertyDefaultInputDevice;
251 size = sizeof(default_id);
252 sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0,
253 NULL, &size, &default_id);
255 WARN("Getting _DefaultInputDevice property failed: %lx\n", sc);
259 addr.mSelector = kAudioHardwarePropertyDevices;
260 sc = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &addr, 0,
263 WARN("Getting _Devices property size failed: %lx\n", sc);
267 devices = HeapAlloc(GetProcessHeap(), 0, devsize);
269 return E_OUTOFMEMORY;
271 sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0, NULL,
274 WARN("Getting _Devices property failed: %lx\n", sc);
275 HeapFree(GetProcessHeap(), 0, devices);
279 ndevices = devsize / sizeof(AudioDeviceID);
281 *ids = HeapAlloc(GetProcessHeap(), 0, ndevices * sizeof(WCHAR *));
283 HeapFree(GetProcessHeap(), 0, devices);
284 return E_OUTOFMEMORY;
287 *keys = HeapAlloc(GetProcessHeap(), 0, ndevices * sizeof(AudioDeviceID *));
289 HeapFree(GetProcessHeap(), 0, *ids);
290 HeapFree(GetProcessHeap(), 0, devices);
291 return E_OUTOFMEMORY;
295 *def_index = (UINT)-1;
296 for(i = 0; i < ndevices; ++i){
297 AudioBufferList *buffers;
303 addr.mSelector = kAudioDevicePropertyStreamConfiguration;
305 addr.mScope = kAudioDevicePropertyScopeOutput;
307 addr.mScope = kAudioDevicePropertyScopeInput;
309 sc = AudioObjectGetPropertyDataSize(devices[i], &addr, 0, NULL, &size);
311 WARN("Unable to get _StreamConfiguration property size for "
312 "device %lu: %lx\n", devices[i], sc);
316 buffers = HeapAlloc(GetProcessHeap(), 0, size);
318 HeapFree(GetProcessHeap(), 0, devices);
319 for(j = 0; j < *num; ++j)
320 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
321 HeapFree(GetProcessHeap(), 0, *keys);
322 HeapFree(GetProcessHeap(), 0, *ids);
323 return E_OUTOFMEMORY;
326 sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL,
329 WARN("Unable to get _StreamConfiguration property for "
330 "device %lu: %lx\n", devices[i], sc);
331 HeapFree(GetProcessHeap(), 0, buffers);
335 /* check that there's at least one channel in this device before
336 * we claim it as usable */
337 for(j = 0; j < buffers->mNumberBuffers; ++j)
338 if(buffers->mBuffers[j].mNumberChannels > 0)
340 if(j >= buffers->mNumberBuffers){
341 HeapFree(GetProcessHeap(), 0, buffers);
345 HeapFree(GetProcessHeap(), 0, buffers);
348 addr.mSelector = kAudioObjectPropertyName;
349 sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL,
352 WARN("Unable to get _Name property for device %lu: %lx\n",
357 if(!CFStringGetCString(name, nameA, sizeof(nameA),
358 kCFStringEncodingUTF8)){
359 WARN("Error converting string to UTF8\n");
366 len = MultiByteToWideChar(CP_UNIXCP, 0, nameA, -1, NULL, 0);
367 (*ids)[*num] = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
369 HeapFree(GetProcessHeap(), 0, devices);
370 for(j = 0; j < *num; ++j){
371 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
372 HeapFree(GetProcessHeap(), 0, (*keys)[j]);
374 HeapFree(GetProcessHeap(), 0, *ids);
375 HeapFree(GetProcessHeap(), 0, *keys);
376 return E_OUTOFMEMORY;
378 MultiByteToWideChar(CP_UNIXCP, 0, nameA, -1, (*ids)[*num], len);
380 (*keys)[*num] = HeapAlloc(GetProcessHeap(), 0, sizeof(AudioDeviceID));
382 HeapFree(GetProcessHeap(), 0, devices);
383 HeapFree(GetProcessHeap(), 0, (*ids)[*num]);
384 for(j = 0; j < *num; ++j){
385 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
386 HeapFree(GetProcessHeap(), 0, (*keys)[j]);
388 HeapFree(GetProcessHeap(), 0, *ids);
389 HeapFree(GetProcessHeap(), 0, *keys);
390 return E_OUTOFMEMORY;
392 *(*keys)[*num] = devices[i];
394 if(*def_index == (UINT)-1 && devices[i] == default_id)
400 if(*def_index == (UINT)-1)
403 HeapFree(GetProcessHeap(), 0, devices);
408 HRESULT WINAPI AUDDRV_GetAudioEndpoint(AudioDeviceID *adevid, IMMDevice *dev,
409 EDataFlow dataflow, IAudioClient **out)
413 TRACE("%p %d %p\n", dev, dataflow, out);
415 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACImpl));
417 return E_OUTOFMEMORY;
419 This->IAudioClient_iface.lpVtbl = &AudioClient_Vtbl;
420 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
421 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
422 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
423 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
424 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
426 This->dataflow = dataflow;
428 if(dataflow == eRender)
429 This->scope = kAudioDevicePropertyScopeOutput;
430 else if(dataflow == eCapture)
431 This->scope = kAudioDevicePropertyScopeInput;
433 HeapFree(GetProcessHeap(), 0, This);
440 IMMDevice_AddRef(This->parent);
442 list_init(&This->avail_buffers);
444 This->adevid = *adevid;
446 *out = &This->IAudioClient_iface;
447 IAudioClient_AddRef(&This->IAudioClient_iface);
452 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient *iface,
453 REFIID riid, void **ppv)
455 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
460 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClient))
463 IUnknown_AddRef((IUnknown*)*ppv);
466 WARN("Unknown interface %s\n", debugstr_guid(riid));
467 return E_NOINTERFACE;
470 static ULONG WINAPI AudioClient_AddRef(IAudioClient *iface)
472 ACImpl *This = impl_from_IAudioClient(iface);
474 ref = InterlockedIncrement(&This->ref);
475 TRACE("(%p) Refcount now %u\n", This, ref);
479 static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
481 ACImpl *This = impl_from_IAudioClient(iface);
483 ref = InterlockedDecrement(&This->ref);
484 TRACE("(%p) Refcount now %u\n", This, ref);
486 IAudioClient_Stop(iface);
488 AudioQueueDispose(This->aqueue, 1);
490 EnterCriticalSection(&g_sessions_lock);
491 list_remove(&This->entry);
492 if(list_empty(&This->session->clients)){
493 list_remove(&This->session->entry);
494 DeleteCriticalSection(&This->session->lock);
495 HeapFree(GetProcessHeap(), 0, This->session->channel_vols);
496 HeapFree(GetProcessHeap(), 0, This->session);
498 LeaveCriticalSection(&g_sessions_lock);
500 HeapFree(GetProcessHeap(), 0, This->vols);
501 HeapFree(GetProcessHeap(), 0, This->public_buffer);
502 CoTaskMemFree(This->fmt);
503 IMMDevice_Release(This->parent);
504 HeapFree(GetProcessHeap(), 0, This);
509 static void dump_fmt(const WAVEFORMATEX *fmt)
511 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
512 switch(fmt->wFormatTag){
513 case WAVE_FORMAT_PCM:
514 TRACE("WAVE_FORMAT_PCM");
516 case WAVE_FORMAT_IEEE_FLOAT:
517 TRACE("WAVE_FORMAT_IEEE_FLOAT");
519 case WAVE_FORMAT_EXTENSIBLE:
520 TRACE("WAVE_FORMAT_EXTENSIBLE");
528 TRACE("nChannels: %u\n", fmt->nChannels);
529 TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
530 TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
531 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
532 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
533 TRACE("cbSize: %u\n", fmt->cbSize);
535 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
536 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
537 TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
538 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
539 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
543 static DWORD get_channel_mask(unsigned int channels)
549 return SPEAKER_FRONT_CENTER;
551 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
553 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT |
554 SPEAKER_LOW_FREQUENCY;
556 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
559 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
560 SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY;
562 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
563 SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER;
565 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
566 SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER |
569 FIXME("Unknown speaker configuration: %u\n", channels);
573 static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
578 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
579 size = sizeof(WAVEFORMATEXTENSIBLE);
581 size = sizeof(WAVEFORMATEX);
583 ret = CoTaskMemAlloc(size);
587 memcpy(ret, fmt, size);
589 ret->cbSize = size - sizeof(WAVEFORMATEX);
594 static HRESULT ca_get_audiodesc(AudioStreamBasicDescription *desc,
595 const WAVEFORMATEX *fmt)
597 const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)fmt;
599 if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
600 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
601 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
602 desc->mFormatID = kAudioFormatLinearPCM;
603 if(fmt->wBitsPerSample > 8)
604 desc->mFormatFlags = kAudioFormatFlagIsSignedInteger;
605 }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
606 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
607 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
608 desc->mFormatID = kAudioFormatLinearPCM;
609 desc->mFormatFlags = kAudioFormatFlagIsFloat;
610 }else if(fmt->wFormatTag == WAVE_FORMAT_MULAW ||
611 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
612 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_MULAW))){
613 desc->mFormatID = kAudioFormatULaw;
614 }else if(fmt->wFormatTag == WAVE_FORMAT_ALAW ||
615 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
616 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_ALAW))){
617 desc->mFormatID = kAudioFormatALaw;
619 return AUDCLNT_E_UNSUPPORTED_FORMAT;
621 desc->mSampleRate = fmt->nSamplesPerSec;
622 desc->mBytesPerPacket = fmt->nBlockAlign;
623 desc->mFramesPerPacket = 1;
624 desc->mBytesPerFrame = fmt->nBlockAlign;
625 desc->mChannelsPerFrame = fmt->nChannels;
626 desc->mBitsPerChannel = fmt->wBitsPerSample;
632 static void ca_out_buffer_cb(void *user, AudioQueueRef aqueue,
633 AudioQueueBufferRef buffer)
636 AQBuffer *buf = buffer->mUserData;
638 OSSpinLockLock(&This->lock);
639 list_add_tail(&This->avail_buffers, &buf->entry);
640 This->inbuf_frames -= buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
641 OSSpinLockUnlock(&This->lock);
644 static void ca_in_buffer_cb(void *user, AudioQueueRef aqueue,
645 AudioQueueBufferRef buffer, const AudioTimeStamp *start,
646 UInt32 ndesc, const AudioStreamPacketDescription *descs)
649 AQBuffer *buf = buffer->mUserData;
651 OSSpinLockLock(&This->lock);
652 list_add_tail(&This->avail_buffers, &buf->entry);
653 This->inbuf_frames += buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
654 OSSpinLockUnlock(&This->lock);
657 static HRESULT ca_setup_aqueue(AudioDeviceID did, EDataFlow flow,
658 const WAVEFORMATEX *fmt, void *user, AudioQueueRef *aqueue)
660 AudioStreamBasicDescription desc;
661 AudioObjectPropertyAddress addr;
667 addr.mScope = kAudioObjectPropertyScopeGlobal;
669 addr.mSelector = kAudioDevicePropertyDeviceUID;
672 sc = AudioObjectGetPropertyData(did, &addr, 0, NULL, &size, &uid);
674 WARN("Unable to get _DeviceUID property: %lx\n", sc);
678 hr = ca_get_audiodesc(&desc, fmt);
685 sc = AudioQueueNewOutput(&desc, ca_out_buffer_cb, user, NULL, NULL, 0,
687 else if(flow == eCapture)
688 sc = AudioQueueNewInput(&desc, ca_in_buffer_cb, user, NULL, NULL, 0,
695 WARN("Unable to create AudioQueue: %lx\n", sc);
700 sc = AudioQueueSetProperty(*aqueue, kAudioQueueProperty_CurrentDevice,
712 static AudioSession *create_session(const GUID *guid, EDataFlow flow,
717 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
721 memcpy(&ret->guid, guid, sizeof(GUID));
723 ret->dataflow = flow;
725 list_init(&ret->clients);
727 list_add_head(&g_sessions, &ret->entry);
729 InitializeCriticalSection(&ret->lock);
731 ret->channel_count = num_channels;
732 ret->channel_vols = HeapAlloc(GetProcessHeap(), 0,
733 sizeof(float) * num_channels);
734 if(!ret->channel_vols){
735 HeapFree(GetProcessHeap(), 0, ret);
739 for(; num_channels > 0; --num_channels)
740 ret->channel_vols[num_channels - 1] = 1.f;
742 ret->master_vol = 1.f;
747 static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
748 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
749 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
750 const GUID *sessionguid)
752 ACImpl *This = impl_from_IAudioClient(iface);
757 TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
758 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
765 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
766 return AUDCLNT_E_NOT_INITIALIZED;
768 if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
769 AUDCLNT_STREAMFLAGS_LOOPBACK |
770 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
771 AUDCLNT_STREAMFLAGS_NOPERSIST |
772 AUDCLNT_STREAMFLAGS_RATEADJUST |
773 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
774 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
775 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED)){
776 TRACE("Unknown flags: %08x\n", flags);
780 OSSpinLockLock(&This->lock);
783 OSSpinLockUnlock(&This->lock);
784 return AUDCLNT_E_ALREADY_INITIALIZED;
787 hr = ca_setup_aqueue(This->adevid, This->dataflow, fmt, This, &This->aqueue);
789 OSSpinLockUnlock(&This->lock);
793 This->fmt = clone_format(fmt);
795 AudioQueueDispose(This->aqueue, 1);
797 OSSpinLockUnlock(&This->lock);
798 return E_OUTOFMEMORY;
802 This->period_ms = period / 10000;
803 if(This->period_ms == 0)
806 This->period_ms = MinimumPeriod / 10000;
808 This->bufsize_frames = ceil(fmt->nSamplesPerSec * (duration / 10000000.));
810 if(This->dataflow == eCapture){
812 UInt32 bsize = ceil((This->bufsize_frames / (double)CAPTURE_BUFFERS) *
813 This->fmt->nBlockAlign);
814 for(i = 0; i < CAPTURE_BUFFERS; ++i){
817 buf = HeapAlloc(GetProcessHeap(), 0, sizeof(AQBuffer));
819 AudioQueueDispose(This->aqueue, 1);
821 CoTaskMemFree(This->fmt);
823 OSSpinLockUnlock(&This->lock);
824 return E_OUTOFMEMORY;
827 sc = AudioQueueAllocateBuffer(This->aqueue, bsize, &buf->buf);
829 AudioQueueDispose(This->aqueue, 1);
831 CoTaskMemFree(This->fmt);
833 OSSpinLockUnlock(&This->lock);
834 WARN("Couldn't allocate buffer: %lx\n", sc);
838 buf->buf->mUserData = buf;
840 sc = AudioQueueEnqueueBuffer(This->aqueue, buf->buf, 0, NULL);
842 ERR("Couldn't enqueue buffer: %lx\n", sc);
848 This->vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float));
850 AudioQueueDispose(This->aqueue, 1);
852 CoTaskMemFree(This->fmt);
854 OSSpinLockUnlock(&This->lock);
855 return E_OUTOFMEMORY;
858 for(i = 0; i < fmt->nChannels; ++i)
864 EnterCriticalSection(&g_sessions_lock);
866 if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
867 This->session = create_session(&GUID_NULL, This->dataflow,
870 LeaveCriticalSection(&g_sessions_lock);
871 AudioQueueDispose(This->aqueue, 1);
873 CoTaskMemFree(This->fmt);
875 HeapFree(GetProcessHeap(), 0, This->vols);
877 OSSpinLockUnlock(&This->lock);
878 return E_OUTOFMEMORY;
881 AudioSession *session;
883 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
884 if(IsEqualGUID(sessionguid, &session->guid) &&
885 This->dataflow == session->dataflow){
886 if(session->channel_count != fmt->nChannels){
887 LeaveCriticalSection(&g_sessions_lock);
888 AudioQueueDispose(This->aqueue, 1);
890 CoTaskMemFree(This->fmt);
892 HeapFree(GetProcessHeap(), 0, This->vols);
894 OSSpinLockUnlock(&This->lock);
897 This->session = session;
902 This->session = create_session(sessionguid, This->dataflow,
905 LeaveCriticalSection(&g_sessions_lock);
906 AudioQueueDispose(This->aqueue, 1);
908 CoTaskMemFree(This->fmt);
910 HeapFree(GetProcessHeap(), 0, This->vols);
912 OSSpinLockUnlock(&This->lock);
913 return E_OUTOFMEMORY;
918 list_add_tail(&This->session->clients, &This->entry);
920 LeaveCriticalSection(&g_sessions_lock);
924 OSSpinLockUnlock(&This->lock);
929 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
932 ACImpl *This = impl_from_IAudioClient(iface);
934 TRACE("(%p)->(%p)\n", This, frames);
939 OSSpinLockLock(&This->lock);
942 OSSpinLockUnlock(&This->lock);
943 return AUDCLNT_E_NOT_INITIALIZED;
946 *frames = This->bufsize_frames;
948 OSSpinLockUnlock(&This->lock);
953 static HRESULT ca_get_max_stream_latency(ACImpl *This, UInt32 *max)
955 AudioObjectPropertyAddress addr;
961 addr.mScope = This->scope;
963 addr.mSelector = kAudioDevicePropertyStreams;
965 sc = AudioObjectGetPropertyDataSize(This->adevid, &addr, 0, NULL,
968 WARN("Unable to get size for _Streams property: %lx\n", sc);
972 ids = HeapAlloc(GetProcessHeap(), 0, size);
974 return E_OUTOFMEMORY;
976 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL, &size, ids);
978 WARN("Unable to get _Streams property: %lx\n", sc);
979 HeapFree(GetProcessHeap(), 0, ids);
983 nstreams = size / sizeof(AudioStreamID);
986 addr.mSelector = kAudioStreamPropertyLatency;
987 for(i = 0; i < nstreams; ++i){
990 size = sizeof(latency);
991 sc = AudioObjectGetPropertyData(ids[i], &addr, 0, NULL,
994 WARN("Unable to get _Latency property: %lx\n", sc);
1002 HeapFree(GetProcessHeap(), 0, ids);
1007 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
1008 REFERENCE_TIME *out)
1010 ACImpl *This = impl_from_IAudioClient(iface);
1011 UInt32 latency, stream_latency, size;
1012 AudioObjectPropertyAddress addr;
1016 TRACE("(%p)->(%p)\n", This, out);
1021 OSSpinLockLock(&This->lock);
1024 OSSpinLockUnlock(&This->lock);
1025 return AUDCLNT_E_NOT_INITIALIZED;
1028 addr.mScope = This->scope;
1029 addr.mSelector = kAudioDevicePropertyLatency;
1032 size = sizeof(latency);
1033 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL,
1036 WARN("Couldn't get _Latency property: %lx\n", sc);
1037 OSSpinLockUnlock(&This->lock);
1041 hr = ca_get_max_stream_latency(This, &stream_latency);
1043 OSSpinLockUnlock(&This->lock);
1047 latency += stream_latency;
1048 *out = (latency / (double)This->fmt->nSamplesPerSec) * 10000000;
1050 OSSpinLockUnlock(&This->lock);
1055 static HRESULT AudioClient_GetCurrentPadding_nolock(ACImpl *This,
1059 return AUDCLNT_E_NOT_INITIALIZED;
1061 *numpad = This->inbuf_frames;
1066 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
1069 ACImpl *This = impl_from_IAudioClient(iface);
1072 TRACE("(%p)->(%p)\n", This, numpad);
1077 OSSpinLockLock(&This->lock);
1079 hr = AudioClient_GetCurrentPadding_nolock(This, numpad);
1081 OSSpinLockUnlock(&This->lock);
1086 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
1087 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
1088 WAVEFORMATEX **outpwfx)
1090 ACImpl *This = impl_from_IAudioClient(iface);
1091 AudioQueueRef aqueue;
1094 TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx);
1096 if(!pwfx || (mode == AUDCLNT_SHAREMODE_SHARED && !outpwfx))
1099 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1100 return E_INVALIDARG;
1102 if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1103 pwfx->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1104 return E_INVALIDARG;
1108 OSSpinLockLock(&This->lock);
1110 hr = ca_setup_aqueue(This->adevid, This->dataflow, pwfx, NULL, &aqueue);
1112 AudioQueueDispose(aqueue, 1);
1113 OSSpinLockUnlock(&This->lock);
1116 TRACE("returning %08x\n", S_OK);
1120 OSSpinLockUnlock(&This->lock);
1125 TRACE("returning %08x\n", AUDCLNT_E_UNSUPPORTED_FORMAT);
1126 return AUDCLNT_E_UNSUPPORTED_FORMAT;
1129 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
1130 WAVEFORMATEX **pwfx)
1132 ACImpl *This = impl_from_IAudioClient(iface);
1133 WAVEFORMATEXTENSIBLE *fmt;
1137 AudioBufferList *buffers;
1138 AudioObjectPropertyAddress addr;
1141 TRACE("(%p)->(%p)\n", This, pwfx);
1146 *pwfx = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEXTENSIBLE));
1148 return E_OUTOFMEMORY;
1150 fmt = (WAVEFORMATEXTENSIBLE*)*pwfx;
1152 fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1154 addr.mScope = This->scope;
1156 addr.mSelector = kAudioDevicePropertyStreamConfiguration;
1158 sc = AudioObjectGetPropertyDataSize(This->adevid, &addr, 0, NULL, &size);
1160 HeapFree(GetProcessHeap(), 0, fmt);
1161 WARN("Unable to get size for _StreamConfiguration property: %lx\n", sc);
1165 buffers = HeapAlloc(GetProcessHeap(), 0, size);
1167 HeapFree(GetProcessHeap(), 0, fmt);
1168 return E_OUTOFMEMORY;
1171 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL,
1174 HeapFree(GetProcessHeap(), 0, fmt);
1175 HeapFree(GetProcessHeap(), 0, buffers);
1176 WARN("Unable to get _StreamConfiguration property: %lx\n", sc);
1180 fmt->Format.nChannels = 0;
1181 for(i = 0; i < buffers->mNumberBuffers; ++i)
1182 fmt->Format.nChannels += buffers->mBuffers[i].mNumberChannels;
1184 HeapFree(GetProcessHeap(), 0, buffers);
1186 fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
1188 addr.mSelector = kAudioDevicePropertyNominalSampleRate;
1189 size = sizeof(Float64);
1190 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL, &size, &rate);
1192 HeapFree(GetProcessHeap(), 0, fmt);
1193 WARN("Unable to get _NominalSampleRate property: %lx\n", sc);
1196 fmt->Format.nSamplesPerSec = rate;
1198 /* CoreAudio doesn't seem to give a device format preference, so just
1199 * choose a common format... */
1200 fmt->Format.wBitsPerSample = 16;
1201 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1203 fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
1204 fmt->Format.nChannels) / 8;
1205 fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
1206 fmt->Format.nBlockAlign;
1208 fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
1209 fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1216 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
1217 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1219 ACImpl *This = impl_from_IAudioClient(iface);
1221 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
1223 if(!defperiod && !minperiod)
1226 OSSpinLockLock(&This->lock);
1228 if(This->period_ms){
1230 *defperiod = This->period_ms * 10000;
1232 *minperiod = This->period_ms * 10000;
1235 *defperiod = DefaultPeriod;
1237 *minperiod = MinimumPeriod;
1240 OSSpinLockUnlock(&This->lock);
1245 void CALLBACK ca_period_cb(void *user, BOOLEAN timer)
1247 ACImpl *This = user;
1249 OSSpinLockLock(&This->lock);
1251 SetEvent(This->event);
1252 OSSpinLockUnlock(&This->lock);
1255 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
1257 ACImpl *This = impl_from_IAudioClient(iface);
1260 TRACE("(%p)\n", This);
1262 OSSpinLockLock(&This->lock);
1265 OSSpinLockUnlock(&This->lock);
1266 return AUDCLNT_E_NOT_INITIALIZED;
1269 if(This->playing != StateStopped){
1270 OSSpinLockUnlock(&This->lock);
1271 return AUDCLNT_E_NOT_STOPPED;
1274 if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
1275 OSSpinLockUnlock(&This->lock);
1276 return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1280 if(!CreateTimerQueueTimer(&This->timer, g_timer_q,
1281 ca_period_cb, This, 0, This->period_ms, 0))
1282 ERR("Unable to create timer: %u\n", GetLastError());
1284 This->playing = StateInTransition;
1286 OSSpinLockUnlock(&This->lock);
1288 sc = AudioQueueStart(This->aqueue, NULL);
1290 WARN("Unable to start audio queue: %lx\n", sc);
1294 OSSpinLockLock(&This->lock);
1296 This->playing = StatePlaying;
1298 OSSpinLockUnlock(&This->lock);
1303 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
1305 ACImpl *This = impl_from_IAudioClient(iface);
1308 TRACE("(%p)\n", This);
1310 OSSpinLockLock(&This->lock);
1313 OSSpinLockUnlock(&This->lock);
1314 return AUDCLNT_E_NOT_INITIALIZED;
1317 if(This->playing == StateStopped){
1318 OSSpinLockUnlock(&This->lock);
1322 if(This->playing == StateInTransition){
1323 OSSpinLockUnlock(&This->lock);
1327 if(This->timer && This->timer != INVALID_HANDLE_VALUE){
1328 DeleteTimerQueueTimer(g_timer_q, This->timer, INVALID_HANDLE_VALUE);
1332 This->playing = StateInTransition;
1334 OSSpinLockUnlock(&This->lock);
1336 sc = AudioQueueFlush(This->aqueue);
1338 WARN("Unable to flush audio queue: %lx\n", sc);
1340 sc = AudioQueuePause(This->aqueue);
1342 WARN("Unable to pause audio queue: %lx\n", sc);
1346 OSSpinLockLock(&This->lock);
1348 This->playing = StateStopped;
1350 OSSpinLockUnlock(&This->lock);
1355 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
1357 ACImpl *This = impl_from_IAudioClient(iface);
1361 TRACE("(%p)\n", This);
1363 OSSpinLockLock(&This->lock);
1366 OSSpinLockUnlock(&This->lock);
1367 return AUDCLNT_E_NOT_INITIALIZED;
1370 if(This->playing != StateStopped){
1371 OSSpinLockUnlock(&This->lock);
1372 return AUDCLNT_E_NOT_STOPPED;
1375 This->written_frames = 0;
1377 hr = AudioClock_GetPosition_nolock(This, &This->last_time, NULL, TRUE);
1379 OSSpinLockUnlock(&This->lock);
1383 OSSpinLockUnlock(&This->lock);
1385 sc = AudioQueueReset(This->aqueue);
1387 WARN("Unable to reset audio queue: %lx\n", sc);
1394 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1397 ACImpl *This = impl_from_IAudioClient(iface);
1399 TRACE("(%p)->(%p)\n", This, event);
1402 return E_INVALIDARG;
1404 OSSpinLockLock(&This->lock);
1407 OSSpinLockUnlock(&This->lock);
1408 return AUDCLNT_E_NOT_INITIALIZED;
1411 if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
1412 OSSpinLockUnlock(&This->lock);
1413 return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1416 This->event = event;
1418 OSSpinLockUnlock(&This->lock);
1423 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1426 ACImpl *This = impl_from_IAudioClient(iface);
1428 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1434 OSSpinLockLock(&This->lock);
1437 OSSpinLockUnlock(&This->lock);
1438 return AUDCLNT_E_NOT_INITIALIZED;
1441 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1442 if(This->dataflow != eRender){
1443 OSSpinLockUnlock(&This->lock);
1444 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1446 *ppv = &This->IAudioRenderClient_iface;
1447 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1448 if(This->dataflow != eCapture){
1449 OSSpinLockUnlock(&This->lock);
1450 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1452 *ppv = &This->IAudioCaptureClient_iface;
1453 }else if(IsEqualIID(riid, &IID_IAudioClock)){
1454 *ppv = &This->IAudioClock_iface;
1455 }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1456 *ppv = &This->IAudioStreamVolume_iface;
1457 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1458 if(!This->session_wrapper){
1459 This->session_wrapper = AudioSessionWrapper_Create(This);
1460 if(!This->session_wrapper){
1461 OSSpinLockUnlock(&This->lock);
1462 return E_OUTOFMEMORY;
1466 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1467 }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1468 if(!This->session_wrapper){
1469 This->session_wrapper = AudioSessionWrapper_Create(This);
1470 if(!This->session_wrapper){
1471 OSSpinLockUnlock(&This->lock);
1472 return E_OUTOFMEMORY;
1476 *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1477 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1478 if(!This->session_wrapper){
1479 This->session_wrapper = AudioSessionWrapper_Create(This);
1480 if(!This->session_wrapper){
1481 OSSpinLockUnlock(&This->lock);
1482 return E_OUTOFMEMORY;
1486 *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1490 IUnknown_AddRef((IUnknown*)*ppv);
1491 OSSpinLockUnlock(&This->lock);
1495 OSSpinLockUnlock(&This->lock);
1497 FIXME("stub %s\n", debugstr_guid(riid));
1498 return E_NOINTERFACE;
1501 static const IAudioClientVtbl AudioClient_Vtbl =
1503 AudioClient_QueryInterface,
1505 AudioClient_Release,
1506 AudioClient_Initialize,
1507 AudioClient_GetBufferSize,
1508 AudioClient_GetStreamLatency,
1509 AudioClient_GetCurrentPadding,
1510 AudioClient_IsFormatSupported,
1511 AudioClient_GetMixFormat,
1512 AudioClient_GetDevicePeriod,
1516 AudioClient_SetEventHandle,
1517 AudioClient_GetService
1520 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1521 IAudioRenderClient *iface, REFIID riid, void **ppv)
1523 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1529 if(IsEqualIID(riid, &IID_IUnknown) ||
1530 IsEqualIID(riid, &IID_IAudioRenderClient))
1533 IUnknown_AddRef((IUnknown*)*ppv);
1537 WARN("Unknown interface %s\n", debugstr_guid(riid));
1538 return E_NOINTERFACE;
1541 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1543 ACImpl *This = impl_from_IAudioRenderClient(iface);
1544 return AudioClient_AddRef(&This->IAudioClient_iface);
1547 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1549 ACImpl *This = impl_from_IAudioRenderClient(iface);
1550 return AudioClient_Release(&This->IAudioClient_iface);
1553 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1554 UINT32 frames, BYTE **data)
1556 ACImpl *This = impl_from_IAudioRenderClient(iface);
1558 UINT32 pad, bytes = frames * This->fmt->nBlockAlign;
1562 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1567 OSSpinLockLock(&This->lock);
1569 if(This->getbuf_last){
1570 OSSpinLockUnlock(&This->lock);
1571 return AUDCLNT_E_OUT_OF_ORDER;
1575 This->getbuf_last = TRUE;
1576 OSSpinLockUnlock(&This->lock);
1580 hr = AudioClient_GetCurrentPadding_nolock(This, &pad);
1582 OSSpinLockUnlock(&This->lock);
1586 if(pad + frames > This->bufsize_frames){
1587 OSSpinLockUnlock(&This->lock);
1588 return AUDCLNT_E_BUFFER_TOO_LARGE;
1591 LIST_FOR_EACH_ENTRY(buf, &This->avail_buffers, AQBuffer, entry){
1592 if(buf->buf->mAudioDataBytesCapacity >= bytes){
1593 This->public_buffer = buf->buf;
1594 list_remove(&buf->entry);
1599 if(&buf->entry == &This->avail_buffers){
1600 sc = AudioQueueAllocateBuffer(This->aqueue, bytes,
1601 &This->public_buffer);
1603 OSSpinLockUnlock(&This->lock);
1604 WARN("Unable to allocate buffer: %lx\n", sc);
1607 buf = HeapAlloc(GetProcessHeap(), 0, sizeof(AQBuffer));
1609 AudioQueueFreeBuffer(This->aqueue, This->public_buffer);
1610 This->public_buffer = NULL;
1611 OSSpinLockUnlock(&This->lock);
1612 return E_OUTOFMEMORY;
1614 buf->buf = This->public_buffer;
1615 This->public_buffer->mUserData = buf;
1618 *data = This->public_buffer->mAudioData;
1620 This->getbuf_last = TRUE;
1622 OSSpinLockUnlock(&This->lock);
1627 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1628 IAudioRenderClient *iface, UINT32 frames, DWORD flags)
1630 ACImpl *This = impl_from_IAudioRenderClient(iface);
1633 TRACE("(%p)->(%u, %x)\n", This, frames, flags);
1635 OSSpinLockLock(&This->lock);
1637 if(!This->getbuf_last){
1638 OSSpinLockUnlock(&This->lock);
1639 return AUDCLNT_E_OUT_OF_ORDER;
1642 if(flags & AUDCLNT_BUFFERFLAGS_SILENT){
1643 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)This->fmt;
1644 if((This->fmt->wFormatTag == WAVE_FORMAT_PCM ||
1645 (This->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1646 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) &&
1647 This->fmt->wBitsPerSample == 8)
1648 memset(This->public_buffer->mAudioData, 128,
1649 frames * This->fmt->nBlockAlign);
1651 memset(This->public_buffer->mAudioData, 0,
1652 frames * This->fmt->nBlockAlign);
1655 This->public_buffer->mAudioDataByteSize = frames * This->fmt->nBlockAlign;
1657 sc = AudioQueueEnqueueBuffer(This->aqueue, This->public_buffer, 0, NULL);
1659 OSSpinLockUnlock(&This->lock);
1660 WARN("Unable to enqueue buffer: %lx\n", sc);
1664 if(This->playing == StateStopped)
1665 AudioQueuePrime(This->aqueue, 0, NULL);
1667 This->public_buffer = NULL;
1668 This->getbuf_last = FALSE;
1669 This->written_frames += frames;
1670 This->inbuf_frames += frames;
1672 OSSpinLockUnlock(&This->lock);
1677 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1678 AudioRenderClient_QueryInterface,
1679 AudioRenderClient_AddRef,
1680 AudioRenderClient_Release,
1681 AudioRenderClient_GetBuffer,
1682 AudioRenderClient_ReleaseBuffer
1685 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1686 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1688 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1694 if(IsEqualIID(riid, &IID_IUnknown) ||
1695 IsEqualIID(riid, &IID_IAudioCaptureClient))
1698 IUnknown_AddRef((IUnknown*)*ppv);
1702 WARN("Unknown interface %s\n", debugstr_guid(riid));
1703 return E_NOINTERFACE;
1706 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1708 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1709 return IAudioClient_AddRef(&This->IAudioClient_iface);
1712 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1714 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1715 return IAudioClient_Release(&This->IAudioClient_iface);
1718 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1719 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1722 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1724 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1727 if(!data || !frames || !flags)
1730 OSSpinLockLock(&This->lock);
1732 if(This->getbuf_last){
1733 OSSpinLockUnlock(&This->lock);
1734 return AUDCLNT_E_OUT_OF_ORDER;
1737 if(This->public_buffer){
1738 *data = This->public_buffer->mAudioData;
1740 This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
1742 struct list *head = list_head(&This->avail_buffers);
1747 AQBuffer *buf = LIST_ENTRY(head, AQBuffer, entry);
1748 This->public_buffer = buf->buf;
1749 *data = This->public_buffer->mAudioData;
1751 This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
1752 list_remove(&buf->entry);
1757 This->written_frames += *frames;
1758 This->inbuf_frames -= *frames;
1759 This->getbuf_last = TRUE;
1761 if(devpos || qpcpos)
1762 AudioClock_GetPosition_nolock(This, devpos, qpcpos, FALSE);
1764 OSSpinLockUnlock(&This->lock);
1766 return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
1769 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1770 IAudioCaptureClient *iface, UINT32 done)
1772 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1773 UINT32 pbuf_frames =
1774 This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
1777 TRACE("(%p)->(%u)\n", This, done);
1779 OSSpinLockLock(&This->lock);
1781 if(!This->getbuf_last){
1782 OSSpinLockUnlock(&This->lock);
1783 return AUDCLNT_E_OUT_OF_ORDER;
1786 if(done != 0 && done != pbuf_frames){
1787 OSSpinLockUnlock(&This->lock);
1788 return AUDCLNT_E_INVALID_SIZE;
1792 sc = AudioQueueEnqueueBuffer(This->aqueue, This->public_buffer,
1795 WARN("Unable to enqueue buffer: %lx\n", sc);
1796 This->public_buffer = NULL;
1799 This->getbuf_last = FALSE;
1801 OSSpinLockUnlock(&This->lock);
1806 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1807 IAudioCaptureClient *iface, UINT32 *frames)
1809 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1813 TRACE("(%p)->(%p)\n", This, frames);
1818 OSSpinLockLock(&This->lock);
1820 head = list_head(&This->avail_buffers);
1823 *frames = This->bufsize_frames / CAPTURE_BUFFERS;
1824 OSSpinLockUnlock(&This->lock);
1828 buf = LIST_ENTRY(head, AQBuffer, entry);
1829 *frames = buf->buf->mAudioDataByteSize / This->fmt->nBlockAlign;
1831 OSSpinLockUnlock(&This->lock);
1836 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1838 AudioCaptureClient_QueryInterface,
1839 AudioCaptureClient_AddRef,
1840 AudioCaptureClient_Release,
1841 AudioCaptureClient_GetBuffer,
1842 AudioCaptureClient_ReleaseBuffer,
1843 AudioCaptureClient_GetNextPacketSize
1846 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1847 REFIID riid, void **ppv)
1849 ACImpl *This = impl_from_IAudioClock(iface);
1851 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1857 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
1859 else if(IsEqualIID(riid, &IID_IAudioClock2))
1860 *ppv = &This->IAudioClock2_iface;
1862 IUnknown_AddRef((IUnknown*)*ppv);
1866 WARN("Unknown interface %s\n", debugstr_guid(riid));
1867 return E_NOINTERFACE;
1870 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
1872 ACImpl *This = impl_from_IAudioClock(iface);
1873 return IAudioClient_AddRef(&This->IAudioClient_iface);
1876 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
1878 ACImpl *This = impl_from_IAudioClock(iface);
1879 return IAudioClient_Release(&This->IAudioClient_iface);
1882 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
1884 ACImpl *This = impl_from_IAudioClock(iface);
1886 TRACE("(%p)->(%p)\n", This, freq);
1888 *freq = This->fmt->nSamplesPerSec;
1893 static HRESULT AudioClock_GetPosition_nolock(ACImpl *This,
1894 UINT64 *pos, UINT64 *qpctime, BOOL raw)
1896 AudioTimeStamp time;
1899 sc = AudioQueueGetCurrentTime(This->aqueue, NULL, &time, NULL);
1900 if(sc == kAudioQueueErr_InvalidRunState){
1902 }else if(sc == noErr){
1903 if(!(time.mFlags & kAudioTimeStampSampleTimeValid)){
1904 FIXME("Sample time not valid, should calculate from something else\n");
1909 *pos = time.mSampleTime;
1911 *pos = time.mSampleTime - This->last_time;
1913 WARN("Unable to get current time: %lx\n", sc);
1918 LARGE_INTEGER stamp, freq;
1919 QueryPerformanceCounter(&stamp);
1920 QueryPerformanceFrequency(&freq);
1921 *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
1927 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
1930 ACImpl *This = impl_from_IAudioClock(iface);
1933 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
1938 OSSpinLockLock(&This->lock);
1940 hr = AudioClock_GetPosition_nolock(This, pos, qpctime, FALSE);
1942 OSSpinLockUnlock(&This->lock);
1947 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
1950 ACImpl *This = impl_from_IAudioClock(iface);
1952 TRACE("(%p)->(%p)\n", This, chars);
1957 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
1962 static const IAudioClockVtbl AudioClock_Vtbl =
1964 AudioClock_QueryInterface,
1967 AudioClock_GetFrequency,
1968 AudioClock_GetPosition,
1969 AudioClock_GetCharacteristics
1972 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
1973 REFIID riid, void **ppv)
1975 ACImpl *This = impl_from_IAudioClock2(iface);
1976 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
1979 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
1981 ACImpl *This = impl_from_IAudioClock2(iface);
1982 return IAudioClient_AddRef(&This->IAudioClient_iface);
1985 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
1987 ACImpl *This = impl_from_IAudioClock2(iface);
1988 return IAudioClient_Release(&This->IAudioClient_iface);
1991 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
1992 UINT64 *pos, UINT64 *qpctime)
1994 ACImpl *This = impl_from_IAudioClock2(iface);
1996 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
2001 static const IAudioClock2Vtbl AudioClock2_Vtbl =
2003 AudioClock2_QueryInterface,
2005 AudioClock2_Release,
2006 AudioClock2_GetDevicePosition
2009 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
2011 AudioSessionWrapper *ret;
2013 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2014 sizeof(AudioSessionWrapper));
2018 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
2019 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
2020 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
2022 ret->client = client;
2023 ret->session = client->session;
2024 AudioClient_AddRef(&client->IAudioClient_iface);
2029 static HRESULT WINAPI AudioSessionControl_QueryInterface(
2030 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
2032 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2038 if(IsEqualIID(riid, &IID_IUnknown) ||
2039 IsEqualIID(riid, &IID_IAudioSessionControl) ||
2040 IsEqualIID(riid, &IID_IAudioSessionControl2))
2043 IUnknown_AddRef((IUnknown*)*ppv);
2047 WARN("Unknown interface %s\n", debugstr_guid(riid));
2048 return E_NOINTERFACE;
2051 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
2053 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2055 ref = InterlockedIncrement(&This->ref);
2056 TRACE("(%p) Refcount now %u\n", This, ref);
2060 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
2062 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2064 ref = InterlockedDecrement(&This->ref);
2065 TRACE("(%p) Refcount now %u\n", This, ref);
2067 OSSpinLockLock(&This->client->lock);
2068 This->client->session_wrapper = NULL;
2069 OSSpinLockUnlock(&This->client->lock);
2070 AudioClient_Release(&This->client->IAudioClient_iface);
2071 HeapFree(GetProcessHeap(), 0, This);
2076 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
2077 AudioSessionState *state)
2079 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2082 TRACE("(%p)->(%p)\n", This, state);
2085 return NULL_PTR_ERR;
2087 EnterCriticalSection(&g_sessions_lock);
2089 if(list_empty(&This->session->clients)){
2090 *state = AudioSessionStateExpired;
2091 LeaveCriticalSection(&g_sessions_lock);
2095 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
2096 OSSpinLockLock(&client->lock);
2097 if(client->playing == StatePlaying ||
2098 client->playing == StateInTransition){
2099 *state = AudioSessionStateActive;
2100 OSSpinLockUnlock(&client->lock);
2101 LeaveCriticalSection(&g_sessions_lock);
2104 OSSpinLockUnlock(&client->lock);
2107 LeaveCriticalSection(&g_sessions_lock);
2109 *state = AudioSessionStateInactive;
2114 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
2115 IAudioSessionControl2 *iface, WCHAR **name)
2117 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2119 FIXME("(%p)->(%p) - stub\n", This, name);
2124 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
2125 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
2127 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2129 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
2134 static HRESULT WINAPI AudioSessionControl_GetIconPath(
2135 IAudioSessionControl2 *iface, WCHAR **path)
2137 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2139 FIXME("(%p)->(%p) - stub\n", This, path);
2144 static HRESULT WINAPI AudioSessionControl_SetIconPath(
2145 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
2147 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2149 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
2154 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
2155 IAudioSessionControl2 *iface, GUID *group)
2157 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2159 FIXME("(%p)->(%p) - stub\n", This, group);
2164 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
2165 IAudioSessionControl2 *iface, GUID *group, const GUID *session)
2167 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2169 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
2170 debugstr_guid(session));
2175 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
2176 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2178 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2180 FIXME("(%p)->(%p) - stub\n", This, events);
2185 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
2186 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2188 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2190 FIXME("(%p)->(%p) - stub\n", This, events);
2195 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
2196 IAudioSessionControl2 *iface, WCHAR **id)
2198 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2200 FIXME("(%p)->(%p) - stub\n", This, id);
2205 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
2206 IAudioSessionControl2 *iface, WCHAR **id)
2208 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2210 FIXME("(%p)->(%p) - stub\n", This, id);
2215 static HRESULT WINAPI AudioSessionControl_GetProcessId(
2216 IAudioSessionControl2 *iface, DWORD *pid)
2218 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2220 TRACE("(%p)->(%p)\n", This, pid);
2225 *pid = GetCurrentProcessId();
2230 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
2231 IAudioSessionControl2 *iface)
2233 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2235 TRACE("(%p)\n", This);
2240 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
2241 IAudioSessionControl2 *iface, BOOL optout)
2243 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2245 TRACE("(%p)->(%d)\n", This, optout);
2250 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
2252 AudioSessionControl_QueryInterface,
2253 AudioSessionControl_AddRef,
2254 AudioSessionControl_Release,
2255 AudioSessionControl_GetState,
2256 AudioSessionControl_GetDisplayName,
2257 AudioSessionControl_SetDisplayName,
2258 AudioSessionControl_GetIconPath,
2259 AudioSessionControl_SetIconPath,
2260 AudioSessionControl_GetGroupingParam,
2261 AudioSessionControl_SetGroupingParam,
2262 AudioSessionControl_RegisterAudioSessionNotification,
2263 AudioSessionControl_UnregisterAudioSessionNotification,
2264 AudioSessionControl_GetSessionIdentifier,
2265 AudioSessionControl_GetSessionInstanceIdentifier,
2266 AudioSessionControl_GetProcessId,
2267 AudioSessionControl_IsSystemSoundsSession,
2268 AudioSessionControl_SetDuckingPreference
2271 /* index == -1 means set all channels, otherwise sets only the given channel */
2272 static HRESULT ca_setvol(ACImpl *This, UINT32 index)
2274 AudioObjectPropertyAddress addr;
2278 if(index == (UINT32)-1){
2281 for(i = 0; i < This->fmt->nChannels; ++i){
2283 hr = ca_setvol(This, i);
2290 level = This->session->master_vol * This->session->channel_vols[index] *
2293 addr.mScope = This->scope;
2294 addr.mSelector = kAudioDevicePropertyVolumeScalar;
2295 addr.mElement = index + 1;
2297 sc = AudioObjectSetPropertyData(This->adevid, &addr, 0, NULL,
2298 sizeof(float), &level);
2300 WARN("Setting _VolumeScalar property failed: %lx\n", sc);
2307 static HRESULT ca_session_setvol(AudioSession *session, UINT32 index)
2312 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry){
2314 hr = ca_setvol(client, index);
2322 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
2323 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
2325 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2331 if(IsEqualIID(riid, &IID_IUnknown) ||
2332 IsEqualIID(riid, &IID_ISimpleAudioVolume))
2335 IUnknown_AddRef((IUnknown*)*ppv);
2339 WARN("Unknown interface %s\n", debugstr_guid(riid));
2340 return E_NOINTERFACE;
2343 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
2345 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2346 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2349 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
2351 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2352 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2355 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
2356 ISimpleAudioVolume *iface, float level, const GUID *context)
2358 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2359 AudioSession *session = This->session;
2362 TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
2364 if(level < 0.f || level > 1.f)
2365 return E_INVALIDARG;
2368 FIXME("Notifications not supported yet\n");
2370 EnterCriticalSection(&session->lock);
2372 session->master_vol = level;
2374 ret = ca_session_setvol(session, -1);
2376 LeaveCriticalSection(&session->lock);
2381 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
2382 ISimpleAudioVolume *iface, float *level)
2384 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2385 AudioSession *session = This->session;
2387 TRACE("(%p)->(%p)\n", session, level);
2390 return NULL_PTR_ERR;
2392 *level = session->master_vol;
2397 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
2398 BOOL mute, const GUID *context)
2400 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2401 AudioSession *session = This->session;
2403 FIXME("(%p)->(%u, %p) - stub\n", session, mute, context);
2408 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
2411 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2412 AudioSession *session = This->session;
2414 FIXME("(%p)->(%p) - stub\n", session, mute);
2417 return NULL_PTR_ERR;
2422 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
2424 SimpleAudioVolume_QueryInterface,
2425 SimpleAudioVolume_AddRef,
2426 SimpleAudioVolume_Release,
2427 SimpleAudioVolume_SetMasterVolume,
2428 SimpleAudioVolume_GetMasterVolume,
2429 SimpleAudioVolume_SetMute,
2430 SimpleAudioVolume_GetMute
2433 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
2434 IAudioStreamVolume *iface, REFIID riid, void **ppv)
2436 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2442 if(IsEqualIID(riid, &IID_IUnknown) ||
2443 IsEqualIID(riid, &IID_IAudioStreamVolume))
2446 IUnknown_AddRef((IUnknown*)*ppv);
2450 WARN("Unknown interface %s\n", debugstr_guid(riid));
2451 return E_NOINTERFACE;
2454 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
2456 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2457 return IAudioClient_AddRef(&This->IAudioClient_iface);
2460 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
2462 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2463 return IAudioClient_Release(&This->IAudioClient_iface);
2466 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
2467 IAudioStreamVolume *iface, UINT32 *out)
2469 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2471 TRACE("(%p)->(%p)\n", This, out);
2476 *out = This->fmt->nChannels;
2481 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
2482 IAudioStreamVolume *iface, UINT32 index, float level)
2484 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2487 TRACE("(%p)->(%d, %f)\n", This, index, level);
2489 if(level < 0.f || level > 1.f)
2490 return E_INVALIDARG;
2492 if(index >= This->fmt->nChannels)
2493 return E_INVALIDARG;
2495 OSSpinLockLock(&This->lock);
2497 This->vols[index] = level;
2499 ret = ca_setvol(This, index);
2501 OSSpinLockUnlock(&This->lock);
2506 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2507 IAudioStreamVolume *iface, UINT32 index, float *level)
2509 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2511 TRACE("(%p)->(%d, %p)\n", This, index, level);
2516 if(index >= This->fmt->nChannels)
2517 return E_INVALIDARG;
2519 *level = This->vols[index];
2524 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2525 IAudioStreamVolume *iface, UINT32 count, const float *levels)
2527 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2531 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2536 if(count != This->fmt->nChannels)
2537 return E_INVALIDARG;
2539 OSSpinLockLock(&This->lock);
2541 for(i = 0; i < count; ++i)
2542 This->vols[i] = levels[i];
2544 ret = ca_setvol(This, -1);
2546 OSSpinLockUnlock(&This->lock);
2551 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2552 IAudioStreamVolume *iface, UINT32 count, float *levels)
2554 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2557 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2562 if(count != This->fmt->nChannels)
2563 return E_INVALIDARG;
2565 OSSpinLockLock(&This->lock);
2567 for(i = 0; i < count; ++i)
2568 levels[i] = This->vols[i];
2570 OSSpinLockUnlock(&This->lock);
2575 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2577 AudioStreamVolume_QueryInterface,
2578 AudioStreamVolume_AddRef,
2579 AudioStreamVolume_Release,
2580 AudioStreamVolume_GetChannelCount,
2581 AudioStreamVolume_SetChannelVolume,
2582 AudioStreamVolume_GetChannelVolume,
2583 AudioStreamVolume_SetAllVolumes,
2584 AudioStreamVolume_GetAllVolumes
2587 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2588 IChannelAudioVolume *iface, REFIID riid, void **ppv)
2590 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2596 if(IsEqualIID(riid, &IID_IUnknown) ||
2597 IsEqualIID(riid, &IID_IChannelAudioVolume))
2600 IUnknown_AddRef((IUnknown*)*ppv);
2604 WARN("Unknown interface %s\n", debugstr_guid(riid));
2605 return E_NOINTERFACE;
2608 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2610 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2611 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2614 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2616 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2617 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2620 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2621 IChannelAudioVolume *iface, UINT32 *out)
2623 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2624 AudioSession *session = This->session;
2626 TRACE("(%p)->(%p)\n", session, out);
2629 return NULL_PTR_ERR;
2631 *out = session->channel_count;
2636 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2637 IChannelAudioVolume *iface, UINT32 index, float level,
2638 const GUID *context)
2640 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2641 AudioSession *session = This->session;
2644 TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2645 wine_dbgstr_guid(context));
2647 if(level < 0.f || level > 1.f)
2648 return E_INVALIDARG;
2650 if(index >= session->channel_count)
2651 return E_INVALIDARG;
2654 FIXME("Notifications not supported yet\n");
2656 EnterCriticalSection(&session->lock);
2658 session->channel_vols[index] = level;
2660 ret = ca_session_setvol(session, index);
2662 LeaveCriticalSection(&session->lock);
2667 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2668 IChannelAudioVolume *iface, UINT32 index, float *level)
2670 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2671 AudioSession *session = This->session;
2673 TRACE("(%p)->(%d, %p)\n", session, index, level);
2676 return NULL_PTR_ERR;
2678 if(index >= session->channel_count)
2679 return E_INVALIDARG;
2681 *level = session->channel_vols[index];
2686 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2687 IChannelAudioVolume *iface, UINT32 count, const float *levels,
2688 const GUID *context)
2690 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2691 AudioSession *session = This->session;
2695 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2696 wine_dbgstr_guid(context));
2699 return NULL_PTR_ERR;
2701 if(count != session->channel_count)
2702 return E_INVALIDARG;
2705 FIXME("Notifications not supported yet\n");
2707 EnterCriticalSection(&session->lock);
2709 for(i = 0; i < count; ++i)
2710 session->channel_vols[i] = levels[i];
2712 ret = ca_session_setvol(session, -1);
2714 LeaveCriticalSection(&session->lock);
2719 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2720 IChannelAudioVolume *iface, UINT32 count, float *levels)
2722 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2723 AudioSession *session = This->session;
2726 TRACE("(%p)->(%d, %p)\n", session, count, levels);
2729 return NULL_PTR_ERR;
2731 if(count != session->channel_count)
2732 return E_INVALIDARG;
2734 for(i = 0; i < count; ++i)
2735 levels[i] = session->channel_vols[i];
2740 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2742 ChannelAudioVolume_QueryInterface,
2743 ChannelAudioVolume_AddRef,
2744 ChannelAudioVolume_Release,
2745 ChannelAudioVolume_GetChannelCount,
2746 ChannelAudioVolume_SetChannelVolume,
2747 ChannelAudioVolume_GetChannelVolume,
2748 ChannelAudioVolume_SetAllVolumes,
2749 ChannelAudioVolume_GetAllVolumes