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
30 #include "wine/debug.h"
31 #include "wine/unicode.h"
32 #include "wine/list.h"
35 #include "mmdeviceapi.h"
39 #include "audioclient.h"
40 #include "endpointvolume.h"
41 #include "audiopolicy.h"
48 #include <sys/types.h>
50 #include <sys/ioctl.h>
54 #include <libkern/OSAtomic.h>
55 #include <CoreAudio/CoreAudio.h>
56 #include <AudioToolbox/AudioQueue.h>
58 WINE_DEFAULT_DEBUG_CHANNEL(coreaudio);
60 #define CAPTURE_BUFFERS 5
62 static const REFERENCE_TIME DefaultPeriod = 200000;
63 static const REFERENCE_TIME MinimumPeriod = 100000;
65 typedef struct _AQBuffer {
66 AudioQueueBufferRef buf;
70 typedef struct ACImpl {
71 IAudioClient IAudioClient_iface;
72 IAudioRenderClient IAudioRenderClient_iface;
73 IAudioCaptureClient IAudioCaptureClient_iface;
74 IAudioSessionControl2 IAudioSessionControl2_iface;
75 ISimpleAudioVolume ISimpleAudioVolume_iface;
76 IAudioClock IAudioClock_iface;
77 IAudioClock2 IAudioClock2_iface;
87 AUDCLNT_SHAREMODE share;
93 UINT32 period_ms, bufsize_frames, inbuf_frames, written_frames;
95 AudioQueueBufferRef public_buffer;
99 struct list avail_buffers;
101 /* We can't use debug printing or {Enter,Leave}CriticalSection from
102 * OSX callback threads, so we use OSX's OSSpinLock for synchronization
103 * instead. OSSpinLock is not a recursive lock, so don't call
104 * synchronized functions while holding the lock. */
114 static const IAudioClientVtbl AudioClient_Vtbl;
115 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
116 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
117 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
118 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
119 static const IAudioClockVtbl AudioClock_Vtbl;
120 static const IAudioClock2Vtbl AudioClock2_Vtbl;
122 static HANDLE g_timer_q;
124 static HRESULT AudioClock_GetPosition_nolock(ACImpl *This, UINT64 *pos,
125 UINT64 *qpctime, BOOL raw);
127 static inline ACImpl *impl_from_IAudioClient(IAudioClient *iface)
129 return CONTAINING_RECORD(iface, ACImpl, IAudioClient_iface);
132 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
134 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
137 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
139 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
142 static inline ACImpl *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
144 return CONTAINING_RECORD(iface, ACImpl, IAudioSessionControl2_iface);
147 static inline ACImpl *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
149 return CONTAINING_RECORD(iface, ACImpl, ISimpleAudioVolume_iface);
152 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
154 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
157 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
159 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
162 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids,
163 AudioDeviceID ***keys, UINT *num, UINT *def_index)
165 UInt32 devsize, size;
166 AudioDeviceID *devices;
167 AudioDeviceID default_id;
168 AudioObjectPropertyAddress addr;
172 TRACE("%d %p %p %p\n", flow, ids, num, def_index);
174 addr.mScope = kAudioObjectPropertyScopeGlobal;
175 addr.mElement = kAudioObjectPropertyElementMaster;
177 addr.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
178 else if(flow == eCapture)
179 addr.mSelector = kAudioHardwarePropertyDefaultInputDevice;
183 size = sizeof(default_id);
184 sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0,
185 NULL, &size, &default_id);
187 WARN("Getting _DefaultInputDevice property failed: %lx\n", sc);
191 addr.mSelector = kAudioHardwarePropertyDevices;
192 sc = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &addr, 0,
195 WARN("Getting _Devices property size failed: %lx\n", sc);
199 devices = HeapAlloc(GetProcessHeap(), 0, devsize);
201 return E_OUTOFMEMORY;
203 sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0, NULL,
206 WARN("Getting _Devices property failed: %lx\n", sc);
207 HeapFree(GetProcessHeap(), 0, devices);
211 ndevices = devsize / sizeof(AudioDeviceID);
213 *ids = HeapAlloc(GetProcessHeap(), 0, ndevices * sizeof(WCHAR *));
215 HeapFree(GetProcessHeap(), 0, devices);
216 return E_OUTOFMEMORY;
219 *keys = HeapAlloc(GetProcessHeap(), 0, ndevices * sizeof(AudioDeviceID *));
221 HeapFree(GetProcessHeap(), 0, *ids);
222 HeapFree(GetProcessHeap(), 0, devices);
223 return E_OUTOFMEMORY;
227 *def_index = (UINT)-1;
228 for(i = 0; i < ndevices; ++i){
229 AudioBufferList *buffers;
235 addr.mSelector = kAudioDevicePropertyStreamConfiguration;
237 addr.mScope = kAudioDevicePropertyScopeOutput;
239 addr.mScope = kAudioDevicePropertyScopeInput;
241 sc = AudioObjectGetPropertyDataSize(devices[i], &addr, 0, NULL, &size);
243 WARN("Unable to get _StreamConfiguration property size for "
244 "device %lu: %lx\n", devices[i], sc);
248 buffers = HeapAlloc(GetProcessHeap(), 0, size);
250 HeapFree(GetProcessHeap(), 0, devices);
251 for(j = 0; j < *num; ++j)
252 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
253 HeapFree(GetProcessHeap(), 0, *keys);
254 HeapFree(GetProcessHeap(), 0, *ids);
255 return E_OUTOFMEMORY;
258 sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL,
261 WARN("Unable to get _StreamConfiguration property for "
262 "device %lu: %lx\n", devices[i], sc);
263 HeapFree(GetProcessHeap(), 0, buffers);
267 /* check that there's at least one channel in this device before
268 * we claim it as usable */
269 for(j = 0; j < buffers->mNumberBuffers; ++j)
270 if(buffers->mBuffers[j].mNumberChannels > 0)
272 if(j >= buffers->mNumberBuffers){
273 HeapFree(GetProcessHeap(), 0, buffers);
277 HeapFree(GetProcessHeap(), 0, buffers);
280 addr.mSelector = kAudioObjectPropertyName;
281 sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL,
284 WARN("Unable to get _Name property for device %lu: %lx\n",
289 if(!CFStringGetCString(name, nameA, sizeof(nameA),
290 kCFStringEncodingUTF8)){
291 WARN("Error converting string to UTF8\n");
298 len = MultiByteToWideChar(CP_UNIXCP, 0, nameA, -1, NULL, 0);
299 (*ids)[*num] = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
301 HeapFree(GetProcessHeap(), 0, devices);
302 for(j = 0; j < *num; ++j){
303 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
304 HeapFree(GetProcessHeap(), 0, (*keys)[j]);
306 HeapFree(GetProcessHeap(), 0, *ids);
307 HeapFree(GetProcessHeap(), 0, *keys);
308 return E_OUTOFMEMORY;
310 MultiByteToWideChar(CP_UNIXCP, 0, nameA, -1, (*ids)[*num], len);
312 (*keys)[*num] = HeapAlloc(GetProcessHeap(), 0, sizeof(AudioDeviceID));
314 HeapFree(GetProcessHeap(), 0, devices);
315 HeapFree(GetProcessHeap(), 0, (*ids)[*num]);
316 for(j = 0; j < *num; ++j){
317 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
318 HeapFree(GetProcessHeap(), 0, (*keys)[j]);
320 HeapFree(GetProcessHeap(), 0, *ids);
321 HeapFree(GetProcessHeap(), 0, *keys);
322 return E_OUTOFMEMORY;
324 *(*keys)[*num] = devices[i];
326 if(*def_index == (UINT)-1 && devices[i] == default_id)
332 if(*def_index == (UINT)-1)
335 HeapFree(GetProcessHeap(), 0, devices);
340 HRESULT WINAPI AUDDRV_GetAudioEndpoint(AudioDeviceID *adevid, IMMDevice *dev,
341 EDataFlow dataflow, IAudioClient **out)
345 TRACE("%p %d %p\n", dev, dataflow, out);
348 g_timer_q = CreateTimerQueue();
353 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACImpl));
355 return E_OUTOFMEMORY;
357 This->IAudioClient_iface.lpVtbl = &AudioClient_Vtbl;
358 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
359 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
360 This->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
361 This->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
362 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
363 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
365 This->dataflow = dataflow;
370 IMMDevice_AddRef(This->parent);
372 list_init(&This->avail_buffers);
374 This->adevid = *adevid;
376 *out = &This->IAudioClient_iface;
377 IAudioClient_AddRef(&This->IAudioClient_iface);
382 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient *iface,
383 REFIID riid, void **ppv)
385 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
390 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClient))
393 IUnknown_AddRef((IUnknown*)*ppv);
396 WARN("Unknown interface %s\n", debugstr_guid(riid));
397 return E_NOINTERFACE;
400 static ULONG WINAPI AudioClient_AddRef(IAudioClient *iface)
402 ACImpl *This = impl_from_IAudioClient(iface);
404 ref = InterlockedIncrement(&This->ref);
405 TRACE("(%p) Refcount now %u\n", This, ref);
409 static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
411 ACImpl *This = impl_from_IAudioClient(iface);
413 ref = InterlockedDecrement(&This->ref);
414 TRACE("(%p) Refcount now %u\n", This, ref);
416 IAudioClient_Stop(iface);
418 AudioQueueDispose(This->aqueue, 1);
419 HeapFree(GetProcessHeap(), 0, This->public_buffer);
420 HeapFree(GetProcessHeap(), 0, This->fmt);
421 IMMDevice_Release(This->parent);
422 HeapFree(GetProcessHeap(), 0, This);
427 static void dump_fmt(const WAVEFORMATEX *fmt)
429 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
430 switch(fmt->wFormatTag){
431 case WAVE_FORMAT_PCM:
432 TRACE("WAVE_FORMAT_PCM");
434 case WAVE_FORMAT_IEEE_FLOAT:
435 TRACE("WAVE_FORMAT_IEEE_FLOAT");
437 case WAVE_FORMAT_EXTENSIBLE:
438 TRACE("WAVE_FORMAT_EXTENSIBLE");
446 TRACE("nChannels: %u\n", fmt->nChannels);
447 TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
448 TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
449 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
450 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
451 TRACE("cbSize: %u\n", fmt->cbSize);
453 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
454 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
455 TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
456 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
457 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
461 static DWORD get_channel_mask(unsigned int channels)
467 return SPEAKER_FRONT_CENTER;
469 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
471 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT |
472 SPEAKER_LOW_FREQUENCY;
474 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
477 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
478 SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY;
480 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
481 SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER;
483 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
484 SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER |
487 FIXME("Unknown speaker configuration: %u\n", channels);
491 static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
496 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
497 size = sizeof(WAVEFORMATEXTENSIBLE);
499 size = sizeof(WAVEFORMATEX);
501 ret = HeapAlloc(GetProcessHeap(), 0, size);
505 memcpy(ret, fmt, size);
507 ret->cbSize = size - sizeof(WAVEFORMATEX);
512 static HRESULT ca_get_audiodesc(AudioStreamBasicDescription *desc,
513 const WAVEFORMATEX *fmt)
515 const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)fmt;
517 if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
518 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
519 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
520 desc->mFormatID = kAudioFormatLinearPCM;
521 if(fmt->wBitsPerSample > 8)
522 desc->mFormatFlags = kAudioFormatFlagIsSignedInteger;
523 }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
524 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
525 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
526 desc->mFormatID = kAudioFormatLinearPCM;
527 desc->mFormatFlags = kAudioFormatFlagIsFloat;
528 }else if(fmt->wFormatTag == WAVE_FORMAT_MULAW ||
529 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
530 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_MULAW))){
531 desc->mFormatID = kAudioFormatULaw;
532 }else if(fmt->wFormatTag == WAVE_FORMAT_ALAW ||
533 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
534 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_ALAW))){
535 desc->mFormatID = kAudioFormatALaw;
537 return AUDCLNT_E_UNSUPPORTED_FORMAT;
539 desc->mSampleRate = fmt->nSamplesPerSec;
540 desc->mBytesPerPacket = fmt->nBlockAlign;
541 desc->mFramesPerPacket = 1;
542 desc->mBytesPerFrame = fmt->nBlockAlign;
543 desc->mChannelsPerFrame = fmt->nChannels;
544 desc->mBitsPerChannel = fmt->wBitsPerSample;
550 static void ca_out_buffer_cb(void *user, AudioQueueRef aqueue,
551 AudioQueueBufferRef buffer)
554 AQBuffer *buf = buffer->mUserData;
556 OSSpinLockLock(&This->lock);
557 list_add_tail(&This->avail_buffers, &buf->entry);
558 This->inbuf_frames -= buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
559 OSSpinLockUnlock(&This->lock);
562 static void ca_in_buffer_cb(void *user, AudioQueueRef aqueue,
563 AudioQueueBufferRef buffer, const AudioTimeStamp *start,
564 UInt32 ndesc, const AudioStreamPacketDescription *descs)
567 AQBuffer *buf = buffer->mUserData;
569 OSSpinLockLock(&This->lock);
570 list_add_tail(&This->avail_buffers, &buf->entry);
571 This->inbuf_frames += buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
572 OSSpinLockUnlock(&This->lock);
575 static HRESULT ca_setup_aqueue(AudioDeviceID did, EDataFlow flow,
576 const WAVEFORMATEX *fmt, void *user, AudioQueueRef *aqueue)
578 AudioStreamBasicDescription desc;
579 AudioObjectPropertyAddress addr;
585 addr.mScope = kAudioObjectPropertyScopeGlobal;
587 addr.mSelector = kAudioDevicePropertyDeviceUID;
590 sc = AudioObjectGetPropertyData(did, &addr, 0, NULL, &size, &uid);
592 WARN("Unable to get _DeviceUID property: %lx\n", sc);
596 hr = ca_get_audiodesc(&desc, fmt);
603 sc = AudioQueueNewOutput(&desc, ca_out_buffer_cb, user, NULL, NULL, 0,
605 else if(flow == eCapture)
606 sc = AudioQueueNewInput(&desc, ca_in_buffer_cb, user, NULL, NULL, 0,
613 WARN("Unable to create AudioQueue: %lx\n", sc);
618 sc = AudioQueueSetProperty(*aqueue, kAudioQueueProperty_CurrentDevice,
630 static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
631 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
632 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
633 const GUID *sessionguid)
635 ACImpl *This = impl_from_IAudioClient(iface);
639 TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
640 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
647 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
648 return AUDCLNT_E_NOT_INITIALIZED;
650 if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
651 AUDCLNT_STREAMFLAGS_LOOPBACK |
652 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
653 AUDCLNT_STREAMFLAGS_NOPERSIST |
654 AUDCLNT_STREAMFLAGS_RATEADJUST |
655 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
656 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
657 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED)){
658 TRACE("Unknown flags: %08x\n", flags);
662 OSSpinLockLock(&This->lock);
665 OSSpinLockUnlock(&This->lock);
666 return AUDCLNT_E_ALREADY_INITIALIZED;
669 hr = ca_setup_aqueue(This->adevid, This->dataflow, fmt, This, &This->aqueue);
671 OSSpinLockUnlock(&This->lock);
675 This->fmt = clone_format(fmt);
677 AudioQueueDispose(This->aqueue, 1);
679 OSSpinLockUnlock(&This->lock);
680 return E_OUTOFMEMORY;
684 This->period_ms = period / 10000;
685 if(This->period_ms == 0)
688 This->period_ms = MinimumPeriod / 10000;
690 This->bufsize_frames = ceil(fmt->nSamplesPerSec * (duration / 10000000.));
692 if(This->dataflow == eCapture){
694 UInt32 bsize = ceil((This->bufsize_frames / (double)CAPTURE_BUFFERS) *
695 This->fmt->nBlockAlign);
696 for(i = 0; i < CAPTURE_BUFFERS; ++i){
699 buf = HeapAlloc(GetProcessHeap(), 0, sizeof(AQBuffer));
701 AudioQueueDispose(This->aqueue, 1);
703 OSSpinLockUnlock(&This->lock);
704 return E_OUTOFMEMORY;
707 sc = AudioQueueAllocateBuffer(This->aqueue, bsize, &buf->buf);
709 AudioQueueDispose(This->aqueue, 1);
711 OSSpinLockUnlock(&This->lock);
712 WARN("Couldn't allocate buffer: %lx\n", sc);
716 buf->buf->mUserData = buf;
718 sc = AudioQueueEnqueueBuffer(This->aqueue, buf->buf, 0, NULL);
720 ERR("Couldn't enqueue buffer: %lx\n", sc);
729 OSSpinLockUnlock(&This->lock);
734 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
737 ACImpl *This = impl_from_IAudioClient(iface);
739 TRACE("(%p)->(%p)\n", This, frames);
744 OSSpinLockLock(&This->lock);
747 OSSpinLockUnlock(&This->lock);
748 return AUDCLNT_E_NOT_INITIALIZED;
751 *frames = This->bufsize_frames;
753 OSSpinLockUnlock(&This->lock);
758 static HRESULT ca_get_max_stream_latency(ACImpl *This, UInt32 *max)
760 AudioObjectPropertyAddress addr;
766 if(This->dataflow == eRender)
767 addr.mScope = kAudioDevicePropertyScopeOutput;
768 else if(This->dataflow == eCapture)
769 addr.mScope = kAudioDevicePropertyScopeInput;
773 addr.mSelector = kAudioDevicePropertyStreams;
775 sc = AudioObjectGetPropertyDataSize(This->adevid, &addr, 0, NULL,
778 WARN("Unable to get size for _Streams property: %lx\n", sc);
782 ids = HeapAlloc(GetProcessHeap(), 0, size);
784 return E_OUTOFMEMORY;
786 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL, &size, ids);
788 WARN("Unable to get _Streams property: %lx\n", sc);
789 HeapFree(GetProcessHeap(), 0, ids);
793 nstreams = size / sizeof(AudioStreamID);
796 addr.mSelector = kAudioStreamPropertyLatency;
797 for(i = 0; i < nstreams; ++i){
800 size = sizeof(latency);
801 sc = AudioObjectGetPropertyData(ids[i], &addr, 0, NULL,
804 WARN("Unable to get _Latency property: %lx\n", sc);
812 HeapFree(GetProcessHeap(), 0, ids);
817 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
820 ACImpl *This = impl_from_IAudioClient(iface);
821 UInt32 latency, stream_latency, size;
822 AudioObjectPropertyAddress addr;
826 TRACE("(%p)->(%p)\n", This, out);
831 OSSpinLockLock(&This->lock);
834 OSSpinLockUnlock(&This->lock);
835 return AUDCLNT_E_NOT_INITIALIZED;
838 if(This->dataflow == eRender)
839 addr.mScope = kAudioDevicePropertyScopeOutput;
840 else if(This->dataflow == eCapture)
841 addr.mScope = kAudioDevicePropertyScopeInput;
843 OSSpinLockUnlock(&This->lock);
846 addr.mSelector = kAudioDevicePropertyLatency;
849 size = sizeof(latency);
850 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL,
853 WARN("Couldn't get _Latency property: %lx\n", sc);
854 OSSpinLockUnlock(&This->lock);
858 hr = ca_get_max_stream_latency(This, &stream_latency);
860 OSSpinLockUnlock(&This->lock);
864 latency += stream_latency;
865 *out = (latency / (double)This->fmt->nSamplesPerSec) * 10000000;
867 OSSpinLockUnlock(&This->lock);
872 static HRESULT AudioClient_GetCurrentPadding_nolock(ACImpl *This,
876 return AUDCLNT_E_NOT_INITIALIZED;
878 *numpad = This->inbuf_frames;
883 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
886 ACImpl *This = impl_from_IAudioClient(iface);
889 TRACE("(%p)->(%p)\n", This, numpad);
894 OSSpinLockLock(&This->lock);
896 hr = AudioClient_GetCurrentPadding_nolock(This, numpad);
898 OSSpinLockUnlock(&This->lock);
903 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
904 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
905 WAVEFORMATEX **outpwfx)
907 ACImpl *This = impl_from_IAudioClient(iface);
908 AudioQueueRef aqueue;
911 TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx);
913 if(!pwfx || (mode == AUDCLNT_SHAREMODE_SHARED && !outpwfx))
916 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
919 if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
920 pwfx->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
925 OSSpinLockLock(&This->lock);
927 hr = ca_setup_aqueue(This->adevid, This->dataflow, pwfx, NULL, &aqueue);
929 AudioQueueDispose(aqueue, 1);
930 OSSpinLockUnlock(&This->lock);
933 TRACE("returning %08x\n", S_OK);
937 OSSpinLockUnlock(&This->lock);
942 TRACE("returning %08x\n", AUDCLNT_E_UNSUPPORTED_FORMAT);
943 return AUDCLNT_E_UNSUPPORTED_FORMAT;
946 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
949 ACImpl *This = impl_from_IAudioClient(iface);
950 WAVEFORMATEXTENSIBLE *fmt;
954 AudioBufferList *buffers;
955 AudioObjectPropertyAddress addr;
958 TRACE("(%p)->(%p)\n", This, pwfx);
963 *pwfx = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEXTENSIBLE));
965 return E_OUTOFMEMORY;
967 fmt = (WAVEFORMATEXTENSIBLE*)*pwfx;
969 fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
971 if(This->dataflow == eRender)
972 addr.mScope = kAudioDevicePropertyScopeOutput;
973 else if(This->dataflow == eCapture)
974 addr.mScope = kAudioDevicePropertyScopeInput;
976 OSSpinLockUnlock(&This->lock);
980 addr.mSelector = kAudioDevicePropertyStreamConfiguration;
982 sc = AudioObjectGetPropertyDataSize(This->adevid, &addr, 0, NULL, &size);
984 HeapFree(GetProcessHeap(), 0, fmt);
985 WARN("Unable to get size for _StreamConfiguration property: %lx\n", sc);
989 buffers = HeapAlloc(GetProcessHeap(), 0, size);
991 HeapFree(GetProcessHeap(), 0, fmt);
992 return E_OUTOFMEMORY;
995 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL,
998 HeapFree(GetProcessHeap(), 0, fmt);
999 HeapFree(GetProcessHeap(), 0, buffers);
1000 WARN("Unable to get _StreamConfiguration property: %lx\n", sc);
1004 fmt->Format.nChannels = 0;
1005 for(i = 0; i < buffers->mNumberBuffers; ++i)
1006 fmt->Format.nChannels += buffers->mBuffers[i].mNumberChannels;
1008 HeapFree(GetProcessHeap(), 0, buffers);
1010 fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
1012 addr.mSelector = kAudioDevicePropertyNominalSampleRate;
1013 size = sizeof(Float64);
1014 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL, &size, &rate);
1016 HeapFree(GetProcessHeap(), 0, fmt);
1017 WARN("Unable to get _NominalSampleRate property: %lx\n", sc);
1020 fmt->Format.nSamplesPerSec = rate;
1022 /* CoreAudio doesn't seem to give a device format preference, so just
1023 * choose a common format... */
1024 fmt->Format.wBitsPerSample = 16;
1025 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1027 fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
1028 fmt->Format.nChannels) / 8;
1029 fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
1030 fmt->Format.nBlockAlign;
1032 fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
1033 fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1040 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
1041 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1043 ACImpl *This = impl_from_IAudioClient(iface);
1045 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
1047 if(!defperiod && !minperiod)
1050 OSSpinLockLock(&This->lock);
1052 if(This->period_ms){
1054 *defperiod = This->period_ms * 10000;
1056 *minperiod = This->period_ms * 10000;
1059 *defperiod = DefaultPeriod;
1061 *minperiod = MinimumPeriod;
1064 OSSpinLockUnlock(&This->lock);
1069 void CALLBACK ca_period_cb(void *user, BOOLEAN timer)
1071 ACImpl *This = user;
1073 OSSpinLockLock(&This->lock);
1075 SetEvent(This->event);
1076 OSSpinLockUnlock(&This->lock);
1079 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
1081 ACImpl *This = impl_from_IAudioClient(iface);
1084 TRACE("(%p)\n", This);
1086 OSSpinLockLock(&This->lock);
1089 OSSpinLockUnlock(&This->lock);
1090 return AUDCLNT_E_NOT_INITIALIZED;
1093 if(This->playing != StateStopped){
1094 OSSpinLockUnlock(&This->lock);
1095 return AUDCLNT_E_NOT_STOPPED;
1098 if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
1099 OSSpinLockUnlock(&This->lock);
1100 return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1104 if(!CreateTimerQueueTimer(&This->timer, g_timer_q,
1105 ca_period_cb, This, 0, This->period_ms, 0))
1106 ERR("Unable to create timer: %u\n", GetLastError());
1108 This->playing = StateInTransition;
1110 OSSpinLockUnlock(&This->lock);
1112 sc = AudioQueueStart(This->aqueue, NULL);
1114 WARN("Unable to start audio queue: %lx\n", sc);
1118 OSSpinLockLock(&This->lock);
1120 This->playing = StatePlaying;
1122 OSSpinLockUnlock(&This->lock);
1127 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
1129 ACImpl *This = impl_from_IAudioClient(iface);
1132 TRACE("(%p)\n", This);
1134 OSSpinLockLock(&This->lock);
1137 OSSpinLockUnlock(&This->lock);
1138 return AUDCLNT_E_NOT_INITIALIZED;
1141 if(This->playing == StateStopped){
1142 OSSpinLockUnlock(&This->lock);
1146 if(This->playing == StateInTransition){
1147 OSSpinLockUnlock(&This->lock);
1151 if(This->timer && This->timer != INVALID_HANDLE_VALUE){
1152 DeleteTimerQueueTimer(g_timer_q, This->timer, INVALID_HANDLE_VALUE);
1156 This->playing = StateInTransition;
1158 OSSpinLockUnlock(&This->lock);
1160 sc = AudioQueueFlush(This->aqueue);
1162 WARN("Unable to flush audio queue: %lx\n", sc);
1164 sc = AudioQueuePause(This->aqueue);
1166 WARN("Unable to pause audio queue: %lx\n", sc);
1170 OSSpinLockLock(&This->lock);
1172 This->playing = StateStopped;
1174 OSSpinLockUnlock(&This->lock);
1179 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
1181 ACImpl *This = impl_from_IAudioClient(iface);
1185 TRACE("(%p)\n", This);
1187 OSSpinLockLock(&This->lock);
1190 OSSpinLockUnlock(&This->lock);
1191 return AUDCLNT_E_NOT_INITIALIZED;
1194 if(This->playing != StateStopped){
1195 OSSpinLockUnlock(&This->lock);
1196 return AUDCLNT_E_NOT_STOPPED;
1199 This->written_frames = 0;
1201 hr = AudioClock_GetPosition_nolock(This, &This->last_time, NULL, TRUE);
1203 OSSpinLockUnlock(&This->lock);
1207 OSSpinLockUnlock(&This->lock);
1209 sc = AudioQueueReset(This->aqueue);
1211 WARN("Unable to reset audio queue: %lx\n", sc);
1218 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1221 ACImpl *This = impl_from_IAudioClient(iface);
1223 TRACE("(%p)->(%p)\n", This, event);
1226 return E_INVALIDARG;
1228 OSSpinLockLock(&This->lock);
1231 OSSpinLockUnlock(&This->lock);
1232 return AUDCLNT_E_NOT_INITIALIZED;
1235 if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
1236 OSSpinLockUnlock(&This->lock);
1237 return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1240 This->event = event;
1242 OSSpinLockUnlock(&This->lock);
1247 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1250 ACImpl *This = impl_from_IAudioClient(iface);
1252 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1258 OSSpinLockLock(&This->lock);
1261 OSSpinLockUnlock(&This->lock);
1262 return AUDCLNT_E_NOT_INITIALIZED;
1265 OSSpinLockUnlock(&This->lock);
1267 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1268 if(This->dataflow != eRender)
1269 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1270 *ppv = &This->IAudioRenderClient_iface;
1271 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1272 if(This->dataflow != eCapture)
1273 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1274 *ppv = &This->IAudioCaptureClient_iface;
1275 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1276 *ppv = &This->IAudioSessionControl2_iface;
1277 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1278 *ppv = &This->ISimpleAudioVolume_iface;
1279 }else if(IsEqualIID(riid, &IID_IAudioClock)){
1280 *ppv = &This->IAudioClock_iface;
1284 IUnknown_AddRef((IUnknown*)*ppv);
1288 FIXME("stub %s\n", debugstr_guid(riid));
1289 return E_NOINTERFACE;
1292 static const IAudioClientVtbl AudioClient_Vtbl =
1294 AudioClient_QueryInterface,
1296 AudioClient_Release,
1297 AudioClient_Initialize,
1298 AudioClient_GetBufferSize,
1299 AudioClient_GetStreamLatency,
1300 AudioClient_GetCurrentPadding,
1301 AudioClient_IsFormatSupported,
1302 AudioClient_GetMixFormat,
1303 AudioClient_GetDevicePeriod,
1307 AudioClient_SetEventHandle,
1308 AudioClient_GetService
1311 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1312 IAudioRenderClient *iface, REFIID riid, void **ppv)
1314 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1320 if(IsEqualIID(riid, &IID_IUnknown) ||
1321 IsEqualIID(riid, &IID_IAudioRenderClient))
1324 IUnknown_AddRef((IUnknown*)*ppv);
1328 WARN("Unknown interface %s\n", debugstr_guid(riid));
1329 return E_NOINTERFACE;
1332 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1334 ACImpl *This = impl_from_IAudioRenderClient(iface);
1335 return AudioClient_AddRef(&This->IAudioClient_iface);
1338 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1340 ACImpl *This = impl_from_IAudioRenderClient(iface);
1341 return AudioClient_Release(&This->IAudioClient_iface);
1344 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1345 UINT32 frames, BYTE **data)
1347 ACImpl *This = impl_from_IAudioRenderClient(iface);
1349 UINT32 pad, bytes = frames * This->fmt->nBlockAlign;
1353 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1358 OSSpinLockLock(&This->lock);
1360 if(This->getbuf_last){
1361 OSSpinLockUnlock(&This->lock);
1362 return AUDCLNT_E_OUT_OF_ORDER;
1366 This->getbuf_last = TRUE;
1367 OSSpinLockUnlock(&This->lock);
1371 hr = AudioClient_GetCurrentPadding_nolock(This, &pad);
1373 OSSpinLockUnlock(&This->lock);
1377 if(pad + frames > This->bufsize_frames){
1378 OSSpinLockUnlock(&This->lock);
1379 return AUDCLNT_E_BUFFER_TOO_LARGE;
1382 LIST_FOR_EACH_ENTRY(buf, &This->avail_buffers, AQBuffer, entry){
1383 if(buf->buf->mAudioDataBytesCapacity >= bytes){
1384 This->public_buffer = buf->buf;
1385 list_remove(&buf->entry);
1390 if(&buf->entry == &This->avail_buffers){
1391 sc = AudioQueueAllocateBuffer(This->aqueue, bytes,
1392 &This->public_buffer);
1394 OSSpinLockUnlock(&This->lock);
1395 WARN("Unable to allocate buffer: %lx\n", sc);
1398 buf = HeapAlloc(GetProcessHeap(), 0, sizeof(AQBuffer));
1400 AudioQueueFreeBuffer(This->aqueue, This->public_buffer);
1401 This->public_buffer = NULL;
1402 OSSpinLockUnlock(&This->lock);
1403 return E_OUTOFMEMORY;
1405 buf->buf = This->public_buffer;
1406 This->public_buffer->mUserData = buf;
1409 *data = This->public_buffer->mAudioData;
1411 This->getbuf_last = TRUE;
1413 OSSpinLockUnlock(&This->lock);
1418 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1419 IAudioRenderClient *iface, UINT32 frames, DWORD flags)
1421 ACImpl *This = impl_from_IAudioRenderClient(iface);
1424 TRACE("(%p)->(%u, %x)\n", This, frames, flags);
1426 OSSpinLockLock(&This->lock);
1428 if(!This->getbuf_last){
1429 OSSpinLockUnlock(&This->lock);
1430 return AUDCLNT_E_OUT_OF_ORDER;
1433 if(flags & AUDCLNT_BUFFERFLAGS_SILENT){
1434 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)This->fmt;
1435 if((This->fmt->wFormatTag == WAVE_FORMAT_PCM ||
1436 (This->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1437 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) &&
1438 This->fmt->wBitsPerSample == 8)
1439 memset(This->public_buffer->mAudioData, 128,
1440 frames * This->fmt->nBlockAlign);
1442 memset(This->public_buffer->mAudioData, 0,
1443 frames * This->fmt->nBlockAlign);
1446 This->public_buffer->mAudioDataByteSize = frames * This->fmt->nBlockAlign;
1448 sc = AudioQueueEnqueueBuffer(This->aqueue, This->public_buffer, 0, NULL);
1450 OSSpinLockUnlock(&This->lock);
1451 WARN("Unable to enqueue buffer: %lx\n", sc);
1455 if(This->playing == StateStopped)
1456 AudioQueuePrime(This->aqueue, 0, NULL);
1458 This->public_buffer = NULL;
1459 This->getbuf_last = FALSE;
1460 This->written_frames += frames;
1461 This->inbuf_frames += frames;
1463 OSSpinLockUnlock(&This->lock);
1468 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1469 AudioRenderClient_QueryInterface,
1470 AudioRenderClient_AddRef,
1471 AudioRenderClient_Release,
1472 AudioRenderClient_GetBuffer,
1473 AudioRenderClient_ReleaseBuffer
1476 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1477 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1479 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1485 if(IsEqualIID(riid, &IID_IUnknown) ||
1486 IsEqualIID(riid, &IID_IAudioCaptureClient))
1489 IUnknown_AddRef((IUnknown*)*ppv);
1493 WARN("Unknown interface %s\n", debugstr_guid(riid));
1494 return E_NOINTERFACE;
1497 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1499 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1500 return IAudioClient_AddRef(&This->IAudioClient_iface);
1503 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1505 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1506 return IAudioClient_Release(&This->IAudioClient_iface);
1509 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1510 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1513 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1515 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1518 if(!data || !frames || !flags)
1521 OSSpinLockLock(&This->lock);
1523 if(This->getbuf_last){
1524 OSSpinLockUnlock(&This->lock);
1525 return AUDCLNT_E_OUT_OF_ORDER;
1528 if(This->public_buffer){
1529 *data = This->public_buffer->mAudioData;
1531 This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
1533 struct list *head = list_head(&This->avail_buffers);
1538 AQBuffer *buf = LIST_ENTRY(head, AQBuffer, entry);
1539 This->public_buffer = buf->buf;
1540 *data = This->public_buffer->mAudioData;
1542 This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
1543 list_remove(&buf->entry);
1548 This->written_frames += *frames;
1549 This->inbuf_frames -= *frames;
1550 This->getbuf_last = TRUE;
1552 if(devpos || qpcpos)
1553 AudioClock_GetPosition_nolock(This, devpos, qpcpos, FALSE);
1555 OSSpinLockUnlock(&This->lock);
1557 return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
1560 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1561 IAudioCaptureClient *iface, UINT32 done)
1563 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1564 UINT32 pbuf_frames =
1565 This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
1568 TRACE("(%p)->(%u)\n", This, done);
1570 OSSpinLockLock(&This->lock);
1572 if(!This->getbuf_last){
1573 OSSpinLockUnlock(&This->lock);
1574 return AUDCLNT_E_OUT_OF_ORDER;
1577 if(done != 0 && done != pbuf_frames){
1578 OSSpinLockUnlock(&This->lock);
1579 return AUDCLNT_E_INVALID_SIZE;
1583 sc = AudioQueueEnqueueBuffer(This->aqueue, This->public_buffer,
1586 WARN("Unable to enqueue buffer: %lx\n", sc);
1587 This->public_buffer = NULL;
1590 This->getbuf_last = FALSE;
1592 OSSpinLockUnlock(&This->lock);
1597 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1598 IAudioCaptureClient *iface, UINT32 *frames)
1600 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1604 TRACE("(%p)->(%p)\n", This, frames);
1609 OSSpinLockLock(&This->lock);
1611 head = list_head(&This->avail_buffers);
1614 *frames = This->bufsize_frames / CAPTURE_BUFFERS;
1615 OSSpinLockUnlock(&This->lock);
1619 buf = LIST_ENTRY(head, AQBuffer, entry);
1620 *frames = buf->buf->mAudioDataByteSize / This->fmt->nBlockAlign;
1622 OSSpinLockUnlock(&This->lock);
1627 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1629 AudioCaptureClient_QueryInterface,
1630 AudioCaptureClient_AddRef,
1631 AudioCaptureClient_Release,
1632 AudioCaptureClient_GetBuffer,
1633 AudioCaptureClient_ReleaseBuffer,
1634 AudioCaptureClient_GetNextPacketSize
1637 static HRESULT WINAPI AudioSessionControl_QueryInterface(
1638 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
1640 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1646 if(IsEqualIID(riid, &IID_IUnknown) ||
1647 IsEqualIID(riid, &IID_IAudioSessionControl) ||
1648 IsEqualIID(riid, &IID_IAudioSessionControl2))
1651 IUnknown_AddRef((IUnknown*)*ppv);
1655 WARN("Unknown interface %s\n", debugstr_guid(riid));
1656 return E_NOINTERFACE;
1659 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
1661 ACImpl *This = impl_from_IAudioSessionControl2(iface);
1662 return IAudioClient_AddRef(&This->IAudioClient_iface);
1665 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
1667 ACImpl *This = impl_from_IAudioSessionControl2(iface);
1668 return IAudioClient_Release(&This->IAudioClient_iface);
1671 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
1672 AudioSessionState *state)
1674 ACImpl *This = impl_from_IAudioSessionControl2(iface);
1676 FIXME("(%p)->(%p) - stub\n", This, state);
1684 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
1685 IAudioSessionControl2 *iface, WCHAR **name)
1687 ACImpl *This = impl_from_IAudioSessionControl2(iface);
1689 FIXME("(%p)->(%p) - stub\n", This, name);
1694 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
1695 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
1697 ACImpl *This = impl_from_IAudioSessionControl2(iface);
1699 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
1704 static HRESULT WINAPI AudioSessionControl_GetIconPath(
1705 IAudioSessionControl2 *iface, WCHAR **path)
1707 ACImpl *This = impl_from_IAudioSessionControl2(iface);
1709 FIXME("(%p)->(%p) - stub\n", This, path);
1714 static HRESULT WINAPI AudioSessionControl_SetIconPath(
1715 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
1717 ACImpl *This = impl_from_IAudioSessionControl2(iface);
1719 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
1724 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
1725 IAudioSessionControl2 *iface, GUID *group)
1727 ACImpl *This = impl_from_IAudioSessionControl2(iface);
1729 FIXME("(%p)->(%p) - stub\n", This, group);
1734 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
1735 IAudioSessionControl2 *iface, GUID *group, const GUID *session)
1737 ACImpl *This = impl_from_IAudioSessionControl2(iface);
1739 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
1740 debugstr_guid(session));
1745 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
1746 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
1748 ACImpl *This = impl_from_IAudioSessionControl2(iface);
1750 FIXME("(%p)->(%p) - stub\n", This, events);
1755 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
1756 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
1758 ACImpl *This = impl_from_IAudioSessionControl2(iface);
1760 FIXME("(%p)->(%p) - stub\n", This, events);
1765 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
1766 IAudioSessionControl2 *iface, WCHAR **id)
1768 ACImpl *This = impl_from_IAudioSessionControl2(iface);
1770 FIXME("(%p)->(%p) - stub\n", This, id);
1775 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
1776 IAudioSessionControl2 *iface, WCHAR **id)
1778 ACImpl *This = impl_from_IAudioSessionControl2(iface);
1780 FIXME("(%p)->(%p) - stub\n", This, id);
1785 static HRESULT WINAPI AudioSessionControl_GetProcessId(
1786 IAudioSessionControl2 *iface, DWORD *pid)
1788 ACImpl *This = impl_from_IAudioSessionControl2(iface);
1790 TRACE("(%p)->(%p)\n", This, pid);
1795 *pid = GetCurrentProcessId();
1800 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
1801 IAudioSessionControl2 *iface)
1803 ACImpl *This = impl_from_IAudioSessionControl2(iface);
1805 TRACE("(%p)\n", This);
1810 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
1811 IAudioSessionControl2 *iface, BOOL optout)
1813 ACImpl *This = impl_from_IAudioSessionControl2(iface);
1815 TRACE("(%p)->(%d)\n", This, optout);
1820 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
1822 AudioSessionControl_QueryInterface,
1823 AudioSessionControl_AddRef,
1824 AudioSessionControl_Release,
1825 AudioSessionControl_GetState,
1826 AudioSessionControl_GetDisplayName,
1827 AudioSessionControl_SetDisplayName,
1828 AudioSessionControl_GetIconPath,
1829 AudioSessionControl_SetIconPath,
1830 AudioSessionControl_GetGroupingParam,
1831 AudioSessionControl_SetGroupingParam,
1832 AudioSessionControl_RegisterAudioSessionNotification,
1833 AudioSessionControl_UnregisterAudioSessionNotification,
1834 AudioSessionControl_GetSessionIdentifier,
1835 AudioSessionControl_GetSessionInstanceIdentifier,
1836 AudioSessionControl_GetProcessId,
1837 AudioSessionControl_IsSystemSoundsSession,
1838 AudioSessionControl_SetDuckingPreference
1841 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
1842 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
1844 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1850 if(IsEqualIID(riid, &IID_IUnknown) ||
1851 IsEqualIID(riid, &IID_ISimpleAudioVolume))
1854 IUnknown_AddRef((IUnknown*)*ppv);
1858 WARN("Unknown interface %s\n", debugstr_guid(riid));
1859 return E_NOINTERFACE;
1862 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
1864 ACImpl *This = impl_from_ISimpleAudioVolume(iface);
1865 return IAudioClient_AddRef(&This->IAudioClient_iface);
1868 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
1870 ACImpl *This = impl_from_ISimpleAudioVolume(iface);
1871 return IAudioClient_Release(&This->IAudioClient_iface);
1874 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
1875 ISimpleAudioVolume *iface, float level, const GUID *context)
1877 ACImpl *This = impl_from_ISimpleAudioVolume(iface);
1879 FIXME("(%p)->(%f, %p) - stub\n", This, level, context);
1884 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
1885 ISimpleAudioVolume *iface, float *level)
1887 ACImpl *This = impl_from_ISimpleAudioVolume(iface);
1889 FIXME("(%p)->(%p) - stub\n", This, level);
1894 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
1895 BOOL mute, const GUID *context)
1897 ACImpl *This = impl_from_ISimpleAudioVolume(iface);
1899 FIXME("(%p)->(%u, %p) - stub\n", This, mute, context);
1904 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
1907 ACImpl *This = impl_from_ISimpleAudioVolume(iface);
1909 FIXME("(%p)->(%p) - stub\n", This, mute);
1914 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
1916 SimpleAudioVolume_QueryInterface,
1917 SimpleAudioVolume_AddRef,
1918 SimpleAudioVolume_Release,
1919 SimpleAudioVolume_SetMasterVolume,
1920 SimpleAudioVolume_GetMasterVolume,
1921 SimpleAudioVolume_SetMute,
1922 SimpleAudioVolume_GetMute
1925 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1926 REFIID riid, void **ppv)
1928 ACImpl *This = impl_from_IAudioClock(iface);
1930 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1936 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
1938 else if(IsEqualIID(riid, &IID_IAudioClock2))
1939 *ppv = &This->IAudioClock2_iface;
1941 IUnknown_AddRef((IUnknown*)*ppv);
1945 WARN("Unknown interface %s\n", debugstr_guid(riid));
1946 return E_NOINTERFACE;
1949 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
1951 ACImpl *This = impl_from_IAudioClock(iface);
1952 return IAudioClient_AddRef(&This->IAudioClient_iface);
1955 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
1957 ACImpl *This = impl_from_IAudioClock(iface);
1958 return IAudioClient_Release(&This->IAudioClient_iface);
1961 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
1963 ACImpl *This = impl_from_IAudioClock(iface);
1965 TRACE("(%p)->(%p)\n", This, freq);
1967 *freq = This->fmt->nSamplesPerSec;
1972 static HRESULT AudioClock_GetPosition_nolock(ACImpl *This,
1973 UINT64 *pos, UINT64 *qpctime, BOOL raw)
1975 AudioTimeStamp time;
1978 sc = AudioQueueGetCurrentTime(This->aqueue, NULL, &time, NULL);
1979 if(sc == kAudioQueueErr_InvalidRunState){
1981 }else if(sc == noErr){
1982 if(!(time.mFlags & kAudioTimeStampSampleTimeValid)){
1983 FIXME("Sample time not valid, should calculate from something else\n");
1988 *pos = time.mSampleTime;
1990 *pos = time.mSampleTime - This->last_time;
1992 WARN("Unable to get current time: %lx\n", sc);
1997 LARGE_INTEGER stamp, freq;
1998 QueryPerformanceCounter(&stamp);
1999 QueryPerformanceFrequency(&freq);
2000 *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
2006 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
2009 ACImpl *This = impl_from_IAudioClock(iface);
2012 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
2017 OSSpinLockLock(&This->lock);
2019 hr = AudioClock_GetPosition_nolock(This, pos, qpctime, FALSE);
2021 OSSpinLockUnlock(&This->lock);
2026 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
2029 ACImpl *This = impl_from_IAudioClock(iface);
2031 TRACE("(%p)->(%p)\n", This, chars);
2036 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
2041 static const IAudioClockVtbl AudioClock_Vtbl =
2043 AudioClock_QueryInterface,
2046 AudioClock_GetFrequency,
2047 AudioClock_GetPosition,
2048 AudioClock_GetCharacteristics
2051 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
2052 REFIID riid, void **ppv)
2054 ACImpl *This = impl_from_IAudioClock2(iface);
2055 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
2058 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
2060 ACImpl *This = impl_from_IAudioClock2(iface);
2061 return IAudioClient_AddRef(&This->IAudioClient_iface);
2064 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
2066 ACImpl *This = impl_from_IAudioClock2(iface);
2067 return IAudioClient_Release(&This->IAudioClient_iface);
2070 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
2071 UINT64 *pos, UINT64 *qpctime)
2073 ACImpl *This = impl_from_IAudioClock2(iface);
2075 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
2080 static const IAudioClock2Vtbl AudioClock2_Vtbl =
2082 AudioClock2_QueryInterface,
2084 AudioClock2_Release,
2085 AudioClock2_GetDevicePosition