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