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