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