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 {
85 typedef struct _AudioSessionWrapper {
86 IAudioSessionControl2 IAudioSessionControl2_iface;
91 AudioSession *session;
92 } AudioSessionWrapper;
95 IAudioClient IAudioClient_iface;
96 IAudioRenderClient IAudioRenderClient_iface;
97 IAudioCaptureClient IAudioCaptureClient_iface;
98 ISimpleAudioVolume ISimpleAudioVolume_iface;
99 IAudioClock IAudioClock_iface;
100 IAudioClock2 IAudioClock2_iface;
110 AUDCLNT_SHAREMODE share;
113 AudioDeviceID adevid;
114 AudioQueueRef aqueue;
116 UINT32 period_ms, bufsize_frames, inbuf_frames, written_frames;
118 AudioQueueBufferRef public_buffer;
122 AudioSession *session;
123 AudioSessionWrapper *session_wrapper;
127 struct list avail_buffers;
129 /* We can't use debug printing or {Enter,Leave}CriticalSection from
130 * OSX callback threads, so we use OSX's OSSpinLock for synchronization
131 * instead. OSSpinLock is not a recursive lock, so don't call
132 * synchronized functions while holding the lock. */
142 static const IAudioClientVtbl AudioClient_Vtbl;
143 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
144 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
145 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
146 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
147 static const IAudioClockVtbl AudioClock_Vtbl;
148 static const IAudioClock2Vtbl AudioClock2_Vtbl;
150 static HANDLE g_timer_q;
152 static CRITICAL_SECTION g_sessions_lock;
153 static struct list g_sessions = LIST_INIT(g_sessions);
155 static HRESULT AudioClock_GetPosition_nolock(ACImpl *This, UINT64 *pos,
156 UINT64 *qpctime, BOOL raw);
157 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
159 static inline ACImpl *impl_from_IAudioClient(IAudioClient *iface)
161 return CONTAINING_RECORD(iface, ACImpl, IAudioClient_iface);
164 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
166 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
169 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
171 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
174 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
176 return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
179 static inline ACImpl *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
181 return CONTAINING_RECORD(iface, ACImpl, ISimpleAudioVolume_iface);
184 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
186 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
189 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
191 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
194 BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
196 if(reason == DLL_PROCESS_ATTACH){
197 g_timer_q = CreateTimerQueue();
201 InitializeCriticalSection(&g_sessions_lock);
207 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids,
208 AudioDeviceID ***keys, UINT *num, UINT *def_index)
210 UInt32 devsize, size;
211 AudioDeviceID *devices;
212 AudioDeviceID default_id;
213 AudioObjectPropertyAddress addr;
217 TRACE("%d %p %p %p\n", flow, ids, num, def_index);
219 addr.mScope = kAudioObjectPropertyScopeGlobal;
220 addr.mElement = kAudioObjectPropertyElementMaster;
222 addr.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
223 else if(flow == eCapture)
224 addr.mSelector = kAudioHardwarePropertyDefaultInputDevice;
228 size = sizeof(default_id);
229 sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0,
230 NULL, &size, &default_id);
232 WARN("Getting _DefaultInputDevice property failed: %lx\n", sc);
236 addr.mSelector = kAudioHardwarePropertyDevices;
237 sc = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &addr, 0,
240 WARN("Getting _Devices property size failed: %lx\n", sc);
244 devices = HeapAlloc(GetProcessHeap(), 0, devsize);
246 return E_OUTOFMEMORY;
248 sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0, NULL,
251 WARN("Getting _Devices property failed: %lx\n", sc);
252 HeapFree(GetProcessHeap(), 0, devices);
256 ndevices = devsize / sizeof(AudioDeviceID);
258 *ids = HeapAlloc(GetProcessHeap(), 0, ndevices * sizeof(WCHAR *));
260 HeapFree(GetProcessHeap(), 0, devices);
261 return E_OUTOFMEMORY;
264 *keys = HeapAlloc(GetProcessHeap(), 0, ndevices * sizeof(AudioDeviceID *));
266 HeapFree(GetProcessHeap(), 0, *ids);
267 HeapFree(GetProcessHeap(), 0, devices);
268 return E_OUTOFMEMORY;
272 *def_index = (UINT)-1;
273 for(i = 0; i < ndevices; ++i){
274 AudioBufferList *buffers;
280 addr.mSelector = kAudioDevicePropertyStreamConfiguration;
282 addr.mScope = kAudioDevicePropertyScopeOutput;
284 addr.mScope = kAudioDevicePropertyScopeInput;
286 sc = AudioObjectGetPropertyDataSize(devices[i], &addr, 0, NULL, &size);
288 WARN("Unable to get _StreamConfiguration property size for "
289 "device %lu: %lx\n", devices[i], sc);
293 buffers = HeapAlloc(GetProcessHeap(), 0, size);
295 HeapFree(GetProcessHeap(), 0, devices);
296 for(j = 0; j < *num; ++j)
297 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
298 HeapFree(GetProcessHeap(), 0, *keys);
299 HeapFree(GetProcessHeap(), 0, *ids);
300 return E_OUTOFMEMORY;
303 sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL,
306 WARN("Unable to get _StreamConfiguration property for "
307 "device %lu: %lx\n", devices[i], sc);
308 HeapFree(GetProcessHeap(), 0, buffers);
312 /* check that there's at least one channel in this device before
313 * we claim it as usable */
314 for(j = 0; j < buffers->mNumberBuffers; ++j)
315 if(buffers->mBuffers[j].mNumberChannels > 0)
317 if(j >= buffers->mNumberBuffers){
318 HeapFree(GetProcessHeap(), 0, buffers);
322 HeapFree(GetProcessHeap(), 0, buffers);
325 addr.mSelector = kAudioObjectPropertyName;
326 sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL,
329 WARN("Unable to get _Name property for device %lu: %lx\n",
334 if(!CFStringGetCString(name, nameA, sizeof(nameA),
335 kCFStringEncodingUTF8)){
336 WARN("Error converting string to UTF8\n");
343 len = MultiByteToWideChar(CP_UNIXCP, 0, nameA, -1, NULL, 0);
344 (*ids)[*num] = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
346 HeapFree(GetProcessHeap(), 0, devices);
347 for(j = 0; j < *num; ++j){
348 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
349 HeapFree(GetProcessHeap(), 0, (*keys)[j]);
351 HeapFree(GetProcessHeap(), 0, *ids);
352 HeapFree(GetProcessHeap(), 0, *keys);
353 return E_OUTOFMEMORY;
355 MultiByteToWideChar(CP_UNIXCP, 0, nameA, -1, (*ids)[*num], len);
357 (*keys)[*num] = HeapAlloc(GetProcessHeap(), 0, sizeof(AudioDeviceID));
359 HeapFree(GetProcessHeap(), 0, devices);
360 HeapFree(GetProcessHeap(), 0, (*ids)[*num]);
361 for(j = 0; j < *num; ++j){
362 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
363 HeapFree(GetProcessHeap(), 0, (*keys)[j]);
365 HeapFree(GetProcessHeap(), 0, *ids);
366 HeapFree(GetProcessHeap(), 0, *keys);
367 return E_OUTOFMEMORY;
369 *(*keys)[*num] = devices[i];
371 if(*def_index == (UINT)-1 && devices[i] == default_id)
377 if(*def_index == (UINT)-1)
380 HeapFree(GetProcessHeap(), 0, devices);
385 HRESULT WINAPI AUDDRV_GetAudioEndpoint(AudioDeviceID *adevid, IMMDevice *dev,
386 EDataFlow dataflow, IAudioClient **out)
390 TRACE("%p %d %p\n", dev, dataflow, out);
392 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACImpl));
394 return E_OUTOFMEMORY;
396 This->IAudioClient_iface.lpVtbl = &AudioClient_Vtbl;
397 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
398 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
399 This->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
400 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
401 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
403 This->dataflow = dataflow;
408 IMMDevice_AddRef(This->parent);
410 list_init(&This->avail_buffers);
412 This->adevid = *adevid;
414 *out = &This->IAudioClient_iface;
415 IAudioClient_AddRef(&This->IAudioClient_iface);
420 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient *iface,
421 REFIID riid, void **ppv)
423 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
428 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClient))
431 IUnknown_AddRef((IUnknown*)*ppv);
434 WARN("Unknown interface %s\n", debugstr_guid(riid));
435 return E_NOINTERFACE;
438 static ULONG WINAPI AudioClient_AddRef(IAudioClient *iface)
440 ACImpl *This = impl_from_IAudioClient(iface);
442 ref = InterlockedIncrement(&This->ref);
443 TRACE("(%p) Refcount now %u\n", This, ref);
447 static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
449 ACImpl *This = impl_from_IAudioClient(iface);
451 ref = InterlockedDecrement(&This->ref);
452 TRACE("(%p) Refcount now %u\n", This, ref);
454 IAudioClient_Stop(iface);
456 AudioQueueDispose(This->aqueue, 1);
458 EnterCriticalSection(&g_sessions_lock);
459 list_remove(&This->entry);
460 if(list_empty(&This->session->clients)){
461 list_remove(&This->session->entry);
462 HeapFree(GetProcessHeap(), 0, This->session);
464 LeaveCriticalSection(&g_sessions_lock);
466 HeapFree(GetProcessHeap(), 0, This->public_buffer);
467 CoTaskMemFree(This->fmt);
468 IMMDevice_Release(This->parent);
469 HeapFree(GetProcessHeap(), 0, This);
474 static void dump_fmt(const WAVEFORMATEX *fmt)
476 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
477 switch(fmt->wFormatTag){
478 case WAVE_FORMAT_PCM:
479 TRACE("WAVE_FORMAT_PCM");
481 case WAVE_FORMAT_IEEE_FLOAT:
482 TRACE("WAVE_FORMAT_IEEE_FLOAT");
484 case WAVE_FORMAT_EXTENSIBLE:
485 TRACE("WAVE_FORMAT_EXTENSIBLE");
493 TRACE("nChannels: %u\n", fmt->nChannels);
494 TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
495 TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
496 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
497 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
498 TRACE("cbSize: %u\n", fmt->cbSize);
500 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
501 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
502 TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
503 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
504 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
508 static DWORD get_channel_mask(unsigned int channels)
514 return SPEAKER_FRONT_CENTER;
516 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
518 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT |
519 SPEAKER_LOW_FREQUENCY;
521 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
524 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
525 SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY;
527 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
528 SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER;
530 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
531 SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER |
534 FIXME("Unknown speaker configuration: %u\n", channels);
538 static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
543 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
544 size = sizeof(WAVEFORMATEXTENSIBLE);
546 size = sizeof(WAVEFORMATEX);
548 ret = CoTaskMemAlloc(size);
552 memcpy(ret, fmt, size);
554 ret->cbSize = size - sizeof(WAVEFORMATEX);
559 static HRESULT ca_get_audiodesc(AudioStreamBasicDescription *desc,
560 const WAVEFORMATEX *fmt)
562 const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)fmt;
564 if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
565 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
566 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
567 desc->mFormatID = kAudioFormatLinearPCM;
568 if(fmt->wBitsPerSample > 8)
569 desc->mFormatFlags = kAudioFormatFlagIsSignedInteger;
570 }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
571 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
572 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
573 desc->mFormatID = kAudioFormatLinearPCM;
574 desc->mFormatFlags = kAudioFormatFlagIsFloat;
575 }else if(fmt->wFormatTag == WAVE_FORMAT_MULAW ||
576 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
577 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_MULAW))){
578 desc->mFormatID = kAudioFormatULaw;
579 }else if(fmt->wFormatTag == WAVE_FORMAT_ALAW ||
580 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
581 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_ALAW))){
582 desc->mFormatID = kAudioFormatALaw;
584 return AUDCLNT_E_UNSUPPORTED_FORMAT;
586 desc->mSampleRate = fmt->nSamplesPerSec;
587 desc->mBytesPerPacket = fmt->nBlockAlign;
588 desc->mFramesPerPacket = 1;
589 desc->mBytesPerFrame = fmt->nBlockAlign;
590 desc->mChannelsPerFrame = fmt->nChannels;
591 desc->mBitsPerChannel = fmt->wBitsPerSample;
597 static void ca_out_buffer_cb(void *user, AudioQueueRef aqueue,
598 AudioQueueBufferRef buffer)
601 AQBuffer *buf = buffer->mUserData;
603 OSSpinLockLock(&This->lock);
604 list_add_tail(&This->avail_buffers, &buf->entry);
605 This->inbuf_frames -= buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
606 OSSpinLockUnlock(&This->lock);
609 static void ca_in_buffer_cb(void *user, AudioQueueRef aqueue,
610 AudioQueueBufferRef buffer, const AudioTimeStamp *start,
611 UInt32 ndesc, const AudioStreamPacketDescription *descs)
614 AQBuffer *buf = buffer->mUserData;
616 OSSpinLockLock(&This->lock);
617 list_add_tail(&This->avail_buffers, &buf->entry);
618 This->inbuf_frames += buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
619 OSSpinLockUnlock(&This->lock);
622 static HRESULT ca_setup_aqueue(AudioDeviceID did, EDataFlow flow,
623 const WAVEFORMATEX *fmt, void *user, AudioQueueRef *aqueue)
625 AudioStreamBasicDescription desc;
626 AudioObjectPropertyAddress addr;
632 addr.mScope = kAudioObjectPropertyScopeGlobal;
634 addr.mSelector = kAudioDevicePropertyDeviceUID;
637 sc = AudioObjectGetPropertyData(did, &addr, 0, NULL, &size, &uid);
639 WARN("Unable to get _DeviceUID property: %lx\n", sc);
643 hr = ca_get_audiodesc(&desc, fmt);
650 sc = AudioQueueNewOutput(&desc, ca_out_buffer_cb, user, NULL, NULL, 0,
652 else if(flow == eCapture)
653 sc = AudioQueueNewInput(&desc, ca_in_buffer_cb, user, NULL, NULL, 0,
660 WARN("Unable to create AudioQueue: %lx\n", sc);
665 sc = AudioQueueSetProperty(*aqueue, kAudioQueueProperty_CurrentDevice,
677 static AudioSession *create_session(const GUID *guid, EDataFlow flow)
681 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
685 memcpy(&ret->guid, guid, sizeof(GUID));
687 ret->dataflow = flow;
689 list_init(&ret->clients);
691 list_add_head(&g_sessions, &ret->entry);
696 static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
697 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
698 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
699 const GUID *sessionguid)
701 ACImpl *This = impl_from_IAudioClient(iface);
705 TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
706 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
713 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
714 return AUDCLNT_E_NOT_INITIALIZED;
716 if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
717 AUDCLNT_STREAMFLAGS_LOOPBACK |
718 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
719 AUDCLNT_STREAMFLAGS_NOPERSIST |
720 AUDCLNT_STREAMFLAGS_RATEADJUST |
721 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
722 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
723 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED)){
724 TRACE("Unknown flags: %08x\n", flags);
728 OSSpinLockLock(&This->lock);
731 OSSpinLockUnlock(&This->lock);
732 return AUDCLNT_E_ALREADY_INITIALIZED;
735 hr = ca_setup_aqueue(This->adevid, This->dataflow, fmt, This, &This->aqueue);
737 OSSpinLockUnlock(&This->lock);
741 This->fmt = clone_format(fmt);
743 AudioQueueDispose(This->aqueue, 1);
745 OSSpinLockUnlock(&This->lock);
746 return E_OUTOFMEMORY;
750 This->period_ms = period / 10000;
751 if(This->period_ms == 0)
754 This->period_ms = MinimumPeriod / 10000;
756 This->bufsize_frames = ceil(fmt->nSamplesPerSec * (duration / 10000000.));
758 if(This->dataflow == eCapture){
760 UInt32 bsize = ceil((This->bufsize_frames / (double)CAPTURE_BUFFERS) *
761 This->fmt->nBlockAlign);
762 for(i = 0; i < CAPTURE_BUFFERS; ++i){
765 buf = HeapAlloc(GetProcessHeap(), 0, sizeof(AQBuffer));
767 AudioQueueDispose(This->aqueue, 1);
769 CoTaskMemFree(This->fmt);
771 OSSpinLockUnlock(&This->lock);
772 return E_OUTOFMEMORY;
775 sc = AudioQueueAllocateBuffer(This->aqueue, bsize, &buf->buf);
777 AudioQueueDispose(This->aqueue, 1);
779 CoTaskMemFree(This->fmt);
781 OSSpinLockUnlock(&This->lock);
782 WARN("Couldn't allocate buffer: %lx\n", sc);
786 buf->buf->mUserData = buf;
788 sc = AudioQueueEnqueueBuffer(This->aqueue, buf->buf, 0, NULL);
790 ERR("Couldn't enqueue buffer: %lx\n", sc);
799 EnterCriticalSection(&g_sessions_lock);
801 if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
802 This->session = create_session(&GUID_NULL, This->dataflow);
804 LeaveCriticalSection(&g_sessions_lock);
805 AudioQueueDispose(This->aqueue, 1);
807 CoTaskMemFree(This->fmt);
809 OSSpinLockUnlock(&This->lock);
810 return E_OUTOFMEMORY;
813 AudioSession *session;
815 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry)
816 if(IsEqualGUID(sessionguid, &session->guid) &&
817 This->dataflow == session->dataflow)
818 This->session = session;
821 This->session = create_session(sessionguid, This->dataflow);
823 LeaveCriticalSection(&g_sessions_lock);
824 AudioQueueDispose(This->aqueue, 1);
826 CoTaskMemFree(This->fmt);
828 OSSpinLockUnlock(&This->lock);
829 return E_OUTOFMEMORY;
834 list_add_tail(&This->session->clients, &This->entry);
836 LeaveCriticalSection(&g_sessions_lock);
838 OSSpinLockUnlock(&This->lock);
843 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
846 ACImpl *This = impl_from_IAudioClient(iface);
848 TRACE("(%p)->(%p)\n", This, frames);
853 OSSpinLockLock(&This->lock);
856 OSSpinLockUnlock(&This->lock);
857 return AUDCLNT_E_NOT_INITIALIZED;
860 *frames = This->bufsize_frames;
862 OSSpinLockUnlock(&This->lock);
867 static HRESULT ca_get_max_stream_latency(ACImpl *This, UInt32 *max)
869 AudioObjectPropertyAddress addr;
875 if(This->dataflow == eRender)
876 addr.mScope = kAudioDevicePropertyScopeOutput;
877 else if(This->dataflow == eCapture)
878 addr.mScope = kAudioDevicePropertyScopeInput;
882 addr.mSelector = kAudioDevicePropertyStreams;
884 sc = AudioObjectGetPropertyDataSize(This->adevid, &addr, 0, NULL,
887 WARN("Unable to get size for _Streams property: %lx\n", sc);
891 ids = HeapAlloc(GetProcessHeap(), 0, size);
893 return E_OUTOFMEMORY;
895 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL, &size, ids);
897 WARN("Unable to get _Streams property: %lx\n", sc);
898 HeapFree(GetProcessHeap(), 0, ids);
902 nstreams = size / sizeof(AudioStreamID);
905 addr.mSelector = kAudioStreamPropertyLatency;
906 for(i = 0; i < nstreams; ++i){
909 size = sizeof(latency);
910 sc = AudioObjectGetPropertyData(ids[i], &addr, 0, NULL,
913 WARN("Unable to get _Latency property: %lx\n", sc);
921 HeapFree(GetProcessHeap(), 0, ids);
926 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
929 ACImpl *This = impl_from_IAudioClient(iface);
930 UInt32 latency, stream_latency, size;
931 AudioObjectPropertyAddress addr;
935 TRACE("(%p)->(%p)\n", This, out);
940 OSSpinLockLock(&This->lock);
943 OSSpinLockUnlock(&This->lock);
944 return AUDCLNT_E_NOT_INITIALIZED;
947 if(This->dataflow == eRender)
948 addr.mScope = kAudioDevicePropertyScopeOutput;
949 else if(This->dataflow == eCapture)
950 addr.mScope = kAudioDevicePropertyScopeInput;
952 OSSpinLockUnlock(&This->lock);
955 addr.mSelector = kAudioDevicePropertyLatency;
958 size = sizeof(latency);
959 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL,
962 WARN("Couldn't get _Latency property: %lx\n", sc);
963 OSSpinLockUnlock(&This->lock);
967 hr = ca_get_max_stream_latency(This, &stream_latency);
969 OSSpinLockUnlock(&This->lock);
973 latency += stream_latency;
974 *out = (latency / (double)This->fmt->nSamplesPerSec) * 10000000;
976 OSSpinLockUnlock(&This->lock);
981 static HRESULT AudioClient_GetCurrentPadding_nolock(ACImpl *This,
985 return AUDCLNT_E_NOT_INITIALIZED;
987 *numpad = This->inbuf_frames;
992 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
995 ACImpl *This = impl_from_IAudioClient(iface);
998 TRACE("(%p)->(%p)\n", This, numpad);
1003 OSSpinLockLock(&This->lock);
1005 hr = AudioClient_GetCurrentPadding_nolock(This, numpad);
1007 OSSpinLockUnlock(&This->lock);
1012 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
1013 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
1014 WAVEFORMATEX **outpwfx)
1016 ACImpl *This = impl_from_IAudioClient(iface);
1017 AudioQueueRef aqueue;
1020 TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx);
1022 if(!pwfx || (mode == AUDCLNT_SHAREMODE_SHARED && !outpwfx))
1025 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1026 return E_INVALIDARG;
1028 if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1029 pwfx->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1030 return E_INVALIDARG;
1034 OSSpinLockLock(&This->lock);
1036 hr = ca_setup_aqueue(This->adevid, This->dataflow, pwfx, NULL, &aqueue);
1038 AudioQueueDispose(aqueue, 1);
1039 OSSpinLockUnlock(&This->lock);
1042 TRACE("returning %08x\n", S_OK);
1046 OSSpinLockUnlock(&This->lock);
1051 TRACE("returning %08x\n", AUDCLNT_E_UNSUPPORTED_FORMAT);
1052 return AUDCLNT_E_UNSUPPORTED_FORMAT;
1055 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
1056 WAVEFORMATEX **pwfx)
1058 ACImpl *This = impl_from_IAudioClient(iface);
1059 WAVEFORMATEXTENSIBLE *fmt;
1063 AudioBufferList *buffers;
1064 AudioObjectPropertyAddress addr;
1067 TRACE("(%p)->(%p)\n", This, pwfx);
1072 *pwfx = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEXTENSIBLE));
1074 return E_OUTOFMEMORY;
1076 fmt = (WAVEFORMATEXTENSIBLE*)*pwfx;
1078 fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1080 if(This->dataflow == eRender)
1081 addr.mScope = kAudioDevicePropertyScopeOutput;
1082 else if(This->dataflow == eCapture)
1083 addr.mScope = kAudioDevicePropertyScopeInput;
1085 OSSpinLockUnlock(&This->lock);
1086 return E_UNEXPECTED;
1089 addr.mSelector = kAudioDevicePropertyStreamConfiguration;
1091 sc = AudioObjectGetPropertyDataSize(This->adevid, &addr, 0, NULL, &size);
1093 HeapFree(GetProcessHeap(), 0, fmt);
1094 WARN("Unable to get size for _StreamConfiguration property: %lx\n", sc);
1098 buffers = HeapAlloc(GetProcessHeap(), 0, size);
1100 HeapFree(GetProcessHeap(), 0, fmt);
1101 return E_OUTOFMEMORY;
1104 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL,
1107 HeapFree(GetProcessHeap(), 0, fmt);
1108 HeapFree(GetProcessHeap(), 0, buffers);
1109 WARN("Unable to get _StreamConfiguration property: %lx\n", sc);
1113 fmt->Format.nChannels = 0;
1114 for(i = 0; i < buffers->mNumberBuffers; ++i)
1115 fmt->Format.nChannels += buffers->mBuffers[i].mNumberChannels;
1117 HeapFree(GetProcessHeap(), 0, buffers);
1119 fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
1121 addr.mSelector = kAudioDevicePropertyNominalSampleRate;
1122 size = sizeof(Float64);
1123 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL, &size, &rate);
1125 HeapFree(GetProcessHeap(), 0, fmt);
1126 WARN("Unable to get _NominalSampleRate property: %lx\n", sc);
1129 fmt->Format.nSamplesPerSec = rate;
1131 /* CoreAudio doesn't seem to give a device format preference, so just
1132 * choose a common format... */
1133 fmt->Format.wBitsPerSample = 16;
1134 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1136 fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
1137 fmt->Format.nChannels) / 8;
1138 fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
1139 fmt->Format.nBlockAlign;
1141 fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
1142 fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1149 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
1150 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1152 ACImpl *This = impl_from_IAudioClient(iface);
1154 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
1156 if(!defperiod && !minperiod)
1159 OSSpinLockLock(&This->lock);
1161 if(This->period_ms){
1163 *defperiod = This->period_ms * 10000;
1165 *minperiod = This->period_ms * 10000;
1168 *defperiod = DefaultPeriod;
1170 *minperiod = MinimumPeriod;
1173 OSSpinLockUnlock(&This->lock);
1178 void CALLBACK ca_period_cb(void *user, BOOLEAN timer)
1180 ACImpl *This = user;
1182 OSSpinLockLock(&This->lock);
1184 SetEvent(This->event);
1185 OSSpinLockUnlock(&This->lock);
1188 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
1190 ACImpl *This = impl_from_IAudioClient(iface);
1193 TRACE("(%p)\n", This);
1195 OSSpinLockLock(&This->lock);
1198 OSSpinLockUnlock(&This->lock);
1199 return AUDCLNT_E_NOT_INITIALIZED;
1202 if(This->playing != StateStopped){
1203 OSSpinLockUnlock(&This->lock);
1204 return AUDCLNT_E_NOT_STOPPED;
1207 if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
1208 OSSpinLockUnlock(&This->lock);
1209 return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1213 if(!CreateTimerQueueTimer(&This->timer, g_timer_q,
1214 ca_period_cb, This, 0, This->period_ms, 0))
1215 ERR("Unable to create timer: %u\n", GetLastError());
1217 This->playing = StateInTransition;
1219 OSSpinLockUnlock(&This->lock);
1221 sc = AudioQueueStart(This->aqueue, NULL);
1223 WARN("Unable to start audio queue: %lx\n", sc);
1227 OSSpinLockLock(&This->lock);
1229 This->playing = StatePlaying;
1231 OSSpinLockUnlock(&This->lock);
1236 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
1238 ACImpl *This = impl_from_IAudioClient(iface);
1241 TRACE("(%p)\n", This);
1243 OSSpinLockLock(&This->lock);
1246 OSSpinLockUnlock(&This->lock);
1247 return AUDCLNT_E_NOT_INITIALIZED;
1250 if(This->playing == StateStopped){
1251 OSSpinLockUnlock(&This->lock);
1255 if(This->playing == StateInTransition){
1256 OSSpinLockUnlock(&This->lock);
1260 if(This->timer && This->timer != INVALID_HANDLE_VALUE){
1261 DeleteTimerQueueTimer(g_timer_q, This->timer, INVALID_HANDLE_VALUE);
1265 This->playing = StateInTransition;
1267 OSSpinLockUnlock(&This->lock);
1269 sc = AudioQueueFlush(This->aqueue);
1271 WARN("Unable to flush audio queue: %lx\n", sc);
1273 sc = AudioQueuePause(This->aqueue);
1275 WARN("Unable to pause audio queue: %lx\n", sc);
1279 OSSpinLockLock(&This->lock);
1281 This->playing = StateStopped;
1283 OSSpinLockUnlock(&This->lock);
1288 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
1290 ACImpl *This = impl_from_IAudioClient(iface);
1294 TRACE("(%p)\n", This);
1296 OSSpinLockLock(&This->lock);
1299 OSSpinLockUnlock(&This->lock);
1300 return AUDCLNT_E_NOT_INITIALIZED;
1303 if(This->playing != StateStopped){
1304 OSSpinLockUnlock(&This->lock);
1305 return AUDCLNT_E_NOT_STOPPED;
1308 This->written_frames = 0;
1310 hr = AudioClock_GetPosition_nolock(This, &This->last_time, NULL, TRUE);
1312 OSSpinLockUnlock(&This->lock);
1316 OSSpinLockUnlock(&This->lock);
1318 sc = AudioQueueReset(This->aqueue);
1320 WARN("Unable to reset audio queue: %lx\n", sc);
1327 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1330 ACImpl *This = impl_from_IAudioClient(iface);
1332 TRACE("(%p)->(%p)\n", This, event);
1335 return E_INVALIDARG;
1337 OSSpinLockLock(&This->lock);
1340 OSSpinLockUnlock(&This->lock);
1341 return AUDCLNT_E_NOT_INITIALIZED;
1344 if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
1345 OSSpinLockUnlock(&This->lock);
1346 return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1349 This->event = event;
1351 OSSpinLockUnlock(&This->lock);
1356 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1359 ACImpl *This = impl_from_IAudioClient(iface);
1361 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1367 OSSpinLockLock(&This->lock);
1370 OSSpinLockUnlock(&This->lock);
1371 return AUDCLNT_E_NOT_INITIALIZED;
1374 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1375 if(This->dataflow != eRender){
1376 OSSpinLockUnlock(&This->lock);
1377 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1379 *ppv = &This->IAudioRenderClient_iface;
1380 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1381 if(This->dataflow != eCapture){
1382 OSSpinLockUnlock(&This->lock);
1383 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1385 *ppv = &This->IAudioCaptureClient_iface;
1386 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1387 if(!This->session_wrapper){
1388 This->session_wrapper = AudioSessionWrapper_Create(This);
1389 if(!This->session_wrapper){
1390 OSSpinLockUnlock(&This->lock);
1391 return E_OUTOFMEMORY;
1395 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1396 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1397 *ppv = &This->ISimpleAudioVolume_iface;
1398 }else if(IsEqualIID(riid, &IID_IAudioClock)){
1399 *ppv = &This->IAudioClock_iface;
1403 IUnknown_AddRef((IUnknown*)*ppv);
1404 OSSpinLockUnlock(&This->lock);
1408 OSSpinLockUnlock(&This->lock);
1410 FIXME("stub %s\n", debugstr_guid(riid));
1411 return E_NOINTERFACE;
1414 static const IAudioClientVtbl AudioClient_Vtbl =
1416 AudioClient_QueryInterface,
1418 AudioClient_Release,
1419 AudioClient_Initialize,
1420 AudioClient_GetBufferSize,
1421 AudioClient_GetStreamLatency,
1422 AudioClient_GetCurrentPadding,
1423 AudioClient_IsFormatSupported,
1424 AudioClient_GetMixFormat,
1425 AudioClient_GetDevicePeriod,
1429 AudioClient_SetEventHandle,
1430 AudioClient_GetService
1433 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1434 IAudioRenderClient *iface, REFIID riid, void **ppv)
1436 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1442 if(IsEqualIID(riid, &IID_IUnknown) ||
1443 IsEqualIID(riid, &IID_IAudioRenderClient))
1446 IUnknown_AddRef((IUnknown*)*ppv);
1450 WARN("Unknown interface %s\n", debugstr_guid(riid));
1451 return E_NOINTERFACE;
1454 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1456 ACImpl *This = impl_from_IAudioRenderClient(iface);
1457 return AudioClient_AddRef(&This->IAudioClient_iface);
1460 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1462 ACImpl *This = impl_from_IAudioRenderClient(iface);
1463 return AudioClient_Release(&This->IAudioClient_iface);
1466 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1467 UINT32 frames, BYTE **data)
1469 ACImpl *This = impl_from_IAudioRenderClient(iface);
1471 UINT32 pad, bytes = frames * This->fmt->nBlockAlign;
1475 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1480 OSSpinLockLock(&This->lock);
1482 if(This->getbuf_last){
1483 OSSpinLockUnlock(&This->lock);
1484 return AUDCLNT_E_OUT_OF_ORDER;
1488 This->getbuf_last = TRUE;
1489 OSSpinLockUnlock(&This->lock);
1493 hr = AudioClient_GetCurrentPadding_nolock(This, &pad);
1495 OSSpinLockUnlock(&This->lock);
1499 if(pad + frames > This->bufsize_frames){
1500 OSSpinLockUnlock(&This->lock);
1501 return AUDCLNT_E_BUFFER_TOO_LARGE;
1504 LIST_FOR_EACH_ENTRY(buf, &This->avail_buffers, AQBuffer, entry){
1505 if(buf->buf->mAudioDataBytesCapacity >= bytes){
1506 This->public_buffer = buf->buf;
1507 list_remove(&buf->entry);
1512 if(&buf->entry == &This->avail_buffers){
1513 sc = AudioQueueAllocateBuffer(This->aqueue, bytes,
1514 &This->public_buffer);
1516 OSSpinLockUnlock(&This->lock);
1517 WARN("Unable to allocate buffer: %lx\n", sc);
1520 buf = HeapAlloc(GetProcessHeap(), 0, sizeof(AQBuffer));
1522 AudioQueueFreeBuffer(This->aqueue, This->public_buffer);
1523 This->public_buffer = NULL;
1524 OSSpinLockUnlock(&This->lock);
1525 return E_OUTOFMEMORY;
1527 buf->buf = This->public_buffer;
1528 This->public_buffer->mUserData = buf;
1531 *data = This->public_buffer->mAudioData;
1533 This->getbuf_last = TRUE;
1535 OSSpinLockUnlock(&This->lock);
1540 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1541 IAudioRenderClient *iface, UINT32 frames, DWORD flags)
1543 ACImpl *This = impl_from_IAudioRenderClient(iface);
1546 TRACE("(%p)->(%u, %x)\n", This, frames, flags);
1548 OSSpinLockLock(&This->lock);
1550 if(!This->getbuf_last){
1551 OSSpinLockUnlock(&This->lock);
1552 return AUDCLNT_E_OUT_OF_ORDER;
1555 if(flags & AUDCLNT_BUFFERFLAGS_SILENT){
1556 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)This->fmt;
1557 if((This->fmt->wFormatTag == WAVE_FORMAT_PCM ||
1558 (This->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1559 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) &&
1560 This->fmt->wBitsPerSample == 8)
1561 memset(This->public_buffer->mAudioData, 128,
1562 frames * This->fmt->nBlockAlign);
1564 memset(This->public_buffer->mAudioData, 0,
1565 frames * This->fmt->nBlockAlign);
1568 This->public_buffer->mAudioDataByteSize = frames * This->fmt->nBlockAlign;
1570 sc = AudioQueueEnqueueBuffer(This->aqueue, This->public_buffer, 0, NULL);
1572 OSSpinLockUnlock(&This->lock);
1573 WARN("Unable to enqueue buffer: %lx\n", sc);
1577 if(This->playing == StateStopped)
1578 AudioQueuePrime(This->aqueue, 0, NULL);
1580 This->public_buffer = NULL;
1581 This->getbuf_last = FALSE;
1582 This->written_frames += frames;
1583 This->inbuf_frames += frames;
1585 OSSpinLockUnlock(&This->lock);
1590 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1591 AudioRenderClient_QueryInterface,
1592 AudioRenderClient_AddRef,
1593 AudioRenderClient_Release,
1594 AudioRenderClient_GetBuffer,
1595 AudioRenderClient_ReleaseBuffer
1598 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1599 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1601 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1607 if(IsEqualIID(riid, &IID_IUnknown) ||
1608 IsEqualIID(riid, &IID_IAudioCaptureClient))
1611 IUnknown_AddRef((IUnknown*)*ppv);
1615 WARN("Unknown interface %s\n", debugstr_guid(riid));
1616 return E_NOINTERFACE;
1619 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1621 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1622 return IAudioClient_AddRef(&This->IAudioClient_iface);
1625 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1627 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1628 return IAudioClient_Release(&This->IAudioClient_iface);
1631 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1632 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1635 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1637 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1640 if(!data || !frames || !flags)
1643 OSSpinLockLock(&This->lock);
1645 if(This->getbuf_last){
1646 OSSpinLockUnlock(&This->lock);
1647 return AUDCLNT_E_OUT_OF_ORDER;
1650 if(This->public_buffer){
1651 *data = This->public_buffer->mAudioData;
1653 This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
1655 struct list *head = list_head(&This->avail_buffers);
1660 AQBuffer *buf = LIST_ENTRY(head, AQBuffer, entry);
1661 This->public_buffer = buf->buf;
1662 *data = This->public_buffer->mAudioData;
1664 This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
1665 list_remove(&buf->entry);
1670 This->written_frames += *frames;
1671 This->inbuf_frames -= *frames;
1672 This->getbuf_last = TRUE;
1674 if(devpos || qpcpos)
1675 AudioClock_GetPosition_nolock(This, devpos, qpcpos, FALSE);
1677 OSSpinLockUnlock(&This->lock);
1679 return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
1682 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1683 IAudioCaptureClient *iface, UINT32 done)
1685 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1686 UINT32 pbuf_frames =
1687 This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
1690 TRACE("(%p)->(%u)\n", This, done);
1692 OSSpinLockLock(&This->lock);
1694 if(!This->getbuf_last){
1695 OSSpinLockUnlock(&This->lock);
1696 return AUDCLNT_E_OUT_OF_ORDER;
1699 if(done != 0 && done != pbuf_frames){
1700 OSSpinLockUnlock(&This->lock);
1701 return AUDCLNT_E_INVALID_SIZE;
1705 sc = AudioQueueEnqueueBuffer(This->aqueue, This->public_buffer,
1708 WARN("Unable to enqueue buffer: %lx\n", sc);
1709 This->public_buffer = NULL;
1712 This->getbuf_last = FALSE;
1714 OSSpinLockUnlock(&This->lock);
1719 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1720 IAudioCaptureClient *iface, UINT32 *frames)
1722 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1726 TRACE("(%p)->(%p)\n", This, frames);
1731 OSSpinLockLock(&This->lock);
1733 head = list_head(&This->avail_buffers);
1736 *frames = This->bufsize_frames / CAPTURE_BUFFERS;
1737 OSSpinLockUnlock(&This->lock);
1741 buf = LIST_ENTRY(head, AQBuffer, entry);
1742 *frames = buf->buf->mAudioDataByteSize / This->fmt->nBlockAlign;
1744 OSSpinLockUnlock(&This->lock);
1749 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1751 AudioCaptureClient_QueryInterface,
1752 AudioCaptureClient_AddRef,
1753 AudioCaptureClient_Release,
1754 AudioCaptureClient_GetBuffer,
1755 AudioCaptureClient_ReleaseBuffer,
1756 AudioCaptureClient_GetNextPacketSize
1759 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1760 REFIID riid, void **ppv)
1762 ACImpl *This = impl_from_IAudioClock(iface);
1764 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1770 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
1772 else if(IsEqualIID(riid, &IID_IAudioClock2))
1773 *ppv = &This->IAudioClock2_iface;
1775 IUnknown_AddRef((IUnknown*)*ppv);
1779 WARN("Unknown interface %s\n", debugstr_guid(riid));
1780 return E_NOINTERFACE;
1783 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
1785 ACImpl *This = impl_from_IAudioClock(iface);
1786 return IAudioClient_AddRef(&This->IAudioClient_iface);
1789 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
1791 ACImpl *This = impl_from_IAudioClock(iface);
1792 return IAudioClient_Release(&This->IAudioClient_iface);
1795 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
1797 ACImpl *This = impl_from_IAudioClock(iface);
1799 TRACE("(%p)->(%p)\n", This, freq);
1801 *freq = This->fmt->nSamplesPerSec;
1806 static HRESULT AudioClock_GetPosition_nolock(ACImpl *This,
1807 UINT64 *pos, UINT64 *qpctime, BOOL raw)
1809 AudioTimeStamp time;
1812 sc = AudioQueueGetCurrentTime(This->aqueue, NULL, &time, NULL);
1813 if(sc == kAudioQueueErr_InvalidRunState){
1815 }else if(sc == noErr){
1816 if(!(time.mFlags & kAudioTimeStampSampleTimeValid)){
1817 FIXME("Sample time not valid, should calculate from something else\n");
1822 *pos = time.mSampleTime;
1824 *pos = time.mSampleTime - This->last_time;
1826 WARN("Unable to get current time: %lx\n", sc);
1831 LARGE_INTEGER stamp, freq;
1832 QueryPerformanceCounter(&stamp);
1833 QueryPerformanceFrequency(&freq);
1834 *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
1840 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
1843 ACImpl *This = impl_from_IAudioClock(iface);
1846 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
1851 OSSpinLockLock(&This->lock);
1853 hr = AudioClock_GetPosition_nolock(This, pos, qpctime, FALSE);
1855 OSSpinLockUnlock(&This->lock);
1860 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
1863 ACImpl *This = impl_from_IAudioClock(iface);
1865 TRACE("(%p)->(%p)\n", This, chars);
1870 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
1875 static const IAudioClockVtbl AudioClock_Vtbl =
1877 AudioClock_QueryInterface,
1880 AudioClock_GetFrequency,
1881 AudioClock_GetPosition,
1882 AudioClock_GetCharacteristics
1885 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
1886 REFIID riid, void **ppv)
1888 ACImpl *This = impl_from_IAudioClock2(iface);
1889 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
1892 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
1894 ACImpl *This = impl_from_IAudioClock2(iface);
1895 return IAudioClient_AddRef(&This->IAudioClient_iface);
1898 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
1900 ACImpl *This = impl_from_IAudioClock2(iface);
1901 return IAudioClient_Release(&This->IAudioClient_iface);
1904 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
1905 UINT64 *pos, UINT64 *qpctime)
1907 ACImpl *This = impl_from_IAudioClock2(iface);
1909 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
1914 static const IAudioClock2Vtbl AudioClock2_Vtbl =
1916 AudioClock2_QueryInterface,
1918 AudioClock2_Release,
1919 AudioClock2_GetDevicePosition
1922 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
1924 AudioSessionWrapper *ret;
1926 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1927 sizeof(AudioSessionWrapper));
1931 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
1933 ret->client = client;
1934 ret->session = client->session;
1935 AudioClient_AddRef(&client->IAudioClient_iface);
1940 static HRESULT WINAPI AudioSessionControl_QueryInterface(
1941 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
1943 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1949 if(IsEqualIID(riid, &IID_IUnknown) ||
1950 IsEqualIID(riid, &IID_IAudioSessionControl) ||
1951 IsEqualIID(riid, &IID_IAudioSessionControl2))
1954 IUnknown_AddRef((IUnknown*)*ppv);
1958 WARN("Unknown interface %s\n", debugstr_guid(riid));
1959 return E_NOINTERFACE;
1962 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
1964 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1966 ref = InterlockedIncrement(&This->ref);
1967 TRACE("(%p) Refcount now %u\n", This, ref);
1971 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
1973 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1975 ref = InterlockedDecrement(&This->ref);
1976 TRACE("(%p) Refcount now %u\n", This, ref);
1978 OSSpinLockLock(&This->client->lock);
1979 This->client->session_wrapper = NULL;
1980 OSSpinLockUnlock(&This->client->lock);
1981 AudioClient_Release(&This->client->IAudioClient_iface);
1982 HeapFree(GetProcessHeap(), 0, This);
1987 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
1988 AudioSessionState *state)
1990 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1993 TRACE("(%p)->(%p)\n", This, state);
1996 return NULL_PTR_ERR;
1998 EnterCriticalSection(&g_sessions_lock);
2000 if(list_empty(&This->session->clients)){
2001 *state = AudioSessionStateExpired;
2002 LeaveCriticalSection(&g_sessions_lock);
2006 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
2007 OSSpinLockLock(&client->lock);
2008 if(client->playing == StatePlaying ||
2009 client->playing == StateInTransition){
2010 *state = AudioSessionStateActive;
2011 OSSpinLockUnlock(&client->lock);
2012 LeaveCriticalSection(&g_sessions_lock);
2015 OSSpinLockUnlock(&client->lock);
2018 LeaveCriticalSection(&g_sessions_lock);
2020 *state = AudioSessionStateInactive;
2025 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
2026 IAudioSessionControl2 *iface, WCHAR **name)
2028 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2030 FIXME("(%p)->(%p) - stub\n", This, name);
2035 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
2036 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
2038 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2040 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
2045 static HRESULT WINAPI AudioSessionControl_GetIconPath(
2046 IAudioSessionControl2 *iface, WCHAR **path)
2048 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2050 FIXME("(%p)->(%p) - stub\n", This, path);
2055 static HRESULT WINAPI AudioSessionControl_SetIconPath(
2056 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
2058 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2060 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
2065 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
2066 IAudioSessionControl2 *iface, GUID *group)
2068 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2070 FIXME("(%p)->(%p) - stub\n", This, group);
2075 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
2076 IAudioSessionControl2 *iface, GUID *group, const GUID *session)
2078 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2080 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
2081 debugstr_guid(session));
2086 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
2087 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2089 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2091 FIXME("(%p)->(%p) - stub\n", This, events);
2096 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
2097 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2099 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2101 FIXME("(%p)->(%p) - stub\n", This, events);
2106 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
2107 IAudioSessionControl2 *iface, WCHAR **id)
2109 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2111 FIXME("(%p)->(%p) - stub\n", This, id);
2116 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
2117 IAudioSessionControl2 *iface, WCHAR **id)
2119 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2121 FIXME("(%p)->(%p) - stub\n", This, id);
2126 static HRESULT WINAPI AudioSessionControl_GetProcessId(
2127 IAudioSessionControl2 *iface, DWORD *pid)
2129 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2131 TRACE("(%p)->(%p)\n", This, pid);
2136 *pid = GetCurrentProcessId();
2141 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
2142 IAudioSessionControl2 *iface)
2144 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2146 TRACE("(%p)\n", This);
2151 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
2152 IAudioSessionControl2 *iface, BOOL optout)
2154 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2156 TRACE("(%p)->(%d)\n", This, optout);
2161 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
2163 AudioSessionControl_QueryInterface,
2164 AudioSessionControl_AddRef,
2165 AudioSessionControl_Release,
2166 AudioSessionControl_GetState,
2167 AudioSessionControl_GetDisplayName,
2168 AudioSessionControl_SetDisplayName,
2169 AudioSessionControl_GetIconPath,
2170 AudioSessionControl_SetIconPath,
2171 AudioSessionControl_GetGroupingParam,
2172 AudioSessionControl_SetGroupingParam,
2173 AudioSessionControl_RegisterAudioSessionNotification,
2174 AudioSessionControl_UnregisterAudioSessionNotification,
2175 AudioSessionControl_GetSessionIdentifier,
2176 AudioSessionControl_GetSessionInstanceIdentifier,
2177 AudioSessionControl_GetProcessId,
2178 AudioSessionControl_IsSystemSoundsSession,
2179 AudioSessionControl_SetDuckingPreference
2182 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
2183 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
2185 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2191 if(IsEqualIID(riid, &IID_IUnknown) ||
2192 IsEqualIID(riid, &IID_ISimpleAudioVolume))
2195 IUnknown_AddRef((IUnknown*)*ppv);
2199 WARN("Unknown interface %s\n", debugstr_guid(riid));
2200 return E_NOINTERFACE;
2203 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
2205 ACImpl *This = impl_from_ISimpleAudioVolume(iface);
2206 return IAudioClient_AddRef(&This->IAudioClient_iface);
2209 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
2211 ACImpl *This = impl_from_ISimpleAudioVolume(iface);
2212 return IAudioClient_Release(&This->IAudioClient_iface);
2215 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
2216 ISimpleAudioVolume *iface, float level, const GUID *context)
2218 ACImpl *This = impl_from_ISimpleAudioVolume(iface);
2220 FIXME("(%p)->(%f, %p) - stub\n", This, level, context);
2225 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
2226 ISimpleAudioVolume *iface, float *level)
2228 ACImpl *This = impl_from_ISimpleAudioVolume(iface);
2230 FIXME("(%p)->(%p) - stub\n", This, level);
2235 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
2236 BOOL mute, const GUID *context)
2238 ACImpl *This = impl_from_ISimpleAudioVolume(iface);
2240 FIXME("(%p)->(%u, %p) - stub\n", This, mute, context);
2245 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
2248 ACImpl *This = impl_from_ISimpleAudioVolume(iface);
2250 FIXME("(%p)->(%p) - stub\n", This, mute);
2255 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
2257 SimpleAudioVolume_QueryInterface,
2258 SimpleAudioVolume_AddRef,
2259 SimpleAudioVolume_Release,
2260 SimpleAudioVolume_SetMasterVolume,
2261 SimpleAudioVolume_GetMasterVolume,
2262 SimpleAudioVolume_SetMute,
2263 SimpleAudioVolume_GetMute