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