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