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"
40 #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 _QueuedBufInfo {
69 Float64 start_sampletime;
75 typedef struct _AQBuffer {
76 AudioQueueBufferRef buf;
81 typedef struct ACImpl ACImpl;
83 typedef struct _AudioSession {
94 CRITICAL_SECTION lock;
99 typedef struct _AudioSessionWrapper {
100 IAudioSessionControl2 IAudioSessionControl2_iface;
101 IChannelAudioVolume IChannelAudioVolume_iface;
102 ISimpleAudioVolume ISimpleAudioVolume_iface;
107 AudioSession *session;
108 } AudioSessionWrapper;
111 IAudioClient IAudioClient_iface;
112 IAudioRenderClient IAudioRenderClient_iface;
113 IAudioCaptureClient IAudioCaptureClient_iface;
114 IAudioClock IAudioClock_iface;
115 IAudioClock2 IAudioClock2_iface;
116 IAudioStreamVolume IAudioStreamVolume_iface;
126 AUDCLNT_SHAREMODE share;
130 AudioDeviceID adevid;
131 AudioQueueRef aqueue;
132 AudioObjectPropertyScope scope;
134 UINT32 period_ms, bufsize_frames, inbuf_frames;
135 UINT64 last_time, written_frames;
136 AudioQueueBufferRef public_buffer;
140 Float64 highest_sampletime;
142 AudioSession *session;
143 AudioSessionWrapper *session_wrapper;
147 struct list avail_buffers;
148 struct list queued_bufinfos;
150 /* We can't use debug printing or {Enter,Leave}CriticalSection from
151 * OSX callback threads, so we use OSX's OSSpinLock for synchronization
152 * instead. OSSpinLock is not a recursive lock, so don't call
153 * synchronized functions while holding the lock. */
163 static const IAudioClientVtbl AudioClient_Vtbl;
164 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
165 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
166 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
167 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
168 static const IAudioClockVtbl AudioClock_Vtbl;
169 static const IAudioClock2Vtbl AudioClock2_Vtbl;
170 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
171 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
172 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl;
174 typedef struct _SessionMgr {
175 IAudioSessionManager2 IAudioSessionManager2_iface;
182 static HANDLE g_timer_q;
184 static CRITICAL_SECTION g_sessions_lock;
185 static CRITICAL_SECTION_DEBUG g_sessions_lock_debug =
187 0, 0, &g_sessions_lock,
188 { &g_sessions_lock_debug.ProcessLocksList, &g_sessions_lock_debug.ProcessLocksList },
189 0, 0, { (DWORD_PTR)(__FILE__ ": g_sessions_lock") }
191 static CRITICAL_SECTION g_sessions_lock = { &g_sessions_lock_debug, -1, 0, 0, 0, 0 };
192 static struct list g_sessions = LIST_INIT(g_sessions);
194 static HRESULT AudioClock_GetPosition_nolock(ACImpl *This, UINT64 *pos,
196 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
197 static HRESULT ca_setvol(ACImpl *This, UINT32 index);
199 static inline ACImpl *impl_from_IAudioClient(IAudioClient *iface)
201 return CONTAINING_RECORD(iface, ACImpl, IAudioClient_iface);
204 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
206 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
209 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
211 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
214 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
216 return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
219 static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
221 return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
224 static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
226 return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
229 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
231 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
234 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
236 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
239 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
241 return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
244 static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface)
246 return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface);
249 BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
253 case DLL_PROCESS_ATTACH:
254 g_timer_q = CreateTimerQueue();
259 case DLL_PROCESS_DETACH:
260 DeleteCriticalSection(&g_sessions_lock);
266 /* From <dlls/mmdevapi/mmdevapi.h> */
267 enum DriverPriority {
268 Priority_Unavailable = 0,
274 int WINAPI AUDDRV_GetPriority(void)
276 return Priority_Neutral;
279 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids,
280 AudioDeviceID ***keys, UINT *num, UINT *def_index)
282 UInt32 devsize, size;
283 AudioDeviceID *devices;
284 AudioDeviceID default_id;
285 AudioObjectPropertyAddress addr;
289 TRACE("%d %p %p %p\n", flow, ids, num, def_index);
291 addr.mScope = kAudioObjectPropertyScopeGlobal;
292 addr.mElement = kAudioObjectPropertyElementMaster;
294 addr.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
295 else if(flow == eCapture)
296 addr.mSelector = kAudioHardwarePropertyDefaultInputDevice;
300 size = sizeof(default_id);
301 sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0,
302 NULL, &size, &default_id);
304 WARN("Getting _DefaultInputDevice property failed: %lx\n", sc);
308 addr.mSelector = kAudioHardwarePropertyDevices;
309 sc = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &addr, 0,
312 WARN("Getting _Devices property size failed: %lx\n", sc);
316 devices = HeapAlloc(GetProcessHeap(), 0, devsize);
318 return E_OUTOFMEMORY;
320 sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0, NULL,
323 WARN("Getting _Devices property failed: %lx\n", sc);
324 HeapFree(GetProcessHeap(), 0, devices);
328 ndevices = devsize / sizeof(AudioDeviceID);
330 *ids = HeapAlloc(GetProcessHeap(), 0, ndevices * sizeof(WCHAR *));
332 HeapFree(GetProcessHeap(), 0, devices);
333 return E_OUTOFMEMORY;
336 *keys = HeapAlloc(GetProcessHeap(), 0, ndevices * sizeof(AudioDeviceID *));
338 HeapFree(GetProcessHeap(), 0, *ids);
339 HeapFree(GetProcessHeap(), 0, devices);
340 return E_OUTOFMEMORY;
344 *def_index = (UINT)-1;
345 for(i = 0; i < ndevices; ++i){
346 AudioBufferList *buffers;
351 addr.mSelector = kAudioDevicePropertyStreamConfiguration;
353 addr.mScope = kAudioDevicePropertyScopeOutput;
355 addr.mScope = kAudioDevicePropertyScopeInput;
357 sc = AudioObjectGetPropertyDataSize(devices[i], &addr, 0, NULL, &size);
359 WARN("Unable to get _StreamConfiguration property size for "
360 "device %lu: %lx\n", devices[i], sc);
364 buffers = HeapAlloc(GetProcessHeap(), 0, size);
366 HeapFree(GetProcessHeap(), 0, devices);
367 for(j = 0; j < *num; ++j){
368 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
369 HeapFree(GetProcessHeap(), 0, (*keys)[j]);
371 HeapFree(GetProcessHeap(), 0, *keys);
372 HeapFree(GetProcessHeap(), 0, *ids);
373 return E_OUTOFMEMORY;
376 sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL,
379 WARN("Unable to get _StreamConfiguration property for "
380 "device %lu: %lx\n", devices[i], sc);
381 HeapFree(GetProcessHeap(), 0, buffers);
385 /* check that there's at least one channel in this device before
386 * we claim it as usable */
387 for(j = 0; j < buffers->mNumberBuffers; ++j)
388 if(buffers->mBuffers[j].mNumberChannels > 0)
390 if(j >= buffers->mNumberBuffers){
391 HeapFree(GetProcessHeap(), 0, buffers);
395 HeapFree(GetProcessHeap(), 0, buffers);
398 addr.mSelector = kAudioObjectPropertyName;
399 sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL,
402 WARN("Unable to get _Name property for device %lu: %lx\n",
407 len = CFStringGetLength(name) + 1;
408 (*ids)[*num] = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
411 HeapFree(GetProcessHeap(), 0, devices);
412 for(j = 0; j < *num; ++j){
413 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
414 HeapFree(GetProcessHeap(), 0, (*keys)[j]);
416 HeapFree(GetProcessHeap(), 0, *ids);
417 HeapFree(GetProcessHeap(), 0, *keys);
418 return E_OUTOFMEMORY;
420 CFStringGetCharacters(name, CFRangeMake(0, len - 1), (UniChar*)(*ids)[*num]);
421 ((*ids)[*num])[len - 1] = 0;
424 (*keys)[*num] = HeapAlloc(GetProcessHeap(), 0, sizeof(AudioDeviceID));
426 HeapFree(GetProcessHeap(), 0, devices);
427 HeapFree(GetProcessHeap(), 0, (*ids)[*num]);
428 for(j = 0; j < *num; ++j){
429 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
430 HeapFree(GetProcessHeap(), 0, (*keys)[j]);
432 HeapFree(GetProcessHeap(), 0, *ids);
433 HeapFree(GetProcessHeap(), 0, *keys);
434 return E_OUTOFMEMORY;
436 *(*keys)[*num] = devices[i];
438 if(*def_index == (UINT)-1 && devices[i] == default_id)
441 TRACE("device %u: id %s key %u%s\n", *num, debugstr_w((*ids)[*num]),
442 (unsigned int)*(*keys)[*num], (*def_index == *num) ? " (default)" : "");
447 if(*def_index == (UINT)-1)
450 HeapFree(GetProcessHeap(), 0, devices);
455 HRESULT WINAPI AUDDRV_GetAudioEndpoint(AudioDeviceID *adevid, IMMDevice *dev,
456 EDataFlow dataflow, IAudioClient **out)
460 TRACE("%u %p %d %p\n", (unsigned int)*adevid, dev, dataflow, out);
462 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACImpl));
464 return E_OUTOFMEMORY;
466 This->IAudioClient_iface.lpVtbl = &AudioClient_Vtbl;
467 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
468 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
469 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
470 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
471 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
473 This->dataflow = dataflow;
475 if(dataflow == eRender)
476 This->scope = kAudioDevicePropertyScopeOutput;
477 else if(dataflow == eCapture)
478 This->scope = kAudioDevicePropertyScopeInput;
480 HeapFree(GetProcessHeap(), 0, This);
487 IMMDevice_AddRef(This->parent);
489 list_init(&This->avail_buffers);
490 list_init(&This->queued_bufinfos);
492 This->adevid = *adevid;
494 *out = &This->IAudioClient_iface;
495 IAudioClient_AddRef(&This->IAudioClient_iface);
500 /* current position from start of stream */
501 #define BUFPOS_ABSOLUTE 1
502 /* current position from start of this buffer */
503 #define BUFPOS_RELATIVE 2
505 static UINT64 get_current_aqbuffer_position(ACImpl *This, int mode)
508 QueuedBufInfo *bufinfo;
511 head = list_head(&This->queued_bufinfos);
513 TRACE("No buffers queued\n");
514 if(mode == BUFPOS_ABSOLUTE)
515 return This->written_frames;
518 bufinfo = LIST_ENTRY(head, QueuedBufInfo, entry);
520 if(This->playing == StatePlaying){
521 AudioTimeStamp tstamp;
524 /* AudioQueueGetCurrentTime() is brain damaged. The returned
525 * mSampleTime member jumps backwards seemingly at random, so
526 * we record the highest sampletime and use that during these
529 * It also behaves poorly when the queue is paused, jumping
530 * forwards during the pause and backwards again after resuming.
531 * So we record the sampletime when the queue is paused and use
533 sc = AudioQueueGetCurrentTime(This->aqueue, NULL, &tstamp, NULL);
535 if(sc != kAudioQueueErr_InvalidRunState)
536 WARN("Unable to get current time: %lx\n", sc);
540 if(!(tstamp.mFlags & kAudioTimeStampSampleTimeValid)){
541 FIXME("SampleTime not valid: %lx\n", tstamp.mFlags);
545 if(tstamp.mSampleTime > This->highest_sampletime)
546 This->highest_sampletime = tstamp.mSampleTime;
549 while(This->highest_sampletime > bufinfo->start_sampletime + bufinfo->len_frames){
550 This->inbuf_frames -= bufinfo->len_frames;
551 list_remove(&bufinfo->entry);
552 HeapFree(GetProcessHeap(), 0, bufinfo);
554 head = list_head(&This->queued_bufinfos);
556 TRACE("No buffers queued\n");
557 if(mode == BUFPOS_ABSOLUTE)
558 return This->written_frames;
561 bufinfo = LIST_ENTRY(head, QueuedBufInfo, entry);
564 if(This->highest_sampletime < bufinfo->start_sampletime)
567 ret = This->highest_sampletime - bufinfo->start_sampletime;
569 if(mode == BUFPOS_ABSOLUTE)
570 ret += bufinfo->start_pos;
572 TRACE("%llu frames (%s)\n", ret,
573 mode == BUFPOS_ABSOLUTE ? "absolute" : "relative");
578 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient *iface,
579 REFIID riid, void **ppv)
581 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
586 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClient))
589 IUnknown_AddRef((IUnknown*)*ppv);
592 WARN("Unknown interface %s\n", debugstr_guid(riid));
593 return E_NOINTERFACE;
596 static ULONG WINAPI AudioClient_AddRef(IAudioClient *iface)
598 ACImpl *This = impl_from_IAudioClient(iface);
600 ref = InterlockedIncrement(&This->ref);
601 TRACE("(%p) Refcount now %u\n", This, ref);
605 static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
607 ACImpl *This = impl_from_IAudioClient(iface);
609 ref = InterlockedDecrement(&This->ref);
610 TRACE("(%p) Refcount now %u\n", This, ref);
613 AQBuffer *buf, *next;
614 QueuedBufInfo *bufinfo, *bufinfo2;
616 if(This->public_buffer){
617 buf = This->public_buffer->mUserData;
618 list_add_tail(&This->avail_buffers, &buf->entry);
621 IAudioClient_Stop(iface);
622 AudioQueueStop(This->aqueue, 1);
624 /* Stopped synchronously, all buffers returned. */
625 LIST_FOR_EACH_ENTRY_SAFE(buf, next, &This->avail_buffers, AQBuffer, entry){
626 AudioQueueFreeBuffer(This->aqueue, buf->buf);
627 HeapFree(GetProcessHeap(), 0, buf);
630 LIST_FOR_EACH_ENTRY_SAFE(bufinfo, bufinfo2, &This->queued_bufinfos,
631 QueuedBufInfo, entry)
632 HeapFree(GetProcessHeap(), 0, bufinfo);
634 AudioQueueDispose(This->aqueue, 1);
637 EnterCriticalSection(&g_sessions_lock);
638 list_remove(&This->entry);
639 LeaveCriticalSection(&g_sessions_lock);
641 HeapFree(GetProcessHeap(), 0, This->vols);
642 CoTaskMemFree(This->fmt);
643 IMMDevice_Release(This->parent);
644 HeapFree(GetProcessHeap(), 0, This);
649 static void dump_fmt(const WAVEFORMATEX *fmt)
651 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
652 switch(fmt->wFormatTag){
653 case WAVE_FORMAT_PCM:
654 TRACE("WAVE_FORMAT_PCM");
656 case WAVE_FORMAT_IEEE_FLOAT:
657 TRACE("WAVE_FORMAT_IEEE_FLOAT");
659 case WAVE_FORMAT_EXTENSIBLE:
660 TRACE("WAVE_FORMAT_EXTENSIBLE");
668 TRACE("nChannels: %u\n", fmt->nChannels);
669 TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
670 TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
671 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
672 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
673 TRACE("cbSize: %u\n", fmt->cbSize);
675 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
676 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
677 TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
678 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
679 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
683 static DWORD get_channel_mask(unsigned int channels)
689 return KSAUDIO_SPEAKER_MONO;
691 return KSAUDIO_SPEAKER_STEREO;
693 return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY;
695 return KSAUDIO_SPEAKER_QUAD; /* not _SURROUND */
697 return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY;
699 return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */
701 return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER;
703 return KSAUDIO_SPEAKER_7POINT1_SURROUND; /* Vista deprecates 7POINT1 */
705 FIXME("Unknown speaker configuration: %u\n", channels);
709 static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
714 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
715 size = sizeof(WAVEFORMATEXTENSIBLE);
717 size = sizeof(WAVEFORMATEX);
719 ret = CoTaskMemAlloc(size);
723 memcpy(ret, fmt, size);
725 ret->cbSize = size - sizeof(WAVEFORMATEX);
730 static HRESULT ca_get_audiodesc(AudioStreamBasicDescription *desc,
731 const WAVEFORMATEX *fmt)
733 const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)fmt;
735 desc->mFormatFlags = 0;
737 if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
738 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
739 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
740 desc->mFormatID = kAudioFormatLinearPCM;
741 if(fmt->wBitsPerSample > 8)
742 desc->mFormatFlags = kAudioFormatFlagIsSignedInteger;
743 }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
744 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
745 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
746 desc->mFormatID = kAudioFormatLinearPCM;
747 desc->mFormatFlags = kAudioFormatFlagIsFloat;
748 }else if(fmt->wFormatTag == WAVE_FORMAT_MULAW ||
749 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
750 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_MULAW))){
751 desc->mFormatID = kAudioFormatULaw;
752 }else if(fmt->wFormatTag == WAVE_FORMAT_ALAW ||
753 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
754 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_ALAW))){
755 desc->mFormatID = kAudioFormatALaw;
757 return AUDCLNT_E_UNSUPPORTED_FORMAT;
759 desc->mSampleRate = fmt->nSamplesPerSec;
760 desc->mBytesPerPacket = fmt->nBlockAlign;
761 desc->mFramesPerPacket = 1;
762 desc->mBytesPerFrame = fmt->nBlockAlign;
763 desc->mChannelsPerFrame = fmt->nChannels;
764 desc->mBitsPerChannel = fmt->wBitsPerSample;
770 static void ca_out_buffer_cb(void *user, AudioQueueRef aqueue,
771 AudioQueueBufferRef buffer)
774 AQBuffer *buf = buffer->mUserData;
776 OSSpinLockLock(&This->lock);
777 list_add_tail(&This->avail_buffers, &buf->entry);
778 OSSpinLockUnlock(&This->lock);
781 static void ca_in_buffer_cb(void *user, AudioQueueRef aqueue,
782 AudioQueueBufferRef buffer, const AudioTimeStamp *start,
783 UInt32 ndesc, const AudioStreamPacketDescription *descs)
786 AQBuffer *buf = buffer->mUserData;
788 OSSpinLockLock(&This->lock);
789 list_add_tail(&This->avail_buffers, &buf->entry);
790 This->inbuf_frames += buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
791 OSSpinLockUnlock(&This->lock);
794 static HRESULT ca_setup_aqueue(AudioDeviceID did, EDataFlow flow,
795 const WAVEFORMATEX *fmt, void *user, AudioQueueRef *aqueue)
797 AudioStreamBasicDescription desc;
798 AudioObjectPropertyAddress addr;
804 addr.mScope = kAudioObjectPropertyScopeGlobal;
806 addr.mSelector = kAudioDevicePropertyDeviceUID;
809 sc = AudioObjectGetPropertyData(did, &addr, 0, NULL, &size, &uid);
811 WARN("Unable to get _DeviceUID property: %lx\n", sc);
815 hr = ca_get_audiodesc(&desc, fmt);
822 sc = AudioQueueNewOutput(&desc, ca_out_buffer_cb, user, NULL, NULL, 0,
824 else if(flow == eCapture)
825 sc = AudioQueueNewInput(&desc, ca_in_buffer_cb, user, NULL, NULL, 0,
832 WARN("Unable to create AudioQueue: %lx\n", sc);
837 sc = AudioQueueSetProperty(*aqueue, kAudioQueueProperty_CurrentDevice,
849 static void session_init_vols(AudioSession *session, UINT channels)
851 if(session->channel_count < channels){
854 if(session->channel_vols)
855 session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
856 session->channel_vols, sizeof(float) * channels);
858 session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
859 sizeof(float) * channels);
860 if(!session->channel_vols)
863 for(i = session->channel_count; i < channels; ++i)
864 session->channel_vols[i] = 1.f;
866 session->channel_count = channels;
870 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
875 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
879 memcpy(&ret->guid, guid, sizeof(GUID));
881 ret->device = device;
883 list_init(&ret->clients);
885 list_add_head(&g_sessions, &ret->entry);
887 InitializeCriticalSection(&ret->lock);
888 ret->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": AudioSession.lock");
890 session_init_vols(ret, num_channels);
892 ret->master_vol = 1.f;
897 /* if channels == 0, then this will return or create a session with
898 * matching dataflow and GUID. otherwise, channels must also match */
899 static HRESULT get_audio_session(const GUID *sessionguid,
900 IMMDevice *device, UINT channels, AudioSession **out)
902 AudioSession *session;
904 if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
905 *out = create_session(&GUID_NULL, device, channels);
907 return E_OUTOFMEMORY;
913 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
914 if(session->device == device &&
915 IsEqualGUID(sessionguid, &session->guid)){
916 session_init_vols(session, channels);
923 *out = create_session(sessionguid, device, channels);
925 return E_OUTOFMEMORY;
931 static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
932 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
933 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
934 const GUID *sessionguid)
936 ACImpl *This = impl_from_IAudioClient(iface);
941 TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
942 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
949 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
950 return AUDCLNT_E_NOT_INITIALIZED;
952 if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
953 AUDCLNT_STREAMFLAGS_LOOPBACK |
954 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
955 AUDCLNT_STREAMFLAGS_NOPERSIST |
956 AUDCLNT_STREAMFLAGS_RATEADJUST |
957 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
958 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
959 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED)){
960 TRACE("Unknown flags: %08x\n", flags);
964 if(mode == AUDCLNT_SHAREMODE_SHARED){
965 period = DefaultPeriod;
966 if( duration < 3 * period)
967 duration = 3 * period;
970 period = DefaultPeriod; /* not minimum */
971 if(period < MinimumPeriod || period > 5000000)
972 return AUDCLNT_E_INVALID_DEVICE_PERIOD;
973 if(duration > 20000000) /* the smaller the period, the lower this limit */
974 return AUDCLNT_E_BUFFER_SIZE_ERROR;
975 if(flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK){
976 if(duration != period)
977 return AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL;
978 FIXME("EXCLUSIVE mode with EVENTCALLBACK\n");
979 return AUDCLNT_E_DEVICE_IN_USE;
981 if( duration < 8 * period)
982 duration = 8 * period; /* may grow above 2s */
986 OSSpinLockLock(&This->lock);
989 OSSpinLockUnlock(&This->lock);
990 return AUDCLNT_E_ALREADY_INITIALIZED;
993 hr = ca_setup_aqueue(This->adevid, This->dataflow, fmt, This, &This->aqueue);
995 OSSpinLockUnlock(&This->lock);
999 This->fmt = clone_format(fmt);
1001 AudioQueueDispose(This->aqueue, 1);
1002 This->aqueue = NULL;
1003 OSSpinLockUnlock(&This->lock);
1004 return E_OUTOFMEMORY;
1007 This->period_ms = period / 10000;
1009 This->bufsize_frames = MulDiv(duration, fmt->nSamplesPerSec, 10000000);
1011 if(This->dataflow == eCapture){
1013 UInt32 bsize = ceil((This->bufsize_frames / (double)CAPTURE_BUFFERS) *
1014 This->fmt->nBlockAlign);
1015 for(i = 0; i < CAPTURE_BUFFERS; ++i){
1018 buf = HeapAlloc(GetProcessHeap(), 0, sizeof(AQBuffer));
1020 AudioQueueDispose(This->aqueue, 1);
1021 This->aqueue = NULL;
1022 CoTaskMemFree(This->fmt);
1024 OSSpinLockUnlock(&This->lock);
1025 return E_OUTOFMEMORY;
1028 sc = AudioQueueAllocateBuffer(This->aqueue, bsize, &buf->buf);
1030 AudioQueueDispose(This->aqueue, 1);
1031 This->aqueue = NULL;
1032 CoTaskMemFree(This->fmt);
1034 OSSpinLockUnlock(&This->lock);
1035 WARN("Couldn't allocate buffer: %lx\n", sc);
1039 buf->buf->mUserData = buf;
1041 sc = AudioQueueEnqueueBuffer(This->aqueue, buf->buf, 0, NULL);
1043 ERR("Couldn't enqueue buffer: %lx\n", sc);
1049 This->vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float));
1051 AudioQueueDispose(This->aqueue, 1);
1052 This->aqueue = NULL;
1053 CoTaskMemFree(This->fmt);
1055 OSSpinLockUnlock(&This->lock);
1056 return E_OUTOFMEMORY;
1059 for(i = 0; i < fmt->nChannels; ++i)
1060 This->vols[i] = 1.f;
1063 This->flags = flags;
1065 EnterCriticalSection(&g_sessions_lock);
1067 hr = get_audio_session(sessionguid, This->parent, fmt->nChannels,
1070 LeaveCriticalSection(&g_sessions_lock);
1071 AudioQueueDispose(This->aqueue, 1);
1072 This->aqueue = NULL;
1073 CoTaskMemFree(This->fmt);
1075 HeapFree(GetProcessHeap(), 0, This->vols);
1077 OSSpinLockUnlock(&This->lock);
1078 return E_INVALIDARG;
1081 list_add_tail(&This->session->clients, &This->entry);
1083 LeaveCriticalSection(&g_sessions_lock);
1085 ca_setvol(This, -1);
1087 OSSpinLockUnlock(&This->lock);
1092 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
1095 ACImpl *This = impl_from_IAudioClient(iface);
1097 TRACE("(%p)->(%p)\n", This, frames);
1102 OSSpinLockLock(&This->lock);
1105 OSSpinLockUnlock(&This->lock);
1106 return AUDCLNT_E_NOT_INITIALIZED;
1109 *frames = This->bufsize_frames;
1111 OSSpinLockUnlock(&This->lock);
1116 static HRESULT ca_get_max_stream_latency(ACImpl *This, UInt32 *max)
1118 AudioObjectPropertyAddress addr;
1124 addr.mScope = This->scope;
1126 addr.mSelector = kAudioDevicePropertyStreams;
1128 sc = AudioObjectGetPropertyDataSize(This->adevid, &addr, 0, NULL,
1131 WARN("Unable to get size for _Streams property: %lx\n", sc);
1135 ids = HeapAlloc(GetProcessHeap(), 0, size);
1137 return E_OUTOFMEMORY;
1139 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL, &size, ids);
1141 WARN("Unable to get _Streams property: %lx\n", sc);
1142 HeapFree(GetProcessHeap(), 0, ids);
1146 nstreams = size / sizeof(AudioStreamID);
1149 addr.mSelector = kAudioStreamPropertyLatency;
1150 for(i = 0; i < nstreams; ++i){
1153 size = sizeof(latency);
1154 sc = AudioObjectGetPropertyData(ids[i], &addr, 0, NULL,
1157 WARN("Unable to get _Latency property: %lx\n", sc);
1165 HeapFree(GetProcessHeap(), 0, ids);
1170 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
1171 REFERENCE_TIME *out)
1173 ACImpl *This = impl_from_IAudioClient(iface);
1174 UInt32 latency, stream_latency, size;
1175 AudioObjectPropertyAddress addr;
1179 TRACE("(%p)->(%p)\n", This, out);
1184 OSSpinLockLock(&This->lock);
1187 OSSpinLockUnlock(&This->lock);
1188 return AUDCLNT_E_NOT_INITIALIZED;
1191 addr.mScope = This->scope;
1192 addr.mSelector = kAudioDevicePropertyLatency;
1195 size = sizeof(latency);
1196 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL,
1199 WARN("Couldn't get _Latency property: %lx\n", sc);
1200 OSSpinLockUnlock(&This->lock);
1204 hr = ca_get_max_stream_latency(This, &stream_latency);
1206 OSSpinLockUnlock(&This->lock);
1210 latency += stream_latency;
1211 /* pretend we process audio in Period chunks, so max latency includes
1212 * the period time */
1213 *out = MulDiv(latency, 10000000, This->fmt->nSamplesPerSec)
1214 + This->period_ms * 10000;
1216 OSSpinLockUnlock(&This->lock);
1221 static HRESULT AudioClient_GetCurrentPadding_nolock(ACImpl *This,
1225 return AUDCLNT_E_NOT_INITIALIZED;
1227 if(This->dataflow == eRender){
1229 bufpos = get_current_aqbuffer_position(This, BUFPOS_RELATIVE);
1230 *numpad = This->inbuf_frames - bufpos;
1232 *numpad = This->inbuf_frames;
1237 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
1240 ACImpl *This = impl_from_IAudioClient(iface);
1243 TRACE("(%p)->(%p)\n", This, numpad);
1248 OSSpinLockLock(&This->lock);
1250 hr = AudioClient_GetCurrentPadding_nolock(This, numpad);
1252 OSSpinLockUnlock(&This->lock);
1257 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
1258 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
1259 WAVEFORMATEX **outpwfx)
1261 ACImpl *This = impl_from_IAudioClient(iface);
1262 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)pwfx;
1263 AudioQueueRef aqueue;
1266 TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx);
1268 if(!pwfx || (mode == AUDCLNT_SHAREMODE_SHARED && !outpwfx))
1271 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1272 return E_INVALIDARG;
1274 if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1275 pwfx->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1276 return E_INVALIDARG;
1283 if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1284 fmtex->dwChannelMask != 0 &&
1285 fmtex->dwChannelMask != get_channel_mask(pwfx->nChannels))
1286 return AUDCLNT_E_UNSUPPORTED_FORMAT;
1288 OSSpinLockLock(&This->lock);
1290 hr = ca_setup_aqueue(This->adevid, This->dataflow, pwfx, NULL, &aqueue);
1292 AudioQueueDispose(aqueue, 1);
1293 OSSpinLockUnlock(&This->lock);
1294 TRACE("returning %08x\n", S_OK);
1298 OSSpinLockUnlock(&This->lock);
1300 TRACE("returning %08x\n", AUDCLNT_E_UNSUPPORTED_FORMAT);
1301 return AUDCLNT_E_UNSUPPORTED_FORMAT;
1304 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
1305 WAVEFORMATEX **pwfx)
1307 ACImpl *This = impl_from_IAudioClient(iface);
1308 WAVEFORMATEXTENSIBLE *fmt;
1312 AudioBufferList *buffers;
1313 AudioObjectPropertyAddress addr;
1316 TRACE("(%p)->(%p)\n", This, pwfx);
1322 fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
1324 return E_OUTOFMEMORY;
1326 fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1328 addr.mScope = This->scope;
1330 addr.mSelector = kAudioDevicePropertyStreamConfiguration;
1332 sc = AudioObjectGetPropertyDataSize(This->adevid, &addr, 0, NULL, &size);
1335 WARN("Unable to get size for _StreamConfiguration property: %lx\n", sc);
1339 buffers = HeapAlloc(GetProcessHeap(), 0, size);
1342 return E_OUTOFMEMORY;
1345 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL,
1349 HeapFree(GetProcessHeap(), 0, buffers);
1350 WARN("Unable to get _StreamConfiguration property: %lx\n", sc);
1354 fmt->Format.nChannels = 0;
1355 for(i = 0; i < buffers->mNumberBuffers; ++i)
1356 fmt->Format.nChannels += buffers->mBuffers[i].mNumberChannels;
1358 HeapFree(GetProcessHeap(), 0, buffers);
1360 fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
1362 addr.mSelector = kAudioDevicePropertyNominalSampleRate;
1363 size = sizeof(Float64);
1364 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL, &size, &rate);
1367 WARN("Unable to get _NominalSampleRate property: %lx\n", sc);
1370 fmt->Format.nSamplesPerSec = rate;
1372 fmt->Format.wBitsPerSample = 32;
1373 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
1375 fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
1376 fmt->Format.nChannels) / 8;
1377 fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
1378 fmt->Format.nBlockAlign;
1380 fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
1381 fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1383 *pwfx = (WAVEFORMATEX*)fmt;
1389 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
1390 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1392 ACImpl *This = impl_from_IAudioClient(iface);
1394 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
1396 if(!defperiod && !minperiod)
1400 *defperiod = DefaultPeriod;
1402 *minperiod = MinimumPeriod;
1407 void CALLBACK ca_period_cb(void *user, BOOLEAN timer)
1409 ACImpl *This = user;
1411 OSSpinLockLock(&This->lock);
1413 SetEvent(This->event);
1414 OSSpinLockUnlock(&This->lock);
1417 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
1419 ACImpl *This = impl_from_IAudioClient(iface);
1422 TRACE("(%p)\n", This);
1424 OSSpinLockLock(&This->lock);
1427 OSSpinLockUnlock(&This->lock);
1428 return AUDCLNT_E_NOT_INITIALIZED;
1431 if(This->playing != StateStopped){
1432 OSSpinLockUnlock(&This->lock);
1433 return AUDCLNT_E_NOT_STOPPED;
1436 if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
1437 OSSpinLockUnlock(&This->lock);
1438 return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1442 if(!CreateTimerQueueTimer(&This->timer, g_timer_q,
1443 ca_period_cb, This, 0, This->period_ms, 0))
1444 ERR("Unable to create timer: %u\n", GetLastError());
1446 This->playing = StateInTransition;
1448 OSSpinLockUnlock(&This->lock);
1450 sc = AudioQueueStart(This->aqueue, NULL);
1452 WARN("Unable to start audio queue: %lx\n", sc);
1456 OSSpinLockLock(&This->lock);
1458 This->playing = StatePlaying;
1460 OSSpinLockUnlock(&This->lock);
1465 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
1467 ACImpl *This = impl_from_IAudioClient(iface);
1468 AudioTimeStamp tstamp;
1471 TRACE("(%p)\n", This);
1473 OSSpinLockLock(&This->lock);
1476 OSSpinLockUnlock(&This->lock);
1477 return AUDCLNT_E_NOT_INITIALIZED;
1480 if(This->playing == StateStopped){
1481 OSSpinLockUnlock(&This->lock);
1485 if(This->playing == StateInTransition){
1486 OSSpinLockUnlock(&This->lock);
1490 if(This->timer && This->timer != INVALID_HANDLE_VALUE){
1491 DeleteTimerQueueTimer(g_timer_q, This->timer, INVALID_HANDLE_VALUE);
1495 This->playing = StateInTransition;
1497 sc = AudioQueueGetCurrentTime(This->aqueue, NULL, &tstamp, NULL);
1499 if(tstamp.mFlags & kAudioTimeStampSampleTimeValid){
1500 if(tstamp.mSampleTime > This->highest_sampletime)
1501 This->highest_sampletime = tstamp.mSampleTime;
1503 WARN("Returned tstamp mSampleTime not valid: %lx\n", tstamp.mFlags);
1505 WARN("GetCurrentTime failed: %lx\n", sc);
1507 OSSpinLockUnlock(&This->lock);
1509 sc = AudioQueueFlush(This->aqueue);
1511 WARN("Unable to flush audio queue: %lx\n", sc);
1513 sc = AudioQueuePause(This->aqueue);
1515 WARN("Unable to pause audio queue: %lx\n", sc);
1519 OSSpinLockLock(&This->lock);
1521 This->playing = StateStopped;
1523 OSSpinLockUnlock(&This->lock);
1528 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
1530 ACImpl *This = impl_from_IAudioClient(iface);
1532 QueuedBufInfo *bufinfo, *bufinfo2;
1534 TRACE("(%p)\n", This);
1536 OSSpinLockLock(&This->lock);
1539 OSSpinLockUnlock(&This->lock);
1540 return AUDCLNT_E_NOT_INITIALIZED;
1543 if(This->playing != StateStopped){
1544 OSSpinLockUnlock(&This->lock);
1545 return AUDCLNT_E_NOT_STOPPED;
1548 if(This->getbuf_last){
1549 OSSpinLockUnlock(&This->lock);
1550 return AUDCLNT_E_BUFFER_OPERATION_PENDING;
1553 This->written_frames = 0;
1554 This->inbuf_frames = 0;
1556 LIST_FOR_EACH_ENTRY_SAFE(bufinfo, bufinfo2, &This->queued_bufinfos,
1557 QueuedBufInfo, entry){
1558 list_remove(&bufinfo->entry);
1559 HeapFree(GetProcessHeap(), 0, bufinfo);
1562 OSSpinLockUnlock(&This->lock);
1564 sc = AudioQueueReset(This->aqueue);
1566 WARN("Unable to reset audio queue: %lx\n", sc);
1573 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1576 ACImpl *This = impl_from_IAudioClient(iface);
1578 TRACE("(%p)->(%p)\n", This, event);
1581 return E_INVALIDARG;
1583 OSSpinLockLock(&This->lock);
1586 OSSpinLockUnlock(&This->lock);
1587 return AUDCLNT_E_NOT_INITIALIZED;
1590 if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
1591 OSSpinLockUnlock(&This->lock);
1592 return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1595 This->event = event;
1597 OSSpinLockUnlock(&This->lock);
1602 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1605 ACImpl *This = impl_from_IAudioClient(iface);
1607 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1613 OSSpinLockLock(&This->lock);
1616 OSSpinLockUnlock(&This->lock);
1617 return AUDCLNT_E_NOT_INITIALIZED;
1620 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1621 if(This->dataflow != eRender){
1622 OSSpinLockUnlock(&This->lock);
1623 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1625 IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
1626 *ppv = &This->IAudioRenderClient_iface;
1627 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1628 if(This->dataflow != eCapture){
1629 OSSpinLockUnlock(&This->lock);
1630 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1632 IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
1633 *ppv = &This->IAudioCaptureClient_iface;
1634 }else if(IsEqualIID(riid, &IID_IAudioClock)){
1635 IAudioClock_AddRef(&This->IAudioClock_iface);
1636 *ppv = &This->IAudioClock_iface;
1637 }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1638 IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
1639 *ppv = &This->IAudioStreamVolume_iface;
1640 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1641 if(!This->session_wrapper){
1642 This->session_wrapper = AudioSessionWrapper_Create(This);
1643 if(!This->session_wrapper){
1644 OSSpinLockUnlock(&This->lock);
1645 return E_OUTOFMEMORY;
1648 IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
1650 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1651 }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1652 if(!This->session_wrapper){
1653 This->session_wrapper = AudioSessionWrapper_Create(This);
1654 if(!This->session_wrapper){
1655 OSSpinLockUnlock(&This->lock);
1656 return E_OUTOFMEMORY;
1659 IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
1661 *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1662 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1663 if(!This->session_wrapper){
1664 This->session_wrapper = AudioSessionWrapper_Create(This);
1665 if(!This->session_wrapper){
1666 OSSpinLockUnlock(&This->lock);
1667 return E_OUTOFMEMORY;
1670 ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
1672 *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1676 OSSpinLockUnlock(&This->lock);
1680 OSSpinLockUnlock(&This->lock);
1682 FIXME("stub %s\n", debugstr_guid(riid));
1683 return E_NOINTERFACE;
1686 static const IAudioClientVtbl AudioClient_Vtbl =
1688 AudioClient_QueryInterface,
1690 AudioClient_Release,
1691 AudioClient_Initialize,
1692 AudioClient_GetBufferSize,
1693 AudioClient_GetStreamLatency,
1694 AudioClient_GetCurrentPadding,
1695 AudioClient_IsFormatSupported,
1696 AudioClient_GetMixFormat,
1697 AudioClient_GetDevicePeriod,
1701 AudioClient_SetEventHandle,
1702 AudioClient_GetService
1705 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1706 IAudioRenderClient *iface, REFIID riid, void **ppv)
1708 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1714 if(IsEqualIID(riid, &IID_IUnknown) ||
1715 IsEqualIID(riid, &IID_IAudioRenderClient))
1718 IUnknown_AddRef((IUnknown*)*ppv);
1722 WARN("Unknown interface %s\n", debugstr_guid(riid));
1723 return E_NOINTERFACE;
1726 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1728 ACImpl *This = impl_from_IAudioRenderClient(iface);
1729 return AudioClient_AddRef(&This->IAudioClient_iface);
1732 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1734 ACImpl *This = impl_from_IAudioRenderClient(iface);
1735 return AudioClient_Release(&This->IAudioClient_iface);
1738 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1739 UINT32 frames, BYTE **data)
1741 ACImpl *This = impl_from_IAudioRenderClient(iface);
1743 UINT32 pad, bytes = frames * This->fmt->nBlockAlign;
1747 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1753 OSSpinLockLock(&This->lock);
1755 if(This->getbuf_last){
1756 OSSpinLockUnlock(&This->lock);
1757 return AUDCLNT_E_OUT_OF_ORDER;
1761 OSSpinLockUnlock(&This->lock);
1765 hr = AudioClient_GetCurrentPadding_nolock(This, &pad);
1767 OSSpinLockUnlock(&This->lock);
1771 if(pad + frames > This->bufsize_frames){
1772 OSSpinLockUnlock(&This->lock);
1773 return AUDCLNT_E_BUFFER_TOO_LARGE;
1776 LIST_FOR_EACH_ENTRY(buf, &This->avail_buffers, AQBuffer, entry){
1777 if(buf->buf->mAudioDataBytesCapacity >= bytes){
1778 This->public_buffer = buf->buf;
1779 list_remove(&buf->entry);
1784 if(&buf->entry == &This->avail_buffers){
1785 sc = AudioQueueAllocateBuffer(This->aqueue, bytes,
1786 &This->public_buffer);
1788 OSSpinLockUnlock(&This->lock);
1789 WARN("Unable to allocate buffer: %lx\n", sc);
1792 buf = HeapAlloc(GetProcessHeap(), 0, sizeof(AQBuffer));
1794 AudioQueueFreeBuffer(This->aqueue, This->public_buffer);
1795 This->public_buffer = NULL;
1796 OSSpinLockUnlock(&This->lock);
1797 return E_OUTOFMEMORY;
1799 buf->buf = This->public_buffer;
1800 This->public_buffer->mUserData = buf;
1803 *data = This->public_buffer->mAudioData;
1805 This->getbuf_last = frames;
1807 OSSpinLockUnlock(&This->lock);
1812 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1813 IAudioRenderClient *iface, UINT32 frames, DWORD flags)
1815 ACImpl *This = impl_from_IAudioRenderClient(iface);
1816 AudioTimeStamp start_time;
1819 TRACE("(%p)->(%u, %x)\n", This, frames, flags);
1821 OSSpinLockLock(&This->lock);
1824 This->getbuf_last = 0;
1825 if(This->public_buffer){
1826 AQBuffer *buf = This->public_buffer->mUserData;
1827 list_add_tail(&This->avail_buffers, &buf->entry);
1828 This->public_buffer = NULL;
1830 OSSpinLockUnlock(&This->lock);
1834 if(!This->getbuf_last){
1835 OSSpinLockUnlock(&This->lock);
1836 return AUDCLNT_E_OUT_OF_ORDER;
1839 if(frames > This->getbuf_last){
1840 OSSpinLockUnlock(&This->lock);
1841 return AUDCLNT_E_INVALID_SIZE;
1844 if(flags & AUDCLNT_BUFFERFLAGS_SILENT){
1845 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)This->fmt;
1846 if((This->fmt->wFormatTag == WAVE_FORMAT_PCM ||
1847 (This->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1848 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) &&
1849 This->fmt->wBitsPerSample == 8)
1850 memset(This->public_buffer->mAudioData, 128,
1851 frames * This->fmt->nBlockAlign);
1853 memset(This->public_buffer->mAudioData, 0,
1854 frames * This->fmt->nBlockAlign);
1857 This->public_buffer->mAudioDataByteSize = frames * This->fmt->nBlockAlign;
1859 sc = AudioQueueEnqueueBufferWithParameters(This->aqueue,
1860 This->public_buffer, 0, NULL, 0, 0, 0, NULL, NULL, &start_time);
1862 OSSpinLockUnlock(&This->lock);
1863 WARN("Unable to enqueue buffer: %lx\n", sc);
1867 if(start_time.mFlags & kAudioTimeStampSampleTimeValid){
1868 QueuedBufInfo *bufinfo;
1870 bufinfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*bufinfo));
1871 bufinfo->start_sampletime = start_time.mSampleTime;
1872 bufinfo->start_pos = This->written_frames;
1873 bufinfo->len_frames = frames;
1875 list_add_tail(&This->queued_bufinfos, &bufinfo->entry);
1877 WARN("Start time didn't contain valid SampleTime member\n");
1879 if(This->playing == StateStopped)
1880 AudioQueuePrime(This->aqueue, 0, NULL);
1882 This->public_buffer = NULL;
1883 This->getbuf_last = 0;
1884 This->written_frames += frames;
1885 This->inbuf_frames += frames;
1887 OSSpinLockUnlock(&This->lock);
1892 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1893 AudioRenderClient_QueryInterface,
1894 AudioRenderClient_AddRef,
1895 AudioRenderClient_Release,
1896 AudioRenderClient_GetBuffer,
1897 AudioRenderClient_ReleaseBuffer
1900 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1901 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1903 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1909 if(IsEqualIID(riid, &IID_IUnknown) ||
1910 IsEqualIID(riid, &IID_IAudioCaptureClient))
1913 IUnknown_AddRef((IUnknown*)*ppv);
1917 WARN("Unknown interface %s\n", debugstr_guid(riid));
1918 return E_NOINTERFACE;
1921 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1923 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1924 return IAudioClient_AddRef(&This->IAudioClient_iface);
1927 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1929 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1930 return IAudioClient_Release(&This->IAudioClient_iface);
1933 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1934 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1937 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1939 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1942 if(!data || !frames || !flags)
1945 OSSpinLockLock(&This->lock);
1947 if(This->getbuf_last){
1948 OSSpinLockUnlock(&This->lock);
1949 return AUDCLNT_E_OUT_OF_ORDER;
1952 if(This->public_buffer){
1954 This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
1956 struct list *head = list_head(&This->avail_buffers);
1960 AQBuffer *buf = LIST_ENTRY(head, AQBuffer, entry);
1961 This->public_buffer = buf->buf;
1963 This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
1964 list_remove(&buf->entry);
1966 OSStatus sc = AudioQueueEnqueueBuffer(This->aqueue, This->public_buffer, 0, NULL);
1968 ERR("Unable to enqueue buffer: %lx\n", sc);
1969 This->public_buffer = NULL;
1970 WARN("empty packet\n");
1975 if((This->getbuf_last = *frames)){
1978 *data = This->public_buffer->mAudioData;
1981 *devpos = This->written_frames;
1982 if(qpcpos) /* fixme: qpc of recording time */
1983 AudioClock_GetPosition_nolock(This, &pos, qpcpos);
1985 OSSpinLockUnlock(&This->lock);
1987 return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
1990 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1991 IAudioCaptureClient *iface, UINT32 done)
1993 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1996 TRACE("(%p)->(%u)\n", This, done);
1998 OSSpinLockLock(&This->lock);
2001 This->getbuf_last = 0;
2002 OSSpinLockUnlock(&This->lock);
2006 if(!This->getbuf_last){
2007 OSSpinLockUnlock(&This->lock);
2008 return AUDCLNT_E_OUT_OF_ORDER;
2011 if(This->getbuf_last != done){
2012 OSSpinLockUnlock(&This->lock);
2013 return AUDCLNT_E_INVALID_SIZE;
2016 This->written_frames += done;
2017 This->inbuf_frames -= done;
2018 This->getbuf_last = 0;
2020 sc = AudioQueueEnqueueBuffer(This->aqueue, This->public_buffer, 0, NULL);
2022 OSSpinLockUnlock(&This->lock);
2023 /* fixme: can't zero public_buffer or we lose memory, but then
2024 * GetBuffer will see that packet again and again. */
2025 ERR("Unable to enqueue buffer: %lx\n", sc);
2026 return AUDCLNT_E_DEVICE_INVALIDATED;
2028 This->public_buffer = NULL;
2030 OSSpinLockUnlock(&This->lock);
2035 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
2036 IAudioCaptureClient *iface, UINT32 *frames)
2038 ACImpl *This = impl_from_IAudioCaptureClient(iface);
2042 TRACE("(%p)->(%p)\n", This, frames);
2047 OSSpinLockLock(&This->lock);
2049 head = list_head(&This->avail_buffers);
2052 *frames = This->bufsize_frames / CAPTURE_BUFFERS;
2053 OSSpinLockUnlock(&This->lock);
2057 buf = LIST_ENTRY(head, AQBuffer, entry);
2058 *frames = buf->buf->mAudioDataByteSize / This->fmt->nBlockAlign;
2060 OSSpinLockUnlock(&This->lock);
2065 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
2067 AudioCaptureClient_QueryInterface,
2068 AudioCaptureClient_AddRef,
2069 AudioCaptureClient_Release,
2070 AudioCaptureClient_GetBuffer,
2071 AudioCaptureClient_ReleaseBuffer,
2072 AudioCaptureClient_GetNextPacketSize
2075 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
2076 REFIID riid, void **ppv)
2078 ACImpl *This = impl_from_IAudioClock(iface);
2080 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2086 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
2088 else if(IsEqualIID(riid, &IID_IAudioClock2))
2089 *ppv = &This->IAudioClock2_iface;
2091 IUnknown_AddRef((IUnknown*)*ppv);
2095 WARN("Unknown interface %s\n", debugstr_guid(riid));
2096 return E_NOINTERFACE;
2099 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
2101 ACImpl *This = impl_from_IAudioClock(iface);
2102 return IAudioClient_AddRef(&This->IAudioClient_iface);
2105 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
2107 ACImpl *This = impl_from_IAudioClock(iface);
2108 return IAudioClient_Release(&This->IAudioClient_iface);
2111 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
2113 ACImpl *This = impl_from_IAudioClock(iface);
2115 TRACE("(%p)->(%p)\n", This, freq);
2117 *freq = This->fmt->nSamplesPerSec;
2122 static HRESULT AudioClock_GetPosition_nolock(ACImpl *This,
2123 UINT64 *pos, UINT64 *qpctime)
2125 if(This->dataflow == eRender)
2126 *pos = get_current_aqbuffer_position(This, BUFPOS_ABSOLUTE);
2128 *pos = This->inbuf_frames + This->written_frames;
2131 LARGE_INTEGER stamp, freq;
2132 QueryPerformanceCounter(&stamp);
2133 QueryPerformanceFrequency(&freq);
2134 *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
2140 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
2143 ACImpl *This = impl_from_IAudioClock(iface);
2146 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
2151 OSSpinLockLock(&This->lock);
2153 hr = AudioClock_GetPosition_nolock(This, pos, qpctime);
2155 OSSpinLockUnlock(&This->lock);
2160 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
2163 ACImpl *This = impl_from_IAudioClock(iface);
2165 TRACE("(%p)->(%p)\n", This, chars);
2170 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
2175 static const IAudioClockVtbl AudioClock_Vtbl =
2177 AudioClock_QueryInterface,
2180 AudioClock_GetFrequency,
2181 AudioClock_GetPosition,
2182 AudioClock_GetCharacteristics
2185 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
2186 REFIID riid, void **ppv)
2188 ACImpl *This = impl_from_IAudioClock2(iface);
2189 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
2192 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
2194 ACImpl *This = impl_from_IAudioClock2(iface);
2195 return IAudioClient_AddRef(&This->IAudioClient_iface);
2198 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
2200 ACImpl *This = impl_from_IAudioClock2(iface);
2201 return IAudioClient_Release(&This->IAudioClient_iface);
2204 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
2205 UINT64 *pos, UINT64 *qpctime)
2207 ACImpl *This = impl_from_IAudioClock2(iface);
2209 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
2214 static const IAudioClock2Vtbl AudioClock2_Vtbl =
2216 AudioClock2_QueryInterface,
2218 AudioClock2_Release,
2219 AudioClock2_GetDevicePosition
2222 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
2224 AudioSessionWrapper *ret;
2226 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2227 sizeof(AudioSessionWrapper));
2231 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
2232 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
2233 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
2237 ret->client = client;
2239 ret->session = client->session;
2240 AudioClient_AddRef(&client->IAudioClient_iface);
2246 static HRESULT WINAPI AudioSessionControl_QueryInterface(
2247 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
2249 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2255 if(IsEqualIID(riid, &IID_IUnknown) ||
2256 IsEqualIID(riid, &IID_IAudioSessionControl) ||
2257 IsEqualIID(riid, &IID_IAudioSessionControl2))
2260 IUnknown_AddRef((IUnknown*)*ppv);
2264 WARN("Unknown interface %s\n", debugstr_guid(riid));
2265 return E_NOINTERFACE;
2268 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
2270 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2272 ref = InterlockedIncrement(&This->ref);
2273 TRACE("(%p) Refcount now %u\n", This, ref);
2277 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
2279 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2281 ref = InterlockedDecrement(&This->ref);
2282 TRACE("(%p) Refcount now %u\n", This, ref);
2285 OSSpinLockLock(&This->client->lock);
2286 This->client->session_wrapper = NULL;
2287 OSSpinLockUnlock(&This->client->lock);
2288 AudioClient_Release(&This->client->IAudioClient_iface);
2290 HeapFree(GetProcessHeap(), 0, This);
2295 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
2296 AudioSessionState *state)
2298 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2301 TRACE("(%p)->(%p)\n", This, state);
2304 return NULL_PTR_ERR;
2306 EnterCriticalSection(&g_sessions_lock);
2308 if(list_empty(&This->session->clients)){
2309 *state = AudioSessionStateExpired;
2310 LeaveCriticalSection(&g_sessions_lock);
2314 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
2315 OSSpinLockLock(&client->lock);
2316 if(client->playing == StatePlaying ||
2317 client->playing == StateInTransition){
2318 *state = AudioSessionStateActive;
2319 OSSpinLockUnlock(&client->lock);
2320 LeaveCriticalSection(&g_sessions_lock);
2323 OSSpinLockUnlock(&client->lock);
2326 LeaveCriticalSection(&g_sessions_lock);
2328 *state = AudioSessionStateInactive;
2333 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
2334 IAudioSessionControl2 *iface, WCHAR **name)
2336 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2338 FIXME("(%p)->(%p) - stub\n", This, name);
2343 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
2344 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
2346 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2348 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
2353 static HRESULT WINAPI AudioSessionControl_GetIconPath(
2354 IAudioSessionControl2 *iface, WCHAR **path)
2356 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2358 FIXME("(%p)->(%p) - stub\n", This, path);
2363 static HRESULT WINAPI AudioSessionControl_SetIconPath(
2364 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
2366 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2368 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
2373 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
2374 IAudioSessionControl2 *iface, GUID *group)
2376 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2378 FIXME("(%p)->(%p) - stub\n", This, group);
2383 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
2384 IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
2386 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2388 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
2389 debugstr_guid(session));
2394 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
2395 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2397 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2399 FIXME("(%p)->(%p) - stub\n", This, events);
2404 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
2405 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2407 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2409 FIXME("(%p)->(%p) - stub\n", This, events);
2414 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
2415 IAudioSessionControl2 *iface, WCHAR **id)
2417 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2419 FIXME("(%p)->(%p) - stub\n", This, id);
2424 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
2425 IAudioSessionControl2 *iface, WCHAR **id)
2427 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2429 FIXME("(%p)->(%p) - stub\n", This, id);
2434 static HRESULT WINAPI AudioSessionControl_GetProcessId(
2435 IAudioSessionControl2 *iface, DWORD *pid)
2437 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2439 TRACE("(%p)->(%p)\n", This, pid);
2444 *pid = GetCurrentProcessId();
2449 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
2450 IAudioSessionControl2 *iface)
2452 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2454 TRACE("(%p)\n", This);
2459 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
2460 IAudioSessionControl2 *iface, BOOL optout)
2462 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2464 TRACE("(%p)->(%d)\n", This, optout);
2469 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
2471 AudioSessionControl_QueryInterface,
2472 AudioSessionControl_AddRef,
2473 AudioSessionControl_Release,
2474 AudioSessionControl_GetState,
2475 AudioSessionControl_GetDisplayName,
2476 AudioSessionControl_SetDisplayName,
2477 AudioSessionControl_GetIconPath,
2478 AudioSessionControl_SetIconPath,
2479 AudioSessionControl_GetGroupingParam,
2480 AudioSessionControl_SetGroupingParam,
2481 AudioSessionControl_RegisterAudioSessionNotification,
2482 AudioSessionControl_UnregisterAudioSessionNotification,
2483 AudioSessionControl_GetSessionIdentifier,
2484 AudioSessionControl_GetSessionInstanceIdentifier,
2485 AudioSessionControl_GetProcessId,
2486 AudioSessionControl_IsSystemSoundsSession,
2487 AudioSessionControl_SetDuckingPreference
2490 /* index == -1 means set all channels, otherwise sets only the given channel */
2491 static HRESULT ca_setvol(ACImpl *This, UINT32 index)
2496 if(index == (UINT32)-1){
2499 for(i = 0; i < This->fmt->nChannels; ++i){
2501 hr = ca_setvol(This, i);
2508 if(This->session->mute)
2511 level = This->session->master_vol *
2512 This->session->channel_vols[index] * This->vols[index];
2514 sc = AudioQueueSetParameter(This->aqueue, kAudioQueueParam_Volume, level);
2516 WARN("Setting _Volume property failed: %lx\n", sc);
2521 static HRESULT ca_session_setvol(AudioSession *session, UINT32 index)
2526 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry){
2528 hr = ca_setvol(client, index);
2536 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
2537 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
2539 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2545 if(IsEqualIID(riid, &IID_IUnknown) ||
2546 IsEqualIID(riid, &IID_ISimpleAudioVolume))
2549 IUnknown_AddRef((IUnknown*)*ppv);
2553 WARN("Unknown interface %s\n", debugstr_guid(riid));
2554 return E_NOINTERFACE;
2557 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
2559 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2560 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2563 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
2565 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2566 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2569 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
2570 ISimpleAudioVolume *iface, float level, const GUID *context)
2572 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2573 AudioSession *session = This->session;
2576 TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
2578 if(level < 0.f || level > 1.f)
2579 return E_INVALIDARG;
2582 FIXME("Notifications not supported yet\n");
2584 EnterCriticalSection(&session->lock);
2586 session->master_vol = level;
2588 ret = ca_session_setvol(session, -1);
2590 LeaveCriticalSection(&session->lock);
2595 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
2596 ISimpleAudioVolume *iface, float *level)
2598 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2599 AudioSession *session = This->session;
2601 TRACE("(%p)->(%p)\n", session, level);
2604 return NULL_PTR_ERR;
2606 *level = session->master_vol;
2611 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
2612 BOOL mute, const GUID *context)
2614 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2615 AudioSession *session = This->session;
2617 TRACE("(%p)->(%u, %p)\n", session, mute, context);
2620 FIXME("Notifications not supported yet\n");
2622 EnterCriticalSection(&session->lock);
2624 session->mute = mute;
2626 ca_session_setvol(session, -1);
2628 LeaveCriticalSection(&session->lock);
2633 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
2636 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2637 AudioSession *session = This->session;
2639 TRACE("(%p)->(%p)\n", session, mute);
2642 return NULL_PTR_ERR;
2644 *mute = session->mute;
2649 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
2651 SimpleAudioVolume_QueryInterface,
2652 SimpleAudioVolume_AddRef,
2653 SimpleAudioVolume_Release,
2654 SimpleAudioVolume_SetMasterVolume,
2655 SimpleAudioVolume_GetMasterVolume,
2656 SimpleAudioVolume_SetMute,
2657 SimpleAudioVolume_GetMute
2660 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
2661 IAudioStreamVolume *iface, REFIID riid, void **ppv)
2663 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2669 if(IsEqualIID(riid, &IID_IUnknown) ||
2670 IsEqualIID(riid, &IID_IAudioStreamVolume))
2673 IUnknown_AddRef((IUnknown*)*ppv);
2677 WARN("Unknown interface %s\n", debugstr_guid(riid));
2678 return E_NOINTERFACE;
2681 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
2683 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2684 return IAudioClient_AddRef(&This->IAudioClient_iface);
2687 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
2689 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2690 return IAudioClient_Release(&This->IAudioClient_iface);
2693 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
2694 IAudioStreamVolume *iface, UINT32 *out)
2696 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2698 TRACE("(%p)->(%p)\n", This, out);
2703 *out = This->fmt->nChannels;
2708 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
2709 IAudioStreamVolume *iface, UINT32 index, float level)
2711 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2714 TRACE("(%p)->(%d, %f)\n", This, index, level);
2716 if(level < 0.f || level > 1.f)
2717 return E_INVALIDARG;
2719 if(index >= This->fmt->nChannels)
2720 return E_INVALIDARG;
2722 OSSpinLockLock(&This->lock);
2724 This->vols[index] = level;
2726 WARN("AudioQueue doesn't support per-channel volume control\n");
2727 ret = ca_setvol(This, index);
2729 OSSpinLockUnlock(&This->lock);
2734 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2735 IAudioStreamVolume *iface, UINT32 index, float *level)
2737 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2739 TRACE("(%p)->(%d, %p)\n", This, index, level);
2744 if(index >= This->fmt->nChannels)
2745 return E_INVALIDARG;
2747 *level = This->vols[index];
2752 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2753 IAudioStreamVolume *iface, UINT32 count, const float *levels)
2755 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2759 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2764 if(count != This->fmt->nChannels)
2765 return E_INVALIDARG;
2767 OSSpinLockLock(&This->lock);
2769 for(i = 0; i < count; ++i)
2770 This->vols[i] = levels[i];
2772 ret = ca_setvol(This, -1);
2774 OSSpinLockUnlock(&This->lock);
2779 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2780 IAudioStreamVolume *iface, UINT32 count, float *levels)
2782 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2785 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2790 if(count != This->fmt->nChannels)
2791 return E_INVALIDARG;
2793 OSSpinLockLock(&This->lock);
2795 for(i = 0; i < count; ++i)
2796 levels[i] = This->vols[i];
2798 OSSpinLockUnlock(&This->lock);
2803 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2805 AudioStreamVolume_QueryInterface,
2806 AudioStreamVolume_AddRef,
2807 AudioStreamVolume_Release,
2808 AudioStreamVolume_GetChannelCount,
2809 AudioStreamVolume_SetChannelVolume,
2810 AudioStreamVolume_GetChannelVolume,
2811 AudioStreamVolume_SetAllVolumes,
2812 AudioStreamVolume_GetAllVolumes
2815 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2816 IChannelAudioVolume *iface, REFIID riid, void **ppv)
2818 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2824 if(IsEqualIID(riid, &IID_IUnknown) ||
2825 IsEqualIID(riid, &IID_IChannelAudioVolume))
2828 IUnknown_AddRef((IUnknown*)*ppv);
2832 WARN("Unknown interface %s\n", debugstr_guid(riid));
2833 return E_NOINTERFACE;
2836 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2838 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2839 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2842 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2844 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2845 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2848 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2849 IChannelAudioVolume *iface, UINT32 *out)
2851 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2852 AudioSession *session = This->session;
2854 TRACE("(%p)->(%p)\n", session, out);
2857 return NULL_PTR_ERR;
2859 *out = session->channel_count;
2864 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2865 IChannelAudioVolume *iface, UINT32 index, float level,
2866 const GUID *context)
2868 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2869 AudioSession *session = This->session;
2872 TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2873 wine_dbgstr_guid(context));
2875 if(level < 0.f || level > 1.f)
2876 return E_INVALIDARG;
2878 if(index >= session->channel_count)
2879 return E_INVALIDARG;
2882 FIXME("Notifications not supported yet\n");
2884 EnterCriticalSection(&session->lock);
2886 session->channel_vols[index] = level;
2888 WARN("AudioQueue doesn't support per-channel volume control\n");
2889 ret = ca_session_setvol(session, index);
2891 LeaveCriticalSection(&session->lock);
2896 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2897 IChannelAudioVolume *iface, UINT32 index, float *level)
2899 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2900 AudioSession *session = This->session;
2902 TRACE("(%p)->(%d, %p)\n", session, index, level);
2905 return NULL_PTR_ERR;
2907 if(index >= session->channel_count)
2908 return E_INVALIDARG;
2910 *level = session->channel_vols[index];
2915 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2916 IChannelAudioVolume *iface, UINT32 count, const float *levels,
2917 const GUID *context)
2919 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2920 AudioSession *session = This->session;
2924 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2925 wine_dbgstr_guid(context));
2928 return NULL_PTR_ERR;
2930 if(count != session->channel_count)
2931 return E_INVALIDARG;
2934 FIXME("Notifications not supported yet\n");
2936 EnterCriticalSection(&session->lock);
2938 for(i = 0; i < count; ++i)
2939 session->channel_vols[i] = levels[i];
2941 ret = ca_session_setvol(session, -1);
2943 LeaveCriticalSection(&session->lock);
2948 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2949 IChannelAudioVolume *iface, UINT32 count, float *levels)
2951 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2952 AudioSession *session = This->session;
2955 TRACE("(%p)->(%d, %p)\n", session, count, levels);
2958 return NULL_PTR_ERR;
2960 if(count != session->channel_count)
2961 return E_INVALIDARG;
2963 for(i = 0; i < count; ++i)
2964 levels[i] = session->channel_vols[i];
2969 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2971 ChannelAudioVolume_QueryInterface,
2972 ChannelAudioVolume_AddRef,
2973 ChannelAudioVolume_Release,
2974 ChannelAudioVolume_GetChannelCount,
2975 ChannelAudioVolume_SetChannelVolume,
2976 ChannelAudioVolume_GetChannelVolume,
2977 ChannelAudioVolume_SetAllVolumes,
2978 ChannelAudioVolume_GetAllVolumes
2981 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2982 REFIID riid, void **ppv)
2984 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2990 if(IsEqualIID(riid, &IID_IUnknown) ||
2991 IsEqualIID(riid, &IID_IAudioSessionManager) ||
2992 IsEqualIID(riid, &IID_IAudioSessionManager2))
2995 IUnknown_AddRef((IUnknown*)*ppv);
2999 WARN("Unknown interface %s\n", debugstr_guid(riid));
3000 return E_NOINTERFACE;
3003 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
3005 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3007 ref = InterlockedIncrement(&This->ref);
3008 TRACE("(%p) Refcount now %u\n", This, ref);
3012 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
3014 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3016 ref = InterlockedDecrement(&This->ref);
3017 TRACE("(%p) Refcount now %u\n", This, ref);
3019 HeapFree(GetProcessHeap(), 0, This);
3023 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
3024 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
3025 IAudioSessionControl **out)
3027 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3028 AudioSession *session;
3029 AudioSessionWrapper *wrapper;
3032 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
3035 hr = get_audio_session(session_guid, This->device, 0, &session);
3039 wrapper = AudioSessionWrapper_Create(NULL);
3041 return E_OUTOFMEMORY;
3043 wrapper->session = session;
3045 *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
3050 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
3051 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
3052 ISimpleAudioVolume **out)
3054 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3055 AudioSession *session;
3056 AudioSessionWrapper *wrapper;
3059 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
3062 hr = get_audio_session(session_guid, This->device, 0, &session);
3066 wrapper = AudioSessionWrapper_Create(NULL);
3068 return E_OUTOFMEMORY;
3070 wrapper->session = session;
3072 *out = &wrapper->ISimpleAudioVolume_iface;
3077 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
3078 IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
3080 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3081 FIXME("(%p)->(%p) - stub\n", This, out);
3085 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
3086 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
3088 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3089 FIXME("(%p)->(%p) - stub\n", This, notification);
3093 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
3094 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
3096 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3097 FIXME("(%p)->(%p) - stub\n", This, notification);
3101 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
3102 IAudioSessionManager2 *iface, const WCHAR *session_id,
3103 IAudioVolumeDuckNotification *notification)
3105 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3106 FIXME("(%p)->(%p) - stub\n", This, notification);
3110 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
3111 IAudioSessionManager2 *iface,
3112 IAudioVolumeDuckNotification *notification)
3114 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3115 FIXME("(%p)->(%p) - stub\n", This, notification);
3119 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
3121 AudioSessionManager_QueryInterface,
3122 AudioSessionManager_AddRef,
3123 AudioSessionManager_Release,
3124 AudioSessionManager_GetAudioSessionControl,
3125 AudioSessionManager_GetSimpleAudioVolume,
3126 AudioSessionManager_GetSessionEnumerator,
3127 AudioSessionManager_RegisterSessionNotification,
3128 AudioSessionManager_UnregisterSessionNotification,
3129 AudioSessionManager_RegisterDuckNotification,
3130 AudioSessionManager_UnregisterDuckNotification
3133 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
3134 IAudioSessionManager2 **out)
3138 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
3140 return E_OUTOFMEMORY;
3142 This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
3143 This->device = device;
3146 *out = &This->IAudioSessionManager2_iface;