jscript: Get rid of BSTR in date.c.
[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                 bytes_per_sample * 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                 bytes_per_sample * 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     switch(This->fmt->wBitsPerSample){
1843     case 8: {
1844             UINT8 *tgt_buf, *src_buf;
1845             tgt_buf = This->remapping_buf;
1846             src_buf = buf;
1847             for(i = 0; i < frames; ++i){
1848                 for(c = 0; c < This->fmt->nChannels; ++c)
1849                     tgt_buf[This->alsa_channel_map[c]] = src_buf[c];
1850                 tgt_buf += This->alsa_channels;
1851                 src_buf += This->fmt->nChannels;
1852             }
1853             break;
1854         }
1855     case 16: {
1856             UINT16 *tgt_buf, *src_buf;
1857             tgt_buf = (UINT16*)This->remapping_buf;
1858             src_buf = (UINT16*)buf;
1859             for(i = 0; i < frames; ++i){
1860                 for(c = 0; c < This->fmt->nChannels; ++c)
1861                     tgt_buf[This->alsa_channel_map[c]] = src_buf[c];
1862                 tgt_buf += This->alsa_channels;
1863                 src_buf += This->fmt->nChannels;
1864             }
1865         }
1866         break;
1867     case 32: {
1868             UINT32 *tgt_buf, *src_buf;
1869             tgt_buf = (UINT32*)This->remapping_buf;
1870             src_buf = (UINT32*)buf;
1871             for(i = 0; i < frames; ++i){
1872                 for(c = 0; c < This->fmt->nChannels; ++c)
1873                     tgt_buf[This->alsa_channel_map[c]] = src_buf[c];
1874                 tgt_buf += This->alsa_channels;
1875                 src_buf += This->fmt->nChannels;
1876             }
1877         }
1878         break;
1879     default: {
1880             BYTE *tgt_buf, *src_buf;
1881             tgt_buf = This->remapping_buf;
1882             src_buf = buf;
1883             for(i = 0; i < frames; ++i){
1884                 for(c = 0; c < This->fmt->nChannels; ++c)
1885                     memcpy(&tgt_buf[This->alsa_channel_map[c] * bytes_per_sample],
1886                             &src_buf[c * bytes_per_sample], bytes_per_sample);
1887                 tgt_buf += This->alsa_channels * bytes_per_sample;
1888                 src_buf += This->fmt->nChannels * bytes_per_sample;
1889             }
1890         }
1891         break;
1892     }
1893
1894     return This->remapping_buf;
1895 }
1896
1897 static snd_pcm_sframes_t alsa_write_best_effort(snd_pcm_t *handle, BYTE *buf,
1898         snd_pcm_uframes_t frames, ACImpl *This, BOOL mute)
1899 {
1900     snd_pcm_sframes_t written;
1901
1902     if(mute){
1903         int err;
1904         if((err = snd_pcm_format_set_silence(This->alsa_format, buf,
1905                         frames * This->fmt->nChannels)) < 0)
1906             WARN("Setting buffer to silence failed: %d (%s)\n", err,
1907                     snd_strerror(err));
1908     }
1909
1910     buf = remap_channels(This, buf, frames);
1911
1912     written = snd_pcm_writei(handle, buf, frames);
1913     if(written < 0){
1914         int ret;
1915
1916         if(written == -EAGAIN)
1917             /* buffer full */
1918             return 0;
1919
1920         WARN("writei failed, recovering: %ld (%s)\n", written,
1921                 snd_strerror(written));
1922
1923         ret = snd_pcm_recover(handle, written, 0);
1924         if(ret < 0){
1925             WARN("Could not recover: %d (%s)\n", ret, snd_strerror(ret));
1926             return ret;
1927         }
1928
1929         written = snd_pcm_writei(handle, buf, frames);
1930     }
1931
1932     return written;
1933 }
1934
1935 static void alsa_write_data(ACImpl *This)
1936 {
1937     snd_pcm_sframes_t written, in_alsa;
1938     snd_pcm_uframes_t to_write, avail, write_limit, max_period;
1939     int err;
1940     BYTE *buf =
1941         This->local_buffer + (This->lcl_offs_frames * This->fmt->nBlockAlign);
1942
1943     /* this call seems to be required to get an accurate snd_pcm_state() */
1944     avail = snd_pcm_avail_update(This->pcm_handle);
1945
1946     if(snd_pcm_state(This->pcm_handle) == SND_PCM_STATE_XRUN ||
1947             avail > This->alsa_bufsize_frames){
1948         TRACE("XRun state avail %ld, recovering\n", avail);
1949
1950         avail = This->alsa_bufsize_frames;
1951
1952         if((err = snd_pcm_recover(This->pcm_handle, -EPIPE, 1)) < 0)
1953             WARN("snd_pcm_recover failed: %d (%s)\n", err, snd_strerror(err));
1954
1955         if((err = snd_pcm_reset(This->pcm_handle)) < 0)
1956             WARN("snd_pcm_reset failed: %d (%s)\n", err, snd_strerror(err));
1957
1958         if((err = snd_pcm_prepare(This->pcm_handle)) < 0)
1959             WARN("snd_pcm_prepare failed: %d (%s)\n", err, snd_strerror(err));
1960     }else
1961         TRACE("pad: %ld\n", This->alsa_bufsize_frames - avail);
1962
1963     if(This->held_frames == 0)
1964         return;
1965
1966     if(This->lcl_offs_frames + This->held_frames > This->bufsize_frames)
1967         to_write = This->bufsize_frames - This->lcl_offs_frames;
1968     else
1969         to_write = This->held_frames;
1970
1971     max_period = max(This->mmdev_period_frames, This->alsa_period_frames);
1972
1973     /* try to keep 3 ALSA periods or 3 MMDevAPI periods in the ALSA buffer and
1974      * no more */
1975     write_limit = 0;
1976     in_alsa = This->alsa_bufsize_frames - avail;
1977     while(in_alsa + write_limit < max_period * 3)
1978         write_limit += max_period;
1979     if(write_limit == 0)
1980         return;
1981
1982     to_write = min(to_write, write_limit);
1983
1984     /* Add a lead-in when starting with too few frames to ensure
1985      * continuous rendering.  Additional benefit: Force ALSA to start.
1986      * GetPosition continues to reflect the speaker position because
1987      * snd_pcm_delay includes buffered frames in its total delay
1988      * and last_pos_frames prevents moving backwards. */
1989     if(!in_alsa && This->held_frames < This->hidden_frames){
1990         UINT32 s_frames = This->hidden_frames - This->held_frames;
1991         BYTE *silence = HeapAlloc(GetProcessHeap(), 0,
1992                 s_frames * This->fmt->nBlockAlign);
1993
1994         if(silence){
1995             in_alsa = alsa_write_best_effort(This->pcm_handle,
1996                 silence, s_frames, This, TRUE);
1997             TRACE("lead-in %ld\n", in_alsa);
1998             HeapFree(GetProcessHeap(), 0, silence);
1999             if(in_alsa <= 0)
2000                 return;
2001         }else
2002             WARN("Couldn't allocate lead-in, expect underrun\n");
2003     }
2004
2005     written = alsa_write_best_effort(This->pcm_handle, buf, to_write, This,
2006             This->session->mute);
2007     if(written < 0){
2008         WARN("Couldn't write: %ld (%s)\n", written, snd_strerror(written));
2009         return;
2010     }
2011
2012     This->lcl_offs_frames += written;
2013     This->lcl_offs_frames %= This->bufsize_frames;
2014     This->held_frames -= written;
2015
2016     if(written < to_write){
2017         /* ALSA buffer probably full */
2018         return;
2019     }
2020
2021     if(This->held_frames && (written < write_limit)){
2022         /* wrapped and have some data back at the start to write */
2023         written = alsa_write_best_effort(This->pcm_handle, This->local_buffer,
2024                 min(This->held_frames, write_limit - written), This,
2025                 This->session->mute);
2026         if(written < 0){
2027             WARN("Couldn't write: %ld (%s)\n", written, snd_strerror(written));
2028             return;
2029         }
2030
2031         This->lcl_offs_frames += written;
2032         This->lcl_offs_frames %= This->bufsize_frames;
2033         This->held_frames -= written;
2034     }
2035 }
2036
2037 static void alsa_read_data(ACImpl *This)
2038 {
2039     snd_pcm_sframes_t pos, readable, nread;
2040
2041     pos = (This->held_frames + This->lcl_offs_frames) % This->bufsize_frames;
2042     readable = This->bufsize_frames - pos;
2043
2044     nread = snd_pcm_readi(This->pcm_handle,
2045             This->local_buffer + pos * This->fmt->nBlockAlign, readable);
2046     if(nread < 0){
2047         int ret;
2048
2049         WARN("read failed, recovering: %ld (%s)\n", nread, snd_strerror(nread));
2050
2051         ret = snd_pcm_recover(This->pcm_handle, nread, 0);
2052         if(ret < 0){
2053             WARN("Recover failed: %d (%s)\n", ret, snd_strerror(ret));
2054             return;
2055         }
2056
2057         nread = snd_pcm_readi(This->pcm_handle,
2058                 This->local_buffer + pos * This->fmt->nBlockAlign, readable);
2059         if(nread < 0){
2060             WARN("read failed: %ld (%s)\n", nread, snd_strerror(nread));
2061             return;
2062         }
2063     }
2064
2065     if(This->session->mute){
2066         int err;
2067         if((err = snd_pcm_format_set_silence(This->alsa_format,
2068                         This->local_buffer + pos * This->fmt->nBlockAlign,
2069                         nread)) < 0)
2070             WARN("Setting buffer to silence failed: %d (%s)\n", err,
2071                     snd_strerror(err));
2072     }
2073
2074     This->held_frames += nread;
2075
2076     if(This->held_frames > This->bufsize_frames){
2077         WARN("Overflow of unread data\n");
2078         This->lcl_offs_frames += This->held_frames;
2079         This->lcl_offs_frames %= This->bufsize_frames;
2080         This->held_frames = This->bufsize_frames;
2081     }
2082 }
2083
2084 static void CALLBACK alsa_push_buffer_data(void *user, BOOLEAN timer)
2085 {
2086     ACImpl *This = user;
2087
2088     EnterCriticalSection(&This->lock);
2089
2090     if(This->started){
2091         if(This->dataflow == eRender)
2092             alsa_write_data(This);
2093         else if(This->dataflow == eCapture)
2094             alsa_read_data(This);
2095
2096         if(This->event)
2097             SetEvent(This->event);
2098     }
2099
2100     LeaveCriticalSection(&This->lock);
2101 }
2102
2103 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
2104 {
2105     ACImpl *This = impl_from_IAudioClient(iface);
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->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
2117         LeaveCriticalSection(&This->lock);
2118         return AUDCLNT_E_EVENTHANDLE_NOT_SET;
2119     }
2120
2121     if(This->started){
2122         LeaveCriticalSection(&This->lock);
2123         return AUDCLNT_E_NOT_STOPPED;
2124     }
2125
2126     if(This->dataflow == eCapture){
2127         /* dump any data that might be leftover in the ALSA capture buffer */
2128         snd_pcm_readi(This->pcm_handle, This->local_buffer,
2129                 This->bufsize_frames);
2130     }
2131
2132     if(!CreateTimerQueueTimer(&This->timer, g_timer_q, alsa_push_buffer_data,
2133             This, 0, This->mmdev_period_rt / 10000, WT_EXECUTEINTIMERTHREAD)){
2134         LeaveCriticalSection(&This->lock);
2135         WARN("Unable to create timer: %u\n", GetLastError());
2136         return E_OUTOFMEMORY;
2137     }
2138
2139     This->started = TRUE;
2140
2141     LeaveCriticalSection(&This->lock);
2142
2143     return S_OK;
2144 }
2145
2146 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
2147 {
2148     ACImpl *This = impl_from_IAudioClient(iface);
2149     HANDLE event;
2150     BOOL wait;
2151
2152     TRACE("(%p)\n", This);
2153
2154     EnterCriticalSection(&This->lock);
2155
2156     if(!This->initted){
2157         LeaveCriticalSection(&This->lock);
2158         return AUDCLNT_E_NOT_INITIALIZED;
2159     }
2160
2161     if(!This->started){
2162         LeaveCriticalSection(&This->lock);
2163         return S_FALSE;
2164     }
2165
2166     /* Stop without losing written frames or position.
2167      * snd_pcm_pause would be appropriate but is unsupported by dmix.
2168      * snd_pcm_drain yields EAGAIN in NONBLOCK mode, except with Pulse. */
2169
2170     event = CreateEventW(NULL, TRUE, FALSE, NULL);
2171     wait = !DeleteTimerQueueTimer(g_timer_q, This->timer, event);
2172     if(wait)
2173         WARN("DeleteTimerQueueTimer error %u\n", GetLastError());
2174     wait = wait && GetLastError() == ERROR_IO_PENDING;
2175
2176     This->started = FALSE;
2177
2178     LeaveCriticalSection(&This->lock);
2179
2180     if(event && wait)
2181         WaitForSingleObject(event, INFINITE);
2182     CloseHandle(event);
2183
2184     return S_OK;
2185 }
2186
2187 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
2188 {
2189     ACImpl *This = impl_from_IAudioClient(iface);
2190
2191     TRACE("(%p)\n", This);
2192
2193     EnterCriticalSection(&This->lock);
2194
2195     if(!This->initted){
2196         LeaveCriticalSection(&This->lock);
2197         return AUDCLNT_E_NOT_INITIALIZED;
2198     }
2199
2200     if(This->started){
2201         LeaveCriticalSection(&This->lock);
2202         return AUDCLNT_E_NOT_STOPPED;
2203     }
2204
2205     if(This->getbuf_last){
2206         LeaveCriticalSection(&This->lock);
2207         return AUDCLNT_E_BUFFER_OPERATION_PENDING;
2208     }
2209
2210     if(snd_pcm_drop(This->pcm_handle) < 0)
2211         WARN("snd_pcm_drop failed\n");
2212
2213     if(snd_pcm_reset(This->pcm_handle) < 0)
2214         WARN("snd_pcm_reset failed\n");
2215
2216     if(snd_pcm_prepare(This->pcm_handle) < 0)
2217         WARN("snd_pcm_prepare failed\n");
2218
2219     if(This->dataflow == eRender){
2220         This->written_frames = 0;
2221         This->last_pos_frames = 0;
2222     }else{
2223         This->written_frames += This->held_frames;
2224     }
2225     This->held_frames = 0;
2226     This->lcl_offs_frames = 0;
2227
2228     LeaveCriticalSection(&This->lock);
2229
2230     return S_OK;
2231 }
2232
2233 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
2234         HANDLE event)
2235 {
2236     ACImpl *This = impl_from_IAudioClient(iface);
2237
2238     TRACE("(%p)->(%p)\n", This, event);
2239
2240     if(!event)
2241         return E_INVALIDARG;
2242
2243     EnterCriticalSection(&This->lock);
2244
2245     if(!This->initted){
2246         LeaveCriticalSection(&This->lock);
2247         return AUDCLNT_E_NOT_INITIALIZED;
2248     }
2249
2250     if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
2251         LeaveCriticalSection(&This->lock);
2252         return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
2253     }
2254
2255     This->event = event;
2256
2257     LeaveCriticalSection(&This->lock);
2258
2259     return S_OK;
2260 }
2261
2262 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
2263         void **ppv)
2264 {
2265     ACImpl *This = impl_from_IAudioClient(iface);
2266
2267     TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
2268
2269     if(!ppv)
2270         return E_POINTER;
2271     *ppv = NULL;
2272
2273     EnterCriticalSection(&This->lock);
2274
2275     if(!This->initted){
2276         LeaveCriticalSection(&This->lock);
2277         return AUDCLNT_E_NOT_INITIALIZED;
2278     }
2279
2280     if(IsEqualIID(riid, &IID_IAudioRenderClient)){
2281         if(This->dataflow != eRender){
2282             LeaveCriticalSection(&This->lock);
2283             return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
2284         }
2285         IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
2286         *ppv = &This->IAudioRenderClient_iface;
2287     }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
2288         if(This->dataflow != eCapture){
2289             LeaveCriticalSection(&This->lock);
2290             return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
2291         }
2292         IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
2293         *ppv = &This->IAudioCaptureClient_iface;
2294     }else if(IsEqualIID(riid, &IID_IAudioClock)){
2295         IAudioClock_AddRef(&This->IAudioClock_iface);
2296         *ppv = &This->IAudioClock_iface;
2297     }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
2298         IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
2299         *ppv = &This->IAudioStreamVolume_iface;
2300     }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
2301         if(!This->session_wrapper){
2302             This->session_wrapper = AudioSessionWrapper_Create(This);
2303             if(!This->session_wrapper){
2304                 LeaveCriticalSection(&This->lock);
2305                 return E_OUTOFMEMORY;
2306             }
2307         }else
2308             IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
2309
2310         *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
2311     }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
2312         if(!This->session_wrapper){
2313             This->session_wrapper = AudioSessionWrapper_Create(This);
2314             if(!This->session_wrapper){
2315                 LeaveCriticalSection(&This->lock);
2316                 return E_OUTOFMEMORY;
2317             }
2318         }else
2319             IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
2320
2321         *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
2322     }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
2323         if(!This->session_wrapper){
2324             This->session_wrapper = AudioSessionWrapper_Create(This);
2325             if(!This->session_wrapper){
2326                 LeaveCriticalSection(&This->lock);
2327                 return E_OUTOFMEMORY;
2328             }
2329         }else
2330             ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
2331
2332         *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
2333     }
2334
2335     if(*ppv){
2336         LeaveCriticalSection(&This->lock);
2337         return S_OK;
2338     }
2339
2340     LeaveCriticalSection(&This->lock);
2341
2342     FIXME("stub %s\n", debugstr_guid(riid));
2343     return E_NOINTERFACE;
2344 }
2345
2346 static const IAudioClientVtbl AudioClient_Vtbl =
2347 {
2348     AudioClient_QueryInterface,
2349     AudioClient_AddRef,
2350     AudioClient_Release,
2351     AudioClient_Initialize,
2352     AudioClient_GetBufferSize,
2353     AudioClient_GetStreamLatency,
2354     AudioClient_GetCurrentPadding,
2355     AudioClient_IsFormatSupported,
2356     AudioClient_GetMixFormat,
2357     AudioClient_GetDevicePeriod,
2358     AudioClient_Start,
2359     AudioClient_Stop,
2360     AudioClient_Reset,
2361     AudioClient_SetEventHandle,
2362     AudioClient_GetService
2363 };
2364
2365 static HRESULT WINAPI AudioRenderClient_QueryInterface(
2366         IAudioRenderClient *iface, REFIID riid, void **ppv)
2367 {
2368     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2369
2370     if(!ppv)
2371         return E_POINTER;
2372     *ppv = NULL;
2373
2374     if(IsEqualIID(riid, &IID_IUnknown) ||
2375             IsEqualIID(riid, &IID_IAudioRenderClient))
2376         *ppv = iface;
2377     if(*ppv){
2378         IUnknown_AddRef((IUnknown*)*ppv);
2379         return S_OK;
2380     }
2381
2382     WARN("Unknown interface %s\n", debugstr_guid(riid));
2383     return E_NOINTERFACE;
2384 }
2385
2386 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
2387 {
2388     ACImpl *This = impl_from_IAudioRenderClient(iface);
2389     return AudioClient_AddRef(&This->IAudioClient_iface);
2390 }
2391
2392 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
2393 {
2394     ACImpl *This = impl_from_IAudioRenderClient(iface);
2395     return AudioClient_Release(&This->IAudioClient_iface);
2396 }
2397
2398 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
2399         UINT32 frames, BYTE **data)
2400 {
2401     ACImpl *This = impl_from_IAudioRenderClient(iface);
2402     UINT32 write_pos;
2403
2404     TRACE("(%p)->(%u, %p)\n", This, frames, data);
2405
2406     if(!data)
2407         return E_POINTER;
2408     *data = NULL;
2409
2410     EnterCriticalSection(&This->lock);
2411
2412     if(This->getbuf_last){
2413         LeaveCriticalSection(&This->lock);
2414         return AUDCLNT_E_OUT_OF_ORDER;
2415     }
2416
2417     if(!frames){
2418         LeaveCriticalSection(&This->lock);
2419         return S_OK;
2420     }
2421
2422     /* held_frames == GetCurrentPadding_nolock(); */
2423     if(This->held_frames + frames > This->bufsize_frames){
2424         LeaveCriticalSection(&This->lock);
2425         return AUDCLNT_E_BUFFER_TOO_LARGE;
2426     }
2427
2428     write_pos =
2429         (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
2430     if(write_pos + frames > This->bufsize_frames){
2431         if(This->tmp_buffer_frames < frames){
2432             HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
2433             This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
2434                     frames * This->fmt->nBlockAlign);
2435             if(!This->tmp_buffer){
2436                 LeaveCriticalSection(&This->lock);
2437                 return E_OUTOFMEMORY;
2438             }
2439             This->tmp_buffer_frames = frames;
2440         }
2441         *data = This->tmp_buffer;
2442         This->getbuf_last = -frames;
2443     }else{
2444         *data = This->local_buffer + write_pos * This->fmt->nBlockAlign;
2445         This->getbuf_last = frames;
2446     }
2447
2448     LeaveCriticalSection(&This->lock);
2449
2450     return S_OK;
2451 }
2452
2453 static void alsa_wrap_buffer(ACImpl *This, BYTE *buffer, UINT32 written_frames)
2454 {
2455     snd_pcm_uframes_t write_offs_frames =
2456         (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
2457     UINT32 write_offs_bytes = write_offs_frames * This->fmt->nBlockAlign;
2458     snd_pcm_uframes_t chunk_frames = This->bufsize_frames - write_offs_frames;
2459     UINT32 chunk_bytes = chunk_frames * This->fmt->nBlockAlign;
2460     UINT32 written_bytes = written_frames * This->fmt->nBlockAlign;
2461
2462     if(written_bytes <= chunk_bytes){
2463         memcpy(This->local_buffer + write_offs_bytes, buffer, written_bytes);
2464     }else{
2465         memcpy(This->local_buffer + write_offs_bytes, buffer, chunk_bytes);
2466         memcpy(This->local_buffer, buffer + chunk_bytes,
2467                 written_bytes - chunk_bytes);
2468     }
2469 }
2470
2471 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
2472         IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
2473 {
2474     ACImpl *This = impl_from_IAudioRenderClient(iface);
2475     BYTE *buffer;
2476
2477     TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
2478
2479     EnterCriticalSection(&This->lock);
2480
2481     if(!written_frames){
2482         This->getbuf_last = 0;
2483         LeaveCriticalSection(&This->lock);
2484         return S_OK;
2485     }
2486
2487     if(!This->getbuf_last){
2488         LeaveCriticalSection(&This->lock);
2489         return AUDCLNT_E_OUT_OF_ORDER;
2490     }
2491
2492     if(written_frames > (This->getbuf_last >= 0 ? This->getbuf_last : -This->getbuf_last)){
2493         LeaveCriticalSection(&This->lock);
2494         return AUDCLNT_E_INVALID_SIZE;
2495     }
2496
2497     if(This->getbuf_last >= 0)
2498         buffer = This->local_buffer + This->fmt->nBlockAlign *
2499           ((This->lcl_offs_frames + This->held_frames) % This->bufsize_frames);
2500     else
2501         buffer = This->tmp_buffer;
2502
2503     if(flags & AUDCLNT_BUFFERFLAGS_SILENT){
2504         if(This->fmt->wBitsPerSample == 8)
2505             memset(buffer, 128, written_frames * This->fmt->nBlockAlign);
2506         else
2507             memset(buffer, 0, written_frames * This->fmt->nBlockAlign);
2508     }
2509
2510     if(This->getbuf_last < 0)
2511         alsa_wrap_buffer(This, buffer, written_frames);
2512
2513     This->held_frames += written_frames;
2514     This->written_frames += written_frames;
2515     This->getbuf_last = 0;
2516
2517     LeaveCriticalSection(&This->lock);
2518
2519     return S_OK;
2520 }
2521
2522 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
2523     AudioRenderClient_QueryInterface,
2524     AudioRenderClient_AddRef,
2525     AudioRenderClient_Release,
2526     AudioRenderClient_GetBuffer,
2527     AudioRenderClient_ReleaseBuffer
2528 };
2529
2530 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
2531         IAudioCaptureClient *iface, REFIID riid, void **ppv)
2532 {
2533     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2534
2535     if(!ppv)
2536         return E_POINTER;
2537     *ppv = NULL;
2538
2539     if(IsEqualIID(riid, &IID_IUnknown) ||
2540             IsEqualIID(riid, &IID_IAudioCaptureClient))
2541         *ppv = iface;
2542     if(*ppv){
2543         IUnknown_AddRef((IUnknown*)*ppv);
2544         return S_OK;
2545     }
2546
2547     WARN("Unknown interface %s\n", debugstr_guid(riid));
2548     return E_NOINTERFACE;
2549 }
2550
2551 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
2552 {
2553     ACImpl *This = impl_from_IAudioCaptureClient(iface);
2554     return IAudioClient_AddRef(&This->IAudioClient_iface);
2555 }
2556
2557 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
2558 {
2559     ACImpl *This = impl_from_IAudioCaptureClient(iface);
2560     return IAudioClient_Release(&This->IAudioClient_iface);
2561 }
2562
2563 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
2564         BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
2565         UINT64 *qpcpos)
2566 {
2567     ACImpl *This = impl_from_IAudioCaptureClient(iface);
2568
2569     TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
2570             devpos, qpcpos);
2571
2572     if(!data || !frames || !flags)
2573         return E_POINTER;
2574
2575     EnterCriticalSection(&This->lock);
2576
2577     if(This->getbuf_last){
2578         LeaveCriticalSection(&This->lock);
2579         return AUDCLNT_E_OUT_OF_ORDER;
2580     }
2581
2582     /* hr = GetNextPacketSize(iface, frames); */
2583     if(This->held_frames < This->mmdev_period_frames){
2584         *frames = 0;
2585         LeaveCriticalSection(&This->lock);
2586         return AUDCLNT_S_BUFFER_EMPTY;
2587     }
2588     *frames = This->mmdev_period_frames;
2589
2590     if(This->lcl_offs_frames + *frames > This->bufsize_frames){
2591         UINT32 chunk_bytes, offs_bytes, frames_bytes;
2592         if(This->tmp_buffer_frames < *frames){
2593             HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
2594             This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
2595                     *frames * This->fmt->nBlockAlign);
2596             if(!This->tmp_buffer){
2597                 LeaveCriticalSection(&This->lock);
2598                 return E_OUTOFMEMORY;
2599             }
2600             This->tmp_buffer_frames = *frames;
2601         }
2602
2603         *data = This->tmp_buffer;
2604         chunk_bytes = (This->bufsize_frames - This->lcl_offs_frames) *
2605             This->fmt->nBlockAlign;
2606         offs_bytes = This->lcl_offs_frames * This->fmt->nBlockAlign;
2607         frames_bytes = *frames * This->fmt->nBlockAlign;
2608         memcpy(This->tmp_buffer, This->local_buffer + offs_bytes, chunk_bytes);
2609         memcpy(This->tmp_buffer + chunk_bytes, This->local_buffer,
2610                 frames_bytes - chunk_bytes);
2611     }else
2612         *data = This->local_buffer +
2613             This->lcl_offs_frames * This->fmt->nBlockAlign;
2614
2615     This->getbuf_last = *frames;
2616     *flags = 0;
2617
2618     if(devpos)
2619       *devpos = This->written_frames;
2620     if(qpcpos){ /* fixme: qpc of recording time */
2621         LARGE_INTEGER stamp, freq;
2622         QueryPerformanceCounter(&stamp);
2623         QueryPerformanceFrequency(&freq);
2624         *qpcpos = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
2625     }
2626
2627     LeaveCriticalSection(&This->lock);
2628
2629     return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
2630 }
2631
2632 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
2633         IAudioCaptureClient *iface, UINT32 done)
2634 {
2635     ACImpl *This = impl_from_IAudioCaptureClient(iface);
2636
2637     TRACE("(%p)->(%u)\n", This, done);
2638
2639     EnterCriticalSection(&This->lock);
2640
2641     if(!done){
2642         This->getbuf_last = 0;
2643         LeaveCriticalSection(&This->lock);
2644         return S_OK;
2645     }
2646
2647     if(!This->getbuf_last){
2648         LeaveCriticalSection(&This->lock);
2649         return AUDCLNT_E_OUT_OF_ORDER;
2650     }
2651
2652     if(This->getbuf_last != done){
2653         LeaveCriticalSection(&This->lock);
2654         return AUDCLNT_E_INVALID_SIZE;
2655     }
2656
2657     This->written_frames += done;
2658     This->held_frames -= done;
2659     This->lcl_offs_frames += done;
2660     This->lcl_offs_frames %= This->bufsize_frames;
2661     This->getbuf_last = 0;
2662
2663     LeaveCriticalSection(&This->lock);
2664
2665     return S_OK;
2666 }
2667
2668 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
2669         IAudioCaptureClient *iface, UINT32 *frames)
2670 {
2671     ACImpl *This = impl_from_IAudioCaptureClient(iface);
2672
2673     TRACE("(%p)->(%p)\n", This, frames);
2674
2675     if(!frames)
2676         return E_POINTER;
2677
2678     EnterCriticalSection(&This->lock);
2679
2680     *frames = This->held_frames < This->mmdev_period_frames ? 0 : This->mmdev_period_frames;
2681
2682     LeaveCriticalSection(&This->lock);
2683
2684     return S_OK;
2685 }
2686
2687 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
2688 {
2689     AudioCaptureClient_QueryInterface,
2690     AudioCaptureClient_AddRef,
2691     AudioCaptureClient_Release,
2692     AudioCaptureClient_GetBuffer,
2693     AudioCaptureClient_ReleaseBuffer,
2694     AudioCaptureClient_GetNextPacketSize
2695 };
2696
2697 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
2698         REFIID riid, void **ppv)
2699 {
2700     ACImpl *This = impl_from_IAudioClock(iface);
2701
2702     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2703
2704     if(!ppv)
2705         return E_POINTER;
2706     *ppv = NULL;
2707
2708     if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
2709         *ppv = iface;
2710     else if(IsEqualIID(riid, &IID_IAudioClock2))
2711         *ppv = &This->IAudioClock2_iface;
2712     if(*ppv){
2713         IUnknown_AddRef((IUnknown*)*ppv);
2714         return S_OK;
2715     }
2716
2717     WARN("Unknown interface %s\n", debugstr_guid(riid));
2718     return E_NOINTERFACE;
2719 }
2720
2721 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
2722 {
2723     ACImpl *This = impl_from_IAudioClock(iface);
2724     return IAudioClient_AddRef(&This->IAudioClient_iface);
2725 }
2726
2727 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
2728 {
2729     ACImpl *This = impl_from_IAudioClock(iface);
2730     return IAudioClient_Release(&This->IAudioClient_iface);
2731 }
2732
2733 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
2734 {
2735     ACImpl *This = impl_from_IAudioClock(iface);
2736
2737     TRACE("(%p)->(%p)\n", This, freq);
2738
2739     *freq = This->fmt->nSamplesPerSec;
2740
2741     return S_OK;
2742 }
2743
2744 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
2745         UINT64 *qpctime)
2746 {
2747     ACImpl *This = impl_from_IAudioClock(iface);
2748     UINT64 written_frames, position;
2749     UINT32 held_frames;
2750     int err;
2751     snd_pcm_state_t alsa_state;
2752     snd_pcm_uframes_t avail_frames;
2753     snd_pcm_sframes_t delay_frames;
2754
2755     TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
2756
2757     if(!pos)
2758         return E_POINTER;
2759
2760     EnterCriticalSection(&This->lock);
2761
2762     /* call required to get accurate snd_pcm_state() */
2763     avail_frames = snd_pcm_avail_update(This->pcm_handle);
2764     alsa_state = snd_pcm_state(This->pcm_handle);
2765     written_frames = This->written_frames;
2766     held_frames = This->held_frames;
2767
2768     err = snd_pcm_delay(This->pcm_handle, &delay_frames);
2769     if(err < 0){
2770         /* old Pulse, shortly after start */
2771         WARN("snd_pcm_delay failed in state %u: %d (%s)\n", alsa_state, err, snd_strerror(err));
2772     }
2773
2774     if(This->dataflow == eRender){
2775         position = written_frames - held_frames; /* maximum */
2776         if(!This->started || alsa_state > SND_PCM_STATE_RUNNING)
2777             ; /* mmdevapi stopped or ALSA underrun: pretend everything was played */
2778         else if(err<0 || delay_frames > position - This->last_pos_frames)
2779             /* Pulse bug: past underrun, despite recovery, avail_frames & delay
2780              * may be larger than alsa_bufsize_frames, as if cumulating frames. */
2781             /* Pulse bug: EIO(-5) shortly after starting: nothing played */
2782             position = This->last_pos_frames;
2783         else if(delay_frames > 0)
2784             position -= delay_frames;
2785     }else
2786         position = written_frames + held_frames;
2787
2788     /* ensure monotic growth */
2789     This->last_pos_frames = position;
2790
2791     LeaveCriticalSection(&This->lock);
2792
2793     TRACE("frames written: %u, held: %u, avail: %ld, delay: %ld state %d, pos: %u\n",
2794           (UINT32)(written_frames%1000000000), held_frames,
2795           avail_frames, delay_frames, alsa_state, (UINT32)(position%1000000000));
2796     *pos = position;
2797
2798     if(qpctime){
2799         LARGE_INTEGER stamp, freq;
2800         QueryPerformanceCounter(&stamp);
2801         QueryPerformanceFrequency(&freq);
2802         *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
2803     }
2804
2805     return S_OK;
2806 }
2807
2808 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
2809         DWORD *chars)
2810 {
2811     ACImpl *This = impl_from_IAudioClock(iface);
2812
2813     TRACE("(%p)->(%p)\n", This, chars);
2814
2815     if(!chars)
2816         return E_POINTER;
2817
2818     *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
2819
2820     return S_OK;
2821 }
2822
2823 static const IAudioClockVtbl AudioClock_Vtbl =
2824 {
2825     AudioClock_QueryInterface,
2826     AudioClock_AddRef,
2827     AudioClock_Release,
2828     AudioClock_GetFrequency,
2829     AudioClock_GetPosition,
2830     AudioClock_GetCharacteristics
2831 };
2832
2833 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
2834         REFIID riid, void **ppv)
2835 {
2836     ACImpl *This = impl_from_IAudioClock2(iface);
2837     return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
2838 }
2839
2840 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
2841 {
2842     ACImpl *This = impl_from_IAudioClock2(iface);
2843     return IAudioClient_AddRef(&This->IAudioClient_iface);
2844 }
2845
2846 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
2847 {
2848     ACImpl *This = impl_from_IAudioClock2(iface);
2849     return IAudioClient_Release(&This->IAudioClient_iface);
2850 }
2851
2852 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
2853         UINT64 *pos, UINT64 *qpctime)
2854 {
2855     ACImpl *This = impl_from_IAudioClock2(iface);
2856
2857     FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
2858
2859     return E_NOTIMPL;
2860 }
2861
2862 static const IAudioClock2Vtbl AudioClock2_Vtbl =
2863 {
2864     AudioClock2_QueryInterface,
2865     AudioClock2_AddRef,
2866     AudioClock2_Release,
2867     AudioClock2_GetDevicePosition
2868 };
2869
2870 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
2871 {
2872     AudioSessionWrapper *ret;
2873
2874     ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2875             sizeof(AudioSessionWrapper));
2876     if(!ret)
2877         return NULL;
2878
2879     ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
2880     ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
2881     ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
2882
2883     ret->ref = 1;
2884
2885     ret->client = client;
2886     if(client){
2887         ret->session = client->session;
2888         AudioClient_AddRef(&client->IAudioClient_iface);
2889     }
2890
2891     return ret;
2892 }
2893
2894 static HRESULT WINAPI AudioSessionControl_QueryInterface(
2895         IAudioSessionControl2 *iface, REFIID riid, void **ppv)
2896 {
2897     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2898
2899     if(!ppv)
2900         return E_POINTER;
2901     *ppv = NULL;
2902
2903     if(IsEqualIID(riid, &IID_IUnknown) ||
2904             IsEqualIID(riid, &IID_IAudioSessionControl) ||
2905             IsEqualIID(riid, &IID_IAudioSessionControl2))
2906         *ppv = iface;
2907     if(*ppv){
2908         IUnknown_AddRef((IUnknown*)*ppv);
2909         return S_OK;
2910     }
2911
2912     WARN("Unknown interface %s\n", debugstr_guid(riid));
2913     return E_NOINTERFACE;
2914 }
2915
2916 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
2917 {
2918     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2919     ULONG ref;
2920     ref = InterlockedIncrement(&This->ref);
2921     TRACE("(%p) Refcount now %u\n", This, ref);
2922     return ref;
2923 }
2924
2925 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
2926 {
2927     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2928     ULONG ref;
2929     ref = InterlockedDecrement(&This->ref);
2930     TRACE("(%p) Refcount now %u\n", This, ref);
2931     if(!ref){
2932         if(This->client){
2933             EnterCriticalSection(&This->client->lock);
2934             This->client->session_wrapper = NULL;
2935             LeaveCriticalSection(&This->client->lock);
2936             AudioClient_Release(&This->client->IAudioClient_iface);
2937         }
2938         HeapFree(GetProcessHeap(), 0, This);
2939     }
2940     return ref;
2941 }
2942
2943 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
2944         AudioSessionState *state)
2945 {
2946     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2947     ACImpl *client;
2948
2949     TRACE("(%p)->(%p)\n", This, state);
2950
2951     if(!state)
2952         return NULL_PTR_ERR;
2953
2954     EnterCriticalSection(&g_sessions_lock);
2955
2956     if(list_empty(&This->session->clients)){
2957         *state = AudioSessionStateExpired;
2958         LeaveCriticalSection(&g_sessions_lock);
2959         return S_OK;
2960     }
2961
2962     LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
2963         EnterCriticalSection(&client->lock);
2964         if(client->started){
2965             *state = AudioSessionStateActive;
2966             LeaveCriticalSection(&client->lock);
2967             LeaveCriticalSection(&g_sessions_lock);
2968             return S_OK;
2969         }
2970         LeaveCriticalSection(&client->lock);
2971     }
2972
2973     LeaveCriticalSection(&g_sessions_lock);
2974
2975     *state = AudioSessionStateInactive;
2976
2977     return S_OK;
2978 }
2979
2980 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
2981         IAudioSessionControl2 *iface, WCHAR **name)
2982 {
2983     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2984
2985     FIXME("(%p)->(%p) - stub\n", This, name);
2986
2987     return E_NOTIMPL;
2988 }
2989
2990 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
2991         IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
2992 {
2993     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2994
2995     FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
2996
2997     return E_NOTIMPL;
2998 }
2999
3000 static HRESULT WINAPI AudioSessionControl_GetIconPath(
3001         IAudioSessionControl2 *iface, WCHAR **path)
3002 {
3003     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
3004
3005     FIXME("(%p)->(%p) - stub\n", This, path);
3006
3007     return E_NOTIMPL;
3008 }
3009
3010 static HRESULT WINAPI AudioSessionControl_SetIconPath(
3011         IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
3012 {
3013     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
3014
3015     FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
3016
3017     return E_NOTIMPL;
3018 }
3019
3020 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
3021         IAudioSessionControl2 *iface, GUID *group)
3022 {
3023     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
3024
3025     FIXME("(%p)->(%p) - stub\n", This, group);
3026
3027     return E_NOTIMPL;
3028 }
3029
3030 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
3031         IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
3032 {
3033     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
3034
3035     FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
3036             debugstr_guid(session));
3037
3038     return E_NOTIMPL;
3039 }
3040
3041 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
3042         IAudioSessionControl2 *iface, IAudioSessionEvents *events)
3043 {
3044     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
3045
3046     FIXME("(%p)->(%p) - stub\n", This, events);
3047
3048     return S_OK;
3049 }
3050
3051 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
3052         IAudioSessionControl2 *iface, IAudioSessionEvents *events)
3053 {
3054     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
3055
3056     FIXME("(%p)->(%p) - stub\n", This, events);
3057
3058     return S_OK;
3059 }
3060
3061 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
3062         IAudioSessionControl2 *iface, WCHAR **id)
3063 {
3064     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
3065
3066     FIXME("(%p)->(%p) - stub\n", This, id);
3067
3068     return E_NOTIMPL;
3069 }
3070
3071 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
3072         IAudioSessionControl2 *iface, WCHAR **id)
3073 {
3074     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
3075
3076     FIXME("(%p)->(%p) - stub\n", This, id);
3077
3078     return E_NOTIMPL;
3079 }
3080
3081 static HRESULT WINAPI AudioSessionControl_GetProcessId(
3082         IAudioSessionControl2 *iface, DWORD *pid)
3083 {
3084     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
3085
3086     TRACE("(%p)->(%p)\n", This, pid);
3087
3088     if(!pid)
3089         return E_POINTER;
3090
3091     *pid = GetCurrentProcessId();
3092
3093     return S_OK;
3094 }
3095
3096 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
3097         IAudioSessionControl2 *iface)
3098 {
3099     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
3100
3101     TRACE("(%p)\n", This);
3102
3103     return S_FALSE;
3104 }
3105
3106 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
3107         IAudioSessionControl2 *iface, BOOL optout)
3108 {
3109     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
3110
3111     TRACE("(%p)->(%d)\n", This, optout);
3112
3113     return S_OK;
3114 }
3115
3116 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
3117 {
3118     AudioSessionControl_QueryInterface,
3119     AudioSessionControl_AddRef,
3120     AudioSessionControl_Release,
3121     AudioSessionControl_GetState,
3122     AudioSessionControl_GetDisplayName,
3123     AudioSessionControl_SetDisplayName,
3124     AudioSessionControl_GetIconPath,
3125     AudioSessionControl_SetIconPath,
3126     AudioSessionControl_GetGroupingParam,
3127     AudioSessionControl_SetGroupingParam,
3128     AudioSessionControl_RegisterAudioSessionNotification,
3129     AudioSessionControl_UnregisterAudioSessionNotification,
3130     AudioSessionControl_GetSessionIdentifier,
3131     AudioSessionControl_GetSessionInstanceIdentifier,
3132     AudioSessionControl_GetProcessId,
3133     AudioSessionControl_IsSystemSoundsSession,
3134     AudioSessionControl_SetDuckingPreference
3135 };
3136
3137 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
3138         ISimpleAudioVolume *iface, REFIID riid, void **ppv)
3139 {
3140     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
3141
3142     if(!ppv)
3143         return E_POINTER;
3144     *ppv = NULL;
3145
3146     if(IsEqualIID(riid, &IID_IUnknown) ||
3147             IsEqualIID(riid, &IID_ISimpleAudioVolume))
3148         *ppv = iface;
3149     if(*ppv){
3150         IUnknown_AddRef((IUnknown*)*ppv);
3151         return S_OK;
3152     }
3153
3154     WARN("Unknown interface %s\n", debugstr_guid(riid));
3155     return E_NOINTERFACE;
3156 }
3157
3158 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
3159 {
3160     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
3161     return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
3162 }
3163
3164 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
3165 {
3166     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
3167     return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
3168 }
3169
3170 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
3171         ISimpleAudioVolume *iface, float level, const GUID *context)
3172 {
3173     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
3174     AudioSession *session = This->session;
3175
3176     TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
3177
3178     if(level < 0.f || level > 1.f)
3179         return E_INVALIDARG;
3180
3181     if(context)
3182         FIXME("Notifications not supported yet\n");
3183
3184     TRACE("ALSA does not support volume control\n");
3185
3186     EnterCriticalSection(&session->lock);
3187
3188     session->master_vol = level;
3189
3190     LeaveCriticalSection(&session->lock);
3191
3192     return S_OK;
3193 }
3194
3195 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
3196         ISimpleAudioVolume *iface, float *level)
3197 {
3198     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
3199     AudioSession *session = This->session;
3200
3201     TRACE("(%p)->(%p)\n", session, level);
3202
3203     if(!level)
3204         return NULL_PTR_ERR;
3205
3206     *level = session->master_vol;
3207
3208     return S_OK;
3209 }
3210
3211 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
3212         BOOL mute, const GUID *context)
3213 {
3214     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
3215     AudioSession *session = This->session;
3216
3217     TRACE("(%p)->(%u, %p)\n", session, mute, context);
3218
3219     if(context)
3220         FIXME("Notifications not supported yet\n");
3221
3222     session->mute = mute;
3223
3224     return S_OK;
3225 }
3226
3227 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
3228         BOOL *mute)
3229 {
3230     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
3231     AudioSession *session = This->session;
3232
3233     TRACE("(%p)->(%p)\n", session, mute);
3234
3235     if(!mute)
3236         return NULL_PTR_ERR;
3237
3238     *mute = session->mute;
3239
3240     return S_OK;
3241 }
3242
3243 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl  =
3244 {
3245     SimpleAudioVolume_QueryInterface,
3246     SimpleAudioVolume_AddRef,
3247     SimpleAudioVolume_Release,
3248     SimpleAudioVolume_SetMasterVolume,
3249     SimpleAudioVolume_GetMasterVolume,
3250     SimpleAudioVolume_SetMute,
3251     SimpleAudioVolume_GetMute
3252 };
3253
3254 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
3255         IAudioStreamVolume *iface, REFIID riid, void **ppv)
3256 {
3257     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
3258
3259     if(!ppv)
3260         return E_POINTER;
3261     *ppv = NULL;
3262
3263     if(IsEqualIID(riid, &IID_IUnknown) ||
3264             IsEqualIID(riid, &IID_IAudioStreamVolume))
3265         *ppv = iface;
3266     if(*ppv){
3267         IUnknown_AddRef((IUnknown*)*ppv);
3268         return S_OK;
3269     }
3270
3271     WARN("Unknown interface %s\n", debugstr_guid(riid));
3272     return E_NOINTERFACE;
3273 }
3274
3275 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
3276 {
3277     ACImpl *This = impl_from_IAudioStreamVolume(iface);
3278     return IAudioClient_AddRef(&This->IAudioClient_iface);
3279 }
3280
3281 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
3282 {
3283     ACImpl *This = impl_from_IAudioStreamVolume(iface);
3284     return IAudioClient_Release(&This->IAudioClient_iface);
3285 }
3286
3287 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
3288         IAudioStreamVolume *iface, UINT32 *out)
3289 {
3290     ACImpl *This = impl_from_IAudioStreamVolume(iface);
3291
3292     TRACE("(%p)->(%p)\n", This, out);
3293
3294     if(!out)
3295         return E_POINTER;
3296
3297     *out = This->fmt->nChannels;
3298
3299     return S_OK;
3300 }
3301
3302 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
3303         IAudioStreamVolume *iface, UINT32 index, float level)
3304 {
3305     ACImpl *This = impl_from_IAudioStreamVolume(iface);
3306
3307     TRACE("(%p)->(%d, %f)\n", This, index, level);
3308
3309     if(level < 0.f || level > 1.f)
3310         return E_INVALIDARG;
3311
3312     if(index >= This->fmt->nChannels)
3313         return E_INVALIDARG;
3314
3315     TRACE("ALSA does not support volume control\n");
3316
3317     EnterCriticalSection(&This->lock);
3318
3319     This->vols[index] = level;
3320
3321     LeaveCriticalSection(&This->lock);
3322
3323     return S_OK;
3324 }
3325
3326 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
3327         IAudioStreamVolume *iface, UINT32 index, float *level)
3328 {
3329     ACImpl *This = impl_from_IAudioStreamVolume(iface);
3330
3331     TRACE("(%p)->(%d, %p)\n", This, index, level);
3332
3333     if(!level)
3334         return E_POINTER;
3335
3336     if(index >= This->fmt->nChannels)
3337         return E_INVALIDARG;
3338
3339     *level = This->vols[index];
3340
3341     return S_OK;
3342 }
3343
3344 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
3345         IAudioStreamVolume *iface, UINT32 count, const float *levels)
3346 {
3347     ACImpl *This = impl_from_IAudioStreamVolume(iface);
3348     int i;
3349
3350     TRACE("(%p)->(%d, %p)\n", This, count, levels);
3351
3352     if(!levels)
3353         return E_POINTER;
3354
3355     if(count != This->fmt->nChannels)
3356         return E_INVALIDARG;
3357
3358     TRACE("ALSA does not support volume control\n");
3359
3360     EnterCriticalSection(&This->lock);
3361
3362     for(i = 0; i < count; ++i)
3363         This->vols[i] = levels[i];
3364
3365     LeaveCriticalSection(&This->lock);
3366
3367     return S_OK;
3368 }
3369
3370 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
3371         IAudioStreamVolume *iface, UINT32 count, float *levels)
3372 {
3373     ACImpl *This = impl_from_IAudioStreamVolume(iface);
3374     int i;
3375
3376     TRACE("(%p)->(%d, %p)\n", This, count, levels);
3377
3378     if(!levels)
3379         return E_POINTER;
3380
3381     if(count != This->fmt->nChannels)
3382         return E_INVALIDARG;
3383
3384     EnterCriticalSection(&This->lock);
3385
3386     for(i = 0; i < count; ++i)
3387         levels[i] = This->vols[i];
3388
3389     LeaveCriticalSection(&This->lock);
3390
3391     return S_OK;
3392 }
3393
3394 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
3395 {
3396     AudioStreamVolume_QueryInterface,
3397     AudioStreamVolume_AddRef,
3398     AudioStreamVolume_Release,
3399     AudioStreamVolume_GetChannelCount,
3400     AudioStreamVolume_SetChannelVolume,
3401     AudioStreamVolume_GetChannelVolume,
3402     AudioStreamVolume_SetAllVolumes,
3403     AudioStreamVolume_GetAllVolumes
3404 };
3405
3406 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
3407         IChannelAudioVolume *iface, REFIID riid, void **ppv)
3408 {
3409     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
3410
3411     if(!ppv)
3412         return E_POINTER;
3413     *ppv = NULL;
3414
3415     if(IsEqualIID(riid, &IID_IUnknown) ||
3416             IsEqualIID(riid, &IID_IChannelAudioVolume))
3417         *ppv = iface;
3418     if(*ppv){
3419         IUnknown_AddRef((IUnknown*)*ppv);
3420         return S_OK;
3421     }
3422
3423     WARN("Unknown interface %s\n", debugstr_guid(riid));
3424     return E_NOINTERFACE;
3425 }
3426
3427 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
3428 {
3429     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
3430     return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
3431 }
3432
3433 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
3434 {
3435     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
3436     return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
3437 }
3438
3439 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
3440         IChannelAudioVolume *iface, UINT32 *out)
3441 {
3442     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
3443     AudioSession *session = This->session;
3444
3445     TRACE("(%p)->(%p)\n", session, out);
3446
3447     if(!out)
3448         return NULL_PTR_ERR;
3449
3450     *out = session->channel_count;
3451
3452     return S_OK;
3453 }
3454
3455 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
3456         IChannelAudioVolume *iface, UINT32 index, float level,
3457         const GUID *context)
3458 {
3459     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
3460     AudioSession *session = This->session;
3461
3462     TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
3463             wine_dbgstr_guid(context));
3464
3465     if(level < 0.f || level > 1.f)
3466         return E_INVALIDARG;
3467
3468     if(index >= session->channel_count)
3469         return E_INVALIDARG;
3470
3471     if(context)
3472         FIXME("Notifications not supported yet\n");
3473
3474     TRACE("ALSA does not support volume control\n");
3475
3476     EnterCriticalSection(&session->lock);
3477
3478     session->channel_vols[index] = level;
3479
3480     LeaveCriticalSection(&session->lock);
3481
3482     return S_OK;
3483 }
3484
3485 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
3486         IChannelAudioVolume *iface, UINT32 index, float *level)
3487 {
3488     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
3489     AudioSession *session = This->session;
3490
3491     TRACE("(%p)->(%d, %p)\n", session, index, level);
3492
3493     if(!level)
3494         return NULL_PTR_ERR;
3495
3496     if(index >= session->channel_count)
3497         return E_INVALIDARG;
3498
3499     *level = session->channel_vols[index];
3500
3501     return S_OK;
3502 }
3503
3504 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
3505         IChannelAudioVolume *iface, UINT32 count, const float *levels,
3506         const GUID *context)
3507 {
3508     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
3509     AudioSession *session = This->session;
3510     int i;
3511
3512     TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
3513             wine_dbgstr_guid(context));
3514
3515     if(!levels)
3516         return NULL_PTR_ERR;
3517
3518     if(count != session->channel_count)
3519         return E_INVALIDARG;
3520
3521     if(context)
3522         FIXME("Notifications not supported yet\n");
3523
3524     TRACE("ALSA does not support volume control\n");
3525
3526     EnterCriticalSection(&session->lock);
3527
3528     for(i = 0; i < count; ++i)
3529         session->channel_vols[i] = levels[i];
3530
3531     LeaveCriticalSection(&session->lock);
3532
3533     return S_OK;
3534 }
3535
3536 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
3537         IChannelAudioVolume *iface, UINT32 count, float *levels)
3538 {
3539     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
3540     AudioSession *session = This->session;
3541     int i;
3542
3543     TRACE("(%p)->(%d, %p)\n", session, count, levels);
3544
3545     if(!levels)
3546         return NULL_PTR_ERR;
3547
3548     if(count != session->channel_count)
3549         return E_INVALIDARG;
3550
3551     for(i = 0; i < count; ++i)
3552         levels[i] = session->channel_vols[i];
3553
3554     return S_OK;
3555 }
3556
3557 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
3558 {
3559     ChannelAudioVolume_QueryInterface,
3560     ChannelAudioVolume_AddRef,
3561     ChannelAudioVolume_Release,
3562     ChannelAudioVolume_GetChannelCount,
3563     ChannelAudioVolume_SetChannelVolume,
3564     ChannelAudioVolume_GetChannelVolume,
3565     ChannelAudioVolume_SetAllVolumes,
3566     ChannelAudioVolume_GetAllVolumes
3567 };
3568
3569 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
3570         REFIID riid, void **ppv)
3571 {
3572     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
3573
3574     if(!ppv)
3575         return E_POINTER;
3576     *ppv = NULL;
3577
3578     if(IsEqualIID(riid, &IID_IUnknown) ||
3579             IsEqualIID(riid, &IID_IAudioSessionManager) ||
3580             IsEqualIID(riid, &IID_IAudioSessionManager2))
3581         *ppv = iface;
3582     if(*ppv){
3583         IUnknown_AddRef((IUnknown*)*ppv);
3584         return S_OK;
3585     }
3586
3587     WARN("Unknown interface %s\n", debugstr_guid(riid));
3588     return E_NOINTERFACE;
3589 }
3590
3591 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
3592 {
3593     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3594     ULONG ref;
3595     ref = InterlockedIncrement(&This->ref);
3596     TRACE("(%p) Refcount now %u\n", This, ref);
3597     return ref;
3598 }
3599
3600 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
3601 {
3602     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3603     ULONG ref;
3604     ref = InterlockedDecrement(&This->ref);
3605     TRACE("(%p) Refcount now %u\n", This, ref);
3606     if(!ref)
3607         HeapFree(GetProcessHeap(), 0, This);
3608     return ref;
3609 }
3610
3611 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
3612         IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
3613         IAudioSessionControl **out)
3614 {
3615     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3616     AudioSession *session;
3617     AudioSessionWrapper *wrapper;
3618     HRESULT hr;
3619
3620     TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
3621             flags, out);
3622
3623     hr = get_audio_session(session_guid, This->device, 0, &session);
3624     if(FAILED(hr))
3625         return hr;
3626
3627     wrapper = AudioSessionWrapper_Create(NULL);
3628     if(!wrapper)
3629         return E_OUTOFMEMORY;
3630
3631     wrapper->session = session;
3632
3633     *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
3634
3635     return S_OK;
3636 }
3637
3638 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
3639         IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
3640         ISimpleAudioVolume **out)
3641 {
3642     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3643     AudioSession *session;
3644     AudioSessionWrapper *wrapper;
3645     HRESULT hr;
3646
3647     TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
3648             flags, out);
3649
3650     hr = get_audio_session(session_guid, This->device, 0, &session);
3651     if(FAILED(hr))
3652         return hr;
3653
3654     wrapper = AudioSessionWrapper_Create(NULL);
3655     if(!wrapper)
3656         return E_OUTOFMEMORY;
3657
3658     wrapper->session = session;
3659
3660     *out = &wrapper->ISimpleAudioVolume_iface;
3661
3662     return S_OK;
3663 }
3664
3665 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
3666         IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
3667 {
3668     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3669     FIXME("(%p)->(%p) - stub\n", This, out);
3670     return E_NOTIMPL;
3671 }
3672
3673 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
3674         IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
3675 {
3676     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3677     FIXME("(%p)->(%p) - stub\n", This, notification);
3678     return E_NOTIMPL;
3679 }
3680
3681 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
3682         IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
3683 {
3684     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3685     FIXME("(%p)->(%p) - stub\n", This, notification);
3686     return E_NOTIMPL;
3687 }
3688
3689 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
3690         IAudioSessionManager2 *iface, const WCHAR *session_id,
3691         IAudioVolumeDuckNotification *notification)
3692 {
3693     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3694     FIXME("(%p)->(%p) - stub\n", This, notification);
3695     return E_NOTIMPL;
3696 }
3697
3698 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
3699         IAudioSessionManager2 *iface,
3700         IAudioVolumeDuckNotification *notification)
3701 {
3702     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3703     FIXME("(%p)->(%p) - stub\n", This, notification);
3704     return E_NOTIMPL;
3705 }
3706
3707 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
3708 {
3709     AudioSessionManager_QueryInterface,
3710     AudioSessionManager_AddRef,
3711     AudioSessionManager_Release,
3712     AudioSessionManager_GetAudioSessionControl,
3713     AudioSessionManager_GetSimpleAudioVolume,
3714     AudioSessionManager_GetSessionEnumerator,
3715     AudioSessionManager_RegisterSessionNotification,
3716     AudioSessionManager_UnregisterSessionNotification,
3717     AudioSessionManager_RegisterDuckNotification,
3718     AudioSessionManager_UnregisterDuckNotification
3719 };
3720
3721 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
3722         IAudioSessionManager2 **out)
3723 {
3724     SessionMgr *This;
3725
3726     This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
3727     if(!This)
3728         return E_OUTOFMEMORY;
3729
3730     This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
3731     This->device = device;
3732     This->ref = 1;
3733
3734     *out = &This->IAudioSessionManager2_iface;
3735
3736     return S_OK;
3737 }