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