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