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