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