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