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