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