winecoreaudio.drv: Move IAudioClock closer to its related interfaces.
[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     EDataFlow dataflow;
81
82     struct list entry;
83 } AudioSession;
84
85 typedef struct _AudioSessionWrapper {
86     IAudioSessionControl2 IAudioSessionControl2_iface;
87
88     LONG ref;
89
90     ACImpl *client;
91     AudioSession *session;
92 } AudioSessionWrapper;
93
94 struct ACImpl {
95     IAudioClient IAudioClient_iface;
96     IAudioRenderClient IAudioRenderClient_iface;
97     IAudioCaptureClient IAudioCaptureClient_iface;
98     ISimpleAudioVolume ISimpleAudioVolume_iface;
99     IAudioClock IAudioClock_iface;
100     IAudioClock2 IAudioClock2_iface;
101
102     LONG ref;
103
104     IMMDevice *parent;
105
106     WAVEFORMATEX *fmt;
107
108     EDataFlow dataflow;
109     DWORD flags;
110     AUDCLNT_SHAREMODE share;
111     HANDLE event;
112
113     AudioDeviceID adevid;
114     AudioQueueRef aqueue;
115     HANDLE timer;
116     UINT32 period_ms, bufsize_frames, inbuf_frames, written_frames;
117     UINT64 last_time;
118     AudioQueueBufferRef public_buffer;
119     BOOL getbuf_last;
120     int playing;
121
122     AudioSession *session;
123     AudioSessionWrapper *session_wrapper;
124
125     struct list entry;
126
127     struct list avail_buffers;
128
129     /* We can't use debug printing or {Enter,Leave}CriticalSection from
130      * OSX callback threads, so we use OSX's OSSpinLock for synchronization
131      * instead. OSSpinLock is not a recursive lock, so don't call
132      * synchronized functions while holding the lock. */
133     OSSpinLock lock;
134 };
135
136 enum PlayingStates {
137     StateStopped = 0,
138     StatePlaying,
139     StateInTransition
140 };
141
142 static const IAudioClientVtbl AudioClient_Vtbl;
143 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
144 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
145 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
146 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
147 static const IAudioClockVtbl AudioClock_Vtbl;
148 static const IAudioClock2Vtbl AudioClock2_Vtbl;
149
150 static HANDLE g_timer_q;
151
152 static CRITICAL_SECTION g_sessions_lock;
153 static struct list g_sessions = LIST_INIT(g_sessions);
154
155 static HRESULT AudioClock_GetPosition_nolock(ACImpl *This, UINT64 *pos,
156         UINT64 *qpctime, BOOL raw);
157 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
158
159 static inline ACImpl *impl_from_IAudioClient(IAudioClient *iface)
160 {
161     return CONTAINING_RECORD(iface, ACImpl, IAudioClient_iface);
162 }
163
164 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
165 {
166     return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
167 }
168
169 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
170 {
171     return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
172 }
173
174 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
175 {
176     return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
177 }
178
179 static inline ACImpl *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
180 {
181     return CONTAINING_RECORD(iface, ACImpl, ISimpleAudioVolume_iface);
182 }
183
184 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
185 {
186     return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
187 }
188
189 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
190 {
191     return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
192 }
193
194 BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
195 {
196     if(reason == DLL_PROCESS_ATTACH){
197         g_timer_q = CreateTimerQueue();
198         if(!g_timer_q)
199             return FALSE;
200
201         InitializeCriticalSection(&g_sessions_lock);
202     }
203
204     return TRUE;
205 }
206
207 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids,
208         AudioDeviceID ***keys, UINT *num, UINT *def_index)
209 {
210     UInt32 devsize, size;
211     AudioDeviceID *devices;
212     AudioDeviceID default_id;
213     AudioObjectPropertyAddress addr;
214     OSStatus sc;
215     int i, ndevices;
216
217     TRACE("%d %p %p %p\n", flow, ids, num, def_index);
218
219     addr.mScope = kAudioObjectPropertyScopeGlobal;
220     addr.mElement = kAudioObjectPropertyElementMaster;
221     if(flow == eRender)
222         addr.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
223     else if(flow == eCapture)
224         addr.mSelector = kAudioHardwarePropertyDefaultInputDevice;
225     else
226         return E_INVALIDARG;
227
228     size = sizeof(default_id);
229     sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0,
230             NULL, &size, &default_id);
231     if(sc != noErr){
232         WARN("Getting _DefaultInputDevice property failed: %lx\n", sc);
233         default_id = -1;
234     }
235
236     addr.mSelector = kAudioHardwarePropertyDevices;
237     sc = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &addr, 0,
238             NULL, &devsize);
239     if(sc != noErr){
240         WARN("Getting _Devices property size failed: %lx\n", sc);
241         return E_FAIL;
242     }
243
244     devices = HeapAlloc(GetProcessHeap(), 0, devsize);
245     if(!devices)
246         return E_OUTOFMEMORY;
247
248     sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0, NULL,
249             &devsize, devices);
250     if(sc != noErr){
251         WARN("Getting _Devices property failed: %lx\n", sc);
252         HeapFree(GetProcessHeap(), 0, devices);
253         return E_FAIL;
254     }
255
256     ndevices = devsize / sizeof(AudioDeviceID);
257
258     *ids = HeapAlloc(GetProcessHeap(), 0, ndevices * sizeof(WCHAR *));
259     if(!*ids){
260         HeapFree(GetProcessHeap(), 0, devices);
261         return E_OUTOFMEMORY;
262     }
263
264     *keys = HeapAlloc(GetProcessHeap(), 0, ndevices * sizeof(AudioDeviceID *));
265     if(!*ids){
266         HeapFree(GetProcessHeap(), 0, *ids);
267         HeapFree(GetProcessHeap(), 0, devices);
268         return E_OUTOFMEMORY;
269     }
270
271     *num = 0;
272     *def_index = (UINT)-1;
273     for(i = 0; i < ndevices; ++i){
274         AudioBufferList *buffers;
275         CFStringRef name;
276         SIZE_T len;
277         char nameA[256];
278         int j;
279
280         addr.mSelector = kAudioDevicePropertyStreamConfiguration;
281         if(flow == eRender)
282             addr.mScope = kAudioDevicePropertyScopeOutput;
283         else
284             addr.mScope = kAudioDevicePropertyScopeInput;
285         addr.mElement = 0;
286         sc = AudioObjectGetPropertyDataSize(devices[i], &addr, 0, NULL, &size);
287         if(sc != noErr){
288             WARN("Unable to get _StreamConfiguration property size for "
289                     "device %lu: %lx\n", devices[i], sc);
290             continue;
291         }
292
293         buffers = HeapAlloc(GetProcessHeap(), 0, size);
294         if(!buffers){
295             HeapFree(GetProcessHeap(), 0, devices);
296             for(j = 0; j < *num; ++j)
297                 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
298             HeapFree(GetProcessHeap(), 0, *keys);
299             HeapFree(GetProcessHeap(), 0, *ids);
300             return E_OUTOFMEMORY;
301         }
302
303         sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL,
304                 &size, buffers);
305         if(sc != noErr){
306             WARN("Unable to get _StreamConfiguration property for "
307                     "device %lu: %lx\n", devices[i], sc);
308             HeapFree(GetProcessHeap(), 0, buffers);
309             continue;
310         }
311
312         /* check that there's at least one channel in this device before
313          * we claim it as usable */
314         for(j = 0; j < buffers->mNumberBuffers; ++j)
315             if(buffers->mBuffers[j].mNumberChannels > 0)
316                 break;
317         if(j >= buffers->mNumberBuffers){
318             HeapFree(GetProcessHeap(), 0, buffers);
319             continue;
320         }
321
322         HeapFree(GetProcessHeap(), 0, buffers);
323
324         size = sizeof(name);
325         addr.mSelector = kAudioObjectPropertyName;
326         sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL,
327                 &size, &name);
328         if(sc != noErr){
329             WARN("Unable to get _Name property for device %lu: %lx\n",
330                     devices[i], sc);
331             continue;
332         }
333
334         if(!CFStringGetCString(name, nameA, sizeof(nameA),
335                     kCFStringEncodingUTF8)){
336             WARN("Error converting string to UTF8\n");
337             CFRelease(name);
338             continue;
339         }
340
341         CFRelease(name);
342
343         len = MultiByteToWideChar(CP_UNIXCP, 0, nameA, -1, NULL, 0);
344         (*ids)[*num] = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
345         if(!(*ids)[*num]){
346             HeapFree(GetProcessHeap(), 0, devices);
347             for(j = 0; j < *num; ++j){
348                 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
349                 HeapFree(GetProcessHeap(), 0, (*keys)[j]);
350             }
351             HeapFree(GetProcessHeap(), 0, *ids);
352             HeapFree(GetProcessHeap(), 0, *keys);
353             return E_OUTOFMEMORY;
354         }
355         MultiByteToWideChar(CP_UNIXCP, 0, nameA, -1, (*ids)[*num], len);
356
357         (*keys)[*num] = HeapAlloc(GetProcessHeap(), 0, sizeof(AudioDeviceID));
358         if(!(*ids)[*num]){
359             HeapFree(GetProcessHeap(), 0, devices);
360             HeapFree(GetProcessHeap(), 0, (*ids)[*num]);
361             for(j = 0; j < *num; ++j){
362                 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
363                 HeapFree(GetProcessHeap(), 0, (*keys)[j]);
364             }
365             HeapFree(GetProcessHeap(), 0, *ids);
366             HeapFree(GetProcessHeap(), 0, *keys);
367             return E_OUTOFMEMORY;
368         }
369         *(*keys)[*num] = devices[i];
370
371         if(*def_index == (UINT)-1 && devices[i] == default_id)
372             *def_index = *num;
373
374         (*num)++;
375     }
376
377     if(*def_index == (UINT)-1)
378         *def_index = 0;
379
380     HeapFree(GetProcessHeap(), 0, devices);
381
382     return S_OK;
383 }
384
385 HRESULT WINAPI AUDDRV_GetAudioEndpoint(AudioDeviceID *adevid, IMMDevice *dev,
386         EDataFlow dataflow, IAudioClient **out)
387 {
388     ACImpl *This;
389
390     TRACE("%p %d %p\n", dev, dataflow, out);
391
392     This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACImpl));
393     if(!This)
394         return E_OUTOFMEMORY;
395
396     This->IAudioClient_iface.lpVtbl = &AudioClient_Vtbl;
397     This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
398     This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
399     This->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
400     This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
401     This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
402
403     This->dataflow = dataflow;
404
405     This->lock = 0;
406
407     This->parent = dev;
408     IMMDevice_AddRef(This->parent);
409
410     list_init(&This->avail_buffers);
411
412     This->adevid = *adevid;
413
414     *out = &This->IAudioClient_iface;
415     IAudioClient_AddRef(&This->IAudioClient_iface);
416
417     return S_OK;
418 }
419
420 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient *iface,
421         REFIID riid, void **ppv)
422 {
423     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
424
425     if(!ppv)
426         return E_POINTER;
427     *ppv = NULL;
428     if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClient))
429         *ppv = iface;
430     if(*ppv){
431         IUnknown_AddRef((IUnknown*)*ppv);
432         return S_OK;
433     }
434     WARN("Unknown interface %s\n", debugstr_guid(riid));
435     return E_NOINTERFACE;
436 }
437
438 static ULONG WINAPI AudioClient_AddRef(IAudioClient *iface)
439 {
440     ACImpl *This = impl_from_IAudioClient(iface);
441     ULONG ref;
442     ref = InterlockedIncrement(&This->ref);
443     TRACE("(%p) Refcount now %u\n", This, ref);
444     return ref;
445 }
446
447 static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
448 {
449     ACImpl *This = impl_from_IAudioClient(iface);
450     ULONG ref;
451     ref = InterlockedDecrement(&This->ref);
452     TRACE("(%p) Refcount now %u\n", This, ref);
453     if(!ref){
454         IAudioClient_Stop(iface);
455         if(This->aqueue)
456             AudioQueueDispose(This->aqueue, 1);
457         if(This->session){
458             EnterCriticalSection(&g_sessions_lock);
459             list_remove(&This->entry);
460             if(list_empty(&This->session->clients)){
461                 list_remove(&This->session->entry);
462                 HeapFree(GetProcessHeap(), 0, This->session);
463             }
464             LeaveCriticalSection(&g_sessions_lock);
465         }
466         HeapFree(GetProcessHeap(), 0, This->public_buffer);
467         CoTaskMemFree(This->fmt);
468         IMMDevice_Release(This->parent);
469         HeapFree(GetProcessHeap(), 0, This);
470     }
471     return ref;
472 }
473
474 static void dump_fmt(const WAVEFORMATEX *fmt)
475 {
476     TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
477     switch(fmt->wFormatTag){
478     case WAVE_FORMAT_PCM:
479         TRACE("WAVE_FORMAT_PCM");
480         break;
481     case WAVE_FORMAT_IEEE_FLOAT:
482         TRACE("WAVE_FORMAT_IEEE_FLOAT");
483         break;
484     case WAVE_FORMAT_EXTENSIBLE:
485         TRACE("WAVE_FORMAT_EXTENSIBLE");
486         break;
487     default:
488         TRACE("Unknown");
489         break;
490     }
491     TRACE(")\n");
492
493     TRACE("nChannels: %u\n", fmt->nChannels);
494     TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
495     TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
496     TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
497     TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
498     TRACE("cbSize: %u\n", fmt->cbSize);
499
500     if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
501         WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
502         TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
503         TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
504         TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
505     }
506 }
507
508 static DWORD get_channel_mask(unsigned int channels)
509 {
510     switch(channels){
511     case 0:
512         return 0;
513     case 1:
514         return SPEAKER_FRONT_CENTER;
515     case 2:
516         return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
517     case 3:
518         return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT |
519             SPEAKER_LOW_FREQUENCY;
520     case 4:
521         return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
522             SPEAKER_BACK_RIGHT;
523     case 5:
524         return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
525             SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY;
526     case 6:
527         return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
528             SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER;
529     case 7:
530         return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
531             SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER |
532             SPEAKER_BACK_CENTER;
533     }
534     FIXME("Unknown speaker configuration: %u\n", channels);
535     return 0;
536 }
537
538 static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
539 {
540     WAVEFORMATEX *ret;
541     size_t size;
542
543     if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
544         size = sizeof(WAVEFORMATEXTENSIBLE);
545     else
546         size = sizeof(WAVEFORMATEX);
547
548     ret = CoTaskMemAlloc(size);
549     if(!ret)
550         return NULL;
551
552     memcpy(ret, fmt, size);
553
554     ret->cbSize = size - sizeof(WAVEFORMATEX);
555
556     return ret;
557 }
558
559 static HRESULT ca_get_audiodesc(AudioStreamBasicDescription *desc,
560         const WAVEFORMATEX *fmt)
561 {
562     const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)fmt;
563
564     if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
565             (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
566              IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
567         desc->mFormatID = kAudioFormatLinearPCM;
568         if(fmt->wBitsPerSample > 8)
569             desc->mFormatFlags = kAudioFormatFlagIsSignedInteger;
570     }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
571             (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
572              IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
573         desc->mFormatID = kAudioFormatLinearPCM;
574         desc->mFormatFlags = kAudioFormatFlagIsFloat;
575     }else if(fmt->wFormatTag == WAVE_FORMAT_MULAW ||
576             (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
577              IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_MULAW))){
578         desc->mFormatID = kAudioFormatULaw;
579     }else if(fmt->wFormatTag == WAVE_FORMAT_ALAW ||
580             (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
581              IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_ALAW))){
582         desc->mFormatID = kAudioFormatALaw;
583     }else
584         return AUDCLNT_E_UNSUPPORTED_FORMAT;
585
586     desc->mSampleRate = fmt->nSamplesPerSec;
587     desc->mBytesPerPacket = fmt->nBlockAlign;
588     desc->mFramesPerPacket = 1;
589     desc->mBytesPerFrame = fmt->nBlockAlign;
590     desc->mChannelsPerFrame = fmt->nChannels;
591     desc->mBitsPerChannel = fmt->wBitsPerSample;
592     desc->mReserved = 0;
593
594     return S_OK;
595 }
596
597 static void ca_out_buffer_cb(void *user, AudioQueueRef aqueue,
598         AudioQueueBufferRef buffer)
599 {
600     ACImpl *This = user;
601     AQBuffer *buf = buffer->mUserData;
602
603     OSSpinLockLock(&This->lock);
604     list_add_tail(&This->avail_buffers, &buf->entry);
605     This->inbuf_frames -= buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
606     OSSpinLockUnlock(&This->lock);
607 }
608
609 static void ca_in_buffer_cb(void *user, AudioQueueRef aqueue,
610         AudioQueueBufferRef buffer, const AudioTimeStamp *start,
611         UInt32 ndesc, const AudioStreamPacketDescription *descs)
612 {
613     ACImpl *This = user;
614     AQBuffer *buf = buffer->mUserData;
615
616     OSSpinLockLock(&This->lock);
617     list_add_tail(&This->avail_buffers, &buf->entry);
618     This->inbuf_frames += buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
619     OSSpinLockUnlock(&This->lock);
620 }
621
622 static HRESULT ca_setup_aqueue(AudioDeviceID did, EDataFlow flow,
623         const WAVEFORMATEX *fmt, void *user, AudioQueueRef *aqueue)
624 {
625     AudioStreamBasicDescription desc;
626     AudioObjectPropertyAddress addr;
627     CFStringRef uid;
628     OSStatus sc;
629     HRESULT hr;
630     UInt32 size;
631
632     addr.mScope = kAudioObjectPropertyScopeGlobal;
633     addr.mElement = 0;
634     addr.mSelector = kAudioDevicePropertyDeviceUID;
635
636     size = sizeof(uid);
637     sc = AudioObjectGetPropertyData(did, &addr, 0, NULL, &size, &uid);
638     if(sc != noErr){
639         WARN("Unable to get _DeviceUID property: %lx\n", sc);
640         return E_FAIL;
641     }
642
643     hr = ca_get_audiodesc(&desc, fmt);
644     if(FAILED(hr)){
645         CFRelease(uid);
646         return hr;
647     }
648
649     if(flow == eRender)
650         sc = AudioQueueNewOutput(&desc, ca_out_buffer_cb, user, NULL, NULL, 0,
651                 aqueue);
652     else if(flow == eCapture)
653         sc = AudioQueueNewInput(&desc, ca_in_buffer_cb, user, NULL, NULL, 0,
654                 aqueue);
655     else{
656         CFRelease(uid);
657         return E_UNEXPECTED;
658     }
659     if(sc != noErr){
660         WARN("Unable to create AudioQueue: %lx\n", sc);
661         CFRelease(uid);
662         return E_FAIL;
663     }
664
665     sc = AudioQueueSetProperty(*aqueue, kAudioQueueProperty_CurrentDevice,
666             &uid, sizeof(uid));
667     if(sc != noErr){
668         CFRelease(uid);
669         return E_FAIL;
670     }
671
672     CFRelease(uid);
673
674     return S_OK;
675 }
676
677 static AudioSession *create_session(const GUID *guid, EDataFlow flow)
678 {
679     AudioSession *ret;
680
681     ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
682     if(!ret)
683         return NULL;
684
685     memcpy(&ret->guid, guid, sizeof(GUID));
686
687     ret->dataflow = flow;
688
689     list_init(&ret->clients);
690
691     list_add_head(&g_sessions, &ret->entry);
692
693     return ret;
694 }
695
696 static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
697         AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
698         REFERENCE_TIME period, const WAVEFORMATEX *fmt,
699         const GUID *sessionguid)
700 {
701     ACImpl *This = impl_from_IAudioClient(iface);
702     HRESULT hr;
703     OSStatus sc;
704
705     TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
706           wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
707
708     if(!fmt)
709         return E_POINTER;
710
711     dump_fmt(fmt);
712
713     if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
714         return AUDCLNT_E_NOT_INITIALIZED;
715
716     if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
717                 AUDCLNT_STREAMFLAGS_LOOPBACK |
718                 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
719                 AUDCLNT_STREAMFLAGS_NOPERSIST |
720                 AUDCLNT_STREAMFLAGS_RATEADJUST |
721                 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
722                 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
723                 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED)){
724         TRACE("Unknown flags: %08x\n", flags);
725         return E_INVALIDARG;
726     }
727
728     OSSpinLockLock(&This->lock);
729
730     if(This->aqueue){
731         OSSpinLockUnlock(&This->lock);
732         return AUDCLNT_E_ALREADY_INITIALIZED;
733     }
734
735     hr = ca_setup_aqueue(This->adevid, This->dataflow, fmt, This, &This->aqueue);
736     if(FAILED(hr)){
737         OSSpinLockUnlock(&This->lock);
738         return hr;
739     }
740
741     This->fmt = clone_format(fmt);
742     if(!This->fmt){
743         AudioQueueDispose(This->aqueue, 1);
744         This->aqueue = NULL;
745         OSSpinLockUnlock(&This->lock);
746         return E_OUTOFMEMORY;
747     }
748
749     if(period){
750         This->period_ms = period / 10000;
751         if(This->period_ms == 0)
752             This->period_ms = 1;
753     }else
754         This->period_ms = MinimumPeriod / 10000;
755
756     This->bufsize_frames = ceil(fmt->nSamplesPerSec * (duration / 10000000.));
757
758     if(This->dataflow == eCapture){
759         int i;
760         UInt32 bsize = ceil((This->bufsize_frames / (double)CAPTURE_BUFFERS) *
761                 This->fmt->nBlockAlign);
762         for(i = 0; i < CAPTURE_BUFFERS; ++i){
763             AQBuffer *buf;
764
765             buf = HeapAlloc(GetProcessHeap(), 0, sizeof(AQBuffer));
766             if(!buf){
767                 AudioQueueDispose(This->aqueue, 1);
768                 This->aqueue = NULL;
769                 CoTaskMemFree(This->fmt);
770                 This->fmt = NULL;
771                 OSSpinLockUnlock(&This->lock);
772                 return E_OUTOFMEMORY;
773             }
774
775             sc = AudioQueueAllocateBuffer(This->aqueue, bsize, &buf->buf);
776             if(sc != noErr){
777                 AudioQueueDispose(This->aqueue, 1);
778                 This->aqueue = NULL;
779                 CoTaskMemFree(This->fmt);
780                 This->fmt = NULL;
781                 OSSpinLockUnlock(&This->lock);
782                 WARN("Couldn't allocate buffer: %lx\n", sc);
783                 return E_FAIL;
784             }
785
786             buf->buf->mUserData = buf;
787
788             sc = AudioQueueEnqueueBuffer(This->aqueue, buf->buf, 0, NULL);
789             if(sc != noErr){
790                 ERR("Couldn't enqueue buffer: %lx\n", sc);
791                 break;
792             }
793         }
794     }
795
796     This->share = mode;
797     This->flags = flags;
798
799     EnterCriticalSection(&g_sessions_lock);
800
801     if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
802         This->session = create_session(&GUID_NULL, This->dataflow);
803         if(!This->session){
804             LeaveCriticalSection(&g_sessions_lock);
805             AudioQueueDispose(This->aqueue, 1);
806             This->aqueue = NULL;
807             CoTaskMemFree(This->fmt);
808             This->fmt = NULL;
809             OSSpinLockUnlock(&This->lock);
810             return E_OUTOFMEMORY;
811         }
812     }else{
813         AudioSession *session;
814
815         LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry)
816             if(IsEqualGUID(sessionguid, &session->guid) &&
817                     This->dataflow == session->dataflow)
818                 This->session = session;
819
820         if(!This->session){
821             This->session = create_session(sessionguid, This->dataflow);
822             if(!This->session){
823                 LeaveCriticalSection(&g_sessions_lock);
824                 AudioQueueDispose(This->aqueue, 1);
825                 This->aqueue = NULL;
826                 CoTaskMemFree(This->fmt);
827                 This->fmt = NULL;
828                 OSSpinLockUnlock(&This->lock);
829                 return E_OUTOFMEMORY;
830             }
831         }
832     }
833
834     list_add_tail(&This->session->clients, &This->entry);
835
836     LeaveCriticalSection(&g_sessions_lock);
837
838     OSSpinLockUnlock(&This->lock);
839
840     return S_OK;
841 }
842
843 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
844         UINT32 *frames)
845 {
846     ACImpl *This = impl_from_IAudioClient(iface);
847
848     TRACE("(%p)->(%p)\n", This, frames);
849
850     if(!frames)
851         return E_POINTER;
852
853     OSSpinLockLock(&This->lock);
854
855     if(!This->aqueue){
856         OSSpinLockUnlock(&This->lock);
857         return AUDCLNT_E_NOT_INITIALIZED;
858     }
859
860     *frames = This->bufsize_frames;
861
862     OSSpinLockUnlock(&This->lock);
863
864     return S_OK;
865 }
866
867 static HRESULT ca_get_max_stream_latency(ACImpl *This, UInt32 *max)
868 {
869     AudioObjectPropertyAddress addr;
870     AudioStreamID *ids;
871     UInt32 size;
872     OSStatus sc;
873     int nstreams, i;
874
875     if(This->dataflow == eRender)
876         addr.mScope = kAudioDevicePropertyScopeOutput;
877     else if(This->dataflow == eCapture)
878         addr.mScope = kAudioDevicePropertyScopeInput;
879     else
880         return E_UNEXPECTED;
881     addr.mElement = 0;
882     addr.mSelector = kAudioDevicePropertyStreams;
883
884     sc = AudioObjectGetPropertyDataSize(This->adevid, &addr, 0, NULL,
885             &size);
886     if(sc != noErr){
887         WARN("Unable to get size for _Streams property: %lx\n", sc);
888         return E_FAIL;
889     }
890
891     ids = HeapAlloc(GetProcessHeap(), 0, size);
892     if(!ids)
893         return E_OUTOFMEMORY;
894
895     sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL, &size, ids);
896     if(sc != noErr){
897         WARN("Unable to get _Streams property: %lx\n", sc);
898         HeapFree(GetProcessHeap(), 0, ids);
899         return E_FAIL;
900     }
901
902     nstreams = size / sizeof(AudioStreamID);
903     *max = 0;
904
905     addr.mSelector = kAudioStreamPropertyLatency;
906     for(i = 0; i < nstreams; ++i){
907         UInt32 latency;
908
909         size = sizeof(latency);
910         sc = AudioObjectGetPropertyData(ids[i], &addr, 0, NULL,
911                 &size, &latency);
912         if(sc != noErr){
913             WARN("Unable to get _Latency property: %lx\n", sc);
914             continue;
915         }
916
917         if(latency > *max)
918             *max = latency;
919     }
920
921     HeapFree(GetProcessHeap(), 0, ids);
922
923     return S_OK;
924 }
925
926 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
927         REFERENCE_TIME *out)
928 {
929     ACImpl *This = impl_from_IAudioClient(iface);
930     UInt32 latency, stream_latency, size;
931     AudioObjectPropertyAddress addr;
932     OSStatus sc;
933     HRESULT hr;
934
935     TRACE("(%p)->(%p)\n", This, out);
936
937     if(!out)
938         return E_POINTER;
939
940     OSSpinLockLock(&This->lock);
941
942     if(!This->aqueue){
943         OSSpinLockUnlock(&This->lock);
944         return AUDCLNT_E_NOT_INITIALIZED;
945     }
946
947     if(This->dataflow == eRender)
948         addr.mScope = kAudioDevicePropertyScopeOutput;
949     else if(This->dataflow == eCapture)
950         addr.mScope = kAudioDevicePropertyScopeInput;
951     else{
952         OSSpinLockUnlock(&This->lock);
953         return E_UNEXPECTED;
954     }
955     addr.mSelector = kAudioDevicePropertyLatency;
956     addr.mElement = 0;
957
958     size = sizeof(latency);
959     sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL,
960             &size, &latency);
961     if(sc != noErr){
962         WARN("Couldn't get _Latency property: %lx\n", sc);
963         OSSpinLockUnlock(&This->lock);
964         return E_FAIL;
965     }
966
967     hr = ca_get_max_stream_latency(This, &stream_latency);
968     if(FAILED(hr)){
969         OSSpinLockUnlock(&This->lock);
970         return hr;
971     }
972
973     latency += stream_latency;
974     *out = (latency / (double)This->fmt->nSamplesPerSec) * 10000000;
975
976     OSSpinLockUnlock(&This->lock);
977
978     return S_OK;
979 }
980
981 static HRESULT AudioClient_GetCurrentPadding_nolock(ACImpl *This,
982         UINT32 *numpad)
983 {
984     if(!This->aqueue)
985         return AUDCLNT_E_NOT_INITIALIZED;
986
987     *numpad = This->inbuf_frames;
988
989     return S_OK;
990 }
991
992 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
993         UINT32 *numpad)
994 {
995     ACImpl *This = impl_from_IAudioClient(iface);
996     HRESULT hr;
997
998     TRACE("(%p)->(%p)\n", This, numpad);
999
1000     if(!numpad)
1001         return E_POINTER;
1002
1003     OSSpinLockLock(&This->lock);
1004
1005     hr = AudioClient_GetCurrentPadding_nolock(This, numpad);
1006
1007     OSSpinLockUnlock(&This->lock);
1008
1009     return hr;
1010 }
1011
1012 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
1013         AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
1014         WAVEFORMATEX **outpwfx)
1015 {
1016     ACImpl *This = impl_from_IAudioClient(iface);
1017     AudioQueueRef aqueue;
1018     HRESULT hr;
1019
1020     TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx);
1021
1022     if(!pwfx || (mode == AUDCLNT_SHAREMODE_SHARED && !outpwfx))
1023         return E_POINTER;
1024
1025     if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1026         return E_INVALIDARG;
1027
1028     if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1029             pwfx->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1030         return E_INVALIDARG;
1031
1032     dump_fmt(pwfx);
1033
1034     OSSpinLockLock(&This->lock);
1035
1036     hr = ca_setup_aqueue(This->adevid, This->dataflow, pwfx, NULL, &aqueue);
1037     if(SUCCEEDED(hr)){
1038         AudioQueueDispose(aqueue, 1);
1039         OSSpinLockUnlock(&This->lock);
1040         if(outpwfx)
1041             *outpwfx = NULL;
1042         TRACE("returning %08x\n", S_OK);
1043         return S_OK;
1044     }
1045
1046     OSSpinLockUnlock(&This->lock);
1047
1048     if(outpwfx)
1049         *outpwfx = NULL;
1050
1051     TRACE("returning %08x\n", AUDCLNT_E_UNSUPPORTED_FORMAT);
1052     return AUDCLNT_E_UNSUPPORTED_FORMAT;
1053 }
1054
1055 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
1056         WAVEFORMATEX **pwfx)
1057 {
1058     ACImpl *This = impl_from_IAudioClient(iface);
1059     WAVEFORMATEXTENSIBLE *fmt;
1060     OSStatus sc;
1061     UInt32 size;
1062     Float64 rate;
1063     AudioBufferList *buffers;
1064     AudioObjectPropertyAddress addr;
1065     int i;
1066
1067     TRACE("(%p)->(%p)\n", This, pwfx);
1068
1069     if(!pwfx)
1070         return E_POINTER;
1071
1072     *pwfx = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEXTENSIBLE));
1073     if(!*pwfx)
1074         return E_OUTOFMEMORY;
1075
1076     fmt = (WAVEFORMATEXTENSIBLE*)*pwfx;
1077
1078     fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1079
1080     if(This->dataflow == eRender)
1081         addr.mScope = kAudioDevicePropertyScopeOutput;
1082     else if(This->dataflow == eCapture)
1083         addr.mScope = kAudioDevicePropertyScopeInput;
1084     else{
1085         OSSpinLockUnlock(&This->lock);
1086         return E_UNEXPECTED;
1087     }
1088     addr.mElement = 0;
1089     addr.mSelector = kAudioDevicePropertyStreamConfiguration;
1090
1091     sc = AudioObjectGetPropertyDataSize(This->adevid, &addr, 0, NULL, &size);
1092     if(sc != noErr){
1093         HeapFree(GetProcessHeap(), 0, fmt);
1094         WARN("Unable to get size for _StreamConfiguration property: %lx\n", sc);
1095         return E_FAIL;
1096     }
1097
1098     buffers = HeapAlloc(GetProcessHeap(), 0, size);
1099     if(!buffers){
1100         HeapFree(GetProcessHeap(), 0, fmt);
1101         return E_OUTOFMEMORY;
1102     }
1103
1104     sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL,
1105             &size, buffers);
1106     if(sc != noErr){
1107         HeapFree(GetProcessHeap(), 0, fmt);
1108         HeapFree(GetProcessHeap(), 0, buffers);
1109         WARN("Unable to get _StreamConfiguration property: %lx\n", sc);
1110         return E_FAIL;
1111     }
1112
1113     fmt->Format.nChannels = 0;
1114     for(i = 0; i < buffers->mNumberBuffers; ++i)
1115         fmt->Format.nChannels += buffers->mBuffers[i].mNumberChannels;
1116
1117     HeapFree(GetProcessHeap(), 0, buffers);
1118
1119     fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
1120
1121     addr.mSelector = kAudioDevicePropertyNominalSampleRate;
1122     size = sizeof(Float64);
1123     sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL, &size, &rate);
1124     if(sc != noErr){
1125         HeapFree(GetProcessHeap(), 0, fmt);
1126         WARN("Unable to get _NominalSampleRate property: %lx\n", sc);
1127         return E_FAIL;
1128     }
1129     fmt->Format.nSamplesPerSec = rate;
1130
1131     /* CoreAudio doesn't seem to give a device format preference, so just
1132      * choose a common format... */
1133     fmt->Format.wBitsPerSample = 16;
1134     fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1135
1136     fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
1137             fmt->Format.nChannels) / 8;
1138     fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
1139         fmt->Format.nBlockAlign;
1140
1141     fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
1142     fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1143
1144     dump_fmt(*pwfx);
1145
1146     return S_OK;
1147 }
1148
1149 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
1150         REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1151 {
1152     ACImpl *This = impl_from_IAudioClient(iface);
1153
1154     TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
1155
1156     if(!defperiod && !minperiod)
1157         return E_POINTER;
1158
1159     OSSpinLockLock(&This->lock);
1160
1161     if(This->period_ms){
1162         if(defperiod)
1163             *defperiod = This->period_ms * 10000;
1164         if(minperiod)
1165             *minperiod = This->period_ms * 10000;
1166     }else{
1167         if(defperiod)
1168             *defperiod = DefaultPeriod;
1169         if(minperiod)
1170             *minperiod = MinimumPeriod;
1171     }
1172
1173     OSSpinLockUnlock(&This->lock);
1174
1175     return S_OK;
1176 }
1177
1178 void CALLBACK ca_period_cb(void *user, BOOLEAN timer)
1179 {
1180     ACImpl *This = user;
1181
1182     OSSpinLockLock(&This->lock);
1183     if(This->event)
1184         SetEvent(This->event);
1185     OSSpinLockUnlock(&This->lock);
1186 }
1187
1188 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
1189 {
1190     ACImpl *This = impl_from_IAudioClient(iface);
1191     OSStatus sc;
1192
1193     TRACE("(%p)\n", This);
1194
1195     OSSpinLockLock(&This->lock);
1196
1197     if(!This->aqueue){
1198         OSSpinLockUnlock(&This->lock);
1199         return AUDCLNT_E_NOT_INITIALIZED;
1200     }
1201
1202     if(This->playing != StateStopped){
1203         OSSpinLockUnlock(&This->lock);
1204         return AUDCLNT_E_NOT_STOPPED;
1205     }
1206
1207     if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
1208         OSSpinLockUnlock(&This->lock);
1209         return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1210     }
1211
1212     if(This->event)
1213         if(!CreateTimerQueueTimer(&This->timer, g_timer_q,
1214                     ca_period_cb, This, 0, This->period_ms, 0))
1215             ERR("Unable to create timer: %u\n", GetLastError());
1216
1217     This->playing = StateInTransition;
1218
1219     OSSpinLockUnlock(&This->lock);
1220
1221     sc = AudioQueueStart(This->aqueue, NULL);
1222     if(sc != noErr){
1223         WARN("Unable to start audio queue: %lx\n", sc);
1224         return E_FAIL;
1225     }
1226
1227     OSSpinLockLock(&This->lock);
1228
1229     This->playing = StatePlaying;
1230
1231     OSSpinLockUnlock(&This->lock);
1232
1233     return S_OK;
1234 }
1235
1236 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
1237 {
1238     ACImpl *This = impl_from_IAudioClient(iface);
1239     OSStatus sc;
1240
1241     TRACE("(%p)\n", This);
1242
1243     OSSpinLockLock(&This->lock);
1244
1245     if(!This->aqueue){
1246         OSSpinLockUnlock(&This->lock);
1247         return AUDCLNT_E_NOT_INITIALIZED;
1248     }
1249
1250     if(This->playing == StateStopped){
1251         OSSpinLockUnlock(&This->lock);
1252         return S_FALSE;
1253     }
1254
1255     if(This->playing == StateInTransition){
1256         OSSpinLockUnlock(&This->lock);
1257         return S_OK;
1258     }
1259
1260     if(This->timer && This->timer != INVALID_HANDLE_VALUE){
1261         DeleteTimerQueueTimer(g_timer_q, This->timer, INVALID_HANDLE_VALUE);
1262         This->timer = NULL;
1263     }
1264
1265     This->playing = StateInTransition;
1266
1267     OSSpinLockUnlock(&This->lock);
1268
1269     sc = AudioQueueFlush(This->aqueue);
1270     if(sc != noErr)
1271         WARN("Unable to flush audio queue: %lx\n", sc);
1272
1273     sc = AudioQueuePause(This->aqueue);
1274     if(sc != noErr){
1275         WARN("Unable to pause audio queue: %lx\n", sc);
1276         return E_FAIL;
1277     }
1278
1279     OSSpinLockLock(&This->lock);
1280
1281     This->playing = StateStopped;
1282
1283     OSSpinLockUnlock(&This->lock);
1284
1285     return S_OK;
1286 }
1287
1288 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
1289 {
1290     ACImpl *This = impl_from_IAudioClient(iface);
1291     HRESULT hr;
1292     OSStatus sc;
1293
1294     TRACE("(%p)\n", This);
1295
1296     OSSpinLockLock(&This->lock);
1297
1298     if(!This->aqueue){
1299         OSSpinLockUnlock(&This->lock);
1300         return AUDCLNT_E_NOT_INITIALIZED;
1301     }
1302
1303     if(This->playing != StateStopped){
1304         OSSpinLockUnlock(&This->lock);
1305         return AUDCLNT_E_NOT_STOPPED;
1306     }
1307
1308     This->written_frames = 0;
1309
1310     hr = AudioClock_GetPosition_nolock(This, &This->last_time, NULL, TRUE);
1311     if(FAILED(hr)){
1312         OSSpinLockUnlock(&This->lock);
1313         return hr;
1314     }
1315
1316     OSSpinLockUnlock(&This->lock);
1317
1318     sc = AudioQueueReset(This->aqueue);
1319     if(sc != noErr){
1320         WARN("Unable to reset audio queue: %lx\n", sc);
1321         return E_FAIL;
1322     }
1323
1324     return S_OK;
1325 }
1326
1327 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1328         HANDLE event)
1329 {
1330     ACImpl *This = impl_from_IAudioClient(iface);
1331
1332     TRACE("(%p)->(%p)\n", This, event);
1333
1334     if(!event)
1335         return E_INVALIDARG;
1336
1337     OSSpinLockLock(&This->lock);
1338
1339     if(!This->aqueue){
1340         OSSpinLockUnlock(&This->lock);
1341         return AUDCLNT_E_NOT_INITIALIZED;
1342     }
1343
1344     if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
1345         OSSpinLockUnlock(&This->lock);
1346         return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1347     }
1348
1349     This->event = event;
1350
1351     OSSpinLockUnlock(&This->lock);
1352
1353     return S_OK;
1354 }
1355
1356 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1357         void **ppv)
1358 {
1359     ACImpl *This = impl_from_IAudioClient(iface);
1360
1361     TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1362
1363     if(!ppv)
1364         return E_POINTER;
1365     *ppv = NULL;
1366
1367     OSSpinLockLock(&This->lock);
1368
1369     if(!This->aqueue){
1370         OSSpinLockUnlock(&This->lock);
1371         return AUDCLNT_E_NOT_INITIALIZED;
1372     }
1373
1374     if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1375         if(This->dataflow != eRender){
1376             OSSpinLockUnlock(&This->lock);
1377             return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1378         }
1379         *ppv = &This->IAudioRenderClient_iface;
1380     }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1381         if(This->dataflow != eCapture){
1382             OSSpinLockUnlock(&This->lock);
1383             return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1384         }
1385         *ppv = &This->IAudioCaptureClient_iface;
1386     }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1387         if(!This->session_wrapper){
1388             This->session_wrapper = AudioSessionWrapper_Create(This);
1389             if(!This->session_wrapper){
1390                 OSSpinLockUnlock(&This->lock);
1391                 return E_OUTOFMEMORY;
1392             }
1393         }
1394
1395         *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1396     }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1397         *ppv = &This->ISimpleAudioVolume_iface;
1398     }else if(IsEqualIID(riid, &IID_IAudioClock)){
1399         *ppv = &This->IAudioClock_iface;
1400     }
1401
1402     if(*ppv){
1403         IUnknown_AddRef((IUnknown*)*ppv);
1404         OSSpinLockUnlock(&This->lock);
1405         return S_OK;
1406     }
1407
1408     OSSpinLockUnlock(&This->lock);
1409
1410     FIXME("stub %s\n", debugstr_guid(riid));
1411     return E_NOINTERFACE;
1412 }
1413
1414 static const IAudioClientVtbl AudioClient_Vtbl =
1415 {
1416     AudioClient_QueryInterface,
1417     AudioClient_AddRef,
1418     AudioClient_Release,
1419     AudioClient_Initialize,
1420     AudioClient_GetBufferSize,
1421     AudioClient_GetStreamLatency,
1422     AudioClient_GetCurrentPadding,
1423     AudioClient_IsFormatSupported,
1424     AudioClient_GetMixFormat,
1425     AudioClient_GetDevicePeriod,
1426     AudioClient_Start,
1427     AudioClient_Stop,
1428     AudioClient_Reset,
1429     AudioClient_SetEventHandle,
1430     AudioClient_GetService
1431 };
1432
1433 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1434         IAudioRenderClient *iface, REFIID riid, void **ppv)
1435 {
1436     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1437
1438     if(!ppv)
1439         return E_POINTER;
1440     *ppv = NULL;
1441
1442     if(IsEqualIID(riid, &IID_IUnknown) ||
1443             IsEqualIID(riid, &IID_IAudioRenderClient))
1444         *ppv = iface;
1445     if(*ppv){
1446         IUnknown_AddRef((IUnknown*)*ppv);
1447         return S_OK;
1448     }
1449
1450     WARN("Unknown interface %s\n", debugstr_guid(riid));
1451     return E_NOINTERFACE;
1452 }
1453
1454 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1455 {
1456     ACImpl *This = impl_from_IAudioRenderClient(iface);
1457     return AudioClient_AddRef(&This->IAudioClient_iface);
1458 }
1459
1460 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1461 {
1462     ACImpl *This = impl_from_IAudioRenderClient(iface);
1463     return AudioClient_Release(&This->IAudioClient_iface);
1464 }
1465
1466 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1467         UINT32 frames, BYTE **data)
1468 {
1469     ACImpl *This = impl_from_IAudioRenderClient(iface);
1470     AQBuffer *buf;
1471     UINT32 pad, bytes = frames * This->fmt->nBlockAlign;
1472     HRESULT hr;
1473     OSStatus sc;
1474
1475     TRACE("(%p)->(%u, %p)\n", This, frames, data);
1476
1477     if(!data)
1478         return E_POINTER;
1479
1480     OSSpinLockLock(&This->lock);
1481
1482     if(This->getbuf_last){
1483         OSSpinLockUnlock(&This->lock);
1484         return AUDCLNT_E_OUT_OF_ORDER;
1485     }
1486
1487     if(!frames){
1488         This->getbuf_last = TRUE;
1489         OSSpinLockUnlock(&This->lock);
1490         return S_OK;
1491     }
1492
1493     hr = AudioClient_GetCurrentPadding_nolock(This, &pad);
1494     if(FAILED(hr)){
1495         OSSpinLockUnlock(&This->lock);
1496         return hr;
1497     }
1498
1499     if(pad + frames > This->bufsize_frames){
1500         OSSpinLockUnlock(&This->lock);
1501         return AUDCLNT_E_BUFFER_TOO_LARGE;
1502     }
1503
1504     LIST_FOR_EACH_ENTRY(buf, &This->avail_buffers, AQBuffer, entry){
1505         if(buf->buf->mAudioDataBytesCapacity >= bytes){
1506             This->public_buffer = buf->buf;
1507             list_remove(&buf->entry);
1508             break;
1509         }
1510     }
1511
1512     if(&buf->entry == &This->avail_buffers){
1513         sc = AudioQueueAllocateBuffer(This->aqueue, bytes,
1514                 &This->public_buffer);
1515         if(sc != noErr){
1516             OSSpinLockUnlock(&This->lock);
1517             WARN("Unable to allocate buffer: %lx\n", sc);
1518             return E_FAIL;
1519         }
1520         buf = HeapAlloc(GetProcessHeap(), 0, sizeof(AQBuffer));
1521         if(!buf){
1522             AudioQueueFreeBuffer(This->aqueue, This->public_buffer);
1523             This->public_buffer = NULL;
1524             OSSpinLockUnlock(&This->lock);
1525             return E_OUTOFMEMORY;
1526         }
1527         buf->buf = This->public_buffer;
1528         This->public_buffer->mUserData = buf;
1529     }
1530
1531     *data = This->public_buffer->mAudioData;
1532
1533     This->getbuf_last = TRUE;
1534
1535     OSSpinLockUnlock(&This->lock);
1536
1537     return S_OK;
1538 }
1539
1540 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1541         IAudioRenderClient *iface, UINT32 frames, DWORD flags)
1542 {
1543     ACImpl *This = impl_from_IAudioRenderClient(iface);
1544     OSStatus sc;
1545
1546     TRACE("(%p)->(%u, %x)\n", This, frames, flags);
1547
1548     OSSpinLockLock(&This->lock);
1549
1550     if(!This->getbuf_last){
1551         OSSpinLockUnlock(&This->lock);
1552         return AUDCLNT_E_OUT_OF_ORDER;
1553     }
1554
1555     if(flags & AUDCLNT_BUFFERFLAGS_SILENT){
1556         WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)This->fmt;
1557         if((This->fmt->wFormatTag == WAVE_FORMAT_PCM ||
1558                 (This->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1559                  IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) &&
1560                 This->fmt->wBitsPerSample == 8)
1561             memset(This->public_buffer->mAudioData, 128,
1562                     frames * This->fmt->nBlockAlign);
1563         else
1564             memset(This->public_buffer->mAudioData, 0,
1565                     frames * This->fmt->nBlockAlign);
1566     }
1567
1568     This->public_buffer->mAudioDataByteSize = frames * This->fmt->nBlockAlign;
1569
1570     sc = AudioQueueEnqueueBuffer(This->aqueue, This->public_buffer, 0, NULL);
1571     if(sc != noErr){
1572         OSSpinLockUnlock(&This->lock);
1573         WARN("Unable to enqueue buffer: %lx\n", sc);
1574         return E_FAIL;
1575     }
1576
1577     if(This->playing == StateStopped)
1578         AudioQueuePrime(This->aqueue, 0, NULL);
1579
1580     This->public_buffer = NULL;
1581     This->getbuf_last = FALSE;
1582     This->written_frames += frames;
1583     This->inbuf_frames += frames;
1584
1585     OSSpinLockUnlock(&This->lock);
1586
1587     return S_OK;
1588 }
1589
1590 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1591     AudioRenderClient_QueryInterface,
1592     AudioRenderClient_AddRef,
1593     AudioRenderClient_Release,
1594     AudioRenderClient_GetBuffer,
1595     AudioRenderClient_ReleaseBuffer
1596 };
1597
1598 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1599         IAudioCaptureClient *iface, REFIID riid, void **ppv)
1600 {
1601     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1602
1603     if(!ppv)
1604         return E_POINTER;
1605     *ppv = NULL;
1606
1607     if(IsEqualIID(riid, &IID_IUnknown) ||
1608             IsEqualIID(riid, &IID_IAudioCaptureClient))
1609         *ppv = iface;
1610     if(*ppv){
1611         IUnknown_AddRef((IUnknown*)*ppv);
1612         return S_OK;
1613     }
1614
1615     WARN("Unknown interface %s\n", debugstr_guid(riid));
1616     return E_NOINTERFACE;
1617 }
1618
1619 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1620 {
1621     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1622     return IAudioClient_AddRef(&This->IAudioClient_iface);
1623 }
1624
1625 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1626 {
1627     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1628     return IAudioClient_Release(&This->IAudioClient_iface);
1629 }
1630
1631 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1632         BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1633         UINT64 *qpcpos)
1634 {
1635     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1636
1637     TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1638             devpos, qpcpos);
1639
1640     if(!data || !frames || !flags)
1641         return E_POINTER;
1642
1643     OSSpinLockLock(&This->lock);
1644
1645     if(This->getbuf_last){
1646         OSSpinLockUnlock(&This->lock);
1647         return AUDCLNT_E_OUT_OF_ORDER;
1648     }
1649
1650     if(This->public_buffer){
1651         *data = This->public_buffer->mAudioData;
1652         *frames =
1653             This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
1654     }else{
1655         struct list *head = list_head(&This->avail_buffers);
1656         if(!head){
1657             *data = NULL;
1658             *frames = 0;
1659         }else{
1660             AQBuffer *buf = LIST_ENTRY(head, AQBuffer, entry);
1661             This->public_buffer = buf->buf;
1662             *data = This->public_buffer->mAudioData;
1663             *frames =
1664                 This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
1665             list_remove(&buf->entry);
1666         }
1667     }
1668
1669     *flags = 0;
1670     This->written_frames += *frames;
1671     This->inbuf_frames -= *frames;
1672     This->getbuf_last = TRUE;
1673
1674     if(devpos || qpcpos)
1675         AudioClock_GetPosition_nolock(This, devpos, qpcpos, FALSE);
1676
1677     OSSpinLockUnlock(&This->lock);
1678
1679     return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
1680 }
1681
1682 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1683         IAudioCaptureClient *iface, UINT32 done)
1684 {
1685     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1686     UINT32 pbuf_frames =
1687         This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
1688     OSStatus sc;
1689
1690     TRACE("(%p)->(%u)\n", This, done);
1691
1692     OSSpinLockLock(&This->lock);
1693
1694     if(!This->getbuf_last){
1695         OSSpinLockUnlock(&This->lock);
1696         return AUDCLNT_E_OUT_OF_ORDER;
1697     }
1698
1699     if(done != 0 && done != pbuf_frames){
1700         OSSpinLockUnlock(&This->lock);
1701         return AUDCLNT_E_INVALID_SIZE;
1702     }
1703
1704     if(done){
1705         sc = AudioQueueEnqueueBuffer(This->aqueue, This->public_buffer,
1706                 0, NULL);
1707         if(sc != noErr)
1708             WARN("Unable to enqueue buffer: %lx\n", sc);
1709         This->public_buffer = NULL;
1710     }
1711
1712     This->getbuf_last = FALSE;
1713
1714     OSSpinLockUnlock(&This->lock);
1715
1716     return S_OK;
1717 }
1718
1719 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1720         IAudioCaptureClient *iface, UINT32 *frames)
1721 {
1722     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1723     struct list *head;
1724     AQBuffer *buf;
1725
1726     TRACE("(%p)->(%p)\n", This, frames);
1727
1728     if(!frames)
1729         return E_POINTER;
1730
1731     OSSpinLockLock(&This->lock);
1732
1733     head = list_head(&This->avail_buffers);
1734
1735     if(!head){
1736         *frames = This->bufsize_frames / CAPTURE_BUFFERS;
1737         OSSpinLockUnlock(&This->lock);
1738         return S_OK;
1739     }
1740
1741     buf = LIST_ENTRY(head, AQBuffer, entry);
1742     *frames = buf->buf->mAudioDataByteSize / This->fmt->nBlockAlign;
1743
1744     OSSpinLockUnlock(&This->lock);
1745
1746     return S_OK;
1747 }
1748
1749 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1750 {
1751     AudioCaptureClient_QueryInterface,
1752     AudioCaptureClient_AddRef,
1753     AudioCaptureClient_Release,
1754     AudioCaptureClient_GetBuffer,
1755     AudioCaptureClient_ReleaseBuffer,
1756     AudioCaptureClient_GetNextPacketSize
1757 };
1758
1759 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1760         REFIID riid, void **ppv)
1761 {
1762     ACImpl *This = impl_from_IAudioClock(iface);
1763
1764     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1765
1766     if(!ppv)
1767         return E_POINTER;
1768     *ppv = NULL;
1769
1770     if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
1771         *ppv = iface;
1772     else if(IsEqualIID(riid, &IID_IAudioClock2))
1773         *ppv = &This->IAudioClock2_iface;
1774     if(*ppv){
1775         IUnknown_AddRef((IUnknown*)*ppv);
1776         return S_OK;
1777     }
1778
1779     WARN("Unknown interface %s\n", debugstr_guid(riid));
1780     return E_NOINTERFACE;
1781 }
1782
1783 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
1784 {
1785     ACImpl *This = impl_from_IAudioClock(iface);
1786     return IAudioClient_AddRef(&This->IAudioClient_iface);
1787 }
1788
1789 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
1790 {
1791     ACImpl *This = impl_from_IAudioClock(iface);
1792     return IAudioClient_Release(&This->IAudioClient_iface);
1793 }
1794
1795 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
1796 {
1797     ACImpl *This = impl_from_IAudioClock(iface);
1798
1799     TRACE("(%p)->(%p)\n", This, freq);
1800
1801     *freq = This->fmt->nSamplesPerSec;
1802
1803     return S_OK;
1804 }
1805
1806 static HRESULT AudioClock_GetPosition_nolock(ACImpl *This,
1807         UINT64 *pos, UINT64 *qpctime, BOOL raw)
1808 {
1809     AudioTimeStamp time;
1810     OSStatus sc;
1811
1812     sc = AudioQueueGetCurrentTime(This->aqueue, NULL, &time, NULL);
1813     if(sc == kAudioQueueErr_InvalidRunState){
1814         *pos = 0;
1815     }else if(sc == noErr){
1816         if(!(time.mFlags & kAudioTimeStampSampleTimeValid)){
1817             FIXME("Sample time not valid, should calculate from something else\n");
1818             return E_FAIL;
1819         }
1820
1821         if(raw)
1822             *pos = time.mSampleTime;
1823         else
1824             *pos = time.mSampleTime - This->last_time;
1825     }else{
1826         WARN("Unable to get current time: %lx\n", sc);
1827         return E_FAIL;
1828     }
1829
1830     if(qpctime){
1831         LARGE_INTEGER stamp, freq;
1832         QueryPerformanceCounter(&stamp);
1833         QueryPerformanceFrequency(&freq);
1834         *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
1835     }
1836
1837     return S_OK;
1838 }
1839
1840 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
1841         UINT64 *qpctime)
1842 {
1843     ACImpl *This = impl_from_IAudioClock(iface);
1844     HRESULT hr;
1845
1846     TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
1847
1848     if(!pos)
1849         return E_POINTER;
1850
1851     OSSpinLockLock(&This->lock);
1852
1853     hr = AudioClock_GetPosition_nolock(This, pos, qpctime, FALSE);
1854
1855     OSSpinLockUnlock(&This->lock);
1856
1857     return hr;
1858 }
1859
1860 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
1861         DWORD *chars)
1862 {
1863     ACImpl *This = impl_from_IAudioClock(iface);
1864
1865     TRACE("(%p)->(%p)\n", This, chars);
1866
1867     if(!chars)
1868         return E_POINTER;
1869
1870     *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
1871
1872     return S_OK;
1873 }
1874
1875 static const IAudioClockVtbl AudioClock_Vtbl =
1876 {
1877     AudioClock_QueryInterface,
1878     AudioClock_AddRef,
1879     AudioClock_Release,
1880     AudioClock_GetFrequency,
1881     AudioClock_GetPosition,
1882     AudioClock_GetCharacteristics
1883 };
1884
1885 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
1886         REFIID riid, void **ppv)
1887 {
1888     ACImpl *This = impl_from_IAudioClock2(iface);
1889     return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
1890 }
1891
1892 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
1893 {
1894     ACImpl *This = impl_from_IAudioClock2(iface);
1895     return IAudioClient_AddRef(&This->IAudioClient_iface);
1896 }
1897
1898 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
1899 {
1900     ACImpl *This = impl_from_IAudioClock2(iface);
1901     return IAudioClient_Release(&This->IAudioClient_iface);
1902 }
1903
1904 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
1905         UINT64 *pos, UINT64 *qpctime)
1906 {
1907     ACImpl *This = impl_from_IAudioClock2(iface);
1908
1909     FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
1910
1911     return E_NOTIMPL;
1912 }
1913
1914 static const IAudioClock2Vtbl AudioClock2_Vtbl =
1915 {
1916     AudioClock2_QueryInterface,
1917     AudioClock2_AddRef,
1918     AudioClock2_Release,
1919     AudioClock2_GetDevicePosition
1920 };
1921
1922 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
1923 {
1924     AudioSessionWrapper *ret;
1925
1926     ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1927             sizeof(AudioSessionWrapper));
1928     if(!ret)
1929         return NULL;
1930
1931     ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
1932
1933     ret->client = client;
1934     ret->session = client->session;
1935     AudioClient_AddRef(&client->IAudioClient_iface);
1936
1937     return ret;
1938 }
1939
1940 static HRESULT WINAPI AudioSessionControl_QueryInterface(
1941         IAudioSessionControl2 *iface, REFIID riid, void **ppv)
1942 {
1943     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1944
1945     if(!ppv)
1946         return E_POINTER;
1947     *ppv = NULL;
1948
1949     if(IsEqualIID(riid, &IID_IUnknown) ||
1950             IsEqualIID(riid, &IID_IAudioSessionControl) ||
1951             IsEqualIID(riid, &IID_IAudioSessionControl2))
1952         *ppv = iface;
1953     if(*ppv){
1954         IUnknown_AddRef((IUnknown*)*ppv);
1955         return S_OK;
1956     }
1957
1958     WARN("Unknown interface %s\n", debugstr_guid(riid));
1959     return E_NOINTERFACE;
1960 }
1961
1962 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
1963 {
1964     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1965     ULONG ref;
1966     ref = InterlockedIncrement(&This->ref);
1967     TRACE("(%p) Refcount now %u\n", This, ref);
1968     return ref;
1969 }
1970
1971 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
1972 {
1973     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1974     ULONG ref;
1975     ref = InterlockedDecrement(&This->ref);
1976     TRACE("(%p) Refcount now %u\n", This, ref);
1977     if(!ref){
1978         OSSpinLockLock(&This->client->lock);
1979         This->client->session_wrapper = NULL;
1980         OSSpinLockUnlock(&This->client->lock);
1981         AudioClient_Release(&This->client->IAudioClient_iface);
1982         HeapFree(GetProcessHeap(), 0, This);
1983     }
1984     return ref;
1985 }
1986
1987 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
1988         AudioSessionState *state)
1989 {
1990     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1991     ACImpl *client;
1992
1993     TRACE("(%p)->(%p)\n", This, state);
1994
1995     if(!state)
1996         return NULL_PTR_ERR;
1997
1998     EnterCriticalSection(&g_sessions_lock);
1999
2000     if(list_empty(&This->session->clients)){
2001         *state = AudioSessionStateExpired;
2002         LeaveCriticalSection(&g_sessions_lock);
2003         return S_OK;
2004     }
2005
2006     LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
2007         OSSpinLockLock(&client->lock);
2008         if(client->playing == StatePlaying ||
2009                 client->playing == StateInTransition){
2010             *state = AudioSessionStateActive;
2011             OSSpinLockUnlock(&client->lock);
2012             LeaveCriticalSection(&g_sessions_lock);
2013             return S_OK;
2014         }
2015         OSSpinLockUnlock(&client->lock);
2016     }
2017
2018     LeaveCriticalSection(&g_sessions_lock);
2019
2020     *state = AudioSessionStateInactive;
2021
2022     return S_OK;
2023 }
2024
2025 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
2026         IAudioSessionControl2 *iface, WCHAR **name)
2027 {
2028     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2029
2030     FIXME("(%p)->(%p) - stub\n", This, name);
2031
2032     return E_NOTIMPL;
2033 }
2034
2035 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
2036         IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
2037 {
2038     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2039
2040     FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
2041
2042     return E_NOTIMPL;
2043 }
2044
2045 static HRESULT WINAPI AudioSessionControl_GetIconPath(
2046         IAudioSessionControl2 *iface, WCHAR **path)
2047 {
2048     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2049
2050     FIXME("(%p)->(%p) - stub\n", This, path);
2051
2052     return E_NOTIMPL;
2053 }
2054
2055 static HRESULT WINAPI AudioSessionControl_SetIconPath(
2056         IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
2057 {
2058     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2059
2060     FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
2061
2062     return E_NOTIMPL;
2063 }
2064
2065 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
2066         IAudioSessionControl2 *iface, GUID *group)
2067 {
2068     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2069
2070     FIXME("(%p)->(%p) - stub\n", This, group);
2071
2072     return E_NOTIMPL;
2073 }
2074
2075 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
2076         IAudioSessionControl2 *iface, GUID *group, const GUID *session)
2077 {
2078     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2079
2080     FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
2081             debugstr_guid(session));
2082
2083     return E_NOTIMPL;
2084 }
2085
2086 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
2087         IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2088 {
2089     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2090
2091     FIXME("(%p)->(%p) - stub\n", This, events);
2092
2093     return S_OK;
2094 }
2095
2096 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
2097         IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2098 {
2099     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2100
2101     FIXME("(%p)->(%p) - stub\n", This, events);
2102
2103     return S_OK;
2104 }
2105
2106 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
2107         IAudioSessionControl2 *iface, WCHAR **id)
2108 {
2109     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2110
2111     FIXME("(%p)->(%p) - stub\n", This, id);
2112
2113     return E_NOTIMPL;
2114 }
2115
2116 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
2117         IAudioSessionControl2 *iface, WCHAR **id)
2118 {
2119     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2120
2121     FIXME("(%p)->(%p) - stub\n", This, id);
2122
2123     return E_NOTIMPL;
2124 }
2125
2126 static HRESULT WINAPI AudioSessionControl_GetProcessId(
2127         IAudioSessionControl2 *iface, DWORD *pid)
2128 {
2129     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2130
2131     TRACE("(%p)->(%p)\n", This, pid);
2132
2133     if(!pid)
2134         return E_POINTER;
2135
2136     *pid = GetCurrentProcessId();
2137
2138     return S_OK;
2139 }
2140
2141 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
2142         IAudioSessionControl2 *iface)
2143 {
2144     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2145
2146     TRACE("(%p)\n", This);
2147
2148     return S_FALSE;
2149 }
2150
2151 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
2152         IAudioSessionControl2 *iface, BOOL optout)
2153 {
2154     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2155
2156     TRACE("(%p)->(%d)\n", This, optout);
2157
2158     return S_OK;
2159 }
2160
2161 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
2162 {
2163     AudioSessionControl_QueryInterface,
2164     AudioSessionControl_AddRef,
2165     AudioSessionControl_Release,
2166     AudioSessionControl_GetState,
2167     AudioSessionControl_GetDisplayName,
2168     AudioSessionControl_SetDisplayName,
2169     AudioSessionControl_GetIconPath,
2170     AudioSessionControl_SetIconPath,
2171     AudioSessionControl_GetGroupingParam,
2172     AudioSessionControl_SetGroupingParam,
2173     AudioSessionControl_RegisterAudioSessionNotification,
2174     AudioSessionControl_UnregisterAudioSessionNotification,
2175     AudioSessionControl_GetSessionIdentifier,
2176     AudioSessionControl_GetSessionInstanceIdentifier,
2177     AudioSessionControl_GetProcessId,
2178     AudioSessionControl_IsSystemSoundsSession,
2179     AudioSessionControl_SetDuckingPreference
2180 };
2181
2182 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
2183         ISimpleAudioVolume *iface, REFIID riid, void **ppv)
2184 {
2185     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2186
2187     if(!ppv)
2188         return E_POINTER;
2189     *ppv = NULL;
2190
2191     if(IsEqualIID(riid, &IID_IUnknown) ||
2192             IsEqualIID(riid, &IID_ISimpleAudioVolume))
2193         *ppv = iface;
2194     if(*ppv){
2195         IUnknown_AddRef((IUnknown*)*ppv);
2196         return S_OK;
2197     }
2198
2199     WARN("Unknown interface %s\n", debugstr_guid(riid));
2200     return E_NOINTERFACE;
2201 }
2202
2203 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
2204 {
2205     ACImpl *This = impl_from_ISimpleAudioVolume(iface);
2206     return IAudioClient_AddRef(&This->IAudioClient_iface);
2207 }
2208
2209 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
2210 {
2211     ACImpl *This = impl_from_ISimpleAudioVolume(iface);
2212     return IAudioClient_Release(&This->IAudioClient_iface);
2213 }
2214
2215 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
2216         ISimpleAudioVolume *iface, float level, const GUID *context)
2217 {
2218     ACImpl *This = impl_from_ISimpleAudioVolume(iface);
2219
2220     FIXME("(%p)->(%f, %p) - stub\n", This, level, context);
2221
2222     return E_NOTIMPL;
2223 }
2224
2225 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
2226         ISimpleAudioVolume *iface, float *level)
2227 {
2228     ACImpl *This = impl_from_ISimpleAudioVolume(iface);
2229
2230     FIXME("(%p)->(%p) - stub\n", This, level);
2231
2232     return E_NOTIMPL;
2233 }
2234
2235 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
2236         BOOL mute, const GUID *context)
2237 {
2238     ACImpl *This = impl_from_ISimpleAudioVolume(iface);
2239
2240     FIXME("(%p)->(%u, %p) - stub\n", This, mute, context);
2241
2242     return E_NOTIMPL;
2243 }
2244
2245 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
2246         BOOL *mute)
2247 {
2248     ACImpl *This = impl_from_ISimpleAudioVolume(iface);
2249
2250     FIXME("(%p)->(%p) - stub\n", This, mute);
2251
2252     return E_NOTIMPL;
2253 }
2254
2255 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl  =
2256 {
2257     SimpleAudioVolume_QueryInterface,
2258     SimpleAudioVolume_AddRef,
2259     SimpleAudioVolume_Release,
2260     SimpleAudioVolume_SetMasterVolume,
2261     SimpleAudioVolume_GetMasterVolume,
2262     SimpleAudioVolume_SetMute,
2263     SimpleAudioVolume_GetMute
2264 };