wined3d: Recognize Nvidia GT520 cards.
[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 "mmsystem.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         }
982     }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
983             (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
984              IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
985         if(fmt->wBitsPerSample == 32)
986             format = SND_PCM_FORMAT_FLOAT_LE;
987         else if(fmt->wBitsPerSample == 64)
988             format = SND_PCM_FORMAT_FLOAT64_LE;
989         else
990             WARN("Unsupported float size: %u\n", fmt->wBitsPerSample);
991     }else
992         WARN("Unknown wave format: %04x\n", fmt->wFormatTag);
993     return format;
994 }
995
996 static void session_init_vols(AudioSession *session, UINT channels)
997 {
998     if(session->channel_count < channels){
999         UINT i;
1000
1001         if(session->channel_vols)
1002             session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
1003                     session->channel_vols, sizeof(float) * channels);
1004         else
1005             session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
1006                     sizeof(float) * channels);
1007         if(!session->channel_vols)
1008             return;
1009
1010         for(i = session->channel_count; i < channels; ++i)
1011             session->channel_vols[i] = 1.f;
1012
1013         session->channel_count = channels;
1014     }
1015 }
1016
1017 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
1018         UINT num_channels)
1019 {
1020     AudioSession *ret;
1021
1022     ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
1023     if(!ret)
1024         return NULL;
1025
1026     memcpy(&ret->guid, guid, sizeof(GUID));
1027
1028     ret->device = device;
1029
1030     list_init(&ret->clients);
1031
1032     list_add_head(&g_sessions, &ret->entry);
1033
1034     InitializeCriticalSection(&ret->lock);
1035     ret->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": AudioSession.lock");
1036
1037     session_init_vols(ret, num_channels);
1038
1039     ret->master_vol = 1.f;
1040
1041     return ret;
1042 }
1043
1044 /* if channels == 0, then this will return or create a session with
1045  * matching dataflow and GUID. otherwise, channels must also match */
1046 static HRESULT get_audio_session(const GUID *sessionguid,
1047         IMMDevice *device, UINT channels, AudioSession **out)
1048 {
1049     AudioSession *session;
1050
1051     if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
1052         *out = create_session(&GUID_NULL, device, channels);
1053         if(!*out)
1054             return E_OUTOFMEMORY;
1055
1056         return S_OK;
1057     }
1058
1059     *out = NULL;
1060     LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
1061         if(session->device == device &&
1062                 IsEqualGUID(sessionguid, &session->guid)){
1063             session_init_vols(session, channels);
1064             *out = session;
1065             break;
1066         }
1067     }
1068
1069     if(!*out){
1070         *out = create_session(sessionguid, device, channels);
1071         if(!*out)
1072             return E_OUTOFMEMORY;
1073     }
1074
1075     return S_OK;
1076 }
1077
1078 static int alsa_channel_index(DWORD flag)
1079 {
1080     switch(flag){
1081     case SPEAKER_FRONT_LEFT:
1082         return 0;
1083     case SPEAKER_FRONT_RIGHT:
1084         return 1;
1085     case SPEAKER_BACK_LEFT:
1086         return 2;
1087     case SPEAKER_BACK_RIGHT:
1088         return 3;
1089     case SPEAKER_FRONT_CENTER:
1090         return 4;
1091     case SPEAKER_LOW_FREQUENCY:
1092         return 5;
1093     case SPEAKER_SIDE_LEFT:
1094         return 6;
1095     case SPEAKER_SIDE_RIGHT:
1096         return 7;
1097     }
1098     return -1;
1099 }
1100
1101 static BOOL need_remapping(ACImpl *This, const WAVEFORMATEX *fmt)
1102 {
1103     unsigned int i;
1104     for(i = 0; i < fmt->nChannels; ++i){
1105         if(This->alsa_channel_map[i] != i)
1106             return TRUE;
1107     }
1108     return FALSE;
1109 }
1110
1111 static DWORD get_channel_mask(unsigned int channels)
1112 {
1113     switch(channels){
1114     case 0:
1115         return 0;
1116     case 1:
1117         return KSAUDIO_SPEAKER_MONO;
1118     case 2:
1119         return KSAUDIO_SPEAKER_STEREO;
1120     case 3:
1121         return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY;
1122     case 4:
1123         return KSAUDIO_SPEAKER_QUAD;    /* not _SURROUND */
1124     case 5:
1125         return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY;
1126     case 6:
1127         return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */
1128     case 7:
1129         return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER;
1130     case 8:
1131         return KSAUDIO_SPEAKER_7POINT1_SURROUND; /* Vista deprecates 7POINT1 */
1132     }
1133     FIXME("Unknown speaker configuration: %u\n", channels);
1134     return 0;
1135 }
1136
1137 static HRESULT map_channels(ACImpl *This, const WAVEFORMATEX *fmt)
1138 {
1139     if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE || fmt->nChannels > 2){
1140         WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
1141         DWORD mask, flag = SPEAKER_FRONT_LEFT;
1142         UINT i = 0;
1143
1144         if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1145                 fmtex->dwChannelMask != 0)
1146             mask = fmtex->dwChannelMask;
1147         else
1148             mask = get_channel_mask(fmt->nChannels);
1149
1150         This->alsa_channels = 0;
1151
1152         while(i < fmt->nChannels && !(flag & SPEAKER_RESERVED)){
1153             if(mask & flag){
1154                 This->alsa_channel_map[i] = alsa_channel_index(flag);
1155                 TRACE("Mapping mmdevapi channel %u (0x%x) to ALSA channel %d\n",
1156                         i, flag, This->alsa_channel_map[i]);
1157                 if(This->alsa_channel_map[i] >= This->alsa_channels)
1158                     This->alsa_channels = This->alsa_channel_map[i] + 1;
1159                 ++i;
1160             }
1161             flag <<= 1;
1162         }
1163
1164         while(i < fmt->nChannels){
1165             This->alsa_channel_map[i] = This->alsa_channels;
1166             TRACE("Mapping mmdevapi channel %u to ALSA channel %d\n",
1167                     i, This->alsa_channel_map[i]);
1168             ++This->alsa_channels;
1169             ++i;
1170         }
1171
1172         for(i = 0; i < fmt->nChannels; ++i){
1173             if(This->alsa_channel_map[i] == -1){
1174                 This->alsa_channel_map[i] = This->alsa_channels;
1175                 ++This->alsa_channels;
1176                 TRACE("Remapping mmdevapi channel %u to ALSA channel %d\n",
1177                         i, This->alsa_channel_map[i]);
1178             }
1179         }
1180
1181         This->need_remapping = need_remapping(This, fmt);
1182
1183         TRACE("need_remapping: %u, alsa_channels: %d\n", This->need_remapping, This->alsa_channels);
1184     }else{
1185         This->need_remapping = FALSE;
1186         This->alsa_channels = fmt->nChannels;
1187         TRACE("need_remapping: %u, alsa_channels: %d\n", This->need_remapping, This->alsa_channels);
1188     }
1189
1190     return S_OK;
1191 }
1192
1193 static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
1194         AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
1195         REFERENCE_TIME period, const WAVEFORMATEX *fmt,
1196         const GUID *sessionguid)
1197 {
1198     ACImpl *This = impl_from_IAudioClient(iface);
1199     snd_pcm_sw_params_t *sw_params = NULL;
1200     snd_pcm_format_t format;
1201     unsigned int rate, alsa_period_us;
1202     int err, i;
1203     HRESULT hr = S_OK;
1204
1205     TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
1206           wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
1207
1208     if(!fmt)
1209         return E_POINTER;
1210
1211     if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1212         return AUDCLNT_E_NOT_INITIALIZED;
1213
1214     if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
1215                 AUDCLNT_STREAMFLAGS_LOOPBACK |
1216                 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
1217                 AUDCLNT_STREAMFLAGS_NOPERSIST |
1218                 AUDCLNT_STREAMFLAGS_RATEADJUST |
1219                 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
1220                 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
1221                 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED)){
1222         TRACE("Unknown flags: %08x\n", flags);
1223         return E_INVALIDARG;
1224     }
1225
1226     if(mode == AUDCLNT_SHAREMODE_SHARED){
1227         period = DefaultPeriod;
1228         if( duration < 3 * period)
1229             duration = 3 * period;
1230     }else{
1231         if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
1232             if(((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask == 0 ||
1233                     ((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask & SPEAKER_RESERVED)
1234                 return AUDCLNT_E_UNSUPPORTED_FORMAT;
1235         }
1236
1237         if(!period)
1238             period = DefaultPeriod; /* not minimum */
1239         if(period < MinimumPeriod || period > 5000000)
1240             return AUDCLNT_E_INVALID_DEVICE_PERIOD;
1241         if(duration > 20000000) /* the smaller the period, the lower this limit */
1242             return AUDCLNT_E_BUFFER_SIZE_ERROR;
1243         if(flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK){
1244             if(duration != period)
1245                 return AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL;
1246             FIXME("EXCLUSIVE mode with EVENTCALLBACK\n");
1247             return AUDCLNT_E_DEVICE_IN_USE;
1248         }else{
1249             if( duration < 8 * period)
1250                 duration = 8 * period; /* may grow above 2s */
1251         }
1252     }
1253
1254     EnterCriticalSection(&This->lock);
1255
1256     if(This->initted){
1257         LeaveCriticalSection(&This->lock);
1258         return AUDCLNT_E_ALREADY_INITIALIZED;
1259     }
1260
1261     dump_fmt(fmt);
1262
1263     if(FAILED(map_channels(This, fmt))){
1264         WARN("map_channels failed\n");
1265         hr = AUDCLNT_E_ENDPOINT_CREATE_FAILED;
1266         goto exit;
1267     }
1268
1269     if((err = snd_pcm_hw_params_any(This->pcm_handle, This->hw_params)) < 0){
1270         WARN("Unable to get hw_params: %d (%s)\n", err, snd_strerror(err));
1271         hr = AUDCLNT_E_ENDPOINT_CREATE_FAILED;
1272         goto exit;
1273     }
1274
1275     if((err = snd_pcm_hw_params_set_access(This->pcm_handle, This->hw_params,
1276                 SND_PCM_ACCESS_RW_INTERLEAVED)) < 0){
1277         WARN("Unable to set access: %d (%s)\n", err, snd_strerror(err));
1278         hr = AUDCLNT_E_ENDPOINT_CREATE_FAILED;
1279         goto exit;
1280     }
1281
1282     format = alsa_format(fmt);
1283     if (format == SND_PCM_FORMAT_UNKNOWN){
1284         hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
1285         goto exit;
1286     }
1287
1288     if((err = snd_pcm_hw_params_set_format(This->pcm_handle, This->hw_params,
1289                 format)) < 0){
1290         WARN("Unable to set ALSA format to %u: %d (%s)\n", format, err,
1291                 snd_strerror(err));
1292         hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
1293         goto exit;
1294     }
1295
1296     This->alsa_format = format;
1297
1298     rate = fmt->nSamplesPerSec;
1299     if((err = snd_pcm_hw_params_set_rate_near(This->pcm_handle, This->hw_params,
1300                 &rate, NULL)) < 0){
1301         WARN("Unable to set rate to %u: %d (%s)\n", rate, err,
1302                 snd_strerror(err));
1303         hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
1304         goto exit;
1305     }
1306
1307     if((err = snd_pcm_hw_params_set_channels(This->pcm_handle, This->hw_params,
1308                 This->alsa_channels)) < 0){
1309         WARN("Unable to set channels to %u: %d (%s)\n", fmt->nChannels, err,
1310                 snd_strerror(err));
1311         hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
1312         goto exit;
1313     }
1314
1315     This->mmdev_period_rt = period;
1316     alsa_period_us = This->mmdev_period_rt / 10;
1317     if((err = snd_pcm_hw_params_set_period_time_near(This->pcm_handle,
1318                 This->hw_params, &alsa_period_us, NULL)) < 0)
1319         WARN("Unable to set period time near %u: %d (%s)\n", alsa_period_us,
1320                 err, snd_strerror(err));
1321     /* ALSA updates the output variable alsa_period_us */
1322
1323     This->mmdev_period_frames = MulDiv(fmt->nSamplesPerSec,
1324             This->mmdev_period_rt, 10000000);
1325
1326     /* Buffer 4 ALSA periods if large enough, else 4 mmdevapi periods */
1327     This->alsa_bufsize_frames = This->mmdev_period_frames * 4;
1328     if(err < 0 || alsa_period_us < period / 10)
1329         err = snd_pcm_hw_params_set_buffer_size_near(This->pcm_handle,
1330                 This->hw_params, &This->alsa_bufsize_frames);
1331     else{
1332         unsigned int periods = 4;
1333         err = snd_pcm_hw_params_set_periods_near(This->pcm_handle, This->hw_params, &periods, NULL);
1334     }
1335     if(err < 0)
1336         WARN("Unable to set buffer size: %d (%s)\n", err, snd_strerror(err));
1337
1338     if((err = snd_pcm_hw_params(This->pcm_handle, This->hw_params)) < 0){
1339         WARN("Unable to set hw params: %d (%s)\n", err, snd_strerror(err));
1340         hr = AUDCLNT_E_ENDPOINT_CREATE_FAILED;
1341         goto exit;
1342     }
1343
1344     if((err = snd_pcm_hw_params_get_period_size(This->hw_params,
1345                     &This->alsa_period_frames, NULL)) < 0){
1346         WARN("Unable to get period size: %d (%s)\n", err, snd_strerror(err));
1347         hr = AUDCLNT_E_ENDPOINT_CREATE_FAILED;
1348         goto exit;
1349     }
1350
1351     if((err = snd_pcm_hw_params_get_buffer_size(This->hw_params,
1352                     &This->alsa_bufsize_frames)) < 0){
1353         WARN("Unable to get buffer size: %d (%s)\n", err, snd_strerror(err));
1354         hr = AUDCLNT_E_ENDPOINT_CREATE_FAILED;
1355         goto exit;
1356     }
1357
1358     sw_params = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_sw_params_sizeof());
1359     if(!sw_params){
1360         hr = E_OUTOFMEMORY;
1361         goto exit;
1362     }
1363
1364     if((err = snd_pcm_sw_params_current(This->pcm_handle, sw_params)) < 0){
1365         WARN("Unable to get sw_params: %d (%s)\n", err, snd_strerror(err));
1366         hr = AUDCLNT_E_ENDPOINT_CREATE_FAILED;
1367         goto exit;
1368     }
1369
1370     if((err = snd_pcm_sw_params_set_start_threshold(This->pcm_handle,
1371                     sw_params, 1)) < 0){
1372         WARN("Unable set start threshold to 0: %d (%s)\n", err, snd_strerror(err));
1373         hr = AUDCLNT_E_ENDPOINT_CREATE_FAILED;
1374         goto exit;
1375     }
1376
1377     if((err = snd_pcm_sw_params_set_stop_threshold(This->pcm_handle,
1378                     sw_params, This->alsa_bufsize_frames)) < 0){
1379         WARN("Unable set stop threshold to %lu: %d (%s)\n",
1380                 This->alsa_bufsize_frames, err, snd_strerror(err));
1381         hr = AUDCLNT_E_ENDPOINT_CREATE_FAILED;
1382         goto exit;
1383     }
1384
1385     if((err = snd_pcm_sw_params(This->pcm_handle, sw_params)) < 0){
1386         WARN("Unable to set sw params: %d (%s)\n", err, snd_strerror(err));
1387         hr = AUDCLNT_E_ENDPOINT_CREATE_FAILED;
1388         goto exit;
1389     }
1390
1391     if((err = snd_pcm_prepare(This->pcm_handle)) < 0){
1392         WARN("Unable to prepare device: %d (%s)\n", err, snd_strerror(err));
1393         hr = AUDCLNT_E_ENDPOINT_CREATE_FAILED;
1394         goto exit;
1395     }
1396
1397     /* Bear in mind weird situations where
1398      * ALSA period (50ms) > mmdevapi buffer (3x10ms)
1399      * or surprising rounding as seen with 22050x8x1 with Pulse:
1400      * ALSA period 220 vs.  221 frames in mmdevapi and
1401      *      buffer 883 vs. 2205 frames in mmdevapi! */
1402     This->bufsize_frames = MulDiv(duration, fmt->nSamplesPerSec, 10000000);
1403     This->hidden_frames = This->alsa_period_frames + This->mmdev_period_frames +
1404         MulDiv(fmt->nSamplesPerSec, EXTRA_SAFE_RT, 10000000);
1405
1406     /* Check if the ALSA buffer is so small that it will run out before
1407      * the next MMDevAPI period tick occurs. Allow a little wiggle room
1408      * with 120% of the period time. */
1409     if(This->alsa_bufsize_frames < 1.2 * This->mmdev_period_frames)
1410         FIXME("ALSA buffer time is too small. Expect underruns. (%lu < %u * 1.2)\n",
1411                 This->alsa_bufsize_frames, This->mmdev_period_frames);
1412
1413     This->local_buffer = HeapAlloc(GetProcessHeap(), 0,
1414             This->bufsize_frames * fmt->nBlockAlign);
1415     if(!This->local_buffer){
1416         hr = E_OUTOFMEMORY;
1417         goto exit;
1418     }
1419     if (fmt->wBitsPerSample == 8)
1420         memset(This->local_buffer, 128, This->bufsize_frames * fmt->nBlockAlign);
1421     else
1422         memset(This->local_buffer, 0, This->bufsize_frames * fmt->nBlockAlign);
1423
1424     This->fmt = clone_format(fmt);
1425     if(!This->fmt){
1426         hr = E_OUTOFMEMORY;
1427         goto exit;
1428     }
1429
1430     This->vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float));
1431     if(!This->vols){
1432         hr = E_OUTOFMEMORY;
1433         goto exit;
1434     }
1435
1436     for(i = 0; i < fmt->nChannels; ++i)
1437         This->vols[i] = 1.f;
1438
1439     This->share = mode;
1440     This->flags = flags;
1441
1442     EnterCriticalSection(&g_sessions_lock);
1443
1444     hr = get_audio_session(sessionguid, This->parent, fmt->nChannels,
1445             &This->session);
1446     if(FAILED(hr)){
1447         LeaveCriticalSection(&g_sessions_lock);
1448         goto exit;
1449     }
1450
1451     list_add_tail(&This->session->clients, &This->entry);
1452
1453     LeaveCriticalSection(&g_sessions_lock);
1454
1455     This->initted = TRUE;
1456
1457     TRACE("ALSA period: %lu frames\n", This->alsa_period_frames);
1458     TRACE("ALSA buffer: %lu frames\n", This->alsa_bufsize_frames);
1459     TRACE("MMDevice period: %u frames\n", This->mmdev_period_frames);
1460     TRACE("MMDevice buffer: %u frames\n", This->bufsize_frames);
1461
1462 exit:
1463     HeapFree(GetProcessHeap(), 0, sw_params);
1464     if(FAILED(hr)){
1465         HeapFree(GetProcessHeap(), 0, This->local_buffer);
1466         This->local_buffer = NULL;
1467         CoTaskMemFree(This->fmt);
1468         This->fmt = NULL;
1469         HeapFree(GetProcessHeap(), 0, This->vols);
1470         This->vols = NULL;
1471     }
1472
1473     LeaveCriticalSection(&This->lock);
1474
1475     return hr;
1476 }
1477
1478 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
1479         UINT32 *out)
1480 {
1481     ACImpl *This = impl_from_IAudioClient(iface);
1482
1483     TRACE("(%p)->(%p)\n", This, out);
1484
1485     if(!out)
1486         return E_POINTER;
1487
1488     EnterCriticalSection(&This->lock);
1489
1490     if(!This->initted){
1491         LeaveCriticalSection(&This->lock);
1492         return AUDCLNT_E_NOT_INITIALIZED;
1493     }
1494
1495     *out = This->bufsize_frames;
1496
1497     LeaveCriticalSection(&This->lock);
1498
1499     return S_OK;
1500 }
1501
1502 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
1503         REFERENCE_TIME *latency)
1504 {
1505     ACImpl *This = impl_from_IAudioClient(iface);
1506
1507     TRACE("(%p)->(%p)\n", This, latency);
1508
1509     if(!latency)
1510         return E_POINTER;
1511
1512     EnterCriticalSection(&This->lock);
1513
1514     if(!This->initted){
1515         LeaveCriticalSection(&This->lock);
1516         return AUDCLNT_E_NOT_INITIALIZED;
1517     }
1518
1519     /* Hide some frames in the ALSA buffer. Allows us to return GetCurrentPadding=0
1520      * yet have enough data left to play (as if it were in native's mixer). Add:
1521      * + mmdevapi_period such that at the end of it, ALSA still has data;
1522      * + EXTRA_SAFE (~4ms) to allow for late callback invocation / fluctuation;
1523      * + alsa_period such that ALSA always has at least one period to play. */
1524     if(This->dataflow == eRender)
1525         *latency = MulDiv(This->hidden_frames, 10000000, This->fmt->nSamplesPerSec);
1526     else
1527         *latency = MulDiv(This->alsa_period_frames, 10000000, This->fmt->nSamplesPerSec)
1528                  + This->mmdev_period_rt;
1529
1530     LeaveCriticalSection(&This->lock);
1531
1532     return S_OK;
1533 }
1534
1535 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
1536         UINT32 *out)
1537 {
1538     ACImpl *This = impl_from_IAudioClient(iface);
1539
1540     TRACE("(%p)->(%p)\n", This, out);
1541
1542     if(!out)
1543         return E_POINTER;
1544
1545     EnterCriticalSection(&This->lock);
1546
1547     if(!This->initted){
1548         LeaveCriticalSection(&This->lock);
1549         return AUDCLNT_E_NOT_INITIALIZED;
1550     }
1551
1552     /* padding is solely updated at callback time in shared mode */
1553     *out = This->held_frames;
1554
1555     LeaveCriticalSection(&This->lock);
1556
1557     TRACE("pad: %u\n", *out);
1558
1559     return S_OK;
1560 }
1561
1562 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
1563         AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *fmt,
1564         WAVEFORMATEX **out)
1565 {
1566     ACImpl *This = impl_from_IAudioClient(iface);
1567     snd_pcm_format_mask_t *formats = NULL;
1568     snd_pcm_format_t format;
1569     HRESULT hr = S_OK;
1570     WAVEFORMATEX *closest = NULL;
1571     unsigned int max = 0, min = 0;
1572     int err;
1573
1574     TRACE("(%p)->(%x, %p, %p)\n", This, mode, fmt, out);
1575
1576     if(!fmt || (mode == AUDCLNT_SHAREMODE_SHARED && !out))
1577         return E_POINTER;
1578
1579     if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1580         return E_INVALIDARG;
1581
1582     if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1583             fmt->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1584         return E_INVALIDARG;
1585
1586     dump_fmt(fmt);
1587
1588     if(out){
1589         *out = NULL;
1590         if(mode != AUDCLNT_SHAREMODE_SHARED)
1591             out = NULL;
1592     }
1593
1594     if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1595             (fmt->nAvgBytesPerSec == 0 ||
1596              fmt->nBlockAlign == 0 ||
1597              ((WAVEFORMATEXTENSIBLE*)fmt)->Samples.wValidBitsPerSample > fmt->wBitsPerSample))
1598         return E_INVALIDARG;
1599
1600     if(fmt->nChannels == 0)
1601         return AUDCLNT_E_UNSUPPORTED_FORMAT;
1602
1603     EnterCriticalSection(&This->lock);
1604
1605     if((err = snd_pcm_hw_params_any(This->pcm_handle, This->hw_params)) < 0){
1606         hr = AUDCLNT_E_DEVICE_INVALIDATED;
1607         goto exit;
1608     }
1609
1610     formats = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1611             snd_pcm_format_mask_sizeof());
1612     if(!formats){
1613         hr = E_OUTOFMEMORY;
1614         goto exit;
1615     }
1616
1617     snd_pcm_hw_params_get_format_mask(This->hw_params, formats);
1618     format = alsa_format(fmt);
1619     if (format == SND_PCM_FORMAT_UNKNOWN ||
1620         !snd_pcm_format_mask_test(formats, format)){
1621         hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
1622         goto exit;
1623     }
1624
1625     closest = clone_format(fmt);
1626     if(!closest){
1627         hr = E_OUTOFMEMORY;
1628         goto exit;
1629     }
1630
1631     if((err = snd_pcm_hw_params_get_rate_min(This->hw_params, &min, NULL)) < 0){
1632         hr = AUDCLNT_E_DEVICE_INVALIDATED;
1633         WARN("Unable to get min rate: %d (%s)\n", err, snd_strerror(err));
1634         goto exit;
1635     }
1636
1637     if((err = snd_pcm_hw_params_get_rate_max(This->hw_params, &max, NULL)) < 0){
1638         hr = AUDCLNT_E_DEVICE_INVALIDATED;
1639         WARN("Unable to get max rate: %d (%s)\n", err, snd_strerror(err));
1640         goto exit;
1641     }
1642
1643     if(fmt->nSamplesPerSec < min || fmt->nSamplesPerSec > max){
1644         hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
1645         goto exit;
1646     }
1647
1648     if((err = snd_pcm_hw_params_get_channels_min(This->hw_params, &min)) < 0){
1649         hr = AUDCLNT_E_DEVICE_INVALIDATED;
1650         WARN("Unable to get min channels: %d (%s)\n", err, snd_strerror(err));
1651         goto exit;
1652     }
1653
1654     if((err = snd_pcm_hw_params_get_channels_max(This->hw_params, &max)) < 0){
1655         hr = AUDCLNT_E_DEVICE_INVALIDATED;
1656         WARN("Unable to get max channels: %d (%s)\n", err, snd_strerror(err));
1657         goto exit;
1658     }
1659     if(fmt->nChannels > max){
1660         hr = S_FALSE;
1661         closest->nChannels = max;
1662     }else if(fmt->nChannels < min){
1663         hr = S_FALSE;
1664         closest->nChannels = min;
1665     }
1666
1667     if(FAILED(map_channels(This, fmt))){
1668         hr = AUDCLNT_E_DEVICE_INVALIDATED;
1669         WARN("map_channels failed\n");
1670         goto exit;
1671     }
1672     if(This->alsa_channels > max){
1673         hr = S_FALSE;
1674         closest->nChannels = max;
1675     }
1676
1677     if(closest->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
1678         ((WAVEFORMATEXTENSIBLE*)closest)->dwChannelMask = get_channel_mask(closest->nChannels);
1679
1680     if(fmt->nBlockAlign != fmt->nChannels * fmt->wBitsPerSample / 8 ||
1681             fmt->nAvgBytesPerSec != fmt->nBlockAlign * fmt->nSamplesPerSec ||
1682             (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1683              ((WAVEFORMATEXTENSIBLE*)fmt)->Samples.wValidBitsPerSample < fmt->wBitsPerSample))
1684         hr = S_FALSE;
1685
1686     if(mode == AUDCLNT_SHAREMODE_EXCLUSIVE &&
1687             fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
1688         if(((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask == 0 ||
1689                 ((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask & SPEAKER_RESERVED)
1690             hr = S_FALSE;
1691     }
1692
1693 exit:
1694     LeaveCriticalSection(&This->lock);
1695     HeapFree(GetProcessHeap(), 0, formats);
1696
1697     if(hr == S_FALSE && !out)
1698         hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
1699
1700     if(hr == S_FALSE && out) {
1701         closest->nBlockAlign =
1702             closest->nChannels * closest->wBitsPerSample / 8;
1703         closest->nAvgBytesPerSec =
1704             closest->nBlockAlign * closest->nSamplesPerSec;
1705         if(closest->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
1706             ((WAVEFORMATEXTENSIBLE*)closest)->Samples.wValidBitsPerSample = closest->wBitsPerSample;
1707         *out = closest;
1708     } else
1709         CoTaskMemFree(closest);
1710
1711     TRACE("returning: %08x\n", hr);
1712     return hr;
1713 }
1714
1715 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
1716         WAVEFORMATEX **pwfx)
1717 {
1718     ACImpl *This = impl_from_IAudioClient(iface);
1719     WAVEFORMATEXTENSIBLE *fmt;
1720     snd_pcm_format_mask_t *formats;
1721     unsigned int max_rate, max_channels;
1722     int err;
1723     HRESULT hr = S_OK;
1724
1725     TRACE("(%p)->(%p)\n", This, pwfx);
1726
1727     if(!pwfx)
1728         return E_POINTER;
1729     *pwfx = NULL;
1730
1731     fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
1732     if(!fmt)
1733         return E_OUTOFMEMORY;
1734
1735     formats = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_format_mask_sizeof());
1736     if(!formats){
1737         CoTaskMemFree(fmt);
1738         return E_OUTOFMEMORY;
1739     }
1740
1741     EnterCriticalSection(&This->lock);
1742
1743     if((err = snd_pcm_hw_params_any(This->pcm_handle, This->hw_params)) < 0){
1744         WARN("Unable to get hw_params: %d (%s)\n", err, snd_strerror(err));
1745         hr = AUDCLNT_E_DEVICE_INVALIDATED;
1746         goto exit;
1747     }
1748
1749     snd_pcm_hw_params_get_format_mask(This->hw_params, formats);
1750
1751     fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1752     if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_FLOAT_LE)){
1753         fmt->Format.wBitsPerSample = 32;
1754         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
1755     }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S16_LE)){
1756         fmt->Format.wBitsPerSample = 16;
1757         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1758     }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_U8)){
1759         fmt->Format.wBitsPerSample = 8;
1760         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1761     }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S32_LE)){
1762         fmt->Format.wBitsPerSample = 32;
1763         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1764     }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S24_3LE)){
1765         fmt->Format.wBitsPerSample = 24;
1766         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1767     }else{
1768         ERR("Didn't recognize any available ALSA formats\n");
1769         hr = AUDCLNT_E_DEVICE_INVALIDATED;
1770         goto exit;
1771     }
1772
1773     if((err = snd_pcm_hw_params_get_channels_max(This->hw_params,
1774                     &max_channels)) < 0){
1775         WARN("Unable to get max channels: %d (%s)\n", err, snd_strerror(err));
1776         hr = AUDCLNT_E_DEVICE_INVALIDATED;
1777         goto exit;
1778     }
1779
1780     if(max_channels > 2)
1781         fmt->Format.nChannels = 2;
1782     else
1783         fmt->Format.nChannels = max_channels;
1784
1785     fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
1786
1787     if((err = snd_pcm_hw_params_get_rate_max(This->hw_params, &max_rate,
1788                     NULL)) < 0){
1789         WARN("Unable to get max rate: %d (%s)\n", err, snd_strerror(err));
1790         hr = AUDCLNT_E_DEVICE_INVALIDATED;
1791         goto exit;
1792     }
1793
1794     if(max_rate >= 48000)
1795         fmt->Format.nSamplesPerSec = 48000;
1796     else if(max_rate >= 44100)
1797         fmt->Format.nSamplesPerSec = 44100;
1798     else if(max_rate >= 22050)
1799         fmt->Format.nSamplesPerSec = 22050;
1800     else if(max_rate >= 11025)
1801         fmt->Format.nSamplesPerSec = 11025;
1802     else if(max_rate >= 8000)
1803         fmt->Format.nSamplesPerSec = 8000;
1804     else{
1805         ERR("Unknown max rate: %u\n", max_rate);
1806         hr = AUDCLNT_E_DEVICE_INVALIDATED;
1807         goto exit;
1808     }
1809
1810     fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
1811             fmt->Format.nChannels) / 8;
1812     fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
1813         fmt->Format.nBlockAlign;
1814
1815     fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
1816     fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1817
1818     dump_fmt((WAVEFORMATEX*)fmt);
1819     *pwfx = (WAVEFORMATEX*)fmt;
1820
1821 exit:
1822     LeaveCriticalSection(&This->lock);
1823     if(FAILED(hr))
1824         CoTaskMemFree(fmt);
1825     HeapFree(GetProcessHeap(), 0, formats);
1826
1827     return hr;
1828 }
1829
1830 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
1831         REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1832 {
1833     ACImpl *This = impl_from_IAudioClient(iface);
1834
1835     TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
1836
1837     if(!defperiod && !minperiod)
1838         return E_POINTER;
1839
1840     if(defperiod)
1841         *defperiod = DefaultPeriod;
1842     if(minperiod)
1843         *minperiod = MinimumPeriod;
1844
1845     return S_OK;
1846 }
1847
1848 static BYTE *remap_channels(ACImpl *This, BYTE *buf, snd_pcm_uframes_t frames)
1849 {
1850     snd_pcm_uframes_t i;
1851     UINT c;
1852     UINT bytes_per_sample = This->fmt->wBitsPerSample / 8;
1853
1854     if(!This->need_remapping)
1855         return buf;
1856
1857     if(!This->remapping_buf){
1858         This->remapping_buf = HeapAlloc(GetProcessHeap(), 0,
1859                 bytes_per_sample * This->alsa_channels * frames);
1860         This->remapping_buf_frames = frames;
1861     }else if(This->remapping_buf_frames < frames){
1862         This->remapping_buf = HeapReAlloc(GetProcessHeap(), 0, This->remapping_buf,
1863                 bytes_per_sample * This->alsa_channels * frames);
1864         This->remapping_buf_frames = frames;
1865     }
1866
1867     snd_pcm_format_set_silence(This->alsa_format, This->remapping_buf,
1868             frames * This->alsa_channels);
1869
1870     switch(This->fmt->wBitsPerSample){
1871     case 8: {
1872             UINT8 *tgt_buf, *src_buf;
1873             tgt_buf = This->remapping_buf;
1874             src_buf = buf;
1875             for(i = 0; i < frames; ++i){
1876                 for(c = 0; c < This->fmt->nChannels; ++c)
1877                     tgt_buf[This->alsa_channel_map[c]] = src_buf[c];
1878                 tgt_buf += This->alsa_channels;
1879                 src_buf += This->fmt->nChannels;
1880             }
1881             break;
1882         }
1883     case 16: {
1884             UINT16 *tgt_buf, *src_buf;
1885             tgt_buf = (UINT16*)This->remapping_buf;
1886             src_buf = (UINT16*)buf;
1887             for(i = 0; i < frames; ++i){
1888                 for(c = 0; c < This->fmt->nChannels; ++c)
1889                     tgt_buf[This->alsa_channel_map[c]] = src_buf[c];
1890                 tgt_buf += This->alsa_channels;
1891                 src_buf += This->fmt->nChannels;
1892             }
1893         }
1894         break;
1895     case 32: {
1896             UINT32 *tgt_buf, *src_buf;
1897             tgt_buf = (UINT32*)This->remapping_buf;
1898             src_buf = (UINT32*)buf;
1899             for(i = 0; i < frames; ++i){
1900                 for(c = 0; c < This->fmt->nChannels; ++c)
1901                     tgt_buf[This->alsa_channel_map[c]] = src_buf[c];
1902                 tgt_buf += This->alsa_channels;
1903                 src_buf += This->fmt->nChannels;
1904             }
1905         }
1906         break;
1907     default: {
1908             BYTE *tgt_buf, *src_buf;
1909             tgt_buf = This->remapping_buf;
1910             src_buf = buf;
1911             for(i = 0; i < frames; ++i){
1912                 for(c = 0; c < This->fmt->nChannels; ++c)
1913                     memcpy(&tgt_buf[This->alsa_channel_map[c] * bytes_per_sample],
1914                             &src_buf[c * bytes_per_sample], bytes_per_sample);
1915                 tgt_buf += This->alsa_channels * bytes_per_sample;
1916                 src_buf += This->fmt->nChannels * bytes_per_sample;
1917             }
1918         }
1919         break;
1920     }
1921
1922     return This->remapping_buf;
1923 }
1924
1925 static snd_pcm_sframes_t alsa_write_best_effort(snd_pcm_t *handle, BYTE *buf,
1926         snd_pcm_uframes_t frames, ACImpl *This, BOOL mute)
1927 {
1928     snd_pcm_sframes_t written;
1929
1930     if(mute){
1931         int err;
1932         if((err = snd_pcm_format_set_silence(This->alsa_format, buf,
1933                         frames * This->fmt->nChannels)) < 0)
1934             WARN("Setting buffer to silence failed: %d (%s)\n", err,
1935                     snd_strerror(err));
1936     }
1937
1938     buf = remap_channels(This, buf, frames);
1939
1940     written = snd_pcm_writei(handle, buf, frames);
1941     if(written < 0){
1942         int ret;
1943
1944         if(written == -EAGAIN)
1945             /* buffer full */
1946             return 0;
1947
1948         WARN("writei failed, recovering: %ld (%s)\n", written,
1949                 snd_strerror(written));
1950
1951         ret = snd_pcm_recover(handle, written, 0);
1952         if(ret < 0){
1953             WARN("Could not recover: %d (%s)\n", ret, snd_strerror(ret));
1954             return ret;
1955         }
1956
1957         written = snd_pcm_writei(handle, buf, frames);
1958     }
1959
1960     return written;
1961 }
1962
1963 static void alsa_write_data(ACImpl *This)
1964 {
1965     snd_pcm_sframes_t written, in_alsa;
1966     snd_pcm_uframes_t to_write, avail, write_limit, max_period;
1967     int err;
1968     BYTE *buf =
1969         This->local_buffer + (This->lcl_offs_frames * This->fmt->nBlockAlign);
1970
1971     /* this call seems to be required to get an accurate snd_pcm_state() */
1972     avail = snd_pcm_avail_update(This->pcm_handle);
1973
1974     if(snd_pcm_state(This->pcm_handle) == SND_PCM_STATE_XRUN ||
1975             avail > This->alsa_bufsize_frames){
1976         TRACE("XRun state avail %ld, recovering\n", avail);
1977
1978         avail = This->alsa_bufsize_frames;
1979
1980         if((err = snd_pcm_recover(This->pcm_handle, -EPIPE, 1)) < 0)
1981             WARN("snd_pcm_recover failed: %d (%s)\n", err, snd_strerror(err));
1982
1983         if((err = snd_pcm_reset(This->pcm_handle)) < 0)
1984             WARN("snd_pcm_reset failed: %d (%s)\n", err, snd_strerror(err));
1985
1986         if((err = snd_pcm_prepare(This->pcm_handle)) < 0)
1987             WARN("snd_pcm_prepare failed: %d (%s)\n", err, snd_strerror(err));
1988     }else
1989         TRACE("pad: %ld\n", This->alsa_bufsize_frames - avail);
1990
1991     if(This->held_frames == 0)
1992         return;
1993
1994     if(This->lcl_offs_frames + This->held_frames > This->bufsize_frames)
1995         to_write = This->bufsize_frames - This->lcl_offs_frames;
1996     else
1997         to_write = This->held_frames;
1998
1999     max_period = max(This->mmdev_period_frames, This->alsa_period_frames);
2000
2001     /* try to keep 3 ALSA periods or 3 MMDevAPI periods in the ALSA buffer and
2002      * no more */
2003     write_limit = 0;
2004     in_alsa = This->alsa_bufsize_frames - avail;
2005     while(in_alsa + write_limit < max_period * 3)
2006         write_limit += max_period;
2007     if(write_limit == 0)
2008         return;
2009
2010     to_write = min(to_write, write_limit);
2011
2012     /* Add a lead-in when starting with too few frames to ensure
2013      * continuous rendering.  Additional benefit: Force ALSA to start.
2014      * GetPosition continues to reflect the speaker position because
2015      * snd_pcm_delay includes buffered frames in its total delay
2016      * and last_pos_frames prevents moving backwards. */
2017     if(!in_alsa && This->held_frames < This->hidden_frames){
2018         UINT32 s_frames = This->hidden_frames - This->held_frames;
2019         BYTE *silence = HeapAlloc(GetProcessHeap(), 0,
2020                 s_frames * This->fmt->nBlockAlign);
2021
2022         if(silence){
2023             in_alsa = alsa_write_best_effort(This->pcm_handle,
2024                 silence, s_frames, This, TRUE);
2025             TRACE("lead-in %ld\n", in_alsa);
2026             HeapFree(GetProcessHeap(), 0, silence);
2027             if(in_alsa <= 0)
2028                 return;
2029         }else
2030             WARN("Couldn't allocate lead-in, expect underrun\n");
2031     }
2032
2033     written = alsa_write_best_effort(This->pcm_handle, buf, to_write, This,
2034             This->session->mute);
2035     if(written < 0){
2036         WARN("Couldn't write: %ld (%s)\n", written, snd_strerror(written));
2037         return;
2038     }
2039
2040     This->lcl_offs_frames += written;
2041     This->lcl_offs_frames %= This->bufsize_frames;
2042     This->held_frames -= written;
2043
2044     if(written < to_write){
2045         /* ALSA buffer probably full */
2046         return;
2047     }
2048
2049     if(This->held_frames && (written < write_limit)){
2050         /* wrapped and have some data back at the start to write */
2051         written = alsa_write_best_effort(This->pcm_handle, This->local_buffer,
2052                 min(This->held_frames, write_limit - written), This,
2053                 This->session->mute);
2054         if(written < 0){
2055             WARN("Couldn't write: %ld (%s)\n", written, snd_strerror(written));
2056             return;
2057         }
2058
2059         This->lcl_offs_frames += written;
2060         This->lcl_offs_frames %= This->bufsize_frames;
2061         This->held_frames -= written;
2062     }
2063 }
2064
2065 static void alsa_read_data(ACImpl *This)
2066 {
2067     snd_pcm_sframes_t pos, readable, nread;
2068
2069     pos = (This->held_frames + This->lcl_offs_frames) % This->bufsize_frames;
2070     readable = This->bufsize_frames - pos;
2071
2072     nread = snd_pcm_readi(This->pcm_handle,
2073             This->local_buffer + pos * This->fmt->nBlockAlign, readable);
2074     TRACE("read %ld from %u limit %lu\n", nread, This->held_frames + This->lcl_offs_frames, readable);
2075     if(nread < 0){
2076         int ret;
2077
2078         if(nread == -EAGAIN) /* no data yet */
2079             return;
2080
2081         WARN("read failed, recovering: %ld (%s)\n", nread, snd_strerror(nread));
2082
2083         ret = snd_pcm_recover(This->pcm_handle, nread, 0);
2084         if(ret < 0){
2085             WARN("Recover failed: %d (%s)\n", ret, snd_strerror(ret));
2086             return;
2087         }
2088
2089         nread = snd_pcm_readi(This->pcm_handle,
2090                 This->local_buffer + pos * This->fmt->nBlockAlign, readable);
2091         if(nread < 0){
2092             WARN("read failed: %ld (%s)\n", nread, snd_strerror(nread));
2093             return;
2094         }
2095     }
2096
2097     if(This->session->mute){
2098         int err;
2099         if((err = snd_pcm_format_set_silence(This->alsa_format,
2100                         This->local_buffer + pos * This->fmt->nBlockAlign,
2101                         nread)) < 0)
2102             WARN("Setting buffer to silence failed: %d (%s)\n", err,
2103                     snd_strerror(err));
2104     }
2105
2106     This->held_frames += nread;
2107
2108     if(This->held_frames > This->bufsize_frames){
2109         WARN("Overflow of unread data\n");
2110         This->lcl_offs_frames += This->held_frames;
2111         This->lcl_offs_frames %= This->bufsize_frames;
2112         This->held_frames = This->bufsize_frames;
2113     }
2114 }
2115
2116 static void CALLBACK alsa_push_buffer_data(void *user, BOOLEAN timer)
2117 {
2118     ACImpl *This = user;
2119
2120     EnterCriticalSection(&This->lock);
2121
2122     if(This->started){
2123         if(This->dataflow == eRender)
2124             alsa_write_data(This);
2125         else if(This->dataflow == eCapture)
2126             alsa_read_data(This);
2127
2128         if(This->event)
2129             SetEvent(This->event);
2130     }
2131
2132     LeaveCriticalSection(&This->lock);
2133 }
2134
2135 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
2136 {
2137     ACImpl *This = impl_from_IAudioClient(iface);
2138
2139     TRACE("(%p)\n", This);
2140
2141     EnterCriticalSection(&This->lock);
2142
2143     if(!This->initted){
2144         LeaveCriticalSection(&This->lock);
2145         return AUDCLNT_E_NOT_INITIALIZED;
2146     }
2147
2148     if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
2149         LeaveCriticalSection(&This->lock);
2150         return AUDCLNT_E_EVENTHANDLE_NOT_SET;
2151     }
2152
2153     if(This->started){
2154         LeaveCriticalSection(&This->lock);
2155         return AUDCLNT_E_NOT_STOPPED;
2156     }
2157
2158     if(This->dataflow == eCapture){
2159         /* dump any data that might be leftover in the ALSA capture buffer */
2160         snd_pcm_readi(This->pcm_handle, This->local_buffer,
2161                 This->bufsize_frames);
2162     }
2163
2164     if(!CreateTimerQueueTimer(&This->timer, g_timer_q, alsa_push_buffer_data,
2165             This, 0, This->mmdev_period_rt / 10000, WT_EXECUTEINTIMERTHREAD)){
2166         LeaveCriticalSection(&This->lock);
2167         WARN("Unable to create timer: %u\n", GetLastError());
2168         return E_OUTOFMEMORY;
2169     }
2170
2171     This->started = TRUE;
2172
2173     LeaveCriticalSection(&This->lock);
2174
2175     return S_OK;
2176 }
2177
2178 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
2179 {
2180     ACImpl *This = impl_from_IAudioClient(iface);
2181     HANDLE event;
2182     BOOL wait;
2183
2184     TRACE("(%p)\n", This);
2185
2186     EnterCriticalSection(&This->lock);
2187
2188     if(!This->initted){
2189         LeaveCriticalSection(&This->lock);
2190         return AUDCLNT_E_NOT_INITIALIZED;
2191     }
2192
2193     if(!This->started){
2194         LeaveCriticalSection(&This->lock);
2195         return S_FALSE;
2196     }
2197
2198     /* Stop without losing written frames or position.
2199      * snd_pcm_pause would be appropriate but is unsupported by dmix.
2200      * snd_pcm_drain yields EAGAIN in NONBLOCK mode, except with Pulse. */
2201
2202     event = CreateEventW(NULL, TRUE, FALSE, NULL);
2203     wait = !DeleteTimerQueueTimer(g_timer_q, This->timer, event);
2204     if(wait)
2205         WARN("DeleteTimerQueueTimer error %u\n", GetLastError());
2206     wait = wait && GetLastError() == ERROR_IO_PENDING;
2207
2208     This->started = FALSE;
2209
2210     LeaveCriticalSection(&This->lock);
2211
2212     if(event && wait)
2213         WaitForSingleObject(event, INFINITE);
2214     CloseHandle(event);
2215
2216     return S_OK;
2217 }
2218
2219 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
2220 {
2221     ACImpl *This = impl_from_IAudioClient(iface);
2222
2223     TRACE("(%p)\n", This);
2224
2225     EnterCriticalSection(&This->lock);
2226
2227     if(!This->initted){
2228         LeaveCriticalSection(&This->lock);
2229         return AUDCLNT_E_NOT_INITIALIZED;
2230     }
2231
2232     if(This->started){
2233         LeaveCriticalSection(&This->lock);
2234         return AUDCLNT_E_NOT_STOPPED;
2235     }
2236
2237     if(This->getbuf_last){
2238         LeaveCriticalSection(&This->lock);
2239         return AUDCLNT_E_BUFFER_OPERATION_PENDING;
2240     }
2241
2242     if(snd_pcm_drop(This->pcm_handle) < 0)
2243         WARN("snd_pcm_drop failed\n");
2244
2245     if(snd_pcm_reset(This->pcm_handle) < 0)
2246         WARN("snd_pcm_reset failed\n");
2247
2248     if(snd_pcm_prepare(This->pcm_handle) < 0)
2249         WARN("snd_pcm_prepare failed\n");
2250
2251     if(This->dataflow == eRender){
2252         This->written_frames = 0;
2253         This->last_pos_frames = 0;
2254     }else{
2255         This->written_frames += This->held_frames;
2256     }
2257     This->held_frames = 0;
2258     This->lcl_offs_frames = 0;
2259
2260     LeaveCriticalSection(&This->lock);
2261
2262     return S_OK;
2263 }
2264
2265 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
2266         HANDLE event)
2267 {
2268     ACImpl *This = impl_from_IAudioClient(iface);
2269
2270     TRACE("(%p)->(%p)\n", This, event);
2271
2272     if(!event)
2273         return E_INVALIDARG;
2274
2275     EnterCriticalSection(&This->lock);
2276
2277     if(!This->initted){
2278         LeaveCriticalSection(&This->lock);
2279         return AUDCLNT_E_NOT_INITIALIZED;
2280     }
2281
2282     if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
2283         LeaveCriticalSection(&This->lock);
2284         return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
2285     }
2286
2287     This->event = event;
2288
2289     LeaveCriticalSection(&This->lock);
2290
2291     return S_OK;
2292 }
2293
2294 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
2295         void **ppv)
2296 {
2297     ACImpl *This = impl_from_IAudioClient(iface);
2298
2299     TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
2300
2301     if(!ppv)
2302         return E_POINTER;
2303     *ppv = NULL;
2304
2305     EnterCriticalSection(&This->lock);
2306
2307     if(!This->initted){
2308         LeaveCriticalSection(&This->lock);
2309         return AUDCLNT_E_NOT_INITIALIZED;
2310     }
2311
2312     if(IsEqualIID(riid, &IID_IAudioRenderClient)){
2313         if(This->dataflow != eRender){
2314             LeaveCriticalSection(&This->lock);
2315             return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
2316         }
2317         IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
2318         *ppv = &This->IAudioRenderClient_iface;
2319     }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
2320         if(This->dataflow != eCapture){
2321             LeaveCriticalSection(&This->lock);
2322             return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
2323         }
2324         IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
2325         *ppv = &This->IAudioCaptureClient_iface;
2326     }else if(IsEqualIID(riid, &IID_IAudioClock)){
2327         IAudioClock_AddRef(&This->IAudioClock_iface);
2328         *ppv = &This->IAudioClock_iface;
2329     }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
2330         IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
2331         *ppv = &This->IAudioStreamVolume_iface;
2332     }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
2333         if(!This->session_wrapper){
2334             This->session_wrapper = AudioSessionWrapper_Create(This);
2335             if(!This->session_wrapper){
2336                 LeaveCriticalSection(&This->lock);
2337                 return E_OUTOFMEMORY;
2338             }
2339         }else
2340             IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
2341
2342         *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
2343     }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
2344         if(!This->session_wrapper){
2345             This->session_wrapper = AudioSessionWrapper_Create(This);
2346             if(!This->session_wrapper){
2347                 LeaveCriticalSection(&This->lock);
2348                 return E_OUTOFMEMORY;
2349             }
2350         }else
2351             IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
2352
2353         *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
2354     }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
2355         if(!This->session_wrapper){
2356             This->session_wrapper = AudioSessionWrapper_Create(This);
2357             if(!This->session_wrapper){
2358                 LeaveCriticalSection(&This->lock);
2359                 return E_OUTOFMEMORY;
2360             }
2361         }else
2362             ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
2363
2364         *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
2365     }
2366
2367     if(*ppv){
2368         LeaveCriticalSection(&This->lock);
2369         return S_OK;
2370     }
2371
2372     LeaveCriticalSection(&This->lock);
2373
2374     FIXME("stub %s\n", debugstr_guid(riid));
2375     return E_NOINTERFACE;
2376 }
2377
2378 static const IAudioClientVtbl AudioClient_Vtbl =
2379 {
2380     AudioClient_QueryInterface,
2381     AudioClient_AddRef,
2382     AudioClient_Release,
2383     AudioClient_Initialize,
2384     AudioClient_GetBufferSize,
2385     AudioClient_GetStreamLatency,
2386     AudioClient_GetCurrentPadding,
2387     AudioClient_IsFormatSupported,
2388     AudioClient_GetMixFormat,
2389     AudioClient_GetDevicePeriod,
2390     AudioClient_Start,
2391     AudioClient_Stop,
2392     AudioClient_Reset,
2393     AudioClient_SetEventHandle,
2394     AudioClient_GetService
2395 };
2396
2397 static HRESULT WINAPI AudioRenderClient_QueryInterface(
2398         IAudioRenderClient *iface, REFIID riid, void **ppv)
2399 {
2400     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2401
2402     if(!ppv)
2403         return E_POINTER;
2404     *ppv = NULL;
2405
2406     if(IsEqualIID(riid, &IID_IUnknown) ||
2407             IsEqualIID(riid, &IID_IAudioRenderClient))
2408         *ppv = iface;
2409     if(*ppv){
2410         IUnknown_AddRef((IUnknown*)*ppv);
2411         return S_OK;
2412     }
2413
2414     WARN("Unknown interface %s\n", debugstr_guid(riid));
2415     return E_NOINTERFACE;
2416 }
2417
2418 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
2419 {
2420     ACImpl *This = impl_from_IAudioRenderClient(iface);
2421     return AudioClient_AddRef(&This->IAudioClient_iface);
2422 }
2423
2424 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
2425 {
2426     ACImpl *This = impl_from_IAudioRenderClient(iface);
2427     return AudioClient_Release(&This->IAudioClient_iface);
2428 }
2429
2430 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
2431         UINT32 frames, BYTE **data)
2432 {
2433     ACImpl *This = impl_from_IAudioRenderClient(iface);
2434     UINT32 write_pos;
2435
2436     TRACE("(%p)->(%u, %p)\n", This, frames, data);
2437
2438     if(!data)
2439         return E_POINTER;
2440     *data = NULL;
2441
2442     EnterCriticalSection(&This->lock);
2443
2444     if(This->getbuf_last){
2445         LeaveCriticalSection(&This->lock);
2446         return AUDCLNT_E_OUT_OF_ORDER;
2447     }
2448
2449     if(!frames){
2450         LeaveCriticalSection(&This->lock);
2451         return S_OK;
2452     }
2453
2454     /* held_frames == GetCurrentPadding_nolock(); */
2455     if(This->held_frames + frames > This->bufsize_frames){
2456         LeaveCriticalSection(&This->lock);
2457         return AUDCLNT_E_BUFFER_TOO_LARGE;
2458     }
2459
2460     write_pos =
2461         (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
2462     if(write_pos + frames > This->bufsize_frames){
2463         if(This->tmp_buffer_frames < frames){
2464             HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
2465             This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
2466                     frames * This->fmt->nBlockAlign);
2467             if(!This->tmp_buffer){
2468                 LeaveCriticalSection(&This->lock);
2469                 return E_OUTOFMEMORY;
2470             }
2471             This->tmp_buffer_frames = frames;
2472         }
2473         *data = This->tmp_buffer;
2474         This->getbuf_last = -frames;
2475     }else{
2476         *data = This->local_buffer + write_pos * This->fmt->nBlockAlign;
2477         This->getbuf_last = frames;
2478     }
2479
2480     LeaveCriticalSection(&This->lock);
2481
2482     return S_OK;
2483 }
2484
2485 static void alsa_wrap_buffer(ACImpl *This, BYTE *buffer, UINT32 written_frames)
2486 {
2487     snd_pcm_uframes_t write_offs_frames =
2488         (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
2489     UINT32 write_offs_bytes = write_offs_frames * This->fmt->nBlockAlign;
2490     snd_pcm_uframes_t chunk_frames = This->bufsize_frames - write_offs_frames;
2491     UINT32 chunk_bytes = chunk_frames * This->fmt->nBlockAlign;
2492     UINT32 written_bytes = written_frames * This->fmt->nBlockAlign;
2493
2494     if(written_bytes <= chunk_bytes){
2495         memcpy(This->local_buffer + write_offs_bytes, buffer, written_bytes);
2496     }else{
2497         memcpy(This->local_buffer + write_offs_bytes, buffer, chunk_bytes);
2498         memcpy(This->local_buffer, buffer + chunk_bytes,
2499                 written_bytes - chunk_bytes);
2500     }
2501 }
2502
2503 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
2504         IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
2505 {
2506     ACImpl *This = impl_from_IAudioRenderClient(iface);
2507     BYTE *buffer;
2508
2509     TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
2510
2511     EnterCriticalSection(&This->lock);
2512
2513     if(!written_frames){
2514         This->getbuf_last = 0;
2515         LeaveCriticalSection(&This->lock);
2516         return S_OK;
2517     }
2518
2519     if(!This->getbuf_last){
2520         LeaveCriticalSection(&This->lock);
2521         return AUDCLNT_E_OUT_OF_ORDER;
2522     }
2523
2524     if(written_frames > (This->getbuf_last >= 0 ? This->getbuf_last : -This->getbuf_last)){
2525         LeaveCriticalSection(&This->lock);
2526         return AUDCLNT_E_INVALID_SIZE;
2527     }
2528
2529     if(This->getbuf_last >= 0)
2530         buffer = This->local_buffer + This->fmt->nBlockAlign *
2531           ((This->lcl_offs_frames + This->held_frames) % This->bufsize_frames);
2532     else
2533         buffer = This->tmp_buffer;
2534
2535     if(flags & AUDCLNT_BUFFERFLAGS_SILENT){
2536         if(This->fmt->wBitsPerSample == 8)
2537             memset(buffer, 128, written_frames * This->fmt->nBlockAlign);
2538         else
2539             memset(buffer, 0, written_frames * This->fmt->nBlockAlign);
2540     }
2541
2542     if(This->getbuf_last < 0)
2543         alsa_wrap_buffer(This, buffer, written_frames);
2544
2545     This->held_frames += written_frames;
2546     This->written_frames += written_frames;
2547     This->getbuf_last = 0;
2548
2549     LeaveCriticalSection(&This->lock);
2550
2551     return S_OK;
2552 }
2553
2554 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
2555     AudioRenderClient_QueryInterface,
2556     AudioRenderClient_AddRef,
2557     AudioRenderClient_Release,
2558     AudioRenderClient_GetBuffer,
2559     AudioRenderClient_ReleaseBuffer
2560 };
2561
2562 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
2563         IAudioCaptureClient *iface, REFIID riid, void **ppv)
2564 {
2565     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2566
2567     if(!ppv)
2568         return E_POINTER;
2569     *ppv = NULL;
2570
2571     if(IsEqualIID(riid, &IID_IUnknown) ||
2572             IsEqualIID(riid, &IID_IAudioCaptureClient))
2573         *ppv = iface;
2574     if(*ppv){
2575         IUnknown_AddRef((IUnknown*)*ppv);
2576         return S_OK;
2577     }
2578
2579     WARN("Unknown interface %s\n", debugstr_guid(riid));
2580     return E_NOINTERFACE;
2581 }
2582
2583 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
2584 {
2585     ACImpl *This = impl_from_IAudioCaptureClient(iface);
2586     return IAudioClient_AddRef(&This->IAudioClient_iface);
2587 }
2588
2589 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
2590 {
2591     ACImpl *This = impl_from_IAudioCaptureClient(iface);
2592     return IAudioClient_Release(&This->IAudioClient_iface);
2593 }
2594
2595 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
2596         BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
2597         UINT64 *qpcpos)
2598 {
2599     ACImpl *This = impl_from_IAudioCaptureClient(iface);
2600
2601     TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
2602             devpos, qpcpos);
2603
2604     if(!data || !frames || !flags)
2605         return E_POINTER;
2606
2607     EnterCriticalSection(&This->lock);
2608
2609     if(This->getbuf_last){
2610         LeaveCriticalSection(&This->lock);
2611         return AUDCLNT_E_OUT_OF_ORDER;
2612     }
2613
2614     /* hr = GetNextPacketSize(iface, frames); */
2615     if(This->held_frames < This->mmdev_period_frames){
2616         *frames = 0;
2617         LeaveCriticalSection(&This->lock);
2618         return AUDCLNT_S_BUFFER_EMPTY;
2619     }
2620     *frames = This->mmdev_period_frames;
2621
2622     if(This->lcl_offs_frames + *frames > This->bufsize_frames){
2623         UINT32 chunk_bytes, offs_bytes, frames_bytes;
2624         if(This->tmp_buffer_frames < *frames){
2625             HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
2626             This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
2627                     *frames * This->fmt->nBlockAlign);
2628             if(!This->tmp_buffer){
2629                 LeaveCriticalSection(&This->lock);
2630                 return E_OUTOFMEMORY;
2631             }
2632             This->tmp_buffer_frames = *frames;
2633         }
2634
2635         *data = This->tmp_buffer;
2636         chunk_bytes = (This->bufsize_frames - This->lcl_offs_frames) *
2637             This->fmt->nBlockAlign;
2638         offs_bytes = This->lcl_offs_frames * This->fmt->nBlockAlign;
2639         frames_bytes = *frames * This->fmt->nBlockAlign;
2640         memcpy(This->tmp_buffer, This->local_buffer + offs_bytes, chunk_bytes);
2641         memcpy(This->tmp_buffer + chunk_bytes, This->local_buffer,
2642                 frames_bytes - chunk_bytes);
2643     }else
2644         *data = This->local_buffer +
2645             This->lcl_offs_frames * This->fmt->nBlockAlign;
2646
2647     This->getbuf_last = *frames;
2648     *flags = 0;
2649
2650     if(devpos)
2651       *devpos = This->written_frames;
2652     if(qpcpos){ /* fixme: qpc of recording time */
2653         LARGE_INTEGER stamp, freq;
2654         QueryPerformanceCounter(&stamp);
2655         QueryPerformanceFrequency(&freq);
2656         *qpcpos = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
2657     }
2658
2659     LeaveCriticalSection(&This->lock);
2660
2661     return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
2662 }
2663
2664 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
2665         IAudioCaptureClient *iface, UINT32 done)
2666 {
2667     ACImpl *This = impl_from_IAudioCaptureClient(iface);
2668
2669     TRACE("(%p)->(%u)\n", This, done);
2670
2671     EnterCriticalSection(&This->lock);
2672
2673     if(!done){
2674         This->getbuf_last = 0;
2675         LeaveCriticalSection(&This->lock);
2676         return S_OK;
2677     }
2678
2679     if(!This->getbuf_last){
2680         LeaveCriticalSection(&This->lock);
2681         return AUDCLNT_E_OUT_OF_ORDER;
2682     }
2683
2684     if(This->getbuf_last != done){
2685         LeaveCriticalSection(&This->lock);
2686         return AUDCLNT_E_INVALID_SIZE;
2687     }
2688
2689     This->written_frames += done;
2690     This->held_frames -= done;
2691     This->lcl_offs_frames += done;
2692     This->lcl_offs_frames %= This->bufsize_frames;
2693     This->getbuf_last = 0;
2694
2695     LeaveCriticalSection(&This->lock);
2696
2697     return S_OK;
2698 }
2699
2700 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
2701         IAudioCaptureClient *iface, UINT32 *frames)
2702 {
2703     ACImpl *This = impl_from_IAudioCaptureClient(iface);
2704
2705     TRACE("(%p)->(%p)\n", This, frames);
2706
2707     if(!frames)
2708         return E_POINTER;
2709
2710     EnterCriticalSection(&This->lock);
2711
2712     *frames = This->held_frames < This->mmdev_period_frames ? 0 : This->mmdev_period_frames;
2713
2714     LeaveCriticalSection(&This->lock);
2715
2716     return S_OK;
2717 }
2718
2719 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
2720 {
2721     AudioCaptureClient_QueryInterface,
2722     AudioCaptureClient_AddRef,
2723     AudioCaptureClient_Release,
2724     AudioCaptureClient_GetBuffer,
2725     AudioCaptureClient_ReleaseBuffer,
2726     AudioCaptureClient_GetNextPacketSize
2727 };
2728
2729 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
2730         REFIID riid, void **ppv)
2731 {
2732     ACImpl *This = impl_from_IAudioClock(iface);
2733
2734     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2735
2736     if(!ppv)
2737         return E_POINTER;
2738     *ppv = NULL;
2739
2740     if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
2741         *ppv = iface;
2742     else if(IsEqualIID(riid, &IID_IAudioClock2))
2743         *ppv = &This->IAudioClock2_iface;
2744     if(*ppv){
2745         IUnknown_AddRef((IUnknown*)*ppv);
2746         return S_OK;
2747     }
2748
2749     WARN("Unknown interface %s\n", debugstr_guid(riid));
2750     return E_NOINTERFACE;
2751 }
2752
2753 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
2754 {
2755     ACImpl *This = impl_from_IAudioClock(iface);
2756     return IAudioClient_AddRef(&This->IAudioClient_iface);
2757 }
2758
2759 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
2760 {
2761     ACImpl *This = impl_from_IAudioClock(iface);
2762     return IAudioClient_Release(&This->IAudioClient_iface);
2763 }
2764
2765 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
2766 {
2767     ACImpl *This = impl_from_IAudioClock(iface);
2768
2769     TRACE("(%p)->(%p)\n", This, freq);
2770
2771     *freq = This->fmt->nSamplesPerSec;
2772
2773     return S_OK;
2774 }
2775
2776 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
2777         UINT64 *qpctime)
2778 {
2779     ACImpl *This = impl_from_IAudioClock(iface);
2780     UINT64 written_frames, position;
2781     UINT32 held_frames;
2782     int err;
2783     snd_pcm_state_t alsa_state;
2784     snd_pcm_uframes_t avail_frames;
2785     snd_pcm_sframes_t delay_frames;
2786
2787     TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
2788
2789     if(!pos)
2790         return E_POINTER;
2791
2792     EnterCriticalSection(&This->lock);
2793
2794     /* call required to get accurate snd_pcm_state() */
2795     avail_frames = snd_pcm_avail_update(This->pcm_handle);
2796     alsa_state = snd_pcm_state(This->pcm_handle);
2797     written_frames = This->written_frames;
2798     held_frames = This->held_frames;
2799
2800     err = snd_pcm_delay(This->pcm_handle, &delay_frames);
2801     if(err < 0){
2802         /* old Pulse, shortly after start */
2803         WARN("snd_pcm_delay failed in state %u: %d (%s)\n", alsa_state, err, snd_strerror(err));
2804     }
2805
2806     if(This->dataflow == eRender){
2807         position = written_frames - held_frames; /* maximum */
2808         if(!This->started || alsa_state > SND_PCM_STATE_RUNNING)
2809             ; /* mmdevapi stopped or ALSA underrun: pretend everything was played */
2810         else if(err<0 || delay_frames > position - This->last_pos_frames)
2811             /* Pulse bug: past underrun, despite recovery, avail_frames & delay
2812              * may be larger than alsa_bufsize_frames, as if cumulating frames. */
2813             /* Pulse bug: EIO(-5) shortly after starting: nothing played */
2814             position = This->last_pos_frames;
2815         else if(delay_frames > 0)
2816             position -= delay_frames;
2817     }else
2818         position = written_frames + held_frames;
2819
2820     /* ensure monotic growth */
2821     This->last_pos_frames = position;
2822
2823     LeaveCriticalSection(&This->lock);
2824
2825     TRACE("frames written: %u, held: %u, avail: %ld, delay: %ld state %d, pos: %u\n",
2826           (UINT32)(written_frames%1000000000), held_frames,
2827           avail_frames, delay_frames, alsa_state, (UINT32)(position%1000000000));
2828     *pos = position;
2829
2830     if(qpctime){
2831         LARGE_INTEGER stamp, freq;
2832         QueryPerformanceCounter(&stamp);
2833         QueryPerformanceFrequency(&freq);
2834         *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
2835     }
2836
2837     return S_OK;
2838 }
2839
2840 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
2841         DWORD *chars)
2842 {
2843     ACImpl *This = impl_from_IAudioClock(iface);
2844
2845     TRACE("(%p)->(%p)\n", This, chars);
2846
2847     if(!chars)
2848         return E_POINTER;
2849
2850     *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
2851
2852     return S_OK;
2853 }
2854
2855 static const IAudioClockVtbl AudioClock_Vtbl =
2856 {
2857     AudioClock_QueryInterface,
2858     AudioClock_AddRef,
2859     AudioClock_Release,
2860     AudioClock_GetFrequency,
2861     AudioClock_GetPosition,
2862     AudioClock_GetCharacteristics
2863 };
2864
2865 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
2866         REFIID riid, void **ppv)
2867 {
2868     ACImpl *This = impl_from_IAudioClock2(iface);
2869     return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
2870 }
2871
2872 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
2873 {
2874     ACImpl *This = impl_from_IAudioClock2(iface);
2875     return IAudioClient_AddRef(&This->IAudioClient_iface);
2876 }
2877
2878 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
2879 {
2880     ACImpl *This = impl_from_IAudioClock2(iface);
2881     return IAudioClient_Release(&This->IAudioClient_iface);
2882 }
2883
2884 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
2885         UINT64 *pos, UINT64 *qpctime)
2886 {
2887     ACImpl *This = impl_from_IAudioClock2(iface);
2888
2889     FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
2890
2891     return E_NOTIMPL;
2892 }
2893
2894 static const IAudioClock2Vtbl AudioClock2_Vtbl =
2895 {
2896     AudioClock2_QueryInterface,
2897     AudioClock2_AddRef,
2898     AudioClock2_Release,
2899     AudioClock2_GetDevicePosition
2900 };
2901
2902 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
2903 {
2904     AudioSessionWrapper *ret;
2905
2906     ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2907             sizeof(AudioSessionWrapper));
2908     if(!ret)
2909         return NULL;
2910
2911     ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
2912     ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
2913     ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
2914
2915     ret->ref = 1;
2916
2917     ret->client = client;
2918     if(client){
2919         ret->session = client->session;
2920         AudioClient_AddRef(&client->IAudioClient_iface);
2921     }
2922
2923     return ret;
2924 }
2925
2926 static HRESULT WINAPI AudioSessionControl_QueryInterface(
2927         IAudioSessionControl2 *iface, REFIID riid, void **ppv)
2928 {
2929     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2930
2931     if(!ppv)
2932         return E_POINTER;
2933     *ppv = NULL;
2934
2935     if(IsEqualIID(riid, &IID_IUnknown) ||
2936             IsEqualIID(riid, &IID_IAudioSessionControl) ||
2937             IsEqualIID(riid, &IID_IAudioSessionControl2))
2938         *ppv = iface;
2939     if(*ppv){
2940         IUnknown_AddRef((IUnknown*)*ppv);
2941         return S_OK;
2942     }
2943
2944     WARN("Unknown interface %s\n", debugstr_guid(riid));
2945     return E_NOINTERFACE;
2946 }
2947
2948 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
2949 {
2950     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2951     ULONG ref;
2952     ref = InterlockedIncrement(&This->ref);
2953     TRACE("(%p) Refcount now %u\n", This, ref);
2954     return ref;
2955 }
2956
2957 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
2958 {
2959     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2960     ULONG ref;
2961     ref = InterlockedDecrement(&This->ref);
2962     TRACE("(%p) Refcount now %u\n", This, ref);
2963     if(!ref){
2964         if(This->client){
2965             EnterCriticalSection(&This->client->lock);
2966             This->client->session_wrapper = NULL;
2967             LeaveCriticalSection(&This->client->lock);
2968             AudioClient_Release(&This->client->IAudioClient_iface);
2969         }
2970         HeapFree(GetProcessHeap(), 0, This);
2971     }
2972     return ref;
2973 }
2974
2975 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
2976         AudioSessionState *state)
2977 {
2978     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2979     ACImpl *client;
2980
2981     TRACE("(%p)->(%p)\n", This, state);
2982
2983     if(!state)
2984         return NULL_PTR_ERR;
2985
2986     EnterCriticalSection(&g_sessions_lock);
2987
2988     if(list_empty(&This->session->clients)){
2989         *state = AudioSessionStateExpired;
2990         LeaveCriticalSection(&g_sessions_lock);
2991         return S_OK;
2992     }
2993
2994     LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
2995         EnterCriticalSection(&client->lock);
2996         if(client->started){
2997             *state = AudioSessionStateActive;
2998             LeaveCriticalSection(&client->lock);
2999             LeaveCriticalSection(&g_sessions_lock);
3000             return S_OK;
3001         }
3002         LeaveCriticalSection(&client->lock);
3003     }
3004
3005     LeaveCriticalSection(&g_sessions_lock);
3006
3007     *state = AudioSessionStateInactive;
3008
3009     return S_OK;
3010 }
3011
3012 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
3013         IAudioSessionControl2 *iface, WCHAR **name)
3014 {
3015     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
3016
3017     FIXME("(%p)->(%p) - stub\n", This, name);
3018
3019     return E_NOTIMPL;
3020 }
3021
3022 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
3023         IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
3024 {
3025     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
3026
3027     FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
3028
3029     return E_NOTIMPL;
3030 }
3031
3032 static HRESULT WINAPI AudioSessionControl_GetIconPath(
3033         IAudioSessionControl2 *iface, WCHAR **path)
3034 {
3035     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
3036
3037     FIXME("(%p)->(%p) - stub\n", This, path);
3038
3039     return E_NOTIMPL;
3040 }
3041
3042 static HRESULT WINAPI AudioSessionControl_SetIconPath(
3043         IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
3044 {
3045     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
3046
3047     FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
3048
3049     return E_NOTIMPL;
3050 }
3051
3052 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
3053         IAudioSessionControl2 *iface, GUID *group)
3054 {
3055     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
3056
3057     FIXME("(%p)->(%p) - stub\n", This, group);
3058
3059     return E_NOTIMPL;
3060 }
3061
3062 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
3063         IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
3064 {
3065     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
3066
3067     FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
3068             debugstr_guid(session));
3069
3070     return E_NOTIMPL;
3071 }
3072
3073 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
3074         IAudioSessionControl2 *iface, IAudioSessionEvents *events)
3075 {
3076     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
3077
3078     FIXME("(%p)->(%p) - stub\n", This, events);
3079
3080     return S_OK;
3081 }
3082
3083 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
3084         IAudioSessionControl2 *iface, IAudioSessionEvents *events)
3085 {
3086     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
3087
3088     FIXME("(%p)->(%p) - stub\n", This, events);
3089
3090     return S_OK;
3091 }
3092
3093 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
3094         IAudioSessionControl2 *iface, WCHAR **id)
3095 {
3096     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
3097
3098     FIXME("(%p)->(%p) - stub\n", This, id);
3099
3100     return E_NOTIMPL;
3101 }
3102
3103 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
3104         IAudioSessionControl2 *iface, WCHAR **id)
3105 {
3106     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
3107
3108     FIXME("(%p)->(%p) - stub\n", This, id);
3109
3110     return E_NOTIMPL;
3111 }
3112
3113 static HRESULT WINAPI AudioSessionControl_GetProcessId(
3114         IAudioSessionControl2 *iface, DWORD *pid)
3115 {
3116     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
3117
3118     TRACE("(%p)->(%p)\n", This, pid);
3119
3120     if(!pid)
3121         return E_POINTER;
3122
3123     *pid = GetCurrentProcessId();
3124
3125     return S_OK;
3126 }
3127
3128 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
3129         IAudioSessionControl2 *iface)
3130 {
3131     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
3132
3133     TRACE("(%p)\n", This);
3134
3135     return S_FALSE;
3136 }
3137
3138 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
3139         IAudioSessionControl2 *iface, BOOL optout)
3140 {
3141     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
3142
3143     TRACE("(%p)->(%d)\n", This, optout);
3144
3145     return S_OK;
3146 }
3147
3148 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
3149 {
3150     AudioSessionControl_QueryInterface,
3151     AudioSessionControl_AddRef,
3152     AudioSessionControl_Release,
3153     AudioSessionControl_GetState,
3154     AudioSessionControl_GetDisplayName,
3155     AudioSessionControl_SetDisplayName,
3156     AudioSessionControl_GetIconPath,
3157     AudioSessionControl_SetIconPath,
3158     AudioSessionControl_GetGroupingParam,
3159     AudioSessionControl_SetGroupingParam,
3160     AudioSessionControl_RegisterAudioSessionNotification,
3161     AudioSessionControl_UnregisterAudioSessionNotification,
3162     AudioSessionControl_GetSessionIdentifier,
3163     AudioSessionControl_GetSessionInstanceIdentifier,
3164     AudioSessionControl_GetProcessId,
3165     AudioSessionControl_IsSystemSoundsSession,
3166     AudioSessionControl_SetDuckingPreference
3167 };
3168
3169 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
3170         ISimpleAudioVolume *iface, REFIID riid, void **ppv)
3171 {
3172     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
3173
3174     if(!ppv)
3175         return E_POINTER;
3176     *ppv = NULL;
3177
3178     if(IsEqualIID(riid, &IID_IUnknown) ||
3179             IsEqualIID(riid, &IID_ISimpleAudioVolume))
3180         *ppv = iface;
3181     if(*ppv){
3182         IUnknown_AddRef((IUnknown*)*ppv);
3183         return S_OK;
3184     }
3185
3186     WARN("Unknown interface %s\n", debugstr_guid(riid));
3187     return E_NOINTERFACE;
3188 }
3189
3190 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
3191 {
3192     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
3193     return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
3194 }
3195
3196 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
3197 {
3198     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
3199     return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
3200 }
3201
3202 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
3203         ISimpleAudioVolume *iface, float level, const GUID *context)
3204 {
3205     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
3206     AudioSession *session = This->session;
3207
3208     TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
3209
3210     if(level < 0.f || level > 1.f)
3211         return E_INVALIDARG;
3212
3213     if(context)
3214         FIXME("Notifications not supported yet\n");
3215
3216     TRACE("ALSA does not support volume control\n");
3217
3218     EnterCriticalSection(&session->lock);
3219
3220     session->master_vol = level;
3221
3222     LeaveCriticalSection(&session->lock);
3223
3224     return S_OK;
3225 }
3226
3227 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
3228         ISimpleAudioVolume *iface, float *level)
3229 {
3230     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
3231     AudioSession *session = This->session;
3232
3233     TRACE("(%p)->(%p)\n", session, level);
3234
3235     if(!level)
3236         return NULL_PTR_ERR;
3237
3238     *level = session->master_vol;
3239
3240     return S_OK;
3241 }
3242
3243 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
3244         BOOL mute, const GUID *context)
3245 {
3246     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
3247     AudioSession *session = This->session;
3248
3249     TRACE("(%p)->(%u, %p)\n", session, mute, context);
3250
3251     if(context)
3252         FIXME("Notifications not supported yet\n");
3253
3254     session->mute = mute;
3255
3256     return S_OK;
3257 }
3258
3259 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
3260         BOOL *mute)
3261 {
3262     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
3263     AudioSession *session = This->session;
3264
3265     TRACE("(%p)->(%p)\n", session, mute);
3266
3267     if(!mute)
3268         return NULL_PTR_ERR;
3269
3270     *mute = session->mute;
3271
3272     return S_OK;
3273 }
3274
3275 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl  =
3276 {
3277     SimpleAudioVolume_QueryInterface,
3278     SimpleAudioVolume_AddRef,
3279     SimpleAudioVolume_Release,
3280     SimpleAudioVolume_SetMasterVolume,
3281     SimpleAudioVolume_GetMasterVolume,
3282     SimpleAudioVolume_SetMute,
3283     SimpleAudioVolume_GetMute
3284 };
3285
3286 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
3287         IAudioStreamVolume *iface, REFIID riid, void **ppv)
3288 {
3289     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
3290
3291     if(!ppv)
3292         return E_POINTER;
3293     *ppv = NULL;
3294
3295     if(IsEqualIID(riid, &IID_IUnknown) ||
3296             IsEqualIID(riid, &IID_IAudioStreamVolume))
3297         *ppv = iface;
3298     if(*ppv){
3299         IUnknown_AddRef((IUnknown*)*ppv);
3300         return S_OK;
3301     }
3302
3303     WARN("Unknown interface %s\n", debugstr_guid(riid));
3304     return E_NOINTERFACE;
3305 }
3306
3307 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
3308 {
3309     ACImpl *This = impl_from_IAudioStreamVolume(iface);
3310     return IAudioClient_AddRef(&This->IAudioClient_iface);
3311 }
3312
3313 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
3314 {
3315     ACImpl *This = impl_from_IAudioStreamVolume(iface);
3316     return IAudioClient_Release(&This->IAudioClient_iface);
3317 }
3318
3319 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
3320         IAudioStreamVolume *iface, UINT32 *out)
3321 {
3322     ACImpl *This = impl_from_IAudioStreamVolume(iface);
3323
3324     TRACE("(%p)->(%p)\n", This, out);
3325
3326     if(!out)
3327         return E_POINTER;
3328
3329     *out = This->fmt->nChannels;
3330
3331     return S_OK;
3332 }
3333
3334 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
3335         IAudioStreamVolume *iface, UINT32 index, float level)
3336 {
3337     ACImpl *This = impl_from_IAudioStreamVolume(iface);
3338
3339     TRACE("(%p)->(%d, %f)\n", This, index, level);
3340
3341     if(level < 0.f || level > 1.f)
3342         return E_INVALIDARG;
3343
3344     if(index >= This->fmt->nChannels)
3345         return E_INVALIDARG;
3346
3347     TRACE("ALSA does not support volume control\n");
3348
3349     EnterCriticalSection(&This->lock);
3350
3351     This->vols[index] = level;
3352
3353     LeaveCriticalSection(&This->lock);
3354
3355     return S_OK;
3356 }
3357
3358 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
3359         IAudioStreamVolume *iface, UINT32 index, float *level)
3360 {
3361     ACImpl *This = impl_from_IAudioStreamVolume(iface);
3362
3363     TRACE("(%p)->(%d, %p)\n", This, index, level);
3364
3365     if(!level)
3366         return E_POINTER;
3367
3368     if(index >= This->fmt->nChannels)
3369         return E_INVALIDARG;
3370
3371     *level = This->vols[index];
3372
3373     return S_OK;
3374 }
3375
3376 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
3377         IAudioStreamVolume *iface, UINT32 count, const float *levels)
3378 {
3379     ACImpl *This = impl_from_IAudioStreamVolume(iface);
3380     int i;
3381
3382     TRACE("(%p)->(%d, %p)\n", This, count, levels);
3383
3384     if(!levels)
3385         return E_POINTER;
3386
3387     if(count != This->fmt->nChannels)
3388         return E_INVALIDARG;
3389
3390     TRACE("ALSA does not support volume control\n");
3391
3392     EnterCriticalSection(&This->lock);
3393
3394     for(i = 0; i < count; ++i)
3395         This->vols[i] = levels[i];
3396
3397     LeaveCriticalSection(&This->lock);
3398
3399     return S_OK;
3400 }
3401
3402 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
3403         IAudioStreamVolume *iface, UINT32 count, float *levels)
3404 {
3405     ACImpl *This = impl_from_IAudioStreamVolume(iface);
3406     int i;
3407
3408     TRACE("(%p)->(%d, %p)\n", This, count, levels);
3409
3410     if(!levels)
3411         return E_POINTER;
3412
3413     if(count != This->fmt->nChannels)
3414         return E_INVALIDARG;
3415
3416     EnterCriticalSection(&This->lock);
3417
3418     for(i = 0; i < count; ++i)
3419         levels[i] = This->vols[i];
3420
3421     LeaveCriticalSection(&This->lock);
3422
3423     return S_OK;
3424 }
3425
3426 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
3427 {
3428     AudioStreamVolume_QueryInterface,
3429     AudioStreamVolume_AddRef,
3430     AudioStreamVolume_Release,
3431     AudioStreamVolume_GetChannelCount,
3432     AudioStreamVolume_SetChannelVolume,
3433     AudioStreamVolume_GetChannelVolume,
3434     AudioStreamVolume_SetAllVolumes,
3435     AudioStreamVolume_GetAllVolumes
3436 };
3437
3438 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
3439         IChannelAudioVolume *iface, REFIID riid, void **ppv)
3440 {
3441     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
3442
3443     if(!ppv)
3444         return E_POINTER;
3445     *ppv = NULL;
3446
3447     if(IsEqualIID(riid, &IID_IUnknown) ||
3448             IsEqualIID(riid, &IID_IChannelAudioVolume))
3449         *ppv = iface;
3450     if(*ppv){
3451         IUnknown_AddRef((IUnknown*)*ppv);
3452         return S_OK;
3453     }
3454
3455     WARN("Unknown interface %s\n", debugstr_guid(riid));
3456     return E_NOINTERFACE;
3457 }
3458
3459 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
3460 {
3461     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
3462     return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
3463 }
3464
3465 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
3466 {
3467     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
3468     return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
3469 }
3470
3471 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
3472         IChannelAudioVolume *iface, UINT32 *out)
3473 {
3474     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
3475     AudioSession *session = This->session;
3476
3477     TRACE("(%p)->(%p)\n", session, out);
3478
3479     if(!out)
3480         return NULL_PTR_ERR;
3481
3482     *out = session->channel_count;
3483
3484     return S_OK;
3485 }
3486
3487 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
3488         IChannelAudioVolume *iface, UINT32 index, float level,
3489         const GUID *context)
3490 {
3491     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
3492     AudioSession *session = This->session;
3493
3494     TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
3495             wine_dbgstr_guid(context));
3496
3497     if(level < 0.f || level > 1.f)
3498         return E_INVALIDARG;
3499
3500     if(index >= session->channel_count)
3501         return E_INVALIDARG;
3502
3503     if(context)
3504         FIXME("Notifications not supported yet\n");
3505
3506     TRACE("ALSA does not support volume control\n");
3507
3508     EnterCriticalSection(&session->lock);
3509
3510     session->channel_vols[index] = level;
3511
3512     LeaveCriticalSection(&session->lock);
3513
3514     return S_OK;
3515 }
3516
3517 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
3518         IChannelAudioVolume *iface, UINT32 index, float *level)
3519 {
3520     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
3521     AudioSession *session = This->session;
3522
3523     TRACE("(%p)->(%d, %p)\n", session, index, level);
3524
3525     if(!level)
3526         return NULL_PTR_ERR;
3527
3528     if(index >= session->channel_count)
3529         return E_INVALIDARG;
3530
3531     *level = session->channel_vols[index];
3532
3533     return S_OK;
3534 }
3535
3536 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
3537         IChannelAudioVolume *iface, UINT32 count, const float *levels,
3538         const GUID *context)
3539 {
3540     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
3541     AudioSession *session = This->session;
3542     int i;
3543
3544     TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
3545             wine_dbgstr_guid(context));
3546
3547     if(!levels)
3548         return NULL_PTR_ERR;
3549
3550     if(count != session->channel_count)
3551         return E_INVALIDARG;
3552
3553     if(context)
3554         FIXME("Notifications not supported yet\n");
3555
3556     TRACE("ALSA does not support volume control\n");
3557
3558     EnterCriticalSection(&session->lock);
3559
3560     for(i = 0; i < count; ++i)
3561         session->channel_vols[i] = levels[i];
3562
3563     LeaveCriticalSection(&session->lock);
3564
3565     return S_OK;
3566 }
3567
3568 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
3569         IChannelAudioVolume *iface, UINT32 count, float *levels)
3570 {
3571     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
3572     AudioSession *session = This->session;
3573     int i;
3574
3575     TRACE("(%p)->(%d, %p)\n", session, count, levels);
3576
3577     if(!levels)
3578         return NULL_PTR_ERR;
3579
3580     if(count != session->channel_count)
3581         return E_INVALIDARG;
3582
3583     for(i = 0; i < count; ++i)
3584         levels[i] = session->channel_vols[i];
3585
3586     return S_OK;
3587 }
3588
3589 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
3590 {
3591     ChannelAudioVolume_QueryInterface,
3592     ChannelAudioVolume_AddRef,
3593     ChannelAudioVolume_Release,
3594     ChannelAudioVolume_GetChannelCount,
3595     ChannelAudioVolume_SetChannelVolume,
3596     ChannelAudioVolume_GetChannelVolume,
3597     ChannelAudioVolume_SetAllVolumes,
3598     ChannelAudioVolume_GetAllVolumes
3599 };
3600
3601 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
3602         REFIID riid, void **ppv)
3603 {
3604     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
3605
3606     if(!ppv)
3607         return E_POINTER;
3608     *ppv = NULL;
3609
3610     if(IsEqualIID(riid, &IID_IUnknown) ||
3611             IsEqualIID(riid, &IID_IAudioSessionManager) ||
3612             IsEqualIID(riid, &IID_IAudioSessionManager2))
3613         *ppv = iface;
3614     if(*ppv){
3615         IUnknown_AddRef((IUnknown*)*ppv);
3616         return S_OK;
3617     }
3618
3619     WARN("Unknown interface %s\n", debugstr_guid(riid));
3620     return E_NOINTERFACE;
3621 }
3622
3623 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
3624 {
3625     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3626     ULONG ref;
3627     ref = InterlockedIncrement(&This->ref);
3628     TRACE("(%p) Refcount now %u\n", This, ref);
3629     return ref;
3630 }
3631
3632 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
3633 {
3634     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3635     ULONG ref;
3636     ref = InterlockedDecrement(&This->ref);
3637     TRACE("(%p) Refcount now %u\n", This, ref);
3638     if(!ref)
3639         HeapFree(GetProcessHeap(), 0, This);
3640     return ref;
3641 }
3642
3643 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
3644         IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
3645         IAudioSessionControl **out)
3646 {
3647     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3648     AudioSession *session;
3649     AudioSessionWrapper *wrapper;
3650     HRESULT hr;
3651
3652     TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
3653             flags, out);
3654
3655     hr = get_audio_session(session_guid, This->device, 0, &session);
3656     if(FAILED(hr))
3657         return hr;
3658
3659     wrapper = AudioSessionWrapper_Create(NULL);
3660     if(!wrapper)
3661         return E_OUTOFMEMORY;
3662
3663     wrapper->session = session;
3664
3665     *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
3666
3667     return S_OK;
3668 }
3669
3670 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
3671         IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
3672         ISimpleAudioVolume **out)
3673 {
3674     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3675     AudioSession *session;
3676     AudioSessionWrapper *wrapper;
3677     HRESULT hr;
3678
3679     TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
3680             flags, out);
3681
3682     hr = get_audio_session(session_guid, This->device, 0, &session);
3683     if(FAILED(hr))
3684         return hr;
3685
3686     wrapper = AudioSessionWrapper_Create(NULL);
3687     if(!wrapper)
3688         return E_OUTOFMEMORY;
3689
3690     wrapper->session = session;
3691
3692     *out = &wrapper->ISimpleAudioVolume_iface;
3693
3694     return S_OK;
3695 }
3696
3697 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
3698         IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
3699 {
3700     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3701     FIXME("(%p)->(%p) - stub\n", This, out);
3702     return E_NOTIMPL;
3703 }
3704
3705 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
3706         IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
3707 {
3708     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3709     FIXME("(%p)->(%p) - stub\n", This, notification);
3710     return E_NOTIMPL;
3711 }
3712
3713 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
3714         IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
3715 {
3716     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3717     FIXME("(%p)->(%p) - stub\n", This, notification);
3718     return E_NOTIMPL;
3719 }
3720
3721 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
3722         IAudioSessionManager2 *iface, const WCHAR *session_id,
3723         IAudioVolumeDuckNotification *notification)
3724 {
3725     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3726     FIXME("(%p)->(%p) - stub\n", This, notification);
3727     return E_NOTIMPL;
3728 }
3729
3730 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
3731         IAudioSessionManager2 *iface,
3732         IAudioVolumeDuckNotification *notification)
3733 {
3734     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3735     FIXME("(%p)->(%p) - stub\n", This, notification);
3736     return E_NOTIMPL;
3737 }
3738
3739 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
3740 {
3741     AudioSessionManager_QueryInterface,
3742     AudioSessionManager_AddRef,
3743     AudioSessionManager_Release,
3744     AudioSessionManager_GetAudioSessionControl,
3745     AudioSessionManager_GetSimpleAudioVolume,
3746     AudioSessionManager_GetSessionEnumerator,
3747     AudioSessionManager_RegisterSessionNotification,
3748     AudioSessionManager_UnregisterSessionNotification,
3749     AudioSessionManager_RegisterDuckNotification,
3750     AudioSessionManager_UnregisterDuckNotification
3751 };
3752
3753 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
3754         IAudioSessionManager2 **out)
3755 {
3756     SessionMgr *This;
3757
3758     This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
3759     if(!This)
3760         return E_OUTOFMEMORY;
3761
3762     This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
3763     This->device = device;
3764     This->ref = 1;
3765
3766     *out = &This->IAudioSessionManager2_iface;
3767
3768     return S_OK;
3769 }