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