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