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