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