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