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