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