winealsa: Unify the checks for wBitsPerSample.
[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     }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
740             (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
741              IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
742         if(fmt->wBitsPerSample == 32)
743             format = SND_PCM_FORMAT_FLOAT_LE;
744         else if(fmt->wBitsPerSample == 64)
745             format = SND_PCM_FORMAT_FLOAT64_LE;
746         else
747             WARN("Unsupported float size: %u\n", fmt->wBitsPerSample);
748     }else
749         WARN("Unknown wave format: %04x\n", fmt->wFormatTag);
750     return format;
751 }
752
753 static void session_init_vols(AudioSession *session, UINT channels)
754 {
755     if(session->channel_count < channels){
756         UINT i;
757
758         if(session->channel_vols)
759             session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
760                     session->channel_vols, sizeof(float) * channels);
761         else
762             session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
763                     sizeof(float) * channels);
764         if(!session->channel_vols)
765             return;
766
767         for(i = session->channel_count; i < channels; ++i)
768             session->channel_vols[i] = 1.f;
769
770         session->channel_count = channels;
771     }
772 }
773
774 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
775         UINT num_channels)
776 {
777     AudioSession *ret;
778
779     ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
780     if(!ret)
781         return NULL;
782
783     memcpy(&ret->guid, guid, sizeof(GUID));
784
785     ret->device = device;
786
787     list_init(&ret->clients);
788
789     list_add_head(&g_sessions, &ret->entry);
790
791     InitializeCriticalSection(&ret->lock);
792     ret->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": AudioSession.lock");
793
794     session_init_vols(ret, num_channels);
795
796     ret->master_vol = 1.f;
797
798     return ret;
799 }
800
801 /* if channels == 0, then this will return or create a session with
802  * matching dataflow and GUID. otherwise, channels must also match */
803 static HRESULT get_audio_session(const GUID *sessionguid,
804         IMMDevice *device, UINT channels, AudioSession **out)
805 {
806     AudioSession *session;
807
808     if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
809         *out = create_session(&GUID_NULL, device, channels);
810         if(!*out)
811             return E_OUTOFMEMORY;
812
813         return S_OK;
814     }
815
816     *out = NULL;
817     LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
818         if(session->device == device &&
819                 IsEqualGUID(sessionguid, &session->guid)){
820             session_init_vols(session, channels);
821             *out = session;
822             break;
823         }
824     }
825
826     if(!*out){
827         *out = create_session(sessionguid, device, channels);
828         if(!*out)
829             return E_OUTOFMEMORY;
830     }
831
832     return S_OK;
833 }
834
835 static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
836         AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
837         REFERENCE_TIME period, const WAVEFORMATEX *fmt,
838         const GUID *sessionguid)
839 {
840     ACImpl *This = impl_from_IAudioClient(iface);
841     snd_pcm_sw_params_t *sw_params = NULL;
842     snd_pcm_format_t format;
843     unsigned int rate, alsa_period_us;
844     int err, i;
845     HRESULT hr = S_OK;
846
847     TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
848           wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
849
850     if(!fmt)
851         return E_POINTER;
852
853     if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
854         return AUDCLNT_E_NOT_INITIALIZED;
855
856     if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
857                 AUDCLNT_STREAMFLAGS_LOOPBACK |
858                 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
859                 AUDCLNT_STREAMFLAGS_NOPERSIST |
860                 AUDCLNT_STREAMFLAGS_RATEADJUST |
861                 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
862                 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
863                 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED)){
864         TRACE("Unknown flags: %08x\n", flags);
865         return E_INVALIDARG;
866     }
867
868     if(mode == AUDCLNT_SHAREMODE_SHARED){
869         period = DefaultPeriod;
870         if( duration < 3 * period)
871             duration = 3 * period;
872     }else{
873         if(!period)
874             period = DefaultPeriod; /* not minimum */
875         if(period < MinimumPeriod || period > 5000000)
876             return AUDCLNT_E_INVALID_DEVICE_PERIOD;
877         if(duration > 20000000) /* the smaller the period, the lower this limit */
878             return AUDCLNT_E_BUFFER_SIZE_ERROR;
879         if(flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK){
880             if(duration != period)
881                 return AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL;
882             FIXME("EXCLUSIVE mode with EVENTCALLBACK\n");
883             return AUDCLNT_E_DEVICE_IN_USE;
884         }else{
885             if( duration < 8 * period)
886                 duration = 8 * period; /* may grow above 2s */
887         }
888     }
889
890     EnterCriticalSection(&This->lock);
891
892     if(This->initted){
893         LeaveCriticalSection(&This->lock);
894         return AUDCLNT_E_ALREADY_INITIALIZED;
895     }
896
897     dump_fmt(fmt);
898
899     if((err = snd_pcm_hw_params_any(This->pcm_handle, This->hw_params)) < 0){
900         WARN("Unable to get hw_params: %d (%s)\n", err, snd_strerror(err));
901         hr = E_FAIL;
902         goto exit;
903     }
904
905     if((err = snd_pcm_hw_params_set_access(This->pcm_handle, This->hw_params,
906                 SND_PCM_ACCESS_RW_INTERLEAVED)) < 0){
907         WARN("Unable to set access: %d (%s)\n", err, snd_strerror(err));
908         hr = E_FAIL;
909         goto exit;
910     }
911
912     format = alsa_format(fmt);
913     if (format == SND_PCM_FORMAT_UNKNOWN){
914         hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
915         goto exit;
916     }
917
918     if((err = snd_pcm_hw_params_set_format(This->pcm_handle, This->hw_params,
919                 format)) < 0){
920         WARN("Unable to set ALSA format to %u: %d (%s)\n", format, err,
921                 snd_strerror(err));
922         hr = E_FAIL;
923         goto exit;
924     }
925
926     This->alsa_format = format;
927
928     rate = fmt->nSamplesPerSec;
929     if((err = snd_pcm_hw_params_set_rate_near(This->pcm_handle, This->hw_params,
930                 &rate, NULL)) < 0){
931         WARN("Unable to set rate to %u: %d (%s)\n", rate, err,
932                 snd_strerror(err));
933         hr = E_FAIL;
934         goto exit;
935     }
936
937     if((err = snd_pcm_hw_params_set_channels(This->pcm_handle, This->hw_params,
938                 fmt->nChannels)) < 0){
939         WARN("Unable to set channels to %u: %d (%s)\n", fmt->nChannels, err,
940                 snd_strerror(err));
941         hr = E_FAIL;
942         goto exit;
943     }
944
945     This->mmdev_period_rt = period;
946     alsa_period_us = This->mmdev_period_rt / 10;
947     if((err = snd_pcm_hw_params_set_period_time_near(This->pcm_handle,
948                 This->hw_params, &alsa_period_us, NULL)) < 0)
949         WARN("Unable to set period time near %u: %d (%s)\n", alsa_period_us,
950                 err, snd_strerror(err));
951     /* ALSA updates the output variable alsa_period_us */
952
953     This->mmdev_period_frames = MulDiv(fmt->nSamplesPerSec,
954             This->mmdev_period_rt, 10000000);
955
956     This->bufsize_frames = MulDiv(duration, fmt->nSamplesPerSec, 10000000);
957
958     /* Buffer 4 ALSA periods if large enough, else 4 mmdevapi periods */
959     This->alsa_bufsize_frames = This->mmdev_period_frames * 4;
960     if(err < 0 || alsa_period_us < period / 10)
961         err = snd_pcm_hw_params_set_buffer_size_near(This->pcm_handle,
962                 This->hw_params, &This->alsa_bufsize_frames);
963     else{
964         unsigned int periods = 4;
965         err = snd_pcm_hw_params_set_periods_near(This->pcm_handle, This->hw_params, &periods, NULL);
966     }
967     if(err < 0)
968         WARN("Unable to set buffer size: %d (%s)\n", err, snd_strerror(err));
969
970     if((err = snd_pcm_hw_params(This->pcm_handle, This->hw_params)) < 0){
971         WARN("Unable to set hw params: %d (%s)\n", err, snd_strerror(err));
972         hr = E_FAIL;
973         goto exit;
974     }
975
976     if((err = snd_pcm_hw_params_get_period_size(This->hw_params,
977                     &This->alsa_period_frames, NULL)) < 0){
978         WARN("Unable to get period size: %d (%s)\n", err, snd_strerror(err));
979         hr = E_FAIL;
980         goto exit;
981     }
982
983     if((err = snd_pcm_hw_params_get_buffer_size(This->hw_params,
984                     &This->alsa_bufsize_frames)) < 0){
985         WARN("Unable to get buffer size: %d (%s)\n", err, snd_strerror(err));
986         hr = E_FAIL;
987         goto exit;
988     }
989
990     sw_params = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_sw_params_sizeof());
991     if(!sw_params){
992         hr = E_OUTOFMEMORY;
993         goto exit;
994     }
995
996     if((err = snd_pcm_sw_params_current(This->pcm_handle, sw_params)) < 0){
997         WARN("Unable to get sw_params: %d (%s)\n", err, snd_strerror(err));
998         hr = E_FAIL;
999         goto exit;
1000     }
1001
1002     if((err = snd_pcm_sw_params_set_start_threshold(This->pcm_handle,
1003                     sw_params, 1)) < 0){
1004         WARN("Unable set start threshold to 0: %d (%s)\n", err, snd_strerror(err));
1005         hr = E_FAIL;
1006         goto exit;
1007     }
1008
1009     if((err = snd_pcm_sw_params_set_stop_threshold(This->pcm_handle,
1010                     sw_params, This->alsa_bufsize_frames)) < 0){
1011         WARN("Unable set stop threshold to %lu: %d (%s)\n",
1012                 This->alsa_bufsize_frames, err, snd_strerror(err));
1013         hr = E_FAIL;
1014         goto exit;
1015     }
1016
1017     if((err = snd_pcm_sw_params(This->pcm_handle, sw_params)) < 0){
1018         WARN("Unable set sw params: %d (%s)\n", err, snd_strerror(err));
1019         hr = E_FAIL;
1020         goto exit;
1021     }
1022
1023     if((err = snd_pcm_prepare(This->pcm_handle)) < 0){
1024         WARN("Unable to prepare device: %d (%s)\n", err, snd_strerror(err));
1025         hr = E_FAIL;
1026         goto exit;
1027     }
1028
1029     /* Check if the ALSA buffer is so small that it will run out before
1030      * the next MMDevAPI period tick occurs. Allow a little wiggle room
1031      * with 120% of the period time. */
1032     if(This->alsa_bufsize_frames < 1.2 * This->mmdev_period_frames)
1033         FIXME("ALSA buffer time is too small. Expect underruns. (%lu < %u * 1.2)\n",
1034                 This->alsa_bufsize_frames, This->mmdev_period_frames);
1035
1036     This->local_buffer = HeapAlloc(GetProcessHeap(), 0,
1037             This->bufsize_frames * fmt->nBlockAlign);
1038     if(!This->local_buffer){
1039         hr = E_OUTOFMEMORY;
1040         goto exit;
1041     }
1042     if (fmt->wBitsPerSample == 8)
1043         memset(This->local_buffer, 128, This->bufsize_frames * fmt->nBlockAlign);
1044     else
1045         memset(This->local_buffer, 0, This->bufsize_frames * fmt->nBlockAlign);
1046
1047     This->fmt = clone_format(fmt);
1048     if(!This->fmt){
1049         hr = E_OUTOFMEMORY;
1050         goto exit;
1051     }
1052
1053     This->vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float));
1054     if(!This->vols){
1055         hr = E_OUTOFMEMORY;
1056         goto exit;
1057     }
1058
1059     for(i = 0; i < fmt->nChannels; ++i)
1060         This->vols[i] = 1.f;
1061
1062     This->share = mode;
1063     This->flags = flags;
1064
1065     EnterCriticalSection(&g_sessions_lock);
1066
1067     hr = get_audio_session(sessionguid, This->parent, fmt->nChannels,
1068             &This->session);
1069     if(FAILED(hr)){
1070         LeaveCriticalSection(&g_sessions_lock);
1071         goto exit;
1072     }
1073
1074     list_add_tail(&This->session->clients, &This->entry);
1075
1076     LeaveCriticalSection(&g_sessions_lock);
1077
1078     This->initted = TRUE;
1079
1080     TRACE("ALSA period: %lu frames\n", This->alsa_period_frames);
1081     TRACE("ALSA buffer: %lu frames\n", This->alsa_bufsize_frames);
1082     TRACE("MMDevice period: %u frames\n", This->mmdev_period_frames);
1083     TRACE("MMDevice buffer: %u frames\n", This->bufsize_frames);
1084
1085 exit:
1086     HeapFree(GetProcessHeap(), 0, sw_params);
1087     if(FAILED(hr)){
1088         HeapFree(GetProcessHeap(), 0, This->local_buffer);
1089         This->local_buffer = NULL;
1090         CoTaskMemFree(This->fmt);
1091         This->fmt = NULL;
1092         HeapFree(GetProcessHeap(), 0, This->vols);
1093         This->vols = NULL;
1094     }
1095
1096     LeaveCriticalSection(&This->lock);
1097
1098     return hr;
1099 }
1100
1101 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
1102         UINT32 *out)
1103 {
1104     ACImpl *This = impl_from_IAudioClient(iface);
1105
1106     TRACE("(%p)->(%p)\n", This, out);
1107
1108     if(!out)
1109         return E_POINTER;
1110
1111     EnterCriticalSection(&This->lock);
1112
1113     if(!This->initted){
1114         LeaveCriticalSection(&This->lock);
1115         return AUDCLNT_E_NOT_INITIALIZED;
1116     }
1117
1118     *out = This->bufsize_frames;
1119
1120     LeaveCriticalSection(&This->lock);
1121
1122     return S_OK;
1123 }
1124
1125 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
1126         REFERENCE_TIME *latency)
1127 {
1128     ACImpl *This = impl_from_IAudioClient(iface);
1129
1130     TRACE("(%p)->(%p)\n", This, latency);
1131
1132     if(!latency)
1133         return E_POINTER;
1134
1135     EnterCriticalSection(&This->lock);
1136
1137     if(!This->initted){
1138         LeaveCriticalSection(&This->lock);
1139         return AUDCLNT_E_NOT_INITIALIZED;
1140     }
1141
1142     LeaveCriticalSection(&This->lock);
1143
1144     /* one mmdevapi period plus one period we hide in the ALSA buffer */
1145     *latency = MulDiv(This->alsa_period_frames, 10000000, This->fmt->nSamplesPerSec)
1146              + This->mmdev_period_rt;
1147
1148     return S_OK;
1149 }
1150
1151 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
1152         UINT32 *out)
1153 {
1154     ACImpl *This = impl_from_IAudioClient(iface);
1155
1156     TRACE("(%p)->(%p)\n", This, out);
1157
1158     if(!out)
1159         return E_POINTER;
1160
1161     EnterCriticalSection(&This->lock);
1162
1163     if(!This->initted){
1164         LeaveCriticalSection(&This->lock);
1165         return AUDCLNT_E_NOT_INITIALIZED;
1166     }
1167
1168     *out = This->held_frames;
1169
1170     /* call required to get accurate snd_pcm_state() */
1171     snd_pcm_avail_update(This->pcm_handle);
1172     TRACE("pad: %u, state: %u\n", *out, snd_pcm_state(This->pcm_handle));
1173
1174     LeaveCriticalSection(&This->lock);
1175
1176     return S_OK;
1177 }
1178
1179 static DWORD get_channel_mask(unsigned int channels)
1180 {
1181     switch(channels){
1182     case 0:
1183         return 0;
1184     case 1:
1185         return KSAUDIO_SPEAKER_MONO;
1186     case 2:
1187         return KSAUDIO_SPEAKER_STEREO;
1188     case 3:
1189         return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY;
1190     case 4:
1191         return KSAUDIO_SPEAKER_QUAD;    /* not _SURROUND */
1192     case 5:
1193         return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY;
1194     case 6:
1195         return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */
1196     case 7:
1197         return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER;
1198     case 8:
1199         return KSAUDIO_SPEAKER_7POINT1; /* not 7POINT1_SURROUND */
1200     }
1201     FIXME("Unknown speaker configuration: %u\n", channels);
1202     return 0;
1203 }
1204
1205 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
1206         AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *fmt,
1207         WAVEFORMATEX **out)
1208 {
1209     ACImpl *This = impl_from_IAudioClient(iface);
1210     snd_pcm_format_mask_t *formats = NULL;
1211     snd_pcm_format_t format;
1212     HRESULT hr = S_OK;
1213     WAVEFORMATEX *closest = NULL;
1214     const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)fmt;
1215     unsigned int max = 0, min = 0;
1216     int err;
1217
1218     TRACE("(%p)->(%x, %p, %p)\n", This, mode, fmt, out);
1219
1220     if(!fmt || (mode == AUDCLNT_SHAREMODE_SHARED && !out))
1221         return E_POINTER;
1222
1223     if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1224         return E_INVALIDARG;
1225
1226     if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1227             fmt->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1228         return E_INVALIDARG;
1229
1230     dump_fmt(fmt);
1231
1232     if(out){
1233         *out = NULL;
1234         if(mode != AUDCLNT_SHAREMODE_SHARED)
1235             out = NULL;
1236     }
1237
1238     EnterCriticalSection(&This->lock);
1239
1240     if((err = snd_pcm_hw_params_any(This->pcm_handle, This->hw_params)) < 0){
1241         hr = E_FAIL;
1242         goto exit;
1243     }
1244
1245     formats = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1246             snd_pcm_format_mask_sizeof());
1247     if(!formats){
1248         hr = E_OUTOFMEMORY;
1249         goto exit;
1250     }
1251
1252     snd_pcm_hw_params_get_format_mask(This->hw_params, formats);
1253     format = alsa_format(fmt);
1254     if (format == SND_PCM_FORMAT_UNKNOWN ||
1255         !snd_pcm_format_mask_test(formats, format)){
1256         hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
1257         goto exit;
1258     }
1259
1260     closest = clone_format(fmt);
1261     if(!closest){
1262         hr = E_OUTOFMEMORY;
1263         goto exit;
1264     }
1265
1266     if((err = snd_pcm_hw_params_get_rate_min(This->hw_params, &min, NULL)) < 0){
1267         hr = E_FAIL;
1268         WARN("Unable to get min rate: %d (%s)\n", err, snd_strerror(err));
1269         goto exit;
1270     }
1271
1272     if((err = snd_pcm_hw_params_get_rate_max(This->hw_params, &max, NULL)) < 0){
1273         hr = E_FAIL;
1274         WARN("Unable to get max rate: %d (%s)\n", err, snd_strerror(err));
1275         goto exit;
1276     }
1277
1278     if(fmt->nSamplesPerSec < min || fmt->nSamplesPerSec > max){
1279         hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
1280         goto exit;
1281     }
1282
1283     if((err = snd_pcm_hw_params_get_channels_min(This->hw_params, &min)) < 0){
1284         hr = E_FAIL;
1285         WARN("Unable to get min channels: %d (%s)\n", err, snd_strerror(err));
1286         goto exit;
1287     }
1288
1289     if((err = snd_pcm_hw_params_get_channels_max(This->hw_params, &max)) < 0){
1290         hr = E_FAIL;
1291         WARN("Unable to get max channels: %d (%s)\n", err, snd_strerror(err));
1292         goto exit;
1293     }
1294     if(max > 8)
1295         max = 2;
1296     if(fmt->nChannels > max){
1297         hr = S_FALSE;
1298         closest->nChannels = max;
1299     }else if(fmt->nChannels < min){
1300         hr = S_FALSE;
1301         closest->nChannels = min;
1302     }
1303
1304     if(closest->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
1305         DWORD mask = get_channel_mask(closest->nChannels);
1306
1307         ((WAVEFORMATEXTENSIBLE*)closest)->dwChannelMask = mask;
1308
1309         if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1310                 fmtex->dwChannelMask != 0 &&
1311                 fmtex->dwChannelMask != mask)
1312             hr = S_FALSE;
1313     }
1314
1315 exit:
1316     LeaveCriticalSection(&This->lock);
1317     HeapFree(GetProcessHeap(), 0, formats);
1318
1319     if(hr == S_FALSE && !out)
1320         hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
1321
1322     if(hr == S_FALSE && out) {
1323         closest->nBlockAlign =
1324             closest->nChannels * closest->wBitsPerSample / 8;
1325         closest->nAvgBytesPerSec =
1326             closest->nBlockAlign * closest->nSamplesPerSec;
1327         *out = closest;
1328     } else
1329         CoTaskMemFree(closest);
1330
1331     TRACE("returning: %08x\n", hr);
1332     return hr;
1333 }
1334
1335 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
1336         WAVEFORMATEX **pwfx)
1337 {
1338     ACImpl *This = impl_from_IAudioClient(iface);
1339     WAVEFORMATEXTENSIBLE *fmt;
1340     snd_pcm_format_mask_t *formats;
1341     unsigned int max_rate, max_channels;
1342     int err;
1343     HRESULT hr = S_OK;
1344
1345     TRACE("(%p)->(%p)\n", This, pwfx);
1346
1347     if(!pwfx)
1348         return E_POINTER;
1349     *pwfx = NULL;
1350
1351     fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
1352     if(!fmt)
1353         return E_OUTOFMEMORY;
1354
1355     formats = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_format_mask_sizeof());
1356     if(!formats){
1357         CoTaskMemFree(fmt);
1358         return E_OUTOFMEMORY;
1359     }
1360
1361     EnterCriticalSection(&This->lock);
1362
1363     if((err = snd_pcm_hw_params_any(This->pcm_handle, This->hw_params)) < 0){
1364         WARN("Unable to get hw_params: %d (%s)\n", err, snd_strerror(err));
1365         hr = E_FAIL;
1366         goto exit;
1367     }
1368
1369     snd_pcm_hw_params_get_format_mask(This->hw_params, formats);
1370
1371     fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1372     if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_FLOAT_LE)){
1373         fmt->Format.wBitsPerSample = 32;
1374         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
1375     }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S16_LE)){
1376         fmt->Format.wBitsPerSample = 16;
1377         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1378     }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_U8)){
1379         fmt->Format.wBitsPerSample = 8;
1380         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1381     }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S32_LE)){
1382         fmt->Format.wBitsPerSample = 32;
1383         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1384     }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S24_3LE)){
1385         fmt->Format.wBitsPerSample = 24;
1386         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1387     }else{
1388         ERR("Didn't recognize any available ALSA formats\n");
1389         hr = E_FAIL;
1390         goto exit;
1391     }
1392
1393     if((err = snd_pcm_hw_params_get_channels_max(This->hw_params,
1394                     &max_channels)) < 0){
1395         WARN("Unable to get max channels: %d (%s)\n", err, snd_strerror(err));
1396         hr = E_FAIL;
1397         goto exit;
1398     }
1399
1400     if(max_channels > 2){
1401         FIXME("Don't know what to do with %u channels, pretending there's "
1402                 "only 2 channels\n", max_channels);
1403         fmt->Format.nChannels = 2;
1404     }else
1405         fmt->Format.nChannels = max_channels;
1406
1407     fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
1408
1409     if((err = snd_pcm_hw_params_get_rate_max(This->hw_params, &max_rate,
1410                     NULL)) < 0){
1411         WARN("Unable to get max rate: %d (%s)\n", err, snd_strerror(err));
1412         hr = E_FAIL;
1413         goto exit;
1414     }
1415
1416     if(max_rate >= 48000)
1417         fmt->Format.nSamplesPerSec = 48000;
1418     else if(max_rate >= 44100)
1419         fmt->Format.nSamplesPerSec = 44100;
1420     else if(max_rate >= 22050)
1421         fmt->Format.nSamplesPerSec = 22050;
1422     else if(max_rate >= 11025)
1423         fmt->Format.nSamplesPerSec = 11025;
1424     else if(max_rate >= 8000)
1425         fmt->Format.nSamplesPerSec = 8000;
1426     else{
1427         ERR("Unknown max rate: %u\n", max_rate);
1428         hr = E_FAIL;
1429         goto exit;
1430     }
1431
1432     fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
1433             fmt->Format.nChannels) / 8;
1434     fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
1435         fmt->Format.nBlockAlign;
1436
1437     fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
1438     fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1439
1440     dump_fmt((WAVEFORMATEX*)fmt);
1441     *pwfx = (WAVEFORMATEX*)fmt;
1442
1443 exit:
1444     LeaveCriticalSection(&This->lock);
1445     if(FAILED(hr))
1446         CoTaskMemFree(fmt);
1447     HeapFree(GetProcessHeap(), 0, formats);
1448
1449     return hr;
1450 }
1451
1452 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
1453         REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1454 {
1455     ACImpl *This = impl_from_IAudioClient(iface);
1456
1457     TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
1458
1459     if(!defperiod && !minperiod)
1460         return E_POINTER;
1461
1462     if(defperiod)
1463         *defperiod = DefaultPeriod;
1464     if(minperiod)
1465         *minperiod = MinimumPeriod;
1466
1467     return S_OK;
1468 }
1469
1470 static snd_pcm_sframes_t alsa_write_best_effort(snd_pcm_t *handle, BYTE *buf,
1471         snd_pcm_uframes_t frames, ACImpl *This)
1472 {
1473     snd_pcm_sframes_t written;
1474
1475     if(This->session->mute){
1476         int err;
1477         if((err = snd_pcm_format_set_silence(This->alsa_format, buf,
1478                         frames * This->fmt->nChannels)) < 0)
1479             WARN("Setting buffer to silence failed: %d (%s)\n", err,
1480                     snd_strerror(err));
1481     }
1482
1483     written = snd_pcm_writei(handle, buf, frames);
1484     if(written < 0){
1485         int ret;
1486
1487         if(written == -EAGAIN)
1488             /* buffer full */
1489             return 0;
1490
1491         WARN("writei failed, recovering: %ld (%s)\n", written,
1492                 snd_strerror(written));
1493
1494         ret = snd_pcm_recover(handle, written, 0);
1495         if(ret < 0){
1496             WARN("Could not recover: %d (%s)\n", ret, snd_strerror(ret));
1497             return ret;
1498         }
1499
1500         written = snd_pcm_writei(handle, buf, frames);
1501     }
1502
1503     return written;
1504 }
1505
1506 static void alsa_write_data(ACImpl *This)
1507 {
1508     snd_pcm_sframes_t written;
1509     snd_pcm_uframes_t to_write, avail, write_limit, max_period, in_alsa;
1510     int err;
1511     BYTE *buf =
1512         This->local_buffer + (This->lcl_offs_frames * This->fmt->nBlockAlign);
1513
1514     /* this call seems to be required to get an accurate snd_pcm_state() */
1515     avail = snd_pcm_avail_update(This->pcm_handle);
1516
1517     if(snd_pcm_state(This->pcm_handle) == SND_PCM_STATE_XRUN ||
1518             avail > This->alsa_bufsize_frames){
1519         TRACE("XRun state, recovering\n");
1520
1521         avail = This->alsa_bufsize_frames;
1522
1523         if((err = snd_pcm_recover(This->pcm_handle, -EPIPE, 1)) < 0)
1524             WARN("snd_pcm_recover failed: %d (%s)\n", err, snd_strerror(err));
1525
1526         if((err = snd_pcm_reset(This->pcm_handle)) < 0)
1527             WARN("snd_pcm_reset failed: %d (%s)\n", err, snd_strerror(err));
1528
1529         if((err = snd_pcm_prepare(This->pcm_handle)) < 0)
1530             WARN("snd_pcm_prepare failed: %d (%s)\n", err, snd_strerror(err));
1531     }
1532
1533     if(This->held_frames == 0)
1534         return;
1535
1536     if(This->lcl_offs_frames + This->held_frames > This->bufsize_frames)
1537         to_write = This->bufsize_frames - This->lcl_offs_frames;
1538     else
1539         to_write = This->held_frames;
1540
1541     max_period = max(This->mmdev_period_frames, This->alsa_period_frames);
1542
1543     /* try to keep 3 ALSA periods or 3 MMDevAPI periods in the ALSA buffer and
1544      * no more */
1545     write_limit = 0;
1546     in_alsa = This->alsa_bufsize_frames - avail;
1547     while(in_alsa + write_limit < max_period * 3)
1548         write_limit += max_period;
1549     if(write_limit == 0)
1550         return;
1551
1552     to_write = min(to_write, write_limit);
1553
1554     written = alsa_write_best_effort(This->pcm_handle, buf, to_write, This);
1555     if(written < 0){
1556         WARN("Couldn't write: %ld (%s)\n", written, snd_strerror(written));
1557         return;
1558     }
1559
1560     This->lcl_offs_frames += written;
1561     This->lcl_offs_frames %= This->bufsize_frames;
1562     This->held_frames -= written;
1563
1564     if(written < to_write){
1565         /* ALSA buffer probably full */
1566         return;
1567     }
1568
1569     if(This->held_frames && (written < write_limit)){
1570         /* wrapped and have some data back at the start to write */
1571         written = alsa_write_best_effort(This->pcm_handle, This->local_buffer,
1572                 min(This->held_frames, write_limit - written), This);
1573         if(written < 0){
1574             WARN("Couldn't write: %ld (%s)\n", written, snd_strerror(written));
1575             return;
1576         }
1577
1578         This->lcl_offs_frames += written;
1579         This->lcl_offs_frames %= This->bufsize_frames;
1580         This->held_frames -= written;
1581     }
1582 }
1583
1584 static void alsa_read_data(ACImpl *This)
1585 {
1586     snd_pcm_sframes_t pos, readable, nread;
1587
1588     pos = (This->held_frames + This->lcl_offs_frames) % This->bufsize_frames;
1589     readable = This->bufsize_frames - pos;
1590
1591     nread = snd_pcm_readi(This->pcm_handle,
1592             This->local_buffer + pos * This->fmt->nBlockAlign, readable);
1593     if(nread < 0){
1594         int ret;
1595
1596         WARN("read failed, recovering: %ld (%s)\n", nread, snd_strerror(nread));
1597
1598         ret = snd_pcm_recover(This->pcm_handle, nread, 0);
1599         if(ret < 0){
1600             WARN("Recover failed: %d (%s)\n", ret, snd_strerror(ret));
1601             return;
1602         }
1603
1604         nread = snd_pcm_readi(This->pcm_handle,
1605                 This->local_buffer + pos * This->fmt->nBlockAlign, readable);
1606         if(nread < 0){
1607             WARN("read failed: %ld (%s)\n", nread, snd_strerror(nread));
1608             return;
1609         }
1610     }
1611
1612     if(This->session->mute){
1613         int err;
1614         if((err = snd_pcm_format_set_silence(This->alsa_format,
1615                         This->local_buffer + pos * This->fmt->nBlockAlign,
1616                         nread)) < 0)
1617             WARN("Setting buffer to silence failed: %d (%s)\n", err,
1618                     snd_strerror(err));
1619     }
1620
1621     This->held_frames += nread;
1622
1623     if(This->held_frames > This->bufsize_frames){
1624         WARN("Overflow of unread data\n");
1625         This->lcl_offs_frames += This->held_frames;
1626         This->lcl_offs_frames %= This->bufsize_frames;
1627         This->held_frames = This->bufsize_frames;
1628     }
1629 }
1630
1631 static void CALLBACK alsa_push_buffer_data(void *user, BOOLEAN timer)
1632 {
1633     ACImpl *This = user;
1634
1635     EnterCriticalSection(&This->lock);
1636
1637     if(This->started){
1638         if(This->dataflow == eRender)
1639             alsa_write_data(This);
1640         else if(This->dataflow == eCapture)
1641             alsa_read_data(This);
1642
1643         if(This->event)
1644             SetEvent(This->event);
1645     }
1646
1647     LeaveCriticalSection(&This->lock);
1648 }
1649
1650 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
1651 {
1652     ACImpl *This = impl_from_IAudioClient(iface);
1653
1654     TRACE("(%p)\n", This);
1655
1656     EnterCriticalSection(&This->lock);
1657
1658     if(!This->initted){
1659         LeaveCriticalSection(&This->lock);
1660         return AUDCLNT_E_NOT_INITIALIZED;
1661     }
1662
1663     if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
1664         LeaveCriticalSection(&This->lock);
1665         return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1666     }
1667
1668     if(This->started){
1669         LeaveCriticalSection(&This->lock);
1670         return AUDCLNT_E_NOT_STOPPED;
1671     }
1672
1673     if(This->dataflow == eCapture){
1674         /* dump any data that might be leftover in the ALSA capture buffer */
1675         snd_pcm_readi(This->pcm_handle, This->local_buffer,
1676                 This->bufsize_frames);
1677     }
1678
1679     if(!CreateTimerQueueTimer(&This->timer, g_timer_q, alsa_push_buffer_data,
1680             This, 0, This->mmdev_period_rt / 10000, WT_EXECUTEINTIMERTHREAD)){
1681         LeaveCriticalSection(&This->lock);
1682         WARN("Unable to create timer: %u\n", GetLastError());
1683         return E_FAIL;
1684     }
1685
1686     This->started = TRUE;
1687
1688     LeaveCriticalSection(&This->lock);
1689
1690     return S_OK;
1691 }
1692
1693 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
1694 {
1695     ACImpl *This = impl_from_IAudioClient(iface);
1696     HANDLE event;
1697     BOOL wait;
1698
1699     TRACE("(%p)\n", This);
1700
1701     EnterCriticalSection(&This->lock);
1702
1703     if(!This->initted){
1704         LeaveCriticalSection(&This->lock);
1705         return AUDCLNT_E_NOT_INITIALIZED;
1706     }
1707
1708     if(!This->started){
1709         LeaveCriticalSection(&This->lock);
1710         return S_FALSE;
1711     }
1712
1713     if(snd_pcm_drop(This->pcm_handle) < 0)
1714         WARN("snd_pcm_drop failed\n");
1715
1716     if(snd_pcm_reset(This->pcm_handle) < 0)
1717         WARN("snd_pcm_reset failed\n");
1718
1719     if(snd_pcm_prepare(This->pcm_handle) < 0)
1720         WARN("snd_pcm_prepare failed\n");
1721
1722     event = CreateEventW(NULL, TRUE, FALSE, NULL);
1723     wait = !DeleteTimerQueueTimer(g_timer_q, This->timer, event);
1724     if(wait)
1725         WARN("DeleteTimerQueueTimer error %u\n", GetLastError());
1726     wait = wait && GetLastError() == ERROR_IO_PENDING;
1727
1728     This->started = FALSE;
1729
1730     LeaveCriticalSection(&This->lock);
1731
1732     if(event && wait)
1733         WaitForSingleObject(event, INFINITE);
1734     CloseHandle(event);
1735
1736     return S_OK;
1737 }
1738
1739 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
1740 {
1741     ACImpl *This = impl_from_IAudioClient(iface);
1742
1743     TRACE("(%p)\n", This);
1744
1745     EnterCriticalSection(&This->lock);
1746
1747     if(!This->initted){
1748         LeaveCriticalSection(&This->lock);
1749         return AUDCLNT_E_NOT_INITIALIZED;
1750     }
1751
1752     if(This->started){
1753         LeaveCriticalSection(&This->lock);
1754         return AUDCLNT_E_NOT_STOPPED;
1755     }
1756
1757     if(This->buf_state != NOT_LOCKED){
1758         LeaveCriticalSection(&This->lock);
1759         return AUDCLNT_E_BUFFER_OPERATION_PENDING;
1760     }
1761
1762     if(snd_pcm_drop(This->pcm_handle) < 0)
1763         WARN("snd_pcm_drop failed\n");
1764
1765     if(snd_pcm_reset(This->pcm_handle) < 0)
1766         WARN("snd_pcm_reset failed\n");
1767
1768     if(snd_pcm_prepare(This->pcm_handle) < 0)
1769         WARN("snd_pcm_prepare failed\n");
1770
1771     This->last_pos_frames = 0;
1772     This->held_frames = 0;
1773     This->written_frames = 0;
1774     This->lcl_offs_frames = 0;
1775
1776     LeaveCriticalSection(&This->lock);
1777
1778     return S_OK;
1779 }
1780
1781 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1782         HANDLE event)
1783 {
1784     ACImpl *This = impl_from_IAudioClient(iface);
1785
1786     TRACE("(%p)->(%p)\n", This, event);
1787
1788     if(!event)
1789         return E_INVALIDARG;
1790
1791     EnterCriticalSection(&This->lock);
1792
1793     if(!This->initted){
1794         LeaveCriticalSection(&This->lock);
1795         return AUDCLNT_E_NOT_INITIALIZED;
1796     }
1797
1798     if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
1799         LeaveCriticalSection(&This->lock);
1800         return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1801     }
1802
1803     This->event = event;
1804
1805     LeaveCriticalSection(&This->lock);
1806
1807     return S_OK;
1808 }
1809
1810 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1811         void **ppv)
1812 {
1813     ACImpl *This = impl_from_IAudioClient(iface);
1814
1815     TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1816
1817     if(!ppv)
1818         return E_POINTER;
1819     *ppv = NULL;
1820
1821     EnterCriticalSection(&This->lock);
1822
1823     if(!This->initted){
1824         LeaveCriticalSection(&This->lock);
1825         return AUDCLNT_E_NOT_INITIALIZED;
1826     }
1827
1828     if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1829         if(This->dataflow != eRender){
1830             LeaveCriticalSection(&This->lock);
1831             return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1832         }
1833         IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
1834         *ppv = &This->IAudioRenderClient_iface;
1835     }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1836         if(This->dataflow != eCapture){
1837             LeaveCriticalSection(&This->lock);
1838             return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1839         }
1840         IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
1841         *ppv = &This->IAudioCaptureClient_iface;
1842     }else if(IsEqualIID(riid, &IID_IAudioClock)){
1843         IAudioClock_AddRef(&This->IAudioClock_iface);
1844         *ppv = &This->IAudioClock_iface;
1845     }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1846         IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
1847         *ppv = &This->IAudioStreamVolume_iface;
1848     }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1849         if(!This->session_wrapper){
1850             This->session_wrapper = AudioSessionWrapper_Create(This);
1851             if(!This->session_wrapper){
1852                 LeaveCriticalSection(&This->lock);
1853                 return E_OUTOFMEMORY;
1854             }
1855         }else
1856             IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
1857
1858         *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1859     }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1860         if(!This->session_wrapper){
1861             This->session_wrapper = AudioSessionWrapper_Create(This);
1862             if(!This->session_wrapper){
1863                 LeaveCriticalSection(&This->lock);
1864                 return E_OUTOFMEMORY;
1865             }
1866         }else
1867             IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
1868
1869         *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1870     }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1871         if(!This->session_wrapper){
1872             This->session_wrapper = AudioSessionWrapper_Create(This);
1873             if(!This->session_wrapper){
1874                 LeaveCriticalSection(&This->lock);
1875                 return E_OUTOFMEMORY;
1876             }
1877         }else
1878             ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
1879
1880         *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1881     }
1882
1883     if(*ppv){
1884         LeaveCriticalSection(&This->lock);
1885         return S_OK;
1886     }
1887
1888     LeaveCriticalSection(&This->lock);
1889
1890     FIXME("stub %s\n", debugstr_guid(riid));
1891     return E_NOINTERFACE;
1892 }
1893
1894 static const IAudioClientVtbl AudioClient_Vtbl =
1895 {
1896     AudioClient_QueryInterface,
1897     AudioClient_AddRef,
1898     AudioClient_Release,
1899     AudioClient_Initialize,
1900     AudioClient_GetBufferSize,
1901     AudioClient_GetStreamLatency,
1902     AudioClient_GetCurrentPadding,
1903     AudioClient_IsFormatSupported,
1904     AudioClient_GetMixFormat,
1905     AudioClient_GetDevicePeriod,
1906     AudioClient_Start,
1907     AudioClient_Stop,
1908     AudioClient_Reset,
1909     AudioClient_SetEventHandle,
1910     AudioClient_GetService
1911 };
1912
1913 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1914         IAudioRenderClient *iface, REFIID riid, void **ppv)
1915 {
1916     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1917
1918     if(!ppv)
1919         return E_POINTER;
1920     *ppv = NULL;
1921
1922     if(IsEqualIID(riid, &IID_IUnknown) ||
1923             IsEqualIID(riid, &IID_IAudioRenderClient))
1924         *ppv = iface;
1925     if(*ppv){
1926         IUnknown_AddRef((IUnknown*)*ppv);
1927         return S_OK;
1928     }
1929
1930     WARN("Unknown interface %s\n", debugstr_guid(riid));
1931     return E_NOINTERFACE;
1932 }
1933
1934 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1935 {
1936     ACImpl *This = impl_from_IAudioRenderClient(iface);
1937     return AudioClient_AddRef(&This->IAudioClient_iface);
1938 }
1939
1940 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1941 {
1942     ACImpl *This = impl_from_IAudioRenderClient(iface);
1943     return AudioClient_Release(&This->IAudioClient_iface);
1944 }
1945
1946 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1947         UINT32 frames, BYTE **data)
1948 {
1949     ACImpl *This = impl_from_IAudioRenderClient(iface);
1950     UINT32 write_pos;
1951     UINT32 pad;
1952     HRESULT hr;
1953
1954     TRACE("(%p)->(%u, %p)\n", This, frames, data);
1955
1956     if(!data)
1957         return E_POINTER;
1958
1959     EnterCriticalSection(&This->lock);
1960
1961     if(This->buf_state != NOT_LOCKED){
1962         LeaveCriticalSection(&This->lock);
1963         return AUDCLNT_E_OUT_OF_ORDER;
1964     }
1965
1966     if(!frames){
1967         This->buf_state = LOCKED_NORMAL;
1968         LeaveCriticalSection(&This->lock);
1969         return S_OK;
1970     }
1971
1972     hr = IAudioClient_GetCurrentPadding(&This->IAudioClient_iface, &pad);
1973     if(FAILED(hr)){
1974         LeaveCriticalSection(&This->lock);
1975         return hr;
1976     }
1977
1978     if(pad + frames > This->bufsize_frames){
1979         LeaveCriticalSection(&This->lock);
1980         return AUDCLNT_E_BUFFER_TOO_LARGE;
1981     }
1982
1983     write_pos =
1984         (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1985     if(write_pos + frames > This->bufsize_frames){
1986         if(This->tmp_buffer_frames < frames){
1987             HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
1988             This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1989                     frames * This->fmt->nBlockAlign);
1990             if(!This->tmp_buffer){
1991                 LeaveCriticalSection(&This->lock);
1992                 return E_OUTOFMEMORY;
1993             }
1994             This->tmp_buffer_frames = frames;
1995         }
1996         *data = This->tmp_buffer;
1997         This->buf_state = LOCKED_WRAPPED;
1998     }else{
1999         *data = This->local_buffer + write_pos * This->fmt->nBlockAlign;
2000         This->buf_state = LOCKED_NORMAL;
2001     }
2002
2003     LeaveCriticalSection(&This->lock);
2004
2005     return S_OK;
2006 }
2007
2008 static void alsa_wrap_buffer(ACImpl *This, BYTE *buffer, UINT32 written_frames)
2009 {
2010     snd_pcm_uframes_t write_offs_frames =
2011         (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
2012     UINT32 write_offs_bytes = write_offs_frames * This->fmt->nBlockAlign;
2013     snd_pcm_uframes_t chunk_frames = This->bufsize_frames - write_offs_frames;
2014     UINT32 chunk_bytes = chunk_frames * This->fmt->nBlockAlign;
2015     UINT32 written_bytes = written_frames * This->fmt->nBlockAlign;
2016
2017     if(written_bytes <= chunk_bytes){
2018         memcpy(This->local_buffer + write_offs_bytes, buffer, written_bytes);
2019     }else{
2020         memcpy(This->local_buffer + write_offs_bytes, buffer, chunk_bytes);
2021         memcpy(This->local_buffer, buffer + chunk_bytes,
2022                 written_bytes - chunk_bytes);
2023     }
2024 }
2025
2026 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
2027         IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
2028 {
2029     ACImpl *This = impl_from_IAudioRenderClient(iface);
2030     BYTE *buffer;
2031
2032     TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
2033
2034     EnterCriticalSection(&This->lock);
2035
2036     if(This->buf_state == NOT_LOCKED || !written_frames){
2037         This->buf_state = NOT_LOCKED;
2038         LeaveCriticalSection(&This->lock);
2039         return written_frames ? AUDCLNT_E_OUT_OF_ORDER : S_OK;
2040     }
2041
2042     if(This->buf_state == LOCKED_NORMAL)
2043         buffer = This->local_buffer + This->fmt->nBlockAlign *
2044           ((This->lcl_offs_frames + This->held_frames) % This->bufsize_frames);
2045     else
2046         buffer = This->tmp_buffer;
2047
2048     if(flags & AUDCLNT_BUFFERFLAGS_SILENT){
2049         if(This->fmt->wBitsPerSample == 8)
2050             memset(buffer, 128, written_frames * This->fmt->nBlockAlign);
2051         else
2052             memset(buffer, 0, written_frames * This->fmt->nBlockAlign);
2053     }
2054
2055     if(This->buf_state == LOCKED_WRAPPED)
2056         alsa_wrap_buffer(This, buffer, written_frames);
2057
2058     This->held_frames += written_frames;
2059     This->written_frames += written_frames;
2060     This->buf_state = NOT_LOCKED;
2061
2062     LeaveCriticalSection(&This->lock);
2063
2064     return S_OK;
2065 }
2066
2067 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
2068     AudioRenderClient_QueryInterface,
2069     AudioRenderClient_AddRef,
2070     AudioRenderClient_Release,
2071     AudioRenderClient_GetBuffer,
2072     AudioRenderClient_ReleaseBuffer
2073 };
2074
2075 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
2076         IAudioCaptureClient *iface, REFIID riid, void **ppv)
2077 {
2078     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2079
2080     if(!ppv)
2081         return E_POINTER;
2082     *ppv = NULL;
2083
2084     if(IsEqualIID(riid, &IID_IUnknown) ||
2085             IsEqualIID(riid, &IID_IAudioCaptureClient))
2086         *ppv = iface;
2087     if(*ppv){
2088         IUnknown_AddRef((IUnknown*)*ppv);
2089         return S_OK;
2090     }
2091
2092     WARN("Unknown interface %s\n", debugstr_guid(riid));
2093     return E_NOINTERFACE;
2094 }
2095
2096 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
2097 {
2098     ACImpl *This = impl_from_IAudioCaptureClient(iface);
2099     return IAudioClient_AddRef(&This->IAudioClient_iface);
2100 }
2101
2102 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
2103 {
2104     ACImpl *This = impl_from_IAudioCaptureClient(iface);
2105     return IAudioClient_Release(&This->IAudioClient_iface);
2106 }
2107
2108 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
2109         BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
2110         UINT64 *qpcpos)
2111 {
2112     ACImpl *This = impl_from_IAudioCaptureClient(iface);
2113     HRESULT hr;
2114
2115     TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
2116             devpos, qpcpos);
2117
2118     if(!data || !frames || !flags)
2119         return E_POINTER;
2120
2121     EnterCriticalSection(&This->lock);
2122
2123     if(This->buf_state != NOT_LOCKED){
2124         LeaveCriticalSection(&This->lock);
2125         return AUDCLNT_E_OUT_OF_ORDER;
2126     }
2127
2128     hr = IAudioCaptureClient_GetNextPacketSize(iface, frames);
2129     if(FAILED(hr)){
2130         LeaveCriticalSection(&This->lock);
2131         return hr;
2132     }
2133
2134     *flags = 0;
2135
2136     if(This->lcl_offs_frames + *frames > This->bufsize_frames){
2137         UINT32 chunk_bytes, offs_bytes, frames_bytes;
2138         if(This->tmp_buffer_frames < *frames){
2139             HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
2140             This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
2141                     *frames * This->fmt->nBlockAlign);
2142             if(!This->tmp_buffer){
2143                 LeaveCriticalSection(&This->lock);
2144                 return E_OUTOFMEMORY;
2145             }
2146             This->tmp_buffer_frames = *frames;
2147         }
2148
2149         *data = This->tmp_buffer;
2150         chunk_bytes = (This->bufsize_frames - This->lcl_offs_frames) *
2151             This->fmt->nBlockAlign;
2152         offs_bytes = This->lcl_offs_frames * This->fmt->nBlockAlign;
2153         frames_bytes = *frames * This->fmt->nBlockAlign;
2154         memcpy(This->tmp_buffer, This->local_buffer + offs_bytes, chunk_bytes);
2155         memcpy(This->tmp_buffer + chunk_bytes, This->local_buffer,
2156                 frames_bytes - chunk_bytes);
2157     }else
2158         *data = This->local_buffer +
2159             This->lcl_offs_frames * This->fmt->nBlockAlign;
2160
2161     This->buf_state = LOCKED_NORMAL;
2162
2163     if(devpos || qpcpos)
2164         IAudioClock_GetPosition(&This->IAudioClock_iface, devpos, qpcpos);
2165
2166     LeaveCriticalSection(&This->lock);
2167
2168     return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
2169 }
2170
2171 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
2172         IAudioCaptureClient *iface, UINT32 done)
2173 {
2174     ACImpl *This = impl_from_IAudioCaptureClient(iface);
2175
2176     TRACE("(%p)->(%u)\n", This, done);
2177
2178     EnterCriticalSection(&This->lock);
2179
2180     if(This->buf_state == NOT_LOCKED){
2181         LeaveCriticalSection(&This->lock);
2182         return AUDCLNT_E_OUT_OF_ORDER;
2183     }
2184
2185     This->held_frames -= done;
2186     This->lcl_offs_frames += done;
2187     This->lcl_offs_frames %= This->bufsize_frames;
2188
2189     This->buf_state = NOT_LOCKED;
2190
2191     LeaveCriticalSection(&This->lock);
2192
2193     return S_OK;
2194 }
2195
2196 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
2197         IAudioCaptureClient *iface, UINT32 *frames)
2198 {
2199     ACImpl *This = impl_from_IAudioCaptureClient(iface);
2200
2201     TRACE("(%p)->(%p)\n", This, frames);
2202
2203     return AudioClient_GetCurrentPadding(&This->IAudioClient_iface, frames);
2204 }
2205
2206 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
2207 {
2208     AudioCaptureClient_QueryInterface,
2209     AudioCaptureClient_AddRef,
2210     AudioCaptureClient_Release,
2211     AudioCaptureClient_GetBuffer,
2212     AudioCaptureClient_ReleaseBuffer,
2213     AudioCaptureClient_GetNextPacketSize
2214 };
2215
2216 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
2217         REFIID riid, void **ppv)
2218 {
2219     ACImpl *This = impl_from_IAudioClock(iface);
2220
2221     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2222
2223     if(!ppv)
2224         return E_POINTER;
2225     *ppv = NULL;
2226
2227     if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
2228         *ppv = iface;
2229     else if(IsEqualIID(riid, &IID_IAudioClock2))
2230         *ppv = &This->IAudioClock2_iface;
2231     if(*ppv){
2232         IUnknown_AddRef((IUnknown*)*ppv);
2233         return S_OK;
2234     }
2235
2236     WARN("Unknown interface %s\n", debugstr_guid(riid));
2237     return E_NOINTERFACE;
2238 }
2239
2240 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
2241 {
2242     ACImpl *This = impl_from_IAudioClock(iface);
2243     return IAudioClient_AddRef(&This->IAudioClient_iface);
2244 }
2245
2246 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
2247 {
2248     ACImpl *This = impl_from_IAudioClock(iface);
2249     return IAudioClient_Release(&This->IAudioClient_iface);
2250 }
2251
2252 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
2253 {
2254     ACImpl *This = impl_from_IAudioClock(iface);
2255
2256     TRACE("(%p)->(%p)\n", This, freq);
2257
2258     *freq = This->fmt->nSamplesPerSec;
2259
2260     return S_OK;
2261 }
2262
2263 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
2264         UINT64 *qpctime)
2265 {
2266     ACImpl *This = impl_from_IAudioClock(iface);
2267     UINT64 written_frames, position;
2268     UINT32 held_frames;
2269     int err;
2270     snd_pcm_state_t alsa_state;
2271     snd_pcm_uframes_t avail_frames;
2272     snd_pcm_sframes_t delay_frames;
2273
2274     TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
2275
2276     if(!pos)
2277         return E_POINTER;
2278
2279     EnterCriticalSection(&This->lock);
2280
2281     /* call required to get accurate snd_pcm_state() */
2282     avail_frames = snd_pcm_avail_update(This->pcm_handle);
2283     alsa_state = snd_pcm_state(This->pcm_handle);
2284     written_frames = This->written_frames;
2285     held_frames = This->held_frames;
2286
2287     err = snd_pcm_delay(This->pcm_handle, &delay_frames);
2288     if(err < 0){
2289         /* old Pulse, shortly after start */
2290         WARN("snd_pcm_delay failed in state %u: %d (%s)\n", alsa_state, err, snd_strerror(err));
2291     }
2292
2293     if(This->dataflow == eRender){
2294         position = written_frames - held_frames; /* maximum */
2295         if(!This->started || alsa_state > SND_PCM_STATE_RUNNING)
2296             ; /* mmdevapi stopped or ALSA underrun: pretend everything was played */
2297         else if(err<0 || delay_frames > position - This->last_pos_frames)
2298             /* Pulse bug: past underrun, despite recovery, avail_frames & delay
2299              * may be larger than alsa_bufsize_frames, as if cumulating frames. */
2300             /* Pulse bug: EIO(-5) shortly after starting: nothing played */
2301             position = This->last_pos_frames;
2302         else if(delay_frames > 0)
2303             position -= delay_frames;
2304     }else
2305         position = written_frames + held_frames;
2306
2307     /* ensure monotic growth */
2308     This->last_pos_frames = position;
2309
2310     LeaveCriticalSection(&This->lock);
2311
2312     TRACE("frames written: %u, held: %u, avail: %ld, delay: %ld state %d, pos: %u\n",
2313           (UINT32)(written_frames%1000000000), held_frames,
2314           avail_frames, delay_frames, alsa_state, (UINT32)(position%1000000000));
2315     *pos = position;
2316
2317     if(qpctime){
2318         LARGE_INTEGER stamp, freq;
2319         QueryPerformanceCounter(&stamp);
2320         QueryPerformanceFrequency(&freq);
2321         *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
2322     }
2323
2324     return S_OK;
2325 }
2326
2327 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
2328         DWORD *chars)
2329 {
2330     ACImpl *This = impl_from_IAudioClock(iface);
2331
2332     TRACE("(%p)->(%p)\n", This, chars);
2333
2334     if(!chars)
2335         return E_POINTER;
2336
2337     *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
2338
2339     return S_OK;
2340 }
2341
2342 static const IAudioClockVtbl AudioClock_Vtbl =
2343 {
2344     AudioClock_QueryInterface,
2345     AudioClock_AddRef,
2346     AudioClock_Release,
2347     AudioClock_GetFrequency,
2348     AudioClock_GetPosition,
2349     AudioClock_GetCharacteristics
2350 };
2351
2352 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
2353         REFIID riid, void **ppv)
2354 {
2355     ACImpl *This = impl_from_IAudioClock2(iface);
2356     return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
2357 }
2358
2359 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
2360 {
2361     ACImpl *This = impl_from_IAudioClock2(iface);
2362     return IAudioClient_AddRef(&This->IAudioClient_iface);
2363 }
2364
2365 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
2366 {
2367     ACImpl *This = impl_from_IAudioClock2(iface);
2368     return IAudioClient_Release(&This->IAudioClient_iface);
2369 }
2370
2371 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
2372         UINT64 *pos, UINT64 *qpctime)
2373 {
2374     ACImpl *This = impl_from_IAudioClock2(iface);
2375
2376     FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
2377
2378     return E_NOTIMPL;
2379 }
2380
2381 static const IAudioClock2Vtbl AudioClock2_Vtbl =
2382 {
2383     AudioClock2_QueryInterface,
2384     AudioClock2_AddRef,
2385     AudioClock2_Release,
2386     AudioClock2_GetDevicePosition
2387 };
2388
2389 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
2390 {
2391     AudioSessionWrapper *ret;
2392
2393     ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2394             sizeof(AudioSessionWrapper));
2395     if(!ret)
2396         return NULL;
2397
2398     ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
2399     ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
2400     ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
2401
2402     ret->ref = 1;
2403
2404     ret->client = client;
2405     if(client){
2406         ret->session = client->session;
2407         AudioClient_AddRef(&client->IAudioClient_iface);
2408     }
2409
2410     return ret;
2411 }
2412
2413 static HRESULT WINAPI AudioSessionControl_QueryInterface(
2414         IAudioSessionControl2 *iface, REFIID riid, void **ppv)
2415 {
2416     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2417
2418     if(!ppv)
2419         return E_POINTER;
2420     *ppv = NULL;
2421
2422     if(IsEqualIID(riid, &IID_IUnknown) ||
2423             IsEqualIID(riid, &IID_IAudioSessionControl) ||
2424             IsEqualIID(riid, &IID_IAudioSessionControl2))
2425         *ppv = iface;
2426     if(*ppv){
2427         IUnknown_AddRef((IUnknown*)*ppv);
2428         return S_OK;
2429     }
2430
2431     WARN("Unknown interface %s\n", debugstr_guid(riid));
2432     return E_NOINTERFACE;
2433 }
2434
2435 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
2436 {
2437     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2438     ULONG ref;
2439     ref = InterlockedIncrement(&This->ref);
2440     TRACE("(%p) Refcount now %u\n", This, ref);
2441     return ref;
2442 }
2443
2444 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
2445 {
2446     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2447     ULONG ref;
2448     ref = InterlockedDecrement(&This->ref);
2449     TRACE("(%p) Refcount now %u\n", This, ref);
2450     if(!ref){
2451         if(This->client){
2452             EnterCriticalSection(&This->client->lock);
2453             This->client->session_wrapper = NULL;
2454             LeaveCriticalSection(&This->client->lock);
2455             AudioClient_Release(&This->client->IAudioClient_iface);
2456         }
2457         HeapFree(GetProcessHeap(), 0, This);
2458     }
2459     return ref;
2460 }
2461
2462 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
2463         AudioSessionState *state)
2464 {
2465     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2466     ACImpl *client;
2467
2468     TRACE("(%p)->(%p)\n", This, state);
2469
2470     if(!state)
2471         return NULL_PTR_ERR;
2472
2473     EnterCriticalSection(&g_sessions_lock);
2474
2475     if(list_empty(&This->session->clients)){
2476         *state = AudioSessionStateExpired;
2477         LeaveCriticalSection(&g_sessions_lock);
2478         return S_OK;
2479     }
2480
2481     LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
2482         EnterCriticalSection(&client->lock);
2483         if(client->started){
2484             *state = AudioSessionStateActive;
2485             LeaveCriticalSection(&client->lock);
2486             LeaveCriticalSection(&g_sessions_lock);
2487             return S_OK;
2488         }
2489         LeaveCriticalSection(&client->lock);
2490     }
2491
2492     LeaveCriticalSection(&g_sessions_lock);
2493
2494     *state = AudioSessionStateInactive;
2495
2496     return S_OK;
2497 }
2498
2499 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
2500         IAudioSessionControl2 *iface, WCHAR **name)
2501 {
2502     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2503
2504     FIXME("(%p)->(%p) - stub\n", This, name);
2505
2506     return E_NOTIMPL;
2507 }
2508
2509 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
2510         IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
2511 {
2512     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2513
2514     FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
2515
2516     return E_NOTIMPL;
2517 }
2518
2519 static HRESULT WINAPI AudioSessionControl_GetIconPath(
2520         IAudioSessionControl2 *iface, WCHAR **path)
2521 {
2522     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2523
2524     FIXME("(%p)->(%p) - stub\n", This, path);
2525
2526     return E_NOTIMPL;
2527 }
2528
2529 static HRESULT WINAPI AudioSessionControl_SetIconPath(
2530         IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
2531 {
2532     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2533
2534     FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
2535
2536     return E_NOTIMPL;
2537 }
2538
2539 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
2540         IAudioSessionControl2 *iface, GUID *group)
2541 {
2542     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2543
2544     FIXME("(%p)->(%p) - stub\n", This, group);
2545
2546     return E_NOTIMPL;
2547 }
2548
2549 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
2550         IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
2551 {
2552     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2553
2554     FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
2555             debugstr_guid(session));
2556
2557     return E_NOTIMPL;
2558 }
2559
2560 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
2561         IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2562 {
2563     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2564
2565     FIXME("(%p)->(%p) - stub\n", This, events);
2566
2567     return S_OK;
2568 }
2569
2570 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
2571         IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2572 {
2573     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2574
2575     FIXME("(%p)->(%p) - stub\n", This, events);
2576
2577     return S_OK;
2578 }
2579
2580 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
2581         IAudioSessionControl2 *iface, WCHAR **id)
2582 {
2583     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2584
2585     FIXME("(%p)->(%p) - stub\n", This, id);
2586
2587     return E_NOTIMPL;
2588 }
2589
2590 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
2591         IAudioSessionControl2 *iface, WCHAR **id)
2592 {
2593     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2594
2595     FIXME("(%p)->(%p) - stub\n", This, id);
2596
2597     return E_NOTIMPL;
2598 }
2599
2600 static HRESULT WINAPI AudioSessionControl_GetProcessId(
2601         IAudioSessionControl2 *iface, DWORD *pid)
2602 {
2603     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2604
2605     TRACE("(%p)->(%p)\n", This, pid);
2606
2607     if(!pid)
2608         return E_POINTER;
2609
2610     *pid = GetCurrentProcessId();
2611
2612     return S_OK;
2613 }
2614
2615 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
2616         IAudioSessionControl2 *iface)
2617 {
2618     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2619
2620     TRACE("(%p)\n", This);
2621
2622     return S_FALSE;
2623 }
2624
2625 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
2626         IAudioSessionControl2 *iface, BOOL optout)
2627 {
2628     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2629
2630     TRACE("(%p)->(%d)\n", This, optout);
2631
2632     return S_OK;
2633 }
2634
2635 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
2636 {
2637     AudioSessionControl_QueryInterface,
2638     AudioSessionControl_AddRef,
2639     AudioSessionControl_Release,
2640     AudioSessionControl_GetState,
2641     AudioSessionControl_GetDisplayName,
2642     AudioSessionControl_SetDisplayName,
2643     AudioSessionControl_GetIconPath,
2644     AudioSessionControl_SetIconPath,
2645     AudioSessionControl_GetGroupingParam,
2646     AudioSessionControl_SetGroupingParam,
2647     AudioSessionControl_RegisterAudioSessionNotification,
2648     AudioSessionControl_UnregisterAudioSessionNotification,
2649     AudioSessionControl_GetSessionIdentifier,
2650     AudioSessionControl_GetSessionInstanceIdentifier,
2651     AudioSessionControl_GetProcessId,
2652     AudioSessionControl_IsSystemSoundsSession,
2653     AudioSessionControl_SetDuckingPreference
2654 };
2655
2656 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
2657         ISimpleAudioVolume *iface, REFIID riid, void **ppv)
2658 {
2659     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2660
2661     if(!ppv)
2662         return E_POINTER;
2663     *ppv = NULL;
2664
2665     if(IsEqualIID(riid, &IID_IUnknown) ||
2666             IsEqualIID(riid, &IID_ISimpleAudioVolume))
2667         *ppv = iface;
2668     if(*ppv){
2669         IUnknown_AddRef((IUnknown*)*ppv);
2670         return S_OK;
2671     }
2672
2673     WARN("Unknown interface %s\n", debugstr_guid(riid));
2674     return E_NOINTERFACE;
2675 }
2676
2677 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
2678 {
2679     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2680     return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2681 }
2682
2683 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
2684 {
2685     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2686     return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2687 }
2688
2689 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
2690         ISimpleAudioVolume *iface, float level, const GUID *context)
2691 {
2692     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2693     AudioSession *session = This->session;
2694
2695     TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
2696
2697     if(level < 0.f || level > 1.f)
2698         return E_INVALIDARG;
2699
2700     if(context)
2701         FIXME("Notifications not supported yet\n");
2702
2703     TRACE("ALSA does not support volume control\n");
2704
2705     EnterCriticalSection(&session->lock);
2706
2707     session->master_vol = level;
2708
2709     LeaveCriticalSection(&session->lock);
2710
2711     return S_OK;
2712 }
2713
2714 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
2715         ISimpleAudioVolume *iface, float *level)
2716 {
2717     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2718     AudioSession *session = This->session;
2719
2720     TRACE("(%p)->(%p)\n", session, level);
2721
2722     if(!level)
2723         return NULL_PTR_ERR;
2724
2725     *level = session->master_vol;
2726
2727     return S_OK;
2728 }
2729
2730 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
2731         BOOL mute, const GUID *context)
2732 {
2733     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2734     AudioSession *session = This->session;
2735
2736     TRACE("(%p)->(%u, %p)\n", session, mute, context);
2737
2738     if(context)
2739         FIXME("Notifications not supported yet\n");
2740
2741     session->mute = mute;
2742
2743     return S_OK;
2744 }
2745
2746 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
2747         BOOL *mute)
2748 {
2749     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2750     AudioSession *session = This->session;
2751
2752     TRACE("(%p)->(%p)\n", session, mute);
2753
2754     if(!mute)
2755         return NULL_PTR_ERR;
2756
2757     *mute = session->mute;
2758
2759     return S_OK;
2760 }
2761
2762 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl  =
2763 {
2764     SimpleAudioVolume_QueryInterface,
2765     SimpleAudioVolume_AddRef,
2766     SimpleAudioVolume_Release,
2767     SimpleAudioVolume_SetMasterVolume,
2768     SimpleAudioVolume_GetMasterVolume,
2769     SimpleAudioVolume_SetMute,
2770     SimpleAudioVolume_GetMute
2771 };
2772
2773 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
2774         IAudioStreamVolume *iface, REFIID riid, void **ppv)
2775 {
2776     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2777
2778     if(!ppv)
2779         return E_POINTER;
2780     *ppv = NULL;
2781
2782     if(IsEqualIID(riid, &IID_IUnknown) ||
2783             IsEqualIID(riid, &IID_IAudioStreamVolume))
2784         *ppv = iface;
2785     if(*ppv){
2786         IUnknown_AddRef((IUnknown*)*ppv);
2787         return S_OK;
2788     }
2789
2790     WARN("Unknown interface %s\n", debugstr_guid(riid));
2791     return E_NOINTERFACE;
2792 }
2793
2794 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
2795 {
2796     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2797     return IAudioClient_AddRef(&This->IAudioClient_iface);
2798 }
2799
2800 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
2801 {
2802     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2803     return IAudioClient_Release(&This->IAudioClient_iface);
2804 }
2805
2806 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
2807         IAudioStreamVolume *iface, UINT32 *out)
2808 {
2809     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2810
2811     TRACE("(%p)->(%p)\n", This, out);
2812
2813     if(!out)
2814         return E_POINTER;
2815
2816     *out = This->fmt->nChannels;
2817
2818     return S_OK;
2819 }
2820
2821 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
2822         IAudioStreamVolume *iface, UINT32 index, float level)
2823 {
2824     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2825
2826     TRACE("(%p)->(%d, %f)\n", This, index, level);
2827
2828     if(level < 0.f || level > 1.f)
2829         return E_INVALIDARG;
2830
2831     if(index >= This->fmt->nChannels)
2832         return E_INVALIDARG;
2833
2834     TRACE("ALSA does not support volume control\n");
2835
2836     EnterCriticalSection(&This->lock);
2837
2838     This->vols[index] = level;
2839
2840     LeaveCriticalSection(&This->lock);
2841
2842     return S_OK;
2843 }
2844
2845 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2846         IAudioStreamVolume *iface, UINT32 index, float *level)
2847 {
2848     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2849
2850     TRACE("(%p)->(%d, %p)\n", This, index, level);
2851
2852     if(!level)
2853         return E_POINTER;
2854
2855     if(index >= This->fmt->nChannels)
2856         return E_INVALIDARG;
2857
2858     *level = This->vols[index];
2859
2860     return S_OK;
2861 }
2862
2863 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2864         IAudioStreamVolume *iface, UINT32 count, const float *levels)
2865 {
2866     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2867     int i;
2868
2869     TRACE("(%p)->(%d, %p)\n", This, count, levels);
2870
2871     if(!levels)
2872         return E_POINTER;
2873
2874     if(count != This->fmt->nChannels)
2875         return E_INVALIDARG;
2876
2877     TRACE("ALSA does not support volume control\n");
2878
2879     EnterCriticalSection(&This->lock);
2880
2881     for(i = 0; i < count; ++i)
2882         This->vols[i] = levels[i];
2883
2884     LeaveCriticalSection(&This->lock);
2885
2886     return S_OK;
2887 }
2888
2889 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2890         IAudioStreamVolume *iface, UINT32 count, float *levels)
2891 {
2892     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2893     int i;
2894
2895     TRACE("(%p)->(%d, %p)\n", This, count, levels);
2896
2897     if(!levels)
2898         return E_POINTER;
2899
2900     if(count != This->fmt->nChannels)
2901         return E_INVALIDARG;
2902
2903     EnterCriticalSection(&This->lock);
2904
2905     for(i = 0; i < count; ++i)
2906         levels[i] = This->vols[i];
2907
2908     LeaveCriticalSection(&This->lock);
2909
2910     return S_OK;
2911 }
2912
2913 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2914 {
2915     AudioStreamVolume_QueryInterface,
2916     AudioStreamVolume_AddRef,
2917     AudioStreamVolume_Release,
2918     AudioStreamVolume_GetChannelCount,
2919     AudioStreamVolume_SetChannelVolume,
2920     AudioStreamVolume_GetChannelVolume,
2921     AudioStreamVolume_SetAllVolumes,
2922     AudioStreamVolume_GetAllVolumes
2923 };
2924
2925 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2926         IChannelAudioVolume *iface, REFIID riid, void **ppv)
2927 {
2928     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2929
2930     if(!ppv)
2931         return E_POINTER;
2932     *ppv = NULL;
2933
2934     if(IsEqualIID(riid, &IID_IUnknown) ||
2935             IsEqualIID(riid, &IID_IChannelAudioVolume))
2936         *ppv = iface;
2937     if(*ppv){
2938         IUnknown_AddRef((IUnknown*)*ppv);
2939         return S_OK;
2940     }
2941
2942     WARN("Unknown interface %s\n", debugstr_guid(riid));
2943     return E_NOINTERFACE;
2944 }
2945
2946 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2947 {
2948     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2949     return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2950 }
2951
2952 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2953 {
2954     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2955     return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2956 }
2957
2958 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2959         IChannelAudioVolume *iface, UINT32 *out)
2960 {
2961     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2962     AudioSession *session = This->session;
2963
2964     TRACE("(%p)->(%p)\n", session, out);
2965
2966     if(!out)
2967         return NULL_PTR_ERR;
2968
2969     *out = session->channel_count;
2970
2971     return S_OK;
2972 }
2973
2974 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2975         IChannelAudioVolume *iface, UINT32 index, float level,
2976         const GUID *context)
2977 {
2978     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2979     AudioSession *session = This->session;
2980
2981     TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2982             wine_dbgstr_guid(context));
2983
2984     if(level < 0.f || level > 1.f)
2985         return E_INVALIDARG;
2986
2987     if(index >= session->channel_count)
2988         return E_INVALIDARG;
2989
2990     if(context)
2991         FIXME("Notifications not supported yet\n");
2992
2993     TRACE("ALSA does not support volume control\n");
2994
2995     EnterCriticalSection(&session->lock);
2996
2997     session->channel_vols[index] = level;
2998
2999     LeaveCriticalSection(&session->lock);
3000
3001     return S_OK;
3002 }
3003
3004 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
3005         IChannelAudioVolume *iface, UINT32 index, float *level)
3006 {
3007     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
3008     AudioSession *session = This->session;
3009
3010     TRACE("(%p)->(%d, %p)\n", session, index, level);
3011
3012     if(!level)
3013         return NULL_PTR_ERR;
3014
3015     if(index >= session->channel_count)
3016         return E_INVALIDARG;
3017
3018     *level = session->channel_vols[index];
3019
3020     return S_OK;
3021 }
3022
3023 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
3024         IChannelAudioVolume *iface, UINT32 count, const float *levels,
3025         const GUID *context)
3026 {
3027     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
3028     AudioSession *session = This->session;
3029     int i;
3030
3031     TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
3032             wine_dbgstr_guid(context));
3033
3034     if(!levels)
3035         return NULL_PTR_ERR;
3036
3037     if(count != session->channel_count)
3038         return E_INVALIDARG;
3039
3040     if(context)
3041         FIXME("Notifications not supported yet\n");
3042
3043     TRACE("ALSA does not support volume control\n");
3044
3045     EnterCriticalSection(&session->lock);
3046
3047     for(i = 0; i < count; ++i)
3048         session->channel_vols[i] = levels[i];
3049
3050     LeaveCriticalSection(&session->lock);
3051
3052     return S_OK;
3053 }
3054
3055 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
3056         IChannelAudioVolume *iface, UINT32 count, float *levels)
3057 {
3058     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
3059     AudioSession *session = This->session;
3060     int i;
3061
3062     TRACE("(%p)->(%d, %p)\n", session, count, levels);
3063
3064     if(!levels)
3065         return NULL_PTR_ERR;
3066
3067     if(count != session->channel_count)
3068         return E_INVALIDARG;
3069
3070     for(i = 0; i < count; ++i)
3071         levels[i] = session->channel_vols[i];
3072
3073     return S_OK;
3074 }
3075
3076 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
3077 {
3078     ChannelAudioVolume_QueryInterface,
3079     ChannelAudioVolume_AddRef,
3080     ChannelAudioVolume_Release,
3081     ChannelAudioVolume_GetChannelCount,
3082     ChannelAudioVolume_SetChannelVolume,
3083     ChannelAudioVolume_GetChannelVolume,
3084     ChannelAudioVolume_SetAllVolumes,
3085     ChannelAudioVolume_GetAllVolumes
3086 };
3087
3088 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
3089         REFIID riid, void **ppv)
3090 {
3091     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
3092
3093     if(!ppv)
3094         return E_POINTER;
3095     *ppv = NULL;
3096
3097     if(IsEqualIID(riid, &IID_IUnknown) ||
3098             IsEqualIID(riid, &IID_IAudioSessionManager) ||
3099             IsEqualIID(riid, &IID_IAudioSessionManager2))
3100         *ppv = iface;
3101     if(*ppv){
3102         IUnknown_AddRef((IUnknown*)*ppv);
3103         return S_OK;
3104     }
3105
3106     WARN("Unknown interface %s\n", debugstr_guid(riid));
3107     return E_NOINTERFACE;
3108 }
3109
3110 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
3111 {
3112     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3113     ULONG ref;
3114     ref = InterlockedIncrement(&This->ref);
3115     TRACE("(%p) Refcount now %u\n", This, ref);
3116     return ref;
3117 }
3118
3119 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
3120 {
3121     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3122     ULONG ref;
3123     ref = InterlockedDecrement(&This->ref);
3124     TRACE("(%p) Refcount now %u\n", This, ref);
3125     if(!ref)
3126         HeapFree(GetProcessHeap(), 0, This);
3127     return ref;
3128 }
3129
3130 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
3131         IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
3132         IAudioSessionControl **out)
3133 {
3134     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3135     AudioSession *session;
3136     AudioSessionWrapper *wrapper;
3137     HRESULT hr;
3138
3139     TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
3140             flags, out);
3141
3142     hr = get_audio_session(session_guid, This->device, 0, &session);
3143     if(FAILED(hr))
3144         return hr;
3145
3146     wrapper = AudioSessionWrapper_Create(NULL);
3147     if(!wrapper)
3148         return E_OUTOFMEMORY;
3149
3150     wrapper->session = session;
3151
3152     *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
3153
3154     return S_OK;
3155 }
3156
3157 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
3158         IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
3159         ISimpleAudioVolume **out)
3160 {
3161     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3162     AudioSession *session;
3163     AudioSessionWrapper *wrapper;
3164     HRESULT hr;
3165
3166     TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
3167             flags, out);
3168
3169     hr = get_audio_session(session_guid, This->device, 0, &session);
3170     if(FAILED(hr))
3171         return hr;
3172
3173     wrapper = AudioSessionWrapper_Create(NULL);
3174     if(!wrapper)
3175         return E_OUTOFMEMORY;
3176
3177     wrapper->session = session;
3178
3179     *out = &wrapper->ISimpleAudioVolume_iface;
3180
3181     return S_OK;
3182 }
3183
3184 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
3185         IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
3186 {
3187     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3188     FIXME("(%p)->(%p) - stub\n", This, out);
3189     return E_NOTIMPL;
3190 }
3191
3192 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
3193         IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
3194 {
3195     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3196     FIXME("(%p)->(%p) - stub\n", This, notification);
3197     return E_NOTIMPL;
3198 }
3199
3200 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
3201         IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
3202 {
3203     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3204     FIXME("(%p)->(%p) - stub\n", This, notification);
3205     return E_NOTIMPL;
3206 }
3207
3208 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
3209         IAudioSessionManager2 *iface, const WCHAR *session_id,
3210         IAudioVolumeDuckNotification *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_UnregisterDuckNotification(
3218         IAudioSessionManager2 *iface,
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 const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
3227 {
3228     AudioSessionManager_QueryInterface,
3229     AudioSessionManager_AddRef,
3230     AudioSessionManager_Release,
3231     AudioSessionManager_GetAudioSessionControl,
3232     AudioSessionManager_GetSimpleAudioVolume,
3233     AudioSessionManager_GetSessionEnumerator,
3234     AudioSessionManager_RegisterSessionNotification,
3235     AudioSessionManager_UnregisterSessionNotification,
3236     AudioSessionManager_RegisterDuckNotification,
3237     AudioSessionManager_UnregisterDuckNotification
3238 };
3239
3240 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
3241         IAudioSessionManager2 **out)
3242 {
3243     SessionMgr *This;
3244
3245     This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
3246     if(!This)
3247         return E_OUTOFMEMORY;
3248
3249     This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
3250     This->device = device;
3251     This->ref = 1;
3252
3253     *out = &This->IAudioSessionManager2_iface;
3254
3255     return S_OK;
3256 }