winecoreaudio: Fix a leak.
[wine/multimedia.git] / dlls / winecoreaudio.drv / mmdevdrv.c
blob414aaf5cc3339a6c0801d01fccfc43ffaaf49c14
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)[j]);
351 HeapFree(GetProcessHeap(), 0, *keys);
352 HeapFree(GetProcessHeap(), 0, *ids);
353 return E_OUTOFMEMORY;
356 sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL,
357 &size, buffers);
358 if(sc != noErr){
359 WARN("Unable to get _StreamConfiguration property for "
360 "device %lu: %lx\n", devices[i], sc);
361 HeapFree(GetProcessHeap(), 0, buffers);
362 continue;
365 /* check that there's at least one channel in this device before
366 * we claim it as usable */
367 for(j = 0; j < buffers->mNumberBuffers; ++j)
368 if(buffers->mBuffers[j].mNumberChannels > 0)
369 break;
370 if(j >= buffers->mNumberBuffers){
371 HeapFree(GetProcessHeap(), 0, buffers);
372 continue;
375 HeapFree(GetProcessHeap(), 0, buffers);
377 size = sizeof(name);
378 addr.mSelector = kAudioObjectPropertyName;
379 sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL,
380 &size, &name);
381 if(sc != noErr){
382 WARN("Unable to get _Name property for device %lu: %lx\n",
383 devices[i], sc);
384 continue;
387 if(!CFStringGetCString(name, nameA, sizeof(nameA),
388 kCFStringEncodingUTF8)){
389 WARN("Error converting string to UTF8\n");
390 CFRelease(name);
391 continue;
394 CFRelease(name);
396 len = MultiByteToWideChar(CP_UNIXCP, 0, nameA, -1, NULL, 0);
397 (*ids)[*num] = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
398 if(!(*ids)[*num]){
399 HeapFree(GetProcessHeap(), 0, devices);
400 for(j = 0; j < *num; ++j){
401 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
402 HeapFree(GetProcessHeap(), 0, (*keys)[j]);
404 HeapFree(GetProcessHeap(), 0, *ids);
405 HeapFree(GetProcessHeap(), 0, *keys);
406 return E_OUTOFMEMORY;
408 MultiByteToWideChar(CP_UNIXCP, 0, nameA, -1, (*ids)[*num], len);
410 (*keys)[*num] = HeapAlloc(GetProcessHeap(), 0, sizeof(AudioDeviceID));
411 if(!(*ids)[*num]){
412 HeapFree(GetProcessHeap(), 0, devices);
413 HeapFree(GetProcessHeap(), 0, (*ids)[*num]);
414 for(j = 0; j < *num; ++j){
415 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
416 HeapFree(GetProcessHeap(), 0, (*keys)[j]);
418 HeapFree(GetProcessHeap(), 0, *ids);
419 HeapFree(GetProcessHeap(), 0, *keys);
420 return E_OUTOFMEMORY;
422 *(*keys)[*num] = devices[i];
424 if(*def_index == (UINT)-1 && devices[i] == default_id)
425 *def_index = *num;
427 (*num)++;
430 if(*def_index == (UINT)-1)
431 *def_index = 0;
433 HeapFree(GetProcessHeap(), 0, devices);
435 return S_OK;
438 HRESULT WINAPI AUDDRV_GetAudioEndpoint(AudioDeviceID *adevid, IMMDevice *dev,
439 EDataFlow dataflow, IAudioClient **out)
441 ACImpl *This;
443 TRACE("%p %d %p\n", dev, dataflow, out);
445 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACImpl));
446 if(!This)
447 return E_OUTOFMEMORY;
449 This->IAudioClient_iface.lpVtbl = &AudioClient_Vtbl;
450 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
451 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
452 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
453 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
454 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
456 This->dataflow = dataflow;
458 if(dataflow == eRender)
459 This->scope = kAudioDevicePropertyScopeOutput;
460 else if(dataflow == eCapture)
461 This->scope = kAudioDevicePropertyScopeInput;
462 else{
463 HeapFree(GetProcessHeap(), 0, This);
464 return E_INVALIDARG;
467 This->lock = 0;
469 This->parent = dev;
470 IMMDevice_AddRef(This->parent);
472 list_init(&This->avail_buffers);
474 This->adevid = *adevid;
476 *out = &This->IAudioClient_iface;
477 IAudioClient_AddRef(&This->IAudioClient_iface);
479 return S_OK;
482 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient *iface,
483 REFIID riid, void **ppv)
485 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
487 if(!ppv)
488 return E_POINTER;
489 *ppv = NULL;
490 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClient))
491 *ppv = iface;
492 if(*ppv){
493 IUnknown_AddRef((IUnknown*)*ppv);
494 return S_OK;
496 WARN("Unknown interface %s\n", debugstr_guid(riid));
497 return E_NOINTERFACE;
500 static ULONG WINAPI AudioClient_AddRef(IAudioClient *iface)
502 ACImpl *This = impl_from_IAudioClient(iface);
503 ULONG ref;
504 ref = InterlockedIncrement(&This->ref);
505 TRACE("(%p) Refcount now %u\n", This, ref);
506 return ref;
509 static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
511 ACImpl *This = impl_from_IAudioClient(iface);
512 ULONG ref;
513 ref = InterlockedDecrement(&This->ref);
514 TRACE("(%p) Refcount now %u\n", This, ref);
515 if(!ref){
516 IAudioClient_Stop(iface);
517 if(This->aqueue)
518 AudioQueueDispose(This->aqueue, 1);
519 if(This->session){
520 EnterCriticalSection(&g_sessions_lock);
521 list_remove(&This->entry);
522 LeaveCriticalSection(&g_sessions_lock);
524 HeapFree(GetProcessHeap(), 0, This->vols);
525 HeapFree(GetProcessHeap(), 0, This->public_buffer);
526 CoTaskMemFree(This->fmt);
527 IMMDevice_Release(This->parent);
528 HeapFree(GetProcessHeap(), 0, This);
530 return ref;
533 static void dump_fmt(const WAVEFORMATEX *fmt)
535 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
536 switch(fmt->wFormatTag){
537 case WAVE_FORMAT_PCM:
538 TRACE("WAVE_FORMAT_PCM");
539 break;
540 case WAVE_FORMAT_IEEE_FLOAT:
541 TRACE("WAVE_FORMAT_IEEE_FLOAT");
542 break;
543 case WAVE_FORMAT_EXTENSIBLE:
544 TRACE("WAVE_FORMAT_EXTENSIBLE");
545 break;
546 default:
547 TRACE("Unknown");
548 break;
550 TRACE(")\n");
552 TRACE("nChannels: %u\n", fmt->nChannels);
553 TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
554 TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
555 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
556 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
557 TRACE("cbSize: %u\n", fmt->cbSize);
559 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
560 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
561 TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
562 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
563 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
567 static DWORD get_channel_mask(unsigned int channels)
569 switch(channels){
570 case 0:
571 return 0;
572 case 1:
573 return KSAUDIO_SPEAKER_MONO;
574 case 2:
575 return KSAUDIO_SPEAKER_STEREO;
576 case 3:
577 return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY;
578 case 4:
579 return KSAUDIO_SPEAKER_QUAD; /* not _SURROUND */
580 case 5:
581 return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY;
582 case 6:
583 return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */
584 case 7:
585 return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER;
586 case 8:
587 return KSAUDIO_SPEAKER_7POINT1; /* not 7POINT1_SURROUND */
589 FIXME("Unknown speaker configuration: %u\n", channels);
590 return 0;
593 static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
595 WAVEFORMATEX *ret;
596 size_t size;
598 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
599 size = sizeof(WAVEFORMATEXTENSIBLE);
600 else
601 size = sizeof(WAVEFORMATEX);
603 ret = CoTaskMemAlloc(size);
604 if(!ret)
605 return NULL;
607 memcpy(ret, fmt, size);
609 ret->cbSize = size - sizeof(WAVEFORMATEX);
611 return ret;
614 static HRESULT ca_get_audiodesc(AudioStreamBasicDescription *desc,
615 const WAVEFORMATEX *fmt)
617 const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)fmt;
619 desc->mFormatFlags = 0;
621 if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
622 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
623 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
624 desc->mFormatID = kAudioFormatLinearPCM;
625 if(fmt->wBitsPerSample > 8)
626 desc->mFormatFlags = kAudioFormatFlagIsSignedInteger;
627 }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
628 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
629 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
630 desc->mFormatID = kAudioFormatLinearPCM;
631 desc->mFormatFlags = kAudioFormatFlagIsFloat;
632 }else if(fmt->wFormatTag == WAVE_FORMAT_MULAW ||
633 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
634 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_MULAW))){
635 desc->mFormatID = kAudioFormatULaw;
636 }else if(fmt->wFormatTag == WAVE_FORMAT_ALAW ||
637 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
638 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_ALAW))){
639 desc->mFormatID = kAudioFormatALaw;
640 }else
641 return AUDCLNT_E_UNSUPPORTED_FORMAT;
643 desc->mSampleRate = fmt->nSamplesPerSec;
644 desc->mBytesPerPacket = fmt->nBlockAlign;
645 desc->mFramesPerPacket = 1;
646 desc->mBytesPerFrame = fmt->nBlockAlign;
647 desc->mChannelsPerFrame = fmt->nChannels;
648 desc->mBitsPerChannel = fmt->wBitsPerSample;
649 desc->mReserved = 0;
651 return S_OK;
654 static void ca_out_buffer_cb(void *user, AudioQueueRef aqueue,
655 AudioQueueBufferRef buffer)
657 ACImpl *This = user;
658 AQBuffer *buf = buffer->mUserData;
660 OSSpinLockLock(&This->lock);
661 list_add_tail(&This->avail_buffers, &buf->entry);
662 This->inbuf_frames -= buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
663 OSSpinLockUnlock(&This->lock);
666 static void ca_in_buffer_cb(void *user, AudioQueueRef aqueue,
667 AudioQueueBufferRef buffer, const AudioTimeStamp *start,
668 UInt32 ndesc, const AudioStreamPacketDescription *descs)
670 ACImpl *This = user;
671 AQBuffer *buf = buffer->mUserData;
673 OSSpinLockLock(&This->lock);
674 list_add_tail(&This->avail_buffers, &buf->entry);
675 This->inbuf_frames += buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
676 OSSpinLockUnlock(&This->lock);
679 static HRESULT ca_setup_aqueue(AudioDeviceID did, EDataFlow flow,
680 const WAVEFORMATEX *fmt, void *user, AudioQueueRef *aqueue)
682 AudioStreamBasicDescription desc;
683 AudioObjectPropertyAddress addr;
684 CFStringRef uid;
685 OSStatus sc;
686 HRESULT hr;
687 UInt32 size;
689 addr.mScope = kAudioObjectPropertyScopeGlobal;
690 addr.mElement = 0;
691 addr.mSelector = kAudioDevicePropertyDeviceUID;
693 size = sizeof(uid);
694 sc = AudioObjectGetPropertyData(did, &addr, 0, NULL, &size, &uid);
695 if(sc != noErr){
696 WARN("Unable to get _DeviceUID property: %lx\n", sc);
697 return E_FAIL;
700 hr = ca_get_audiodesc(&desc, fmt);
701 if(FAILED(hr)){
702 CFRelease(uid);
703 return hr;
706 if(flow == eRender)
707 sc = AudioQueueNewOutput(&desc, ca_out_buffer_cb, user, NULL, NULL, 0,
708 aqueue);
709 else if(flow == eCapture)
710 sc = AudioQueueNewInput(&desc, ca_in_buffer_cb, user, NULL, NULL, 0,
711 aqueue);
712 else{
713 CFRelease(uid);
714 return E_UNEXPECTED;
716 if(sc != noErr){
717 WARN("Unable to create AudioQueue: %lx\n", sc);
718 CFRelease(uid);
719 return E_FAIL;
722 sc = AudioQueueSetProperty(*aqueue, kAudioQueueProperty_CurrentDevice,
723 &uid, sizeof(uid));
724 if(sc != noErr){
725 CFRelease(uid);
726 return E_FAIL;
729 CFRelease(uid);
731 return S_OK;
734 static void session_init_vols(AudioSession *session, UINT channels)
736 if(session->channel_count < channels){
737 UINT i;
739 if(session->channel_vols)
740 session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
741 session->channel_vols, sizeof(float) * channels);
742 else
743 session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
744 sizeof(float) * channels);
745 if(!session->channel_vols)
746 return;
748 for(i = session->channel_count; i < channels; ++i)
749 session->channel_vols[i] = 1.f;
751 session->channel_count = channels;
755 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
756 UINT num_channels)
758 AudioSession *ret;
760 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
761 if(!ret)
762 return NULL;
764 memcpy(&ret->guid, guid, sizeof(GUID));
766 ret->device = device;
768 list_init(&ret->clients);
770 list_add_head(&g_sessions, &ret->entry);
772 InitializeCriticalSection(&ret->lock);
774 session_init_vols(ret, num_channels);
776 ret->master_vol = 1.f;
778 return ret;
781 /* if channels == 0, then this will return or create a session with
782 * matching dataflow and GUID. otherwise, channels must also match */
783 static HRESULT get_audio_session(const GUID *sessionguid,
784 IMMDevice *device, UINT channels, AudioSession **out)
786 AudioSession *session;
788 if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
789 *out = create_session(&GUID_NULL, device, channels);
790 if(!*out)
791 return E_OUTOFMEMORY;
793 return S_OK;
796 *out = NULL;
797 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
798 if(session->device == device &&
799 IsEqualGUID(sessionguid, &session->guid)){
800 session_init_vols(session, channels);
801 *out = session;
802 break;
806 if(!*out){
807 *out = create_session(sessionguid, device, channels);
808 if(!*out)
809 return E_OUTOFMEMORY;
812 return S_OK;
815 static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
816 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
817 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
818 const GUID *sessionguid)
820 ACImpl *This = impl_from_IAudioClient(iface);
821 HRESULT hr;
822 OSStatus sc;
823 int i;
825 TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
826 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
828 if(!fmt)
829 return E_POINTER;
831 dump_fmt(fmt);
833 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
834 return AUDCLNT_E_NOT_INITIALIZED;
836 if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
837 AUDCLNT_STREAMFLAGS_LOOPBACK |
838 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
839 AUDCLNT_STREAMFLAGS_NOPERSIST |
840 AUDCLNT_STREAMFLAGS_RATEADJUST |
841 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
842 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
843 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED)){
844 TRACE("Unknown flags: %08x\n", flags);
845 return E_INVALIDARG;
848 OSSpinLockLock(&This->lock);
850 if(This->aqueue){
851 OSSpinLockUnlock(&This->lock);
852 return AUDCLNT_E_ALREADY_INITIALIZED;
855 hr = ca_setup_aqueue(This->adevid, This->dataflow, fmt, This, &This->aqueue);
856 if(FAILED(hr)){
857 OSSpinLockUnlock(&This->lock);
858 return hr;
861 This->fmt = clone_format(fmt);
862 if(!This->fmt){
863 AudioQueueDispose(This->aqueue, 1);
864 This->aqueue = NULL;
865 OSSpinLockUnlock(&This->lock);
866 return E_OUTOFMEMORY;
869 if(period){
870 This->period_ms = period / 10000;
871 if(This->period_ms == 0)
872 This->period_ms = 1;
873 }else
874 This->period_ms = MinimumPeriod / 10000;
876 if(!duration)
877 duration = 300000; /* 0.03s */
878 This->bufsize_frames = ceil(fmt->nSamplesPerSec * (duration / 10000000.));
880 if(This->dataflow == eCapture){
881 int i;
882 UInt32 bsize = ceil((This->bufsize_frames / (double)CAPTURE_BUFFERS) *
883 This->fmt->nBlockAlign);
884 for(i = 0; i < CAPTURE_BUFFERS; ++i){
885 AQBuffer *buf;
887 buf = HeapAlloc(GetProcessHeap(), 0, sizeof(AQBuffer));
888 if(!buf){
889 AudioQueueDispose(This->aqueue, 1);
890 This->aqueue = NULL;
891 CoTaskMemFree(This->fmt);
892 This->fmt = NULL;
893 OSSpinLockUnlock(&This->lock);
894 return E_OUTOFMEMORY;
897 sc = AudioQueueAllocateBuffer(This->aqueue, bsize, &buf->buf);
898 if(sc != noErr){
899 AudioQueueDispose(This->aqueue, 1);
900 This->aqueue = NULL;
901 CoTaskMemFree(This->fmt);
902 This->fmt = NULL;
903 OSSpinLockUnlock(&This->lock);
904 WARN("Couldn't allocate buffer: %lx\n", sc);
905 return E_FAIL;
908 buf->buf->mUserData = buf;
910 sc = AudioQueueEnqueueBuffer(This->aqueue, buf->buf, 0, NULL);
911 if(sc != noErr){
912 ERR("Couldn't enqueue buffer: %lx\n", sc);
913 break;
918 This->vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float));
919 if(!This->vols){
920 AudioQueueDispose(This->aqueue, 1);
921 This->aqueue = NULL;
922 CoTaskMemFree(This->fmt);
923 This->fmt = NULL;
924 OSSpinLockUnlock(&This->lock);
925 return E_OUTOFMEMORY;
928 for(i = 0; i < fmt->nChannels; ++i)
929 This->vols[i] = 1.f;
931 This->share = mode;
932 This->flags = flags;
934 EnterCriticalSection(&g_sessions_lock);
936 hr = get_audio_session(sessionguid, This->parent, fmt->nChannels,
937 &This->session);
938 if(FAILED(hr)){
939 LeaveCriticalSection(&g_sessions_lock);
940 AudioQueueDispose(This->aqueue, 1);
941 This->aqueue = NULL;
942 CoTaskMemFree(This->fmt);
943 This->fmt = NULL;
944 HeapFree(GetProcessHeap(), 0, This->vols);
945 This->vols = NULL;
946 OSSpinLockUnlock(&This->lock);
947 return E_INVALIDARG;
950 list_add_tail(&This->session->clients, &This->entry);
952 LeaveCriticalSection(&g_sessions_lock);
954 ca_setvol(This, -1);
956 OSSpinLockUnlock(&This->lock);
958 return S_OK;
961 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
962 UINT32 *frames)
964 ACImpl *This = impl_from_IAudioClient(iface);
966 TRACE("(%p)->(%p)\n", This, frames);
968 if(!frames)
969 return E_POINTER;
971 OSSpinLockLock(&This->lock);
973 if(!This->aqueue){
974 OSSpinLockUnlock(&This->lock);
975 return AUDCLNT_E_NOT_INITIALIZED;
978 *frames = This->bufsize_frames;
980 OSSpinLockUnlock(&This->lock);
982 return S_OK;
985 static HRESULT ca_get_max_stream_latency(ACImpl *This, UInt32 *max)
987 AudioObjectPropertyAddress addr;
988 AudioStreamID *ids;
989 UInt32 size;
990 OSStatus sc;
991 int nstreams, i;
993 addr.mScope = This->scope;
994 addr.mElement = 0;
995 addr.mSelector = kAudioDevicePropertyStreams;
997 sc = AudioObjectGetPropertyDataSize(This->adevid, &addr, 0, NULL,
998 &size);
999 if(sc != noErr){
1000 WARN("Unable to get size for _Streams property: %lx\n", sc);
1001 return E_FAIL;
1004 ids = HeapAlloc(GetProcessHeap(), 0, size);
1005 if(!ids)
1006 return E_OUTOFMEMORY;
1008 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL, &size, ids);
1009 if(sc != noErr){
1010 WARN("Unable to get _Streams property: %lx\n", sc);
1011 HeapFree(GetProcessHeap(), 0, ids);
1012 return E_FAIL;
1015 nstreams = size / sizeof(AudioStreamID);
1016 *max = 0;
1018 addr.mSelector = kAudioStreamPropertyLatency;
1019 for(i = 0; i < nstreams; ++i){
1020 UInt32 latency;
1022 size = sizeof(latency);
1023 sc = AudioObjectGetPropertyData(ids[i], &addr, 0, NULL,
1024 &size, &latency);
1025 if(sc != noErr){
1026 WARN("Unable to get _Latency property: %lx\n", sc);
1027 continue;
1030 if(latency > *max)
1031 *max = latency;
1034 HeapFree(GetProcessHeap(), 0, ids);
1036 return S_OK;
1039 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
1040 REFERENCE_TIME *out)
1042 ACImpl *This = impl_from_IAudioClient(iface);
1043 UInt32 latency, stream_latency, size;
1044 AudioObjectPropertyAddress addr;
1045 OSStatus sc;
1046 HRESULT hr;
1048 TRACE("(%p)->(%p)\n", This, out);
1050 if(!out)
1051 return E_POINTER;
1053 OSSpinLockLock(&This->lock);
1055 if(!This->aqueue){
1056 OSSpinLockUnlock(&This->lock);
1057 return AUDCLNT_E_NOT_INITIALIZED;
1060 addr.mScope = This->scope;
1061 addr.mSelector = kAudioDevicePropertyLatency;
1062 addr.mElement = 0;
1064 size = sizeof(latency);
1065 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL,
1066 &size, &latency);
1067 if(sc != noErr){
1068 WARN("Couldn't get _Latency property: %lx\n", sc);
1069 OSSpinLockUnlock(&This->lock);
1070 return E_FAIL;
1073 hr = ca_get_max_stream_latency(This, &stream_latency);
1074 if(FAILED(hr)){
1075 OSSpinLockUnlock(&This->lock);
1076 return hr;
1079 latency += stream_latency;
1080 *out = (latency / (double)This->fmt->nSamplesPerSec) * 10000000;
1082 OSSpinLockUnlock(&This->lock);
1084 return S_OK;
1087 static HRESULT AudioClient_GetCurrentPadding_nolock(ACImpl *This,
1088 UINT32 *numpad)
1090 if(!This->aqueue)
1091 return AUDCLNT_E_NOT_INITIALIZED;
1093 *numpad = This->inbuf_frames;
1095 return S_OK;
1098 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
1099 UINT32 *numpad)
1101 ACImpl *This = impl_from_IAudioClient(iface);
1102 HRESULT hr;
1104 TRACE("(%p)->(%p)\n", This, numpad);
1106 if(!numpad)
1107 return E_POINTER;
1109 OSSpinLockLock(&This->lock);
1111 hr = AudioClient_GetCurrentPadding_nolock(This, numpad);
1113 OSSpinLockUnlock(&This->lock);
1115 return hr;
1118 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
1119 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
1120 WAVEFORMATEX **outpwfx)
1122 ACImpl *This = impl_from_IAudioClient(iface);
1123 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)pwfx;
1124 AudioQueueRef aqueue;
1125 HRESULT hr;
1127 TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx);
1129 if(!pwfx || (mode == AUDCLNT_SHAREMODE_SHARED && !outpwfx))
1130 return E_POINTER;
1132 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1133 return E_INVALIDARG;
1135 if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1136 pwfx->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1137 return E_INVALIDARG;
1139 dump_fmt(pwfx);
1141 if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1142 fmtex->dwChannelMask != 0 &&
1143 fmtex->dwChannelMask != get_channel_mask(pwfx->nChannels))
1144 return AUDCLNT_E_UNSUPPORTED_FORMAT;
1146 OSSpinLockLock(&This->lock);
1148 hr = ca_setup_aqueue(This->adevid, This->dataflow, pwfx, NULL, &aqueue);
1149 if(SUCCEEDED(hr)){
1150 AudioQueueDispose(aqueue, 1);
1151 OSSpinLockUnlock(&This->lock);
1152 if(outpwfx)
1153 *outpwfx = NULL;
1154 TRACE("returning %08x\n", S_OK);
1155 return S_OK;
1158 OSSpinLockUnlock(&This->lock);
1160 if(outpwfx)
1161 *outpwfx = NULL;
1163 TRACE("returning %08x\n", AUDCLNT_E_UNSUPPORTED_FORMAT);
1164 return AUDCLNT_E_UNSUPPORTED_FORMAT;
1167 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
1168 WAVEFORMATEX **pwfx)
1170 ACImpl *This = impl_from_IAudioClient(iface);
1171 WAVEFORMATEXTENSIBLE *fmt;
1172 OSStatus sc;
1173 UInt32 size;
1174 Float64 rate;
1175 AudioBufferList *buffers;
1176 AudioObjectPropertyAddress addr;
1177 int i;
1179 TRACE("(%p)->(%p)\n", This, pwfx);
1181 if(!pwfx)
1182 return E_POINTER;
1183 *pwfx = NULL;
1185 fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
1186 if(!fmt)
1187 return E_OUTOFMEMORY;
1189 fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1191 addr.mScope = This->scope;
1192 addr.mElement = 0;
1193 addr.mSelector = kAudioDevicePropertyStreamConfiguration;
1195 sc = AudioObjectGetPropertyDataSize(This->adevid, &addr, 0, NULL, &size);
1196 if(sc != noErr){
1197 CoTaskMemFree(fmt);
1198 WARN("Unable to get size for _StreamConfiguration property: %lx\n", sc);
1199 return E_FAIL;
1202 buffers = HeapAlloc(GetProcessHeap(), 0, size);
1203 if(!buffers){
1204 CoTaskMemFree(fmt);
1205 return E_OUTOFMEMORY;
1208 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL,
1209 &size, buffers);
1210 if(sc != noErr){
1211 CoTaskMemFree(fmt);
1212 HeapFree(GetProcessHeap(), 0, buffers);
1213 WARN("Unable to get _StreamConfiguration property: %lx\n", sc);
1214 return E_FAIL;
1217 fmt->Format.nChannels = 0;
1218 for(i = 0; i < buffers->mNumberBuffers; ++i)
1219 fmt->Format.nChannels += buffers->mBuffers[i].mNumberChannels;
1221 HeapFree(GetProcessHeap(), 0, buffers);
1223 fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
1225 addr.mSelector = kAudioDevicePropertyNominalSampleRate;
1226 size = sizeof(Float64);
1227 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL, &size, &rate);
1228 if(sc != noErr){
1229 CoTaskMemFree(fmt);
1230 WARN("Unable to get _NominalSampleRate property: %lx\n", sc);
1231 return E_FAIL;
1233 fmt->Format.nSamplesPerSec = rate;
1235 fmt->Format.wBitsPerSample = 32;
1236 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
1238 fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
1239 fmt->Format.nChannels) / 8;
1240 fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
1241 fmt->Format.nBlockAlign;
1243 fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
1244 fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1246 *pwfx = (WAVEFORMATEX*)fmt;
1247 dump_fmt(*pwfx);
1249 return S_OK;
1252 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
1253 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1255 ACImpl *This = impl_from_IAudioClient(iface);
1257 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
1259 if(!defperiod && !minperiod)
1260 return E_POINTER;
1262 OSSpinLockLock(&This->lock);
1264 if(This->period_ms){
1265 if(defperiod)
1266 *defperiod = This->period_ms * 10000;
1267 if(minperiod)
1268 *minperiod = This->period_ms * 10000;
1269 }else{
1270 if(defperiod)
1271 *defperiod = DefaultPeriod;
1272 if(minperiod)
1273 *minperiod = MinimumPeriod;
1276 OSSpinLockUnlock(&This->lock);
1278 return S_OK;
1281 void CALLBACK ca_period_cb(void *user, BOOLEAN timer)
1283 ACImpl *This = user;
1285 OSSpinLockLock(&This->lock);
1286 if(This->event)
1287 SetEvent(This->event);
1288 OSSpinLockUnlock(&This->lock);
1291 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
1293 ACImpl *This = impl_from_IAudioClient(iface);
1294 OSStatus sc;
1296 TRACE("(%p)\n", This);
1298 OSSpinLockLock(&This->lock);
1300 if(!This->aqueue){
1301 OSSpinLockUnlock(&This->lock);
1302 return AUDCLNT_E_NOT_INITIALIZED;
1305 if(This->playing != StateStopped){
1306 OSSpinLockUnlock(&This->lock);
1307 return AUDCLNT_E_NOT_STOPPED;
1310 if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
1311 OSSpinLockUnlock(&This->lock);
1312 return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1315 if(This->event)
1316 if(!CreateTimerQueueTimer(&This->timer, g_timer_q,
1317 ca_period_cb, This, 0, This->period_ms, 0))
1318 ERR("Unable to create timer: %u\n", GetLastError());
1320 This->playing = StateInTransition;
1322 OSSpinLockUnlock(&This->lock);
1324 sc = AudioQueueStart(This->aqueue, NULL);
1325 if(sc != noErr){
1326 WARN("Unable to start audio queue: %lx\n", sc);
1327 return E_FAIL;
1330 OSSpinLockLock(&This->lock);
1332 This->playing = StatePlaying;
1334 OSSpinLockUnlock(&This->lock);
1336 return S_OK;
1339 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
1341 ACImpl *This = impl_from_IAudioClient(iface);
1342 OSStatus sc;
1344 TRACE("(%p)\n", This);
1346 OSSpinLockLock(&This->lock);
1348 if(!This->aqueue){
1349 OSSpinLockUnlock(&This->lock);
1350 return AUDCLNT_E_NOT_INITIALIZED;
1353 if(This->playing == StateStopped){
1354 OSSpinLockUnlock(&This->lock);
1355 return S_FALSE;
1358 if(This->playing == StateInTransition){
1359 OSSpinLockUnlock(&This->lock);
1360 return S_OK;
1363 if(This->timer && This->timer != INVALID_HANDLE_VALUE){
1364 DeleteTimerQueueTimer(g_timer_q, This->timer, INVALID_HANDLE_VALUE);
1365 This->timer = NULL;
1368 This->playing = StateInTransition;
1370 OSSpinLockUnlock(&This->lock);
1372 sc = AudioQueueFlush(This->aqueue);
1373 if(sc != noErr)
1374 WARN("Unable to flush audio queue: %lx\n", sc);
1376 sc = AudioQueuePause(This->aqueue);
1377 if(sc != noErr){
1378 WARN("Unable to pause audio queue: %lx\n", sc);
1379 return E_FAIL;
1382 OSSpinLockLock(&This->lock);
1384 This->playing = StateStopped;
1386 OSSpinLockUnlock(&This->lock);
1388 return S_OK;
1391 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
1393 ACImpl *This = impl_from_IAudioClient(iface);
1394 HRESULT hr;
1395 OSStatus sc;
1397 TRACE("(%p)\n", This);
1399 OSSpinLockLock(&This->lock);
1401 if(!This->aqueue){
1402 OSSpinLockUnlock(&This->lock);
1403 return AUDCLNT_E_NOT_INITIALIZED;
1406 if(This->playing != StateStopped){
1407 OSSpinLockUnlock(&This->lock);
1408 return AUDCLNT_E_NOT_STOPPED;
1411 if(This->getbuf_last){
1412 OSSpinLockUnlock(&This->lock);
1413 return AUDCLNT_E_BUFFER_OPERATION_PENDING;
1416 This->written_frames = 0;
1418 hr = AudioClock_GetPosition_nolock(This, &This->last_time, NULL, TRUE);
1419 if(FAILED(hr)){
1420 OSSpinLockUnlock(&This->lock);
1421 return hr;
1424 OSSpinLockUnlock(&This->lock);
1426 sc = AudioQueueReset(This->aqueue);
1427 if(sc != noErr){
1428 WARN("Unable to reset audio queue: %lx\n", sc);
1429 return E_FAIL;
1432 return S_OK;
1435 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1436 HANDLE event)
1438 ACImpl *This = impl_from_IAudioClient(iface);
1440 TRACE("(%p)->(%p)\n", This, event);
1442 if(!event)
1443 return E_INVALIDARG;
1445 OSSpinLockLock(&This->lock);
1447 if(!This->aqueue){
1448 OSSpinLockUnlock(&This->lock);
1449 return AUDCLNT_E_NOT_INITIALIZED;
1452 if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
1453 OSSpinLockUnlock(&This->lock);
1454 return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1457 This->event = event;
1459 OSSpinLockUnlock(&This->lock);
1461 return S_OK;
1464 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1465 void **ppv)
1467 ACImpl *This = impl_from_IAudioClient(iface);
1469 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1471 if(!ppv)
1472 return E_POINTER;
1473 *ppv = NULL;
1475 OSSpinLockLock(&This->lock);
1477 if(!This->aqueue){
1478 OSSpinLockUnlock(&This->lock);
1479 return AUDCLNT_E_NOT_INITIALIZED;
1482 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1483 if(This->dataflow != eRender){
1484 OSSpinLockUnlock(&This->lock);
1485 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1487 IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
1488 *ppv = &This->IAudioRenderClient_iface;
1489 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1490 if(This->dataflow != eCapture){
1491 OSSpinLockUnlock(&This->lock);
1492 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1494 IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
1495 *ppv = &This->IAudioCaptureClient_iface;
1496 }else if(IsEqualIID(riid, &IID_IAudioClock)){
1497 IAudioClock_AddRef(&This->IAudioClock_iface);
1498 *ppv = &This->IAudioClock_iface;
1499 }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1500 IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
1501 *ppv = &This->IAudioStreamVolume_iface;
1502 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1503 if(!This->session_wrapper){
1504 This->session_wrapper = AudioSessionWrapper_Create(This);
1505 if(!This->session_wrapper){
1506 OSSpinLockUnlock(&This->lock);
1507 return E_OUTOFMEMORY;
1509 }else
1510 IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
1512 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1513 }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1514 if(!This->session_wrapper){
1515 This->session_wrapper = AudioSessionWrapper_Create(This);
1516 if(!This->session_wrapper){
1517 OSSpinLockUnlock(&This->lock);
1518 return E_OUTOFMEMORY;
1520 }else
1521 IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
1523 *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1524 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1525 if(!This->session_wrapper){
1526 This->session_wrapper = AudioSessionWrapper_Create(This);
1527 if(!This->session_wrapper){
1528 OSSpinLockUnlock(&This->lock);
1529 return E_OUTOFMEMORY;
1531 }else
1532 ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
1534 *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1537 if(*ppv){
1538 OSSpinLockUnlock(&This->lock);
1539 return S_OK;
1542 OSSpinLockUnlock(&This->lock);
1544 FIXME("stub %s\n", debugstr_guid(riid));
1545 return E_NOINTERFACE;
1548 static const IAudioClientVtbl AudioClient_Vtbl =
1550 AudioClient_QueryInterface,
1551 AudioClient_AddRef,
1552 AudioClient_Release,
1553 AudioClient_Initialize,
1554 AudioClient_GetBufferSize,
1555 AudioClient_GetStreamLatency,
1556 AudioClient_GetCurrentPadding,
1557 AudioClient_IsFormatSupported,
1558 AudioClient_GetMixFormat,
1559 AudioClient_GetDevicePeriod,
1560 AudioClient_Start,
1561 AudioClient_Stop,
1562 AudioClient_Reset,
1563 AudioClient_SetEventHandle,
1564 AudioClient_GetService
1567 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1568 IAudioRenderClient *iface, REFIID riid, void **ppv)
1570 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1572 if(!ppv)
1573 return E_POINTER;
1574 *ppv = NULL;
1576 if(IsEqualIID(riid, &IID_IUnknown) ||
1577 IsEqualIID(riid, &IID_IAudioRenderClient))
1578 *ppv = iface;
1579 if(*ppv){
1580 IUnknown_AddRef((IUnknown*)*ppv);
1581 return S_OK;
1584 WARN("Unknown interface %s\n", debugstr_guid(riid));
1585 return E_NOINTERFACE;
1588 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1590 ACImpl *This = impl_from_IAudioRenderClient(iface);
1591 return AudioClient_AddRef(&This->IAudioClient_iface);
1594 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1596 ACImpl *This = impl_from_IAudioRenderClient(iface);
1597 return AudioClient_Release(&This->IAudioClient_iface);
1600 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1601 UINT32 frames, BYTE **data)
1603 ACImpl *This = impl_from_IAudioRenderClient(iface);
1604 AQBuffer *buf;
1605 UINT32 pad, bytes = frames * This->fmt->nBlockAlign;
1606 HRESULT hr;
1607 OSStatus sc;
1609 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1611 if(!data)
1612 return E_POINTER;
1613 *data = NULL;
1615 OSSpinLockLock(&This->lock);
1617 if(This->getbuf_last){
1618 OSSpinLockUnlock(&This->lock);
1619 return AUDCLNT_E_OUT_OF_ORDER;
1622 if(!frames){
1623 OSSpinLockUnlock(&This->lock);
1624 return S_OK;
1627 hr = AudioClient_GetCurrentPadding_nolock(This, &pad);
1628 if(FAILED(hr)){
1629 OSSpinLockUnlock(&This->lock);
1630 return hr;
1633 if(pad + frames > This->bufsize_frames){
1634 OSSpinLockUnlock(&This->lock);
1635 return AUDCLNT_E_BUFFER_TOO_LARGE;
1638 LIST_FOR_EACH_ENTRY(buf, &This->avail_buffers, AQBuffer, entry){
1639 if(buf->buf->mAudioDataBytesCapacity >= bytes){
1640 This->public_buffer = buf->buf;
1641 list_remove(&buf->entry);
1642 break;
1646 if(&buf->entry == &This->avail_buffers){
1647 sc = AudioQueueAllocateBuffer(This->aqueue, bytes,
1648 &This->public_buffer);
1649 if(sc != noErr){
1650 OSSpinLockUnlock(&This->lock);
1651 WARN("Unable to allocate buffer: %lx\n", sc);
1652 return E_FAIL;
1654 buf = HeapAlloc(GetProcessHeap(), 0, sizeof(AQBuffer));
1655 if(!buf){
1656 AudioQueueFreeBuffer(This->aqueue, This->public_buffer);
1657 This->public_buffer = NULL;
1658 OSSpinLockUnlock(&This->lock);
1659 return E_OUTOFMEMORY;
1661 buf->buf = This->public_buffer;
1662 This->public_buffer->mUserData = buf;
1665 *data = This->public_buffer->mAudioData;
1667 This->getbuf_last = frames;
1669 OSSpinLockUnlock(&This->lock);
1671 return S_OK;
1674 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1675 IAudioRenderClient *iface, UINT32 frames, DWORD flags)
1677 ACImpl *This = impl_from_IAudioRenderClient(iface);
1678 OSStatus sc;
1680 TRACE("(%p)->(%u, %x)\n", This, frames, flags);
1682 OSSpinLockLock(&This->lock);
1684 if(!frames){
1685 This->getbuf_last = 0;
1686 if(This->public_buffer){
1687 AQBuffer *buf = This->public_buffer->mUserData;
1688 list_add_tail(&This->avail_buffers, &buf->entry);
1689 This->public_buffer = NULL;
1691 OSSpinLockUnlock(&This->lock);
1692 return S_OK;
1695 if(!This->getbuf_last){
1696 OSSpinLockUnlock(&This->lock);
1697 return AUDCLNT_E_OUT_OF_ORDER;
1700 if(frames > This->getbuf_last){
1701 OSSpinLockUnlock(&This->lock);
1702 return AUDCLNT_E_INVALID_SIZE;
1705 if(flags & AUDCLNT_BUFFERFLAGS_SILENT){
1706 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)This->fmt;
1707 if((This->fmt->wFormatTag == WAVE_FORMAT_PCM ||
1708 (This->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1709 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) &&
1710 This->fmt->wBitsPerSample == 8)
1711 memset(This->public_buffer->mAudioData, 128,
1712 frames * This->fmt->nBlockAlign);
1713 else
1714 memset(This->public_buffer->mAudioData, 0,
1715 frames * This->fmt->nBlockAlign);
1718 This->public_buffer->mAudioDataByteSize = frames * This->fmt->nBlockAlign;
1720 sc = AudioQueueEnqueueBuffer(This->aqueue, This->public_buffer, 0, NULL);
1721 if(sc != noErr){
1722 OSSpinLockUnlock(&This->lock);
1723 WARN("Unable to enqueue buffer: %lx\n", sc);
1724 return E_FAIL;
1727 if(This->playing == StateStopped)
1728 AudioQueuePrime(This->aqueue, 0, NULL);
1730 This->public_buffer = NULL;
1731 This->getbuf_last = 0;
1732 This->written_frames += frames;
1733 This->inbuf_frames += frames;
1735 OSSpinLockUnlock(&This->lock);
1737 return S_OK;
1740 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1741 AudioRenderClient_QueryInterface,
1742 AudioRenderClient_AddRef,
1743 AudioRenderClient_Release,
1744 AudioRenderClient_GetBuffer,
1745 AudioRenderClient_ReleaseBuffer
1748 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1749 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1751 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1753 if(!ppv)
1754 return E_POINTER;
1755 *ppv = NULL;
1757 if(IsEqualIID(riid, &IID_IUnknown) ||
1758 IsEqualIID(riid, &IID_IAudioCaptureClient))
1759 *ppv = iface;
1760 if(*ppv){
1761 IUnknown_AddRef((IUnknown*)*ppv);
1762 return S_OK;
1765 WARN("Unknown interface %s\n", debugstr_guid(riid));
1766 return E_NOINTERFACE;
1769 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1771 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1772 return IAudioClient_AddRef(&This->IAudioClient_iface);
1775 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1777 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1778 return IAudioClient_Release(&This->IAudioClient_iface);
1781 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1782 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1783 UINT64 *qpcpos)
1785 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1787 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1788 devpos, qpcpos);
1790 if(!data || !frames || !flags)
1791 return E_POINTER;
1793 OSSpinLockLock(&This->lock);
1795 if(This->getbuf_last){
1796 OSSpinLockUnlock(&This->lock);
1797 return AUDCLNT_E_OUT_OF_ORDER;
1800 if(This->public_buffer){
1801 *data = This->public_buffer->mAudioData;
1802 *frames =
1803 This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
1804 }else{
1805 struct list *head = list_head(&This->avail_buffers);
1806 if(!head){
1807 *data = NULL;
1808 *frames = 0;
1809 }else{
1810 AQBuffer *buf = LIST_ENTRY(head, AQBuffer, entry);
1811 This->public_buffer = buf->buf;
1812 *data = This->public_buffer->mAudioData;
1813 *frames =
1814 This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
1815 list_remove(&buf->entry);
1819 *flags = 0;
1820 This->written_frames += *frames;
1821 This->inbuf_frames -= *frames;
1822 This->getbuf_last = 1;
1824 if(devpos || qpcpos)
1825 AudioClock_GetPosition_nolock(This, devpos, qpcpos, FALSE);
1827 OSSpinLockUnlock(&This->lock);
1829 return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
1832 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1833 IAudioCaptureClient *iface, UINT32 done)
1835 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1836 UINT32 pbuf_frames;
1837 OSStatus sc;
1839 TRACE("(%p)->(%u)\n", This, done);
1841 OSSpinLockLock(&This->lock);
1843 if(!This->getbuf_last){
1844 OSSpinLockUnlock(&This->lock);
1845 return AUDCLNT_E_OUT_OF_ORDER;
1848 pbuf_frames = This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
1849 if(done != 0 && done != pbuf_frames){
1850 OSSpinLockUnlock(&This->lock);
1851 return AUDCLNT_E_INVALID_SIZE;
1854 if(done){
1855 sc = AudioQueueEnqueueBuffer(This->aqueue, This->public_buffer,
1856 0, NULL);
1857 if(sc != noErr)
1858 WARN("Unable to enqueue buffer: %lx\n", sc);
1859 This->public_buffer = NULL;
1862 This->getbuf_last = 0;
1864 OSSpinLockUnlock(&This->lock);
1866 return S_OK;
1869 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1870 IAudioCaptureClient *iface, UINT32 *frames)
1872 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1873 struct list *head;
1874 AQBuffer *buf;
1876 TRACE("(%p)->(%p)\n", This, frames);
1878 if(!frames)
1879 return E_POINTER;
1881 OSSpinLockLock(&This->lock);
1883 head = list_head(&This->avail_buffers);
1885 if(!head){
1886 *frames = This->bufsize_frames / CAPTURE_BUFFERS;
1887 OSSpinLockUnlock(&This->lock);
1888 return S_OK;
1891 buf = LIST_ENTRY(head, AQBuffer, entry);
1892 *frames = buf->buf->mAudioDataByteSize / This->fmt->nBlockAlign;
1894 OSSpinLockUnlock(&This->lock);
1896 return S_OK;
1899 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1901 AudioCaptureClient_QueryInterface,
1902 AudioCaptureClient_AddRef,
1903 AudioCaptureClient_Release,
1904 AudioCaptureClient_GetBuffer,
1905 AudioCaptureClient_ReleaseBuffer,
1906 AudioCaptureClient_GetNextPacketSize
1909 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1910 REFIID riid, void **ppv)
1912 ACImpl *This = impl_from_IAudioClock(iface);
1914 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1916 if(!ppv)
1917 return E_POINTER;
1918 *ppv = NULL;
1920 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
1921 *ppv = iface;
1922 else if(IsEqualIID(riid, &IID_IAudioClock2))
1923 *ppv = &This->IAudioClock2_iface;
1924 if(*ppv){
1925 IUnknown_AddRef((IUnknown*)*ppv);
1926 return S_OK;
1929 WARN("Unknown interface %s\n", debugstr_guid(riid));
1930 return E_NOINTERFACE;
1933 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
1935 ACImpl *This = impl_from_IAudioClock(iface);
1936 return IAudioClient_AddRef(&This->IAudioClient_iface);
1939 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
1941 ACImpl *This = impl_from_IAudioClock(iface);
1942 return IAudioClient_Release(&This->IAudioClient_iface);
1945 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
1947 ACImpl *This = impl_from_IAudioClock(iface);
1949 TRACE("(%p)->(%p)\n", This, freq);
1951 *freq = This->fmt->nSamplesPerSec;
1953 return S_OK;
1956 static HRESULT AudioClock_GetPosition_nolock(ACImpl *This,
1957 UINT64 *pos, UINT64 *qpctime, BOOL raw)
1959 AudioTimeStamp time;
1960 OSStatus sc;
1962 sc = AudioQueueGetCurrentTime(This->aqueue, NULL, &time, NULL);
1963 if(sc == kAudioQueueErr_InvalidRunState){
1964 *pos = 0;
1965 }else if(sc == noErr){
1966 if(!(time.mFlags & kAudioTimeStampSampleTimeValid)){
1967 FIXME("Sample time not valid, should calculate from something else\n");
1968 return E_FAIL;
1971 if(raw)
1972 *pos = time.mSampleTime;
1973 else
1974 *pos = time.mSampleTime - This->last_time;
1975 }else{
1976 WARN("Unable to get current time: %lx\n", sc);
1977 return E_FAIL;
1980 if(qpctime){
1981 LARGE_INTEGER stamp, freq;
1982 QueryPerformanceCounter(&stamp);
1983 QueryPerformanceFrequency(&freq);
1984 *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
1987 return S_OK;
1990 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
1991 UINT64 *qpctime)
1993 ACImpl *This = impl_from_IAudioClock(iface);
1994 HRESULT hr;
1996 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
1998 if(!pos)
1999 return E_POINTER;
2001 OSSpinLockLock(&This->lock);
2003 hr = AudioClock_GetPosition_nolock(This, pos, qpctime, FALSE);
2005 OSSpinLockUnlock(&This->lock);
2007 return hr;
2010 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
2011 DWORD *chars)
2013 ACImpl *This = impl_from_IAudioClock(iface);
2015 TRACE("(%p)->(%p)\n", This, chars);
2017 if(!chars)
2018 return E_POINTER;
2020 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
2022 return S_OK;
2025 static const IAudioClockVtbl AudioClock_Vtbl =
2027 AudioClock_QueryInterface,
2028 AudioClock_AddRef,
2029 AudioClock_Release,
2030 AudioClock_GetFrequency,
2031 AudioClock_GetPosition,
2032 AudioClock_GetCharacteristics
2035 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
2036 REFIID riid, void **ppv)
2038 ACImpl *This = impl_from_IAudioClock2(iface);
2039 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
2042 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
2044 ACImpl *This = impl_from_IAudioClock2(iface);
2045 return IAudioClient_AddRef(&This->IAudioClient_iface);
2048 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
2050 ACImpl *This = impl_from_IAudioClock2(iface);
2051 return IAudioClient_Release(&This->IAudioClient_iface);
2054 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
2055 UINT64 *pos, UINT64 *qpctime)
2057 ACImpl *This = impl_from_IAudioClock2(iface);
2059 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
2061 return E_NOTIMPL;
2064 static const IAudioClock2Vtbl AudioClock2_Vtbl =
2066 AudioClock2_QueryInterface,
2067 AudioClock2_AddRef,
2068 AudioClock2_Release,
2069 AudioClock2_GetDevicePosition
2072 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
2074 AudioSessionWrapper *ret;
2076 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2077 sizeof(AudioSessionWrapper));
2078 if(!ret)
2079 return NULL;
2081 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
2082 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
2083 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
2085 ret->ref = 1;
2087 ret->client = client;
2088 if(client){
2089 ret->session = client->session;
2090 AudioClient_AddRef(&client->IAudioClient_iface);
2093 return ret;
2096 static HRESULT WINAPI AudioSessionControl_QueryInterface(
2097 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
2099 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2101 if(!ppv)
2102 return E_POINTER;
2103 *ppv = NULL;
2105 if(IsEqualIID(riid, &IID_IUnknown) ||
2106 IsEqualIID(riid, &IID_IAudioSessionControl) ||
2107 IsEqualIID(riid, &IID_IAudioSessionControl2))
2108 *ppv = iface;
2109 if(*ppv){
2110 IUnknown_AddRef((IUnknown*)*ppv);
2111 return S_OK;
2114 WARN("Unknown interface %s\n", debugstr_guid(riid));
2115 return E_NOINTERFACE;
2118 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
2120 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2121 ULONG ref;
2122 ref = InterlockedIncrement(&This->ref);
2123 TRACE("(%p) Refcount now %u\n", This, ref);
2124 return ref;
2127 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
2129 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2130 ULONG ref;
2131 ref = InterlockedDecrement(&This->ref);
2132 TRACE("(%p) Refcount now %u\n", This, ref);
2133 if(!ref){
2134 if(This->client){
2135 OSSpinLockLock(&This->client->lock);
2136 This->client->session_wrapper = NULL;
2137 OSSpinLockUnlock(&This->client->lock);
2138 AudioClient_Release(&This->client->IAudioClient_iface);
2140 HeapFree(GetProcessHeap(), 0, This);
2142 return ref;
2145 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
2146 AudioSessionState *state)
2148 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2149 ACImpl *client;
2151 TRACE("(%p)->(%p)\n", This, state);
2153 if(!state)
2154 return NULL_PTR_ERR;
2156 EnterCriticalSection(&g_sessions_lock);
2158 if(list_empty(&This->session->clients)){
2159 *state = AudioSessionStateExpired;
2160 LeaveCriticalSection(&g_sessions_lock);
2161 return S_OK;
2164 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
2165 OSSpinLockLock(&client->lock);
2166 if(client->playing == StatePlaying ||
2167 client->playing == StateInTransition){
2168 *state = AudioSessionStateActive;
2169 OSSpinLockUnlock(&client->lock);
2170 LeaveCriticalSection(&g_sessions_lock);
2171 return S_OK;
2173 OSSpinLockUnlock(&client->lock);
2176 LeaveCriticalSection(&g_sessions_lock);
2178 *state = AudioSessionStateInactive;
2180 return S_OK;
2183 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
2184 IAudioSessionControl2 *iface, WCHAR **name)
2186 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2188 FIXME("(%p)->(%p) - stub\n", This, name);
2190 return E_NOTIMPL;
2193 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
2194 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
2196 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2198 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
2200 return E_NOTIMPL;
2203 static HRESULT WINAPI AudioSessionControl_GetIconPath(
2204 IAudioSessionControl2 *iface, WCHAR **path)
2206 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2208 FIXME("(%p)->(%p) - stub\n", This, path);
2210 return E_NOTIMPL;
2213 static HRESULT WINAPI AudioSessionControl_SetIconPath(
2214 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
2216 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2218 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
2220 return E_NOTIMPL;
2223 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
2224 IAudioSessionControl2 *iface, GUID *group)
2226 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2228 FIXME("(%p)->(%p) - stub\n", This, group);
2230 return E_NOTIMPL;
2233 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
2234 IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
2236 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2238 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
2239 debugstr_guid(session));
2241 return E_NOTIMPL;
2244 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
2245 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2247 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2249 FIXME("(%p)->(%p) - stub\n", This, events);
2251 return S_OK;
2254 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
2255 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2257 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2259 FIXME("(%p)->(%p) - stub\n", This, events);
2261 return S_OK;
2264 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
2265 IAudioSessionControl2 *iface, WCHAR **id)
2267 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2269 FIXME("(%p)->(%p) - stub\n", This, id);
2271 return E_NOTIMPL;
2274 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
2275 IAudioSessionControl2 *iface, WCHAR **id)
2277 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2279 FIXME("(%p)->(%p) - stub\n", This, id);
2281 return E_NOTIMPL;
2284 static HRESULT WINAPI AudioSessionControl_GetProcessId(
2285 IAudioSessionControl2 *iface, DWORD *pid)
2287 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2289 TRACE("(%p)->(%p)\n", This, pid);
2291 if(!pid)
2292 return E_POINTER;
2294 *pid = GetCurrentProcessId();
2296 return S_OK;
2299 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
2300 IAudioSessionControl2 *iface)
2302 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2304 TRACE("(%p)\n", This);
2306 return S_FALSE;
2309 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
2310 IAudioSessionControl2 *iface, BOOL optout)
2312 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2314 TRACE("(%p)->(%d)\n", This, optout);
2316 return S_OK;
2319 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
2321 AudioSessionControl_QueryInterface,
2322 AudioSessionControl_AddRef,
2323 AudioSessionControl_Release,
2324 AudioSessionControl_GetState,
2325 AudioSessionControl_GetDisplayName,
2326 AudioSessionControl_SetDisplayName,
2327 AudioSessionControl_GetIconPath,
2328 AudioSessionControl_SetIconPath,
2329 AudioSessionControl_GetGroupingParam,
2330 AudioSessionControl_SetGroupingParam,
2331 AudioSessionControl_RegisterAudioSessionNotification,
2332 AudioSessionControl_UnregisterAudioSessionNotification,
2333 AudioSessionControl_GetSessionIdentifier,
2334 AudioSessionControl_GetSessionInstanceIdentifier,
2335 AudioSessionControl_GetProcessId,
2336 AudioSessionControl_IsSystemSoundsSession,
2337 AudioSessionControl_SetDuckingPreference
2340 /* index == -1 means set all channels, otherwise sets only the given channel */
2341 static HRESULT ca_setvol(ACImpl *This, UINT32 index)
2343 float level;
2344 OSStatus sc;
2346 if(index == (UINT32)-1){
2347 HRESULT ret = S_OK;
2348 UINT32 i;
2349 for(i = 0; i < This->fmt->nChannels; ++i){
2350 HRESULT hr;
2351 hr = ca_setvol(This, i);
2352 if(FAILED(hr))
2353 ret = hr;
2355 return ret;
2358 if(This->session->mute)
2359 level = 0;
2360 else
2361 level = This->session->master_vol *
2362 This->session->channel_vols[index] * This->vols[index];
2364 sc = AudioQueueSetParameter(This->aqueue, kAudioQueueParam_Volume, level);
2365 if(sc != noErr)
2366 WARN("Setting _Volume property failed: %lx\n", sc);
2368 return S_OK;
2371 static HRESULT ca_session_setvol(AudioSession *session, UINT32 index)
2373 HRESULT ret = S_OK;
2374 ACImpl *client;
2376 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry){
2377 HRESULT hr;
2378 hr = ca_setvol(client, index);
2379 if(FAILED(hr))
2380 ret = hr;
2383 return ret;
2386 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
2387 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
2389 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2391 if(!ppv)
2392 return E_POINTER;
2393 *ppv = NULL;
2395 if(IsEqualIID(riid, &IID_IUnknown) ||
2396 IsEqualIID(riid, &IID_ISimpleAudioVolume))
2397 *ppv = iface;
2398 if(*ppv){
2399 IUnknown_AddRef((IUnknown*)*ppv);
2400 return S_OK;
2403 WARN("Unknown interface %s\n", debugstr_guid(riid));
2404 return E_NOINTERFACE;
2407 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
2409 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2410 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2413 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
2415 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2416 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2419 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
2420 ISimpleAudioVolume *iface, float level, const GUID *context)
2422 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2423 AudioSession *session = This->session;
2424 HRESULT ret;
2426 TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
2428 if(level < 0.f || level > 1.f)
2429 return E_INVALIDARG;
2431 if(context)
2432 FIXME("Notifications not supported yet\n");
2434 EnterCriticalSection(&session->lock);
2436 session->master_vol = level;
2438 ret = ca_session_setvol(session, -1);
2440 LeaveCriticalSection(&session->lock);
2442 return ret;
2445 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
2446 ISimpleAudioVolume *iface, float *level)
2448 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2449 AudioSession *session = This->session;
2451 TRACE("(%p)->(%p)\n", session, level);
2453 if(!level)
2454 return NULL_PTR_ERR;
2456 *level = session->master_vol;
2458 return S_OK;
2461 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
2462 BOOL mute, const GUID *context)
2464 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2465 AudioSession *session = This->session;
2467 TRACE("(%p)->(%u, %p)\n", session, mute, context);
2469 if(context)
2470 FIXME("Notifications not supported yet\n");
2472 EnterCriticalSection(&session->lock);
2474 session->mute = mute;
2476 ca_session_setvol(session, -1);
2478 LeaveCriticalSection(&session->lock);
2480 return S_OK;
2483 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
2484 BOOL *mute)
2486 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2487 AudioSession *session = This->session;
2489 TRACE("(%p)->(%p)\n", session, mute);
2491 if(!mute)
2492 return NULL_PTR_ERR;
2494 *mute = session->mute;
2496 return S_OK;
2499 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
2501 SimpleAudioVolume_QueryInterface,
2502 SimpleAudioVolume_AddRef,
2503 SimpleAudioVolume_Release,
2504 SimpleAudioVolume_SetMasterVolume,
2505 SimpleAudioVolume_GetMasterVolume,
2506 SimpleAudioVolume_SetMute,
2507 SimpleAudioVolume_GetMute
2510 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
2511 IAudioStreamVolume *iface, REFIID riid, void **ppv)
2513 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2515 if(!ppv)
2516 return E_POINTER;
2517 *ppv = NULL;
2519 if(IsEqualIID(riid, &IID_IUnknown) ||
2520 IsEqualIID(riid, &IID_IAudioStreamVolume))
2521 *ppv = iface;
2522 if(*ppv){
2523 IUnknown_AddRef((IUnknown*)*ppv);
2524 return S_OK;
2527 WARN("Unknown interface %s\n", debugstr_guid(riid));
2528 return E_NOINTERFACE;
2531 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
2533 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2534 return IAudioClient_AddRef(&This->IAudioClient_iface);
2537 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
2539 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2540 return IAudioClient_Release(&This->IAudioClient_iface);
2543 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
2544 IAudioStreamVolume *iface, UINT32 *out)
2546 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2548 TRACE("(%p)->(%p)\n", This, out);
2550 if(!out)
2551 return E_POINTER;
2553 *out = This->fmt->nChannels;
2555 return S_OK;
2558 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
2559 IAudioStreamVolume *iface, UINT32 index, float level)
2561 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2562 HRESULT ret;
2564 TRACE("(%p)->(%d, %f)\n", This, index, level);
2566 if(level < 0.f || level > 1.f)
2567 return E_INVALIDARG;
2569 if(index >= This->fmt->nChannels)
2570 return E_INVALIDARG;
2572 OSSpinLockLock(&This->lock);
2574 This->vols[index] = level;
2576 WARN("AudioQueue doesn't support per-channel volume control\n");
2577 ret = ca_setvol(This, index);
2579 OSSpinLockUnlock(&This->lock);
2581 return ret;
2584 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2585 IAudioStreamVolume *iface, UINT32 index, float *level)
2587 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2589 TRACE("(%p)->(%d, %p)\n", This, index, level);
2591 if(!level)
2592 return E_POINTER;
2594 if(index >= This->fmt->nChannels)
2595 return E_INVALIDARG;
2597 *level = This->vols[index];
2599 return S_OK;
2602 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2603 IAudioStreamVolume *iface, UINT32 count, const float *levels)
2605 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2606 int i;
2607 HRESULT ret;
2609 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2611 if(!levels)
2612 return E_POINTER;
2614 if(count != This->fmt->nChannels)
2615 return E_INVALIDARG;
2617 OSSpinLockLock(&This->lock);
2619 for(i = 0; i < count; ++i)
2620 This->vols[i] = levels[i];
2622 ret = ca_setvol(This, -1);
2624 OSSpinLockUnlock(&This->lock);
2626 return ret;
2629 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2630 IAudioStreamVolume *iface, UINT32 count, float *levels)
2632 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2633 int i;
2635 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2637 if(!levels)
2638 return E_POINTER;
2640 if(count != This->fmt->nChannels)
2641 return E_INVALIDARG;
2643 OSSpinLockLock(&This->lock);
2645 for(i = 0; i < count; ++i)
2646 levels[i] = This->vols[i];
2648 OSSpinLockUnlock(&This->lock);
2650 return S_OK;
2653 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2655 AudioStreamVolume_QueryInterface,
2656 AudioStreamVolume_AddRef,
2657 AudioStreamVolume_Release,
2658 AudioStreamVolume_GetChannelCount,
2659 AudioStreamVolume_SetChannelVolume,
2660 AudioStreamVolume_GetChannelVolume,
2661 AudioStreamVolume_SetAllVolumes,
2662 AudioStreamVolume_GetAllVolumes
2665 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2666 IChannelAudioVolume *iface, REFIID riid, void **ppv)
2668 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2670 if(!ppv)
2671 return E_POINTER;
2672 *ppv = NULL;
2674 if(IsEqualIID(riid, &IID_IUnknown) ||
2675 IsEqualIID(riid, &IID_IChannelAudioVolume))
2676 *ppv = iface;
2677 if(*ppv){
2678 IUnknown_AddRef((IUnknown*)*ppv);
2679 return S_OK;
2682 WARN("Unknown interface %s\n", debugstr_guid(riid));
2683 return E_NOINTERFACE;
2686 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2688 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2689 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2692 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2694 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2695 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2698 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2699 IChannelAudioVolume *iface, UINT32 *out)
2701 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2702 AudioSession *session = This->session;
2704 TRACE("(%p)->(%p)\n", session, out);
2706 if(!out)
2707 return NULL_PTR_ERR;
2709 *out = session->channel_count;
2711 return S_OK;
2714 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2715 IChannelAudioVolume *iface, UINT32 index, float level,
2716 const GUID *context)
2718 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2719 AudioSession *session = This->session;
2720 HRESULT ret;
2722 TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2723 wine_dbgstr_guid(context));
2725 if(level < 0.f || level > 1.f)
2726 return E_INVALIDARG;
2728 if(index >= session->channel_count)
2729 return E_INVALIDARG;
2731 if(context)
2732 FIXME("Notifications not supported yet\n");
2734 EnterCriticalSection(&session->lock);
2736 session->channel_vols[index] = level;
2738 WARN("AudioQueue doesn't support per-channel volume control\n");
2739 ret = ca_session_setvol(session, index);
2741 LeaveCriticalSection(&session->lock);
2743 return ret;
2746 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2747 IChannelAudioVolume *iface, UINT32 index, float *level)
2749 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2750 AudioSession *session = This->session;
2752 TRACE("(%p)->(%d, %p)\n", session, index, level);
2754 if(!level)
2755 return NULL_PTR_ERR;
2757 if(index >= session->channel_count)
2758 return E_INVALIDARG;
2760 *level = session->channel_vols[index];
2762 return S_OK;
2765 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2766 IChannelAudioVolume *iface, UINT32 count, const float *levels,
2767 const GUID *context)
2769 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2770 AudioSession *session = This->session;
2771 int i;
2772 HRESULT ret;
2774 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2775 wine_dbgstr_guid(context));
2777 if(!levels)
2778 return NULL_PTR_ERR;
2780 if(count != session->channel_count)
2781 return E_INVALIDARG;
2783 if(context)
2784 FIXME("Notifications not supported yet\n");
2786 EnterCriticalSection(&session->lock);
2788 for(i = 0; i < count; ++i)
2789 session->channel_vols[i] = levels[i];
2791 ret = ca_session_setvol(session, -1);
2793 LeaveCriticalSection(&session->lock);
2795 return ret;
2798 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2799 IChannelAudioVolume *iface, UINT32 count, float *levels)
2801 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2802 AudioSession *session = This->session;
2803 int i;
2805 TRACE("(%p)->(%d, %p)\n", session, count, levels);
2807 if(!levels)
2808 return NULL_PTR_ERR;
2810 if(count != session->channel_count)
2811 return E_INVALIDARG;
2813 for(i = 0; i < count; ++i)
2814 levels[i] = session->channel_vols[i];
2816 return S_OK;
2819 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2821 ChannelAudioVolume_QueryInterface,
2822 ChannelAudioVolume_AddRef,
2823 ChannelAudioVolume_Release,
2824 ChannelAudioVolume_GetChannelCount,
2825 ChannelAudioVolume_SetChannelVolume,
2826 ChannelAudioVolume_GetChannelVolume,
2827 ChannelAudioVolume_SetAllVolumes,
2828 ChannelAudioVolume_GetAllVolumes
2831 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2832 REFIID riid, void **ppv)
2834 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2836 if(!ppv)
2837 return E_POINTER;
2838 *ppv = NULL;
2840 if(IsEqualIID(riid, &IID_IUnknown) ||
2841 IsEqualIID(riid, &IID_IAudioSessionManager) ||
2842 IsEqualIID(riid, &IID_IAudioSessionManager2))
2843 *ppv = iface;
2844 if(*ppv){
2845 IUnknown_AddRef((IUnknown*)*ppv);
2846 return S_OK;
2849 WARN("Unknown interface %s\n", debugstr_guid(riid));
2850 return E_NOINTERFACE;
2853 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2855 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2856 ULONG ref;
2857 ref = InterlockedIncrement(&This->ref);
2858 TRACE("(%p) Refcount now %u\n", This, ref);
2859 return ref;
2862 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2864 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2865 ULONG ref;
2866 ref = InterlockedDecrement(&This->ref);
2867 TRACE("(%p) Refcount now %u\n", This, ref);
2868 if(!ref)
2869 HeapFree(GetProcessHeap(), 0, This);
2870 return ref;
2873 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2874 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2875 IAudioSessionControl **out)
2877 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2878 AudioSession *session;
2879 AudioSessionWrapper *wrapper;
2880 HRESULT hr;
2882 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2883 flags, out);
2885 hr = get_audio_session(session_guid, This->device, 0, &session);
2886 if(FAILED(hr))
2887 return hr;
2889 wrapper = AudioSessionWrapper_Create(NULL);
2890 if(!wrapper)
2891 return E_OUTOFMEMORY;
2893 wrapper->session = session;
2895 *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
2897 return S_OK;
2900 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
2901 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2902 ISimpleAudioVolume **out)
2904 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2905 AudioSession *session;
2906 AudioSessionWrapper *wrapper;
2907 HRESULT hr;
2909 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2910 flags, out);
2912 hr = get_audio_session(session_guid, This->device, 0, &session);
2913 if(FAILED(hr))
2914 return hr;
2916 wrapper = AudioSessionWrapper_Create(NULL);
2917 if(!wrapper)
2918 return E_OUTOFMEMORY;
2920 wrapper->session = session;
2922 *out = &wrapper->ISimpleAudioVolume_iface;
2924 return S_OK;
2927 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
2928 IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
2930 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2931 FIXME("(%p)->(%p) - stub\n", This, out);
2932 return E_NOTIMPL;
2935 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
2936 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2938 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2939 FIXME("(%p)->(%p) - stub\n", This, notification);
2940 return E_NOTIMPL;
2943 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
2944 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2946 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2947 FIXME("(%p)->(%p) - stub\n", This, notification);
2948 return E_NOTIMPL;
2951 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
2952 IAudioSessionManager2 *iface, const WCHAR *session_id,
2953 IAudioVolumeDuckNotification *notification)
2955 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2956 FIXME("(%p)->(%p) - stub\n", This, notification);
2957 return E_NOTIMPL;
2960 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
2961 IAudioSessionManager2 *iface,
2962 IAudioVolumeDuckNotification *notification)
2964 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2965 FIXME("(%p)->(%p) - stub\n", This, notification);
2966 return E_NOTIMPL;
2969 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
2971 AudioSessionManager_QueryInterface,
2972 AudioSessionManager_AddRef,
2973 AudioSessionManager_Release,
2974 AudioSessionManager_GetAudioSessionControl,
2975 AudioSessionManager_GetSimpleAudioVolume,
2976 AudioSessionManager_GetSessionEnumerator,
2977 AudioSessionManager_RegisterSessionNotification,
2978 AudioSessionManager_UnregisterSessionNotification,
2979 AudioSessionManager_RegisterDuckNotification,
2980 AudioSessionManager_UnregisterDuckNotification
2983 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
2984 IAudioSessionManager2 **out)
2986 SessionMgr *This;
2988 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
2989 if(!This)
2990 return E_OUTOFMEMORY;
2992 This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
2993 This->device = device;
2994 This->ref = 1;
2996 *out = &This->IAudioSessionManager2_iface;
2998 return S_OK;