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