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