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