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