winecoreaudio.drv: Don't fail if setting volume fails.
[wine.git] / dlls / winecoreaudio.drv / mmdevdrv.c
blob44219672b81c4fe6e51fdd351829cf5872868055
1 /*
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
20 #define COBJMACROS
21 #include "config.h"
23 #include <stdarg.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winnls.h"
28 #include "winreg.h"
29 #include "wine/debug.h"
30 #include "wine/unicode.h"
31 #include "wine/list.h"
33 #include "ole2.h"
34 #include "mmdeviceapi.h"
35 #include "devpkey.h"
36 #include "dshow.h"
37 #include "dsound.h"
39 #include "initguid.h"
40 #include "endpointvolume.h"
41 #include "audioclient.h"
42 #include "audiopolicy.h"
44 #include <errno.h>
45 #include <limits.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <sys/types.h>
50 #include <sys/stat.h>
51 #include <sys/ioctl.h>
52 #include <fcntl.h>
53 #include <unistd.h>
55 #include <libkern/OSAtomic.h>
56 #include <CoreAudio/CoreAudio.h>
57 #include <AudioToolbox/AudioQueue.h>
59 WINE_DEFAULT_DEBUG_CHANNEL(coreaudio);
61 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
63 #define CAPTURE_BUFFERS 5
65 static const REFERENCE_TIME DefaultPeriod = 200000;
66 static const REFERENCE_TIME MinimumPeriod = 100000;
68 typedef struct _AQBuffer {
69 AudioQueueBufferRef buf;
70 struct list entry;
71 } AQBuffer;
73 struct ACImpl;
74 typedef struct ACImpl ACImpl;
76 typedef struct _AudioSession {
77 GUID guid;
78 struct list clients;
80 IMMDevice *device;
82 float master_vol;
83 UINT32 channel_count;
84 float *channel_vols;
85 BOOL mute;
87 CRITICAL_SECTION lock;
89 struct list entry;
90 } AudioSession;
92 typedef struct _AudioSessionWrapper {
93 IAudioSessionControl2 IAudioSessionControl2_iface;
94 IChannelAudioVolume IChannelAudioVolume_iface;
95 ISimpleAudioVolume ISimpleAudioVolume_iface;
97 LONG ref;
99 ACImpl *client;
100 AudioSession *session;
101 } AudioSessionWrapper;
103 struct ACImpl {
104 IAudioClient IAudioClient_iface;
105 IAudioRenderClient IAudioRenderClient_iface;
106 IAudioCaptureClient IAudioCaptureClient_iface;
107 IAudioClock IAudioClock_iface;
108 IAudioClock2 IAudioClock2_iface;
109 IAudioStreamVolume IAudioStreamVolume_iface;
111 LONG ref;
113 IMMDevice *parent;
115 WAVEFORMATEX *fmt;
117 EDataFlow dataflow;
118 DWORD flags;
119 AUDCLNT_SHAREMODE share;
120 HANDLE event;
121 float *vols;
123 AudioDeviceID adevid;
124 AudioQueueRef aqueue;
125 AudioObjectPropertyScope scope;
126 HANDLE timer;
127 UINT32 period_ms, bufsize_frames, inbuf_frames;
128 UINT64 last_time, written_frames;
129 AudioQueueBufferRef public_buffer;
130 UINT32 getbuf_last;
131 int playing;
133 AudioSession *session;
134 AudioSessionWrapper *session_wrapper;
136 struct list entry;
138 struct list avail_buffers;
140 /* We can't use debug printing or {Enter,Leave}CriticalSection from
141 * OSX callback threads, so we use OSX's OSSpinLock for synchronization
142 * instead. OSSpinLock is not a recursive lock, so don't call
143 * synchronized functions while holding the lock. */
144 OSSpinLock lock;
147 enum PlayingStates {
148 StateStopped = 0,
149 StatePlaying,
150 StateInTransition
153 static const IAudioClientVtbl AudioClient_Vtbl;
154 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
155 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
156 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
157 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
158 static const IAudioClockVtbl AudioClock_Vtbl;
159 static const IAudioClock2Vtbl AudioClock2_Vtbl;
160 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
161 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
162 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl;
164 typedef struct _SessionMgr {
165 IAudioSessionManager2 IAudioSessionManager2_iface;
167 LONG ref;
169 IMMDevice *device;
170 } SessionMgr;
172 static HANDLE g_timer_q;
174 static CRITICAL_SECTION g_sessions_lock;
175 static struct list g_sessions = LIST_INIT(g_sessions);
177 static HRESULT AudioClock_GetPosition_nolock(ACImpl *This, UINT64 *pos,
178 UINT64 *qpctime, BOOL raw);
179 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
180 static HRESULT ca_setvol(ACImpl *This, UINT32 index);
182 static inline ACImpl *impl_from_IAudioClient(IAudioClient *iface)
184 return CONTAINING_RECORD(iface, ACImpl, IAudioClient_iface);
187 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
189 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
192 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
194 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
197 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
199 return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
202 static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
204 return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
207 static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
209 return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
212 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
214 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
217 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
219 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
222 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
224 return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
227 static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface)
229 return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface);
232 BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
234 if(reason == DLL_PROCESS_ATTACH){
235 g_timer_q = CreateTimerQueue();
236 if(!g_timer_q)
237 return FALSE;
239 InitializeCriticalSection(&g_sessions_lock);
242 return TRUE;
245 /* From <dlls/mmdevapi/mmdevapi.h> */
246 enum DriverPriority {
247 Priority_Unavailable = 0,
248 Priority_Low,
249 Priority_Neutral,
250 Priority_Preferred
253 int WINAPI AUDDRV_GetPriority(void)
255 return Priority_Neutral;
258 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids,
259 AudioDeviceID ***keys, UINT *num, UINT *def_index)
261 UInt32 devsize, size;
262 AudioDeviceID *devices;
263 AudioDeviceID default_id;
264 AudioObjectPropertyAddress addr;
265 OSStatus sc;
266 int i, ndevices;
268 TRACE("%d %p %p %p\n", flow, ids, num, def_index);
270 addr.mScope = kAudioObjectPropertyScopeGlobal;
271 addr.mElement = kAudioObjectPropertyElementMaster;
272 if(flow == eRender)
273 addr.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
274 else if(flow == eCapture)
275 addr.mSelector = kAudioHardwarePropertyDefaultInputDevice;
276 else
277 return E_INVALIDARG;
279 size = sizeof(default_id);
280 sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0,
281 NULL, &size, &default_id);
282 if(sc != noErr){
283 WARN("Getting _DefaultInputDevice property failed: %lx\n", sc);
284 default_id = -1;
287 addr.mSelector = kAudioHardwarePropertyDevices;
288 sc = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &addr, 0,
289 NULL, &devsize);
290 if(sc != noErr){
291 WARN("Getting _Devices property size failed: %lx\n", sc);
292 return E_FAIL;
295 devices = HeapAlloc(GetProcessHeap(), 0, devsize);
296 if(!devices)
297 return E_OUTOFMEMORY;
299 sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0, NULL,
300 &devsize, devices);
301 if(sc != noErr){
302 WARN("Getting _Devices property failed: %lx\n", sc);
303 HeapFree(GetProcessHeap(), 0, devices);
304 return E_FAIL;
307 ndevices = devsize / sizeof(AudioDeviceID);
309 *ids = HeapAlloc(GetProcessHeap(), 0, ndevices * sizeof(WCHAR *));
310 if(!*ids){
311 HeapFree(GetProcessHeap(), 0, devices);
312 return E_OUTOFMEMORY;
315 *keys = HeapAlloc(GetProcessHeap(), 0, ndevices * sizeof(AudioDeviceID *));
316 if(!*ids){
317 HeapFree(GetProcessHeap(), 0, *ids);
318 HeapFree(GetProcessHeap(), 0, devices);
319 return E_OUTOFMEMORY;
322 *num = 0;
323 *def_index = (UINT)-1;
324 for(i = 0; i < ndevices; ++i){
325 AudioBufferList *buffers;
326 CFStringRef name;
327 SIZE_T len;
328 char nameA[256];
329 int j;
331 addr.mSelector = kAudioDevicePropertyStreamConfiguration;
332 if(flow == eRender)
333 addr.mScope = kAudioDevicePropertyScopeOutput;
334 else
335 addr.mScope = kAudioDevicePropertyScopeInput;
336 addr.mElement = 0;
337 sc = AudioObjectGetPropertyDataSize(devices[i], &addr, 0, NULL, &size);
338 if(sc != noErr){
339 WARN("Unable to get _StreamConfiguration property size for "
340 "device %lu: %lx\n", devices[i], sc);
341 continue;
344 buffers = HeapAlloc(GetProcessHeap(), 0, size);
345 if(!buffers){
346 HeapFree(GetProcessHeap(), 0, devices);
347 for(j = 0; j < *num; ++j)
348 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
349 HeapFree(GetProcessHeap(), 0, *keys);
350 HeapFree(GetProcessHeap(), 0, *ids);
351 return E_OUTOFMEMORY;
354 sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL,
355 &size, buffers);
356 if(sc != noErr){
357 WARN("Unable to get _StreamConfiguration property for "
358 "device %lu: %lx\n", devices[i], sc);
359 HeapFree(GetProcessHeap(), 0, buffers);
360 continue;
363 /* check that there's at least one channel in this device before
364 * we claim it as usable */
365 for(j = 0; j < buffers->mNumberBuffers; ++j)
366 if(buffers->mBuffers[j].mNumberChannels > 0)
367 break;
368 if(j >= buffers->mNumberBuffers){
369 HeapFree(GetProcessHeap(), 0, buffers);
370 continue;
373 HeapFree(GetProcessHeap(), 0, buffers);
375 size = sizeof(name);
376 addr.mSelector = kAudioObjectPropertyName;
377 sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL,
378 &size, &name);
379 if(sc != noErr){
380 WARN("Unable to get _Name property for device %lu: %lx\n",
381 devices[i], sc);
382 continue;
385 if(!CFStringGetCString(name, nameA, sizeof(nameA),
386 kCFStringEncodingUTF8)){
387 WARN("Error converting string to UTF8\n");
388 CFRelease(name);
389 continue;
392 CFRelease(name);
394 len = MultiByteToWideChar(CP_UNIXCP, 0, nameA, -1, NULL, 0);
395 (*ids)[*num] = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
396 if(!(*ids)[*num]){
397 HeapFree(GetProcessHeap(), 0, devices);
398 for(j = 0; j < *num; ++j){
399 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
400 HeapFree(GetProcessHeap(), 0, (*keys)[j]);
402 HeapFree(GetProcessHeap(), 0, *ids);
403 HeapFree(GetProcessHeap(), 0, *keys);
404 return E_OUTOFMEMORY;
406 MultiByteToWideChar(CP_UNIXCP, 0, nameA, -1, (*ids)[*num], len);
408 (*keys)[*num] = HeapAlloc(GetProcessHeap(), 0, sizeof(AudioDeviceID));
409 if(!(*ids)[*num]){
410 HeapFree(GetProcessHeap(), 0, devices);
411 HeapFree(GetProcessHeap(), 0, (*ids)[*num]);
412 for(j = 0; j < *num; ++j){
413 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
414 HeapFree(GetProcessHeap(), 0, (*keys)[j]);
416 HeapFree(GetProcessHeap(), 0, *ids);
417 HeapFree(GetProcessHeap(), 0, *keys);
418 return E_OUTOFMEMORY;
420 *(*keys)[*num] = devices[i];
422 if(*def_index == (UINT)-1 && devices[i] == default_id)
423 *def_index = *num;
425 (*num)++;
428 if(*def_index == (UINT)-1)
429 *def_index = 0;
431 HeapFree(GetProcessHeap(), 0, devices);
433 return S_OK;
436 HRESULT WINAPI AUDDRV_GetAudioEndpoint(AudioDeviceID *adevid, IMMDevice *dev,
437 EDataFlow dataflow, IAudioClient **out)
439 ACImpl *This;
441 TRACE("%p %d %p\n", dev, dataflow, out);
443 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACImpl));
444 if(!This)
445 return E_OUTOFMEMORY;
447 This->IAudioClient_iface.lpVtbl = &AudioClient_Vtbl;
448 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
449 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
450 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
451 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
452 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
454 This->dataflow = dataflow;
456 if(dataflow == eRender)
457 This->scope = kAudioDevicePropertyScopeOutput;
458 else if(dataflow == eCapture)
459 This->scope = kAudioDevicePropertyScopeInput;
460 else{
461 HeapFree(GetProcessHeap(), 0, This);
462 return E_INVALIDARG;
465 This->lock = 0;
467 This->parent = dev;
468 IMMDevice_AddRef(This->parent);
470 list_init(&This->avail_buffers);
472 This->adevid = *adevid;
474 *out = &This->IAudioClient_iface;
475 IAudioClient_AddRef(&This->IAudioClient_iface);
477 return S_OK;
480 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient *iface,
481 REFIID riid, void **ppv)
483 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
485 if(!ppv)
486 return E_POINTER;
487 *ppv = NULL;
488 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClient))
489 *ppv = iface;
490 if(*ppv){
491 IUnknown_AddRef((IUnknown*)*ppv);
492 return S_OK;
494 WARN("Unknown interface %s\n", debugstr_guid(riid));
495 return E_NOINTERFACE;
498 static ULONG WINAPI AudioClient_AddRef(IAudioClient *iface)
500 ACImpl *This = impl_from_IAudioClient(iface);
501 ULONG ref;
502 ref = InterlockedIncrement(&This->ref);
503 TRACE("(%p) Refcount now %u\n", This, ref);
504 return ref;
507 static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
509 ACImpl *This = impl_from_IAudioClient(iface);
510 ULONG ref;
511 ref = InterlockedDecrement(&This->ref);
512 TRACE("(%p) Refcount now %u\n", This, ref);
513 if(!ref){
514 IAudioClient_Stop(iface);
515 if(This->aqueue)
516 AudioQueueDispose(This->aqueue, 1);
517 if(This->session){
518 EnterCriticalSection(&g_sessions_lock);
519 list_remove(&This->entry);
520 LeaveCriticalSection(&g_sessions_lock);
522 HeapFree(GetProcessHeap(), 0, This->vols);
523 HeapFree(GetProcessHeap(), 0, This->public_buffer);
524 CoTaskMemFree(This->fmt);
525 IMMDevice_Release(This->parent);
526 HeapFree(GetProcessHeap(), 0, This);
528 return ref;
531 static void dump_fmt(const WAVEFORMATEX *fmt)
533 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
534 switch(fmt->wFormatTag){
535 case WAVE_FORMAT_PCM:
536 TRACE("WAVE_FORMAT_PCM");
537 break;
538 case WAVE_FORMAT_IEEE_FLOAT:
539 TRACE("WAVE_FORMAT_IEEE_FLOAT");
540 break;
541 case WAVE_FORMAT_EXTENSIBLE:
542 TRACE("WAVE_FORMAT_EXTENSIBLE");
543 break;
544 default:
545 TRACE("Unknown");
546 break;
548 TRACE(")\n");
550 TRACE("nChannels: %u\n", fmt->nChannels);
551 TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
552 TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
553 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
554 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
555 TRACE("cbSize: %u\n", fmt->cbSize);
557 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
558 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
559 TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
560 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
561 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
565 static DWORD get_channel_mask(unsigned int channels)
567 switch(channels){
568 case 0:
569 return 0;
570 case 1:
571 return KSAUDIO_SPEAKER_MONO;
572 case 2:
573 return KSAUDIO_SPEAKER_STEREO;
574 case 3:
575 return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY;
576 case 4:
577 return KSAUDIO_SPEAKER_QUAD; /* not _SURROUND */
578 case 5:
579 return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY;
580 case 6:
581 return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */
582 case 7:
583 return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER;
584 case 8:
585 return KSAUDIO_SPEAKER_7POINT1; /* not 7POINT1_SURROUND */
587 FIXME("Unknown speaker configuration: %u\n", channels);
588 return 0;
591 static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
593 WAVEFORMATEX *ret;
594 size_t size;
596 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
597 size = sizeof(WAVEFORMATEXTENSIBLE);
598 else
599 size = sizeof(WAVEFORMATEX);
601 ret = CoTaskMemAlloc(size);
602 if(!ret)
603 return NULL;
605 memcpy(ret, fmt, size);
607 ret->cbSize = size - sizeof(WAVEFORMATEX);
609 return ret;
612 static HRESULT ca_get_audiodesc(AudioStreamBasicDescription *desc,
613 const WAVEFORMATEX *fmt)
615 const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)fmt;
617 desc->mFormatFlags = 0;
619 if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
620 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
621 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
622 desc->mFormatID = kAudioFormatLinearPCM;
623 if(fmt->wBitsPerSample > 8)
624 desc->mFormatFlags = kAudioFormatFlagIsSignedInteger;
625 }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
626 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
627 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
628 desc->mFormatID = kAudioFormatLinearPCM;
629 desc->mFormatFlags = kAudioFormatFlagIsFloat;
630 }else if(fmt->wFormatTag == WAVE_FORMAT_MULAW ||
631 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
632 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_MULAW))){
633 desc->mFormatID = kAudioFormatULaw;
634 }else if(fmt->wFormatTag == WAVE_FORMAT_ALAW ||
635 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
636 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_ALAW))){
637 desc->mFormatID = kAudioFormatALaw;
638 }else
639 return AUDCLNT_E_UNSUPPORTED_FORMAT;
641 desc->mSampleRate = fmt->nSamplesPerSec;
642 desc->mBytesPerPacket = fmt->nBlockAlign;
643 desc->mFramesPerPacket = 1;
644 desc->mBytesPerFrame = fmt->nBlockAlign;
645 desc->mChannelsPerFrame = fmt->nChannels;
646 desc->mBitsPerChannel = fmt->wBitsPerSample;
647 desc->mReserved = 0;
649 return S_OK;
652 static void ca_out_buffer_cb(void *user, AudioQueueRef aqueue,
653 AudioQueueBufferRef buffer)
655 ACImpl *This = user;
656 AQBuffer *buf = buffer->mUserData;
658 OSSpinLockLock(&This->lock);
659 list_add_tail(&This->avail_buffers, &buf->entry);
660 This->inbuf_frames -= buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
661 OSSpinLockUnlock(&This->lock);
664 static void ca_in_buffer_cb(void *user, AudioQueueRef aqueue,
665 AudioQueueBufferRef buffer, const AudioTimeStamp *start,
666 UInt32 ndesc, const AudioStreamPacketDescription *descs)
668 ACImpl *This = user;
669 AQBuffer *buf = buffer->mUserData;
671 OSSpinLockLock(&This->lock);
672 list_add_tail(&This->avail_buffers, &buf->entry);
673 This->inbuf_frames += buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
674 OSSpinLockUnlock(&This->lock);
677 static HRESULT ca_setup_aqueue(AudioDeviceID did, EDataFlow flow,
678 const WAVEFORMATEX *fmt, void *user, AudioQueueRef *aqueue)
680 AudioStreamBasicDescription desc;
681 AudioObjectPropertyAddress addr;
682 CFStringRef uid;
683 OSStatus sc;
684 HRESULT hr;
685 UInt32 size;
687 addr.mScope = kAudioObjectPropertyScopeGlobal;
688 addr.mElement = 0;
689 addr.mSelector = kAudioDevicePropertyDeviceUID;
691 size = sizeof(uid);
692 sc = AudioObjectGetPropertyData(did, &addr, 0, NULL, &size, &uid);
693 if(sc != noErr){
694 WARN("Unable to get _DeviceUID property: %lx\n", sc);
695 return E_FAIL;
698 hr = ca_get_audiodesc(&desc, fmt);
699 if(FAILED(hr)){
700 CFRelease(uid);
701 return hr;
704 if(flow == eRender)
705 sc = AudioQueueNewOutput(&desc, ca_out_buffer_cb, user, NULL, NULL, 0,
706 aqueue);
707 else if(flow == eCapture)
708 sc = AudioQueueNewInput(&desc, ca_in_buffer_cb, user, NULL, NULL, 0,
709 aqueue);
710 else{
711 CFRelease(uid);
712 return E_UNEXPECTED;
714 if(sc != noErr){
715 WARN("Unable to create AudioQueue: %lx\n", sc);
716 CFRelease(uid);
717 return E_FAIL;
720 sc = AudioQueueSetProperty(*aqueue, kAudioQueueProperty_CurrentDevice,
721 &uid, sizeof(uid));
722 if(sc != noErr){
723 CFRelease(uid);
724 return E_FAIL;
727 CFRelease(uid);
729 return S_OK;
732 static void session_init_vols(AudioSession *session, UINT channels)
734 if(session->channel_count < channels){
735 UINT i;
737 if(session->channel_vols)
738 session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
739 session->channel_vols, sizeof(float) * channels);
740 else
741 session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
742 sizeof(float) * channels);
743 if(!session->channel_vols)
744 return;
746 for(i = session->channel_count; i < channels; ++i)
747 session->channel_vols[i] = 1.f;
749 session->channel_count = channels;
753 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
754 UINT num_channels)
756 AudioSession *ret;
758 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
759 if(!ret)
760 return NULL;
762 memcpy(&ret->guid, guid, sizeof(GUID));
764 ret->device = device;
766 list_init(&ret->clients);
768 list_add_head(&g_sessions, &ret->entry);
770 InitializeCriticalSection(&ret->lock);
772 session_init_vols(ret, num_channels);
774 ret->master_vol = 1.f;
776 return ret;
779 /* if channels == 0, then this will return or create a session with
780 * matching dataflow and GUID. otherwise, channels must also match */
781 static HRESULT get_audio_session(const GUID *sessionguid,
782 IMMDevice *device, UINT channels, AudioSession **out)
784 AudioSession *session;
786 if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
787 *out = create_session(&GUID_NULL, device, channels);
788 if(!*out)
789 return E_OUTOFMEMORY;
791 return S_OK;
794 *out = NULL;
795 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
796 if(session->device == device &&
797 IsEqualGUID(sessionguid, &session->guid)){
798 session_init_vols(session, channels);
799 *out = session;
800 break;
804 if(!*out){
805 *out = create_session(sessionguid, device, channels);
806 if(!*out)
807 return E_OUTOFMEMORY;
810 return S_OK;
813 static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
814 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
815 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
816 const GUID *sessionguid)
818 ACImpl *This = impl_from_IAudioClient(iface);
819 HRESULT hr;
820 OSStatus sc;
821 int i;
823 TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
824 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
826 if(!fmt)
827 return E_POINTER;
829 dump_fmt(fmt);
831 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
832 return AUDCLNT_E_NOT_INITIALIZED;
834 if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
835 AUDCLNT_STREAMFLAGS_LOOPBACK |
836 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
837 AUDCLNT_STREAMFLAGS_NOPERSIST |
838 AUDCLNT_STREAMFLAGS_RATEADJUST |
839 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
840 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
841 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED)){
842 TRACE("Unknown flags: %08x\n", flags);
843 return E_INVALIDARG;
846 OSSpinLockLock(&This->lock);
848 if(This->aqueue){
849 OSSpinLockUnlock(&This->lock);
850 return AUDCLNT_E_ALREADY_INITIALIZED;
853 hr = ca_setup_aqueue(This->adevid, This->dataflow, fmt, This, &This->aqueue);
854 if(FAILED(hr)){
855 OSSpinLockUnlock(&This->lock);
856 return hr;
859 This->fmt = clone_format(fmt);
860 if(!This->fmt){
861 AudioQueueDispose(This->aqueue, 1);
862 This->aqueue = NULL;
863 OSSpinLockUnlock(&This->lock);
864 return E_OUTOFMEMORY;
867 if(period){
868 This->period_ms = period / 10000;
869 if(This->period_ms == 0)
870 This->period_ms = 1;
871 }else
872 This->period_ms = MinimumPeriod / 10000;
874 if(!duration)
875 duration = 300000; /* 0.03s */
876 This->bufsize_frames = ceil(fmt->nSamplesPerSec * (duration / 10000000.));
878 if(This->dataflow == eCapture){
879 int i;
880 UInt32 bsize = ceil((This->bufsize_frames / (double)CAPTURE_BUFFERS) *
881 This->fmt->nBlockAlign);
882 for(i = 0; i < CAPTURE_BUFFERS; ++i){
883 AQBuffer *buf;
885 buf = HeapAlloc(GetProcessHeap(), 0, sizeof(AQBuffer));
886 if(!buf){
887 AudioQueueDispose(This->aqueue, 1);
888 This->aqueue = NULL;
889 CoTaskMemFree(This->fmt);
890 This->fmt = NULL;
891 OSSpinLockUnlock(&This->lock);
892 return E_OUTOFMEMORY;
895 sc = AudioQueueAllocateBuffer(This->aqueue, bsize, &buf->buf);
896 if(sc != noErr){
897 AudioQueueDispose(This->aqueue, 1);
898 This->aqueue = NULL;
899 CoTaskMemFree(This->fmt);
900 This->fmt = NULL;
901 OSSpinLockUnlock(&This->lock);
902 WARN("Couldn't allocate buffer: %lx\n", sc);
903 return E_FAIL;
906 buf->buf->mUserData = buf;
908 sc = AudioQueueEnqueueBuffer(This->aqueue, buf->buf, 0, NULL);
909 if(sc != noErr){
910 ERR("Couldn't enqueue buffer: %lx\n", sc);
911 break;
916 This->vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float));
917 if(!This->vols){
918 AudioQueueDispose(This->aqueue, 1);
919 This->aqueue = NULL;
920 CoTaskMemFree(This->fmt);
921 This->fmt = NULL;
922 OSSpinLockUnlock(&This->lock);
923 return E_OUTOFMEMORY;
926 for(i = 0; i < fmt->nChannels; ++i)
927 This->vols[i] = 1.f;
929 This->share = mode;
930 This->flags = flags;
932 EnterCriticalSection(&g_sessions_lock);
934 hr = get_audio_session(sessionguid, This->parent, fmt->nChannels,
935 &This->session);
936 if(FAILED(hr)){
937 LeaveCriticalSection(&g_sessions_lock);
938 AudioQueueDispose(This->aqueue, 1);
939 This->aqueue = NULL;
940 CoTaskMemFree(This->fmt);
941 This->fmt = NULL;
942 HeapFree(GetProcessHeap(), 0, This->vols);
943 This->vols = NULL;
944 OSSpinLockUnlock(&This->lock);
945 return E_INVALIDARG;
948 list_add_tail(&This->session->clients, &This->entry);
950 LeaveCriticalSection(&g_sessions_lock);
952 ca_setvol(This, -1);
954 OSSpinLockUnlock(&This->lock);
956 return S_OK;
959 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
960 UINT32 *frames)
962 ACImpl *This = impl_from_IAudioClient(iface);
964 TRACE("(%p)->(%p)\n", This, frames);
966 if(!frames)
967 return E_POINTER;
969 OSSpinLockLock(&This->lock);
971 if(!This->aqueue){
972 OSSpinLockUnlock(&This->lock);
973 return AUDCLNT_E_NOT_INITIALIZED;
976 *frames = This->bufsize_frames;
978 OSSpinLockUnlock(&This->lock);
980 return S_OK;
983 static HRESULT ca_get_max_stream_latency(ACImpl *This, UInt32 *max)
985 AudioObjectPropertyAddress addr;
986 AudioStreamID *ids;
987 UInt32 size;
988 OSStatus sc;
989 int nstreams, i;
991 addr.mScope = This->scope;
992 addr.mElement = 0;
993 addr.mSelector = kAudioDevicePropertyStreams;
995 sc = AudioObjectGetPropertyDataSize(This->adevid, &addr, 0, NULL,
996 &size);
997 if(sc != noErr){
998 WARN("Unable to get size for _Streams property: %lx\n", sc);
999 return E_FAIL;
1002 ids = HeapAlloc(GetProcessHeap(), 0, size);
1003 if(!ids)
1004 return E_OUTOFMEMORY;
1006 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL, &size, ids);
1007 if(sc != noErr){
1008 WARN("Unable to get _Streams property: %lx\n", sc);
1009 HeapFree(GetProcessHeap(), 0, ids);
1010 return E_FAIL;
1013 nstreams = size / sizeof(AudioStreamID);
1014 *max = 0;
1016 addr.mSelector = kAudioStreamPropertyLatency;
1017 for(i = 0; i < nstreams; ++i){
1018 UInt32 latency;
1020 size = sizeof(latency);
1021 sc = AudioObjectGetPropertyData(ids[i], &addr, 0, NULL,
1022 &size, &latency);
1023 if(sc != noErr){
1024 WARN("Unable to get _Latency property: %lx\n", sc);
1025 continue;
1028 if(latency > *max)
1029 *max = latency;
1032 HeapFree(GetProcessHeap(), 0, ids);
1034 return S_OK;
1037 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
1038 REFERENCE_TIME *out)
1040 ACImpl *This = impl_from_IAudioClient(iface);
1041 UInt32 latency, stream_latency, size;
1042 AudioObjectPropertyAddress addr;
1043 OSStatus sc;
1044 HRESULT hr;
1046 TRACE("(%p)->(%p)\n", This, out);
1048 if(!out)
1049 return E_POINTER;
1051 OSSpinLockLock(&This->lock);
1053 if(!This->aqueue){
1054 OSSpinLockUnlock(&This->lock);
1055 return AUDCLNT_E_NOT_INITIALIZED;
1058 addr.mScope = This->scope;
1059 addr.mSelector = kAudioDevicePropertyLatency;
1060 addr.mElement = 0;
1062 size = sizeof(latency);
1063 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL,
1064 &size, &latency);
1065 if(sc != noErr){
1066 WARN("Couldn't get _Latency property: %lx\n", sc);
1067 OSSpinLockUnlock(&This->lock);
1068 return E_FAIL;
1071 hr = ca_get_max_stream_latency(This, &stream_latency);
1072 if(FAILED(hr)){
1073 OSSpinLockUnlock(&This->lock);
1074 return hr;
1077 latency += stream_latency;
1078 *out = (latency / (double)This->fmt->nSamplesPerSec) * 10000000;
1080 OSSpinLockUnlock(&This->lock);
1082 return S_OK;
1085 static HRESULT AudioClient_GetCurrentPadding_nolock(ACImpl *This,
1086 UINT32 *numpad)
1088 if(!This->aqueue)
1089 return AUDCLNT_E_NOT_INITIALIZED;
1091 *numpad = This->inbuf_frames;
1093 return S_OK;
1096 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
1097 UINT32 *numpad)
1099 ACImpl *This = impl_from_IAudioClient(iface);
1100 HRESULT hr;
1102 TRACE("(%p)->(%p)\n", This, numpad);
1104 if(!numpad)
1105 return E_POINTER;
1107 OSSpinLockLock(&This->lock);
1109 hr = AudioClient_GetCurrentPadding_nolock(This, numpad);
1111 OSSpinLockUnlock(&This->lock);
1113 return hr;
1116 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
1117 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
1118 WAVEFORMATEX **outpwfx)
1120 ACImpl *This = impl_from_IAudioClient(iface);
1121 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)pwfx;
1122 AudioQueueRef aqueue;
1123 HRESULT hr;
1125 TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx);
1127 if(!pwfx || (mode == AUDCLNT_SHAREMODE_SHARED && !outpwfx))
1128 return E_POINTER;
1130 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1131 return E_INVALIDARG;
1133 if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1134 pwfx->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1135 return E_INVALIDARG;
1137 dump_fmt(pwfx);
1139 if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1140 fmtex->dwChannelMask != 0 &&
1141 fmtex->dwChannelMask != get_channel_mask(pwfx->nChannels))
1142 return AUDCLNT_E_UNSUPPORTED_FORMAT;
1144 OSSpinLockLock(&This->lock);
1146 hr = ca_setup_aqueue(This->adevid, This->dataflow, pwfx, NULL, &aqueue);
1147 if(SUCCEEDED(hr)){
1148 AudioQueueDispose(aqueue, 1);
1149 OSSpinLockUnlock(&This->lock);
1150 if(outpwfx)
1151 *outpwfx = NULL;
1152 TRACE("returning %08x\n", S_OK);
1153 return S_OK;
1156 OSSpinLockUnlock(&This->lock);
1158 if(outpwfx)
1159 *outpwfx = NULL;
1161 TRACE("returning %08x\n", AUDCLNT_E_UNSUPPORTED_FORMAT);
1162 return AUDCLNT_E_UNSUPPORTED_FORMAT;
1165 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
1166 WAVEFORMATEX **pwfx)
1168 ACImpl *This = impl_from_IAudioClient(iface);
1169 WAVEFORMATEXTENSIBLE *fmt;
1170 OSStatus sc;
1171 UInt32 size;
1172 Float64 rate;
1173 AudioBufferList *buffers;
1174 AudioObjectPropertyAddress addr;
1175 int i;
1177 TRACE("(%p)->(%p)\n", This, pwfx);
1179 if(!pwfx)
1180 return E_POINTER;
1181 *pwfx = NULL;
1183 fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
1184 if(!fmt)
1185 return E_OUTOFMEMORY;
1187 fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1189 addr.mScope = This->scope;
1190 addr.mElement = 0;
1191 addr.mSelector = kAudioDevicePropertyStreamConfiguration;
1193 sc = AudioObjectGetPropertyDataSize(This->adevid, &addr, 0, NULL, &size);
1194 if(sc != noErr){
1195 CoTaskMemFree(fmt);
1196 WARN("Unable to get size for _StreamConfiguration property: %lx\n", sc);
1197 return E_FAIL;
1200 buffers = HeapAlloc(GetProcessHeap(), 0, size);
1201 if(!buffers){
1202 CoTaskMemFree(fmt);
1203 return E_OUTOFMEMORY;
1206 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL,
1207 &size, buffers);
1208 if(sc != noErr){
1209 CoTaskMemFree(fmt);
1210 HeapFree(GetProcessHeap(), 0, buffers);
1211 WARN("Unable to get _StreamConfiguration property: %lx\n", sc);
1212 return E_FAIL;
1215 fmt->Format.nChannels = 0;
1216 for(i = 0; i < buffers->mNumberBuffers; ++i)
1217 fmt->Format.nChannels += buffers->mBuffers[i].mNumberChannels;
1219 HeapFree(GetProcessHeap(), 0, buffers);
1221 fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
1223 addr.mSelector = kAudioDevicePropertyNominalSampleRate;
1224 size = sizeof(Float64);
1225 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL, &size, &rate);
1226 if(sc != noErr){
1227 CoTaskMemFree(fmt);
1228 WARN("Unable to get _NominalSampleRate property: %lx\n", sc);
1229 return E_FAIL;
1231 fmt->Format.nSamplesPerSec = rate;
1233 fmt->Format.wBitsPerSample = 32;
1234 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
1236 fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
1237 fmt->Format.nChannels) / 8;
1238 fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
1239 fmt->Format.nBlockAlign;
1241 fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
1242 fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1244 *pwfx = (WAVEFORMATEX*)fmt;
1245 dump_fmt(*pwfx);
1247 return S_OK;
1250 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
1251 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1253 ACImpl *This = impl_from_IAudioClient(iface);
1255 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
1257 if(!defperiod && !minperiod)
1258 return E_POINTER;
1260 OSSpinLockLock(&This->lock);
1262 if(This->period_ms){
1263 if(defperiod)
1264 *defperiod = This->period_ms * 10000;
1265 if(minperiod)
1266 *minperiod = This->period_ms * 10000;
1267 }else{
1268 if(defperiod)
1269 *defperiod = DefaultPeriod;
1270 if(minperiod)
1271 *minperiod = MinimumPeriod;
1274 OSSpinLockUnlock(&This->lock);
1276 return S_OK;
1279 void CALLBACK ca_period_cb(void *user, BOOLEAN timer)
1281 ACImpl *This = user;
1283 OSSpinLockLock(&This->lock);
1284 if(This->event)
1285 SetEvent(This->event);
1286 OSSpinLockUnlock(&This->lock);
1289 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
1291 ACImpl *This = impl_from_IAudioClient(iface);
1292 OSStatus sc;
1294 TRACE("(%p)\n", This);
1296 OSSpinLockLock(&This->lock);
1298 if(!This->aqueue){
1299 OSSpinLockUnlock(&This->lock);
1300 return AUDCLNT_E_NOT_INITIALIZED;
1303 if(This->playing != StateStopped){
1304 OSSpinLockUnlock(&This->lock);
1305 return AUDCLNT_E_NOT_STOPPED;
1308 if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
1309 OSSpinLockUnlock(&This->lock);
1310 return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1313 if(This->event)
1314 if(!CreateTimerQueueTimer(&This->timer, g_timer_q,
1315 ca_period_cb, This, 0, This->period_ms, 0))
1316 ERR("Unable to create timer: %u\n", GetLastError());
1318 This->playing = StateInTransition;
1320 OSSpinLockUnlock(&This->lock);
1322 sc = AudioQueueStart(This->aqueue, NULL);
1323 if(sc != noErr){
1324 WARN("Unable to start audio queue: %lx\n", sc);
1325 return E_FAIL;
1328 OSSpinLockLock(&This->lock);
1330 This->playing = StatePlaying;
1332 OSSpinLockUnlock(&This->lock);
1334 return S_OK;
1337 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
1339 ACImpl *This = impl_from_IAudioClient(iface);
1340 OSStatus sc;
1342 TRACE("(%p)\n", This);
1344 OSSpinLockLock(&This->lock);
1346 if(!This->aqueue){
1347 OSSpinLockUnlock(&This->lock);
1348 return AUDCLNT_E_NOT_INITIALIZED;
1351 if(This->playing == StateStopped){
1352 OSSpinLockUnlock(&This->lock);
1353 return S_FALSE;
1356 if(This->playing == StateInTransition){
1357 OSSpinLockUnlock(&This->lock);
1358 return S_OK;
1361 if(This->timer && This->timer != INVALID_HANDLE_VALUE){
1362 DeleteTimerQueueTimer(g_timer_q, This->timer, INVALID_HANDLE_VALUE);
1363 This->timer = NULL;
1366 This->playing = StateInTransition;
1368 OSSpinLockUnlock(&This->lock);
1370 sc = AudioQueueFlush(This->aqueue);
1371 if(sc != noErr)
1372 WARN("Unable to flush audio queue: %lx\n", sc);
1374 sc = AudioQueuePause(This->aqueue);
1375 if(sc != noErr){
1376 WARN("Unable to pause audio queue: %lx\n", sc);
1377 return E_FAIL;
1380 OSSpinLockLock(&This->lock);
1382 This->playing = StateStopped;
1384 OSSpinLockUnlock(&This->lock);
1386 return S_OK;
1389 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
1391 ACImpl *This = impl_from_IAudioClient(iface);
1392 HRESULT hr;
1393 OSStatus sc;
1395 TRACE("(%p)\n", This);
1397 OSSpinLockLock(&This->lock);
1399 if(!This->aqueue){
1400 OSSpinLockUnlock(&This->lock);
1401 return AUDCLNT_E_NOT_INITIALIZED;
1404 if(This->playing != StateStopped){
1405 OSSpinLockUnlock(&This->lock);
1406 return AUDCLNT_E_NOT_STOPPED;
1409 if(This->getbuf_last){
1410 OSSpinLockUnlock(&This->lock);
1411 return AUDCLNT_E_BUFFER_OPERATION_PENDING;
1414 This->written_frames = 0;
1416 hr = AudioClock_GetPosition_nolock(This, &This->last_time, NULL, TRUE);
1417 if(FAILED(hr)){
1418 OSSpinLockUnlock(&This->lock);
1419 return hr;
1422 OSSpinLockUnlock(&This->lock);
1424 sc = AudioQueueReset(This->aqueue);
1425 if(sc != noErr){
1426 WARN("Unable to reset audio queue: %lx\n", sc);
1427 return E_FAIL;
1430 return S_OK;
1433 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1434 HANDLE event)
1436 ACImpl *This = impl_from_IAudioClient(iface);
1438 TRACE("(%p)->(%p)\n", This, event);
1440 if(!event)
1441 return E_INVALIDARG;
1443 OSSpinLockLock(&This->lock);
1445 if(!This->aqueue){
1446 OSSpinLockUnlock(&This->lock);
1447 return AUDCLNT_E_NOT_INITIALIZED;
1450 if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
1451 OSSpinLockUnlock(&This->lock);
1452 return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1455 This->event = event;
1457 OSSpinLockUnlock(&This->lock);
1459 return S_OK;
1462 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1463 void **ppv)
1465 ACImpl *This = impl_from_IAudioClient(iface);
1467 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1469 if(!ppv)
1470 return E_POINTER;
1471 *ppv = NULL;
1473 OSSpinLockLock(&This->lock);
1475 if(!This->aqueue){
1476 OSSpinLockUnlock(&This->lock);
1477 return AUDCLNT_E_NOT_INITIALIZED;
1480 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1481 if(This->dataflow != eRender){
1482 OSSpinLockUnlock(&This->lock);
1483 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1485 IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
1486 *ppv = &This->IAudioRenderClient_iface;
1487 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1488 if(This->dataflow != eCapture){
1489 OSSpinLockUnlock(&This->lock);
1490 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1492 IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
1493 *ppv = &This->IAudioCaptureClient_iface;
1494 }else if(IsEqualIID(riid, &IID_IAudioClock)){
1495 IAudioClock_AddRef(&This->IAudioClock_iface);
1496 *ppv = &This->IAudioClock_iface;
1497 }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1498 IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
1499 *ppv = &This->IAudioStreamVolume_iface;
1500 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1501 if(!This->session_wrapper){
1502 This->session_wrapper = AudioSessionWrapper_Create(This);
1503 if(!This->session_wrapper){
1504 OSSpinLockUnlock(&This->lock);
1505 return E_OUTOFMEMORY;
1507 }else
1508 IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
1510 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1511 }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1512 if(!This->session_wrapper){
1513 This->session_wrapper = AudioSessionWrapper_Create(This);
1514 if(!This->session_wrapper){
1515 OSSpinLockUnlock(&This->lock);
1516 return E_OUTOFMEMORY;
1518 }else
1519 IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
1521 *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1522 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1523 if(!This->session_wrapper){
1524 This->session_wrapper = AudioSessionWrapper_Create(This);
1525 if(!This->session_wrapper){
1526 OSSpinLockUnlock(&This->lock);
1527 return E_OUTOFMEMORY;
1529 }else
1530 ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
1532 *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1535 if(*ppv){
1536 OSSpinLockUnlock(&This->lock);
1537 return S_OK;
1540 OSSpinLockUnlock(&This->lock);
1542 FIXME("stub %s\n", debugstr_guid(riid));
1543 return E_NOINTERFACE;
1546 static const IAudioClientVtbl AudioClient_Vtbl =
1548 AudioClient_QueryInterface,
1549 AudioClient_AddRef,
1550 AudioClient_Release,
1551 AudioClient_Initialize,
1552 AudioClient_GetBufferSize,
1553 AudioClient_GetStreamLatency,
1554 AudioClient_GetCurrentPadding,
1555 AudioClient_IsFormatSupported,
1556 AudioClient_GetMixFormat,
1557 AudioClient_GetDevicePeriod,
1558 AudioClient_Start,
1559 AudioClient_Stop,
1560 AudioClient_Reset,
1561 AudioClient_SetEventHandle,
1562 AudioClient_GetService
1565 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1566 IAudioRenderClient *iface, REFIID riid, void **ppv)
1568 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1570 if(!ppv)
1571 return E_POINTER;
1572 *ppv = NULL;
1574 if(IsEqualIID(riid, &IID_IUnknown) ||
1575 IsEqualIID(riid, &IID_IAudioRenderClient))
1576 *ppv = iface;
1577 if(*ppv){
1578 IUnknown_AddRef((IUnknown*)*ppv);
1579 return S_OK;
1582 WARN("Unknown interface %s\n", debugstr_guid(riid));
1583 return E_NOINTERFACE;
1586 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1588 ACImpl *This = impl_from_IAudioRenderClient(iface);
1589 return AudioClient_AddRef(&This->IAudioClient_iface);
1592 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1594 ACImpl *This = impl_from_IAudioRenderClient(iface);
1595 return AudioClient_Release(&This->IAudioClient_iface);
1598 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1599 UINT32 frames, BYTE **data)
1601 ACImpl *This = impl_from_IAudioRenderClient(iface);
1602 AQBuffer *buf;
1603 UINT32 pad, bytes = frames * This->fmt->nBlockAlign;
1604 HRESULT hr;
1605 OSStatus sc;
1607 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1609 if(!data)
1610 return E_POINTER;
1611 *data = NULL;
1613 OSSpinLockLock(&This->lock);
1615 if(This->getbuf_last){
1616 OSSpinLockUnlock(&This->lock);
1617 return AUDCLNT_E_OUT_OF_ORDER;
1620 if(!frames){
1621 OSSpinLockUnlock(&This->lock);
1622 return S_OK;
1625 hr = AudioClient_GetCurrentPadding_nolock(This, &pad);
1626 if(FAILED(hr)){
1627 OSSpinLockUnlock(&This->lock);
1628 return hr;
1631 if(pad + frames > This->bufsize_frames){
1632 OSSpinLockUnlock(&This->lock);
1633 return AUDCLNT_E_BUFFER_TOO_LARGE;
1636 LIST_FOR_EACH_ENTRY(buf, &This->avail_buffers, AQBuffer, entry){
1637 if(buf->buf->mAudioDataBytesCapacity >= bytes){
1638 This->public_buffer = buf->buf;
1639 list_remove(&buf->entry);
1640 break;
1644 if(&buf->entry == &This->avail_buffers){
1645 sc = AudioQueueAllocateBuffer(This->aqueue, bytes,
1646 &This->public_buffer);
1647 if(sc != noErr){
1648 OSSpinLockUnlock(&This->lock);
1649 WARN("Unable to allocate buffer: %lx\n", sc);
1650 return E_FAIL;
1652 buf = HeapAlloc(GetProcessHeap(), 0, sizeof(AQBuffer));
1653 if(!buf){
1654 AudioQueueFreeBuffer(This->aqueue, This->public_buffer);
1655 This->public_buffer = NULL;
1656 OSSpinLockUnlock(&This->lock);
1657 return E_OUTOFMEMORY;
1659 buf->buf = This->public_buffer;
1660 This->public_buffer->mUserData = buf;
1663 *data = This->public_buffer->mAudioData;
1665 This->getbuf_last = frames;
1667 OSSpinLockUnlock(&This->lock);
1669 return S_OK;
1672 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1673 IAudioRenderClient *iface, UINT32 frames, DWORD flags)
1675 ACImpl *This = impl_from_IAudioRenderClient(iface);
1676 OSStatus sc;
1678 TRACE("(%p)->(%u, %x)\n", This, frames, flags);
1680 OSSpinLockLock(&This->lock);
1682 if(!frames){
1683 This->getbuf_last = 0;
1684 if(This->public_buffer){
1685 AQBuffer *buf = This->public_buffer->mUserData;
1686 list_add_tail(&This->avail_buffers, &buf->entry);
1687 This->public_buffer = NULL;
1689 OSSpinLockUnlock(&This->lock);
1690 return S_OK;
1693 if(!This->getbuf_last){
1694 OSSpinLockUnlock(&This->lock);
1695 return AUDCLNT_E_OUT_OF_ORDER;
1698 if(frames > This->getbuf_last){
1699 OSSpinLockUnlock(&This->lock);
1700 return AUDCLNT_E_INVALID_SIZE;
1703 if(flags & AUDCLNT_BUFFERFLAGS_SILENT){
1704 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)This->fmt;
1705 if((This->fmt->wFormatTag == WAVE_FORMAT_PCM ||
1706 (This->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1707 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) &&
1708 This->fmt->wBitsPerSample == 8)
1709 memset(This->public_buffer->mAudioData, 128,
1710 frames * This->fmt->nBlockAlign);
1711 else
1712 memset(This->public_buffer->mAudioData, 0,
1713 frames * This->fmt->nBlockAlign);
1716 This->public_buffer->mAudioDataByteSize = frames * This->fmt->nBlockAlign;
1718 sc = AudioQueueEnqueueBuffer(This->aqueue, This->public_buffer, 0, NULL);
1719 if(sc != noErr){
1720 OSSpinLockUnlock(&This->lock);
1721 WARN("Unable to enqueue buffer: %lx\n", sc);
1722 return E_FAIL;
1725 if(This->playing == StateStopped)
1726 AudioQueuePrime(This->aqueue, 0, NULL);
1728 This->public_buffer = NULL;
1729 This->getbuf_last = 0;
1730 This->written_frames += frames;
1731 This->inbuf_frames += frames;
1733 OSSpinLockUnlock(&This->lock);
1735 return S_OK;
1738 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1739 AudioRenderClient_QueryInterface,
1740 AudioRenderClient_AddRef,
1741 AudioRenderClient_Release,
1742 AudioRenderClient_GetBuffer,
1743 AudioRenderClient_ReleaseBuffer
1746 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1747 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1749 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1751 if(!ppv)
1752 return E_POINTER;
1753 *ppv = NULL;
1755 if(IsEqualIID(riid, &IID_IUnknown) ||
1756 IsEqualIID(riid, &IID_IAudioCaptureClient))
1757 *ppv = iface;
1758 if(*ppv){
1759 IUnknown_AddRef((IUnknown*)*ppv);
1760 return S_OK;
1763 WARN("Unknown interface %s\n", debugstr_guid(riid));
1764 return E_NOINTERFACE;
1767 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1769 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1770 return IAudioClient_AddRef(&This->IAudioClient_iface);
1773 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1775 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1776 return IAudioClient_Release(&This->IAudioClient_iface);
1779 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1780 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1781 UINT64 *qpcpos)
1783 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1785 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1786 devpos, qpcpos);
1788 if(!data || !frames || !flags)
1789 return E_POINTER;
1791 OSSpinLockLock(&This->lock);
1793 if(This->getbuf_last){
1794 OSSpinLockUnlock(&This->lock);
1795 return AUDCLNT_E_OUT_OF_ORDER;
1798 if(This->public_buffer){
1799 *data = This->public_buffer->mAudioData;
1800 *frames =
1801 This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
1802 }else{
1803 struct list *head = list_head(&This->avail_buffers);
1804 if(!head){
1805 *data = NULL;
1806 *frames = 0;
1807 }else{
1808 AQBuffer *buf = LIST_ENTRY(head, AQBuffer, entry);
1809 This->public_buffer = buf->buf;
1810 *data = This->public_buffer->mAudioData;
1811 *frames =
1812 This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
1813 list_remove(&buf->entry);
1817 *flags = 0;
1818 This->written_frames += *frames;
1819 This->inbuf_frames -= *frames;
1820 This->getbuf_last = 1;
1822 if(devpos || qpcpos)
1823 AudioClock_GetPosition_nolock(This, devpos, qpcpos, FALSE);
1825 OSSpinLockUnlock(&This->lock);
1827 return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
1830 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1831 IAudioCaptureClient *iface, UINT32 done)
1833 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1834 UINT32 pbuf_frames;
1835 OSStatus sc;
1837 TRACE("(%p)->(%u)\n", This, done);
1839 OSSpinLockLock(&This->lock);
1841 if(!This->getbuf_last){
1842 OSSpinLockUnlock(&This->lock);
1843 return AUDCLNT_E_OUT_OF_ORDER;
1846 pbuf_frames = This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
1847 if(done != 0 && done != pbuf_frames){
1848 OSSpinLockUnlock(&This->lock);
1849 return AUDCLNT_E_INVALID_SIZE;
1852 if(done){
1853 sc = AudioQueueEnqueueBuffer(This->aqueue, This->public_buffer,
1854 0, NULL);
1855 if(sc != noErr)
1856 WARN("Unable to enqueue buffer: %lx\n", sc);
1857 This->public_buffer = NULL;
1860 This->getbuf_last = 0;
1862 OSSpinLockUnlock(&This->lock);
1864 return S_OK;
1867 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1868 IAudioCaptureClient *iface, UINT32 *frames)
1870 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1871 struct list *head;
1872 AQBuffer *buf;
1874 TRACE("(%p)->(%p)\n", This, frames);
1876 if(!frames)
1877 return E_POINTER;
1879 OSSpinLockLock(&This->lock);
1881 head = list_head(&This->avail_buffers);
1883 if(!head){
1884 *frames = This->bufsize_frames / CAPTURE_BUFFERS;
1885 OSSpinLockUnlock(&This->lock);
1886 return S_OK;
1889 buf = LIST_ENTRY(head, AQBuffer, entry);
1890 *frames = buf->buf->mAudioDataByteSize / This->fmt->nBlockAlign;
1892 OSSpinLockUnlock(&This->lock);
1894 return S_OK;
1897 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1899 AudioCaptureClient_QueryInterface,
1900 AudioCaptureClient_AddRef,
1901 AudioCaptureClient_Release,
1902 AudioCaptureClient_GetBuffer,
1903 AudioCaptureClient_ReleaseBuffer,
1904 AudioCaptureClient_GetNextPacketSize
1907 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1908 REFIID riid, void **ppv)
1910 ACImpl *This = impl_from_IAudioClock(iface);
1912 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1914 if(!ppv)
1915 return E_POINTER;
1916 *ppv = NULL;
1918 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
1919 *ppv = iface;
1920 else if(IsEqualIID(riid, &IID_IAudioClock2))
1921 *ppv = &This->IAudioClock2_iface;
1922 if(*ppv){
1923 IUnknown_AddRef((IUnknown*)*ppv);
1924 return S_OK;
1927 WARN("Unknown interface %s\n", debugstr_guid(riid));
1928 return E_NOINTERFACE;
1931 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
1933 ACImpl *This = impl_from_IAudioClock(iface);
1934 return IAudioClient_AddRef(&This->IAudioClient_iface);
1937 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
1939 ACImpl *This = impl_from_IAudioClock(iface);
1940 return IAudioClient_Release(&This->IAudioClient_iface);
1943 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
1945 ACImpl *This = impl_from_IAudioClock(iface);
1947 TRACE("(%p)->(%p)\n", This, freq);
1949 *freq = This->fmt->nSamplesPerSec;
1951 return S_OK;
1954 static HRESULT AudioClock_GetPosition_nolock(ACImpl *This,
1955 UINT64 *pos, UINT64 *qpctime, BOOL raw)
1957 AudioTimeStamp time;
1958 OSStatus sc;
1960 sc = AudioQueueGetCurrentTime(This->aqueue, NULL, &time, NULL);
1961 if(sc == kAudioQueueErr_InvalidRunState){
1962 *pos = 0;
1963 }else if(sc == noErr){
1964 if(!(time.mFlags & kAudioTimeStampSampleTimeValid)){
1965 FIXME("Sample time not valid, should calculate from something else\n");
1966 return E_FAIL;
1969 if(raw)
1970 *pos = time.mSampleTime;
1971 else
1972 *pos = time.mSampleTime - This->last_time;
1973 }else{
1974 WARN("Unable to get current time: %lx\n", sc);
1975 return E_FAIL;
1978 if(qpctime){
1979 LARGE_INTEGER stamp, freq;
1980 QueryPerformanceCounter(&stamp);
1981 QueryPerformanceFrequency(&freq);
1982 *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
1985 return S_OK;
1988 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
1989 UINT64 *qpctime)
1991 ACImpl *This = impl_from_IAudioClock(iface);
1992 HRESULT hr;
1994 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
1996 if(!pos)
1997 return E_POINTER;
1999 OSSpinLockLock(&This->lock);
2001 hr = AudioClock_GetPosition_nolock(This, pos, qpctime, FALSE);
2003 OSSpinLockUnlock(&This->lock);
2005 return hr;
2008 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
2009 DWORD *chars)
2011 ACImpl *This = impl_from_IAudioClock(iface);
2013 TRACE("(%p)->(%p)\n", This, chars);
2015 if(!chars)
2016 return E_POINTER;
2018 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
2020 return S_OK;
2023 static const IAudioClockVtbl AudioClock_Vtbl =
2025 AudioClock_QueryInterface,
2026 AudioClock_AddRef,
2027 AudioClock_Release,
2028 AudioClock_GetFrequency,
2029 AudioClock_GetPosition,
2030 AudioClock_GetCharacteristics
2033 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
2034 REFIID riid, void **ppv)
2036 ACImpl *This = impl_from_IAudioClock2(iface);
2037 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
2040 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
2042 ACImpl *This = impl_from_IAudioClock2(iface);
2043 return IAudioClient_AddRef(&This->IAudioClient_iface);
2046 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
2048 ACImpl *This = impl_from_IAudioClock2(iface);
2049 return IAudioClient_Release(&This->IAudioClient_iface);
2052 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
2053 UINT64 *pos, UINT64 *qpctime)
2055 ACImpl *This = impl_from_IAudioClock2(iface);
2057 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
2059 return E_NOTIMPL;
2062 static const IAudioClock2Vtbl AudioClock2_Vtbl =
2064 AudioClock2_QueryInterface,
2065 AudioClock2_AddRef,
2066 AudioClock2_Release,
2067 AudioClock2_GetDevicePosition
2070 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
2072 AudioSessionWrapper *ret;
2074 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2075 sizeof(AudioSessionWrapper));
2076 if(!ret)
2077 return NULL;
2079 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
2080 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
2081 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
2083 ret->ref = 1;
2085 ret->client = client;
2086 if(client){
2087 ret->session = client->session;
2088 AudioClient_AddRef(&client->IAudioClient_iface);
2091 return ret;
2094 static HRESULT WINAPI AudioSessionControl_QueryInterface(
2095 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
2097 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2099 if(!ppv)
2100 return E_POINTER;
2101 *ppv = NULL;
2103 if(IsEqualIID(riid, &IID_IUnknown) ||
2104 IsEqualIID(riid, &IID_IAudioSessionControl) ||
2105 IsEqualIID(riid, &IID_IAudioSessionControl2))
2106 *ppv = iface;
2107 if(*ppv){
2108 IUnknown_AddRef((IUnknown*)*ppv);
2109 return S_OK;
2112 WARN("Unknown interface %s\n", debugstr_guid(riid));
2113 return E_NOINTERFACE;
2116 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
2118 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2119 ULONG ref;
2120 ref = InterlockedIncrement(&This->ref);
2121 TRACE("(%p) Refcount now %u\n", This, ref);
2122 return ref;
2125 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
2127 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2128 ULONG ref;
2129 ref = InterlockedDecrement(&This->ref);
2130 TRACE("(%p) Refcount now %u\n", This, ref);
2131 if(!ref){
2132 if(This->client){
2133 OSSpinLockLock(&This->client->lock);
2134 This->client->session_wrapper = NULL;
2135 OSSpinLockUnlock(&This->client->lock);
2136 AudioClient_Release(&This->client->IAudioClient_iface);
2138 HeapFree(GetProcessHeap(), 0, This);
2140 return ref;
2143 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
2144 AudioSessionState *state)
2146 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2147 ACImpl *client;
2149 TRACE("(%p)->(%p)\n", This, state);
2151 if(!state)
2152 return NULL_PTR_ERR;
2154 EnterCriticalSection(&g_sessions_lock);
2156 if(list_empty(&This->session->clients)){
2157 *state = AudioSessionStateExpired;
2158 LeaveCriticalSection(&g_sessions_lock);
2159 return S_OK;
2162 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
2163 OSSpinLockLock(&client->lock);
2164 if(client->playing == StatePlaying ||
2165 client->playing == StateInTransition){
2166 *state = AudioSessionStateActive;
2167 OSSpinLockUnlock(&client->lock);
2168 LeaveCriticalSection(&g_sessions_lock);
2169 return S_OK;
2171 OSSpinLockUnlock(&client->lock);
2174 LeaveCriticalSection(&g_sessions_lock);
2176 *state = AudioSessionStateInactive;
2178 return S_OK;
2181 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
2182 IAudioSessionControl2 *iface, WCHAR **name)
2184 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2186 FIXME("(%p)->(%p) - stub\n", This, name);
2188 return E_NOTIMPL;
2191 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
2192 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
2194 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2196 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
2198 return E_NOTIMPL;
2201 static HRESULT WINAPI AudioSessionControl_GetIconPath(
2202 IAudioSessionControl2 *iface, WCHAR **path)
2204 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2206 FIXME("(%p)->(%p) - stub\n", This, path);
2208 return E_NOTIMPL;
2211 static HRESULT WINAPI AudioSessionControl_SetIconPath(
2212 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
2214 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2216 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
2218 return E_NOTIMPL;
2221 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
2222 IAudioSessionControl2 *iface, GUID *group)
2224 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2226 FIXME("(%p)->(%p) - stub\n", This, group);
2228 return E_NOTIMPL;
2231 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
2232 IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
2234 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2236 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
2237 debugstr_guid(session));
2239 return E_NOTIMPL;
2242 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
2243 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2245 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2247 FIXME("(%p)->(%p) - stub\n", This, events);
2249 return S_OK;
2252 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
2253 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2255 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2257 FIXME("(%p)->(%p) - stub\n", This, events);
2259 return S_OK;
2262 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
2263 IAudioSessionControl2 *iface, WCHAR **id)
2265 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2267 FIXME("(%p)->(%p) - stub\n", This, id);
2269 return E_NOTIMPL;
2272 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
2273 IAudioSessionControl2 *iface, WCHAR **id)
2275 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2277 FIXME("(%p)->(%p) - stub\n", This, id);
2279 return E_NOTIMPL;
2282 static HRESULT WINAPI AudioSessionControl_GetProcessId(
2283 IAudioSessionControl2 *iface, DWORD *pid)
2285 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2287 TRACE("(%p)->(%p)\n", This, pid);
2289 if(!pid)
2290 return E_POINTER;
2292 *pid = GetCurrentProcessId();
2294 return S_OK;
2297 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
2298 IAudioSessionControl2 *iface)
2300 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2302 TRACE("(%p)\n", This);
2304 return S_FALSE;
2307 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
2308 IAudioSessionControl2 *iface, BOOL optout)
2310 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2312 TRACE("(%p)->(%d)\n", This, optout);
2314 return S_OK;
2317 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
2319 AudioSessionControl_QueryInterface,
2320 AudioSessionControl_AddRef,
2321 AudioSessionControl_Release,
2322 AudioSessionControl_GetState,
2323 AudioSessionControl_GetDisplayName,
2324 AudioSessionControl_SetDisplayName,
2325 AudioSessionControl_GetIconPath,
2326 AudioSessionControl_SetIconPath,
2327 AudioSessionControl_GetGroupingParam,
2328 AudioSessionControl_SetGroupingParam,
2329 AudioSessionControl_RegisterAudioSessionNotification,
2330 AudioSessionControl_UnregisterAudioSessionNotification,
2331 AudioSessionControl_GetSessionIdentifier,
2332 AudioSessionControl_GetSessionInstanceIdentifier,
2333 AudioSessionControl_GetProcessId,
2334 AudioSessionControl_IsSystemSoundsSession,
2335 AudioSessionControl_SetDuckingPreference
2338 /* index == -1 means set all channels, otherwise sets only the given channel */
2339 static HRESULT ca_setvol(ACImpl *This, UINT32 index)
2341 float level;
2342 OSStatus sc;
2344 if(index == (UINT32)-1){
2345 HRESULT ret = S_OK;
2346 UINT32 i;
2347 for(i = 0; i < This->fmt->nChannels; ++i){
2348 HRESULT hr;
2349 hr = ca_setvol(This, i);
2350 if(FAILED(hr))
2351 ret = hr;
2353 return ret;
2356 if(This->session->mute)
2357 level = 0;
2358 else
2359 level = This->session->master_vol *
2360 This->session->channel_vols[index] * This->vols[index];
2362 sc = AudioQueueSetParameter(This->aqueue, kAudioQueueParam_Volume, level);
2363 if(sc != noErr)
2364 WARN("Setting _Volume property failed: %lx\n", sc);
2366 return S_OK;
2369 static HRESULT ca_session_setvol(AudioSession *session, UINT32 index)
2371 HRESULT ret = S_OK;
2372 ACImpl *client;
2374 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry){
2375 HRESULT hr;
2376 hr = ca_setvol(client, index);
2377 if(FAILED(hr))
2378 ret = hr;
2381 return ret;
2384 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
2385 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
2387 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2389 if(!ppv)
2390 return E_POINTER;
2391 *ppv = NULL;
2393 if(IsEqualIID(riid, &IID_IUnknown) ||
2394 IsEqualIID(riid, &IID_ISimpleAudioVolume))
2395 *ppv = iface;
2396 if(*ppv){
2397 IUnknown_AddRef((IUnknown*)*ppv);
2398 return S_OK;
2401 WARN("Unknown interface %s\n", debugstr_guid(riid));
2402 return E_NOINTERFACE;
2405 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
2407 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2408 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2411 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
2413 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2414 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2417 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
2418 ISimpleAudioVolume *iface, float level, const GUID *context)
2420 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2421 AudioSession *session = This->session;
2422 HRESULT ret;
2424 TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
2426 if(level < 0.f || level > 1.f)
2427 return E_INVALIDARG;
2429 if(context)
2430 FIXME("Notifications not supported yet\n");
2432 EnterCriticalSection(&session->lock);
2434 session->master_vol = level;
2436 ret = ca_session_setvol(session, -1);
2438 LeaveCriticalSection(&session->lock);
2440 return ret;
2443 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
2444 ISimpleAudioVolume *iface, float *level)
2446 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2447 AudioSession *session = This->session;
2449 TRACE("(%p)->(%p)\n", session, level);
2451 if(!level)
2452 return NULL_PTR_ERR;
2454 *level = session->master_vol;
2456 return S_OK;
2459 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
2460 BOOL mute, const GUID *context)
2462 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2463 AudioSession *session = This->session;
2465 TRACE("(%p)->(%u, %p)\n", session, mute, context);
2467 if(context)
2468 FIXME("Notifications not supported yet\n");
2470 EnterCriticalSection(&session->lock);
2472 session->mute = mute;
2474 ca_session_setvol(session, -1);
2476 LeaveCriticalSection(&session->lock);
2478 return S_OK;
2481 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
2482 BOOL *mute)
2484 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2485 AudioSession *session = This->session;
2487 TRACE("(%p)->(%p)\n", session, mute);
2489 if(!mute)
2490 return NULL_PTR_ERR;
2492 *mute = session->mute;
2494 return S_OK;
2497 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
2499 SimpleAudioVolume_QueryInterface,
2500 SimpleAudioVolume_AddRef,
2501 SimpleAudioVolume_Release,
2502 SimpleAudioVolume_SetMasterVolume,
2503 SimpleAudioVolume_GetMasterVolume,
2504 SimpleAudioVolume_SetMute,
2505 SimpleAudioVolume_GetMute
2508 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
2509 IAudioStreamVolume *iface, REFIID riid, void **ppv)
2511 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2513 if(!ppv)
2514 return E_POINTER;
2515 *ppv = NULL;
2517 if(IsEqualIID(riid, &IID_IUnknown) ||
2518 IsEqualIID(riid, &IID_IAudioStreamVolume))
2519 *ppv = iface;
2520 if(*ppv){
2521 IUnknown_AddRef((IUnknown*)*ppv);
2522 return S_OK;
2525 WARN("Unknown interface %s\n", debugstr_guid(riid));
2526 return E_NOINTERFACE;
2529 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
2531 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2532 return IAudioClient_AddRef(&This->IAudioClient_iface);
2535 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
2537 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2538 return IAudioClient_Release(&This->IAudioClient_iface);
2541 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
2542 IAudioStreamVolume *iface, UINT32 *out)
2544 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2546 TRACE("(%p)->(%p)\n", This, out);
2548 if(!out)
2549 return E_POINTER;
2551 *out = This->fmt->nChannels;
2553 return S_OK;
2556 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
2557 IAudioStreamVolume *iface, UINT32 index, float level)
2559 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2560 HRESULT ret;
2562 TRACE("(%p)->(%d, %f)\n", This, index, level);
2564 if(level < 0.f || level > 1.f)
2565 return E_INVALIDARG;
2567 if(index >= This->fmt->nChannels)
2568 return E_INVALIDARG;
2570 OSSpinLockLock(&This->lock);
2572 This->vols[index] = level;
2574 WARN("AudioQueue doesn't support per-channel volume control\n");
2575 ret = ca_setvol(This, index);
2577 OSSpinLockUnlock(&This->lock);
2579 return ret;
2582 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2583 IAudioStreamVolume *iface, UINT32 index, float *level)
2585 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2587 TRACE("(%p)->(%d, %p)\n", This, index, level);
2589 if(!level)
2590 return E_POINTER;
2592 if(index >= This->fmt->nChannels)
2593 return E_INVALIDARG;
2595 *level = This->vols[index];
2597 return S_OK;
2600 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2601 IAudioStreamVolume *iface, UINT32 count, const float *levels)
2603 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2604 int i;
2605 HRESULT ret;
2607 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2609 if(!levels)
2610 return E_POINTER;
2612 if(count != This->fmt->nChannels)
2613 return E_INVALIDARG;
2615 OSSpinLockLock(&This->lock);
2617 for(i = 0; i < count; ++i)
2618 This->vols[i] = levels[i];
2620 ret = ca_setvol(This, -1);
2622 OSSpinLockUnlock(&This->lock);
2624 return ret;
2627 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2628 IAudioStreamVolume *iface, UINT32 count, float *levels)
2630 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2631 int i;
2633 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2635 if(!levels)
2636 return E_POINTER;
2638 if(count != This->fmt->nChannels)
2639 return E_INVALIDARG;
2641 OSSpinLockLock(&This->lock);
2643 for(i = 0; i < count; ++i)
2644 levels[i] = This->vols[i];
2646 OSSpinLockUnlock(&This->lock);
2648 return S_OK;
2651 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2653 AudioStreamVolume_QueryInterface,
2654 AudioStreamVolume_AddRef,
2655 AudioStreamVolume_Release,
2656 AudioStreamVolume_GetChannelCount,
2657 AudioStreamVolume_SetChannelVolume,
2658 AudioStreamVolume_GetChannelVolume,
2659 AudioStreamVolume_SetAllVolumes,
2660 AudioStreamVolume_GetAllVolumes
2663 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2664 IChannelAudioVolume *iface, REFIID riid, void **ppv)
2666 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2668 if(!ppv)
2669 return E_POINTER;
2670 *ppv = NULL;
2672 if(IsEqualIID(riid, &IID_IUnknown) ||
2673 IsEqualIID(riid, &IID_IChannelAudioVolume))
2674 *ppv = iface;
2675 if(*ppv){
2676 IUnknown_AddRef((IUnknown*)*ppv);
2677 return S_OK;
2680 WARN("Unknown interface %s\n", debugstr_guid(riid));
2681 return E_NOINTERFACE;
2684 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2686 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2687 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2690 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2692 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2693 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2696 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2697 IChannelAudioVolume *iface, UINT32 *out)
2699 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2700 AudioSession *session = This->session;
2702 TRACE("(%p)->(%p)\n", session, out);
2704 if(!out)
2705 return NULL_PTR_ERR;
2707 *out = session->channel_count;
2709 return S_OK;
2712 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2713 IChannelAudioVolume *iface, UINT32 index, float level,
2714 const GUID *context)
2716 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2717 AudioSession *session = This->session;
2718 HRESULT ret;
2720 TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2721 wine_dbgstr_guid(context));
2723 if(level < 0.f || level > 1.f)
2724 return E_INVALIDARG;
2726 if(index >= session->channel_count)
2727 return E_INVALIDARG;
2729 if(context)
2730 FIXME("Notifications not supported yet\n");
2732 EnterCriticalSection(&session->lock);
2734 session->channel_vols[index] = level;
2736 WARN("AudioQueue doesn't support per-channel volume control\n");
2737 ret = ca_session_setvol(session, index);
2739 LeaveCriticalSection(&session->lock);
2741 return ret;
2744 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2745 IChannelAudioVolume *iface, UINT32 index, float *level)
2747 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2748 AudioSession *session = This->session;
2750 TRACE("(%p)->(%d, %p)\n", session, index, level);
2752 if(!level)
2753 return NULL_PTR_ERR;
2755 if(index >= session->channel_count)
2756 return E_INVALIDARG;
2758 *level = session->channel_vols[index];
2760 return S_OK;
2763 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2764 IChannelAudioVolume *iface, UINT32 count, const float *levels,
2765 const GUID *context)
2767 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2768 AudioSession *session = This->session;
2769 int i;
2770 HRESULT ret;
2772 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2773 wine_dbgstr_guid(context));
2775 if(!levels)
2776 return NULL_PTR_ERR;
2778 if(count != session->channel_count)
2779 return E_INVALIDARG;
2781 if(context)
2782 FIXME("Notifications not supported yet\n");
2784 EnterCriticalSection(&session->lock);
2786 for(i = 0; i < count; ++i)
2787 session->channel_vols[i] = levels[i];
2789 ret = ca_session_setvol(session, -1);
2791 LeaveCriticalSection(&session->lock);
2793 return ret;
2796 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2797 IChannelAudioVolume *iface, UINT32 count, float *levels)
2799 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2800 AudioSession *session = This->session;
2801 int i;
2803 TRACE("(%p)->(%d, %p)\n", session, count, levels);
2805 if(!levels)
2806 return NULL_PTR_ERR;
2808 if(count != session->channel_count)
2809 return E_INVALIDARG;
2811 for(i = 0; i < count; ++i)
2812 levels[i] = session->channel_vols[i];
2814 return S_OK;
2817 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2819 ChannelAudioVolume_QueryInterface,
2820 ChannelAudioVolume_AddRef,
2821 ChannelAudioVolume_Release,
2822 ChannelAudioVolume_GetChannelCount,
2823 ChannelAudioVolume_SetChannelVolume,
2824 ChannelAudioVolume_GetChannelVolume,
2825 ChannelAudioVolume_SetAllVolumes,
2826 ChannelAudioVolume_GetAllVolumes
2829 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2830 REFIID riid, void **ppv)
2832 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2834 if(!ppv)
2835 return E_POINTER;
2836 *ppv = NULL;
2838 if(IsEqualIID(riid, &IID_IUnknown) ||
2839 IsEqualIID(riid, &IID_IAudioSessionManager) ||
2840 IsEqualIID(riid, &IID_IAudioSessionManager2))
2841 *ppv = iface;
2842 if(*ppv){
2843 IUnknown_AddRef((IUnknown*)*ppv);
2844 return S_OK;
2847 WARN("Unknown interface %s\n", debugstr_guid(riid));
2848 return E_NOINTERFACE;
2851 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2853 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2854 ULONG ref;
2855 ref = InterlockedIncrement(&This->ref);
2856 TRACE("(%p) Refcount now %u\n", This, ref);
2857 return ref;
2860 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2862 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2863 ULONG ref;
2864 ref = InterlockedDecrement(&This->ref);
2865 TRACE("(%p) Refcount now %u\n", This, ref);
2866 if(!ref)
2867 HeapFree(GetProcessHeap(), 0, This);
2868 return ref;
2871 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2872 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2873 IAudioSessionControl **out)
2875 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2876 AudioSession *session;
2877 AudioSessionWrapper *wrapper;
2878 HRESULT hr;
2880 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2881 flags, out);
2883 hr = get_audio_session(session_guid, This->device, 0, &session);
2884 if(FAILED(hr))
2885 return hr;
2887 wrapper = AudioSessionWrapper_Create(NULL);
2888 if(!wrapper)
2889 return E_OUTOFMEMORY;
2891 wrapper->session = session;
2893 *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
2895 return S_OK;
2898 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
2899 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2900 ISimpleAudioVolume **out)
2902 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2903 AudioSession *session;
2904 AudioSessionWrapper *wrapper;
2905 HRESULT hr;
2907 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2908 flags, out);
2910 hr = get_audio_session(session_guid, This->device, 0, &session);
2911 if(FAILED(hr))
2912 return hr;
2914 wrapper = AudioSessionWrapper_Create(NULL);
2915 if(!wrapper)
2916 return E_OUTOFMEMORY;
2918 wrapper->session = session;
2920 *out = &wrapper->ISimpleAudioVolume_iface;
2922 return S_OK;
2925 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
2926 IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
2928 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2929 FIXME("(%p)->(%p) - stub\n", This, out);
2930 return E_NOTIMPL;
2933 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
2934 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2936 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2937 FIXME("(%p)->(%p) - stub\n", This, notification);
2938 return E_NOTIMPL;
2941 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
2942 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2944 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2945 FIXME("(%p)->(%p) - stub\n", This, notification);
2946 return E_NOTIMPL;
2949 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
2950 IAudioSessionManager2 *iface, const WCHAR *session_id,
2951 IAudioVolumeDuckNotification *notification)
2953 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2954 FIXME("(%p)->(%p) - stub\n", This, notification);
2955 return E_NOTIMPL;
2958 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
2959 IAudioSessionManager2 *iface,
2960 IAudioVolumeDuckNotification *notification)
2962 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2963 FIXME("(%p)->(%p) - stub\n", This, notification);
2964 return E_NOTIMPL;
2967 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
2969 AudioSessionManager_QueryInterface,
2970 AudioSessionManager_AddRef,
2971 AudioSessionManager_Release,
2972 AudioSessionManager_GetAudioSessionControl,
2973 AudioSessionManager_GetSimpleAudioVolume,
2974 AudioSessionManager_GetSessionEnumerator,
2975 AudioSessionManager_RegisterSessionNotification,
2976 AudioSessionManager_UnregisterSessionNotification,
2977 AudioSessionManager_RegisterDuckNotification,
2978 AudioSessionManager_UnregisterDuckNotification
2981 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
2982 IAudioSessionManager2 **out)
2984 SessionMgr *This;
2986 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
2987 if(!This)
2988 return E_OUTOFMEMORY;
2990 This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
2991 This->device = device;
2992 This->ref = 1;
2994 *out = &This->IAudioSessionManager2_iface;
2996 return S_OK;