winecoreaudio.drv: Make AudioSessionManager methods static.
[wine] / dlls / winecoreaudio.drv / mmdevdrv.c
1 /*
2  * Copyright 2011 Andrew Eikum for CodeWeavers
3  *
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.
8  *
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.
13  *
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
17  */
18
19 #define NONAMELESSUNION
20 #define COBJMACROS
21 #include "config.h"
22
23 #include <stdarg.h>
24
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"
32
33 #include "ole2.h"
34 #include "mmdeviceapi.h"
35 #include "devpkey.h"
36 #include "dshow.h"
37 #include "dsound.h"
38 #include "endpointvolume.h"
39
40 #include "initguid.h"
41 #include "audioclient.h"
42 #include "audiopolicy.h"
43
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>
54
55 #include <libkern/OSAtomic.h>
56 #include <CoreAudio/CoreAudio.h>
57 #include <AudioToolbox/AudioQueue.h>
58
59 WINE_DEFAULT_DEBUG_CHANNEL(coreaudio);
60
61 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
62
63 #define CAPTURE_BUFFERS 5
64
65 static const REFERENCE_TIME DefaultPeriod = 200000;
66 static const REFERENCE_TIME MinimumPeriod = 100000;
67
68 typedef struct _AQBuffer {
69     AudioQueueBufferRef buf;
70     struct list entry;
71 } AQBuffer;
72
73 struct ACImpl;
74 typedef struct ACImpl ACImpl;
75
76 typedef struct _AudioSession {
77     GUID guid;
78     struct list clients;
79
80     IMMDevice *device;
81
82     float master_vol;
83     UINT32 channel_count;
84     float *channel_vols;
85     BOOL mute;
86
87     CRITICAL_SECTION lock;
88
89     struct list entry;
90 } AudioSession;
91
92 typedef struct _AudioSessionWrapper {
93     IAudioSessionControl2 IAudioSessionControl2_iface;
94     IChannelAudioVolume IChannelAudioVolume_iface;
95     ISimpleAudioVolume ISimpleAudioVolume_iface;
96
97     LONG ref;
98
99     ACImpl *client;
100     AudioSession *session;
101 } AudioSessionWrapper;
102
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;
110
111     LONG ref;
112
113     IMMDevice *parent;
114
115     WAVEFORMATEX *fmt;
116
117     EDataFlow dataflow;
118     DWORD flags;
119     AUDCLNT_SHAREMODE share;
120     HANDLE event;
121     float *vols;
122
123     AudioDeviceID adevid;
124     AudioQueueRef aqueue;
125     AudioObjectPropertyScope scope;
126     HANDLE timer;
127     UINT32 period_ms, bufsize_frames, inbuf_frames, written_frames;
128     UINT64 last_time;
129     AudioQueueBufferRef public_buffer;
130     BOOL getbuf_last;
131     int playing;
132
133     AudioSession *session;
134     AudioSessionWrapper *session_wrapper;
135
136     struct list entry;
137
138     struct list avail_buffers;
139
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;
145 };
146
147 enum PlayingStates {
148     StateStopped = 0,
149     StatePlaying,
150     StateInTransition
151 };
152
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;
163
164 typedef struct _SessionMgr {
165     IAudioSessionManager2 IAudioSessionManager2_iface;
166
167     LONG ref;
168
169     IMMDevice *device;
170 } SessionMgr;
171
172 static HANDLE g_timer_q;
173
174 static CRITICAL_SECTION g_sessions_lock;
175 static struct list g_sessions = LIST_INIT(g_sessions);
176
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);
181
182 static inline ACImpl *impl_from_IAudioClient(IAudioClient *iface)
183 {
184     return CONTAINING_RECORD(iface, ACImpl, IAudioClient_iface);
185 }
186
187 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
188 {
189     return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
190 }
191
192 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
193 {
194     return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
195 }
196
197 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
198 {
199     return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
200 }
201
202 static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
203 {
204     return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
205 }
206
207 static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
208 {
209     return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
210 }
211
212 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
213 {
214     return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
215 }
216
217 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
218 {
219     return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
220 }
221
222 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
223 {
224     return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
225 }
226
227 static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface)
228 {
229     return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface);
230 }
231
232 BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
233 {
234     if(reason == DLL_PROCESS_ATTACH){
235         g_timer_q = CreateTimerQueue();
236         if(!g_timer_q)
237             return FALSE;
238
239         InitializeCriticalSection(&g_sessions_lock);
240     }
241
242     return TRUE;
243 }
244
245 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids,
246         AudioDeviceID ***keys, UINT *num, UINT *def_index)
247 {
248     UInt32 devsize, size;
249     AudioDeviceID *devices;
250     AudioDeviceID default_id;
251     AudioObjectPropertyAddress addr;
252     OSStatus sc;
253     int i, ndevices;
254
255     TRACE("%d %p %p %p\n", flow, ids, num, def_index);
256
257     addr.mScope = kAudioObjectPropertyScopeGlobal;
258     addr.mElement = kAudioObjectPropertyElementMaster;
259     if(flow == eRender)
260         addr.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
261     else if(flow == eCapture)
262         addr.mSelector = kAudioHardwarePropertyDefaultInputDevice;
263     else
264         return E_INVALIDARG;
265
266     size = sizeof(default_id);
267     sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0,
268             NULL, &size, &default_id);
269     if(sc != noErr){
270         WARN("Getting _DefaultInputDevice property failed: %lx\n", sc);
271         default_id = -1;
272     }
273
274     addr.mSelector = kAudioHardwarePropertyDevices;
275     sc = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &addr, 0,
276             NULL, &devsize);
277     if(sc != noErr){
278         WARN("Getting _Devices property size failed: %lx\n", sc);
279         return E_FAIL;
280     }
281
282     devices = HeapAlloc(GetProcessHeap(), 0, devsize);
283     if(!devices)
284         return E_OUTOFMEMORY;
285
286     sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0, NULL,
287             &devsize, devices);
288     if(sc != noErr){
289         WARN("Getting _Devices property failed: %lx\n", sc);
290         HeapFree(GetProcessHeap(), 0, devices);
291         return E_FAIL;
292     }
293
294     ndevices = devsize / sizeof(AudioDeviceID);
295
296     *ids = HeapAlloc(GetProcessHeap(), 0, ndevices * sizeof(WCHAR *));
297     if(!*ids){
298         HeapFree(GetProcessHeap(), 0, devices);
299         return E_OUTOFMEMORY;
300     }
301
302     *keys = HeapAlloc(GetProcessHeap(), 0, ndevices * sizeof(AudioDeviceID *));
303     if(!*ids){
304         HeapFree(GetProcessHeap(), 0, *ids);
305         HeapFree(GetProcessHeap(), 0, devices);
306         return E_OUTOFMEMORY;
307     }
308
309     *num = 0;
310     *def_index = (UINT)-1;
311     for(i = 0; i < ndevices; ++i){
312         AudioBufferList *buffers;
313         CFStringRef name;
314         SIZE_T len;
315         char nameA[256];
316         int j;
317
318         addr.mSelector = kAudioDevicePropertyStreamConfiguration;
319         if(flow == eRender)
320             addr.mScope = kAudioDevicePropertyScopeOutput;
321         else
322             addr.mScope = kAudioDevicePropertyScopeInput;
323         addr.mElement = 0;
324         sc = AudioObjectGetPropertyDataSize(devices[i], &addr, 0, NULL, &size);
325         if(sc != noErr){
326             WARN("Unable to get _StreamConfiguration property size for "
327                     "device %lu: %lx\n", devices[i], sc);
328             continue;
329         }
330
331         buffers = HeapAlloc(GetProcessHeap(), 0, size);
332         if(!buffers){
333             HeapFree(GetProcessHeap(), 0, devices);
334             for(j = 0; j < *num; ++j)
335                 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
336             HeapFree(GetProcessHeap(), 0, *keys);
337             HeapFree(GetProcessHeap(), 0, *ids);
338             return E_OUTOFMEMORY;
339         }
340
341         sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL,
342                 &size, buffers);
343         if(sc != noErr){
344             WARN("Unable to get _StreamConfiguration property for "
345                     "device %lu: %lx\n", devices[i], sc);
346             HeapFree(GetProcessHeap(), 0, buffers);
347             continue;
348         }
349
350         /* check that there's at least one channel in this device before
351          * we claim it as usable */
352         for(j = 0; j < buffers->mNumberBuffers; ++j)
353             if(buffers->mBuffers[j].mNumberChannels > 0)
354                 break;
355         if(j >= buffers->mNumberBuffers){
356             HeapFree(GetProcessHeap(), 0, buffers);
357             continue;
358         }
359
360         HeapFree(GetProcessHeap(), 0, buffers);
361
362         size = sizeof(name);
363         addr.mSelector = kAudioObjectPropertyName;
364         sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL,
365                 &size, &name);
366         if(sc != noErr){
367             WARN("Unable to get _Name property for device %lu: %lx\n",
368                     devices[i], sc);
369             continue;
370         }
371
372         if(!CFStringGetCString(name, nameA, sizeof(nameA),
373                     kCFStringEncodingUTF8)){
374             WARN("Error converting string to UTF8\n");
375             CFRelease(name);
376             continue;
377         }
378
379         CFRelease(name);
380
381         len = MultiByteToWideChar(CP_UNIXCP, 0, nameA, -1, NULL, 0);
382         (*ids)[*num] = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
383         if(!(*ids)[*num]){
384             HeapFree(GetProcessHeap(), 0, devices);
385             for(j = 0; j < *num; ++j){
386                 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
387                 HeapFree(GetProcessHeap(), 0, (*keys)[j]);
388             }
389             HeapFree(GetProcessHeap(), 0, *ids);
390             HeapFree(GetProcessHeap(), 0, *keys);
391             return E_OUTOFMEMORY;
392         }
393         MultiByteToWideChar(CP_UNIXCP, 0, nameA, -1, (*ids)[*num], len);
394
395         (*keys)[*num] = HeapAlloc(GetProcessHeap(), 0, sizeof(AudioDeviceID));
396         if(!(*ids)[*num]){
397             HeapFree(GetProcessHeap(), 0, devices);
398             HeapFree(GetProcessHeap(), 0, (*ids)[*num]);
399             for(j = 0; j < *num; ++j){
400                 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
401                 HeapFree(GetProcessHeap(), 0, (*keys)[j]);
402             }
403             HeapFree(GetProcessHeap(), 0, *ids);
404             HeapFree(GetProcessHeap(), 0, *keys);
405             return E_OUTOFMEMORY;
406         }
407         *(*keys)[*num] = devices[i];
408
409         if(*def_index == (UINT)-1 && devices[i] == default_id)
410             *def_index = *num;
411
412         (*num)++;
413     }
414
415     if(*def_index == (UINT)-1)
416         *def_index = 0;
417
418     HeapFree(GetProcessHeap(), 0, devices);
419
420     return S_OK;
421 }
422
423 HRESULT WINAPI AUDDRV_GetAudioEndpoint(AudioDeviceID *adevid, IMMDevice *dev,
424         EDataFlow dataflow, IAudioClient **out)
425 {
426     ACImpl *This;
427
428     TRACE("%p %d %p\n", dev, dataflow, out);
429
430     This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACImpl));
431     if(!This)
432         return E_OUTOFMEMORY;
433
434     This->IAudioClient_iface.lpVtbl = &AudioClient_Vtbl;
435     This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
436     This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
437     This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
438     This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
439     This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
440
441     This->dataflow = dataflow;
442
443     if(dataflow == eRender)
444         This->scope = kAudioDevicePropertyScopeOutput;
445     else if(dataflow == eCapture)
446         This->scope = kAudioDevicePropertyScopeInput;
447     else{
448         HeapFree(GetProcessHeap(), 0, This);
449         return E_INVALIDARG;
450     }
451
452     This->lock = 0;
453
454     This->parent = dev;
455     IMMDevice_AddRef(This->parent);
456
457     list_init(&This->avail_buffers);
458
459     This->adevid = *adevid;
460
461     *out = &This->IAudioClient_iface;
462     IAudioClient_AddRef(&This->IAudioClient_iface);
463
464     return S_OK;
465 }
466
467 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient *iface,
468         REFIID riid, void **ppv)
469 {
470     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
471
472     if(!ppv)
473         return E_POINTER;
474     *ppv = NULL;
475     if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClient))
476         *ppv = iface;
477     if(*ppv){
478         IUnknown_AddRef((IUnknown*)*ppv);
479         return S_OK;
480     }
481     WARN("Unknown interface %s\n", debugstr_guid(riid));
482     return E_NOINTERFACE;
483 }
484
485 static ULONG WINAPI AudioClient_AddRef(IAudioClient *iface)
486 {
487     ACImpl *This = impl_from_IAudioClient(iface);
488     ULONG ref;
489     ref = InterlockedIncrement(&This->ref);
490     TRACE("(%p) Refcount now %u\n", This, ref);
491     return ref;
492 }
493
494 static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
495 {
496     ACImpl *This = impl_from_IAudioClient(iface);
497     ULONG ref;
498     ref = InterlockedDecrement(&This->ref);
499     TRACE("(%p) Refcount now %u\n", This, ref);
500     if(!ref){
501         IAudioClient_Stop(iface);
502         if(This->aqueue)
503             AudioQueueDispose(This->aqueue, 1);
504         if(This->session){
505             EnterCriticalSection(&g_sessions_lock);
506             list_remove(&This->entry);
507             LeaveCriticalSection(&g_sessions_lock);
508         }
509         HeapFree(GetProcessHeap(), 0, This->vols);
510         HeapFree(GetProcessHeap(), 0, This->public_buffer);
511         CoTaskMemFree(This->fmt);
512         IMMDevice_Release(This->parent);
513         HeapFree(GetProcessHeap(), 0, This);
514     }
515     return ref;
516 }
517
518 static void dump_fmt(const WAVEFORMATEX *fmt)
519 {
520     TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
521     switch(fmt->wFormatTag){
522     case WAVE_FORMAT_PCM:
523         TRACE("WAVE_FORMAT_PCM");
524         break;
525     case WAVE_FORMAT_IEEE_FLOAT:
526         TRACE("WAVE_FORMAT_IEEE_FLOAT");
527         break;
528     case WAVE_FORMAT_EXTENSIBLE:
529         TRACE("WAVE_FORMAT_EXTENSIBLE");
530         break;
531     default:
532         TRACE("Unknown");
533         break;
534     }
535     TRACE(")\n");
536
537     TRACE("nChannels: %u\n", fmt->nChannels);
538     TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
539     TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
540     TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
541     TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
542     TRACE("cbSize: %u\n", fmt->cbSize);
543
544     if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
545         WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
546         TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
547         TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
548         TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
549     }
550 }
551
552 static DWORD get_channel_mask(unsigned int channels)
553 {
554     switch(channels){
555     case 0:
556         return 0;
557     case 1:
558         return SPEAKER_FRONT_CENTER;
559     case 2:
560         return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
561     case 3:
562         return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT |
563             SPEAKER_LOW_FREQUENCY;
564     case 4:
565         return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
566             SPEAKER_BACK_RIGHT;
567     case 5:
568         return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
569             SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY;
570     case 6:
571         return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
572             SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER;
573     case 7:
574         return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
575             SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER |
576             SPEAKER_BACK_CENTER;
577     }
578     FIXME("Unknown speaker configuration: %u\n", channels);
579     return 0;
580 }
581
582 static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
583 {
584     WAVEFORMATEX *ret;
585     size_t size;
586
587     if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
588         size = sizeof(WAVEFORMATEXTENSIBLE);
589     else
590         size = sizeof(WAVEFORMATEX);
591
592     ret = CoTaskMemAlloc(size);
593     if(!ret)
594         return NULL;
595
596     memcpy(ret, fmt, size);
597
598     ret->cbSize = size - sizeof(WAVEFORMATEX);
599
600     return ret;
601 }
602
603 static HRESULT ca_get_audiodesc(AudioStreamBasicDescription *desc,
604         const WAVEFORMATEX *fmt)
605 {
606     const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)fmt;
607
608     desc->mFormatFlags = 0;
609
610     if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
611             (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
612              IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
613         desc->mFormatID = kAudioFormatLinearPCM;
614         if(fmt->wBitsPerSample > 8)
615             desc->mFormatFlags = kAudioFormatFlagIsSignedInteger;
616     }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
617             (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
618              IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
619         desc->mFormatID = kAudioFormatLinearPCM;
620         desc->mFormatFlags = kAudioFormatFlagIsFloat;
621     }else if(fmt->wFormatTag == WAVE_FORMAT_MULAW ||
622             (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
623              IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_MULAW))){
624         desc->mFormatID = kAudioFormatULaw;
625     }else if(fmt->wFormatTag == WAVE_FORMAT_ALAW ||
626             (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
627              IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_ALAW))){
628         desc->mFormatID = kAudioFormatALaw;
629     }else
630         return AUDCLNT_E_UNSUPPORTED_FORMAT;
631
632     desc->mSampleRate = fmt->nSamplesPerSec;
633     desc->mBytesPerPacket = fmt->nBlockAlign;
634     desc->mFramesPerPacket = 1;
635     desc->mBytesPerFrame = fmt->nBlockAlign;
636     desc->mChannelsPerFrame = fmt->nChannels;
637     desc->mBitsPerChannel = fmt->wBitsPerSample;
638     desc->mReserved = 0;
639
640     return S_OK;
641 }
642
643 static void ca_out_buffer_cb(void *user, AudioQueueRef aqueue,
644         AudioQueueBufferRef buffer)
645 {
646     ACImpl *This = user;
647     AQBuffer *buf = buffer->mUserData;
648
649     OSSpinLockLock(&This->lock);
650     list_add_tail(&This->avail_buffers, &buf->entry);
651     This->inbuf_frames -= buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
652     OSSpinLockUnlock(&This->lock);
653 }
654
655 static void ca_in_buffer_cb(void *user, AudioQueueRef aqueue,
656         AudioQueueBufferRef buffer, const AudioTimeStamp *start,
657         UInt32 ndesc, const AudioStreamPacketDescription *descs)
658 {
659     ACImpl *This = user;
660     AQBuffer *buf = buffer->mUserData;
661
662     OSSpinLockLock(&This->lock);
663     list_add_tail(&This->avail_buffers, &buf->entry);
664     This->inbuf_frames += buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
665     OSSpinLockUnlock(&This->lock);
666 }
667
668 static HRESULT ca_setup_aqueue(AudioDeviceID did, EDataFlow flow,
669         const WAVEFORMATEX *fmt, void *user, AudioQueueRef *aqueue)
670 {
671     AudioStreamBasicDescription desc;
672     AudioObjectPropertyAddress addr;
673     CFStringRef uid;
674     OSStatus sc;
675     HRESULT hr;
676     UInt32 size;
677
678     addr.mScope = kAudioObjectPropertyScopeGlobal;
679     addr.mElement = 0;
680     addr.mSelector = kAudioDevicePropertyDeviceUID;
681
682     size = sizeof(uid);
683     sc = AudioObjectGetPropertyData(did, &addr, 0, NULL, &size, &uid);
684     if(sc != noErr){
685         WARN("Unable to get _DeviceUID property: %lx\n", sc);
686         return E_FAIL;
687     }
688
689     hr = ca_get_audiodesc(&desc, fmt);
690     if(FAILED(hr)){
691         CFRelease(uid);
692         return hr;
693     }
694
695     if(flow == eRender)
696         sc = AudioQueueNewOutput(&desc, ca_out_buffer_cb, user, NULL, NULL, 0,
697                 aqueue);
698     else if(flow == eCapture)
699         sc = AudioQueueNewInput(&desc, ca_in_buffer_cb, user, NULL, NULL, 0,
700                 aqueue);
701     else{
702         CFRelease(uid);
703         return E_UNEXPECTED;
704     }
705     if(sc != noErr){
706         WARN("Unable to create AudioQueue: %lx\n", sc);
707         CFRelease(uid);
708         return E_FAIL;
709     }
710
711     sc = AudioQueueSetProperty(*aqueue, kAudioQueueProperty_CurrentDevice,
712             &uid, sizeof(uid));
713     if(sc != noErr){
714         CFRelease(uid);
715         return E_FAIL;
716     }
717
718     CFRelease(uid);
719
720     return S_OK;
721 }
722
723 static void session_init_vols(AudioSession *session, UINT channels)
724 {
725     if(session->channel_count < channels){
726         UINT i;
727
728         if(session->channel_vols)
729             session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
730                     session->channel_vols, sizeof(float) * channels);
731         else
732             session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
733                     sizeof(float) * channels);
734         if(!session->channel_vols)
735             return;
736
737         for(i = session->channel_count; i < channels; ++i)
738             session->channel_vols[i] = 1.f;
739
740         session->channel_count = channels;
741     }
742 }
743
744 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
745         UINT num_channels)
746 {
747     AudioSession *ret;
748
749     ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
750     if(!ret)
751         return NULL;
752
753     memcpy(&ret->guid, guid, sizeof(GUID));
754
755     ret->device = device;
756
757     list_init(&ret->clients);
758
759     list_add_head(&g_sessions, &ret->entry);
760
761     InitializeCriticalSection(&ret->lock);
762
763     session_init_vols(ret, num_channels);
764
765     ret->master_vol = 1.f;
766
767     return ret;
768 }
769
770 /* if channels == 0, then this will return or create a session with
771  * matching dataflow and GUID. otherwise, channels must also match */
772 static HRESULT get_audio_session(const GUID *sessionguid,
773         IMMDevice *device, UINT channels, AudioSession **out)
774 {
775     AudioSession *session;
776
777     if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
778         *out = create_session(&GUID_NULL, device, channels);
779         if(!*out)
780             return E_OUTOFMEMORY;
781
782         return S_OK;
783     }
784
785     *out = NULL;
786     LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
787         if(session->device == device &&
788                 IsEqualGUID(sessionguid, &session->guid)){
789             session_init_vols(session, channels);
790             *out = session;
791             break;
792         }
793     }
794
795     if(!*out){
796         *out = create_session(sessionguid, device, channels);
797         if(!*out)
798             return E_OUTOFMEMORY;
799     }
800
801     return S_OK;
802 }
803
804 static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
805         AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
806         REFERENCE_TIME period, const WAVEFORMATEX *fmt,
807         const GUID *sessionguid)
808 {
809     ACImpl *This = impl_from_IAudioClient(iface);
810     HRESULT hr;
811     OSStatus sc;
812     int i;
813
814     TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
815           wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
816
817     if(!fmt)
818         return E_POINTER;
819
820     dump_fmt(fmt);
821
822     if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
823         return AUDCLNT_E_NOT_INITIALIZED;
824
825     if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
826                 AUDCLNT_STREAMFLAGS_LOOPBACK |
827                 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
828                 AUDCLNT_STREAMFLAGS_NOPERSIST |
829                 AUDCLNT_STREAMFLAGS_RATEADJUST |
830                 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
831                 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
832                 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED)){
833         TRACE("Unknown flags: %08x\n", flags);
834         return E_INVALIDARG;
835     }
836
837     OSSpinLockLock(&This->lock);
838
839     if(This->aqueue){
840         OSSpinLockUnlock(&This->lock);
841         return AUDCLNT_E_ALREADY_INITIALIZED;
842     }
843
844     hr = ca_setup_aqueue(This->adevid, This->dataflow, fmt, This, &This->aqueue);
845     if(FAILED(hr)){
846         OSSpinLockUnlock(&This->lock);
847         return hr;
848     }
849
850     This->fmt = clone_format(fmt);
851     if(!This->fmt){
852         AudioQueueDispose(This->aqueue, 1);
853         This->aqueue = NULL;
854         OSSpinLockUnlock(&This->lock);
855         return E_OUTOFMEMORY;
856     }
857
858     if(period){
859         This->period_ms = period / 10000;
860         if(This->period_ms == 0)
861             This->period_ms = 1;
862     }else
863         This->period_ms = MinimumPeriod / 10000;
864
865     This->bufsize_frames = ceil(fmt->nSamplesPerSec * (duration / 10000000.));
866
867     if(This->dataflow == eCapture){
868         int i;
869         UInt32 bsize = ceil((This->bufsize_frames / (double)CAPTURE_BUFFERS) *
870                 This->fmt->nBlockAlign);
871         for(i = 0; i < CAPTURE_BUFFERS; ++i){
872             AQBuffer *buf;
873
874             buf = HeapAlloc(GetProcessHeap(), 0, sizeof(AQBuffer));
875             if(!buf){
876                 AudioQueueDispose(This->aqueue, 1);
877                 This->aqueue = NULL;
878                 CoTaskMemFree(This->fmt);
879                 This->fmt = NULL;
880                 OSSpinLockUnlock(&This->lock);
881                 return E_OUTOFMEMORY;
882             }
883
884             sc = AudioQueueAllocateBuffer(This->aqueue, bsize, &buf->buf);
885             if(sc != noErr){
886                 AudioQueueDispose(This->aqueue, 1);
887                 This->aqueue = NULL;
888                 CoTaskMemFree(This->fmt);
889                 This->fmt = NULL;
890                 OSSpinLockUnlock(&This->lock);
891                 WARN("Couldn't allocate buffer: %lx\n", sc);
892                 return E_FAIL;
893             }
894
895             buf->buf->mUserData = buf;
896
897             sc = AudioQueueEnqueueBuffer(This->aqueue, buf->buf, 0, NULL);
898             if(sc != noErr){
899                 ERR("Couldn't enqueue buffer: %lx\n", sc);
900                 break;
901             }
902         }
903     }
904
905     This->vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float));
906     if(!This->vols){
907         AudioQueueDispose(This->aqueue, 1);
908         This->aqueue = NULL;
909         CoTaskMemFree(This->fmt);
910         This->fmt = NULL;
911         OSSpinLockUnlock(&This->lock);
912         return E_OUTOFMEMORY;
913     }
914
915     for(i = 0; i < fmt->nChannels; ++i)
916         This->vols[i] = 1.f;
917
918     This->share = mode;
919     This->flags = flags;
920
921     EnterCriticalSection(&g_sessions_lock);
922
923     hr = get_audio_session(sessionguid, This->parent, fmt->nChannels,
924             &This->session);
925     if(FAILED(hr)){
926         LeaveCriticalSection(&g_sessions_lock);
927         AudioQueueDispose(This->aqueue, 1);
928         This->aqueue = NULL;
929         CoTaskMemFree(This->fmt);
930         This->fmt = NULL;
931         HeapFree(GetProcessHeap(), 0, This->vols);
932         This->vols = NULL;
933         OSSpinLockUnlock(&This->lock);
934         return E_INVALIDARG;
935     }
936
937     list_add_tail(&This->session->clients, &This->entry);
938
939     LeaveCriticalSection(&g_sessions_lock);
940
941     ca_setvol(This, -1);
942
943     OSSpinLockUnlock(&This->lock);
944
945     return S_OK;
946 }
947
948 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
949         UINT32 *frames)
950 {
951     ACImpl *This = impl_from_IAudioClient(iface);
952
953     TRACE("(%p)->(%p)\n", This, frames);
954
955     if(!frames)
956         return E_POINTER;
957
958     OSSpinLockLock(&This->lock);
959
960     if(!This->aqueue){
961         OSSpinLockUnlock(&This->lock);
962         return AUDCLNT_E_NOT_INITIALIZED;
963     }
964
965     *frames = This->bufsize_frames;
966
967     OSSpinLockUnlock(&This->lock);
968
969     return S_OK;
970 }
971
972 static HRESULT ca_get_max_stream_latency(ACImpl *This, UInt32 *max)
973 {
974     AudioObjectPropertyAddress addr;
975     AudioStreamID *ids;
976     UInt32 size;
977     OSStatus sc;
978     int nstreams, i;
979
980     addr.mScope = This->scope;
981     addr.mElement = 0;
982     addr.mSelector = kAudioDevicePropertyStreams;
983
984     sc = AudioObjectGetPropertyDataSize(This->adevid, &addr, 0, NULL,
985             &size);
986     if(sc != noErr){
987         WARN("Unable to get size for _Streams property: %lx\n", sc);
988         return E_FAIL;
989     }
990
991     ids = HeapAlloc(GetProcessHeap(), 0, size);
992     if(!ids)
993         return E_OUTOFMEMORY;
994
995     sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL, &size, ids);
996     if(sc != noErr){
997         WARN("Unable to get _Streams property: %lx\n", sc);
998         HeapFree(GetProcessHeap(), 0, ids);
999         return E_FAIL;
1000     }
1001
1002     nstreams = size / sizeof(AudioStreamID);
1003     *max = 0;
1004
1005     addr.mSelector = kAudioStreamPropertyLatency;
1006     for(i = 0; i < nstreams; ++i){
1007         UInt32 latency;
1008
1009         size = sizeof(latency);
1010         sc = AudioObjectGetPropertyData(ids[i], &addr, 0, NULL,
1011                 &size, &latency);
1012         if(sc != noErr){
1013             WARN("Unable to get _Latency property: %lx\n", sc);
1014             continue;
1015         }
1016
1017         if(latency > *max)
1018             *max = latency;
1019     }
1020
1021     HeapFree(GetProcessHeap(), 0, ids);
1022
1023     return S_OK;
1024 }
1025
1026 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
1027         REFERENCE_TIME *out)
1028 {
1029     ACImpl *This = impl_from_IAudioClient(iface);
1030     UInt32 latency, stream_latency, size;
1031     AudioObjectPropertyAddress addr;
1032     OSStatus sc;
1033     HRESULT hr;
1034
1035     TRACE("(%p)->(%p)\n", This, out);
1036
1037     if(!out)
1038         return E_POINTER;
1039
1040     OSSpinLockLock(&This->lock);
1041
1042     if(!This->aqueue){
1043         OSSpinLockUnlock(&This->lock);
1044         return AUDCLNT_E_NOT_INITIALIZED;
1045     }
1046
1047     addr.mScope = This->scope;
1048     addr.mSelector = kAudioDevicePropertyLatency;
1049     addr.mElement = 0;
1050
1051     size = sizeof(latency);
1052     sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL,
1053             &size, &latency);
1054     if(sc != noErr){
1055         WARN("Couldn't get _Latency property: %lx\n", sc);
1056         OSSpinLockUnlock(&This->lock);
1057         return E_FAIL;
1058     }
1059
1060     hr = ca_get_max_stream_latency(This, &stream_latency);
1061     if(FAILED(hr)){
1062         OSSpinLockUnlock(&This->lock);
1063         return hr;
1064     }
1065
1066     latency += stream_latency;
1067     *out = (latency / (double)This->fmt->nSamplesPerSec) * 10000000;
1068
1069     OSSpinLockUnlock(&This->lock);
1070
1071     return S_OK;
1072 }
1073
1074 static HRESULT AudioClient_GetCurrentPadding_nolock(ACImpl *This,
1075         UINT32 *numpad)
1076 {
1077     if(!This->aqueue)
1078         return AUDCLNT_E_NOT_INITIALIZED;
1079
1080     *numpad = This->inbuf_frames;
1081
1082     return S_OK;
1083 }
1084
1085 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
1086         UINT32 *numpad)
1087 {
1088     ACImpl *This = impl_from_IAudioClient(iface);
1089     HRESULT hr;
1090
1091     TRACE("(%p)->(%p)\n", This, numpad);
1092
1093     if(!numpad)
1094         return E_POINTER;
1095
1096     OSSpinLockLock(&This->lock);
1097
1098     hr = AudioClient_GetCurrentPadding_nolock(This, numpad);
1099
1100     OSSpinLockUnlock(&This->lock);
1101
1102     return hr;
1103 }
1104
1105 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
1106         AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
1107         WAVEFORMATEX **outpwfx)
1108 {
1109     ACImpl *This = impl_from_IAudioClient(iface);
1110     AudioQueueRef aqueue;
1111     HRESULT hr;
1112
1113     TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx);
1114
1115     if(!pwfx || (mode == AUDCLNT_SHAREMODE_SHARED && !outpwfx))
1116         return E_POINTER;
1117
1118     if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1119         return E_INVALIDARG;
1120
1121     if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1122             pwfx->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1123         return E_INVALIDARG;
1124
1125     dump_fmt(pwfx);
1126
1127     OSSpinLockLock(&This->lock);
1128
1129     hr = ca_setup_aqueue(This->adevid, This->dataflow, pwfx, NULL, &aqueue);
1130     if(SUCCEEDED(hr)){
1131         AudioQueueDispose(aqueue, 1);
1132         OSSpinLockUnlock(&This->lock);
1133         if(outpwfx)
1134             *outpwfx = NULL;
1135         TRACE("returning %08x\n", S_OK);
1136         return S_OK;
1137     }
1138
1139     OSSpinLockUnlock(&This->lock);
1140
1141     if(outpwfx)
1142         *outpwfx = NULL;
1143
1144     TRACE("returning %08x\n", AUDCLNT_E_UNSUPPORTED_FORMAT);
1145     return AUDCLNT_E_UNSUPPORTED_FORMAT;
1146 }
1147
1148 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
1149         WAVEFORMATEX **pwfx)
1150 {
1151     ACImpl *This = impl_from_IAudioClient(iface);
1152     WAVEFORMATEXTENSIBLE *fmt;
1153     OSStatus sc;
1154     UInt32 size;
1155     Float64 rate;
1156     AudioBufferList *buffers;
1157     AudioObjectPropertyAddress addr;
1158     int i;
1159
1160     TRACE("(%p)->(%p)\n", This, pwfx);
1161
1162     if(!pwfx)
1163         return E_POINTER;
1164     *pwfx = NULL;
1165
1166     fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
1167     if(!fmt)
1168         return E_OUTOFMEMORY;
1169
1170     fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1171
1172     addr.mScope = This->scope;
1173     addr.mElement = 0;
1174     addr.mSelector = kAudioDevicePropertyStreamConfiguration;
1175
1176     sc = AudioObjectGetPropertyDataSize(This->adevid, &addr, 0, NULL, &size);
1177     if(sc != noErr){
1178         CoTaskMemFree(fmt);
1179         WARN("Unable to get size for _StreamConfiguration property: %lx\n", sc);
1180         return E_FAIL;
1181     }
1182
1183     buffers = HeapAlloc(GetProcessHeap(), 0, size);
1184     if(!buffers){
1185         CoTaskMemFree(fmt);
1186         return E_OUTOFMEMORY;
1187     }
1188
1189     sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL,
1190             &size, buffers);
1191     if(sc != noErr){
1192         CoTaskMemFree(fmt);
1193         HeapFree(GetProcessHeap(), 0, buffers);
1194         WARN("Unable to get _StreamConfiguration property: %lx\n", sc);
1195         return E_FAIL;
1196     }
1197
1198     fmt->Format.nChannels = 0;
1199     for(i = 0; i < buffers->mNumberBuffers; ++i)
1200         fmt->Format.nChannels += buffers->mBuffers[i].mNumberChannels;
1201
1202     HeapFree(GetProcessHeap(), 0, buffers);
1203
1204     fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
1205
1206     addr.mSelector = kAudioDevicePropertyNominalSampleRate;
1207     size = sizeof(Float64);
1208     sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL, &size, &rate);
1209     if(sc != noErr){
1210         CoTaskMemFree(fmt);
1211         WARN("Unable to get _NominalSampleRate property: %lx\n", sc);
1212         return E_FAIL;
1213     }
1214     fmt->Format.nSamplesPerSec = rate;
1215
1216     fmt->Format.wBitsPerSample = 32;
1217     fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
1218
1219     fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
1220             fmt->Format.nChannels) / 8;
1221     fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
1222         fmt->Format.nBlockAlign;
1223
1224     fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
1225     fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1226
1227     *pwfx = (WAVEFORMATEX*)fmt;
1228     dump_fmt(*pwfx);
1229
1230     return S_OK;
1231 }
1232
1233 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
1234         REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1235 {
1236     ACImpl *This = impl_from_IAudioClient(iface);
1237
1238     TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
1239
1240     if(!defperiod && !minperiod)
1241         return E_POINTER;
1242
1243     OSSpinLockLock(&This->lock);
1244
1245     if(This->period_ms){
1246         if(defperiod)
1247             *defperiod = This->period_ms * 10000;
1248         if(minperiod)
1249             *minperiod = This->period_ms * 10000;
1250     }else{
1251         if(defperiod)
1252             *defperiod = DefaultPeriod;
1253         if(minperiod)
1254             *minperiod = MinimumPeriod;
1255     }
1256
1257     OSSpinLockUnlock(&This->lock);
1258
1259     return S_OK;
1260 }
1261
1262 void CALLBACK ca_period_cb(void *user, BOOLEAN timer)
1263 {
1264     ACImpl *This = user;
1265
1266     OSSpinLockLock(&This->lock);
1267     if(This->event)
1268         SetEvent(This->event);
1269     OSSpinLockUnlock(&This->lock);
1270 }
1271
1272 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
1273 {
1274     ACImpl *This = impl_from_IAudioClient(iface);
1275     OSStatus sc;
1276
1277     TRACE("(%p)\n", This);
1278
1279     OSSpinLockLock(&This->lock);
1280
1281     if(!This->aqueue){
1282         OSSpinLockUnlock(&This->lock);
1283         return AUDCLNT_E_NOT_INITIALIZED;
1284     }
1285
1286     if(This->playing != StateStopped){
1287         OSSpinLockUnlock(&This->lock);
1288         return AUDCLNT_E_NOT_STOPPED;
1289     }
1290
1291     if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
1292         OSSpinLockUnlock(&This->lock);
1293         return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1294     }
1295
1296     if(This->event)
1297         if(!CreateTimerQueueTimer(&This->timer, g_timer_q,
1298                     ca_period_cb, This, 0, This->period_ms, 0))
1299             ERR("Unable to create timer: %u\n", GetLastError());
1300
1301     This->playing = StateInTransition;
1302
1303     OSSpinLockUnlock(&This->lock);
1304
1305     sc = AudioQueueStart(This->aqueue, NULL);
1306     if(sc != noErr){
1307         WARN("Unable to start audio queue: %lx\n", sc);
1308         return E_FAIL;
1309     }
1310
1311     OSSpinLockLock(&This->lock);
1312
1313     This->playing = StatePlaying;
1314
1315     OSSpinLockUnlock(&This->lock);
1316
1317     return S_OK;
1318 }
1319
1320 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
1321 {
1322     ACImpl *This = impl_from_IAudioClient(iface);
1323     OSStatus sc;
1324
1325     TRACE("(%p)\n", This);
1326
1327     OSSpinLockLock(&This->lock);
1328
1329     if(!This->aqueue){
1330         OSSpinLockUnlock(&This->lock);
1331         return AUDCLNT_E_NOT_INITIALIZED;
1332     }
1333
1334     if(This->playing == StateStopped){
1335         OSSpinLockUnlock(&This->lock);
1336         return S_FALSE;
1337     }
1338
1339     if(This->playing == StateInTransition){
1340         OSSpinLockUnlock(&This->lock);
1341         return S_OK;
1342     }
1343
1344     if(This->timer && This->timer != INVALID_HANDLE_VALUE){
1345         DeleteTimerQueueTimer(g_timer_q, This->timer, INVALID_HANDLE_VALUE);
1346         This->timer = NULL;
1347     }
1348
1349     This->playing = StateInTransition;
1350
1351     OSSpinLockUnlock(&This->lock);
1352
1353     sc = AudioQueueFlush(This->aqueue);
1354     if(sc != noErr)
1355         WARN("Unable to flush audio queue: %lx\n", sc);
1356
1357     sc = AudioQueuePause(This->aqueue);
1358     if(sc != noErr){
1359         WARN("Unable to pause audio queue: %lx\n", sc);
1360         return E_FAIL;
1361     }
1362
1363     OSSpinLockLock(&This->lock);
1364
1365     This->playing = StateStopped;
1366
1367     OSSpinLockUnlock(&This->lock);
1368
1369     return S_OK;
1370 }
1371
1372 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
1373 {
1374     ACImpl *This = impl_from_IAudioClient(iface);
1375     HRESULT hr;
1376     OSStatus sc;
1377
1378     TRACE("(%p)\n", This);
1379
1380     OSSpinLockLock(&This->lock);
1381
1382     if(!This->aqueue){
1383         OSSpinLockUnlock(&This->lock);
1384         return AUDCLNT_E_NOT_INITIALIZED;
1385     }
1386
1387     if(This->playing != StateStopped){
1388         OSSpinLockUnlock(&This->lock);
1389         return AUDCLNT_E_NOT_STOPPED;
1390     }
1391
1392     This->written_frames = 0;
1393
1394     hr = AudioClock_GetPosition_nolock(This, &This->last_time, NULL, TRUE);
1395     if(FAILED(hr)){
1396         OSSpinLockUnlock(&This->lock);
1397         return hr;
1398     }
1399
1400     OSSpinLockUnlock(&This->lock);
1401
1402     sc = AudioQueueReset(This->aqueue);
1403     if(sc != noErr){
1404         WARN("Unable to reset audio queue: %lx\n", sc);
1405         return E_FAIL;
1406     }
1407
1408     return S_OK;
1409 }
1410
1411 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1412         HANDLE event)
1413 {
1414     ACImpl *This = impl_from_IAudioClient(iface);
1415
1416     TRACE("(%p)->(%p)\n", This, event);
1417
1418     if(!event)
1419         return E_INVALIDARG;
1420
1421     OSSpinLockLock(&This->lock);
1422
1423     if(!This->aqueue){
1424         OSSpinLockUnlock(&This->lock);
1425         return AUDCLNT_E_NOT_INITIALIZED;
1426     }
1427
1428     if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
1429         OSSpinLockUnlock(&This->lock);
1430         return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1431     }
1432
1433     This->event = event;
1434
1435     OSSpinLockUnlock(&This->lock);
1436
1437     return S_OK;
1438 }
1439
1440 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1441         void **ppv)
1442 {
1443     ACImpl *This = impl_from_IAudioClient(iface);
1444
1445     TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1446
1447     if(!ppv)
1448         return E_POINTER;
1449     *ppv = NULL;
1450
1451     OSSpinLockLock(&This->lock);
1452
1453     if(!This->aqueue){
1454         OSSpinLockUnlock(&This->lock);
1455         return AUDCLNT_E_NOT_INITIALIZED;
1456     }
1457
1458     if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1459         if(This->dataflow != eRender){
1460             OSSpinLockUnlock(&This->lock);
1461             return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1462         }
1463         IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
1464         *ppv = &This->IAudioRenderClient_iface;
1465     }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1466         if(This->dataflow != eCapture){
1467             OSSpinLockUnlock(&This->lock);
1468             return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1469         }
1470         IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
1471         *ppv = &This->IAudioCaptureClient_iface;
1472     }else if(IsEqualIID(riid, &IID_IAudioClock)){
1473         IAudioClock_AddRef(&This->IAudioClock_iface);
1474         *ppv = &This->IAudioClock_iface;
1475     }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1476         IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
1477         *ppv = &This->IAudioStreamVolume_iface;
1478     }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1479         if(!This->session_wrapper){
1480             This->session_wrapper = AudioSessionWrapper_Create(This);
1481             if(!This->session_wrapper){
1482                 OSSpinLockUnlock(&This->lock);
1483                 return E_OUTOFMEMORY;
1484             }
1485         }else
1486             IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
1487
1488         *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1489     }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1490         if(!This->session_wrapper){
1491             This->session_wrapper = AudioSessionWrapper_Create(This);
1492             if(!This->session_wrapper){
1493                 OSSpinLockUnlock(&This->lock);
1494                 return E_OUTOFMEMORY;
1495             }
1496         }else
1497             IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
1498
1499         *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1500     }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
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;
1506             }
1507         }else
1508             ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
1509
1510         *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1511     }
1512
1513     if(*ppv){
1514         OSSpinLockUnlock(&This->lock);
1515         return S_OK;
1516     }
1517
1518     OSSpinLockUnlock(&This->lock);
1519
1520     FIXME("stub %s\n", debugstr_guid(riid));
1521     return E_NOINTERFACE;
1522 }
1523
1524 static const IAudioClientVtbl AudioClient_Vtbl =
1525 {
1526     AudioClient_QueryInterface,
1527     AudioClient_AddRef,
1528     AudioClient_Release,
1529     AudioClient_Initialize,
1530     AudioClient_GetBufferSize,
1531     AudioClient_GetStreamLatency,
1532     AudioClient_GetCurrentPadding,
1533     AudioClient_IsFormatSupported,
1534     AudioClient_GetMixFormat,
1535     AudioClient_GetDevicePeriod,
1536     AudioClient_Start,
1537     AudioClient_Stop,
1538     AudioClient_Reset,
1539     AudioClient_SetEventHandle,
1540     AudioClient_GetService
1541 };
1542
1543 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1544         IAudioRenderClient *iface, REFIID riid, void **ppv)
1545 {
1546     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1547
1548     if(!ppv)
1549         return E_POINTER;
1550     *ppv = NULL;
1551
1552     if(IsEqualIID(riid, &IID_IUnknown) ||
1553             IsEqualIID(riid, &IID_IAudioRenderClient))
1554         *ppv = iface;
1555     if(*ppv){
1556         IUnknown_AddRef((IUnknown*)*ppv);
1557         return S_OK;
1558     }
1559
1560     WARN("Unknown interface %s\n", debugstr_guid(riid));
1561     return E_NOINTERFACE;
1562 }
1563
1564 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1565 {
1566     ACImpl *This = impl_from_IAudioRenderClient(iface);
1567     return AudioClient_AddRef(&This->IAudioClient_iface);
1568 }
1569
1570 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1571 {
1572     ACImpl *This = impl_from_IAudioRenderClient(iface);
1573     return AudioClient_Release(&This->IAudioClient_iface);
1574 }
1575
1576 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1577         UINT32 frames, BYTE **data)
1578 {
1579     ACImpl *This = impl_from_IAudioRenderClient(iface);
1580     AQBuffer *buf;
1581     UINT32 pad, bytes = frames * This->fmt->nBlockAlign;
1582     HRESULT hr;
1583     OSStatus sc;
1584
1585     TRACE("(%p)->(%u, %p)\n", This, frames, data);
1586
1587     if(!data)
1588         return E_POINTER;
1589
1590     OSSpinLockLock(&This->lock);
1591
1592     if(This->getbuf_last){
1593         OSSpinLockUnlock(&This->lock);
1594         return AUDCLNT_E_OUT_OF_ORDER;
1595     }
1596
1597     if(!frames){
1598         This->getbuf_last = TRUE;
1599         OSSpinLockUnlock(&This->lock);
1600         return S_OK;
1601     }
1602
1603     hr = AudioClient_GetCurrentPadding_nolock(This, &pad);
1604     if(FAILED(hr)){
1605         OSSpinLockUnlock(&This->lock);
1606         return hr;
1607     }
1608
1609     if(pad + frames > This->bufsize_frames){
1610         OSSpinLockUnlock(&This->lock);
1611         return AUDCLNT_E_BUFFER_TOO_LARGE;
1612     }
1613
1614     LIST_FOR_EACH_ENTRY(buf, &This->avail_buffers, AQBuffer, entry){
1615         if(buf->buf->mAudioDataBytesCapacity >= bytes){
1616             This->public_buffer = buf->buf;
1617             list_remove(&buf->entry);
1618             break;
1619         }
1620     }
1621
1622     if(&buf->entry == &This->avail_buffers){
1623         sc = AudioQueueAllocateBuffer(This->aqueue, bytes,
1624                 &This->public_buffer);
1625         if(sc != noErr){
1626             OSSpinLockUnlock(&This->lock);
1627             WARN("Unable to allocate buffer: %lx\n", sc);
1628             return E_FAIL;
1629         }
1630         buf = HeapAlloc(GetProcessHeap(), 0, sizeof(AQBuffer));
1631         if(!buf){
1632             AudioQueueFreeBuffer(This->aqueue, This->public_buffer);
1633             This->public_buffer = NULL;
1634             OSSpinLockUnlock(&This->lock);
1635             return E_OUTOFMEMORY;
1636         }
1637         buf->buf = This->public_buffer;
1638         This->public_buffer->mUserData = buf;
1639     }
1640
1641     *data = This->public_buffer->mAudioData;
1642
1643     This->getbuf_last = TRUE;
1644
1645     OSSpinLockUnlock(&This->lock);
1646
1647     return S_OK;
1648 }
1649
1650 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1651         IAudioRenderClient *iface, UINT32 frames, DWORD flags)
1652 {
1653     ACImpl *This = impl_from_IAudioRenderClient(iface);
1654     OSStatus sc;
1655
1656     TRACE("(%p)->(%u, %x)\n", This, frames, flags);
1657
1658     OSSpinLockLock(&This->lock);
1659
1660     if(!This->getbuf_last){
1661         OSSpinLockUnlock(&This->lock);
1662         return AUDCLNT_E_OUT_OF_ORDER;
1663     }
1664
1665     if(flags & AUDCLNT_BUFFERFLAGS_SILENT){
1666         WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)This->fmt;
1667         if((This->fmt->wFormatTag == WAVE_FORMAT_PCM ||
1668                 (This->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1669                  IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) &&
1670                 This->fmt->wBitsPerSample == 8)
1671             memset(This->public_buffer->mAudioData, 128,
1672                     frames * This->fmt->nBlockAlign);
1673         else
1674             memset(This->public_buffer->mAudioData, 0,
1675                     frames * This->fmt->nBlockAlign);
1676     }
1677
1678     This->public_buffer->mAudioDataByteSize = frames * This->fmt->nBlockAlign;
1679
1680     sc = AudioQueueEnqueueBuffer(This->aqueue, This->public_buffer, 0, NULL);
1681     if(sc != noErr){
1682         OSSpinLockUnlock(&This->lock);
1683         WARN("Unable to enqueue buffer: %lx\n", sc);
1684         return E_FAIL;
1685     }
1686
1687     if(This->playing == StateStopped)
1688         AudioQueuePrime(This->aqueue, 0, NULL);
1689
1690     This->public_buffer = NULL;
1691     This->getbuf_last = FALSE;
1692     This->written_frames += frames;
1693     This->inbuf_frames += frames;
1694
1695     OSSpinLockUnlock(&This->lock);
1696
1697     return S_OK;
1698 }
1699
1700 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1701     AudioRenderClient_QueryInterface,
1702     AudioRenderClient_AddRef,
1703     AudioRenderClient_Release,
1704     AudioRenderClient_GetBuffer,
1705     AudioRenderClient_ReleaseBuffer
1706 };
1707
1708 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1709         IAudioCaptureClient *iface, REFIID riid, void **ppv)
1710 {
1711     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1712
1713     if(!ppv)
1714         return E_POINTER;
1715     *ppv = NULL;
1716
1717     if(IsEqualIID(riid, &IID_IUnknown) ||
1718             IsEqualIID(riid, &IID_IAudioCaptureClient))
1719         *ppv = iface;
1720     if(*ppv){
1721         IUnknown_AddRef((IUnknown*)*ppv);
1722         return S_OK;
1723     }
1724
1725     WARN("Unknown interface %s\n", debugstr_guid(riid));
1726     return E_NOINTERFACE;
1727 }
1728
1729 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1730 {
1731     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1732     return IAudioClient_AddRef(&This->IAudioClient_iface);
1733 }
1734
1735 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1736 {
1737     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1738     return IAudioClient_Release(&This->IAudioClient_iface);
1739 }
1740
1741 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1742         BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1743         UINT64 *qpcpos)
1744 {
1745     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1746
1747     TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1748             devpos, qpcpos);
1749
1750     if(!data || !frames || !flags)
1751         return E_POINTER;
1752
1753     OSSpinLockLock(&This->lock);
1754
1755     if(This->getbuf_last){
1756         OSSpinLockUnlock(&This->lock);
1757         return AUDCLNT_E_OUT_OF_ORDER;
1758     }
1759
1760     if(This->public_buffer){
1761         *data = This->public_buffer->mAudioData;
1762         *frames =
1763             This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
1764     }else{
1765         struct list *head = list_head(&This->avail_buffers);
1766         if(!head){
1767             *data = NULL;
1768             *frames = 0;
1769         }else{
1770             AQBuffer *buf = LIST_ENTRY(head, AQBuffer, entry);
1771             This->public_buffer = buf->buf;
1772             *data = This->public_buffer->mAudioData;
1773             *frames =
1774                 This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
1775             list_remove(&buf->entry);
1776         }
1777     }
1778
1779     *flags = 0;
1780     This->written_frames += *frames;
1781     This->inbuf_frames -= *frames;
1782     This->getbuf_last = TRUE;
1783
1784     if(devpos || qpcpos)
1785         AudioClock_GetPosition_nolock(This, devpos, qpcpos, FALSE);
1786
1787     OSSpinLockUnlock(&This->lock);
1788
1789     return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
1790 }
1791
1792 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1793         IAudioCaptureClient *iface, UINT32 done)
1794 {
1795     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1796     UINT32 pbuf_frames =
1797         This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
1798     OSStatus sc;
1799
1800     TRACE("(%p)->(%u)\n", This, done);
1801
1802     OSSpinLockLock(&This->lock);
1803
1804     if(!This->getbuf_last){
1805         OSSpinLockUnlock(&This->lock);
1806         return AUDCLNT_E_OUT_OF_ORDER;
1807     }
1808
1809     if(done != 0 && done != pbuf_frames){
1810         OSSpinLockUnlock(&This->lock);
1811         return AUDCLNT_E_INVALID_SIZE;
1812     }
1813
1814     if(done){
1815         sc = AudioQueueEnqueueBuffer(This->aqueue, This->public_buffer,
1816                 0, NULL);
1817         if(sc != noErr)
1818             WARN("Unable to enqueue buffer: %lx\n", sc);
1819         This->public_buffer = NULL;
1820     }
1821
1822     This->getbuf_last = FALSE;
1823
1824     OSSpinLockUnlock(&This->lock);
1825
1826     return S_OK;
1827 }
1828
1829 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1830         IAudioCaptureClient *iface, UINT32 *frames)
1831 {
1832     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1833     struct list *head;
1834     AQBuffer *buf;
1835
1836     TRACE("(%p)->(%p)\n", This, frames);
1837
1838     if(!frames)
1839         return E_POINTER;
1840
1841     OSSpinLockLock(&This->lock);
1842
1843     head = list_head(&This->avail_buffers);
1844
1845     if(!head){
1846         *frames = This->bufsize_frames / CAPTURE_BUFFERS;
1847         OSSpinLockUnlock(&This->lock);
1848         return S_OK;
1849     }
1850
1851     buf = LIST_ENTRY(head, AQBuffer, entry);
1852     *frames = buf->buf->mAudioDataByteSize / This->fmt->nBlockAlign;
1853
1854     OSSpinLockUnlock(&This->lock);
1855
1856     return S_OK;
1857 }
1858
1859 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1860 {
1861     AudioCaptureClient_QueryInterface,
1862     AudioCaptureClient_AddRef,
1863     AudioCaptureClient_Release,
1864     AudioCaptureClient_GetBuffer,
1865     AudioCaptureClient_ReleaseBuffer,
1866     AudioCaptureClient_GetNextPacketSize
1867 };
1868
1869 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1870         REFIID riid, void **ppv)
1871 {
1872     ACImpl *This = impl_from_IAudioClock(iface);
1873
1874     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1875
1876     if(!ppv)
1877         return E_POINTER;
1878     *ppv = NULL;
1879
1880     if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
1881         *ppv = iface;
1882     else if(IsEqualIID(riid, &IID_IAudioClock2))
1883         *ppv = &This->IAudioClock2_iface;
1884     if(*ppv){
1885         IUnknown_AddRef((IUnknown*)*ppv);
1886         return S_OK;
1887     }
1888
1889     WARN("Unknown interface %s\n", debugstr_guid(riid));
1890     return E_NOINTERFACE;
1891 }
1892
1893 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
1894 {
1895     ACImpl *This = impl_from_IAudioClock(iface);
1896     return IAudioClient_AddRef(&This->IAudioClient_iface);
1897 }
1898
1899 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
1900 {
1901     ACImpl *This = impl_from_IAudioClock(iface);
1902     return IAudioClient_Release(&This->IAudioClient_iface);
1903 }
1904
1905 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
1906 {
1907     ACImpl *This = impl_from_IAudioClock(iface);
1908
1909     TRACE("(%p)->(%p)\n", This, freq);
1910
1911     *freq = This->fmt->nSamplesPerSec;
1912
1913     return S_OK;
1914 }
1915
1916 static HRESULT AudioClock_GetPosition_nolock(ACImpl *This,
1917         UINT64 *pos, UINT64 *qpctime, BOOL raw)
1918 {
1919     AudioTimeStamp time;
1920     OSStatus sc;
1921
1922     sc = AudioQueueGetCurrentTime(This->aqueue, NULL, &time, NULL);
1923     if(sc == kAudioQueueErr_InvalidRunState){
1924         *pos = 0;
1925     }else if(sc == noErr){
1926         if(!(time.mFlags & kAudioTimeStampSampleTimeValid)){
1927             FIXME("Sample time not valid, should calculate from something else\n");
1928             return E_FAIL;
1929         }
1930
1931         if(raw)
1932             *pos = time.mSampleTime;
1933         else
1934             *pos = time.mSampleTime - This->last_time;
1935     }else{
1936         WARN("Unable to get current time: %lx\n", sc);
1937         return E_FAIL;
1938     }
1939
1940     if(qpctime){
1941         LARGE_INTEGER stamp, freq;
1942         QueryPerformanceCounter(&stamp);
1943         QueryPerformanceFrequency(&freq);
1944         *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
1945     }
1946
1947     return S_OK;
1948 }
1949
1950 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
1951         UINT64 *qpctime)
1952 {
1953     ACImpl *This = impl_from_IAudioClock(iface);
1954     HRESULT hr;
1955
1956     TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
1957
1958     if(!pos)
1959         return E_POINTER;
1960
1961     OSSpinLockLock(&This->lock);
1962
1963     hr = AudioClock_GetPosition_nolock(This, pos, qpctime, FALSE);
1964
1965     OSSpinLockUnlock(&This->lock);
1966
1967     return hr;
1968 }
1969
1970 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
1971         DWORD *chars)
1972 {
1973     ACImpl *This = impl_from_IAudioClock(iface);
1974
1975     TRACE("(%p)->(%p)\n", This, chars);
1976
1977     if(!chars)
1978         return E_POINTER;
1979
1980     *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
1981
1982     return S_OK;
1983 }
1984
1985 static const IAudioClockVtbl AudioClock_Vtbl =
1986 {
1987     AudioClock_QueryInterface,
1988     AudioClock_AddRef,
1989     AudioClock_Release,
1990     AudioClock_GetFrequency,
1991     AudioClock_GetPosition,
1992     AudioClock_GetCharacteristics
1993 };
1994
1995 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
1996         REFIID riid, void **ppv)
1997 {
1998     ACImpl *This = impl_from_IAudioClock2(iface);
1999     return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
2000 }
2001
2002 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
2003 {
2004     ACImpl *This = impl_from_IAudioClock2(iface);
2005     return IAudioClient_AddRef(&This->IAudioClient_iface);
2006 }
2007
2008 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
2009 {
2010     ACImpl *This = impl_from_IAudioClock2(iface);
2011     return IAudioClient_Release(&This->IAudioClient_iface);
2012 }
2013
2014 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
2015         UINT64 *pos, UINT64 *qpctime)
2016 {
2017     ACImpl *This = impl_from_IAudioClock2(iface);
2018
2019     FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
2020
2021     return E_NOTIMPL;
2022 }
2023
2024 static const IAudioClock2Vtbl AudioClock2_Vtbl =
2025 {
2026     AudioClock2_QueryInterface,
2027     AudioClock2_AddRef,
2028     AudioClock2_Release,
2029     AudioClock2_GetDevicePosition
2030 };
2031
2032 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
2033 {
2034     AudioSessionWrapper *ret;
2035
2036     ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2037             sizeof(AudioSessionWrapper));
2038     if(!ret)
2039         return NULL;
2040
2041     ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
2042     ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
2043     ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
2044
2045     ret->ref = 1;
2046
2047     ret->client = client;
2048     if(client){
2049         ret->session = client->session;
2050         AudioClient_AddRef(&client->IAudioClient_iface);
2051     }
2052
2053     return ret;
2054 }
2055
2056 static HRESULT WINAPI AudioSessionControl_QueryInterface(
2057         IAudioSessionControl2 *iface, REFIID riid, void **ppv)
2058 {
2059     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2060
2061     if(!ppv)
2062         return E_POINTER;
2063     *ppv = NULL;
2064
2065     if(IsEqualIID(riid, &IID_IUnknown) ||
2066             IsEqualIID(riid, &IID_IAudioSessionControl) ||
2067             IsEqualIID(riid, &IID_IAudioSessionControl2))
2068         *ppv = iface;
2069     if(*ppv){
2070         IUnknown_AddRef((IUnknown*)*ppv);
2071         return S_OK;
2072     }
2073
2074     WARN("Unknown interface %s\n", debugstr_guid(riid));
2075     return E_NOINTERFACE;
2076 }
2077
2078 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
2079 {
2080     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2081     ULONG ref;
2082     ref = InterlockedIncrement(&This->ref);
2083     TRACE("(%p) Refcount now %u\n", This, ref);
2084     return ref;
2085 }
2086
2087 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
2088 {
2089     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2090     ULONG ref;
2091     ref = InterlockedDecrement(&This->ref);
2092     TRACE("(%p) Refcount now %u\n", This, ref);
2093     if(!ref){
2094         if(This->client){
2095             OSSpinLockLock(&This->client->lock);
2096             This->client->session_wrapper = NULL;
2097             OSSpinLockUnlock(&This->client->lock);
2098             AudioClient_Release(&This->client->IAudioClient_iface);
2099         }
2100         HeapFree(GetProcessHeap(), 0, This);
2101     }
2102     return ref;
2103 }
2104
2105 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
2106         AudioSessionState *state)
2107 {
2108     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2109     ACImpl *client;
2110
2111     TRACE("(%p)->(%p)\n", This, state);
2112
2113     if(!state)
2114         return NULL_PTR_ERR;
2115
2116     EnterCriticalSection(&g_sessions_lock);
2117
2118     if(list_empty(&This->session->clients)){
2119         *state = AudioSessionStateExpired;
2120         LeaveCriticalSection(&g_sessions_lock);
2121         return S_OK;
2122     }
2123
2124     LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
2125         OSSpinLockLock(&client->lock);
2126         if(client->playing == StatePlaying ||
2127                 client->playing == StateInTransition){
2128             *state = AudioSessionStateActive;
2129             OSSpinLockUnlock(&client->lock);
2130             LeaveCriticalSection(&g_sessions_lock);
2131             return S_OK;
2132         }
2133         OSSpinLockUnlock(&client->lock);
2134     }
2135
2136     LeaveCriticalSection(&g_sessions_lock);
2137
2138     *state = AudioSessionStateInactive;
2139
2140     return S_OK;
2141 }
2142
2143 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
2144         IAudioSessionControl2 *iface, WCHAR **name)
2145 {
2146     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2147
2148     FIXME("(%p)->(%p) - stub\n", This, name);
2149
2150     return E_NOTIMPL;
2151 }
2152
2153 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
2154         IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
2155 {
2156     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2157
2158     FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
2159
2160     return E_NOTIMPL;
2161 }
2162
2163 static HRESULT WINAPI AudioSessionControl_GetIconPath(
2164         IAudioSessionControl2 *iface, WCHAR **path)
2165 {
2166     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2167
2168     FIXME("(%p)->(%p) - stub\n", This, path);
2169
2170     return E_NOTIMPL;
2171 }
2172
2173 static HRESULT WINAPI AudioSessionControl_SetIconPath(
2174         IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
2175 {
2176     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2177
2178     FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
2179
2180     return E_NOTIMPL;
2181 }
2182
2183 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
2184         IAudioSessionControl2 *iface, GUID *group)
2185 {
2186     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2187
2188     FIXME("(%p)->(%p) - stub\n", This, group);
2189
2190     return E_NOTIMPL;
2191 }
2192
2193 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
2194         IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
2195 {
2196     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2197
2198     FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
2199             debugstr_guid(session));
2200
2201     return E_NOTIMPL;
2202 }
2203
2204 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
2205         IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2206 {
2207     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2208
2209     FIXME("(%p)->(%p) - stub\n", This, events);
2210
2211     return S_OK;
2212 }
2213
2214 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
2215         IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2216 {
2217     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2218
2219     FIXME("(%p)->(%p) - stub\n", This, events);
2220
2221     return S_OK;
2222 }
2223
2224 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
2225         IAudioSessionControl2 *iface, WCHAR **id)
2226 {
2227     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2228
2229     FIXME("(%p)->(%p) - stub\n", This, id);
2230
2231     return E_NOTIMPL;
2232 }
2233
2234 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
2235         IAudioSessionControl2 *iface, WCHAR **id)
2236 {
2237     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2238
2239     FIXME("(%p)->(%p) - stub\n", This, id);
2240
2241     return E_NOTIMPL;
2242 }
2243
2244 static HRESULT WINAPI AudioSessionControl_GetProcessId(
2245         IAudioSessionControl2 *iface, DWORD *pid)
2246 {
2247     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2248
2249     TRACE("(%p)->(%p)\n", This, pid);
2250
2251     if(!pid)
2252         return E_POINTER;
2253
2254     *pid = GetCurrentProcessId();
2255
2256     return S_OK;
2257 }
2258
2259 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
2260         IAudioSessionControl2 *iface)
2261 {
2262     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2263
2264     TRACE("(%p)\n", This);
2265
2266     return S_FALSE;
2267 }
2268
2269 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
2270         IAudioSessionControl2 *iface, BOOL optout)
2271 {
2272     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2273
2274     TRACE("(%p)->(%d)\n", This, optout);
2275
2276     return S_OK;
2277 }
2278
2279 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
2280 {
2281     AudioSessionControl_QueryInterface,
2282     AudioSessionControl_AddRef,
2283     AudioSessionControl_Release,
2284     AudioSessionControl_GetState,
2285     AudioSessionControl_GetDisplayName,
2286     AudioSessionControl_SetDisplayName,
2287     AudioSessionControl_GetIconPath,
2288     AudioSessionControl_SetIconPath,
2289     AudioSessionControl_GetGroupingParam,
2290     AudioSessionControl_SetGroupingParam,
2291     AudioSessionControl_RegisterAudioSessionNotification,
2292     AudioSessionControl_UnregisterAudioSessionNotification,
2293     AudioSessionControl_GetSessionIdentifier,
2294     AudioSessionControl_GetSessionInstanceIdentifier,
2295     AudioSessionControl_GetProcessId,
2296     AudioSessionControl_IsSystemSoundsSession,
2297     AudioSessionControl_SetDuckingPreference
2298 };
2299
2300 /* index == -1 means set all channels, otherwise sets only the given channel */
2301 static HRESULT ca_setvol(ACImpl *This, UINT32 index)
2302 {
2303     float level;
2304     OSStatus sc;
2305
2306     if(index == (UINT32)-1){
2307         HRESULT ret = S_OK;
2308         UINT32 i;
2309         for(i = 0; i < This->fmt->nChannels; ++i){
2310             HRESULT hr;
2311             hr = ca_setvol(This, i);
2312             if(FAILED(hr))
2313                 ret = hr;
2314         }
2315         return ret;
2316     }
2317
2318     if(This->session->mute)
2319         level = 0;
2320     else
2321         level = This->session->master_vol *
2322             This->session->channel_vols[index] * This->vols[index];
2323
2324     sc = AudioQueueSetParameter(This->aqueue, kAudioQueueParam_Volume, level);
2325     if(sc != noErr){
2326         WARN("Setting _Volume property failed: %lx\n", sc);
2327         return E_FAIL;
2328     }
2329
2330     return S_OK;
2331 }
2332
2333 static HRESULT ca_session_setvol(AudioSession *session, UINT32 index)
2334 {
2335     HRESULT ret = S_OK;
2336     ACImpl *client;
2337
2338     LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry){
2339         HRESULT hr;
2340         hr = ca_setvol(client, index);
2341         if(FAILED(hr))
2342             ret = hr;
2343     }
2344
2345     return ret;
2346 }
2347
2348 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
2349         ISimpleAudioVolume *iface, REFIID riid, void **ppv)
2350 {
2351     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2352
2353     if(!ppv)
2354         return E_POINTER;
2355     *ppv = NULL;
2356
2357     if(IsEqualIID(riid, &IID_IUnknown) ||
2358             IsEqualIID(riid, &IID_ISimpleAudioVolume))
2359         *ppv = iface;
2360     if(*ppv){
2361         IUnknown_AddRef((IUnknown*)*ppv);
2362         return S_OK;
2363     }
2364
2365     WARN("Unknown interface %s\n", debugstr_guid(riid));
2366     return E_NOINTERFACE;
2367 }
2368
2369 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
2370 {
2371     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2372     return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2373 }
2374
2375 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
2376 {
2377     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2378     return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2379 }
2380
2381 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
2382         ISimpleAudioVolume *iface, float level, const GUID *context)
2383 {
2384     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2385     AudioSession *session = This->session;
2386     HRESULT ret;
2387
2388     TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
2389
2390     if(level < 0.f || level > 1.f)
2391         return E_INVALIDARG;
2392
2393     if(context)
2394         FIXME("Notifications not supported yet\n");
2395
2396     EnterCriticalSection(&session->lock);
2397
2398     session->master_vol = level;
2399
2400     ret = ca_session_setvol(session, -1);
2401
2402     LeaveCriticalSection(&session->lock);
2403
2404     return ret;
2405 }
2406
2407 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
2408         ISimpleAudioVolume *iface, float *level)
2409 {
2410     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2411     AudioSession *session = This->session;
2412
2413     TRACE("(%p)->(%p)\n", session, level);
2414
2415     if(!level)
2416         return NULL_PTR_ERR;
2417
2418     *level = session->master_vol;
2419
2420     return S_OK;
2421 }
2422
2423 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
2424         BOOL mute, const GUID *context)
2425 {
2426     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2427     AudioSession *session = This->session;
2428
2429     TRACE("(%p)->(%u, %p)\n", session, mute, context);
2430
2431     if(context)
2432         FIXME("Notifications not supported yet\n");
2433
2434     EnterCriticalSection(&session->lock);
2435
2436     session->mute = mute;
2437
2438     ca_session_setvol(session, -1);
2439
2440     LeaveCriticalSection(&session->lock);
2441
2442     return S_OK;
2443 }
2444
2445 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
2446         BOOL *mute)
2447 {
2448     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2449     AudioSession *session = This->session;
2450
2451     TRACE("(%p)->(%p)\n", session, mute);
2452
2453     if(!mute)
2454         return NULL_PTR_ERR;
2455
2456     *mute = session->mute;
2457
2458     return S_OK;
2459 }
2460
2461 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl  =
2462 {
2463     SimpleAudioVolume_QueryInterface,
2464     SimpleAudioVolume_AddRef,
2465     SimpleAudioVolume_Release,
2466     SimpleAudioVolume_SetMasterVolume,
2467     SimpleAudioVolume_GetMasterVolume,
2468     SimpleAudioVolume_SetMute,
2469     SimpleAudioVolume_GetMute
2470 };
2471
2472 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
2473         IAudioStreamVolume *iface, REFIID riid, void **ppv)
2474 {
2475     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2476
2477     if(!ppv)
2478         return E_POINTER;
2479     *ppv = NULL;
2480
2481     if(IsEqualIID(riid, &IID_IUnknown) ||
2482             IsEqualIID(riid, &IID_IAudioStreamVolume))
2483         *ppv = iface;
2484     if(*ppv){
2485         IUnknown_AddRef((IUnknown*)*ppv);
2486         return S_OK;
2487     }
2488
2489     WARN("Unknown interface %s\n", debugstr_guid(riid));
2490     return E_NOINTERFACE;
2491 }
2492
2493 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
2494 {
2495     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2496     return IAudioClient_AddRef(&This->IAudioClient_iface);
2497 }
2498
2499 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
2500 {
2501     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2502     return IAudioClient_Release(&This->IAudioClient_iface);
2503 }
2504
2505 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
2506         IAudioStreamVolume *iface, UINT32 *out)
2507 {
2508     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2509
2510     TRACE("(%p)->(%p)\n", This, out);
2511
2512     if(!out)
2513         return E_POINTER;
2514
2515     *out = This->fmt->nChannels;
2516
2517     return S_OK;
2518 }
2519
2520 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
2521         IAudioStreamVolume *iface, UINT32 index, float level)
2522 {
2523     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2524     HRESULT ret;
2525
2526     TRACE("(%p)->(%d, %f)\n", This, index, level);
2527
2528     if(level < 0.f || level > 1.f)
2529         return E_INVALIDARG;
2530
2531     if(index >= This->fmt->nChannels)
2532         return E_INVALIDARG;
2533
2534     OSSpinLockLock(&This->lock);
2535
2536     This->vols[index] = level;
2537
2538     WARN("AudioQueue doesn't support per-channel volume control\n");
2539     ret = ca_setvol(This, index);
2540
2541     OSSpinLockUnlock(&This->lock);
2542
2543     return ret;
2544 }
2545
2546 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2547         IAudioStreamVolume *iface, UINT32 index, float *level)
2548 {
2549     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2550
2551     TRACE("(%p)->(%d, %p)\n", This, index, level);
2552
2553     if(!level)
2554         return E_POINTER;
2555
2556     if(index >= This->fmt->nChannels)
2557         return E_INVALIDARG;
2558
2559     *level = This->vols[index];
2560
2561     return S_OK;
2562 }
2563
2564 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2565         IAudioStreamVolume *iface, UINT32 count, const float *levels)
2566 {
2567     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2568     int i;
2569     HRESULT ret;
2570
2571     TRACE("(%p)->(%d, %p)\n", This, count, levels);
2572
2573     if(!levels)
2574         return E_POINTER;
2575
2576     if(count != This->fmt->nChannels)
2577         return E_INVALIDARG;
2578
2579     OSSpinLockLock(&This->lock);
2580
2581     for(i = 0; i < count; ++i)
2582         This->vols[i] = levels[i];
2583
2584     ret = ca_setvol(This, -1);
2585
2586     OSSpinLockUnlock(&This->lock);
2587
2588     return ret;
2589 }
2590
2591 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2592         IAudioStreamVolume *iface, UINT32 count, float *levels)
2593 {
2594     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2595     int i;
2596
2597     TRACE("(%p)->(%d, %p)\n", This, count, levels);
2598
2599     if(!levels)
2600         return E_POINTER;
2601
2602     if(count != This->fmt->nChannels)
2603         return E_INVALIDARG;
2604
2605     OSSpinLockLock(&This->lock);
2606
2607     for(i = 0; i < count; ++i)
2608         levels[i] = This->vols[i];
2609
2610     OSSpinLockUnlock(&This->lock);
2611
2612     return S_OK;
2613 }
2614
2615 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2616 {
2617     AudioStreamVolume_QueryInterface,
2618     AudioStreamVolume_AddRef,
2619     AudioStreamVolume_Release,
2620     AudioStreamVolume_GetChannelCount,
2621     AudioStreamVolume_SetChannelVolume,
2622     AudioStreamVolume_GetChannelVolume,
2623     AudioStreamVolume_SetAllVolumes,
2624     AudioStreamVolume_GetAllVolumes
2625 };
2626
2627 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2628         IChannelAudioVolume *iface, REFIID riid, void **ppv)
2629 {
2630     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2631
2632     if(!ppv)
2633         return E_POINTER;
2634     *ppv = NULL;
2635
2636     if(IsEqualIID(riid, &IID_IUnknown) ||
2637             IsEqualIID(riid, &IID_IChannelAudioVolume))
2638         *ppv = iface;
2639     if(*ppv){
2640         IUnknown_AddRef((IUnknown*)*ppv);
2641         return S_OK;
2642     }
2643
2644     WARN("Unknown interface %s\n", debugstr_guid(riid));
2645     return E_NOINTERFACE;
2646 }
2647
2648 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2649 {
2650     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2651     return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2652 }
2653
2654 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2655 {
2656     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2657     return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2658 }
2659
2660 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2661         IChannelAudioVolume *iface, UINT32 *out)
2662 {
2663     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2664     AudioSession *session = This->session;
2665
2666     TRACE("(%p)->(%p)\n", session, out);
2667
2668     if(!out)
2669         return NULL_PTR_ERR;
2670
2671     *out = session->channel_count;
2672
2673     return S_OK;
2674 }
2675
2676 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2677         IChannelAudioVolume *iface, UINT32 index, float level,
2678         const GUID *context)
2679 {
2680     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2681     AudioSession *session = This->session;
2682     HRESULT ret;
2683
2684     TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2685             wine_dbgstr_guid(context));
2686
2687     if(level < 0.f || level > 1.f)
2688         return E_INVALIDARG;
2689
2690     if(index >= session->channel_count)
2691         return E_INVALIDARG;
2692
2693     if(context)
2694         FIXME("Notifications not supported yet\n");
2695
2696     EnterCriticalSection(&session->lock);
2697
2698     session->channel_vols[index] = level;
2699
2700     WARN("AudioQueue doesn't support per-channel volume control\n");
2701     ret = ca_session_setvol(session, index);
2702
2703     LeaveCriticalSection(&session->lock);
2704
2705     return ret;
2706 }
2707
2708 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2709         IChannelAudioVolume *iface, UINT32 index, float *level)
2710 {
2711     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2712     AudioSession *session = This->session;
2713
2714     TRACE("(%p)->(%d, %p)\n", session, index, level);
2715
2716     if(!level)
2717         return NULL_PTR_ERR;
2718
2719     if(index >= session->channel_count)
2720         return E_INVALIDARG;
2721
2722     *level = session->channel_vols[index];
2723
2724     return S_OK;
2725 }
2726
2727 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2728         IChannelAudioVolume *iface, UINT32 count, const float *levels,
2729         const GUID *context)
2730 {
2731     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2732     AudioSession *session = This->session;
2733     int i;
2734     HRESULT ret;
2735
2736     TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2737             wine_dbgstr_guid(context));
2738
2739     if(!levels)
2740         return NULL_PTR_ERR;
2741
2742     if(count != session->channel_count)
2743         return E_INVALIDARG;
2744
2745     if(context)
2746         FIXME("Notifications not supported yet\n");
2747
2748     EnterCriticalSection(&session->lock);
2749
2750     for(i = 0; i < count; ++i)
2751         session->channel_vols[i] = levels[i];
2752
2753     ret = ca_session_setvol(session, -1);
2754
2755     LeaveCriticalSection(&session->lock);
2756
2757     return ret;
2758 }
2759
2760 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2761         IChannelAudioVolume *iface, UINT32 count, float *levels)
2762 {
2763     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2764     AudioSession *session = This->session;
2765     int i;
2766
2767     TRACE("(%p)->(%d, %p)\n", session, count, levels);
2768
2769     if(!levels)
2770         return NULL_PTR_ERR;
2771
2772     if(count != session->channel_count)
2773         return E_INVALIDARG;
2774
2775     for(i = 0; i < count; ++i)
2776         levels[i] = session->channel_vols[i];
2777
2778     return S_OK;
2779 }
2780
2781 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2782 {
2783     ChannelAudioVolume_QueryInterface,
2784     ChannelAudioVolume_AddRef,
2785     ChannelAudioVolume_Release,
2786     ChannelAudioVolume_GetChannelCount,
2787     ChannelAudioVolume_SetChannelVolume,
2788     ChannelAudioVolume_GetChannelVolume,
2789     ChannelAudioVolume_SetAllVolumes,
2790     ChannelAudioVolume_GetAllVolumes
2791 };
2792
2793 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2794         REFIID riid, void **ppv)
2795 {
2796     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2797
2798     if(!ppv)
2799         return E_POINTER;
2800     *ppv = NULL;
2801
2802     if(IsEqualIID(riid, &IID_IUnknown) ||
2803             IsEqualIID(riid, &IID_IAudioSessionManager) ||
2804             IsEqualIID(riid, &IID_IAudioSessionManager2))
2805         *ppv = iface;
2806     if(*ppv){
2807         IUnknown_AddRef((IUnknown*)*ppv);
2808         return S_OK;
2809     }
2810
2811     WARN("Unknown interface %s\n", debugstr_guid(riid));
2812     return E_NOINTERFACE;
2813 }
2814
2815 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2816 {
2817     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2818     ULONG ref;
2819     ref = InterlockedIncrement(&This->ref);
2820     TRACE("(%p) Refcount now %u\n", This, ref);
2821     return ref;
2822 }
2823
2824 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2825 {
2826     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2827     ULONG ref;
2828     ref = InterlockedDecrement(&This->ref);
2829     TRACE("(%p) Refcount now %u\n", This, ref);
2830     if(!ref)
2831         HeapFree(GetProcessHeap(), 0, This);
2832     return ref;
2833 }
2834
2835 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2836         IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2837         IAudioSessionControl **out)
2838 {
2839     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2840     AudioSession *session;
2841     AudioSessionWrapper *wrapper;
2842     HRESULT hr;
2843
2844     TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2845             flags, out);
2846
2847     hr = get_audio_session(session_guid, This->device, 0, &session);
2848     if(FAILED(hr))
2849         return hr;
2850
2851     wrapper = AudioSessionWrapper_Create(NULL);
2852     if(!wrapper)
2853         return E_OUTOFMEMORY;
2854
2855     wrapper->session = session;
2856
2857     *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
2858
2859     return S_OK;
2860 }
2861
2862 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
2863         IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2864         ISimpleAudioVolume **out)
2865 {
2866     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2867     AudioSession *session;
2868     AudioSessionWrapper *wrapper;
2869     HRESULT hr;
2870
2871     TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2872             flags, out);
2873
2874     hr = get_audio_session(session_guid, This->device, 0, &session);
2875     if(FAILED(hr))
2876         return hr;
2877
2878     wrapper = AudioSessionWrapper_Create(NULL);
2879     if(!wrapper)
2880         return E_OUTOFMEMORY;
2881
2882     wrapper->session = session;
2883
2884     *out = &wrapper->ISimpleAudioVolume_iface;
2885
2886     return S_OK;
2887 }
2888
2889 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
2890         IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
2891 {
2892     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2893     FIXME("(%p)->(%p) - stub\n", This, out);
2894     return E_NOTIMPL;
2895 }
2896
2897 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
2898         IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2899 {
2900     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2901     FIXME("(%p)->(%p) - stub\n", This, notification);
2902     return E_NOTIMPL;
2903 }
2904
2905 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
2906         IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2907 {
2908     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2909     FIXME("(%p)->(%p) - stub\n", This, notification);
2910     return E_NOTIMPL;
2911 }
2912
2913 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
2914         IAudioSessionManager2 *iface, const WCHAR *session_id,
2915         IAudioVolumeDuckNotification *notification)
2916 {
2917     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2918     FIXME("(%p)->(%p) - stub\n", This, notification);
2919     return E_NOTIMPL;
2920 }
2921
2922 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
2923         IAudioSessionManager2 *iface,
2924         IAudioVolumeDuckNotification *notification)
2925 {
2926     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2927     FIXME("(%p)->(%p) - stub\n", This, notification);
2928     return E_NOTIMPL;
2929 }
2930
2931 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
2932 {
2933     AudioSessionManager_QueryInterface,
2934     AudioSessionManager_AddRef,
2935     AudioSessionManager_Release,
2936     AudioSessionManager_GetAudioSessionControl,
2937     AudioSessionManager_GetSimpleAudioVolume,
2938     AudioSessionManager_GetSessionEnumerator,
2939     AudioSessionManager_RegisterSessionNotification,
2940     AudioSessionManager_UnregisterSessionNotification,
2941     AudioSessionManager_RegisterDuckNotification,
2942     AudioSessionManager_UnregisterDuckNotification
2943 };
2944
2945 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
2946         IAudioSessionManager2 **out)
2947 {
2948     SessionMgr *This;
2949
2950     This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
2951     if(!This)
2952         return E_OUTOFMEMORY;
2953
2954     This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
2955     This->device = device;
2956     This->ref = 1;
2957
2958     *out = &This->IAudioSessionManager2_iface;
2959
2960     return S_OK;
2961 }