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